Version: SMASH-3.1
angles.h
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2015,2017-2018,2020,2022
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);
95  void set_psi(const double psi);
104  void set_costheta(const double cos);
115  void set_theta(const double theta);
127  bool add_to_theta(const double delta);
142  bool add_to_theta(const double delta, const bool reverse);
144  double phi() const;
146  double psi() const;
148  double costheta() const;
150  double sintheta() const;
156  double x() const;
162  double y() const;
168  double z() const;
170  ThreeVector inline threevec() const;
172  double theta() const;
173 
178  struct InvalidTheta : public std::invalid_argument {
179  using std::invalid_argument::invalid_argument;
180  };
181 
182  private:
184  double phi_;
186  double psi_;
188  double costheta_;
189 };
190 
195 inline std::ostream &operator<<(std::ostream &out, const Angles &a) {
196  return out << "φ:" << field << a.phi() << ", cos ϑ:" << field << a.costheta();
197 }
198 
200  /* Isotropic distribution: phi in [0, 2pi) and cos(theta) in [-1,1]. */
201  phi_ = random::uniform(0.0, twopi);
202  costheta_ = random::uniform(-1.0, 1.0);
203 }
204 
205 void inline Angles::set_phi(const double newphi) {
206  /* Make sure that phi is in the range [0,2pi). */
207  phi_ = newphi;
208  if (newphi < 0 || newphi >= twopi) {
209  phi_ -= twopi * std::floor(newphi / twopi);
210  }
211 }
212 
213 void inline Angles::set_psi(const double newpsi) {
214  /* Make sure that phi is in the range [0,2pi). */
215  psi_ = newpsi;
216  if (newpsi < 0 || newpsi >= twopi) {
217  psi_ -= twopi * std::floor(newpsi / twopi);
218  }
219 }
220 
221 void inline Angles::set_costheta(const double newcos) {
222  costheta_ = newcos;
223  /* check if costheta_ is in -1..1. If not, well. Error handling here
224  * is a lot harder than in the above. Still, I will silently do the
225  * same as above. Note, though, that costheta = 1 is allowed, even if
226  * it cannot be generated by distribute_isotropically(). */
227  if ((costheta_ < -1. - really_small) || (costheta_ > 1. + really_small)) {
228  throw InvalidTheta("Wrong value for costheta (must be in [-1,1]): " +
229  std::to_string(costheta_));
230  }
231  if (costheta_ < -1.) {
232  costheta_ = -1.;
233  } else if (costheta_ > 1.) {
234  costheta_ = 1.;
235  }
236 }
237 void inline Angles::set_theta(const double newtheta) {
238  /* no error handling necessary, because this gives a sensible answer
239  * for every real number. */
240  set_costheta(std::cos(newtheta));
241 }
242 
243 bool inline Angles::add_to_theta(const double delta) {
244  if (delta < -M_PI || delta > M_PI) {
245  throw InvalidTheta("Cannot advance polar angle by " +
246  std::to_string(delta));
247  }
248  double theta_plus_delta = delta + theta();
249  /* if sum is not in [0, PI], force it to be there:
250  * "upper" overflow:
251  * theta + delta + the_new_angle = 2*M_PI */
252  if (theta_plus_delta > M_PI) {
253  set_theta(twopi - theta_plus_delta);
254  // set_phi takes care that phi_ is in [0 .. 2*M_PI]
255  set_phi(phi() + M_PI);
256  return true; // meaning "we did change phi"
257  // "lower" overflow: theta + delta switches sign
258  } else if (theta_plus_delta < 0) {
259  set_theta(-theta_plus_delta);
260  set_phi(phi() + M_PI);
261  return true; // meaning "we did change phi"
262  // no overflow: set theta, do not touch phi:
263  } else {
264  set_theta(theta_plus_delta);
265  }
266  return false; // meaning "we did NOT change phi"
267 }
268 bool inline Angles::add_to_theta(const double delta, const bool reverse) {
269  double plusminus_one = reverse ? -1.0 : +1.0;
270  bool this_reverse = add_to_theta(plusminus_one * delta);
271  /* if we had to reverse first time and now reverse again OR if we
272  * didn't reverse in either part, we do not reverse in total.
273  * else: if we reverse in one, but not the other part, we reverse in
274  * total. */
275  return this_reverse ^ reverse;
276 }
277 
278 double inline Angles::costheta() const { return costheta_; }
279 double inline Angles::phi() const { return phi_; }
280 double inline Angles::psi() const { return psi_; }
281 double inline Angles::sintheta() const {
282  return std::sqrt(1.0 - costheta_ * costheta_);
283 }
284 double inline Angles::x() const { return sintheta() * std::cos(phi_); }
285 double inline Angles::y() const { return sintheta() * std::sin(phi_); }
286 double inline Angles::z() const { return costheta_; }
287 
289  return ThreeVector(x(), y(), z());
290 }
291 
292 double inline Angles::theta() const { return std::acos(costheta_); }
293 
294 } // namespace smash
295 
296 #endif // SRC_INCLUDE_SMASH_ANGLES_H_
Angles provides a common interface for generating directions: i.e., two angles that should be interpr...
Definition: angles.h:59
ThreeVector threevec() const
Definition: angles.h:288
void distribute_isotropically()
Populate the object with a new direction.
Definition: angles.h:199
double z() const
Definition: angles.h:286
double x() const
Definition: angles.h:284
void set_costheta(const double cos)
Set the polar angle from its cosine.
Definition: angles.h:221
bool add_to_theta(const double delta)
Advance polar angle.
Definition: angles.h:243
Angles(double ph, double cost)
Definition: angles.h:71
void set_phi(const double phi)
Sets the azimuthal angle.
Definition: angles.h:205
void set_theta(const double theta)
Set the polar angle.
Definition: angles.h:237
double y() const
Definition: angles.h:285
double theta() const
Definition: angles.h:292
double phi() const
Definition: angles.h:279
double phi_
Azimuthal angle .
Definition: angles.h:184
double psi_
Euler angle .
Definition: angles.h:186
double costheta_
Cosine of polar angle .
Definition: angles.h:188
Angles()
Default constructor.
Definition: angles.h:65
void set_psi(const double psi)
Sets the euler angle psi.
Definition: angles.h:213
double psi() const
Definition: angles.h:280
double sintheta() const
Definition: angles.h:281
double costheta() const
Definition: angles.h:278
The ThreeVector class represents a physical three-vector with the components .
Definition: threevector.h:31
Collection of useful constants that are known at compile time.
std::ostream & operator<<(std::ostream &out, const ActionPtr &action)
Convenience: dereferences the ActionPtr to Action.
Definition: action.h:547
std::basic_ostream< CharT, Traits > & field(std::basic_ostream< CharT, Traits > &s)
Stream modifier to align the next object to a specific width w.
T uniform(T min, T max)
Definition: random.h:88
Definition: action.h:24
constexpr double twopi
.
Definition: constants.h:45
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:37
Thrown for invalid values for theta.
Definition: angles.h:178