Reference documentation for deal.II version 8.5.1
function_spherical.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2016 - 2017 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/point.h>
17 #include <deal.II/base/function_spherical.h>
18 #include <deal.II/base/geometric_utilities.h>
19 
20 #include <cmath>
21 #include <algorithm>
22 
23 DEAL_II_NAMESPACE_OPEN
24 namespace Functions
25 {
26 
27  // other implementations/notes:
28  // https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/geometry/euclidean/threed/SphericalCoordinates.java
29  // http://mathworld.wolfram.com/SphericalCoordinates.html
30 
31  /*derivation of Hessian in Maxima as function of tensor products of unit vectors:
32 
33  depends(ur,[theta,phi]);
34  depends(utheta,theta);
35  depends(uphi,[theta,phi]);
36  depends(f,[r,theta,phi]);
37  declare([f,r,theta,phi], scalar)@f$
38  dotscrules: true;
39  grads(a):=ur.diff(a,r)+(1/r)*uphi.diff(a,phi)+(1/(r*sin(phi)))*utheta.diff(a,theta);
40 
41 
42  H : factor(grads(grads(f)));
43  H2: subst([diff(ur,theta)=sin(phi)*utheta,
44  diff(utheta,theta)=-cos(phi)*uphi-sin(phi)*ur,
45  diff(uphi,theta)=cos(phi)*utheta,
46  diff(ur,phi)=uphi,
47  diff(uphi,phi)=-ur],
48  H);
49  H3: trigsimp(fullratsimp(H2));
50 
51 
52  srules : [diff(f,r)=sg0,
53  diff(f,theta)=sg1,
54  diff(f,phi)=sg2,
55  diff(f,r,2)=sh0,
56  diff(f,theta,2)=sh1,
57  diff(f,phi,2)=sh2,
58  diff(f,r,1,theta,1)=sh3,
59  diff(f,r,1,phi,1)=sh4,
60  diff(f,theta,1,phi,1)=sh5,
61  cos(phi)=cos_phi,
62  cos(theta)=cos_theta,
63  sin(phi)=sin_phi,
64  sin(theta)=sin_theta
65  ]@f$
66 
67  c_utheta2 : distrib(subst(srules, ratcoeff(expand(H3), utheta.utheta)));
68  c_utheta_ur : (subst(srules, ratcoeff(expand(H3), utheta.ur)));
69  (subst(srules, ratcoeff(expand(H3), ur.utheta))) - c_utheta_ur;
70  c_utheta_uphi : (subst(srules, ratcoeff(expand(H3), utheta.uphi)));
71  (subst(srules, ratcoeff(expand(H3), uphi.utheta))) - c_utheta_uphi;
72  c_ur2 : (subst(srules, ratcoeff(expand(H3), ur.ur)));
73  c_ur_uphi : (subst(srules, ratcoeff(expand(H3), ur.uphi)));
74  (subst(srules, ratcoeff(expand(H3), uphi.ur))) - c_ur_uphi;
75  c_uphi2 : (subst(srules, ratcoeff(expand(H3), uphi.uphi)));
76 
77 
78  where (used later to do tensor products):
79 
80  ur : [cos(theta)*sin(phi), sin(theta)*sin(phi), cos(phi)];
81  utheta : [-sin(theta), cos(theta), 0];
82  uphi : [cos(theta)*cos(phi), sin(theta)*cos(phi), -sin(phi)];
83 
84  with the following proof of substitution rules above:
85 
86  -diff(ur,theta)+sin(phi)*utheta;
87  trigsimp(-diff(utheta,theta)-cos(phi)*uphi-sin(phi)*ur);
88  -diff(uphi,theta)+cos(phi)*utheta;
89  -diff(ur,phi)+uphi;
90  -diff(uphi,phi)-ur;
91 
92  */
93 
94  namespace
95  {
96 
100  template <int dim>
101  void set_unit_vectors(const double &cos_theta,
102  const double &sin_theta,
103  const double &cos_phi,
104  const double &sin_phi,
105  Tensor<1,dim> &unit_r,
106  Tensor<1,dim> &unit_theta,
107  Tensor<1,dim> &unit_phi)
108  {
109  unit_r[0] = cos_theta * sin_phi;
110  unit_r[1] = sin_theta * sin_phi;
111  unit_r[2] = cos_phi;
112 
113  unit_theta[0] = -sin_theta;
114  unit_theta[1] = cos_theta;
115  unit_theta[2] = 0.;
116 
117  unit_phi[0] = cos_theta * cos_phi;
118  unit_phi[1] = sin_theta * cos_phi;
119  unit_phi[2] = -sin_phi;
120  }
121 
122 
126  template <int dim>
127  void add_outer_product(SymmetricTensor<2,dim> &out,
128  const double &val,
129  const Tensor<1,dim> &in1,
130  const Tensor<1,dim> &in2)
131  {
132  if (val != 0.)
133  for (unsigned int i = 0; i < dim; i++)
134  for (unsigned int j = i; j < dim; j++)
135  out[i][j] += (in1[i]*in2[j]+in1[j]*in2[i])*val;
136  }
137 
141  template <int dim>
142  void add_outer_product(SymmetricTensor<2,dim> &out,
143  const double &val,
144  const Tensor<1,dim> &in)
145  {
146  if (val != 0.)
147  for (unsigned int i = 0; i < dim; i++)
148  for (unsigned int j = i; j < dim; j++)
149  out[i][j] += val*in[i]*in[j];
150  }
151  }
152 
153 
154 
155  template <int dim>
157  const unsigned int n_components)
158  :
159  Function<dim>(n_components),
160  coordinate_system_offset(p)
161  {
162  AssertThrow(dim==3,
164  }
165 
166 
167 
168  template <int dim>
169  double
171  const unsigned int component) const
172  {
173  const Point<dim> p = p_ - coordinate_system_offset;
174  const std_cxx11::array<double, dim> sp = GeometricUtilities::Coordinates::to_spherical(p);
175  return svalue(sp, component);
176  }
177 
178 
179 
180  template <int dim>
183  const unsigned int component) const
184  {
185  const Point<dim> p = p_ - coordinate_system_offset;
186  const std_cxx11::array<double, dim> sp = GeometricUtilities::Coordinates::to_spherical(p);
187  const std_cxx11::array<double, dim> sg = sgradient(sp, component);
188 
189  // somewhat backwards, but we need cos/sin's for unit vectors
190  const double cos_theta = std::cos(sp[1]);
191  const double sin_theta = std::sin(sp[1]);
192  const double cos_phi = std::cos(sp[2]);
193  const double sin_phi = std::sin(sp[2]);
194 
195  Tensor<1,dim> unit_r, unit_theta, unit_phi;
196  set_unit_vectors(cos_theta, sin_theta,
197  cos_phi, sin_phi,
198  unit_r, unit_theta, unit_phi);
199 
200  Tensor<1,dim> res;
201 
202  if (sg[0] != 0.)
203  {
204  res += unit_r * sg[0];
205  }
206 
207  if (sg[1] * sin_phi != 0.)
208  {
209  Assert (sp[0] != 0.,
210  ExcDivideByZero());
211  res += unit_theta * sg[1] / (sp[0] * sin_phi);
212  }
213 
214  if (sg[2] != 0.)
215  {
216  Assert (sp[0] != 0.,
217  ExcDivideByZero());
218  res += unit_phi * sg[2] / sp[0];
219  }
220 
221  return res;
222  }
223 
224 
225 
226  template <int dim>
229  const unsigned int component) const
230  {
231  const Point<dim> p = p_ - coordinate_system_offset;
232  const std_cxx11::array<double, dim> sp = GeometricUtilities::Coordinates::to_spherical(p);
233  const std_cxx11::array<double, dim> sg = sgradient(sp, component);
234  const std_cxx11::array<double, 6> sh = shessian(sp, component);
235 
236  // somewhat backwards, but we need cos/sin's for unit vectors
237  const double cos_theta = std::cos(sp[1]);
238  const double sin_theta = std::sin(sp[1]);
239  const double cos_phi = std::cos(sp[2]);
240  const double sin_phi = std::sin(sp[2]);
241  const double r = sp[0];
242 
243  Tensor<1,dim> unit_r, unit_theta, unit_phi;
244  set_unit_vectors(cos_theta, sin_theta,
245  cos_phi, sin_phi,
246  unit_r, unit_theta, unit_phi);
247 
248  const double sin_phi2 = sin_phi*sin_phi;
249  const double r2 = r*r;
250  Assert (r != 0.,
251  ExcDivideByZero());
252 
253  const double c_utheta2 = sg[0]/r +
254  ((sin_phi!= 0.) ?
255  (cos_phi*sg[2])/(r2*sin_phi)+sh[1]/(r2*sin_phi2) :
256  0.);
257  const double c_utheta_ur = ((sin_phi != 0.) ?
258  (r*sh[3]-sg[1])/(r2*sin_phi) :
259  0.);
260  const double c_utheta_uphi = ((sin_phi != 0.) ?
261  (sh[5]*sin_phi-cos_phi*sg[1])/(r2*sin_phi2) :
262  0.);
263  const double c_ur2 = sh[0];
264  const double c_ur_uphi = (r*sh[4]-sg[2])/r2;
265  const double c_uphi2 = (sh[2]+r*sg[0])/r2;
266 
267  // go through each tensor product
269 
270  add_outer_product(res,
271  c_utheta2,
272  unit_theta);
273 
274  add_outer_product(res,
275  c_utheta_ur,
276  unit_theta,
277  unit_r);
278 
279  add_outer_product(res,
280  c_utheta_uphi,
281  unit_theta,
282  unit_phi);
283 
284  add_outer_product(res,
285  c_ur2,
286  unit_r);
287 
288  add_outer_product(res,
289  c_ur_uphi,
290  unit_r,
291  unit_phi);
292 
293  add_outer_product(res,
294  c_uphi2,
295  unit_phi);
296 
297  return res;
298  }
299 
300 
301 
302  template <int dim>
303  std::size_t
305  {
306  return sizeof(Spherical<dim>);
307  }
308 
309 
310 
311  template <int dim>
312  double
313  Spherical<dim>::svalue(const std_cxx11::array<double, dim> & /* sp */,
314  const unsigned int /*component*/) const
315  {
316  AssertThrow(false,
318  return 0.;
319  }
320 
321 
322 
323  template <int dim>
324  std_cxx11::array<double, dim>
325  Spherical<dim>::sgradient(const std_cxx11::array<double, dim> & /* sp */,
326  const unsigned int /*component*/) const
327  {
328  AssertThrow(false,
330  return std_cxx11::array<double,dim>();
331  }
332 
333 
334 
335  template <int dim>
336  std_cxx11::array<double, 6>
337  Spherical<dim>::shessian (const std_cxx11::array<double, dim> & /* sp */,
338  const unsigned int /*component*/) const
339  {
340  AssertThrow(false,
342  return std_cxx11::array<double, 6>();
343  }
344 
345 
346 
347 // explicit instantiations
348  template class Spherical<3>;
349 
350 }
351 
352 DEAL_II_NAMESPACE_CLOSE
virtual SymmetricTensor< 2, dim > hessian(const Point< dim > &p, const unsigned int component=0) const
virtual double value(const Point< dim > &point, const unsigned int component=0) const
Spherical(const Point< dim > &center=Point< dim >(), const unsigned int n_components=1)
#define AssertThrow(cond, exc)
Definition: exceptions.h:369
std_cxx11::array< double, dim > to_spherical(const Point< dim > &point)
static ::ExceptionBase & ExcDivideByZero()
virtual Tensor< 1, dim > gradient(const Point< dim > &p, const unsigned int component=0) const
virtual std_cxx11::array< double, 6 > shessian(const std_cxx11::array< double, dim > &sp, const unsigned int component) const
#define Assert(cond, exc)
Definition: exceptions.h:313
virtual double svalue(const std_cxx11::array< double, dim > &sp, const unsigned int component) const
virtual std_cxx11::array< double, dim > sgradient(const std_cxx11::array< double, dim > &sp, const unsigned int component) const
static ::ExceptionBase & ExcNotImplemented()