void MolfileLoader::_postLoad()

in core/indigo-core/molecule/src/molfile_loader.cpp [1894:2168]


void MolfileLoader::_postLoad()
{
    for (int i = _bmol->vertexBegin(); i < _bmol->vertexEnd(); i = _bmol->vertexNext(i))
    {
        // Update attachment orders for rgroup bonds if they were not specified explicitly
        if (!_bmol->isRSite(i))
            continue;

        const Vertex& vertex = _bmol->getVertex(i);

        if (vertex.degree() == 1 && _bmol->getRSiteAttachmentPointByOrder(i, 0) == -1)
            _bmol->setRSiteAttachmentOrder(i, vertex.neiVertex(vertex.neiBegin()), 0);
        else if (vertex.degree() == 2 && (_bmol->getRSiteAttachmentPointByOrder(i, 0) == -1 || _bmol->getRSiteAttachmentPointByOrder(i, 1) == -1))
        {
            int nei_idx_1 = vertex.neiVertex(vertex.neiBegin());
            int nei_idx_2 = vertex.neiVertex(vertex.neiNext(vertex.neiBegin()));

            _bmol->setRSiteAttachmentOrder(i, std::min(nei_idx_1, nei_idx_2), 0);
            _bmol->setRSiteAttachmentOrder(i, std::max(nei_idx_1, nei_idx_2), 1);
        }
        else if (vertex.degree() > 2)
        {
            int j;

            for (j = 0; j < vertex.degree(); j++)
                if (_bmol->getRSiteAttachmentPointByOrder(i, j) == -1)
                {
                    QS_DEF(Array<int>, nei_indices);
                    nei_indices.clear();

                    for (int nei_idx = vertex.neiBegin(); nei_idx < vertex.neiEnd(); nei_idx = vertex.neiNext(nei_idx))
                        nei_indices.push(vertex.neiVertex(nei_idx));

                    nei_indices.qsort(_asc_cmp_cb, 0);

                    for (int order = 0; order < vertex.degree(); order++)
                        _bmol->setRSiteAttachmentOrder(i, nei_indices[order], order);
                    break;
                }
        }
    }

    if (_mol != 0)
    {
        for (int k = 0; k < _atoms_num; k++)
            if (_hcount[k] > 0)
                _mol->setImplicitH(k, _hcount[k] - 1);
    }

    for (int i = _bmol->sgroups.begin(); i != _bmol->sgroups.end(); i = _bmol->sgroups.next(i))
    {
        SGroup& sgroup = _bmol->sgroups.getSGroup(i);
        if (sgroup.sgroup_type == SGroup::SG_TYPE_DAT)
        {
            DataSGroup& dsg = static_cast<DataSGroup&>(sgroup);
            if (dsg.parent_idx > -1 && std::string(dsg.name.ptr()) == "SMMX:class")
            {
                SGroup& parent_sgroup = _bmol->sgroups.getSGroup(dsg.parent_idx);
                if (parent_sgroup.sgroup_type == SGroup::SG_TYPE_SUP)
                {
                    auto& sa = static_cast<Superatom&>(parent_sgroup);
                    if (sa.sa_natreplace.size() == 0)
                        sa.sa_natreplace.copy(dsg.sa_natreplace);
                    if (sa.sa_class.size() == 0)
                        sa.sa_class.copy(dsg.data);
                }
            }

            if (dsg.isMrv_implicit())
            {
                BufferScanner scanner(dsg.data);
                scanner.skip(DataSGroup::impl_prefix_len); // IMPL_H
                int hcount = scanner.readInt1();
                int k = dsg.atoms[0];

                if ((_mol != 0) && (_hcount[k] == 0))
                    _mol->setImplicitH(k, hcount);
                else if (_hcount[k] == 0)
                {
                    _hcount[k] = hcount + 1;
                }
                _bmol->sgroups.remove(i);
            }
        }
    }

    if (_qmol != 0)
    {
        for (int i = _qmol->edgeBegin(); i < _qmol->edgeEnd(); i = _qmol->edgeNext(i))
        {
            if (_ignore_cistrans[i])
                continue;

            const Edge& edge = _qmol->getEdge(i);

            if ((_stereo_care_atoms[edge.beg] && _stereo_care_atoms[edge.end]) || _stereo_care_bonds[i])
            {
                // in fragments such as C-C=C-C=C-C, the middle single bond
                // has both ends 'stereo care', but should not be considered
                // as 'stereo care' itself
                if (MoleculeCisTrans::isGeomStereoBond(*_bmol, i, 0, true))
                    _qmol->setBondStereoCare(i, true);
            }
        }

        for (int k = 0; k < _atoms_num; k++)
        {
            int expl_h = 0;

            if (_hcount[k] >= 0)
            {
                // count explicit hydrogens
                const Vertex& vertex = _bmol->getVertex(k);
                for (int j = vertex.neiBegin(); j != vertex.neiEnd(); j = vertex.neiNext(j))
                {
                    if (_bmol->getAtomNumber(vertex.neiVertex(j)) == ELEM_H)
                        expl_h++;
                }
            }

            if (_hcount[k] == 1)
            {
                // no hydrogens unless explicitly drawn
                _qmol->resetAtom(k, QueryMolecule::Atom::und(_qmol->releaseAtom(k), new QueryMolecule::Atom(QueryMolecule::ATOM_TOTAL_H, expl_h)));
            }
            else if (_hcount[k] > 1)
            {
                // (_hcount[k] - 1) or more atoms in addition to explicitly drawn
                // no hydrogens unless explicitly drawn
                _qmol->resetAtom(
                    k, QueryMolecule::Atom::und(_qmol->releaseAtom(k), new QueryMolecule::Atom(QueryMolecule::ATOM_TOTAL_H, expl_h + _hcount[k] - 1, 100)));
            }
        }
    }

    // Some "either" bonds may mean not "either stereocenter", but
    // "either cis-trans", or "connected to either cis-trans".

    for (int i = 0; i < _bonds_num; i++)
        if (_bmol->getBondDirection(i) == BOND_EITHER)
        {
            if (MoleculeCisTrans::isGeomStereoBond(*_bmol, i, 0, true))
            {
                _ignore_cistrans[i] = 1;
                _sensible_bond_directions[i] = 1;
            }
            else
            {
                int k;
                const Vertex& v = _bmol->getVertex(_bmol->getEdge(i).beg);

                for (k = v.neiBegin(); k != v.neiEnd(); k = v.neiNext(k))
                {
                    if (MoleculeCisTrans::isGeomStereoBond(*_bmol, v.neiEdge(k), 0, true))
                    {
                        _ignore_cistrans[v.neiEdge(k)] = 1;
                        _sensible_bond_directions[i] = 1;
                        break;
                    }
                }
            }
        }

    _bmol->buildFromBondsStereocenters(stereochemistry_options, _sensible_bond_directions.ptr());
    _bmol->buildFromBondsAlleneStereo(stereochemistry_options.ignore_errors, _sensible_bond_directions.ptr());

    if (!_chiral && treat_stereo_as == 0)
        for (int i = 0; i < _atoms_num; i++)
        {
            int type = _bmol->stereocenters.getType(i);

            if (type == MoleculeStereocenters::ATOM_ABS)
                _bmol->stereocenters.setType(i, MoleculeStereocenters::ATOM_AND, 1);
        }

    if (treat_stereo_as != 0)
        for (int i = 0; i < _atoms_num; i++)
        {
            int type = _bmol->stereocenters.getType(i);

            if (type == MoleculeStereocenters::ATOM_ABS)
                _bmol->stereocenters.setType(i, treat_stereo_as, 1);
        }

    for (int i = 0; i < _atoms_num; i++)
        if (_stereocenter_types[i] > 0)
        {
            if (_bmol->stereocenters.getType(i) == 0)
            {
                if (!stereochemistry_options.ignore_errors)
                    throw Error("stereo type specified for atom #%d, but the bond "
                                "directions does not say that it is a stereocenter",
                                i);
            }
            else
                _bmol->stereocenters.setType(i, _stereocenter_types[i], _stereocenter_groups[i]);
        }

    _bmol->buildCisTrans(_ignore_cistrans.ptr());

    for (int i = 0; i < _bonds_num; i++)
    {
        if (_bmol->getBondDirection(i) && !_sensible_bond_directions[i])
        {
            if (!stereochemistry_options.ignore_errors && !_qmol) // Don't check for query molecule
                throw Error("direction of bond #%d makes no sense", i);
        }
    }

    // Remove adding default R-group logic behavior
    /*
       int n_rgroups = _bmol->rgroups.getRGroupCount();
       for (i = 1; i <= n_rgroups; i++)
          if (_bmol->rgroups.getRGroup(i).occurrence.size() == 0 &&
              _bmol->rgroups.getRGroup(i).fragments.size() > 0)
             _bmol->rgroups.getRGroup(i).occurrence.push((1 << 16) | 0xFFFF);
    */
    _bmol->have_xyz = true;
    MoleculeCIPCalculator cip;
    cip.convertSGroupsToCIP(*_bmol);

    // collect unique nucleotide templates

    std::unordered_map<std::string, int> nucleo_templates;
    for (int tg_idx = _bmol->tgroups.begin(); tg_idx != _bmol->tgroups.end(); tg_idx = _bmol->tgroups.next(tg_idx))
    {
        auto& tg = _bmol->tgroups.getTGroup(tg_idx);
        if (isNucleotideClass(tg.tgroup_class.ptr()))
            nucleo_templates.emplace(tg.tgroup_name.ptr(), tg_idx);
    }

    if (_bmol->tgroups.getTGroupCount() && _bmol->sgroups.getSGroupCount())
        _bmol->transformSuperatomsToTemplates(_max_template_id);

    std::set<int> templates_to_remove;
    std::unordered_map<MonomerKey, int, pair_hash> new_templates;
    if (!_bmol->isQueryMolecule())
    {
        for (int atom_idx = _bmol->vertexBegin(); atom_idx != _bmol->vertexEnd(); atom_idx = _bmol->vertexNext(atom_idx))
        {
            if (_bmol->isTemplateAtom(atom_idx) && isNucleotideClass(_bmol->getTemplateAtomClass(atom_idx)))
            {
                int tg_idx = _bmol->getTemplateAtomTemplateIndex(atom_idx);
                if (tg_idx == -1)
                {
                    auto atom_name = _bmol->getTemplateAtom(atom_idx);
                    auto nt_it = nucleo_templates.find(atom_name);
                    if (nt_it != nucleo_templates.end())
                    {
                        if (_expandNucleotide(atom_idx, nt_it->second, new_templates))
                            templates_to_remove.insert(nt_it->second);
                    }
                    else
                    {
                        // TODO: handle missing template case
                    }
                }
                else // tg_idx != -1 means the template is converted from S-Group
                {
                    // TODO: handle modified monomer. Currently it leaves as is.
                }
            }
        }
    }

    for (auto idx : templates_to_remove)
        _bmol->tgroups.remove(idx);

    // fix layout
    // if (templates_to_remove.size() && _bmol->countComponents())
    //{
    //    SequenceLayout sl(*_bmol);
    //    sl.make();
    //}
}