version 3.11-dev
Loading...
Searching...
No Matches
io/vtkoutputmodule.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
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_VTK_OUTPUT_MODULE_HH
13#define DUMUX_IO_VTK_OUTPUT_MODULE_HH
14
15#include <functional>
16#include <memory>
17#include <string>
18
19#include <dune/common/timer.hh>
20#include <dune/common/fvector.hh>
21#include <dune/common/typetraits.hh>
22
23#include <dune/geometry/type.hh>
24#include <dune/geometry/multilineargeometry.hh>
25
26#include <dune/grid/common/mcmgmapper.hh>
27#include <dune/grid/common/partitionset.hh>
28#include <dune/grid/io/file/vtk/vtkwriter.hh>
29#include <dune/grid/io/file/vtk/vtksequencewriter.hh>
30#include <dune/grid/common/partitionset.hh>
31
32#include <dumux/common/concepts/variables_.hh>
35#include <dumux/common/typetraits/localdofs_.hh>
36#include <dumux/io/format.hh>
40
43#include "velocityoutput.hh"
44
45namespace Dumux {
46
52template<class GridGeometry>
54{
55 using GridView = typename GridGeometry::GridView;
56 static constexpr int dim = GridView::dimension;
57
58public:
60 using Field = Vtk::template Field<GridView>;
61
62 VtkOutputModuleBase(const GridGeometry& gridGeometry,
63 const std::string& name,
64 const std::string& paramGroup = "",
65 Dune::VTK::DataMode dm = Dune::VTK::conforming,
66 bool verbose = true)
67 : gridGeometry_(gridGeometry)
68 , name_(name)
69 , paramGroup_(paramGroup)
70 , dm_(dm)
71 , verbose_(gridGeometry.gridView().comm().rank() == 0 && verbose)
72 {
73 const auto precisionString = getParamFromGroup<std::string>(paramGroup, "Vtk.Precision", "Float32");
74 precision_ = Dumux::Vtk::stringToPrecision(precisionString);
75 const auto coordPrecision = Dumux::Vtk::stringToPrecision(getParamFromGroup<std::string>(paramGroup, "Vtk.CoordPrecision", precisionString));
76 writer_ = std::make_shared<Dune::VTKWriter<GridView>>(gridGeometry.gridView(), dm, coordPrecision);
77 sequenceWriter_ = std::make_unique<Dune::VTKSequenceWriter<GridView>>(writer_, name);
78 addProcessRank_ = getParamFromGroup<bool>(this->paramGroup(), "Vtk.AddProcessRank", true);
79 }
80
81 virtual ~VtkOutputModuleBase() = default;
82
84 const std::string& paramGroup() const
85 { return paramGroup_; }
86
96 template<typename Vector>
97 void addField(const Vector& v,
98 const std::string& name,
100 { addField(v, name, this->precision(), fieldType); }
101
112 template<typename Vector>
113 void addField(const Vector& v,
114 const std::string& name,
115 Dumux::Vtk::Precision precision,
117 {
118 // Deduce the number of components from the given vector type
119 const auto nComp = getNumberOfComponents_(v);
120
121 const auto numElemDofs = gridGeometry().elementMapper().size();
122 const auto numVertexDofs = gridGeometry().vertexMapper().size();
123
124 // Automatically deduce the field type ...
125 if(fieldType == Vtk::FieldType::automatic)
126 {
127 if(numElemDofs == numVertexDofs)
128 DUNE_THROW(Dune::InvalidStateException, "Automatic deduction of FieldType failed. Please explicitly specify FieldType::element or FieldType::vertex.");
129
130 if(v.size() == numElemDofs)
131 fieldType = Vtk::FieldType::element;
132 else if(v.size() == numVertexDofs)
133 fieldType = Vtk::FieldType::vertex;
134 else
135 DUNE_THROW(Dune::RangeError, "Size mismatch of added field!");
136 }
137 // ... or check if the user-specified type matches the size of v
138 else
139 {
140 if(fieldType == Vtk::FieldType::element)
141 if(v.size() != numElemDofs)
142 DUNE_THROW(Dune::RangeError, "Size mismatch of added field!");
143
144 if(fieldType == Vtk::FieldType::vertex)
145 if(v.size() != numVertexDofs)
146 DUNE_THROW(Dune::RangeError, "Size mismatch of added field!");
147 }
148
149 // add the appropriate field
150 if (fieldType == Vtk::FieldType::element)
151 addField(Field(gridGeometry_.gridView(), gridGeometry_.elementMapper(), v, name, nComp, 0, dm_, precision));
152 else
153 addField(Field(gridGeometry_.gridView(), gridGeometry_.vertexMapper(), v, name, nComp, dim, dm_, precision));
154 }
155
160 void addField(Field&& field)
161 {
162 // data arrays in the vtk output have to be unique within cell and point data
163 // look if we have a field by the same name with the same codim, if so, replace it
164 for (auto i = 0UL; i < fields_.size(); ++i)
165 {
166 if (fields_[i].name() == field.name() && fields_[i].codim() == field.codim())
167 {
168 fields_[i] = std::move(field);
169 std::cout << Fmt::format(
170 "VtkOutputModule: Replaced field \"{}\" (codim {}). "
171 "A field by the same name & codim had already been registered previously.\n",
172 field.name(), field.codim()
173 );
174 return;
175 }
176 }
177
178 // otherwise add it to the end of the fields
179 fields_.push_back(std::move(field));
180 }
181
187 void write(double time, Dune::VTK::OutputType type = Dune::VTK::ascii)
188 {
189 Dune::Timer timer;
190
191 // write to file depending on data mode
192 if (dm_ == Dune::VTK::conforming)
193 writeConforming_(time, type);
194 else if (dm_ == Dune::VTK::nonconforming)
195 writeNonConforming_(time, type);
196 else
197 DUNE_THROW(Dune::NotImplemented, "Output for provided VTK data mode");
198
200 timer.stop();
201 if (verbose_)
202 std::cout << Fmt::format("Writing output for problem \"{}\". Took {:.2g} seconds.\n", name_, timer.elapsed());
203 }
204
205protected:
206 const GridGeometry& gridGeometry() const { return gridGeometry_; }
207
208 bool verbose() const { return verbose_; }
209 const std::string& name() const { return name_; }
210 Dune::VTK::DataMode dataMode() const { return dm_; }
211 Dumux::Vtk::Precision precision() const { return precision_; }
212
213 Dune::VTKWriter<GridView>& writer() { return *writer_; }
214 Dune::VTKSequenceWriter<GridView>& sequenceWriter() { return *sequenceWriter_; }
215
216 const std::vector<Field>& fields() const { return fields_; }
217
218 void addCellData(const Field& field)
219 {
220 if (std::ranges::find(addedCellData_, field.name()) == addedCellData_.end())
221 {
222 this->sequenceWriter().addCellData(field.get());
223 addedCellData_.push_back(field.name());
224 }
225 }
226
227 void addVertexData(const Field& field)
228 {
229 if (std::ranges::find(addedVertexData_, field.name()) == addedVertexData_.end())
230 {
231 this->sequenceWriter().addVertexData(field.get());
232 addedVertexData_.push_back(field.name());
233 }
234 }
235
236 // keep track of what has been already added because Dune::VTK::Writer
237 // potentially adds the same field twice which is not allowed in VTK/Paraview
238 std::vector<std::string> addedCellData_;
239 std::vector<std::string> addedVertexData_;
240
241private:
243 virtual void writeConforming_(double time, Dune::VTK::OutputType type)
244 {
248
249 // process rank
250 std::vector<int> rank;
251
253 if (!fields_.empty() || addProcessRank_)
254 {
255 const auto numCells = gridGeometry_.gridView().size(0);
256
257 // maybe allocate space for the process rank
258 if (addProcessRank_)
259 {
260 rank.resize(numCells);
261
262 for (const auto& element : elements(gridGeometry_.gridView(), Dune::Partitions::interior))
263 {
264 const auto eIdxGlobal = gridGeometry_.elementMapper().index(element);
265 rank[eIdxGlobal] = gridGeometry_.gridView().comm().rank();
266 }
267 }
268
272
273 // the process rank
274 if (addProcessRank_)
275 this->addCellData(Field(gridGeometry_.gridView(), gridGeometry_.elementMapper(), rank, "process rank", 1, 0));
276
277 // also register additional (non-standardized) user fields if any
278 for (auto&& field : fields_)
279 {
280 if (field.codim() == 0)
281 this->addCellData(field);
282 else if (field.codim() == dim)
283 this->addVertexData(field);
284 else
285 DUNE_THROW(Dune::RangeError, "Cannot add wrongly sized vtk scalar field!");
286 }
287 }
288
292 this->sequenceWriter().write(time, type);
293
297 this->writer().clear();
298
299 this->addedCellData_.clear();
300 this->addedVertexData_.clear();
301 }
302
304 virtual void writeNonConforming_(double time, Dune::VTK::OutputType type)
305 {
306 DUNE_THROW(Dune::NotImplemented, "Non-conforming VTK output");
307 }
308
310 template<class Vector>
311 std::size_t getNumberOfComponents_(const Vector& v)
312 {
313 if constexpr (Dune::IsIndexable<decltype(std::declval<Vector>()[0])>::value)
314 return v[0].size();
315 else
316 return 1;
317 }
318
319 const GridGeometry& gridGeometry_;
320 std::string name_;
321 const std::string paramGroup_;
322 Dune::VTK::DataMode dm_;
323 bool verbose_;
324 Dumux::Vtk::Precision precision_;
325
326 std::shared_ptr<Dune::VTKWriter<GridView>> writer_;
327 std::unique_ptr<Dune::VTKSequenceWriter<GridView>> sequenceWriter_;
328
329 std::vector<Field> fields_;
330
331 bool addProcessRank_ = true;
332};
333
346template<class GridVariables, class SolutionVector>
347class VtkOutputModule : public VtkOutputModuleBase<Dumux::GridDiscretization_t<GridVariables>>
348{
351
352 using VV = Concept::Variables_t<GridVariables>;
353 using Scalar = typename GridVariables::Scalar;
354
355 using GridView = typename GridGeometry::GridView;
356
357 enum {
358 dim = GridView::dimension,
359 dimWorld = GridView::dimensionworld
360 };
361
362 using Element = typename GridView::template Codim<0>::Entity;
363 using VolVarsVector = Dune::FieldVector<Scalar, dimWorld>;
364
365 static constexpr bool isBox = GridGeometry::discMethod == DiscretizationMethods::box;
366 static constexpr bool isDiamond = GridGeometry::discMethod == DiscretizationMethods::fcdiamond;
367 static constexpr bool isPQ1Bubble = GridGeometry::discMethod == DiscretizationMethods::pq1bubble;
368 static constexpr bool isPQ2 = GridGeometry::discMethod == DiscretizationMethods::pq2;
369
370 struct VolVarScalarDataInfo { std::function<Scalar(const VV&)> get; std::string name; Dumux::Vtk::Precision precision_; };
371 struct VolVarVectorDataInfo { std::function<VolVarsVector(const VV&)> get; std::string name; Dumux::Vtk::Precision precision_; };
372
373 using VelocityOutputType = Dumux::VelocityOutput<GridVariables>;
374
375public:
377 using Field = Vtk::template Field<GridView>;
379 using VolumeVariables = VV;
380
381 VtkOutputModule(const GridVariables& gridVariables,
382 const SolutionVector& sol,
383 const std::string& name,
384 const std::string& paramGroup = "",
385 Dune::VTK::DataMode dm = Dune::VTK::conforming,
386 bool verbose = true)
388 , gridVariables_(gridVariables)
389 , sol_(sol)
390 , velocityOutput_(std::make_shared<VelocityOutputType>())
391 {
392 enableVelocityOutput_ = getParamFromGroup<bool>(this->paramGroup(), "Vtk.AddVelocity", false);
393 addProcessRank_ = getParamFromGroup<bool>(this->paramGroup(), "Vtk.AddProcessRank", true);
394 }
395
400
407 void addVelocityOutput(std::shared_ptr<VelocityOutputType> velocityOutput)
408 { velocityOutput_ = velocityOutput; }
409
413 void addVolumeVariable(std::function<Scalar(const VolumeVariables&)>&& f,
414 const std::string& name)
415 {
416 // data arrays in the vtk output have to be unique within cell and point data
417 // look if we have a field by the same name with the same codim, if so, replace it
418 for (auto i = 0UL; i < volVarScalarDataInfo_.size(); ++i)
419 {
420 if (volVarScalarDataInfo_[i].name == name)
421 {
422 volVarScalarDataInfo_[i] = VolVarScalarDataInfo{f, name, this->precision()};
423 std::cout << Fmt::format(
424 "VtkOutputModule: Replaced volume variable output \"{}\". "
425 "A field by the same name had already been registered previously.\n",
426 name
427 );
428 return;
429 }
430 }
431
432 // otherwise add it to the end of the fields
433 volVarScalarDataInfo_.push_back(VolVarScalarDataInfo{f, name, this->precision()});
434 }
435
440 template<class VVV = VolVarsVector, typename std::enable_if_t<(VVV::dimension > 1), int> = 0>
441 void addVolumeVariable(std::function<VolVarsVector(const VolumeVariables&)>&& f,
442 const std::string& name)
443 {
444 // data arrays in the vtk output have to be unique within cell and point data
445 // look if we have a field by the same name with the same codim, if so, replace it
446 for (auto i = 0UL; i < volVarVectorDataInfo_.size(); ++i)
447 {
448 if (volVarVectorDataInfo_[i].name == name)
449 {
450 volVarVectorDataInfo_[i] = VolVarVectorDataInfo{f, name, this->precision()};
451 std::cout << Fmt::format(
452 "VtkOutputModule: Replaced volume variable output \"{}\". "
453 "A field by the same name had already been registered previously.\n",
454 name
455 );
456 return;
457 }
458 }
459
460 // otherwise add it to the end of the fields
461 volVarVectorDataInfo_.push_back(VolVarVectorDataInfo{f, name, this->precision()});
462 }
463
464protected:
465 // some return functions for differing implementations to use
466 const auto& problem() const { return curGridVariables_().problem(); }
467 const GridVariables& gridVariables() const { return gridVariables_; }
468 const GridGeometry& gridGeometry() const { return Dumux::gridDiscretization(gridVariables_); }
469 const SolutionVector& sol() const { return sol_; }
470
471 const std::vector<VolVarScalarDataInfo>& volVarScalarDataInfo() const { return volVarScalarDataInfo_; }
472 const std::vector<VolVarVectorDataInfo>& volVarVectorDataInfo() const { return volVarVectorDataInfo_; }
473
474 using VelocityOutput = VelocityOutputType;
475 const VelocityOutput& velocityOutput() const { return *velocityOutput_; }
476
477 const auto& curGridVariables_() const
478 {
479 if constexpr (Concept::FVGridVariables<GridVariables>)
480 return gridVariables_.curGridVolVars();
481 else
482 return gridVariables_.curGridVars();
483 }
484
485private:
486
488 void writeConforming_(double time, Dune::VTK::OutputType type) override
489 {
490 const Dune::VTK::DataMode dm = Dune::VTK::conforming;
494
495 // instantiate the velocity output
496 using VelocityVector = typename VelocityOutput::VelocityVector;
497 std::vector<VelocityVector> velocity(velocityOutput_->numFluidPhases());
498
499 // process rank
500 std::vector<double> rank;
501
502 // volume variable data
503 std::vector<std::vector<Scalar>> volVarScalarData;
504 std::vector<std::vector<VolVarsVector>> volVarVectorData;
505
507 if (!volVarScalarDataInfo_.empty()
508 || !volVarVectorDataInfo_.empty()
509 || !this->fields().empty()
510 || velocityOutput_->enableOutput()
511 || addProcessRank_)
512 {
513 const auto numCells = gridGeometry().gridView().size(0);
514 const auto numDofs = numDofs_();
515
516 // get fields for all volume variables
517 if (!volVarScalarDataInfo_.empty())
518 volVarScalarData.resize(volVarScalarDataInfo_.size(), std::vector<Scalar>(numDofs));
519 if (!volVarVectorDataInfo_.empty())
520 volVarVectorData.resize(volVarVectorDataInfo_.size(), std::vector<VolVarsVector>(numDofs));
521
522 if (velocityOutput_->enableOutput())
523 {
524 for (int phaseIdx = 0; phaseIdx < velocityOutput_->numFluidPhases(); ++phaseIdx)
525 {
526 if (velocityOutput_->fieldType() == VelocityOutput::FieldType::element)
527 velocity[phaseIdx].resize(numCells);
528 else if (velocityOutput_->fieldType() == VelocityOutput::FieldType::vertex)
529 velocity[phaseIdx].resize(numDofs);
530 else
531 {
532 if(isBox && dim == 1)
533 velocity[phaseIdx].resize(numCells);
534 else
535 velocity[phaseIdx].resize(numDofs);
536 }
537 }
538 }
539
540 // maybe allocate space for the process rank
541 if (addProcessRank_) rank.resize(numCells);
542
543 auto fvGeometry = localView(gridGeometry());
544 auto elemVolVars = localView(curGridVariables_());
545 for (const auto& element : elements(gridGeometry().gridView()))
546 {
547 if (!velocityOutput_->enableOutput() &&
548 element.partitionType() != Dune::PartitionType::InteriorEntity)
549 {
550 continue;
551 }
552 const auto eIdxGlobal = gridGeometry().elementMapper().index(element);
553 // If velocity output is enabled we need to bind to the whole stencil
554 // otherwise element-local data is sufficient
555 if (velocityOutput_->enableOutput())
556 {
557 fvGeometry.bind(element);
558 elemVolVars.bind(element, fvGeometry, sol_);
559 }
560 else
561 {
562 fvGeometry.bindElement(element);
563 elemVolVars.bindElement(element, fvGeometry, sol_);
564 }
565
566 // velocity output
567 if (velocityOutput_->enableOutput())
568 {
569 if constexpr (Concept::FVGridVariables<GridVariables>)
570 {
571 const auto elemFluxVarsCache = localView(gridVariables_.gridFluxVarsCache()).bind(element, fvGeometry, elemVolVars);
572
573 for (int phaseIdx = 0; phaseIdx < velocityOutput_->numFluidPhases(); ++phaseIdx)
574 velocityOutput_->calculateVelocity(velocity[phaseIdx], element, fvGeometry, elemVolVars, elemFluxVarsCache, phaseIdx);
575 }
576 else
577 {
578 for (int phaseIdx = 0; phaseIdx < velocityOutput_->numFluidPhases(); ++phaseIdx)
579 velocityOutput_->calculateVelocity(velocity[phaseIdx], element, fvGeometry, elemVolVars, phaseIdx);
580 }
581 }
582 else if (element.partitionType() != Dune::PartitionType::InteriorEntity)
583 {
584 continue;
585 }
586
587 if (!volVarScalarDataInfo_.empty() || !volVarVectorDataInfo_.empty())
588 {
589 using ElementDisc = typename GridGeometry::LocalView;
591 {
592 for (const auto& scv : scvs(fvGeometry))
593 {
594 const auto dofIdxGlobal = scv.dofIndex();
595 const auto& volVars = elemVolVars[scv];
596
597 // get the scalar-valued data
598 for (std::size_t i = 0; i < volVarScalarDataInfo_.size(); ++i)
599 volVarScalarData[i][dofIdxGlobal] = volVarScalarDataInfo_[i].get(volVars);
600
601 // get the vector-valued data
602 for (std::size_t i = 0; i < volVarVectorDataInfo_.size(); ++i)
603 volVarVectorData[i][dofIdxGlobal] = volVarVectorDataInfo_[i].get(volVars);
604 }
605 }
608 {
609 for (const auto& localDof : nonCVLocalDofs(fvGeometry))
610 {
611 const auto dofIdxGlobal = localDof.dofIndex();
612 const auto& volVars = elemVolVars[localDof];
613
614 // get the scalar-valued data
615 for (std::size_t i = 0; i < volVarScalarDataInfo_.size(); ++i)
616 volVarScalarData[i][dofIdxGlobal] = volVarScalarDataInfo_[i].get(volVars);
617
618 // get the vector-valued data
619 for (std::size_t i = 0; i < volVarVectorDataInfo_.size(); ++i)
620 volVarVectorData[i][dofIdxGlobal] = volVarVectorDataInfo_[i].get(volVars);
621 }
622 }
623 }
624
626 if (addProcessRank_)
627 rank[eIdxGlobal] = static_cast<double>(gridGeometry().gridView().comm().rank());
628 }
629
633
634 // volume variables if any
635 if constexpr (isBox || isPQ1Bubble || isPQ2)
636 {
637 for (std::size_t i = 0; i < volVarScalarDataInfo_.size(); ++i)
638 this->addVertexData( Field(gridGeometry().gridView(), gridGeometry().dofMapper(), volVarScalarData[i],
639 volVarScalarDataInfo_[i].name, /*numComp*/1, /*codim*/dim, dm, this->precision()) );
640 for (std::size_t i = 0; i < volVarVectorDataInfo_.size(); ++i)
641 this->addVertexData( Field(gridGeometry().gridView(), gridGeometry().dofMapper(), volVarVectorData[i],
642 volVarVectorDataInfo_[i].name, /*numComp*/dimWorld, /*codim*/dim, dm, this->precision()) );
643
644 if constexpr (isPQ1Bubble)
645 {
646 for (std::size_t i = 0; i < volVarScalarDataInfo_.size(); ++i)
647 this->addCellData( Field(gridGeometry().gridView(), gridGeometry().dofMapper(), volVarScalarData[i],
648 volVarScalarDataInfo_[i].name, /*numComp*/1, /*codim*/0,dm, this->precision()) );
649 for (std::size_t i = 0; i < volVarVectorDataInfo_.size(); ++i)
650 this->addCellData( Field(gridGeometry().gridView(), gridGeometry().dofMapper(), volVarVectorData[i],
651 volVarVectorDataInfo_[i].name, /*numComp*/dimWorld, /*codim*/0,dm, this->precision()) );
652 }
653
654 }
655 else
656 {
657 for (std::size_t i = 0; i < volVarScalarDataInfo_.size(); ++i)
658 this->addCellData( Field(gridGeometry().gridView(), gridGeometry().elementMapper(), volVarScalarData[i],
659 volVarScalarDataInfo_[i].name, /*numComp*/1, /*codim*/0,dm, this->precision()) );
660 for (std::size_t i = 0; i < volVarVectorDataInfo_.size(); ++i)
661 this->addCellData( Field(gridGeometry().gridView(), gridGeometry().elementMapper(), volVarVectorData[i],
662 volVarVectorDataInfo_[i].name, /*numComp*/dimWorld, /*codim*/0,dm, this->precision()) );
663 }
664
665 // the velocity field
666 if (velocityOutput_->enableOutput())
667 {
668 if (velocityOutput_->fieldType() == VelocityOutput::FieldType::vertex
669 || ( (velocityOutput_->fieldType() == VelocityOutput::FieldType::automatic) && dim > 1 && isBox ))
670 {
671 for (int phaseIdx = 0; phaseIdx < velocityOutput_->numFluidPhases(); ++phaseIdx)
672 this->addVertexData( Field(gridGeometry().gridView(), gridGeometry().vertexMapper(), velocity[phaseIdx],
673 "velocity_" + velocityOutput_->phaseName(phaseIdx) + " (m/s)",
674 /*numComp*/dimWorld, /*codim*/dim, dm, this->precision()) );
675 }
676 // cell-centered models
677 else
678 {
679 for (int phaseIdx = 0; phaseIdx < velocityOutput_->numFluidPhases(); ++phaseIdx)
680 this->addCellData( Field(gridGeometry().gridView(), gridGeometry().elementMapper(), velocity[phaseIdx],
681 "velocity_" + velocityOutput_->phaseName(phaseIdx) + " (m/s)",
682 /*numComp*/dimWorld, /*codim*/0, dm, this->precision()) );
683 }
684 }
685
686 // the process rank
687 if (addProcessRank_)
688 this->addCellData(Field(gridGeometry().gridView(), gridGeometry().elementMapper(), rank, "process rank", 1, 0));
689
690 // also register additional (non-standardized) user fields if any
691 for (auto&& field : this->fields())
692 {
693 if (field.codim() == 0)
694 this->addCellData(field);
695 else if (field.codim() == dim)
696 this->addVertexData(field);
697 else
698 DUNE_THROW(Dune::RangeError, "Cannot add wrongly sized vtk scalar field!");
699 }
700 }
701
705 this->sequenceWriter().write(time, type);
706
710 this->writer().clear();
711
712 this->addedCellData_.clear();
713 this->addedVertexData_.clear();
714 }
715
717 void writeNonConforming_(double time, Dune::VTK::OutputType type) override
718 {
719 const Dune::VTK::DataMode dm = Dune::VTK::nonconforming;
720
721 // only supports finite-element-like discretization schemes
722 if(!isBox && !isDiamond)
723 DUNE_THROW(Dune::NotImplemented,
724 "Non-conforming output for discretization scheme " << GridGeometry::discMethod
725 );
726
730
731 // check the velocity output
732 if (enableVelocityOutput_ && !velocityOutput_->enableOutput())
733 std::cerr << "Warning! Velocity output was enabled in the input file"
734 << " but no velocity output policy was set for the VTK output module:"
735 << " There will be no velocity output."
736 << " Use the addVelocityOutput member function of the VTK output module." << std::endl;
737 using VelocityVector = typename VelocityOutput::VelocityVector;
738 std::vector<VelocityVector> velocity(velocityOutput_->numFluidPhases());
739
740 // process rank
741 std::vector<double> rank;
742
743 // volume variable data (indexing: volvardata/element/localindex)
744 using ScalarDataContainer = std::vector< std::vector<Scalar> >;
745 using VectorDataContainer = std::vector< std::vector<VolVarsVector> >;
746 std::vector< ScalarDataContainer > volVarScalarData;
747 std::vector< VectorDataContainer > volVarVectorData;
748
750 if (!volVarScalarDataInfo_.empty()
751 || !volVarVectorDataInfo_.empty()
752 || !this->fields().empty()
753 || velocityOutput_->enableOutput()
754 || addProcessRank_)
755 {
756 const auto numCells = gridGeometry().gridView().size(0);
757 const auto outputSize = numDofs_();
758
759 // get fields for all volume variables
760 if (!volVarScalarDataInfo_.empty())
761 volVarScalarData.resize(volVarScalarDataInfo_.size(), ScalarDataContainer(numCells));
762 if (!volVarVectorDataInfo_.empty())
763 volVarVectorData.resize(volVarVectorDataInfo_.size(), VectorDataContainer(numCells));
764
765 if (velocityOutput_->enableOutput())
766 {
767 for (int phaseIdx = 0; phaseIdx < velocityOutput_->numFluidPhases(); ++phaseIdx)
768 {
769 if((isBox && dim == 1) || isDiamond)
770 velocity[phaseIdx].resize(numCells);
771 else
772 velocity[phaseIdx].resize(outputSize);
773 }
774 }
775
776 // maybe allocate space for the process rank
777 if (addProcessRank_) rank.resize(numCells);
778
779 // now we go element-local to extract values at local dof locations
780 auto fvGeometry = localView(gridGeometry());
781 auto elemVolVars = localView(curGridVariables_());
782 for (const auto& element : elements(gridGeometry().gridView()))
783 {
784 if (!velocityOutput_->enableOutput() &&
785 element.partitionType() != Dune::PartitionType::InteriorEntity)
786 {
787 continue;
788 }
789 const auto eIdxGlobal = gridGeometry().elementMapper().index(element);
790 // If velocity output is enabled we need to bind to the whole stencil
791 // otherwise element-local data is sufficient
792 if (velocityOutput_->enableOutput())
793 {
794 fvGeometry.bind(element);
795 elemVolVars.bind(element, fvGeometry, sol_);
796 }
797 else
798 {
799 fvGeometry.bindElement(element);
800 elemVolVars.bindElement(element, fvGeometry, sol_);
801 }
802
803 const auto numLocalDofs = Dumux::Detail::LocalDofs::numLocalDofs(fvGeometry);
804 // resize element-local data containers
805 for (std::size_t i = 0; i < volVarScalarDataInfo_.size(); ++i)
806 volVarScalarData[i][eIdxGlobal].resize(numLocalDofs);
807 for (std::size_t i = 0; i < volVarVectorDataInfo_.size(); ++i)
808 volVarVectorData[i][eIdxGlobal].resize(numLocalDofs);
809
810 // velocity output
811 if (velocityOutput_->enableOutput())
812 {
813 if constexpr (Concept::FVGridVariables<GridVariables>)
814 {
815 const auto elemFluxVarsCache = localView(gridVariables_.gridFluxVarsCache()).bind(element, fvGeometry, elemVolVars);
816 for (int phaseIdx = 0; phaseIdx < velocityOutput_->numFluidPhases(); ++phaseIdx)
817 velocityOutput_->calculateVelocity(velocity[phaseIdx], element, fvGeometry, elemVolVars, elemFluxVarsCache, phaseIdx);
818 }
819 else
820 {
821 for (int phaseIdx = 0; phaseIdx < velocityOutput_->numFluidPhases(); ++phaseIdx)
822 velocityOutput_->calculateVelocity(velocity[phaseIdx], element, fvGeometry, elemVolVars, phaseIdx);
823 }
824 }
825 else if (element.partitionType() != Dune::PartitionType::InteriorEntity)
826 {
827 continue;
828 }
829
830 if (!volVarScalarDataInfo_.empty() || !volVarVectorDataInfo_.empty())
831 {
832 using ElementDisc = typename GridGeometry::LocalView;
834 {
835 for (const auto& scv : scvs(fvGeometry))
836 {
837 const auto& volVars = elemVolVars[scv];
838
839 // get the scalar-valued data
840 for (std::size_t i = 0; i < volVarScalarDataInfo_.size(); ++i)
841 volVarScalarData[i][eIdxGlobal][scv.localDofIndex()] = volVarScalarDataInfo_[i].get(volVars);
842
843 // get the vector-valued data
844 for (std::size_t i = 0; i < volVarVectorDataInfo_.size(); ++i)
845 volVarVectorData[i][eIdxGlobal][scv.localDofIndex()] = volVarVectorDataInfo_[i].get(volVars);
846 }
847 }
850 {
851 for (const auto& localDof : nonCVLocalDofs(fvGeometry))
852 {
853 const auto& volVars = elemVolVars[localDof];
854
855 // get the scalar-valued data
856 for (std::size_t i = 0; i < volVarScalarDataInfo_.size(); ++i)
857 volVarScalarData[i][eIdxGlobal][localDof.index()] = volVarScalarDataInfo_[i].get(volVars);
858
859 // get the vector-valued data
860 for (std::size_t i = 0; i < volVarVectorDataInfo_.size(); ++i)
861 volVarVectorData[i][eIdxGlobal][localDof.index()] = volVarVectorDataInfo_[i].get(volVars);
862 }
863 }
864 }
865
867 if (addProcessRank_)
868 rank[eIdxGlobal] = static_cast<double>(gridGeometry().gridView().comm().rank());
869 }
870
874
875 // volume variables if any
876 static constexpr int dofLocCodim = isDiamond ? 1 : dim;
877 for (std::size_t i = 0; i < volVarScalarDataInfo_.size(); ++i)
878 this->addVertexData(Field(
879 gridGeometry().gridView(), gridGeometry().elementMapper(),
880 volVarScalarData[i], volVarScalarDataInfo_[i].name,
881 /*numComp*/1, /*codim*/dofLocCodim, /*nonconforming*/dm, this->precision()
882 ));
883
884 for (std::size_t i = 0; i < volVarVectorDataInfo_.size(); ++i)
885 this->addVertexData(Field(
886 gridGeometry().gridView(), gridGeometry().elementMapper(),
887 volVarVectorData[i], volVarVectorDataInfo_[i].name,
888 /*numComp*/dimWorld, /*codim*/dofLocCodim, /*nonconforming*/dm, this->precision()
889 ));
890
891 // the velocity field
892 if (velocityOutput_->enableOutput())
893 {
894 // node-wise velocities
895 if (dim > 1 && !isDiamond)
896 for (int phaseIdx = 0; phaseIdx < velocityOutput_->numFluidPhases(); ++phaseIdx)
897 this->addVertexData(Field(
898 gridGeometry().gridView(), gridGeometry().vertexMapper(), velocity[phaseIdx],
899 "velocity_" + velocityOutput_->phaseName(phaseIdx) + " (m/s)",
900 /*numComp*/dimWorld, /*codim*/dofLocCodim, dm, this->precision()
901 ));
902
903 // cell-wise velocities
904 else
905 for (int phaseIdx = 0; phaseIdx < velocityOutput_->numFluidPhases(); ++phaseIdx)
906 this->addCellData(Field(
907 gridGeometry().gridView(), gridGeometry().elementMapper(), velocity[phaseIdx],
908 "velocity_" + velocityOutput_->phaseName(phaseIdx) + " (m/s)",
909 /*numComp*/dimWorld, /*codim*/0, dm, this->precision()
910 ));
911 }
912 }
913
914 // the process rank
915 if (addProcessRank_)
916 this->addCellData(Field(
917 gridGeometry().gridView(), gridGeometry().elementMapper(),
918 rank, "process rank", /*numComp*/1, /*codim*/0
919 ));
920
921 // also register additional (non-standardized) user fields if any
922 for (const auto& field : this->fields())
923 {
924 if (field.codim() == 0)
925 this->addCellData(field);
926 else if (field.codim() == dim || field.codim() == 1)
927 this->addVertexData(field);
928 else
929 DUNE_THROW(Dune::RangeError, "Cannot add wrongly sized vtk scalar field!");
930 }
931
935 this->sequenceWriter().write(time, type);
936
940 this->writer().clear();
941
942 this->addedCellData_.clear();
943 this->addedVertexData_.clear();
944 }
945
947 std::size_t numDofs_() const
948 {
949 // TODO this should actually always be dofMapper.size()
950 // maybe some discretizations needs special treatment (?)
951 if constexpr (isBox || isDiamond || isPQ1Bubble || isPQ2)
952 return gridGeometry().dofMapper().size();
953 else
954 return gridGeometry().elementMapper().size();
955 }
956
957 const GridVariables& gridVariables_;
958 const SolutionVector& sol_;
959
960 std::vector<VolVarScalarDataInfo> volVarScalarDataInfo_;
961 std::vector<VolVarVectorDataInfo> volVarVectorDataInfo_;
962
963 std::shared_ptr<VelocityOutput> velocityOutput_;
964 bool enableVelocityOutput_ = false;
965 bool addProcessRank_ = true;
966};
967
968} // end namespace Dumux
969
970#endif
@ vertex
Definition io/velocityoutput.hh:48
@ automatic
Definition io/velocityoutput.hh:48
@ element
Definition io/velocityoutput.hh:48
std::vector< Dune::FieldVector< Scalar, dimWorld > > VelocityVector
Definition io/velocityoutput.hh:41
Velocity output for implicit (porous media) models.
Definition io/velocityoutput.hh:27
Dumux::Vtk::Precision precision() const
Definition io/vtkoutputmodule.hh:211
const std::string & paramGroup() const
Definition io/vtkoutputmodule.hh:84
void addCellData(const Field &field)
Definition io/vtkoutputmodule.hh:218
void write(double time, Dune::VTK::OutputType type=Dune::VTK::ascii)
Definition io/vtkoutputmodule.hh:187
VtkOutputModuleBase(const GridGeometry &gridGeometry, const std::string &name, const std::string &paramGroup="", Dune::VTK::DataMode dm=Dune::VTK::conforming, bool verbose=true)
Definition io/vtkoutputmodule.hh:62
Dune::VTK::DataMode dataMode() const
Definition io/vtkoutputmodule.hh:210
Dune::VTKWriter< GridView > & writer()
Definition io/vtkoutputmodule.hh:213
Dune::VTKSequenceWriter< GridView > & sequenceWriter()
Definition io/vtkoutputmodule.hh:214
const std::string & name() const
Definition io/vtkoutputmodule.hh:209
const std::vector< Field > & fields() const
Definition io/vtkoutputmodule.hh:216
virtual ~VtkOutputModuleBase()=default
virtual void writeNonConforming_(double time, Dune::VTK::OutputType type)
Assembles the fields and adds them to the writer (nonconforming output).
Definition io/vtkoutputmodule.hh:304
std::vector< std::string > addedCellData_
Definition io/vtkoutputmodule.hh:238
void addField(const Vector &v, const std::string &name, Dumux::Vtk::Precision precision, Vtk::FieldType fieldType=Vtk::FieldType::automatic)
Add a scalar or vector valued vtk field.
Definition io/vtkoutputmodule.hh:113
bool verbose() const
Definition io/vtkoutputmodule.hh:208
Vtk::template Field< GridView > Field
the type of Field that can be added to this writer
Definition io/vtkoutputmodule.hh:60
std::vector< std::string > addedVertexData_
Definition io/vtkoutputmodule.hh:239
virtual void writeConforming_(double time, Dune::VTK::OutputType type)
Assembles the fields and adds them to the writer (conforming output).
Definition io/vtkoutputmodule.hh:243
void addField(const Vector &v, const std::string &name, Vtk::FieldType fieldType=Vtk::FieldType::automatic)
Add a scalar or vector valued vtk field.
Definition io/vtkoutputmodule.hh:97
void addVertexData(const Field &field)
Definition io/vtkoutputmodule.hh:227
const Dumux::GridDiscretization_t< GridVariables > & gridGeometry() const
Definition io/vtkoutputmodule.hh:206
void addField(Field &&field)
Add a scalar or vector valued vtk field.
Definition io/vtkoutputmodule.hh:160
const auto & problem() const
Definition io/vtkoutputmodule.hh:466
const GridVariables & gridVariables() const
Definition io/vtkoutputmodule.hh:467
void addVolumeVariable(std::function< VolVarsVector(const VolumeVariables &)> &&f, const std::string &name)
Definition io/vtkoutputmodule.hh:441
VV VolumeVariables
export type of the volume variables for the outputfields
Definition io/vtkoutputmodule.hh:379
void addVolumeVariable(std::function< Scalar(const VolumeVariables &)> &&f, const std::string &name)
Definition io/vtkoutputmodule.hh:413
void addVelocityOutput(std::shared_ptr< VelocityOutputType > velocityOutput)
Add a velocity output policy.
Definition io/vtkoutputmodule.hh:407
const auto & curGridVariables_() const
Definition io/vtkoutputmodule.hh:477
const VelocityOutput & velocityOutput() const
Definition io/vtkoutputmodule.hh:475
VelocityOutputType VelocityOutput
Definition io/vtkoutputmodule.hh:474
Vtk::template Field< GridView > Field
the type of Field that can be added to this writer
Definition io/vtkoutputmodule.hh:377
void writeNonConforming_(double time, Dune::VTK::OutputType type) override
Assembles the fields and adds them to the writer (nonconforming output).
Definition io/vtkoutputmodule.hh:717
const SolutionVector & sol() const
Definition io/vtkoutputmodule.hh:469
const GridGeometry & gridGeometry() const
Definition io/vtkoutputmodule.hh:468
void writeConforming_(double time, Dune::VTK::OutputType type) override
Assembles the fields and adds them to the writer (conforming output).
Definition io/vtkoutputmodule.hh:488
VtkOutputModule(const GridVariables &gridVariables, const SolutionVector &sol, const std::string &name, const std::string &paramGroup="", Dune::VTK::DataMode dm=Dune::VTK::conforming, bool verbose=true)
Definition io/vtkoutputmodule.hh:381
const std::vector< VolVarScalarDataInfo > & volVarScalarDataInfo() const
Definition io/vtkoutputmodule.hh:471
const std::vector< VolVarVectorDataInfo > & volVarVectorDataInfo() const
Definition io/vtkoutputmodule.hh:472
Concept for pure finite-element discretizations (no FV structure).
Definition concepts.hh:50
Concept for finite-volume discretizations.
Definition concepts.hh:26
Concept for hybrid finite-element/finite-volume discretizations.
Definition concepts.hh:39
Concepts for discretization types.
Vtk field types available in Dumux.
Formatting based on the fmt-library which implements std::format of C++20.
Dune style VTK functions.
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
Precision stringToPrecision(std::string_view precisionName)
Maps a string (e.g. from input) to a Dune precision type.
Definition precision.hh:27
FieldType
Identifier for vtk field types.
Definition fieldtype.hh:22
@ vertex
Definition fieldtype.hh:23
@ automatic
Definition fieldtype.hh:23
@ element
Definition fieldtype.hh:23
T getParamFromGroup(Args &&... args)
A free function to get a parameter from the parameter tree singleton with a model group.
Definition parameters.hh:149
decltype(auto) gridDiscretization(const T &t, Args &&... args)
The grid discretization.
Definition griddiscretization.hh:65
typename Detail::GridDiscretizationType< T >::type GridDiscretization_t
The grid discretization type of a class exporting it.
Definition griddiscretization.hh:54
Default velocity output policy for porous media models.
Class representing dofs on elements for control-volume finite element schemes.
The available discretization methods in Dumux.
constexpr FCDiamond fcdiamond
Definition method.hh:184
constexpr PQ2 pq2
Definition method.hh:178
constexpr Box box
Definition method.hh:176
constexpr PQ1Bubble pq1bubble
Definition method.hh:180
Definition adapt.hh:17
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.