GammaLib  2.1.0.dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GApplicationPars.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * GApplicationPars.cpp - Application parameters *
3  * ----------------------------------------------------------------------- *
4  * copyright (C) 2010-2021 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 GApplicationPars.cpp
23  * @brief Application parameter container class implementation
24  * @author Juergen Knoedlseder
25  */
26 
27 /* __ Includes ___________________________________________________________ */
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include <pwd.h> // user/passwd function
32 #include <fcntl.h> // for file locking
33 #include <unistd.h> // access() function
34 #include <sys/stat.h> // mkdir() function
35 #include <cstdlib> // std::getenv() function
36 #include <cstdio> // std::fopen(), etc. functions
37 #include <sstream>
38 #include "GException.hpp"
39 #include "GTools.hpp"
40 #include "GFilename.hpp"
41 #include "GApplicationPars.hpp"
42 
43 /* __ Method name definitions ____________________________________________ */
44 #define G_ACCESS "GApplicationPars::operator[](std::string&)"
45 #define G_AT "GApplicationPar& GApplicationPars::at(int&)"
46 #define G_APPEND "GApplicationPars::append(GApplicationPar&)"
47 #define G_INSERT1 "GApplicationPar& GApplicationPars::insert(int&, "\
48  "GApplicationPar&)"
49 #define G_INSERT2 "GApplicationPar& GApplicationPars::insert(std::string&, "\
50  "GApplicationPar&)"
51 #define G_REMOVE1 "GApplicationPars::remove(int&)"
52 #define G_REMOVE2 "GApplicationPars::remove(std::string&)"
53 #define G_EXTEND "GApplicationPars::extend(GApplicationPars&)"
54 #define G_LOAD1 "GApplicationPars::load(GFilename&)"
55 #define G_LOAD2 "GApplicationPars::load(GFilename&, "\
56  "std::vector<std::string>&)"
57 #define G_SAVE "GApplicationPars::save(GFilename&)"
58 #define G_OUTPATH "GApplicationPars::outpath(std::string&)"
59 #define G_READ "GApplicationPars::read(std::string&)"
60 #define G_WRITE "GApplicationPars::write(std::string&)"
61 #define G_PARSE "GApplicationPars::parse()"
62 
63 /* __ Macros _____________________________________________________________ */
64 
65 /* __ Coding definitions _________________________________________________ */
66 #define G_LOCK_PARFILE //!< Enables parfile locking
67 //#define G_CHECK_LOCK_PARFILE //!< Enables check of parfile locking
68 
69 /* __ Debug definitions __________________________________________________ */
70 
71 
72 /*==========================================================================
73  = =
74  = Constructors/destructors =
75  = =
76  ==========================================================================*/
77 
78 /***********************************************************************//**
79  * @brief Void constructor
80  ***************************************************************************/
82 {
83  // Initialise private members for clean destruction
84  init_members();
85 
86  // Return
87  return;
88 }
89 
90 
91 /***********************************************************************//**
92  * @brief Parameter file constructor
93  *
94  * @param[in] filename Parameter filename.
95  ***************************************************************************/
97 {
98  // Initialise private members for clean destruction
99  init_members();
100 
101  // Load parameters
102  load(filename);
103 
104  // Return
105  return;
106 }
107 
108 /***********************************************************************//**
109  * @brief Parameter constructor
110  *
111  * @param[in] filename Parameter filename.
112  * @param[in] args Command line arguments.
113  ***************************************************************************/
115  const std::vector<std::string>& args)
116 {
117  // Initialise private members for clean destruction
118  init_members();
119 
120  // Load parameters
121  load(filename, args);
122 
123  // Return
124  return;
125 }
126 
127 
128 /***********************************************************************//**
129  * @brief Copy constructor
130  *
131  * @param[in] pars Parameter container.
132  ***************************************************************************/
134 {
135  // Initialise private members for clean destruction
136  init_members();
137 
138  // Copy members
139  copy_members(pars);
140 
141  // Return
142  return;
143 }
144 
145 
146 /***********************************************************************//**
147  * @brief Destructor
148  ***************************************************************************/
150 {
151  // Free members
152  free_members();
153 
154  // Return
155  return;
156 }
157 
158 
159 /*==========================================================================
160  = =
161  = Operators =
162  = =
163  ==========================================================================*/
164 
165 /***********************************************************************//**
166  * @brief Assignment operator
167  *
168  * @param[in] pars Parameter container.
169  * @return Parameter container.
170  ***************************************************************************/
172 {
173  // Execute only if object is not identical
174  if (this != &pars) {
175 
176  // Free members
177  free_members();
178 
179  // Initialise private members for clean destruction
180  init_members();
181 
182  // Copy members
183  copy_members(pars);
184 
185  } // endif: object was not identical
186 
187  // Return
188  return *this;
189 }
190 
191 
192 /***********************************************************************//**
193  * @brief Returns reference to parameter
194  *
195  * @param[in] name Parameter name.
196  * @return Parameter.
197  *
198  * @exception GException::invalid_argument
199  * Parameter with specified name not found in container.
200  ***************************************************************************/
202 {
203  // Get parameter index
204  int index = get_index(name);
205 
206  // Throw exception if parameter name has not been found
207  if (index == -1) {
208  std::string msg = "Parameter \""+name+"\" has not been found in "
209  "parameter file. Please specify a valid parameter "
210  "name.";
212  }
213 
214  // Return reference
215  return (m_pars[index]);
216 }
217 
218 
219 /***********************************************************************//**
220  * @brief Returns reference to parameter (const version)
221  *
222  * @param[in] name Parameter name.
223  * @return Parameter.
224  *
225  * @exception GException::invalid_argument
226  * Parameter with specified name not found in container.
227  ***************************************************************************/
228 const GApplicationPar& GApplicationPars::operator[](const std::string& name) const
229 {
230  // Get parameter index
231  int index = get_index(name);
232 
233  // Throw exception if parameter name has not been found
234  if (index == -1) {
235  std::string msg = "Parameter \""+name+"\" has not been found in "
236  "parameter file. Please specify a valid parameter "
237  "name.";
239  }
240 
241  // Return reference
242  return (m_pars[index]);
243 }
244 
245 
246 /*==========================================================================
247  = =
248  = Public methods =
249  = =
250  ==========================================================================*/
251 
252 /***********************************************************************//**
253  * @brief Clear parameter container
254  ***************************************************************************/
256 {
257  // Free members
258  free_members();
259 
260  // Init members
261  init_members();
262 
263  // Return
264  return;
265 }
266 
267 
268 /***********************************************************************//**
269  * @brief Clone parameter container
270  *
271  * @return Pointer to deep copy of parameter container.
272  ***************************************************************************/
274 {
275  return (new GApplicationPars(*this));
276 }
277 
278 
279 /***********************************************************************//**
280  * @brief Returns reference to parameter
281  *
282  * @param[in] index Parameter index [0,...,size()-1].
283  *
284  * @exception GException::out_of_range
285  * Parameter index is out of range.
286  ***************************************************************************/
288 {
289  // Compile option: raise an exception if index is out of range
290  #if defined(G_RANGE_CHECK)
291  if (index < 0 || index >= size()) {
292  throw GException::out_of_range(G_AT, "Parameter index", index, size());
293  }
294  #endif
295 
296  // Return reference
297  return (m_pars[index]);
298 }
299 
300 
301 /***********************************************************************//**
302  * @brief Returns reference to parameter (const version)
303  *
304  * @param[in] index Parameter index [0,...,size()-1].
305  *
306  * @exception GException::out_of_range
307  * Parameter index is out of range.
308  ***************************************************************************/
309 const GApplicationPar& GApplicationPars::at(const int& index) const
310 {
311  // Compile option: raise an exception if index is out of range
312  #if defined(G_RANGE_CHECK)
313  if (index < 0 || index >= size()) {
314  throw GException::out_of_range(G_AT, "Parameter index", index, size());
315  }
316  #endif
317 
318  // Return reference
319  return (m_pars[index]);
320 }
321 
322 
323 /***********************************************************************//**
324  * @brief Append parameter to container
325  *
326  * @param[in] par Parameter.
327  * @return Reference to deep copy of appended parameter.
328  *
329  * @exception GException::invalid_value
330  * Parameter with same name exists already in container.
331  *
332  * This method appends one parameter to the parameter container. The
333  * parameter provided to the method can be deleted after calling this method.
334  ***************************************************************************/
336 {
337  // Check if a parameter with specified name does not yet exist
338  int inx = get_index(par.name());
339  if (inx != -1) {
340  std::string msg =
341  "Attempt to append parameter with name \""+par.name()+"\" in"
342  " parameter container, but a parameter with the same name exists"
343  " already at index "+gammalib::str(inx)+" in the container.\n"
344  "Every parameter in the parameter container needs a unique name.";
346  }
347 
348  // Append parameter
349  m_pars.push_back(par);
350 
351  // Get reference of appended parameter
352  GApplicationPar& parameter = m_pars[m_pars.size()-1];
353 
354  // Build parameter file line
355  size_t start = 0;
356  size_t stop = 0;
357  std::string line = parline(parameter, &start, &stop);
358 
359  // Append parameter file line and attributes
360  m_line.push_back(m_parfile.size());
361  m_parfile.push_back(line);
362  m_vstart.push_back(start);
363  m_vstop.push_back(stop);
364 
365  // Return parameter reference
366  return parameter;
367 }
368 
369 
370 /***********************************************************************//**
371  * @brief Append standard parameters to container
372  *
373  * This method appends the standard parameters to the parameter container.
374  * Standard parameters are: "chatter", "clobber", "debug" and "mode".
375  ***************************************************************************/
377 {
378  // Append standard parameters
379  append(GApplicationPar("chatter","i","h","2","0","4","Chattiness of output"));
380  append(GApplicationPar("clobber","b","h","yes","","","Overwrite existing output files with new output files?"));
381  append(GApplicationPar("debug","b","h","no","","","Debugging mode activated"));
382  append(GApplicationPar("mode","s","h","ql","","","Mode of automatic parameters"));
383 
384  // Return
385  return;
386 }
387 
388 
389 /***********************************************************************//**
390  * @brief Insert parameter into container
391  *
392  * @param[in] index Parameter index [0,...,size()-1].
393  * @param[in] par Parameter.
394  * @return Reference to deep copy of inserted parameter.
395  *
396  * Inserts a parameter into the container before the parameter with the
397  * specified @p index.
398  ***************************************************************************/
400 {
401  // Compile option: raise exception if index is out of range
402  #if defined(G_RANGE_CHECK)
403  if (is_empty()) {
404  if (index > 0) {
405  throw GException::out_of_range(G_INSERT1, "Parameter index", index, size());
406  }
407  }
408  else {
409  if (index < 0 || index >= size()) {
410  throw GException::out_of_range(G_INSERT1, "Parameter index", index, size());
411  }
412  }
413  #endif
414 
415  // Check if a parameter with specified name does not yet exist
416  int inx = get_index(par.name());
417  if (inx != -1) {
418  std::string msg =
419  "Attempt to insert parameter with name \""+par.name()+"\" in"
420  " parameter container before index "+gammalib::str(index)+
421  ", but a parameter with the same name exists already at index "+
422  gammalib::str(inx)+" in the container.\n"
423  "Every parameter in the parameter container needs a unique name.";
425  }
426 
427  // Inserts parameter
428  m_pars.insert(m_pars.begin()+index, par);
429 
430  // Get reference of appended parameter
431  GApplicationPar& parameter = m_pars[m_pars.size()-1];
432 
433  // Build parameter file line
434  size_t start = 0;
435  size_t stop = 0;
436  std::string line = parline(parameter, &start, &stop);
437 
438  // Determine at which line number of the parameter file the parameter
439  // should be inserted
440  int line_number = m_line[index];
441 
442  // Insert parameter file line and parameter attributes
443  m_parfile.insert(m_parfile.begin()+line_number, line);
444  m_line.insert(m_line.begin()+index, line_number);
445  m_vstart.insert(m_vstart.begin()+index, start);
446  m_vstop.insert(m_vstop.begin()+index, stop);
447 
448  // Increment the line numbers for all parameters after the inserted one
449  for (int i = index+1; i < size(); ++i) {
450  m_line[i]++;
451  }
452 
453  // Return parameter reference
454  return parameter;
455 }
456 
457 
458 /***********************************************************************//**
459  * @brief Insert parameter into container
460  *
461  * @param[in] name Parameter name.
462  * @param[in] par Parameter.
463  * @return Reference to deep copy of inserted parameter.
464  *
465  * @exception GException::invalid_argument
466  * Parameter with specified name not found in container.
467  *
468  * Inserts a parameter into the container before the parameter with the
469  * specified @p name.
470  ***************************************************************************/
471 GApplicationPar& GApplicationPars::insert(const std::string& name,
472  const GApplicationPar& par)
473 {
474  // Get parameter index
475  int index = get_index(name);
476 
477  // Throw exception if parameter name was not found
478  if (index == -1) {
479  std::string msg = "Parameter \""+name+"\" has not been found in "
480  "parameter file. Please specify a valid parameter "
481  "name.";
483  }
484 
485  // Insert by index and return parameter reference
486  return (insert(index, par));
487 }
488 
489 
490 /***********************************************************************//**
491  * @brief Remove parameter from container
492  *
493  * @param[in] index Parameter index [0,...,size()-1].
494  *
495  * @exception GException::out_of_range
496  * Parameter index is out of range.
497  *
498  * Remove parameter with specified @p index from container.
499  ***************************************************************************/
500 void GApplicationPars::remove(const int& index)
501 {
502  // Compile option: raise exception if index is out of range
503  #if defined(G_RANGE_CHECK)
504  if (index < 0 || index >= size()) {
505  throw GException::out_of_range(G_REMOVE1, "Parameter index", index, size());
506  }
507  #endif
508 
509  // Erase parameter from container
510  m_pars.erase(m_pars.begin() + index);
511 
512  // Remove parameter file line and parameter attributes
513  m_parfile.erase(m_parfile.begin() + m_line[index]);
514  m_line.erase(m_line.begin() + index);
515  m_vstart.erase(m_vstart.begin() + index);
516  m_vstop.erase(m_vstop.begin() + index);
517 
518  // Decrement the line numbers for all parameters after the removed one
519  for (int i = index; i < size(); ++i) {
520  m_line[i]--;
521  }
522 
523  // Return
524  return;
525 }
526 
527 
528 /***********************************************************************//**
529  * @brief Remove parameter from container
530  *
531  * @param[in] name Parameter name.
532  *
533  * @exception GException::invalid_argument
534  * Parameter with specified name not found in container.
535  *
536  * Remove parameter with specified @p name from container.
537  ***************************************************************************/
538 void GApplicationPars::remove(const std::string& name)
539 {
540  // Get parameter index
541  int index = get_index(name);
542 
543  // Throw exception if parameter name was not found
544  if (index == -1) {
545  std::string msg = "Parameter \""+name+"\" has not been found in "
546  "parameter file. Please specify a valid parameter "
547  "name.";
549  }
550 
551  // Remove by index
552  remove(index);
553 
554  // Return
555  return;
556 }
557 
558 
559 /***********************************************************************//**
560  * @brief Append parameter container
561  *
562  * @param[in] pars Parameter container.
563  *
564  * @exception GException::invalid_value
565  * Parameter with the same name exists already.
566  *
567  * Append parameter container to the container.
568  ***************************************************************************/
570 {
571  // Do nothing if parameter container is empty
572  if (!pars.is_empty()) {
573 
574  // Get size. Note that we extract the size first to avoid an
575  // endless loop that arises when a container is appended to
576  // itself.
577  int num = pars.size();
578 
579  // Reserve enough space
580  reserve(size() + num);
581 
582  // Loop over all parameters and append copies
583  for (int i = 0; i < num; ++i) {
584 
585  // Check if parameter name does not yet exist
586  int inx = get_index(pars[i].name());
587  if (inx != -1) {
588  std::string msg =
589  "Attempt to append parameter with name \""+pars[i].name()+
590  "\" to parameter container, but a parameter with the same "
591  "name exists already at index "+gammalib::str(inx)+" in "
592  "the container. Every parameter in the parameter container "
593  "needs to have a unique name.";
595  }
596 
597  // Append parameter to container
598  append(pars[i]);
599 
600  } // endfor: looped over all parameters
601 
602  } // endif: parameter container was not empty
603 
604  // Return
605  return;
606 }
607 
608 
609 /***********************************************************************//**
610  * @brief Check parameter exists
611  *
612  * @param[in] name Parameter name.
613  * @return True if parameter with specified name exists, false otherwise.
614  *
615  * Determines whether a parameter with the specified name exists already in
616  * the parameter container.
617  ***************************************************************************/
618 bool GApplicationPars::contains(const std::string& name) const
619 {
620  // Get parameter index
621  int inx = get_index(name);
622 
623  // Return test result
624  return (inx != -1);
625 }
626 
627 
628 /***********************************************************************//**
629  * @brief Load parameters
630  *
631  * @param[in] filename Parameter filename.
632  *
633  * @exception GException::invalid_argument
634  * Parameter file not found.
635  *
636  * Loads all parameters from parameter file.
637  *
638  * If the syspfiles path is set then load the parameter file from that
639  * location and update the parameters using a paramater file that is found
640  * in the users "pfiles" directory.
641  *
642  * Otherwise, search the parameter file in the usual location (see the
643  * GApplicationPars::inpath method for more information).
644  ***************************************************************************/
645 void GApplicationPars::load(const GFilename& filename)
646 {
647  // Reset parameters
648  m_parfile.clear();
649 
650  // If a syspfiles path was set then get parfile from this path and
651  // update the parameters using a copy found in the users "pfiles"
652  // directory
653  std::string path = syspfiles_path(filename.url());
654  if (!path.empty()) {
655 
656  // Read parfile
657  read(path);
658 
659  // Parse parfile
660  parse();
661 
662  // Synchronize parfile using a copy found in the users "pfiles"
663  // directory
664  path = pfiles_path(filename.url());
665  if (!path.empty()) {
666  synchronise(path);
667  }
668 
669  }
670 
671  // ... otherwise get path to parameter file for input
672  else {
673 
674  // Get parfile file path
675  path = inpath(filename.url());
676 
677  // If file path is empty then throw an exception
678  if (path.empty()) {
679  std::string msg = "Parameter file \""+filename.url()+"\" not "
680  "found. Please specify an existing parameter "
681  "file.";
683  }
684 
685  // Read parfile
686  read(path);
687 
688  // Parse parfile
689  parse();
690 
691  }
692 
693  // Return
694  return;
695 }
696 
697 
698 /***********************************************************************//**
699  * @brief Load parameters
700  *
701  * @param[in] filename Parameter filename.
702  * @param[in] args Command line arguments.
703  *
704  * @exception GException::invalid_argument
705  * Invalid command line argument encountered.
706  *
707  * Loads all parameters from parameter file. Parameters are overwritten by
708  * the values specified in the command line arguments.
709  ***************************************************************************/
710 void GApplicationPars::load(const GFilename& filename,
711  const std::vector<std::string>& args)
712 {
713  // Load parameters
714  load(filename);
715 
716  // Overwrite parameter values that are specified in the command line
717  for (int i = 1; i < args.size(); ++i) {
718 
719  // Extract parameter name and value (empty values are permitted)
720  size_t pos = args[i].find("=");
721  if (pos == std::string::npos) {
722  std::string msg = "No \"=\" symbol found for command line "
723  "parameter \""+args[i]+"\". Please specify a "
724  "valid command line parameter of the form "
725  "\"name=value\".";
727  }
728  std::string name = args[i].substr(0, pos);
729  std::string value = args[i].substr(pos+1);
730  if (name.length() < 1) {
731  std::string msg = "No parameter name found for before the \"=\" "
732  "symbol for command line parameter \""+args[i]+
733  "\". Please specify a valid command line "
734  "parameter of the form \"name=value\".";
736  }
737 
738  // Check if parameter exists
739  if (!contains(name)) {
740  std::string msg = "No parameter with name \""+name+"\" found. "
741  "Please specify an existing command line "
742  "parameter.";
744  }
745 
746  // Assign value
747  try {
748  (*this)[name].value(value);
749  }
750  catch (GException::invalid_value &e) {
751  std::string msg = "Assignment of command line parameter \""+
752  args[i]+"\" failed.";
754  }
755 
756  // Set mode to hidden to prevent querying the parameter
757  if ((*this)[name].mode() == "q") {
758  (*this)[name].mode("h");
759  }
760  else if ((*this)[name].mode() == "ql") {
761  (*this)[name].mode("hl");
762  }
763  else if ((*this)[name].mode() == "lq") {
764  (*this)[name].mode("lh");
765  }
766 
767  } // endfor: looped over all parameters
768 
769  // Return
770  return;
771 }
772 
773 
774 /***********************************************************************//**
775  * @brief Save parameters
776  *
777  * @param[in] filename Parameter filename.
778  *
779  * @exception GException::file_error
780  * No valid directory to write the parameter file has been found.
781  ***************************************************************************/
782 void GApplicationPars::save(const GFilename& filename)
783 {
784  // Get path to parameter file for output
785  std::string path = outpath(filename.url());
786  if (path.size() == 0) {
787  std::string msg = "Parameter file \""+filename+"\" not found. Please "
788  "make sure that the PFILES environment variable is "
789  "set correctly.";
790  throw GException::file_error(G_LOAD2, msg);
791  }
792 
793  // Update parameter file
794  update();
795 
796  // Write parfile
797  write(path);
798 
799  // Return
800  return;
801 }
802 
803 
804 /***********************************************************************//**
805  * @brief Set class from pickled string vector
806  *
807  * @param[in] string String vector containing class information.
808  ***************************************************************************/
809 void GApplicationPars::pickle(const std::vector<std::string>& string)
810 {
811  // Clear object
812  clear();
813 
814  // Extract vector sizes
815  int n_parfile = gammalib::toint(string[0]);
816  int n_pars = gammalib::toint(string[1]);
817  int n_line = gammalib::toint(string[2]);
818  int n_vstart = gammalib::toint(string[3]);
819  int n_vstop = gammalib::toint(string[4]);
820 
821  // Initialise string pointer
822  int istring = 5;
823 
824  // Extract parameter file lines
825  for (int i = 0; i < n_parfile; ++i, ++istring) {
826  m_parfile.push_back(string[istring]);
827  }
828 
829  // Extract application parameters
830  for (int i = 0; i < n_pars; ++i) {
831  int n_par = gammalib::toint(string[istring]);
832  int i_start = istring + 1;
833  int i_end = i_start + n_par;
834  GApplicationPar par;
835  par.pickle(std::vector<std::string>(string.begin()+i_start,
836  string.begin()+i_end));
837  m_pars.push_back(par);
838  istring = i_end;
839  }
840 
841  // Extract line numbers
842  for (int i = 0; i < n_line; ++i, ++istring) {
843  m_line.push_back(gammalib::toint(string[istring]));
844  }
845 
846  // Extract columns of start values
847  for (int i = 0; i < n_vstart; ++i, ++istring) {
848  m_vstart.push_back((size_t)gammalib::toint(string[istring]));
849  }
850 
851  // Extract columns of stop values
852  for (int i = 0; i < n_vstop; ++i, ++istring) {
853  m_vstop.push_back((size_t)gammalib::toint(string[istring]));
854  }
855 
856  // Extract effective mode and location of syspfiles
857  m_mode = string[istring++];
858  m_syspfiles = string[istring++];
859 
860  // Return
861  return;
862 }
863 
864 
865 /***********************************************************************//**
866  * @brief Return pickled string vector
867  *
868  * @return String vector containing class information.
869  ***************************************************************************/
870 std::vector<std::string> GApplicationPars::pickle(void) const
871 {
872  // Allocate vector of strings
873  std::vector<std::string> string;
874 
875  // Store vector lengths
876  string.push_back(gammalib::str(m_parfile.size()));
877  string.push_back(gammalib::str(m_pars.size()));
878  string.push_back(gammalib::str(m_line.size()));
879  string.push_back(gammalib::str(m_vstart.size()));
880  string.push_back(gammalib::str(m_vstop.size()));
881 
882  // Store parfile lines
883  for (int i = 0; i < m_parfile.size(); ++i) {
884  string.push_back(m_parfile[i]);
885  }
886 
887  // Store application parameters
888  for (int i = 0; i < m_pars.size(); ++i) {
889  std::vector<std::string> par = m_pars[i].pickle();
890  string.push_back(gammalib::str(par.size()));
891  for (int k = 0; k < par.size(); ++k) {
892  string.push_back(par[k]);
893  }
894  }
895 
896  // Store line numbers
897  for (int i = 0; i < m_line.size(); ++i) {
898  string.push_back(gammalib::str(m_line[i]));
899  }
900 
901  // Store columns of start values
902  for (int i = 0; i < m_vstart.size(); ++i) {
903  string.push_back(gammalib::str(m_vstart[i]));
904  }
905 
906  // Store columns of stop values
907  for (int i = 0; i < m_vstop.size(); ++i) {
908  string.push_back(gammalib::str(m_vstop[i]));
909  }
910 
911  // Store effective mode and location of syspfiles
912  string.push_back(m_mode);
913  string.push_back(m_syspfiles);
914 
915  // Return string vector
916  return string;
917 }
918 
919 
920 /***********************************************************************//**
921  * @brief Print parameters
922  *
923  * @param[in] chatter Chattiness.
924  * @return String containing parameter information.
925  ***************************************************************************/
926 std::string GApplicationPars::print(const GChatter& chatter) const
927 {
928  // Initialise result string
929  std::string result;
930 
931  // Continue only if chatter is not silent
932  if (chatter != SILENT) {
933 
934  // Append header
935  result.append("=== GApplicationPars ===");
936 
937  // Append parameters
938  for (int i = 0; i < size(); ++i) {
939  result.append("\n"+m_pars[i].print(chatter));
940  }
941 
942  } // endif: chatter was not silent
943 
944  // Return result
945  return result;
946 }
947 
948 
949 /*==========================================================================
950  = =
951  = Private methods =
952  = =
953  ==========================================================================*/
954 
955 /***********************************************************************//**
956  * @brief Initialise class members
957  ***************************************************************************/
959 {
960  // Initialise members
961  m_parfile.clear();
962  m_pars.clear();
963  m_line.clear();
964  m_vstart.clear();
965  m_vstop.clear();
966  m_mode = "h";
967  m_syspfiles.clear();
968 
969  // Return
970  return;
971 }
972 
973 
974 /***********************************************************************//**
975  * @brief Copy class members
976  *
977  * @param[in] pars Object from which members which should be copied.
978  ***************************************************************************/
980 {
981  // Copy attributes
982  m_parfile = pars.m_parfile;
983  m_pars = pars.m_pars;
984  m_line = pars.m_line;
985  m_vstart = pars.m_vstart;
986  m_vstop = pars.m_vstop;
987  m_mode = pars.m_mode;
988  m_syspfiles = pars.m_syspfiles;
989 
990  // Return
991  return;
992 }
993 
994 
995 /***********************************************************************//**
996  * @brief Delete class members
997  ***************************************************************************/
999 {
1000  // Return
1001  return;
1002 }
1003 
1004 
1005 /***********************************************************************//**
1006  * @brief Determine filepath for parameter file input
1007  *
1008  * @param[in] filename Parameter filename to search for.
1009  *
1010  * Locates parameter file for input.
1011  * The parameter file is first searched in the directories that are listed
1012  * in the PFILES environment variable. Directories may be separated by : or
1013  * by ; in PFILES.
1014  *
1015  * If the PFILES environment variable is not set the parameter file is
1016  * searched in the users pfiles directory.
1017  *
1018  * If still no parameter file is found, the parameter file is searched (in
1019  * the given order) in ${GAMMALIB}/syspfiles and in ${prefix}/syspfiles,
1020  * where ${prefix} is the path to the GammaLib installation.
1021  ***************************************************************************/
1022 std::string GApplicationPars::inpath(const std::string& filename) const
1023 {
1024  // Allocate result path
1025  std::string path;
1026 
1027  // Search for parameter file in PFILES directories if the PFILES
1028  // environment variable has been set
1029  char* ptr = std::getenv("PFILES");
1030  if (ptr != NULL) {
1031 
1032  // Extract directories from PFILES environment variable
1033  std::string pfiles = ptr;
1034  std::vector<std::string> dirs = gammalib::split(pfiles, ":;");
1035 
1036  // Search for first occurence of parameter file
1037  for (int i = 0; i < dirs.size(); ++i) {
1038 
1039  // Build filename
1040  std::string fname = dirs[i] + "/" + filename;
1041 
1042  // If file is accessible for reading then exit loop
1043  if (access(fname.c_str(), R_OK) == 0) {
1044  path = fname;
1045  break;
1046  }
1047 
1048  } // endfor: searched all directories given in PFILES
1049 
1050  } // endif: PFILES environment variable has been set
1051 
1052  // ... otherwise, if no PFILES environment variable has been set
1053  // then search in users pfiles directory
1054  else {
1055  uid_t uid = geteuid();
1056  struct passwd* pw = getpwuid(uid);
1057  if (pw != NULL) {
1058  std::string fname = std::string(pw->pw_dir) + "/pfiles/" + filename;
1059  if (access(fname.c_str(), R_OK) == 0) {
1060  path = fname;
1061  }
1062  }
1063  } // endif: searched in users pfiles directory
1064 
1065  // If we have no valid path so far then search file within GAMMALIB
1066  // repository (${GAMMALIB}/syspfiles)
1067  if (path.size() == 0) {
1068  ptr = std::getenv("GAMMALIB");
1069  if (ptr != NULL) {
1070  std::string fname = std::string(ptr) + "/syspfiles/" + filename;
1071  if (access(fname.c_str(), R_OK) == 0) {
1072  path = fname;
1073  }
1074  }
1075  }
1076 
1077  // If we have no valid path so far then search file within GammaLib
1078  // package (${prefix}/syspfiles)
1079  #ifdef PACKAGE_PREFIX
1080  if (path.size() == 0) {
1081  std::string fname = std::string(PACKAGE_PREFIX) + "/syspfiles/" +
1082  filename;
1083  if (access(fname.c_str(), R_OK) == 0) {
1084  path = fname;
1085  }
1086  }
1087  #endif
1088 
1089  // Return path
1090  return path;
1091 }
1092 
1093 
1094 /***********************************************************************//**
1095  * @brief Return path to parfile in $PFILES or $HOME/pfiles folder
1096  *
1097  * @param[in] filename Parameter filename to search for.
1098  * @return Full parameter filename, including absolute access path.
1099  *
1100  * Locates parameter file in the directories that are listed in the PFILES
1101  * environment variable. Directories may be separated by : or by ; in the
1102  * PFILES environment variable.
1103  *
1104  * If the PFILES environment variable is not set the parameter file is
1105  * searched in the users pfiles directory.
1106  *
1107  * If parameter file was not found, or the parameter file is not
1108  * read-accessible, an empty string is returned.
1109  ***************************************************************************/
1110 std::string GApplicationPars::pfiles_path(const std::string& filename) const
1111 {
1112  // Allocate result path
1113  std::string path;
1114 
1115  // Search for parameter file in PFILES directories if the PFILES
1116  // environment variable has been set
1117  char* ptr = std::getenv("PFILES");
1118  if (ptr != NULL) {
1119 
1120  // Extract directories from PFILES environment variable
1121  std::string pfiles = ptr;
1122  std::vector<std::string> dirs = gammalib::split(pfiles, ":;");
1123 
1124  // Search for first occurence of parameter file
1125  for (int i = 0; i < dirs.size(); ++i) {
1126 
1127  // Build filename
1128  std::string fname = dirs[i] + "/" + filename;
1129 
1130  // If file is accessible for reading then exit loop
1131  if (access(fname.c_str(), R_OK) == 0) {
1132  path = fname;
1133  break;
1134  }
1135 
1136  } // endfor: searched all directories given in PFILES
1137 
1138  } // endif: PFILES environment variable has been set
1139 
1140  // ... otherwise, if no PFILES environment variable has been set
1141  // then search in users pfiles directory
1142  else {
1143  uid_t uid = geteuid();
1144  struct passwd* pw = getpwuid(uid);
1145  if (pw != NULL) {
1146  std::string fname = std::string(pw->pw_dir) + "/pfiles/" + filename;
1147  if (access(fname.c_str(), R_OK) == 0) {
1148  path = fname;
1149  }
1150  }
1151  } // endif: searched in users pfiles directory
1152 
1153  // Return path
1154  return path;
1155 }
1156 
1157 
1158 /***********************************************************************//**
1159  * @brief Return path to parfile in m_syspfiles folder
1160  *
1161  * @param[in] filename Parameter filename to search for.
1162  * @return Full parameter filename, including absolute access path.
1163  *
1164  * Locates parameter file in the directory that is specified by the
1165  * m_syspfiles string. If the string is empty, the specified file is not
1166  * found or read accessible, an empty string is returned.
1167  ***************************************************************************/
1168 std::string GApplicationPars::syspfiles_path(const std::string& filename) const
1169 {
1170  // Allocate result path
1171  std::string path;
1172 
1173  // Continue only if m_syspfiles is not empty
1174  if (!m_syspfiles.empty()) {
1175  std::string fname = m_syspfiles + "/" + filename;
1176  if (access(fname.c_str(), R_OK) == 0) {
1177  path = fname;
1178  }
1179  }
1180 
1181  // Return path
1182  return path;
1183 }
1184 
1185 
1186 /***********************************************************************//**
1187  * @brief Determine filepath for parameter file output
1188  *
1189  * @param[in] filename Parameter filename.
1190  *
1191  * @exception GException::runtime_error
1192  * Unable to determine users home directory.
1193  * Unable to create pfiles directory.
1194  * Unable to make pfiles directory accessible to user.
1195  *
1196  * Searchs for first writable directory listed in PFILES environment
1197  * variable. If PFILES is not set then use pfiles directory in users
1198  * home directory. If pfiles directory does not exist then create it.
1199  * If directory exists but is not writable then make it writable.
1200  ***************************************************************************/
1201 std::string GApplicationPars::outpath(const std::string& filename) const
1202 {
1203  // Allocate result path
1204  std::string path;
1205 
1206  // Search for writeable PFILES directories
1207  char* ptr = std::getenv("PFILES");
1208  if (ptr != NULL) {
1209 
1210  // Extract directories from PFILES environment variable
1211  std::string pfiles = ptr;
1212  std::vector<std::string> dirs = gammalib::split(pfiles, ":;");
1213 
1214  // Search for first writeable
1215  for (int i = 0; i < dirs.size(); ++i) {
1216 
1217  // If directory is accessible for writing then exit loop
1218  if (access(dirs[i].c_str(), W_OK) == 0) {
1219  path = dirs[i] + "/" + filename;
1220  break;
1221  }
1222 
1223  }
1224  } // endif: PFILES environment variable exists
1225 
1226  // If no valid directory is found in PFILES environment variable then
1227  // use pfiles directory in users home directory.
1228  if (path.size() == 0) {
1229 
1230  // Get users home directory
1231  uid_t uid = geteuid();
1232  gid_t gid = getegid();
1233  struct passwd* pw = getpwuid(uid);
1234  if (pw == NULL) {
1235  std::string msg = "Unable to determine users home directory.";
1237  }
1238 
1239  // Set path
1240  path = std::string(pw->pw_dir) + "/pfiles";
1241 
1242  // If directory does not exist then create it
1243  if (access(path.c_str(), F_OK) != 0) {
1244  if (mkdir(path.c_str(),
1245  S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
1246  std::string msg = "Unable to create \""+path+"\".";
1248  }
1249  }
1250 
1251  // If directory exists but is not writable then make it writable
1252  else if (access(path.c_str(), W_OK) != 0) {
1253  if (chown(path.c_str(), uid, gid) != 0 ||
1254  chmod(path.c_str(),
1255  S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
1256  std::string msg = "Could not make \""+path+"\" write "
1257  "accessible for writing of the applications "
1258  "parameter file.";
1260  }
1261  }
1262 
1263  // Append filename
1264  path = path + "/" + filename;
1265 
1266  } // endif: no valid directory found in PFILES
1267 
1268  // Return path
1269  return path;
1270 }
1271 
1272 
1273 /***********************************************************************//**
1274  * @brief Read parameter file
1275  *
1276  * @param[in] filename Parameter filename (absolut path).
1277  *
1278  * @exception GException::file_error
1279  * Unable to open parameter file (read access requested).
1280  *
1281  * Read all lines of the parameter file. Each line is terminated by a newline
1282  * character. The file will be locked to avoid simultaneous access by another
1283  * process.
1284  ***************************************************************************/
1285 void GApplicationPars::read(const std::string& filename)
1286 {
1287  // Put in OpenMP critical zone. Note that it is important that the zone
1288  // has an identical name to the corresponding zone in the write()
1289  // method so that multiple threads cannot at the same time read and write
1290  // the parameter file (see #3287).
1291  #pragma omp critical(GApplicationsPars_io)
1292  {
1293  // Allocate line buffer
1294  const int n = 1000;
1295  char line[n];
1296 
1297  // Trying to get file lock
1298  #if defined(G_LOCK_PARFILE)
1299  struct flock lock;
1300  lock.l_type = F_RDLCK; // Want a read lock
1301  lock.l_whence = SEEK_SET; // Want beginning of file
1302  lock.l_start = 0; // No offset, lock entire file ...
1303  lock.l_len = 0; // ... to the end
1304  lock.l_pid = getpid(); // Current process ID
1305  int fd;
1306  if ((fd = open(filename.c_str(), O_RDONLY)) == -1) {
1307  std::string msg = "Could not open parameter file \""+filename+
1308  "\" for locking.";
1309  throw GException::file_error(G_READ, msg);
1310  }
1311  #if defined(G_CHECK_LOCK_PARFILE)
1312  if (fcntl(fd, F_SETLKW, &lock) == -1) { // F_SETLKW: wait until unlocked
1313  std::string msg = "Could not get a lock on the parameter file \""+
1314  filename+"\".";
1315  throw GException::file_error(G_READ, msg);
1316  }
1317  #else
1318  fcntl(fd, F_SETLKW, &lock);
1319  #endif
1320  #endif
1321 
1322  // Open parameter file
1323  FILE* fptr = fopen(filename.c_str(), "r");
1324  if (fptr == NULL) {
1325  std::string msg = "Could not open the parameter file \""+
1326  filename+"\" for reading.";
1327  throw GException::file_error(G_READ, msg);
1328  }
1329 
1330  // Read lines
1331  while (fgets(line, n, fptr) != NULL) {
1332  m_parfile.push_back(std::string(line));
1333  }
1334 
1335  // Close file
1336  fclose(fptr);
1337 
1338  // Unlock file
1339  #if defined(G_LOCK_PARFILE)
1340  if (fd != -1) {
1341  lock.l_type = F_UNLCK;
1342  #if defined(G_CHECK_LOCK_PARFILE)
1343  if (fcntl(fd, F_SETLK, &lock) == -1) {
1344  std::string msg = "Could not unlock the parameter file \""+
1345  filename+"\".";
1346  throw GException::file_error(G_READ, msg);
1347  }
1348  #else
1349  fcntl(fd, F_SETLK, &lock);
1350  #endif
1351  close(fd);
1352  }
1353  #endif
1354  }
1355 
1356  // Return
1357  return;
1358 }
1359 
1360 
1361 /***********************************************************************//**
1362  * @brief Write parameter file
1363  *
1364  * @param[in] filename Parameter filename (absolut path).
1365  *
1366  * @exception GException::file_error
1367  * Unable to open parameter file (write access requested).
1368  *
1369  * Writes all lines of the parameter file. The file will be locked to avoid
1370  * simultaneous access by another process.
1371  ***************************************************************************/
1372 void GApplicationPars::write(const std::string& filename) const
1373 {
1374  // Put in OpenMP critical zone Note that it is important that the zone
1375  // has an identical name to the corresponding zone in the read()
1376  // method so that multiple threads cannot at the same time read and write
1377  // the parameter file (see #3287).
1378  #pragma omp critical(GApplicationsPars_io)
1379  {
1380  // Trying to get file lock. We have to do this after opening the file
1381  // using the fopen function, as the file may not exist, hence it needs
1382  // to be created first.
1383  #if defined(G_LOCK_PARFILE)
1384  struct flock lock;
1385  lock.l_type = F_WRLCK; // Want a write lock
1386  lock.l_whence = SEEK_SET; // Want beginning of file
1387  lock.l_start = 0; // No offset, lock entire file ...
1388  lock.l_len = 0; // ... to the end
1389  lock.l_pid = getpid(); // Current process ID
1390  int fd;
1391  if ((fd = open(filename.c_str(), O_WRONLY)) != -1) {
1392  #if defined(G_CHECK_LOCK_PARFILE)
1393  if (fcntl(fd, F_SETLKW, &lock) == -1) { // F_SETLKW: wait until unlocked
1394  std::string msg = "Could not get a lock on the parameter file \""+
1395  filename+"\".";
1396  throw GException::file_error(G_WRITE, msg);
1397  }
1398  #else
1399  fcntl(fd, F_SETLKW, &lock);
1400  #endif
1401  }
1402  #endif
1403 
1404  // Open parameter file.
1405  FILE* fptr = fopen(filename.c_str(), "w");
1406  if (fptr == NULL) {
1407  std::string msg = "Could not open the parameter file \""+
1408  filename+"\" for writing.";
1409  throw GException::file_error(G_WRITE, msg);
1410  }
1411 
1412  // If file is not locked then lock it now.
1413  #if defined(G_LOCK_PARFILE)
1414  if (fd == -1) {
1415  if ((fd = open(filename.c_str(), O_WRONLY)) != -1) {
1416  #if defined(G_CHECK_LOCK_PARFILE)
1417  if (fcntl(fd, F_SETLKW, &lock) == -1) { // F_SETLKW: wait until unlocked
1418  fclose(fptr);
1419  std::string msg = "Could not get a lock on the parameter "
1420  "file \""+filename+"\".";
1421  throw GException::file_error(G_WRITE, msg);
1422  }
1423  #else
1424  fcntl(fd, F_SETLKW, &lock);
1425  #endif
1426  }
1427  }
1428  #endif
1429 
1430  // Write lines
1431  for (int i = 0; i < m_parfile.size(); ++i) {
1432  fprintf(fptr, "%s", m_parfile[i].c_str());
1433  }
1434 
1435  // Close file
1436  fclose(fptr);
1437 
1438  // Unlock file
1439  #if defined(G_LOCK_PARFILE)
1440  if (fd != -1) {
1441  lock.l_type = F_UNLCK;
1442  #if defined(G_CHECK_LOCK_PARFILE)
1443  if (fcntl(fd, F_SETLK, &lock) == -1) {
1444  std::string msg = "Could not unlock the parameter file \""+
1445  filename+"\".";
1446  throw GException::file_error(G_WRITE, msg);
1447  }
1448  #else
1449  fcntl(fd, F_SETLK, &lock);
1450  #endif
1451  close(fd);
1452  }
1453  #endif
1454  }
1455 
1456  // Return
1457  return;
1458 }
1459 
1460 
1461 /***********************************************************************//**
1462  * @brief Parse parameter file
1463  *
1464  * @exception GException::invalid_value
1465  * Syntax error encountered in parameter file.
1466  *
1467  * The parameter type has to be one b,i,r,s,f,fr,fw,fe,fn. The fr,fw,fe,fn
1468  * types test for read access, write access, file existence, and file
1469  * absence, respectively.
1470  * The parameter mode has to be one of a,h,l,q,hl,ql,lh,lq. For mode 'a' the
1471  * effective mode equals to the value given by the mode parameter, if it
1472  * exists. Without the presence of the mode parameter the effective mode
1473  * will be 'h'.
1474  ***************************************************************************/
1476 {
1477  // Preset effective mode to 'hidden'
1478  m_mode = "h";
1479 
1480  // Parse all lines
1481  for (int i = 0; i < m_parfile.size(); ++i) {
1482 
1483  // Get line without any leading and trailing whitespace
1484  std::string line = gammalib::strip_whitespace(m_parfile[i]);
1485 
1486  // If line contains a single linefeed then skip the line
1487  if (line.length() == 1 && line[0] == '\n')
1488  continue;
1489 
1490  // If line is empty or if line starts with # then skip the line
1491  if (line.length() == 0 || line[0] == '#') {
1492  continue;
1493  }
1494 
1495  // Get the 7 text fields of valid a parameter line
1496  std::string fields[7];
1497  int quotes = 0;
1498  size_t start = 0;
1499  size_t end = line.length() - 1;
1500  int index = 0;
1501  size_t vstart = 0;
1502  size_t vstop = 0;
1503  for (size_t pos = 0; pos < line.length(); ++pos) {
1504 
1505  // Toggle quotes
1506  if (line[pos] == '"') {
1507  quotes = 1-quotes;
1508  }
1509 
1510  // Search for comma only if we are outside quotes. If comma is
1511  // found or end of line is reached then extract a field and start
1512  // searching again from the position following the comma. Strip
1513  // leading and trailing quotes from the fields.
1514  if (quotes == 0) {
1515  if (line[pos] == ',' || pos == end) {
1516  if (index < 7) {
1517  fields[index] =
1519  pos-start)), "\"");
1520  if (index == 3) {
1521  vstart = start;
1522  vstop = pos;
1523  }
1524  start = pos + 1;
1525  }
1526  index++;
1527  }
1528  }
1529 
1530  } // endfor: looped over line
1531 
1532  // Throw an error if quotes are not balanced
1533  if (quotes != 0) {
1534  std::string msg = "Quotes are not balanced in the following line "
1535  "of the parameter file: "+
1536  gammalib::strip_chars(line,"\n")+". Please "
1537  "correct the parameter file.";
1538  throw GException::invalid_value(G_PARSE, msg);
1539  }
1540 
1541  // Throw an error if line has not 7 fields
1542  if (index != 7) {
1543  std::string msg = "Number of fields ("+gammalib::str(index)+") "
1544  "does not correspond to the expected number of "
1545  "7 fields in the following line of the parameter "
1546  "file: "+gammalib::strip_chars(line,"\n")+". "
1547  "Please correct the parameter file.";
1548  throw GException::invalid_value(G_PARSE, msg);
1549  }
1550 
1551  // Verify if parameter name does not yet exist
1552  if (contains(fields[0])) {
1553  std::string msg = "Redefinition of parameter name \""+fields[0]+
1554  "\" in the following line of the parameter "
1555  "file: "+gammalib::strip_chars(line,"\n")+". "
1556  "Please correct the parameter file.";
1557  throw GException::invalid_value(G_PARSE, msg);
1558  }
1559 
1560  // Add parameter
1561  try {
1562  m_pars.push_back(GApplicationPar(fields[0], fields[1], fields[2],
1563  fields[3], fields[4], fields[5],
1564  fields[6]));
1565  m_line.push_back(i);
1566  m_vstart.push_back(vstart);
1567  m_vstop.push_back(vstop);
1568  }
1569  catch (GException::invalid_value &e) {
1570  std::string msg = "Error \""+std::string(e.what())+"\" encountered "
1571  "in the following line of the parameter file: "+
1572  gammalib::strip_chars(line,"\n")+". "
1573  "Please correct the parameter file.";
1574  throw GException::invalid_value(G_PARSE, msg);
1575  }
1576 
1577  // If parameter name is mode then store the effective mode
1578  if (fields[0] == "mode") {
1579  if (fields[3] != "h" && fields[3] != "q" &&
1580  fields[3] != "hl" && fields[3] != "ql" &&
1581  fields[3] != "lh" && fields[3] != "lq") {
1582  std::string msg = "Mode parameter has invalid value \""+
1583  fields[3]+"\" in the following line of the "
1584  "parameter file: "+
1585  gammalib::strip_chars(line,"\n")+". "
1586  "Please correct the parameter file.";
1587  throw GException::invalid_value(G_PARSE, msg);
1588  }
1589  m_mode = fields[3];
1590  }
1591 
1592  } // endfor: looped over lines
1593 
1594  // Set effective mode for all parameters that have mode 'auto'
1595  for (int i = 0; i < m_pars.size(); ++i) {
1596  if (m_pars[i].mode() == "a") {
1597  m_pars[i].mode(m_mode);
1598  }
1599  }
1600 
1601  // Return
1602  return;
1603 }
1604 
1605 
1606 /***********************************************************************//**
1607  * @brief Update parameter file
1608  *
1609  * Update lines of parameter file according to the parameter values. This
1610  * method handles correctly formatted parameter files by replacing the value
1611  * at its original location within the line (preserving additional
1612  * whitespace).
1613  * Updating is only done of the parameter mode is 'learn'.
1614  ***************************************************************************/
1616 {
1617  // Loop over all parameters
1618  for (int i = 0; i < m_pars.size(); ++i) {
1619 
1620  // Update only if requested and allowed
1621  if (m_pars[i].m_update && m_pars[i].is_learn()) {
1622  m_parfile[m_line[i]] = m_parfile[m_line[i]].substr(0, m_vstart[i]) +
1623  m_pars[i].m_value +
1624  m_parfile[m_line[i]].substr(m_vstop[i]);
1625  m_vstop[i] = m_vstart[i] + m_pars[i].m_value.length();
1626  }
1627 
1628  } // endfor: looped over all parameters
1629 
1630  // Return
1631  return;
1632 }
1633 
1634 
1635 /***********************************************************************//**
1636  * @brief Synchronise parameter file with the parameter values in a another
1637  * parameter file
1638  *
1639  * @param[in] filename File name of other parameter file.
1640  *
1641  * Copies over all values from another parameter file that correspond to
1642  * parameters with the same name and type, and that are signaled as "learn"
1643  * in the other parameter file.
1644  ***************************************************************************/
1645 void GApplicationPars::synchronise(const std::string& filename)
1646 {
1647  // Allocate other application parameters
1648  GApplicationPars pars;
1649 
1650  // Read other application parameters
1651  pars.read(filename);
1652 
1653  // Parse other parameters
1654  pars.parse();
1655 
1656  // Loop over all parameters in parameter file
1657  for (int i = 0; i < m_pars.size(); ++i) {
1658 
1659  // If a parameter with the same name and type exists in the other
1660  // parameter file
1661  int inx = pars.get_index(m_pars[i].name());
1662  if (inx != -1) {
1663 
1664  // If the parameter types match, the mode in the other parameter
1665  // file is "learn", and the parameter values differ, then copy
1666  // over the value and signal value updating
1667  if ((m_pars[i].type() == pars[inx].type()) &&
1668  pars[inx].is_learn() &&
1669  m_pars[i].m_value != pars[inx].m_value) {
1670  m_pars[i].m_value = pars[inx].m_value;
1671  m_pars[i].m_status = pars[inx].m_status;
1672  m_pars[i].m_update = true;
1673  }
1674 
1675  } // endif: parameter with same name existed
1676 
1677  } // endfor: looped over all parameters
1678 
1679  // Return
1680  return;
1681 }
1682 
1683 
1684 /***********************************************************************//**
1685  * @brief Return parameter index by name
1686  *
1687  * @param[in] name Parameter name.
1688  * @return Parameter index (-1 if parameter name has not been found)
1689  *
1690  * Returns parameter index based on the specified @p name. If no parameter
1691  * with the specified @p name is found the method returns -1.
1692  ***************************************************************************/
1693 int GApplicationPars::get_index(const std::string& name) const
1694 {
1695  // Initialise index
1696  int index = -1;
1697 
1698  // Search parameter with specified name
1699  for (int i = 0; i < size(); ++i) {
1700  if (m_pars[i].name() == name) {
1701  index = i;
1702  break;
1703  }
1704  }
1705 
1706  // Return index
1707  return index;
1708 }
1709 
1710 
1711 /***********************************************************************//**
1712  * @brief Return parameter file line for a specific parameter
1713  *
1714  * @param[in] par Parameter.
1715  * @param[out] start Column of value start.
1716  * @param[out] stop Column of value stop.
1717  * @return Parameter file line (termined by \n).
1718  *
1719  * Constructs the parameter file line for a specific parameter and returns
1720  * the line as a string. The line is terminated by a \n character.
1721  ***************************************************************************/
1723  size_t* start,
1724  size_t* stop) const
1725 {
1726  // Declate line
1727  std::string line;
1728 
1729  // Build parameter file line
1730  line.append(par.name()+", ");
1731  line.append(par.type()+ ", ");
1732  line.append(par.mode()+ ",");
1733  *start = line.length();
1734  line.append(par.value()+ ",");
1735  *stop = line.length();
1736  line.append(par.min()+ ",");
1737  line.append(par.max()+ ",");
1738  line.append("\""+par.prompt()+"\"\n");
1739 
1740  // Return line
1741  return line;
1742 }
std::vector< size_t > m_vstart
Column of value start.
const std::string & prompt(void) const
Returns parameter prompt.
Application parameter container class definition.
GApplicationPar & append(const GApplicationPar &par)
Append parameter to container.
Application parameter container class.
void init_members(void)
Initialise class members.
std::string m_mode
Effective mode.
void value(const std::string &value)
Set parameter value.
std::string m_syspfiles
Optional location of syspfiles.
std::string getenv(const std::string &arg)
Return value of environment variable.
Definition: GTools.cpp:465
void type(const std::string &type)
Set parameter type.
std::string syspfiles_path(const std::string &filename) const
Return path to parfile in m_syspfiles folder.
std::string print(const GChatter &chatter=NORMAL) const
Print parameters.
#define G_READ
void mode(const std::string &mode)
Set parameter mode.
GApplicationPars & operator=(const GApplicationPars &pars)
Assignment operator.
std::vector< GApplicationPar > m_pars
Parameters.
void parse(void)
Parse parameter file.
#define G_WRITE
#define G_EXTEND
std::string parline(GApplicationPar &par, size_t *start, size_t *stop) const
Return parameter file line for a specific parameter.
std::string strip_chars(const std::string &arg, const std::string &chars)
Strip leading and trailing character from string.
Definition: GTools.cpp:94
std::vector< std::string > split(const std::string &s, const std::string &sep)
Split string.
Definition: GTools.cpp:983
Gammalib tools definition.
void reserve(const int &num)
Reserves space for parameters in container.
#define G_AT
std::string inpath(const std::string &filename) const
Determine filepath for parameter file input.
std::string strip_whitespace(const std::string &arg)
Strip leading and trailing whitespace from string.
Definition: GTools.cpp:80
#define G_REMOVE1
#define G_LOAD1
void synchronise(const std::string &filename)
Synchronise parameter file with the parameter values in a another parameter file. ...
void free_members(void)
Delete class members.
int size(void) const
Return number of parameters in container.
void remove(const int &index)
Remove parameter from container.
const std::string & name(void) const
Returns parameter name.
GApplicationPars(void)
Void constructor.
Filename class.
Definition: GFilename.hpp:62
void pickle(const std::vector< std::string > &string)
Set class from pickled string vector.
#define G_INSERT1
void update(void)
Update parameter file.
virtual ~GApplicationPars(void)
Destructor.
std::vector< std::string > m_parfile
Parameter file lines.
#define G_OUTPATH
const std::string & max(void) const
Returns parameter maximum.
GChatter
Definition: GTypemaps.hpp:33
void save(const GFilename &filename)
Save parameters.
#define G_REMOVE2
std::string pfiles_path(const std::string &filename) const
Return path to parfile in $PFILES or $HOME/pfiles folder.
void copy_members(const GApplicationPars &pars)
Copy class members.
std::vector< std::string > pickle(void) const
Return pickled string vector.
virtual const char * what() const
Exception message.
Definition: GException.cpp:37
#define G_ACCESS
GApplicationPar & at(const int &index)
Returns reference to parameter.
std::string url(void) const
Return Uniform Resource Locator (URL)
Definition: GFilename.hpp:189
#define G_LOAD2
GApplicationPar & operator[](const int &index)
Returns reference to parameter.
void read(const std::string &filename)
Read parameter file.
std::string outpath(const std::string &filename) const
Determine filepath for parameter file output.
void write(const std::string &filename) const
Write parameter file.
Exception handler interface definition.
Application parameter class.
const std::string & min(void) const
Returns parameter minimum.
int toint(const std::string &arg)
Convert string into integer value.
Definition: GTools.cpp:821
std::vector< size_t > m_vstop
Column of value stop.
void append_standard(void)
Append standard parameters to container.
#define G_PARSE
std::vector< int > m_line
Line number of parameter.
#define G_INSERT2
void extend(const GApplicationPars &pars)
Append parameter container.
bool is_empty(void) const
Signals if there are no parameters in container.
int get_index(const std::string &name) const
Return parameter index by name.
Filename class interface definition.
void load(const GFilename &filename)
Load parameters.
GApplicationPar & insert(const int &index, const GApplicationPar &par)
Insert parameter into container.
GApplicationPars * clone(void) const
Clone parameter container.
#define G_APPEND
bool contains(const std::string &name) const
Check parameter exists.
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition: GTools.cpp:489
void clear(void)
Clear parameter container.