Version: SMASH-2.0
angles.h
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2020
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #ifndef SRC_INCLUDE_SMASH_ANGLES_H_
11 #define SRC_INCLUDE_SMASH_ANGLES_H_
12 
13 #include <iostream>
14 #include <stdexcept>
15 
16 #include "constants.h"
17 #include "iomanipulators.h"
18 #include "random.h"
19 #include "threevector.h"
20 
21 namespace smash {
22 
44 /*
45  * Internals
46  * ---------
47  *
48  * The object internally stores the azimuthal angle \f$\varphi\f$ and
49  * the cosine of the polar angle \f$\cos\vartheta\f$. Nobody should rely
50  * on this never changing, though; the interface user should be totally
51  * oblivious to this.
52  *
53  * Possible future improvements
54  * ----------------------------
55  *
56  * More distributions need to be implemented once there is a physics
57  * case to use them.
58  */
59 class Angles {
60  public:
65  Angles() : phi_(0), costheta_(0) {}
71  Angles(double ph, double cost) {
72  set_phi(ph);
73  set_costheta(cost);
74  }
88  void set_phi(const double phi);
97  void set_costheta(const double cos);
108  void set_theta(const double theta);
120  bool add_to_theta(const double delta);
135  bool add_to_theta(const double delta, const bool reverse);
137  double phi() const;
139  double costheta() const;
141  double sintheta() const;
147  double x() const;
153  double y() const;
159  double z() const;
161  ThreeVector inline threevec() const;
163  double theta() const;
164 
169  struct InvalidTheta : public std::invalid_argument {
170  using std::invalid_argument::invalid_argument;
171  };
172 
173  private:
175  double phi_;
177  double costheta_;
178 };
179 
184 inline std::ostream &operator<<(std::ostream &out, const Angles &a) {
185  return out << "φ:" << field << a.phi() << ", cos ϑ:" << field << a.costheta();
186 }
187 
189  /* Isotropic distribution: phi in [0, 2pi) and cos(theta) in [-1,1]. */
190  phi_ = random::uniform(0.0, twopi);
191  costheta_ = random::uniform(-1.0, 1.0);
192 }
193 
194 void inline Angles::set_phi(const double newphi) {
195  /* Make sure that phi is in the range [0,2pi). */
196  phi_ = newphi;
197  if (newphi < 0 || newphi >= twopi) {
198  phi_ -= twopi * std::floor(newphi / twopi);
199  }
200 }
201 
202 void inline Angles::set_costheta(const double newcos) {
203  costheta_ = newcos;
204  /* check if costheta_ is in -1..1. If not, well. Error handling here
205  * is a lot harder than in the above. Still, I will silently do the
206  * same as above. Note, though, that costheta = 1 is allowed, even if
207  * it cannot be generated by distribute_isotropically(). */
208  if ((costheta_ < -1. - really_small) || (costheta_ > 1. + really_small)) {
209  throw InvalidTheta("Wrong value for costheta (must be in [-1,1]): " +
210  std::to_string(costheta_));
211  }
212  if (costheta_ < -1.) {
213  costheta_ = -1.;
214  } else if (costheta_ > 1.) {
215  costheta_ = 1.;
216  }
217 }
218 void inline Angles::set_theta(const double newtheta) {
219  /* no error handling necessary, because this gives a sensible answer
220  * for every real number. */
221  set_costheta(std::cos(newtheta));
222 }
223 
224 bool inline Angles::add_to_theta(const double delta) {
225  if (delta < -M_PI || delta > M_PI) {
226  throw InvalidTheta("Cannot advance polar angle by " +
227  std::to_string(delta));
228  }
229  double theta_plus_delta = delta + theta();
230  /* if sum is not in [0, PI], force it to be there:
231  * "upper" overflow:
232  * theta + delta + the_new_angle = 2*M_PI */
233  if (theta_plus_delta > M_PI) {
234  set_theta(twopi - theta_plus_delta);
235  // set_phi takes care that phi_ is in [0 .. 2*M_PI]
236  set_phi(phi() + M_PI);
237  return true; // meaning "we did change phi"
238  // "lower" overflow: theta + delta switches sign
239  } else if (theta_plus_delta < 0) {
240  set_theta(-theta_plus_delta);
241  set_phi(phi() + M_PI);
242  return true; // meaning "we did change phi"
243  // no overflow: set theta, do not touch phi:
244  } else {
245  set_theta(theta_plus_delta);
246  }
247  return false; // meaning "we did NOT change phi"
248 }
249 bool inline Angles::add_to_theta(const double delta, const bool reverse) {
250  double plusminus_one = reverse ? -1.0 : +1.0;
251  bool this_reverse = add_to_theta(plusminus_one * delta);
252  /* if we had to reverse first time and now reverse again OR if we
253  * didn't reverse in either part, we do not reverse in total.
254  * else: if we reverse in one, but not the other part, we reverse in
255  * total. */
256  return this_reverse ^ reverse;
257 }
258 
259 double inline Angles::costheta() const { return costheta_; }
260 double inline Angles::phi() const { return phi_; }
261 double inline Angles::sintheta() const {
262  return std::sqrt(1.0 - costheta_ * costheta_);
263 }
264 double inline Angles::x() const { return sintheta() * std::cos(phi_); }
265 double inline Angles::y() const { return sintheta() * std::sin(phi_); }
266 double inline Angles::z() const { return costheta_; }
267 
269  return ThreeVector(x(), y(), z());
270 }
271 
272 double inline Angles::theta() const { return std::acos(costheta_); }
273 
274 } // namespace smash
275 
276 #endif // SRC_INCLUDE_SMASH_ANGLES_H_
smash
Definition: action.h:24
smash::Angles::phi
double phi() const
Definition: angles.h:260
smash::Angles::y
double y() const
Definition: angles.h:265
smash::Angles::set_phi
void set_phi(const double phi)
Sets the azimuthal angle.
Definition: angles.h:194
smash::field
std::basic_ostream< CharT, Traits > & field(std::basic_ostream< CharT, Traits > &s)
Definition: iomanipulators.h:30
smash::operator<<
std::ostream & operator<<(std::ostream &out, const ActionPtr &action)
Definition: action.h:518
smash::Angles::distribute_isotropically
void distribute_isotropically()
Populate the object with a new direction.
Definition: angles.h:188
smash::Angles::set_theta
void set_theta(const double theta)
Set the polar angle.
Definition: angles.h:218
smash::Angles::x
double x() const
Definition: angles.h:264
smash::really_small
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:37
random.h
smash::ThreeVector
Definition: threevector.h:31
smash::twopi
constexpr double twopi
.
Definition: constants.h:42
smash::Angles::Angles
Angles()
Default constructor.
Definition: angles.h:65
smash::Angles::Angles
Angles(double ph, double cost)
Definition: angles.h:71
threevector.h
smash::Angles::z
double z() const
Definition: angles.h:266
smash::Angles::set_costheta
void set_costheta(const double cos)
Set the polar angle from its cosine.
Definition: angles.h:202
smash::Angles::phi_
double phi_
Azimuthal angle .
Definition: angles.h:175
smash::Angles::threevec
ThreeVector threevec() const
Definition: angles.h:268
constants.h
iomanipulators.h
smash::Angles::InvalidTheta
Definition: angles.h:169
smash::Angles::sintheta
double sintheta() const
Definition: angles.h:261
smash::Angles
Angles provides a common interface for generating directions: i.e., two angles that should be interpr...
Definition: angles.h:59
smash::random::uniform
T uniform(T min, T max)
Definition: random.h:88
smash::Angles::theta
double theta() const
Definition: angles.h:272
smash::Angles::costheta_
double costheta_
Cosine of polar angle .
Definition: angles.h:177
smash::Angles::add_to_theta
bool add_to_theta(const double delta)
Advance polar angle.
Definition: angles.h:224
smash::Angles::costheta
double costheta() const
Definition: angles.h:259