Loading [MathJax]/extensions/tex2jax.js
Mesh Oriented datABase  (version 5.5.1)
An array-based unstructured mesh library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
mbtempest.cpp File Reference
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <vector>
#include <string>
#include <sstream>
#include <cassert>
#include "moab/Core.hpp"
#include "moab/IntxMesh/IntxUtils.hpp"
#include "moab/Remapping/TempestRemapper.hpp"
#include "moab/Remapping/TempestOnlineMap.hpp"
#include "moab/ProgOptions.hpp"
#include "moab/CpuTimer.hpp"
#include "DebugOutput.hpp"
+ Include dependency graph for mbtempest.cpp:

Go to the source code of this file.

Classes

struct  ToolContext
 

Functions

static moab::ErrorCode CreateTempestMesh (ToolContext &, moab::TempestRemapper &remapper, Mesh *)
 
double sample_slow_harmonic (double dLon, double dLat)
 
double sample_fast_harmonic (double dLon, double dLat)
 
double sample_constant (double dLon, double dLat)
 
double sample_stationary_vortex (double dLon, double dLat)
 
std::string get_file_read_options (ToolContext &ctx, std::string filename)
 
int main (int argc, char *argv[])
 

Function Documentation

◆ CreateTempestMesh()

static moab::ErrorCode CreateTempestMesh ( ToolContext ctx,
moab::TempestRemapper remapper,
Mesh *  tempest_mesh 
)
static

Definition at line 1039 of file mbtempest.cpp.

1040 { 1041  moab::ErrorCode rval = moab::MB_SUCCESS; 1042  int err; 1043  moab::DebugOutput& outputFormatter = ctx.outputFormatter; 1044  1045  if( !ctx.proc_id ) 1046  { 1047  outputFormatter.printf( 0, "Creating TempestRemap Mesh object ...\n" ); 1048  } 1049  1050  if( ctx.meshType == moab::TempestRemapper::OVERLAP_FILES ) 1051  { 1052  ctx.timer_push( "create Tempest OverlapMesh" ); 1053  // For the overlap method, choose between: "fuzzy", "exact" or "mixed" 1054  err = GenerateOverlapMesh( ctx.inFilenames[0], ctx.inFilenames[1], *tempest_mesh, ctx.outFilename, "NetCDF4", 1055  "exact", true ); 1056  if( err ) 1057  rval = moab::MB_FAILURE; 1058  else 1059  ctx.meshes.push_back( tempest_mesh ); 1060  ctx.timer_pop(); 1061  } 1062  else if( ctx.meshType == moab::TempestRemapper::OVERLAP_MEMORY ) 1063  { 1064  // Load the meshes and validate 1065  ctx.meshsets.resize( 3 ); 1066  ctx.meshes.resize( 3 ); 1067  ctx.meshsets[0] = remapper.GetMeshSet( moab::Remapper::SourceMesh ); 1068  ctx.meshsets[1] = remapper.GetMeshSet( moab::Remapper::TargetMesh ); 1069  ctx.meshsets[2] = remapper.GetMeshSet( moab::Remapper::OverlapMesh ); 1070  1071  ctx.timer_push( "load MOAB Source mesh" ); 1072  // First the source 1073  rval = remapper.LoadMesh( moab::Remapper::SourceMesh, ctx.inFilenames[0], moab::TempestRemapper::DEFAULT );MB_CHK_ERR( rval ); 1074  ctx.meshes[0] = remapper.GetMesh( moab::Remapper::SourceMesh ); 1075  ctx.timer_pop(); 1076  1077  ctx.timer_push( "load MOAB Target mesh" ); 1078  // Next the target 1079  rval = remapper.LoadMesh( moab::Remapper::TargetMesh, ctx.inFilenames[1], moab::TempestRemapper::DEFAULT );MB_CHK_ERR( rval ); 1080  ctx.meshes[1] = remapper.GetMesh( moab::Remapper::TargetMesh ); 1081  ctx.timer_pop(); 1082  1083  ctx.timer_push( "generate TempestRemap OverlapMesh" ); 1084  // Now let us construct the overlap mesh, by calling TempestRemap interface directly 1085  // For the overlap method, choose between: "fuzzy", "exact" or "mixed" 1086  err = GenerateOverlapWithMeshes( *ctx.meshes[0], *ctx.meshes[1], *tempest_mesh, "" /*ctx.outFilename*/, 1087  "NetCDF4", "exact", false ); 1088  ctx.timer_pop(); 1089  if( err ) 1090  rval = moab::MB_FAILURE; 1091  else 1092  { 1093  remapper.SetMesh( moab::Remapper::OverlapMesh, tempest_mesh ); 1094  ctx.meshes[2] = remapper.GetMesh( moab::Remapper::OverlapMesh ); 1095  // ctx.meshes.push_back(*tempest_mesh); 1096  } 1097  } 1098  else if( ctx.meshType == moab::TempestRemapper::OVERLAP_MOAB ) 1099  { 1100  ctx.meshsets.resize( 3 ); 1101  ctx.meshes.resize( 3 ); 1102  ctx.meshsets[0] = remapper.GetMeshSet( moab::Remapper::SourceMesh ); 1103  ctx.meshsets[1] = remapper.GetMeshSet( moab::Remapper::TargetMesh ); 1104  ctx.meshsets[2] = remapper.GetMeshSet( moab::Remapper::OverlapMesh ); 1105  1106  const double radius_src = 1.0 /*2.0*acos(-1.0)*/; 1107  const double radius_dest = 1.0 /*2.0*acos(-1.0)*/; 1108  1109  std::vector< int > smetadata, tmetadata; 1110  //const char* additional_read_opts = ( ctx.n_procs > 1 ? "NO_SET_CONTAINING_PARENTS;" : "" ); 1111  std::string additional_read_opts_src = get_file_read_options( ctx, ctx.inFilenames[0] ); 1112  1113  ctx.timer_push( "load MOAB Source mesh" ); 1114  // Load the source mesh and validate 1115  rval = 1116  remapper.LoadNativeMesh( ctx.inFilenames[0], ctx.meshsets[0], smetadata, additional_read_opts_src.c_str() );MB_CHK_ERR( rval ); 1117  if( smetadata.size() ) remapper.SetMeshType( moab::Remapper::SourceMesh, smetadata ); 1118  ctx.timer_pop(); 1119  1120  ctx.timer_push( "preprocess MOAB Source mesh" ); 1121  // Rescale the radius of both to compute the intersection 1122  rval = moab::IntxUtils::ScaleToRadius( ctx.mbcore, ctx.meshsets[0], radius_src );MB_CHK_ERR( rval ); 1123  1124  ctx.timer_pop(); 1125  1126  // Load the target mesh and validate 1127  std::string addititional_read_opts_tgt = get_file_read_options( ctx, ctx.inFilenames[1] ); 1128  // addititional_read_opts_tgt += "PARALLEL_GHOSTS=2.0.3;PARALLEL_THIN_GHOST_LAYER;"; 1129  1130  ctx.timer_push( "load MOAB Target mesh" ); 1131  rval = remapper.LoadNativeMesh( ctx.inFilenames[1], ctx.meshsets[1], tmetadata, 1132  addititional_read_opts_tgt.c_str() );MB_CHK_ERR( rval ); 1133  if( tmetadata.size() ) remapper.SetMeshType( moab::Remapper::TargetMesh, tmetadata ); 1134  ctx.timer_pop(); 1135  1136  ctx.timer_push( "preprocess MOAB Target mesh" ); 1137  rval = moab::IntxUtils::ScaleToRadius( ctx.mbcore, ctx.meshsets[1], radius_dest );MB_CHK_ERR( rval ); 1138  ctx.timer_pop(); 1139  1140  if( ctx.computeWeights ) 1141  { 1142  ctx.timer_push( "convert MOAB meshes to TempestRemap meshes in memory" ); 1143  // convert MOAB representation to TempestRemap's Mesh for source 1144  rval = remapper.ConvertMeshToTempest( moab::Remapper::SourceMesh );MB_CHK_ERR( rval ); 1145  ctx.meshes[0] = remapper.GetMesh( moab::Remapper::SourceMesh ); 1146  1147  // convert MOAB representation to TempestRemap's Mesh for target 1148  rval = remapper.ConvertMeshToTempest( moab::Remapper::TargetMesh );MB_CHK_ERR( rval ); 1149  ctx.meshes[1] = remapper.GetMesh( moab::Remapper::TargetMesh ); 1150  ctx.timer_pop(); 1151  } 1152  } 1153  else if( ctx.meshType == moab::TempestRemapper::ICO ) 1154  { 1155  ctx.timer_push( "generate ICO mesh with TempestRemap" ); 1156  err = GenerateICOMesh( *tempest_mesh, ctx.blockSize, ctx.computeDual, ctx.outFilename, "NetCDF4" ); 1157  ctx.timer_pop(); 1158  1159  if( err ) 1160  rval = moab::MB_FAILURE; 1161  else 1162  ctx.meshes.push_back( tempest_mesh ); 1163  } 1164  else if( ctx.meshType == moab::TempestRemapper::RLL ) 1165  { 1166  ctx.timer_push( "generate RLL mesh with TempestRemap" ); 1167  err = GenerateRLLMesh( *tempest_mesh, // Mesh& meshOut, 1168  ctx.blockSize * 2, ctx.blockSize, // int nLongitudes, int nLatitudes, 1169  0.0, 360.0, // double dLonBegin, double dLonEnd, 1170  -90.0, 90.0, // double dLatBegin, double dLatEnd, 1171  false, false, false, // bool fGlobalCap, bool fFlipLatLon, bool fForceGlobal, 1172  "" /*ctx.inFilename*/, "", 1173  "", // std::string strInputFile, std::string strInputFileLonName, std::string 1174  // strInputFileLatName, 1175  ctx.outFilename, "NetCDF4", // std::string strOutputFile, std::string strOutputFormat 1176  true // bool fVerbose 1177  ); 1178  ctx.timer_pop(); 1179  1180  if( err ) 1181  rval = moab::MB_FAILURE; 1182  else 1183  ctx.meshes.push_back( tempest_mesh ); 1184  } 1185  else // default 1186  { 1187  ctx.timer_push( "generate CS mesh with TempestRemap" ); 1188  err = GenerateCSMesh( *tempest_mesh, ctx.blockSize, ctx.outFilename, "NetCDF4" ); 1189  ctx.timer_pop(); 1190  if( err ) 1191  rval = moab::MB_FAILURE; 1192  else 1193  ctx.meshes.push_back( tempest_mesh ); 1194  } 1195  1196  if( ctx.meshType != moab::TempestRemapper::OVERLAP_MOAB && !tempest_mesh ) 1197  { 1198  std::cout << "Tempest Mesh is not a complete object; Quitting..."; 1199  exit( -1 ); 1200  } 1201  1202  return rval; 1203 }

References ToolContext::blockSize, ToolContext::computeDual, ToolContext::computeWeights, moab::TempestRemapper::ConvertMeshToTempest(), moab::TempestRemapper::DEFAULT, ErrorCode, get_file_read_options(), moab::TempestRemapper::GetMesh(), moab::TempestRemapper::GetMeshSet(), moab::TempestRemapper::ICO, ToolContext::inFilenames, moab::TempestRemapper::LoadMesh(), moab::Remapper::LoadNativeMesh(), MB_CHK_ERR, MB_SUCCESS, ToolContext::mbcore, ToolContext::meshes, ToolContext::meshsets, ToolContext::meshType, ToolContext::outFilename, ToolContext::outputFormatter, moab::TempestRemapper::OVERLAP_FILES, moab::TempestRemapper::OVERLAP_MEMORY, moab::TempestRemapper::OVERLAP_MOAB, moab::Remapper::OverlapMesh, moab::DebugOutput::printf(), ToolContext::proc_id, moab::TempestRemapper::RLL, moab::IntxUtils::ScaleToRadius(), moab::TempestRemapper::SetMesh(), moab::TempestRemapper::SetMeshType(), moab::Remapper::SourceMesh, moab::Remapper::TargetMesh, ToolContext::timer_pop(), and ToolContext::timer_push().

Referenced by main().

◆ get_file_read_options()

std::string get_file_read_options ( ToolContext ctx,
std::string  filename 
)

Definition at line 417 of file mbtempest.cpp.

418 { 419  // if running in serial, blank option may suffice in general 420  std::string opts = ""; 421  if( ctx.n_procs > 1 ) 422  { 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;"; 426  // "PARALLEL_GHOSTS=2.0.3;PARALLEL_THIN_GHOST_LAYER;"; 427  else if( extension == "nc" ) 428  { 429  // set default set of options 430  opts = "PARALLEL=READ_PART;PARTITION_METHOD=RCBZOLTAN;"; 431  432  if( ctx.proc_id == 0 ) 433  { 434  { 435  NcFile ncFile( filename.c_str(), NcFile::ReadOnly ); 436  if( !ncFile.is_valid() ) 437  _EXCEPTION1( "Unable to open grid file \"%s\" for reading", filename.c_str() ); 438  439  // Check for dimension names "grid_size", "grid_rank" and "grid_corners" 440  int iSCRIPFormat = 0, iMPASFormat = 0, iESMFFormat = 0; 441  for( int i = 0; i < ncFile.num_dims(); i++ ) 442  { 443  std::string strDimName = ncFile.get_dim( i )->name(); 444  if( strDimName == "grid_size" || strDimName == "grid_corners" || strDimName == "grid_rank" ) 445  iSCRIPFormat++; 446  if( strDimName == "nodeCount" || strDimName == "elementCount" || 447  strDimName == "maxNodePElement" ) 448  iESMFFormat++; 449  if( strDimName == "nCells" || strDimName == "nEdges" || strDimName == "nVertices" || 450  strDimName == "vertexDegree" ) 451  iMPASFormat++; 452  } 453  ncFile.close(); 454  455  if( iESMFFormat == 3 ) // Input from a NetCDF ESMF file 456  { 457  opts = "PARALLEL=READ_PART;PARTITION_METHOD=RCBZOLTAN;PARALLEL_RESOLVE_SHARED_ENTS;VARIABLE=;"; 458  } 459  if( iSCRIPFormat == 3 ) // Input from a NetCDF SCRIP file 460  { 461  opts = "PARALLEL=READ_PART;PARTITION_METHOD=RCBZOLTAN;"; 462  } 463  if( iMPASFormat == 4 ) // Input from a NetCDF SCRIP file 464  { 465  opts = "PARALLEL=READ_PART;PARTITION_METHOD=RCBZOLTAN;" 466  "PARALLEL_RESOLVE_SHARED_ENTS;NO_EDGES;NO_MIXED_ELEMENTS;VARIABLE=;"; 467  } 468  } 469  } 470  471 #ifdef MOAB_HAVE_MPI 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 ); 476 #endif 477  } 478  else 479  return "PARALLEL=BCAST_DELETE;PARTITION=TRIVIAL;PARALLEL_RESOLVE_SHARED_ENTS;"; 480  } 481  return opts; 482 }

References ToolContext::n_procs, ncFile, and ToolContext::proc_id.

Referenced by CreateTempestMesh().

◆ main()

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

Definition at line 484 of file mbtempest.cpp.

485 { 486  moab::ErrorCode rval; 487  NcError error( NcError::verbose_nonfatal ); 488  std::stringstream sstr; 489  std::string historyStr; 490  491  int proc_id = 0, nprocs = 1; 492 #ifdef MOAB_HAVE_MPI 493  MPI_Init( &argc, &argv ); 494  MPI_Comm_rank( MPI_COMM_WORLD, &proc_id ); 495  MPI_Comm_size( MPI_COMM_WORLD, &nprocs ); 496 #endif 497  498  moab::Core* mbCore = new( std::nothrow ) moab::Core; 499  500  if( nullptr == mbCore ) 501  { 502  return 1; 503  } 504  505  // Build the history string 506  for( int ia = 0; ia < argc; ++ia ) 507  historyStr += std::string( argv[ia] ) + " "; 508  509  ToolContext* runCtx; 510 #ifdef MOAB_HAVE_MPI 511  moab::ParallelComm* pcomm = new moab::ParallelComm( mbCore, MPI_COMM_WORLD, 0 ); 512  513  runCtx = new ToolContext( mbCore, pcomm ); 514  const char* writeOptions = ( nprocs > 1 ? "PARALLEL=WRITE_PART" : "" ); 515 #else 516  runCtx = new ToolContext( mbCore ); 517  const char* writeOptions = ""; 518 #endif 519  runCtx->ParseCLOptions( argc, argv ); 520  521  const double radius_src = 1.0 /*2.0*acos(-1.0)*/; 522  const double radius_dest = 1.0 /*2.0*acos(-1.0)*/; 523  524  moab::DebugOutput& outputFormatter = runCtx->outputFormatter; 525  526 #ifdef MOAB_HAVE_MPI 527  moab::TempestRemapper remapper( mbCore, pcomm ); 528 #else 529  moab::TempestRemapper remapper( mbCore ); 530 #endif 531  remapper.meshValidate = true; 532  remapper.constructEdgeMap = true; 533  remapper.initialize(); 534  535  // Default area_method = lHuiller; Options: Girard, lHuiller, GaussQuadrature (if TR is available) 536  moab::IntxAreaUtils areaAdaptor( moab::IntxAreaUtils::GaussQuadrature ); 537  538  Mesh* tempest_mesh = new Mesh(); 539  rval = CreateTempestMesh( *runCtx, remapper, tempest_mesh );MB_CHK_ERR( rval ); 540  541  if( runCtx->meshType == moab::TempestRemapper::OVERLAP_MEMORY ) 542  { 543  // Compute intersections with MOAB 544  // For the overlap method, choose between: "fuzzy", "exact" or "mixed" 545  assert( runCtx->meshes.size() == 3 ); 546  547 #ifdef MOAB_HAVE_MPI 548  rval = pcomm->check_all_shared_handles();MB_CHK_ERR( rval ); 549 #endif 550  551  // Load the meshes and validate 552  rval = remapper.ConvertTempestMesh( moab::Remapper::SourceMesh );MB_CHK_ERR( rval ); 553  rval = remapper.ConvertTempestMesh( moab::Remapper::TargetMesh );MB_CHK_ERR( rval ); 554  rval = remapper.ConvertTempestMesh( moab::Remapper::OverlapMesh );MB_CHK_ERR( rval ); 555  if( !runCtx->skip_io ) 556  { 557  rval = mbCore->write_mesh( "tempest_intersection.h5m", &runCtx->meshsets[2], 1 );MB_CHK_ERR( rval ); 558  } 559  560  // print verbosely about the problem setting 561  size_t velist[6], gvelist[6]; 562  { 563  moab::Range rintxverts, rintxelems; 564  rval = mbCore->get_entities_by_dimension( runCtx->meshsets[0], 0, rintxverts );MB_CHK_ERR( rval ); 565  rval = mbCore->get_entities_by_dimension( runCtx->meshsets[0], 2, rintxelems );MB_CHK_ERR( rval ); 566  velist[0] = rintxverts.size(); 567  velist[1] = rintxelems.size(); 568  569  moab::Range bintxverts, bintxelems; 570  rval = mbCore->get_entities_by_dimension( runCtx->meshsets[1], 0, bintxverts );MB_CHK_ERR( rval ); 571  rval = mbCore->get_entities_by_dimension( runCtx->meshsets[1], 2, bintxelems );MB_CHK_ERR( rval ); 572  velist[2] = bintxverts.size(); 573  velist[3] = bintxelems.size(); 574  } 575  576  moab::EntityHandle intxset; // == remapper.GetMeshSet(moab::Remapper::OverlapMesh); 577  578  // Compute intersections with MOAB 579  { 580  // Create the intersection on the sphere object 581  runCtx->timer_push( "setup the intersector" ); 582  583  moab::Intx2MeshOnSphere* mbintx = new moab::Intx2MeshOnSphere( mbCore ); 584  mbintx->set_error_tolerance( runCtx->epsrel ); 585  mbintx->set_box_error( runCtx->boxeps ); 586  mbintx->set_radius_source_mesh( radius_src ); 587  mbintx->set_radius_destination_mesh( radius_dest ); 588 #ifdef MOAB_HAVE_MPI 589  mbintx->set_parallel_comm( pcomm ); 590 #endif 591  rval = mbintx->FindMaxEdges( runCtx->meshsets[0], runCtx->meshsets[1] );MB_CHK_ERR( rval ); 592  593 #ifdef MOAB_HAVE_MPI 594  moab::Range local_verts; 595  rval = mbintx->build_processor_euler_boxes( runCtx->meshsets[1], local_verts );MB_CHK_ERR( rval ); 596  597  runCtx->timer_pop(); 598  599  moab::EntityHandle covering_set; 600  runCtx->timer_push( "communicate the mesh" ); 601  // TODO:: needs clarification 602  // we compute just intersection here, no need for extra ghost layers anyway 603  // ghost layers are needed in coverage for bilinear map, which does not actually need intersection 604  // this will be fixed in the future, bilinear map needs just coverage, not intersection 605  // so I am not passing the ghost layer here, even though there is an option in runCtx for a ghost layer 606  rval = mbintx->construct_covering_set( runCtx->meshsets[0], covering_set );MB_CHK_ERR( rval ); // lots of communication if mesh is distributed very differently 607  runCtx->timer_pop(); 608  609  // print verbosely about the problem setting 610  { 611  moab::Range cintxverts, cintxelems; 612  rval = mbCore->get_entities_by_dimension( covering_set, 0, cintxverts );MB_CHK_ERR( rval ); 613  rval = mbCore->get_entities_by_dimension( covering_set, 2, cintxelems );MB_CHK_ERR( rval ); 614  velist[4] = cintxverts.size(); 615  velist[5] = cintxelems.size(); 616  } 617  618  MPI_Reduce( velist, gvelist, 6, MPI_UINT64_T, MPI_SUM, 0, MPI_COMM_WORLD ); 619  620 #else 621  moab::EntityHandle covering_set = runCtx->meshsets[0]; 622  for( int i = 0; i < 6; i++ ) 623  gvelist[i] = velist[i]; 624 #endif 625  626  if( !proc_id ) 627  { 628  outputFormatter.printf( 0, "The source set contains %lu vertices and %lu elements \n", gvelist[0], 629  gvelist[0] ); 630  outputFormatter.printf( 0, "The covering set contains %lu vertices and %lu elements \n", gvelist[2], 631  gvelist[2] ); 632  outputFormatter.printf( 0, "The target set contains %lu vertices and %lu elements \n", gvelist[1], 633  gvelist[1] ); 634  } 635  636  // Now let's invoke the MOAB intersection algorithm in parallel with a 637  // source and target mesh set representing two different decompositions 638  runCtx->timer_push( "compute intersections with MOAB" ); 639  rval = mbCore->create_meshset( moab::MESHSET_SET, intxset );MB_CHK_SET_ERR( rval, "Can't create new set" ); 640  rval = mbintx->intersect_meshes( covering_set, runCtx->meshsets[1], intxset );MB_CHK_SET_ERR( rval, "Can't compute the intersection of meshes on the sphere" ); 641  runCtx->timer_pop(); 642  643  // free the memory 644  delete mbintx; 645  } 646  647  { 648  moab::Range intxelems, intxverts; 649  rval = mbCore->get_entities_by_dimension( intxset, 2, intxelems );MB_CHK_ERR( rval ); 650  rval = mbCore->get_entities_by_dimension( intxset, 0, intxverts, true );MB_CHK_ERR( rval ); 651  outputFormatter.printf( 0, "The intersection set contains %lu elements and %lu vertices \n", 652  intxelems.size(), intxverts.size() ); 653  654  moab::IntxAreaUtils areaAdaptorHuiller( moab::IntxAreaUtils::lHuiller ); // lHuiller, GaussQuadrature 655  double initial_sarea = 656  areaAdaptorHuiller.area_on_sphere( mbCore, runCtx->meshsets[0], 657  radius_src ); // use the target to compute the initial area 658  double initial_tarea = 659  areaAdaptorHuiller.area_on_sphere( mbCore, runCtx->meshsets[1], 660  radius_dest ); // use the target to compute the initial area 661  double intx_area = areaAdaptorHuiller.area_on_sphere( mbCore, intxset, radius_src ); 662  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 ); 668  } 669  670  // Write out our computed intersection file 671  if( !runCtx->skip_io ) 672  { 673  rval = mbCore->write_mesh( "moab_intersection.h5m", &intxset, 1 );MB_CHK_ERR( rval ); 674  } 675  676  if( runCtx->computeWeights ) 677  { 678  runCtx->timer_push( "compute weights with the Tempest meshes" ); 679  // Call to generate an offline map with the tempest meshes 680  OfflineMap weightMap; 681  int err = GenerateOfflineMapWithMeshes( *runCtx->meshes[0], *runCtx->meshes[1], *runCtx->meshes[2], 682  runCtx->disc_methods[0], // std::string strInputType 683  runCtx->disc_methods[1], // std::string strOutputType, 684  runCtx->mapOptions, weightMap ); 685  runCtx->timer_pop(); 686  687  std::map< std::string, std::string > mapAttributes; 688  if( err ) 689  { 690  rval = moab::MB_FAILURE; 691  } 692  else 693  { 694  if( !runCtx->skip_io ) weightMap.Write( "outWeights.nc", mapAttributes ); 695  } 696  } 697  } 698  else if( runCtx->meshType == moab::TempestRemapper::OVERLAP_MOAB ) 699  { 700  // Usage: mpiexec -n 2 tools/mbtempest -t 5 -l mycs_2.h5m -l myico_2.h5m -f myoverlap_2.h5m 701 #ifdef MOAB_HAVE_MPI 702  rval = pcomm->check_all_shared_handles();MB_CHK_ERR( rval ); 703 #endif 704  705  // print verbosely about the problem setting 706  size_t velist[4] = {}, gvelist[4] = {}; 707  { 708  moab::Range srcverts, srcelems; 709  rval = mbCore->get_entities_by_dimension( runCtx->meshsets[0], 0, srcverts );MB_CHK_ERR( rval ); 710  rval = mbCore->get_entities_by_dimension( runCtx->meshsets[0], 2, srcelems );MB_CHK_ERR( rval ); 711  rval = moab::IntxUtils::fix_degenerate_quads( mbCore, runCtx->meshsets[0] );MB_CHK_ERR( rval ); 712  if( runCtx->enforceConvexity ) 713  { 714  rval = moab::IntxUtils::enforce_convexity( mbCore, runCtx->meshsets[0], proc_id );MB_CHK_ERR( rval ); 715  } 716  rval = areaAdaptor.positive_orientation( mbCore, runCtx->meshsets[0], radius_src );MB_CHK_ERR( rval ); 717  // if( !proc_id ) 718  // outputFormatter.printf( 0, "The source set contains %lu vertices and %lu elements \n", srcverts.size(), 719  // srcelems.size() ); 720  velist[0] = srcverts.size(); 721  velist[1] = srcelems.size(); 722  723  moab::Range tgtverts, tgtelems; 724  rval = mbCore->get_entities_by_dimension( runCtx->meshsets[1], 0, tgtverts );MB_CHK_ERR( rval ); 725  rval = mbCore->get_entities_by_dimension( runCtx->meshsets[1], 2, tgtelems );MB_CHK_ERR( rval ); 726  rval = moab::IntxUtils::fix_degenerate_quads( mbCore, runCtx->meshsets[1] );MB_CHK_ERR( rval ); 727  if( runCtx->enforceConvexity ) 728  { 729  rval = moab::IntxUtils::enforce_convexity( mbCore, runCtx->meshsets[1], proc_id );MB_CHK_ERR( rval ); 730  } 731  rval = areaAdaptor.positive_orientation( mbCore, runCtx->meshsets[1], radius_dest );MB_CHK_ERR( rval ); 732  // if( !proc_id ) 733  // outputFormatter.printf( 0, "The target set contains %lu vertices and %lu elements \n", tgtverts.size(), 734  // tgtelems.size() ); 735  velist[2] = tgtverts.size(); 736  velist[3] = tgtelems.size(); 737  } 738  //rval = mbCore->write_file( "source_mesh.h5m", nullptr, writeOptions, &runCtx->meshsets[0], 1 );MB_CHK_ERR( rval ); 739  //rval = mbCore->write_file( "target_mesh.h5m", nullptr, writeOptions, &runCtx->meshsets[1], 1 );MB_CHK_ERR( rval ); 740  741  // if( runCtx->nlayers && nprocs > 1 ) 742  // { 743  // remapper.ResetMeshSet( moab::Remapper::SourceMesh, runCtx->meshsets[3] ); 744  // runCtx->meshes[0] = remapper.GetMesh( moab::Remapper::SourceMesh ); // ? 745  // } 746  747  // First compute the covering set such that the target elements are fully covered by the 748  // local source grid 749  runCtx->timer_push( "construct covering set for intersection" ); 750  rval = remapper.ConstructCoveringSet( runCtx->epsrel, 1.0, 1.0, runCtx->boxeps, runCtx->rrmGrids, 751  runCtx->useGnomonicProjection, runCtx->nlayers );MB_CHK_ERR( rval ); 752  runCtx->timer_pop(); 753  754 #ifdef MOAB_HAVE_MPI 755  MPI_Reduce( velist, gvelist, 4, MPI_UINT64_T, MPI_SUM, 0, MPI_COMM_WORLD ); 756 #else 757  for( int i = 0; i < 4; i++ ) 758  gvelist[i] = velist[i]; 759 #endif 760  761  if( !proc_id && runCtx->print_diagnostics ) 762  { 763  outputFormatter.printf( 0, "The source set contains %lu vertices and %lu elements \n", gvelist[0], 764  gvelist[1] ); 765  outputFormatter.printf( 0, "The target set contains %lu vertices and %lu elements \n", gvelist[2], 766  gvelist[3] ); 767  } 768  769  // Compute intersections with MOAB with either the Kd-tree or the advancing front algorithm 770  runCtx->timer_push( "setup and compute mesh intersections" ); 771  rval = remapper.ComputeOverlapMesh( runCtx->kdtreeSearch, false );MB_CHK_ERR( rval ); 772  runCtx->timer_pop(); 773  774  // print some diagnostic checks to see if the overlap grid resolved the input meshes 775  // correctly 776  double dTotalOverlapArea = 0.0; 777  if( runCtx->print_diagnostics ) 778  { 779  moab::IntxAreaUtils areaAdaptorHuiller( 780  moab::IntxAreaUtils::GaussQuadrature ); // lHuiller, GaussQuadrature 781  double local_areas[3], 782  global_areas[3]; // Array for Initial area, and through Method 1 and Method 2 783  // local_areas[0] = area_on_sphere_lHuiller ( mbCore, runCtx->meshsets[1], radius_src ); 784  local_areas[0] = areaAdaptorHuiller.area_on_sphere( mbCore, runCtx->meshsets[0], radius_src ); 785  local_areas[1] = areaAdaptorHuiller.area_on_sphere( mbCore, runCtx->meshsets[1], radius_dest ); 786  local_areas[2] = areaAdaptorHuiller.area_on_sphere( mbCore, runCtx->meshsets[2], radius_src ); 787  788 #ifdef MOAB_HAVE_MPI 789  MPI_Allreduce( &local_areas[0], &global_areas[0], 3, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD ); 790 #else 791  global_areas[0] = local_areas[0]; 792  global_areas[1] = local_areas[1]; 793  global_areas[2] = local_areas[2]; 794 #endif 795  if( !proc_id ) 796  { 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] ); 801  // outputFormatter.printf ( 0, " area with l'Huiller: %12.14f with Girard: 802  // %12.14f\n", global_areas[2], global_areas[3] ); outputFormatter.printf ( 0, " 803  // relative difference areas = %12.10e\n", fabs ( global_areas[2] - global_areas[3] 804  // ) / 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] ); 808  } 809  dTotalOverlapArea = global_areas[2]; 810  } 811  812  if( runCtx->intxFilename.size() ) 813  { 814  moab::EntityHandle writableOverlapSet; 815  rval = mbCore->create_meshset( moab::MESHSET_SET, writableOverlapSet );MB_CHK_SET_ERR( rval, "Can't create new set" ); 816  moab::EntityHandle meshOverlapSet = remapper.GetMeshSet( moab::Remapper::OverlapMesh ); 817  moab::Range ovEnts; 818  rval = mbCore->get_entities_by_dimension( meshOverlapSet, 2, ovEnts );MB_CHK_SET_ERR( rval, "Can't create new set" ); 819  rval = mbCore->get_entities_by_dimension( meshOverlapSet, 0, ovEnts );MB_CHK_SET_ERR( rval, "Can't create new set" ); 820  821 #ifdef MOAB_HAVE_MPI 822  // Do not remove ghosted entities if we still haven't computed weights 823  // Remove ghosted entities from overlap set before writing the new mesh set to file 824  if( nprocs > 1 ) 825  { 826  moab::Range ghostedEnts; 827  rval = remapper.GetOverlapAugmentedEntities( ghostedEnts );MB_CHK_ERR( rval ); 828  ovEnts = moab::subtract( ovEnts, ghostedEnts ); 829 #ifdef MOAB_DBG 830  if( !runCtx->skip_io ) 831  { 832  std::stringstream filename; 833  filename << "aug_overlap" << runCtx->pcomm->rank() << ".h5m"; 834  rval = runCtx->mbcore->write_file( filename.str().c_str(), 0, 0, &meshOverlapSet, 1 );MB_CHK_ERR( rval ); 835  } 836 #endif 837  } 838 #endif 839  rval = mbCore->add_entities( writableOverlapSet, ovEnts );MB_CHK_SET_ERR( rval, "adding local intx cells failed" ); 840  841 #ifdef MOAB_HAVE_MPI 842 #ifdef MOAB_DBG 843  if( nprocs > 1 && !runCtx->skip_io ) 844  { 845  std::stringstream filename; 846  filename << "writable_intx_" << runCtx->pcomm->rank() << ".h5m"; 847  rval = runCtx->mbcore->write_file( filename.str().c_str(), 0, 0, &writableOverlapSet, 1 );MB_CHK_ERR( rval ); 848  } 849 #endif 850 #endif 851  852  size_t lastindex = runCtx->intxFilename.find_last_of( "." ); 853  sstr.str( "" ); 854  sstr << runCtx->intxFilename.substr( 0, lastindex ) << ".h5m"; 855  if( !runCtx->proc_id ) 856  std::cout << "Writing out the MOAB intersection mesh file to " << sstr.str() << std::endl; 857  858  // Write out our computed intersection file 859  if( !runCtx->skip_io ) 860  { 861  rval = mbCore->write_file( sstr.str().c_str(), nullptr, writeOptions, &writableOverlapSet, 1 );MB_CHK_ERR( rval ); 862  } 863  } 864  865  if( runCtx->computeWeights ) 866  { 867  runCtx->meshes[2] = remapper.GetMesh( moab::Remapper::OverlapMesh ); 868  if( !runCtx->proc_id ) std::cout << std::endl; 869  870  runCtx->timer_push( "setup computation of weights" ); 871  // Call to generate the remapping weights with the tempest meshes 872  moab::TempestOnlineMap* weightMap = new moab::TempestOnlineMap( &remapper ); 873  runCtx->timer_pop(); 874  875  runCtx->timer_push( "compute weights with TempestRemap" ); 876  rval = weightMap->GenerateRemappingWeights( 877  runCtx->disc_methods[0], // std::string strInputType 878  runCtx->disc_methods[1], // std::string strOutputType, 879  runCtx->mapOptions, // const GenerateOfflineMapAlgorithmOptions& options 880  runCtx->doftag_names[0], // const std::string& source_tag_name 881  runCtx->doftag_names[1] // const std::string& target_tag_name 882  );MB_CHK_ERR( rval ); 883  runCtx->timer_pop(); 884  885  weightMap->PrintMapStatistics(); 886  887  // Invoke the CheckMap routine on the TempestRemap serial interface directly, if running 888  // on a single process 889  if( runCtx->fCheck ) 890  { 891  const double dNormalTolerance = 1.0E-8; 892  const double dStrictTolerance = 1.0E-12; 893  weightMap->CheckMap( runCtx->fCheck, runCtx->fCheck, runCtx->fCheck && ( runCtx->ensureMonotonicity ), 894  dNormalTolerance, dStrictTolerance, dTotalOverlapArea ); 895  } 896  897  if( runCtx->outFilename.size() ) 898  { 899  std::map< std::string, std::string > attrMap; 900  attrMap["MOABversion"] = std::string( MOAB_VERSION ); 901  attrMap["Title"] = "MOAB-TempestRemap (mbtempest) Offline Regridding Weight Generator"; 902  attrMap["normalization"] = "ovarea"; 903  attrMap["remap_options"] = runCtx->mapOptions.strMethod; 904  attrMap["domain_a"] = runCtx->inFilenames[0]; 905  attrMap["domain_b"] = runCtx->inFilenames[1]; 906  if( runCtx->intxFilename.size() ) attrMap["domain_aUb"] = runCtx->intxFilename; 907  attrMap["map_aPb"] = runCtx->outFilename; 908  attrMap["methodorder_a"] = runCtx->disc_methods[0] + ":" + std::to_string( runCtx->disc_orders[0] ) + 909  ":" + std::string( runCtx->doftag_names[0] ); 910  attrMap["concave_a"] = runCtx->mapOptions.fSourceConcave ? "true" : "false"; 911  attrMap["methodorder_b"] = runCtx->disc_methods[1] + ":" + std::to_string( runCtx->disc_orders[1] ) + 912  ":" + std::string( runCtx->doftag_names[1] ); 913  attrMap["concave_b"] = runCtx->mapOptions.fTargetConcave ? "true" : "false"; 914  attrMap["bubble"] = runCtx->mapOptions.fNoBubble ? "false" : "true"; 915  attrMap["history"] = historyStr; 916  917  // Write the map file to disk in parallel using either HDF5 or SCRIP interface 918  // in extra case; maybe need a better solution, just create it with the right meshset 919  // from the beginning; 920  if( !runCtx->skip_io ) 921  { 922  rval = weightMap->WriteParallelMap( runCtx->outFilename.c_str(), attrMap );MB_CHK_ERR( rval ); 923  } 924  } 925  926  if( runCtx->verifyWeights ) 927  { 928  // Let us pick a sampling test function for solution evaluation 929  // SH, SV, FH, USERVAR 930  bool userVariable = false; 931  moab::TempestOnlineMap::sample_function testFunction; 932  if( !runCtx->variableToVerify.compare( "SH" ) ) 933  testFunction = &sample_slow_harmonic; 934  else if( !runCtx->variableToVerify.compare( "FH" ) ) 935  testFunction = &sample_fast_harmonic; 936  else if( !runCtx->variableToVerify.compare( "SV" ) ) 937  testFunction = &sample_stationary_vortex; 938  else 939  { 940  userVariable = runCtx->variableToVerify.size() ? true : false; 941  testFunction = runCtx->variableToVerify.size() ? nullptr : sample_stationary_vortex; 942  } 943  944  moab::Tag srcAnalyticalFunction; 945  moab::Tag tgtAnalyticalFunction; 946  moab::Tag tgtProjectedFunction; 947  if( testFunction ) 948  { 949  runCtx->timer_push( "describe a solution on source grid" ); 950  rval = weightMap->DefineAnalyticalSolution( srcAnalyticalFunction, "AnalyticalSolnSrcExact", 951  moab::Remapper::SourceMesh, testFunction );MB_CHK_ERR( rval ); 952  runCtx->timer_pop(); 953  954  runCtx->timer_push( "describe a solution on target grid" ); 955  956  rval = weightMap->DefineAnalyticalSolution( tgtAnalyticalFunction, "AnalyticalSolnTgtExact", 957  moab::Remapper::TargetMesh, testFunction, 958  &tgtProjectedFunction, "ProjectedSolnTgt" );MB_CHK_ERR( rval ); 959  // rval = mbCore->write_file ( "tgtWithSolnTag.h5m", nullptr, writeOptions, 960  // &runCtx->meshsets[1], 1 ); MB_CHK_ERR ( rval ); 961  runCtx->timer_pop(); 962  } 963  else 964  { 965  rval = mbCore->tag_get_handle( runCtx->variableToVerify.c_str(), srcAnalyticalFunction );MB_CHK_ERR( rval ); 966  967  rval = mbCore->tag_get_handle( "ProjectedSolnTgt", 1, moab::MB_TYPE_DOUBLE, tgtProjectedFunction, 968  moab::MB_TAG_DENSE | moab::MB_TAG_CREAT );MB_CHK_ERR( rval ); 969  } 970  971  if( !runCtx->skip_io ) 972  { 973  rval = mbCore->write_file( "srcWithSolnTag.h5m", nullptr, writeOptions, &runCtx->meshsets[0], 1 );MB_CHK_ERR( rval ); 974  } 975  976  runCtx->timer_push( "compute solution projection on target grid" ); 977  rval = weightMap->ApplyWeights( srcAnalyticalFunction, tgtProjectedFunction, false, runCtx->cassType );MB_CHK_ERR( rval ); 978  runCtx->timer_pop(); 979  980  if( !runCtx->skip_io ) 981  { 982  rval = mbCore->write_file( "tgtWithSolnTag2.h5m", nullptr, writeOptions, &runCtx->meshsets[1], 1 );MB_CHK_ERR( rval ); 983  } 984  985  if( nprocs == 1 && runCtx->baselineFile.size() ) 986  { 987  // save the field from tgtWithSolnTag2 in a text file, and global ids for cells 988  moab::Range tgtCells; 989  rval = mbCore->get_entities_by_dimension( runCtx->meshsets[1], 2, tgtCells );MB_CHK_ERR( rval ); 990  std::vector< int > globIds; 991  globIds.resize( tgtCells.size() ); 992  std::vector< double > vals; 993  vals.resize( tgtCells.size() ); 994  moab::Tag projTag; 995  rval = mbCore->tag_get_handle( "ProjectedSolnTgt", projTag );MB_CHK_ERR( rval ); 996  moab::Tag gid = mbCore->globalId_tag(); 997  rval = mbCore->tag_get_data( gid, tgtCells, &globIds[0] );MB_CHK_ERR( rval ); 998  rval = mbCore->tag_get_data( projTag, tgtCells, &vals[0] );MB_CHK_ERR( rval ); 999  std::fstream fs; 1000  fs.open( runCtx->baselineFile.c_str(), std::fstream::out ); 1001  fs << std::setprecision( 15 ); // maximum precision for doubles 1002  for( size_t i = 0; i < tgtCells.size(); i++ ) 1003  fs << globIds[i] << " " << vals[i] << "\n"; 1004  fs.close(); 1005  // for good measure, save the source file too, with the tag AnalyticalSolnSrcExact 1006  // it will be used later to test, along with a target file 1007  if( !runCtx->skip_io ) 1008  { 1009  rval = mbCore->write_file( "srcWithSolnTag.h5m", nullptr, writeOptions, &runCtx->meshsets[0], 1 );MB_CHK_ERR( rval ); 1010  } 1011  } 1012  1013  // compute error metrics if it is a known analytical functional 1014  if( !userVariable ) 1015  { 1016  runCtx->timer_push( "compute error metrics against analytical solution on target grid" ); 1017  std::map< std::string, double > errMetrics; 1018  rval = weightMap->ComputeMetrics( moab::Remapper::TargetMesh, tgtAnalyticalFunction, 1019  tgtProjectedFunction, errMetrics, true );MB_CHK_ERR( rval ); 1020  runCtx->timer_pop(); 1021  } 1022  } 1023  1024  delete weightMap; 1025  } 1026  } 1027  1028  // Clean up 1029  remapper.clear(); 1030  delete runCtx; 1031  delete mbCore; 1032  1033 #ifdef MOAB_HAVE_MPI 1034  MPI_Finalize(); 1035 #endif 1036  exit( 0 ); 1037 }

References moab::Core::add_entities(), moab::TempestOnlineMap::ApplyWeights(), moab::IntxAreaUtils::area_on_sphere(), ToolContext::baselineFile, ToolContext::boxeps, ToolContext::cassType, moab::ParallelComm::check_all_shared_handles(), moab::TempestRemapper::clear(), moab::TempestOnlineMap::ComputeMetrics(), moab::TempestRemapper::ComputeOverlapMesh(), ToolContext::computeWeights, moab::TempestRemapper::ConstructCoveringSet(), moab::TempestRemapper::constructEdgeMap, moab::TempestRemapper::ConvertTempestMesh(), moab::Core::create_meshset(), CreateTempestMesh(), moab::TempestOnlineMap::DefineAnalyticalSolution(), ToolContext::disc_methods, ToolContext::disc_orders, ToolContext::doftag_names, moab::IntxUtils::enforce_convexity(), ToolContext::enforceConvexity, ToolContext::ensureMonotonicity, ToolContext::epsrel, error(), ErrorCode, ToolContext::fCheck, moab::Intx2Mesh::FindMaxEdges(), moab::IntxUtils::fix_degenerate_quads(), moab::IntxAreaUtils::GaussQuadrature, moab::TempestOnlineMap::GenerateRemappingWeights(), moab::Core::get_entities_by_dimension(), moab::TempestRemapper::GetMesh(), moab::TempestRemapper::GetMeshSet(), moab::TempestRemapper::GetOverlapAugmentedEntities(), moab::Core::globalId_tag(), ToolContext::inFilenames, moab::TempestRemapper::initialize(), moab::Intx2Mesh::intersect_meshes(), ToolContext::intxFilename, ToolContext::kdtreeSearch, moab::IntxAreaUtils::lHuiller, ToolContext::mapOptions, MB_CHK_ERR, MB_CHK_SET_ERR, MB_TAG_CREAT, MB_TAG_DENSE, MB_TYPE_DOUBLE, ToolContext::mbcore, ToolContext::meshes, MESHSET_SET, ToolContext::meshsets, ToolContext::meshType, moab::TempestRemapper::meshValidate, MOAB_VERSION, ToolContext::nlayers, ToolContext::outFilename, ToolContext::outputFormatter, moab::TempestRemapper::OVERLAP_MEMORY, moab::TempestRemapper::OVERLAP_MOAB, moab::Remapper::OverlapMesh, ToolContext::ParseCLOptions(), moab::IntxAreaUtils::positive_orientation(), ToolContext::print_diagnostics, moab::DebugOutput::printf(), moab::TempestOnlineMap::PrintMapStatistics(), ToolContext::proc_id, ToolContext::rrmGrids, sample_fast_harmonic(), sample_slow_harmonic(), sample_stationary_vortex(), moab::Intx2Mesh::set_box_error(), moab::Intx2Mesh::set_error_tolerance(), moab::Intx2MeshOnSphere::set_radius_destination_mesh(), moab::Intx2MeshOnSphere::set_radius_source_mesh(), moab::Range::size(), ToolContext::skip_io, moab::Remapper::SourceMesh, moab::subtract(), moab::Core::tag_get_data(), moab::Core::tag_get_handle(), moab::Remapper::TargetMesh, ToolContext::timer_pop(), ToolContext::timer_push(), ToolContext::useGnomonicProjection, ToolContext::variableToVerify, ToolContext::verifyWeights, moab::Core::write_file(), moab::Core::write_mesh(), and moab::TempestOnlineMap::WriteParallelMap().

◆ sample_constant()

double sample_constant ( double  dLon,
double  dLat 
)
inline

Definition at line 1220 of file mbtempest.cpp.

1221 { 1222  return 1.0; 1223 }

◆ sample_fast_harmonic()

double sample_fast_harmonic ( double  dLon,
double  dLat 
)
inline

Definition at line 1214 of file mbtempest.cpp.

1215 { 1216  return ( 2.0 + pow( sin( 2.0 * dLat ), 16.0 ) * cos( 16.0 * dLon ) ); 1217  // return (2.0 + pow(cos(2.0 * dLat), 16.0) * cos(16.0 * dLon)); 1218 }

Referenced by main().

◆ sample_slow_harmonic()

double sample_slow_harmonic ( double  dLon,
double  dLat 
)
inline

Definition at line 1209 of file mbtempest.cpp.

1210 { 1211  return ( 2.0 + cos( dLat ) * cos( dLat ) * cos( 2.0 * dLon ) ); 1212 }

Referenced by main().

◆ sample_stationary_vortex()

double sample_stationary_vortex ( double  dLon,
double  dLat 
)
inline

Find the rotated longitude and latitude of a point on a sphere with pole at (dLonC, dLatC).

Definition at line 1225 of file mbtempest.cpp.

1226 { 1227  const double dLon0 = 0.0; 1228  const double dLat0 = 0.6; 1229  const double dR0 = 3.0; 1230  const double dD = 5.0; 1231  const double dT = 6.0; 1232  1233  /// Find the rotated longitude and latitude of a point on a sphere 1234  /// with pole at (dLonC, dLatC). 1235  { 1236  double dSinC = sin( dLat0 ); 1237  double dCosC = cos( dLat0 ); 1238  double dCosT = cos( dLat ); 1239  double dSinT = sin( dLat ); 1240  1241  double dTrm = dCosT * cos( dLon - dLon0 ); 1242  double dX = dSinC * dTrm - dCosC * dSinT; 1243  double dY = dCosT * sin( dLon - dLon0 ); 1244  double dZ = dSinC * dSinT + dCosC * dTrm; 1245  1246  dLon = atan2( dY, dX ); 1247  if( dLon < 0.0 ) 1248  { 1249  dLon += 2.0 * M_PI; 1250  } 1251  dLat = asin( dZ ); 1252  } 1253  1254  double dRho = dR0 * cos( dLat ); 1255  double dVt = 3.0 * sqrt( 3.0 ) / 2.0 / cosh( dRho ) / cosh( dRho ) * tanh( dRho ); 1256  1257  double dOmega; 1258  if( dRho == 0.0 ) 1259  { 1260  dOmega = 0.0; 1261  } 1262  else 1263  { 1264  dOmega = dVt / dRho; 1265  } 1266  1267  return ( 1.0 - tanh( dRho / dD * sin( dLon - dOmega * dT ) ) ); 1268 }

Referenced by main().