Xyst test code coverage report
Current view: top level - Inciter - Discretization.cpp (source / functions) Hit Total Coverage
Commit: 7512f2d92be539d3e2bf801c81cb357720d8ffd7 Lines: 473 670 70.6 %
Date: 2025-04-27 10:04:21 Functions: 44 49 89.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 440 1040 42.3 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/Inciter/Discretization.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                 :            :   \details   Data and functionality common to all discretization schemes
      10                 :            :   \see       Discretization.h and Discretization.C for more info.
      11                 :            : */
      12                 :            : // *****************************************************************************
      13                 :            : 
      14                 :            : #include <iomanip>
      15                 :            : 
      16                 :            : #include "Reorder.hpp"
      17                 :            : #include "Vector.hpp"
      18                 :            : #include "DerivedData.hpp"
      19                 :            : #include "Discretization.hpp"
      20                 :            : #include "MeshWriter.hpp"
      21                 :            : #include "DiagWriter.hpp"
      22                 :            : #include "InciterConfig.hpp"
      23                 :            : #include "Print.hpp"
      24                 :            : #include "Around.hpp"
      25                 :            : #include "PDFReducer.hpp"
      26                 :            : #include "XystBuildConfig.hpp"
      27                 :            : #include "Box.hpp"
      28                 :            : #include "Transfer.hpp"
      29                 :            : #include "HoleReducer.hpp"
      30                 :            : 
      31                 :            : namespace inciter {
      32                 :            : 
      33                 :            : static CkReduction::reducerType PDFMerger;
      34                 :            : static CkReduction::reducerType HoleMerger;
      35                 :            : extern ctr::Config g_cfg;
      36                 :            : 
      37                 :            : } // inciter::
      38                 :            : 
      39                 :            : using inciter::Discretization;
      40                 :            : 
      41                 :       2576 : Discretization::Discretization(
      42                 :            :   std::size_t meshid,
      43                 :            :   const std::vector< CProxy_Discretization >& disc,
      44                 :            :   const CProxy_Transporter& transporter,
      45                 :            :   const tk::CProxy_MeshWriter& meshwriter,
      46                 :            :   const tk::UnsMesh::CoordMap& coordmap,
      47                 :            :   const tk::UnsMesh::Chunk& el,
      48                 :            :   const std::map< int, std::unordered_set< std::size_t > >& nodeCommMap,
      49                 :       2576 :   int nc ) :
      50                 :       2576 :   m_meshid( meshid ),
      51                 :       2576 :   m_nchare( nc ),
      52                 :       2576 :   m_it( 0 ),
      53                 :       2576 :   m_itr( 0 ),
      54                 :       2576 :   m_itf( 0 ),
      55                 :       2576 :   m_initial( 1 ),
      56                 :       2576 :   m_t( g_cfg.get< tag::t0 >() ),
      57                 :       2576 :   m_lastDumpTime( -std::numeric_limits< tk::real >::max() ),
      58                 :       2576 :   m_physFieldFloor( 0.0 ),
      59                 :       2576 :   m_physHistFloor( 0.0 ),
      60                 :       2576 :   m_physIntegFloor( 0.0 ),
      61         [ +  - ]:       2576 :   m_rangeFieldFloor( g_cfg.get< tag::fieldout, tag::range >().size(), 0.0 ),
      62         [ +  - ]:       2576 :   m_rangeHistFloor( g_cfg.get< tag::histout, tag::range >().size(), 0.0 ),
      63         [ +  - ]:       2576 :   m_rangeIntegFloor( g_cfg.get< tag::integout, tag::range >().size(), 0.0 ),
      64                 :       2576 :   m_dt( g_cfg.get< tag::dt >() ),
      65                 :       2576 :   m_dtn( m_dt ),
      66                 :       2576 :   m_nvol( 0 ),
      67         [ +  - ]:       2576 :   m_disc( disc ),
      68         [ +  - ]:       2576 :   m_transporter( transporter ),
      69         [ +  - ]:       2576 :   m_meshwriter( meshwriter ),
      70         [ +  - ]:       2576 :   m_el( el ),     // fills m_inpoel, m_gid, m_lid
      71                 :       2576 :   m_coord( setCoord( coordmap ) ),
      72                 :       2576 :   m_meshvol( 0.0 ),
      73         [ +  - ]:       2576 :   m_v( m_gid.size(), 0.0 ),
      74         [ +  - ]:       2576 :   m_vol( m_gid.size(), 0.0 ),
      75                 :       2576 :   m_refined( 0 ),
      76                 :       2576 :   m_prevstatus( std::chrono::high_resolution_clock::now() ),
      77                 :       2576 :   m_nrestart( 0 ),
      78                 :       2576 :   m_res( 0.0 ),
      79                 :       2576 :   m_res0( 0.0 ),
      80                 :       2576 :   m_res1( 0.0 ),
      81                 :       2576 :   m_dea( 0 ),
      82                 :       2576 :   m_deastarted( 0 ),
      83                 :       2576 :   m_pit( 0 ),
      84         [ +  - ]:      15456 :   m_mit( 0 )
      85                 :            : // *****************************************************************************
      86                 :            : //  Constructor
      87                 :            : //! \param[in] meshid Mesh ID
      88                 :            : //! \param[in] disc Discretization proxy for all meshes
      89                 :            : //! \param[in] transporter Host (Transporter) proxy
      90                 :            : //! \param[in] meshwriter Mesh writer proxy
      91                 :            : //! \param[in] coordmap Coordinates of mesh nodes and their global IDs
      92                 :            : //! \param[in] el Elements of the mesh chunk we operate on
      93                 :            : //! \param[in] nodeCommMap Node lists associated to chare IDs bordering the
      94                 :            : //!   mesh chunk we operate on
      95                 :            : //! \param[in] nc Total number of Discretization chares
      96                 :            : // *****************************************************************************
      97                 :            : {
      98 [ -  + ][ -  - ]:       2576 :   Assert( !m_inpoel.empty(), "No elements assigned to Discretization chare" );
         [ -  - ][ -  - ]
      99 [ +  - ][ -  + ]:       2576 :   Assert( tk::positiveJacobians( m_inpoel, m_coord ),
         [ -  - ][ -  - ]
                 [ -  - ]
     100                 :            :           "Jacobian in input mesh to Discretization non-positive" );
     101                 :            :   #if not defined(__INTEL_COMPILER) || defined(NDEBUG)
     102                 :            :   // The above ifdef skips running the conformity test with the intel compiler
     103                 :            :   // in debug mode only. This is necessary because in tk::conforming(), filling
     104                 :            :   // up the map can fail with some meshes (only in parallel), e.g., tube.exo,
     105                 :            :   // used by some regression tests, due to the intel compiler generating some
     106                 :            :   // garbage incorrect code - only in debug, only in parallel, only with that
     107                 :            :   // mesh.
     108 [ +  - ][ -  + ]:       2576 :   Assert( tk::conforming( m_inpoel, m_coord ),
         [ -  - ][ -  - ]
                 [ -  - ]
     109                 :            :           "Input mesh to Discretization not conforming" );
     110                 :            :   #endif
     111                 :            : 
     112                 :            :   // Store node communication map
     113 [ +  - ][ +  - ]:      27504 :   for (const auto& [c,map] : nodeCommMap) m_nodeCommMap[c] = map;
                 [ +  + ]
     114                 :            : 
     115                 :            :   // Get ready for computing/communicating nodal volumes
     116         [ +  - ]:       2576 :   startvol();
     117                 :            : 
     118                 :            :   // Find host elements of user-specified points where time histories are
     119                 :            :   // saved, and save the shape functions evaluated at the point locations
     120                 :       2576 :   const auto& pt = g_cfg.get< tag::histout, tag::points >();
     121         [ +  + ]:       2816 :   for (std::size_t p=0; p<pt.size(); ++p) {
     122                 :            :     std::array< tk::real, 4 > N;
     123                 :        240 :     const auto& l = pt[p];
     124         [ +  + ]:     117607 :     for (std::size_t e=0; e<m_inpoel.size()/4; ++e) {
     125 [ +  - ][ +  + ]:     117442 :       if (tk::intet( m_coord, m_inpoel, l, e, N )) {
     126 [ +  - ][ +  - ]:         75 :         m_histdata.push_back( HistData{{ "p"+std::to_string(p+1), e, N }} );
                 [ +  - ]
     127                 :         75 :         break;
     128                 :            :       }
     129                 :            :     }
     130                 :            :   }
     131                 :            : 
     132                 :            :   // Register with mesh-transfer (if coupled)
     133         [ +  - ]:       2576 :   if (m_disc.size() == 1) {
     134         [ +  - ]:       2576 :     transfer_initialized();
     135                 :            :   } else {
     136         [ -  - ]:          0 :     if (thisIndex == 0) {
     137 [ -  - ][ -  - ]:          0 :       transfer::addMesh( thisProxy, m_nchare,
     138 [ -  - ][ -  - ]:          0 :         CkCallback(CkIndex_Discretization::transfer_initialized(), thisProxy) );
     139                 :            :     }
     140                 :            :   }
     141                 :       2576 : }
     142                 :            : 
     143                 :            : void
     144                 :       2576 : Discretization::transfer_initialized()
     145                 :            : // *****************************************************************************
     146                 :            : // Our mesh has been registered with the mesh-to-mesh transfer (if coupled)
     147                 :            : // *****************************************************************************
     148                 :            : {
     149                 :            :   // Compute number of mesh points owned
     150                 :       2576 :   std::size_t npoin = m_gid.size();
     151 [ +  - ][ +  + ]:     318543 :   for (auto g : m_gid) if (tk::slave( m_nodeCommMap, g, thisIndex ) ) --npoin;
                 [ +  + ]
     152                 :            : 
     153                 :            :   // Tell the RTS that the Discretization chares have been created and compute
     154                 :            :   // the total number of mesh points across the distributed mesh
     155         [ +  - ]:       2576 :   std::vector< std::size_t > meshdata{ m_meshid, npoin };
     156         [ +  - ]:       2576 :   contribute( meshdata, CkReduction::sum_ulong,
     157 [ +  - ][ +  - ]:       5152 :     CkCallback( CkReductionTarget(Transporter,disccreated), m_transporter ) );
     158                 :       2576 : }
     159                 :            : 
     160                 :            : void
     161                 :       9755 : Discretization::transfer( tk::Fields& u, CkCallback c, bool trflag )
     162                 :            : // *****************************************************************************
     163                 :            : // Initiate solution transfer from background to overset mesh (if coupled)
     164                 :            : // *****************************************************************************
     165                 :            : {
     166         [ +  - ]:       9755 :   if (m_disc.size() == 1) {     // not coupled
     167                 :            : 
     168                 :       9755 :     c.send();
     169                 :            : 
     170                 :            :   }
     171                 :            :   else {
     172                 :            : 
     173                 :          0 :     m_transfer_complete = c;
     174                 :          0 :     m_transfer_sol = static_cast< tk::Fields* >( &u );
     175                 :          0 :     m_trflag = trflag;
     176                 :            : 
     177                 :            :     // Initiate transfer in 'to' direction
     178         [ -  - ]:          0 :     if (!m_meshid) {
     179         [ -  - ]:          0 :       transfer::setSourceTets( thisProxy, thisIndex, m_inpoel, m_coord, u,
     180         [ -  - ]:          0 :         m_transfer_flag, /*transfer direction=*/ 0,
     181 [ -  - ][ -  - ]:          0 :         CkCallback( CkIndex_Discretization::transfer_from(),
     182         [ -  - ]:          0 :                     thisProxy[thisIndex] ) );
     183                 :            :     }
     184                 :            :     else {
     185         [ -  - ]:          0 :       transfer::setDestPoints( thisProxy, thisIndex, m_coord, u,
     186         [ -  - ]:          0 :         m_transfer_flag, m_trflag, /*transfer direction=*/ 0,
     187 [ -  - ][ -  - ]:          0 :         CkCallback( CkIndex_Discretization::transfer_from(),
     188         [ -  - ]:          0 :                     thisProxy[thisIndex] ) );
     189                 :            :     }
     190                 :            : 
     191                 :            :   }
     192                 :       9755 : }
     193                 :            : 
     194                 :            : void
     195                 :          0 : Discretization::transfer_from()
     196                 :            : // *****************************************************************************
     197                 :            : // Initiate solution transfer from overset to background mesh
     198                 :            : // *****************************************************************************
     199                 :            : {
     200         [ -  - ]:          0 :   if (!m_meshid) {
     201         [ -  - ]:          0 :     transfer::setDestPoints( thisProxy, thisIndex, m_coord, *m_transfer_sol,
     202                 :          0 :       m_transfer_flag, m_trflag, /*transfer direction=*/ 1,
     203         [ -  - ]:          0 :       m_transfer_complete );
     204                 :            :   }
     205                 :            :   else {
     206         [ -  - ]:          0 :     transfer::setSourceTets( thisProxy, thisIndex, m_inpoel, m_coord,
     207                 :          0 :       *m_transfer_sol, m_transfer_flag, /*transfer direction=*/ 1,
     208         [ -  - ]:          0 :       m_transfer_complete );
     209                 :            :   }
     210                 :          0 : }
     211                 :            : 
     212                 :            : void
     213                 :        385 : Discretization::intergrid(
     214                 :            :   const std::map< int, std::vector< std::size_t > >& bnode )
     215                 :            : // *****************************************************************************
     216                 :            : //  Prepare integrid-boundary data structures (if coupled)
     217                 :            : //! \param[in] bnode Boundary-node lists mapped to side sets used in input file
     218                 :            : // *****************************************************************************
     219                 :            : {
     220                 :        385 :   bool multi = g_cfg.get< tag::input >().size() > 1;
     221         [ +  - ]:        385 :   if (!multi) return;
     222         [ -  - ]:          0 :   m_transfer_flag.resize( m_coord[0].size(), -2.0 );
     223         [ -  - ]:          0 :   if (!m_meshid) return;
     224                 :            : 
     225                 :            :   // Access intergrid-boundary side set ids for this mesh
     226                 :          0 :   const auto& setids = g_cfg.get< tag::overset, tag::intergrid_ >()[ m_meshid ];
     227                 :            : 
     228                 :            :   // Compile unique set of intergrid-boundary side set ids for this mesh
     229         [ -  - ]:          0 :   std::unordered_set< std::size_t > ibs( begin(setids), end(setids) );
     230         [ -  - ]:          0 :   if (ibs.empty()) return;
     231                 :            : 
     232                 :            :   // Flag points on intergrid boundary
     233                 :          0 :   std::unordered_set< std::size_t > bp; // points flagged
     234         [ -  - ]:          0 :   for (const auto& [setid,n] : bnode) {
     235 [ -  - ][ -  - ]:          0 :     if (ibs.count( static_cast<std::size_t>(setid) )) {
     236         [ -  - ]:          0 :       for (auto g : n) {
     237         [ -  - ]:          0 :         auto i = tk::cref_find(m_lid,g);
     238                 :          0 :         m_transfer_flag[i] = 2.0;
     239         [ -  - ]:          0 :         bp.insert(i);
     240                 :            :       }
     241                 :            :     }
     242                 :            :   }
     243                 :            : 
     244                 :            :   // Configure number of layers
     245                 :          0 :   auto eps = std::numeric_limits< tk::real >::epsilon();
     246                 :          0 :   const auto& layers = g_cfg.get< tag::overset, tag::layers_ >()[ m_meshid ];
     247                 :          0 :   std::uint64_t ilays = 2;      // default number of inner layers
     248                 :          0 :   std::uint64_t mlays = 4;      // default number of middle layers
     249                 :          0 :   std::uint64_t olays = 2;      // default number of outer layers
     250         [ -  - ]:          0 :   if (layers.size() == 3) {
     251                 :          0 :     ilays = layers[0];
     252                 :          0 :     mlays = layers[1];
     253                 :          0 :     olays = layers[2];
     254                 :            :   }
     255                 :            : 
     256                 :            :   // Add some layers to intergrid boundary
     257 [ -  - ][ -  - ]:          0 :   auto psup = tk::genPsup( m_inpoel, 4, tk::genEsup( m_inpoel, 4 ) );
     258         [ -  - ]:          0 :   for (std::uint64_t n=0; n<ilays; ++n) {
     259                 :          0 :     std::unordered_set< std::size_t > add;
     260         [ -  - ]:          0 :     for (auto p : bp) {
     261         [ -  - ]:          0 :       for (auto q : tk::Around(psup,p)) {
     262         [ -  - ]:          0 :         if (std::abs(m_transfer_flag[q]+2.0) < eps) m_transfer_flag[q] = 1.0;
     263         [ -  - ]:          0 :         add.insert(q);
     264                 :            :       }
     265                 :            :     }
     266         [ -  - ]:          0 :     bp.merge( add );
     267                 :          0 :     add.clear();
     268                 :          0 :   }
     269                 :            : 
     270                 :            :   // Mark middle layers for buffering / relaxation
     271         [ -  - ]:          0 :   for (std::uint64_t n=0; n<mlays; ++n) {
     272                 :          0 :     std::unordered_set< std::size_t > add;
     273         [ -  - ]:          0 :     for (auto p : bp) {
     274         [ -  - ]:          0 :       for (auto q : tk::Around(psup,p)) {
     275         [ -  - ]:          0 :         if (std::abs(m_transfer_flag[q]+2.0) < eps) m_transfer_flag[q] = -1.0;
     276         [ -  - ]:          0 :         add.insert(q);
     277                 :            :       }
     278                 :            :     }
     279         [ -  - ]:          0 :     bp.merge( add );
     280                 :          0 :     add.clear();
     281                 :          0 :   }
     282                 :            : 
     283                 :            :   // Mark outer layers for solution transfer from background to overset
     284         [ -  - ]:          0 :   for (std::uint64_t n=0; n<olays; ++n) {
     285                 :          0 :     std::unordered_set< std::size_t > add;
     286         [ -  - ]:          0 :     for (auto p : bp) {
     287         [ -  - ]:          0 :       for (auto q : tk::Around(psup,p)) {
     288         [ -  - ]:          0 :         if (std::abs(m_transfer_flag[q]+2.0) < eps) m_transfer_flag[q] = 0.0;
     289         [ -  - ]:          0 :         add.insert(q);
     290                 :            :       }
     291                 :            :     }
     292         [ -  - ]:          0 :     bp.merge( add );
     293                 :          0 :     add.clear();
     294                 :          0 :   }
     295         [ -  - ]:          0 : }
     296                 :            : 
     297                 :            : void
     298                 :        385 : Discretization::hole(
     299                 :            :   const std::map< int, std::vector< std::size_t > >& bface,
     300                 :            :   const std::vector< std::size_t >& triinpoel,
     301                 :            :   CkCallback c )
     302                 :            : // *****************************************************************************
     303                 :            : //  Prepare integrid-boundary data structures (if coupled)
     304                 :            : //! \param[in] bface Boundary-face lists mapped to side sets used in input file
     305                 :            : //! \param[in] triinpoel Boundary-face connectivity (local ids)
     306                 :            : //! \param[in] c Call to continue with when done
     307                 :            : // *****************************************************************************
     308                 :            : {
     309                 :        385 :   bool multi = g_cfg.get< tag::input >().size() > 1;
     310 [ +  - ][ +  - ]:        385 :   if (!multi) { c.send(); return; }
     311                 :            : 
     312                 :          0 :   m_holcont = c;
     313                 :            : 
     314                 :          0 :   std::unordered_map< std::size_t, std::vector< tk::real > > hol;
     315                 :            : 
     316         [ -  - ]:          0 :   if (m_meshid) {
     317                 :            :     // Access intergrid-boundary side set ids for this mesh
     318                 :          0 :     const auto& setids = g_cfg.get< tag::overset, tag::intergrid_ >()[m_meshid];
     319                 :            :     // Compile unique set of intergrid-boundary side set ids for this mesh
     320         [ -  - ]:          0 :     std::unordered_set< std::size_t > ibs( begin(setids), end(setids) );
     321                 :            : 
     322                 :          0 :     const auto& x = m_coord[0];
     323                 :          0 :     const auto& y = m_coord[1];
     324                 :          0 :     const auto& z = m_coord[2];
     325                 :            : 
     326                 :            :     // Collect faces on intergrid boundary
     327         [ -  - ]:          0 :     auto& h = hol[0];   // a single hole for now (given by multiple side sets)
     328         [ -  - ]:          0 :     for (const auto& [setid,faceids] : bface) {
     329 [ -  - ][ -  - ]:          0 :       if (ibs.count( static_cast<std::size_t>(setid) )) {
     330         [ -  - ]:          0 :         for (auto f : faceids) {
     331                 :          0 :           const auto t = triinpoel.data() + f*3;
     332         [ -  - ]:          0 :           h.push_back( x[t[0]] );
     333         [ -  - ]:          0 :           h.push_back( y[t[0]] );
     334         [ -  - ]:          0 :           h.push_back( z[t[0]] );
     335         [ -  - ]:          0 :           h.push_back( x[t[1]] );
     336         [ -  - ]:          0 :           h.push_back( y[t[1]] );
     337         [ -  - ]:          0 :           h.push_back( z[t[1]] );
     338         [ -  - ]:          0 :           h.push_back( x[t[2]] );
     339         [ -  - ]:          0 :           h.push_back( y[t[2]] );
     340         [ -  - ]:          0 :           h.push_back( z[t[2]] );
     341                 :            :         }
     342                 :            :       }
     343                 :            :     }
     344                 :            : 
     345                 :            :     // overset mesh sends hole-parts to background mesh for assembly
     346                 :            :     // (allreduce to all partitions of mesh 0)
     347         [ -  - ]:          0 :     auto stream = serialize( hol );
     348         [ -  - ]:          0 :     contribute( stream.first, stream.second.get(), HoleMerger,
     349 [ -  - ][ -  - ]:          0 :      CkCallback(CkIndex_Discretization::aggregateHoles(nullptr), m_disc[0]) );
     350                 :          0 :   }
     351                 :          0 : }
     352                 :            : 
     353                 :            : void
     354                 :          0 : Discretization::aggregateHoles( CkReductionMsg* msg )
     355                 :            : // *****************************************************************************
     356                 :            : //  Receive hole data from other meshes
     357                 :            : //! \param[in] msg Aggregated hole data
     358                 :            : //! \note Only background mesh (mesh 0) is supposed to call this.
     359                 :            : // *****************************************************************************
     360                 :            : {
     361                 :          0 :   std::unordered_map< std::size_t, std::vector< tk::real > > inhol;
     362                 :            : 
     363                 :          0 :   PUP::fromMem creator( msg->getData() );
     364         [ -  - ]:          0 :   creator | inhol;
     365 [ -  - ][ -  - ]:          0 :   delete msg;
     366                 :            : 
     367         [ -  - ]:          0 :   for (auto&& [hid,data] : inhol) {
     368         [ -  - ]:          0 :     auto& hole = m_transfer_hole[ hid ];
     369 [ -  - ][ -  - ]:          0 :     std::move( begin(data), end(data), std::back_inserter(hole) );
     370                 :            :   }
     371                 :            : 
     372                 :            :   // back to sender overset mesh so it can continue (enough to this partition)
     373 [ -  - ][ -  - ]:          0 :   m_disc[ 1 ][ thisIndex ].holeComplete();
     374                 :            : 
     375                 :            :   // background mesh also complete
     376         [ -  - ]:          0 :   m_holcont.send();
     377                 :          0 : }
     378                 :            : 
     379                 :            : void
     380                 :          0 : Discretization::holeComplete()
     381                 :            : // *****************************************************************************
     382                 :            : // Hole communication complete
     383                 :            : // *****************************************************************************
     384                 :            : {
     385                 :          0 :   m_holcont.send();
     386                 :          0 : }
     387                 :            : 
     388                 :            : void
     389                 :        385 : Discretization::holefind()
     390                 :            : // *****************************************************************************
     391                 :            : // Find mesh nodes within holes
     392                 :            : // *****************************************************************************
     393                 :            : {
     394                 :        385 :   bool multi = g_cfg.get< tag::input >().size() > 1;
     395         [ +  - ]:        385 :   if (!multi) return;
     396 [ -  - ][ -  - ]:          0 :   if (m_meshid or m_transfer_hole.empty()) return;
                 [ -  - ]
     397                 :            : 
     398                 :            :   // account for hole symmetry if specified
     399                 :          0 :   const auto& sym = g_cfg.get< tag::overset, tag::sym_ >()[ 1 ];
     400                 :            : 
     401                 :            :   // collect face centers and normals for hole surface
     402                 :          0 :   std::vector< tk::real > face;
     403         [ -  - ]:          0 :   for (const auto& [hid,tricoord] : m_transfer_hole) { // for each hole
     404         [ -  - ]:          0 :     for (std::size_t t=0; t<tricoord.size()/9; ++t) {  // each hole triangle
     405                 :          0 :       const auto f = tricoord.data() + t*9;
     406                 :          0 :       auto x0 = f[0];
     407                 :          0 :       auto y0 = f[1];
     408                 :          0 :       auto z0 = f[2];
     409                 :          0 :       auto x1 = f[3];
     410                 :          0 :       auto y1 = f[4];
     411                 :          0 :       auto z1 = f[5];
     412                 :          0 :       auto x2 = f[6];
     413                 :          0 :       auto y2 = f[7];
     414                 :          0 :       auto z2 = f[8];
     415                 :          0 :       auto cx = (x0 + x1 + x2) / 3.0;
     416                 :          0 :       auto cy = (y0 + y1 + y2) / 3.0;
     417                 :          0 :       auto cz = (z0 + z1 + z2) / 3.0;
     418                 :            :       const std::array< tk::real, 3 >
     419                 :          0 :         ba{ x1-x0, y1-y0, z1-z0 }, ca{ x2-x0, y2-y0, z2-z0 };
     420                 :          0 :       auto [nx,ny,nz] = tk::cross( ba, ca );
     421                 :          0 :       nx /= -2.0;
     422                 :          0 :       ny /= -2.0;
     423                 :          0 :       nz /= -2.0;
     424         [ -  - ]:          0 :       face.push_back( cx );
     425         [ -  - ]:          0 :       face.push_back( cy );
     426         [ -  - ]:          0 :       face.push_back( cz );
     427         [ -  - ]:          0 :       face.push_back( nx );
     428         [ -  - ]:          0 :       face.push_back( ny );
     429         [ -  - ]:          0 :       face.push_back( nz );
     430         [ -  - ]:          0 :       if (sym == "z") {         // augment hole with symmetric part
     431         [ -  - ]:          0 :         face.push_back( cx );
     432         [ -  - ]:          0 :         face.push_back( cy );
     433         [ -  - ]:          0 :         face.push_back( -cz );
     434         [ -  - ]:          0 :         face.push_back( nx );
     435         [ -  - ]:          0 :         face.push_back( ny );
     436         [ -  - ]:          0 :         face.push_back( -nz );
     437                 :            :       }
     438                 :            :     }
     439                 :            :   }
     440                 :            : 
     441                 :          0 :   const auto& x = m_coord[0];
     442                 :          0 :   const auto& y = m_coord[1];
     443                 :          0 :   const auto& z = m_coord[2];
     444                 :          0 :   auto npoin = x.size();
     445                 :            : 
     446                 :            :   // compute integral for finding hole nodes on background mesh
     447                 :          0 :   auto inteps = 1.0;
     448                 :          0 :   auto intval = 4.0 * M_PI;
     449                 :          0 :   std::unordered_set< std::size_t > hp; // hole points
     450         [ -  - ]:          0 :   for (std::size_t i=0; i<npoin; ++i) {
     451                 :          0 :     tk::real holeint = 0.0;
     452         [ -  - ]:          0 :     for (std::size_t t=0; t<face.size()/6; ++t) {
     453                 :          0 :       const auto f = face.data() + t*6;
     454                 :          0 :       auto dx = f[0] - x[i];
     455                 :          0 :       auto dy = f[1] - y[i];
     456                 :          0 :       auto dz = f[2] - z[i];
     457                 :          0 :       auto r = std::pow( dx*dx + dy*dy + dz*dz, 1.5 );
     458                 :          0 :       auto vx = dx / r;
     459                 :          0 :       auto vy = dy / r;
     460                 :          0 :       auto vz = dz / r;
     461                 :          0 :       holeint += vx*f[3] + vy*f[4] + vz*f[5];
     462                 :            :     }
     463         [ -  - ]:          0 :     if (std::abs(holeint - intval) < inteps) {
     464                 :          0 :       m_transfer_flag[i] = 2.0;
     465         [ -  - ]:          0 :       hp.insert(i);
     466                 :            :     }
     467                 :            :   }
     468                 :            : 
     469                 :            :   // grow hole by one extra layer
     470 [ -  - ][ -  - ]:          0 :   auto psup = tk::genPsup( m_inpoel, 4, tk::genEsup( m_inpoel, 4 ) );
     471                 :          0 :   auto eps = std::numeric_limits< tk::real >::epsilon();
     472         [ -  - ]:          0 :   for (auto p : hp) {
     473         [ -  - ]:          0 :     for (auto q : tk::Around(psup,p)) {
     474         [ -  - ]:          0 :       if (std::abs(m_transfer_flag[q]+2.0) < eps) m_transfer_flag[q] = 2.0;
     475                 :            :     }
     476                 :            :   }
     477                 :          0 : }
     478                 :            : 
     479                 :            : void
     480                 :          0 : Discretization::resizePostAMR(
     481                 :            :   const tk::UnsMesh::Chunk& chunk,
     482                 :            :   const tk::UnsMesh::Coords& coord,
     483                 :            :   const std::unordered_map< int, std::unordered_set< std::size_t > >&
     484                 :            :     nodeCommMap,
     485                 :            :   const std::set< std::size_t >& /*removedNodes*/ )
     486                 :            : // *****************************************************************************
     487                 :            : //  Resize mesh data structures after mesh refinement
     488                 :            : //! \param[in] chunk New mesh chunk (connectivity and global<->local id maps)
     489                 :            : //! \param[in] coord New mesh node coordinates
     490                 :            : //! \param[in] nodeCommMap New node communication map
     491                 :            : //! \param[in] removedNodes Newly removed mesh node local ids
     492                 :            : // *****************************************************************************
     493                 :            : {
     494                 :          0 :   m_el = chunk;                 // updates m_inpoel, m_gid, m_lid
     495                 :          0 :   m_nodeCommMap = nodeCommMap;
     496                 :            : 
     497                 :            :   // Update mesh volume container size
     498         [ -  - ]:          0 :   m_vol.resize( m_gid.size(), 0.0 );
     499                 :            : 
     500                 :            :   // update mesh node coordinates
     501                 :          0 :   m_coord = coord;
     502                 :          0 : }
     503                 :            : 
     504                 :            : void
     505                 :       2576 : Discretization::startvol()
     506                 :            : // *****************************************************************************
     507                 :            : //  Get ready for (re-)computing/communicating nodal volumes
     508                 :            : // *****************************************************************************
     509                 :            : {
     510                 :       2576 :   m_nvol = 0;
     511 [ +  - ][ +  - ]:       2576 :   thisProxy[ thisIndex ].wait4vol();
     512                 :            : 
     513                 :            :   // Zero out mesh volume container
     514         [ +  - ]:       2576 :   std::fill( begin(m_vol), end(m_vol), 0.0 );
     515                 :            : 
     516                 :            :   // Clear receive buffer that will be used for collecting nodal volumes
     517                 :       2576 :   m_volc.clear();
     518                 :       2576 : }
     519                 :            : 
     520                 :            : void
     521                 :        804 : Discretization::registerReducers()
     522                 :            : // *****************************************************************************
     523                 :            : //  Configure Charm++ reduction types
     524                 :            : //!  \details Since this is a [initnode] routine, see the .ci file, the
     525                 :            : //!   Charm++ runtime system executes the routine exactly once on every
     526                 :            : //!   logical node early on in the Charm++ init sequence. Must be static as
     527                 :            : //!   it is called without an object. See also: Section "Initializations at
     528                 :            : //!   Program Startup" at in the Charm++ manual
     529                 :            : //!   http://charm.cs.illinois.edu/manuals/html/charm++/manual.html.
     530                 :            : // *****************************************************************************
     531                 :            : {
     532                 :        804 :   PDFMerger = CkReduction::addReducer( tk::mergeUniPDFs );
     533                 :        804 :   HoleMerger = CkReduction::addReducer( mergeHole );
     534                 :        804 : }
     535                 :            : 
     536                 :            : tk::UnsMesh::Coords
     537                 :       2576 : Discretization::setCoord( const tk::UnsMesh::CoordMap& coordmap )
     538                 :            : // *****************************************************************************
     539                 :            : // Set mesh coordinates based on coordinates map
     540                 :            : // *****************************************************************************
     541                 :            : {
     542 [ -  + ][ -  - ]:       2576 :   Assert( coordmap.size() == m_gid.size(), "Size mismatch" );
         [ -  - ][ -  - ]
     543 [ -  + ][ -  - ]:       2576 :   Assert( coordmap.size() == m_lid.size(), "Size mismatch" );
         [ -  - ][ -  - ]
     544                 :            : 
     545                 :       2576 :   tk::UnsMesh::Coords coord;
     546         [ +  - ]:       2576 :   coord[0].resize( coordmap.size() );
     547         [ +  - ]:       2576 :   coord[1].resize( coordmap.size() );
     548         [ +  - ]:       2576 :   coord[2].resize( coordmap.size() );
     549                 :            : 
     550         [ +  + ]:     318543 :   for (const auto& [ gid, coords ] : coordmap) {
     551         [ +  - ]:     315967 :     auto i = tk::cref_find( m_lid, gid );
     552                 :     315967 :     coord[0][i] = coords[0];
     553                 :     315967 :     coord[1][i] = coords[1];
     554                 :     315967 :     coord[2][i] = coords[2];
     555                 :            :   }
     556                 :            : 
     557                 :       2576 :   return coord;
     558                 :          0 : }
     559                 :            : 
     560                 :            : void
     561                 :       1682 : Discretization::remap(
     562                 :            :   const std::unordered_map< std::size_t, std::size_t >& map )
     563                 :            : // *****************************************************************************
     564                 :            : //  Remap mesh data based on new local ids
     565                 :            : //! \param[in] map Mapping of old->new local ids
     566                 :            : // *****************************************************************************
     567                 :            : {
     568                 :            :   // Remap connectivity containing local IDs
     569 [ +  - ][ +  + ]:    2787754 :   for (auto& l : m_inpoel) l = tk::cref_find(map,l);
     570                 :            : 
     571                 :            :   // Remap global->local id map
     572 [ +  - ][ +  + ]:     200013 :   for (auto& [g,l] : m_lid) l = tk::cref_find(map,l);
     573                 :            : 
     574                 :            :   // Remap global->local id map
     575                 :       1682 :   auto maxid = std::numeric_limits< std::size_t >::max();
     576         [ +  - ]:       1682 :   std::vector< std::size_t > newgid( m_gid.size(), maxid );
     577         [ +  + ]:     200013 :   for (const auto& [o,n] : map) newgid[n] = m_gid[o];
     578                 :       1682 :   m_gid = std::move( newgid );
     579                 :            : 
     580 [ +  - ][ -  + ]:     200013 :   Assert( std::all_of( m_gid.cbegin(), m_gid.cend(),
         [ -  - ][ -  - ]
                 [ -  - ]
     581                 :            :             [=](std::size_t i){ return i < maxid; } ),
     582                 :            :           "Not all gid have been remapped" );
     583                 :            : 
     584                 :            :   // Remap nodal volumes (with contributions along chare-boundaries)
     585         [ +  - ]:       1682 :   std::vector< tk::real > newvol( m_vol.size(), 0.0 );
     586         [ +  + ]:     200013 :   for (const auto& [o,n] : map) newvol[n] = m_vol[o];
     587                 :       1682 :   m_vol = std::move( newvol );
     588                 :            : 
     589                 :            :   // Remap nodal volumes (without contributions along chare-boundaries)
     590         [ +  - ]:       1682 :   std::vector< tk::real > newv( m_v.size(), 0.0 );
     591         [ +  + ]:     200013 :   for (const auto& [o,n] : map) newv[n] = m_v[o];
     592                 :       1682 :   m_v = std::move( newv );
     593                 :            : 
     594                 :            :   // Remap locations of node coordinates
     595                 :       1682 :   tk::UnsMesh::Coords newcoord;
     596                 :       1682 :   auto npoin = m_coord[0].size();
     597         [ +  - ]:       1682 :   newcoord[0].resize( npoin );
     598         [ +  - ]:       1682 :   newcoord[1].resize( npoin );
     599         [ +  - ]:       1682 :   newcoord[2].resize( npoin );
     600         [ +  + ]:     200013 :   for (const auto& [o,n] : map) {
     601                 :     198331 :     newcoord[0][n] = m_coord[0][o];
     602                 :     198331 :     newcoord[1][n] = m_coord[1][o];
     603                 :     198331 :     newcoord[2][n] = m_coord[2][o];
     604                 :            :   }
     605                 :       1682 :   m_coord = std::move( newcoord );
     606                 :       1682 : }
     607                 :            : 
     608                 :            : void
     609                 :       2576 : Discretization::setRefiner( const CProxy_Refiner& ref )
     610                 :            : // *****************************************************************************
     611                 :            : //  Set Refiner Charm++ proxy
     612                 :            : //! \param[in] ref Incoming refiner proxy to store
     613                 :            : // *****************************************************************************
     614                 :            : {
     615                 :       2576 :   m_refiner = ref;
     616                 :       2576 : }
     617                 :            : 
     618                 :            : void
     619                 :       2576 : Discretization::vol()
     620                 :            : // *****************************************************************************
     621                 :            : // Sum mesh volumes to nodes, start communicating them on chare-boundaries
     622                 :            : // *****************************************************************************
     623                 :            : {
     624                 :       2576 :   const auto& x = m_coord[0];
     625                 :       2576 :   const auto& y = m_coord[1];
     626                 :       2576 :   const auto& z = m_coord[2];
     627                 :            : 
     628                 :            :   // Compute nodal volumes on our chunk of the mesh
     629         [ +  + ]:    1138146 :   for (std::size_t e=0; e<m_inpoel.size()/4; ++e) {
     630                 :    1135570 :     const auto N = m_inpoel.data() + e*4;
     631                 :            :     const std::array< tk::real, 3 >
     632                 :    1135570 :       ba{{ x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]] }},
     633                 :    1135570 :       ca{{ x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]] }},
     634                 :    1135570 :       da{{ x[N[3]]-x[N[0]], y[N[3]]-y[N[0]], z[N[3]]-z[N[0]] }};
     635                 :    1135570 :     const auto J = tk::triple( ba, ca, da ) / 24.0;
     636 [ -  + ][ -  - ]:    1135570 :     ErrChk( J > 0, "Element Jacobian non-positive: PE:" +
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
                 [ -  - ]
     637                 :            :                    std::to_string(CkMyPe()) + ", node IDs: " +
     638                 :            :                    std::to_string(m_gid[N[0]]) + ',' +
     639                 :            :                    std::to_string(m_gid[N[1]]) + ',' +
     640                 :            :                    std::to_string(m_gid[N[2]]) + ',' +
     641                 :            :                    std::to_string(m_gid[N[3]]) + ", coords: (" +
     642                 :            :                    std::to_string(x[N[0]]) + ", " +
     643                 :            :                    std::to_string(y[N[0]]) + ", " +
     644                 :            :                    std::to_string(z[N[0]]) + "), (" +
     645                 :            :                    std::to_string(x[N[1]]) + ", " +
     646                 :            :                    std::to_string(y[N[1]]) + ", " +
     647                 :            :                    std::to_string(z[N[1]]) + "), (" +
     648                 :            :                    std::to_string(x[N[2]]) + ", " +
     649                 :            :                    std::to_string(y[N[2]]) + ", " +
     650                 :            :                    std::to_string(z[N[2]]) + "), (" +
     651                 :            :                    std::to_string(x[N[3]]) + ", " +
     652                 :            :                    std::to_string(y[N[3]]) + ", " +
     653                 :            :                    std::to_string(z[N[3]]) + ')' );
     654                 :            :     // scatter add V/4 to nodes
     655         [ +  + ]:    5677850 :     for (std::size_t j=0; j<4; ++j) m_vol[N[j]] += J;
     656                 :            :   }
     657                 :            : 
     658                 :            :   // Store nodal volumes without contributions from other chares on
     659                 :            :   // chare-boundaries
     660                 :       2576 :   m_v = m_vol;
     661                 :            : 
     662                 :            :   // Send our nodal volume contributions to neighbor chares
     663         [ +  + ]:       2576 :   if (m_nodeCommMap.empty()) {
     664                 :         78 :     comvol_complete();
     665                 :            :   } else {
     666         [ +  + ]:      27426 :     for (const auto& [c,n] : m_nodeCommMap) {
     667         [ +  - ]:      24928 :       std::vector< tk::real > v( n.size() );
     668                 :      24928 :       std::size_t j = 0;
     669 [ +  - ][ +  + ]:     176660 :       for (auto i : n) v[ j++ ] = m_vol[ tk::cref_find(m_lid,i) ];
     670 [ +  - ][ +  - ]:      49856 :       thisProxy[c].comvol( thisIndex,
     671         [ +  - ]:      49856 :                            std::vector<std::size_t>(begin(n), end(n)), v );
     672                 :      24928 :     }
     673                 :            :   }
     674                 :            : 
     675                 :       2576 :   ownvol_complete();
     676                 :       2576 : }
     677                 :            : 
     678                 :            : void
     679                 :      24928 : Discretization::comvol( int c,
     680                 :            :                         const std::vector< std::size_t >& gid,
     681                 :            :                         const std::vector< tk::real >& nodevol )
     682                 :            : // *****************************************************************************
     683                 :            : //  Receive nodal volumes on chare-boundaries
     684                 :            : //! \param[in] c Sender chare id
     685                 :            : //! \param[in] gid Global mesh node IDs at which we receive volume contributions
     686                 :            : //! \param[in] nodevol Partial sums of nodal volume contributions to
     687                 :            : //!    chare-boundary nodes
     688                 :            : // *****************************************************************************
     689                 :            : {
     690 [ -  + ][ -  - ]:      24928 :   Assert( nodevol.size() == gid.size(), "Size mismatch" );
         [ -  - ][ -  - ]
     691                 :            : 
     692                 :      24928 :   auto& cvolc = m_cvolc[c];
     693         [ +  + ]:     176660 :   for (std::size_t i=0; i<gid.size(); ++i) {
     694                 :     151732 :     m_volc[ gid[i] ] += nodevol[i];
     695                 :     151732 :     cvolc[ tk::cref_find(m_lid,gid[i]) ] = nodevol[i];
     696                 :            :   }
     697                 :            : 
     698         [ +  + ]:      24928 :   if (++m_nvol == m_nodeCommMap.size()) {
     699                 :       2498 :     m_nvol = 0;
     700                 :       2498 :     comvol_complete();
     701                 :            :   }
     702                 :      24928 : }
     703                 :            : 
     704                 :            : void
     705                 :       2576 : Discretization::totalvol()
     706                 :            : // *****************************************************************************
     707                 :            : // Sum mesh volumes and contribute own mesh volume to total volume
     708                 :            : // *****************************************************************************
     709                 :            : {
     710                 :            :   // Add received contributions to nodal volumes
     711         [ +  + ]:      93337 :   for (const auto& [gid, vol] : m_volc)
     712         [ +  - ]:      90761 :     m_vol[ tk::cref_find(m_lid,gid) ] += vol;
     713                 :            : 
     714                 :            :   // Clear receive buffer
     715                 :       2576 :   tk::destroy(m_volc);
     716                 :            : 
     717                 :            :   // Sum mesh volume to host
     718                 :            :   std::vector< tk::real > tvol{ 0.0,
     719                 :       2576 :                                 static_cast<tk::real>(m_initial),
     720         [ +  - ]:       2576 :                                 static_cast<tk::real>(m_meshid) };
     721         [ +  + ]:     318543 :   for (auto v : m_v) tvol[0] += v;
     722         [ +  - ]:       2576 :   contribute( tvol, CkReduction::sum_double,
     723 [ +  - ][ +  - ]:       5152 :     CkCallback(CkReductionTarget(Transporter,totalvol), m_transporter) );
     724                 :       2576 : }
     725                 :            : 
     726                 :            : void
     727                 :       2576 : Discretization::stat( tk::real mesh_volume )
     728                 :            : // *****************************************************************************
     729                 :            : // Compute mesh cell statistics
     730                 :            : //! \param[in] mesh_volume Total mesh volume
     731                 :            : // *****************************************************************************
     732                 :            : {
     733                 :            :   // Store total mesh volume
     734                 :       2576 :   m_meshvol = mesh_volume;
     735                 :            : 
     736                 :       2576 :   const auto& x = m_coord[0];
     737                 :       2576 :   const auto& y = m_coord[1];
     738                 :       2576 :   const auto& z = m_coord[2];
     739                 :            : 
     740                 :       2576 :   auto MIN = -std::numeric_limits< tk::real >::max();
     741                 :       2576 :   auto MAX = std::numeric_limits< tk::real >::max();
     742         [ +  - ]:       2576 :   std::vector< tk::real > min( 6, MAX );
     743         [ +  - ]:       2576 :   std::vector< tk::real > max( 6, MIN );
     744         [ +  - ]:       2576 :   std::vector< tk::real > sum( 9, 0.0 );
     745                 :       2576 :   tk::UniPDF edgePDF( 1e-4 );
     746                 :       2576 :   tk::UniPDF volPDF( 1e-4 );
     747                 :       2576 :   tk::UniPDF ntetPDF( 1e-4 );
     748                 :            : 
     749                 :            :   // Compute points surrounding points
     750 [ +  - ][ +  - ]:       2576 :   auto psup = tk::genPsup( m_inpoel, 4, tk::genEsup(m_inpoel,4) );
     751 [ -  + ][ -  - ]:       2576 :   Assert( psup.second.size()-1 == m_gid.size(),
         [ -  - ][ -  - ]
     752                 :            :           "Number of mesh points and number of global IDs unequal" );
     753                 :            : 
     754                 :            :   // Compute edge length statistics
     755                 :            :   // Note that while the min and max edge lengths are independent of the number
     756                 :            :   // of CPUs (by the time they are aggregated across all chares), the sum of
     757                 :            :   // the edge lengths and the edge length PDF are not. This is because the
     758                 :            :   // edges on the chare-boundary are counted multiple times and we
     759                 :            :   // conscientiously do not make an effort to precisely compute this, because
     760                 :            :   // that would require communication and more complex logic. Since these
     761                 :            :   // statistics are intended as simple average diagnostics, we ignore these
     762                 :            :   // small differences. For reproducible average edge lengths and edge length
     763                 :            :   // PDFs, run the mesh in serial.
     764                 :       2576 :   tk::UnsMesh::EdgeSet edges;
     765         [ +  + ]:     318543 :   for (std::size_t p=0; p<m_gid.size(); ++p) {
     766         [ +  + ]:    3620953 :     for (auto i : tk::Around(psup,p)) {
     767                 :    3304986 :        const auto dx = x[ i ] - x[ p ];
     768                 :    3304986 :        const auto dy = y[ i ] - y[ p ];
     769                 :    3304986 :        const auto dz = z[ i ] - z[ p ];
     770                 :    3304986 :        const auto length = std::sqrt( dx*dx + dy*dy + dz*dz );
     771         [ +  + ]:    3304986 :        if (length < min[0]) min[0] = length;
     772         [ +  + ]:    3304986 :        if (length > max[0]) max[0] = length;
     773                 :    3304986 :        sum[0] += 1.0;
     774                 :    3304986 :        sum[1] += length;
     775         [ +  - ]:    3304986 :        edgePDF.add( length );
     776         [ +  - ]:    3304986 :        edges.insert( { m_gid[i], m_gid[p] } );
     777                 :            :     }
     778                 :            :   }
     779                 :            : 
     780                 :            :   // Compute mesh cell volume statistics
     781         [ +  + ]:    1138146 :   for (std::size_t e=0; e<m_inpoel.size()/4; ++e) {
     782                 :    1135570 :     const std::array< std::size_t, 4 > N{{ m_inpoel[e*4+0], m_inpoel[e*4+1],
     783                 :    1135570 :                                            m_inpoel[e*4+2], m_inpoel[e*4+3] }};
     784                 :            :     const std::array< tk::real, 3 >
     785                 :    1135570 :       ba{{ x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]] }},
     786                 :    1135570 :       ca{{ x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]] }},
     787                 :    1135570 :       da{{ x[N[3]]-x[N[0]], y[N[3]]-y[N[0]], z[N[3]]-z[N[0]] }};
     788                 :    1135570 :     const auto L = std::cbrt( tk::triple( ba, ca, da ) / 6.0 );
     789         [ +  + ]:    1135570 :     if (L < min[1]) min[1] = L;
     790         [ +  + ]:    1135570 :     if (L > max[1]) max[1] = L;
     791                 :    1135570 :     sum[2] += 1.0;
     792                 :    1135570 :     sum[3] += L;
     793         [ +  - ]:    1135570 :     volPDF.add( L );
     794                 :            :   }
     795                 :            : 
     796                 :            :   // Contribute statistics
     797                 :       2576 :   sum[4] = 1.0;
     798                 :       2576 :   min[2] = max[2] = sum[5] = static_cast< tk::real >( m_inpoel.size() / 4 );
     799                 :       2576 :   min[3] = max[3] = sum[6] = static_cast< tk::real >( m_gid.size() );
     800                 :       2576 :   min[4] = max[4] = sum[7] = static_cast< tk::real >( edges.size() );
     801                 :       2576 :   min[5] = max[5] = sum[8] =
     802                 :       2576 :     static_cast< tk::real >( tk::sumvalsize(m_nodeCommMap) ) /
     803                 :       2576 :     static_cast< tk::real >( m_gid.size() );
     804         [ +  - ]:       2576 :   ntetPDF.add( min[2] );
     805                 :            : 
     806         [ +  - ]:       2576 :   min.push_back( static_cast<tk::real>(m_meshid) );
     807         [ +  - ]:       2576 :   max.push_back( static_cast<tk::real>(m_meshid) );
     808         [ +  - ]:       2576 :   sum.push_back( static_cast<tk::real>(m_meshid) );
     809                 :            : 
     810                 :            :   // Contribute to mesh statistics across all Discretization chares
     811         [ +  - ]:       2576 :   contribute( min, CkReduction::min_double,
     812 [ +  - ][ +  - ]:       5152 :     CkCallback(CkReductionTarget(Transporter,minstat), m_transporter) );
     813         [ +  - ]:       2576 :   contribute( max, CkReduction::max_double,
     814 [ +  - ][ +  - ]:       5152 :     CkCallback(CkReductionTarget(Transporter,maxstat), m_transporter) );
     815         [ +  - ]:       2576 :   contribute( sum, CkReduction::sum_double,
     816 [ +  - ][ +  - ]:       5152 :     CkCallback(CkReductionTarget(Transporter,sumstat), m_transporter) );
     817                 :            : 
     818                 :            :   // Serialize PDFs to raw stream
     819 [ +  - ][ +  - ]:      10304 :   auto stream = tk::serialize( m_meshid, { edgePDF, volPDF, ntetPDF } );
         [ +  + ][ -  - ]
     820                 :            :   // Create Charm++ callback function for reduction of PDFs with
     821                 :            :   // Transporter::pdfstat() as the final target where the results will appear.
     822 [ +  - ][ +  - ]:       2576 :   CkCallback cb( CkIndex_Transporter::pdfstat(nullptr), m_transporter );
     823                 :            :   // Contribute serialized PDF of partial sums to host via Charm++ reduction
     824         [ +  - ]:       2576 :   contribute( stream.first, stream.second.get(), PDFMerger, cb );
     825 [ +  - ][ +  - ]:       5152 : }
         [ +  - ][ -  - ]
                 [ -  - ]
     826                 :            : 
     827                 :            : void
     828                 :       2576 : Discretization::boxvol()
     829                 :            : // *****************************************************************************
     830                 :            : // Compute total box IC volume
     831                 :            : // *****************************************************************************
     832                 :            : {
     833                 :            :   // Determine which nodes reside in user-defined IC box(es) if any
     834         [ +  - ]:       2576 :   m_boxnodes = problems::boxnodes( m_coord );
     835                 :            : 
     836                 :            :   // Compute partial box IC volume (just add up all boxes)
     837                 :       2576 :   tk::real boxvol = 0.0;
     838                 :            :   // cppcheck-suppress useStlAlgorithm
     839 [ +  + ][ +  + ]:       4055 :   for (const auto& b : m_boxnodes) for (auto i : b) boxvol += m_v[i];
     840                 :            : 
     841                 :            :   // Sum up box IC volume across all chares
     842         [ +  - ]:       2576 :   std::vector< tk::real > meshdata{ boxvol, static_cast<tk::real>(m_meshid) };
     843         [ +  - ]:       2576 :   contribute( meshdata, CkReduction::sum_double,
     844 [ +  - ][ +  - ]:       5152 :     CkCallback(CkReductionTarget(Transporter,boxvol), m_transporter) );
     845                 :       2576 : }
     846                 :            : 
     847                 :            : void
     848                 :       3547 : Discretization::write(
     849                 :            :   const std::vector< std::size_t >& inpoel,
     850                 :            :   const tk::UnsMesh::Coords& coord,
     851                 :            :   const std::map< int, std::vector< std::size_t > >& bface,
     852                 :            :   const std::map< int, std::vector< std::size_t > >& bnode,
     853                 :            :   const std::vector< std::size_t >& triinpoel,
     854                 :            :   const std::vector< std::string>& elemfieldnames,
     855                 :            :   const std::vector< std::string>& nodefieldnames,
     856                 :            :   const std::vector< std::string>& elemsurfnames,
     857                 :            :   const std::vector< std::string>& nodesurfnames,
     858                 :            :   const std::vector< std::vector< tk::real > >& elemfields,
     859                 :            :   const std::vector< std::vector< tk::real > >& nodefields,
     860                 :            :   const std::vector< std::vector< tk::real > >& elemsurfs,
     861                 :            :   const std::vector< std::vector< tk::real > >& nodesurfs,
     862                 :            :   CkCallback c )
     863                 :            : // *****************************************************************************
     864                 :            : //  Output mesh and fields data (solution dump) to file(s)
     865                 :            : //! \param[in] inpoel Mesh connectivity for the mesh chunk to be written
     866                 :            : //! \param[in] coord Node coordinates of the mesh chunk to be written
     867                 :            : //! \param[in] bface Map of boundary-face lists mapped to corresponding side set
     868                 :            : //!   ids for this mesh chunk
     869                 :            : //! \param[in] bnode Map of boundary-node lists mapped to corresponding side set
     870                 :            : //!   ids for this mesh chunk
     871                 :            : //! \param[in] triinpoel Interconnectivity of points and boundary-face in this
     872                 :            : //!   mesh chunk
     873                 :            : //! \param[in] elemfieldnames Names of element fields to be output to file
     874                 :            : //! \param[in] nodefieldnames Names of node fields to be output to file
     875                 :            : //! \param[in] elemsurfnames Names of elem surface fields to be output to file
     876                 :            : //! \param[in] nodesurfnames Names of node surface fields to be output to file
     877                 :            : //! \param[in] elemfields Field data in mesh elements to output to file
     878                 :            : //! \param[in] nodefields Field data in mesh nodes to output to file
     879                 :            : //! \param[in] elemsurfs Surface field data in mesh elements to output to file
     880                 :            : //! \param[in] nodesurfs Surface field data in mesh nodes to output to file
     881                 :            : //! \param[in] c Function to continue with after the write
     882                 :            : //! \details Since m_meshwriter is a Charm++ chare group, it never migrates and
     883                 :            : //!   an instance is guaranteed on every PE. We index the first PE on every
     884                 :            : //!   logical compute node. In Charm++'s non-SMP mode, a node is the same as a
     885                 :            : //!   PE, so the index is the same as CkMyPe(). In SMP mode the index is the
     886                 :            : //!   first PE on every logical node. In non-SMP mode this yields one or more
     887                 :            : //!   output files per PE with zero or non-zero virtualization, respectively. If
     888                 :            : //!   there are multiple chares on a PE, the writes are serialized per PE, since
     889                 :            : //!   only a single entry method call can be executed at any given time. In SMP
     890                 :            : //!   mode, still the same number of files are output (one per chare), but the
     891                 :            : //!   output is serialized through the first PE of each compute node. In SMP
     892                 :            : //!   mode, channeling multiple files via a single PE on each node is required
     893                 :            : //!   by NetCDF and HDF5, as well as ExodusII, since none of these libraries are
     894                 :            : //!   thread-safe.
     895                 :            : // *****************************************************************************
     896                 :            : {
     897                 :            :   // If the previous iteration refined (or moved) the mesh or this is called
     898                 :            :   // before the first time step, we also output the mesh.
     899                 :       3547 :   bool meshoutput = m_itf == 0 ? true : false;
     900                 :            : 
     901                 :       3547 :   auto eps = std::numeric_limits< tk::real >::epsilon();
     902                 :       3547 :   bool fieldoutput = false;
     903                 :            : 
     904                 :            :   // Output field data only if there is no dump at this physical time yet
     905         [ +  - ]:       3547 :   if (std::abs(m_lastDumpTime - m_t) > eps ) {
     906                 :       3547 :     m_lastDumpTime = m_t;
     907                 :       3547 :     ++m_itf;
     908                 :       3547 :     fieldoutput = true;
     909                 :            :   }
     910                 :            : 
     911                 :       3547 :   bool multi = g_cfg.get< tag::input >().size() > 1;
     912         [ -  + ]:       3547 :   const auto& ft = multi ? g_cfg.get< tag::fieldout_ >()[ m_meshid ]
     913                 :       3547 :                          : g_cfg.get< tag::fieldout >();
     914                 :            : 
     915                 :       3547 :   const auto& f = ft.get< tag::sidesets >();
     916         [ +  - ]:       3547 :   std::set< int > outsets( begin(f), end(f) );
     917                 :            : 
     918                 :            :   m_meshwriter[ CkNodeFirst( CkMyNode() ) ].
     919 [ +  - ][ +  - ]:       7094 :     write( m_meshid, meshoutput, fieldoutput, m_itr, m_itf, m_t, thisIndex,
     920                 :       3547 :            g_cfg.get< tag::output >(),
     921                 :            :            inpoel, coord, bface, bnode, triinpoel, elemfieldnames,
     922                 :            :            nodefieldnames, elemsurfnames, nodesurfnames, elemfields, nodefields,
     923                 :            :            elemsurfs, nodesurfs, outsets, c );
     924                 :       3547 : }
     925                 :            : 
     926                 :            : void
     927                 :      40576 : Discretization::setdt( tk::real newdt )
     928                 :            : // *****************************************************************************
     929                 :            : // Set time step size
     930                 :            : //! \param[in] newdt Size of the new time step
     931                 :            : // *****************************************************************************
     932                 :            : {
     933                 :      40576 :   m_dtn = m_dt;
     934                 :      40576 :   m_dt = newdt;
     935                 :            : 
     936                 :            :   // Truncate the size of last time step
     937                 :      40576 :   const auto term = g_cfg.get< tag::term >();
     938         [ +  + ]:      40576 :   if (m_t+m_dt > term) m_dt = term - m_t;
     939                 :      40576 : }
     940                 :            : 
     941                 :            : void
     942                 :      40608 : Discretization::next()
     943                 :            : // *****************************************************************************
     944                 :            : // Prepare for next step
     945                 :            : // *****************************************************************************
     946                 :            : {
     947                 :            :   // Update floor of physics time divided by output interval times
     948                 :      40608 :   const auto eps = std::numeric_limits< tk::real >::epsilon();
     949                 :      40608 :   bool multi = g_cfg.get< tag::input >().size() > 1;
     950         [ -  + ]:      40608 :   const auto& ftab = multi ? g_cfg.get< tag::fieldout_ >()[ m_meshid ]
     951                 :      40608 :                            : g_cfg.get< tag::fieldout >();
     952                 :      40608 :   const auto ft = ftab.get< tag::time >();
     953         [ +  + ]:      40608 :   if (ft > eps) m_physFieldFloor = std::floor( m_t / ft );
     954                 :      40608 :   const auto ht = g_cfg.get< tag::histout, tag::time >();
     955         [ +  - ]:      40608 :   if (ht > eps) m_physHistFloor = std::floor( m_t / ht );
     956                 :      40608 :   const auto it = g_cfg.get< tag::integout, tag::time >();
     957         [ +  - ]:      40608 :   if (it > eps) m_physIntegFloor = std::floor( m_t / it );
     958                 :            : 
     959                 :            :   // Update floors of physics time divided by output interval times for ranges
     960                 :      40608 :   const auto& rf = ftab.get< tag::range >();
     961         [ +  + ]:      41008 :   for (std::size_t i=0; i<rf.size(); ++i) {
     962 [ +  + ][ +  + ]:        400 :     if (m_t > rf[i][0] and m_t < rf[i][1]) {
                 [ +  + ]
     963                 :         32 :       m_rangeFieldFloor[i] = std::floor( m_t / rf[i][2] );
     964                 :            :     }
     965                 :            :   }
     966                 :            : 
     967                 :      40608 :   const auto& rh = g_cfg.get< tag::histout, tag::range >();
     968         [ +  + ]:      42848 :   for (std::size_t i=0; i<rh.size(); ++i) {
     969 [ +  + ][ +  + ]:       2240 :     if (m_t > rh[i][0] and m_t < rh[i][1]) {
                 [ +  + ]
     970                 :        620 :       m_rangeHistFloor[i] = std::floor( m_t / rh[i][2] );
     971                 :            :     }
     972                 :            :   }
     973                 :            : 
     974                 :      40608 :   const auto& ri = g_cfg.get< tag::integout, tag::range >();
     975         [ +  + ]:      40648 :   for (std::size_t i=0; i<ri.size(); ++i) {
     976 [ +  + ][ +  + ]:         40 :     if (m_t > ri[i][0] and m_t < ri[i][1]) {
                 [ +  + ]
     977                 :         10 :       m_rangeIntegFloor[i] = std::floor( m_t / ri[i][2] );
     978                 :            :     }
     979                 :            :   }
     980                 :            : 
     981                 :      40608 :   ++m_it;
     982                 :      40608 :   m_t += m_dt;
     983                 :      40608 : }
     984                 :            : 
     985                 :            : void
     986                 :       2574 : Discretization::grindZero()
     987                 :            : // *****************************************************************************
     988                 :            : //  Zero grind-time
     989                 :            : // *****************************************************************************
     990                 :            : {
     991                 :       2574 :   m_prevstatus = std::chrono::high_resolution_clock::now();
     992                 :            : 
     993 [ +  + ][ +  - ]:       2574 :   if (thisIndex == 0 && m_meshid == 0) {
     994         [ +  - ]:        260 :     tk::Print() << "Starting time stepping ...\n";
     995                 :            :   }
     996                 :       2574 : }
     997                 :            : 
     998                 :            : bool
     999                 :      38032 : Discretization::restarted( int nrestart )
    1000                 :            : // *****************************************************************************
    1001                 :            : //  Detect if just returned from a checkpoint and if so, zero timers
    1002                 :            : //! \param[in] nrestart Number of times restarted
    1003                 :            : //! \return True if restart detected
    1004                 :            : // *****************************************************************************
    1005                 :            : {
    1006                 :            :   // Detect if just restarted from checkpoint:
    1007                 :            :   //   nrestart == -1 if there was no checkpoint this step
    1008                 :            :   //   m_nrestart == nrestart if there was a checkpoint this step
    1009                 :            :   //   if both false, just restarted from a checkpoint
    1010 [ +  + ][ +  - ]:      38032 :   bool restarted = nrestart != -1 and m_nrestart != nrestart;
    1011                 :            : 
    1012                 :            :    // If just restarted from checkpoint
    1013         [ +  + ]:      38032 :   if (restarted) {
    1014                 :            :     // Update number of restarts
    1015                 :         30 :     m_nrestart = nrestart;
    1016                 :            :     // Start timer measuring time stepping wall clock time
    1017                 :         30 :     m_timer.zero();
    1018                 :            :     // Zero grind-timer
    1019                 :         30 :     grindZero();
    1020                 :            :   }
    1021                 :            : 
    1022                 :      38032 :   return restarted;
    1023                 :            : }
    1024                 :            : 
    1025                 :            : std::string
    1026                 :        726 : Discretization::histfilename( const std::string& id, std::streamsize precision )
    1027                 :            : // *****************************************************************************
    1028                 :            : //  Construct history output filename
    1029                 :            : //! \param[in] id History point id
    1030                 :            : //! \param[in] precision Floating point precision to use for output
    1031                 :            : //! \return History file name
    1032                 :            : // *****************************************************************************
    1033                 :            : {
    1034         [ +  - ]:        726 :   auto of = g_cfg.get< tag::output >();
    1035         [ +  - ]:        726 :   std::stringstream ss;
    1036                 :            : 
    1037 [ +  - ][ +  - ]:        726 :   ss << std::setprecision(static_cast<int>(precision)) << of << ".hist." << id;
                 [ +  - ]
    1038                 :            : 
    1039         [ +  - ]:       1452 :   return ss.str();
    1040                 :        726 : }
    1041                 :            : 
    1042                 :            : void
    1043                 :         74 : Discretization::histheader( std::vector< std::string >&& names )
    1044                 :            : // *****************************************************************************
    1045                 :            : //  Output headers for time history files (one for each point)
    1046                 :            : //! \param[in] names History output variable names
    1047                 :            : // *****************************************************************************
    1048                 :            : {
    1049         [ +  + ]:        149 :   for (const auto& h : m_histdata) {
    1050                 :         75 :     auto prec = g_cfg.get< tag::histout, tag:: precision >();
    1051         [ +  - ]:        150 :     tk::DiagWriter hw( histfilename( h.get< tag::id >(), prec ),
    1052                 :         75 :                        g_cfg.get< tag::histout, tag::format >(),
    1053         [ +  - ]:         75 :                        prec );
    1054         [ +  - ]:         75 :     hw.header( names );
    1055                 :         75 :   }
    1056                 :         74 : }
    1057                 :            : 
    1058                 :            : void
    1059                 :       1238 : Discretization::history( std::vector< std::vector< tk::real > >&& data )
    1060                 :            : // *****************************************************************************
    1061                 :            : //  Output time history for a time step
    1062                 :            : //! \param[in] data Time history data for all variables and equations integrated
    1063                 :            : // *****************************************************************************
    1064                 :            : {
    1065 [ -  + ][ -  - ]:       1238 :   Assert( data.size() == m_histdata.size(), "Size mismatch" );
         [ -  - ][ -  - ]
    1066                 :            : 
    1067                 :       1238 :   std::size_t i = 0;
    1068         [ +  + ]:       1889 :   for (const auto& h : m_histdata) {
    1069                 :        651 :     auto prec = g_cfg.get< tag::histout, tag::precision >();
    1070         [ +  - ]:       1302 :     tk::DiagWriter hw( histfilename( h.get< tag::id >(), prec ),
    1071                 :        651 :                        g_cfg.get< tag::histout, tag::format >(),
    1072                 :            :                        prec,
    1073         [ +  - ]:        651 :                        std::ios_base::app );
    1074         [ +  - ]:        651 :     hw.write( m_it, m_t, m_dt, data[i] );
    1075                 :        651 :     ++i;
    1076                 :        651 :   }
    1077                 :       1238 : }
    1078                 :            : 
    1079                 :            : bool
    1080                 :      43668 : Discretization::fielditer() const
    1081                 :            : // *****************************************************************************
    1082                 :            : //  Decide if field output iteration count interval is hit
    1083                 :            : //! \return True if field output iteration count interval is hit
    1084                 :            : // *****************************************************************************
    1085                 :            : {
    1086         [ +  + ]:      43668 :   if (g_cfg.get< tag::benchmark >()) return false;
    1087                 :            : 
    1088                 :      25068 :   bool multi = g_cfg.get< tag::input >().size() > 1;
    1089         [ -  + ]:      25068 :   const auto& ft = multi ? g_cfg.get< tag::fieldout_ >()[ m_meshid ]
    1090                 :      25068 :                          : g_cfg.get< tag::fieldout >();
    1091                 :            : 
    1092                 :      25068 :   return m_it % ft.get< tag::iter >() == 0;
    1093                 :            : }
    1094                 :            : 
    1095                 :            : bool
    1096                 :      41081 : Discretization::fieldtime() const
    1097                 :            : // *****************************************************************************
    1098                 :            : //  Decide if field output physics time interval is hit
    1099                 :            : //! \return True if field output physics time interval is hit
    1100                 :            : // *****************************************************************************
    1101                 :            : {
    1102         [ +  + ]:      41081 :   if (g_cfg.get< tag::benchmark >()) return false;
    1103                 :            : 
    1104                 :      22481 :   auto eps = std::numeric_limits< tk::real >::epsilon();
    1105                 :      22481 :   bool multi = g_cfg.get< tag::input >().size() > 1;
    1106         [ -  + ]:      22481 :   const auto& ftab = multi ? g_cfg.get< tag::fieldout_ >()[ m_meshid ]
    1107                 :      22481 :                            : g_cfg.get< tag::fieldout >();
    1108                 :      22481 :   auto ft = ftab.get< tag::time >();
    1109                 :            : 
    1110         [ +  + ]:      22481 :   if (ft < eps) return false;
    1111                 :            : 
    1112                 :      22449 :   return std::floor(m_t/ft) - m_physFieldFloor > eps;
    1113                 :            : }
    1114                 :            : 
    1115                 :            : bool
    1116                 :      41057 : Discretization::fieldrange() const
    1117                 :            : // *****************************************************************************
    1118                 :            : //  Decide if physics time falls into a field output time range
    1119                 :            : //! \return True if physics time falls into a field output time range
    1120                 :            : // *****************************************************************************
    1121                 :            : {
    1122         [ +  + ]:      41057 :   if (g_cfg.get< tag::benchmark >()) return false;
    1123                 :            : 
    1124                 :      22457 :   const auto eps = std::numeric_limits< tk::real >::epsilon();
    1125                 :            : 
    1126                 :      22457 :   bool output = false;
    1127                 :            : 
    1128                 :      22457 :   bool multi = g_cfg.get< tag::input >().size() > 1;
    1129         [ -  + ]:      22457 :   const auto& ftab = multi ? g_cfg.get< tag::fieldout_ >()[ m_meshid ]
    1130                 :      22457 :                            : g_cfg.get< tag::fieldout >();
    1131                 :      22457 :   const auto& rf = ftab.get< tag::range >();
    1132         [ +  + ]:      22957 :   for (std::size_t i=0; i<rf.size(); ++i) {
    1133 [ +  + ][ +  + ]:        500 :     if (m_t > rf[i][0] and m_t < rf[i][1]) {
                 [ +  + ]
    1134                 :         40 :       output |= std::floor(m_t/rf[i][2]) - m_rangeFieldFloor[i] > eps;
    1135                 :            :     }
    1136                 :            :   }
    1137                 :            : 
    1138                 :      22457 :   return output;
    1139                 :            : }
    1140                 :            : 
    1141                 :            : bool
    1142                 :      43668 : Discretization::histiter() const
    1143                 :            : // *****************************************************************************
    1144                 :            : //  Decide if history output iteration count interval is hit
    1145                 :            : //! \return True if history output iteration count interval is hit
    1146                 :            : // *****************************************************************************
    1147                 :            : {
    1148         [ +  + ]:      43668 :   if (g_cfg.get< tag::benchmark >()) return false;
    1149                 :            : 
    1150                 :      25068 :   auto hist = g_cfg.get< tag::histout, tag::iter >();
    1151                 :      25068 :   const auto& hist_points = g_cfg.get< tag::histout, tag::points >();
    1152                 :            : 
    1153 [ +  + ][ +  - ]:      25068 :   return m_it % hist == 0 and not hist_points.empty();
    1154                 :            : }
    1155                 :            : 
    1156                 :            : bool
    1157                 :      42882 : Discretization::histtime() const
    1158                 :            : // *****************************************************************************
    1159                 :            : //  Decide if history output physics time interval is hit
    1160                 :            : //! \return True if history output physics time interval is hit
    1161                 :            : // *****************************************************************************
    1162                 :            : {
    1163         [ +  + ]:      42882 :   if (g_cfg.get< tag::benchmark >()) return false;
    1164                 :            : 
    1165                 :      24282 :   auto eps = std::numeric_limits< tk::real >::epsilon();
    1166                 :      24282 :   auto ht = g_cfg.get< tag::histout, tag::time >();
    1167                 :            : 
    1168         [ -  + ]:      24282 :   if (ht < eps) return false;
    1169                 :            : 
    1170                 :      24282 :   return std::floor(m_t/ht) - m_physHistFloor > eps;
    1171                 :            : }
    1172                 :            : 
    1173                 :            : bool
    1174                 :      42624 : Discretization::histrange() const
    1175                 :            : // *****************************************************************************
    1176                 :            : //  Decide if physics time falls into a history output time range
    1177                 :            : //! \return True if physics time falls into a history output time range
    1178                 :            : // *****************************************************************************
    1179                 :            : {
    1180         [ +  + ]:      42624 :   if (g_cfg.get< tag::benchmark >()) return false;
    1181                 :            : 
    1182                 :      24024 :   auto eps = std::numeric_limits< tk::real >::epsilon();
    1183                 :            : 
    1184                 :      24024 :   bool output = false;
    1185                 :            : 
    1186                 :      24024 :   const auto& rh = g_cfg.get< tag::histout, tag::range >();
    1187         [ +  + ]:      26184 :   for (std::size_t i=0; i<rh.size(); ++i) {
    1188 [ +  + ][ +  + ]:       2160 :     if (m_t > rh[i][0] and m_t < rh[i][1]) {
                 [ +  + ]
    1189                 :        590 :       output |= std::floor(m_t/rh[i][2]) - m_rangeHistFloor[i] > eps;
    1190                 :            :     }
    1191                 :            :   }
    1192                 :            : 
    1193                 :      24024 :   return output;
    1194                 :            : }
    1195                 :            : 
    1196                 :            : bool
    1197                 :      43668 : Discretization::integiter() const
    1198                 :            : // *****************************************************************************
    1199                 :            : //  Decide if integral output iteration count interval is hit
    1200                 :            : //! \return True if integral output iteration count interval is hit
    1201                 :            : // *****************************************************************************
    1202                 :            : {
    1203         [ +  + ]:      43668 :   if (g_cfg.get< tag::benchmark >()) return false;
    1204                 :            : 
    1205                 :      25068 :   auto integ = g_cfg.get< tag::integout, tag::iter >();
    1206                 :      25068 :   const auto& sidesets_integral = g_cfg.get< tag::integout, tag::sidesets >();
    1207                 :            : 
    1208 [ +  + ][ +  - ]:      25068 :   return m_it % integ == 0 and not sidesets_integral.empty();
    1209                 :            : }
    1210                 :            : 
    1211                 :            : bool
    1212                 :      43342 : Discretization::integtime() const
    1213                 :            : // *****************************************************************************
    1214                 :            : //  Decide if integral output physics time interval is hit
    1215                 :            : //! \return True if integral output physics time interval is hit
    1216                 :            : // *****************************************************************************
    1217                 :            : {
    1218         [ +  + ]:      43342 :   if (g_cfg.get< tag::benchmark >()) return false;
    1219                 :            : 
    1220                 :      24742 :   auto eps = std::numeric_limits< tk::real >::epsilon();
    1221                 :      24742 :   auto it = g_cfg.get< tag::integout, tag::time >();
    1222                 :            : 
    1223         [ -  + ]:      24742 :   if (it < eps) return false;
    1224                 :            : 
    1225                 :      24742 :   return std::floor(m_t/it) - m_physIntegFloor > eps;
    1226                 :            : }
    1227                 :            : 
    1228                 :            : bool
    1229                 :      43315 : Discretization::integrange() const
    1230                 :            : // *****************************************************************************
    1231                 :            : //  Decide if physics time falls into a integral output time range
    1232                 :            : //! \return True if physics time falls into a integral output time range
    1233                 :            : // *****************************************************************************
    1234                 :            : {
    1235         [ +  + ]:      43315 :   if (g_cfg.get< tag::benchmark >()) return false;
    1236                 :            : 
    1237                 :      24715 :   auto eps = std::numeric_limits< tk::real >::epsilon();
    1238                 :            : 
    1239                 :      24715 :   bool output = false;
    1240                 :            : 
    1241                 :      24715 :   const auto& ri = g_cfg.get< tag::integout, tag::range >();
    1242         [ +  + ]:      24775 :   for (std::size_t i=0; i<ri.size(); ++i) {
    1243 [ +  + ][ +  + ]:         60 :     if (m_t > ri[i][0] and m_t < ri[i][1]) {
                 [ +  + ]
    1244                 :         15 :       output |= std::floor(m_t/ri[i][2]) - m_rangeIntegFloor[i] > eps;
    1245                 :            :     }
    1246                 :            :   }
    1247                 :            : 
    1248                 :      24715 :   return output;
    1249                 :            : }
    1250                 :            : 
    1251                 :            : bool
    1252                 :      45489 : Discretization::finished() const
    1253                 :            : // *****************************************************************************
    1254                 :            : //  Decide if this is the last time step
    1255                 :            : //! \return True if this is the last time step
    1256                 :            : // *****************************************************************************
    1257                 :            : {
    1258                 :      45489 :   auto eps = std::numeric_limits< tk::real >::epsilon();
    1259                 :      45489 :   auto nstep = g_cfg.get< tag::nstep >();
    1260                 :      45489 :   auto term = g_cfg.get< tag::term >();
    1261                 :      45489 :   auto residual = g_cfg.get< tag::residual >();
    1262                 :            : 
    1263 [ +  + ][ +  + ]:      87979 :   return std::abs(m_t-term) < eps or m_it >= nstep or
    1264 [ +  + ][ -  + ]:      87979 :          (m_res > 0.0 and m_res < residual);
    1265                 :            : }
    1266                 :            : 
    1267                 :            : void
    1268                 :       1060 : Discretization::residual( tk::real r )
    1269                 :            : // *****************************************************************************
    1270                 :            : //  Update residual (during convergence to steady state)
    1271                 :            : //! \param[in] r Current residual
    1272                 :            : // *****************************************************************************
    1273                 :            : {
    1274                 :       1060 :   auto ttyi = g_cfg.get< tag::ttyi >();
    1275                 :            : 
    1276         [ +  - ]:       1060 :   if (m_it % ttyi == 0) {
    1277                 :       1060 :     m_res0 = m_res1;
    1278                 :       1060 :     m_res1 = r;
    1279                 :            :   }
    1280                 :            : 
    1281                 :       1060 :   m_res = r;
    1282                 :       1060 : }
    1283                 :            : 
    1284                 :            : bool
    1285                 :         48 : Discretization::deastart()
    1286                 :            : // *****************************************************************************
    1287                 :            : //  Decide whether to start the deactivation procedure in this time step
    1288                 :            : //! \return True to start the deactivation prcedure in this time step
    1289                 :            : // *****************************************************************************
    1290                 :            : {
    1291 [ +  + ][ +  - ]:         48 :   if (not m_deastarted and m_t > g_cfg.get<tag::deatime>() + m_dt) {
                 [ +  + ]
    1292                 :         19 :     m_deastarted = 1;
    1293                 :         19 :     return true;
    1294                 :            :   }
    1295                 :            : 
    1296                 :         29 :   return false;
    1297                 :            : }
    1298                 :            : 
    1299                 :            : bool
    1300                 :       6086 : Discretization::deactivate() const
    1301                 :            : // *****************************************************************************
    1302                 :            : //  Decide whether to run deactivation procedure in this time step
    1303                 :            : //! \return True to run deactivation prcedure in this time step
    1304                 :            : // *****************************************************************************
    1305                 :            : {
    1306                 :       6086 :   auto dea = g_cfg.get< tag::deactivate >();
    1307                 :       6086 :   auto deafreq = g_cfg.get< tag::deafreq >();
    1308                 :            : 
    1309 [ +  + ][ +  - ]:       6086 :   if (dea and !m_nodeCommMap.empty() and m_it % deafreq == 0)
         [ +  + ][ +  + ]
    1310                 :        200 :     return true;
    1311                 :            :   else
    1312                 :       5886 :     return false;
    1313                 :            : }
    1314                 :            : 
    1315                 :            : void
    1316                 :         10 : Discretization::deactivated( int n )
    1317                 :            : // *****************************************************************************
    1318                 :            : //  Receive deactivation report
    1319                 :            : //! \param[in] n Sum of deactivated chares
    1320                 :            : // *****************************************************************************
    1321                 :            : {
    1322                 :         10 :   m_dea = n;
    1323                 :         10 : }
    1324                 :            : 
    1325                 :            : bool
    1326                 :      17212 : Discretization::lb() const
    1327                 :            : // *****************************************************************************
    1328                 :            : //  Decide whether to do load balancing this time step
    1329                 :            : //! \return True to do load balancing in this time step
    1330                 :            : // *****************************************************************************
    1331                 :            : {
    1332                 :      17212 :   auto lbfreq = g_cfg.get< tag::lbfreq >();
    1333                 :      17212 :   auto lbtime = g_cfg.get< tag::lbtime >();
    1334                 :            : 
    1335 [ +  - ][ +  + ]:      17212 :   if ((m_t > lbtime and m_it % lbfreq == 0) or m_it == 2)
                 [ +  + ]
    1336                 :      12064 :     return true;
    1337                 :            :   else
    1338                 :       5148 :     return false;
    1339                 :            : }
    1340                 :            : 
    1341                 :            : void
    1342                 :        701 : Discretization::pit( std::size_t it )
    1343                 :            : // *****************************************************************************
    1344                 :            : //  Update number of pressure linear solve iterations taken
    1345                 :            : //! \param[in] it Number of pressure linear solve iterations taken
    1346                 :            : // *****************************************************************************
    1347                 :            : {
    1348                 :        701 :   m_pit = it;
    1349                 :        701 : }
    1350                 :            : 
    1351                 :            : void
    1352                 :         20 : Discretization::mit( std::size_t it )
    1353                 :            : // *****************************************************************************
    1354                 :            : //  Update number of momentum/transport linear solve iterations taken
    1355                 :            : //! \param[in] it Number of momentum/transport linear solve iterations taken
    1356                 :            : // *****************************************************************************
    1357                 :            : {
    1358                 :         20 :   m_mit = it;
    1359                 :         20 : }
    1360                 :            : 
    1361                 :            : void
    1362                 :        255 : Discretization::npoin( std::size_t n )
    1363                 :            : // *****************************************************************************
    1364                 :            : //  Set number of mesh points (across all meshes)
    1365                 :            : //! \param[in] n Number of mesh points
    1366                 :            : // *****************************************************************************
    1367                 :            : {
    1368                 :        255 :   m_npoin = n;
    1369                 :        255 : }
    1370                 :            : 
    1371                 :            : void
    1372                 :      18577 : Discretization::status()
    1373                 :            : // *****************************************************************************
    1374                 :            : // Output one-liner status report
    1375                 :            : // *****************************************************************************
    1376                 :            : {
    1377                 :      18577 :   const auto ttyi = g_cfg.get< tag::ttyi >();
    1378                 :            : 
    1379 [ +  + ][ +  - ]:      18577 :   if (thisIndex == 0 and m_meshid == 0 and m_it % ttyi == 0) {
                 [ +  + ]
    1380                 :            : 
    1381                 :            :     // estimate grind time (taken between this and the previous time step)
    1382                 :            :     using std::chrono::duration_cast;
    1383                 :            :     using us = std::chrono::microseconds;
    1384                 :            :     using clock = std::chrono::high_resolution_clock;
    1385 [ +  - ][ +  - ]:       3060 :     auto grind_time = duration_cast< us >(clock::now() - m_prevstatus).count()
    1386                 :       3060 :                       / static_cast< long >( ttyi );
    1387                 :       3060 :     auto grind_perf = static_cast<tk::real>(grind_time)
    1388                 :       3060 :                       / static_cast<tk::real>(m_npoin);
    1389                 :       3060 :     m_prevstatus = clock::now();
    1390                 :            : 
    1391                 :       3060 :     const auto term = g_cfg.get< tag::term >();
    1392                 :       3060 :     const auto t0 = g_cfg.get< tag::t0 >();
    1393                 :       3060 :     const auto nstep = g_cfg.get< tag::nstep >();
    1394                 :       3060 :     const auto diag = g_cfg.get< tag::diag_iter >();
    1395                 :       3060 :     const auto rsfreq = g_cfg.get< tag::rsfreq >();
    1396                 :       3060 :     const auto benchmark = g_cfg.get< tag::benchmark >();
    1397                 :       3060 :     const auto residual = g_cfg.get< tag::residual >();
    1398         [ +  - ]:       3060 :     const auto solver = g_cfg.get< tag::solver >();
    1399         [ +  + ]:       3060 :     const auto pre = solver == "chocg" ? 1 : 0;
    1400                 :       3060 :     const auto theta = g_cfg.get< tag::theta >();
    1401                 :       3060 :     const auto eps = std::numeric_limits< tk::real >::epsilon();
    1402 [ +  + ][ +  + ]:       3060 :     const auto mom = solver == "chocg" and theta > eps ? 1 : 0;
    1403                 :            : 
    1404                 :            :     // estimate time elapsed and time for accomplishment
    1405 [ +  - ][ +  - ]:       3060 :     tk::Timer::Watch ete, eta;
    1406         [ +  - ]:       3060 :     m_timer.eta( term-t0, m_t-t0, nstep, m_it, m_res0, m_res1, residual,
    1407                 :            :                  ete, eta );
    1408                 :            : 
    1409                 :       3060 :     tk::Print print;
    1410                 :            : 
    1411                 :            :     // Output one-liner
    1412                 :       3060 :     print << std::setfill(' ') << std::setw(8) << m_it << "  "
    1413                 :          0 :           << std::scientific << std::setprecision(6)
    1414                 :          0 :           << std::setw(12) << m_t << "  "
    1415                 :       3060 :           << m_dt << "  "
    1416                 :          0 :           << std::setfill('0')
    1417                 :          0 :           << std::setw(3) << ete.hrs.count() << ":"
    1418                 :          0 :           << std::setw(2) << ete.min.count() << ":"
    1419                 :          0 :           << std::setw(2) << ete.sec.count() << "  "
    1420                 :          0 :           << std::setw(3) << eta.hrs.count() << ":"
    1421                 :          0 :           << std::setw(2) << eta.min.count() << ":"
    1422                 :          0 :           << std::setw(2) << eta.sec.count() << "  "
    1423                 :          0 :           << std::scientific << std::setprecision(6) << std::setfill(' ')
    1424                 :          0 :           << std::setw(9) << grind_time << "  "
    1425 [ +  - ][ +  - ]:       3060 :           << std::setw(9) << grind_perf << "  ";
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
    1426                 :            : 
    1427                 :            :     // Augment one-liner status with output indicators
    1428 [ +  - ][ +  + ]:       3060 :     if (fielditer() or fieldtime() or fieldrange()) print << 'f';
         [ +  - ][ +  + ]
         [ +  - ][ +  + ]
         [ +  + ][ +  - ]
    1429 [ +  + ][ +  - ]:       3060 :     if (not (m_it % diag)) print << 'd';
    1430 [ +  - ][ +  + ]:       3060 :     if (histiter() or histtime() or histrange()) print << 't';
         [ +  - ][ +  + ]
         [ +  - ][ +  + ]
         [ +  + ][ +  - ]
    1431 [ +  - ][ +  + ]:       3060 :     if (integiter() or integtime() or integrange()) print << 'i';
         [ +  - ][ +  + ]
         [ +  - ][ +  + ]
         [ +  + ][ +  - ]
    1432 [ -  + ][ -  - ]:       3060 :     if (m_refined) print << 'h';
    1433 [ +  - ][ +  + ]:       3060 :     if (lb() and not finished()) print << 'l';
         [ +  - ][ +  + ]
         [ +  + ][ +  - ]
    1434 [ +  + ][ +  - ]:       3060 :     if (not benchmark && (not (m_it % rsfreq) || finished())) print << 'c';
         [ +  - ][ +  + ]
         [ +  + ][ +  - ]
    1435 [ +  + ][ +  - ]:       3060 :     if (m_deastarted and deactivate()) {
         [ +  + ][ +  + ]
    1436 [ +  - ][ +  - ]:         10 :       print << "\te:" << m_dea << '/' << m_nchare;
         [ +  - ][ +  - ]
    1437                 :            :     }
    1438 [ +  + ][ +  - ]:       3060 :     if (pre) print << "\tp:" << m_pit;
                 [ +  - ]
    1439 [ +  + ][ +  - ]:       3060 :     if (mom) print << "\tm:" << m_mit;
                 [ +  - ]
    1440                 :            : 
    1441         [ +  - ]:       3060 :     print << '\n';
    1442                 :       3060 :   }
    1443                 :      18577 : }
    1444                 :            : 
    1445                 :            : #include "NoWarning/discretization.def.h"

Generated by: LCOV version 1.16