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