MOAB: Mesh Oriented datABase  (version 5.5.0)
intx_on_sphere_test.cpp File Reference
#include <iostream>
#include <sstream>
#include <ctime>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include "moab/Core.hpp"
#include "moab/IntxMesh/Intx2MeshOnSphere.hpp"
#include "moab/IntxMesh/IntxUtils.hpp"
#include "TestUtil.hpp"
#include "moab/ProgOptions.hpp"
#include <cmath>
+ Include dependency graph for intx_on_sphere_test.cpp:

Go to the source code of this file.

Functions

int main (int argc, char *argv[])
 

Function Documentation

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 25 of file intx_on_sphere_test.cpp.

26 {
27 
28  std::string firstModel, secondModel, outputFile;
29 
30  firstModel = TestDir + "unittest/mbcslam/lagrangeHomme.vtk";
31  secondModel = TestDir + "unittest/mbcslam/eulerHomme.vtk";
32 
33  ProgOptions opts;
34  opts.addOpt< std::string >( "first,t", "first mesh filename (source)", &firstModel );
35  opts.addOpt< std::string >( "second,m", "second mesh filename (target)", &secondModel );
36  opts.addOpt< std::string >( "outputFile,o", "output intersection file", &outputFile );
37 
38  double R = 1.; // input
39  double epsrel = 1.e-12;
40  double boxeps = 1.e-4;
41  outputFile = "intx.h5m";
42  opts.addOpt< double >( "radius,R", "radius for model intx", &R );
43  opts.addOpt< double >( "epsilon,e", "relative error in intx", &epsrel );
44  opts.addOpt< double >( "boxerror,b", "relative error for box boundaries", &boxeps );
45 
46  int output_fraction = 0;
47  int write_files_rank = 0;
48  int brute_force = 0;
49 
50  opts.addOpt< int >( "outputFraction,f", "output fraction of areas", &output_fraction );
51  opts.addOpt< int >( "writeFiles,w", "write files of interest", &write_files_rank );
52  opts.addOpt< int >( "kdtreeOption,k", "use kd tree for intersection", &brute_force );
53 
54  opts.parseCommandLine( argc, argv );
55  int rank = 0, size = 1;
56 #ifdef MOAB_HAVE_MPI
57  MPI_Init( &argc, &argv );
58  MPI_Comm_rank( MPI_COMM_WORLD, &rank );
59  MPI_Comm_size( MPI_COMM_WORLD, &size );
60 #endif
61 
62  // check command line arg second grid is red, arrival, first mesh is blue, departure
63  // will will keep the
64  std::string optsRead = ( size == 1 ? ""
65  : std::string( "PARALLEL=READ_PART;PARTITION=PARALLEL_PARTITION" ) +
66  std::string( ";PARALLEL_RESOLVE_SHARED_ENTS" ) );
67 
68  // read meshes in 2 file sets
69  ErrorCode rval;
70  Core moab;
71  Interface* mb = &moab; // global
72  EntityHandle sf1, sf2, outputSet;
73 
74  // create meshsets and load files
75 
76  rval = mb->create_meshset( MESHSET_SET, sf1 );MB_CHK_ERR( rval );
77  rval = mb->create_meshset( MESHSET_SET, sf2 );MB_CHK_ERR( rval );
78  if( 0 == rank ) std::cout << "Loading mesh file " << firstModel << "\n";
79  rval = mb->load_file( firstModel.c_str(), &sf1, optsRead.c_str() );MB_CHK_ERR( rval );
80  if( 0 == rank ) std::cout << "Loading mesh file " << secondModel << "\n";
81  rval = mb->load_file( secondModel.c_str(), &sf2, optsRead.c_str() );MB_CHK_ERR( rval );
82 
83  if( 0 == rank )
84  {
85  std::cout << "Radius: " << R << "\n";
86  std::cout << "relative eps: " << epsrel << "\n";
87  std::cout << "box eps: " << boxeps << "\n";
88  std::cout << " use kd tree for intersection: " << brute_force << "\n";
89  }
90  rval = mb->create_meshset( MESHSET_SET, outputSet );MB_CHK_ERR( rval );
91 
92  // fix radius of both meshes, to be consistent with input R
93  rval = moab::IntxUtils::ScaleToRadius( mb, sf1, R );MB_CHK_ERR( rval );
94  rval = moab::IntxUtils::ScaleToRadius( mb, sf2, R );MB_CHK_ERR( rval );
95 
96 #if 0
97  // std::cout << "Fix orientation etc ..\n";
98  //IntxUtils; those calls do nothing for a good mesh
99  rval = fix_degenerate_quads(mb, sf1);MB_CHK_ERR(rval);
100  rval = fix_degenerate_quads(mb, sf2);MB_CHK_ERR(rval);
101 
102  rval = positive_orientation(mb, sf1, R);MB_CHK_ERR(rval);
103  rval = positive_orientation(mb, sf2, R);MB_CHK_ERR(rval);
104 #endif
105 
106 #ifdef MOAB_HAVE_MPI
107  ParallelComm* pcomm = ParallelComm::get_pcomm( mb, 0 );
108 #endif
109  Intx2MeshOnSphere worker( mb );
110  IntxAreaUtils areaAdaptor;
111 
112  worker.set_error_tolerance( R * epsrel );
113  worker.set_box_error( boxeps );
114 #ifdef MOAB_HAVE_MPI
115  worker.set_parallel_comm( pcomm );
116 #endif
117  // worker.SetEntityType(moab::MBQUAD);
118  worker.set_radius_source_mesh( R );
119  worker.set_radius_destination_mesh( R );
120  // worker.enable_debug();
121 
122  rval = worker.FindMaxEdges( sf1, sf2 );MB_CHK_ERR( rval );
123 
124  EntityHandle covering_set;
125 #ifdef MOAB_HAVE_MPI
126  if( size > 1 )
127  {
128  Range local_verts;
129  rval = worker.build_processor_euler_boxes( sf2, local_verts );MB_CHK_ERR( rval ); // output also the local_verts
130  if( write_files_rank )
131  {
132  std::stringstream outf;
133  outf << "second_mesh" << rank << ".h5m";
134  rval = mb->write_file( outf.str().c_str(), 0, 0, &sf2, 1 );MB_CHK_ERR( rval );
135  }
136  }
137  if( size > 1 )
138  {
139  double elapsed = MPI_Wtime();
140  rval = mb->create_meshset( moab::MESHSET_SET, covering_set );MB_CHK_SET_ERR( rval, "Can't create new set" );
141  bool gnomonic = true;
142  rval = worker.construct_covering_set( sf1, covering_set, gnomonic );MB_CHK_ERR( rval ); // lots of communication if mesh is distributed very differently
143  elapsed = MPI_Wtime() - elapsed;
144  if( 0 == rank ) std::cout << "\nTime to communicate the mesh = " << elapsed << std::endl;
145  // area fraction of the covering set that needed to be communicated from other processors
146  // number of elements in the covering set communicated, compared to total number of elements
147  // in the covering set
148  if( output_fraction )
149  {
150  EntityHandle comm_set; // set with elements communicated from other tasks
151  rval = mb->create_meshset( MESHSET_SET, comm_set );MB_CHK_ERR( rval );
152  // see how much more different is compared to sf1
153  rval = mb->unite_meshset( comm_set, covering_set );MB_CHK_ERR( rval ); // will have to subtract from covering set, initial set
154  // subtract
155  rval = mb->subtract_meshset( comm_set, sf1 );MB_CHK_ERR( rval );
156  // compute fractions
157  double area_cov_set = areaAdaptor.area_on_sphere( mb, covering_set, R );
158  assert( area_cov_set > 0 );
159  double comm_area = areaAdaptor.area_on_sphere( mb, comm_set, R );
160  // more important is actually the number of elements communicated
161  int num_cov_cells, num_comm_cells;
162  rval = mb->get_number_entities_by_dimension( covering_set, 2, num_cov_cells );MB_CHK_ERR( rval );
163  rval = mb->get_number_entities_by_dimension( comm_set, 2, num_comm_cells );MB_CHK_ERR( rval );
164  double fraction_area = comm_area / area_cov_set;
165  double fraction_num_cells =
166  (double)num_comm_cells / num_cov_cells; // determine min, max, average of these fractions
167 
168  double max_fraction_area, max_fraction_num_cells, min_fraction_area, min_fraction_num_cells;
169  double average_fraction_area, average_fraction_num_cells;
170  MPI_Reduce( &fraction_area, &max_fraction_area, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD );
171  MPI_Reduce( &fraction_num_cells, &max_fraction_num_cells, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD );
172  MPI_Reduce( &fraction_area, &min_fraction_area, 1, MPI_DOUBLE, MPI_MIN, 0, MPI_COMM_WORLD );
173  MPI_Reduce( &fraction_num_cells, &min_fraction_num_cells, 1, MPI_DOUBLE, MPI_MIN, 0, MPI_COMM_WORLD );
174  MPI_Reduce( &fraction_area, &average_fraction_area, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD );
175  MPI_Reduce( &fraction_num_cells, &average_fraction_num_cells, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD );
176  average_fraction_area /= size;
177  average_fraction_num_cells /= size;
178  if( rank == 0 )
179  {
180  std::cout << " fraction area: min: " << min_fraction_area << " max: " << max_fraction_area
181  << " average :" << average_fraction_area << " \n";
182  std::cout << " fraction num cells: min: " << min_fraction_num_cells
183  << " max: " << max_fraction_num_cells << " average: " << average_fraction_num_cells << " \n";
184  }
185  }
186  if( write_files_rank )
187  {
188  std::stringstream cof;
189  cof << "covering_mesh" << rank << ".h5m";
190  rval = mb->write_file( cof.str().c_str(), 0, 0, &covering_set, 1 );MB_CHK_ERR( rval );
191  }
192  }
193  else
194 #endif
195  covering_set = sf1;
196 
197  if( 0 == rank ) std::cout << "Computing intersections ..\n";
198 #ifdef MOAB_HAVE_MPI
199  double elapsed = MPI_Wtime();
200 #endif
201  if( brute_force )
202  {
203  rval = worker.intersect_meshes_kdtree( covering_set, sf2, outputSet );MB_CHK_SET_ERR( rval, "failed to intersect meshes with slow method" );
204  }
205  else
206  {
207  rval = worker.intersect_meshes( covering_set, sf2, outputSet );MB_CHK_SET_ERR( rval, "failed to intersect meshes" );
208  }
209 #ifdef MOAB_HAVE_MPI
210  elapsed = MPI_Wtime() - elapsed;
211  if( 0 == rank ) std::cout << "\nTime to compute the intersection between meshes = " << elapsed << std::endl;
212 #endif
213  // the output set does not have the intx vertices on the boundary shared, so they will be
214  // duplicated right now we write this file just for checking it looks OK
215 
216  // compute total area with 2 methods
217  // double initial_area = areaAdaptor.area_on_sphere_lHuiller(mb, sf1, R);
218  // double area_method1 = areaAdaptor.area_on_sphere_lHuiller(mb, outputSet, R);
219  // double area_method2 = areaAdaptor.area_on_sphere(mb, outputSet, R);
220 
221  // std::cout << "initial area: " << initial_area << "\n";
222  // std::cout<< " area with l'Huiller: " << area_method1 << " with Girard: " << area_method2<<
223  // "\n"; std::cout << " relative difference areas " <<
224  // fabs(area_method1-area_method2)/area_method1 << "\n"; std::cout << " relative error " <<
225  // fabs(area_method1-initial_area)/area_method1 << "\n";
226 
227  if( write_files_rank )
228  {
229  std::stringstream outf;
230  outf << "intersect" << rank << ".h5m";
231  rval = mb->write_file( outf.str().c_str(), 0, 0, &outputSet, 1 );
232  }
233  double intx_area = areaAdaptor.area_on_sphere( mb, outputSet, R );
234  double arrival_area = areaAdaptor.area_on_sphere( mb, sf2, R );
235  std::cout << "On rank : " << rank << " arrival area: " << arrival_area << " intersection area:" << intx_area
236  << " rel error: " << fabs( ( intx_area - arrival_area ) / arrival_area ) << "\n";
237 
238 #ifdef MOAB_HAVE_MPI
239 #ifdef MOAB_HAVE_HDF5_PARALLEL
240  rval = mb->write_file( outputFile.c_str(), 0, "PARALLEL=WRITE_PART", &outputSet, 1 );MB_CHK_SET_ERR( rval, "failed to write intx file" );
241 #else
242  // write intx set on rank 0, in serial; we cannot write in parallel
243  if( 0 == rank )
244  {
245  rval = mb->write_file( outputFile.c_str(), 0, 0, &outputSet, 1 );MB_CHK_SET_ERR( rval, "failed to write intx file" );
246  }
247 #endif
248  MPI_Finalize();
249 #else
250  rval = mb->write_file( outputFile.c_str(), 0, 0, &outputSet, 1 );MB_CHK_SET_ERR( rval, "failed to write intx file" );
251 #endif
252  return 0;
253 }

References ProgOptions::addOpt(), moab::IntxAreaUtils::area_on_sphere(), moab::Core::create_meshset(), ErrorCode, moab::Intx2Mesh::FindMaxEdges(), moab::Core::get_number_entities_by_dimension(), moab::ParallelComm::get_pcomm(), moab::Intx2Mesh::intersect_meshes(), moab::Intx2Mesh::intersect_meshes_kdtree(), moab::Core::load_file(), mb, MB_CHK_ERR, MB_CHK_SET_ERR, MESHSET_SET, MPI_COMM_WORLD, ProgOptions::parseCommandLine(), moab::R, rank, moab::IntxUtils::ScaleToRadius(), moab::Intx2Mesh::set_box_error(), moab::Intx2Mesh::set_error_tolerance(), moab::Intx2MeshOnSphere::set_radius_destination_mesh(), moab::Intx2MeshOnSphere::set_radius_source_mesh(), size, moab::Core::subtract_meshset(), moab::Core::unite_meshset(), and moab::Core::write_file().