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});
71 if (!props.size())
return nullptr;
72 auto* table =
new G4MaterialPropertiesTable();
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());
99 B2DEBUG(50,
"Creating new Nist Builder instances");
107 G4Material* mat{
nullptr};
115 if (!mat && name.substr(0, 3) !=
"G4_") {
130 if (!mat && showErrors) B2ERROR(
"Material '" << name <<
"' could not be found");
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;
141 scaledMat =
new G4Material(scaled, mat->GetDensity() * *
m_densityScale, mat,
142 mat->GetState(), mat->GetTemperature(), mat->GetPressure());
154 if (!elm) B2ERROR(
"Element '" << name <<
"' could not be found");
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");
204#ifdef __clang_analyzer__
210 mat->AddElement(cmp, component.getFraction());
212 G4Material* cmp =
getMaterial(component.getName());
214 B2ERROR(
"Cannot create material " << parameters.getName() <<
": material " << component.getName() <<
" not found");
215#ifdef __clang_analyzer__
221 mat->AddMaterial(cmp, component.getFraction());
226 mat->SetMaterialPropertiesTable(
createProperties(parameters.getProperties()));
236 string name = parameters.getString(
"@name");
237 B2DEBUG(10,
"Creating Material Config " << name);
238 string stateStr = parameters.getString(
"state",
"undefined");
239 double density = parameters.getDensity(
"density", 0);
240 double temperature = parameters.getDouble(
"temperature", CLHEP::STP_Temperature);
241 double pressure = parameters.getDouble(
"pressure", CLHEP::STP_Pressure / CLHEP::pascal);
251 double sumFractions(0);
254 for (
const GearDir& component : parameters.getNodes(
"Components/Material")) {
255 const string componentName = component.getString();
256 double fraction = component.getDouble(
"@fraction", 1.0);
257 material.
addComponent({componentName,
false, fraction});
258 sumFractions += fraction;
261 for (
const GearDir& element : parameters.getNodes(
"Components/Element")) {
262 const std::string elementName = element.getString();
263 double fraction = element.getDouble(
"@fraction", 1.0);
265 sumFractions += fraction;
269 if (abs(sumFractions - 1) > numeric_limits<double>::epsilon()) {
270 B2WARNING(
"createMaterial " << name <<
": Fractions not normalized, scaling by 1/" << sumFractions);
272 cmp.setFraction(cmp.getFraction() / sumFractions);
277 boost::to_lower(stateStr);
278 G4State state = kStateUndefined;
279 if (stateStr ==
"solid") {
281 }
else if (stateStr ==
"liquid") {
282 state = kStateLiquid;
283 }
else if (stateStr ==
"gas") {
285 }
else if (stateStr !=
"undefined") {
286 B2WARNING(
"createMaterial " << name <<
": Unknown state '" << stateStr <<
"', using undefined");
290 addProperties(material, parameters);
303 G4OpticalSurface* optSurf =
new G4OpticalSurface(surface.
getName(),
304 (G4OpticalSurfaceModel) surface.
getModel(),
305 (G4OpticalSurfaceFinish) surface.
getFinish(),
306 (G4SurfaceType) surface.
getType(),
315 string name = parameters.getString(
"@name",
"OpticalSurface");
316 string modelString = parameters.getString(
"Model",
"glisur");
317 string finishString = parameters.getString(
"Finish",
"polished");
318 string typeString = parameters.getString(
"Type",
"dielectric_dielectric");
319 double value = parameters.getDouble(
"Value", 1.0);
321#define CHECK_ENUM_VALUE(name,value) if (name##String == #value) { name = value; }
322 G4OpticalSurfaceModel model;
323 boost::to_lower(modelString);
324 CHECK_ENUM_VALUE(model, glisur)
325 else CHECK_ENUM_VALUE(model, unified)
326 else CHECK_ENUM_VALUE(model, LUT)
328 B2FATAL(
"Unknown Optical Surface Model: " << modelString);
331 G4OpticalSurfaceFinish finish;
332 boost::to_lower(finishString);
333 CHECK_ENUM_VALUE(finish, polished)
334 else CHECK_ENUM_VALUE(finish, polishedfrontpainted)
335 else CHECK_ENUM_VALUE(finish, polishedbackpainted)
336 else CHECK_ENUM_VALUE(finish, ground)
337 else CHECK_ENUM_VALUE(finish, groundfrontpainted)
338 else CHECK_ENUM_VALUE(finish, groundbackpainted)
339 else CHECK_ENUM_VALUE(finish, polishedlumirrorair)
340 else CHECK_ENUM_VALUE(finish, polishedlumirrorglue)
341 else CHECK_ENUM_VALUE(finish, polishedair)
342 else CHECK_ENUM_VALUE(finish, polishedteflonair)
343 else CHECK_ENUM_VALUE(finish, polishedtioair)
344 else CHECK_ENUM_VALUE(finish, polishedtyvekair)
345 else CHECK_ENUM_VALUE(finish, polishedvm2000air)
346 else CHECK_ENUM_VALUE(finish, polishedvm2000glue)
347 else CHECK_ENUM_VALUE(finish, etchedlumirrorair)
348 else CHECK_ENUM_VALUE(finish, etchedlumirrorglue)
349 else CHECK_ENUM_VALUE(finish, etchedair)
350 else CHECK_ENUM_VALUE(finish, etchedteflonair)
351 else CHECK_ENUM_VALUE(finish, etchedtioair)
352 else CHECK_ENUM_VALUE(finish, etchedtyvekair)
353 else CHECK_ENUM_VALUE(finish, etchedvm2000air)
354 else CHECK_ENUM_VALUE(finish, etchedvm2000glue)
355 else CHECK_ENUM_VALUE(finish, groundlumirrorair)
356 else CHECK_ENUM_VALUE(finish, groundlumirrorglue)
357 else CHECK_ENUM_VALUE(finish, groundair)
358 else CHECK_ENUM_VALUE(finish, groundteflonair)
359 else CHECK_ENUM_VALUE(finish, groundtioair)
360 else CHECK_ENUM_VALUE(finish, groundtyvekair)
361 else CHECK_ENUM_VALUE(finish, groundvm2000air)
362 else CHECK_ENUM_VALUE(finish, groundvm2000glue)
364 B2FATAL(
"Unknown Optical Surface Finish: " << finishString);
368 boost::to_lower(typeString);
369 CHECK_ENUM_VALUE(type, dielectric_metal)
370 else CHECK_ENUM_VALUE(type, dielectric_dielectric)
371 else CHECK_ENUM_VALUE(type, dielectric_LUT)
372 else CHECK_ENUM_VALUE(type, firsov)
373 else CHECK_ENUM_VALUE(type, x_ray)
375 B2FATAL(
"Unknown Optical Surface Type: " << typeString);
377#undef CHECK_ENUM_VALUE
380 addProperties(surface,
GearDir(parameters,
"Properties"));
387 B2DEBUG(50,
"Cleaning G4MaterialPropertiesTable");
388 for (G4MaterialPropertiesTable* prop :
m_PropTables)
delete prop;
391 B2DEBUG(50,
"Cleaning G4Materials");
392 G4MaterialTable& materials = *G4Material::GetMaterialTable();
393 for (G4Material* mat : materials)
delete mat;
395 B2DEBUG(50,
"Cleaning G4Elements");
396 G4ElementTable& elements = *G4Element::GetElementTable();
397 for (G4Element* elm : elements)
delete elm;
399 B2DEBUG(50,
"Cleaning G4Isotopes");
400 auto& isotopes =
const_cast<G4IsotopeTable&
>(*G4Isotope::GetIsotopeTable());
401 for (G4Isotope* iso : isotopes)
delete iso;
409 B2DEBUG(50,
"Clean up material cache");
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.
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
std::vector< GeoMaterialComponent > & getComponents()
get all components
Represent an optical finish of a surface.
const std::string & getName() const
get name of the optical surface
int getFinish() const
get finish of the surface
const std::vector< GeoMaterialProperty > & getProperties() const
get all properties
double getValue() const
get value for the surface condition
int getType() const
get type of the surface
int getModel() const
get model for the surface
void insert(const KEY &key, const VALUE &value)
Insert a key value pair into the cache.
bool retrieve(const KEY &key, VALUE &value)
Retrieve a value from the cache if it exists.
static const double GeV
Standard of [energy, momentum, mass].
Exception to be thrown in case of an empty result.
Thin wrapper around the Geant4 Material system.
GeoOpticalSurface createOpticalSurfaceConfig(const gearbox::Interface ¶meters)
Create Optical Surface Configuration from XML description.
G4Material * getMaterial(const std::string &name, bool showErrors=true)
Get a pointer to the G4Material with the given name.
GeoMaterial createMaterialConfig(const gearbox::Interface ¶meters)
Create Material from XML description.
~Materials()
Destructor for objects that I have created.
G4NistElementBuilder * m_nistElementBuilder
G4NistElementBuilder instance to create chemical elements with correct natural abundances from NIST d...
G4NistMaterialBuilder * m_nistMaterialBuilder
G4NistMaterialBuilder to create predefined materials from NIST database.
static Materials & getInstance()
Get a reference to the singleton instance.
Materials()
Singleton: hide constructor.
G4MaterialPropertiesTable * createProperties(const std::vector< GeoMaterialProperty > &props)
Create a properties table from a vector of properties.
void initBuilders()
Initialize Nist Builder instances.
G4Material * createMaterial(const gearbox::Interface ¶meters)
Create a material from the parameters specified by parameters.
MRUCache< std::string, G4Material * > m_materialCache
Cache for already searched Materials.
std::optional< double > m_densityScale
If set we scale all densities by a given factor.
G4Material * findMaterial(const std::string &name)
find an existing material by name
std::set< std::string > m_ignoreScaling
Names of materials we don't want to scale.
void clear()
Clear all existing materials.
std::vector< G4MaterialPropertiesTable * > m_PropTables
Vector of created G4MaterialProperties objects.
G4OpticalSurface * createOpticalSurface(const gearbox::Interface ¶meters)
Create an optical surface from parameters, will abort on error.
G4Element * getElement(const std::string &name)
Find given chemical element.
Class to store variables with their name which were sent to the logging service.
static double convertValue(double value, const std::string &unitString)
Converts a floating point value to the standard framework unit.
Abstract base class for different kinds of events.