98 epsrel( ReferenceTolerance )
133 MPI_Reduce( &locElapsed, &maxElapsed, 1, MPI_DOUBLE, MPI_MAX, 0, pcomm->
comm() );
134 MPI_Reduce( &locElapsed, &avgElapsed, 1, MPI_DOUBLE, MPI_SUM, 0, pcomm->
comm() );
136 maxElapsed = locElapsed;
137 avgElapsed = locElapsed;
142 std::cout <<
"[LOG] Time taken to " <<
opName.c_str() <<
": max = " << maxElapsed
143 <<
", avg = " << avgElapsed <<
"\n";
154 std::string expectedFName =
"output.exo";
155 std::string expectedMethod =
"fv";
156 std::string expectedFVMethod =
"none";
157 std::string expectedDofTagName =
"GLOBAL_ID";
158 int expectedOrder = 1;
160 int nlayer_input = 0;
164 std::cout <<
"Command line options provided to mbtempest:\n ";
165 for(
int iarg = 0; iarg < argc; ++iarg )
166 std::cout << argv[iarg] <<
" ";
167 std::cout << std::endl << std::endl;
170 opts.
addOpt<
int >(
"type,t",
171 "Type of mesh (default=CS; Choose from [CS=0, RLL=1, ICO=2, OVERLAP_FILES=3, "
172 "OVERLAP_MEMORY=4, OVERLAP_MOAB=5])",
175 opts.
addOpt<
int >(
"res,r",
"Resolution of the mesh (default=5)", &
blockSize );
177 opts.
addOpt<
void >(
"dual,d",
"Output the dual of the mesh (relevant only for ICO mesh type)", &
computeDual );
179 opts.
addOpt< std::string >(
"file,f",
"Output computed mesh or remapping weights to specified filename",
181 opts.
addOpt< std::string >(
182 "load,l",
"Input mesh filenames for source and target meshes. (relevant only when computing weights)",
185 opts.
addOpt<
void >(
"advfront,a",
186 "Use the advancing front intersection instead of the Kd-tree based algorithm "
187 "to compute mesh intersections. (relevant only when computing weights)" );
189 opts.
addOpt< std::string >(
"intx,i",
"Output TempestRemap intersection mesh filename", &
intxFilename );
191 opts.
addOpt<
void >(
"weights,w",
192 "Compute and output the weights using the overlap mesh (generally "
193 "relevant only for OVERLAP mesh)",
197 "verbose,v",
"Print verbose diagnostic messages during intersection and map computation (default=false)",
200 opts.
addOpt< std::string >(
"method,m",
"Discretization method for the source and target solution fields",
203 opts.
addOpt<
int >(
"order,o",
"Discretization orders for the source and target solution fields",
206 opts.
addOpt< std::string >(
"global_id,g",
207 "Tag name that contains the global DoF IDs for source and target solution fields",
208 &expectedDofTagName );
210 opts.
addOpt< std::string >(
"fvmethod",
211 "Sub-type method for FV-FV projections (invdist, delaunay, bilin, "
212 "intbilin, intbilingb, none. Default: none)",
215 opts.
addOpt<
void >(
"noconserve",
216 "Do not apply conservation to the resultant weights (relevant only "
217 "when computing weights)",
220 opts.
addOpt<
void >(
"volumetric",
221 "Apply a volumetric projection to compute the weights (relevant only "
222 "when computing weights)",
225 opts.
addOpt<
void >(
"skip_output",
"For performance studies, skip all I/O operations.", &
skip_io );
227 opts.
addOpt<
void >(
"gnomonic",
"Use Gnomonic plane projections to compute coverage mesh.",
230 opts.
addOpt<
void >(
"enforce_convexity",
"check convexity of input meshes to compute mesh intersections",
233 opts.
addOpt<
void >(
"nobubble",
"do not use bubble on interior of spectral element nodes",
238 "Use sparse solver for constraints when we have high-valence (typical with high-res RLL mesh)",
241 opts.
addOpt<
void >(
"rrmgrids",
242 "At least one of the meshes is a regionally refined grid (relevant to "
243 "accelerate intersection computation)",
246 opts.
addOpt<
void >(
"checkmap",
"Check the generated map for conservation and consistency", &
fCheck );
248 opts.
addOpt<
void >(
"verify",
249 "Verify the accuracy of the maps by projecting analytical functions "
250 "from source to target "
251 "grid by applying the maps",
254 opts.
addOpt< std::string >(
"var",
255 "Tag name of the variable to use in the verification study "
256 "(error metrics for user defined variables may not be available)",
259 opts.
addOpt<
int >(
"monotonicity",
"Ensure monotonicity in the weight generation. Options=[0,1,2,3]",
262 opts.
addOpt<
int >(
"ghost",
"Number of ghost layers in coverage mesh (default=1)", &nlayer_input );
264 opts.
addOpt<
double >(
"boxeps",
"The tolerance for boxes (default=1e-7)", &
boxeps );
266 opts.
addOpt<
int >(
"caas",
"apply CAAS nonlinear filter after linear map application", &useCAAS );
361 if( expectedFVMethod !=
"none" )
363 mapOptions.strMethod += expectedFVMethod +
";";
398 expectedFName.clear();
420 std::string opts =
"";
423 size_t lastindex = filename.find_last_of(
"." );
424 std::string extension = filename.substr( lastindex + 1, filename.size() );
425 if( extension ==
"h5m" )
return "PARALLEL=READ_PART;PARTITION=PARALLEL_PARTITION;PARALLEL_RESOLVE_SHARED_ENTS;";
427 else if( extension ==
"nc" )
430 opts =
"PARALLEL=READ_PART;PARTITION_METHOD=RCBZOLTAN;";
435 NcFile
ncFile( filename.c_str(), NcFile::ReadOnly );
437 _EXCEPTION1(
"Unable to open grid file \"%s\" for reading", filename.c_str() );
440 int iSCRIPFormat = 0, iMPASFormat = 0, iESMFFormat = 0;
441 for(
int i = 0; i <
ncFile.num_dims(); i++ )
443 std::string strDimName =
ncFile.get_dim( i )->name();
444 if( strDimName ==
"grid_size" || strDimName ==
"grid_corners" || strDimName ==
"grid_rank" )
446 if( strDimName ==
"nodeCount" || strDimName ==
"elementCount" ||
447 strDimName ==
"maxNodePElement" )
449 if( strDimName ==
"nCells" || strDimName ==
"nEdges" || strDimName ==
"nVertices" ||
450 strDimName ==
"vertexDegree" )
455 if( iESMFFormat == 3 )
457 opts =
"PARALLEL=READ_PART;PARTITION_METHOD=RCBZOLTAN;PARALLEL_RESOLVE_SHARED_ENTS;VARIABLE=;";
459 if( iSCRIPFormat == 3 )
461 opts =
"PARALLEL=READ_PART;PARTITION_METHOD=RCBZOLTAN;";
463 if( iMPASFormat == 4 )
465 opts =
"PARALLEL=READ_PART;PARTITION_METHOD=RCBZOLTAN;"
466 "PARALLEL_RESOLVE_SHARED_ENTS;NO_EDGES;NO_MIXED_ELEMENTS;VARIABLE=;";
472 int line_size = opts.size();
473 MPI_Bcast( &line_size, 1, MPI_INT, 0, MPI_COMM_WORLD );
474 if( ctx.
proc_id != 0 ) opts.resize( line_size );
475 MPI_Bcast(
const_cast< char*
>( opts.data() ), line_size, MPI_CHAR, 0, MPI_COMM_WORLD );
479 return "PARALLEL=BCAST_DELETE;PARTITION=TRIVIAL;PARALLEL_RESOLVE_SHARED_ENTS;";
484 int main(
int argc,
char* argv[] )
487 NcError
error( NcError::verbose_nonfatal );
488 std::stringstream sstr;
489 std::string historyStr;
491 int proc_id = 0, nprocs = 1;
493 MPI_Init( &argc, &argv );
494 MPI_Comm_rank( MPI_COMM_WORLD, &proc_id );
495 MPI_Comm_size( MPI_COMM_WORLD, &nprocs );
500 if(
nullptr == mbCore )
506 for(
int ia = 0; ia < argc; ++ia )
507 historyStr += std::string( argv[ia] ) +
" ";
514 const char* writeOptions = ( nprocs > 1 ?
"PARALLEL=WRITE_PART" :
"" );
517 const char* writeOptions =
"";
521 const double radius_src = 1.0 ;
522 const double radius_dest = 1.0 ;
538 Mesh* tempest_mesh =
new Mesh();
545 assert( runCtx->
meshes.size() == 3 );
561 size_t velist[6], gvelist[6];
566 velist[0] = rintxverts.
size();
567 velist[1] = rintxelems.
size();
572 velist[2] = bintxverts.
size();
573 velist[3] = bintxelems.
size();
581 runCtx->
timer_push(
"setup the intersector" );
589 mbintx->set_parallel_comm( pcomm );
595 rval = mbintx->build_processor_euler_boxes( runCtx->
meshsets[1], local_verts );
MB_CHK_ERR( rval );
606 rval = mbintx->construct_covering_set( runCtx->
meshsets[0], covering_set );
MB_CHK_ERR( rval );
614 velist[4] = cintxverts.
size();
615 velist[5] = cintxelems.
size();
618 MPI_Reduce( velist, gvelist, 6, MPI_UINT64_T, MPI_SUM, 0, MPI_COMM_WORLD );
622 for(
int i = 0; i < 6; i++ )
623 gvelist[i] = velist[i];
628 outputFormatter.
printf( 0,
"The source set contains %lu vertices and %lu elements \n", gvelist[0],
630 outputFormatter.
printf( 0,
"The covering set contains %lu vertices and %lu elements \n", gvelist[2],
632 outputFormatter.
printf( 0,
"The target set contains %lu vertices and %lu elements \n", gvelist[1],
638 runCtx->
timer_push(
"compute intersections with MOAB" );
651 outputFormatter.
printf( 0,
"The intersection set contains %lu elements and %lu vertices \n",
652 intxelems.
size(), intxverts.
size() );
655 double initial_sarea =
658 double initial_tarea =
661 double intx_area = areaAdaptorHuiller.
area_on_sphere( mbCore, intxset, radius_src );
663 outputFormatter.
printf( 0,
"mesh areas: source = %12.10f, target = %12.10f, intersection = %12.10f \n",
664 initial_sarea, initial_tarea, intx_area );
665 outputFormatter.
printf( 0,
"relative error w.r.t source = %12.10e, target = %12.10e \n",
666 fabs( intx_area - initial_sarea ) / initial_sarea,
667 fabs( intx_area - initial_tarea ) / initial_tarea );
678 runCtx->
timer_push(
"compute weights with the Tempest meshes" );
680 OfflineMap weightMap;
681 int err = GenerateOfflineMapWithMeshes( *runCtx->
meshes[0], *runCtx->
meshes[1], *runCtx->
meshes[2],
687 std::map< std::string, std::string > mapAttributes;
690 rval = moab::MB_FAILURE;
694 if( !runCtx->
skip_io ) weightMap.Write(
"outWeights.nc", mapAttributes );
706 size_t velist[4] = {}, gvelist[4] = {};
720 velist[0] = srcverts.
size();
721 velist[1] = srcelems.
size();
735 velist[2] = tgtverts.
size();
736 velist[3] = tgtelems.
size();
749 runCtx->
timer_push(
"construct covering set for intersection" );
755 MPI_Reduce( velist, gvelist, 4, MPI_UINT64_T, MPI_SUM, 0, MPI_COMM_WORLD );
757 for(
int i = 0; i < 4; i++ )
758 gvelist[i] = velist[i];
763 outputFormatter.
printf( 0,
"The source set contains %lu vertices and %lu elements \n", gvelist[0],
765 outputFormatter.
printf( 0,
"The target set contains %lu vertices and %lu elements \n", gvelist[2],
770 runCtx->
timer_push(
"setup and compute mesh intersections" );
776 double dTotalOverlapArea = 0.0;
781 double local_areas[3],
789 MPI_Allreduce( &local_areas[0], &global_areas[0], 3, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
791 global_areas[0] = local_areas[0];
792 global_areas[1] = local_areas[1];
793 global_areas[2] = local_areas[2];
797 outputFormatter.
printf( 0,
798 "initial area: source mesh = %12.14f, target mesh = "
799 "%12.14f, overlap mesh = %12.14f\n",
800 global_areas[0], global_areas[1], global_areas[2] );
805 outputFormatter.
printf( 0,
"relative error w.r.t source = %12.14e, and target = %12.14e\n",
806 fabs( global_areas[0] - global_areas[2] ) / global_areas[0],
807 fabs( global_areas[1] - global_areas[2] ) / global_areas[1] );
809 dTotalOverlapArea = global_areas[2];
832 std::stringstream filename;
833 filename <<
"aug_overlap" << runCtx->pcomm->rank() <<
".h5m";
843 if( nprocs > 1 && !runCtx->
skip_io )
845 std::stringstream filename;
846 filename <<
"writable_intx_" << runCtx->pcomm->rank() <<
".h5m";
852 size_t lastindex = runCtx->
intxFilename.find_last_of(
"." );
854 sstr << runCtx->
intxFilename.substr( 0, lastindex ) <<
".h5m";
856 std::cout <<
"Writing out the MOAB intersection mesh file to " << sstr.str() << std::endl;
861 rval = mbCore->
write_file( sstr.str().c_str(),
nullptr, writeOptions, &writableOverlapSet, 1 );
MB_CHK_ERR( rval );
868 if( !runCtx->
proc_id ) std::cout << std::endl;
870 runCtx->
timer_push(
"setup computation of weights" );
875 runCtx->
timer_push(
"compute weights with TempestRemap" );
891 const double dNormalTolerance = 1.0E-8;
892 const double dStrictTolerance = 1.0E-12;
894 dNormalTolerance, dStrictTolerance, dTotalOverlapArea );
899 std::map< std::string, std::string > attrMap;
901 attrMap[
"Title"] =
"MOAB-TempestRemap (mbtempest) Offline Regridding Weight Generator";
902 attrMap[
"normalization"] =
"ovarea";
903 attrMap[
"remap_options"] = runCtx->
mapOptions.strMethod;
910 attrMap[
"concave_a"] = runCtx->
mapOptions.fSourceConcave ?
"true" :
"false";
913 attrMap[
"concave_b"] = runCtx->
mapOptions.fTargetConcave ?
"true" :
"false";
914 attrMap[
"bubble"] = runCtx->
mapOptions.fNoBubble ?
"false" :
"true";
915 attrMap[
"history"] = historyStr;
930 bool userVariable =
false;
949 runCtx->
timer_push(
"describe a solution on source grid" );
954 runCtx->
timer_push(
"describe a solution on target grid" );
958 &tgtProjectedFunction,
"ProjectedSolnTgt" );
MB_CHK_ERR( rval );
976 runCtx->
timer_push(
"compute solution projection on target grid" );
990 std::vector< int > globIds;
991 globIds.resize( tgtCells.
size() );
992 std::vector< double > vals;
993 vals.resize( tgtCells.
size() );
1000 fs.open( runCtx->
baselineFile.c_str(), std::fstream::out );
1001 fs << std::setprecision( 15 );
1002 for(
size_t i = 0; i < tgtCells.
size(); i++ )
1003 fs << globIds[i] <<
" " << vals[i] <<
"\n";
1017 runCtx->
timer_push(
"compute error metrics against analytical solution on target grid" );
1018 std::map< std::string, double > errMetrics;
1020 tgtProjectedFunction, errMetrics,
true );
MB_CHK_ERR( rval );
1034 #ifdef MOAB_HAVE_MPI
1048 outputFormatter.
printf( 0,
"Creating TempestRemap Mesh object ...\n" );
1053 ctx.
timer_push(
"create Tempest OverlapMesh" );
1058 rval = moab::MB_FAILURE;
1060 ctx.
meshes.push_back( tempest_mesh );
1084 ctx.
timer_push(
"generate TempestRemap OverlapMesh" );
1087 err = GenerateOverlapWithMeshes( *ctx.
meshes[0], *ctx.
meshes[1], *tempest_mesh,
"" ,
1088 "NetCDF4",
"exact",
false );
1091 rval = moab::MB_FAILURE;
1107 const double radius_src = 1.0 ;
1108 const double radius_dest = 1.0 ;
1110 std::vector< int > smetadata, tmetadata;
1121 ctx.
timer_push(
"preprocess MOAB Source mesh" );
1133 addititional_read_opts_tgt.c_str() );
MB_CHK_ERR( rval );
1137 ctx.
timer_push(
"preprocess MOAB Target mesh" );
1143 ctx.
timer_push(
"convert MOAB meshes to TempestRemap meshes in memory" );
1156 ctx.
timer_push(
"generate ICO mesh with TempestRemap" );
1161 rval = moab::MB_FAILURE;
1163 ctx.
meshes.push_back( tempest_mesh );
1167 ctx.
timer_push(
"generate RLL mesh with TempestRemap" );
1168 err = GenerateRLLMesh( *tempest_mesh,
1172 false,
false,
false,
1182 rval = moab::MB_FAILURE;
1184 ctx.
meshes.push_back( tempest_mesh );
1188 ctx.
timer_push(
"generate CS mesh with TempestRemap" );
1192 rval = moab::MB_FAILURE;
1194 ctx.
meshes.push_back( tempest_mesh );
1199 std::cout <<
"Tempest Mesh is not a complete object; Quitting...";
1212 return ( 2.0 + cos( dLat ) * cos( dLat ) * cos( 2.0 * dLon ) );
1217 return ( 2.0 + pow( sin( 2.0 * dLat ), 16.0 ) * cos( 16.0 * dLon ) );
1228 const double dLon0 = 0.0;
1229 const double dLat0 = 0.6;
1230 const double dR0 = 3.0;
1231 const double dD = 5.0;
1232 const double dT = 6.0;
1237 double dSinC = sin( dLat0 );
1238 double dCosC = cos( dLat0 );
1239 double dCosT = cos( dLat );
1240 double dSinT = sin( dLat );
1242 double dTrm = dCosT * cos( dLon - dLon0 );
1243 double dX = dSinC * dTrm - dCosC * dSinT;
1244 double dY = dCosT * sin( dLon - dLon0 );
1245 double dZ = dSinC * dSinT + dCosC * dTrm;
1247 dLon = atan2( dY, dX );
1255 double dRho = dR0 * cos( dLat );
1256 double dVt = 3.0 * sqrt( 3.0 ) / 2.0 / cosh( dRho ) / cosh( dRho ) * tanh( dRho );
1265 dOmega = dVt / dRho;
1268 return ( 1.0 - tanh( dRho / dD * sin( dLon - dOmega * dT ) ) );