1 /**
2 * MOAB, a Mesh-Oriented datABase, is a software component for creating,
3 * storing and accessing finite element mesh data.
4 *
5 * Copyright 2004 Sandia Corporation. Under the terms of Contract
6 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
7 * retains certain rights in this software.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 */
15
16 #ifndef SCD_ELEMENT_DATA_HPP
17 #define SCD_ELEMENT_DATA_HPP
18
19 //
20 // Class: ScdElementData
21 //
22 // Purpose: represent a rectangular element of mesh
23 //
24 // A ScdElement represents a rectangular element of mesh, including both vertices and
25 // elements, and the parametric space used to address that element. Vertex data,
26 // i.e. coordinates, may not be stored directly in the element, but the element returns
27 // information about the vertex handles of vertices in the element. Vertex and element
28 // handles associated with the element are each contiguous.
29
30 #include "SequenceData.hpp"
31 #include "moab/HomXform.hpp"
32 #include "moab/CN.hpp"
33 #include "ScdVertexData.hpp"
34 #include "Internals.hpp"
35 #include "moab/Range.hpp"
36
37 #include <vector>
38 #include <algorithm>
39
40 namespace moab {
41
42 class ScdElementData : public SequenceData
43 {
44
45 //! structure to hold references to bounding vertex blocks
46 class VertexDataRef
47 {
48 private:
49 HomCoord minmax[2];
50 HomXform xform, invXform;
51 ScdVertexData *srcSeq;
52 public:
53 friend class ScdElementData;
54
55 VertexDataRef(const HomCoord &min, const HomCoord &max,
56 const HomXform &tmp_xform, ScdVertexData *this_seq);
57
58 bool contains(const HomCoord &coords) const;
59 };
60
61 private:
62
63 //! parameter min/max/stride for vertices, in homogeneous coords ijkh; elements
64 //! are one less than max
65 HomCoord boxParams[3];
66
67 //! difference between max and min params plus one (i.e. # VERTICES in
68 //! each parametric direction)
69 int dIJK[3];
70
71 //! difference between max and min params (i.e. # ELEMENTS in
72 //! each parametric direction)
73 int dIJKm1[3];
74
75 //! whether scd element rectangle is periodic in i and possibly j
76 int isPeriodic[2];
77
78 //! bare constructor, so compiler doesn't create one for me
79 ScdElementData();
80
81 //! list of bounding vertex blocks
82 std::vector<VertexDataRef> vertexSeqRefs;
83
84 public:
85
86 //! constructor
87 ScdElementData( EntityHandle start_handle,
88 const int imin, const int jmin, const int kmin,
89 const int imax, const int jmax, const int kmax,
90 int *is_periodic);
91
92 virtual ~ScdElementData();
93
94 //! get handle of vertex at homogeneous coords
95 inline EntityHandle get_vertex(const HomCoord &coords) const;
get_vertex(int i,int j,int k) const96 inline EntityHandle get_vertex(int i, int j, int k) const
97 { return get_vertex(HomCoord(i,j,k)); }
98
99 //! get handle of element at i, j, k
100 EntityHandle get_element(const int i, const int j, const int k) const;
101
102 //! get min params for this element
103 const HomCoord &min_params() const;
104
105 //! get max params for this element
106 const HomCoord &max_params() const;
107
108 //! get the number of vertices in each direction, inclusive
109 void param_extents(int &di, int &dj, int &dk) const;
110
111 //! given a handle, get the corresponding parameters
112 ErrorCode get_params(const EntityHandle ehandle,
113 int &i, int &j, int &k) const;
114
115 //! return whether rectangle is periodic in i
is_periodic_i() const116 inline int is_periodic_i() const {return isPeriodic[0];};
117
118 //! return whether rectangle is periodic in j
is_periodic_j() const119 inline int is_periodic_j() const {return isPeriodic[1];};
120
is_periodic(int is_p[2]) const121 inline void is_periodic(int is_p[2]) const
122 {is_p[0] = isPeriodic[0]; is_p[1] = isPeriodic[1];}
123
124 //! convenience functions for parameter extents
i_min() const125 int i_min() const {return (boxParams[0].hom_coord())[0];}
j_min() const126 int j_min() const {return (boxParams[0].hom_coord())[1];}
k_min() const127 int k_min() const {return (boxParams[0].hom_coord())[2];}
i_max() const128 int i_max() const {return (boxParams[1].hom_coord())[0];}
j_max() const129 int j_max() const {return (boxParams[1].hom_coord())[1];}
k_max() const130 int k_max() const {return (boxParams[1].hom_coord())[2];}
131
132 //! test the bounding vertex sequences and determine whether they fully
133 //! define the vertices covering this element block's parameter space
134 bool boundary_complete() const;
135
136 //! test whether this sequence contains these parameters
137 inline bool contains(const HomCoord &coords) const;
138
139 //! test whether *vertex parameterization* in this sequence contains these parameters
140 inline bool contains_vertex(const HomCoord &coords) const;
141
142 //! get connectivity of an entity given entity's parameters
143 inline ErrorCode get_params_connectivity(const int i, const int j, const int k,
144 std::vector<EntityHandle>& connectivity) const;
145
146 //! add a vertex seq ref to this element sequence;
147 //! if bb_input is true, bounding box (in eseq-local coords) of vseq being added
148 //! is input in bb_min and bb_max (allows partial sharing of vseq rather than the whole
149 //! vseq); if it's false, the whole vseq is referenced and the eseq-local coordinates
150 //! is computed from the transformed bounding box of the vseq
151 ErrorCode add_vsequence(ScdVertexData *vseq,
152 const HomCoord &p1, const HomCoord &q1,
153 const HomCoord &p2, const HomCoord &q2,
154 const HomCoord &p3, const HomCoord &q3,
155 bool bb_input = false,
156 const HomCoord &bb_min = HomCoord::unitv[0],
157 const HomCoord &bb_max = HomCoord::unitv[0]);
158
159
160 SequenceData* subset( EntityHandle start,
161 EntityHandle end,
162 const int* sequence_data_sizes,
163 const int* tag_data_sizes ) const;
164
165 static EntityID calc_num_entities( EntityHandle start_handle,
166 int irange,
167 int jrange,
168 int krange,
169 int *is_periodic = NULL);
170
171 unsigned long get_memory_use() const;
172 };
173
get_element(const int i,const int j,const int k) const174 inline EntityHandle ScdElementData::get_element(const int i, const int j, const int k) const
175 {
176 return start_handle() + (i-i_min()) + (j-j_min())*dIJKm1[0] + (k-k_min())*dIJKm1[0]*dIJKm1[1];
177 }
178
min_params() const179 inline const HomCoord &ScdElementData::min_params() const
180 {
181 return boxParams[0];
182 }
183
max_params() const184 inline const HomCoord &ScdElementData::max_params() const
185 {
186 return boxParams[1];
187 }
188
189 //! get the number of vertices in each direction, inclusive
param_extents(int & di,int & dj,int & dk) const190 inline void ScdElementData::param_extents(int &di, int &dj, int &dk) const
191 {
192 di = dIJK[0];
193 dj = dIJK[1];
194 dk = dIJK[2];
195 }
196
get_params(const EntityHandle ehandle,int & i,int & j,int & k) const197 inline ErrorCode ScdElementData::get_params(const EntityHandle ehandle,
198 int &i, int &j, int &k) const
199 {
200 if (TYPE_FROM_HANDLE(ehandle) != TYPE_FROM_HANDLE(start_handle())) return MB_FAILURE;
201
202 int hdiff = ehandle - start_handle();
203
204 // use double ?: test below because on some platforms, both sides of the : are
205 // evaluated, and if dIJKm1[1] is zero, that'll generate a divide-by-zero
206 k = (dIJKm1[1] > 0 ? hdiff / (dIJKm1[1] > 0 ? dIJKm1[0]*dIJKm1[1] : 1) : 0);
207 j = (hdiff - (k*dIJKm1[0]*dIJKm1[1])) / dIJKm1[0];
208 i = hdiff % dIJKm1[0];
209
210 k += boxParams[0].k();
211 j += boxParams[0].j();
212 i += boxParams[0].i();
213
214 return (ehandle >= start_handle() &&
215 ehandle < start_handle()+size() &&
216 i >= i_min() && i <= i_max() &&
217 j >= j_min() && j <= j_max() &&
218 k >= k_min() && k <= k_max()) ? MB_SUCCESS : MB_FAILURE;
219 }
220
contains(const HomCoord & temp) const221 inline bool ScdElementData::contains(const HomCoord &temp) const
222 {
223 // upper bound is < instead of <= because element params max is one less
224 // than vertex params max, except in case of 2d or 1d sequence
225 return ((dIJKm1[0] && temp.i() >= boxParams[0].i() && temp.i() < boxParams[0].i()+dIJKm1[0]) &&
226 ((!dIJKm1[1] && temp.j() == boxParams[1].j()) ||
227 (dIJKm1[1] && temp.j() >= boxParams[0].j() && temp.j() < boxParams[0].j()+dIJKm1[1])) &&
228 ((!dIJKm1[2] && temp.k() == boxParams[1].k()) ||
229 (dIJKm1[2] && temp.k() >= boxParams[0].k() && temp.k() < boxParams[0].k()+dIJKm1[2])));
230 }
231
contains_vertex(const HomCoord & temp) const232 inline bool ScdElementData::contains_vertex(const HomCoord &temp) const
233 {
234 // upper bound is < instead of <= because element params max is one less
235 // than vertex params max, except in case of 2d or 1d sequence
236 return ((dIJK[0] && temp.i() >= boxParams[0].i() && temp.i() < boxParams[0].i()+dIJK[0]) &&
237 ((!dIJK[1] && temp.j() == boxParams[1].j()) ||
238 (dIJK[1] && temp.j() >= boxParams[0].j() && temp.j() < boxParams[0].j()+dIJK[1])) &&
239 ((!dIJK[2] && temp.k() == boxParams[1].k()) ||
240 (dIJK[2] && temp.k() >= boxParams[0].k() && temp.k() < boxParams[0].k()+dIJK[2])));
241 }
242
contains(const HomCoord & coords) const243 inline bool ScdElementData::VertexDataRef::contains(const HomCoord &coords) const
244 {
245 return (minmax[0] <= coords && minmax[1] >= coords);
246 }
247
VertexDataRef(const HomCoord & this_min,const HomCoord & this_max,const HomXform & tmp_xform,ScdVertexData * this_seq)248 inline ScdElementData::VertexDataRef::VertexDataRef(const HomCoord &this_min, const HomCoord &this_max,
249 const HomXform &tmp_xform, ScdVertexData *this_seq)
250 : xform(tmp_xform), invXform(tmp_xform.inverse()), srcSeq(this_seq)
251 {
252 minmax[0] = HomCoord(this_min);
253 minmax[1] = HomCoord(this_max);
254 }
255
get_vertex(const HomCoord & coords) const256 inline EntityHandle ScdElementData::get_vertex(const HomCoord &coords) const
257 {
258 assert(boundary_complete());
259 for (std::vector<VertexDataRef>::const_iterator it = vertexSeqRefs.begin();
260 it != vertexSeqRefs.end(); ++it) {
261 if ((*it).minmax[0] <= coords && (*it).minmax[1] >= coords) {
262 // first get the vertex block-local parameters
263 HomCoord local_coords = coords / (*it).xform;
264
265 assert((*it).srcSeq->contains(local_coords));
266
267 // now get the vertex handle for those coords
268 return (*it).srcSeq->get_vertex(local_coords);
269 }
270 }
271
272 // got here, it's an error
273 return 0;
274 }
275
add_vsequence(ScdVertexData * vseq,const HomCoord & p1,const HomCoord & q1,const HomCoord & p2,const HomCoord & q2,const HomCoord & p3,const HomCoord & q3,bool bb_input,const HomCoord & bb_min,const HomCoord & bb_max)276 inline ErrorCode ScdElementData::add_vsequence(ScdVertexData *vseq,
277 const HomCoord &p1, const HomCoord &q1,
278 const HomCoord &p2, const HomCoord &q2,
279 const HomCoord &p3, const HomCoord &q3,
280 bool bb_input,
281 const HomCoord &bb_min,
282 const HomCoord &bb_max)
283 {
284 // compute the transform given the vseq-local parameters and the mapping to
285 // this element sequence's parameters passed in minmax
286 HomXform M;
287 M.three_pt_xform(p1, q1, p2, q2, p3, q3);
288
289 // min and max in element seq's parameter system may not be same as those in
290 // vseq's system, so need to take min/max
291
292 HomCoord minmax[2];
293 if (bb_input) {
294 minmax[0] = bb_min;
295 minmax[1] = bb_max;
296 }
297 else {
298 minmax[0] = vseq->min_params() * M;
299 minmax[1] = vseq->max_params() * M;
300 }
301
302 // check against other vseq's to make sure they don't overlap
303 for (std::vector<VertexDataRef>::const_iterator vsit = vertexSeqRefs.begin();
304 vsit != vertexSeqRefs.end(); ++vsit)
305 if ((*vsit).contains(minmax[0]) || (*vsit).contains(minmax[1]))
306 return MB_FAILURE;
307
308 HomCoord tmp_min(std::min(minmax[0].i(), minmax[1].i()),
309 std::min(minmax[0].j(), minmax[1].j()),
310 std::min(minmax[0].k(), minmax[1].k()));
311 HomCoord tmp_max(std::max(minmax[0].i(), minmax[1].i()),
312 std::max(minmax[0].j(), minmax[1].j()),
313 std::max(minmax[0].k(), minmax[1].k()));
314
315
316 // set up a new vertex sequence reference
317 VertexDataRef tmp_seq_ref(tmp_min, tmp_max, M, vseq);
318
319 // add to the list
320 vertexSeqRefs.push_back(tmp_seq_ref);
321
322 return MB_SUCCESS;
323 }
324
get_params_connectivity(const int i,const int j,const int k,std::vector<EntityHandle> & connectivity) const325 inline ErrorCode ScdElementData::get_params_connectivity(const int i, const int j, const int k,
326 std::vector<EntityHandle>& connectivity) const
327 {
328 if (contains(HomCoord(i, j, k)) == false) return MB_FAILURE;
329
330 int ip1 = (isPeriodic[0] ? (i+1)%dIJKm1[0] : i+1),
331 jp1 = (isPeriodic[1] ? (j+1)%dIJKm1[1] : j+1);
332
333 connectivity.push_back(get_vertex(i, j, k));
334 connectivity.push_back(get_vertex(ip1, j, k));
335 if (CN::Dimension(TYPE_FROM_HANDLE(start_handle())) < 2) return MB_SUCCESS;
336 connectivity.push_back(get_vertex(ip1, jp1, k));
337 connectivity.push_back(get_vertex(i, jp1, k));
338 if (CN::Dimension(TYPE_FROM_HANDLE(start_handle())) < 3) return MB_SUCCESS;
339 connectivity.push_back(get_vertex(i, j, k+1));
340 connectivity.push_back(get_vertex(ip1, j, k+1));
341 connectivity.push_back(get_vertex(ip1, jp1, k+1));
342 connectivity.push_back(get_vertex(i, jp1, k+1));
343 return MB_SUCCESS;
344 }
345
346 } // namespace moab
347
348 #endif
349