int dumpweights(HyPerCol * hc, int argc, char * argv[]) {
   int status = PV_SUCCESS;
   bool existsgenconn = false;
   for( int k=0; k < hc->numberOfConnections(); k++ ) {
      HyPerConn * conn = dynamic_cast<HyPerConn *>(hc->getConnection(k));
      //Only test plastic conns
      if( conn != NULL) {
         if(conn->getPlasticityFlag()){
            existsgenconn = true;
            int status1 = dumponeweight(conn);
            if( status == PV_SUCCESS ) status = status1;
         }
      }
   }
   if( existsgenconn && status != PV_SUCCESS ) {
      for( int k=0; k<72; k++ ) { pvInfo().printf("="); }
      pvInfo().printf("\n");
   }
   int rank = hc->icCommunicator()->commRank();
   char * paramsfilename;
   pv_getopt_str(argc, argv, "-p", &paramsfilename, NULL/*paramusage*/);
   if( status != PV_SUCCESS ) {
      pvErrorNoExit().printf("Rank %d: %s failed with return code %d.\n", rank, paramsfilename, status);
   }
   else {
      pvInfo().printf("Rank %d: %s succeeded.\n", rank, paramsfilename);
   }
   free(paramsfilename);
   return status;
}
int NormalizeScale::normalizeWeights() {
   int status = PV_SUCCESS;

   assert(numConnections >= 1);

   // All connections in the group must have the same values of sharedWeights, numArbors, and numDataPatches
   HyPerConn * conn0 = connectionList[0];

#ifdef USE_SHMGET
#ifdef PV_USE_MPI
   if (conn->getShmgetFlag() && !callingConn->getShmgetOwner(0)) { // Assumes that all arbors are owned by the same process
      MPI_Barrier(conn->getParent()->icCommunicator()->communicator());
      return status;
   }
#endif // PV_USE_MPI
#endif // USE_SHMGET

   float scale_factor = strength;

   status = NormalizeMultiply::normalizeWeights(); // applies normalize_cutoff threshold and symmetrizeWeights

   int nxp = conn0->xPatchSize();
   int nyp = conn0->yPatchSize();
   int nfp = conn0->fPatchSize();
   int nxpShrunken = conn0->getNxpShrunken();
   int nypShrunken = conn0->getNypShrunken();
   int offsetShrunken = conn0->getOffsetShrunken();
   int xPatchStride = conn0->xPatchStride();
   int yPatchStride = conn0->yPatchStride();
   int weights_per_patch = nxp*nyp*nfp;
   int nArbors = conn0->numberOfAxonalArborLists();
   int numDataPatches = conn0->getNumDataPatches();

   for (int patchindex = 0; patchindex<numDataPatches; patchindex++) {
      for (int arborID = 0; arborID<nArbors; arborID++) {
         for (int c=0; c<numConnections; c++) {
            HyPerConn * conn = connectionList[c];
            pvwdata_t * dataStartPatch = conn->get_wDataStart(arborID)+patchindex*weights_per_patch;
            normalizePatch(dataStartPatch, weights_per_patch, scale_factor);
         }
      }
   }
#ifdef OBSOLETE // Marked obsolete Dec 9, 2014.
#ifdef USE_SHMGET
#ifdef PV_USE_MPI
   if (conn->getShmgetFlag()) {
      assert(conn->getShmgetOwner(0)); // Assumes that all arbors are owned by the same process
      MPI_Barrier(conn->getParent()->icCommunicator()->communicator());
   }
#endif // PV_USE_MPI
#endif // USE_SHMGET
#endif // OBSOLETE
   return status;
}
int TestConnProbe::outputState(double timed){
   //Grab weights of probe and test for the value of .625/1.5, or .4166666
   HyPerConn* conn = getTargetHyPerConn();
   int numPreExt = conn->preSynapticLayer()->getNumExtended();
   int syw = conn->yPatchStride();                   // stride in patch

   for(int kPre = 0; kPre < numPreExt; kPre++){
      PVPatch * weights = conn->getWeights(kPre, 0);
      int nk  = conn->fPatchSize() * weights->nx;

      pvwdata_t * data = conn->get_wData(0,kPre);
      int ny  = weights->ny;
      for (int y = 0; y < ny; y++) {
         pvwdata_t * dataYStart = data + y * syw;
         for(int k = 0; k < nk; k++){
            if(fabs(timed - 0) < (parent->getDeltaTime()/2)){
               if(fabs(dataYStart[k] - 1) > .01){
                  std::cout << "dataYStart[k]: " << dataYStart[k] << "\n";
               }
               assert(fabs(dataYStart[k] - 1) <= .01);
            }
            else if(fabs(timed - 1) < (parent->getDeltaTime()/2)){
               if(fabs(dataYStart[k] - 1.375) > .01){
                  std::cout << "dataYStart[k]: " << dataYStart[k] << "\n";
               }
               assert(fabs(dataYStart[k] - 1.375) <= .01);
            }

         }
      }
   }
   return PV_SUCCESS;

}
int MomentumTestConnProbe::outputState(double timed){
   //Grab weights of probe and test for the value of .625/1.5, or .4166666
   HyPerConn* conn = getTargetHyPerConn();
   int numPreExt = conn->preSynapticLayer()->getNumExtended();
   int syw = conn->yPatchStride();                   // stride in patch

   for(int kPre = 0; kPre < numPreExt; kPre++){
      PVPatch * weights = conn->getWeights(kPre, 0);
      int nk  = conn->fPatchSize() * weights->nx;

      pvwdata_t * data = conn->get_wData(0,kPre);
      int ny  = weights->ny;
      pvdata_t wCorrect;
      for (int y = 0; y < ny; y++) {
         pvwdata_t * dataYStart = data + y * syw;
         for(int k = 0; k < nk; k++){
            pvdata_t wObserved = dataYStart[k];
            if(timed < 3){
               wCorrect = 0;
            }
            else{
               wCorrect = .376471;
               for(int i = 0; i < (timed-3); i++){
                  wCorrect += .376471 * exp(-(2*(i+1)));
               }
            }
            assert(fabs(wObserved - wCorrect) <= 1e-4);
         }
      }
   }
   return PV_SUCCESS;

}
/**
 * @timef
 */
int PlasticConnTestProbe::outputState(double timed) {
   HyPerConn * c = getTargetHyPerConn();
   InterColComm * icComm = c->getParent()->icCommunicator();
   const int rcvProc = 0;
   if( icComm->commRank() != rcvProc ) {
      return PV_SUCCESS;
   }
   assert(getTargetConn()!=NULL);
   outputStream->printf("    Time %f, connection \"%s\":\n", timed, getTargetName());
   const pvwdata_t * w = c->get_wDataHead(getArbor(), getKernelIndex());
   const pvdata_t * dw = c->get_dwDataHead(getArbor(), getKernelIndex());
   if( getOutputPlasticIncr() && dw == NULL ) {
      pvError().printf("PlasticConnTestProbe \"%s\": connection \"%s\" has dKernelData(%d,%d) set to null.\n", getName(), getTargetName(), getKernelIndex(), getArbor());
   }
   int nxp = c->xPatchSize();
   int nyp = c->yPatchSize();
   int nfp = c->fPatchSize();
   int status = PV_SUCCESS;
   for( int k=0; k<nxp*nyp*nfp; k++ ) {
      int x=kxPos(k,nxp,nyp,nfp);
      int wx = (nxp-1)/2 - x; // assumes connection is one-to-one
      if(getOutputWeights()) {
         pvdata_t wCorrect = timed*wx;
         pvdata_t wObserved = w[k];
         if( fabs( ((double) (wObserved - wCorrect))/timed ) > 1e-4 ) {
            int y=kyPos(k,nxp,nyp,nfp);
            int f=featureIndex(k,nxp,nyp,nfp);
            outputStream->printf("        index %d (x=%d, y=%d, f=%d: w = %f, should be %f\n", k, x, y, f, wObserved, wCorrect);
         }
      }
      if(timed > 0 && getOutputPlasticIncr() && dw != NULL) {
         pvdata_t dwCorrect = wx;
         pvdata_t dwObserved = dw[k];
         if( dwObserved != dwCorrect ) {
            int y=kyPos(k,nxp,nyp,nfp);
            int f=featureIndex(k,nxp,nyp,nfp);
            outputStream->printf("        index %d (x=%d, y=%d, f=%d: dw = %f, should be %f\n", k, x, y, f, dwObserved, dwCorrect);
         }
      }
   }
   assert(status==PV_SUCCESS);
   if( status == PV_SUCCESS ) {
      if (getOutputWeights())     { outputStream->printf("        All weights are correct.\n"); }
      if (getOutputPlasticIncr()) { outputStream->printf("        All plastic increments are correct.\n"); }
   }
   if(getOutputPatchIndices()) {
      patchIndices(c);
   }

   return PV_SUCCESS;
}
/**
 * @timef
 */
int MomentumConnTestProbe::outputState(double timed) {
   HyPerConn * c = getTargetHyPerConn();
   InterColComm * icComm = c->getParent()->icCommunicator();
   const int rcvProc = 0;
   if( icComm->commRank() != rcvProc ) {
      return PV_SUCCESS;
   }
   assert(getTargetConn()!=NULL);
   FILE * fp = getStream()->fp;
   fprintf(fp, "    Time %f, connection \"%s\":\n", timed, getTargetName());
   const pvwdata_t * w = c->get_wDataHead(getArbor(), getKernelIndex());
   const pvdata_t * dw = c->get_dwDataHead(getArbor(), getKernelIndex());
   if( getOutputPlasticIncr() && dw == NULL ) {
      fprintf(stderr, "MomentumConnTestProbe \"%s\": connection \"%s\" has dKernelData(%d,%d) set to null.\n", getName(), getTargetName(), getKernelIndex(), getArbor());
      assert(false);
   }
   int nxp = c->xPatchSize();
   int nyp = c->yPatchSize();
   int nfp = c->fPatchSize();
   int status = PV_SUCCESS;
   for( int k=0; k<nxp*nyp*nfp; k++ ) {
      pvdata_t wObserved = w[k];
      //Pulse happens at time 3
      pvdata_t wCorrect;

      if(timed < 3){
         wCorrect = 0;
      }
      else{
         if(isViscosity){
            wCorrect = 1;
            for(int i = 0; i < (timed - 3); i++){
               wCorrect += exp(-(2*(i+1)));
            }
         }
         else{
            wCorrect = 2 - pow(2, -(timed - 3));
         }
      }

      if( fabs( ((double) (wObserved - wCorrect))/timed ) > 1e-4 ) {
         int y=kyPos(k,nxp,nyp,nfp);
         int f=featureIndex(k,nxp,nyp,nfp);
         fprintf(fp, "        w = %f, should be %f\n", wObserved, wCorrect);
         exit(-1);
      }
   }

   return PV_SUCCESS;
}
int main(int argc, char* argv[])
{
   int status = 0;

   PV_Init* initObj = new PV_Init(&argc, &argv);
   initObj->initialize(argc, argv);

   // create the managing hypercolumn
   //
   HyPerCol* hc = new HyPerCol("test_constant_input column", argc, argv, initObj);

   // create the image
   //
   TestImage * image = new TestImage("test_constant_input image", hc);

   // create the layers
   //
   HyPerLayer * retina = new Retina("test_constant_input retina", hc);

   // create the connections
   //
   HyPerConn * conn = new HyPerConn("test_constant_input connection", hc);
   const int nxp = conn->xPatchSize();
   const int nyp = conn->yPatchSize();
   const PVLayerLoc * imageLoc = image->getLayerLoc();
   const PVLayerLoc * retinaLoc = image->getLayerLoc();
   const int nfPre = imageLoc->nf;
    
   float sumOfWeights = (float) (nxp*nyp*nfPre);
   if (imageLoc->nx > retinaLoc->nx) { sumOfWeights *= imageLoc->nx/retinaLoc->nx;}
   if (imageLoc->ny > retinaLoc->ny) { sumOfWeights *= imageLoc->ny/retinaLoc->ny;}
   
   hc->run();

   const int rank = hc->columnId();
#ifdef DEBUG_OUTPUT
   printf("[%d]: column: ", rank);
   printLoc(hc->getImageLoc());
   printf("[%d]: image : ", rank);
   printLoc(image->getImageLoc());
   printf("[%d]: retina: ", rank);
   printLoc(*retina->getLayerLoc());
   printf("[%d]: l1    : ", rank);
   printLoc(*l1->getLayerLoc());
#endif

   status = checkLoc(hc, image->getLayerLoc());
   if (status != PV_SUCCESS) {
      fprintf(stderr, "[%d]: test_constant_input: ERROR in image loc\n", rank);
      exit(status);
   }

   status = checkLoc(hc, retina->getLayerLoc());
   if (status != PV_SUCCESS) {
      fprintf(stderr, "[%d]: test_constant_input: ERROR in retina loc\n", rank);
      exit(status);
   }

   status = checkInput(image->getLayerLoc(), image->getActivity(), image->getConstantVal(), true);
   if (status != PV_SUCCESS) {
      fprintf(stderr, "[%d]: test_constant_input: ERROR in image data\n", rank);
      exit(status);
   }

   float retinaVal = sumOfWeights * image->getConstantVal();

   status = checkInput(retina->getLayerLoc(), retina->getActivity(), retinaVal, false);
   if (status != 0) {
      fprintf(stderr, "[%d]: test_constant_input: ERROR in retina data\n", rank);
      exit(status);
   }

   status = checkInput(retina->getLayerLoc(), retina->getLayerData(), retinaVal, true);
   if (status != 0) {
      fprintf(stderr, "[%d]: test_constant_input: ERROR in retina data\n", rank);
      exit(status);
   }

   delete hc;
   delete initObj;

   return status;
}
int main(int argc, char * argv[])
{
   PV_Init* initObj = new PV_Init(&argc, &argv, false/*allowUnrecognizedArguments*/);
   PV_Arguments * arguments = initObj->getArguments();
   if (arguments->getParamsFile()==NULL) {
      int rank = 0;
      MPI_Comm_rank(MPI_COMM_WORLD, &rank);
      if (rank==0) {
         fprintf(stderr, "%s does not take a -p argument; the necessary param file is hardcoded.\n", argv[0]);
      }
      MPI_Barrier(MPI_COMM_WORLD);
      exit(EXIT_FAILURE);
   }

   arguments->setParamsFile("input/test_gauss2d.params");
   const char * pre_layer_name = "test_gauss2d pre";
   const char * post_layer_name = "test_gauss2d post";
   const char * pre2_layer_name = "test_gauss2d pre 2";
   const char * post2_layer_name = "test_gauss2d post 2";

   initObj->initialize();
   PV::HyPerCol * hc = new PV::HyPerCol("test_gauss2d column", initObj);
   PV::Example * pre = new PV::Example(pre_layer_name, hc);
   assert(pre);
   PV::Example * post = new PV::Example(post_layer_name, hc);
   assert(post);

   
   PV::HyPerConn * cHyPer = new HyPerConn("test_gauss2d hyperconn", hc);

   PV::HyPerConn * cKernel = new HyPerConn("test_gauss2d kernelconn", hc);

   PV::Example * pre2 = new PV::Example(pre2_layer_name, hc);
   assert(pre2);
   PV::Example * post2 = new PV::Example(post2_layer_name, hc);
   assert(post2);

   PV::HyPerConn * cHyPer1to2 =
         new HyPerConn("test_gauss2d hyperconn 1 to 2", hc);
   assert(cHyPer1to2);

   PV::HyPerConn * cKernel1to2 =
         new HyPerConn("test_gauss2d kernelconn 1 to 2", hc);
   assert(cKernel1to2);

   PV::HyPerConn * cHyPer2to1 =
         new HyPerConn("test_gauss2d hyperconn 2 to 1", hc);
   assert(cHyPer2to1);

   PV::HyPerConn * cKernel2to1 =
         new HyPerConn("test_gauss2d kernelconn 2 to 1", hc);
   assert(cKernel2to1);
   
   int status = 0;

   for (int l=0; l<hc->numberOfLayers(); l++) {
      status = hc->getLayer(l)->communicateInitInfo();
      assert(status==PV_SUCCESS);
   }
   for (int c=0; c<hc->numberOfConnections(); c++) {
      status = hc->getConnection(c)->communicateInitInfo();
      assert(status==PV_SUCCESS);
   }
   for (int l=0; l<hc->numberOfLayers(); l++) {
      status = hc->getLayer(l)->allocateDataStructures();
      assert(status==PV_SUCCESS);
   }
   for( int c=0; c<hc->numberOfConnections(); c++ ) {
      BaseConnection * baseConn = hc->getConnection(c);
      HyPerConn * conn = dynamic_cast<HyPerConn *>(baseConn);
      conn->allocateDataStructures();
      conn->writeWeights(0, true);
   }

   const int axonID = 0;
   int num_pre_extended = pre->clayer->numExtended;
   assert(num_pre_extended == cHyPer->getNumWeightPatches());

   for (int kPre = 0; kPre < num_pre_extended; kPre++) {
     //printf("testing testing 1 2 3...\n");
     status = check_kernel_vs_hyper(cHyPer, cKernel, kPre, axonID);
     assert(status==0);
     status = check_kernel_vs_hyper(cHyPer1to2, cKernel1to2, kPre, axonID);
     assert(status==0);
     status = check_kernel_vs_hyper(cHyPer2to1, cKernel2to1, kPre, axonID);
     assert(status==0);
   }

   delete hc;
   delete initObj;
   return 0;
}
int NormalizeContrastZeroMean::normalizeWeights() {
   int status = PV_SUCCESS;

   assert(numConnections >= 1);

   // TODO: need to ensure that all connections in connectionList have same nxp,nyp,nfp,numArbors,numDataPatches
   HyPerConn * conn0 = connectionList[0];
   for (int c=1; c<numConnections; c++) {
      HyPerConn * conn = connectionList[c];
      if (conn->numberOfAxonalArborLists() != conn0->numberOfAxonalArborLists()) {
         if (parent->columnId() == 0) {
            pvErrorNoExit().printf("Normalizer %s: All connections in the normalization group must have the same number of arbors (Connection \"%s\" has %d; connection \"%s\" has %d).\n",
                  this->getName(), conn0->getName(), conn0->numberOfAxonalArborLists(), conn->getName(), conn->numberOfAxonalArborLists());
         }
         status = PV_FAILURE;
      }
      if (conn->getNumDataPatches() != conn0->getNumDataPatches()) {
         if (parent->columnId() == 0) {
            pvErrorNoExit().printf("Normalizer %s: All connections in the normalization group must have the same number of data patches (Connection \"%s\" has %d; connection \"%s\" has %d).\n",
                  this->getName(), conn0->getName(), conn0->getNumDataPatches(), conn->getName(), conn->getNumDataPatches());
         }
         status = PV_FAILURE;
      }
      if (status==PV_FAILURE) {
         MPI_Barrier(parent->icCommunicator()->communicator());
         exit(EXIT_FAILURE);
      }
   }

   float scale_factor = strength;

   status = NormalizeBase::normalizeWeights(); // applies normalize_cutoff threshold and symmetrizeWeights

   int nArbors = conn0->numberOfAxonalArborLists();
   int numDataPatches = conn0->getNumDataPatches();
   if (normalizeArborsIndividually) {
      for (int arborID = 0; arborID<nArbors; arborID++) {
         for (int patchindex = 0; patchindex<numDataPatches; patchindex++) {
            double sum = 0.0;
            double sumsq = 0.0;
            int weights_per_patch = 0;
            for (int c=0; c<numConnections; c++) {
               HyPerConn * conn = connectionList[c];
               int nxp = conn0->xPatchSize();
               int nyp = conn0->yPatchSize();
               int nfp = conn0->fPatchSize();
               weights_per_patch += nxp*nyp*nfp;
               pvwdata_t * dataStartPatch = conn->get_wDataStart(arborID) + patchindex * weights_per_patch;
               accumulateSumAndSumSquared(dataStartPatch, weights_per_patch, &sum, &sumsq);
            }
            if (fabs(sum) <= minSumTolerated) {
               pvWarn().printf("for NormalizeContrastZeroMean \"%s\": sum of weights in patch %d of arbor %d is within minSumTolerated=%f of zero. Weights in this patch unchanged.\n", this->getName(), patchindex, arborID, minSumTolerated);
               break; // TODO: continue instead of break?  continue as opposed to break is more consistent with warning above.
            }
            float mean = sum/weights_per_patch;
            float var = sumsq/weights_per_patch - mean*mean;
            for (int c=0; c<numConnections; c++) {
               HyPerConn * conn = connectionList[c];
               pvwdata_t * dataStartPatch = conn->get_wDataStart(arborID) + patchindex * weights_per_patch;
               subtractOffsetAndNormalize(dataStartPatch, weights_per_patch, sum/weights_per_patch, sqrt(var)/scale_factor);
            }
         }
      }
   }
   else {
      for (int patchindex = 0; patchindex<numDataPatches; patchindex++) {
         double sum = 0.0;
         double sumsq = 0.0;
         int weights_per_patch = 0;
         for (int arborID = 0; arborID<nArbors; arborID++) {
            for (int c=0; c<numConnections; c++) {
               HyPerConn * conn = connectionList[c];
               int nxp = conn0->xPatchSize();
               int nyp = conn0->yPatchSize();
               int nfp = conn0->fPatchSize();
               weights_per_patch += nxp*nyp*nfp;
               pvwdata_t * dataStartPatch = conn->get_wDataStart(arborID)+patchindex*weights_per_patch;
               accumulateSumAndSumSquared(dataStartPatch, weights_per_patch, &sum, &sumsq);
            }
         }
         if (fabs(sum) <= minSumTolerated) {
            pvWarn().printf("for NormalizeContrastZeroMean \"%s\": sum of weights in patch %d is within minSumTolerated=%f of zero. Weights in this patch unchanged.\n", getName(), patchindex, minSumTolerated);
            break; // TODO: continue instead of break?  continue as opposed to break is more consistent with warning above.

         }
         int count = weights_per_patch*nArbors;
         float mean = sum/count;
         float var = sumsq/count - mean*mean;
         for (int arborID = 0; arborID<nArbors; arborID++) {
            for (int c=0; c<numConnections; c++) {
               HyPerConn * conn = connectionList[c];
               pvwdata_t * dataStartPatch = conn->get_wDataStart(arborID)+patchindex*weights_per_patch;
               subtractOffsetAndNormalize(dataStartPatch, weights_per_patch, mean, sqrt(var)/scale_factor);
            }
         }
      }
   }

   return status;
}
Exemple #10
0
int customexit(HyPerCol * hc, int argc, char ** argv) {
   BaseConnection * baseConn;
   baseConn = hc->getConnFromName("initializeFromInitWeights");
   HyPerConn * initializeFromInitWeightsConn = dynamic_cast<HyPerConn *>(baseConn);
   // There must be a connection named initializeFromInitWeights. It should have a single weight with value 1
   assert(initializeFromInitWeightsConn);
   assert(initializeFromInitWeightsConn->xPatchSize()==1);
   assert(initializeFromInitWeightsConn->yPatchSize()==1);
   assert(initializeFromInitWeightsConn->fPatchSize()==1);
   assert(initializeFromInitWeightsConn->numberOfAxonalArborLists()==1);
   assert(initializeFromInitWeightsConn->get_wData(0,0)[0] == 1.0f);

   // There must be a connection named initializeFromCheckpoint.  It should have a single weight with value 2
   baseConn = hc->getConnFromName("initializeFromCheckpoint");
   HyPerConn * initializeFromCheckpointConn = dynamic_cast<HyPerConn *>(baseConn);
   assert(initializeFromCheckpointConn);
   assert(initializeFromCheckpointConn->xPatchSize()==1);
   assert(initializeFromCheckpointConn->yPatchSize()==1);
   assert(initializeFromCheckpointConn->fPatchSize()==1);
   assert(initializeFromCheckpointConn->numberOfAxonalArborLists()==1);
   assert(initializeFromCheckpointConn->get_wData(0,0)[0] == 2.0f);
   return PV_SUCCESS;
}
/**
 * @timef
 * NOTES:
 *    - kPost, kxPost, kyPost are indices in the restricted post-synaptic layer.
 *
 */
int PostConnProbe::outputState(double timef)
{
   int k, kxPre, kyPre;
   HyPerConn * c = getTargetHyPerConn();
   PVPatch  * w;
   PVPatch *** wPost = c->convertPreSynapticWeights(timef);

   // TODO - WARNING: currently only works if nfPre==0

   const PVLayer * lPre = c->preSynapticLayer()->clayer;
   const PVLayer * lPost = c->postSynapticLayer()->clayer;

   const int nxPre = lPre->loc.nx;
   const int nyPre = lPre->loc.ny;
   const int nfPre = lPre->loc.nf;
   const PVHalo * haloPre = &lPre->loc.halo;

   const int nxPost = lPost->loc.nx;
   const int nyPost = lPost->loc.ny;
   const int nfPost = lPost->loc.nf;
   const PVHalo * haloPost = &lPost->loc.halo;

   // calc kPost if needed
   if (kPost < 0) {
      kPost = kIndex(kxPost, kyPost, kfPost, nxPost, nyPost, nfPost);
   }
   else {
      kxPost = kxPos(kPost, nxPost, nyPost, nfPost);
      kyPost = kyPos(kPost, nxPost, nyPost, nfPost);
      kfPost = featureIndex(kPost, nxPost, nyPost, nfPost);
   }

   c->preSynapticPatchHead(kxPost, kyPost, kfPost, &kxPre, &kyPre);

   const int kxPreEx = kxPre + haloPre->lt;
   const int kyPreEx = kyPre + haloPre->up;

   const int kxPostEx = kxPost + haloPost->lt;
   const int kyPostEx = kyPost + haloPost->up;
   const int kPostEx = kIndex(kxPostEx, kyPostEx, kfPost, nxPost+haloPost->lt+haloPost->rt, nyPost+haloPost->dn+haloPost->up, nfPost);

   const bool postFired = lPost->activity->data[kPostEx] > 0.0;

   w = wPost[getArborID()][kPost];
   pvwdata_t * wPostData = c->getWPostData(getArborID(),kPost);

   const int nw = w->nx * w->ny * nfPost; //w->nf;

   if (wPrev == NULL) {
      wPrev = (pvwdata_t *) calloc(nw, sizeof(pvwdata_t));
      for (k = 0; k < nw; k++) {
         wPrev[k] = wPostData[k]; // This is broken if the patch is shrunken
      }
   }
   if (wActiv == NULL) {
      wActiv = (pvwdata_t *) calloc(nw, sizeof(pvwdata_t));
   }

   k = 0;
   for (int ky = 0; ky < w->ny; ky++) {
      for (int kx = 0; kx < w->nx; kx++) {
         int kPre = kIndex(kx+kxPreEx, ky+kyPreEx, 0, nxPre+haloPre->lt+haloPre->rt, nyPre+haloPre->dn+haloPre->up, nfPre);
         wActiv[k++] = lPre->activity->data[kPre];
      }
   }

   bool changed = false;
   for (k = 0; k < nw; k++) {
      if (wPrev[k] != wPostData[k] || wActiv[k] != 0.0) {
         changed = true;
         break;
      }
   }
   FILE * fp = getStream()->fp;
   if (stdpVars && (postFired || changed)) {
      if (postFired) fprintf(fp, "*");
      else fprintf(fp, " ");
      fprintf(fp, "t=%.1f w%d(%d,%d,%d) prePatchHead(%d,%d): ", timef, kPost, kxPost,
            kyPost, kfPost, kxPre, kyPre);
      if (image) fprintf(fp, "tag==%d ", image->tag());
      fprintf(fp, "\n");
   }
   if (stdpVars && changed) {
      text_write_patch_extra(fp, w, wPostData, wPrev, wActiv, getTargetHyPerConn());
      fflush(fp);
   }

   for (k = 0; k < nw; k++) {
      wPrev[k] = wPostData[k];
   }

   if (outputIndices) {
      fprintf(fp, "w%d(%d,%d,%d) prePatchHead(%d,%d): ", kPost, kxPost, kyPost, kfPost, kxPre, kyPre);
      if(!stdpVars){
        fprintf(fp,"\n");
      }
      const PVLayer * lPre = c->preSynapticLayer()->clayer;
      write_patch_indices(fp, w, &lPre->loc, kxPre, kyPre, 0);
      fflush(fp);
   }

   return 0;
}