Tomographer  v5.4
Tomographer C++ Framework Documentation
sphcoords.h
Go to the documentation of this file.
1 /* This file is part of the Tomographer project, which is distributed under the
2  * terms of the MIT license.
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2016 ETH Zurich, Institute for Theoretical Physics, Philippe Faist
7  * Copyright (c) 2017 Caltech, Institute for Quantum Information and Matter, Philippe Faist
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a copy
10  * of this software and associated documentation files (the "Software"), to deal
11  * in the Software without restriction, including without limitation the rights
12  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13  * copies of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included in
17  * all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
27 
28 #ifndef SPHCOORDS_H
29 #define SPHCOORDS_H
30 
31 #include <cmath>
32 
33 #include <Eigen/Eigen>
34 
35 #include <tomographer/tools/cxxutil.h> // tomographer_assert()
36 
37 
46 namespace Tomographer {
47 namespace MathTools {
48 namespace SphCoords {
49 
50 
67 template<typename Der1, typename Der2>
69 {
70  { using namespace Eigen; EIGEN_STATIC_ASSERT_LVALUE(Der2); }
71  typedef typename Eigen::MatrixBase<Der1>::Scalar Scalar;
72 
73  tomographer_assert(cart.cols() == 1 && rtheta.cols() == 1);
74  tomographer_assert(cart.rows() == rtheta.rows());
75 
76  const Eigen::Index ds = cart.rows()-1; // dimension of the sphere
77 
78  // see http://people.sc.fsu.edu/~jburkardt/cpp_src/hypersphere_properties/hypersphere_properties.cpp
79  // and http://en.wikipedia.org/wiki/N-sphere#Spherical_coordinates
80  //
81  // Remember that artcot(x/y) for us can be replaced by atan2(y, x)
82 
83  //
84  // R coordinate -- rtheta(0)
85  //
86  rtheta(0) = sqrt(cart.transpose()*cart);
87 
88  //
89  // theta coordinates -- rtheta(1..ds)
90  //
91 
92  // REMEMBER: .block() arguments are (OFFSET, SIZE) and not (STARTOFFSET, ENDOFFSET)
93  // .segment() arguments are (STARTPOS, LEN) and not (STARTPOS, ENDPOS)
94 
95  // all except last
96  rtheta.segment(1,ds-1).setZero();
97 
98  Eigen::Index i;
99 
100  Scalar val = pow(cart(ds),2);
101  for (i = ds-1; i >= 1; --i) {
102  val = val + pow(cart(i),2);
103  rtheta(i) = val;
104  }
105 
106  for (i = 1; i < ds; i++) {
107  rtheta(i) = atan2(sqrt(rtheta(i)), cart(i-1));
108  }
109 
110  // last angle, theta(ds-1) == rtheta(ds) :
111  val = sqrt(pow(cart(ds), 2) + pow(cart(ds-1), 2)) + cart(ds-1);
112 
113  rtheta(ds) = 2.0 * atan2(cart(ds), val);
114 }
115 
116 
138 template<typename Der1, typename Der2>
140  const typename Eigen::MatrixBase<Der1>::Scalar R = 1.0)
141 {
142  { using namespace Eigen; EIGEN_STATIC_ASSERT_LVALUE(Der2); }
143  // same as sph_to_cart, except that only the angles are given, and R is given
144  // separately, defaulting to 1.
145 
146  // typedef typename Eigen::MatrixBase<Der1>::Scalar Scalar;
147 
148  tomographer_assert(cart.cols() == 1 && theta.cols() == 1);
149  tomographer_assert(cart.rows() == theta.rows() + 1);
150 
151  const Eigen::Index ds = theta.rows(); // dimension of the sphere
152 
153  // see http://people.sc.fsu.edu/~jburkardt/cpp_src/hypersphere_properties/hypersphere_properties.cpp
154 
155  cart.setConstant(R); // R coordinate
156 
157  Eigen::Index i;
158  for (i = 0; i < ds; ++i) {
159  cart(i) *= cos(theta(i));
160  cart.segment(i+1, ds+1 - (i+1)) *= sin(theta(i));
161  }
162 }
163 
178 template<typename Der1, typename Der2>
180 {
181  { using namespace Eigen; EIGEN_STATIC_ASSERT_LVALUE(Der2); }
182  // typedef typename Eigen::MatrixBase<Der1>::Scalar Scalar;
183 
184  tomographer_assert(cart.cols() == 1 && rtheta.cols() == 1);
185  tomographer_assert(cart.rows() == rtheta.rows());
186 
187  const Eigen::Index ds = rtheta.rows()-1; // dimension of the sphere
188 
189  // see http://people.sc.fsu.edu/~jburkardt/cpp_src/hypersphere_properties/hypersphere_properties.cpp
190 
191  sphsurf_to_cart(cart, rtheta.segment(1,ds), rtheta(0));
192 }
193 
194 
195 
213 template<typename Der1>
215 {
216  const Eigen::Index ds = rtheta.rows()-1; // dimension of the sphere
217  typename Eigen::MatrixBase<Der1>::Scalar jac = pow(rtheta(0), (int)ds); // r^{n-1}
218 
219  Eigen::Index i;
220  for (i = 0; i < ds-1; ++i) {
221  jac *= pow(sin(rtheta(1+i)), (int)(ds-1-i));
222  }
223 
224  return jac;
225 }
226 
248 template<typename Der1>
250 {
251  const Eigen::Index ds = theta.rows();
252 
253  typename Eigen::MatrixBase<Der1>::Scalar jac = 1;
254 
255  Eigen::Index i;
256  for (i = 0; i < ds-1; ++i) {
257  jac *= pow(sin(theta(i)), (int)(ds-1-i));
258  }
259 
260  return jac;
261 }
262 
263 
280 template<typename Der1, typename Der2>
282 {
283  //
284  // For this calculation & the 2nd derivatives, see [Drafts&Calculations, Vol. V,
285  // 13.02.2015 (~60%)]
286  //
287 
288  { using namespace Eigen; EIGEN_STATIC_ASSERT_LVALUE(Der1); }
289  typedef typename Eigen::ArrayBase<Der1>::Scalar Scalar;
290 
291  const Eigen::Index ds = theta.rows();
292  const Eigen::Index n = ds + 1;
293 
294  tomographer_assert(theta.cols() == 1);
295  tomographer_assert(dxdtheta.rows() == (int)n);
296  tomographer_assert(dxdtheta.cols() == (int)ds);
297 
299  sintheta = theta.array().sin();
301  costheta = theta.array().cos();
302 
303  Eigen::Index i, k, mm;
304  for (i = 0; i < ds; ++i) {
305  for (k = 0; k < n; ++k) {
306  //std::cout << "k,i = "<< k<< ", "<< i << "\n";
307  Scalar val = 0.0;
308  // pick the right case
309  if (i > k) {
310  //std::cout << "[situation i>k]\n";
311  val = 0.0;
312  } else if (i == k && k < n - 1) {
313  //std::cout << "[situation i == k && k < n-1]\n";
314  val = -1;
315  for (mm = 0; mm <= i; ++mm) {
316  val *= sintheta(mm);
317  }
318  } else if (i == k && k == n-1) {
319  //std::cout << "[situation i == k && k == n-1]\n";
320  val = costheta(i);
321  for (mm = 0; mm < i; ++mm) {
322  val *= sintheta(mm);
323  }
324  } else if (i < k && k < n-1) {
325  //std::cout << "[situation i < k && k < n-1]\n";
326  val = costheta(i) * costheta(k);
327  for (mm = 0; mm < k; ++mm) {
328  if (mm == i) {
329  continue;
330  }
331  val *= sintheta(mm);
332  }
333  } else { // i < k && k == n-1
334  //std::cout << "[else: {situation i < k && k == n-1}]\n";
335  val = costheta(i);
336  for (mm = 0; mm < n-1; ++mm) {
337  if (mm == i) {
338  continue;
339  }
340  val *= sintheta(mm);
341  }
342  }
343  dxdtheta(k,i) = val;
344  //std::cout << "dxdtheta(k="<<k<<",i="<<i<<") = "<< val << "\n";
345  }
346  }
347 }
348 
364 template<typename Der1, typename Der2>
365 inline void sphsurf_diffjac2(Eigen::ArrayBase<Der1> & ddxddtheta, const Eigen::MatrixBase<Der2>& theta)
366 {
367  //
368  // For this calculation & the 2nd derivatives, see [Drafts&Calculations, Vol. V,
369  // 13.02.2015 (~60%)]
370  //
371 
372  { using namespace Eigen; EIGEN_STATIC_ASSERT_LVALUE(Der1); }
373  typedef typename Eigen::ArrayBase<Der1>::Scalar Scalar;
374 
375  const Eigen::Index ds = theta.rows();
376  const Eigen::Index n = ds + 1;
377 
378  tomographer_assert(theta.cols() == 1);
379  tomographer_assert(ddxddtheta.rows() == (int)n);
380  tomographer_assert(ddxddtheta.cols() == (int)(ds*ds));
381 
383  sintheta = theta.array().sin();
385  costheta = theta.array().cos();
386 
387  Eigen::Index i, j, k, mm;
388  for (k = 0; k < n; ++k) {
389  for (i = 0; i < ds; ++i) {
390  for (j = 0; j <= i; ++j) {
391  //std::cout << "k,i,j = "<< k<< ", "<< i << ", " << j << "\n";
392  Scalar val = 0.0;
393  if (i > k) {
394  val = 0.0;
395  } else if (i == k && k < n-1) {
396  val = -costheta(j);
397  for (mm = 0; mm <= i; ++mm) {
398  if (mm == j) {
399  continue;
400  }
401  val *= sintheta(mm);
402  }
403  } else if (i == k && k == n-1) {
404  if (j == i) {
405  val = -1.0;
406  for (mm = 0; mm <= i; ++mm) {
407  val *= sintheta(mm);
408  }
409  } else { // j < i
410  val = costheta(i)*costheta(j);
411  for (mm = 0; mm < i; ++mm) { // i not included
412  if (mm == j) {
413  continue;
414  }
415  val *= sintheta(mm);
416  }
417  }
418  } else if (i < k && k < n-1) {
419  if (j == i) {
420  val = -costheta(k);
421  for (mm = 0; mm < k; ++mm) {
422  val *= sintheta(mm);
423  }
424  } else { // j < i
425  val = costheta(j)*costheta(i)*costheta(k);
426  for (mm = 0; mm < k; ++mm) {
427  if (mm == j || mm == i) {
428  continue;
429  }
430  val *= sintheta(mm);
431  }
432  }
433  } else { // i < k && k == n-1
434  if (j == i) {
435  val = -1.0;
436  for (mm = 0; mm < n-1; ++mm) {
437  val *= sintheta(mm);
438  }
439  } else { // j < i
440  val = costheta(i)*costheta(j);
441  for (mm = 0; mm < n-1; ++mm) {
442  if (mm == i || mm == j) {
443  continue;
444  }
445  val *= sintheta(mm);
446  }
447  }
448  }
449  // set the calculated value
450  ddxddtheta(k, i+ds*j) = val;
451  ddxddtheta(k, j+ds*i) = val; // symmetric
452  }
453  }
454  }
455 }
456 
457 
458 } // namespace SphCoords
459 } // namespace MathTools
460 } // namespace Tomographer
461 
462 
463 #endif
void cart_to_sph(Eigen::MatrixBase< Der2 > &rtheta, const Eigen::MatrixBase< Der1 > &cart)
Convert Cartesian coordinates to spherical coordinates in N dimensions.
Definition: sphcoords.h:68
Base namespace for the Tomographer project.
Definition: densellh.h:45
void sphsurf_to_cart(Eigen::MatrixBase< Der2 > &cart, const Eigen::MatrixBase< Der1 > &theta, const typename Eigen::MatrixBase< Der1 >::Scalar R=1.0)
Convert spherical angles to Cartesian coordinates in N dimensions.
Definition: sphcoords.h:139
void sphsurf_diffjac(Eigen::ArrayBase< Der1 > &dxdtheta, const Eigen::MatrixBase< Der2 > &theta)
The differential of passing from spherical to cartesian coordinates on the sphere of unit radius...
Definition: sphcoords.h:281
SegmentReturnType segment(Index start, Index n)
Derived & setConstant(const Scalar &value)
Some C++ utilities, with a tad of C++11 tricks.
ArrayWrapper< Derived > array()
Eigen::Transpose< Derived > transpose()
void sphsurf_diffjac2(Eigen::ArrayBase< Der1 > &ddxddtheta, const Eigen::MatrixBase< Der2 > &theta)
The second order differential of passing from spherical to cartesian coordinates on the sphere of uni...
Definition: sphcoords.h:365
Eigen::MatrixBase< Der1 >::Scalar surf_sph_jacobian(const Eigen::MatrixBase< Der1 > &theta)
Surface element of the hypersphere.
Definition: sphcoords.h:249
Eigen::MatrixBase< Der1 >::Scalar cart_to_sph_jacobian(const Eigen::MatrixBase< Der1 > &rtheta)
Volume element of the hypersphere.
Definition: sphcoords.h:214
#define tomographer_assert(...)
Assertion test macro.
Definition: cxxdefs.h:84
void sph_to_cart(Eigen::MatrixBase< Der2 > &cart, const Eigen::MatrixBase< Der1 > &rtheta)
Convert spherical coordinates to Cartesian coordinates in N dimensions.
Definition: sphcoords.h:179