New HyPerLayer Buffer - PetaVision/OpenPV GitHub Wiki
The standard HyPerLayer class contains a membrane potential V, and an
activity buffer A. For many purposes this is enough, but you may
have occasion to write a derived class that uses additional buffers.
This page describes the preferred procedure for adding a buffer to a subclass.
The buffer must be declared as a pointer with a type other than void\*.
Throughout, we assume that the buffer is a member variable called newBuffer.
Allocation and deallocation
In the constructor, initialize newBuffer to NULL. If you follow the
guidelines in the Subclassing HyPerLayer page,
set newBuffer to NULL in the initialize_base() method.
Override the allocateDataStructures() method. It should call the parent
class's allocateDataStructures(), and then call the appropriate buffer
allocation method.
allocateBuffer(&newBuffer, size, description)is the most general method. Note that it is thesizeis an integer indicating the number of values in the buffer, anddescriptionis a character array (C-style string) used to provide a descriptive error message if the allocation fails.allocateRestrictedBuffer(&newBuffer, description)is a wrapper to be used when*newBufferis of typepvdata_t(currentlyfloat) and is a restricted buffer. It callsallocateBufferwith a size ofnbatch*nx*ny*nf.allocateExtendedBuffer(&newBuffer, description)is a wrapper to be used when*newBufferis of typepvdata_tand is an extended buffer. It callsallocateBufferwith a size ofnbatch*(nx+halo->lt+halo->rt)*(ny+halo->dn+halo->up)*nf.
To free the buffer, in the destructor call the appropriate buffer deallocation method.
freeBuffer(&newBuffer)is the most general method.freeRestrictedBuffer(&newBuffer)andfreeExtendedBuffer(&newBuffer)are provided to balanceallocateRestrictedBuffer()andallocateExtendedBuffer(). Note, however, that these functions are merely wrappers aroundfreeBuffer(). There are no checks on whether the provided argument was originally created withallocateBuffer()or a related method.
Example:
Code fragments for DerivedClass.hpp:
class DerivedClass : public ParentClass {
...
public
virtual DerivedClass::~DerivedClass();
pvdata_t const * getNewBuffer() const { return newBuffer; }
protected:
virtual int allocateDataStructures();
pvdata_t * newBuffer;
private:
int initialize_base();
...
};
Code fragments for DerivedClass.cpp:
// In DerivedClass.cpp:
int DerivedClass::initialize_base() {
newBuffer = NULL;
}
int DerivedClass::allocateDataStructures() {
int status = ParentClass::allocateDataStructures();
if (status==PV_SUCCESS) {
status = allocateBuffer(&newBuffer, 1024, "the new buffer");
}
return status;
}
DerivedClass::~DerivedClass() {
freeBuffer(&newBuffer);
}
Checkpointing
If the contents of the buffer are necessary for recreating the layer's state, you will need to checkpoint the buffer. Assuming that newBuffer is the size of either a restricted or an extended layer buffer, do the following.
To have the buffer appear in checkpoints, override checkpointWrite(),
calling the parent class's checkpointWrite() method and then call
writeBufferFile() with the address of the buffer.
To have the buffer get read when initializing or restarting from a checkpoint,
override readStateFromCheckpoint(), calling the parent class's
checkpointWrite() method and then call readBufferFile() with the address
of the buffer.
Example:
Code fragments for DerivedClass.hpp:
class DerivedClass : public ParentClass {
...
public
int checkpointWrite(char const * cpDir);
int readStateFromCheckpoint(char const * cpDir, double * timeptr);
...
};
Code fragments for DerivedClass.cpp:
// In DerivedClass.cpp:
int DerivedClass::checkpointWrite(char const * cpDir) {
int status = ParentClass::checkpointWrite(cpDir);
if (status==PV_SUCCESS) {
char * filename = parent->pathInCheckpoint(cpDir, getName(), "_newBuffer.pvp");
double timed = (double) parent->simulationTime();
bool isExtended = /*whether the buffer is extended or not*/;
status = writeBufferFile(
filename, parent->icCommunicator(), timed, &newBuffer,
1/*number of bands; generally one*/,
isExtended, getLayerLoc());
free(filename);
}
return status;
}
int DerivedClass::readStateFromCheckpoint(char const * cpDir, double * timeptr) {
int status = ParentClass::readStateFromCheckpoint(cpDir, timeptr);
if (status==PV_SUCCESS) {
char * filename = parent->pathInCheckpoint(cpDir, getName(), "_newBuffer.pvp");
status = readBufferFile(
filename, parent->icCommunicator(), timeptr, &newBuffer,
1,
/*extended*/false, getLayerLoc());
free(filename);
}
return status;
}
Using the buffer on the GPU
This section is under construction.