RepastHPC  2.3.1
ValueLayerND.h
1 /*
2  * Repast for High Performance Computing (Repast HPC)
3  *
4  * Copyright (c) 2010 Argonne National Laboratory
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with
8  * or without modification, are permitted provided that the following
9  * conditions are met:
10  *
11  * Redistributions of source code must retain the above copyright notice,
12  * this list of conditions and the following disclaimer.
13  *
14  * Redistributions in binary form must reproduce the above copyright notice,
15  * this list of conditions and the following disclaimer in the documentation
16  * and/or other materials provided with the distribution.
17  *
18  * Neither the name of the Argonne National Laboratory nor the names of its
19  * contributors may be used to endorse or promote products derived from
20  * this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES OR
26  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
32  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  *
35  * ValueLayerND.h
36  *
37  * Created on: July 18, 2016
38  * Author: jtm
39  */
40 
41 #ifndef VALUELAYERND_H_
42 #define VALUELAYERND_H_
43 
44 #include <fstream>
45 
46 #include "mpi.h"
47 
48 #include "Point.h"
49 #include "GridDimensions.h"
50 #include "RepastProcess.h"
51 
52 
53 using namespace std;
54 
55 namespace repast {
56 
65 struct RankDatum{
66  int rank;
67  MPI_Datatype datatype;
68  int sendPtrOffset;
69  int receivePtrOffset;
70  int sendDir; // Integer representing the direction a send will be sent, in N-space
71  int recvDir; // Integer representing the direction a receive will have been sent, in N-space
72 };
73 
81 template<typename T>
83 public:
84 
94  DimensionDatum(int indx, GridDimensions globalBoundaries, GridDimensions localBoundaries, int buffer, bool isPeriodic);
95 
99  virtual ~DimensionDatum(){}
100 
101  int globalCoordinateMin, globalCoordinateMax; // Coordinates of the global simulation boundaries
102  int localBoundariesMin, localBoundariesMax; // Coordinates of the local process boundaries in this layer
103  int simplifiedBoundariesMin, simplifiedBoundariesMax; // Coordinates of the 'simplified' coordinates (assuming local boundary origins and NO wrapping)
104  int leftBufferSize, rightBufferSize; // Buffer size
105  int matchingCoordinateMin, matchingCoordinateMax; // Region within simplified boundaries within which coordinates match Global Simulation Coordinate system
106  bool periodic; // True if the global simulation space is periodic on this dimension
107  bool atLeftBound, atRightBound; // True if the local boundaries abut the global boundaries (whether periodic or not)
108  bool spaceContinuesLeft, spaceContinuesRight; // False if the local boundaries abut the (non-periodic) global boundaries
109  int globalWidth; // Global width of the simulation boundaries in simulation units
110  int localWidth; // Width of the local boundaries
111  int width; // Total width (units = sizeof T) on this dimension (local extents + buffer sizes if not against global nonperiodic bounds)
112  int widthInBytes;
113 
119  int getSendReceiveSize(int relativeLocation);
120 
136  int getTransformedCoord(int originalCoord);
137 
154  int getIndexedCoord(int originalCoord, bool isSimplified = false);
155 
164  bool isInLocalBounds(int originalCoord);
165 
166 
173  void report(int dimensionNumber){
174  std::cout << repast::RepastProcess::instance()->rank() << " " << dimensionNumber << " " <<
175  "global (" << globalCoordinateMin << ", " << globalCoordinateMax << ") " <<
176  "local (" << localBoundariesMin << ", " << localBoundariesMax << ") " <<
177  "simple (" << simplifiedBoundariesMin << ", " << simplifiedBoundariesMax << ") " <<
178  "match (" << matchingCoordinateMin << ", " << matchingCoordinateMax << ") " <<
179  "globalWidth = " << globalWidth << " localWidth = " << localWidth << " width = " << width << " bytes = " << widthInBytes << std::endl;
180  }
181 };
182 
183 template<typename T>
184 DimensionDatum<T>::DimensionDatum(int indx, GridDimensions globalBoundaries, GridDimensions localBoundaries, int buffer, bool isPeriodic):
185  leftBufferSize(buffer), rightBufferSize(buffer), periodic(isPeriodic){
186  globalCoordinateMin = globalBoundaries.origin(indx);
187  globalCoordinateMax = globalBoundaries.origin(indx) + globalBoundaries.extents(indx);
188  localBoundariesMin = localBoundaries.origin(indx);
189  localBoundariesMax = localBoundaries.origin(indx) + localBoundaries.extents(indx);
190 
191  atLeftBound = localBoundariesMin == globalCoordinateMin;
192  atRightBound = localBoundariesMax == globalCoordinateMax;
193 
194  spaceContinuesLeft = !atLeftBound || periodic;
195  spaceContinuesRight = !atRightBound || periodic;
196 
197  simplifiedBoundariesMin = localBoundariesMin - leftBufferSize;
198  simplifiedBoundariesMax = localBoundariesMax + rightBufferSize;
199 
200  matchingCoordinateMin = localBoundariesMin;
201  if(spaceContinuesLeft && !atLeftBound ) matchingCoordinateMin -= leftBufferSize;
202 
203  matchingCoordinateMax = localBoundariesMax;
204  if(spaceContinuesRight && !atRightBound) matchingCoordinateMax += rightBufferSize;
205 
206  globalWidth = globalCoordinateMax - globalCoordinateMin;
207  localWidth = localBoundariesMax - localBoundariesMin;
208  width = leftBufferSize + localWidth + rightBufferSize;
209  widthInBytes = width * (sizeof(T));
210 }
211 
212 
213 template<typename T>
214 int DimensionDatum<T>::getSendReceiveSize(int relativeLocation){
215  switch(relativeLocation){
216  case -1: return leftBufferSize;
217  case 1: return rightBufferSize;
218  case 0:
219  default:
220  return localWidth;
221  }
222 }
223 
224 template<typename T>
226  if(originalCoord < matchingCoordinateMin){ // Assume (!) original is on right (!) side of periodic boundary, starting at some value
227  return matchingCoordinateMax + (originalCoord - globalCoordinateMin);
228  }
229  else if(originalCoord > matchingCoordinateMax){
230  return matchingCoordinateMin - (globalCoordinateMax - originalCoord);
231  }
232  else return originalCoord; // Within matching boundaries; no need to transform
233 
234 }
235 
236 template<typename T>
237 int DimensionDatum<T>::getIndexedCoord(int originalCoord, bool isSimplified){
238  return (isSimplified ? originalCoord : getTransformedCoord(originalCoord)) - simplifiedBoundariesMin;
239 }
240 
241 template<typename T>
242 bool DimensionDatum<T>::isInLocalBounds(int originalCoord){
243  return originalCoord >= localBoundariesMin && originalCoord < localBoundariesMax;
244 }
245 
246 /*******************************************************************/
247 
252 template<typename T>
254 
255 private:
256  bool dummy; // Used for cases when error flag is not requested
257 
258 protected:
259  CartesianTopology* cartTopology;
260  GridDimensions localBoundaries;
261  int length; // Total length of the entire array (one data space)
262 
263  int numDims; // Number of dimensions
264  bool globalSpaceIsPeriodic; // True if the global space is periodic
265 
266  vector<int> places; // Multipliers to calculate index, for each dimension
267  vector<int> strides; // Sizes of each dimensions, in bytes
268  vector<DimensionDatum<T> > dimensionData; // List of data for each dimension
269  RankDatum* neighborData; // List of data for each adjacent rank
270  int neighborCount; // Count of adjacent ranks
271  MPI_Request* requests; // Pointer to MPI requests (for wait operations)
272 
273  int instanceID; // Unique ID for managing MPI requests without mix-ups
274  int syncCount;
275 
284  AbstractValueLayerND(vector<int> processesPerDim, GridDimensions globalBoundaries, int bufferSize, bool periodic);
285  virtual ~AbstractValueLayerND();
286 
287 
288 public:
289 
290  static int instanceCount;
291 
298  virtual bool isInLocalBounds(vector<int> coords);
299 
300  /*
301  * Returns true only if the coordinates given are within the local boundaries
302  *
303  * @param coords Coordinates to be tested
304  * @return true if the coordinates are within the local boundaries
305  */
306  virtual bool isInLocalBounds(Point<int> location);
307 
315  return localBoundaries;
316  }
317 
318 protected:
319  // Methods implemented in this class but visible only to child classes:
320 
331  vector<int> getIndexes(vector<int> location, bool isSimplified = false);
332 
346  int getIndex(vector<int> location, bool isSimplified = false);
347 
348 
360  int getIndex(Point<int> location);
361 
362 
363  // Virtual methods (implemented by child classes
364 
382  virtual void initialize(T initialValue, bool fillBufferZone = false, bool fillLocal = true) = 0;
383 
391  virtual void initialize(T initialLocalValue, T initialBufferZoneValue) = 0;
392 
404  virtual T addValueAt(T val, Point<int> location, bool& errFlag) = 0;
405 
417  virtual T addValueAt(T val, vector<int> location, bool& errFlag) = 0;
418 
430  virtual T setValueAt(T val, Point<int> location, bool& errFlag) = 0;
431 
443  virtual T setValueAt(T val, vector<int> location, bool& errFlag) = 0;
444 
454  virtual T getValueAt(Point<int> location, bool& errFlag) = 0;
455 
465  virtual T getValueAt(vector<int> location, bool& errFlag) = 0;
466 
475  virtual void synchronize() = 0;
476 
477 private:
478 
491  void getMPIDataType(RelativeLocation relLoc, MPI_Datatype &datatype);
492 
501  void getMPIDataType(int radius, MPI_Datatype &datatype);
502 
511  void getMPIDataType(vector<int> sideLengths, MPI_Datatype &datatype, int dimensionIndex);
512 
517  MPI_Datatype getRawMPIDataType();
518 
519 
534  int getSendPointerOffset(RelativeLocation relLoc);
535 
551  int getReceivePointerOffset(RelativeLocation relLoc);
552 
553 
554 };
555 
556 
557 
558 template<typename T>
559 int AbstractValueLayerND<T>::instanceCount = 0;
560 
561 template<typename T>
562 AbstractValueLayerND<T>::AbstractValueLayerND(vector<int> processesPerDim, GridDimensions globalBoundaries,int bufferSize, bool periodic): globalSpaceIsPeriodic(periodic), syncCount(0){
565  cartTopology = RepastProcess::instance()->getCartesianTopology(processesPerDim, periodic);
566  // Calculate the size to be used for the buffers
567  numDims = processesPerDim.size();
568 
569  int rank = RepastProcess::instance()->rank();
570  localBoundaries = cartTopology->getDimensions(rank, globalBoundaries);
571 
572  // First create the basic coordinate data per dimension
573  length = 1;
574  int val = 1;
575  for(int i = 0; i < numDims; i++){
576  DimensionDatum<T> datum(i, globalBoundaries, localBoundaries, bufferSize, periodic);
577  length *= datum.width;
578  dimensionData.push_back(datum);
579  places.push_back(val);
580  strides.push_back(val * sizeof(T));
581  val *= dimensionData[i].width;
582  }
583 
584  // Now create the rank-based data per neighbor
585  RelativeLocation relLoc(numDims);
586  RelativeLocation relLocTrimmed = cartTopology->trim(rank, relLoc); // Initialized to minima
587 
588  vector<int> myCoordinates;
589  cartTopology->getCoordinates(rank, myCoordinates);
590 
591  neighborData = new RankDatum[relLoc.getMaxIndex()];
592  neighborCount = 0;
593  do{
594  if(relLoc.validNonCenter()){ // Skip 0,0,0,0,0
595  RankDatum* datum;
596  datum = &neighborData[neighborCount];
597  // Collect the information about this rank here
598  getMPIDataType(relLoc, datum->datatype);
599  datum->sendPtrOffset = getSendPointerOffset(relLoc);
600  datum->receivePtrOffset = getReceivePointerOffset(relLoc);
601  vector<int> current = relLoc.getCurrentValue();
602  datum->rank = cartTopology->getRank(myCoordinates, current);
603  datum->sendDir = RelativeLocation::getDirectionIndex(current);
604  datum->recvDir = RelativeLocation::getReverseDirectionIndex(current);
605 
606  neighborCount++;
607  }
608  }while(relLoc.increment());
609 
610  // Create arrays for MPI requests and results (statuses)
611  requests = new MPI_Request[neighborCount * 2];
612 }
613 
614 template<typename T>
616  delete[] neighborData; // Should Free MPI Datatypes first...
617  delete[] requests;
618 }
619 
620 template<typename T>
622  for(int i = 0; i < numDims; i++){
623  DimensionDatum<T>* datum = &dimensionData[i];
624  if(!datum->isInLocalBounds(coords[i])) return false;
625  }
626  return true;
627 }
628 
629 template<typename T>
631  return isInLocalBounds(location.coords());
632 }
633 
634 template<typename T>
635 vector<int> AbstractValueLayerND<T>::getIndexes(vector<int> location, bool isSimplified){
636  vector<int> ret;
637  ret.assign(numDims, 0); // Make the right amount of space
638  for(int i = 0; i < numDims; i++) ret[i] = dimensionData[i].getIndexedCoord(location[i], isSimplified);
639  return ret;
640 }
641 
642 template<typename T>
643 int AbstractValueLayerND<T>::getIndex(vector<int> location, bool isSimplified){
644  vector<int> indexed = getIndexes(location, isSimplified);
645  int val = 0;
646  for(int i = numDims - 1; i >= 0; i--) val += indexed[i] * places[i];
647  if(val < 0 || val > length) val = -1;
648  return val;
649 }
650 
651 template<typename T>
653  return getIndex(location.coords());
654 }
655 
656 
657 template<typename T>
658 void AbstractValueLayerND<T>::getMPIDataType(RelativeLocation relLoc, MPI_Datatype &datatype){
659  vector<int> sideLengths;
660  for(int i = 0; i < numDims; i++) sideLengths.push_back(dimensionData[i].getSendReceiveSize(relLoc[i]));
661  getMPIDataType(sideLengths, datatype, numDims - 1);
662 }
663 
664 template<typename T>
665 void AbstractValueLayerND<T>::getMPIDataType(int radius, MPI_Datatype &datatype){
666  vector<int> sideLengths;
667  sideLengths.assign(numDims, 2 * radius + 1);
668  getMPIDataType(sideLengths, datatype, numDims - 1);
669 }
670 
671 template<typename T>
672 void AbstractValueLayerND<T>::getMPIDataType(vector<int> sideLengths, MPI_Datatype &datatype, int dimensionIndex){
673  if(dimensionIndex == 0){
674  MPI_Type_contiguous(sideLengths[dimensionIndex], getRawMPIDataType(), &datatype);
675  }
676  else{
677  MPI_Datatype innerType;
678  getMPIDataType(sideLengths, innerType, dimensionIndex - 1);
679  MPI_Type_create_hvector(sideLengths[dimensionIndex], // Count
680  1, // BlockLength: just one of the inner data type
681  strides[dimensionIndex], // Stride, in bytes
682  innerType, // Inner Datatype
683  &datatype);
684  }
685  // Commit?
686  MPI_Type_commit(&datatype);
687 }
688 
689 
690 template<typename T>
691 int AbstractValueLayerND<T>::getSendPointerOffset(RelativeLocation relLoc){
692  int ret = 0;
693  for(int i = 0; i < numDims; i++){
694  DimensionDatum<T>* datum = &dimensionData[i];
695  ret += (relLoc[i] <= 0 ? datum->leftBufferSize : datum->width - (2 * datum->rightBufferSize)) * places[i];
696  }
697  return ret;
698 }
699 
700 template<typename T>
701 int AbstractValueLayerND<T>::getReceivePointerOffset(RelativeLocation relLoc){
702  int ret = 0;
703  for(int i = 0; i < numDims; i++){
704  DimensionDatum<T>* datum = &dimensionData[i];
705  ret += (relLoc[i] < 0 ? 0 : (relLoc[i] == 0 ? datum->leftBufferSize : datum->width - datum->rightBufferSize)) * places[i];
706  }
707  return ret;
708 }
709 
710 
769 template<typename T>
771 
772 private:
773  T* dataSpace; // Pointer to the data space
774 
775 public:
776 
777  ValueLayerND(vector<int> processesPerDim, GridDimensions globalBoundaries, int bufferSize,
778  bool periodic, T initialValue = 0, T initialBufferZoneValue = 0);
779  virtual ~ValueLayerND();
780 
784  virtual void initialize(T initialValue, bool fillBufferZone = false, bool fillLocal = true);
785 
789  virtual void initialize(T initialLocalValue, T initialBufferZoneValue);
790 
794  virtual T addValueAt(T val, Point<int> location, bool& errFlag);
795 
799  virtual T addValueAt(T val, vector<int> location, bool& errFlag);
800 
804  virtual T setValueAt(T val, Point<int> location, bool& errFlag);
805 
809  virtual T setValueAt(T val, vector<int> location, bool& errFlag);
810 
814  virtual T getValueAt(Point<int> location, bool& errFlag);
815 
819  virtual T getValueAt(vector<int> location, bool& errFlag);
820 
824  virtual void synchronize();
825 
848  void write(string fileLocation, string filetag, bool writeSharedBoundaryAreas = false);
849 
850 
851 private:
852 
853 
865  void fillDimension(T localValue, T bufferZoneValue, bool doBufferZone, bool doLocal, T* dataSpacePointer, int dimIndex);
866 
867  /*
868  * Writes one dimension's information to the specified csv file.
869  *
870  * @param outfile output file
871  * @param dataSpacePointer pointer to the data space to be written
872  * @param currentPosition position currently being written (for recursive calls)
873  * @param dimIndex dimension currently being written (for recursive calls)
874  * @param writeSharedBoundaryAreas if true, write the areas that are non-local to this process
875  */
876  void writeDimension(std::ofstream& outfile, T* dataSpacePointer, int* currentPosition, int dimIndex, bool writeSharedBoundaryAreas = false);
877 
878 };
879 
880 
881 
882 
883 
891 template<typename T>
893 
894 protected:
895 
896  T* dataSpace1; // Permanent pointer to bank 1 of the data space
897  T* dataSpace2; // Permanent pointer to bank 2 of the data space
898  T* currentDataSpace; // Temporary pointer to the active data space
899  T* otherDataSpace; // Temporary pointer to the inactive data space
900 
901 public:
902 
903  ValueLayerNDSU(vector<int> processesPerDim, GridDimensions globalBoundaries, int bufferSize, bool periodic, T initialValue = 0, T initialBufferZoneValue = 0);
904  virtual ~ValueLayerNDSU();
905 
909  virtual void initialize(T initialValue, bool fillBufferZone = false, bool fillLocal = true);
910 
914  virtual void initialize(T initialLocalValue, T initialBufferZoneValue);
915 
919  virtual T addValueAt(T val, Point<int> location, bool& errFlag);
920 
924  virtual T addValueAt(T val, vector<int> location, bool& errFlag);
925 
929  virtual T setValueAt(T val, Point<int> location, bool& errFlag);
930 
934  virtual T setValueAt(T val, vector<int> location, bool& errFlag);
935 
939  virtual T getValueAt(Point<int> location, bool& errFlag);
940 
944  virtual T getValueAt(vector<int> location, bool& errFlag);
945 
949  virtual void synchronize();
950 
954  virtual void write(string fileLocation, string filetag, bool writeSharedBoundaryAreas = false);
955 
959  void switchValueLayer();
960 
970  virtual T addSecondaryValueAt(T val, Point<int> location, bool& errFlag);
971 
981  virtual T addSecondaryValueAt(T val, vector<int> location, bool& errFlag);
982 
992  virtual T setSecondaryValueAt(T val, Point<int> location, bool& errFlag);
993 
1003  virtual T setSecondaryValueAt(T val, vector<int> location, bool& errFlag);
1004 
1013  virtual T getSecondaryValueAt(Point<int> location, bool& errFlag);
1014 
1023  virtual T getSecondaryValueAt(vector<int> location, bool& errFlag);
1024 
1028  virtual void copyCurrentToSecondary();
1029 
1033  virtual void copySecondaryToCurrent();
1034 
1070  void flowback();
1071 
1072 private:
1073 
1086  void fillDimension(T localValue, T bufferZoneValue, bool doBufferZone, bool doLocal, T* dataSpace1Pointer, T* dataSpace2Pointer, int dimIndex);
1087 
1088  /*
1089  * Writes one dimension's information to the specified csv file.
1090  *
1091  * @param outfile output file
1092  * @param dataSpacePointer pointer to the data space to be written
1093  * @param currentPosition position currently being written (for recursive calls)
1094  * @param dimIndex dimension currently being written (for recursive calls)
1095  * @param writeSharedBoundaryAreas if true, write the areas that are non-local to this process
1096  */
1097  void writeDimension(std::ofstream& outfile, T* dataSpacePointer, int* currentPosition, int dimIndex, bool writeSharedBoundaryAreas = false);
1098 
1104  void sumInto(T* dataSpace1Pointer, T* dataSpace2Pointer, int dimIndex);
1105 
1106 };
1107 
1108 
1109 
1110 template<typename T>
1111 ValueLayerND<T>::ValueLayerND(vector<int> processesPerDim, GridDimensions globalBoundaries, int bufferSize, bool periodic,
1112  T initialValue, T initialBufferZoneValue): AbstractValueLayerND<T>(processesPerDim, globalBoundaries, bufferSize, periodic){
1113 
1114  // Create the actual arrays for the data
1115  dataSpace = new T[AbstractValueLayerND<T>::length];
1116 
1117  // Finally, fill the data with the initial values
1118  initialize(initialValue, initialBufferZoneValue);
1119 
1120  // And synchronize
1121  synchronize();
1122 
1123 }
1124 
1125 template<typename T>
1126 ValueLayerND<T>::~ValueLayerND(){
1127  delete[] dataSpace;
1128 }
1129 
1130 template<typename T>
1131 void ValueLayerND<T>::initialize(T initialValue, bool fillBufferZone, bool fillLocal){
1132  fillDimension(initialValue, initialValue, fillBufferZone, fillLocal, dataSpace, AbstractValueLayerND<T>::numDims - 1);
1133 }
1134 
1135 template<typename T>
1136 void ValueLayerND<T>::initialize(T initialLocalValue, T initialBufferZoneValue){
1137  fillDimension(initialLocalValue, initialBufferZoneValue, true, true, dataSpace, AbstractValueLayerND<T>::numDims - 1);
1138 }
1139 
1140 template<typename T>
1141 T ValueLayerND<T>::addValueAt(T val, Point<int> location, bool& errFlag){
1142  errFlag = false;
1143  int indx = this->getIndex(location);
1144  if(indx == -1){
1145  errFlag = true;
1146  return val;
1147  }
1148  T* pt = &dataSpace[indx];
1149  return (*pt = *pt + val);
1150 }
1151 
1152 template<typename T>
1153 T ValueLayerND<T>::addValueAt(T val, vector<int> location, bool& errFlag){
1154  errFlag = false;
1155  int indx = this->getIndex(location);
1156  if(indx == -1){
1157  errFlag = true;
1158  return val;
1159  }
1160 
1161  T* pt = &dataSpace[indx];
1162  return (*pt = *pt + val);
1163 }
1164 
1165 template<typename T>
1166 T ValueLayerND<T>::setValueAt(T val, Point<int> location, bool& errFlag){
1167  errFlag = false;
1168  int indx = this->getIndex(location);
1169  if(indx == -1){
1170  errFlag = true;
1171  return val;
1172  }
1173  T* pt = &dataSpace[indx];
1174  return (*pt = val);
1175 }
1176 
1177 template<typename T>
1178 T ValueLayerND<T>::setValueAt(T val, vector<int> location, bool& errFlag){
1179  errFlag = false;
1180  int indx = this->getIndex(location);
1181  if(indx == -1){
1182  errFlag = true;
1183  return val;
1184  }
1185  T* pt = &dataSpace[indx];
1186  return (*pt = val);
1187 }
1188 
1189 template<typename T>
1190 T ValueLayerND<T>::getValueAt(vector<int> location, bool& errFlag){
1191  errFlag = false;
1192  int indx = this->getIndex(location);
1193  if(indx == -1){
1194  errFlag = true;
1195  return 0;
1196  }
1197  return dataSpace[indx];
1198 }
1199 
1200 template<typename T>
1201 T ValueLayerND<T>::getValueAt(Point<int> location, bool& errFlag){
1202  errFlag = false;
1203  int indx = this->getIndex(location);
1204  if(indx == -1){
1205  errFlag = true;
1206  return 0;
1207  }
1208  return dataSpace[indx];
1209 }
1210 
1211 template<typename T>
1216  // Note: the syncCount and send/recv directions are used to create a unique tag value for the
1217  // mpi sends and receives. The tag value must be unique in two ways: first, successive calls to this
1218  // function must be different enough that they can't be confused. The 'syncCount' value is used to
1219  // achieve this, and it will loop from 0-9 and then repeat. The second, the tag must sometimes
1220  // differentiate between sends and receives that are going to the same rank. If a dimension
1221  // has only 2 processes but wrap-around borders, then one process may be sending to the other
1222  // process twice (once left and once right). The 'sendDir' and 'recvDir' values trap this
1223 
1224  // For each entry in neighbors:
1225  MPI_Status statuses[AbstractValueLayerND<T>::neighborCount * 2];
1226  for(int i = 0; i < AbstractValueLayerND<T>::neighborCount; i++){
1227  MPI_Isend(&dataSpace[AbstractValueLayerND<T>::neighborData[i].sendPtrOffset], 1, AbstractValueLayerND<T>::neighborData[i].datatype,
1229  MPI_Irecv(&dataSpace[AbstractValueLayerND<T>::neighborData[i].receivePtrOffset], 1, AbstractValueLayerND<T>::neighborData[i].datatype,
1231  }
1233 }
1234 
1235 
1236 template<typename T>
1237 void ValueLayerND<T>::write(string fileLocation, string fileTag, bool writeSharedBoundaryAreas){
1238  std::ofstream outfile;
1239  std::ostringstream stream;
1240  int rank = repast::RepastProcess::instance()->rank();
1241  stream << fileLocation << "ValueLayer_" << fileTag << "_" << rank << ".csv";
1242  std::string filename = stream.str();
1243 
1244  const char * c = filename.c_str();
1245  outfile.open(c, std::ios_base::trunc | std::ios_base::out); // it will not delete the content of file, will add a new line
1246 
1247  // Write headers
1248  for(int i = 0; i < AbstractValueLayerND<T>::numDims; i++) outfile << "DIM_" << i << ",";
1249  outfile << "VALUE" << endl;
1250 
1251  int* positions = new int[AbstractValueLayerND<T>::numDims];
1252  for(int i = 0; i < AbstractValueLayerND<T>::numDims; i++) positions[i] = 0;
1253 
1254  writeDimension(outfile, dataSpace, positions, AbstractValueLayerND<T>::numDims - 1, writeSharedBoundaryAreas);
1255 
1256  outfile.close();
1257 }
1258 
1259 
1260 template<typename T>
1261 void ValueLayerND<T>::fillDimension(T localValue, T bufferValue, bool doBufferZone, bool doLocal, T* dataSpacePointer, int dimIndex){
1262  if(!doBufferZone && !doLocal) return;
1263  int bufferEdge = AbstractValueLayerND<T>::dimensionData[dimIndex].leftBufferSize;
1264  int localEdge = bufferEdge + AbstractValueLayerND<T>::dimensionData[dimIndex].localWidth;
1265  int upperBound = localEdge + AbstractValueLayerND<T>::dimensionData[dimIndex].rightBufferSize;
1266 
1267  int pointerIncrement = AbstractValueLayerND<T>::places[dimIndex];
1268 
1269 
1270  int i = 0;
1271  for(; i < bufferEdge; i++){
1272  if(doBufferZone){
1273  if(dimIndex == 0){
1274  *dataSpacePointer = bufferValue;
1275  }
1276  else{
1277  fillDimension(bufferValue, bufferValue, doBufferZone, doLocal, dataSpacePointer, dimIndex - 1);
1278  }
1279  }
1280  // Increment the pointers
1281  dataSpacePointer += pointerIncrement;
1282  }
1283  for(; i < localEdge; i++){
1284  if(doLocal){
1285  if(dimIndex == 0){
1286  *dataSpacePointer = localValue;
1287  }
1288  else{
1289  fillDimension(localValue, bufferValue, doBufferZone, doLocal, dataSpacePointer, dimIndex - 1);
1290  }
1291  }
1292  // Increment the pointers
1293  dataSpacePointer += pointerIncrement;
1294  }
1295  if(doBufferZone){ // Note: we don't need to finish this at all if not doing buffer zone
1296  for(; i < upperBound; i++){
1297  if(dimIndex == 0){
1298  *dataSpacePointer = bufferValue;
1299  }
1300  else{
1301  fillDimension(bufferValue, bufferValue, doBufferZone, doLocal, dataSpacePointer, dimIndex - 1);
1302  }
1303  }
1304  dataSpacePointer += pointerIncrement;
1305  }
1306 
1307 }
1308 
1309 template<typename T>
1310 void ValueLayerND<T>::writeDimension(std::ofstream& outfile, T* dataSpacePointer, int* currentPosition, int dimIndex, bool writeSharedBoundaryAreas){
1311  int bufferEdge = AbstractValueLayerND<T>::dimensionData[dimIndex].leftBufferSize;
1312  int localEdge = bufferEdge + AbstractValueLayerND<T>::dimensionData[dimIndex].localWidth;
1313  int upperBound = localEdge + AbstractValueLayerND<T>::dimensionData[dimIndex].rightBufferSize;
1314 
1315  int pointerIncrement = AbstractValueLayerND<T>::places[dimIndex];
1316  int i = 0;
1317  for(; i < bufferEdge; i++){
1318  currentPosition[dimIndex] = i;
1319  if(writeSharedBoundaryAreas){
1320  if(dimIndex == 0){
1321  T val = *dataSpacePointer;
1322  if(val != 0){
1323  for(int j = 0; j < AbstractValueLayerND<T>::numDims; j++) outfile << (currentPosition[j] - AbstractValueLayerND<T>::dimensionData[j].leftBufferSize + AbstractValueLayerND<T>::dimensionData[j].localBoundariesMin) << ",";
1324  outfile << val << endl;
1325  }
1326  }
1327  else{
1328  writeDimension(outfile, dataSpacePointer, currentPosition, dimIndex - 1, writeSharedBoundaryAreas);
1329  }
1330  }
1331  // Increment the pointers
1332  dataSpacePointer += pointerIncrement;
1333  }
1334  for(; i < localEdge; i++){
1335  currentPosition[dimIndex] = i;
1336  if(dimIndex == 0){
1337  T val = *dataSpacePointer;
1338  if(val != 0){
1339  for(int j = 0; j < AbstractValueLayerND<T>::numDims; j++) outfile << (currentPosition[j] - AbstractValueLayerND<T>::dimensionData[j].leftBufferSize + AbstractValueLayerND<T>::dimensionData[j].localBoundariesMin) << ",";
1340  outfile << val << endl;
1341  }
1342  }
1343  else{
1344  writeDimension(outfile, dataSpacePointer, currentPosition, dimIndex - 1, writeSharedBoundaryAreas);
1345  }
1346  // Increment the pointers
1347  dataSpacePointer += pointerIncrement;
1348  }
1349  if(writeSharedBoundaryAreas){ // Note: we don't need to finish this at all if not doing buffer zone
1350  for(; i < upperBound; i++){
1351  currentPosition[dimIndex] = i;
1352  if(dimIndex == 0){
1353  T val = *dataSpacePointer;
1354  if(val != 0){
1355  for(int j = 0; j < AbstractValueLayerND<T>::numDims; j++) outfile << (currentPosition[j] - AbstractValueLayerND<T>::dimensionData[j].leftBufferSize + AbstractValueLayerND<T>::dimensionData[j].localBoundariesMin) << ",";
1356  outfile << *dataSpacePointer << endl;
1357  }
1358  }
1359  else{
1360  writeDimension(outfile, dataSpacePointer, currentPosition, dimIndex - 1, writeSharedBoundaryAreas);
1361  }
1362  }
1363  dataSpacePointer += pointerIncrement;
1364  }
1365 
1366 }
1367 
1368 
1369 
1370 
1371 template<typename T>
1372 ValueLayerNDSU<T>::ValueLayerNDSU(vector<int> processesPerDim, GridDimensions globalBoundaries, int bufferSize, bool periodic,
1373  T initialValue, T initialBufferZoneValue): AbstractValueLayerND<T>(processesPerDim, globalBoundaries, bufferSize, periodic){
1374 
1375  // Create the actual arrays for the data
1376  dataSpace1 = new T[AbstractValueLayerND<T>::length];
1377  dataSpace2 = new T[AbstractValueLayerND<T>::length];
1378  currentDataSpace = dataSpace1;
1379  otherDataSpace = dataSpace2;
1380 
1381  // Finally, fill the data with the initial values
1382  initialize(initialValue, initialBufferZoneValue);
1383 
1384  // And synchronize
1385  synchronize();
1386 
1387 }
1388 
1389 template<typename T>
1390 ValueLayerNDSU<T>::~ValueLayerNDSU(){
1391  delete[] currentDataSpace;
1392  delete[] otherDataSpace;
1393 }
1394 
1395 template<typename T>
1396 void ValueLayerNDSU<T>::initialize(T initialValue, bool fillBufferZone, bool fillLocal){
1397  fillDimension(initialValue, initialValue, fillBufferZone, fillLocal, dataSpace1, dataSpace2, AbstractValueLayerND<T>::numDims - 1);
1398 }
1399 
1400 template<typename T>
1401 void ValueLayerNDSU<T>::initialize(T initialLocalValue, T initialBufferZoneValue){
1402  fillDimension(initialLocalValue, initialBufferZoneValue, true, true, dataSpace1, dataSpace2, AbstractValueLayerND<T>::numDims - 1);
1403 }
1404 
1405 template<typename T>
1406 T ValueLayerNDSU<T>::addValueAt(T val, Point<int> location, bool& errFlag){
1407  int indx = this->getIndex(location);
1408  if(indx == -1) return nan("");
1409  T* pt = &currentDataSpace[indx];
1410  return (*pt = *pt + val);
1411 }
1412 
1413 template<typename T>
1414 T ValueLayerNDSU<T>::addValueAt(T val, vector<int> location, bool& errFlag){
1415  int indx = this->getIndex(location);
1416  if(indx == -1) return nan("");
1417  T* pt = &currentDataSpace[indx];
1418  return (*pt = *pt + val);
1419 }
1420 
1421 template<typename T>
1422 T ValueLayerNDSU<T>::setValueAt(T val, Point<int> location, bool& errFlag){
1423  int indx = this->getIndex(location);
1424  if(indx == -1) return nan("");
1425  T* pt = &currentDataSpace[indx];
1426  return (*pt = val);
1427 }
1428 
1429 template<typename T>
1430 T ValueLayerNDSU<T>::setValueAt(T val, vector<int> location, bool& errFlag){
1431  int indx = this->getIndex(location);
1432  if(indx == -1) return nan("");
1433  T* pt = &currentDataSpace[indx];
1434  return (*pt = val);
1435 }
1436 
1437 template<typename T>
1438 T ValueLayerNDSU<T>::getValueAt(Point<int> location, bool& errFlag){
1439  int indx = this->getIndex(location);
1440  if(indx == -1) return nan("");
1441  return currentDataSpace[indx];
1442 }
1443 
1444 template<typename T>
1445 T ValueLayerNDSU<T>::getValueAt(vector<int> location, bool& errFlag){
1446  int indx = this->getIndex(location);
1447  if(indx == -1) return nan("");
1448  return currentDataSpace[indx];
1449 }
1450 
1451 
1452 template<typename T>
1457  // Note: the syncCount and send/recv directions are used to create a unique tag value for the
1458  // mpi sends and receives. The tag value must be unique in two ways: first, successive calls to this
1459  // function must be different enough that they can't be confused. The 'syncCount' value is used to
1460  // achieve this, and it will loop from 0-9 and then repeat. The second, the tag must sometimes
1461  // differentiate between sends and receives that are going to the same rank. If a dimension
1462  // has only 2 processes but wrap-around borders, then one process may be sending to the other
1463  // process twice (once left and once right). The 'sendDir' and 'recvDir' values trap this
1464 
1465  // For each entry in neighbors:
1466  MPI_Status statuses[AbstractValueLayerND<T>::neighborCount * 2];
1467  for(int i = 0; i < AbstractValueLayerND<T>::neighborCount; i++){
1468  MPI_Isend(&currentDataSpace[AbstractValueLayerND<T>::neighborData[i].sendPtrOffset], 1, AbstractValueLayerND<T>::neighborData[i].datatype,
1470  MPI_Irecv(&currentDataSpace[AbstractValueLayerND<T>::neighborData[i].receivePtrOffset], 1, AbstractValueLayerND<T>::neighborData[i].datatype,
1472  }
1474 }
1475 
1476 template<typename T>
1477 void ValueLayerNDSU<T>::write(string fileLocation, string fileTag, bool writeSharedBoundaryAreas){
1478  std::ofstream outfile;
1479  std::ostringstream stream;
1480  int rank = repast::RepastProcess::instance()->rank();
1481  stream << fileLocation << "ValueLayer_" << fileTag << "_" << rank << ".csv";
1482  std::string filename = stream.str();
1483 
1484  const char * c = filename.c_str();
1485  outfile.open(c, std::ios_base::trunc | std::ios_base::out); // it will not delete the content of file, will add a new line
1486 
1487  // Write headers
1488  for(int i = 0; i < AbstractValueLayerND<T>::numDims; i++) outfile << "DIM_" << i << ",";
1489  outfile << "VALUE" << endl;
1490 
1491  int* positions = new int[AbstractValueLayerND<T>::numDims];
1492  for(int i = 0; i < AbstractValueLayerND<T>::numDims; i++) positions[i] = 0;
1493 
1494  writeDimension(outfile, currentDataSpace, positions, AbstractValueLayerND<T>::numDims - 1, writeSharedBoundaryAreas);
1495 
1496  outfile.close();
1497 }
1498 
1499 template<typename T>
1501  // Switch the data banks
1502  T* tempDataSpace = currentDataSpace;
1503  currentDataSpace = otherDataSpace;
1504  otherDataSpace = tempDataSpace;
1505 }
1506 
1507 template<typename T>
1508 T ValueLayerNDSU<T>::addSecondaryValueAt(T val, Point<int> location, bool& errFlag){
1509  errFlag = false;
1510  int indx = this->getIndex(location);
1511  if(indx == -1){
1512  errFlag = true;
1513  return val;
1514  }
1515  T* pt = &otherDataSpace[indx];
1516  return (*pt = *pt + val);
1517 }
1518 
1519 template<typename T>
1520 T ValueLayerNDSU<T>::addSecondaryValueAt(T val, vector<int> location, bool& errFlag){
1521  errFlag = false;
1522  int indx = this->getIndex(location);
1523  if(indx == -1){
1524  errFlag = true;
1525  return val;
1526  }
1527  T* pt = &otherDataSpace[indx];
1528  return (*pt = *pt + val);
1529 }
1530 
1531 template<typename T>
1532 T ValueLayerNDSU<T>::setSecondaryValueAt(T val, Point<int> location, bool& errFlag){
1533  errFlag = false;
1534  int indx = this->getIndex(location);
1535  if(indx == -1){
1536  errFlag = true;
1537  return val;
1538  }
1539  T* pt = &otherDataSpace[indx];
1540  return (*pt = val);
1541 }
1542 
1543 template<typename T>
1544 T ValueLayerNDSU<T>::setSecondaryValueAt(T val, vector<int> location, bool& errFlag){
1545  errFlag = false;
1546  int indx = this->getIndex(location);
1547  if(indx == -1){
1548  errFlag = true;
1549  return val;
1550  }
1551  T* pt = &otherDataSpace[indx];
1552  return (*pt = val);
1553 }
1554 
1555 template<typename T>
1557  errFlag = false;
1558  int indx = this->getIndex(location);
1559  if(indx == -1){
1560  errFlag = true;
1561  return 0;
1562  }
1563  return otherDataSpace[indx];
1564 }
1565 
1566 template<typename T>
1567 T ValueLayerNDSU<T>::getSecondaryValueAt(vector<int> location, bool& errFlag){
1568  errFlag = false;
1569  int indx = this->getIndex(location);
1570  if(indx == -1){
1571  errFlag = true;
1572  return 0;
1573  }
1574  return otherDataSpace[indx];
1575 }
1576 
1577 template<typename T>
1579  T d = 0;
1580  memcpy(otherDataSpace, currentDataSpace, AbstractValueLayerND<T>::length * sizeof d);
1581 }
1582 
1583 template<typename T>
1585  T d = 0;
1586  memcpy(currentDataSpace, otherDataSpace, AbstractValueLayerND<T>::length * sizeof d);
1587 }
1588 
1589 template<typename T>
1591  std::cout << " valueLayer is executing flowback on rank " << repast::RepastProcess::instance()->rank() << std::endl;
1592  // Fill the other data space with zeros
1593  T d = 0;
1594  memset(otherDataSpace, 0, AbstractValueLayerND<T>::length * sizeof d);
1595 
1596  // Loop through the (3^N - 1)/2 directions
1597 
1598  // Note: TODO: Do all the sends as 'waitall', then process all the receives, with the final
1599  // sends waitall being the block before returning to simulation operation
1600 
1601  // For each direction:
1604  std::cout << " valueLayer is executing flowback on rank " << repast::RepastProcess::instance()->rank() << " LIST SIZE = " << listSize << std::endl;
1605  MPI_Request* flowbackRequests = new MPI_Request[4]; // No more than four at a time (may be only 2)
1606  do{
1607  int LDir = relLoc.getIndex();
1609  // Need to create a send to the L and a send to the R, then matching receives
1610  // We create these in pairs because we can take a small advantage of non-blocking
1611  // sends but be assured that the L and R data are not going to interfere
1612  RankDatum* datum;
1613 
1614 
1615  int countOfRequests = 0;
1616  for(int i = 0; i < listSize; i++){ // To do: Shouldn't loop through this, but instead should index once
1618  // Note: (!!!) Yes, we are using the 'send' pointer for the _receive_ and the 'receive' pointer for the send...
1619  if(datum->sendDir == LDir){
1620  MPI_Isend(&currentDataSpace[datum->receivePtrOffset], 1, datum->datatype,
1621  datum->rank, 1001, AbstractValueLayerND<T>::cartTopology->topologyComm, &flowbackRequests[countOfRequests]);
1622  countOfRequests++;
1623  }
1624  else if(datum->sendDir == RDir){
1625  MPI_Isend(&currentDataSpace[datum->receivePtrOffset], 1, datum->datatype,
1626  datum->rank, 2002, AbstractValueLayerND<T>::cartTopology->topologyComm, &flowbackRequests[countOfRequests]);
1627  countOfRequests++;
1628  }
1629  if(datum->recvDir == LDir){
1630  MPI_Irecv(&otherDataSpace[datum->sendPtrOffset], 1, datum->datatype,
1631  datum->rank, 1001, AbstractValueLayerND<T>::cartTopology->topologyComm, &flowbackRequests[countOfRequests]);
1632  countOfRequests++;
1633  }
1634  else if(datum->recvDir == RDir){
1635  MPI_Irecv(&otherDataSpace[datum->sendPtrOffset], 1, datum->datatype,
1636  datum->rank, 2002, AbstractValueLayerND<T>::cartTopology->topologyComm, &flowbackRequests[countOfRequests]);
1637  countOfRequests++;
1638  }
1639  }
1640  MPI_Status statuses[countOfRequests];
1641  // Perform the sends and receives
1642  std::cout << " valueLayer is executing flowback on rank " << repast::RepastProcess::instance()->rank() << " DOING WAITALL WITH LDIRECTION " << LDir << std::endl;
1643  MPI_Waitall(countOfRequests, flowbackRequests, statuses);
1644  std::cout << " valueLayer is executing flowback on rank " << repast::RepastProcess::instance()->rank() << " DONE WITH WAITALL... " << std::endl;
1645  // Copy the received data from the other data space into
1646  // the current data space, summing the values and clearing
1647  // the other data space to zeros
1648  sumInto(currentDataSpace, otherDataSpace, AbstractValueLayerND<T>::numDims - 1);
1649 
1650  relLoc.increment();
1651  }while(relLoc.validNonCenter()); // Note: STOP at 0,0,0,0...: because each location creates a send and a receive in both L and R, only need to do half
1652 
1653  delete[] flowbackRequests; // Cleanup
1654 
1655 }
1656 
1657 template<typename T>
1658 void ValueLayerNDSU<T>::fillDimension(T localValue, T bufferValue, bool doBufferZone, bool doLocal, T* dataSpace1Pointer, T* dataSpace2Pointer, int dimIndex){
1659  if(!doBufferZone && !doLocal) return;
1660  int bufferEdge = AbstractValueLayerND<T>::dimensionData[dimIndex].leftBufferSize;
1661  int localEdge = bufferEdge + AbstractValueLayerND<T>::dimensionData[dimIndex].localWidth;
1662  int upperBound = localEdge + AbstractValueLayerND<T>::dimensionData[dimIndex].rightBufferSize;
1663 
1664  int pointerIncrement = AbstractValueLayerND<T>::places[dimIndex];
1665 
1666 
1667  int i = 0;
1668  for(; i < bufferEdge; i++){
1669  if(doBufferZone){
1670  if(dimIndex == 0){
1671  *dataSpace1Pointer = bufferValue;
1672  *dataSpace2Pointer = bufferValue;
1673  }
1674  else{
1675  fillDimension(bufferValue, bufferValue, doBufferZone, doLocal, dataSpace1Pointer, dataSpace2Pointer, dimIndex - 1);
1676  }
1677  }
1678  // Increment the pointers
1679  dataSpace1Pointer += pointerIncrement;
1680  dataSpace2Pointer += pointerIncrement;
1681  }
1682  for(; i < localEdge; i++){
1683  if(doLocal){
1684  if(dimIndex == 0){
1685  *dataSpace1Pointer = localValue;
1686  *dataSpace2Pointer = localValue;
1687  }
1688  else{
1689  fillDimension(localValue, bufferValue, doBufferZone, doLocal, dataSpace1Pointer, dataSpace2Pointer, dimIndex - 1);
1690  }
1691  }
1692  // Increment the pointers
1693  dataSpace1Pointer += pointerIncrement;
1694  dataSpace2Pointer += pointerIncrement;
1695  }
1696  if(doBufferZone){ // Note: we don't need to finish this at all if not doing buffer zone
1697  for(; i < upperBound; i++){
1698  if(dimIndex == 0){
1699  *dataSpace1Pointer = bufferValue;
1700  *dataSpace2Pointer = bufferValue;
1701  }
1702  else{
1703  fillDimension(bufferValue, bufferValue, doBufferZone, doLocal, dataSpace1Pointer, dataSpace2Pointer, dimIndex - 1);
1704  }
1705  }
1706  dataSpace1Pointer += pointerIncrement;
1707  dataSpace2Pointer += pointerIncrement;
1708  }
1709 
1710 }
1711 
1712 template<typename T>
1713 void ValueLayerNDSU<T>::writeDimension(std::ofstream& outfile, T* dataSpacePointer, int* currentPosition, int dimIndex, bool writeSharedBoundaryAreas){
1714  int bufferEdge = AbstractValueLayerND<T>::dimensionData[dimIndex].leftBufferSize;
1715  int localEdge = bufferEdge + AbstractValueLayerND<T>::dimensionData[dimIndex].localWidth;
1716  int upperBound = localEdge + AbstractValueLayerND<T>::dimensionData[dimIndex].rightBufferSize;
1717 
1718  int pointerIncrement = AbstractValueLayerND<T>::places[dimIndex];
1719  int i = 0;
1720  for(; i < bufferEdge; i++){
1721  currentPosition[dimIndex] = i;
1722  if(writeSharedBoundaryAreas){
1723  if(dimIndex == 0){
1724  T val = *dataSpacePointer;
1725  if(val != 0){
1726  for(int j = 0; j < AbstractValueLayerND<T>::numDims; j++) outfile << (currentPosition[j] - AbstractValueLayerND<T>::dimensionData[j].leftBufferSize + AbstractValueLayerND<T>::dimensionData[j].localBoundariesMin) << ",";
1727  outfile << val << endl;
1728  }
1729  }
1730  else{
1731  writeDimension(outfile, dataSpacePointer, currentPosition, dimIndex - 1, writeSharedBoundaryAreas);
1732  }
1733  }
1734  // Increment the pointers
1735  dataSpacePointer += pointerIncrement;
1736  }
1737  for(; i < localEdge; i++){
1738  currentPosition[dimIndex] = i;
1739  if(dimIndex == 0){
1740  T val = *dataSpacePointer;
1741  if(val != 0){
1742  for(int j = 0; j < AbstractValueLayerND<T>::numDims; j++) outfile << (currentPosition[j] - AbstractValueLayerND<T>::dimensionData[j].leftBufferSize + AbstractValueLayerND<T>::dimensionData[j].localBoundariesMin) << ",";
1743  outfile << val << endl;
1744  }
1745  }
1746  else{
1747  writeDimension(outfile, dataSpacePointer, currentPosition, dimIndex - 1, writeSharedBoundaryAreas);
1748  }
1749  // Increment the pointers
1750  dataSpacePointer += pointerIncrement;
1751  }
1752  if(writeSharedBoundaryAreas){ // Note: we don't need to finish this at all if not doing buffer zone
1753  for(; i < upperBound; i++){
1754  currentPosition[dimIndex] = i;
1755  if(dimIndex == 0){
1756  T val = *dataSpacePointer;
1757  if(val != 0){
1758  for(int j = 0; j < AbstractValueLayerND<T>::numDims; j++) outfile << (currentPosition[j] - AbstractValueLayerND<T>::dimensionData[j].leftBufferSize + AbstractValueLayerND<T>::dimensionData[j].localBoundariesMin) << ",";
1759  outfile << *dataSpacePointer << endl;
1760  }
1761  }
1762  else{
1763  writeDimension(outfile, dataSpacePointer, currentPosition, dimIndex - 1, writeSharedBoundaryAreas);
1764  }
1765  }
1766  dataSpacePointer += pointerIncrement;
1767  }
1768 
1769 }
1770 
1771 
1772 template<typename T>
1773 void ValueLayerNDSU<T>::sumInto(T* dataSpace1Pointer, T* dataSpace2Pointer, int dimIndex){
1774  //std::cout << " ON RANK " << repast::RepastProcess::instance()->rank() << " SUMINTO RUNNING WITH DIM INDEX OF " << dimIndex << std::endl;
1775  int bufferEdge = AbstractValueLayerND<T>::dimensionData[dimIndex].leftBufferSize;
1776  int localEdge = bufferEdge + AbstractValueLayerND<T>::dimensionData[dimIndex].localWidth;
1777  //int upperBound = localEdge + AbstractValueLayerND<T>::dimensionData[dimIndex].rightBufferSize;
1778 
1779  int pointerIncrement = AbstractValueLayerND<T>::places[dimIndex];
1780  int leftPointerSkip = pointerIncrement * AbstractValueLayerND<T>::dimensionData[dimIndex].leftBufferSize;
1781  //int rightPointerSkip = pointerIncrement * AbstractValueLayerND<T>::dimensionData[dimIndex].rightBufferSize;
1782 
1783  // Skip the left buffer zone
1784  dataSpace1Pointer += leftPointerSkip;
1785  dataSpace2Pointer += leftPointerSkip;
1786 
1787  // Loop local edge to local edge
1788  for(int i = bufferEdge; i < localEdge; i++){
1789  if(dimIndex == 0){
1790  //if(*dataSpace2Pointer > 0) std::cout << " ON RANK " << repast::RepastProcess::instance()->rank() << " SUMINTO FOUND VALUE OF " << *dataSpace2Pointer << " ADDING TO " << *dataSpace1Pointer << " at " << i << " dimIndex " << dimIndex << std::endl;
1791  *dataSpace1Pointer += *dataSpace2Pointer; // Add space 2's value into space 1
1792  *dataSpace2Pointer = 0; // Zero out space 2
1793  }
1794  else sumInto(dataSpace1Pointer, dataSpace2Pointer, dimIndex - 1); // Recursive call
1795  dataSpace1Pointer += pointerIncrement;
1796  dataSpace2Pointer += pointerIncrement;
1797  }
1798 
1799 }
1800 
1801 
1802 
1803 
1804 
1805 
1806 
1807 }
1808 
1809 #endif /* VALUELAYERND_H_ */
repast::ValueLayerNDSU::setSecondaryValueAt
virtual T setSecondaryValueAt(T val, Point< int > location, bool &errFlag)
Sets the specified value to the value in the non-current data bank at the given location.
Definition: ValueLayerND.h:1532
repast::CartesianTopology
Definition: CartesianTopology.h:55
repast::CartesianTopology::trim
RelativeLocation trim(int rank, RelativeLocation volume)
Trims the relative location volume to only valid values.
Definition: CartesianTopology.cpp:105
repast::GridDimensions::extents
const Point< double > & extents() const
Gets the extents along each dimension.
Definition: GridDimensions.h:90
repast::AbstractValueLayerND::addValueAt
virtual T addValueAt(T val, Point< int > location, bool &errFlag)=0
Adds to the value in the grid at a specific location Returns the new value.
repast::ValueLayerND::initialize
virtual void initialize(T initialValue, bool fillBufferZone=false, bool fillLocal=true)
Inherited from AbstractValueLayerND.
Definition: ValueLayerND.h:1131
repast::RepastProcess::rank
int rank() const
Gets the rank of this process.
Definition: RepastProcess.h:378
repast::ValueLayerND::synchronize
virtual void synchronize()
Inherited from AbstractValueLayerND.
Definition: ValueLayerND.h:1212
repast::RelativeLocation::getDirectionIndex
static int getDirectionIndex(vector< int > dirVec)
Assumes that the vector given can be reduced to a 'unit' vector (in which all values are either -1,...
Definition: RelativeLocation.cpp:51
repast::RelativeLocation::getMaxIndex
int getMaxIndex()
Gets the maximum index value; this will be one less than the total number of values.
Definition: RelativeLocation.cpp:185
repast::AbstractValueLayerND::getIndexes
vector< int > getIndexes(vector< int > location, bool isSimplified=false)
Gets a vector of the indexed locations.
Definition: ValueLayerND.h:635
repast::RelativeLocation::getReverseDirectionIndex
static int getReverseDirectionIndex(vector< int > dirVec)
Assumes that the vector given can be reduced to a 'unit' vector (in which all values are either -1,...
Definition: RelativeLocation.cpp:60
repast::ValueLayerNDSU::flowback
void flowback()
ValueLayerNDSU can do something that no other value layer- or, in fact, any other object in Repast HP...
Definition: ValueLayerND.h:1590
repast::AbstractValueLayerND::AbstractValueLayerND
AbstractValueLayerND(vector< int > processesPerDim, GridDimensions globalBoundaries, int bufferSize, bool periodic)
Constructor.
Definition: ValueLayerND.h:562
repast::ValueLayerNDSU::switchValueLayer
void switchValueLayer()
Switch from one value layer to the other.
Definition: ValueLayerND.h:1500
repast::AbstractValueLayerND::initialize
virtual void initialize(T initialValue, bool fillBufferZone=false, bool fillLocal=true)=0
Initializes the array to the specified value.
repast::CartesianTopology::getRank
int getRank(std::vector< int > &loc, std::vector< int > &relLoc)
Gets the rank of the process at the specified offset from the specified location.
Definition: CartesianTopology.cpp:62
repast::ValueLayerNDSU::getValueAt
virtual T getValueAt(Point< int > location, bool &errFlag)
Inherited from AbstractValueLayerND.
Definition: ValueLayerND.h:1438
repast::AbstractValueLayerND::getValueAt
virtual T getValueAt(Point< int > location, bool &errFlag)=0
Gets the value in the grid at a specific location.
repast::GridDimensions::origin
const Point< double > & origin() const
Gets the origin.
Definition: GridDimensions.h:83
repast::ValueLayerNDSU::copyCurrentToSecondary
virtual void copyCurrentToSecondary()
Copies the data in the current value layer to the secondary layer.
Definition: ValueLayerND.h:1578
repast::ValueLayerNDSU::write
virtual void write(string fileLocation, string filetag, bool writeSharedBoundaryAreas=false)
Write this rank's data to a CSV file.
Definition: ValueLayerND.h:1477
repast::AbstractValueLayerND::isInLocalBounds
virtual bool isInLocalBounds(vector< int > coords)
Returns true only if the coordinates given are within the local boundaries.
Definition: ValueLayerND.h:621
repast::DimensionDatum::getTransformedCoord
int getTransformedCoord(int originalCoord)
Given a coordinate in global simulation coordinates, returns the value in simplified coordinates.
Definition: ValueLayerND.h:225
repast::RelativeLocation::getCurrentValue
vector< int > getCurrentValue()
Gets the array of current values.
Definition: RelativeLocation.cpp:173
repast::CartesianTopology::getCoordinates
void getCoordinates(int rank, std::vector< int > &coords)
Gets the coordinates in the MPI Cartesian Communicator for the specified rank.
Definition: CartesianTopology.cpp:81
repast::ValueLayerND::setValueAt
virtual T setValueAt(T val, Point< int > location, bool &errFlag)
Inherited from AbstractValueLayerND.
Definition: ValueLayerND.h:1166
repast::AbstractValueLayerND
An AbstractValueLayerND is the abstract parent class for N-dimensional value layers.
Definition: ValueLayerND.h:253
repast::DimensionDatum::~DimensionDatum
virtual ~DimensionDatum()
Destructor.
Definition: ValueLayerND.h:99
repast::RelativeLocation::getIndex
int getIndex(vector< int > value)
Gets the index value associated with the specified position.
Definition: RelativeLocation.cpp:197
repast::GridDimensions
Basic structure for specifying grid dimenions.
Definition: GridDimensions.h:58
repast::DimensionDatum::report
void report(int dimensionNumber)
Writes a report to the std out file.
Definition: ValueLayerND.h:173
repast::AbstractValueLayerND::getIndex
int getIndex(vector< int > location, bool isSimplified=false)
Given a location in global simulation coordinates, get the offset from the global base pointer to the...
Definition: ValueLayerND.h:643
repast::ValueLayerNDSU::getSecondaryValueAt
virtual T getSecondaryValueAt(Point< int > location, bool &errFlag)
Gets the specified value to the value in the non-current data bank at the given location.
Definition: ValueLayerND.h:1556
repast::AbstractValueLayerND::synchronize
virtual void synchronize()=0
Synchronizes across processes.
repast::ValueLayerNDSU::setValueAt
virtual T setValueAt(T val, Point< int > location, bool &errFlag)
Inherited from AbstractValueLayerND.
Definition: ValueLayerND.h:1422
repast::ValueLayerNDSU::addValueAt
virtual T addValueAt(T val, Point< int > location, bool &errFlag)
Inherited from AbstractValueLayerND.
Definition: ValueLayerND.h:1406
repast::ValueLayerNDSU::addSecondaryValueAt
virtual T addSecondaryValueAt(T val, Point< int > location, bool &errFlag)
Adds the specified value to the value in the non-current data bank at the given location.
Definition: ValueLayerND.h:1508
repast::ValueLayerND
The ValueLayerND class is an N-dimensional layer of values.
Definition: ValueLayerND.h:770
repast::RankDatum
The RankDatum struct stores the data that the ValueLayerND class will need for each of its 3^N - 1 ne...
Definition: ValueLayerND.h:65
repast::RepastProcess::instance
static RepastProcess * instance()
Gets this RepastProcess.
Definition: RepastProcess.cpp:126
repast::AbstractValueLayerND::getLocalBoundaries
const GridDimensions & getLocalBoundaries()
Gets the local boundaries for this process's part of the value layer.
Definition: ValueLayerND.h:314
repast::DimensionDatum::isInLocalBounds
bool isInLocalBounds(int originalCoord)
Returns true if the specified coordinate is within the local boundaries on this dimension.
Definition: ValueLayerND.h:242
repast::ValueLayerNDSU::copySecondaryToCurrent
virtual void copySecondaryToCurrent()
Copies the data in the secondary layer to the current value layer.
Definition: ValueLayerND.h:1584
repast::ValueLayerND::getValueAt
virtual T getValueAt(Point< int > location, bool &errFlag)
Inherited from AbstractValueLayerND.
Definition: ValueLayerND.h:1201
repast::ValueLayerNDSU::initialize
virtual void initialize(T initialValue, bool fillBufferZone=false, bool fillLocal=true)
Inherited from AbstractValueLayerND.
Definition: ValueLayerND.h:1396
repast::ValueLayerNDSU
ValueLayerNDSU is a version of the ValueLayerND class that facilitates SynchronousUpdating: that is,...
Definition: ValueLayerND.h:892
repast::Point::coords
const std::vector< T > & coords() const
Gets the coordinates of this point as a vector.
Definition: Point.h:229
repast::ValueLayerNDSU::synchronize
virtual void synchronize()
Inherited from AbstractValueLayerND.
Definition: ValueLayerND.h:1453
repast::DimensionDatum::getIndexedCoord
int getIndexedCoord(int originalCoord, bool isSimplified=false)
Given a coordinate, returns the index of that coordinate.
Definition: ValueLayerND.h:237
repast::ValueLayerND::addValueAt
virtual T addValueAt(T val, Point< int > location, bool &errFlag)
Inherited from AbstractValueLayerND.
Definition: ValueLayerND.h:1141
repast::DimensionDatum
The DimensionDatum class stores all of the data that the ValueLayerND class will need for each dimens...
Definition: ValueLayerND.h:82
repast::Point< int >
repast::AbstractValueLayerND::setValueAt
virtual T setValueAt(T val, Point< int > location, bool &errFlag)=0
Sets the value in the grid at a specific location Returns the new value.
repast::RelativeLocation
A RelativeLocation is a vector of integers that express a relative location in a coordinate system; t...
Definition: RelativeLocation.h:103
repast::DimensionDatum::getSendReceiveSize
int getSendReceiveSize(int relativeLocation)
Gets the size of the data to be sent during synchronization.
Definition: ValueLayerND.h:214
repast::ValueLayerND::write
void write(string fileLocation, string filetag, bool writeSharedBoundaryAreas=false)
Write the values in this ValueLayer to a .csv file.
Definition: ValueLayerND.h:1237
repast::CartesianTopology::getDimensions
GridDimensions getDimensions(int rank, GridDimensions globalBoundaries)
Gets the GridDimensions boundaries for the specified rank.
Definition: CartesianTopology.cpp:87
repast::RelativeLocation::validNonCenter
bool validNonCenter()
Returns false when the values are all zeroes, true otherwise.
Definition: RelativeLocation.cpp:219