/////////////////////////////////////////////////////////////////////
//
// Class for calculating the total mass-dependent width
// from first principles
//
//                                  Author:  I. Froehlich
/////////////////////////////////////////////////////////////////////


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

#include "PHadronModel.h"


ClassImp(PHadronModel)

PHadronModel::PHadronModel()  {
};

PHadronModel::PHadronModel(const Char_t *id, const Char_t *de, Int_t key) :
    PChannelModel(id, de, key) {

    if (is_pid < 0)
	Warning("PHadronModel", "The model (%s) should be bound to PARTICLES only", de);

    global_weight_scaling = 1.;
};

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

Bool_t PHadronModel::GetWidth(Double_t mass, Double_t *width, Int_t didx) {
    //Calculates the mass-dependent width (either partial for the decy or
    //total for the particles)
    //
    //If didx is set, return the partial width of the decay channel didx
    //This can be used for mass sampling in PChannel
    //(else set didx to -1)
    //
    //Returns the mass-dependent width for a hadronic resonance id of mass m.
    //It is based on first principles and is valid for arbitrary resonances
    //given the pole mass, vacuum width, and decay modes (units GeV/c**2).
    //
 
    if (didx >= 0) {
	//Do not calculate the width from first principles
	//but use the partial width only
	*width = makeDynamicData()->GetDecayPartialWidth(mass, didx);
	return kTRUE;
    }

    int twidx = makeStaticData()->GetTWidx(is_pid);
    double g0 =	makeStaticData()->GetParticleTotalWidth(is_pid); // vacuum width

    if (!width_init) // if 1st call, initialize flags
	makeDynamicData()->GetParticleDepth(is_pid);   

    if (twidx==-1 || g0 < (*unstable_width) || mass==0. || 
	makeStaticData()->GetParticleNChannels(is_pid)==0) { 
	*width = g0; // no mass-dependent width
	return kTRUE;
    }

    double dm;            // mass range
    int j, didx2;
    double mm, g_tmp;

    Bool_t self_consistency_loop      = kTRUE;
    Bool_t next_self_consistency_loop = kFALSE;

    if (!width_init) {   
	// Below: enter once on the first call
	width_init++;
	
	global_weight_scaling = makeDynamicData()->GetParticleScalingFactor(is_pid);

	mmin = PData::LMass(is_pid);   // mass threshold
	mmax = PData::UMass(is_pid);   // mass ceiling
	dm   = (mmax-mmin)/(maxmesh-3.); // mass increment for the mesh
 
	Info("GetWidth", "Width 1st call for %s, mass range %f GeV to %f GeV",
	     description, mmin, mmax);

	while (self_consistency_loop) {
	    // The mass-dependent width is evaluated on a mesh as a function of mass.
	    
	    // now loop over decay modes
	    Int_t listkey = -1;
	    Int_t tid[11];
	    while (makeDataBase()->MakeListIterator(primary_key, "pnmodes", "link", &listkey)) {
		tid[0] = 10; 
		makeStaticData()->GetDecayModeByKey(listkey, tid); 
		// retrieve current mode info
		didx2 = makeStaticData()->GetDecayIdxByKey(listkey);
		//np=tid[0];
		if (makeStaticData()->GetPWidx(didx2) != -1 ) {  
		    // Note: The next call is required 
		    // if the current particle has nested decays via 
		    // any recognized modes.
		    // The innermost widths must be available by the time 
		    // the local Width sampling 
		    // is called and their calculation is forced here.
		    makeDynamicData()->GetDecayPartialWidth(mass, didx2);
		}
	    } //end iterator
	    // _____________________________________________________________________
	    // Store the total width: Unitarity is assumed for normalization, i.e. the
	    // available decay modes are taken to exhaust the total transition strength.
	    // This means:  Sum(all branching ratios)=1

	    if (mesh) delete mesh;

	    mesh = new PMesh(maxmesh-2, "mesh");
	    for (j=0; j<maxmesh-2; ++j) {  // loop over the mesh points [0-200]
		g_tmp = 0.;                // reset the sum of mass-dependent partial widths
		mm = mmin+j*dm;            // update mass on the mesh
		while (makeDataBase()->MakeListIterator(primary_key, "pnmodes", "link", &listkey)) {
		    didx2  = makeStaticData()->GetDecayIdxByKey(listkey);
		    g_tmp += makeDynamicData()->GetDecayPartialWidth(mm,didx2);
		}
		mesh->SetNode(j, g_tmp);
	    }
	    mesh->SetMin(mmin); // store mass threshold
	    mesh->SetMax(mmax); // store mass ceiling

	    // End of first call: the mass-dependent width is stored for future use


	    //******** Scaling
	    //By the way... Normalize Int(weight) to =1
	    Double_t global_weight = 0;
	    for (j=0; j<maxmesh-2; ++j) {  // loop over the mesh points [0-200]
		mm = mmin+j*dm;            // update mass on the mesh
		global_weight += dm*makeDynamicData()->GetParticleTotalWeight(mm, is_pid);		
	    }
	    
	    if (global_weight)
		makeDynamicData()->SetParticleScalingFactor(is_pid, 1/(global_weight));
	    global_weight_scaling = makeDynamicData()->GetParticleScalingFactor(is_pid);

	    //*********Self-consistency
	    //It is important that width_init is already defined, otherwise we go in endless loop here
	    listkey = -1;
	    self_consistency_loop = kFALSE;
	    while (makeDataBase()->MakeListIterator(primary_key, "pnmodes", "link", &listkey)) {
		//Loop again over decay modes
		didx2 = makeStaticData()->GetDecayIdxByKey(listkey);
		Double_t partial_weight = 0.; // reset the sum of mass-dependent branching ratio
		global_weight = 0.; 

		int brflag = makeStaticData()->GetDecayBRFlag(didx2);
		if (brflag) { //Do integration 
		    for (j=0; j<maxmesh-2; ++j) {  // loop over the mesh points [0-200]
			mm = mmin+j*dm;            // update mass on the mesh
			
			if (makeDynamicData()->GetParticleTotalWidth(mm,is_pid) > 0)

			    partial_weight += dm*(makeDynamicData()->GetDecayPartialWidth(mm,didx2)*
						  makeDynamicData()->GetParticleTotalWeight(mm,is_pid)*
						  makeStaticData()->GetParticleTotalWidth(is_pid)/
						  makeDynamicData()->GetParticleTotalWidth(mm,is_pid));
			//Obtain the partial fold
			//PWidth/TWidth is the mass-dependent BR
			//*TWeight will be the Partial mass shape
			//Int(Partial mass shape)/Int(Total mass shape) must be the static BR
			
			global_weight += dm*makeDynamicData()->GetParticleTotalWeight(mm,is_pid);
			
			
		    }
		} else { //pole width
		    mm = makeStaticData()->GetParticleMass(is_pid);
		    partial_weight = (makeDynamicData()->GetDecayPartialWidth(mm,didx2)*
				      makeDynamicData()->GetParticleTotalWeight(mm,is_pid)*
				      makeStaticData()->GetParticleTotalWidth(is_pid)/
				      makeDynamicData()->GetParticleTotalWidth(mm,is_pid));
		    global_weight = makeDynamicData()->GetParticleTotalWeight(mm,is_pid);
		}
		
		//Global weight should be 1 after Scaling

		Double_t calculated_br = 0;
		Double_t tot_sc        = 1.;
		//take into account scfactor at mass pole
		tot_sc = makeDynamicData()->GetParticleTotalWidth(makeStaticData()->GetParticleMass(is_pid),is_pid)/
		    makeStaticData()->GetParticleTotalWidth(is_pid);

		if (global_weight) //Compare the calculated partial width to the static one
		    calculated_br = tot_sc*partial_weight/global_weight;
								      
		if ((calculated_br/makeStaticData()->GetDecayPartialWidth(didx2) > 1.001)
		    || (calculated_br/makeStaticData()->GetDecayPartialWidth(didx2) < 0.999)) { 
		    //set SC factor and go on...
		    if (!makeDynamicData()->CheckSCAbort(didx2)) { //check for endless loop
			Warning("GetWidth", "Self consistency calculation failed for decay: %s (%i)",
				makeStaticData()->GetDecayName(didx2), didx2);
			Warning("GetWidth", "Calculated Width: %f, Static Width: %f", 
				calculated_br, 
				makeStaticData()->GetDecayPartialWidth(didx2));
			next_self_consistency_loop = kTRUE; //break the complete loop			
		    } else {
			if (calculated_br > 0) {
			    self_consistency_loop = kTRUE;
			    makeDynamicData()->SetDecaySCFactor(didx2, 
								makeStaticData()->GetDecayPartialWidth(didx2)/
								calculated_br);
			}
		    }
		}
	    } //END modes iterator
	    if (next_self_consistency_loop) 
		self_consistency_loop = kFALSE; 
	}  //END	while (self_consistency_loop) {
    } //width init

    *width = mesh->GetLinearIP(mass);

    return kTRUE;
}

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