void MoleculeJsonLoader::loadMolecule()

in core/indigo-core/molecule/src/molecule_json_loader.cpp [1523:1819]


void MoleculeJsonLoader::loadMolecule(BaseMolecule& mol, bool load_arrows)
{
    ObjArray<Array<int>> mol_mappings;
    for (rapidjson::SizeType node_idx = 0; node_idx < _mol_nodes.Size(); ++node_idx)
    {
        std::vector<EnhancedStereoCenter> stereo_centers;
        std::unique_ptr<BaseMolecule> pmol(mol.neu());
        _pmol = nullptr;
        _pqmol = nullptr;
        if (pmol->isQueryMolecule())
        {
            _pqmol = &pmol->asQueryMolecule();
        }
        else
        {
            _pmol = &pmol->asMolecule();
        }
        mol.original_format = BaseMolecule::KET;

        auto& mol_node = _mol_nodes[node_idx];

        if (mol_node.HasMember("atoms"))
        {
            // parse atoms
            auto& atoms = mol_node["atoms"];
            parseAtoms(atoms, *pmol, stereo_centers);
            // parse bonds
            if (mol_node.HasMember("bonds"))
            {
                parseBonds(mol_node["bonds"], *pmol);
            }
            pmol->unhighlightAll();
            if (mol_node.HasMember("highlight"))
            {
                parseHighlight(mol_node["highlight"], *pmol);
            }

            // parse SGroups
            if (mol_node.HasMember("sgroups"))
            {
                parseSGroups(mol_node["sgroups"], *pmol);
            }

            if (mol_node.HasMember("stereoFlagPosition"))
            {
                setStereoFlagPosition(mol_node["stereoFlagPosition"], node_idx, mol);
            }

            if (mol_node.HasMember("properties"))
            {
                parseProperties(mol_node["properties"], *pmol);
            }
        }
        else
        {
            throw Error("Expected atoms block not found");
        }

        Array<int> mapping;
        mol.mergeWithMolecule(*pmol, &mapping, 0);
        mol_mappings.push().copy(mapping);

        for (auto& sc : stereo_centers)
        {
            sc._atom_idx = mapping[sc._atom_idx];
            _stereo_centers.push_back(sc);
        }
    }

    MoleculeRGroups& rgroups = mol.rgroups;
    Document data;
    for (auto& rgrp : _rgroups)
    {
        RGroup& rgroup = rgroups.getRGroup(rgrp.first);
        Value one_rnode(kArrayType);
        Value& rnode = rgrp.second;
        if (rnode.HasMember("fragments"))
        {
            auto& rfragments = rnode["fragments"];
            for (SizeType i = 0; i < rfragments.Size(); i++)
            {
                std::unique_ptr<BaseMolecule> fragment(mol.neu());
                one_rnode.PushBack(rfragments[i], data.GetAllocator());
                MoleculeJsonLoader loader(one_rnode);
                loader.stereochemistry_options = stereochemistry_options;
                loader.loadMolecule(*fragment.get());
                rgroup.fragments.add(fragment.release());
                one_rnode.Clear();
            }
        }
        else
        {
            std::unique_ptr<BaseMolecule> fragment(mol.neu());
            one_rnode.PushBack(rnode, data.GetAllocator());
            MoleculeJsonLoader loader(one_rnode);
            loader.stereochemistry_options = stereochemistry_options;
            loader.loadMolecule(*fragment.get());
            rgroup.fragments.add(fragment.release());
        }
    }

    // Add monomer teplates
    for (SizeType i = 0; i < _templates.Size(); i++)
    {
        auto& mt = _templates[i];
        // int tp = mt.GetType();
        if (mt.HasMember("type") && mt["type"].GetString() == std::string("monomerTemplate"))
            parseMonomerTemplate(mt, mol, stereochemistry_options);
        else if (mt.HasMember("type") && mt["type"].GetString() == std::string("ambiguousMonomerTemplate"))
            parseAmbiguousMonomerTemplate(mt, mol);
    }

    std::unordered_map<int, int> monomer_id_mapping;
    for (SizeType i = 0; i < _monomer_array.Size(); i++)
    {
        auto& ma = _monomer_array[i];

        if (!ma.HasMember("alias"))
            throw Error("Monomer alias is missing");

        int idx = mol.addTemplateAtom(ma["alias"].GetString());
        int monomer_id = std::stoi(std::string(ma["id"].GetString()));
        monomer_id_mapping.emplace(monomer_id, idx);

        if (ma.HasMember("seqid"))
            mol.setTemplateAtomSeqid(idx, ma["seqid"].GetInt());

        if (ma.HasMember("position"))
        {
            auto& pos_val = ma["position"];
            mol.setAtomXyz(idx, static_cast<float>(pos_val["x"].GetDouble()), static_cast<float>(pos_val["y"].GetDouble()), 0);
        }

        std::string template_id = ma["templateId"].GetString();
        auto temp_it = _id_to_template.find(template_id);
        if (temp_it != _id_to_template.end())
        {
            mol.setTemplateAtomClass(idx, monomerMolClass(monomerTemplateClass(_templates[temp_it->second])).c_str());
            mol.setTemplateAtomTemplateIndex(idx, temp_it->second);
        }
    }

    for (SizeType i = 0; i < _monomer_shapes.Size(); i++)
    {
        auto& shape = _monomer_shapes[i];
        Vec2f position;
        const Value& coords = shape["position"];
        position.x = coords["x"].GetFloat();
        position.y = coords["y"].GetFloat();
        std::vector<std::string> monomers;
        auto& mons = shape["monomers"];
        for (SizeType j = 0; j < mons.Size(); j++)
        {
            monomers.emplace_back(mons[j].GetString());
        }
        mol.monomer_shapes.add(new KetMonomerShape(shape["id"].GetString(), shape["collapsed"].GetBool(), shape["shape"].GetString(), position, monomers));
    }

    std::vector<int> ignore_cistrans(mol.edgeCount());
    std::vector<int> sensible_bond_directions(mol.edgeCount());
    for (int i = 0; i < mol.edgeCount(); i++)
        if (mol.getBondDirection(i) == BOND_EITHER)
        {
            if (mol.cis_trans.isIgnored(i))
            {
                ignore_cistrans[i] = 1;
                sensible_bond_directions[i] = 1;
            }
            else if (MoleculeCisTrans::isGeomStereoBond(mol, i, 0, true))
            {
                ignore_cistrans[i] = 1;
                sensible_bond_directions[i] = 1;
            }
            else
            {
                int k;
                const Vertex& v = mol.getVertex(mol.getEdge(i).beg);

                for (k = v.neiBegin(); k != v.neiEnd(); k = v.neiNext(k))
                {
                    if (MoleculeCisTrans::isGeomStereoBond(mol, v.neiEdge(k), 0, true))
                    {
                        ignore_cistrans[v.neiEdge(k)] = 1;
                        sensible_bond_directions[i] = 1;
                        break;
                    }
                }
            }
        }

    mol.buildFromBondsStereocenters(stereochemistry_options, sensible_bond_directions.data());
    mol.buildFromBondsAlleneStereo(stereochemistry_options.ignore_errors, sensible_bond_directions.data());

    if (!mol.getChiralFlag())
        for (int i : mol.vertices())
        {
            int type = mol.stereocenters.getType(i);
            if (type == MoleculeStereocenters::ATOM_ABS)
                mol.stereocenters.setType(i, MoleculeStereocenters::ATOM_AND, 1);
        }

    mol.buildCisTrans(ignore_cistrans.data());
    mol.have_xyz = true;
    if (mol.stereocenters.size() == 0)
    {
        mol.buildFrom3dCoordinatesStereocenters(stereochemistry_options);
    }

    for (const auto& sc : _stereo_centers)
    {
        if (mol.stereocenters.getType(sc._atom_idx) == 0)
        {
            if (stereochemistry_options.ignore_errors)
                mol.addStereocentersIgnoreBad(sc._atom_idx, sc._type, sc._group, false); // add non-valid stereocenters
            else if (!_pqmol)
                throw Error("stereo type specified for atom #%d, but the bond "
                            "directions does not say that it is a stereocenter",
                            sc._atom_idx);
        }
        else
            mol.stereocenters.setType(sc._atom_idx, sc._type, sc._group);
    }

    for (int i : mol.edges())
    {
        if (mol.getBondDirection(i) > 0 && !sensible_bond_directions[i])
        {
            if (!stereochemistry_options.ignore_errors && !_pqmol)
                throw Error("direction of bond #%d makes no sense", i);
        }
    }

    // handle monomer's connections after all
    for (rapidjson::SizeType i = 0; i < _connection_array.Size(); ++i)
    {
        auto& connection = _connection_array[i];
        int order = _BOND_ANY;
        if (connection.HasMember("connectionType"))
        {
            std::string conn_type = connection["connectionType"].GetString();
            if (conn_type == "single")
                order = BOND_SINGLE;
            else if (conn_type == "hydrogen")
                order = _BOND_HYDROGEN;
        }
        auto& ep1 = connection["endpoint1"];
        auto& ep2 = connection["endpoint2"];

        int id1 = -1;
        int id2 = -1;
        std::string atp1, atp2;

        if (ep1.HasMember("monomerId"))
        {
            id1 = monomer_id_mapping.at(extract_id(ep1["monomerId"].GetString(), "monomer"));
            if (order == BOND_SINGLE)
                atp1 = convertAPFromHELM(ep1["attachmentPointId"].GetString());
        }
        else if (ep1.HasMember("moleculeId") && ep1.HasMember("atomId"))
        {
            int mol_id = extract_id(ep1["moleculeId"].GetString(), "mol");
            id1 = mol_mappings[mol_id][atoi(ep1["atomId"].GetString())];
        }
        else
            throw Error("Invalid endpoint");

        if (ep2.HasMember("monomerId"))
        {
            id2 = monomer_id_mapping.at(extract_id(ep2["monomerId"].GetString(), "monomer"));
            if (order == BOND_SINGLE)
                atp2 = convertAPFromHELM(ep2["attachmentPointId"].GetString());
        }
        else if (ep2.HasMember("moleculeId") && ep2.HasMember("atomId"))
        {
            int mol_id = extract_id(ep2["moleculeId"].GetString(), "mol");
            id2 = mol_mappings[mol_id][atoi(ep2["atomId"].GetString())];
        }
        else
            throw Error("Invalid endpoint");

        if (atp1.size())
            mol.setTemplateAtomAttachmentOrder(id1, id2, atp1.c_str());

        if (atp2.size())
            mol.setTemplateAtomAttachmentOrder(id2, id1, atp2.c_str());

        mol.addBond_Silent(id1, id2, order);
    }

    MoleculeLayout ml(mol, false);
    ml.layout_orientation = UNCPECIFIED;
    ml.updateSGroups();
    loadMetaObjects(_meta_objects, mol.meta());
    int arrows_count = mol.meta().getMetaCount(ReactionArrowObject::CID) + mol.meta().getMetaCount(ReactionMultitailArrowObject::CID);
    if (arrows_count && !load_arrows)
        throw Error("Not a molecule. Found %d arrows.", arrows_count);
}