1 #include <libgeodecomp.h>
2
3 using namespace LibGeoDecomp;
4
5
6 /**
7 * A simple Adaptive Mesh Refinement (AMR) demo with automatic grid
8 * adaptation. It computes a simple heat dissipation with fixed
9 * heating/cooling points.
10 *
11 * We're using in-cell refinement, which means that all
12 * finer grids (patches) are stored within cells of the coarsest
13 * level. This implies that these cells do not all have the same
14 * memory footprint. The code has been optimized for brevity and
15 * legibility, not performance.
16 */
17 template<
18 int SUBLEVEL_DIM_X = 4,
19 int SUBLEVEL_DIM_Y = SUBLEVEL_DIM_X,
20 int SUBLEVEL_TILE_SIZE = (SUBLEVEL_DIM_X * SUBLEVEL_DIM_Y),
21 int DELTA_MAX = 10>
22 class AMRDiffusionCell
23 {
24 public:
25 typedef AMRDiffusionCell value_type;
26
sublevelDimX()27 inline static int sublevelDimX()
28 {
29 return SUBLEVEL_DIM_X;
30 }
31
sublevelDimY()32 inline static int sublevelDimY()
33 {
34 return SUBLEVEL_DIM_Y;
35 }
36
37 // const static int PATCH_DIM_BITS = 3;
38 // // sublevel patches (refined grids) are PATCH_DIM x PATCH_DIM in size.
39 // const static int PATCH_DIM = 1 >< PATCH_DIM_BITS;
40 // const static int PATCH_DIM_BITMASK = PATCH_DIM - 1;
41
42 // const static int BASE_DIM_BITS = 20;
43 // const static int BASE_DIM = 1 << BASE_DIM_BITS;
44 // const static int BASE_DIM_BITMASK = BASE_DIM - 1;
45
46 // fixme: move this to dedicated class/file
47 template<typename NEIGHBORHOOD>
48 class HoodAdapter
49 {
50 public:
HoodAdapter(const NEIGHBORHOOD & hood)51 inline HoodAdapter(const NEIGHBORHOOD& hood) :
52 hood(hood)
53 {}
54
55 template<int X, int Y>
operator ()(FixedCoord<X,Y,0>,const AMRDiffusionCell & origin) const56 const AMRDiffusionCell *operator()(FixedCoord<X, Y, 0>, const AMRDiffusionCell& origin) const
57 {
58 Coord<2> searchPoint = origin.logicalCoord +
59 Coord<2>(X * origin.logicalOffset.x(),
60 Y * origin.logicalOffset.y());
61
62 // std::cout << "looking for " << searchPoint << "\n";
63 const AMRDiffusionCell *res = 0;
64
65 if (origin.logicalCoord == Coord<2>(16, 0)) {
66 // std::cout << " looking for " << searchPoint << "\n"
67 // << " FixedCoord<" << X << ", " << Y << ">\n";
68 }
69
70 // most accesses go to (0, 0)
71 res = hood[FixedCoord<0, 0>()].lookup(searchPoint);
72 if (res) {
73 // if (origin.logicalCoord == Coord<2>(16, 0)) std::cout << " found at A\n";
74 return res;
75 }
76
77 res = hood[FixedCoord<-1, -1>()].lookup(searchPoint);
78 if (res) {
79 // if (origin.logicalCoord == Coord<2>(16, 0)) std::cout << " found at B\n";
80 return res;
81 }
82
83 res = hood[FixedCoord< 0, -1>()].lookup(searchPoint);
84 if (res) {
85 // if (origin.logicalCoord == Coord<2>(16, 0)) std::cout << " found at C\n";
86 return res;
87 }
88
89 res = hood[FixedCoord< 1, -1>()].lookup(searchPoint);
90 if (res) {
91 // if (origin.logicalCoord == Coord<2>(16, 0)) std::cout << " found at D\n";
92 return res;
93 }
94
95 // same row:
96 res = hood[FixedCoord<-1, 0>()].lookup(searchPoint);
97 if (res) {
98 // if (origin.logicalCoord == Coord<2>(16, 0)) std::cout << " found at E\n";
99 return res;
100 }
101
102 res = hood[FixedCoord< 1, 0>()].lookup(searchPoint);
103 if (res) {
104 // if (origin.logicalCoord == Coord<2>(16, 0)) std::cout << " found at F\n";
105 return res;
106 }
107
108 // lower row:
109 res = hood[FixedCoord<-1, 1>()].lookup(searchPoint);
110 if (res) {
111 // if (origin.logicalCoord == Coord<2>(16, 0)) std::cout << " found at G\n";
112 return res;
113 }
114
115 res = hood[FixedCoord< 0, 1>()].lookup(searchPoint);
116 if (res) {
117 // if (origin.logicalCoord == Coord<2>(16, 0)) std::cout << " found at H\n";
118 return res;
119 }
120
121 res = hood[FixedCoord< 1, 1>()].lookup(searchPoint);
122 if (res) {
123 // if (origin.logicalCoord == Coord<2>(16, 0)) std::cout << " found at I\n";
124 return res;
125 }
126
127 // std::cout << "searchPoint: " << searchPoint << "\n"
128 // << "origin: " << origin.logicalCoord << ", " << origin.logicalOffset << "\n";
129 throw std::logic_error("neighbor not found");
130 }
131
132 private:
133 const NEIGHBORHOOD& hood;
134 };
135
136 // fixme: move this to dedicated class/file
137 // fixme: ignore non-leaf nodes in size calculation and visitor pattern?
138 class Iterator
139 {
140 public:
Iterator(const AMRDiffusionCell * cell)141 Iterator(const AMRDiffusionCell *cell) :
142 cursors(1, cell)
143 {}
144
operator *() const145 const AMRDiffusionCell& operator*() const
146 {
147 return *cursors.back();
148 }
149
operator ++()150 void operator++()
151 {
152 // std::cout << "operator++1\n";
153 if (cursors.back()->sublevel.size() != 0) {
154 cursors.push_back(&cursors.back()->sublevel[0][0]);
155 // std::cout << "operator++2b\n";
156 return;
157 }
158
159 cursors.back()++;
160 // we'll need to pop all cursors which have reached the
161 // end of their superordinate level (but preserve the
162 // top-most cursor as it may be part of the topmost layer)
163 while ((cursors.size() > 1) &&
164 ((*(cursors.end() - 2))->sublevel[0].end() == cursors.back())) {
165 cursors.pop_back();
166 cursors.back()++;
167 }
168 // std::cout << "operator++2a\n";
169 }
170
operator ==(const Iterator & other) const171 inline bool operator==(const Iterator& other) const
172 {
173 return cursors.back() == other.cursors.back();
174 }
175
operator !=(const Iterator & other) const176 inline bool operator!=(const Iterator& other) const
177 {
178 return cursors.back() != other.cursors.back();
179 }
180
operator ->() const181 inline const AMRDiffusionCell* operator->() const
182 {
183 return cursors.back();
184 }
185
186 private:
187 std::vector<const AMRDiffusionCell*> cursors;
188 };
189
190 typedef Iterator iterator;
191 typedef Iterator const_iterator;
192
193 // template<typename NEIGHBORHOOD>
194 // class LookupHelper
195 // {
196 // public:
197 // LookupHelper(const NEIGHBORHOOD *hood) :
198 // hood(hood)
199 // {}
200
201 // inline
202 // const AMRDiffusionCell& operator()(const unsigned long x, const unsigned long y) const
203 // {
204 // Coord<2> relativeCoord;
205 // unsigned long baseCoordX = x & BASE_DIM_BITMASK;
206 // unsigned long baseCoordY = y & BASE_DIM_BITMASK;
207
208 // if (baseCoordX < centerX) {
209 // relativeCoord.x() = -1;
210 // } else {
211 // if (baseCoordX > centerX) {
212 // relativeCoord.x() = 1;
213 // }
214 // }
215
216 // if (baseCoordY < centerY) {
217 // relativeCoord.y() = -1;
218 // } else {
219 // if (baseCoordY > centerY) {
220 // relativeCoord.y() = 1;
221 // }
222 // }
223
224 // return (*this)((*hood)[relativeCoord], x >> BASE_DIM_BITS, y >> BASE_DIM_BITS);
225 // }
226
227 // inline
228 // const AMRDiffusionCell& operator()(const AMRDiffusionCell& cell, const unsigned long x, const unsigned long y) const
229 // {
230 // if (cell.dim == Coord<2>()) {
231 // return cell;
232 // }
233
234 // // Coord<2> relativeCoord(
235 // // x & PATCH_DIM_BITMASK,
236 // // y & PATCH_DIM_BITMASK);
237 // // return (*this)(cell[relativeCoord], x >> PATCH_DIM_BITS, y >> PATCH_DIM_BITS);
238 // // fixme
239 // return cell;
240 // }
241
242 // private:
243 // const NEIGHBORHOOD *hood;
244 // unsigned long centerX;
245 // unsigned long centerY;
246 // };
247
248
AMRDiffusionCell(const FloatCoord<2> & pos=FloatCoord<2> (0,0),const FloatCoord<2> & dim=FloatCoord<2> (1,1),const Coord<2> & logicalCoord=Coord<2> (),const Coord<2> & logicalOffset=Coord<2> (0,0),const double value=0,const double influx=0,const int depth=0,const int maxDepth=0,const bool edgeCell=false,const double contagiousFlag=0)249 inline AMRDiffusionCell(
250 const FloatCoord<2>& pos = FloatCoord<2>(0, 0),
251 const FloatCoord<2>& dim = FloatCoord<2>(1, 1),
252 const Coord<2>& logicalCoord = Coord<2>(),
253 const Coord<2>& logicalOffset = Coord<2>(0, 0),
254 const double value = 0,
255 const double influx = 0,
256 const int depth = 0,
257 const int maxDepth = 0,
258 const bool edgeCell = false,
259 const double contagiousFlag = 0) :
260 pos(pos),
261 dim(dim),
262 logicalCoord(logicalCoord),
263 logicalOffset(logicalOffset),
264 value(value),
265 influx(influx),
266 depth(depth),
267 maxDepth(maxDepth),
268 edgeCell(edgeCell),
269 contagiousFlag(contagiousFlag)
270 {}
271
272 class API : public APITraits::HasUnstructuredGrid
273 {};
274
275 // fixme: use 2 nano steps to avoid refinement/coarseing to create gaps of 2 refinement levels
276
277 template<typename NEIGHBORHOOD>
update(const NEIGHBORHOOD & hood,int)278 void update(const NEIGHBORHOOD& hood, int)
279 {
280 *this = hood[FixedCoord<0, 0>()];
281 HoodAdapter<NEIGHBORHOOD> adapter(hood);
282 actualUpdate(adapter);
283 }
284
begin() const285 Iterator begin() const
286 {
287 return Iterator(this);
288 }
289
end() const290 Iterator end() const
291 {
292 return Iterator(this + 1);
293 }
294
size() const295 std::size_t size() const
296 {
297 std::size_t ret = 1;
298 if (sublevel.size()) {
299 for (const AMRDiffusionCell *i = sublevel[0].begin(); i != sublevel[0].end(); ++i) {
300 ret += i->size();
301 }
302 }
303
304 return ret;
305 }
306
getPoint() const307 FloatCoord<2> getPoint() const
308 {
309 return pos;
310 }
311
getShape() const312 std::vector<FloatCoord<2> > getShape() const
313 {
314 std::vector<FloatCoord<2> > shape;
315 shape << pos
316 << pos + FloatCoord<2>(dim[0], 0)
317 << pos + dim
318 << pos + FloatCoord<2>(0, dim[1]);
319 return shape;
320 }
321
322 // fixme: private:
323
324 std::vector<FixedArray<AMRDiffusionCell, SUBLEVEL_TILE_SIZE> > sublevel;
325 FloatCoord<2> pos;
326 FloatCoord<2> dim;
327 Coord<2> logicalCoord;
328 Coord<2> logicalOffset;
329 double value;
330 double influx;
331 int depth;
332 int maxDepth;
333 bool edgeCell;
334 double contagiousFlag;
335
336 #define HOOD(X, Y) hood(FixedCoord<X, Y>(), *this)
337
338 template<typename NEIGHBORHOOD>
actualUpdate(const NEIGHBORHOOD & hood)339 void actualUpdate(const NEIGHBORHOOD& hood)
340 {
341 // fixme
342 value =
343 influx +
344 0.25 *
345 (HOOD( 0, -1)->value +
346 HOOD(-1, 0)->value +
347 HOOD( 1, 0)->value +
348 HOOD( 0, 1)->value);
349
350 // if (contagiousFlag == 1.0) {
351 // std::cout << "infection at " << logicalCoord << ", " << logicalOffset << "\n";
352 // }
353
354 // if (logicalCoord == Coord<2>(16, 0)) {
355 // const AMRDiffusionCell *c = HOOD(-1, 0);
356 // std::cout << "state at " << logicalCoord << " is " << contagiousFlag
357 // << ", left neighbor is " << c->logicalCoord
358 // << " of size " << c->logicalOffset
359 // << " with " << c->contagiousFlag
360 // << " and edge: " << c->edgeCell
361 // << "\n";
362 // }
363
364 contagiousFlag =
365 std::max(contagiousFlag,
366 std::max(HOOD(0, -1)->contagiousFlag,
367 std::max(HOOD(-1, 0)->contagiousFlag,
368 std::max(HOOD(1, 0)->contagiousFlag,
369 HOOD(0, 1)->contagiousFlag))));
370
371 if (sublevel.size()) {
372 for (int i = 0; i < sublevel[0].size(); ++i) {
373 sublevel[0][i].actualUpdate(hood);
374 }
375 } else {
376 if (depth < maxDepth) {
377 // check for refinement, fixme: extract into method
378 double delta = 0;
379 delta = std::max(delta, std::abs(value - HOOD(0, -1)->value));
380 delta = std::max(delta, std::abs(value - HOOD(0, 1)->value));
381 delta = std::max(delta, std::abs(value - HOOD(-1, 0)->value));
382 delta = std::max(delta, std::abs(value - HOOD( 1, 0)->value));
383
384 if (delta > DELTA_MAX) {
385 sublevel.resize(1);
386 FloatCoord<2> sublevelDim(
387 dim[0] / SUBLEVEL_DIM_X,
388 dim[1] / SUBLEVEL_DIM_Y);
389
390 Coord<2> newLogicalOffset(
391 logicalOffset.x() / SUBLEVEL_DIM_X,
392 logicalOffset.y() / SUBLEVEL_DIM_Y);
393
394 for (int y = 0; y < SUBLEVEL_DIM_Y; ++y) {
395 for (int x = 0; x < SUBLEVEL_DIM_X; ++x) {
396 Coord<2> index(x, y);
397 FloatCoord<2> newPos = pos + sublevelDim.scale(index);
398 Coord<2> newLogicalCoord = logicalCoord + index.scale(newLogicalOffset);
399
400 sublevel[0] << AMRDiffusionCell(
401 newPos,
402 sublevelDim,
403 newLogicalCoord,
404 newLogicalOffset,
405 value,
406 influx,
407 depth + 1,
408 maxDepth,
409 edgeCell,
410 contagiousFlag);
411 }
412 }
413 }
414 }
415 }
416 }
417
lookup(const Coord<2> & searchPoint) const418 const AMRDiffusionCell *lookup(const Coord<2>& searchPoint) const
419 {
420 Coord<2> oppositeSide = logicalCoord + logicalOffset;
421 bool outside =
422 (searchPoint.x() < logicalCoord.x()) ||
423 (searchPoint.x() >= oppositeSide.x()) ||
424 (searchPoint.y() < logicalCoord.y()) ||
425 (searchPoint.y() >= oppositeSide.y());
426
427 if (edgeCell && outside) {
428 // std::cout << " edgeCell, searchPoint : " << searchPoint << "\n"
429 // << " edgeCell, logicalCoord: " << logicalCoord << "\n"
430 // << " edgeCell, oppositeSide: " << oppositeSide << "\n\n";
431 return this;
432 }
433
434 if (edgeCell || outside) {
435 // std::cout << " outside(" << searchPoint << ")\n";
436 return 0;
437 }
438
439 if (sublevel.size() == 0) {
440 // std::cout << " no more sublevels\n";
441 return this;
442 }
443
444 for (std::size_t i = 0; i < sublevel[0].size(); ++i) {
445 const AMRDiffusionCell *ret = sublevel[0][i].lookup(searchPoint);
446 if (ret) {
447 // std::cout << " child hit\n";
448 return ret;
449 }
450 }
451
452 return 0;
453 }
454
455 // {
456 // double delta = 0;
457 // delta = std::max(std::abs(HOOD(0, 1) - HOOD( 0, -1)),
458 // std::abs(HOOD(1, 0) - HOOD(-1, 0)));
459
460
461 // // do not descent if we're already on the finest level
462 // if (sublevel.dimensions == Coord<2>(0, 0)) {
463 // simpleUpdate(hood, delta);
464 // } else {
465 // hierarchicalUpdate(hood, delta);
466 // }
467
468 // }
469
470 // template<typename NEIGHBORHOOD>
471 // void simpleUpdate(const NEIGHBORHOOD& hood, const double delta)
472 // {
473 // // refine if delta of neighbors is too large
474 // if (delta > DELTA_MAX) {
475 // sublevel.resize(Coord<2>(PATCH_DIM, PATCH_DIM));
476 // FloatCoord newDim(dim.x() * (1.0 / PATCH_DIM),
477 // dim.y() * (1.0 / PATCH_DIM));
478
479 // for (int y = 0; y < PATCH_DIM; ++y) {
480 // for (int x = 0; x < PATCH_DIM; ++x) {
481 // sublevel[Coord<2>(x, y)] = AMRDiffusionCell(
482 // pos + FloatCoord<2>(newDim.x() * x, newDim.y() * y),
483 // newDim,
484 // value,
485 // depth + 1);
486 // }
487 // }
488
489 // return;
490 // }
491
492 // value =
493 // (HOOD( 0, -1).value +
494 // HOOD(-1, 0).value +
495 // HOOD( 1, 0).value +
496 // HOOD( 0, 1).value);
497 // }
498
499 // template<typename NEIGHBORHOOD>
500 // void hierarchicalUpdate(const NEIGHBORHOOD& hood, const double delta)
501 // {
502 // // coarsen if delta of neighbors is small enough
503 // if (delta <= DELTA_MAX) {
504 // value = gatherFromSublevel();
505 // sublevel.resize(Coord<2>(0, 0));
506
507 // return;
508 // }
509
510 // // 1 step on coarse level equals PATCH_DIM steps on the
511 // // finer levels.
512 // for (int t = 0; t < PATCH_DIM; ++t) {
513 // updateFinerLevel(hood);
514 // }
515
516 // value = gatherFromSublevel();
517 // }
518
519 // template<typename NEIGHBORHOOD>
520 // void updateFinerLevel(const NEIGHBORHOOD& hood, double delta)
521 // {
522 // for (int y = 0; y < PATCH_DIM; ++y) {
523 // for (int x = 0; x < PATCH_DIM; ++x) {
524 // // fixme: use wrapper object instead of hood
525 // sublevel[Coord<2>(x, y)].actualUpdate(hood);
526 // }
527 // }
528 // }
529
530 // double gatherFromSublevel() const
531 // {
532 // double newValue = 0;
533 // for (int y = 0; y < PATCH_DIM; ++y) {
534 // for (int x = 0; x < PATCH_DIM; ++x) {
535 // newValue += sublevel[Coord(x, y)].value;
536 // }
537 // }
538 // newValue *= 1.0 / (double(PATCH_DIM) * double(PATCH_DIM));
539
540 // return newValue;
541 // }
542
543 #undef HOOD
544 };
545
546 class AMRInitializer : public SimpleInitializer<AMRDiffusionCell<> >
547 {
548 public:
AMRInitializer(const Coord<2> dim,const unsigned steps)549 explicit AMRInitializer(
550 const Coord<2> dim,
551 const unsigned steps) :
552 SimpleInitializer<AMRDiffusionCell<> >(dim, steps)
553 {}
554
grid(GridBase<AMRDiffusionCell<>,2> * ret)555 virtual void grid(GridBase<AMRDiffusionCell<>, 2> *ret)
556 {
557 CoordBox<2> box = ret->boundingBox();
558 int depth = 0;
559 int maxDepth = 2;
560
561 Coord<2> logicalOffset(1, 1);
562 for (int j = 0; j < maxDepth; ++j) {
563 logicalOffset = logicalOffset.scale(
564 Coord<2>(
565 AMRDiffusionCell<>::sublevelDimX(),
566 AMRDiffusionCell<>::sublevelDimY()));
567 }
568
569 Coord<2> logicalEdgePos = box.origin.scale(logicalOffset);
570 Coord<2> logicalEdgeOffset = Coord<2>(
571 logicalOffset.x() * box.dimensions.x(),
572 logicalOffset.y() * box.dimensions.y());
573
574 ret->setEdge(AMRDiffusionCell<>(
575 // fixme:
576 FloatCoord<2>(-1, -1),
577 FloatCoord<2>( 2, 2),
578 logicalEdgePos,
579 logicalEdgeOffset,
580 0.0,
581 0.0,
582 0,
583 0,
584 true));
585
586 for (CoordBox<2>::Iterator i = box.begin(); i != box.end(); ++i) {
587 double influx = 0;
588 if (i->y() == 0) {
589 influx = i->x();
590 if (i->x() >= (box.dimensions.x() / 2)) {
591 influx = box.dimensions.x() - influx - 1;
592 }
593
594 influx *= influx;
595 }
596
597 FloatCoord<2> dim(1, 1);
598 FloatCoord<2> pos = dim.scale(*i);
599
600 Coord<2> logicalPos = i->scale(logicalOffset);
601
602
603 // fixme: kill this?
604 // // no refinement on boundary
605 // if ((i->y() == 0) || (i->y() == (box.dimensions.y() - 1)) ||
606 // (i->x() == 0) || (i->x() == (box.dimensions.x() - 1))) {
607 // maxDepth = 0;
608 // }
609
610 double flag = 0;
611 if (*i == Coord<2>(0, 0)) {
612 flag = 1;
613 }
614 AMRDiffusionCell<> cell(pos, dim, logicalPos, logicalOffset, 0, influx, depth, maxDepth, false, flag);
615 ret->set(*i, cell);
616 }
617 }
618 };
619
620 // class FooBar
621 // {
622 // public:
623
624 // template<typename WRITER>
625 // void dumpData(WRITER *writer)
626 // {
627 // double dim = 10;
628
629 // for (int i = 0; i < 10; ++i) {
630 // for (int x = 0; x < 8; ++x) {
631 // for (int y = 0; y < 8; ++y) {
632 // writer->addQuad(FloatCoord<2>(x * dim, y * dim), FloatCoord<2>(dim, dim));
633 // }
634 // }
635
636 // dim *= 0.125;
637 // }
638 // }
639
640 // int dummy;
641 // };
642
643
main(int argc,char ** argv)644 int main(int argc, char **argv)
645 {
646 // Grid<FooBar> grid(Coord<2>(1, 1));
647 // SiloWriter<FooBar> writer("foobar", 1);
648 // writer.stepFinished(grid, 14, WRITER_INITIALIZED);
649
650 Coord<2> gridDim(15, 10);
651 int maxSteps = 1000;
652 SerialSimulator<AMRDiffusionCell<> > sim(new AMRInitializer(gridDim, maxSteps));
653
654 SiloWriter<AMRDiffusionCell<> > *siloWriter = new SiloWriter<AMRDiffusionCell<> >("AMR", 1);
655 siloWriter->addSelectorForUnstructuredGrid(
656 &AMRDiffusionCell<>::value, "value");
657 siloWriter->addSelectorForUnstructuredGrid(
658 &AMRDiffusionCell<>::contagiousFlag, "flag");
659 sim.addWriter(siloWriter);
660
661 sim.run();
662
663 return 0;
664 }
665