ATLAS Offline Software
Loading...
Searching...
No Matches
InDetMaterialManager.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4
8#include "GeoModelKernel/GeoIntrusivePtr.h"
9#include "GeoModelKernel/GeoMaterial.h"
10#include "GeoModelKernel/GeoElement.h"
11#include "GeoModelKernel/Units.h"
12#include "GaudiKernel/SystemOfUnits.h"
18
19#include <iostream>
20#include <iomanip>
21#include <cmath> //for std::abs
22#include <stdexcept>
23
24//for checking whether a value is a reliable denominator
26
27// Constructor
28InDetMaterialManager::InDetMaterialManager(const std::string& managerName,
29 StoreGateSvc* detStore)
30 : AthMessaging(managerName),
31 m_managerName(managerName),
33 m_athenaComps(nullptr) {
35}
36
37// Constructor
38InDetMaterialManager::InDetMaterialManager(const std::string& managerName,
39 StoreGateSvc* detStore,
40 const IRDBRecordset_ptr& weightTable,
41 const std::string& space,
42 bool extraFunctionality)
43 : AthMessaging(managerName),
44 m_managerName(managerName),
45 m_extraFunctionality(extraFunctionality),
46 m_athenaComps(nullptr) {
48
49 if (weightTable) addWeightTable(weightTable, space);
50
51 // For testing we add a few materials.
52 //m_weightMap["sct::CoolingBlock"] = MaterialByWeight(2.418*CLHEP::gram);
53 //m_weightMap["sct::CoolingBlock"] = MaterialByWeight(2*CLHEP::gram);
54 //m_weightMap["sct::BrlHybrid"] = MaterialByWeight("sct::Hybrid", 8*CLHEP::gram);
55 //m_weightMap["sct::FwdHybrid"] = MaterialByWeight("std::Carbon", 7.662*CLHEP::gram);
56}
57
58InDetMaterialManager::InDetMaterialManager(const std::string& managerName, StoreGateSvc* detStore,
59 const IRDBRecordset_ptr& weightTable,
60 const IRDBRecordset_ptr& compositionTable,
61 const std::string& space)
62 : AthMessaging(managerName),
63 m_managerName(managerName),
65 m_athenaComps(nullptr) {
67
68 if (weightTable) addWeightTable(weightTable, space);
69 if (compositionTable) addCompositionTable(compositionTable, space);
70}
71
72InDetMaterialManager::InDetMaterialManager(const std::string& managerName,
73 InDetDD::AthenaComps* athenaComps)
74 : AthMessaging(managerName),
75 m_managerName(managerName),
77 m_athenaComps(athenaComps) {
80}
81
83
86 return detStore->tryRetrieve<StoredMaterialManager>("MATERIALS");
87}
88
89const GeoElement*
90InDetMaterialManager::getElement(const std::string& elementName) {
92 std::string errorMessage("Null pointer to Stored Material Manager!");
93 ATH_MSG_FATAL(errorMessage);
94 throw std::runtime_error(errorMessage);
95 }
96 return m_materialManager->getElement(elementName);
97}
98
99const GeoMaterial*
100InDetMaterialManager::getMaterial(const std::string& materialName) {
101 return extraScaledMaterial(materialName, getMaterialInternal(materialName));
102}
103
104bool
105InDetMaterialManager::hasMaterial(const std::string& materialName) const {
106 return m_weightMap.find(materialName) != m_weightMap.end();
107}
108
109const GeoMaterial*
110InDetMaterialManager::getMaterialInternal(const std::string& materialName) {
111 // First check local store of materials. If not found then get it from the GeoModel
112 // manager.
113 const GeoMaterial* material = getAdditionalMaterial(materialName);
114
115 if (!material) {
116 if(!m_materialManager) {
117 std::string errorMessage("Null pointer to Stored Material Manager!");
118 ATH_MSG_FATAL(errorMessage);
119 throw std::runtime_error(errorMessage);
120 }
121 // This prints error message if not found.
122 material = m_materialManager->getMaterial(materialName);
123 }
124 return material;
125}
126
127const GeoMaterial*
128InDetMaterialManager::getAdditionalMaterial(const std::string& materialName) const {
129 MaterialStore::const_iterator iter;
130 if ((iter = m_store.find(materialName)) != m_store.end()) {
131 return iter->second;
132 } else {
133 return nullptr;
134 }
135}
136
137const GeoMaterial*
139 const double volumeTot,
140 const double volume1, const std::string& matName1,
141 const double volume2, const std::string& matName2
142 ) {
143 std::vector<std::string> baseMaterials;
144 std::vector<double> fracWeight;
145 baseMaterials.reserve(2);
146 fracWeight.reserve(2);
147
148 ATH_MSG_DEBUG("Composite material : " << volumeTot / Gaudi::Units::cm3 << " = " << volume1 / Gaudi::Units::cm3
149 << " + " << volume2 / Gaudi::Units::cm3);
150 ATH_MSG_DEBUG("Composite material : " << matName1 << " " << matName2);
151
152 double density1, density2;
153
154 MaterialWeightMap::const_iterator iter;
155 if ((iter = m_weightMap.find(matName1)) != m_weightMap.end()) {
156 const GeoMaterial* mat1 = getMaterialForVolume(matName1, volume1);
157 density1 = mat1->getDensity();
158 ATH_MSG_DEBUG("Composite material 1 - weight : " << density1 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
159 } else {
160 const GeoMaterial* mat1 = getMaterial(matName1);
161 density1 = mat1->getDensity();
162 ATH_MSG_DEBUG("Composite material 1 - standard : " << density1 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
163 }
164
165 if ((iter = m_weightMap.find(matName2)) != m_weightMap.end()) {
166 const GeoMaterial* mat2 = getMaterialForVolume(matName2, volume2);
167 density2 = mat2->getDensity();
168 ATH_MSG_DEBUG("Composite material 2 - weight : " << density2 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
169 } else {
170 const GeoMaterial* mat2 = getMaterial(matName2);
171 density2 = mat2->getDensity();
172 ATH_MSG_DEBUG("Composite material 2 - standard : " << density2 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
173 }
174
175 double weight1 = density1 * volume1;
176 double weight2 = density2 * volume2;
177 double invWeightTot = 1.0 / (weight1 + weight2);
178
179 double density = (weight1 + weight2) / volumeTot;
180
181 double frac1 = weight1 / (weight1 + weight2);
182 double frac2 = weight2 / (weight1 + weight2);
183 double density_2 = 1.0 / (frac1 / density1 + frac2 / density2);
184 double density_3 = (weight1 + weight2) / (volume1 + volume2);
185 ATH_MSG_DEBUG("-> weights : " << weight1 / (GeoModelKernelUnits::gram) << " " << weight2 / (GeoModelKernelUnits::gram));
186 ATH_MSG_DEBUG("-> density : " << density / (GeoModelKernelUnits::gram / Gaudi::Units::cm3) << " " << density_2 /
187 (GeoModelKernelUnits::gram / Gaudi::Units::cm3) << " " << density_3 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
188
189
190 baseMaterials.push_back(matName1);
191 baseMaterials.push_back(matName2);
192 fracWeight.push_back(weight1 * invWeightTot);
193 fracWeight.push_back(weight2 * invWeightTot);
194
195 return getMaterial(newMatName, baseMaterials, fracWeight, density);
196}
197
198// This creates a new material with specified density.
199
200// If a newName is supplied it creates the new material even if the orginal material
201// has the same density. It however first checks if the material with NewName exists.
202
203// If no new name is supplied then it checks the density of
204// the existing material. If it is consistent it returns the material.
205// If it is different it creates a material with the string "Modified" added to the
206// name.
207
208
209const GeoMaterial*
210InDetMaterialManager::getMaterial(const std::string& origMaterialName,
211 double density,
212 const std::string& newName) {
213 return extraScaledMaterial(origMaterialName, newName,
214 getMaterialInternal(origMaterialName, density, newName));
215}
216
217const GeoMaterial*
218InDetMaterialManager::getMaterialInternal(const std::string& origMaterialName,
219 double density,
220 const std::string& newName) {
221 std::string newName2 = newName;
222 bool newNameProvided = !newName2.empty();
223 if (!newNameProvided) {
224 newName2 = origMaterialName + "Modified";
225 }
226
227 const GeoMaterial* newMaterial = nullptr;
228
229 // First see if we already have the modified material
230 const GeoMaterial* material = getAdditionalMaterial(newName2);
231 if (material) {
232 if (!compareDensity(material->getDensity(), density)) {
233 ATH_MSG_WARNING("Density is not consistent for material " << newName2
234 << " " << material->getDensity() / (GeoModelKernelUnits::gram / Gaudi::Units::cm3)
235 << " / " << density / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
236 }
237 newMaterial = material;
238 } else {
239 const GeoMaterial* origMaterial = getMaterialInternal(origMaterialName);
240 newMaterial = origMaterial;
241 if (origMaterial) {
242 // If no new name was provided we check if the density is compatible
243 // and if so we return the original material.
244 if (newNameProvided || !compareDensity(origMaterial->getDensity(), density)) {
245 // create new material
246 GeoMaterial* newMaterialTmp = new GeoMaterial(newName2, density);
247 newMaterialTmp->add(const_cast<GeoMaterial*>(origMaterial), 1.);
248 addMaterial(newMaterialTmp);
249 newMaterial = newMaterialTmp;
250 }
251 }
252 }
253 return newMaterial;
254}
255
256const GeoMaterial*
257InDetMaterialManager::getMaterialScaled(const std::string& origMaterialName,
258 double scaleFactor,
259 const std::string& newName) {
260 return extraScaledMaterial(origMaterialName, newName,
261 getMaterialScaledInternal(origMaterialName, scaleFactor, newName));
262}
263
264const GeoMaterial*
265InDetMaterialManager::getMaterialScaledInternal(const std::string& origMaterialName,
266 double scaleFactor,
267 const std::string& newName) {
268 // Don't allow large scale factors
269 if (scaleFactor > 1000 || scaleFactor < 0.001) {
270 ATH_MSG_ERROR("Scale factor must be between 0.001 and 1000.");
271 return nullptr;
272 }
273
274 const GeoMaterial* origMaterial = getMaterialInternal(origMaterialName);
275
276 // If scalefactor is 1 and no new name is requested
277 // then just return the orginal material
278 if (newName.empty() && scaleFactor == 1.) return origMaterial;
279
280 const GeoMaterial* newMaterial = nullptr;
281
282 if (origMaterial) {
283 double density = origMaterial->getDensity() * scaleFactor;
284 std::string newName2 = newName;
285 if (newName2.empty()) {
286 // Create name using the scale factor.
287 int scaleInt = static_cast<int>(scaleFactor * 10000);
288 int scale1 = scaleInt / 10000;
289 int scale2 = scaleInt % 10000;
290
291 std::ostringstream os;
292 os << origMaterialName << scale1 << "_" << std::setw(4) << std::setfill('0') << scale2;
293 newName2 = os.str();
294 }
295
296 newMaterial = getMaterialInternal(origMaterialName, density, newName2);
297 }
298
299 return newMaterial;
300}
301
302void
303InDetMaterialManager::addMaterial(GeoMaterial* material) {
304 GeoIntrusivePtr<const GeoMaterial> matPtr{material};
305 std::string name(material->getName());
306 if (m_store.find(name) != m_store.end()) {
307 ATH_MSG_WARNING("Ignoring attempt to redefine an existing material: " << name);
308 // Delete the material if it is not already ref counted.
309 //std::cout << m_store[name] << std::endl;
310 } else {
311 material->lock();
312 m_store[name] = std::move(matPtr);
313
314 ATH_MSG_DEBUG("Created new material: " << name << ", " << material->getDensity() /
315 (Gaudi::Units::g / Gaudi::Units::cm3) << " g/cm3");
316 }
317}
318
319bool
320InDetMaterialManager::compareDensity(double d1, double d2) const {
321 if (close_to_zero(d2)){
322 throw (std::runtime_error("InDetMaterialManager:compareDensity: Density is zero"));
323 }
324 return(std::abs(d1 / d2 - 1.) < 1e-5);
325}
326
327void
328InDetMaterialManager::addWeightTable(const IRDBRecordset_ptr& weightTable, const std::string& space) {
329 ATH_MSG_DEBUG("Reading in weight table: " << weightTable->nodeName());
330 // If not using geometryDBSvc revert to old version
331 if (!db()) {
332 ATH_MSG_DEBUG("GeometryDBSvc not available. Using old version.");
333 addWeightTableOld(weightTable, space);
334 return;
335 }
336 for (unsigned int i = 0; i < db()->getTableSize(weightTable); i++) {
337 std::string materialName = db()->getString(weightTable, "MATERIAL", i);
338 if (!space.empty()) {
339 materialName = space + "::" + materialName;
340 }
341 std::string materialBase;
342 if (db()->testField(weightTable, "BASEMATERIAL", i)) {
343 materialBase = db()->getString(weightTable, "BASEMATERIAL", i);
344 }
345 double weight = db()->getDouble(weightTable, "WEIGHT", i) * GeoModelKernelUnits::gram;
346 //std::cout << materialName << " " << materialBase << " " << weight/CLHEP::g << std::endl;
347
348 bool linearWeightFlag = false;
349 if (m_extraFunctionality && db()->testField(weightTable, "LINWEIGHTFLAG", i)) {
350 linearWeightFlag = db()->getInt(weightTable, "LINWEIGHTFLAG", i);
351 }
352
353 if (m_weightMap.find(materialName) != m_weightMap.end()) {
354 ATH_MSG_WARNING("Material: " << materialName << " already exists in weight table");
355 } else {
356 ATH_MSG_DEBUG("Adding " << materialName
357 << " weight " << weight
358 << " linearWeightFlag " << linearWeightFlag
359 << " raw weight " << db()->getDouble(weightTable, "WEIGHT", i)
360 << " m_extraFunctionality " << m_extraFunctionality
361 << " to weight table");
362 m_weightMap[materialName] = MaterialByWeight(materialBase, weight, linearWeightFlag);
363 }
364 }
365}
366
367void
368InDetMaterialManager::addWeightMaterial(const std::string& materialName, const std::string& materialBase, double weight,
369 int linearWeightFlag) {
370 // Weight in gr
371 weight = weight * GeoModelKernelUnits::gram;
372
373 if (m_weightMap.find(materialName) != m_weightMap.end()) {
374 ATH_MSG_WARNING("Material: " << materialName << " already exists in weight table");
375 } else {
376 ATH_MSG_DEBUG("Adding " << materialName
377 << " weight " << weight
378 << " linearWeightFlag " << linearWeightFlag
379 << " to weight table");
380 m_weightMap[materialName] = MaterialByWeight(materialBase, weight, linearWeightFlag);
381 }
382}
383
384void
385InDetMaterialManager::addWeightTableOld(const IRDBRecordset_ptr& weightTable, const std::string& space) {
386 for (unsigned int i = 0; i < weightTable->size(); i++) {
387 const IRDBRecord* record = (*weightTable)[i];
388 std::string materialName = record->getString("MATERIAL");
389 if (!space.empty()) {
390 materialName = space + "::" + materialName;
391 }
392 std::string materialBase;
393 if (!record->isFieldNull("BASEMATERIAL")) {
394 materialBase = record->getString("BASEMATERIAL");
395 }
396 double weight = record->getDouble("WEIGHT") * GeoModelKernelUnits::gram;
397 //std::cout << materialName << " " << materialBase << " " << weight/CLHEP::g << std::endl;
398
399 bool linearWeightFlag = false;
401 linearWeightFlag = record->getInt("LINWEIGHTFLAG");
402 }
403
404 if (m_weightMap.find(materialName) != m_weightMap.end()) {
405 ATH_MSG_WARNING("Material: " << materialName << " already exists in weight table");
406 } else {
407 m_weightMap[materialName] = MaterialByWeight(materialBase, weight, linearWeightFlag);
408 }
409 }
410}
411
412void
413InDetMaterialManager::addCompositionTable(const IRDBRecordset_ptr& compositionTable, const std::string& space) {
414 ATH_MSG_DEBUG("Reading in composition table: " << compositionTable->nodeName());
415
416 if (!db()) {
417 ATH_MSG_ERROR("GeometryDBSvc not available. Unable to read in composition table.");
418 }
419 for (unsigned int i = 0; i < db()->getTableSize(compositionTable); i++) {
420 std::string materialName = db()->getString(compositionTable, "MATERIAL", i);
421 if (!space.empty()) {
422 materialName = space + "::" + materialName;
423 }
424
425 std::string componentName = db()->getString(compositionTable, "COMPONENT", i);
426 int count = db()->getInt(compositionTable, "COUNT", i);
427 double factor = db()->getDouble(compositionTable, "FACTOR", i);
428 double actualLength = db()->getDouble(compositionTable, "ACTUALLENGTH", i);
429
430 m_matCompositionMap.insert(std::pair<std::string, MaterialComponent>(materialName,
431 MaterialComponent(componentName,
432 count * factor,
433 actualLength)));
434 }
435}
436
437void
439 if (!scalingTable) return;
440
441 if (db()->getTableSize(scalingTable) == 0) return;
442
443 ATH_MSG_DEBUG("Reading in extra material scaling table: " << scalingTable->nodeName());
444 if (!db()) {
445 ATH_MSG_ERROR("GeometryDBSvc not available. Unable to read in scaling table.");
446 }
447 for (unsigned int i = 0; i < db()->getTableSize(scalingTable); i++) {
448 std::string materialName = db()->getString(scalingTable, "MATERIAL", i);
449 double scalingFactor = db()->getDouble(scalingTable, "FACTOR", i);
450
451 if (msgLvl(MSG::DEBUG)) {
452 if (scalingFactor >= 0 || scalingFactor == 1) {
453 msg(MSG::DEBUG) << "Material " << materialName << " will be scaled by: " << scalingFactor << endmsg;
454 } else {
455 // -ve or scalefactor = 1 means will not be scaled.
456 msg(MSG::DEBUG) << "Material " << materialName << " will be NOT be scaled." << endmsg;
457 }
458 }
459 if (m_scalingMap.find(materialName) != m_scalingMap.end()) {
460 ATH_MSG_WARNING("Overriding material: " << materialName << " which already exists in scaling table");
461 }
462 m_scalingMap[materialName] = scalingFactor;
463 }
464}
465
466const GeoMaterial*
467InDetMaterialManager::getMaterialForVolume(const std::string& materialName, double volume, const std::string& newName) {
468 // Make sure we have a valid volume size.
469 if (volume <= 0) {
470 ATH_MSG_ERROR("Invalid volume : " << volume);
471 return nullptr;
472 }
473
474 // Find if material is in the weight table.
475 // If so we use the information to create a material with the
476 // density calculated from the volume and weight. If a base material
477 // is specified in the weight table, then a new material is made
478 // which is the same as the base material but with the new
479 // density. If no base material is specified then there should be a
480 // material already existing with that name. If the existing material already has the
481 // correct density it is used, otherwise a new material is created
482 // with the string "Modified" added to the material name.
483
484 MaterialWeightMap::const_iterator iter;
485 if ((iter = m_weightMap.find(materialName)) != m_weightMap.end()) {
486 const std::string& materialBase = iter->second.name;
487 double weight = iter->second.weight;
488 double density = weight / volume;
489 if (iter->second.linearWeightFlag) {
490 ATH_MSG_ERROR("Material defined by linear weight cannot be created with getMaterialForVolume method: " <<
491 materialName);
492 }
493
494 ATH_MSG_VERBOSE("Found material in weight table - name, base, weight(g), volume(cm3), density(g/cm3): "
495 << materialName << ", "
496 << materialBase << ", "
497 << weight / GeoModelKernelUnits::gram << ", "
498 << volume / Gaudi::Units::cm3 << ", "
499 << density / (Gaudi::Units::g / Gaudi::Units::cm3));
500
501 if (materialBase.empty()) {
502 return getMaterial(materialName, density, newName);
503 } else {
504 if (newName.empty()) {
505 return getMaterial(materialBase, density, materialName);
506 } else {
507 return getMaterial(materialBase, density, newName);
508 }
509 }
510 } else {
511 // If not in the weight table we just return the material.
512 // This is not an error.
513 ATH_MSG_VERBOSE("Material not in weight table, using standard material: "
514 << materialName
515 << ", volume(cm3) = " << volume / Gaudi::Units::cm3);
516 return getMaterial(materialName);
517 }
518}
519
520const GeoMaterial*
521InDetMaterialManager::getMaterialForVolumeLength(const std::string& materialName, double volume, double length,
522 const std::string& newName) {
523 // In the case there is no material composition table (MaterialCompositionMap) and no linear weights are used this
524 // will
525 // behave the same way as getMaterialForVolume.
526 // If the material is in the MaterialCompositionMap it will build a material using the components
527 // from that table. If any components are defined as a linear weight the length is used to calculate the
528 // weight (ie linear weight * length).
529
530
531 std::string name;
532 if (newName.empty()) {
533 name = materialName;
534 } else {
535 name = newName;
536 }
537
538 // Make sure we have a valid volume size.
539 if (volume <= 0 || length <= 0) {
540 ATH_MSG_ERROR("Invalid volume or length : " << volume << ", " << length);
541 return nullptr;
542 }
543
544 // First look in the predefinded collections
545 std::pair<MaterialCompositionMap::const_iterator, MaterialCompositionMap::const_iterator> iterRange;
546 iterRange = m_matCompositionMap.equal_range(materialName);
547 if (iterRange.first != m_matCompositionMap.end()) {
548 ATH_MSG_VERBOSE("Found material in material composition table:" << materialName);
549
550 std::vector<double> factors;
551 std::vector<std::string> components;
552 for (MaterialCompositionMap::const_iterator iter = iterRange.first; iter != iterRange.second; ++iter) {
553 double factorTmp = iter->second.factor;
554 if (iter->second.actualLength > 0) factorTmp *= iter->second.actualLength / length;
555 factors.push_back(factorTmp);
556 components.push_back(iter->second.name);
557 }
558 return getMaterialForVolumeLength(name, components, factors, volume, length);
559 }
560
561 // Next look in weight table
562 MaterialWeightMap::const_iterator iter;
563 if ((iter = m_weightMap.find(materialName)) != m_weightMap.end()) {
564 const std::string& materialBase = iter->second.name;
565 double weight = iter->second.weight;
566 double density = weight / volume;
567 if (iter->second.linearWeightFlag) weight *= length;
568
569 if (materialBase.empty()) {
570 return getMaterial(materialName, density, newName);
571 } else {
572 return getMaterial(materialBase, density, name);
573 }
574 } else {
575 // Otherwise we just return the material.
576 // This is not an error.
577 ATH_MSG_VERBOSE("Material not in weight table, using standard material: "
578 << materialName
579 << ", volume(cm3) = " << volume / Gaudi::Units::cm3);
580 return getMaterial(materialName);
581 }
582}
583
584const GeoMaterial*
586 const std::string& materialComponent,
587 double factor,
588 double volume,
589 double length) {
590 std::vector<std::string> tmpMaterialComponents(1, materialComponent);
591 std::vector<double> tmpFactors(1, factor);
592 return getMaterialForVolumeLength(name, tmpMaterialComponents, tmpFactors, volume, length);
593}
594
595const GeoMaterial*
597 const std::vector<std::string>& materialComponents,
598 const std::vector<double>& factors,
599 double volume,
600 double length) {
601 // Make sure we have a valid volume size.
602 if (volume <= 0 || length <= 0) {
603 ATH_MSG_ERROR("Invalid volume or length : " << volume << ", " << length);
604 return nullptr;
605 }
606
607 if (!factors.empty() && factors.size() < materialComponents.size()) {
608 ATH_MSG_WARNING("getMaterialForVolumeLength: factor vector size too small. Setting remaining factors to 1.");
609 }
610
611 std::vector<std::string> baseMaterials;
612 std::vector<double> fracWeight;
613 baseMaterials.reserve(materialComponents.size());
614 fracWeight.reserve(materialComponents.size());
615
616 double totWeight = 0;
617 for (unsigned int iComp = 0; iComp < materialComponents.size(); ++iComp) {
618 const std::string& materialName = materialComponents[iComp];
619
620 // First search in MaterialWeightMap
621 MaterialWeightMap::const_iterator iter;
622 if ((iter = m_weightMap.find(materialName)) != m_weightMap.end()) {
623 const std::string& materialBase = iter->second.name;
624 double weight = iter->second.weight;
625
626 if (iComp < factors.size()) {
627 weight *= factors[iComp];
628 }
629 ATH_MSG_DEBUG("Material " << materialName
630 << " found in weight table, weight " << iter->second.weight / GeoModelKernelUnits::gram
631 << " factor " << factors[iComp]
632 << " w*fac*len " << weight * length / GeoModelKernelUnits::gram
633 << " basMat " << materialBase
634 << " linear? " << iter->second.linearWeightFlag);
635
636 if (iter->second.linearWeightFlag) weight *= length;
637 if (materialBase.empty()) {
638 // If no base material then name should refer to an already defined material
639 baseMaterials.push_back(materialName);
640 } else {
641 baseMaterials.push_back(materialBase);
642 }
643 fracWeight.push_back(weight); // Will be normalized later.
644 totWeight += weight;
645 } else {
646 // If not in the weight table we look for a regular material.
647 // I don't think this would normally be intentional so we give a warning message.
648 /*
649 if (msgLvl(MSG::WARNING))
650 msg(MSG::WARNING)
651 << "Component material not in weight table, using standard material: "
652 << materialName << " with weight= "
653 << factors.at(iComp) * length
654 << endmsg;
655 const GeoMaterial * material = getMaterialInternal(materialName);
656 */
657
658 // In this case the factor should correspond to the linear weight
659 double weight = factors.at(iComp) * length * GeoModelKernelUnits::gram;
660
661 // If material not found, will get error message when attempting to make the material. So carry on here.
662 baseMaterials.push_back(materialName);
663 fracWeight.push_back(weight);
664 totWeight += weight;
665 }
666 }
667
668 if (msgLvl(MSG::VERBOSE)) {
669 msg(MSG::VERBOSE) << "Creating material from multiple components: " << name << endmsg;
670 for (unsigned int i = 0; i < materialComponents.size(); ++i) {
671 msg(MSG::VERBOSE) << " Component " << i << ": Name = " << baseMaterials[i]
672 << " Weight(g) = " << fracWeight[i] / Gaudi::Units::g << endmsg;
673 }
674 }
675 if (close_to_zero(totWeight)){
676 ATH_MSG_ERROR("totWeight is zero in InDetMaterialManager::getMaterialForVolumeLength");
677 return nullptr;
678 }
679 for (unsigned int i = 0; i < fracWeight.size(); ++i) {
680 fracWeight[i] /= totWeight;
681 }
682 if (close_to_zero(volume)){
683 ATH_MSG_ERROR("volume is zero in InDetMaterialManager::getMaterialForVolumeLength");
684 return nullptr;
685 }
686 double density = totWeight / volume;
687
688 return getMaterial(name, baseMaterials, fracWeight, density);
689}
690
691
692const GeoMaterial*
693InDetMaterialManager::getMaterial(const std::string& name,
694 const std::vector<std::string>& materialComponents,
695 const std::vector<double>& fracWeight,
696 double density) {
697 return extraScaledMaterial(name, getMaterialInternal(name, materialComponents, fracWeight, density));
698}
699
700const GeoMaterial*
702 const std::vector<std::string>& materialComponents,
703 const std::vector<double>& fracWeight,
704 double density) {
705 const GeoMaterial* newMaterial = nullptr;
706
707 // First see if we already have the material
708 const GeoMaterial* material = getAdditionalMaterial(name);
709
710 if (material) {
711 if (!compareDensity(material->getDensity(), density)) {
712 ATH_MSG_WARNING("Density is not consistent for material " << name);
713 }
714 newMaterial = material;
715 } else {
716 GeoMaterial* newMaterialTmp = new GeoMaterial(name, density);
717 for (unsigned int i = 0; i < materialComponents.size(); i++) {
718 const GeoMaterial* origMaterial = getMaterialInternal(materialComponents[i]);
719 if (origMaterial) {
720 newMaterialTmp->add(const_cast<GeoMaterial*>(origMaterial), fracWeight[i]);
721 } else {
722 ATH_MSG_ERROR("Material component missing " << materialComponents[i]);
723 }
724 }
725 addMaterial(newMaterialTmp);
726 newMaterial = newMaterialTmp;
727 }
728 return newMaterial;
729}
730
731const IGeometryDBSvc*
733 if (m_athenaComps) return m_athenaComps->geomDB();
734
735 return nullptr;
736}
737
738void
740 const std::string materialTable = "ExtraMaterials";
741 const std::string componentsTable = "ExtraMatComponents";
742
743 // Look for tables ExtraMaterials and ExtraMatComponents.
744 // These are text file only tables where extra materials are desired or
745 // one wants to override some database ones.
746 if (!db() || !db()->testField("", "TableSize:" + materialTable) || !db()->getTableSize(materialTable)
747 || !db()->testField("", "TableSize:" + componentsTable) || !db()->getTableSize(componentsTable)) return;
748
749
750 ATH_MSG_INFO("Extra materials being read in from text file.");
751
752 using MatMap = std::map<std::string, MaterialDef>;
753 MatMap materials;
754
755 // read in material table
756 for (unsigned int iMat = 0; iMat < db()->getTableSize(materialTable); iMat++) {
757 std::string materialName = db()->getString(materialTable, "NAME", iMat);
758 double density = db()->getDouble(materialTable, "DENSITY", iMat) * Gaudi::Units::g / Gaudi::Units::cm3;
759 materials[materialName] = MaterialDef(materialName, density);
760 }
761
762 // read in material component table
763 for (unsigned int iComp = 0; iComp < db()->getTableSize(componentsTable); iComp++) {
764 std::string materialName = db()->getString(componentsTable, "NAME", iComp);
765 std::string compName = db()->getString(componentsTable, "COMPNAME", iComp);
766 double fracWeight = db()->getDouble(componentsTable, "FRACTION", iComp);
767 MatMap::iterator iter = materials.find(materialName);
768 if (iter != materials.end()) {
769 iter->second.addComponent(compName, fracWeight);
770 } else {
771 ATH_MSG_ERROR("Attemp to add material component, " << compName << ", to non-existing material: "
772 << materialName);
773 }
774 }
775
776 //Now create the materials
777 int matCount = 0;
778 int matCountLast = -1;
779 bool someUndefined = true;
780 // While there are still undefined materials keep creating materials.
781 // Check also that the matCount had change to avoid endless loop due to cyclicly
782 // defined materials.
783 while (someUndefined && matCount != matCountLast) {
784 matCountLast = matCount;
785 someUndefined = false;
786 for (MatMap::iterator iter = materials.begin(); iter != materials.end(); ++iter) {
787 MaterialDef& tmpMat = iter->second;
788 if (!tmpMat.isCreated()) {
789 // Check if any components are materials in this table and if they are defined.
790 // If not flag that there are undefined materials and go to next material
791 bool compsDefined = true;
792 for (unsigned int iComp = 0; iComp < tmpMat.numComponents(); ++iComp) {
793 const std::string& compName = tmpMat.compName(iComp);
794 MatMap::iterator iter2 = materials.find(compName);
795 if (iter2 != materials.end()) {
796 if (!iter2->second.isCreated()) {
797 compsDefined = false;
798 break;
799 }
800 }
801 }
802 if (compsDefined) {
803 createMaterial(tmpMat);
804 tmpMat.setCreated();
805 matCount++;
806 } else {
807 someUndefined = true;
808 }
809 }
810 }
811 }
812
813
814 if (someUndefined) {
815 ATH_MSG_ERROR("Not all materials could be defined due to cyclic definitions");
816 }
817}
818
819void
821 if (material.numComponents() == 0) {
822 ATH_MSG_ERROR("Material has no components: " << material.name());
823 return;
824 }
825
826 // If total of fractions is greater than 1.1 then assume material is define by ratio of atoms.
827 double totWeight = material.totalFraction();
828 bool byAtomicRatio = false;
829 if (totWeight > 1.1) {
830 byAtomicRatio = true;
831 for (unsigned int i = 0; i < material.numComponents(); i++) {
832 if (material.compName(i).find("::") != std::string::npos) {
833 // If component name has "::" in it then its not an element.
834 ATH_MSG_ERROR("Material, " << material.name() <<
835 ", is assumed to be defined by atomic ratio (due to total fraction > 1)"
836 " but component is not an element: " << material.compName(i));
837 return;
838 }
839 const GeoElement* element = getElement(material.compName(i));
840 if (!element) {
841 ATH_MSG_ERROR("Error making material " << material.name() << ". Element not found: " <<
842 material.compName(i));
843 return;
844 }
845 totWeight += material.fraction(i) * element->getA();
846 }
847 } else {
848 // Check if total fraction is close to 1.
849 if (std::abs(totWeight - 1) > 0.01) {
850 ATH_MSG_WARNING("Total fractional weight does not sum to 1. Will renormalize. Total = " << totWeight);
851 }
852 }
853 // Now build the material
854 GeoIntrusivePtr<GeoMaterial> newMaterial{new GeoMaterial(material.name(), material.density())};
855 ATH_MSG_DEBUG("Creating material: " << material.name() << " with density: "
856 << material.density() / (Gaudi::Units::g / Gaudi::Units::cm3));
857 if (close_to_zero(totWeight)){
858 ATH_MSG_ERROR("totWeight is zero in InDetMaterialManager::createMaterial");
859 return;
860 }
861 for (unsigned int i = 0; i < material.numComponents(); i++) {
862 double fracWeight = material.fraction(i) / totWeight;
863 if (material.compName(i).find("::") == std::string::npos) {
864 const GeoElement* element = getElement(material.compName(i));
865 if (!element) {
866 ATH_MSG_ERROR("Error making material " << material.name() << ". Element not found: " << material.compName(i));
867 // delete the partially created material
868 return;
869 }
870 if (byAtomicRatio) {
871 fracWeight = material.fraction(i) * element->getA() / totWeight;
872 }
873 newMaterial->add(const_cast<GeoElement*>(element), fracWeight);
874 ATH_MSG_DEBUG(" Component: " << material.compName(i) << " " << fracWeight);
875 } else {
876 GeoIntrusivePtr<const GeoMaterial> materialTmp{getMaterialInternal(material.compName(i))};
877 if (!materialTmp) {
878 ATH_MSG_ERROR("Error making material " << material.name() << ". Component not found: " << material.compName(i));
879 // delete the partially created material
880 return;
881 }
882 if (byAtomicRatio) {
883 // Should not happen as already checked that all components were elements.
884 ATH_MSG_ERROR("Unexpected Error");
885 }
886 newMaterial->add(const_cast<GeoMaterial*>(materialTmp.get()), fracWeight);
887 ATH_MSG_DEBUG(" Component: " << material.compName(i) << " " << fracWeight);
888 }
889 }
890 newMaterial->lock();
891 addMaterial(newMaterial);
892}
893
898
900 : m_name(name),
902 m_created(false)
903{}
904
905void
907 m_components.push_back(compName);
908 m_fractions.push_back(fraction);
909}
910
911double
913 double sum = 0;
914
915 for (unsigned int i = 0; i < m_fractions.size(); i++) {
916 sum += m_fractions[i];
917 }
918 return sum;
919}
920
921// We need the original name as the GeoMaterial from the standard
922// material manager has its namespace dropped. We have two versions
923// of extraScaledMaterial. One where two names are provided. In this
924// version if newName is not empty that is used, otherwise
925// materialName is used. The other just has one name and that is the
926// one that is used.
927
928const GeoMaterial*
929InDetMaterialManager::extraScaledMaterial(const std::string& materialName,
930 const std::string& newName,
931 const GeoMaterial* origMaterial) {
932 if (newName.empty()) {
933 return extraScaledMaterial(materialName, origMaterial);
934 } else {
935 return extraScaledMaterial(newName, origMaterial);
936 }
937}
938
939const GeoMaterial*
940InDetMaterialManager::extraScaledMaterial(const std::string& materialName, const GeoMaterial* origMaterial) {
941 if (!origMaterial) throw std::runtime_error(std::string("Invalid material: ") + materialName);
942
943 double scaleFactor = getExtraScaleFactor(materialName);
944 // -1 (or any -ve number) indicates material is not scaled. And if the scale factor
945 // is 1 then there is no need to create a new material.
946 if (scaleFactor < 0 || scaleFactor == 1 || materialName.find("Ether") != std::string::npos) return origMaterial;
947
948 if (scaleFactor == 0) return getMaterialInternal("std::Vacuum");
949
950 std::string newName = materialName + "_ExtraScaling";
951
952 // Check if it is already made.
953 const GeoMaterial* newMaterial = getAdditionalMaterial(newName);
954
955 // Already made so we return it.
956 if (newMaterial) return newMaterial;
957
958 // Otherwise we need to make it.
959 double density = origMaterial->getDensity() * scaleFactor;
960
961 // create new material
962 GeoMaterial* newMaterialTmp = new GeoMaterial(newName, density);
963 newMaterialTmp->add(const_cast<GeoMaterial*>(origMaterial), 1.);
964 addMaterial(newMaterialTmp);
965 newMaterial = newMaterialTmp;
966
967 return newMaterial;
968}
969
970double
971InDetMaterialManager::getExtraScaleFactor(const std::string& materialName) {
972 // If name is found in map we return the corresponding scale factor.
973 // The special name "ALL" indicates all materials are scaled.
974 // Individual materials can be excluded from scaling by giving either
975 // a -ve scaling factor or just specifying a scaling factor of 1.
976 // A scaling factor of 0 means the material will be replaced by vacuum.
977
978 ExtraScaleFactorMap::const_iterator iter = m_scalingMap.find(materialName);
979 if (iter != m_scalingMap.end()) {
980 return iter->second;
981 } else {
982 // Check for special names
983 // ALL means everything scaled. Do not scale air or vacuum (unless explicity requested)
984 iter = m_scalingMap.find("ALL");
985 if (iter != m_scalingMap.end() && materialName != "std::Air" && materialName != "std::Vacuum") {
986 return iter->second;
987 }
988 }
989
990 // If not found then return -1 to indicate material is not to be scaled.
991 return -1;
992}
#define endmsg
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
double length(const pvec &v)
std::shared_ptr< IRDBRecordset > IRDBRecordset_ptr
Definition of the abstract IRDBRecord interface.
Definition of the abstract IRDBRecordset interface.
bool close_to_zero(T value, T eps=std::numeric_limits< T >::epsilon())
#define scale2
#define scale1
MsgStream & msg() const
The standard message stream.
bool msgLvl(const MSG::Level lvl) const
Test the output level.
AthMessaging(IMessageSvc *msgSvc, const std::string &name)
Constructor.
Interface class to access geometry database with possibility to override parameters from a text file.
virtual std::string getString(IRDBRecordset_ptr recordSet, const std::string &name, int index=0) const =0
virtual int getInt(IRDBRecordset_ptr recordSet, const std::string &name, int index=0) const =0
virtual double getDouble(IRDBRecordset_ptr recordSet, const std::string &name, int index=0) const =0
The following methods will first look in the text file if provided and then look in the database.
virtual unsigned int getTableSize(IRDBRecordset_ptr recordSet) const =0
IRDBRecord is one record in the IRDBRecordset object.
Definition IRDBRecord.h:27
virtual const std::string & getString(const std::string &fieldName) const =0
Get string field value.
virtual bool isFieldNull(const std::string &fieldName) const =0
Check if the field value is NULL.
virtual int getInt(const std::string &fieldName) const =0
Get int field value.
virtual double getDouble(const std::string &fieldName) const =0
Get double field value.
virtual std::string nodeName() const =0
virtual unsigned int size() const =0
Class to hold various Athena components.
const StoreGateSvc * detStore() const
Class to hold information need to create a material.
void addComponent(const std::string &compName, double fraction)
const std::string & compName(unsigned int i) const
std::vector< std::string > m_components
double fraction(unsigned int i) const
ExtraScaleFactorMap m_scalingMap
const GeoElement * getElement(const std::string &elementName)
Get element from GeoModel material manager.
MaterialWeightMap m_weightMap
bool compareDensity(double d1, double d2) const
const GeoMaterial * getMaterialInternal(const std::string &materialName)
void addMaterial(GeoMaterial *material)
Add material.
void createMaterial(const MaterialDef &material)
double getExtraScaleFactor(const std::string &materialName)
MaterialCompositionMap m_matCompositionMap
const GeoMaterial * getMaterialScaledInternal(const std::string &origMaterialName, double scaleFactor, const std::string &newName="")
void addCompositionTable(const IRDBRecordset_ptr &compositionTable, const std::string &space="")
const GeoMaterial * extraScaledMaterial(const std::string &materialName, const std::string &newName, const GeoMaterial *origMaterial)
const GeoMaterial * getMaterialForVolume(const std::string &materialName, double volume, const std::string &newName="")
Create and get material with a density calculated to give weight in predefined weight table.
const GeoMaterial * getCompositeMaterialForVolume(const std::string &newMatName, const double volumeTot, const double volume1, const std::string &matName1, const double volume2, const std::string &matName2)
const GeoMaterial * getAdditionalMaterial(const std::string &materialName) const
const IGeometryDBSvc * db()
StoredMaterialManager * retrieveManager(const StoreGateSvc *detStore)
const GeoMaterial * getMaterialScaled(const std::string &origMaterialName, double scaleFactor, const std::string &newName="")
void addScalingTable(const IRDBRecordset_ptr &scalingTable)
void addWeightTable(const IRDBRecordset_ptr &weightTable, const std::string &space="")
const GeoMaterial * getMaterial(const std::string &materialName)
Get material. First looks for locally defined material and if not found looks in GeoModel material ma...
StoredMaterialManager * m_materialManager
void addWeightTableOld(const IRDBRecordset_ptr &weightTable, const std::string &space)
void addWeightMaterial(const std::string &materialName, const std::string &materialBase, double weight, int linearWeightFlag)
bool hasMaterial(const std::string &materialName) const
InDetMaterialManager(const std::string &managerName, StoreGateSvc *detStore)
const GeoMaterial * getMaterialForVolumeLength(const std::string &materialName, double volume, double length, const std::string &newName="")
const InDetDD::AthenaComps * m_athenaComps
The Athena Transient Store API.
This class holds one or more material managers and makes them storeable, under StoreGate.
test if a value is close enough to zero to be an unreliable denominator.
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:146
bool close_to_zero(T value, T eps=std::numeric_limits< T >::epsilon())