File indexing completed on 2024-04-21 03:41:36

0001 /*
0002     SPDX-FileCopyrightText: 2005 Inge Wallin <inge@lysator.liu.se>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #ifndef MOLECULEPARSER_H
0007 #define MOLECULEPARSER_H
0008 
0009 #include "science_export.h"
0010 
0011 #include "element.h"
0012 #include "parser.h"
0013 
0014 #include <QList>
0015 #include <QMap>
0016 
0017 /**
0018  * @class ElementCount
0019  * @author Inge Wallin
0020  */
0021 class SCIENCE_EXPORT ElementCount
0022 {
0023 public:
0024     /**
0025      * Constructor
0026      */
0027     ElementCount(Element *_element, int _count)
0028     {
0029         m_element = _element;
0030         m_count = _count;
0031     }
0032 
0033     /**
0034      * Constructor
0035      */
0036     explicit ElementCount(Element *_element)
0037     {
0038         m_element = _element;
0039         m_count = 0;
0040     }
0041     /**
0042      * Destructor
0043      */
0044     ~ElementCount();
0045 
0046     /**
0047      * @return the Element
0048      */
0049     Element *element() const
0050     {
0051         return m_element;
0052     }
0053 
0054     /**
0055      * @return the number of occurrences of the Element
0056      */
0057     int count() const
0058     {
0059         return m_count;
0060     }
0061 
0062     /**
0063      * Add @p _count occurrences of the Element
0064      * @param _count The number of times the Element occurs
0065      */
0066     void add(int _count)
0067     {
0068         m_count += _count;
0069     }
0070     void multiply(int _factor)
0071     {
0072         m_count *= _factor;
0073     }
0074 
0075     /**
0076      * The Element of the object
0077      */
0078     Element *m_element;
0079     /**
0080      * The number of occurrences
0081      */
0082     int m_count;
0083 };
0084 
0085 /**
0086  * This class is used to count the elements in the molecule
0087  * which is being calculated
0088  *
0089  * @class ElementCountMap
0090  * @author Inge Wallin
0091  */
0092 class SCIENCE_EXPORT ElementCountMap
0093 {
0094 public:
0095     /**
0096      * Constructor
0097      */
0098     ElementCountMap();
0099 
0100     /**
0101      * Destructor
0102      */
0103     ~ElementCountMap();
0104 
0105     /**
0106      * Clear the map of ElementCount pointers
0107      */
0108     void clear()
0109     {
0110         m_map.clear();
0111     }
0112 
0113     /**
0114      * @param _element the searched Element
0115      * @return the Element which is searched
0116      */
0117     ElementCount *search(Element *_element);
0118 
0119     /**
0120      * @param _map
0121      */
0122     void add(ElementCountMap &_map);
0123 
0124     /**
0125      * Returns the elements in the molecule. For example, if the molecule
0126      * is CO2, a list with C and O will be returned.
0127      * @return the elements in the molecule
0128      */
0129     QList<Element *> elements() const;
0130 
0131     /**
0132      * @param _element
0133      * @param _count
0134      */
0135     void add(Element *_element, int _count);
0136 
0137     /**
0138      * @param _factor
0139      */
0140     void multiply(int _factor);
0141 
0142     QList<ElementCount *> map()
0143     {
0144         return m_map;
0145     }
0146 
0147 private:
0148     QList<ElementCount *> m_map;
0149 };
0150 
0151 /**
0152  * @class MoleculeParser
0153  *
0154  * Parse molecule formulas.
0155  *
0156  * Usage:
0157  * @code
0158  *   MoleculeParser  parser;
0159  *   QString         chemical_formula = "C2H5OH";
0160  *   double          weight;
0161  *
0162  *   if (parser.weight(chemical_formula, &weight))
0163  *     cout << "Weight of " << chemical_formula << " = " << weight << ".\n";
0164  *   else
0165  *     cout << "Parse error\n";
0166  * @endcode
0167  *
0168  * If a short form of a compound is specified, it will be expanded.
0169  * Example :- EtOH -> (C2H5OH)
0170  * @code
0171  *   MoleculeParser  parser;
0172  *   QString         chemical_formula = "EtOH";
0173  *   double          weight;
0174  *
0175  *   if (parser.weight(chemical_formula, &weight))
0176  *     cout << "Weight of " << chemical_formula << " = " << weight << ".\n";
0177  *   else
0178  *     cout << "Parse error\n";
0179  * @endcode
0180  *
0181  * @author Inge Wallin
0182  * @author Kashyap R Puranik
0183  */
0184 class SCIENCE_EXPORT MoleculeParser : public Parser
0185 {
0186 public:
0187     /**
0188      * @param list This list of chemical elements will be used internally
0189      * for searching and matching with searched strings
0190      * Constructor
0191      */
0192     explicit MoleculeParser(const QList<Element *> &list);
0193 
0194     /**
0195      * Constructor
0196      *
0197      * @param _str @ref Parser::start the parsing with @p _str
0198      */
0199     explicit MoleculeParser(const QString &_str);
0200 
0201     /**
0202      * Destructor
0203      */
0204     ~MoleculeParser() override;
0205 
0206     /**
0207      * Try to parse the molecule @p molecule and get the weight of it.
0208      * The calculated weight is stored in @p _result.
0209      *
0210      * @param _moleculeString
0211      * @param _resultMass
0212      * @param _resultMap
0213      *
0214      * @return whether the parsing was successful or not
0215      */
0216     bool weight(const QString &_moleculeString, double *_resultMass, ElementCountMap *_resultMap);
0217 
0218     QSet<QString> aliasList();
0219 
0220 private:
0221     // Helper functions
0222     bool parseSubmolecule(double *_resultMass, ElementCountMap *_resultMap);
0223     bool parseTerm(double *_resultMass, ElementCountMap *_resultMap);
0224     // This function expands the molecule string
0225     // eg expandFormula(EtOH)    returns (C2H5)OH
0226     QString expandFormula(const QString &_shortMolecularMass);
0227     // This function expands a term
0228     // eg expandTerm(Et) returns (C2H5)
0229     QString expandTerm(const QString &_group);
0230 
0231     QList<Element *> m_elementList;
0232 
0233     static const int ELEMENT_TOKEN = 300;
0234 
0235     Element *lookupElement(const QString &_name);
0236 
0237     QMap<Element *, int> m_elementMap;
0238 
0239     // Contains the list of aliases eg, { "Et - C2H5", "Me - CH3"}
0240     QSet<QString> *m_aliasList;
0241     // if this booloean is "true" the parser found an error
0242     bool m_error;
0243 
0244 protected:
0245     /**
0246      * Extends the standard tokenizer in Parser::getNextToken().
0247      */
0248     int getNextToken() override;
0249 
0250 private:
0251     Element *m_elementVal; // Valid if m_nextToken == ELEMENT_TOKEN
0252 };
0253 
0254 #endif // MOLECULEPARSER_H