Skip to content

Commit 847a473

Browse files
committed
Added unit tests; reworked Wigner D functions, but they are not yet functioning.
1 parent f49cbe0 commit 847a473

15 files changed

+217
-238
lines changed

CMakeLists.txt

+6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ set(CMAKE_CXX_FLAGS "-std=c++11" )
66

77
include(CommonMacros)
88

9+
# Includes Catch in the project:
10+
add_subdirectory(external/catch)
11+
include_directories(${CATCH_INCLUDE_DIR} ${COMMON_INCLUDES})
12+
enable_testing(true) # Enables unit-testing.
13+
914
# setup ROOT includes and libraries
1015
find_package(ROOT)
1116

@@ -45,5 +50,6 @@ set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Wno-long-long -Werror=
4550
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -D ELPP_DISABLE_DEBUG_LOGS" )
4651

4752
add_subdirectory(src)
53+
add_subdirectory(test)
4854
add_subdirectory(programs)
4955

examples/bat_gen/dkkpi.cxx

+2
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ dkkpi::dkkpi(std::string name)
6464

6565
D_->prepare();
6666

67+
D_->printDecayChain();
68+
6769
std::vector<std::shared_ptr<yap::ComplexParameter> > freeAmps = D_->freeAmplitudes();
6870
for (unsigned i = 0; i < freeAmps.size(); ++i)
6971
freeAmps[i]->setValue(yap::Complex_1);

external/catch/CMakeLists.txt

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
cmake_minimum_required(VERSION 2.8.8)
2+
project(catch_builder CXX)
3+
include(ExternalProject)
4+
find_package(Git REQUIRED)
5+
6+
ExternalProject_Add(
7+
catch
8+
PREFIX ${CMAKE_BINARY_DIR}/catch
9+
GIT_REPOSITORY https://github.com/philsquared/Catch.git
10+
TIMEOUT 10
11+
UPDATE_COMMAND ${GIT_EXECUTABLE} pull
12+
CONFIGURE_COMMAND ""
13+
BUILD_COMMAND ""
14+
INSTALL_COMMAND ""
15+
LOG_DOWNLOAD ON
16+
)
17+
18+
# Expose required variable (CATCH_INCLUDE_DIR) to parent scope
19+
ExternalProject_Get_Property(catch source_dir)
20+
set(CATCH_INCLUDE_DIR ${source_dir}/include CACHE INTERNAL "Path to include folder for Catch")

include/BlattWeisskopf.h

+3
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,10 @@ class BlattWeisskopf : public AmplitudeComponent, public DataAccessor
7171
/// DecayChannel this BlattWeisskopf belongs to
7272
DecayChannel* DecayChannel_;
7373

74+
/// Blatt-Weisskopf factor at nominal mass
7475
std::shared_ptr<RealCachedDataValue> Fq_r;
76+
77+
/// Blatt-Weisskopf factor at data mass
7578
std::shared_ptr<RealCachedDataValue> Fq_ab;
7679
};
7780

include/DecayChannel.h

+3
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,10 @@ class DecayChannel : public AmplitudeComponent, public DataAccessor
143143
/// SpinAmplitude can be shared between several DecayChannels
144144
std::shared_ptr<SpinAmplitude> SpinAmplitude_;
145145

146+
/// Independent amplitude for channel's contribution to full model
146147
std::shared_ptr<ComplexParameter> FreeAmplitude_;
148+
149+
/// amplitude from spin dynamics, mass shapes, etc.
147150
std::shared_ptr<ComplexCachedDataValue> FixedAmplitude_;
148151

149152
};

include/HelicitySpinAmplitude.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class HelicitySpinAmplitude : public SpinAmplitude
8585

8686
/// Clebsch-Gordan coefficient for 2*λ_1, 2*λ_2
8787
/// \todo make this a Parameter???
88-
std::map<std::shared_ptr<const ParticleCombination>, double> ClebschGordanCoefficients_;
88+
ParticleCombinationMap<double> ClebschGordanCoefficients_;
8989

9090
std::shared_ptr<ComplexCachedDataValue> SpinAmplitude_;
9191

include/MathUtilities.h

+5-9
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace yap {
3030

3131
/// return n!
3232
inline double factorial(int n)
33-
{ return std::tgamma(n + 1.); }
33+
{ return std::tgamma(n + 1); }
3434

3535
/// returns whether val is an odd number
3636
inline bool isOdd(int val)
@@ -41,14 +41,10 @@ inline bool isEven(int val)
4141
{ return not isOdd(val); }
4242

4343
/// extracts sign from value
44-
inline int signum(int val)
45-
{
46-
if (val < 0)
47-
return -1;
48-
if (val > 0)
49-
return +1;
50-
return 0;
51-
}
44+
template <typename T>
45+
typename std::enable_if<std::is_signed<T>::value, int>::type
46+
signum(const T& val)
47+
{ return (T(0) < val) - (val < T(0)); }
5248

5349
/// optimized function for (-1)^n
5450
inline int powMinusOne(const int exponent)

include/WignerD.h

+37-64
Original file line numberDiff line numberDiff line change
@@ -17,84 +17,57 @@
1717
*/
1818

1919
/// \file
20+
/// \brief Functions for caching and calculating Wigner d and D functions
21+
/// \author Daniel Greenwald, Johannes Rauch
22+
///
23+
/// Calculation is based on M. E. Rose's _Elementary Theory of Angular Momentum_ (1957):
24+
///
25+
/// \f$ D^{J}_{MN}(\alpha, \beta, \gamma) \equiv \exp(-iM\alpha) d^{J}_{MN}(\beta) \exp(-iN\gamma)\f$
26+
///
27+
/// \f$ d^{J}_{MN}(\beta) \equiv \sum_{K} A (-)^{K+M-N} B_{K} (\cos\frac{\beta}{2})^{2J+N-M-2K} (\sin\frac{\beta}{2})^{M-N+2K} \f$
28+
///
29+
/// with \f$ A \equiv (J+N)!(J-N)!(J+M)!(J-M)!\f$
30+
/// and \f$ B_{K} \equiv (J-M-K)!((J+N-K)!(K+M-N)!K!\f$.
31+
///
32+
/// The limits on K are governed by the factorials,
33+
/// since \f$ (1 / X!) = 0 \f$ if \f$ X < 0\f$.
34+
///
35+
/// We only cache matrix elements with M in [-J, J] and N in [-J, min(0, m)].
36+
/// This amounts to the lower triangle and the diagonal without the bottom right corner.
37+
/// The uncached matrix elements are given by the by the symmetries
38+
/// - \f$ d^{J}_{MN}(\beta) = (-)^(M-N) d^{J}_{NM}(\beta)\f$
39+
/// - \f$ d^{J}_{MN}(\beta) = (-)^{M-N) d^{J}_{-N-M}(\beta)\f$
2040

2141
#ifndef yap_WignerD_h
2242
#define yap_WignerD_h
2343

44+
#include "Constants.h"
45+
2446
#include <complex>
25-
#include <vector>
2647

2748
namespace yap {
2849

29-
/// Wigner d-function d^j_{two_m two_n}(theta)
30-
double dFunction(const int two_j, const int two_m, const int two_n, const double theta);
31-
32-
/// spherical harmonics Y_l^{two_m}(theta, phi)
33-
std::complex<double> sphericalHarmonic(const int two_l, const int two_m, const double theta, const double phi);
34-
35-
/// Wigner D-function D^j_{two_m two_n}(alpha, beta, gamma)
36-
std::complex<double> DFunction(const int two_j, const int two_m, const int two_n, const double alpha, const double beta, const double gamma);
37-
38-
/// complex conjugate of Wigner D-function D^j_{two_m two_n}(alpha, beta, gamma)
39-
std::complex<double> DFunctionConj(const int two_j, const int two_m, const int two_n, const double alpha, const double beta, const double gamma);
40-
41-
42-
/// \class dFunctionCached
43-
/// \brief cached Wigner d and D functions
44-
/// \author Daniel Greenwald, Johannes Rauch
45-
/// This class has been copied from rootpwa and modified
46-
class dFunctionCached
47-
{
48-
49-
public:
50-
51-
struct cacheEntryType {
52-
cacheEntryType()
53-
: constTerm(0)
54-
{ }
50+
/// Wigner D-function \f$ D^{J}_{M N}(\alpha, \beta, \gamma) \f$
51+
std::complex<double> DFunction(unsigned char twoJ, char twoM, char twoN, double alpha, double beta, double gamma);
5552

56-
double constTerm;
57-
std::vector<int> kmn1;
58-
std::vector<int> jmnk;
59-
std::vector<double> factor;
60-
};
53+
/// \return Wigner d-function \f$ d^{J}_{M N}(\beta) \f$
54+
/// \param twoJ twice the total spin of system
55+
/// \param twoM twice the first spin projection
56+
/// \param twoN twice the second spin projection
57+
/// \param beta rotation angle
58+
double dFunction(unsigned char twoJ, char twoM, char twoN, double beta);
6159

62-
typedef std::vector<std::vector<std::vector<cacheEntryType> > > cacheType;
6360

61+
namespace dMatrix {
6462

65-
/// get singleton instance
66-
static dFunctionCached& instance()
67-
{ return _instance; }
63+
/// Cache d-matrix elements for representation of spin J
64+
/// \param twoJ twice the spin of the representation
65+
void cache(unsigned char twoJ);
6866

69-
/// \return d^j_{two_m two_n}(theta)
70-
double operator ()(const int two_j, const int two_m, const int two_n, const double theta);
71-
72-
/// \return caching flag
73-
static bool useCache()
74-
{ return _useCache; }
75-
76-
/// sets caching flag
77-
static void setUseCache(const bool useCache = true)
78-
{ _useCache = useCache; }
79-
80-
/// \return cache size in bytes
81-
static unsigned int cacheSize();
82-
83-
84-
private:
85-
86-
dFunctionCached();
87-
~dFunctionCached();
88-
dFunctionCached(const dFunctionCached&);
89-
dFunctionCached& operator =(const dFunctionCached&);
90-
91-
static dFunctionCached _instance; ///< singleton instance
92-
static bool _useCache; ///< if set to true, cache is used
93-
94-
static const unsigned int _maxJ = 21; ///< maximum allowed angular momentum * 2 + 1
95-
static cacheEntryType* _cache[_maxJ][_maxJ + 1][_maxJ + 1]; ///< cache for intermediate terms [two_j][two_m][two_n]
96-
};
67+
/// \return cache size in bytes
68+
unsigned int cacheSize();
9769

70+
}
9871

9972
}
10073

src/BlattWeisskopf.cxx

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ BlattWeisskopf::BlattWeisskopf(DecayChannel* decayChannel) :
2929
//-------------------------
3030
std::complex<double> BlattWeisskopf::amplitude(DataPoint& d, const std::shared_ptr<const ParticleCombination>& pc, unsigned dataPartitionIndex) const
3131
{
32-
/// \todo check
3332
unsigned symIndex = symmetrizationIndex(pc);
3433
bool calc(false); // for debugging
3534

@@ -94,6 +93,7 @@ double BlattWeisskopf::F2(int twoL, double R2, double q2)
9493
case 4: // L = 2
9594
return 9. + 3.*z + z * z;
9695
default:
96+
/// \todo put in generic formula for L > 2
9797
LOG(ERROR) << "calculation of Blatt-Weisskopf barrier factor is not (yet) implemented for L = "
9898
<< spinToString(twoL) << ". returning 0." << std::endl;
9999
return 0;

src/DecayChannel.cxx

+3-3
Original file line numberDiff line numberDiff line change
@@ -96,16 +96,16 @@ std::complex<double> DecayChannel::amplitude(DataPoint& d, const std::shared_ptr
9696
{
9797
DEBUG("DecayChannel::amplitude - " << std::string(*this) << " " << std::string(*pc));
9898

99-
/// \todo check
10099
unsigned symIndex = symmetrizationIndex(pc);
101100

102101
if (FixedAmplitude_->calculationStatus(pc, symIndex, dataPartitionIndex) == kUncalculated) {
103102
std::complex<double> a = BlattWeisskopf_->amplitude(d, pc, dataPartitionIndex) * SpinAmplitude_->amplitude(d, pc, dataPartitionIndex);
104103

104+
/// \todo remove this check---no zeroes should be encountered, if all is consistent.
105105
if (a != Complex_0) {
106-
auto& pcDaughters = pc->daughters();
106+
// multiplies the amplitude by each Daughter's amplitude, for the appropriate daughter particle combination
107107
for (unsigned i = 0; i < Daughters_.size(); ++i) {
108-
a *= Daughters_[i]->amplitude(d, pcDaughters.at(i), dataPartitionIndex);
108+
a *= Daughters_[i]->amplitude(d, pc->daughters()[i], dataPartitionIndex);
109109
if (a == Complex_0)
110110
break;
111111
}

src/DecayingParticle.cxx

+3-1
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@ DecayingParticle::DecayingParticle(const QuantumNumbers& q, double mass, std::st
2626
//-------------------------
2727
std::complex<double> DecayingParticle::amplitude(DataPoint& d, const std::shared_ptr<const ParticleCombination>& pc, unsigned dataPartitionIndex) const
2828
{
29-
// \todo check
3029
unsigned symIndex = symmetrizationIndex(pc);
3130

3231
if (Amplitude_->calculationStatus(pc, symIndex, dataPartitionIndex) == kUncalculated) {
3332

3433
std::complex<double> a = Complex_0;
3534

35+
/// \todo Is this the best way to do it? (loop over pc's then channels. or channels then pc's?)
36+
37+
// sum up DecayChannel::amplitude over each channel
3638
for (auto& c : channels()) {
3739
if (c->hasSymmetrizationIndex(pc))
3840
a += c->amplitude(d, pc, dataPartitionIndex);

src/HelicitySpinAmplitude.cxx

+9-11
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,18 @@ std::complex<double> HelicitySpinAmplitude::amplitude(DataPoint& d, const std::s
3333

3434
// \todo angular normalization factor??? sqrt(2*L + 1)
3535

36-
const int J = InitialQuantumNumbers_.twoJ();
37-
// DFunction == 1 for J == 0
38-
// if (J != 0) {
39-
const int Lambda = pc->twoLambda();
36+
unsigned char twoJ = InitialQuantumNumbers_.twoJ();
4037

41-
const int lambda1 = pc->daughters()[0]->twoLambda();
42-
const int lambda2 = pc->daughters()[1]->twoLambda();
43-
const int lambda = lambda1 - lambda2;
38+
char twoM = pc->twoLambda();
4439

45-
const double phi = initialStateParticle()->helicityAngles().phi(d, pc);
46-
const double theta = initialStateParticle()->helicityAngles().theta(d, pc);
40+
char twoLambda1 = pc->daughters()[0]->twoLambda();
41+
char twoLambda2 = pc->daughters()[1]->twoLambda();
42+
char twoLambda = twoLambda1 - twoLambda2;
4743

48-
a *= DFunctionConj(J, Lambda, lambda, phi, theta, 0);
49-
// }
44+
double phi = initialStateParticle()->helicityAngles().phi(d, pc);
45+
double theta = initialStateParticle()->helicityAngles().theta(d, pc);
46+
47+
a *= std::conj(DFunction(twoJ, twoM, twoLambda, phi, theta, 0));
5048

5149
SpinAmplitude_->setValue(a, d, symIndex, dataPartitionIndex);
5250

src/InitialStateParticle.cxx

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ InitialStateParticle::~InitialStateParticle()
4040
std::complex<double> InitialStateParticle::amplitude(DataPoint& d, unsigned dataPartitionIndex) const
4141
{
4242
std::complex<double> a = Complex_0;
43+
// sum up DecayingParticle::amplitude over each particle combination
4344
for (auto& pc : particleCombinations())
4445
a += amplitude(d, pc, dataPartitionIndex);
4546
return a;

0 commit comments

Comments
 (0)