GammaLib  2.1.0.dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GModelAssociations.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * GModelAssociations.cpp - Model associations container class *
3  * ----------------------------------------------------------------------- *
4  * copyright (C) 2020-2022 by Juergen Knoedlseder *
5  * ----------------------------------------------------------------------- *
6  * *
7  * This program is free software: you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation, either version 3 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License *
18  * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19  * *
20  ***************************************************************************/
21 /**
22  * @file GModelAssociations.cpp
23  * @brief Model associations container class implementation
24  * @author Juergen Knoedlseder
25  */
26 
27 /* __ Includes ___________________________________________________________ */
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include "GTools.hpp"
32 #include "GException.hpp"
33 #include "GXmlElement.hpp"
34 #include "GModelAssociations.hpp"
35 #include "GModelAssociation.hpp"
36 
37 /* __ Method name definitions ____________________________________________ */
38 #define G_ACCESS "GModelAssociations::operator[](std::string&)"
39 #define G_AT "GModelAssociations::at(int&)"
40 #define G_SET1 "GModelAssociations::set(int&, GModelAssociation&)"
41 #define G_SET2 "GModelAssociations::set(std::string&, GModelAssociation&)"
42 #define G_APPEND "GModelAssociations::append(GModelAssociation&)"
43 #define G_INSERT1 "GModelAssociations::insert(int&, GModelAssociation&)"
44 #define G_INSERT2 "GModelAssociations::insert(std::string&, "\
45  "GModelAssociation&)"
46 #define G_REMOVE1 "GModelAssociations::remove(int&)"
47 #define G_REMOVE2 "GModelAssociations::remove(std::string&)"
48 #define G_EXTEND "GModelAssociations::extend(GModelAssociations&)"
49 #define G_READ "GModelAssociations::read(GXml&)"
50 #define G_GET_ASSOCIATION_XML "GModelAssociations::get_association_xml("\
51  "GXmlElement&, std::string&)"
52 
53 /* __ Macros _____________________________________________________________ */
54 
55 /* __ Coding definitions _________________________________________________ */
56 
57 /* __ Debug definitions __________________________________________________ */
58 
59 
60 /*==========================================================================
61  = =
62  = Constructors/destructors =
63  = =
64  ==========================================================================*/
65 
66 /***********************************************************************//**
67  * @brief Void constructor
68  ***************************************************************************/
70 {
71  // Initialise members
72  init_members();
73 
74  // Return
75  return;
76 }
77 
78 
79 /***********************************************************************//**
80  * @brief XML element constructor
81  *
82  * @param[in] xml XML element.
83  *
84  * Construct a model associations container from an XML element.
85  ***************************************************************************/
87 {
88  // Initialise private members
89  init_members();
90 
91  // Read model associations container from XML element
92  read(xml);
93 
94  // Return
95  return;
96 }
97 
98 
99 /***********************************************************************//**
100  * @brief Copy constructor
101  *
102  * @param[in] associations Model associations container.
103  ***************************************************************************/
105 {
106  // Initialise members
107  init_members();
108 
109  // Copy members
110  copy_members(associations);
111 
112  // Return
113  return;
114 }
115 
116 
117 /***********************************************************************//**
118  * @brief Destructor
119  ***************************************************************************/
121 {
122  // Free members
123  free_members();
124 
125  // Return
126  return;
127 }
128 
129 
130 /*==========================================================================
131  = =
132  = Operators =
133  = =
134  ==========================================================================*/
135 
136 /***********************************************************************//**
137  * @brief Assignment operator
138  *
139  * @param[in] associations Model associations container.
140  * @return Model associations container.
141  ***************************************************************************/
143 {
144  // Execute only if object is not identical
145  if (this != &associations) {
146 
147  // Free members
148  free_members();
149 
150  // Initialise members
151  init_members();
152 
153  // Copy members
154  copy_members(associations);
155 
156  } // endif: object was not identical
157 
158  // Return
159  return *this;
160 }
161 
162 
163 /***********************************************************************//**
164  * @brief Return reference to model association
165  *
166  * @param[in] name Model association name.
167  *
168  * @exception GException::invalid_argument
169  * Model association with specified @p name not found in container.
170  *
171  * Returns a reference to the model with the specified @p name.
172  ***************************************************************************/
174 {
175  // Return association using const method
176  return const_cast<GModelAssociation&>((*static_cast<const GModelAssociations*>(this))[name]);
177 }
178 
179 
180 /***********************************************************************//**
181  * @brief Return reference to model association (const version)
182  *
183  * @param[in] name Model association name.
184  *
185  * @exception GException::invalid_argument
186  * Model association with specified @p name not found in container.
187  *
188  * Returns a const reference to the model with the specified @p name.
189  ***************************************************************************/
190 const GModelAssociation& GModelAssociations::operator[](const std::string& name) const
191 {
192  // Get model index
193  int index = get_index(name);
194 
195  // Throw exception if model name was not found
196  if (index == -1) {
197  std::string msg = "Model association \""+name+"\" not found in "
198  "container.";
200  }
201 
202  // Return pointer
203  return m_associations[index];
204 }
205 
206 
207 /*==========================================================================
208  = =
209  = Public methods =
210  = =
211  ==========================================================================*/
212 
213 /***********************************************************************//**
214  * @brief Clear object
215  *
216  * Removes all model associations from the container.
217  ***************************************************************************/
219 {
220  // Free class members
221  free_members();
222 
223  // Initialise members
224  init_members();
225 
226  // Return
227  return;
228 }
229 
230 
231 /***********************************************************************//**
232  * @brief Clone instance
233  *
234  * @return Pointer to deep copy of model associations container
235  *
236  * Makes a deep copy of the model associations container instance.
237  ***************************************************************************/
239 {
240  return new GModelAssociations(*this);
241 }
242 
243 
244 /***********************************************************************//**
245  * @brief Return reference to model association
246  *
247  * @param[in] index Model association index [0,...,size()-1].
248  *
249  * @exception GException::out_of_range
250  * Model association index is out of range.
251  *
252  * Returns a reference to the model association with the specified @p index.
253  ***************************************************************************/
255 {
256  // Return association using const method
257  return const_cast<GModelAssociation&>(static_cast<const GModelAssociations*>(this)->at(index));
258 }
259 
260 
261 /***********************************************************************//**
262  * @brief Return reference to model association (const version)
263  *
264  * @param[in] index Model association index [0,...,size()-1].
265  *
266  * @exception GException::out_of_range
267  * Model association index is out of range.
268  *
269  * Returns a const reference to the model association with the specified
270  * @p index.
271  ***************************************************************************/
272 const GModelAssociation& GModelAssociations::at(const int& index) const
273 {
274  // Compile option: raise an exception if index is out of range
275  #if defined(G_RANGE_CHECK)
276  if (index < 0 || index >= size()) {
277  throw GException::out_of_range(G_AT, "Model association index", index, size());
278  }
279  #endif
280 
281  // Return pointer
282  return m_associations[index];
283 }
284 
285 
286 /***********************************************************************//**
287  * @brief Append model association to container
288  *
289  * @param[in] association Model association.
290  * @return Reference to appended model association.
291  *
292  * @exception GException::invalid_value
293  * Name of model association exists already in container.
294  *
295  * Appends model association to the container.
296  ***************************************************************************/
298 {
299  // Check if a model association with specified name does not yet exist
300  int inx = get_index(association.name());
301  if (inx != -1) {
302  std::string msg =
303  "Attempt to append model association \""+association.name()+"\" "
304  "to association container, but an association with the same name "
305  "exists already at index "+gammalib::str(inx)+" in the container. "
306  "Every model association in the container needs a unique name.";
308  }
309 
310  // Append model association
311  m_associations.push_back(association);
312 
313  // Return reference to model association
314  return (m_associations[size()-1]);
315 }
316 
317 
318 /***********************************************************************//**
319  * @brief Insert model association into container
320  *
321  * @param[in] index Model association index [0,...,size()-1].
322  * @param[in] association Model association.
323  * @return Reference to inserted model association.
324  *
325  * @exception GException::out_of_range
326  * Model association index is out of range.
327  * @exception GException::invalid_value
328  * Name of model association exists already in container.
329  *
330  * Inserts a @p model association into the container before the model
331  * association with the specified @p index.
332  ***************************************************************************/
334  const GModelAssociation& association)
335 {
336  // Compile option: raise exception if index is out of range
337  #if defined(G_RANGE_CHECK)
338  if (is_empty()) {
339  if (index > 0) {
340  throw GException::out_of_range(G_INSERT1, "Model association index",
341  index, size());
342  }
343  }
344  else {
345  if (index < 0 || index >= size()) {
346  throw GException::out_of_range(G_INSERT1, "Model association index",
347  index, size());
348  }
349  }
350  #endif
351 
352  // Check if a model association with specified name does not yet exist
353  int inx = get_index(association.name());
354  if (inx != -1) {
355  std::string msg =
356  "Attempt to insert model association \""+association.name()+"\" "
357  "in container before index "+gammalib::str(index)+", but an "
358  "association with the same name exists already at index "+
359  gammalib::str(inx)+" in the container. Every model association "
360  "in the container needs a unique name.";
362  }
363 
364  // Inserts deep copy of model association
365  m_associations.insert(m_associations.begin()+index, association);
366 
367  // Return reference to model association
368  return (m_associations[index]);
369 }
370 
371 
372 /***********************************************************************//**
373  * @brief Insert model association into container
374  *
375  * @param[in] name Model association name.
376  * @param[in] association Model association.
377  * @return Reference to inserted model association.
378  *
379  * @exception GException::invalid_argument
380  * Model association with specified name not found in container.
381  * @exception GException::invalid_value
382  * Name of model association exists already in container.
383  *
384  * Inserts a @p model association into the container before the model
385  * association with the specified @p name.
386  ***************************************************************************/
388  const GModelAssociation& association)
389 {
390  // Get association index
391  int index = get_index(name);
392 
393  // Throw exception if parameter name was not found
394  if (index == -1) {
395  std::string msg = "Model association \""+name+"\" not found in "
396  "container.";
398  }
399 
400  // Check if a model with specified name does not yet exist
401  int inx = get_index(association.name());
402  if (inx != -1) {
403  std::string msg =
404  "Attempt to insert model association \""+association.name()+"\" "
405  "in container before index "+gammalib::str(index)+", but an "
406  "association with the same name exists already at index "+
407  gammalib::str(inx)+" in the container. Every model association "
408  "in the container needs a unique name.";
410  }
411 
412  // Inserts deep copy of model association
413  m_associations.insert(m_associations.begin()+index, association);
414 
415  // Return reference to model association
416  return (m_associations[index]);
417 }
418 
419 
420 /***********************************************************************//**
421  * @brief Remove model association from container
422  *
423  * @param[in] index Model association index [0,...,size()-1].
424  *
425  * @exception GException::out_of_range
426  * Model association index is out of range.
427  *
428  * Remove model association of specified @p index from container.
429  ***************************************************************************/
430 void GModelAssociations::remove(const int& index)
431 {
432  // Compile option: raise exception if index is out of range
433  #if defined(G_RANGE_CHECK)
434  if (index < 0 || index >= size()) {
435  throw GException::out_of_range(G_REMOVE1, "Model association index",
436  index, size());
437  }
438  #endif
439 
440  // Erase model association component from container
441  m_associations.erase(m_associations.begin() + index);
442 
443  // Return
444  return;
445 }
446 
447 
448 /***********************************************************************//**
449  * @brief Remove model association from container
450  *
451  * @param[in] name Model association name.
452  *
453  * @exception GException::invalid_argument
454  * Model association with specified name not found in container.
455  *
456  * Remove model association of specified @p name from container.
457  ***************************************************************************/
458 void GModelAssociations::remove(const std::string& name)
459 {
460  // Get parameter index
461  int index = get_index(name);
462 
463  // Throw exception if parameter name was not found
464  if (index == -1) {
465  std::string msg = "Model association \""+name+"\" not found in "
466  "container.";
468  }
469 
470  // Erase model association component from container
471  m_associations.erase(m_associations.begin() + index);
472 
473  // Return
474  return;
475 }
476 
477 
478 /***********************************************************************//**
479  * @brief Append model association container
480  *
481  * @param[in] associations Model association container.
482  *
483  * Append model association container to the container.
484  ***************************************************************************/
486 {
487  // Do nothing if model association container is empty
488  if (!associations.is_empty()) {
489 
490  // Get size. Note that we extract the size first to avoid an
491  // endless loop that arises when a container is appended to
492  // itself.
493  int num = associations.size();
494 
495  // Reserve enough space
496  reserve(size() + num);
497 
498  // Loop over all model association components and append pointers
499  // to deep copies
500  for (int i = 0; i < num; ++i) {
501 
502  // Check if model association name does not yet exist
503  int inx = get_index(associations[i].name());
504  if (inx != -1) {
505  std::string msg =
506  "Attempt to append model association \""+
507  associations[i].name()+"\" to container, but an "
508  "association with the same name exists already at "
509  "index "+gammalib::str(inx)+" in the container. Every "
510  "model association in the container needs a unique name.";
512  }
513 
514  // Append model association to container
515  m_associations.push_back(associations[i]);
516 
517  } // endfor: looped over all model associations
518 
519  } // endif: model association container was not empty
520 
521  // Return
522  return;
523 }
524 
525 
526 /***********************************************************************//**
527  * @brief Signals if model association name exists
528  *
529  * @param[in] name Model association name.
530  * @return True if model association with specified @p name exists.
531  *
532  * Searches all model association names for a match with the specified
533  * @p name. If the specified name has been found, true is returned.
534  ***************************************************************************/
535 bool GModelAssociations::contains(const std::string& name) const
536 {
537  // Get model association index
538  int index = get_index(name);
539 
540  // Return
541  return (index != -1);
542 }
543 
544 
545 /***********************************************************************//**
546  * @brief Read model associations from XML document
547  *
548  * @param[in] xml XML element.
549  *
550  * Read model associations from the XML element. The XML element is expected
551  * to have the following structure
552  *
553  * <associations>
554  * <association name="Crab">
555  * <property name="RA" value="83.6331"/>
556  * <property name="DEC" value="22.0145"/>
557  * <property name="distance" value="0.0123"/>
558  * <property name="probability" value="0.978"/>
559  * </association>
560  * </associations>
561  *
562  * This method does nothing if no "associations" tag is present in the XML
563  * element.
564  ***************************************************************************/
566 {
567  // Initialise associations
568  m_associations.clear();
569 
570  // Continue only if there is an <associations> tag
571  if (xml.elements("associations") > 0) {
572 
573  // Get pointer on associations
574  const GXmlElement* associations = xml.element("associations", 0);
575 
576  // Determine number of associations
577  int n = associations->elements("association");
578 
579  // Loop over all associations
580  for (int i = 0; i < n; ++i) {
581 
582  // Get pointer on association
583  const GXmlElement* element = associations->element("association", i);
584 
585  // Construct association from XML element
586  GModelAssociation association(*element);
587 
588  // Append assocition to container
589  append(association);
590 
591  } // endfor: looped over all associations
592 
593  } // endif: an association tag was present
594 
595  // Return
596  return;
597 }
598 
599 
600 /***********************************************************************//**
601  * @brief Write models into XML element
602  *
603  * @param[in] xml XML element.
604  *
605  * Write model associations into the first "associations" element that is
606  * found in the XML element. In case that no "associations" element exists,
607  * one is added to the XML element. The written XML element has the
608  * following structure
609  *
610  * <associations>
611  * <association name="Crab">
612  * <property name="RA" value="83.6331"/>
613  * <property name="DEC" value="22.0145"/>
614  * <property name="distance" value="0.0123"/>
615  * <property name="probability" value="0.978"/>
616  * </association>
617  * </associations>
618  *
619  * This method does nothing if there are no associations in the instance.
620  ***************************************************************************/
622 {
623  // Continue only if there are associations
624  if (!is_empty()) {
625 
626  // If there is no associations tag then append one
627  if (xml.elements("associations") == 0) {
628  xml.append(GXmlElement("associations"));
629  }
630 
631  // Get pointer on model associations
632  GXmlElement* associations = xml.element("associations", 0);
633 
634  // Write all model associations into the XML element
635  for (int i = 0; i < size(); ++i) {
636  GXmlElement* association = get_association_xml(*associations,
637  m_associations[i].name());
638  m_associations[i].write(*association);
639  }
640 
641  } // endif: there were associations to write
642 
643  // Return
644  return;
645 }
646 
647 
648 /***********************************************************************//**
649  * @brief Print model associations
650  *
651  * @param[in] chatter Chattiness.
652  * @return String containing model association container information.
653  *
654  * Prints all model associations into a string.
655  ***************************************************************************/
656 std::string GModelAssociations::print(const GChatter& chatter) const
657 {
658  // Initialise result string
659  std::string result;
660 
661  // Continue only if chatter is not silent
662  if (chatter != SILENT) {
663 
664  // Append header
665  result.append("=== GModelAssociations ===");
666 
667  // Append information
668  result.append("\n"+gammalib::parformat("Number of associations"));
669  result.append(gammalib::str(size()));
670 
671  // Append associations
672  for (int i = 0; i < size(); ++i) {
673  result.append("\n"+m_associations[i].print(chatter));
674  }
675 
676  } // endif: chatter was not silent
677 
678  // Return result
679  return result;
680 }
681 
682 
683 /*==========================================================================
684  = =
685  = Private methods =
686  = =
687  ==========================================================================*/
688 
689 /***********************************************************************//**
690  * @brief Initialise class members
691  ***************************************************************************/
693 {
694  // Initialise members
695  m_associations.clear();
696 
697  // Return
698  return;
699 }
700 
701 
702 /***********************************************************************//**
703  * @brief Copy class members
704  *
705  * @param[in] associations Model association container.
706  ***************************************************************************/
708 {
709  // Copy members
710  m_associations = associations.m_associations;
711 
712  // Return
713  return;
714 }
715 
716 
717 /***********************************************************************//**
718  * @brief Delete class members
719  ***************************************************************************/
721 {
722  // Return
723  return;
724 }
725 
726 
727 /***********************************************************************//**
728  * @brief Return model association index by name
729  *
730  * @param[in] name Model ssociation name.
731  * @return Model association index (-1 if not found)
732  *
733  * Returns model association index based on the specified @p name. If no
734  * model association with the specified @p name is found the method returns
735  * -1.
736  ***************************************************************************/
737 int GModelAssociations::get_index(const std::string& name) const
738 {
739  // Initialise index
740  int index = -1;
741 
742  // Search model association with specified name
743  for (int i = 0; i < size(); ++i) {
744  if (m_associations[i].name() == name) {
745  index = i;
746  break;
747  }
748  }
749 
750  // Return index
751  return index;
752 }
753 
754 
755 /***********************************************************************//**
756  * @brief Return pointer to model association with given name in XML element
757  *
758  * @param[in] xml XML element.
759  * @param[in] name Model association name.
760  * @return Pointer to model association XML element.
761  *
762  * @exception GException::invalid_value
763  * Invalid XML format encountered.
764  *
765  * Returns pointer to model association with given @p name in XML element.
766  * If the @p name is not found, a model association with the given @p name
767  * is added.
768  *
769  * The function checks for multiple occurences of a model association and
770  * throws an exception in case that more than one association with a given
771  * name is found.
772  ***************************************************************************/
774  const std::string& name) const
775 {
776  // Initialize XML element pointer
777  GXmlElement* association = NULL;
778 
779  // Number of elements
780  int number = 0;
781 
782  // Get number of elements in XML element
783  int n = xml.elements("association");
784 
785  // Search for property with given name
786  for (int i = 0; i < n; ++i) {
787  GXmlElement* element = xml.element("association", i);
788  if (element->attribute("name") == name) {
789  association = element;
790  number++;
791  }
792  }
793 
794  // Create property if none was found
795  if (number == 0) {
796  association = static_cast<GXmlElement*>(xml.append(GXmlElement("association name=\""+name+"\"")));
797  number++;
798  }
799 
800  // Throw case dependent exception
801  if (number < 1) {
802  std::string msg = "Model association \""+name+"\" not found in XML "
803  " element. Please verify the XML format.";
805  }
806  else if (number > 1) {
807  std::string msg = "Model association \""+name+"\" found "+
808  gammalib::str(number)+" times in XML element."
809  " Please verify the XML format.";
811  }
812 
813  // Return
814  return association;
815 }
std::string number(const std::string &noun, const int &number)
Convert singular noun into number noun.
Definition: GTools.cpp:1167
XML element node class interface definition.
int size(void) const
Return number of associations in container.
#define G_GET_ASSOCIATION_XML
#define G_REMOVE2
GModelAssociations & operator=(const GModelAssociations &associations)
Assignment operator.
GModelAssociation & insert(const int &index, const GModelAssociation &association)
Insert model association into container.
XML element node class.
Definition: GXmlElement.hpp:48
virtual int elements(void) const
Return number of GXMLElement children of node.
Definition: GXmlNode.cpp:586
void clear(void)
Clear object.
Gammalib tools definition.
std::string print(const GChatter &chatter=NORMAL) const
Print model associations.
Model association class.
Model associations container class definition.
void write(GXmlElement &xml) const
Write models into XML element.
bool contains(const std::string &name) const
Signals if model association name exists.
GModelAssociation & append(const GModelAssociation &association)
Append model association to container.
void init_members(void)
Initialise class members.
const GXmlAttribute * attribute(const int &index) const
Return attribute.
virtual ~GModelAssociations(void)
Destructor.
#define G_AT
GModelAssociation & operator[](const int &index)
Return reference to association.
void copy_members(const GModelAssociations &associations)
Copy class members.
void remove(const int &index)
Remove model association from container.
#define G_APPEND
GModelAssociations(void)
Void constructor.
GChatter
Definition: GTypemaps.hpp:33
int get_index(const std::string &name) const
Return model association index by name.
GModelAssociations * clone(void) const
Clone instance.
virtual GXmlElement * element(const int &index)
Return pointer to GXMLElement child.
Definition: GXmlNode.cpp:640
void read(const GXmlElement &xml)
Read model associations from XML document.
bool is_empty(void) const
Signals if there are no associations in container.
Model association class definition.
void reserve(const int &num)
Reserves space for associations in container.
#define G_EXTEND
Exception handler interface definition.
#define G_REMOVE1
#define G_ACCESS
Model associations container class.
const std::string & name(void) const
Return association name.
GXmlElement * get_association_xml(GXmlElement &xml, const std::string &name) const
Return pointer to model association with given name in XML element.
std::vector< GModelAssociation > m_associations
List of associations.
void extend(const GModelAssociations &associations)
Append model association container.
virtual GXmlNode * append(const GXmlNode &node)
Append XML child node.
Definition: GXmlNode.cpp:287
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition: GTools.cpp:1143
#define G_INSERT2
GModelAssociation & at(const int &index)
Return reference to model association.
#define G_INSERT1
void free_members(void)
Delete class members.
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition: GTools.cpp:489