9 #include <geometry/Materials.h>
10 #include <framework/logging/Logger.h>
11 #include <framework/gearbox/GearDir.h>
12 #include <framework/gearbox/Unit.h>
13 #include <geometry/dbobjects/GeoMaterial.h>
14 #include <geometry/dbobjects/GeoOpticalSurface.h>
18 #include <boost/algorithm/string.hpp>
20 #include <G4Material.hh>
21 #include <G4Element.hh>
22 #include <G4NistManager.hh>
23 #include <G4OpticalSurface.hh>
24 #include <G4MaterialPropertiesTable.hh>
26 #include "CLHEP/Units/PhysicalConstants.h"
41 template<
class T>
void addProperties(T&
object,
const gearbox::Interface& parameters)
44 if (parameters.getNumberNodes(
"Property") > 0) {
46 for (
const GearDir& property : parameters.getNodes(
"Property")) {
49 name =
property.getString(
"@name");
50 }
catch (gearbox::PathEmptyError&) {
51 B2ERROR(
"Property at " << property.getPath() <<
" does not have a name attribute, ignoring");
54 const double conversionFactor = Unit::convertValue(1, property.getString(
"@unit",
"GeV"));
55 unsigned int nValues =
property.getNumberNodes(
"value");
56 std::vector<double> energies(nValues, 0);
57 std::vector<double> values(nValues, 0);
58 for (
unsigned int i = 0; i < nValues; ++i) {
59 GearDir value(property,
"value", i + 1);
60 energies[i] = value.getDouble(
"@energy") * conversionFactor;
61 values[i] = value.getDouble();
63 object.addProperty({name, energies, values});
69 G4MaterialPropertiesTable* Materials::createProperties(
const std::vector<GeoMaterialProperty>& props)
71 if (!props.size())
return nullptr;
72 auto* table =
new G4MaterialPropertiesTable();
73 m_PropTables.push_back(table);
75 std::vector<double> energies = prop.getEnergies();
76 std::vector<double> values = prop.getValues();
77 const size_t n = values.size();
79 for (
double& energy : energies) energy *= CLHEP::GeV / Unit::GeV;
80 table->AddProperty(prop.getName().c_str(), energies.data(), values.data(), n);
87 static unique_ptr<Materials> instance(
new Materials());
91 Materials::~Materials()
96 void Materials::initBuilders()
98 if (!m_nistMaterialBuilder) {
99 B2DEBUG(50,
"Creating new Nist Builder instances");
100 m_nistElementBuilder =
new G4NistElementBuilder(0);
101 m_nistMaterialBuilder =
new G4NistMaterialBuilder(m_nistElementBuilder, 0);
105 G4Material* Materials::findMaterial(
const string& name)
107 G4Material* mat{
nullptr};
108 if (m_materialCache.retrieve(name, mat)) {
112 mat = m_nistMaterialBuilder->FindOrBuildMaterial(name);
115 if (!mat && name.substr(0, 3) !=
"G4_") {
117 mat = m_nistMaterialBuilder->FindOrBuildMaterial(
"G4_" + name);
119 if (!mat) mat = m_nistMaterialBuilder->FindOrBuildMaterial(
"G4_" + boost::to_upper_copy(name));
123 m_materialCache.insert(name, mat);
127 G4Material* Materials::getMaterial(
const string& name,
bool showErrors)
129 G4Material* mat = findMaterial(name);
130 if (!mat && showErrors) B2ERROR(
"Material '" << name <<
"' could not be found");
133 if (m_densityScale) {
134 if (m_ignoreScaling.count(name) > 0)
return mat;
135 if (name.substr(0, 7) ==
"scaled:")
136 B2WARNING(
"Requested an already scaled material ... scaling once more" <<
LogVar(
"material", name));
137 std::string scaled =
"scaled:" + std::to_string(*m_densityScale) +
":" + name;
138 G4Material* scaledMat = findMaterial(scaled);
141 scaledMat =
new G4Material(scaled, mat->GetDensity() * *m_densityScale, mat,
142 mat->GetState(), mat->GetTemperature(), mat->GetPressure());
143 m_materialCache.insert(scaled, scaledMat);
150 G4Element* Materials::getElement(
const string& name)
153 G4Element* elm = m_nistElementBuilder->FindOrBuildElement(name);
154 if (!elm) B2ERROR(
"Element '" << name <<
"' could not be found");
160 GeoMaterial material = createMaterialConfig(parameters);
161 return createMaterial(material);
164 G4Material* Materials::createMaterial(
const GeoMaterial& parameters)
166 G4Material* oldmat = getMaterial(parameters.getName(),
false);
169 B2ERROR(
"Material with name " << parameters.getName() <<
" already existing");
172 B2DEBUG(10,
"Creating Material " << parameters.getName());
175 double density = parameters.getDensity() * CLHEP::g / CLHEP::cm3;
176 if (density < 1e-25) {
181 if (component.getIselement()) {
182 B2ERROR(
"createMaterial " << parameters.getName()
183 <<
": Cannot calculate density when adding elements, please provde a density");
186 G4Material* mat = getMaterial(component.getName());
188 B2ERROR(
"createMaterial " << parameters.getName() <<
": Material '" << component.getName() <<
"' not found");
191 density += mat->GetDensity() * component.getFraction();
196 G4Material* mat =
new G4Material(parameters.getName(), density, parameters.getComponents().size(),
197 (G4State)parameters.getState(), parameters.getTemperature(), parameters.getPressure() * CLHEP::pascal);
200 if (component.getIselement()) {
201 G4Element* cmp = getElement(component.getName());
203 B2ERROR(
"Cannot create material " << parameters.getName() <<
": element " << component.getName() <<
" not found");
206 mat->AddElement(cmp, component.getFraction());
208 G4Material* cmp = getMaterial(component.getName());
210 B2ERROR(
"Cannot create material " << parameters.getName() <<
": material " << component.getName() <<
" not found");
211 #ifdef __clang_analyzer__
217 mat->AddMaterial(cmp, component.getFraction());
222 mat->SetMaterialPropertiesTable(createProperties(parameters.getProperties()));
225 m_materialCache.insert(parameters.getName(), mat);
232 string name = parameters.getString(
"@name");
233 B2DEBUG(10,
"Creating Material Config " << name);
234 string stateStr = parameters.getString(
"state",
"undefined");
235 double density = parameters.getDensity(
"density", 0);
236 double temperature = parameters.getDouble(
"temperature", CLHEP::STP_Temperature);
237 double pressure = parameters.getDouble(
"pressure", CLHEP::STP_Pressure / CLHEP::pascal);
247 double sumFractions(0);
250 for (
const GearDir& component : parameters.getNodes(
"Components/Material")) {
251 const string componentName = component.getString();
252 double fraction = component.getDouble(
"@fraction", 1.0);
253 material.
addComponent({componentName,
false, fraction});
254 sumFractions += fraction;
257 for (
const GearDir& element : parameters.getNodes(
"Components/Element")) {
258 const std::string elementName = element.getString();
259 double fraction = element.getDouble(
"@fraction", 1.0);
261 sumFractions += fraction;
265 if (abs(sumFractions - 1) > numeric_limits<double>::epsilon()) {
266 B2WARNING(
"createMaterial " << name <<
": Fractions not normalized, scaling by 1/" << sumFractions);
268 cmp.setFraction(cmp.getFraction() / sumFractions);
273 boost::to_lower(stateStr);
274 G4State state = kStateUndefined;
275 if (stateStr ==
"solid") {
277 }
else if (stateStr ==
"liquid") {
278 state = kStateLiquid;
279 }
else if (stateStr ==
"gas") {
281 }
else if (stateStr !=
"undefined") {
282 B2WARNING(
"createMaterial " << name <<
": Unknown state '" << stateStr <<
"', using undefined");
286 addProperties(material, parameters);
294 return createOpticalSurface(surface);
299 G4OpticalSurface* optSurf =
new G4OpticalSurface(surface.
getName(),
300 (G4OpticalSurfaceModel) surface.
getModel(),
301 (G4OpticalSurfaceFinish) surface.
getFinish(),
302 (G4SurfaceType) surface.
getType(),
304 optSurf->SetMaterialPropertiesTable(createProperties(surface.
getProperties()));
311 string name = parameters.getString(
"@name",
"OpticalSurface");
312 string modelString = parameters.getString(
"Model",
"glisur");
313 string finishString = parameters.getString(
"Finish",
"polished");
314 string typeString = parameters.getString(
"Type",
"dielectric_dielectric");
315 double value = parameters.getDouble(
"Value", 1.0);
317 #define CHECK_ENUM_VALUE(name,value) if (name##String == #value) { name = value; }
318 G4OpticalSurfaceModel model;
319 boost::to_lower(modelString);
320 CHECK_ENUM_VALUE(model, glisur)
321 else CHECK_ENUM_VALUE(model, unified)
322 else CHECK_ENUM_VALUE(model, LUT)
324 B2FATAL(
"Unknown Optical Surface Model: " << modelString);
327 G4OpticalSurfaceFinish finish;
328 boost::to_lower(finishString);
329 CHECK_ENUM_VALUE(finish, polished)
330 else CHECK_ENUM_VALUE(finish, polishedfrontpainted)
331 else CHECK_ENUM_VALUE(finish, polishedbackpainted)
332 else CHECK_ENUM_VALUE(finish, ground)
333 else CHECK_ENUM_VALUE(finish, groundfrontpainted)
334 else CHECK_ENUM_VALUE(finish, groundbackpainted)
335 else CHECK_ENUM_VALUE(finish, polishedlumirrorair)
336 else CHECK_ENUM_VALUE(finish, polishedlumirrorglue)
337 else CHECK_ENUM_VALUE(finish, polishedair)
338 else CHECK_ENUM_VALUE(finish, polishedteflonair)
339 else CHECK_ENUM_VALUE(finish, polishedtioair)
340 else CHECK_ENUM_VALUE(finish, polishedtyvekair)
341 else CHECK_ENUM_VALUE(finish, polishedvm2000air)
342 else CHECK_ENUM_VALUE(finish, polishedvm2000glue)
343 else CHECK_ENUM_VALUE(finish, etchedlumirrorair)
344 else CHECK_ENUM_VALUE(finish, etchedlumirrorglue)
345 else CHECK_ENUM_VALUE(finish, etchedair)
346 else CHECK_ENUM_VALUE(finish, etchedteflonair)
347 else CHECK_ENUM_VALUE(finish, etchedtioair)
348 else CHECK_ENUM_VALUE(finish, etchedtyvekair)
349 else CHECK_ENUM_VALUE(finish, etchedvm2000air)
350 else CHECK_ENUM_VALUE(finish, etchedvm2000glue)
351 else CHECK_ENUM_VALUE(finish, groundlumirrorair)
352 else CHECK_ENUM_VALUE(finish, groundlumirrorglue)
353 else CHECK_ENUM_VALUE(finish, groundair)
354 else CHECK_ENUM_VALUE(finish, groundteflonair)
355 else CHECK_ENUM_VALUE(finish, groundtioair)
356 else CHECK_ENUM_VALUE(finish, groundtyvekair)
357 else CHECK_ENUM_VALUE(finish, groundvm2000air)
358 else CHECK_ENUM_VALUE(finish, groundvm2000glue)
360 B2FATAL(
"Unknown Optical Surface Finish: " << finishString);
364 boost::to_lower(typeString);
365 CHECK_ENUM_VALUE(type, dielectric_metal)
366 else CHECK_ENUM_VALUE(type, dielectric_dielectric)
367 else CHECK_ENUM_VALUE(type, dielectric_LUT)
368 else CHECK_ENUM_VALUE(type, firsov)
369 else CHECK_ENUM_VALUE(type, x_ray)
371 B2FATAL(
"Unknown Optical Surface Type: " << typeString);
373 #undef CHECK_ENUM_VALUE
376 addProperties(surface,
GearDir(parameters,
"Properties"));
380 void Materials::clear()
383 B2DEBUG(50,
"Cleaning G4MaterialPropertiesTable");
384 for (G4MaterialPropertiesTable* prop : m_PropTables)
delete prop;
385 m_PropTables.clear();
387 B2DEBUG(50,
"Cleaning G4Materials");
388 G4MaterialTable& materials = *G4Material::GetMaterialTable();
389 for (G4Material* mat : materials)
delete mat;
391 B2DEBUG(50,
"Cleaning G4Elements");
392 G4ElementTable& elements = *G4Element::GetElementTable();
393 for (G4Element* elm : elements)
delete elm;
395 B2DEBUG(50,
"Cleaning G4Isotopes");
396 auto& isotopes =
const_cast<G4IsotopeTable&
>(*G4Isotope::GetIsotopeTable());
397 for (G4Isotope* iso : isotopes)
delete iso;
400 delete m_nistMaterialBuilder;
401 delete m_nistElementBuilder;
402 m_nistMaterialBuilder =
nullptr;
403 m_nistElementBuilder =
nullptr;
405 B2DEBUG(50,
"Clean up material cache");
406 m_materialCache.clear();
GearDir is the basic class used for accessing the parameter store.
Class to represent a material informaion in the Database.
void setPressure(double pressure)
set the pressure of the material (in default framework units
void setState(int state)
set the state of the material
void addComponent(const GeoMaterialComponent &component)
add a component to the material.
std::vector< GeoMaterialComponent > & getComponents()
get all components
void setName(const std::string &name)
set the name of the material
void setTemperature(double temperature)
set the temperature of the material (in default framework units
void setDensity(double density)
set the density of the material (in default framework units
Represent an optical finish of a surface.
int getFinish() const
get finish of the surface
const std::string & getName() const
get name of the optical surface
double getValue() const
get value for the surface condition
const std::vector< GeoMaterialProperty > & getProperties() const
get all properties
int getType() const
get type of the surface
int getModel() const
get model for the surface
Exception to be thrown in case of an empty result.
Thin wrapper around the Geant4 Material system.
Class to store variables with their name which were sent to the logging service.
Abstract base class for different kinds of events.