Loading [MathJax]/extensions/tex2jax.js
Plugins
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
richards_linker.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020-2015: G-CSC, Goethe University Frankfurt
3 * Author: Arne Naegel
4 *
5 * This file is part of UG4.
6 *
7 * UG4 is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License version 3 (as published by the
9 * Free Software Foundation) with the following additional attribution
10 * requirements (according to LGPL/GPL v3 §7):
11 *
12 * (1) The following notice must be displayed in the Appropriate Legal Notices
13 * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
14 *
15 * (2) The following notice must be displayed at a prominent place in the
16 * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
17 *
18 * (3) The following bibliography is recommended for citation and must be
19 * preserved in all covered files:
20 * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
21 * parallel geometric multigrid solver on hierarchically distributed grids.
22 * Computing and visualization in science 16, 4 (2013), 151-164"
23 * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
24 * flexible software system for simulating pde based models on high performance
25 * computers. Computing and visualization in science 16, 4 (2013), 165-179"
26 *
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU Lesser General Public License for more details.
31 */
32
33#ifndef __H__UG__RICHARDS_PLUGIN__LINKER_H__
34#define __H__UG__RICHARDS_PLUGIN__LINKER_H__
35
36// UG4
39
40// Plugin
41#include "van_genuchten.h"
42
43#include "json_basics.hh"
44
45namespace ug{
46namespace Richards{
47
48/*
49template <typename T>
50struct crtp
51{
52 T& underlying() { return static_cast<T&>(*this); }
53 T const& underlying() const { return static_cast<T const&>(*this); }
54};
55
56class LucasBase : public crtp<LucasBase>
57{
58
59
60 double evalOutside(double x)
61 {
62 return underlying().evalBase()
63 };
64
65
66// double evalBase(double x)
67// { return x*x}
68}
69
70class Lucas1 : public LucasBase{
71 double evalBase(double x)
72 { return x*x}
73}
74*/
76// Richards linker
78
80template <int dim>
92
94template <int dim, class TFunctor>
96 : public StdDataLinker< RichardsLinker<dim, TFunctor>, number, dim>,
97 public IRichardsLinker<dim>
98{
99public:
103 typedef typename TFunctor::TModel TModel;
105
106 enum inputs { _H_=0, _SIZE_};
107
108
109 public:
111
114 {
115 // this linker needs exactly one input
116 this->set_num_input(_SIZE_);
117 UG_LOG("RichardsLinker::RichardsLinker" << std::endl);
118 }
119
120
121 inline void evaluate (data_type& value,
122 const MathVector<dim>& globIP,
123 number time, int si) const
124 {
125 // UG_LOG("RichardsLinker::evaluate1: " << std::endl);
126 number cap;
127 double dummy;
128 (*richards_base_type::m_spCapillary)(cap, globIP, time, si);
129 TFunctor::get_func_values(m_model, &cap, &value, &dummy, 1);
130 }
131
132 template <int refDim>
133 inline void evaluate(data_type vValue[],
134 const MathVector<dim> vGlobIP[],
135 number time, int si,
136 GridObject* elem,
137 const MathVector<dim> vCornerCoords[],
138 const MathVector<refDim> vLocIP[],
139 const size_t nip,
140 LocalVector* u,
141 const MathMatrix<refDim, dim>* vJT = NULL) const
142 {
143 // UG_LOG("RichardsLinker::evaluate2: " << std::endl);
144 number vCapVal[nip];
145 (*richards_base_type::m_spCapillary)(&vCapVal[0], vGlobIP, time, si,
146 elem, vCornerCoords, vLocIP, nip, u, vJT);
147
148 number vdSdH[nip]; // dummies
149 TFunctor::get_func_values(m_model,vCapVal, vValue, vdSdH, nip);
150
151 }
152
153 template <int refDim>
155 const MathVector<dim> vGlobIP[],
156 number time, int si,
157 GridObject* elem,
158 const MathVector<dim> vCornerCoords[],
159 const MathVector<refDim> vLocIP[],
160 const size_t nip,
161 LocalVector* u,
162 bool bDeriv,
163 int s,
164 std::vector<std::vector<number > > vvvDeriv[],
165 const MathMatrix<refDim, dim>* vJT = NULL) const
166 {
167 // UG_LOG("RichardsLinker::eval_and_deriv: " << std::endl);
168 size_t sid=this->series_id(_H_,s);
169
170 // Checks.
171 UG_ASSERT(s >=0, "Huhh: Requires non-negative s");
172 UG_ASSERT(static_cast<size_t>(sid) < richards_base_type::m_spCapillary->num_series(), "Huhh: Requires data m_spCapillary!");
173 UG_ASSERT(static_cast<size_t>(sid) < richards_base_type::m_spDCapillary->num_series(), "Huhh: Requires data m_spCapillary!");
174 UG_ASSERT(nip == this->m_spCapillary->num_ip(sid),
175 "Huhh: Requires data m_spCapillary:" << nip << "!=" << this->m_spCapillary->num_ip(sid));
176 UG_ASSERT(nip == this->m_spDCapillary->num_ip(sid),
177 "Huhh: Requires data m_spCapillary:" << nip << "!=" << this->m_spDCapillary->num_ip(sid));
178
179
180
181 // Get the data from ip series.
182 const number* vH = richards_base_type::m_spCapillary->values(sid);
183 number vdSdH[nip];
184 TFunctor::get_func_values(m_model, vH, vValue, vdSdH, nip);
185
186
187 // Compute the derivatives at all ips.
188
189 // Check, if something to do.
190 if((!bDeriv) || this->zero_derivative()) return;
191
192 // Clear all derivative values.
193 this->set_zero(vvvDeriv, nip);
194
195 // Derivatives w.r.t height
197 {
198
199 for(size_t ip = 0; ip < nip; ++ip)
200 for(size_t fct = 0; fct < richards_base_type::m_spDCapillary->num_fct(); ++fct)
201 {
202 // get derivative of w.r.t. to all functions
203 const number* vDHeight = richards_base_type::m_spDCapillary->deriv(sid, ip, fct);
204
205 // get common fct id for this function
206 const size_t commonFct = this->input_common_fct(_H_, fct);
207
208 if (this->num_sh(commonFct) == nip)
209 {
210 // FV1 mass lumping
211 vvvDeriv[ip][commonFct][ip] += vdSdH[ip] * vDHeight[ip];
212 }
213 else
214 {
215 for(size_t sh = 0; sh < this->num_sh(commonFct); ++sh)
216 {
217 UG_ASSERT(commonFct < vvvDeriv[ip].size(), commonFct<<", "<<vvvDeriv[ip].size());
218 vvvDeriv[ip][commonFct][sh] += vdSdH[ip] * vDHeight[sh];
219 }
220 }
221 }
222
223 }
224
225 }
226
227 public:
230 {
231 richards_base_type::m_spCapillary = data; // for evaluation
232 richards_base_type::m_spDCapillary = data.template cast_dynamic<DependentUserData<number, dim> >(); // for derivatives
233 base_type::set_input(_H_, data, data);
234 }
235
236 public:
237 TModel& model() { return m_model; }
238 const TModel& model() const { return m_model; }
239
240 protected:
242};
243
244
246template <typename M>
248{
249 typedef M TModel;
250 static void get_func_values(const TModel &model, const double *h, double *s, double *dsdh, size_t n)
251 { model.get_saturations(h, s, dsdh, n); }
252};
253
255template <typename M>
257{
258 typedef M TModel;
259 static void get_func_values(const M& model, const double *h, double *k, double *dkdh, size_t n)
260 { model.get_conductivities(h, k, dkdh, n);}
261};
262
263
264/**********************************************
265 * Simple exponential model.
266 **********************************************/
267
268template <int dim>
269struct ExponentialSaturation : public RichardsLinker<dim, SaturationAdapter<ExponentialModel> >
270{
273};
274
275
276template <int dim>
277struct ExponentialConductivity : public RichardsLinker<dim, ConductivityAdapter<ExponentialModel> >
278{
281};
282
283
284
285/**********************************************
286 * Van Genuchten - Mualem
287 **********************************************/
288
292
294template <int dim>
295struct RichardsSaturation : public RichardsLinker<dim,vanGenuchtenSaturationAdapter>
296{
299};
300
301template <int dim>
307
308
309// TODO: Can we define the classes as follows?
310template <int dim>
312
313template <int dim>
315
316/**********************************************
317 * Gardner
318 **********************************************/
321
322template <int dim>
323class GardnerSaturation : public RichardsLinker<dim,GardnerSaturationAdapter>
324{
325public:
328};
329
330template <int dim>
331class GardnerConductivity : public RichardsLinker<dim,GardnerConductivityAdapter>
332{
333public:
336};
337
338/**********************************************
339 * Haverkamp
340 **********************************************/
343
344template <int dim>
345class HaverkampSaturation : public RichardsLinker<dim,HaverkampSaturationAdapter>
346{
347public:
350};
351
352template <int dim>
353class HaverkampConductivity : public RichardsLinker<dim,HaverkampConductivityAdapter>
354{
355public:
358};
359
360
361
362
363
365template <int dim>
367
368
369public:
372
374
375 UserDataFactory(input_type capillary) : m_capillary(capillary) {}
376
379 { auto sat = make_sp(new ExponentialSaturation<dim>(m)); sat->set_capillary(m_capillary); return sat; }
380
382 { auto cond = make_sp(new ExponentialConductivity<dim>(m)); cond->set_capillary(m_capillary); return cond;}
383
384 // van Genuchten models.
386 { auto sat = make_sp(new VanGenuchtenSaturation<dim>(m)); sat->set_capillary(m_capillary); return sat; }
387
389 { auto cond = make_sp(new VanGenuchtenConductivity<dim>(m)); cond->set_capillary(m_capillary); return cond;}
390
391protected:
393};
394
395
396
397template <int dim>
398class OnSurfaceCondition : public UserData<number, dim, bool>
399{
400
401public:
402 typedef number TData;
403 typedef bool TRet;
404
408
411
412
413protected:
415
416public:
418 bool continuous() const {return true;}
419
421 bool requires_grid_fct() const {return false;}
422
423 public:
425 virtual TRet operator() (TData& value,
426 const MathVector<dim>& globIP,
427 number time, int si) const
428 {
429 math_vector_type fluxVec;
430 m_spFlux->operator()(fluxVec, globIP, time, si);
431 // return m_spFlux->operator(value);
432 value = 47.11;
433 return (fluxVec[dim]>0) ? true : false;
434 }
435
437 virtual void operator()(TData vValue[],
438 const MathVector<dim> vGlobIP[],
439 number time, int si, const size_t nip) const
440 {}
441
442 virtual void operator()(TData vValue[],
443 const MathVector<dim> vGlobIP[],
444 number time, int si,
445 GridObject* elem,
446 const MathVector<dim> vCornerCoords[],
447 const MathVector<1> vLocIP[],
448 const size_t nip,
449 LocalVector* u,
450 const MathMatrix<1, dim>* vJT = NULL) const
451 {}
452
453 virtual void operator()(TData vValue[],
454 const MathVector<dim> vGlobIP[],
455 number time, int si,
456 GridObject* elem,
457 const MathVector<dim> vCornerCoords[],
458 const MathVector<2> vLocIP[],
459 const size_t nip,
460 LocalVector* u,
461 const MathMatrix<2, dim>* vJT = NULL) const
462 {}
463
464 virtual void operator()(TData vValue[],
465 const MathVector<dim> vGlobIP[],
466 number time, int si,
467 GridObject* elem,
468 const MathVector<dim> vCornerCoords[],
469 const MathVector<3> vLocIP[],
470 const size_t nip,
471 LocalVector* u,
472 const MathMatrix<3, dim>* vJT = NULL) const
473 {}
474
475};
476// TODO: Should be replaced!
478/* struct RelativePermeabilityAdapter
479{
480 typedef VanGenuchtenModel TModel;
481 static void get_func_values(const TModel &model, const double *h, double *k, double *dkdh, size_t n)
482 { model.get_relative_permeabilities(h, k, dkdh, n); }
483};
484
485
486template <int dim>
487class RichardsRelativePermeability : public RichardsLinker<dim,RelativePermeabilityAdapter>
488{
489public:
490 typedef RichardsLinker<dim,RelativePermeabilityAdapter> base_type;
491 RichardsRelativePermeability(const typename RelativePermeabilityAdapter::TModel &model) : RichardsLinker<dim, RelativePermeabilityAdapter> (model)
492 {}
493};
494*/
495
496
497/*
498
499
500template<TUserData>
501SmartPtr<TUserData> CreateUserData(nlohmann::json j, nlohmann::json jparams)
502{
503 SmartPtr<TUserDataNumber> inst = SPNULL;
504 const int dim = TUserData::dim;
505
506 auto jtype = j.at("type");
507 auto jvalue = j.at("value");
508
509
510 if (jtype.is_string())
511 {
512 std::string mystring;
513 jtype.get_to(mystring);
514
515 // JSON: "value" : {"$ref" : "#/bar"}
516 // LUA value = { "$ref" = "#/bar" }
517
518 if (std::string("RichardsSaturation").compare(mystring))
519 {
520 typedef RichardsSaturation<dim> TRichardsSaturation;
521 typedef typename TRichardsSaturation::parameter_type TParameter;
522 TParameter p;
523
524 make_sp(new TRichardsSaturation(p));
525 }
526
527
528 } else if (jtype.is_number())
529 {
530 double myval;
531 jtype.get_to(myval);
532 inst = make_sp(new ConstUserNumber<dim>(myval));
533 }
534
535 return inst;
536
537};
538
539template <int dim>
540SmartPtr<CplUserData<number, dim> > CreateUserDataNumber(const char *jstring) {
541
542 typedef CplUserData<number, dim> TUserDataNumber;
543
544 SmartPtr<TUserDataNumber> inst = SPNULL;
545 try
546 {
547 nlohmann::json j = nlohmann::json::parse(jstring);
548 VanGenuchtenParameters p = j.get<VanGenuchtenParameters>();
549 inst = make_sp(new VanGenuchtenModel(p));
550 }
551 catch (...)
552 {
553 std::cout << "Construction failed!" << std::endl;
554 }
555 return inst;
556};
557*/
558
559
560
561
562} // namespace Richards
563} // end namespace ug
564
565#ifdef UG_JSON
566namespace nlohmann {
567
568 // Construct RichardsSaturation from JSON
569 template <int dim>
570 struct adl_serializer<ug::Richards::RichardsSaturation<dim> >
571 {
572 typedef typename ug::Richards::RichardsSaturation<dim> TRichardsLinker;
574
575 static TRichardsLinker from_json(const json& j)
576 { return j.get<TModel>(); } // initialize from model }
577
578 static void to_json(json& j, TRichardsLinker s)
579 { j = s.model(); }
580 };
581
582 // Construct RichardsConductivity from JSON
583 template <int dim>
584 struct adl_serializer<ug::Richards::RichardsConductivity<dim> >
585 {
586 typedef typename ug::Richards::RichardsConductivity<dim> TRichardsLinker;
588
589 static TRichardsLinker from_json(const json& j)
590 { return j.get<TModel>(); } // initialize from model }
591
592 static void to_json(json& j, TRichardsLinker s)
593 { j = s.model(); }
594 };
595};
596#endif
597
598
599#endif /* __H__UG__RICHARDS_PLUGIN__LINKER_H__ */
parameterString s
Definition Biogas.lua:2
TData & value(size_t s, size_t ip)
size_t num_series() const
number time() const
const MathVector< dim > & ip(size_t s, size_t ip) const
Implement a simple exponential model.
Definition van_genuchten.h:278
Definition richards_linker.h:332
RichardsLinker< dim, GardnerConductivityAdapter > base_type
Definition richards_linker.h:334
GardnerConductivity(const typename base_type::TModel &model)
Definition richards_linker.h:335
Definition richards_linker.h:324
RichardsLinker< dim, GardnerSaturationAdapter > base_type
Definition richards_linker.h:326
GardnerSaturation(const typename base_type::TModel &model)
Definition richards_linker.h:327
Definition richards_linker.h:354
RichardsLinker< dim, HaverkampConductivityAdapter > base_type
Definition richards_linker.h:356
HaverkampConductivity(const typename base_type::TModel &model)
Definition richards_linker.h:357
Definition richards_linker.h:346
RichardsLinker< dim, HaverkampSaturationAdapter > base_type
Definition richards_linker.h:348
HaverkampSaturation(const typename base_type::TModel &model)
Definition richards_linker.h:349
Definition richards_linker.h:399
virtual void operator()(TData vValue[], const MathVector< dim > vGlobIP[], number time, int si, GridObject *elem, const MathVector< dim > vCornerCoords[], const MathVector< 2 > vLocIP[], const size_t nip, LocalVector *u, const MathMatrix< 2, dim > *vJT=NULL) const
Definition richards_linker.h:453
virtual ~OnSurfaceCondition()
Definition richards_linker.h:410
virtual void operator()(TData vValue[], const MathVector< dim > vGlobIP[], number time, int si, const size_t nip) const
returns values for global positions
Definition richards_linker.h:437
MathVector< dim > math_vector_type
Definition richards_linker.h:406
virtual void operator()(TData vValue[], const MathVector< dim > vGlobIP[], number time, int si, GridObject *elem, const MathVector< dim > vCornerCoords[], const MathVector< 3 > vLocIP[], const size_t nip, LocalVector *u, const MathMatrix< 3, dim > *vJT=NULL) const
Definition richards_linker.h:464
OnSurfaceCondition(SmartPtr< TVectorData > spFlux)
Definition richards_linker.h:409
UserData< MathVector< dim >, dim > TVectorData
Definition richards_linker.h:407
virtual TRet operator()(TData &value, const MathVector< dim > &globIP, number time, int si) const
returns value for a global position
Definition richards_linker.h:425
SmartPtr< TVectorData > m_spFlux
Definition richards_linker.h:414
virtual void operator()(TData vValue[], const MathVector< dim > vGlobIP[], number time, int si, GridObject *elem, const MathVector< dim > vCornerCoords[], const MathVector< 1 > vLocIP[], const size_t nip, LocalVector *u, const MathMatrix< 1, dim > *vJT=NULL) const
Definition richards_linker.h:442
UserData< number, dim, bool > user_data_base_type
Definition richards_linker.h:405
bool continuous() const
returns if provided data is continuous over geometric object boundaries
Definition richards_linker.h:418
number TData
Definition richards_linker.h:402
bool TRet
Definition richards_linker.h:403
bool requires_grid_fct() const
returns if grid function is needed for evaluation
Definition richards_linker.h:421
Prototype of a linker. Returns values depending on the Functor class.
Definition richards_linker.h:98
void evaluate(data_type &value, const MathVector< dim > &globIP, number time, int si) const
Definition richards_linker.h:121
IRichardsLinker< dim > richards_base_type
Definition richards_linker.h:104
TModel & model()
Definition richards_linker.h:237
TFunctor::TModel TModel
Definition richards_linker.h:103
void set_capillary(SmartPtr< CplUserData< number, dim > > data)
Implements IRichardsLinker interface.
Definition richards_linker.h:229
StdDataLinker< RichardsLinker< dim, TFunctor >, number, dim > base_type
Base class type.
Definition richards_linker.h:101
number data_type
Definition richards_linker.h:102
RichardsLinker(const TModel &model)
Definition richards_linker.h:112
base_type::base_type user_data_base_type
Definition richards_linker.h:110
inputs
Definition richards_linker.h:106
@ _SIZE_
Definition richards_linker.h:106
@ _H_
Definition richards_linker.h:106
void evaluate(data_type vValue[], const MathVector< dim > vGlobIP[], number time, int si, GridObject *elem, const MathVector< dim > vCornerCoords[], const MathVector< refDim > vLocIP[], const size_t nip, LocalVector *u, const MathMatrix< refDim, dim > *vJT=NULL) const
Definition richards_linker.h:133
TModel m_model
Definition richards_linker.h:241
void eval_and_deriv(data_type vValue[], const MathVector< dim > vGlobIP[], number time, int si, GridObject *elem, const MathVector< dim > vCornerCoords[], const MathVector< refDim > vLocIP[], const size_t nip, LocalVector *u, bool bDeriv, int s, std::vector< std::vector< number > > vvvDeriv[], const MathMatrix< refDim, dim > *vJT=NULL) const
Definition richards_linker.h:154
const TModel & model() const
Definition richards_linker.h:238
Factory class. This constructs appropriate "UserData" from suitable models.
Definition richards_linker.h:366
return_type create_saturation(const ExponentialModel &m)
Exponential models.
Definition richards_linker.h:378
return_type create_conductivity(const VanGenuchtenModel &m)
Definition richards_linker.h:388
CplUserData< number, dim > TUserDataNumber
Definition richards_linker.h:370
SmartPtr< CplUserData< number, dim > > input_type
Definition richards_linker.h:373
input_type m_capillary
Definition richards_linker.h:392
return_type create_conductivity(const ExponentialModel &m)
Definition richards_linker.h:381
UserDataFactory(input_type capillary)
Definition richards_linker.h:375
return_type create_saturation(const VanGenuchtenModel &m)
Definition richards_linker.h:385
SmartPtr< TUserDataNumber > return_type
Definition richards_linker.h:371
Implements a van Genuchten-Mualem model.
Definition van_genuchten.h:368
virtual void set_input(size_t i, SmartPtr< ICplUserData< dim > > input, SmartPtr< UserDataInfo > info)
#define UG_ASSERT(expr, msg)
#define UG_LOG(msg)
double number
ConductivityAdapter< HaverkampModel > HaverkampConductivityAdapter
Definition richards_linker.h:342
SaturationAdapter< VanGenuchtenModel > vanGenuchtenSaturationAdapter
Shortcuts for van Genuchten.
Definition richards_linker.h:290
ConductivityAdapter< GardnerModel > GardnerConductivityAdapter
Definition richards_linker.h:320
SaturationAdapter< GardnerModel > GardnerSaturationAdapter
Definition richards_linker.h:319
ConductivityAdapter< VanGenuchtenModel > vanGenuchtenConductivityAdapter
Definition richards_linker.h:291
SaturationAdapter< HaverkampModel > HaverkampSaturationAdapter
Definition richards_linker.h:341
SmartPtr< T, FreePolicy > make_sp(T *inst)
Returns conductivities (note: corresponds to relative permeability, iff Ksat=1.0).
Definition richards_linker.h:257
static void get_func_values(const M &model, const double *h, double *k, double *dkdh, size_t n)
Definition richards_linker.h:259
M TModel
Definition richards_linker.h:258
Definition richards_linker.h:278
RichardsLinker< dim, ConductivityAdapter< ExponentialModel > > base_type
Definition richards_linker.h:279
ExponentialConductivity(const ExponentialModel &m)
Definition richards_linker.h:280
Definition richards_linker.h:270
ExponentialSaturation(const ExponentialModel &m)
Definition richards_linker.h:272
RichardsLinker< dim, SaturationAdapter< ExponentialModel > > base_type
Definition richards_linker.h:271
This is a 'dummy' base class. It indicates a pressure dependent linker.
Definition richards_linker.h:82
IRichardsLinker()
Definition richards_linker.h:83
SmartPtr< DependentUserData< number, dim > > m_spDCapillary
Definition richards_linker.h:87
virtual ~IRichardsLinker()
Definition richards_linker.h:84
SmartPtr< CplUserData< number, dim > > m_spCapillary
Definition richards_linker.h:86
virtual void set_capillary(SmartPtr< CplUserData< number, dim > > data)=0
Definition richards_linker.h:303
RichardsConductivity(const typename base_type::TModel &model)
Definition richards_linker.h:305
RichardsLinker< dim, vanGenuchtenConductivityAdapter > base_type
Definition richards_linker.h:304
van Genuchten classes. (ideally, those could be type-def'ed as well..)
Definition richards_linker.h:296
RichardsLinker< dim, vanGenuchtenSaturationAdapter > base_type
Definition richards_linker.h:297
RichardsSaturation(const typename base_type::TModel &model)
Definition richards_linker.h:298
Returns saturations.
Definition richards_linker.h:248
M TModel
Definition richards_linker.h:249
static void get_func_values(const TModel &model, const double *h, double *s, double *dsdh, size_t n)
Definition richards_linker.h:250