Belle II Software light-2406-ragdoll
Materials.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
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>
15
16#include <memory>
17#include <limits>
18#include <boost/algorithm/string.hpp>
19
20#include <G4Material.hh>
21#include <G4Element.hh>
22#include <G4NistManager.hh>
23#include <G4OpticalSurface.hh>
24#include <G4MaterialPropertiesTable.hh>
25
26#include "CLHEP/Units/PhysicalConstants.h"
27
28using namespace std;
29
30namespace Belle2 {
35 namespace geometry {
36 namespace {
41 template<class T> void addProperties(T& object, const gearbox::Interface& parameters)
42 {
43 // check if we have properties defined for this material
44 if (parameters.getNumberNodes("Property") > 0) {
45 //Apparantly we have properties, so lets add them to the Material
46 for (const GearDir& property : parameters.getNodes("Property")) {
47 string name;
48 try {
49 name = property.getString("@name");
50 } catch (gearbox::PathEmptyError&) {
51 B2ERROR("Property at " << property.getPath() << " does not have a name attribute, ignoring");
52 continue;
53 }
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();
62 }
63 object.addProperty({name, energies, values});
64 }
65 }
66 }
67 }
68
69 G4MaterialPropertiesTable* Materials::createProperties(const std::vector<GeoMaterialProperty>& props)
70 {
71 if (!props.size()) return nullptr;
72 auto* table = new G4MaterialPropertiesTable();
73 m_PropTables.push_back(table);
74 for (const GeoMaterialProperty& prop : props) {
75 std::vector<double> energies = prop.getEnergies();
76 std::vector<double> values = prop.getValues();
77 const size_t n = values.size();
78 // convert energies to Geant4 Units
79 for (double& energy : energies) energy *= CLHEP::GeV / Unit::GeV;
80 table->AddProperty(prop.getName().c_str(), energies.data(), values.data(), n);
81 }
82 return table;
83 }
84
86 {
87 static unique_ptr<Materials> instance(new Materials());
88 return *instance;
89 }
90
92 {
93 clear();
94 }
95
97 {
99 B2DEBUG(50, "Creating new Nist Builder instances");
100 m_nistElementBuilder = new G4NistElementBuilder(0);
101 m_nistMaterialBuilder = new G4NistMaterialBuilder(m_nistElementBuilder, 0);
102 }
103 }
104
105 G4Material* Materials::findMaterial(const string& name)
106 {
107 G4Material* mat{nullptr};
108 if (m_materialCache.retrieve(name, mat)) {
109 return mat;
110 }
111 initBuilders();
112 mat = m_nistMaterialBuilder->FindOrBuildMaterial(name);
113
114 //Try different combinations of the Material name to fallback to predefined G4 Elements
115 if (!mat && name.substr(0, 3) != "G4_") {
116 //Mainly for materials from single elements, e.g. G4_Al, G4_Si
117 mat = m_nistMaterialBuilder->FindOrBuildMaterial("G4_" + name);
118 //For predefined materials, e.g. G4_AIR, G4_TEFLON
119 if (!mat) mat = m_nistMaterialBuilder->FindOrBuildMaterial("G4_" + boost::to_upper_copy(name));
120 }
121
122 //Insert into cache
123 m_materialCache.insert(name, mat);
124 return mat;
125 }
126
127 G4Material* Materials::getMaterial(const string& name, bool showErrors)
128 {
129 G4Material* mat = findMaterial(name);
130 if (!mat && showErrors) B2ERROR("Material '" << name << "' could not be found");
131 // There is a chance that we want to scale densities of all materials for studies.
132 // Now we have the original so we can look to the scaled one or create it if it's missing
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);
139 if (!scaledMat) {
140 assert(mat);
141 scaledMat = new G4Material(scaled, mat->GetDensity() * *m_densityScale, mat,
142 mat->GetState(), mat->GetTemperature(), mat->GetPressure());
143 m_materialCache.insert(scaled, scaledMat);
144 }
145 return scaledMat;
146 }
147 return mat;
148 }
149
150 G4Element* Materials::getElement(const string& name)
151 {
152 initBuilders();
153 G4Element* elm = m_nistElementBuilder->FindOrBuildElement(name);
154 if (!elm) B2ERROR("Element '" << name << "' could not be found");
155 return elm;
156 }
157
158 G4Material* Materials::createMaterial(const gearbox::Interface& parameters)
159 {
160 GeoMaterial material = createMaterialConfig(parameters);
161 return createMaterial(material);
162 }
163
164 G4Material* Materials::createMaterial(const GeoMaterial& parameters)
165 {
166 G4Material* oldmat = getMaterial(parameters.getName(), false);
167 if (oldmat) {
168 //We cannot modify or delete materials, so we just use existing ones
169 B2ERROR("Material with name " << parameters.getName() << " already existing");
170 return oldmat;
171 }
172 B2DEBUG(10, "Creating Material " << parameters.getName());
173 //If density is negative or smaller than epsilon we should calculate the
174 //density from the used materials
175 double density = parameters.getDensity() * CLHEP::g / CLHEP::cm3;
176 if (density < 1e-25) {
177 density = 0;
178 for (const GeoMaterialComponent& component : parameters.getComponents()) {
179 //Check if we can calculate density, only works if we just add materials,
180 //elements do not have density
181 if (component.getIselement()) {
182 B2ERROR("createMaterial " << parameters.getName()
183 << ": Cannot calculate density when adding elements, please provde a density");
184 return nullptr;
185 }
186 G4Material* mat = getMaterial(component.getName());
187 if (!mat) {
188 B2ERROR("createMaterial " << parameters.getName() << ": Material '" << component.getName() << "' not found");
189 return nullptr;
190 }
191 density += mat->GetDensity() * component.getFraction();
192 }
193 }
194
195 //Finally, create Material and add all components
196 G4Material* mat = new G4Material(parameters.getName(), density, parameters.getComponents().size(),
197 (G4State)parameters.getState(), parameters.getTemperature(), parameters.getPressure() * CLHEP::pascal);
198
199 for (const GeoMaterialComponent& component : parameters.getComponents()) {
200 if (component.getIselement()) {
201 G4Element* cmp = getElement(component.getName());
202 if (!cmp) {
203 B2ERROR("Cannot create material " << parameters.getName() << ": element " << component.getName() << " not found");
204 return nullptr;
205 }
206 mat->AddElement(cmp, component.getFraction());
207 } else {
208 G4Material* cmp = getMaterial(component.getName());
209 if (!cmp) {
210 B2ERROR("Cannot create material " << parameters.getName() << ": material " << component.getName() << " not found");
211#ifdef __clang_analyzer__
212 continue;
213#else
214 return nullptr;
215#endif
216 }
217 mat->AddMaterial(cmp, component.getFraction());
218 }
219 }
220
221 //add properties
222 mat->SetMaterialPropertiesTable(createProperties(parameters.getProperties()));
223
224 //Insert into cache and return
225 m_materialCache.insert(parameters.getName(), mat);
226 return mat;
227 }
228
230 {
231 //Get straightforward parameters from gearbox
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); // * CLHEP::g / CLHEP::cm3;
236 double temperature = parameters.getDouble("temperature", CLHEP::STP_Temperature);
237 double pressure = parameters.getDouble("pressure", CLHEP::STP_Pressure / CLHEP::pascal);
238
239 // set the simple ones like they are
240 GeoMaterial material;
241 material.setName(name);
242 material.setPressure(pressure);
243 material.setTemperature(temperature);
244 material.setDensity(density);
245
246 //Sum up fractions to see if they are normalized
247 double sumFractions(0);
248
249 // Add all component materials
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;
255 }
256 // Add all component elements
257 for (const GearDir& element : parameters.getNodes("Components/Element")) {
258 const std::string elementName = element.getString();
259 double fraction = element.getDouble("@fraction", 1.0);
260 material.addComponent({elementName, true, fraction});
261 sumFractions += fraction;
262 }
263
264 //Warn if the fractions are not normalized
265 if (abs(sumFractions - 1) > numeric_limits<double>::epsilon()) {
266 B2WARNING("createMaterial " << name << ": Fractions not normalized, scaling by 1/" << sumFractions);
267 for (GeoMaterialComponent& cmp : material.getComponents()) {
268 cmp.setFraction(cmp.getFraction() / sumFractions);
269 }
270 }
271
272 //Determine material state
273 boost::to_lower(stateStr);
274 G4State state = kStateUndefined;
275 if (stateStr == "solid") {
276 state = kStateSolid;
277 } else if (stateStr == "liquid") {
278 state = kStateLiquid;
279 } else if (stateStr == "gas") {
280 state = kStateGas;
281 } else if (stateStr != "undefined") {
282 B2WARNING("createMaterial " << name << ": Unknown state '" << stateStr << "', using undefined");
283 }
284 material.setState(state);
285
286 addProperties(material, parameters);
287 // all done, return material description
288 return material;
289 }
290
291 G4OpticalSurface* Materials::createOpticalSurface(const gearbox::Interface& parameters)
292 {
293 GeoOpticalSurface surface = createOpticalSurfaceConfig(parameters);
294 return createOpticalSurface(surface);
295 }
296
297 G4OpticalSurface* Materials::createOpticalSurface(const GeoOpticalSurface& surface)
298 {
299 G4OpticalSurface* optSurf = new G4OpticalSurface(surface.getName(),
300 (G4OpticalSurfaceModel) surface.getModel(),
301 (G4OpticalSurfaceFinish) surface.getFinish(),
302 (G4SurfaceType) surface.getType(),
303 surface.getValue());
304 optSurf->SetMaterialPropertiesTable(createProperties(surface.getProperties()));
305 //m_OptSurfaces.push_back(optSurf);
306 return optSurf;
307 }
308
310 {
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);
316
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)
323 else {
324 B2FATAL("Unknown Optical Surface Model: " << modelString);
325 }
326
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)
359 else {
360 B2FATAL("Unknown Optical Surface Finish: " << finishString);
361 }
362
363 G4SurfaceType type;
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)
370 else {
371 B2FATAL("Unknown Optical Surface Type: " << typeString);
372 }
373#undef CHECK_ENUM_VALUE
374
375 GeoOpticalSurface surface(name, model, finish, type, value);
376 addProperties(surface, GearDir(parameters, "Properties"));
377 return surface;
378 }
379
381 {
382 // delete all property tables we have
383 B2DEBUG(50, "Cleaning G4MaterialPropertiesTable");
384 for (G4MaterialPropertiesTable* prop : m_PropTables) delete prop;
385 m_PropTables.clear();
386 // and last but not least: get rid of all materials
387 B2DEBUG(50, "Cleaning G4Materials");
388 G4MaterialTable& materials = *G4Material::GetMaterialTable();
389 for (G4Material* mat : materials) delete mat;
390 materials.clear();
391 B2DEBUG(50, "Cleaning G4Elements");
392 G4ElementTable& elements = *G4Element::GetElementTable();
393 for (G4Element* elm : elements) delete elm;
394 elements.clear();
395 B2DEBUG(50, "Cleaning G4Isotopes");
396 auto& isotopes = const_cast<G4IsotopeTable&>(*G4Isotope::GetIsotopeTable());
397 for (G4Isotope* iso : isotopes) delete iso;
398 isotopes.clear();
399 // delete material and element builder as they keep indices to materials they created :/
402 m_nistMaterialBuilder = nullptr;
403 m_nistElementBuilder = nullptr;
404 // finally, get rid of the cache, it's invalid now anyway
405 B2DEBUG(50, "Clean up material cache");
407 }
408
409 } //geometry namespace
411} //Belle2 namespace
GearDir is the basic class used for accessing the parameter store.
Definition: GearDir.h:31
Component of a material.
Property of a material.
Class to represent a material informaion in the Database.
Definition: GeoMaterial.h:22
void setPressure(double pressure)
set the pressure of the material (in default framework units
Definition: GeoMaterial.h:35
void setState(int state)
set the state of the material
Definition: GeoMaterial.h:29
void addComponent(const GeoMaterialComponent &component)
add a component to the material.
Definition: GeoMaterial.h:37
void setName(const std::string &name)
set the name of the material
Definition: GeoMaterial.h:27
void setTemperature(double temperature)
set the temperature of the material (in default framework units
Definition: GeoMaterial.h:33
void setDensity(double density)
set the density of the material (in default framework units
Definition: GeoMaterial.h:31
std::vector< GeoMaterialComponent > & getComponents()
get all components
Definition: GeoMaterial.h:51
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.
Definition: MRUCache.h:79
void clear()
Clear cache.
Definition: MRUCache.h:125
bool retrieve(const KEY &key, VALUE &value)
Retrieve a value from the cache if it exists.
Definition: MRUCache.h:104
static const double GeV
Standard of [energy, momentum, mass].
Definition: Unit.h:51
Exception to be thrown in case of an empty result.
Definition: Interface.h:35
Thin wrapper around the Geant4 Material system.
Definition: Materials.h:48
GeoOpticalSurface createOpticalSurfaceConfig(const gearbox::Interface &parameters)
Create Optical Surface Configuration from XML description.
Definition: Materials.cc:309
G4Material * getMaterial(const std::string &name, bool showErrors=true)
Get a pointer to the G4Material with the given name.
Definition: Materials.cc:127
GeoMaterial createMaterialConfig(const gearbox::Interface &parameters)
Create Material from XML description.
Definition: Materials.cc:229
~Materials()
Destructor for objects that I have created.
Definition: Materials.cc:91
G4NistElementBuilder * m_nistElementBuilder
G4NistElementBuilder instance to create chemical elements with correct natural abundances from NIST d...
Definition: Materials.h:168
G4NistMaterialBuilder * m_nistMaterialBuilder
G4NistMaterialBuilder to create predefined materials from NIST database.
Definition: Materials.h:170
static Materials & getInstance()
Get a reference to the singleton instance.
Definition: Materials.cc:85
Materials()
Singleton: hide constructor.
Definition: Materials.h:152
G4MaterialPropertiesTable * createProperties(const std::vector< GeoMaterialProperty > &props)
Create a properties table from a vector of properties.
Definition: Materials.cc:69
void initBuilders()
Initialize Nist Builder instances.
Definition: Materials.cc:96
G4Material * createMaterial(const gearbox::Interface &parameters)
Create a material from the parameters specified by parameters.
Definition: Materials.cc:158
MRUCache< std::string, G4Material * > m_materialCache
Cache for already searched Materials.
Definition: Materials.h:161
std::optional< double > m_densityScale
If set we scale all densities by a given factor.
Definition: Materials.h:179
G4Material * findMaterial(const std::string &name)
find an existing material by name
Definition: Materials.cc:105
std::set< std::string > m_ignoreScaling
Names of materials we don't want to scale.
Definition: Materials.h:181
void clear()
Clear all existing materials.
Definition: Materials.cc:380
std::vector< G4MaterialPropertiesTable * > m_PropTables
Vector of created G4MaterialProperties objects.
Definition: Materials.h:164
G4OpticalSurface * createOpticalSurface(const gearbox::Interface &parameters)
Create an optical surface from parameters, will abort on error.
Definition: Materials.cc:291
G4Element * getElement(const std::string &name)
Find given chemical element.
Definition: Materials.cc:150
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.
Definition: UnitConst.cc:129
Abstract base class for different kinds of events.
Definition: ClusterUtils.h:24
STL namespace.