Geant4 Cross Reference |
1 // 1 // 2 // ******************************************* 2 // ******************************************************************** 3 // * License and Disclaimer 3 // * License and Disclaimer * 4 // * 4 // * * 5 // * The Geant4 software is copyright of th 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/ 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. 9 // * include a list of copyright holders. * 10 // * 10 // * * 11 // * Neither the authors of this software syst 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing fin 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warran 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assum 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitatio 16 // * for the full disclaimer and the limitation of liability. * 17 // * 17 // * * 18 // * This code implementation is the result 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboratio 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distri 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you ag 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publicati 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Sof 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************* 24 // ******************************************************************** 25 // 25 // 26 // ------------------------------------------- 26 // ------------------------------------------------------------------- 27 // 27 // 28 // GEANT4 Class file 28 // GEANT4 Class file 29 // 29 // 30 // 30 // 31 // File name: G4GammaNuclearXS 31 // File name: G4GammaNuclearXS 32 // 32 // 33 // Authors V.Ivantchenko, Geant4, 20 October << 33 // Author V.Ivantchenko, Geant4, 22 October 2020 34 // B.Kutsenko, BINP/NSU, 10 August 20 << 35 // 34 // 36 // Modifications: 35 // Modifications: 37 // 36 // 38 37 39 #include "G4GammaNuclearXS.hh" 38 #include "G4GammaNuclearXS.hh" >> 39 #include "G4Gamma.hh" 40 #include "G4DynamicParticle.hh" 40 #include "G4DynamicParticle.hh" 41 #include "G4ThreeVector.hh" << 41 #include "G4ProductionCutsTable.hh" 42 #include "G4ElementTable.hh" << 43 #include "G4Material.hh" 42 #include "G4Material.hh" 44 #include "G4Element.hh" 43 #include "G4Element.hh" 45 #include "G4ElementData.hh" << 44 #include "G4PhysicsLogVector.hh" 46 #include "G4PhysicsVector.hh" << 47 #include "G4PhysicsLinearVector.hh" << 48 #include "G4PhysicsFreeVector.hh" << 49 #include "G4CrossSectionDataSetRegistry.hh" 45 #include "G4CrossSectionDataSetRegistry.hh" 50 #include "G4PhotoNuclearCrossSection.hh" 46 #include "G4PhotoNuclearCrossSection.hh" 51 #include "G4HadronicParameters.hh" << 52 #include "Randomize.hh" 47 #include "Randomize.hh" 53 #include "G4SystemOfUnits.hh" 48 #include "G4SystemOfUnits.hh" 54 #include "G4Gamma.hh" << 55 #include "G4IsotopeList.hh" 49 #include "G4IsotopeList.hh" 56 #include "G4AutoLock.hh" << 57 50 58 #include <fstream> 51 #include <fstream> 59 #include <sstream> 52 #include <sstream> 60 #include <vector> << 61 53 62 G4ElementData* G4GammaNuclearXS::data = nullpt << 54 // factory >> 55 #include "G4CrossSectionFactory.hh" >> 56 // >> 57 G4_DECLARE_XS_FACTORY(G4GammaNuclearXS); 63 58 64 G4double G4GammaNuclearXS::coeff[3][3]; << 59 G4PhysicsVector* G4GammaNuclearXS::data[] = {nullptr}; 65 G4double G4GammaNuclearXS::xs150[] = {0.0}; << 60 G4double G4GammaNuclearXS::coeff[] = {0.0}; 66 const G4int G4GammaNuclearXS::freeVectorExcept << 67 4, 6, 7, 8, 27, 39, 45, 65, 67, 69, 73}; << 68 G4String G4GammaNuclearXS::gDataDirectory = "" 61 G4String G4GammaNuclearXS::gDataDirectory = ""; 69 62 70 namespace << 63 #ifdef G4MULTITHREADED 71 { << 64 G4Mutex G4GammaNuclearXS::gNuclearXSMutex = G4MUTEX_INITIALIZER; 72 // Upper limit of the linear transition betw << 65 #endif 73 const G4double eTransitionBound = 150.*CLHEP << 74 // A limit energy to correct CHIPS parameter << 75 const G4double ehigh = 10*CLHEP::GeV; << 76 } << 77 66 78 G4GammaNuclearXS::G4GammaNuclearXS() 67 G4GammaNuclearXS::G4GammaNuclearXS() 79 : G4VCrossSectionDataSet(Default_Name()), ga << 68 : G4VCrossSectionDataSet(Default_Name()), 80 { << 69 ggXsection(nullptr), 81 verboseLevel = 0; << 70 gamma(G4Gamma::Gamma()), 82 if (verboseLevel > 0) { << 71 isMaster(false) 83 G4cout << "G4GammaNuclearXS::G4GammaNuclea << 72 { 84 << MAXZGAMMAXS << G4endl; << 73 // verboseLevel = 0; 85 } << 74 if(verboseLevel > 0){ 86 ggXsection = dynamic_cast<G4PhotoNuclearCros << 75 G4cout << "G4GammaNuclearXS::G4GammaNuclearXS Initialise for Z < " 87 (G4CrossSectionDataSetRegistry::Instance() << 76 << MAXZEL << G4endl; 88 if (ggXsection == nullptr) { << 89 ggXsection = new G4PhotoNuclearCrossSectio << 90 } 77 } >> 78 ggXsection = G4CrossSectionDataSetRegistry::Instance()->GetCrossSectionDataSet("PhotoNuclearXS"); >> 79 if(ggXsection == nullptr) ggXsection = new G4PhotoNuclearCrossSection(); 91 SetForAllAtomsAndEnergies(true); 80 SetForAllAtomsAndEnergies(true); >> 81 } 92 82 93 // full data set is uploaded once << 83 G4GammaNuclearXS::~G4GammaNuclearXS() 94 if (nullptr == data) { << 84 { 95 data = new G4ElementData(MAXZGAMMAXS); << 85 if(isMaster) { 96 data->SetName("gNuclear"); << 86 for(G4int i=0; i<MAXZEL; ++i) { 97 for (G4int Z=1; Z<MAXZGAMMAXS; ++Z) { << 87 delete data[i]; 98 Initialise(Z); << 88 data[i] = nullptr; 99 } 89 } 100 } 90 } 101 } 91 } 102 92 103 void G4GammaNuclearXS::CrossSectionDescription 93 void G4GammaNuclearXS::CrossSectionDescription(std::ostream& outFile) const 104 { 94 { 105 outFile << "G4GammaNuclearXS calculates the 95 outFile << "G4GammaNuclearXS calculates the gamma nuclear\n" 106 << "cross-section for GDR energy reg << 96 << "cross section on nuclei using data from the high precision\n" 107 << "data from the high precision\n" << 97 << "LEND gamma database. The data are simplified and smoothed over\n" 108 << "IAEA photonuclear database (2019 << 98 << "the resonance region in order to reduce CPU time.\n" 109 << "implemented with previous CHIPS photon << 99 << "For high energies Glauber-Gribiv cross section is used.\n"; 110 } 100 } 111 101 112 G4bool 102 G4bool 113 G4GammaNuclearXS::IsElementApplicable(const G4 103 G4GammaNuclearXS::IsElementApplicable(const G4DynamicParticle*, 114 G4int, c 104 G4int, const G4Material*) 115 { 105 { 116 return true; 106 return true; 117 } 107 } 118 108 119 G4bool G4GammaNuclearXS::IsIsoApplicable(const 109 G4bool G4GammaNuclearXS::IsIsoApplicable(const G4DynamicParticle*, 120 G4int 110 G4int, G4int, 121 const 111 const G4Element*, const G4Material*) 122 { 112 { 123 return true; 113 return true; 124 } 114 } 125 115 126 G4double 116 G4double 127 G4GammaNuclearXS::GetElementCrossSection(const 117 G4GammaNuclearXS::GetElementCrossSection(const G4DynamicParticle* aParticle, 128 G4int << 118 G4int ZZ, const G4Material* mat) 129 { 119 { 130 return ElementCrossSection(aParticle->GetKin << 120 G4double xs = 0.0; 131 } << 121 G4double ekin = aParticle->GetKineticEnergy(); 132 122 133 G4double << 123 G4int Z = (ZZ >= MAXZEL) ? MAXZEL - 1 : ZZ; 134 G4GammaNuclearXS::ElementCrossSection(const G4 << 124 135 { << 125 auto pv = GetPhysicsVector(Z); 136 // check cache << 126 if(pv == nullptr) { return xs; } 137 const G4int Z = (ZZ < MAXZGAMMAXS) ? ZZ : MA << 127 // G4cout << "G4GammaNuclearXS::GetCrossSection e= " << ekin 138 if(Z == fZ && ekin == fEkin) { return fXS; } << 128 // << " Z= " << Z << G4endl; 139 fZ = Z; << 129 140 fEkin = ekin; << 130 if(ekin <= pv->GetMaxEnergy()) { 141 << 131 xs = pv->LogVectorValue(ekin, aParticle->GetLogKineticEnergy()); 142 auto pv = data->GetElementData(Z); << 132 } else { 143 const G4double limCHIPS1 = 25*CLHEP::MeV; << 133 xs = coeff[Z]*ggXsection->GetElementCrossSection(aParticle, Z, mat); 144 const G4double limCHIPS2 = 16*CLHEP::MeV; << 145 if (pv == nullptr || 1 == Z || Z == 40 || Z << 146 (Z == 24 && ekin >= limCHIPS1) || << 147 (Z == 39 && ekin >= limCHIPS1) || << 148 (Z == 50 && ekin >= limCHIPS2) || << 149 (Z == 64 && ekin >= limCHIPS2) << 150 ) { << 151 fXS = ggXsection->ComputeElementXSection(e << 152 return fXS; << 153 } << 154 const G4double emax = pv->GetMaxEnergy(); << 155 << 156 // low energy based on data << 157 if(ekin <= emax) { << 158 fXS = pv->Value(ekin); << 159 // high energy CHIPS parameterisation << 160 } else if(ekin >= eTransitionBound) { << 161 fXS = ggXsection->ComputeElementXSection(e << 162 // linear interpolation << 163 } else { << 164 const G4double rxs = xs150[Z]; << 165 const G4double lxs = pv->Value(emax); << 166 fXS = lxs + (ekin - emax)*(rxs - lxs)/(eTr << 167 } 134 } 168 135 169 #ifdef G4VERBOSE 136 #ifdef G4VERBOSE 170 if(verboseLevel > 1) { 137 if(verboseLevel > 1) { 171 G4cout << "Z= " << Z << " Ekin(MeV)= " << 138 G4cout << "Z= " << Z << " Ekin(MeV)= " << ekin/CLHEP::MeV 172 << ", nElmXS(b)= " << fXS/CLHEP::barn << 139 << ", nElmXS(b)= " << xs/CLHEP::barn 173 << G4endl; 140 << G4endl; 174 } 141 } 175 #endif 142 #endif 176 return fXS; << 143 return xs; 177 } << 178 << 179 G4double G4GammaNuclearXS::LowEnergyCrossSecti << 180 { << 181 const G4int Z = (ZZ < MAXZGAMMAXS) ? ZZ : MA << 182 auto pv = data->GetElementData(Z); << 183 return pv->Value(ekin); << 184 } 144 } 185 145 186 G4double G4GammaNuclearXS::GetIsoCrossSection( 146 G4double G4GammaNuclearXS::GetIsoCrossSection( 187 const G4DynamicParticle* aParticle, << 147 const G4DynamicParticle* aParticle, 188 G4int Z, G4int A, 148 G4int Z, G4int A, 189 const G4Isotope*, const G4Element*, const G << 149 const G4Isotope*, const G4Element*, >> 150 const G4Material* mat) 190 { 151 { 191 return IsoCrossSection(aParticle->GetKinetic << 152 return GetElementCrossSection(aParticle, Z, mat) * A/aeff[Z]; 192 } << 193 << 194 G4double << 195 G4GammaNuclearXS::IsoCrossSection(const G4doub << 196 { << 197 const G4int Z = (ZZ < MAXZGAMMAXS) ? ZZ : MA << 198 // cross section per element << 199 G4double xs = ElementCrossSection(ekin, Z); << 200 << 201 if (Z > 2) { << 202 xs *= A/aeff[Z]; << 203 } else { << 204 G4int AA = A - amin[Z]; << 205 if(ekin >= ehigh && AA >=0 && AA <=2) { << 206 xs *= coeff[Z][AA]; << 207 } else { << 208 xs = ggXsection->ComputeIsoXSection(ekin << 209 } << 210 } << 211 << 212 #ifdef G4VERBOSE << 213 if(verboseLevel > 1) { << 214 G4cout << "G4GammaNuclearXS::IsoXS: Z= " << 215 << " Ekin(MeV)= " << ekin/CLHEP::MeV << 216 << ", ElmXS(b)= " << xs/CLHEP::barn << G << 217 } << 218 #endif << 219 return xs; << 220 } 153 } 221 154 222 const G4Isotope* G4GammaNuclearXS::SelectIsoto 155 const G4Isotope* G4GammaNuclearXS::SelectIsotope( 223 const G4Element* anElement, G4double ki << 156 const G4Element* anElement, G4double, G4double) 224 { 157 { 225 std::size_t nIso = anElement->GetNumberOfIso << 158 size_t nIso = anElement->GetNumberOfIsotopes(); 226 const G4Isotope* iso = anElement->GetIsotope 159 const G4Isotope* iso = anElement->GetIsotope(0); 227 160 >> 161 //G4cout << "SelectIsotope NIso= " << nIso << G4endl; 228 if(1 == nIso) { return iso; } 162 if(1 == nIso) { return iso; } 229 163 230 const G4double* abundVector = anElement->Get 164 const G4double* abundVector = anElement->GetRelativeAbundanceVector(); >> 165 G4double q = G4UniformRand(); 231 G4double sum = 0.0; 166 G4double sum = 0.0; 232 G4int Z = anElement->GetZasInt(); << 167 size_t j; 233 168 234 // use isotope cross sections << 169 // isotope wise cross section not used 235 std::size_t nn = temp.size(); << 170 for (j=0; j<nIso; ++j) { 236 if(nn < nIso) { temp.resize(nIso, 0.); } << 171 sum += abundVector[j]; 237 << 172 if(q <= sum) { 238 for (std::size_t j=0; j<nIso; ++j) { << 173 iso = anElement->GetIsotope(j); 239 //G4cout << j << "-th isotope " << (*isoVe << 240 // << " abund= " << abundVector[j] << 241 sum += abundVector[j]* << 242 IsoCrossSection(kinEnergy, Z, anElement- << 243 temp[j] = sum; << 244 } << 245 sum *= G4UniformRand(); << 246 for (std::size_t j = 0; j<nIso; ++j) { << 247 if(temp[j] >= sum) { << 248 iso = anElement->GetIsotope((G4int)j); << 249 break; 174 break; 250 } 175 } 251 } 176 } 252 return iso; 177 return iso; 253 } 178 } 254 179 255 void G4GammaNuclearXS::BuildPhysicsTable(const << 180 void >> 181 G4GammaNuclearXS::BuildPhysicsTable(const G4ParticleDefinition& p) 256 { 182 { 257 if(verboseLevel > 1) { << 183 if(verboseLevel > 0){ 258 G4cout << "G4GammaNuclearXS::BuildPhysicsT 184 G4cout << "G4GammaNuclearXS::BuildPhysicsTable for " 259 << p.GetParticleName() << G4endl; 185 << p.GetParticleName() << G4endl; 260 } 186 } 261 if(p.GetParticleName() != "gamma") { 187 if(p.GetParticleName() != "gamma") { 262 G4ExceptionDescription ed; 188 G4ExceptionDescription ed; 263 ed << p.GetParticleName() << " is a wrong 189 ed << p.GetParticleName() << " is a wrong particle type -" 264 << " only gamma is allowed"; 190 << " only gamma is allowed"; 265 G4Exception("G4GammaNuclearXS::BuildPhysic 191 G4Exception("G4GammaNuclearXS::BuildPhysicsTable(..)","had012", 266 FatalException, ed, ""); 192 FatalException, ed, ""); 267 return; 193 return; 268 } 194 } >> 195 if(0. == coeff[0]) { >> 196 #ifdef G4MULTITHREADED >> 197 G4MUTEXLOCK(&gNuclearXSMutex); >> 198 if(0. == coeff[0]) { >> 199 #endif >> 200 coeff[0] = 1.0; >> 201 isMaster = true; >> 202 FindDirectoryPath(); >> 203 #ifdef G4MULTITHREADED >> 204 } >> 205 G4MUTEXUNLOCK(&gNuclearXSMutex); >> 206 #endif >> 207 } 269 208 270 // prepare isotope selection << 209 // it is possible re-initialisation for the second run 271 const G4ElementTable* table = G4Element::Get << 210 if(isMaster) { 272 std::size_t nIso = temp.size(); << 211 273 for (auto const & elm : *table ) { << 212 // Access to elements 274 std::size_t n = elm->GetNumberOfIsotopes() << 213 auto theCoupleTable = G4ProductionCutsTable::GetProductionCutsTable(); 275 if (n > nIso) { nIso = n; } << 214 size_t numOfCouples = theCoupleTable->GetTableSize(); >> 215 for(size_t j=0; j<numOfCouples; ++j) { >> 216 auto mat = theCoupleTable->GetMaterialCutsCouple(j)->GetMaterial(); >> 217 auto elmVec = mat->GetElementVector(); >> 218 size_t numOfElem = mat->GetNumberOfElements(); >> 219 for (size_t ie = 0; ie < numOfElem; ++ie) { >> 220 G4int Z = std::max(1,std::min(((*elmVec)[ie])->GetZasInt(), MAXZEL-1)); >> 221 if(data[Z] == nullptr) { Initialise(Z); } >> 222 } >> 223 } 276 } 224 } 277 temp.resize(nIso, 0.0); << 278 } 225 } 279 226 280 const G4String& G4GammaNuclearXS::FindDirector 227 const G4String& G4GammaNuclearXS::FindDirectoryPath() 281 { 228 { >> 229 // check environment variable 282 // build the complete string identifying the 230 // build the complete string identifying the file with the data set 283 if(gDataDirectory.empty()) { 231 if(gDataDirectory.empty()) { 284 std::ostringstream ost; << 232 char* path = std::getenv("G4PARTICLEXSDATA"); 285 ost << G4HadronicParameters::Instance()->G << 233 if (path) { 286 gDataDirectory = ost.str(); << 234 std::ostringstream ost; >> 235 ost << path << "/gamma/inel"; >> 236 gDataDirectory = ost.str(); >> 237 } else { >> 238 G4Exception("G4GammaNuclearXS::Initialise(..)","had013", >> 239 FatalException, >> 240 "Environment variable G4PARTICLEXSDATA is not defined"); >> 241 } 287 } 242 } 288 return gDataDirectory; 243 return gDataDirectory; 289 } 244 } 290 245 291 void G4GammaNuclearXS::Initialise(G4int Z) << 246 void G4GammaNuclearXS::InitialiseOnFly(G4int Z) 292 { 247 { 293 // upload data from file << 248 #ifdef G4MULTITHREADED 294 std::ostringstream ost; << 249 G4MUTEXLOCK(&gNuclearXSMutex); 295 ost << FindDirectoryPath() << Z ; << 250 if(data[Z] == nullptr) { 296 G4PhysicsVector* v = RetrieveVector(ost, tru << 251 #endif 297 << 252 Initialise(Z); 298 data->InitialiseForElement(Z, v); << 253 #ifdef G4MULTITHREADED 299 /* << 254 } 300 G4cout << "G4GammaNuclearXS::Initialise for << 255 G4MUTEXUNLOCK(&gNuclearXSMutex); 301 << " A= " << Amean << " Amin= " << amin[Z] << 256 #endif 302 << " Amax= " << amax[Z] << G4endl; << 303 */ << 304 xs150[Z] = ggXsection->ComputeElementXSectio << 305 << 306 // compute corrections for low Z data << 307 if(Z <= 2){ << 308 if(amax[Z] > amin[Z]) { << 309 for(G4int A=amin[Z]; A<=amax[Z]; ++A) { << 310 G4int AA = A - amin[Z]; << 311 if(AA >= 0 && AA <= 2) { << 312 G4double sig1 = ggXsection->ComputeIsoXSec << 313 G4double sig2 = ggXsection->ComputeElement << 314 if(sig2 > 0.) { coeff[Z][AA] = (sig1/sig2) << 315 else { coeff[Z][AA] = 1.; } << 316 } << 317 } << 318 } << 319 } << 320 } 257 } 321 258 322 G4PhysicsVector* << 259 void G4GammaNuclearXS::Initialise(G4int Z) 323 G4GammaNuclearXS::RetrieveVector(std::ostrings << 324 { 260 { 325 G4PhysicsVector* v = nullptr; << 261 if(data[Z] != nullptr) { return; } >> 262 >> 263 // upload data from file >> 264 data[Z] = new G4PhysicsLogVector(); 326 265 >> 266 std::ostringstream ost; >> 267 ost << FindDirectoryPath() << Z ; 327 std::ifstream filein(ost.str().c_str()); 268 std::ifstream filein(ost.str().c_str()); 328 if (!filein.is_open()) { << 269 if (!(filein)) { 329 if(warn) { << 270 G4ExceptionDescription ed; 330 G4ExceptionDescription ed; << 271 ed << "Data file <" << ost.str().c_str() 331 ed << "Data file <" << ost.str().c_str() << 272 << "> is not opened!"; 332 << "> is not opened!"; << 273 G4Exception("G4GammaNuclearXS::Initialise(..)","had014", 333 G4Exception("G4GammaNuclearXS::RetrieveV << 274 FatalException, ed, "Check G4PARTICLEXSDATA"); 334 FatalException, ed, "Check G4PARTICLEXSD << 275 return; 335 } << 336 } else { << 337 if(verboseLevel > 1) { << 338 G4cout << "File " << ost.str() << 339 << " is opened by G4GammaNuclearXS" << << 340 } << 341 // retrieve data from DB << 342 if(std::find(std::begin(freeVectorExceptio << 343 == std::end(freeVectorException)) { << 344 v = new G4PhysicsLinearVector(false); << 345 } else { << 346 v = new G4PhysicsFreeVector(false); << 347 } << 348 if(!v->Retrieve(filein, true)) { << 349 G4ExceptionDescription ed; << 350 ed << "Data file <" << ost.str().c_str() << 351 << "> is not retrieved!"; << 352 G4Exception("G4GammaNuclearXS::RetrieveV << 353 FatalException, ed, "Check G4PARTICLEXSD << 354 } << 355 } 276 } 356 return v; << 277 if(verboseLevel > 1) { >> 278 G4cout << "file " << ost.str() >> 279 << " is opened by G4GammaNuclearXS" << G4endl; >> 280 } >> 281 >> 282 // retrieve data from DB >> 283 if(!data[Z]->Retrieve(filein, true)) { >> 284 G4ExceptionDescription ed; >> 285 ed << "Data file <" << ost.str().c_str() >> 286 << "> is not retrieved!"; >> 287 G4Exception("G4GammaNuclearXS::Initialise(..)","had015", >> 288 FatalException, ed, "Check G4PARTICLEXSDATA"); >> 289 return; >> 290 } >> 291 // smooth transition >> 292 G4Material* mat(nullptr); >> 293 G4ThreeVector mom(0.0,0.0,1.0); >> 294 G4DynamicParticle dp(gamma, mom, data[Z]->GetMaxEnergy()); >> 295 G4double sig1 = (*(data[Z]))[data[Z]->GetVectorLength()-1]; >> 296 G4double sig2 = ggXsection->GetElementCrossSection(&dp, Z, mat); >> 297 coeff[Z] = (sig2 > 0.) ? sig1/sig2 : 1.0; 357 } 298 } 358 << 359 299