Flow123d
region.cc
Go to the documentation of this file.
1 /*
2  * material_dispatch.cc
3  *
4  * Created on: Nov 27, 2012
5  * Author: jb
6  */
7 
8 #include <string>
9 #include <sstream>
10 
11 #include "mesh/region.hh"
12 #include "system/exceptions.hh"
13 
14 #include "input/input_type.hh"
15 #include "input/type_base.hh"
16 #include "input/accessors.hh"
17 #include <boost/foreach.hpp>
18 
19 using namespace std;
20 
21 
22 
23 std::string Region::label() const
24  { return db_->get_label(idx_); }
25 
26 
27 
28 unsigned int Region::id() const
29  { return db_->get_id(idx_); }
30 
31 
32 
33 unsigned int Region::dim() const
34  { return db_->get_dim(idx_); }
35 
36 /**************************************************************************************************
37  * Implementation of RegionDB
38  */
39 
40 
41 namespace IT=Input::Type;
42 
43 
44 
46  IT::Record("Region", "Definition of region of elements.")
48  "Label (name) of the region. Has to be unique in one mesh.\n")
50  "The ID of the region to which you assign label.")
51  .declare_key("element_list", IT::Array( IT::Integer(0) ), IT::Default::optional(),
52  "Specification of the region by the list of elements. This is not recomended")
53  .close();
54 
56  IT::Record("RegionSet", "Definition of one region set.")
58  "Unique name of the region set.")
59  .declare_key("region_ids", IT::Array( IT::Integer(0)),
60  "List of region ID numbers that has to be added to the region set.")
61  .declare_key("region_labels", IT::Array( IT::String()),
62  "List of labels of the regions that has to be added to the region set.")
63  .declare_key("union", IT::Array( IT::String(), 2,2),
64  "Defines region set as a union of given pair of sets. Overrides previous keys.")
65  .declare_key("intersection", IT::Array( IT::String(), 2,2),
66  "Defines region set as an intersection of given pair of sets. Overrides previous keys.")
67  .declare_key("difference", IT::Array( IT::String(), 2,2),
68  "Defines region set as a difference of given pair of sets. Overrides previous keys.")
69  .close();
70 
71 
72 /// Default constructor
74 : closed_(false), n_boundary_(0), n_bulk_(0) {
75 
76  // adding implicit boundary and bulk regions
77  // How to deal with dimension, clean solution is to have implicit region for every
78  // dimension, or we can allow regions of mixed dimension
79  //implicit_bulk_ = add_region(Region::undefined-1, "IMPLICIT BULK", 0, Region::bulk);
80  //implicit_boundary_ = ;
81 
82 }
83 
84 
86  return add_region(Region::undefined-2, "IMPLICIT BOUNDARY", undefined_dim, Region::boundary);
87 }
88 
89 
90 void RegionDB::check_dim_consistency(IDIter it_id, unsigned int dim) {
91  // check dimension
92  if (it_id->dim_ != dim) {
93  // User can introduce regions through the mesh input record, however without dim
94  // specification. Here we allow overwriting dimension in this case
95  if (it_id->dim_ == undefined_dim) {
96  RegionItem item(it_id->index, it_id->id, it_id->label, dim);
97  region_set_.replace(
98  region_set_.get<Index>().find( it_id->index ),
99  item);
100  }
101  else THROW(ExcInconsistentDimension() << EI_Label(it_id->label) << EI_ID(it_id->id) );
102  }
103 
104 }
105 
106 
107 Region RegionDB::add_region( unsigned int id, const std::string &label, unsigned int dim, bool boundary) {
108  if (closed_) xprintf(PrgErr, "Can not add to closed region DB.\n");
109 
110  IDIter it_id = region_set_.get<ID>().find(id);
111  LabelIter it_label = region_set_.get<Label>().find(label);
112 
113  if (it_id != region_set_.get<ID>().end() ) {
114  unsigned int index = it_id->index;
115  if (it_id->dim_ != undefined_dim && index != it_label->index) THROW(ExcNonuniqueID() << EI_Label(label) << EI_ID(id) << EI_LabelOfOtherID(it_id->label) );
116 
117  check_dim_consistency(it_id, dim); // possibly update DB
118 
119  Region r_id=Region(index, *this);
120  // check boundary
121  if ( r_id.is_boundary() != boundary )
122  THROW(ExcInconsistentBoundary() << EI_Label(label) << EI_ID(id) );
123 
124  return r_id;
125  } else
126  if (it_label != region_set_.get<Label>().end() ) {
127  // ID is free, not label
128  THROW(ExcNonuniqueLabel() << EI_Label(label) << EI_ID(id) << EI_IDOfOtherLabel(it_label->id) );
129  } else {
130  // if DB is open add new entry
131  if (closed_)
132  THROW( ExcAddingIntoClosed() << EI_Label(label) <<EI_ID(id) );
133  else {
134  unsigned int index;
135  if (boundary) {
136  index = (n_boundary_ <<1);
137  n_boundary_++;
138  } else {
139  index = (n_bulk_ << 1)+1;
140  n_bulk_++;
141  }
142  if (index >= max_n_regions) xprintf(UsrErr, "Too many regions, more then %d\n", max_n_regions);
143  if ( ! region_set_.insert( RegionItem(index, id, label, dim) ).second )
144  THROW( ExcCantAdd() << EI_Label(label) <<EI_ID(id) );
145  return Region(index, *this);
146  }
147  }
148  return Region(); // should not happen
149 }
150 
151 
152 Region RegionDB::add_region(unsigned int id, const std::string &label, unsigned int dim) {
153  if (label.size() != 0) {
154  bool boundary = label[0] == '.';
155  return add_region(id, label, dim, boundary);
156  }
157  // else
158  stringstream ss;
159  ss << "region_" << id;
160  return add_region(id, ss.str(), dim, false);
161 }
162 
163 
164 Region RegionDB::add_region(unsigned int id, unsigned int dim) {
165  RegionTable::index<ID>::type::iterator it_id = region_set_.get<ID>().find(id);
166  if ( it_id!=region_set_.get<ID>().end() ) {
167  // just check dimension
168  check_dim_consistency(it_id, dim);
169  return Region(it_id->index, *this);
170  }
171  // else
172  stringstream ss;
173  ss << "region_" << id;
174  return add_region(id, ss.str(), dim, false);
175 }
176 
177 
178 
179 Region RegionDB::find_label(const std::string &label) const
180 {
181  LabelIter it_label = region_set_.get<Label>().find(label);
182  if (it_label==region_set_.get<Label>().end() ) return Region();
183  return Region(it_label->index, *this);
184 }
185 
186 
187 
188 
189 
190 Region RegionDB::find_id(unsigned int id) const
191 {
192  IDIter it_id = region_set_.get<ID>().find(id);
193  if ( it_id==region_set_.get<ID>().end() ) return Region();
194  return Region(it_id->index, *this);
195 }
196 
197 
198 
199 
200 const std::string & RegionDB::get_label(unsigned int idx) const {
201  RegionTable::index<Index>::type::iterator it = region_set_.get<Index>().find(idx);
202  ASSERT( it!= region_set_.get<Index>().end(), "No region with index: %u\n", idx);
203  return it->label;
204 }
205 
206 
207 
208 unsigned int RegionDB::get_id(unsigned int idx) const {
209  RegionTable::index<Index>::type::iterator it = region_set_.get<Index>().find(idx);
210  ASSERT( it!= region_set_.get<Index>().end(), "No region with index: %u\n", idx);
211  return it->id;
212 }
213 
214 
215 
216 unsigned int RegionDB::get_dim(unsigned int idx) const {
217  RegionTable::index<Index>::type::iterator it = region_set_.get<Index>().find(idx);
218  ASSERT( it!= region_set_.get<Index>().end(), "No region with index: %u\n", idx);
219  return it->dim_;
220 }
221 
222 
223 
225  closed_=true;
226  // set default sets
227  for(unsigned int i=0; i< size(); i++) {
228  Region reg(i, *this);
229 
230  if (reg.is_boundary() && (reg.boundary_idx() < boundary_size()) ) {
231  add_to_set("BOUNDARY", reg );
232  add_to_set("ALL", reg);
233  } else
234  if ( (! reg.is_boundary()) && (reg.bulk_idx() < bulk_size()) ) {
235  add_to_set("BULK", reg );
236  add_to_set("ALL", reg);
237  }
238  }
239 }
240 
241 
242 unsigned int RegionDB::size() const {
243  ASSERT(closed_, "RegionDB not closed yet.\n");
244  return 2* max(n_boundary_, n_bulk_);
245 }
246 
247 
248 
249 unsigned int RegionDB::boundary_size() const {
250  ASSERT(closed_, "RegionDB not closed yet.\n");
251  return n_boundary_;
252 }
253 
254 
255 
256 unsigned int RegionDB::bulk_size() const {
257  ASSERT(closed_, "RegionDB not closed yet.\n");
258  return n_bulk_;
259 }
260 
261 
262 
263 
264 void RegionDB::add_to_set( const string& set_name, Region region) {
266 
267  if (it == sets_.end()) {
268  RegionSet set;
269  set.push_back(region);
270 
271  sets_.insert( std::make_pair(set_name, set) );
272  } else {
273  RegionSet & set = (*it).second;
274  if ( std::find(set.begin(), set.end(), region)==set.end() ) {
275  set.push_back(region); // add region if doesn't exist
276  }
277  }
278 }
279 
280 
281 void RegionDB::add_set( const string& set_name, const RegionSet & set) {
282  // add region only if it is not in the set
283  if (sets_.find(set_name) == sets_.end()) {
284  sets_.insert( std::make_pair(set_name, set) );
285  }
286 }
287 
288 
289 RegionSet RegionDB::union_sets( const string & set_name_1, const string & set_name_2) {
290  RegionSet set_union;
291  RegionSet set_1, set_2;
292  RegionSet::iterator it;
293 
294  prepare_sets(set_name_1, set_name_2, set_1, set_2);
295  set_union.resize(set_1.size() + set_2.size());
296  it = std::set_union(set_1.begin(), set_1.end(), set_2.begin(), set_2.end(), set_union.begin(), Region::comp);
297  set_union.resize(it - set_union.begin());
298 
299  return set_union;
300 }
301 
302 
303 RegionSet RegionDB::intersection( const string & set_name_1, const string & set_name_2) {
304  RegionSet set_insec;
305  RegionSet set_1, set_2;
306  RegionSet::iterator it;
307 
308  prepare_sets(set_name_1, set_name_2, set_1, set_2);
309  set_insec.resize(set_1.size() + set_2.size());
310  it = std::set_intersection(set_1.begin(), set_1.end(), set_2.begin(), set_2.end(), set_insec.begin(), Region::comp);
311  set_insec.resize(it - set_insec.begin());
312 
313  return set_insec;
314 }
315 
316 
317 RegionSet RegionDB::difference( const string & set_name_1, const string & set_name_2) {
318  RegionSet set_diff;
319  RegionSet set_1, set_2;
320  RegionSet::iterator it;
321 
322  prepare_sets(set_name_1, set_name_2, set_1, set_2);
323  set_diff.resize(set_1.size() + set_2.size());
324  it = std::set_difference(set_1.begin(), set_1.end(), set_2.begin(), set_2.end(), set_diff.begin(), Region::comp);
325  set_diff.resize(it - set_diff.begin());
326 
327  return set_diff;
328 }
329 
330 
331 void RegionDB::prepare_sets( const string & set_name_1, const string & set_name_2,
332  RegionSet & set_1, RegionSet & set_2) {
333  std::map<std::string, RegionSet>::iterator it_1 = sets_.find(set_name_1);
334  std::map<std::string, RegionSet>::iterator it_2 = sets_.find(set_name_2);
335 
336  if ( it_1 == sets_.end() ) { THROW(ExcUnknownSet() << EI_Label(set_name_1)); }
337  if ( it_2 == sets_.end() ) { THROW(ExcUnknownSet() << EI_Label(set_name_2)); }
338 
339  set_1 = (*it_1).second;
340  set_2 = (*it_2).second;
341 
342  std::stable_sort(set_1.begin(), set_1.end(), Region::comp);
343  std::stable_sort(set_2.begin(), set_2.end(), Region::comp);
344 }
345 
346 
347 
348 pair<string,string> RegionDB::get_and_check_operands(const Input::Array & operands)
349 {
350  vector<string> names;
351  operands.copy_to(names);
352  if ( names.size() != 2 ) THROW(ExcWrongOpNumber() << EI_NumOp(names.size()) << operands.ei_address() );
353  auto ret_names = pair<string,string>(names[0], names[1]);
354  if ( sets_.find( ret_names.first ) == sets_.end() )
355  THROW( ExcUnknownSet() << EI_Label( ret_names.first )
356  << operands.ei_address() );
357  if ( sets_.find( ret_names.second ) == sets_.end() )
358  THROW( ExcUnknownSet() << EI_Label( ret_names.second )
359  << operands.ei_address() );
360  return ret_names;
361 }
362 
363 
364 
365 RegionSet RegionDB::get_region_set(const string & set_name) const {
367  if ( it == sets_.end() ) {
368  return RegionSet();
369  }
370  return (*it).second;
371 }
372 
373 
376  it != arr.end();
377  ++it) {
378 
379  Input::Record rec = (*it);
380  string set_name;
381  Input::Array region_ids, region_labels;
382  Input::Array union_names, intersection_names, difference_names;
383  RegionSet region_set;
384 
385  rec.opt_val("name", set_name);
386 
387  if (rec.opt_val("region_ids", region_ids) ) {
388  for (Input::Iterator<unsigned int> it_ids = region_ids.begin<unsigned int>();
389  it_ids != region_ids.end();
390  ++it_ids) {
391  Region reg = find_id(*it_ids);
392  if (reg.is_valid()) {
393  if ( std::find(region_set.begin(), region_set.end(), reg)==region_set.end() ) {
394  region_set.push_back(reg); // add region if doesn't exist
395  }
396  } else {
397  xprintf(Warn, "Region with id %d doesn't exist. Skipping\n", (*it_ids));
398  }
399  }
400  }
401 
402  if (rec.opt_val("region_labels", region_labels) ) {
403  for (Input::Iterator<string> it_labels = region_labels.begin<string>();
404  it_labels != region_labels.end();
405  ++it_labels) {
406  Region reg = find_label(*it_labels);
407  if (reg.is_valid()) {
408  if ( std::find(region_set.begin(), region_set.end(), reg)==region_set.end() ) {
409  region_set.push_back(reg); // add region if doesn't exist
410  }
411  } else {
412  xprintf(Warn, "Region with label %s doesn't exist. Skipping\n", (*it_labels).c_str());
413  }
414  }
415  }
416 
417  Input::Iterator<Input::Array> operands = rec.find<Input::Array>("union");
418  if ( operands ) {
419 
420  if (region_set.size() != 0) {
421  xprintf(Warn, "Overwriting previous initialization of region set '%s' by union operation.\n", set_name.c_str());
422  }
423 
424  pair<string,string> set_names = get_and_check_operands(*operands);
425  region_set = union_sets( set_names.first, set_names.second );
426  }
427 
428  operands = rec.find<Input::Array>("intersection");
429  if (operands) {
430 
431  if (region_set.size() != 0) {
432  xprintf(Warn, "Overwriting previous initialization of region set '%s' by intersection operation.\n", set_name.c_str());
433  }
434 
435  pair<string,string> set_names = get_and_check_operands(*operands);
436  region_set = intersection( set_names.first, set_names.second );
437  }
438 
439  operands = rec.find<Input::Array>("difference");
440  if (operands) {
441 
442  if (region_set.size() != 0) {
443  xprintf(Warn, "Overwriting previous initialization of region set '%s' by difference operation.\n", set_name.c_str());
444  }
445 
446  pair<string,string> set_names = get_and_check_operands(*operands);
447  region_set = difference( set_names.first, set_names.second );
448  }
449 
450  add_set(set_name, region_set);
451  }
452 
453  /*
454  Input::Array region_ids;
455  if (rec.opt_val("region_ids", region_ids) ) {
456  ... add regions
457  // for int_item in region_ids -> RegionDB.find_id(int_item)
458  // ... bud prida nalezany region pomoci add_to_set, nebo chyba
459 
460  }
461 
462  if (rec.opt_val("region_labels", region_labels)) {
463  // ... podobne pro region_labels, s pouzitim RegionDB::find_label
464 
465  }
466 
467  if (rec.opt_val("union", ...) ) {
468  ...
469  if (region_set.size() != 0) xprintf(Warn, "Overwriting previous initialization of region set 'NAME' by union operation.");
470  }
471  */
472 }
473 
475  map.clear();
476 
477  for (Input::Iterator<Input::Record> it = region_list.begin<Input::Record>();
478  it != region_list.end();
479  ++it) {
480 
481  Input::Record rec = (*it);
482  string region_name = rec.val<string>("name");
483  unsigned int region_id = rec.val<unsigned int>("id");
484  add_region(region_id, region_name, undefined_dim);
485 
486  Input::Array element_list;
487  if (rec.opt_val("element_list", element_list) ) {
488  for (Input::Iterator<unsigned int> it_element = element_list.begin<unsigned int>();
489  it_element != element_list.end();
490  ++it_element) {
491 
492  std::map<unsigned int, unsigned int>::iterator it_map = map.find((*it_element));
493  if (it_map == map.end()) {
494  map.insert( std::make_pair((*it_element), region_id) );
495  } else {
496  xprintf(Warn, "Element with id %u can't be added more than once.\n", (*it_element));
497  }
498  }
499  }
500  }
501 }