base.hh 10.9 KB
Newer Older
1 2
#ifndef DUNE_DORIE_MODEL_BASE_HH
#define DUNE_DORIE_MODEL_BASE_HH
3

4
#include <dune/dorie/common/logging.hh>
5

6 7 8
#include <dune/common/exceptions.hh>
#include <dune/common/float_cmp.hh>

9 10
#include <dune/dorie/common/util.hh>

11 12 13
namespace Dune{
namespace Dorie{

14
/*-------------------------------------------------------------------------*//**
15 16
 * @brief      Base class for models.
 * @details    This class is used to handle models with a common interface.
17
 * @author     Santiago Ospina De Los Ríos
18 19 20 21
 * @date       2018
 * @todo       Dune::Dorie::OutputPolicy can handle specific intermediate times
 *             of the stepping.
 * @ingroup    Models
22
 */
23
class ModelBase
24 25 26 27
{
public:

  /**
28
   * @brief      Constructs the ModelBase.
29
   *
30 31 32 33
   * @param[in]  log_name  Name of this model. Appears in the log.
   * @param[in]  log_level  The log level of the logger.
   * @param[in]  helper  The Dune::MPIHelper instance of this process.
   * @param[in]  output_policy  The output policy.
34
   *                            Defaults to OutputPolicy::None.
35 36
   * @param[in]  adapt_policy  The adapt policy.
   *                           Defaults to AdaptiviyPolicy::None.
37
   */
38
  ModelBase(
39 40 41
    const std::string log_name,
    const std::string log_level,
    const Dune::MPIHelper& helper,
42
    OutputPolicy output_policy=OutputPolicy::None,
43 44 45 46
    AdaptivityPolicy adapt_policy=AdaptivityPolicy::None
  )
    : _output_policy(output_policy)
    , _adapt_policy(adapt_policy)
47 48
    , _log(create_logger(log_name, helper, spdlog::level::from_str(log_level)))
  { }
49

50
  virtual ~ModelBase () = default;
51
  /*-----------------------------------------------------------------------*//**
52 53
   * @brief      Sets the output policy.
   *
54
   * @param[in]  output_policy  The output policy,
55
   */
56
  void set_policy(OutputPolicy output_policy) {_output_policy = output_policy;}
57

58
  /*-----------------------------------------------------------------------*//**
59 60
   * @brief      Sets the adaptivity policy.
   *
61
   * @param[in]  adapt_policy  The adaptivity policy.
62
   */
63 64 65 66
  void set_policy(AdaptivityPolicy adapt_policy)
  {
    _adapt_policy = adapt_policy;
  }
67

68
  /*-----------------------------------------------------------------------*//**
69 70 71 72
   * @brief      Returns the current output policy.
   *
   * @return     The current output policy.
   */
73
  OutputPolicy     output_policy() const {return _output_policy;}
74 75


76
  /*-----------------------------------------------------------------------*//**
77 78 79 80
   * @brief      Returns the current adaptivity policy.
   *
   * @return     The current adaptivity policy.
   */
81
  AdaptivityPolicy adaptivity_policy() const {return _adapt_policy;}
82

83
  /// Set the logger for this model
84 85 86 87 88 89 90
  /** @param logger The new logger
   */
  void set_logger (const std::shared_ptr<spdlog::logger> logger)
  {
    _log = logger;
  }

91
  /// Return the logger of this model
92
  std::shared_ptr<spdlog::logger> logger() const { return _log; }
93

94
  /*-----------------------------------------------------------------------*//**
95 96
   * @brief      Writes the data.
   */
97
  void virtual write_data() const
98
  {
99
    if (_output_policy != OutputPolicy::None) {
100
      _log->error("This model does not implement writing data. "
101 102
                  "Override this function if you set a different output policy "
                  "than None");
103
      DUNE_THROW(Dune::IOError, "'write_data' not implemented!");
104
    }
105 106
  }

107
  /*-----------------------------------------------------------------------*//**
108 109
   * @brief      Mark the grid in order to improve the current model.
   */
110
  virtual void mark_grid()
111
  {
112
    _log->error("This model does not implement an algorithm for marking "
113 114
                "the grid");
    DUNE_THROW(Dune::NotImplemented, "'mark_grid' not implemented!");
115 116
  }

117
  /*-----------------------------------------------------------------------*//**
118 119
   * @brief      Operations before adaptation of the grid
   */
120
  virtual void pre_adapt_grid() {};
121

122 123 124
  /*-----------------------------------------------------------------------*//**
   * @brief      Adapt the grid together it every dependency of the grid (e.g.
   *             solution vector and grid function spaces).
125
   */
126
  virtual void adapt_grid()
127
  {
128
    if (_adapt_policy != AdaptivityPolicy::None) {
129
      _log->error("This model does not implement a grid adaptation "
130 131 132 133
                  "algorithm.");
      DUNE_THROW(Dune::NotImplemented, "'adapt_grid' not implemented");
    }
    else {
134
      _log->error("Calling 'adapt_grid' on a model with "
135 136 137
                  "AdaptivityPolicy::None. Grid adaptation refused");
      DUNE_THROW(Dune::InvalidStateException, "Invalid adaptation policy");
    }
138 139
  }

140
  /*-----------------------------------------------------------------------*//**
141 142
   * @brief      Operations after adaptation of the grid
   */
143
  virtual void post_adapt_grid() {};
144

145
  /*-----------------------------------------------------------------------*//**
146 147 148 149
   * @brief      Method that provides the begin time of the model.
   *
   * @return     Begin time of the model.
   */
150
  virtual double begin_time() const = 0;
151

152
  /*-----------------------------------------------------------------------*//**
153 154 155 156
   * @brief      Method that provides the end time of the model.
   *
   * @return     End time of the model.
   */
157
  virtual double end_time() const = 0;
158

159
  /*-----------------------------------------------------------------------*//**
160 161 162 163
   * @brief      Method that provides the current time of the model.
   *
   * @return     Current time of the model.
   */
164
  virtual double current_time() const = 0;
165

166
  /*-----------------------------------------------------------------------*//**
167 168
   * @brief      Suggest a time step to the model.
   *
169 170
   * @param[in]  dt    { parameter_description }
   * @param[in]  suggestion  for the internal time step of the model.
171
   */
172
  virtual void suggest_timestep(double dt) = 0;
173

174
  /*-----------------------------------------------------------------------*//**
175
   * @brief      Performs one steps in direction to end_time(). The time-step
176 177
   *             should never result on a bigger step than the one suggested in
   *             suggest_timestep().
178 179 180
   */
  virtual void step() = 0;

181
  /*-----------------------------------------------------------------------*//**
182 183
   * @brief      Runs the model performing steps until current_time() equals
   *             end_time()
184
   */
185 186
  virtual void run()
  {
187 188
    if (output_policy() != OutputPolicy::None)
      write_data();
189

190
    while( Dune::FloatCmp::lt( current_time(), end_time()) )
191 192
    {
      step();
193

194 195
      if (adaptivity_policy() != AdaptivityPolicy::None)
        if ( Dune::FloatCmp::lt( current_time(), end_time()) )
196
        {
197 198 199 200
          mark_grid();
          pre_adapt_grid();
          adapt_grid();
          post_adapt_grid();
201 202 203
        }
    }
  }
204 205

private:
206 207
  OutputPolicy      _output_policy;
  AdaptivityPolicy  _adapt_policy;
208 209

protected:
210
  //! The logger of this model
211
  std::shared_ptr<spdlog::logger> _log;
212 213
};

Lukas Riedel's avatar
Lukas Riedel committed
214 215
/**
@{
216
  @class ModelBase
Lukas Riedel's avatar
Lukas Riedel committed
217

218
  ## Base class for models
Lukas Riedel's avatar
Lukas Riedel committed
219 220 221 222 223

  ### Stepping:
  
    The method `step()` must be an abstract method that always has to be 
    implemented by the derived class. The step must succeed always, otherwise, 
224
    it should throw a `ModelStepException`. It means that time adaptivity  
Lukas Riedel's avatar
Lukas Riedel committed
225 226 227 228 229 230 231 232
    must be done internally so that the time step succeeds.

  ### Writing data:

    The method `step()` must be able to decide whether to write data or not. 
    (Say that in one case one wants that transport writes that every step and in 
    another case one wants that it writes at the end of the Richards step. The 
    first case can't be covered writing data in the `run()` method of the 
233
    coupled model.) Then, enum class called `OutputPolicy`  must decide 
Lukas Riedel's avatar
Lukas Riedel committed
234 235 236 237 238 239 240
    whether to call the method `write_data()`. This policy can be set and be 
    extracted by the methods `set_policy(OutputPolicy)` and `output_policy()` 
    respectively.

    The method `write_data()` should be in charge of writing the data. 
    In principle, this method should be only used following the `OutputPolicy`. 
    Usually called at the end of each step and at the beginning of the 
241
    model. Since the `step()` method is in charge of it, it is assumed that 
Lukas Riedel's avatar
Lukas Riedel committed
242
    this method writes the *current* state of the model (e.g. intermediate 
243
    results of the coupled model for the transport state).
Lukas Riedel's avatar
Lukas Riedel committed
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275

  ### Adaptivity:

    For the purpose of having a generic `run()` method in this class, the sketch 
    of the adaptivity must be provided here. First, adaptivity must be never 
    done inside the method `step()`. Additionally, if the model can perform 
    adaptivity, it must provide the method `mark_grid()`, otherwise, it must 
    throw a `NotImplemented` exception. For completion, there must be a method 
    called `adapt_grid()` that pack all the known degrees of freedom and, the 
    grid function spaces and perform the adaptivity. 

    Similar to the idea of `OutputPolicy` there must be an `AdaptivityPolicy` 
    set by the methods `set_policy(AdaptivityPolicy)` and `adaptivity_policy()` 
    respectively which will be set by default to `AdaptivityPolicy::None`. 
    
    Having this separation between marking the grid and adaptivity of solutions 
    leave coupled models to decide which model will mark the grid inside its 
    method of `mark_grid()` and still handle the adaptivity implementing 
    `adapt_grid()` separately.

  ### Time control:

    A minimal interface is only providing `begin_time()`, `end_time()` and 
    `current_time()`. 

    In order to keep solution vectors minimal at the time of adaptivity, DORiE 
    expect the several models synchronized in time. Therefore, a good and still 
    minimal interface is only suggesting the timestep to the model via 
    `suggest_timestep(double dt)`. Such suggestion has to be taken into account 
    within the model, and the model must ensure that the timestep is done in 
    `step()` is never bigger than the suggested one so that coupled models can 
    achieve synchronization. Naturally, models have to ensure that 
276
    `begin_time()` \f$=\f$ `current_time()` when they are constructed.
Lukas Riedel's avatar
Lukas Riedel committed
277 278 279

  ### Local Operator Setup:

280
    Since adaptivity can modify the complete setup of the model, and since 
Lukas Riedel's avatar
Lukas Riedel committed
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
    the method `adapt_grid()` is not necessarily called by the model. 
    There is a need for the method `post_adapt_grid()` which is in charge of
    setup everything again to the new grid. Same argument holds for 
    `pre_adapt_grid()`.

  ### Run:

    With all the definitions given before, a general algorithm to run the 
    program can be given by following code:

    ```
    virtual void run()
    {
      if (output_policy() != OutputPolicy::None)
        write_data();

      while( current_time() < end_time() )
      {
        step();
        
        if (adaptivity_policy() != AdaptivityPolicy::None)
          if ( current_time() < end_time() )
          {
            mark_grid();
            pre_adapt_grid();
            adapt_grid();
            post_adapt_grid();
          }
      }
    }
    ```
@}

*/

316 317 318
} // namespace Dorie
} // namespace Dune

319
#endif // DUNE_DORIE_MODEL_BASE_HH