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();
102 std::vector< std::string > dimNames;
103 std::vector< int > dimSizes;
104 dimNames.push_back(
"num_elem" );
105 dimSizes.push_back( m_meshInputCov->faces.size() );
107 this->InitializeSourceDimensions( dimNames, dimSizes );
112 std::vector< std::string > dimNames;
113 std::vector< int > dimSizes;
114 dimNames.push_back(
"num_elem" );
115 dimSizes.push_back( m_meshOutput->faces.size() );
117 this->InitializeTargetDimensions( dimNames, dimSizes );
125 m_interface =
nullptr;
129 m_meshInput =
nullptr;
130 m_meshOutput =
nullptr;
131 m_meshOverlap =
nullptr;
137 const std::string tgtDofTagName )
142 tagSize = ( m_eInputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Src * m_nDofsPEl_Src );
148 MB_CHK_SET_ERR( MB_FAILURE,
"DoF tag is not set correctly for source mesh." );
153 tagSize = ( m_eOutputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Dest * m_nDofsPEl_Dest );
158 MB_CHK_SET_ERR( MB_FAILURE,
"DoF tag is not set correctly for target mesh." );
170 bool isSrcContinuous,
171 DataArray3D< int >* srcdataGLLNodes,
172 DataArray3D< int >* srcdataGLLNodesSrc,
175 bool isTgtContinuous,
176 DataArray3D< int >* tgtdataGLLNodes )
178 std::vector< bool > dgll_cgll_row_ldofmap, dgll_cgll_col_ldofmap, dgll_cgll_covcol_ldofmap;
179 std::vector< int > src_soln_gdofs, locsrc_soln_gdofs, tgt_soln_gdofs;
182 m_srcDiscType = srcType;
183 m_destDiscType = destType;
184 m_input_order = srcOrder;
185 m_output_order = destOrder;
187 bool vprint = is_root &&
false;
192 int srcTagSize = ( m_eInputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Src * m_nDofsPEl_Src );
193 if( m_remapper->point_cloud_source )
195 assert( m_nDofsPEl_Src == 1 );
196 col_gdofmap.resize( m_remapper->m_covering_source_vertices.size(), UINT_MAX );
197 col_dtoc_dofmap.resize( m_remapper->m_covering_source_vertices.size(), -1 );
198 src_soln_gdofs.resize( m_remapper->m_covering_source_vertices.size(), -1 );
200 m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_covering_source_vertices, &src_soln_gdofs[0] ) );
205 col_gdofmap.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, UINT_MAX );
206 col_dtoc_dofmap.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, -1 );
207 src_soln_gdofs.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, -1 );
209 m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_covering_source_entities, &src_soln_gdofs[0] ) );
212 m_nTotDofs_SrcCov = 0;
213 if( srcdataGLLNodes ==
nullptr )
216 for(
unsigned i = 0; i < col_gdofmap.size(); ++i )
218 auto gdof = src_soln_gdofs[i];
220 col_gdofmap[i] = gdof - 1;
221 col_dtoc_dofmap[i] = i;
222 if( vprint ) std::cout <<
"Col: " << i <<
", " << col_gdofmap[i] <<
"\n";
228 if( isSrcContinuous )
229 dgll_cgll_covcol_ldofmap.resize( m_remapper->m_covering_source_entities.size() * srcTagSize,
false );
231 for(
unsigned j = 0; j < m_remapper->m_covering_source_entities.size(); j++ )
233 for(
int p = 0; p < m_nDofsPEl_Src; p++ )
235 for(
int q = 0; q < m_nDofsPEl_Src; q++ )
237 const int localDOF = ( *srcdataGLLNodes )[p][q][j] - 1;
238 const int offsetDOF = j * srcTagSize + p * m_nDofsPEl_Src + q;
239 if( isSrcContinuous && !dgll_cgll_covcol_ldofmap[localDOF] )
242 dgll_cgll_covcol_ldofmap[localDOF] =
true;
244 if( !isSrcContinuous ) m_nTotDofs_SrcCov++;
245 assert( src_soln_gdofs[offsetDOF] > 0 );
250 if( isSrcContinuous )
252 col_gdofmap[localDOF] = src_soln_gdofs[offsetDOF] - 1;
253 col_dtoc_dofmap[offsetDOF] = localDOF;
257 col_gdofmap[offsetDOF] = src_soln_gdofs[offsetDOF] - 1;
258 col_dtoc_dofmap[offsetDOF] = offsetDOF;
265 if( m_remapper->point_cloud_source )
267 assert( m_nDofsPEl_Src == 1 );
268 srccol_gdofmap.resize( m_remapper->m_source_vertices.size(), UINT_MAX );
269 srccol_dtoc_dofmap.resize( m_remapper->m_covering_source_vertices.size(), -1 );
270 locsrc_soln_gdofs.resize( m_remapper->m_source_vertices.size(), -1 );
271 MB_CHK_ERR( m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_source_vertices, &locsrc_soln_gdofs[0] ) );
275 srccol_gdofmap.resize( m_remapper->m_source_entities.size() * srcTagSize, UINT_MAX );
276 srccol_dtoc_dofmap.resize( m_remapper->m_source_entities.size() * srcTagSize, -1 );
277 locsrc_soln_gdofs.resize( m_remapper->m_source_entities.size() * srcTagSize, -1 );
278 MB_CHK_ERR( m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_source_entities, &locsrc_soln_gdofs[0] ) );
283 if( srcdataGLLNodesSrc ==
nullptr )
286 for(
unsigned i = 0; i < srccol_gdofmap.size(); ++i )
288 auto gdof = locsrc_soln_gdofs[i];
290 srccol_gdofmap[i] = gdof - 1;
291 srccol_dtoc_dofmap[i] = i;
297 if( isSrcContinuous ) dgll_cgll_col_ldofmap.resize( m_remapper->m_source_entities.size() * srcTagSize,
false );
299 for(
unsigned j = 0; j < m_remapper->m_source_entities.size(); j++ )
301 for(
int p = 0; p < m_nDofsPEl_Src; p++ )
303 for(
int q = 0; q < m_nDofsPEl_Src; q++ )
305 const int localDOF = ( *srcdataGLLNodesSrc )[p][q][j] - 1;
306 const int offsetDOF = j * srcTagSize + p * m_nDofsPEl_Src + q;
307 if( isSrcContinuous && !dgll_cgll_col_ldofmap[localDOF] )
310 dgll_cgll_col_ldofmap[localDOF] =
true;
312 if( !isSrcContinuous ) m_nTotDofs_Src++;
313 assert( locsrc_soln_gdofs[offsetDOF] > 0 );
314 if( isSrcContinuous )
316 srccol_gdofmap[localDOF] = locsrc_soln_gdofs[offsetDOF] - 1;
317 srccol_dtoc_dofmap[offsetDOF] = localDOF;
321 srccol_gdofmap[offsetDOF] = locsrc_soln_gdofs[offsetDOF] - 1;
322 srccol_dtoc_dofmap[offsetDOF] = offsetDOF;
329 int tgtTagSize = ( m_eOutputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Dest * m_nDofsPEl_Dest );
330 if( m_remapper->point_cloud_target )
332 assert( m_nDofsPEl_Dest == 1 );
333 row_gdofmap.resize( m_remapper->m_target_vertices.size(), UINT_MAX );
334 row_dtoc_dofmap.resize( m_remapper->m_target_vertices.size(), -1 );
335 tgt_soln_gdofs.resize( m_remapper->m_target_vertices.size(), -1 );
336 MB_CHK_ERR( m_interface->tag_get_data( m_dofTagDest, m_remapper->m_target_vertices, &tgt_soln_gdofs[0] ) );
341 row_gdofmap.resize( m_remapper->m_target_entities.size() * tgtTagSize, UINT_MAX );
342 row_dtoc_dofmap.resize( m_remapper->m_target_entities.size() * tgtTagSize, -1 );
343 tgt_soln_gdofs.resize( m_remapper->m_target_entities.size() * tgtTagSize, -1 );
344 MB_CHK_ERR( m_interface->tag_get_data( m_dofTagDest, m_remapper->m_target_entities, &tgt_soln_gdofs[0] ) );
350 if( tgtdataGLLNodes ==
nullptr )
353 for(
unsigned i = 0; i < row_gdofmap.size(); ++i )
355 auto gdof = tgt_soln_gdofs[i];
357 row_gdofmap[i] = gdof - 1;
358 row_dtoc_dofmap[i] = i;
359 if( vprint ) std::cout <<
"Row: " << i <<
", " << row_gdofmap[i] <<
"\n";
365 if( isTgtContinuous ) dgll_cgll_row_ldofmap.resize( m_remapper->m_target_entities.size() * tgtTagSize,
false );
367 for(
unsigned j = 0; j < m_remapper->m_target_entities.size(); j++ )
369 for(
int p = 0; p < m_nDofsPEl_Dest; p++ )
371 for(
int q = 0; q < m_nDofsPEl_Dest; q++ )
373 const int localDOF = ( *tgtdataGLLNodes )[p][q][j] - 1;
374 const int offsetDOF = j * tgtTagSize + p * m_nDofsPEl_Dest + q;
375 if( isTgtContinuous && !dgll_cgll_row_ldofmap[localDOF] )
378 dgll_cgll_row_ldofmap[localDOF] =
true;
380 if( !isTgtContinuous ) m_nTotDofs_Dest++;
381 assert( tgt_soln_gdofs[offsetDOF] > 0 );
382 if( isTgtContinuous )
384 row_gdofmap[localDOF] = tgt_soln_gdofs[offsetDOF] - 1;
385 row_dtoc_dofmap[offsetDOF] = localDOF;
389 row_gdofmap[offsetDOF] = tgt_soln_gdofs[offsetDOF] - 1;
390 row_dtoc_dofmap[offsetDOF] = offsetDOF;
393 std::cout <<
"Row: " << offsetDOF <<
", " << localDOF <<
", " << row_gdofmap[offsetDOF] <<
", "
394 << m_nTotDofs_Dest <<
"\n";
401 #if defined( MOAB_HAVE_EIGEN3 ) && defined( VERBOSE )
404 std::cout <<
"[" << rank <<
"] DoFs: row = " << m_nTotDofs_Dest <<
" (gdofmap.size=" << row_gdofmap.size()
405 <<
"), col_src = " << m_nTotDofs_Src <<
", col_cov = " << m_nTotDofs_SrcCov
406 <<
" (gdofmap.size=" << col_gdofmap.size() <<
")\n";
411 #ifdef CHECK_INCREASING_DOF
412 for(
size_t i = 0; i < row_gdofmap.size() - 1; i++ )
414 if( row_gdofmap[i] > row_gdofmap[i + 1] )
415 std::cout <<
" on rank " << rank <<
" in row_gdofmap[" << i <<
"]=" << row_gdofmap[i] <<
" > row_gdofmap["
416 << i + 1 <<
"]=" << row_gdofmap[i + 1] <<
" \n";
418 for(
size_t i = 0; i < col_gdofmap.size() - 1; i++ )
420 if( col_gdofmap[i] > col_gdofmap[i + 1] )
421 std::cout <<
" on rank " << rank <<
" in col_gdofmap[" << i <<
"]=" << col_gdofmap[i] <<
" > col_gdofmap["
422 << i + 1 <<
"]=" << col_gdofmap[i + 1] <<
" \n";
438 col_dtoc_dofmap.resize( values_entities.size(), -1 );
439 for(
size_t j = 0; j < values_entities.size(); j++ )
442 const auto it = colMap.find( values_entities[j] - 1 );
443 if( it != colMap.end() ) col_dtoc_dofmap[j] = it->second;
452 row_dtoc_dofmap.resize( values_entities.size(), -1 );
453 for(
size_t j = 0; j < values_entities.size(); j++ )
456 const auto it = rowMap.find( values_entities[j] - 1 );
457 if( it != rowMap.end() ) row_dtoc_dofmap[j] = it->second;
465 std::vector< bool >& delivered )
467 delivered.assign( ncols,
false );
468 for(
size_t k = 0; k < col_dtoc_dofmap.size(); k++ )
470 const int mc = col_dtoc_dofmap[k];
471 if( mc >= 0 && mc < ncols ) delivered[mc] =
true;
477 first_absent_gid = -1;
478 const int ncols = m_nTotDofs_SrcCov;
479 std::vector< bool > delivered;
482 for(
int mc = 0; mc < ncols; mc++ )
487 if( first_absent_gid < 0 && mc < (
int)col_gdofmap.size() )
488 first_absent_gid = (int)col_gdofmap[mc] + 1;
496 const int ncols = m_nTotDofs_SrcCov;
497 std::vector< bool > delivered;
505 for(
int r = 0; r < m_weightMatrix.outerSize(); r++ )
507 for( WeightMatrix::InnerIterator it( m_weightMatrix, r ); it; ++it )
509 const int mc = (int)it.col();
510 if( mc < 0 || mc >= ncols || !delivered[mc] )
512 if( it.value() != 0.0 ) dropped++;
518 m_weightMatrix.prune( [](
const Eigen::Index&,
const Eigen::Index&,
const double& v ) {
return v != 0.0; } );
524 std::string strOutputType,
525 const GenerateOfflineMapAlgorithmOptions& mapOptions,
526 const std::string& srcDofTagName,
527 const std::string& tgtDofTagName )
529 NcError
error( NcError::silent_nonfatal );
532 dbgprint.set_prefix(
"[TempestOnlineMap]: " );
535 const bool m_bPointCloudSource = ( m_remapper->point_cloud_source );
536 const bool m_bPointCloudTarget = ( m_remapper->point_cloud_target );
537 const bool m_bPointCloud = m_bPointCloudSource || m_bPointCloudTarget;
546 STLStringHelper::ToLower( strInputType );
547 STLStringHelper::ToLower( strOutputType );
552 if( strInputType ==
"fv" )
554 eInputType = DiscretizationType_FV;
556 else if( strInputType ==
"cgll" )
558 eInputType = DiscretizationType_CGLL;
560 else if( strInputType ==
"dgll" )
562 eInputType = DiscretizationType_DGLL;
564 else if( strInputType ==
"pcloud" )
566 eInputType = DiscretizationType_PCLOUD;
570 _EXCEPTION1(
"Invalid \"in_type\" value (%s), expected [fv|cgll|dgll]", strInputType.c_str() );
573 if( strOutputType ==
"fv" )
575 eOutputType = DiscretizationType_FV;
577 else if( strOutputType ==
"cgll" )
579 eOutputType = DiscretizationType_CGLL;
581 else if( strOutputType ==
"dgll" )
583 eOutputType = DiscretizationType_DGLL;
585 else if( strOutputType ==
"pcloud" )
587 eOutputType = DiscretizationType_PCLOUD;
591 _EXCEPTION1(
"Invalid \"out_type\" value (%s), expected [fv|cgll|dgll]", strOutputType.c_str() );
595 m_bConserved = !mapOptions.fNoConservation;
596 m_eInputType = eInputType;
597 m_eOutputType = eOutputType;
600 std::string strMapAlgorithm(
"" );
601 int nMonotoneType = ( mapOptions.fMonotone ) ? ( 1 ) : ( 0 );
604 std::set< std::string > setMethodStrings;
607 for(
size_t i = 0; i <= mapOptions.strMethod.length(); i++ )
609 if( ( i == mapOptions.strMethod.length() ) || ( mapOptions.strMethod[i] ==
';' ) )
611 std::string strMethodString = mapOptions.strMethod.substr( iLast, i - iLast );
612 STLStringHelper::RemoveWhitespaceInPlace( strMethodString );
613 if( strMethodString.length() > 0 )
615 setMethodStrings.insert( strMethodString );
622 for(
const auto& it : setMethodStrings )
627 if( ( m_eInputType == DiscretizationType_FV ) && ( m_eOutputType == DiscretizationType_FV ) )
629 _EXCEPTIONT(
"--method \"mono2\" is only used when remapping to/from CGLL or DGLL grids" );
635 else if( it ==
"mono3" )
637 if( ( m_eInputType == DiscretizationType_FV ) && ( m_eOutputType == DiscretizationType_FV ) )
639 _EXCEPTIONT(
"--method \"mono3\" is only used when remapping to/from CGLL or DGLL grids" );
645 else if( it ==
"volumetric" )
647 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType == DiscretizationType_FV ) )
649 _EXCEPTIONT(
"--method \"volumetric\" may only be used for FV->CGLL or FV->DGLL remapping" );
651 strMapAlgorithm =
"volumetric";
655 else if( it ==
"invdist" )
657 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
659 _EXCEPTIONT(
"--method \"invdist\" may only be used for FV->FV remapping" );
661 strMapAlgorithm =
"invdist";
665 else if( it ==
"delaunay" )
667 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
669 _EXCEPTIONT(
"--method \"delaunay\" may only be used for FV->FV remapping" );
671 strMapAlgorithm =
"delaunay";
675 else if( it ==
"bilin" )
677 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
679 _EXCEPTIONT(
"--method \"bilin\" may only be used for FV->FV remapping" );
681 strMapAlgorithm =
"fvbilin";
685 else if( it ==
"intbilin" )
687 if( m_eOutputType != DiscretizationType_FV )
689 _EXCEPTIONT(
"--method \"intbilin\" may only be used when mapping to FV." );
691 if( m_eInputType == DiscretizationType_FV )
693 strMapAlgorithm =
"fvintbilin";
697 strMapAlgorithm =
"mono3";
702 else if( it ==
"intbilingb" )
704 if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
706 _EXCEPTIONT(
"--method \"intbilingb\" may only be used for FV->FV remapping" );
708 strMapAlgorithm =
"fvintbilingb";
712 _EXCEPTION1(
"Invalid --method argument \"%s\"", it.c_str() );
717 ( m_eInputType == DiscretizationType_FV || m_eInputType == DiscretizationType_PCLOUD ? 1
720 ( m_eOutputType == DiscretizationType_FV || m_eOutputType == DiscretizationType_PCLOUD ? 1
721 : mapOptions.nPout );
724 MB_CHK_ERR( SetDOFmapTags( srcDofTagName, tgtDofTagName ) );
728 rval = m_interface->tag_get_handle(
"aream", 1,
MB_TYPE_DOUBLE, areaTag,
732 if( is_root )
dbgprint.printf( 0,
"aream tag already defined \n" );
735 double local_areas[3] = { 0.0, 0.0, 0.0 }, global_areas[3] = { 0.0, 0.0, 0.0 };
736 if( !m_bPointCloudSource )
739 if( is_root )
dbgprint.printf( 0,
"Calculating input mesh Face areas\n" );
740 local_areas[0] = m_meshInput->CalculateFaceAreas( mapOptions.fSourceConcave );
742 MB_CHK_ERR( m_interface->tag_set_data( areaTag, m_remapper->m_source_entities, m_meshInput->vecFaceArea ) );
745 m_meshInputCov->CalculateFaceAreas( mapOptions.fSourceConcave );
748 if( !m_bPointCloudTarget )
751 if( is_root )
dbgprint.printf( 0,
"Calculating output mesh Face areas\n" );
752 local_areas[1] = m_meshOutput->CalculateFaceAreas( mapOptions.fTargetConcave );
755 m_interface->tag_set_data( areaTag, m_remapper->m_target_entities, m_meshOutput->vecFaceArea ) );
764 assert( m_meshOverlap->vecSourceFaceIx.size() == m_meshOverlap->vecTargetFaceIx.size() );
766 if( is_root )
dbgprint.printf( 0,
"Calculating overlap mesh Face areas\n" );
768 m_meshOverlap->CalculateFaceAreas( mapOptions.fSourceConcave || mapOptions.fTargetConcave );
772 std::copy( local_areas, local_areas + 3, global_areas );
775 if( m_pcomm && is_parallel )
776 MPI_Reduce( local_areas, global_areas, 3, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
780 dbgprint.printf( 0,
"Input Mesh Geometric Area: %1.15e\n", global_areas[0] );
781 dbgprint.printf( 0,
"Output Mesh Geometric Area: %1.15e\n", global_areas[1] );
782 if (m_meshOverlap)
dbgprint.printf( 0,
"Overlap Mesh Recovered Area: %1.15e\n", global_areas[2] );
786 constexpr
bool fCorrectAreas =
true;
787 if( fCorrectAreas && m_meshOverlap )
789 if( is_root )
dbgprint.printf( 0,
"Correcting source/target areas to overlap mesh areas\n" );
790 DataArray1D< double > dSourceArea( m_meshInputCov->faces.size() );
791 DataArray1D< double > dTargetArea( m_meshOutput->faces.size() );
793 assert( m_meshOverlap->vecSourceFaceIx.size() == m_meshOverlap->faces.size() );
794 assert( m_meshOverlap->vecTargetFaceIx.size() == m_meshOverlap->faces.size() );
795 assert( m_meshOverlap->vecFaceArea.GetRows() == m_meshOverlap->faces.size() );
797 assert( m_meshInputCov->vecFaceArea.GetRows() == m_meshInputCov->faces.size() );
798 assert( m_meshOutput->vecFaceArea.GetRows() == m_meshOutput->faces.size() );
800 for(
size_t i = 0; i < m_meshOverlap->faces.size(); i++ )
802 if( m_meshOverlap->vecSourceFaceIx[i] < 0 || m_meshOverlap->vecTargetFaceIx[i] < 0 )
806 assert(
static_cast< size_t >( m_meshOverlap->vecSourceFaceIx[i] ) < m_meshInputCov->faces.size() );
807 dSourceArea[m_meshOverlap->vecSourceFaceIx[i]] += m_meshOverlap->vecFaceArea[i];
808 assert(
static_cast< size_t >( m_meshOverlap->vecTargetFaceIx[i] ) < m_meshOutput->faces.size() );
809 dTargetArea[m_meshOverlap->vecTargetFaceIx[i]] += m_meshOverlap->vecFaceArea[i];
812 for(
size_t i = 0; i < m_meshInputCov->faces.size(); i++ )
814 if( fabs( dSourceArea[i] - m_meshInputCov->vecFaceArea[i] ) < 1.0e-10 )
816 m_meshInputCov->vecFaceArea[i] = dSourceArea[i];
819 for(
size_t i = 0; i < m_meshOutput->faces.size(); i++ )
821 if( fabs( dTargetArea[i] - m_meshOutput->vecFaceArea[i] ) < 1.0e-10 )
823 m_meshOutput->vecFaceArea[i] = dTargetArea[i];
829 if( !m_bPointCloudSource && eInputType == DiscretizationType_FV )
831 this->SetSourceAreas( m_meshInputCov->vecFaceArea );
832 if( m_meshInputCov->vecMask.size() )
834 this->SetSourceMask( m_meshInputCov->vecMask );
839 if( !m_bPointCloudTarget && eOutputType == DiscretizationType_FV )
841 this->SetTargetAreas( m_meshOutput->vecFaceArea );
842 if( m_meshOutput->vecMask.size() )
844 this->SetTargetMask( m_meshOutput->vecMask );
860 if( ( eInputType == DiscretizationType_FV ) && ( eOutputType == DiscretizationType_FV ) )
863 if( m_meshInputCov->revnodearray.size() == 0 ) m_meshInputCov->ConstructReverseNodeArray();
864 if( m_meshInputCov->edgemap.size() == 0 ) m_meshInputCov->ConstructEdgeMap(
false );
867 this->InitializeSourceCoordinatesFromMeshFV( *m_meshInputCov );
868 this->InitializeTargetCoordinatesFromMeshFV( *m_meshOutput );
870 this->m_pdataGLLNodesIn =
nullptr;
871 this->m_pdataGLLNodesOut =
nullptr;
874 MB_CHK_ERR( this->SetDOFmapAssociation( eInputType, mapOptions.nPin,
false,
nullptr,
nullptr, eOutputType,
875 mapOptions.nPout,
false,
nullptr ) );
878 if( is_root )
dbgprint.printf( 0,
"Calculating remap weights\n" );
881 if( strMapAlgorithm ==
"invdist" )
883 if( m_meshInputCov->faces.size() )
885 if( is_root )
dbgprint.printf( 0,
"Calculating map (invdist)\n" );
886 LinearRemapFVtoFVInvDist( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *
this );
889 else if( strMapAlgorithm ==
"delaunay" )
891 if( m_meshInputCov->faces.size() )
893 if( is_root )
dbgprint.printf( 0,
"Calculating map (delaunay)\n" );
894 if (m_meshOverlap) LinearRemapTriangulation( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *
this );
898 LinearRemapTriangulation( *m_meshInputCov, *m_meshOutput, dummy, *
this );
902 else if( strMapAlgorithm ==
"fvintbilin" )
904 if( m_meshInputCov->faces.size() )
906 if( is_root )
dbgprint.printf( 0,
"Calculating map (intbilin)\n" );
907 LinearRemapIntegratedBilinear( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *
this );
910 else if( strMapAlgorithm ==
"fvintbilingb" )
912 if( m_meshInputCov->faces.size() )
914 if( is_root )
dbgprint.printf( 0,
"Calculating map (intbilingb)\n" );
915 LinearRemapIntegratedGeneralizedBarycentric( *m_meshInputCov, *m_meshOutput, *m_meshOverlap,
919 else if( strMapAlgorithm ==
"fvbilin" )
924 m_meshInputCov->Write(
"SourceMeshMBTR.g" );
925 m_meshOutput->Write(
"TargetMeshMBTR.g" );
929 m_meshInputCov->Write(
"SourceMeshMBTR" + std::to_string( rank ) +
".g" );
930 m_meshOutput->Write(
"TargetMeshMBTR" + std::to_string( rank ) +
".g" );
934 if( m_meshInputCov->faces.size() )
936 if( is_root )
dbgprint.printf( 0,
"Calculating map (bilin)\n" );
937 if (m_meshOverlap) LinearRemapBilinear( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *
this );
941 LinearRemapBilinear( *m_meshInputCov, *m_meshOutput, dummy, *
this );
947 if( is_root )
dbgprint.printf( 0,
"Calculating conservative FV-FV map\n" );
948 if( m_meshInputCov->faces.size() )
950 #ifdef USE_NATIVE_TEMPESTREMAP_ROUTINES
951 LinearRemapFVtoFV( *m_meshInputCov, *m_meshOutput, *m_meshOverlap,
952 ( mapOptions.fMonotone ) ? ( 1 ) : ( mapOptions.nPin ), *
this );
954 LinearRemapFVtoFV_Tempest_MOAB( ( mapOptions.fMonotone ? 1 : mapOptions.nPin ) );
959 else if( eInputType == DiscretizationType_FV )
961 DataArray3D< double > dataGLLJacobian;
963 if( is_root )
dbgprint.printf( 0,
"Generating output mesh meta data\n" );
964 double dNumericalArea_loc = GenerateMetaData( *m_meshOutput, mapOptions.nPout, mapOptions.fNoBubble,
965 dataGLLNodesDest, dataGLLJacobian );
967 double dNumericalArea = dNumericalArea_loc;
970 MPI_Reduce( &dNumericalArea_loc, &dNumericalArea, 1, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
972 if( is_root )
dbgprint.printf( 0,
"Output Mesh Numerical Area: %1.15e\n", dNumericalArea );
975 this->InitializeSourceCoordinatesFromMeshFV( *m_meshInputCov );
976 this->InitializeTargetCoordinatesFromMeshFE( *m_meshOutput, mapOptions.nPout, dataGLLNodesDest );
978 this->m_pdataGLLNodesIn =
nullptr;
979 this->m_pdataGLLNodesOut = &dataGLLNodesDest;
982 bool fContinuous = ( eOutputType == DiscretizationType_CGLL );
984 if( eOutputType == DiscretizationType_CGLL )
986 GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobian, this->GetTargetAreas() );
990 GenerateDiscontinuousJacobian( dataGLLJacobian, this->GetTargetAreas() );
994 if( m_meshInputCov->revnodearray.size() == 0 ) m_meshInputCov->ConstructReverseNodeArray();
995 if( m_meshInputCov->edgemap.size() == 0 ) m_meshInputCov->ConstructEdgeMap(
false );
998 MB_CHK_ERR( this->SetDOFmapAssociation( eInputType, mapOptions.nPin,
false,
nullptr,
nullptr, eOutputType,
999 mapOptions.nPout, ( eOutputType == DiscretizationType_CGLL ),
1000 &dataGLLNodesDest ) );
1003 if( strMapAlgorithm ==
"volumetric" )
1005 if( is_root )
dbgprint.printf( 0,
"Calculating remapping weights for FV->GLL (volumetric)\n" );
1006 LinearRemapFVtoGLL_Volumetric( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesDest,
1007 dataGLLJacobian, this->GetTargetAreas(), mapOptions.nPin, *
this,
1008 nMonotoneType, fContinuous, mapOptions.fNoConservation );
1012 if( is_root )
dbgprint.printf( 0,
"Calculating remapping weights for FV->GLL\n" );
1013 LinearRemapFVtoGLL( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesDest, dataGLLJacobian,
1014 this->GetTargetAreas(), mapOptions.nPin, *
this, nMonotoneType, fContinuous,
1015 mapOptions.fNoConservation );
1018 else if( ( eInputType == DiscretizationType_PCLOUD ) || ( eOutputType == DiscretizationType_PCLOUD ) )
1020 DataArray3D< double > dataGLLJacobian;
1021 if( !m_bPointCloudSource )
1024 if( m_meshInputCov->revnodearray.size() == 0 ) m_meshInputCov->ConstructReverseNodeArray();
1025 if( m_meshInputCov->edgemap.size() == 0 ) m_meshInputCov->ConstructEdgeMap(
false );
1028 if( eInputType == DiscretizationType_FV )
1030 this->InitializeSourceCoordinatesFromMeshFV( *m_meshInputCov );
1034 if( is_root )
dbgprint.printf( 0,
"Generating input mesh meta data\n" );
1035 DataArray3D< double > dataGLLJacobianSrc;
1036 GenerateMetaData( *m_meshInputCov, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrcCov,
1038 GenerateMetaData( *m_meshInput, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrc,
1039 dataGLLJacobianSrc );
1044 if( !m_bPointCloudTarget )
1047 if( m_meshOutput->revnodearray.size() == 0 ) m_meshOutput->ConstructReverseNodeArray();
1048 if( m_meshOutput->edgemap.size() == 0 ) m_meshOutput->ConstructEdgeMap(
false );
1051 if( eOutputType == DiscretizationType_FV )
1053 this->InitializeSourceCoordinatesFromMeshFV( *m_meshOutput );
1057 if( is_root )
dbgprint.printf( 0,
"Generating output mesh meta data\n" );
1058 GenerateMetaData( *m_meshOutput, mapOptions.nPout, mapOptions.fNoBubble, dataGLLNodesDest,
1066 eInputType, mapOptions.nPin, ( eInputType == DiscretizationType_CGLL ),
1067 ( m_bPointCloudSource || eInputType == DiscretizationType_FV ?
nullptr : &dataGLLNodesSrcCov ),
1068 ( m_bPointCloudSource || eInputType == DiscretizationType_FV ?
nullptr : &dataGLLNodesSrc ),
1069 eOutputType, mapOptions.nPout, ( eOutputType == DiscretizationType_CGLL ),
1070 ( m_bPointCloudTarget ?
nullptr : &dataGLLNodesDest ) ) );
1073 if( is_root )
dbgprint.printf( 0,
"Calculating remap weights with Nearest-Neighbor method\n" );
1074 MB_CHK_ERR( LinearRemapNN_MOAB(
true ,
false ) );
1076 else if( ( eInputType != DiscretizationType_FV ) && ( eOutputType == DiscretizationType_FV ) )
1078 DataArray3D< double > dataGLLJacobianSrc, dataGLLJacobian;
1080 if( is_root )
dbgprint.printf( 0,
"Generating input mesh meta data\n" );
1082 GenerateMetaData( *m_meshInput, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrc,
1083 dataGLLJacobianSrc );
1084 GenerateMetaData( *m_meshInputCov, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrcCov,
1087 if( dataGLLNodesSrcCov.GetSubColumns() != m_meshInputCov->faces.size() )
1089 _EXCEPTIONT(
"Number of element does not match between metadata and "
1094 this->InitializeSourceCoordinatesFromMeshFE( *m_meshInputCov, mapOptions.nPin, dataGLLNodesSrcCov );
1095 this->InitializeTargetCoordinatesFromMeshFV( *m_meshOutput );
1098 bool fContinuousIn = ( eInputType == DiscretizationType_CGLL );
1100 if( eInputType == DiscretizationType_CGLL )
1102 GenerateUniqueJacobian( dataGLLNodesSrcCov, dataGLLJacobian, this->GetSourceAreas() );
1106 GenerateDiscontinuousJacobian( dataGLLJacobian, this->GetSourceAreas() );
1110 MB_CHK_ERR( this->SetDOFmapAssociation( eInputType, mapOptions.nPin,
1111 ( eInputType == DiscretizationType_CGLL ), &dataGLLNodesSrcCov,
1112 &dataGLLNodesSrc, eOutputType, mapOptions.nPout,
false,
nullptr ) );
1115 if( is_root )
dbgprint.printf( 0,
"Calculating remap weights\n" );
1117 if( strMapAlgorithm ==
"volumetric" )
1119 _EXCEPTIONT(
"Unimplemented: Volumetric currently unavailable for"
1123 this->m_pdataGLLNodesIn = &dataGLLNodesSrcCov;
1124 this->m_pdataGLLNodesOut =
nullptr;
1126 #ifdef USE_NATIVE_TEMPESTREMAP_ROUTINES
1127 LinearRemapSE4( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesSrcCov, dataGLLJacobian,
1128 nMonotoneType, fContinuousIn, mapOptions.fNoConservation, mapOptions.fSparseConstraints,
1131 LinearRemapSE4_Tempest_MOAB( dataGLLNodesSrcCov, dataGLLJacobian, nMonotoneType, fContinuousIn,
1132 mapOptions.fNoConservation, mapOptions.fSparseConstraints );
1135 else if( ( eInputType != DiscretizationType_FV ) && ( eOutputType != DiscretizationType_FV ) )
1137 DataArray3D< double > dataGLLJacobianIn, dataGLLJacobianSrc;
1138 DataArray3D< double > dataGLLJacobianOut;
1141 if( is_root )
dbgprint.printf( 0,
"Generating input mesh meta data\n" );
1143 GenerateMetaData( *m_meshInput, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrc,
1144 dataGLLJacobianSrc );
1146 GenerateMetaData( *m_meshInputCov, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrcCov,
1147 dataGLLJacobianIn );
1149 if( is_root )
dbgprint.printf( 0,
"Generating output mesh meta data\n" );
1150 GenerateMetaData( *m_meshOutput, mapOptions.nPout, mapOptions.fNoBubble, dataGLLNodesDest,
1151 dataGLLJacobianOut );
1154 this->InitializeSourceCoordinatesFromMeshFE( *m_meshInputCov, mapOptions.nPin, dataGLLNodesSrcCov );
1155 this->InitializeTargetCoordinatesFromMeshFE( *m_meshOutput, mapOptions.nPout, dataGLLNodesDest );
1158 bool fContinuousIn = ( eInputType == DiscretizationType_CGLL );
1160 if( eInputType == DiscretizationType_CGLL )
1162 GenerateUniqueJacobian( dataGLLNodesSrcCov, dataGLLJacobianIn, this->GetSourceAreas() );
1166 GenerateDiscontinuousJacobian( dataGLLJacobianIn, this->GetSourceAreas() );
1170 bool fContinuousOut = ( eOutputType == DiscretizationType_CGLL );
1172 if( eOutputType == DiscretizationType_CGLL )
1174 GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobianOut, this->GetTargetAreas() );
1178 GenerateDiscontinuousJacobian( dataGLLJacobianOut, this->GetTargetAreas() );
1182 MB_CHK_ERR( this->SetDOFmapAssociation( eInputType, mapOptions.nPin,
1183 ( eInputType == DiscretizationType_CGLL ), &dataGLLNodesSrcCov,
1184 &dataGLLNodesSrc, eOutputType, mapOptions.nPout,
1185 ( eOutputType == DiscretizationType_CGLL ), &dataGLLNodesDest ) );
1187 this->m_pdataGLLNodesIn = &dataGLLNodesSrcCov;
1188 this->m_pdataGLLNodesOut = &dataGLLNodesDest;
1191 if( is_root )
dbgprint.printf( 0,
"Calculating remap weights\n" );
1193 #ifdef USE_NATIVE_TEMPESTREMAP_ROUTINES
1194 LinearRemapGLLtoGLL_Integrated( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesSrcCov,
1195 dataGLLJacobianIn, dataGLLNodesDest, dataGLLJacobianOut,
1196 this->GetTargetAreas(), mapOptions.nPin, mapOptions.nPout, nMonotoneType,
1197 fContinuousIn, fContinuousOut, mapOptions.fSparseConstraints, *
this );
1199 LinearRemapGLLtoGLL2_MOAB( dataGLLNodesSrcCov, dataGLLJacobianIn, dataGLLNodesDest, dataGLLJacobianOut,
1200 this->GetTargetAreas(), mapOptions.nPin, mapOptions.nPout, nMonotoneType,
1201 fContinuousIn, fContinuousOut, mapOptions.fNoConservation );
1206 _EXCEPTIONT(
"Not implemented" );
1209 #ifdef MOAB_HAVE_EIGEN3
1210 copy_tempest_sparsemat_to_eigen3();
1213 #ifdef MOAB_HAVE_MPI
1218 MB_CHK_ERR( m_remapper->GetOverlapAugmentedEntities( ghostedEnts ) );
1220 MB_CHK_SET_ERR( m_interface->remove_entities( m_meshOverlapSet, ghostedEnts ),
1221 "Deleting ghosted entities failed" );
1225 if( !mapOptions.fNoCheck )
1227 if( is_root )
dbgprint.printf( 0,
"Verifying map" );
1228 this->IsConsistent( 1.0e-8 );
1229 if( !mapOptions.fNoConservation ) this->IsConservative( 1.0e-8 );
1231 if( nMonotoneType != 0 )
1233 this->IsMonotone( 1.0e-12 );
1237 catch( Exception& e )
1239 dbgprint.printf( 0,
"%s", e.ToString().c_str() );
1240 return ( moab::MB_FAILURE );
1244 return ( moab::MB_FAILURE );
1253 #ifndef MOAB_HAVE_MPI
1255 return OfflineMap::IsConsistent( dTolerance );
1260 DataArray1D< int > dataRows;
1261 DataArray1D< int > dataCols;
1262 DataArray1D< double > dataEntries;
1265 DataArray1D< double > dRowSums;
1266 m_mapRemap.GetEntries( dataRows, dataCols, dataEntries );
1267 dRowSums.Allocate( m_mapRemap.GetRows() );
1269 for(
unsigned i = 0; i < dataRows.GetRows(); i++ )
1271 dRowSums[dataRows[i]] += dataEntries[i];
1275 int fConsistent = 0;
1276 for(
unsigned i = 0; i < dRowSums.GetRows(); i++ )
1278 if( fabs( dRowSums[i] - 1.0 ) > dTolerance )
1281 int rowGID = row_gdofmap[i];
1282 Announce(
"TempestOnlineMap is not consistent in row %i (%1.15e)", rowGID, dRowSums[i] );
1287 int fConsistentGlobal = 0;
1288 ierr = MPI_Allreduce( &fConsistent, &fConsistentGlobal, 1, MPI_INT, MPI_SUM, m_pcomm->comm() );
1289 if( ierr != MPI_SUCCESS )
return -1;
1291 return fConsistentGlobal;
1299 #ifndef MOAB_HAVE_MPI
1301 return OfflineMap::IsConservative( dTolerance );
1308 DataArray1D< int > dataRows;
1309 DataArray1D< int > dataCols;
1310 DataArray1D< double > dataEntries;
1311 const DataArray1D< double >& dTargetAreas = this->GetTargetAreas();
1312 const DataArray1D< double >& dSourceAreas = this->GetSourceAreas();
1315 std::vector< int > dColumnsUnique;
1316 std::vector< double > dColumnSums;
1318 int nColumns = m_mapRemap.GetColumns();
1319 m_mapRemap.GetEntries( dataRows, dataCols, dataEntries );
1320 dColumnSums.resize( m_nTotDofs_SrcCov, 0.0 );
1321 dColumnsUnique.resize( m_nTotDofs_SrcCov, -1 );
1323 for(
unsigned i = 0; i < dataEntries.GetRows(); i++ )
1325 dColumnSums[dataCols[i]] += dataEntries[i] * dTargetAreas[dataRows[i]] / dSourceAreas[dataCols[i]];
1327 assert( dataCols[i] < m_nTotDofs_SrcCov );
1330 int colGID = this->GetColGlobalDoF( dataCols[i] );
1332 dColumnsUnique[dataCols[i]] = colGID;
1339 std::vector< int > nElementsInProc;
1340 const int nDATA = 3;
1341 nElementsInProc.resize( size * nDATA );
1342 int senddata[nDATA] = { nColumns, m_nTotDofs_SrcCov, m_nTotDofs_Src };
1343 ierr = MPI_Gather( senddata, nDATA, MPI_INT, nElementsInProc.data(), nDATA, MPI_INT, rootProc, m_pcomm->comm() );
1344 if( ierr != MPI_SUCCESS )
return -1;
1346 int nTotVals = 0, nTotColumns = 0;
1347 std::vector< int > dColumnIndices;
1348 std::vector< double > dColumnSumsTotal;
1349 std::vector< int > displs, rcount;
1350 if( rank == rootProc )
1352 displs.resize( size + 1, 0 );
1353 rcount.resize( size, 0 );
1355 for(
int ir = 0; ir < size; ++ir )
1357 nTotVals += nElementsInProc[ir * nDATA];
1358 nTotColumns += nElementsInProc[ir * nDATA + 1];
1362 rcount[ir] = nElementsInProc[ir * nDATA + 1];
1368 printf(
"Total nnz: %d, global source elements = %d\n", nTotVals, gsum );
1370 dColumnIndices.resize( nTotColumns, -1 );
1371 dColumnSumsTotal.resize( nTotColumns, 0.0 );
1385 ierr = MPI_Gatherv( dColumnsUnique.data(), m_nTotDofs_SrcCov, MPI_INT, dColumnIndices.data(), rcount.data(),
1386 displs.data(), MPI_INT, rootProc, m_pcomm->comm() );
1387 if( ierr != MPI_SUCCESS )
return -1;
1388 ierr = MPI_Gatherv( dColumnSums.data(), m_nTotDofs_SrcCov, MPI_DOUBLE, dColumnSumsTotal.data(), rcount.data(),
1389 displs.data(), MPI_DOUBLE, rootProc, m_pcomm->comm() );
1390 if( ierr != MPI_SUCCESS )
return -1;
1396 dColumnSums.clear();
1397 dColumnsUnique.clear();
1400 int fConservative = 0;
1401 if( rank == rootProc )
1403 displs[size] = ( nTotColumns );
1405 std::map< int, double > dColumnSumsOnRoot;
1407 for(
int ir = 0; ir < size; ir++ )
1409 for(
int ips = displs[ir]; ips < displs[ir + 1]; ips++ )
1411 if( dColumnIndices[ips] < 0 )
continue;
1414 dColumnSumsOnRoot[dColumnIndices[ips]] += dColumnSumsTotal[ips];
1420 for( std::map< int, double >::iterator it = dColumnSumsOnRoot.begin(); it != dColumnSumsOnRoot.end(); ++it )
1423 if( fabs( it->second - 1.0 ) > dTolerance )
1426 Announce(
"TempestOnlineMap is not conservative in column "
1429 it->first, it->second );
1435 ierr = MPI_Bcast( &fConservative, 1, MPI_INT, rootProc, m_pcomm->comm() );
1436 if( ierr != MPI_SUCCESS )
return -1;
1438 return fConservative;
1446 #ifndef MOAB_HAVE_MPI
1448 return OfflineMap::IsMonotone( dTolerance );
1453 DataArray1D< int > dataRows;
1454 DataArray1D< int > dataCols;
1455 DataArray1D< double > dataEntries;
1457 m_mapRemap.GetEntries( dataRows, dataCols, dataEntries );
1461 for(
unsigned i = 0; i < dataRows.GetRows(); i++ )
1463 if( ( dataEntries[i] < -dTolerance ) || ( dataEntries[i] > 1.0 + dTolerance ) )
1467 Announce(
"TempestOnlineMap is not monotone in entry (%i): %1.15e", i, dataEntries[i] );
1472 int fMonotoneGlobal = 0;
1473 ierr = MPI_Allreduce( &fMonotone, &fMonotoneGlobal, 1, MPI_INT, MPI_SUM, m_pcomm->comm() );
1474 if( ierr != MPI_SUCCESS )
return -1;
1476 return fMonotoneGlobal;
1484 const Range& entities,
1485 bool useMOABAdjacencies,
1488 assert( nrings > 0 );
1489 assert( useMOABAdjacencies || trMesh !=
nullptr );
1491 const size_t nrows = vecAdjFaces.size();
1498 if( useMOABAdjacencies )
1508 int adjIndex = entities.
index( *it );
1510 if( adjIndex >= 0 ) vecAdjFaces[
index].insert( adjIndex );
1520 GetAdjacentFaceVectorByEdge( *trMesh,
index, nrings *
face.edges.size(), adjFaces );
1523 for(
auto adjFace : adjFaces )
1524 if( adjFace.first >= 0 )
1525 vecAdjFaces[
index].insert( adjFace.first );
1535 double default_projection )
1537 std::vector< double > solSTagVals;
1538 std::vector< double > solTTagVals;
1541 if( m_remapper->point_cloud_source || m_remapper->point_cloud_target )
1543 if( m_remapper->point_cloud_source )
1546 solSTagVals.resize( covSrcEnts.
size(), default_projection );
1552 solSTagVals.resize( covSrcEnts.
size() * this->GetSourceNDofsPerElement() * this->GetSourceNDofsPerElement(),
1553 default_projection );
1556 if( m_remapper->point_cloud_target )
1559 solTTagVals.resize( tgtEnts.
size(), default_projection );
1565 solTTagVals.resize( tgtEnts.
size() * this->GetDestinationNDofsPerElement() *
1566 this->GetDestinationNDofsPerElement(),
1567 default_projection );
1575 solSTagVals.resize( covSrcEnts.
size() * this->GetSourceNDofsPerElement() * this->GetSourceNDofsPerElement(),
1576 default_projection );
1577 solTTagVals.resize( tgtEnts.
size() * this->GetDestinationNDofsPerElement() *
1578 this->GetDestinationNDofsPerElement(),
1579 default_projection );
1586 MB_CHK_SET_ERR( m_interface->tag_get_data( srcSolutionTag, sents, &solSTagVals[0] ),
1587 "Getting local tag data failed" );
1592 MB_CHK_SET_ERR( this->ApplyWeights( solSTagVals, solTTagVals, transpose ),
1593 "Applying remap operator onto source vector data failed" );
1596 MB_CHK_SET_ERR( m_interface->tag_set_data( tgtSolutionTag, tents, &solTTagVals[0] ),
1597 "Setting target tag data failed" );
1599 if( caasType != CAAS_NONE )
1601 std::string tgtSolutionTagName;
1602 MB_CHK_SET_ERR( m_interface->tag_get_name( tgtSolutionTag, tgtSolutionTagName ),
"Getting tag name failed" );
1605 constexpr
int nmax_caas_iterations = 10;
1606 double mismatch = 1.0;
1607 int caasIteration = 0;
1608 double initialMismatch = 0.0;
1609 while( ( fabs( mismatch / initialMismatch ) > 1e-15 && fabs( mismatch ) > 1e-15 ) &&
1610 caasIteration++ < nmax_caas_iterations )
1612 double dMassDiffPostGlobal;
1613 std::pair< double, double > mDefect =
1614 this->ApplyBoundsLimiting( solSTagVals, solTTagVals, caasType, caasIteration, mismatch );
1615 #ifdef MOAB_HAVE_MPI
1616 double dMassDiffPost = mDefect.second;
1617 MPI_Allreduce( &dMassDiffPost, &dMassDiffPostGlobal, 1, MPI_DOUBLE, MPI_SUM, m_pcomm->comm() );
1619 dMassDiffPostGlobal = mDefect.second;
1621 if( caasIteration == 1 ) initialMismatch = mDefect.first;
1622 if( m_remapper->verbose && is_root )
1624 printf(
"Field {%s} -> CAAS iteration: %d, mass defect: %3.4e, post-CAAS: %3.4e\n",
1625 tgtSolutionTagName.c_str(), caasIteration, mDefect.first, dMassDiffPostGlobal );
1627 mismatch = dMassDiffPostGlobal;
1630 MB_CHK_SET_ERR( m_interface->tag_set_data( tgtSolutionTag, tents, &solTTagVals[0] ),
1631 "Setting local tag data failed" );
1644 std::vector< double > solSTagVals, solTTagVals;
1647 if( m_remapper->point_cloud_source || m_remapper->point_cloud_target )
1649 if( m_remapper->point_cloud_source )
1652 solSTagVals.resize( covSrcEnts.
size(), 0.0 );
1658 solSTagVals.resize( covSrcEnts.
size() * this->GetSourceNDofsPerElement() *
1659 this->GetSourceNDofsPerElement(),
1663 if( m_remapper->point_cloud_target )
1666 solTTagVals.resize( tgtEnts.
size(), 0.0 );
1672 solTTagVals.resize( tgtEnts.
size() * this->GetDestinationNDofsPerElement() *
1673 this->GetDestinationNDofsPerElement(),
1682 solSTagVals.resize( covSrcEnts.
size() * this->GetSourceNDofsPerElement() * this->GetSourceNDofsPerElement(),
1685 tgtEnts.
size() * this->GetDestinationNDofsPerElement() * this->GetDestinationNDofsPerElement(), 0.0 );
1691 MB_CHK_SET_ERR( m_interface->tag_get_data( srcSolutionTag, sents, &solSTagVals[0] ),
1692 "Getting source tag data failed" );
1695 MB_CHK_SET_ERR( this->ApplyWeights( solSTagVals, solTTagVals,
false ),
1696 "High-order projection failed" );
1699 MB_CHK_SET_ERR( m_interface->tag_set_data( tgtSolutionTag, tents, &solTTagVals[0] ),
1700 "Setting target tag data failed" );
1702 if( caasType == CAAS_NONE || loWeightMap ==
nullptr )
return moab::MB_SUCCESS;
1796 const size_t nTargetDofs = solTTagVals.size();
1797 const size_t nSourceDofs = solSTagVals.size();
1802 if( row_dtoc_dofmap.size() < nTargetDofs )
1804 MB_CHK_SET_ERR( moab::MB_FAILURE,
"row_dtoc_dofmap smaller than target tag size" );
1808 std::vector< double > yLow( nTargetDofs, 0.0 );
1810 "Low-order projection failed" );
1868 std::vector< double > srcNorm8wt;
1869 bool hasNorm8wt =
false;
1872 moab::ErrorCode rvalN = m_interface->tag_get_handle(
"norm8wt", normTag );
1873 if(
MB_SUCCESS == rvalN && normTag !=
nullptr )
1881 srcNorm8wt.resize( sents.
size(), 0.0 );
1882 moab::ErrorCode rvalD = m_interface->tag_get_data( normTag, sents, &srcNorm8wt[0] );
1883 if(
MB_SUCCESS == rvalD && srcNorm8wt.size() == nSourceDofs )
1899 std::vector< double > lcl_lo( nTargetDofs, 1e308 );
1900 std::vector< double > lcl_hi( nTargetDofs, -1e308 );
1902 WeightMatrix& hiW = this->m_weightMatrix;
1903 for(
size_t i = 0; i < nTargetDofs; i++ )
1905 int r = row_dtoc_dofmap[i];
1906 if( r < 0 || r >= hiW.outerSize() )
continue;
1907 for( WeightMatrix::InnerIterator it( hiW, r ); it; ++it )
1912 int mc = (int)it.col();
1926 for(
size_t k = 0; k < nSourceDofs && k < col_dtoc_dofmap.size(); k++ )
1927 if( col_dtoc_dofmap[k] > maxMatCol ) maxMatCol = col_dtoc_dofmap[k];
1928 std::vector< int > col_inv( maxMatCol + 1, -1 );
1929 for(
size_t k = 0; k < nSourceDofs && k < col_dtoc_dofmap.size(); k++ )
1930 if( col_dtoc_dofmap[k] >= 0 ) col_inv[col_dtoc_dofmap[k]] = (int)k;
1939 int bndsLocalErr = 0;
1940 int bndsFirstRowG = -1;
1941 int bndsFirstMc = -1;
1942 double bndsFirstWgt = 0.0;
1943 int bndsFirstKind = 0;
1945 for(
size_t i = 0; i < nTargetDofs; i++ )
1947 int r = row_dtoc_dofmap[i];
1948 if( r < 0 || r >= hiW.outerSize() )
continue;
1949 for( WeightMatrix::InnerIterator it( hiW, r ); it; ++it )
1961 if( fabs( it.value() ) < 1e-50 )
continue;
1962 const int mc = (int)it.col();
1972 if( mc < 0 || mc > maxMatCol )
1977 bndsFirstRowG = (r >= 0 && r < (int)row_gdofmap.size()) ? (
int)row_gdofmap[r] : -1;
1979 bndsFirstWgt = it.value();
1984 const int srcIdx = col_inv[mc];
1990 bndsFirstRowG = (r >= 0 && r < (int)row_gdofmap.size()) ? (
int)row_gdofmap[r] : -1;
1992 bndsFirstWgt = it.value();
1997 if( srcIdx >= (
int)nSourceDofs )
2002 bndsFirstRowG = (r >= 0 && r < (int)row_gdofmap.size()) ? (
int)row_gdofmap[r] : -1;
2004 bndsFirstWgt = it.value();
2014 double v = solSTagVals[srcIdx];
2017 const double n = srcNorm8wt[srcIdx];
2018 if( fabs(n) < 1
E-20 )
continue;
2021 if( v < lcl_lo[i] ) lcl_lo[i] = v;
2022 if( v > lcl_hi[i] ) lcl_hi[i] = v;
2028 if( lcl_lo[i] > lcl_hi[i] )
2036 #ifdef MOAB_HAVE_MPI
2038 MPI_Comm comm = m_pcomm ? m_pcomm->comm() : MPI_COMM_SELF;
2039 int bndsGlobalErr = 0;
2040 MPI_Allreduce( &bndsLocalErr, &bndsGlobalErr, 1, MPI_INT, MPI_MAX, comm );
2044 MPI_Comm_rank( comm, &myRank );
2047 static const char* kindStr[4] = {
"?",
"mc>maxMatCol",
"col_inv[mc]==-1",
"srcIdx>=nSourceDofs" };
2049 "FATAL: ApplyWeightsWithDualMap bounds extraction dropped a nonzero "
2050 "high-order stencil column on rank %d.\n"
2051 " global_target_row=%d matrix_col=%d weight=%.17e reason=%s\n"
2052 " This means the source coverage on this rank does NOT contain a "
2053 "column the owned high-order row references — the 3-ring (or whatever) "
2054 "ghost layer setting is too narrow, or the map file was generated against "
2055 "a different mesh. Bounds computed over an incomplete stencil break BFB; "
2056 "aborting rather than silently producing wrong CAAS output.\n",
2057 myRank, bndsFirstRowG, bndsFirstMc, bndsFirstWgt, kindStr[bndsFirstKind] );
2060 MPI_Abort( comm, 1 );
2066 static const char* kindStr[4] = {
"?",
"mc>maxMatCol",
"col_inv[mc]==-1",
"srcIdx>=nSourceDofs" };
2068 "FATAL: ApplyWeightsWithDualMap bounds extraction dropped a nonzero "
2069 "high-order stencil column.\n"
2070 " global_target_row=%d matrix_col=%d weight=%.17e reason=%s\n",
2071 bndsFirstRowG, bndsFirstMc, bndsFirstWgt, kindStr[bndsFirstKind] );
2073 return moab::MB_FAILURE;
2081 for(
size_t i = 0; i < nTargetDofs; i++ )
2083 if( yLow[i] == 0.0 )
2085 solTTagVals[i] = 0.0;
2096 double g_lo = 1e308, g_hi = -1e308;
2097 for(
size_t i = 0; i < nTargetDofs; i++ )
2099 int r = row_dtoc_dofmap[i];
2100 if( r < 0 || r >= (
int)row_gdofmap.size() )
continue;
2101 if( lcl_lo[i] < g_lo ) g_lo = lcl_lo[i];
2102 if( lcl_hi[i] > g_hi ) g_hi = lcl_hi[i];
2104 #ifdef MOAB_HAVE_MPI
2106 MPI_Comm comm = m_pcomm ? m_pcomm->comm() : MPI_COMM_SELF;
2107 double tmp_min = g_lo, tmp_max = g_hi;
2108 MPI_Allreduce( &tmp_min, &g_lo, 1, MPI_DOUBLE, MPI_MIN, comm );
2109 MPI_Allreduce( &tmp_max, &g_hi, 1, MPI_DOUBLE, MPI_MAX, comm );
2122 std::vector< double > mappedNorm8wt( nTargetDofs, 0.0 );
2126 "Mapped-norm8wt computation (low-order on source norm8wt) failed" );
2130 std::vector< double > srcOnes( nSourceDofs, 1.0 );
2132 "Mapped-norm8wt computation (low-order on ones) failed" );
2145 for(
size_t i = 0; i < nTargetDofs; i++ )
2147 const double w = mappedNorm8wt[i];
2165 std::vector< double > tgtAreas( nTargetDofs, 0.0 );
2167 std::vector< moab::EntityHandle > tentVec;
2168 tentVec.reserve( tents.
size() );
2170 tentVec.push_back( *it );
2172 bool got_areas =
false;
2178 moab::ErrorCode rval = m_interface->tag_get_handle(
"aream", aream_tag );
2179 if(
MB_SUCCESS == rval && aream_tag !=
nullptr && !tentVec.empty() )
2181 const size_t nents = std::min< size_t >( tentVec.size(), nTargetDofs );
2182 std::vector< double > aream_vals( nents, 0.0 );
2183 rval = m_interface->tag_get_data( aream_tag, &tentVec[0], (
int)nents, &aream_vals[0] );
2186 for(
size_t i = 0; i < nents; i++ ) tgtAreas[i] = aream_vals[i];
2197 const DataArray1D< double >& dTargetAreas = this->GetTargetAreas();
2198 const size_t nRows = dTargetAreas.GetRows();
2199 if( nRows >= nTargetDofs )
2201 for(
size_t i = 0; i < nTargetDofs; i++ )
2203 int r = row_dtoc_dofmap[i];
2204 if( r >= 0 && (
size_t)r < nRows )
2205 tgtAreas[i] = dTargetAreas[r];
2216 "ApplyWeightsWithDualMap: no target-cell areas available. "
2217 "Neither the 'aream' tag (from iMOAB_LoadMapFile with "
2218 "arearead != 0) nor OfflineMap::GetTargetAreas() (from an "
2219 "online map build) provided areas. Recomputing areas from "
2220 "mesh geometry is not bit-for-bit with MCT and is no longer "
2221 "permitted in the CAAS path. Re-load the map file with an "
2222 "area-bearing arearead setting (e.g. arearead=3 for F-maps), "
2223 "or build the online map so target areas are populated." );
2230 std::vector< int > rowGids( nTargetDofs, -1 );
2231 std::vector< double > massLowPerRow( nTargetDofs, 0.0 );
2232 std::vector< double > massHiUnclippedPerRow( nTargetDofs, 0.0 );
2233 std::vector< double > clipDefectPerRow( nTargetDofs, 0.0 );
2234 std::vector< double > capLowPerRow( nTargetDofs, 0.0 );
2235 std::vector< double > capHighPerRow( nTargetDofs, 0.0 );
2237 for(
size_t i = 0; i < nTargetDofs; i++ )
2239 int r = row_dtoc_dofmap[i];
2240 if( r < 0 || r >= (
int)row_gdofmap.size() )
2243 rowGids[i] = (int)row_gdofmap[r];
2245 const double area = tgtAreas[i];
2246 const double y = solTTagVals[i];
2247 const double lo = lcl_lo[i];
2248 const double hi = lcl_hi[i];
2254 dm = ( y - lo ) * area;
2259 dm = ( y - hi ) * area;
2261 clipDefectPerRow[i] = dm;
2262 capLowPerRow[i] = ( yc - lo ) * area;
2263 capHighPerRow[i] = ( hi - yc ) * area;
2264 massLowPerRow[i] = yLow[i] * area;
2272 massHiUnclippedPerRow[i] = y * area;
2274 solTTagVals[i] = yc;
2289 #ifdef MOAB_HAVE_MPI
2290 MPI_Comm reduce_comm = m_pcomm ? m_pcomm->comm() : MPI_COMM_SELF;
2292 int reduce_comm = 0;
2294 #ifdef MOAB_HAVE_MPI
2300 const std::vector< int >& reduce_mask = rowGids;
2307 const std::vector< std::vector< double > > caasFields = {
2308 massLowPerRow, massHiUnclippedPerRow, clipDefectPerRow,
2309 capLowPerRow, capHighPerRow };
2310 std::vector< double > caasGsums;
2312 const double M_low = caasGsums[0];
2313 const double M_hi_unclipped = caasGsums[1];
2314 const double dM_clip = caasGsums[2];
2315 const double cap_low_g = caasGsums[3];
2316 const double cap_high_g = caasGsums[4];
2339 const double diff = M_low - M_hi_unclipped;
2340 const double dM_total = dM_clip + diff;
2355 if( dM_total > 0.0 && cap_high_g > 0.0 )
2357 for(
size_t i = 0; i < nTargetDofs; i++ )
2359 const double area = tgtAreas[i];
2360 const double yc = solTTagVals[i];
2362 solTTagVals[i] = yc + ( ( lcl_hi[i] - yc ) / cap_high_g ) * dM_total;
2365 else if( dM_total < 0.0 && cap_low_g > 0.0 )
2367 for(
size_t i = 0; i < nTargetDofs; i++ )
2369 const double area = tgtAreas[i];
2370 const double yc = solTTagVals[i];
2372 solTTagVals[i] = yc + ( ( yc - lcl_lo[i] ) / cap_low_g ) * dM_total;
2388 for(
size_t i = 0; i < nTargetDofs; i++ )
2390 if( fabs(yLow[i]) < 1
E-40 )
continue;
2391 if( solTTagVals[i] < g_lo ) solTTagVals[i] = g_lo;
2392 if( solTTagVals[i] > g_hi ) solTTagVals[i] = g_hi;
2396 MB_CHK_SET_ERR( m_interface->tag_set_data( tgtSolutionTag, tents, &solTTagVals[0] ),
2397 "Setting target tag data failed" );
2403 const std::string& solnName,
2405 sample_function testFunction,
2407 std::string cloneSolnName )
2409 const bool outputEnabled = ( is_root );
2419 trmesh = m_remapper->m_covering_source;
2420 entities = ( m_remapper->point_cloud_source ? m_remapper->m_covering_source_vertices
2421 : m_remapper->m_covering_source_entities );
2422 discOrder = m_nDofsPEl_Src;
2423 discMethod = m_eInputType;
2428 trmesh = m_remapper->m_target;
2430 ( m_remapper->point_cloud_target ? m_remapper->m_target_vertices : m_remapper->m_target_entities );
2431 discOrder = m_nDofsPEl_Dest;
2432 discMethod = m_eOutputType;
2437 std::cout <<
"Invalid context specified for defining an analytical solution tag" << std::endl;
2438 return moab::MB_FAILURE;
2445 if( clonedSolnTag !=
nullptr )
2447 if( cloneSolnName.size() == 0 )
2449 cloneSolnName = solnName + std::string(
"Cloned" );
2456 const int TriQuadratureOrder = 10;
2458 if( outputEnabled ) std::cout <<
"Using triangular quadrature of order " << TriQuadratureOrder << std::endl;
2460 TriangularQuadratureRule triquadrule( TriQuadratureOrder );
2462 const int TriQuadraturePoints = triquadrule.GetPoints();
2464 const DataArray2D< double >& TriQuadratureG = triquadrule.GetG();
2465 const DataArray1D< double >& TriQuadratureW = triquadrule.GetW();
2468 DataArray1D< double > dVar;
2469 DataArray1D< double > dVarMB;
2472 DataArray1D< double > dNodeArea;
2477 if( discMethod == DiscretizationType_CGLL || discMethod == DiscretizationType_DGLL )
2480 const bool fGLL =
true;
2481 const bool fGLLIntegrate =
false;
2484 DataArray3D< int > dataGLLNodes;
2485 DataArray3D< double > dataGLLJacobian;
2487 GenerateMetaData( *trmesh, discOrder,
false, dataGLLNodes, dataGLLJacobian );
2490 int nElements = trmesh->faces.size();
2493 for(
int k = 0; k < nElements; k++ )
2495 const Face&
face = trmesh->faces[k];
2497 if(
face.edges.size() != 4 )
2499 _EXCEPTIONT(
"Non-quadrilateral face detected; "
2500 "incompatible with --gll" );
2505 const bool fDiscontinuous = ( discMethod == DiscretizationType_DGLL );
2507 if( fDiscontinuous )
2510 iMaxNode = nElements * discOrder * discOrder;
2515 for(
int i = 0; i < discOrder; i++ )
2516 for(
int j = 0; j < discOrder; j++ )
2517 for(
int k = 0; k < nElements; k++ )
2518 if( dataGLLNodes[i][j][k] > iMaxNode )
2519 iMaxNode = dataGLLNodes[i][j][k];
2523 DataArray1D< double > dG;
2524 DataArray1D< double > dW;
2526 GaussLobattoQuadrature::GetPoints( discOrder, 0.0, 1.0, dG, dW );
2529 const int nGaussP = 10;
2531 DataArray1D< double > dGaussG;
2532 DataArray1D< double > dGaussW;
2534 GaussQuadrature::GetPoints( nGaussP, 0.0, 1.0, dGaussG, dGaussW );
2537 dVar.Allocate( iMaxNode );
2538 dVarMB.Allocate( discOrder * discOrder * nElements );
2539 dNodeArea.Allocate( iMaxNode );
2542 for(
int k = 0; k < nElements; k++ )
2544 const Face&
face = trmesh->faces[k];
2549 for(
int i = 0; i < discOrder; i++ )
2551 for(
int j = 0; j < discOrder; j++ )
2559 ApplyLocalMap(
face, trmesh->nodes, dG[i], dG[j], node, dDx1G, dDx2G );
2562 double dNodeLon = atan2( node.y, node.x );
2563 if( dNodeLon < 0.0 )
2565 dNodeLon += 2.0 * M_PI;
2567 double dNodeLat = asin( node.z );
2569 double dSample = ( *testFunction )( dNodeLon, dNodeLat );
2571 if( fDiscontinuous )
2572 dVar[k * discOrder * discOrder + j * discOrder + i] = dSample;
2574 dVar[dataGLLNodes[j][i][k] - 1] = dSample;
2581 DataArray2D< double > dCoeff( discOrder, discOrder );
2583 for(
int p = 0; p < nGaussP; p++ )
2585 for(
int q = 0; q < nGaussP; q++ )
2593 ApplyLocalMap(
face, trmesh->nodes, dGaussG[p], dGaussG[q], node, dDx1G, dDx2G );
2596 Node nodeCross = CrossProduct( dDx1G, dDx2G );
2599 sqrt( nodeCross.x * nodeCross.x + nodeCross.y * nodeCross.y + nodeCross.z * nodeCross.z );
2603 SampleGLLFiniteElement( 0, discOrder, dGaussG[p], dGaussG[q], dCoeff );
2606 double dNodeLon = atan2( node.y, node.x );
2607 if( dNodeLon < 0.0 )
2609 dNodeLon += 2.0 * M_PI;
2611 double dNodeLat = asin( node.z );
2613 double dSample = ( *testFunction )( dNodeLon, dNodeLat );
2616 for(
int i = 0; i < discOrder; i++ )
2618 for(
int j = 0; j < discOrder; j++ )
2621 double dNodalArea = dCoeff[i][j] * dGaussW[p] * dGaussW[q] * dJacobian;
2623 dVar[dataGLLNodes[i][j][k] - 1] += dSample * dNodalArea;
2625 dNodeArea[dataGLLNodes[i][j][k] - 1] += dNodalArea;
2636 for(
size_t i = 0; i < dVar.GetRows(); i++ )
2638 dVar[i] /= dNodeArea[i];
2645 for(
unsigned j = 0; j < entities.
size(); j++ )
2646 for(
int p = 0; p < discOrder; p++ )
2647 for(
int q = 0; q < discOrder; q++ )
2649 const int offsetDOF = j * discOrder * discOrder + p * discOrder + q;
2650 dVarMB[offsetDOF] = dVar[col_dtoc_dofmap[offsetDOF]];
2655 for(
unsigned j = 0; j < entities.
size(); j++ )
2656 for(
int p = 0; p < discOrder; p++ )
2657 for(
int q = 0; q < discOrder; q++ )
2659 const int offsetDOF = j * discOrder * discOrder + p * discOrder + q;
2660 dVarMB[offsetDOF] = dVar[row_dtoc_dofmap[offsetDOF]];
2665 MB_CHK_ERR( m_interface->tag_set_data( solnTag, entities, &dVarMB[0] ) );
2670 if( discMethod == DiscretizationType_FV )
2675 dVar.Allocate( trmesh->faces.size() );
2677 std::vector< Node >& nodes = trmesh->nodes;
2680 for(
size_t i = 0; i < trmesh->faces.size(); i++ )
2682 const Face&
face = trmesh->faces[i];
2685 for(
size_t j = 0; j <
face.edges.size() - 2; j++ )
2688 const Node& node0 = nodes[
face[0]];
2689 const Node& node1 = nodes[
face[j + 1]];
2690 const Node& node2 = nodes[
face[j + 2]];
2694 faceTri.SetNode( 0,
face[0] );
2695 faceTri.SetNode( 1,
face[j + 1] );
2696 faceTri.SetNode( 2,
face[j + 2] );
2698 double dTriangleArea = CalculateFaceArea( faceTri, nodes );
2701 double dTotalSample = 0.0;
2704 for(
int k = 0; k < TriQuadraturePoints; k++ )
2706 Node node( TriQuadratureG[k][0] * node0.x + TriQuadratureG[k][1] * node1.x +
2707 TriQuadratureG[k][2] * node2.x,
2708 TriQuadratureG[k][0] * node0.y + TriQuadratureG[k][1] * node1.y +
2709 TriQuadratureG[k][2] * node2.y,
2710 TriQuadratureG[k][0] * node0.z + TriQuadratureG[k][1] * node1.z +
2711 TriQuadratureG[k][2] * node2.z );
2713 double dMagnitude = node.Magnitude();
2714 node.x /= dMagnitude;
2715 node.y /= dMagnitude;
2716 node.z /= dMagnitude;
2718 double dLon = atan2( node.y, node.x );
2723 double dLat = asin( node.z );
2725 double dSample = ( *testFunction )( dLon, dLat );
2727 dTotalSample += dSample * TriQuadratureW[k] * dTriangleArea;
2730 dVar[i] += dTotalSample / trmesh->vecFaceArea[i];
2733 MB_CHK_ERR( m_interface->tag_set_data( solnTag, entities, &dVar[0] ) );
2738 std::vector< Node >& nodes = trmesh->nodes;
2741 dVar.Allocate( nodes.size() );
2743 for(
size_t j = 0; j < nodes.size(); j++ )
2745 Node& node = nodes[j];
2746 double dMagnitude = node.Magnitude();
2747 node.x /= dMagnitude;
2748 node.y /= dMagnitude;
2749 node.z /= dMagnitude;
2750 double dLon = atan2( node.y, node.x );
2755 double dLat = asin( node.z );
2757 double dSample = ( *testFunction )( dLon, dLat );
2761 MB_CHK_ERR( m_interface->tag_set_data( solnTag, entities, &dVar[0] ) );
2771 std::map< std::string, double >& metrics,
2774 const bool outputEnabled = ( is_root );
2785 entities = ( m_remapper->point_cloud_source ? m_remapper->m_covering_source_vertices
2786 : m_remapper->m_covering_source_entities );
2787 discOrder = m_nDofsPEl_Src;
2795 ( m_remapper->point_cloud_target ? m_remapper->m_target_vertices : m_remapper->m_target_entities );
2796 discOrder = m_nDofsPEl_Dest;
2802 std::cout <<
"Invalid context specified for defining an analytical solution tag" << std::endl;
2803 return moab::MB_FAILURE;
2808 std::string exactTagName, projTagName;
2809 const int ntotsize = entities.
size() * discOrder * discOrder;
2810 std::vector< double > exactSolution( ntotsize, 0.0 ), projSolution( ntotsize, 0.0 );
2811 MB_CHK_ERR( m_interface->tag_get_name( exactTag, exactTagName ) );
2812 MB_CHK_ERR( m_interface->tag_get_data( exactTag, entities, &exactSolution[0] ) );
2813 MB_CHK_ERR( m_interface->tag_get_name( approxTag, projTagName ) );
2814 MB_CHK_ERR( m_interface->tag_get_data( approxTag, entities, &projSolution[0] ) );
2816 const auto& ovents = m_remapper->m_overlap_entities;
2818 std::vector< double > errnorms( 4, 0.0 ), globerrnorms( 4, 0.0 );
2819 double sumarea = 0.0;
2820 for(
size_t i = 0; i < ovents.size(); ++i )
2822 const int srcidx = m_remapper->m_overlap->vecSourceFaceIx[i];
2823 if( srcidx < 0 )
continue;
2824 const int tgtidx = m_remapper->m_overlap->vecTargetFaceIx[i];
2825 if( tgtidx < 0 )
continue;
2826 const double ovarea = m_remapper->m_overlap->vecFaceArea[i];
2827 const double error = fabs( exactSolution[tgtidx] - projSolution[tgtidx] );
2828 errnorms[0] += ovarea *
error;
2830 errnorms[3] = (
error > errnorms[3] ?
error : errnorms[3] );
2833 errnorms[2] = sumarea;
2834 #ifdef MOAB_HAVE_MPI
2837 MPI_Reduce( &errnorms[0], &globerrnorms[0], 3, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
2838 MPI_Reduce( &errnorms[3], &globerrnorms[3], 1, MPI_DOUBLE, MPI_MAX, 0, m_pcomm->comm() );
2841 for(
int i = 0; i < 4; ++i )
2842 globerrnorms[i] = errnorms[i];
2845 globerrnorms[0] = ( globerrnorms[0] / globerrnorms[2] );
2846 globerrnorms[1] = std::sqrt( globerrnorms[1] / globerrnorms[2] );
2849 metrics[
"L1Error"] = globerrnorms[0];
2850 metrics[
"L2Error"] = globerrnorms[1];
2851 metrics[
"LinfError"] = globerrnorms[3];
2855 std::cout <<
"Error metrics when comparing " << projTagName <<
" against " << exactTagName << std::endl;
2856 std::cout <<
"\t Total Intersection area = " << globerrnorms[2] << std::endl;
2857 std::cout <<
"\t L_1 error = " << globerrnorms[0] << std::endl;
2858 std::cout <<
"\t L_2 error = " << globerrnorms[1] << std::endl;
2859 std::cout <<
"\t L_inf error = " << globerrnorms[3] << std::endl;