Flow123d  master-a7f2151e0
field_set.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 field_set.cc
15  * @brief
16  */
17 
18 #include "fields/field_set.hh"
19 #include "fields/bc_field.hh"
20 #include "system/sys_profiler.hh"
22 #include "fem/mapping_p1.hh"
23 #include "mesh/ref_element.hh"
25 #include <boost/algorithm/string/replace.hpp>
26 #include <queue>
27 
28 
30 : mesh_(nullptr) {}
31 
32 
33 const Input::Type::Record & FieldSet::get_user_field(const std::string &equation_name) {
34  static Field<3, FieldValue<3>::Scalar> scalar_field;
35  static Field<3, FieldValue<3>::VectorFixed> vector_field;
36  static Field<3, FieldValue<3>::TensorFixed> tensor_field;
37  return Input::Type::Record( equation_name+":UserData", "Record to set fields of the equation: "+equation_name+".")
39  "Name of user defined field.")
40  .declare_key("is_boundary", Input::Type::Bool(), Input::Type::Default("false"),
41  "Type of field: boundary or bulk.")
42  .declare_key("scalar_field", scalar_field.get_input_type(), Input::Type::Default::obligatory(),
43  "Instance of FieldAlgoBase ScalarField descendant.\n"
44  "One of keys 'scalar_field', 'vector_field', 'tensor_field' must be set.\n"
45  "If you set more than one of these keys, only first key is accepted.")
46  .declare_key("vector_field", vector_field.get_input_type(),
47  "Instance of FieldAlgoBase VectorField descendant. See above for details.")
48  .declare_key("tensor_field", tensor_field.get_input_type(),
49  "Instance of FieldAlgoBase TensorField descendant. See above for details.")
50  .close();
51 }
52 
53 FieldSet &FieldSet::operator +=(FieldCommon &add_field) {
54  FieldCommon *found_field = field(add_field.name());
55  if (found_field) {
56  ASSERT(&add_field==found_field)(add_field.name()).error("Another field of the same name exists when adding field\n");
57  } else {
58  field_list.push_back(&add_field);
59  }
60  return *this;
61 }
62 
63 
64 
65 FieldSet &FieldSet::operator +=(const FieldSet &other) {
66  for(auto field_ptr : other.field_list) this->operator +=(*field_ptr);
67  return *this;
68 }
69 
70 
71 
72 FieldSet FieldSet::subset(std::vector<std::string> names) const {
73  FieldSet set;
74  set.set_mesh( *this->mesh_ );
75  for(auto name : names) set += (*this)[name];
76  return set;
77 }
78 
79 
80 
81 FieldSet FieldSet::subset( FieldFlag::Flags::Mask mask) const {
82  FieldSet set;
83  for(auto field : field_list)
84  if (field->flags().match(mask)) set += *field;
85  return set;
86 }
87 
88 
89 
90 Input::Type::Record FieldSet::make_field_descriptor_type(const std::string &equation_name) const {
91  string rec_name = equation_name + ":Data";
93  Input::Type::Record rec = Input::Type::Record(rec_name, desc)
95 
96  for(auto field : field_list) {
97  if ( field->flags().match(FieldFlag::declare_input) ) {
98  string description = field->description() + " (($[" + field->units().format_latex() + "]$))";
99 
100  // Adding units is not so simple.
101  // 1) It must be correct for Latex.
102  // 2) It should be consistent with rest of documentation.
103  // 3) Should be specified for all fields.
104  //if (units != "") description+= " [" +field->units() + "]";
105 
106  // TODO: temporary solution, see FieldCommon::multifield_
107 
108  std::shared_ptr<Input::Type::TypeBase> field_type_ptr;
109  if (field->is_multifield()) {
110  field_type_ptr = std::make_shared<Input::Type::Array>(field->get_multifield_input_type());
111  } else {
112  field_type_ptr = std::make_shared<Input::Type::Instance>(field->get_input_type());
113  }
114  ASSERT( field->units().is_def() )(field->input_name()).error("units not def.");
116  { {FlowAttribute::field_unit(), field->units().json() },
118  );
119  string default_val = field->input_default();
120  if (default_val != "") {
121  boost::replace_all(default_val, "\"", "\\\"");
122  key_attributes[FlowAttribute::field_default_value()] = "\"" + default_val + "\"";
123  }
124  rec.declare_key(field->input_name(), field_type_ptr, Input::Type::Default::optional(), description, key_attributes);
125  }
126 
127  }
128  return rec.close();
129 }
130 
131 
132 /*
133 Input::Type::Selection FieldSet::make_output_field_selection(const string &name, const string &desc)
134 {
135  namespace IT=Input::Type;
136  IT::Selection sel(name, desc);
137  int i=0;
138  // add value for each field excluding boundary fields
139  for( auto field : field_list)
140  {
141  if ( !field->is_bc() && field->flags().match( FieldFlag::allow_output) )
142  {
143  string desc = "Output of the field " + field->name() + " (($[" + field->units().format_latex()+"]$))";
144  if (field->description().length() > 0)
145  desc += " (" + field->description() + ").";
146  else
147  desc += ".";
148  DebugOut() << field->get_value_attribute();
149 
150  sel.add_value(i, field->name(), desc, { {FlowAttribute::field_value_shape(), field->get_value_attribute()} } );
151  i++;
152  }
153  }
154 
155  return sel;
156 }
157 */
158 
159 
160 void FieldSet::set_field(const std::string &dest_field_name, FieldCommon &source)
161 {
162  auto &field = (*this)[dest_field_name];
163  field.copy_from(source);
164 }
165 
166 
167 
168 FieldCommon *FieldSet::field(const std::string &field_name) const {
169  for(auto field : field_list)
170  if (field->name() ==field_name) return field;
171  return nullptr;
172 }
173 
174 
175 
176 FieldCommon *FieldSet::user_field(const std::string &field_name, const TimeStep &time) {
177  auto it = user_fields_input_.find(field_name);
178  if (it != user_fields_input_.end()) {
179  uint new_index = user_field_list_.size();
180  bool is_bdr = it->second.val<bool>("is_boundary");
181 
182  Input::AbstractRecord field_arec;
183  if (it->second.opt_val("scalar_field", field_arec)) {
184  Field<3, FieldValue<3>::Scalar> * scalar_field;
185  if (is_bdr)
186  scalar_field = new BCField<3, FieldValue<3>::Scalar>();
187  else
188  scalar_field = new Field<3, FieldValue<3>::Scalar>();
189  *this+=scalar_field
190  ->name(field_name)
191  .description("")
193  scalar_field->set_mesh(*mesh_);
194  scalar_field->set( it->second.val<Input::AbstractRecord>("scalar_field"), time.end());
195  user_field_list_.push_back( scalar_field );
196  } else if (it->second.opt_val("vector_field", field_arec)) {
197  Field<3, FieldValue<3>::VectorFixed> * vector_field;
198  if (is_bdr)
199  vector_field = new BCField<3, FieldValue<3>::VectorFixed>();
200  else
201  vector_field = new Field<3, FieldValue<3>::VectorFixed>();
202  *this+=vector_field
203  ->name(field_name)
204  .description("")
206  vector_field->set_mesh(*mesh_);
207  vector_field->set( it->second.val<Input::AbstractRecord>("scalar_field"), time.end());
208  user_field_list_.push_back( vector_field );
209  } else if (it->second.opt_val("tensor_field", field_arec)) {
210  Field<3, FieldValue<3>::TensorFixed> * tensor_field;
211  if (is_bdr)
212  tensor_field = new BCField<3, FieldValue<3>::TensorFixed>();
213  else
214  tensor_field = new Field<3, FieldValue<3>::TensorFixed>();
215  *this+=tensor_field
216  ->name(field_name)
217  .description("")
219  tensor_field->set_mesh(*mesh_);
220  tensor_field->set( it->second.val<Input::AbstractRecord>("scalar_field"), time.end());
221  user_field_list_.push_back( tensor_field );
222  } else {
223  THROW(ExcFieldNotSet() << FieldCommon::EI_Field(field_name));
224  }
225 
226  FieldCommon &user_field = *user_field_list_[new_index];
228  return &user_field;
229  } else
230  return nullptr;
231 }
232 
233 
234 
235 FieldCommon &FieldSet::operator[](const std::string &field_name) const {
236  FieldCommon *found_field=field(field_name);
237  if (found_field) return *found_field;
238 
239  THROW(ExcUnknownField() << FieldCommon::EI_Field(field_name));
240  return *field_list[0]; // formal to prevent compiler warning
241 }
242 
243 
244 bool FieldSet::set_time(const TimeStep &time, LimitSide limit_side) {
245  bool changed_all=false;
246  for(auto field : field_list) changed_all = field->set_time(time, limit_side) || changed_all;
247  return changed_all;
248 }
249 
250 
251 
252 bool FieldSet::changed() const {
253  bool changed_all=false;
254  for(auto field : field_list) changed_all = changed_all || field->changed();
255  return changed_all;
256 }
257 
258 
259 
260 bool FieldSet::is_constant(Region reg) const {
261  bool const_all=true;
262  for(auto field : field_list) const_all = const_all && field->is_constant(reg);
263  return const_all;
264 }
265 
266 
268  bool is_jump = false;
269  for(auto field : field_list) is_jump = is_jump || field->is_jump_time();
270  return is_jump;
271 }
272 
273 
275  ASSERT_GT(region_field_update_order_.size(), 0).error("Variable 'region_dependency_list' is empty. Did you call 'set_dependency' method?\n");
276  for (unsigned int i_reg_patch=0; i_reg_patch<cache_map.n_regions(); ++i_reg_patch) {
277  for (const FieldCommon *field : region_field_update_order_[cache_map.region_idx_from_chunk_position(i_reg_patch)])
278  field->cache_update(cache_map, i_reg_patch);
279  }
280 }
281 
282 
283 void FieldSet::set_dependency(FieldSet &used_fieldset) {
285  std::unordered_set<const FieldCommon *> used_fields;
286 
287  for (unsigned int i_reg=0; i_reg<mesh_->region_db().size(); ++i_reg) {
288  for (FieldListAccessor f_acc : used_fieldset.fields_range()) {
289  topological_sort( f_acc.field(), i_reg, used_fields );
290  }
291  used_fields.clear();
292  }
293 }
294 
295 
296 void FieldSet::topological_sort(const FieldCommon *f, unsigned int i_reg, std::unordered_set<const FieldCommon *> &used_fields) {
297  if (used_fields.find(f) != used_fields.end() ) return; // field processed
298  used_fields.insert(f);
299  auto dep_vec = f->set_dependency(*this, i_reg); // vector of dependent fields
300  for (auto f_dep : dep_vec) {
301  topological_sort(f_dep, i_reg, used_fields);
302  }
303  region_field_update_order_[i_reg].push_back(f);
304 }
305 
306 
308  *this += X_.name("X")
309  .units(UnitSI().m())
310  .input_default("0.0")
312  .description("Coordinates field.");
313 
314  *this += depth_.name("d")
315  .units(UnitSI().m())
316  .input_default("0.0")
318  .description("Depth field.");
319 
320  if (this->mesh_ != nullptr) {
321  X_.set_mesh(*this->mesh_);
322  depth_.set_mesh(*this->mesh_);
323  }
324 
326 }
327 
328 
330  auto bgn_it = make_iter<FieldListAccessor>( FieldListAccessor(field_list, 0) );
331  auto end_it = make_iter<FieldListAccessor>( FieldListAccessor(field_list, field_list.size()) );
332  return Range<FieldListAccessor>(bgn_it, end_it);
333 }
334 
335 
336 std::string FieldSet::print_dependency() const {
337  ASSERT_GT(region_field_update_order_.size(), 0).error("Variable 'region_dependency_list' is empty. Did you call 'set_dependency' method?\n");
338  std::stringstream s;
339  for (auto reg_it : region_field_update_order_) {
340  s << "\nregion_idx " << reg_it.first << ": ";
341  for (auto f_it : reg_it.second) {
342  s << f_it->name() << ", ";
343  }
344  }
345  return s.str();
346 }
347 
348 
350  this->user_fields_input_.clear();
352  it != input_list.end();
353  ++it) {
354  std::string name = it->val<std::string>("name");
355  user_fields_input_[name] = *it;
356  }
357 }
358 
359 
360 std::ostream &operator<<(std::ostream &stream, const FieldSet &set) {
361  for(FieldCommon * field : set.field_list) {
362  stream << *field
363  << std::endl;
364  }
365  return stream;
366 }
FieldCommon::units
FieldCommon & units(const UnitSI &units)
Set basic units of the field.
Definition: field_common.hh:152
bc_field.hh
FieldSet::set_user_fields_map
void set_user_fields_map(Input::Array input_list)
Definition: field_set.cc:349
FieldSet::operator[]
FieldCommon & operator[](const std::string &field_name) const
Definition: field_set.cc:235
Input::Type::Bool
Class for declaration of the input of type Bool.
Definition: type_base.hh:452
FieldSet::get_user_field
const Input::Type::Record & get_user_field(const std::string &equation_name)
Declare input record type of field defined by user.
Definition: field_set.cc:33
ref_element.hh
Class RefElement defines numbering of vertices, sides, calculation of normal vectors etc.
ASSERT_GT
#define ASSERT_GT(a, b)
Definition of comparative assert macro (Greater Than) only for debug mode.
Definition: asserts.hh:317
UnitSI::dimensionless
static UnitSI & dimensionless()
Returns dimensionless unit.
Definition: unit_si.cc:55
FieldSet::user_field_list_
std::vector< FieldCommon * > user_field_list_
List of fields defined by user.
Definition: field_set.hh:404
FieldSet::is_jump_time
bool is_jump_time() const
Definition: field_set.cc:267
FieldSet::set_time
bool set_time(const TimeStep &time, LimitSide limit_side)
Definition: field_set.cc:244
FieldSet::is_constant
bool is_constant(Region reg) const
Definition: field_set.cc:260
FieldListAccessor
Definition: field_set.hh:61
MeshBase::region_db
const RegionDB & region_db() const
Definition: mesh.h:175
ASSERT
#define ASSERT(expr)
Definition: asserts.hh:351
ElementCacheMap
Directing class of FieldValueCache.
Definition: field_value_cache.hh:151
FieldSet::set_dependency
void set_dependency(FieldSet &used_fieldset)
Definition: field_set.cc:283
FieldCommon::copy_from
virtual void copy_from(const FieldCommon &other)=0
FieldSet::user_field
FieldCommon * user_field(const std::string &field_name, const TimeStep &time)
Definition: field_set.cc:176
field_set.hh
THROW
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:53
FieldSet::fields_range
Range< FieldListAccessor > fields_range() const
Returns range of Fields held in field_list.
Definition: field_set.cc:329
std::vector< std::string >
FieldSet::region_field_update_order_
std::map< unsigned int, std::vector< const FieldCommon * > > region_field_update_order_
Definition: field_set.hh:415
FieldSet::changed
bool changed() const
Definition: field_set.cc:252
FieldCommon::set_time
virtual bool set_time(const TimeStep &time, LimitSide limit_side)=0
FieldCommon::flags
FieldCommon & flags(FieldFlag::Flags::Mask mask)
Definition: field_common.hh:191
Field::get_input_type
IT::Instance get_input_type() override
Definition: field.impl.hh:178
uint
unsigned int uint
Definition: mh_dofhandler.hh:101
operator<<
std::ostream & operator<<(std::ostream &stream, const FieldSet &set)
Definition: field_set.cc:360
FlowAttribute::field_value_shape
static string field_value_shape()
Definition: flow_attribute_lib.hh:47
Input::Array::begin
Iterator< ValueType > begin() const
Definition: accessors_impl.hh:145
FlowAttribute::field_unit
static string field_unit()
Definition: flow_attribute_lib.hh:38
FieldSet::user_fields_input_
std::unordered_map< std::string, Input::Record > user_fields_input_
Map assigns Input::Record to each field defined in optional Input::Array 'user_fields'.
Definition: field_set.hh:427
FieldCommon::field_descriptor_record
static IT::Record field_descriptor_record(const string &record_name)
Definition: field_common.cc:60
Region
Definition: region.hh:145
Input::Iterator
Definition: accessors.hh:143
FieldSet::field_list
std::vector< FieldCommon * > field_list
List of all fields.
Definition: field_set.hh:401
FieldSet::X_
FieldCoords X_
Field holds coordinates for computing of FieldFormulas.
Definition: field_set.hh:421
Input::Type::Default
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:61
Input::Type::TypeBase::attribute_map
std::map< std::string, json_string > attribute_map
Defines map of Input::Type attributes.
Definition: type_base.hh:101
LimitSide::left
@ left
FieldSet::topological_sort
void topological_sort(const FieldCommon *f, unsigned int i_reg, std::unordered_set< const FieldCommon * > &used_fields)
Helper method sort used fields by dependency.
Definition: field_set.cc:296
FieldSet::print_dependency
std::string print_dependency() const
Return order of evaluated fields by dependency and region_idx.
Definition: field_set.cc:336
TimeStep::end
double end() const
Definition: time_governor.hh:161
FieldCommon::get_value_attribute
virtual std::string get_value_attribute() const =0
Input::Record
Accessor to the data with type Type::Record.
Definition: accessors.hh:291
sys_profiler.hh
Field::set
void set(FieldBasePtr field, double time, std::vector< std::string > region_set_names={"ALL"})
Definition: field.impl.hh:244
flow_attribute_lib.hh
TimeStep
Representation of one time step..
Definition: time_governor.hh:123
FieldSet::mesh_
const Mesh * mesh_
Pointer to the mesh.
Definition: field_set.hh:407
Input::AbstractRecord
Accessor to the polymorphic input data of a type given by an AbstracRecord object.
Definition: accessors.hh:458
Input::Type::Default::obligatory
static Default obligatory()
The factory function to make an empty default value which is obligatory.
Definition: type_record.hh:110
bidirectional_map.hh
Implementation of bidirectional map.
FieldCommon
Common abstract parent of all Field<...> classes.
Definition: field_common.hh:76
UnitSI
Class for representation SI units of Fields.
Definition: unit_si.hh:40
FieldSet::add_coords_field
void add_coords_field()
Definition: field_set.cc:307
FieldCommon::set_dependency
virtual std::vector< const FieldCommon * > set_dependency(FieldSet &field_set, unsigned int i_reg) const =0
FieldCommon::field_descriptor_record_description
static const std::string field_descriptor_record_description(const string &record_name)
Definition: field_common.cc:73
Input::Type::Record::declare_key
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:503
FieldCoords::set_mesh
void set_mesh(const Mesh &mesh) override
Definition: field_coords.hh:66
FieldCommon::changed
bool changed() const
Definition: field_common.hh:363
LimitSide
LimitSide
Definition: field_common.hh:63
FieldSet::cache_update
void cache_update(ElementCacheMap &cache_map)
Definition: field_set.cc:274
FieldSet
Container for various descendants of FieldCommonBase.
Definition: field_set.hh:159
std::map< std::string, json_string >
FieldFlag::input_copy
static constexpr Mask input_copy
Definition: field_flag.hh:44
Input::Type::Record::close
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:304
FieldDepth::set_field_coords
void set_field_coords(FieldCoords *field_coords)
Setter of field_coords data member.
Definition: field_depth.hh:143
Input::Type
Definition: balance.hh:41
Input::Type::Record
Record type proxy class.
Definition: type_record.hh:182
FieldCommon::is_multifield
bool is_multifield() const
Definition: field_common.hh:467
FieldDepth::set_mesh
void set_mesh(const Mesh &mesh) override
Definition: field_depth.hh:64
FieldCommon::input_default
FieldCommon & input_default(const string &input_default)
Definition: field_common.hh:139
FieldCommon::get_input_type
virtual IT::Instance get_input_type()=0
Input::Type::Record::copy_keys
Record & copy_keys(const Record &other)
Copy keys from other record.
Definition: type_record.cc:216
Range
Range helper class.
Definition: range_wrapper.hh:65
Field::set_mesh
void set_mesh(const Mesh &mesh) override
Definition: field.impl.hh:205
Input::Type::String
Class for declaration of the input data that are in string format.
Definition: type_base.hh:582
ElementCacheMap::region_idx_from_chunk_position
unsigned int region_idx_from_chunk_position(unsigned int chunk_pos) const
Return begin position of region chunk specified by position in map.
Definition: field_value_cache.hh:269
Input::Array
Accessor to input data conforming to declared Array.
Definition: accessors.hh:566
FlowAttribute::field_default_value
static string field_default_value()
Definition: flow_attribute_lib.hh:65
FieldSet::set_mesh
void set_mesh(const Mesh &mesh)
Definition: field_set.hh:281
FieldCommon::get_multifield_input_type
virtual IT::Array get_multifield_input_type()=0
FieldFlag::declare_input
static constexpr Mask declare_input
The field can be set from input. The key in input field descriptor is declared. (default on)
Definition: field_flag.hh:35
FieldSet::FieldSet
FieldSet()
Default constructor.
Definition: field_set.cc:29
mapping_p1.hh
Class MappingP1 implements the affine transformation of the unit cell onto the actual cell.
FieldCommon::input_name
const std::string & input_name() const
Definition: field_common.hh:242
FieldCommon::is_jump_time
bool is_jump_time()
Definition: field_common.hh:306
BCField
Definition: bc_field.hh:32
FieldSet::set_field
void set_field(const std::string &dest_field_name, FieldCommon &source)
Definition: field_set.cc:160
FieldCommon::description
FieldCommon & description(const string &description)
Definition: field_common.hh:127
Field
Class template representing a field with values dependent on: point, element, and region.
Definition: field.hh:91
FieldCommon::cache_update
virtual void cache_update(ElementCacheMap &cache_map, unsigned int region_patch_idx) const =0
Input::Type::Default::optional
static Default optional()
The factory function to make an empty default value which is optional.
Definition: type_record.hh:124
Input::Array::end
IteratorBase end() const
Definition: accessors_impl.hh:157
FieldSet::depth_
FieldDepth depth_
Field holds surface depth for computing of FieldFormulas.
Definition: field_set.hh:424
FieldSet::make_field_descriptor_type
Input::Type::Record make_field_descriptor_type(const std::string &equation_name) const
Definition: field_set.cc:90
ElementCacheMap::n_regions
unsigned int n_regions() const
Return number of stored regions.
Definition: field_value_cache.hh:229
FieldCommon::is_constant
virtual bool is_constant(Region reg)=0
FieldSet::field
FieldCommon * field(const std::string &field_name) const
Definition: field_set.cc:168
FieldCommon::name
FieldCommon & name(const string &name)
Definition: field_common.hh:120