deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11:20:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
function_spherical.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2017 - 2024 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
15#include <deal.II/base/point.h>
16
17#include <algorithm>
18#include <cmath>
19
21namespace Functions
22{
23 // other implementations/notes:
24 // https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/SphericalCoordinates.java
25 // http://mathworld.wolfram.com/SphericalCoordinates.html
26
27 /*derivation of Hessian in Maxima as function of tensor products of unit
28 vectors:
29
30 depends(ur,[theta,phi]);
31 depends(utheta,theta);
32 depends(uphi,[theta,phi]);
33 depends(f,[r,theta,phi]);
34 declare([f,r,theta,phi], scalar)@f$
35 dotscrules: true;
36 grads(a):=ur.diff(a,r)+(1/r)*uphi.diff(a,phi)+(1/(r*sin(phi)))*utheta.diff(a,theta);
37
38
39 H : factor(grads(grads(f)));
40 H2: subst([diff(ur,theta)=sin(phi)*utheta,
41 diff(utheta,theta)=-cos(phi)*uphi-sin(phi)*ur,
42 diff(uphi,theta)=cos(phi)*utheta,
43 diff(ur,phi)=uphi,
44 diff(uphi,phi)=-ur],
45 H);
46 H3: trigsimp(fullratsimp(H2));
47
48
49 srules : [diff(f,r)=sg0,
50 diff(f,theta)=sg1,
51 diff(f,phi)=sg2,
52 diff(f,r,2)=sh0,
53 diff(f,theta,2)=sh1,
54 diff(f,phi,2)=sh2,
55 diff(f,r,1,theta,1)=sh3,
56 diff(f,r,1,phi,1)=sh4,
57 diff(f,theta,1,phi,1)=sh5,
58 cos(phi)=cos_phi,
59 cos(theta)=cos_theta,
60 sin(phi)=sin_phi,
61 sin(theta)=sin_theta
62 ]@f$
63
64 c_utheta2 : distrib(subst(srules, ratcoeff(expand(H3), utheta.utheta)));
65 c_utheta_ur : (subst(srules, ratcoeff(expand(H3), utheta.ur)));
66 (subst(srules, ratcoeff(expand(H3), ur.utheta))) - c_utheta_ur;
67 c_utheta_uphi : (subst(srules, ratcoeff(expand(H3), utheta.uphi)));
68 (subst(srules, ratcoeff(expand(H3), uphi.utheta))) - c_utheta_uphi;
69 c_ur2 : (subst(srules, ratcoeff(expand(H3), ur.ur)));
70 c_ur_uphi : (subst(srules, ratcoeff(expand(H3), ur.uphi)));
71 (subst(srules, ratcoeff(expand(H3), uphi.ur))) - c_ur_uphi;
72 c_uphi2 : (subst(srules, ratcoeff(expand(H3), uphi.uphi)));
73
74
75 where (used later to do tensor products):
76
77 ur : [cos(theta)*sin(phi), sin(theta)*sin(phi), cos(phi)];
78 utheta : [-sin(theta), cos(theta), 0];
79 uphi : [cos(theta)*cos(phi), sin(theta)*cos(phi), -sin(phi)];
80
81 with the following proof of substitution rules above:
82
83 -diff(ur,theta)+sin(phi)*utheta;
84 trigsimp(-diff(utheta,theta)-cos(phi)*uphi-sin(phi)*ur);
85 -diff(uphi,theta)+cos(phi)*utheta;
86 -diff(ur,phi)+uphi;
87 -diff(uphi,phi)-ur;
88
89 */
90
91 namespace
92 {
96 template <int dim>
97 void
98 set_unit_vectors(const double cos_theta,
99 const double sin_theta,
100 const double cos_phi,
101 const double sin_phi,
102 Tensor<1, dim> &unit_r,
103 Tensor<1, dim> &unit_theta,
104 Tensor<1, dim> &unit_phi)
105 {
106 unit_r[0] = cos_theta * sin_phi;
107 unit_r[1] = sin_theta * sin_phi;
108 unit_r[2] = cos_phi;
109
110 unit_theta[0] = -sin_theta;
111 unit_theta[1] = cos_theta;
112 unit_theta[2] = 0.;
113
114 unit_phi[0] = cos_theta * cos_phi;
115 unit_phi[1] = sin_theta * cos_phi;
116 unit_phi[2] = -sin_phi;
117 }
118
119
123 template <int dim>
124 void
125 add_outer_product(SymmetricTensor<2, dim> &out,
126 const double val,
127 const Tensor<1, dim> &in1,
128 const Tensor<1, dim> &in2)
129 {
130 if (val != 0.)
131 for (unsigned int i = 0; i < dim; ++i)
132 for (unsigned int j = i; j < dim; ++j)
133 out[i][j] += (in1[i] * in2[j] + in1[j] * in2[i]) * val;
134 }
135
139 template <int dim>
140 void
141 add_outer_product(SymmetricTensor<2, dim> &out,
142 const double val,
143 const Tensor<1, dim> &in)
144 {
145 if (val != 0.)
146 for (unsigned int i = 0; i < dim; ++i)
147 for (unsigned int j = i; j < dim; ++j)
148 out[i][j] += val * in[i] * in[j];
149 }
150 } // namespace
151
152
153
154 template <int dim>
156 const unsigned int n_components)
157 : Function<dim>(n_components)
158 , coordinate_system_offset(p)
159 {
160 AssertThrow(dim == 3, ExcNotImplemented());
161 }
162
163
164
165 template <int dim>
166 double
168 const unsigned int component) const
169 {
170 const Point<dim> p = p_ - coordinate_system_offset;
171 const std::array<double, dim> sp =
173 return svalue(sp, component);
174 }
175
176
177
178 template <int dim>
181 const unsigned int /*component*/) const
182
183 {
185 return {};
186 }
187
188
189
190 template <>
192 Spherical<3>::gradient(const Point<3> &p_, const unsigned int component) const
193 {
194 constexpr int dim = 3;
195 const Point<dim> p = p_ - coordinate_system_offset;
196 const std::array<double, dim> sp =
198 const std::array<double, dim> sg = sgradient(sp, component);
199
200 // somewhat backwards, but we need cos/sin's for unit vectors
201 const double cos_theta = std::cos(sp[1]);
202 const double sin_theta = std::sin(sp[1]);
203 const double cos_phi = std::cos(sp[2]);
204 const double sin_phi = std::sin(sp[2]);
205
206 Tensor<1, dim> unit_r, unit_theta, unit_phi;
207 set_unit_vectors(
208 cos_theta, sin_theta, cos_phi, sin_phi, unit_r, unit_theta, unit_phi);
209
210 Tensor<1, dim> res;
211
212 if (sg[0] != 0.)
213 {
214 res += unit_r * sg[0];
215 }
216
217 if (sg[1] * sin_phi != 0.)
218 {
219 Assert(sp[0] != 0., ExcDivideByZero());
220 res += unit_theta * sg[1] / (sp[0] * sin_phi);
221 }
222
223 if (sg[2] != 0.)
224 {
225 Assert(sp[0] != 0., ExcDivideByZero());
226 res += unit_phi * sg[2] / sp[0];
227 }
228
229 return res;
230 }
231
232
233
234 template <int dim>
237 const unsigned int /*component*/) const
238 {
240 return {};
241 }
242
243
244
245 template <>
247 Spherical<3>::hessian(const Point<3> &p_, const unsigned int component) const
248
249 {
250 constexpr int dim = 3;
251 const Point<dim> p = p_ - coordinate_system_offset;
252 const std::array<double, dim> sp =
254 const std::array<double, dim> sg = sgradient(sp, component);
255 const std::array<double, 6> sh = shessian(sp, component);
256
257 // somewhat backwards, but we need cos/sin's for unit vectors
258 const double cos_theta = std::cos(sp[1]);
259 const double sin_theta = std::sin(sp[1]);
260 const double cos_phi = std::cos(sp[2]);
261 const double sin_phi = std::sin(sp[2]);
262 const double r = sp[0];
263
264 Tensor<1, dim> unit_r, unit_theta, unit_phi;
265 set_unit_vectors(
266 cos_theta, sin_theta, cos_phi, sin_phi, unit_r, unit_theta, unit_phi);
267
268 const double sin_phi2 = sin_phi * sin_phi;
269 const double r2 = r * r;
270 Assert(r != 0., ExcDivideByZero());
271
272 const double c_utheta2 =
273 sg[0] / r + ((sin_phi != 0.) ? (cos_phi * sg[2]) / (r2 * sin_phi) +
274 sh[1] / (r2 * sin_phi2) :
275 0.);
276 const double c_utheta_ur =
277 ((sin_phi != 0.) ? (r * sh[3] - sg[1]) / (r2 * sin_phi) : 0.);
278 const double c_utheta_uphi =
279 ((sin_phi != 0.) ? (sh[5] * sin_phi - cos_phi * sg[1]) / (r2 * sin_phi2) :
280 0.);
281 const double c_ur2 = sh[0];
282 const double c_ur_uphi = (r * sh[4] - sg[2]) / r2;
283 const double c_uphi2 = (sh[2] + r * sg[0]) / r2;
284
285 // go through each tensor product
287
288 add_outer_product(res, c_utheta2, unit_theta);
289
290 add_outer_product(res, c_utheta_ur, unit_theta, unit_r);
291
292 add_outer_product(res, c_utheta_uphi, unit_theta, unit_phi);
293
294 add_outer_product(res, c_ur2, unit_r);
295
296 add_outer_product(res, c_ur_uphi, unit_r, unit_phi);
297
298 add_outer_product(res, c_uphi2, unit_phi);
299
300 return res;
301 }
302
303
304
305 template <int dim>
306 std::size_t
308 {
309 return sizeof(Spherical<dim>);
310 }
311
312
313
314 template <int dim>
315 double
316 Spherical<dim>::svalue(const std::array<double, dim> & /* sp */,
317 const unsigned int /*component*/) const
318 {
320 return 0.;
321 }
322
323
324
325 template <int dim>
326 std::array<double, dim>
327 Spherical<dim>::sgradient(const std::array<double, dim> & /* sp */,
328 const unsigned int /*component*/) const
329 {
331 return std::array<double, dim>();
332 }
333
334
335
336 template <int dim>
337 std::array<double, 6>
338 Spherical<dim>::shessian(const std::array<double, dim> & /* sp */,
339 const unsigned int /*component*/) const
340 {
342 return std::array<double, 6>();
343 }
344
345
346
347 // explicit instantiations
348 template class Spherical<1>;
349 template class Spherical<2>;
350 template class Spherical<3>;
351
352} // namespace Functions
353
virtual SymmetricTensor< 2, dim > hessian(const Point< dim > &p, const unsigned int component=0) const override
Spherical(const Point< dim > &center=Point< dim >(), const unsigned int n_components=1)
virtual Tensor< 1, dim > gradient(const Point< dim > &p, const unsigned int component=0) const override
virtual std::array< double, dim > sgradient(const std::array< double, dim > &sp, const unsigned int component) const
virtual double value(const Point< dim > &point, const unsigned int component=0) const override
virtual std::size_t memory_consumption() const override
virtual std::array< double, 6 > shessian(const std::array< double, dim > &sp, const unsigned int component) const
virtual double svalue(const std::array< double, dim > &sp, const unsigned int component) const
Definition point.h:111
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_NOT_IMPLEMENTED()
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
static ::ExceptionBase & ExcDivideByZero()
#define AssertThrow(cond, exc)
std::array< double, dim > to_spherical(const Point< dim > &point)
::VectorizedArray< Number, width > cos(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sin(const ::VectorizedArray< Number, width > &)