OpenLB 1.8.1
Loading...
Searching...
No Matches
introspection.h
Go to the documentation of this file.
1/* This file is part of the OpenLB library
2 *
3 * Copyright (C) 2024 Adrian Kummerlaender
4 * E-mail contact: info@openlb.net
5 * The most recent release of OpenLB can be downloaded at
6 * <http://www.openlb.net/>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program; if not, write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22*/
23
24#ifndef OLB_CORE_INTROSPECTION_H
25#define OLB_CORE_INTROSPECTION_H
26
27#include "concepts.h"
28
29#include <set>
30#include <optional>
31#include <regex>
32
33#include "olbInit.h"
34
35#include "cse/symbolGenerator.h"
36
37namespace olb {
38
39template<typename T, typename DESCRIPTOR, Platform PLATFORM> class ConcreteBlockLattice;
40
41namespace introspection {
42
43template <typename DYNAMICS>
44[[gnu::noinline]]
45std::optional<std::size_t> getArithmeticOperationCount() {
47 try {
48 using DESCRIPTOR = typename DYNAMICS::descriptor_t;
50 exprLattice.setStatisticsEnabled(false);
51 exprLattice.setIntrospectability(false);
52 exprLattice.setDynamics(0, meta::id<typename DYNAMICS::template exchange_value_type<Expr>>{});
54 exprLattice.collide();
55 return Expr::count();
56 }
57 catch (std::domain_error& error) {
58 return std::nullopt;
59 }
60 } else {
61 return std::nullopt;
62 }
63}
64
65template <typename OPERATOR, typename DESCRIPTOR>
66[[gnu::noinline]]
67std::optional<std::size_t> getArithmeticOperationCount() {
68 try {
69 const int r = 3;
70 Vector<int,DESCRIPTOR::d> extend(r*2+1);
73 exprLattice.setStatisticsEnabled(false);
74 exprLattice.setIntrospectability(false);
75 if (OPERATOR::scope == OperatorScope::PerBlock) {
76 exprLattice.addPostProcessor(typeid(stage::CSE),
78 } else {
79 exprLattice.addPostProcessor(typeid(stage::CSE),
80 center,
82 }
84 exprLattice.postProcess(typeid(stage::CSE));
85 return Expr::count();
86 }
87 catch (std::domain_error& error) {
88 return std::nullopt;
89 }
90}
91
92template <typename DYNAMICS>
93[[gnu::noinline]]
94std::optional<std::size_t> getComplexity() {
96 try {
97 using DESCRIPTOR = typename DYNAMICS::descriptor_t;
99 exprLattice.setStatisticsEnabled(false);
100 exprLattice.setIntrospectability(false);
101 exprLattice.setDynamics(0, meta::id<typename DYNAMICS::template exchange_value_type<Expr>>{});
102 exprLattice.collide();
103 std::size_t size = 0;
104 for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
105 size += exprLattice.get(0)[iPop].size();
106 }
107 return size;
108 }
109 catch (std::domain_error& error) {
110 return std::nullopt;
111 }
112 } else {
113 return std::nullopt;
114 }
115}
116
117template <concepts::IntrospectableDynamics DYNAMICS>
118[[gnu::noinline]]
120 try {
121 using DESCRIPTOR = typename DYNAMICS::descriptor_t;
123 exprLattice.setStatisticsEnabled(false);
124 exprLattice.setIntrospectability(false);
125 exprLattice.setDynamics(0, meta::id<typename DYNAMICS::template exchange_value_type<Expr>>{});
126 exprLattice.collide();
127 }
128 catch (std::domain_error& error) {
129 return false;
130 }
131 return true;
132}
133
134template <typename OPERATOR, typename DESCRIPTOR>
135[[gnu::noinline]]
137 try {
138 const int r = 3;
139 Vector<int,DESCRIPTOR::d> extend(r*2+1);
142 exprLattice.setStatisticsEnabled(false);
143 exprLattice.setIntrospectability(false);
144 if (OPERATOR::scope == OperatorScope::PerBlock) {
145 exprLattice.addPostProcessor(typeid(stage::CSE),
147 } else {
148 exprLattice.addPostProcessor(typeid(stage::CSE),
149 center,
151 }
152 exprLattice.postProcess(typeid(stage::CSE));
153 }
154 catch (std::domain_error& error) {
155 return false;
156 }
157 return true;
158}
159
160template <typename DYNAMICS>
163 return false;
164}
165
166template <typename T, typename DESCRIPTOR, typename DYNAMICS>
167[[gnu::noinline]]
168std::set<FieldTypePromise<T,DESCRIPTOR>> getFieldsAccessedByDynamics() {
170 lattice.setStatisticsEnabled(false);
171 lattice.setIntrospectability(false);
172
173 std::set<FieldTypePromise<T,DESCRIPTOR>> preCollide;
174 lattice.getData().forEach([&](auto& anyFieldType) {
175 preCollide.emplace(anyFieldType.getPromise());
176 });
177
179 lattice.collide();
180
181 std::set<FieldTypePromise<T,DESCRIPTOR>> postCollide;
182 lattice.getData().forEach([&](auto& anyFieldType) {
183 postCollide.emplace(anyFieldType.getPromise());
184 });
185
186 std::set<FieldTypePromise<T,DESCRIPTOR>> accessed;
187 std::set_difference(postCollide.begin(), postCollide.end(),
188 preCollide.begin(), preCollide.end(),
189 std::inserter(accessed, accessed.end()));
190 return accessed;
191}
192
193template <typename T, typename DESCRIPTOR, typename DYNAMICS>
194[[gnu::noinline]]
195std::set<FieldTypePromise<T,DESCRIPTOR>> getFieldsAccessedByCollision() {
197 lattice.setStatisticsEnabled(false);
198 lattice.setIntrospectability(false);
199
201
202 std::set<FieldTypePromise<T,DESCRIPTOR>> preCollide;
203 lattice.getData().forEach([&](auto& anyFieldType) {
204 preCollide.emplace(anyFieldType.getPromise());
205 });
206
207 lattice.collide();
208
209 std::set<FieldTypePromise<T,DESCRIPTOR>> postCollide;
210 lattice.getData().forEach([&](auto& anyFieldType) {
211 postCollide.emplace(anyFieldType.getPromise());
212 });
213
214 std::set<FieldTypePromise<T,DESCRIPTOR>> accessed;
215 std::set_difference(postCollide.begin(), postCollide.end(),
216 preCollide.begin(), preCollide.end(),
217 std::inserter(accessed, accessed.end()));
218 return accessed;
219}
220
221template <typename T, typename DESCRIPTOR, typename OPERATOR>
222[[gnu::noinline]]
223std::set<FieldTypePromise<T,DESCRIPTOR>> getFieldsAccessedByOperator() {
225 lattice.setStatisticsEnabled(false);
226 lattice.setIntrospectability(false);
227
228 std::set<FieldTypePromise<T,DESCRIPTOR>> prePostProcess;
229 lattice.getData().forEach([&](auto& anyFieldType) {
230 prePostProcess.emplace(anyFieldType.getPromise());
231 });
232
233 if (OPERATOR::scope == OperatorScope::PerBlock) {
234 lattice.addPostProcessor(typeid(stage::CSE),
236 } else {
237 lattice.addPostProcessor(typeid(stage::CSE),
238 0,
240 }
241 lattice.postProcess(typeid(stage::CSE));
242
243 std::set<FieldTypePromise<T,DESCRIPTOR>> postPostProcess;
244 lattice.getData().forEach([&](auto& anyFieldType) {
245 postPostProcess.emplace(anyFieldType.getPromise());
246 });
247
248 std::set<FieldTypePromise<T,DESCRIPTOR>> accessed;
249 std::set_difference(postPostProcess.begin(), postPostProcess.end(),
250 prePostProcess.begin(), prePostProcess.end(),
251 std::inserter(accessed, accessed.end()));
252 return accessed;
253}
254
256template <typename DYNAMICS>
257[[gnu::noinline]]
258std::optional<std::size_t> getMemoryBandwidthOfCollision() {
259 using T = Expr;
260 using DESCRIPTOR = DYNAMICS::descriptor_t;
261
262 try {
265 exprLattice.setIntrospectability(false);
266 exprLattice.setStatisticsEnabled(false);
267
268 exprLattice.setDynamics(0, meta::id<typename DYNAMICS::template exchange_value_type<T>>{});
269
270 std::size_t bandwidth = 0;
271
273 auto cell = exprLattice.get(pos);
274 for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
275 cell[iPop] = "cell[" + std::to_string(iPop) + "]";
276 }
277 // Assume that all populations are read
278 bandwidth += DESCRIPTOR::q;
279
281
282 // Initialize expressions for the accessed fields
283 for (auto field : accessedFields) {
284 if (auto dim = field.dimension()) {
285 // Assume that all touched fields are read
286 bandwidth += *dim;
287 std::vector<T> initExpr;
288 for (unsigned iD=0; iD < dim; ++iD) {
289 initExpr.emplace_back("cell[" + cse::remove_array_from_name(field.name()) + "][" + std::to_string(iD) + "]");
290 }
291 field.setPlaceholderExpression(cell, initExpr);
292 }
293 }
294
295 // Execute one colliding step to obtain post-collision expressions
296 exprLattice.collide();
297
298 for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
299 if (!cell[iPop].isSymbol("cell[" + std::to_string(iPop) + "]")) {
300 // Count number of population updates
301 bandwidth += 1;
302 }
303 }
304
305 // Obtain fields which were updated and overwritten by the operator
306 for (auto field : accessedFields) {
307 if (auto dim = field.dimension()) {
308 auto postExpr = field.getPlaceholderExpression(cell);
309 for (unsigned iD=0; iD < dim; ++iD) {
310 if (!postExpr[iD].isSymbol("cell["
311 + cse::remove_array_from_name(field.name())
312 + "][" + std::to_string(iD) + "]")) {
313 // Count number of field component updates
314 bandwidth += 1;
315 }
316 }
317 }
318 }
319
320 return bandwidth;
321 }
322 catch (std::domain_error& error) {
323 return std::nullopt;
324 }
325}
326
328[[gnu::noinline]]
329std::string getSimplifiedDynamicsName(std::string name) {
330 std::regex removeBaseTypeAndDescriptorRe("(float|double|Expr),\\s?descriptors::D[23]Q[0-9]+<([^<>]*|<([^<>]*|<[^<>]*>)*>)*>,?\\s?");
331 std::regex lineBreakRe("((dynamics|collision|forcing|equilibria)::[a-zA-Z]+|momenta::Tuple<)");
332
333 std::string stage0;
334 std::string stage1;
335 std::regex_replace(std::back_inserter(stage0),
336 name.begin(), name.end(), removeBaseTypeAndDescriptorRe,
337 "");
338 std::regex_replace(std::back_inserter(stage1),
339 stage0.begin(), stage0.end(), lineBreakRe,
340 "\n$&");
341 return stage1;
342}
343
344
345}
346
347}
348
349#endif
void defineDynamics(LatticeR< DESCRIPTOR::d > latticeR, DynamicsPromise< T, DESCRIPTOR > &&promise)
Assign promised DYNAMICS to latticeR.
Cell< T, DESCRIPTOR > get(CellID iCell)
Get Cell interface for index iCell.
Implementation of BlockLattice on a concrete PLATFORM.
void collide() override
Apply collision step of non-overlap interior.
void postProcess(std::type_index stage) override
Execute post processors of stage.
void addPostProcessor(std::type_index stage, LatticeR< DESCRIPTOR::d > latticeR, PostProcessorPromise< T, DESCRIPTOR > &&promise) override
Schedule post processor for application to latticeR in stage.
void setDynamics(CellID iCell, DynamicsPromise< T, DESCRIPTOR > &&promise) override
Set dynamics at iCell to promised dynamics.
ConcreteData< T, DESCRIPTOR, PLATFORM > & getData()
Basic value-substitute enabling extraction of expression trees for code generation.
Definition expr.h:39
static void reset()
Resets FLOP counter.
Definition expr.h:123
static std::size_t count()
Return accumulated FLOPs.
Definition expr.h:133
Plain old scalar vector.
std::string remove_array_from_name(const std::string &arg)
Unwrap FIELD type from FieldArray.
std::optional< std::size_t > getArithmeticOperationCount()
std::optional< std::size_t > getMemoryBandwidthOfCollision()
Returns estimate of number of scalar reads and writes for DYNAMICS::collide.
std::optional< std::size_t > getComplexity()
std::set< FieldTypePromise< T, DESCRIPTOR > > getFieldsAccessedByCollision()
std::string getSimplifiedDynamicsName(std::string name)
Return reduced and reasonable newline-separated version of given full dynamics name.
std::set< FieldTypePromise< T, DESCRIPTOR > > getFieldsAccessedByOperator()
std::set< FieldTypePromise< T, DESCRIPTOR > > getFieldsAccessedByDynamics()
Top level namespace for all of OpenLB.
@ PerBlock
Per-block application, i.e. OPERATOR::apply is passed a ConcreteBlockLattice.
LB initialisation routine – header file.
Identity type to pass non-constructible types as value.
Definition meta.h:79
Seperate step only used for extracting expression tree.
Definition stages.h:61