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)
92 std::string errorMessage(
"Null pointer to Stored Material Manager!");
94 throw std::runtime_error(errorMessage);
117 std::string errorMessage(
"Null pointer to Stored Material Manager!");
119 throw std::runtime_error(errorMessage);
129 MaterialStore::const_iterator iter;
139 const double volumeTot,
140 const double volume1,
const std::string& matName1,
141 const double volume2,
const std::string& matName2
143 std::vector<std::string> baseMaterials;
144 std::vector<double> fracWeight;
145 baseMaterials.reserve(2);
146 fracWeight.reserve(2);
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);
152 double density1, density2;
154 MaterialWeightMap::const_iterator iter;
157 density1 = mat1->getDensity();
158 ATH_MSG_DEBUG(
"Composite material 1 - weight : " << density1 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
161 density1 = mat1->getDensity();
162 ATH_MSG_DEBUG(
"Composite material 1 - standard : " << density1 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
167 density2 = mat2->getDensity();
168 ATH_MSG_DEBUG(
"Composite material 2 - weight : " << density2 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
171 density2 = mat2->getDensity();
172 ATH_MSG_DEBUG(
"Composite material 2 - standard : " << density2 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
175 double weight1 = density1 * volume1;
176 double weight2 = density2 * volume2;
177 double invWeightTot = 1.0 / (weight1 + weight2);
179 double density = (weight1 + weight2) / volumeTot;
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));
190 baseMaterials.push_back(matName1);
191 baseMaterials.push_back(matName2);
192 fracWeight.push_back(weight1 * invWeightTot);
193 fracWeight.push_back(weight2 * invWeightTot);
195 return getMaterial(newMatName, baseMaterials, fracWeight, density);
212 const std::string& newName) {
220 const std::string& newName) {
221 std::string newName2 = newName;
222 bool newNameProvided = !newName2.empty();
223 if (!newNameProvided) {
224 newName2 = origMaterialName +
"Modified";
227 const GeoMaterial* newMaterial =
nullptr;
234 <<
" " << material->getDensity() / (GeoModelKernelUnits::gram / Gaudi::Units::cm3)
235 <<
" / " << density / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
237 newMaterial = material;
240 newMaterial = origMaterial;
244 if (newNameProvided || !
compareDensity(origMaterial->getDensity(), density)) {
246 GeoMaterial* newMaterialTmp =
new GeoMaterial(newName2, density);
247 newMaterialTmp->add(
const_cast<GeoMaterial*
>(origMaterial), 1.);
249 newMaterial = newMaterialTmp;
259 const std::string& newName) {
267 const std::string& newName) {
269 if (scaleFactor > 1000 || scaleFactor < 0.001) {
270 ATH_MSG_ERROR(
"Scale factor must be between 0.001 and 1000.");
278 if (newName.empty() && scaleFactor == 1.)
return origMaterial;
280 const GeoMaterial* newMaterial =
nullptr;
283 double density = origMaterial->getDensity() * scaleFactor;
284 std::string newName2 = newName;
285 if (newName2.empty()) {
287 int scaleInt =
static_cast<int>(scaleFactor * 10000);
288 int scale1 = scaleInt / 10000;
289 int scale2 = scaleInt % 10000;
291 std::ostringstream os;
292 os << origMaterialName <<
scale1 <<
"_" << std::setw(4) << std::setfill(
'0') <<
scale2;
304 GeoIntrusivePtr<const GeoMaterial> matPtr{material};
305 std::string name(material->getName());
307 ATH_MSG_WARNING(
"Ignoring attempt to redefine an existing material: " << name);
312 m_store[name] = std::move(matPtr);
314 ATH_MSG_DEBUG(
"Created new material: " << name <<
", " << material->getDensity() /
315 (Gaudi::Units::g / Gaudi::Units::cm3) <<
" g/cm3");
322 throw (std::runtime_error(
"InDetMaterialManager:compareDensity: Density is zero"));
324 return(std::abs(d1 / d2 - 1.) < 1e-5);
332 ATH_MSG_DEBUG(
"GeometryDBSvc not available. Using old version.");
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;
341 std::string materialBase;
342 if (
db()->testField(weightTable,
"BASEMATERIAL", i)) {
343 materialBase =
db()->
getString(weightTable,
"BASEMATERIAL", i);
345 double weight =
db()->
getDouble(weightTable,
"WEIGHT", i) * GeoModelKernelUnits::gram;
348 bool linearWeightFlag =
false;
350 linearWeightFlag =
db()->
getInt(weightTable,
"LINWEIGHTFLAG", i);
354 ATH_MSG_WARNING(
"Material: " << materialName <<
" already exists in weight table");
357 <<
" weight " << weight
358 <<
" linearWeightFlag " << linearWeightFlag
359 <<
" raw weight " <<
db()->getDouble(weightTable,
"WEIGHT", i)
361 <<
" to weight table");
369 int linearWeightFlag) {
371 weight = weight * GeoModelKernelUnits::gram;
374 ATH_MSG_WARNING(
"Material: " << materialName <<
" already exists in weight table");
377 <<
" weight " << weight
378 <<
" linearWeightFlag " << linearWeightFlag
379 <<
" to weight table");
386 for (
unsigned int i = 0; i < weightTable->
size(); i++) {
388 std::string materialName = record->
getString(
"MATERIAL");
389 if (!space.empty()) {
390 materialName = space +
"::" + materialName;
392 std::string materialBase;
394 materialBase = record->
getString(
"BASEMATERIAL");
396 double weight = record->
getDouble(
"WEIGHT") * GeoModelKernelUnits::gram;
399 bool linearWeightFlag =
false;
401 linearWeightFlag = record->
getInt(
"LINWEIGHTFLAG");
405 ATH_MSG_WARNING(
"Material: " << materialName <<
" already exists in weight table");
417 ATH_MSG_ERROR(
"GeometryDBSvc not available. Unable to read in composition table.");
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;
425 std::string componentName =
db()->
getString(compositionTable,
"COMPONENT", i);
427 double factor =
db()->
getDouble(compositionTable,
"FACTOR", i);
428 double actualLength =
db()->
getDouble(compositionTable,
"ACTUALLENGTH", i);
439 if (!scalingTable)
return;
441 if (
db()->getTableSize(scalingTable) == 0)
return;
445 ATH_MSG_ERROR(
"GeometryDBSvc not available. Unable to read in scaling table.");
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);
452 if (scalingFactor >= 0 || scalingFactor == 1) {
453 msg(MSG::DEBUG) <<
"Material " << materialName <<
" will be scaled by: " << scalingFactor <<
endmsg;
456 msg(MSG::DEBUG) <<
"Material " << materialName <<
" will be NOT be scaled." <<
endmsg;
460 ATH_MSG_WARNING(
"Overriding material: " << materialName <<
" which already exists in scaling table");
484 MaterialWeightMap::const_iterator iter;
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: " <<
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));
501 if (materialBase.empty()) {
502 return getMaterial(materialName, density, newName);
504 if (newName.empty()) {
505 return getMaterial(materialBase, density, materialName);
507 return getMaterial(materialBase, density, newName);
513 ATH_MSG_VERBOSE(
"Material not in weight table, using standard material: "
515 <<
", volume(cm3) = " << volume / Gaudi::Units::cm3);
522 const std::string& newName) {
532 if (newName.empty()) {
539 if (volume <= 0 ||
length <= 0) {
545 std::pair<MaterialCompositionMap::const_iterator, MaterialCompositionMap::const_iterator> iterRange;
548 ATH_MSG_VERBOSE(
"Found material in material composition table:" << materialName);
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);
562 MaterialWeightMap::const_iterator iter;
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;
569 if (materialBase.empty()) {
570 return getMaterial(materialName, density, newName);
577 ATH_MSG_VERBOSE(
"Material not in weight table, using standard material: "
579 <<
", volume(cm3) = " << volume / Gaudi::Units::cm3);
586 const std::string& materialComponent,
590 std::vector<std::string> tmpMaterialComponents(1, materialComponent);
591 std::vector<double> tmpFactors(1, factor);
597 const std::vector<std::string>& materialComponents,
598 const std::vector<double>& factors,
602 if (volume <= 0 ||
length <= 0) {
607 if (!factors.empty() && factors.size() < materialComponents.size()) {
608 ATH_MSG_WARNING(
"getMaterialForVolumeLength: factor vector size too small. Setting remaining factors to 1.");
611 std::vector<std::string> baseMaterials;
612 std::vector<double> fracWeight;
613 baseMaterials.reserve(materialComponents.size());
614 fracWeight.reserve(materialComponents.size());
616 double totWeight = 0;
617 for (
unsigned int iComp = 0; iComp < materialComponents.size(); ++iComp) {
618 const std::string& materialName = materialComponents[iComp];
621 MaterialWeightMap::const_iterator iter;
623 const std::string& materialBase = iter->second.name;
624 double weight = iter->second.weight;
626 if (iComp < factors.size()) {
627 weight *= factors[iComp];
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);
636 if (iter->second.linearWeightFlag) weight *=
length;
637 if (materialBase.empty()) {
639 baseMaterials.push_back(materialName);
641 baseMaterials.push_back(materialBase);
643 fracWeight.push_back(weight);
659 double weight = factors.at(iComp) *
length * GeoModelKernelUnits::gram;
662 baseMaterials.push_back(materialName);
663 fracWeight.push_back(weight);
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;
676 ATH_MSG_ERROR(
"totWeight is zero in InDetMaterialManager::getMaterialForVolumeLength");
679 for (
unsigned int i = 0; i < fracWeight.size(); ++i) {
680 fracWeight[i] /= totWeight;
683 ATH_MSG_ERROR(
"volume is zero in InDetMaterialManager::getMaterialForVolumeLength");
686 double density = totWeight / volume;
688 return getMaterial(name, baseMaterials, fracWeight, density);
694 const std::vector<std::string>& materialComponents,
695 const std::vector<double>& fracWeight,
702 const std::vector<std::string>& materialComponents,
703 const std::vector<double>& fracWeight,
705 const GeoMaterial* newMaterial =
nullptr;
714 newMaterial = material;
716 GeoMaterial* newMaterialTmp =
new GeoMaterial(name, density);
717 for (
unsigned int i = 0; i < materialComponents.size(); i++) {
720 newMaterialTmp->add(
const_cast<GeoMaterial*
>(origMaterial), fracWeight[i]);
722 ATH_MSG_ERROR(
"Material component missing " << materialComponents[i]);
726 newMaterial = newMaterialTmp;
740 const std::string materialTable =
"ExtraMaterials";
741 const std::string componentsTable =
"ExtraMatComponents";
746 if (!
db() || !
db()->testField(
"",
"TableSize:" + materialTable) || !
db()->getTableSize(materialTable)
747 || !
db()->testField(
"",
"TableSize:" + componentsTable) || !
db()->getTableSize(componentsTable))
return;
750 ATH_MSG_INFO(
"Extra materials being read in from text file.");
752 using MatMap = std::map<std::string, MaterialDef>;
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);
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);
771 ATH_MSG_ERROR(
"Attemp to add material component, " << compName <<
", to non-existing material: "
778 int matCountLast = -1;
779 bool someUndefined =
true;
783 while (someUndefined && matCount != matCountLast) {
784 matCountLast = matCount;
785 someUndefined =
false;
786 for (MatMap::iterator iter = materials.begin(); iter != materials.end(); ++iter) {
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;
807 someUndefined =
true;
815 ATH_MSG_ERROR(
"Not all materials could be defined due to cyclic definitions");
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) {
835 ", is assumed to be defined by atomic ratio (due to total fraction > 1)"
836 " but component is not an element: " << material.
compName(i));
841 ATH_MSG_ERROR(
"Error making material " << material.
name() <<
". Element not found: " <<
845 totWeight += material.
fraction(i) * element->getA();
849 if (std::abs(totWeight - 1) > 0.01) {
850 ATH_MSG_WARNING(
"Total fractional weight does not sum to 1. Will renormalize. Total = " << totWeight);
854 GeoIntrusivePtr<GeoMaterial> newMaterial{
new GeoMaterial(material.
name(), material.
density())};
856 << material.
density() / (Gaudi::Units::g / Gaudi::Units::cm3));
858 ATH_MSG_ERROR(
"totWeight is zero in InDetMaterialManager::createMaterial");
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) {
871 fracWeight = material.
fraction(i) * element->getA() / totWeight;
873 newMaterial->add(
const_cast<GeoElement*
>(element), fracWeight);
886 newMaterial->add(
const_cast<GeoMaterial*
>(materialTmp.get()), fracWeight);
915 for (
unsigned int i = 0; i <
m_fractions.size(); i++) {
930 const std::string& newName,
931 const GeoMaterial* origMaterial) {
932 if (newName.empty()) {
941 if (!origMaterial)
throw std::runtime_error(std::string(
"Invalid material: ") + materialName);
946 if (scaleFactor < 0 || scaleFactor == 1 || materialName.find(
"Ether") != std::string::npos)
return origMaterial;
950 std::string newName = materialName +
"_ExtraScaling";
956 if (newMaterial)
return newMaterial;
959 double density = origMaterial->getDensity() * scaleFactor;
962 GeoMaterial* newMaterialTmp =
new GeoMaterial(newName, density);
963 newMaterialTmp->add(
const_cast<GeoMaterial*
>(origMaterial), 1.);
965 newMaterial = newMaterialTmp;
978 ExtraScaleFactorMap::const_iterator iter =
m_scalingMap.find(materialName);
985 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.
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.
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)
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 GeoElement * getElement(const std::string &elementName)
Get element from GeoModel material manager.
MaterialWeightMap m_weightMap
bool compareDensity(double d1, double d2) const
bool m_extraFunctionality
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)
std::string m_managerName
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="")
void addTextFileMaterials()
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 ®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())