PetaVision  Alpha
BaseProbe.cpp
1 /*
2  * BaseProbe.cpp
3  *
4  * Created on: Mar 7, 2009
5  * Author: rasmussn
6  */
7 
8 #include "BaseProbe.hpp"
9 #include "ColumnEnergyProbe.hpp"
10 #include "layers/HyPerLayer.hpp"
11 #include <float.h>
12 #include <limits>
13 
14 namespace PV {
15 
16 BaseProbe::BaseProbe() {
17  initialize_base();
18  // Derived classes of BaseProbe should call BaseProbe::initialize themselves.
19 }
20 
21 BaseProbe::~BaseProbe() {
22  for (auto &s : mOutputStreams) {
23  delete s;
24  }
25  mOutputStreams.clear();
26  free(targetName);
27  targetName = NULL;
28  free(msgparams);
29  msgparams = NULL;
30  free(msgstring);
31  msgstring = NULL;
32  free(probeOutputFilename);
33  probeOutputFilename = NULL;
34  if (triggerLayerName) {
35  free(triggerLayerName);
36  triggerLayerName = NULL;
37  }
38  free(energyProbe);
39  free(probeValues);
40 }
41 
42 int BaseProbe::initialize_base() {
43  targetName = NULL;
44  msgparams = NULL;
45  msgstring = NULL;
46  textOutputFlag = true;
47  probeOutputFilename = NULL;
48  triggerFlag = false;
49  triggerLayerName = NULL;
50  triggerLayer = NULL;
51  triggerOffset = 0;
52  energyProbe = NULL;
53  coefficient = 1.0;
54  numValues = 0;
55  probeValues = NULL;
56  lastUpdateTime = 0.0;
57  return PV_SUCCESS;
58 }
59 
64 int BaseProbe::initialize(const char *name, HyPerCol *hc) {
65  int status = BaseObject::initialize(name, hc);
66  if (status != PV_SUCCESS) {
67  return status;
68  }
69  readParams();
70  initNumValues();
71  return status;
72 }
73 
74 void BaseProbe::setObjectType() { mObjectType = lookupKeyword(); }
75 
76 int BaseProbe::ioParamsFillGroup(enum ParamsIOFlag ioFlag) {
77  ioParam_targetName(ioFlag);
78  ioParam_message(ioFlag);
79  ioParam_textOutputFlag(ioFlag);
82  ioParam_triggerFlag(ioFlag);
83  ioParam_triggerOffset(ioFlag);
84  ioParam_energyProbe(ioFlag);
85  ioParam_coefficient(ioFlag);
86  return PV_SUCCESS;
87 }
88 
89 void BaseProbe::ioParam_targetName(enum ParamsIOFlag ioFlag) {
90  parent->parameters()->ioParamStringRequired(ioFlag, name, "targetName", &targetName);
91 }
92 
93 void BaseProbe::ioParam_message(enum ParamsIOFlag ioFlag) {
94  parent->parameters()->ioParamString(
95  ioFlag, name, "message", &msgparams, NULL, false /*warnIfAbsent*/);
96  if (ioFlag == PARAMS_IO_READ) {
97  initMessage(msgparams);
98  }
99 }
100 
101 void BaseProbe::ioParam_energyProbe(enum ParamsIOFlag ioFlag) {
102  parent->parameters()->ioParamString(
103  ioFlag, name, "energyProbe", &energyProbe, NULL, false /*warnIfAbsent*/);
104 }
105 
106 void BaseProbe::ioParam_coefficient(enum ParamsIOFlag ioFlag) {
107  assert(!parent->parameters()->presentAndNotBeenRead(name, "energyProbe"));
108  if (energyProbe && energyProbe[0]) {
109  parent->parameters()->ioParamValue(
110  ioFlag, name, "coefficient", &coefficient, coefficient, true /*warnIfAbsent*/);
111  }
112 }
113 
114 void BaseProbe::ioParam_textOutputFlag(enum ParamsIOFlag ioFlag) {
115  parent->parameters()->ioParamValue(
116  ioFlag, name, "textOutputFlag", &textOutputFlag, textOutputFlag);
117 }
118 
119 void BaseProbe::ioParam_probeOutputFile(enum ParamsIOFlag ioFlag) {
120  assert(!parent->parameters()->presentAndNotBeenRead(name, "textOutputFlag"));
121  if (textOutputFlag) {
122  parent->parameters()->ioParamString(
123  ioFlag, name, "probeOutputFile", &probeOutputFilename, NULL, false /*warnIfAbsent*/);
124  }
125 }
126 
127 void BaseProbe::ioParam_triggerLayerName(enum ParamsIOFlag ioFlag) {
128  parent->parameters()->ioParamString(
129  ioFlag, name, "triggerLayerName", &triggerLayerName, NULL, false /*warnIfAbsent*/);
130  if (ioFlag == PARAMS_IO_READ) {
131  triggerFlag = (triggerLayerName != NULL && triggerLayerName[0] != '\0');
132  }
133 }
134 
135 // triggerFlag was deprecated Oct 7, 2015, and marked obsolete Jun 9, 2017.
136 // Setting triggerLayerName to a nonempty string has the effect of triggerFlag=true, and
137 // setting triggerLayerName to NULL or "" has the effect of triggerFlag=false.
138 // For a reasonable fade-out time, it is an error for triggerFlag to be defined in params.
139 void BaseProbe::ioParam_triggerFlag(enum ParamsIOFlag ioFlag) {
140  assert(!parent->parameters()->presentAndNotBeenRead(name, "triggerLayerName"));
141  if (ioFlag == PARAMS_IO_READ && parent->parameters()->present(name, "triggerFlag")) {
142  bool flagFromParams = false;
143  parent->parameters()->ioParamValue(
144  ioFlag, name, "triggerFlag", &flagFromParams, flagFromParams);
145  if (parent->columnId() == 0) {
146  Fatal(triggerFlagDeprecated);
147  triggerFlagDeprecated.printf(
148  "%s: triggerFlag is obsolete for probes.\n", getDescription_c());
149  triggerFlagDeprecated.printf(
150  " If triggerLayerName is a nonempty string, triggering will be on;\n");
151  triggerFlagDeprecated.printf(
152  " if triggerLayerName is empty or null, triggering will be off.\n");
153  }
154  }
155 }
156 
157 void BaseProbe::ioParam_triggerOffset(enum ParamsIOFlag ioFlag) {
158  assert(!parent->parameters()->presentAndNotBeenRead(name, "triggerFlag"));
159  if (triggerFlag) {
160  parent->parameters()->ioParamValue(
161  ioFlag, name, "triggerOffset", &triggerOffset, triggerOffset);
162  if (triggerOffset < 0) {
163  Fatal().printf(
164  "%s \"%s\" error in rank %d process: TriggerOffset (%f) "
165  "must be positive\n",
166  parent->parameters()->groupKeywordFromName(name),
167  name,
168  parent->columnId(),
169  triggerOffset);
170  }
171  }
172 }
173 
174 void BaseProbe::initOutputStreams(const char *filename, Checkpointer *checkpointer) {
175  MPIBlock const *mpiBlock = checkpointer->getMPIBlock();
176  int blockColumnIndex = mpiBlock->getColumnIndex();
177  int blockRowIndex = mpiBlock->getRowIndex();
178  if (blockColumnIndex == 0 and blockRowIndex == 0) {
179  int localBatchWidth = parent->getNBatch();
180  int mpiBatchIndex = mpiBlock->getStartBatch() + mpiBlock->getBatchIndex();
181  int localBatchOffset = localBatchWidth * mpiBatchIndex;
182  mOutputStreams.resize(localBatchWidth);
183  char const *probeOutputFilename = getProbeOutputFilename();
184  if (probeOutputFilename) {
185  std::string path(probeOutputFilename);
186  auto extensionStart = path.rfind('.');
187  std::string extension;
188  if (extensionStart != std::string::npos) {
189  extension = path.substr(extensionStart);
190  path = path.substr(0, extensionStart);
191  }
192  std::ios_base::openmode mode = std::ios_base::out;
193  if (!checkpointer->getCheckpointReadDirectory().empty()) {
194  mode |= std::ios_base::app;
195  }
196  for (int b = 0; b < localBatchWidth; b++) {
197  int globalBatchIndex = b + localBatchOffset;
198  std::string batchPath = path;
199  std::string batchIndexString = std::to_string(globalBatchIndex);
200  batchPath.append("_batchElement_").append(batchIndexString).append(extension);
201  if (batchPath[0] != '/') {
202  batchPath = checkpointer->makeOutputPathFilename(batchPath);
203  }
204  auto fs = new FileStream(batchPath.c_str(), mode, checkpointer->doesVerifyWrites());
205  mOutputStreams[b] = fs;
206  }
207  }
208  else {
209  for (int b = 0; b < localBatchWidth; b++) {
210  mOutputStreams[b] = new PrintStream(PV::getOutputStream());
211  }
212  }
213  }
214  else {
215  mOutputStreams.clear();
216  }
217 }
218 
219 void BaseProbe::initNumValues() { setNumValues(parent->getNBatch()); }
220 
222  if (n > 0) {
223  double *newValuesBuffer = (double *)realloc(probeValues, (size_t)n * sizeof(*probeValues));
224  FatalIf(
225  newValuesBuffer == nullptr,
226  "%s unable to set number of values to %d\n",
227  getDescription_c(),
228  n);
229  // realloc() succeeded
230  probeValues = newValuesBuffer;
231  numValues = n;
232  }
233  else {
234  free(probeValues);
235  probeValues = nullptr;
236  }
237 }
238 
239 Response::Status
240 BaseProbe::communicateInitInfo(std::shared_ptr<CommunicateInitInfoMessage const> message) {
241  // Set up triggering.
242  if (triggerFlag) {
243  triggerLayer = message->lookup<HyPerLayer>(std::string(triggerLayerName));
244  if (triggerLayer == NULL) {
245  if (parent->columnId() == 0) {
246  ErrorLog().printf(
247  "%s \"%s\": triggerLayer \"%s\" is not a layer in the HyPerCol.\n",
248  parent->parameters()->groupKeywordFromName(name),
249  name,
250  triggerLayerName);
251  }
252  MPI_Barrier(parent->getCommunicator()->communicator());
253  exit(EXIT_FAILURE);
254  }
255  }
256 
257  // Add the probe to the ColumnEnergyProbe, if there is one.
258  if (energyProbe && energyProbe[0]) {
259  ColumnEnergyProbe *probe = message->lookup<ColumnEnergyProbe>(std::string(energyProbe));
260  if (probe == NULL) {
261  if (parent->columnId() == 0) {
262  ErrorLog().printf(
263  "%s \"%s\": energyProbe \"%s\" is not a ColumnEnergyProbe in the "
264  "column.\n",
265  parent->parameters()->groupKeywordFromName(getName()),
266  getName(),
267  energyProbe);
268  }
269  MPI_Barrier(parent->getCommunicator()->communicator());
270  exit(EXIT_FAILURE);
271  }
272  int termAdded = probe->addTerm(this);
273  FatalIf(
274  termAdded != PV_SUCCESS,
275  "Failed to add %s to %s.\n",
276  getDescription_c(),
277  probe->getDescription_c());
278  }
279  return Response::SUCCESS;
280 }
281 
282 int BaseProbe::initMessage(const char *msg) {
283  assert(msgstring == NULL);
284  int status = PV_SUCCESS;
285  if (msg != NULL && msg[0] != '\0') {
286  size_t msglen = strlen(msg);
287  this->msgstring = (char *)calloc(
288  msglen + 2,
289  sizeof(char)); // Allocate room for colon plus null terminator
290  if (this->msgstring) {
291  memcpy(this->msgstring, msg, msglen);
292  this->msgstring[msglen] = ':';
293  this->msgstring[msglen + 1] = '\0';
294  }
295  }
296  else {
297  this->msgstring = (char *)calloc(1, sizeof(char));
298  if (this->msgstring) {
299  this->msgstring[0] = '\0';
300  }
301  }
302  if (!this->msgstring) {
303  ErrorLog().printf(
304  "%s \"%s\": Unable to allocate memory for probe's message.\n",
305  parent->parameters()->groupKeywordFromName(name),
306  name);
307  status = PV_FAILURE;
308  }
309  assert(status == PV_SUCCESS);
310  return status;
311 }
312 
313 bool BaseProbe::needUpdate(double simTime, double dt) {
314  if (triggerFlag) {
315  return triggerLayer->needUpdate(simTime + triggerOffset, dt);
316  }
317  return true;
318 }
319 
320 Response::Status BaseProbe::registerData(Checkpointer *checkpointer) {
321  auto status = BaseObject::registerData(checkpointer);
322  if (!Response::completed(status)) {
323  return status;
324  }
325  initOutputStreams(probeOutputFilename, checkpointer);
326  return Response::SUCCESS;
327 }
328 
329 void BaseProbe::getValues(double timevalue) {
330  if (needRecalc(timevalue)) {
331  calcValues(timevalue);
332  lastUpdateTime = referenceUpdateTime();
333  }
334 }
335 
336 void BaseProbe::getValues(double timevalue, double *values) {
337  getValues(timevalue);
338  memcpy(values, probeValues, sizeof(*probeValues) * (size_t)getNumValues());
339 }
340 
341 void BaseProbe::getValues(double timevalue, std::vector<double> *valuesVector) {
342  valuesVector->resize(this->getNumValues());
343  getValues(timevalue, &valuesVector->front());
344 }
345 
346 double BaseProbe::getValue(double timevalue, int index) {
347  if (index < 0 || index >= getNumValues()) {
348  return std::numeric_limits<double>::signaling_NaN();
349  }
350  else {
351  if (needRecalc(timevalue)) {
352  getValues(timevalue);
353  }
354  }
355  return probeValues[index];
356 }
357 
358 Response::Status BaseProbe::outputStateWrapper(double timef, double dt) {
359  auto status = Response::NO_ACTION;
360  if (textOutputFlag && needUpdate(timef, dt)) {
361  status = outputState(timef);
362  }
363  return status;
364 }
365 
366 } // namespace PV
virtual void ioParam_coefficient(enum ParamsIOFlag ioFlag)
coefficient: If energyProbe is set, the coefficient parameter specifies that ColumnEnergyProbe multip...
Definition: BaseProbe.cpp:106
double getValue(double timevalue, int index)
Definition: BaseProbe.cpp:346
virtual void calcValues(double timevalue)=0
int present(const char *groupName, const char *paramName)
Definition: PVParams.cpp:1254
void setNumValues(int n)
Definition: BaseProbe.cpp:221
int addTerm(BaseProbe *probe)
Adds a probe to the energy calculation.
virtual int ioParamsFillGroup(enum ParamsIOFlag ioFlag) override
Definition: BaseProbe.cpp:76
char const * getProbeOutputFilename()
Definition: BaseProbe.hpp:314
virtual void ioParam_message(enum ParamsIOFlag ioFlag)
message: A string parameter that is typically included in the lines output by the outputState method ...
Definition: BaseProbe.cpp:93
virtual double referenceUpdateTime() const =0
virtual Response::Status outputState(double timef)=0
virtual void ioParam_energyProbe(enum ParamsIOFlag ioFlag)
energyProbe: If nonblank, specifies the name of a ColumnEnergyProbe that this probe contributes an en...
Definition: BaseProbe.cpp:101
static bool completed(Status &a)
Definition: Response.hpp:49
virtual void ioParam_triggerFlag(enum ParamsIOFlag ioFlag)
triggerFlag: If false, the needUpdate method always returns true, so that outputState is called every...
Definition: BaseProbe.cpp:139
virtual void initNumValues()
Definition: BaseProbe.cpp:219
virtual bool needRecalc(double timevalue)=0
int getColumnIndex() const
Definition: MPIBlock.hpp:166
virtual void ioParam_triggerOffset(enum ParamsIOFlag ioFlag)
triggerOffset: If triggerFlag is true, triggerOffset specifies the time interval before the triggerLa...
Definition: BaseProbe.cpp:157
virtual void initOutputStreams(const char *filename, Checkpointer *checkpointer)
Definition: BaseProbe.cpp:174
virtual bool needUpdate(double simTime, double dt)
virtual bool needUpdate(double time, double dt)
Definition: BaseProbe.cpp:313
char const * lookupKeyword() const
Definition: BaseObject.cpp:42
virtual void ioParam_textOutputFlag(enum ParamsIOFlag ioFlag)
textOutputFlag: A boolean parameter that sets whether to generate an output file. Defaults to true...
Definition: BaseProbe.cpp:114
virtual Response::Status registerData(Checkpointer *checkpointer) override
Definition: BaseProbe.cpp:320
virtual Response::Status outputStateWrapper(double timef, double dt)
Definition: BaseProbe.cpp:358
void getValues(double timevalue, double *valuesVector)
Definition: BaseProbe.cpp:336
virtual void ioParam_probeOutputFile(enum ParamsIOFlag ioFlag)
probeOutputFile: If textOutputFlag is true, probeOutputFile specifies the name of the file that the o...
Definition: BaseProbe.cpp:119
int getBatchIndex() const
Definition: MPIBlock.hpp:171
int getStartBatch() const
Definition: MPIBlock.hpp:156
virtual void ioParam_triggerLayerName(enum ParamsIOFlag ioFlag)
triggerLayerName: If triggerFlag is true, triggerLayerName specifies the layer to check for triggerin...
Definition: BaseProbe.cpp:127
int getRowIndex() const
Definition: MPIBlock.hpp:161
virtual void ioParam_targetName(enum ParamsIOFlag ioFlag)
targetName: the name of the object that the probe attaches to. In LayerProbe, targetName is used to d...
Definition: BaseProbe.cpp:89
int getNumValues()
Definition: BaseProbe.hpp:61
void readParams()
Definition: BaseObject.hpp:62
int initialize(const char *name, HyPerCol *hc)
Definition: BaseProbe.cpp:64
virtual Response::Status communicateInitInfo(std::shared_ptr< CommunicateInitInfoMessage const > message) override=0
Definition: BaseProbe.cpp:240
std::string makeOutputPathFilename(std::string const &path)
virtual int initMessage(const char *msg)
Definition: BaseProbe.cpp:282