PetaVision  Alpha
PVParams.cpp
1 /*
2  * PVParams.cpp
3  *
4  * Created on: Nov 27, 2008
5  * Author: rasmussn
6  */
7 
8 #include "PVParams.hpp"
9 #include "include/pv_common.h"
10 #include "utils/PVAlloc.hpp"
11 #include <assert.h>
12 #include <climits> // INT_MIN
13 #include <cmath> // nearbyint()
14 #include <iostream>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #ifdef PV_USE_LUA
19 #include <lua.hpp>
20 #endif // PV_USE_LUA
21 
22 #define PARAMETERARRAY_INITIALSIZE 8
23 #define PARAMETERARRAYSTACK_INITIALCOUNT 5
24 #define PARAMETERSTRINGSTACK_INITIALCOUNT 5
25 #define PARAMETERSWEEP_INCREMENTCOUNT 10
26 
27 // define for debug output
28 #define DEBUG_PARSING
29 
30 #ifdef HAS_MAIN
31 extern FILE *yyin;
32 #endif // HAS_MAIN
33 
40 int pv_parseParameters(PV::PVParams *action_handler, const char *paramBuffer, size_t len);
41 
42 #ifdef HAS_MAIN
43 #define INITIALNUMGROUPS 20 // maximum number of groups
44 int main() {
45  PV_Stream pvstream = PV_fopen("parser/params.txt", "r", false);
46  yyin = pvstream->fp;
47  PV::PVParams *handler = new PV::PVParams(INITIAL_NUM_GROUPS);
48 
49  pv_parseParameters(handler);
50 
51  PV_fclose(pvstream);
52  yyin = NULL;
53  delete handler;
54 
55  return 0;
56 }
57 #endif // HAS_MAIN
58 
59 namespace PV {
60 
65 Parameter::Parameter(const char *name, double value) {
66  paramName = strdup(name);
67  paramValue = (float)value;
68  paramDblValue = value;
69  hasBeenReadFlag = false;
70 }
71 
72 Parameter::~Parameter() { free(paramName); }
73 
74 ParameterArray::ParameterArray(int initialSize) {
75  hasBeenReadFlag = false;
76  paramNameSet = false;
77  paramName = strdup("Unnamed Parameter array");
78  bufferSize = initialSize;
79  arraySize = 0;
80  values = NULL;
81  if (bufferSize > 0) {
82  values = (float *)calloc(bufferSize, sizeof(float));
83  valuesDbl = (double *)calloc(bufferSize, sizeof(double));
84  if (values == NULL || valuesDbl == NULL) {
85  Fatal().printf("ParameterArray failed to allocate memory for \"%s\"\n", name());
86  }
87  }
88 }
89 
90 ParameterArray::~ParameterArray() {
91  free(paramName);
92  paramName = NULL;
93  free(values);
94  values = NULL;
95  free(valuesDbl);
96  valuesDbl = NULL;
97 }
98 
99 int ParameterArray::setName(const char *name) {
100  int status = PV_SUCCESS;
101  if (paramNameSet == false) {
102  free(paramName);
103  paramName = strdup(name);
104  paramNameSet = true;
105  }
106  else {
107  ErrorLog().printf(
108  "ParameterArray::setName called with \"%s\" but name is already set to \"%s\"\n",
109  name,
110  paramName);
111  status = PV_FAILURE;
112  }
113  return status;
114 }
115 
116 int ParameterArray::pushValue(double value) {
117  assert(bufferSize >= arraySize);
118  if (bufferSize == arraySize) {
119  bufferSize += PARAMETERARRAY_INITIALSIZE;
120  float *new_values = (float *)calloc(bufferSize, sizeof(float));
121  if (new_values == NULL) {
122  Fatal().printf(
123  "ParameterArray::pushValue failed to increase array \"%s\" to %d values\n",
124  name(),
125  arraySize + 1);
126  }
127  memcpy(new_values, values, sizeof(float) * arraySize);
128  free(values);
129  values = new_values;
130  double *new_values_dbl = (double *)calloc(bufferSize, sizeof(double));
131  if (new_values == NULL) {
132  Fatal().printf(
133  "ParameterArray::pushValue failed to increase array \"%s\" to %d values\n",
134  name(),
135  arraySize + 1);
136  }
137  memcpy(new_values_dbl, valuesDbl, sizeof(double) * arraySize);
138  free(valuesDbl);
139  valuesDbl = new_values_dbl;
140  }
141  assert(arraySize < bufferSize);
142  valuesDbl[arraySize] = value;
143  values[arraySize] = (float)value;
144  arraySize++;
145  return arraySize;
146 }
147 
148 ParameterArray *ParameterArray::copyParameterArray() {
149  ParameterArray *returnPA = new ParameterArray(bufferSize);
150  int status = returnPA->setName(paramName);
151  assert(status == PV_SUCCESS);
152  for (int i = 0; i < arraySize; i++) {
153  returnPA->pushValue(valuesDbl[i]);
154  }
155  return returnPA;
156 }
157 
162 ParameterString::ParameterString(const char *name, const char *value) {
163  paramName = name ? strdup(name) : NULL;
164  paramValue = value ? strdup(value) : NULL;
165  hasBeenReadFlag = false;
166 }
167 
168 ParameterString::~ParameterString() {
169  free(paramName);
170  free(paramValue);
171 }
172 
177  this->maxCount = maxCount;
178  count = 0;
179  parameters = (Parameter **)malloc(maxCount * sizeof(Parameter *));
180 }
181 
182 ParameterStack::~ParameterStack() {
183  for (int i = 0; i < count; i++) {
184  delete parameters[i];
185  }
186  free(parameters);
187 }
188 
193  assert(count < maxCount);
194  parameters[count++] = param;
195  return 0;
196 }
197 
198 Parameter *ParameterStack::pop() {
199  assert(count > 0);
200  return parameters[count--];
201 }
202 
203 ParameterArrayStack::ParameterArrayStack(int initialCount) {
204  allocation = initialCount;
205  count = 0;
206  parameterArrays = NULL;
207  if (initialCount > 0) {
208  parameterArrays = (ParameterArray **)calloc(allocation, sizeof(ParameterArray *));
209  if (parameterArrays == NULL) {
210  Fatal().printf(
211  "ParameterArrayStack unable to allocate %d parameter arrays\n", initialCount);
212  }
213  }
214 }
215 
216 ParameterArrayStack::~ParameterArrayStack() {
217  for (int k = 0; k < count; k++) {
218  delete parameterArrays[k];
219  parameterArrays[k] = NULL;
220  }
221  free(parameterArrays);
222  parameterArrays = NULL;
223 }
224 
225 int ParameterArrayStack::push(ParameterArray *array) {
226  assert(count <= allocation);
227  if (count == allocation) {
228  int newallocation = allocation + RESIZE_ARRAY_INCR;
229  ParameterArray **newParameterArrays =
230  (ParameterArray **)malloc(newallocation * sizeof(ParameterArray *));
231  if (!newParameterArrays)
232  return PV_FAILURE;
233  for (int i = 0; i < count; i++) {
234  newParameterArrays[i] = parameterArrays[i];
235  }
236  allocation = newallocation;
237  free(parameterArrays);
238  parameterArrays = newParameterArrays;
239  }
240  assert(count < allocation);
241  parameterArrays[count] = array;
242  count++;
243  return PV_SUCCESS;
244 }
245 
246 /*
247  * initialCount
248  */
249 ParameterStringStack::ParameterStringStack(int initialCount) {
250  allocation = initialCount;
251  count = 0;
252  parameterStrings = (ParameterString **)calloc(allocation, sizeof(ParameterString *));
253 }
254 
255 ParameterStringStack::~ParameterStringStack() {
256  for (int i = 0; i < count; i++) {
257  delete parameterStrings[i];
258  }
259  free(parameterStrings);
260 }
261 
262 /*
263  * @param
264  */
265 int ParameterStringStack::push(ParameterString *param) {
266  assert(count <= allocation);
267  if (count == allocation) {
268  int newallocation = allocation + RESIZE_ARRAY_INCR;
269  ParameterString **newparameterStrings =
270  (ParameterString **)malloc(newallocation * sizeof(ParameterString *));
271  if (!newparameterStrings)
272  return PV_FAILURE;
273  for (int i = 0; i < count; i++) {
274  newparameterStrings[i] = parameterStrings[i];
275  }
276  allocation = newallocation;
277  free(parameterStrings);
278  parameterStrings = newparameterStrings;
279  }
280  assert(count < allocation);
281  parameterStrings[count++] = param;
282  return PV_SUCCESS;
283 }
284 
285 ParameterString *ParameterStringStack::pop() {
286  if (count > 0) {
287  return parameterStrings[count--];
288  }
289  else
290  return NULL;
291 }
292 
293 const char *ParameterStringStack::lookup(const char *targetname) {
294  const char *result = NULL;
295  for (int i = 0; i < count; i++) {
296  if (!strcmp(parameterStrings[i]->getName(), targetname)) {
297  result = parameterStrings[i]->getValue();
298  }
299  }
300  return result;
301 }
302 
309 ParameterGroup::ParameterGroup(
310  char *name,
311  ParameterStack *stack,
312  ParameterArrayStack *array_stack,
313  ParameterStringStack *string_stack,
314  int rank) {
315  this->groupName = strdup(name);
316  this->groupKeyword = NULL;
317  this->stack = stack;
318  this->arrayStack = array_stack;
319  this->stringStack = string_stack;
320  this->processRank = rank;
321 }
322 
323 ParameterGroup::~ParameterGroup() {
324  free(groupName);
325  groupName = NULL;
326  free(groupKeyword);
327  groupKeyword = NULL;
328  delete stack;
329  stack = NULL;
330  delete arrayStack;
331  arrayStack = NULL;
332  delete stringStack;
333  stringStack = NULL;
334 }
335 
336 int ParameterGroup::setGroupKeyword(const char *keyword) {
337  if (groupKeyword == NULL) {
338  size_t keywordlen = strlen(keyword);
339  groupKeyword = (char *)malloc(keywordlen + 1);
340  if (groupKeyword) {
341  strcpy(groupKeyword, keyword);
342  }
343  }
344  return groupKeyword == NULL ? PV_FAILURE : PV_SUCCESS;
345 }
346 
347 int ParameterGroup::setStringStack(ParameterStringStack *stringStack) {
348  this->stringStack = stringStack;
349  // ParameterGroup::setStringStack takes ownership of the stringStack;
350  // i.e. it will delete it when the ParameterGroup is deleted.
351  // You shouldn't use a stringStack after calling this routine with it.
352  // Instead, query it with ParameterGroup::stringPresent and
353  // ParameterGroup::stringValue methods.
354  return stringStack == NULL ? PV_FAILURE : PV_SUCCESS;
355 }
356 
360 int ParameterGroup::present(const char *name) {
361  int count = stack->size();
362  for (int i = 0; i < count; i++) {
363  Parameter *p = stack->peek(i);
364  if (strcmp(name, p->name()) == 0) {
365  return 1; // string is present
366  }
367  }
368  return 0; // string not present
369 }
370 
374 double ParameterGroup::value(const char *name) {
375  int count = stack->size();
376  for (int i = 0; i < count; i++) {
377  Parameter *p = stack->peek(i);
378  if (strcmp(name, p->name()) == 0) {
379  return p->value();
380  }
381  }
382  Fatal().printf(
383  "PVParams::ParameterGroup::value: ERROR, couldn't find a value for %s"
384  " in group %s\n",
385  name,
386  groupName);
387  return PV_FAILURE; // suppresses warning in compilers that don't recognize Fatal always exits.
388 }
389 
390 bool ParameterGroup::arrayPresent(const char *name) {
391  bool array_found = false;
392  int count = arrayStack->size();
393  for (int i = 0; i < count; i++) {
394  ParameterArray *p = arrayStack->peek(i);
395  if (strcmp(name, p->name()) == 0) {
396  array_found = true; // string is present
397  break;
398  }
399  }
400  if (!array_found) { array_found = (present(name) != 0); }
401  return array_found;
402 }
403 
404 const float *ParameterGroup::arrayValues(const char *name, int *size) {
405  int count = arrayStack->size();
406  *size = 0;
407  const float *v = NULL;
408  ParameterArray *p = NULL;
409  for (int i = 0; i < count; i++) {
410  p = arrayStack->peek(i);
411  if (strcmp(name, p->name()) == 0) {
412  v = p->getValues(size);
413  break;
414  }
415  }
416  if (!v) {
417  Parameter *q = NULL;
418  for (int i = 0; i < stack->size(); i++) {
419  Parameter *q1 = stack->peek(i);
420  assert(q1);
421  if (strcmp(name, q1->name()) == 0) {
422  q = q1;
423  break;
424  }
425  }
426  if (q) {
427  v = q->valuePtr();
428  *size = 1;
429  }
430  }
431  return v;
432 }
433 
434 const double *ParameterGroup::arrayValuesDbl(const char *name, int *size) {
435  int count = arrayStack->size();
436  *size = 0;
437  const double *v = NULL;
438  ParameterArray *p = NULL;
439  for (int i = 0; i < count; i++) {
440  p = arrayStack->peek(i);
441  if (strcmp(name, p->name()) == 0) {
442  v = p->getValuesDbl(size);
443  break;
444  }
445  }
446  if (!v) {
447  Parameter *q = NULL;
448  for (int i = 0; i < stack->size(); i++) {
449  Parameter *q1 = stack->peek(i);
450  assert(q1);
451  if (strcmp(name, q1->name()) == 0) {
452  q = q1;
453  break;
454  }
455  }
456  if (q) {
457  v = q->valueDblPtr();
458  *size = 1;
459  }
460  }
461  return v;
462 }
463 
464 int ParameterGroup::stringPresent(const char *stringName) {
465  // not really necessary, as stringValue returns NULL if the
466  // string is not found, but included on the analogy with
467  // value and present methods for floating-point parameters
468  if (!stringName)
469  return 0;
470  int count = stringStack->size();
471  for (int i = 0; i < count; i++) {
472  ParameterString *pstr = stringStack->peek(i);
473  assert(pstr);
474  if (!strcmp(stringName, pstr->getName())) {
475  return 1; // string is present
476  }
477  }
478  return 0; // string not present
479 }
480 
481 const char *ParameterGroup::stringValue(const char *stringName) {
482  if (!stringName)
483  return NULL;
484  int count = stringStack->size();
485  for (int i = 0; i < count; i++) {
486  ParameterString *pstr = stringStack->peek(i);
487  assert(pstr);
488  if (!strcmp(stringName, pstr->getName())) {
489  return pstr->getValue();
490  }
491  }
492  return NULL;
493 }
494 
495 int ParameterGroup::warnUnread() {
496  int status = PV_SUCCESS;
497  int count;
498  count = stack->size();
499  for (int i = 0; i < count; i++) {
500  Parameter *p = stack->peek(i);
501  if (!p->hasBeenRead()) {
502  if (processRank == 0)
503  WarnLog().printf(
504  "Parameter group \"%s\": parameter \"%s\" has not been read.\n",
505  name(),
506  p->name());
507  status = PV_FAILURE;
508  }
509  }
510  count = arrayStack->size();
511  for (int i = 0; i < count; i++) {
512  ParameterArray *parr = arrayStack->peek(i);
513  if (!parr->hasBeenRead()) {
514  if (processRank == 0)
515  WarnLog().printf(
516  "Parameter group \"%s\": array parameter \"%s\" has not been read.\n",
517  name(),
518  parr->name());
519  }
520  }
521  count = stringStack->size();
522  for (int i = 0; i < count; i++) {
523  ParameterString *pstr = stringStack->peek(i);
524  if (!pstr->hasBeenRead()) {
525  if (processRank == 0)
526  WarnLog().printf(
527  "Parameter group \"%s\": string parameter \"%s\" has not been read.\n",
528  name(),
529  pstr->getName());
530  status = PV_FAILURE;
531  }
532  }
533  return status;
534 }
535 
536 bool ParameterGroup::hasBeenRead(const char *paramName) {
537  int count;
538  count = stack->size();
539  for (int i = 0; i < count; i++) {
540  Parameter *p = stack->peek(i);
541  if (!strcmp(p->name(), paramName)) {
542  return p->hasBeenRead();
543  }
544  }
545  count = arrayStack->size();
546  for (int i = 0; i < count; i++) {
547  ParameterArray *parr = arrayStack->peek(i);
548  if (!strcmp(parr->name(), paramName)) {
549  return parr->hasBeenRead();
550  }
551  }
552  count = stringStack->size();
553  for (int i = 0; i < count; i++) {
554  ParameterString *pstr = stringStack->peek(i);
555  if (!strcmp(pstr->getName(), paramName)) {
556  return pstr->hasBeenRead();
557  }
558  }
559  return false;
560 }
561 
562 int ParameterGroup::clearHasBeenReadFlags() {
563  int status = PV_SUCCESS;
564  int count = stack->size();
565  for (int i = 0; i < count; i++) {
566  Parameter *p = stack->peek(i);
567  p->clearHasBeenRead();
568  }
569  count = arrayStack->size();
570  for (int i = 0; i < count; i++) {
571  ParameterArray *parr = arrayStack->peek(i);
572  parr->clearHasBeenRead();
573  }
574  count = stringStack->size();
575  for (int i = 0; i < count; i++) {
576  ParameterString *pstr = stringStack->peek(i);
577  pstr->clearHasBeenRead();
578  }
579  return status;
580 }
581 
582 int ParameterGroup::pushNumerical(Parameter *param) { return stack->push(param); }
583 
584 int ParameterGroup::pushString(ParameterString *param) { return stringStack->push(param); }
585 
586 int ParameterGroup::setValue(const char *param_name, double value) {
587  int status = PV_SUCCESS;
588  int count = stack->size();
589  for (int i = 0; i < count; i++) {
590  Parameter *p = stack->peek(i);
591  if (strcmp(param_name, p->name()) == 0) {
592  p->setValue(value);
593  return PV_SUCCESS;
594  }
595  }
596  Fatal().printf(
597  "PVParams::ParameterGroup::setValue: ERROR, couldn't find parameter %s"
598  " in group \"%s\"\n",
599  param_name,
600  name());
601 
602  return status;
603 }
604 
605 int ParameterGroup::setStringValue(const char *param_name, const char *svalue) {
606  int status = PV_SUCCESS;
607  int count = stringStack->size();
608  for (int i = 0; i < count; i++) {
609  ParameterString *p = stringStack->peek(i);
610  if (strcmp(param_name, p->getName()) == 0) {
611  p->setValue(svalue);
612  return PV_SUCCESS;
613  }
614  }
615  Fatal().printf(
616  "PVParams::ParameterGroup::setStringValue: ERROR, couldn't find a string value for %s"
617  " in group \"%s\"\n",
618  param_name,
619  name());
620 
621  return status;
622 }
623 
628  ParameterStack *returnStack = new ParameterStack(MAX_PARAMS);
629  for (int i = 0; i < stack->size(); i++) {
630  returnStack->push(stack->peek(i)->copyParameter());
631  }
632  return returnStack;
633 }
634 
639  ParameterArrayStack *returnStack = new ParameterArrayStack(PARAMETERARRAYSTACK_INITIALCOUNT);
640  for (int i = 0; i < arrayStack->size(); i++) {
641  returnStack->push(arrayStack->peek(i)->copyParameterArray());
642  }
643  return returnStack;
644 }
645 
650  ParameterStringStack *returnStack = new ParameterStringStack(PARAMETERSTRINGSTACK_INITIALCOUNT);
651  for (int i = 0; i < stringStack->size(); i++) {
652  returnStack->push(stringStack->peek(i)->copyParameterString());
653  }
654  return returnStack;
655 }
656 
657 ParameterSweep::ParameterSweep() {
658  groupName = NULL;
659  paramName = NULL;
660  numValues = 0;
661  currentBufferSize = 0;
662  type = SWEEP_UNDEF;
663  valuesNumber = NULL;
664  valuesString = NULL;
665 }
666 
667 ParameterSweep::~ParameterSweep() {
668  free(groupName);
669  groupName = NULL;
670  free(paramName);
671  paramName = NULL;
672  free(valuesNumber);
673  valuesNumber = NULL;
674  if (valuesString != NULL) {
675  for (int k = 0; k < numValues; k++) {
676  free(valuesString[k]);
677  }
678  free(valuesString);
679  valuesString = NULL;
680  }
681 }
682 
683 int ParameterSweep::setGroupAndParameter(const char *groupname, const char *parametername) {
684  int status = PV_SUCCESS;
685  if (groupName != NULL || paramName != NULL) {
686  ErrorLog(errorMessage);
687  errorMessage.printf("ParameterSweep::setGroupParameter: ");
688  if (groupName != NULL) {
689  errorMessage.printf(" groupName has already been set to \"%s\".", groupName);
690  }
691  if (paramName != NULL) {
692  errorMessage.printf(" paramName has already been set to \"%s\".", paramName);
693  }
694  errorMessage.printf("\n");
695  status = PV_FAILURE;
696  }
697  else {
698  groupName = strdup(groupname);
699  paramName = strdup(parametername);
700  // Check for duplicates
701  }
702  return status;
703 }
704 
705 int ParameterSweep::pushNumericValue(double val) {
706  int status = PV_SUCCESS;
707  if (numValues == 0) {
708  type = SWEEP_NUMBER;
709  }
710  assert(type == SWEEP_NUMBER);
711  assert(valuesString == NULL);
712 
713  assert(numValues <= currentBufferSize);
714  if (numValues == currentBufferSize) {
715  currentBufferSize += PARAMETERSWEEP_INCREMENTCOUNT;
716  double *newValuesNumber = (double *)calloc(currentBufferSize, sizeof(double));
717  if (newValuesNumber == NULL) {
718  ErrorLog().printf("ParameterSweep:pushNumericValue: unable to allocate memory\n");
719  status = PV_FAILURE;
720  abort();
721  }
722  for (int k = 0; k < numValues; k++) {
723  newValuesNumber[k] = valuesNumber[k];
724  }
725  free(valuesNumber);
726  valuesNumber = newValuesNumber;
727  }
728  valuesNumber[numValues] = val;
729  numValues++;
730  return status;
731 }
732 
733 int ParameterSweep::pushStringValue(const char *sval) {
734  int status = PV_SUCCESS;
735  if (numValues == 0) {
736  type = SWEEP_STRING;
737  }
738  assert(type == SWEEP_STRING);
739  assert(valuesNumber == NULL);
740 
741  assert(numValues <= currentBufferSize);
742  if (numValues == currentBufferSize) {
743  currentBufferSize += PARAMETERSWEEP_INCREMENTCOUNT;
744  char **newValuesString = (char **)calloc(currentBufferSize, sizeof(char *));
745  if (newValuesString == NULL) {
746  ErrorLog().printf("ParameterSweep:pushStringValue: unable to allocate memory\n");
747  status = PV_FAILURE;
748  abort();
749  }
750  for (int k = 0; k < numValues; k++) {
751  newValuesString[k] = valuesString[k];
752  }
753  free(valuesString);
754  valuesString = newValuesString;
755  }
756  valuesString[numValues] = strdup(sval);
757  numValues++;
758  return status;
759 }
760 
761 int ParameterSweep::getNumericValue(int n, double *val) {
762  int status = PV_SUCCESS;
763  assert(valuesNumber != NULL);
764  if (type != SWEEP_NUMBER || n < 0 || n >= numValues) {
765  status = PV_FAILURE;
766  }
767  else {
768  *val = valuesNumber[n];
769  }
770  return status;
771 }
772 
773 const char *ParameterSweep::getStringValue(int n) {
774  char *str = NULL;
775  assert(valuesString != NULL);
776  if (type == SWEEP_STRING && n >= 0 && n < numValues) {
777  str = valuesString[n];
778  }
779  return str;
780 }
781 
787 PVParams::PVParams(const char *filename, size_t initialSize, Communicator *inIcComm) {
788  this->icComm = inIcComm;
789  initialize(initialSize);
790  parseFile(filename);
791 }
792 
793 /*
794  * @initialSize
795  * @icComm
796  */
797 PVParams::PVParams(size_t initialSize, Communicator *inIcComm) {
798  this->icComm = inIcComm;
799  initialize(initialSize);
800 }
801 
802 /*
803  * @buffer
804  * @bufferLength
805  * @initialSize
806  * @icComm
807  */
808 PVParams::PVParams(
809  const char *buffer,
810  long int bufferLength,
811  size_t initialSize,
812  Communicator *inIcComm) {
813  this->icComm = inIcComm;
814  initialize(initialSize);
815  parseBuffer(buffer, bufferLength);
816 }
817 
818 PVParams::~PVParams() {
819  for (int i = 0; i < numGroups; i++) {
820  delete groups[i];
821  }
822  free(groups);
823  delete currentParamArray;
824  currentParamArray = NULL;
825  delete stack;
826  delete arrayStack;
827  delete stringStack;
828  delete this->activeParamSweep;
829  for (int i = 0; i < numParamSweeps; i++) {
830  delete paramSweeps[i];
831  }
832  free(paramSweeps);
833  paramSweeps = NULL;
834 }
835 
836 /*
837  * @initialSize
838  */
839 int PVParams::initialize(size_t initialSize) {
840  this->numGroups = 0;
841  groupArraySize = initialSize;
842  // Get world rank and size
843  MPI_Comm_rank(icComm->globalCommunicator(), &worldRank);
844  MPI_Comm_size(icComm->globalCommunicator(), &worldSize);
845 
846  groups = (ParameterGroup **)malloc(initialSize * sizeof(ParameterGroup *));
847  stack = new ParameterStack(MAX_PARAMS);
848  arrayStack = new ParameterArrayStack(PARAMETERARRAYSTACK_INITIALCOUNT);
849  stringStack = new ParameterStringStack(PARAMETERSTRINGSTACK_INITIALCOUNT);
850 
851  currentParamArray = new ParameterArray(PARAMETERARRAYSTACK_INITIALCOUNT);
852 
853  numParamSweeps = 0;
854  paramSweeps = NULL;
855  newActiveParamSweep();
856 #ifdef DEBUG_PARSING
857  debugParsing = true;
858 #else
859  debugParsing = false;
860 #endif // DEBUG_PARSING
861  disable = false;
862 
863  return (groups && stack && stringStack && activeParamSweep) ? PV_SUCCESS : PV_FAILURE;
864 }
865 
866 int PVParams::newActiveParamSweep() {
867  int status = PV_SUCCESS;
868  activeParamSweep = new ParameterSweep();
869  if (activeParamSweep == NULL) {
870  Fatal().printf("PVParams::newActiveParamSweep: unable to create activeParamSweep");
871  status = PV_FAILURE;
872  }
873  return status;
874 }
875 
876 int PVParams::parseFile(const char *filename) {
877  int rootproc = 0;
878  char *paramBuffer = nullptr;
879  size_t bufferlen;
880  if (worldRank == rootproc) {
881  std::string paramBufferString("");
882  loadParamBuffer(filename, paramBufferString);
883  bufferlen = paramBufferString.size();
884  // Older versions of MPI_Send require void*, not void const*
885  paramBuffer = (char *)pvMalloc(bufferlen + 1);
886  memcpy(paramBuffer, paramBufferString.c_str(), bufferlen);
887  paramBuffer[bufferlen] = '\0';
888 
889 #ifdef PV_USE_MPI
890  int sz = worldSize;
891  for (int i = 0; i < sz; i++) {
892  if (i == rootproc)
893  continue;
894  MPI_Send(paramBuffer, (int)bufferlen, MPI_CHAR, i, 31, icComm->globalCommunicator());
895  }
896 #endif // PV_USE_MPI
897  }
898  else { // rank != rootproc
899 #ifdef PV_USE_MPI
900  MPI_Status mpi_status;
901  int count;
902  MPI_Probe(rootproc, 31, icComm->globalCommunicator(), &mpi_status);
903  // int status =
904  MPI_Get_count(&mpi_status, MPI_CHAR, &count);
905  bufferlen = (size_t)count;
906  paramBuffer = (char *)malloc(bufferlen);
907  if (paramBuffer == NULL) {
908  Fatal().printf(
909  "PVParams::parseFile: Rank %d process unable to allocate memory for params buffer\n",
910  worldRank);
911  }
912  MPI_Recv(
913  paramBuffer,
914  (int)bufferlen,
915  MPI_CHAR,
916  rootproc,
917  31,
918  icComm->globalCommunicator(),
919  MPI_STATUS_IGNORE);
920 #endif // PV_USE_MPI
921  }
922 
923  int status = parseBuffer(paramBuffer, bufferlen);
924  free(paramBuffer);
925  return status;
926 }
927 
928 void PVParams::loadParamBuffer(char const *filename, std::string &paramsFileString) {
929  if (filename == nullptr) {
930  Fatal() << "PVParams::loadParamBuffer: filename is null\n";
931  }
932  struct stat filestatus;
933  if (PV_stat(filename, &filestatus)) {
934  Fatal().printf(
935  "PVParams::parseFile unable to get status of file \"%s\": %s\n",
936  filename,
937  strerror(errno));
938  }
939  if (filestatus.st_mode & S_IFDIR) {
940  Fatal().printf("PVParams::parseFile: specified file \"%s\" is a directory.\n", filename);
941  }
942 
943 #ifdef PV_USE_LUA
944  char const *const luaext = ".lua";
945  size_t const luaextlen = strlen(luaext);
946  size_t const fnlen = strlen(filename);
947  bool const useLua = fnlen >= luaextlen && !strcmp(&filename[fnlen - luaextlen], luaext);
948 #else // PV_USE_LUA
949  bool const useLua = false;
950 #endif // PV_USE_LUA
951 
952  if (useLua) {
953 #ifdef PV_USE_LUA
954  InfoLog() << "Running lua program \"" << filename << "\".\n";
955  lua_State *lua_state = luaL_newstate();
956  luaL_openlibs(lua_state);
957  int result = luaL_dofile(lua_state, filename);
958  if (result != LUA_OK) {
959  char const *errorMessage = lua_tostring(lua_state, -1);
960  lua_pop(lua_state, 1);
961  Fatal() << errorMessage;
962  }
963  lua_getglobal(lua_state, "paramsFileString");
964  size_t llength;
965  char const *lstring = lua_tolstring(lua_state, -1, &llength);
966  if (lstring == nullptr) {
967  Fatal() << "Lua program \"" << filename
968  << "\" does not create a string variable \"paramsFileString\".\n";
969  }
970  paramsFileString.insert(paramsFileString.end(), lstring, &lstring[llength]);
971  lua_pop(lua_state, 1);
972  lua_close(lua_state);
973  InfoLog() << "Retrieved paramsFileString, with length " << llength << ".\n";
974 #endif // PV_USE_LUA
975  }
976  else {
977  off_t sz = filestatus.st_size;
978  std::ifstream paramsStream(filename, std::ios_base::in);
979  if (paramsStream.fail()) {
980  throw;
981  } // TODO: provide a helpful strerror(errno)-like message
982  paramsFileString.resize(sz);
983  paramsStream.read(&paramsFileString[0], sz);
984  }
985 }
986 
987 bool PVParams::hasSweepValue(const char *inParamName) {
988  bool out = false;
989  const char *group_name;
990  for (int k = 0; k < numberOfParameterSweeps(); k++) {
991  ParameterSweep *sweep = paramSweeps[k];
992  group_name = sweep->getGroupName();
993  const char *param_name = sweep->getParamName();
994  ParameterGroup *gp = group(group_name);
995  if (gp == NULL) {
996  Fatal().printf(
997  "PVParams::hasSweepValue error: ParameterSweep %d (zero-indexed) refers to "
998  "non-existent group \"%s\"\n",
999  k,
1000  group_name);
1001  }
1002  if (!strcmp(gp->getGroupKeyword(), "HyPerCol") && !strcmp(param_name, inParamName)) {
1003  out = true;
1004  break;
1005  }
1006  }
1007  return out;
1008 }
1009 
1010 int PVParams::parseBuffer(char const *buffer, long int bufferLength) {
1011  // Assumes that each MPI process has the same contents in buffer.
1012 
1013  // This is where it calls the scanner and parser
1014  parseStatus = pv_parseParameters(this, buffer, bufferLength);
1015  if (parseStatus != 0) {
1016  ErrorLog().printf(
1017  "Rank %d process: pv_parseParameters failed with return value %d\n",
1018  worldRank,
1019  parseStatus);
1020  }
1021  getOutputStream().flush();
1022 
1023  setParameterSweepSize(); // Need to set sweepSize here, because if the outputPath sweep needs to
1024  // be created we need to know the size.
1025 
1026  // If there is at least one ParameterSweep and none of them set outputPath, create a
1027  // parameterSweep that does set outputPath.
1028 
1029  // If both parameterSweep and batchSweep is set, must autoset output path, as there is no way to
1030  // specify both paramSweep and batchSweep
1031  if (numberOfParameterSweeps() > 0) {
1032  if (!hasSweepValue("outputPath")) {
1033  const char *hypercolgroupname = NULL;
1034  const char *outputPathName = NULL;
1035  for (int g = 0; g < numGroups; g++) {
1036  if (groups[g]->getGroupKeyword(), "HyPerCol") {
1037  hypercolgroupname = groups[g]->name();
1038  outputPathName = groups[g]->stringValue("outputPath");
1039  if (outputPathName == NULL) {
1040  Fatal().printf(
1041  "PVParams::outputPath must be specified if parameterSweep does "
1042  "not sweep over outputPath\n");
1043  }
1044  break;
1045  }
1046  }
1047  if (hypercolgroupname == NULL) {
1048  ErrorLog().printf("PVParams::parseBuffer: no HyPerCol group\n");
1049  abort();
1050  }
1051 
1052  char dummy;
1053  int lenserialno = snprintf(&dummy, 0, "%d", parameterSweepSize - 1);
1054  int len = snprintf(
1055  &dummy,
1056  0,
1057  "%s/paramsweep_%0*d/",
1058  outputPathName,
1059  lenserialno,
1060  parameterSweepSize - 1)
1061  + 1;
1062  char *outputPathStr = (char *)calloc(len, sizeof(char));
1063  if (outputPathStr == NULL)
1064  abort();
1065  for (int i = 0; i < parameterSweepSize; i++) {
1066  int chars_needed = snprintf(
1067  outputPathStr, len, "%s/paramsweep_%0*d/", outputPathName, lenserialno, i);
1068  assert(chars_needed < len);
1069  activeParamSweep->pushStringValue(outputPathStr);
1070  }
1071  free(outputPathStr);
1072  outputPathStr = NULL;
1073  addActiveParamSweep(hypercolgroupname, "outputPath");
1074  }
1075 
1076  if (!hasSweepValue("checkpointWriteDir")) {
1077  const char *hypercolgroupname = NULL;
1078  const char *checkpointWriteDir = NULL;
1079  for (int g = 0; g < numGroups; g++) {
1080  if (groups[g]->getGroupKeyword(), "HyPerCol") {
1081  hypercolgroupname = groups[g]->name();
1082  checkpointWriteDir = groups[g]->stringValue("checkpointWriteDir");
1083  // checkpointWriteDir can be NULL if checkpointWrite is set to false
1084  break;
1085  }
1086  }
1087  if (hypercolgroupname == NULL) {
1088  ErrorLog().printf("PVParams::parseBuffer: no HyPerCol group\n");
1089  abort();
1090  }
1091  if (checkpointWriteDir) {
1092  char dummy;
1093  int lenserialno = snprintf(&dummy, 0, "%d", parameterSweepSize - 1);
1094  int len = snprintf(
1095  &dummy,
1096  0,
1097  "%s/paramsweep_%0*d/",
1098  checkpointWriteDir,
1099  lenserialno,
1100  parameterSweepSize - 1)
1101  + 1;
1102  char *checkpointPathStr = (char *)calloc(len, sizeof(char));
1103  if (checkpointPathStr == NULL)
1104  abort();
1105  for (int i = 0; i < parameterSweepSize; i++) {
1106  int chars_needed = snprintf(
1107  checkpointPathStr,
1108  len,
1109  "%s/paramsweep_%0*d/",
1110  checkpointWriteDir,
1111  lenserialno,
1112  i);
1113  assert(chars_needed < len);
1114  activeParamSweep->pushStringValue(checkpointPathStr);
1115  }
1116  free(checkpointPathStr);
1117  checkpointPathStr = NULL;
1118  addActiveParamSweep(hypercolgroupname, "checkpointWriteDir");
1119  }
1120  }
1121  }
1122 
1123  if (icComm->numCommBatches() > 1) {
1124  ParameterGroup *hypercolGroup = nullptr;
1125  for (int g = 0; g < numGroups; g++) {
1126  ParameterGroup *group = groups[g];
1127  if (!strcmp(group->getGroupKeyword(), "HyPerCol")) {
1128  hypercolGroup = group;
1129  break;
1130  }
1131  }
1132  FatalIf(hypercolGroup == nullptr, "PVParams::parseBuffer: no HyPerCol group\n");
1133  }
1134 
1135  // Each ParameterSweep needs to have its group/parameter pair added to the database, if it's not
1136  // already present.
1137  for (int k = 0; k < numberOfParameterSweeps(); k++) {
1138  ParameterSweep *sweep = paramSweeps[k];
1139  const char *group_name = sweep->getGroupName();
1140  const char *param_name = sweep->getParamName();
1141  SweepType type = sweep->getType();
1142  ParameterGroup *g = group(group_name);
1143  if (g == NULL) {
1144  ErrorLog().printf("ParameterSweep: there is no group \"%s\"\n", group_name);
1145  abort();
1146  }
1147  switch (type) {
1148  case SWEEP_NUMBER:
1149  if (!g->present(param_name)) {
1150  Parameter *p = new Parameter(param_name, 0.0);
1151  g->pushNumerical(p);
1152  }
1153  break;
1154  case SWEEP_STRING:
1155  if (!g->stringPresent(param_name)) {
1156  ParameterString *p = new ParameterString(param_name, "");
1157  g->pushString(p);
1158  }
1159  break;
1160  default: assert(0); break;
1161  }
1162  }
1163 
1164  clearHasBeenReadFlags();
1165 
1166  return PV_SUCCESS;
1167 }
1168 
1169 // TODO other integer types should also use valueInt
1170 template <>
1171 void PVParams::ioParamValue<int>(
1172  enum ParamsIOFlag ioFlag,
1173  const char *groupName,
1174  const char *paramName,
1175  int *paramValue,
1176  int defaultValue,
1177  bool warnIfAbsent) {
1178  switch (ioFlag) {
1179  case PARAMS_IO_READ:
1180  *paramValue = valueInt(groupName, paramName, defaultValue, warnIfAbsent);
1181  break;
1182  case PARAMS_IO_WRITE: writeParam(paramName, *paramValue); break;
1183  }
1184 }
1185 
1186 template <>
1187 void PVParams::ioParamValueRequired<int>(
1188  enum ParamsIOFlag ioFlag,
1189  const char *groupName,
1190  const char *paramName,
1191  int *paramValue) {
1192  switch (ioFlag) {
1193  case PARAMS_IO_READ: *paramValue = valueInt(groupName, paramName); break;
1194  case PARAMS_IO_WRITE: writeParam(paramName, *paramValue); break;
1195  }
1196 }
1197 
1198 int PVParams::setParameterSweepSize() {
1199  parameterSweepSize = -1;
1200  for (int k = 0; k < this->numberOfParameterSweeps(); k++) {
1201  if (parameterSweepSize < 0) {
1202  parameterSweepSize = this->paramSweeps[k]->getNumValues();
1203  }
1204  else {
1205  if (parameterSweepSize != this->paramSweeps[k]->getNumValues()) {
1206  ErrorLog().printf(
1207  "PVParams::setParameterSweepSize: all ParameterSweeps in the "
1208  "parameters file must have the same number of entries.\n");
1209  abort();
1210  }
1211  }
1212  }
1213  if (parameterSweepSize < 0)
1214  parameterSweepSize = 0;
1215  return parameterSweepSize;
1216 }
1217 
1218 int PVParams::setParameterSweepValues(int n) {
1219  int status = PV_SUCCESS;
1220  // Set parameter sweeps
1221  if (n < 0 || n >= parameterSweepSize) {
1222  status = PV_FAILURE;
1223  return status;
1224  }
1225  for (int k = 0; k < this->numberOfParameterSweeps(); k++) {
1226  ParameterSweep *paramSweep = paramSweeps[k];
1227  SweepType type = paramSweep->getType();
1228  const char *group_name = paramSweep->getGroupName();
1229  const char *param_name = paramSweep->getParamName();
1230  ParameterGroup *gp = group(group_name);
1231  assert(gp != NULL);
1232 
1233  const char *s;
1234  double v = 0.0f;
1235  switch (type) {
1236  case SWEEP_NUMBER:
1237  paramSweep->getNumericValue(n, &v);
1238  gp->setValue(param_name, v);
1239  break;
1240  case SWEEP_STRING:
1241  s = paramSweep->getStringValue(n);
1242  gp->setStringValue(param_name, s);
1243  break;
1244  default: assert(0); break;
1245  }
1246  }
1247  return status;
1248 }
1249 
1254 int PVParams::present(const char *groupName, const char *paramName) {
1255  ParameterGroup *g = group(groupName);
1256  if (g == NULL) {
1257  if (worldRank == 0) {
1258  ErrorLog().printf("PVParams::present: couldn't find a group for %s\n", groupName);
1259  }
1260  exit(EXIT_FAILURE);
1261  }
1262 
1263  return g->present(paramName);
1264 }
1265 
1270 double PVParams::value(const char *groupName, const char *paramName) {
1271  ParameterGroup *g = group(groupName);
1272  if (g == NULL) {
1273  if (worldRank == 0) {
1274  ErrorLog().printf("PVParams::value: ERROR, couldn't find a group for %s\n", groupName);
1275  }
1276  exit(EXIT_FAILURE);
1277  }
1278 
1279  return g->value(paramName);
1280 }
1281 
1282 int PVParams::valueInt(const char *groupName, const char *paramName) {
1283  double v = value(groupName, paramName);
1284  return convertParamToInt(v);
1285 }
1286 
1287 int PVParams::valueInt(
1288  const char *groupName,
1289  const char *paramName,
1290  int initialValue,
1291  bool warnIfAbsent) {
1292  double v = value(groupName, paramName, (double)initialValue, warnIfAbsent);
1293  return convertParamToInt(v);
1294 }
1295 
1296 int PVParams::convertParamToInt(double value) {
1297  int y = 0;
1298  if (value >= (double)INT_MAX) {
1299  y = INT_MAX;
1300  }
1301  else if (value <= (double)INT_MIN) {
1302  y = INT_MIN;
1303  }
1304  else {
1305  y = (int)nearbyint(value);
1306  }
1307  return y;
1308 }
1309 
1316  const char *groupName,
1317  const char *paramName,
1318  double initialValue,
1319  bool warnIfAbsent) {
1320  if (present(groupName, paramName)) {
1321  return value(groupName, paramName);
1322  }
1323  else {
1324  if (warnIfAbsent && worldRank == 0) {
1325  WarnLog().printf(
1326  "Using default value %f for parameter \"%s\" in group \"%s\"\n",
1327  initialValue,
1328  paramName,
1329  groupName);
1330  }
1331  return initialValue;
1332  }
1333 }
1334 
1335 template <>
1336 void PVParams::writeParam<bool>(const char *paramName, bool paramValue) {
1337  if (mPrintParamsStream != nullptr) {
1338  pvAssert(mPrintLuaStream);
1339  std::stringstream vstr("");
1340  vstr << (paramValue ? "true" : "false");
1341  mPrintParamsStream->printf(" %-35s = %s;\n", paramName, vstr.str().c_str());
1342  mPrintLuaStream->printf(" %-35s = %s;\n", paramName, vstr.str().c_str());
1343  }
1344 }
1345 
1346 bool PVParams::arrayPresent(const char *groupName, const char *paramName) {
1347  ParameterGroup *g = group(groupName);
1348  if (g == NULL) {
1349  if (worldRank == 0) {
1350  ErrorLog().printf("PVParams::present: couldn't find a group for %s\n", groupName);
1351  }
1352  exit(EXIT_FAILURE);
1353  }
1354 
1355  return g->arrayPresent(paramName);
1356 }
1357 
1358 // Could use a template function for arrayValues and arrayValuesDbl
1359 /*
1360  * @groupName
1361  * @paramName
1362  * @size
1363  */
1364 const float *
1365 PVParams::arrayValues(const char *groupName, const char *paramName, int *size, bool warnIfAbsent) {
1366  ParameterGroup *g = group(groupName);
1367  if (g == NULL) {
1368  if (worldRank == 0) {
1369  ErrorLog().printf("PVParams::value: couldn't find a group for %s\n", groupName);
1370  }
1371  return NULL;
1372  }
1373  const float *retval = g->arrayValues(paramName, size);
1374  if (retval == NULL) {
1375  assert(*size == 0);
1376  if (worldRank == 0) {
1377  WarnLog().printf(
1378  "Using empty array for parameter \"%s\" in group \"%s\"\n", paramName, groupName);
1379  }
1380  }
1381  return retval;
1382 }
1383 
1384 /*
1385  * @groupName
1386  * @paramName
1387  * @size
1388  */
1389 const double *PVParams::arrayValuesDbl(
1390  const char *groupName,
1391  const char *paramName,
1392  int *size,
1393  bool warnIfAbsent) {
1394  ParameterGroup *g = group(groupName);
1395  if (g == NULL) {
1396  if (worldRank == 0) {
1397  ErrorLog().printf("PVParams::value: couldn't find a group for %s\n", groupName);
1398  }
1399  return NULL;
1400  }
1401  const double *retval = g->arrayValuesDbl(paramName, size);
1402  if (retval == NULL) {
1403  assert(*size == 0);
1404  if (worldRank == 0) {
1405  WarnLog().printf(
1406  "Using empty array for parameter \"%s\" in group \"%s\"\n", paramName, groupName);
1407  }
1408  }
1409  return retval;
1410 }
1411 
1412 void PVParams::ioParamString(
1413  enum ParamsIOFlag ioFlag,
1414  const char *groupName,
1415  const char *paramName,
1416  char **paramStringValue,
1417  const char *defaultValue,
1418  bool warnIfAbsent) {
1419  const char *paramString = nullptr;
1420  switch (ioFlag) {
1421  case PARAMS_IO_READ:
1422  if (stringPresent(groupName, paramName)) {
1423  paramString = stringValue(groupName, paramName, warnIfAbsent);
1424  }
1425  else {
1426  // parameter was not set in params file; use the default. But default might or might
1427  // not be nullptr.
1428  if (worldRank == 0 and warnIfAbsent == true) {
1429  if (defaultValue != nullptr) {
1430  WarnLog().printf(
1431  "Using default value \"%s\" for string parameter \"%s\" in group \"%s\"\n",
1432  defaultValue,
1433  paramName,
1434  groupName);
1435  }
1436  else {
1437  WarnLog().printf(
1438  "Using default value of nullptr for string parameter \"%s\" in group "
1439  "\"%s\"\n",
1440  paramName,
1441  groupName);
1442  }
1443  }
1444  paramString = defaultValue;
1445  }
1446  if (paramString != nullptr) {
1447  *paramStringValue = strdup(paramString);
1448  FatalIf(
1449  *paramStringValue == nullptr,
1450  "Global rank %d process unable to copy param %s in group \"%s\": %s\n",
1451  worldRank,
1452  paramName,
1453  groupName,
1454  strerror(errno));
1455  }
1456  else {
1457  *paramStringValue = nullptr;
1458  }
1459  break;
1460  case PARAMS_IO_WRITE: writeParamString(paramName, *paramStringValue);
1461  }
1462 }
1463 
1464 void PVParams::ioParamStringRequired(
1465  enum ParamsIOFlag ioFlag,
1466  const char *groupName,
1467  const char *paramName,
1468  char **paramStringValue) {
1469  const char *paramString = nullptr;
1470  switch (ioFlag) {
1471  case PARAMS_IO_READ:
1472  paramString = stringValue(groupName, paramName, false /*warnIfAbsent*/);
1473  if (paramString != nullptr) {
1474  *paramStringValue = strdup(paramString);
1475  FatalIf(
1476  *paramStringValue == nullptr,
1477  "Global Rank %d process unable to copy param %s in group \"%s\": %s\n",
1478  worldRank,
1479  paramName,
1480  groupName,
1481  strerror(errno));
1482  }
1483  else if (!stringPresent(groupName, paramName)) {
1484  // Setting the param to NULL explicitly is allowed;
1485  // if the string parameter is not present at all, error out.
1486  if (worldRank == 0) {
1487  ErrorLog().printf(
1488  "%s \"%s\": string parameter \"%s\" is required.\n",
1489  groupKeywordFromName(groupName),
1490  groupName,
1491  paramName);
1492  }
1493  MPI_Barrier(icComm->globalCommunicator());
1494  exit(EXIT_FAILURE);
1495  }
1496  else {
1497  *paramStringValue = nullptr;
1498  }
1499  break;
1500  case PARAMS_IO_WRITE: writeParamString(paramName, *paramStringValue);
1501  }
1502 }
1503 
1504 /*
1505  * @groupName
1506  * @paramStringName
1507  */
1508 int PVParams::stringPresent(const char *groupName, const char *paramStringName) {
1509  ParameterGroup *g = group(groupName);
1510  if (g == NULL) {
1511  if (worldRank == 0) {
1512  ErrorLog().printf("PVParams::stringPresent: couldn't find a group for %s\n", groupName);
1513  }
1514  exit(EXIT_FAILURE);
1515  }
1516 
1517  return g->stringPresent(paramStringName);
1518 }
1519 
1520 /*
1521  * @groupName
1522  * @paramStringName
1523  */
1524 const char *
1525 PVParams::stringValue(const char *groupName, const char *paramStringName, bool warnIfAbsent) {
1526  if (stringPresent(groupName, paramStringName)) {
1527  ParameterGroup *g = group(groupName);
1528  return g->stringValue(paramStringName);
1529  }
1530  else {
1531  if (warnIfAbsent && worldRank == 0) {
1532  WarnLog().printf(
1533  "No parameter string named \"%s\" in group \"%s\"\n", paramStringName, groupName);
1534  }
1535  return NULL;
1536  }
1537 }
1538 
1539 void PVParams::writeParamString(const char *paramName, const char *svalue) {
1540  if (mPrintParamsStream != nullptr) {
1541  pvAssert(mPrintLuaStream);
1542  if (svalue != nullptr) {
1543  mPrintParamsStream->printf(" %-35s = \"%s\";\n", paramName, svalue);
1544  mPrintLuaStream->printf(" %-35s = \"%s\";\n", paramName, svalue);
1545  }
1546  else {
1547  mPrintParamsStream->printf(" %-35s = NULL;\n", paramName);
1548  mPrintLuaStream->printf(" %-35s = NULL;\n", paramName);
1549  }
1550  }
1551 }
1552 
1556 ParameterGroup *PVParams::group(const char *groupName) {
1557  for (int i = 0; i < numGroups; i++) {
1558  if (strcmp(groupName, groups[i]->name()) == 0) {
1559  return groups[i];
1560  }
1561  }
1562  return NULL;
1563 }
1564 
1565 const char *PVParams::groupNameFromIndex(int index) {
1566  bool inbounds = index >= 0 && index < numGroups;
1567  return inbounds ? groups[index]->name() : NULL;
1568 }
1569 
1570 const char *PVParams::groupKeywordFromIndex(int index) {
1571  bool inbounds = index >= 0 && index < numGroups;
1572  return inbounds ? groups[index]->getGroupKeyword() : NULL;
1573 }
1574 
1575 const char *PVParams::groupKeywordFromName(const char *name) {
1576  const char *kw = NULL;
1577  ParameterGroup *g = group(name);
1578  if (g != NULL) {
1579  kw = g->getGroupKeyword();
1580  }
1581  return kw;
1582 }
1583 
1588 void PVParams::addGroup(char *keyword, char *name) {
1589  assert((size_t)numGroups <= groupArraySize);
1590 
1591  // Verify that the new group's name is not an existing group's name
1592  for (int k = 0; k < numGroups; k++) {
1593  if (!strcmp(name, groups[k]->name())) {
1594  Fatal().printf("Rank %d process: group name \"%s\" duplicated\n", worldRank, name);
1595  }
1596  }
1597 
1598  if ((size_t)numGroups == groupArraySize) {
1599  groupArraySize += RESIZE_ARRAY_INCR;
1600  ParameterGroup **newGroups =
1601  (ParameterGroup **)malloc(groupArraySize * sizeof(ParameterGroup *));
1602  assert(newGroups);
1603  for (int k = 0; k < numGroups; k++) {
1604  newGroups[k] = groups[k];
1605  }
1606  free(groups);
1607  groups = newGroups;
1608  }
1609 
1610  groups[numGroups] = new ParameterGroup(name, stack, arrayStack, stringStack, worldRank);
1611  groups[numGroups]->setGroupKeyword(keyword);
1612 
1613  // the parameter group takes over control of the PVParams's stack and stringStack; make new ones.
1614  stack = new ParameterStack(MAX_PARAMS);
1615  arrayStack = new ParameterArrayStack(PARAMETERARRAYSTACK_INITIALCOUNT);
1616  stringStack = new ParameterStringStack(PARAMETERSTRINGSTACK_INITIALCOUNT);
1617 
1618  numGroups++;
1619 }
1620 
1621 void PVParams::addActiveParamSweep(const char *group_name, const char *param_name) {
1622  // Search for group_name and param_name in both ParameterSweep and BatchSweep list of objects
1623  for (int p = 0; p < numParamSweeps; p++) {
1624  if (strcmp(paramSweeps[p]->getGroupName(), group_name) == 0
1625  && strcmp(paramSweeps[p]->getParamName(), param_name) == 0) {
1626  Fatal().printf(
1627  "PVParams::addActiveParamSweep: Parameter sweep %s, %s already exists\n",
1628  group_name,
1629  param_name);
1630  }
1631  }
1632 
1633  activeParamSweep->setGroupAndParameter(group_name, param_name);
1634  ParameterSweep **newParamSweeps =
1635  (ParameterSweep **)calloc(numParamSweeps + 1, sizeof(ParameterSweep *));
1636  if (newParamSweeps == NULL) {
1637  Fatal().printf(
1638  "PVParams::action_parameter_sweep: unable to allocate memory for larger paramSweeps\n");
1639  }
1640  for (int k = 0; k < numParamSweeps; k++) {
1641  newParamSweeps[k] = paramSweeps[k];
1642  }
1643  free(paramSweeps);
1644  paramSweeps = newParamSweeps;
1645  paramSweeps[numParamSweeps] = activeParamSweep;
1646  numParamSweeps++;
1647  newActiveParamSweep();
1648 }
1649 
1650 int PVParams::warnUnread() {
1651  int status = PV_SUCCESS;
1652  for (int i = 0; i < numberOfGroups(); i++) {
1653  if (groups[i]->warnUnread() != PV_SUCCESS) {
1654  status = PV_FAILURE;
1655  }
1656  }
1657  return status;
1658 }
1659 
1660 bool PVParams::hasBeenRead(const char *group_name, const char *param_name) {
1661  ParameterGroup *g = group(group_name);
1662  if (g == NULL) {
1663  return false;
1664  }
1665 
1666  return g->hasBeenRead(param_name);
1667 }
1668 
1669 bool PVParams::presentAndNotBeenRead(const char *group_name, const char *param_name) {
1670  bool is_present = present(group_name, param_name);
1671  if (!is_present)
1672  is_present = arrayPresent(group_name, param_name);
1673  if (!is_present)
1674  is_present = stringPresent(group_name, param_name);
1675  bool has_been_read = hasBeenRead(group_name, param_name);
1676  return is_present && !has_been_read;
1677 }
1678 
1679 int PVParams::clearHasBeenReadFlags() {
1680  int status = PV_SUCCESS;
1681  for (int i = 0; i < numberOfGroups(); i++) {
1682  if (groups[i]->clearHasBeenReadFlags() != PV_SUCCESS) {
1683  status = PV_FAILURE;
1684  }
1685  }
1686  return status;
1687 }
1688 
1689 void PVParams::handleUnnecessaryParameter(const char *group_name, const char *param_name) {
1690  if (present(group_name, param_name)) {
1691  if (worldRank == 0) {
1692  const char *class_name = groupKeywordFromName(group_name);
1693  WarnLog().printf(
1694  "%s \"%s\" does not use parameter %s, but it is present in the parameters file.\n",
1695  class_name,
1696  group_name,
1697  param_name);
1698  }
1699  value(group_name,
1700  param_name); // marks param as read so that presentAndNotBeenRead doesn't trip up
1701  }
1702 }
1703 
1704 void PVParams::handleUnnecessaryStringParameter(const char *group_name, const char *param_name) {
1705  int status = PV_SUCCESS;
1706  const char *class_name = groupKeywordFromName(group_name);
1707  if (stringPresent(group_name, param_name)) {
1708  if (worldRank == 0) {
1709  WarnLog().printf(
1710  "%s \"%s\" does not use string parameter %s, but it is present in the parameters "
1711  "file.\n",
1712  class_name,
1713  group_name,
1714  param_name);
1715  }
1716  const char *params_value = stringValue(group_name, param_name, false /*warnIfAbsent*/);
1717  // marks param as read so that presentAndNotBeenRead doesn't trip up
1718  }
1719 }
1720 
1722  const char *group_name,
1723  const char *param_name,
1724  const char *correct_value,
1725  bool case_insensitive_flag) {
1726  int status = PV_SUCCESS;
1727  const char *class_name = groupKeywordFromName(group_name);
1728  if (stringPresent(group_name, param_name)) {
1729  if (worldRank == 0) {
1730  WarnLog().printf(
1731  "%s \"%s\" does not use string parameter %s, but it is present in the parameters "
1732  "file.\n",
1733  class_name,
1734  group_name,
1735  param_name);
1736  }
1737  const char *params_value = stringValue(group_name, param_name, false /*warnIfAbsent*/);
1738  // marks param as read so that presentAndNotBeenRead doesn't trip up
1739 
1740  // Check against correct value.
1741  if (params_value != nullptr && correct_value != nullptr) {
1742  char *correct_value_i =
1743  strdup(correct_value); // need mutable strings for case-insensitive comparison
1744  char *params_value_i =
1745  strdup(params_value); // need mutable strings for case-insensitive comparison
1746  if (correct_value_i == nullptr) {
1747  status = PV_FAILURE;
1748  if (worldRank == 0) {
1749  ErrorLog().printf(
1750  "%s \"%s\": Rank %d process unable to copy correct string value: %s.\n",
1751  class_name,
1752  group_name,
1753  worldRank,
1754  strerror(errno));
1755  }
1756  }
1757  if (params_value_i == nullptr) {
1758  status = PV_FAILURE;
1759  if (worldRank == 0) {
1760  ErrorLog().printf(
1761  "%s \"%s\": Rank %d process unable to copy parameter string value: %s.\n",
1762  class_name,
1763  group_name,
1764  worldRank,
1765  strerror(errno));
1766  }
1767  }
1768  if (case_insensitive_flag) {
1769  for (char *c = params_value_i; *c != '\0'; c++) {
1770  *c = (char)tolower((int)*c);
1771  }
1772  for (char *c = correct_value_i; *c != '\0'; c++) {
1773  *c = (char)tolower((int)*c);
1774  }
1775  }
1776  if (strcmp(params_value_i, correct_value_i) != 0) {
1777  status = PV_FAILURE;
1778  if (worldRank == 0) {
1779  ErrorLog().printf(
1780  "%s \"%s\": parameter string %s = \"%s\" is inconsistent with correct value "
1781  "\"%s\". Exiting.\n",
1782  class_name,
1783  group_name,
1784  param_name,
1785  params_value,
1786  correct_value);
1787  }
1788  }
1789  free(correct_value_i);
1790  free(params_value_i);
1791  }
1792  else if (params_value == nullptr && correct_value != nullptr) {
1793  status = PV_FAILURE;
1794  if (worldRank == 0) {
1795  ErrorLog().printf(
1796  "%s \"%s\": parameter string %s = NULL is inconsistent with correct value "
1797  "\"%s\". Exiting.\n",
1798  class_name,
1799  group_name,
1800  param_name,
1801  correct_value);
1802  }
1803  }
1804  else if (params_value != nullptr && correct_value == nullptr) {
1805  status = PV_FAILURE;
1806  if (worldRank == 0) {
1807  ErrorLog().printf(
1808  "%s \"%s\": parameter string %s = \"%s\" is inconsistent with correct value of "
1809  "NULL. Exiting.\n",
1810  class_name,
1811  group_name,
1812  param_name,
1813  params_value);
1814  }
1815  }
1816  else {
1817  pvAssert(params_value == nullptr && correct_value == nullptr);
1818  pvAssert(status == PV_SUCCESS);
1819  }
1820  }
1821  if (status != PV_SUCCESS) {
1822  MPI_Barrier(icComm->globalCommunicator());
1823  exit(EXIT_FAILURE);
1824  }
1825 }
1826 
1831 void PVParams::action_pvparams_directive(char *id, double val) {
1832  if (!strcmp(id, "debugParsing")) {
1833  debugParsing = (val != 0);
1834  if (worldRank == 0) {
1835  InfoLog(directiveMessage);
1836  directiveMessage.printf("debugParsing turned ");
1837  if (debugParsing) {
1838  directiveMessage.printf("on.\n");
1839  }
1840  else {
1841  directiveMessage.printf("off.\n");
1842  }
1843  }
1844  }
1845  else if (!strcmp(id, "disable")) {
1846  disable = (val != 0);
1847  if (worldRank == 0) {
1848  InfoLog(directiveMessage);
1849  directiveMessage.printf("Parsing params file ");
1850  if (disable) {
1851  directiveMessage.printf("disabled.\n");
1852  }
1853  else {
1854  directiveMessage.printf("enabled.\n");
1855  }
1856  }
1857  }
1858  else {
1859  if (worldRank == 0) {
1860  WarnLog().printf("Unrecognized directive %s = %f, skipping.\n", id, val);
1861  }
1862  }
1863 }
1864 
1869 void PVParams::action_parameter_group() {
1870  if (disable)
1871  return;
1872  if (debugParsing && worldRank == 0) {
1873  InfoLog().printf(
1874  "action_parameter_group: %s \"%s\" parsed successfully.\n",
1875  currGroupKeyword,
1876  currGroupName);
1877  InfoLog().flush();
1878  }
1879  // build a parameter group
1880  addGroup(currGroupKeyword, currGroupName);
1881 }
1882 void PVParams::action_parameter_group_name(char *keyword, char *name) {
1883  if (disable)
1884  return;
1885  // remove surrounding quotes
1886  int len = strlen(++name);
1887  name[len - 1] = '\0';
1888 
1889  if (debugParsing && worldRank == 0) {
1890  InfoLog().printf(
1891  "action_parameter_group_name: %s \"%s\" parsed successfully.\n", keyword, name);
1892  InfoLog().flush();
1893  }
1894  currGroupKeyword = keyword;
1895  currGroupName = name;
1896 }
1897 
1902 void PVParams::action_parameter_def(char *id, double val) {
1903  if (disable)
1904  return;
1905  if (debugParsing && worldRank == 0) {
1906  InfoLog().flush();
1907  InfoLog().printf("action_parameter_def: %s = %lf\n", id, val);
1908  InfoLog().flush();
1909  }
1910  checkDuplicates(id);
1911  Parameter *p = new Parameter(id, val);
1912  stack->push(p);
1913 }
1914 
1915 void PVParams::action_parameter_def_overwrite(char *id, double val) {
1916  if (disable)
1917  return;
1918  if (debugParsing && worldRank == 0) {
1919  InfoLog().flush();
1920  InfoLog().printf("action_parameter_def_overwrite: %s = %lf\n", id, val);
1921  InfoLog().flush();
1922  }
1923  // Search through current parameters for the id
1924  char *param_name = stripOverwriteTag(id);
1925  Parameter *currParam = NULL;
1926  for (int i = 0; i < stack->size(); i++) {
1927  Parameter *param = stack->peek(i);
1928  if (strcmp(param->name(), param_name) == 0) {
1929  currParam = param;
1930  }
1931  }
1932  if (!currParam) {
1933  for (int i = 0; i < arrayStack->size(); i++) {
1934  ParameterArray *arrayParam = arrayStack->peek(i);
1935  if (strcmp(arrayParam->name(), param_name) == 0) {
1936  InfoLog().flush();
1937  InfoLog().printf(
1938  "%s is defined as an array parameter. Overwriting array parameters with value "
1939  "parameters not implemented yet.\n",
1940  id);
1941  InfoLog().flush();
1942  }
1943  }
1944  InfoLog().flush();
1945  ErrorLog().printf("Overwrite: %s is not an existing parameter to overwrite.\n", id);
1946  InfoLog().flush();
1947  }
1948  free(param_name);
1949  // Set to new value
1950  currParam->setValue(val);
1951 }
1952 
1953 void PVParams::action_parameter_array(char *id) {
1954  if (disable)
1955  return;
1956  if (debugParsing && worldRank == 0) {
1957  InfoLog().flush();
1958  InfoLog().printf("action_parameter_array: %s\n", id);
1959  InfoLog().flush();
1960  }
1961  int status = currentParamArray->setName(id);
1962  assert(status == PV_SUCCESS);
1963  checkDuplicates(id);
1964  arrayStack->push(currentParamArray);
1965  currentParamArray = new ParameterArray(PARAMETERARRAYSTACK_INITIALCOUNT);
1966 }
1967 
1968 void PVParams::action_parameter_array_overwrite(char *id) {
1969  if (disable)
1970  return;
1971  if (debugParsing && worldRank == 0) {
1972  InfoLog().flush();
1973  InfoLog().printf("action_parameter_array_overwrite: %s\n", id);
1974  InfoLog().flush();
1975  }
1976  // Search through current parameters for the id
1977  char *param_name = stripOverwriteTag(id);
1978  ParameterArray *origArray = NULL;
1979  for (int i = 0; i < arrayStack->size(); i++) {
1980  ParameterArray *arrayParam = arrayStack->peek(i);
1981  if (strcmp(arrayParam->name(), param_name) == 0) {
1982  origArray = arrayParam;
1983  }
1984  }
1985  if (!origArray) {
1986  for (int i = 0; i < stack->size(); i++) {
1987  Parameter *param = stack->peek(i);
1988  if (strcmp(param->name(), param_name) == 0) {
1989  InfoLog().flush();
1990  InfoLog().printf(
1991  "%s is defined as a value parameter. Overwriting value parameters with array "
1992  "parameters not implemented yet.\n",
1993  id);
1994  InfoLog().flush();
1995  }
1996  }
1997  InfoLog().flush();
1998  ErrorLog().printf("Overwrite: %s is not an existing parameter to overwrite.\n", id);
1999  InfoLog().flush();
2000  }
2001  free(param_name);
2002  // Set values of arrays
2003  origArray->resetArraySize();
2004  for (int i = 0; i < currentParamArray->getArraySize(); i++) {
2005  origArray->pushValue(currentParamArray->peek(i));
2006  }
2007  assert(origArray->getArraySize() == currentParamArray->getArraySize());
2008  delete currentParamArray;
2009  currentParamArray = new ParameterArray(PARAMETERARRAYSTACK_INITIALCOUNT);
2010 }
2011 
2012 void PVParams::action_parameter_array_value(double val) {
2013  if (disable)
2014  return;
2015  if (debugParsing && worldRank == 0) {
2016  InfoLog().flush();
2017  InfoLog().printf("action_parameter_array_value %lf\n", val);
2018  }
2019  int sz = currentParamArray->getArraySize();
2020  int newsize = currentParamArray->pushValue(val);
2021  assert(newsize == sz + 1);
2022 }
2023 
2024 void PVParams::action_parameter_string_def(const char *id, const char *stringval) {
2025  if (disable)
2026  return;
2027  if (debugParsing && worldRank == 0) {
2028  InfoLog().flush();
2029  InfoLog().printf("action_parameter_string_def: %s = %s\n", id, stringval);
2030  InfoLog().flush();
2031  }
2032  checkDuplicates(id);
2033  char *param_value = stripQuotationMarks(stringval);
2034  assert(!stringval || param_value); // stringval can be null, but if stringval is not null,
2035  // param_value should also be non-null
2036  ParameterString *pstr = new ParameterString(id, param_value);
2037  stringStack->push(pstr);
2038  free(param_value);
2039 }
2040 
2041 void PVParams::action_parameter_string_def_overwrite(const char *id, const char *stringval) {
2042  if (disable)
2043  return;
2044  if (debugParsing && worldRank == 0) {
2045  InfoLog().flush();
2046  InfoLog().printf("action_parameter_string_def_overwrite: %s = %s\n", id, stringval);
2047  InfoLog().flush();
2048  }
2049  // Search through current parameters for the id
2050  char *param_name = stripOverwriteTag(id);
2051  ParameterString *currParam = NULL;
2052  for (int i = 0; i < stringStack->size(); i++) {
2053  ParameterString *param = stringStack->peek(i);
2054  assert(param);
2055  if (strcmp(param->getName(), param_name) == 0) {
2056  currParam = param;
2057  }
2058  }
2059  free(param_name);
2060  if (!currParam) {
2061  ErrorLog().printf("Overwrite: %s is not an existing parameter to overwrite.\n", id);
2062  }
2063  char *param_value = stripQuotationMarks(stringval);
2064  assert(!stringval || param_value); // stringval can be null, but if stringval is not null,
2065  // param_value should also be non-null
2066  // Set to new value
2067  currParam->setValue(param_value);
2068  free(param_value);
2069 }
2070 
2071 void PVParams::action_parameter_filename_def(const char *id, const char *stringval) {
2072  if (disable)
2073  return;
2074  if (debugParsing && worldRank == 0) {
2075  InfoLog().flush();
2076  InfoLog().printf("action_parameter_filename_def: %s = %s\n", id, stringval);
2077  InfoLog().flush();
2078  }
2079  checkDuplicates(id);
2080  char *param_value = stripQuotationMarks(stringval);
2081  assert(param_value);
2082  ParameterString *pstr = new ParameterString(id, param_value);
2083  free(param_value);
2084  stringStack->push(pstr);
2085 }
2086 
2087 void PVParams::action_parameter_filename_def_overwrite(const char *id, const char *stringval) {
2088  if (disable)
2089  return;
2090  if (debugParsing && worldRank == 0) {
2091  InfoLog().flush();
2092  InfoLog().printf("action_parameter_filename_def_overwrite: %s = %s\n", id, stringval);
2093  InfoLog().flush();
2094  }
2095  // Search through current parameters for the id
2096  char *param_name = stripOverwriteTag(id);
2097  ParameterString *currParam = NULL;
2098  for (int i = 0; i < stringStack->size(); i++) {
2099  ParameterString *param = stringStack->peek(i);
2100  assert(param);
2101  if (strcmp(param->getName(), param_name) == 0) {
2102  currParam = param;
2103  }
2104  }
2105  free(param_name);
2106  param_name = NULL;
2107  if (!currParam) {
2108  ErrorLog().printf("Overwrite: %s is not an existing parameter to overwrite.\n", id);
2109  }
2110  char *param_value = stripQuotationMarks(stringval);
2111  assert(param_value);
2112  currParam->setValue(param_value);
2113  free(param_value);
2114 }
2115 
2116 void PVParams::action_include_directive(const char *stringval) {
2117  if (disable)
2118  return;
2119  if (debugParsing && worldRank == 0) {
2120  InfoLog().flush();
2121  InfoLog().printf("action_include_directive: including %s\n", stringval);
2122  InfoLog().flush();
2123  }
2124  // The include directive must be the first parameter in the group if defined
2125  if (stack->size() != 0 || arrayStack->size() != 0 || stringStack->size() != 0) {
2126  ErrorLog().printf(
2127  "Import of %s must be the first parameter specified in the group.\n", stringval);
2128  InfoLog().flush();
2129  }
2130  // Grab the parameter value
2131  char *param_value = stripQuotationMarks(stringval);
2132  // Grab the included group's ParameterGroup object
2133  ParameterGroup *includeGroup = NULL;
2134  for (int groupidx = 0; groupidx < numGroups; groupidx++) {
2135  // If strings are matching
2136  if (strcmp(groups[groupidx]->name(), param_value) == 0) {
2137  includeGroup = groups[groupidx];
2138  }
2139  }
2140  // If group not found
2141  if (!includeGroup) {
2142  ErrorLog().printf("Include: include group %s is not defined.\n", param_value);
2143  }
2144  // Check keyword of group
2145  if (strcmp(includeGroup->getGroupKeyword(), currGroupKeyword) != 0) {
2146  ErrorLog().printf(
2147  "Include: Cannot include group %s, which is a %s, into a %s. Group types must be the "
2148  "same.\n",
2149  param_value,
2150  includeGroup->getGroupKeyword(),
2151  currGroupKeyword);
2152  }
2153  free(param_value);
2154  // Load all stack values into current parameter group
2155 
2156  assert(stack->size() == 0);
2157  delete stack;
2158  stack = includeGroup->copyStack();
2159 
2160  assert(arrayStack->size() == 0);
2161  delete arrayStack;
2162  arrayStack = includeGroup->copyArrayStack();
2163 
2164  assert(stringStack->size() == 0);
2165  delete stringStack;
2166  stringStack = includeGroup->copyStringStack();
2167 }
2168 
2169 void PVParams::action_parameter_sweep_open(const char *groupname, const char *paramname) {
2170  if (disable)
2171  return;
2172  // strip quotation marks from groupname
2173  currSweepGroupName = stripQuotationMarks(groupname);
2174  assert(currSweepGroupName);
2175  currSweepParamName = strdup(paramname);
2176  if (debugParsing && worldRank == 0) {
2177  InfoLog().flush();
2178  InfoLog().printf(
2179  "action_parameter_sweep_open: Sweep for group %s, parameter \"%s\" starting\n",
2180  groupname,
2181  paramname);
2182  InfoLog().flush();
2183  }
2184 }
2185 
2186 void PVParams::action_parameter_sweep_close() {
2187  if (disable)
2188  return;
2189  addActiveParamSweep(currSweepGroupName, currSweepParamName);
2190  if (debugParsing && worldRank == 0) {
2191  InfoLog().printf(
2192  "action_parameter_group: ParameterSweep for %s \"%s\" parsed successfully.\n",
2193  currSweepGroupName,
2194  currSweepParamName);
2195  InfoLog().flush();
2196  }
2197  // build a parameter group
2198  free(currSweepGroupName);
2199  free(currSweepParamName);
2200 }
2201 
2202 void PVParams::action_parameter_sweep_values_number(double val) {
2203  if (disable)
2204  return;
2205  if (debugParsing && worldRank == 0) {
2206  InfoLog().flush();
2207  InfoLog().printf("action_parameter_sweep_values_number: %f\n", val);
2208  InfoLog().flush();
2209  }
2210  activeParamSweep->pushNumericValue(val);
2211 }
2212 
2213 void PVParams::action_parameter_sweep_values_string(const char *stringval) {
2214  if (disable)
2215  return;
2216  if (debugParsing && worldRank == 0) {
2217  InfoLog().flush();
2218  InfoLog().printf("action_sweep_values_string: %s\n", stringval);
2219  InfoLog().flush();
2220  }
2221  char *string = stripQuotationMarks(stringval);
2222  assert(!stringval || string); // stringval can be null, but if stringval is not null, string
2223  // should also be non-null
2224  activeParamSweep->pushStringValue(string);
2225  free(string);
2226 }
2227 
2228 void PVParams::action_parameter_sweep_values_filename(const char *stringval) {
2229  if (disable)
2230  return;
2231  if (debugParsing && worldRank == 0) {
2232  InfoLog().flush();
2233  InfoLog().printf("action_sweep_values_filename: %s\n", stringval);
2234  InfoLog().flush();
2235  }
2236  char *filename = stripQuotationMarks(stringval);
2237  assert(filename);
2238  activeParamSweep->pushStringValue(filename);
2239  free(filename);
2240 }
2241 
2242 void PVParams::checkDuplicates(const char *paramName) {
2243  bool hasDuplicate = false;
2244  for (int k = 0; k < stack->size(); k++) {
2245  Parameter *parm = stack->peek(k);
2246  if (!strcmp(paramName, parm->name())) {
2247  ErrorLog().printf(
2248  "Rank %d process: The params group for %s \"%s\" duplicates "
2249  "parameter \"%s\".\n",
2250  worldRank,
2251  currGroupKeyword,
2252  currGroupName,
2253  paramName);
2254  hasDuplicate = true;
2255  }
2256  }
2257  for (int k = 0; k < arrayStack->size(); k++) {
2258  if (!strcmp(paramName, arrayStack->peek(k)->name())) {
2259  ErrorLog().printf(
2260  "Rank %d process: The params group for %s \"%s\" duplicates "
2261  "array parameter \"%s\".\n",
2262  worldRank,
2263  currGroupKeyword,
2264  currGroupName,
2265  paramName);
2266  hasDuplicate = true;
2267  }
2268  }
2269  for (int k = 0; k < stringStack->size(); k++) {
2270  if (!strcmp(paramName, stringStack->peek(k)->getName())) {
2271  ErrorLog().printf(
2272  "Rank %d process: The params group for %s \"%s\" duplicates "
2273  "string parameter \"%s\".\n",
2274  worldRank,
2275  currGroupKeyword,
2276  currGroupName,
2277  paramName);
2278  hasDuplicate = true;
2279  }
2280  }
2281  if (hasDuplicate) {
2282  exit(EXIT_FAILURE);
2283  }
2284 }
2285 
2286 char *PVParams::stripQuotationMarks(const char *s) {
2287  // If a string has quotes as its first and last character, return the
2288  // part of the string inside the quotes, e.g. {'"', 'c', 'a', 't', '"'}
2289  // becomes {'c', 'a', 't'}. If the string is null or does not have quotes at the
2290  // beginning and end, return NULL.
2291  // It is the responsibility of the routine that calls stripQuotationMarks
2292  // to free the returned string to avoid a memory leak.
2293  if (s == NULL) {
2294  return NULL;
2295  }
2296  char *noquotes = NULL;
2297  int len = strlen(s);
2298  if (len >= 2 && s[0] == '"' && s[len - 1] == '"') {
2299  noquotes = (char *)calloc(len - 1, sizeof(char));
2300  memcpy(noquotes, s + 1, len - 2);
2301  noquotes[len - 2] = '\0'; // Not strictly necessary since noquotes was calloc'ed
2302  }
2303  return noquotes;
2304 }
2305 
2306 char *PVParams::stripOverwriteTag(const char *s) {
2307  // Strips the @ tag to any overwritten params
2308  int len = strlen(s);
2309  char *notag = NULL;
2310  if (len >= 1 && s[0] == '@') {
2311  notag = (char *)calloc(len, sizeof(char));
2312  memcpy(notag, s + 1, len - 1);
2313  notag[len - 1] = '\0';
2314  }
2315  return notag;
2316 }
2317 
2318 } // close namespace PV block
ParameterStringStack * copyStringStack()
Definition: PVParams.cpp:649
ParameterArrayStack * copyArrayStack()
Definition: PVParams.cpp:638
int push(Parameter *param)
Definition: PVParams.cpp:192
int present(const char *groupName, const char *paramName)
Definition: PVParams.cpp:1254
ParameterGroup * group(const char *groupName)
Definition: PVParams.cpp:1556
double value(const char *groupName, const char *paramName)
Definition: PVParams.cpp:1270
ParameterStack(int maxCount)
Definition: PVParams.cpp:176
void action_parameter_def(char *id, double val)
Definition: PVParams.cpp:1902
void action_pvparams_directive(char *id, double val)
Definition: PVParams.cpp:1831
void handleUnnecessaryStringParameter(const char *group_name, const char *param_name)
Definition: PVParams.cpp:1704
ParameterStack * copyStack()
Definition: PVParams.cpp:627