EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_smart_envelope.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ smart envelope geometry
5 # Copyright (C) 2015 National Research Council Canada
6 #
7 # This file is part of EGSnrc.
8 #
9 # EGSnrc is free software: you can redistribute it and/or modify it under
10 # the terms of the GNU Affero General Public License as published by the
11 # Free Software Foundation, either version 3 of the License, or (at your
12 # option) any later version.
13 #
14 # EGSnrc is distributed in the hope that it will be useful, but WITHOUT ANY
15 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
17 # more details.
18 #
19 # You should have received a copy of the GNU Affero General Public License
20 # along with EGSnrc. If not, see <http://www.gnu.org/licenses/>.
21 #
22 ###############################################################################
23 #
24 # Author: Iwan Kawrakow, 2008
25 #
26 # Contributors: Frederic Tessier
27 # Ernesto Mainegra-Hing
28 # Marc Chamberland
29 # Hannah Gallop
30 #
31 ###############################################################################
32 #
33 # A "smart" envelope geometry. The smartness is due to the fact that there
34 # can be only zero or one inscribed geometry per base geometry region, which
35 # makes many of the checks faster.
36 #
37 # In addition, unlike the regular envelope geometry where all inscribed
38 # geometries always must completely fit inside the base geometry, here
39 # geometries can be inscribed using logic 0 or 1.
40 #
41 # Logic 0 is as before, i.e., geometry must completely fit into the region
42 # where it is being inscribed.
43 #
44 # Logic 1 means that the inscribed geometry extends beyond the region and
45 # therefore the smart envelope also checks the base geometry in this case.
46 # This is very similar to a CD geometry except that now the space outside
47 # the inscribed geometry is still part of the geometry.
48 #
49 # Warning: not completely tested, so don't use for production runs yet.
50 #
51 ###############################################################################
52 */
53 
54 
60 #include "egs_smart_envelope.h"
61 #include "egs_input.h"
62 #include "egs_functions.h"
63 
64 #include <cstdlib>
65 
66 using namespace std;
67 
68 string EGS_SMART_ENVELOPE_LOCAL EGS_SmartEnvelope::type = "EGS_SmartEnvelope";
69 
70 static bool EGS_SMART_ENVELOPE_LOCAL inputSet = false;
71 
72 void EGS_SmartEnvelope::setMedia(EGS_Input *,int,const int *) {
73  egsWarning("EGS_SmartEnvelope::setMedia: don't use this method. Use the\n"
74  " setMedia() methods of the geometry objects that make up this geometry\n");
75 }
76 
77 void EGS_SmartEnvelope::setRelativeRho(int start, int end, EGS_Float rho) {
78  setRelativeRho(0);
79 }
80 
81 void EGS_SmartEnvelope::setRelativeRho(EGS_Input *) {
82  egsWarning("EGS_SmartEnvelope::setRelativeRho(): don't use this method."
83  " Use the\n setRelativeRho methods of the geometry objects that make up"
84  " this geometry\n");
85 }
86 
87 void EGS_SmartEnvelope::setBScaling(int start, int end, EGS_Float bf) {
88  setBScaling(0);
89 }
90 
91 void EGS_SmartEnvelope::setBScaling(EGS_Input *) {
92  egsWarning("EGS_SmartEnvelope::setsetBScaling(): don't use this method."
93  " Use the\n setsetBScaling methods of the geometry objects that make up"
94  " this geometry\n");
95 }
96 
97 struct EGS_SMART_ENVELOPE_LOCAL SmartEnvelopeAux {
99  int ireg;
100  int type;
101  int nreg;
102  int *regs;
103  SmartEnvelopeAux() : g(0), ireg(-1), type(0), nreg(0) {};
104  ~SmartEnvelopeAux() {
105  if (nreg>0) {
106  delete [] regs;
107  }
108  };
109 };
110 
111 EGS_SmartEnvelope::EGS_SmartEnvelope(EGS_BaseGeometry *G,
112  const vector<SmartEnvelopeAux *> &fgeoms, const string &Name) :
113  EGS_BaseGeometry(Name), geometries(0), gindex(0),
114  reg_to_inscr(0), reg_to_base(0), local_start(0), itype(0) {
115  if (!G) {
116  egsFatal("EGS_SmartEnvelope: base geometry must not be null\n");
117  }
118  g = G;
119  g->ref();
120  n_in = fgeoms.size();
121  if (!n_in) {
122  egsFatal("EGS_SmartEnvelope: no inscribed geometries!\n");
123  }
124  geometries = new EGS_BaseGeometry * [n_in];
125  nbase = g->regions();
126  gindex = new int [nbase];
127  itype = new char [fgeoms.size()];
128  int j;
129  for (j=0; j<nbase; j++) {
130  gindex[j] = -1;
131  }
132  for (j=0; j<fgeoms.size(); j++) {
133  itype[j] = 0;
134  }
135  int nreg_inscribed = 0;
136  bool ok = true;
137  for (j=0; j<fgeoms.size(); j++) {
138  geometries[j] = fgeoms[j]->g;
139  geometries[j]->ref();
140  int i = fgeoms[j]->ireg;
141  if (gindex[i] >= 0) {
142  egsWarning("EGS_SmartEnvelope:"
143  " There can only be a single geometry inscribed in a region\n");
144  egsWarning(" You are trying to inscribe %s into region %d but\n",
145  geometries[j]->getName().c_str(),i);
146  egsWarning(" geometry %s is already inscribed in this region\n",
147  geometries[gindex[i]]->getName().c_str());
148  ok = false;
149  }
150  else {
151  gindex[i] = j;
152  itype[j] = fgeoms[j]->type;
153  //egsInformation("inscribing %d into %d with type %d\n",j,i,itype[j]);
154  nreg_inscribed += geometries[j]->regions();
155  }
156  }
157  if (!ok) {
158  egsFatal("EGS_SmartEnvelope: errors during definition\n");
159  }
160  nreg = nbase + nreg_inscribed;
161  local_start = new int [fgeoms.size()];
162  reg_to_inscr = new int [nreg_inscribed];
163  reg_to_base = new int [nreg_inscribed];
164  int nr = 0;
165  for (j=0; j<fgeoms.size(); j++) {
166  local_start[j] = nbase + nr;
167  int nj = geometries[j]->regions();
168  for (int i=nr; i<nr+nj; ++i) {
169  reg_to_inscr[i] = j;
170  reg_to_base[i] = fgeoms[j]->ireg;
171  }
172  nr += nj;
173  }
174  is_convex = g->isConvex();
175  has_rho_scaling = g->hasRhoScaling();
176  if (!has_rho_scaling) {
177  for (int j=0; j<n_in; j++) {
178  if (geometries[j]->hasRhoScaling()) {
179  has_rho_scaling = true;
180  break;
181  }
182  }
183  }
184  has_B_scaling = g->hasBScaling();
185  if (!has_B_scaling) {
186  for (int j=0; j<n_in; j++) {
187  if (geometries[j]->hasBScaling()) {
188  has_B_scaling = true;
189  break;
190  }
191  }
192  }
193 }
194 
195 EGS_SmartEnvelope::~EGS_SmartEnvelope() {
196  if (!g->deref()) {
197  delete g;
198  }
199  for (int j=0; j<n_in; j++) {
200  if (!geometries[j]->deref()) {
201  delete geometries[j];
202  }
203  }
204  if (geometries) {
205  delete [] geometries;
206  }
207  if (gindex) {
208  delete [] gindex;
209  }
210  if (reg_to_inscr) {
211  delete [] reg_to_inscr;
212  }
213  if (reg_to_base) {
214  delete [] reg_to_base ;
215  }
216  if (local_start) {
217  delete [] local_start;
218  }
219  if (itype) {
220  delete itype;
221  }
222 }
223 
224 void EGS_SmartEnvelope::printInfo() const {
226  egsInformation(" base geometry = %s (type %s)\n",g->getName().c_str(),
227  g->getType().c_str());
228  egsInformation(" inscribed geometries:\n");
229  for (int j=0; j<n_in; j++) egsInformation(" %s (type %s) in region=%d, "
230  " itype=%d\n",
231  geometries[j]->getName().c_str(),geometries[j]->getType().c_str(),
232  reg_to_base[j],(int)itype[j]);
234  "=======================================================\n");
235 }
236 
237 
238 static char EGS_SMART_ENVELOPE_LOCAL eeg_message1[] =
239  "createGeometry(smart envelope): %s\n";
240 static char EGS_SMART_ENVELOPE_LOCAL eeg_message2[] =
241  "null input?";
242 static char EGS_SMART_ENVELOPE_LOCAL eeg_message3[] =
243  "no 'base geometry' input?";
244 static char EGS_SMART_ENVELOPE_LOCAL eeg_message4[] =
245  "incorrect base geometry definition";
246 static char EGS_SMART_ENVELOPE_LOCAL eeg_message5[] =
247  "missing/incorrect 'base geometry' input";
248 static char EGS_SMART_ENVELOPE_LOCAL eeg_message6[] =
249  "createGeometry(smart envelope): no geometry with name %s defined\n";
250 //static char EGS_SMART_ENVELOPE_LOCAL eeg_message7[] =
251 //"no inscirebed geometries defined?. I hope you know what you are doing";
252 //static char EGS_SMART_ENVELOPE_LOCAL eeg_message8[] =
253 //"an error occured while constructing inscibed geometries";
254 
255 static char EGS_SMART_ENVELOPE_LOCAL eeg_keyword1[] = "base geometry";
256 static char EGS_SMART_ENVELOPE_LOCAL eeg_keyword2[] = "geometry";
257 //static char EGS_SMART_ENVELOPE_LOCAL eeg_keyword3[] = "inscribed geometries";
258 
259 extern "C" {
260 
261  static void setInputs() {
262  inputSet = true;
263 
264  setBaseGeometryInputs(false);
265 
266  geomBlockInput->getSingleInput("library")->setValues({"egs_smart_envelope"});
267 
268  // Format: name, isRequired, description, vector string of allowed values
269  geomBlockInput->addSingleInput("base geometry", true, "The name of a previously defined geometry, that other geometries will be placed strictly inside.");
270  geomBlockInput->addSingleInput("inscribed geometries", true, "A list of previously defined geometries to place inside the base geometry. They must not intersect each other or extend beyond the base geometry.");
271  }
272 
273  EGS_SMART_ENVELOPE_EXPORT shared_ptr<EGS_BlockInput> getInputs() {
274  if (!inputSet) {
275  setInputs();
276  }
277  return geomBlockInput;
278  }
279 
280  EGS_SMART_ENVELOPE_EXPORT EGS_BaseGeometry *createGeometry(EGS_Input *input) {
281  if (!input) {
282  egsWarning(eeg_message1,eeg_message2);
283  return 0;
284  }
285  //
286  // *** Base geometry
287  //
288  EGS_Input *i = input->takeInputItem(eeg_keyword1);
289  if (!i) {
290  egsWarning(eeg_message1,eeg_message3);
291  return 0;
292  }
293  EGS_Input *ig = i->takeInputItem(eeg_keyword2);
294  EGS_BaseGeometry *g;
295  if (ig) { // defined inline
297  delete ig;
298  if (!g) {
299  egsWarning(eeg_message1,eeg_message4);
300  delete i;
301  return 0;
302  }
303  }
304  else { // defined via a name of a previously defined geometry
305  string bgname;
306  int err = i->getInput(eeg_keyword1,bgname);
307  delete i;
308  if (err) {
309  egsWarning(eeg_message1,eeg_message5);
310  return 0;
311  }
312  g = EGS_BaseGeometry::getGeometry(bgname);
313  if (!g) {
314  egsWarning(eeg_message6,bgname.c_str());
315  return 0;
316  }
317  }
318  vector<SmartEnvelopeAux *> fgeoms;
319  int nbase = g->regions();
320  EGS_Input *ix;
321  while ((ix = input->takeInputItem("inscribe geometry")) != 0) {
322  vector<string> values;
323  ix->getInput("inscribe geometry",values);
324  if (values.size() < 2) egsWarning("createGeometry(smart envelope):"
325  " %d inputs for 'inscribe geometry'? 2 or more are needed\n",values.size());
326  else {
328  if (!gj) {
329  egsWarning(eeg_message6,values[0].c_str());
330  }
331  else {
333  aux->g = gj;
334  aux->ireg = atoi(values[1].c_str());
335  aux->type = values.size() == 3 ? atoi(values[2].c_str()) : 0;
336  //egsInformation("set geometr: %s %d %d\n",values[0].c_str(),aux->ireg,aux->type);
337  if (aux->ireg < 0 || aux->ireg >= nbase) {
338  egsWarning("createGeometry(smart envelope): wrong "
339  "region index %d for inscribed geometry %s\n",
340  aux->ireg,gj->getName().c_str());
341  delete aux;
342  }
343  else {
344  fgeoms.push_back(aux);
345  }
346  }
347  }
348  delete ix;
349  }
350  EGS_BaseGeometry *result = new EGS_SmartEnvelope(g,fgeoms,"");
351  result->setName(input);
352  result->setBoundaryTolerance(input);
353  result->setLabels(input);
354  for (int j=0; j<fgeoms.size(); j++) {
355  delete fgeoms[j];
356  }
357  return result;
358 
359  }
360 
361  int EGS_SmartEnvelope::getGlobalRegionOffset(const string geomName) {
362  // Look for the named geometry in the inscribed geometries
363  for (int i=0; i<n_in; i++) {
364  if (geometries[i] && geometries[i]->getName() == geomName) {
365  return local_start[i];
366  }
367  }
368 
369  // If it's not found above, search through the inscribed geometries in case they are composite geometries
370  for (int i=0; i<n_in; i++) {
371  int shift = geometries[i]->getGlobalRegionOffset(geomName);
372  if (shift >= 0) {
373  shift += local_start[i];
374  return shift;
375  }
376  }
377 
378  // Return -1 for not found
379  return -1;
380  }
381 
382  void EGS_SmartEnvelope::getLabelRegions(const string &str, vector<int> &regs, bool sanitize) {
383 
384  // label defined in the envelope geometry
385  g->getLabelRegions(str, regs, sanitize);
386 
387  // label defined in the inscribed geometries
388  vector<int> gregs;
389  for (int i=0; i<n_in; i++) {
390 
391  // add regions from set geometries
392  gregs.clear();
393  if (geometries[i]) {
394  geometries[i]->getLabelRegions(str, gregs, sanitize);
395  }
396 
397  // shift region numbers according to indexing style
398  for (int j=0; j<gregs.size(); j++) {
399  gregs[j] += local_start[i];
400  }
401 
402  // add regions to the list
403  regs.insert(regs.end(), gregs.begin(), gregs.end());
404 
405  }
406 
407  // label defined in self (envelope geometry input block)
408  EGS_BaseGeometry::getLabelRegions(str, regs, sanitize);
409 
410  }
411 
412 }
Base geometry class. Every geometry class must be derived from EGS_BaseGeometry.
virtual int getGlobalRegionOffset(const string geomName)
Get the global region number for the first region in the geometry.
int deref()
Decrease the reference count to this geometry.
static EGS_BaseGeometry * createSingleGeometry(EGS_Input *inp)
Create a single geometry from the input inp.
virtual const string & getType() const =0
Get the geometry type.
bool hasBScaling() const
Does this geometry object have a B field scaling feature?
virtual bool hasRhoScaling()
Does this geometry object have a mass density scaling feature?
void setName(EGS_Input *inp)
Set the name of the geometry from the input inp.
const string & getName() const
Get the name of this geometry.
bool isConvex() const
Is the geometry convex?
int regions() const
Returns the number of local regions in this geometry.
int setLabels(EGS_Input *input)
Set the labels from an input block.
virtual void printInfo() const
Print information about this geometry.
int ref()
Increase the reference count to this geometry.
static EGS_BaseGeometry * getGeometry(const string &Name)
Get a pointer to the geometry named Name.
void setBoundaryTolerance(EGS_Input *inp)
Set the value of the boundary tolerance from the input inp.
virtual void getLabelRegions(const string &str, vector< int > &regs, bool sanitize=true)
Get the list of all regions labeled with str.
A class for storing information in a tree-like structure of key-value pairs. This class is used throu...
Definition: egs_input.h:182
EGS_Input * takeInputItem(const string &key, bool self=true)
Get the property named key.
Definition: egs_input.cpp:229
int getInput(const string &key, vector< string > &values) const
Assign values to an array of strings from an input identified by key.
Definition: egs_input.cpp:341
int n_in
Number of inscribed geometries.
void setMedia(EGS_Input *, int, const int *)
Don't set media for an envelope geometry.
int * gindex
Index of inscribed geometries.
EGS_BaseGeometry * g
The envelope geometry.
int * local_start
First region for each inscribed geometry.
int * reg_to_inscr
Region to inscribed geometry conversion.
static string type
Geometry type.
int * reg_to_base
Region to base region conversion.
EGS_BaseGeometry ** geometries
The inscribed geometries.
Global egspp functions header file.
EGS_GLIB_EXPORT EGS_BaseGeometry * createGeometry(EGS_Input *input)
Definition: egs_glib.cpp:84
EGS_Input class header file.
A smart envelope geometry: header.
EGS_InfoFunction EGS_EXPORT egsInformation
Always use this function for reporting the progress of a simulation and any other type of information...
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.