/////////////////////////////////////////////////////////////////////
//
//
//                                  Author:  I. Froehlich
/////////////////////////////////////////////////////////////////////


using namespace std;
#include <sstream>
#include <iostream>
#include <iomanip>

#include "PHadronDecayM2.h"


PHadronDecayM2::PHadronDecayM2()  {
};

PHadronDecayM2::PHadronDecayM2(const Char_t *id, const  Char_t *de, Int_t key) :
    PHadronDecayM1(id, de, key) {
    if (is_channel < 0)
	Warning("PHadronDecayM2", "The model (%s) should be bound to CHANNELS only", de);   
};

PDistribution *PHadronDecayM2::Clone(const char *) const {
    return new PHadronDecayM2((const PHadronDecayM2 &)* this);
};

Bool_t PHadronDecayM2::Init(void) {
    return PHadronDecayM1::Init();
};

int PHadronDecayM2::GetDepth(int i) {    
    //Initialize daughter decay modes
    return PHadronDecayM1::GetDepth(i);
};

Bool_t PHadronDecayM2::Prepare(void) {
    //Things which might change during the eventloop
    return PHadronDecayM1::Prepare();
};

void PHadronDecayM2::SubPrint(Int_t) const {
    //Print sub-models    
    if (model1) {
	cout << " ";
	cout << model1->GetDescription();
    }
    if (model2) {
	cout << " ";
	cout << model2->GetDescription();
    }
};

Bool_t PHadronDecayM2::SampleMass(void) {
    //Mass-sampling wrapper
    Double_t mass[3];
    mass[0] = parent->M();
   
    if (!SampleMass(mass)) return kFALSE;

    daughter1->SetM(mass[1]);
    daughter2->SetM(mass[2]);

    return kTRUE;
};

Bool_t PHadronDecayM2::SampleMass(Double_t *mass, Int_t *) {
    //samples the mass of the unstable decay products
    //Input: mass[0] (parent)
    //Output: mass[1] and mass[2] 
    //Order of particles in the array must be the same as defined in data base

    //BUGBUG: Why is didx not used here?
 
    Double_t ecm = mass[0];    
    if (sampleM2(ecm)) {
	mass[1] = dynamic_mass1;
	mass[2] = dynamic_mass2;	
	//Warning("SampleMass","done in [%s], ecm=%f",GetIdentifier(),ecm);
    } else {
	Warning("SampleMass", "failed in [%s], ecm=%f", GetIdentifier(), ecm);
	return kFALSE;
    }
    if (ecm < (dynamic_mass1+dynamic_mass2)) {
	Warning("SampleMass", "Violation of energy");
	return kFALSE;
    }

    return kTRUE;
};

Bool_t PHadronDecayM2::GetWidth(Double_t mass, Double_t *width, Int_t) {

    if (makeStaticData()->GetPWidx(is_channel) == -1) 
	return 0.; // Disabled --> BUGBUG why not static?

    if (!makeStaticData()->GetPWidx(is_channel)) { // Enter below only on the first call

	Info("GetWidth", "Called for %s", makeStaticData()->GetDecayName(is_channel));

	makeDynamicData()->GetParticleDepth(parent_id); // if 1st call will initialize flags

	mmin = makeStaticData()->GetDecayEmin(is_channel);  // mass threshold for the decay
	Double_t w0 = makeStaticData()->GetDecayBR(is_channel);      // starting weight
	
	mmax = PData::UMass(parent_id);                // mass ceiling
	Double_t dm = (mmax-mmin)/(maxmesh-3.);          // mass increment
	double mass_threshold1, mass_ceiling1;
	double mass_threshold2, mass_ceiling2;
	
	mass_threshold1 = PData::LMass(id1);
	mass_ceiling1   = mmax-PData::LMass(id2);
	mass_threshold2 = PData::LMass(id2);
	mass_ceiling2   = mmax-PData::LMass(id1);
    
	mesh = new PMesh(maxmesh-2, "mesh");
	for (int i=0; i<maxmesh-2; ++i) {
	    Double_t mm = mmin+i*dm;                     // current invariant mass

	    Double_t temp0      = 0.;
	    Double_t temp0_norm = 0.;

	    //First find out the maximum of the unstable weight,
	    //since very small weights folded with very high phase space
	    //correction seem to diverge
	    //Anyhow, these stuff will not contribute so much to the integral
	    Double_t bw_max = 0;
	    for (int mc1=0; mc1<mc_max; mc1++) {
		for (int mc2=0; mc2<mc_max; mc2++) {
		    Double_t running_unstable_mass1 = mass_threshold1+((Double_t(mc1)/Double_t(mc_max))
								       *(mass_ceiling1-mass_threshold1));
		    Double_t running_unstable_mass2 = mass_threshold2+((Double_t(mc2)/Double_t(mc_max))
								       *(mass_ceiling2-mass_threshold2));
		    Double_t w = makeDynamicData()->GetParticleTotalWeight(running_unstable_mass1 ,id1);
		    w *= makeDynamicData()->GetParticleTotalWeight(running_unstable_mass2 ,id2);
		    if (w > bw_max) 
			bw_max = w;
		}
	    }

	    //Continue with the integration, when a pole mass has been found
	    if (bw_max > 0) 
		for (int mc1=0; mc1<mc_max; mc1++) {
		    for (int mc2=0; mc2<mc_max; mc2++) {
			Double_t temp1 = 0.;

			//We integrate always over the same binning structure,
			//this avoids artefacts (IF, 6.6.2007)

			Double_t running_unstable_mass1 = mass_threshold1+((Double_t(mc1)/Double_t(mc_max))
									   *(mass_ceiling1-mass_threshold1));
			Double_t running_unstable_mass2 = mass_threshold2+((Double_t(mc2)/Double_t(mc_max))
									   *(mass_ceiling2-mass_threshold2));
			if (mm > (running_unstable_mass1+running_unstable_mass2)) {
			    //Fold with pcms (phase space factor for BW) 
			    temp1 = PKinematics::pcms(mm, running_unstable_mass1, running_unstable_mass2);
			    //Fold with mass shape all unstable particles
			    Double_t w = makeDynamicData()->GetParticleTotalWeight(running_unstable_mass1, id1);
			    w *= makeDynamicData()->GetParticleTotalWeight(running_unstable_mass2, id2);			    
			    temp1 *= w;
			    if (w > (0.01*bw_max)) {  
				//Cut-off condition with avoids arteficialy destructed behaviour
				temp0_norm += temp1;
				//Get the Gamma_m_m1_m2			    
				temp1 *= HadronWidth(mm, running_unstable_mass1, running_unstable_mass2);
				temp0 += temp1;
			    }
			}
		    }
		}
	    if (temp0_norm > 0) //Normalization
		temp0 /= temp0_norm;
	    temp0 *= w0;
	    mesh->SetNode(i, temp0); 
	}

	mesh->SetMin(mmin);                 // store mass threshold
	mesh->SetMax(mmax);                 // store mass ceiling
	makeStaticData()->SetPWidx(is_channel, 1);  //Enable channel
    } //END first call

    if (mesh)  {
	*width = mesh->GetLinearIP(mass);
	return kTRUE;
    }
    return kFALSE;
}

Double_t PHadronDecayM2::GetWeight(Double_t *mass, Int_t *didx) {
    //Get the weight of the decay mass[0]->mass[1]+mass[2]
    //Input: mass[0] (parent)
    //mass[1] and mass[2] 
    //Order of particles must be the same as defined in data base

    //If set, use parameters
    int didx_local1 = didx1,
	didx_local2 = didx2;
    if (didx) {
	didx_local1 = didx[1];
	didx_local2 = didx[2];
    }

    return BWWeight(id1, mass[0], mass[1], mass[2], didx_local1, id2, didx_local2); 
}


bool PHadronDecayM2::sampleM2(const double &ecm) {
    
    // Mass sampling algorithm in case of hadronic decay to two unstable hadrons

    dynamic_mass1=0.; 
    dynamic_mass2=0.;                      // reset masses
    double m0[2] = {makeStaticData()->GetParticleMass(id1),
		    makeStaticData()->GetParticleMass(id2)}; // mass poles
    double ml[2] = {PData::LMass(id1), PData::LMass(id2)};// mass thresholds
    double mh[2] = {ecm-ml[1], ecm-ml[0]};    // maximum available masses
    double f, y, m1, m2, mx[2] = {TMath::Min(m0[0],mh[0]),TMath::Min(m0[1],mh[1])};
    double maxW1, maxW2;
    
    //for(int iter=0;iter<5;iter++) {   // find 2-dim maximum of Weight() function 
    maxW1 = maxBWWeight(id1, ecm, ml[0], mh[0], mx[0], mx[1], didx1, id2, didx2);
    maxW2 = maxBWWeight(id2, ecm, ml[1], mh[1], mx[1], mx[0], didx2, id1, didx1);
    //}
    
    int counter = 0;

    abort = kFALSE;
    
 repeat:                           // re-enter if parameter change is forced
 
    f = scale*TMath::Max(maxW1,maxW2);
    if (f == 0.) {
	return kFALSE;
    }

    // The rejection method is used to sample the masses m1 and m2.
    // (see e.g. Ref 6). This is by far the most efficient method in this case.
    // Using TF2 and GetRandom of ROOT is several orders of magnitude slower!
    
    do {                              // enter the rejection-method loop
	m1 = ml[0] + PUtils::sampleFlat()*(mh[0]-ml[0]);
	m2 = ml[1] + PUtils::sampleFlat()*(mh[1]-ml[1]);
	y = BWWeight(id1, ecm, m1, m2, didx1, id2, didx2); // y(m1,m2) is the distribution function
	counter++;
    } while ((PUtils::sampleFlat()>y/f) && counter<10000);
    
    if (f < y) {   // Error: the test function fails to bound the distribution fn;
	scale = scale*y/f + 0.1;
//  printf("%s %f %i\n",Message[14],scale,counter);
	if (counter < 10000) goto repeat; // ...and try again
    }
    dynamic_mass1 = m1;
    dynamic_mass2 = m2;
    
    return kTRUE;
}

ClassImp(PHadronDecayM2)
 PHadronDecayM2.cc:1
 PHadronDecayM2.cc:2
 PHadronDecayM2.cc:3
 PHadronDecayM2.cc:4
 PHadronDecayM2.cc:5
 PHadronDecayM2.cc:6
 PHadronDecayM2.cc:7
 PHadronDecayM2.cc:8
 PHadronDecayM2.cc:9
 PHadronDecayM2.cc:10
 PHadronDecayM2.cc:11
 PHadronDecayM2.cc:12
 PHadronDecayM2.cc:13
 PHadronDecayM2.cc:14
 PHadronDecayM2.cc:15
 PHadronDecayM2.cc:16
 PHadronDecayM2.cc:17
 PHadronDecayM2.cc:18
 PHadronDecayM2.cc:19
 PHadronDecayM2.cc:20
 PHadronDecayM2.cc:21
 PHadronDecayM2.cc:22
 PHadronDecayM2.cc:23
 PHadronDecayM2.cc:24
 PHadronDecayM2.cc:25
 PHadronDecayM2.cc:26
 PHadronDecayM2.cc:27
 PHadronDecayM2.cc:28
 PHadronDecayM2.cc:29
 PHadronDecayM2.cc:30
 PHadronDecayM2.cc:31
 PHadronDecayM2.cc:32
 PHadronDecayM2.cc:33
 PHadronDecayM2.cc:34
 PHadronDecayM2.cc:35
 PHadronDecayM2.cc:36
 PHadronDecayM2.cc:37
 PHadronDecayM2.cc:38
 PHadronDecayM2.cc:39
 PHadronDecayM2.cc:40
 PHadronDecayM2.cc:41
 PHadronDecayM2.cc:42
 PHadronDecayM2.cc:43
 PHadronDecayM2.cc:44
 PHadronDecayM2.cc:45
 PHadronDecayM2.cc:46
 PHadronDecayM2.cc:47
 PHadronDecayM2.cc:48
 PHadronDecayM2.cc:49
 PHadronDecayM2.cc:50
 PHadronDecayM2.cc:51
 PHadronDecayM2.cc:52
 PHadronDecayM2.cc:53
 PHadronDecayM2.cc:54
 PHadronDecayM2.cc:55
 PHadronDecayM2.cc:56
 PHadronDecayM2.cc:57
 PHadronDecayM2.cc:58
 PHadronDecayM2.cc:59
 PHadronDecayM2.cc:60
 PHadronDecayM2.cc:61
 PHadronDecayM2.cc:62
 PHadronDecayM2.cc:63
 PHadronDecayM2.cc:64
 PHadronDecayM2.cc:65
 PHadronDecayM2.cc:66
 PHadronDecayM2.cc:67
 PHadronDecayM2.cc:68
 PHadronDecayM2.cc:69
 PHadronDecayM2.cc:70
 PHadronDecayM2.cc:71
 PHadronDecayM2.cc:72
 PHadronDecayM2.cc:73
 PHadronDecayM2.cc:74
 PHadronDecayM2.cc:75
 PHadronDecayM2.cc:76
 PHadronDecayM2.cc:77
 PHadronDecayM2.cc:78
 PHadronDecayM2.cc:79
 PHadronDecayM2.cc:80
 PHadronDecayM2.cc:81
 PHadronDecayM2.cc:82
 PHadronDecayM2.cc:83
 PHadronDecayM2.cc:84
 PHadronDecayM2.cc:85
 PHadronDecayM2.cc:86
 PHadronDecayM2.cc:87
 PHadronDecayM2.cc:88
 PHadronDecayM2.cc:89
 PHadronDecayM2.cc:90
 PHadronDecayM2.cc:91
 PHadronDecayM2.cc:92
 PHadronDecayM2.cc:93
 PHadronDecayM2.cc:94
 PHadronDecayM2.cc:95
 PHadronDecayM2.cc:96
 PHadronDecayM2.cc:97
 PHadronDecayM2.cc:98
 PHadronDecayM2.cc:99
 PHadronDecayM2.cc:100
 PHadronDecayM2.cc:101
 PHadronDecayM2.cc:102
 PHadronDecayM2.cc:103
 PHadronDecayM2.cc:104
 PHadronDecayM2.cc:105
 PHadronDecayM2.cc:106
 PHadronDecayM2.cc:107
 PHadronDecayM2.cc:108
 PHadronDecayM2.cc:109
 PHadronDecayM2.cc:110
 PHadronDecayM2.cc:111
 PHadronDecayM2.cc:112
 PHadronDecayM2.cc:113
 PHadronDecayM2.cc:114
 PHadronDecayM2.cc:115
 PHadronDecayM2.cc:116
 PHadronDecayM2.cc:117
 PHadronDecayM2.cc:118
 PHadronDecayM2.cc:119
 PHadronDecayM2.cc:120
 PHadronDecayM2.cc:121
 PHadronDecayM2.cc:122
 PHadronDecayM2.cc:123
 PHadronDecayM2.cc:124
 PHadronDecayM2.cc:125
 PHadronDecayM2.cc:126
 PHadronDecayM2.cc:127
 PHadronDecayM2.cc:128
 PHadronDecayM2.cc:129
 PHadronDecayM2.cc:130
 PHadronDecayM2.cc:131
 PHadronDecayM2.cc:132
 PHadronDecayM2.cc:133
 PHadronDecayM2.cc:134
 PHadronDecayM2.cc:135
 PHadronDecayM2.cc:136
 PHadronDecayM2.cc:137
 PHadronDecayM2.cc:138
 PHadronDecayM2.cc:139
 PHadronDecayM2.cc:140
 PHadronDecayM2.cc:141
 PHadronDecayM2.cc:142
 PHadronDecayM2.cc:143
 PHadronDecayM2.cc:144
 PHadronDecayM2.cc:145
 PHadronDecayM2.cc:146
 PHadronDecayM2.cc:147
 PHadronDecayM2.cc:148
 PHadronDecayM2.cc:149
 PHadronDecayM2.cc:150
 PHadronDecayM2.cc:151
 PHadronDecayM2.cc:152
 PHadronDecayM2.cc:153
 PHadronDecayM2.cc:154
 PHadronDecayM2.cc:155
 PHadronDecayM2.cc:156
 PHadronDecayM2.cc:157
 PHadronDecayM2.cc:158
 PHadronDecayM2.cc:159
 PHadronDecayM2.cc:160
 PHadronDecayM2.cc:161
 PHadronDecayM2.cc:162
 PHadronDecayM2.cc:163
 PHadronDecayM2.cc:164
 PHadronDecayM2.cc:165
 PHadronDecayM2.cc:166
 PHadronDecayM2.cc:167
 PHadronDecayM2.cc:168
 PHadronDecayM2.cc:169
 PHadronDecayM2.cc:170
 PHadronDecayM2.cc:171
 PHadronDecayM2.cc:172
 PHadronDecayM2.cc:173
 PHadronDecayM2.cc:174
 PHadronDecayM2.cc:175
 PHadronDecayM2.cc:176
 PHadronDecayM2.cc:177
 PHadronDecayM2.cc:178
 PHadronDecayM2.cc:179
 PHadronDecayM2.cc:180
 PHadronDecayM2.cc:181
 PHadronDecayM2.cc:182
 PHadronDecayM2.cc:183
 PHadronDecayM2.cc:184
 PHadronDecayM2.cc:185
 PHadronDecayM2.cc:186
 PHadronDecayM2.cc:187
 PHadronDecayM2.cc:188
 PHadronDecayM2.cc:189
 PHadronDecayM2.cc:190
 PHadronDecayM2.cc:191
 PHadronDecayM2.cc:192
 PHadronDecayM2.cc:193
 PHadronDecayM2.cc:194
 PHadronDecayM2.cc:195
 PHadronDecayM2.cc:196
 PHadronDecayM2.cc:197
 PHadronDecayM2.cc:198
 PHadronDecayM2.cc:199
 PHadronDecayM2.cc:200
 PHadronDecayM2.cc:201
 PHadronDecayM2.cc:202
 PHadronDecayM2.cc:203
 PHadronDecayM2.cc:204
 PHadronDecayM2.cc:205
 PHadronDecayM2.cc:206
 PHadronDecayM2.cc:207
 PHadronDecayM2.cc:208
 PHadronDecayM2.cc:209
 PHadronDecayM2.cc:210
 PHadronDecayM2.cc:211
 PHadronDecayM2.cc:212
 PHadronDecayM2.cc:213
 PHadronDecayM2.cc:214
 PHadronDecayM2.cc:215
 PHadronDecayM2.cc:216
 PHadronDecayM2.cc:217
 PHadronDecayM2.cc:218
 PHadronDecayM2.cc:219
 PHadronDecayM2.cc:220
 PHadronDecayM2.cc:221
 PHadronDecayM2.cc:222
 PHadronDecayM2.cc:223
 PHadronDecayM2.cc:224
 PHadronDecayM2.cc:225
 PHadronDecayM2.cc:226
 PHadronDecayM2.cc:227
 PHadronDecayM2.cc:228
 PHadronDecayM2.cc:229
 PHadronDecayM2.cc:230
 PHadronDecayM2.cc:231
 PHadronDecayM2.cc:232
 PHadronDecayM2.cc:233
 PHadronDecayM2.cc:234
 PHadronDecayM2.cc:235
 PHadronDecayM2.cc:236
 PHadronDecayM2.cc:237
 PHadronDecayM2.cc:238
 PHadronDecayM2.cc:239
 PHadronDecayM2.cc:240
 PHadronDecayM2.cc:241
 PHadronDecayM2.cc:242
 PHadronDecayM2.cc:243
 PHadronDecayM2.cc:244
 PHadronDecayM2.cc:245
 PHadronDecayM2.cc:246
 PHadronDecayM2.cc:247
 PHadronDecayM2.cc:248
 PHadronDecayM2.cc:249
 PHadronDecayM2.cc:250
 PHadronDecayM2.cc:251
 PHadronDecayM2.cc:252
 PHadronDecayM2.cc:253
 PHadronDecayM2.cc:254
 PHadronDecayM2.cc:255
 PHadronDecayM2.cc:256
 PHadronDecayM2.cc:257
 PHadronDecayM2.cc:258
 PHadronDecayM2.cc:259