/*************************************************************************** PRgeHandler.h Author: Andreas Suter e-mail: andreas.suter@psi.ch ***************************************************************************/ /*************************************************************************** * Copyright (C) 2007-2026 by Andreas Suter * * andreas.suter@psi.ch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _PRGEHANDLER_H_ #define _PRGEHANDLER_H_ #include #include #include #include #include #include "PMusr.h" //----------------------------------------------------------------------------- /** * \brief Data structure for a single TrimSP range distribution at a given energy. * * PRgeData stores the muon/particle implantation depth profile calculated by * TrimSP (Transport of Ions in Matter - Stopping and Range) for a specific * implantation energy. It contains the depth distribution n(z) and normalized * distribution nn(z) where ∫nn(z)dz = 1. * * \see PRgeHandler for the class that reads and manages RGE data * \see PRgeDataList for collections of RGE data sets */ struct PRgeData { Double_t energy; ///< Implantation energy in eV PDoubleVector depth; ///< Depth values in nanometers (nm) PDoubleVector amplitude; ///< Number of particles at each depth (raw counts from TrimSP) PDoubleVector nn; ///< Normalized particle density where ∫nn(z)dz = 1 Double_t noOfParticles; ///< Total number of particles (sum of amplitudes) }; //----------------------------------------------------------------------------- /** * \brief Container for multiple TrimSP range distributions at different energies. * * PRgeDataList is a vector of PRgeData structures, typically containing * implantation profiles for a range of energies (e.g., 1-30 keV). */ typedef std::vector PRgeDataList; //----------------------------------------------------------------------------- /** * \brief XML SAX parser handler for TrimSP configuration files. * * PXmlRgeHandler parses XML configuration files to extract TrimSP (Transport * of Ions in Matter) data file locations and parameters. The XML file specifies: * - Data path: Directory containing .rge files * - Filename prefix: Base name for RGE files (e.g., "LCCO_E") * - Energy list: Implantation energies (individual values or start/stop/step) * * This handler implements ROOT's TSAXParser callbacks for event-driven XML parsing. * * \par XML Format Example: * \code{.xml} * * /path/to/rge/files * Material_E * 1000 * 5000 * * * \endcode * * \see PRgeHandler for the main RGE data manager * \see TSAXParser for ROOT's SAX parser implementation */ class PXmlRgeHandler : public TObject, public TQObject { public: /// Default constructor PXmlRgeHandler() {} /// Destructor virtual ~PXmlRgeHandler() {} /// Called at start of XML document parsing (SLOT) virtual void OnStartDocument(); // SLOT /// Called at end of XML document parsing, performs validation (SLOT) virtual void OnEndDocument(); // SLOT /** * \brief Called when XML start tag is encountered (SLOT) * \param str Element name * \param attributes Element attributes (used for energy_vect) */ virtual void OnStartElement(const char* str, const TList* attributes); // SLOT /** * \brief Called when XML end tag is encountered (SLOT) * \param str Element name */ virtual void OnEndElement(const char* str); // SLOT /** * \brief Called for element content between tags (SLOT) * \param str Character data */ virtual void OnCharacters(const char* str); // SLOT /** * \brief Called for XML comments (SLOT) * \param str Comment text */ virtual void OnComment(const char* str); // SLOT /** * \brief Called when parser emits a warning (SLOT) * \param str Warning message */ virtual void OnWarning(const char* str); // SLOT /** * \brief Called when parser encounters an error (SLOT) * \param str Error message */ virtual void OnError(const char* str); // SLOT /** * \brief Called when parser encounters a fatal error (SLOT) * \param str Fatal error message */ virtual void OnFatalError(const char* str); // SLOT /** * \brief Called for CDATA blocks (SLOT) * \param str CDATA content * \param len Length of CDATA */ virtual void OnCdataBlock(const char* str, Int_t len); // SLOT /** * \brief Returns validity status of parsed configuration. * \return True if XML was parsed successfully and all required fields are present */ virtual bool IsValid() { return fIsValid; } /** * \brief Returns the TrimSP data directory path. * \return Directory path containing .rge files */ virtual std::string GetTrimSpDataPath() { return fTrimSpDataPath; } /** * \brief Returns the RGE filename prefix. * \return Filename prefix (e.g., "LCCO_E" for files like LCCO_E1000.rge) */ virtual std::string GetTrimSpFlnPre() { return fTrimSpFlnPre; } /** * \brief Returns the list of implantation energies. * \return Vector of energies in eV */ virtual const PIntVector GetTrimSpDataVectorList() const { return fTrimSpDataEnergyList; } private: /// Enum for tracking which XML element is currently being parsed enum EKeyWords {eEmpty, eDataPath, eFlnPre, eEnergy}; EKeyWords fKey; ///< Current parsing context/state bool isTrimSp{false}; ///< True when inside element bool fIsValid{true}; ///< Validity flag (false if parsing errors occur) std::string fTrimSpDataPath{""}; ///< Directory path to RGE files std::string fTrimSpFlnPre{""}; ///< RGE filename prefix (e.g., "LCCO_E" for LCCO_E1000.rge) PIntVector fTrimSpDataEnergyList; ///< List of implantation energies in eV ClassDef(PXmlRgeHandler, 1) }; //----------------------------------------------------------------------------- /** * \brief Manager for TrimSP range distribution data. * * PRgeHandler reads and manages muon/particle implantation depth profiles * calculated by TrimSP (Transport of Ions in Matter - Stopping and Range). * It provides access to: * - Particle implantation depth distributions n(E,z) * - Normalized distributions nn(E,z) where ∫nn(z)dz = 1 * - Maximum penetration depths for different energies * * The class loads RGE files specified in an XML configuration file, which * can contain data for multiple implantation energies. RGE files contain * depth (in Ångström) vs. particle count data from TrimSP simulations. * * \par Typical Usage: * \code * PRgeHandler rge("config.xml"); * if (rge.IsValid()) { * Double_t zmax = rge.GetZmax(5000.0); // Max depth at 5 keV * Double_t n = rge.Get_n(5000.0, 10.0); // Distribution at 5 keV, 10 nm depth * } * \endcode * * \see PRgeData for the data structure holding individual distributions * \see PXmlRgeHandler for XML configuration parsing */ class PRgeHandler : public TObject { public: /** * \brief Constructor that loads TrimSP data from XML configuration. * \param fln Path to XML configuration file (empty string for manual setup) * * Parses the XML file to get RGE file locations and energies, then loads * all specified RGE files. Sets fValid to false if any errors occur. */ PRgeHandler(std::string fln=""); /// Destructor virtual ~PRgeHandler() {} /** * \brief Returns validity status. * \return True if all RGE files loaded successfully, false if errors occurred */ virtual bool IsValid() { return fValid; } /** * \brief Returns number of loaded RGE data sets. * \return Number of energy data sets (one per energy value) */ virtual UInt_t GetNoOfRgeDataSets() { return (UInt_t)fData.size(); } /** * \brief Returns all RGE data sets. * \return Vector of all loaded PRgeData structures */ virtual PRgeDataList GetRgeData() { return fData; } /** * \brief Returns maximum penetration depth for a given energy. * \param energy Implantation energy in eV * \return Maximum depth in nm, or -1 if energy not found */ virtual Double_t GetZmax(const Double_t energy); /** * \brief Returns maximum penetration depth for a data set index. * \param idx Data set index (0 to GetNoOfRgeDataSets()-1) * \return Maximum depth in nm, or -1 if idx out of range */ virtual Double_t GetZmax(const Int_t idx); /** * \brief Returns normalized particle distribution at given energy and depth. * \param energy Implantation energy in eV * \param z Depth in nm * \return Normalized distribution nn(E,z), or 0.0 if out of range * * Uses linear interpolation between data points. The normalization ensures * that ∫nn(z)dz = 1 over the entire depth range. */ virtual Double_t Get_n(const Double_t energy, const Double_t z); /** * \brief Returns normalized particle distribution at given index and depth. * \param idx Data set index (0 to GetNoOfRgeDataSets()-1) * \param z Depth in nm * \return Normalized distribution nn(idx,z), or 0.0 if out of range * * Uses linear interpolation between data points. The normalization ensures * that ∫nn(z)dz = 1 over the entire depth range. */ virtual Double_t Get_n(const Int_t idx, const Double_t z); /** * \brief Finds the data set index for a given energy. * \param energy Implantation energy in eV * \return Data set index, or -1 if energy not found * * Uses tolerance of 0.9 keV for matching energies. */ virtual Int_t GetEnergyIndex(const Double_t energy); private: bool fValid{false}; ///< Validity flag (true if all RGE files loaded successfully) PRgeDataList fData; ///< Collection of RGE data sets (one per energy) /** * \brief Reads a single RGE file and populates a PRgeData structure. * \param fln Path to the .rge file * \param data PRgeData structure to populate * \return True on success, false on error * * Parses the two-column format (depth amplitude) from TrimSP output. * Converts depth from Ångström to nanometers. */ virtual bool ReadRgeFile(const std::string fln, PRgeData &data); ClassDef(PRgeHandler, 1) }; #endif // _PRGEHANDLER_H_