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