/* XrayLib.NET copyright (c) 2010-2019 Matthew Wormington. All rights reserved. File: Compound.h Author: Matthew Wormington Language: C++/CLI Compiler: Microsoft Visual Studio 2017 Created: September 5, 2010 $Version:$ $Revision:$ $RevDate:$ Description: Contains a managed class around the XrayLib CompoundParser for use with XrayLib.NET. "A library for X-ray–matter interaction cross sections for X-ray fluorescence applications". A. Brunetti, M. Sanchez del Rio, B. Golosio, A. Simionovici, A. Somogyi, Spectrochimica Acta Part B 59 (2004) 1725–1731 http://ftp.esrf.fr/pub/scisoft/xraylib/ Notes: A singleton pattern has been used so that only one instance of the class is ever created. The Instance property provides a global point of access to the instance. The implementation is based on the Static Initialization example in the following Microsoft article: http://msdn.microsoft.com/en-us/library/ms998558.aspx XrayLib copyright (c) 2009, Bruno Golosio, Antonio Brunetti, Manuel Sanchez del Rio, Tom Schoonjans and Teemu Ikonen. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY Bruno Golosio, Antonio Brunetti, Manuel Sanchez del Rio, Tom Schoonjans, Teemu Ikonen and Matthew Wormington ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Bruno Golosio, Antonio Brunetti, Manuel Sanchez del Rio, Tom Schoonjans and Teemu Ikonen BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ extern "C" { #include "..\XrayLib\xraylib-parser.h" } using namespace System; using namespace System::Collections::Generic; using namespace System::Runtime::InteropServices; using namespace System::Text; /// /// A namespace that contains scientific classes. /// namespace Science { /// /// A simple class that gives information on the composition of a compound. /// public ref class CompoundData { List^ _atomCount; List^ _atomicNumber; int _elementCount; List^ _massFraction; double _molarMass; double _totalAtomCount; public: /// Default constructor. CompoundData() { _atomCount = gcnew List(); _atomicNumber = gcnew List(); _massFraction = gcnew List(); Clear(); } /// Constructor. /// The chemical formula of the compound. CompoundData(String^ compound) { _atomCount = gcnew List(); _atomicNumber = gcnew List(); _massFraction = gcnew List(); Parse(compound); } /// Constructor. /// Will calculate the composition corresponding to the sum of the /// compositions of A and B, taking into their weights, with /// weightA + weightB typically less than 1.0. /// The chemical formula of compound A. /// The weight of compound A. /// The chemical formula of compound B. /// The weight of compound B. CompoundData(String^ compoundA, double weightA, String^ compoundB, double weightB) { ::compoundData *cdA, *cdB; ::compoundData *cd; _atomCount = gcnew List(); _atomicNumber = gcnew List(); _massFraction = gcnew List(); Clear(); if (String::IsNullOrEmpty(compoundA) || String::IsNullOrEmpty(compoundB) || (weightA < 0.0) || (weightB < 0.0)) return; IntPtr p = Marshal::StringToHGlobalAnsi(compoundA); try { char* pCompound = static_cast(p.ToPointer()); ::xrl_error *error = nullptr; cdA = ::CompoundParser(pCompound, &error); Errors::HandleError(error); } finally { Marshal::FreeHGlobal(p); } if (cdA == nullptr) return; p = Marshal::StringToHGlobalAnsi(compoundB); try { char* pCompound = static_cast(p.ToPointer()); ::xrl_error *error = nullptr; cdB = ::CompoundParser(pCompound, &error); Errors::HandleError(error); } finally { Marshal::FreeHGlobal(p); } if (cdB == nullptr) { ::FreeCompoundData(cdA); return; } cd = ::add_compound_data(*cdA, weightA, *cdB, weightB); if (cd != nullptr) { _elementCount = cd->nElements; if (_elementCount > 0) { for (int i = 0; i < _elementCount; i++) { _atomCount->Add(cd->nAtoms[i]); _atomicNumber->Add(cd->Elements[i]); _massFraction->Add(cd->massFractions[i]); } } _molarMass = cd->molarMass; _totalAtomCount = cd->nAtomsAll; ::FreeCompoundData(cd); } ::FreeCompoundData(cdA); ::FreeCompoundData(cdB); } /// Parses the chemical formula of the compound into its component elements. /// The chemical formula of the compound. void Parse(String^ compound) { struct ::compoundData *cd; if (String::IsNullOrEmpty(compound)) return; Clear(); IntPtr p = Marshal::StringToHGlobalAnsi(compound); try { char* pCompound = static_cast(p.ToPointer()); ::xrl_error *error = nullptr; cd = ::CompoundParser(pCompound, &error); Errors::HandleError(error); } finally { Marshal::FreeHGlobal(p); } if (cd != nullptr) { _elementCount = cd->nElements; if (_elementCount > 0) { for (int i = 0; i < _elementCount; i++) { _atomCount->Add(cd->nAtoms[i]); _atomicNumber->Add(cd->Elements[i]); _massFraction->Add(cd->massFractions[i]); } } _molarMass = cd->molarMass; _totalAtomCount = cd->nAtomsAll; } ::FreeCompoundData(cd); } /// Clears this object to its blank/initial state. void Clear() { _elementCount = 0; _atomCount->Clear(); _atomicNumber->Clear(); _massFraction->Clear(); _totalAtomCount = 0; } /// Gets the total number of atoms. /// The total number of atoms. property double TotalAtomCount { double get() { return _totalAtomCount; } } /// Gets the number of atoms of the component element with the specified index. /// The number of atoms[int]. property double AtomCount[int] { double get(int index) { return _atomCount[index]; } } /// Gets the number of elements. /// The number of elements. property double ElementCount { double get() { return _elementCount; } } /// Gets the atomic number of the component element with the specified index. /// The atomic number[int]. property int AtomicNumber[int] { int get(int index) { return _atomicNumber[index]; } } /// Gets the mass fraction of the component element with the specified index. /// The mass fraction[int]. property double MassFraction[int] { double get(int index) { return _massFraction[index]; } } /// Convert this object into a string representation. /// Null if it fails, else a string representation of this object. virtual String^ ToString() override { StringBuilder^ sb = gcnew StringBuilder(); sb->AppendLine(String::Format("ElementCount: {0}", _elementCount)); sb->AppendLine(String::Format("AtomicNumber, AtomCount, MassFraction")); for (int i=0; i<_elementCount; i++) sb->AppendLine(String::Format("{0}, {1}, {2}", _atomicNumber[i], _atomCount[i], _massFraction[i])); sb->AppendLine(String::Format("MolarMass: {0}", _molarMass)); sb->AppendLine(String::Format("TotalAtomCount: {0}", _totalAtomCount)); return sb->ToString(); } /// Returns the atomic symbol for the specified element. /// Atomic number of the element. /// Atomic symbol, else null if it fails. static String^ AtomicNumberToSymbol(int Z) { ::xrl_error *error = nullptr; char* pSymbol = ::AtomicNumberToSymbol(Z, &error); Errors::HandleError(error); String^ symbol = gcnew String(pSymbol); ::xrlFree(pSymbol); return symbol; } /// Returns the atomic number for the specified element. /// Atomic symbol of the element. /// Atomic number, else zero if it fails. static int SymbolToAtomicNumber(String^ symbol) { int result = 0; IntPtr p = Marshal::StringToHGlobalAnsi(symbol); try { ::xrl_error *error = nullptr; char* pSymbol = static_cast(p.ToPointer()); result = ::SymbolToAtomicNumber(pSymbol, &error); Errors::HandleError(error); } finally { Marshal::FreeHGlobal(p); } return result; } }; }