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"
62 #define MPI_CHK_ERR( err ) \
65 std::cout << "MPI Failure. ErrorCode (" << ( err ) << ") "; \
66 std::cout << "\nMPI Aborting... \n"; \
67 return moab::MB_FAILURE; \
75 m_pcomm =
m_remapper->get_parallel_communicator();
106 std::vector< std::string > dimNames;
107 std::vector< int > dimSizes;
108 dimNames.push_back(
"num_elem" );
109 dimSizes.push_back( m_meshInputCov->faces.size() );
111 this->InitializeSourceDimensions( dimNames, dimSizes );
116 std::vector< std::string > dimNames;
117 std::vector< int > dimSizes;
118 dimNames.push_back(
"num_elem" );
119 dimSizes.push_back( m_meshOutput->faces.size() );
121 this->InitializeTargetDimensions( dimNames, dimSizes );
129 m_interface =
nullptr;
133 m_meshInput =
nullptr;
134 m_meshOutput =
nullptr;
135 m_meshOverlap =
nullptr;
141 const std::string tgtDofTagName )
146 tagSize = ( m_eInputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Src * m_nDofsPEl_Src );
152 MB_CHK_SET_ERR( MB_FAILURE,
"DoF tag is not set correctly for source mesh." );
157 tagSize = ( m_eOutputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Dest * m_nDofsPEl_Dest );
162 MB_CHK_SET_ERR( MB_FAILURE,
"DoF tag is not set correctly for target mesh." );
174 bool isSrcContinuous,
175 DataArray3D< int >* srcdataGLLNodes,
176 DataArray3D< int >* srcdataGLLNodesSrc,
179 bool isTgtContinuous,
180 DataArray3D< int >* tgtdataGLLNodes )
182 std::vector< bool > dgll_cgll_row_ldofmap, dgll_cgll_col_ldofmap, dgll_cgll_covcol_ldofmap;
183 std::vector< int > src_soln_gdofs, locsrc_soln_gdofs, tgt_soln_gdofs;
186 m_srcDiscType = srcType;
187 m_destDiscType = destType;
188 m_input_order = srcOrder;
189 m_output_order = destOrder;
191 bool vprint = is_root &&
false;
196 int srcTagSize = ( m_eInputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Src * m_nDofsPEl_Src );
197 if( m_remapper->point_cloud_source )
199 assert( m_nDofsPEl_Src == 1 );
200 col_gdofmap.resize( m_remapper->m_covering_source_vertices.size(), UINT_MAX );
201 col_dtoc_dofmap.resize( m_remapper->m_covering_source_vertices.size(), -1 );
202 src_soln_gdofs.resize( m_remapper->m_covering_source_vertices.size(), -1 );
204 m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_covering_source_vertices, &src_soln_gdofs[0] ) );
209 col_gdofmap.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, UINT_MAX );
210 col_dtoc_dofmap.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, -1 );
211 src_soln_gdofs.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, -1 );
213 m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_covering_source_entities, &src_soln_gdofs[0] ) );
216 m_nTotDofs_SrcCov = 0;
217 if( srcdataGLLNodes ==
nullptr )
220 for(
unsigned i = 0; i < col_gdofmap.size(); ++i )
222 auto gdof = src_soln_gdofs[i];
224 col_gdofmap[i] = gdof - 1;
225 col_dtoc_dofmap[i] = i;
226 if( vprint ) std::cout <<
"Col: " << i <<
", " << col_gdofmap[i] <<
"\n";
232 if( isSrcContinuous )
233 dgll_cgll_covcol_ldofmap.resize( m_remapper->m_covering_source_entities.size() * srcTagSize,
false );
235 for(
unsigned j = 0; j < m_remapper->m_covering_source_entities.size(); j++ )
237 for(
int p = 0; p < m_nDofsPEl_Src; p++ )
239 for(
int q = 0; q < m_nDofsPEl_Src; q++ )
241 const int localDOF = ( *srcdataGLLNodes )[p][q][j] - 1;
242 const int offsetDOF = j * srcTagSize + p * m_nDofsPEl_Src + q;
243 if( isSrcContinuous && !dgll_cgll_covcol_ldofmap[localDOF] )
246 dgll_cgll_covcol_ldofmap[localDOF] =
true;
248 if( !isSrcContinuous ) m_nTotDofs_SrcCov++;
249 assert( src_soln_gdofs[offsetDOF] > 0 );
254 if( isSrcContinuous )
256 col_gdofmap[localDOF] = src_soln_gdofs[offsetDOF] - 1;
257 col_dtoc_dofmap[offsetDOF] = localDOF;
261 col_gdofmap[offsetDOF] = src_soln_gdofs[offsetDOF] - 1;
262 col_dtoc_dofmap[offsetDOF] = offsetDOF;
269 if( m_remapper->point_cloud_source )
271 assert( m_nDofsPEl_Src == 1 );
272 srccol_gdofmap.resize( m_remapper->m_source_vertices.size(), UINT_MAX );
273 srccol_dtoc_dofmap.resize( m_remapper->m_covering_source_vertices.size(), -1 );
274 locsrc_soln_gdofs.resize( m_remapper->m_source_vertices.size(), -1 );
275 MB_CHK_ERR( m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_source_vertices, &locsrc_soln_gdofs[0] ) );
279 srccol_gdofmap.resize( m_remapper->m_source_entities.size() * srcTagSize, UINT_MAX );
280 srccol_dtoc_dofmap.resize( m_remapper->m_source_entities.size() * srcTagSize, -1 );
281 locsrc_soln_gdofs.resize( m_remapper->m_source_entities.size() * srcTagSize, -1 );
282 MB_CHK_ERR( m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_source_entities, &locsrc_soln_gdofs[0] ) );
287 if( srcdataGLLNodesSrc ==
nullptr )
290 for(
unsigned i = 0; i < srccol_gdofmap.size(); ++i )
292 auto gdof = locsrc_soln_gdofs[i];
294 srccol_gdofmap[i] = gdof - 1;
295 srccol_dtoc_dofmap[i] = i;
301 if( isSrcContinuous ) dgll_cgll_col_ldofmap.resize( m_remapper->m_source_entities.size() * srcTagSize,
false );
303 for(
unsigned j = 0; j < m_remapper->m_source_entities.size(); j++ )
305 for(
int p = 0; p < m_nDofsPEl_Src; p++ )
307 for(
int q = 0; q < m_nDofsPEl_Src; q++ )
309 const int localDOF = ( *srcdataGLLNodesSrc )[p][q][j] - 1;
310 const int offsetDOF = j * srcTagSize + p * m_nDofsPEl_Src + q;
311 if( isSrcContinuous && !dgll_cgll_col_ldofmap[localDOF] )
314 dgll_cgll_col_ldofmap[localDOF] =
true;
316 if( !isSrcContinuous ) m_nTotDofs_Src++;
317 assert( locsrc_soln_gdofs[offsetDOF] > 0 );
318 if( isSrcContinuous )
320 srccol_gdofmap[localDOF] = locsrc_soln_gdofs[offsetDOF] - 1;
321 srccol_dtoc_dofmap[offsetDOF] = localDOF;
325 srccol_gdofmap[offsetDOF] = locsrc_soln_gdofs[offsetDOF] - 1;
326 srccol_dtoc_dofmap[offsetDOF] = offsetDOF;
333 int tgtTagSize = ( m_eOutputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Dest * m_nDofsPEl_Dest );
334 if( m_remapper->point_cloud_target )
336 assert( m_nDofsPEl_Dest == 1 );
337 row_gdofmap.resize( m_remapper->m_target_vertices.size(), UINT_MAX );
338 row_dtoc_dofmap.resize( m_remapper->m_target_vertices.size(), -1 );
339 tgt_soln_gdofs.resize( m_remapper->m_target_vertices.size(), -1 );
340 MB_CHK_ERR( m_interface->tag_get_data( m_dofTagDest, m_remapper->m_target_vertices, &tgt_soln_gdofs[0] ) );
345 row_gdofmap.resize( m_remapper->m_target_entities.size() * tgtTagSize, UINT_MAX );
346 row_dtoc_dofmap.resize( m_remapper->m_target_entities.size() * tgtTagSize, -1 );
347 tgt_soln_gdofs.resize( m_remapper->m_target_entities.size() * tgtTagSize, -1 );
348 MB_CHK_ERR( m_interface->tag_get_data( m_dofTagDest, m_remapper->m_target_entities, &tgt_soln_gdofs[0] ) );
354 if( tgtdataGLLNodes ==
nullptr )
357 for(
unsigned i = 0; i < row_gdofmap.size(); ++i )
359 auto gdof = tgt_soln_gdofs[i];
361 row_gdofmap[i] = gdof - 1;
362 row_dtoc_dofmap[i] = i;
363 if( vprint ) std::cout <<
"Row: " << i <<
", " << row_gdofmap[i] <<
"\n";
369 if( isTgtContinuous ) dgll_cgll_row_ldofmap.resize( m_remapper->m_target_entities.size() * tgtTagSize,
false );
371 for(
unsigned j = 0; j < m_remapper->m_target_entities.size(); j++ )
373 for(
int p = 0; p < m_nDofsPEl_Dest; p++ )
375 for(
int q = 0; q < m_nDofsPEl_Dest; q++ )
377 const int localDOF = ( *tgtdataGLLNodes )[p][q][j] - 1;
378 const int offsetDOF = j * tgtTagSize + p * m_nDofsPEl_Dest + q;
379 if( isTgtContinuous && !dgll_cgll_row_ldofmap[localDOF] )
382 dgll_cgll_row_ldofmap[localDOF] =
true;
384 if( !isTgtContinuous ) m_nTotDofs_Dest++;
385 assert( tgt_soln_gdofs[offsetDOF] > 0 );
386 if( isTgtContinuous )
388 row_gdofmap[localDOF] = tgt_soln_gdofs[offsetDOF] - 1;
389 row_dtoc_dofmap[offsetDOF] = localDOF;
393 row_gdofmap[offsetDOF] = tgt_soln_gdofs[offsetDOF] - 1;
394 row_dtoc_dofmap[offsetDOF] = offsetDOF;
397 std::cout <<
"Row: " << offsetDOF <<
", " << localDOF <<
", " << row_gdofmap[offsetDOF] <<
", "
398 << m_nTotDofs_Dest <<
"\n";
405 #if defined( MOAB_HAVE_EIGEN3 ) && defined( VERBOSE )
408 std::cout <<
"[" << rank <<
"] DoFs: row = " << m_nTotDofs_Dest <<
" (gdofmap.size=" << row_gdofmap.size()
409 <<
"), col_src = " << m_nTotDofs_Src <<
", col_cov = " << m_nTotDofs_SrcCov
410 <<
" (gdofmap.size=" << col_gdofmap.size() <<
")\n";
415 #ifdef CHECK_INCREASING_DOF
416 for(
size_t i = 0; i < row_gdofmap.size() - 1; i++ )
418 if( row_gdofmap[i] > row_gdofmap[i + 1] )
419 std::cout <<
" on rank " << rank <<
" in row_gdofmap[" << i <<
"]=" << row_gdofmap[i] <<
" > row_gdofmap["
420 << i + 1 <<
"]=" << row_gdofmap[i + 1] <<
" \n";
422 for(
size_t i = 0; i < col_gdofmap.size() - 1; i++ )
424 if( col_gdofmap[i] > col_gdofmap[i + 1] )
425 std::cout <<
" on rank " << rank <<
" in col_gdofmap[" << i <<
"]=" << col_gdofmap[i] <<
" > col_gdofmap["
426 << i + 1 <<
"]=" << col_gdofmap[i + 1] <<
" \n";
442 col_dtoc_dofmap.resize( values_entities.size(), -1 );
443 for(
size_t j = 0; j < values_entities.size(); j++ )
446 const auto it = colMap.find( values_entities[j] - 1 );
447 if( it != colMap.end() ) col_dtoc_dofmap[j] = it->second;
456 row_dtoc_dofmap.resize( values_entities.size(), -1 );
457 for(
size_t j = 0; j < values_entities.size(); j++ )
460 const auto it = rowMap.find( values_entities[j] - 1 );
461 if( it != rowMap.end() ) row_dtoc_dofmap[j] = it->second;
469 std::vector< bool >& delivered )
471 delivered.assign( ncols,
false );
472 for(
size_t k = 0; k < col_dtoc_dofmap.size(); k++ )
474 const int mc = col_dtoc_dofmap[k];
475 if( mc >= 0 && mc < ncols ) delivered[mc] =
true;
481 first_absent_gid = -1;
482 const int ncols = m_nTotDofs_SrcCov;
483 std::vector< bool > delivered;
486 for(
int mc = 0; mc < ncols; mc++ )
491 if( first_absent_gid < 0 && mc < (
int)col_gdofmap.size() )
492 first_absent_gid = (int)col_gdofmap[mc] + 1;
500 const int ncols = m_nTotDofs_SrcCov;
501 std::vector< bool > delivered;
509 for(
int r = 0; r < m_weightMatrix.outerSize(); r++ )
511 for( WeightMatrix::InnerIterator it( m_weightMatrix, r ); it; ++it )
513 const int mc = (int)it.col();
514 if( mc < 0 || mc >= ncols || !delivered[mc] )
516 if( it.value() != 0.0 ) dropped++;
522 m_weightMatrix.prune( [](
const Eigen::Index&,
const Eigen::Index&,
const double& v ) {
return v != 0.0; } );
528 std::string strOutputType,
529 const GenerateOfflineMapAlgorithmOptions& mapOptions,
530 const std::string& srcDofTagName,
531 const std::string& tgtDofTagName )
533 #ifdef MOAB_HAVE_NETCDF
534 NcError
error( NcError::silent_nonfatal );
538 dbgprint.set_prefix(
"[TempestOnlineMap]: " );
541 const bool m_bPointCloudSource = ( m_remapper->point_cloud_source );
542 const bool m_bPointCloudTarget = ( m_remapper->point_cloud_target );
543 const bool m_bPointCloud = m_bPointCloudSource || m_bPointCloudTarget;
552 STLStringHelper::ToLower( strInputType );
553 STLStringHelper::ToLower( strOutputType );
558 if( strInputType ==
"fv" )
560 eInputType = DiscretizationType_FV;
562 else if( strInputType ==
"cgll" )
564 eInputType = DiscretizationType_CGLL;
566 else if( strInputType ==
"dgll" )
568 eInputType = DiscretizationType_DGLL;
570 else if( strInputType ==
"pcloud" )
572 eInputType = DiscretizationType_PCLOUD;
576 _EXCEPTION1(
"Invalid \"in_type\" value (%s), expected [fv|cgll|dgll]", strInputType.c_str() );
579 if( strOutputType ==
"fv" )
581 eOutputType = DiscretizationType_FV;
583 else if( strOutputType ==
"cgll" )
585 eOutputType = DiscretizationType_CGLL;
587 else if( strOutputType ==
"dgll" )
589 eOutputType = DiscretizationType_DGLL;
591 else if( strOutputType ==
"pcloud" )
593 eOutputType = DiscretizationType_PCLOUD;
597 _EXCEPTION1(
"Invalid \"out_type\" value (%s), expected [fv|cgll|dgll]", strOutputType.c_str() );
601 m_bConserved = !mapOptions.fNoConservation;
602 m_eInputType = eInputType;
603 m_eOutputType = eOutputType;
606 std::string strMapAlgorithm(
"" );
607 int nMonotoneType = ( mapOptions.fMonotone ) ? ( 1 ) : ( 0 );
610 std::set< std::string > setMethodStrings;
613 for(
size_t i = 0; i <= mapOptions.strMethod.length(); i++ )
615 if( ( i == mapOptions.strMethod.length() ) || ( mapOptions.strMethod[i] ==
';' ) )
617 std::string strMethodString = mapOptions.strMethod.substr( iLast, i - iLast );
618 STLStringHelper::RemoveWhitespaceInPlace( strMethodString );
619 if( strMethodString.length() > 0 )
621 setMethodStrings.insert( strMethodString );
628 for(
const auto& it : setMethodStrings )
633 if( ( m_eInputType == DiscretizationType_FV ) && ( m_eOutputType == DiscretizationType_FV ) )
635 _EXCEPTIONT(
"--method \"mono2\" is only used when remapping to/from CGLL or DGLL grids" );
641 else if( it ==
"mono3" )
643 if( ( m_eInputType == DiscretizationType_FV ) && ( m_eOutputType == DiscretizationType_FV ) )
645 _EXCEPTIONT(
"--method \"mono3\" is only used when remapping to/from CGLL or DGLL grids" );
651 else if( it ==
"volumetric" )
653 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType == DiscretizationType_FV ) )
655 _EXCEPTIONT(
"--method \"volumetric\" may only be used for FV->CGLL or FV->DGLL remapping" );
657 strMapAlgorithm =
"volumetric";
661 else if( it ==
"invdist" )
663 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
665 _EXCEPTIONT(
"--method \"invdist\" may only be used for FV->FV remapping" );
667 strMapAlgorithm =
"invdist";
671 else if( it ==
"delaunay" )
673 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
675 _EXCEPTIONT(
"--method \"delaunay\" may only be used for FV->FV remapping" );
677 strMapAlgorithm =
"delaunay";
681 else if( it ==
"bilin" )
683 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
685 _EXCEPTIONT(
"--method \"bilin\" may only be used for FV->FV remapping" );
687 strMapAlgorithm =
"fvbilin";
691 else if( it ==
"intbilin" )
693 if( m_eOutputType != DiscretizationType_FV )
695 _EXCEPTIONT(
"--method \"intbilin\" may only be used when mapping to FV." );
697 if( m_eInputType == DiscretizationType_FV )
699 strMapAlgorithm =
"fvintbilin";
703 strMapAlgorithm =
"mono3";
708 else if( it ==
"intbilingb" )
710 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
712 _EXCEPTIONT(
"--method \"intbilingb\" may only be used for FV->FV remapping" );
714 strMapAlgorithm =
"fvintbilingb";
718 _EXCEPTION1(
"Invalid --method argument \"%s\"", it.c_str() );
723 ( m_eInputType == DiscretizationType_FV || m_eInputType == DiscretizationType_PCLOUD ? 1
726 ( m_eOutputType == DiscretizationType_FV || m_eOutputType == DiscretizationType_PCLOUD ? 1
727 : mapOptions.nPout );
730 MB_CHK_ERR( SetDOFmapTags( srcDofTagName, tgtDofTagName ) );
734 rval = m_interface->tag_get_handle(
"aream", 1,
MB_TYPE_DOUBLE, areaTag,
738 if( is_root )
dbgprint.printf( 0,
"aream tag already defined \n" );
741 double local_areas[3] = { 0.0, 0.0, 0.0 }, global_areas[3] = { 0.0, 0.0, 0.0 };
742 if( !m_bPointCloudSource )
745 if( is_root )
dbgprint.printf( 0,
"Calculating input mesh Face areas\n" );
746 local_areas[0] = m_meshInput->CalculateFaceAreas( mapOptions.fSourceConcave );
748 MB_CHK_ERR( m_interface->tag_set_data( areaTag, m_remapper->m_source_entities, m_meshInput->vecFaceArea ) );
751 m_meshInputCov->CalculateFaceAreas( mapOptions.fSourceConcave );
754 if( !m_bPointCloudTarget )
757 if( is_root )
dbgprint.printf( 0,
"Calculating output mesh Face areas\n" );
758 local_areas[1] = m_meshOutput->CalculateFaceAreas( mapOptions.fTargetConcave );
761 m_interface->tag_set_data( areaTag, m_remapper->m_target_entities, m_meshOutput->vecFaceArea ) );
770 assert( m_meshOverlap->vecSourceFaceIx.size() == m_meshOverlap->vecTargetFaceIx.size() );
772 if( is_root )
dbgprint.printf( 0,
"Calculating overlap mesh Face areas\n" );
774 m_meshOverlap->CalculateFaceAreas( mapOptions.fSourceConcave || mapOptions.fTargetConcave );
785 if( m_pcomm && is_parallel )
787 double ghost_area = 0.0;
788 for(
size_t iover = 0; iover < m_meshOverlap->faces.size(); iover++ )
789 if( m_meshOverlap->vecTargetFaceIx[iover] < 0 ) ghost_area += m_meshOverlap->vecFaceArea[iover];
790 local_areas[2] -= ghost_area;
796 std::copy( local_areas, local_areas + 3, global_areas );
799 if( m_pcomm && is_parallel )
800 MPI_Reduce( local_areas, global_areas, 3, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
804 dbgprint.printf( 0,
"Input Mesh Geometric Area: %1.15e\n", global_areas[0] );
805 dbgprint.printf( 0,
"Output Mesh Geometric Area: %1.15e\n", global_areas[1] );
806 if (m_meshOverlap)
dbgprint.printf( 0,
"Overlap Mesh Recovered Area: %1.15e\n", global_areas[2] );
810 constexpr
bool fCorrectAreas =
true;
811 if( fCorrectAreas && m_meshOverlap )
813 if( is_root )
dbgprint.printf( 0,
"Correcting source/target areas to overlap mesh areas\n" );
814 DataArray1D< double > dSourceArea( m_meshInputCov->faces.size() );
815 DataArray1D< double > dTargetArea( m_meshOutput->faces.size() );
817 assert( m_meshOverlap->vecSourceFaceIx.size() == m_meshOverlap->faces.size() );
818 assert( m_meshOverlap->vecTargetFaceIx.size() == m_meshOverlap->faces.size() );
819 assert( m_meshOverlap->vecFaceArea.GetRows() == m_meshOverlap->faces.size() );
821 assert( m_meshInputCov->vecFaceArea.GetRows() == m_meshInputCov->faces.size() );
822 assert( m_meshOutput->vecFaceArea.GetRows() == m_meshOutput->faces.size() );
824 for(
size_t i = 0; i < m_meshOverlap->faces.size(); i++ )
826 if( m_meshOverlap->vecSourceFaceIx[i] < 0 || m_meshOverlap->vecTargetFaceIx[i] < 0 )
830 assert(
static_cast< size_t >( m_meshOverlap->vecSourceFaceIx[i] ) < m_meshInputCov->faces.size() );
831 dSourceArea[m_meshOverlap->vecSourceFaceIx[i]] += m_meshOverlap->vecFaceArea[i];
832 assert(
static_cast< size_t >( m_meshOverlap->vecTargetFaceIx[i] ) < m_meshOutput->faces.size() );
833 dTargetArea[m_meshOverlap->vecTargetFaceIx[i]] += m_meshOverlap->vecFaceArea[i];
852 const bool regional = ( m_remapper !=
nullptr && m_remapper->IsRegionalMesh() );
854 auto accept_area = [regional](
double accumulated,
double geometric ) ->
bool {
855 if( regional )
return accumulated > 0.0;
856 return fabs( accumulated - geometric ) < 1.0e-10;
859 size_t nUncoveredTarget = 0;
860 for(
size_t i = 0; i < m_meshInputCov->faces.size(); i++ )
862 if( accept_area( dSourceArea[i], m_meshInputCov->vecFaceArea[i] ) )
863 m_meshInputCov->vecFaceArea[i] = dSourceArea[i];
865 for(
size_t i = 0; i < m_meshOutput->faces.size(); i++ )
867 if( accept_area( dTargetArea[i], m_meshOutput->vecFaceArea[i] ) )
868 m_meshOutput->vecFaceArea[i] = dTargetArea[i];
869 else if( regional && dTargetArea[i] <= 0.0 )
885 size_t nUncovered = nUncoveredTarget;
887 if( m_pcomm && is_parallel )
889 size_t local = nUncoveredTarget;
890 MPI_Reduce( &local, &nUncovered, 1, MPI_UNSIGNED_LONG, MPI_SUM, 0, m_pcomm->comm() );
893 if( is_root && nUncovered > 0 )
895 "Regional mesh: %zu target cells have no overlap coverage; their areas "
896 "are left geometric and their map rows will be empty\n",
902 if( !m_bPointCloudSource && eInputType == DiscretizationType_FV )
904 this->SetSourceAreas( m_meshInputCov->vecFaceArea );
905 if( m_meshInputCov->vecMask.size() )
907 this->SetSourceMask( m_meshInputCov->vecMask );
912 if( !m_bPointCloudTarget && eOutputType == DiscretizationType_FV )
914 this->SetTargetAreas( m_meshOutput->vecFaceArea );
915 if( m_meshOutput->vecMask.size() )
917 this->SetTargetMask( m_meshOutput->vecMask );
931 if( ( eInputType == DiscretizationType_FV ) && ( eOutputType == DiscretizationType_FV ) )
934 if( m_meshInputCov->revnodearray.size() == 0 ) m_meshInputCov->ConstructReverseNodeArray();
935 if( m_meshInputCov->edgemap.size() == 0 ) m_meshInputCov->ConstructEdgeMap(
false );
938 this->InitializeSourceCoordinatesFromMeshFV( *m_meshInputCov );
939 this->InitializeTargetCoordinatesFromMeshFV( *m_meshOutput );
941 this->m_pdataGLLNodesIn =
nullptr;
942 this->m_pdataGLLNodesOut =
nullptr;
945 MB_CHK_ERR( this->SetDOFmapAssociation( eInputType, mapOptions.nPin,
false,
nullptr,
nullptr, eOutputType,
946 mapOptions.nPout,
false,
nullptr ) );
949 if( is_root )
dbgprint.printf( 0,
"Calculating remap weights\n" );
952 if( strMapAlgorithm ==
"invdist" )
954 if( m_meshInputCov->faces.size() )
956 if( is_root )
dbgprint.printf( 0,
"Calculating map (invdist)\n" );
957 LinearRemapFVtoFVInvDist( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *
this );
960 else if( strMapAlgorithm ==
"delaunay" )
962 if( m_meshInputCov->faces.size() )
964 if( is_root )
dbgprint.printf( 0,
"Calculating map (delaunay)\n" );
965 if (m_meshOverlap) LinearRemapTriangulation( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *
this );
969 LinearRemapTriangulation( *m_meshInputCov, *m_meshOutput, dummy, *
this );
973 else if( strMapAlgorithm ==
"fvintbilin" )
975 if( m_meshInputCov->faces.size() )
977 if( is_root )
dbgprint.printf( 0,
"Calculating map (intbilin)\n" );
978 LinearRemapIntegratedBilinear( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *
this );
981 else if( strMapAlgorithm ==
"fvintbilingb" )
983 if( m_meshInputCov->faces.size() )
985 if( is_root )
dbgprint.printf( 0,
"Calculating map (intbilingb)\n" );
986 LinearRemapIntegratedGeneralizedBarycentric( *m_meshInputCov, *m_meshOutput, *m_meshOverlap,
990 else if( strMapAlgorithm ==
"fvbilin" )
995 m_meshInputCov->Write(
"SourceMeshMBTR.g" );
996 m_meshOutput->Write(
"TargetMeshMBTR.g" );
1000 m_meshInputCov->Write(
"SourceMeshMBTR" + std::to_string( rank ) +
".g" );
1001 m_meshOutput->Write(
"TargetMeshMBTR" + std::to_string( rank ) +
".g" );
1005 if( m_meshInputCov->faces.size() )
1007 if( is_root )
dbgprint.printf( 0,
"Calculating map (bilin)\n" );
1008 if (m_meshOverlap) LinearRemapBilinear( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *
this );
1012 LinearRemapBilinear( *m_meshInputCov, *m_meshOutput, dummy, *
this );
1018 if( is_root )
dbgprint.printf( 0,
"Calculating conservative FV-FV map\n" );
1019 if( m_meshInputCov->faces.size() )
1021 #ifdef USE_NATIVE_TEMPESTREMAP_ROUTINES
1022 LinearRemapFVtoFV( *m_meshInputCov, *m_meshOutput, *m_meshOverlap,
1023 ( mapOptions.fMonotone ) ? ( 1 ) : ( mapOptions.nPin ), *
this );
1025 LinearRemapFVtoFV_Tempest_MOAB( ( mapOptions.fMonotone ? 1 : mapOptions.nPin ) );
1030 else if( eInputType == DiscretizationType_FV )
1032 DataArray3D< double > dataGLLJacobian;
1034 if( is_root )
dbgprint.printf( 0,
"Generating output mesh meta data\n" );
1035 double dNumericalArea_loc = GenerateMetaData( *m_meshOutput, mapOptions.nPout, mapOptions.fNoBubble,
1036 dataGLLNodesDest, dataGLLJacobian );
1038 double dNumericalArea = dNumericalArea_loc;
1039 #ifdef MOAB_HAVE_MPI
1041 MPI_Reduce( &dNumericalArea_loc, &dNumericalArea, 1, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
1043 if( is_root )
dbgprint.printf( 0,
"Output Mesh Numerical Area: %1.15e\n", dNumericalArea );
1046 this->InitializeSourceCoordinatesFromMeshFV( *m_meshInputCov );
1047 this->InitializeTargetCoordinatesFromMeshFE( *m_meshOutput, mapOptions.nPout, dataGLLNodesDest );
1049 this->m_pdataGLLNodesIn =
nullptr;
1050 this->m_pdataGLLNodesOut = &dataGLLNodesDest;
1053 bool fContinuous = ( eOutputType == DiscretizationType_CGLL );
1055 if( eOutputType == DiscretizationType_CGLL )
1057 GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobian, this->GetTargetAreas() );
1061 GenerateDiscontinuousJacobian( dataGLLJacobian, this->GetTargetAreas() );
1065 if( m_meshInputCov->revnodearray.size() == 0 ) m_meshInputCov->ConstructReverseNodeArray();
1066 if( m_meshInputCov->edgemap.size() == 0 ) m_meshInputCov->ConstructEdgeMap(
false );
1069 MB_CHK_ERR( this->SetDOFmapAssociation( eInputType, mapOptions.nPin,
false,
nullptr,
nullptr, eOutputType,
1070 mapOptions.nPout, ( eOutputType == DiscretizationType_CGLL ),
1071 &dataGLLNodesDest ) );
1074 if( strMapAlgorithm ==
"volumetric" )
1076 if( is_root )
dbgprint.printf( 0,
"Calculating remapping weights for FV->GLL (volumetric)\n" );
1077 LinearRemapFVtoGLL_Volumetric( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesDest,
1078 dataGLLJacobian, this->GetTargetAreas(), mapOptions.nPin, *
this,
1079 nMonotoneType, fContinuous, mapOptions.fNoConservation );
1083 if( is_root )
dbgprint.printf( 0,
"Calculating remapping weights for FV->GLL\n" );
1084 LinearRemapFVtoGLL( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesDest, dataGLLJacobian,
1085 this->GetTargetAreas(), mapOptions.nPin, *
this, nMonotoneType, fContinuous,
1086 mapOptions.fNoConservation );
1089 else if( ( eInputType == DiscretizationType_PCLOUD ) || ( eOutputType == DiscretizationType_PCLOUD ) )
1091 DataArray3D< double > dataGLLJacobian;
1092 if( !m_bPointCloudSource )
1095 if( m_meshInputCov->revnodearray.size() == 0 ) m_meshInputCov->ConstructReverseNodeArray();
1096 if( m_meshInputCov->edgemap.size() == 0 ) m_meshInputCov->ConstructEdgeMap(
false );
1099 if( eInputType == DiscretizationType_FV )
1101 this->InitializeSourceCoordinatesFromMeshFV( *m_meshInputCov );
1105 if( is_root )
dbgprint.printf( 0,
"Generating input mesh meta data\n" );
1106 DataArray3D< double > dataGLLJacobianSrc;
1107 GenerateMetaData( *m_meshInputCov, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrcCov,
1109 GenerateMetaData( *m_meshInput, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrc,
1110 dataGLLJacobianSrc );
1115 if( !m_bPointCloudTarget )
1118 if( m_meshOutput->revnodearray.size() == 0 ) m_meshOutput->ConstructReverseNodeArray();
1119 if( m_meshOutput->edgemap.size() == 0 ) m_meshOutput->ConstructEdgeMap(
false );
1122 if( eOutputType == DiscretizationType_FV )
1124 this->InitializeSourceCoordinatesFromMeshFV( *m_meshOutput );
1128 if( is_root )
dbgprint.printf( 0,
"Generating output mesh meta data\n" );
1129 GenerateMetaData( *m_meshOutput, mapOptions.nPout, mapOptions.fNoBubble, dataGLLNodesDest,
1137 eInputType, mapOptions.nPin, ( eInputType == DiscretizationType_CGLL ),
1138 ( m_bPointCloudSource || eInputType == DiscretizationType_FV ?
nullptr : &dataGLLNodesSrcCov ),
1139 ( m_bPointCloudSource || eInputType == DiscretizationType_FV ?
nullptr : &dataGLLNodesSrc ),
1140 eOutputType, mapOptions.nPout, ( eOutputType == DiscretizationType_CGLL ),
1141 ( m_bPointCloudTarget ?
nullptr : &dataGLLNodesDest ) ) );
1144 if( is_root )
dbgprint.printf( 0,
"Calculating remap weights with Nearest-Neighbor method\n" );
1145 MB_CHK_ERR( LinearRemapNN_MOAB(
true ,
false ) );
1147 else if( ( eInputType != DiscretizationType_FV ) && ( eOutputType == DiscretizationType_FV ) )
1149 DataArray3D< double > dataGLLJacobianSrc, dataGLLJacobian;
1151 if( is_root )
dbgprint.printf( 0,
"Generating input mesh meta data\n" );
1153 GenerateMetaData( *m_meshInput, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrc,
1154 dataGLLJacobianSrc );
1155 GenerateMetaData( *m_meshInputCov, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrcCov,
1158 if( dataGLLNodesSrcCov.GetSubColumns() != m_meshInputCov->faces.size() )
1160 _EXCEPTIONT(
"Number of element does not match between metadata and "
1165 this->InitializeSourceCoordinatesFromMeshFE( *m_meshInputCov, mapOptions.nPin, dataGLLNodesSrcCov );
1166 this->InitializeTargetCoordinatesFromMeshFV( *m_meshOutput );
1169 bool fContinuousIn = ( eInputType == DiscretizationType_CGLL );
1171 if( eInputType == DiscretizationType_CGLL )
1173 GenerateUniqueJacobian( dataGLLNodesSrcCov, dataGLLJacobian, this->GetSourceAreas() );
1177 GenerateDiscontinuousJacobian( dataGLLJacobian, this->GetSourceAreas() );
1181 MB_CHK_ERR( this->SetDOFmapAssociation( eInputType, mapOptions.nPin,
1182 ( eInputType == DiscretizationType_CGLL ), &dataGLLNodesSrcCov,
1183 &dataGLLNodesSrc, eOutputType, mapOptions.nPout,
false,
nullptr ) );
1186 if( is_root )
dbgprint.printf( 0,
"Calculating remap weights\n" );
1188 if( strMapAlgorithm ==
"volumetric" )
1190 _EXCEPTIONT(
"Unimplemented: Volumetric currently unavailable for"
1194 this->m_pdataGLLNodesIn = &dataGLLNodesSrcCov;
1195 this->m_pdataGLLNodesOut =
nullptr;
1197 #ifdef USE_NATIVE_TEMPESTREMAP_ROUTINES
1198 LinearRemapSE4( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesSrcCov, dataGLLJacobian,
1199 nMonotoneType, fContinuousIn, mapOptions.fNoConservation, mapOptions.fSparseConstraints,
1202 LinearRemapSE4_Tempest_MOAB( dataGLLNodesSrcCov, dataGLLJacobian, nMonotoneType, fContinuousIn,
1203 mapOptions.fNoConservation, mapOptions.fSparseConstraints );
1206 else if( ( eInputType != DiscretizationType_FV ) && ( eOutputType != DiscretizationType_FV ) )
1208 DataArray3D< double > dataGLLJacobianIn, dataGLLJacobianSrc;
1209 DataArray3D< double > dataGLLJacobianOut;
1212 if( is_root )
dbgprint.printf( 0,
"Generating input mesh meta data\n" );
1214 GenerateMetaData( *m_meshInput, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrc,
1215 dataGLLJacobianSrc );
1217 GenerateMetaData( *m_meshInputCov, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrcCov,
1218 dataGLLJacobianIn );
1220 if( is_root )
dbgprint.printf( 0,
"Generating output mesh meta data\n" );
1221 GenerateMetaData( *m_meshOutput, mapOptions.nPout, mapOptions.fNoBubble, dataGLLNodesDest,
1222 dataGLLJacobianOut );
1225 this->InitializeSourceCoordinatesFromMeshFE( *m_meshInputCov, mapOptions.nPin, dataGLLNodesSrcCov );
1226 this->InitializeTargetCoordinatesFromMeshFE( *m_meshOutput, mapOptions.nPout, dataGLLNodesDest );
1229 bool fContinuousIn = ( eInputType == DiscretizationType_CGLL );
1231 if( eInputType == DiscretizationType_CGLL )
1233 GenerateUniqueJacobian( dataGLLNodesSrcCov, dataGLLJacobianIn, this->GetSourceAreas() );
1237 GenerateDiscontinuousJacobian( dataGLLJacobianIn, this->GetSourceAreas() );
1241 bool fContinuousOut = ( eOutputType == DiscretizationType_CGLL );
1243 if( eOutputType == DiscretizationType_CGLL )
1245 GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobianOut, this->GetTargetAreas() );
1249 GenerateDiscontinuousJacobian( dataGLLJacobianOut, this->GetTargetAreas() );
1253 MB_CHK_ERR( this->SetDOFmapAssociation( eInputType, mapOptions.nPin,
1254 ( eInputType == DiscretizationType_CGLL ), &dataGLLNodesSrcCov,
1255 &dataGLLNodesSrc, eOutputType, mapOptions.nPout,
1256 ( eOutputType == DiscretizationType_CGLL ), &dataGLLNodesDest ) );
1258 this->m_pdataGLLNodesIn = &dataGLLNodesSrcCov;
1259 this->m_pdataGLLNodesOut = &dataGLLNodesDest;
1262 if( is_root )
dbgprint.printf( 0,
"Calculating remap weights\n" );
1264 #ifdef USE_NATIVE_TEMPESTREMAP_ROUTINES
1265 LinearRemapGLLtoGLL_Integrated( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesSrcCov,
1266 dataGLLJacobianIn, dataGLLNodesDest, dataGLLJacobianOut,
1267 this->GetTargetAreas(), mapOptions.nPin, mapOptions.nPout, nMonotoneType,
1268 fContinuousIn, fContinuousOut, mapOptions.fSparseConstraints, *
this );
1270 LinearRemapGLLtoGLL2_MOAB( dataGLLNodesSrcCov, dataGLLJacobianIn, dataGLLNodesDest, dataGLLJacobianOut,
1271 this->GetTargetAreas(), mapOptions.nPin, mapOptions.nPout, nMonotoneType,
1272 fContinuousIn, fContinuousOut, mapOptions.fNoConservation );
1277 _EXCEPTIONT(
"Not implemented" );
1280 #ifdef MOAB_HAVE_EIGEN3
1281 copy_tempest_sparsemat_to_eigen3();
1284 #ifdef MOAB_HAVE_MPI
1289 MB_CHK_ERR( m_remapper->GetOverlapAugmentedEntities( ghostedEnts ) );
1291 MB_CHK_SET_ERR( m_interface->remove_entities( m_meshOverlapSet, ghostedEnts ),
1292 "Deleting ghosted entities failed" );
1296 if( !mapOptions.fNoCheck )
1298 if( is_root )
dbgprint.printf( 0,
"Verifying map" );
1299 this->IsConsistent( 1.0e-8 );
1300 if( !mapOptions.fNoConservation ) this->IsConservative( 1.0e-8 );
1302 if( nMonotoneType != 0 )
1304 this->IsMonotone( 1.0e-12 );
1308 catch( Exception& e )
1310 dbgprint.printf( 0,
"%s", e.ToString().c_str() );
1311 return ( moab::MB_FAILURE );
1315 return ( moab::MB_FAILURE );
1324 #ifndef MOAB_HAVE_MPI
1326 return OfflineMap::IsConsistent( dTolerance );
1331 DataArray1D< int > dataRows;
1332 DataArray1D< int > dataCols;
1333 DataArray1D< double > dataEntries;
1336 DataArray1D< double > dRowSums;
1337 m_mapRemap.GetEntries( dataRows, dataCols, dataEntries );
1338 dRowSums.Allocate( m_mapRemap.GetRows() );
1340 for(
unsigned i = 0; i < dataRows.GetRows(); i++ )
1342 dRowSums[dataRows[i]] += dataEntries[i];
1346 int fConsistent = 0;
1347 for(
unsigned i = 0; i < dRowSums.GetRows(); i++ )
1349 if( fabs( dRowSums[i] - 1.0 ) > dTolerance )
1352 int rowGID = row_gdofmap[i];
1353 Announce(
"TempestOnlineMap is not consistent in row %i (%1.15e)", rowGID, dRowSums[i] );
1358 int fConsistentGlobal = 0;
1359 ierr = MPI_Allreduce( &fConsistent, &fConsistentGlobal, 1, MPI_INT, MPI_SUM, m_pcomm->comm() );
1360 if( ierr != MPI_SUCCESS )
return -1;
1362 return fConsistentGlobal;
1370 #ifndef MOAB_HAVE_MPI
1372 return OfflineMap::IsConservative( dTolerance );
1379 DataArray1D< int > dataRows;
1380 DataArray1D< int > dataCols;
1381 DataArray1D< double > dataEntries;
1382 const DataArray1D< double >& dTargetAreas = this->GetTargetAreas();
1383 const DataArray1D< double >& dSourceAreas = this->GetSourceAreas();
1386 std::vector< int > dColumnsUnique;
1387 std::vector< double > dColumnSums;
1389 int nColumns = m_mapRemap.GetColumns();
1390 m_mapRemap.GetEntries( dataRows, dataCols, dataEntries );
1391 dColumnSums.resize( m_nTotDofs_SrcCov, 0.0 );
1392 dColumnsUnique.resize( m_nTotDofs_SrcCov, -1 );
1394 for(
unsigned i = 0; i < dataEntries.GetRows(); i++ )
1396 dColumnSums[dataCols[i]] += dataEntries[i] * dTargetAreas[dataRows[i]] / dSourceAreas[dataCols[i]];
1398 assert( dataCols[i] < m_nTotDofs_SrcCov );
1401 int colGID = this->GetColGlobalDoF( dataCols[i] );
1403 dColumnsUnique[dataCols[i]] = colGID;
1410 std::vector< int > nElementsInProc;
1411 const int nDATA = 3;
1412 nElementsInProc.resize( size * nDATA );
1413 int senddata[nDATA] = { nColumns, m_nTotDofs_SrcCov, m_nTotDofs_Src };
1414 ierr = MPI_Gather( senddata, nDATA, MPI_INT, nElementsInProc.data(), nDATA, MPI_INT, rootProc, m_pcomm->comm() );
1415 if( ierr != MPI_SUCCESS )
return -1;
1417 int nTotVals = 0, nTotColumns = 0;
1418 std::vector< int > dColumnIndices;
1419 std::vector< double > dColumnSumsTotal;
1420 std::vector< int > displs, rcount;
1421 if( rank == rootProc )
1423 displs.resize( size + 1, 0 );
1424 rcount.resize( size, 0 );
1426 for(
int ir = 0; ir < size; ++ir )
1428 nTotVals += nElementsInProc[ir * nDATA];
1429 nTotColumns += nElementsInProc[ir * nDATA + 1];
1433 rcount[ir] = nElementsInProc[ir * nDATA + 1];
1439 printf(
"Total nnz: %d, global source elements = %d\n", nTotVals, gsum );
1441 dColumnIndices.resize( nTotColumns, -1 );
1442 dColumnSumsTotal.resize( nTotColumns, 0.0 );
1456 ierr = MPI_Gatherv( dColumnsUnique.data(), m_nTotDofs_SrcCov, MPI_INT, dColumnIndices.data(), rcount.data(),
1457 displs.data(), MPI_INT, rootProc, m_pcomm->comm() );
1458 if( ierr != MPI_SUCCESS )
return -1;
1459 ierr = MPI_Gatherv( dColumnSums.data(), m_nTotDofs_SrcCov, MPI_DOUBLE, dColumnSumsTotal.data(), rcount.data(),
1460 displs.data(), MPI_DOUBLE, rootProc, m_pcomm->comm() );
1461 if( ierr != MPI_SUCCESS )
return -1;
1467 dColumnSums.clear();
1468 dColumnsUnique.clear();
1471 int fConservative = 0;
1472 if( rank == rootProc )
1474 displs[size] = ( nTotColumns );
1476 std::map< int, double > dColumnSumsOnRoot;
1478 for(
int ir = 0; ir < size; ir++ )
1480 for(
int ips = displs[ir]; ips < displs[ir + 1]; ips++ )
1482 if( dColumnIndices[ips] < 0 )
continue;
1485 dColumnSumsOnRoot[dColumnIndices[ips]] += dColumnSumsTotal[ips];
1491 for( std::map< int, double >::iterator it = dColumnSumsOnRoot.begin(); it != dColumnSumsOnRoot.end(); ++it )
1494 if( fabs( it->second - 1.0 ) > dTolerance )
1497 Announce(
"TempestOnlineMap is not conservative in column "
1500 it->first, it->second );
1506 ierr = MPI_Bcast( &fConservative, 1, MPI_INT, rootProc, m_pcomm->comm() );
1507 if( ierr != MPI_SUCCESS )
return -1;
1509 return fConservative;
1517 #ifndef MOAB_HAVE_MPI
1519 return OfflineMap::IsMonotone( dTolerance );
1524 DataArray1D< int > dataRows;
1525 DataArray1D< int > dataCols;
1526 DataArray1D< double > dataEntries;
1528 m_mapRemap.GetEntries( dataRows, dataCols, dataEntries );
1532 for(
unsigned i = 0; i < dataRows.GetRows(); i++ )
1534 if( ( dataEntries[i] < -dTolerance ) || ( dataEntries[i] > 1.0 + dTolerance ) )
1538 Announce(
"TempestOnlineMap is not monotone in entry (%i): %1.15e", i, dataEntries[i] );
1543 int fMonotoneGlobal = 0;
1544 ierr = MPI_Allreduce( &fMonotone, &fMonotoneGlobal, 1, MPI_INT, MPI_SUM, m_pcomm->comm() );
1545 if( ierr != MPI_SUCCESS )
return -1;
1547 return fMonotoneGlobal;
1555 const Range& entities,
1556 bool useMOABAdjacencies,
1559 assert( nrings > 0 );
1560 assert( useMOABAdjacencies || trMesh !=
nullptr );
1562 const size_t nrows = vecAdjFaces.size();
1569 if( useMOABAdjacencies )
1579 int adjIndex = entities.
index( *it );
1581 if( adjIndex >= 0 ) vecAdjFaces[
index].insert( adjIndex );
1591 GetAdjacentFaceVectorByEdge( *trMesh,
index, nrings *
face.edges.size(), adjFaces );
1594 for(
auto adjFace : adjFaces )
1595 if( adjFace.first >= 0 )
1596 vecAdjFaces[
index].insert( adjFace.first );
1606 double default_projection )
1608 std::vector< double > solSTagVals;
1609 std::vector< double > solTTagVals;
1612 if( m_remapper->point_cloud_source || m_remapper->point_cloud_target )
1614 if( m_remapper->point_cloud_source )
1617 solSTagVals.resize( covSrcEnts.
size(), default_projection );
1623 solSTagVals.resize( covSrcEnts.
size() * this->GetSourceNDofsPerElement() * this->GetSourceNDofsPerElement(),
1624 default_projection );
1627 if( m_remapper->point_cloud_target )
1630 solTTagVals.resize( tgtEnts.
size(), default_projection );
1636 solTTagVals.resize( tgtEnts.
size() * this->GetDestinationNDofsPerElement() *
1637 this->GetDestinationNDofsPerElement(),
1638 default_projection );
1646 solSTagVals.resize( covSrcEnts.
size() * this->GetSourceNDofsPerElement() * this->GetSourceNDofsPerElement(),
1647 default_projection );
1648 solTTagVals.resize( tgtEnts.
size() * this->GetDestinationNDofsPerElement() *
1649 this->GetDestinationNDofsPerElement(),
1650 default_projection );
1657 MB_CHK_SET_ERR( m_interface->tag_get_data( srcSolutionTag, sents, &solSTagVals[0] ),
1658 "Getting local tag data failed" );
1663 MB_CHK_SET_ERR( this->ApplyWeights( solSTagVals, solTTagVals, transpose ),
1664 "Applying remap operator onto source vector data failed" );
1667 MB_CHK_SET_ERR( m_interface->tag_set_data( tgtSolutionTag, tents, &solTTagVals[0] ),
1668 "Setting target tag data failed" );
1670 if( caasType != CAAS_NONE )
1672 std::string tgtSolutionTagName;
1673 MB_CHK_SET_ERR( m_interface->tag_get_name( tgtSolutionTag, tgtSolutionTagName ),
"Getting tag name failed" );
1676 constexpr
int nmax_caas_iterations = 10;
1677 double mismatch = 1.0;
1678 int caasIteration = 0;
1679 double initialMismatch = 0.0;
1680 while( ( fabs( mismatch / initialMismatch ) > 1e-15 && fabs( mismatch ) > 1e-15 ) &&
1681 caasIteration++ < nmax_caas_iterations )
1683 double dMassDiffPostGlobal;
1684 std::pair< double, double > mDefect =
1685 this->ApplyBoundsLimiting( solSTagVals, solTTagVals, caasType, caasIteration, mismatch );
1686 #ifdef MOAB_HAVE_MPI
1687 double dMassDiffPost = mDefect.second;
1688 MPI_Allreduce( &dMassDiffPost, &dMassDiffPostGlobal, 1, MPI_DOUBLE, MPI_SUM, m_pcomm->comm() );
1690 dMassDiffPostGlobal = mDefect.second;
1692 if( caasIteration == 1 ) initialMismatch = mDefect.first;
1693 if( m_remapper->verbose && is_root )
1695 printf(
"Field {%s} -> CAAS iteration: %d, mass defect: %3.4e, post-CAAS: %3.4e\n",
1696 tgtSolutionTagName.c_str(), caasIteration, mDefect.first, dMassDiffPostGlobal );
1698 mismatch = dMassDiffPostGlobal;
1701 MB_CHK_SET_ERR( m_interface->tag_set_data( tgtSolutionTag, tents, &solTTagVals[0] ),
1702 "Setting local tag data failed" );
1715 std::vector< double > solSTagVals, solTTagVals;
1718 if( m_remapper->point_cloud_source || m_remapper->point_cloud_target )
1720 if( m_remapper->point_cloud_source )
1723 solSTagVals.resize( covSrcEnts.
size(), 0.0 );
1729 solSTagVals.resize( covSrcEnts.
size() * this->GetSourceNDofsPerElement() *
1730 this->GetSourceNDofsPerElement(),
1734 if( m_remapper->point_cloud_target )
1737 solTTagVals.resize( tgtEnts.
size(), 0.0 );
1743 solTTagVals.resize( tgtEnts.
size() * this->GetDestinationNDofsPerElement() *
1744 this->GetDestinationNDofsPerElement(),
1753 solSTagVals.resize( covSrcEnts.
size() * this->GetSourceNDofsPerElement() * this->GetSourceNDofsPerElement(),
1756 tgtEnts.
size() * this->GetDestinationNDofsPerElement() * this->GetDestinationNDofsPerElement(), 0.0 );
1762 MB_CHK_SET_ERR( m_interface->tag_get_data( srcSolutionTag, sents, &solSTagVals[0] ),
1763 "Getting source tag data failed" );
1766 MB_CHK_SET_ERR( this->ApplyWeights( solSTagVals, solTTagVals,
false ),
1767 "High-order projection failed" );
1770 MB_CHK_SET_ERR( m_interface->tag_set_data( tgtSolutionTag, tents, &solTTagVals[0] ),
1771 "Setting target tag data failed" );
1773 if( caasType == CAAS_NONE || loWeightMap ==
nullptr )
return moab::MB_SUCCESS;
1867 const size_t nTargetDofs = solTTagVals.size();
1868 const size_t nSourceDofs = solSTagVals.size();
1873 if( row_dtoc_dofmap.size() < nTargetDofs )
1875 MB_CHK_SET_ERR( moab::MB_FAILURE,
"row_dtoc_dofmap smaller than target tag size" );
1879 std::vector< double > yLow( nTargetDofs, 0.0 );
1881 "Low-order projection failed" );
1939 std::vector< double > srcNorm8wt;
1940 bool hasNorm8wt =
false;
1943 moab::ErrorCode rvalN = m_interface->tag_get_handle(
"norm8wt", normTag );
1944 if(
MB_SUCCESS == rvalN && normTag !=
nullptr )
1952 srcNorm8wt.resize( sents.
size(), 0.0 );
1953 moab::ErrorCode rvalD = m_interface->tag_get_data( normTag, sents, &srcNorm8wt[0] );
1954 if(
MB_SUCCESS == rvalD && srcNorm8wt.size() == nSourceDofs )
1970 std::vector< double > lcl_lo( nTargetDofs, 1e308 );
1971 std::vector< double > lcl_hi( nTargetDofs, -1e308 );
1973 WeightMatrix& hiW = this->m_weightMatrix;
1974 for(
size_t i = 0; i < nTargetDofs; i++ )
1976 int r = row_dtoc_dofmap[i];
1977 if( r < 0 || r >= hiW.outerSize() )
continue;
1978 for( WeightMatrix::InnerIterator it( hiW, r ); it; ++it )
1983 int mc = (int)it.col();
1997 for(
size_t k = 0; k < nSourceDofs && k < col_dtoc_dofmap.size(); k++ )
1998 if( col_dtoc_dofmap[k] > maxMatCol ) maxMatCol = col_dtoc_dofmap[k];
1999 std::vector< int > col_inv( maxMatCol + 1, -1 );
2000 for(
size_t k = 0; k < nSourceDofs && k < col_dtoc_dofmap.size(); k++ )
2001 if( col_dtoc_dofmap[k] >= 0 ) col_inv[col_dtoc_dofmap[k]] = (int)k;
2010 int bndsLocalErr = 0;
2011 int bndsFirstRowG = -1;
2012 int bndsFirstMc = -1;
2013 double bndsFirstWgt = 0.0;
2014 int bndsFirstKind = 0;
2016 for(
size_t i = 0; i < nTargetDofs; i++ )
2018 int r = row_dtoc_dofmap[i];
2019 if( r < 0 || r >= hiW.outerSize() )
continue;
2020 for( WeightMatrix::InnerIterator it( hiW, r ); it; ++it )
2032 if( fabs( it.value() ) < 1e-50 )
continue;
2033 const int mc = (int)it.col();
2043 if( mc < 0 || mc > maxMatCol )
2048 bndsFirstRowG = (r >= 0 && r < (int)row_gdofmap.size()) ? (
int)row_gdofmap[r] : -1;
2050 bndsFirstWgt = it.value();
2055 const int srcIdx = col_inv[mc];
2061 bndsFirstRowG = (r >= 0 && r < (int)row_gdofmap.size()) ? (
int)row_gdofmap[r] : -1;
2063 bndsFirstWgt = it.value();
2068 if( srcIdx >= (
int)nSourceDofs )
2073 bndsFirstRowG = (r >= 0 && r < (int)row_gdofmap.size()) ? (
int)row_gdofmap[r] : -1;
2075 bndsFirstWgt = it.value();
2085 double v = solSTagVals[srcIdx];
2088 const double n = srcNorm8wt[srcIdx];
2089 if( fabs(n) < 1
E-20 )
continue;
2092 if( v < lcl_lo[i] ) lcl_lo[i] = v;
2093 if( v > lcl_hi[i] ) lcl_hi[i] = v;
2099 if( lcl_lo[i] > lcl_hi[i] )
2107 #ifdef MOAB_HAVE_MPI
2109 MPI_Comm comm = m_pcomm ? m_pcomm->comm() : MPI_COMM_SELF;
2110 int bndsGlobalErr = 0;
2111 MPI_Allreduce( &bndsLocalErr, &bndsGlobalErr, 1, MPI_INT, MPI_MAX, comm );
2115 MPI_Comm_rank( comm, &myRank );
2118 static const char* kindStr[4] = {
"?",
"mc>maxMatCol",
"col_inv[mc]==-1",
"srcIdx>=nSourceDofs" };
2120 "FATAL: ApplyWeightsWithDualMap bounds extraction dropped a nonzero "
2121 "high-order stencil column on rank %d.\n"
2122 " global_target_row=%d matrix_col=%d weight=%.17e reason=%s\n"
2123 " This means the source coverage on this rank does NOT contain a "
2124 "column the owned high-order row references — the 3-ring (or whatever) "
2125 "ghost layer setting is too narrow, or the map file was generated against "
2126 "a different mesh. Bounds computed over an incomplete stencil break BFB; "
2127 "aborting rather than silently producing wrong CAAS output.\n",
2128 myRank, bndsFirstRowG, bndsFirstMc, bndsFirstWgt, kindStr[bndsFirstKind] );
2131 MPI_Abort( comm, 1 );
2137 static const char* kindStr[4] = {
"?",
"mc>maxMatCol",
"col_inv[mc]==-1",
"srcIdx>=nSourceDofs" };
2139 "FATAL: ApplyWeightsWithDualMap bounds extraction dropped a nonzero "
2140 "high-order stencil column.\n"
2141 " global_target_row=%d matrix_col=%d weight=%.17e reason=%s\n",
2142 bndsFirstRowG, bndsFirstMc, bndsFirstWgt, kindStr[bndsFirstKind] );
2144 return moab::MB_FAILURE;
2152 for(
size_t i = 0; i < nTargetDofs; i++ )
2154 if( yLow[i] == 0.0 )
2156 solTTagVals[i] = 0.0;
2167 double g_lo = 1e308, g_hi = -1e308;
2168 for(
size_t i = 0; i < nTargetDofs; i++ )
2170 int r = row_dtoc_dofmap[i];
2171 if( r < 0 || r >= (
int)row_gdofmap.size() )
continue;
2172 if( lcl_lo[i] < g_lo ) g_lo = lcl_lo[i];
2173 if( lcl_hi[i] > g_hi ) g_hi = lcl_hi[i];
2175 #ifdef MOAB_HAVE_MPI
2177 MPI_Comm comm = m_pcomm ? m_pcomm->comm() : MPI_COMM_SELF;
2178 double tmp_min = g_lo, tmp_max = g_hi;
2179 MPI_Allreduce( &tmp_min, &g_lo, 1, MPI_DOUBLE, MPI_MIN, comm );
2180 MPI_Allreduce( &tmp_max, &g_hi, 1, MPI_DOUBLE, MPI_MAX, comm );
2193 std::vector< double > mappedNorm8wt( nTargetDofs, 0.0 );
2197 "Mapped-norm8wt computation (low-order on source norm8wt) failed" );
2201 std::vector< double > srcOnes( nSourceDofs, 1.0 );
2203 "Mapped-norm8wt computation (low-order on ones) failed" );
2216 for(
size_t i = 0; i < nTargetDofs; i++ )
2218 const double w = mappedNorm8wt[i];
2236 std::vector< double > tgtAreas( nTargetDofs, 0.0 );
2238 std::vector< moab::EntityHandle > tentVec;
2239 tentVec.reserve( tents.
size() );
2241 tentVec.push_back( *it );
2243 bool got_areas =
false;
2249 moab::ErrorCode rval = m_interface->tag_get_handle(
"aream", aream_tag );
2250 if(
MB_SUCCESS == rval && aream_tag !=
nullptr && !tentVec.empty() )
2252 const size_t nents = std::min< size_t >( tentVec.size(), nTargetDofs );
2253 std::vector< double > aream_vals( nents, 0.0 );
2254 rval = m_interface->tag_get_data( aream_tag, &tentVec[0], (
int)nents, &aream_vals[0] );
2257 for(
size_t i = 0; i < nents; i++ ) tgtAreas[i] = aream_vals[i];
2268 const DataArray1D< double >& dTargetAreas = this->GetTargetAreas();
2269 const size_t nRows = dTargetAreas.GetRows();
2270 if( nRows >= nTargetDofs )
2272 for(
size_t i = 0; i < nTargetDofs; i++ )
2274 int r = row_dtoc_dofmap[i];
2275 if( r >= 0 && (
size_t)r < nRows )
2276 tgtAreas[i] = dTargetAreas[r];
2287 "ApplyWeightsWithDualMap: no target-cell areas available. "
2288 "Neither the 'aream' tag (from iMOAB_LoadMapFile with "
2289 "arearead != 0) nor OfflineMap::GetTargetAreas() (from an "
2290 "online map build) provided areas. Recomputing areas from "
2291 "mesh geometry is not bit-for-bit with MCT and is no longer "
2292 "permitted in the CAAS path. Re-load the map file with an "
2293 "area-bearing arearead setting (e.g. arearead=3 for F-maps), "
2294 "or build the online map so target areas are populated." );
2301 std::vector< int > rowGids( nTargetDofs, -1 );
2302 std::vector< double > massLowPerRow( nTargetDofs, 0.0 );
2303 std::vector< double > massHiUnclippedPerRow( nTargetDofs, 0.0 );
2304 std::vector< double > clipDefectPerRow( nTargetDofs, 0.0 );
2305 std::vector< double > capLowPerRow( nTargetDofs, 0.0 );
2306 std::vector< double > capHighPerRow( nTargetDofs, 0.0 );
2308 for(
size_t i = 0; i < nTargetDofs; i++ )
2310 int r = row_dtoc_dofmap[i];
2311 if( r < 0 || r >= (
int)row_gdofmap.size() )
2314 rowGids[i] = (int)row_gdofmap[r];
2316 const double area = tgtAreas[i];
2317 const double y = solTTagVals[i];
2318 const double lo = lcl_lo[i];
2319 const double hi = lcl_hi[i];
2325 dm = ( y - lo ) * area;
2330 dm = ( y - hi ) * area;
2332 clipDefectPerRow[i] = dm;
2333 capLowPerRow[i] = ( yc - lo ) * area;
2334 capHighPerRow[i] = ( hi - yc ) * area;
2335 massLowPerRow[i] = yLow[i] * area;
2343 massHiUnclippedPerRow[i] = y * area;
2345 solTTagVals[i] = yc;
2360 #ifdef MOAB_HAVE_MPI
2361 MPI_Comm reduce_comm = m_pcomm ? m_pcomm->comm() : MPI_COMM_SELF;
2363 int reduce_comm = 0;
2365 #ifdef MOAB_HAVE_MPI
2371 const std::vector< int >& reduce_mask = rowGids;
2378 const std::vector< std::vector< double > > caasFields = {
2379 massLowPerRow, massHiUnclippedPerRow, clipDefectPerRow,
2380 capLowPerRow, capHighPerRow };
2381 std::vector< double > caasGsums;
2383 const double M_low = caasGsums[0];
2384 const double M_hi_unclipped = caasGsums[1];
2385 const double dM_clip = caasGsums[2];
2386 const double cap_low_g = caasGsums[3];
2387 const double cap_high_g = caasGsums[4];
2410 const double diff = M_low - M_hi_unclipped;
2411 const double dM_total = dM_clip + diff;
2426 if( dM_total > 0.0 && cap_high_g > 0.0 )
2428 for(
size_t i = 0; i < nTargetDofs; i++ )
2430 const double area = tgtAreas[i];
2431 const double yc = solTTagVals[i];
2433 solTTagVals[i] = yc + ( ( lcl_hi[i] - yc ) / cap_high_g ) * dM_total;
2436 else if( dM_total < 0.0 && cap_low_g > 0.0 )
2438 for(
size_t i = 0; i < nTargetDofs; i++ )
2440 const double area = tgtAreas[i];
2441 const double yc = solTTagVals[i];
2443 solTTagVals[i] = yc + ( ( yc - lcl_lo[i] ) / cap_low_g ) * dM_total;
2459 for(
size_t i = 0; i < nTargetDofs; i++ )
2461 if( fabs(yLow[i]) < 1
E-40 )
continue;
2462 if( solTTagVals[i] < g_lo ) solTTagVals[i] = g_lo;
2463 if( solTTagVals[i] > g_hi ) solTTagVals[i] = g_hi;
2467 MB_CHK_SET_ERR( m_interface->tag_set_data( tgtSolutionTag, tents, &solTTagVals[0] ),
2468 "Setting target tag data failed" );
2474 const std::string& solnName,
2476 sample_function testFunction,
2478 std::string cloneSolnName )
2480 const bool outputEnabled = ( is_root );
2490 trmesh = m_remapper->m_covering_source;
2491 entities = ( m_remapper->point_cloud_source ? m_remapper->m_covering_source_vertices
2492 : m_remapper->m_covering_source_entities );
2493 discOrder = m_nDofsPEl_Src;
2494 discMethod = m_eInputType;
2499 trmesh = m_remapper->m_target;
2501 ( m_remapper->point_cloud_target ? m_remapper->m_target_vertices : m_remapper->m_target_entities );
2502 discOrder = m_nDofsPEl_Dest;
2503 discMethod = m_eOutputType;
2508 std::cout <<
"Invalid context specified for defining an analytical solution tag" << std::endl;
2509 return moab::MB_FAILURE;
2516 if( clonedSolnTag !=
nullptr )
2518 if( cloneSolnName.size() == 0 )
2520 cloneSolnName = solnName + std::string(
"Cloned" );
2527 const int TriQuadratureOrder = 10;
2529 if( outputEnabled ) std::cout <<
"Using triangular quadrature of order " << TriQuadratureOrder << std::endl;
2531 TriangularQuadratureRule triquadrule( TriQuadratureOrder );
2533 const int TriQuadraturePoints = triquadrule.GetPoints();
2535 const DataArray2D< double >& TriQuadratureG = triquadrule.GetG();
2536 const DataArray1D< double >& TriQuadratureW = triquadrule.GetW();
2539 DataArray1D< double > dVar;
2540 DataArray1D< double > dVarMB;
2543 DataArray1D< double > dNodeArea;
2548 if( discMethod == DiscretizationType_CGLL || discMethod == DiscretizationType_DGLL )
2551 const bool fGLL =
true;
2552 const bool fGLLIntegrate =
false;
2555 DataArray3D< int > dataGLLNodes;
2556 DataArray3D< double > dataGLLJacobian;
2558 GenerateMetaData( *trmesh, discOrder,
false, dataGLLNodes, dataGLLJacobian );
2561 int nElements = trmesh->faces.size();
2564 for(
int k = 0; k < nElements; k++ )
2566 const Face&
face = trmesh->faces[k];
2568 if(
face.edges.size() != 4 )
2570 _EXCEPTIONT(
"Non-quadrilateral face detected; "
2571 "incompatible with --gll" );
2576 const bool fDiscontinuous = ( discMethod == DiscretizationType_DGLL );
2578 if( fDiscontinuous )
2581 iMaxNode = nElements * discOrder * discOrder;
2586 for(
int i = 0; i < discOrder; i++ )
2587 for(
int j = 0; j < discOrder; j++ )
2588 for(
int k = 0; k < nElements; k++ )
2589 if( dataGLLNodes[i][j][k] > iMaxNode )
2590 iMaxNode = dataGLLNodes[i][j][k];
2594 DataArray1D< double > dG;
2595 DataArray1D< double > dW;
2597 GaussLobattoQuadrature::GetPoints( discOrder, 0.0, 1.0, dG, dW );
2600 const int nGaussP = 10;
2602 DataArray1D< double > dGaussG;
2603 DataArray1D< double > dGaussW;
2605 GaussQuadrature::GetPoints( nGaussP, 0.0, 1.0, dGaussG, dGaussW );
2608 dVar.Allocate( iMaxNode );
2609 dVarMB.Allocate( discOrder * discOrder * nElements );
2610 dNodeArea.Allocate( iMaxNode );
2613 for(
int k = 0; k < nElements; k++ )
2615 const Face&
face = trmesh->faces[k];
2620 for(
int i = 0; i < discOrder; i++ )
2622 for(
int j = 0; j < discOrder; j++ )
2630 ApplyLocalMap(
face, trmesh->nodes, dG[i], dG[j], node, dDx1G, dDx2G );
2633 double dNodeLon = atan2( node.y, node.x );
2634 if( dNodeLon < 0.0 )
2636 dNodeLon += 2.0 * M_PI;
2638 double dNodeLat = asin( node.z );
2640 double dSample = ( *testFunction )( dNodeLon, dNodeLat );
2642 if( fDiscontinuous )
2643 dVar[k * discOrder * discOrder + j * discOrder + i] = dSample;
2645 dVar[dataGLLNodes[j][i][k] - 1] = dSample;
2652 DataArray2D< double > dCoeff( discOrder, discOrder );
2654 for(
int p = 0; p < nGaussP; p++ )
2656 for(
int q = 0; q < nGaussP; q++ )
2664 ApplyLocalMap(
face, trmesh->nodes, dGaussG[p], dGaussG[q], node, dDx1G, dDx2G );
2667 Node nodeCross = CrossProduct( dDx1G, dDx2G );
2670 sqrt( nodeCross.x * nodeCross.x + nodeCross.y * nodeCross.y + nodeCross.z * nodeCross.z );
2674 SampleGLLFiniteElement( 0, discOrder, dGaussG[p], dGaussG[q], dCoeff );
2677 double dNodeLon = atan2( node.y, node.x );
2678 if( dNodeLon < 0.0 )
2680 dNodeLon += 2.0 * M_PI;
2682 double dNodeLat = asin( node.z );
2684 double dSample = ( *testFunction )( dNodeLon, dNodeLat );
2687 for(
int i = 0; i < discOrder; i++ )
2689 for(
int j = 0; j < discOrder; j++ )
2692 double dNodalArea = dCoeff[i][j] * dGaussW[p] * dGaussW[q] * dJacobian;
2694 dVar[dataGLLNodes[i][j][k] - 1] += dSample * dNodalArea;
2696 dNodeArea[dataGLLNodes[i][j][k] - 1] += dNodalArea;
2707 for(
size_t i = 0; i < dVar.GetRows(); i++ )
2709 dVar[i] /= dNodeArea[i];
2716 for(
unsigned j = 0; j < entities.
size(); j++ )
2717 for(
int p = 0; p < discOrder; p++ )
2718 for(
int q = 0; q < discOrder; q++ )
2720 const int offsetDOF = j * discOrder * discOrder + p * discOrder + q;
2721 dVarMB[offsetDOF] = dVar[col_dtoc_dofmap[offsetDOF]];
2726 for(
unsigned j = 0; j < entities.
size(); j++ )
2727 for(
int p = 0; p < discOrder; p++ )
2728 for(
int q = 0; q < discOrder; q++ )
2730 const int offsetDOF = j * discOrder * discOrder + p * discOrder + q;
2731 dVarMB[offsetDOF] = dVar[row_dtoc_dofmap[offsetDOF]];
2736 MB_CHK_ERR( m_interface->tag_set_data( solnTag, entities, &dVarMB[0] ) );
2741 if( discMethod == DiscretizationType_FV )
2746 dVar.Allocate( trmesh->faces.size() );
2748 std::vector< Node >& nodes = trmesh->nodes;
2751 for(
size_t i = 0; i < trmesh->faces.size(); i++ )
2753 const Face&
face = trmesh->faces[i];
2756 for(
size_t j = 0; j <
face.edges.size() - 2; j++ )
2759 const Node& node0 = nodes[
face[0]];
2760 const Node& node1 = nodes[
face[j + 1]];
2761 const Node& node2 = nodes[
face[j + 2]];
2765 faceTri.SetNode( 0,
face[0] );
2766 faceTri.SetNode( 1,
face[j + 1] );
2767 faceTri.SetNode( 2,
face[j + 2] );
2769 double dTriangleArea = CalculateFaceArea( faceTri, nodes );
2772 double dTotalSample = 0.0;
2775 for(
int k = 0; k < TriQuadraturePoints; k++ )
2777 Node node( TriQuadratureG[k][0] * node0.x + TriQuadratureG[k][1] * node1.x +
2778 TriQuadratureG[k][2] * node2.x,
2779 TriQuadratureG[k][0] * node0.y + TriQuadratureG[k][1] * node1.y +
2780 TriQuadratureG[k][2] * node2.y,
2781 TriQuadratureG[k][0] * node0.z + TriQuadratureG[k][1] * node1.z +
2782 TriQuadratureG[k][2] * node2.z );
2784 double dMagnitude = node.Magnitude();
2785 node.x /= dMagnitude;
2786 node.y /= dMagnitude;
2787 node.z /= dMagnitude;
2789 double dLon = atan2( node.y, node.x );
2794 double dLat = asin( node.z );
2796 double dSample = ( *testFunction )( dLon, dLat );
2798 dTotalSample += dSample * TriQuadratureW[k] * dTriangleArea;
2801 dVar[i] += dTotalSample / trmesh->vecFaceArea[i];
2804 MB_CHK_ERR( m_interface->tag_set_data( solnTag, entities, &dVar[0] ) );
2809 std::vector< Node >& nodes = trmesh->nodes;
2812 dVar.Allocate( nodes.size() );
2814 for(
size_t j = 0; j < nodes.size(); j++ )
2816 Node& node = nodes[j];
2817 double dMagnitude = node.Magnitude();
2818 node.x /= dMagnitude;
2819 node.y /= dMagnitude;
2820 node.z /= dMagnitude;
2821 double dLon = atan2( node.y, node.x );
2826 double dLat = asin( node.z );
2828 double dSample = ( *testFunction )( dLon, dLat );
2832 MB_CHK_ERR( m_interface->tag_set_data( solnTag, entities, &dVar[0] ) );
2842 std::map< std::string, double >& metrics,
2845 const bool outputEnabled = ( is_root );
2856 entities = ( m_remapper->point_cloud_source ? m_remapper->m_covering_source_vertices
2857 : m_remapper->m_covering_source_entities );
2858 discOrder = m_nDofsPEl_Src;
2866 ( m_remapper->point_cloud_target ? m_remapper->m_target_vertices : m_remapper->m_target_entities );
2867 discOrder = m_nDofsPEl_Dest;
2873 std::cout <<
"Invalid context specified for defining an analytical solution tag" << std::endl;
2874 return moab::MB_FAILURE;
2879 std::string exactTagName, projTagName;
2880 const int ntotsize = entities.
size() * discOrder * discOrder;
2881 std::vector< double > exactSolution( ntotsize, 0.0 ), projSolution( ntotsize, 0.0 );
2882 MB_CHK_ERR( m_interface->tag_get_name( exactTag, exactTagName ) );
2883 MB_CHK_ERR( m_interface->tag_get_data( exactTag, entities, &exactSolution[0] ) );
2884 MB_CHK_ERR( m_interface->tag_get_name( approxTag, projTagName ) );
2885 MB_CHK_ERR( m_interface->tag_get_data( approxTag, entities, &projSolution[0] ) );
2887 const auto& ovents = m_remapper->m_overlap_entities;
2889 std::vector< double > errnorms( 4, 0.0 ), globerrnorms( 4, 0.0 );
2890 double sumarea = 0.0;
2891 for(
size_t i = 0; i < ovents.size(); ++i )
2893 const int srcidx = m_remapper->m_overlap->vecSourceFaceIx[i];
2894 if( srcidx < 0 )
continue;
2895 const int tgtidx = m_remapper->m_overlap->vecTargetFaceIx[i];
2896 if( tgtidx < 0 )
continue;
2897 const double ovarea = m_remapper->m_overlap->vecFaceArea[i];
2898 const double error = fabs( exactSolution[tgtidx] - projSolution[tgtidx] );
2899 errnorms[0] += ovarea *
error;
2901 errnorms[3] = (
error > errnorms[3] ?
error : errnorms[3] );
2904 errnorms[2] = sumarea;
2905 #ifdef MOAB_HAVE_MPI
2908 MPI_Reduce( &errnorms[0], &globerrnorms[0], 3, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
2909 MPI_Reduce( &errnorms[3], &globerrnorms[3], 1, MPI_DOUBLE, MPI_MAX, 0, m_pcomm->comm() );
2912 for(
int i = 0; i < 4; ++i )
2913 globerrnorms[i] = errnorms[i];
2916 globerrnorms[0] = ( globerrnorms[0] / globerrnorms[2] );
2917 globerrnorms[1] = std::sqrt( globerrnorms[1] / globerrnorms[2] );
2920 metrics[
"L1Error"] = globerrnorms[0];
2921 metrics[
"L2Error"] = globerrnorms[1];
2922 metrics[
"LinfError"] = globerrnorms[3];
2926 std::cout <<
"Error metrics when comparing " << projTagName <<
" against " << exactTagName << std::endl;
2927 std::cout <<
"\t Total Intersection area = " << globerrnorms[2] << std::endl;
2928 std::cout <<
"\t L_1 error = " << globerrnorms[0] << std::endl;
2929 std::cout <<
"\t L_2 error = " << globerrnorms[1] << std::endl;
2930 std::cout <<
"\t L_inf error = " << globerrnorms[3] << std::endl;