Arcane  v3.14.10.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
BasicRayMeshIntersection.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* BasicRayMeshIntersection.cc (C) 2000-2023 */
9/* */
10/* Service basique de calcul d'intersection entre segments et maillage. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/Array.h"
15#include "arcane/utils/Real3.h"
16#include "arcane/utils/StringBuilder.h"
17#include "arcane/utils/TraceAccessor.h"
18#include "arcane/utils/NotImplementedException.h"
19
20#include "arcane/ISubDomain.h"
21#include "arcane/IMesh.h"
22#include "arcane/IItemFamily.h"
23#include "arcane/Item.h"
24#include "arcane/BasicService.h"
25#include "arcane/FactoryService.h"
26#include "arcane/ItemPrinter.h"
27#include "arcane/ItemGroup.h"
28#include "arcane/VariableTypes.h"
29#include "arcane/IRayMeshIntersection.h"
30#include "arcane/IParallelMng.h"
31#include "arcane/IParticleFamily.h"
32
33#include "arcane_packages.h"
34
35#ifdef ARCANE_HAS_PACKAGE_LIMA
36#include <Lima/lima++.h>
37#define GLOBAL_HAS_LIMA true
38#else
39#define GLOBAL_HAS_LIMA false
40#endif
41
42/*---------------------------------------------------------------------------*/
43/*---------------------------------------------------------------------------*/
44
45namespace
46{
47const bool global_has_lima = GLOBAL_HAS_LIMA;
48}
49
50namespace Arcane
51{
52
53/*---------------------------------------------------------------------------*/
54/*---------------------------------------------------------------------------*/
55/*!
56 * \brief Calcul l'intersection d'un rayon avec un ensemble de triangles en 3D.
57 *
58 * Un rayon est une demi-droite et est défini par son origine et sa direction.
59 * Il faut positionner les rayons (via setRays()) et la liste des triangles
60 * (via setTriangles()) puis appeler la méthode compute(). En retour, on
61 * peut récupérer pour chaque rayon la distance (distances()) et le triangle intersecté
62 * (intersectedTriangleIndexes()).
63 *
64 * Les vues passées en argument (setRays() et setTriangles()) ne doivent pas être
65 * modifiées tant que l'instance existe.
66 */
68: public TraceAccessor
69{
70 public:
72 : TraceAccessor(tm)
73 {
74 }
75
76 /*!
77 * \brief Position la liste des rayons dont on souhaite calculer l'intersection.
78 */
80 {
81 m_rays_origin = origins;
82 m_rays_direction = directions;
83 }
84 /*!
85 * \brief Positionne la liste des triangles dont on souhaite calculer l'intersection
86 * avec les rayons. Le tableau \a indexes contient pour chaque triangle les indices
87 * dans le tableau \a coordinates de chaque sommet. Par exemple,
88 * indexes[0..2] contient les indices des sommets du 1er triangle, indexes[3..5]
89 * ceux du second.
90 */
92 {
93 m_triangles_coordinates = coordinates;
94 m_triangles_indexes = indexes;
95 }
96 /*!
97 * \brief Calcul l'intersection de chaque rayon avec la liste des triangles.
98 * Si un rayon intersecte plusieurs triangles, on concerve celui dont
99 * la distance par rapport à l'origine du rayon est la plus petite.
100 */
101 void compute();
102 /*!
103 * \brief Distance de l'origine d'un rayon à son point d'intersection.
104 * Distance (exprimée relativivement à la norme de \a directions)
105 * du point d'intersection d'un rayon par rapport à son origine.
106 * Pour le rayon \a i, son point d'intersection est donc donnée
107 * par la formule (origins[i] + distances[i]*directions[i]).
108 * La distance est négative si le rayon n'intersecte aucun triangle.
109 * Ce tableau est remplit lors de l'appel à compute().
110 */
112 {
113 return m_distances;
114 }
115
116 /*!
117 * \brief Indices des triangles intersectés.
118 * Indice dans le tableau donnée par \a setTriangles() du triangle
119 * intersecté par chaque rayon. Cet indice vaut (-1) si un rayon
120 * n'intersecte pas un triangle. Ce tableau est remplit lors
121 * de l'appel à compute().
122 */
124 {
125 return m_intersected_triangle_indexes;
126 }
127
128 Real checkIntersection(Real3 origin,Real3 direction,Real3 p0,Real3 p1,Real3 p2);
129
130 static bool checkBoundingBox(Real3 origin,Real3 direction,Real3 box_min,Real3 box_max);
131
132 private:
133
134 void _compute2(Int32 triangle_id,Real3 p0,Real3 p1,Real3 p2);
135
136 private:
137
138 Real3ConstArrayView m_rays_origin;
139 Real3ConstArrayView m_rays_direction;
140 Real3ConstArrayView m_triangles_coordinates;
141 Int32ConstArrayView m_triangles_indexes;
142
143 RealUniqueArray m_distances;
144 Int32UniqueArray m_intersected_triangle_indexes;
145};
146
147/*---------------------------------------------------------------------------*/
148/*---------------------------------------------------------------------------*/
149
151compute()
152{
153 Integer nb_ray = m_rays_origin.size();
154 m_distances.resize(nb_ray);
155 m_distances.fill(1.0e100);
156 m_intersected_triangle_indexes.resize(nb_ray);
157 m_intersected_triangle_indexes.fill(-1);
158 Integer nb_index = m_triangles_indexes.size();
159 if ((nb_index%3)!=0)
160 throw FatalErrorException(A_FUNCINFO,"bad triangle_index count (({0}) % 3)!=0");
161 Integer nb_triangle = nb_index / 3;
162 info() << "COMPUTE RAY INTERSECTION nb_ray=" << nb_ray
163 << " nb_triangle=" << nb_triangle;
164
165 for( Integer i=0; i<nb_triangle; ++i ){
166 Real3 p0 = m_triangles_coordinates[m_triangles_indexes[(i*3)]];
167 Real3 p1 = m_triangles_coordinates[m_triangles_indexes[(i*3)+1]];
168 Real3 p2 = m_triangles_coordinates[m_triangles_indexes[(i*3)+2]];
169 _compute2(i,p0,p1,p2);
170 }
171
172 for( Integer i=0; i<nb_ray; ++i ){
173 Int32 tid = m_intersected_triangle_indexes[i];
174 if (tid==(-1))
175 m_distances[i] = -1.0;
176 }
177}
178
179/*---------------------------------------------------------------------------*/
180/*---------------------------------------------------------------------------*/
181
182void RayTriangle3DIntersection::
183_compute2(Int32 triangle_id,Real3 p0,Real3 p1,Real3 p2)
184{
185 Integer nb_ray = m_rays_origin.size();
186 for( Integer i=0; i<nb_ray; ++i ){
187 Real t = checkIntersection(m_rays_origin[i],m_rays_direction[i],p0,p1,p2);
188 if (t>=0.0){
189 info() << "Segment " << i << " intersect triangle " << triangle_id << " T=" << t;
190 if (t<m_distances[i]){
191 m_distances[i] = t;
192 m_intersected_triangle_indexes[i] = triangle_id;
193 info() << "Get this triangle";
194 }
195 }
196 }
197}
198
199/*---------------------------------------------------------------------------*/
200/*---------------------------------------------------------------------------*/
201/*!
202 * \brief Calcul l'intersection de la demi-droite [origin,direction)
203 * avec le triangle (p0,p1,p2).
204 *
205 * La direction n'a pas besoin d'être normalisée.
206 *
207 * La position du point d'intersection est P = origin + t * direction
208 * où \a t est la valeur retournée par cette fonction. Cette valeur
209 * est négative si si aucun point d'intersection n'est trouvé.
210 */
213 Real3 direction,
214 Real3 p0,Real3 p1,Real3 p2)
215{
216 // Cette routine s'inspire du code de la bibliothèque WildMagic
217 // dont la licence est ci-dessous.
218
219 // Wild Magic Source Code
220 // David Eberly
221 // http://www.geometrictools.com
222 // Copyright (c) 1998-2009
223 //
224 // This library is free software; you can redistribute it and/or modify it
225 // under the terms of the GNU Lesser General Public License as published by
226 // the Free Software Foundation; either version 2.1 of the License, or (at
227 // your option) any later version. The license is available for reading at
228 // either of the locations:
229 // http://www.gnu.org/copyleft/lgpl.html
230 // http://www.geometrictools.com/License/WildMagicLicense.pdf
231 //
232
233
234 Real ZERO_TOLERANCE = 1.0e-14;
235 // compute the offset origin, edges, and normal
236 Real3 kDiff = origin - p0;
237 Real3 kEdge1 = p1 - p0;
238 Real3 kEdge2 = p2 - p0;
239 Real3 kNormal = math::vecMul(kEdge1,kEdge2);
240
241 Real fDdN = math::dot(direction,kNormal);
242 Real fSign;
243 if (fDdN > ZERO_TOLERANCE)
244 {
245 fSign = (Real)1.0;
246 }
247 else if (fDdN < -ZERO_TOLERANCE)
248 {
249 fSign = (Real)-1.0;
250 fDdN = -fDdN;
251 }
252 else
253 {
254 // Segment and triangle are parallel, call it a "no intersection"
255 // even if the segment does intersect.
256 return (-1.0);
257 }
258
259 Real fDdQxE2 = fSign*math::dot(direction,math::vecMul(kDiff,kEdge2));
260 if (fDdQxE2 >= (Real)0.0)
261 {
262 Real fDdE1xQ = fSign*math::dot(direction,math::vecMul(kEdge1,kDiff));
263 if (fDdE1xQ >= (Real)0.0)
264 {
265 Real diff = fDdN-(fDdQxE2 + fDdE1xQ);
266 // L'epsilon sert si le segment traverse par la face à proximité
267 // d'une des arêtes de la face. Dans ce cas, on considère qu'il
268 // y a intersection. Sans cela, à cause des arrondis numériques,
269 // un segment pourrait traverser le maillage en passant par une
270 // arête entre deux faces sans intersecter ces dernières.
271 if (diff>=0.0 || diff>-ZERO_TOLERANCE)
272 {
273 // line intersects triangle, check if segment does
274 Real fQdN = -fSign*math::dot(kDiff,kNormal);
275
276 // Comme il s'agit d'une demi-droite et pas d'un segment,
277 // il y a toujours intersection si \a t est positif.
278#if 0
279 Real fExtDdN = m_pkSegment->Extent*fDdN;
280 if (-fExtDdN <= fQdN && fQdN <= fExtDdN)
281 {
282 // segment intersects triangle
283 return true;
284 }
285#endif
286 Real fInv = ((Real)1.0)/fDdN;
287 Real t = fQdN*fInv;
288 //Real b1 = fDdQxE2*fInv;
289 //Real b2 = fDdE1xQ*fInv;
290 //Real b0 = (Real)1.0 - b1 - b2;
291 // P = origin + t*direction = b0*V0 + b1*V1 + b2*V2
292 //info() << "** INTERSECT POS=" << b0 << " y=" << b1 << " z=" << b2 << " T=" << t;
293 //Real intersect_p = origin + t*direction;
294 return t;
295
296 // else: |t| > extent, no intersection
297 }
298 // else: b1+b2 > 1, no intersection
299 }
300 // else: b2 < 0, no intersection
301 }
302 // else: b1 < 0, no intersection
303
304 return (-1.0);
305}
306
307/*---------------------------------------------------------------------------*/
308/*---------------------------------------------------------------------------*/
309
310bool RayTriangle3DIntersection::
311checkBoundingBox(Real3 origin,Real3 direction,Real3 box_min,Real3 box_max)
312{
313 Real3 box_center = (box_max+box_min) * 0.5;
314 Real afWdU[3], afAWdU[3], afDdU[3], afADdU[3], afAWxDdU[3], fRhs;
315
316 Real3 kDiff = origin - box_center;
317 Real3 Axis[3];
318 //Axis[0].x = box_max.x - box_min.x;
319 //Axis[1].y = box_max.y - box_min.y;
320 //Axis[2].z = box_max.z - box_min.z;
321 Axis[0] = Real3(1.0,0.0,0.0);
322 Axis[1] = Real3(0.0,1.0,0.0);
323 Axis[2] = Real3(0.0,0.0,1.0);
324 Real Extent[3];
325 Extent[0] = box_max.x - box_min.x;
326 Extent[1] = box_max.y - box_min.y;
327 Extent[2] = box_max.z - box_min.z;
328
329 afWdU[0] = math::dot(direction,Axis[0]);
330 afAWdU[0] = math::abs(afWdU[0]);
331 afDdU[0] = math::dot(kDiff,Axis[0]);
332 afADdU[0] = math::abs(afDdU[0]);
333 if (afADdU[0] > Extent[0] && afDdU[0]*afWdU[0] >= (Real)0.0)
334 {
335 return false;
336 }
337
338 afWdU[1] = math::dot(direction,Axis[1]);
339 afAWdU[1] = math::abs(afWdU[1]);
340 afDdU[1] = math::dot(kDiff,Axis[1]);
341 afADdU[1] = math::abs(afDdU[1]);
342 if (afADdU[1] > Extent[1] && afDdU[1]*afWdU[1] >= (Real)0.0)
343 {
344 return false;
345 }
346
347 afWdU[2] = math::dot(direction,Axis[2]);
348 afAWdU[2] = math::abs(afWdU[2]);
349 afDdU[2] = math::dot(kDiff,Axis[2]);
350 afADdU[2] = math::abs(afDdU[2]);
351 if (afADdU[2] > Extent[2] && afDdU[2]*afWdU[2] >= (Real)0.0)
352 {
353 return false;
354 }
355
356 Real3 kWxD = math::vecMul(direction,kDiff);
357
358 afAWxDdU[0] = math::abs(math::dot(kWxD,Axis[0]));
359 fRhs = Extent[1]*afAWdU[2] + Extent[2]*afAWdU[1];
360 if (afAWxDdU[0] > fRhs)
361 {
362 return false;
363 }
364
365 afAWxDdU[1] = math::abs(math::dot(kWxD,Axis[1]));
366 fRhs = Extent[0]*afAWdU[2] + Extent[2]*afAWdU[0];
367 if (afAWxDdU[1] > fRhs)
368 {
369 return false;
370 }
371
372 afAWxDdU[2] = math::abs(math::dot(kWxD,Axis[2]));
373 fRhs = Extent[0]*afAWdU[1] + Extent[1]*afAWdU[0];
374 if (afAWxDdU[2] > fRhs)
375 {
376 return false;
377 }
378
379 return true;
380}
381
382/*---------------------------------------------------------------------------*/
383/*---------------------------------------------------------------------------*/
384
386: public IRayFaceIntersector
387{
388 public:
390 : m_triangle_intersector(tm)
391 {
392 }
393 public:
394 bool computeIntersection(Real3 origin,Real3 direction,
395 Int32 orig_face_local_id,
396 Int32 face_local_id,
397 Real3ConstArrayView face_nodes,
398 Int32* user_value,
399 Real* distance,Real3* position)
400 {
401 ARCANE_UNUSED(orig_face_local_id);
402 ARCANE_UNUSED(face_local_id);
403
404 Integer nb_node = face_nodes.size();
405 switch(nb_node){
406 case 4:
407 {
408 Real3 center = (face_nodes[0] + face_nodes[1] + face_nodes[2] + face_nodes[3]) / 4.0;
409 Real d0 = m_triangle_intersector.checkIntersection(origin,direction,center,face_nodes[0],face_nodes[1]);
410 Real d1 = m_triangle_intersector.checkIntersection(origin,direction,center,face_nodes[1],face_nodes[2]);
411 Real d2 = m_triangle_intersector.checkIntersection(origin,direction,center,face_nodes[2],face_nodes[3]);
412 Real d3 = m_triangle_intersector.checkIntersection(origin,direction,center,face_nodes[3],face_nodes[0]);
413 Real d = 1.0e100;
414 bool found = false;
415 if (d0>=0.0 && d0<d){
416 found = true;
417 d = d0;
418 }
419 if (d1>=0.0 && d1<d){
420 found = true;
421 d = d1;
422 }
423 if (d2>=0.0 && d2<d){
424 found = true;
425 d = d2;
426 }
427 if (d3>=0.0 && d3<d){
428 found = true;
429 d = d3;
430 }
431 if (!found)
432 d = -1.0;
433 *distance = d;
434 *position = origin + d * direction;
435 *user_value = 1;
436 return found;
437 }
438 break;
439 default:
440 throw NotImplementedException(A_FUNCINFO,"only quad face is implemented");
441 }
442 }
443 public:
444 RayTriangle3DIntersection m_triangle_intersector;
445};
446
447/*---------------------------------------------------------------------------*/
448/*---------------------------------------------------------------------------*/
449/*!
450 * \brief Service basique de calcul d'intersection entre segments et maillage.
451 */
453: public BasicService
455{
456 public:
457
459 virtual ~BasicRayMeshIntersection() {}
460
461 public:
462
463 virtual void build(){}
464 virtual void compute(Real3ConstArrayView segments_position,
465 Real3ConstArrayView segments_direction,
466 Int32ConstArrayView segments_orig_face,
467 Int32ArrayView user_values,
468 Real3ArrayView intersections,
469 RealArrayView distances,
470 Int32ArrayView faces_local_id);
471
472 virtual void compute(IItemFamily* ray_family,
473 VariableParticleReal3& rays_position,
474 VariableParticleReal3& rays_direction,
475 VariableParticleInt32& rays_orig_face,
476 VariableParticleInt32& user_values,
477 VariableParticleReal3& intersections,
478 VariableParticleReal& distances,
479 VariableParticleInt32& rays_face);
480
481 virtual void setFaceIntersector(IRayFaceIntersector* intersector)
482 {
483 m_face_intersector = intersector;
484 }
486 {
487 return m_face_intersector;
488 }
489
490 public:
491
492 inline void _checkBoundingBox(Real3 p,Real3* ARCANE_RESTRICT min_bounding_box,
493 Real3* ARCANE_RESTRICT max_bounding_box)
494 {
495 if (p.x<min_bounding_box->x)
496 min_bounding_box->x = p.x;
497 if (p.y<min_bounding_box->y)
498 min_bounding_box->y = p.y;
499 if (p.z<min_bounding_box->z)
500 min_bounding_box->z = p.z;
501
502 if (p.x>max_bounding_box->x)
503 max_bounding_box->x = p.x;
504 if (p.y>max_bounding_box->y)
505 max_bounding_box->y = p.y;
506 if (p.z>max_bounding_box->z)
507 max_bounding_box->z = p.z;
508 }
509
510 void _writeSegments(Int32 rank,
511 Real3ConstArrayView positions,
512 Real3ConstArrayView directions,
513 RealConstArrayView distances);
514 private:
515 IRayFaceIntersector* m_face_intersector;
516};
517
518/*---------------------------------------------------------------------------*/
519/*---------------------------------------------------------------------------*/
520
521BasicRayMeshIntersection::
522BasicRayMeshIntersection(const ServiceBuildInfo& sbi)
523: BasicService(sbi)
524, m_face_intersector(0)
525{
526}
527
528/*---------------------------------------------------------------------------*/
529/*---------------------------------------------------------------------------*/
530
532compute(Real3ConstArrayView segments_position,
533 Real3ConstArrayView segments_direction,
534 Int32ConstArrayView segments_orig_face,
535 Int32ArrayView user_values,
536 Real3ArrayView segments_intersection,
537 RealArrayView segments_distance,
538 Int32ArrayView faces_local_id)
539{
540 IMesh* mesh = this->mesh();
541
542 bool is_3d = mesh->dimension()==3;
543 info() << "COMPUTE INTERSECTION!!";
544 FaceGroup outer_faces = mesh->outerFaces();
545 Integer nb_face = outer_faces.size();
546 Integer nb_segment = segments_position.size();
547 info() << "NB OUTER FACE=" << nb_face << " NB_SEGMENT=" << nb_segment;
548 VariableNodeReal3 nodes_coordinates(mesh->nodesCoordinates());
549 const Real max_value = 1.0e100;
550 const Real3 max_bb(max_value,max_value,max_value);
551 const Real3 min_bb(-max_value,-max_value,-max_value);
552
553 Real3 mesh_min_bounding_box(max_bb);
554 Real3 mesh_max_bounding_box(min_bb);
555 Integer max_face_local_id = mesh->faceFamily()->maxLocalId();
556 Real3UniqueArray faces_min_bb(max_face_local_id);
557 Real3UniqueArray faces_max_bb(max_face_local_id);
558
559 // Calcule les bounding box
560 {
561 ENUMERATE_FACE(iface,outer_faces){
562 Int32 lid = iface.localId();
563 Real3 face_max_bb(max_bb);
564 Real3 face_min_bb(min_bb);
565 for( NodeEnumerator inode((*iface).nodes()); inode.hasNext(); ++inode )
566 _checkBoundingBox(nodes_coordinates[inode],&face_min_bb,&face_max_bb);
567 _checkBoundingBox(face_min_bb,&mesh_min_bounding_box,&mesh_max_bounding_box);
568 _checkBoundingBox(face_max_bb,&mesh_min_bounding_box,&mesh_max_bounding_box);
569 //TODO: peut-etre ajouter un epsilon autour de le BB pour eviter
570 // les erreurs d'arrondi dans la determination de l'intersection
571 faces_min_bb[lid] = face_min_bb;
572 faces_max_bb[lid] = face_max_bb;
573 }
574 }
575
576 //RealArray segments_distance;
577 segments_distance.fill(max_value);
578 faces_local_id.fill(NULL_ITEM_LOCAL_ID);
579
580 if (!m_face_intersector)
581 m_face_intersector = new BasicRayFaceIntersector(traceMng());
582
583 Real3UniqueArray face_nodes;
584 for( Integer i=0; i<nb_segment; ++i ){
585 Real3 position = segments_position[i];
586 Real3 direction = segments_direction[i];
587 Int32 orig_face_local_id = segments_orig_face[i];
588 Real3 intersection;
589 Real distance = 1.0e100;
590 Int32 min_face_local_id = NULL_ITEM_LOCAL_ID;
591 Int32 user_value = 0;
592 ENUMERATE_FACE(iface,outer_faces){
593 const Face& face = *iface;
594 // On ne traite que ses propres faces
595 if (!face.isOwn())
596 continue;
597 Int32 lid = face.localId();
598 // En 3D, cherche si intersection avec la bounding box.
599 // s'il n'y en a pas, inutile d'aller plus loin.
600 bool is_bb = true;
601 if (is_3d)
602 is_bb = RayTriangle3DIntersection::checkBoundingBox(position,direction,faces_min_bb[lid],faces_max_bb[lid]);
603 if (!is_bb)
604 continue;
605 Integer nb_node = face.nbNode();
606 face_nodes.resize(nb_node);
607 for( NodeEnumerator inode(face.nodes()); inode.hasNext(); ++inode )
608 face_nodes[inode.index()] = nodes_coordinates[inode];
609 Real d = 0.0;
610 Real3 local_intersection;
611 Int32 uv = 0;
612 bool is_found = m_face_intersector->computeIntersection(position,direction,orig_face_local_id,lid,
613 face_nodes,&uv,&d,&local_intersection);
614 //if (i==15){
615 // for( Integer z=0; z<nb_node; ++z )
616 // info() << "FACE NODE lid=" << lid << " I=" << i << " v=" << face_nodes[z] << " d=" << d;
617 //}
618 //if (!is_bb)
619 //info() << "CHECK INTERSECTION: is_bb=" << is_bb << " " << is_found << '\n';
620 if (is_found && !is_bb)
621 fatal() << "Intersection found but no bounding box intersection";
622 if (is_found && d<distance){
623 distance = d;
624 min_face_local_id = lid;
625 intersection = local_intersection;
626 user_value = uv;
627 }
628 }
629 if (min_face_local_id==NULL_ITEM_LOCAL_ID)
630 distance = -1.0;
631 segments_distance[i] = distance;
632 segments_intersection[i] = intersection;
633 faces_local_id[i] = min_face_local_id;
634 user_values[i] = user_value;
635 }
636}
637
639{
640 Int32 contrib_owner;
641 Int32 owner;
642 Int32 local_id;
643 Int32 face_local_id;
644 Int32 orig_face_local_id;
645 Int32 user_value;
646 Real distance;
647 Real3POD intersection;
648};
649
650
651/*---------------------------------------------------------------------------*/
652/*---------------------------------------------------------------------------*/
653
655compute(IItemFamily* ray_family,
656 VariableParticleReal3& rays_position,
657 VariableParticleReal3& rays_direction,
658 VariableParticleInt32& rays_orig_face,
659 VariableParticleInt32& rays_user_value,
660 VariableParticleReal3& intersections,
661 VariableParticleReal& distances,
662 VariableParticleInt32& rays_face)
663{
664 // NOTE: rays_orig_face n'est pas utilisé.
665
666 IMesh* mesh = ray_family->mesh();
667 IParallelMng* pm = mesh->parallelMng();
668 Int32 my_rank = pm->commRank();
669 // Suppose que les rayons sont compactés
670 Integer nb_local_ray = ray_family->allItems().size();
671 //if (nb_local_ray!=ray_family->maxLocalId()){
672 //fatal() << "La famille de rayons doit être compactée nb=" << nb_local_ray
673 // << " max_id=" << ray_family->maxLocalId();
674 //}
675 Integer global_nb_ray = pm->reduce(Parallel::ReduceSum,nb_local_ray);
676 if (global_nb_ray==0)
677 return;
678 info() << "LOCAL_NB_RAY=" << nb_local_ray << " GLOBAL=" << global_nb_ray;
679
680 // Recopie dans un tableau local les informations d'entrée.
681 // Cela est toujours nécessaire car les particules ne sont pas forcément
682 // compactées et il peut y avoir des trous dans la numérotation.
683 Real3UniqueArray local_positions(nb_local_ray);
684 Real3UniqueArray local_directions(nb_local_ray);
685
686 ENUMERATE_PARTICLE(iitem,ray_family->allItems()){
687 Integer index = iitem.index();
688 //local_ids[index] = iitem.localId();
689 //unique_ids[index] = (*iitem).uniqueId();
690 local_positions[index] = rays_position[iitem];
691 local_directions[index] = rays_direction[iitem];
692 }
693
694 if (pm->isParallel()){
695
696 Int32UniqueArray local_ids(nb_local_ray);
697 Int64UniqueArray unique_ids(nb_local_ray);
698 ENUMERATE_ITEM(iitem,ray_family->allItems()){
699 Integer index = iitem.index();
700 local_ids[index] = iitem.localId();
701 unique_ids[index] = (*iitem).uniqueId();
702 }
703
704 // En parallèle, pour l'instant récupère les rayons des autres processeurs
705
706 Real3UniqueArray all_positions;
707 pm->allGatherVariable(local_positions,all_positions);
708 Real3UniqueArray all_directions;
709 pm->allGatherVariable(local_directions,all_directions);
710
711 Int32UniqueArray local_owners(nb_local_ray);
712 local_owners.fill(my_rank);
713
714 Int32UniqueArray all_owners;
715 pm->allGatherVariable(local_owners,all_owners);
716 Int32UniqueArray all_local_ids;
717 pm->allGatherVariable(local_ids,all_local_ids);
718 Int64UniqueArray all_unique_ids;
719 pm->allGatherVariable(unique_ids,all_unique_ids);
720
721 Int32UniqueArray all_user_values(global_nb_ray);
722 Int32UniqueArray all_orig_faces(global_nb_ray,NULL_ITEM_LOCAL_ID);
723 RealUniqueArray all_distances(global_nb_ray);
724 Real3UniqueArray all_intersections(global_nb_ray);
725 Int32UniqueArray all_faces(global_nb_ray);
726 // Mettre à (-1) les faces dont je ne suis pas le propriétaire
727 for( Integer z=0, zn=all_orig_faces.size(); z<zn; ++z ){
728 if (all_owners[z]!=my_rank)
729 all_orig_faces[z] = NULL_ITEM_LOCAL_ID;
730 }
731 compute(all_positions,all_directions,all_orig_faces,all_user_values,all_intersections,all_distances,all_faces);
732 /*for( Integer i=0; i<global_nb_ray; ++i ){
733 info() << "RAY I=" << i << " uid=" << all_unique_ids[i] << " lid=" << all_local_ids[i]
734 << " owner=" << all_owners[i] << " position=" << all_positions[i]
735 << " direction=" << all_directions[i] << " distance=" << all_distances[i]
736 << " face=" << all_faces[i];
737 }*/
738 {
739 UniqueArray<FoundInfo> founds_info;
740
741 for( Integer i=0; i<global_nb_ray; ++i ){
742 Int32 face_lid = all_faces[i];
743 if (face_lid==NULL_ITEM_LOCAL_ID)
744 continue;
745 FoundInfo fi;
746 fi.contrib_owner = my_rank;
747 fi.owner = all_owners[i];
748 fi.local_id = all_local_ids[i];
749 fi.face_local_id = all_faces[i];
750 fi.orig_face_local_id = all_orig_faces[i];
751 fi.user_value = all_user_values[i];
752 fi.intersection = all_intersections[i];
753 fi.distance = all_distances[i];
754 founds_info.add(fi);
755 }
756 info() << "NB_FOUND=" << founds_info.size();
757 //Array<FoundInfo> global_founds_info;
758 ByteUniqueArray global_founds_info_bytes;
759 Integer finfo_byte_size = arcaneCheckArraySize(founds_info.size()*sizeof(FoundInfo));
760 ByteConstArrayView local_fi(finfo_byte_size,(const Byte*)founds_info.data());
761 pm->allGatherVariable(local_fi,global_founds_info_bytes);
762 Integer gfi_byte_size = arcaneCheckArraySize(global_founds_info_bytes.size()/sizeof(FoundInfo));
763 ConstArrayView<FoundInfo> global_founds_info(gfi_byte_size,(const FoundInfo*)global_founds_info_bytes.data());
764 Integer nb_total_found = global_founds_info.size();
765 ParticleInfoListView rays(ray_family);
766 rays_face.fill(NULL_ITEM_LOCAL_ID);
767 distances.fill(0.0);
768 VariableItemInt32& rays_new_owner = ray_family->itemsNewOwner();
769 rays_new_owner.fill(my_rank);
770 for( Integer i=0; i<nb_total_found; ++i ){
771 const FoundInfo& fi = global_founds_info[i];
772 Int32 owner = fi.owner;
773 // Il ne faut traiter que ses propres rayons
774 if (owner!=my_rank)
775 continue;
776 Int32 local_id = fi.local_id;
777 Particle ray = rays[local_id];
778 Real distance = fi.distance;
779 if ((rays_face[ray]==NULL_ITEM_LOCAL_ID) || distance<distances[ray]){
780 distances[ray] = distance;
781 intersections[ray] = Real3(fi.intersection.x,fi.intersection.y,fi.intersection.z);
782 rays_face[ray] = fi.face_local_id;
783 rays_user_value[ray] = fi.user_value;
784 rays_new_owner[ray] = fi.contrib_owner;
785 //info() << "SET RAY uid=" << ray.uniqueId() << " distance=" << distance << " new_owner=" << fi.contrib_owner;
786 }
787 /*info() << "GLOBAL RAY I=" << i << " uid=" << ray.uniqueId() << " lid=" << fi.local_id
788 << " owner=" << fi.owner
789 << " distance=" << fi.distance
790 << " contrib_owner=" << fi.contrib_owner
791 << " face=" << fi.face_local_id
792 << " new_owner=" << rays_new_owner[ray];*/
793 }
794 ray_family->toParticleFamily()->exchangeParticles();
795 }
796 }
797 else{
798
799 Int32UniqueArray orig_faces(nb_local_ray);
800 Int32UniqueArray user_values(nb_local_ray);
801
802 ENUMERATE_PARTICLE(iitem,ray_family->allItems()){
803 Integer index = iitem.index();
804 orig_faces[index] = rays_orig_face[iitem];
805 user_values[index] = rays_user_value[iitem];
806 }
807
808 Real3UniqueArray out_intersections(nb_local_ray);
809 RealUniqueArray out_distances(nb_local_ray);
810 Int32UniqueArray out_faces(nb_local_ray);
811
812 compute(local_positions,local_directions,orig_faces,user_values,out_intersections,out_distances,out_faces);
813
814 // Recopie en sortie les valeurs dans les variables correspondantes.
815 ENUMERATE_PARTICLE(iitem,ray_family->allItems()){
816 Integer index = iitem.index();
817 intersections[iitem] = out_intersections[index];
818 distances[iitem] = out_distances[index];
819 rays_face[iitem] = out_faces[index];
820 }
821
822 }
823
824 // Pour test, écrit les rayons et leur point d'impact.
825 {
826 Integer nb_new_ray = ray_family->nbItem();
827 RealUniqueArray local_distances(nb_new_ray);
828 local_directions.resize(nb_new_ray);
829 local_positions.resize(nb_new_ray);
830 ENUMERATE_PARTICLE(iitem,ray_family->allItems()){
831 Integer index = iitem.index();
832 local_distances[index] = distances[iitem];
833 local_directions[index] = rays_direction[iitem];
834 local_positions[index] = rays_position[iitem];
835 }
836 if (global_has_lima)
837 _writeSegments(my_rank,local_positions,local_directions,local_distances);
838 }
839
840}
841
842/*---------------------------------------------------------------------------*/
843/*---------------------------------------------------------------------------*/
844
845/*---------------------------------------------------------------------------*/
846/*---------------------------------------------------------------------------*/
847
848void BasicRayMeshIntersection::
849_writeSegments(Int32 rank,
850 Real3ConstArrayView positions,
851 Real3ConstArrayView directions,
852 RealConstArrayView distances)
853{
854#ifdef ARCANE_HAS_PACKAGE_LIMA
855 Lima::Maillage lima("segments");
856 lima.dimension(Lima::D3);
857
858 Integer nb_segment = positions.size();
859 UniqueArray<Lima::Noeud> lm_nodes(nb_segment*2);
860 for( Integer i=0; i<nb_segment; ++i ){
861 Real t = distances[i];
862 if (t<0.0)
863 t = 10.0;
864 lm_nodes[i*2].set_x(positions[i].x);
865 lm_nodes[i*2].set_y(positions[i].y);
866 lm_nodes[i*2].set_z(positions[i].z);
867
868 lm_nodes[(i*2)+1].set_x(positions[i].x + t*directions[i].x);
869 lm_nodes[(i*2)+1].set_y(positions[i].y + t*directions[i].y);
870 lm_nodes[(i*2)+1].set_z(positions[i].z + t*directions[i].z);
871 lima.ajouter(lm_nodes[(i*2)]);
872 lima.ajouter(lm_nodes[(i*2)+1]);
873 lima.ajouter(Lima::Bras(lm_nodes[i*2],lm_nodes[(i*2)+1]));
874 }
875 StringBuilder sb("segments");
876 sb+=rank;
877 sb+=".unf";
878 std::string s(sb.toString().localstr());
879 lima.ecrire(s);
880#else
881 ARCANE_UNUSED(rank);
882 ARCANE_UNUSED(positions);
883 ARCANE_UNUSED(directions);
884 ARCANE_UNUSED(distances);
885 ARCANE_THROW(NotSupportedException,"Lima is not available");
886#endif
887}
888
889/*---------------------------------------------------------------------------*/
890/*---------------------------------------------------------------------------*/
891
892ARCANE_REGISTER_SUB_DOMAIN_FACTORY(BasicRayMeshIntersection,IRayMeshIntersection,
893 BasicRayMeshIntersection);
894
895/*---------------------------------------------------------------------------*/
896/*---------------------------------------------------------------------------*/
897
898} // End namespace Arcane
899
900/*---------------------------------------------------------------------------*/
901/*---------------------------------------------------------------------------*/
#define ARCANE_THROW(exception_class,...)
Macro pour envoyer une exception avec formattage.
#define ENUMERATE_FACE(name, group)
Enumérateur générique d'un groupe de faces.
#define ENUMERATE_PARTICLE(name, group)
Enumérateur générique d'un groupe de particules.
#define ENUMERATE_ITEM(name, group)
Enumérateur générique d'un groupe de noeuds.
#define ARCANE_REGISTER_SUB_DOMAIN_FACTORY(aclass, ainterface, aname)
Enregistre un service de fabrique pour la classe aclass.
bool computeIntersection(Real3 origin, Real3 direction, Int32 orig_face_local_id, Int32 face_local_id, Real3ConstArrayView face_nodes, Int32 *user_value, Real *distance, Real3 *position)
Calcul l'intersection entre un rayon et une face.
Service basique de calcul d'intersection entre segments et maillage.
virtual void build()
Construction de niveau build du service.
virtual void setFaceIntersector(IRayFaceIntersector *intersector)
Positionne le callback d'intersection.
virtual IRayFaceIntersector * faceIntersector()
Intersecteur utilisé (0 si aucun spécifié)
virtual void compute(Real3ConstArrayView segments_position, Real3ConstArrayView segments_direction, Int32ConstArrayView segments_orig_face, Int32ArrayView user_values, Real3ArrayView intersections, RealArrayView distances, Int32ArrayView faces_local_id)
Calcule l'intersection.
Classe de base de service lié à un sous-domaine.
Face d'une maille.
Definition Item.h:932
Interface d'une famille d'entités.
virtual IParticleFamily * toParticleFamily()=0
Retourne l'interface de la famille de particule de cette famille.
virtual ItemGroup allItems() const =0
Groupe de toutes les entités.
virtual Int32 maxLocalId() const =0
virtual IMesh * mesh() const =0
Maillage associé
virtual Integer nbItem() const =0
Nombre d'entités.
virtual VariableItemInt32 & itemsNewOwner()=0
Variable contenant le numéro du nouveau sous-domaine propriétaire de l'entité.
virtual FaceGroup outerFaces()=0
Groupe de toutes les faces sur la frontière.
virtual Integer dimension()=0
Dimension du maillage (1D, 2D ou 3D).
virtual IItemFamily * faceFamily()=0
Retourne la famille des faces.
virtual VariableNodeReal3 & nodesCoordinates()=0
Coordonnées des noeuds.
virtual IParallelMng * parallelMng()=0
Gestionnaire de parallèlisme.
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual void allGatherVariable(ConstArrayView< char > send_buf, Array< char > &recv_buf)=0
Effectue un regroupement sur tous les processeurs.
virtual bool isParallel() const =0
Retourne true si l'exécution est parallèle.
virtual char reduce(eReduceType rt, char v)=0
Effectue la réduction de type rt sur le réel v et retourne la valeur.
virtual void exchangeParticles()=0
Échange des entités.
Interface générique du calcul de l'intersection d'un rayon avec une face.
virtual bool computeIntersection(Real3 origin, Real3 direction, Int32 orig_face_local_id, Int32 face_local_id, Real3ConstArrayView face_nodes, Int32 *user_value, Real *distance, Real3 *intersection_position)=0
Calcul l'intersection entre un rayon et une face.
Calcul de l'intersection entre un ensemble de segments et la surface d'un maillage.
Integer size() const
Nombre d'éléments du groupe.
Definition ItemGroup.h:88
Variable scalaire sur un type d'entité du maillage.
NodeConnectedListViewType nodes() const
Liste des noeuds de l'entité
Definition Item.h:771
Int32 nbNode() const
Nombre de noeuds de l'entité
Definition Item.h:765
constexpr Int32 localId() const
Identifiant local de l'entité dans le sous-domaine du processeur.
Definition Item.h:210
bool isOwn() const
true si l'entité est appartient au sous-domaine
Definition Item.h:244
Variable scalaire sur un type d'entité du maillage.
Vue sur les informations des particules.
Particule.
Definition Item.h:1383
Calcul l'intersection d'un rayon avec un ensemble de triangles en 3D.
void setRays(Real3ConstArrayView origins, Real3ConstArrayView directions)
Position la liste des rayons dont on souhaite calculer l'intersection.
Real checkIntersection(Real3 origin, Real3 direction, Real3 p0, Real3 p1, Real3 p2)
Calcul l'intersection de la demi-droite [origin,direction) avec le triangle (p0,p1,...
void compute()
Calcul l'intersection de chaque rayon avec la liste des triangles. Si un rayon intersecte plusieurs t...
void setTriangles(Real3ConstArrayView coordinates, Int32ConstArrayView indexes)
Positionne la liste des triangles dont on souhaite calculer l'intersection avec les rayons....
Int32ConstArrayView intersectedTriangleIndexes()
Indices des triangles intersectés. Indice dans le tableau donnée par setTriangles() du triangle inter...
RealConstArrayView distances()
Distance de l'origine d'un rayon à son point d'intersection. Distance (exprimée relativivement à la n...
Classe gérant un vecteur de réel de dimension 3.
Definition Real3.h:132
Structure contenant les informations pour créer un service.
Integer size() const
Nombre d'éléments du vecteur.
Vue modifiable d'un tableau d'un type T.
void fill(const T &o) noexcept
Remplit le tableau avec la valeur o.
const T * data() const
Accès à la racine du tableau hors toute protection.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
void fill(ConstReferenceType value)
Remplit le tableau avec la valeur value.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
Vue constante d'un tableau de type T.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
Exception lorsqu'une erreur fatale est survenue.
Interface du gestionnaire de traces.
TraceMessage fatal() const
Flot pour un message d'erreur fatale.
ITraceMng * traceMng() const
Gestionnaire de trace.
TraceMessage info() const
Flot pour un message d'information.
Vecteur 1D de données avec sémantique par valeur (style STL).
__host__ __device__ Real dot(Real2 u, Real2 v)
Produit scalaire de u par v dans .
Definition MathUtils.h:96
__host__ __device__ Real3 vecMul(Real3 u, Real3 v)
Produit vectoriel de u par v. dans .
Definition MathUtils.h:52
ItemEnumeratorT< Node > NodeEnumerator
Enumérateurs sur des noeuds.
Definition ItemTypes.h:254
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
Integer arcaneCheckArraySize(unsigned long long size)
Vérifie que size peut être converti dans un 'Integer' pour servir de taille à un tableau....
ConstArrayView< Real3 > Real3ConstArrayView
Equivalent C d'un tableau à une dimension de Real3.
Definition UtilsTypes.h:654
ConstArrayView< Real > RealConstArrayView
Equivalent C d'un tableau à une dimension de réels.
Definition UtilsTypes.h:646
unsigned char Byte
Type d'un octet.
Definition UtilsTypes.h:142
Real y
deuxième composante du triplet
Definition Real3.h:36
Real z
troisième composante du triplet
Definition Real3.h:37
Real x
première composante du triplet
Definition Real3.h:35