BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSMaterials.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) Royal Holloway,
3University of London 2001 - 2024.
4
5This file is part of BDSIM.
6
7BDSIM is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published
9by the Free Software Foundation version 3 of the License.
10
11BDSIM is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with BDSIM. If not, see <http://www.gnu.org/licenses/>.
18*/
19#include "BDSDebug.hh"
20#include "BDSException.hh"
21#include "BDSIdealGas.hh"
22#include "BDSMaterials.hh"
23#include "BDSParser.hh"
24#include "BDSUtilities.hh"
25#include "BDSWarning.hh"
26
27#include "G4MaterialTable.hh"
28#include "G4String.hh"
29#include "G4NistManager.hh"
30#include "G4Version.hh"
31
32#include <iomanip>
33#include <list>
34#include <map>
35#include <set>
36#include <vector>
37
39
41{
42 if (!instance)
43 {instance = new BDSMaterials();}
44 return instance;
45}
46
47BDSMaterials::BDSMaterials()
48{
49#ifdef BDSDEBUG
50 G4cout << "BDSMaterials: G4 predefined units: " << G4endl;
51 G4cout << "g= " << CLHEP::g << G4endl;
52 G4cout << "m= " << CLHEP::m << G4endl;
53 G4cout << "mole= " << CLHEP::mole << G4endl;
54 G4cout << "kelvin= " << CLHEP::kelvin << G4endl;
55#endif
56
66}
67
69{
70 //default Geant4 temperature = 293.15 K (NTP_Temperature)
71 //default Geant4 pressure = 1atm
72#if G4VERSION_NUMBER < 1011
73 G4double NTP_Temperature = 293.15;
74#endif
75
76 // solid materials
77 // metals
78 // standard single element metals
79 AddExistingMaterialAlias("Al", "aluminium");
80 AddExistingMaterialAlias("Be", "beryllium");
81 AddExistingMaterialAlias("C", "carbon");
82 AddExistingMaterialAlias("Cr", "chromium");
83 AddExistingMaterialAlias("Cu", "copper");
84 AddExistingMaterialAlias("Fe", "iron");
85 AddExistingMaterialAlias("Pb", "lead");
86 AddExistingMaterialAlias("Mg", "magnesium");
87 AddExistingMaterialAlias("Ni", "nickel");
88 AddExistingMaterialAlias("Si", "silicon");
89 AddExistingMaterialAlias("Ti", "titanium");
90 AddExistingMaterialAlias("W", "tungsten");
91 AddExistingMaterialAlias("U", "uranium");
92 AddExistingMaterialAlias("V", "vanadium");
93 AddExistingMaterialAlias("Zn", "zinc");
94
95 // special forms
96 std::list<int> singleElement = {1};
97 AddMaterial("graphite", 2.265, kStateSolid, NTP_Temperature, 1, {"C"}, singleElement);
98 AddMaterial("graphitefoam", 0.61, kStateSolid, NTP_Temperature, 1, {"C"}, singleElement);
99 AddMaterial("solidhydrogen",8.96, kStateSolid, NTP_Temperature, 1, {"H"}, singleElement);
100 AddMaterial("solidnitrogen",8.96, kStateSolid, NTP_Temperature, 1, {"N"}, singleElement);
101 AddMaterial("solidoxygen", 8.96, kStateSolid, NTP_Temperature, 1, {"O"}, singleElement);
102 AddMaterial("weightiron", 7.87, kStateSolid, NTP_Temperature, 1, {"Fe"}, singleElement);
103
104 // composites and alloys
105 AddMaterial("leadtungstate" ,
106 8.27,
107 kStateSolid, NTP_Temperature, 1,
108 {"Pb","W" ,"O" },
109 std::list<int>{1, 1, 4});
110
111 AddMaterial("smco",
112 8.4,
113 kStateSolid, 300, 1,
114 {"Sm","Co"},
115 std::list<double>{0.338, 0.662});
116
117 // Titanium alloy (BDS collimator material SLAC-TN-03-069 p25) deacon 15 Jun 2007
118 AddMaterial("titaniumalloy",
119 4.48,
120 kStateSolid, 300, 1,
121 {"V" ,"Al","Ti"},
122 std::list<double>{0.025, 0.03, 0.945});
123
124 // Carbon Steel (shell of cryomodule). LDeacon 21 Feb 2006
125 AddMaterial("carbonsteel",
126 7.87,
127 kStateSolid, 100, 1,
128 {"C","Mn","P","S","Fe"},
129 std::list<double>{0.0017, 0.0045, 0.0004, 0.0005, 0.9929});
130
131 // Copper Alloy 17410 (C17410) "Beryllium Copper"
132 AddMaterial("berylliumcopper",
133 8.8,
134 kStateSolid, 300, 1,
135 {"Cu", "Be", "Co", "Al", "Fe", "Ni"},
136 std::list<double>{0.991, 0.0031, 0.00500, 0.0004, 0.0003, 0.0002});
137
138 // Stainless Steel 316L
139 AddMaterial("stainlesssteel",
140 8.0,
141 kStateSolid, 295, 1,
142 {"C","Mn","Si","P","S","Cr","Mo","Ni","N","Fe"},
143 std::list<double>{0.0003, 0.02, 0.0075, 0.00045, 0.0003, 0.17, 0.025, 0.12, 0.001, 0.65545});
144
145 // Stainless Steel AISI code 304L (low-carbon) @ 300K
146 AddMaterial("stainless_steel_304L",
147 8.02,
148 kStateSolid, 300, 1,
149 {"Fe", "Cr", "Ni", "Mn", "Si", "P", "S", "C"},
150 std::list<double>{0.67145, 0.185, 0.1125, 0.02, 0.01, 0.00045, 0.0003, 0.0003});
151
152 // Stainless Steel AISI code 304L (low-carbon) @ 87K
153 AddMaterial("stainless_steel_304L_87K",
154 8.02,
155 kStateSolid, 87, 1,
156 {"Fe", "Cr", "Ni", "Mn", "Si", "P", "S", "C"},
157 std::list<double>{0.67145, 0.185, 0.1125, 0.02, 0.01, 0.00045, 0.0003, 0.0003});
158
159 // Stainless Steel AISI code 304L (low-carbon) @ 2K
160 AddMaterial("stainless_steel_304L_2K",
161 8.02,
162 kStateSolid, 2, 1,
163 {"Fe", "Cr", "Ni", "Mn", "Si", "P", "S", "C"},
164 std::list<double>{0.67145, 0.185, 0.1125, 0.02, 0.01, 0.00045, 0.0003, 0.0003});
165
166 // Stainless Steel AISI code 316LN
167 // (Type 316, low carbon, nitrogen-enhanced) @ 300K
168 AddMaterial("stainless_steel_316LN",
169 8.03,
170 kStateSolid, 300, 1,
171 {"Fe", "Cr", "Ni", "Mo", "Mn", "Si", "Ti", "N", "Nb",
172 "Cu", "Co", "P", "C", "S", "Ta", "B"},
173 std::list<double>{0.65093, 0.1700, 0.12000, 0.02500, 0.0200, 0.00750,
174 0.00150, 0.0014, 0.00100, 0.00100, 0.0005, 0.00045,
175 0.00030, 0.0003, 0.00010, 0.00002});
176
177 // Stainless Steel AISI code 316LN
178 // (Type 316, low-carbon nitrogen-enhanced) @ 87K
179 AddMaterial("stainless_steel_316LN_87K",
180 8.03,
181 kStateSolid, 87, 1,
182 {"Fe", "Cr", "Ni", "Mo", "Mn", "Si", "Ti", "N",
183 "Nb", "Cu", "Co", "P", "C", "S", "Ta", "B"},
184 std::list<double>{0.65093, 0.1700, 0.12000, 0.02500, 0.0200,
185 0.00750, 0.00150, 0.0014, 0.00100, 0.00100,
186 0.0005, 0.00045, 0.00030, 0.0003, 0.00010,
187 0.00002});
188
189 // Stainless Steel AISI code 316LN
190 // (Type 316, low-carbon nitrogen-enhanced) @ 2K
191 AddMaterial("stainless_steel_316LN_2K",
192 8.03,
193 kStateSolid, 2, 1,
194 {"Fe", "Cr", "Ni", "Mo", "Mn", "Si", "Ti", "N",
195 "Nb", "Cu", "Co", "P", "C", "S", "Ta", "B"},
196 std::list<double>{0.65093, 0.1700, 0.12000, 0.02500, 0.0200,
197 0.00750, 0.00150, 0.0014, 0.00100, 0.00100,
198 0.0005, 0.00045, 0.00030, 0.0003, 0.00010,
199 0.00002});
200
201
202 // Mild Steel
203 AddMaterial("mild_steel", 8.000, kStateSolid, 295, 1,
204 {"C", "Mn", "Si", "Fe"},
205 std::list<double>{0.002, 0.005, 0.0015, 0.99150});
206
207 // Pure tungsten is not typically used, but instead part of "heavy
208 // alloy." I think "heavy" in the sense that the tungsten makes up almost
209 // all of the composition, and tungsten is a very dense metal.
210 AddMaterial("tungsten_heavy_alloy",
211 18.5,
212 kStateSolid, 87, 1,
213 {"W", "Ni", "Fe"},
214 std::list<double>{0.97, 0.02, 0.01});
215
216 // For HL-LHC Collimation - Inermet170
217 AddMaterial("inermet170",
218 17.0,
219 kStateSolid, 300, 1,
220 {"W", "Ni", "Cu"},
221 std::list<double>{0.90, 0.05, 0.05});
222
223 // For HL-LHC Collimation - Inermet176
224 AddMaterial("inermet176",
225 17.6,
226 kStateSolid, 300, 1,
227 {"W", "Ni", "Cu"},
228 std::list<double>{0.925, 0.0375, 0.0375});
229
230 // For HL-LHC Collimation - Inermet180
231 AddMaterial("inermet180",
232 18.0,
233 kStateSolid, 300, 1,
234 {"W", "Ni", "Cu"},
235 std::list<double>{0.95, 0.025, 0.025});
236}
237
239{
240 // niobium at 2K
241 AddMaterial("niobium_2k", 8.57 , kStateSolid, 2, 1, {"Nb"}, std::list<int>{1});
242 AddExistingMaterialAlias("niobium_2k", "nb_2k"); // alias
243 // niobium titanium at 4K
244 AddMaterial("nbti_4k", 5.6 , kStateSolid, 4, 1, {"Nb","Ti"}, std::list<int>{1,1});
245}
246
248{
249 // boron Nickel (absorber)
250 AddMaterial("bn5000",
251 1.925,
252 kStateSolid, 300, 1,
253 {"B","Ni","O","Ca","Si"},
254 std::list<double>{0.383249242, 0.472071387, 0.0366276887, 0.0228923054, 0.0851593762});
255
256 // calcium carbonate (calcite)
257 AddMaterial("calciumCarbonate",
258 2.711,
259 kStateSolid, 300, 1,
260 {"Ca","O","C"},
261 std::list<int>{1,3,1});
262
263 // clay
264 AddMaterial("clay",
265 1.746,
266 kStateSolid, 300, 1,
267 {"Al","O","Si","H"},
268 std::list<int>{1,9,2,4});
269
270 AddMaterial("concrete",
271 2.3,
272 kStateSolid, 300, 1, {"Si","O","H","Ca","Al","Fe"},
273 std::list<double>{0.227915, 0.60541, 0.09972, 0.04986, 0.014245, 0.00285});
274
275 // we make the material manually here so we have a pointer to it. note density units must
276 // be used here.
277 G4Material* tmpMaterial = new G4Material("fusedsilica",
278 1.032*CLHEP::g/CLHEP::cm3, // density
279 2,
280 kStateSolid);
281 tmpMaterial->AddElement(GetElement("O") , 2);
282 tmpMaterial->AddElement(GetElement("Si"), 1);
283 const G4int FusedSilica_NUMENTRIES = 3; //Number of entries in the material properties table
284 G4double FusedSilica_RIND[FusedSilica_NUMENTRIES]={1.49,1.49,1.49};
285 G4double FusedSilica_AbsLength[FusedSilica_NUMENTRIES]={420.*CLHEP::cm,420.*CLHEP::cm,420.*CLHEP::cm};
286 G4double FusedSilica_Energy[FusedSilica_NUMENTRIES] = {2.0*CLHEP::eV,7.0*CLHEP::eV,7.14*CLHEP::eV};
287 G4MaterialPropertiesTable* fsMaterialPropertiesTable = CreatePropertiesTable();
288 fsMaterialPropertiesTable->AddProperty("ABSLENGTH",FusedSilica_Energy,FusedSilica_AbsLength,FusedSilica_NUMENTRIES);
289 fsMaterialPropertiesTable->AddProperty("RINDEX",FusedSilica_Energy,FusedSilica_RIND,FusedSilica_NUMENTRIES);
290 tmpMaterial->SetMaterialPropertiesTable(fsMaterialPropertiesTable);
291 AddMaterial(tmpMaterial, "fusedsilica");
292
293 // perspex
294 AddMaterial("perspex",
295 1.18,
296 kStateSolid,
297 300,
298 1,
299 {"C","O","H"},
300 std::list<double>{0.59984,0.31961,0.08055});
301
302 // invar - Temperature 2 kelvin. LDeacon 6th Feburary 2006
303 AddMaterial("invar" ,
304 8.1 ,
305 kStateSolid, 2, 1,
306 {"Ni","Fe"},
307 std::list<double>{0.35,0.65});
308
309 // kapton polyimide film
310 AddMaterial("kapton",
311 1.42,
312 kStateSolid, 295, 1,
313 {"H","C","N","O"},
314 std::list<double>{0.026362,0.691133,0.073270,0.209235});
315
316 // n-bk7
317 tmpMaterial = new G4Material("n-bk7", 1.032*CLHEP::g/CLHEP::cm3, 2, kStateSolid);
318 tmpMaterial->AddElement(GetElement("O") , 2);
319 tmpMaterial->AddElement(GetElement("Si"), 1);
320 const G4int N_Bk7_NUMENTRIES = 3; //Number of entries in the material properties table
321 G4double N_Bk7_RIND[N_Bk7_NUMENTRIES]={1.51680,1.51680,1.51680};
322 G4double N_Bk7_AbsLength[N_Bk7_NUMENTRIES]={420.*CLHEP::cm,420.*CLHEP::cm,420.*CLHEP::cm};
323 G4double N_Bk7_Energy[N_Bk7_NUMENTRIES] = {2.0*CLHEP::eV,7.0*CLHEP::eV,7.14*CLHEP::eV};
324 G4MaterialPropertiesTable* nbk7MaterialPropertiesTable = CreatePropertiesTable();
325 nbk7MaterialPropertiesTable->AddProperty("ABSLENGTH",N_Bk7_Energy,N_Bk7_AbsLength,N_Bk7_NUMENTRIES);
326 nbk7MaterialPropertiesTable->AddProperty("RINDEX",N_Bk7_Energy,N_Bk7_RIND,N_Bk7_NUMENTRIES);
327 tmpMaterial->SetMaterialPropertiesTable(nbk7MaterialPropertiesTable);
328 AddMaterial(tmpMaterial, "n-bk7");
329
330 // quartz
331 AddMaterial("quartz", 2.655, kStateSolid, 300, 1, {"Si","O"}, std::list<int>{1,2});
332
333 // marl
334 AddMaterial("marl",
335 1.474,
336 kStateSolid, 300, 1,
337 {"clay","calciumCarbonate"},
338 std::list<double>{0.5,0.5});
339
340 // clayousMarl
341 AddMaterial("clayousMarl",
342 1.555,
343 kStateSolid, 300, 1,
344 {"clay","calciumCarbonate"},
345 std::list<double>{0.65,0.35});
346
347 // limousMarl
348 AddMaterial("limousMarl",
349 1.392,
350 kStateSolid, 300, 1,
351 {"clay", "calciumCarbonate"},
352 std::list<double>{0.35,0.65});
353
354 // "standard" soil (dry)
355 AddMaterial("soil",
356 1.9,
357 kStateSolid, 300, 1,
358 {"Si","O","H","Al"},
359 std::list<double>{0.33377483443708611, 0.57218543046357617, 0.022516556291390728, 0.071523178807947022});
360
361 // epoxy Resin components
362 // the main component of epoxy resin commonly used to insulate magnet coils.
363 AddMaterial("aralditef", 1.175, kStateSolid, 300, 1, {"C","H","O"},std::list<int>{12,18,4});
364
365 // a hardener for the epoxy resin
366 AddMaterial("hy906", 1.225, kStateSolid, 300, 1, {"C","H","O"},std::list<int>{10,5,3});
367
368 // an accelerator for epoxy resin
369 AddMaterial("dy061", 1.025, kStateSolid, 300, 1, {"C","H","O","N"},std::list<int>{15,25,1,3});
370
371 // material type 3 from CERN 81-05, "The Selection and Properties of Epoxide Resins
372 // Used for the Insulation of Magnet Systems in Radiation Environments".
373 AddMaterial("epoxyresin3",
374 1.20,
375 kStateSolid, 300, 1,
376 {"aralditef","hy906","dy061"},
377 std::list<double>{0.497512,0.497512,0.004976});
378
379 // cellulose
380 tmpMaterial = G4NistManager::Instance()->FindOrBuildMaterial("G4_CELLULOSE_CELLOPHANE",true,true);
381 const G4int Cellulose_NUMENTRIES = 3; //Number of entries in the material properties table
382 G4double Cellulose_RIND[Cellulose_NUMENTRIES] = {1.532,1.532,1.532};//Assume constant refractive index.
383 G4double Cellulose_Energy[Cellulose_NUMENTRIES] = {2.0*CLHEP::eV,7.0*CLHEP::eV,7.14*CLHEP::eV}; //The energies.
384 G4MaterialPropertiesTable* celluloseMaterialPropertiesTable = CreatePropertiesTable();
385 celluloseMaterialPropertiesTable->AddProperty("RINDEX",Cellulose_Energy, Cellulose_RIND, Cellulose_NUMENTRIES);
386 tmpMaterial->SetMaterialPropertiesTable(celluloseMaterialPropertiesTable);
387 AddMaterial(tmpMaterial, "cellulose");
388
389 // polyurethane
390 AddMaterial("polyurethane",
391 1.05,
392 kStateSolid, NTP_Temperature, 1,
393 {"C","H","N","O"},
394 std::list<int>{6,10,2,4});
395
396 // RCH 1000 - Ultra high molecular weight polyethylene [PE-UHMW]
397 // at 4K for LHC dipoles
398 AddMaterial("rch1000_4k",
399 0.925,
400 kStateSolid, 4, 1,
401 {"C", "H"},
402 std::list<int>{2,4});
403}
404
406{
407 //YAG
408 G4Material* tmpMaterial = new G4Material("yag", 4.56*CLHEP::g/CLHEP::cm3, 3);
409 tmpMaterial->AddElement(GetElement("Y") , 3);
410 tmpMaterial->AddElement(GetElement("Al"), 5);
411 tmpMaterial->AddElement(GetElement("O") , 12);
412 G4double birks = 0.08*CLHEP::mm/CLHEP::MeV;
413 tmpMaterial->GetIonisation()->SetBirksConstant(birks);
414 G4MaterialPropertiesTable* mpt_YAG = CreatePropertiesTable();
415 // const int nEntries3=60;
416 const G4int nEntries = 9;
417 G4double PhotonEnergyYAG[nEntries];
418 G4double dNEntries2=(G4double)nEntries;
419 G4double energyMin=1.91*CLHEP::eV;
420 G4double energyMax=2.76*CLHEP::eV;
421 G4double deltaEnergy=(energyMax-energyMin)/(dNEntries2-1.0);
422 G4double energy=energyMin;
423 for (G4int i=0; i<nEntries; energy += deltaEnergy, i++)
424 {PhotonEnergyYAG[i]=energy;}
425
426 G4double RefractiveIndexYAG[nEntries] = //Approximately correct, but check for different wavelengths
427 { 1.82, 1.82, 1.82, 1.82, 1.82, 1.82, 1.82,
428 1.82, 1.82 };
429
430 mpt_YAG->AddProperty("RINDEX",PhotonEnergyYAG, RefractiveIndexYAG, nEntries);
431#if G4VERSION_NUMBER < 1079
432 G4double scintFastYAG[nEntries] = //Approximately correct
433 { 0, 0.25, 2.0, 14.0, 13.0, 7.0, 4.0, 2.0, 0.0 };
434 // All of these parameters are deprecated in V11 onwards and will cause a crash
435 mpt_YAG->AddProperty("FASTCOMPONENT",PhotonEnergyYAG, scintFastYAG, nEntries)->SetSpline(true);
436 mpt_YAG->AddConstProperty("FASTTIMECONSTANT",70.*CLHEP::ns); //Approximately correct
437 mpt_YAG->AddConstProperty("YIELDRATIO",1.0);
438#endif
439 mpt_YAG->AddConstProperty("SCINTILLATIONYIELD",8000./CLHEP::MeV); //Approximately correct
440 mpt_YAG->AddConstProperty("RESOLUTIONSCALE",2.0); //Check this
441 tmpMaterial->SetMaterialPropertiesTable(mpt_YAG);
442 AddMaterial(tmpMaterial, "yag");
443
444 //UPS-923A - see http://www.amcrys-h.com/
445 //Define the material properties (copy from NIST table of materials).
446 G4NistManager* nistManager = G4NistManager::Instance();
447 G4Material* polystyrene = nistManager->FindOrBuildMaterial("G4_POLYSTYRENE",true,true);
448 tmpMaterial = new G4Material("ups923a",polystyrene->GetDensity(),1);
449 tmpMaterial->AddMaterial(polystyrene,1);
450 tmpMaterial->SetName("ups923a");
451 std::vector<G4double> ups923a_PhotonEnergy = {
452 3.35, 3.31, 3.28, 3.26, 3.25, 3.23, 3.23,
453 3.22, 3.21, 3.19, 3.18, 3.17, 3.16, 3.15,
454 3.14, 3.14, 3.13, 3.11, 3.1, 3.09, 3.09,
455 3.08, 3.07, 3.04, 3.02, 3.02, 3.01, 2.99,
456 2.98, 2.97, 2.97, 2.95, 2.95, 2.93, 2.93,
457 2.92, 2.92, 2.91, 2.89, 2.88, 2.87, 2.86,
458 2.85, 2.83, 2.81, 2.8, 2.79, 2.78, 2.76,
459 2.74, 2.72, 2.71, 2.68, 2.66, 2.64, 2.62,
460 2.61, 2.58, 2.55, 2.53, 2.5, 2.48, 2.46,
461 2.44, 2.41, 2.38, 2.35 };
462 std::reverse(ups923a_PhotonEnergy.begin(), ups923a_PhotonEnergy.end());
463
464 // AUG 21 - these were previously just one number as a const property but they should be non-const
465 // which requires vs energy numbers - so just use arrays the same shape
466 std::vector<G4double> ups923a_RINDEX(ups923a_PhotonEnergy.size(), 1.52);
467 std::vector<G4double> ups923a_ABSLENGTH(ups923a_PhotonEnergy.size(), 1*CLHEP::m);
468
469 G4MaterialPropertiesTable* ups923a_mt = CreatePropertiesTable();
470#if G4VERSION_NUMBER < 1070
471 ups923a_mt->AddProperty("RINDEX", ups923a_PhotonEnergy.data(), ups923a_RINDEX.data(), (int)ups923a_PhotonEnergy.size());
472 ups923a_mt->AddProperty("ABSLENGTH", ups923a_PhotonEnergy.data(), ups923a_ABSLENGTH.data(), (int)ups923a_PhotonEnergy.size());
473#else
474 ups923a_mt->AddProperty("RINDEX", ups923a_PhotonEnergy, ups923a_RINDEX);
475 ups923a_mt->AddProperty("ABSLENGTH", ups923a_PhotonEnergy, ups923a_ABSLENGTH);
476#endif
477 //Birk's constant
478 birks = (0.014/1.06)*CLHEP::cm/CLHEP::MeV;
479 tmpMaterial->GetIonisation()->SetBirksConstant(birks);
480#if G4VERSION_NUMBER < 1079
481 const G4int ups923a_numentries = 67;
482 G4double ups923a_emission[ups923a_numentries] = {
483 0, 0.04, 0.11, 0.2, 0.3, 0.4, 0.52,
484 0.62, 0.67, 0.68, 0.67, 0.62, 0.53, 0.48,
485 0.44, 0.42, 0.4, 0.41, 0.42, 0.51, 0.46,
486 0.57, 0.67, 0.78, 0.91, 0.93, 0.95, 0.96,
487 0.94, 0.91, 0.85, 0.76, 0.67, 0.61, 0.57,
488 0.55, 0.52, 0.51, 0.52, 0.54, 0.57, 0.58,
489 0.6, 0.6, 0.59, 0.58, 0.55, 0.48, 0.42,
490 0.37, 0.33, 0.31, 0.29, 0.28, 0.26, 0.24,
491 0.2, 0.17, 0.12, 0.09, 0.08, 0.07,
492 0.06, 0.04, 0.02, 0.01, 0.01 };
493 ups923a_mt->AddConstProperty("FASTTIMECONSTANT",3.3*CLHEP::ns);
494 ups923a_mt->AddProperty("FASTCOMPONENT",ups923a_PhotonEnergy.data(), ups923a_emission, ups923a_numentries)->SetSpline(true);
495 ups923a_mt->AddConstProperty("YIELDRATIO",1.0);
496#endif
497 ups923a_mt->AddConstProperty("RESOLUTIONSCALE",2.0); //Check this
498 G4double scintYieldAnthracene=14200; //Anthracene yield per 1 CLHEP::MeV
499 G4double scintYieldUPS923A=scintYieldAnthracene*0.60;//60% of anthracene
500 ups923a_mt->AddConstProperty("SCINTILLATIONYIELD",scintYieldUPS923A/CLHEP::MeV);
501
502 tmpMaterial->SetMaterialPropertiesTable(ups923a_mt);
503 AddMaterial(tmpMaterial, "ups923a");
504
505 // PET
506 G4double pet_density=1.4*CLHEP::g/CLHEP::cm3;
507 G4int pet_nelements=3;
508 G4State pet_state=kStateSolid;
509 tmpMaterial= new G4Material("pet",
510 pet_density,
511 pet_nelements,
512 pet_state);
513 tmpMaterial->AddElement(nistManager->FindOrBuildElement("C",true),10);
514 tmpMaterial->AddElement(nistManager->FindOrBuildElement("H",true),8);
515 tmpMaterial->AddElement(nistManager->FindOrBuildElement("O",true),4);
516 const G4int Pet_NUMENTRIES = 3; //Number of entries in the material properties table
517 G4double Pet_RIND[Pet_NUMENTRIES] = {1.570,1.570,1.570};//Assume constant refractive index.
518 G4double Pet_Energy[Pet_NUMENTRIES] = {2.0*CLHEP::eV,7.0*CLHEP::eV,7.14*CLHEP::eV}; //The energies.
519 G4MaterialPropertiesTable* petMaterialPropertiesTable = CreatePropertiesTable();
520 petMaterialPropertiesTable->AddProperty("RINDEX",Pet_Energy, Pet_RIND, Pet_NUMENTRIES);
521 tmpMaterial->SetMaterialPropertiesTable(petMaterialPropertiesTable);
522 AddMaterial(tmpMaterial, "pet");
523
524 // Opaque PET (Dacron)
525 tmpMaterial= new G4Material("pet_opaque",
526 pet_density,
527 pet_nelements,
528 pet_state);
529 tmpMaterial->AddElement(nistManager->FindOrBuildElement("C",true),10);
530 tmpMaterial->AddElement(nistManager->FindOrBuildElement("H",true),8);
531 tmpMaterial->AddElement(nistManager->FindOrBuildElement("O",true),4);
532 const G4int Pet_Opaque_NUMENTRIES = 3; //Number of entries in the material properties table
533 G4double Pet_Opaque_RIND[Pet_Opaque_NUMENTRIES] = {1.570,1.570,1.570};//Assume constant refractive index.
534 G4double Pet_Opaque_Energy[Pet_Opaque_NUMENTRIES] = {2.0*CLHEP::eV,7.0*CLHEP::eV,7.14*CLHEP::eV}; //The energies.
535 G4double Pet_Opaque_abslen[]={1*CLHEP::um, 1*CLHEP::um, 1*CLHEP::um};
536 G4MaterialPropertiesTable* pet_opaqueMaterialPropertiesTable = CreatePropertiesTable();
537 pet_opaqueMaterialPropertiesTable->AddProperty("RINDEX",Pet_Opaque_Energy, Pet_Opaque_RIND, Pet_Opaque_NUMENTRIES);
538 pet_opaqueMaterialPropertiesTable->AddProperty("ABSLENGTH",Pet_Opaque_Energy, Pet_Opaque_abslen, Pet_Opaque_NUMENTRIES);
539 tmpMaterial->SetMaterialPropertiesTable(pet_opaqueMaterialPropertiesTable);
540 AddMaterial(tmpMaterial, "pet_opaque");
541
542 // Gadolinium oxysulphate Gd_2 O_2 S
543 G4Material* GOS = nistManager->FindOrBuildMaterial("G4_GADOLINIUM_OXYSULFIDE",true,true);
544
545 // Ganolinium oxysulphate in a polyurethane elastomer (lanex)
546 G4double fill_factor=0.5;
547 G4double lanex_density=fill_factor*GOS->GetDensity()+(1-fill_factor)*GetMaterial("polyurethane")->GetDensity();
548 G4double gos_fraction_by_mass=fill_factor*GOS->GetDensity()/lanex_density;
549 G4double pur_fraction_by_mass=1-gos_fraction_by_mass;
550
551 tmpMaterial = new G4Material("lanex", lanex_density, 2);
552 tmpMaterial->AddMaterial(GOS, gos_fraction_by_mass);
553 tmpMaterial->AddMaterial(GetMaterial("polyurethane"), pur_fraction_by_mass);
554
555 G4MaterialPropertiesTable* mptLanex = CreatePropertiesTable();
556 const G4int nentLanex=2;
557 G4double rindex=1.50;//(1.82+1.50)/2.0;
558 G4double energytab[]={2.239*CLHEP::eV, 2.241*CLHEP::eV};
559 G4double rindextab[]={rindex, rindex};
560 G4double abslen[]={7*CLHEP::mm, 7*CLHEP::mm};
561 mptLanex->AddProperty("RINDEX",energytab, rindextab, nentLanex); //Average refractive index of bulk material
562 mptLanex->AddProperty("ABSLENGTH", energytab, abslen, nentLanex);
563#if G4VERSION_NUMBER < 1079
564 mptLanex->AddConstProperty("MIEHG", 60.3e-3*CLHEP::mm); // interface changed in V11
565 G4double emitspec[]={1.0, 1.0};
566 mptLanex->AddProperty("FASTCOMPONENT",energytab, emitspec, nentLanex);
567 mptLanex->AddConstProperty("FASTTIMECONSTANT", 1.*CLHEP::ns);
568#endif
569 G4double scintScalingFactor=1;
570 mptLanex->AddConstProperty("SCINTILLATIONYIELD",7.8e4/CLHEP::MeV);
571 mptLanex->AddConstProperty("RESOLUTIONSCALE",1.0);
572 mptLanex->AddConstProperty("MIEHG_FORWARD", 0.91);
573 mptLanex->AddConstProperty("MIEHG_BACKWARD", 0.91);
574 mptLanex->AddConstProperty("MIEHG_FORWARD_RATIO", 1.0);
575 tmpMaterial->SetMaterialPropertiesTable(mptLanex);
576 AddMaterial(tmpMaterial, "lanex");
577
578 //Ganolinium oxysulphate in a polyurethane elastomer (lanex) - version 2
579 tmpMaterial = new G4Material("lanex2", lanex_density, 2);
580 tmpMaterial->AddMaterial(GOS, gos_fraction_by_mass);
581 tmpMaterial->AddMaterial(GetMaterial("polyurethane"), pur_fraction_by_mass);
582 G4MaterialPropertiesTable* mptLanex2 = CreatePropertiesTable();
583 mptLanex2->AddProperty("RINDEX",energytab, rindextab, nentLanex); //Average refractive index of bulk material
584 mptLanex2->AddProperty("ABSLENGTH", energytab, abslen, nentLanex);
585#if G4VERSION_NUMBER < 1079
586 mptLanex2->AddConstProperty("MIEHG", 60.3e-3*CLHEP::mm);
587 mptLanex2->AddProperty("FASTCOMPONENT",energytab, emitspec, nentLanex);
588 mptLanex2->AddConstProperty("FASTTIMECONSTANT", 1.*CLHEP::ns);
589#endif
590 mptLanex2->AddConstProperty("SCINTILLATIONYIELD",8.9e4/CLHEP::MeV);
591 mptLanex2->AddConstProperty("RESOLUTIONSCALE",1.0);
592 mptLanex2->AddConstProperty("MIEHG_FORWARD", 0.91);
593 mptLanex2->AddConstProperty("MIEHG_BACKWARD", 0.91);
594 mptLanex2->AddConstProperty("MIEHG_FORWARD_RATIO", 0.5);
595 tmpMaterial->SetMaterialPropertiesTable(mptLanex);
596 AddMaterial(tmpMaterial, "lanex2");
597
598 //gos_lanex - GOS with the bulk optical transport properties of lanex particles suspended in an elastomer but the atomic, density and scintillation properties of GOS
599 G4double gos_lanex_density=GOS->GetDensity();
600 tmpMaterial = new G4Material("gos_lanex", gos_lanex_density, 1);
601 tmpMaterial->AddMaterial(GOS, 1.0);
602 G4MaterialPropertiesTable* mptGOSLanex = CreatePropertiesTable();
603 const G4int nentGOSLanex=2;
604 G4double rindexGOSLanex=1.50;
605 G4double energyGOSLanexTab[]={2.239*CLHEP::eV, 2.241*CLHEP::eV};
606 G4double rindexGOSLanexTab[]={rindexGOSLanex, rindexGOSLanex};
607 G4double abslenGOSLanex[]={7*CLHEP::mm, 7*CLHEP::mm};
608 G4double gosLanexMiehgForward=0.911;
609 G4double gosLanexMiehgBackward=0.911;
610 G4double gosLanexMiehgForwardRatio=0.5;
611#if G4VERSION_NUMBER < 1079
612 G4double mieHgTimeConst=1.0*CLHEP::ns;
613 G4double emitspecGOSLanex[]={1.0, 1.0};
614 G4double mieScatteringLengthGOSLanex=60.3*CLHEP::um;
615 mptGOSLanex->AddProperty("FASTCOMPONENT",energyGOSLanexTab, emitspecGOSLanex, nentGOSLanex);
616 mptGOSLanex->AddConstProperty("FASTTIMECONSTANT", mieHgTimeConst);
617 mptGOSLanex->AddConstProperty("YIELDRATIO", 1.0);
618 mptGOSLanex->AddConstProperty("MIEHG", mieScatteringLengthGOSLanex);
619#endif
620 mptGOSLanex->AddConstProperty("SCINTILLATIONYIELD",8.9e4/CLHEP::MeV); //Intrinisic scintilation yield of GOS
621 mptGOSLanex->AddConstProperty("RESOLUTIONSCALE", 1.0);
622 mptGOSLanex->AddConstProperty("MIEHG_FORWARD", gosLanexMiehgForward);
623 mptGOSLanex->AddConstProperty("MIEHG_BACKWARD", gosLanexMiehgBackward);
624 mptGOSLanex->AddConstProperty("MIEHG_FORWARD_RATIO", gosLanexMiehgForwardRatio);
625 mptGOSLanex->AddProperty("RINDEX",energyGOSLanexTab, rindexGOSLanexTab, nentGOSLanex); //Average refractive index of bulk material
626 mptGOSLanex->AddProperty("ABSLENGTH", energyGOSLanexTab, abslenGOSLanex, nentGOSLanex);
627 tmpMaterial->SetMaterialPropertiesTable(mptGOSLanex);
628 AddMaterial(tmpMaterial, "gos_lanex");
629
630 //Same as gos_lanex but refractive index = 1
631 tmpMaterial = new G4Material("gos_ri1", gos_lanex_density, 1);
632 tmpMaterial->AddMaterial(GOS, 1.0);
633 G4MaterialPropertiesTable* mptGOSLanexRi1 = CreatePropertiesTable();
634 G4double rindexGOSLanexRi1Tab[]={1.0, 1.0};
635#if G4VERSION_NUMBER < 1079
636 mptGOSLanexRi1->AddProperty("FASTCOMPONENT",energyGOSLanexTab, emitspecGOSLanex, nentGOSLanex);
637 mptGOSLanexRi1->AddConstProperty("FASTTIMECONSTANT", mieHgTimeConst);
638 mptGOSLanexRi1->AddConstProperty("YIELDRATIO", 1.0);
639 mptGOSLanexRi1->AddConstProperty("MIEHG", mieScatteringLengthGOSLanex);
640#endif
641 mptGOSLanexRi1->AddConstProperty("SCINTILLATIONYIELD",8.9e4/CLHEP::MeV); //Intrinisic scintilation yield of GOS
642 mptGOSLanexRi1->AddConstProperty("RESOLUTIONSCALE", 1.0);
643 mptGOSLanexRi1->AddConstProperty("MIEHG_FORWARD", gosLanexMiehgForward);
644 mptGOSLanexRi1->AddConstProperty("MIEHG_BACKWARD", gosLanexMiehgBackward);
645 mptGOSLanexRi1->AddConstProperty("MIEHG_FORWARD_RATIO", gosLanexMiehgForwardRatio);
646 mptGOSLanexRi1->AddProperty("RINDEX",energyGOSLanexTab, rindexGOSLanexRi1Tab, nentGOSLanex); //Average refractive index of bulk material
647 mptGOSLanexRi1->AddProperty("ABSLENGTH", energyGOSLanexTab, abslenGOSLanex, nentGOSLanex);
648 tmpMaterial->SetMaterialPropertiesTable(mptGOSLanexRi1);
649 AddMaterial(tmpMaterial, "gos_ri1");
650
651 //pet_lanex - PET with the bulk optical transport properties of lanex particles suspended in an elastomer but the atomic, density and scintillation properties of PET
652 G4double pet_lanex_density=GetMaterial("polyurethane")->GetDensity();
653 tmpMaterial = new G4Material("pet_lanex", pet_lanex_density, 1);
654 tmpMaterial->AddMaterial(GetMaterial("polyurethane"), 1.0);
655 G4MaterialPropertiesTable* mptPETLanex = CreatePropertiesTable();
656 mptPETLanex->AddConstProperty("MIEHG_FORWARD", gosLanexMiehgForward);
657 mptPETLanex->AddConstProperty("MIEHG_BACKWARD", gosLanexMiehgBackward);
658 mptPETLanex->AddConstProperty("MIEHG_FORWARD_RATIO", gosLanexMiehgForwardRatio);
659#if G4VERSION_NUMBER < 1079
660 mptPETLanex->AddConstProperty("MIEHG", mieScatteringLengthGOSLanex);
661#endif
662 mptPETLanex->AddProperty("RINDEX",energyGOSLanexTab, rindexGOSLanexTab, nentGOSLanex); //Average refractive index of bulk material
663 mptPETLanex->AddProperty("ABSLENGTH", energyGOSLanexTab, abslenGOSLanex, nentGOSLanex);
664 tmpMaterial->SetMaterialPropertiesTable(mptPETLanex);
665 AddMaterial(tmpMaterial, "pet_lanex");
666
667 //Medex (larger grained lanex)
668 // G4double medex_fill_factor=0.5;
669 G4double medex_density=fill_factor*GOS->GetDensity()+(1-fill_factor)*GetMaterial("polyurethane")->GetDensity();
670 G4double medex_gos_fraction_by_mass=fill_factor*GOS->GetDensity()/medex_density;
671 G4double medex_pur_fraction_by_mass=1-medex_gos_fraction_by_mass;
672 tmpMaterial = new G4Material("medex", medex_density, 2);
673 tmpMaterial->AddMaterial(GOS, medex_gos_fraction_by_mass);
674 tmpMaterial->AddMaterial(GetMaterial("polyurethane"), medex_pur_fraction_by_mass);
675 G4MaterialPropertiesTable* mptMedex = CreatePropertiesTable();
676 const G4int nentMedex=2;
677 // G4double medexRindex=(1.82+1.50)/2.0;
678 // G4double medexEnergytab[]={2.239*CLHEP::eV, 2.241*CLHEP::eV};
679 G4double medexRindextab[]={rindex, rindex};
680
681 G4double medexAbslen[]={7*CLHEP::mm, 7*CLHEP::mm};
682 mptMedex->AddProperty("RINDEX",energytab, medexRindextab, nentMedex); //Average refractive index of bulk material
683 mptMedex->AddProperty("ABSLENGTH", energytab, medexAbslen, nentMedex);
684#if G4VERSION_NUMBER < 1079
685 mptMedex->AddConstProperty("MIEHG", 230e-3*CLHEP::mm);
686 G4double medexEmitspec[]={1.0, 1.0};
687 mptMedex->AddProperty("FASTCOMPONENT",energytab, medexEmitspec, nentMedex);
688 mptMedex->AddConstProperty("FASTTIMECONSTANT", 1.*CLHEP::ns);
689#endif
690 mptMedex->AddConstProperty("SCINTILLATIONYIELD",scintScalingFactor*2.94e4/CLHEP::MeV);
691 mptMedex->AddConstProperty("RESOLUTIONSCALE",1.0);
692 mptMedex->AddConstProperty("MIEHG_FORWARD", 0.93);
693 mptMedex->AddConstProperty("MIEHG_BACKWARD", 0.93);
694 mptMedex->AddConstProperty("MIEHG_FORWARD_RATIO", 1.0);
695 tmpMaterial->SetMaterialPropertiesTable(mptMedex);
696 AddMaterial(tmpMaterial, "medex");
697
698 // carbon fiber
699 G4double frac_graph=0.5;
700 G4double frac_poly=0.5;
701 G4Material* graph=GetMaterial("G4_GRAPHITE");
702 G4Material* poly=GetMaterial("G4_POLYACRYLONITRILE");
703 G4double dens_graph=graph->GetDensity();
704 G4double dens_poly=poly->GetDensity();
705
706 G4double dens_cf =frac_graph*dens_graph+frac_poly*dens_poly;
707 G4double frac_graph_bw=frac_graph*dens_graph/dens_cf;
708 G4double frac_poly_bw=frac_poly*dens_poly/dens_cf;
709 tmpMaterial = new G4Material("carbonfiber", dens_cf, 2);
710 tmpMaterial->AddMaterial(graph, frac_graph_bw);
711 tmpMaterial->AddMaterial(poly, frac_poly_bw);
712 G4MaterialPropertiesTable* mptCarbonfiber = CreatePropertiesTable();
713 const G4int nentCarbonfiber=2;
714 G4double energytab_cf[]={2.239*CLHEP::eV, 2.241*CLHEP::eV};
715 G4double carbonfiberRindextab[]={2.6, 2.6};
716 G4double carbonfiberAbslen[]={2.1*CLHEP::um, 2.1*CLHEP::um};
717 mptCarbonfiber->AddProperty("RINDEX",energytab_cf, carbonfiberRindextab, nentCarbonfiber); //Average refractive index of bulk material
718 mptCarbonfiber->AddProperty("ABSLENGTH", energytab_cf, carbonfiberAbslen, nentCarbonfiber);
719 tmpMaterial->SetMaterialPropertiesTable(mptCarbonfiber);
720 AddMaterial(tmpMaterial, "carbonfiber");
721}
722
724{
725 AddMaterial("lhcconcrete",
726 2.42,
727 kStateSolid, 300, 1,
728 {"H","C","O","Na","Mg","Al","Si","K","Ca","Fe","P","S",
729 "Ti","Mn","Zn","Zr","Ba","Pb","Sr","Eu"},
730 std::list<double>{0.59785345499811 *CLHEP::perCent,
731 5.59989402848226 *CLHEP::perCent,
732 49.1111702720319 *CLHEP::perCent,
733 0.45137935852357 *CLHEP::perCent,
734 0.66062806777291 *CLHEP::perCent,
735 2.05561946276849 *CLHEP::perCent,
736 18.7995018924154 *CLHEP::perCent,
737 0.65365311079793 *CLHEP::perCent,
738 20.0191229406116 *CLHEP::perCent,
739 1.11400027114647 *CLHEP::perCent,
740 0.04782827639985 *CLHEP::perCent,
741 0.01195706909996 *CLHEP::perCent,
742 0.3457585814739 *CLHEP::perCent,
743 0.03856154784738 *CLHEP::perCent,
744 0.02401378044242 *CLHEP::perCent,
745 0.00737352594498 *CLHEP::perCent,
746 0.01783596140744 *CLHEP::perCent,
747 0.04623400051985 *CLHEP::perCent,
748 0.39757254757374 *CLHEP::perCent,
749 4.184974185E-05 *CLHEP::perCent});
750
751 // LHC Rock
752 AddMaterial("lhc_rock",
753 2,
754 kStateSolid, 300, 1,
755 {"H", "Na", "Si", "Fe", "C", "Mg", "K", "O", "Al", "Ca"},
756 std::list<double>{0.006, 0.01, 0.2, 0.014, 0.03, 0.005, 0.01, 0.5, 0.03, 0.195});
757
758 // Superconducting components of LHC magnet elements
759 // Definitions taken from FLUKA
760
761 std::list<int> singleElement = {1};
762 // Liquid helium at 1.9K
763 AddMaterial("lhe_1.9k",
764 0.1472,
765 kStateLiquid, 1.9, 1,
766 {"He"}, singleElement);
767
768 // Niobium @ 87K
769 AddMaterial("nb_87k",
770 8.902 ,
771 kStateSolid , 87 , 1,
772 {"Nb"}, singleElement);
773
774 // Titanium @ 87K
775 AddMaterial("ti_87k",
776 4.54,
777 kStateSolid, 87 , 1,
778 {"Ti"}, singleElement);
779
780 // superconductor NbTi with Ti = 47% by weight
781 AddMaterial("nbti_87k",
782 6.0471,
783 kStateSolid , 87 , 1,
784 {"nb_87k","ti_87k"},
785 std::list<double>{0.53,0.47});
786
787 // copper at 4 Kelvin
788 AddMaterial("cu_4k",
789 8.96,
790 kStateSolid, 4, 1,
791 {"Cu"}, singleElement);
792
793 // copper at 2 Kelvin
794 AddMaterial("cu_2k",
795 8.96,
796 kStateSolid, 2, 1,
797 {"Cu"}, singleElement);
798
799 // naked superconductor NbTi wire with Cu/SC volume ratio (>= 4.0 and <4.8)
800 AddMaterial("nbti.1",
801 8.4206,
802 kStateSolid, 4, 1,
803 {"nbti_87k","cu_4k"},
804 std::list<double>{1.0/5.4, 4.4/5.4});
805
806 // For HL-LHC Collimation - Copper Diamond - TBC - component fractions
807 AddMaterial("copperdiamond",
808 5.3,
809 kStateSolid, 300, 1,
810 {"Cu", "C"},
811 std::list<double>{0.32, 0.68});
812 AddExistingMaterialAlias("copperdiamond", "cucd");
813
814 // For HL-LHC Collimation - Copper Diamond
815 AddMaterial("molybdenumcarbide",
816 8.9,
817 kStateSolid, 300, 1,
818 {"Mo", "C"},
819 std::list<int>{1, 1});
820 AddExistingMaterialAlias("molybdenumcarbide", "mogr");
821}
822
824{
825 AddMaterial("liquidhelium", 0.12498, kStateLiquid, 4.15, 1, {"He"}, std::list<int>{1});
826
827 // water
828 AddExistingMaterialAlias("G4_WATER", "water"); // use NIST water
829 G4Material* water = GetMaterial("water"); // get the material pointer back
830
831 // add refractive index to G4_WATER material for cherenkov radiation to work
832 const G4int nEntries = 9;
833 G4MaterialPropertiesTable* waterProperties = CreatePropertiesTable();
834 G4double photonEnergy[nEntries];
835 G4double dNEntries = (G4double)nEntries;
836 G4double energyMin = 1.*CLHEP::eV;
837 G4double energyMax = 3.*CLHEP::eV;
838 G4double deltaEnergy = (energyMax-energyMin)/(dNEntries-1.0);
839 G4double energy = energyMin;
840 for (G4int i = 0; i < nEntries; energy += deltaEnergy, i++)
841 {photonEnergy[i] = energy;}
842 G4double refractiveIndex[nEntries] = {1.325, 1.325, 1.326, 1.327, 1.328, 1.33, 1.333, 1.336, 1.343};
843 waterProperties->AddProperty("RINDEX", photonEnergy, refractiveIndex, nEntries);
844 water->SetMaterialPropertiesTable(waterProperties);
845}
846
848{
849 AddExistingMaterialAlias("N", "nitrogen");
850
851 // air
852 AddExistingMaterialAlias("G4_AIR", "air");
853 G4Material* g4AirMaterial = GetMaterial("air");
854 const G4int airNEntries = 3;
855 // source: NPL Tables of Physical & Chemical Constants. Refractive indices at
856 // different energies.
857 G4double airRefractiveIndex[airNEntries] = {1.000292,1.000292,1.000292};
858 G4double airEnergy[airNEntries] = {2.0*CLHEP::eV,7.0*CLHEP::eV,7.14*CLHEP::eV};
859 G4MaterialPropertiesTable* airProperties = CreatePropertiesTable();
860 airProperties->AddProperty("RINDEX", airEnergy, airRefractiveIndex, airNEntries);
861 g4AirMaterial->SetMaterialPropertiesTable(airProperties);
862
863 // old way - manually constructed air
864 // room temperature temperature and standard pressure
865 G4double temperature = 300*CLHEP::kelvin;
866 G4double pressure = 1.0*CLHEP::atmosphere;
867 G4double airDensity = 0.001225; // g/cm3
868 G4Material* tmpMaterial = new G4Material("airbdsim",
869 airDensity*CLHEP::g/CLHEP::cm3,
870 2,
871 kStateGas,
872 temperature,
873 pressure);
874 tmpMaterial->AddElement(GetElement("O"), 0.2);
875 tmpMaterial->AddElement(GetElement("N"), 0.8);
876 tmpMaterial->SetMaterialPropertiesTable(airProperties);
877 AddMaterial(tmpMaterial, "airbdsim");
878
879 // Carbon monoxide
880 G4double coDensity = 0.001145; // g/cm3
881 AddMaterial("carbonmonoxide",
882 coDensity,
883 kStateGas,
884 temperature,
885 pressure,
886 {"C","O"},
887 std::list<int>{1,1});
888
889 // Carbon monoxide beam pipe gas
890 G4double bp_pressure = 0.0133e-9 * (CLHEP::bar/CLHEP::atmosphere); //10 nTorr pressure
891 AddMaterial("bp_carbonmonoxide",
892 coDensity,
893 kStateGas,
894 temperature,
895 bp_pressure,
896 {"C","O"},
897 std::list<int>{1,1});
898}
899
901{
902 //Awake plasma - rubidium at density of 7e14 atoms/cm3
903 // G4double numberDensity = 7.0e14/CLHEP::cm3;
904 G4double a = 85.4678*CLHEP::g/CLHEP::mole;
905 G4double density = 1e-7 * CLHEP::g/CLHEP::cm3;
906 G4Material* tmpMaterial = new G4Material("awakeplasma", 37., a, density);
907 AddMaterial(tmpMaterial, "awakeplasma");
908}
909
911{
912 // Default vacuum (same composition as residual vacuum in warm sections of LHC).
913 G4double vacpressure;
914 // check if parser is initialised (in case list materials is asked by command line)
916 {vacpressure=BDSParser::Instance()->GetOptions().vacuumPressure*CLHEP::bar;}
917 else
918 {vacpressure=1e-12*CLHEP::bar;}
919 G4double temperature = 300*CLHEP::kelvin;
920 G4double density = (CLHEP::STP_Temperature/temperature) * (vacpressure/(1.*CLHEP::atmosphere)) * 29*CLHEP::g/(22.4*1.e-3*CLHEP::m3);
921
922 G4Material* tmpMaterial = new G4Material("vacuum",
923 density,
924 3, kStateGas,
925 temperature, vacpressure);
926 tmpMaterial->AddElement(GetElement("H"), 0.482);
927 tmpMaterial->AddElement(GetElement("C"), 0.221);
928 tmpMaterial->AddElement(GetElement("O"), 0.297);
929 AddMaterial(tmpMaterial, "vacuum");
930
931 const G4int Vac_NUMENTRIES = 3;
932 // Assume refractive index = 1 in a vacuum.
933 G4double Vac_RIND[Vac_NUMENTRIES] = {1.000,1.000,1.000};
934 G4double Vac_Energy[Vac_NUMENTRIES] = {2.0*CLHEP::eV,7.0*CLHEP::eV,7.14*CLHEP::eV};
935 G4MaterialPropertiesTable* vacMaterialPropertiesTable = CreatePropertiesTable();
936 vacMaterialPropertiesTable->AddProperty("RINDEX",Vac_Energy, Vac_RIND, Vac_NUMENTRIES);
937 tmpMaterial->SetMaterialPropertiesTable(vacMaterialPropertiesTable);
938
939 // copy regular vacuum as named 'laservac' to detect where laserwire is.
940 // G4Material doesn't have a copy constructor but it has a sort of copy
941 // constructor.
942 G4Material* regularVacuum = GetMaterial("vacuum");
943 G4Material* laservac = new G4Material("laservac",
944 regularVacuum->GetDensity(),
945 regularVacuum,
946 kStateGas,
947 regularVacuum->GetTemperature(),
948 regularVacuum->GetPressure());
949 AddMaterial(laservac, "laservac");
950}
951
952void BDSMaterials::AddMaterial(G4Material* material, G4String name)
953{
954 name = BDS::LowerCase(name);
955 if (materialNames.count(name) == 0) // not defined already
956 {
957 materials[name] = material;
958 materialNames.insert(name);
959 }
960 else
961 {throw BDSException(__METHOD_NAME__, "Material \"" + name + "\" already exists");}
962}
963
964void BDSMaterials::AddExistingMaterialAlias(const G4String &existingMaterialName,
965 G4String alias)
966{
967 alias = BDS::LowerCase(alias);
968 G4Material* material = GetMaterial(existingMaterialName);
969 aliases[alias] = material; // store in lower case as that's how we search
970 aliasNames.insert(alias);
971
972 // cache aliases for a given material for feedback
973 auto search = materialToAliases.find(material);
974 if (search == materialToAliases.end())
975 {materialToAliases[material] = {};}
976 materialToAliases[material].push_back(alias);
977}
978
979void BDSMaterials::AddMaterial(G4String name,
980 G4double Z,
981 G4double A,
982 G4double density,
983 G4State state,
984 G4double temperature,
985 G4double pressure)
986{
987 // convention: material name in small letters (to be able to find materials regardless of capitalisation)
988 name = BDS::LowerCase(name);
989 DensityCheck(density, name);
990
991 G4Material* tmpMaterial = new G4Material(name,
992 Z,
993 A*CLHEP::g/CLHEP::mole,
994 density*CLHEP::g/CLHEP::cm3,
995 state,
996 temperature*CLHEP::kelvin,
997 pressure*CLHEP::atmosphere);
998 AddMaterial(tmpMaterial, name);
999}
1000
1001template <typename Type>
1002void BDSMaterials::AddMaterial(G4String name,
1003 G4double density,
1004 G4State state,
1005 G4double temperature,
1006 G4double pressure,
1007 const std::list<G4String>& components,
1008 const std::list<Type>& componentFractions)
1009{
1010 name = BDS::LowerCase(name);
1011 DensityCheck(density, name);
1012
1013 // Recursive check on the components of a gas material to check if the ideal gas equation is respected
1014 if(state == G4State::kStateGas && instance != nullptr)
1015 {
1016 BDSIdealGas::CheckGasLaw(name,temperature, pressure, density, components, componentFractions);
1017 }
1018
1019 G4Material* tmpMaterial = new G4Material(name,
1020 density*CLHEP::g/CLHEP::cm3,
1021 (G4int)components.size(),
1022 state,
1023 temperature*CLHEP::kelvin,
1024 pressure*CLHEP::atmosphere);
1025 std::list<G4String>::const_iterator sIter;
1026 typename std::list<Type>::const_iterator dIter;
1027 for (sIter = components.begin(), dIter = componentFractions.begin();
1028 sIter != components.end();
1029 ++sIter, ++dIter)
1030 {
1031#ifdef BDSDEBUG
1032 G4cout << "BDSMaterials::AddMaterial: " << *sIter << G4endl;
1033#endif
1034 G4Element* element = CheckElement(*sIter);
1035 if (element)
1036 {tmpMaterial->AddElement(element, (*dIter));}
1037 else
1038 {tmpMaterial->AddMaterial(GetMaterial(*sIter), (*dIter));}
1039 }
1040 AddMaterial(tmpMaterial, name);
1041}
1042
1043G4Material* BDSMaterials::GetMaterial(G4String material) const
1044{
1045 if (material.empty())
1046 {throw BDSException(__METHOD_NAME__, "empty material name");}
1047 G4String materialOriginal = material;
1048 // for short names we assume they're elements so we prefix with G4_ and
1049 // get them from NIST
1050 G4String nistString ("G4_");
1051 if (material.length() <= 2)
1052#if G4VERSION_NUMBER > 1099
1053 {material = nistString + material;}
1054#else
1055 {material.prepend(nistString);}
1056#endif
1057
1058 G4String start = material.substr(0,3);
1059 if (nistString == start)
1060 {
1061#ifdef BDSDEBUG
1062 G4cout << "Using NIST material " << material << G4endl;
1063#endif
1064 G4Material* mat = G4NistManager::Instance()->FindOrBuildMaterial(material, true, true);
1065 if (!mat)
1066 {throw BDSException(__METHOD_NAME__, "\"" + material + "\" could not be found by NIST.");}
1067 return mat;
1068 }
1069 else
1070 {
1071 // find material regardless of capitalisation
1072 material = BDS::LowerCase(material);
1073
1074 // search predefined + parser materials
1075 if (materialNames.count(material) == 1)
1076 {return materials.at(material);}
1077 else if (aliasNames.count(material) == 1)
1078 {return aliases.at(material);}
1079 else
1080 {
1081 // search aliases
1082 if (externalMaterialNames.count(material) == 1)
1083 {return externalMaterials.at(material);}
1084 else
1085 {// can't find it -> warn and exit
1086 ListMaterials();
1087 throw BDSException(__METHOD_NAME__, "\"" + materialOriginal + "\" is unknown.");
1088 }
1089 }
1090 }
1091}
1092
1093void BDSMaterials::CheckForConflictingMaterialsAfterLoad(const G4String& geometryFileName,
1094 const G4String& componentName) const
1095{
1096 G4MaterialTable* table = G4Material::GetMaterialTable();
1097
1098 G4bool check = false;
1099 std::map<G4String, G4int> nameCount;
1100 for (const auto& mat : *table)
1101 {
1102 G4String name = mat->GetName();
1103 auto search = nameCount.find(name);
1104 if (search == nameCount.end())
1105 {nameCount[name] = 0;}
1106 nameCount[name] += 1;
1107 check = check || nameCount[name] > 1; // flag for efficiency - don't loop again if we don't need to
1108 }
1109
1110 if (check)
1111 {
1112 for (const auto& nc: nameCount)
1113 {
1114 if (nc.second > 1)
1115 {
1116 G4String msg = "the material \"" + nc.first + "\" has been defined more\n";
1117 msg += "than once now and will cause the wrong material to be used for any future usages.\n";
1118 msg += "Error caused by GDML file \""+geometryFileName+"\" in component \""+componentName+"\"\n";
1119 msg += "This is most likely due to a material name in the GDML file conflicting with a predefined one in BDSIM.";
1120 if (BDS::StartsWith(BDS::LowerCase(nc.first), "g4_"))
1121 {BDS::Warning(msg);} // only warn for a NIST one as ultimately it won't be that different even if redefined from reloading
1122 else
1123 {throw BDSException(__METHOD_NAME__, msg);}
1124 }
1125 }
1126 }
1127}
1128
1129
1130void BDSMaterials::CacheMaterialsFromGDML(const std::map<G4String, G4Material*>& materialsGDML)
1131{
1132 // this function is really just concerning GDML material caching and not
1133 // all external format name caching...
1134 for (const auto& kv : materialsGDML)
1135 {
1136 G4String nameLower = BDS::LowerCase(kv.first);
1137
1138 // We have to allow names that are in bdsim materials as the user could have
1139 // used just a bdsim material by name. However, we can't know if that was one
1140 // that was constructed uniquely with the same name. For this, we need to check
1141 // the material table in the above function.
1142 if (BDS::StartsWith(nameLower, "g4_") || materials.find(nameLower) != materials.end())
1143 {continue;} // a Geant4 material or a BDSIM one
1144
1145 if (externalMaterialNames.count(nameLower) == 1)
1146 {
1147 G4String msg = "the material \""+kv.first+"\" is already defined and has\n";
1148 msg += "already been loaded from a previous GDML file(s) and is ambiguous.\n";
1149 msg += "Please prepend with the BDSIM element used to load the file to be explicit.";
1150 throw BDSException(__METHOD_NAME__, msg);
1151 }
1152
1153 // it's ok for a GDML material to have a material name the same as a BDSIM
1154 // alias as only the real name will conflict
1155
1156 externalMaterials[nameLower] = kv.second;
1157 externalMaterialNames.insert(nameLower);
1158 }
1159}
1160
1161void BDSMaterials::AddElement(G4Element* element, const G4String& symbol)
1162{
1163 if (CheckElement(symbol) != nullptr)
1164 {throw BDSException(__METHOD_NAME__, "Element \"" + symbol + "\" already exists.");}
1165
1166 elements.insert(make_pair(symbol, element));
1167#ifdef BDSDEBUG
1168 G4cout << "New element : " << symbol << G4endl;
1169#endif
1170}
1171
1172void BDSMaterials::AddElement(const G4String& name,
1173 const G4String& symbol,
1174 G4double Z,
1175 G4double A)
1176{
1177 G4Element* tmpElement = new G4Element(name, symbol, Z, A*CLHEP::g/CLHEP::mole);
1178 AddElement(tmpElement, symbol);
1179}
1180
1181void BDSMaterials::DensityCheck(G4double density,
1182 const G4String& materialName) const
1183{
1184 if (density > 1e2)
1185 {// so greater than 100g / cm3, the densest natural material is around 23g/cm3
1186 G4String msg = "material \"" + materialName + "\"has a density higher than 100g/cm3! Perhaps check this!\n";
1187 msg += "Density: " + std::to_string(density) + " g/cm3... proceeding";
1188 BDS::Warning(__METHOD_NAME__, msg);
1189 }
1190}
1191
1192G4Element* BDSMaterials::CheckElement(const G4String& symbol) const
1193{
1194 // first look in defined element list
1195 auto iter = elements.find(symbol);
1196 if(iter != elements.end())
1197 {return (*iter).second;}
1198 else
1199 {
1200 G4Element* element = G4NistManager::Instance()->FindOrBuildElement(symbol, true);
1201 return element;
1202 }
1203}
1204
1205G4Element* BDSMaterials::GetElement(const G4String& symbol) const
1206{
1207 G4Element* element = CheckElement(symbol);
1208 if (!element)
1209 {throw BDSException(__METHOD_NAME__, "Element \"" + symbol + "\" could not be found.");}
1210 return element;
1211}
1212
1213void BDSMaterials::PrintBasicMaterialMassFraction(G4Material* material) const
1214{
1215 // simpler version of geant4 code
1216 for (G4int i = 0; i < (G4int)material->GetNumberOfElements(); i++)
1217 {
1218 G4cout << (*(material->GetElementVector()))[i]->GetName() << "\t "
1219 << (material->GetFractionVector()[i])/CLHEP::perCent << " %" << G4endl;
1220 }
1221}
1222
1224{
1225 auto flagsCache(G4cout.flags());
1226 G4cout << __METHOD_NAME__ << G4endl;
1227 // always print out vacuum composition
1228 G4Material* vacuum = GetMaterial("vacuum");
1229 G4cout<< "\"vacuum\" composition: " << G4endl;
1231 G4cout<< "pressure = " << vacuum->GetPressure()/CLHEP::bar << " bar" << G4endl;
1232 G4cout<< "temperature = " << vacuum->GetTemperature()/CLHEP::kelvin << " K" << G4endl;
1233 G4cout<< "density = " << vacuum->GetDensity()/(CLHEP::g/CLHEP::cm3)<< " g/cm^3" << G4endl << G4endl;
1234
1235 G4cout << "All elements are available with their 1 or 2 letter chemical symbol. ie C or G4_C" << G4endl << G4endl;
1236
1237 if (!elements.empty())
1238 {
1239 G4cout << "Extra defined elements are:" << G4endl;
1240 for (const auto& element : elements)
1241 {G4cout << std::left << std::setw(12) << element.second->GetName() << " - " << element.second->GetSymbol() << G4endl;}
1242 G4cout << G4endl;
1243 }
1244
1245 G4cout << "Defined materials are:" << G4endl;
1246 for (const auto& material : materials)
1247 {
1248 G4cout << material.first;
1249 G4String realName = material.second->GetName();
1250 if (realName != material.first)
1251 {G4cout << " (" << material.second->GetName() << ")" << G4endl;}
1252 else
1253 {G4cout << G4endl;}
1254
1255 auto aliasSearch = materialToAliases.find(material.second);
1256 if (aliasSearch != materialToAliases.end())
1257 {
1258 const auto v = aliasSearch->second;
1259 G4cout << "Aliases: ";
1260 for (const auto& n : v)
1261 {G4cout << "\"" << n << "\" ";}
1262 G4cout << G4endl;
1263 }
1264 }
1265 G4cout << G4endl;
1266 G4cout << "All aliases: (alias, real name)" << G4endl;
1267 for (const auto& aliasMaterial : aliases)
1268 {
1269 G4cout << aliasMaterial.first << " : " << aliasMaterial.second->GetName() << G4endl;}
1270 G4cout << G4endl;
1271 G4cout << "Available NIST materials are:" << G4endl;
1272 G4NistManager::Instance()->ListMaterials("all");
1273
1274 if (!externalMaterialNames.empty())
1275 {
1276 G4cout << "Loaded materials from external geometry:" << G4endl;
1277 for (const auto& mat: externalMaterialNames)
1278 {G4cout << mat << G4endl;}
1279 }
1280 G4cout.flags(flagsCache);
1281}
1282
1283BDSMaterials::~BDSMaterials()
1284{
1285 for (auto& material : materials)
1286 {delete material.second;}
1287 materials.clear();
1288 materialNames.clear();
1289
1290 // we don't delete externalMaterials as any loaded from GDML will be
1291 // deleted by Geant4
1292 externalMaterialNames.clear();
1293
1294 for (auto& element : elements)
1295 {delete element.second;}
1296 elements.clear();
1297
1298 for (G4MaterialPropertiesTable* table : propertiesTables)
1299 {delete table;}
1300
1301 instance = nullptr;
1302}
1303
1305{
1306 // This function uses the list from the parser and prepares
1307 // the necessary materials for this run.
1308#ifdef BDSDEBUG
1309 G4bool debug = true;
1310#else
1311 G4bool debug = false;
1312#endif
1313
1314 // convert the parsed atom list to list of Geant4 G4Elements
1315 if (verbose || debug)
1316 {G4cout << __METHOD_NAME__ << "parsing the atom list..." << G4endl;}
1317 for (const auto& it : BDSParser::Instance()->GetAtoms())
1318 {AddElement(it.name,it.symbol,it.Z,it.A);}
1319 if (verbose || debug)
1320 {G4cout << "size of atom list: "<< BDSParser::Instance()->GetAtoms().size() << G4endl;}
1321
1322 // convert the parsed material list to list of Geant4 G4Materials
1323 if (verbose || debug)
1324 {G4cout << "parsing the material list..."<< G4endl;}
1325 for (auto it : BDSParser::Instance()->GetMaterials())
1326 {
1327 G4State itsState;
1328 if (it.state=="solid")
1329 {itsState = kStateSolid;}
1330 else if (it.state=="liquid")
1331 {itsState = kStateLiquid;}
1332 else if (it.state=="gas")
1333 {itsState = kStateGas;}
1334 else
1335 {
1336 G4cout << "Unknown material state "<< it.state
1337 << ", setting it to default (solid)"
1338 << G4endl;
1339 it.state="solid";
1340 itsState = kStateSolid;
1341 }
1342
1343#ifdef BDSDEBUG
1344 G4cout << "---->adding Material, ";
1345 it.print();
1346#endif
1347
1348 if(it.Z != 0)
1349 {
1350 AddMaterial(it.name,
1351 it.Z,
1352 it.A,
1353 it.density,
1354 itsState,
1355 it.temper,
1356 it.pressure);
1357 }
1358 else if(!(it.components.empty()))
1359 {
1360 std::list<G4String> tempComponents;
1361 for (const auto& jt : it.components)
1362 {tempComponents.emplace_back(G4String(jt));}
1363
1364 if(it.componentsWeights.size()==it.components.size())
1365 {
1366 AddMaterial(it.name,
1367 it.density,
1368 itsState,
1369 it.temper,
1370 it.pressure,
1371 tempComponents,
1372 it.componentsWeights);
1373 }
1374 else if(it.componentsFractions.size()==it.components.size())
1375 {
1376 AddMaterial(it.name,
1377 it.density,
1378 itsState,
1379 it.temper,
1380 it.pressure,
1381 tempComponents,
1382 it.componentsFractions);
1383 }
1384 else
1385 {throw BDSException(__METHOD_NAME__, "Badly defined material - number of components is not equal to number of weights or mass fractions!");}
1386 }
1387 else
1388 {throw BDSException(__METHOD_NAME__, "Badly defined material - need more information!");}
1389 }
1390 if (verbose || debug)
1391 {G4cout << "size of material list: "<< BDSParser::Instance()->GetMaterials().size() << G4endl;}
1392}
1393
1394G4MaterialPropertiesTable* BDSMaterials::CreatePropertiesTable()
1395{
1396 G4MaterialPropertiesTable* table = new G4MaterialPropertiesTable();
1397 propertiesTables.push_back(table);
1398 return table;
1399}
General exception with possible name of object and message.
A class for all material definitions known to BDSIM. Additional materials can be added in the parser ...
void DefineMetals()
Methods called by constructor.
std::set< G4String > aliasNames
Map of other names to existing materials. To avoid double deletion. Also in lower case.
void DefineLHCComponents()
Methods called by constructor.
std::map< G4Material *, std::vector< G4String > > materialToAliases
Keep a vector of possible aliases for every material for print out and user feedback.
void DefineGases()
Methods called by constructor.
void DefineNonMetalSolids()
Methods called by constructor.
void DensityCheck(G4double density, const G4String &materialName) const
Print warning if density suspiciously high. Should be in g/cm3 in G4 units already.
void DefineScintillators()
Methods called by constructor.
void DefineVacuums()
Methods called by constructor.
static BDSMaterials * Instance()
Singleton pattern access.
G4MaterialPropertiesTable * CreatePropertiesTable()
Create new properties table and store in vector.
static BDSMaterials * instance
Singleton instance.
std::set< G4String > materialNames
Map of materials, convention name lowercase.
std::map< G4String, G4Element * > elements
Map of elements, no lowercase convention.
void DefineLiquids()
Methods called by constructor.
G4Material * GetMaterial(G4String material) const
Get material by name.
void PrepareRequiredMaterials(G4bool verbose=false)
converts parser material list
void CacheMaterialsFromGDML(const std::map< G4String, G4Material * > &materialsGDML)
Introduce materials loaded from GDML into this instance.
void ListMaterials() const
output available materials
void DefinePlasmas()
Methods called by constructor.
std::set< G4String > externalMaterialNames
Keep hold of externally constructed materials to indicate conflicts to the user but not to delete.
void CheckForConflictingMaterialsAfterLoad(const G4String &geometryFileName, const G4String &componentName) const
void AddElement(G4Element *element, const G4String &symbol)
Add a G4Element.
void AddMaterial(G4Material *material, G4String name)
Add G4Material.
void DefineSuperconductors()
Methods called by constructor.
G4Element * CheckElement(const G4String &symbol) const
Return element if defined (nullptr if not)
void AddExistingMaterialAlias(const G4String &existingMaterialName, G4String alias)
Add alias to a material.
G4Element * GetElement(const G4String &symbol) const
Get element by name.
void PrintBasicMaterialMassFraction(G4Material *material) const
Print mass fractions of consituents of a given material.
std::vector< G4MaterialPropertiesTable * > propertiesTables
Material tables for storing pointers.
static BDSParser * Instance()
Access method.
Definition BDSParser.cc:30
std::vector< GMAD::Atom > GetAtoms() const
Return the parser list of that object.
Definition BDSParser.hh:97
static bool IsInitialised()
Returns if parser is initialised.
Definition BDSParser.cc:51
const GMAD::Options & GetOptions() const
Return options.
Definition BDSParser.hh:51
std::vector< GMAD::Material > GetMaterials() const
Return the parser list of that object.
Definition BDSParser.hh:106
G4String LowerCase(const G4String &str)
Utility function to simplify lots of syntax changes for pedantic g4 changes.
G4bool StartsWith(const std::string &expression, const std::string &prefix)
Return true if a string "expression" starts with "prefix".