• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Open-Sn / opensn / 16766938693

05 Aug 2025 03:26PM UTC coverage: 73.386% (+0.1%) from 73.282%
16766938693

push

github

web-flow
Merge pull request #693 from andrsd/move-bnds

Moving sweep boundaries into `DiscreteOrdinatesProblem`

247 of 311 new or added lines in 19 files covered. (79.42%)

625 existing lines in 49 files now uncovered.

18320 of 24964 relevant lines covered (73.39%)

43106214.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

34.58
/python/lib/post.cc
1
// SPDX-FileCopyrightText: 2025 The OpenSn Authors <https://open-sn.github.io/opensn/>
2
// SPDX-License-Identifier: MIT
3

4
#include "python/lib/py_wrappers.h"
5
#include "framework/runtime.h"
6
#include "framework/event_system/event.h"
7
#include "framework/logging/log.h"
8
#include "framework/post_processors/aggregate_nodal_value_post_processor.h"
9
#include "framework/post_processors/cell_volume_integral_post_processor.h"
10
#include "framework/post_processors/post_processor.h"
11
#include "framework/post_processors/post_processor_printer.h"
12
#include "framework/post_processors/solver_info_post_processor.h"
13
#include "framework/utils/utils.h"
14
#include <cstdint>
15
#include <stdexcept>
16
#include <string>
17
#include <vector>
18

19
namespace opensn
20
{
21

22
// Wrap post processors
23
void
24
WrapPostProcessor(py::module& post)
380✔
25
{
26
  // clang-format off
27
  // post processor
28
  auto pp = py::class_<PostProcessor, std::shared_ptr<PostProcessor>>(
380✔
29
    post,
30
    "PostProcessor",
31
    R"(
32
    Base class for all post-processors.
33

34
    Wrapper of :cpp:class:`opensn::PostProcessor`.
35
    )"
36
  );
380✔
37
  pp.def(
380✔
38
    "GetValue",
39
    [](PostProcessor& self)
380✔
40
    {
41
      const ParameterBlock& value = self.GetValue();
×
UNCOV
42
      return value.GetValue<double>();
×
43
    },
44
    R"(
45
    ???
46
    )"
47
  );
48
  pp.def(
380✔
49
    "Execute",
50
    [](PostProcessor& self, const std::string& event_name){
380✔
51
      self.Execute(Event(event_name));
32✔
52
    },
32✔
53
    R"(
54
    ???
55

56
    Parameters
57
    ----------
58
    event_name: str, default='ManualExecutation'
59
        ???
60
    )",
61
    py::arg("event_name") = "ManualExecutation"
380✔
62
  );
63

64
  // solver info post processor
65
  auto solver_info_pp = py::class_<SolverInfoPostProcessor,
380✔
66
                                   std::shared_ptr<SolverInfoPostProcessor>,
67
                                   PostProcessor>(
68
    post,
69
    "SolverInfoPostProcessor",
70
    R"(
71
    Post-processor for basic info of a Solver.
72

73
    This solver's execution does not filter whether solver events are for the relevant solver. This
74
    is done to avoid differing time-histories.
75

76
    (really unclear, rephrasing is needed)
77
    ???
78

79
    Wrapper of :cpp:class:`opensn::SolverInfoPostProcessor`.
80
    )"
81
  );
380✔
82
  solver_info_pp.def(
760✔
83
    py::init(
380✔
UNCOV
84
      [](py::kwargs& params)
×
85
      {
UNCOV
86
        return SolverInfoPostProcessor::Create(kwargs_to_param_block(params));
×
87
      }
88
    ),
89
    R"(
90
    Construct a solver info post processor object.
91

92
    Parameters
93
    ----------
94
    name: str
95
        Name of the post processor; used throughout the program.
96
    execute_on: List[str], default=['SolverInitialized', 'SolverAdvanced', 'SolverExecuted', 'ProgramExecuted']
97
        List of events at which the post-processor executes.
98
    print_on: List[str], default=['SolverInitialized', 'SolverAdvanced', 'SolverExecuted', 'ProgramExecuted']
99
        List of events at which the post-processor prints, ensuring these events are also set for the
100
        post-processor printer.
101
    initial_value: Dict, default={}
102
        Dictionary of initial value.
103
    print_numeric_format: {'fixed', 'floating_point', 'scientific', 'general'}, default='general'
104
        Numeric format for printing.
105
    print_precision: int, default=6
106
        Number of digits displayed after the decimal point.
107
    solvername_filter: str, default=''
108
        Filter to control update events to execute only on calls from the specified solver.
109
    solver: pyopensn.solver.Solver
110
        Target solver.
111
    info: Dict, default={}
112
        Dictionary requiring at minimum the parameter ``name`` to pass to the solver. Each solver
113
        may define additional custom parameters to retrieve various types of information.
114
    )"
115
  );
116

117
  // aggregate nodal value post processor
118
  auto agg_nodel_value_pp = py::class_<AggregateNodalValuePostProcessor,
380✔
119
                                       std::shared_ptr<AggregateNodalValuePostProcessor>,
120
                                       PostProcessor>(
121
    post,
122
    "AggregateNodalValuePostProcessor",
123
    R"(
124
    Aggregator for nodal values.
125

126
    Gets the max/min/avg nodal value of a field function among nodal values.
127

128
    Wrapper of :cpp:class:`opensn::AggregateNodalValuePostProcessor`.
129
    )"
130
  );
380✔
131
  agg_nodel_value_pp.def(
760✔
132
    py::init(
380✔
UNCOV
133
      [](py::kwargs& params)
×
134
      {
UNCOV
135
        return AggregateNodalValuePostProcessor::Create(kwargs_to_param_block(params));
×
136
      }
137
    ),
138
    R"(
139
    Construct an aggregate nodal value post processor object.
140

141
    Parameters
142
    ----------
143
    name: str
144
        Name of the post processor; used throughout the program.
145
    execute_on: List[str], default=['SolverInitialized', 'SolverAdvanced', 'SolverExecuted', 'ProgramExecuted']
146
        List of events at which the post-processor executes.
147
    print_on: List[str], default=['SolverInitialized', 'SolverAdvanced', 'SolverExecuted', 'ProgramExecuted']
148
        List of events at which the post-processor prints, ensuring these events are also set for the
149
        post-processor printer.
150
    initial_value: Dict, default={}
151
        Dictionary of initial value.
152
    print_numeric_format: {'fixed', 'floating_point', 'scientific', 'general'}, default='general'
153
        Numeric format for printing.
154
    print_precision: int, default=6
155
        Number of digits displayed after the decimal point.
156
    solvername_filter: str, default=''
157
        Filter to control update events to execute only on calls from the specified solver.
158
    operation: {'max', 'min', 'avg'}
159
        The required operation to be performed.
160
    )"
161
  );
162

163
  // cell volume integral post processor
164
  auto cell_volume_int_pp = py::class_<CellVolumeIntegralPostProcessor,
380✔
165
                                       std::shared_ptr<CellVolumeIntegralPostProcessor>,
166
                                       PostProcessor>(
167
    post,
168
    "CellVolumeIntegralPostProcessor",
169
    R"(
170
    Compute the volumetric integral of a field-function.
171
    )"
172
  );
380✔
173
  cell_volume_int_pp.def(
760✔
174
    py::init(
380✔
175
      [](py::kwargs& params)
32✔
176
      {
177
        return CellVolumeIntegralPostProcessor::Create(kwargs_to_param_block(params));
32✔
178
      }
179
    ),
180
    R"(
181
    Construct a cell volume integral post processor object.
182

183
    Parameters
184
    ----------
185
    name: str
186
        Name of the post processor; used throughout the program.
187
    execute_on: List[str], default=['SolverInitialized', 'SolverAdvanced', 'SolverExecuted', 'ProgramExecuted']
188
        List of events at which the post-processor executes.
189
    print_on: List[str], default=['SolverInitialized', 'SolverAdvanced', 'SolverExecuted', 'ProgramExecuted']
190
        List of events at which the post-processor prints, ensuring these events are also set for the
191
        post-processor printer.
192
    initial_value: Dict, default={}
193
        Dictionary of initial value.
194
    print_numeric_format: {'fixed', 'floating_point', 'scientific', 'general'}, default='general'
195
        Numeric format for printing.
196
    print_precision: int, default=6
197
        Number of digits displayed after the decimal point.
198
    solvername_filter: str, default=''
199
        Filter to control update events to execute only on calls from the specified solver.
200
    compute_volume_average: bool, default=False
201
        Flag, when true will compute the volume average of the post-processor.
202
    )"
203
  );
204
  // clang-format on
205
}
380✔
206

207
// Wrap printer options
208
void
209
WrapPrinter(py::module& post)
380✔
210
{
211
  // clang-format off
212
  // print
213
  post.def(
380✔
214
    "Print",
215
    [](py::sequence& pp_list)
380✔
216
    {
217
      // convert to vector of pointers
218
      std::vector<const PostProcessor*> cpp_pp_list;
×
219
      cpp_pp_list.reserve(pp_list.size());
×
UNCOV
220
      for (py::handle py_pp: pp_list)
×
221
      {
222
        cpp_pp_list.push_back(py_pp.cast<PostProcessor*>());
×
UNCOV
223
        auto back = py_pp.cast<SolverInfoPostProcessor*>();
×
224
      }
225
      // get printer
226
      PostProcessorPrinter& printer = PostProcessorPrinter::GetInstance();
×
227
      std::string output = printer.GetPrintedPostProcessors(cpp_pp_list);
×
228
      log.Log() << output;
×
UNCOV
229
    },
×
230
    R"(
231
    Print a list of post-processors.
232

233
    Parameters
234
    ---------
235
    pp_list: List[pyopensn.post.PostProcessor]
236
        List of post-processors to print.
237
    )",
238
    py::arg("pp_list")
380✔
239
  );
240
  // set options
241
  post.def(
380✔
242
    "SetPrinterOptions",
243
    [](py::kwargs& params)
380✔
244
    {
245
      // get printer
246
      PostProcessorPrinter& printer = PostProcessorPrinter::GetInstance();
×
UNCOV
247
      for (auto [key, value] : params)
×
248
      {
249
        // compute hash for key
250
        std::string key_name = key.cast<std::string>();
×
UNCOV
251
        std::uint32_t key_hash = hash_djb2a(key_name);
×
252
        // set based on hash
UNCOV
253
        switch (key_hash)
×
254
        {
255
          case "scalar_pp_table_format"_hash:
×
256
          {
×
257
            std::string option = value.cast<std::string>();
×
UNCOV
258
            if (option == "vertical")
×
259
            {
UNCOV
260
              printer.SetScalarPPTableFormat(ScalarPPTableFormat::VERTICAL);
×
261
            }
UNCOV
262
            else if (option == "horizontal")
×
263
            {
UNCOV
264
              printer.SetScalarPPTableFormat(ScalarPPTableFormat::HORIZONTAL);
×
265
            }
266
            else
267
            {
268
              throw std::invalid_argument("Unsupported format \"" + option +
×
UNCOV
269
                                          "\" specified for option \"scalar_pp_table_format\"");
×
270
            }
271
            log.Log() << "PostProcessorPrinter scalar_pp_table_format set to " << option;
×
272
            break;
×
273
          }
×
274
          case "events_on_which_to_print_postprocs"_hash:
×
275
          {
×
276
            std::vector<std::string> events;
×
277
            py::sequence py_value = value.cast<py::sequence>();
×
278
            events.reserve(py_value.size());
×
UNCOV
279
            for (py::handle py_event: py_value)
×
280
            {
UNCOV
281
              events.push_back(py_event.cast<std::string>());
×
282
            }
283
            printer.SetEventsOnWhichPrintPPs(events);
×
284
            log.Log() << "PostProcessorPrinter events_on_which_to_print_postprocs set";
×
285
            break;
×
286
          }
×
287
          case "print_scalar_time_history"_hash:
×
288
          {
×
UNCOV
289
            printer.SetPrintScalarTimeHistory(value.cast<bool>());
×
290
            break;
291
          }
292
          case "print_vector_time_history"_hash:
×
293
          {
×
UNCOV
294
            printer.SetPrintVectorTimeHistory(value.cast<bool>());
×
295
            break;
296
          }
297
          case "per_column_size_scalars"_hash:
×
298
          {
×
UNCOV
299
            printer.SetScalarPerColumnSize(value.cast<bool>());
×
300
            break;
301
          }
302
          case "per_column_size_vectors"_hash:
×
303
          {
×
UNCOV
304
            printer.SetVectorPerColumnSize(value.cast<bool>());
×
305
            break;
306
          }
307
          case "table_column_limit"_hash:
×
308
          {
×
UNCOV
309
            printer.SetTableColumnLimit(value.cast<size_t>());
×
310
            break;
311
          }
312
          case "time_history_limit"_hash:
×
313
          {
×
UNCOV
314
            printer.SetTimeHistoryLimit(value.cast<size_t>());
×
315
            break;
316
          }
317
          case "csv_filename"_hash:
×
318
          {
×
319
            printer.SetCSVFilename(value.cast<std::string>());
×
UNCOV
320
            break;
×
321
          }
322
          default:
×
323
          {
×
UNCOV
324
            throw std::invalid_argument("Invalid option \"" + key_name + "\"");
×
325
          }
326
        }
327
      }
×
UNCOV
328
    },
×
329
    R"(
330
    Set printer options.
331

332
    Parameters
333
    ----------
334
    scalar_pp_table_format: {'vertical', 'horizontal'}, default='vertical'
335
        The table format with which to print scalar.
336
    events_on_which_to_print_postprocs: List[str], default=['SolverInitialized', 'SolverAdvanced', 'SolverExecuted', 'ProgramExecuted']
337
        A list of events on which to print post-processors.
338
    print_scalar_time_history: bool, default=True
339
        Control whether a time history of scalar post-processors are printed. If false, only the
340
        latest version will be printed.
341
    print_vector_time_history: bool, default=True
342
        Control whether a time history of vector post-processors are printed. If false, only the
343
        latest version will be printed.
344
    per_column_size_scalars: bool, default=True
345
        Control the sizing of printed columns. If false, all the columns will be the same size.
346
    per_column_size_vectors: bool, default=True
347
        Control the sizing of printed columns. If false, all the columns will be the same size.
348
    table_column_limit: int, default=120
349
        The maximum column, if reached, would cause tables to be wrapped. A minimum limit of 80 is
350
        automatically enforced.
351
    time_history_limit: int, default=15
352
        Maximum amount of time values to show in post-processor histories. A maximum of 1000 is
353
        automatically enforced.
354
    csv_filename: str, default=''
355
        If not empty, a file will be printed with all the post-processors formatted as comma
356
        seperated values.
357
    )"
358
  );
359
  // clang-format on
360
}
380✔
361

362
// Wrap the post-processing components of OpenSn.
363
void
364
py_post(py::module& pyopensn)
34✔
365
{
366
  py::module post = pyopensn.def_submodule("post", "Post-processing module.");
34✔
367
  WrapPostProcessor(post);
34✔
368
  WrapPrinter(post);
34✔
369
}
34✔
370

371
} // namespace opensn
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc