Flow123d  JS_before_hm-1008-g3dab983
region.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 region.cc
15  * @brief
16  */
17 
18 #include <string>
19 #include <sstream>
20 
21 #include "mesh/region.hh"
22 #include "system/exceptions.hh"
23 #include "system/system.hh"
24 
25 #include "input/input_type.hh"
26 #include "input/type_base.hh"
27 #include "input/accessors.hh"
28 
29 using namespace std;
30 
31 
32 std::string Region::label() const
33  { return db_->get_label(idx_); }
34 
35 
36 
37 unsigned int Region::id() const
38  { return db_->get_id(idx_); }
39 
40 
41 
42 unsigned int Region::dim() const
43  { return db_->get_dim(idx_); }
44 
45 bool Region::is_in_region_set(const RegionSet &set) const
46 {
47  for(const Region &reg : set)
48  if (reg.idx_ == this->idx_) return true;
49  return false;
50 }
51 
52 /**************************************************************************************************
53  * Implementation of RegionDB
54  */
55 
56 
57 
58 const unsigned int RegionDB::max_n_regions = 10000;
59 const unsigned int RegionDB::undefined_dim = 10;
60 
61 
62 /// Default constructor
64 : closed_(false), n_boundary_(0), n_bulk_(0), max_id_(0) {
65 
66  // adding implicit boundary and bulk regions
67  // How to deal with dimension, clean solution is to have implicit region for every
68  // dimension, or we can allow regions of mixed dimension
69  //implicit_bulk_ = add_region(Region::undefined-1, "IMPLICIT BULK", 0, Region::bulk);
70  //implicit_boundary_ = ;
71 
72 }
73 
74 
77  if ( it_id!=region_table_.get<DimId>().end() ) {
78  return Region(it_id->index, *this);
79  }
80 
81  return insert_region(Region::undefined-2, ".IMPLICIT_BOUNDARY", undefined_dim, Region::boundary, "");
82 }
83 
84 
85 Region RegionDB::add_region( unsigned int id, const std::string &label, unsigned int dim, const std::string &address) {
86  bool boundary = is_boundary(label);
87  DimIDIter it_id = region_table_.get<DimId>().find(DimID(dim,id));
88  if (it_id != region_table_.get<DimId>().end() ) {
89  // Find existing region
90  return find_by_dimid(it_id, id, label, boundary);
91  }
92 
93  DimIDIter it_undef_dim = region_table_.get<DimId>().find(DimID(undefined_dim,id));
94  if (it_undef_dim != region_table_.get<DimId>().end() ) {
95  // Region with same ID and undefined_dim exists, replace undefined_dim
96  return replace_region_dim(it_undef_dim, dim, boundary);
97  }
98 
99  LabelIter it_label = region_table_.get<Label>().find(label);
100  if (it_label != region_table_.get<Label>().end() ) {
101  // ID is free, not label
102  THROW(ExcNonuniqueLabel() << EI_Label(label) << EI_ID(id) << EI_IDOfOtherLabel(it_label->get_id()) );
103  }
104 
105  return insert_region(id, label, dim, boundary, address);
106 }
107 
108 
109 Region RegionDB::rename_region( Region reg, const std::string &new_label ) {
110  OLD_ASSERT(reg.is_valid(), "Non-existing region can't be renamed to '%s'.\n", new_label.c_str());
111 
112  // test if region with new_label exists
113  LabelIter it_label = region_table_.get<Label>().find(new_label);
114  if (it_label != region_table_.get<Label>().end() ) {
115  if ( reg.id() == it_label->index ) {
116  return reg;
117  } else {
118  // region with same label and other ID exists
119  THROW(ExcNonuniqueLabel() << EI_Label(new_label) << EI_ID(reg.id()) << EI_IDOfOtherLabel(it_label->get_id()) );
120  }
121  }
122 
123  // replace region label
124  unsigned int index = reg.idx();
125  RegionSetTable::iterator it = sets_.find(reg.label()); // rename set
126  std::swap(sets_[new_label], it->second);
127  sets_.erase(it);
128  bool old_boundary_flag = reg.is_boundary(); // check old x new boundary flag - take account in adding to sets
129 
130  RegionItem item(index, reg.id(), new_label, reg.dim(), this->get_region_address(index));
131  region_table_.replace(
132  region_table_.get<Index>().find(index),
133  item);
134 
135  if (old_boundary_flag != reg.is_boundary()) { // move region between BULK and .BOUNDARY sets
136  WarningOut().fmt("Change boundary flag of region with id {} and label {}.\n", reg.id(), new_label);
137  if (old_boundary_flag) {
138  erase_from_set(".BOUNDARY", reg );
139  add_to_set("BULK", reg );
140  } else {
141  erase_from_set("BULK", reg );
142  add_to_set(".BOUNDARY", reg );
143  }
144  }
145 
146  return Region(index, *this);
147 }
148 
149 
150 Region RegionDB::get_region(unsigned int id, unsigned int dim) {
151  DimIDIter it_id = region_table_.get<DimId>().find(DimID(dim,id));
152  if ( it_id!=region_table_.get<DimId>().end() ) {
153  // Region found.
154  return Region(it_id->index, *this);
155  }
156 
157  DimIDIter it_undef_dim = region_table_.get<DimId>().find(DimID(undefined_dim,id));
158  if (it_undef_dim == region_table_.get<DimId>().end() ) {
159  // Region doesn't exist.
160  return Region();
161  } else {
162  // Region with same ID and undefined_dim exists, replace undefined_dim
163  bool boundary = is_boundary(it_undef_dim->label);
164  return replace_region_dim(it_undef_dim, dim, boundary);
165  }
166 }
167 
168 
169 Region RegionDB::find_label(const std::string &label) const
170 {
171  LabelIter it_label = region_table_.get<Label>().find(label);
172  if (it_label==region_table_.get<Label>().end() ) return Region();
173  return Region(it_label->index, *this);
174 }
175 
176 
177 
178 
179 
180 Region RegionDB::find_id(unsigned int id, unsigned int dim) const
181 {
182  DimIDIter it_id = region_table_.get<DimId>().find(DimID(dim, id));
183  if ( it_id==region_table_.get<DimId>().end() ) return Region();
184  return Region(it_id->index, *this);
185 }
186 
187 
188 
189 
190 Region RegionDB::find_id(unsigned int id) const
191 {
192  if (region_table_.get<OnlyID>().count(id) > 1) {
193  THROW( ExcUniqueRegionId() << EI_ID( id ) );
194  }
195  OnlyIDIter it_id = region_table_.get<OnlyID>().find(id);
196  if ( it_id==region_table_.get<OnlyID>().end() ) return Region();
197  return Region(it_id->index, *this);
198 }
199 
200 
201 
202 
203 const std::string & RegionDB::get_label(unsigned int idx) const {
204  RegionTable::index<Index>::type::iterator it = region_table_.get<Index>().find(idx);
205  OLD_ASSERT( it!= region_table_.get<Index>().end(), "No region with index: %u\n", idx);
206  return it->label;
207 }
208 
209 
210 
211 unsigned int RegionDB::get_id(unsigned int idx) const {
212  RegionTable::index<Index>::type::iterator it = region_table_.get<Index>().find(idx);
213  OLD_ASSERT( it!= region_table_.get<Index>().end(), "No region with index: %u\n", idx);
214  return it->get_id();
215 }
216 
217 
218 
219 unsigned int RegionDB::get_dim(unsigned int idx) const {
220  RegionTable::index<Index>::type::iterator it = region_table_.get<Index>().find(idx);
221  OLD_ASSERT( it!= region_table_.get<Index>().end(), "No region with index: %u\n", idx);
222  return it->dim();
223 }
224 
225 
226 
227 const std::string & RegionDB::get_region_address(unsigned int idx) const {
228  RegionTable::index<Index>::type::iterator it = region_table_.get<Index>().find(idx);
229  OLD_ASSERT( it!= region_table_.get<Index>().end(), "No region with index: %u\n", idx);
230  return it->address;
231 }
232 
233 
234 
235 void RegionDB::mark_used_region(unsigned int idx) {
236  RegionTable::index<Index>::type::iterator it = region_table_.get<Index>().find(idx);
237  OLD_ASSERT( it!= region_table_.get<Index>().end(), "No region with index: %u\n", idx);
238  if ( !it->used ) {
239  unsigned int index = it->index;
240  RegionItem item(index, it->get_id(), it->label, it->dim(), it->address, true);
241  region_table_.replace(
242  region_table_.get<Index>().find(index),
243  item);
244  }
245 }
246 
247 
248 
250  closed_=true;
251 }
252 
253 
254 unsigned int RegionDB::size() const {
255  OLD_ASSERT(closed_, "RegionDB not closed yet.\n");
256  return 2* max(n_boundary_, n_bulk_);
257 }
258 
259 
260 
261 unsigned int RegionDB::boundary_size() const {
262  OLD_ASSERT(closed_, "RegionDB not closed yet.\n");
263  return n_boundary_;
264 }
265 
266 
267 
268 unsigned int RegionDB::bulk_size() const {
269  OLD_ASSERT(closed_, "RegionDB not closed yet.\n");
270  return n_bulk_;
271 }
272 
273 
274 
275 
276 void RegionDB::add_to_set( const string& set_name, Region region) {
277  RegionSetTable::iterator it = sets_.find(set_name);
278 
279  if (it == sets_.end()) {
280  RegionSet set;
281  set.push_back(region);
282 
283  sets_.insert( std::make_pair(set_name, set) );
284  } else {
285  RegionSet & set = (*it).second;
286  if ( std::find(set.begin(), set.end(), region)==set.end() ) {
287  set.push_back(region); // add region if doesn't exist
288  }
289  }
290 }
291 
292 
293 void RegionDB::add_set( const string& set_name, const RegionSet & set) {
294  // add region only if it is not in the set
295  if (sets_.find(set_name) == sets_.end()) {
296  sets_.insert( std::make_pair(set_name, set) );
297  }
298 }
299 
300 
301 void RegionDB::erase_from_set( const string& set_name, Region region) {
302  RegionSetTable::iterator it = sets_.find(set_name);
303  OLD_ASSERT(it != sets_.end(), "Region set '%s' doesn't exist.", set_name.c_str());
304  RegionSet & set = (*it).second;
305 
306  auto set_it = std::find(set.begin(), set.end(), region);
307  OLD_ASSERT(set_it != set.end(), "Erased region was not found in set '%s'", set_name.c_str());
308  set.erase(set_it);
309 }
310 
311 
313 {
314  vector<string> names;
315  operands.copy_to(names);
316 
317  for (string name : names) {
318  if ( sets_.find( name ) == sets_.end() )
319  THROW( ExcUnknownSet() << EI_Label( name )
320  << operands.ei_address() );
321  }
322 
323  return names;
324 }
325 
326 
327 
328 RegionSet RegionDB::get_region_set(const string & set_name) const {
329  RegionSetTable::const_iterator it = sets_.find(set_name);
330  if ( it == sets_.end() ) {
331  return RegionSet();
332  }
333  return (*it).second;
334 }
335 
336 
337 string RegionDB::create_label_from_id(unsigned int id) const {
338  stringstream ss;
339  ss << "region_" << id;
340  return ss.str();
341 }
342 
343 Region RegionDB::insert_region(unsigned int id, const std::string &label, unsigned int dim, bool boundary, const std::string &address) {
344  if (closed_) THROW( ExcAddingIntoClosed() << EI_Label(label) << EI_ID(id) );
345 
346  unsigned int index;
347  if (boundary) {
348  index = (n_boundary_ <<1);
349  n_boundary_++;
350  } else {
351  index = (n_bulk_ << 1)+1;
352  n_bulk_++;
353  }
354 
355  if ( ! region_table_.insert( RegionItem(index, id, label, dim, address) ).second )
356  THROW( ExcCantAdd() << EI_Label(label) << EI_ID(id) );
357  if (max_id_ < id) {
358  max_id_ = id;
359  }
360 
361  Region reg = Region(index, *this);
362  // add region to sets
363  RegionSet region_set;
364  region_set.push_back( reg );
365  this->add_set(reg.label(), region_set);
366  add_to_set("ALL", reg);
367  if (reg.is_boundary()) {
368  add_to_set(".BOUNDARY", reg );
369  } else {
370  add_to_set("BULK", reg );
371  }
372 
373  return reg;
374 }
375 
376 Region RegionDB::replace_region_dim(DimIDIter it_undef_dim, unsigned int dim, bool boundary) {
377  OLD_ASSERT( it_undef_dim->dim() == undefined_dim,
378  "Dimension of replaced region with id=%u must be undefined_dim, actually is: %u\n", it_undef_dim->get_id(), it_undef_dim->dim());
379 
380  unsigned int index = it_undef_dim->index;
381 
382  RegionItem item(index, it_undef_dim->get_id(), it_undef_dim->label, dim, this->get_region_address(index));
383  region_table_.replace(
384  region_table_.get<Index>().find(index),
385  item);
386 
387  Region r_id=Region(index, *this);
388  // check boundary
389  if ( r_id.is_boundary() != boundary )
390  THROW(ExcInconsistentBoundary() << EI_Label(it_undef_dim->label) << EI_ID(it_undef_dim->get_id()) );
391 
392  return r_id;
393 }
394 
395 Region RegionDB::find_by_dimid(DimIDIter it_id, unsigned int id, const std::string &label, bool boundary) {
396  unsigned int index = it_id->index;
397  LabelIter it_label = region_table_.get<Label>().find(label);
398  if ( it_label == region_table_.get<Label>().end() || index != it_label->index )
399  THROW(ExcNonuniqueID() << EI_Label(label) << EI_ID(id) << EI_LabelOfOtherID(it_id->label) );
400 
401  Region r_id=Region(index, *this);
402  // check boundary
403  if ( r_id.is_boundary() != boundary )
404  THROW(ExcInconsistentBoundary() << EI_Label(label) << EI_ID(id) );
405 
406  return r_id;
407 }
408 
409 void RegionDB::print_region_table(ostream& stream) const {
410  ASSERT(closed_).error("RegionDB not closed yet.\n");
411 
412  // stratified regions by type
413  std::vector<std::string> boundaries, bulks, sets;
414  for (RegionSetTable::const_iterator it = sets_.begin(); it != sets_.end(); ++it) { // iterates through RegionSets
415  string rset_label = it->first;
416  LabelIter label_it = region_table_.get<Label>().find(rset_label);
417  if ( label_it != region_table_.get<Label>().end() ) { // checks if Region with same label as RegionSet exists
418  if ( (rset_label.size() > 0) && (rset_label[0] == '.') ) boundaries.push_back(rset_label);
419  else bulks.push_back(rset_label);
420  } else {
421  sets.push_back(rset_label);
422  }
423 
424  }
425 
426  // print table
427  stream << "----------- Table of all regions: -----------";
428  if (boundaries.size()) {
429  stream << endl << " - Boundary elementary regions -" << endl;
430  stream << std::setfill(' ') << "name" << setw(14) << "" << setw(6) << "id" << " dim" << endl; // table header
431  for (std::vector<std::string>::iterator it = boundaries.begin(); it < boundaries.end(); ++it) {
432  LabelIter label_it = region_table_.get<Label>().find(*it);
433  stream << std::left << setw(18) << (*it) << std::right << setw(6) << label_it->get_id() << setw(4) << label_it->dim() << endl;
434  }
435  }
436  if (bulks.size()) {
437  stream << endl << " - Bulk elementary regions -" << endl;
438  stream << "name" << setw(14) << "" << setw(6) << "id" << " dim" << endl; // table header
439  for (std::vector<std::string>::iterator it = bulks.begin(); it < bulks.end(); ++it) {
440  LabelIter label_it = region_table_.get<Label>().find(*it);
441  stream << std::left << setw(18) << (*it) << std::right << setw(6) << label_it->get_id() << setw(4) << label_it->dim() << endl;
442  }
443  }
444  if (sets.size()) {
445  stream << endl << " - Sets of regions -" << endl;
446  stream << "name" << setw(14) << "" << "contains regions" << endl; // table header
447  for (std::vector<std::string>::const_iterator it = sets.begin(); it < sets.end(); ++it) {
448  RegionSetTable::const_iterator set_it = sets_.find(*it);
449  stream << std::left << setw(18) << (*it) << std::right << "[";
450  for (RegionSet::const_iterator r_it = set_it->second.begin(); r_it!=set_it->second.end(); ++r_it) {
451  if (r_it != set_it->second.begin()) stream << ", ";
452  stream << "\"" << r_it->label() << "\"";
453  }
454  stream << "]" << endl;
455  }
456  }
457  stream << std::setfill('-') << setw(45) << "" << std::setfill(' ') << endl << endl;
458 }
459 
460 
462  ASSERT(closed_).error("RegionDB not closed yet.");
463 
465  WarningOut().fmt("Too many regions are defined (bulk {} + boundary {} >= {}). This may have negative impact on performace.\n"
466  "The user is adviced to simplify the input data and to decrease the number of regions (e.g. using FieldFE input).\n",
468  }
469 
470  for (RegionTable::index<Index>::type::iterator it = region_table_.get<Index>().begin();
471  it!= region_table_.get<Index>().end();
472  ++it) {
473  if(! it->used){
474  WarningOut().fmt("Region [id = {}, label = '{}'] is not used in any element.",
475  it->get_id(), it->label);
476  }
477  }
478 }
479 
480 
482  std::set<Region, bool (*)(const Region&, const Region&)> set(Region::comp);
483 
484  for (string set_name : set_names) {
485  RegionSet r_set = get_region_set(set_name);
486  set.insert(r_set.begin(), r_set.end());
487  }
488 
489  return RegionSet(set.begin(), set.end());
490 }
unsigned int size() const
Definition: region.cc:254
const std::string & get_label(unsigned int idx) const
Definition: region.cc:203
RegionSet get_region_set(const std::string &set_name) const
Definition: region.cc:328
Accessor to input data conforming to declared Array.
Definition: accessors.hh:566
EI_Address ei_address() const
Definition: accessors.cc:314
bool is_boundary() const
Returns true if it is a Boundary region and false if it is a Bulk region.
Definition: region.hh:74
Region rename_region(Region reg, const std::string &new_label)
Definition: region.cc:109
unsigned int bulk_size() const
Definition: region.cc:268
RegionSetTable sets_
Map of region sets.
Definition: region.hh:557
static bool comp(const Region &a, const Region &b)
Comparative method of two regions.
Definition: region.hh:173
static const unsigned int undefined
index for undefined region
Definition: region.hh:119
unsigned int max_id_
Maximal value of Region::id()
Definition: region.hh:554
void add_to_set(const std::string &set_name, Region region)
Definition: region.cc:276
std::string create_label_from_id(unsigned int id) const
Definition: region.cc:337
RegionSet union_set(std::vector< std::string > set_names) const
Definition: region.cc:481
#define ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library...
Definition: asserts.hh:347
Region replace_region_dim(DimIDIter it_undef_dim, unsigned int dim, bool boundary)
Definition: region.cc:376
unsigned int idx_
Definition: region.hh:116
One item in region database.
Definition: region.hh:495
std::vector< Region > RegionSet
Definition: region.hh:130
Region get_region(unsigned int id, unsigned int dim)
Definition: region.cc:150
#define OLD_ASSERT(...)
Definition: global_defs.h:131
Region find_by_dimid(DimIDIter it_id, unsigned int id, const std::string &label, bool boundary)
Definition: region.cc:395
Region find_id(unsigned int id, unsigned int dim) const
Definition: region.cc:180
std::vector< std::string > get_and_check_operands(const Input::Array &operands) const
Definition: region.cc:312
void add_set(const std::string &set_name, const RegionSet &set)
Definition: region.cc:293
RegionTable::index< Label >::type::iterator LabelIter
Definition: region.hh:539
bool is_boundary(const std::string &label)
Definition: region.hh:606
void close()
Definition: region.cc:249
Region implicit_boundary_region()
Definition: region.cc:75
unsigned int n_bulk_
Number of bulk regions.
Definition: region.hh:552
std::pair< unsigned int, unsigned int > DimID
Definition: region.hh:492
RegionDB()
Default constructor.
Definition: region.cc:63
void swap(nlohmann::json &j1, nlohmann::json &j2) noexcept(is_nothrow_move_constructible< nlohmann::json >::value andis_nothrow_move_assignable< nlohmann::json >::value)
exchanges the values of two JSON objects
Definition: json.hpp:8688
RegionTable::index< OnlyID >::type::iterator OnlyIDIter
Definition: region.hh:541
RegionSet boundary
Definition: region.hh:560
RegionTable::index< DimId >::type::iterator DimIDIter
Definition: region.hh:540
void check_regions()
Definition: region.cc:461
void mark_used_region(unsigned int idx)
Definition: region.cc:235
Region add_region(unsigned int id, const std::string &label, unsigned int dim, const std::string &address="implicit")
Definition: region.cc:85
const std::string & get_region_address(unsigned int idx) const
Definition: region.cc:227
Region insert_region(unsigned int id, const std::string &label, unsigned int dim, bool boundary, const std::string &address)
Definition: region.cc:343
void copy_to(Container &out) const
static const unsigned int max_n_regions
Definition: region.hh:328
unsigned int get_id(unsigned int idx) const
Definition: region.cc:211
unsigned int boundary_size() const
Definition: region.cc:261
RegionTable region_table_
Database of all regions (both boundary and bulk).
Definition: region.hh:545
void erase_from_set(const std::string &set_name, Region region)
Definition: region.cc:301
bool is_in_region_set(const RegionSet &set) const
Definition: region.cc:45
unsigned int get_dim(unsigned int idx) const
Definition: region.cc:219
void print_region_table(std::ostream &stream) const
Definition: region.cc:409
#define WarningOut()
Macro defining &#39;warning&#39; record of log.
Definition: logger.hh:270
static const unsigned int undefined_dim
Definition: region.hh:332
Region find_label(const std::string &label) const
Definition: region.cc:169
bool is_valid() const
Returns false if the region has undefined/invalid value.
Definition: region.hh:78
std::string label() const
Returns label of the region (using RegionDB)
Definition: region.cc:32
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:53
bool closed_
flag for closed database, no regions can be added, but you can add region sets
Definition: region.hh:548
unsigned int n_boundary_
Number of boundary regions.
Definition: region.hh:550
unsigned int id() const
Returns id of the region (using RegionDB)
Definition: region.cc:37
unsigned int dim() const
Returns dimension of the region.
Definition: region.cc:42
unsigned int idx() const
Returns a global index of the region.
Definition: region.hh:82