1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// *****************************************************************************
/*!
  \file      src/Inciter/DiagReducer.cpp
  \copyright 2012-2015 J. Bakosi,
             2016-2018 Los Alamos National Security, LLC.,
             2019-2021 Triad National Security, LLC.,
             2022-2024 J. Bakosi
             All rights reserved. See the LICENSE file for details.
  \brief     Custom Charm++ reducer for merging diagnostics across PEs
  \details   Custom Charm++ reducer for merging diagnostics across PEs.
*/
// *****************************************************************************

#include <stddef.h>
#include <type_traits>
#include <memory>

#include "DiagReducer.hpp"
#include "Diagnostics.hpp"
#include "Exception.hpp"

namespace inciter {
namespace diagnostics {

std::pair< int, std::unique_ptr<char[]> >
serialize( std::size_t meshid,
           std::size_t ncomp,
           const std::vector< std::vector< tk::real > >& d )
// *****************************************************************************
// Serialize diagnostics to raw memory stream
//! \param[in] meshid Mesh ID
//! \param[in] ncomp Number of scalar components whose diagnostics are computed
//! \param[in] d Diagnostics vector of vectors (of eq components)
//! \return Pair of the length and the raw stream containing the serialized
//!   vectors
// *****************************************************************************
{
  // Prepare for serializing diagnostics to a raw binary stream, compute size
  PUP::sizer sizer;
  sizer | meshid;
  sizer | ncomp;
  sizer | const_cast< std::vector< std::vector< tk::real > >& >( d );

  // Create raw character stream to store the serialized vectors
  std::unique_ptr<char[]> flatData = std::make_unique<char[]>( sizer.size() );

  // Serialize vector, each message will contain a vector
  PUP::toMem packer( flatData.get() );
  packer | meshid;
  packer | ncomp;
  packer | const_cast< std::vector< std::vector< tk::real > >& >( d );

  // Return size of and raw stream
  return { sizer.size(), std::move(flatData) };
}

CkReductionMsg*
mergeDiag( int nmsg, CkReductionMsg **msgs )
// *****************************************************************************
// Charm++ custom reducer for merging diagnostics during reduction across PEs
//! \param[in] nmsg Number of messages in msgs
//! \param[in] msgs Charm++ reduction message containing the serialized
//!   diagnostics
//! \return Aggregated diagnostics built for further aggregation if needed
// *****************************************************************************
{
  using namespace diagnostics;

  // Will store deserialized diagnostics vector of vectors
  std::size_t meshid;
  std::size_t ncomp;
  std::vector< std::vector< tk::real > > v;

  // Create PUP deserializer based on message passed in
  PUP::fromMem creator( msgs[0]->getData() );

  // Deserialize vector from raw stream
  // cppcheck-suppress uninitvar
  creator | meshid;
  creator | ncomp;<--- Uninitialized variable: ncomp
  creator | v;

  for (int m=1; m<nmsg; ++m) {
    // Unpack vector
    std::size_t mid;
    std::size_t nc;
    std::vector< std::vector< tk::real > > w;
    PUP::fromMem curCreator( msgs[m]->getData() );
    // cppcheck-suppress uninitvar
    curCreator | mid;
    curCreator | nc;<--- Uninitialized variable: nc
    curCreator | w;
    // Aggregate diagnostics vector
    // cppcheck-suppress uninitvar
    // cppcheck-suppress unreadVariable
    meshid = mid;<--- Unmatched suppression: uninitvar
    ncomp = nc;<--- Variable 'ncomp' is assigned a value that is never used.
    Assert( v.size() == w.size(),
            "Size mismatch during diagnostics aggregation" );
    Assert( v.size() == NUMDIAG,
            "Size mismatch during diagnostics aggregation" );
    // cppcheck-suppress unsignedLessThanZero
    for (std::size_t i=0; i<v.size(); ++i)
      Assert( v[i].size() == w[i].size(),
              "Size mismatch during diagnostics aggregation" );
    // Apply diagnostics aggregation policy
    // Sum for L2 normal of the numerical solution for all scalar components
    for (std::size_t i=0; i<v[L2SOL].size(); ++i) v[L2SOL][i] += w[L2SOL][i];<--- Access out of bounds<--- Access out of bounds
    // Sum for the L2 norm of the residual of all components
    for (std::size_t i=0; i<v[L2RES].size(); ++i) v[L2RES][i] += w[L2RES][i];<--- Access out of bounds<--- Access out of bounds
    // Sum of the total energy over the entire domain
    v[TOTALEN][0] += w[TOTALEN][0];<--- Access out of bounds<--- Access out of bounds
    // Sum for the L2 norm of the numerical - analytical solution for all comps
    for (std::size_t i=0; i<v[L2ERR].size(); ++i) v[L2ERR][i] += w[L2ERR][i];<--- Access out of bounds<--- Access out of bounds
    // Sum for the L1 norm of the numerical - analytical solution for all comps
    for (std::size_t i=0; i<v[L1ERR].size(); ++i) v[L1ERR][i] += w[L1ERR][i];<--- Access out of bounds<--- Access out of bounds
    // Copy ITER, TIME, DT
    for (std::size_t i=0; i<v[ITER].size(); ++i) v[ITER][i] = w[ITER][i];<--- Access out of bounds<--- Access out of bounds
    for (std::size_t i=0; i<v[TIME].size(); ++i) v[TIME][i] = w[TIME][i];<--- Access out of bounds<--- Access out of bounds
    for (std::size_t i=0; i<v[DT].size(); ++i) v[DT][i] = w[DT][i];<--- Access out of bounds<--- Access out of bounds
  }

  // Serialize concatenated diagnostics vector to raw stream
  auto stream = serialize( meshid, ncomp, v );

  // Forward serialized diagnostics
  return CkReductionMsg::buildNew( stream.first, stream.second.get() );
}

} // diagnostics::
} // inciter::