Plugins
Loading...
Searching...
No Matches
add_river_sss.h
Go to the documentation of this file.
1
6#ifndef UG4_ADD_RIVER_SSS_H
7#define UG4_ADD_RIVER_SSS_H
8
12#include "../d3f_sss.h"
16
17namespace ug {
18namespace d3f {
19
29template <typename TDomain>
30class ExfiltrationFlux : public StdDataLinker<ExfiltrationFlux<TDomain>, number, TDomain::dim> {
31public:
32 static const int dim = TDomain::dim;
33 typedef typename TDomain::grid_type TGrid;
34 typedef typename TGrid::template EdgeAttachmentAccessor<ANumber> accessor_type;
35
36 explicit ExfiltrationFlux(accessor_type& acc) : m_acc(acc) {}
37
38 inline void evaluate(number& value, const MathVector<dim>& globIP, number time, int si) const {
39 UG_THROW("ExfiltrationFlux: Point evaluation not supported. Use element-based evaluation.");
40 }
41
45 template <int refDim>
46 inline void evaluate(number vValue[],
47 const MathVector<dim> vGlobIP[],
48 number time, int si,
49 GridObject* elem,
50 const MathVector<dim> vCornerCoords[],
51 const MathVector<refDim> vLocIP[],
52 const size_t nip,
53 LocalVector* u,
54 const MathMatrix<refDim, dim>* vJT = NULL) const
55 {
56 Edge* edgeElem = static_cast<Edge*>(elem);
57 const number flux = m_acc[edgeElem];
58 for (size_t ip = 0; ip < nip; ++ip) {
59 vValue[ip] = flux;
60 }
61 }
62
63 template <int refDim>
64 void eval_and_deriv(number vValue[],
65 const MathVector<dim> vGlobIP[],
66 number time, int si,
67 GridObject* elem,
68 const MathVector<dim> vCornerCoords[],
69 const MathVector<refDim> vLocIP[],
70 const size_t nip,
71 LocalVector* u,
72 bool bDeriv,
73 int s,
74 std::vector<std::vector<number>> vvvDeriv[],
75 const MathMatrix<refDim, dim>* vJT = NULL) const
76 {
77 evaluate<refDim>(vValue, vGlobIP, time, si, elem, vCornerCoords, vLocIP, nip, u, vJT);
78 // Exchange flux is treated explicitly in the coupling; derivative w.r.t. surface state is zero.
79 }
80
81 bool requires_grid_fct() const { return true; }
82
83private:
85};
86
105template <typename TDomain, typename TAlgebra>
107public:
108 static const int dim = TDomain::dim;
111 typedef typename TDomain::grid_type TGrid;
112 typedef typename TGrid::template EdgeAttachmentAccessor<ANumber> accessor_type;
115
116 RiverSSSManager() = default;
117
124 : m_spRiverU(riverU), m_spSubsurfaceU(ssU)
125 {
127
128 TGrid& grid = *riverU->domain()->grid();
129 grid.attach_to_edges(m_aExchangeFlux);
131
133 .template cast_dynamic<CplUserData<number, dim>>();
134 }
135
136 // --- Configuration ---
137 void set_bottom_permeability(number perm) { m_perm = perm; }
138 void set_bottom_thickness(number thickness) { m_bottom_thickness = thickness; }
139 void set_river_width(number width) { m_width = width; }
141
143 void push_sss_manager(SmartPtr<TSSSManager> ssmngr) { m_vspSSSManager.push_back(ssmngr); }
144
150 UG_LOG("Initializing River SSS managers...\n");
151 m_vspLineSSS.clear();
152
153 auto river_grid = m_spRiverU->domain()->grid();
154 const size_t numEdges = river_grid->template num<Edge>();
155 m_vspLineSSS.assign(numEdges, SPNULL);
156
157 auto vAcc = m_spRiverU->domain()->position_accessor();
158 auto iter = m_spRiverU->template begin<Edge>();
159 auto end = m_spRiverU->template end<Edge>();
160
161 size_t i = 0;
162 for (; iter != end; ++iter, ++i) {
163 Edge* edge = *iter;
164 m_aaExchangeFlux[edge] = 0.0;
165
166 MathVector<dim> x0 = vAcc[edge->vertex(0)];
167 MathVector<dim> x1 = vAcc[edge->vertex(1)];
168
169 // Evaluate subsurface pressure at the higher node (approximate phreatic surface)
170 MathVector<dim> eval_point = (x0[dim - 1] > x1[dim - 1]) ? x0 : x1;
171
172 number subsurface_pressure = 0.0;
173 if (!m_spGlobEval->try_evaluate_global(subsurface_pressure, eval_point)) {
174 // Processor doesn't own the 3D volume under this river segment
175 continue;
176 }
177
178 // Create SSS: Intensity is driven by the 1D water column height (h)
179 auto spSSS = make_sp(new line_sss_type(x0, x1));
180 spSSS->set_edge(edge);
181
182 // We initialize with current height data
183 std::vector<DoFIndex> ind;
184 m_spRiverU->template dof_indices<Edge>(edge, 0, ind);
185 number h = (x0[dim - 1] > x1[dim - 1]) ? DoFRef(*m_spRiverU, ind[0]) : DoFRef(*m_spRiverU, ind[1]);
186
187 spSSS->set(m_gravity * m_density * h, 0.0, m_perm, m_width, m_bottom_thickness);
188 m_vspLineSSS[i] = spSSS;
189
190 for (auto& ssmngr : m_vspSSSManager) {
191 ssmngr->add_line(spSSS);
192 }
193 }
194 }
195
202 auto vAcc = m_spRiverU->domain()->position_accessor();
203 auto iter = m_spRiverU->template begin<Edge>();
204 auto end = m_spRiverU->template end<Edge>();
205
206 size_t i = 0;
207 for (; iter != end; ++iter, ++i) {
208 auto spSSS = m_vspLineSSS[i];
209 if (!spSSS.valid()) continue;
210
211 Edge* edge = *iter;
212 std::vector<DoFIndex> ind;
213 m_spRiverU->template dof_indices<Edge>(edge, 0, ind);
214
215 MathVector<dim> x0 = vAcc[edge->vertex(0)];
216 MathVector<dim> x1 = vAcc[edge->vertex(1)];
217 number h = (x0[dim - 1] > x1[dim - 1]) ? DoFRef(*m_spRiverU, ind[0]) : DoFRef(*m_spRiverU, ind[1]);
218
219 // Update SSS intensity: p_river = rho * g * h
220 spSSS->set(m_gravity * m_density * h, 0.0, m_perm, m_width, m_bottom_thickness);
221 }
222 }
223
234 const size_t numEdges = m_spRiverU->domain()->grid()->template num<Edge>();
235 m_vflux.assign(numEdges, 0.0);
236
237 // Reset local flux accumulation
238 auto river_grid = m_spRiverU->domain()->grid();
239 for (auto it = m_spRiverU->template begin<Edge>(); it != m_spRiverU->template end<Edge>(); ++it) {
240 m_aaExchangeFlux[*it] = 0.0;
241 }
242
243 typedef typename TDomain::position_accessor_type t_pos_accessor;
245 line_iterator<TElem, t_pos_accessor, DimFV1Geometry<dim>> t_lin_sss_iter;
246
247 t_pos_accessor& aaPos = u->domain()->position_accessor();
248 auto& grid = static_cast<Grid&>(*u->domain()->grid());
250 std::vector<MathVector<dim>> vCorner;
251
253
254 // Iterate only over cached interface elements
255 for (auto elem : m_interface_elements) {
256 CollectCornerCoordinates(vCorner, *elem, aaPos, true);
257 geo.update(elem, &vCorner[0], u->domain()->subset_handler().get());
258
259 // Check each sub-control volume (SCV) of the 3D cell
260 for (size_t ip = 0; ip < geo.num_scv(); ip++) {
261 size_t co = geo.scv(ip).node_id();
262
263 std::vector<DoFIndex> ind;
264 u->dof_indices(elem, u->fct_id_by_name("p"), ind);
265 const number p_sub = DoFRef(*u, ind[co]);
266
267 // Find all river segments crossing this SCV
268 for (t_lin_sss_iter line(m_vspSSSManager[0].get(), elem, grid, aaPos, geo, co); !line.is_over(); ++line) {
269 auto* line_sss = *line;
270 Edge* river_edge = line_sss->get_edge();
271
272 const number segmentLength = VecDistance(line.seg_start(), line.seg_end());
273 const number p_riv = line_sss->intensity();
274 const number matrix_perm = line_sss->matrix_permeability();
275 const number rel_bot_perm = line_sss->relative_bottom_permeability();
276
277 // Only handle infiltration (river -> subsurface) if desired,
278 // or both. Currently assumes exfiltration is driving the coupling.
279 if (p_sub < p_riv) continue;
280
281 // Reconstruct analytical leakage: Q [m^3/s] = L * (K/mu) * (p_sub - p_riv) * (W/B)
282 const number total_perm = matrix_perm * rel_bot_perm;
283 const number leakage_vol = segmentLength * (total_perm / m_viscosity) *
284 (p_sub - p_riv) * (m_width / m_bottom_thickness);
285
286 // Convert to target line flux [m^2/s]
287 const number edge_length = VecDistance(vAcc(river_edge->vertex(0)), vAcc(river_edge->vertex(1)));
288 m_aaExchangeFlux[river_edge] += leakage_vol / edge_length;
289 }
290 }
291 }
292
293 // --- MPI Synchronization ---
294#ifdef UG_PARALLEL
295 if (pcl::NumProcs() > 1) {
296 // Flatten to array for reduction
297 size_t idx = 0;
298 for (auto it = m_spRiverU->template begin<Edge>(); it != m_spRiverU->template end<Edge>(); ++it, ++idx) {
299 m_vflux[idx] = m_aaExchangeFlux[*it];
300 }
301 // Sum up partial fluxes from distributed 3D interface volumes
303 std::vector<number> global_fluxes(numEdges, 0.0);
304 com.allreduce(&m_vflux[0], &global_fluxes[0], numEdges, pcl::DataTypeTraits<number>::get_data_type(), PCL_RO_SUM);
305 // Write back global values to local 1D copies
306 idx = 0;
307 for (auto it = m_spRiverU->template begin<Edge>(); it != m_spRiverU->template end<Edge>(); ++it, ++idx) {
308 m_aaExchangeFlux[*it] = global_fluxes[idx];
309 }
310 }
311#endif
312 }
313
314private:
319 m_interface_elements.clear();
320 typedef typename TDomain::position_accessor_type t_pos_accessor;
322 line_iterator<TElem, t_pos_accessor, DimFV1Geometry<dim>> t_lin_sss_iter;
323
324 t_pos_accessor& aaPos = u->domain()->position_accessor();
325 auto& grid = static_cast<Grid&>(*u->domain()->grid());
327 std::vector<MathVector<dim>> vCorner;
328
329 for (auto iter = u->template begin<TElem>(); iter != u->template end<TElem>(); ++iter) {
330 auto elem = *iter;
331 CollectCornerCoordinates(vCorner, *elem, aaPos, true);
332 geo.update(elem, &vCorner[0], u->domain()->subset_handler().get());
333
334 bool found = false;
335 for (size_t i = 0; i < geo.num_scv() && !found; i++) {
336 t_lin_sss_iter line(m_vspSSSManager[0].get(), elem, grid, aaPos, geo, geo.scv(i).node_id());
337 if (!line.is_over()) {
338 m_interface_elements.push_back(elem);
339 found = true;
340 }
341 }
342 }
343 }
344
345 // Helper for vertex position access on the river grid
346 MathVector<dim> vAcc(Vertex* v) const { return m_spRiverU->domain()->position_accessor()[v]; }
347
353
354 std::vector<SmartPtr<TSSSManager>> m_vspSSSManager;
355 std::vector<SmartPtr<line_sss_type>> m_vspLineSSS;
356 std::vector<number> m_vflux;
357 std::vector<TElem*> m_interface_elements;
358
359 number m_perm = 1e-10;
365
368};
369
370} // namespace d3f
371} // namespace ug
372
373#endif // UG4_ADD_RIVER_SSS_H
parameterString s
Definition Biogas.lua:2
T * get()
size_t allreduce(const size_t &t, pcl::ReduceOperation op) const
TData & value(size_t s, size_t ip)
size_t num_scv() const
void update(GridObject *elem, const MathVector< worldDim > *vCornerCoords, const ISubsetHandler *ish=NULL)
const SCV & scv(size_t i) const
virtual Vertex * vertex(size_t index) const
dim_traits< dim >::grid_base_object element_type
number time() const
const MathVector< dim > & ip(size_t s, size_t ip) const
Spatial linker that exposes exchange fluxes stored on 1D edges.
Definition add_river_sss.h:30
void eval_and_deriv(number vValue[], const MathVector< dim > vGlobIP[], number time, int si, GridObject *elem, const MathVector< dim > vCornerCoords[], const MathVector< refDim > vLocIP[], const size_t nip, LocalVector *u, bool bDeriv, int s, std::vector< std::vector< number > > vvvDeriv[], const MathMatrix< refDim, dim > *vJT=NULL) const
Definition add_river_sss.h:64
static const int dim
Definition add_river_sss.h:32
TDomain::grid_type TGrid
Definition add_river_sss.h:33
void evaluate(number &value, const MathVector< dim > &globIP, number time, int si) const
Definition add_river_sss.h:38
accessor_type & m_acc
Definition add_river_sss.h:84
ExfiltrationFlux(accessor_type &acc)
Definition add_river_sss.h:36
TGrid::template EdgeAttachmentAccessor< ANumber > accessor_type
Definition add_river_sss.h:34
bool requires_grid_fct() const
Definition add_river_sss.h:81
void evaluate(number vValue[], const MathVector< dim > vGlobIP[], number time, int si, GridObject *elem, const MathVector< dim > vCornerCoords[], const MathVector< refDim > vLocIP[], const size_t nip, LocalVector *u, const MathMatrix< refDim, dim > *vJT=NULL) const
Retrieves the flux value for a given 1D edge element.
Definition add_river_sss.h:46
Orchestrates the mass exchange between a 1D river and a 3D subsurface.
Definition add_river_sss.h:106
TDomain::grid_type TGrid
Definition add_river_sss.h:111
SmartPtr< CplUserData< number, dim > > m_spExfiltrationFlux
Definition add_river_sss.h:351
number m_density
Definition add_river_sss.h:364
void update_line_sss(number dt)
Updates SSS intensities with current 1D river levels.
Definition add_river_sss.h:201
MathVector< dim > vAcc(Vertex *v) const
Definition add_river_sss.h:346
void set_density(SmartPtr< CplUserData< number, dim > > density)
Definition add_river_sss.h:140
std::vector< SmartPtr< line_sss_type > > m_vspLineSSS
Definition add_river_sss.h:355
number m_gravity
Definition add_river_sss.h:362
SmartPtr< TGridFunction > m_spSubsurfaceU
Definition add_river_sss.h:350
TGrid::template EdgeAttachmentAccessor< ANumber > accessor_type
Definition add_river_sss.h:112
void cache_interface_elements(SmartPtr< TGridFunction > u)
Identifies all 3D cells that contain at least one river segment.
Definition add_river_sss.h:318
SmartPtr< TGridFunction > m_spRiverU
Definition add_river_sss.h:349
static const int dim
Definition add_river_sss.h:108
void init_line_sss()
Creates line SSS objects in the 3D domain for all 1D river edges. Must be called once before the simu...
Definition add_river_sss.h:149
ANumber m_aExchangeFlux
Definition add_river_sss.h:366
SmartPtr< GlobalGridFunctionNumberData< TGridFunction > > m_spGlobEval
Definition add_river_sss.h:348
SmartPtr< CplUserData< number, dim > > m_spDensity
Definition add_river_sss.h:352
TSSSManager::line_sss_type line_sss_type
Definition add_river_sss.h:113
RiverSSSManager(SmartPtr< TGridFunction > riverU, SmartPtr< TGridFunction > ssU)
Constructor.
Definition add_river_sss.h:123
void set_bottom_thickness(number thickness)
Definition add_river_sss.h:138
void set_river_width(number width)
Definition add_river_sss.h:139
void evaluate_exchange_flux(SmartPtr< TGridFunction > u)
Computes the mass-conservative exchange flux [m^2/s] integrated over each river edge.
Definition add_river_sss.h:233
accessor_type m_aaExchangeFlux
Definition add_river_sss.h:367
TGridFunction::element_type TElem
Definition add_river_sss.h:114
SmartPtr< CplUserData< number, dim > > get_qex()
Definition add_river_sss.h:142
std::vector< TElem * > m_interface_elements
Definition add_river_sss.h:357
void push_sss_manager(SmartPtr< TSSSManager > ssmngr)
Definition add_river_sss.h:143
RiverSingularSourcesAndSinks< dim > TSSSManager
Definition add_river_sss.h:110
GridFunction< TDomain, TAlgebra > TGridFunction
Definition add_river_sss.h:109
std::vector< number > m_vflux
Definition add_river_sss.h:356
void set_bottom_permeability(number perm)
Definition add_river_sss.h:137
number m_viscosity
Definition add_river_sss.h:363
number m_bottom_thickness
Definition add_river_sss.h:361
std::vector< SmartPtr< TSSSManager > > m_vspSSSManager
Definition add_river_sss.h:354
number m_width
Definition add_river_sss.h:360
number m_perm
Definition add_river_sss.h:359
Specialization of the optimized SSS manager for river networks.
Definition river_sss.h:357
function get(x, y, z, t)
SmartPtr< TGrid > grid()
void CollectCornerCoordinates(int base_object_id, std::vector< typename TDomain::position_type > &vCornerCoordsOut, GridObject &elem, const TDomain &domain, bool clearContainer)
#define PCL_RO_SUM
int NumProcs()
const NullSmartPtr SPNULL
#define UG_THROW(msg)
#define UG_LOG(msg)
double number
vector_t::value_type VecDistance(const vector_t &v1, const vector_t &v2)
const number & DoFRef(const TMatrix &mat, const DoFIndex &iInd, const DoFIndex &jInd)
SmartPtr< T, FreePolicy > make_sp(T *inst)