Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/materials/src/G4MaterialPropertiesTable.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  1 //
  2 // ********************************************************************
  3 // * License and Disclaimer                                           *
  4 // *                                                                  *
  5 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
  6 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
  7 // * conditions of the Geant4 Software License,  included in the file *
  8 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
  9 // * include a list of copyright holders.                             *
 10 // *                                                                  *
 11 // * Neither the authors of this software system, nor their employing *
 12 // * institutes,nor the agencies providing financial support for this *
 13 // * work  make  any representation or  warranty, express or implied, *
 14 // * regarding  this  software system or assume any liability for its *
 15 // * use.  Please see the license in the file  LICENSE  and URL above *
 16 // * for the full disclaimer and the limitation of liability.         *
 17 // *                                                                  *
 18 // * This  code  implementation is the result of  the  scientific and *
 19 // * technical work of the GEANT4 collaboration.                      *
 20 // * By using,  copying,  modifying or  distributing the software (or *
 21 // * any work based  on the software)  you  agree  to acknowledge its *
 22 // * use  in  resulting  scientific  publications,  and indicate your *
 23 // * acceptance of all terms of the Geant4 Software license.          *
 24 // ********************************************************************
 25 
 26 ////////////////////////////////////////////////////////////////////////
 27 // G4MaterialPropertiesTable Implementation
 28 ////////////////////////////////////////////////////////////////////////
 29 //
 30 // File: G4MaterialPropertiesTable.cc
 31 // Version:     1.0
 32 // Created:     1996-02-08
 33 // Author:      Juliet Armstrong
 34 // Updated:     2005-05-12 add SetGROUPVEL(), courtesy of
 35 //              Horton-Smith (bug report #741), by P. Gumplinger
 36 //              2002-11-05 add named material constants by P. Gumplinger
 37 //              1999-11-05 Migration from G4RWTPtrHashDictionary to STL
 38 //                         by John Allison
 39 //              1997-03-26 by Peter Gumplinger
 40 //              > cosmetics (only)
 41 //
 42 ////////////////////////////////////////////////////////////////////////
 43 
 44 #include "G4MaterialPropertiesTable.hh"
 45 
 46 #include "G4Log.hh"
 47 #include "G4OpticalMaterialProperties.hh"
 48 #include "G4PhysicalConstants.hh"
 49 #include "globals.hh"
 50 
 51 #include <algorithm>
 52 #include <cassert>
 53 
 54 #ifdef G4MULTITHREADED
 55 #  include "G4AutoLock.hh"
 56 namespace
 57 {
 58 G4Mutex materialPropertyTableMutex = G4MUTEX_INITIALIZER;
 59 }
 60 #endif
 61 
 62 G4MaterialPropertiesTable::G4MaterialPropertiesTable()
 63 {
 64   // elements of these 2 vectors must be in same order as
 65   // the corresponding enums in G4MaterialPropertiesIndex.hh
 66   fMatPropNames.assign(kNumberOfPropertyIndex, "");
 67   fMatPropNames[kRINDEX] =                    "RINDEX";
 68   fMatPropNames[kREFLECTIVITY] =              "REFLECTIVITY";
 69   fMatPropNames[kREALRINDEX] =                "REALRINDEX";
 70   fMatPropNames[kIMAGINARYRINDEX] =           "IMAGINARYRINDEX";
 71   fMatPropNames[kEFFICIENCY] =                "EFFICIENCY";
 72   fMatPropNames[kTRANSMITTANCE] =             "TRANSMITTANCE";
 73   fMatPropNames[kSPECULARLOBECONSTANT] =      "SPECULARLOBECONSTANT";
 74   fMatPropNames[kSPECULARSPIKECONSTANT] =     "SPECULARSPIKECONSTANT";
 75   fMatPropNames[kBACKSCATTERCONSTANT] =       "BACKSCATTERCONSTANT";
 76   fMatPropNames[kGROUPVEL] =                  "GROUPVEL";
 77   fMatPropNames[kMIEHG] =                     "MIEHG";
 78   fMatPropNames[kRAYLEIGH] =                  "RAYLEIGH";
 79   fMatPropNames[kWLSCOMPONENT] =              "WLSCOMPONENT";
 80   fMatPropNames[kWLSABSLENGTH] =              "WLSABSLENGTH";
 81   fMatPropNames[kWLSCOMPONENT2] =             "WLSCOMPONENT2";
 82   fMatPropNames[kWLSABSLENGTH2] =             "WLSABSLENGTH2";
 83   fMatPropNames[kABSLENGTH] =                 "ABSLENGTH";
 84   fMatPropNames[kPROTONSCINTILLATIONYIELD] =  "PROTONSCINTILLATIONYIELD";
 85   fMatPropNames[kDEUTERONSCINTILLATIONYIELD] ="DEUTERONSCINTILLATIONYIELD";
 86   fMatPropNames[kTRITONSCINTILLATIONYIELD] =  "TRITONSCINTILLATIONYIELD";
 87   fMatPropNames[kALPHASCINTILLATIONYIELD] =   "ALPHASCINTILLATIONYIELD";
 88   fMatPropNames[kIONSCINTILLATIONYIELD] =     "IONSCINTILLATIONYIELD";
 89   fMatPropNames[kELECTRONSCINTILLATIONYIELD] ="ELECTRONSCINTILLATIONYIELD";
 90   fMatPropNames[kSCINTILLATIONCOMPONENT1] =   "SCINTILLATIONCOMPONENT1";
 91   fMatPropNames[kSCINTILLATIONCOMPONENT2] =   "SCINTILLATIONCOMPONENT2";
 92   fMatPropNames[kSCINTILLATIONCOMPONENT3] =   "SCINTILLATIONCOMPONENT3";
 93   fMatPropNames[kCOATEDRINDEX] =              "COATEDRINDEX";
 94 
 95   fMP.assign(kNumberOfPropertyIndex, nullptr);
 96 
 97   fMatConstPropNames.assign(kNumberOfConstPropertyIndex, "");
 98   fMatConstPropNames[kSURFACEROUGHNESS] =             "SURFACEROUGHNESS";
 99   fMatConstPropNames[kISOTHERMAL_COMPRESSIBILITY] =   "ISOTHERMAL_COMPRESSIBILITY";
100   fMatConstPropNames[kRS_SCALE_FACTOR] =              "RS_SCALE_FACTOR";
101   fMatConstPropNames[kWLSMEANNUMBERPHOTONS] =         "WLSMEANNUMBERPHOTONS";
102   fMatConstPropNames[kWLSTIMECONSTANT] =              "WLSTIMECONSTANT";
103   fMatConstPropNames[kWLSMEANNUMBERPHOTONS2] =        "WLSMEANNUMBERPHOTONS2";
104   fMatConstPropNames[kWLSTIMECONSTANT2] =             "WLSTIMECONSTANT2";
105   fMatConstPropNames[kMIEHG_FORWARD] =                "MIEHG_FORWARD";
106   fMatConstPropNames[kMIEHG_BACKWARD] =               "MIEHG_BACKWARD";
107   fMatConstPropNames[kMIEHG_FORWARD_RATIO] =          "MIEHG_FORWARD_RATIO";
108   fMatConstPropNames[kSCINTILLATIONYIELD] =           "SCINTILLATIONYIELD";
109   fMatConstPropNames[kRESOLUTIONSCALE] =              "RESOLUTIONSCALE";
110   fMatConstPropNames[kFERMIPOT] =                     "FERMIPOT";
111   fMatConstPropNames[kDIFFUSION] =                    "DIFFUSION";
112   fMatConstPropNames[kSPINFLIP] =                     "SPINFLIP";
113   fMatConstPropNames[kLOSS] =                         "LOSS";
114   fMatConstPropNames[kLOSSCS] =                       "LOSSCS";
115   fMatConstPropNames[kABSCS] =                        "ABSCS";
116   fMatConstPropNames[kSCATCS] =                       "SCATCS";
117   fMatConstPropNames[kMR_NBTHETA] =                   "MR_NBTHETA";
118   fMatConstPropNames[kMR_NBE] =                       "MR_NBE";
119   fMatConstPropNames[kMR_RRMS] =                      "MR_RRMS";
120   fMatConstPropNames[kMR_CORRLEN] =                   "MR_CORRLEN";
121   fMatConstPropNames[kMR_THETAMIN] =                  "MR_THETAMIN";
122   fMatConstPropNames[kMR_THETAMAX] =                  "MR_THETAMAX";
123   fMatConstPropNames[kMR_EMIN] =                      "MR_EMIN";
124   fMatConstPropNames[kMR_EMAX] =                      "MR_EMAX";
125   fMatConstPropNames[kMR_ANGNOTHETA] =                "MR_ANGNOTHETA";
126   fMatConstPropNames[kMR_ANGNOPHI] =                  "MR_ANGNOPHI";
127   fMatConstPropNames[kMR_ANGCUT] =                    "MR_ANGCUT";
128   fMatConstPropNames[kSCINTILLATIONTIMECONSTANT1] =   "SCINTILLATIONTIMECONSTANT1";
129   fMatConstPropNames[kSCINTILLATIONTIMECONSTANT2] =   "SCINTILLATIONTIMECONSTANT2";
130   fMatConstPropNames[kSCINTILLATIONTIMECONSTANT3] =   "SCINTILLATIONTIMECONSTANT3";
131   fMatConstPropNames[kSCINTILLATIONRISETIME1] =       "SCINTILLATIONRISETIME1";
132   fMatConstPropNames[kSCINTILLATIONRISETIME2] =       "SCINTILLATIONRISETIME2";
133   fMatConstPropNames[kSCINTILLATIONRISETIME3] =       "SCINTILLATIONRISETIME3";
134   fMatConstPropNames[kSCINTILLATIONYIELD1] =          "SCINTILLATIONYIELD1";
135   fMatConstPropNames[kSCINTILLATIONYIELD2] =          "SCINTILLATIONYIELD2";
136   fMatConstPropNames[kSCINTILLATIONYIELD3] =          "SCINTILLATIONYIELD3";
137   fMatConstPropNames[kPROTONSCINTILLATIONYIELD1] =    "PROTONSCINTILLATIONYIELD1";
138   fMatConstPropNames[kPROTONSCINTILLATIONYIELD2] =    "PROTONSCINTILLATIONYIELD2";
139   fMatConstPropNames[kPROTONSCINTILLATIONYIELD3] =    "PROTONSCINTILLATIONYIELD3";
140   fMatConstPropNames[kDEUTERONSCINTILLATIONYIELD1] =  "DEUTERONSCINTILLATIONYIELD1";
141   fMatConstPropNames[kDEUTERONSCINTILLATIONYIELD2] =  "DEUTERONSCINTILLATIONYIELD2";
142   fMatConstPropNames[kDEUTERONSCINTILLATIONYIELD3] =  "DEUTERONSCINTILLATIONYIELD3";
143   fMatConstPropNames[kTRITONSCINTILLATIONYIELD1] =    "TRITONSCINTILLATIONYIELD1";
144   fMatConstPropNames[kTRITONSCINTILLATIONYIELD2] =    "TRITONSCINTILLATIONYIELD2";
145   fMatConstPropNames[kTRITONSCINTILLATIONYIELD3] =    "TRITONSCINTILLATIONYIELD3";
146   fMatConstPropNames[kALPHASCINTILLATIONYIELD1] =     "ALPHASCINTILLATIONYIELD1";
147   fMatConstPropNames[kALPHASCINTILLATIONYIELD2] =     "ALPHASCINTILLATIONYIELD2";
148   fMatConstPropNames[kALPHASCINTILLATIONYIELD3] =     "ALPHASCINTILLATIONYIELD3";
149   fMatConstPropNames[kIONSCINTILLATIONYIELD1] =       "IONSCINTILLATIONYIELD1";
150   fMatConstPropNames[kIONSCINTILLATIONYIELD2] =       "IONSCINTILLATIONYIELD2";
151   fMatConstPropNames[kIONSCINTILLATIONYIELD3] =       "IONSCINTILLATIONYIELD3";
152   fMatConstPropNames[kELECTRONSCINTILLATIONYIELD1] =  "ELECTRONSCINTILLATIONYIELD1";
153   fMatConstPropNames[kELECTRONSCINTILLATIONYIELD2] =  "ELECTRONSCINTILLATIONYIELD2";
154   fMatConstPropNames[kELECTRONSCINTILLATIONYIELD3] =  "ELECTRONSCINTILLATIONYIELD3";
155   fMatConstPropNames[kCOATEDTHICKNESS] =              "COATEDTHICKNESS";
156   fMatConstPropNames[kCOATEDFRUSTRATEDTRANSMISSION] = "COATEDFRUSTRATEDTRANSMISSION";
157   fMatConstPropNames[kPROTONSCINTILLATIONTIMECONSTANT1] =   "PROTONSCINTILLATIONTIMECONSTANT1";
158   fMatConstPropNames[kPROTONSCINTILLATIONTIMECONSTANT2] =   "PROTONSCINTILLATIONTIMECONSTANT2";
159   fMatConstPropNames[kPROTONSCINTILLATIONTIMECONSTANT3] =   "PROTONSCINTILLATIONTIMECONSTANT3";
160   fMatConstPropNames[kDEUTERONSCINTILLATIONTIMECONSTANT1] = "DEUTERONSCINTILLATIONTIMECONSTANT1";
161   fMatConstPropNames[kDEUTERONSCINTILLATIONTIMECONSTANT2] = "DEUTERONSCINTILLATIONTIMECONSTANT2";
162   fMatConstPropNames[kDEUTERONSCINTILLATIONTIMECONSTANT3] = "DEUTERONSCINTILLATIONTIMECONSTANT3";
163   fMatConstPropNames[kTRITONSCINTILLATIONTIMECONSTANT1] =   "TRITONSCINTILLATIONTIMECONSTANT1";
164   fMatConstPropNames[kTRITONSCINTILLATIONTIMECONSTANT2] =   "TRITONSCINTILLATIONTIMECONSTANT2";
165   fMatConstPropNames[kTRITONSCINTILLATIONTIMECONSTANT3] =   "TRITONSCINTILLATIONTIMECONSTANT3";
166   fMatConstPropNames[kALPHASCINTILLATIONTIMECONSTANT1] =    "ALPHASCINTILLATIONTIMECONSTANT1";
167   fMatConstPropNames[kALPHASCINTILLATIONTIMECONSTANT2] =    "ALPHASCINTILLATIONTIMECONSTANT2";
168   fMatConstPropNames[kALPHASCINTILLATIONTIMECONSTANT3] =    "ALPHASCINTILLATIONTIMECONSTANT3";
169   fMatConstPropNames[kIONSCINTILLATIONTIMECONSTANT1] =      "IONSCINTILLATIONTIMECONSTANT1";
170   fMatConstPropNames[kIONSCINTILLATIONTIMECONSTANT2] =      "IONSCINTILLATIONTIMECONSTANT2";
171   fMatConstPropNames[kIONSCINTILLATIONTIMECONSTANT3] =      "IONSCINTILLATIONTIMECONSTANT3";
172   fMatConstPropNames[kELECTRONSCINTILLATIONTIMECONSTANT1] = "ELECTRONSCINTILLATIONTIMECONSTANT1";
173   fMatConstPropNames[kELECTRONSCINTILLATIONTIMECONSTANT2] = "ELECTRONSCINTILLATIONTIMECONSTANT2";
174   fMatConstPropNames[kELECTRONSCINTILLATIONTIMECONSTANT3] = "ELECTRONSCINTILLATIONTIMECONSTANT3";
175   fMCP.assign(kNumberOfConstPropertyIndex, {0., false});
176 }
177 
178 G4MaterialPropertiesTable::~G4MaterialPropertiesTable()
179 {
180   for (auto prop : fMP) {
181     delete (prop);
182   }
183 }
184 
185 G4int G4MaterialPropertiesTable::GetConstPropertyIndex(const G4String& key) const
186 {
187   // Returns the constant material property index corresponding to a key
188 
189   std::size_t index = std::distance(fMatConstPropNames.cbegin(),
190     std::find(fMatConstPropNames.cbegin(), fMatConstPropNames.cend(), key));
191   if (index < fMatConstPropNames.size()) {
192     return (G4int)index;
193   }
194 
195   G4ExceptionDescription ed;
196   ed << "Constant Material Property Index for key " << key << " not found.";
197   G4Exception("G4MaterialPropertiesTable::GetConstPropertyIndex()", "mat200", FatalException, ed);
198   return 0;
199 }
200 
201 G4int G4MaterialPropertiesTable::GetPropertyIndex(const G4String& key) const
202 {
203   // Returns the material property index corresponding to a key
204   std::size_t index = std::distance(
205     fMatPropNames.cbegin(), std::find(fMatPropNames.cbegin(), fMatPropNames.cend(), key));
206   if (index < fMatPropNames.size()) {
207     return (G4int)index;
208   }
209   G4ExceptionDescription ed;
210   ed << "Material Property Index for key " << key << " not found.";
211   G4Exception("G4MaterialPropertiesTable::GetPropertyIndex()", "mat201", FatalException, ed);
212   return 0;
213 }
214 
215 G4double G4MaterialPropertiesTable::GetConstProperty(const G4int index) const
216 {
217   // Returns the constant material property corresponding to an index
218   // fatal exception if property not found
219 
220   if (index < (G4int)fMCP.size() && fMCP[index].second) {
221     return fMCP[index].first;
222   }
223   G4ExceptionDescription ed;
224   ed << "Constant Material Property " << fMatConstPropNames[index] << " not found.";
225   G4Exception("G4MaterialPropertiesTable::GetConstProperty()", "mat202", FatalException, ed);
226   return 0.;
227 }
228 
229 G4double G4MaterialPropertiesTable::GetConstProperty(const G4String& key) const
230 {
231   // Returns the constant material property corresponding to a key
232   // fatal exception if property not found
233 
234   return GetConstProperty(GetConstPropertyIndex(key));
235 }
236 
237 G4double G4MaterialPropertiesTable::GetConstProperty(const char* key) const
238 {
239   return GetConstProperty(GetConstPropertyIndex(G4String(key)));
240 }
241 
242 G4bool G4MaterialPropertiesTable::ConstPropertyExists(const G4int index) const
243 {
244   // Returns true if a const property corresponding to 'index' exists
245 
246   return index >= 0 && index < (G4int)fMCP.size() && fMCP[index].second;
247 }
248 
249 G4bool G4MaterialPropertiesTable::ConstPropertyExists(const G4String& key) const
250 {
251   // Returns true if a const property 'key' exists
252   std::size_t index = std::distance(fMatConstPropNames.cbegin(),
253     std::find(fMatConstPropNames.cbegin(), fMatConstPropNames.cend(), key));
254   if (index < fMatConstPropNames.size()) {  // index is type std::size_t so >= 0
255     return ConstPropertyExists((G4int)index);
256   }
257   return false;
258 }
259 
260 G4bool G4MaterialPropertiesTable::ConstPropertyExists(const char* key) const
261 {
262   std::size_t index = std::distance(fMatConstPropNames.cbegin(),
263     std::find(fMatConstPropNames.cbegin(), fMatConstPropNames.cend(), key));
264   if (index < fMatConstPropNames.size()) {  // index is type std::size_t so >= 0
265     return ConstPropertyExists((G4int)index);
266   }
267   return false;
268 }
269 
270 G4MaterialPropertyVector* G4MaterialPropertiesTable::GetProperty(const G4String& key) const
271 {
272   // Returns a Material Property Vector corresponding to a key
273   if (std::find(fMatPropNames.cbegin(), fMatPropNames.cend(), key) != fMatPropNames.cend()) {
274     const G4int index = GetPropertyIndex(G4String(key));
275     return GetProperty(index);
276   }
277   return nullptr;
278 }
279 
280 G4MaterialPropertyVector* G4MaterialPropertiesTable::GetProperty(const char* key) const
281 {
282   if (std::find(fMatPropNames.cbegin(), fMatPropNames.cend(), key) != fMatPropNames.cend()) {
283     const G4int index = GetPropertyIndex(G4String(key));
284     return GetProperty(index);
285   }
286   return nullptr;
287 }
288 
289 G4MaterialPropertyVector* G4MaterialPropertiesTable::GetProperty(const G4int index) const
290 {
291   // Returns a Material Property Vector corresponding to an index
292   // returns nullptr if the property has not been defined by user
293   if (index >= 0 && index < (G4int)fMP.size()) {
294     return fMP[index];
295   }
296   return nullptr;
297 }
298 
299 G4MaterialPropertyVector* G4MaterialPropertiesTable::AddProperty(const G4String& key,
300   const std::vector<G4double>& photonEnergies, const std::vector<G4double>& propertyValues,
301   G4bool createNewKey, G4bool spline)
302 {
303   if (photonEnergies.size() != propertyValues.size()) {
304     G4ExceptionDescription ed;
305     ed << "AddProperty error. Number of property values must be equal to the number of\n"
306        << "energy values. Property name: " << key;
307     G4Exception("G4MaterialPropertiesTable::AddProperty()", "mat204", FatalException, ed);
308   }
309 
310   if (photonEnergies.size() == 1) {
311     G4ExceptionDescription ed;
312     ed << "AddProperty warning. A material property vector must have more than one value.\n"
313        << "Unless you will later add an entry, this is an error.\n"
314        << "Property name: " << key;
315     G4Exception("G4MaterialPropertiesTable::AddProperty()", "mat218", JustWarning, ed);
316   }
317 
318   // G4PhysicsVector assumes energies are in increasing order
319   for (std::size_t i = 0; i < photonEnergies.size() - 1; ++i) {
320     if (photonEnergies.at(i + 1) < photonEnergies.at(i)) {
321       G4ExceptionDescription ed;
322       ed << "Energies in material property vector must be in increasing "
323          << "order. Key: " << key << " Energy: " << photonEnergies.at(i + 1);
324       G4Exception("G4MaterialPropertiesTable::AddProperty()", "mat215", FatalException, ed);
325     }
326   }
327 
328   // if the key doesn't exist, add it if requested
329   if (std::find(fMatPropNames.cbegin(), fMatPropNames.cend(), key) == fMatPropNames.cend()) {
330     if (createNewKey) {
331       fMatPropNames.push_back(key);
332       fMP.push_back(nullptr);
333     }
334     else {
335       G4ExceptionDescription ed;
336       ed << "Attempting to create a new material property vector " << key << " without setting\n"
337          << "createNewKey parameter of AddProperty to true.";
338       G4Exception("G4MaterialPropertiesTable::AddProperty()", "mat205", FatalException, ed);
339     }
340   }
341 
342   auto* mpv = new G4MaterialPropertyVector(photonEnergies, propertyValues, spline);
343   mpv->SetVerboseLevel(1);
344   if (spline) {
345     mpv->FillSecondDerivatives();
346   }
347   G4int index = GetPropertyIndex(key);
348   fMP[index] = mpv;
349 
350   // if key is RINDEX, we calculate GROUPVEL -
351   // contribution from Tao Lin (IHEP, the JUNO experiment)
352   if (key == "RINDEX") {
353     CalculateGROUPVEL();
354   }
355 
356   return mpv;
357 }
358 
359 G4MaterialPropertyVector* G4MaterialPropertiesTable::AddProperty(const char* key,
360   G4double* photonEnergies, G4double* propertyValues, G4int numEntries, G4bool createNewKey,
361   G4bool spline)
362 {
363   // Provides a way of adding a property to the Material Properties
364   // Table given a pair of arrays and a key
365   G4String k(key);
366 
367   std::vector<G4double> energies(photonEnergies, photonEnergies + numEntries);
368   std::vector<G4double> values(propertyValues, propertyValues + numEntries);
369   return AddProperty(k, energies, values, createNewKey, spline);
370 }
371 
372 void G4MaterialPropertiesTable::AddProperty(
373   const G4String& key, G4MaterialPropertyVector* mpv, G4bool createNewKey)
374 {
375   //  Provides a way of adding a property to the Material Properties
376   //  Table given an G4MaterialPropertyVector Reference and a key
377 
378   // G4PhysicsVector assumes energies are in increasing order
379   if (mpv->GetVectorLength() > 1) {
380     for (std::size_t i = 0; i < mpv->GetVectorLength() - 1; ++i) {
381       if (mpv->Energy(i + 1) < mpv->Energy(i)) {
382         G4ExceptionDescription ed;
383         ed << "Energies in material property vector must be in increasing "
384            << "order. Key: " << key << " Energy: " << mpv->Energy(i + 1);
385         G4Exception("G4MaterialPropertiesTable::AddProperty()", "mat216", FatalException, ed);
386       }
387     }
388   }
389 
390   if (mpv->GetVectorLength() <= 1) {
391     G4ExceptionDescription ed;
392     ed << "AddProperty warning. A material property vector must have more than one value.\n"
393        << "Unless you will later add an entry, this is an error.\n"
394        << "Property name: " << key;
395     G4Exception("G4MaterialPropertiesTable::AddProperty()", "mat219", JustWarning, ed);
396   }
397 
398   // if the key doesn't exist, add it
399   if (std::find(fMatPropNames.cbegin(), fMatPropNames.cend(), key) == fMatPropNames.cend()) {
400     if (createNewKey) {
401       fMatPropNames.push_back(key);
402       fMP.push_back(nullptr);
403     }
404     else {
405       G4ExceptionDescription ed;
406       ed << "Attempting to create a new material property key " << key << " without setting\n"
407          << "createNewKey parameter of AddProperty to true.";
408       G4Exception("G4MaterialPropertiesTable::AddProperty()", "mat206", FatalException, ed);
409     }
410   }
411   G4int index = GetPropertyIndex(key);
412   fMP[index] = mpv;
413 
414   // if key is RINDEX, we calculate GROUPVEL -
415   // contribution from Tao Lin (IHEP, the JUNO experiment)
416   if (key == "RINDEX") {
417     CalculateGROUPVEL();
418   }
419 }
420 
421 void G4MaterialPropertiesTable::AddProperty(
422   const char* key, G4MaterialPropertyVector* mpv, G4bool createNewKey)
423 {
424   AddProperty(G4String(key), mpv, createNewKey);
425 }
426 
427 void G4MaterialPropertiesTable::AddProperty(const G4String& key, const G4String& mat)
428 {
429   // load a material property vector defined in Geant4 source
430   G4MaterialPropertyVector* v = G4OpticalMaterialProperties::GetProperty(key, mat);
431   AddProperty(key, v);
432 }
433 
434 void G4MaterialPropertiesTable::AddConstProperty(
435   const G4String& key, G4double propertyValue, G4bool createNewKey)
436 {
437   // Provides a way of adding a constant property to the Material Properties
438   // Table given a key
439   if (std::find(fMatConstPropNames.cbegin(), fMatConstPropNames.cend(), key) ==
440       fMatConstPropNames.cend())
441   {
442     if (createNewKey) {
443       fMatConstPropNames.push_back(key);
444       fMCP.emplace_back(0., true);
445     }
446     else {
447       G4ExceptionDescription ed;
448       ed << "Attempting to create a new material constant property key " << key
449          << " without setting\n"
450          << "createNewKey parameter of AddProperty to true.";
451       G4Exception("G4MaterialPropertiesTable::AddProperty()", "mat207", FatalException, ed);
452     }
453   }
454   G4int index = GetConstPropertyIndex(key);
455 
456   fMCP[index] = std::pair<G4double, G4bool>{propertyValue, true};
457 }
458 
459 void G4MaterialPropertiesTable::AddConstProperty(
460   const char* key, G4double propertyValue, G4bool createNewKey)
461 {
462   // Provides a way of adding a constant property to the Material Properties
463   // Table given a key
464   AddConstProperty(G4String(key), propertyValue, createNewKey);
465 }
466 
467 void G4MaterialPropertiesTable::RemoveConstProperty(const G4String& key)
468 {
469   G4int index = GetConstPropertyIndex(key);
470   if (index < (G4int)fMCP.size()) {
471     fMCP[index] = std::pair<G4double, G4bool>{0., false};
472   }
473 }
474 
475 void G4MaterialPropertiesTable::RemoveConstProperty(const char* key)
476 {
477   RemoveConstProperty(G4String(key));
478 }
479 
480 void G4MaterialPropertiesTable::RemoveProperty(const G4String& key)
481 {
482   G4int index = GetPropertyIndex(key);
483   delete fMP[index];
484   fMP[index] = nullptr;
485 }
486 
487 void G4MaterialPropertiesTable::RemoveProperty(const char* key) { RemoveProperty(G4String(key)); }
488 
489 void G4MaterialPropertiesTable::AddEntry(
490   const G4String& key, G4double aPhotonEnergy, G4double aPropertyValue)
491 {
492   // Allows to add an entry pair directly to the Material Property Vector
493   // given a key.
494   if (std::find(fMatPropNames.cbegin(), fMatPropNames.cend(), key) == fMatPropNames.cend()) {
495     G4ExceptionDescription ed;
496     ed << "Material Property Vector " << key << " not found.";
497     G4Exception("G4MaterialPropertiesTable::AddEntry()", "mat214", FatalException, ed);
498   }
499   G4int index = GetPropertyIndex(key);
500 
501   G4MaterialPropertyVector* targetVector = fMP[index];
502   if (targetVector != nullptr) {
503     // do not allow duplicate energies
504     for (std::size_t i = 0; i < targetVector->GetVectorLength(); ++i) {
505       if (aPhotonEnergy == targetVector->Energy(i)) {
506         G4ExceptionDescription ed;
507         ed << "Energy values in material property vector must be unique. "
508            << "Key: " << key;
509         G4Exception("G4MaterialPropertiesTable::AddEntry()", "mat217", FatalException, ed);
510       }
511     }
512 
513     targetVector->InsertValues(aPhotonEnergy, aPropertyValue);
514   }
515   else {
516     G4ExceptionDescription ed;
517     ed << "Material Property Vector " << key << " not found.";
518     G4Exception("G4MaterialPropertiesTable::AddEntry()", "mat208", FatalException, ed);
519   }
520   if (key == "RINDEX") {
521     CalculateGROUPVEL();
522   }
523 }
524 
525 void G4MaterialPropertiesTable::AddEntry(
526   const char* key, G4double aPhotonEnergy, G4double aPropertyValue)
527 {
528   AddEntry(G4String(key), aPhotonEnergy, aPropertyValue);
529 }
530 
531 void G4MaterialPropertiesTable::DumpTable() const
532 {
533   // material properties
534   G4int j = 0;
535   for (const auto& prop : fMP) {
536     if (prop != nullptr) {
537       G4cout << j << ": " << fMatPropNames[j] << G4endl;
538       prop->DumpValues();
539     }
540     ++j;
541   }
542   // material constant properties
543   j = 0;
544   for (const auto& cprop : fMCP) {
545     if (cprop.second) {
546       G4cout << j << ": " << fMatConstPropNames[j] << " " << cprop.first << G4endl;
547     }
548     ++j;
549   }
550 }
551 
552 G4MaterialPropertyVector* G4MaterialPropertiesTable::CalculateGROUPVEL()
553 {
554 #ifdef G4MULTITHREADED
555   G4AutoLock mptm(&materialPropertyTableMutex);
556 #endif
557 
558   // check if "GROUPVEL" already exists. If so, remove it.
559   if (fMP[kGROUPVEL] != nullptr) {
560     this->RemoveProperty("GROUPVEL");
561   }
562 
563   // fetch RINDEX data, give up if unavailable
564   G4MaterialPropertyVector* rindex = this->GetProperty(kRINDEX);
565   if (rindex == nullptr) {
566     return nullptr;
567   }
568 
569   // RINDEX exists but has no entries, give up
570   if (rindex->GetVectorLength() == 0) {
571     return nullptr;
572   }
573 
574   // add GROUPVEL vector
575   auto* groupvel = new G4MaterialPropertyVector();
576   groupvel->SetVerboseLevel(1);
577 
578   // fill GROUPVEL vector using RINDEX values
579   // rindex built-in "iterator" was advanced to first entry above
580   G4double E0 = rindex->Energy(0);
581   G4double n0 = (*rindex)[0];
582 
583   if (E0 <= 0.) {
584     G4Exception("G4MaterialPropertiesTable::CalculateGROUPVEL()", "mat211", FatalException,
585       "Optical Photon Energy <= 0");
586   }
587 
588   if (rindex->GetVectorLength() >= 2) {
589     // good, we have at least two entries in RINDEX
590     // get next energy/value pair
591 
592     G4double E1 = rindex->Energy(1);
593     G4double n1 = (*rindex)[1];
594 
595     if (E1 <= 0.) {
596       G4Exception("G4MaterialPropertiesTable::CalculateGROUPVEL()", "mat212", FatalException,
597         "Optical Photon Energy <= 0");
598     }
599 
600     G4double vg;
601 
602     // add entry at first photon energy
603     vg = c_light / (n0 + (n1 - n0) / G4Log(E1 / E0));
604 
605     // allow only for 'normal dispersion' -> dn/d(logE) > 0
606     if ((vg < 0) || (vg > c_light / n0)) {
607       vg = c_light / n0;
608     }
609 
610     groupvel->InsertValues(E0, vg);
611 
612     // add entries at midpoints between remaining photon energies
613     for (std::size_t i = 2; i < rindex->GetVectorLength(); ++i) {
614       vg = c_light / (0.5 * (n0 + n1) + (n1 - n0) / G4Log(E1 / E0));
615 
616       // allow only for 'normal dispersion' -> dn/d(logE) > 0
617       if ((vg < 0) || (vg > c_light / (0.5 * (n0 + n1)))) {
618         vg = c_light / (0.5 * (n0 + n1));
619       }
620       groupvel->InsertValues(0.5 * (E0 + E1), vg);
621 
622       // get next energy/value pair, or exit loop
623       E0 = E1;
624       n0 = n1;
625       E1 = rindex->Energy(i);
626       n1 = (*rindex)[i];
627 
628       if (E1 <= 0.) {
629         G4Exception("G4MaterialPropertiesTable::CalculateGROUPVEL()", "mat213", FatalException,
630           "Optical Photon Energy <= 0");
631       }
632     }
633 
634     // add entry at last photon energy
635     vg = c_light / (n1 + (n1 - n0) / G4Log(E1 / E0));
636 
637     // allow only for 'normal dispersion' -> dn/d(logE) > 0
638     if ((vg < 0) || (vg > c_light / n1)) {
639       vg = c_light / n1;
640     }
641     groupvel->InsertValues(E1, vg);
642   }
643   else  // only one entry in RINDEX -- weird!
644   {
645     groupvel->InsertValues(E0, c_light / n0);
646   }
647 
648   this->AddProperty("GROUPVEL", groupvel);
649 
650   return groupvel;
651 }
652