Tomographer  v1.0a
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 <Eigen/Eigen>
31 #include <cmath>
32 
41 namespace Tomographer
42 {
43 namespace SphCoords
44 {
45 
46 
63 template<typename Der1, typename Der2>
65 {
66  { using namespace Eigen; EIGEN_STATIC_ASSERT_LVALUE(Der2); }
67  typedef typename Eigen::MatrixBase<Der1>::Scalar Scalar;
68 
69  eigen_assert(cart.cols() == 1 && rtheta.cols() == 1);
70  eigen_assert(cart.rows() == rtheta.rows());
71 
72  const size_t ds = cart.rows()-1; // dimension of the sphere
73 
74  // see http://people.sc.fsu.edu/~jburkardt/cpp_src/hypersphere_properties/hypersphere_properties.cpp
75  // and http://en.wikipedia.org/wiki/N-sphere#Spherical_coordinates
76  //
77  // Remember that artcot(x/y) for us can be replaced by atan2(y, x)
78 
79  //
80  // R coordinate -- rtheta(0)
81  //
82  rtheta(0) = sqrt(cart.transpose()*cart);
83 
84  //
85  // theta coordinates -- rtheta(1..ds)
86  //
87 
88  // REMEMBER: .block() arguments are (OFFSET, SIZE) and not (STARTOFFSET, ENDOFFSET)
89 
90  // all except last
91  rtheta.block(1,0,ds-1,1).setZero();
92 
93  size_t i;
94 
95  Scalar val = pow(cart(ds),2);
96  for (i = ds-1; i >= 1; --i) {
97  val = val + pow(cart(i),2);
98  rtheta(i) = val;
99  }
100 
101  for (i = 1; i < ds; i++) {
102  rtheta(i) = atan2(sqrt(rtheta(i)), cart(i-1));
103  }
104 
105  // last angle, theta(ds-1) == rtheta(ds) :
106  val = sqrt(pow(cart(ds), 2) + pow(cart(ds-1), 2)) + cart(ds-1);
107 
108  rtheta(ds) = 2.0 * atan2(cart(ds), val);
109 }
110 
111 
133 template<typename Der1, typename Der2>
135  const typename Eigen::MatrixBase<Der1>::Scalar R = 1.0)
136 {
137  { using namespace Eigen; EIGEN_STATIC_ASSERT_LVALUE(Der2); }
138  // same as sph_to_cart, except that only the angles are given, and R is given
139  // separately, defaulting to 1.
140 
141  // typedef typename Eigen::MatrixBase<Der1>::Scalar Scalar;
142 
143  eigen_assert(cart.cols() == 1 && theta.cols() == 1);
144  eigen_assert(cart.rows() == theta.rows() + 1);
145 
146  const size_t ds = theta.rows(); // dimension of the sphere
147 
148  // see http://people.sc.fsu.edu/~jburkardt/cpp_src/hypersphere_properties/hypersphere_properties.cpp
149 
150  cart.setConstant(R); // R coordinate
151 
152  size_t i;
153  for (i = 0; i < ds; ++i) {
154  cart(i) *= cos(theta(i));
155  cart.block(i+1, 0, ds+1 - (i+1), 1) *= sin(theta(i));
156  }
157 }
158 
173 template<typename Der1, typename Der2>
175 {
176  { using namespace Eigen; EIGEN_STATIC_ASSERT_LVALUE(Der2); }
177  // typedef typename Eigen::MatrixBase<Der1>::Scalar Scalar;
178 
179  eigen_assert(cart.cols() == 1 && rtheta.cols() == 1);
180  eigen_assert(cart.rows() == rtheta.rows());
181 
182  const size_t ds = rtheta.rows()-1; // dimension of the sphere
183 
184  // see http://people.sc.fsu.edu/~jburkardt/cpp_src/hypersphere_properties/hypersphere_properties.cpp
185 
186  sphsurf_to_cart(cart, rtheta.block(1,0,ds,1), rtheta(0));
187 }
188 
189 
190 
207 template<typename Der1>
209 {
210  const size_t ds = rtheta.rows()-1; // dimension of the sphere
211  typename Eigen::MatrixBase<Der1>::Scalar jac = pow(rtheta(0), (int)ds); // r^{n-1}
212 
213  size_t i;
214  for (i = 0; i < ds-1; ++i) {
215  jac *= pow(sin(rtheta(1+i)), (int)(ds-1-i));
216  }
217 
218  return jac;
219 }
220 
241 template<typename Der1>
243 {
244  const size_t ds = theta.rows();
245 
246  typename Eigen::MatrixBase<Der1>::Scalar jac = 1;
247 
248  size_t i;
249  for (i = 0; i < ds-1; ++i) {
250  jac *= pow(sin(theta(i)), (int)(ds-1-i));
251  }
252 
253  return jac;
254 }
255 
256 
273 template<typename Der1, typename Der2>
275 {
276  //
277  // For this calculation & the 2nd derivatives, see [Drafts&Calculations, Vol. V,
278  // 13.02.2015 (~60%)]
279  //
280 
281  { using namespace Eigen; EIGEN_STATIC_ASSERT_LVALUE(Der1); }
282  typedef typename Eigen::ArrayBase<Der1>::Scalar Scalar;
283 
284  const size_t ds = theta.rows();
285  const size_t n = ds + 1;
286 
287  eigen_assert(theta.cols() == 1);
288  eigen_assert(dxdtheta.rows() == (int)n);
289  eigen_assert(dxdtheta.cols() == (int)ds);
290 
292  sintheta = theta.array().sin();
294  costheta = theta.array().cos();
295 
296  size_t i, k, mm;
297  for (i = 0; i < ds; ++i) {
298  for (k = 0; k < n; ++k) {
299  //std::cout << "k,i = "<< k<< ", "<< i << "\n";
300  Scalar val = 0.0;
301  // pick the right case
302  if (i > k) {
303  //std::cout << "[situation i>k]\n";
304  val = 0.0;
305  } else if (i == k && k < n - 1) {
306  //std::cout << "[situation i == k && k < n-1]\n";
307  val = -1;
308  for (mm = 0; mm <= i; ++mm) {
309  val *= sintheta(mm);
310  }
311  } else if (i == k && k == n-1) {
312  //std::cout << "[situation i == k && k == n-1]\n";
313  val = costheta(i);
314  for (mm = 0; mm < i; ++mm) {
315  val *= sintheta(mm);
316  }
317  } else if (i < k && k < n-1) {
318  //std::cout << "[situation i < k && k < n-1]\n";
319  val = costheta(i) * costheta(k);
320  for (mm = 0; mm < k; ++mm) {
321  if (mm == i) {
322  continue;
323  }
324  val *= sintheta(mm);
325  }
326  } else { // i < k && k == n-1
327  //std::cout << "[else: {situation i < k && k == n-1}]\n";
328  val = costheta(i);
329  for (mm = 0; mm < n-1; ++mm) {
330  if (mm == i) {
331  continue;
332  }
333  val *= sintheta(mm);
334  }
335  }
336  dxdtheta(k,i) = val;
337  //std::cout << "dxdtheta(k="<<k<<",i="<<i<<") = "<< val << "\n";
338  }
339  }
340 }
341 
357 template<typename Der1, typename Der2>
359 {
360  //
361  // For this calculation & the 2nd derivatives, see [Drafts&Calculations, Vol. V,
362  // 13.02.2015 (~60%)]
363  //
364 
365  { using namespace Eigen; EIGEN_STATIC_ASSERT_LVALUE(Der1); }
366  typedef typename Eigen::ArrayBase<Der1>::Scalar Scalar;
367 
368  const size_t ds = theta.rows();
369  const size_t n = ds + 1;
370 
371  eigen_assert(theta.cols() == 1);
372  eigen_assert(ddxddtheta.rows() == (int)n);
373  eigen_assert(ddxddtheta.cols() == (int)(ds*ds));
374 
376  sintheta = theta.array().sin();
378  costheta = theta.array().cos();
379 
380  size_t i, j, k, mm;
381  for (k = 0; k < n; ++k) {
382  for (i = 0; i < ds; ++i) {
383  for (j = 0; j <= i; ++j) {
384  //std::cout << "k,i,j = "<< k<< ", "<< i << ", " << j << "\n";
385  Scalar val = 0.0;
386  if (i > k) {
387  val = 0.0;
388  } else if (i == k && k < n-1) {
389  val = -costheta(j);
390  for (mm = 0; mm <= i; ++mm) {
391  if (mm == j) {
392  continue;
393  }
394  val *= sintheta(mm);
395  }
396  } else if (i == k && k == n-1) {
397  if (j == i) {
398  val = -1.0;
399  for (mm = 0; mm <= i; ++mm) {
400  val *= sintheta(mm);
401  }
402  } else { // j < i
403  val = costheta(i)*costheta(j);
404  for (mm = 0; mm < i; ++mm) { // i not included
405  if (mm == j) {
406  continue;
407  }
408  val *= sintheta(mm);
409  }
410  }
411  } else if (i < k && k < n-1) {
412  if (j == i) {
413  val = -costheta(k);
414  for (mm = 0; mm < k; ++mm) {
415  val *= sintheta(mm);
416  }
417  } else { // j < i
418  val = costheta(j)*costheta(i)*costheta(k);
419  for (mm = 0; mm < k; ++mm) {
420  if (mm == j || mm == i) {
421  continue;
422  }
423  val *= sintheta(mm);
424  }
425  }
426  } else { // i < k && k == n-1
427  if (j == i) {
428  val = -1.0;
429  for (mm = 0; mm < n-1; ++mm) {
430  val *= sintheta(mm);
431  }
432  } else { // j < i
433  val = costheta(i)*costheta(j);
434  for (mm = 0; mm < n-1; ++mm) {
435  if (mm == i || mm == j) {
436  continue;
437  }
438  val *= sintheta(mm);
439  }
440  }
441  }
442  // set the calculated value
443  ddxddtheta(k, i+ds*j) = val;
444  ddxddtheta(k, j+ds*i) = val; // symmetric
445  }
446  }
447  }
448 }
449 
450 
451 }
452 }
453 
454 
455 #endif
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:134
Base namespace for the Tomographer project.
Definition: dmmhrw.h:51
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:64
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:358
Eigen::MatrixBase< Der1 >::Scalar surf_sph_jacobian(const Eigen::MatrixBase< Der1 > &theta)
Surface element of the hypersphere.
Definition: sphcoords.h:242
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:274
Derived & setConstant(const Scalar &value)
Block< Derived > block(Index startRow, Index startCol, Index blockRows, Index blockCols)
ArrayWrapper< Derived > array()
Eigen::MatrixBase< Der1 >::Scalar cart_to_sph_jacobian(const Eigen::MatrixBase< Der1 > &rtheta)
Volume element of the hypersphere.
Definition: sphcoords.h:208
Eigen::Transpose< Derived > transpose()
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:174