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"
41 const std::string& space,
42 bool extraFunctionality)
61 const std::string& space)
91 std::string errorMessage(
"Null pointer to Stored Material Manager!");
93 throw std::runtime_error(errorMessage);
116 std::string errorMessage(
"Null pointer to Stored Material Manager!");
118 throw std::runtime_error(errorMessage);
128 MaterialStore::const_iterator iter;
138 const double volumeTot,
139 const double volume1,
const std::string& matName1,
140 const double volume2,
const std::string& matName2
142 std::vector<std::string> baseMaterials;
143 std::vector<double> fracWeight;
144 baseMaterials.reserve(2);
145 fracWeight.reserve(2);
147 ATH_MSG_DEBUG(
"Composite material : " << volumeTot / Gaudi::Units::cm3 <<
" = " << volume1 / Gaudi::Units::cm3
148 <<
" + " << volume2 / Gaudi::Units::cm3);
149 ATH_MSG_DEBUG(
"Composite material : " << matName1 <<
" " << matName2);
151 double density1, density2;
153 MaterialWeightMap::const_iterator iter;
156 density1 = mat1->getDensity();
157 ATH_MSG_DEBUG(
"Composite material 1 - weight : " << density1 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
160 density1 = mat1->getDensity();
161 ATH_MSG_DEBUG(
"Composite material 1 - standard : " << density1 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
166 density2 = mat2->getDensity();
167 ATH_MSG_DEBUG(
"Composite material 2 - weight : " << density2 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
170 density2 = mat2->getDensity();
171 ATH_MSG_DEBUG(
"Composite material 2 - standard : " << density2 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
174 double weight1 = density1 * volume1;
175 double weight2 = density2 * volume2;
176 double invWeightTot = 1.0 / (weight1 + weight2);
178 double density = (weight1 + weight2) / volumeTot;
180 double frac1 = weight1 / (weight1 + weight2);
181 double frac2 = weight2 / (weight1 + weight2);
182 double density_2 = 1.0 / (frac1 / density1 + frac2 / density2);
183 double density_3 = (weight1 + weight2) / (volume1 + volume2);
184 ATH_MSG_DEBUG(
"-> weights : " << weight1 / (GeoModelKernelUnits::gram) <<
" " << weight2 / (GeoModelKernelUnits::gram));
185 ATH_MSG_DEBUG(
"-> density : " << density / (GeoModelKernelUnits::gram / Gaudi::Units::cm3) <<
" " << density_2 /
186 (GeoModelKernelUnits::gram / Gaudi::Units::cm3) <<
" " << density_3 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
189 baseMaterials.push_back(matName1);
190 baseMaterials.push_back(matName2);
191 fracWeight.push_back(weight1 * invWeightTot);
192 fracWeight.push_back(weight2 * invWeightTot);
194 return getMaterial(newMatName, baseMaterials, fracWeight, density);
211 std::string_view newName) {
219 std::string_view newName) {
220 std::string newName2{newName};
221 bool newNameProvided = !newName2.empty();
222 if (!newNameProvided) {
223 newName2 = std::string{origMaterialName} +
"Modified";
226 const GeoMaterial* newMaterial =
nullptr;
233 <<
" " << material->getDensity() / (GeoModelKernelUnits::gram / Gaudi::Units::cm3)
234 <<
" / " << density / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
236 newMaterial = material;
239 newMaterial = origMaterial;
243 if (newNameProvided || !
compareDensity(origMaterial->getDensity(), density)) {
245 GeoMaterial* newMaterialTmp =
new GeoMaterial(newName2, density);
246 newMaterialTmp->add(
const_cast<GeoMaterial*
>(origMaterial), 1.);
248 newMaterial = newMaterialTmp;
258 const std::string& newName) {
266 const std::string& newName) {
268 if (scaleFactor > 1000 || scaleFactor < 0.001) {
269 ATH_MSG_ERROR(
"Scale factor must be between 0.001 and 1000.");
277 if (newName.empty() && scaleFactor == 1.)
return origMaterial;
279 const GeoMaterial* newMaterial =
nullptr;
282 double density = origMaterial->getDensity() * scaleFactor;
283 std::string newName2 = newName;
284 if (newName2.empty()) {
286 int scaleInt =
static_cast<int>(scaleFactor * 10000);
287 int scale1 = scaleInt / 10000;
288 int scale2 = scaleInt % 10000;
290 std::ostringstream os;
291 os << origMaterialName <<
scale1 <<
"_" << std::setw(4) << std::setfill(
'0') <<
scale2;
303 GeoIntrusivePtr<const GeoMaterial> matPtr{material};
304 std::string name(material->getName());
306 ATH_MSG_WARNING(
"Ignoring attempt to redefine an existing material: " << name);
311 m_store[name] = std::move(matPtr);
313 ATH_MSG_DEBUG(
"Created new material: " << name <<
", " << material->getDensity() /
314 (Gaudi::Units::g / Gaudi::Units::cm3) <<
" g/cm3");
321 throw (std::runtime_error(
"InDetMaterialManager:compareDensity: Density is zero"));
323 return(std::abs(d1 / d2 - 1.) < 1e-5);
329 for(
const auto& rec : *weightTable) {
330 std::string materialName = rec->getString(
"MATERIAL");
331 if (!space.empty()) {
332 materialName = space +
"::" + materialName;
334 std::string materialBase;
336 if (!rec->isFieldNull(
"BASEMATERIAL")) {
337 materialBase = rec->getString(
"BASEMATERIAL");
340 catch(std::runtime_error&) {
343 double weight = rec->getDouble(
"WEIGHT") * GeoModelKernelUnits::gram;
345 bool linearWeightFlag =
false;
348 if(!rec->isFieldNull(
"LINWEIGHTFLAG")) {
349 linearWeightFlag = rec->getInt(
"LINWEIGHTFLAG");
352 catch(std::runtime_error&) {
358 ATH_MSG_WARNING(
"Material: " << materialName <<
" already exists in weight table");
361 <<
" weight " << weight
362 <<
" linearWeightFlag " << linearWeightFlag
363 <<
" raw weight " << rec->getDouble(
"WEIGHT")
365 <<
" to weight table");
373 int linearWeightFlag) {
375 weight = weight * GeoModelKernelUnits::gram;
378 ATH_MSG_WARNING(
"Material: " << materialName <<
" already exists in weight table");
381 <<
" weight " << weight
382 <<
" linearWeightFlag " << linearWeightFlag
383 <<
" to weight table");
392 for (
const auto& rec : *compositionTable) {
393 std::string materialName = rec->getString(
"MATERIAL");
394 if (!space.empty()) {
395 materialName = space +
"::" + materialName;
398 std::string componentName = rec->getString(
"COMPONENT");
399 int count = rec->getInt(
"COUNT");
400 double factor = rec->getDouble(
"FACTOR");
401 double actualLength = rec->getDouble(
"ACTUALLENGTH");
412 if (!scalingTable || scalingTable->
size()==0)
return;
414 for (
const auto& rec : *scalingTable) {
415 std::string materialName = rec->getString(
"MATERIAL");
416 double scalingFactor = rec->getDouble(
"FACTOR");
418 if (scalingFactor >= 0 || scalingFactor == 1) {
419 ATH_MSG_DEBUG(
"Material " << materialName <<
" will be scaled by: " << scalingFactor);
422 ATH_MSG_DEBUG(
"Material " << materialName <<
" will be NOT be scaled.");
425 ATH_MSG_WARNING(
"Overriding material: " << materialName <<
" which already exists in scaling table");
449 MaterialWeightMap::const_iterator iter;
451 const std::string& materialBase = iter->second.name;
452 double weight = iter->second.weight;
453 double density = weight / volume;
454 if (iter->second.linearWeightFlag) {
455 ATH_MSG_ERROR(
"Material defined by linear weight cannot be created with getMaterialForVolume method: " <<
459 ATH_MSG_VERBOSE(
"Found material in weight table - name, base, weight(g), volume(cm3), density(g/cm3): "
460 << materialName <<
", "
461 << materialBase <<
", "
462 << weight / GeoModelKernelUnits::gram <<
", "
463 << volume / Gaudi::Units::cm3 <<
", "
464 << density / (Gaudi::Units::g / Gaudi::Units::cm3));
466 if (materialBase.empty()) {
467 return getMaterial(materialName, density, newName);
469 if (newName.empty()) {
470 return getMaterial(materialBase, density, materialName);
472 return getMaterial(materialBase, density, newName);
478 ATH_MSG_VERBOSE(
"Material not in weight table, using standard material: "
480 <<
", volume(cm3) = " << volume / Gaudi::Units::cm3);
487 const std::string& newName) {
497 if (newName.empty()) {
504 if (volume <= 0 ||
length <= 0) {
510 std::pair<MaterialCompositionMap::const_iterator, MaterialCompositionMap::const_iterator> iterRange;
513 ATH_MSG_VERBOSE(
"Found material in material composition table:" << materialName);
515 std::vector<double> factors;
516 std::vector<std::string> components;
517 for (MaterialCompositionMap::const_iterator iter = iterRange.first; iter != iterRange.second; ++iter) {
518 double factorTmp = iter->second.factor;
519 if (iter->second.actualLength > 0) factorTmp *= iter->second.actualLength /
length;
520 factors.push_back(factorTmp);
521 components.push_back(iter->second.name);
527 MaterialWeightMap::const_iterator iter;
529 const std::string& materialBase = iter->second.name;
530 double weight = iter->second.weight;
531 double density = weight / volume;
532 if (iter->second.linearWeightFlag) weight *=
length;
534 if (materialBase.empty()) {
535 return getMaterial(materialName, density, newName);
542 ATH_MSG_VERBOSE(
"Material not in weight table, using standard material: "
544 <<
", volume(cm3) = " << volume / Gaudi::Units::cm3);
551 const std::string& materialComponent,
555 std::vector<std::string> tmpMaterialComponents(1, materialComponent);
556 std::vector<double> tmpFactors(1, factor);
562 const std::vector<std::string>& materialComponents,
563 const std::vector<double>& factors,
567 if (volume <= 0 ||
length <= 0) {
572 if (!factors.empty() && factors.size() < materialComponents.size()) {
573 ATH_MSG_WARNING(
"getMaterialForVolumeLength: factor vector size too small. Setting remaining factors to 1.");
576 std::vector<std::string> baseMaterials;
577 std::vector<double> fracWeight;
578 baseMaterials.reserve(materialComponents.size());
579 fracWeight.reserve(materialComponents.size());
581 double totWeight = 0;
582 for (
unsigned int iComp = 0; iComp < materialComponents.size(); ++iComp) {
583 const std::string& materialName = materialComponents[iComp];
586 MaterialWeightMap::const_iterator iter;
588 const std::string& materialBase = iter->second.name;
589 double weight = iter->second.weight;
591 if (iComp < factors.size()) {
592 weight *= factors[iComp];
595 <<
" found in weight table, weight " << iter->second.weight / GeoModelKernelUnits::gram
596 <<
" factor " << factors[iComp]
597 <<
" w*fac*len " << weight *
length / GeoModelKernelUnits::gram
598 <<
" basMat " << materialBase
599 <<
" linear? " << iter->second.linearWeightFlag);
601 if (iter->second.linearWeightFlag) weight *=
length;
602 if (materialBase.empty()) {
604 baseMaterials.push_back(materialName);
606 baseMaterials.push_back(materialBase);
608 fracWeight.push_back(weight);
624 double weight = factors.at(iComp) *
length * GeoModelKernelUnits::gram;
627 baseMaterials.push_back(materialName);
628 fracWeight.push_back(weight);
633 if (
msgLvl(MSG::VERBOSE)) {
634 msg(MSG::VERBOSE) <<
"Creating material from multiple components: " << name <<
endmsg;
635 for (
unsigned int i = 0; i < materialComponents.size(); ++i) {
636 msg(MSG::VERBOSE) <<
" Component " << i <<
": Name = " << baseMaterials[i]
637 <<
" Weight(g) = " << fracWeight[i] / Gaudi::Units::g <<
endmsg;
641 ATH_MSG_ERROR(
"totWeight is zero in InDetMaterialManager::getMaterialForVolumeLength");
644 for (
unsigned int i = 0; i < fracWeight.size(); ++i) {
645 fracWeight[i] /= totWeight;
648 ATH_MSG_ERROR(
"volume is zero in InDetMaterialManager::getMaterialForVolumeLength");
651 double density = totWeight / volume;
653 return getMaterial(name, baseMaterials, fracWeight, density);
659 const std::vector<std::string>& materialComponents,
660 const std::vector<double>& fracWeight,
667 const std::vector<std::string>& materialComponents,
668 const std::vector<double>& fracWeight,
670 const GeoMaterial* newMaterial =
nullptr;
679 newMaterial = material;
681 GeoMaterial* newMaterialTmp =
new GeoMaterial(name, density);
682 for (
unsigned int i = 0; i < materialComponents.size(); i++) {
685 newMaterialTmp->add(
const_cast<GeoMaterial*
>(origMaterial), fracWeight[i]);
687 ATH_MSG_ERROR(
"Material component missing " << materialComponents[i]);
691 newMaterial = newMaterialTmp;
705 bool byAtomicRatio =
false;
706 if (totWeight > 1.1) {
707 byAtomicRatio =
true;
708 for (
unsigned int i = 0; i < material.
numComponents(); i++) {
709 if (material.
compName(i).find(
"::") != std::string::npos) {
712 ", is assumed to be defined by atomic ratio (due to total fraction > 1)"
713 " but component is not an element: " << material.
compName(i));
718 ATH_MSG_ERROR(
"Error making material " << material.
name() <<
". Element not found: " <<
722 totWeight += material.
fraction(i) * element->getA();
726 if (std::abs(totWeight - 1) > 0.01) {
727 ATH_MSG_WARNING(
"Total fractional weight does not sum to 1. Will renormalize. Total = " << totWeight);
731 GeoIntrusivePtr<GeoMaterial> newMaterial{
new GeoMaterial(material.
name(), material.
density())};
733 << material.
density() / (Gaudi::Units::g / Gaudi::Units::cm3));
735 ATH_MSG_ERROR(
"totWeight is zero in InDetMaterialManager::createMaterial");
738 for (
unsigned int i = 0; i < material.
numComponents(); i++) {
739 double fracWeight = material.
fraction(i) / totWeight;
740 if (material.
compName(i).find(
"::") == std::string::npos) {
748 fracWeight = material.
fraction(i) * element->getA() / totWeight;
750 newMaterial->add(
const_cast<GeoElement*
>(element), fracWeight);
763 newMaterial->add(
const_cast<GeoMaterial*
>(materialTmp.get()), fracWeight);
792 for (
unsigned int i = 0; i <
m_fractions.size(); i++) {
807 std::string_view newName,
808 const GeoMaterial* origMaterial) {
809 if (newName.empty()) {
818 if (!origMaterial)
throw std::runtime_error(std::format(
"Invalid material: {}",materialName));
823 if (scaleFactor < 0 || scaleFactor == 1 || materialName.find(
"Ether") != std::string::npos)
return origMaterial;
827 std::string newName = std::string{materialName} +
"_ExtraScaling";
833 if (newMaterial)
return newMaterial;
836 double density = origMaterial->getDensity() * scaleFactor;
839 GeoMaterial* newMaterialTmp =
new GeoMaterial(newName, density);
840 newMaterialTmp->add(
const_cast<GeoMaterial*
>(origMaterial), 1.);
842 newMaterial = newMaterialTmp;
855 ExtraScaleFactorMap::const_iterator iter =
m_scalingMap.find(materialName);
862 if (iter !=
m_scalingMap.end() && materialName !=
"std::Air" && materialName !=
"std::Vacuum") {
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
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())
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)
std::vector< double > m_fractions
unsigned int numComponents() const
const std::string & compName(unsigned int i) const
std::vector< std::string > m_components
double totalFraction() const
double fraction(unsigned int i) const
const std::string & name() const
ExtraScaleFactorMap m_scalingMap
const GeoMaterial * extraScaledMaterial(std::string_view materialName, std::string_view newName, const GeoMaterial *origMaterial)
const GeoElement * getElement(const std::string &elementName)
Get element from GeoModel material manager.
const GeoMaterial * getAdditionalMaterial(std::string_view materialName) const
MaterialWeightMap m_weightMap
bool compareDensity(double d1, double d2) const
bool m_extraFunctionality
void addMaterial(GeoMaterial *material)
Add material.
void createMaterial(const MaterialDef &material)
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="")
std::string m_managerName
const GeoMaterial * getCompositeMaterialForVolume(const std::string &newMatName, const double volumeTot, const double volume1, const std::string &matName1, const double volume2, const std::string &matName2)
StoredMaterialManager * retrieveManager(const StoreGateSvc *detStore)
const GeoMaterial * getMaterialScaled(const std::string &origMaterialName, double scaleFactor, const std::string &newName="")
void addScalingTable(const IRDBRecordset_ptr &scalingTable)
double getExtraScaleFactor(std::string_view materialName)
const GeoMaterial * getMaterialForVolume(std::string_view materialName, double volume, std::string_view newName={})
Create and get material with a density calculated to give weight in predefined weight table.
const GeoMaterial * getMaterial(std::string_view materialName)
Get material. First looks for locally defined material and if not found looks in GeoModel material ma...
void addWeightTable(const IRDBRecordset_ptr &weightTable, const std::string &space="")
StoredMaterialManager * m_materialManager
const GeoMaterial * getMaterialInternal(std::string_view materialName)
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 ®x)
count how many occurances of a regx are in a string
bool close_to_zero(T value, T eps=std::numeric_limits< T >::epsilon())