11#include <NeXusFile.hpp>
12#include <boost/lexical_cast.hpp>
19using str_pair = std::pair<std::string, std::string>;
26constexpr double INV_FOUR_PI = 1. / (4. * M_PI);
28inline double scatteringLength(
const double real,
const double imag) {
31 length = std::abs(real);
32 }
else if (real == 0.) {
33 length = std::abs(imag);
35 length = std::hypot(real, imag);
38 if (!std::isnormal(length)) {
45inline double scatteringXS(
const double realLength,
const double imagLength) {
46 double lengthSqrd = (realLength * realLength) + (imagLength * imagLength);
48 if (!std::isnormal(lengthSqrd)) {
51 return .04 * M_PI * lengthSqrd;
57 const double multiplicity)
58 : atom(
std::move(atom)), multiplicity(multiplicity) {}
80 const double packingFraction,
const double temperature,
const double pressure)
81 : m_name(
std::move(name)), m_atomTotal(0.0), m_numberDensity(numberDensity), m_packingFraction(packingFraction),
82 m_temperature(temperature), m_pressure(pressure) {
99 const double packingFraction,
const double temperature,
const double pressure)
100 : m_name(
std::move(name)), m_chemicalFormula(), m_atomTotal(1.0), m_numberDensity(numberDensity),
101 m_packingFraction(packingFraction), m_temperature(temperature), m_pressure(pressure) {
129 double weightedTotal;
136 return subtotal +
right.atom->neutron.abs_scatt_xs *
right.multiplicity;
141 if (!std::isnormal(weightedTotal)) {
151 double weightedTotal;
157 return subtotal +
right.atom->neutron.tot_scatt_xs *
right.multiplicity;
162 if (!std::isnormal(weightedTotal)) {
294 throw std::runtime_error(
"xRayAttenuationProfile override not set");
315 std::vector<double>::const_iterator lambdaEnd)
const {
319 std::vector<double> linearCoef(std::distance(lambdaBegin, lambdaEnd));
321 std::transform(lambdaBegin, lambdaEnd, linearCoef.begin(),
322 [densityTerm,
this](
const double lambda) { return densityTerm * this->absorbXSection(lambda); });
354 const double weightedTotal =
357 return subtotal +
right.atom->neutron.coh_scatt_length_real *
right.multiplicity;
361 if (!std::isnormal(weightedTotal)) {
364 return weightedTotal;
375 const double weightedTotal =
378 return subtotal +
right.atom->neutron.coh_scatt_length_img *
right.multiplicity;
382 if (!std::isnormal(weightedTotal)) {
385 return weightedTotal;
396 const double weightedTotal =
399 return subtotal +
right.atom->neutron.inc_scatt_length_real *
right.multiplicity;
403 if (!std::isnormal(weightedTotal)) {
406 return weightedTotal;
417 const double weightedTotal =
420 return subtotal +
right.atom->neutron.inc_scatt_length_img *
right.multiplicity;
424 if (!std::isnormal(weightedTotal)) {
427 return weightedTotal;
439 return 10. * std::sqrt(crossSection) * INV_FOUR_PI;
451 lengthSqrd = real * real;
452 }
else if (real == 0.) {
453 lengthSqrd = imag * imag;
455 lengthSqrd = real * real + imag * imag;
458 if (!std::isnormal(lengthSqrd)) {
472 return 100. * crossSection * INV_FOUR_PI;
482 return 100. * crossSection * INV_FOUR_PI;
490 file->makeGroup(group,
"NXdata",
true);
491 file->putAttr(
"version", 2);
492 file->putAttr(
"name",
m_name);
495 std::string style =
"formula";
500 style =
"userdefined";
503 file->putAttr(
"formulaStyle", style);
506 if (style ==
"formula") {
507 std::stringstream formula;
509 if (formulaUnit.atom->a_number != 0) {
512 formula << formulaUnit.atom->symbol;
513 if (formulaUnit.atom->a_number != 0) {
514 formula << formulaUnit.atom->a_number <<
")";
516 formula << formulaUnit.multiplicity <<
" ";
518 file->writeData(
"chemical_formula", formula.str());
519 }
else if (style ==
"userdefined") {
520 file->writeData(
"coh_scatt_length_real",
m_chemicalFormula[0].atom->neutron.coh_scatt_length_real);
521 file->writeData(
"coh_scatt_length_img",
m_chemicalFormula[0].atom->neutron.coh_scatt_length_img);
522 file->writeData(
"inc_scatt_length_real",
m_chemicalFormula[0].atom->neutron.inc_scatt_length_real);
523 file->writeData(
"inc_scatt_length_img",
m_chemicalFormula[0].atom->neutron.inc_scatt_length_img);
524 file->writeData(
"coh_scatt_xs",
m_chemicalFormula[0].atom->neutron.coh_scatt_xs);
525 file->writeData(
"inc_scatt_xs",
m_chemicalFormula[0].atom->neutron.inc_scatt_xs);
526 file->writeData(
"tot_scatt_xs",
m_chemicalFormula[0].atom->neutron.tot_scatt_xs);
527 file->writeData(
"abs_scatt_xs",
m_chemicalFormula[0].atom->neutron.abs_scatt_xs);
528 file->writeData(
"tot_scatt_length",
m_chemicalFormula[0].atom->neutron.tot_scatt_length);
529 file->writeData(
"coh_scatt_length",
m_chemicalFormula[0].atom->neutron.coh_scatt_length);
530 file->writeData(
"inc_scatt_length",
m_chemicalFormula[0].atom->neutron.inc_scatt_length);
545 file->openGroup(group,
"NXdata");
546 file->getAttr(
"name",
m_name);
548 file->getAttr(
"version", version);
552 uint16_t element_Z, element_A;
553 file->readData(
"element_Z", element_Z);
554 file->readData(
"element_A", element_A);
562 }
catch (std::runtime_error &) {
564 }
else if (version == 2) {
566 file->getAttr(
"formulaStyle", style);
568 if (style ==
"formula") {
570 file->readData(
"chemical_formula", formula);
573 }
else if (style ==
"userdefined") {
591 throw std::runtime_error(
"Only know how to read version 1 or 2 for Material");
600 }
catch (std::runtime_error &) {
609str_pair getAtomName(
const std::string &text)
612 if (text.size() <= 1)
613 return std::make_pair(text,
"");
618 if ((s[1] >=
'0' && s[1] <=
'9') || s[1] ==
'.')
619 return std::make_pair(text.substr(0, 1), text.substr(1));
621 return std::make_pair(text.substr(0, 2), text.substr(2));
629 for (
const auto &atom : tokens) {
632 float numberAtoms = 1;
633 uint16_t aNumber = 0;
636 if (atom.find(
'(') != std::string::npos) {
638 size_t end = atom.find(
')');
639 if (end == std::string::npos) {
640 std::stringstream msg;
641 msg <<
"Failed to parse isotope \"" << atom <<
"\"";
642 throw std::runtime_error(msg.str());
646 std::string numberAtomsStr = atom.substr(end + 1);
647 if (!numberAtomsStr.empty())
648 numberAtoms = boost::lexical_cast<float>(numberAtomsStr);
651 name = atom.substr(1, end - 1);
655 aNumber = boost::lexical_cast<uint16_t>(temp.second);
660 if (!temp.second.empty())
661 numberAtoms = boost::lexical_cast<float>(temp.second);
664 CF.emplace_back(getAtom(
name, aNumber),
static_cast<double>(numberAtoms));
665 }
catch (boost::bad_lexical_cast &e) {
666 std::stringstream msg;
667 msg <<
"While trying to parse atom \"" << atom <<
"\" encountered bad_lexical_cast: " << e.what();
668 throw std::runtime_error(msg.str());
const std::vector< double > * lambda
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
ChemicalFormula m_chemicalFormula
The normalized chemical formula.
double m_totalScatterXSection
Material()
Default constructor.
double attenuationCoefficient(const double lambda) const
double m_temperature
Temperature.
void setAttenuationProfile(AttenuationProfile attenuationOverride)
Allow an explicit attenuation profile to be loaded onto the material that overrides the standard line...
double attenuation(const double distance, const double lambda=PhysicalConstants::NeutronAtom::ReferenceLambda) const
Compute the attenuation at a given wavelength over the given distance.
void setXRayAttenuationProfile(AttenuationProfile attenuationProfile)
std::vector< FormulaUnit > ChemicalFormula
const Material::ChemicalFormula & chemicalFormula() const
void saveNexus(::NeXus::File *file, const std::string &group) const
Save the object to an open NeXus file.
double packingFraction() const
Get the packing fraction.
static ChemicalFormula parseChemicalFormula(const std::string &chemicalSymbol)
void countAtoms()
Update the total atom count.
double cohScatterLengthReal(const double lambda=PhysicalConstants::NeutronAtom::ReferenceLambda) const
Get the coherent scattering length for a given wavelength in fm.
void calculateLinearAbsorpXSectionByWL()
Update the linear absorption x section (by wavelength)
double incohScatterLengthSqrd(const double lambda=PhysicalConstants::NeutronAtom::ReferenceLambda) const
Get the incoherent length squared, , for a given wavelength in .
double incohScatterLength(const double lambda=PhysicalConstants::NeutronAtom::ReferenceLambda) const
Get the incoherent length for a given wavelength in fm.
double temperature() const
Get the temperature.
double cohScatterLength(const double lambda=PhysicalConstants::NeutronAtom::ReferenceLambda) const
Get the coherent scattering length for a given wavelength in fm.
double cohScatterLengthSqrd(const double lambda=PhysicalConstants::NeutronAtom::ReferenceLambda) const
Get the coherent scattering length squared, , for a given wavelength in .
double cohScatterLengthImg(const double lambda=PhysicalConstants::NeutronAtom::ReferenceLambda) const
Get the coherent scattering length for a given wavelength in fm.
double numberDensity() const
Get the number density.
double incohScatterLengthReal(const double lambda=PhysicalConstants::NeutronAtom::ReferenceLambda) const
Get the incoherent length for a given wavelength in fm.
double m_packingFraction
Packing fraction should be between 0 and 2.
double m_atomTotal
Total number of atoms.
double totalAtoms() const
The total number of atoms in the formula.
boost::optional< AttenuationProfile > m_attenuationOverride
double cohScatterXSection() const
Get the coherent scattering cross section for a given wavelength in barns.
void loadNexus(::NeXus::File *file, const std::string &group)
Load the object from an open NeXus file.
double totalScatterLength(const double lambda=PhysicalConstants::NeutronAtom::ReferenceLambda) const
Return the total scattering length for a given wavelength in fm.
double absorbXSection(const double lambda=PhysicalConstants::NeutronAtom::ReferenceLambda) const
Get the absorption cross section at a given wavelength in barns.
const std::string & name() const
Returns the name of the material.
double numberDensityEffective() const
Get the effective number density.
double incohScatterXSection() const
Get the incoherent cross section for a given wavelength in barns.
double pressure() const
Get the pressure.
double incohScatterLengthImg(const double lambda=PhysicalConstants::NeutronAtom::ReferenceLambda) const
Get the incoherent length for a given wavelength in fm.
double linearAbsorpCoef(const double lambda=PhysicalConstants::NeutronAtom::ReferenceLambda) const
Returns the linear coefficient of absorption for the material in units of cm^-1 this should match the...
double totalScatterXSection() const
Return the total scattering cross section for a given wavelength in barns.
std::string m_name
Material name.
double m_linearAbsorpXSectionByWL
double m_pressure
Pressure.
boost::optional< AttenuationProfile > m_xRayAttenuationProfile
double m_numberDensity
Number density in atoms per A^-3.
bool hasValidXRayAttenuationProfile()
double xRayAttenuation(const double distance, const double energy) const
Compute the x-ray attenuation at a given energy over the given distance.
double totalScatterLengthSqrd(const double lambda=PhysicalConstants::NeutronAtom::ReferenceLambda) const
Return the total scattering length squared, , for a given wavelength in .
void calculateTotalScatterXSection()
Update the total scatter x section.
@ TOK_IGNORE_EMPTY
ignore empty tokens
Struture to hold the common information for an atom.
std::pair< std::string, std::string > str_pair
A namespace containing physical constants that are required by algorithms and unit routines.
MANTID_KERNEL_DLL const Atom & getAtom(const uint16_t z_number, const uint16_t a_number=0)
MANTID_KERNEL_DLL NeutronAtom getNeutronAtom(const uint16_t z_number, const uint16_t a_number=0)
Retrieve a copy of NeutronAtom.
Structure to store neutronic scattering information for the various elements.
double coh_scatt_length_real
The real part of the coherent scattering length in fm.
double tot_scatt_length
The total scattering length in fm.
double inc_scatt_length
The incoherent scattering length in fm.
uint16_t z_number
The atomic number, or number of protons, for the atom.
double coh_scatt_length
The coherent scattering length in fm.
double coh_scatt_length_img
The imaginary part of the coherent scattering length in fm.
double inc_scatt_length_img
The imaginary part of the incoherent scattering length in fm.
double inc_scatt_xs
The incoherent scattering cross section in barns.
double tot_scatt_xs
The total scattering cross section in barns.
double abs_scatt_xs
The absorption cross section for 2200m/s neutrons in barns.
double inc_scatt_length_real
The real part of the incoherent scattering length in fm.
double coh_scatt_xs
The coherent scattering cross section in barns.
static const double ReferenceLambda
The reference wavelength value for absorption cross sections.
uint16_t a_number
The total number of protons and neutrons, or mass number, for the atom for isotopic averages this is ...