Flow123d  JS_before_hm-1576-g4d0b70e
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 "system/sys_profiler.hh"
21 #include "fem/mapping_p1.hh"
22 #include "mesh/ref_element.hh"
24 #include "fields/dfs_topo_sort.hh"
25 #include <boost/algorithm/string/replace.hpp>
26 #include <queue>
27 
28 
30 {}
31 
32 FieldSet &FieldSet::operator +=(FieldCommon &add_field) {
33  FieldCommon *found_field = field(add_field.name());
34  if (found_field) {
35  OLD_ASSERT(&add_field==found_field, "Another field of the same name exists when adding field: %s\n",
36  add_field.name().c_str());
37  } else {
38  field_list.push_back(&add_field);
39  }
40  return *this;
41 }
42 
43 
44 
45 FieldSet &FieldSet::operator +=(const FieldSet &other) {
46  for(auto field_ptr : other.field_list) this->operator +=(*field_ptr);
47  return *this;
48 }
49 
50 
51 
52 FieldSet FieldSet::subset(std::vector<std::string> names) const {
53  FieldSet set;
54  set.set_mesh( *this->mesh_ );
55  for(auto name : names) set += (*this)[name];
56  return set;
57 }
58 
59 
60 
61 FieldSet FieldSet::subset( FieldFlag::Flags::Mask mask) const {
62  FieldSet set;
63  for(auto field : field_list)
64  if (field->flags().match(mask)) set += *field;
65  return set;
66 }
67 
68 
69 
70 Input::Type::Record FieldSet::make_field_descriptor_type(const std::string &equation_name) const {
71  string rec_name = equation_name + ":Data";
73  Input::Type::Record rec = Input::Type::Record(rec_name, desc)
75 
76  for(auto field : field_list) {
77  if ( field->flags().match(FieldFlag::declare_input) ) {
78  string description = field->description() + " (($[" + field->units().format_latex() + "]$))";
79 
80  // Adding units is not so simple.
81  // 1) It must be correct for Latex.
82  // 2) It should be consistent with rest of documentation.
83  // 3) Should be specified for all fields.
84  //if (units != "") description+= " [" +field->units() + "]";
85 
86  // TODO: temporary solution, see FieldCommon::multifield_
87 
88  std::shared_ptr<Input::Type::TypeBase> field_type_ptr;
89  if (field->is_multifield()) {
90  field_type_ptr = std::make_shared<Input::Type::Array>(field->get_multifield_input_type());
91  } else {
92  field_type_ptr = std::make_shared<Input::Type::Instance>(field->get_input_type());
93  }
94  ASSERT( field->units().is_def() )(field->input_name()).error("units not def.");
96  { {FlowAttribute::field_unit(), field->units().json() },
98  );
99  string default_val = field->input_default();
100  if (default_val != "") {
101  boost::replace_all(default_val, "\"", "\\\"");
102  key_attributes[FlowAttribute::field_default_value()] = "\"" + default_val + "\"";
103  }
104  rec.declare_key(field->input_name(), field_type_ptr, Input::Type::Default::optional(), description, key_attributes);
105  }
106 
107  }
108  return rec.close();
109 }
110 
111 
112 /*
113 Input::Type::Selection FieldSet::make_output_field_selection(const string &name, const string &desc)
114 {
115  namespace IT=Input::Type;
116  IT::Selection sel(name, desc);
117  int i=0;
118  // add value for each field excluding boundary fields
119  for( auto field : field_list)
120  {
121  if ( !field->is_bc() && field->flags().match( FieldFlag::allow_output) )
122  {
123  string desc = "Output of the field " + field->name() + " (($[" + field->units().format_latex()+"]$))";
124  if (field->description().length() > 0)
125  desc += " (" + field->description() + ").";
126  else
127  desc += ".";
128  DebugOut() << field->get_value_attribute();
129 
130  sel.add_value(i, field->name(), desc, { {FlowAttribute::field_value_shape(), field->get_value_attribute()} } );
131  i++;
132  }
133  }
134 
135  return sel;
136 }
137 */
138 
139 
140 void FieldSet::set_field(const std::string &dest_field_name, FieldCommon &source)
141 {
142  auto &field = (*this)[dest_field_name];
143  field.copy_from(source);
144 }
145 
146 
147 
148 FieldCommon *FieldSet::field(const std::string &field_name) const {
149  for(auto field : field_list)
150  if (field->name() ==field_name) return field;
151  return nullptr;
152 }
153 
154 
155 
156 FieldCommon &FieldSet::operator[](const std::string &field_name) const {
157  FieldCommon *found_field=field(field_name);
158  if (found_field) return *found_field;
159 
160  THROW(ExcUnknownField() << FieldCommon::EI_Field(field_name));
161  return *field_list[0]; // formal to prevent compiler warning
162 }
163 
164 
165 bool FieldSet::set_time(const TimeStep &time, LimitSide limit_side) {
166  bool changed_all=false;
167  for(auto field : field_list) changed_all = field->set_time(time, limit_side) || changed_all;
168  return changed_all;
169 }
170 
171 
172 
173 bool FieldSet::changed() const {
174  bool changed_all=false;
175  for(auto field : field_list) changed_all = changed_all || field->changed();
176  return changed_all;
177 }
178 
179 
180 
181 bool FieldSet::is_constant(Region reg) const {
182  bool const_all=true;
183  for(auto field : field_list) const_all = const_all && field->is_constant(reg);
184  return const_all;
185 }
186 
187 
189  bool is_jump = false;
190  for(auto field : field_list) is_jump = is_jump || field->is_jump_time();
191  return is_jump;
192 }
193 
194 
196  ASSERT_GT_DBG(region_field_update_order_.size(), 0).error("Variable 'region_dependency_list' is empty. Did you call 'set_dependency' method?\n");
197  for (unsigned int i_reg_patch=0; i_reg_patch<cache_map.n_regions(); ++i_reg_patch) {
198  for (const FieldCommon *field : region_field_update_order_[cache_map.region_idx_from_chunk_position(i_reg_patch)])
199  field->cache_update(cache_map, i_reg_patch);
200  }
201 }
202 
203 
204 void FieldSet::set_dependency(FieldSet &used_fieldset) {
205  BidirectionalMap<const FieldCommon *> field_indices_map; // position of field / multifield component in FieldSet
206  for (FieldListAccessor f_acc : this->fields_range())
207  field_indices_map.add_item( f_acc.field() );
209  std::vector<bool> used_fields(field_indices_map.size()); // marks used fields (positions correspond to field_indices_map)
210  std::queue<const FieldCommon *> q;
211 
212  unordered_map<std::string, unsigned int>::iterator it;
213  for (unsigned int i_reg=0; i_reg<mesh_->region_db().size(); ++i_reg) {
214  // TODO:
215  // - move the loop body into separate method
216  // - Remove explicit creation of the graph.
217  // - Just move topological_sort_util to FieldSet and iterate over requested fields
218  // directly. Pushback the closed fields directly into region_field_update_order_[i_reg] call std::reverse after
219  // DFS for a single region.
220  // - Use an unordered_set to mark visited fields instead of BidirectionalMap + used_fields.
221 
222  DfsTopoSort dfs(field_indices_map.size());
223  std::fill(used_fields.begin(), used_fields.end(), false);
224  uint n_used_fields = 0; // number of all used fields (size of used_fieldset + fields depending on FieldFormula and FieldModel)
225  for (FieldListAccessor f_acc : used_fieldset.fields_range()) {
226  q.push(f_acc.field());
227  n_used_fields++;
228  used_fields[ field_indices_map.get_position( f_acc.field() ) ] = true;
229  }
230  while (q.size() > 0) {
231  auto field = q.front();
232  int field_idx = field_indices_map.get_position( field );
233  ASSERT_GE_DBG(field_idx, 0);
234  auto dep_vec = field->set_dependency(*this, i_reg); // vector of dependent fields
235  for (auto f : dep_vec) {
236  uint field_pos = field_indices_map.get_position(f);
237  dfs.add_edge( uint(field_idx), field_pos );
238  if (!used_fields[ field_pos ]) {
239  q.push(f);
240  n_used_fields++;
241  used_fields[ field_pos ] = true;
242  }
243  }
244  q.pop();
245  }
246  auto sort_vec = dfs.topological_sort();
248  for (unsigned int i_field=0, i_order=0; i_field<sort_vec.size(); ++i_field) {
249  if ( !used_fields[sort_vec[i_field]] ) continue;
250  region_field_update_order_[i_reg][i_order] = field_indices_map[ sort_vec[i_field] ];
251  i_order++;
252  }
253  }
254 }
255 
256 
258  *this += X_.name("X")
259  .units(UnitSI().m())
260  .input_default("0.0")
262  .description("Coordinates field.");
263 
264  *this += depth_.name("d")
265  .units(UnitSI().m())
266  .input_default("0.0")
268  .description("Depth field.");
269 
271 }
272 
273 
275  auto bgn_it = make_iter<FieldListAccessor>( FieldListAccessor(field_list, 0) );
276  auto end_it = make_iter<FieldListAccessor>( FieldListAccessor(field_list, field_list.size()) );
277  return Range<FieldListAccessor>(bgn_it, end_it);
278 }
279 
280 
281 std::string FieldSet::print_dependency() const {
282  ASSERT_GT_DBG(region_field_update_order_.size(), 0).error("Variable 'region_dependency_list' is empty. Did you call 'set_dependency' method?\n");
283  std::stringstream s;
284  for (auto reg_it : region_field_update_order_) {
285  s << "\nregion_idx " << reg_it.first << ": ";
286  for (auto f_it : reg_it.second) {
287  s << f_it->name() << ", ";
288  }
289  }
290  return s.str();
291 }
292 
293 
294 std::ostream &operator<<(std::ostream &stream, const FieldSet &set) {
295  for(FieldCommon * field : set.field_list) {
296  stream << *field
297  << std::endl;
298  }
299  return stream;
300 }
std::vector< FieldCommon * > field_list
List of all fields.
Definition: field_set.hh:379
Class MappingP1 implements the affine transformation of the unit cell onto the actual cell...
unsigned int size() const
Definition: region.cc:254
FieldDepth depth_
Field holds surface depth for computing of FieldFormulas.
Definition: field_set.hh:396
bool is_jump_time() const
Definition: field_set.cc:188
Common abstract parent of all Field<...> classes.
Definition: field_common.hh:74
Container for various descendants of FieldCommonBase.
Definition: field_set.hh:159
std::map< unsigned int, std::vector< const FieldCommon * > > region_field_update_order_
Definition: field_set.hh:390
virtual void copy_from(const FieldCommon &other)=0
const Mesh * mesh_
Pointer to the mesh.
Definition: field_set.hh:382
FieldCommon & operator[](const std::string &field_name) const
Definition: field_set.cc:156
FieldCoords X_
Field holds coordinates for computing of FieldFormulas.
Definition: field_set.hh:393
unsigned int size() const
Return size of map.
void set_field_coords(FieldCoords *field_coords)
Setter of field_coords data member.
Definition: field_depth.hh:143
void set_dependency(FieldSet &used_fieldset)
Definition: field_set.cc:204
unsigned int uint
virtual bool is_constant(Region reg)=0
Implementation of bidirectional map.
#define ASSERT_GE_DBG(a, b)
Definition of comparative assert macro (Greater or Equal) only for debug mode.
Definition: asserts.hh:324
Range helper class.
virtual std::string get_value_attribute() const =0
virtual IT::Instance get_input_type()=0
Directing class of FieldValueCache.
virtual bool set_time(const TimeStep &time, LimitSide limit_side)=0
static string field_default_value()
const RegionDB & region_db() const
Definition: mesh.h:142
#define ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library...
Definition: asserts.hh:347
static const std::string field_descriptor_record_description(const string &record_name)
Definition: field_common.cc:73
#define ASSERT_GT_DBG(a, b)
Definition of comparative assert macro (Greater Than) only for debug mode.
Definition: asserts.hh:316
std::string print_dependency() const
Return order of evaluated fields by dependency and region_idx.
Definition: field_set.cc:281
FieldCommon & units(const UnitSI &units)
Set basic units of the field.
unsigned int n_regions() const
Return number of stored regions.
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:304
unsigned int region_idx_from_chunk_position(unsigned int chunk_pos) const
Return begin position of region chunk specified by position in map.
static Default optional()
The factory function to make an empty default value which is optional.
Definition: type_record.hh:124
#define OLD_ASSERT(...)
Definition: global_defs.h:131
FieldCommon * field(const std::string &field_name) const
Definition: field_set.cc:148
Range< FieldListAccessor > fields_range() const
Returns range of Fields held in field_list.
Definition: field_set.cc:274
unsigned int add_item(T val)
Add new item at the end position of map.
static constexpr Mask input_copy
Definition: field_flag.hh:44
FieldCommon & input_default(const string &input_default)
static IT::Record field_descriptor_record(const string &record_name)
Definition: field_common.cc:60
std::map< std::string, json_string > attribute_map
Defines map of Input::Type attributes.
Definition: type_base.hh:101
virtual std::vector< const FieldCommon * > set_dependency(FieldSet &field_set, unsigned int i_reg) const =0
void set_field(const std::string &dest_field_name, FieldCommon &source)
Definition: field_set.cc:140
static string field_value_shape()
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
bool is_multifield() const
Record & copy_keys(const Record &other)
Copy keys from other record.
Definition: type_record.cc:216
bool is_jump_time()
FieldCommon & description(const string &description)
void add_coords_field()
Definition: field_set.cc:257
virtual IT::Array get_multifield_input_type()=0
void cache_update(ElementCacheMap &cache_map)
Definition: field_set.cc:195
bool set_time(const TimeStep &time, LimitSide limit_side)
Definition: field_set.cc:165
bool is_constant(Region reg) const
Definition: field_set.cc:181
FieldCommon & name(const string &name)
Class RefElement defines numbering of vertices, sides, calculation of normal vectors etc...
static string field_unit()
bool changed() const
void set_mesh(const Mesh &mesh)
Definition: field_set.hh:274
friend std::ostream & operator<<(std::ostream &stream, const FieldSet &set)
Definition: field_set.cc:294
Record type proxy class.
Definition: type_record.hh:182
FieldCommon & flags(FieldFlag::Flags::Mask mask)
const std::string & input_name() const
Class for representation SI units of Fields.
Definition: unit_si.hh:40
int get_position(T val) const
Return position of item of given value.
virtual void cache_update(ElementCacheMap &cache_map, unsigned int region_patch_idx) const =0
FieldSet()
Default constructor.
Definition: field_set.cc:29
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:53
Representation of one time step..
Bidirectional map templated by <T, unsigned int>.
bool changed() const
Definition: field_set.cc:173
LimitSide
Definition: field_common.hh:61
Input::Type::Record make_field_descriptor_type(const std::string &equation_name) const
Definition: field_set.cc:70
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