Xyst test code coverage report
Current view: top level - Inciter - Discretization.cpp (source / functions) Hit Total Coverage
Commit: e489e3468f2b950872163df1285c13fa7a355e8c Lines: 357 362 98.6 %
Date: 2024-11-20 18:16:45 Functions: 38 40 95.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 307 590 52.0 %

           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-2024 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 "XystBuildConfig.hpp"
      26                 :            : #include "Box.hpp"
      27                 :            : 
      28                 :            : namespace inciter {
      29                 :            : 
      30                 :            : static CkReduction::reducerType PDFMerger;
      31                 :            : extern ctr::Config g_cfg;
      32                 :            : 
      33                 :            : } // inciter::
      34                 :            : 
      35                 :            : using inciter::Discretization;
      36                 :            : 
      37                 :       2459 : Discretization::Discretization(
      38                 :            :   std::size_t meshid,
      39                 :            :   const CProxy_Transporter& transporter,
      40                 :            :   const tk::CProxy_MeshWriter& meshwriter,
      41                 :            :   const tk::UnsMesh::CoordMap& coordmap,
      42                 :            :   const tk::UnsMesh::Chunk& el,
      43                 :            :   const std::map< int, std::unordered_set< std::size_t > >& nodeCommMap,
      44                 :       2459 :   int nc ) :
      45                 :       2459 :   m_meshid( meshid ),
      46                 :       2459 :   m_nchare( nc ),
      47                 :       2459 :   m_it( 0 ),
      48                 :       2459 :   m_itr( 0 ),
      49                 :       2459 :   m_itf( 0 ),
      50                 :       2459 :   m_initial( 1 ),
      51                 :       2459 :   m_t( g_cfg.get< tag::t0 >() ),
      52                 :       2459 :   m_lastDumpTime( -std::numeric_limits< tk::real >::max() ),
      53                 :       2459 :   m_physFieldFloor( 0.0 ),
      54                 :       2459 :   m_physHistFloor( 0.0 ),
      55                 :       2459 :   m_physIntegFloor( 0.0 ),
      56         [ +  - ]:       2459 :   m_rangeFieldFloor( g_cfg.get< tag::fieldout_range >().size(), 0.0 ),
      57 [ +  - ][ -  - ]:       2459 :   m_rangeHistFloor( g_cfg.get< tag::histout_range >().size(), 0.0 ),
      58 [ +  - ][ -  - ]:       2459 :   m_rangeIntegFloor( g_cfg.get< tag::integout_range >().size(), 0.0 ),
      59                 :       2459 :   m_dt( g_cfg.get< tag::dt >() ),
      60                 :       2459 :   m_dtn( m_dt ),
      61                 :       2459 :   m_nvol( 0 ),
      62                 :            :   m_transporter( transporter ),
      63                 :            :   m_meshwriter( meshwriter ),
      64                 :            :   m_el( el ),     // fills m_inpoel, m_gid, m_lid
      65                 :       2459 :   m_coord( setCoord( coordmap ) ),
      66                 :       2459 :   m_meshvol( 0.0 ),
      67         [ +  - ]:       2459 :   m_v( m_gid.size(), 0.0 ),
      68 [ +  - ][ -  - ]:       2459 :   m_vol( m_gid.size(), 0.0 ),
      69                 :       2459 :   m_refined( 0 ),
      70                 :       2459 :   m_prevstatus( std::chrono::high_resolution_clock::now() ),
      71                 :       2459 :   m_nrestart( 0 ),
      72                 :       2459 :   m_res( 0.0 ),
      73                 :       2459 :   m_res0( 0.0 ),
      74                 :       2459 :   m_res1( 0.0 ),
      75                 :       2459 :   m_dea( 0 ),
      76                 :       2459 :   m_deastarted( 0 ),
      77                 :       2459 :   m_pit( 0 ),
      78 [ +  - ][ +  - ]:      12295 :   m_mit( 0 )
         [ +  - ][ +  - ]
      79                 :            : // *****************************************************************************
      80                 :            : //  Constructor
      81                 :            : //! \param[in] meshid Mesh ID
      82                 :            : //! \param[in] transporter Host (Transporter) proxy
      83                 :            : //! \param[in] meshwriter Mesh writer proxy
      84                 :            : //! \param[in] coordmap Coordinates of mesh nodes and their global IDs
      85                 :            : //! \param[in] el Elements of the mesh chunk we operate on
      86                 :            : //! \param[in] nodeCommMap Node lists associated to chare IDs bordering the
      87                 :            : //!   mesh chunk we operate on
      88                 :            : //! \param[in] nc Total number of Discretization chares
      89                 :            : // *****************************************************************************
      90                 :            : {
      91                 :            :   Assert( !m_inpoel.empty(), "No elements assigned to Discretization chare" );
      92                 :            :   Assert( tk::positiveJacobians( m_inpoel, m_coord ),
      93                 :            :           "Jacobian in input mesh to Discretization non-positive" );
      94                 :            :   #if not defined(__INTEL_COMPILER) || defined(NDEBUG)
      95                 :            :   // The above ifdef skips running the conformity test with the intel compiler
      96                 :            :   // in debug mode only. This is necessary because in tk::conforming(), filling
      97                 :            :   // up the map can fail with some meshes (only in parallel), e.g., tube.exo,
      98                 :            :   // used by some regression tests, due to the intel compiler generating some
      99                 :            :   // garbage incorrect code - only in debug, only in parallel, only with that
     100                 :            :   // mesh.
     101                 :            :   Assert( tk::conforming( m_inpoel, m_coord ),
     102                 :            :           "Input mesh to Discretization not conforming" );
     103                 :            :   #endif
     104                 :            : 
     105                 :            :   // Store node communication map
     106         [ +  + ]:      26823 :   for (const auto& [c,map] : nodeCommMap) m_nodeCommMap[c] = map;
     107                 :            : 
     108                 :            :   // Get ready for computing/communicating nodal volumes
     109         [ +  - ]:       2459 :   startvol();
     110                 :            : 
     111                 :            :   // Find host elements of user-specified points where time histories are
     112                 :            :   // saved, and save the shape functions evaluated at the point locations
     113                 :            :   const auto& pt = g_cfg.get< tag::histout >();
     114         [ +  + ]:       2699 :   for (std::size_t p=0; p<pt.size(); ++p) {
     115                 :            :     std::array< tk::real, 4 > N;
     116                 :            :     const auto& l = pt[p];
     117         [ +  + ]:     117564 :     for (std::size_t e=0; e<m_inpoel.size()/4; ++e) {
     118 [ +  - ][ +  + ]:     117399 :       if (tk::intet( m_coord, m_inpoel, l, e, N )) {
     119         [ +  - ]:         75 :         m_histdata.push_back( HistData{{ "p"+std::to_string(p+1), e, N }} );
     120                 :         75 :         break;
     121                 :            :       }
     122                 :            :     }
     123                 :            :   }
     124                 :            : 
     125                 :            :   // Compute number of mesh points owned
     126                 :       2459 :   std::size_t npoin = m_gid.size();
     127 [ +  - ][ +  + ]:     278519 :   for (auto g : m_gid) if (tk::slave( m_nodeCommMap, g, thisIndex ) ) --npoin;
                 [ +  + ]
     128                 :            : 
     129                 :            :   // Tell the RTS that the Discretization chares have been created and compute
     130                 :            :   // the total number of mesh points across the distributed mesh
     131         [ +  - ]:       2459 :   std::vector< std::size_t > meshdata{ m_meshid, npoin };
     132         [ +  - ]:       2459 :   contribute( meshdata, CkReduction::sum_ulong,
     133 [ +  - ][ -  - ]:       2459 :     CkCallback( CkReductionTarget(Transporter,disccreated), m_transporter ) );
     134                 :       2459 : }
     135                 :            : 
     136                 :            : void
     137                 :          0 : Discretization::resizePostAMR(
     138                 :            :   const tk::UnsMesh::Chunk& chunk,
     139                 :            :   const tk::UnsMesh::Coords& coord,
     140                 :            :   const std::unordered_map< int, std::unordered_set< std::size_t > >&
     141                 :            :     nodeCommMap,
     142                 :            :   const std::set< std::size_t >& /*removedNodes*/ )
     143                 :            : // *****************************************************************************
     144                 :            : //  Resize mesh data structures after mesh refinement
     145                 :            : //! \param[in] chunk New mesh chunk (connectivity and global<->local id maps)
     146                 :            : //! \param[in] coord New mesh node coordinates
     147                 :            : //! \param[in] nodeCommMap New node communication map
     148                 :            : //! \param[in] removedNodes Newly removed mesh node local ids
     149                 :            : // *****************************************************************************
     150                 :            : {
     151                 :            :   m_el = chunk;                 // updates m_inpoel, m_gid, m_lid
     152                 :            :   m_nodeCommMap = nodeCommMap;
     153                 :            : 
     154                 :            :   // Update mesh volume container size
     155                 :          0 :   m_vol.resize( m_gid.size(), 0.0 );
     156                 :            : 
     157                 :            :   // update mesh node coordinates
     158                 :            :   m_coord = coord;
     159                 :          0 : }
     160                 :            : 
     161                 :            : void
     162                 :       2459 : Discretization::startvol()
     163                 :            : // *****************************************************************************
     164                 :            : //  Get ready for (re-)computing/communicating nodal volumes
     165                 :            : // *****************************************************************************
     166                 :            : {
     167                 :       2459 :   m_nvol = 0;
     168         [ +  - ]:       4918 :   thisProxy[ thisIndex ].wait4vol();
     169                 :            : 
     170                 :            :   // Zero out mesh volume container
     171                 :            :   std::fill( begin(m_vol), end(m_vol), 0.0 );
     172                 :            : 
     173                 :            :   // Clear receive buffer that will be used for collecting nodal volumes
     174                 :            :   m_volc.clear();
     175                 :       2459 : }
     176                 :            : 
     177                 :            : void
     178                 :        768 : Discretization::registerReducers()
     179                 :            : // *****************************************************************************
     180                 :            : //  Configure Charm++ reduction types
     181                 :            : //!  \details Since this is a [initnode] routine, see the .ci file, the
     182                 :            : //!   Charm++ runtime system executes the routine exactly once on every
     183                 :            : //!   logical node early on in the Charm++ init sequence. Must be static as
     184                 :            : //!   it is called without an object. See also: Section "Initializations at
     185                 :            : //!   Program Startup" at in the Charm++ manual
     186                 :            : //!   http://charm.cs.illinois.edu/manuals/html/charm++/manual.html.
     187                 :            : // *****************************************************************************
     188                 :            : {
     189                 :        768 :   PDFMerger = CkReduction::addReducer( tk::mergeUniPDFs );
     190                 :        768 : }
     191                 :            : 
     192                 :            : tk::UnsMesh::Coords
     193                 :       2459 : Discretization::setCoord( const tk::UnsMesh::CoordMap& coordmap )
     194                 :            : // *****************************************************************************
     195                 :            : // Set mesh coordinates based on coordinates map
     196                 :            : // *****************************************************************************
     197                 :            : {
     198                 :            :   Assert( coordmap.size() == m_gid.size(), "Size mismatch" );
     199                 :            :   Assert( coordmap.size() == m_lid.size(), "Size mismatch" );
     200                 :            : 
     201                 :            :   tk::UnsMesh::Coords coord;
     202         [ +  - ]:       2459 :   coord[0].resize( coordmap.size() );
     203         [ +  - ]:       2459 :   coord[1].resize( coordmap.size() );
     204         [ +  - ]:       2459 :   coord[2].resize( coordmap.size() );
     205                 :            : 
     206         [ +  + ]:     278519 :   for (const auto& [ gid, coords ] : coordmap) {
     207                 :     276060 :     auto i = tk::cref_find( m_lid, gid );
     208                 :     276060 :     coord[0][i] = coords[0];
     209                 :     276060 :     coord[1][i] = coords[1];
     210                 :     276060 :     coord[2][i] = coords[2];
     211                 :            :   }
     212                 :            : 
     213                 :       2459 :   return coord;
     214                 :          0 : }
     215                 :            : 
     216                 :            : void
     217                 :       1565 : Discretization::remap(
     218                 :            :   const std::unordered_map< std::size_t, std::size_t >& map )
     219                 :            : // *****************************************************************************
     220                 :            : //  Remap mesh data based on new local ids
     221                 :            : //! \param[in] map Mapping of old->new local ids
     222                 :            : // *****************************************************************************
     223                 :            : {
     224                 :            :   // Remap connectivity containing local IDs
     225         [ +  + ]:    2135129 :   for (auto& l : m_inpoel) l = tk::cref_find(map,l);
     226                 :            : 
     227                 :            :   // Remap global->local id map
     228         [ +  + ]:     160857 :   for (auto& [g,l] : m_lid) l = tk::cref_find(map,l);
     229                 :            : 
     230                 :            :   // Remap global->local id map
     231                 :       1565 :   auto maxid = std::numeric_limits< std::size_t >::max();
     232                 :       1565 :   std::vector< std::size_t > newgid( m_gid.size(), maxid );
     233         [ +  + ]:     160857 :   for (const auto& [o,n] : map) newgid[n] = m_gid[o];
     234                 :       1565 :   m_gid = std::move( newgid );
     235                 :            : 
     236                 :            :   Assert( std::all_of( m_gid.cbegin(), m_gid.cend(),
     237                 :            :             [=](std::size_t i){ return i < maxid; } ),
     238                 :            :           "Not all gid have been remapped" );
     239                 :            : 
     240                 :            :   // Remap nodal volumes (with contributions along chare-boundaries)
     241 [ +  - ][ -  - ]:       1565 :   std::vector< tk::real > newvol( m_vol.size(), 0.0 );
     242         [ +  + ]:     160857 :   for (const auto& [o,n] : map) newvol[n] = m_vol[o];
     243                 :       1565 :   m_vol = std::move( newvol );
     244                 :            : 
     245                 :            :   // Remap nodal volumes (without contributions along chare-boundaries)
     246 [ +  - ][ -  - ]:       1565 :   std::vector< tk::real > newv( m_v.size(), 0.0 );
     247         [ +  + ]:     160857 :   for (const auto& [o,n] : map) newv[n] = m_v[o];
     248                 :       1565 :   m_v = std::move( newv );
     249                 :            : 
     250                 :            :   // Remap locations of node coordinates
     251                 :            :   tk::UnsMesh::Coords newcoord;
     252                 :            :   auto npoin = m_coord[0].size();
     253         [ +  - ]:       1565 :   newcoord[0].resize( npoin );
     254         [ +  - ]:       1565 :   newcoord[1].resize( npoin );
     255         [ +  - ]:       1565 :   newcoord[2].resize( npoin );
     256         [ +  + ]:     160857 :   for (const auto& [o,n] : map) {
     257                 :     159292 :     newcoord[0][n] = m_coord[0][o];
     258                 :     159292 :     newcoord[1][n] = m_coord[1][o];
     259                 :     159292 :     newcoord[2][n] = m_coord[2][o];
     260                 :            :   }
     261                 :            :   m_coord = std::move( newcoord );
     262                 :       3130 : }
     263                 :            : 
     264                 :            : void
     265                 :       2459 : Discretization::setRefiner( const CProxy_Refiner& ref )
     266                 :            : // *****************************************************************************
     267                 :            : //  Set Refiner Charm++ proxy
     268                 :            : //! \param[in] ref Incoming refiner proxy to store
     269                 :            : // *****************************************************************************
     270                 :            : {
     271                 :            :   m_refiner = ref;
     272                 :       2459 : }
     273                 :            : 
     274                 :            : void
     275                 :       2459 : Discretization::vol()
     276                 :            : // *****************************************************************************
     277                 :            : // Sum mesh volumes to nodes, start communicating them on chare-boundaries
     278                 :            : // *****************************************************************************
     279                 :            : {
     280                 :            :   const auto& x = m_coord[0];
     281                 :            :   const auto& y = m_coord[1];
     282                 :            :   const auto& z = m_coord[2];
     283                 :            : 
     284                 :            :   // Compute nodal volumes on our chunk of the mesh
     285         [ +  + ]:     974902 :   for (std::size_t e=0; e<m_inpoel.size()/4; ++e) {
     286                 :     972443 :     const auto N = m_inpoel.data() + e*4;
     287                 :            :     const std::array< tk::real, 3 >
     288         [ -  + ]:     972443 :       ba{{ x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]] }},
     289                 :     972443 :       ca{{ x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]] }},
     290         [ -  + ]:     972443 :       da{{ x[N[3]]-x[N[0]], y[N[3]]-y[N[0]], z[N[3]]-z[N[0]] }};
     291                 :     972443 :     const auto J = tk::triple( ba, ca, da ) / 24.0;
     292 [ -  + ][ -  - ]:     972443 :     ErrChk( J > 0, "Element Jacobian non-positive: PE:" +
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
                 [ -  - ]
     293                 :            :                    std::to_string(CkMyPe()) + ", node IDs: " +
     294                 :            :                    std::to_string(m_gid[N[0]]) + ',' +
     295                 :            :                    std::to_string(m_gid[N[1]]) + ',' +
     296                 :            :                    std::to_string(m_gid[N[2]]) + ',' +
     297                 :            :                    std::to_string(m_gid[N[3]]) + ", coords: (" +
     298                 :            :                    std::to_string(x[N[0]]) + ", " +
     299                 :            :                    std::to_string(y[N[0]]) + ", " +
     300                 :            :                    std::to_string(z[N[0]]) + "), (" +
     301                 :            :                    std::to_string(x[N[1]]) + ", " +
     302                 :            :                    std::to_string(y[N[1]]) + ", " +
     303                 :            :                    std::to_string(z[N[1]]) + "), (" +
     304                 :            :                    std::to_string(x[N[2]]) + ", " +
     305                 :            :                    std::to_string(y[N[2]]) + ", " +
     306                 :            :                    std::to_string(z[N[2]]) + "), (" +
     307                 :            :                    std::to_string(x[N[3]]) + ", " +
     308                 :            :                    std::to_string(y[N[3]]) + ", " +
     309                 :            :                    std::to_string(z[N[3]]) + ')' );
     310                 :            :     // scatter add V/4 to nodes
     311         [ +  + ]:    4862215 :     for (std::size_t j=0; j<4; ++j) m_vol[N[j]] += J;
     312                 :            :   }
     313                 :            : 
     314                 :            :   // Store nodal volumes without contributions from other chares on
     315                 :            :   // chare-boundaries
     316                 :       2459 :   m_v = m_vol;
     317                 :            : 
     318                 :            :   // Send our nodal volume contributions to neighbor chares
     319         [ +  + ]:       2459 :   if (m_nodeCommMap.empty()) {
     320                 :         71 :     comvol_complete();
     321                 :            :   } else {
     322         [ +  + ]:      26752 :     for (const auto& [c,n] : m_nodeCommMap) {
     323                 :      24364 :       std::vector< tk::real > v( n.size() );
     324                 :            :       std::size_t j = 0;
     325         [ +  + ]:     166764 :       for (auto i : n) v[ j++ ] = m_vol[ tk::cref_find(m_lid,i) ];
     326 [ +  - ][ +  - ]:      73092 :       thisProxy[c].comvol( thisIndex,
         [ +  - ][ -  - ]
     327 [ +  - ][ -  + ]:      48728 :                            std::vector<std::size_t>(begin(n), end(n)), v );
                 [ -  - ]
     328                 :            :     }
     329                 :            :   }
     330                 :            : 
     331                 :       2459 :   ownvol_complete();
     332                 :       2459 : }
     333                 :            : 
     334                 :            : void
     335                 :      24364 : Discretization::comvol( int c,
     336                 :            :                         const std::vector< std::size_t >& gid,
     337                 :            :                         const std::vector< tk::real >& nodevol )
     338                 :            : // *****************************************************************************
     339                 :            : //  Receive nodal volumes on chare-boundaries
     340                 :            : //! \param[in] c Sender chare id
     341                 :            : //! \param[in] gid Global mesh node IDs at which we receive volume contributions
     342                 :            : //! \param[in] nodevol Partial sums of nodal volume contributions to
     343                 :            : //!    chare-boundary nodes
     344                 :            : // *****************************************************************************
     345                 :            : {
     346                 :            :   Assert( nodevol.size() == gid.size(), "Size mismatch" );
     347                 :            : 
     348                 :            :   auto& cvolc = m_cvolc[c];
     349         [ +  + ]:     166764 :   for (std::size_t i=0; i<gid.size(); ++i) {
     350                 :     142400 :     m_volc[ gid[i] ] += nodevol[i];
     351                 :     142400 :     cvolc[ tk::cref_find(m_lid,gid[i]) ] = nodevol[i];
     352                 :            :   }
     353                 :            : 
     354         [ +  + ]:      24364 :   if (++m_nvol == m_nodeCommMap.size()) {
     355                 :       2388 :     m_nvol = 0;
     356                 :       2388 :     comvol_complete();
     357                 :            :   }
     358                 :      24364 : }
     359                 :            : 
     360                 :            : void
     361                 :       2459 : Discretization::totalvol()
     362                 :            : // *****************************************************************************
     363                 :            : // Sum mesh volumes and contribute own mesh volume to total volume
     364                 :            : // *****************************************************************************
     365                 :            : {
     366                 :            :   // Add received contributions to nodal volumes
     367         [ +  + ]:      85562 :   for (const auto& [gid, vol] : m_volc)
     368                 :      83103 :     m_vol[ tk::cref_find(m_lid,gid) ] += vol;
     369                 :            : 
     370                 :            :   // Clear receive buffer
     371                 :       2459 :   tk::destroy(m_volc);
     372                 :            : 
     373                 :            :   // Sum mesh volume to host
     374                 :            :   std::vector< tk::real > tvol{ 0.0,
     375                 :       2459 :                                 static_cast<tk::real>(m_initial),
     376                 :       2459 :                                 static_cast<tk::real>(m_meshid) };
     377         [ +  + ]:     278519 :   for (auto v : m_v) tvol[0] += v;
     378         [ +  - ]:       2459 :   contribute( tvol, CkReduction::sum_double,
     379 [ +  - ][ -  - ]:       2459 :     CkCallback(CkReductionTarget(Transporter,totalvol), m_transporter) );
     380                 :       2459 : }
     381                 :            : 
     382                 :            : void
     383                 :       2459 : Discretization::stat( tk::real mesh_volume )
     384                 :            : // *****************************************************************************
     385                 :            : // Compute mesh cell statistics
     386                 :            : //! \param[in] mesh_volume Total mesh volume
     387                 :            : // *****************************************************************************
     388                 :            : {
     389                 :            :   // Store total mesh volume
     390                 :       2459 :   m_meshvol = mesh_volume;
     391                 :            : 
     392                 :            :   const auto& x = m_coord[0];
     393                 :            :   const auto& y = m_coord[1];
     394                 :            :   const auto& z = m_coord[2];
     395                 :            : 
     396                 :       2459 :   auto MIN = -std::numeric_limits< tk::real >::max();
     397                 :       2459 :   auto MAX = std::numeric_limits< tk::real >::max();
     398                 :       2459 :   std::vector< tk::real > min( 6, MAX );
     399 [ +  - ][ -  - ]:       2459 :   std::vector< tk::real > max( 6, MIN );
     400 [ +  - ][ +  - ]:       2459 :   std::vector< tk::real > sum( 9, 0.0 );
                 [ -  - ]
     401                 :            :   tk::UniPDF edgePDF( 1e-4 );
     402                 :            :   tk::UniPDF volPDF( 1e-4 );
     403                 :            :   tk::UniPDF ntetPDF( 1e-4 );
     404                 :            : 
     405                 :            :   // Compute points surrounding points
     406 [ +  - ][ +  - ]:       2459 :   auto psup = tk::genPsup( m_inpoel, 4, tk::genEsup(m_inpoel,4) );
     407                 :            :   Assert( psup.second.size()-1 == m_gid.size(),
     408                 :            :           "Number of mesh points and number of global IDs unequal" );
     409                 :            : 
     410                 :            :   // Compute edge length statistics
     411                 :            :   // Note that while the min and max edge lengths are independent of the number
     412                 :            :   // of CPUs (by the time they are aggregated across all chares), the sum of
     413                 :            :   // the edge lengths and the edge length PDF are not. This is because the
     414                 :            :   // edges on the chare-boundary are counted multiple times and we
     415                 :            :   // conscientiously do not make an effort to precisely compute this, because
     416                 :            :   // that would require communication and more complex logic. Since these
     417                 :            :   // statistics are intended as simple average diagnostics, we ignore these
     418                 :            :   // small differences. For reproducible average edge lengths and edge length
     419                 :            :   // PDFs, run the mesh in serial.
     420                 :            :   tk::UnsMesh::EdgeSet edges;
     421         [ +  + ]:     278519 :   for (std::size_t p=0; p<m_gid.size(); ++p) {
     422 [ +  + ][ +  + ]:    3129662 :     for (auto i : tk::Around(psup,p)) {
     423                 :    2853602 :        const auto dx = x[ i ] - x[ p ];
     424                 :    2853602 :        const auto dy = y[ i ] - y[ p ];
     425                 :    2853602 :        const auto dz = z[ i ] - z[ p ];
     426         [ +  + ]:    2853602 :        const auto length = std::sqrt( dx*dx + dy*dy + dz*dz );
     427         [ +  + ]:    2853602 :        if (length < min[0]) min[0] = length;
     428         [ +  + ]:    2853602 :        if (length > max[0]) max[0] = length;
     429                 :    2853602 :        sum[0] += 1.0;
     430                 :    2853602 :        sum[1] += length;
     431         [ +  - ]:    2853602 :        edgePDF.add( length );
     432         [ +  - ]:    2853602 :        edges.insert( { m_gid[i], m_gid[p] } );
     433                 :            :     }
     434                 :            :   }
     435                 :            : 
     436                 :            :   // Compute mesh cell volume statistics
     437         [ +  + ]:     974902 :   for (std::size_t e=0; e<m_inpoel.size()/4; ++e) {
     438         [ +  + ]:     972443 :     const std::array< std::size_t, 4 > N{{ m_inpoel[e*4+0], m_inpoel[e*4+1],
     439         [ +  + ]:     972443 :                                            m_inpoel[e*4+2], m_inpoel[e*4+3] }};
     440                 :            :     const std::array< tk::real, 3 >
     441                 :     972443 :       ba{{ x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]] }},
     442                 :     972443 :       ca{{ x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]] }},
     443         [ +  + ]:     972443 :       da{{ x[N[3]]-x[N[0]], y[N[3]]-y[N[0]], z[N[3]]-z[N[0]] }};
     444                 :     972443 :     const auto L = std::cbrt( tk::triple( ba, ca, da ) / 6.0 );
     445         [ +  + ]:     972443 :     if (L < min[1]) min[1] = L;
     446         [ +  + ]:     972443 :     if (L > max[1]) max[1] = L;
     447                 :     972443 :     sum[2] += 1.0;
     448                 :     972443 :     sum[3] += L;
     449         [ +  - ]:     972443 :     volPDF.add( L );
     450                 :            :   }
     451                 :            : 
     452                 :            :   // Contribute statistics
     453                 :       2459 :   sum[4] = 1.0;
     454                 :       2459 :   min[2] = max[2] = sum[5] = static_cast< tk::real >( m_inpoel.size() / 4 );
     455                 :       2459 :   min[3] = max[3] = sum[6] = static_cast< tk::real >( m_gid.size() );
     456                 :       2459 :   min[4] = max[4] = sum[7] = static_cast< tk::real >( edges.size() );
     457                 :       2459 :   min[5] = max[5] = sum[8] =
     458                 :       2459 :     static_cast< tk::real >( tk::sumvalsize(m_nodeCommMap) ) /
     459                 :            :     static_cast< tk::real >( m_gid.size() );
     460         [ +  - ]:       2459 :   ntetPDF.add( min[2] );
     461                 :            : 
     462         [ +  - ]:       2459 :   min.push_back( static_cast<tk::real>(m_meshid) );
     463         [ +  - ]:       2459 :   max.push_back( static_cast<tk::real>(m_meshid) );
     464         [ +  - ]:       2459 :   sum.push_back( static_cast<tk::real>(m_meshid) );
     465                 :            : 
     466                 :            :   // Contribute to mesh statistics across all Discretization chares
     467         [ +  - ]:       2459 :   contribute( min, CkReduction::min_double,
     468         [ +  - ]:       2459 :     CkCallback(CkReductionTarget(Transporter,minstat), m_transporter) );
     469                 :            :   contribute( max, CkReduction::max_double,
     470         [ +  - ]:       2459 :     CkCallback(CkReductionTarget(Transporter,maxstat), m_transporter) );
     471                 :            :   contribute( sum, CkReduction::sum_double,
     472                 :       2459 :     CkCallback(CkReductionTarget(Transporter,sumstat), m_transporter) );
     473                 :            : 
     474                 :            :   // Serialize PDFs to raw stream
     475 [ +  - ][ +  - ]:       9836 :   auto stream = tk::serialize( m_meshid, { edgePDF, volPDF, ntetPDF } );
         [ +  + ][ +  - ]
                 [ -  - ]
     476                 :            :   // Create Charm++ callback function for reduction of PDFs with
     477                 :            :   // Transporter::pdfstat() as the final target where the results will appear.
     478                 :            :   CkCallback cb( CkIndex_Transporter::pdfstat(nullptr), m_transporter );
     479                 :            :   // Contribute serialized PDF of partial sums to host via Charm++ reduction
     480         [ +  - ]:       2459 :   contribute( stream.first, stream.second.get(), PDFMerger, cb );
     481 [ +  - ][ +  - ]:       7377 : }
         [ +  - ][ -  - ]
     482                 :            : 
     483                 :            : void
     484                 :       2459 : Discretization::boxvol()
     485                 :            : // *****************************************************************************
     486                 :            : // Compute total box IC volume
     487                 :            : // *****************************************************************************
     488                 :            : {
     489                 :            :   // Determine which nodes reside in user-defined IC box(es) if any
     490                 :       2459 :   m_boxnodes = problems::boxnodes( m_coord );
     491                 :            : 
     492                 :            :   // Compute partial box IC volume (just add up all boxes)
     493                 :            :   tk::real boxvol = 0.0;
     494                 :            :   // cppcheck-suppress useStlAlgorithm
     495 [ +  + ][ +  + ]:       3938 :   for (const auto& b : m_boxnodes) for (auto i : b) boxvol += m_v[i];
     496                 :            : 
     497                 :            :   // Sum up box IC volume across all chares
     498                 :       2459 :   std::vector< tk::real > meshdata{ boxvol, static_cast<tk::real>(m_meshid) };
     499         [ +  - ]:       2459 :   contribute( meshdata, CkReduction::sum_double,
     500 [ +  - ][ -  - ]:       2459 :     CkCallback(CkReductionTarget(Transporter,boxvol), m_transporter) );
     501                 :       2459 : }
     502                 :            : 
     503                 :            : void
     504                 :       3270 : Discretization::write(
     505                 :            :   const std::vector< std::size_t >& inpoel,
     506                 :            :   const tk::UnsMesh::Coords& coord,
     507                 :            :   const std::map< int, std::vector< std::size_t > >& bface,
     508                 :            :   const std::map< int, std::vector< std::size_t > >& bnode,
     509                 :            :   const std::vector< std::size_t >& triinpoel,
     510                 :            :   const std::vector< std::string>& elemfieldnames,
     511                 :            :   const std::vector< std::string>& nodefieldnames,
     512                 :            :   const std::vector< std::string>& elemsurfnames,
     513                 :            :   const std::vector< std::string>& nodesurfnames,
     514                 :            :   const std::vector< std::vector< tk::real > >& elemfields,
     515                 :            :   const std::vector< std::vector< tk::real > >& nodefields,
     516                 :            :   const std::vector< std::vector< tk::real > >& elemsurfs,
     517                 :            :   const std::vector< std::vector< tk::real > >& nodesurfs,
     518                 :            :   CkCallback c )
     519                 :            : // *****************************************************************************
     520                 :            : //  Output mesh and fields data (solution dump) to file(s)
     521                 :            : //! \param[in] inpoel Mesh connectivity for the mesh chunk to be written
     522                 :            : //! \param[in] coord Node coordinates of the mesh chunk to be written
     523                 :            : //! \param[in] bface Map of boundary-face lists mapped to corresponding side set
     524                 :            : //!   ids for this mesh chunk
     525                 :            : //! \param[in] bnode Map of boundary-node lists mapped to corresponding side set
     526                 :            : //!   ids for this mesh chunk
     527                 :            : //! \param[in] triinpoel Interconnectivity of points and boundary-face in this
     528                 :            : //!   mesh chunk
     529                 :            : //! \param[in] elemfieldnames Names of element fields to be output to file
     530                 :            : //! \param[in] nodefieldnames Names of node fields to be output to file
     531                 :            : //! \param[in] elemsurfnames Names of elem surface fields to be output to file
     532                 :            : //! \param[in] nodesurfnames Names of node surface fields to be output to file
     533                 :            : //! \param[in] elemfields Field data in mesh elements to output to file
     534                 :            : //! \param[in] nodefields Field data in mesh nodes to output to file
     535                 :            : //! \param[in] elemsurfs Surface field data in mesh elements to output to file
     536                 :            : //! \param[in] nodesurfs Surface field data in mesh nodes to output to file
     537                 :            : //! \param[in] c Function to continue with after the write
     538                 :            : //! \details Since m_meshwriter is a Charm++ chare group, it never migrates and
     539                 :            : //!   an instance is guaranteed on every PE. We index the first PE on every
     540                 :            : //!   logical compute node. In Charm++'s non-SMP mode, a node is the same as a
     541                 :            : //!   PE, so the index is the same as CkMyPe(). In SMP mode the index is the
     542                 :            : //!   first PE on every logical node. In non-SMP mode this yields one or more
     543                 :            : //!   output files per PE with zero or non-zero virtualization, respectively. If
     544                 :            : //!   there are multiple chares on a PE, the writes are serialized per PE, since
     545                 :            : //!   only a single entry method call can be executed at any given time. In SMP
     546                 :            : //!   mode, still the same number of files are output (one per chare), but the
     547                 :            : //!   output is serialized through the first PE of each compute node. In SMP
     548                 :            : //!   mode, channeling multiple files via a single PE on each node is required
     549                 :            : //!   by NetCDF and HDF5, as well as ExodusII, since none of these libraries are
     550                 :            : //!   thread-safe.
     551                 :            : // *****************************************************************************
     552                 :            : {
     553                 :            :   // If the previous iteration refined (or moved) the mesh or this is called
     554                 :            :   // before the first time step, we also output the mesh.
     555                 :       3270 :   bool meshoutput = m_itf == 0 ? true : false;
     556                 :            : 
     557                 :            :   auto eps = std::numeric_limits< tk::real >::epsilon();
     558                 :       3270 :   bool fieldoutput = false;
     559                 :            : 
     560                 :            :   // Output field data only if there is no dump at this physical time yet
     561         [ +  - ]:       3270 :   if (std::abs(m_lastDumpTime - m_t) > eps ) {
     562                 :       3270 :     m_lastDumpTime = m_t;
     563                 :       3270 :     ++m_itf;
     564                 :       3270 :     fieldoutput = true;
     565                 :            :   }
     566                 :            : 
     567                 :            :   const auto& f = g_cfg.get< tag::fieldout >();
     568                 :       3270 :   std::set< int > outsets( begin(f), end(f) );
     569                 :            : 
     570                 :            :   m_meshwriter[ CkNodeFirst( CkMyNode() ) ].
     571 [ +  - ][ +  - ]:       9810 :     write( m_meshid, meshoutput, fieldoutput, m_itr, m_itf, m_t, thisIndex,
     572                 :            :            g_cfg.get< tag::output >(),
     573                 :            :            inpoel, coord, bface, bnode, triinpoel, elemfieldnames,
     574                 :            :            nodefieldnames, elemsurfnames, nodesurfnames, elemfields, nodefields,
     575                 :            :            elemsurfs, nodesurfs, outsets, c );
     576                 :       3270 : }
     577                 :            : 
     578                 :            : void
     579                 :      38286 : Discretization::setdt( tk::real newdt )
     580                 :            : // *****************************************************************************
     581                 :            : // Set time step size
     582                 :            : //! \param[in] newdt Size of the new time step
     583                 :            : // *****************************************************************************
     584                 :            : {
     585                 :      38286 :   m_dtn = m_dt;
     586                 :      38286 :   m_dt = newdt;
     587                 :            : 
     588                 :            :   // Truncate the size of last time step
     589                 :      38286 :   const auto term = g_cfg.get< tag::term >();
     590         [ +  + ]:      38286 :   if (m_t+m_dt > term) m_dt = term - m_t;
     591                 :      38286 : }
     592                 :            : 
     593                 :            : void
     594                 :      38318 : Discretization::next()
     595                 :            : // *****************************************************************************
     596                 :            : // Prepare for next step
     597                 :            : // *****************************************************************************
     598                 :            : {
     599                 :            :   // Update floor of physics time divided by output interval times
     600                 :            :   const auto eps = std::numeric_limits< tk::real >::epsilon();
     601                 :      38318 :   const auto ft = g_cfg.get< tag::fieldout_time >();
     602         [ +  - ]:      38318 :   if (ft > eps) m_physFieldFloor = std::floor( m_t / ft );
     603                 :      38318 :   const auto ht = g_cfg.get< tag::histout_time >();
     604         [ +  - ]:      38318 :   if (ht > eps) m_physHistFloor = std::floor( m_t / ht );
     605                 :      38318 :   const auto it = g_cfg.get< tag::integout_time >();
     606         [ +  - ]:      38318 :   if (it > eps) m_physIntegFloor = std::floor( m_t / it );
     607                 :            : 
     608                 :            :   // Update floors of physics time divided by output interval times for ranges
     609                 :            :   const auto& rf = g_cfg.get< tag::fieldout_range >();
     610         [ +  + ]:      38718 :   for (std::size_t i=0; i<rf.size(); ++i) {
     611 [ +  + ][ +  + ]:        400 :     if (m_t > rf[i][0] and m_t < rf[i][1]) {
     612                 :         32 :       m_rangeFieldFloor[i] = std::floor( m_t / rf[i][2] );
     613                 :            :     }
     614                 :            :   }
     615                 :            : 
     616                 :            :   const auto& rh = g_cfg.get< tag::histout_range >();
     617         [ +  + ]:      40558 :   for (std::size_t i=0; i<rh.size(); ++i) {
     618 [ +  + ][ +  + ]:       2240 :     if (m_t > rh[i][0] and m_t < rh[i][1]) {
     619                 :        620 :       m_rangeHistFloor[i] = std::floor( m_t / rh[i][2] );
     620                 :            :     }
     621                 :            :   }
     622                 :            : 
     623                 :            :   const auto& ri = g_cfg.get< tag::integout_range >();
     624         [ +  + ]:      38358 :   for (std::size_t i=0; i<ri.size(); ++i) {
     625 [ +  + ][ +  + ]:         40 :     if (m_t > ri[i][0] and m_t < ri[i][1]) {
     626                 :         10 :       m_rangeIntegFloor[i] = std::floor( m_t / ri[i][2] );
     627                 :            :     }
     628                 :            :   }
     629                 :            : 
     630                 :      38318 :   ++m_it;
     631                 :      38318 :   m_t += m_dt;
     632                 :      38318 : }
     633                 :            : 
     634                 :            : void
     635                 :       2452 : Discretization::grindZero()
     636                 :            : // *****************************************************************************
     637                 :            : //  Zero grind-time
     638                 :            : // *****************************************************************************
     639                 :            : {
     640                 :       2452 :   m_prevstatus = std::chrono::high_resolution_clock::now();
     641                 :            : 
     642 [ +  + ][ +  - ]:       2452 :   if (thisIndex == 0 && m_meshid == 0) {
     643                 :            :     tk::Print() << "Starting time stepping ...\n";
     644                 :            :   }
     645                 :       2452 : }
     646                 :            : 
     647                 :            : bool
     648                 :      35859 : Discretization::restarted( int nrestart )
     649                 :            : // *****************************************************************************
     650                 :            : //  Detect if just returned from a checkpoint and if so, zero timers
     651                 :            : //! \param[in] nrestart Number of times restarted
     652                 :            : //! \return True if restart detected
     653                 :            : // *****************************************************************************
     654                 :            : {
     655                 :            :   // Detect if just restarted from checkpoint:
     656                 :            :   //   nrestart == -1 if there was no checkpoint this step
     657                 :            :   //   m_nrestart == nrestart if there was a checkpoint this step
     658                 :            :   //   if both false, just restarted from a checkpoint
     659 [ +  + ][ +  - ]:      35859 :   bool restarted = nrestart != -1 and m_nrestart != nrestart;
     660                 :            : 
     661                 :            :    // If just restarted from checkpoint
     662                 :            :   if (restarted) {
     663                 :            :     // Update number of restarts
     664                 :         25 :     m_nrestart = nrestart;
     665                 :            :     // Start timer measuring time stepping wall clock time
     666                 :         25 :     m_timer.zero();
     667                 :            :     // Zero grind-timer
     668                 :         25 :     grindZero();
     669                 :            :   }
     670                 :            : 
     671                 :      35859 :   return restarted;
     672                 :            : }
     673                 :            : 
     674                 :            : std::string
     675                 :        726 : Discretization::histfilename( const std::string& id, std::streamsize precision )
     676                 :            : // *****************************************************************************
     677                 :            : //  Construct history output filename
     678                 :            : //! \param[in] id History point id
     679                 :            : //! \param[in] precision Floating point precision to use for output
     680                 :            : //! \return History file name
     681                 :            : // *****************************************************************************
     682                 :            : {
     683                 :            :   auto of = g_cfg.get< tag::output >();
     684         [ +  - ]:        726 :   std::stringstream ss;
     685                 :            : 
     686         [ +  - ]:        726 :   ss << std::setprecision(static_cast<int>(precision)) << of << ".hist." << id;
     687                 :            : 
     688                 :        726 :   return ss.str();
     689                 :        726 : }
     690                 :            : 
     691                 :            : void
     692                 :         74 : Discretization::histheader( std::vector< std::string >&& names )
     693                 :            : // *****************************************************************************
     694                 :            : //  Output headers for time history files (one for each point)
     695                 :            : //! \param[in] names History output variable names
     696                 :            : // *****************************************************************************
     697                 :            : {
     698         [ +  + ]:        149 :   for (const auto& h : m_histdata) {
     699                 :         75 :     auto prec = g_cfg.get< tag::histout_precision >();
     700                 :         75 :     tk::DiagWriter hw( histfilename( h.get< tag::id >(), prec ),
     701                 :            :                        g_cfg.get< tag::histout_format >(),
     702         [ +  - ]:         75 :                        prec );
     703         [ +  - ]:         75 :     hw.header( names );
     704                 :            :   }
     705                 :         74 : }
     706                 :            : 
     707                 :            : void
     708                 :       1238 : Discretization::history( std::vector< std::vector< tk::real > >&& data )
     709                 :            : // *****************************************************************************
     710                 :            : //  Output time history for a time step
     711                 :            : //! \param[in] data Time history data for all variables and equations integrated
     712                 :            : // *****************************************************************************
     713                 :            : {
     714                 :            :   Assert( data.size() == m_histdata.size(), "Size mismatch" );
     715                 :            : 
     716                 :            :   std::size_t i = 0;
     717         [ +  + ]:       1889 :   for (const auto& h : m_histdata) {
     718                 :        651 :     auto prec = g_cfg.get< tag::histout_precision >();
     719         [ +  - ]:       1302 :     tk::DiagWriter hw( histfilename( h.get< tag::id >(), prec ),
     720                 :            :                        g_cfg.get< tag::histout_format >(),
     721                 :            :                        prec,
     722         [ +  - ]:        651 :                        std::ios_base::app );
     723         [ +  - ]:        651 :     hw.write( m_it, m_t, m_dt, data[i] );
     724                 :        651 :     ++i;
     725                 :            :   }
     726                 :       1238 : }
     727                 :            : 
     728                 :            : bool
     729                 :      41138 : Discretization::fielditer() const
     730                 :            : // *****************************************************************************
     731                 :            : //  Decide if field output iteration count interval is hit
     732                 :            : //! \return True if field output iteration count interval is hit
     733                 :            : // *****************************************************************************
     734                 :            : {
     735         [ +  + ]:      41138 :   if (g_cfg.get< tag::benchmark >()) return false;
     736                 :            : 
     737                 :      22538 :   return m_it % g_cfg.get< tag::fieldout_iter >() == 0;
     738                 :            : }
     739                 :            : 
     740                 :            : bool
     741                 :      38617 : Discretization::fieldtime() const
     742                 :            : // *****************************************************************************
     743                 :            : //  Decide if field output physics time interval is hit
     744                 :            : //! \return True if field output physics time interval is hit
     745                 :            : // *****************************************************************************
     746                 :            : {
     747         [ +  + ]:      38617 :   if (g_cfg.get< tag::benchmark >()) return false;
     748                 :            : 
     749                 :            :   auto eps = std::numeric_limits< tk::real >::epsilon();
     750                 :      20017 :   auto ft = g_cfg.get< tag::fieldout_time >();
     751                 :            : 
     752         [ +  - ]:      20017 :   if (ft < eps) return false;
     753                 :            : 
     754                 :      20017 :   return std::floor(m_t/ft) - m_physFieldFloor > eps;
     755                 :            : }
     756                 :            : 
     757                 :            : bool
     758                 :      38593 : Discretization::fieldrange() const
     759                 :            : // *****************************************************************************
     760                 :            : //  Decide if physics time falls into a field output time range
     761                 :            : //! \return True if physics time falls into a field output time range
     762                 :            : // *****************************************************************************
     763                 :            : {
     764         [ +  + ]:      38593 :   if (g_cfg.get< tag::benchmark >()) return false;
     765                 :            : 
     766                 :            :   const auto eps = std::numeric_limits< tk::real >::epsilon();
     767                 :            : 
     768                 :            :   bool output = false;
     769                 :            : 
     770                 :            :   const auto& rf = g_cfg.get< tag::fieldout_range >();
     771         [ +  + ]:      20493 :   for (std::size_t i=0; i<rf.size(); ++i) {
     772 [ +  + ][ +  + ]:        500 :     if (m_t > rf[i][0] and m_t < rf[i][1]) {
     773                 :         40 :       output |= std::floor(m_t/rf[i][2]) - m_rangeFieldFloor[i] > eps;
     774                 :            :     }
     775                 :            :   }
     776                 :            : 
     777                 :            :   return output;
     778                 :            : }
     779                 :            : 
     780                 :            : bool
     781                 :      41138 : Discretization::histiter() const
     782                 :            : // *****************************************************************************
     783                 :            : //  Decide if history output iteration count interval is hit
     784                 :            : //! \return True if history output iteration count interval is hit
     785                 :            : // *****************************************************************************
     786                 :            : {
     787         [ +  + ]:      41138 :   if (g_cfg.get< tag::benchmark >()) return false;
     788                 :            : 
     789                 :      22538 :   auto hist = g_cfg.get< tag::histout_iter >();
     790                 :            :   const auto& hist_points = g_cfg.get< tag::histout >();
     791                 :            : 
     792 [ +  + ][ -  + ]:      22538 :   return m_it % hist == 0 and not hist_points.empty();
     793                 :            : }
     794                 :            : 
     795                 :            : bool
     796                 :      40352 : Discretization::histtime() const
     797                 :            : // *****************************************************************************
     798                 :            : //  Decide if history output physics time interval is hit
     799                 :            : //! \return True if history output physics time interval is hit
     800                 :            : // *****************************************************************************
     801                 :            : {
     802         [ +  + ]:      40352 :   if (g_cfg.get< tag::benchmark >()) return false;
     803                 :            : 
     804                 :            :   auto eps = std::numeric_limits< tk::real >::epsilon();
     805                 :      21752 :   auto ht = g_cfg.get< tag::histout_time >();
     806                 :            : 
     807         [ +  - ]:      21752 :   if (ht < eps) return false;
     808                 :            : 
     809                 :      21752 :   return std::floor(m_t/ht) - m_physHistFloor > eps;
     810                 :            : }
     811                 :            : 
     812                 :            : bool
     813                 :      40094 : Discretization::histrange() const
     814                 :            : // *****************************************************************************
     815                 :            : //  Decide if physics time falls into a history output time range
     816                 :            : //! \return True if physics time falls into a history output time range
     817                 :            : // *****************************************************************************
     818                 :            : {
     819         [ +  + ]:      40094 :   if (g_cfg.get< tag::benchmark >()) return false;
     820                 :            : 
     821                 :            :   auto eps = std::numeric_limits< tk::real >::epsilon();
     822                 :            : 
     823                 :            :   bool output = false;
     824                 :            : 
     825                 :            :   const auto& rh = g_cfg.get< tag::histout_range >();
     826         [ +  + ]:      23654 :   for (std::size_t i=0; i<rh.size(); ++i) {
     827 [ +  + ][ +  + ]:       2160 :     if (m_t > rh[i][0] and m_t < rh[i][1]) {
     828                 :        590 :       output |= std::floor(m_t/rh[i][2]) - m_rangeHistFloor[i] > eps;
     829                 :            :     }
     830                 :            :   }
     831                 :            : 
     832                 :            :   return output;
     833                 :            : }
     834                 :            : 
     835                 :            : bool
     836                 :      41138 : Discretization::integiter() const
     837                 :            : // *****************************************************************************
     838                 :            : //  Decide if integral output iteration count interval is hit
     839                 :            : //! \return True if integral output iteration count interval is hit
     840                 :            : // *****************************************************************************
     841                 :            : {
     842         [ +  + ]:      41138 :   if (g_cfg.get< tag::benchmark >()) return false;
     843                 :            : 
     844                 :      22538 :   auto integ = g_cfg.get< tag::integout_iter >();
     845                 :            :   const auto& sidesets_integral = g_cfg.get< tag::integout >();
     846                 :            : 
     847 [ +  + ][ -  + ]:      22538 :   return m_it % integ == 0 and not sidesets_integral.empty();
     848                 :            : }
     849                 :            : 
     850                 :            : bool
     851                 :      40878 : Discretization::integtime() const
     852                 :            : // *****************************************************************************
     853                 :            : //  Decide if integral output physics time interval is hit
     854                 :            : //! \return True if integral output physics time interval is hit
     855                 :            : // *****************************************************************************
     856                 :            : {
     857         [ +  + ]:      40878 :   if (g_cfg.get< tag::benchmark >()) return false;
     858                 :            : 
     859                 :            :   auto eps = std::numeric_limits< tk::real >::epsilon();
     860                 :      22278 :   auto it = g_cfg.get< tag::integout_time >();
     861                 :            : 
     862         [ +  - ]:      22278 :   if (it < eps) return false;
     863                 :            : 
     864                 :      22278 :   return std::floor(m_t/it) - m_physIntegFloor > eps;
     865                 :            : }
     866                 :            : 
     867                 :            : bool
     868                 :      40851 : Discretization::integrange() const
     869                 :            : // *****************************************************************************
     870                 :            : //  Decide if physics time falls into a integral output time range
     871                 :            : //! \return True if physics time falls into a integral output time range
     872                 :            : // *****************************************************************************
     873                 :            : {
     874         [ +  + ]:      40851 :   if (g_cfg.get< tag::benchmark >()) return false;
     875                 :            : 
     876                 :            :   auto eps = std::numeric_limits< tk::real >::epsilon();
     877                 :            : 
     878                 :            :   bool output = false;
     879                 :            : 
     880                 :            :   const auto& ri = g_cfg.get< tag::integout_range >();
     881         [ +  + ]:      22311 :   for (std::size_t i=0; i<ri.size(); ++i) {
     882 [ +  + ][ +  + ]:         60 :     if (m_t > ri[i][0] and m_t < ri[i][1]) {
     883                 :         15 :       output |= std::floor(m_t/ri[i][2]) - m_rangeIntegFloor[i] > eps;
     884                 :            :     }
     885                 :            :   }
     886                 :            : 
     887                 :            :   return output;
     888                 :            : }
     889                 :            : 
     890                 :            : bool
     891                 :      42753 : Discretization::finished() const
     892                 :            : // *****************************************************************************
     893                 :            : //  Decide if this is the last time step
     894                 :            : //! \return True if this is the last time step
     895                 :            : // *****************************************************************************
     896                 :            : {
     897                 :            :   auto eps = std::numeric_limits< tk::real >::epsilon();
     898                 :      42753 :   auto nstep = g_cfg.get< tag::nstep >();
     899                 :      42753 :   auto term = g_cfg.get< tag::term >();
     900                 :      42753 :   auto residual = g_cfg.get< tag::residual >();
     901                 :            : 
     902 [ +  + ][ +  + ]:      42753 :   return std::abs(m_t-term) < eps or m_it >= nstep or
     903 [ +  + ][ -  + ]:      39906 :          (m_res > 0.0 and m_res < residual);
     904                 :            : }
     905                 :            : 
     906                 :            : void
     907                 :       1010 : Discretization::residual( tk::real r )
     908                 :            : // *****************************************************************************
     909                 :            : //  Update residual (during convergence to steady state)
     910                 :            : //! \param[in] r Current residual
     911                 :            : // *****************************************************************************
     912                 :            : {
     913                 :       1010 :   auto ttyi = g_cfg.get< tag::ttyi >();
     914                 :            : 
     915         [ +  - ]:       1010 :   if (m_it % ttyi == 0) {
     916                 :       1010 :     m_res0 = m_res1;
     917                 :       1010 :     m_res1 = r;
     918                 :            :   }
     919                 :            : 
     920                 :       1010 :   m_res = r;
     921                 :       1010 : }
     922                 :            : 
     923                 :            : bool
     924                 :         55 : Discretization::deastart()
     925                 :            : // *****************************************************************************
     926                 :            : //  Decide whether to start the deactivation procedure in this time step
     927                 :            : //! \return True to start the deactivation prcedure in this time step
     928                 :            : // *****************************************************************************
     929                 :            : {
     930 [ +  + ][ +  - ]:         55 :   if (not m_deastarted and m_t > g_cfg.get<tag::deatime>() + m_dt) {
     931                 :         19 :     m_deastarted = 1;
     932                 :         19 :     return true;
     933                 :            :   }
     934                 :            : 
     935                 :            :   return false;
     936                 :            : }
     937                 :            : 
     938                 :            : bool
     939                 :       6086 : Discretization::deactivate() const
     940                 :            : // *****************************************************************************
     941                 :            : //  Decide whether to run deactivation procedure in this time step
     942                 :            : //! \return True to run deactivation prcedure in this time step
     943                 :            : // *****************************************************************************
     944                 :            : {
     945                 :       6086 :   auto dea = g_cfg.get< tag::deactivate >();
     946                 :       6086 :   auto deafreq = g_cfg.get< tag::deafreq >();
     947                 :            : 
     948 [ +  + ][ +  - ]:       6086 :   if (dea and !m_nodeCommMap.empty() and m_it % deafreq == 0)
                 [ +  + ]
     949                 :            :     return true;
     950                 :            :   else
     951                 :       5886 :     return false;
     952                 :            : }
     953                 :            : 
     954                 :            : void
     955                 :         10 : Discretization::deactivated( int n )
     956                 :            : // *****************************************************************************
     957                 :            : //  Receive deactivation report
     958                 :            : //! \param[in] n Sum of deactivated chares
     959                 :            : // *****************************************************************************
     960                 :            : {
     961                 :         10 :   m_dea = n;
     962                 :         10 : }
     963                 :            : 
     964                 :            : bool
     965                 :      16972 : Discretization::lb() const
     966                 :            : // *****************************************************************************
     967                 :            : //  Decide whether to do load balancing this time step
     968                 :            : //! \return True to do load balancing in this time step
     969                 :            : // *****************************************************************************
     970                 :            : {
     971                 :      16972 :   auto lbfreq = g_cfg.get< tag::lbfreq >();
     972                 :      16972 :   auto lbtime = g_cfg.get< tag::lbtime >();
     973                 :            : 
     974 [ +  - ][ +  + ]:      16972 :   if ((m_t > lbtime and m_it % lbfreq == 0) or m_it == 2)
                 [ +  + ]
     975                 :            :     return true;
     976                 :            :   else
     977                 :       5114 :     return false;
     978                 :            : }
     979                 :            : 
     980                 :            : void
     981                 :        559 : Discretization::pit( std::size_t it )
     982                 :            : // *****************************************************************************
     983                 :            : //  Update number of pressure linear solve iterations taken
     984                 :            : //! \param[in] it Number of pressure linear solve iterations taken
     985                 :            : // *****************************************************************************
     986                 :            : {
     987                 :        559 :   m_pit = it;
     988                 :        559 : }
     989                 :            : 
     990                 :            : void
     991                 :         20 : Discretization::mit( std::size_t it )
     992                 :            : // *****************************************************************************
     993                 :            : //  Update number of momentum/transport linear solve iterations taken
     994                 :            : //! \param[in] it Number of momentum/transport linear solve iterations taken
     995                 :            : // *****************************************************************************
     996                 :            : {
     997                 :         20 :   m_mit = it;
     998                 :         20 : }
     999                 :            : 
    1000                 :            : void
    1001                 :        242 : Discretization::npoin( std::size_t n )
    1002                 :            : // *****************************************************************************
    1003                 :            : //  Set number of mesh points (across all meshes)
    1004                 :            : //! \param[in] n Number of mesh points
    1005                 :            : // *****************************************************************************
    1006                 :            : {
    1007                 :        242 :   m_npoin = n;
    1008                 :        242 : }
    1009                 :            : 
    1010                 :            : void
    1011                 :      18307 : Discretization::status()
    1012                 :            : // *****************************************************************************
    1013                 :            : // Output one-liner status report
    1014                 :            : // *****************************************************************************
    1015                 :            : {
    1016                 :      18307 :   const auto ttyi = g_cfg.get< tag::ttyi >();
    1017                 :            : 
    1018 [ +  + ][ +  - ]:      18307 :   if (thisIndex == 0 and m_meshid == 0 and m_it % ttyi == 0) {
                 [ +  + ]
    1019                 :            : 
    1020                 :            :     // estimate grind time (taken between this and the previous time step)
    1021                 :            :     using std::chrono::duration_cast;
    1022                 :            :     using us = std::chrono::microseconds;
    1023                 :            :     using clock = std::chrono::high_resolution_clock;
    1024                 :       2820 :     auto grind_time = duration_cast< us >(clock::now() - m_prevstatus).count()
    1025                 :       2820 :                       / static_cast< long >( ttyi );
    1026                 :       2820 :     auto grind_perf = static_cast<tk::real>(grind_time)
    1027                 :       2820 :                       / static_cast<tk::real>(m_npoin);
    1028                 :       2820 :     m_prevstatus = clock::now();
    1029                 :            : 
    1030                 :       2820 :     const auto term = g_cfg.get< tag::term >();
    1031                 :       2820 :     const auto t0 = g_cfg.get< tag::t0 >();
    1032                 :       2820 :     const auto nstep = g_cfg.get< tag::nstep >();
    1033                 :       2820 :     const auto diag = g_cfg.get< tag::diag_iter >();
    1034                 :       2820 :     const auto rsfreq = g_cfg.get< tag::rsfreq >();
    1035                 :       2820 :     const auto benchmark = g_cfg.get< tag::benchmark >();
    1036                 :       2820 :     const auto residual = g_cfg.get< tag::residual >();
    1037                 :            :     const auto solver = g_cfg.get< tag::solver >();
    1038         [ +  + ]:       2820 :     const auto pre = solver == "chocg" ? 1 : 0;
    1039                 :       2820 :     const auto theta = g_cfg.get< tag::theta >();
    1040                 :            :     const auto eps = std::numeric_limits< tk::real >::epsilon();
    1041 [ +  + ][ +  + ]:       2820 :     const auto mom = solver == "chocg" and theta > eps ? 1 : 0;
    1042                 :            : 
    1043                 :            :     // estimate time elapsed and time for accomplishment
    1044                 :            :     tk::Timer::Watch ete, eta;
    1045         [ +  - ]:       2820 :     m_timer.eta( term-t0, m_t-t0, nstep, m_it, m_res0, m_res1, residual,
    1046                 :            :                  ete, eta );
    1047                 :            : 
    1048                 :            :     tk::Print print;
    1049                 :            : 
    1050                 :            :     // Output one-liner
    1051                 :       5640 :     print << std::setfill(' ') << std::setw(8) << m_it << "  "
    1052                 :            :           << std::scientific << std::setprecision(6)
    1053                 :            :           << std::setw(12) << m_t << "  "
    1054                 :            :           << m_dt << "  "
    1055                 :       5640 :           << std::setfill('0')
    1056                 :            :           << std::setw(3) << ete.hrs.count() << ":"
    1057                 :            :           << std::setw(2) << ete.min.count() << ":"
    1058                 :            :           << std::setw(2) << ete.sec.count() << "  "
    1059                 :            :           << std::setw(3) << eta.hrs.count() << ":"
    1060                 :            :           << std::setw(2) << eta.min.count() << ":"
    1061                 :            :           << std::setw(2) << eta.sec.count() << "  "
    1062         [ -  - ]:          0 :           << std::scientific << std::setprecision(6) << std::setfill(' ')
    1063                 :            :           << std::setw(9) << grind_time << "  "
    1064 [ +  - ][ +  - ]:       8460 :           << std::setw(9) << grind_perf << "  ";
                 [ +  - ]
    1065                 :            : 
    1066                 :            :     // Augment one-liner status with output indicators
    1067 [ +  - ][ +  + ]:       2820 :     if (fielditer() or fieldtime() or fieldrange()) print << 'f';
         [ +  - ][ +  + ]
         [ +  - ][ +  + ]
    1068         [ +  - ]:       2820 :     if (not (m_it % diag)) print << 'd';
    1069 [ +  - ][ +  + ]:       2820 :     if (histiter() or histtime() or histrange()) print << 't';
         [ +  - ][ +  + ]
         [ +  - ][ +  + ]
    1070 [ +  - ][ +  + ]:       2820 :     if (integiter() or integtime() or integrange()) print << 'i';
         [ +  - ][ +  + ]
         [ +  - ][ +  + ]
    1071         [ -  + ]:       2820 :     if (m_refined) print << 'h';
    1072 [ +  - ][ +  + ]:       2820 :     if (lb() and not finished()) print << 'l';
         [ +  - ][ +  + ]
    1073 [ +  + ][ +  - ]:       2820 :     if (not benchmark && (not (m_it % rsfreq) || finished())) print << 'c';
         [ +  - ][ +  + ]
    1074 [ +  + ][ +  - ]:       2820 :     if (m_deastarted and deactivate()) {
                 [ +  + ]
    1075                 :            :       print << "\te:" << m_dea << '/' << m_nchare;
    1076                 :            :     }
    1077         [ +  + ]:       2820 :     if (pre) print << "\tp:" << m_pit;
    1078         [ +  + ]:       2820 :     if (mom) print << "\tm:" << m_mit;
    1079                 :            : 
    1080                 :            :     print << '\n';
    1081                 :            :   }
    1082                 :      18307 : }
    1083                 :            : 
    1084                 :            : #include "NoWarning/discretization.def.h"

Generated by: LCOV version 1.16