Salome HOME
87ab6b14c43a6771c0ff92cbbb50fea4e23daf01
[modules/med.git] / src / INTERP_KERNEL / Interpolation3D.txx
1 // Copyright (C) 2007-2013  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony Geay (CEA/DEN)
20 #ifndef __INTERPOLATION3D_TXX__
21 #define __INTERPOLATION3D_TXX__
22
23 #include "Interpolation3D.hxx"
24 #include "Interpolation.txx"
25 #include "MeshElement.txx"
26 #include "TransformedTriangle.hxx"
27 #include "PolyhedronIntersectorP0P0.txx"
28 #include "PointLocator3DIntersectorP0P0.txx"
29 #include "PolyhedronIntersectorP0P1.txx"
30 #include "PointLocator3DIntersectorP0P1.txx"
31 #include "PolyhedronIntersectorP1P0.txx"
32 #include "PolyhedronIntersectorP1P0Bary.txx"
33 #include "PointLocator3DIntersectorP1P0.txx"
34 #include "PolyhedronIntersectorP1P1.txx"
35 #include "PointLocator3DIntersectorP1P1.txx"
36 #include "Log.hxx"
37 /// If defined, use recursion to traverse the binary search tree, else use the BBTree class
38 //#define USE_RECURSIVE_BBOX_FILTER
39
40 #ifdef USE_RECURSIVE_BBOX_FILTER
41 #include "MeshRegion.txx"
42 #include "RegionNode.hxx"
43 #include <stack>
44
45 #else // use BBTree class
46
47 #include "BBTree.txx"
48
49 #endif
50
51 namespace INTERP_KERNEL
52 {
53   /**
54    * Calculates the matrix of volumes of intersection between the elements of srcMesh and the elements of targetMesh.
55    * The calculation is done in two steps. First a filtering process reduces the number of pairs of elements for which the
56    * calculation must be carried out by eliminating pairs that do not intersect based on their bounding boxes. Then, the 
57    * volume of intersection is calculated by an object of type Intersector3D for the remaining pairs, and entered into the
58    * intersection matrix. 
59    * 
60    * The matrix is partially sparse : it is a vector of maps of integer - double pairs. 
61    * It can also be an INTERP_KERNEL::Matrix object.
62    * The length of the vector is equal to the number of target elements - for each target element there is a map, regardless
63    * of whether the element intersects any source elements or not. But in the maps there are only entries for those source elements
64    * which have a non-zero intersection volume with the target element. The vector has indices running from 
65    * 0 to (nb target elements - 1), meaning that the map for target element i is stored at index i - 1. In the maps, however,
66    * the indexing is more natural : the intersection volume of the target element i with source element j is found at matrix[i-1][j].
67    * 
68
69    * @param srcMesh     3-dimensional source mesh
70    * @param targetMesh  3-dimesional target mesh, containing only tetraedra
71    * @param result      matrix in which the result is stored 
72    *
73    */
74   template<class MyMeshType, class MatrixType>
75   int Interpolation3D::interpolateMeshes(const MyMeshType& srcMesh, const MyMeshType& targetMesh, MatrixType& result, const char *method)
76   {
77     typedef typename MyMeshType::MyConnType ConnType;
78     // create MeshElement objects corresponding to each element of the two meshes
79     const unsigned long numSrcElems = srcMesh.getNumberOfElements();
80     const unsigned long numTargetElems = targetMesh.getNumberOfElements();
81
82     LOG(2, "Source mesh has " << numSrcElems << " elements and target mesh has " << numTargetElems << " elements ");
83
84     std::vector<MeshElement<ConnType>*> srcElems(numSrcElems);
85     std::vector<MeshElement<ConnType>*> targetElems(numTargetElems);
86
87     std::map<MeshElement<ConnType>*, int> indices;
88
89     for(unsigned long i = 0 ; i < numSrcElems ; ++i)
90       srcElems[i] = new MeshElement<ConnType>(i, srcMesh);       
91
92     for(unsigned long i = 0 ; i < numTargetElems ; ++i)
93       targetElems[i] = new MeshElement<ConnType>(i, targetMesh);
94
95     Intersector3D<MyMeshType,MatrixType>* intersector=0;
96     std::string methC = InterpolationOptions::filterInterpolationMethod(method);
97     if(methC=="P0P0")
98       {
99         switch(InterpolationOptions::getIntersectionType())
100           {
101           case Triangulation:
102             intersector=new PolyhedronIntersectorP0P0<MyMeshType,MatrixType>(targetMesh, srcMesh, getSplittingPolicy());
103             break;
104           case PointLocator:
105             intersector=new PointLocator3DIntersectorP0P0<MyMeshType,MatrixType>(targetMesh, srcMesh, getPrecision());
106             break;
107           default:
108             throw INTERP_KERNEL::Exception("Invalid 3D intersection type for P0P0 interp specified : must be Triangle or PointLocator.");
109           }
110       }
111     else if(methC=="P0P1")
112       {
113         switch(InterpolationOptions::getIntersectionType())
114           {
115           case Triangulation:
116             intersector=new PolyhedronIntersectorP0P1<MyMeshType,MatrixType>(targetMesh, srcMesh, getSplittingPolicy());
117             break;
118           case PointLocator:
119             intersector=new PointLocator3DIntersectorP0P1<MyMeshType,MatrixType>(targetMesh, srcMesh, getPrecision());
120             break;
121           default:
122             throw INTERP_KERNEL::Exception("Invalid 3D intersection type for P0P1 interp specified : must be Triangle or PointLocator.");
123           }
124       }
125     else if(methC=="P1P0")
126       {
127         switch(InterpolationOptions::getIntersectionType())
128           {
129           case Triangulation:
130             intersector=new PolyhedronIntersectorP1P0<MyMeshType,MatrixType>(targetMesh, srcMesh, getSplittingPolicy());
131             break;
132           case PointLocator:
133             intersector=new PointLocator3DIntersectorP1P0<MyMeshType,MatrixType>(targetMesh, srcMesh, getPrecision());
134             break;
135           default:
136             throw INTERP_KERNEL::Exception("Invalid 3D intersection type for P1P0 interp specified : must be Triangle or PointLocator.");
137           }
138       }
139     else if(methC=="P1P0Bary")
140       {
141         if(InterpolationOptions::getIntersectionType()==Triangulation)
142           intersector=new PolyhedronIntersectorP1P0Bary<MyMeshType,MatrixType>(targetMesh, srcMesh, getSplittingPolicy());
143         else
144           throw INTERP_KERNEL::Exception("Invalid 3D intersection type specified : must be Triangle.");
145       }
146     else if(methC=="P1P1")
147       {
148         switch(InterpolationOptions::getIntersectionType())
149           {
150           case Triangulation:
151             intersector=new PolyhedronIntersectorP1P1<MyMeshType,MatrixType>(targetMesh, srcMesh, getSplittingPolicy());
152             break;
153           case PointLocator:
154             intersector=new PointLocator3DIntersectorP1P1<MyMeshType,MatrixType>(targetMesh, srcMesh, getPrecision());
155             break;
156           default:
157             throw INTERP_KERNEL::Exception("Invalid 3D intersection type for P1P1 interp specified : must be Triangle or PointLocator.");
158           }
159       }
160     else
161       throw Exception("Invalid method choosed must be in \"P0P0\", \"P0P1\", \"P1P0\" or \"P1P1\".");
162     // create empty maps for all source elements
163     result.resize(intersector->getNumberOfRowsOfResMatrix());
164
165 #ifdef USE_RECURSIVE_BBOX_FILTER
166
167     /*
168      * Performs a depth-first search over srcMesh, using bounding boxes to recursively eliminate the elements of targetMesh
169      * which cannot intersect smaller and smaller regions of srcMesh. At each level, each region is divided in two, forming
170      * a binary search tree with leaves consisting of only one element of the source mesh together with the elements of the
171      * target mesh that can intersect it. The recursion is implemented with a stack of RegionNodes, each one containing a 
172      * source region and a target region. Each region has an associated bounding box and a vector of pointers to the elements 
173      * that belong to it. Each MeshElement contains a bounding box and the global number of the corresponding element in the mesh.
174      */
175
176     // create initial RegionNode and fill up its source region with all the source mesh elements and
177     // its target region with all the target mesh elements whose bounding box
178     // intersects that of the source region
179
180     RegionNode<ConnType>* firstNode = new RegionNode<ConnType>();
181
182     MeshRegion<ConnType>& srcRegion = firstNode->getSrcRegion();
183
184     for(unsigned long i = 0 ; i < numSrcElems ; ++i)
185       {
186         srcRegion.addElement(srcElems[i], srcMesh);
187       }
188
189     MeshRegion<ConnType>& targetRegion = firstNode->getTargetRegion();
190
191     for(unsigned long i = 0 ; i < numTargetElems ; ++i)
192       {
193         if(!srcRegion.isDisjointWithElementBoundingBox( *(targetElems[i]) ))
194           {
195             targetRegion.addElement(targetElems[i], targetMesh);
196           }
197       }
198
199     // Using a stack, descend recursively, creating at each step two new RegionNodes having as source region the left and
200     // right part of the source region of the current node (created using MeshRegion::split()) and as target region all the 
201     // elements of the target mesh whose bounding box intersects the corresponding part
202     // Continue until the source region contains only one element, at which point the intersection volumes are
203     // calculated with all the remaining target mesh elements and stored in the matrix if they are non-zero.
204
205     std::stack< RegionNode<ConnType>* > nodes;
206     nodes.push(firstNode);
207
208     while(!nodes.empty())
209       {
210         RegionNode<ConnType>* currNode = nodes.top();
211         nodes.pop();
212         LOG(4, "Popping node ");
213
214         if(currNode->getTargetRegion().getNumberOfElements() == 1)
215           {
216             // calculate volumes
217             LOG(4, " - One element");
218
219             MeshElement<ConnType>* targetElement = *(currNode->getTargetRegion().getBeginElements());
220             std::vector<ConnType> intersectElems;
221             for(typename std::vector< MeshElement<ConnType>* >::const_iterator iter = currNode->getSrcRegion().getBeginElements();iter != currNode->getSrcRegion().getEndElements();++iter)
222               intersectElems.push_back((*iter)->getIndex());
223             intersector->intersectCells(targetElement->getIndex(),intersectElems,result);
224           }
225         else // recursion 
226           {
227
228             LOG(4, " - Recursion");
229
230             RegionNode<ConnType>* leftNode = new RegionNode<ConnType>();
231             RegionNode<ConnType>* rightNode = new RegionNode<ConnType>();
232
233             // split current source region
234             //} decide on axis
235             static BoundingBox::BoxCoord axis = BoundingBox::XMAX;
236
237             currNode->getTargetRegion().split(leftNode->getTargetRegion(), rightNode->getTargetRegion(), axis, targetMesh);
238
239             LOG(5, "After split, left target region has " << leftNode->getTargetRegion().getNumberOfElements()
240                 << " elements and right target region has " << rightNode->getTargetRegion().getNumberOfElements() 
241                 << " elements");
242
243             // ugly hack to avoid problem with enum which does not start at 0
244             // I guess I ought to implement ++ for it instead ...
245             // Anyway, it basically chooses the next axis, cyclically
246             axis = (axis != BoundingBox::ZMAX) ? static_cast<BoundingBox::BoxCoord>(axis + 1) : BoundingBox::XMAX;
247
248             // add source elements of current node that overlap the target regions of the new nodes
249             LOG(5, " -- Adding source elements");
250             int numLeftElements = 0;
251             int numRightElements = 0;
252             for(typename std::vector<MeshElement<ConnType>*>::const_iterator iter = currNode->getSrcRegion().getBeginElements() ; 
253                 iter != currNode->getSrcRegion().getEndElements() ; ++iter)
254               {
255                 LOG(6, " --- New target node");
256
257                 if(!leftNode->getTargetRegion().isDisjointWithElementBoundingBox(**iter))
258                   {
259                     leftNode->getSrcRegion().addElement(*iter, srcMesh);
260                     ++numLeftElements;
261                   }
262
263                 if(!rightNode->getTargetRegion().isDisjointWithElementBoundingBox(**iter))
264                   {
265                     rightNode->getSrcRegion().addElement(*iter, srcMesh);
266                     ++numRightElements;
267                   }
268
269               }
270
271             LOG(5, "Left src region has " << numLeftElements << " elements and right src region has " 
272                 << numRightElements << " elements");
273
274             // push new nodes on stack
275             if(numLeftElements != 0)
276               {
277                 nodes.push(leftNode);
278               }
279             else
280               {
281                 delete leftNode;
282               }
283
284             if(numRightElements != 0)
285               {
286                 nodes.push(rightNode);
287               }
288             else
289               {
290                 delete rightNode;
291               }
292           }
293
294         // all nodes are deleted here
295         delete currNode;
296
297         LOG(4, "Next iteration. Nodes left : " << nodes.size());
298       }
299
300 #else // Use BBTree
301
302       // create BBTree structure
303       // - get bounding boxes
304     double* bboxes = new double[6 * numSrcElems];
305     int* srcElemIdx = new int[numSrcElems];
306     for(unsigned long i = 0; i < numSrcElems ; ++i)
307       {
308         // get source bboxes in right order
309         const BoundingBox* box = srcElems[i]->getBoundingBox();
310         bboxes[6*i+0] = box->getCoordinate(BoundingBox::XMIN);
311         bboxes[6*i+1] = box->getCoordinate(BoundingBox::XMAX);
312         bboxes[6*i+2] = box->getCoordinate(BoundingBox::YMIN);
313         bboxes[6*i+3] = box->getCoordinate(BoundingBox::YMAX);
314         bboxes[6*i+4] = box->getCoordinate(BoundingBox::ZMIN);
315         bboxes[6*i+5] = box->getCoordinate(BoundingBox::ZMAX);
316
317         // source indices have to begin with zero for BBox, I think
318         srcElemIdx[i] = srcElems[i]->getIndex();
319       }
320
321     BBTree<3,ConnType> tree(bboxes, srcElemIdx, 0, numSrcElems);
322
323     // for each target element, get source elements with which to calculate intersection
324     // - calculate intersection by calling intersectCells
325     for(unsigned long i = 0; i < numTargetElems; ++i)
326       {
327         const BoundingBox* box = targetElems[i]->getBoundingBox();
328         const int targetIdx = targetElems[i]->getIndex();
329
330         // get target bbox in right order
331         double targetBox[6];
332         targetBox[0] = box->getCoordinate(BoundingBox::XMIN);
333         targetBox[1] = box->getCoordinate(BoundingBox::XMAX);
334         targetBox[2] = box->getCoordinate(BoundingBox::YMIN);
335         targetBox[3] = box->getCoordinate(BoundingBox::YMAX);
336         targetBox[4] = box->getCoordinate(BoundingBox::ZMIN);
337         targetBox[5] = box->getCoordinate(BoundingBox::ZMAX);
338
339         std::vector<ConnType> intersectElems;
340
341         tree.getIntersectingElems(targetBox, intersectElems);
342
343         if ( !intersectElems.empty() )
344           intersector->intersectCells(targetIdx,intersectElems,result);
345       }
346
347     delete [] bboxes;
348     delete [] srcElemIdx;
349
350 #endif
351     // free allocated memory
352     int ret=intersector->getNumberOfColsOfResMatrix();
353
354     delete intersector;
355
356     for(unsigned long i = 0 ; i < numSrcElems ; ++i)
357       {
358         delete srcElems[i];
359       }
360     for(unsigned long i = 0 ; i < numTargetElems ; ++i)
361       {
362         delete targetElems[i];
363       }
364     return ret;
365
366   }
367 }
368
369 #endif