EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_input_struct.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ input struct
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: Reid Townson, 2019
25 #
26 # Contributors:
27 #
28 ###############################################################################
29 */
30 
31 
38 #include "egs_functions.h"
39 #include "egs_input_struct.h"
40 #include <algorithm>
41 
42 EGS_InputStruct::EGS_InputStruct() {}
43 
44 EGS_InputStruct::~EGS_InputStruct() {}
45 
46 shared_ptr<EGS_BlockInput> EGS_InputStruct::addBlockInput(string blockTit, bool isReq) {
47  blockInputs.push_back(make_shared<EGS_BlockInput>(blockTit, isReq, nullptr));
48 
49  return blockInputs.back();
50 }
51 
52 shared_ptr<EGS_BlockInput> EGS_InputStruct::addBlockInput(shared_ptr<EGS_BlockInput> block) {
53  blockInputs.push_back(block);
54 
55  return blockInputs.back();
56 }
57 
58 void EGS_InputStruct::addBlockInputs(vector<shared_ptr<EGS_BlockInput>> blocks) {
59  blockInputs.insert(blockInputs.end(), blocks.begin(), blocks.end());
60 }
61 
63  auto it = blockInputs.begin();
64  while (it != blockInputs.end()) {
65  if ((*it)->getTitle() == title) {
66  it = blockInputs.erase(it);
67  } else {
68  ++it;
69  }
70  }
71 }
72 
74  auto it = blockInputs.begin();
75  while (it != blockInputs.end()) {
76  if ((*it)->getAppName() == appName) {
77  it = blockInputs.erase(it);
78  } else {
79  ++it;
80  }
81  }
82 }
83 
84 vector<shared_ptr<EGS_BlockInput>> EGS_InputStruct::getBlockInputs() {
85  return blockInputs;
86 }
87 
88 shared_ptr<EGS_BlockInput> EGS_InputStruct::getBlockInput(string title, string parentTitle) {
89  // Search for top-level matches first
90  for (auto &block: blockInputs) {
91  if (egsEquivStr(block->getTitle(), title)) {
92  return block;
93  }
94  }
95 
96  // If not found as a top-level block, do a recursive search
97  for (auto &block: blockInputs) {
98  // Special exceptions for application input blocks that have the same title as an existing input block
99  if ((egsEquivStr(title, "planar scoring") || egsEquivStr(title, "spectrum")) && !egsEquivStr(block->getTitle(), parentTitle.c_str())) {
100  continue;
101  }
102  // Do a search (this calls the EGS_BlockInput version of getBlockInput)
103  auto foundBlock = block->getBlockInput(title);
104  if (foundBlock) {
105  return foundBlock;
106  }
107  }
108 
109  return nullptr;
110 }
111 
112 shared_ptr<EGS_BlockInput> EGS_InputStruct::getLibraryBlock(string blockTitle, string libraryName) {
113  // Loop through each input block in the structure to find the library with
114  // the matching name
115  auto libraryBlock = make_shared<EGS_BlockInput>();
116  for (auto &block : blockInputs) {
117  libraryBlock = block->getLibraryBlock(blockTitle, libraryName);
118  if (libraryBlock) {
119  break;
120  }
121  }
122  return libraryBlock;
123 }
124 
125 vector<string> EGS_InputStruct::getLibraryOptions(string blockTitle) {
126  // Loop through each input block in the structure to find all the possible
127  // library options that match the input block type
128  // E.g. find all the geometry libraries
129  vector<string> libOptions;
130  for (auto &block : blockInputs) {
131 
132  // We only search the 2nd-level blocks
133  // i.e. don't look at the geometry definition block, look at the geometries
134  for (auto &block2 : block->getBlockInputs()) {
135  if (block2 && (block2->getTitle() == blockTitle)) {
136  vector<string> libAr = block2->getSingleInput("library")->getValues();
137  for (auto &lib : libAr) {
138  if (lib.size() > 0) {
139  libOptions.push_back(lib);
140  }
141  }
142  }
143  }
144  }
145 
146  // If nothing was found on the 2nd level blocks, search the top level ones
147  // This is the case for shapes
148  if (libOptions.size() < 1) {
149  for (auto &block : blockInputs) {
150 
151  if (block && (block->getTitle() == blockTitle ||
152  // Handle the special case where "target shape" and "source shape" for egs_collimated_source need to match just "shape".
153  (egsEquivStr(block->getTitle(), "shape") && (egsEquivStr(blockTitle, "target shape") || egsEquivStr(blockTitle, "source shape"))))) {
154  vector<string> libAr = block->getSingleInput("library")->getValues();
155  for (auto &lib : libAr) {
156  if (lib.size() > 0) {
157  libOptions.push_back(lib);
158  }
159  }
160  }
161  }
162  }
163 
164  return libOptions;
165 }
166 
167 
168 EGS_BlockInput::EGS_BlockInput() {}
169 
170 EGS_BlockInput::EGS_BlockInput(string blockTit, bool isReq, shared_ptr<EGS_BlockInput> par) {
171  blockTitle = blockTit;
172  isRequired = isReq;
173  parent = par;
174  application = "";
175 }
176 
177 EGS_BlockInput::~EGS_BlockInput() {}
178 
179 void EGS_BlockInput::setTitle(string blockTit) {
180  blockTitle = blockTit;
181 }
182 
184  return blockTitle;
185 }
186 
187 void EGS_BlockInput::setAppName(string appName) {
188  application = appName;
189 }
190 
192  return application;
193 }
194 
195 shared_ptr<EGS_SingleInput> EGS_BlockInput::addSingleInput(string inputTag, bool isReq, const string desc, const vector<string> vals) {
196  // If an input by with the same tag already exists, delete the old one
197  // We don't allow duplicate tags. So new ones overwrite old ones
198  singleInputs.erase(
199  std::remove_if(singleInputs.begin(), singleInputs.end(),
200  [&](const std::shared_ptr<EGS_SingleInput> &inp) {
201  return inp && egsEquivStr(inp->getTag(), inputTag);
202  }),
203  singleInputs.end()
204  );
205  singleInputs.push_back(make_shared<EGS_SingleInput>(inputTag, isReq, desc, vals));
206  return singleInputs.back();
207 }
208 
209 shared_ptr<EGS_BlockInput> EGS_BlockInput::addBlockInput(string blockTit, bool isReq) {
210  blockInputs.push_back(make_shared<EGS_BlockInput>(blockTit, isReq, shared_from_this()));
211 
212  return blockInputs.back();
213 }
214 
215 shared_ptr<EGS_BlockInput> EGS_BlockInput::addBlockInput(shared_ptr<EGS_BlockInput> block) {
216  block->setParent(shared_from_this());
217  blockInputs.push_back(block);
218 
219  return blockInputs.back();
220 }
221 
222 vector<shared_ptr<EGS_SingleInput>> EGS_BlockInput::getSingleInputs() {
223  return singleInputs;
224 }
225 
226 vector<shared_ptr<EGS_SingleInput>> EGS_BlockInput::getSingleInputs(string title) {
227  if (egsEquivStr(blockTitle, title) || (parent != nullptr && egsEquivStr(parent->getTitle(), "media definition") && egsEquivStr(blockTitle, "pegsless")) ||
228  // Handle the special case where "target shape" and "source shape" for egs_collimated_source need to match just "shape".
229  (egsEquivStr(blockTitle, "shape") && (egsEquivStr(title, "target shape") || egsEquivStr(title, "source shape"))) ||
230  // Handle the special case where material names match any block title
231  (egsEquivStr(blockTitle, "myMediumName"))
232  ) {
233  return singleInputs;
234  }
235  else {
236  for (auto &block: blockInputs) {
237  auto inp = block->getSingleInputs(title);
238  if (inp.size() > 0) {
239  return inp;
240  }
241  }
242  // If we don't find it in the first pass, recurse
243  for (auto &block: blockInputs) {
244  auto result = block->getBlockInputs(title);
245  if(result.size() > 0) {
246  auto inp = block->getSingleInputs(title);
247  return inp;
248  }
249  }
250  }
251 
252  return {};
253 }
254 
255 vector<shared_ptr<EGS_BlockInput>> EGS_BlockInput::getBlockInputs() {
256  return blockInputs;
257 }
258 
259 vector<shared_ptr<EGS_BlockInput>> EGS_BlockInput::getBlockInputs(string title) {
260  if (egsEquivStr(blockTitle, title) || (parent != nullptr && egsEquivStr(parent->getTitle(), "media definition") && egsEquivStr(blockTitle, "pegsless")) ||
261  // Handle the special case where "target shape" and "source shape" for egs_collimated_source need to match just "shape".
262  (egsEquivStr(blockTitle, "shape") && (egsEquivStr(title, "target shape") || egsEquivStr(title, "source shape")))) {
263  return blockInputs;
264  }
265  else {
266  for (auto &block: blockInputs) {
267  if (egsEquivStr(block->getTitle(), title)) {
268  return block->getBlockInputs();
269  }
270  }
271  }
272 
273  return {};
274 }
275 
276 shared_ptr<EGS_SingleInput> EGS_BlockInput::getSingleInput(string inputTag) {
277  for (auto &inp : singleInputs) {
278  // TODO: this assumes unique inputTag
279  if (inp && egsEquivStr(inp->getTag(), inputTag)) {
280  return inp;
281  }
282  }
283 
284  // If not found in the top level, search recursively
285  for (auto &block: blockInputs) {
286  auto inp = block->getSingleInput(inputTag);
287  if (inp) {
288  return inp;
289  }
290  }
291 
292  return nullptr;
293 }
294 
295 shared_ptr<EGS_SingleInput> EGS_BlockInput::getSingleInput(string inputTag, string title) {
296  // First search the top-level input block
297  if (egsEquivStr(blockTitle, title) || (parent != nullptr && egsEquivStr(parent->getTitle(), "media definition") && egsEquivStr(blockTitle, "pegsless")) ||
298  // Handle the special case where "target shape" and "source shape" for egs_collimated_source need to match just "shape".
299  (egsEquivStr(blockTitle, "shape") && (egsEquivStr(title, "target shape") || egsEquivStr(title, "source shape"))) ||
300  // Handle the special case where material names match any block title
301  (egsEquivStr(blockTitle, "myMediumName"))
302  ) {
303  for (auto &inp: singleInputs) {
304  // TODO: this assumes unique inputTag
305  if (inp && egsEquivStr(inp->getTag(), inputTag)) {
306  return inp;
307  }
308  }
309  }
310 
311  auto block = getBlockInput(title);
312  if(block) {
313  auto inp = block->getSingleInput(inputTag);
314  if (inp) {
315  return inp;
316  }
317  }
318 
319  return nullptr;
320 }
321 
322 shared_ptr<EGS_BlockInput> EGS_BlockInput::getBlockInput(string title) {
323 
324  if (egsEquivStr(blockTitle, title)) {
325  return shared_from_this();
326  }
327  else {
328  for (auto &block: blockInputs) {
329  if (egsEquivStr(block->getTitle(), title)) {
330  return block;
331  }
332  else if (egsEquivStr(block->getTitle(), "shape") && (egsEquivStr(title, "source shape") || egsEquivStr(title, "target shape"))) {
333  // Handle the special case where "target shape" and "source shape" for egs_collimated_source need to match just "shape".
334  return block;
335  }
336  else {
337  // Do a recursive search
338  auto foundBlock = block->getBlockInput(title);
339  if (foundBlock) {
340  return foundBlock;
341  }
342  }
343  }
344  }
345 
346  if(parent != nullptr && egsEquivStr(parent->getTitle(), "media definition") && egsEquivStr(blockTitle, "pegsless")) {
347  return shared_from_this();
348 
349  }
350 
351 
352  return nullptr;
353 }
354 
355 void EGS_BlockInput::setParent(shared_ptr<EGS_BlockInput> par) {
356  parent = par;
357 }
358 
359 shared_ptr<EGS_BlockInput> EGS_BlockInput::getParent() {
360  return parent;
361 }
362 
363 shared_ptr<EGS_BlockInput> EGS_BlockInput::getLibraryBlock(string blockTitle, string libraryName) {
364  // First search the singleInputs for the library name
365  for (auto &inp: singleInputs) {
366  if (!inp) {
367  continue;
368  }
369  if (egsEquivStr(inp->getTag(), "library")) {
370  if (inp->getValues().size() && egsEquivStr(inp->getValues().front(), libraryName)) {
371  return shared_from_this();
372  }
373  else {
374  break;
375  }
376  }
377  }
378 
379  // If not found, go through input blocks
380  for (auto &block: blockInputs) {
381  auto libraryBlock = block->getLibraryBlock(blockTitle, libraryName);
382  if (libraryBlock) {
383  return libraryBlock;
384  }
385  }
386  return nullptr;
387 }
388 
389 bool EGS_BlockInput::contains(string inputTag) {
390  for (auto &inp: singleInputs) {
391  if (!inp) {
392  continue;
393  }
394  if (egsEquivStr(inp->getTag(), inputTag)) {
395  return true;
396  }
397  }
398  return false;
399 }
400 
401 void EGS_BlockInput::addDependency(shared_ptr<EGS_SingleInput> inp, string val, bool isAntiDependency) {
402  dependencyInp.push_back(inp);
403  dependencyVal.push_back(val);
404  dependencyAnti.push_back(isAntiDependency);
405 }
406 
407 void EGS_BlockInput::addDependency(shared_ptr<EGS_BlockInput> block, bool isAntiDependency) {
408  dependencyBlock = block;
409  dependencyBlockAnti = isAntiDependency;
410 }
411 
412 vector<shared_ptr<EGS_SingleInput>> EGS_BlockInput::getDependencyInp() {
413  return dependencyInp;
414 }
415 
417  return dependencyVal;
418 }
419 
421  return dependencyAnti;
422 }
423 
424 shared_ptr<EGS_BlockInput> EGS_BlockInput::getDependencyBlock() {
425  return dependencyBlock;
426 }
427 
429  return dependencyBlockAnti;
430 }
431 
432 EGS_SingleInput::EGS_SingleInput() {}
433 
434 EGS_SingleInput::EGS_SingleInput(string inputTag, bool isReq, const string desc, const vector<string> vals) {
435  tag = inputTag;
436  isRequired = isReq;
437  description = desc;
438  values = vals;
439 }
440 
441 EGS_SingleInput::~EGS_SingleInput() {}
442 
443 void EGS_SingleInput::addDependency(shared_ptr<EGS_SingleInput> inp, string val, bool isAntiDependency) {
444  dependencyInp.push_back(inp);
445  dependencyVal.push_back(val);
446  dependencyAnti.push_back(isAntiDependency);
447 }
448 
449 void EGS_SingleInput::addDependency(shared_ptr<EGS_BlockInput> block, bool isAntiDependency) {
450  dependencyBlock = block;
451  dependencyBlockAnti = isAntiDependency;
452 }
453 
454 vector<shared_ptr<EGS_SingleInput>> EGS_SingleInput::getDependencyInp() {
455  return dependencyInp;
456 }
457 
459  return dependencyVal;
460 }
461 
463  return dependencyAnti;
464 }
465 
466 shared_ptr<EGS_BlockInput> EGS_SingleInput::getDependencyBlock() {
467  return dependencyBlock;
468 }
469 
471  return dependencyBlockAnti;
472 }
473 
475  return tag;
476 }
477 
479  return isRequired;
480 }
481 
482 const vector<string> EGS_SingleInput::getValues() {
483  return values;
484 }
485 
486 void EGS_SingleInput::setValues(const vector<string> vals) {
487  values = vals;
488 }
489 
491  return description;
492 }
bool getDependencyBlockAnti()
Get whether or not the block dependency is an anti-dependency.
string getTitle()
Get the title of the block.
shared_ptr< EGS_BlockInput > getParent()
Get the parent input block.
string getAppName()
Get the application name of the block.
shared_ptr< EGS_BlockInput > addBlockInput(string blockTit, bool isReq=false)
Add an input block to be nested inside this one.
void setAppName(string appName)
Set the appName of the block.
bool contains(string inputTag)
Check if this input block contains the input inputTag.
vector< shared_ptr< EGS_BlockInput > > getBlockInputs()
Get a list of the nested input blocks for this input block.
shared_ptr< EGS_BlockInput > getBlockInput(string title)
Get the input block title.
void addDependency(shared_ptr< EGS_SingleInput > inp, string val="", bool isAntiDependency=false)
Add a dependency of this input block on input inp being value val.
shared_ptr< EGS_BlockInput > getDependencyBlock()
Get the dependency block (can be only one).
vector< shared_ptr< EGS_SingleInput > > getSingleInputs()
Get a list of the inputs for this input block.
vector< bool > getDependencyAnti()
Get a list of whether or not these are anti-dependencies.
vector< shared_ptr< EGS_SingleInput > > getDependencyInp()
Get the input dependency.
shared_ptr< EGS_BlockInput > getLibraryBlock(string blockTitle, string libraryName)
Get the input block containing the library tag matching libraryName.
vector< string > getDependencyVal()
Get the input dependency required value.
void setParent(shared_ptr< EGS_BlockInput > par)
Set the parent to be par.
shared_ptr< EGS_SingleInput > getSingleInput(string inputTag)
Get the input named inputTag.
void setTitle(string blockTit)
Set the title of the block.
shared_ptr< EGS_SingleInput > addSingleInput(string inputTag, bool isReq, const string desc, const vector< string > vals=vector< string >())
Add a single input.
vector< string > getLibraryOptions(string blockTitle)
Get the possible values for the library tag for the block blockTitle.
shared_ptr< EGS_BlockInput > getLibraryBlock(string blockTitle, string libraryName)
Get the input block blockTitle that contains the library libraryName.
void addBlockInputs(vector< shared_ptr< EGS_BlockInput >> blocks)
Add a list of input blocks that are already defined as blocks.
void removeBlockInputByApp(string appName)
Removes block inputs in input struct based on name of app variable.
shared_ptr< EGS_BlockInput > addBlockInput(string blockTit, bool isReq=false)
Add an input block named blockTit.
void removeBlockInput(string blockTitle)
Remove the input block named blockTitle.
vector< shared_ptr< EGS_BlockInput > > getBlockInputs()
Get the list of input blocks.
shared_ptr< EGS_BlockInput > getBlockInput(string title, string parentTitle="")
Get the input block named title.
string getTag()
Get the name of the input.
bool getDependencyBlockAnti()
Get whether or not the block dependency is an anti-dependency.
vector< shared_ptr< EGS_SingleInput > > getDependencyInp()
Get a list of all the dependencies for this input.
void setValues(const vector< string > vals)
Set the list of possible values for this input.
vector< string > getDependencyVal()
Get a list of the required dependency values.
vector< bool > getDependencyAnti()
Get a list of whether or not these are anti-dependencies.
const vector< string > getValues()
Get the list of possible values for this input.
shared_ptr< EGS_BlockInput > getDependencyBlock()
Get the dependency block (can be only one).
bool getRequired()
Get whether or not this input is required.
string getDescription()
Get the description for this input.
void addDependency(shared_ptr< EGS_SingleInput > inp, string val="", bool isAntiDependency=false)
Add a dependency for this input, by the name of inp.
Global egspp functions header file.
The input struct header file.