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  domain.push_back( mesh()->region_db().find_label(domain_name) ); // try find region by label
368  if (! domain[0].is_valid() ) xprintf(Warn, "Unknown region with label: '%s'\n", domain_name.c_str());
369 
370  } else if (shared_->list_it_->opt_val("rid", id)) {
371  domain.push_back( mesh()->region_db().find_id(id) ); // try find region by ID
372  if (! domain[0].is_valid() ) xprintf(Warn, "Unknown region with id: '%d'\n", id);
373 
374  } else {
375  THROW(ExcMissingDomain()
376  << EI_Field(this->name())
377  << shared_->list_it_->ei_address() );
378  }
379  if (domain.size() == 0) continue;
380 
381  // get field instance
382  FieldBasePtr field_instance = read_field_descriptor_hook(*(shared_->list_it_), *this);
383  if (field_instance) // skip descriptors without related keys
384  {
385  // add to history
386  ASSERT_EQUAL( field_instance->n_comp() , n_comp());
387  field_instance->set_mesh( mesh() , is_bc() );
388  for(const Region &reg: domain) {
389  data_->region_history_[reg.idx()].push_front(
390  HistoryPoint(input_time, field_instance)
391  );
392  }
393  }
394  ++shared_->list_it_;
395  }
396  }
397 }
398 
399 template<int spacedim, class Value>
401  ASSERT(mesh(), "Null mesh pointer.");
402  if (shared_->is_fully_initialized_) return;
403 
404  // check there are no empty field pointers, collect regions to be initialized from default value
405  RegionSet regions_to_init; // empty vector
406 
407  for(const Region &reg : mesh()->region_db().get_region_set("ALL") )
408  if (reg.is_boundary() == is_bc()) { // for regions that match type of the field domain
409  RegionHistory &rh = data_->region_history_[reg.idx()];
410  if ( rh.empty() || ! rh[0].second) // empty region history
411  {
412  // test if check is turned on and control field is FieldConst
413  if (no_check_control_field_ && no_check_control_field_->is_constant(reg) ) {
414  // get constant enum value
415  auto elm = ElementAccessor<spacedim>(mesh(), reg);
416  FieldEnum value = no_check_control_field_->value(elm.centre(),elm);
417  // check that the value is in the disable list
418  if ( std::find(shared_->no_check_values_.begin(), shared_->no_check_values_.end(), value)
419  != shared_->no_check_values_.end() )
420  continue; // the field is not needed on this region
421  }
422  if (shared_->default_ != "") { // try to use default
423  regions_to_init.push_back( reg );
424  } else {
425  xprintf(UsrErr, "Missing value of the field '%s' on region ID: %d label: %s.\n",
426  name().c_str(), reg.id(), reg.label().c_str() );
427  }
428  }
429  }
430 
431  // possibly set from default value
432  if ( regions_to_init.size() ) {
433  xprintf(Warn, "Using default value '%s' for part of field '%s'.\n", input_default().c_str(), name().c_str());
434 
435  // has to deal with fact that reader can not deal with input consisting of simple values
436  string default_input=input_default();
437  auto input_type = get_input_type();
438  Input::JSONToStorage reader( default_input, input_type );
439 
440  auto a_rec = reader.get_root_interface<Input::AbstractRecord>();
441  auto field_ptr = FieldBaseType::function_factory( a_rec , n_comp() );
442  field_ptr->set_mesh( mesh(), is_bc() );
443  for(const Region &reg: regions_to_init) {
444  data_->region_history_[reg.idx()]
445  .push_front(HistoryPoint( 0.0, field_ptr) );
446  }
447  }
448  shared_->is_fully_initialized_;
449 }
450 
451 
452 
453 //template<int spacedim, class Value>
454 //BCField<spacedim, Value>::BCField() { this->bc_=true; }
455 
456 
457 
458 
459 
460 /******************************************************************************************
461  * Implementation of MultiField<...>
462  */
463 
464 template<int spacedim, class Value>
466 : FieldCommonBase()
467 {}
468 
469 
470 
471 template<int spacedim, class Value>
473  sub_fields_.resize( names.size() );
474  sub_names_ = names;
475  for(unsigned int i_comp=0; i_comp < size(); i_comp++)
476  {
477  sub_fields_[i_comp].units( units() );
478 
479  if (sub_names_[i_comp].length() == 0)
480  sub_fields_[i_comp].name( name() );
481  else
482  sub_fields_[i_comp].name( sub_names_[i_comp] + "_" + name());
483  }
484 }
485 
486 
487 
488 template<int spacedim, class Value>
490 }
491 
492 
493 template<int spacedim, class Value>
495 {
496  for ( SubFieldType &field : sub_fields_)
497  field.set_limit_side(side);
498 }
499 
500 
501 template<int spacedim, class Value>
503  const TimeGovernor &time)
504 {
505  bool any=false;
506  for( SubFieldType &field : sub_fields_) {
507  if (field.set_time(time))
508  any = true;
509  }
510  return any;
511 }
512 
513 
514 
515 template<int spacedim, class Value>
517  shared_->mesh_ = &mesh;
518  for(unsigned int i_comp=0; i_comp < size(); i_comp++)
519  sub_fields_[i_comp].set_mesh(mesh);
520 }
521 
522 
523 template<int spacedim, class Value>
525  if (typeid(other) == typeid(*this)) {
526  auto const &other_field = dynamic_cast< MultiField<spacedim, Value> const &>(other);
527  this->operator=(other_field);
528  } else if (typeid(other) == typeid(SubFieldType)) {
529  auto const &other_field = dynamic_cast< SubFieldType const &>(other);
530  sub_fields_.resize(1);
531  sub_fields_[0] = other_field;
532  }
533 }
534 
535 
536 
537 template<int spacedim, class Value>
539 {
540  // currently we cannot output boundary fields
541  if (!is_bc())
542  stream->register_data(this->output_type(), *this);
543 }
544 
545 
546 
547 
548 
549 template<int spacedim, class Value>
551  bool const_all=false;
552  for(auto field : sub_fields_) const_all = const_all || field.is_constant(reg);
553  return const_all;
554 }
555 
556 
557 
558 
559 
560 #endif /* FIELD_IMPL_HH_ */