Plugins
Loading...
Searching...
No Matches
fract_thf_fv1_impl.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2025 Gesellschaft fuer Anlagen- und Reaktorsicherheit gGmbH
3 * SPDX-License-Identifier: EUPL-1.2
4 * SPDX-FileContributor: Dmitry Logashenko, Sabine Stichel
5 * SPDX-FileContributor: Goethe Universität Frankfurt
6 * SPDX-FileType: SOURCE
7 *
8 * This file is part of d3f++.
9 * d3f++ is an extension for UG4. Licensing information and citation requirements of UG4 are provided in LICENSES/UG4-LGPL_2.1
10 */
11
12
13/*
14 * fract_thf_fv1_impl.h - class member implementation of the discretization of
15 * the FV-discretization of the thermohaline flow in fractured porous media.
16 *
17 * Based on the modules by A. Vogel.
18 */
19
20/* UG4 headers: */
25#ifdef UG_FOR_LUA
27#endif
28
29namespace ug{
30namespace d3f{
31
33// Local discretization interface
35
37template<typename TDomain>
39(
40 const std::vector<LFEID> & vLfeID,
41 bool bNonRegular
42)
43{
44// check the grid
45 if (bNonRegular)
46 UG_THROW ("ERROR in FractTHF_FV1:"
47 " The discretization does not support hanging nodes.\n");
48
49// check number of the components
50 if (vLfeID.size () != 3)
51 UG_THROW ("FractTHF_FV1: The density driven flow requires two coponents in every vertex.");
52 /* one component for the real part and one for the imaginary part */
53
54// check whether these are the LagrangeP1 elements
55 if (vLfeID[0] != LFEID(LFEID::LAGRANGE, dim, 1) || vLfeID[1] != LFEID(LFEID::LAGRANGE, dim, 1) || vLfeID[2] != LFEID(LFEID::LAGRANGE, dim, 1))
56 UG_THROW ("FractTHF_FV1: This discretization works with the LagrangeP1-elements only.");
57}
58
60// assembling
62
64template<typename TDomain>
66{
67 if (m_spVolStabData.valid())
68 // set the "volume extensions" to 0
69 m_spVolStabData->reset_flux();
70
71 if (m_sss_mngr.valid ())
72 {
73 // reset the markers of the singular sources and sinks
74 m_sss_mngr->init_all_point_sss ();
75 m_sss_mngr->init_all_line_sss ();
76 }
77}
78
80template<typename TDomain>
81template<typename TElem>
83(
85 int si
86)
87{
88// check whether we are in a degenerated fracture
89 if (! m_spFractManager.valid())
90 m_isFracture = false;
91 else
92 {
93 if (! m_spFractManager->is_closed ())
94 UG_THROW ("FractTHF_FV1: Fracture manager not closed");
95 m_isFracture = m_spFractManager->contains (si);
96 }
97
98// check the imports
99 if (!m_imDensityCo.data_given())
100 UG_THROW ("FractTHF_FV1: Missing Import 'density at corners'.");
101 if (!m_imDensityIP.data_given())
102 UG_THROW ("FractTHF_FV1: Missing Import 'density at IPs'.");
103 if (!m_imViscosityCo.data_given())
104 UG_THROW ("FractTHF_FV1: Missing Import 'viscosity at corners'.");
105 if (!m_imViscosityIP.data_given())
106 UG_THROW ("FractTHF_FV1: Missing Import 'viscosity at IP's'.");
107 if (!m_imConstGravity.data_given())
108 UG_THROW ("FractTHF_FV1: Missing Import 'gravity'.");
109 if (!m_imPorosity.data_given())
110 UG_THROW ("FractTHF_FV1: Missing Import 'porosity'.");
111 if(m_spVolStabData.valid() && !m_imOldDensityCo.data_given())
112 UG_THROW ("FractTHF_FV1: Missing Import 'density at corners'.");
113
114// get the gravity
115 if (m_imConstGravity.constant())
116 (*m_imConstGravity.user_data()) (m_Gravity, MathVector<dim>(), 0.0, 0);
117 else
118 UG_THROW ("FractTHF_FV1: Gravity must be constant.");
119
120// call the specific routine:
121 if (! m_isFracture)
122 this->template bulk_prepare_element_loop<TElem> (roid, si);
123 else
124 this->template fract_prepare_element_loop<TElem> (roid, si);
125
126// check if the volume stabilization is active
127 m_bVolStabDataActive = (m_spVolStabData.valid() && m_spVolStabData->flux_is_active());
128}
129
131template<typename TDomain>
132template<typename TElem>
134(
135 ReferenceObjectID roid,
136 int si
137)
138{
139 typedef FV1Geometry<TElem, dim> TBulkFVGeom;
140
141// check the imports
142 if (!m_imPermeability.data_given())
143 UG_THROW ("FractTHF_FV1: Missing Import 'full-dim. permeability'.");
144 if (!m_imDiffusion.data_given())
145 UG_THROW ("FractTHF_FV1: Missing Import 'full_dim. diffusion'.");
146 if (!m_imThermalConductivity.data_given())
147 UG_THROW ("FractTHF_FV1: Missing Import 'full_dim. thermal conductivity'.");
148
149// check, that upwind has been set
150 if (m_spUpwind.invalid())
151 UG_THROW("FractTHF_FV1: Upwind for the transport has not been set.");
152 if (m_spUpwindEnergy.invalid())
153 UG_THROW("FractTHF_FV1: Upwind for the energy has not been set.");
154
155 TBulkFVGeom& bulk_geo = GeomProvider<TBulkFVGeom>::get();
156 static const int refDim = TElem::dim;
157
158// set local IP coordinates
159 const MathVector<refDim>* vSCVFip = bulk_geo.scvf_local_ips();
160 size_t numSCVFip = bulk_geo.num_scvf_ips();
161 m_imDensityIP.template set_local_ips<refDim> (vSCVFip, numSCVFip, false);
162 m_imViscosityIP.template set_local_ips<refDim> (vSCVFip, numSCVFip, false);
163
164 m_imFractDarcyVelIP.template set_local_ips<refDim> (vSCVFip, numSCVFip, false);//to delete
165
166 const MathVector<refDim>* vSCVip = bulk_geo.scv_local_ips();
167 size_t numSCVip = bulk_geo.num_scv_ips();
168 m_imDensityCo.template set_local_ips<refDim> (vSCVip, numSCVip, false);
169 m_imViscosityCo.template set_local_ips<refDim> (vSCVip, numSCVip, false);
170 if (m_spVolStabData.valid ())
171 m_imOldDensityCo.template set_local_ips<refDim> (vSCVip, numSCVip, 1, false);
172
173 const MathVector<refDim>* coe_local = bulk_geo.coe_local ();
174 m_imPorosity.template set_local_ips<refDim> (coe_local, 1, false);
175 m_imPermeability.template set_local_ips<refDim> (coe_local, 1, false);
176 m_imDiffusion.template set_local_ips<refDim> (coe_local, 1, false);
177 m_imThermalConductivity.template set_local_ips<refDim> (coe_local, 1, false);
178
179// init upwind for element type
180 if(! m_spUpwind->template set_geometry_type<TBulkFVGeom>(bulk_geo))
181 UG_THROW("FractTHF_FV1: Cannot init upwind for the transport for bulk element type.");
182// init upwind for element type
183 if(! m_spUpwindEnergy->template set_geometry_type<TBulkFVGeom>(bulk_geo))
184 UG_THROW("FractTHF_FV1: Cannot init upwind for the energy for bulk element type.");
185}
186
188template<typename TDomain>
189template<typename TElem>
191(
192 ReferenceObjectID roid,
193 int si
194)
195{
196 typedef typename reference_element_traits<TElem>::reference_element_type ref_elem_type;
197 static const int refDim = TElem::dim; // dimensionality of the element, not the side!
198 ref_elem_type& rRefElem = Provider<ref_elem_type>::get ();
199
200// initialize the pointer to the FV geometry for fracture elements
201 m_pFractGeo = &GeomProvider<TFractFVGeom>::get (LFEID (LFEID::LAGRANGE, low_dim, 1), 1);
202
203// check the imports
204 if (!m_imAperture.data_given())
205 UG_THROW ("FractTHF_FV1: Missing Import 'fracture width (aperture)'.");
206 if (!m_imFractPermeability.data_given())
207 UG_THROW ("FractTHF_FV1: Missing Import 'permeability along fracture'.");
208 if (!m_imOrthoPermeability.data_given())
209 UG_THROW ("FractTHF_FV1: Missing Import 'permeability of the bulk-fracture interface'.");
210 if (!m_imFractDiffusion.data_given())
211 UG_THROW ("FractTHF_FV1: Missing Import 'diffusion along fracture'.");
212 if (!m_imOrthoDiffusion.data_given())
213 UG_THROW ("FractTHF_FV1: Missing Import 'diffusion through the bulk-fracture interface'.");
214 if (!m_imFractThermCond.data_given())
215 UG_THROW ("FractTHF_FV1: Missing Import 'thermal conductivity along fracture'.");
216 if (!m_imOrthoThermCond.data_given())
217 UG_THROW ("FractTHF_FV1: Missing Import 'thermal conductivity through the bulk-fracture interface'.");
218 if(!m_imFractDarcyVelIP.data_given())
219 UG_THROW("FractTHF_FV1: Missing Import: Darcy Velocity in fracture.");
220
221// check, that upwind has been set
222 if (m_spUpwind.invalid())
223 UG_THROW("FractTHF_FV1: Upwind for the transport has not been set.");
224// check, that upwind has been set
225 if (m_spUpwindEnergy.invalid())
226 UG_THROW("FractTHF_FV1: Upwind for the energy has not been set.");
227
228// set up local ip coordinates for corner import parameters
229// REMARK: Note that for the fracture elements, values of the corner import
230// parameters are indexed not by scv (as for the normal elements) but by
231// the corner indices in the reference element
232 m_imDensityCo.template set_local_ips<refDim> (rRefElem.corners(), ref_elem_type::numCorners, false);
233 m_imViscosityCo.template set_local_ips<refDim> (rRefElem.corners(), ref_elem_type::numCorners, false);
234 if(m_spVolStabData.valid())
235 m_imOldDensityCo.template set_local_ips<refDim> (rRefElem.corners(), ref_elem_type::numCorners, 1, false);
236}
237
239template<typename TDomain>
240template<typename TElem>
244
246template<typename TDomain>
247template<typename TElem>
249(
250 const LocalVector & u,
251 GridObject * elem,
252 ReferenceObjectID roid, // id of reference element used for assembling
253 const position_type vCornerCoords []
254)
255{
256 TElem * pElem = static_cast<TElem*> (elem);
257
258// call the specific routine:
259 if (! m_isFracture)
260 this->template bulk_prepare_element<TElem> (u, pElem, vCornerCoords);
261 else
262 this->template fract_prepare_element<TElem> (u, pElem, vCornerCoords);
263}
264
266template<typename TDomain>
267template<typename TElem>
269(
270 const LocalVector & u,
271 TElem * elem,
272 const position_type vCornerCoords []
273)
274{
275 typedef FV1Geometry<TElem, dim> TBulkFVGeom;
276
277// update the FV geometry for this element
278 TBulkFVGeom& bulk_geo = GeomProvider<TBulkFVGeom>::get();
279 try
280 {
281 bulk_geo.update (elem, vCornerCoords, &(this->subset_handler()));
282 }
283 UG_CATCH_THROW("FractTHF_FV1: Cannot update the Finite Volume Geometry for a bulk element.");
284
285// set global positions for user data
286 const MathVector<dim>* vSCVFip = bulk_geo.scvf_global_ips();
287 size_t numSCVFip = bulk_geo.num_scvf_ips();
288 m_imDensityIP.set_global_ips (vSCVFip, numSCVFip);
289 m_imViscosityIP.set_global_ips (vSCVFip, numSCVFip);
290
291 m_imFractDarcyVelIP.set_global_ips (vSCVFip, numSCVFip);//to delete
292
293 const MathVector<dim>* vSCVip = bulk_geo.scv_global_ips();
294 size_t numSCVip = bulk_geo.num_scv_ips();
295 m_imDensityCo.set_global_ips (vSCVip, numSCVip);
296 m_imViscosityCo.set_global_ips (vSCVip, numSCVip);
297 if(m_spVolStabData.valid())
298 m_imOldDensityCo.set_global_ips (vSCVip, numSCVip);
299
300 const MathVector<dim>* coe_global = bulk_geo.coe_global ();
301 m_imPorosity.set_global_ips (coe_global, 1);
302 m_imPermeability.set_global_ips (coe_global, 1);
303 m_imDiffusion.set_global_ips (coe_global, 1);
304 m_imThermalConductivity.set_global_ips (coe_global, 1);
305}
306
308template<typename TDomain>
309template<typename TElem>
311(
312 const LocalVector & u,
313 TElem * elem,
314 const position_type vCornerCoords []
315)
316{
317 typedef typename reference_element_traits<TElem>::reference_element_type ref_elem_type;
318 ref_elem_type& rRefElem = Provider<ref_elem_type>::get ();
319
320// get the non-degenerated sides of the fracture element
321 try
322 {
323 m_spFractManager->get_layer_sides
324 (elem,
325 m_numFractCo, m_innerFractSide, m_innerFractSideIdx, m_innerSideCo,
326 m_outerFractSide, m_outerFractSideIdx, m_outerSideCo,
327 m_assCo);
328 }
329 UG_CATCH_THROW("FractTHF_FV1: Cannot find orientation of a fracture element.");
330
331// compute the FV geometry of the inner side
332 MathVector<dim> vSideCornerCoords [maxFractSideCorners];
333 try
334 {
335 for (size_t co = 0; co < m_numFractCo; co++)
336 vSideCornerCoords [co] = vCornerCoords [m_innerSideCo [co]];
337 m_pFractGeo->update (m_innerFractSide, vSideCornerCoords, &(this->subset_handler()));
338 }
339 UG_CATCH_THROW("FractTHF_FV1: Cannot update the Finite Volume Geometry for a fracture element.");
340 size_t numSCVFip = m_pFractGeo->num_scvf_ips ();
341
342// convert local coordinates of the side into the local coordinates of the element (for the input parameters)
343 MathVector<dim> vSideLocCornerCoords [maxFractSideCorners];
344 try
345 {
347 = ReferenceMappingProvider::get<low_dim, dim> (m_innerFractSide->reference_object_id ());
348 for (size_t co = 0; co < m_numFractCo; co++)
349 vSideLocCornerCoords [co] = rRefElem.corner (m_innerSideCo [co]);
350 rMapping.update (vSideLocCornerCoords);
351
352 rMapping.local_to_global (m_elem_loc_coe, *(m_pFractGeo->coe_local ()));
353 rMapping.local_to_global (m_elem_loc_scvf, m_pFractGeo->scvf_local_ips (), numSCVFip);
354 }
355 UG_CATCH_THROW("FractTHF_FV1: Cannot transform local side coordinates to local element coordinates in a fracture element.");
356
357// set local IP coordinates
358 m_imDensityIP.template set_local_ips<dim> (m_elem_loc_scvf, numSCVFip);
359 m_imViscosityIP.template set_local_ips<dim> (m_elem_loc_scvf, numSCVFip);
360
361 m_imAperture.template set_local_ips<dim> (&m_elem_loc_coe, 1);
362 m_imPorosity.template set_local_ips<dim> (&m_elem_loc_coe, 1);
363 m_imFractPermeability.template set_local_ips<dim> (&m_elem_loc_coe, 1);
364 m_imOrthoPermeability.template set_local_ips<dim> (&m_elem_loc_coe, 1);
365 m_imFractDiffusion.template set_local_ips<dim> (&m_elem_loc_coe, 1);
366 m_imOrthoDiffusion.template set_local_ips<dim> (&m_elem_loc_coe, 1);
367 m_imFractThermCond.template set_local_ips<dim> (&m_elem_loc_coe, 1);
368 m_imOrthoThermCond.template set_local_ips<dim> (&m_elem_loc_coe, 1);
369
370// set global positions for user data
371 const MathVector<dim>* vSCVFip = m_pFractGeo->scvf_global_ips();
372 m_imDensityIP.set_global_ips (vSCVFip, numSCVFip);
373 m_imViscosityIP.set_global_ips (vSCVFip, numSCVFip);
374
375 const MathVector<dim>* coe_global = m_pFractGeo->coe_global ();
376 m_imAperture.set_global_ips (coe_global, 1);
377 m_imPorosity.set_global_ips (coe_global, 1);
378 m_imFractPermeability.set_global_ips (coe_global, 1);
379 m_imOrthoPermeability.set_global_ips (coe_global, 1);
380 m_imFractDiffusion.set_global_ips (coe_global, 1);
381 m_imOrthoDiffusion.set_global_ips (coe_global, 1);
382 m_imFractThermCond.set_global_ips (coe_global, 1);
383 m_imOrthoThermCond.set_global_ips (coe_global, 1);
384
385// set up global ip coordinates for corner import parameters
386// REMARK: Note that for the fracture elements, values of the corner import
387// parameters are indexed not by scv (as for the normal elements) but by
388// the corner indices in the reference element
389 m_imDensityCo.set_global_ips (vCornerCoords, ref_elem_type::numCorners);
390 m_imViscosityCo.set_global_ips (vCornerCoords, ref_elem_type::numCorners);
391 if(m_spVolStabData.valid())
392 m_imOldDensityCo.set_global_ips (vCornerCoords, ref_elem_type::numCorners);
393
394// set global and local positions for velocity import
395 m_imFractDarcyVelIP.template set_local_ips<dim> (m_elem_loc_scvf, numSCVFip);
396 m_imFractDarcyVelIP.set_global_ips(vSCVFip, numSCVFip);
397
398// compute the orthogonal gravity
399 MathVector<dim> outerNormal;
400 number outerNormalNorm;
401 SideNormal<ref_elem_type, dim> (outerNormal, m_outerFractSideIdx, vCornerCoords);
402 if ((outerNormalNorm = VecLength (outerNormal)) < 1e-32)
403 UG_THROW ("FractTHF_FV1: Cannot get the normal to a fracture.")
404 m_orthGravity = VecDot (m_Gravity, outerNormal) / outerNormalNorm;
405
406// init upwind for element type
407 if(! m_spUpwind->template set_geometry_type<TFractFVGeom>(*m_pFractGeo))
408 UG_THROW("FractTHF_FV1: Cannot init upwind for the transport for fracture element type.");
409// init upwind for element type
410 if(! m_spUpwindEnergy->template set_geometry_type<TFractFVGeom>(*m_pFractGeo))
411 UG_THROW("FractTHF_FV1: Cannot init upwind for the energy for fracture element type.");
412}
413
415template<typename TDomain>
416template<typename TFVGeom, typename TConsGravity>
418(
419 MathVector<dim>& Vel,
420 size_t ip,
421 const TFVGeom& geo,
422 TConsGravity& ConsGravityMethod,
423 MathVector<TFVGeom::dim> vConsGravity[],
424 number vPressure[],
426)
427{
428 const typename TFVGeom::SCVF& scvf = geo.scvf(ip);
429
430// Compute rho * g (as the consistent gravity force)
431 ConsGravityMethod.template compute<dim>
432 (Vel, scvf.local_ip(), scvf.JTInv(), scvf.local_grad_vector(), vConsGravity);
433
434// The pressure-gradient part:
435 for (size_t sh = 0; sh < scvf.num_sh(); sh++)
436 VecScaleAppend (Vel, - vPressure[sh], scvf.global_grad(sh));
437
438// The viscosity factor:
439 VecScale (Vel, Vel, 1 / Viscosity);
440}
441
443template<typename TDomain>
444template<typename TElem>
446(
447 LocalVector & d,
448 const LocalVector & u,
449 GridObject * elem,
450 const position_type vCornerCoords []
451)
452{
453 TElem * pElem = static_cast<TElem*> (elem);
454
455// call the specific routine:
456 if (! m_isFracture)
457 {
458 this->template bulk_ass_dA_elem<TElem> (d, u, pElem, vCornerCoords);
459 }
460 else
461 {
462 this->template fract_ass_dA_elem<TElem> (d, u, pElem, vCornerCoords);
463 this->template fract_bulk_ass_dA_elem<TElem> (d, u, pElem, vCornerCoords);
464 }
465}
466
468template<typename TDomain>
469template<typename TElem>
471(
472 LocalVector & d,
473 const LocalVector & u,
474 TElem * pElem,
475 const position_type vCornerCoords []
476)
477{
478 typedef typename reference_element_traits<TElem>::reference_element_type ref_elem_type;
479 typedef FV1Geometry<TElem, dim> TBulkFVGeom;
481
482 MathMatrix<dim,dim> Diffusion[TBulkFVGeom::numSCVF];
483 MathMatrix<dim,dim> ThermCond[TBulkFVGeom::numSCVF];
484 MathVector<dim> Dgrad_c_ip, Dgrad_T_ip;
485 MathVector<dim> grad_c_ip, grad_T_ip;
486 MathVector<dim> Vel[TBulkFVGeom::numSCVF], DarcyVel[TBulkFVGeom::numSCVF];
487
488// Get finite volume geometry
489 const TBulkFVGeom& bulk_geo = GeomProvider<TBulkFVGeom>::get();
490
491 const size_t numSh = bulk_geo.num_sh();
492 const size_t numScvf = bulk_geo.num_scvf();
493
494// Consistent gravity and its derivative at corners
495 TConsGravity ConsGravityMethod;
496 MathVector<ref_elem_type::dim> vConsGravity [ref_elem_type::numCorners];
497
498// Prepare the consistent gravity
499 try
500 {
501 ConsGravityMethod.template prepare<dim>
502 (vConsGravity, numSh, vCornerCoords, m_imDensityCo.values(), m_Gravity);
503 }
504 UG_CATCH_THROW ("FractTHF_FV1::bulk_ass_dA_elem: Cannot prepare Consistent Gravity.");
505
506// Get the corner pressure
507 number vPressure [ref_elem_type::numCorners];
508 for (size_t sh = 0; sh < numSh; sh++)
509 vPressure[sh] = u(_P_, sh);
510
511// Compute Diffusion - Dispersion
512 MatScale(Diffusion[0], m_imPorosity[0], m_imDiffusion[0]);
513 for (size_t ip = 1; ip < numScvf; ip++)
514 Diffusion[ip] = Diffusion[0];
515 //TODO add Dispersion
516
517// Compute the thermal conductivity
518 ThermCond[0] = m_imThermalConductivity[0];
519 for (size_t ip = 1; ip < numScvf; ip++)
520 ThermCond[ip] = ThermCond[0];
521
522// Compute the Darcy velocity at the ips and the convection shapes
523 for (size_t ip = 0; ip < numScvf; ip++)
524 {
525 this->template compute_ip_Darcy_velocity<TBulkFVGeom, TConsGravity>
526 (Vel[ip], ip, bulk_geo, ConsGravityMethod, vConsGravity, vPressure,
527 m_imViscosityIP[ip]);
528 MatVecMult (DarcyVel[ip], m_imPermeability[0], Vel[ip]);
529 }
530
531// compute upwind shapes for transport equation
532 if(!m_spUpwind->update(&bulk_geo, DarcyVel, Diffusion, false))
533 UG_THROW("FractTHF_FV1::bulk_ass_dA_elem: Cannot compute convection shapes for the transport equation.");
534
535// compute upwind shapes for transport equation
536 if(!m_spUpwindEnergy->update(&bulk_geo, DarcyVel, ThermCond, false))
537 UG_THROW("FractTHF_FV1::bulk_ass_dA_elem: Cannot compute convection shapes for the energy equation.");
538
539// get a const (!!) reference to the upwind
540 const IConvectionShapes<dim>& convShape
541 = *const_cast<const IConvectionShapes<dim>*>(m_spUpwind.get());
542
543// get a const (!!) reference to the upwind
544 const IConvectionShapes<dim>& convShapeT
545 = *const_cast<const IConvectionShapes<dim>*>(m_spUpwindEnergy.get());
546
547 for (size_t ip = 0; ip < numScvf; ip++)
548 {
549 // Get current SCVF
550 const typename TBulkFVGeom::SCVF& scvf = bulk_geo.scvf(ip);
551
552 // The the gradient of c and T at the ip:
553 VecSet (grad_c_ip, 0.0); VecSet (grad_T_ip, 0.0);
554 for (size_t sh = 0; sh < scvf.num_sh(); sh++)
555 {
556 VecScaleAppend (grad_c_ip, u(_C_, sh), scvf.global_grad(sh));
557 VecScaleAppend (grad_T_ip, u(_T_, sh), scvf.global_grad(sh));
558 }
559
561 // Transport Equation
563
564 number flux = 0;
565
566 // Compute Convective Flux
567 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
568 flux += convShape(ip, sh) * u(_C_, sh);
569
570 // Compute Diffusive Flux
571 MatVecMult(Dgrad_c_ip, Diffusion[ip], grad_c_ip);
572 const number diffFlux = VecDot(Dgrad_c_ip, scvf.normal());
573
574 // Sum total flux
575 flux -= diffFlux;
576 if(!m_BoussinesqTransport) flux *= m_imDensityIP[ip];
577
578 // Add contribution to transport equation
579 d(_C_,scvf.from()) += flux;
580 d(_C_,scvf.to()) -= flux;
581
583 // Flow Equation
585
586 // Compute flux
587 flux = VecDot(DarcyVel[ip], scvf.normal());
588 if(!m_BoussinesqFlow) flux *= m_imDensityIP[ip];
589
590 // Add contribution to flow equation
591 d(_P_,scvf.from()) += flux;
592 d(_P_,scvf.to()) -= flux;
593
594 // Volume stabilization: Add the continuity equation to the transport equation
595 if(m_bVolStabDataActive)
596 {
597 m_spVolStabData->stiff(pElem->vertex(scvf.from())) -= flux;
598 m_spVolStabData->stiff(pElem->vertex(scvf.to())) += flux;
599 }
600
602 // Energy Equation
604
605 // Compute Convective Flux
606 flux = 0;
607 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
608 flux += convShapeT(ip, sh) * u(_T_, sh);
609 flux *= m_imHeatCapacityFluid;
610
611 if(m_BoussinesqEnergy) flux *= m_BoussinesqDensity;
612 else flux *= m_imDensityIP[ip];
613
614 // Compute Diffusive Flux
615 MatVecMult(Dgrad_T_ip, ThermCond[ip], grad_T_ip);
616 const number thermDiffFlux = VecDot(Dgrad_T_ip, scvf.normal());
617
618 // Sum total flux
619 flux -= thermDiffFlux;
620
621 // Add contribution to transport equation
622 d(_T_,scvf.from()) += flux;
623 d(_T_,scvf.to()) -= flux;
624 }
625
626// Assemble the singular sources and sinks
627 if (m_sss_mngr.valid () && (m_sss_mngr->num_points () != 0 || m_sss_mngr->num_lines () != 0))
628 {
629 typedef typename domain_type::position_accessor_type t_pos_accessor;
631 point_iterator<TElem,t_pos_accessor,TBulkFVGeom> t_pnt_sss_iter;
633 line_iterator<TElem,t_pos_accessor,TBulkFVGeom> t_lin_sss_iter;
634
635 t_pos_accessor& aaPos = this->domain()->position_accessor ();
636 Grid& grid = (Grid&) *this->domain()->grid ();
637
638 for(size_t ip = 0; ip < bulk_geo.num_scv(); ip++)
639 {
640 size_t co = bulk_geo.scv(ip).node_id ();
641
642 // point sources
643 for (t_pnt_sss_iter pnt (m_sss_mngr.get (), pElem, grid, aaPos, bulk_geo, co);
644 ! pnt.is_over (); ++pnt)
645 {
647 if (! pnt_sss->marked_for (pElem, co))
648 continue;
649 pnt_sss->compute (pnt_sss->position (), this->time (), -1); //TODO: set the subset id instead of -1
650 ass_sss_dA_elem (d, u, pElem, co, pnt_sss->intensity (), pnt_sss->concentration (), pnt_sss->temperature ());
651 }
652
653 // line sources
654 for (t_lin_sss_iter line (m_sss_mngr.get (), pElem, grid, aaPos, bulk_geo, co);
655 ! line.is_over (); ++line)
656 {
658 number len = VecDistance (line.seg_start (), line.seg_end ());
659 line_sss->compute (line.seg_start (), this->time (), -1); //TODO: set the subset id instead of -1
660 ass_sss_dA_elem (d, u, pElem, co, line_sss->intensity (), line_sss->concentration (), line_sss->temperature (), len);
661 }
662 }
663 }
664}
665
667template<typename TDomain>
668template<typename TElem>
670(
671 LocalVector & d,
672 const LocalVector & u,
673 TElem * pElem,
674 const position_type vCornerCoords []
675)
676{
677 const number half_fr_width = m_imAperture[0] / 2;
678
679 MathMatrix<dim,dim> Diffusion[TFractFVGeom::maxNumSCVF];
680 MathMatrix<dim,dim> ThermCond[TFractFVGeom::maxNumSCVF];
681 MathVector<dim> Dgrad_c_ip, Dgrad_T_ip;
682 MathVector<dim> grad_c_ip, grad_T_ip;
683
684 const size_t numSh = m_pFractGeo->num_sh();
685 const size_t numScvf = m_pFractGeo->num_scvf();
686
687// Get the corner values
688 number vConcentration [maxFractSideCorners];
689 number vTemperature [maxFractSideCorners];
690 for (size_t sh = 0; sh < numSh; sh++)
691 {
692 size_t co = m_innerSideCo[sh];
693 vConcentration[sh] = u(_C_, co);
694 vTemperature[sh] = u(_T_, co);
695 }
696
697// Compute Diffusion - Dispersion
698 MatSet (Diffusion[0], 0);
699 MatDiagSet (Diffusion[0], m_imPorosity[0] * m_imFractDiffusion[0]);
700 for (size_t ip = 1; ip < numScvf; ip++)
701 Diffusion[ip] = Diffusion[0];
702 //TODO add Dispersion
703
704// Compute the thermal conductivity
705 MatSet (ThermCond[0], 0);
706 MatDiagSet (ThermCond[0], m_imFractThermCond[0]);
707 for (size_t ip = 1; ip < numScvf; ip++)
708 ThermCond[ip] = ThermCond[0];
709
710// compute upwind shapes for transport equation
711 if(!m_spUpwind->update(m_pFractGeo, m_imFractDarcyVelIP.values(), Diffusion, false))
712 UG_THROW("FractTHF_FV1::fract_ass_dA_elem: Cannot compute convection shapes for the transport equation.");
713
714 const IConvectionShapes<dim>& convShape
715 = *const_cast<const IConvectionShapes<dim>*>(m_spUpwind.get());
716
717// compute upwind shapes for energy equation
718 if(!m_spUpwindEnergy->update(m_pFractGeo, m_imFractDarcyVelIP.values(), ThermCond, false))
719 UG_THROW("FractTHF_FV1::fract_ass_dA_elem: Cannot compute convection shapes for the energy equation.");
720
721 const IConvectionShapes<dim>& convShapeT
722 = *const_cast<const IConvectionShapes<dim>*>(m_spUpwindEnergy.get());
723
724// Loop Sub Control Volume Faces (SCVF)
725 for (size_t ip = 0; ip < numScvf; ip++)
726 {
727 // Get current SCVF
728 const typename TFractFVGeom::SCVF& scvf = m_pFractGeo->scvf(ip);
729
730 // The ip-concentration and the gradient of c at the ip:
731 VecSet (grad_c_ip, 0.0); VecSet (grad_T_ip, 0.0);
732 for (size_t sh = 0; sh < scvf.num_sh(); sh++)
733 {
734 VecScaleAppend (grad_c_ip, vConcentration[sh], scvf.global_grad(sh));
735 VecScaleAppend (grad_T_ip, vTemperature[sh], scvf.global_grad(sh));
736 }
737
739 // Transport Equation
741
742 number flux = 0;
743
744 // Compute Convective Flux
745 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
746 flux += convShape(ip, sh) * vConcentration[sh];
747
748 // Compute Diffusive Flux
749 MatVecMult(Dgrad_c_ip, Diffusion[ip], grad_c_ip);
750 const number diffFlux = VecDot(Dgrad_c_ip, scvf.normal());
751
752 // Sum total flux
753 flux = (flux - diffFlux) * half_fr_width;
754 if(!m_BoussinesqTransport) flux *= m_imDensityIP[ip];
755
756 // Add contribution to transport equation
757 d(_C_, m_innerSideCo[scvf.from()]) += flux;
758 d(_C_, m_innerSideCo[scvf.to()]) -= flux;
759
761 // Flow Equation
763
764 // Compute flux
765 flux = VecDot(m_imFractDarcyVelIP[ip], scvf.normal()) * half_fr_width;
766
767 if(!m_BoussinesqFlow) flux *= m_imDensityIP[ip];
768
769 // Add contribution to flow equation
770 d(_P_, m_innerSideCo[scvf.from()]) += flux;
771 d(_P_, m_innerSideCo[scvf.to()]) -= flux;
772
773 // Volume stabilization: Add the continuity equation to the transport equation
774 if(m_bVolStabDataActive)
775 {
776 m_spVolStabData->stiff(pElem->vertex(m_innerSideCo[scvf.from()])) -= flux;
777 m_spVolStabData->stiff(pElem->vertex(m_innerSideCo[scvf.to()])) += flux;
778 }
779
781 // Energy Equation
783
784 // Compute Convective Flux
785 flux = 0;
786 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
787 flux += convShapeT(ip, sh) * vTemperature[sh];
788 flux *= m_imHeatCapacityFluid;
789
790 if(m_BoussinesqEnergy) flux *= m_BoussinesqDensity;
791 else flux *= m_imDensityIP[ip];
792
793 // Compute Diffusive Flux
794 MatVecMult(Dgrad_T_ip, ThermCond[ip], grad_T_ip);
795 const number thermDiffFlux = VecDot(Dgrad_T_ip, scvf.normal());
796
797 // Sum total flux
798 flux = (flux - thermDiffFlux) * half_fr_width;
799
800 // Add contribution to transport equation
801 d(_T_, m_innerSideCo[scvf.from()]) += flux;
802 d(_T_, m_innerSideCo[scvf.to()]) -= flux;
803 }
804
805// Assemble the singular sources and sinks
806 if (m_sss_mngr.valid () && m_sss_mngr->num_lines () != 0)
807 {
808 typedef typename domain_type::position_accessor_type t_pos_accessor;
810 line_iterator<side_type,t_pos_accessor,TFractFVGeom> t_lin_sss_iter;
811
812 t_pos_accessor& aaPos = this->domain()->position_accessor ();
813 Grid& grid = (Grid&) *this->domain()->grid ();
814
815 for(size_t ip = 0; ip < m_pFractGeo->num_scv(); ip++)
816 {
817 // Get the corner of the face
818 size_t side_co = m_pFractGeo->scv(ip).node_id ();
819 // Get associated node of the element (not side!)
820 size_t co = m_innerSideCo [m_pFractGeo->scv(ip).node_id ()];
821
822 // line sources (that correspond to the point sources)
823 for (t_lin_sss_iter line (m_sss_mngr.get (), m_innerFractSide, grid, aaPos, *m_pFractGeo, side_co);
824 ! line.is_over (); ++line)
825 {
827 if (! line_sss->marked_for (m_innerFractSide, side_co))
828 continue;
829 line_sss->compute (line.seg_start (), this->time (), -1); //TODO: set the subset id instead of -1
830 ass_sss_dA_elem (d, u, pElem, co, line_sss->intensity (), line_sss->concentration (), line_sss->temperature (), 0.5);
831 /* Remark: "0.5" because the source is taken into account twise. */
832 }
833 }
834 }
835}
836
838template<typename TDomain>
839template<typename TElem>
841(
842 LocalVector & d,
843 const LocalVector & u,
844 TElem * pElem,
845 const position_type vCornerCoords []
846)
847{
848 const number orthDiffusion = m_imPorosity[0] * m_imOrthoDiffusion[0];
849
850 const number half_fr_width = m_imAperture[0] / 2;
851
852// loop over the corners of the inner side
853 for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ip++)
854 {
855 // Get current SCV
856 const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv(ip);
857
858 // Get associated node of the element (not side!)
859 const int co = m_innerSideCo [scv.node_id()];
860
861 // Get the corner values
862 const number orthC_f = u(_C_, co);
863 const number orthC_m = u(_C_, m_assCo[co]);
864 const number orthP_f = u(_P_, co);
865 const number orthP_m = u(_P_, m_assCo[co]);
866 const number orthT_f = u(_T_, co);
867 const number orthT_m = u(_T_, m_assCo[co]);
868 const number fractDensity = m_imDensityCo[co];
869 const number orthDensity = m_imDensityCo [m_assCo[co]];
870 const number orthViscosity = m_imViscosityCo [m_assCo[co]];
871
872 // Flux velocity between the fracture and the bulk medium
873 const number orthVelocity = (m_orthGravity * (orthDensity - fractDensity)
874 - (orthP_m - orthP_f) / half_fr_width)
875 * m_imOrthoPermeability[0] / orthViscosity;
876
878 number flux;
879
881 // Transport Equation
883
884 flux = orthDiffusion * (orthC_m - orthC_f) / half_fr_width;
885 /* We use the full upwind here: */
886 flux -= orthVelocity * ((orthVelocity >= 0)? orthC_f : orthC_m);
887 flux *= scv.volume();
888 if (! m_BoussinesqTransport) flux *= orthDensity;
889 d(_C_, m_assCo[co]) += flux;
890 d(_C_, co) -= flux;
891
893 // Flow Equation
895
896 flux = orthVelocity * scv.volume();
897 if (! m_BoussinesqFlow) flux *= orthDensity;
898 d(_P_, m_assCo[co]) -= flux;
899 d(_P_, co) += flux;
900
901 // Volume stabilization: Add the continuity equation to the transport equation
902 if(m_bVolStabDataActive)
903 {
904 m_spVolStabData->stiff(pElem->vertex(m_assCo[co])) += flux;
905 m_spVolStabData->stiff(pElem->vertex(co)) -= flux;
906 }
907
909 // Energy Equation
911
912 /* We use the full upwind here: */
913 flux = - orthVelocity * ((orthVelocity >= 0)? orthT_f : orthT_m)
914 * m_imHeatCapacityFluid
915 * (m_BoussinesqEnergy? m_BoussinesqDensity : orthDensity);
916 flux += m_imOrthoThermCond[0] * (orthT_m - orthT_f) / half_fr_width;
917 flux *= scv.volume();
918 d(_T_, m_assCo[co]) += flux;
919 d(_T_, co) -= flux;
920 }
921}
922
924template<typename TDomain>
925template<typename TFVGeom, typename TConsGravity, size_t maxCorners>
927(
928 MathVector<dim>& Vel,
929 MathVector<dim> Vel_c[],
930 MathVector<dim> Vel_p[],
931 MathVector<dim> Vel_T[],
932 size_t ip,
933 const TFVGeom& geo,
934 TConsGravity& ConsGravityMethod,
935 MathVector<TFVGeom::dim> vConsGravity_c[][maxCorners],
936 MathVector<TFVGeom::dim> vConsGravity_T[][maxCorners],
937 number vPressure[],
939 number Viscosity_c[],
940 number Viscosity_T[]
941)
942{
943 const typename TFVGeom::SCVF& scvf = geo.scvf(ip);
944 const number InvVisco = 1 / Viscosity;
945 const size_t numSh = geo.num_sh();
946
947// Compute the derivatives of rho g - grad p, multiplied by the viscosity
948 for (size_t sh = 0; sh < numSh; sh++)
949 {
950 ConsGravityMethod.template compute<dim>
951 (Vel_c[sh], scvf.local_ip(), scvf.JTInv(), scvf.local_grad_vector(),
952 vConsGravity_c[sh]);
953 VecScale (Vel_c[sh], Vel_c[sh], InvVisco);
954
955 ConsGravityMethod.template compute<dim>
956 (Vel_T[sh], scvf.local_ip(), scvf.JTInv(), scvf.local_grad_vector(),
957 vConsGravity_T[sh]);
958 VecScale (Vel_T[sh], Vel_T[sh], InvVisco);
959
960 VecScale (Vel_p[sh], scvf.global_grad(sh), -InvVisco);
961 }
962
963// Take into account the derivative of the viscosity wrt c
964 if (Viscosity_c != NULL)
965 for (size_t sh = 0; sh < numSh; sh++)
966 VecScaleAppend (Vel_c[sh], -Viscosity_c[sh] * InvVisco, Vel);
967
968// Take into account the derivative of the viscosity wrt T
969 if (Viscosity_T != NULL)
970 for (size_t sh = 0; sh < numSh; sh++)
971 VecScaleAppend (Vel_T[sh], -Viscosity_T[sh] * InvVisco, Vel);
972}
973
975template<typename TDomain>
976template<typename TElem>
978(
979 LocalMatrix & J,
980 const LocalVector & u,
981 GridObject * elem,
982 const position_type vCornerCoords []
983)
984{
985 TElem * pElem = static_cast<TElem*> (elem);
986
987// call the specific routine:
988 if (! m_isFracture)
989 this->template bulk_ass_JA_elem<TElem> (J, u, pElem, vCornerCoords);
990 else
991 {
992 this->template fract_ass_JA_elem<TElem> (J, u, pElem, vCornerCoords);
993 this->template fract_bulk_ass_JA_elem<TElem> (J, u, pElem, vCornerCoords);
994 }
995}
996
998template<typename TDomain>
999template<typename TElem>
1001(
1002 LocalMatrix & J,
1003 const LocalVector & u,
1004 TElem * pElem,
1005 const position_type vCornerCoords []
1006)
1007{
1008 typedef typename reference_element_traits<TElem>::reference_element_type ref_elem_type;
1009 typedef FV1Geometry<TElem, dim> TBulkFVGeom;
1011 static const size_t numCorners = ref_elem_type::numCorners;
1012
1013 // Get finite volume geometry
1014 const TBulkFVGeom& bulk_geo = GeomProvider<TBulkFVGeom>::get();
1015
1016 const size_t numSh = bulk_geo.num_sh();
1017 const size_t numScvf = bulk_geo.num_scvf();
1018
1019 MathMatrix<dim,dim> Diffusion[TBulkFVGeom::numSCVF];
1020 MathMatrix<dim,dim> ThermCond[TBulkFVGeom::numSCVF];
1021 MathVector<dim> Dgrad;
1022 MathVector<dim> Vel[TBulkFVGeom::numSCVF], DarcyVel[TBulkFVGeom::numSCVF];
1023 MathVector<dim> Vel_c[numCorners], Vel_p[numCorners], Vel_T[numCorners];
1024 MathVector<dim> vDDarcyVel_c[numCorners], vDDarcyVel_p[numCorners], vDDarcyVel_T[numCorners];
1025 MathVector<dim> grad_c_ip, grad_T_ip;
1026 number vDFlux_c [numCorners], vDFlux_p [numCorners], vDFlux_T [numCorners];
1027 number vViscosity_c [numCorners], * pViscosity_c;
1028 number vViscosity_T [numCorners], * pViscosity_T;
1029
1030// Consistent gravity and its derivative at corners
1031 TConsGravity ConsGravityMethod;
1032 MathVector<ref_elem_type::dim> vConsGravity [numCorners];
1033 MathVector<ref_elem_type::dim> vConsGravity_c [numCorners][numCorners];
1034 MathVector<ref_elem_type::dim> vConsGravity_T [numCorners][numCorners];
1035
1036// Prepare the consistent gravity
1037 try
1038 {
1039 ConsGravityMethod.template prepare<dim>
1040 (vConsGravity, numSh, vCornerCoords, m_imDensityCo.values(), m_Gravity);
1041
1042 number co_density [numCorners];
1043 memset (co_density, 0, ref_elem_type::numCorners * sizeof (number));
1044 for (size_t sh = 0; sh < numSh; sh++)
1045 { //TODO: use scv, not merely shape id here!
1046 co_density[sh] = m_imDensityCo.deriv (sh, _C_, sh); // we assume the completely local dependence of \f$\rho\f$ of \f$c\f$
1047 ConsGravityMethod.template prepare<dim>
1048 (vConsGravity_c[sh], numSh, vCornerCoords, co_density, m_Gravity);
1049 co_density[sh] = 0.0;
1050 }
1051 for (size_t sh = 0; sh < numSh; sh++)
1052 { //TODO: use scv, not merely shape id here!
1053 co_density[sh] = m_imDensityCo.deriv (sh, _T_, sh); // we assume the completely local dependence of \f$\rho\f$ of \f$T\f$
1054 ConsGravityMethod.template prepare<dim>
1055 (vConsGravity_T[sh], numSh, vCornerCoords, co_density, m_Gravity);
1056 co_density[sh] = 0.0;
1057 }
1058 }
1059 UG_CATCH_THROW ("FractTHF_FV1::bulk_ass_JA_elem: Cannot prepare Consistent Gravity or its derivatives.");
1060
1061// Get the corner pressure
1062 number vPressure [numCorners];
1063 for (size_t sh = 0; sh < numSh; sh++)
1064 vPressure[sh] = u(_P_, sh);
1065
1066// Compute Diffusion - Dispersion
1067 MatScale(Diffusion[0], m_imPorosity[0], m_imDiffusion[0]);
1068 for (size_t ip = 1; ip < numScvf; ip++)
1069 Diffusion[ip] = Diffusion[0];
1070 //TODO add Dispersion
1071
1072// Compute the thermal conductivity
1073 ThermCond[0] = m_imThermalConductivity[0];
1074 for (size_t ip = 1; ip < numScvf; ip++)
1075 ThermCond[ip] = ThermCond[0];
1076
1077// Compute the Darcy velocity at the ips and the convection shapes
1078 for (size_t ip = 0; ip < numScvf; ip++)
1079 {
1080 this->template compute_ip_Darcy_velocity<TBulkFVGeom, TConsGravity>
1081 (Vel[ip], ip, bulk_geo, ConsGravityMethod, vConsGravity, vPressure,
1082 m_imViscosityIP[ip]);
1083 MatVecMult (DarcyVel[ip], m_imPermeability[0], Vel[ip]);
1084 }
1085
1086// compute upwind shapes for transport equation
1087 if(!m_spUpwind->update(&bulk_geo, DarcyVel, Diffusion, true))
1088 UG_THROW("FractTHF_FV1::bulk_ass_dA_elem: Cannot compute convection shapes for the transport equation.");
1089
1090// compute upwind shapes for transport equation
1091 if(!m_spUpwindEnergy->update(&bulk_geo, DarcyVel, ThermCond, true))
1092 UG_THROW("FractTHF_FV1::bulk_ass_dA_elem: Cannot compute convection shapes for the energy equation.");
1093
1094// get a const (!!) reference to the upwind
1095 const IConvectionShapes<dim>& convShape
1096 = *const_cast<const IConvectionShapes<dim>*>(m_spUpwind.get());
1097
1098// get a const (!!) reference to the upwind
1099 const IConvectionShapes<dim>& convShapeT
1100 = *const_cast<const IConvectionShapes<dim>*>(m_spUpwindEnergy.get());
1101
1102// Loop Sub Control Volume Faces (SCVF)
1103 for (size_t ip = 0; ip < numScvf; ip++)
1104 {
1105 // Get current SCVF
1106 const typename TBulkFVGeom::SCVF& scvf = bulk_geo.scvf(ip);
1107
1108 // The ip-concentration and the gradient of c at the ip:
1109 VecSet (grad_c_ip, 0.0); VecSet (grad_T_ip, 0.0);
1110 for (size_t sh = 0; sh < scvf.num_sh(); sh++)
1111 {
1112 VecScaleAppend (grad_c_ip, u(_C_, sh), scvf.global_grad(sh));
1113 VecScaleAppend (grad_T_ip, u(_T_, sh), scvf.global_grad(sh));
1114 }
1115
1116 // Compute the derivative of the viscosity
1117 if (m_imViscosityIP.constant ())
1118 {
1119 pViscosity_c = NULL;
1120 pViscosity_T = NULL;
1121 }
1122 else
1123 {
1124 for (size_t sh = 0; sh < numSh; sh++)
1125 {
1126 vViscosity_c[sh] = m_imViscosityIP.deriv(ip, _C_, sh);
1127 vViscosity_T[sh] = m_imViscosityIP.deriv(ip, _T_, sh);
1128 }
1129 pViscosity_c = vViscosity_c;
1130 pViscosity_T = vViscosity_T;
1131 }
1132
1133 // Compute derivatives of the Darcy velocity
1134 this->template compute_J_ip_Darcy_velocity <TBulkFVGeom, TConsGravity, numCorners>
1135 (Vel[ip], Vel_c, Vel_p, Vel_T, ip, bulk_geo, ConsGravityMethod,
1136 vConsGravity_c, vConsGravity_T, vPressure,
1137 m_imViscosityIP[ip], pViscosity_c, pViscosity_T);
1138 for (size_t sh = 0; sh < numSh; sh++)
1139 {
1140 MatVecMult (vDDarcyVel_c[sh], m_imPermeability[0], Vel_c[sh]);
1141 MatVecMult (vDDarcyVel_p[sh], m_imPermeability[0], Vel_p[sh]);
1142 MatVecMult (vDDarcyVel_T[sh], m_imPermeability[0], Vel_T[sh]);
1143 }
1144
1146 // Transport Equation
1148
1149 // Loop Shape Functions
1150 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1151 {
1152 // Compute Derivative of Convective Flux
1153 vDFlux_c[sh] = convShape(ip, sh);
1154 vDFlux_p[sh] = 0.0;
1155 vDFlux_T[sh] = 0.0;
1156
1157 // Derivative w.r.t. Velocity
1158 for(size_t sh1 = 0; sh1 < scvf.num_sh(); ++sh1)
1159 {
1160 vDFlux_c[sh] += u(_C_, sh1) * VecDot(convShape.D_vel(ip, sh1), vDDarcyVel_c[sh]);
1161 vDFlux_p[sh] += u(_C_, sh1) * VecDot(convShape.D_vel(ip, sh1), vDDarcyVel_p[sh]);
1162 vDFlux_T[sh] += u(_C_, sh1) * VecDot(convShape.D_vel(ip, sh1), vDDarcyVel_T[sh]);
1163 }
1164
1165 //TODO: add derivative of Dispersion
1166
1167 // Add Derivative of Diffusive Flux
1168 MatVecMult(Dgrad, Diffusion[ip], scvf.global_grad(sh));
1169 vDFlux_c[sh] -= VecDot(Dgrad, scvf.normal());
1170 }
1171
1172 // Handle density in case of full equation
1173 if(!m_BoussinesqTransport)
1174 {
1175 // Convective Flux
1176 number flux = 0;
1177 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1178 flux += convShape(ip, sh) * u(_C_, sh);
1179
1180 // Diffusive Flux
1181 MatVecMult(Dgrad, Diffusion[ip], grad_c_ip);
1182 flux -= VecDot(Dgrad, scvf.normal());
1183
1184 // Derivative of product
1185 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1186 {
1187 vDFlux_c[sh] = m_imDensityIP[ip] * vDFlux_c[sh] +
1188 m_imDensityIP.deriv(ip, _C_, sh) * flux;
1189 vDFlux_p[sh] *= m_imDensityIP[ip];
1190 vDFlux_T[sh] = m_imDensityIP[ip] * vDFlux_T[sh] +
1191 m_imDensityIP.deriv(ip, _T_, sh) * flux;
1192 }
1193 }
1194
1195 // Add Flux contribution
1196 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1197 {
1198 J(_C_, scvf.from(), _C_, sh) += vDFlux_c[sh];
1199 J(_C_, scvf.to(), _C_, sh) -= vDFlux_c[sh];
1200 J(_C_, scvf.from(), _P_, sh) += vDFlux_p[sh];
1201 J(_C_, scvf.to(), _P_, sh) -= vDFlux_p[sh];
1202 J(_C_, scvf.from(), _T_, sh) += vDFlux_T[sh];
1203 J(_C_, scvf.to(), _T_, sh) -= vDFlux_T[sh];
1204 }
1205
1206
1208 // Flow Equation
1210
1211 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1212 {
1213 vDFlux_c[sh] = VecDot(vDDarcyVel_c[sh], scvf.normal());
1214 vDFlux_p[sh] = VecDot(vDDarcyVel_p[sh], scvf.normal());
1215 vDFlux_T[sh] = VecDot(vDDarcyVel_T[sh], scvf.normal());
1216 }
1217
1218 number flux = VecDot(DarcyVel[ip], scvf.normal());
1219
1220 if(!m_BoussinesqFlow)
1221 {
1222 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1223 {
1224 vDFlux_c[sh] = m_imDensityIP[ip] * vDFlux_c[sh] +
1225 m_imDensityIP.deriv(ip, _C_, sh) * flux;
1226 vDFlux_p[sh] *= m_imDensityIP[ip];
1227 vDFlux_T[sh] = m_imDensityIP[ip] * vDFlux_T[sh] +
1228 m_imDensityIP.deriv(ip, _T_, sh) * flux;
1229 }
1230
1231 flux *= m_imDensityIP[ip];
1232 }
1233
1234 // Add Flux contribution
1235 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1236 {
1237 J(_P_, scvf.from(), _C_, sh) += vDFlux_c[sh];
1238 J(_P_, scvf.to(), _C_, sh) -= vDFlux_c[sh];
1239 J(_P_, scvf.from(), _P_, sh) += vDFlux_p[sh];
1240 J(_P_, scvf.to(), _P_, sh) -= vDFlux_p[sh];
1241 J(_P_, scvf.from(), _T_, sh) += vDFlux_T[sh];
1242 J(_P_, scvf.to(), _T_, sh) -= vDFlux_T[sh];
1243 }
1244
1245 // Volume stabilization: Add the continuity equation to the transport equation
1246 // REMARK: We do not compute derivatives of the defect of the conf. eq. here because this defect tends to 0.
1247 if(m_bVolStabDataActive)
1248 {
1249 m_spVolStabData->stiff(pElem->vertex(scvf.from())) -= flux;
1250 m_spVolStabData->stiff(pElem->vertex(scvf.to())) += flux;
1251 }
1252
1253
1255 // Energy Equation
1257
1258 // Loop Shape Functions
1259 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1260 {
1261 // Compute Derivative of Convective Flux
1262 vDFlux_c[sh] = 0.0;
1263 vDFlux_p[sh] = 0.0;
1264 vDFlux_T[sh] = convShape(ip, sh);
1265
1266 // Derivative w.r.t. Velocity
1267 for(size_t sh1 = 0; sh1 < scvf.num_sh(); ++sh1)
1268 {
1269 vDFlux_c[sh] += u(_T_, sh1) * VecDot(convShapeT.D_vel(ip, sh1), vDDarcyVel_c[sh]);
1270 vDFlux_p[sh] += u(_T_, sh1) * VecDot(convShapeT.D_vel(ip, sh1), vDDarcyVel_p[sh]);
1271 vDFlux_T[sh] += u(_T_, sh1) * VecDot(convShapeT.D_vel(ip, sh1), vDDarcyVel_T[sh]);
1272 }
1273
1274 vDFlux_c[sh] *= m_imHeatCapacityFluid;
1275 vDFlux_p[sh] *= m_imHeatCapacityFluid;
1276 vDFlux_T[sh] *= m_imHeatCapacityFluid;
1277 }
1278
1279 // Handle density in case of full equation
1280 if(!m_BoussinesqEnergy)
1281 {
1282 // Convective Flux
1283 number flux = 0;
1284 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1285 flux += convShapeT(ip, sh) * u(_T_, sh);
1286 flux *= m_imHeatCapacityFluid;
1287
1288 // Derivative of product
1289 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1290 {
1291 vDFlux_c[sh] = m_imDensityIP[ip] * vDFlux_c[sh] +
1292 m_imDensityIP.deriv(ip, _C_, sh) * flux;
1293 vDFlux_p[sh] *= m_imDensityIP[ip];
1294 vDFlux_T[sh] = m_imDensityIP[ip] * vDFlux_T[sh] +
1295 m_imDensityIP.deriv(ip, _T_, sh) * flux;
1296 }
1297 }
1298 else
1299 {
1300 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1301 {
1302 vDFlux_c[sh] *= m_BoussinesqDensity;
1303 vDFlux_p[sh] *= m_BoussinesqDensity;
1304 vDFlux_T[sh] *= m_BoussinesqDensity;
1305 }
1306 }
1307
1308 // Loop Shape Functions
1309 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1310 {
1311 // Add Derivative of Diffusive Flux
1312 MatVecMult(Dgrad, ThermCond[ip], scvf.global_grad(sh));
1313 vDFlux_T[sh] -= VecDot(Dgrad, scvf.normal());
1314 }
1315
1316 // Add Flux contribution
1317 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1318 {
1319 J(_T_, scvf.from(), _C_, sh) += vDFlux_c[sh];
1320 J(_T_, scvf.to(), _C_, sh) -= vDFlux_c[sh];
1321 J(_T_, scvf.from(), _P_, sh) += vDFlux_p[sh];
1322 J(_T_, scvf.to(), _P_, sh) -= vDFlux_p[sh];
1323 J(_T_, scvf.from(), _T_, sh) += vDFlux_T[sh];
1324 J(_T_, scvf.to(), _T_, sh) -= vDFlux_T[sh];
1325 }
1326 }
1327
1328// Assemble the singular sources and sinks
1329 if (m_sss_mngr.valid () && (m_sss_mngr->num_points () != 0 || m_sss_mngr->num_lines () != 0))
1330 {
1331 typedef typename domain_type::position_accessor_type t_pos_accessor;
1333 point_iterator<TElem,t_pos_accessor,TBulkFVGeom> t_pnt_sss_iter;
1335 line_iterator<TElem,t_pos_accessor,TBulkFVGeom> t_lin_sss_iter;
1336
1337 t_pos_accessor& aaPos = this->domain()->position_accessor ();
1338 Grid& grid = (Grid&) *this->domain()->grid ();
1339
1340 for(size_t ip = 0; ip < bulk_geo.num_scv(); ip++)
1341 {
1342 size_t co = bulk_geo.scv(ip).node_id ();
1343
1344 // point sources
1345 for (t_pnt_sss_iter pnt (m_sss_mngr.get (), pElem, grid, aaPos, bulk_geo, co);
1346 ! pnt.is_over (); ++pnt)
1347 {
1349 if (! pnt_sss->marked_for (pElem, co))
1350 continue;
1351 pnt_sss->compute (pnt_sss->position (), this->time (), -1); //TODO: set the subset id instead of -1
1352 ass_sss_JA_elem (J, u, pElem, co, pnt_sss->intensity (), pnt_sss->concentration (), pnt_sss->temperature ());
1353 }
1354
1355 // line sources
1356 for (t_lin_sss_iter line (m_sss_mngr.get (), pElem, grid, aaPos, bulk_geo, co);
1357 ! line.is_over (); ++line)
1358 {
1360 number len = VecDistance (line.seg_start (), line.seg_end ());
1361 line_sss->compute (line.seg_start (), this->time (), -1); //TODO: set the subset id instead of -1
1362 ass_sss_JA_elem (J, u, pElem, co, line_sss->intensity (), line_sss->concentration (), line_sss->temperature (), len);
1363 }
1364 }
1365 }
1366}
1367
1369template<typename TDomain>
1370template<typename TElem>
1372(
1373 LocalMatrix & J,
1374 const LocalVector & u,
1375 TElem * pElem,
1376 const position_type vCornerCoords []
1377)
1378{
1379 number half_fr_width = m_imAperture[0] / 2;
1380
1381 const size_t numSh = m_pFractGeo->num_sh();
1382 const size_t numScvf = m_pFractGeo->num_scvf();
1383
1384 MathMatrix<dim,dim> Diffusion[TFractFVGeom::maxNumSCVF];
1385 MathMatrix<dim,dim> ThermCond[TFractFVGeom::maxNumSCVF];
1386 MathVector<dim> Dgrad;
1387 MathVector<dim> grad_c_ip, grad_T_ip;
1388 number vDFlux_c [maxFractSideCorners], vDFlux_p [maxFractSideCorners], vDFlux_T [maxFractSideCorners];
1389
1390// Get the corner values
1391 number vConcentration [maxFractSideCorners];
1392 number vTemperature [maxFractSideCorners];
1393 for (size_t sh = 0; sh < numSh; sh++)
1394 {
1395 size_t co = m_innerSideCo[sh]; // co: index of the corner in the (degenerated) full-dim. element
1396 vConcentration[sh] = u(_C_, co);
1397 vTemperature[sh] = u(_T_, co);
1398 }
1399
1400// Compute Diffusion - Dispersion
1401 MatSet (Diffusion[0], 0);
1402 MatDiagSet (Diffusion[0], m_imPorosity[0] * m_imFractDiffusion[0]);
1403 for (size_t ip = 1; ip < numScvf; ip++)
1404 Diffusion[ip] = Diffusion[0];
1405 //TODO add Dispersion
1406
1407// Compute the thermal conductivity
1408 MatSet (ThermCond[0], 0);
1409 MatDiagSet (ThermCond[0], m_imFractThermCond[0]);
1410 for (size_t ip = 1; ip < numScvf; ip++)
1411 ThermCond[ip] = ThermCond[0];
1412
1413// compute upwind shapes for transport equation
1414 if(!m_spUpwind->update(m_pFractGeo, m_imFractDarcyVelIP.values(), Diffusion, true))
1415 UG_THROW("FractTHF_FV1::fract_ass_dA_elem: Cannot compute convection shapes for the transport equation.");
1416
1417// compute upwind shapes for transport equation
1418 if(!m_spUpwindEnergy->update(m_pFractGeo, m_imFractDarcyVelIP.values(), ThermCond, true))
1419 UG_THROW("FractTHF_FV1::fract_ass_dA_elem: Cannot compute convection shapes for the energy equation.");
1420
1421// get a const (!!) reference to the upwind
1422 const IConvectionShapes<dim>& convShape
1423 = *const_cast<const IConvectionShapes<dim>*>(m_spUpwind.get());
1424
1425// get a const (!!) reference to the upwind
1426 const IConvectionShapes<dim>& convShapeT
1427 = *const_cast<const IConvectionShapes<dim>*>(m_spUpwindEnergy.get());
1428
1429// Loop Sub Control Volume Faces (SCVF)
1430 for (size_t ip = 0; ip < numScvf; ip++)
1431 {
1432 // Get current SCVF
1433 const typename TFractFVGeom::SCVF& scvf = m_pFractGeo->scvf(ip);
1434
1435 // The ip-concentration and the gradient of c at the ip:
1436 VecSet (grad_c_ip, 0.0); VecSet (grad_T_ip, 0.0);
1437 for (size_t sh = 0; sh < scvf.num_sh(); sh++)
1438 {
1439 VecScaleAppend (grad_c_ip, vConcentration[sh], scvf.global_grad(sh));
1440 VecScaleAppend (grad_T_ip, vTemperature[sh], scvf.global_grad(sh));
1441 }
1442
1443 const MathVector<dim>* vDDarcyVel_c = m_imFractDarcyVelIP.deriv(ip, _C_);
1444 const MathVector<dim>* vDDarcyVel_p = m_imFractDarcyVelIP.deriv(ip, _P_);
1445 const MathVector<dim>* vDDarcyVel_T = m_imFractDarcyVelIP.deriv(ip, _T_);
1446
1448 // Transport Equation
1450
1451 // Loop Shape Functions
1452 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1453 {
1454 size_t co = m_innerSideCo[sh]; // co: index of the corner in the (degenerated) full-dim. element
1455
1456 // Compute Derivative of Convective Flux
1457 vDFlux_c[sh] = convShape(ip, sh);
1458 vDFlux_p[sh] = 0.0;
1459 vDFlux_T[sh] = 0.0;
1460
1461 // Derivative w.r.t. Velocity
1462 for(size_t sh1 = 0; sh1 < scvf.num_sh(); ++sh1)
1463 {
1464 vDFlux_c[sh] += vConcentration[sh1] * VecDot(convShape.D_vel(ip, sh1), vDDarcyVel_c[co]);
1465 vDFlux_p[sh] += vConcentration[sh1] * VecDot(convShape.D_vel(ip, sh1), vDDarcyVel_p[co]);
1466 vDFlux_T[sh] += vConcentration[sh1] * VecDot(convShape.D_vel(ip, sh1), vDDarcyVel_T[co]);
1467 }
1468 //TODO: add derivative of Dispersion
1469
1470 // Add Derivative of Diffusive Flux
1471 MatVecMult(Dgrad, Diffusion[ip], scvf.global_grad(sh));
1472 vDFlux_c[sh] -= VecDot(Dgrad, scvf.normal());
1473 }
1474
1475 // Handle density in case of full equation
1476 if(!m_BoussinesqTransport)
1477 {
1478 // Convective Flux
1479 number flux = 0;
1480 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1481 flux += convShape(ip, sh) * vConcentration[sh];
1482
1483 // Diffusive Flux
1484 MatVecMult(Dgrad, Diffusion[ip], grad_c_ip);
1485 flux -= VecDot(Dgrad, scvf.normal());
1486
1487 // Derivative of product
1488 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1489 {
1490 vDFlux_c[sh] = m_imDensityIP[ip] * vDFlux_c[sh] +
1491 (m_imDensityIP.constant() ? 0.0 : m_imDensityIP.deriv(ip, _C_, m_innerSideCo[sh])) * flux;
1492 vDFlux_p[sh] *= m_imDensityIP[ip];
1493 vDFlux_T[sh] = m_imDensityIP[ip] * vDFlux_T[sh] +
1494 (m_imDensityIP.constant() ? 0.0 : m_imDensityIP.deriv(ip, _T_, m_innerSideCo[sh])) * flux;
1495 }
1496 }
1497
1498 // Multiply by the fracture width
1499 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1500 {
1501 vDFlux_c[sh] *= half_fr_width; vDFlux_p[sh] *= half_fr_width; vDFlux_T[sh] *= half_fr_width;
1502 }
1503
1504 // Add Flux contribution
1505 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1506 {
1507 size_t co = m_innerSideCo[sh];
1508 size_t co_from = m_innerSideCo[scvf.from()];
1509 size_t co_to = m_innerSideCo[scvf.to()];
1510
1511 J(_C_, co_from, _C_, co) += vDFlux_c[sh];
1512 J(_C_, co_to, _C_, co) -= vDFlux_c[sh];
1513 J(_C_, co_from, _P_, co) += vDFlux_p[sh];
1514 J(_C_, co_to, _P_, co) -= vDFlux_p[sh];
1515 J(_C_, co_from, _T_, co) += vDFlux_T[sh];
1516 J(_C_, co_to, _T_, co) -= vDFlux_T[sh];
1517 }
1518
1520 // Flow Equation
1522
1523 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1524 {
1525 size_t co = m_innerSideCo[sh];
1526 vDFlux_c[sh] = VecDot(vDDarcyVel_c[co], scvf.normal());
1527 vDFlux_p[sh] = VecDot(vDDarcyVel_p[co], scvf.normal());
1528 vDFlux_T[sh] = VecDot(vDDarcyVel_T[co], scvf.normal());
1529 }
1530
1531 number flux = VecDot(m_imFractDarcyVelIP[ip], scvf.normal());
1532
1533 if(!m_BoussinesqFlow)
1534 {
1535 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1536 {
1537 vDFlux_c[sh] = m_imDensityIP[ip] * vDFlux_c[sh] +
1538 (m_imDensityIP.constant() ? 0.0 : m_imDensityIP.deriv(ip, _C_, m_innerSideCo[sh])) * flux;
1539 vDFlux_p[sh] *= m_imDensityIP[ip];
1540 vDFlux_T[sh] = m_imDensityIP[ip] * vDFlux_T[sh] +
1541 (m_imDensityIP.constant() ? 0.0 : m_imDensityIP.deriv(ip, _T_, m_innerSideCo[sh])) * flux;
1542 }
1543
1544 flux *= m_imDensityIP[ip];
1545 }
1546
1547 // Multiply by the fracture width
1548 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1549 {
1550 vDFlux_c[sh] *= half_fr_width; vDFlux_p[sh] *= half_fr_width; vDFlux_T[sh] *= half_fr_width;
1551 }
1552
1553 // Add Flux contribution
1554 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1555 {
1556 size_t co = m_innerSideCo[sh];
1557 size_t co_from = m_innerSideCo[scvf.from()];
1558 size_t co_to = m_innerSideCo[scvf.to()];
1559
1560 J(_P_, co_from, _C_, co) += vDFlux_c[sh];
1561 J(_P_, co_to, _C_, co) -= vDFlux_c[sh];
1562 J(_P_, co_from, _P_, co) += vDFlux_p[sh];
1563 J(_P_, co_to, _P_, co) -= vDFlux_p[sh];
1564 J(_P_, co_from, _T_, co) += vDFlux_T[sh];
1565 J(_P_, co_to, _T_, co) -= vDFlux_T[sh];
1566 }
1567
1568 // Volume stabilization: Add the continuity equation to the transport equation
1569 // REMARK: We do not compute derivatives of the defect of the conf. eq. here because this defect tends to 0.
1570 if(m_bVolStabDataActive)
1571 {
1572 flux *= half_fr_width;
1573 m_spVolStabData->stiff(pElem->vertex(m_innerSideCo[scvf.from()])) -= flux;
1574 m_spVolStabData->stiff(pElem->vertex(m_innerSideCo[scvf.to()])) += flux;
1575 }
1576
1577
1579 // Energy Equation
1581
1582 // Loop Shape Functions
1583 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1584 {
1585 size_t co = m_innerSideCo[sh]; // co: index of the corner in the (degenerated) full-dim. element
1586
1587 // Compute Derivative of Convective Flux
1588 vDFlux_c[sh] = 0.0;
1589 vDFlux_p[sh] = 0.0;
1590 vDFlux_T[sh] = convShape(ip, sh);
1591
1592 // Derivative w.r.t. Velocity
1593 for(size_t sh1 = 0; sh1 < scvf.num_sh(); ++sh1)
1594 {
1595 vDFlux_c[sh] += vTemperature[sh1] * VecDot(convShapeT.D_vel(ip, sh1), vDDarcyVel_c[co]);
1596 vDFlux_p[sh] += vTemperature[sh1] * VecDot(convShapeT.D_vel(ip, sh1), vDDarcyVel_p[co]);
1597 vDFlux_T[sh] += vTemperature[sh1] * VecDot(convShapeT.D_vel(ip, sh1), vDDarcyVel_T[co]);
1598 }
1599
1600 vDFlux_c[sh] *= m_imHeatCapacityFluid;
1601 vDFlux_p[sh] *= m_imHeatCapacityFluid;
1602 vDFlux_T[sh] *= m_imHeatCapacityFluid;
1603 }
1604
1605 // Handle density in case of full equation
1606 if(!m_BoussinesqEnergy)
1607 {
1608 // Convective Flux
1609 number flux = 0;
1610 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1611 flux += convShapeT(ip, sh) * vTemperature[sh];
1612 flux *= m_imHeatCapacityFluid;
1613
1614 // Derivative of product
1615 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1616 {
1617 vDFlux_c[sh] = m_imDensityIP[ip] * vDFlux_c[sh] +
1618 (m_imDensityIP.constant() ? 0.0 : m_imDensityIP.deriv(ip, _C_, m_innerSideCo[sh])) * flux;
1619 vDFlux_p[sh] *= m_imDensityIP[ip];
1620 vDFlux_T[sh] = m_imDensityIP[ip] * vDFlux_T[sh] +
1621 (m_imDensityIP.constant() ? 0.0 : m_imDensityIP.deriv(ip, _T_, m_innerSideCo[sh])) * flux;
1622 }
1623 }
1624 else
1625 {
1626 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1627 {
1628 vDFlux_c[sh] *= m_BoussinesqDensity;
1629 vDFlux_p[sh] *= m_BoussinesqDensity;
1630 vDFlux_T[sh] *= m_BoussinesqDensity;
1631 }
1632 }
1633
1634 // Loop Shape Functions
1635 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1636 {
1637 // Add Derivative of Diffusive Flux
1638 MatVecMult(Dgrad, ThermCond[ip], scvf.global_grad(sh));
1639 vDFlux_T[sh] -= VecDot(Dgrad, scvf.normal());
1640 }
1641
1642 // Multiply by the fracture width
1643 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1644 {
1645 vDFlux_c[sh] *= half_fr_width; vDFlux_p[sh] *= half_fr_width; vDFlux_T[sh] *= half_fr_width;
1646 }
1647
1648 // Add Flux contribution
1649 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
1650 {
1651 size_t co = m_innerSideCo[sh];
1652 size_t co_from = m_innerSideCo[scvf.from()];
1653 size_t co_to = m_innerSideCo[scvf.to()];
1654
1655 J(_T_, co_from, _C_, co) += vDFlux_c[sh];
1656 J(_T_, co_to, _C_, co) -= vDFlux_c[sh];
1657 J(_T_, co_from, _P_, co) += vDFlux_p[sh];
1658 J(_T_, co_to, _P_, co) -= vDFlux_p[sh];
1659 J(_T_, co_from, _T_, co) += vDFlux_T[sh];
1660 J(_T_, co_to, _T_, co) -= vDFlux_T[sh];
1661 }
1662 }
1663
1664// Assemble the singular sources and sinks
1665 if (m_sss_mngr.valid () && m_sss_mngr->num_lines () != 0)
1666 {
1667 typedef typename domain_type::position_accessor_type t_pos_accessor;
1669 line_iterator<side_type,t_pos_accessor,TFractFVGeom> t_lin_sss_iter;
1670
1671 t_pos_accessor& aaPos = this->domain()->position_accessor ();
1672 Grid& grid = (Grid&) *this->domain()->grid ();
1673
1674 for(size_t ip = 0; ip < m_pFractGeo->num_scv(); ip++)
1675 {
1676 // Get the corner of the face
1677 size_t side_co = m_pFractGeo->scv(ip).node_id ();
1678 // Get associated node of the element (not side!)
1679 size_t co = m_innerSideCo [m_pFractGeo->scv(ip).node_id ()];
1680
1681 // line sources (that correspond to the point sources)
1682 for (t_lin_sss_iter line (m_sss_mngr.get (), m_innerFractSide, grid, aaPos, *m_pFractGeo, side_co);
1683 ! line.is_over (); ++line)
1684 {
1686 if (! line_sss->marked_for (m_innerFractSide, side_co))
1687 continue;
1688 line_sss->compute (line.seg_start (), this->time (), -1); //TODO: set the subset id instead of -1
1689 ass_sss_JA_elem (J, u, pElem, co, line_sss->intensity () / 2, line_sss->concentration (), line_sss->temperature (), 0.5);
1690 /* Remark: "0.5" because the source is taken into account twise. */
1691 }
1692 }
1693 }
1694}
1695
1697template<typename TDomain>
1698template<typename TElem>
1700(
1701 LocalMatrix & J,
1702 const LocalVector & u,
1703 TElem * pElem,
1704 const position_type vCornerCoords []
1705)
1706{
1707 const number orthDiffusion = m_imPorosity[0] * m_imOrthoDiffusion[0];
1708
1709 const number half_fr_width = m_imAperture[0] / 2;
1710
1711// loop over the corners of the inner side
1712 for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ip++)
1713 {
1714 // Get current SCV
1715 const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv(ip);
1716 number s = scv.volume ();
1717
1718 // Get associated node of the element (not side!)
1719 const int co = m_innerSideCo [scv.node_id()];
1720
1721 // Get the corner values
1722 const number orthC_f = u(_C_, co);
1723 const number orthC_m = u(_C_, m_assCo[co]);
1724 const number orthP_f = u(_P_, co);
1725 const number orthP_m = u(_P_, m_assCo[co]);
1726 const number orthT_f = u(_T_, co);
1727 const number orthT_m = u(_T_, m_assCo[co]);
1728
1729 const number fractDensity = m_imDensityCo[co];
1730 const number orthDensity = m_imDensityCo [m_assCo[co]];
1731 number D_fractDensity_c, D_orthDensity_c, D_fractDensity_T, D_orthDensity_T;
1732 if (! m_imDensityCo.constant())
1733 {
1734 D_fractDensity_c = m_imDensityCo.deriv (co, _C_, co);
1735 D_fractDensity_T = m_imDensityCo.deriv (co, _T_, co);
1736 D_orthDensity_c = m_imDensityCo.deriv (m_assCo[co], _C_, m_assCo[co]);
1737 D_orthDensity_T = m_imDensityCo.deriv (m_assCo[co], _T_, m_assCo[co]);
1738 }
1739 else
1740 D_fractDensity_c = D_fractDensity_T = D_orthDensity_c = D_orthDensity_T = 0;
1741
1742 const number orthViscosity = m_imViscosityCo [m_assCo[co]];
1743 number D_orthViscosity_c, D_orthViscosity_T;
1744 if (! m_imViscosityCo.constant())
1745 {
1746 D_orthViscosity_c = m_imViscosityCo.deriv (m_assCo[co], _C_, m_assCo[co]);
1747 D_orthViscosity_T = m_imViscosityCo.deriv (m_assCo[co], _T_, m_assCo[co]);
1748 }
1749 else
1750 D_orthViscosity_c = D_orthViscosity_T = 0;
1751
1752 // Flux velocity between the fracture and the bulk medium
1753
1754 number orthVelocity = (m_orthGravity * (orthDensity - fractDensity)
1755 - (orthP_m - orthP_f) / half_fr_width)
1756 * m_imOrthoPermeability[0];
1757
1758 number D_orthVelocity [3], D_orthVelocity_fr [3]; // 3 components: w.r.t. _C_, _P_ and _T_ resp.
1759
1760 D_orthVelocity [_C_] = (m_orthGravity * D_orthDensity_c
1761 * m_imOrthoPermeability[0] * orthViscosity
1762 - orthVelocity * D_orthViscosity_c) / orthViscosity / orthViscosity;
1763
1764 D_orthVelocity_fr [_C_] = - m_orthGravity * D_fractDensity_c
1765 * m_imOrthoPermeability[0] / orthViscosity;
1766
1767 D_orthVelocity [_P_] = - m_imOrthoPermeability[0]
1768 / half_fr_width / orthViscosity;
1769
1770 D_orthVelocity_fr [_P_] = - D_orthVelocity [_P_];
1771
1772 D_orthVelocity [_T_] = (m_orthGravity * D_orthDensity_T
1773 * m_imOrthoPermeability[0] * orthViscosity
1774 - orthVelocity * D_orthViscosity_T) / orthViscosity / orthViscosity;
1775
1776 D_orthVelocity_fr [_T_] = - m_orthGravity * D_fractDensity_T
1777 * m_imOrthoPermeability[0] / orthViscosity;
1778
1779 orthVelocity /= orthViscosity;
1780
1782 number flux, D_flux [3], D_flux_fr [3]; // 3 components of the derivatives: w.r.t. _C_, _P_ and _T_ resp.
1783
1785 // Transport Equation
1787
1788 D_flux [_C_] = orthDiffusion / half_fr_width;
1789 D_flux_fr [_C_] = - D_flux [_C_];
1790 D_flux [_T_] = D_flux_fr [_T_] = 0;
1791 /* We use the full upwind here: */
1792 if (orthVelocity >= 0)
1793 {
1794 D_flux [_C_] -= D_orthVelocity [_C_] * orthC_f;
1795 D_flux_fr [_C_] -= orthVelocity + D_orthVelocity_fr [_C_] * orthC_f;
1796 D_flux [_P_] = - D_orthVelocity [_P_] * orthC_f;
1797 D_flux_fr [_P_] = - D_orthVelocity_fr [_P_] * orthC_f;
1798 D_flux [_T_] = - D_orthVelocity [_T_] * orthC_f;
1799 D_flux_fr [_T_] = - D_orthVelocity_fr [_T_] * orthC_f;
1800 }
1801 else
1802 {
1803 D_flux [_C_] -= orthVelocity + D_orthVelocity [_C_] * orthC_m;
1804 D_flux_fr [_C_] -= D_orthVelocity_fr [_C_] * orthC_m;
1805 D_flux [_P_] = - D_orthVelocity [_P_] * orthC_m;
1806 D_flux_fr [_P_] = - D_orthVelocity_fr [_P_] * orthC_m;
1807 D_flux [_T_] = - D_orthVelocity [_T_] * orthC_m;
1808 D_flux_fr [_T_] = - D_orthVelocity_fr [_T_] * orthC_m;
1809 }
1810
1811 if (! m_BoussinesqTransport)
1812 {
1813 flux = orthDiffusion * (orthC_m - orthC_f) / half_fr_width;
1814 /* We use the full upwind here: */
1815 flux -= orthVelocity * ((orthVelocity >= 0)? orthC_f : orthC_m);
1816
1817 D_flux [_C_] = D_flux [_C_] * orthDensity + flux * D_orthDensity_c;
1818 D_flux_fr [_C_] *= orthDensity;
1819 D_flux [_P_] *= orthDensity;
1820 D_flux_fr [_P_] *= orthDensity;
1821 D_flux [_T_] = D_flux [_T_] * orthDensity + flux * D_orthDensity_T;
1822 D_flux_fr [_T_] *= orthDensity;
1823 }
1824
1825 J(_C_, m_assCo [co], _C_, m_assCo [co]) += D_flux [_C_] * s;
1826 J(_C_, m_assCo [co], _P_, m_assCo [co]) += D_flux [_P_] * s;
1827 J(_C_, m_assCo [co], _T_, m_assCo [co]) += D_flux [_T_] * s;
1828 J(_C_, m_assCo [co], _C_, co) += D_flux_fr [_C_] * s;
1829 J(_C_, m_assCo [co], _P_, co) += D_flux_fr [_P_] * s;
1830 J(_C_, m_assCo [co], _T_, co) += D_flux_fr [_T_] * s;
1831
1832 J(_C_, co, _C_, m_assCo [co]) -= D_flux [_C_] * s;
1833 J(_C_, co, _P_, m_assCo [co]) -= D_flux [_P_] * s;
1834 J(_C_, co, _T_, m_assCo [co]) -= D_flux [_T_] * s;
1835 J(_C_, co, _C_, co) -= D_flux_fr [_C_] * s;
1836 J(_C_, co, _P_, co) -= D_flux_fr [_P_] * s;
1837 J(_C_, co, _T_, co) -= D_flux_fr [_T_] * s;
1838
1840 // Flow Equation
1842
1843 if (! m_BoussinesqFlow)
1844 {
1845 D_flux [_C_] = (D_orthVelocity [_C_] * orthDensity
1846 + orthVelocity * D_orthDensity_c) * s;
1847 D_flux_fr [_C_] = D_orthVelocity_fr [_C_] * orthDensity * s;
1848 }
1849 else
1850 {
1851 D_flux [_C_] = D_orthVelocity [_C_] * s;
1852 D_flux_fr [_C_] = D_orthVelocity_fr [_C_] * s;
1853 }
1854 J(_P_, m_assCo [co], _C_, m_assCo [co]) -= D_flux [_C_];
1855 J(_P_, co, _C_, m_assCo [co]) += D_flux [_C_];
1856 J(_P_, m_assCo [co], _C_, co) -= D_flux_fr [_C_];
1857 J(_P_, co, _C_, co) += D_flux_fr [_C_];
1858
1859 number rho_x_s = s;
1860 if (! m_BoussinesqFlow) rho_x_s *= orthDensity;
1861
1862 flux = D_orthVelocity [_P_] * rho_x_s;
1863 J(_P_, m_assCo [co], _P_, m_assCo [co]) -= flux;
1864 J(_P_, co, _P_, m_assCo [co]) += flux;
1865
1866 flux = D_orthVelocity_fr [_P_] * rho_x_s;
1867 J(_P_, m_assCo [co], _P_, co) -= flux;
1868 J(_P_, co, _P_, co) += flux;
1869
1870 if (! m_BoussinesqFlow)
1871 {
1872 D_flux [_T_] = (D_orthVelocity [_T_] * orthDensity
1873 + orthVelocity * D_orthDensity_T) * s;
1874 D_flux_fr [_T_] = D_orthVelocity_fr [_T_] * orthDensity * s;
1875 }
1876 else
1877 {
1878 D_flux [_T_] = D_orthVelocity [_T_] * s;
1879 D_flux_fr [_T_] = D_orthVelocity_fr [_T_] * s;
1880 }
1881 J(_P_, m_assCo [co], _T_, m_assCo [co]) -= D_flux [_T_];
1882 J(_P_, co, _T_, m_assCo [co]) += D_flux [_T_];
1883 J(_P_, m_assCo [co], _T_, co) -= D_flux_fr [_T_];
1884 J(_P_, co, _T_, co) += D_flux_fr [_T_];
1885
1886 // Volume stabilization: Add the continuity equation to the transport equation
1887 // REMARK: We do not compute derivatives of the defect of the conf. eq. here because this defect tends to 0.
1888 if(m_bVolStabDataActive)
1889 {
1890 flux = orthVelocity * rho_x_s;
1891 m_spVolStabData->stiff(pElem->vertex(m_assCo[co])) += flux;
1892 m_spVolStabData->stiff(pElem->vertex(co)) -= flux;
1893 }
1894
1896 // Energy Equation
1898
1899 /* We use the full upwind here: */
1900 if (orthVelocity >= 0)
1901 {
1902 D_flux [_C_] = - D_orthVelocity [_C_] * orthT_f * m_imHeatCapacityFluid;
1903 D_flux_fr [_C_] = - D_orthVelocity_fr [_C_] * orthT_f * m_imHeatCapacityFluid;
1904 D_flux [_P_] = - D_orthVelocity [_P_] * orthT_f * m_imHeatCapacityFluid;
1905 D_flux_fr [_P_] = - D_orthVelocity_fr [_P_] * orthT_f * m_imHeatCapacityFluid;
1906 D_flux [_T_] = D_orthVelocity [_T_] * orthT_f * m_imHeatCapacityFluid;
1907 D_flux_fr [_T_] = orthVelocity + D_orthVelocity_fr [_T_] * orthT_f * m_imHeatCapacityFluid;
1908 }
1909 else
1910 {
1911 D_flux [_C_] = - D_orthVelocity [_C_] * orthT_m * m_imHeatCapacityFluid;
1912 D_flux_fr [_C_] = - D_orthVelocity_fr [_C_] * orthT_m * m_imHeatCapacityFluid;
1913 D_flux [_P_] = - D_orthVelocity [_P_] * orthT_m * m_imHeatCapacityFluid;
1914 D_flux_fr [_P_] = - D_orthVelocity_fr [_P_] * orthT_m * m_imHeatCapacityFluid;
1915 D_flux [_T_] = orthVelocity + D_orthVelocity [_T_] * orthT_m * m_imHeatCapacityFluid;
1916 D_flux_fr [_T_] = D_orthVelocity_fr [_T_] * orthT_m * m_imHeatCapacityFluid;
1917 }
1918
1919 if (! m_BoussinesqEnergy)
1920 {
1921 /* We use the full upwind here: */
1922 flux = - orthVelocity * ((orthVelocity >= 0)? orthT_f : orthT_m)
1923 * m_imHeatCapacityFluid * orthDensity;
1924
1925 D_flux [_C_] = D_flux [_C_] * orthDensity + flux * D_orthDensity_c;
1926 D_flux_fr [_C_] *= orthDensity;
1927 D_flux [_P_] *= orthDensity;
1928 D_flux_fr [_P_] *= orthDensity;
1929 D_flux [_T_] = D_flux [_T_] * orthDensity + flux * D_orthDensity_T;
1930 D_flux_fr [_T_] *= orthDensity;
1931 }
1932 else
1933 {
1934 D_flux [_C_] *= m_BoussinesqDensity;
1935 D_flux_fr [_C_] *= m_BoussinesqDensity;
1936 D_flux [_P_] *= m_BoussinesqDensity;
1937 D_flux_fr [_P_] *= m_BoussinesqDensity;
1938 D_flux [_T_] *= m_BoussinesqDensity;
1939 D_flux_fr [_T_] *= m_BoussinesqDensity;
1940 }
1941
1942 D_flux [_T_] += m_imOrthoThermCond[0] / half_fr_width;
1943 D_flux_fr [_T_] -= m_imOrthoThermCond[0] / half_fr_width;
1944
1945 J(_T_, m_assCo [co], _C_, m_assCo [co]) += D_flux [_C_] * s;
1946 J(_T_, m_assCo [co], _P_, m_assCo [co]) += D_flux [_P_] * s;
1947 J(_T_, m_assCo [co], _T_, m_assCo [co]) += D_flux [_T_] * s;
1948 J(_T_, m_assCo [co], _C_, co) += D_flux_fr [_C_] * s;
1949 J(_T_, m_assCo [co], _P_, co) += D_flux_fr [_P_] * s;
1950 J(_T_, m_assCo [co], _T_, co) += D_flux_fr [_T_] * s;
1951
1952 J(_T_, co, _C_, m_assCo [co]) -= D_flux [_C_] * s;
1953 J(_T_, co, _P_, m_assCo [co]) -= D_flux [_P_] * s;
1954 J(_T_, co, _T_, m_assCo [co]) -= D_flux [_T_] * s;
1955 J(_T_, co, _C_, co) -= D_flux_fr [_C_] * s;
1956 J(_T_, co, _P_, co) -= D_flux_fr [_P_] * s;
1957 J(_T_, co, _T_, co) -= D_flux_fr [_T_] * s;
1958 }
1959}
1960
1962template<typename TDomain>
1963template<typename TElem>
1965(
1966 LocalVector& d,
1967 const LocalVector& u,
1968 TElem * pElem,
1969 size_t co,
1970 number intensity,
1971 number concentration,
1972 number temperature,
1973 number factor
1974)
1975{
1976 if (intensity != 0)
1977 { // fluid source/sink
1978 intensity *= factor;
1979 if (intensity > 0)
1980 {
1981 // fluid source
1982 number density = 1000 + 000 * concentration; //FIXME!!
1983 d(_C_, co) -= m_BoussinesqTransport? intensity * concentration : intensity * density * concentration;
1984 d(_P_, co) -= m_BoussinesqFlow? intensity : intensity * density;
1985 d(_T_, co) -= intensity * (m_BoussinesqEnergy? m_BoussinesqDensity : density) * m_imHeatCapacityFluid * temperature;
1986 if(m_bVolStabDataActive)
1987 m_spVolStabData->stiff(pElem->vertex(co)) -= m_BoussinesqFlow? intensity : intensity * density;
1988 }
1989 else
1990 {
1991 // fluid sink
1992 d(_C_, co) -= m_BoussinesqTransport? intensity * u(_C_, co) : intensity * m_imDensityCo[co] * u(_C_, co);
1993 d(_P_, co) -= m_BoussinesqFlow? intensity : intensity * m_imDensityCo[co];
1994 d(_T_, co) -= intensity * (m_BoussinesqEnergy? m_BoussinesqDensity : m_imDensityCo[co]) * m_imHeatCapacityFluid * u(_T_, co);
1995 if(m_bVolStabDataActive)
1996 m_spVolStabData->stiff(pElem->vertex(co))
1997 -= m_BoussinesqFlow? intensity : intensity * m_imDensityCo[co];
1998 }
1999 }
2000 else
2001 { // heat source
2002 if (temperature < 0)
2003 UG_THROW ("FractTHF_FV1: Heat sinks are not implemented.");
2004 d(_T_, co) -= temperature * factor;
2005 }
2006}
2007
2009template<typename TDomain>
2010template<typename TElem>
2012(
2013 LocalMatrix& J,
2014 const LocalVector& u,
2015 TElem * pElem,
2016 size_t co,
2017 number intensity,
2018 number concentration,
2019 number temperature,
2020 number factor
2021)
2022{
2023 if (intensity != 0)
2024 {
2025 intensity *= factor;
2026 if (intensity > 0)
2027 {
2028 // fluid source: no contribution to the maxrix
2029 number density = 1000 + 000 * concentration; //FIXME!!
2030 if(m_bVolStabDataActive)
2031 m_spVolStabData->stiff(pElem->vertex(co))
2032 -= m_BoussinesqFlow? intensity : intensity * density;
2033 }
2034 else
2035 {
2036 // fluid sink: add the intensity to the matrix
2037 if (! m_BoussinesqTransport)
2038 {
2039 if (!m_imDensityCo.constant ())
2040 {
2041 J(_C_, co, _C_, co)
2042 -= intensity * (m_imDensityCo[co] + m_imDensityCo.deriv (co, _C_, co) * u (_C_, co));
2043 J(_C_, co, _T_, co) -= intensity * m_imDensityCo.deriv(co, _T_, co) * m_imDensityCo[co];
2044 }
2045 else
2046 J(_C_, co, _C_, co) -= intensity * m_imDensityCo[co];
2047 }
2048 else
2049 J(_C_, co, _C_, co) -= intensity;
2050
2051 if (! m_BoussinesqFlow && ! m_imDensityCo.constant ())
2052 {
2053 J(_P_, co, _C_, co) -= intensity * m_imDensityCo.deriv (co, _C_, co);
2054 J(_P_, co, _T_, co) -= intensity * m_imDensityCo.deriv (co, _T_, co);
2055 }
2056
2057 if (!m_BoussinesqEnergy)
2058 {
2059 if (!m_imDensityCo.constant())
2060 {
2061 J(_T_, co, _C_, co)
2062 -= intensity * m_imDensityCo.deriv(co, _C_, co) * m_imHeatCapacityFluid * u(_T_, co);
2063 J(_T_, co, _T_, co)
2064 -= intensity * m_imHeatCapacityFluid * (m_imDensityCo.deriv(co, _T_, co) * u(_T_, co) + m_imDensityCo[co]);
2065 }
2066 else
2067 J(_T_, co, _T_, co) -= intensity * m_imHeatCapacityFluid * m_imDensityCo[co];
2068 }
2069 else
2070 J(_T_, co, _T_, co) -= intensity * m_imHeatCapacityFluid * m_BoussinesqDensity;
2071
2072 if(m_bVolStabDataActive)
2073 m_spVolStabData->stiff(pElem->vertex(co))
2074 -= m_BoussinesqFlow? intensity : intensity * m_imDensityCo[co];
2075 }
2076 }
2077 else
2078 { // heat source
2079 if (temperature < 0)
2080 UG_THROW ("FractTHF_FV1: Heat sinks are not implemented.");
2081 // otherwise nothing to assemble in the matrix
2082 }
2083}
2084
2086template<typename TDomain>
2087template<typename TElem>
2089(
2090 LocalVector & d,
2091 const LocalVector & u,
2092 GridObject * elem,
2093 const position_type vCornerCoords []
2094)
2095{
2096 TElem * pElem = static_cast<TElem*> (elem);
2097
2098// call the specific routine:
2099 if (! m_isFracture)
2100 this->template bulk_ass_dM_elem<TElem> (d, u, pElem, vCornerCoords);
2101 else
2102 this->template fract_ass_dM_elem<TElem> (d, u, pElem, vCornerCoords);
2103}
2104
2106template<typename TDomain>
2107template<typename TElem>
2109(
2110 LocalVector & d,
2111 const LocalVector & u,
2112 TElem * pElem,
2113 const position_type vCornerCoords []
2114)
2115{
2116 typedef FV1Geometry<TElem, dim> TBulkFVGeom;
2117
2118// Get finite volume geometry
2119 const TBulkFVGeom& bulk_geo = GeomProvider<TBulkFVGeom>::get();
2120
2121// The porosity is constant per element
2122 number porosity = m_imPorosity [0];
2123
2124// Loop Sub Control Volumes (SCV)
2125 for (size_t ip = 0; ip < bulk_geo.num_scv(); ip++)
2126 {
2127 // Get current SCV
2128 const typename TBulkFVGeom::SCV& scv = bulk_geo.scv(ip);
2129
2130 // Get associated node
2131 const int co = scv.node_id();
2132
2133 // Add to local matrix
2134 if(m_BoussinesqTransport)
2135 d(_C_,co) += porosity * u(_C_,co) * scv.volume();
2136 else
2137 d(_C_,co) += porosity * m_imDensityCo[ip] * u(_C_,co) * scv.volume();
2138
2139 if(m_BoussinesqFlow)
2140 d(_P_,co) += porosity * scv.volume();
2141 else
2142 {
2143 d(_P_,co) += porosity * m_imDensityCo[ip] * scv.volume();
2144
2145 if (m_bVolStabDataActive)
2146 {
2147 // Volume stabilization: Add the continuity equation to the transport equation
2148 // REMARK: We assume the implicit Euler scheme
2149 m_spVolStabData->mass(pElem->vertex(co))
2150 -= porosity * (m_imDensityCo[ip] - m_imOldDensityCo[ip])
2151 * scv.volume();
2152 }
2153 }
2154
2155 if(m_BoussinesqEnergy)
2156 d(_T_,co) +=
2157 (porosity * m_imHeatCapacityFluid * m_BoussinesqDensity
2158 + (1 - porosity) * m_imHeatCapacitySolid * m_imMassDensitySolid)
2159 * u(_T_, co) * scv.volume();
2160 else
2161 d(_T_,co) +=
2162 (porosity * m_imHeatCapacityFluid * m_imDensityCo[ip]
2163 + (1 - porosity) * m_imHeatCapacitySolid * m_imMassDensitySolid)
2164 * u(_T_, co) * scv.volume();
2165 }
2166}
2167
2169template<typename TDomain>
2170template<typename TElem>
2172(
2173 LocalVector & d,
2174 const LocalVector & u,
2175 TElem * pElem,
2176 const position_type vCornerCoords []
2177)
2178{
2179// The porosity (constant per element)
2180 number porosity = m_imPorosity[0];
2181
2182// Loop Sub Control Volumes (SCV)
2183 for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ip++)
2184 {
2185 // Get current SCV
2186 const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv(ip);
2187
2188 // Fracture width ('/ 2' because every fracture is a boundary of 2 elements)
2189 number vol = scv.volume() * m_imAperture[0] / 2;
2190
2191 // Get associated node of the element (not side!)
2192 const int co = m_innerSideCo [scv.node_id()];
2193
2194 // Add to local matrix
2195 if(m_BoussinesqTransport)
2196 d(_C_,co) += porosity * u(_C_,co) * vol;
2197 else
2198 d(_C_,co) += porosity * m_imDensityCo[co] * u(_C_,co) * vol;
2199
2200 if(m_BoussinesqFlow)
2201 d(_P_,co) += porosity * vol;
2202 else
2203 {
2204 d(_P_,co) += porosity * m_imDensityCo[co] * vol;
2205
2206 if (m_bVolStabDataActive)
2207 {
2208 // Volume stabilization: Add the continuity equation to the transport equation
2209 // REMARK: We assume the implicit Euler scheme
2210 m_spVolStabData->mass(pElem->vertex(co))
2211 -= porosity * (m_imDensityCo[co] - m_imOldDensityCo[co]) * vol;
2212 }
2213 }
2214
2215 if(m_BoussinesqEnergy)
2216 d(_T_,co) +=
2217 (porosity * m_imHeatCapacityFluid * m_BoussinesqDensity
2218 + (1 - porosity) * m_imHeatCapacitySolid * m_imMassDensitySolid)
2219 * u(_T_, co) * vol;
2220 else
2221 d(_T_,co) +=
2222 (porosity * m_imHeatCapacityFluid * m_imDensityCo[co]
2223 + (1 - porosity) * m_imHeatCapacitySolid * m_imMassDensitySolid)
2224 * u(_T_, co) * vol;
2225 }
2226}
2227
2229template<typename TDomain>
2230template<typename TElem>
2232(
2233 LocalMatrix & J,
2234 const LocalVector & u,
2235 GridObject * elem,
2236 const position_type vCornerCoords []
2237)
2238{
2239 TElem * pElem = static_cast<TElem*> (elem);
2240
2241// call the specific routine:
2242 if (! m_isFracture)
2243 this->template bulk_ass_JM_elem<TElem> (J, u, pElem, vCornerCoords);
2244 else
2245 this->template fract_ass_JM_elem<TElem> (J, u, pElem, vCornerCoords);
2246}
2247
2249template<typename TDomain>
2250template<typename TElem>
2252(
2253 LocalMatrix & J,
2254 const LocalVector & u,
2255 TElem * pElem,
2256 const position_type vCornerCoords []
2257)
2258{
2259 typedef FV1Geometry<TElem, dim> TBulkFVGeom;
2260
2261// get finite volume geometry
2262 const TBulkFVGeom& bulk_geo = GeomProvider<TBulkFVGeom>::get();
2263
2264// The porosity is constant per element
2265 number porosity = m_imPorosity [0];
2266
2267// loop Sub Control Volumes (SCV)
2268 for (size_t ip = 0; ip < bulk_geo.num_scv(); ip++)
2269 {
2270 // get current SCV
2271 const typename TBulkFVGeom::SCV& scv = bulk_geo.scv(ip);
2272
2273 // get associated node
2274 const int co = scv.node_id();
2275
2276 // Add to local matrix
2277 if(m_BoussinesqTransport)
2278 J(_C_, co, _C_, co) += porosity * scv.volume();
2279 else
2280 J(_C_, co, _C_, co) +=
2281 porosity * scv.volume() *
2282 (m_imDensityCo[ip] + m_imDensityCo.deriv(ip, _C_, co) * u(_C_, co));
2283
2284 if(!m_BoussinesqFlow)
2285 {
2286 J(_P_, co, _C_, co) += porosity * m_imDensityCo.deriv(ip, _C_, co) * scv.volume();
2287
2288 if (m_bVolStabDataActive)
2289 {
2290 // Volume stabilization: Add the continuity equation to the transport equation
2291 // REMARK: We assume the implicit Euler scheme
2292 m_spVolStabData->mass(pElem->vertex(co))
2293 -= porosity * scv.volume() * (m_imDensityCo[ip] - m_imOldDensityCo[ip]);
2294
2295 /*TODO: Do we need this derivative? What we do is subtracting the defect of the flow
2296 * equation multiplied by _C_ from the transport equation. We differentiate the transport
2297 * equation, but not this artificial sink. Thus, we should skip this derivative. Otherwise
2298 * the contribution of the sink will not converge to 0 as soon as we approach the solution
2299 * of the system. However, in ug3, this derivative is present.
2300 *
2301 if(!m_imDensityScv.constant())
2302 m_spVolStabData->mass(pElem->vertex(co)) -=
2303 porosity * scv.volume() * m_imDensityCo.deriv(ip, _C_, co)*u(_C_, co);
2304 */
2305 }
2306 }
2307 //else
2308 //J(_P_, co, _C_, co) += 0;
2309
2310 if(m_BoussinesqEnergy)
2311 J(_T_, co, _T_, co) +=
2312 (porosity * m_imHeatCapacityFluid * m_BoussinesqDensity
2313 + (1 - porosity) * m_imHeatCapacitySolid * m_imMassDensitySolid)
2314 * scv.volume();
2315 else
2316 {
2317 J(_T_, co, _T_, co) +=
2318 (
2319 (porosity * m_imHeatCapacityFluid * m_imDensityCo[ip]
2320 + (1 - porosity) * m_imHeatCapacitySolid * m_imMassDensitySolid)
2321 + porosity * m_imHeatCapacityFluid * (m_imDensityCo.constant() ? 0.0 : m_imDensityCo.deriv(ip, _T_, co))
2322 * u(_T_, co)
2323 ) * scv.volume();
2324
2325 J(_T_, co, _C_, co) +=
2326 porosity * m_imHeatCapacityFluid * (m_imDensityCo.constant() ? 0.0 : m_imDensityCo.deriv(ip, _C_, co))
2327 * u(_T_, co) * scv.volume();
2328 }
2329 }
2330}
2331
2333template<typename TDomain>
2334template<typename TElem>
2336(
2337 LocalMatrix & J,
2338 const LocalVector & u,
2339 TElem * pElem,
2340 const position_type vCornerCoords []
2341)
2342{
2343// The porosity (constant per element)
2344 number porosity = m_imPorosity[0];
2345
2346// loop Sub Control Volumes (SCV)
2347 for (size_t ip = 0; ip < m_pFractGeo->num_scv(); ip++)
2348 {
2349 // get current SCV
2350 const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv(ip);
2351
2352 // Fracture width ('/ 2' because every fracture is a boundary of 2 elements)
2353 number vol = scv.volume() * m_imAperture[0] / 2;
2354
2355 // Get associated node of the element (not side!)
2356 const int co = m_innerSideCo [scv.node_id()];
2357
2358 // Add to local matrix
2359 if(m_BoussinesqTransport)
2360 J(_C_, co, _C_, co) += porosity * vol;
2361 else
2362 {
2363 J(_C_, co, _C_, co) +=
2364 porosity * vol *
2365 (m_imDensityCo[ip]
2366 + (m_imDensityCo.constant() ? 0.0 : m_imDensityCo.deriv(co, _C_, co)) * u(_C_, co));
2367 J(_C_, co, _T_, co) +=
2368 porosity * vol *
2369 (m_imDensityCo.constant() ? 0.0 : m_imDensityCo.deriv(co, _T_, co)) * u(_C_, co);
2370 }
2371
2372 if(!m_BoussinesqFlow){
2373 J(_P_, co, _C_, co) += porosity * (m_imDensityCo.constant() ? 0.0 : m_imDensityCo.deriv(co, _C_, co)) * vol;
2374 J(_P_, co, _T_, co) += porosity * (m_imDensityCo.constant() ? 0.0 : m_imDensityCo.deriv(co, _T_, co)) * vol;
2375
2376 if (m_bVolStabDataActive)
2377 {
2378 // Volume stabilization: Add the continuity equation to the transport equation
2379 // REMARK: We assume the implicit Euler scheme
2380 m_spVolStabData->mass(pElem->vertex(co))
2381 -= porosity * vol * (m_imDensityCo[co] - m_imOldDensityCo[co]);
2382
2383 /*TODO: Do we need this derivative? What we do is subtracting the defect of the flow
2384 * equation multiplied by _C_ from the transport equation. We differentiate the transport
2385 * equation, but not this artificial sink. Thus, we should skip this derivative. Otherwise
2386 * the contribution of the sink will not converge to 0 as soon as we approach the solution
2387 * of the system. However, in ug3, this derivative is present.
2388 *
2389 if(!m_imDensityScv.constant())
2390 m_spVolStabData->mass(pElem->vertex(co)) -=
2391 porosity * vol * m_imDensityCo.deriv(co, _C_, co)*u(_C_, co);
2392 */
2393 }
2394 }
2395 //else
2396 //J(_P_, co, _C_, co) += 0;
2397 //J(_P_, co, _T_, co) += 0;
2398
2399
2400 if(m_BoussinesqEnergy)
2401 J(_T_,co, _T_, co) += vol *
2402 (porosity * m_imHeatCapacityFluid * m_BoussinesqDensity
2403 + (1 - porosity) * m_imHeatCapacitySolid * m_imMassDensitySolid);
2404 else
2405 {
2406 J(_T_, co, _T_, co) += vol *
2407 (
2408 (porosity * m_imHeatCapacityFluid * m_imDensityCo[co]
2409 + (1 - porosity) * m_imHeatCapacitySolid * m_imMassDensitySolid)
2410 + porosity * m_imHeatCapacityFluid * (m_imDensityCo.constant() ? 0.0 : m_imDensityCo.deriv(co, _T_, co))
2411 * u(_T_, co)
2412 );
2413
2414 J(_T_, co, _C_, co) += vol *
2415 porosity * m_imHeatCapacityFluid * (m_imDensityCo.constant() ? 0.0 : m_imDensityCo.deriv(co, _C_, co))
2416 * u(_T_, co);
2417 }
2418
2419 // Remark: Other addings are zero
2420 //J(_C_, co, _P_, co) += 0;
2421 //J(_P_, co, _P_, co) += 0;
2422 //J(_T_, co, _P_, co) += 0;
2423 }
2424}
2425
2427template<typename TDomain>
2428template<typename TElem>
2430(
2431 LocalVector & b,
2432 GridObject * elem,
2433 const position_type vCornerCoords []
2434)
2435{
2436}
2437
2439// implementation of the export parameters
2441
2443template<typename TDomain>
2444template<typename TElem>
2446ex_brine(number vValue[],
2447 const MathVector<dim> vGlobIP[],
2448 number time, int si,
2449 const LocalVector& u,
2450 GridObject* elem,
2451 const MathVector<dim> vCornerCoords[],
2452 const MathVector<dim> vLocIP[],
2453 const size_t nip,
2454 bool bDeriv,
2455 std::vector<std::vector<number> > vvvDeriv[])
2456{
2457// reference element
2458 typedef typename reference_element_traits<TElem>::reference_element_type ref_elem_type;
2459
2460// number of shape functions
2461 static const size_t numSH = ref_elem_type::numCorners;
2462
2463// get trial space
2465
2466// storage for shape function at ip
2467 number vShape[numSH];
2468
2469// loop ips
2470 for(size_t ip = 0; ip < nip; ++ip)
2471 {
2472 // evaluate at shapes at ip
2473 rTrialSpace.shapes(vShape, vLocIP[ip]);
2474
2475 // compute concentration at ip
2476 vValue[ip] = 0.0;
2477 for(size_t sh = 0; sh < numSH; ++sh)
2478 vValue[ip] += u(_C_, sh) * vShape[sh];
2479
2480 // compute derivative w.r.t. to unknowns iff needed
2481 if(bDeriv)
2482 for(size_t sh = 0; sh < numSH; ++sh)
2483 {
2484 vvvDeriv[ip][_C_][sh] = vShape[sh];
2485 vvvDeriv[ip][_P_][sh] = 0.0;
2486 vvvDeriv[ip][_T_][sh] = 0.0;
2487 }
2488 }
2489}
2490
2492template<typename TDomain>
2493template<typename TElem>
2495ex_pressure(number vValue[],
2496 const MathVector<dim> vGlobIP[],
2497 number time, int si,
2498 const LocalVector& u,
2499 GridObject* elem,
2500 const MathVector<dim> vCornerCoords[],
2501 const MathVector<dim> vLocIP[],
2502 const size_t nip,
2503 bool bDeriv,
2504 std::vector<std::vector<number> > vvvDeriv[])
2505{
2506// reference element
2507 typedef typename reference_element_traits<TElem>::reference_element_type ref_elem_type;
2508
2509// number of shape functions
2510 static const size_t numSH = ref_elem_type::numCorners;
2511
2512// get trial space
2514
2515// storage for shape function at ip
2516 number vShape[numSH];
2517
2518// loop ips
2519 for(size_t ip = 0; ip < nip; ++ip)
2520 {
2521 // evaluate at shapes at ip
2522 rTrialSpace.shapes(vShape, vLocIP[ip]);
2523
2524 // compute concentration at ip
2525 vValue[ip] = 0.0;
2526 for(size_t sh = 0; sh < numSH; ++sh)
2527 vValue[ip] += u(_P_, sh) * vShape[sh];
2528
2529 // compute derivative w.r.t. to unknowns iff needed
2530 if(bDeriv)
2531 for(size_t sh = 0; sh < numSH; ++sh)
2532 {
2533 vvvDeriv[ip][_P_][sh] = vShape[sh];
2534 vvvDeriv[ip][_C_][sh] = 0.0;
2535 vvvDeriv[ip][_T_][sh] = 0.0;
2536 }
2537 }
2538}
2539
2541template<typename TDomain>
2542template<typename TElem>
2544ex_temperature(number vValue[],
2545 const MathVector<dim> vGlobIP[],
2546 number time, int si,
2547 const LocalVector& u,
2548 GridObject* elem,
2549 const MathVector<dim> vCornerCoords[],
2550 const MathVector<dim> vLocIP[],
2551 const size_t nip,
2552 bool bDeriv,
2553 std::vector<std::vector<number> > vvvDeriv[])
2554{
2555// reference element
2556 typedef typename reference_element_traits<TElem>::reference_element_type ref_elem_type;
2557
2558// number of shape functions
2559 static const size_t numSH = ref_elem_type::numCorners;
2560
2561// get trial space
2563
2564// storage for shape function at ip
2565 number vShape[numSH];
2566
2567// loop ips
2568 for(size_t ip = 0; ip < nip; ++ip)
2569 {
2570 // evaluate at shapes at ip
2571 rTrialSpace.shapes(vShape, vLocIP[ip]);
2572
2573 // compute concentration at ip
2574 vValue[ip] = 0.0;
2575 for(size_t sh = 0; sh < numSH; ++sh)
2576 vValue[ip] += u(_T_, sh) * vShape[sh];
2577
2578 // compute derivative w.r.t. to unknowns iff needed
2579 if(bDeriv)
2580 for(size_t sh = 0; sh < numSH; ++sh)
2581 {
2582 vvvDeriv[ip][_T_][sh] = vShape[sh];
2583 vvvDeriv[ip][_C_][sh] = 0.0;
2584 vvvDeriv[ip][_P_][sh] = 0.0;
2585 }
2586 }
2587}
2588
2590template<typename TDomain>
2591template<typename TElem>
2594(
2595 MathVector<dim> vValue[],
2596 const MathVector<dim> vGlobIP[],
2597 number time, int si,
2598 const LocalVector& u,
2599 GridObject* elem,
2600 const MathVector<dim> vCornerCoords[],
2601 const MathVector<dim> vLocIP[],
2602 const size_t nip,
2603 bool bDeriv,
2604 std::vector<std::vector<MathVector<dim> > > vvvDeriv[]
2605)
2606{
2607 if (m_isFracture)
2608 {
2609 typedef StdLinConsistentGravity<low_dim> TConsGravity;
2610
2611 // this evaluation is implemented only for the standard set of the IPs
2612 if (nip != m_pFractGeo->num_scvf())
2613 UG_THROW ("FractTHF_FV1: The Darcy velocity export parameter is only implemented for the standard set of IPs.");
2614
2615 // number of shape functions
2616 const size_t numSh = m_pFractGeo->num_sh();
2617
2618 MathVector<dim> Vel;
2619 MathVector<dim> Vel_c[maxFractSideCorners], Vel_p[maxFractSideCorners], Vel_T[maxFractSideCorners];
2620 number vViscosity_c [maxFractSideCorners], * pViscosity_c;
2621 number vViscosity_T [maxFractSideCorners], * pViscosity_T;
2622
2623 // Get the corner values
2624 number vDensity [maxFractSideCorners];
2625 number vPressure [maxFractSideCorners];
2626 for (size_t sh = 0; sh < numSh; sh++)
2627 {
2628 size_t co = m_innerSideCo[sh];
2629 vDensity[sh] = m_imDensityCo[co];
2630 vPressure[sh] = u(_P_, co);
2631 }
2632
2633 // Consistent gravity and its derivative at corners
2634 TConsGravity ConsGravityMethod;
2635 MathVector<low_dim> vConsGravity [maxFractSideCorners];
2636 MathVector<low_dim> vConsGravity_c [maxFractSideCorners][maxFractSideCorners];
2637 MathVector<low_dim> vConsGravity_T [maxFractSideCorners][maxFractSideCorners];
2638
2639 // Prepare the consistent gravity
2640 try
2641 {
2642 ConsGravityMethod.template prepare<dim>
2643 (vConsGravity, numSh, m_pFractGeo->corners(), vDensity, m_Gravity);
2644
2645 if(bDeriv)
2646 {
2647 number co_density [maxFractSideCorners];
2648 memset (co_density, 0, numSh * sizeof (number));
2649 for (size_t sh = 0; sh < numSh; sh++)
2650 { //TODO: use scv, not merely shape id here!
2651 size_t co = m_innerSideCo[sh];
2652 if(!m_imDensityCo.constant())
2653 co_density[sh] = m_imDensityCo.deriv (co, _C_, co); // we assume the completely local dependence of \f$\rho\f$ of \f$c\f$
2654 ConsGravityMethod.template prepare<dim>
2655 (vConsGravity_c[sh], numSh, m_pFractGeo->corners(), co_density, m_Gravity);
2656 co_density[sh] = 0.0;
2657 }
2658 for (size_t sh = 0; sh < numSh; sh++)
2659 { //TODO: use scv, not merely shape id here!
2660 size_t co = m_innerSideCo[sh];
2661 if(!m_imDensityCo.constant())
2662 co_density[sh] = m_imDensityCo.deriv (co, _T_, co); // we assume the completely local dependence of \f$\rho\f$ of \f$c\f$
2663 ConsGravityMethod.template prepare<dim>
2664 (vConsGravity_T[sh], numSh, m_pFractGeo->corners(), co_density, m_Gravity);
2665 co_density[sh] = 0.0;
2666 }
2667 }
2668 }
2669 UG_CATCH_THROW ("FractTHF_FV1::fract_ass_dA_elem: Cannot prepare Consistent Gravity.");
2670
2671 // Loop the ips
2672 for (size_t ip = 0; ip < nip; ip++)
2673 {
2674 // Darcy velocity to be filled
2675 MathVector<dim>& DarcyVel = vValue[ip];
2676
2677 // Compute the Darcy velocity at the ips and the convection shapes
2678 this->template compute_ip_Darcy_velocity<TFractFVGeom, TConsGravity>
2679 (Vel, ip, *m_pFractGeo, ConsGravityMethod, vConsGravity, vPressure,
2680 m_imViscosityIP[ip]);
2681 VecScale (DarcyVel, Vel, m_imFractPermeability[0]);
2682
2683 // Compute the derivatives
2684 if(bDeriv)
2685 {
2686 // Derivatives to be filled
2687 MathVector<dim>* DarcyVel_c = &vvvDeriv[ip][_C_][0];
2688 MathVector<dim>* DarcyVel_p = &vvvDeriv[ip][_P_][0];
2689 MathVector<dim>* DarcyVel_T = &vvvDeriv[ip][_T_][0];
2690
2691 // Clear all the derivatives (as we fill up not all of them):
2692 for (size_t co = 0; co < vvvDeriv[ip][_C_].size(); co++)
2693 DarcyVel_c[co] = 0.0;
2694 for (size_t co = 0; co < vvvDeriv[ip][_P_].size(); co++)
2695 DarcyVel_p[co] = 0.0;
2696 for (size_t co = 0; co < vvvDeriv[ip][_T_].size(); co++)
2697 DarcyVel_T[co] = 0.0;
2698
2699 // Compute the derivative of the viscosity
2700 if (m_imViscosityIP.constant ())
2701 {
2702 pViscosity_c = NULL;
2703 pViscosity_T = NULL;
2704 }
2705 else
2706 {
2707 for (size_t sh = 0; sh < numSh; sh++)
2708 {
2709 size_t co = m_innerSideCo[sh];
2710 vViscosity_c[sh] = m_imViscosityIP.deriv(ip, _C_, co);
2711 vViscosity_T[sh] = m_imViscosityIP.deriv(ip, _T_, co);
2712 }
2713 pViscosity_c = vViscosity_c;
2714 pViscosity_T = vViscosity_T;
2715 }
2716
2717 // Compute derivatives of the Darcy velocity
2718 this->template compute_J_ip_Darcy_velocity <TFractFVGeom, TConsGravity, maxFractSideCorners>
2719 (Vel, Vel_c, Vel_p, Vel_T, ip, *m_pFractGeo, ConsGravityMethod,
2720 vConsGravity_c, vConsGravity_T, vPressure,
2721 m_imViscosityIP[ip], pViscosity_c, pViscosity_T);
2722 for (size_t sh = 0; sh < numSh; sh++)
2723 {
2724 size_t co = m_innerSideCo[sh];
2725 VecScale (DarcyVel_c[co], Vel_c[sh], m_imFractPermeability[0]);
2726 VecScale (DarcyVel_p[co], Vel_p[sh], m_imFractPermeability[0]);
2727 VecScale (DarcyVel_T[co], Vel_T[sh], m_imFractPermeability[0]);
2728 }
2729 }
2730 }
2731 }
2732 else
2733 UG_THROW ("FractTHF_FV1: The Darcy velocity export parameter is currently implemented only for fractures.");
2734}
2735
2736
2738template<typename TDomain>
2739template<typename TElem>
2742(
2743 number vValue[],
2744 const MathVector<dim> vGlobIP[],
2745 number time, int si,
2746 const LocalVector& u,
2747 GridObject* elem,
2748 const MathVector<dim> vCornerCoords[],
2749 const MathVector<dim> vLocIP[],
2750 const size_t nip,
2751 bool bDeriv,
2752 std::vector<std::vector<number> > vvvDeriv[]
2753)
2754{
2755 if (m_isFracture)
2756 {
2757 // this evaluation is implemented only for the standard set of the IPs
2758 if (nip != m_pFractGeo->num_scv())
2759 UG_THROW ("FractDDF_FV1: The Darcy velocity export parameter is only implemented for the standard set of IPs.");
2760
2761 const number half_fr_width = m_imAperture[0] / 2;
2762
2763 // loop over the corners of the inner side
2764 for (size_t ip = 0; ip < nip; ip++)
2765 {
2766 // Get current SCV
2767 const typename TFractFVGeom::SCV& scv = m_pFractGeo->scv(ip);
2768 number& orthVelocity = vValue[ip];
2769
2770 // Get associated node of the element (not side!)
2771 const int co = m_innerSideCo [scv.node_id()];
2772
2773 // Get the corner values
2774 const number orthP_f = u(_P_, co);
2775 const number orthP_m = u(_P_, m_assCo[co]);
2776 const number fractDensity = m_imDensityCo[co];
2777 const number orthDensity = m_imDensityCo [m_assCo[co]];
2778 const number orthViscosity = m_imViscosityCo [m_assCo[co]];
2779
2780 // Flux velocity between the fracture and the bulk medium
2781 orthVelocity = (m_orthGravity * (orthDensity - fractDensity)
2782 - (orthP_m - orthP_f) / half_fr_width)
2783 * m_imOrthoPermeability[0];
2784
2785 // Compute the derivatives
2786 if(bDeriv)
2787 {
2788 // Derivatives to be filled
2789 number* DarcyVel_c = &vvvDeriv[ip][_C_][0]; // array indexed by the shape
2790 number* DarcyVel_p = &vvvDeriv[ip][_P_][0]; // array indexed by the shape
2791 number* DarcyVel_T = &vvvDeriv[ip][_T_][0]; // array indexed by the shape
2792
2793 // Clear all the derivatives (as we fill up not all of them):
2794 for (size_t i = 0; i < vvvDeriv[ip][_C_].size(); i++) DarcyVel_c[i] = 0;
2795 for (size_t i = 0; i < vvvDeriv[ip][_P_].size(); i++) DarcyVel_p[i] = 0;
2796 for (size_t i = 0; i < vvvDeriv[ip][_T_].size(); i++) DarcyVel_p[i] = 0;
2797
2798 // Compute the derivatives:
2799 number D_fractDensity_c, D_orthDensity_c, D_fractDensity_T, D_orthDensity_T;
2800 if (! m_imDensityCo.constant())
2801 {
2802 D_fractDensity_c = m_imDensityCo.deriv (co, _C_, co);
2803 D_fractDensity_T = m_imDensityCo.deriv (co, _T_, co);
2804 D_orthDensity_c = m_imDensityCo.deriv (m_assCo[co], _C_, m_assCo[co]);
2805 D_orthDensity_T = m_imDensityCo.deriv (m_assCo[co], _T_, m_assCo[co]);
2806 }
2807 else
2808 D_fractDensity_c = D_fractDensity_T = D_orthDensity_c = D_orthDensity_T = 0;
2809
2810 const number orthViscosity = m_imViscosityCo [m_assCo[co]];
2811 number D_orthViscosity_c, D_orthViscosity_T;
2812 if (! m_imViscosityCo.constant())
2813 {
2814 D_orthViscosity_c = m_imViscosityCo.deriv (m_assCo[co], _C_, m_assCo[co]);
2815 D_orthViscosity_T = m_imViscosityCo.deriv (m_assCo[co], _T_, m_assCo[co]);
2816 }
2817 else
2818 D_orthViscosity_c = D_orthViscosity_T = 0;
2819
2820 number D_orthVelocity [3], D_orthVelocity_fr [3]; // 3 components: w.r.t. _C_, _P_ and _T_ resp.
2821
2822 D_orthVelocity [_C_] = (m_orthGravity * D_orthDensity_c
2823 * m_imOrthoPermeability[0] * orthViscosity
2824 - orthVelocity * D_orthViscosity_c) / orthViscosity / orthViscosity;
2825
2826 D_orthVelocity_fr [_C_] = - m_orthGravity * D_fractDensity_c
2827 * m_imOrthoPermeability[0] / orthViscosity;
2828
2829 D_orthVelocity [_P_] = - m_imOrthoPermeability[0]
2830 / half_fr_width / orthViscosity;
2831
2832 D_orthVelocity_fr [_P_] = - D_orthVelocity [_P_];
2833
2834 D_orthVelocity [_T_] = (m_orthGravity * D_orthDensity_T
2835 * m_imOrthoPermeability[0] * orthViscosity
2836 - orthVelocity * D_orthViscosity_T) / orthViscosity / orthViscosity;
2837
2838 D_orthVelocity_fr [_T_] = - m_orthGravity * D_fractDensity_T
2839 * m_imOrthoPermeability[0] / orthViscosity;
2840
2841 DarcyVel_c[co] = D_orthVelocity_fr[_C_];
2842 DarcyVel_p[co] = D_orthVelocity_fr[_P_];
2843 DarcyVel_T[co] = D_orthVelocity_fr[_T_];
2844
2845 DarcyVel_c[m_assCo[co]] = D_orthVelocity[_C_];
2846 DarcyVel_p[m_assCo[co]] = D_orthVelocity[_P_];
2847 DarcyVel_T[m_assCo[co]] = D_orthVelocity[_T_];
2848 }
2849
2850 // The viscosity:
2851 orthVelocity /= orthViscosity;
2852 }
2853 }
2854 else
2855 UG_THROW ("FractTHF_FV1: The orthogonal Darcy velocity export parameter is implemented only for fractures.");
2856}
2857
2859// register assembling functions
2861
2863template<typename TDomain>
2864template<typename TElem> // the element to register for
2866{
2868 static const int refDim = reference_element_traits<TElem>::dim;
2869
2870 this->clear_add_fct(id);
2871
2872 this->set_prep_elem_loop_fct(id, & this_type::template prepare_element_loop<TElem>);
2873 this->set_prep_elem_fct (id, & this_type::template prepare_element<TElem>);
2874 this->set_fsh_elem_loop_fct (id, & this_type::template finish_element_loop<TElem>);
2875 this->set_add_jac_A_elem_fct(id, & this_type::template ass_JA_elem<TElem>);
2876 this->set_add_jac_M_elem_fct(id, & this_type::template ass_JM_elem<TElem>);
2877 this->set_add_def_A_elem_fct(id, & this_type::template ass_dA_elem<TElem>);
2878 this->set_add_def_M_elem_fct(id, & this_type::template ass_dM_elem<TElem>);
2879 this->set_add_rhs_elem_fct (id, & this_type::template ass_rhs_elem<TElem>);
2880
2881 m_exBrine->template set_fct<this_type, refDim> (id, this, &this_type::template ex_brine<TElem>);
2882 m_exPressure->template set_fct<this_type, refDim> (id, this, &this_type::template ex_pressure<TElem>);
2883 m_exTemperature->template set_fct<this_type, refDim> (id, this, &this_type::template ex_temperature<TElem>);
2884 m_exFractDarcyVel->template set_fct<this_type,refDim>(id, this, &this_type::template ex_darcy_fract<TElem>);
2885 m_exOrthoFractDarcyVel->template set_fct<this_type,refDim>(id, this, &this_type::template ex_darcy_ortho_fract<TElem>);
2886}
2887
2891template <typename TDomain>
2893(
2894 const char* functions,
2895 const char* subsets
2896)
2897: IElemDisc<TDomain> (functions, subsets)
2898{
2899 init();
2900};
2901
2902template <typename TDomain>
2904(
2905 const std::vector<std::string>& vFct,
2906 const std::vector<std::string>& vSubset
2907)
2908: IElemDisc<TDomain> (vFct, vSubset)
2909{
2910 init();
2911};
2912
2913template <typename TDomain>
2915{
2916 set_boussinesq (false);
2917
2918 m_imDensityCo.set_comp_lin_defect (false);
2919 m_imOldDensityCo.set_comp_lin_defect (false);
2920 m_imDensityIP.set_comp_lin_defect (false),
2921 m_imViscosityCo.set_comp_lin_defect (false);
2922 m_imViscosityIP.set_comp_lin_defect (false);
2923 m_imConstGravity.set_comp_lin_defect (false);
2924 m_imPorosity.set_comp_lin_defect (false);
2925 m_imPermeability .set_comp_lin_defect(false);
2926 m_imDiffusion.set_comp_lin_defect (false);
2927 m_imThermalConductivity.set_comp_lin_defect (false);
2928 m_imAperture.set_comp_lin_defect (false);
2929 m_imFractPermeability.set_comp_lin_defect (false);
2930 m_imOrthoPermeability.set_comp_lin_defect (false);
2931 m_imFractDiffusion.set_comp_lin_defect (false);
2932 m_imOrthoDiffusion.set_comp_lin_defect (false);
2933 m_imFractThermCond.set_comp_lin_defect (false);
2934 m_imOrthoThermCond.set_comp_lin_defect (false);
2935 m_spUpwind = make_sp(new ConvectionShapesFullUpwind<dim>);
2936 m_spUpwindEnergy = make_sp(new ConvectionShapesFullUpwind<dim>);
2937 m_imFractDarcyVelIP.set_comp_lin_defect (false);
2938
2939 m_spVolStabData = SPNULL;
2940
2941 std::string functions;
2942 for(size_t i = 0; i < this->symb_fcts().size(); ++i)
2943 {
2944 if(i > 0) functions.append(",");
2945 functions.append(this->symb_fcts()[i]);
2946 }
2947
2948 m_exBrine = make_sp (new DataExport<number, dim> (functions.c_str()));
2949 m_exPressure = make_sp (new DataExport<number, dim> (functions.c_str()));
2950 m_exTemperature = make_sp (new DataExport<number, dim> (functions.c_str()));
2951 m_exFractDarcyVel = make_sp (new DataExport<MathVector<dim>, dim>(functions.c_str()));
2952 m_exOrthoFractDarcyVel = make_sp (new DataExport<number, dim>(functions.c_str()));
2953
2954// check number of functions
2955 if (this->num_fct () != 3)
2956 UG_THROW ("Wrong number of functions: The ElemDisc 'FractTHF_FV1'"
2957 " needs exactly 3 symbolic function"
2958 " (one for the mass fraction and one for the pressure).");
2959
2960// register imports
2961
2962 this->register_import (m_imDensityCo);
2963 this->register_import (m_imOldDensityCo);
2964 this->register_import (m_imDensityIP);
2965 this->register_import (m_imViscosityCo);
2966 this->register_import (m_imViscosityIP);
2967 this->register_import (m_imConstGravity);
2968
2969 this->register_import (m_imPorosity);
2970
2971 this->register_import (m_imPermeability);
2972 this->register_import (m_imDiffusion);
2973 this->register_import (m_imThermalConductivity);
2974
2975 this->register_import (m_imAperture);
2976 this->register_import (m_imFractPermeability);
2977 this->register_import (m_imOrthoPermeability);
2978 this->register_import (m_imFractDiffusion);
2979 this->register_import (m_imOrthoDiffusion);
2980 this->register_import (m_imFractThermCond);
2981 this->register_import (m_imOrthoThermCond);
2982
2983 this->register_import(m_imFractDarcyVelIP);
2984
2985// connect to own export
2986 m_imFractDarcyVelIP.set_data(m_exFractDarcyVel);
2987
2988// register the local assembling functions
2989 boost::mpl::for_each<AssembleElemList> (RegisterLocalDiscr (this));
2990
2991}
2992
2993} // namespace d3f
2994} // end namespace ug
2995
2996/* End of File */
parameterString s
Definition Biogas.lua:2
void shapes(shape_type *vShape, const MathVector< dim > &x) const
virtual void local_to_global(MathVector< worldDim > &globPos, const MathVector< dim > &locPos) const=0
virtual void update(const MathVector< worldDim > *vCornerCoord)=0
const MathVector< dim > & position()
static TGeom & get()
const MathVector< dim > & D_vel(size_t scvf, size_t sh) const
static TClass & get()
void bulk_ass_dM_elem(LocalVector &d, const LocalVector &u, TElem *elem, const position_type vCornerCoords[])
computes the mass part of the defect of a time-dependent problem on a bulk element
Definition fract_thf_fv1_impl.h:2109
void fract_ass_dA_elem(LocalVector &d, const LocalVector &u, TElem *elem, const position_type vCornerCoords[])
computes the stiffness part of the local defect on a fracture element
Definition fract_thf_fv1_impl.h:670
FractTHF_FV1(const char *functions, const char *subsets)
class constructor
Definition fract_thf_fv1_impl.h:2893
base_type::position_type position_type
position type
Definition fract_thf_fv1.h:78
void ass_dM_elem(LocalVector &d, const LocalVector &u, GridObject *elem, const position_type vCornerCoords[])
computes the mass part of the defect of a time-dependent problem
Definition fract_thf_fv1_impl.h:2089
void prepare_element(const LocalVector &u, GridObject *elem, ReferenceObjectID roid, const position_type vCornerCoords[])
prepares a given element for assembling
Definition fract_thf_fv1_impl.h:249
virtual void prep_assemble_loop()
called once bevore assembling
Definition fract_thf_fv1_impl.h:65
void fract_prepare_element(const LocalVector &u, TElem *elem, const position_type vCornerCoords[])
prepares a given fracture element for assembling
Definition fract_thf_fv1_impl.h:311
void fract_bulk_ass_dA_elem(LocalVector &d, const LocalVector &u, TElem *elem, const position_type vCornerCoords[])
computes the stiffness fracture-bulk interaction terms of the local defect on a fracture element
Definition fract_thf_fv1_impl.h:841
void fract_ass_dM_elem(LocalVector &d, const LocalVector &u, TElem *elem, const position_type vCornerCoords[])
computes the mass part of the defect of a time-dependent problem on a fracture element
Definition fract_thf_fv1_impl.h:2172
void fract_ass_JM_elem(LocalMatrix &J, const LocalVector &u, TElem *elem, const position_type vCornerCoords[])
computes the mass matrix of a time-dependent problem on a fracture element
Definition fract_thf_fv1_impl.h:2336
void register_loc_discr_func()
registers the local assembler functions for a given element
Definition fract_thf_fv1_impl.h:2865
void ass_rhs_elem(LocalVector &d, GridObject *elem, const position_type vCornerCoords[])
computes the right-hand side due to the sources
Definition fract_thf_fv1_impl.h:2430
void bulk_prepare_element_loop(ReferenceObjectID roid, int si)
prepares the loop over the elements: the 'bulk' version
Definition fract_thf_fv1_impl.h:134
void ex_temperature(number vValue[], const MathVector< dim > vGlobIP[], number time, int si, const LocalVector &u, GridObject *elem, const MathVector< dim > vCornerCoords[], const MathVector< dim > vLocIP[], const size_t nip, bool bDeriv, std::vector< std::vector< number > > vvvDeriv[])
export parameter for the temperature (to compute density and viscosity)
Definition fract_thf_fv1_impl.h:2544
void bulk_ass_JM_elem(LocalMatrix &J, const LocalVector &u, TElem *elem, const position_type vCornerCoords[])
computes the mass matrix of a time-dependent problem on a bulk element
Definition fract_thf_fv1_impl.h:2252
void bulk_ass_JA_elem(LocalMatrix &J, const LocalVector &u, TElem *elem, const position_type vCornerCoords[])
computes the local stiffness matrix on a bulk element
Definition fract_thf_fv1_impl.h:1001
void ex_darcy_fract(MathVector< dim > vValue[], const MathVector< dim > vGlobIP[], number time, int si, const LocalVector &u, GridObject *elem, const MathVector< dim > vCornerCoords[], const MathVector< dim > vLocIP[], const size_t nip, bool bDeriv, std::vector< std::vector< MathVector< dim > > > vvvDeriv[])
export parameter for the Darcy velocity in the fracture
Definition fract_thf_fv1_impl.h:2594
void ass_JM_elem(LocalMatrix &J, const LocalVector &u, GridObject *elem, const position_type vCornerCoords[])
computes the mass matrix of a time-dependent problem
Definition fract_thf_fv1_impl.h:2232
void bulk_ass_dA_elem(LocalVector &d, const LocalVector &u, TElem *elem, const position_type vCornerCoords[])
computes the stiffness part of the local defect on a bulk element
Definition fract_thf_fv1_impl.h:471
void ass_dA_elem(LocalVector &d, const LocalVector &u, GridObject *elem, const position_type vCornerCoords[])
computes the stiffness part of the local defect
Definition fract_thf_fv1_impl.h:446
void bulk_prepare_element(const LocalVector &u, TElem *elem, const position_type vCornerCoords[])
prepares a given bulk element for assembling
Definition fract_thf_fv1_impl.h:269
void init()
Definition fract_thf_fv1_impl.h:2914
void ex_pressure(number vValue[], const MathVector< dim > vGlobIP[], number time, int si, const LocalVector &u, GridObject *elem, const MathVector< dim > vCornerCoords[], const MathVector< dim > vLocIP[], const size_t nip, bool bDeriv, std::vector< std::vector< number > > vvvDeriv[])
export parameter for the pressure
Definition fract_thf_fv1_impl.h:2495
void ass_sss_JA_elem(LocalMatrix &J, const LocalVector &u, TElem *pElem, size_t co, number intensity, number concentration, number temperature, number factor=1)
assembles a singular source or sink in the jacobian
Definition fract_thf_fv1_impl.h:2012
void fract_prepare_element_loop(ReferenceObjectID roid, int si)
prepares the loop over the elements: the 'fracture' version
Definition fract_thf_fv1_impl.h:191
void ex_darcy_ortho_fract(number vValue[], const MathVector< dim > vGlobIP[], number time, int si, const LocalVector &u, GridObject *elem, const MathVector< dim > vCornerCoords[], const MathVector< dim > vLocIP[], const size_t nip, bool bDeriv, std::vector< std::vector< number > > vvvDeriv[])
export parameter for the orthogonal Darcy velocity
Definition fract_thf_fv1_impl.h:2742
void compute_J_ip_Darcy_velocity(MathVector< dim > &Vel, MathVector< dim > Vel_c[], MathVector< dim > Vel_p[], MathVector< dim > Vel_T[], size_t ip, const TFVGeom &geo, TConsGravity &ConsGravityMethod, MathVector< TFVGeom::dim > vConsGravity_c[][maxCorners], MathVector< TFVGeom::dim > vConsGravity_T[][maxCorners], number vPressure[], number Viscosity, number Viscosity_c[], number Viscosity_T[])
computes the derivatives of the Darcy velocity (not scaled with the permeability)
Definition fract_thf_fv1_impl.h:927
void ass_sss_dA_elem(LocalVector &d, const LocalVector &u, TElem *pElem, size_t co, number intensity, number concentration, number temperature, number factor=1)
assembles a singular source or sink in the defect
Definition fract_thf_fv1_impl.h:1965
void prepare_element_loop(ReferenceObjectID roid, int si)
prepares the loop over the elements: checks whether the parameters are set, ...
Definition fract_thf_fv1_impl.h:83
void ex_brine(number vValue[], const MathVector< dim > vGlobIP[], number time, int si, const LocalVector &u, GridObject *elem, const MathVector< dim > vCornerCoords[], const MathVector< dim > vLocIP[], const size_t nip, bool bDeriv, std::vector< std::vector< number > > vvvDeriv[])
export parameter for the concentration (to compute density and viscosity)
Definition fract_thf_fv1_impl.h:2446
void ass_JA_elem(LocalMatrix &J, const LocalVector &u, GridObject *elem, const position_type vCornerCoords[])
computes the local stiffness matrix
Definition fract_thf_fv1_impl.h:978
void compute_ip_Darcy_velocity(MathVector< dim > &Vel, size_t ip, const TFVGeom &bulk_geo, TConsGravity &ConsGravityMethod, MathVector< TFVGeom::dim > vConsGravity[], number vPressure[], number Viscosity)
computes the Darcy velocity (not scaled with the permeability)
Definition fract_thf_fv1_impl.h:418
virtual void prepare_setting(const std::vector< LFEID > &vLfeID, bool bNonRegular)
check type of the grid and the trial space
Definition fract_thf_fv1_impl.h:39
void finish_element_loop()
finalizes the loop over the elements
Definition fract_thf_fv1_impl.h:241
void fract_ass_JA_elem(LocalMatrix &J, const LocalVector &u, TElem *elem, const position_type vCornerCoords[])
computes the local stiffness matrix on a fracture element
Definition fract_thf_fv1_impl.h:1372
void fract_bulk_ass_JA_elem(LocalMatrix &J, const LocalVector &u, TElem *elem, const position_type vCornerCoords[])
computes the local stiffness matrix of the fracture-bulk interaction terms on a fracture element
Definition fract_thf_fv1_impl.h:1700
Definition d3f_sss.h:324
function get(x, y, z, t)
function util d3f parse Viscosity(ViscosityDesc, w)
SmartPtr< TSubsetHandler > subset_handler()
SmartPtr< TGrid > grid()
void MatSet(matrix_t &mInOut, typename matrix_t::value_type s)
void MatDiagSet(matrix_t &mInOut, typename matrix_t::value_type s)
void MatScale(matrix_t &mOut, typename matrix_t::value_type s, const matrix_t &m)
const NullSmartPtr SPNULL
#define UG_CATCH_THROW(msg)
#define UG_THROW(msg)
double number
void MatVecMult(vector_t_out &vOut, const matrix_t &m, const vector_t_in &v)
vector_t::value_type VecLength(const vector_t &v)
void VecScaleAppend(vector_t &vOut, typename vector_t::value_type s1, const vector_t &v1)
vector_t::value_type VecDistance(const vector_t &v1, const vector_t &v2)
void VecScale(vector_t &vOut, const vector_t &v, typename vector_t::value_type s)
vector_t::value_type VecDot(const vector_t &v1, const vector_t &v2)
ReferenceObjectID
void VecSet(vector_t &dest, number alpha, const std::vector< size_t > vIndex)
SmartPtr< T, FreePolicy > make_sp(T *inst)
Definition fract_thf_fv1.h:677