1 #pragma once
2 
3 /// \file Accumulated.h
4 /// \brief Buffer storing quantity values accumulated by summing over particle pairs
5 /// \author Pavel Sevecek (sevecek at sirrah.troja.mff.cuni.cz)
6 /// \date 2016-2021
7 
8 #include "common/ForwardDecl.h"
9 #include "objects/containers/Array.h"
10 #include "objects/geometry/TracelessTensor.h"
11 #include "objects/wrappers/Variant.h"
12 #include "quantities/QuantityIds.h"
13 
14 NAMESPACE_SPH_BEGIN
15 
16 enum class OrderEnum;
17 
18 enum class BufferSource {
19     /// Only a single derivative accumulates to this buffer
20     UNIQUE,
21 
22     /// Multiple derivatives may accumulate into the buffer
23     SHARED,
24 };
25 
26 /// \brief Storage for accumulating derivatives.
27 ///
28 /// Each thread shall own its own Accumulated storage. Each accumulated buffer is associated with a quantity
29 /// using QuantityId.
30 class Accumulated {
31 private:
32     template <typename... TArgs>
33     using HolderVariant = Variant<Array<TArgs>...>;
34 
35     using Buffer = HolderVariant<Size, Float, Vector, TracelessTensor, SymmetricTensor>;
36 
37     struct Element {
38         /// ID of accumulated quantity, used to stored the quantity into the storage
39         QuantityId id;
40 
41         /// Order, specifying whether we are accumulating values or derivatives
42         OrderEnum order;
43 
44         /// Accumulated data
45         Buffer buffer;
46     };
47     Array<Element> buffers;
48 
49     struct QuantityRecord {
50         QuantityId id;
51         bool unique;
52     };
53 
54     /// Debug array, holding IDs of all quantities to check for uniqueness.
55     Array<QuantityRecord> records;
56 
57 public:
58     /// \brief Creates a new storage with given ID.
59     ///
60     /// Should be called once for each thread when the solver is initialized.
61     /// \param id ID of the accumulated quantity
62     /// \param order Order of the quantity. Only highest order can be accumulated, this parameter is used to
63     ///              ensure the derivative is used consistently.
64     /// \param unique Whether this buffer is being accumulated by a single derivative. It has no effect on
65     ///               the simulation, but ensures a consistency of the run (that we don't accumulate two
66     ///               different velocity gradients, for example).
67     template <typename TValue>
68     void insert(const QuantityId id, const OrderEnum order, const BufferSource source);
69 
70     /// \brief Initialize all storages.
71     ///
72     /// Storages are resized if needed and cleared out of all previously accumulated values.
73     void initialize(const Size size);
74 
75     /// \brief Returns the buffer of given quantity and given order.
76     ///
77     /// \note Accumulated can store only one buffer per quantity, so the order is not neccesary to retrive the
78     /// buffer, but it is required to check that we are indeed returning the required order of quantity. It
79     /// also makes the code more readable.
80     template <typename TValue>
81     Array<TValue>& getBuffer(const QuantityId id, const OrderEnum order);
82 
83     /// \brief Sums values of a list of storages.
84     ///
85     /// Storages must have the same number of buffers and the matching buffers must have the same type and
86     /// same size.
87     void sum(ArrayView<Accumulated*> others);
88 
89     /// \brief Sums values, concurently over different quantities
90     void sum(IScheduler& scheduler, ArrayView<Accumulated*> others);
91 
92     /// \brief Stores accumulated values to corresponding quantities.
93     ///
94     /// The accumulated quantity must already exist in the storage and its order must be at least the order of
95     /// the accumulated buffer. The accumulated buffer is cleared (filled with zeroes) after storing the
96     /// values into the storage.
97     void store(IScheduler& scheduler, Storage& storage);
98 
99     Size getBufferCnt() const;
100 
101 private:
102     template <typename Type>
103     Array<Iterator<Type>> getBufferIterators(const QuantityId id, ArrayView<Accumulated*> others);
104 
105     template <typename Type>
106     void sumBuffer(Array<Type>& buffer1, const QuantityId id, ArrayView<Accumulated*> others);
107 
108     template <typename Type>
109     void sumBuffer(IScheduler& scheduler,
110         Array<Type>& buffer1,
111         const QuantityId id,
112         ArrayView<Accumulated*> others);
113 
114     bool hasBuffer(const QuantityId id, const OrderEnum order) const;
115 };
116 
117 
118 NAMESPACE_SPH_END
119