version 3.11-dev
Loading...
Searching...
No Matches
gridwriter.hh
Go to the documentation of this file.
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 sw=2 sts=2:
3//
4// SPDX-FileCopyrightText: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
12#ifndef DUMUX_IO_GRID_WRITER_HH
13#define DUMUX_IO_GRID_WRITER_HH
14
15#include <config.h>
16
17#if DUMUX_HAVE_GRIDFORMAT
18
19#include <ranges>
20#include <execution>
21#include <concepts>
22#include <type_traits>
23
24#include <gridformat/common/type_traits.hpp>
25#include <gridformat/gridformat.hpp>
26#include <gridformat/traits/dune.hpp>
27
28#include <dune/common/exceptions.hh>
29#include <dune/common/timer.hh>
30
31#include <dumux/io/format.hh>
36
37namespace Dumux::IO {
38
39
40#ifndef DOXYGEN
41namespace Detail {
42
43template<typename Grid, typename Format, typename Comm, typename... Args>
44auto makeParallelWriter(const Grid& grid, const Format& fmt, const Dune::Communication<Comm>& comm, Args&&... args)
45{
46 return comm.size() > 1
47 ? GridFormat::Writer<Grid>{fmt, grid, static_cast<Comm>(comm), std::forward<Args>(args)...}
48 : GridFormat::Writer<Grid>{fmt, grid, std::forward<Args>(args)...};
49}
50
51template<typename Grid, typename Format, typename... Args>
52auto makeParallelWriter(const Grid& grid, const Format& fmt, const Dune::Communication<Dune::No_Comm>&, Args&&... args)
53{ return GridFormat::Writer<Grid>{fmt, grid, std::forward<Args>(args)...}; }
54
55template<typename Grid, typename Format, typename... Args>
56auto makeWriter(const Grid& grid, const Format& fmt, Args&&... args)
57{
58 const auto& comm = GridFormat::Dune::Traits::GridView<Grid>::get(grid).comm();
59 return makeParallelWriter(grid, fmt, comm, std::forward<Args>(args)...);
60}
61
62template<typename T>
63concept Container = requires(const T& t) {
64 { t.size() };
65 { t[std::size_t{}] };
66};
67
68} // namespace Detail
69#endif // DOXYGEN
70
71
72namespace VTK { using namespace GridFormat::VTK; }
73namespace Format { using namespace GridFormat::Formats; }
74namespace Encoding { using namespace GridFormat::Encoding; }
75namespace Compression { using namespace GridFormat::Compression; using GridFormat::none; }
76namespace Precision {
77 using GridFormat::float32;
78 using GridFormat::float64;
79
80 using GridFormat::uint64;
81 using GridFormat::uint32;
82 using GridFormat::uint16;
83 using GridFormat::uint8;
84
85 using GridFormat::int64;
86 using GridFormat::int32;
87 using GridFormat::int16;
88 using GridFormat::int8;
89} // namespace Precision
90
91
96template<int order>
97struct Order { static_assert(order > 0, "order must be > 0"); };
98
99template<int o>
100inline constexpr auto order = Order<o>{};
101
116template<GridFormat::Concepts::Grid GridView, int order = 1>
117class GridWriter
118{
119 using Grid = std::conditional_t<
120 (order > 1),
121 CVFELagrangeGrid<GridView, order>,
122 GridView
123 >;
124 using Cell = GridFormat::Cell<Grid>;
125 using Vertex = typename GridView::template Codim<GridView::dimension>::Entity;
126 using Element = typename GridView::template Codim<0>::Entity;
127 using Writer = GridFormat::Writer<Grid>;
128
129 public:
134 template<typename Format>
135 explicit GridWriter(const Format& fmt,
136 const GridView& gridView,
137 const Order<order>& = {})
138 : gridView_{gridView}
139 , grid_{makeGrid_(gridView)}
140 , writer_{Detail::makeWriter(grid_, fmt)}
141 {
142 if (gridView.comm().size() > 0 && getParam<bool>("IO.GridWriter.AddProcessRank", true))
143 setCellField("process rank", [&](const Cell&) { return gridView.comm().rank(); }, Precision::uint64);
144 }
145
150 template<typename Format>
151 explicit GridWriter(const Format& fmt,
152 const GridView& gridView,
153 const std::string& filename,
154 const Order<order>& = {})
155 : gridView_{gridView}
156 , grid_{makeGrid_(gridView)}
157 , writer_{Detail::makeWriter(grid_, fmt, filename)}
158 {
159 if (gridView.comm().size() > 0 && getParam<bool>("IO.GridWriter.AddProcessRank", true))
160 setCellField("process rank", [&](const Cell&) { return gridView.comm().rank(); }, Precision::uint64);
161 }
162
167 std::string write(const std::string& name) const
168 { return writer_.write(name); }
169
174 template<std::floating_point T>
175 std::string write(T time) const
176 { return writer_.write(time); }
177
179 template<GridFormat::Concepts::CellFunction<GridView> F,
180 GridFormat::Concepts::Scalar T = GridFormat::FieldScalar<std::invoke_result_t<F, Element>>>
181 void setCellField(const std::string& name, F&& f, const GridFormat::Precision<T>& prec = {})
182 { writer_.set_cell_field(name, std::move(f), prec); }
183
185 template<GridFormat::Dune::Concepts::Function<GridView> F>
186 void setCellField(const std::string& name, F&& f)
187 { GridFormat::Dune::set_cell_function(std::forward<F>(f), writer_, name); }
188
190 template<typename F, GridFormat::Concepts::Scalar T>
191 void setCellField(const std::string& name, F&& f, const GridFormat::Precision<T>& prec)
192 { GridFormat::Dune::set_cell_function(std::forward<F>(f), writer_, name, prec); }
193
195 template<GridFormat::Concepts::PointFunction<GridView> F,
196 GridFormat::Concepts::Scalar T = GridFormat::FieldScalar<std::invoke_result_t<F, Vertex>>>
197 void setPointField(const std::string& name, F&& f, const GridFormat::Precision<T>& prec = {})
198 requires (order == 1)
199 { writer_.set_point_field(name, std::move(f), prec); }
200
203 template<Detail::Container C,
204 GridFormat::Concepts::Scalar T = GridFormat::MDRangeScalar<C>>
205 void setPointField(const std::string& name, const C& values,
206 const GridFormat::Precision<T>& prec = {})
207 requires (order > 1)
208 {
209 using Point = typename Grid::Point;
210 writer_.set_point_field(name, [&values](const Point& p) -> std::ranges::range_value_t<C> {
211 return values[p.dofIndex];
212 }, prec);
213 }
214
217 template<GridFormat::Dune::Concepts::Function<GridView> F>
218 void setPointField(const std::string& name, F&& f)
219 { GridFormat::Dune::set_point_function(std::forward<F>(f), writer_, name); }
220
222 template<GridFormat::Dune::Concepts::Function<GridView> F, GridFormat::Concepts::Scalar T>
223 void setPointField(const std::string& name, F&& f, const GridFormat::Precision<T>& prec)
224 { GridFormat::Dune::set_point_function(std::forward<F>(f), writer_, name, prec); }
225
227 void clear()
228 { writer_.clear(); }
229
231 void update()
232 {
233 if constexpr (order > 1)
234 grid_.update(gridView_);
235 }
236
237 private:
238 Grid makeGrid_(const GridView& gv) const
239 {
240 if constexpr (order > 1)
241 return Grid{gv};
242 else
243 return gv;
244 }
245
246 GridView gridView_;
247 Grid grid_;
248 Writer writer_;
249};
250
255template<typename GridVariables, typename SolutionVector>
256class OutputModule : private GridWriter<typename Dumux::GridDiscretization_t<GridVariables>::GridView, 1> {
257 using ParentType = GridWriter<typename Dumux::GridDiscretization_t<GridVariables>::GridView, 1>;
258 using GridView = typename Dumux::GridDiscretization_t<GridVariables>::GridView;
259
260 static constexpr bool isCVFE = DiscretizationMethods::isCVFE<typename Dumux::GridDiscretization_t<GridVariables>::DiscretizationMethod>;
261 static constexpr int dimWorld = Dumux::GridDiscretization_t<GridVariables>::GridView::dimensionworld;
262 using Scalar = typename GridVariables::Scalar;
263 using Vector = Dune::FieldVector<Scalar, dimWorld>;
264 using Tensor = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
265 using VolVar = typename GridVariables::VolumeVariables;
266
267 class VolVarFieldStorage;
268
269 static constexpr int defaultVerbosity_ = 1;
270
271 public:
272 using VolumeVariables = VolVar;
273
274 static constexpr auto defaultFileFormat = IO::Format::pvd_with(
275 IO::Format::vtu.with({
276 .encoder = IO::Encoding::ascii,
277 .compressor = IO::Compression::none,
278 .data_format = VTK::DataFormat::inlined
279 })
280 );
281
285 explicit OutputModule(const GridVariables& gridVariables,
286 const SolutionVector& sol,
287 const std::string& filename)
288 : ParentType{defaultFileFormat, Dumux::gridDiscretization(gridVariables).gridView(), filename, order<1>}
289 , gridVariables_{gridVariables}
290 , solutionVector_{sol}
291 {
292 setVerbosity(defaultVerbosity_);
293 }
294
299 template<typename Format>
300 explicit OutputModule(const Format& fmt,
301 const GridVariables& gridVariables,
302 const SolutionVector& sol)
303 : ParentType{fmt, Dumux::gridDiscretization(gridVariables).gridView(), order<1>}
304 , gridVariables_{gridVariables}
305 , solutionVector_{sol}
306 {
307 setVerbosity(defaultVerbosity_);
308 }
309
314 template<typename Format>
315 explicit OutputModule(const Format& fmt,
316 const GridVariables& gridVariables,
317 const SolutionVector& sol,
318 const std::string& filename)
319 : ParentType{fmt, Dumux::gridDiscretization(gridVariables).gridView(), filename, order<1>}
320 , gridVariables_{gridVariables}
321 , solutionVector_{sol}
322 {
323 setVerbosity(defaultVerbosity_);
324 }
325
329 template<std::invocable<const VolumeVariables&> VolVarFunction>
330 void addVolumeVariable(VolVarFunction&& f, const std::string& name)
331 {
332 using ResultType = std::invoke_result_t<std::remove_cvref_t<VolVarFunction>, const VolumeVariables&>;
333 if constexpr (GridFormat::Concepts::Scalar<ResultType>)
334 setVolVarField_<ResultType>(name, volVarFields_.registerScalarField(name, [_f=std::move(f)] (const auto& vv) {
335 return static_cast<Scalar>(_f(vv));
336 }));
337 else if constexpr (GridFormat::mdrange_dimension<ResultType> == 1)
338 setVolVarField_<GridFormat::MDRangeScalar<ResultType>>(name, volVarFields_.registerVectorField(name, [_f=std::move(f)] (const auto& vv) {
339 return VolVarFieldStorage::toStorageVector(_f(vv));
340 }));
341 else if constexpr (GridFormat::mdrange_dimension<ResultType> == 2)
342 setVolVarField_<GridFormat::MDRangeScalar<ResultType>>(name, volVarFields_.registerTensorField(name, [_f=std::move(f)] (const auto& vv) {
343 return VolVarFieldStorage::toStorageTensor(_f(vv));
344 }));
345 else
346 {
347 static_assert(
348 Dune::AlwaysFalse<VolVarFunction>::value,
349 "Could not identify the given volume variable as scalar, vector or tensor."
350 );
351 }
352 }
353
358 template<Detail::Container C>
359 void addField(const C& values, const std::string& name)
360 { addField(values, name, GridFormat::Precision<GridFormat::MDRangeScalar<C>>{}); }
361
366 template<Detail::Container C, GridFormat::Concepts::Scalar T>
367 void addField(const C& values, const std::string& name, const GridFormat::Precision<T>& prec)
368 {
369 const bool hasCellSize = values.size() == gridDisc_().elementMapper().size();
370 const bool hasPointSize = values.size() == gridDisc_().vertexMapper().size();
371 if (hasCellSize && hasPointSize)
372 DUNE_THROW(Dune::InvalidStateException, "Automatic deduction of field type failed. Please use addCellField or addPointField instead.");
373 if (!hasCellSize && !hasPointSize)
374 DUNE_THROW(Dune::InvalidStateException, "Automatic deduction of field type failed. Given container size does not match neither the number of points nor cells.");
375
376 if (hasCellSize)
377 addCellField(values, name, prec);
378 else
379 addPointField(values, name, prec);
380 }
381
385 template<GridFormat::Concepts::PointFunction<GridView> DofFunction>
386 void addPointField(DofFunction&& f, const std::string& name)
387 { this->setPointField(name, std::forward<DofFunction>(f)); }
388
392 template<Detail::Container C>
393 void addPointField(const C& values, const std::string& name)
394 { addPointField(values, name, GridFormat::Precision<GridFormat::MDRangeScalar<C>>{}); }
395
399 template<Detail::Container C, GridFormat::Concepts::Scalar T>
400 void addPointField(const C& values, const std::string& name, const GridFormat::Precision<T>& prec)
401 {
402 if (values.size() != gridDisc_().vertexMapper().size())
403 DUNE_THROW(Dune::InvalidStateException, "Given container does not match the number of points in the grid");
404
405 addPointField_(values, name, prec);
406 }
407
411 template<GridFormat::Concepts::CellFunction<GridView> DofFunction>
412 void addCellField(DofFunction&& f, const std::string& name)
413 { this->setCellField(name, std::forward<DofFunction>(f)); }
414
418 template<Detail::Container C>
419 void addCellField(const C& values, const std::string& name)
420 { addCellField(values, name, GridFormat::Precision<GridFormat::MDRangeScalar<C>>{}); }
421
425 template<Detail::Container C, GridFormat::Concepts::Scalar T>
426 void addCellField(const C& values, const std::string& name, const GridFormat::Precision<T>& prec)
427 {
428 if (values.size() != gridDisc_().elementMapper().size())
429 DUNE_THROW(Dune::InvalidStateException, "Given container does not match the number of cells in the grid");
430
431 addCellField_(values, name, prec);
432 }
433
437 std::string write(const std::string& name)
438 {
439 Dune::Timer timer;
440
441 volVarFields_.updateFieldData(gridVariables_, solutionVector_);
442 auto filename = ParentType::write(name);
443 volVarFields_.clearFieldData();
444
445 timer.stop();
446 if (verbosity_ > 0)
447 std::cout << Fmt::format(
448 "Writing output to \"{}\". Took {:.2g} seconds.\n",
449 filename, timer.elapsed()
450 );
451
452 return filename;
453 }
454
458 template<std::floating_point T>
459 std::string write(T time)
460 {
461 Dune::Timer timer;
462
463 volVarFields_.updateFieldData(gridVariables_, solutionVector_);
464 auto filename = ParentType::write(time);
465 volVarFields_.clearFieldData();
466
467 timer.stop();
468 if (verbosity_ > 0)
469 std::cout << Fmt::format(
470 "Writing output to \"{}\". Took {:.2g} seconds.\n",
471 filename, timer.elapsed()
472 );
473
474 return filename;
475 }
476
478 void clear() {
479 ParentType::clear();
480 volVarFields_.clear();
481 }
482
483 void setVerbosity(int verbosity)
484 {
485 if (gridDisc_().gridView().comm().rank() == 0)
486 verbosity_ = verbosity;
487 }
488
489private:
490 // reproduce behaviour of VtkOutputModule that flattens vectors of size 1
491 template<Detail::Container C, GridFormat::Concepts::Scalar T>
492 requires(GridFormat::has_sub_range<C> && std::ranges::range_value_t<C>::size() == 1)
493 void addPointField_(const C& values, const std::string& name, const GridFormat::Precision<T>& prec)
494 {
495 this->setPointField(name, [&] (const auto& vertex) -> T {
496 return values[gridDisc_().vertexMapper().index(vertex)][0];
497 }, prec);
498 }
499
500 template<Detail::Container C, GridFormat::Concepts::Scalar T>
501 void addPointField_(const C& values, const std::string& name, const GridFormat::Precision<T>& prec)
502 {
503 this->setPointField(name, [&] (const auto& vertex) -> std::ranges::range_value_t<C> {
504 return values[gridDisc_().vertexMapper().index(vertex)];
505 }, prec);
506 }
507
508 // reproduce behaviour of VtkOutputModule that flattens vectors of size 1
509 template<Detail::Container C, GridFormat::Concepts::Scalar T>
510 requires(GridFormat::has_sub_range<C> && std::ranges::range_value_t<C>::size() == 1)
511 void addCellField_(const C& values, const std::string& name, const GridFormat::Precision<T>& prec)
512 {
513 this->setCellField(name, [&] (const auto& element) -> T {
514 return values[gridDisc_().elementMapper().index(element)][0];
515 }, prec);
516 }
517
518 template<Detail::Container C, GridFormat::Concepts::Scalar T>
519 void addCellField_(const C& values, const std::string& name, const GridFormat::Precision<T>& prec)
520 {
521 this->setCellField(name, [&] (const auto& element) -> std::ranges::range_value_t<C> {
522 return values[gridDisc_().elementMapper().index(element)];
523 }, prec);
524 }
525
526 template<typename ResultType, typename Id>
527 void setVolVarField_(const std::string& name, Id&& volVarFieldId)
528 {
529 auto dofEntityField = [&, _id=std::move(volVarFieldId)] (const auto& entity) {
530 return volVarFields_.getValue(_id, gridDisc_().dofMapper().index(entity));
531 };
532 if constexpr (isCVFE)
533 this->setPointField(name, std::move(dofEntityField), GridFormat::Precision<ResultType>{});
534 else
535 this->setCellField(name, std::move(dofEntityField), GridFormat::Precision<ResultType>{});
536 }
537
538 const auto& gridDisc_() const
539 { return Dumux::gridDiscretization(gridVariables_); }
540
541 const GridVariables& gridVariables_;
542 const SolutionVector& solutionVector_;
543 VolVarFieldStorage volVarFields_;
544 int verbosity_ = 0;
545};
546
547// Class to store vol var fields; implementation detail of the OutputModule class
548template<typename GridVariables, typename SolutionVector>
549class OutputModule<GridVariables, SolutionVector>::VolVarFieldStorage
550{
551 enum class FieldType
552 { scalar, vector, tensor };
553
554 struct FieldInfo
555 {
556 std::string name;
557 FieldType type;
558 std::size_t index;
559 };
560
561 template<typename T>
562 struct FieldStorage
563 {
564 std::vector<T> data;
565 std::function<T(const VolVar&)> getter;
566 };
567
568public:
569 template<FieldType ft>
570 struct FieldId { std::size_t index; };
571
572 template<std::ranges::range R>
573 static constexpr auto toStorageVector(R&& in)
574 {
575 Vector result;
576 std::ranges::copy(in, result.begin());
577 return result;
578 }
579
580 template<GridFormat::Concepts::MDRange<2> R>
581 static constexpr auto toStorageTensor(R&& in)
582 {
583 Tensor result;
584 std::ranges::for_each(in, [&, i=0] (const auto& row) mutable {
585 std::ranges::copy(row, result[i++].begin());
586 });
587 return result;
588 }
589
590 template<FieldType ft>
591 const auto& getValue(const FieldId<ft>& id, std::size_t idx) const
592 {
593 if constexpr (ft == FieldType::scalar)
594 return scalarFieldStorage_.at(id.index).data.at(idx);
595 else if constexpr (ft == FieldType::vector)
596 return vectorFieldStorage_.at(id.index).data.at(idx);
597 else
598 return tensorFieldStorage_.at(id.index).data.at(idx);
599 }
600
601 auto registerScalarField(std::string name, std::function<Scalar(const VolVar&)> f)
602 { return register_<FieldType::scalar>(std::move(name), scalarFieldStorage_, std::move(f)); }
603
604 auto registerVectorField(std::string name, std::function<Vector(const VolVar&)> f)
605 { return register_<FieldType::vector>(std::move(name), vectorFieldStorage_, std::move(f)); }
606
607 auto registerTensorField(std::string name, std::function<Tensor(const VolVar&)> f)
608 { return register_<FieldType::tensor>(std::move(name), tensorFieldStorage_, std::move(f)); }
609
610 void updateFieldData(const GridVariables& gridVars, const SolutionVector& x)
611 {
612 const auto& gridDisc = Dumux::gridDiscretization(gridVars);
613 resizeFieldData_(gridDisc.numDofs());
614 const auto range = GridFormat::cells(gridDisc.gridView());
615 std::for_each(
616#if __cpp_lib_parallel_algorithm >= 201603L
617 std::execution::par_unseq,
618#endif
619 std::ranges::begin(range),
620 std::ranges::end(range),
621 [&] (const auto& element) {
622 auto fvGeometry = localView(gridDisc).bindElement(element);
623 auto elemVolVars = localView(gridVars.curGridVolVars()).bindElement(element, fvGeometry, x);
624 for (const auto& scv : scvs(fvGeometry))
625 {
626 const auto& volVars = elemVolVars[scv];
627 for (auto& s : scalarFieldStorage_) { s.data.at(scv.dofIndex()) = s.getter(volVars); }
628 for (auto& s : vectorFieldStorage_) { s.data.at(scv.dofIndex()) = s.getter(volVars); }
629 for (auto& s : tensorFieldStorage_) { s.data.at(scv.dofIndex()) = s.getter(volVars); }
630 }
631 });
632 }
633
634 void clearFieldData()
635 {
636 for (auto& s : scalarFieldStorage_) { s.data.clear(); }
637 for (auto& s : vectorFieldStorage_) { s.data.clear(); }
638 for (auto& s : tensorFieldStorage_) { s.data.clear(); }
639 }
640
641 void clear()
642 {
643 fields_.clear();
644 scalarFieldStorage_.clear();
645 vectorFieldStorage_.clear();
646 tensorFieldStorage_.clear();
647 }
648
649private:
650 template<FieldType ft, typename T>
651 auto register_(std::string&& name,
652 std::vector<FieldStorage<T>>& storage,
653 std::function<T(const VolVar&)>&& f)
654 {
655 if (exists_<ft>(name))
656 DUNE_THROW(Dune::InvalidStateException, "Volume variables field '" << name << "' is already defined.");
657
658 FieldId<ft> id{storage.size()};
659 fields_.emplace_back(FieldInfo{std::move(name), ft, id.index});
660 storage.push_back({{}, std::move(f)});
661 return id;
662 }
663
664 template<FieldType ft>
665 bool exists_(const std::string& name) const
666 {
667 return std::ranges::any_of(fields_, [&] (const FieldInfo& info) {
668 return info.type == ft && info.name == name;
669 });
670 }
671
672 void resizeFieldData_(std::size_t size)
673 {
674 std::ranges::for_each(scalarFieldStorage_, [&] (auto& s) { s.data.resize(size); });
675 std::ranges::for_each(vectorFieldStorage_, [&] (auto& s) { s.data.resize(size); });
676 std::ranges::for_each(tensorFieldStorage_, [&] (auto& s) { s.data.resize(size); });
677 }
678
679 std::vector<FieldInfo> fields_;
680 std::vector<FieldStorage<Scalar>> scalarFieldStorage_;
681 std::vector<FieldStorage<Vector>> vectorFieldStorage_;
682 std::vector<FieldStorage<Tensor>> tensorFieldStorage_;
683};
684
685} // namespace Dumux::IO
686
687#else // DUMUX_HAVE_GRIDFORMAT
688
689namespace Dumux::IO {
690
691template<class... Args>
693{
694public:
695 template<class... _Args>
696 GridWriter(_Args&&...)
697 {
698 static_assert(
699 false,
700 "GridWriter only available when the GridFormat library is available. "
701 "Use `git submodule update --init` to pull it and reconfigure the project "
702 "(note: C++20 is required)."
703 );
704 }
705};
706
707template<class... Args>
709{
710public:
711 template<class... _Args>
712 OutputModule(_Args&&...)
713 {
714 static_assert(
715 false,
716 "OutputModule only available when the GridFormat library is available. "
717 "Use `git submodule update --init` to pull it and reconfigure the project "
718 "(note: C++20 is required)."
719 );
720 }
721};
722
723} // namespace Dumux::IO
724
725#endif // DUMUX_HAVE_GRIDFORMAT
726#endif // DUMUX_IO_GRID_HH
Definition gridwriter.hh:693
GridWriter(_Args &&...)
Definition gridwriter.hh:696
Definition gridwriter.hh:709
OutputModule(_Args &&...)
Definition gridwriter.hh:712
A gridformat-compatible grid type for CVFE discretizations that uses DuMux DOF indices directly for V...
Formatting based on the fmt-library which implements std::format of C++20.
Type traits for classes providing a grid discretization.
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition localview.hh:26
FieldType
Identifier for vtk field types.
Definition fieldtype.hh:22
T getParam(Args &&... args)
A free function to get a parameter from the parameter tree singleton.
Definition parameters.hh:139
decltype(auto) gridDiscretization(const T &t, Args &&... args)
The grid discretization.
Definition griddiscretization.hh:65
The available discretization methods in Dumux.
constexpr bool isCVFE
Definition method.hh:67
Definition cvfegridfunction.hh:31
std::ranges::range auto scvs(const FVElementGeometry &fvGeometry, const LocalDof &localDof)
Definition localdof.hh:82
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.