in core/indigo-core/molecule/src/molecule_json_loader.cpp [265:679]
void MoleculeJsonLoader::parseAtoms(const rapidjson::Value& atoms, BaseMolecule& mol, std::vector<EnhancedStereoCenter>& stereo_centers)
{
mol.reaction_atom_mapping.clear_resize(atoms.Size());
mol.reaction_atom_mapping.zerofill();
mol.reaction_atom_inversion.clear_resize(atoms.Size());
mol.reaction_atom_inversion.zerofill();
mol.reaction_atom_exact_change.clear_resize(atoms.Size());
mol.reaction_atom_exact_change.zerofill();
std::vector<int> hcounts;
hcounts.resize(atoms.Size(), 0);
for (SizeType i = 0; i < atoms.Size(); i++)
{
std::string label;
int atom_idx = 0, charge = 0, valence = 0, radical = 0, isotope = 0, elem = 0, rsite_idx = 0;
bool is_not_list = false;
std::unique_ptr<QueryMolecule::Atom> atomlist;
const Value& a = atoms[i];
if (a.HasMember("isotope"))
isotope = a["isotope"].GetInt();
if (a.HasMember("attachmentPoints"))
{
int val = a["attachmentPoints"].GetInt();
for (int att_idx = 0; (1 << att_idx) <= val; att_idx++)
if (val & (1 << att_idx))
mol.addAttachmentPoint(att_idx + 1, i);
}
if (a.HasMember("type"))
{
std::string atom_type = a["type"].GetString();
if (atom_type == "rg-label" && a.HasMember("$refs") && a["$refs"].Size())
{
std::string ref = a["$refs"][0].GetString();
if (ref.find("rg-") == 0 && ref.erase(0, 3).size())
{
rsite_idx = std::stoi(ref);
elem = ELEM_RSITE;
label = "R";
if (a.HasMember("attachmentOrder"))
{
const auto& rattachments = a["attachmentOrder"];
for (SizeType j = 0; j < rattachments.Size(); ++j)
{
const auto& rattachment = rattachments[j];
if (rattachment.HasMember("attachmentAtom"))
{
auto attindex = rattachment["attachmentAtom"].GetInt();
int attid = -1;
if (rattachment.HasMember("attachmentId"))
{
attid = rattachment["attachmentId"].GetInt();
}
mol.setRSiteAttachmentOrder(i, attindex, attid);
}
}
}
}
else
throw Error("invalid refs: %s", ref.c_str());
}
else if (atom_type == "atom-list")
{
if (!_pqmol)
throw Error("atom-list is allowed only for queries");
is_not_list = a.HasMember("notList") ? a["notList"].GetBool() : false;
const Value& elements = a["elements"];
int pseudo_count = 0;
elem = ELEM_ATOMLIST;
for (rapidjson::SizeType j = 0; j < elements.Size(); ++j)
{
auto elem_label = elements[j].GetString();
int list_elem = Element::fromString2(elem_label);
std::unique_ptr<QueryMolecule::Atom> cur_atom;
if (list_elem != -1)
{
cur_atom = std::make_unique<QueryMolecule::Atom>(QueryMolecule::ATOM_NUMBER, list_elem);
}
else
{
pseudo_count++;
if (pseudo_count > 1)
throw Error("%s inside atom list, if present, must be single", elem_label);
cur_atom = std::make_unique<QueryMolecule::Atom>(QueryMolecule::ATOM_PSEUDO, elem_label);
}
if (atomlist.get() == 0)
atomlist.reset(cur_atom.release());
else
atomlist.reset(QueryMolecule::Atom::oder(atomlist.release(), cur_atom.release()));
}
if (is_not_list)
atomlist.reset(QueryMolecule::Atom::nicht(atomlist.release()));
}
else
throw Error("invalid atom type: %s", atom_type.c_str());
}
else
{
label = a["label"].GetString();
if (label == "D")
{
elem = ELEM_H;
isotope = DEUTERIUM;
}
else if (label == "T")
{
elem = ELEM_H;
isotope = TRITIUM;
}
else
{
elem = Element::fromString2(label.c_str());
if (elem == -1)
{
if (!_pqmol && QueryMolecule::getAtomType(label.c_str()) != _ATOM_PSEUDO)
throw Error("'%s' label is allowed only for queries", label.c_str());
elem = ELEM_PSEUDO;
if (isotope != 0)
{
throw Error("isotope number not allowed on pseudo-atoms");
}
}
}
}
if (a.HasMember("charge"))
charge = a["charge"].GetInt();
if (a.HasMember("explicitValence"))
valence = a["explicitValence"].GetInt();
if (a.HasMember("radical"))
radical = a["radical"].GetInt();
if (_pmol)
{
atom_idx = _pmol->addAtom(elem);
_pmol->setAtomCharge_Silent(atom_idx, charge);
_pmol->setAtomRadical(atom_idx, radical);
_pmol->setAtomIsotope(atom_idx, isotope);
if (valence > 0 && valence <= 14)
_pmol->setExplicitValence(atom_idx, valence);
if (valence == 15)
_pmol->setExplicitValence(atom_idx, 0);
if (elem == ELEM_PSEUDO)
{
_pmol->setPseudoAtom(atom_idx, label.c_str());
}
}
else
{
atom_idx = addAtomToMoleculeQuery(label.c_str(), elem, charge, valence, radical, isotope);
if (atomlist.get())
_pqmol->resetAtom(atom_idx, QueryMolecule::Atom::und(_pqmol->releaseAtom(atom_idx), atomlist.release()));
}
if (a.HasMember("selected") && a["selected"].GetBool())
{
if (_pmol)
_pmol->selectAtom(atom_idx);
else
_pqmol->selectAtom(atom_idx);
}
if (a.HasMember("ringBondCount"))
{
if (_pqmol)
{
int rbcount = a["ringBondCount"].GetInt();
if (rbcount == -1) // no ring bonds
_pqmol->resetAtom(atom_idx,
QueryMolecule::Atom::und(_pqmol->releaseAtom(atom_idx), new QueryMolecule::Atom(QueryMolecule::ATOM_RING_BONDS, 0)));
else if (rbcount == -2) // as drawn
{
int k, rbonds = 0;
const Vertex& vertex = _pqmol->getVertex(atom_idx);
for (k = vertex.neiBegin(); k != vertex.neiEnd(); k = vertex.neiNext(k))
if (_pqmol->getEdgeTopology(vertex.neiEdge(k)) == TOPOLOGY_RING)
rbonds++;
_pqmol->resetAtom(atom_idx, QueryMolecule::Atom::und(_pqmol->releaseAtom(atom_idx),
new QueryMolecule::Atom(QueryMolecule::ATOM_RING_BONDS_AS_DRAWN, rbonds)));
}
else if (rbcount > 1)
_pqmol->resetAtom(atom_idx, QueryMolecule::Atom::und(_pqmol->releaseAtom(atom_idx),
new QueryMolecule::Atom(QueryMolecule::ATOM_RING_BONDS, rbcount, rbcount)));
else
throw Error("ring bond count = %d makes no sense", rbcount);
}
else if (!ignore_noncritical_query_features)
throw Error("ring bond count is allowed only for queries");
}
if (a.HasMember("substitutionCount"))
{
if (!_pqmol)
throw Error("substitution counts are allowed only for queries");
int sub_count = a["substitutionCount"].GetInt();
if (sub_count == -1) // no substitution
_pqmol->resetAtom(atom_idx,
QueryMolecule::Atom::und(_pqmol->releaseAtom(atom_idx), new QueryMolecule::Atom(QueryMolecule::ATOM_SUBSTITUENTS, 0)));
else if (sub_count == -2)
{
_pqmol->resetAtom(atom_idx,
QueryMolecule::Atom::und(_pqmol->releaseAtom(atom_idx), new QueryMolecule::Atom(QueryMolecule::ATOM_SUBSTITUENTS_AS_DRAWN,
_pqmol->getVertex(atom_idx).degree())));
}
else if (sub_count > 0)
_pqmol->resetAtom(atom_idx,
QueryMolecule::Atom::und(_pqmol->releaseAtom(atom_idx), new QueryMolecule::Atom(QueryMolecule::ATOM_SUBSTITUENTS, sub_count,
(sub_count < 6 ? sub_count : 100))));
else
throw Error("invalid SUB value: %d", sub_count);
}
if (a.HasMember("hCount"))
{
if (!_pqmol)
{
if (!ignore_noncritical_query_features)
throw Error("H count is allowed only for queries");
}
hcounts[atom_idx] = a["hCount"].GetInt();
}
if (a.HasMember("implicitHCount"))
{
if (_pmol)
_pmol->setImplicitH(atom_idx, a["implicitHCount"].GetInt());
else
{
int count = a["implicitHCount"].GetInt();
if (count < 0)
throw Error("Wrong value for implicitHCount: %d", count);
_pqmol->resetAtom(atom_idx,
QueryMolecule::Atom::und(_pqmol->releaseAtom(atom_idx), new QueryMolecule::Atom(QueryMolecule::ATOM_IMPLICIT_H, count)));
}
}
if (a.HasMember("invRet"))
{
mol.reaction_atom_inversion[atom_idx] = a["invRet"].GetInt();
}
if (a.HasMember("unsaturatedAtom"))
{
if (_pqmol)
{
if (a["unsaturatedAtom"].GetBool())
_pqmol->resetAtom(atom_idx, QueryMolecule::Atom::und(_pqmol->releaseAtom(i), new QueryMolecule::Atom(QueryMolecule::ATOM_UNSATURATION, 0)));
}
else if (!ignore_noncritical_query_features)
throw Error("unsaturation flag is allowed only for queries");
}
if (a.HasMember("exactChangeFlag"))
{
mol.reaction_atom_exact_change[atom_idx] = a["exactChangeFlag"].GetBool();
}
if (a.HasMember("mapping"))
{
mol.reaction_atom_mapping[atom_idx] = a["mapping"].GetInt();
}
if (rsite_idx)
mol.allowRGroupOnRSite(atom_idx, rsite_idx);
if (a.HasMember("stereoLabel"))
{
std::string sl = a["stereoLabel"].GetString();
if (sl.find("abs") != std::string::npos)
{
stereo_centers.emplace_back(atom_idx, MoleculeStereocenters::ATOM_ABS, 1);
}
else if (sl.find("or") != std::string::npos)
{
int grp = std::stoi(sl.substr(2));
if (grp)
stereo_centers.emplace_back(atom_idx, MoleculeStereocenters::ATOM_OR, grp);
}
else if (sl.find("&") != std::string::npos)
{
int grp = std::stoi(sl.substr(1));
if (grp)
stereo_centers.emplace_back(atom_idx, MoleculeStereocenters::ATOM_AND, grp);
}
}
if (a.HasMember("location"))
{
const Value& coords = a["location"];
if (coords.Size() > 0)
{
Vec3f a_pos;
a_pos.x = coords[0].GetFloat();
a_pos.y = coords[1].GetFloat();
a_pos.z = coords[2].GetFloat();
mol.setAtomXyz(atom_idx, a_pos);
}
}
if (a.HasMember("alias"))
{
mol.setAlias(atom_idx, a["alias"].GetString());
}
if (a.HasMember("cip"))
{
std::string cip_str = a["cip"].GetString();
auto cip = stringToCIP(cip_str);
if (cip != CIPDesc::NONE)
mol.setAtomCIP(atom_idx, cip);
}
if (a.HasMember("queryProperties"))
{
if (_pqmol)
{
auto qProps = a["queryProperties"].GetObject();
if (qProps.HasMember("customQuery"))
{
std::string customQuery = qProps["customQuery"].GetString();
std::unique_ptr<QueryMolecule::Atom> atom = make_unique<QueryMolecule::Atom>();
SmilesLoader::readSmartsAtomStr(customQuery, atom);
_pqmol->resetAtom(atom_idx, atom.release());
}
else
{
if (qProps.HasMember("aromaticity"))
{
std::string arom = qProps["aromaticity"].GetString();
int aromatic;
if (arom == ATOM_AROMATIC_STR)
aromatic = ATOM_AROMATIC;
else if (arom == ATOM_ALIPHATIC_STR)
aromatic = ATOM_ALIPHATIC;
else
throw Error("Wrong value for aromaticity.");
_pqmol->resetAtom(atom_idx, QueryMolecule::Atom::und(_pqmol->releaseAtom(atom_idx),
new QueryMolecule::Atom(QueryMolecule::ATOM_AROMATICITY, aromatic)));
}
if (qProps.HasMember("ringMembership"))
{
int rmem = qProps["ringMembership"].GetInt();
_pqmol->resetAtom(
atom_idx, QueryMolecule::Atom::und(_pqmol->releaseAtom(atom_idx), new QueryMolecule::Atom(QueryMolecule::ATOM_SSSR_RINGS, rmem)));
}
if (qProps.HasMember("ringSize"))
{
int rsize = qProps["ringSize"].GetInt();
_pqmol->resetAtom(atom_idx, QueryMolecule::Atom::und(_pqmol->releaseAtom(atom_idx),
new QueryMolecule::Atom(QueryMolecule::ATOM_SMALLEST_RING_SIZE, rsize)));
}
if (qProps.HasMember("connectivity"))
{
int conn = qProps["connectivity"].GetInt();
_pqmol->resetAtom(
atom_idx, QueryMolecule::Atom::und(_pqmol->releaseAtom(atom_idx), new QueryMolecule::Atom(QueryMolecule::ATOM_CONNECTIVITY, conn)));
}
if (qProps.HasMember("chirality"))
{
std::string chirality_value = qProps["chirality"].GetString();
int chirality;
if (chirality_value == "clockwise")
chirality = QueryMolecule::CHIRALITY_CLOCKWISE;
else if (chirality_value == "anticlockwise")
chirality = QueryMolecule::CHIRALITY_ANTICLOCKWISE;
else
throw Error("Wrong value for chirality.");
_pqmol->resetAtom(atom_idx, QueryMolecule::Atom::und(
_pqmol->releaseAtom(atom_idx),
new QueryMolecule::Atom(QueryMolecule::ATOM_CHIRALITY, QueryMolecule::CHIRALITY_GENERAL, chirality)));
}
}
}
else
throw Error("queryProperties is allowed only for queries");
}
}
if (_pqmol)
for (int k = 0; k < static_cast<int>(hcounts.size()); k++)
{
int expl_h = 0;
if (hcounts[k] >= 0)
{
// count explicit hydrogens
const Vertex& vertex = mol.getVertex(k);
int i;
for (i = vertex.neiBegin(); i != vertex.neiEnd(); i = vertex.neiNext(i))
{
if (mol.getAtomNumber(vertex.neiVertex(i)) == ELEM_H)
expl_h++;
}
}
if (hcounts[k] == 1)
{
// no hydrogens unless explicitly drawn
_pqmol->resetAtom(k, QueryMolecule::Atom::und(_pqmol->releaseAtom(k), new QueryMolecule::Atom(QueryMolecule::ATOM_TOTAL_H, expl_h)));
}
else if (hcounts[k] > 1)
{
// no hydrogens unless explicitly drawn
_pqmol->resetAtom(
k, QueryMolecule::Atom::und(_pqmol->releaseAtom(k), new QueryMolecule::Atom(QueryMolecule::ATOM_TOTAL_H, expl_h + hcounts[k] - 1, 100)));
}
}
}