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