00001 #include "SimG4Core/GFlash/interface/GflashHadronShowerProfile.h"
00002 #include "SimG4Core/GFlash/interface/GflashEnergySpot.h"
00003 #include "SimG4Core/GFlash/interface/GflashHistogram.h"
00004
00005 #include "FWCore/ServiceRegistry/interface/Service.h"
00006 #include "FWCore/Utilities/interface/RandomNumberGenerator.h"
00007
00008 #include "CLHEP/GenericFunctions/IncompleteGamma.hh"
00009 #include "CLHEP/GenericFunctions/LogGamma.hh"
00010 #include "Randomize.hh"
00011
00012
00013 #include "SimG4Core/GFlash/interface/GflashTrajectoryPoint.h"
00014
00015 #include <math.h>
00016
00017 GflashHadronShowerProfile::GflashHadronShowerProfile(G4Region* envelope)
00018 {
00019 showerType = 0;
00020 jCalorimeter = Gflash::kNULL;
00021 theHelix = new GflashTrajectory;
00022 theHisto = GflashHistogram::instance();
00023
00024 edm::Service<edm::RandomNumberGenerator> rng;
00025 if ( ! rng.isAvailable()) {
00026 throw cms::Exception("Configuration")
00027 << "GflashHadronShowerProfile requires RandomNumberGeneratorService\n"
00028 << "which is not present in the configuration file. "
00029 << "You must add the service\n in the configuration file or "
00030 << "remove the modules that require it.";
00031 }
00032 theRandGauss = new CLHEP::RandGaussQ(rng->getEngine());
00033 theRandGamma = new CLHEP::RandGamma(rng->getEngine());
00034
00035
00036 fillFluctuationVector();
00037 }
00038
00039 GflashHadronShowerProfile::~GflashHadronShowerProfile()
00040 {
00041
00042 delete theHelix;
00043 delete theRandGauss;
00044 delete theRandGamma;
00045 }
00046
00047 Gflash::CalorimeterNumber GflashHadronShowerProfile::getCalorimeterNumber(const G4ThreeVector position)
00048 {
00049 Gflash::CalorimeterNumber index = Gflash::kNULL;
00050 G4double eta = position.getEta();
00051
00052
00053 if (fabs(eta) < Gflash::EtaMax[Gflash::kESPM] || fabs(eta) < Gflash::EtaMax[Gflash::kHB]) {
00054 if(position.getRho() > Gflash::Rmin[Gflash::kESPM] &&
00055 position.getRho() < Gflash::Rmax[Gflash::kESPM] ) {
00056 index = Gflash::kESPM;
00057 }
00058 if(position.getRho() > Gflash::Rmin[Gflash::kHB] &&
00059 position.getRho() < Gflash::Rmax[Gflash::kHB]) {
00060 index = Gflash::kHB;
00061 }
00062 }
00063
00064 else if (fabs(eta) > Gflash::EtaMin[Gflash::kENCA] || fabs(eta) > Gflash::EtaMin[Gflash::kHE]) {
00065 if( fabs(position.getZ()) > Gflash::Zmin[Gflash::kENCA] &&
00066 fabs(position.getZ()) < Gflash::Zmax[Gflash::kENCA] ) {
00067 index = Gflash::kENCA;
00068 }
00069 if( fabs(position.getZ()) > Gflash::Zmin[Gflash::kHE] &&
00070 fabs(position.getZ()) < Gflash::Zmax[Gflash::kHE] ) {
00071 index = Gflash::kHE;
00072 }
00073 }
00074 return index;
00075 }
00076
00077 void GflashHadronShowerProfile::hadronicParameterization(const G4FastTrack& fastTrack)
00078 {
00079
00080
00081
00082
00083
00084
00085
00086 const G4int maxNumberOfSpots = 10000;
00087
00088
00089
00090
00091
00092 const G4double maxShowerDepthforR50 = 10.0;
00093
00094 G4double rShower = 0.;
00095 G4double rGauss = theRandGauss->fire();
00096
00097
00098
00099
00100 G4double einc = fastTrack.GetPrimaryTrack()->GetKineticEnergy()/GeV;
00101 G4ThreeVector positionShower = fastTrack.GetPrimaryTrack()->GetPosition()/cm;
00102 G4ThreeVector momentumShower = fastTrack.GetPrimaryTrack()->GetMomentum()/GeV;
00103
00104
00105 jCalorimeter = getCalorimeterNumber(positionShower);
00106
00107
00108 loadParameters(fastTrack);
00109
00110
00111
00112
00113 const G4double bField = 4.0*tesla;
00114
00115 double charge = fastTrack.GetPrimaryTrack()->GetStep()->GetPreStepPoint()->GetCharge();
00116
00117 theHelix->initializeTrajectory(momentumShower,positionShower,charge,bField/tesla);
00118
00119
00120
00121 G4double pathLength0 = 0;
00122 G4double transDepth = 0;
00123
00124
00125
00126
00127
00128
00129 G4double stepLengthLeft = 0.0;
00130
00131 if(jCalorimeter == Gflash::kESPM || jCalorimeter == Gflash::kHB ) {
00132 pathLength0 = theHelix->getPathLengthAtRhoEquals(positionShower.getRho());
00133 stepLengthLeft = theHelix->getPathLengthAtRhoEquals(Gflash::Rmax[Gflash::kHB])
00134 - theHelix->getPathLengthAtRhoEquals(positionShower.getRho());
00135 if(showerType == 3 ) {
00136 transDepth = theHelix->getPathLengthAtRhoEquals(Gflash::Rmin[Gflash::kHB]) - pathLength0;
00137 }
00138 }
00139 else if (jCalorimeter == Gflash::kENCA || jCalorimeter == Gflash::kHE ) {
00140 pathLength0 = theHelix->getPathLengthAtZ(positionShower.getZ());
00141 stepLengthLeft = theHelix->getPathLengthAtRhoEquals(Gflash::Zmax[Gflash::kHE])
00142 - theHelix->getPathLengthAtRhoEquals(positionShower.getZ());
00143 if ( showerType ==7 ) {
00144 transDepth = theHelix->getPathLengthAtZ(Gflash::Zmin[Gflash::kHE]) - pathLength0;
00145 }
00146 }
00147 else {
00148
00149 stepLengthLeft = 200.0;
00150 }
00151
00152 G4double pathLength = pathLength0;
00153
00154
00155 G4int numberOfSpots = std::max( 50, static_cast<int>(800.*std::log(einc)+50.));
00156 numberOfSpots = std::min(numberOfSpots,maxNumberOfSpots);
00157
00158
00159
00160
00161 G4double spotEnergy = energyToDeposit/numberOfSpots;
00162
00163
00164 const G4double divisionStep = 1.0;
00165 G4double deltaStep = 0.0;
00166 G4double showerDepth = 0.0;
00167
00168
00169 G4int totalNumberOfSpots = 0;
00170
00171
00172 aEnergySpotList.clear();
00173
00174 double scaleLateral = 0.0;
00175 const double rMoliere = 2.19;
00176
00177 while(stepLengthLeft > 0.0) {
00178
00179
00180 if ( stepLengthLeft < divisionStep ) {
00181 deltaStep = stepLengthLeft;
00182 stepLengthLeft = 0.0;
00183 }
00184 else {
00185 deltaStep = divisionStep;
00186 stepLengthLeft -= deltaStep;
00187 }
00188
00189 showerDepth += deltaStep;
00190 pathLength += deltaStep;
00191
00192
00193 double deltaEnergy = 0.;
00194
00195 double heightProfile = longitudinalProfile(showerDepth,pathLength,transDepth);
00196
00197 deltaEnergy = heightProfile*divisionStep*energyToDeposit;
00198
00199
00200
00201
00202
00203 double hadronicFraction = 1.0;
00204 G4double fluctuatedEnergy = deltaEnergy;
00205 G4int nSpotsInStep = std::max(1,static_cast<int>(fluctuatedEnergy/spotEnergy));
00206 G4double sampleSpotEnergy = hadronicFraction*fluctuatedEnergy/nSpotsInStep;
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219 double showerDepthR50 = std::min(showerDepth/20.7394, maxShowerDepthforR50);
00220
00221 double R50 = lateralPar[0] + lateralPar[1] * showerDepthR50;
00222 double varinanceR50 = std::pow((lateralPar[2] + lateralPar[3] * showerDepthR50) * R50, 2);
00223
00224
00225
00226 double sigmaSq = std::log(varinanceR50/(R50*R50)+1.0);
00227 double sigmaR50 = std::sqrt(sigmaSq);
00228 double meanR50 = std::log(R50) - (sigmaSq/2.);
00229
00230 R50 = std::exp(rGauss*sigmaR50 + meanR50);
00231
00232
00233
00234
00235
00236 if(showerType == 4 || showerType == 8) {
00237 scaleLateral = (3.5+1.0*showerDepth)*rMoliere;
00238 }
00239 else {
00240
00241 if(showerDepthR50 < 2.0 ) {
00242 scaleLateral = (5.5-0.4*std::log(einc))*rMoliere;
00243 }
00244 else {
00245 scaleLateral = ( 14-1.5*std::log(einc))*rMoliere;
00246 }
00247 }
00248
00249
00250
00251
00252 R50 *= scaleLateral;
00253
00254 GflashEnergySpot eSpot;
00255
00256 for (G4int ispot = 0 ; ispot < nSpotsInStep ; ispot++) {
00257
00258 totalNumberOfSpots++;
00259
00260
00261 G4double rnunif = G4UniformRand();
00262 G4double rxPDF = std::sqrt(rnunif/(1.-rnunif));
00263 rShower = R50 * rxPDF;
00264
00265
00266 G4double azimuthalAngle = 0.0;
00267
00268 azimuthalAngle = twopi*G4UniformRand();
00269
00270
00271
00272 G4double incrementPath = (deltaStep/nSpotsInStep)*(ispot+0.5 - 0.5*nSpotsInStep);
00273
00274
00275 GflashTrajectoryPoint trajectoryPoint;
00276 theHelix->getGflashTrajectoryPoint(trajectoryPoint,pathLength+incrementPath);
00277
00278
00279 G4ThreeVector SpotPosition = trajectoryPoint.getPosition() +
00280 rShower*std::cos(azimuthalAngle)*trajectoryPoint.getOrthogonalUnitVector() +
00281 rShower*std::sin(azimuthalAngle)*trajectoryPoint.getCrossUnitVector();
00282
00283
00284
00285 eSpot.setEnergy(sampleSpotEnergy*GeV);
00286 eSpot.setPosition(SpotPosition*cm);
00287 aEnergySpotList.push_back(eSpot);
00288
00289
00290 if(theHisto->getStoreFlag()) {
00291 theHisto->rshower->Fill(rShower);
00292 theHisto->lateralx->Fill(rShower*std::cos(azimuthalAngle));
00293 theHisto->lateraly->Fill(rShower*std::sin(azimuthalAngle));
00294 theHisto->gfhlongProfile->Fill(pathLength+incrementPath-pathLength0,positionShower.getRho(),eSpot.getEnergy()*GeV);
00295 }
00296 }
00297 }
00298
00299 }
00300
00301 void GflashHadronShowerProfile::loadParameters(const G4FastTrack& fastTrack)
00302 {
00303
00304
00305
00306 G4double einc = fastTrack.GetPrimaryTrack()->GetKineticEnergy()/GeV;
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320 G4TouchableHistory* touch = (G4TouchableHistory*)(fastTrack.GetPrimaryTrack()->GetTouchable());
00321 G4LogicalVolume* lv = touch->GetVolume()->GetLogicalVolume();
00322 std::size_t pos1 = lv->GetName().find("EBRY");
00323 std::size_t pos2 = lv->GetName().find("EFRY");
00324
00325 G4ThreeVector position = fastTrack.GetPrimaryTrack()->GetPosition()/cm;
00326
00327 showerType = 0;
00328
00329 G4double correctionAsDepth = 0.0;
00330
00331
00332 if (jCalorimeter == Gflash::kESPM || jCalorimeter == Gflash::kHB ) {
00333
00334 G4double posRho = position.getRho();
00335
00336 if(pos1 != std::string::npos) {
00337 showerType = 2;
00338 }
00339 else {
00340 if(jCalorimeter == Gflash::kESPM) {
00341 showerType = 3;
00342 if( posRho < 129.0 ) showerType = 1;
00343 }
00344 else showerType = 4;
00345 }
00346
00347 if ( posRho < 150.0 ) {
00348 correctionAsDepth = 0.01-2.0/((posRho-150.)*(posRho-150.) +5.4*5.4);
00349 }
00350 else {
00351 correctionAsDepth = 0.03-2.0/((posRho-150.)*(posRho-150.) +4.7*4.7);
00352 }
00353 }
00354
00355 else if (jCalorimeter == Gflash::kENCA || jCalorimeter == Gflash::kHE) {
00356 if(pos2 != std::string::npos) {
00357 showerType = 6;
00358 }
00359 else {
00360 if(jCalorimeter == Gflash::kENCA) {
00361 showerType = 7;
00362 if(fabs(position.getZ()) < 330.0 ) showerType = 5;
00363 }
00364 else showerType = 8;
00365 }
00366
00367 }
00368
00369
00370
00371
00372 G4double fractionEnergy = 1.0;
00373 G4double sigmaEnergy = 0.0;
00374
00375 if( showerType == 4 || showerType == 8) {
00376
00377 fractionEnergy = 0.7125 + 0.0812*std::tanh(0.9040*(std::log(einc) - 2.6307));
00378 sigmaEnergy = 0.0257/std::sqrt(einc) + 0.0734;
00379 }
00380 else {
00381 fractionEnergy = 0.7125 + 0.0812*std::tanh(0.9040*(std::log(einc) - 2.6307));
00382 sigmaEnergy = 0.0844/std::sqrt(einc) + 0.0592;
00383 }
00384
00385 energyToDeposit = fractionEnergy*(1.0+correctionAsDepth)*einc*(1.0+sigmaEnergy*theRandGauss->fire());
00386 energyToDeposit = std::max(0.0,energyToDeposit);
00387
00388
00389
00390
00391
00392 longPar[0][0] = 1.41*std::max(0.0,-5.96481e-03 + 0.18231*std::tanh(0.55451*(std::log(einc)-0.458775))) ;
00393 longPar[0][1] = std::max(0.0,2.01611 + 1.77483 * std::tanh(0.75719*(std::log(einc) - 2.58172)));
00394 longPar[0][2] = std::max(0.0,0.21261 + 0.24168 * std::tanh(0.76962*(std::log(einc) - 2.11936)));
00395 longPar[0][3] = std::max(0.0,1.05577e-02 + 1.00807 * std::tanh(-6.31044e-04*(std::log(einc) - 4.60658)));
00396 longPar[0][4] = 0.87*std::max(0.0,1.19845e-01 + 6.87070e-02 * std::tanh(-8.23888e-01*(std::log(einc) - 2.90178)));
00397 longPar[0][5] = std::max(0.0,2.49694e+01 + 1.10258e+01 * std::tanh(6.16435e-01*(std::log(einc) - 3.56012)));
00398
00399 longSigma[0][0] = 0.02;
00400 longSigma[0][1] = 0.16;
00401 longSigma[0][2] = 0.02;
00402 longSigma[0][3] = 0.01;
00403 longSigma[0][4] = 0.03;
00404 longSigma[0][5] = 2.50;
00405
00406 longPar[1][0] = 0.1126;
00407 longPar[1][1] = 1.3857;
00408 longPar[1][2] = std::max(0.0,1.1353 + 0.4997*std::tanh(-0.6382*(std::log(einc) - 2.0035)));
00409 longPar[1][3] = 0.2300;
00410 longPar[1][4] = 3.5018;
00411 longPar[1][5] = std::max(0.0,0.6151 - 0.0561*std::log(einc));
00412
00413 longSigma[1][0] = 0.01;
00414 longSigma[1][1] = 0.44;
00415 longSigma[1][2] = 0.01;
00416 longSigma[1][3] = 0.01;
00417 longSigma[1][4] = 0.20;
00418 longSigma[1][5] = 0.04;
00419
00420 longPar[2][0] = std::max(0.0,-1.55624e+01+1.56831e+01*std::tanh(5.93651e-01*(std::log(einc) + 4.89902)));
00421 longPar[2][1] = std::max(0.0,7.28995e-01+ 7.71148e-01*std::tanh(4.77898e-01*(std::log(einc) - 1.69087)));
00422 longPar[2][2] = std::max(0.0,1.23387+ 7.34778e-01*std::tanh(-3.14958e-01*(std::log(einc) - 0.529206)));
00423 longPar[2][3] = std::max(0.0,1.02070e+02+1.01873e+02*std::tanh(-4.99805e-01*(std::log(einc) + 5.04012)));
00424 longPar[2][4] = std::max(0.0,3.59765+8.53358e-01*std::tanh( 8.47277e-01*(std::log(einc) - 3.36548)));
00425 longPar[2][5] = std::max(0.0,4.27294e-01+1.62535e-02*std::tanh(-2.26278*(std::log(einc) - 1.81308)));
00426
00427 longSigma[2][0] = 0.01;
00428 longSigma[2][1] = 0.44;
00429 longSigma[2][2] = 0.01;
00430 longSigma[2][3] = 0.01;
00431 longSigma[2][4] = 0.20;
00432 longSigma[2][5] = 0.04;
00433
00434 double normalZ[Gflash::NxN];
00435 for (int i = 0; i < Gflash::NxN ; i++) normalZ[i] = theRandGauss->fire();
00436
00437 for(int k = 0 ; k < Gflash::NRegion ; k++) {
00438 for(int i = 0 ; i < Gflash::NxN ; i++) {
00439 double correlationSum = 0.0;
00440 for(int j = 0 ; j < Gflash::NxN ; j++) {
00441 correlationSum += correlationVector[Gflash::NStart[Gflash::NRegion]+(i+1)/2+j]*normalZ[i];
00442 }
00443 longPar[k][i] = std::max(0.0,longPar[k][i]+longSigma[k][i]*correlationSum);
00444 }
00445 }
00446
00447
00448
00449 lateralPar[0] = 0.20;
00450 lateralPar[1] = std::max(0.0,0.40 -0.06*std::log(einc));
00451 lateralPar[2] = 0.70 - 0.05*std::max(0.,std::log(einc));
00452 lateralPar[3] = 0.20 * lateralPar[2];
00453 }
00454
00455 G4double GflashHadronShowerProfile::longitudinalProfile(G4double showerDepth, G4double pathLength, G4double transDepth){
00456
00457 G4double heightProfile = 0;
00458
00459
00460
00461
00462
00463
00464
00465 Genfun::LogGamma lgam;
00466 GflashTrajectoryPoint tempPoint;
00467 theHelix->getGflashTrajectoryPoint(tempPoint,pathLength);
00468
00469 double x = 0.0;
00470
00471 if(showerType == 1 || showerType == 2 ) {
00472
00473 if(tempPoint.getPosition().getRho() < 150.0 ) {
00474 x = showerDepth*longPar[0][2];
00475 heightProfile = longPar[0][0]*std::pow(x,longPar[0][1]-1.0)*std::exp(-x)/std::exp(lgam(longPar[0][1]))+longPar[0][3];
00476 }
00477 else if (tempPoint.getPosition().getRho() > Gflash::Rmin[Gflash::kHB] ){
00478 x = showerDepth;
00479 heightProfile = longPar[0][4]*std::exp(-x/longPar[0][5]);
00480 heightProfile *= Gflash::ScaleSensitive;
00481 }
00482 else heightProfile = 0.;
00483 }
00484 else if(showerType == 5 || showerType == 6){
00485
00486 if(std::abs(tempPoint.getPosition().getZ()) < Gflash::Zmin[Gflash::kENCA]+23.0 ) {
00487 x = showerDepth*longPar[0][2];
00488 heightProfile = longPar[0][0]*std::pow(x,longPar[0][1]-1.0)*std::exp(-x)/std::exp(lgam(longPar[0][1]))+longPar[0][3];
00489 }
00490 else if (std::abs(tempPoint.getPosition().getZ()) > Gflash::Rmin[Gflash::kHE] ){
00491 x = showerDepth;
00492 heightProfile = longPar[0][4]*std::exp(-x/longPar[0][5]);
00493 heightProfile *= Gflash::ScaleSensitive;
00494 }
00495 else heightProfile = 0.;
00496 }
00497 else if (showerType == 3 || showerType == 7 ) {
00498
00499 if((showerDepth - transDepth) > 0.0) {
00500 double x1 = (showerDepth-transDepth)*longPar[1][2]/16.42;
00501 double x2 = (showerDepth-transDepth)*longPar[1][5]/1.49;
00502
00503 heightProfile = longPar[1][3]*std::pow(x1,longPar[1][1]-1.0)*std::exp(-x1)/std::exp(lgam(longPar[1][1]))
00504 + (1.0-longPar[1][3])*std::pow(x2,longPar[1][4]-1.0)*std::exp(-x2)/std::exp(lgam(longPar[1][4]));
00505 heightProfile = std::max(0.0,longPar[1][0]*heightProfile);
00506 heightProfile *= Gflash::ScaleSensitive;
00507 }
00508 else heightProfile = 0.;
00509 }
00510 else if (showerType == 4 || showerType == 8 ) {
00511
00512 double x1 = showerDepth*longPar[2][2]/16.42;
00513 double x2 = showerDepth*longPar[2][5]/1.49;
00514 heightProfile = longPar[2][3]*std::pow(x1,longPar[2][1]-1.0)*std::exp(-x1)/std::exp(lgam(longPar[2][1]))
00515 + (1.0-longPar[2][3])*std::pow(x2,longPar[2][4]-1.0)*std::exp(-x2)/std::exp(lgam(longPar[2][4]));
00516 heightProfile = std::max(0.0,longPar[2][0]*heightProfile);
00517 heightProfile *= Gflash::ScaleSensitive;
00518 }
00519
00520 return heightProfile;
00521 }
00522
00523 void GflashHadronShowerProfile::samplingFluctuation(G4double &de, G4double einc){
00524
00525 G4double spot[Gflash::NDET];
00526
00527 for(G4int i = 0 ; i < Gflash::NDET ; i++) {
00528 spot[i] = std::pow(Gflash::SAMHAD[0][i],2)
00529 + std::pow(Gflash::SAMHAD[1][i],2)/einc
00530 + std::pow(Gflash::SAMHAD[2][i],2)*einc;
00531 }
00532 G4double ein = de * (energyToDeposit/einc);
00533
00534 de = (ein > 0 ) ?
00535 theRandGamma->fire(ein/spot[jCalorimeter],1.0)*spot[jCalorimeter] : ein;
00536 }
00537
00538 G4bool GflashHadronShowerProfile::insideSampling(const G4ThreeVector pos) {
00539 G4bool issampling = false;
00540
00541 if((jCalorimeter == Gflash::kHB) || (jCalorimeter == Gflash::kHE) ||
00542 ((jCalorimeter == Gflash::kESPM) && ((pos.rho()/cm - 177.5) > 0)) ||
00543 ((jCalorimeter == Gflash::kENCA) && ( fabs(pos.z()/cm - 391.95) > 0 ))) issampling = true;
00544 return issampling;
00545 }
00546
00547 void GflashHadronShowerProfile::fillFluctuationVector() {
00548
00549
00550 for(G4int k = 0 ; k < Gflash::NRegion ; k++) {
00551 const G4int dim = Gflash::NDim[k];
00552 G4double **xr = new G4double *[dim];
00553 G4double **xrho = new G4double *[dim];
00554
00555 for(G4int j=0;j<dim;j++) {
00556 xr[j] = new G4double [dim];
00557 xrho[j] = new G4double [dim];
00558 }
00559
00560 for(G4int i = 0; i < dim; i++) {
00561 for(G4int j = 0; j < i+1 ; j++) {
00562 xrho[i][j] = Gflash::rho[i+Gflash::NRegion*k][j];
00563 xrho[i][j] = Gflash::rho[i][j];
00564 xrho[j][i] = xrho[i][j];
00565 }
00566 }
00567
00568 doCholeskyReduction(xrho,xr,dim);
00569
00570 for(G4int i = 0 ; i < dim ; i++) {
00571 for (G4int j = 0 ; j < i+1 ; j++){
00572 correlationVector[Gflash::NStart[k]+i*(i+1)/2 + j] = xr[i][j];
00573 }
00574 }
00575
00576 std::cout << "this should be calcuated at constructor" << std::endl;
00577 for(int i = 0; i < 21 ; i++) std::cout << correlationVector[i] << std::endl;
00578
00579 for(G4int j=0;j<dim;j++) delete [] xr[j];
00580 delete [] xr;
00581 for(G4int j=0;j<dim;j++) delete [] xrho[j];
00582 delete [] xrho;
00583 }
00584 }
00585
00586 void GflashHadronShowerProfile::doCholeskyReduction(double **vv, double **cc, const int ndim) {
00587
00588 G4double sumCjkSquare;
00589 G4double vjjLess;
00590 G4double sumCikjk;
00591
00592 cc[0][0] = std::sqrt(vv[0][0]);
00593
00594 for(G4int j=1 ; j < ndim ; j++) {
00595 cc[j][0] = vv[j][0]/cc[0][0];
00596 }
00597
00598 for(G4int j=1 ; j < ndim ; j++) {
00599
00600 sumCjkSquare = 0.0;
00601 for (G4int k=0 ; k < j ; k++) sumCjkSquare += cc[j][k]*cc[j][k];
00602
00603 vjjLess = vv[j][j] - sumCjkSquare;
00604
00605 if ( vjjLess < 0. ) {
00606 std::cout << "GflashHadronShowerProfile::CholeskyReduction failed " << std::endl;
00607 }
00608 else {
00609 cc[j][j] = std::sqrt(std::fabs(vjjLess));
00610
00611 for (G4int i=j+1 ; i < ndim ; i++) {
00612 sumCikjk = 0.;
00613 for(G4int k=0 ; k < j ; k++) sumCikjk += cc[i][k]*cc[j][k];
00614 cc[i][j] = (vv[i][j] - sumCikjk)/cc[j][j];
00615 }
00616 }
00617 }
00618 }