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