root/src/misc/meshlessadapter.h @ 33:727aed332c25

Revision 33:727aed332c25, 10.5 KB (checked in by Andreas Schaefer <gentryx@…>, 22 months ago)

ContainerCell? can now remove elements, too

Line 
1#ifndef _libgeodecomp_misc_meshlessadapter_h_
2#define _libgeodecomp_misc_meshlessadapter_h_
3
4#include <list>
5#include <set>
6#include <libgeodecomp/misc/floatcoord.h>
7#include <libgeodecomp/misc/grid.h>
8#include <libgeodecomp/misc/supermap.h>
9#include <libgeodecomp/misc/topologies.h>
10
11namespace LibGeoDecomp {
12
13/**
14 * A utility class which supports users in porting meshless codes to
15 * LibGeoDecomp by superimposing a stencil structure, even though the
16 * actual cells may be connected by an irregular graph.
17 */
18template<class TOPOLOGY=Topologies::Torus<2>::Topology>
19class MeshlessAdapter
20{
21public:
22    friend class MeshlessAdapterTest;
23    static const int DIM = TOPOLOGY::DIMENSIONS;
24    static const int MAX_SIZE = 300000;
25
26    typedef std::list<FloatCoord<DIM> > CoordList;
27    typedef Grid<CoordList, TOPOLOGY> CoordListGrid;
28    typedef SuperVector<FloatCoord<DIM> > CoordVec;
29    typedef SuperVector<SuperVector<int> > Graph;
30
31    /**
32     * creates an MeshlessAdapter which assumes that the coordinates
33     * of the cells are elementwise smaller than _dimensions. The
34     * stencil cells will be of size boxSize^DIMENSIONS.
35     */
36    inline MeshlessAdapter(
37        const FloatCoord<DIM>& _dimensions=FloatCoord<DIM>(), 
38        const double& _boxSize=1) :
39        dimensions(_dimensions)
40    {
41        resetBoxSize(_boxSize);
42    }
43   
44    inline CoordListGrid grid() const
45    {
46        return CoordListGrid(discreteDim);
47    }
48   
49    inline Coord<DIM> posToCoord(const FloatCoord<DIM>& pos) const
50    {
51        Coord<DIM> c;
52        for (int i = 0; i < DIM; ++i) {
53            // cut all overhanging coords
54            c.c[i] = std::min(discreteDim.c[i] - 1,
55                              (int)(pos.c[i] * scale));
56        }
57        return c;
58    }
59
60    inline void insert(CoordListGrid *grid, const FloatCoord<DIM>& pos) const
61    {
62        Coord<2> c = posToCoord(pos);
63        (*grid)[c].push_back(pos);
64    }
65
66    /**
67     * checks if the grid cell containing pos or any of its neighbors
68     * in its Moore neighborhood contains a vertex which is closer to
69     * pos than the boxSize. May return a list of all found vertex IDs
70     * if coords is set.
71     */
72    bool search(
73        const CoordListGrid& positions,
74        const FloatCoord<DIM>& pos,
75        std::set<int> *coords = 0) const
76    {
77        bool found = false;
78        Coord<DIM> center = posToCoord(pos);
79   
80        CoordBox<DIM> box(CoordDiagonal<DIM>()(-1), CoordDiagonal<DIM>()(3));
81        CoordBoxSequence<DIM> s = box.sequence();
82        while (s.hasNext()) {
83            Coord<DIM> newCenter = center + s.next();
84            bool res = searchList(positions[newCenter], pos, coords);
85            found |= res;
86        }
87
88        return found;
89    }
90
91    inline CoordVec findAllPositions(const CoordListGrid& positions) const
92    {
93        CoordVec ret;
94
95        CoordBox<DIM> box = positions.boundingBox();
96        CoordBoxSequence<DIM> s = box.sequence();
97        while (s.hasNext()) {
98            const std::list<FloatCoord<DIM> >& list = positions[s.next()];
99            for (typename std::list<FloatCoord<DIM> >::const_iterator iter = list.begin();
100                 iter != list.end();
101                 ++iter) {
102                ret.push_back(*iter);
103            }
104        }
105
106        return ret;
107    }
108
109    double findOptimumBoxSize(
110        const CoordVec& positions, 
111        const Graph& graph)
112    {
113        double upperBorder = -1;
114        double lowerBorder = -1;
115
116        Coord<DIM> upperBorderDim;
117        Coord<DIM> lowerBorderDim;
118       
119        // the exponential back-off algorithm allows us to find upper
120        // and lower bound for the optimal box size in log time
121        if (checkBoxSize(positions, graph)) {
122            upperBorder = boxSize;
123            upperBorderDim = discreteDim;
124            resetBoxSize(boxSize * 0.5);
125            while (checkBoxSize(positions, graph))
126                resetBoxSize(boxSize * 0.5);
127            lowerBorder = boxSize;
128            lowerBorderDim = discreteDim;
129        } else {
130            lowerBorder = boxSize;
131            lowerBorderDim = discreteDim;
132            resetBoxSize(boxSize * 2);
133            while (!checkBoxSize(positions, graph))
134                resetBoxSize(boxSize * 2);
135            upperBorder = boxSize;
136            upperBorderDim = discreteDim;
137        }
138
139        // The loop condition is not very tight. I'd rather test for
140        // equality here. But the loose test is necessary to keep the
141        // number of iterations low in the general case, and finite in
142        // special cases where deadlocks would occurr otherwise.
143        while (intervalTooLarge(lowerBorderDim, upperBorderDim)) {
144            double middle = (upperBorder + lowerBorder) * 0.5;
145            resetBoxSize(middle);
146            if (checkBoxSize(positions, graph)) {
147                upperBorder = middle;
148                upperBorderDim = discreteDim;
149            } else {
150                lowerBorder = middle;
151                lowerBorderDim = discreteDim;
152            }
153        }
154     
155        double maxBoxSize = 0;
156        double nextLower = 0;
157       
158        // the resulting box size may lead to overhangs on the far
159        // boundaries which would get added to the nearest container
160        // cells. this step enlarges the box size slightly to ensure a
161        // smooth distribution.
162        for (int i = 0; i < DIM; ++i) {
163            double current = dimensions.c[i] / upperBorderDim.c[i];
164            if (current > maxBoxSize) {
165                maxBoxSize = current;
166                // because the loop condition above is not tight, the
167                // next smaller box size might represet a valid
168                // solution, too.
169                nextLower = dimensions.c[i] / (upperBorderDim.c[i] + 1);
170            }
171        }
172           
173        resetBoxSize(nextLower);
174        if (checkBoxSize(positions, graph)) 
175            return nextLower;
176
177        resetBoxSize(maxBoxSize);
178        // this should never happen, but might in arcane cases where
179        // the packaging density is much higher on the far boundaries
180        // than elsewhere in the the simulation space.
181        if (!checkBoxSize(positions, graph))
182            throw std::logic_error("failed to determine a valid box size");
183        return maxBoxSize;
184    }
185
186    bool checkBoxSize(const CoordVec& positions, const Graph& graph)
187    {
188        for (int i = 0; i < graph.size(); ++i) 
189            for (SuperVector<int>::const_iterator n = graph[i].begin(); 
190                 n != graph[i].end(); ++n) 
191                if (manhattanDistance(positions[i], positions[*n]) > 1)
192                    return false;
193
194        return true;
195    }
196
197    const Coord<DIM>& getDiscreteDim() const
198    {
199        return discreteDim;
200    }
201
202    SuperMap<std::string, double> reportFillLevels(const CoordVec& positions) const
203    {
204        SuperMap<Coord<DIM>, int> cache;
205        for (typename CoordVec::const_iterator i = positions.begin(); i != positions.end(); ++i) {
206            Coord<DIM> c = posToCoord(*i);
207            cache[c]++;
208        }
209
210        long sum = 0;
211        long emptyCells = 0;
212        int lowestFill = cache[Coord<DIM>()];
213        int highestFill = cache[Coord<DIM>()];
214
215        CoordBox<DIM> box(Coord<DIM>(), discreteDim);
216        CoordBoxSequence<DIM> s = box.sequence();
217        while (s.hasNext()) {
218            Coord<DIM> c = s.next();
219            lowestFill  = std::min(cache[c], lowestFill);
220            highestFill = std::max(cache[c], highestFill);
221            sum += cache[c];
222
223            if (cache[c] == 0)
224                ++emptyCells;
225        }
226
227        SuperMap<std::string, double> ret;
228        ret["emptyCells"]  = emptyCells;
229        ret["averageFill"] = 1.0 * sum / discreteDim.prod();
230        ret["lowestFill"]  = lowestFill;
231        ret["highestFill"] = highestFill;
232        return ret;
233    }
234
235    const double& getBoxSize() const
236    {
237        return boxSize;
238    }
239
240private:
241    FloatCoord<DIM> dimensions;
242    Coord<DIM> discreteDim;
243    double scale;
244    double radius2;
245    double boxSize;
246
247    void resetBoxSize(const double& newBoxSize)
248    {
249        scale = 1 / newBoxSize;
250        radius2 = newBoxSize * newBoxSize;
251        boxSize = newBoxSize;
252
253        // cut the edges via floor to avoid too thin boundaries, which
254        // may interfere with a Torus topology where some cells, for
255        // instance on the left border would try to access their left
256        // neighbors (actually on the right side of the domain), but
257        // would be unable to find them since the resulting grid thin
258        // boundary container cells on the right would not contain all
259        // required neighbors.
260        for (int i = 0; i < DIM; ++i) {
261            discreteDim.c[i] = std::max(1.0, std::floor(dimensions.c[i] * scale));
262        }
263
264        if (discreteDim.prod() > MAX_SIZE) 
265            throw std::logic_error("too many container cells are required");
266    }
267
268    bool searchList(
269        const std::list<FloatCoord<DIM> >& list,
270        const FloatCoord<DIM>& pos,
271        std::set<int> *coords = 0) const
272    {
273        bool found = false;
274
275        for (typename std::list<FloatCoord<DIM> >::const_iterator iter = list.begin();
276             iter != list.end();
277             ++iter) {
278            if (distance2(pos, *iter) < radius2) {
279                found = true;
280                if (coords)
281                    coords->insert(iter->id);
282            }
283        }
284
285        return found;
286    }
287
288    /**
289     * returns the square of the euclidean distance of a and b.
290     */
291    double distance2(const FloatCoord<DIM>& a, const FloatCoord<DIM>& b) const
292    {
293        double dist2 = 0;
294
295        for (int i = 0; i < DIM; ++i) {
296            double delta = std::abs(a.c[i] - b.c[i]);
297            if (TOPOLOGY::wrapsAxis(i))
298                delta = std::min(delta, dimensions.c[i] - delta);
299            dist2 += delta * delta;
300        }
301
302        return dist2;
303    }
304
305    int manhattanDistance(const FloatCoord<DIM>& a, const FloatCoord<DIM>& b) const
306    {
307        Coord<DIM> coordA = posToCoord(a);
308        Coord<DIM> coordB = posToCoord(b);
309        Coord<DIM> delta = coordA - coordB;
310        int maxDist = 0;
311       
312        for (int i = 0; i < DIM; ++i) {
313            int dist = std::abs(delta.c[i]);
314            if (TOPOLOGY::wrapsAxis(i))
315                dist = std::min(dist, discreteDim.c[i] - dist);
316            maxDist = std::max(dist, maxDist);
317        }
318
319        return maxDist;
320    }
321
322    bool intervalTooLarge(const Coord<DIM>& a, const Coord<DIM>& b)
323    {
324        int maxDist = 0;
325        for (int i = 0; i < DIM; ++i) {
326            maxDist = std::max(maxDist, std::abs(a.c[i] - b.c[i]));
327        }
328        return maxDist > 1;
329
330    }
331};
332
333}
334
335#endif
Note: See TracBrowser for help on using the browser.