File indexing completed on 2025-01-18 09:54:36
0001
0002
0003 #include <sstream>
0004 #include <cmath>
0005 #include <gsl/gsl_sf_legendre.h>
0006 #include <complex>
0007 #include <cstdlib>
0008 #include <stdexcept>
0009 #include "CLHEP/GenericFunctions/ClebschGordanCoefficientSet.hh"
0010 namespace Genfun {
0011
0012 FUNCTION_OBJECT_IMP(SphericalHarmonicFit)
0013
0014 class SphericalHarmonicFit::Clockwork {
0015
0016 public:
0017
0018 Clockwork(unsigned int LMAX):LMAX(LMAX),coefficientsA(LMAX),coefficientsASq(2*LMAX) {}
0019
0020 struct MStruct {
0021 unsigned int M;
0022 Genfun::Parameter *fractionAbsMOrHigher;
0023 Genfun::Parameter *fractionMPositive;
0024 Genfun::Parameter *phaseMPlus;
0025 Genfun::Parameter *phaseMMinus;
0026 };
0027
0028 struct LStruct {
0029 unsigned int L;
0030 Genfun::Parameter *fractionLOrHigher;
0031 Genfun::Parameter *phaseLM0;
0032 std::vector<MStruct> mstruct;
0033 };
0034
0035 std::vector<LStruct> lstruct;
0036 const unsigned int LMAX;
0037
0038
0039 SphericalHarmonicCoefficientSet coefficientsA;
0040 SphericalHarmonicCoefficientSet coefficientsASq;
0041 ClebschGordanCoefficientSet ClebschGordan;
0042
0043 void recomputeCoefficients() {
0044
0045
0046
0047
0048
0049
0050 std::complex<double> I(0,1.0);
0051 double f=1.0;
0052 double fThisSum=0.0;
0053 for (unsigned int l=0;l<=LMAX;l++) {
0054
0055
0056
0057 const LStruct *lStructThis= (l==0 ? NULL: & lstruct[l-1]);
0058 const LStruct *lStructNext= (l==LMAX ? NULL: & lstruct[l]);
0059 double fHigher = lStructNext ? lStructNext->fractionLOrHigher->getValue() : NULL;
0060 double fThis = f*(1-fHigher);
0061 fThisSum+=fThis;
0062
0063 double g=1.0;
0064 double gThisSum=0.0;
0065 for (int m=0;m<=int(l);m++) {
0066
0067
0068
0069 const MStruct *mStructThis= ((m==0 || !lStructThis) ? NULL: & lStructThis->mstruct[m-1]);
0070 const MStruct *mStructNext= (m==int(l) ? NULL: & lStructThis->mstruct[m]);
0071 double gHigher = mStructNext ? mStructNext->fractionAbsMOrHigher->getValue() : NULL;
0072 double gThis = g*(1-gHigher);
0073 gThisSum+=gThis;
0074
0075 if (fThis<0) {
0076 std::cout << "L-fraction correction" << fThis << "-->0" << std::endl;
0077 fThis=0.0;
0078 }
0079 if (gThis<0) {
0080 std::cout << "M-fraction correction" << gThis << "-->0" << std::endl;
0081 gThis=0.0;
0082 }
0083 double px=0.0;
0084 if (m==0) {
0085 if (lStructThis) {
0086 double amplitude = sqrt(fThis*gThis);
0087 px = lStructThis->phaseLM0->getValue();;
0088 coefficientsA(l,m)=exp(I*px)*amplitude;
0089 }
0090
0091 else {
0092 double amplitude = sqrt(fThis*gThis);
0093 coefficientsA(l,m)=exp(I*px)*amplitude;
0094 }
0095 }
0096
0097 else {
0098 {
0099 double amplitude = sqrt(fThis*gThis*mStructThis->fractionMPositive->getValue());
0100 px = mStructThis->phaseMPlus->getValue();;
0101 coefficientsA(l,m)=exp(I*px)*amplitude;
0102 }
0103 {
0104 double amplitude = sqrt(fThis*gThis*(1-mStructThis->fractionMPositive->getValue()));
0105 px = mStructThis->phaseMMinus->getValue();;
0106 coefficientsA(l,-m)=exp(I*px)*amplitude;
0107 }
0108 }
0109 g*=gHigher;
0110 }
0111 f*=fHigher;
0112 }
0113 }
0114 };
0115
0116
0117 inline
0118 SphericalHarmonicFit::SphericalHarmonicFit(unsigned int LMAX):
0119 c(new Clockwork(LMAX))
0120 {
0121 for (unsigned int l=1;l<=LMAX;l++) {
0122 Clockwork::LStruct lstruct;
0123 lstruct.L=l;
0124 {
0125 std::ostringstream stream;
0126 stream << "Fraction L>=" << l;
0127 lstruct.fractionLOrHigher= new Genfun::Parameter(stream.str(), 0.5, 0, 1);
0128 }
0129 {
0130 std::ostringstream stream;
0131 stream << "Phase L=" << l << "; M=0";
0132 lstruct.phaseLM0= new Genfun::Parameter(stream.str(), M_PI, -2*M_PI, 2*M_PI);
0133 }
0134 for (unsigned int m=1;m<=l;m++) {
0135 Clockwork::MStruct mstruct;
0136 mstruct.M=m;
0137 {
0138 std::ostringstream stream;
0139 stream << "Fraction L= " << l << "; |M| >=" << m;
0140 mstruct.fractionAbsMOrHigher= new Genfun::Parameter(stream.str(), 0.5, 0, 1);
0141 }
0142 {
0143 std::ostringstream stream;
0144 stream << "Fraction L=" << l << "; M=+" << m ;
0145 mstruct.fractionMPositive= new Genfun::Parameter(stream.str(), 0.5, 0, 1);
0146 }
0147 {
0148 std::ostringstream stream;
0149 stream << "Phase L=" << l << "; M=+" << m ;
0150 mstruct.phaseMPlus= new Genfun::Parameter(stream.str(), M_PI, -2*M_PI, 2*M_PI);
0151 }
0152 {
0153 std::ostringstream stream;
0154 stream << "Phase L=" << l << "; M=-" << m ;
0155 mstruct.phaseMMinus= new Genfun::Parameter(stream.str(), M_PI, -2*M_PI, 2*M_PI);
0156 }
0157
0158 lstruct.mstruct.push_back(mstruct);
0159 }
0160 c->lstruct.push_back(lstruct);
0161 }
0162 }
0163
0164
0165 inline
0166 SphericalHarmonicFit::~SphericalHarmonicFit() {
0167 for (unsigned int i=0;i<c->lstruct.size();i++) {
0168 delete c->lstruct[i].fractionLOrHigher;
0169 delete c->lstruct[i].phaseLM0;
0170 for (unsigned int j=0;j<c->lstruct[i].mstruct.size();j++) {
0171 delete c->lstruct[i].mstruct[j].fractionAbsMOrHigher;
0172 delete c->lstruct[i].mstruct[j].fractionMPositive;
0173 delete c->lstruct[i].mstruct[j].phaseMPlus;
0174 delete c->lstruct[i].mstruct[j].phaseMMinus;
0175 }
0176 }
0177 delete c;
0178 }
0179
0180 inline
0181 SphericalHarmonicFit::SphericalHarmonicFit(const SphericalHarmonicFit & right):
0182 AbsFunction(),
0183 c(new Clockwork(right.c->LMAX))
0184 {
0185 for (unsigned int i=0;i<right.c->lstruct.size();i++) {
0186 Clockwork::LStruct lstruct;
0187 lstruct.L= right.c->lstruct[i].L;
0188 lstruct.fractionLOrHigher = new Parameter(*right.c->lstruct[i].fractionLOrHigher);
0189 lstruct.phaseLM0 = new Parameter(*right.c->lstruct[i].phaseLM0);
0190 for (unsigned int j=0;j<right.c->lstruct[i].mstruct.size();j++) {
0191 Clockwork::MStruct mstruct;
0192 mstruct.M=right.c->lstruct[i].mstruct[j].M;
0193 mstruct.fractionAbsMOrHigher=new Parameter(*right.c->lstruct[i].mstruct[j].fractionAbsMOrHigher);
0194 mstruct.fractionMPositive =new Parameter(*right.c->lstruct[i].mstruct[j].fractionMPositive);
0195 mstruct.phaseMPlus =new Parameter(*right.c->lstruct[i].mstruct[j].phaseMPlus);
0196 mstruct.phaseMMinus =new Parameter(*right.c->lstruct[i].mstruct[j].phaseMMinus);
0197 lstruct.mstruct.push_back(mstruct);
0198 }
0199 c->lstruct.push_back(lstruct);
0200 }
0201 }
0202
0203 inline
0204 double SphericalHarmonicFit::operator() (double ) const {
0205 throw std::runtime_error("Dimensionality error in SphericalHarmonicFit");
0206 return 0;
0207 }
0208
0209 inline
0210 double SphericalHarmonicFit::operator() (const Argument & a ) const {
0211 unsigned int LMAX=c->LMAX;
0212 double x = a[0];
0213 double phi=a[1];
0214
0215
0216
0217
0218
0219 std::vector< std::vector<double> > Plm(LMAX+1);
0220 for (int m=0;m<=int(LMAX);m++) {
0221 Plm[m].resize(LMAX+1);
0222 gsl_sf_legendre_sphPlm_array (LMAX, m, x, &*Plm[m].begin());
0223 }
0224
0225 c->recomputeCoefficients();
0226 std::complex<double> P=0.0;
0227 std::complex<double> I(0,1.0);
0228 for (unsigned int l=0;l<=LMAX;l++) {
0229 for (int m=0;m<=int(l);m++) {
0230 {
0231 int LP=l-abs(m);
0232 double Pn= Plm[abs(m)][LP];
0233
0234 if (!finite(Pn)) return 0.0;
0235
0236
0237 P+=(c->coefficientsA(l,m)*Pn*exp(I*(m*phi)));
0238
0239 if (m!=0) P+= ( (m%2 ?-1.0:1.0)*c->coefficientsA(l,-m)*Pn*exp(-I*(m*phi)));
0240 }
0241 }
0242 }
0243
0244 double retVal=std::norm(P);
0245 if (!finite(retVal)) {
0246 return 0.0;
0247 }
0248 return retVal;
0249 }
0250
0251 inline
0252 unsigned int SphericalHarmonicFit::lMax() const {
0253 return c->LMAX;
0254 }
0255
0256 inline
0257 unsigned int SphericalHarmonicFit::numComponents() const {
0258 return (c->LMAX+1)*(c->LMAX+1)-1;
0259 }
0260
0261
0262 inline
0263 Parameter *SphericalHarmonicFit::getFractionLOrHigher(unsigned int L){
0264 return c->lstruct[L-1].fractionLOrHigher;
0265 }
0266
0267 inline
0268 const Parameter *SphericalHarmonicFit::getFractionLOrHigher(unsigned int L) const {
0269 return c->lstruct[L-1].fractionLOrHigher;
0270 }
0271
0272
0273 inline
0274 Parameter *SphericalHarmonicFit::getPhaseLM0(unsigned int L){
0275 return c->lstruct[L-1].phaseLM0;
0276 }
0277
0278 inline
0279 const Parameter *SphericalHarmonicFit::getPhaseLM0(unsigned int L) const{
0280 return c->lstruct[L-1].phaseLM0;
0281 }
0282
0283
0284 inline
0285 Parameter *SphericalHarmonicFit::getFractionAbsMOrHigher(unsigned int L, unsigned int M){
0286 return c->lstruct[L-1].mstruct[M-1].fractionAbsMOrHigher;
0287 }
0288
0289 inline
0290 const Parameter *SphericalHarmonicFit::getFractionAbsMOrHigher(unsigned int L, unsigned int M) const{
0291 return c->lstruct[L-1].mstruct[M-1].fractionAbsMOrHigher;
0292 }
0293
0294
0295
0296 inline
0297 Parameter *SphericalHarmonicFit::getFractionMPositive(unsigned int L, unsigned int M){
0298 return c->lstruct[L-1].mstruct[M-1].fractionMPositive;
0299 }
0300
0301 inline
0302 const Parameter *SphericalHarmonicFit::getFractionMPositive(unsigned int L, unsigned int M) const{
0303 return c->lstruct[L-1].mstruct[M-1].fractionMPositive;
0304 }
0305
0306
0307
0308 inline
0309 Parameter *SphericalHarmonicFit::getPhaseMPlus(unsigned int L, unsigned int M){
0310 return c->lstruct[L-1].mstruct[M-1].phaseMPlus;
0311 }
0312
0313 inline
0314 const Parameter *SphericalHarmonicFit::getPhaseMPlus(unsigned int L, unsigned int M) const{
0315 return c->lstruct[L-1].mstruct[M-1].phaseMPlus;
0316 }
0317
0318
0319
0320 inline
0321 Parameter *SphericalHarmonicFit::getPhaseMMinus(unsigned int L, unsigned int M){
0322 return c->lstruct[L-1].mstruct[M-1].phaseMMinus;
0323 }
0324
0325 inline
0326 const Parameter *SphericalHarmonicFit::getPhaseMMinus(unsigned int L, unsigned int M) const{
0327 return c->lstruct[L-1].mstruct[M-1].phaseMMinus;
0328 }
0329
0330 inline
0331 const SphericalHarmonicCoefficientSet & SphericalHarmonicFit::coefficientsA() const {
0332 c->recomputeCoefficients();
0333 return c->coefficientsA;
0334 }
0335
0336 inline
0337 const SphericalHarmonicCoefficientSet & SphericalHarmonicFit::coefficientsASq() const{
0338 c->recomputeCoefficients();
0339 unsigned int LMAX=c->coefficientsA.getLMax();
0340 for (unsigned int L=0;L<=2*LMAX;L++) {
0341 for (int M=-L; M<=int(L); M++) {
0342 c->coefficientsASq(L,M)=0.0;
0343 for (unsigned int l1=0;l1<=LMAX;l1++) {
0344 for (unsigned int l2=0;l2<=LMAX;l2++) {
0345 for (int m1=-l1;m1<=int(l1);m1++) {
0346 for (int m2=-l2;m2<=int(l2);m2++) {
0347 if (m1-m2==M) {
0348 if (((l1+l2) >= L) && abs(l1-l2) <=int(L)) {
0349 c->coefficientsASq(L,M) += (c->coefficientsA(l1,m1)*
0350 conj(c->coefficientsA(l2,m2))*
0351 (m2%2 ? -1.0:1.0) *
0352 sqrt((2*l1+1)*(2*l2+1)/(4*M_PI*(2*L+1)))*
0353 c->ClebschGordan(l1,l2,0,0,L,0)*c->ClebschGordan(l1,l2,m1,-m2,L,M));
0354 }
0355 }
0356 }
0357 }
0358 }
0359 }
0360 }
0361 }
0362 return c->coefficientsASq;
0363 }
0364
0365 inline
0366 void SphericalHarmonicFit::recomputeCoefficients() const {
0367 c->recomputeCoefficients();
0368 }
0369
0370 }