00001 #ifndef LIBGEODECOMP_MISC_TESTCELL_H
00002 #define LIBGEODECOMP_MISC_TESTCELL_H
00003
00004 #include <libgeodecomp/config.h>
00005 #include <libgeodecomp/misc/apitraits.h>
00006 #include <libgeodecomp/geometry/coord.h>
00007 #include <libgeodecomp/geometry/coordbox.h>
00008 #include <libgeodecomp/geometry/stencils.h>
00009 #include <libgeodecomp/storage/coordmap.h>
00010 #include <libgeodecomp/storage/fixedneighborhood.h>
00011
00012 #include <iostream>
00013 #include <libflatarray/flat_array.hpp>
00014
00015 namespace LibGeoDecomp {
00016
00017 namespace TestCellHelpers {
00018
00019 class EmptyAPI
00020 {
00021 };
00022
00023 class SoAAPI :
00024 public APITraits::HasSoA,
00025 public APITraits::HasFixedCoordsOnlyUpdate,
00026 public APITraits::HasUpdateLineX
00027 {};
00028
00029 template<int DIM>
00030 class TopologyType
00031 {
00032 public:
00033 typedef typename Topologies::Cube<DIM>::Topology Topology;
00034 };
00035
00036
00037 template<>
00038 class TopologyType<3>
00039 {
00040 public:
00041 typedef Topologies::Torus<3>::Topology Topology;
00042 };
00043
00044 class StdOutput
00045 {
00046 public:
00047 template<typename T>
00048 const StdOutput& operator<<(T output) const
00049 {
00050 std::cout << output;
00051 return *this;
00052 }
00053 };
00054
00055 class NoOutput
00056 {
00057 public:
00058 template<typename T>
00059 const NoOutput& operator<<(T ) const
00060 {
00061 return *this;
00062 }
00063 };
00064
00065 template<class STENCIL, int INDEX>
00066 class CheckNeighbor
00067 {
00068 public:
00069 typedef typename STENCIL::template Coords<INDEX> RelCoord;
00070
00071 template<class TESTCELL, class NEIGHBORHOOD>
00072 void operator()(bool *isValid, TESTCELL *cell, const NEIGHBORHOOD& neighborhood)
00073 {
00074 (*isValid) &= cell->checkNeighbor(neighborhood[RelCoord()], RelCoord());
00075 }
00076 };
00077
00078 }
00079
00083 template<
00084 int DIM,
00085 typename STENCIL = Stencils::Moore<DIM, 1>,
00086 typename TOPOLOGY = typename TestCellHelpers::TopologyType<DIM>::Topology,
00087 typename ADDITIONAL_API = TestCellHelpers::EmptyAPI,
00088 typename OUTPUT = TestCellHelpers::StdOutput>
00089 class TestCell
00090 {
00091 public:
00092 friend class Typemaps;
00093 friend class TestCellTest;
00094
00095 static const int DIMENSIONS = DIM;
00096 static const unsigned NANO_STEPS = 27;
00097
00098 class API :
00099 public ADDITIONAL_API,
00100 public APITraits::HasTopology<TOPOLOGY>,
00101 public APITraits::HasNanoSteps<NANO_STEPS>,
00102 public APITraits::HasStencil<STENCIL>
00103 #ifdef LIBGEODECOMP_WITH_MPI
00104 , public APITraits::HasAutoGeneratedMPIDataType<Typemaps>
00105 #endif
00106 {};
00107
00108 Coord<DIM> pos;
00109 CoordBox<DIM> dimensions;
00110 unsigned cycleCounter;
00111 bool isEdgeCell;
00112 bool isValid;
00113 double testValue;
00114
00115 static double defaultValue()
00116 {
00117 return 666;
00118 }
00119
00120 TestCell() :
00121 cycleCounter(0),
00122 isEdgeCell(false),
00123 isValid(false),
00124 testValue(defaultValue())
00125 {}
00126
00127 TestCell(
00128 const Coord<DIM>& pos,
00129 const Coord<DIM>& gridDim,
00130 const unsigned& cycleCounter = 0,
00131 const double& testValue = defaultValue()) :
00132 pos(pos),
00133 dimensions(Coord<DIM>(), gridDim),
00134 cycleCounter(cycleCounter),
00135 isValid(true),
00136 testValue(testValue)
00137 {
00138 isEdgeCell = !inBounds(pos);
00139 }
00140
00141 const bool& valid() const
00142 {
00143 return isValid;
00144 }
00145
00146 bool inBounds(const Coord<DIM>& c) const
00147 {
00148 return !TOPOLOGY::isOutOfBounds(c, dimensions.dimensions);
00149 }
00150
00151 bool operator==(const TestCell& other) const
00152 {
00153 return (pos == other.pos)
00154 && (dimensions == other.dimensions)
00155 && (cycleCounter == other.cycleCounter)
00156 && (isEdgeCell == other.isEdgeCell)
00157 && (isValid == other.isValid)
00158 && (testValue == other.testValue);
00159 }
00160
00161 bool operator!=(const TestCell& other) const
00162 {
00163 return !((*this) == other);
00164 }
00165
00166 template<typename COORD_MAP>
00167 void update(const COORD_MAP& neighborhood, const unsigned& nanoStep)
00168 {
00169
00170 *this = TestCell(neighborhood[FixedCoord<0, 0, 0>()]);
00171
00172 if (isEdgeCell) {
00173 OUTPUT() << "TestCell error: update called for edge cell\n";
00174 isValid = false;
00175 return;
00176 }
00177
00178 Stencils::Repeat<STENCIL::VOLUME,
00179 TestCellHelpers::CheckNeighbor,
00180 STENCIL>()(&isValid, this, neighborhood);
00181
00182 if (nanoStep >= NANO_STEPS) {
00183 OUTPUT() << "TestCell error: nanoStep too large: "
00184 << nanoStep << "\n";
00185 isValid = false;
00186 return;
00187 }
00188
00189 unsigned expectedNanoStep = cycleCounter % NANO_STEPS;
00190 if (nanoStep != expectedNanoStep) {
00191 OUTPUT() << "TestCell error: nanoStep out of sync. got "
00192 << nanoStep << " but expected "
00193 << expectedNanoStep << "\n";
00194 isValid = false;
00195 return;
00196 }
00197
00198 ++cycleCounter;
00199 }
00200
00201 template<typename NEIGHBORHOOD>
00202 static void updateLineX(
00203 TestCell *targetLine,
00204 long *index,
00205 long indexEnd,
00206 const NEIGHBORHOOD& hood,
00207 unsigned nanoStep)
00208 {
00209 for (; *index < indexEnd; ++(*index)) {
00210 targetLine[*index].update(hood, nanoStep);
00211 }
00212 }
00213
00214 template<typename ACCESSOR1, typename ACCESSOR2>
00215 static void updateLineX(
00216 ACCESSOR1 hoodOld, int indexEnd,
00217 ACCESSOR2 hoodNew, unsigned nanoStep)
00218 {
00219 for (; hoodOld.index() < indexEnd; ++hoodOld.index(), ++hoodNew.index) {
00220 TestCell cell;
00221 cell.update(hoodOld, nanoStep);
00222 hoodNew << cell;
00223 }
00224 }
00225
00226 std::string toString() const
00227 {
00228 std::ostringstream ret;
00229 ret << "TestCell\n"
00230 << " pos: " << pos << "\n"
00231 << " dimensions: " << dimensions << "\n"
00232 << " cycleCounter: " << cycleCounter << "\n"
00233 << " isEdgeCell: " << (isEdgeCell ? "true" : "false") << "\n"
00234 << " testValue: " << testValue << "\n"
00235 << " isValid: " << (isValid ? "true" : "false") << "\n";
00236 return ret.str();
00237 }
00238
00239
00240
00241 bool checkNeighbor(
00242 const TestCell& other,
00243 const Coord<DIM>& relativeLoc) const
00244 {
00245 if (!other.isValid) {
00246 OUTPUT() << "Update Error for " << toString() << ":\n"
00247 << "Invalid Neighbor at " << relativeLoc << ":\n"
00248 << other.toString()
00249 << "--------------" << "\n";
00250 return false;
00251 }
00252 bool otherShouldBeEdge = !inBounds(pos + relativeLoc);
00253 if (other.isEdgeCell != otherShouldBeEdge) {
00254 OUTPUT() << "TestCell error: bad edge cell (expected: "
00255 << otherShouldBeEdge << ", is: "
00256 << other.isEdgeCell << " at relative coord "
00257 << relativeLoc << ")\n";
00258 return false;
00259 }
00260 if (!otherShouldBeEdge) {
00261 if (other.cycleCounter != cycleCounter) {
00262 OUTPUT() << "Update Error for TestCell "
00263 << toString() << ":\n"
00264 << "cycle counter out of sync with neighbor "
00265 << other.toString() << "\n";
00266 return false;
00267 }
00268 if (other.dimensions != dimensions) {
00269 OUTPUT() << "TestCell error: grid dimensions differ. Expected: "
00270 << dimensions << ", but got " << other.dimensions << "\n";
00271 return false;
00272 }
00273
00274 Coord<DIM> rawPos = pos + relativeLoc;
00275 Coord<DIM> expectedPos =
00276 TOPOLOGY::normalize(rawPos, dimensions.dimensions);
00277
00278 if (other.pos != expectedPos) {
00279 OUTPUT() << "TestCell error: other position "
00280 << other.pos
00281 << " doesn't match expected "
00282 << expectedPos << "\n";
00283 return false;
00284 }
00285 }
00286 return true;
00287 }
00288
00289 template<int X, int Y, int Z>
00290 bool checkNeighbor(
00291 const TestCell& other,
00292 FixedCoord<X, Y, Z> coord) const
00293 {
00294 return checkNeighbor(other, Coord<DIM>(coord));
00295 }
00296 };
00297
00298 typedef TestCell<
00299 3,
00300 Stencils::Moore<3, 1>,
00301 Topologies::Cube<3>::Topology,
00302 TestCellHelpers::SoAAPI
00303 > TestCellSoA;
00304
00312 class TestCellMPIDatatypeHelper
00313 {
00314 friend class Typemaps;
00315 TestCell<1> a;
00316 TestCell<2> b;
00317 TestCell<3> c;
00318 };
00319
00320 }
00321
00322 LIBFLATARRAY_REGISTER_SOA(LibGeoDecomp::TestCellSoA, ((LibGeoDecomp::Coord<3>)(pos))((LibGeoDecomp::CoordBox<3>)(dimensions))((unsigned)(cycleCounter))((bool)(isEdgeCell))((bool)(isValid))((double)(testValue)))
00323
00324 template<
00325 typename CharT,
00326 typename Traits,
00327 int Dim,
00328 typename Stencil,
00329 typename Topology,
00330 typename AdditionalAPI,
00331 typename Output>
00332 std::basic_ostream<CharT, Traits>&
00333 operator<<(std::basic_ostream<CharT, Traits>& os,
00334 const LibGeoDecomp::TestCell<Dim, Stencil, Topology, AdditionalAPI, Output>& cell)
00335 {
00336 os << cell.toString();
00337 return os;
00338 }
00339
00340 #endif