// // ******************************************************************** // * License and Disclaimer * // * * // * The Geant4 software is copyright of the Copyright Holders of * // * the Geant4 Collaboration. It is provided under the terms and * // * conditions of the Geant4 Software License, included in the file * // * LICENSE and available at http://cern.ch/geant4/license . These * // * include a list of copyright holders. * // * * // * Neither the authors of this software system, nor their employing * // * institutes,nor the agencies providing financial support for this * // * work make any representation or warranty, express or implied, * // * regarding this software system or assume any liability for its * // * use. Please see the license in the file LICENSE and URL above * // * for the full disclaimer and the limitation of liability. * // * * // * This code implementation is the result of the scientific and * // * technical work of the GEANT4 collaboration. * // * By using, copying, modifying or distributing the software (or * // * any work based on the software) you agree to acknowledge its * // * use in resulting scientific publications, and indicate your * // * acceptance of all terms of the Geant4 Software license. * // ******************************************************************** // // neutron_hp -- source file // J.P. Wellisch, Nov-1996 // A prototype of the low energy neutron transport model. // // 070523 Try to limit sum of secondary photon energy while keeping distribution shape // in the of nDiscrete = 1 an nPartial = 1. Most case are satisfied. // T. Koi // 070606 Add Partial case by T. Koi // 070618 fix memory leaking by T. Koi // 080801 fix memory leaking by T. Koi // 080801 Correcting data disorder which happened when both InitPartial // and InitAnglurar methods was called in a same instance by T. Koi // 090514 Fix bug in IC electron emission case // Contribution from Chao Zhang (Chao.Zhang@usd.edu) and Dongming Mei(Dongming.Mei@usd.edu) // But it looks like never cause real effect in G4NDL3.13 (at least Natural elements) TK // 101111 Change warning message for "repFlag == 2 && isoFlag != 1" case // // there is a lot of unused (and undebugged) code in this file. Kept for the moment just in case. @@ // P. Arce, June-2014 Conversion neutron_hp to particle_hp // #include "G4ParticleHPPhotonDist.hh" #include "G4Electron.hh" #include "G4ParticleHPLegendreStore.hh" #include "G4PhysicalConstants.hh" #include "G4Poisson.hh" #include "G4SystemOfUnits.hh" #include G4bool G4ParticleHPPhotonDist::InitMean(std::istream& aDataFile) { G4bool result = true; if (aDataFile >> repFlag) { aDataFile >> targetMass; if (repFlag == 1) { // multiplicities aDataFile >> nDiscrete; const std::size_t msize = nDiscrete > 0 ? nDiscrete : 1; disType = new G4int[msize]; energy = new G4double[msize]; // actualMult = new G4int[msize]; theYield = new G4ParticleHPVector[msize]; for (std::size_t i = 0; i < msize; ++i) { aDataFile >> disType[i] >> energy[i]; energy[i] *= eV; theYield[i].Init(aDataFile, eV); } } else if (repFlag == 2) { aDataFile >> theInternalConversionFlag; aDataFile >> theBaseEnergy; theBaseEnergy *= eV; aDataFile >> theInternalConversionFlag; aDataFile >> nGammaEnergies; const std::size_t esize = nGammaEnergies > 0 ? nGammaEnergies : 1; theLevelEnergies = new G4double[esize]; theTransitionProbabilities = new G4double[esize]; if (theInternalConversionFlag == 2) thePhotonTransitionFraction = new G4double[esize]; for (std::size_t ii = 0; ii < esize; ++ii) { if (theInternalConversionFlag == 1) { aDataFile >> theLevelEnergies[ii] >> theTransitionProbabilities[ii]; theLevelEnergies[ii] *= eV; } else if (theInternalConversionFlag == 2) { aDataFile >> theLevelEnergies[ii] >> theTransitionProbabilities[ii] >> thePhotonTransitionFraction[ii]; theLevelEnergies[ii] *= eV; } else { throw G4HadronicException(__FILE__, __LINE__, "G4ParticleHPPhotonDist: Unknown conversion flag"); } } } else { G4cout << "Data representation in G4ParticleHPPhotonDist: " << repFlag << G4endl; throw G4HadronicException( __FILE__, __LINE__, "G4ParticleHPPhotonDist: This data representation is not implemented."); } } else { result = false; } return result; } void G4ParticleHPPhotonDist::InitAngular(std::istream& aDataFile) { G4int i, ii; // angular distributions aDataFile >> isoFlag; if (isoFlag != 1) { if (repFlag == 2) G4cout << "G4ParticleHPPhotonDist: repFlag == 2 && isoFlag != 1 is unexpected! If you use " "G4ND3.x, then please report to Geant4 HyperNews. " << G4endl; aDataFile >> tabulationType >> nDiscrete2 >> nIso; if (theGammas != nullptr && nDiscrete2 != nDiscrete) G4cout << "080731c G4ParticleHPPhotonDist nDiscrete2 != nDiscrete, It looks like something " "wrong in your NDL files. Please update the latest. If you still have this " "messages after the update, then please report to Geant4 Hyper News." << G4endl; // The order of cross section (InitPartials) and distribution // (InitAngular here) data are different, we have to re-coordinate // consistent data order. std::vector vct_gammas_par; std::vector vct_shells_par; std::vector vct_primary_par; std::vector vct_distype_par; std::vector vct_pXS_par; if (theGammas != nullptr && theShells != nullptr) { // copy the cross section data for (i = 0; i < nDiscrete; ++i) { vct_gammas_par.push_back(theGammas[i]); vct_shells_par.push_back(theShells[i]); vct_primary_par.push_back(isPrimary[i]); vct_distype_par.push_back(disType[i]); auto hpv = new G4ParticleHPVector; *hpv = thePartialXsec[i]; vct_pXS_par.push_back(hpv); } } const std::size_t psize = nDiscrete2 > 0 ? nDiscrete2 : 1; if (theGammas == nullptr) theGammas = new G4double[psize]; if (theShells == nullptr) theShells = new G4double[psize]; for (i = 0; i < nIso; ++i) // isotropic photons { aDataFile >> theGammas[i] >> theShells[i]; theGammas[i] *= eV; theShells[i] *= eV; } const std::size_t tsize = nDiscrete2 - nIso > 0 ? nDiscrete2 - nIso : 1; nNeu = new G4int[tsize]; if (tabulationType == 1) theLegendre = new G4ParticleHPLegendreTable*[tsize]; if (tabulationType == 2) theAngular = new G4ParticleHPAngularP*[tsize]; for (i = nIso; i < nDiscrete2; ++i) { if (tabulationType == 1) { aDataFile >> theGammas[i] >> theShells[i] >> nNeu[i - nIso]; theGammas[i] *= eV; theShells[i] *= eV; const std::size_t lsize = nNeu[i - nIso] > 0 ? nNeu[i - nIso] : 1; theLegendre[i - nIso] = new G4ParticleHPLegendreTable[lsize]; theLegendreManager.Init(aDataFile); for (ii = 0; ii < nNeu[i - nIso]; ++ii) { theLegendre[i - nIso][ii].Init(aDataFile); } } else if (tabulationType == 2) { aDataFile >> theGammas[i] >> theShells[i] >> nNeu[i - nIso]; theGammas[i] *= eV; theShells[i] *= eV; const std::size_t asize = nNeu[i - nIso] > 0 ? nNeu[i - nIso] : 1; theAngular[i - nIso] = new G4ParticleHPAngularP[asize]; for (ii = 0; ii < nNeu[i - nIso]; ++ii) { theAngular[i - nIso][ii].Init(aDataFile); } } else { G4cout << "tabulation type: tabulationType" << G4endl; throw G4HadronicException( __FILE__, __LINE__, "cannot deal with this tabulation type for angular distributions."); } } if (!vct_gammas_par.empty()) { // Reordering cross section data to corrsponding distribution data for (i = 0; i < nDiscrete; ++i) { for (G4int j = 0; j < nDiscrete; ++j) { // Checking gamma and shell to identification if (theGammas[i] == vct_gammas_par[j] && theShells[i] == vct_shells_par[j]) { isPrimary[i] = vct_primary_par[j]; disType[i] = vct_distype_par[j]; thePartialXsec[i] = (*(vct_pXS_par[j])); } } } // Garbage collection for (auto it = vct_pXS_par.cbegin(); it != vct_pXS_par.cend(); ++it) { delete *it; } } } } void G4ParticleHPPhotonDist::InitEnergies(std::istream& aDataFile) { G4int i, energyDistributionsNeeded = 0; for (i = 0; i < nDiscrete; ++i) { if (disType[i] == 1) energyDistributionsNeeded = 1; } if (energyDistributionsNeeded == 0) return; aDataFile >> nPartials; const std::size_t dsize = nPartials > 0 ? nPartials : 1; distribution = new G4int[dsize]; probs = new G4ParticleHPVector[dsize]; partials = new G4ParticleHPPartial*[dsize]; G4int nen; G4int dummy; for (i = 0; i < nPartials; ++i) { aDataFile >> dummy; probs[i].Init(aDataFile, eV); aDataFile >> nen; partials[i] = new G4ParticleHPPartial(nen); partials[i]->InitInterpolation(aDataFile); partials[i]->Init(aDataFile); } } void G4ParticleHPPhotonDist::InitPartials(std::istream& aDataFile, G4ParticleHPVector* theXsec) { if (theXsec != nullptr) theReactionXsec = theXsec; aDataFile >> nDiscrete >> targetMass; if (nDiscrete != 1) { theTotalXsec.Init(aDataFile, eV); } const std::size_t dsize = nDiscrete > 0 ? nDiscrete : 1; theGammas = new G4double[dsize]; theShells = new G4double[dsize]; isPrimary = new G4int[dsize]; disType = new G4int[dsize]; thePartialXsec = new G4ParticleHPVector[dsize]; for (std::size_t i = 0; i < dsize; ++i) { aDataFile >> theGammas[i] >> theShells[i] >> isPrimary[i] >> disType[i]; theGammas[i] *= eV; theShells[i] *= eV; thePartialXsec[i].Init(aDataFile, eV); } } G4ReactionProductVector* G4ParticleHPPhotonDist::GetPhotons(G4double anEnergy) { // the partial cross-section case is not all in this yet. if (actualMult.Get() == nullptr) { actualMult.Get() = new std::vector(nDiscrete); } G4int i, ii, iii; G4int nSecondaries = 0; auto thePhotons = new G4ReactionProductVector; if (repFlag == 1) { G4double current = 0; for (i = 0; i < nDiscrete; ++i) { current = theYield[i].GetY(anEnergy); actualMult.Get()->at(i) = (G4int)G4Poisson(current); // max cut-off still missing @@@ if (nDiscrete == 1 && current < 1.0001) { actualMult.Get()->at(i) = static_cast(current); if (current < 1) { actualMult.Get()->at(i) = 0; if (G4UniformRand() < current) actualMult.Get()->at(i) = 1; } } nSecondaries += actualMult.Get()->at(i); } for (i = 0; i < nSecondaries; ++i) { auto theOne = new G4ReactionProduct; theOne->SetDefinition(G4Gamma::Gamma()); thePhotons->push_back(theOne); } G4int count = 0; if (nDiscrete == 1 && nPartials == 1) { if (actualMult.Get()->at(0) > 0) { if (disType[0] == 1) { // continuum G4ParticleHPVector* temp; temp = partials[0]->GetY(anEnergy); //@@@ look at, seems fishy G4double maximumE = temp->GetX(temp->GetVectorLength() - 1); // This is an assumption. std::vector photons_e_best(actualMult.Get()->at(0), 0.0); G4double best = DBL_MAX; G4int maxTry = 1000; for (G4int j = 0; j < maxTry; ++j) { std::vector photons_e(actualMult.Get()->at(0), 0.0); for (auto it = photons_e.begin(); it < photons_e.end(); ++it) { *it = temp->Sample(); } if (std::accumulate(photons_e.cbegin(), photons_e.cend(), 0.0) > maximumE) { if (std::accumulate(photons_e.cbegin(), photons_e.cend(), 0.0) < best) photons_e_best = photons_e; continue; } G4int iphot = 0; for (auto it = photons_e.cbegin(); it < photons_e.cend(); ++it) { thePhotons->operator[](iphot)->SetKineticEnergy( *it); // Replace index count, which was not incremented, // with iphot, which is, as per Artem Zontikov, // bug report 2167 ++iphot; } break; } delete temp; } else { // discrete thePhotons->operator[](count)->SetKineticEnergy(energy[i]); } ++count; if (count > nSecondaries) throw G4HadronicException(__FILE__, __LINE__, "G4ParticleHPPhotonDist::GetPhotons inconsistency"); } } else { // nDiscrete != 1 or nPartials != 1 for (i = 0; i < nDiscrete; ++i) { for (ii = 0; ii < actualMult.Get()->at(i); ++ii) { if (disType[i] == 1) { // continuum G4double sum = 0, run = 0; for (iii = 0; iii < nPartials; ++iii) sum += probs[iii].GetY(anEnergy); G4double random = G4UniformRand(); G4int theP = 0; for (iii = 0; iii < nPartials; ++iii) { run += probs[iii].GetY(anEnergy); theP = iii; if (random < run / sum) break; } if (theP == nPartials) theP = nPartials - 1; // das sortiert J aus. sum = 0; G4ParticleHPVector* temp; temp = partials[theP]->GetY(anEnergy); //@@@ look at, seems fishy G4double eGamm = temp->Sample(); thePhotons->operator[](count)->SetKineticEnergy(eGamm); delete temp; } else { // discrete thePhotons->operator[](count)->SetKineticEnergy(energy[i]); } ++count; if (count > nSecondaries) throw G4HadronicException(__FILE__, __LINE__, "G4ParticleHPPhotonDist::GetPhotons inconsistency"); } } } // now do the angular distributions... if (isoFlag == 1) { for (i = 0; i < nSecondaries; ++i) { G4double costheta = 2. * G4UniformRand() - 1; G4double theta = std::acos(costheta); G4double phi = twopi * G4UniformRand(); G4double sinth = std::sin(theta); G4double en = thePhotons->operator[](i)->GetTotalEnergy(); G4ThreeVector temp(en * sinth * std::cos(phi), en * sinth * std::sin(phi), en * std::cos(theta)); thePhotons->operator[](i)->SetMomentum(temp); } } else { for (i = 0; i < nSecondaries; ++i) { G4double currentEnergy = thePhotons->operator[](i)->GetTotalEnergy(); for (ii = 0; ii < nDiscrete2; ++ii) { if (std::abs(currentEnergy - theGammas[ii]) < 0.1 * keV) break; } if (ii == nDiscrete2) --ii; // fix for what seems an (file12 vs file 14) inconsistency found in the ENDF 7N14 // data. @@ if (ii < nIso) { // isotropic distribution // // Fix Bugzilla report #1745 // G4double theta = pi*G4UniformRand(); G4double costheta = 2. * G4UniformRand() - 1; G4double theta = std::acos(costheta); G4double phi = twopi * G4UniformRand(); G4double sinth = std::sin(theta); G4double en = thePhotons->operator[](i)->GetTotalEnergy(); // DHW G4ThreeVector tempVector(en*sinth*std::cos(phi), en*sinth*std::sin(phi), // en*std::cos(theta) ); G4ThreeVector tempVector(en * sinth * std::cos(phi), en * sinth * std::sin(phi), en * costheta); thePhotons->operator[](i)->SetMomentum(tempVector); } else if (tabulationType == 1) { // legendre polynomials G4int it(0); for (iii = 0; iii < nNeu[ii - nIso]; ++iii) // find the neutron energy { it = iii; if (theLegendre[ii - nIso][iii].GetEnergy() > anEnergy) break; } G4ParticleHPLegendreStore aStore(2); aStore.SetCoeff(1, &(theLegendre[ii - nIso][it])); if (it > 0) { aStore.SetCoeff(0, &(theLegendre[ii - nIso][it - 1])); } else { aStore.SetCoeff(0, &(theLegendre[ii - nIso][it])); } G4double cosTh = aStore.SampleMax(anEnergy); G4double theta = std::acos(cosTh); G4double phi = twopi * G4UniformRand(); G4double sinth = std::sin(theta); G4double en = thePhotons->operator[](i)->GetTotalEnergy(); G4ThreeVector tempVector(en * sinth * std::cos(phi), en * sinth * std::sin(phi), en * std::cos(theta)); thePhotons->operator[](i)->SetMomentum(tempVector); } else { // tabulation of probabilities. G4int it(0); for (iii = 0; iii < nNeu[ii - nIso]; ++iii) // find the neutron energy { it = iii; if (theAngular[ii - nIso][iii].GetEnergy() > anEnergy) break; } G4double costh = theAngular[ii - nIso][it].GetCosTh(); // no interpolation yet @@ G4double theta = std::acos(costh); G4double phi = twopi * G4UniformRand(); G4double sinth = std::sin(theta); G4double en = thePhotons->operator[](i)->GetTotalEnergy(); G4ThreeVector tmpVector(en * sinth * std::cos(phi), en * sinth * std::sin(phi), en * costh); thePhotons->operator[](i)->SetMomentum(tmpVector); } } } } else if (repFlag == 2) { auto running = new G4double[nGammaEnergies]; running[0] = theTransitionProbabilities[0]; for (i = 1; i < nGammaEnergies; ++i) { running[i] = running[i - 1] + theTransitionProbabilities[i]; } G4double random = G4UniformRand(); G4int it = 0; for (i = 0; i < nGammaEnergies; ++i) { it = i; if (random < running[i] / running[nGammaEnergies - 1]) break; } delete[] running; G4double totalEnergy = theBaseEnergy - theLevelEnergies[it]; auto theOne = new G4ReactionProduct; theOne->SetDefinition(G4Gamma::Gamma()); random = G4UniformRand(); if (theInternalConversionFlag == 2 && random > thePhotonTransitionFraction[it]) { theOne->SetDefinition(G4Electron::Electron()); // Bug reported Chao Zhang (Chao.Zhang@usd.edu), Dongming Mei(Dongming.Mei@usd.edu) Feb. 25, // 2009 But never enter at least with G4NDL3.13 totalEnergy += G4Electron::Electron()->GetPDGMass(); // proposed correction: add this line for electron } theOne->SetTotalEnergy(totalEnergy); if (isoFlag == 1) { G4double costheta = 2. * G4UniformRand() - 1; G4double theta = std::acos(costheta); G4double phi = twopi * G4UniformRand(); G4double sinth = std::sin(theta); // Bug reported Chao Zhang (Chao.Zhang@usd.edu), Dongming Mei(Dongming.Mei@usd.edu) Feb. 25, // 2009 G4double en = theOne->GetTotalEnergy(); G4double en = theOne->GetTotalMomentum(); // But never cause real effect at least with G4NDL3.13 TK G4ThreeVector temp(en * sinth * std::cos(phi), en * sinth * std::sin(phi), en * std::cos(theta)); theOne->SetMomentum(temp); } else { G4double currentEnergy = theOne->GetTotalEnergy(); for (ii = 0; ii < nDiscrete2; ++ii) { if (std::abs(currentEnergy - theGammas[ii]) < 0.1 * keV) break; } if (ii == nDiscrete2) --ii; // fix for what seems an (file12 vs file 14) inconsistency found in the ENDF 7N14 // data. @@ if (ii < nIso) { // Bug reported Chao Zhang (Chao.Zhang@usd.edu), Dongming Mei(Dongming.Mei@usd.edu) Feb. 25, // 2009 // isotropic distribution // G4double theta = pi*G4UniformRand(); G4double theta = std::acos(2. * G4UniformRand() - 1.); // But this is alos never cause real effect at least with G4NDL3.13 TK not repFlag == 2 AND // isoFlag != 1 G4double phi = twopi * G4UniformRand(); G4double sinth = std::sin(theta); // Bug reported Chao Zhang (Chao.Zhang@usd.edu), Dongming Mei(Dongming.Mei@usd.edu) Feb. 25, // 2009 G4double en = theOne->GetTotalEnergy(); G4double en = theOne->GetTotalMomentum(); // But never cause real effect at least with G4NDL3.13 TK G4ThreeVector tempVector(en * sinth * std::cos(phi), en * sinth * std::sin(phi), en * std::cos(theta)); theOne->SetMomentum(tempVector); } else if (tabulationType == 1) { // legendre polynomials G4int itt(0); for (iii = 0; iii < nNeu[ii - nIso]; ++iii) // find the neutron energy { itt = iii; if (theLegendre[ii - nIso][iii].GetEnergy() > anEnergy) break; } G4ParticleHPLegendreStore aStore(2); aStore.SetCoeff(1, &(theLegendre[ii - nIso][itt])); // aStore.SetCoeff(0, &(theLegendre[ii-nIso][it-1])); // TKDB 110512 if (itt > 0) { aStore.SetCoeff(0, &(theLegendre[ii - nIso][itt - 1])); } else { aStore.SetCoeff(0, &(theLegendre[ii - nIso][itt])); } G4double cosTh = aStore.SampleMax(anEnergy); G4double theta = std::acos(cosTh); G4double phi = twopi * G4UniformRand(); G4double sinth = std::sin(theta); // Bug reported Chao Zhang (Chao.Zhang@usd.edu), Dongming Mei(Dongming.Mei@usd.edu) Feb. 25, // 2009 G4double en = theOne->GetTotalEnergy(); G4double en = theOne->GetTotalMomentum(); // But never cause real effect at least with G4NDL3.13 TK G4ThreeVector tempVector(en * sinth * std::cos(phi), en * sinth * std::sin(phi), en * std::cos(theta)); theOne->SetMomentum(tempVector); } else { // tabulation of probabilities. G4int itt(0); for (iii = 0; iii < nNeu[ii - nIso]; ++iii) // find the neutron energy { itt = iii; if (theAngular[ii - nIso][iii].GetEnergy() > anEnergy) break; } G4double costh = theAngular[ii - nIso][itt].GetCosTh(); // no interpolation yet @@ G4double theta = std::acos(costh); G4double phi = twopi * G4UniformRand(); G4double sinth = std::sin(theta); // Bug reported Chao Zhang (Chao.Zhang@usd.edu), Dongming Mei(Dongming.Mei@usd.edu) Feb. 25, // 2009 G4double en = theOne->GetTotalEnergy(); G4double en = theOne->GetTotalMomentum(); // But never cause real effect at least with G4NDL3.13 TK G4ThreeVector tmpVector(en * sinth * std::cos(phi), en * sinth * std::sin(phi), en * costh); theOne->SetMomentum(tmpVector); } } thePhotons->push_back(theOne); } else if (repFlag == 0) { if (thePartialXsec == nullptr) { return thePhotons; } // Partial Case auto theOne = new G4ReactionProduct; theOne->SetDefinition(G4Gamma::Gamma()); thePhotons->push_back(theOne); // Energy G4double sum = 0.0; std::vector dif(nDiscrete, 0.0); for (G4int j = 0; j < nDiscrete; ++j) { G4double x = thePartialXsec[j].GetXsec(anEnergy); // x in barn if (x > 0) { sum += x; } dif[j] = sum; } G4double rand = G4UniformRand(); G4int iphoton = 0; for (G4int j = 0; j < nDiscrete; ++j) { G4double y = rand * sum; if (dif[j] > y) { iphoton = j; break; } } // Statistically suppress the photon according to reaction cross section // Fix proposed by Artem Zontikov, Bug report #1824 if (theReactionXsec != nullptr) { if (thePartialXsec[iphoton].GetXsec(anEnergy) / theReactionXsec->GetXsec(anEnergy) < G4UniformRand()) { delete thePhotons; thePhotons = nullptr; return thePhotons; } } // Angle G4double cosTheta = 0.0; // mu if (isoFlag == 1) { // Isotropic Case cosTheta = 2. * G4UniformRand() - 1; } else { if (iphoton < nIso) { // still Isotropic cosTheta = 2. * G4UniformRand() - 1; } else { if (tabulationType == 1) { // Legendre polynomials G4int iangle = 0; for (G4int j = 0; j < nNeu[iphoton - nIso]; ++j) { iangle = j; if (theLegendre[iphoton - nIso][j].GetEnergy() > anEnergy) break; } G4ParticleHPLegendreStore aStore(2); aStore.SetCoeff(1, &(theLegendre[iphoton - nIso][iangle])); aStore.SetCoeff(0, &(theLegendre[iphoton - nIso][iangle - 1])); cosTheta = aStore.SampleMax(anEnergy); } else if (tabulationType == 2) { // tabulation of probabilities. G4int iangle = 0; for (G4int j = 0; j < nNeu[iphoton - nIso]; ++j) { iangle = j; if (theAngular[iphoton - nIso][j].GetEnergy() > anEnergy) break; } cosTheta = theAngular[iphoton - nIso][iangle].GetCosTh(); // no interpolation yet @@ } } } // Set G4double phi = twopi * G4UniformRand(); G4double theta = std::acos(cosTheta); G4double sinTheta = std::sin(theta); G4double photonE = theGammas[iphoton]; G4ThreeVector direction(sinTheta * std::cos(phi), sinTheta * std::sin(phi), cosTheta); G4ThreeVector photonP = photonE * direction; thePhotons->operator[](0)->SetMomentum(photonP); } else { delete thePhotons; thePhotons = nullptr; // no gamma data available; some work needed @@@@@@@ } return thePhotons; }