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