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);
140 scaledMat =
new G4Material(scaled, mat->GetDensity() * *m_densityScale, mat,
141 mat->GetState(), mat->GetTemperature(), mat->GetPressure());
142 m_materialCache.insert(scaled, scaledMat);
149 G4Element* Materials::getElement(
const string& name)
152 G4Element* elm = m_nistElementBuilder->FindOrBuildElement(name);
153 if (!elm) B2ERROR(
"Element '" << name <<
"' could not be found");
159 GeoMaterial material = createMaterialConfig(parameters);
160 return createMaterial(material);
163 G4Material* Materials::createMaterial(
const GeoMaterial& parameters)
165 G4Material* oldmat = getMaterial(parameters.getName(),
false);
168 B2ERROR(
"Material with name " << parameters.getName() <<
" already existing");
171 B2DEBUG(10,
"Creating Material " << parameters.getName());
174 double density = parameters.getDensity() * CLHEP::g / CLHEP::cm3;
175 if (density < 1e-25) {
180 if (component.getIselement()) {
181 B2ERROR(
"createMaterial " << parameters.getName()
182 <<
": Cannot calculate density when adding elements, please provde a density");
185 G4Material* mat = getMaterial(component.getName());
187 B2ERROR(
"createMaterial " << parameters.getName() <<
": Material '" << component.getName() <<
"' not found");
190 density += mat->GetDensity() * component.getFraction();
195 G4Material* mat =
new G4Material(parameters.getName(), density, parameters.getComponents().size(),
196 (G4State)parameters.getState(), parameters.getTemperature(), parameters.getPressure() * CLHEP::pascal);
199 if (component.getIselement()) {
200 G4Element* cmp = getElement(component.getName());
202 B2ERROR(
"Cannot create material " << parameters.getName() <<
": element " << component.getName() <<
" not found");
205 mat->AddElement(cmp, component.getFraction());
207 G4Material* cmp = getMaterial(component.getName());
209 B2ERROR(
"Cannot create material " << parameters.getName() <<
": material " << component.getName() <<
" not found");
212 mat->AddMaterial(cmp, component.getFraction());
217 mat->SetMaterialPropertiesTable(createProperties(parameters.getProperties()));
220 m_materialCache.insert(parameters.getName(), mat);
227 string name = parameters.getString(
"@name");
228 B2DEBUG(10,
"Creating Material Config " << name);
229 string stateStr = parameters.getString(
"state",
"undefined");
230 double density = parameters.getDensity(
"density", 0);
231 double temperature = parameters.getDouble(
"temperature", CLHEP::STP_Temperature);
232 double pressure = parameters.getDouble(
"pressure", CLHEP::STP_Pressure / CLHEP::pascal);
242 double sumFractions(0);
245 for (
const GearDir& component : parameters.getNodes(
"Components/Material")) {
246 const string componentName = component.getString();
247 double fraction = component.getDouble(
"@fraction", 1.0);
248 material.
addComponent({componentName,
false, fraction});
249 sumFractions += fraction;
252 for (
const GearDir& element : parameters.getNodes(
"Components/Element")) {
253 const std::string elementName = element.getString();
254 double fraction = element.getDouble(
"@fraction", 1.0);
256 sumFractions += fraction;
260 if (abs(sumFractions - 1) > numeric_limits<double>::epsilon()) {
261 B2WARNING(
"createMaterial " << name <<
": Fractions not normalized, scaling by 1/" << sumFractions);
263 cmp.setFraction(cmp.getFraction() / sumFractions);
268 boost::to_lower(stateStr);
269 G4State state = kStateUndefined;
270 if (stateStr ==
"solid") {
272 }
else if (stateStr ==
"liquid") {
273 state = kStateLiquid;
274 }
else if (stateStr ==
"gas") {
276 }
else if (stateStr !=
"undefined") {
277 B2WARNING(
"createMaterial " << name <<
": Unknown state '" << stateStr <<
"', using undefined");
281 addProperties(material, parameters);
289 return createOpticalSurface(surface);
294 G4OpticalSurface* optSurf =
new G4OpticalSurface(surface.
getName(),
295 (G4OpticalSurfaceModel) surface.
getModel(),
296 (G4OpticalSurfaceFinish) surface.
getFinish(),
297 (G4SurfaceType) surface.
getType(),
299 optSurf->SetMaterialPropertiesTable(createProperties(surface.
getProperties()));
306 string name = parameters.getString(
"@name",
"OpticalSurface");
307 string modelString = parameters.getString(
"Model",
"glisur");
308 string finishString = parameters.getString(
"Finish",
"polished");
309 string typeString = parameters.getString(
"Type",
"dielectric_dielectric");
310 double value = parameters.getDouble(
"Value", 1.0);
312 #define CHECK_ENUM_VALUE(name,value) if (name##String == #value) { name = value; }
313 G4OpticalSurfaceModel model;
314 boost::to_lower(modelString);
315 CHECK_ENUM_VALUE(model, glisur)
316 else CHECK_ENUM_VALUE(model, unified)
317 else CHECK_ENUM_VALUE(model, LUT)
319 B2FATAL(
"Unknown Optical Surface Model: " << modelString);
322 G4OpticalSurfaceFinish finish;
323 boost::to_lower(finishString);
324 CHECK_ENUM_VALUE(finish, polished)
325 else CHECK_ENUM_VALUE(finish, polishedfrontpainted)
326 else CHECK_ENUM_VALUE(finish, polishedbackpainted)
327 else CHECK_ENUM_VALUE(finish, ground)
328 else CHECK_ENUM_VALUE(finish, groundfrontpainted)
329 else CHECK_ENUM_VALUE(finish, groundbackpainted)
330 else CHECK_ENUM_VALUE(finish, polishedlumirrorair)
331 else CHECK_ENUM_VALUE(finish, polishedlumirrorglue)
332 else CHECK_ENUM_VALUE(finish, polishedair)
333 else CHECK_ENUM_VALUE(finish, polishedteflonair)
334 else CHECK_ENUM_VALUE(finish, polishedtioair)
335 else CHECK_ENUM_VALUE(finish, polishedtyvekair)
336 else CHECK_ENUM_VALUE(finish, polishedvm2000air)
337 else CHECK_ENUM_VALUE(finish, polishedvm2000glue)
338 else CHECK_ENUM_VALUE(finish, etchedlumirrorair)
339 else CHECK_ENUM_VALUE(finish, etchedlumirrorglue)
340 else CHECK_ENUM_VALUE(finish, etchedair)
341 else CHECK_ENUM_VALUE(finish, etchedteflonair)
342 else CHECK_ENUM_VALUE(finish, etchedtioair)
343 else CHECK_ENUM_VALUE(finish, etchedtyvekair)
344 else CHECK_ENUM_VALUE(finish, etchedvm2000air)
345 else CHECK_ENUM_VALUE(finish, etchedvm2000glue)
346 else CHECK_ENUM_VALUE(finish, groundlumirrorair)
347 else CHECK_ENUM_VALUE(finish, groundlumirrorglue)
348 else CHECK_ENUM_VALUE(finish, groundair)
349 else CHECK_ENUM_VALUE(finish, groundteflonair)
350 else CHECK_ENUM_VALUE(finish, groundtioair)
351 else CHECK_ENUM_VALUE(finish, groundtyvekair)
352 else CHECK_ENUM_VALUE(finish, groundvm2000air)
353 else CHECK_ENUM_VALUE(finish, groundvm2000glue)
355 B2FATAL(
"Unknown Optical Surface Finish: " << finishString);
359 boost::to_lower(typeString);
360 CHECK_ENUM_VALUE(type, dielectric_metal)
361 else CHECK_ENUM_VALUE(type, dielectric_dielectric)
362 else CHECK_ENUM_VALUE(type, dielectric_LUT)
363 else CHECK_ENUM_VALUE(type, firsov)
364 else CHECK_ENUM_VALUE(type, x_ray)
366 B2FATAL(
"Unknown Optical Surface Type: " << typeString);
368 #undef CHECK_ENUM_VALUE
371 addProperties(surface,
GearDir(parameters,
"Properties"));
375 void Materials::clear()
378 B2DEBUG(50,
"Cleaning G4MaterialPropertiesTable");
379 for (G4MaterialPropertiesTable* prop : m_PropTables)
delete prop;
380 m_PropTables.clear();
382 B2DEBUG(50,
"Cleaning G4Materials");
383 G4MaterialTable& materials = *G4Material::GetMaterialTable();
384 for (G4Material* mat : materials)
delete mat;
386 B2DEBUG(50,
"Cleaning G4Elements");
387 G4ElementTable& elements = *G4Element::GetElementTable();
388 for (G4Element* elm : elements)
delete elm;
390 B2DEBUG(50,
"Cleaning G4Isotopes");
391 auto& isotopes =
const_cast<G4IsotopeTable&
>(*G4Isotope::GetIsotopeTable());
392 for (G4Isotope* iso : isotopes)
delete iso;
395 delete m_nistMaterialBuilder;
396 delete m_nistElementBuilder;
397 m_nistMaterialBuilder =
nullptr;
398 m_nistElementBuilder =
nullptr;
400 B2DEBUG(50,
"Clean up material cache");
401 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.