Plugins
Loading...
Searching...
No Matches
st_venant_submodule_impl.h
Go to the documentation of this file.
1//
2// Created by julian on 5/15/25.
3//
4
5#ifndef D3F_ST_VENANT_SUBMODULE_IMPL_H
6#define D3F_ST_VENANT_SUBMODULE_IMPL_H
7
8// --- Includes ---
13#include "st_venant_submodule.h"
17#include "../../../Limex/time_disc/linear_implicit_timestep.h"
18#include "../../../Limex/time_disc/simple_integrator.hpp"
19#include "../../../Limex/time_disc/time_extrapolation.h"
20#include "../../../Limex/time_disc/time_integrator.hpp"
21#include "../../../Limex/time_disc/time_extrapolation.h"
22#include "../../../Limex/time_disc/limex_integrator.hpp"
25#include "../river_data_observer.h"
26
27namespace ug {
28namespace d3f {
29
35template<typename TDomain, typename TAlgebra>
37 number tolerance,
39 SmartPtr<TDomain> domain,
40 const char* cmp = "")
41{
42 // --- Type Definitions ---
43 typedef typename TAlgebra::vector_type vector_type;
45 typedef NewtonSolver<TAlgebra> newton_solver_type;
46 typedef BiCGStab<vector_type> linear_solver_type;
47 typedef ILU<TAlgebra> ilu_type;
48 typedef StdConvCheck<vector_type> conv_check_type;
52
53 // --- Core Solvers ---
54 auto limex_integrator = make_sp(new limex_type(2));
55 auto newton_solver = make_sp(new newton_solver_type());
56 auto linear_solver = make_sp(new linear_solver_type());
57 auto ilu = make_sp(new ilu_type());
58
59 // --- Convergence Checks ---
60 auto linear_conv_check = make_sp(new conv_check_type(100, 1e-6, 1e-4));
61 linear_solver->set_preconditioner(ilu);
62 linear_solver->set_convergence_check(linear_conv_check);
63
64 auto newton_conv_check = make_sp(new conv_check_type(1, 5e-12, 1e-12));
65 newton_conv_check->set_supress_unsuccessful(true);
66
67 newton_solver->set_linear_solver(linear_solver);
68 newton_solver->set_convergence_check(newton_conv_check);
69
70 // --- Error Estimators for Limex ---
71 auto estimator = make_sp(new gf_estimator_type());
72
73 // If a specific component is passed, estimate error only for that, otherwise do both A and v.
74 if (cmp && cmp[0] != '\0') {
75 auto l2_cmp = make_sp(new l2_type(cmp, 2));
76 estimator->add(l2_cmp.template cast_dynamic<composite_type>());
77 } else {
78 auto l2_A = make_sp(new l2_type("A", 2));
79 auto l2_v = make_sp(new l2_type("v", 2));
80 estimator->add(l2_A.template cast_dynamic<composite_type>());
81 estimator->add(l2_v.template cast_dynamic<composite_type>());
82 }
83
84 // --- Limex Configuration ---
85 limex_integrator->add_stage(1, newton_solver, domain_disc);
86 limex_integrator->add_stage(2, newton_solver, domain_disc);
87
88 limex_integrator->set_tolerance(tolerance);
89 limex_integrator->set_dt_min(1e-12);
90 limex_integrator->set_dt_max(1e10);
91 limex_integrator->add_error_estimator(estimator);
92 limex_integrator->set_increase_factor(2.0);
93 limex_integrator->select_cost_strategy(make_sp<LimexNonlinearCost>(new LimexNonlinearCost()));
94
95 return limex_integrator;
96}
97
101template<typename TGridFunction, int dim>
103
104 // --- Type Definitions ---
105 typedef typename TGridFunction::algebra_type algebra_type;
107 typedef ScaleAddLinker<number, dim, number> scale_add_linker_type;
108 typedef InverseLinker<dim> inverse_linker_type;
109 typedef NeumannBoundaryFV1<domain_type> neumann_type;
111 typedef CplUserData<number, dim> TNumberData;
112 typedef OutflowIntegrationObserver<domain_type, algebra_type> outflow_observer_type;
113
114 // --- 1. Setup Discretization Factory ---
115 auto factory = make_sp(new factory_type());
116 factory->set_b(params.b);
117 factory->set_gravity(params.gravity);
118 factory->set_diffusion(params.diffusion);
119 factory->set_domain(m_domain);
120 factory->set_ks(params.ks);
121
122 // Extract elemental discretizations for Cross-sectional Area (A) and Velocity (v)
123 auto elem_discs = factory->create_1d_swe("River");
124 m_elem_disc_A = elem_discs[0];
125 m_elem_disc_v = elem_discs[1];
126
127 auto A = m_elem_disc_A->value();
128 auto v = m_elem_disc_v->value();
129
130 // --- 2. Physics Linkers (Mathematical Expressions) ---
131 // Water depth: h = A / b
132 auto h = make_sp(new inverse_linker_type());
133 h->divide(A, params.b);
134
135 // Source terms for A: q_exfiltration + q_rainfall
136 auto source_linker = make_sp(new scale_add_linker_type());
137 source_linker->add(1.0, m_qex);
138 source_linker->add(1.0, params.qr);
139 m_elem_disc_A->set_source(source_linker);
140
141 // --- 3. Boundary Conditions ---
142 auto domain_disc = make_sp(new domain_disc_type(m_approx_space));
143
144 auto neumann_A = make_sp(new neumann_type("A"));
145 auto neumann_v = make_sp(new neumann_type("v"));
146 auto dirichlet_A = make_sp(new dirichlet_type());
147 auto dirichlet_v = make_sp(new dirichlet_type());
148
149 // Flux out for Area: Flowrate Q = v * A
150 auto flowrate = make_sp(new scale_add_linker_type());
151 flowrate->add(v, A);
152
153 // Flux out for Velocity: Includes gravity, water depth (h), riverbed elevation (sohle), and v^2
154 auto vv = make_sp(new scale_add_linker_type());
155 vv->add(v, v);
156 auto outflow = make_sp(new scale_add_linker_type());
157 outflow->add(params.gravity, h);
158 outflow->add(params.gravity, factory->export_sohle());
159 outflow->add(1.0, vv);
160
161 // Directional linkers
162 auto outflow_dir = factory->get_boundary_dir();
163 auto wall_dir = make_sp(new scale_add_linker_type());
164 wall_dir->add(-1.0, outflow_dir);
165
166 auto out_outflow = make_sp(new scale_add_linker_type());
167 auto out_flowrate = make_sp(new scale_add_linker_type());
168 out_outflow->add(outflow_dir, outflow);
169 out_flowrate->add(outflow_dir, flowrate);
170
171 // Assign BCs to respective subsets
172 dirichlet_A->add(params.dirichlet_A, "A", "Level");
173 dirichlet_v->add(0.0, "v", "Wall");
174
175 neumann_A->add(out_flowrate.template cast_dynamic<TNumberData>(), "Sink", "River");
176 neumann_v->add(out_outflow.template cast_dynamic<TNumberData>(), "Sink", "River");
177 neumann_v->add(out_outflow.template cast_dynamic<TNumberData>(), "Level", "River");
178
179 // Register all constraints and discretizations
180 domain_disc->add(dirichlet_A.template cast_dynamic<IDomainConstraint<domain_type, algebra_type>>());
181 domain_disc->add(dirichlet_v.template cast_dynamic<IDomainConstraint<domain_type, algebra_type>>());
182 domain_disc->add(neumann_A.template cast_dynamic<IElemDisc<domain_type>>());
183 domain_disc->add(neumann_v.template cast_dynamic<IElemDisc<domain_type>>());
184 domain_disc->add(m_elem_disc_A.template cast_dynamic<IElemDisc<domain_type>>());
185 domain_disc->add(m_elem_disc_v.template cast_dynamic<IElemDisc<domain_type>>());
186
187 // --- 4. Observers and VTK Output ---
188 auto limex_integrator = create_limex_solver(m_tol, domain_disc, this->m_u->domain());
189 auto downStreamVec = make_sp(new EdgeOrientation<domain_type>(m_domain));
190
191 auto vtk = make_sp<VTKOutput<dim>>(new VTKOutput<dim>());
192 vtk->select("v", "v");
193 vtk->select("A", "A");
194 vtk->select(factory->export_sohle().template cast_dynamic<UserData<number, dim>>(), "sohle");
195 vtk->select(flowrate.template cast_dynamic<UserData<number, dim>>(), "flowrate");
196 vtk->select(downStreamVec.template cast_dynamic<UserData<MathVector<dim>, dim>>(), "EdgeOrientation");
197 vtk->select(m_qex.template cast_dynamic<UserData<number, dim>>(), "qex");
198 auto voutflow = make_sp(new ScaleAddLinker<MathVector<dim>, dim, number>());
199 voutflow->add(v, downStreamVec);
200 auto outflow_observer = make_sp(new outflow_observer_type(voutflow, A, "Sink", "River"));
201 limex_integrator->attach_observer(outflow_observer);
202
203 // --- 5. Execution ---
204#ifdef UG_PARALLEL
206 com.barrier();
207 UG_LOG_ALL_PROCS("starting limex\n");
208#endif
209
210 UG_LOG_ALL_PROCS("integrating from " << tStart << " to " << tEnd << "\n");
211
212 if (!m_domain->empty() || true) {
213 limex_integrator->apply(this->m_u, tEnd, this->m_u, tStart);
214 }
215
216 #ifdef UG_PARALLEL
217 com.barrier();
218 if (pcl::ProcRank() == 0 and m_step > 0) {
219 #endif
220
221 typedef typename TGridFunction::template dim_traits<1>::const_iterator const_iterator;
222 typedef typename domain_traits<1>::grid_base_object grid_base_object;
223 const_iterator iter = this->m_u->template begin<grid_base_object>();
224 const_iterator iterEnd = this->m_u->template end<grid_base_object>();
225 typedef UserDataIntegrand<number,TGridFunction> integrand_type;
226 int quad_order = 1;
227
228 integrand_type A_integrand = integrand_type(m_elem_disc_A->value(), this->m_u.get(), tEnd);
229 number value = 1000 * Integrate<dim, 1, const_iterator>(iter, iterEnd,
230 this->m_u->domain()->position_accessor(),
231 A_integrand,
232 quad_order, "");
233 vtk->print("results/rivers", *this->m_u, m_step, tEnd);
234
235 std::ofstream myfile;
236 myfile.open("results/river_outflow.txt", std::ios::out | std::ios::app);
237 myfile << tEnd << "\t" << outflow_observer->value() << "\t"<< value << "\n";
238 UG_LOGN("Total River outflow for dt = " <<tEnd - tStart << " is " << outflow_observer->value() << " kg\n" );
239 myfile.close();
240#ifdef UG_PARALLEL
241
242 }
243#endif
244
245 m_step++;
246}
247
251template<typename TGridFunction, int dim>
253
254 const char* m_filename = "results/river_outflow.txt";
255 #ifdef UG_PARALLEL
256 if (pcl::ProcRank() == 0)
257 #endif
258 {
259 std::ofstream myfile;
260 myfile.open(m_filename, std::ios::out | std::ios::trunc);
261 myfile << "time\taccumulated outflow since last measurement\tstorage\n";
262 myfile.close();
263 }
264
265 // --- 1. Setup Domain & Grid Load ---
266 SmartPtr<typename TGridFunction::domain_type> dom = make_sp(new typename TGridFunction::domain_type());
267 dom->update_domain_info();
268
269 std::vector<std::string> additionalSHNames = dom->additional_subset_handler_names();
270 std::vector<SmartPtr<ISubsetHandler>> ash(additionalSHNames.size());
271 for(size_t i = 0; i < additionalSHNames.size(); ++i) {
272 ash[i] = dom->additional_subset_handler(additionalSHNames[i]);
273 }
274
275 dom->grid()->message_hub()->post_message(GridMessage_Creation(GMCT_CREATION_STARTS, -2));
276
277 SPProjectionHandler ph = make_sp(new ProjectionHandler(dom->geometry3d(), dom->subset_handler()));
278 size_t num_ph = 0;
279
280 // Load mesh from UGX file
281 LoadGridFromUGX(*(dom->grid()), ph, num_ph, *(dom->subset_handler()), additionalSHNames, ash, filename, dom->position_attachment());
282
283 dom->update_subset_infos(-2);
284 dom->grid()->message_hub()->post_message(GridMessage_Creation(GMCT_CREATION_STOPS));
285 dom->update_domain_info();
286
287 m_domain = dom;
288
289 // --- 2. Setup Approximation Space ---
290 m_approx_space = make_sp(new approx_space_type(m_domain));
291
292 // Initialize Lagrange P1 functions for Cross-Sectional Area (A) and Velocity (v)
293 m_approx_space->add("A", "Lagrange", 1);
294 m_approx_space->add("v", "Lagrange", 1);
295 m_approx_space->init_levels();
296 m_approx_space->init_top_surface();
297
298 // --- 3. Initial Interpolations ---
299 this->m_u = make_sp(new TGridFunction(m_approx_space));
300 Interpolate(params.dirichlet_A, this->m_u, "A");
301 Interpolate(0.0, this->m_u, "v");
302
303 // --- 4. Initialize Discretizations ---
304 auto factory = make_sp(new factory_type());
305 factory->set_domain(m_domain);
306 factory->set_b(params.b);
307 factory->set_gravity(params.gravity);
308 factory->set_diffusion(params.diffusion);
309 factory->set_ks(params.ks);
310
311 auto elem_discs = factory->create_1d_swe("River");
312 m_elem_disc_A = elem_discs[0];
313 m_elem_disc_v = elem_discs[1];
314}
315
316} // namespace d3f
317} // namespace ug
318
319#endif //D3F_ST_VENANT_SUBMODULE_IMPL_H
Evaluate difference between two functions (w.r.t various norms)
Definition time_extrapolation.h:881
For.
Definition limex_integrator.hpp:153
Base class for LIMEX time integrator.
Definition limex_integrator.hpp:254
Observer that integrates the river outflow over time.
Definition river_data_observer.h:27
Factory class to construct and link the coupled St. Venant equations.
Definition st_venant_elem_disc.h:61
void init(const char *filename)
Initializes the grid and approximation space from a UGX file.
Definition st_venant_submodule_impl.h:252
void run(number tStart, number tEnd, number dt) override
Executes the simulation loop from tStart to tEnd.
Definition st_venant_submodule_impl.h:102
TGridFunction::algebra_type algebra_type
Definition st_venant_submodule.h:64
int ProcRank()
#define UG_LOG_ALL_PROCS(msg)
#define UG_LOGN(msg)
double number
SmartPtr< LimexTimeIntegrator< TDomain, TAlgebra > > create_limex_solver(number tolerance, SmartPtr< DomainDiscretization< TDomain, TAlgebra > > domain_disc, SmartPtr< TDomain > domain, const char *cmp="")
Creates and configures the Limex Time Integrator for the St. Venant equations.
Definition st_venant_submodule_impl.h:36
bool LoadGridFromUGX(Grid &grid, ISubsetHandler &sh, const char *filename)
GMCT_CREATION_STOPS
GMCT_CREATION_STARTS
void Interpolate(number val, SmartPtr< TGridFunction > spGridFct, const char *cmp)
SmartPtr< T, FreePolicy > make_sp(T *inst)
Submodule for solving the 1D St. Venant (Shallow Water) equations.