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"
40 const std::string& space,
41 bool extraFunctionality)
60 const std::string& space)
90 std::string errorMessage(
"Null pointer to Stored Material Manager!");
92 throw std::runtime_error(errorMessage);
115 std::string errorMessage(
"Null pointer to Stored Material Manager!");
117 throw std::runtime_error(errorMessage);
127 MaterialStore::const_iterator iter;
137 const double volumeTot,
138 const double volume1,
const std::string& matName1,
139 const double volume2,
const std::string& matName2
141 std::vector<std::string> baseMaterials;
142 std::vector<double> fracWeight;
143 baseMaterials.reserve(2);
144 fracWeight.reserve(2);
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);
150 double density1, density2;
152 MaterialWeightMap::const_iterator iter;
155 density1 = mat1->getDensity();
156 ATH_MSG_DEBUG(
"Composite material 1 - weight : " << density1 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
159 density1 = mat1->getDensity();
160 ATH_MSG_DEBUG(
"Composite material 1 - standard : " << density1 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
165 density2 = mat2->getDensity();
166 ATH_MSG_DEBUG(
"Composite material 2 - weight : " << density2 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
169 density2 = mat2->getDensity();
170 ATH_MSG_DEBUG(
"Composite material 2 - standard : " << density2 / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
173 double weight1 = density1 * volume1;
174 double weight2 = density2 * volume2;
175 double invWeightTot = 1.0 / (weight1 + weight2);
177 double density = (weight1 + weight2) / volumeTot;
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));
188 baseMaterials.push_back(matName1);
189 baseMaterials.push_back(matName2);
190 fracWeight.push_back(weight1 * invWeightTot);
191 fracWeight.push_back(weight2 * invWeightTot);
193 return getMaterial(newMatName, baseMaterials, fracWeight, density);
210 const std::string& newName) {
218 const std::string& newName) {
219 std::string newName2 = newName;
220 bool newNameProvided = !newName2.empty();
221 if (!newNameProvided) {
222 newName2 = origMaterialName +
"Modified";
225 const GeoMaterial* newMaterial =
nullptr;
232 <<
" " << material->getDensity() / (GeoModelKernelUnits::gram / Gaudi::Units::cm3)
233 <<
" / " << density / (GeoModelKernelUnits::gram / Gaudi::Units::cm3));
235 newMaterial = material;
238 newMaterial = origMaterial;
242 if (newNameProvided || !
compareDensity(origMaterial->getDensity(), density)) {
244 GeoMaterial* newMaterialTmp =
new GeoMaterial(newName2, density);
245 newMaterialTmp->add(
const_cast<GeoMaterial*
>(origMaterial), 1.);
247 newMaterial = newMaterialTmp;
257 const std::string& newName) {
265 const std::string& newName) {
267 if (scaleFactor > 1000 || scaleFactor < 0.001) {
268 ATH_MSG_ERROR(
"Scale factor must be between 0.001 and 1000.");
276 if (newName.empty() && scaleFactor == 1.)
return origMaterial;
278 const GeoMaterial* newMaterial =
nullptr;
281 double density = origMaterial->getDensity() * scaleFactor;
282 std::string newName2 = newName;
283 if (newName2.empty()) {
285 int scaleInt =
static_cast<int>(scaleFactor * 10000);
286 int scale1 = scaleInt / 10000;
287 int scale2 = scaleInt % 10000;
289 std::ostringstream os;
290 os << origMaterialName <<
scale1 <<
"_" << std::setw(4) << std::setfill(
'0') <<
scale2;
302 GeoIntrusivePtr<const GeoMaterial> matPtr{material};
303 std::string name(material->getName());
305 ATH_MSG_WARNING(
"Ignoring attempt to redefine an existing material: " << name);
310 m_store[name] = std::move(matPtr);
312 ATH_MSG_DEBUG(
"Created new material: " << name <<
", " << material->getDensity() /
313 (Gaudi::Units::g / Gaudi::Units::cm3) <<
" g/cm3");
320 throw (std::runtime_error(
"InDetMaterialManager:compareDensity: Density is zero"));
322 return(std::abs(d1 / d2 - 1.) < 1e-5);
328 for(
const auto& rec : *weightTable) {
329 std::string materialName = rec->getString(
"MATERIAL");
330 if (!space.empty()) {
331 materialName = space +
"::" + materialName;
333 std::string materialBase;
335 if (!rec->isFieldNull(
"BASEMATERIAL")) {
336 materialBase = rec->getString(
"BASEMATERIAL");
339 catch(std::runtime_error&) {
342 double weight = rec->getDouble(
"WEIGHT") * GeoModelKernelUnits::gram;
344 bool linearWeightFlag =
false;
347 if(!rec->isFieldNull(
"LINWEIGHTFLAG")) {
348 linearWeightFlag = rec->getInt(
"LINWEIGHTFLAG");
351 catch(std::runtime_error&) {
357 ATH_MSG_WARNING(
"Material: " << materialName <<
" already exists in weight table");
360 <<
" weight " << weight
361 <<
" linearWeightFlag " << linearWeightFlag
362 <<
" raw weight " << rec->getDouble(
"WEIGHT")
364 <<
" to weight table");
372 int linearWeightFlag) {
374 weight = weight * GeoModelKernelUnits::gram;
377 ATH_MSG_WARNING(
"Material: " << materialName <<
" already exists in weight table");
380 <<
" weight " << weight
381 <<
" linearWeightFlag " << linearWeightFlag
382 <<
" to weight table");
391 for (
const auto& rec : *compositionTable) {
392 std::string materialName = rec->getString(
"MATERIAL");
393 if (!space.empty()) {
394 materialName = space +
"::" + materialName;
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");
411 if (!scalingTable || scalingTable->
size()==0)
return;
413 for (
const auto& rec : *scalingTable) {
414 std::string materialName = rec->getString(
"MATERIAL");
415 double scalingFactor = rec->getDouble(
"FACTOR");
417 if (scalingFactor >= 0 || scalingFactor == 1) {
418 ATH_MSG_DEBUG(
"Material " << materialName <<
" will be scaled by: " << scalingFactor);
421 ATH_MSG_DEBUG(
"Material " << materialName <<
" will be NOT be scaled.");
424 ATH_MSG_WARNING(
"Overriding material: " << materialName <<
" which already exists in scaling table");
448 MaterialWeightMap::const_iterator iter;
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: " <<
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));
465 if (materialBase.empty()) {
466 return getMaterial(materialName, density, newName);
468 if (newName.empty()) {
469 return getMaterial(materialBase, density, materialName);
471 return getMaterial(materialBase, density, newName);
477 ATH_MSG_VERBOSE(
"Material not in weight table, using standard material: "
479 <<
", volume(cm3) = " << volume / Gaudi::Units::cm3);
486 const std::string& newName) {
496 if (newName.empty()) {
503 if (volume <= 0 ||
length <= 0) {
509 std::pair<MaterialCompositionMap::const_iterator, MaterialCompositionMap::const_iterator> iterRange;
512 ATH_MSG_VERBOSE(
"Found material in material composition table:" << materialName);
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);
526 MaterialWeightMap::const_iterator iter;
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;
533 if (materialBase.empty()) {
534 return getMaterial(materialName, density, newName);
541 ATH_MSG_VERBOSE(
"Material not in weight table, using standard material: "
543 <<
", volume(cm3) = " << volume / Gaudi::Units::cm3);
550 const std::string& materialComponent,
554 std::vector<std::string> tmpMaterialComponents(1, materialComponent);
555 std::vector<double> tmpFactors(1, factor);
561 const std::vector<std::string>& materialComponents,
562 const std::vector<double>& factors,
566 if (volume <= 0 ||
length <= 0) {
571 if (!factors.empty() && factors.size() < materialComponents.size()) {
572 ATH_MSG_WARNING(
"getMaterialForVolumeLength: factor vector size too small. Setting remaining factors to 1.");
575 std::vector<std::string> baseMaterials;
576 std::vector<double> fracWeight;
577 baseMaterials.reserve(materialComponents.size());
578 fracWeight.reserve(materialComponents.size());
580 double totWeight = 0;
581 for (
unsigned int iComp = 0; iComp < materialComponents.size(); ++iComp) {
582 const std::string& materialName = materialComponents[iComp];
585 MaterialWeightMap::const_iterator iter;
587 const std::string& materialBase = iter->second.name;
588 double weight = iter->second.weight;
590 if (iComp < factors.size()) {
591 weight *= factors[iComp];
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);
600 if (iter->second.linearWeightFlag) weight *=
length;
601 if (materialBase.empty()) {
603 baseMaterials.push_back(materialName);
605 baseMaterials.push_back(materialBase);
607 fracWeight.push_back(weight);
623 double weight = factors.at(iComp) *
length * GeoModelKernelUnits::gram;
626 baseMaterials.push_back(materialName);
627 fracWeight.push_back(weight);
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;
640 ATH_MSG_ERROR(
"totWeight is zero in InDetMaterialManager::getMaterialForVolumeLength");
643 for (
unsigned int i = 0; i < fracWeight.size(); ++i) {
644 fracWeight[i] /= totWeight;
647 ATH_MSG_ERROR(
"volume is zero in InDetMaterialManager::getMaterialForVolumeLength");
650 double density = totWeight / volume;
652 return getMaterial(name, baseMaterials, fracWeight, density);
658 const std::vector<std::string>& materialComponents,
659 const std::vector<double>& fracWeight,
666 const std::vector<std::string>& materialComponents,
667 const std::vector<double>& fracWeight,
669 const GeoMaterial* newMaterial =
nullptr;
678 newMaterial = material;
680 GeoMaterial* newMaterialTmp =
new GeoMaterial(name, density);
681 for (
unsigned int i = 0; i < materialComponents.size(); i++) {
684 newMaterialTmp->add(
const_cast<GeoMaterial*
>(origMaterial), fracWeight[i]);
686 ATH_MSG_ERROR(
"Material component missing " << materialComponents[i]);
690 newMaterial = newMaterialTmp;
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) {
711 ", is assumed to be defined by atomic ratio (due to total fraction > 1)"
712 " but component is not an element: " << material.
compName(i));
717 ATH_MSG_ERROR(
"Error making material " << material.
name() <<
". Element not found: " <<
721 totWeight += material.
fraction(i) * element->getA();
725 if (std::abs(totWeight - 1) > 0.01) {
726 ATH_MSG_WARNING(
"Total fractional weight does not sum to 1. Will renormalize. Total = " << totWeight);
730 GeoIntrusivePtr<GeoMaterial> newMaterial{
new GeoMaterial(material.
name(), material.
density())};
732 << material.
density() / (Gaudi::Units::g / Gaudi::Units::cm3));
734 ATH_MSG_ERROR(
"totWeight is zero in InDetMaterialManager::createMaterial");
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) {
747 fracWeight = material.
fraction(i) * element->getA() / totWeight;
749 newMaterial->add(
const_cast<GeoElement*
>(element), fracWeight);
762 newMaterial->add(
const_cast<GeoMaterial*
>(materialTmp.get()), fracWeight);
791 for (
unsigned int i = 0; i <
m_fractions.size(); i++) {
806 const std::string& newName,
807 const GeoMaterial* origMaterial) {
808 if (newName.empty()) {
817 if (!origMaterial)
throw std::runtime_error(std::string(
"Invalid material: ") + materialName);
822 if (scaleFactor < 0 || scaleFactor == 1 || materialName.find(
"Ether") != std::string::npos)
return origMaterial;
826 std::string newName = materialName +
"_ExtraScaling";
832 if (newMaterial)
return newMaterial;
835 double density = origMaterial->getDensity() * scaleFactor;
838 GeoMaterial* newMaterialTmp =
new GeoMaterial(newName, density);
839 newMaterialTmp->add(
const_cast<GeoMaterial*
>(origMaterial), 1.);
841 newMaterial = newMaterialTmp;
854 ExtraScaleFactorMap::const_iterator iter =
m_scalingMap.find(materialName);
861 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 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
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 ®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())