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"
42 #ifdef MOAB_HAVE_NETCDFPAR
45 #include "netcdfcpp.h"
58 #define MPI_CHK_ERR( err ) \
61 std::cout << "MPI Failure. ErrorCode (" << ( err ) << ") "; \
62 std::cout << "\nMPI Aborting... \n"; \
63 return moab::MB_FAILURE; \
71 m_pcomm =
m_remapper->get_parallel_communicator();
99 std::vector< std::string > dimNames;
100 std::vector< int > dimSizes;
101 dimNames.push_back(
"num_elem" );
102 dimSizes.push_back( m_meshInputCov->faces.size() );
104 this->InitializeSourceDimensions( dimNames, dimSizes );
109 std::vector< std::string > dimNames;
110 std::vector< int > dimSizes;
111 dimNames.push_back(
"num_elem" );
112 dimSizes.push_back( m_meshOutput->faces.size() );
114 this->InitializeTargetDimensions( dimNames, dimSizes );
122 m_interface =
nullptr;
126 m_meshInput =
nullptr;
127 m_meshOutput =
nullptr;
128 m_meshOverlap =
nullptr;
134 const std::string tgtDofTagName )
139 tagSize = ( m_eInputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Src * m_nDofsPEl_Src );
145 MB_CHK_SET_ERR( MB_FAILURE,
"DoF tag is not set correctly for source mesh." );
150 tagSize = ( m_eOutputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Dest * m_nDofsPEl_Dest );
155 MB_CHK_SET_ERR( MB_FAILURE,
"DoF tag is not set correctly for target mesh." );
167 bool isSrcContinuous,
168 DataArray3D< int >* srcdataGLLNodes,
169 DataArray3D< int >* srcdataGLLNodesSrc,
172 bool isTgtContinuous,
173 DataArray3D< int >* tgtdataGLLNodes )
175 std::vector< bool > dgll_cgll_row_ldofmap, dgll_cgll_col_ldofmap, dgll_cgll_covcol_ldofmap;
176 std::vector< int > src_soln_gdofs, locsrc_soln_gdofs, tgt_soln_gdofs;
179 m_srcDiscType = srcType;
180 m_destDiscType = destType;
181 m_input_order = srcOrder;
182 m_output_order = destOrder;
184 bool vprint = is_root &&
false;
189 int srcTagSize = ( m_eInputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Src * m_nDofsPEl_Src );
190 if( m_remapper->point_cloud_source )
192 assert( m_nDofsPEl_Src == 1 );
193 col_gdofmap.resize( m_remapper->m_covering_source_vertices.size(), UINT_MAX );
194 col_dtoc_dofmap.resize( m_remapper->m_covering_source_vertices.size(), -1 );
195 src_soln_gdofs.resize( m_remapper->m_covering_source_vertices.size(), -1 );
197 m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_covering_source_vertices, &src_soln_gdofs[0] ) );
202 col_gdofmap.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, UINT_MAX );
203 col_dtoc_dofmap.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, -1 );
204 src_soln_gdofs.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, -1 );
206 m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_covering_source_entities, &src_soln_gdofs[0] ) );
209 m_nTotDofs_SrcCov = 0;
210 if( srcdataGLLNodes ==
nullptr )
213 for(
unsigned i = 0; i < col_gdofmap.size(); ++i )
215 auto gdof = src_soln_gdofs[i];
217 col_gdofmap[i] = gdof - 1;
218 col_dtoc_dofmap[i] = i;
219 if( vprint ) std::cout <<
"Col: " << i <<
", " << col_gdofmap[i] <<
"\n";
225 if( isSrcContinuous )
226 dgll_cgll_covcol_ldofmap.resize( m_remapper->m_covering_source_entities.size() * srcTagSize,
false );
228 for(
unsigned j = 0; j < m_remapper->m_covering_source_entities.size(); j++ )
230 for(
int p = 0; p < m_nDofsPEl_Src; p++ )
232 for(
int q = 0; q < m_nDofsPEl_Src; q++ )
234 const int localDOF = ( *srcdataGLLNodes )[p][q][j] - 1;
235 const int offsetDOF = j * srcTagSize + p * m_nDofsPEl_Src + q;
236 if( isSrcContinuous && !dgll_cgll_covcol_ldofmap[localDOF] )
239 dgll_cgll_covcol_ldofmap[localDOF] =
true;
241 if( !isSrcContinuous ) m_nTotDofs_SrcCov++;
242 assert( src_soln_gdofs[offsetDOF] > 0 );
243 col_gdofmap[localDOF] = src_soln_gdofs[offsetDOF] - 1;
244 col_dtoc_dofmap[offsetDOF] = localDOF;
246 std::cout <<
"Col: " << offsetDOF <<
", " << localDOF <<
", " << col_gdofmap[offsetDOF] <<
", "
247 << m_nTotDofs_SrcCov <<
"\n";
253 if( m_remapper->point_cloud_source )
255 assert( m_nDofsPEl_Src == 1 );
256 srccol_gdofmap.resize( m_remapper->m_source_vertices.size(), UINT_MAX );
257 srccol_dtoc_dofmap.resize( m_remapper->m_covering_source_vertices.size(), -1 );
258 locsrc_soln_gdofs.resize( m_remapper->m_source_vertices.size(), -1 );
259 MB_CHK_ERR( m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_source_vertices, &locsrc_soln_gdofs[0] ) );
263 srccol_gdofmap.resize( m_remapper->m_source_entities.size() * srcTagSize, UINT_MAX );
264 srccol_dtoc_dofmap.resize( m_remapper->m_source_entities.size() * srcTagSize, -1 );
265 locsrc_soln_gdofs.resize( m_remapper->m_source_entities.size() * srcTagSize, -1 );
266 MB_CHK_ERR( m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_source_entities, &locsrc_soln_gdofs[0] ) );
271 if( srcdataGLLNodesSrc ==
nullptr )
274 for(
unsigned i = 0; i < srccol_gdofmap.size(); ++i )
276 auto gdof = locsrc_soln_gdofs[i];
278 srccol_gdofmap[i] = gdof - 1;
279 srccol_dtoc_dofmap[i] = i;
285 if( isSrcContinuous ) dgll_cgll_col_ldofmap.resize( m_remapper->m_source_entities.size() * srcTagSize,
false );
287 for(
unsigned j = 0; j < m_remapper->m_source_entities.size(); j++ )
289 for(
int p = 0; p < m_nDofsPEl_Src; p++ )
291 for(
int q = 0; q < m_nDofsPEl_Src; q++ )
293 const int localDOF = ( *srcdataGLLNodesSrc )[p][q][j] - 1;
294 const int offsetDOF = j * srcTagSize + p * m_nDofsPEl_Src + q;
295 if( isSrcContinuous && !dgll_cgll_col_ldofmap[localDOF] )
298 dgll_cgll_col_ldofmap[localDOF] =
true;
300 if( !isSrcContinuous ) m_nTotDofs_Src++;
301 assert( locsrc_soln_gdofs[offsetDOF] > 0 );
302 srccol_gdofmap[localDOF] = locsrc_soln_gdofs[offsetDOF] - 1;
303 srccol_dtoc_dofmap[offsetDOF] = localDOF;
309 int tgtTagSize = ( m_eOutputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Dest * m_nDofsPEl_Dest );
310 if( m_remapper->point_cloud_target )
312 assert( m_nDofsPEl_Dest == 1 );
313 row_gdofmap.resize( m_remapper->m_target_vertices.size(), UINT_MAX );
314 row_dtoc_dofmap.resize( m_remapper->m_target_vertices.size(), -1 );
315 tgt_soln_gdofs.resize( m_remapper->m_target_vertices.size(), -1 );
316 MB_CHK_ERR( m_interface->tag_get_data( m_dofTagDest, m_remapper->m_target_vertices, &tgt_soln_gdofs[0] ) );
321 row_gdofmap.resize( m_remapper->m_target_entities.size() * tgtTagSize, UINT_MAX );
322 row_dtoc_dofmap.resize( m_remapper->m_target_entities.size() * tgtTagSize, -1 );
323 tgt_soln_gdofs.resize( m_remapper->m_target_entities.size() * tgtTagSize, -1 );
324 MB_CHK_ERR( m_interface->tag_get_data( m_dofTagDest, m_remapper->m_target_entities, &tgt_soln_gdofs[0] ) );
330 if( tgtdataGLLNodes ==
nullptr )
333 for(
unsigned i = 0; i < row_gdofmap.size(); ++i )
335 auto gdof = tgt_soln_gdofs[i];
337 row_gdofmap[i] = gdof - 1;
338 row_dtoc_dofmap[i] = i;
339 if( vprint ) std::cout <<
"Row: " << i <<
", " << row_gdofmap[i] <<
"\n";
345 if( isTgtContinuous ) dgll_cgll_row_ldofmap.resize( m_remapper->m_target_entities.size() * tgtTagSize,
false );
347 for(
unsigned j = 0; j < m_remapper->m_target_entities.size(); j++ )
349 for(
int p = 0; p < m_nDofsPEl_Dest; p++ )
351 for(
int q = 0; q < m_nDofsPEl_Dest; q++ )
353 const int localDOF = ( *tgtdataGLLNodes )[p][q][j] - 1;
354 const int offsetDOF = j * tgtTagSize + p * m_nDofsPEl_Dest + q;
355 if( isTgtContinuous && !dgll_cgll_row_ldofmap[localDOF] )
358 dgll_cgll_row_ldofmap[localDOF] =
true;
360 if( !isTgtContinuous ) m_nTotDofs_Dest++;
361 assert( tgt_soln_gdofs[offsetDOF] > 0 );
362 row_gdofmap[localDOF] = tgt_soln_gdofs[offsetDOF] - 1;
363 row_dtoc_dofmap[offsetDOF] = localDOF;
365 std::cout <<
"Row: " << offsetDOF <<
", " << localDOF <<
", " << row_gdofmap[offsetDOF] <<
", "
366 << m_nTotDofs_Dest <<
"\n";
373 #if defined( MOAB_HAVE_EIGEN3 ) && defined( VERBOSE )
376 std::cout <<
"[" << rank <<
"]" <<
"DoFs: row = " << m_nTotDofs_Dest <<
", " << row_gdofmap.size()
377 <<
", col = " << m_nTotDofs_Src <<
", " << m_nTotDofs_SrcCov <<
", " << col_gdofmap.size() <<
"\n";
383 #ifdef CHECK_INCREASING_DOF
384 for(
size_t i = 0; i < row_gdofmap.size() - 1; i++ )
386 if( row_gdofmap[i] > row_gdofmap[i + 1] )
387 std::cout <<
" on rank " << rank <<
" in row_gdofmap[" << i <<
"]=" << row_gdofmap[i] <<
" > row_gdofmap["
388 << i + 1 <<
"]=" << row_gdofmap[i + 1] <<
" \n";
390 for(
size_t i = 0; i < col_gdofmap.size() - 1; i++ )
392 if( col_gdofmap[i] > col_gdofmap[i + 1] )
393 std::cout <<
" on rank " << rank <<
" in col_gdofmap[" << i <<
"]=" << col_gdofmap[i] <<
" > col_gdofmap["
394 << i + 1 <<
"]=" << col_gdofmap[i + 1] <<
" \n";
410 col_dtoc_dofmap.resize( values_entities.size(), -1 );
411 for(
size_t j = 0; j < values_entities.size(); j++ )
414 const auto it = colMap.find( values_entities[j] - 1 );
415 if( it != colMap.end() ) col_dtoc_dofmap[j] = it->second;
424 row_dtoc_dofmap.resize( values_entities.size(), -1 );
425 for(
size_t j = 0; j < values_entities.size(); j++ )
428 const auto it = rowMap.find( values_entities[j] - 1 );
429 if( it != rowMap.end() ) row_dtoc_dofmap[j] = it->second;
436 std::string strOutputType,
437 const GenerateOfflineMapAlgorithmOptions& mapOptions,
438 const std::string& srcDofTagName,
439 const std::string& tgtDofTagName )
441 NcError
error( NcError::silent_nonfatal );
444 dbgprint.set_prefix(
"[TempestOnlineMap]: " );
447 const bool m_bPointCloudSource = ( m_remapper->point_cloud_source );
448 const bool m_bPointCloudTarget = ( m_remapper->point_cloud_target );
449 const bool m_bPointCloud = m_bPointCloudSource || m_bPointCloudTarget;
458 STLStringHelper::ToLower( strInputType );
459 STLStringHelper::ToLower( strOutputType );
464 if( strInputType ==
"fv" )
466 eInputType = DiscretizationType_FV;
468 else if( strInputType ==
"cgll" )
470 eInputType = DiscretizationType_CGLL;
472 else if( strInputType ==
"dgll" )
474 eInputType = DiscretizationType_DGLL;
476 else if( strInputType ==
"pcloud" )
478 eInputType = DiscretizationType_PCLOUD;
482 _EXCEPTION1(
"Invalid \"in_type\" value (%s), expected [fv|cgll|dgll]", strInputType.c_str() );
485 if( strOutputType ==
"fv" )
487 eOutputType = DiscretizationType_FV;
489 else if( strOutputType ==
"cgll" )
491 eOutputType = DiscretizationType_CGLL;
493 else if( strOutputType ==
"dgll" )
495 eOutputType = DiscretizationType_DGLL;
497 else if( strOutputType ==
"pcloud" )
499 eOutputType = DiscretizationType_PCLOUD;
503 _EXCEPTION1(
"Invalid \"out_type\" value (%s), expected [fv|cgll|dgll]", strOutputType.c_str() );
507 m_bConserved = !mapOptions.fNoConservation;
508 m_eInputType = eInputType;
509 m_eOutputType = eOutputType;
512 std::string strMapAlgorithm(
"" );
513 int nMonotoneType = ( mapOptions.fMonotone ) ? ( 1 ) : ( 0 );
516 std::set< std::string > setMethodStrings;
519 for(
size_t i = 0; i <= mapOptions.strMethod.length(); i++ )
521 if( ( i == mapOptions.strMethod.length() ) || ( mapOptions.strMethod[i] ==
';' ) )
523 std::string strMethodString = mapOptions.strMethod.substr( iLast, i - iLast );
524 STLStringHelper::RemoveWhitespaceInPlace( strMethodString );
525 if( strMethodString.length() > 0 )
527 setMethodStrings.insert( strMethodString );
534 for(
auto it : setMethodStrings )
539 if( nMonotoneType != 0 )
541 _EXCEPTIONT(
"Multiple monotonicity specifications found (--mono) or (--method \"mono#\")" );
543 if( ( m_eInputType == DiscretizationType_FV ) && ( m_eOutputType == DiscretizationType_FV ) )
545 _EXCEPTIONT(
"--method \"mono2\" is only used when remapping to/from CGLL or DGLL grids" );
551 else if( it ==
"mono3" )
553 if( nMonotoneType != 0 )
555 _EXCEPTIONT(
"Multiple monotonicity specifications found (--mono) or (--method \"mono#\")" );
557 if( ( m_eInputType == DiscretizationType_FV ) && ( m_eOutputType == DiscretizationType_FV ) )
559 _EXCEPTIONT(
"--method \"mono3\" is only used when remapping to/from CGLL or DGLL grids" );
565 else if( it ==
"volumetric" )
567 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType == DiscretizationType_FV ) )
569 _EXCEPTIONT(
"--method \"volumetric\" may only be used for FV->CGLL or FV->DGLL remapping" );
571 strMapAlgorithm =
"volumetric";
575 else if( it ==
"invdist" )
577 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
579 _EXCEPTIONT(
"--method \"invdist\" may only be used for FV->FV remapping" );
581 strMapAlgorithm =
"invdist";
585 else if( it ==
"delaunay" )
587 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
589 _EXCEPTIONT(
"--method \"delaunay\" may only be used for FV->FV remapping" );
591 strMapAlgorithm =
"delaunay";
595 else if( it ==
"bilin" )
597 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
599 _EXCEPTIONT(
"--method \"bilin\" may only be used for FV->FV remapping" );
601 strMapAlgorithm =
"fvbilin";
605 else if( it ==
"intbilin" )
607 if( m_eOutputType != DiscretizationType_FV )
609 _EXCEPTIONT(
"--method \"intbilin\" may only be used when mapping to FV." );
611 if( m_eInputType == DiscretizationType_FV )
613 strMapAlgorithm =
"fvintbilin";
617 strMapAlgorithm =
"mono3";
622 else if( it ==
"intbilingb" )
624 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
626 _EXCEPTIONT(
"--method \"intbilingb\" may only be used for FV->FV remapping" );
628 strMapAlgorithm =
"fvintbilingb";
632 _EXCEPTION1(
"Invalid --method argument \"%s\"", it.c_str() );
637 ( m_eInputType == DiscretizationType_FV || m_eInputType == DiscretizationType_PCLOUD ? 1
640 ( m_eOutputType == DiscretizationType_FV || m_eOutputType == DiscretizationType_PCLOUD ? 1
641 : mapOptions.nPout );
644 MB_CHK_ERR( SetDOFmapTags( srcDofTagName, tgtDofTagName ) );
648 rval = m_interface->tag_get_handle(
"aream", 1,
MB_TYPE_DOUBLE, areaTag,
652 if( is_root )
dbgprint.printf( 0,
"aream tag already defined \n" );
655 double local_areas[3] = { 0.0, 0.0, 0.0 }, global_areas[3] = { 0.0, 0.0, 0.0 };
656 if( !m_bPointCloudSource )
659 if( is_root )
dbgprint.printf( 0,
"Calculating input mesh Face areas\n" );
660 local_areas[0] = m_meshInput->CalculateFaceAreas( mapOptions.fSourceConcave );
662 MB_CHK_ERR( m_interface->tag_set_data( areaTag, m_remapper->m_source_entities, m_meshInput->vecFaceArea ) );
665 m_meshInputCov->CalculateFaceAreas( mapOptions.fSourceConcave );
668 if( !m_bPointCloudTarget )
671 if( is_root )
dbgprint.printf( 0,
"Calculating output mesh Face areas\n" );
672 local_areas[1] = m_meshOutput->CalculateFaceAreas( mapOptions.fTargetConcave );
675 m_interface->tag_set_data( areaTag, m_remapper->m_target_entities, m_meshOutput->vecFaceArea ) );
681 assert( m_meshOverlap->vecSourceFaceIx.size() == m_meshOverlap->vecTargetFaceIx.size() );
684 if( is_root )
dbgprint.printf( 0,
"Calculating overlap mesh Face areas\n" );
686 m_meshOverlap->CalculateFaceAreas( mapOptions.fSourceConcave || mapOptions.fTargetConcave );
689 std::copy( local_areas, local_areas + 3, global_areas );
692 if( m_pcomm && is_parallel )
693 MPI_Reduce( local_areas, global_areas, 3, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
697 dbgprint.printf( 0,
"Input Mesh Geometric Area: %1.15e\n", global_areas[0] );
698 dbgprint.printf( 0,
"Output Mesh Geometric Area: %1.15e\n", global_areas[1] );
699 dbgprint.printf( 0,
"Overlap Mesh Recovered Area: %1.15e\n", global_areas[2] );
703 constexpr
bool fCorrectAreas =
true;
706 if( is_root )
dbgprint.printf( 0,
"Correcting source/target areas to overlap mesh areas\n" );
707 DataArray1D< double > dSourceArea( m_meshInputCov->faces.size() );
708 DataArray1D< double > dTargetArea( m_meshOutput->faces.size() );
710 assert( m_meshOverlap->vecSourceFaceIx.size() == m_meshOverlap->faces.size() );
711 assert( m_meshOverlap->vecTargetFaceIx.size() == m_meshOverlap->faces.size() );
712 assert( m_meshOverlap->vecFaceArea.GetRows() == m_meshOverlap->faces.size() );
714 assert( m_meshInputCov->vecFaceArea.GetRows() == m_meshInputCov->faces.size() );
715 assert( m_meshOutput->vecFaceArea.GetRows() == m_meshOutput->faces.size() );
717 for(
size_t i = 0; i < m_meshOverlap->faces.size(); i++ )
719 if( m_meshOverlap->vecSourceFaceIx[i] < 0 || m_meshOverlap->vecTargetFaceIx[i] < 0 )
723 assert(
static_cast< size_t >( m_meshOverlap->vecSourceFaceIx[i] ) < m_meshInputCov->faces.size() );
724 dSourceArea[m_meshOverlap->vecSourceFaceIx[i]] += m_meshOverlap->vecFaceArea[i];
725 assert(
static_cast< size_t >( m_meshOverlap->vecTargetFaceIx[i] ) < m_meshOutput->faces.size() );
726 dTargetArea[m_meshOverlap->vecTargetFaceIx[i]] += m_meshOverlap->vecFaceArea[i];
729 for(
size_t i = 0; i < m_meshInputCov->faces.size(); i++ )
731 if( fabs( dSourceArea[i] - m_meshInputCov->vecFaceArea[i] ) < 1.0e-10 )
733 m_meshInputCov->vecFaceArea[i] = dSourceArea[i];
736 for(
size_t i = 0; i < m_meshOutput->faces.size(); i++ )
738 if( fabs( dTargetArea[i] - m_meshOutput->vecFaceArea[i] ) < 1.0e-10 )
740 m_meshOutput->vecFaceArea[i] = dTargetArea[i];
746 if( !m_bPointCloudSource && eInputType == DiscretizationType_FV )
748 this->SetSourceAreas( m_meshInputCov->vecFaceArea );
749 if( m_meshInputCov->vecMask.size() )
751 this->SetSourceMask( m_meshInputCov->vecMask );
756 if( !m_bPointCloudTarget && eOutputType == DiscretizationType_FV )
758 this->SetTargetAreas( m_meshOutput->vecFaceArea );
759 if( m_meshOutput->vecMask.size() )
761 this->SetTargetMask( m_meshOutput->vecMask );
777 if( ( eInputType == DiscretizationType_FV ) && ( eOutputType == DiscretizationType_FV ) )
780 if( m_meshInputCov->revnodearray.size() == 0 ) m_meshInputCov->ConstructReverseNodeArray();
781 if( m_meshInputCov->edgemap.size() == 0 ) m_meshInputCov->ConstructEdgeMap(
false );
784 this->InitializeSourceCoordinatesFromMeshFV( *m_meshInputCov );
785 this->InitializeTargetCoordinatesFromMeshFV( *m_meshOutput );
787 this->m_pdataGLLNodesIn =
nullptr;
788 this->m_pdataGLLNodesOut =
nullptr;
791 MB_CHK_ERR( this->SetDOFmapAssociation( eInputType, mapOptions.nPin,
false,
nullptr,
nullptr, eOutputType,
792 mapOptions.nPout,
false,
nullptr ) );
795 if( is_root )
dbgprint.printf( 0,
"Calculating remap weights\n" );
798 if( strMapAlgorithm ==
"invdist" )
800 if( is_root )
dbgprint.printf( 0,
"Calculating map (invdist)\n" );
801 if( m_meshInputCov->faces.size() )
802 LinearRemapFVtoFVInvDist( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *
this );
804 else if( strMapAlgorithm ==
"delaunay" )
806 if( is_root )
dbgprint.printf( 0,
"Calculating map (delaunay)\n" );
807 if( m_meshInputCov->faces.size() )
808 LinearRemapTriangulation( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *
this );
810 else if( strMapAlgorithm ==
"fvintbilin" )
812 if( is_root )
dbgprint.printf( 0,
"Calculating map (intbilin)\n" );
813 if( m_meshInputCov->faces.size() )
814 LinearRemapIntegratedBilinear( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *
this );
816 else if( strMapAlgorithm ==
"fvintbilingb" )
818 if( is_root )
dbgprint.printf( 0,
"Calculating map (intbilingb)\n" );
819 if( m_meshInputCov->faces.size() )
820 LinearRemapIntegratedGeneralizedBarycentric( *m_meshInputCov, *m_meshOutput, *m_meshOverlap,
823 else if( strMapAlgorithm ==
"fvbilin" )
828 m_meshInputCov->Write(
"SourceMeshMBTR.g" );
829 m_meshOutput->Write(
"TargetMeshMBTR.g" );
833 m_meshInputCov->Write(
"SourceMeshMBTR" + std::to_string( rank ) +
".g" );
834 m_meshOutput->Write(
"TargetMeshMBTR" + std::to_string( rank ) +
".g" );
837 if( is_root )
dbgprint.printf( 0,
"Calculating map (bilin)\n" );
838 if( m_meshInputCov->faces.size() )
839 LinearRemapBilinear( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *
this );
843 if( is_root )
dbgprint.printf( 0,
"Calculating conservative FV-FV map\n" );
844 if( m_meshInputCov->faces.size() )
846 #ifdef USE_NATIVE_TEMPESTREMAP_ROUTINES
847 LinearRemapFVtoFV( *m_meshInputCov, *m_meshOutput, *m_meshOverlap,
848 ( mapOptions.fMonotone ) ? ( 1 ) : ( mapOptions.nPin ), *
this );
850 LinearRemapFVtoFV_Tempest_MOAB( ( mapOptions.fMonotone ? 1 : mapOptions.nPin ) );
855 else if( eInputType == DiscretizationType_FV )
857 DataArray3D< double > dataGLLJacobian;
859 if( is_root )
dbgprint.printf( 0,
"Generating output mesh meta data\n" );
860 double dNumericalArea_loc = GenerateMetaData( *m_meshOutput, mapOptions.nPout, mapOptions.fNoBubble,
861 dataGLLNodesDest, dataGLLJacobian );
863 double dNumericalArea = dNumericalArea_loc;
866 MPI_Reduce( &dNumericalArea_loc, &dNumericalArea, 1, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
868 if( is_root )
dbgprint.printf( 0,
"Output Mesh Numerical Area: %1.15e\n", dNumericalArea );
871 this->InitializeSourceCoordinatesFromMeshFV( *m_meshInputCov );
872 this->InitializeTargetCoordinatesFromMeshFE( *m_meshOutput, mapOptions.nPout, dataGLLNodesDest );
874 this->m_pdataGLLNodesIn =
nullptr;
875 this->m_pdataGLLNodesOut = &dataGLLNodesDest;
878 bool fContinuous = ( eOutputType == DiscretizationType_CGLL );
880 if( eOutputType == DiscretizationType_CGLL )
882 GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobian, this->GetTargetAreas() );
886 GenerateDiscontinuousJacobian( dataGLLJacobian, this->GetTargetAreas() );
890 if( m_meshInputCov->revnodearray.size() == 0 ) m_meshInputCov->ConstructReverseNodeArray();
891 if( m_meshInputCov->edgemap.size() == 0 ) m_meshInputCov->ConstructEdgeMap(
false );
894 MB_CHK_ERR( this->SetDOFmapAssociation( eInputType, mapOptions.nPin,
false,
nullptr,
nullptr, eOutputType,
895 mapOptions.nPout, ( eOutputType == DiscretizationType_CGLL ),
896 &dataGLLNodesDest ) );
899 if( strMapAlgorithm ==
"volumetric" )
901 if( is_root )
dbgprint.printf( 0,
"Calculating remapping weights for FV->GLL (volumetric)\n" );
902 LinearRemapFVtoGLL_Volumetric( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesDest,
903 dataGLLJacobian, this->GetTargetAreas(), mapOptions.nPin, *
this,
904 nMonotoneType, fContinuous, mapOptions.fNoConservation );
908 if( is_root )
dbgprint.printf( 0,
"Calculating remapping weights for FV->GLL\n" );
909 LinearRemapFVtoGLL( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesDest, dataGLLJacobian,
910 this->GetTargetAreas(), mapOptions.nPin, *
this, nMonotoneType, fContinuous,
911 mapOptions.fNoConservation );
914 else if( ( eInputType == DiscretizationType_PCLOUD ) || ( eOutputType == DiscretizationType_PCLOUD ) )
916 DataArray3D< double > dataGLLJacobian;
917 if( !m_bPointCloudSource )
920 if( m_meshInputCov->revnodearray.size() == 0 ) m_meshInputCov->ConstructReverseNodeArray();
921 if( m_meshInputCov->edgemap.size() == 0 ) m_meshInputCov->ConstructEdgeMap(
false );
924 if( eInputType == DiscretizationType_FV )
926 this->InitializeSourceCoordinatesFromMeshFV( *m_meshInputCov );
930 if( is_root )
dbgprint.printf( 0,
"Generating input mesh meta data\n" );
931 DataArray3D< double > dataGLLJacobianSrc;
932 GenerateMetaData( *m_meshInputCov, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrcCov,
934 GenerateMetaData( *m_meshInput, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrc,
935 dataGLLJacobianSrc );
940 if( !m_bPointCloudTarget )
943 if( m_meshOutput->revnodearray.size() == 0 ) m_meshOutput->ConstructReverseNodeArray();
944 if( m_meshOutput->edgemap.size() == 0 ) m_meshOutput->ConstructEdgeMap(
false );
947 if( eOutputType == DiscretizationType_FV )
949 this->InitializeSourceCoordinatesFromMeshFV( *m_meshOutput );
953 if( is_root )
dbgprint.printf( 0,
"Generating output mesh meta data\n" );
954 GenerateMetaData( *m_meshOutput, mapOptions.nPout, mapOptions.fNoBubble, dataGLLNodesDest,
962 eInputType, mapOptions.nPin, ( eInputType == DiscretizationType_CGLL ),
963 ( m_bPointCloudSource || eInputType == DiscretizationType_FV ?
nullptr : &dataGLLNodesSrcCov ),
964 ( m_bPointCloudSource || eInputType == DiscretizationType_FV ?
nullptr : &dataGLLNodesSrc ),
965 eOutputType, mapOptions.nPout, ( eOutputType == DiscretizationType_CGLL ),
966 ( m_bPointCloudTarget ?
nullptr : &dataGLLNodesDest ) ) );
969 if( is_root )
dbgprint.printf( 0,
"Calculating remap weights with Nearest-Neighbor method\n" );
970 MB_CHK_ERR( LinearRemapNN_MOAB(
true ,
false ) );
972 else if( ( eInputType != DiscretizationType_FV ) && ( eOutputType == DiscretizationType_FV ) )
974 DataArray3D< double > dataGLLJacobianSrc, dataGLLJacobian;
976 if( is_root )
dbgprint.printf( 0,
"Generating input mesh meta data\n" );
978 GenerateMetaData( *m_meshInput, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrc,
979 dataGLLJacobianSrc );
980 GenerateMetaData( *m_meshInputCov, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrcCov,
983 if( dataGLLNodesSrcCov.GetSubColumns() != m_meshInputCov->faces.size() )
985 _EXCEPTIONT(
"Number of element does not match between metadata and "
990 this->InitializeSourceCoordinatesFromMeshFE( *m_meshInputCov, mapOptions.nPin, dataGLLNodesSrcCov );
991 this->InitializeTargetCoordinatesFromMeshFV( *m_meshOutput );
994 bool fContinuousIn = ( eInputType == DiscretizationType_CGLL );
996 if( eInputType == DiscretizationType_CGLL )
998 GenerateUniqueJacobian( dataGLLNodesSrcCov, dataGLLJacobian, this->GetSourceAreas() );
1002 GenerateDiscontinuousJacobian( dataGLLJacobian, this->GetSourceAreas() );
1006 MB_CHK_ERR( this->SetDOFmapAssociation( eInputType, mapOptions.nPin,
1007 ( eInputType == DiscretizationType_CGLL ), &dataGLLNodesSrcCov,
1008 &dataGLLNodesSrc, eOutputType, mapOptions.nPout,
false,
nullptr ) );
1011 if( is_root )
dbgprint.printf( 0,
"Calculating remap weights\n" );
1013 if( strMapAlgorithm ==
"volumetric" )
1015 _EXCEPTIONT(
"Unimplemented: Volumetric currently unavailable for"
1019 this->m_pdataGLLNodesIn = &dataGLLNodesSrcCov;
1020 this->m_pdataGLLNodesOut =
nullptr;
1022 #ifdef USE_NATIVE_TEMPESTREMAP_ROUTINES
1023 LinearRemapSE4( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesSrcCov, dataGLLJacobian,
1024 nMonotoneType, fContinuousIn, mapOptions.fNoConservation, mapOptions.fSparseConstraints,
1027 LinearRemapSE4_Tempest_MOAB( dataGLLNodesSrcCov, dataGLLJacobian, nMonotoneType, fContinuousIn,
1028 mapOptions.fNoConservation );
1031 else if( ( eInputType != DiscretizationType_FV ) && ( eOutputType != DiscretizationType_FV ) )
1033 DataArray3D< double > dataGLLJacobianIn, dataGLLJacobianSrc;
1034 DataArray3D< double > dataGLLJacobianOut;
1037 if( is_root )
dbgprint.printf( 0,
"Generating input mesh meta data\n" );
1039 GenerateMetaData( *m_meshInput, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrc,
1040 dataGLLJacobianSrc );
1042 GenerateMetaData( *m_meshInputCov, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrcCov,
1043 dataGLLJacobianIn );
1045 if( is_root )
dbgprint.printf( 0,
"Generating output mesh meta data\n" );
1046 GenerateMetaData( *m_meshOutput, mapOptions.nPout, mapOptions.fNoBubble, dataGLLNodesDest,
1047 dataGLLJacobianOut );
1050 this->InitializeSourceCoordinatesFromMeshFE( *m_meshInputCov, mapOptions.nPin, dataGLLNodesSrcCov );
1051 this->InitializeTargetCoordinatesFromMeshFE( *m_meshOutput, mapOptions.nPout, dataGLLNodesDest );
1054 bool fContinuousIn = ( eInputType == DiscretizationType_CGLL );
1056 if( eInputType == DiscretizationType_CGLL )
1058 GenerateUniqueJacobian( dataGLLNodesSrcCov, dataGLLJacobianIn, this->GetSourceAreas() );
1062 GenerateDiscontinuousJacobian( dataGLLJacobianIn, this->GetSourceAreas() );
1066 bool fContinuousOut = ( eOutputType == DiscretizationType_CGLL );
1068 if( eOutputType == DiscretizationType_CGLL )
1070 GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobianOut, this->GetTargetAreas() );
1074 GenerateDiscontinuousJacobian( dataGLLJacobianOut, this->GetTargetAreas() );
1078 MB_CHK_ERR( this->SetDOFmapAssociation( eInputType, mapOptions.nPin,
1079 ( eInputType == DiscretizationType_CGLL ), &dataGLLNodesSrcCov,
1080 &dataGLLNodesSrc, eOutputType, mapOptions.nPout,
1081 ( eOutputType == DiscretizationType_CGLL ), &dataGLLNodesDest ) );
1083 this->m_pdataGLLNodesIn = &dataGLLNodesSrcCov;
1084 this->m_pdataGLLNodesOut = &dataGLLNodesDest;
1087 if( is_root )
dbgprint.printf( 0,
"Calculating remap weights\n" );
1089 #ifdef USE_NATIVE_TEMPESTREMAP_ROUTINES
1090 LinearRemapGLLtoGLL_Integrated( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesSrcCov,
1091 dataGLLJacobianIn, dataGLLNodesDest, dataGLLJacobianOut,
1092 this->GetTargetAreas(), mapOptions.nPin, mapOptions.nPout, nMonotoneType,
1093 fContinuousIn, fContinuousOut, mapOptions.fSparseConstraints, *
this );
1095 LinearRemapGLLtoGLL2_MOAB( dataGLLNodesSrcCov, dataGLLJacobianIn, dataGLLNodesDest, dataGLLJacobianOut,
1096 this->GetTargetAreas(), mapOptions.nPin, mapOptions.nPout, nMonotoneType,
1097 fContinuousIn, fContinuousOut, mapOptions.fNoConservation );
1102 _EXCEPTIONT(
"Not implemented" );
1105 #ifdef MOAB_HAVE_EIGEN3
1106 copy_tempest_sparsemat_to_eigen3();
1109 #ifdef MOAB_HAVE_MPI
1113 MB_CHK_ERR( m_remapper->GetOverlapAugmentedEntities( ghostedEnts ) );
1115 MB_CHK_SET_ERR( m_interface->remove_entities( m_meshOverlapSet, ghostedEnts ),
1116 "Deleting ghosted entities failed" );
1120 if( !mapOptions.fNoCheck )
1122 if( is_root )
dbgprint.printf( 0,
"Verifying map" );
1123 this->IsConsistent( 1.0e-8 );
1124 if( !mapOptions.fNoConservation ) this->IsConservative( 1.0e-8 );
1126 if( nMonotoneType != 0 )
1128 this->IsMonotone( 1.0e-12 );
1132 catch( Exception& e )
1134 dbgprint.printf( 0,
"%s", e.ToString().c_str() );
1135 return ( moab::MB_FAILURE );
1139 return ( moab::MB_FAILURE );
1148 #ifndef MOAB_HAVE_MPI
1150 return OfflineMap::IsConsistent( dTolerance );
1155 DataArray1D< int > dataRows;
1156 DataArray1D< int > dataCols;
1157 DataArray1D< double > dataEntries;
1160 DataArray1D< double > dRowSums;
1161 m_mapRemap.GetEntries( dataRows, dataCols, dataEntries );
1162 dRowSums.Allocate( m_mapRemap.GetRows() );
1164 for(
unsigned i = 0; i < dataRows.GetRows(); i++ )
1166 dRowSums[dataRows[i]] += dataEntries[i];
1170 int fConsistent = 0;
1171 for(
unsigned i = 0; i < dRowSums.GetRows(); i++ )
1173 if( fabs( dRowSums[i] - 1.0 ) > dTolerance )
1176 int rowGID = row_gdofmap[i];
1177 Announce(
"TempestOnlineMap is not consistent in row %i (%1.15e)", rowGID, dRowSums[i] );
1182 int fConsistentGlobal = 0;
1183 ierr = MPI_Allreduce( &fConsistent, &fConsistentGlobal, 1, MPI_INT, MPI_SUM, m_pcomm->comm() );
1184 if( ierr != MPI_SUCCESS )
return -1;
1186 return fConsistentGlobal;
1194 #ifndef MOAB_HAVE_MPI
1196 return OfflineMap::IsConservative( dTolerance );
1203 DataArray1D< int > dataRows;
1204 DataArray1D< int > dataCols;
1205 DataArray1D< double > dataEntries;
1206 const DataArray1D< double >& dTargetAreas = this->GetTargetAreas();
1207 const DataArray1D< double >& dSourceAreas = this->GetSourceAreas();
1210 std::vector< int > dColumnsUnique;
1211 std::vector< double > dColumnSums;
1213 int nColumns = m_mapRemap.GetColumns();
1214 m_mapRemap.GetEntries( dataRows, dataCols, dataEntries );
1215 dColumnSums.resize( m_nTotDofs_SrcCov, 0.0 );
1216 dColumnsUnique.resize( m_nTotDofs_SrcCov, -1 );
1218 for(
unsigned i = 0; i < dataEntries.GetRows(); i++ )
1220 dColumnSums[dataCols[i]] += dataEntries[i] * dTargetAreas[dataRows[i]] / dSourceAreas[dataCols[i]];
1222 assert( dataCols[i] < m_nTotDofs_SrcCov );
1225 int colGID = this->GetColGlobalDoF( dataCols[i] );
1227 dColumnsUnique[dataCols[i]] = colGID;
1234 std::vector< int > nElementsInProc;
1235 const int nDATA = 3;
1236 nElementsInProc.resize( size * nDATA );
1237 int senddata[nDATA] = { nColumns, m_nTotDofs_SrcCov, m_nTotDofs_Src };
1238 ierr = MPI_Gather( senddata, nDATA, MPI_INT, nElementsInProc.data(), nDATA, MPI_INT, rootProc, m_pcomm->comm() );
1239 if( ierr != MPI_SUCCESS )
return -1;
1241 int nTotVals = 0, nTotColumns = 0;
1242 std::vector< int > dColumnIndices;
1243 std::vector< double > dColumnSourceAreas;
1244 std::vector< double > dColumnSumsTotal;
1245 std::vector< int > displs, rcount;
1246 if( rank == rootProc )
1248 displs.resize( size + 1, 0 );
1249 rcount.resize( size, 0 );
1251 for(
int ir = 0; ir < size; ++ir )
1253 nTotVals += nElementsInProc[ir * nDATA];
1254 nTotColumns += nElementsInProc[ir * nDATA + 1];
1258 rcount[ir] = nElementsInProc[ir * nDATA + 1];
1264 printf(
"Total nnz: %d, global source elements = %d\n", nTotVals, gsum );
1266 dColumnIndices.resize( nTotColumns, -1 );
1267 dColumnSumsTotal.resize( nTotColumns, 0.0 );
1276 ierr = MPI_Gatherv( &dColumnsUnique[0], m_nTotDofs_SrcCov, MPI_INT, &dColumnIndices[0], rcount.data(),
1277 displs.data(), MPI_INT, rootProc, m_pcomm->comm() );
1278 if( ierr != MPI_SUCCESS )
return -1;
1279 ierr = MPI_Gatherv( &dColumnSums[0], m_nTotDofs_SrcCov, MPI_DOUBLE, &dColumnSumsTotal[0], rcount.data(),
1280 displs.data(), MPI_DOUBLE, rootProc, m_pcomm->comm() );
1281 if( ierr != MPI_SUCCESS )
return -1;
1287 dColumnSums.clear();
1288 dColumnsUnique.clear();
1291 int fConservative = 0;
1292 if( rank == rootProc )
1294 displs[size] = ( nTotColumns );
1296 std::map< int, double > dColumnSumsOnRoot;
1298 for(
int ir = 0; ir < size; ir++ )
1300 for(
int ips = displs[ir]; ips < displs[ir + 1]; ips++ )
1302 if( dColumnIndices[ips] < 0 )
continue;
1305 dColumnSumsOnRoot[dColumnIndices[ips]] += dColumnSumsTotal[ips];
1311 for( std::map< int, double >::iterator it = dColumnSumsOnRoot.begin(); it != dColumnSumsOnRoot.end(); ++it )
1314 if( fabs( it->second - 1.0 ) > dTolerance )
1317 Announce(
"TempestOnlineMap is not conservative in column "
1320 it->first, it->second );
1326 ierr = MPI_Bcast( &fConservative, 1, MPI_INT, rootProc, m_pcomm->comm() );
1327 if( ierr != MPI_SUCCESS )
return -1;
1329 return fConservative;
1337 #ifndef MOAB_HAVE_MPI
1339 return OfflineMap::IsMonotone( dTolerance );
1344 DataArray1D< int > dataRows;
1345 DataArray1D< int > dataCols;
1346 DataArray1D< double > dataEntries;
1348 m_mapRemap.GetEntries( dataRows, dataCols, dataEntries );
1352 for(
unsigned i = 0; i < dataRows.GetRows(); i++ )
1354 if( ( dataEntries[i] < -dTolerance ) || ( dataEntries[i] > 1.0 + dTolerance ) )
1358 Announce(
"TempestOnlineMap is not monotone in entry (%i): %1.15e", i, dataEntries[i] );
1363 int fMonotoneGlobal = 0;
1364 ierr = MPI_Allreduce( &fMonotone, &fMonotoneGlobal, 1, MPI_INT, MPI_SUM, m_pcomm->comm() );
1365 if( ierr != MPI_SUCCESS )
return -1;
1367 return fMonotoneGlobal;
1375 const Range& entities,
1376 bool useMOABAdjacencies,
1379 assert( nrings > 0 );
1380 assert( useMOABAdjacencies || trMesh !=
nullptr );
1382 const size_t nrows = vecAdjFaces.size();
1389 if( useMOABAdjacencies )
1399 int adjIndex = entities.
index( *it );
1401 if( adjIndex >= 0 ) vecAdjFaces[
index].insert( adjIndex );
1411 GetAdjacentFaceVectorByEdge( *trMesh,
index, nrings *
face.edges.size(), adjFaces );
1414 for(
auto adjFace : adjFaces )
1415 if( adjFace.first >= 0 )
1416 vecAdjFaces[
index].insert( adjFace.first );
1426 double default_projection )
1428 std::vector< double > solSTagVals;
1429 std::vector< double > solTTagVals;
1432 if( m_remapper->point_cloud_source || m_remapper->point_cloud_target )
1434 if( m_remapper->point_cloud_source )
1437 solSTagVals.resize( covSrcEnts.
size(), default_projection );
1443 solSTagVals.resize( covSrcEnts.
size() * this->GetSourceNDofsPerElement() * this->GetSourceNDofsPerElement(),
1444 default_projection );
1447 if( m_remapper->point_cloud_target )
1450 solTTagVals.resize( tgtEnts.
size(), default_projection );
1456 solTTagVals.resize( tgtEnts.
size() * this->GetDestinationNDofsPerElement() *
1457 this->GetDestinationNDofsPerElement(),
1458 default_projection );
1466 solSTagVals.resize( covSrcEnts.
size() * this->GetSourceNDofsPerElement() * this->GetSourceNDofsPerElement(),
1467 default_projection );
1468 solTTagVals.resize( tgtEnts.
size() * this->GetDestinationNDofsPerElement() *
1469 this->GetDestinationNDofsPerElement(),
1470 default_projection );
1477 MB_CHK_SET_ERR( m_interface->tag_get_data( srcSolutionTag, sents, &solSTagVals[0] ),
1478 "Getting local tag data failed" );
1483 MB_CHK_SET_ERR( this->ApplyWeights( solSTagVals, solTTagVals, transpose ),
1484 "Applying remap operator onto source vector data failed" );
1487 MB_CHK_SET_ERR( m_interface->tag_set_data( tgtSolutionTag, tents, &solTTagVals[0] ),
1488 "Setting target tag data failed" );
1490 if( caasType != CAAS_NONE )
1492 std::string tgtSolutionTagName;
1493 MB_CHK_SET_ERR( m_interface->tag_get_name( tgtSolutionTag, tgtSolutionTagName ),
"Getting tag name failed" );
1496 constexpr
int nmax_caas_iterations = 10;
1497 double mismatch = 1.0;
1498 int caasIteration = 0;
1499 double initialMismatch = 0.0;
1500 while( ( fabs( mismatch / initialMismatch ) > 1e-15 && fabs( mismatch ) > 1e-15 ) &&
1501 caasIteration++ < nmax_caas_iterations )
1503 double dMassDiffPostGlobal;
1504 std::pair< double, double > mDefect =
1505 this->ApplyBoundsLimiting( solSTagVals, solTTagVals, caasType, caasIteration, mismatch );
1506 #ifdef MOAB_HAVE_MPI
1507 double dMassDiffPost = mDefect.second;
1508 MPI_Allreduce( &dMassDiffPost, &dMassDiffPostGlobal, 1, MPI_DOUBLE, MPI_SUM, m_pcomm->comm() );
1510 dMassDiffPostGlobal = mDefect.second;
1512 if( caasIteration == 1 ) initialMismatch = mDefect.first;
1513 if( m_remapper->verbose && is_root )
1515 printf(
"Field {%s} -> CAAS iteration: %d, mass defect: %3.4e, post-CAAS: %3.4e\n",
1516 tgtSolutionTagName.c_str(), caasIteration, mDefect.first, dMassDiffPostGlobal );
1518 mismatch = dMassDiffPostGlobal;
1521 MB_CHK_SET_ERR( m_interface->tag_set_data( tgtSolutionTag, tents, &solTTagVals[0] ),
1522 "Setting local tag data failed" );
1535 std::vector< double > solSTagVals, solTTagVals;
1538 if( m_remapper->point_cloud_source || m_remapper->point_cloud_target )
1540 if( m_remapper->point_cloud_source )
1543 solSTagVals.resize( covSrcEnts.
size(), 0.0 );
1549 solSTagVals.resize( covSrcEnts.
size() * this->GetSourceNDofsPerElement() *
1550 this->GetSourceNDofsPerElement(),
1554 if( m_remapper->point_cloud_target )
1557 solTTagVals.resize( tgtEnts.
size(), 0.0 );
1563 solTTagVals.resize( tgtEnts.
size() * this->GetDestinationNDofsPerElement() *
1564 this->GetDestinationNDofsPerElement(),
1573 solSTagVals.resize( covSrcEnts.
size() * this->GetSourceNDofsPerElement() * this->GetSourceNDofsPerElement(),
1576 tgtEnts.
size() * this->GetDestinationNDofsPerElement() * this->GetDestinationNDofsPerElement(), 0.0 );
1582 MB_CHK_SET_ERR( m_interface->tag_get_data( srcSolutionTag, sents, &solSTagVals[0] ),
1583 "Getting source tag data failed" );
1586 MB_CHK_SET_ERR( this->ApplyWeights( solSTagVals, solTTagVals,
false ),
1587 "High-order projection failed" );
1590 MB_CHK_SET_ERR( m_interface->tag_set_data( tgtSolutionTag, tents, &solTTagVals[0] ),
1591 "Setting target tag data failed" );
1593 if( caasType == CAAS_NONE || loWeightMap ==
nullptr )
return moab::MB_SUCCESS;
1687 const size_t nTargetDofs = solTTagVals.size();
1688 const size_t nSourceDofs = solSTagVals.size();
1693 if( row_dtoc_dofmap.size() < nTargetDofs )
1695 MB_CHK_SET_ERR( moab::MB_FAILURE,
"row_dtoc_dofmap smaller than target tag size" );
1699 std::vector< double > yLow( nTargetDofs, 0.0 );
1701 "Low-order projection failed" );
1759 std::vector< double > srcNorm8wt;
1760 bool hasNorm8wt =
false;
1763 moab::ErrorCode rvalN = m_interface->tag_get_handle(
"norm8wt", normTag );
1764 if(
MB_SUCCESS == rvalN && normTag !=
nullptr )
1772 srcNorm8wt.resize( sents.
size(), 0.0 );
1773 moab::ErrorCode rvalD = m_interface->tag_get_data( normTag, sents, &srcNorm8wt[0] );
1774 if(
MB_SUCCESS == rvalD && srcNorm8wt.size() == nSourceDofs )
1790 std::vector< double > lcl_lo( nTargetDofs, 1e308 );
1791 std::vector< double > lcl_hi( nTargetDofs, -1e308 );
1793 WeightMatrix& hiW = this->m_weightMatrix;
1794 for(
size_t i = 0; i < nTargetDofs; i++ )
1796 int r = row_dtoc_dofmap[i];
1797 if( r < 0 || r >= hiW.outerSize() )
continue;
1798 for( WeightMatrix::InnerIterator it( hiW, r ); it; ++it )
1803 int mc = (int)it.col();
1817 for(
size_t k = 0; k < nSourceDofs && k < col_dtoc_dofmap.size(); k++ )
1818 if( col_dtoc_dofmap[k] > maxMatCol ) maxMatCol = col_dtoc_dofmap[k];
1819 std::vector< int > col_inv( maxMatCol + 1, -1 );
1820 for(
size_t k = 0; k < nSourceDofs && k < col_dtoc_dofmap.size(); k++ )
1821 if( col_dtoc_dofmap[k] >= 0 ) col_inv[col_dtoc_dofmap[k]] = (int)k;
1830 int bndsLocalErr = 0;
1831 int bndsFirstRowG = -1;
1832 int bndsFirstMc = -1;
1833 double bndsFirstWgt = 0.0;
1834 int bndsFirstKind = 0;
1836 for(
size_t i = 0; i < nTargetDofs; i++ )
1838 int r = row_dtoc_dofmap[i];
1839 if( r < 0 || r >= hiW.outerSize() )
continue;
1840 for( WeightMatrix::InnerIterator it( hiW, r ); it; ++it )
1852 if( fabs( it.value() ) < 1e-50 )
continue;
1853 const int mc = (int)it.col();
1863 if( mc < 0 || mc > maxMatCol )
1868 bndsFirstRowG = (r >= 0 && r < (int)row_gdofmap.size()) ? (
int)row_gdofmap[r] : -1;
1870 bndsFirstWgt = it.value();
1875 const int srcIdx = col_inv[mc];
1881 bndsFirstRowG = (r >= 0 && r < (int)row_gdofmap.size()) ? (
int)row_gdofmap[r] : -1;
1883 bndsFirstWgt = it.value();
1888 if( srcIdx >= (
int)nSourceDofs )
1893 bndsFirstRowG = (r >= 0 && r < (int)row_gdofmap.size()) ? (
int)row_gdofmap[r] : -1;
1895 bndsFirstWgt = it.value();
1905 double v = solSTagVals[srcIdx];
1908 const double n = srcNorm8wt[srcIdx];
1909 if( fabs(n) < 1
E-20 )
continue;
1912 if( v < lcl_lo[i] ) lcl_lo[i] = v;
1913 if( v > lcl_hi[i] ) lcl_hi[i] = v;
1919 if( lcl_lo[i] > lcl_hi[i] )
1927 #ifdef MOAB_HAVE_MPI
1929 MPI_Comm comm = m_pcomm ? m_pcomm->comm() : MPI_COMM_SELF;
1930 int bndsGlobalErr = 0;
1931 MPI_Allreduce( &bndsLocalErr, &bndsGlobalErr, 1, MPI_INT, MPI_MAX, comm );
1935 MPI_Comm_rank( comm, &myRank );
1938 static const char* kindStr[4] = {
"?",
"mc>maxMatCol",
"col_inv[mc]==-1",
"srcIdx>=nSourceDofs" };
1940 "FATAL: ApplyWeightsWithDualMap bounds extraction dropped a nonzero "
1941 "high-order stencil column on rank %d.\n"
1942 " global_target_row=%d matrix_col=%d weight=%.17e reason=%s\n"
1943 " This means the source coverage on this rank does NOT contain a "
1944 "column the owned high-order row references — the 3-ring (or whatever) "
1945 "ghost layer setting is too narrow, or the map file was generated against "
1946 "a different mesh. Bounds computed over an incomplete stencil break BFB; "
1947 "aborting rather than silently producing wrong CAAS output.\n",
1948 myRank, bndsFirstRowG, bndsFirstMc, bndsFirstWgt, kindStr[bndsFirstKind] );
1951 MPI_Abort( comm, 1 );
1957 static const char* kindStr[4] = {
"?",
"mc>maxMatCol",
"col_inv[mc]==-1",
"srcIdx>=nSourceDofs" };
1959 "FATAL: ApplyWeightsWithDualMap bounds extraction dropped a nonzero "
1960 "high-order stencil column.\n"
1961 " global_target_row=%d matrix_col=%d weight=%.17e reason=%s\n",
1962 bndsFirstRowG, bndsFirstMc, bndsFirstWgt, kindStr[bndsFirstKind] );
1964 return moab::MB_FAILURE;
1972 for(
size_t i = 0; i < nTargetDofs; i++ )
1974 if( yLow[i] == 0.0 )
1976 solTTagVals[i] = 0.0;
1987 double g_lo = 1e308, g_hi = -1e308;
1988 for(
size_t i = 0; i < nTargetDofs; i++ )
1990 int r = row_dtoc_dofmap[i];
1991 if( r < 0 || r >= (
int)row_gdofmap.size() )
continue;
1992 if( lcl_lo[i] < g_lo ) g_lo = lcl_lo[i];
1993 if( lcl_hi[i] > g_hi ) g_hi = lcl_hi[i];
1995 #ifdef MOAB_HAVE_MPI
1997 MPI_Comm comm = m_pcomm ? m_pcomm->comm() : MPI_COMM_SELF;
1998 double tmp_min = g_lo, tmp_max = g_hi;
1999 MPI_Allreduce( &tmp_min, &g_lo, 1, MPI_DOUBLE, MPI_MIN, comm );
2000 MPI_Allreduce( &tmp_max, &g_hi, 1, MPI_DOUBLE, MPI_MAX, comm );
2013 std::vector< double > mappedNorm8wt( nTargetDofs, 0.0 );
2017 "Mapped-norm8wt computation (low-order on source norm8wt) failed" );
2021 std::vector< double > srcOnes( nSourceDofs, 1.0 );
2023 "Mapped-norm8wt computation (low-order on ones) failed" );
2036 for(
size_t i = 0; i < nTargetDofs; i++ )
2038 const double w = mappedNorm8wt[i];
2056 std::vector< double > tgtAreas( nTargetDofs, 0.0 );
2058 std::vector< moab::EntityHandle > tentVec;
2059 tentVec.reserve( tents.
size() );
2061 tentVec.push_back( *it );
2063 bool got_areas =
false;
2069 moab::ErrorCode rval = m_interface->tag_get_handle(
"aream", aream_tag );
2070 if(
MB_SUCCESS == rval && aream_tag !=
nullptr && !tentVec.empty() )
2072 const size_t nents = std::min< size_t >( tentVec.size(), nTargetDofs );
2073 std::vector< double > aream_vals( nents, 0.0 );
2074 rval = m_interface->tag_get_data( aream_tag, &tentVec[0], (
int)nents, &aream_vals[0] );
2077 for(
size_t i = 0; i < nents; i++ ) tgtAreas[i] = aream_vals[i];
2088 const DataArray1D< double >& dTargetAreas = this->GetTargetAreas();
2089 const size_t nRows = dTargetAreas.GetRows();
2090 if( nRows >= nTargetDofs )
2092 for(
size_t i = 0; i < nTargetDofs; i++ )
2094 int r = row_dtoc_dofmap[i];
2095 if( r >= 0 && (
size_t)r < nRows )
2096 tgtAreas[i] = dTargetAreas[r];
2107 "ApplyWeightsWithDualMap: no target-cell areas available. "
2108 "Neither the 'aream' tag (from iMOAB_LoadMapFile with "
2109 "arearead != 0) nor OfflineMap::GetTargetAreas() (from an "
2110 "online map build) provided areas. Recomputing areas from "
2111 "mesh geometry is not bit-for-bit with MCT and is no longer "
2112 "permitted in the CAAS path. Re-load the map file with an "
2113 "area-bearing arearead setting (e.g. arearead=3 for F-maps), "
2114 "or build the online map so target areas are populated." );
2121 std::vector< int > rowGids( nTargetDofs, -1 );
2122 std::vector< double > massLowPerRow( nTargetDofs, 0.0 );
2123 std::vector< double > massHiUnclippedPerRow( nTargetDofs, 0.0 );
2124 std::vector< double > clipDefectPerRow( nTargetDofs, 0.0 );
2125 std::vector< double > capLowPerRow( nTargetDofs, 0.0 );
2126 std::vector< double > capHighPerRow( nTargetDofs, 0.0 );
2128 for(
size_t i = 0; i < nTargetDofs; i++ )
2130 int r = row_dtoc_dofmap[i];
2131 if( r < 0 || r >= (
int)row_gdofmap.size() )
2134 rowGids[i] = (int)row_gdofmap[r];
2136 const double area = tgtAreas[i];
2137 const double y = solTTagVals[i];
2138 const double lo = lcl_lo[i];
2139 const double hi = lcl_hi[i];
2145 dm = ( y - lo ) * area;
2150 dm = ( y - hi ) * area;
2152 clipDefectPerRow[i] = dm;
2153 capLowPerRow[i] = ( yc - lo ) * area;
2154 capHighPerRow[i] = ( hi - yc ) * area;
2155 massLowPerRow[i] = yLow[i] * area;
2163 massHiUnclippedPerRow[i] = y * area;
2165 solTTagVals[i] = yc;
2180 #ifdef MOAB_HAVE_MPI
2181 MPI_Comm reduce_comm = m_pcomm ? m_pcomm->comm() : MPI_COMM_SELF;
2183 int reduce_comm = 0;
2185 #ifdef MOAB_HAVE_MPI
2191 const std::vector< int >& reduce_mask = rowGids;
2198 const std::vector< std::vector< double > > caasFields = {
2199 massLowPerRow, massHiUnclippedPerRow, clipDefectPerRow,
2200 capLowPerRow, capHighPerRow };
2201 std::vector< double > caasGsums;
2203 const double M_low = caasGsums[0];
2204 const double M_hi_unclipped = caasGsums[1];
2205 const double dM_clip = caasGsums[2];
2206 const double cap_low_g = caasGsums[3];
2207 const double cap_high_g = caasGsums[4];
2230 const double diff = M_low - M_hi_unclipped;
2231 const double dM_total = dM_clip + diff;
2246 if( dM_total > 0.0 && cap_high_g > 0.0 )
2248 for(
size_t i = 0; i < nTargetDofs; i++ )
2250 const double area = tgtAreas[i];
2251 const double yc = solTTagVals[i];
2253 solTTagVals[i] = yc + ( ( lcl_hi[i] - yc ) / cap_high_g ) * dM_total;
2256 else if( dM_total < 0.0 && cap_low_g > 0.0 )
2258 for(
size_t i = 0; i < nTargetDofs; i++ )
2260 const double area = tgtAreas[i];
2261 const double yc = solTTagVals[i];
2263 solTTagVals[i] = yc + ( ( yc - lcl_lo[i] ) / cap_low_g ) * dM_total;
2279 for(
size_t i = 0; i < nTargetDofs; i++ )
2281 if( fabs(yLow[i]) < 1
E-40 )
continue;
2282 if( solTTagVals[i] < g_lo ) solTTagVals[i] = g_lo;
2283 if( solTTagVals[i] > g_hi ) solTTagVals[i] = g_hi;
2287 MB_CHK_SET_ERR( m_interface->tag_set_data( tgtSolutionTag, tents, &solTTagVals[0] ),
2288 "Setting target tag data failed" );
2294 const std::string& solnName,
2296 sample_function testFunction,
2298 std::string cloneSolnName )
2300 const bool outputEnabled = ( is_root );
2310 trmesh = m_remapper->m_covering_source;
2311 entities = ( m_remapper->point_cloud_source ? m_remapper->m_covering_source_vertices
2312 : m_remapper->m_covering_source_entities );
2313 discOrder = m_nDofsPEl_Src;
2314 discMethod = m_eInputType;
2319 trmesh = m_remapper->m_target;
2321 ( m_remapper->point_cloud_target ? m_remapper->m_target_vertices : m_remapper->m_target_entities );
2322 discOrder = m_nDofsPEl_Dest;
2323 discMethod = m_eOutputType;
2328 std::cout <<
"Invalid context specified for defining an analytical solution tag" << std::endl;
2329 return moab::MB_FAILURE;
2336 if( clonedSolnTag !=
nullptr )
2338 if( cloneSolnName.size() == 0 )
2340 cloneSolnName = solnName + std::string(
"Cloned" );
2347 const int TriQuadratureOrder = 10;
2349 if( outputEnabled ) std::cout <<
"Using triangular quadrature of order " << TriQuadratureOrder << std::endl;
2351 TriangularQuadratureRule triquadrule( TriQuadratureOrder );
2353 const int TriQuadraturePoints = triquadrule.GetPoints();
2355 const DataArray2D< double >& TriQuadratureG = triquadrule.GetG();
2356 const DataArray1D< double >& TriQuadratureW = triquadrule.GetW();
2359 DataArray1D< double > dVar;
2360 DataArray1D< double > dVarMB;
2363 DataArray1D< double > dNodeArea;
2368 if( discMethod == DiscretizationType_CGLL || discMethod == DiscretizationType_DGLL )
2371 const bool fGLL =
true;
2372 const bool fGLLIntegrate =
false;
2375 DataArray3D< int > dataGLLNodes;
2376 DataArray3D< double > dataGLLJacobian;
2378 GenerateMetaData( *trmesh, discOrder,
false, dataGLLNodes, dataGLLJacobian );
2381 int nElements = trmesh->faces.size();
2384 for(
int k = 0; k < nElements; k++ )
2386 const Face&
face = trmesh->faces[k];
2388 if(
face.edges.size() != 4 )
2390 _EXCEPTIONT(
"Non-quadrilateral face detected; "
2391 "incompatible with --gll" );
2397 for(
int i = 0; i < discOrder; i++ )
2399 for(
int j = 0; j < discOrder; j++ )
2401 for(
int k = 0; k < nElements; k++ )
2403 if( dataGLLNodes[i][j][k] > iMaxNode )
2405 iMaxNode = dataGLLNodes[i][j][k];
2412 DataArray1D< double > dG;
2413 DataArray1D< double > dW;
2415 GaussLobattoQuadrature::GetPoints( discOrder, 0.0, 1.0, dG, dW );
2418 const int nGaussP = 10;
2420 DataArray1D< double > dGaussG;
2421 DataArray1D< double > dGaussW;
2423 GaussQuadrature::GetPoints( nGaussP, 0.0, 1.0, dGaussG, dGaussW );
2426 dVar.Allocate( iMaxNode );
2427 dVarMB.Allocate( discOrder * discOrder * nElements );
2428 dNodeArea.Allocate( iMaxNode );
2431 for(
int k = 0; k < nElements; k++ )
2433 const Face&
face = trmesh->faces[k];
2438 for(
int i = 0; i < discOrder; i++ )
2440 for(
int j = 0; j < discOrder; j++ )
2448 ApplyLocalMap(
face, trmesh->nodes, dG[i], dG[j], node, dDx1G, dDx2G );
2451 double dNodeLon = atan2( node.y, node.x );
2452 if( dNodeLon < 0.0 )
2454 dNodeLon += 2.0 * M_PI;
2456 double dNodeLat = asin( node.z );
2458 double dSample = ( *testFunction )( dNodeLon, dNodeLat );
2460 dVar[dataGLLNodes[j][i][k] - 1] = dSample;
2467 DataArray2D< double > dCoeff( discOrder, discOrder );
2469 for(
int p = 0; p < nGaussP; p++ )
2471 for(
int q = 0; q < nGaussP; q++ )
2479 ApplyLocalMap(
face, trmesh->nodes, dGaussG[p], dGaussG[q], node, dDx1G, dDx2G );
2482 Node nodeCross = CrossProduct( dDx1G, dDx2G );
2485 sqrt( nodeCross.x * nodeCross.x + nodeCross.y * nodeCross.y + nodeCross.z * nodeCross.z );
2489 SampleGLLFiniteElement( 0, discOrder, dGaussG[p], dGaussG[q], dCoeff );
2492 double dNodeLon = atan2( node.y, node.x );
2493 if( dNodeLon < 0.0 )
2495 dNodeLon += 2.0 * M_PI;
2497 double dNodeLat = asin( node.z );
2499 double dSample = ( *testFunction )( dNodeLon, dNodeLat );
2502 for(
int i = 0; i < discOrder; i++ )
2504 for(
int j = 0; j < discOrder; j++ )
2507 double dNodalArea = dCoeff[i][j] * dGaussW[p] * dGaussW[q] * dJacobian;
2509 dVar[dataGLLNodes[i][j][k] - 1] += dSample * dNodalArea;
2511 dNodeArea[dataGLLNodes[i][j][k] - 1] += dNodalArea;
2522 for(
size_t i = 0; i < dVar.GetRows(); i++ )
2524 dVar[i] /= dNodeArea[i];
2531 for(
unsigned j = 0; j < entities.
size(); j++ )
2532 for(
int p = 0; p < discOrder; p++ )
2533 for(
int q = 0; q < discOrder; q++ )
2535 const int offsetDOF = j * discOrder * discOrder + p * discOrder + q;
2536 dVarMB[offsetDOF] = dVar[col_dtoc_dofmap[offsetDOF]];
2541 for(
unsigned j = 0; j < entities.
size(); j++ )
2542 for(
int p = 0; p < discOrder; p++ )
2543 for(
int q = 0; q < discOrder; q++ )
2545 const int offsetDOF = j * discOrder * discOrder + p * discOrder + q;
2546 dVarMB[offsetDOF] = dVar[row_dtoc_dofmap[offsetDOF]];
2551 MB_CHK_ERR( m_interface->tag_set_data( solnTag, entities, &dVarMB[0] ) );
2556 if( discMethod == DiscretizationType_FV )
2561 dVar.Allocate( trmesh->faces.size() );
2563 std::vector< Node >& nodes = trmesh->nodes;
2566 for(
size_t i = 0; i < trmesh->faces.size(); i++ )
2568 const Face&
face = trmesh->faces[i];
2571 for(
size_t j = 0; j <
face.edges.size() - 2; j++ )
2574 const Node& node0 = nodes[
face[0]];
2575 const Node& node1 = nodes[
face[j + 1]];
2576 const Node& node2 = nodes[
face[j + 2]];
2580 faceTri.SetNode( 0,
face[0] );
2581 faceTri.SetNode( 1,
face[j + 1] );
2582 faceTri.SetNode( 2,
face[j + 2] );
2584 double dTriangleArea = CalculateFaceArea( faceTri, nodes );
2587 double dTotalSample = 0.0;
2590 for(
int k = 0; k < TriQuadraturePoints; k++ )
2592 Node node( TriQuadratureG[k][0] * node0.x + TriQuadratureG[k][1] * node1.x +
2593 TriQuadratureG[k][2] * node2.x,
2594 TriQuadratureG[k][0] * node0.y + TriQuadratureG[k][1] * node1.y +
2595 TriQuadratureG[k][2] * node2.y,
2596 TriQuadratureG[k][0] * node0.z + TriQuadratureG[k][1] * node1.z +
2597 TriQuadratureG[k][2] * node2.z );
2599 double dMagnitude = node.Magnitude();
2600 node.x /= dMagnitude;
2601 node.y /= dMagnitude;
2602 node.z /= dMagnitude;
2604 double dLon = atan2( node.y, node.x );
2609 double dLat = asin( node.z );
2611 double dSample = ( *testFunction )( dLon, dLat );
2613 dTotalSample += dSample * TriQuadratureW[k] * dTriangleArea;
2616 dVar[i] += dTotalSample / trmesh->vecFaceArea[i];
2619 MB_CHK_ERR( m_interface->tag_set_data( solnTag, entities, &dVar[0] ) );
2624 std::vector< Node >& nodes = trmesh->nodes;
2627 dVar.Allocate( nodes.size() );
2629 for(
size_t j = 0; j < nodes.size(); j++ )
2631 Node& node = nodes[j];
2632 double dMagnitude = node.Magnitude();
2633 node.x /= dMagnitude;
2634 node.y /= dMagnitude;
2635 node.z /= dMagnitude;
2636 double dLon = atan2( node.y, node.x );
2641 double dLat = asin( node.z );
2643 double dSample = ( *testFunction )( dLon, dLat );
2647 MB_CHK_ERR( m_interface->tag_set_data( solnTag, entities, &dVar[0] ) );
2657 std::map< std::string, double >& metrics,
2660 const bool outputEnabled = ( is_root );
2671 entities = ( m_remapper->point_cloud_source ? m_remapper->m_covering_source_vertices
2672 : m_remapper->m_covering_source_entities );
2673 discOrder = m_nDofsPEl_Src;
2681 ( m_remapper->point_cloud_target ? m_remapper->m_target_vertices : m_remapper->m_target_entities );
2682 discOrder = m_nDofsPEl_Dest;
2688 std::cout <<
"Invalid context specified for defining an analytical solution tag" << std::endl;
2689 return moab::MB_FAILURE;
2694 std::string exactTagName, projTagName;
2695 const int ntotsize = entities.
size() * discOrder * discOrder;
2696 std::vector< double > exactSolution( ntotsize, 0.0 ), projSolution( ntotsize, 0.0 );
2697 MB_CHK_ERR( m_interface->tag_get_name( exactTag, exactTagName ) );
2698 MB_CHK_ERR( m_interface->tag_get_data( exactTag, entities, &exactSolution[0] ) );
2699 MB_CHK_ERR( m_interface->tag_get_name( approxTag, projTagName ) );
2700 MB_CHK_ERR( m_interface->tag_get_data( approxTag, entities, &projSolution[0] ) );
2702 const auto& ovents = m_remapper->m_overlap_entities;
2704 std::vector< double > errnorms( 4, 0.0 ), globerrnorms( 4, 0.0 );
2705 double sumarea = 0.0;
2706 for(
size_t i = 0; i < ovents.size(); ++i )
2708 const int srcidx = m_remapper->m_overlap->vecSourceFaceIx[i];
2709 if( srcidx < 0 )
continue;
2710 const int tgtidx = m_remapper->m_overlap->vecTargetFaceIx[i];
2711 if( tgtidx < 0 )
continue;
2712 const double ovarea = m_remapper->m_overlap->vecFaceArea[i];
2713 const double error = fabs( exactSolution[tgtidx] - projSolution[tgtidx] );
2714 errnorms[0] += ovarea *
error;
2716 errnorms[3] = (
error > errnorms[3] ?
error : errnorms[3] );
2719 errnorms[2] = sumarea;
2720 #ifdef MOAB_HAVE_MPI
2723 MPI_Reduce( &errnorms[0], &globerrnorms[0], 3, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
2724 MPI_Reduce( &errnorms[3], &globerrnorms[3], 1, MPI_DOUBLE, MPI_MAX, 0, m_pcomm->comm() );
2727 for(
int i = 0; i < 4; ++i )
2728 globerrnorms[i] = errnorms[i];
2731 globerrnorms[0] = ( globerrnorms[0] / globerrnorms[2] );
2732 globerrnorms[1] = std::sqrt( globerrnorms[1] / globerrnorms[2] );
2735 metrics[
"L1Error"] = globerrnorms[0];
2736 metrics[
"L2Error"] = globerrnorms[1];
2737 metrics[
"LinfError"] = globerrnorms[3];
2741 std::cout <<
"Error metrics when comparing " << projTagName <<
" against " << exactTagName << std::endl;
2742 std::cout <<
"\t Total Intersection area = " << globerrnorms[2] << std::endl;
2743 std::cout <<
"\t L_1 error = " << globerrnorms[0] << std::endl;
2744 std::cout <<
"\t L_2 error = " << globerrnorms[1] << std::endl;
2745 std::cout <<
"\t L_inf error = " << globerrnorms[3] << std::endl;