MOAB: Mesh Oriented datABase  (version 5.5.0)
imoab_remap.cpp
Go to the documentation of this file.
1 #include "moab/MOABConfig.h"
2 
3 #ifdef MOAB_HAVE_MPI
4 #include "moab_mpi.h"
5 #endif
6 #include "moab/iMOAB.h"
7 #include "TestUtil.hpp"
8 #include "moab/CpuTimer.hpp"
9 #include "moab/ProgOptions.hpp"
10 
11 // for malloc, free:
12 #include <iostream>
13 #include <iomanip>
14 
15 #define CHECKIERR( ierr, message ) \
16  if( 0 != ( ierr ) ) \
17  { \
18  printf( "%s", message ); \
19  return 1; \
20  }
21 
22 #define ENABLE_ATMLND_COUPLING
23 // this test will be run in serial only
24 int main( int argc, char* argv[] )
25 {
26  ErrCode ierr;
27  std::string atmFilename, ocnFilename, lndFilename, mapFilename;
28 
29  atmFilename = TestDir + "unittest/wholeATM_T.h5m";
30  ocnFilename = TestDir + "unittest/recMeshOcn.h5m";
31 #ifdef ENABLE_ATMLND_COUPLING
32  lndFilename = TestDir + "unittest/wholeLnd.h5m";
33 #endif
34  // mapFilename = TestDir + "unittest/outCS5ICOD5_map.nc";
35 
36  ProgOptions opts;
37  opts.addOpt< std::string >( "atmosphere,t", "atm mesh filename (source)", &atmFilename );
38  opts.addOpt< std::string >( "ocean,m", "ocean mesh filename (target)", &ocnFilename );
39 #ifdef ENABLE_ATMLND_COUPLING
40  opts.addOpt< std::string >( "land,l", "land mesh filename (target)", &lndFilename );
41 #endif
42  bool gen_baseline = false;
43  opts.addOpt< void >( "genbase,g", "generate baseline 1", &gen_baseline );
44 
45  bool no_test_against_baseline = false;
46  opts.addOpt< void >( "no_testbase,t", "do not test against baseline 1", &no_test_against_baseline );
47  std::string baseline = TestDir + "unittest/baseline1.txt";
48 
49  opts.parseCommandLine( argc, argv );
50 
51  {
52  std::cout << " atm file: " << atmFilename << "\n ocn file: " << ocnFilename
53 #ifdef ENABLE_ATMLND_COUPLING
54  << "\n lnd file: " << lndFilename
55 #endif
56  << "\n";
57  }
58 
59 #ifdef MOAB_HAVE_MPI
60  MPI_Init( &argc, &argv );
61  MPI_Comm comm = MPI_COMM_WORLD;
62 #endif
63  /*
64  * MOAB needs to be initialized; A MOAB instance will be created, and will be used by each
65  * application in this framework. There is no parallel context yet.
66  */
67  ierr = iMOAB_Initialize( argc, argv );
68  CHECKIERR( ierr, "failed to initialize MOAB" );
69 
70  int atmAppID, ocnAppID, lndAppID, atmocnAppID, atmlndAppID, lndatmAppID;
71  iMOAB_AppID atmPID = &atmAppID;
72  iMOAB_AppID ocnPID = &ocnAppID;
73  iMOAB_AppID lndPID = &lndAppID;
74  iMOAB_AppID atmocnPID = &atmocnAppID;
75  iMOAB_AppID atmlndPID = &atmlndAppID;
76  iMOAB_AppID lndatmPID = &lndatmAppID;
77 
78  /*
79  * Each application has to be registered once. A mesh set and a parallel communicator will be
80  * associated with each application. A unique application id will be returned, and will be used
81  * for all future mesh operations/queries.
82  */
83  int atmCompID = 10, ocnCompID = 20, lndCompID = 30, atmocnCompID = 100, atmlndCompID = 102, lndatmCompID = 103;
84  ierr = iMOAB_RegisterApplication( "ATM-APP",
85 #ifdef MOAB_HAVE_MPI
86  &comm,
87 #endif
88  &atmCompID, atmPID );
89  CHECKIERR( ierr, "failed to register application1" );
90 
91  ierr = iMOAB_RegisterApplication( "OCN-APP",
92 #ifdef MOAB_HAVE_MPI
93  &comm,
94 #endif
95  &ocnCompID, ocnPID );
96  CHECKIERR( ierr, "failed to register application2" );
97 #ifdef ENABLE_ATMLND_COUPLING
98  ierr = iMOAB_RegisterApplication( "LND-APP",
99 #ifdef MOAB_HAVE_MPI
100  &comm,
101 #endif
102  &lndCompID, lndPID );
103  CHECKIERR( ierr, "failed to register application3" );
104 #endif
105  ierr = iMOAB_RegisterApplication( "ATM-OCN-CPL",
106 #ifdef MOAB_HAVE_MPI
107  &comm,
108 #endif
109  &atmocnCompID, atmocnPID );
110  CHECKIERR( ierr, "failed to register application4" );
111 #ifdef ENABLE_ATMLND_COUPLING
112  ierr = iMOAB_RegisterApplication( "ATM-LND-CPL",
113 #ifdef MOAB_HAVE_MPI
114  &comm,
115 #endif
116  &atmlndCompID, atmlndPID );
117  CHECKIERR( ierr, "failed to register application5" );
118 
119  ierr = iMOAB_RegisterApplication( "LND-ATM-CPL",
120 #ifdef MOAB_HAVE_MPI
121  &comm,
122 #endif
123  &lndatmCompID, lndatmPID );
124  CHECKIERR( ierr, "failed to register application5" );
125 #endif
126  const char* read_opts = "";
127  int num_ghost_layers = 0;
128  /*
129  * Loading the mesh is a parallel IO operation. Ghost layers can be exchanged too, and default
130  * MOAB sets are augmented with ghost elements. By convention, blocks correspond to MATERIAL_SET
131  * sets, side sets with NEUMANN_SET sets, node sets with DIRICHLET_SET sets. Each element and
132  * vertex entity should have a GLOBAL ID tag in the file, which will be available for visible
133  * entities
134  */
135  ierr = iMOAB_LoadMesh( atmPID, atmFilename.c_str(), read_opts, &num_ghost_layers );
136  CHECKIERR( ierr, "failed to load mesh" );
137  ierr = iMOAB_LoadMesh( ocnPID, ocnFilename.c_str(), read_opts, &num_ghost_layers );
138  CHECKIERR( ierr, "failed to load mesh" );
139 #ifdef ENABLE_ATMLND_COUPLING
140  ierr = iMOAB_LoadMesh( lndPID, lndFilename.c_str(), read_opts, &num_ghost_layers );
141  CHECKIERR( ierr, "failed to load mesh" );
142 #endif
143 
144  int nverts[3], nelem[3];
145  /*
146  * Each process in the communicator will have access to a local mesh instance, which will
147  * contain the original cells in the local partition and ghost entities. Number of vertices,
148  * primary cells, visible blocks, number of sidesets and nodesets boundary conditions will be
149  * returned in size 3 arrays, for local, ghost and total numbers.
150  */
151  ierr = iMOAB_GetMeshInfo( atmPID, nverts, nelem, 0, 0, 0 );
152  CHECKIERR( ierr, "failed to get mesh info" );
153  printf( "Atmosphere Component Mesh: %d vertices and %d elements\n", nverts[0], nelem[0] );
154 
155  ierr = iMOAB_GetMeshInfo( ocnPID, nverts, nelem, 0, 0, 0 );
156  CHECKIERR( ierr, "failed to get mesh info" );
157  printf( "Ocean Component Mesh: %d vertices and %d elements\n", nverts[0], nelem[0] );
158 #ifdef ENABLE_ATMLND_COUPLING
159  ierr = iMOAB_GetMeshInfo( lndPID, nverts, nelem, 0, 0, 0 );
160  CHECKIERR( ierr, "failed to get mesh info" );
161  printf( "Land Component Mesh: %d vertices and %d elements\n", nverts[0], nelem[0] );
162 #endif
163  /*
164  * The 2 tags used in this example exist in the file, already.
165  * If a user needs a new tag, it can be defined with the same call as this one
166  * this method, iMOAB_DefineTagStorage, will return a local index for the tag.
167  * The name of the tag is case sensitive.
168  * This method is collective.
169  */
170  // int disc_orders[2] = {1, 1};
171  // const char* disc_methods[2] = {"fv", "fv"};
172  // const char* dof_tag_names[2] = {"GLOBAL_ID", "GLOBAL_ID"};
173  int disc_orders[3] = { 4, 1, 1 };
174  int fMonotoneTypeID = 0, fVolumetric = 0, fValidate = 0, fNoConserve = 0, fNoBubble = 1, fInverseDistanceMap = 0;
175 
176  const std::string disc_methods[3] = { "cgll", "fv", "pcloud" };
177  const std::string dof_tag_names[3] = { "GLOBAL_DOFS", "GLOBAL_ID", "GLOBAL_ID" };
178  const std::string weights_identifiers[3] = { "scalar", "scalar_pointcloud", "scalar_conservative" };
179 
180  const std::string bottomTempField = "a2oTbot";
181  const std::string bottomTempFieldATM = "a2oTbotATM";
182  const std::string bottomTempProjectedField = "a2oTbot_proj";
183  const std::string bottomTempProjectedNCField = "a2oTbot_projnocons";
184 
185  // Attributes for tag data storage
186  int tagIndex[4];
187  // int entTypes[2] = {1, 1}; /* both on elements; */
188  int tagTypes[2] = { DENSE_DOUBLE, DENSE_DOUBLE };
189  int atmCompNDoFs = disc_orders[0] * disc_orders[0], ocnCompNDoFs = 1 /*FV*/;
190 
191  ierr = iMOAB_DefineTagStorage( atmPID, bottomTempField.c_str(), &tagTypes[0], &atmCompNDoFs, &tagIndex[0] );
192  CHECKIERR( ierr, "failed to define the field tag on ATM" );
193 
194  ierr = iMOAB_DefineTagStorage( atmPID, bottomTempFieldATM.c_str(), &tagTypes[0], &atmCompNDoFs, &tagIndex[0] );
195  CHECKIERR( ierr, "failed to define the field tag on ATM" );
196 
197  ierr =
198  iMOAB_DefineTagStorage( ocnPID, bottomTempProjectedField.c_str(), &tagTypes[1], &ocnCompNDoFs, &tagIndex[1] );
199  CHECKIERR( ierr, "failed to define the field tag on OCN" );
200 
201  ierr =
202  iMOAB_DefineTagStorage( ocnPID, bottomTempProjectedNCField.c_str(), &tagTypes[1], &ocnCompNDoFs, &tagIndex[2] );
203  CHECKIERR( ierr, "failed to define the field tag on OCN" );
204 
205 #ifdef ENABLE_ATMLND_COUPLING
206  ierr =
207  iMOAB_DefineTagStorage( lndPID, bottomTempProjectedField.c_str(), &tagTypes[1], &ocnCompNDoFs, &tagIndex[3] );
208  CHECKIERR( ierr, "failed to define the field tag on LND" );
209 #endif
210 
211  /* Next compute the mesh intersection on the sphere between the source (ATM) and target (OCN)
212  * meshes */
213  ierr = iMOAB_ComputeMeshIntersectionOnSphere( atmPID, ocnPID, atmocnPID );
214  CHECKIERR( ierr, "failed to compute mesh intersection between ATM and OCN" );
215 
216 #ifdef ENABLE_ATMLND_COUPLING
217  /* Next compute the mesh intersection on the sphere between the source (ATM) and target (LND)
218  * meshes */
219  ierr = iMOAB_ComputePointDoFIntersection( atmPID, lndPID, atmlndPID );
220  CHECKIERR( ierr, "failed to compute point-cloud mapping ATM-LND" );
221 
222  /* Next compute the mesh intersection on the sphere between the source (LND) and target (ATM)
223  * meshes */
224  ierr = iMOAB_ComputePointDoFIntersection( lndPID, atmPID, lndatmPID );
225  CHECKIERR( ierr, "failed to compute point-cloud mapping LND-ATM" );
226 #endif
227 
228  /* We have the mesh intersection now. Let us compute the remapping weights */
229  fNoConserve = 0;
230 
231  /* Compute the weights to preoject the solution from ATM component to OCN compoenent */
232  ierr = iMOAB_ComputeScalarProjectionWeights( atmocnPID, weights_identifiers[0].c_str(), disc_methods[0].c_str(),
233  &disc_orders[0], disc_methods[1].c_str(), &disc_orders[1], nullptr,
234  &fNoBubble, &fMonotoneTypeID, &fVolumetric, &fInverseDistanceMap,
235  &fNoConserve, &fValidate, dof_tag_names[0].c_str(),
236  dof_tag_names[1].c_str() );
237  CHECKIERR( ierr, "failed to compute remapping projection weights for ATM-OCN scalar "
238  "non-conservative field" );
239 
240  // Let us now write the map file to disk and then read it back to test the I/O API in iMOAB
241 #ifdef MOAB_HAVE_NETCDF
242  {
243  const std::string atmocn_map_file_name = "atm_ocn_map.nc";
244  ierr =
245  iMOAB_WriteMappingWeightsToFile( atmocnPID, weights_identifiers[0].c_str(), atmocn_map_file_name.c_str() );
246  CHECKIERR( ierr, "failed to write map file to disk" );
247 
248  const std::string intx_from_file_identifier = "map-from-file";
249  // use old reader, coupler PID is -1
250  int dummyCpl = -1;
251  int dummy_rowcol = -1;
252  int dummyType = 0;
253  ierr = iMOAB_LoadMappingWeightsFromFile( atmocnPID, &dummyCpl, &dummy_rowcol, &dummyType,
254  intx_from_file_identifier.c_str(), atmocn_map_file_name.c_str() );
255  CHECKIERR( ierr, "failed to load map file from disk" );
256  }
257 #endif
258 #ifdef ENABLE_ATMLND_COUPLING
259  fValidate = 0;
260  /* Compute the weights to preoject the solution from ATM component to LND compoenent */
261  ierr = iMOAB_ComputeScalarProjectionWeights( atmlndPID, weights_identifiers[1].c_str(), disc_methods[0].c_str(),
262  &disc_orders[0], disc_methods[2].c_str(), &disc_orders[2], nullptr,
263  &fNoBubble, &fMonotoneTypeID, &fVolumetric, &fInverseDistanceMap,
264  &fNoConserve, &fValidate, dof_tag_names[0].c_str(),
265  dof_tag_names[2].c_str() );
266  CHECKIERR( ierr, "failed to compute remapping projection weights for ATM-LND scalar "
267  "non-conservative field" );
268 
269  /* Compute the weights to preoject the solution from ATM component to LND compoenent */
270  ierr = iMOAB_ComputeScalarProjectionWeights( lndatmPID, weights_identifiers[1].c_str(), disc_methods[2].c_str(),
271  &disc_orders[2], disc_methods[0].c_str(), &disc_orders[0], nullptr,
272  &fNoBubble, &fMonotoneTypeID, &fVolumetric, &fInverseDistanceMap,
273  &fNoConserve, &fValidate, dof_tag_names[2].c_str(),
274  dof_tag_names[0].c_str() );
275  CHECKIERR( ierr, "failed to compute remapping projection weights for LND-ATM scalar "
276  "non-conservative field" );
277 #endif
278  /* We have the mesh intersection now. Let us compute the remapping weights */
279  fNoConserve = 0;
280  ierr = iMOAB_ComputeScalarProjectionWeights( atmocnPID, weights_identifiers[2].c_str(), disc_methods[0].c_str(),
281  &disc_orders[0], disc_methods[1].c_str(), &disc_orders[1], nullptr,
282  &fNoBubble, &fMonotoneTypeID, &fVolumetric, &fInverseDistanceMap,
283  &fNoConserve, &fValidate, dof_tag_names[0].c_str(),
284  dof_tag_names[1].c_str() );
285  CHECKIERR( ierr, "failed to compute remapping projection weights for scalar conservative field" );
286 
287  /* We have the remapping weights now. Let us apply the weights onto the tag we defined
288  on the srouce mesh and get the projection on the target mesh */
289  ierr = iMOAB_ApplyScalarProjectionWeights( atmocnPID, weights_identifiers[0].c_str(), bottomTempField.c_str(),
290  bottomTempProjectedNCField.c_str() );
291  CHECKIERR( ierr, "failed to apply projection weights for scalar non-conservative field" );
292 
293  /* We have the remapping weights now. Let us apply the weights onto the tag we defined
294  on the srouce mesh and get the projection on the target mesh */
295  ierr = iMOAB_ApplyScalarProjectionWeights( atmocnPID, weights_identifiers[2].c_str(), bottomTempField.c_str(),
296  bottomTempProjectedField.c_str() );
297  CHECKIERR( ierr, "failed to apply projection weights for scalar conservative field" );
298 
299  if( gen_baseline )
300  {
301  // get temp field on ocean, from conservative, the global ids, and dump to the baseline file
302  // first get GlobalIds from ocn, and fields:
303  ierr = iMOAB_GetMeshInfo( ocnPID, nverts, nelem, 0, 0, 0 );
304  CHECKIERR( ierr, "failed to get ocn mesh info" );
305  std::vector< int > gidElems;
306  gidElems.resize( nelem[2] );
307  std::vector< double > tempElems;
308  tempElems.resize( nelem[2] );
309  // get global id storage
310  const std::string GidStr = "GLOBAL_ID"; // hard coded too
311 
312  int tag_type = DENSE_INTEGER, ncomp = 1, tagInd = 0;
313  // we should not have to define global id tag, it is always defined
314  ierr = iMOAB_DefineTagStorage( ocnPID, GidStr.c_str(), &tag_type, &ncomp, &tagInd );
315  CHECKIERR( ierr, "failed to define global id tag" );
316  int ent_type = 1;
317  ierr = iMOAB_GetIntTagStorage( ocnPID, GidStr.c_str(), &nelem[2], &ent_type, &gidElems[0] );
318  CHECKIERR( ierr, "failed to get global ids" );
319  ierr =
320  iMOAB_GetDoubleTagStorage( ocnPID, bottomTempProjectedField.c_str(), &nelem[2], &ent_type, &tempElems[0] );
321  CHECKIERR( ierr, "failed to get temperature field" );
322  std::fstream fs;
323  fs.open( baseline.c_str(), std::fstream::out );
324  fs << std::setprecision( 15 ); // maximum precision for doubles
325  for( int i = 0; i < nelem[2]; i++ )
326  fs << gidElems[i] << " " << tempElems[i] << "\n";
327  fs.close();
328  }
329  if( !no_test_against_baseline )
330  {
331  // get temp field on ocean, from conservative, the global ids, and dump to the baseline file
332  // first get GlobalIds from ocn, and fields:
333  ierr = iMOAB_GetMeshInfo( ocnPID, nverts, nelem, 0, 0, 0 );
334  CHECKIERR( ierr, "failed to get ocn mesh info" );
335  std::vector< int > gidElems;
336  gidElems.resize( nelem[2] );
337  std::vector< double > tempElems;
338  tempElems.resize( nelem[2] );
339  // get global id storage
340  const std::string GidStr = "GLOBAL_ID"; // hard coded too
341 
342  int tag_type = DENSE_INTEGER, ncomp = 1, tagInd = 0;
343  ierr = iMOAB_DefineTagStorage( ocnPID, GidStr.c_str(), &tag_type, &ncomp, &tagInd );
344  CHECKIERR( ierr, "failed to define global id tag" );
345 
346  int ent_type = 1;
347  ierr = iMOAB_GetIntTagStorage( ocnPID, GidStr.c_str(), &nelem[2], &ent_type, &gidElems[0] );
348  CHECKIERR( ierr, "failed to get global ids" );
349  ierr =
350  iMOAB_GetDoubleTagStorage( ocnPID, bottomTempProjectedField.c_str(), &nelem[2], &ent_type, &tempElems[0] );
351  CHECKIERR( ierr, "failed to get temperature field" );
352  int err_code = 1;
353  check_baseline_file( baseline, gidElems, tempElems, 1.e-9, err_code );
354  if( 0 == err_code ) std::cout << " passed baseline test 1\n";
355  }
356 #ifdef ENABLE_ATMLND_COUPLING
357  /* We have the remapping weights now. Let us apply the weights onto the tag we defined
358  on the srouce mesh and get the projection on the target mesh */
359  ierr = iMOAB_ApplyScalarProjectionWeights( atmlndPID, weights_identifiers[1].c_str(), bottomTempField.c_str(),
360  bottomTempProjectedField.c_str() );
361  CHECKIERR( ierr, "failed to apply projection weights for ATM-LND scalar field" );
362 
363  /* We have the remapping weights now. Let us apply the weights onto the tag we defined
364  on the srouce mesh and get the projection on the target mesh */
365  ierr = iMOAB_ApplyScalarProjectionWeights( lndatmPID, weights_identifiers[1].c_str(),
366  bottomTempProjectedField.c_str(), bottomTempFieldATM.c_str() );
367  CHECKIERR( ierr, "failed to apply projection weights for LND-ATM scalar field" );
368 #endif
369  /*
370  * the file can be written in parallel, and it will contain additional tags defined by the user
371  * we may extend the method to write only desired tags to the file
372  */
373  {
374  // free allocated data
375 #ifdef ENABLE_ATMLND_COUPLING
376  char outputFileAtmTgt[] = "fIntxAtmTarget.h5m";
377 #endif
378  char outputFileOcnTgt[] = "fIntxOcnTarget.h5m";
379 #ifdef ENABLE_ATMLND_COUPLING
380  char outputFileLndTgt[] = "fIntxLndTarget.h5m";
381 #endif
382  char writeOptions[] = "";
383 
384  // Write out all the component meshes to disk for verification
385  ierr = iMOAB_WriteMesh( ocnPID, outputFileOcnTgt, writeOptions );
386  CHECKIERR( ierr, "failed to write OCN mesh and data" );
387 #ifdef ENABLE_ATMLND_COUPLING
388  ierr = iMOAB_WriteMesh( lndPID, outputFileLndTgt, writeOptions );
389  CHECKIERR( ierr, "failed to write LND mesh and data" );
390  ierr = iMOAB_WriteMesh( atmPID, outputFileAtmTgt, writeOptions );
391  CHECKIERR( ierr, "failed to write ATM mesh and data" );
392 #endif
393  }
394 
395  /*
396  * deregistering application will delete all mesh entities associated with the application and
397  * will free allocated tag storage.
398  */
399 #ifdef ENABLE_ATMLND_COUPLING
400  ierr = iMOAB_DeregisterApplication( lndPID );
401  CHECKIERR( ierr, "failed to de-register application3" );
402 #endif
403  ierr = iMOAB_DeregisterApplication( ocnPID );
404  CHECKIERR( ierr, "failed to de-register application2" );
405  ierr = iMOAB_DeregisterApplication( atmPID );
406  CHECKIERR( ierr, "failed to de-register application1" );
407 
408  /*
409  * this method will delete MOAB instance
410  */
411  ierr = iMOAB_Finalize();
412  CHECKIERR( ierr, "failed to finalize MOAB" );
413 
414 #ifdef MOAB_HAVE_MPI
415  MPI_Finalize();
416 #endif
417 
418  return 0;
419 }