Xyst test code coverage report
Current view: top level - Inciter - Refiner.cpp (source / functions) Hit Total Coverage
Commit: 7512f2d92be539d3e2bf801c81cb357720d8ffd7 Lines: 711 913 77.9 %
Date: 2025-04-27 10:04:21 Functions: 40 44 90.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 577 1626 35.5 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/Inciter/Refiner.cpp
       4                 :            :   \copyright 2012-2015 J. Bakosi,
       5                 :            :              2016-2018 Los Alamos National Security, LLC.,
       6                 :            :              2019-2021 Triad National Security, LLC.,
       7                 :            :              2022-2025 J. Bakosi
       8                 :            :              All rights reserved. See the LICENSE file for details.
       9                 :            :   \brief     Mesh refiner for interfacing the mesh refinement library
      10                 :            :   \see       Refiner.h for more info.
      11                 :            : */
      12                 :            : // *****************************************************************************
      13                 :            : 
      14                 :            : #include <vector>
      15                 :            : #include <algorithm>
      16                 :            : 
      17                 :            : #include "Refiner.hpp"
      18                 :            : #include "Reorder.hpp"
      19                 :            : #include "AMR/mesh_adapter.hpp"
      20                 :            : #include "AMR/Error.hpp"
      21                 :            : #include "InciterConfig.hpp"
      22                 :            : #include "DerivedData.hpp"
      23                 :            : #include "UnsMesh.hpp"
      24                 :            : #include "Centering.hpp"
      25                 :            : #include "Around.hpp"
      26                 :            : #include "Sorter.hpp"
      27                 :            : #include "Discretization.hpp"
      28                 :            : #include "Problems.hpp"
      29                 :            : #include "Vector.hpp"
      30                 :            : 
      31                 :            : namespace inciter {
      32                 :            : 
      33                 :            : extern ctr::Config g_cfg;
      34                 :            : 
      35                 :            : } // inciter::
      36                 :            : 
      37                 :            : using inciter::Refiner;
      38                 :            : 
      39                 :       2576 : Refiner::Refiner( std::size_t meshid,
      40                 :            :                   const CProxy_Transporter& transporter,
      41                 :            :                   const CProxy_Sorter& sorter,
      42                 :            :                   const tk::CProxy_MeshWriter& meshwriter,
      43                 :            :                   const std::vector< CProxy_Discretization >& discretization,
      44                 :            :                   const CProxy_RieCG& riecg,
      45                 :            :                   const CProxy_LaxCG& laxcg,
      46                 :            :                   const CProxy_ZalCG& zalcg,
      47                 :            :                   const CProxy_KozCG& kozcg,
      48                 :            :                   const CProxy_ChoCG& chocg,
      49                 :            :                   const CProxy_LohCG& lohcg,
      50                 :            :                   const tk::CProxy_ConjugateGradients& cgpre,
      51                 :            :                   const tk::CProxy_ConjugateGradients& cgmom,
      52                 :            :                   const tk::RefinerCallback& cbr,
      53                 :            :                   const tk::SorterCallback& cbs,
      54                 :            :                   const std::vector< std::size_t >& ginpoel,
      55                 :            :                   const tk::UnsMesh::CoordMap& coordmap,
      56                 :            :                   const std::map< int, std::vector< std::size_t > >& bface,
      57                 :            :                   const std::vector< std::size_t >& triinpoel,
      58                 :            :                   const std::map< int, std::vector< std::size_t > >& bnode,
      59                 :       2576 :                   int nchare ) :
      60                 :       2576 :   m_meshid( meshid ),
      61                 :       2576 :   m_ncit(0),
      62                 :       2576 :   m_host( transporter ),
      63         [ +  - ]:       2576 :   m_sorter( sorter ),
      64         [ +  - ]:       2576 :   m_meshwriter( meshwriter ),
      65         [ +  - ]:       2576 :   m_disc( discretization ),
      66         [ +  - ]:       2576 :   m_riecg( riecg ),
      67         [ +  - ]:       2576 :   m_laxcg( laxcg ),
      68         [ +  - ]:       2576 :   m_zalcg( zalcg ),
      69         [ +  - ]:       2576 :   m_kozcg( kozcg ),
      70         [ +  - ]:       2576 :   m_chocg( chocg ),
      71         [ +  - ]:       2576 :   m_lohcg( lohcg ),
      72         [ +  - ]:       2576 :   m_cgpre( cgpre ),
      73         [ +  - ]:       2576 :   m_cgmom( cgmom ),
      74                 :       2576 :   m_cbr( cbr ),
      75                 :       2576 :   m_cbs( cbs ),
      76         [ +  - ]:       2576 :   m_ginpoel( ginpoel ),
      77         [ +  - ]:       2576 :   m_el( tk::global2local( ginpoel ) ),     // fills m_inpoel, m_gid, m_lid
      78                 :       2576 :   m_coordmap( coordmap ),
      79         [ +  - ]:       2576 :   m_coord( flatcoord(coordmap) ),
      80         [ +  - ]:       2576 :   m_bface( bface ),
      81         [ +  - ]:       2576 :   m_bnode( bnode ),
      82         [ +  - ]:       2576 :   m_triinpoel( triinpoel ),
      83                 :       2576 :   m_nchare( nchare ),
      84                 :       2576 :   m_mode( RefMode::T0REF ),
      85                 :       2576 :   m_multi( g_cfg.get< tag::input >().size() > 1 ),
      86 [ -  + ][ +  - ]:       5152 :   m_initref( m_multi ? g_cfg.get< tag::href_ >()[ meshid ].get< tag::init >()
      87                 :       2576 :                      : g_cfg.get< tag::href, tag::init >() ),
      88                 :       2576 :   m_ninitref( m_initref.size() ),
      89         [ +  - ]:       2576 :   m_refiner(
      90                 :          0 :     m_multi ? g_cfg.get< tag::href_ >()[ meshid ].get< tag::maxlevels >()
      91                 :       2576 :             : g_cfg.get< tag::href, tag::maxlevels >(),
      92         [ -  + ]:       2576 :     m_inpoel ),
      93                 :       2576 :   m_nref( 0 ),
      94                 :       2576 :   m_nbnd( 0 ),
      95                 :       2576 :   m_extra( 0 ),
      96                 :       2576 :   m_oldntets( 0 ),
      97         [ +  - ]:       2576 :   m_rid( m_coord[0].size() ),
      98                 :            : //  m_oldrid(),
      99         [ +  - ]:       2576 :   m_lref( m_rid.size() ),
     100                 :            : //  m_oldparent(),
     101 [ +  - ][ +  - ]:      10304 :   m_writeCallback()
     102                 :            : // *****************************************************************************
     103                 :            : //  Constructor
     104                 :            : //! \param[in] meshid Mesh ID
     105                 :            : //! \param[in] transporter Transporter (host) proxy
     106                 :            : //! \param[in] sorter Mesh reordering (sorter) proxy
     107                 :            : //! \param[in] meshwriter Mesh writer proxy
     108                 :            : //! \param[in] discretization Discretization proxy for all meshes
     109                 :            : //! \param[in] riecg Discretization scheme proxy
     110                 :            : //! \param[in] laxcg Discretization scheme proxy
     111                 :            : //! \param[in] zalcg Discretization scheme proxy
     112                 :            : //! \param[in] kozcg Discretization scheme proxy
     113                 :            : //! \param[in] chocg Discretization scheme proxy
     114                 :            : //! \param[in] lohcg Discretization scheme proxy
     115                 :            : //! \param[in] cgpre ConjugateGradients Charm++ proxy for pressure solve
     116                 :            : //! \param[in] cgmom ConjugateGradients Charm++ proxy for momentum solve
     117                 :            : //! \param[in] cbr Charm++ callbacks for Refiner
     118                 :            : //! \param[in] cbs Charm++ callbacks for Sorter
     119                 :            : //! \param[in] ginpoel Mesh connectivity (this chare) using global node IDs
     120                 :            : //! \param[in] coordmap Mesh node coordinates (this chare) for global node IDs
     121                 :            : //! \param[in] bface File-internal elem ids of side sets
     122                 :            : //! \param[in] triinpoel Triangle face connectivity with global IDs
     123                 :            : //! \param[in] bnode Node lists of side sets
     124                 :            : //! \param[in] nchare Total number of refiner chares (chare array elements)
     125                 :            : // *****************************************************************************
     126                 :            : {
     127 [ -  + ][ -  - ]:       2576 :   Assert( !m_ginpoel.empty(), "No elements assigned to refiner chare" );
         [ -  - ][ -  - ]
     128 [ +  - ][ -  + ]:       2576 :   Assert( tk::positiveJacobians( m_inpoel, m_coord ),
         [ -  - ][ -  - ]
                 [ -  - ]
     129                 :            :           "Input mesh to Refiner Jacobian non-positive" );
     130 [ +  - ][ +  - ]:       2576 :   Assert( !tk::leakyPartition(
         [ +  - ][ -  + ]
         [ -  - ][ -  - ]
                 [ -  - ]
     131                 :            :             tk::genEsuelTet( m_inpoel, tk::genEsup(m_inpoel,4) ),
     132                 :            :             m_inpoel, m_coord ),
     133                 :            :           "Input mesh to Refiner leaky" );
     134                 :            : 
     135                 :            :   #if not defined(__INTEL_COMPILER) || defined(NDEBUG)
     136                 :            :   // The above ifdef skips running the conformity test with the intel compiler
     137                 :            :   // in debug mode only. This is necessary because in tk::conforming(), filling
     138                 :            :   // up the map can fail with some meshes (only in parallel), e.g., tube.exo,
     139                 :            :   // used by some regression tests, due to the intel compiler generating some
     140                 :            :   // garbage incorrect code - only in debug, only in parallel, only with that
     141                 :            :   // mesh.
     142 [ +  - ][ -  + ]:       2576 :   Assert( tk::conforming( m_inpoel, m_coord, true, m_rid ),
         [ -  - ][ -  - ]
                 [ -  - ]
     143                 :            :           "Input mesh to Refiner not conforming" );
     144                 :            :   #endif
     145                 :            : 
     146                 :            :   // Generate local -> refiner lib node id map and its inverse
     147         [ +  - ]:       2576 :   libmap();
     148                 :            : 
     149                 :            :   // Reverse initial mesh refinement type list (will pop from back)
     150         [ +  - ]:       2576 :   std::reverse( begin(m_initref), end(m_initref) );
     151                 :            : 
     152                 :            :   // Generate boundary data structures for coarse mesh
     153         [ +  - ]:       2576 :   coarseMesh();
     154                 :            : 
     155                 :            :   // If initial mesh refinement is configured, start initial mesh refinement.
     156         [ -  + ]:       2576 :   const auto& ht = m_multi ? g_cfg.get< tag::href_ >()[ m_meshid ]
     157                 :       2576 :                            : g_cfg.get< tag::href >();
     158 [ +  + ][ +  - ]:       2576 :   if (ht.get< tag::t0 >() && m_ninitref > 0) {
                 [ +  + ]
     159         [ +  - ]:         27 :     t0ref();
     160                 :            :   } else {
     161         [ +  - ]:       2549 :     endt0ref();
     162                 :            :   }
     163                 :       2576 : }
     164                 :            : 
     165                 :            : void
     166                 :       2576 : Refiner::libmap()
     167                 :            : // *****************************************************************************
     168                 :            : // (Re-)generate local -> refiner lib node id map and its inverse
     169                 :            : // *****************************************************************************
     170                 :            : {
     171                 :            :   // Fill initial (matching) mapping between local and refiner node ids
     172                 :       2576 :   std::iota( begin(m_rid), end(m_rid), 0 );
     173                 :            : 
     174                 :            :   // Fill in inverse, mapping refiner to local node ids
     175                 :       2576 :   std::size_t i = 0;
     176 [ +  - ][ +  + ]:     305304 :   for (auto r : m_rid) m_lref[r] = i++;
     177                 :       2576 : }
     178                 :            : 
     179                 :            : void
     180                 :       2585 : Refiner::coarseMesh()
     181                 :            : // *****************************************************************************
     182                 :            : // (Re-)generate side set and block data structures for coarse mesh
     183                 :            : // *****************************************************************************
     184                 :            : {
     185                 :            :   // Generate unique set of faces for each side set of the input (coarsest) mesh
     186                 :       2585 :   m_coarseBndFaces.clear();
     187         [ +  + ]:       8522 :   for (const auto& [ setid, faceids ] : m_bface) {
     188         [ +  - ]:       5937 :     auto& faces = m_coarseBndFaces[ setid ];
     189         [ +  + ]:     266321 :     for (auto f : faceids) {
     190         [ +  - ]:     260384 :       faces.insert(
     191                 :     260384 :         {{{ m_triinpoel[f*3+0], m_triinpoel[f*3+1], m_triinpoel[f*3+2] }}} );
     192                 :            :     }
     193                 :            :   }
     194                 :            : 
     195                 :            :   // Generate unique set of nodes for each side set of the input (coarsest) mesh
     196                 :       2585 :   m_coarseBndNodes.clear();
     197         [ +  + ]:       5390 :   for (const auto& [ setid, nodes ] : m_bnode) {
     198 [ +  - ][ +  - ]:       2805 :     m_coarseBndNodes[ setid ].insert( begin(nodes), end(nodes) );
     199                 :            :   }
     200                 :       2585 : }
     201                 :            : 
     202                 :            : void
     203                 :       2576 : Refiner::sendProxy()
     204                 :            : // *****************************************************************************
     205                 :            : // Send Refiner proxy to Discretization objects
     206                 :            : //! \details This should be called when bound Discretization chare array
     207                 :            : //!   elements have already been created.
     208                 :            : // *****************************************************************************
     209                 :            : {
     210                 :            :   // Make sure (bound) Discretization chare is already created and accessible
     211 [ +  - ][ +  - ]:       2576 :   Assert( m_disc[ m_meshid ][ thisIndex ].ckLocal() != nullptr,
         [ -  + ][ -  - ]
         [ -  - ][ -  - ]
     212                 :            :           "About to dereference nullptr" );
     213                 :            : 
     214                 :            :   // Pass Refiner Charm++ chare proxy to fellow (bound) Discretization object
     215 [ +  - ][ +  - ]:       2576 :   m_disc[ m_meshid ][ thisIndex ].ckLocal()->setRefiner( thisProxy );
                 [ +  - ]
     216                 :       2576 : }
     217                 :            : 
     218                 :            : void
     219                 :          9 : Refiner::reorder()
     220                 :            : // *****************************************************************************
     221                 :            : // Query Sorter and update local mesh with the reordered one
     222                 :            : // *****************************************************************************
     223                 :            : {
     224                 :          9 :   m_sorter[thisIndex].ckLocal()->
     225 [ +  - ][ +  - ]:          9 :     mesh( m_ginpoel, m_coordmap, m_triinpoel, m_bnode );
                 [ +  - ]
     226                 :            : 
     227                 :            :   // Update local mesh data based on data just received from Sorter
     228         [ +  - ]:          9 :   m_el = tk::global2local( m_ginpoel );     // fills m_inpoel, m_gid, m_lid
     229         [ +  - ]:          9 :   m_coord = flatcoord( m_coordmap );
     230                 :            : 
     231                 :            :   // Re-generate boundary data structures for coarse mesh
     232                 :          9 :   coarseMesh();
     233                 :            : 
     234                 :            :   // WARNING: This re-creates the AMR lib which is probably not what we
     235                 :            :   // ultimately want, beacuse this deletes its history recorded during initial
     236                 :            :   // (t<0) refinement. However, this appears to correctly update the local mesh
     237                 :            :   // based on the reordered one (from Sorter) at least when t0ref is off.
     238         [ -  + ]:          9 :   const auto& ht = m_multi ? g_cfg.get< tag::href_ >()[ m_meshid ]
     239                 :          9 :                            : g_cfg.get< tag::href >();
     240         [ +  - ]:          9 :   m_refiner = AMR::mesh_adapter_t( ht.get< tag::maxlevels >(), m_inpoel );
     241                 :          9 : }
     242                 :            : 
     243                 :            : tk::UnsMesh::Coords
     244                 :       2585 : Refiner::flatcoord( const tk::UnsMesh::CoordMap& coordmap )
     245                 :            : // *****************************************************************************
     246                 :            : // Generate flat coordinate data from coordinate map
     247                 :            : //! \param[in] coordmap Coordinates associated to global node IDs of mesh chunk
     248                 :            : //! \return Flat coordinate data
     249                 :            : // *****************************************************************************
     250                 :            : {
     251                 :       2585 :   tk::UnsMesh::Coords coord;
     252                 :            : 
     253                 :            :   // Convert node coordinates associated to global node IDs to a flat vector
     254                 :       2585 :   auto npoin = coordmap.size();
     255 [ -  + ][ -  - ]:       2585 :   Assert( m_gid.size() == npoin, "Size mismatch" );
         [ -  - ][ -  - ]
     256         [ +  - ]:       2585 :   coord[0].resize( npoin );
     257         [ +  - ]:       2585 :   coord[1].resize( npoin );
     258         [ +  - ]:       2585 :   coord[2].resize( npoin );
     259         [ +  + ]:     307623 :   for (const auto& [ gid, coords ] : coordmap) {
     260         [ +  - ]:     305038 :     auto i = tk::cref_find( m_lid, gid );
     261 [ -  + ][ -  - ]:     305038 :     Assert( i < npoin, "Indexing out of coordinate map" );
         [ -  - ][ -  - ]
     262                 :     305038 :     coord[0][i] = coords[0];
     263                 :     305038 :     coord[1][i] = coords[1];
     264                 :     305038 :     coord[2][i] = coords[2];
     265                 :            :   }
     266                 :            : 
     267                 :       2585 :   return coord;
     268                 :          0 : }
     269                 :            : 
     270                 :            : void
     271                 :          0 : Refiner::dtref( const std::map< int, std::vector< std::size_t > >& bface,
     272                 :            :                 const std::map< int, std::vector< std::size_t > >& bnode,
     273                 :            :                 const std::vector< std::size_t >& triinpoel )
     274                 :            : // *****************************************************************************
     275                 :            : // Start mesh refinement (during time stepping, t>0)
     276                 :            : //! \param[in] bface Boundary-faces mapped to side set ids
     277                 :            : //! \param[in] bnode Boundary-node lists mapped to side set ids
     278                 :            : //! \param[in] triinpoel Boundary-face connectivity
     279                 :            : // *****************************************************************************
     280                 :            : {
     281                 :          0 :   m_mode = RefMode::DTREF;
     282                 :            : 
     283                 :            :   // Update boundary node lists
     284                 :          0 :   m_bface = bface;
     285                 :          0 :   m_bnode = bnode;
     286         [ -  - ]:          0 :   m_triinpoel = tk::remap(triinpoel, m_gid);
     287                 :            : 
     288                 :          0 :   start();
     289                 :          0 : }
     290                 :            : 
     291                 :            : void
     292                 :         71 : Refiner::t0ref()
     293                 :            : // *****************************************************************************
     294                 :            : // Output mesh to file before a new step mesh refinement
     295                 :            : // *****************************************************************************
     296                 :            : {
     297 [ -  + ][ -  - ]:         71 :   Assert( m_ninitref > 0, "No initial mesh refinement steps configured" );
         [ -  - ][ -  - ]
     298                 :            :   // Output initial mesh to file
     299                 :         71 :   auto l = m_ninitref - m_initref.size();  // num initref steps completed
     300                 :         71 :   auto t0 = g_cfg.get< tag::t0 >();
     301         [ +  + ]:         71 :   if (l == 0) {
     302 [ +  - ][ +  - ]:         27 :     writeMesh( "t0ref", l, t0-1.0,
     303 [ +  - ][ +  - ]:         54 :       CkCallback( CkIndex_Refiner::start(), thisProxy[thisIndex] ) );
                 [ +  - ]
     304                 :            :   } else {
     305                 :         44 :     start();
     306                 :            :   }
     307                 :         71 : }
     308                 :            : 
     309                 :            : void
     310                 :         71 : Refiner::start()
     311                 :            : // *****************************************************************************
     312                 :            : //  Start new step of mesh refinement
     313                 :            : // *****************************************************************************
     314                 :            : {
     315                 :         71 :   m_extra = 0;
     316                 :         71 :   m_ch.clear();
     317                 :         71 :   m_remoteEdgeData.clear();
     318                 :         71 :   m_remoteEdges.clear();
     319                 :            : 
     320                 :         71 :   updateEdgeData();
     321                 :            : 
     322                 :            :   // Generate and communicate boundary edges
     323                 :         71 :   bndEdges();
     324                 :         71 : }
     325                 :            : 
     326                 :            : void
     327                 :         71 : Refiner::bndEdges()
     328                 :            : // *****************************************************************************
     329                 :            : // Generate boundary edges and send them to all chares
     330                 :            : //! \details Extract edges on the boundary only. The boundary edges (shared by
     331                 :            : //!   multiple chares) will be agreed on a refinement that yields a conforming
     332                 :            : //!   mesh across chares boundaries.
     333                 :            : // *****************************************************************************
     334                 :            : {
     335                 :            :   // Compute the number of edges (chunksize) a chare will respond to when
     336                 :            :   // computing shared edges
     337                 :         71 :   auto N = static_cast< std::size_t >( m_nchare );
     338                 :            :   // cppcheck-suppress unreadVariable
     339                 :         71 :   std::size_t chunksize = std::numeric_limits< std::size_t >::max() / N;
     340                 :            : 
     341                 :            :   // Generate boundary edges of our mesh chunk
     342                 :         71 :   std::unordered_map< int, EdgeSet > chbedges;
     343         [ +  - ]:         71 :   auto esup = tk::genEsup( m_inpoel, 4 );         // elements surrounding points
     344         [ +  - ]:         71 :   auto esuel = tk::genEsuelTet( m_inpoel, esup ); // elems surrounding elements
     345         [ +  + ]:      72875 :   for (std::size_t e=0; e<esuel.size()/4; ++e) {
     346                 :      72804 :     auto mark = e*4;
     347         [ +  + ]:     364020 :     for (std::size_t f=0; f<4; ++f) {
     348         [ +  + ]:     291216 :       if (esuel[mark+f] == -1) {
     349                 :      22868 :         auto A = m_ginpoel[ mark+tk::lpofa[f][0] ];
     350                 :            :         // cppcheck-suppress unreadVariable
     351                 :      22868 :         auto B = m_ginpoel[ mark+tk::lpofa[f][1] ];
     352                 :            :         // cppcheck-suppress unreadVariable
     353                 :      22868 :         auto C = m_ginpoel[ mark+tk::lpofa[f][2] ];
     354 [ +  - ][ -  + ]:      22868 :         Assert( m_lid.find( A ) != end(m_lid), "Local node ID not found" );
         [ -  - ][ -  - ]
                 [ -  - ]
     355 [ +  - ][ -  + ]:      22868 :         Assert( m_lid.find( B ) != end(m_lid), "Local node ID not found" );
         [ -  - ][ -  - ]
                 [ -  - ]
     356 [ +  - ][ -  + ]:      22868 :         Assert( m_lid.find( C ) != end(m_lid), "Local node ID not found" );
         [ -  - ][ -  - ]
                 [ -  - ]
     357                 :            :         // assign edges to bins a single chare will respond to when computing
     358                 :            :         // shared edges
     359                 :      22868 :         auto bin = A / chunksize;
     360 [ -  + ][ -  - ]:      22868 :         Assert( bin < N, "Will index out of number of chares" );
         [ -  - ][ -  - ]
     361 [ +  - ][ +  - ]:      22868 :         chbedges[ static_cast<int>(bin) ].insert( {A,B} );
     362                 :      22868 :         bin = B / chunksize;
     363 [ -  + ][ -  - ]:      22868 :         Assert( bin < N, "Will index out of number of chares" );
         [ -  - ][ -  - ]
     364 [ +  - ][ +  - ]:      22868 :         chbedges[ static_cast<int>(bin) ].insert( {B,C} );
     365                 :      22868 :         bin = C / chunksize;
     366 [ -  + ][ -  - ]:      22868 :         Assert( bin < N, "Will index out of number of chares" );
         [ -  - ][ -  - ]
     367 [ +  - ][ +  - ]:      22868 :         chbedges[ static_cast<int>(bin) ].insert( {C,A} );
     368                 :            :       }
     369                 :            :     }
     370                 :            :   }
     371                 :            : 
     372                 :            :   // Send edges in bins to chares that will compute shared edges
     373                 :         71 :   m_nbnd = chbedges.size();
     374         [ -  + ]:         71 :   if (m_nbnd == 0)
     375         [ -  - ]:          0 :     contribute( sizeof(std::size_t), &m_meshid, CkReduction::nop,
     376                 :          0 :                 m_cbr.get< tag::queried >() );
     377                 :            :   else
     378         [ +  + ]:        168 :     for (const auto& [ targetchare, bndedges ] : chbedges)
     379 [ +  - ][ +  - ]:         97 :       thisProxy[ targetchare ].query( thisIndex, bndedges );
     380                 :         71 : }
     381                 :            : 
     382                 :            : void
     383                 :         97 : Refiner::query( int fromch, const EdgeSet& edges )
     384                 :            : // *****************************************************************************
     385                 :            : // Incoming query for a list boundary edges for which this chare compiles
     386                 :            : // shared edges
     387                 :            : //! \param[in] fromch Sender chare ID
     388                 :            : //! \param[in] edges Chare-boundary edge list from another chare
     389                 :            : // *****************************************************************************
     390                 :            : {
     391                 :            :   // Store incoming edges in edge->chare and its inverse, chare->edge, maps
     392 [ +  - ][ +  - ]:      44086 :   for (const auto& e : edges) m_edgech[ e ].push_back( fromch );
                 [ +  + ]
     393                 :         97 :   m_chedge[ fromch ].insert( begin(edges), end(edges) );
     394                 :            :   // Report back to chare message received from
     395 [ +  - ][ +  - ]:         97 :   thisProxy[ fromch ].recvquery();
     396                 :         97 : }
     397                 :            : 
     398                 :            : void
     399                 :         97 : Refiner::recvquery()
     400                 :            : // *****************************************************************************
     401                 :            : // Receive receipt of boundary edge lists to query
     402                 :            : // *****************************************************************************
     403                 :            : {
     404         [ +  + ]:         97 :   if (--m_nbnd == 0)
     405                 :         71 :     contribute( sizeof(std::size_t), &m_meshid, CkReduction::nop,
     406                 :         71 :                 m_cbr.get< tag::queried >() );
     407                 :         97 : }
     408                 :            : 
     409                 :            : void
     410                 :         71 : Refiner::response()
     411                 :            : // *****************************************************************************
     412                 :            : //  Respond to boundary edge list queries
     413                 :            : // *****************************************************************************
     414                 :            : {
     415                 :         71 :   std::unordered_map< int, std::vector< int > > exp;
     416                 :            : 
     417                 :            :   // Compute shared edges whose chare ids will be sent back to querying chares
     418         [ +  + ]:        168 :   for (const auto& [ neighborchare, bndedges ] : m_chedge) {
     419         [ +  - ]:         97 :     auto& e = exp[ neighborchare ];
     420         [ +  + ]:      44086 :     for (const auto& ed : bndedges)
     421 [ +  - ][ +  + ]:      94126 :       for (auto d : tk::cref_find(m_edgech,ed))
     422         [ +  + ]:      50137 :         if (d != neighborchare)
     423                 :            :           // cppcheck-suppress useStlAlgorithm
     424         [ +  - ]:       6148 :           e.push_back( d );
     425                 :            :   }
     426                 :            : 
     427                 :            :   // Send chare ids of shared edges to chares that issued a query to us. Shared
     428                 :            :   // boundary edges assigned to chare ids sharing the boundary edge were
     429                 :            :   // computed above for those chares that queried this map from us. These
     430                 :            :   // boundary edges form a distributed table and we only work on a chunk of it.
     431                 :            :   // Note that we only send data back to those chares that have queried us. The
     432                 :            :   // receiving sides do not know in advance if they receive messages or not.
     433                 :            :   // Completion is detected by having the receiver respond back and counting
     434                 :            :   // the responses on the sender side, i.e., this chare.
     435                 :         71 :   m_nbnd = exp.size();
     436         [ +  + ]:         71 :   if (m_nbnd == 0)
     437         [ +  - ]:         20 :     contribute( sizeof(std::size_t), &m_meshid, CkReduction::nop,
     438                 :         20 :                 m_cbr.get< tag::responded >() );
     439                 :            :   else
     440         [ +  + ]:        148 :     for (const auto& [ targetchare, bndedges ] : exp)
     441 [ +  - ][ +  - ]:         97 :       thisProxy[ targetchare ].bnd( thisIndex, bndedges );
     442                 :         71 : }
     443                 :            : 
     444                 :            : void
     445                 :         97 : Refiner::bnd( int fromch, const std::vector< int >& chares )
     446                 :            : // *****************************************************************************
     447                 :            : // Receive shared boundary edges for our mesh chunk
     448                 :            : //! \param[in] fromch Sender chare ID
     449                 :            : //! \param[in] chares Chare ids we share edges with
     450                 :            : // *****************************************************************************
     451                 :            : {
     452                 :            :   // Store chare ids we share edges with
     453                 :         97 :   m_ch.insert( begin(chares), end(chares) );
     454                 :            : 
     455                 :            :   // Report back to chare message received from
     456 [ +  - ][ +  - ]:         97 :   thisProxy[ fromch ].recvbnd();
     457                 :         97 : }
     458                 :            : 
     459                 :            : void
     460                 :         97 : Refiner::recvbnd()
     461                 :            : // *****************************************************************************
     462                 :            : // Receive receipt of shared boundary edges
     463                 :            : // *****************************************************************************
     464                 :            : {
     465         [ +  + ]:         97 :   if (--m_nbnd == 0)
     466                 :         51 :     contribute( sizeof(std::size_t), &m_meshid, CkReduction::nop,
     467                 :         51 :                 m_cbr.get< tag::responded >() );
     468                 :         97 : }
     469                 :            : 
     470                 :            : void
     471                 :         71 : Refiner::refine()
     472                 :            : // *****************************************************************************
     473                 :            : //  Do a single step of mesh refinement (really, only tag edges)
     474                 :            : //! \details During initial (t<0, t0ref) mesh refinement, this is a single step
     475                 :            : //!   in a potentially multiple-entry list of initial adaptive mesh refinement
     476                 :            : //!   steps. Distribution of the chare-boundary edges must have preceded this
     477                 :            : //!   step, so that boundary edges (shared by multiple chares) can agree on a
     478                 :            : //!   refinement that yields a conforming mesh across chare boundaries.
     479                 :            : //!
     480                 :            : //!   During-timestepping (t>0, dtref) mesh refinement this is called once, as
     481                 :            : //!   we only do a single step during time stepping.
     482                 :            : // *****************************************************************************
     483                 :            : {
     484                 :            :   // Free memory used for computing shared boundary edges
     485                 :         71 :   tk::destroy( m_edgech );
     486                 :         71 :   tk::destroy( m_chedge );
     487                 :            : 
     488                 :            :   // Perform leak test on old mesh
     489 [ +  - ][ +  - ]:         71 :   Assert( !tk::leakyPartition(
         [ +  - ][ -  + ]
         [ -  - ][ -  - ]
                 [ -  - ]
     490                 :            :             tk::genEsuelTet( m_inpoel, tk::genEsup(m_inpoel,4) ),
     491                 :            :             m_inpoel, m_coord ),
     492                 :            :           "Mesh partition before refinement leaky" );
     493                 :            : 
     494         [ +  - ]:         71 :   if (m_mode == RefMode::T0REF) {
     495                 :            : 
     496                 :            :     // Refine mesh based on next initial refinement type
     497         [ +  - ]:         71 :     if (!m_initref.empty()) {
     498         [ +  - ]:         71 :       auto r = m_initref.back();    // consume (reversed) list from its back
     499         [ +  + ]:         71 :       if (r == "uniform")
     500         [ +  - ]:         31 :         uniformRefine();
     501         [ +  + ]:         40 :       else if (r == "uniform_deref")
     502         [ +  - ]:         24 :         uniformDeRefine();
     503         [ +  - ]:         16 :       else if (r == "ic")
     504         [ +  - ]:         16 :         errorRefine();
     505         [ -  - ]:          0 :       else if (r == "coord")
     506         [ -  - ]:          0 :         coordRefine();
     507         [ -  - ]:          0 :       else if (r == "edges")
     508         [ -  - ]:          0 :         edgelistRefine();
     509 [ -  - ][ -  - ]:          0 :       else Throw( "Initial AMR type not implemented" );
                 [ -  - ]
     510                 :         71 :     }
     511                 :            : 
     512         [ -  - ]:          0 :   } else if (m_mode == RefMode::DTREF) {
     513                 :            : 
     514                 :            :     //if (true)//g_cfg.get< tag::amr, tag::dtref_uniform >())
     515                 :          0 :       uniformRefine();
     516                 :            :     //else
     517                 :            :       //errorRefine();
     518                 :            : 
     519 [ -  - ][ -  - ]:          0 :   } else Throw( "RefMode not implemented" );
                 [ -  - ]
     520                 :            : 
     521                 :            :   // Communicate extra edges
     522                 :         71 :   comExtra();
     523                 :         71 : }
     524                 :            : 
     525                 :            : void
     526                 :         71 : Refiner::comExtra()
     527                 :            : // *****************************************************************************
     528                 :            : // Communicate extra edges along chare boundaries
     529                 :            : // *****************************************************************************
     530                 :            : {
     531                 :            :   // Export extra added nodes on our mesh chunk boundary to other chares
     532         [ +  + ]:         71 :   if (m_ch.empty()) {
     533                 :         13 :     correctref();
     534                 :            :   } else {
     535         [ +  + ]:        146 :     for (auto c : m_ch) {  // for all chares we share at least an edge with
     536 [ +  - ][ +  - ]:         88 :       thisProxy[c].addRefBndEdges(thisIndex, m_localEdgeData, m_intermediates);
                 [ +  - ]
     537                 :            :     }
     538                 :            :   }
     539                 :         71 : }
     540                 :            : 
     541                 :            : void
     542                 :         88 : Refiner::addRefBndEdges(
     543                 :            :   int fromch,
     544                 :            :   const AMR::EdgeData& ed,
     545                 :            :   const std::unordered_set< std::size_t >& intermediates )
     546                 :            : // *****************************************************************************
     547                 :            : //! Receive edges on our chare boundary from other chares
     548                 :            : //! \param[in] fromch Chare call coming from
     549                 :            : //! \param[in] ed Edges on chare boundary
     550                 :            : //! \param[in] intermediates Intermediate nodes
     551                 :            : //! \details Other than update remoteEdge data, this function also updates
     552                 :            : //!   locking information for such edges whos nodes are marked as intermediate
     553                 :            : //!   by neighboring chares.
     554                 :            : // *****************************************************************************
     555                 :            : {
     556                 :            :   // Save/augment buffers of edge data for each sender chare
     557                 :         88 :   auto& red = m_remoteEdgeData[ fromch ];
     558                 :         88 :   auto& re = m_remoteEdges[ fromch ];
     559                 :            :   using edge_data_t = std::tuple< Edge, int, int, AMR::Edge_Lock_Case >;
     560         [ +  + ]:      77072 :   for (const auto& [ edge, data ] : ed) {
     561         [ +  - ]:     153968 :     red.push_back( edge_data_t{ edge, std::get<0>(data), std::get<1>(data),
     562                 :      76984 :       std::get<2>(data) } );
     563         [ +  - ]:      76984 :     re.push_back( edge );
     564                 :            :   }
     565                 :            : 
     566                 :            :   // Add intermediates to mesh refiner lib
     567                 :            :   // needs to be done only when mesh has been actually updated, i.e. first iter
     568         [ +  - ]:         88 :   if (m_ncit == 0) {
     569         [ +  - ]:         88 :     auto esup = tk::genEsup( m_inpoel, 4 );
     570         [ +  - ]:         88 :     auto psup = tk::genPsup( m_inpoel, 4, esup );
     571         [ +  + ]:        239 :     for (const auto g : intermediates) {
     572         [ +  - ]:        151 :       auto l = m_lid.find( g ); // convert to local node ids
     573         [ -  + ]:        151 :       if (l != end(m_lid)) {
     574                 :            :         // lock all edges connected to intermediate node
     575                 :          0 :         auto p = l->second;
     576         [ -  - ]:          0 :         for (auto q : tk::Around(psup,p)) {
     577         [ -  - ]:          0 :           AMR::edge_t e(m_rid[p], m_rid[q]);
     578         [ -  - ]:          0 :           auto& refedge = m_refiner.tet_store.edge_store.get(e);
     579         [ -  - ]:          0 :           if (refedge.lock_case == AMR::Edge_Lock_Case::unlocked) {
     580                 :          0 :             refedge.lock_case = AMR::Edge_Lock_Case::temporary; //intermediate;
     581                 :          0 :             refedge.needs_refining = 0;
     582                 :            :           }
     583                 :            :         }
     584                 :            :       }
     585                 :            :     }
     586                 :         88 :   }
     587                 :            : 
     588                 :            :   // Heard from every worker we share at least a single edge with
     589         [ +  + ]:         88 :   if (++m_nref == m_ch.size()) {
     590                 :         58 :     m_nref = 0;
     591                 :            : 
     592         [ +  - ]:         58 :     updateBndEdgeData();
     593                 :            : 
     594         [ +  - ]:         58 :     std::vector< std::size_t > meshdata{ m_meshid };
     595         [ +  - ]:         58 :     contribute( meshdata, CkReduction::max_ulong,
     596                 :         58 :                 m_cbr.get< tag::compatibility >() );
     597                 :         58 :   }
     598                 :         88 : }
     599                 :            : 
     600                 :            : void
     601                 :         71 : Refiner::correctref()
     602                 :            : // *****************************************************************************
     603                 :            : //  Correct extra edges to arrive at conforming mesh across chare boundaries
     604                 :            : //! \details This function is called repeatedly until there is not a a single
     605                 :            : //!    edge that needs correction for the whole distributed problem to arrive at
     606                 :            : //!    a conforming mesh across chare boundaries during a mesh refinement step.
     607                 :            : // *****************************************************************************
     608                 :            : {
     609                 :         71 :   auto unlocked = AMR::Edge_Lock_Case::unlocked;
     610                 :            : 
     611                 :            :   // Storage for edge data that need correction to yield a conforming mesh
     612                 :         71 :   AMR::EdgeData extra;
     613                 :         71 :   std::size_t neigh_extra(0);
     614                 :            : 
     615                 :            :   // Vars for debugging purposes
     616                 :            :   // cppcheck-suppress unreadVariable
     617                 :         71 :   std::size_t nlocked(0);
     618                 :         71 :   std::array< std::size_t, 4 > ncorrcase{{0,0,0,0}};
     619                 :            : 
     620                 :            :   // loop through all edges shared with other chares
     621         [ +  + ]:        159 :   for (const auto& [ neighborchare, edgedata ] : m_remoteEdgeData) {
     622                 :      77072 :     for (const auto& [edge,remote_needs_refining,remote_needs_derefining,
     623         [ +  + ]:     154144 :       remote_lock_case] : edgedata) {
     624                 :            :       // find local data of remote edge
     625         [ +  - ]:      76984 :       auto it = m_localEdgeData.find( edge );
     626         [ +  + ]:      76984 :       if (it != end(m_localEdgeData)) {
     627                 :       4484 :         auto& local = it->second;
     628                 :       4484 :         auto& local_needs_refining = std::get<0>(local);
     629                 :       4484 :         auto& local_needs_derefining = std::get<1>(local);
     630                 :       4484 :         auto& local_lock_case = std::get<2>(local);
     631                 :            : 
     632                 :            :         // cppcheck-suppress unreadVariable
     633                 :       4484 :         auto local_needs_refining_orig = local_needs_refining;
     634                 :            :         // cppcheck-suppress unreadVariable
     635                 :       4484 :         auto local_needs_derefining_orig = local_needs_derefining;
     636                 :            :         // cppcheck-suppress unreadVariable
     637                 :       4484 :         auto local_lock_case_orig = local_lock_case;
     638                 :            : 
     639 [ -  + ][ -  - ]:       4484 :         Assert( !(local_lock_case > unlocked && local_needs_refining),
         [ -  - ][ -  - ]
                 [ -  - ]
     640                 :            :                 "Invalid local edge: locked & needs refining" );
     641 [ -  + ][ -  - ]:       4484 :         Assert( !(remote_lock_case > unlocked && remote_needs_refining),
         [ -  - ][ -  - ]
                 [ -  - ]
     642                 :            :                 "Invalid remote edge: locked & needs refining" );
     643 [ +  + ][ -  + ]:       4484 :         Assert( !(local_needs_derefining == 1 && local_needs_refining > 0),
         [ -  - ][ -  - ]
                 [ -  - ]
     644                 :            :                 "Invalid local edge: needs refining and derefining" );
     645                 :            : 
     646                 :            :         // The parallel compatibility (par-compat) algorithm
     647                 :            : 
     648                 :            :         // compute lock from local and remote locks as most restrictive
     649                 :       4484 :         local_lock_case = std::max( local_lock_case, remote_lock_case );
     650                 :            : 
     651         [ -  + ]:       4484 :         if (local_lock_case > unlocked) {
     652                 :          0 :           local_needs_refining = 0;
     653         [ -  - ]:          0 :           if (local_needs_refining != local_needs_refining_orig ||
     654         [ -  - ]:          0 :             local_lock_case != local_lock_case_orig)
     655                 :          0 :             ++ncorrcase[0];
     656                 :            :         }
     657                 :            : 
     658                 :            :         // Possible combinations of remote-local ref-deref decisions
     659                 :            :         // rows 1, 5, 9: no action needed.
     660                 :            :         // rows 4, 7, 8: no action on local-side; comm needed.
     661                 :            :         //
     662                 :            :         //    LOCAL          |        REMOTE    |  Result
     663                 :            :         // 1  d              |        d         |  d
     664                 :            :         // 2  d              |        -         |  -
     665                 :            :         // 3  d              |        r         |  r
     666                 :            :         // 4  -              |        d         |  -
     667                 :            :         // 5  -              |        -         |  -
     668                 :            :         // 6  -              |        r         |  r
     669                 :            :         // 7  r              |        d         |  r
     670                 :            :         // 8  r              |        -         |  r
     671                 :            :         // 9  r              |        r         |  r
     672                 :            : 
     673                 :            :         // Rows 3, 6
     674                 :            :         // If remote wants to refine
     675         [ +  + ]:       4484 :         if (remote_needs_refining == 1) {
     676         [ +  - ]:       2198 :           if (local_lock_case == unlocked) {
     677                 :       2198 :             local_needs_refining = 1;
     678                 :       2198 :             local_needs_derefining = false;
     679         [ +  - ]:       2198 :             if (local_needs_refining != local_needs_refining_orig ||
     680         [ -  + ]:       2198 :               local_needs_derefining != local_needs_derefining_orig)
     681                 :          0 :               ++ncorrcase[1];
     682                 :            :           }
     683                 :            :           else {
     684                 :          0 :            ++nlocked;
     685                 :            :           }
     686                 :            :         }
     687                 :            : 
     688                 :            :         // Row 2
     689                 :            :         // If remote neither wants to refine nor derefine
     690 [ +  + ][ +  + ]:       4484 :         if (remote_needs_refining == 0 && remote_needs_derefining == false) {
     691                 :        126 :           local_needs_derefining = false;
     692         [ -  + ]:        126 :           if (local_needs_derefining != local_needs_derefining_orig)
     693                 :          0 :             ++ncorrcase[2];
     694                 :            :         }
     695                 :            : 
     696                 :            :         // Row 1: special case
     697                 :            :         // If remote wants to deref-ref (either of 8:4, 8:2, 4:2)
     698                 :            :         // and local does not want to refine (neither pure ref nor deref-ref)
     699 [ -  + ][ -  - ]:       4484 :         if (remote_needs_refining == 2 && local_needs_refining == 0) {
     700         [ -  - ]:          0 :           if (local_lock_case == unlocked) {
     701                 :          0 :             local_needs_refining = 1;
     702                 :          0 :             local_needs_derefining = false;
     703         [ -  - ]:          0 :             if (local_needs_refining != local_needs_refining_orig ||
     704         [ -  - ]:          0 :               local_needs_derefining != local_needs_derefining_orig)
     705                 :          0 :               ++ncorrcase[3];
     706                 :            :           }
     707                 :            :           else {
     708                 :            :             // cppcheck-suppress unreadVariable
     709                 :          0 :             ++nlocked;
     710                 :            :           }
     711                 :            :         }
     712                 :            : 
     713                 :            :         // Rows 4, 7, 8
     714                 :            : 
     715                 :            :         // if the remote sent us data that makes us change our local state,
     716                 :            :         // e.g., local{-,0} + remote{r,0} -> local{r,0}, i.e., I changed my
     717                 :            :         // state I need to tell the world about it
     718         [ +  - ]:       4484 :         if (local_lock_case != local_lock_case_orig ||
     719         [ +  - ]:       4484 :             local_needs_refining != local_needs_refining_orig ||
     720         [ -  + ]:       4484 :             local_needs_derefining != local_needs_derefining_orig)
     721                 :            :         {
     722         [ -  - ]:          0 :           auto l1 = tk::cref_find( m_lid, edge[0] );
     723         [ -  - ]:          0 :           auto l2 = tk::cref_find( m_lid, edge[1] );
     724 [ -  - ][ -  - ]:          0 :           Assert( l1 != l2, "Edge end-points local ids are the same" );
         [ -  - ][ -  - ]
     725                 :          0 :           auto r1 = m_rid[ l1 ];
     726                 :          0 :           auto r2 = m_rid[ l2 ];
     727 [ -  - ][ -  - ]:          0 :           Assert( r1 != r2, "Edge end-points refiner ids are the same" );
         [ -  - ][ -  - ]
     728                 :            :           //std::cout << thisIndex << ": " << r1 << ", " << r2 << std::endl;
     729                 :            :           //if (m_refiner.tet_store.edge_store.get(AMR::edge_t(r1,r2)).lock_case > local_lock_case) {
     730                 :            :           //  std::cout << thisIndex << ": edge " << r1 << "-" << r2 <<
     731                 :            :           //    "; prev=" << local_lock_case_orig <<
     732                 :            :           //    "; new=" << local_lock_case <<
     733                 :            :           //    "; amr-lib=" << m_refiner.tet_store.edge_store.get(AMR::edge_t(r1,r2)).lock_case <<
     734                 :            :           //    " | parcompatiter " << m_ncit << std::endl;
     735                 :            :           //}
     736         [ -  - ]:          0 :            extra[ {{ std::min(r1,r2), std::max(r1,r2) }} ] =
     737                 :          0 :              { local_needs_refining, local_needs_derefining, local_lock_case };
     738                 :          0 :         }
     739                 :            :         // or if the remote data is inconsistent with what I think, e.g.,
     740                 :            :         // local{r,0} + remote{-,0} -> local{r,0}, i.e., the remote does not
     741                 :            :         // yet agree, so another par-compat iteration will be pursued. but
     742                 :            :         // I do not have to locally run ref-compat.
     743         [ +  - ]:       4484 :         else if (local_lock_case != remote_lock_case ||
     744         [ +  - ]:       4484 :           local_needs_refining != remote_needs_refining ||
     745         [ -  + ]:       4484 :           local_needs_derefining != remote_needs_derefining)
     746                 :            :         {
     747                 :          0 :           ++neigh_extra;
     748                 :            :         }
     749                 :            :       }
     750                 :            :     }
     751                 :            :   }
     752                 :            : 
     753                 :         71 :   m_remoteEdgeData.clear();
     754                 :         71 :   m_extra = extra.size();
     755                 :            :   //std::cout << thisIndex << ": amr correction reqd for nedge: " << m_extra << std::endl;
     756                 :            :   //std::cout << thisIndex << ": amr correction reqd for neighbor edges: " << neigh_extra << std::endl;
     757                 :            :   //std::cout << thisIndex << ": edge counts by correction case: " << ncorrcase[0]
     758                 :            :   //  << ", " << ncorrcase[1] << ", " << ncorrcase[2] << ", " << ncorrcase[3] << std::endl;
     759                 :            :   //std::cout << thisIndex << ": locked edges that req corr: " << nlocked << std::endl;
     760                 :            : 
     761         [ -  + ]:         71 :   if (!extra.empty()) {
     762                 :            :     //std::cout << thisIndex << ": redoing markings" << std::endl;
     763                 :            :     // Do refinement compatibility (ref-compat) for edges that need correction
     764         [ -  - ]:          0 :     m_refiner.mark_error_refinement_corr( extra );
     765                 :          0 :     ++m_ncit;
     766                 :            :     // Update our extra-edge store based on refiner
     767         [ -  - ]:          0 :     updateEdgeData();
     768                 :          0 :     m_remoteEdges.clear();
     769                 :            :   }
     770         [ +  - ]:         71 :   else if (neigh_extra == 0) {
     771                 :         71 :     m_ncit = 0;
     772                 :            :   }
     773                 :            : 
     774                 :            :   // Aggregate number of extra edges that still need correction and some
     775                 :            :   // refinement/derefinement statistics
     776                 :         71 :   const auto& tet_store = m_refiner.tet_store;
     777                 :            :   std::vector< std::size_t >
     778                 :         71 :     m{ m_meshid,
     779                 :         71 :        m_extra,
     780                 :         71 :        tet_store.marked_refinements.size(),
     781                 :         71 :        tet_store.marked_derefinements.size(),
     782         [ +  - ]:         71 :        static_cast< std::underlying_type_t< RefMode > >( m_mode ) };
     783         [ +  - ]:         71 :   contribute( m, CkReduction::sum_ulong, m_cbr.get< tag::matched >() );
     784                 :         71 : }
     785                 :            : 
     786                 :            : void
     787                 :        142 : Refiner::updateEdgeData()
     788                 :            : // *****************************************************************************
     789                 :            : // Query AMR lib and update our local store of edge data
     790                 :            : // *****************************************************************************
     791                 :            : {
     792                 :        142 :   m_localEdgeData.clear();
     793                 :        142 :   m_intermediates.clear();
     794                 :            : 
     795                 :            :   // This currently takes ALL edges from the AMR lib, i.e., on the whole
     796                 :            :   // domain. We should eventually only collect edges here that are shared with
     797                 :            :   // other chares.
     798                 :        142 :   const auto& ref_edges = m_refiner.tet_store.edge_store.edges;
     799                 :        142 :   const auto& refinpoel = m_refiner.tet_store.get_active_inpoel();
     800                 :            : 
     801         [ +  + ]:     145750 :   for (std::size_t e=0; e<refinpoel.size()/4; ++e) {
     802                 :     145608 :     auto A = refinpoel[e*4+0];
     803                 :     145608 :     auto B = refinpoel[e*4+1];
     804                 :     145608 :     auto C = refinpoel[e*4+2];
     805                 :     145608 :     auto D = refinpoel[e*4+3];
     806                 :            :     std::array<Edge,6> edges{{ {{A,B}}, {{B,C}}, {{A,C}},
     807                 :     145608 :                                {{A,D}}, {{B,D}}, {{C,D}} }};
     808         [ +  + ]:    1019256 :     for (const auto& ed : edges) {
     809                 :     873648 :       auto ae = AMR::edge_t{{{ std::min(ed[0],ed[1]), std::max(ed[0],ed[1]) }}};
     810         [ +  - ]:     873648 :       auto r = tk::cref_find( ref_edges, ae );
     811         [ +  - ]:     873648 :       const auto ged = Edge{{ m_gid[ tk::cref_find( m_lref, ed[0] ) ],
     812         [ +  - ]:     873648 :                               m_gid[ tk::cref_find( m_lref, ed[1] ) ] }};
     813         [ +  - ]:     873648 :       m_localEdgeData[ ged ] =
     814                 :    1747296 :         { r.needs_refining, r.needs_derefining, r.lock_case };
     815                 :            :     }
     816                 :            :   }
     817                 :            : 
     818                 :            :   // Build intermediates to send. This currently takes ALL intermediates from
     819                 :            :   // the AMR lib, i.e., on the whole domain. We should eventually only collect
     820                 :            :   // edges here that are shared with other chares.
     821         [ +  + ]:        746 :   for (const auto& r : m_refiner.tet_store.intermediate_list) {
     822 [ +  - ][ +  - ]:        604 :     m_intermediates.insert( m_gid[ tk::cref_find( m_lref, r ) ] );
     823                 :            :   }
     824                 :        142 : }
     825                 :            : 
     826                 :            : void
     827                 :         58 : Refiner::updateBndEdgeData()
     828                 :            : // *****************************************************************************
     829                 :            : // Query AMR lib and update our local store of boundary edge data
     830                 :            : // *****************************************************************************
     831                 :            : {
     832                 :            :   // This currently takes ALL edges from the AMR lib, i.e., on the whole
     833                 :            :   // domain. We should eventually only collect edges here that are shared with
     834                 :            :   // other chares.
     835                 :         58 :   const auto& ref_edges = m_refiner.tet_store.edge_store.edges;
     836                 :         58 :   const auto& refinpoel = m_refiner.tet_store.get_active_inpoel();
     837                 :            : 
     838         [ +  + ]:      48163 :   for (std::size_t e=0; e<refinpoel.size()/4; ++e) {
     839                 :      48105 :     auto A = refinpoel[e*4+0];
     840                 :      48105 :     auto B = refinpoel[e*4+1];
     841                 :      48105 :     auto C = refinpoel[e*4+2];
     842                 :      48105 :     auto D = refinpoel[e*4+3];
     843                 :            :     std::array<Edge,6> edges{{ {{A,B}}, {{B,C}}, {{A,C}},
     844                 :      48105 :                                {{A,D}}, {{B,D}}, {{C,D}} }};
     845         [ +  + ]:     336735 :     for (const auto& ed : edges) {
     846                 :     288630 :       auto ae = AMR::edge_t{{{ std::min(ed[0],ed[1]), std::max(ed[0],ed[1]) }}};
     847         [ +  - ]:     288630 :       auto r = tk::cref_find( ref_edges, ae );
     848         [ +  - ]:     288630 :       const auto ged = Edge{{ m_gid[ tk::cref_find( m_lref, ed[0] ) ],
     849         [ +  - ]:     288630 :                               m_gid[ tk::cref_find( m_lref, ed[1] ) ] }};
     850                 :            :       // only update edges that are on chare boundary OR unlocked
     851 [ +  - ][ +  - ]:     577260 :       if (m_localEdgeData.find(ged) == m_localEdgeData.end() ||
                 [ +  - ]
     852 [ +  - ][ +  - ]:     288630 :         std::get<2>(m_localEdgeData[ged]) == AMR::Edge_Lock_Case::unlocked) {
     853         [ +  - ]:     288630 :         m_localEdgeData[ ged ] = { r.needs_refining, r.needs_derefining,
     854                 :     577260 :           r.lock_case };
     855                 :            :       }
     856                 :            :     }
     857                 :            :   }
     858                 :         58 : }
     859                 :            : 
     860                 :            : std::tuple< std::vector< std::string >,
     861                 :            :             std::vector< std::vector< tk::real > >,
     862                 :            :             std::vector< std::string >,
     863                 :            :             std::vector< std::vector< tk::real > > >
     864                 :         98 : Refiner::refinementFields() const
     865                 :            : // *****************************************************************************
     866                 :            : //  Collect mesh output fields from refiner lib
     867                 :            : //! \return Names and fields of mesh refinement data in mesh cells and nodes
     868                 :            : // *****************************************************************************
     869                 :            : {
     870                 :            :   // Find number of nodes in current mesh
     871         [ +  - ]:         98 :   auto npoin = tk::npoin_in_graph( m_inpoel );
     872                 :            :   // Generate edges surrounding points in current mesh
     873         [ +  - ]:         98 :   auto esup = tk::genEsup( m_inpoel, 4 );
     874                 :            : 
     875                 :            :   // Update solution on current mesh
     876         [ +  - ]:         98 :   const auto& u = solution( npoin, esup );
     877 [ -  + ][ -  - ]:         98 :   Assert( u.nunk() == npoin, "Solution uninitialized or wrong size" );
         [ -  - ][ -  - ]
     878                 :            : 
     879                 :            :   // Compute error in edges on current mesh
     880         [ +  - ]:         98 :   auto edgeError = errorsInEdges( npoin, esup, u );
     881                 :            : 
     882                 :            :   // Transfer error from edges to cells for field output
     883         [ +  - ]:         98 :   std::vector< tk::real > error( m_inpoel.size()/4, 0.0 );
     884         [ +  + ]:     133213 :   for (std::size_t e=0; e<m_inpoel.size()/4; ++e) {
     885                 :     133115 :     auto A = m_inpoel[e*4+0];
     886                 :     133115 :     auto B = m_inpoel[e*4+1];
     887                 :     133115 :     auto C = m_inpoel[e*4+2];
     888                 :     133115 :     auto D = m_inpoel[e*4+3];
     889                 :            :     std::array<Edge,6> edges{{ {{A,B}}, {{B,C}}, {{A,C}},
     890                 :     133115 :                                {{A,D}}, {{B,D}}, {{C,D}} }};
     891                 :            :     // sum error from edges to elements
     892 [ +  - ][ +  + ]:     931805 :     for (const auto& ed : edges) error[e] += tk::cref_find( edgeError, ed );
     893                 :     133115 :     error[e] /= 6.0;    // assign edge-average error to element
     894                 :            :   }
     895                 :            : 
     896                 :            :   // Prepare element fields with mesh refinement data
     897                 :            :   std::vector< std::string >
     898 [ +  - ][ +  + ]:        392 :     elemfieldnames{ "refinement level", "cell type", "error" };
                 [ -  - ]
     899                 :         98 :   auto& tet_store = m_refiner.tet_store;
     900                 :            :   std::vector< std::vector< tk::real > > elemfields{
     901                 :            :     tet_store.get_refinement_level_list(),
     902                 :            :     tet_store.get_cell_type_list(),
     903 [ +  - ][ +  + ]:        392 :     error };
                 [ -  - ]
     904                 :            : 
     905                 :            :   using tuple_t = std::tuple< std::vector< std::string >,
     906                 :            :                               std::vector< std::vector< tk::real > >,
     907                 :            :                               std::vector< std::string >,
     908                 :            :                               std::vector< std::vector< tk::real > > >;
     909         [ +  - ]:        196 :   return tuple_t{ elemfieldnames, elemfields, {}, {} };
     910 [ +  - ][ +  - ]:        294 : }
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
     911                 :            : 
     912                 :            : void
     913                 :         98 : Refiner::writeMesh( const std::string& basefilename,
     914                 :            :                     uint64_t itr,
     915                 :            :                     tk::real t,
     916                 :            :                     CkCallback c ) const
     917                 :            : // *****************************************************************************
     918                 :            : //  Output mesh to file(s)
     919                 :            : //! \param[in] basefilename File name to append to
     920                 :            : //! \param[in] itr Iteration count since a new mesh
     921                 :            : //! \param[in] t "Physical time" to write to file. "Time" here is used to
     922                 :            : //!   designate a new time step at which the mesh is saved.
     923                 :            : //! \param[in] c Function to continue with after the write
     924                 :            : // *****************************************************************************
     925                 :            : {
     926         [ +  - ]:         98 :   auto r = refinementFields();
     927                 :         98 :   auto& elemfieldnames = std::get< 0 >( r );
     928                 :         98 :   auto& elemfields = std::get< 1 >( r );
     929                 :         98 :   auto& nodefieldnames = std::get< 2 >( r );
     930                 :         98 :   auto& nodefields = std::get< 3 >( r );
     931                 :            : 
     932                 :            :   // Prepare solution field names: depvar + component id for all eqs
     933                 :         98 :   auto ncomp = g_cfg.get< tag::problem_ncomp >();
     934 [ +  - ][ +  - ]:         98 :   std::vector< std::string > solfieldnames( ncomp, "u" );
     935 [ -  + ][ -  - ]:         98 :   Assert( solfieldnames.size() == ncomp, "Size mismatch" );
         [ -  - ][ -  - ]
     936                 :            : 
     937                 :         98 :   auto t0 = g_cfg.get< tag::t0 >();
     938                 :            : 
     939                 :            :   // Augment element field names with solution variable names + field ids
     940                 :            :   //nodefieldnames.insert( end(nodefieldnames),
     941                 :            :   //                       begin(solfieldnames), end(solfieldnames) );
     942 [ +  - ][ +  - ]:         98 :   nodefieldnames.push_back( "c1" );
     943                 :            : 
     944                 :            :   // Evaluate initial conditions on current mesh at t0
     945         [ +  - ]:         98 :   tk::Fields u( m_coord[0].size(), ncomp );
     946         [ +  - ]:         98 :   problems::initialize( m_coord, u, t0, /*meshid=*/0 );
     947                 :            : 
     948                 :            :   // Extract all scalar components from solution for output to file
     949                 :            :   //for (std::size_t i=0; i<ncomp; ++i)
     950 [ +  - ][ +  - ]:         98 :   nodefields.push_back( u.extract( 5 ) );
     951                 :            : 
     952                 :            :   // Output mesh
     953                 :            :   m_meshwriter[ CkNodeFirst( CkMyNode() ) ].
     954         [ +  - ]:        196 :     write( m_meshid, /*meshoutput = */ true, /*fieldoutput = */ true, itr, 1, t,
     955         [ +  - ]:         98 :            thisIndex, basefilename, m_inpoel, m_coord, m_bface,
     956 [ +  - ][ +  - ]:        196 :            tk::remap(m_bnode,m_lid), tk::remap(m_triinpoel,m_lid),
     957                 :            :            elemfieldnames, nodefieldnames, {}, {}, elemfields, nodefields, {},
     958                 :            :            {}, {}, c );
     959                 :         98 : }
     960                 :            : 
     961                 :            : void
     962                 :         71 : Refiner::perform()
     963                 :            : // *****************************************************************************
     964                 :            : // Perform mesh refinement and decide how to continue
     965                 :            : //! \details First the mesh refiner object is called to perform a single step
     966                 :            : //!   of mesh refinement. Then, if this function is called during a step
     967                 :            : //!   (potentially multiple levels of) initial AMR, it evaluates whether to do
     968                 :            : //!   another one. If it is called during time stepping, this concludes the
     969                 :            : //!   single mesh refinement step and the new mesh is sent to the PDE worker
     970                 :            : //!   (Discretization).
     971                 :            : // *****************************************************************************
     972                 :            : {
     973                 :            :   // Save old tets and their ids before performing refinement. Outref is always
     974                 :            :   // followed by outderef, so to the outside world, the mesh is uchanged, thus
     975                 :            :   // no update.
     976                 :         71 :   m_oldTets.clear();
     977         [ +  + ]:      82257 :   for (const auto& [ id, tet ] : m_refiner.tet_store.tets) {
     978         [ +  - ]:      82186 :     m_oldTets.insert( tet );
     979                 :            :   }
     980                 :         71 :   m_oldntets = m_oldTets.size();
     981                 :            : 
     982         [ +  - ]:         71 :   if (m_mode == RefMode::T0REF) {
     983                 :            : 
     984                 :            :     // Refine mesh based on next initial refinement type
     985         [ +  - ]:         71 :     if (!m_initref.empty()) {
     986         [ +  - ]:         71 :       auto r = m_initref.back();    // consume (reversed) list from its back
     987         [ +  + ]:         71 :       if (r == "uniform_deref")
     988         [ +  - ]:         24 :         m_refiner.perform_derefinement();
     989                 :            :       else
     990         [ +  - ]:         47 :         m_refiner.perform_refinement();
     991                 :         71 :     }
     992                 :            : 
     993                 :            :   } else {
     994                 :            : 
     995                 :            :     // TODO: does not work yet, fix as above
     996                 :          0 :     m_refiner.perform_refinement();
     997                 :          0 :     m_refiner.perform_derefinement();
     998                 :            :   }
     999                 :            : 
    1000                 :            :   // Remove temporary edge-locks resulting from the parallel compatibility
    1001                 :         71 :   m_refiner.remove_edge_locks(1);
    1002                 :         71 :   m_refiner.remove_edge_temp_locks();
    1003                 :            : 
    1004                 :            :   //auto& tet_store = m_refiner.tet_store;
    1005                 :            :   //std::cout << "before ref: " << tet_store.marked_refinements.size() << ", " << tet_store.marked_derefinements.size() << ", " << tet_store.size() << ", " << tet_store.get_active_inpoel().size() << '\n';
    1006                 :            :   //std::cout << "after ref: " << tet_store.marked_refinements.size() << ", " << tet_store.marked_derefinements.size() << ", " << tet_store.size() << ", " << tet_store.get_active_inpoel().size() << '\n';
    1007                 :            :   //std::cout << "after deref: " << tet_store.marked_refinements.size() << ", " << tet_store.marked_derefinements.size() << ", " << tet_store.size() << ", " << tet_store.get_active_inpoel().size() << '\n';
    1008                 :            : 
    1009                 :            :   // Update volume and boundary mesh
    1010                 :         71 :   updateMesh();
    1011                 :            : 
    1012                 :            :   // Save mesh at every initial refinement step (mainly for debugging). Will
    1013                 :            :   // replace with just a 'next()' in production.
    1014         [ +  - ]:         71 :   if (m_mode == RefMode::T0REF) {
    1015                 :            : 
    1016                 :         71 :     auto l = m_ninitref - m_initref.size() + 1;  // num initref steps completed
    1017                 :         71 :     auto t0 = g_cfg.get< tag::t0 >();
    1018                 :            :     // Generate times equally subdividing t0-1...t0 to ninitref steps
    1019                 :         71 :     auto t =
    1020                 :         71 :       t0 - 1.0 + static_cast<tk::real>(l)/static_cast<tk::real>(m_ninitref);
    1021                 :         71 :     auto itr = l;
    1022                 :            :     // Output mesh after refinement step
    1023 [ +  - ][ +  - ]:         71 :     writeMesh( "t0ref", itr, t,
    1024 [ +  - ][ +  - ]:        142 :                CkCallback( CkIndex_Refiner::next(), thisProxy[thisIndex] ) );
                 [ +  - ]
    1025                 :            : 
    1026                 :            :   } else {
    1027                 :            : 
    1028                 :          0 :     next();
    1029                 :            : 
    1030                 :            :   }
    1031                 :         71 : }
    1032                 :            : 
    1033                 :            : void
    1034                 :         71 : Refiner::next()
    1035                 :            : // *****************************************************************************
    1036                 :            : // Continue after finishing a refinement step
    1037                 :            : // *****************************************************************************
    1038                 :            : {
    1039         [ +  - ]:         71 :   if (m_mode == RefMode::T0REF) {
    1040                 :            : 
    1041                 :            :     // Remove initial mesh refinement step from list
    1042         [ +  - ]:         71 :     if (!m_initref.empty()) m_initref.pop_back();
    1043                 :            :     // Continue to next initial AMR step or finish
    1044         [ +  + ]:         71 :     if (!m_initref.empty()) t0ref(); else endt0ref();
    1045                 :            : 
    1046         [ -  - ]:          0 :   } else if (m_mode == RefMode::DTREF) {
    1047                 :            : 
    1048                 :            :     // Send new mesh, solution, and communication data back to PDE worker
    1049                 :          0 :     const auto& solver = g_cfg.get< tag::solver >();
    1050         [ -  - ]:          0 :     if (solver == "riecg") {
    1051 [ -  - ][ -  - ]:          0 :       m_riecg[ thisIndex ].ckLocal()->resizePostAMR( m_ginpoel,
    1052                 :          0 :         m_el, m_coord, m_addedNodes, m_addedTets, m_removedNodes,
    1053         [ -  - ]:          0 :         m_nodeCommMap, m_bface, m_bnode, m_triinpoel );
    1054                 :            :     }
    1055         [ -  - ]:          0 :     else if (solver == "laxcg") {
    1056 [ -  - ][ -  - ]:          0 :       m_laxcg[ thisIndex ].ckLocal()->resizePostAMR( m_ginpoel,
    1057                 :          0 :         m_el, m_coord, m_addedNodes, m_addedTets, m_removedNodes,
    1058         [ -  - ]:          0 :         m_nodeCommMap, m_bface, m_bnode, m_triinpoel );
    1059                 :            :     }
    1060         [ -  - ]:          0 :     else if (solver == "zalcg") {
    1061 [ -  - ][ -  - ]:          0 :       m_zalcg[ thisIndex ].ckLocal()->resizePostAMR( m_ginpoel,
    1062                 :          0 :         m_el, m_coord, m_addedNodes, m_addedTets, m_removedNodes,
    1063         [ -  - ]:          0 :         m_nodeCommMap, m_bface, m_bnode, m_triinpoel );
    1064                 :            :     }
    1065         [ -  - ]:          0 :     else if (solver == "kozcg") {
    1066 [ -  - ][ -  - ]:          0 :       m_kozcg[ thisIndex ].ckLocal()->resizePostAMR( m_ginpoel,
    1067                 :          0 :         m_el, m_coord, m_addedNodes, m_addedTets, m_removedNodes,
    1068         [ -  - ]:          0 :         m_nodeCommMap, m_bface, m_bnode, m_triinpoel );
    1069                 :            :     }
    1070         [ -  - ]:          0 :     else if (solver == "chocg") {
    1071 [ -  - ][ -  - ]:          0 :       m_chocg[ thisIndex ].ckLocal()->resizePostAMR( m_ginpoel,
    1072                 :          0 :         m_el, m_coord, m_addedNodes, m_addedTets, m_removedNodes,
    1073         [ -  - ]:          0 :         m_nodeCommMap, m_bface, m_bnode, m_triinpoel );
    1074                 :            :     }
    1075         [ -  - ]:          0 :     else if (solver == "lohcg") {
    1076 [ -  - ][ -  - ]:          0 :       m_lohcg[ thisIndex ].ckLocal()->resizePostAMR( m_ginpoel,
    1077                 :          0 :         m_el, m_coord, m_addedNodes, m_addedTets, m_removedNodes,
    1078         [ -  - ]:          0 :         m_nodeCommMap, m_bface, m_bnode, m_triinpoel );
    1079                 :            :     }
    1080                 :            :     else {
    1081 [ -  - ][ -  - ]:          0 :       Throw( "Unknown solver: " + solver );
                 [ -  - ]
    1082                 :            :     }
    1083                 :            : 
    1084 [ -  - ][ -  - ]:          0 :   } else Throw( "RefMode not implemented" );
                 [ -  - ]
    1085                 :         71 : }
    1086                 :            : 
    1087                 :            : void
    1088                 :       2576 : Refiner::endt0ref()
    1089                 :            : // *****************************************************************************
    1090                 :            : // Finish initial mesh refinement
    1091                 :            : //! \details This function is called as after initial mesh refinement has
    1092                 :            : //!   finished. If initial mesh reifnement was not configured by the user, this
    1093                 :            : //!   is the point where we continue after the constructor, by computing the
    1094                 :            : //!   total number of elements across the whole problem.
    1095                 :            : // *****************************************************************************
    1096                 :            : {
    1097                 :            :   // create sorter Charm++ chare array elements using dynamic insertion
    1098         [ +  - ]:       2576 :   m_sorter[ thisIndex ].insert( m_meshid, m_host, m_meshwriter, m_cbs,
    1099                 :       2576 :     m_disc, m_riecg, m_laxcg, m_zalcg, m_kozcg, m_chocg, m_lohcg, m_cgpre,
    1100 [ +  - ][ +  - ]:       2576 :     m_cgmom, CkCallback( CkIndex_Refiner::reorder(), thisProxy[thisIndex] ),
                 [ +  - ]
    1101         [ +  - ]:       2576 :     m_ginpoel, m_coordmap, m_el, m_bface, m_triinpoel, m_bnode, m_nchare );
    1102                 :            : 
    1103                 :            :   // Compute final number of cells across whole problem
    1104                 :            :   std::vector< std::size_t >
    1105         [ +  - ]:       2576 :     meshdata{ m_meshid, m_ginpoel.size()/4, m_coord[0].size() };
    1106         [ +  - ]:       2576 :   contribute( meshdata, CkReduction::sum_ulong, m_cbr.get< tag::refined >() );
    1107                 :            : 
    1108                 :            :   // Free up memory if no dtref
    1109         [ -  + ]:       2576 :   const auto& ht = m_multi ? g_cfg.get< tag::href_ >()[ m_meshid ]
    1110                 :       2576 :                            : g_cfg.get< tag::href >();
    1111         [ +  - ]:       2576 :   if (!ht.get< tag::dt >()) {
    1112                 :       2576 :     tk::destroy( m_ginpoel );
    1113                 :       2576 :     tk::destroy( m_el );
    1114                 :       2576 :     tk::destroy( m_coordmap );
    1115                 :       2576 :     tk::destroy( m_coord );
    1116                 :       2576 :     tk::destroy( m_bface );
    1117                 :       2576 :     tk::destroy( m_bnode );
    1118                 :       2576 :     tk::destroy( m_triinpoel );
    1119                 :       2576 :     tk::destroy( m_initref );
    1120                 :       2576 :     tk::destroy( m_ch );
    1121                 :       2576 :     tk::destroy( m_edgech );
    1122                 :       2576 :     tk::destroy( m_chedge );
    1123                 :       2576 :     tk::destroy( m_localEdgeData );
    1124                 :       2576 :     tk::destroy( m_remoteEdgeData );
    1125                 :       2576 :     tk::destroy( m_remoteEdges );
    1126                 :       2576 :     tk::destroy( m_intermediates );
    1127                 :       2576 :     tk::destroy( m_nodeCommMap );
    1128                 :       2576 :     tk::destroy( m_oldTets );
    1129                 :       2576 :     tk::destroy( m_addedNodes );
    1130                 :       2576 :     tk::destroy( m_addedTets );
    1131                 :       2576 :     tk::destroy( m_coarseBndFaces );
    1132                 :       2576 :     tk::destroy( m_coarseBndNodes );
    1133                 :       2576 :     tk::destroy( m_rid );
    1134                 :            :     //tk::destroy( m_oldrid );
    1135                 :       2576 :     tk::destroy( m_lref );
    1136                 :            :   }
    1137                 :       2576 : }
    1138                 :            : 
    1139                 :            : void
    1140                 :         31 : Refiner::uniformRefine()
    1141                 :            : // *****************************************************************************
    1142                 :            : // Do uniform mesh refinement
    1143                 :            : // *****************************************************************************
    1144                 :            : {
    1145                 :            :   // Do uniform refinement
    1146                 :         31 :   m_refiner.mark_uniform_refinement();
    1147                 :            : 
    1148                 :            :   // Update our extra-edge store based on refiner
    1149                 :         31 :   updateEdgeData();
    1150                 :            : 
    1151                 :            :   // Set number of extra edges to be zero, skipping correction (if this is the
    1152                 :            :   // only step in this refinement step)
    1153                 :         31 :   m_extra = 0;
    1154                 :         31 : }
    1155                 :            : 
    1156                 :            : void
    1157                 :         24 : Refiner::uniformDeRefine()
    1158                 :            : // *****************************************************************************
    1159                 :            : // Do uniform mesh derefinement
    1160                 :            : // *****************************************************************************
    1161                 :            : {
    1162                 :            :   // Do uniform derefinement
    1163                 :         24 :   m_refiner.mark_uniform_derefinement();
    1164                 :            : 
    1165                 :            :   // Update our extra-edge store based on refiner
    1166                 :         24 :   updateEdgeData();
    1167                 :            : 
    1168                 :            :   // Set number of extra edges to be zero, skipping correction (if this is the
    1169                 :            :   // only step in this refinement step)
    1170                 :         24 :   m_extra = 0;
    1171                 :         24 : }
    1172                 :            : 
    1173                 :            : Refiner::EdgeError
    1174                 :        114 : Refiner::errorsInEdges(
    1175                 :            :   std::size_t npoin,
    1176                 :            :   const std::pair< std::vector<std::size_t>, std::vector<std::size_t> >& esup,
    1177                 :            :   const tk::Fields& u ) const
    1178                 :            : // *****************************************************************************
    1179                 :            : //  Compute errors in edges
    1180                 :            : //! \param[in] npoin Number nodes in current mesh (partition)
    1181                 :            : //! \param[in] esup Elements surrounding points linked vectors
    1182                 :            : //! \param[in] u Solution evaluated at mesh nodes for all scalar components
    1183                 :            : //! \return A map associating errors (real values between 0.0 and 1.0 incusive)
    1184                 :            : //!   to edges (2 local node IDs)
    1185                 :            : // *****************************************************************************
    1186                 :            : {
    1187         [ -  + ]:        114 :   const auto& ht = m_multi ? g_cfg.get< tag::href_ >()[ m_meshid ]
    1188                 :        114 :                            : g_cfg.get< tag::href >();
    1189         [ +  - ]:        114 :   auto errtype = ht.get< tag::error >();
    1190                 :        114 :   const auto& refvar = ht.get< tag::refvar >();
    1191         [ +  - ]:        114 :   auto psup = tk::genPsup( m_inpoel, 4, esup );
    1192                 :            : 
    1193                 :            :   // Compute errors in ICs and define refinement criteria for edges
    1194                 :            :   AMR::Error error;
    1195                 :        114 :   EdgeError edgeError;
    1196                 :            : 
    1197         [ +  + ]:      35211 :   for (std::size_t p=0; p<npoin; ++p) { // for all mesh nodes on this chare
    1198         [ +  + ]:     422029 :     for (auto q : tk::Around(psup,p)) { // for all nodes surrounding p
    1199                 :     386932 :       tk::real cmax = 0.0;
    1200         [ +  - ]:     386932 :       AMR::edge_t e(p,q);
    1201         [ +  + ]:     549892 :       for (auto i : refvar) {          // for all refinement variables
    1202         [ +  - ]:     162960 :         auto c = error.scalar( u, e, i-1, m_coord, m_inpoel, esup, errtype );
    1203         [ +  + ]:     162960 :         if (c > cmax) cmax = c;        // find max error at edge
    1204                 :            :       }
    1205         [ +  - ]:     386932 :       edgeError[ {{p,q}} ] = cmax;       // associate error to edge
    1206                 :            :     }
    1207                 :            :   }
    1208                 :            : 
    1209                 :        228 :   return edgeError;
    1210                 :        114 : }
    1211                 :            : 
    1212                 :            : tk::Fields
    1213                 :        114 : Refiner::solution( std::size_t npoin,
    1214                 :            :                    const std::pair< std::vector< std::size_t >,
    1215                 :            :                                     std::vector< std::size_t > >& esup ) const
    1216                 :            : // *****************************************************************************
    1217                 :            : //  Update (or evaluate) solution on current mesh
    1218                 :            : //! \param[in] npoin Number nodes in current mesh (partition)
    1219                 :            : //! \param[in] esup Elements surrounding points linked vectors
    1220                 :            : //! \return Solution updated/evaluated for all scalar components
    1221                 :            : // *****************************************************************************
    1222                 :            : {
    1223                 :            :   // Get solution whose error to evaluate
    1224                 :        114 :   tk::Fields u;
    1225                 :            : 
    1226         [ +  - ]:        114 :   if (m_mode == RefMode::T0REF) {
    1227                 :            : 
    1228                 :            :     // Evaluate initial conditions at mesh nodes
    1229         [ +  - ]:        114 :     u = nodeinit( npoin, esup );
    1230                 :            : 
    1231         [ -  - ]:          0 :   } else if (m_mode == RefMode::DTREF) {
    1232                 :            : 
    1233                 :            :     // Query current solution
    1234                 :          0 :     const auto& solver = g_cfg.get< tag::solver >();
    1235         [ -  - ]:          0 :     if (solver == "riecg") {
    1236 [ -  - ][ -  - ]:          0 :       u = m_riecg[ thisIndex ].ckLocal()->solution();
                 [ -  - ]
    1237                 :            :     }
    1238         [ -  - ]:          0 :     else if (solver == "laxcg") {
    1239 [ -  - ][ -  - ]:          0 :       u = m_laxcg[ thisIndex ].ckLocal()->solution();
                 [ -  - ]
    1240                 :            :     }
    1241         [ -  - ]:          0 :     else if (solver == "zalcg") {
    1242 [ -  - ][ -  - ]:          0 :       u = m_zalcg[ thisIndex ].ckLocal()->solution();
                 [ -  - ]
    1243                 :            :     }
    1244         [ -  - ]:          0 :     else if (solver == "kozcg") {
    1245 [ -  - ][ -  - ]:          0 :       u = m_kozcg[ thisIndex ].ckLocal()->solution();
                 [ -  - ]
    1246                 :            :     }
    1247         [ -  - ]:          0 :     else if (solver == "chocg") {
    1248 [ -  - ][ -  - ]:          0 :       u = m_chocg[ thisIndex ].ckLocal()->solution();
                 [ -  - ]
    1249                 :            :     }
    1250         [ -  - ]:          0 :     else if (solver == "lohcg") {
    1251 [ -  - ][ -  - ]:          0 :       u = m_lohcg[ thisIndex ].ckLocal()->solution();
                 [ -  - ]
    1252                 :            :     }
    1253                 :            :     else {
    1254 [ -  - ][ -  - ]:          0 :       Throw( "Unknown solver: " + solver );
                 [ -  - ]
    1255                 :            :     }
    1256                 :            :  
    1257 [ -  - ][ -  - ]:          0 :   } else Throw( "RefMode not implemented" );
                 [ -  - ]
    1258                 :            : 
    1259                 :        114 :   return u;
    1260                 :          0 : }
    1261                 :            : 
    1262                 :            : void
    1263                 :         16 : Refiner::errorRefine()
    1264                 :            : // *****************************************************************************
    1265                 :            : // Do error-based mesh refinement and derefinement
    1266                 :            : // *****************************************************************************
    1267                 :            : {
    1268                 :            :   // Find number of nodes in old mesh
    1269         [ +  - ]:         16 :   auto npoin = tk::npoin_in_graph( m_inpoel );
    1270                 :            :   // Generate edges surrounding points in old mesh
    1271         [ +  - ]:         16 :   auto esup = tk::genEsup( m_inpoel, 4 );
    1272                 :            : 
    1273                 :            :   // Update solution on current mesh
    1274         [ +  - ]:         16 :   const auto& u = solution( npoin, esup );
    1275 [ -  + ][ -  - ]:         16 :   Assert( u.nunk() == npoin, "Solution uninitialized or wrong size" );
         [ -  - ][ -  - ]
    1276                 :            : 
    1277                 :            :   using AMR::edge_t;
    1278                 :            :   using AMR::edge_tag;
    1279                 :            : 
    1280                 :            :   // Compute error in edges. Tag edge for refinement if error exceeds
    1281                 :            :   // refinement tolerance, tag edge for derefinement if error is below
    1282                 :            :   // derefinement tolerance.
    1283                 :         16 :   auto tolref = 0.2;//g_cfg.get< tag::amr, tag::tolref >();
    1284                 :         16 :   auto tolderef = 0.05;//g_cfg.get< tag::amr, tag::tolderef >();
    1285                 :         16 :   std::vector< std::pair< edge_t, edge_tag > > tagged_edges;
    1286 [ +  - ][ +  + ]:       5551 :   for (const auto& e : errorsInEdges(npoin,esup,u)) {
    1287         [ +  + ]:       5535 :     if (e.second > tolref) {
    1288 [ +  - ][ +  - ]:       7224 :       tagged_edges.push_back( { edge_t( m_rid[e.first[0]], m_rid[e.first[1]] ),
    1289                 :       7224 :                                 edge_tag::REFINE } );
    1290         [ +  + ]:       1923 :     } else if (e.second < tolderef) {
    1291 [ +  - ][ +  - ]:       3464 :       tagged_edges.push_back( { edge_t( m_rid[e.first[0]], m_rid[e.first[1]] ),
    1292                 :       3464 :                                 edge_tag::DEREFINE } );
    1293                 :            :     }
    1294                 :         16 :   }
    1295                 :            : 
    1296                 :            :   // Do error-based refinement
    1297         [ +  - ]:         16 :   m_refiner.mark_error_refinement( tagged_edges );
    1298                 :            : 
    1299                 :            :   // Update our extra-edge store based on refiner
    1300         [ +  - ]:         16 :   updateEdgeData();
    1301                 :            : 
    1302                 :            :   // Set number of extra edges to a nonzero number, triggering correction
    1303                 :         16 :   m_extra = 1;
    1304                 :         16 : }
    1305                 :            : 
    1306                 :            : void
    1307                 :          0 : Refiner::edgelistRefine()
    1308                 :            : // *****************************************************************************
    1309                 :            : // Do mesh refinement based on user explicitly tagging edges
    1310                 :            : // *****************************************************************************
    1311                 :            : {
    1312                 :            :   // Get user-defined node-pairs (edges) to tag for refinement
    1313         [ -  - ]:          0 :   const auto& edgenodelist = std::vector<uint64_t>{0,1};//g_cfg.get< tag::amr, tag::edge >();
    1314                 :            : 
    1315         [ -  - ]:          0 :   if (!edgenodelist.empty()) {  // if user explicitly tagged edges
    1316                 :            :     // Find number of nodes in old mesh
    1317         [ -  - ]:          0 :     auto npoin = tk::npoin_in_graph( m_inpoel );
    1318                 :            :     // Generate edges surrounding points in old mesh
    1319         [ -  - ]:          0 :     auto esup = tk::genEsup( m_inpoel, 4 );
    1320         [ -  - ]:          0 :     auto psup = tk::genPsup( m_inpoel, 4, esup );
    1321                 :            : 
    1322                 :          0 :     EdgeSet useredges;
    1323         [ -  - ]:          0 :     for (std::size_t i=0; i<edgenodelist.size()/2; ++i)
    1324         [ -  - ]:          0 :       useredges.insert( {{ {edgenodelist[i*2+0], edgenodelist[i*2+1]} }} );
    1325                 :            : 
    1326                 :            :     using AMR::edge_t;
    1327                 :            :     using AMR::edge_tag;
    1328                 :            : 
    1329                 :            :     // Tag edges the user configured
    1330                 :          0 :     std::vector< std::pair< edge_t, edge_tag > > tagged_edges;
    1331         [ -  - ]:          0 :     for (std::size_t p=0; p<npoin; ++p)        // for all mesh nodes on this chare
    1332         [ -  - ]:          0 :       for (auto q : tk::Around(psup,p)) {      // for all nodes surrounding p
    1333                 :          0 :         Edge e{{ m_gid[p], m_gid[q] }};
    1334         [ -  - ]:          0 :         auto f = useredges.find(e);
    1335         [ -  - ]:          0 :         if (f != end(useredges)) { // tag edge if on user's list
    1336 [ -  - ][ -  - ]:          0 :           tagged_edges.push_back( { edge_t( m_rid[p], m_rid[q] ),
    1337                 :          0 :                                     edge_tag::REFINE } );
    1338         [ -  - ]:          0 :           useredges.erase( f );
    1339                 :            :         }
    1340                 :            :       }
    1341                 :            : 
    1342                 :            :     // Do error-based refinement
    1343         [ -  - ]:          0 :     m_refiner.mark_error_refinement( tagged_edges );
    1344                 :            : 
    1345                 :            :     // Update our extra-edge store based on refiner
    1346         [ -  - ]:          0 :     updateEdgeData();
    1347                 :            : 
    1348                 :            :     // Set number of extra edges to a nonzero number, triggering correction
    1349                 :          0 :     m_extra = 1;
    1350                 :          0 :   }
    1351                 :          0 : }
    1352                 :            : 
    1353                 :            : void
    1354                 :          0 : Refiner::coordRefine()
    1355                 :            : // *****************************************************************************
    1356                 :            : // Do mesh refinement based on tagging edges based on end-point coordinates
    1357                 :            : // *****************************************************************************
    1358                 :            : {
    1359                 :            :   // Get user-defined half-world coordinates
    1360                 :          0 :   auto xminus = 0.0;
    1361                 :          0 :   auto xplus = 0.0;
    1362                 :          0 :   auto yminus = 0.0;
    1363                 :          0 :   auto yplus = 0.0;
    1364                 :          0 :   auto zminus = 0.0;
    1365                 :          0 :   auto zplus = 0.0;
    1366                 :            : 
    1367                 :            :   // The default is the largest representable double
    1368                 :          0 :   auto eps = 1.0e-12;
    1369                 :          0 :   auto xminus_default = 0.0;
    1370                 :          0 :   auto xplus_default = 0.0;
    1371                 :          0 :   auto yminus_default = 0.0;
    1372                 :          0 :   auto yplus_default = 0.0;
    1373                 :          0 :   auto zminus_default = 0.0;
    1374                 :          0 :   auto zplus_default = 0.0;
    1375                 :            : 
    1376                 :            :   // Decide if user has configured the half-world
    1377                 :          0 :   bool xm = std::abs(xminus - xminus_default) > eps ? true : false;
    1378                 :          0 :   bool xp = std::abs(xplus - xplus_default) > eps ? true : false;
    1379                 :          0 :   bool ym = std::abs(yminus - yminus_default) > eps ? true : false;
    1380                 :          0 :   bool yp = std::abs(yplus - yplus_default) > eps ? true : false;
    1381                 :          0 :   bool zm = std::abs(zminus - zminus_default) > eps ? true : false;
    1382                 :          0 :   bool zp = std::abs(zplus - zplus_default) > eps ? true : false;
    1383                 :            : 
    1384                 :            :   using AMR::edge_t;
    1385                 :            :   using AMR::edge_tag;
    1386                 :            : 
    1387 [ -  - ][ -  - ]:          0 :   if (xm || xp || ym || yp || zm || zp) {       // if any half-world configured
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
    1388                 :            :     // Find number of nodes in old mesh
    1389         [ -  - ]:          0 :     auto npoin = tk::npoin_in_graph( m_inpoel );
    1390                 :            :     // Generate edges surrounding points in old mesh
    1391         [ -  - ]:          0 :     auto esup = tk::genEsup( m_inpoel, 4 );
    1392         [ -  - ]:          0 :     auto psup = tk::genPsup( m_inpoel, 4, esup );
    1393                 :            :     // Get access to node coordinates
    1394                 :          0 :     const auto& x = m_coord[0];
    1395                 :          0 :     const auto& y = m_coord[1];
    1396                 :          0 :     const auto& z = m_coord[2];
    1397                 :            :     // Compute edges to be tagged for refinement
    1398                 :          0 :     std::vector< std::pair< edge_t, edge_tag > > tagged_edges;
    1399         [ -  - ]:          0 :     for (std::size_t p=0; p<npoin; ++p)    // for all mesh nodes on this chare
    1400         [ -  - ]:          0 :       for (auto q : tk::Around(psup,p)) {  // for all nodes surrounding p
    1401                 :          0 :         Edge e{{p,q}};
    1402                 :            : 
    1403                 :          0 :         bool t = true;
    1404 [ -  - ][ -  - ]:          0 :         if (xm) { if (x[p]>xminus && x[q]>xminus) t = false; }
         [ -  - ][ -  - ]
    1405 [ -  - ][ -  - ]:          0 :         if (xp) { if (x[p]<xplus && x[q]<xplus) t = false; }
         [ -  - ][ -  - ]
    1406 [ -  - ][ -  - ]:          0 :         if (ym) { if (y[p]>yminus && y[q]>yminus) t = false; }
         [ -  - ][ -  - ]
    1407 [ -  - ][ -  - ]:          0 :         if (yp) { if (y[p]<yplus && y[q]<yplus) t = false; }
         [ -  - ][ -  - ]
    1408 [ -  - ][ -  - ]:          0 :         if (zm) { if (z[p]>zminus && z[q]>zminus) t = false; }
         [ -  - ][ -  - ]
    1409 [ -  - ][ -  - ]:          0 :         if (zp) { if (z[p]<zplus && z[q]<zplus) t = false; }
         [ -  - ][ -  - ]
    1410                 :            : 
    1411         [ -  - ]:          0 :         if (t) {
    1412 [ -  - ][ -  - ]:          0 :           tagged_edges.push_back( { edge_t( m_rid[e[0]], m_rid[e[1]] ),
    1413                 :          0 :                                     edge_tag::REFINE } );
    1414                 :            :         }
    1415                 :            :       }
    1416                 :            : 
    1417                 :            :     // Do error-based refinement
    1418         [ -  - ]:          0 :     m_refiner.mark_error_refinement( tagged_edges );
    1419                 :            : 
    1420                 :            :     // Update our extra-edge store based on refiner
    1421         [ -  - ]:          0 :     updateEdgeData();
    1422                 :            : 
    1423                 :            :     // Set number of extra edges to a nonzero number, triggering correction
    1424                 :          0 :     m_extra = 1;
    1425                 :          0 :   }
    1426                 :          0 : }
    1427                 :            : 
    1428                 :            : tk::Fields
    1429                 :        114 : Refiner::nodeinit( std::size_t /*npoin*/,
    1430                 :            :                    const std::pair< std::vector< std::size_t >,
    1431                 :            :                                     std::vector< std::size_t > >& /*esup*/ ) const
    1432                 :            : // *****************************************************************************
    1433                 :            : // Evaluate initial conditions (IC) at mesh nodes
    1434                 :            : // //! \param[in] npoin Number points in mesh (on this chare)
    1435                 :            : // //! \param[in] esup Elements surrounding points as linked lists, see tk::genEsup
    1436                 :            : //! \return Initial conditions (evaluated at t0) at nodes
    1437                 :            : // *****************************************************************************
    1438                 :            : {
    1439                 :        114 :   auto t0 = g_cfg.get< tag::t0 >();
    1440                 :        114 :   auto nprop = g_cfg.get< tag::problem_ncomp >();
    1441                 :            : 
    1442                 :            :   // Will store nodal ICs
    1443                 :        114 :   tk::Fields u( m_coord[0].size(), nprop );
    1444                 :            : 
    1445                 :            :   // Evaluate ICs
    1446                 :            : 
    1447                 :            :   // Evaluate ICs for all scalar components integrated
    1448         [ +  - ]:        114 :   problems::initialize( m_coord, u, t0, /*meshid=*/0 );
    1449                 :            : 
    1450 [ -  + ][ -  - ]:        114 :   Assert( u.nunk() == m_coord[0].size(), "Size mismatch" );
         [ -  - ][ -  - ]
    1451 [ -  + ][ -  - ]:        114 :   Assert( u.nprop() == nprop, "Size mismatch" );
         [ -  - ][ -  - ]
    1452                 :            : 
    1453                 :        114 :   return u;
    1454                 :          0 : }
    1455                 :            : 
    1456                 :            : void
    1457                 :         71 : Refiner::updateMesh()
    1458                 :            : // *****************************************************************************
    1459                 :            : // Update old mesh after refinement
    1460                 :            : // *****************************************************************************
    1461                 :            : {
    1462                 :            :   // Get refined mesh connectivity
    1463         [ +  - ]:         71 :   const auto& refinpoel = m_refiner.tet_store.get_active_inpoel();
    1464 [ -  + ][ -  - ]:         71 :   Assert( refinpoel.size()%4 == 0, "Inconsistent refined mesh connectivity" );
         [ -  - ][ -  - ]
    1465                 :            : 
    1466                 :            :   // Generate unique node lists of old and refined mesh using local ids
    1467         [ +  - ]:         71 :   auto rinpoel = m_inpoel;
    1468         [ +  - ]:         71 :   tk::remap( rinpoel, m_rid );
    1469         [ +  - ]:         71 :   std::unordered_set< std::size_t > old( begin(rinpoel), end(rinpoel) );
    1470         [ +  - ]:         71 :   std::unordered_set< std::size_t > ref( begin(refinpoel), end(refinpoel) );
    1471                 :            : 
    1472                 :            :   // Augment refiner id -> local node id map with newly added nodes
    1473                 :         71 :   std::size_t l = m_lref.size();
    1474 [ +  - ][ +  + ]:      31966 :   for (auto r : ref) if (old.find(r) == end(old)) m_lref[r] = l++;
         [ +  - ][ +  + ]
    1475                 :            : 
    1476                 :            :   // Get nodal communication map from Discretization worker
    1477         [ -  + ]:         71 :   if ( m_mode == RefMode::DTREF) {
    1478 [ -  - ][ -  - ]:          0 :     m_nodeCommMap = m_disc[ m_meshid ][ thisIndex ].ckLocal()->NodeCommMap();
                 [ -  - ]
    1479                 :            :   }
    1480                 :            : 
    1481                 :            :   // Update mesh and solution after refinement
    1482         [ +  - ]:         71 :   newVolMesh( old, ref );
    1483                 :            : 
    1484                 :            :   // Update mesh connectivity from refiner lib, remapping refiner to local ids
    1485 [ +  - ][ +  - ]:         71 :   m_inpoel = m_refiner.tet_store.get_active_inpoel();
    1486                 :            : 
    1487         [ +  - ]:         71 :   tk::remap( m_inpoel, m_lref );
    1488                 :            : 
    1489                 :            :   // Update mesh connectivity with new global node ids
    1490         [ +  - ]:         71 :   m_ginpoel = m_inpoel;
    1491 [ +  - ][ -  + ]:         71 :   Assert( tk::uniquecopy(m_ginpoel).size() == m_coord[0].size(),
         [ -  - ][ -  - ]
                 [ -  - ]
    1492                 :            :           "Size mismatch" );
    1493         [ +  - ]:         71 :   tk::remap( m_ginpoel, m_gid );
    1494                 :            : 
    1495                 :            :   // Update boundary face and node information
    1496         [ +  - ]:         71 :   newBndMesh( ref );
    1497                 :            : 
    1498                 :            :   // Augment node communication map with newly added nodes on chare-boundary
    1499         [ -  + ]:         71 :   if (m_mode == RefMode::DTREF) {
    1500         [ -  - ]:          0 :     for (const auto& [ neighborchare, edges ] : m_remoteEdges) {
    1501         [ -  - ]:          0 :       auto& nodes = tk::ref_find( m_nodeCommMap, neighborchare );
    1502         [ -  - ]:          0 :       for (const auto& e : edges) {
    1503                 :            :         // If parent nodes were part of the node communication map for chare
    1504 [ -  - ][ -  - ]:          0 :         if (nodes.find(e[0]) != end(nodes) && nodes.find(e[1]) != end(nodes)) {
         [ -  - ][ -  - ]
                 [ -  - ]
    1505                 :            :           // Add new node if local id was generated for it
    1506         [ -  - ]:          0 :           auto n = Hash<2>()( e );
    1507 [ -  - ][ -  - ]:          0 :           if (m_lid.find(n) != end(m_lid)) nodes.insert( n );
                 [ -  - ]
    1508                 :            :         }
    1509                 :            :       }
    1510                 :            :     }
    1511                 :            :   }
    1512                 :            : 
    1513                 :            :   // Ensure valid mesh after refinement
    1514 [ +  - ][ -  + ]:         71 :   Assert( tk::positiveJacobians( m_inpoel, m_coord ),
         [ -  - ][ -  - ]
                 [ -  - ]
    1515                 :            :           "Refined mesh cell Jacobian non-positive" );
    1516                 :            : 
    1517 [ +  - ][ -  + ]:         71 :   Assert( tk::conforming( m_inpoel, m_coord, true, m_rid ),
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
    1518                 :            :           "Chare-"+std::to_string(thisIndex)+
    1519                 :            :           " mesh not conforming after updating mesh after mesh refinement" );
    1520                 :            : 
    1521                 :            :   // Perform leak test on new mesh
    1522 [ +  - ][ +  - ]:         71 :   Assert( !tk::leakyPartition(
         [ +  - ][ -  + ]
         [ -  - ][ -  - ]
                 [ -  - ]
    1523                 :            :             tk::genEsuelTet( m_inpoel, tk::genEsup(m_inpoel,4) ),
    1524                 :            :             m_inpoel, m_coord ),
    1525                 :            :           "Refined mesh partition leaky" );
    1526                 :         71 : }
    1527                 :            : 
    1528                 :            : void
    1529                 :         71 : Refiner::newVolMesh( const std::unordered_set< std::size_t >& old,
    1530                 :            :                      const std::unordered_set< std::size_t >& ref )
    1531                 :            : // *****************************************************************************
    1532                 :            : //  Compute new volume mesh after mesh refinement
    1533                 :            : //! \param[in] old Unique nodes of the old (unrefined) mesh using
    1534                 :            : //!   refiner-lib ids
    1535                 :            : //! \param[in] ref Unique nodes of the refined mesh using refiner-lib ids
    1536                 :            : // *****************************************************************************
    1537                 :            : {
    1538                 :         71 :   const auto& x = m_coord[0];
    1539                 :         71 :   const auto& y = m_coord[1];
    1540                 :         71 :   const auto& z = m_coord[2];
    1541                 :            : 
    1542                 :            :   // Generate coordinates and ids to newly added nodes after refinement
    1543                 :         71 :   std::unordered_map< std::size_t, std::size_t > gid_add;
    1544                 :         71 :   tk::destroy( m_addedNodes );
    1545                 :         71 :   tk::destroy( m_removedNodes );
    1546                 :         71 :   tk::destroy( m_amrNodeMap );
    1547         [ +  + ]:      31966 :   for (auto r : ref) {               // for all unique nodes of the refined mesh
    1548 [ +  - ][ +  + ]:      31895 :     if (old.find(r) == end(old)) {   // if node is newly added
    1549                 :            :       // get (local) parent ids of newly added node
    1550         [ +  - ]:      22670 :       auto p = m_refiner.node_connectivity.get( r );
    1551 [ -  + ][ -  - ]:      22670 :       Assert(p[0] != p[1], "Node without parent edge in newVolMesh");
         [ -  - ][ -  - ]
    1552 [ +  - ][ +  - ]:      22670 :       Assert( old.find(p[0]) != end(old) && old.find(p[1]) != end(old),
         [ +  - ][ +  - ]
         [ -  - ][ -  - ]
                 [ -  - ]
    1553                 :            :               "Parent(s) not in old mesh" );
    1554                 :            :       // local parent ids
    1555 [ +  - ][ +  - ]:      22670 :       decltype(p) lp{{tk::cref_find(m_lref,p[0]), tk::cref_find(m_lref,p[1])}};
    1556                 :            :       // global parent ids
    1557                 :      22670 :       decltype(p) gp{{m_gid[lp[0]], m_gid[lp[1]]}};
    1558                 :            :       // generate new global ID for newly added node
    1559         [ +  - ]:      22670 :       auto g = Hash<2>()( gp );
    1560                 :            : 
    1561                 :            :       // if node added by AMR lib has not yet been added to Refiner's new mesh
    1562 [ +  - ][ +  - ]:      22670 :       if (m_coordmap.find(g) == end(m_coordmap)) {
    1563 [ -  + ][ -  - ]:      22670 :         Assert( g >= old.size(), "Hashed id overwriting old id" );
         [ -  - ][ -  - ]
    1564 [ +  - ][ -  + ]:      22670 :         Assert( m_lid.find(g) == end(m_lid),
         [ -  - ][ -  - ]
                 [ -  - ]
    1565                 :            :                 "Overwriting entry global->local node ID map" );
    1566         [ +  - ]:      22670 :         auto l = tk::cref_find( m_lref, r );
    1567                 :            :         // store newly added node id and their parent ids (local ids)
    1568         [ +  - ]:      22670 :         m_addedNodes[r] = lp;   // key = r for later update to local
    1569                 :            :         // assign new node to refiner->global map
    1570         [ +  - ]:      22670 :         gid_add[r] = g; // key = r for later search
    1571                 :            :         // assign new node to global->local map
    1572         [ +  - ]:      22670 :         m_lid[g] = l;
    1573                 :            :         // generate and store coordinates for newly added node
    1574         [ +  - ]:      45340 :         m_coordmap.insert( {g, {{ (x[lp[0]] + x[lp[1]])/2.0,
    1575                 :      22670 :                                   (y[lp[0]] + y[lp[1]])/2.0,
    1576                 :      22670 :                                   (z[lp[0]] + z[lp[1]])/2.0 }} } );
    1577                 :            :       }
    1578                 :            :     }
    1579                 :            :   }
    1580                 :         71 :   tk::destroy( m_coord );
    1581                 :            : 
    1582                 :            :   // generate a node map based on oldnodes+addednodes
    1583         [ +  - ]:         71 :   std::vector< size_t > nodeVec(m_coordmap.size());
    1584         [ +  + ]:      41397 :   for (size_t j=0; j<nodeVec.size(); ++j) {
    1585                 :      41326 :     nodeVec[j] = j;
    1586                 :            :   }
    1587                 :            : 
    1588                 :            :   // Remove coordinates and ids of removed nodes due to derefinement
    1589                 :         71 :   std::unordered_map< std::size_t, std::size_t > gid_rem;
    1590         [ +  + ]:      18727 :   for (auto o : old) {               // for all unique nodes of the old mesh
    1591 [ +  - ][ +  + ]:      18656 :     if (ref.find(o) == end(ref)) {   // if node is no longer in new mesh
    1592         [ +  - ]:       9431 :       auto l = tk::cref_find( m_lref, o );
    1593                 :       9431 :       auto g = m_gid[l];
    1594                 :            :       // store local-ids of removed nodes
    1595         [ +  - ]:       9431 :       m_removedNodes.insert(l);
    1596                 :            :       // remove derefined nodes from node comm map
    1597         [ -  + ]:       9431 :       for (auto& [neighborchare, sharednodes] : m_nodeCommMap) {
    1598 [ -  - ][ -  - ]:          0 :         if (sharednodes.find(g) != sharednodes.end()) {
    1599         [ -  - ]:          0 :           sharednodes.erase(g);
    1600                 :            :         }
    1601                 :            :       }
    1602         [ +  - ]:       9431 :       gid_rem[l] = g;
    1603         [ +  - ]:       9431 :       m_lid.erase( g );
    1604         [ +  - ]:       9431 :       m_coordmap.erase( g );
    1605                 :            :     }
    1606                 :            :   }
    1607                 :            : 
    1608                 :            :   // update the node map by removing the derefined nodes
    1609 [ -  + ][ -  - ]:         71 :   if (m_mode == RefMode::DTREF && m_removedNodes.size() > 0) {
                 [ -  + ]
    1610                 :            :     // remove derefined nodes
    1611                 :          0 :     size_t remCount = 0;
    1612                 :          0 :     size_t origSize = nodeVec.size();
    1613         [ -  - ]:          0 :     for (size_t j=0; j<origSize; ++j) {
    1614                 :          0 :       auto nd = nodeVec[j-remCount];
    1615                 :            : 
    1616                 :          0 :       bool no_change = false;
    1617                 :          0 :       size_t nodeidx = 0;
    1618         [ -  - ]:          0 :       for (const auto& rn : m_removedNodes) {
    1619         [ -  - ]:          0 :         if (nd < *m_removedNodes.cbegin()) {
    1620                 :          0 :           no_change = true;
    1621                 :          0 :           break;
    1622                 :            :         }
    1623         [ -  - ]:          0 :         else if (nd <= rn) {
    1624                 :          0 :           nodeidx = rn;
    1625                 :          0 :           break;
    1626                 :            :         }
    1627                 :            :       }
    1628                 :            : 
    1629                 :            :       // if node is out-or-range of removed nodes list, continue with next entry
    1630         [ -  - ]:          0 :       if (no_change)
    1631                 :          0 :         continue;
    1632                 :            :       // if not is within range of removed nodes list, erase node appropriately
    1633         [ -  - ]:          0 :       else if (nodeidx == nd) {
    1634                 :            :         //! Difference type for iterator/pointer arithmetics
    1635                 :            :         using diff_type = std::vector< std::size_t >::difference_type;
    1636         [ -  - ]:          0 :         nodeVec.erase(nodeVec.begin()+static_cast< diff_type >(j-remCount));
    1637                 :          0 :         ++remCount;
    1638                 :            :       }
    1639                 :            :     }
    1640                 :            : 
    1641 [ -  - ][ -  - ]:          0 :     Assert(remCount == m_removedNodes.size(), "Incorrect number of nodes removed "
         [ -  - ][ -  - ]
    1642                 :            :       "from node map.");
    1643                 :            :   }
    1644                 :            : 
    1645                 :            :   // invert node vector to get node map
    1646         [ +  + ]:      41397 :   for (size_t i=0; i<nodeVec.size(); ++i) {
    1647         [ +  - ]:      41326 :     m_amrNodeMap[nodeVec[i]] = i;
    1648                 :            :   }
    1649                 :            : 
    1650                 :            :   //// Save previous states of refiner-local node id maps before update
    1651                 :            :   //m_oldrid = m_rid;
    1652                 :            :   //m_oldlref = m_lref;
    1653                 :            : 
    1654                 :            :   // Generate new node id maps for nodes kept
    1655                 :         71 :   tk::destroy( m_lref );
    1656         [ +  - ]:         71 :   std::vector< std::size_t > rid( ref.size() );
    1657         [ +  - ]:         71 :   std::vector< std::size_t > gid( ref.size() );
    1658                 :         71 :   std::size_t l = 0;    // will generate new local node id
    1659         [ +  + ]:      18727 :   for (std::size_t i=0; i<m_gid.size(); ++i) {
    1660 [ +  - ][ +  + ]:      18656 :     if (gid_rem.find(i) == end(gid_rem)) {
    1661                 :       9225 :       gid[l] = m_gid[i];
    1662                 :       9225 :       rid[l] = m_rid[i];
    1663         [ +  - ]:       9225 :       m_lref[ m_rid[i] ] = l;
    1664                 :       9225 :       ++l;
    1665                 :            :     }
    1666                 :            :   }
    1667                 :            :   // Add newly added nodes due to refinement to node id maps
    1668                 :            :   // cppcheck-suppress unreadVariable
    1669         [ +  - ]:         71 :   decltype(m_addedNodes) addedNodes( m_addedNodes.size() );
    1670         [ +  + ]:      22741 :   for (const auto& n : gid_add) {
    1671                 :      22670 :     auto r = n.first;
    1672                 :      22670 :     auto g = n.second;
    1673                 :      22670 :     gid[l] = g;
    1674                 :            :     // cppcheck-suppress unreadVariable
    1675                 :      22670 :     rid[l] = r;
    1676 [ +  - ][ -  + ]:      22670 :     Assert(m_lref.find(r) == m_lref.end(), "Overwriting lref");
         [ -  - ][ -  - ]
                 [ -  - ]
    1677         [ +  - ]:      22670 :     m_lref[r] = l;
    1678         [ +  - ]:      22670 :     auto it = m_addedNodes.find( r );
    1679 [ -  + ][ -  - ]:      22670 :     Assert( it != end(m_addedNodes), "Cannot find added node" );
         [ -  - ][ -  - ]
    1680         [ +  - ]:      22670 :     addedNodes[l] = std::move(it->second);
    1681 [ +  - ][ +  - ]:      22670 :     addedNodes.at(l)[0] = m_amrNodeMap[addedNodes.at(l)[0]];
                 [ +  - ]
    1682 [ +  - ][ +  - ]:      22670 :     addedNodes.at(l)[1] = m_amrNodeMap[addedNodes.at(l)[1]];
                 [ +  - ]
    1683                 :      22670 :     ++l;
    1684                 :            :   }
    1685 [ -  + ][ -  - ]:         71 :   Assert( m_lref.size() == ref.size(), "Size mismatch" );
         [ -  - ][ -  - ]
    1686                 :            :   //for (auto r : ref) {
    1687                 :            :   //  Assert(m_lref.find(r) != m_lref.end(), "Node missing in lref");
    1688                 :            :   //}
    1689                 :            :   //const auto& int_list = m_refiner.tet_store.intermediate_list;
    1690                 :            :   //for (auto in : int_list) {
    1691                 :            :   //  Assert(m_lref.find(in) != m_lref.end(), "Interm node missing in lref: "
    1692                 :            :   //    + std::to_string(in));
    1693                 :            :   //}
    1694                 :         71 :   m_rid = std::move( rid );
    1695 [ -  + ][ -  - ]:         71 :   Assert( m_rid.size() == ref.size(), "Size mismatch" );
         [ -  - ][ -  - ]
    1696                 :         71 :   m_addedNodes = std::move( addedNodes );
    1697                 :            : 
    1698                 :            :   // Update node coordinates, ids, and id maps
    1699                 :         71 :   auto& rx = m_coord[0];
    1700                 :         71 :   auto& ry = m_coord[1];
    1701                 :         71 :   auto& rz = m_coord[2];
    1702         [ +  - ]:         71 :   rx.resize( ref.size() );
    1703         [ +  - ]:         71 :   ry.resize( ref.size() );
    1704         [ +  - ]:         71 :   rz.resize( ref.size() );
    1705         [ +  + ]:      31966 :   for (std::size_t i=0; i<gid.size(); ++i) {
    1706         [ +  - ]:      31895 :     tk::ref_find( m_lid, gid[i] ) = i;
    1707         [ +  - ]:      31895 :     const auto& c = tk::cref_find( m_coordmap, gid[i] );
    1708                 :      31895 :     rx[i] = c[0];
    1709                 :      31895 :     ry[i] = c[1];
    1710                 :      31895 :     rz[i] = c[2];
    1711                 :            :   }
    1712                 :         71 :   m_gid = std::move( gid );
    1713 [ +  - ][ +  - ]:         71 :   Assert( m_gid.size() == m_lid.size() && m_gid.size() == ref.size(),
         [ -  - ][ -  - ]
                 [ -  - ]
    1714                 :            :     "Size mismatch" );
    1715                 :         71 : }
    1716                 :            : 
    1717                 :            : std::unordered_set< std::size_t >
    1718                 :    2552108 : Refiner::ancestors( std::size_t n )
    1719                 :            : // *****************************************************************************
    1720                 :            : // Find the oldest parents of a mesh node in the AMR hierarchy
    1721                 :            : //! \param[in] n Local node id whose ancestors to search
    1722                 :            : //! \return Parents of local node id from the coarsest (original) mesh
    1723                 :            : // *****************************************************************************
    1724                 :            : {
    1725         [ +  - ]:    2552108 :   auto d = m_refiner.node_connectivity.get( m_rid[n] );
    1726         [ +  - ]:    2552108 :   decltype(d) p{{ tk::cref_find( m_lref, d[0] ),
    1727         [ +  - ]:    2552108 :                   tk::cref_find( m_lref, d[1] ) }};
    1728                 :            : 
    1729                 :    2552108 :   std::unordered_set< std::size_t > s;
    1730                 :            : 
    1731 [ +  - ][ +  + ]:    2552108 :   if (p != AMR::node_pair_t{{n,n}}) {
    1732         [ +  - ]:     926230 :     auto q = ancestors( p[0] );
    1733         [ +  - ]:     926230 :     s.insert( begin(q), end(q) );
    1734         [ +  - ]:     926230 :     auto r = ancestors( p[1] );
    1735         [ +  - ]:     926230 :     s.insert( begin(r), end(r) );
    1736                 :     926230 :   } else {
    1737         [ +  - ]:    1625878 :     s.insert( begin(p), end(p) );
    1738                 :            :   }
    1739                 :            : 
    1740                 :    5104216 :   return s;
    1741                 :          0 : }
    1742                 :            : 
    1743                 :            : Refiner::BndFaceData
    1744                 :         71 : Refiner::boundary()
    1745                 :            : // *****************************************************************************
    1746                 :            : //  Generate boundary data structures used to update refined/derefined boundary
    1747                 :            : //  faces and nodes of side sets
    1748                 :            : //! \return A tuple of boundary face data
    1749                 :            : //! \details The output of this function is used to regenerate physical boundary
    1750                 :            : //!   face and node data structures after refinement, see updateBndData().
    1751                 :            : // *****************************************************************************
    1752                 :            : {
    1753                 :            :   // Generate the inverse of AMR's tet store
    1754                 :         71 :   std::unordered_map< Tet, std::size_t, Hash<4>, Eq<4> > invtets;
    1755         [ +  + ]:     145529 :   for (const auto& [key, tet] : m_refiner.tet_store.tets)
    1756         [ +  - ]:     145458 :     invtets[ tet ] = key;
    1757                 :            : 
    1758                 :            :   //std::cout << thisIndex << " invt: " << invtets.size() << '\n';
    1759                 :            :   //std::cout << thisIndex << " active inpoel size: " << m_refiner.tet_store.get_active_inpoel().size() << '\n';
    1760                 :            :   //std::cout << thisIndex << " marked derefinement size: " << m_refiner.tet_store.marked_derefinements.size() << '\n';
    1761                 :            : 
    1762                 :            :   // Generate data structure pcFaceTets for the new (post-AMR) mesh:
    1763                 :            :   // pcFaceTets is a map that associates all triangle boundary faces (physical
    1764                 :            :   // and chare) to the id of the tet adjacent to the said face.
    1765                 :            :   // Key: Face-nodes' global id; Value: tet-id.
    1766                 :         71 :   std::unordered_map< Face, std::size_t, Hash<3>, Eq<3> > pcFaceTets;
    1767 [ +  - ][ +  - ]:         71 :   auto esuel = tk::genEsuelTet( m_inpoel, tk::genEsup(m_inpoel,4) );
    1768         [ +  + ]:     128238 :   for (std::size_t e=0; e<esuel.size()/4; ++e) {
    1769                 :     128167 :     auto m = e*4;
    1770         [ +  + ]:     640835 :     for (std::size_t f=0; f<4; ++f) {
    1771         [ +  + ]:     512668 :       if (esuel[m+f] == -1) {  // if a face does not have an adjacent tet
    1772                 :      38060 :         Face b{{ m_ginpoel[ m+tk::lpofa[f][0] ],
    1773                 :      38060 :                  m_ginpoel[ m+tk::lpofa[f][1] ],
    1774                 :      76120 :                  m_ginpoel[ m+tk::lpofa[f][2] ] }};
    1775 [ +  - ][ +  - ]:      38060 :         Assert( m_inpoel[m+0] < m_rid.size() &&
         [ +  - ][ +  - ]
         [ -  - ][ -  - ]
                 [ -  - ]
    1776                 :            :                 m_inpoel[m+1] < m_rid.size() &&
    1777                 :            :                 m_inpoel[m+2] < m_rid.size() &&
    1778                 :            :                 m_inpoel[m+3] < m_rid.size(), "Indexing out of rid" );
    1779                 :      76120 :         Tet t{{ m_rid[ m_inpoel[m+0] ], m_rid[ m_inpoel[m+1] ],
    1780                 :      76120 :                 m_rid[ m_inpoel[m+2] ], m_rid[ m_inpoel[m+3] ] }};
    1781                 :            :         //Tet t{{ m_inpoel[m+0], m_inpoel[m+1],
    1782                 :            :         //        m_inpoel[m+2], m_inpoel[m+3] }};
    1783                 :            :         // associate tet id to adjacent (physical or chare) boundary face
    1784         [ +  - ]:      38060 :         auto i = invtets.find( t );
    1785 [ +  - ][ -  + ]:      38060 :         Assert(m_refiner.tet_store.is_active(i->second),
         [ -  - ][ -  - ]
                 [ -  - ]
    1786                 :            :           "Inactive element while regenerating boundary data");
    1787         [ +  - ]:      38060 :         if (i != end(invtets)) {
    1788                 :            :           //std::cout << "refacetets: " <<
    1789                 :            :           //  b[0] << "-" << b[1] << "-" << b[2] << std::endl;
    1790         [ +  - ]:      38060 :           pcFaceTets[ b ] = i->second;
    1791                 :            :         } else {
    1792 [ -  - ][ -  - ]:          0 :           Throw("Active element not found in tet_store");
                 [ -  - ]
    1793                 :            :         }
    1794                 :            :       }
    1795                 :            :     }
    1796                 :            :   }
    1797                 :            : 
    1798                 :            :   // Generate child->parent tet and id maps after refinement/derefinement step
    1799                 :            : //  tk::destroy( m_oldparent );
    1800                 :         71 :   m_addedTets.clear();
    1801                 :         71 :   std::size_t p = 0;
    1802                 :            :   // cppcheck-suppress unreadVariable
    1803                 :         71 :   std::size_t c = 0;
    1804                 :         71 :   const auto& tet_store = m_refiner.tet_store;
    1805         [ +  + ]:     145529 :   for (const auto& t : tet_store.tets) {
    1806                 :            :     // query number of children of tet
    1807         [ +  - ]:     145458 :     auto nc = tet_store.data( t.first ).children.size();
    1808         [ +  + ]:     282302 :     for (decltype(nc) i=0; i<nc; ++i ) {      // for all child tets
    1809                 :            :       // get child tet id
    1810         [ +  - ]:     136844 :       auto childtet = tet_store.get_child_id( t.first, i );
    1811         [ +  - ]:     136844 :       auto ct = tet_store.tets.find( childtet );
    1812 [ -  + ][ -  - ]:     136844 :       Assert(ct != tet_store.tets.end(), "Child not found in tet store");
         [ -  - ][ -  - ]
    1813                 :            : //      //auto cA = tk::cref_find( m_lref, ct->second[0] );
    1814                 :            : //      //auto cB = tk::cref_find( m_lref, ct->second[1] );
    1815                 :            : //      //auto cC = tk::cref_find( m_lref, ct->second[2] );
    1816                 :            : //      //auto cD = tk::cref_find( m_lref, ct->second[3] );
    1817                 :            : //      // get nodes of parent tet
    1818                 :            : //      //auto pA = tk::cref_find( m_lref, t.second[0] );
    1819                 :            : //      //auto pB = tk::cref_find( m_lref, t.second[1] );
    1820                 :            : //      //auto pC = tk::cref_find( m_lref, t.second[2] );
    1821                 :            : //      //auto pD = tk::cref_find( m_lref, t.second[3] );
    1822                 :            : //      // assign parent tet to child tet
    1823                 :            : //      //m_oldparent[ {{cA,cB,cC,cD}} ] = {{pA,pB,pC,pD}};
    1824                 :            : //      m_oldparent[ ct->second ] = t.second; //{{pA,pB,pC,pD}};
    1825 [ +  - ][ +  + ]:     136844 :       if (m_oldTets.find(ct->second) == end(m_oldTets)) {
    1826                 :            :         // TODO: the following code can assign negative ids to newly added tets.
    1827                 :            :         // This needs to be corrected before applying to cell-based schemes.
    1828                 :            :         //Assert((p-m_oldntets) > 0, "Negative id assigned to added tet");
    1829         [ +  - ]:     112028 :         m_addedTets[ c++ ] = p - m_oldntets;
    1830                 :            :       }
    1831                 :            :     }
    1832                 :     145458 :     ++p;
    1833                 :            :   }
    1834                 :            : 
    1835                 :            :   //std::cout << thisIndex << " added: " << m_addedTets.size() << '\n';
    1836                 :            :   //std::cout << thisIndex << " parent: " << m_oldparent.size() << '\n';
    1837                 :            :   //std::cout << thisIndex << " pcret: " << pcFaceTets.size() << '\n';
    1838                 :            : 
    1839                 :            :   //for (std::size_t f=0; f<m_triinpoel.size()/3; ++f) {
    1840                 :            :   //  std::cout << "triinpoel: " <<
    1841                 :            :   //    m_triinpoel[f*3+0] << "-" << m_triinpoel[f*3+1] << "-" <<
    1842                 :            :   //    m_triinpoel[f*3+2] << std::endl;
    1843                 :            :   //}
    1844                 :            : 
    1845                 :        142 :   return pcFaceTets;
    1846                 :         71 : }
    1847                 :            : 
    1848                 :            : void
    1849                 :         71 : Refiner::newBndMesh( const std::unordered_set< std::size_t >& ref )
    1850                 :            : // *****************************************************************************
    1851                 :            : // Update boundary data structures after mesh refinement
    1852                 :            : //! \param[in] ref Unique nodes of the refined mesh using refiner-lib ids
    1853                 :            : // *****************************************************************************
    1854                 :            : {
    1855                 :            :   // Generate boundary face data structures used to regenerate boundary face
    1856                 :            :   // and node data after mesh refinement
    1857         [ +  - ]:         71 :   auto pcFaceTets = boundary();
    1858                 :            : 
    1859                 :            :   // Regerate boundary faces and nodes after AMR step
    1860         [ +  - ]:         71 :   updateBndData( ref, pcFaceTets );
    1861                 :         71 : }
    1862                 :            : 
    1863                 :            : void
    1864                 :         71 : Refiner::updateBndData(
    1865                 :            :   [[maybe_unused]] const std::unordered_set< std::size_t >& ref,
    1866                 :            :   const BndFaceData& pcFaceTets )
    1867                 :            : // *****************************************************************************
    1868                 :            : // Regenerate boundary faces and nodes after AMR step
    1869                 :            : //! \param[in] ref Unique nodes of the refined mesh using refiner-lib ids
    1870                 :            : //! \param[in] pcFaceTets Boundary face data
    1871                 :            : // *****************************************************************************
    1872                 :            : {
    1873                 :            :   // storage for boundary faces associated to side-set IDs of the refined mesh
    1874                 :         71 :   tk::destroy( m_bface );
    1875                 :            :   // storage for boundary faces-node connectivity of the refined mesh
    1876                 :         71 :   tk::destroy( m_triinpoel );
    1877                 :            :   // storage for boundary nodes associated to side-set IDs of the refined mesh
    1878                 :         71 :   tk::destroy( m_bnode );
    1879                 :            : 
    1880                 :            :   // will collect unique faces added for each side set
    1881                 :         71 :   std::unordered_map< int, FaceSet > bf;
    1882                 :            : 
    1883                 :            :   // Lambda to search the parents in the coarsest mesh of a mesh node and if
    1884                 :            :   // found, add its global id to boundary node lists associated to the side
    1885                 :            :   // set(s) of its parents. Argument 'n' is the local id of the mesh node id
    1886                 :            :   // whose parents to search.
    1887                 :     585468 :   auto addBndNodes = [&]( std::size_t n ){
    1888         [ +  - ]:     585468 :     auto a = ancestors( n );  // find parents of n in coarse mesh
    1889         [ +  + ]:     585468 :     if (a.size() == 1) {
    1890                 :            :       // node was part of the coarse mesh
    1891 [ -  + ][ -  - ]:     109874 :       Assert(*a.cbegin() == n, "Single ancestor not self");
         [ -  - ][ -  - ]
    1892         [ +  - ]:     109874 :       auto ss = keys( m_coarseBndNodes, m_gid[*a.cbegin()] );
    1893         [ +  + ]:     269898 :       for (auto s : ss)
    1894 [ +  - ][ +  - ]:     160024 :         m_bnode[ s ].push_back( m_gid[n] );
    1895         [ +  + ]:     585468 :     } else if (a.size() == 2) {
    1896                 :            :       // node was added to an edge of a coarse face
    1897         [ +  - ]:     374802 :       std::vector< std::size_t > p( begin(a), end(a) );
    1898         [ +  - ]:     374802 :       auto ss1 = keys( m_coarseBndNodes, m_gid[p[0]] );
    1899         [ +  - ]:     374802 :       auto ss2 = keys( m_coarseBndNodes, m_gid[p[1]] );
    1900         [ +  + ]:     891908 :       for (auto s : ss1) {
    1901                 :            :         // only add 'n' to bnode if all parent nodes are in same side set, else
    1902                 :            :         // 'n' is not a boundary node
    1903 [ +  - ][ +  + ]:     517106 :         if (ss2.find(s) != end(ss2)) {
    1904 [ +  - ][ +  - ]:     404902 :           m_bnode[ s ].push_back( m_gid[n] );
    1905                 :            :         }
    1906                 :            :       }
    1907         [ +  - ]:     475594 :     } else if (a.size() == 3) {
    1908                 :            :       // node was added inside of a coarse face
    1909         [ +  - ]:     100792 :       std::vector< std::size_t > p( begin(a), end(a) );
    1910         [ +  - ]:     100792 :       auto ss1 = keys( m_coarseBndNodes, m_gid[p[0]] );
    1911         [ +  - ]:     100792 :       auto ss2 = keys( m_coarseBndNodes, m_gid[p[1]] );
    1912         [ +  - ]:     100792 :       auto ss3 = keys( m_coarseBndNodes, m_gid[p[2]] );
    1913         [ +  + ]:     275845 :       for (auto s : ss1) {
    1914                 :            :         // only add 'n' to bnode if all parent nodes are in same side set, else
    1915                 :            :         // 'n' is not a boundary node
    1916 [ +  - ][ +  + ]:     175053 :         if (ss2.find(s) != end(ss2) && ss3.find(s) != end(ss3)) {
         [ +  - ][ +  + ]
                 [ +  + ]
    1917 [ +  - ][ +  - ]:      89992 :           m_bnode[ s ].push_back( m_gid[n] );
    1918                 :            :         }
    1919                 :            :       }
    1920                 :     100792 :     }
    1921                 :     585468 :   };
    1922                 :            : 
    1923                 :            :   // face id counter
    1924                 :         71 :   std::size_t facecnt = 0;
    1925                 :            : 
    1926                 :            :   // Lambda to associate a boundary face and connectivity to a side set.
    1927                 :            :   // Argument 's' is the list of faces (ids) to add the new face to. Argument
    1928                 :            :   // 'ss' is the side set id to which the face is added. Argument 'f' is the
    1929                 :            :   // triangle face connectivity to add.
    1930                 :      33968 :   auto addBndFace = [&]( std::vector< std::size_t >& s, int ss, const Face& f )
    1931                 :            :   {
    1932                 :            :     // only add face if it has not yet been aded to this side set
    1933         [ +  - ]:      33968 :     if (bf[ ss ].insert( f ).second) {
    1934         [ +  - ]:      33968 :       s.push_back( facecnt++ );
    1935         [ +  - ]:      33968 :       m_triinpoel.insert( end(m_triinpoel), begin(f), end(f) );
    1936 [ -  + ][ -  - ]:      33968 :       Assert(m_triinpoel.size()/3 == facecnt, "Incorrect size of triinpoel");
         [ -  - ][ -  - ]
    1937                 :            :     }
    1938                 :      33968 :   };
    1939                 :            : 
    1940                 :            :   // Regenerate boundary faces for new mesh along side sets. For all faces
    1941                 :            :   // associated to side sets, we find the ancestors (parents of nodes in the
    1942                 :            :   // original/coarsest mesh) of the nodes comprising the physical and chare
    1943                 :            :   // boundary faces of the new mesh.
    1944                 :            :   //bool faceNoSs = false;
    1945                 :            :   // for all P/C faces in current (post-AMR) mesh
    1946         [ +  + ]:      38131 :   for (const auto& [ face, tetid ] : pcFaceTets) {
    1947                 :            :     // find ancestors of face
    1948                 :      38060 :     std::unordered_set< std::size_t > ans;
    1949         [ +  + ]:     152240 :     for (std::size_t i=0; i<3; ++i) {
    1950 [ +  - ][ +  - ]:     114180 :       auto ai = ancestors(tk::cref_find(m_lid, face[i]));
    1951         [ +  - ]:     114180 :       ans.insert(ai.begin(), ai.end());
    1952                 :     114180 :     }
    1953 [ -  + ][ -  - ]:      38060 :     Assert(ans.size() == 3, "Incorrect number of ancestors in refined face");
         [ -  - ][ -  - ]
    1954                 :            :     Face af;
    1955                 :      38060 :     std::size_t i = 0;
    1956         [ +  + ]:     152240 :     for (auto ai:ans) {
    1957                 :     114180 :       af[i] = m_gid[ai];
    1958                 :     114180 :       ++i;
    1959                 :            :     }
    1960                 :            :     // for all boundary faces in original mesh
    1961                 :            :     //std::size_t fss = 0;
    1962         [ +  + ]:     233216 :     for (const auto& [ss, cfaceset] : m_coarseBndFaces) {
    1963 [ +  - ][ +  + ]:     195156 :       if (cfaceset.find(af) != cfaceset.end()) {
    1964 [ +  - ][ +  - ]:      33968 :         addBndFace(m_bface[ss], ss, face);
    1965                 :            :         //++fss;
    1966                 :            :       }
    1967         [ +  + ]:     780624 :       for (auto j : face) {
    1968 [ +  - ][ +  - ]:     585468 :         addBndNodes(tk::cref_find(m_lid, j));
    1969                 :            :       }
    1970                 :            :     }
    1971                 :            :     //if (fss==0) {
    1972                 :            :     //  std::cout << "Face added to no/multiple side sets; " << fss << std::endl;
    1973                 :            :     //  faceNoSs = true;
    1974                 :            :     //}
    1975                 :      38060 :   }
    1976                 :            : 
    1977                 :            :   // Commented code below, since diagcg can work without sideset/bcs
    1978                 :            :   //Assert(!faceNoSs, "Face/s added to incorrect number of side sets");
    1979                 :            : 
    1980                 :            :   // Make boundary node IDs unique for each physical boundary (side set)
    1981 [ +  - ][ +  + ]:        423 :   for (auto& s : m_bnode) tk::unique( s.second );
    1982                 :            : 
    1983                 :            :   //for (const auto& [ setid, faceids ] : m_bface) {
    1984                 :            :   //  std::cout << "sset: " << setid << std::endl;
    1985                 :            :   //  for (auto f : faceids) {
    1986                 :            :   //    Assert(f<m_triinpoel.size()/3, "Out of bounds access into triinpoel");
    1987                 :            :   //    std::cout << "new bndfaces: " <<
    1988                 :            :   //      m_triinpoel[f*3+0] << "-" << m_triinpoel[f*3+1] << "-" <<
    1989                 :            :   //      m_triinpoel[f*3+2] << std::endl;
    1990                 :            :   //  }
    1991                 :            :   //}
    1992                 :            : 
    1993                 :            :   //for (std::size_t f=0; f<m_triinpoel.size()/3; ++f) {
    1994                 :            :   //  std::cout << "new triinpoel: " <<
    1995                 :            :   //    m_triinpoel[f*3+0] << "-" << m_triinpoel[f*3+1] << "-" <<
    1996                 :            :   //    m_triinpoel[f*3+2] << std::endl;
    1997                 :            :   //}
    1998                 :            : 
    1999                 :            :   //std::cout << thisIndex << " bf: " << tk::sumvalsize( m_bface ) << '\n';
    2000                 :            : 
    2001                 :            :   //std::cout << thisIndex << " bn: " << tk::sumvalsize( m_bnode ) << '\n';
    2002                 :            : 
    2003                 :            :   // Perform leak-test on boundary face data just updated (only in DEBUG)
    2004 [ +  - ][ -  + ]:         71 :   Assert( bndIntegral(), "Partial boundary integral" );
         [ -  - ][ -  - ]
                 [ -  - ]
    2005                 :         71 : }
    2006                 :            : 
    2007                 :            : bool
    2008                 :         71 : Refiner::bndIntegral()
    2009                 :            : // *****************************************************************************
    2010                 :            : //  Compute partial boundary surface integral and sum across all chares
    2011                 :            : //! \return true so we don't trigger assert in client code
    2012                 :            : //! \details This function computes a partial surface integral over the boundary
    2013                 :            : //!   of the faces of this mesh partition then sends its contribution to perform
    2014                 :            : //!   the integral acorss the total problem boundary. After the global sum a
    2015                 :            : //!   non-zero vector result indicates a leak, e.g., a hole in the boundary
    2016                 :            : //!   which indicates an error in the boundary face data structures used to
    2017                 :            : //!   compute the partial surface integrals.
    2018                 :            : // *****************************************************************************
    2019                 :            : {
    2020                 :         71 :   const auto& x = m_coord[0];
    2021                 :         71 :   const auto& y = m_coord[1];
    2022                 :         71 :   const auto& z = m_coord[2];
    2023                 :            : 
    2024         [ +  - ]:         71 :   std::vector< tk::real > s{{ 0.0, 0.0, 0.0 }};
    2025                 :            : 
    2026         [ +  + ]:        423 :   for (const auto& [ setid, faceids ] : m_bface) {
    2027         [ +  + ]:      34320 :     for (auto f : faceids) {
    2028         [ +  - ]:      33968 :       auto A = tk::cref_find( m_lid, m_triinpoel[f*3+0] );
    2029         [ +  - ]:      33968 :       auto B = tk::cref_find( m_lid, m_triinpoel[f*3+1] );
    2030         [ +  - ]:      33968 :       auto C = tk::cref_find( m_lid, m_triinpoel[f*3+2] );
    2031                 :            :       // Compute face area and normal
    2032                 :            :       tk::real nx, ny, nz;
    2033                 :      33968 :       auto a = tk::normal( x[A],x[B],x[C], y[A],y[B],y[C], z[A],z[B],z[C],
    2034                 :            :                            nx, ny, nz );
    2035                 :            :       // Sum up face area * face unit-normal
    2036                 :      33968 :       s[0] += a * nx;
    2037                 :      33968 :       s[1] += a * ny;
    2038                 :      33968 :       s[2] += a * nz;
    2039                 :            :     }
    2040                 :            :   }
    2041                 :            : 
    2042         [ +  - ]:         71 :   s.push_back( -1.0 );  // negative: no call-back after reduction
    2043         [ +  - ]:         71 :   s.push_back( static_cast< tk::real >( m_meshid ) );
    2044                 :            : 
    2045                 :            :   // Send contribution to host summing partial surface integrals
    2046         [ +  - ]:         71 :   contribute( s, CkReduction::sum_double, m_cbr.get< tag::bndint >() );
    2047                 :            : 
    2048                 :         71 :   return true;  // don't trigger the assert in client code
    2049                 :         71 : }
    2050                 :            : 
    2051                 :            : #include "NoWarning/refiner.def.h"

Generated by: LCOV version 1.16