# Program Listing for File compound.hpp

↰ Return to documentation for file (`cif++/compound.hpp`)

    /*-
     * SPDX-License-Identifier: BSD-2-Clause
     *
     * Copyright (c) 2020-2022 NKI/AVL, Netherlands Cancer Institute
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer
     * 2. 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.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
     */

    #pragma once

    #include "cif++/atom_type.hpp"
    #include "cif++/datablock.hpp"
    #include "cif++/exports.hpp"
    #include "cif++/point.hpp"
    #include "cif++/utilities.hpp"

    #include <map>
    #include <set>
    #include <tuple>
    #include <vector>

    namespace cif
    {

    // --------------------------------------------------------------------

    class compound;
    struct compound_atom;
    class compound_factory_impl;

    enum class bond_type
    {
        sing,
        doub,
        trip,
        quad,
        arom,
        poly,
        delo,
        pi,
    };

    std::string bond_type_to_string(bond_type bondType);

    bond_type parse_bond_type_from_string(const std::string &bondType);

    enum class stereo_config_type : uint8_t
    {
        N = 'N',
        R = 'R',
        S = 'S'
    };

    std::string to_string(stereo_config_type stereo_config);

    stereo_config_type parse_stereo_config_from_string(const std::string &stereo_config);

    struct compound_atom
    {
        std::string id;
        atom_type type_symbol;
        int charge = 0;
        bool aromatic = false;
        bool leaving_atom = false;
        stereo_config_type stereo_config = stereo_config_type::N;
        float x,
            y,
            z;

        point get_location() const
        {
            return { x, y, z };
        }
    };

    struct compound_bond
    {
        std::string atom_id[2];
        bond_type type;
        bool aromatic = false,
            stereo_config = false;
    };

    class compound
    {
      public:
        // accessors

        std::string id() const { return m_id; }
        std::string name() const { return m_name; }
        std::string type() const { return m_type; }
        std::string formula() const { return m_formula; }
        float formula_weight() const { return m_formula_weight; }
        int formal_charge() const { return m_formal_charge; }

        const std::vector<compound_atom> &atoms() const { return m_atoms; }
        const std::vector<compound_bond> &bonds() const { return m_bonds; }

        compound_atom get_atom_by_atom_id(const std::string &atom_id) const;

        bool atoms_bonded(const std::string &atomId_1, const std::string &atomId_2) const;
        float bond_length(const std::string &atomId_1, const std::string &atomId_2) const;

        bool is_water() const
        {
            return m_id == "HOH" or m_id == "H2O" or m_id == "WAT";
        }

        bool is_peptide() const;

        bool is_base() const;

        char one_letter_code() const { return m_one_letter_code; };
        std::string parent_id() const { return m_parent_id; };

      private:
        friend class compound_factory_impl;
        friend class local_compound_factory_impl;

        compound(datablock &db);

        std::string m_id;
        std::string m_name;
        std::string m_type;
        std::string m_formula;
        char m_one_letter_code = 0;
        std::string m_parent_id;
        float m_formula_weight = 0;
        int m_formal_charge = 0;
        std::vector<compound_atom> m_atoms;
        std::vector<compound_bond> m_bonds;
    };

    // --------------------------------------------------------------------
    // Factory class for compound and Link objects

    class compound_factory
    {
      public:

        static void init(bool useThreadLocalInstanceOnly);

        static compound_factory &instance();

        static void clear();

        void set_default_dictionary(const std::filesystem::path &inDictFile);

        void push_dictionary(const std::filesystem::path &inDictFile);

        void push_dictionary(const file &file);

        void pop_dictionary();

        [[deprecated("use is_peptide or is_std_peptide instead)")]]
        bool is_known_peptide(const std::string &res_name) const;

        [[deprecated("use is_base or is_std_base instead)")]]
        bool is_known_base(const std::string &res_name) const;

        bool is_peptide(std::string_view res_name) const;

        bool is_base(std::string_view res_name) const;

        bool is_std_peptide(std::string_view res_name) const;

        bool is_std_base(std::string_view res_name) const;

        bool is_monomer(std::string_view res_name) const;

        bool is_std_monomer(std::string_view res_name) const
        {
            return is_std_base(res_name) or is_std_peptide(res_name);
        }

        bool is_water(std::string_view res_name) const
        {
            return res_name == "HOH" or res_name == "H2O" or res_name == "WAT";
        }

        bool exists(std::string_view res_name) const;

        const compound *create(std::string_view id);

        ~compound_factory();

        CIFPP_EXPORT static const std::map<std::string, char> kAAMap,
            kBaseMap;

        void report_missing_compound(std::string_view compound_id);

        bool get_report_missing() const { return m_report_missing; }

        void set_report_missing(bool report)
        {
            m_report_missing = report;
        }

      private:
        compound_factory();

        compound_factory(const compound_factory &) = delete;
        compound_factory &operator=(const compound_factory &) = delete;

        static std::unique_ptr<compound_factory> s_instance;
        static thread_local std::unique_ptr<compound_factory> tl_instance;
        static bool s_use_thread_local_instance;

        std::shared_ptr<compound_factory_impl> m_impl;
        bool m_report_missing = true;
    };

    // --------------------------------------------------------------------

    class compound_source
    {
      public:
        compound_source(const file &file)
        {
            compound_factory::instance().push_dictionary(file);
        }

        ~compound_source()
        {
            compound_factory::instance().pop_dictionary();
        }
    };

    } // namespace cif