Branch data Line data Source code
1 : : // *****************************************************************************
2 : : /*!
3 : : \file src/Statistics/TriPDF.hpp
4 : : \copyright 2012-2015 J. Bakosi,
5 : : 2016-2018 Los Alamos National Security, LLC.,
6 : : 2019-2021 Triad National Security, LLC.
7 : : All rights reserved. See the LICENSE file for details.
8 : : \brief Joint trivariate PDF estimator
9 : : \details Joint trivariate PDF estimator. This class can be used to estimate
10 : : a joint probability density function (PDF) of three scalar variables from an
11 : : ensemble. The implementation uses the standard container std::unordered_map,
12 : : which is a hash-based associative container with linear algorithmic
13 : : complexity for insertion of a new sample.
14 : : */
15 : : // *****************************************************************************
16 : : #ifndef TriPDF_h
17 : : #define TriPDF_h
18 : :
19 : : #include <array>
20 : : #include <unordered_map>
21 : : #include <algorithm>
22 : :
23 : : #include "Types.hpp"
24 : : #include "PUPUtil.hpp"
25 : :
26 : : namespace tk {
27 : :
28 : : //! Joint trivariate PDF estimator
29 : 0 : class TriPDF {
30 : :
31 : : public:
32 : : //! Number of sample space dimensions
33 : : static const std::size_t dim = 3;
34 : :
35 : : //! Key type
36 : : using key_type = std::array< long, dim >;
37 : :
38 : : //! Pair type
39 : : using pair_type = std::pair< const key_type, tk::real >;
40 : :
41 : : // Hash functor for key_type
42 : : struct key_hash {
43 : : std::size_t operator()( const key_type& key ) const {
44 : 0 : return std::hash< long >()( key[0] ) ^
45 : 0 : std::hash< long >()( key[1] ) ^
46 : 0 : std::hash< long >()( key[2] );
47 : : }
48 : : };
49 : :
50 : : //! \brief Joint trivariate PDF
51 : : //! \details The underlying container type is an unordered_map where the key
52 : : //! is three bin ids corresponding to the three sample space dimensions,
53 : : //! and the mapped value is the sample counter. The hasher functor,
54 : : //! defined by key_hash provides an XORed hash of the three bin ids.
55 : : using map_type = std::unordered_map< key_type, tk::real, key_hash >;
56 : :
57 : : //! Empty constructor for Charm++
58 [ - - ]: 0 : explicit TriPDF() : m_binsize( {{ 0, 0, 0 }} ), m_nsample( 0 ), m_pdf() {}
59 : :
60 : : //! Constructor: Initialize joint trivariate PDF container
61 : : //! \param[in] bs Sample space bin size in all three directions
62 : 0 : explicit TriPDF( const std::vector< tk::real >& bs ) :
63 : 0 : m_binsize( {{ bs[0], bs[1], bs[2] }} ),
64 : : m_nsample( 0 ),
65 : 0 : m_pdf() {}
66 : :
67 : : //! Accessor to number of samples
68 : : //! \return Number of samples collected
69 : : std::size_t nsample() const noexcept { return m_nsample; }
70 : :
71 : : //! Add sample to trivariate PDF
72 : : //! \param[in] sample Sample to add
73 : 0 : void add( std::array< tk::real, dim > sample ) {
74 : 0 : ++m_nsample;
75 : 0 : ++m_pdf[ {{ std::lround( sample[0] / m_binsize[0] ),
76 : 0 : std::lround( sample[1] / m_binsize[1] ),
77 : 0 : std::lround( sample[2] / m_binsize[2] ) }} ];
78 : 0 : }
79 : :
80 : : //! Add multiple samples from a PDF
81 : : //! \param[in] p PDF whose samples to add
82 : 0 : void addPDF( const TriPDF& p ) {
83 : 0 : m_binsize = p.binsize();
84 : 0 : m_nsample += p.nsample();
85 [ - - ]: 0 : for (const auto& e : p.map()) m_pdf[ e.first ] += e.second;
86 : 0 : }
87 : :
88 : : //! Zero bins
89 : 0 : void zero() noexcept { m_nsample = 0; m_pdf.clear(); }
90 : :
91 : : //! Constant accessor to underlying PDF map
92 : : //! \return Constant reference to underlying map
93 : : const map_type& map() const noexcept { return m_pdf; }
94 : :
95 : : //! Constant accessor to bin sizes
96 : : //! \return Constant reference to sample space bin sizes
97 : : const std::array< tk::real, dim >& binsize() const noexcept
98 : : { return m_binsize; }
99 : :
100 : : //! \brief Return minimum and maximum bin ids of sample space in all three
101 : : //! dimensions
102 : : //! \return {xmin,xmax,ymin,ymax,zmin,zmax} Minima and maxima of bin the ids
103 : 0 : std::array< long, 2*dim > extents() const {
104 : : Assert( !m_pdf.empty(), "PDF empty" );
105 : : auto x = std::minmax_element( begin(m_pdf), end(m_pdf),
106 : : []( const pair_type& a, const pair_type& b )
107 [ - - ][ - - ]: 0 : { return a.first[0] < b.first[0]; } );
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
108 : : auto y = std::minmax_element( begin(m_pdf), end(m_pdf),
109 : : []( const pair_type& a, const pair_type& b )
110 [ - - ][ - - ]: 0 : { return a.first[1] < b.first[1]; } );
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
111 : : auto z = std::minmax_element( begin(m_pdf), end(m_pdf),
112 : : []( const pair_type& a, const pair_type& b )
113 [ - - ][ - - ]: 0 : { return a.first[2] < b.first[2]; } );
[ - - ][ - - ]
[ - - ][ - - ]
[ - - ][ - - ]
114 : : return {{ x.first->first[0], x.second->first[0],
115 : : y.first->first[1], y.second->first[1],
116 : 0 : z.first->first[2], z.second->first[2] }};
117 : : }
118 : :
119 : : /** @name Pack/Unpack: Serialize BiPDF object for Charm++ */
120 : : ///@{
121 : : //! Pack/Unpack serialize member function
122 : : //! \param[in,out] p Charm++'s PUP::er serializer object reference
123 : 0 : void pup( PUP::er& p ) {
124 : : p | m_binsize;
125 : 0 : p | m_nsample;
126 : 0 : p | m_pdf;
127 : 0 : }
128 : : //! \brief Pack/Unpack serialize operator|
129 : : //! \param[in,out] p Charm++'s PUP::er serializer object reference
130 : : //! \param[in,out] c TriPDF object reference
131 [ - - ]: 0 : friend void operator|( PUP::er& p, TriPDF& c ) { c.pup(p); }
132 : : ///@}
133 : :
134 : : private:
135 : : std::array< tk::real, dim > m_binsize; //!< Sample space bin sizes
136 : : std::size_t m_nsample; //!< Number of samples collected
137 : : map_type m_pdf; //!< Probability density function
138 : : };
139 : :
140 : : } // tk::
141 : :
142 : : #endif // TriPDF_h
|