My Project
Loading...
Searching...
No Matches
FlowProblemComp.hpp
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 Copyright 2024 SINTEF Digital
5
6 This file is part of the Open Porous Media project (OPM).
7
8 OPM is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
12
13 OPM 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 License
19 along with OPM. If not, see <http://www.gnu.org/licenses/>.
20
21 Consult the COPYING file in the top-level source directory of this
22 module for the precise wording of the license and the list of
23 copyright holders.
24*/
30#ifndef OPM_FLOW_PROBLEM_COMP_HPP
31#define OPM_FLOW_PROBLEM_COMP_HPP
32
33
37
38#include <opm/material/fluidstates/CompositionalFluidState.hpp>
39
40#include <opm/material/thermal/EclThermalLawManager.hpp>
41
42#include <opm/input/eclipse/EclipseState/Compositional/CompositionalConfig.hpp>
43
44#include <algorithm>
45#include <functional>
46#include <set>
47#include <string>
48#include <vector>
49
50namespace Opm {
51
58template <class TypeTag>
59class FlowProblemComp : public FlowProblem<TypeTag>
60{
61 // TODO: the naming of the Types will be adjusted
63
64 using typename FlowProblemType::Scalar;
65 using typename FlowProblemType::Simulator;
66 using typename FlowProblemType::GridView;
67 using typename FlowProblemType::FluidSystem;
68 using typename FlowProblemType::Vanguard;
69
70 // might not be needed
71 using FlowProblemType::dim;
72 using FlowProblemType::dimWorld;
73
74 using FlowProblemType::numPhases;
75 using FlowProblemType::numComponents;
76
77 using FlowProblemType::gasPhaseIdx;
78 using FlowProblemType::oilPhaseIdx;
79 using FlowProblemType::waterPhaseIdx;
80
81 using typename FlowProblemType::Indices;
82 using typename FlowProblemType::PrimaryVariables;
84 using typename FlowProblemType::Evaluation;
85 using typename FlowProblemType::MaterialLaw;
86 using typename FlowProblemType::RateVector;
87
88 using InitialFluidState = CompositionalFluidState<Scalar, FluidSystem>;
90
91public:
94
98 static void registerParameters()
99 {
101
102 EclWriterType::registerParameters();
103
104 // tighter tolerance is needed for compositional modeling here
105 Parameters::SetDefault<Parameters::NewtonTolerance<Scalar>>(1e-7);
106 }
107
108 Opm::CompositionalConfig::EOSType getEosType() const
109 {
110 auto& simulator = this->simulator();
111 const auto& eclState = simulator.vanguard().eclState();
112 return eclState.compositionalConfig().eosType(0);
113 }
114
118 explicit FlowProblemComp(Simulator& simulator)
119 : FlowProblemType(simulator)
120 , thresholdPressures_(simulator)
121 {
122 eclWriter_ = std::make_unique<EclWriterType>(simulator);
123 enableEclOutput_ = Parameters::Get<Parameters::EnableEclOutput>();
124 }
125
130 {
131 // TODO: there should be room to remove duplication for this function,
132 // but there is relatively complicated logic in the function calls in this function
133 // some refactoring is needed for this function
134 FlowProblemType::finishInit();
135
136 auto& simulator = this->simulator();
137
138 auto finishTransmissibilities = [updated = false, this]() mutable {
139 if (updated) {
140 return;
141 }
142 this->transmissibilities_.finishInit(
143 [&vg = this->simulator().vanguard()](const unsigned int it) { return vg.gridIdxToEquilGridIdx(it); });
144 updated = true;
145 };
146 // TODO: we might need to do the same with FlowProblemBlackoil for parallel
147
149
150 if (enableEclOutput_) {
151 eclWriter_->setTransmissibilities(&simulator.problem().eclTransmissibilities());
152 std::function<unsigned int(unsigned int)> equilGridToGrid = [&simulator](unsigned int i) {
153 return simulator.vanguard().gridEquilIdxToGridIdx(i);
154 };
155 eclWriter_->extractOutputTransAndNNC(equilGridToGrid);
156 }
157
158 const auto& eclState = simulator.vanguard().eclState();
159 const auto& schedule = simulator.vanguard().schedule();
160
161 // Set the start time of the simulation
162 simulator.setStartTime(schedule.getStartTime());
163 simulator.setEndTime(schedule.simTime(schedule.size() - 1));
164
165 // We want the episode index to be the same as the report step index to make
166 // things simpler, so we have to set the episode index to -1 because it is
167 // incremented by endEpisode(). The size of the initial time step and
168 // length of the initial episode is set to zero for the same reason.
169 simulator.setEpisodeIndex(-1);
170 simulator.setEpisodeLength(0.0);
171
172 // the "NOGRAV" keyword from Frontsim or setting the EnableGravity to false
173 // disables gravity, else the standard value of the gravity constant at sea level
174 // on earth is used
175 this->gravity_ = 0.0;
176 if (Parameters::Get<Parameters::EnableGravity>())
177 this->gravity_[dim - 1] = 9.80665;
178 if (!eclState.getInitConfig().hasGravity())
179 this->gravity_[dim - 1] = 0.0;
180
181 if (this->enableTuning_) {
182 // if support for the TUNING keyword is enabled, we get the initial time
183 // steping parameters from it instead of from command line parameters
184 const auto& tuning = schedule[0].tuning();
185 this->initialTimeStepSize_ = tuning.TSINIT.has_value() ? tuning.TSINIT.value() : -1.0;
186 this->maxTimeStepAfterWellEvent_ = tuning.TMAXWC;
187 }
188
189 this->initFluidSystem_();
190
191 if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)
192 && FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
193 this->maxOilSaturation_.resize(this->model().numGridDof(), 0.0);
194 }
195
196 this->readRockParameters_(simulator.vanguard().cellCenterDepths(), [&simulator](const unsigned idx) {
197 std::array<int, dim> coords;
198 simulator.vanguard().cartesianCoordinate(idx, coords);
199 for (auto& c : coords) {
200 ++c;
201 }
202 return coords;
203 });
204 FlowProblemType::readMaterialParameters_();
205 FlowProblemType::readThermalParameters_();
206
207 // write the static output files (EGRID, INIT)
208 if (enableEclOutput_) {
209 eclWriter_->writeInit();
210 }
211
212 const auto& initconfig = eclState.getInitConfig();
213 if (initconfig.restartRequested())
214 readEclRestartSolution_();
215 else
216 this->readInitialCondition_();
217
218 FlowProblemType::updatePffDofData_();
219
221 const auto& vanguard = this->simulator().vanguard();
222 const auto& gridView = vanguard.gridView();
223 int numElements = gridView.size(/*codim=*/0);
224 this->polymer_.maxAdsorption.resize(numElements, 0.0);
225 }
226
227 /* readBoundaryConditions_();
228
229 // compute and set eq weights based on initial b values
230 computeAndSetEqWeights_();
231
232 if (enableDriftCompensation_) {
233 drift_.resize(this->model().numGridDof());
234 drift_ = 0.0;
235 } */
236
237 // TODO: check wether the following can work with compostional
238 if (this->enableVtkOutput_() && eclState.getIOConfig().initOnly()) {
239 simulator.setTimeStepSize(0.0);
241 }
242
243 // after finishing the initialization and writing the initial solution, we move
244 // to the first "real" episode/report step
245 // for restart the episode index and start is already set
246 if (!initconfig.restartRequested()) {
247 simulator.startNextEpisode(schedule.seconds(1));
248 simulator.setEpisodeIndex(0);
249 simulator.setTimeStepIndex(0);
250 }
251 }
252
256 void endTimeStep() override
257 {
258 FlowProblemType::endTimeStep();
259
260 const bool isSubStep = !this->simulator().episodeWillBeOver();
261
262 // after the solution is updated, the values in output module also needs to be updated
263 this->eclWriter_->mutableOutputModule().invalidateLocalData();
264
265 // For CpGrid with LGRs, ecl/vtk output is not supported yet.
266 const auto& grid = this->simulator().vanguard().gridView().grid();
267
268 using GridType = std::remove_cv_t<std::remove_reference_t<decltype(grid)>>;
269 constexpr bool isCpGrid = std::is_same_v<GridType, Dune::CpGrid>;
270 if (!isCpGrid || (grid.maxLevel() == 0)) {
271 this->eclWriter_->evalSummaryState(isSubStep);
272 }
273
274 }
275
276 void writeReports(const SimulatorTimer& timer) {
277 if (enableEclOutput_){
278 eclWriter_->writeReports(timer);
279 }
280 }
281
286 void writeOutput(bool verbose) override
287 {
288 FlowProblemType::writeOutput(verbose);
289
290 const bool isSubStep = !this->simulator().episodeWillBeOver();
291
292 data::Solution localCellData = {};
293 if (enableEclOutput_) {
294 if (Parameters::Get<Parameters::EnableWriteAllSolutions>() || !isSubStep) {
295 eclWriter_->writeOutput(std::move(localCellData), isSubStep);
296 }
297 }
298 }
299
305 template <class Context>
306 void boundary(BoundaryRateVector& values,
307 const Context& context,
308 unsigned spaceIdx,
309 unsigned /* timeIdx */) const
310 {
312 if (!context.intersection(spaceIdx).boundary())
313 return;
314
315 values.setNoFlow();
316
317 if (this->nonTrivialBoundaryConditions()) {
318 throw std::logic_error("boundary condition is not supported by compostional modeling yet");
319 }
320 }
321
328 template <class Context>
329 void initial(PrimaryVariables& values, const Context& context, unsigned spaceIdx, unsigned timeIdx) const
330 {
331 const unsigned globalDofIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
332 const auto& initial_fs = initialFluidStates_[globalDofIdx];
334 for (unsigned p = 0; p < numPhases; ++p) { // TODO: assuming the phaseidx continuous
335 // pressure
336 fs.setPressure(p, initial_fs.pressure(p));
337
338 // saturation
339 fs.setSaturation(p, initial_fs.saturation(p));
340
341 // temperature
342 fs.setTemperature(initial_fs.temperature(p));
343 }
344
345
346 if (!zmf_initialization_) {
347 for (unsigned p = 0; p < numPhases; ++p) {
348 for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
349 fs.setMoleFraction(p, compIdx, initial_fs.moleFraction(p, compIdx));
350 }
351 }
352
353 {
354 const auto& eos_type = getEosType();
355 typename FluidSystem::template ParameterCache<Scalar> paramCache(eos_type);
356 paramCache.updatePhase(fs, FluidSystem::oilPhaseIdx);
357 paramCache.updatePhase(fs, FluidSystem::gasPhaseIdx);
358 fs.setDensity(FluidSystem::oilPhaseIdx, FluidSystem::density(fs, paramCache, FluidSystem::oilPhaseIdx));
359 fs.setDensity(FluidSystem::gasPhaseIdx, FluidSystem::density(fs, paramCache, FluidSystem::gasPhaseIdx));
360 }
361 // determine the component fractions
362 Dune::FieldVector<Scalar, numComponents> z(0.0);
363 Scalar sumMoles = 0.0;
364 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
365 if (Indices::waterEnabled && phaseIdx == static_cast<unsigned int>(waterPhaseIdx)){
366 continue;
367 }
368 const auto saturation = fs.saturation(phaseIdx);
369 for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
370 Scalar tmp = fs.molarity(phaseIdx, compIdx) * saturation;
371 tmp = max(tmp, 1e-8);
372 z[compIdx] += tmp;
373 sumMoles += tmp;
374 }
375 }
376 z /= sumMoles;
377 for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
378 fs.setMoleFraction(compIdx, z[compIdx]);
379 }
380 } else {
381 // TODO: should we normalize the input?
382 for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
383 fs.setMoleFraction(compIdx, initial_fs.moleFraction(compIdx));
384 }
385 }
386
387 // Set initial K and L
388 for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
389 const auto& Ktmp = fs.wilsonK_(compIdx);
390 fs.setKvalue(compIdx, Ktmp);
391 }
392
393 const Scalar& Ltmp = -1.0;
394 fs.setLvalue(Ltmp);
395
396 values.assignNaive(fs);
397 }
398
399 void addToSourceDense(RateVector&, unsigned, unsigned) const override
400 {
401 // we do nothing for now
402 }
403
404 const InitialFluidState& initialFluidState(unsigned globalDofIdx) const
405 { return initialFluidStates_[globalDofIdx]; }
406
407 std::vector<InitialFluidState>& initialFluidStates()
408 { return initialFluidStates_; }
409
410 const std::vector<InitialFluidState>& initialFluidStates() const
411 { return initialFluidStates_; }
412
413 const FlowThresholdPressure<TypeTag>& thresholdPressure() const
414 {
415 assert( !thresholdPressures_.enableThresholdPressure() &&
416 " Threshold Pressures are not supported by compostional simulation ");
417 return thresholdPressures_;
418 }
419
420 const EclWriterType& eclWriter() const
421 { return *eclWriter_; }
422
423 EclWriterType& eclWriter()
424 { return *eclWriter_; }
425
426 // TODO: do we need this one?
427 template<class Serializer>
428 void serializeOp(Serializer& serializer)
429 {
430 serializer(static_cast<FlowProblemType&>(*this));
431 serializer(*eclWriter_);
432 }
433protected:
434
435 void updateExplicitQuantities_(int /* episodeIdx*/, int /* timeStepSize */, bool /* first_step_after_restart */) override
436 {
437 // we do nothing here for now
438 }
439
440 void readEquilInitialCondition_() override
441 {
442 throw std::logic_error("Equilibration is not supported by compositional modeling yet");
443 }
444
445 void readEclRestartSolution_()
446 {
447 throw std::logic_error("Restarting is not supported by compositional modeling yet");
448 }
449
450 void readExplicitInitialCondition_() override
451 {
452 readExplicitInitialConditionCompositional_();
453 }
454
455 void readExplicitInitialConditionCompositional_()
456 {
457 const auto& simulator = this->simulator();
458 const auto& vanguard = simulator.vanguard();
459 const auto& eclState = vanguard.eclState();
460 const auto& fp = eclState.fieldProps();
461 const bool has_pressure = fp.has_double("PRESSURE");
462 if (!has_pressure)
463 throw std::runtime_error("The ECL input file requires the presence of the PRESSURE "
464 "keyword if the model is initialized explicitly");
465
466 const bool has_xmf = fp.has_double("XMF");
467 const bool has_ymf = fp.has_double("YMF");
468 const bool has_zmf = fp.has_double("ZMF");
469 if ( !has_zmf && !(has_xmf && has_ymf) ) {
470 throw std::runtime_error("The ECL input file requires the presence of ZMF or XMF and YMF "
471 "keyword if the model is initialized explicitly");
472 }
473
474 if (has_zmf && (has_xmf || has_ymf)) {
475 throw std::runtime_error("The ECL input file can not handle explicit initialization "
476 "with both ZMF and XMF or YMF");
477 }
478
479 if (has_xmf != has_ymf) {
480 throw std::runtime_error("The ECL input file needs XMF and YMF combined to do the explicit "
481 "initializtion when using XMF or YMF");
482 }
483
484 const bool has_temp = fp.has_double("TEMPI");
485
486 // const bool has_gas = fp.has_double("SGAS");
487 assert(fp.has_double("SGAS"));
488
489 std::size_t numDof = this->model().numGridDof();
490
491 initialFluidStates_.resize(numDof);
492
493 std::vector<double> waterSaturationData;
494 std::vector<double> gasSaturationData;
495 std::vector<double> soilData;
496 std::vector<double> pressureData;
497 std::vector<double> tempiData;
498
499 const bool water_active = FluidSystem::phaseIsActive(waterPhaseIdx);
500 const bool gas_active = FluidSystem::phaseIsActive(gasPhaseIdx);
501 const bool oil_active = FluidSystem::phaseIsActive(oilPhaseIdx);
502
503 if (water_active && Indices::numPhases > 2)
504 waterSaturationData = fp.get_double("SWAT");
505 else
506 waterSaturationData.resize(numDof);
507
508 pressureData = fp.get_double("PRESSURE");
509
510 if (has_temp) {
511 tempiData = fp.get_double("TEMPI");
512 } else {
513 ; // TODO: throw?
514 }
515
516 if (gas_active) // && FluidSystem::phaseIsActive(oilPhaseIdx))
517 gasSaturationData = fp.get_double("SGAS");
518 else
519 gasSaturationData.resize(numDof);
520
521 for (std::size_t dofIdx = 0; dofIdx < numDof; ++dofIdx) {
522 auto& dofFluidState = initialFluidStates_[dofIdx];
523 // dofFluidState.setPvtRegionIndex(pvtRegionIndex(dofIdx));
524
525 Scalar temperatureLoc = tempiData[dofIdx];
526 assert(std::isfinite(temperatureLoc) && temperatureLoc > 0);
527 dofFluidState.setTemperature(temperatureLoc);
528
529 if (gas_active) {
530 dofFluidState.setSaturation(FluidSystem::gasPhaseIdx,
531 gasSaturationData[dofIdx]);
532 }
533 if (oil_active) {
534 dofFluidState.setSaturation(FluidSystem::oilPhaseIdx,
535 1.0
536 - waterSaturationData[dofIdx]
537 - gasSaturationData[dofIdx]);
538 }
539 if (water_active) {
540 dofFluidState.setSaturation(FluidSystem::waterPhaseIdx,
541 waterSaturationData[dofIdx]);
542 }
543
545 // set phase pressures
547 const Scalar pressure = pressureData[dofIdx]; // oil pressure (or gas pressure for water-gas system or water pressure for single phase)
548
549 // TODO: zero capillary pressure for now
550 const std::array<Scalar, numPhases> pc = {0};
551 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
552 if (!FluidSystem::phaseIsActive(phaseIdx))
553 continue;
554
555 if (Indices::oilEnabled)
556 dofFluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[oilPhaseIdx]));
557 else if (Indices::gasEnabled)
558 dofFluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[gasPhaseIdx]));
559 else if (Indices::waterEnabled)
560 // single (water) phase
561 dofFluidState.setPressure(phaseIdx, pressure);
562 }
563
564 if (has_xmf && has_ymf) {
565 const auto& xmfData = fp.get_double("XMF");
566 const auto& ymfData = fp.get_double("YMF");
567 for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
568 const std::size_t data_idx = compIdx * numDof + dofIdx;
569 const Scalar xmf = xmfData[data_idx];
570 const Scalar ymf = ymfData[data_idx];
571
572 dofFluidState.setMoleFraction(FluidSystem::oilPhaseIdx, compIdx, xmf);
573 dofFluidState.setMoleFraction(FluidSystem::gasPhaseIdx, compIdx, ymf);
574 }
575 }
576
577 if (has_zmf) {
578 zmf_initialization_ = true;
579 const auto& zmfData = fp.get_double("ZMF");
580 for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
581 const std::size_t data_idx = compIdx * numDof + dofIdx;
582 const Scalar zmf = zmfData[data_idx];
583 dofFluidState.setMoleFraction(compIdx, zmf);
584
585 if (gas_active) {
586 const auto ymf = (dofFluidState.saturation(FluidSystem::gasPhaseIdx) > 0.) ? zmf : Scalar{0};
587 dofFluidState.setMoleFraction(FluidSystem::gasPhaseIdx, compIdx, ymf);
588 }
589 if (oil_active) {
590 const auto xmf = (dofFluidState.saturation(FluidSystem::oilPhaseIdx) > 0.) ? zmf : Scalar{0};
591 dofFluidState.setMoleFraction(FluidSystem::oilPhaseIdx, compIdx, xmf);
592 }
593 }
594 }
595 }
596 }
597
598private:
599
600 void handleSolventBC(const BCProp::BCFace& /* bc */, RateVector& /* rate */) const override
601 {
602 throw std::logic_error("solvent is disabled for compositional modeling and you're trying to add solvent to BC");
603 }
604
605 void handlePolymerBC(const BCProp::BCFace& /* bc */, RateVector& /* rate */) const override
606 {
607 throw std::logic_error("polymer is disabled for compositional modeling and you're trying to add polymer to BC");
608 }
609
610 void handleMicrBC(const BCProp::BCFace& /* bc */, RateVector& /* rate */) const override
611 {
612 throw std::logic_error("MICP is disabled for compositional modeling and you're trying to add microbes to BC");
613 }
614
615 void handleOxygBC(const BCProp::BCFace& /* bc */, RateVector& /* rate */) const override
616 {
617 throw std::logic_error("MICP is disabled for compositional modeling and you're trying to add oxygen to BC");
618 }
619
620 void handleUreaBC(const BCProp::BCFace& /* bc */, RateVector& /* rate */) const override
621 {
622 throw std::logic_error("MICP is disabled for compositional modeling and you're trying to add urea to BC");
623 }
624
625 FlowThresholdPressure<TypeTag> thresholdPressures_;
626
627 std::vector<InitialFluidState> initialFluidStates_;
628
629 bool zmf_initialization_ {false};
630
631 bool enableEclOutput_{false};
632 std::unique_ptr<EclWriterType> eclWriter_;
633};
634
635} // namespace Opm
636
637#endif // OPM_FLOW_PROBLEM_COMP_HPP
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
This class calculates the threshold pressure for grid faces according to the Eclipse Reference Manual...
Output module for the results black oil model writing in ECL binary format.
Collects necessary output values and pass it to opm-common's ECL output.
Definition EclWriter.hpp:114
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
Definition FlowProblemComp.hpp:60
void writeOutput(bool verbose) override
Write the requested quantities of the current solution into the output files.
Definition FlowProblemComp.hpp:286
void finishInit()
Called by the Opm::Simulator in order to initialize the problem.
Definition FlowProblemComp.hpp:129
FlowProblemComp(Simulator &simulator)
Definition FlowProblemComp.hpp:118
void endTimeStep() override
Called by the simulator after each time integration.
Definition FlowProblemComp.hpp:256
void boundary(BoundaryRateVector &values, const Context &context, unsigned spaceIdx, unsigned) const
Evaluate the boundary conditions for a boundary segment.
Definition FlowProblemComp.hpp:306
void initial(PrimaryVariables &values, const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Evaluate the initial value for a control volume.
Definition FlowProblemComp.hpp:329
static void registerParameters()
Registers all available parameters for the problem and the model.
Definition FlowProblemComp.hpp:98
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
Definition FlowProblem.hpp:94
virtual void writeOutput(bool verbose)
Write the requested quantities of the current solution into the output files.
Definition FlowProblem.hpp:473
unsigned pvtRegionIndex(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the index of the relevant region for thermodynmic properties.
Definition FlowProblem.hpp:818
Scalar porosity(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition FlowProblem.hpp:652
static void registerParameters()
Registers all available parameters for the problem and the model.
Definition FlowProblem.hpp:180
Definition SimulatorTimer.hpp:39
This file contains a set of helper functions used by VFPProd / VFPInj.
Definition blackoilboundaryratevector.hh:37
constexpr auto getPropValue()
get the value data member of a property
Definition propertysystem.hh:242
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(....
Definition propertysystem.hh:235