Flow123d  jenkins-Flow123d-windows32-release-multijob-28
field.impl.hh
Go to the documentation of this file.
1 /*
2  * field.impl.hh
3  *
4  * Created on: Feb 13, 2014
5  * Author: jb
6  */
7 
8 #ifndef FIELD_IMPL_HH_
9 #define FIELD_IMPL_HH_
10 
11 #include <boost/foreach.hpp>
12 
13 #include "field.hh"
14 #include "mesh/region.hh"
15 #include "input/json_to_storage.hh"
16 
17 
18 /******************************************************************************************
19  * Implementation of Field<...>
20  */
21 
22 template<int spacedim, class Value>
24 : read_field_descriptor_hook( &read_field_descriptor ),
25  data_(std::make_shared<SharedData>())
26 
27 {
28  // n_comp is nonzero only for variable size vectors Vector, VectorEnum, ..
29  // this invariant is kept also by n_comp setter
30  shared_->n_comp_ = (Value::NRows_ ? 0 : 1);
31 }
32 
33 
34 template<int spacedim, class Value>
35 Field<spacedim,Value>::Field(const string &name, bool bc)
36 : read_field_descriptor_hook( &read_field_descriptor ),
37  data_(std::make_shared<SharedData>())
38 
39 {
40  // n_comp is nonzero only for variable size vectors Vector, VectorEnum, ..
41  // this invariant is kept also by n_comp setter
42  shared_->n_comp_ = (Value::NRows_ ? 0 : 1);
43  shared_->bc_=bc;
44  this->name( name );
45 }
46 
47 
48 
49 template<int spacedim, class Value>
51 : FieldCommon(other),
52  read_field_descriptor_hook( other.read_field_descriptor_hook ),
53  data_(other.data_)
54 {
55  if (other.no_check_control_field_)
56  no_check_control_field_ = make_shared<ControlField>(*other.no_check_control_field_);
57 
58  // initialize region_fields_ vector
59  // shared_is already same as other.shared_
60  if (shared_->mesh_) this->set_mesh( *(shared_->mesh_) );
61 
62 }
63 
64 
65 template<int spacedim, class Value>
67 {
68  ASSERT( flags().match( FieldFlag::input_copy ) , "Try to assign to non-copy field '%s' from the field '%s'.", this->name().c_str(), other.name().c_str());
69  ASSERT(other.shared_->mesh_, "Must call set_mesh before assign to other field.\n");
70  ASSERT( !shared_->mesh_ || (shared_->mesh_==other.shared_->mesh_),
71  "Assignment between fields with different meshes.\n");
72 
73  // check for self assignement
74  if (&other == this) return *this;
75 
76  shared_ = other.shared_;
77  shared_->is_fully_initialized_ = false;
78  set_time_result_ = TimeStatus::unknown;
79 
80  read_field_descriptor_hook = other.read_field_descriptor_hook;
81  data_ = other.data_;
82 
83  if (other.no_check_control_field_) {
84  no_check_control_field_ = make_shared<ControlField>(*other.no_check_control_field_);
85  }
86 
87  // initialize region_fields_ vector
88  // shared_is already same as other.shared_
89  this->set_mesh( *(shared_->mesh_) );
90 
91 
92  return *this;
93 }
94 
95 
96 
97 template<int spacedim, class Value>
99  /*
100  * List of AbstratRecord types created by make_input_tree() in get_input_type() implementation.
101  * We have to return reference, which may be reference to not yet initialized static object.
102  *
103  * TODO: Have method to get persistent copy of an Input Type (which exists nevertheless)
104  */
105  static vector<it::AbstractRecord> ar_list;
106 
107  if (is_enum_valued) {
108  ar_list.push_back(make_input_tree());
109  return ar_list.back();
110  } else {
111  return FieldBaseType::input_type;
112  }
113 }
114 
115 
116 
117 /// ---------- Helper function template for make_input_tree method
118 template <class FieldBaseType>
120 {
121  ASSERT( sel != nullptr,
122  "NULL pointer to selection in Field::get_input_type(), while Value==FieldEnum.\n");
123  return FieldBaseType::get_input_type(sel);
124 }
125 
126 
127 template <class FieldBaseType>
129 {
130  return FieldBaseType::get_input_type(nullptr);
131 }
132 /// ---------- end helper function template
133 
134 
135 
136 
137 template<int spacedim, class Value>
139  ASSERT(is_enum_valued,
140  "Can not use make_input_tree() for non-enum valued fields, use get_inout_type() instead.\n" );
141  return get_input_type_resolution<FieldBaseType>(
142  shared_->input_element_selection_ ,
143  boost::is_same<typename Value::element_type, FieldEnum>());
144 }
145 
146 
147 
148 template<int spacedim, class Value>
150  const Field<spacedim, typename FieldValue<spacedim>::Enum > &control_field,
151  const vector<FieldEnum> &value_list) -> Field &
152 {
153  no_check_control_field_=std::make_shared<ControlField>(control_field);
154  shared_->no_check_values_=value_list;
155  return *this;
156 }
157 
158 template<int spacedim, class Value>
159 void Field<spacedim,Value>::set_mesh(const Mesh &in_mesh) {
160  // since we allow copy of fields before set_mesh is called
161  // we have to check that all copies set the same mesh
162  if (shared_->mesh_ && shared_->mesh_ != &in_mesh) {
163  THROW(ExcFieldMeshDifference() << EI_Field(name()) );
164  }
165 
166  shared_->mesh_ = &in_mesh;
167 
168  // initialize table if it is empty, we assume that the RegionDB is closed at this moment
169  region_fields_.resize( mesh()->region_db().size() );
170  RegionHistory init_history(history_length_limit_); // capacity
171  data_->region_history_.resize( mesh()->region_db().size(), init_history );
172 
173  if (no_check_control_field_) no_check_control_field_->set_mesh(in_mesh);
174 }
175 
176 
177 /*
178 template<int spacedim, class Value>
179 boost::shared_ptr< typename Field<spacedim,Value>::FieldBaseType >
180 Field<spacedim,Value>::operator[] (Region reg)
181 {
182  ASSERT_LESS(reg.idx(), this->region_fields_.size());
183  return this->region_fields_[reg.idx()];
184 }
185 */
186 
187 
188 template <int spacedim, class Value>
190  ASSERT_LESS(reg.idx(), this->region_fields_.size());
191  FieldBasePtr region_field = this->region_fields_[reg.idx()];
192  return (region_field && typeid(*region_field) == typeid(FieldConstant<spacedim, Value>));
193 }
194 
195 /*
196 template<int spacedim, class Value>
197 void Field<spacedim, Value>::set_from_input(const RegionSet &domain, const Input::AbstractRecord &rec) {
198  boost::shared_ptr<FieldBaseType> field = FieldBaseType::function_factory(rec, this->n_comp_);
199  set_field(domain, field);
200 }
201 
202 */
203 
204 template<int spacedim, class Value>
206  const RegionSet &domain,
207  FieldBasePtr field,
208  double time)
209 {
210  ASSERT(field, "Null field pointer.\n");
211 
212  //DBGMSG("test value: %g\n", pressure);
213 
214  ASSERT( mesh(), "Null mesh pointer, set_mesh() has to be called before set_field().\n");
215  if (domain.size() == 0) return;
216 
217  ASSERT_EQUAL( field->n_comp() , n_comp());
218  field->set_mesh( mesh() , is_bc() );
219 
220  HistoryPoint hp = HistoryPoint(time, field);
221  for(const Region &reg: domain) {
222  RegionHistory &region_history = data_->region_history_[reg.idx()];
223  // insert hp into descending time sequence
224  ASSERT( region_history.size() == 0 || region_history[0].first < hp.first, "Can not insert smaller time %g then last time %g in field's history.\n",
225  hp.first, region_history[0].first );
226  region_history.push_front(hp);
227  }
228  set_history_changed();
229 }
230 
231 
232 
233 template<int spacedim, class Value>
235  const RegionSet &domain,
236  const Input::AbstractRecord &a_rec,
237  double time)
238 {
239  set_field(domain, FieldBaseType::function_factory(a_rec, n_comp()), time);
240 }
241 
242 
243 
244 template<int spacedim, class Value>
246 {
247  Input::AbstractRecord field_record;
248  if (rec.opt_val(field.input_name(), field_record))
249  return FieldBaseType::function_factory(field_record, field.n_comp() );
250  else
251  return FieldBasePtr();
252 }
253 
254 
255 
256 
257 template<int spacedim, class Value>
259 {
260  ASSERT( mesh() , "NULL mesh pointer of field '%s'. set_mesh must be called before.\n",name().c_str());
261  ASSERT( limit_side_ != LimitSide::unknown, "Must set limit side on field '%s' before calling set_time.\n",name().c_str());
262 
263  // We perform set_time only once for every time.
264  if (time.t() == last_time_) return changed();
265  last_time_=time.t();
266 
267  // possibly update our control field
268  if (no_check_control_field_) {
269  no_check_control_field_->set_limit_side(limit_side_);
270  no_check_control_field_->set_time(time);
271  }
272 
273  set_time_result_ = TimeStatus::constant;
274 
275  // read all descriptors satisfying time.ge(input_time)
276  update_history(time);
277  check_initialized_region_fields_();
278 
279  // set time on all regions
280  // for regions that match type of the field domain
281  for(const Region &reg: mesh()->region_db().get_region_set("ALL") ) {
282  auto rh = data_->region_history_[reg.idx()];
283 
284  // skip regions with no matching BC flag
285  // skipping regions with empty history - no_check regions
286  if (reg.is_boundary() == is_bc() && !rh.empty() ) {
287  double last_time_in_history = rh.front().first;
288  unsigned int history_size=rh.size();
289  unsigned int i_history;
290  // set history index
291  if ( time.gt(last_time_in_history) ) {
292  // in smooth time
293  i_history=0;
294  } else {
295  // time .eq. input_time; i.e. jump time
296  if (limit_side_ == LimitSide::right) {
297  i_history=0;
298  } else {
299  i_history=1;
300  }
301  }
302  i_history=min(i_history, history_size - 1);
303  ASSERT(i_history >= 0, "Empty field history.");
304  // possibly update field pointer
305  auto new_ptr = rh.at(i_history).second;
306  if (new_ptr != region_fields_[reg.idx()]) {
307  region_fields_[reg.idx()]=new_ptr;
308  set_time_result_ = TimeStatus::changed;
309  }
310  // let FieldBase implementation set the time
311  //DBGMSG("Call particular set time, field: %s t: %g\n",this->name().c_str(), time.t());
312  if ( new_ptr->set_time(time.t()) ) set_time_result_ = TimeStatus::changed;
313 
314  }
315  }
316 
317 // this->changed_during_set_time = this->changed_from_last_set_time_;
318 // this->changed_from_last_set_time_ = false;
319  return changed();
320 }
321 
322 
323 template<int spacedim, class Value>
325  ASSERT( flags().match(FieldFlag::input_copy), "Try to call copy from the field '%s' to the non-copy field '%s'.",
326  other.name().c_str(), this->name().c_str());
327  if (typeid(other) == typeid(*this)) {
328  auto const &other_field = dynamic_cast< Field<spacedim, Value> const &>(other);
329  this->operator=(other_field);
330  }
331 }
332 
333 
334 
335 template<int spacedim, class Value>
337 {
338  // currently we cannot output boundary fields
339  if (!is_bc())
340  stream->register_data(this->output_type(), *this);
341 }
342 
343 
344 
345 template<int spacedim, class Value>
347  auto f = region_fields_[elm.region().idx()];
348  if (f) return f->field_result();
349  else return result_none;
350 }
351 
352 
353 
354 template<int spacedim, class Value>
356  ASSERT( mesh(), "Null mesh pointer, set_mesh() has to be called before.\n");
357 
358  // read input up to given time
359  double input_time;
360  if (shared_->input_list_.size() != 0) {
361  while( shared_->list_it_ != shared_->input_list_.end()
362  && time.ge( input_time = shared_->list_it_->val<double>("time") ) ) {
363 
364  // get domain specification
365  RegionSet domain;
366  std::string domain_name;
367  unsigned int id;
368  if (shared_->list_it_->opt_val("r_set", domain_name)) {
369  domain = mesh()->region_db().get_region_set(domain_name);
370 
371  } else if (shared_->list_it_->opt_val("region", domain_name)) {
372  // try find region by label
373  Region region = mesh()->region_db().find_label(domain_name);
374  if(region.is_valid())
375  domain.push_back(region);
376  else
377  xprintf(Warn, "Unknown region with label: '%s'\n", domain_name.c_str());
378 
379  } else if (shared_->list_it_->opt_val("rid", id)) {
380  // try find region by ID
381  Region region = mesh()->region_db().find_id(id);
382  if(region.is_valid())
383  domain.push_back(region);
384  else
385  xprintf(Warn, "Unknown region with id: '%d'\n", id);
386  } else {
387  THROW(ExcMissingDomain()
388  << shared_->list_it_->ei_address() );
389  }
390 
391  if (domain.size() == 0) {
392  ++shared_->list_it_;
393  continue;
394  }
395  // get field instance
396  FieldBasePtr field_instance = read_field_descriptor_hook(*(shared_->list_it_), *this);
397  if (field_instance) // skip descriptors without related keys
398  {
399  // add to history
400  ASSERT_EQUAL( field_instance->n_comp() , n_comp());
401  field_instance->set_mesh( mesh() , is_bc() );
402  for(const Region &reg: domain) {
403  data_->region_history_[reg.idx()].push_front(
404  HistoryPoint(input_time, field_instance)
405  );
406  }
407  }
408  ++shared_->list_it_;
409  }
410  }
411 }
412 
413 template<int spacedim, class Value>
415  ASSERT(mesh(), "Null mesh pointer.");
416  if (shared_->is_fully_initialized_) return;
417 
418  // check there are no empty field pointers, collect regions to be initialized from default value
419  RegionSet regions_to_init; // empty vector
420 
421  for(const Region &reg : mesh()->region_db().get_region_set("ALL") )
422  if (reg.is_boundary() == is_bc()) { // for regions that match type of the field domain
423  RegionHistory &rh = data_->region_history_[reg.idx()];
424  if ( rh.empty() || ! rh[0].second) // empty region history
425  {
426  // test if check is turned on and control field is FieldConst
427  if (no_check_control_field_ && no_check_control_field_->is_constant(reg) ) {
428  // get constant enum value
429  auto elm = ElementAccessor<spacedim>(mesh(), reg);
430  FieldEnum value = no_check_control_field_->value(elm.centre(),elm);
431  // check that the value is in the disable list
432  if ( std::find(shared_->no_check_values_.begin(), shared_->no_check_values_.end(), value)
433  != shared_->no_check_values_.end() )
434  continue; // the field is not needed on this region
435  }
436  if (shared_->input_default_ != "") { // try to use default
437  regions_to_init.push_back( reg );
438  } else {
439  xprintf(UsrErr, "Missing value of the input field '%s' ('%s') on region ID: %d label: %s.\n",
440  input_name().c_str(), name().c_str(), reg.id(), reg.label().c_str() );
441  }
442  }
443  }
444 
445  // possibly set from default value
446  if ( regions_to_init.size() ) {
447  xprintf(Warn, "Using default value '%s' for part of the input field '%s' ('%s').\n",
448  input_default().c_str(), input_name().c_str(), name().c_str());
449 
450  // has to deal with fact that reader can not deal with input consisting of simple values
451  string default_input=input_default();
452  auto input_type = get_input_type();
453  Input::JSONToStorage reader( default_input, input_type );
454 
455  auto a_rec = reader.get_root_interface<Input::AbstractRecord>();
456  auto field_ptr = FieldBaseType::function_factory( a_rec , n_comp() );
457  field_ptr->set_mesh( mesh(), is_bc() );
458  for(const Region &reg: regions_to_init) {
459  data_->region_history_[reg.idx()]
460  .push_front(HistoryPoint( 0.0, field_ptr) );
461  }
462  }
463  shared_->is_fully_initialized_;
464 }
465 
466 
467 
468 //template<int spacedim, class Value>
469 //BCField<spacedim, Value>::BCField() { this->bc_=true; }
470 
471 
472 
473 
474 
475 /******************************************************************************************
476  * Implementation of MultiField<...>
477  */
478 
479 template<int spacedim, class Value>
481 : FieldCommon()
482 {}
483 
484 
485 
486 template<int spacedim, class Value>
488  sub_fields_.resize( names.size() );
489  sub_names_ = names;
490  for(unsigned int i_comp=0; i_comp < size(); i_comp++)
491  {
492  sub_fields_[i_comp].units( units() );
493 
494  if (sub_names_[i_comp].length() == 0)
495  sub_fields_[i_comp].name( name() );
496  else
497  sub_fields_[i_comp].name( sub_names_[i_comp] + "_" + name());
498  }
499 }
500 
501 
502 
503 #pragma GCC diagnostic push
504 #pragma GCC diagnostic ignored "-Wreturn-type"
505 template<int spacedim, class Value>
507 }
508 #pragma GCC diagnostic pop
509 
510 
511 template<int spacedim, class Value>
513 {
514  for ( SubFieldType &field : sub_fields_)
515  field.set_limit_side(side);
516 }
517 
518 
519 template<int spacedim, class Value>
521  const TimeGovernor &time)
522 {
523  bool any=false;
524  for( SubFieldType &field : sub_fields_) {
525  if (field.set_time(time))
526  any = true;
527  }
528  return any;
529 }
530 
531 
532 
533 template<int spacedim, class Value>
535  shared_->mesh_ = &mesh;
536  for(unsigned int i_comp=0; i_comp < size(); i_comp++)
537  sub_fields_[i_comp].set_mesh(mesh);
538 }
539 
540 
541 template<int spacedim, class Value>
543  if (typeid(other) == typeid(*this)) {
544  auto const &other_field = dynamic_cast< MultiField<spacedim, Value> const &>(other);
545  this->operator=(other_field);
546  } else if (typeid(other) == typeid(SubFieldType)) {
547  auto const &other_field = dynamic_cast< SubFieldType const &>(other);
548  sub_fields_.resize(1);
549  sub_fields_[0] = other_field;
550  }
551 }
552 
553 
554 
555 template<int spacedim, class Value>
557 {
558  // currently we cannot output boundary fields
559  if (!is_bc())
560  stream->register_data(this->output_type(), *this);
561 }
562 
563 
564 
565 
566 
567 template<int spacedim, class Value>
569  bool const_all=false;
570  for(auto field : sub_fields_) const_all = const_all || field.is_constant(reg);
571  return const_all;
572 }
573 
574 
575 
576 
577 
578 #endif /* FIELD_IMPL_HH_ */
void check_initialized_region_fields_()
Definition: field.impl.hh:414
Common abstract parent of all Field<...> classes.
Definition: field_common.hh:45
pair< double, FieldBasePtr > HistoryPoint
Pair: time, pointer to FieldBase instance.
Definition: field.hh:234
void init(const vector< string > &names)
Definition: field.impl.hh:487
void output(OutputTime *stream) override
Definition: field.impl.hh:336
void set_limit_side(LimitSide side) override
Definition: field.impl.hh:512
void update_history(const TimeGovernor &time)
Definition: field.impl.hh:355
FieldBasePtr(* read_field_descriptor_hook)(Input::Record rec, const FieldCommon &field)
Definition: field.hh:71
IT::AbstractRecord make_input_tree()
-------— end helper function template
Definition: field.impl.hh:138
void copy_from(const FieldCommon &other) override
Definition: field.impl.hh:542
Class template representing a field with values dependent on: point, element, and region...
Definition: field.hh:48
void register_data(const DiscreteSpace type, MultiField< spacedim, Value > &multi_field)
Generic method for registering output data stored in MultiField.
Definition: output.h:243
bool ge(double other_time) const
Definition: mesh.h:108
double t() const
Basic time management functionality for unsteady (and steady) solvers (class Equation).
Field()
Definition: field.impl.hh:23
std::shared_ptr< SharedData > data_
Definition: field.hh:248
FieldResult field_result(ElementAccessor< spacedim > &elm) const
Definition: field.impl.hh:346
IT::AbstractRecord & get_input_type() override
Definition: field.impl.hh:98
std::shared_ptr< SharedData > shared_
#define ASSERT(...)
Definition: global_defs.h:120
Definition: system.hh:75
const std::string & name() const
unsigned int FieldEnum
Definition: field_values.hh:66
static constexpr Mask input_copy
A field that is input of its equation and cna not read from input, thus muzt be set by copy...
Definition: field_flag.hh:29
#define ASSERT_EQUAL(a, b)
Definition: global_defs.h:135
Accessor to the data with type Type::Record.
Definition: accessors.hh:308
#define xprintf(...)
Definition: system.hh:104
#define ASSERT_LESS(a, b)
Definition: global_defs.h:163
std::shared_ptr< ControlField > no_check_control_field_
Definition: field.hh:258
Class for declaration of polymorphic Record.
Definition: type_record.hh:467
IT::AbstractRecord & get_input_type() override
Definition: field.impl.hh:506
The class for outputing data during time.
Definition: output_time.hh:37
Accessor to the polymorphic input data of a type given by an AbstracRecord object.
Definition: accessors.hh:423
Region region() const
Definition: accessors.hh:88
IT::AbstractRecord get_input_type_resolution(const Input::Type::Selection *sel, const boost::true_type &)
-------— Helper function template for make_input_tree method
Definition: field.impl.hh:119
FieldResult
Result type have sense only for larger Value types like vectors and tensors.
Definition: system.hh:75
std::shared_ptr< FieldBaseType > FieldBasePtr
Definition: field.hh:52
bool is_constant(Region reg) override
Definition: field.impl.hh:568
auto disable_where(const Field< spacedim, typename FieldValue< spacedim >::Enum > &control_field, const vector< FieldEnum > &value_list) -> Field &
Definition: field.impl.hh:149
boost::circular_buffer< HistoryPoint > RegionHistory
Nearest history of one region.
Definition: field.hh:236
bool is_constant(Region reg) override
Definition: field.impl.hh:189
void set_field(const RegionSet &domain, FieldBasePtr field, double time=0.0)
Definition: field.impl.hh:205
bool set_time(const TimeGovernor &time) override
Definition: field.impl.hh:258
bool set_time(const TimeGovernor &time) override
Definition: field.impl.hh:520
FieldCommon & name(const string &name)
Definition: field_common.hh:71
void set_mesh(const Mesh &mesh) override
Definition: field.impl.hh:159
static FieldBasePtr read_field_descriptor(Input::Record rec, const FieldCommon &field)
Definition: field.impl.hh:245
void output(OutputTime *stream) override
Definition: field.impl.hh:556
Class for representation of a vector of fields of the same physical quantity.
Definition: field.hh:309
bool is_valid() const
Returns false if the region has undefined/invalid value.
Definition: region.hh:70
void copy_from(const FieldCommon &other) override
Definition: field.impl.hh:324
bool gt(double other_time) const
Reader for (slightly) modified JSON files.
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:34
void set_mesh(const Mesh &mesh) override
Definition: field.impl.hh:534
Template for classes storing finite set of named values.
Field & operator=(const Field &other)
Definition: field.impl.hh:66
LimitSide
Definition: field_common.hh:31
unsigned int idx() const
Returns a global index of the region.
Definition: region.hh:74