16 #include "DataArray3D.h"
17 #include "FiniteVolumeTools.h"
18 #include "FiniteElementTools.h"
19 #include "TriangularQuadrature.h"
20 #include "GaussQuadrature.h"
21 #include "GaussLobattoQuadrature.h"
22 #include "SparseMatrix.h"
23 #include "STLStringHelper.h"
24 #include "LinearRemapFV.h"
26 #include "LinearRemapSE0.h"
27 #include "LinearRemapFV.h"
40 #ifdef MOAB_HAVE_NETCDFPAR
43 #include "netcdfcpp.h"
56 #define MPI_CHK_ERR( err ) \
59 std::cout << "MPI Failure. ErrorCode (" << ( err ) << ") "; \
60 std::cout << "\nMPI Aborting... \n"; \
61 return moab::MB_FAILURE; \
69 m_pcomm =
m_remapper->get_parallel_communicator();
97 std::vector< std::string > dimNames;
98 std::vector< int > dimSizes;
99 dimNames.push_back(
"num_elem" );
100 dimSizes.push_back( m_meshInputCov->faces.size() );
102 this->InitializeSourceDimensions( dimNames, dimSizes );
107 std::vector< std::string > dimNames;
108 std::vector< int > dimSizes;
109 dimNames.push_back(
"num_elem" );
110 dimSizes.push_back( m_meshOutput->faces.size() );
112 this->InitializeTargetDimensions( dimNames, dimSizes );
120 m_interface =
nullptr;
124 m_meshInput =
nullptr;
125 m_meshOutput =
nullptr;
126 m_meshOverlap =
nullptr;
132 const std::string tgtDofTagName )
137 tagSize = ( m_eInputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Src * m_nDofsPEl_Src );
143 MB_CHK_SET_ERR( MB_FAILURE,
"DoF tag is not set correctly for source mesh." );
148 tagSize = ( m_eOutputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Dest * m_nDofsPEl_Dest );
153 MB_CHK_SET_ERR( MB_FAILURE,
"DoF tag is not set correctly for target mesh." );
165 bool isSrcContinuous,
166 DataArray3D< int >* srcdataGLLNodes,
167 DataArray3D< int >* srcdataGLLNodesSrc,
170 bool isTgtContinuous,
171 DataArray3D< int >* tgtdataGLLNodes )
173 std::vector< bool > dgll_cgll_row_ldofmap, dgll_cgll_col_ldofmap, dgll_cgll_covcol_ldofmap;
174 std::vector< int > src_soln_gdofs, locsrc_soln_gdofs, tgt_soln_gdofs;
177 m_srcDiscType = srcType;
178 m_destDiscType = destType;
179 m_input_order = srcOrder;
180 m_output_order = destOrder;
182 bool vprint = is_root &&
false;
187 int srcTagSize = ( m_eInputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Src * m_nDofsPEl_Src );
188 if( m_remapper->point_cloud_source )
190 assert( m_nDofsPEl_Src == 1 );
191 col_gdofmap.resize( m_remapper->m_covering_source_vertices.size(), UINT_MAX );
192 col_dtoc_dofmap.resize( m_remapper->m_covering_source_vertices.size(), UINT_MAX );
193 src_soln_gdofs.resize( m_remapper->m_covering_source_vertices.size(), UINT_MAX );
194 MB_CHK_ERR( m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_covering_source_vertices, &src_soln_gdofs[0] ) );
199 col_gdofmap.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, UINT_MAX );
200 col_dtoc_dofmap.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, UINT_MAX );
201 src_soln_gdofs.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, UINT_MAX );
202 MB_CHK_ERR( m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_covering_source_entities, &src_soln_gdofs[0] ) );
205 m_nTotDofs_SrcCov = 0;
206 if( srcdataGLLNodes ==
nullptr )
209 for(
unsigned i = 0; i < col_gdofmap.size(); ++i )
211 auto gdof = src_soln_gdofs[i];
213 col_gdofmap[i] = gdof - 1;
214 col_dtoc_dofmap[i] = i;
215 if( vprint ) std::cout <<
"Col: " << i <<
", " << col_gdofmap[i] <<
"\n";
221 if( isSrcContinuous )
222 dgll_cgll_covcol_ldofmap.resize( m_remapper->m_covering_source_entities.size() * srcTagSize,
false );
224 for(
unsigned j = 0; j < m_remapper->m_covering_source_entities.size(); j++ )
226 for(
int p = 0; p < m_nDofsPEl_Src; p++ )
228 for(
int q = 0; q < m_nDofsPEl_Src; q++ )
230 const int localDOF = ( *srcdataGLLNodes )[p][q][j] - 1;
231 const int offsetDOF = j * srcTagSize + p * m_nDofsPEl_Src + q;
232 if( isSrcContinuous && !dgll_cgll_covcol_ldofmap[localDOF] )
235 dgll_cgll_covcol_ldofmap[localDOF] =
true;
237 if( !isSrcContinuous ) m_nTotDofs_SrcCov++;
238 assert( src_soln_gdofs[offsetDOF] > 0 );
239 col_gdofmap[localDOF] = src_soln_gdofs[offsetDOF] - 1;
240 col_dtoc_dofmap[offsetDOF] = localDOF;
242 std::cout <<
"Col: " << offsetDOF <<
", " << localDOF <<
", " << col_gdofmap[offsetDOF] <<
", "
243 << m_nTotDofs_SrcCov <<
"\n";
249 if( m_remapper->point_cloud_source )
251 assert( m_nDofsPEl_Src == 1 );
252 srccol_gdofmap.resize( m_remapper->m_source_vertices.size(), UINT_MAX );
253 srccol_dtoc_dofmap.resize( m_remapper->m_covering_source_vertices.size(), UINT_MAX );
254 locsrc_soln_gdofs.resize( m_remapper->m_source_vertices.size(), UINT_MAX );
255 MB_CHK_ERR( m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_source_vertices, &locsrc_soln_gdofs[0] ) );
259 srccol_gdofmap.resize( m_remapper->m_source_entities.size() * srcTagSize, UINT_MAX );
260 srccol_dtoc_dofmap.resize( m_remapper->m_source_entities.size() * srcTagSize, UINT_MAX );
261 locsrc_soln_gdofs.resize( m_remapper->m_source_entities.size() * srcTagSize, UINT_MAX );
262 MB_CHK_ERR( m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_source_entities, &locsrc_soln_gdofs[0] ) );
267 if( srcdataGLLNodesSrc ==
nullptr )
270 for(
unsigned i = 0; i < srccol_gdofmap.size(); ++i )
272 auto gdof = locsrc_soln_gdofs[i];
274 srccol_gdofmap[i] = gdof - 1;
275 srccol_dtoc_dofmap[i] = i;
281 if( isSrcContinuous ) dgll_cgll_col_ldofmap.resize( m_remapper->m_source_entities.size() * srcTagSize,
false );
283 for(
unsigned j = 0; j < m_remapper->m_source_entities.size(); j++ )
285 for(
int p = 0; p < m_nDofsPEl_Src; p++ )
287 for(
int q = 0; q < m_nDofsPEl_Src; q++ )
289 const int localDOF = ( *srcdataGLLNodesSrc )[p][q][j] - 1;
290 const int offsetDOF = j * srcTagSize + p * m_nDofsPEl_Src + q;
291 if( isSrcContinuous && !dgll_cgll_col_ldofmap[localDOF] )
294 dgll_cgll_col_ldofmap[localDOF] =
true;
296 if( !isSrcContinuous ) m_nTotDofs_Src++;
297 assert( locsrc_soln_gdofs[offsetDOF] > 0 );
298 srccol_gdofmap[localDOF] = locsrc_soln_gdofs[offsetDOF] - 1;
299 srccol_dtoc_dofmap[offsetDOF] = localDOF;
305 int tgtTagSize = ( m_eOutputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Dest * m_nDofsPEl_Dest );
306 if( m_remapper->point_cloud_target )
308 assert( m_nDofsPEl_Dest == 1 );
309 row_gdofmap.resize( m_remapper->m_target_vertices.size(), UINT_MAX );
310 row_dtoc_dofmap.resize( m_remapper->m_target_vertices.size(), UINT_MAX );
311 tgt_soln_gdofs.resize( m_remapper->m_target_vertices.size(), UINT_MAX );
312 MB_CHK_ERR( m_interface->tag_get_data( m_dofTagDest, m_remapper->m_target_vertices, &tgt_soln_gdofs[0] ) );
317 row_gdofmap.resize( m_remapper->m_target_entities.size() * tgtTagSize, UINT_MAX );
318 row_dtoc_dofmap.resize( m_remapper->m_target_entities.size() * tgtTagSize, UINT_MAX );
319 tgt_soln_gdofs.resize( m_remapper->m_target_entities.size() * tgtTagSize, UINT_MAX );
320 MB_CHK_ERR( m_interface->tag_get_data( m_dofTagDest, m_remapper->m_target_entities, &tgt_soln_gdofs[0] ) );
326 if( tgtdataGLLNodes ==
nullptr )
329 for(
unsigned i = 0; i < row_gdofmap.size(); ++i )
331 auto gdof = tgt_soln_gdofs[i];
333 row_gdofmap[i] = gdof - 1;
334 row_dtoc_dofmap[i] = i;
335 if( vprint ) std::cout <<
"Row: " << i <<
", " << row_gdofmap[i] <<
"\n";
341 if( isTgtContinuous ) dgll_cgll_row_ldofmap.resize( m_remapper->m_target_entities.size() * tgtTagSize,
false );
343 for(
unsigned j = 0; j < m_remapper->m_target_entities.size(); j++ )
345 for(
int p = 0; p < m_nDofsPEl_Dest; p++ )
347 for(
int q = 0; q < m_nDofsPEl_Dest; q++ )
349 const int localDOF = ( *tgtdataGLLNodes )[p][q][j] - 1;
350 const int offsetDOF = j * tgtTagSize + p * m_nDofsPEl_Dest + q;
351 if( isTgtContinuous && !dgll_cgll_row_ldofmap[localDOF] )
354 dgll_cgll_row_ldofmap[localDOF] =
true;
356 if( !isTgtContinuous ) m_nTotDofs_Dest++;
357 assert( tgt_soln_gdofs[offsetDOF] > 0 );
358 row_gdofmap[localDOF] = tgt_soln_gdofs[offsetDOF] - 1;
359 row_dtoc_dofmap[offsetDOF] = localDOF;
361 std::cout <<
"Row: " << offsetDOF <<
", " << localDOF <<
", " << row_gdofmap[offsetDOF] <<
", "
362 << m_nTotDofs_Dest <<
"\n";
369 #if defined( MOAB_HAVE_EIGEN3 ) && defined( VERBOSE )
372 std::cout <<
"[" << rank <<
"]" <<
"DoFs: row = " << m_nTotDofs_Dest <<
", " << row_gdofmap.size()
373 <<
", col = " << m_nTotDofs_Src <<
", " << m_nTotDofs_SrcCov <<
", " << col_gdofmap.size() <<
"\n";
379 #ifdef CHECK_INCREASING_DOF
380 for(
size_t i = 0; i < row_gdofmap.size() - 1; i++ )
382 if( row_gdofmap[i] > row_gdofmap[i + 1] )
383 std::cout <<
" on rank " << rank <<
" in row_gdofmap[" << i <<
"]=" << row_gdofmap[i] <<
" > row_gdofmap["
384 << i + 1 <<
"]=" << row_gdofmap[i + 1] <<
" \n";
386 for(
size_t i = 0; i < col_gdofmap.size() - 1; i++ )
388 if( col_gdofmap[i] > col_gdofmap[i + 1] )
389 std::cout <<
" on rank " << rank <<
" in col_gdofmap[" << i <<
"]=" << col_gdofmap[i] <<
" > col_gdofmap["
390 << i + 1 <<
"]=" << col_gdofmap[i + 1] <<
" \n";
406 col_dtoc_dofmap.resize( values_entities.size(), -1 );
407 for(
size_t j = 0; j < values_entities.size(); j++ )
410 const auto it = colMap.find( values_entities[j] - 1 );
411 if( it != colMap.end() ) col_dtoc_dofmap[j] = it->second;
420 row_dtoc_dofmap.resize( values_entities.size(), -1 );
421 for(
size_t j = 0; j < values_entities.size(); j++ )
424 const auto it = rowMap.find( values_entities[j] - 1 );
425 if( it != rowMap.end() ) row_dtoc_dofmap[j] = it->second;
432 std::string strOutputType,
433 const GenerateOfflineMapAlgorithmOptions& mapOptions,
434 const std::string& srcDofTagName,
435 const std::string& tgtDofTagName )
437 NcError
error( NcError::silent_nonfatal );
440 dbgprint.set_prefix(
"[TempestOnlineMap]: " );
443 const bool m_bPointCloudSource = ( m_remapper->point_cloud_source );
444 const bool m_bPointCloudTarget = ( m_remapper->point_cloud_target );
445 const bool m_bPointCloud = m_bPointCloudSource || m_bPointCloudTarget;
454 STLStringHelper::ToLower( strInputType );
455 STLStringHelper::ToLower( strOutputType );
460 if( strInputType ==
"fv" )
462 eInputType = DiscretizationType_FV;
464 else if( strInputType ==
"cgll" )
466 eInputType = DiscretizationType_CGLL;
468 else if( strInputType ==
"dgll" )
470 eInputType = DiscretizationType_DGLL;
472 else if( strInputType ==
"pcloud" )
474 eInputType = DiscretizationType_PCLOUD;
478 _EXCEPTION1(
"Invalid \"in_type\" value (%s), expected [fv|cgll|dgll]", strInputType.c_str() );
481 if( strOutputType ==
"fv" )
483 eOutputType = DiscretizationType_FV;
485 else if( strOutputType ==
"cgll" )
487 eOutputType = DiscretizationType_CGLL;
489 else if( strOutputType ==
"dgll" )
491 eOutputType = DiscretizationType_DGLL;
493 else if( strOutputType ==
"pcloud" )
495 eOutputType = DiscretizationType_PCLOUD;
499 _EXCEPTION1(
"Invalid \"out_type\" value (%s), expected [fv|cgll|dgll]", strOutputType.c_str() );
503 m_bConserved = !mapOptions.fNoConservation;
504 m_eInputType = eInputType;
505 m_eOutputType = eOutputType;
508 std::string strMapAlgorithm(
"" );
509 int nMonotoneType = ( mapOptions.fMonotone ) ? ( 1 ) : ( 0 );
512 std::set< std::string > setMethodStrings;
515 for(
size_t i = 0; i <= mapOptions.strMethod.length(); i++ )
517 if( ( i == mapOptions.strMethod.length() ) || ( mapOptions.strMethod[i] ==
';' ) )
519 std::string strMethodString = mapOptions.strMethod.substr( iLast, i - iLast );
520 STLStringHelper::RemoveWhitespaceInPlace( strMethodString );
521 if( strMethodString.length() > 0 )
523 setMethodStrings.insert( strMethodString );
530 for(
auto it : setMethodStrings )
535 if( nMonotoneType != 0 )
537 _EXCEPTIONT(
"Multiple monotonicity specifications found (--mono) or (--method \"mono#\")" );
539 if( ( m_eInputType == DiscretizationType_FV ) && ( m_eOutputType == DiscretizationType_FV ) )
541 _EXCEPTIONT(
"--method \"mono2\" is only used when remapping to/from CGLL or DGLL grids" );
547 else if( it ==
"mono3" )
549 if( nMonotoneType != 0 )
551 _EXCEPTIONT(
"Multiple monotonicity specifications found (--mono) or (--method \"mono#\")" );
553 if( ( m_eInputType == DiscretizationType_FV ) && ( m_eOutputType == DiscretizationType_FV ) )
555 _EXCEPTIONT(
"--method \"mono3\" is only used when remapping to/from CGLL or DGLL grids" );
561 else if( it ==
"volumetric" )
563 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType == DiscretizationType_FV ) )
565 _EXCEPTIONT(
"--method \"volumetric\" may only be used for FV->CGLL or FV->DGLL remapping" );
567 strMapAlgorithm =
"volumetric";
571 else if( it ==
"invdist" )
573 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
575 _EXCEPTIONT(
"--method \"invdist\" may only be used for FV->FV remapping" );
577 strMapAlgorithm =
"invdist";
581 else if( it ==
"delaunay" )
583 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
585 _EXCEPTIONT(
"--method \"delaunay\" may only be used for FV->FV remapping" );
587 strMapAlgorithm =
"delaunay";
591 else if( it ==
"bilin" )
593 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
595 _EXCEPTIONT(
"--method \"bilin\" may only be used for FV->FV remapping" );
597 strMapAlgorithm =
"fvbilin";
601 else if( it ==
"intbilin" )
603 if( m_eOutputType != DiscretizationType_FV )
605 _EXCEPTIONT(
"--method \"intbilin\" may only be used when mapping to FV." );
607 if( m_eInputType == DiscretizationType_FV )
609 strMapAlgorithm =
"fvintbilin";
613 strMapAlgorithm =
"mono3";
618 else if( it ==
"intbilingb" )
620 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
622 _EXCEPTIONT(
"--method \"intbilingb\" may only be used for FV->FV remapping" );
624 strMapAlgorithm =
"fvintbilingb";
628 _EXCEPTION1(
"Invalid --method argument \"%s\"", it.c_str() );
633 ( m_eInputType == DiscretizationType_FV || m_eInputType == DiscretizationType_PCLOUD ? 1
636 ( m_eOutputType == DiscretizationType_FV || m_eOutputType == DiscretizationType_PCLOUD ? 1
637 : mapOptions.nPout );
640 MB_CHK_ERR( SetDOFmapTags( srcDofTagName, tgtDofTagName ) );
644 rval = m_interface->tag_get_handle(
"aream", 1,
MB_TYPE_DOUBLE, areaTag,
648 if( is_root )
dbgprint.printf( 0,
"aream tag already defined \n" );
651 double local_areas[3] = { 0.0, 0.0, 0.0 }, global_areas[3] = { 0.0, 0.0, 0.0 };
652 if( !m_bPointCloudSource )
655 if( is_root )
dbgprint.printf( 0,
"Calculating input mesh Face areas\n" );
656 local_areas[0] = m_meshInput->CalculateFaceAreas( mapOptions.fSourceConcave );
658 MB_CHK_ERR( m_interface->tag_set_data( areaTag, m_remapper->m_source_entities, m_meshInput->vecFaceArea ) );
661 m_meshInputCov->CalculateFaceAreas( mapOptions.fSourceConcave );
664 if( !m_bPointCloudTarget )
667 if( is_root )
dbgprint.printf( 0,
"Calculating output mesh Face areas\n" );
668 local_areas[1] = m_meshOutput->CalculateFaceAreas( mapOptions.fTargetConcave );
670 MB_CHK_ERR( m_interface->tag_set_data( areaTag, m_remapper->m_target_entities, m_meshOutput->vecFaceArea ) );
676 assert( m_meshOverlap->vecSourceFaceIx.size() == m_meshOverlap->vecTargetFaceIx.size() );
679 if( is_root )
dbgprint.printf( 0,
"Calculating overlap mesh Face areas\n" );
681 m_meshOverlap->CalculateFaceAreas( mapOptions.fSourceConcave || mapOptions.fTargetConcave );
684 std::copy( local_areas, local_areas + 3, global_areas );
687 if( m_pcomm && is_parallel )
688 MPI_Reduce( local_areas, global_areas, 3, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
692 dbgprint.printf( 0,
"Input Mesh Geometric Area: %1.15e\n", global_areas[0] );
693 dbgprint.printf( 0,
"Output Mesh Geometric Area: %1.15e\n", global_areas[1] );
694 dbgprint.printf( 0,
"Overlap Mesh Recovered Area: %1.15e\n", global_areas[2] );
698 constexpr
bool fCorrectAreas =
true;
701 if( is_root )
dbgprint.printf( 0,
"Correcting source/target areas to overlap mesh areas\n" );
702 DataArray1D< double > dSourceArea( m_meshInputCov->faces.size() );
703 DataArray1D< double > dTargetArea( m_meshOutput->faces.size() );
705 assert( m_meshOverlap->vecSourceFaceIx.size() == m_meshOverlap->faces.size() );
706 assert( m_meshOverlap->vecTargetFaceIx.size() == m_meshOverlap->faces.size() );
707 assert( m_meshOverlap->vecFaceArea.GetRows() == m_meshOverlap->faces.size() );
709 assert( m_meshInputCov->vecFaceArea.GetRows() == m_meshInputCov->faces.size() );
710 assert( m_meshOutput->vecFaceArea.GetRows() == m_meshOutput->faces.size() );
712 for(
size_t i = 0; i < m_meshOverlap->faces.size(); i++ )
714 if( m_meshOverlap->vecSourceFaceIx[i] < 0 || m_meshOverlap->vecTargetFaceIx[i] < 0 )
718 assert(
static_cast< size_t >( m_meshOverlap->vecSourceFaceIx[i] ) < m_meshInputCov->faces.size() );
719 dSourceArea[m_meshOverlap->vecSourceFaceIx[i]] += m_meshOverlap->vecFaceArea[i];
720 assert(
static_cast< size_t >( m_meshOverlap->vecTargetFaceIx[i] ) < m_meshOutput->faces.size() );
721 dTargetArea[m_meshOverlap->vecTargetFaceIx[i]] += m_meshOverlap->vecFaceArea[i];
724 for(
size_t i = 0; i < m_meshInputCov->faces.size(); i++ )
726 if( fabs( dSourceArea[i] - m_meshInputCov->vecFaceArea[i] ) < 1.0e-10 )
728 m_meshInputCov->vecFaceArea[i] = dSourceArea[i];
731 for(
size_t i = 0; i < m_meshOutput->faces.size(); i++ )
733 if( fabs( dTargetArea[i] - m_meshOutput->vecFaceArea[i] ) < 1.0e-10 )
735 m_meshOutput->vecFaceArea[i] = dTargetArea[i];
741 if( !m_bPointCloudSource && eInputType == DiscretizationType_FV )
743 this->SetSourceAreas( m_meshInputCov->vecFaceArea );
744 if( m_meshInputCov->vecMask.size() )
746 this->SetSourceMask( m_meshInputCov->vecMask );
751 if( !m_bPointCloudTarget && eOutputType == DiscretizationType_FV )
753 this->SetTargetAreas( m_meshOutput->vecFaceArea );
754 if( m_meshOutput->vecMask.size() )
756 this->SetTargetMask( m_meshOutput->vecMask );
772 if( ( eInputType == DiscretizationType_FV ) && ( eOutputType == DiscretizationType_FV ) )
775 if( m_meshInputCov->revnodearray.size() == 0 ) m_meshInputCov->ConstructReverseNodeArray();
776 if( m_meshInputCov->edgemap.size() == 0 ) m_meshInputCov->ConstructEdgeMap(
false );
779 this->InitializeSourceCoordinatesFromMeshFV( *m_meshInputCov );
780 this->InitializeTargetCoordinatesFromMeshFV( *m_meshOutput );
782 this->m_pdataGLLNodesIn =
nullptr;
783 this->m_pdataGLLNodesOut =
nullptr;
786 rval = this->SetDOFmapAssociation( eInputType, mapOptions.nPin,
false,
nullptr,
nullptr, eOutputType,
787 mapOptions.nPout,
false,
nullptr );
MB_CHK_ERR( rval );
790 if( is_root )
dbgprint.printf( 0,
"Calculating remap weights\n" );
793 if( strMapAlgorithm ==
"invdist" )
795 if( is_root )
dbgprint.printf( 0,
"Calculating map (invdist)\n" );
796 if( m_meshInputCov->faces.size() )
797 LinearRemapFVtoFVInvDist( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *
this );
799 else if( strMapAlgorithm ==
"delaunay" )
801 if( is_root )
dbgprint.printf( 0,
"Calculating map (delaunay)\n" );
802 if( m_meshInputCov->faces.size() )
803 LinearRemapTriangulation( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *
this );
805 else if( strMapAlgorithm ==
"fvintbilin" )
807 if( is_root )
dbgprint.printf( 0,
"Calculating map (intbilin)\n" );
808 if( m_meshInputCov->faces.size() )
809 LinearRemapIntegratedBilinear( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *
this );
811 else if( strMapAlgorithm ==
"fvintbilingb" )
813 if( is_root )
dbgprint.printf( 0,
"Calculating map (intbilingb)\n" );
814 if( m_meshInputCov->faces.size() )
815 LinearRemapIntegratedGeneralizedBarycentric( *m_meshInputCov, *m_meshOutput, *m_meshOverlap,
818 else if( strMapAlgorithm ==
"fvbilin" )
823 m_meshInputCov->Write(
"SourceMeshMBTR.g" );
824 m_meshOutput->Write(
"TargetMeshMBTR.g" );
828 m_meshInputCov->Write(
"SourceMeshMBTR" + std::to_string( rank ) +
".g" );
829 m_meshOutput->Write(
"TargetMeshMBTR" + std::to_string( rank ) +
".g" );
832 if( is_root )
dbgprint.printf( 0,
"Calculating map (bilin)\n" );
833 if( m_meshInputCov->faces.size() )
834 LinearRemapBilinear( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *
this );
838 if( is_root )
dbgprint.printf( 0,
"Calculating conservative FV-FV map\n" );
839 if( m_meshInputCov->faces.size() )
841 #ifdef USE_NATIVE_TEMPESTREMAP_ROUTINES
842 LinearRemapFVtoFV( *m_meshInputCov, *m_meshOutput, *m_meshOverlap,
843 ( mapOptions.fMonotone ) ? ( 1 ) : ( mapOptions.nPin ), *
this );
845 LinearRemapFVtoFV_Tempest_MOAB( ( mapOptions.fMonotone ? 1 : mapOptions.nPin ) );
850 else if( eInputType == DiscretizationType_FV )
852 DataArray3D< double > dataGLLJacobian;
854 if( is_root )
dbgprint.printf( 0,
"Generating output mesh meta data\n" );
855 double dNumericalArea_loc = GenerateMetaData( *m_meshOutput, mapOptions.nPout, mapOptions.fNoBubble,
856 dataGLLNodesDest, dataGLLJacobian );
858 double dNumericalArea = dNumericalArea_loc;
861 MPI_Reduce( &dNumericalArea_loc, &dNumericalArea, 1, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
863 if( is_root )
dbgprint.printf( 0,
"Output Mesh Numerical Area: %1.15e\n", dNumericalArea );
866 this->InitializeSourceCoordinatesFromMeshFV( *m_meshInputCov );
867 this->InitializeTargetCoordinatesFromMeshFE( *m_meshOutput, mapOptions.nPout, dataGLLNodesDest );
869 this->m_pdataGLLNodesIn =
nullptr;
870 this->m_pdataGLLNodesOut = &dataGLLNodesDest;
873 bool fContinuous = ( eOutputType == DiscretizationType_CGLL );
875 if( eOutputType == DiscretizationType_CGLL )
877 GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobian, this->GetTargetAreas() );
881 GenerateDiscontinuousJacobian( dataGLLJacobian, this->GetTargetAreas() );
885 if( m_meshInputCov->revnodearray.size() == 0 ) m_meshInputCov->ConstructReverseNodeArray();
886 if( m_meshInputCov->edgemap.size() == 0 ) m_meshInputCov->ConstructEdgeMap(
false );
889 rval = this->SetDOFmapAssociation( eInputType, mapOptions.nPin,
false,
nullptr,
nullptr, eOutputType,
890 mapOptions.nPout, ( eOutputType == DiscretizationType_CGLL ),
894 if( strMapAlgorithm ==
"volumetric" )
896 if( is_root )
dbgprint.printf( 0,
"Calculating remapping weights for FV->GLL (volumetric)\n" );
897 LinearRemapFVtoGLL_Volumetric( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesDest,
898 dataGLLJacobian, this->GetTargetAreas(), mapOptions.nPin, *
this,
899 nMonotoneType, fContinuous, mapOptions.fNoConservation );
903 if( is_root )
dbgprint.printf( 0,
"Calculating remapping weights for FV->GLL\n" );
904 LinearRemapFVtoGLL( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesDest, dataGLLJacobian,
905 this->GetTargetAreas(), mapOptions.nPin, *
this, nMonotoneType, fContinuous,
906 mapOptions.fNoConservation );
909 else if( ( eInputType == DiscretizationType_PCLOUD ) || ( eOutputType == DiscretizationType_PCLOUD ) )
911 DataArray3D< double > dataGLLJacobian;
912 if( !m_bPointCloudSource )
915 if( m_meshInputCov->revnodearray.size() == 0 ) m_meshInputCov->ConstructReverseNodeArray();
916 if( m_meshInputCov->edgemap.size() == 0 ) m_meshInputCov->ConstructEdgeMap(
false );
919 if( eInputType == DiscretizationType_FV )
921 this->InitializeSourceCoordinatesFromMeshFV( *m_meshInputCov );
925 if( is_root )
dbgprint.printf( 0,
"Generating input mesh meta data\n" );
926 DataArray3D< double > dataGLLJacobianSrc;
927 GenerateMetaData( *m_meshInputCov, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrcCov,
929 GenerateMetaData( *m_meshInput, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrc,
930 dataGLLJacobianSrc );
935 if( !m_bPointCloudTarget )
938 if( m_meshOutput->revnodearray.size() == 0 ) m_meshOutput->ConstructReverseNodeArray();
939 if( m_meshOutput->edgemap.size() == 0 ) m_meshOutput->ConstructEdgeMap(
false );
942 if( eOutputType == DiscretizationType_FV )
944 this->InitializeSourceCoordinatesFromMeshFV( *m_meshOutput );
948 if( is_root )
dbgprint.printf( 0,
"Generating output mesh meta data\n" );
949 GenerateMetaData( *m_meshOutput, mapOptions.nPout, mapOptions.fNoBubble, dataGLLNodesDest,
956 rval = this->SetDOFmapAssociation(
957 eInputType, mapOptions.nPin, ( eInputType == DiscretizationType_CGLL ),
958 ( m_bPointCloudSource || eInputType == DiscretizationType_FV ?
nullptr : &dataGLLNodesSrcCov ),
959 ( m_bPointCloudSource || eInputType == DiscretizationType_FV ?
nullptr : &dataGLLNodesSrc ),
960 eOutputType, mapOptions.nPout, ( eOutputType == DiscretizationType_CGLL ),
961 ( m_bPointCloudTarget ?
nullptr : &dataGLLNodesDest ) );
MB_CHK_ERR( rval );
964 if( is_root )
dbgprint.printf( 0,
"Calculating remap weights with Nearest-Neighbor method\n" );
965 rval = LinearRemapNN_MOAB(
true ,
false );
MB_CHK_ERR( rval );
967 else if( ( eInputType != DiscretizationType_FV ) && ( eOutputType == DiscretizationType_FV ) )
969 DataArray3D< double > dataGLLJacobianSrc, dataGLLJacobian;
971 if( is_root )
dbgprint.printf( 0,
"Generating input mesh meta data\n" );
973 GenerateMetaData( *m_meshInput, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrc,
974 dataGLLJacobianSrc );
975 GenerateMetaData( *m_meshInputCov, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrcCov,
978 if( dataGLLNodesSrcCov.GetSubColumns() != m_meshInputCov->faces.size() )
980 _EXCEPTIONT(
"Number of element does not match between metadata and "
985 this->InitializeSourceCoordinatesFromMeshFE( *m_meshInputCov, mapOptions.nPin, dataGLLNodesSrcCov );
986 this->InitializeTargetCoordinatesFromMeshFV( *m_meshOutput );
989 bool fContinuousIn = ( eInputType == DiscretizationType_CGLL );
991 if( eInputType == DiscretizationType_CGLL )
993 GenerateUniqueJacobian( dataGLLNodesSrcCov, dataGLLJacobian, this->GetSourceAreas() );
997 GenerateDiscontinuousJacobian( dataGLLJacobian, this->GetSourceAreas() );
1001 rval = this->SetDOFmapAssociation( eInputType, mapOptions.nPin, ( eInputType == DiscretizationType_CGLL ),
1002 &dataGLLNodesSrcCov, &dataGLLNodesSrc, eOutputType, mapOptions.nPout,
1006 if( is_root )
dbgprint.printf( 0,
"Calculating remap weights\n" );
1008 if( strMapAlgorithm ==
"volumetric" )
1010 _EXCEPTIONT(
"Unimplemented: Volumetric currently unavailable for"
1014 this->m_pdataGLLNodesIn = &dataGLLNodesSrcCov;
1015 this->m_pdataGLLNodesOut =
nullptr;
1017 #ifdef USE_NATIVE_TEMPESTREMAP_ROUTINES
1018 LinearRemapSE4( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesSrcCov, dataGLLJacobian,
1019 nMonotoneType, fContinuousIn, mapOptions.fNoConservation, mapOptions.fSparseConstraints,
1022 LinearRemapSE4_Tempest_MOAB( dataGLLNodesSrcCov, dataGLLJacobian, nMonotoneType, fContinuousIn,
1023 mapOptions.fNoConservation );
1026 else if( ( eInputType != DiscretizationType_FV ) && ( eOutputType != DiscretizationType_FV ) )
1028 DataArray3D< double > dataGLLJacobianIn, dataGLLJacobianSrc;
1029 DataArray3D< double > dataGLLJacobianOut;
1032 if( is_root )
dbgprint.printf( 0,
"Generating input mesh meta data\n" );
1034 GenerateMetaData( *m_meshInput, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrc,
1035 dataGLLJacobianSrc );
1037 GenerateMetaData( *m_meshInputCov, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrcCov,
1038 dataGLLJacobianIn );
1040 if( is_root )
dbgprint.printf( 0,
"Generating output mesh meta data\n" );
1041 GenerateMetaData( *m_meshOutput, mapOptions.nPout, mapOptions.fNoBubble, dataGLLNodesDest,
1042 dataGLLJacobianOut );
1045 this->InitializeSourceCoordinatesFromMeshFE( *m_meshInputCov, mapOptions.nPin, dataGLLNodesSrcCov );
1046 this->InitializeTargetCoordinatesFromMeshFE( *m_meshOutput, mapOptions.nPout, dataGLLNodesDest );
1049 bool fContinuousIn = ( eInputType == DiscretizationType_CGLL );
1051 if( eInputType == DiscretizationType_CGLL )
1053 GenerateUniqueJacobian( dataGLLNodesSrcCov, dataGLLJacobianIn, this->GetSourceAreas() );
1057 GenerateDiscontinuousJacobian( dataGLLJacobianIn, this->GetSourceAreas() );
1061 bool fContinuousOut = ( eOutputType == DiscretizationType_CGLL );
1063 if( eOutputType == DiscretizationType_CGLL )
1065 GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobianOut, this->GetTargetAreas() );
1069 GenerateDiscontinuousJacobian( dataGLLJacobianOut, this->GetTargetAreas() );
1073 rval = this->SetDOFmapAssociation( eInputType, mapOptions.nPin, ( eInputType == DiscretizationType_CGLL ),
1074 &dataGLLNodesSrcCov, &dataGLLNodesSrc, eOutputType, mapOptions.nPout,
1075 ( eOutputType == DiscretizationType_CGLL ), &dataGLLNodesDest );
MB_CHK_ERR( rval );
1077 this->m_pdataGLLNodesIn = &dataGLLNodesSrcCov;
1078 this->m_pdataGLLNodesOut = &dataGLLNodesDest;
1081 if( is_root )
dbgprint.printf( 0,
"Calculating remap weights\n" );
1083 #ifdef USE_NATIVE_TEMPESTREMAP_ROUTINES
1084 LinearRemapGLLtoGLL_Integrated( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesSrcCov,
1085 dataGLLJacobianIn, dataGLLNodesDest, dataGLLJacobianOut,
1086 this->GetTargetAreas(), mapOptions.nPin, mapOptions.nPout, nMonotoneType,
1087 fContinuousIn, fContinuousOut, mapOptions.fSparseConstraints, *
this );
1089 LinearRemapGLLtoGLL2_MOAB( dataGLLNodesSrcCov, dataGLLJacobianIn, dataGLLNodesDest, dataGLLJacobianOut,
1090 this->GetTargetAreas(), mapOptions.nPin, mapOptions.nPout, nMonotoneType,
1091 fContinuousIn, fContinuousOut, mapOptions.fNoConservation );
1096 _EXCEPTIONT(
"Not implemented" );
1099 #ifdef MOAB_HAVE_EIGEN3
1100 copy_tempest_sparsemat_to_eigen3();
1103 #ifdef MOAB_HAVE_MPI
1107 rval = m_remapper->GetOverlapAugmentedEntities( ghostedEnts );
MB_CHK_ERR( rval );
1109 rval = m_interface->remove_entities( m_meshOverlapSet, ghostedEnts );
MB_CHK_SET_ERR( rval,
"Deleting ghosted entities failed" );
1113 if( !mapOptions.fNoCheck )
1115 if( is_root )
dbgprint.printf( 0,
"Verifying map" );
1116 this->IsConsistent( 1.0e-8 );
1117 if( !mapOptions.fNoConservation ) this->IsConservative( 1.0e-8 );
1119 if( nMonotoneType != 0 )
1121 this->IsMonotone( 1.0e-12 );
1125 catch( Exception& e )
1127 dbgprint.printf( 0,
"%s", e.ToString().c_str() );
1128 return ( moab::MB_FAILURE );
1132 return ( moab::MB_FAILURE );
1141 #ifndef MOAB_HAVE_MPI
1143 return OfflineMap::IsConsistent( dTolerance );
1148 DataArray1D< int > dataRows;
1149 DataArray1D< int > dataCols;
1150 DataArray1D< double > dataEntries;
1153 DataArray1D< double > dRowSums;
1154 m_mapRemap.GetEntries( dataRows, dataCols, dataEntries );
1155 dRowSums.Allocate( m_mapRemap.GetRows() );
1157 for(
unsigned i = 0; i < dataRows.GetRows(); i++ )
1159 dRowSums[dataRows[i]] += dataEntries[i];
1163 int fConsistent = 0;
1164 for(
unsigned i = 0; i < dRowSums.GetRows(); i++ )
1166 if( fabs( dRowSums[i] - 1.0 ) > dTolerance )
1169 int rowGID = row_gdofmap[i];
1170 Announce(
"TempestOnlineMap is not consistent in row %i (%1.15e)", rowGID, dRowSums[i] );
1175 int fConsistentGlobal = 0;
1176 ierr = MPI_Allreduce( &fConsistent, &fConsistentGlobal, 1, MPI_INT, MPI_SUM, m_pcomm->comm() );
1177 if( ierr != MPI_SUCCESS )
return -1;
1179 return fConsistentGlobal;
1187 #ifndef MOAB_HAVE_MPI
1189 return OfflineMap::IsConservative( dTolerance );
1196 DataArray1D< int > dataRows;
1197 DataArray1D< int > dataCols;
1198 DataArray1D< double > dataEntries;
1199 const DataArray1D< double >& dTargetAreas = this->GetTargetAreas();
1200 const DataArray1D< double >& dSourceAreas = this->GetSourceAreas();
1203 std::vector< int > dColumnsUnique;
1204 std::vector< double > dColumnSums;
1206 int nColumns = m_mapRemap.GetColumns();
1207 m_mapRemap.GetEntries( dataRows, dataCols, dataEntries );
1208 dColumnSums.resize( m_nTotDofs_SrcCov, 0.0 );
1209 dColumnsUnique.resize( m_nTotDofs_SrcCov, -1 );
1211 for(
unsigned i = 0; i < dataEntries.GetRows(); i++ )
1213 dColumnSums[dataCols[i]] += dataEntries[i] * dTargetAreas[dataRows[i]] / dSourceAreas[dataCols[i]];
1215 assert( dataCols[i] < m_nTotDofs_SrcCov );
1218 int colGID = this->GetColGlobalDoF( dataCols[i] );
1220 dColumnsUnique[dataCols[i]] = colGID;
1227 std::vector< int > nElementsInProc;
1228 const int nDATA = 3;
1229 nElementsInProc.resize(
size * nDATA );
1230 int senddata[nDATA] = { nColumns, m_nTotDofs_SrcCov, m_nTotDofs_Src };
1231 ierr = MPI_Gather( senddata, nDATA, MPI_INT, nElementsInProc.data(), nDATA, MPI_INT, rootProc, m_pcomm->comm() );
1232 if( ierr != MPI_SUCCESS )
return -1;
1234 int nTotVals = 0, nTotColumns = 0, nTotColumnsUnq = 0;
1235 std::vector< int > dColumnIndices;
1236 std::vector< double > dColumnSourceAreas;
1237 std::vector< double > dColumnSumsTotal;
1238 std::vector< int > displs, rcount;
1239 if( rank == rootProc )
1241 displs.resize(
size + 1, 0 );
1242 rcount.resize(
size, 0 );
1244 for(
int ir = 0; ir <
size; ++ir )
1246 nTotVals += nElementsInProc[ir * nDATA];
1247 nTotColumns += nElementsInProc[ir * nDATA + 1];
1248 nTotColumnsUnq += nElementsInProc[ir * nDATA + 2];
1251 rcount[ir] = nElementsInProc[ir * nDATA + 1];
1257 printf(
"Total nnz: %d, global source elements = %d\n", nTotVals, gsum );
1259 dColumnIndices.resize( nTotColumns, -1 );
1260 dColumnSumsTotal.resize( nTotColumns, 0.0 );
1269 ierr = MPI_Gatherv( &dColumnsUnique[0], m_nTotDofs_SrcCov, MPI_INT, &dColumnIndices[0], rcount.data(),
1270 displs.data(), MPI_INT, rootProc, m_pcomm->comm() );
1271 if( ierr != MPI_SUCCESS )
return -1;
1272 ierr = MPI_Gatherv( &dColumnSums[0], m_nTotDofs_SrcCov, MPI_DOUBLE, &dColumnSumsTotal[0], rcount.data(),
1273 displs.data(), MPI_DOUBLE, rootProc, m_pcomm->comm() );
1274 if( ierr != MPI_SUCCESS )
return -1;
1280 dColumnSums.clear();
1281 dColumnsUnique.clear();
1284 int fConservative = 0;
1285 if( rank == rootProc )
1287 displs[
size] = ( nTotColumns );
1289 std::map< int, double > dColumnSumsOnRoot;
1291 for(
int ir = 0; ir <
size; ir++ )
1293 for(
int ips = displs[ir]; ips < displs[ir + 1]; ips++ )
1295 if( dColumnIndices[ips] < 0 )
continue;
1297 assert( dColumnIndices[ips] < nTotColumnsUnq );
1298 dColumnSumsOnRoot[dColumnIndices[ips]] += dColumnSumsTotal[ips];
1304 for( std::map< int, double >::iterator it = dColumnSumsOnRoot.begin(); it != dColumnSumsOnRoot.end(); ++it )
1307 if( fabs( it->second - 1.0 ) > dTolerance )
1310 Announce(
"TempestOnlineMap is not conservative in column "
1313 it->first, it->second );
1319 ierr = MPI_Bcast( &fConservative, 1, MPI_INT, rootProc, m_pcomm->comm() );
1320 if( ierr != MPI_SUCCESS )
return -1;
1322 return fConservative;
1330 #ifndef MOAB_HAVE_MPI
1332 return OfflineMap::IsMonotone( dTolerance );
1337 DataArray1D< int > dataRows;
1338 DataArray1D< int > dataCols;
1339 DataArray1D< double > dataEntries;
1341 m_mapRemap.GetEntries( dataRows, dataCols, dataEntries );
1345 for(
unsigned i = 0; i < dataRows.GetRows(); i++ )
1347 if( ( dataEntries[i] < -dTolerance ) || ( dataEntries[i] > 1.0 + dTolerance ) )
1351 Announce(
"TempestOnlineMap is not monotone in entry (%i): %1.15e", i, dataEntries[i] );
1356 int fMonotoneGlobal = 0;
1357 ierr = MPI_Allreduce( &fMonotone, &fMonotoneGlobal, 1, MPI_INT, MPI_SUM, m_pcomm->comm() );
1358 if( ierr != MPI_SUCCESS )
return -1;
1360 return fMonotoneGlobal;
1369 bool useMOABAdjacencies,
1372 assert( nrings > 0 );
1373 assert( useMOABAdjacencies || trMesh !=
nullptr );
1375 const size_t nrows = vecAdjFaces.size();
1377 for(
size_t index = 0; index < nrows; index++ )
1379 vecAdjFaces[index].insert( index );
1382 if( useMOABAdjacencies )
1392 int adjIndex =
entities.index( *it );
1394 if( adjIndex >= 0 ) vecAdjFaces[index].insert( adjIndex );
1403 Face&
face = trMesh->faces[index];
1404 GetAdjacentFaceVectorByEdge( *trMesh, index, nrings *
face.edges.size(), adjFaces );
1407 for(
auto adjFace : adjFaces )
1408 if( adjFace.first >= 0 )
1409 vecAdjFaces[index].insert( adjFace.first );
1419 double default_projection )
1421 std::vector< double > solSTagVals;
1422 std::vector< double > solTTagVals;
1425 if( m_remapper->point_cloud_source || m_remapper->point_cloud_target )
1427 if( m_remapper->point_cloud_source )
1430 solSTagVals.resize( covSrcEnts.
size(), default_projection );
1436 solSTagVals.resize( covSrcEnts.
size() * this->GetSourceNDofsPerElement() * this->GetSourceNDofsPerElement(),
1437 default_projection );
1440 if( m_remapper->point_cloud_target )
1443 solTTagVals.resize( tgtEnts.
size(), default_projection );
1449 solTTagVals.resize( tgtEnts.
size() * this->GetDestinationNDofsPerElement() *
1450 this->GetDestinationNDofsPerElement(),
1451 default_projection );
1459 solSTagVals.resize( covSrcEnts.
size() * this->GetSourceNDofsPerElement() * this->GetSourceNDofsPerElement(),
1460 default_projection );
1461 solTTagVals.resize( tgtEnts.
size() * this->GetDestinationNDofsPerElement() *
1462 this->GetDestinationNDofsPerElement(),
1463 default_projection );
1470 MB_CHK_SET_ERR( m_interface->tag_get_data( srcSolutionTag, sents, &solSTagVals[0] ),
1471 "Getting local tag data failed" );
1476 MB_CHK_SET_ERR( this->ApplyWeights( solSTagVals, solTTagVals, transpose ),
1477 "Applying remap operator onto source vector data failed" );
1480 MB_CHK_SET_ERR( m_interface->tag_set_data( tgtSolutionTag, tents, &solTTagVals[0] ),
1481 "Setting target tag data failed" );
1483 if( caasType != CAAS_NONE )
1485 std::string tgtSolutionTagName;
1486 MB_CHK_SET_ERR( m_interface->tag_get_name( tgtSolutionTag, tgtSolutionTagName ),
"Getting tag name failed" );
1489 constexpr
int nmax_caas_iterations = 10;
1490 double mismatch = 1.0;
1491 int caasIteration = 0;
1492 double initialMismatch = 0.0;
1493 while( ( fabs( mismatch / initialMismatch ) > 1e-15 && fabs( mismatch ) > 1e-15 ) &&
1494 caasIteration++ < nmax_caas_iterations )
1496 double dMassDiffPostGlobal;
1497 std::pair< double, double > mDefect =
1498 this->ApplyBoundsLimiting( solSTagVals, solTTagVals, caasType, caasIteration, mismatch );
1499 #ifdef MOAB_HAVE_MPI
1500 double dMassDiffPost = mDefect.second;
1501 MPI_Allreduce( &dMassDiffPost, &dMassDiffPostGlobal, 1, MPI_DOUBLE, MPI_SUM, m_pcomm->comm() );
1503 dMassDiffPostGlobal = mDefect.second;
1505 if( caasIteration == 1 ) initialMismatch = mDefect.first;
1506 if( m_remapper->verbose && is_root )
1508 printf(
"Field {%s} -> CAAS iteration: %d, mass defect: %3.4e, post-CAAS: %3.4e\n",
1509 tgtSolutionTagName.c_str(), caasIteration, mDefect.first, dMassDiffPostGlobal );
1511 mismatch = dMassDiffPostGlobal;
1514 MB_CHK_SET_ERR( m_interface->tag_set_data( tgtSolutionTag, tents, &solTTagVals[0] ),
1515 "Setting local tag data failed" );
1523 const std::string& solnName,
1525 sample_function testFunction,
1527 std::string cloneSolnName )
1530 const bool outputEnabled = ( is_root );
1540 trmesh = m_remapper->m_covering_source;
1541 entities = ( m_remapper->point_cloud_source ? m_remapper->m_covering_source_vertices
1542 : m_remapper->m_covering_source_entities );
1543 discOrder = m_nDofsPEl_Src;
1544 discMethod = m_eInputType;
1549 trmesh = m_remapper->m_target;
1551 ( m_remapper->point_cloud_target ? m_remapper->m_target_vertices : m_remapper->m_target_entities );
1552 discOrder = m_nDofsPEl_Dest;
1553 discMethod = m_eOutputType;
1558 std::cout <<
"Invalid context specified for defining an analytical solution tag" << std::endl;
1559 return moab::MB_FAILURE;
1564 rval = m_interface->tag_get_handle( solnName.c_str(), discOrder * discOrder,
MB_TYPE_DOUBLE, solnTag,
1566 if( clonedSolnTag !=
nullptr )
1568 if( cloneSolnName.size() == 0 )
1570 cloneSolnName = solnName + std::string(
"Cloned" );
1572 rval = m_interface->tag_get_handle( cloneSolnName.c_str(), discOrder * discOrder,
MB_TYPE_DOUBLE,
1577 const int TriQuadratureOrder = 10;
1579 if( outputEnabled ) std::cout <<
"Using triangular quadrature of order " << TriQuadratureOrder << std::endl;
1581 TriangularQuadratureRule triquadrule( TriQuadratureOrder );
1583 const int TriQuadraturePoints = triquadrule.GetPoints();
1585 const DataArray2D< double >& TriQuadratureG = triquadrule.GetG();
1586 const DataArray1D< double >& TriQuadratureW = triquadrule.GetW();
1589 DataArray1D< double > dVar;
1590 DataArray1D< double > dVarMB;
1593 DataArray1D< double > dNodeArea;
1598 if( discMethod == DiscretizationType_CGLL || discMethod == DiscretizationType_DGLL )
1601 const bool fGLL =
true;
1602 const bool fGLLIntegrate =
false;
1605 DataArray3D< int > dataGLLNodes;
1606 DataArray3D< double > dataGLLJacobian;
1608 GenerateMetaData( *trmesh, discOrder,
false, dataGLLNodes, dataGLLJacobian );
1611 int nElements = trmesh->faces.size();
1614 for(
int k = 0; k < nElements; k++ )
1616 const Face&
face = trmesh->faces[k];
1618 if(
face.edges.size() != 4 )
1620 _EXCEPTIONT(
"Non-quadrilateral face detected; "
1621 "incompatible with --gll" );
1627 for(
int i = 0; i < discOrder; i++ )
1629 for(
int j = 0; j < discOrder; j++ )
1631 for(
int k = 0; k < nElements; k++ )
1633 if( dataGLLNodes[i][j][k] > iMaxNode )
1635 iMaxNode = dataGLLNodes[i][j][k];
1642 DataArray1D< double > dG;
1643 DataArray1D< double > dW;
1645 GaussLobattoQuadrature::GetPoints( discOrder, 0.0, 1.0, dG, dW );
1648 const int nGaussP = 10;
1650 DataArray1D< double > dGaussG;
1651 DataArray1D< double > dGaussW;
1653 GaussQuadrature::GetPoints( nGaussP, 0.0, 1.0, dGaussG, dGaussW );
1656 dVar.Allocate( iMaxNode );
1657 dVarMB.Allocate( discOrder * discOrder * nElements );
1658 dNodeArea.Allocate( iMaxNode );
1661 for(
int k = 0; k < nElements; k++ )
1663 const Face&
face = trmesh->faces[k];
1668 for(
int i = 0; i < discOrder; i++ )
1670 for(
int j = 0; j < discOrder; j++ )
1678 ApplyLocalMap(
face, trmesh->nodes, dG[i], dG[j], node, dDx1G, dDx2G );
1681 double dNodeLon = atan2( node.y, node.x );
1682 if( dNodeLon < 0.0 )
1684 dNodeLon += 2.0 * M_PI;
1686 double dNodeLat = asin( node.z );
1688 double dSample = ( *testFunction )( dNodeLon, dNodeLat );
1690 dVar[dataGLLNodes[j][i][k] - 1] = dSample;
1697 DataArray2D< double > dCoeff( discOrder, discOrder );
1699 for(
int p = 0; p < nGaussP; p++ )
1701 for(
int q = 0; q < nGaussP; q++ )
1709 ApplyLocalMap(
face, trmesh->nodes, dGaussG[p], dGaussG[q], node, dDx1G, dDx2G );
1712 Node nodeCross = CrossProduct( dDx1G, dDx2G );
1715 sqrt( nodeCross.x * nodeCross.x + nodeCross.y * nodeCross.y + nodeCross.z * nodeCross.z );
1719 SampleGLLFiniteElement( 0, discOrder, dGaussG[p], dGaussG[q], dCoeff );
1722 double dNodeLon = atan2( node.y, node.x );
1723 if( dNodeLon < 0.0 )
1725 dNodeLon += 2.0 * M_PI;
1727 double dNodeLat = asin( node.z );
1729 double dSample = ( *testFunction )( dNodeLon, dNodeLat );
1732 for(
int i = 0; i < discOrder; i++ )
1734 for(
int j = 0; j < discOrder; j++ )
1737 double dNodalArea = dCoeff[i][j] * dGaussW[p] * dGaussW[q] * dJacobian;
1739 dVar[dataGLLNodes[i][j][k] - 1] += dSample * dNodalArea;
1741 dNodeArea[dataGLLNodes[i][j][k] - 1] += dNodalArea;
1752 for(
size_t i = 0; i < dVar.GetRows(); i++ )
1754 dVar[i] /= dNodeArea[i];
1761 for(
unsigned j = 0; j <
entities.size(); j++ )
1762 for(
int p = 0; p < discOrder; p++ )
1763 for(
int q = 0; q < discOrder; q++ )
1765 const int offsetDOF = j * discOrder * discOrder + p * discOrder + q;
1766 dVarMB[offsetDOF] = dVar[col_dtoc_dofmap[offsetDOF]];
1771 for(
unsigned j = 0; j <
entities.size(); j++ )
1772 for(
int p = 0; p < discOrder; p++ )
1773 for(
int q = 0; q < discOrder; q++ )
1775 const int offsetDOF = j * discOrder * discOrder + p * discOrder + q;
1776 dVarMB[offsetDOF] = dVar[row_dtoc_dofmap[offsetDOF]];
1781 rval = m_interface->tag_set_data( solnTag,
entities, &dVarMB[0] );
MB_CHK_ERR( rval );
1786 if( discMethod == DiscretizationType_FV )
1791 dVar.Allocate( trmesh->faces.size() );
1793 std::vector< Node >& nodes = trmesh->nodes;
1796 for(
size_t i = 0; i < trmesh->faces.size(); i++ )
1798 const Face&
face = trmesh->faces[i];
1801 for(
size_t j = 0; j <
face.edges.size() - 2; j++ )
1804 const Node& node0 = nodes[
face[0]];
1805 const Node& node1 = nodes[
face[j + 1]];
1806 const Node& node2 = nodes[
face[j + 2]];
1810 faceTri.SetNode( 0,
face[0] );
1811 faceTri.SetNode( 1,
face[j + 1] );
1812 faceTri.SetNode( 2,
face[j + 2] );
1814 double dTriangleArea = CalculateFaceArea( faceTri, nodes );
1817 double dTotalSample = 0.0;
1820 for(
int k = 0; k < TriQuadraturePoints; k++ )
1822 Node node( TriQuadratureG[k][0] * node0.x + TriQuadratureG[k][1] * node1.x +
1823 TriQuadratureG[k][2] * node2.x,
1824 TriQuadratureG[k][0] * node0.y + TriQuadratureG[k][1] * node1.y +
1825 TriQuadratureG[k][2] * node2.y,
1826 TriQuadratureG[k][0] * node0.z + TriQuadratureG[k][1] * node1.z +
1827 TriQuadratureG[k][2] * node2.z );
1829 double dMagnitude = node.Magnitude();
1830 node.x /= dMagnitude;
1831 node.y /= dMagnitude;
1832 node.z /= dMagnitude;
1834 double dLon = atan2( node.y, node.x );
1839 double dLat = asin( node.z );
1841 double dSample = ( *testFunction )( dLon, dLat );
1843 dTotalSample += dSample * TriQuadratureW[k] * dTriangleArea;
1846 dVar[i] += dTotalSample / trmesh->vecFaceArea[i];
1854 std::vector< Node >& nodes = trmesh->nodes;
1857 dVar.Allocate( nodes.size() );
1859 for(
size_t j = 0; j < nodes.size(); j++ )
1861 Node& node = nodes[j];
1862 double dMagnitude = node.Magnitude();
1863 node.x /= dMagnitude;
1864 node.y /= dMagnitude;
1865 node.z /= dMagnitude;
1866 double dLon = atan2( node.y, node.x );
1871 double dLat = asin( node.z );
1873 double dSample = ( *testFunction )( dLon, dLat );
1887 std::map< std::string, double >& metrics,
1891 const bool outputEnabled = ( is_root );
1902 entities = ( m_remapper->point_cloud_source ? m_remapper->m_covering_source_vertices
1903 : m_remapper->m_covering_source_entities );
1904 discOrder = m_nDofsPEl_Src;
1912 ( m_remapper->point_cloud_target ? m_remapper->m_target_vertices : m_remapper->m_target_entities );
1913 discOrder = m_nDofsPEl_Dest;
1919 std::cout <<
"Invalid context specified for defining an analytical solution tag" << std::endl;
1920 return moab::MB_FAILURE;
1925 std::string exactTagName, projTagName;
1926 const int ntotsize =
entities.size() * discOrder * discOrder;
1927 std::vector< double > exactSolution( ntotsize, 0.0 ), projSolution( ntotsize, 0.0 );
1928 rval = m_interface->tag_get_name( exactTag, exactTagName );
MB_CHK_ERR( rval );
1929 rval = m_interface->tag_get_data( exactTag,
entities, &exactSolution[0] );
MB_CHK_ERR( rval );
1930 rval = m_interface->tag_get_name( approxTag, projTagName );
MB_CHK_ERR( rval );
1931 rval = m_interface->tag_get_data( approxTag,
entities, &projSolution[0] );
MB_CHK_ERR( rval );
1933 const auto& ovents = m_remapper->m_overlap_entities;
1935 std::vector< double > errnorms( 4, 0.0 ), globerrnorms( 4, 0.0 );
1936 double sumarea = 0.0;
1937 for(
size_t i = 0; i < ovents.size(); ++i )
1939 const int srcidx = m_remapper->m_overlap->vecSourceFaceIx[i];
1940 if( srcidx < 0 )
continue;
1941 const int tgtidx = m_remapper->m_overlap->vecTargetFaceIx[i];
1942 if( tgtidx < 0 )
continue;
1943 const double ovarea = m_remapper->m_overlap->vecFaceArea[i];
1944 const double error = fabs( exactSolution[tgtidx] - projSolution[tgtidx] );
1945 errnorms[0] += ovarea *
error;
1947 errnorms[3] = (
error > errnorms[3] ?
error : errnorms[3] );
1950 errnorms[2] = sumarea;
1951 #ifdef MOAB_HAVE_MPI
1954 MPI_Reduce( &errnorms[0], &globerrnorms[0], 3, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
1955 MPI_Reduce( &errnorms[3], &globerrnorms[3], 1, MPI_DOUBLE, MPI_MAX, 0, m_pcomm->comm() );
1958 for(
int i = 0; i < 4; ++i )
1959 globerrnorms[i] = errnorms[i];
1962 globerrnorms[0] = ( globerrnorms[0] / globerrnorms[2] );
1963 globerrnorms[1] = std::sqrt( globerrnorms[1] / globerrnorms[2] );
1966 metrics[
"L1Error"] = globerrnorms[0];
1967 metrics[
"L2Error"] = globerrnorms[1];
1968 metrics[
"LinfError"] = globerrnorms[3];
1972 std::cout <<
"Error metrics when comparing " << projTagName <<
" against " << exactTagName << std::endl;
1973 std::cout <<
"\t Total Intersection area = " << globerrnorms[2] << std::endl;
1974 std::cout <<
"\t L_1 error = " << globerrnorms[0] << std::endl;
1975 std::cout <<
"\t L_2 error = " << globerrnorms[1] << std::endl;
1976 std::cout <<
"\t L_inf error = " << globerrnorms[3] << std::endl;