Flow123d  release_2.1.0-87-gfbc1563
transport_operator_splitting.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file transport_operator_splitting.cc
15  * @brief
16  */
17 
18 #include <iostream>
19 #include <iomanip>
20 
21 #include "system/system.hh"
22 #include "system/sys_profiler.hh"
23 
25 #include <petscmat.h>
26 
27 #include "io/output_time.hh"
28 #include "tools/time_governor.hh"
29 #include "system/sys_vector.hh"
30 #include "coupling/equation.hh"
31 #include "coupling/balance.hh"
32 #include "transport/transport.h"
33 #include "mesh/mesh.h"
34 
38 #include "reaction/sorption.hh"
40 
42 
43 #include "la/distribution.hh"
44 #include "input/input_type.hh"
45 #include "input/accessors.hh"
46 #include "input/factory.hh"
48 
49 FLOW123D_FORCE_LINK_IN_CHILD(transportOperatorSplitting);
50 
51 FLOW123D_FORCE_LINK_IN_PARENT(firstOrderReaction);
52 FLOW123D_FORCE_LINK_IN_PARENT(radioactiveDecay);
53 FLOW123D_FORCE_LINK_IN_PARENT(dualPorosity);
54 FLOW123D_FORCE_LINK_IN_PARENT(sorptionMobile);
55 FLOW123D_FORCE_LINK_IN_PARENT(sorptionImmobile);
57 
58 
59 using namespace Input::Type;
60 
61 
62 
64  return Abstract("Solute",
65  "Transport of soluted substances.")
66  .close();
67 }
68 
69 
71  return Record("Coupling_OperatorSplitting",
72  "Transport by convection and/or diffusion\n"
73  "coupled with reaction and adsorption model (ODE per element)\n"
74  " via operator splitting.")
76  .add_attribute( FlowAttribute::subfields_address(), "\"/problem/solute_equation/substances/*/name\"")
78  "Time governor setting for the secondary equation.")
79  .declare_key("balance", Balance::get_input_type(), Default("{}"),
80  "Settings for computing balance.")
82  "Parameters of output stream.")
84  "Specification of transported substances.")
85  // input data
87  "Type of numerical method for solute transport.")
89  "Reaction model involved in transport.")
90 /*
91  .declare_key("output_fields", Array(ConvectionTransport::get_output_selection()),
92  Default("\"conc\""),
93  "List of fields to write to output file.")*/
94  .close();
95 }
96 
97 
99  Input::register_class< TransportOperatorSplitting, Mesh &, const Input::Record>("Coupling_OperatorSplitting") +
101 
102 
103 
104 
105 
106 
107 
109 {
110 
111  ADD_FIELD(porosity, "Mobile porosity", "1.0");
112  porosity
113  .units( UnitSI::dimensionless() )
114  .flags_add(in_main_matrix & in_rhs);
115 
116  add_field(&water_content, "water_content", "INTERNAL - water content passed from unsaturated Darcy", "")
117  .units( UnitSI::dimensionless() )
118  .flags_add(input_copy & in_time_term & in_main_matrix & in_rhs);
119 
120  ADD_FIELD(cross_section, "");
121  cross_section.flags( FieldFlag::input_copy ).flags_add(in_time_term & in_main_matrix & in_rhs);
122 
123  ADD_FIELD(sources_density, "Density of concentration sources.", "0");
124  sources_density.units( UnitSI().kg().m(-3).s(-1) )
125  .flags_add(in_rhs);
126 
127  ADD_FIELD(sources_sigma, "Concentration flux.", "0");
128  sources_sigma.units( UnitSI().s(-1) )
129  .flags_add(in_main_matrix & in_rhs);
130 
131  ADD_FIELD(sources_conc, "Concentration sources threshold.", "0");
132  sources_conc.units( UnitSI().kg().m(-3) )
133  .flags_add(in_rhs);
134 }
135 
136 
137 
138 
139 
140 
141 
142 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
143 
144 
145 
147 : AdvectionProcessBase(init_mesh, in_rec),
148 // Semchem_reactions(NULL),
149  cfl_convection(numeric_limits<double>::max()),
150  cfl_reaction(numeric_limits<double>::max())
151 {
152  START_TIMER("TransportOperatorSpliting");
153 
154  Distribution *el_distribution;
155  int *el_4_loc;
156 
157  Input::AbstractRecord trans = in_rec.val<Input::AbstractRecord>("transport");
158  convection = trans.factory< ConcentrationTransportBase, Mesh &, const Input::Record >(init_mesh, trans);
159 
160  time_ = new TimeGovernor(in_rec.val<Input::Record>("time"));
161  convection->set_time_governor(time());
162 
163  // Initialize list of substances.
164  convection->substances().initialize(in_rec.val<Input::Array>("substances"));
165 
166  // Initialize output stream.
167  convection->set_output_stream(OutputTime::create_output_stream("solute", *mesh_, in_rec.val<Input::Record>("output_stream")));
168 
169 
170  // initialization of balance object
171 
172  balance_ = make_shared<Balance>("mass", mesh_);
173  balance_->init_from_input(in_rec.val<Input::Record>("balance"), this->time());
174 
175  if (balance_)
176  {
177  balance_->units(UnitSI().kg(1));
178  convection->set_balance_object(balance_);
179  }
180 
181  convection->initialize(); //
182 
183 
184 
185 
186  time_ = new TimeGovernor(in_rec.val<Input::Record>("time"), convection->mark_type());
187 
188  this->eq_data_ = &(convection->data());
189 
190  convection->get_par_info(el_4_loc, el_distribution);
191  Input::Iterator<Input::AbstractRecord> reactions_it = in_rec.find<Input::AbstractRecord>("reaction_term");
192  if ( reactions_it ) {
193  // TODO: allowed instances in this case are only
194  // FirstOrderReaction, RadioactiveDecay, SorptionSimple and DualPorosity
195  reaction = (*reactions_it).factory< ReactionTerm, Mesh &, Input::Record >(init_mesh, *reactions_it);
196 
197  reaction->substances(convection->substances())
198  .concentration_matrix(convection->get_concentration_matrix(),
199  el_distribution, el_4_loc, convection->get_row_4_el())
200  .output_stream(convection->output_stream())
201  .set_time_governor((TimeGovernor &)convection->time());
202 
203  reaction->initialize();
204 
205  } else {
206  reaction = nullptr;
207  //Semchem_reactions = nullptr;
208  }
209 }
210 
212 {
213  //delete field_output;
214  //if (Semchem_reactions) delete Semchem_reactions;
215  delete time_;
216 }
217 
218 
220 {
221  //coupling - passing fields
222  if(reaction)
223  if( typeid(*reaction) == typeid(SorptionSimple) ||
224  typeid(*reaction) == typeid(DualPorosity)
225  )
226  {
227  reaction->data().set_field("porosity", convection->data()["porosity"]);
228  }
229 }
230 
231 
232 
233 
235 
236 
237  START_TIMER("TOS-output data");
238 
239 
240  convection->output_data();
241  if(reaction) reaction->output_data(); // do not perform write_time_frame
242  convection->output_stream()->write_time_frame();
243 
244  if (balance_ != nullptr && balance_->is_current( time_->step() ) )
245  {
246  START_TIMER("TOS-balance");
247  convection->calculate_instant_balance();
248  balance_->output(time_->t());
249  END_TIMER("TOS-balance");
250  }
251 
252  END_TIMER("TOS-output data");
253 }
254 
255 
257 {
258  //DebugOut() << "tos ZERO TIME STEP.\n";
259  convection->zero_time_step();
260  if(reaction) reaction->zero_time_step();
261  output_data();
262 
263 }
264 
265 
266 
268 
269  vector<double> source(convection->n_substances()), region_mass(mesh_->region_db().bulk_size());
270 
271  time_->next_time();
272  time_->view("TOS"); //show time governor
273 
274  convection->set_target_time(time_->t());
275 
276  START_TIMER("TOS-one step");
277  int steps=0;
278  while ( convection->time().step().lt(time_->t()) )
279  {
280  steps++;
281  // one internal step
282  // we call evaluate_time_constraint() of convection and reaction separately to
283  // make sure that both routines are executed.
284  bool cfl_convection_changed = convection->evaluate_time_constraint(cfl_convection);
285  bool cfl_reaction_changed = (reaction?reaction->evaluate_time_constraint(cfl_reaction):0);
286  bool cfl_changed = cfl_convection_changed || cfl_reaction_changed;
287 
288  if (steps == 1 || cfl_changed)
289  {
290  convection->time().set_upper_constraint(cfl_convection, "Time step constrained by transport CFL condition (including both flow and sources).");
291  convection->time().set_upper_constraint(cfl_reaction, "Time step constrained by reaction CFL condition.");
292 
293  // fix step with new constraint
294  convection->time().fix_dt_until_mark();
295 
296  convection->time().view("Convection"); // write TG only once on change
297  }
298 
299  convection->update_solution();
300 
301 
302  if (balance_ != nullptr && balance_->cumulative())
303  {
304  START_TIMER("TOS-balance");
305 
306  // save mass after transport step
307  for (unsigned int sbi=0; sbi<convection->n_substances(); sbi++)
308  {
309  balance_->calculate_mass(convection->get_subst_idx()[sbi], convection->get_solution(sbi), region_mass);
310  source[sbi] = 0;
311  for (unsigned int ri=0; ri<mesh_->region_db().bulk_size(); ri++)
312  source[sbi] -= region_mass[ri];
313  }
314 
315  END_TIMER("TOS-balance");
316  }
317 
318  if(reaction) {
319  convection->calculate_concentration_matrix();
320  reaction->update_solution();
321  convection->update_after_reactions(true);
322  }
323  else
324  convection->update_after_reactions(false);
325 
326  //if(Semchem_reactions) Semchem_reactions->update_solution();
327 
328 
329 
330  if (balance_ != nullptr && balance_->cumulative())
331  {
332  START_TIMER("TOS-balance");
333 
334  for (unsigned int sbi=0; sbi<convection->n_substances(); sbi++)
335  {
336  // compute mass difference due to reactions
337  balance_->calculate_mass(convection->get_subst_idx()[sbi], convection->get_solution(sbi), region_mass);
338  for (unsigned int ri=0; ri<mesh_->region_db().bulk_size(); ri++)
339  source[sbi] += region_mass[ri];
340 
341  // update balance of sources due to reactions
342  balance_->add_cumulative_source(sbi, source[sbi]);
343  }
344 
345  END_TIMER("TOS-balance");
346  }
347  }
348 
349  LogOut().fmt("CONVECTION: steps: {}\n", steps);
350 }
351 
352 
353 
354 
355 
357 {
358  convection->set_velocity_field( dh );
359 };
360 
361 
362 
363 
TimeGovernor & time()
Definition: equation.hh:148
FieldSet * eq_data_
Definition: equation.hh:232
static const Input::Type::Record & get_input_type()
Main balance input record type.
Definition: balance.cc:42
Abstract base class for equation clasess.
Accessor to input data conforming to declared Array.
Definition: accessors.hh:561
unsigned int size() const
Returns number of keys in the Record.
Definition: type_record.hh:593
unsigned int bulk_size() const
Definition: region.cc:268
static const Input::Type::Record & get_input_type()
Declare input record type for the equation TransportOperatorSplittiong.
static const Input::Type::Record & get_input_type()
The specification of output stream.
Definition: output_time.cc:38
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:56
virtual void set_velocity_field(const MH_DofHandler &dh) override
void next_time()
Proceed to the next time according to current estimated time step.
static Default obligatory()
The factory function to make an empty default value which is obligatory.
Definition: type_record.hh:105
Definition: mesh.h:95
Iterator< Ret > find(const string &key) const
static string subfields_address()
const RegionDB & region_db() const
Definition: mesh.h:147
static const Input::Type::Record & get_input_type()
Input type for a substance.
Definition: substance.cc:29
const TimeStep & step(int index=-1) const
TransportOperatorSplitting(Mesh &init_mesh, const Input::Record in_rec)
Constructor.
static Input::Type::Abstract & get_input_type()
Common specification of the input record for secondary equations.
double t() const
Abstract & close()
Close the Abstract and add its to type repository (see TypeRepository::add_type). ...
#define ADD_FIELD(name,...)
Definition: field_set.hh:269
Basic time management functionality for unsteady (and steady) solvers (class Equation).
#define LogOut()
Macro defining &#39;log&#39; record of log.
Definition: logger.hh:237
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:301
Basic time management class.
Class for declaration of inputs sequences.
Definition: type_base.hh:339
void view(const char *name="") const
Class ReactionTerm is an abstract class representing reaction term in transport.
Class Dual_por_exchange implements the model of dual porosity.
virtual Record & derive_from(Abstract &parent)
Method to derive new Record from an AbstractRecord parent.
Definition: type_record.cc:193
static Default optional()
The factory function to make an empty default value which is optional.
Definition: type_record.hh:119
static Input::Type::Abstract & get_input_type()
Common specification of the input record for secondary equations.
std::shared_ptr< ReactionTerm > reaction
Record & add_attribute(std::string key, TypeBase::json_string value)
Add TYPE key as obligatory.
Definition: type_record.cc:350
static constexpr Mask input_copy
Definition: field_flag.hh:44
Accessor to the data with type Type::Record.
Definition: accessors.hh:286
const Ret val(const string &key) const
#define START_TIMER(tag)
Starts a timer with specified tag.
Mesh * mesh_
Definition: equation.hh:223
double cfl_convection
Time restriction due to transport.
std::shared_ptr< Balance > balance_
object for calculation and writing the mass balance to file.
Definition: equation.hh:235
Record & declare_key(const string &key, std::shared_ptr< TypeBase > type, const Default &default_value, const string &description, TypeBase::attribute_map key_attributes=TypeBase::attribute_map())
Declares a new key of the Record.
Definition: type_record.cc:488
FLOW123D_FORCE_LINK_IN_CHILD(transportOperatorSplitting)
Class for declaration of polymorphic Record.
Class representing dual porosity model in transport.
Accessor to the polymorphic input data of a type given by an AbstracRecord object.
Definition: accessors.hh:453
virtual void set_time_governor(TimeGovernor &time)
Definition: equation.cc:55
static Input::Type::Abstract & it_abstract_term()
Support classes for parallel programing.
static std::shared_ptr< OutputTime > create_output_stream(const std::string &equation_name, Mesh &mesh, const Input::Record &in_rec)
This method delete all object instances of class OutputTime stored in output_streams vector...
Definition: output_time.cc:191
void output_data() override
Write computed fields.
std::shared_ptr< ConcentrationTransportBase > convection
FLOW123D_FORCE_LINK_IN_PARENT(firstOrderReaction)
Vector classes to support both Iterator, index and Id access and creating co-located vectors...
static const Input::Type::Record & get_input_type()
#define END_TIMER(tag)
Ends a timer with specified tag.
double cfl_reaction
Time restriction due to reactions.
Simple sorption model without dual porosity.
Definition: sorption.hh:39
Record type proxy class.
Definition: type_record.hh:177
const std::shared_ptr< Type > factory(Arguments...arguments) const
Class for representation SI units of Fields.
Definition: unit_si.hh:40
static UnitSI & dimensionless()
Returns dimensionless unit.
Definition: unit_si.cc:55
This file contains classes representing sorption model. Sorption model can be computed both in case t...
TimeGovernor * time_
Definition: equation.hh:224
virtual ~TransportOperatorSplitting()
Destructor.
static const int registrar
Registrar of class to factory.