Skip to content

New HyPerLayer Buffer

Pete Schultz edited this page Mar 12, 2016 · 1 revision

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 the size is an integer indicating the number of values in the buffer, and description is 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 *newBuffer is of type pvdata_t (currently float) and is a restricted buffer. It calls allocateBuffer with a size of nbatch*nx*ny*nf.
  • allocateExtendedBuffer(&newBuffer, description) is a wrapper to be used when *newBuffer is of type pvdata_t and is an extended buffer. It calls allocateBuffer with a size of nbatch*(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) and freeExtendedBuffer(&newBuffer) are provided to balance allocateRestrictedBuffer() and allocateExtendedBuffer(). Note, however, that these functions are merely wrappers around freeBuffer(). There are no checks on whether the provided argument was originally created with allocateBuffer() 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.