PetaVision  Alpha
WTADelivery.cpp
1 /*
2  * WTADelivery.cpp
3  *
4  * Created on: Aug 15, 2018
5  * Author: Pete Schultz
6  */
7 
8 #include "WTADelivery.hpp"
9 #include "columns/HyPerCol.hpp"
10 #include "utils/MapLookupByType.hpp"
11 #include <cstring>
12 
13 namespace PV {
14 
15 WTADelivery::WTADelivery(char const *name, HyPerCol *hc) { initialize(name, hc); }
16 
17 int WTADelivery::initialize(char const *name, HyPerCol *hc) {
18  return BaseDelivery::initialize(name, hc);
19 }
20 
21 void WTADelivery::setObjectType() { mObjectType = "WTADelivery"; }
22 
23 void WTADelivery::ioParam_receiveGpu(enum ParamsIOFlag ioFlag) {
24  // Never receive from gpu
25  mReceiveGpu = false;
26  if (ioFlag == PARAMS_IO_READ) {
27  parent->parameters()->handleUnnecessaryParameter(name, "receiveGpu", false /*correctValue*/);
28  }
29 }
30 
31 Response::Status
32 WTADelivery::communicateInitInfo(std::shared_ptr<CommunicateInitInfoMessage const> message) {
33  auto status = BaseDelivery::communicateInitInfo(message);
34  if (status != Response::SUCCESS) {
35  return status;
36  }
37 
38  auto *singleArbor = mapLookupByType<SingleArbor>(message->mHierarchy, getDescription());
39  FatalIf(!singleArbor, "%s requires a SingleArbor component.\n", getDescription_c());
40  if (!singleArbor->getInitInfoCommunicatedFlag()) {
41  return Response::POSTPONE;
42  }
43 
45  return Response::SUCCESS;
46 }
47 
49  int status = PV_SUCCESS;
50  pvAssert(mPreLayer and mPostLayer); // Only call this after BaseDelivery::communicateInitInfo().
51  PVLayerLoc const *preLoc = mPreLayer->getLayerLoc();
52  PVLayerLoc const *postLoc = mPostLayer->getLayerLoc();
53  if (preLoc->nx != postLoc->nx) {
54  ErrorLog().printf(
55  "%s requires pre and post nx be equal (%d versus %d).\n",
56  getDescription_c(),
57  preLoc->nx,
58  postLoc->nx);
59  status = PV_FAILURE;
60  }
61  if (preLoc->ny != postLoc->ny) {
62  ErrorLog().printf(
63  "%s requires pre and post ny be equal (%d versus %d).\n",
64  getDescription_c(),
65  preLoc->ny,
66  postLoc->ny);
67  status = PV_FAILURE;
68  }
69  if (postLoc->nf != 1) {
70  ErrorLog().printf(
71  "%s requires post nf be equal to 1 (observed value is %d).\n",
72  getDescription_c(),
73  postLoc->nf);
74  status = PV_FAILURE;
75  }
76  if (preLoc->nbatch != postLoc->nbatch) {
77  ErrorLog().printf(
78  "%s requires pre and post nbatch be equal (%d versus %d).\n",
79  getDescription_c(),
80  preLoc->nbatch,
81  postLoc->nbatch);
82  status = PV_FAILURE;
83  }
84  FatalIf(
85  status != PV_SUCCESS,
86  "WTADelivery \"%s\" Error: %s and %s do not have the same dimensions.\n Dims: "
87  "%dx%dx%d vs. %dx%dx%d\n",
88  name,
89  mPreLayer->getName(),
90  mPostLayer->getName(),
91  preLoc->nx,
92  preLoc->ny,
93  preLoc->nf,
94  postLoc->nx,
95  postLoc->ny,
96  postLoc->nf);
97 }
98 
99 void WTADelivery::deliver() {
100  if (mChannelCode == CHANNEL_NOUPDATE) {
101  return;
102  }
103 
104  PVLayerCube const preActivityCube = mPreLayer->getPublisher()->createCube(mDelay);
105  PVLayerLoc const &preLoc = preActivityCube.loc;
106 
107  int const nx = preLoc.nx;
108  int const ny = preLoc.ny;
109  int const nf = preLoc.nf;
110  PVHalo const &halo = preLoc.halo;
111  int nxPreExtended = nx + halo.lt + halo.rt;
112  int nyPreExtended = ny + halo.dn + halo.up;
113  int numPreExtended = nxPreExtended * nyPreExtended * nf;
114  pvAssert(numPreExtended * preLoc.nbatch == preActivityCube.numItems);
115  int numPostRestricted = nx * ny * nf;
116 
117  float *postChannel = mPostLayer->getChannel(mChannelCode);
118  for (int b = 0; b < parent->getNBatch(); b++) {
119  float const *preActivityBuffer = preActivityCube.data + b * numPreExtended;
120  float *postGSynBuffer = postChannel + b * numPostRestricted;
121  // If preActivityCube.isSparse is true, we could use the list of activeIndices.
122  // However, we have to make sure that two indices that correspond to the same location but
123  // different features are collapsed properly, and that if all the nonzero values at a
124  // location are negative but not all values at the location are nonzero, that the maximum is
125  // zero, not the greatest nonzero value.
126  // For now, at least, use the nonsparse method even if preActivityCube.isSparse is true.
127  int const numLocations = nx * ny;
128 #ifdef PV_USE_OPENMP_THREADS
129 #pragma omp parallel for
130 #endif
131  for (int k = 0; k < numLocations; k++) {
132  int const kPreExtended =
133  kIndexExtended(k, nx, ny, 1, halo.lt, halo.rt, halo.dn, halo.up) * nf;
134  float maxValue = -FLT_MAX;
135  for (int f = 0; f < nf; f++) {
136  float value = preActivityBuffer[kPreExtended + f];
137  maxValue = value > maxValue ? value : maxValue;
138  }
139  postGSynBuffer[k] += maxValue;
140  }
141  }
142 #ifdef PV_USE_CUDA
143  mPostLayer->setUpdatedDeviceGSynFlag(!mReceiveGpu);
144 #endif // PV_USE_CUDA
145 }
146 
147 void WTADelivery::deliverUnitInput(float *recvBuffer) {
148  const int numNeuronsPost = mPostLayer->getNumNeuronsAllBatches();
149 #ifdef PV_USE_OPENMP_THREADS
150 #pragma omp parallel for
151 #endif
152  for (int k = 0; k < numNeuronsPost; k++) {
153  recvBuffer[k] += 1.0f;
154  }
155 }
156 
158  bool isReady;
159  if (getChannelCode() == CHANNEL_NOUPDATE) {
160  isReady = true;
161  }
162  else {
163  isReady = getPreLayer()->isExchangeFinished(mDelay);
164  }
165  return isReady;
166 }
167 
168 } // end namespace PV
PVLayerCube createCube(int delay=0)
Definition: Publisher.cpp:60
bool isExchangeFinished(int delay=0)
virtual bool isAllInputReady() override
virtual void ioParam_receiveGpu(enum ParamsIOFlag ioFlag) override
WTADelivery does not use the GPU. It is an error to set receiveGpu to true.
Definition: WTADelivery.cpp:23
void checkPreAndPostDimensions()
Definition: WTADelivery.cpp:48