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();
//}
}