Commit 19288ec4 authored by Santiago Ospina's avatar Santiago Ospina

clean up transport implementation

Signed-off-by: Santiago Ospina De Los Ríos's avatarSantiago Ospina <santiago.ospina@iup.uni-heidelberg.de>
parent e4145e9e
......@@ -174,8 +174,8 @@ adding an empty line, make text **bold** or ``monospaced``.
</category>
<category name="transport.parameters">
<parameter name="molecularDifussion">
<definition> Molecular difussion of the fluid phase </definition>
<parameter name="molecularDiffusion">
<definition> Molecular diffusion of the fluid phase </definition>
<values> float &gt; 0 </values>
<comment> 2E-9 </comment>
</parameter>
......
......@@ -79,16 +79,16 @@ TransportSimulation<Traits>::TransportSimulation(
template<typename Traits>
void TransportSimulation<Traits>::operator_setup ()
{
if (!_gfWaterFlux)
if (!gf_water_flux)
DUNE_THROW(Dune::Exception," ");
if (!_gfSaturation)
if (!gf_saturation)
DUNE_THROW(Dune::Exception," ");
// --- Local Operators ---
double D_eff = inifile.get<double>("parameters.molecularDifussion");
slop = std::make_unique<SLOP>(*sboundary,_gfWaterFlux,_gfSaturation,D_eff /*inifile,*param,gv,*fboundary,*fsource*/);
double diff_coeff = inifile.get<double>("parameters.molecularDiffusion");
slop = std::make_unique<SLOP>(*sboundary,gf_water_flux,gf_saturation,diff_coeff /*inifile,*param,gv,*fboundary,*fsource*/);
tlop = std::make_unique<TLOP>(_gfSaturation/*inifile,*param,gv*/);
tlop = std::make_unique<TLOP>(gf_saturation/*inifile,*param,gv*/);
Dune::PDELab::constraints(*this->gfs,*this->cc,false);
// --- Grid Operators ---
......@@ -145,14 +145,14 @@ void TransportSimulation<Traits>::step ()
this->suggest_timestep(controller->getDT());
// Check whether time intervals of grid functions are valid
if (Dune::FloatCmp::gt(_waterFluxInterval.begin(),t+_dt))
if (Dune::FloatCmp::gt(water_flux_interval.begin,t+dt))
DUNE_THROW(Dune::Exception," ");
if (Dune::FloatCmp::gt(_saturationInterval.begin(),t+_dt))
if (Dune::FloatCmp::gt(saturation_interval.begin,t+dt))
DUNE_THROW(Dune::Exception," ");
if (Dune::FloatCmp::lt(_waterFluxInterval.end(),t+_dt))
DUNE_THROW(Dune::Exception,_waterFluxInterval.end()<< " < "<<t+_dt);
if (Dune::FloatCmp::lt(_saturationInterval.end(),t+_dt))
if (Dune::FloatCmp::lt(water_flux_interval.end,t+dt))
DUNE_THROW(Dune::Exception,water_flux_interval.end<< " < "<<t+dt);
if (Dune::FloatCmp::lt(saturation_interval.end,t+dt))
DUNE_THROW(Dune::Exception," ");
const bool solver_warnings = verbose > 0 && helper.rank() == 0 ?
......@@ -164,13 +164,13 @@ void TransportSimulation<Traits>::step ()
if (not solver_warnings)
dwarn.push(false);
osm->apply(t, _dt, *u, *unext);
osm->apply(t, dt, *u, *unext);
if (not solver_warnings)
dwarn.pop();
u = unext;
if (not ts_param->implicit())
this->suggest_timestep(slop->suggestTimestep(_dt));
this->suggest_timestep(slop->suggestTimestep(dt));
}
catch (Dune::ISTLError &e){
exception = true;
......@@ -192,9 +192,9 @@ void TransportSimulation<Traits>::step ()
template<typename Traits>
void TransportSimulation<Traits>::update_adapters () const
{
Cw = std::make_shared<GFSolute>(gfs,u);
assert(_gfSaturation);
Ctotal = std::make_shared<GFTotalSolute>(*Cw,*_gfSaturation);
c_w = std::make_shared<GFSolute>(gfs,u);
assert(gf_saturation);
c_total = std::make_shared<GFTotalSolute>(*c_w,*gf_saturation);
}
template<typename Traits>
......@@ -206,11 +206,11 @@ void TransportSimulation<Traits>::write_data () const
update_adapters();
if (inifile.get<bool>("output.vertexData"))
{
vtkwriter->addVertexData(Cw,"solute");
vtkwriter->addVertexData(Ctotal,"solute (total)");
vtkwriter->addVertexData(c_w,"solute");
vtkwriter->addVertexData(c_total,"solute (total)");
} else {
vtkwriter->addCellData(Cw,"solute");
vtkwriter->addCellData(Ctotal,"solute (total)");
vtkwriter->addCellData(c_w,"solute");
vtkwriter->addCellData(c_total,"solute (total)");
}
try{
......
......@@ -224,22 +224,22 @@ protected:
std::shared_ptr<U> u;
mutable std::shared_ptr<GFSolute> Cw;
mutable std::shared_ptr<GFTotalSolute> Ctotal;
std::shared_ptr<GFWaterFlux> _gfWaterFlux;
std::shared_ptr<GFSaturation> _gfSaturation;
mutable std::shared_ptr<GFSolute> c_w;
mutable std::shared_ptr<GFTotalSolute> c_total;
std::shared_ptr<GFWaterFlux> gf_water_flux;
std::shared_ptr<GFSaturation> gf_saturation;
TimeInterval _waterFluxInterval = TimeInterval(std::numeric_limits<TimeField>::min(),
std::numeric_limits<TimeField>::min());
TimeInterval _saturationInterval = TimeInterval(std::numeric_limits<TimeField>::min(),
std::numeric_limits<TimeField>::min());
TimeInterval water_flux_interval = TimeInterval{std::numeric_limits<TimeField>::min(),
std::numeric_limits<TimeField>::min()};
TimeInterval saturation_interval = TimeInterval{std::numeric_limits<TimeField>::min(),
std::numeric_limits<TimeField>::min()};
std::unique_ptr<Writer> vtkwriter;
const int verbose;
const Dune::VTK::OutputType output_type;
TimeField _dt;
TimeField dt;
bool operator_setup_flag = true;
public:
......@@ -257,23 +257,23 @@ public:
);
// TODO: Define data exchange with richards
void set_waterflux(TimeInterval time_interval, std::shared_ptr<GFWaterFlux> gfWaterFlux)
void set_waterflux(TimeInterval _time_interval, std::shared_ptr<GFWaterFlux> _gf_water_flux)
{
if (gfWaterFlux)
if (_gf_water_flux)
{
_waterFluxInterval = time_interval;
_gfWaterFlux = gfWaterFlux;
water_flux_interval = _time_interval;
gf_water_flux = _gf_water_flux;
} else
DUNE_THROW(Dune::Exception,"Pointer to gfWaterFlux is invalid!");
}
// TODO: Define data exchange with richards
void set_saturation(TimeInterval time_interval, std::shared_ptr<GFSaturation> gfSaturation)
void set_saturation(TimeInterval _time_interval, std::shared_ptr<GFSaturation> _gf_saturation)
{
if (gfSaturation)
if (_gf_saturation)
{
_saturationInterval = time_interval;
_gfSaturation = gfSaturation;
saturation_interval = _time_interval;
gf_saturation = _gf_saturation;
} else
DUNE_THROW(Dune::Exception,"Pointer to gfWaterFlux is invalid!");
}
......@@ -295,17 +295,17 @@ public:
return controller->getTime();
}
void suggest_timestep(TimeField dt) override
void suggest_timestep(TimeField _dt) override
{
_dt = std::min(dt,controller->getDT());
dt = std::min(_dt,controller->getDT());
}
// TODO: Define data exchange with richards
std::shared_ptr<GFSolute> get_solute()
{
if (!Cw)
if (!c_w)
DUNE_THROW(Dune::Exception,"Solute in invalid state!");
return Cw;
return c_w;
}
protected:
......
......@@ -194,18 +194,10 @@ public:
}
};
template<class TF>
class TimeInterval
{
public:
using TimeField = TF;
TimeInterval(TimeField begin, TimeField end) : _begin(begin), _end(end) {}
const TimeField& begin() const {return _begin;}
TimeField& begin() {return _begin;}
const TimeField& end() const {return _end;}
TimeField& end() {return _end;}
private:
TimeField _begin, _end;
template<typename TF>
struct TimeInterval {
TF begin;
TF end;
};
......
......@@ -9,106 +9,106 @@
#include "util_boundary_condition.hh"
namespace Dune{
namespace Dorie{
namespace Dorie{
/// Boundary type and condition value queries
/** This class containts functions that return the type of boundary conditions
* and the values of the boundary condition parameters. Both types of queries
* can be time dependent.
*/
template<typename Traits>
class SoluteBoundary
{
private:
/// Boundary type and condition value queries
/** This class containts functions that return the type of boundary conditions
* and the values of the boundary condition parameters. Both types of queries
* can be time dependent.
*/
template<typename Traits>
class SoluteBoundary
{
private:
typedef typename Traits::RangeField RF;
typedef typename Traits::Domain Domain;
typedef typename Traits::IntersectionDomain ID;
typedef typename Traits::Intersection Intersection;
typedef typename Traits::RangeField RF;
typedef typename Traits::Domain Domain;
typedef typename Traits::IntersectionDomain ID;
typedef typename Traits::Intersection Intersection;
enum {dim = Traits::dim};
enum {dim = Traits::dim};
//! Object for handling the BC data file and function queries
std::unique_ptr<BCReadoutInterface<Traits>> bcDataHandler;
//! Object for handling the BC data file and function queries
std::unique_ptr<BCReadoutInterface<Traits>> bcDataHandler;
public:
public:
/// Read BC file type and create data handling object
/** \see Dune::Dorie::BCReadoutInterface
* \throw Dune::IOError BC File Type not supported
*/
SoluteBoundary(const Dune::ParameterTree& config)
{
std::string bcFileType = config.get<std::string>("boundary.fileType");
if(bcFileType == "rectangularGrid") {
bcDataHandler = std::make_unique<RectangularGrid<Traits>>(config);
}
else
DUNE_THROW(IOError,"unknown bcFileType specified!");
/// Read BC file type and create data handling object
/** \see Dune::Dorie::BCReadoutInterface
* \throw Dune::IOError BC File Type not supported
*/
SoluteBoundary(const Dune::ParameterTree& config)
{
std::string bcFileType = config.get<std::string>("boundary.fileType");
if(bcFileType == "rectangularGrid") {
bcDataHandler = std::make_unique<RectangularGrid<Traits>>(config);
}
else
DUNE_THROW(IOError,"unknown bcFileType specified!");
}
/// Return next time at which any boundary condition changes. Return -1.0 by default
/** \param time Current time
*/
RF getNextTimeStamp (const RF& time) const {
if(bcDataHandler)
return bcDataHandler->getNextTimeStamp(time);
return -1.0;
}
/// Return next time at which any boundary condition changes. Return -1.0 by default
/** \param time Current time
*/
RF getNextTimeStamp (const RF& time) const {
if(bcDataHandler)
return bcDataHandler->getNextTimeStamp(time);
return -1.0;
}
/// Return Boundary Condition Type at certain position and time
/** \param is Intersection enitity
* \param x Position in local entity coordinates
* \param time Time value
* \param xGlobal Global coordinate
* \return Boundary condition type enumerator
*/
BoundaryCondition::Type bc (const Intersection& is, const ID& x, const RF& time) const
{
const Domain xGlobal = is.geometry().global(x);
if(is.boundary()) {
return bcDataHandler->getBCtype(xGlobal, time);
}
return BoundaryCondition::Other; // unknown
/// Return Boundary Condition Type at certain position and time
/** \param is Intersection enitity
* \param x Position in local entity coordinates
* \param time Time value
* \param xGlobal Global coordinate
* \return Boundary condition type enumerator
*/
BoundaryCondition::Type bc (const Intersection& is, const ID& x, const RF& time) const
{
const Domain xGlobal = is.geometry().global(x);
if(is.boundary()) {
return bcDataHandler->getBCtype(xGlobal, time);
}
return BoundaryCondition::Other; // unknown
}
/**
* @brief Dirichlet boundary condition at certain position and time
* \param is Intersection enitity
* \param x Position in local entity coordinates
* \param time Time value
* \param xglobal Global coordinate
* \return Value of matric head
*/
RF g (const Intersection& is, const ID& x, const RF& time) const
{
const Domain xGlobal = is.geometry().global(x);
if(is.boundary()) {
if(bcDataHandler)
return bcDataHandler->getDirichletValue(xGlobal, time);
}
return 0.0;
/**
* @brief Dirichlet boundary condition at certain position and time
* \param is Intersection enitity
* \param x Position in local entity coordinates
* \param time Time value
* \param xglobal Global coordinate
* \return Value of matric head
*/
RF g (const Intersection& is, const ID& x, const RF& time) const
{
const Domain xGlobal = is.geometry().global(x);
if(is.boundary()) {
if(bcDataHandler)
return bcDataHandler->getDirichletValue(xGlobal, time);
}
return 0.0;
}
/**
* @brief Neumann boundary condition at certain position and time
* \param is Intersection enitity
* \param x Position in local entity coordinates
* \param time Time value
* \param xglobal Global coordinate
* \return Value of flux
*/
RF j (const Intersection& is, const ID& x, const RF& time) const
{
const Domain xGlobal = is.geometry().global(x);
if(is.boundary()) {
if(bcDataHandler)
return bcDataHandler->getNeumannValue(xGlobal, time);
}
return 0.0;
/**
* @brief Neumann boundary condition at certain position and time
* \param is Intersection enitity
* \param x Position in local entity coordinates
* \param time Time value
* \param xglobal Global coordinate
* \return Value of flux
*/
RF j (const Intersection& is, const ID& x, const RF& time) const
{
const Domain xGlobal = is.geometry().global(x);
if(is.boundary()) {
if(bcDataHandler)
return bcDataHandler->getNeumannValue(xGlobal, time);
}
};
}
return 0.0;
}
};
}
}
#endif
......@@ -4,7 +4,7 @@
#include <dune/pdelab/function/const.hh>
namespace Dune {
namespace Dorie {
namespace Dorie {
template<typename T>
using SoluteInitial = Dune::PDELab::ConstGridFunction<typename T::GridView,typename T::RangeField>;
......
......@@ -80,20 +80,22 @@ public:
enum { doPatternSkeleton = true };
// Residual assembly flags
enum { doAlphaVolume = true }; //
// enum { doAlphaVolume = true };
enum { doAlphaBoundary = true };
enum { doAlphaSkeleton = true };
enum { doLambdaVolume = true }; //
// enum { doLambdaVolume = true };
// enum { doLambdaBoundary = true };
private:
static_assert(std::is_same<typename GridFunctionWaterFlux::Traits::GridViewType,
typename GridFunctionSaturation::Traits::GridViewType>::value,
"TransportFVSpatialOperator: GridFunctionWaterFlux and GridFunctionSaturation has to use the same grid view.");
static_assert(std::is_same<
typename GridFunctionWaterFlux::Traits::GridViewType,
typename GridFunctionSaturation::Traits::GridViewType>::value,
"TransportFVSpatialOperator: GridFunctionWaterFlux and"
"GridFunctionSaturation has to use the same grid view.");
// Define domain field
using DF = typename GridFunctionSaturation::Traits::DomainFieldType;
using Flux =typename GridFunctionWaterFlux::Traits::RangeType;
using WaterFlux =typename GridFunctionWaterFlux::Traits::RangeType;
using Saturation =typename GridFunctionSaturation::Traits::RangeType;
// Extract world dimension
......@@ -101,15 +103,23 @@ private:
public:
/**
* @brief Constructor of TransportFVSpatialOperator
*
* @param boundary The boundary terms
* @param[in] gf_flux The grid function of water flux
* @param[in] gf_sat The grid function of water saturation
* @param[in] diff_coeff The diffusion coefficient
*/
TransportFVSpatialOperator(
Boundary& boundary,
std::shared_ptr<GridFunctionWaterFlux> gfFlux,
std::shared_ptr<GridFunctionSaturation> gfSaturation,
double D_eff
std::shared_ptr<GridFunctionWaterFlux> gf_flux,
std::shared_ptr<GridFunctionSaturation> gf_sat,
double diff_coeff
) : _boundary(boundary)
, _gfFlux(gfFlux)
, _gfSaturation(gfSaturation)
, _D_eff(D_eff)
, _gf_flux(gf_flux)
, _gf_sat(gf_sat)
, _diff_coeff(diff_coeff)
{}
/*---------------------------------------------------------------------*//**
......@@ -164,73 +174,73 @@ public:
Traits::LocalBasisType::Traits::RangeFieldType;
// Get entity entities from both sides of the intersection
auto entity_inside = ig.inside();
auto entity_outside = ig.outside();
const auto& entity_i = ig.inside();
const auto& entity_o = ig.outside();
// Get geometries
auto geo = ig.geometry();
auto geo_inside = entity_inside.geometry();
auto geo_outside = entity_outside.geometry();
auto geo_i = entity_i.geometry();
auto geo_o = entity_o.geometry();
// Get geometry of intersection in local coordinates of neighbor entities
auto geo_in_inside = ig.geometryInInside();
// Center in face's reference element
auto ref_el = referenceElement(geo);
auto face_local = ref_el.position(0,0);
auto geo_in_i = ig.geometryInInside();
// Face volume for integration
auto face_volume = geo.volume();
// Entity centers in references elements
auto ref_el_inside = referenceElement(geo_inside);
auto ref_el_outside = referenceElement(geo_outside);
auto local_inside = ref_el_inside.position(0,0);
auto local_outside = ref_el_outside.position(0,0);
// Evaluate diffusion coeff. from either side and take harmonic average
auto D_eff_inside = _D_eff;
auto D_eff_outside = _D_eff;
// Evaluate diffusion coeff. from both sides and take harmonic average
auto diff_coeff_i = _diff_coeff; // FIXME
auto diff_coeff_o = _diff_coeff; // FIXME
auto normal_face = ig.centerUnitOuterNormal();
auto D_eff_avg = 2.0/( 1.0/(D_eff_inside+ 1E-30)
+ 1.0/(D_eff_outside+1E-30));
auto diff_coeff_avg = 2.0/( 1.0/(diff_coeff_i+ 1E-30)
+ 1.0/(diff_coeff_o+ 1E-30));
auto entity_inside_local = geo_in_inside.global(face_local);
// Get center position of the face w.r.t inside entity
auto p_center_face_i = geo_in_i.center();
// Evaluate convective term (i.e water flux)
Flux flux_inside;
_gfFlux->evaluate(entity_inside, entity_inside_local, flux_inside);
auto vn = flux_inside*normal_face;
WaterFlux water_flux_i;
_gf_flux->evaluate(entity_i, p_center_face_i, water_flux_i);
auto water_flux_n = water_flux_i*normal_face;
// Inside unknown value
// Inside solute value
RF u = x_i(lfsu_i,0);
#if 1
// Upwinding
u = (vn>=0) ? x_i(lfsu_i,0) : x_o(lfsu_o,0);
u = (water_flux_n>=0) ? x_i(lfsu_i,0) : x_o(lfsu_o,0);
#endif
// Entity centers in references elements
auto ref_el_i = referenceElement(geo_i);
auto ref_el_o = referenceElement(geo_o);
auto p_center_i = ref_el_i.position(0,0);
auto p_center_o = ref_el_o.position(0,0);
// Entity centers in global coordinates
auto global_inside = geo_inside.global(local_inside);
auto global_outside = geo_outside.global(local_outside);
auto p_center_i_global = geo_i.global(p_center_i);
auto p_center_o_global = geo_o.global(p_center_o);
// Distance between the two entity centers
global_inside -= global_outside;
auto distance = global_inside.two_norm();
p_center_i_global -= p_center_o_global;
auto distance = p_center_i_global.two_norm();
// Finite difference of u between the two entities
RF dudn = (x_o(lfsu_o,0)-x_i(lfsu_i,0))/distance;
// Evaluate saturation
typename GridFunctionSaturation::Traits::RangeType sat_inside;
_gfSaturation->evaluate(ig.inside(),entity_inside_local,sat_inside);
typename GridFunctionSaturation::Traits::RangeType sat_i;
_gf_sat->evaluate(entity_i,p_center_i,sat_i);
// Solute flux in normal direction w.r.t the intersection
auto normal_flux = u*water_flux_n - diff_coeff_avg*dudn*sat_i;
// Symmetric contribution to residual on inside element
r_i.accumulate(lfsu_i, 0, ( u*vn - D_eff_avg*dudn*sat_inside )*face_volume );
r_o.accumulate(lfsu_o, 0, -( u*vn - D_eff_avg*dudn*sat_inside )*face_volume );
r_i.accumulate(lfsv_i, 0, normal_flux*face_volume );
r_o.accumulate(lfsv_o, 0, -normal_flux*face_volume );
if (_first_stage)
_dtmin = std::min(_dtmin,suggestTimestepIntersection(ig));
_dt_min = std::min(_dt_min,suggest_timestep_intersection(ig));
}
......@@ -254,12 +264,16 @@ public:
void alpha_boundary (const IG& ig, const LFSU& lfsu_i, const X& x_i,
const LFSV& lfsv_i, R& r_i) const
{
// Get entities
const auto& entitiy_face = ig.intersection();
const auto& entity_i = ig.inside();
// Get geometries
auto geo = ig.geometry();
auto geo = entitiy_face.geometry();
auto ref_el = referenceElement(geo);
auto face_local = ref_el.position(0,0);
auto p_center_face = ref_el.position(0,0);
auto bc = _boundary.bc(ig.intersection(),face_local,_time);
auto bc = _boundary.bc(entitiy_face,p_center_face,_time);
if (BoundaryCondition::isDirichlet(bc))
{
......@@ -267,69 +281,74 @@ public:
using RF = typename LFSU::Traits::FiniteElementType::
Traits::LocalBasisType::Traits::RangeFieldType;
// Inside entity center
auto entity_inside = ig.inside();
auto geo_inside = entity_inside.geometry();
auto global_inside = geo_inside.center();
auto geo_i = entity_i.geometry();
auto p_center_i_global = geo_i.center();
// Face center in global coordinates
auto global_face = geo.center();
auto p_center_face_global = geo.center();