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)",
196 opts.
addOpt<
void >(
"verbose,v",
197 "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 );
601 rval = mbintx->construct_covering_set( runCtx->
meshsets[0], covering_set );
MB_CHK_ERR( rval );
609 velist[4] = cintxverts.
size();
610 velist[5] = cintxelems.
size();
613 MPI_Reduce( velist, gvelist, 6, MPI_UINT64_T, MPI_SUM, 0, MPI_COMM_WORLD );
617 for(
int i = 0; i < 6; i++ )
618 gvelist[i] = velist[i];
623 outputFormatter.
printf( 0,
"The source set contains %lu vertices and %lu elements \n", gvelist[0],
625 outputFormatter.
printf( 0,
"The covering set contains %lu vertices and %lu elements \n", gvelist[2],
627 outputFormatter.
printf( 0,
"The target set contains %lu vertices and %lu elements \n", gvelist[1],
633 runCtx->
timer_push(
"compute intersections with MOAB" );
646 outputFormatter.
printf( 0,
"The intersection set contains %lu elements and %lu vertices \n",
647 intxelems.
size(), intxverts.
size() );
650 double initial_sarea =
653 double initial_tarea =
656 double intx_area = areaAdaptorHuiller.
area_on_sphere( mbCore, intxset, radius_src );
658 outputFormatter.
printf( 0,
"mesh areas: source = %12.10f, target = %12.10f, intersection = %12.10f \n",
659 initial_sarea, initial_tarea, intx_area );
660 outputFormatter.
printf( 0,
"relative error w.r.t source = %12.10e, target = %12.10e \n",
661 fabs( intx_area - initial_sarea ) / initial_sarea,
662 fabs( intx_area - initial_tarea ) / initial_tarea );
673 runCtx->
timer_push(
"compute weights with the Tempest meshes" );
675 OfflineMap weightMap;
676 int err = GenerateOfflineMapWithMeshes( *runCtx->
meshes[0], *runCtx->
meshes[1], *runCtx->
meshes[2],
682 std::map< std::string, std::string > mapAttributes;
685 rval = moab::MB_FAILURE;
689 if( !runCtx->
skip_io ) weightMap.Write(
"outWeights.nc", mapAttributes );
701 size_t velist[4] = {}, gvelist[4] = {};
715 velist[0] = srcverts.
size();
716 velist[1] = srcelems.
size();
730 velist[2] = tgtverts.
size();
731 velist[3] = tgtelems.
size();
744 runCtx->
timer_push(
"construct covering set for intersection" );
750 MPI_Reduce( velist, gvelist, 4, MPI_UINT64_T, MPI_SUM, 0, MPI_COMM_WORLD );
752 for(
int i = 0; i < 4; i++ )
753 gvelist[i] = velist[i];
758 outputFormatter.
printf( 0,
"The source set contains %lu vertices and %lu elements \n", gvelist[0],
760 outputFormatter.
printf( 0,
"The target set contains %lu vertices and %lu elements \n", gvelist[2],
765 runCtx->
timer_push(
"setup and compute mesh intersections" );
771 double dTotalOverlapArea = 0.0;
776 double local_areas[3],
784 MPI_Allreduce( &local_areas[0], &global_areas[0], 3, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
786 global_areas[0] = local_areas[0];
787 global_areas[1] = local_areas[1];
788 global_areas[2] = local_areas[2];
792 outputFormatter.
printf( 0,
793 "initial area: source mesh = %12.14f, target mesh = "
794 "%12.14f, overlap mesh = %12.14f\n",
795 global_areas[0], global_areas[1], global_areas[2] );
800 outputFormatter.
printf( 0,
"relative error w.r.t source = %12.14e, and target = %12.14e\n",
801 fabs( global_areas[0] - global_areas[2] ) / global_areas[0],
802 fabs( global_areas[1] - global_areas[2] ) / global_areas[1] );
804 dTotalOverlapArea = global_areas[2];
827 std::stringstream filename;
828 filename <<
"aug_overlap" << runCtx->pcomm->rank() <<
".h5m";
838 if( nprocs > 1 && !runCtx->
skip_io )
840 std::stringstream filename;
841 filename <<
"writable_intx_" << runCtx->pcomm->rank() <<
".h5m";
847 size_t lastindex = runCtx->
intxFilename.find_last_of(
"." );
849 sstr << runCtx->
intxFilename.substr( 0, lastindex ) <<
".h5m";
851 std::cout <<
"Writing out the MOAB intersection mesh file to " << sstr.str() << std::endl;
856 rval = mbCore->
write_file( sstr.str().c_str(),
nullptr, writeOptions, &writableOverlapSet, 1 );
MB_CHK_ERR( rval );
863 if( !runCtx->
proc_id ) std::cout << std::endl;
865 runCtx->
timer_push(
"setup computation of weights" );
870 runCtx->
timer_push(
"compute weights with TempestRemap" );
886 const double dNormalTolerance = 1.0E-8;
887 const double dStrictTolerance = 1.0E-12;
889 dNormalTolerance, dStrictTolerance, dTotalOverlapArea );
894 std::map< std::string, std::string > attrMap;
896 attrMap[
"Title"] =
"MOAB-TempestRemap (mbtempest) Offline Regridding Weight Generator";
897 attrMap[
"normalization"] =
"ovarea";
898 attrMap[
"remap_options"] = runCtx->
mapOptions.strMethod;
905 attrMap[
"concave_a"] = runCtx->
mapOptions.fSourceConcave ?
"true" :
"false";
908 attrMap[
"concave_b"] = runCtx->
mapOptions.fTargetConcave ?
"true" :
"false";
909 attrMap[
"bubble"] = runCtx->
mapOptions.fNoBubble ?
"false" :
"true";
910 attrMap[
"history"] = historyStr;
925 bool userVariable =
false;
944 runCtx->
timer_push(
"describe a solution on source grid" );
949 runCtx->
timer_push(
"describe a solution on target grid" );
953 &tgtProjectedFunction,
"ProjectedSolnTgt" );
MB_CHK_ERR( rval );
971 runCtx->
timer_push(
"compute solution projection on target grid" );
985 std::vector< int > globIds;
986 globIds.resize( tgtCells.
size() );
987 std::vector< double > vals;
988 vals.resize( tgtCells.
size() );
995 fs.open( runCtx->
baselineFile.c_str(), std::fstream::out );
996 fs << std::setprecision( 15 );
997 for(
size_t i = 0; i < tgtCells.
size(); i++ )
998 fs << globIds[i] <<
" " << vals[i] <<
"\n";
1011 runCtx->
timer_push(
"compute error metrics against analytical solution on target grid" );
1012 std::map< std::string, double > errMetrics;
1014 tgtProjectedFunction, errMetrics,
true );
MB_CHK_ERR( rval );
1028 #ifdef MOAB_HAVE_MPI
1042 outputFormatter.
printf( 0,
"Creating TempestRemap Mesh object ...\n" );
1047 ctx.
timer_push(
"create Tempest OverlapMesh" );
1052 rval = moab::MB_FAILURE;
1054 ctx.
meshes.push_back( tempest_mesh );
1078 ctx.
timer_push(
"generate TempestRemap OverlapMesh" );
1081 err = GenerateOverlapWithMeshes( *ctx.
meshes[0], *ctx.
meshes[1], *tempest_mesh,
"" ,
1082 "NetCDF4",
"exact",
false );
1085 rval = moab::MB_FAILURE;
1101 const double radius_src = 1.0 ;
1102 const double radius_dest = 1.0 ;
1104 std::vector< int > smetadata, tmetadata;
1115 ctx.
timer_push(
"preprocess MOAB Source mesh" );
1119 #ifdef MOAB_HAVE_MPI
1129 if( !runCtx->skip_io )
1132 std::stringstream filename;
1133 filename <<
"expand_source" << ctx.pcomm->rank() <<
".h5m";
1147 addititional_read_opts_tgt.c_str() );
MB_CHK_ERR( rval );
1151 ctx.
timer_push(
"preprocess MOAB Target mesh" );
1157 ctx.
timer_push(
"convert MOAB meshes to TempestRemap meshes in memory" );
1170 ctx.
timer_push(
"generate ICO mesh with TempestRemap" );
1175 rval = moab::MB_FAILURE;
1177 ctx.
meshes.push_back( tempest_mesh );
1181 ctx.
timer_push(
"generate RLL mesh with TempestRemap" );
1182 err = GenerateRLLMesh( *tempest_mesh,
1186 false,
false,
false,
1196 rval = moab::MB_FAILURE;
1198 ctx.
meshes.push_back( tempest_mesh );
1202 ctx.
timer_push(
"generate CS mesh with TempestRemap" );
1206 rval = moab::MB_FAILURE;
1208 ctx.
meshes.push_back( tempest_mesh );
1213 std::cout <<
"Tempest Mesh is not a complete object; Quitting...";
1226 return ( 2.0 + cos( dLat ) * cos( dLat ) * cos( 2.0 * dLon ) );
1231 return ( 2.0 + pow( sin( 2.0 * dLat ), 16.0 ) * cos( 16.0 * dLon ) );
1242 const double dLon0 = 0.0;
1243 const double dLat0 = 0.6;
1244 const double dR0 = 3.0;
1245 const double dD = 5.0;
1246 const double dT = 6.0;
1251 double dSinC = sin( dLat0 );
1252 double dCosC = cos( dLat0 );
1253 double dCosT = cos( dLat );
1254 double dSinT = sin( dLat );
1256 double dTrm = dCosT * cos( dLon - dLon0 );
1257 double dX = dSinC * dTrm - dCosC * dSinT;
1258 double dY = dCosT * sin( dLon - dLon0 );
1259 double dZ = dSinC * dSinT + dCosC * dTrm;
1261 dLon = atan2( dY, dX );
1269 double dRho = dR0 * cos( dLat );
1270 double dVt = 3.0 * sqrt( 3.0 ) / 2.0 / cosh( dRho ) / cosh( dRho ) * tanh( dRho );
1279 dOmega = dVt / dRho;
1282 return ( 1.0 - tanh( dRho / dD * sin( dLon - dOmega * dT ) ) );