11"""Helper functions for estimating stable time steps for RKDG methods.
22
3- .. autofunction:: dt_non_geometric_factor
3+ Characteristic lengthscales
4+ ---------------------------
5+
6+ .. autofunction:: characteristic_lengthscales
7+
8+ Non-geometric quantities
9+ ------------------------
10+
11+ .. autofunction:: dt_non_geometric_factors
12+
13+ Mesh size utilities
14+ -------------------
15+
416.. autofunction:: dt_geometric_factors
517.. autofunction:: h_max_from_volume
618.. autofunction:: h_min_from_volume
3345
3446import numpy as np
3547
36- from arraycontext import FirstAxisIsElementsTag
48+ from arraycontext import ArrayContext , FirstAxisIsElementsTag , thaw , freeze
3749
3850from grudge .dof_desc import DD_VOLUME , DOFDesc , as_dofdesc
3951from grudge .discretization import DiscretizationCollection
4254
4355from meshmode .dof_array import DOFArray
4456
45- from pytools import memoize_on_first_arg
57+ from pytools import memoize_on_first_arg , memoize_in
58+
59+
60+ def characteristic_lengthscales (
61+ actx : ArrayContext , dcoll : DiscretizationCollection ) -> DOFArray :
62+ r"""Computes the characteristic length scale :math:`h_{\text{loc}}` at
63+ each node. The characteristic length scale is mainly useful for estimating
64+ the stable time step size. E.g. for a hyperbolic system, an estimate of the
65+ stable time step can be estimated as :math:`h_{\text{loc}} / c`, where
66+ :math:`c` is the characteristic wave speed. The estimate is obtained using
67+ the following formula:
68+
69+ .. math::
70+
71+ h_{\text{loc}} = \operatorname{min}\left(\Delta r_i\right) r_D
72+
73+ where :math:`\operatorname{min}\left(\Delta r_i\right)` is the minimum
74+ node distance on the reference cell (see :func:`dt_non_geometric_factors`),
75+ and :math:`r_D` is the inradius of the cell (see :func:`dt_geometric_factors`).
76+
77+ :returns: a frozen :class:`~meshmode.dof_array.DOFArray` containing a
78+ characteristic lengthscale for each element, at each nodal location.
79+
80+ .. note::
81+
82+ While a prediction of stability is only meaningful in relation to a given
83+ time integrator with a known stability region, the lengthscale provided here
84+ is not intended to be specific to any one time integrator, though the
85+ stability region of standard four-stage, fourth-order Runge-Kutta
86+ methods has been used as a guide. Any concrete time integrator will
87+ likely require scaling of the values returned by this routine.
88+ """
89+ @memoize_in (dcoll , (characteristic_lengthscales ,
90+ "compute_characteristic_lengthscales" ))
91+ def _compute_characteristic_lengthscales ():
92+ return freeze (
93+ DOFArray (
94+ actx ,
95+ data = tuple (
96+ # Scale each group array of geometric factors by the
97+ # corresponding group non-geometric factor
98+ cng * geo_facts
99+ for cng , geo_facts in zip (
100+ dt_non_geometric_factors (dcoll ),
101+ thaw (dt_geometric_factors (dcoll ), actx )
102+ )
103+ )
104+ )
105+ )
106+ return thaw (_compute_characteristic_lengthscales (), actx )
46107
47108
48109@memoize_on_first_arg
49- def dt_non_geometric_factor (dcoll : DiscretizationCollection , dd = None ) -> float :
50- r"""Computes the non-geometric scale factor following [Hesthaven_2008]_,
51- section 6.4:
110+ def dt_non_geometric_factors (
111+ dcoll : DiscretizationCollection , dd = None ) -> list :
112+ r"""Computes the non-geometric scale factors following [Hesthaven_2008]_,
113+ section 6.4, for each element group in the *dd* discretization:
52114
53115 .. math::
54116
55117 c_{ng} = \operatorname{min}\left( \Delta r_i \right),
56118
57119 where :math:`\Delta r_i` denotes the distance between two distinct
58- nodes on the reference element.
120+ nodal points on the reference element.
59121
60122 :arg dd: a :class:`~grudge.dof_desc.DOFDesc`, or a value convertible to one.
61123 Defaults to the base volume discretization if not provided.
62- :returns: a :class:`float` denoting the minimum node distance on the
63- reference element.
124+ :returns: a :class:`list` of :class:` float` values denoting the minimum
125+ node distance on the reference element for each group .
64126 """
65127 if dd is None :
66128 dd = DD_VOLUME
@@ -88,8 +150,7 @@ def dt_non_geometric_factor(dcoll: DiscretizationCollection, dd=None) -> float:
88150 )
89151 )
90152
91- # Return minimum over all element groups in the discretization
92- return min (min_delta_rs )
153+ return min_delta_rs
93154
94155
95156# {{{ Mesh size functions
@@ -156,7 +217,6 @@ def h_min_from_volume(
156217 ) ** (1.0 / dim )
157218
158219
159- @memoize_on_first_arg
160220def dt_geometric_factors (
161221 dcoll : DiscretizationCollection , dd = None ) -> DOFArray :
162222 r"""Computes a geometric scaling factor for each cell following [Hesthaven_2008]_,
@@ -175,8 +235,8 @@ def dt_geometric_factors(
175235
176236 :arg dd: a :class:`~grudge.dof_desc.DOFDesc`, or a value convertible to one.
177237 Defaults to the base volume discretization if not provided.
178- :returns: a :class:`~meshmode.dof_array.DOFArray` containing the geometric
179- factors for each cell and at each nodal location.
238+ :returns: a frozen :class:`~meshmode.dof_array.DOFArray` containing the
239+ geometric factors for each cell and at each nodal location.
180240 """
181241 from meshmode .discretization .poly_element import SimplexElementGroupBase
182242
@@ -192,14 +252,20 @@ def dt_geometric_factors(
192252 "Geometric factors are only implemented for simplex element groups"
193253 )
194254
255+ if volm_discr .dim != volm_discr .ambient_dim :
256+ from warnings import warn
257+ warn ("The geometric factor for the characteristic length scale in "
258+ "time step estimation is not necessarily valid for non-volume-"
259+ "filling discretizations. Continuing anyway." , stacklevel = 3 )
260+
195261 cell_vols = abs (
196262 op .elementwise_integral (
197263 dcoll , dd , volm_discr .zeros (actx ) + 1.0
198264 )
199265 )
200266
201267 if dcoll .dim == 1 :
202- return cell_vols
268+ return freeze ( cell_vols )
203269
204270 dd_face = DOFDesc ("all_faces" , dd .discretization_tag )
205271 face_discr = dcoll .discr_from_dd (dd_face )
@@ -230,7 +296,7 @@ def dt_geometric_factors(
230296 )
231297 )
232298
233- return DOFArray (
299+ return freeze ( DOFArray (
234300 actx ,
235301 data = tuple (
236302 actx .einsum ("e,ei->ei" ,
@@ -240,7 +306,7 @@ def dt_geometric_factors(
240306
241307 for cv_i , sae_i in zip (cell_vols , surface_areas )
242308 )
243- )
309+ ))
244310
245311# }}}
246312
0 commit comments