Commit 851a43ba by Maarten L. Hekkelman

Alternative layering of compound factory object implementations

parent 47ae50f7
...@@ -1404,6 +1404,7 @@ class iterator_proxy ...@@ -1404,6 +1404,7 @@ class iterator_proxy
using row_iterator = iterator_impl<RowType>; using row_iterator = iterator_impl<RowType>;
iterator_proxy(Category& cat, row_iterator pos, char const* const columns[N]); iterator_proxy(Category& cat, row_iterator pos, char const* const columns[N]);
iterator_proxy(Category& cat, row_iterator pos, std::initializer_list<char const*> columns);
iterator_proxy(iterator_proxy&& p); iterator_proxy(iterator_proxy&& p);
iterator_proxy& operator=(iterator_proxy&& p); iterator_proxy& operator=(iterator_proxy&& p);
...@@ -1767,6 +1768,13 @@ class Category ...@@ -1767,6 +1768,13 @@ class Category
return iterator_proxy<Row, Ts...>(*this, begin(), columns ); return iterator_proxy<Row, Ts...>(*this, begin(), columns );
} }
template<typename... Ts, typename... Ns>
iterator_proxy<Row, Ts...> rows(Ns... names)
{
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
return iterator_proxy<Row, Ts...>(*this, begin(), { names... });
}
conditional_iterator_proxy<Row> find(Condition&& cond) conditional_iterator_proxy<Row> find(Condition&& cond)
{ {
return find(cbegin(), std::forward<Condition>(cond)); return find(cbegin(), std::forward<Condition>(cond));
...@@ -2126,6 +2134,19 @@ iterator_proxy<RowType, Ts...>::iterator_proxy(Category& cat, row_iterator pos, ...@@ -2126,6 +2134,19 @@ iterator_proxy<RowType, Ts...>::iterator_proxy(Category& cat, row_iterator pos,
mCix[i] = mCat->getColumnIndex(columns[i]); mCix[i] = mCat->getColumnIndex(columns[i]);
} }
template<typename RowType, typename... Ts>
iterator_proxy<RowType, Ts...>::iterator_proxy(Category& cat, row_iterator pos, std::initializer_list<char const*> columns)
: mCat(&cat)
, mCBegin(pos)
, mCEnd(cat.end())
{
// static_assert(columns.size() == N, "The list of column names should be exactly the same as the list of requested columns");
std::size_t i = 0;
for (auto column: columns)
mCix[i++] = mCat->getColumnIndex(column);
}
// -------------------------------------------------------------------- // --------------------------------------------------------------------
template<typename RowType, typename... Ts> template<typename RowType, typename... Ts>
......
...@@ -97,11 +97,6 @@ struct CompoundBond ...@@ -97,11 +97,6 @@ struct CompoundBond
class Compound class Compound
{ {
public: public:
/// \brief factory method, create a Compound based on the three letter code
/// (for amino acids) or the one-letter code (for bases) or the
/// code as it is known in the CCD.
static const Compound *create(const std::string &id);
// accessors // accessors
...@@ -131,6 +126,7 @@ class Compound ...@@ -131,6 +126,7 @@ class Compound
friend class CompoundFactoryImpl; friend class CompoundFactoryImpl;
friend class CCDCompoundFactoryImpl; friend class CCDCompoundFactoryImpl;
friend class CCP4CompoundFactoryImpl;
Compound(cif::Datablock &db); Compound(cif::Datablock &db);
Compound(cif::Datablock &db, const std::string &id, const std::string &name, const std::string &type); Compound(cif::Datablock &db, const std::string &id, const std::string &name, const std::string &type);
...@@ -153,6 +149,14 @@ extern const std::map<std::string, char> kAAMap, kBaseMap; ...@@ -153,6 +149,14 @@ extern const std::map<std::string, char> kAAMap, kBaseMap;
class CompoundFactory class CompoundFactory
{ {
public: public:
/// \brief Initialise a singleton instance.
///
/// If you have a multithreaded application and want to have different
/// compounds in each thread (e.g. a web service processing user requests
/// with different sets of compounds) you can set the \a useThreadLocalInstanceOnly
/// flag to true.
static void init(bool useThreadLocalInstanceOnly); static void init(bool useThreadLocalInstanceOnly);
static CompoundFactory &instance(); static CompoundFactory &instance();
static void clear(); static void clear();
...@@ -163,7 +167,12 @@ class CompoundFactory ...@@ -163,7 +167,12 @@ class CompoundFactory
bool isKnownPeptide(const std::string &res_name) const; bool isKnownPeptide(const std::string &res_name) const;
bool isKnownBase(const std::string &res_name) const; bool isKnownBase(const std::string &res_name) const;
const Compound *get(std::string id); /// \brief Create the Compound object for \a id
///
/// This will create the Compound instance for \a id if it doesn't exist already.
/// The result is owned by this factory and should not be deleted by the user.
/// \param id The Compound ID, a three letter code usually
/// \result The compound, or nullptr if it could not be created (missing info)
const Compound *create(std::string id); const Compound *create(std::string id);
~CompoundFactory(); ~CompoundFactory();
......
...@@ -328,7 +328,7 @@ bool CompoundBondMap::bonded(const std::string &compoundID, const std::string& a ...@@ -328,7 +328,7 @@ bool CompoundBondMap::bonded(const std::string &compoundID, const std::string& a
} }
// not found in our cache, calculate // not found in our cache, calculate
auto compound = CompoundFactory::instance().create(compoundID); auto compound = mmcif::CompoundFactory::instance().create(compoundID);
if (not compound) if (not compound)
throw BondMapException("Missing compound bond info for " + compoundID); throw BondMapException("Missing compound bond info for " + compoundID);
...@@ -621,7 +621,7 @@ std::vector<std::string> BondMap::atomIDsForCompound(const std::string& compound ...@@ -621,7 +621,7 @@ std::vector<std::string> BondMap::atomIDsForCompound(const std::string& compound
{ {
std::vector<std::string> result; std::vector<std::string> result;
auto* compound = mmcif::Compound::create(compoundID); auto* compound = mmcif::CompoundFactory::instance().create(compoundID);
if (compound == nullptr) if (compound == nullptr)
throw BondMapException("Missing bond information for compound " + compoundID); throw BondMapException("Missing bond information for compound " + compoundID);
......
...@@ -39,10 +39,10 @@ ...@@ -39,10 +39,10 @@
#include <fstream> #include <fstream>
#include "cif++/Cif++.hpp" #include "cif++/Cif++.hpp"
#include "cif++/CifParser.hpp"
#include "cif++/CifUtils.hpp" #include "cif++/CifUtils.hpp"
#include "cif++/Compound.hpp" #include "cif++/Compound.hpp"
#include "cif++/Point.hpp" #include "cif++/Point.hpp"
#include "cif++/CifParser.hpp"
namespace ba = boost::algorithm; namespace ba = boost::algorithm;
namespace fs = std::filesystem; namespace fs = std::filesystem;
...@@ -56,28 +56,36 @@ std::string to_string(BondType bondType) ...@@ -56,28 +56,36 @@ std::string to_string(BondType bondType)
{ {
switch (bondType) switch (bondType)
{ {
case BondType::sing: return "sing"; case BondType::sing: return "sing";
case BondType::doub: return "doub"; case BondType::doub: return "doub";
case BondType::trip: return "trip"; case BondType::trip: return "trip";
case BondType::quad: return "quad"; case BondType::quad: return "quad";
case BondType::arom: return "arom"; case BondType::arom: return "arom";
case BondType::poly: return "poly"; case BondType::poly: return "poly";
case BondType::delo: return "delo"; case BondType::delo: return "delo";
case BondType::pi: return "pi"; case BondType::pi: return "pi";
} }
throw std::invalid_argument("Invalid bondType"); throw std::invalid_argument("Invalid bondType");
} }
BondType from_string(const std::string& bondType) BondType from_string(const std::string &bondType)
{ {
if (cif::iequals(bondType, "sing")) return BondType::sing; if (cif::iequals(bondType, "sing"))
if (cif::iequals(bondType, "doub")) return BondType::doub; return BondType::sing;
if (cif::iequals(bondType, "trip")) return BondType::trip; if (cif::iequals(bondType, "doub"))
if (cif::iequals(bondType, "quad")) return BondType::quad; return BondType::doub;
if (cif::iequals(bondType, "arom")) return BondType::arom; if (cif::iequals(bondType, "trip"))
if (cif::iequals(bondType, "poly")) return BondType::poly; return BondType::trip;
if (cif::iequals(bondType, "delo")) return BondType::delo; if (cif::iequals(bondType, "quad"))
if (cif::iequals(bondType, "pi")) return BondType::pi; return BondType::quad;
if (cif::iequals(bondType, "arom"))
return BondType::arom;
if (cif::iequals(bondType, "poly"))
return BondType::poly;
if (cif::iequals(bondType, "delo"))
return BondType::delo;
if (cif::iequals(bondType, "pi"))
return BondType::pi;
throw std::invalid_argument("Invalid bondType: " + bondType); throw std::invalid_argument("Invalid bondType: " + bondType);
} }
...@@ -122,24 +130,23 @@ Compound::Compound(cif::Datablock &db) ...@@ -122,24 +130,23 @@ Compound::Compound(cif::Datablock &db)
chemComp.front().get("id", "name", "type", "formula", "formula_weight", "pdbx_formal_charge"); chemComp.front().get("id", "name", "type", "formula", "formula_weight", "pdbx_formal_charge");
auto &chemCompAtom = db["chem_comp_atom"]; auto &chemCompAtom = db["chem_comp_atom"];
for (auto row: chemCompAtom) for (auto row : chemCompAtom)
{ {
CompoundAtom atom; CompoundAtom atom;
std::string typeSymbol; std::string typeSymbol;
cif::tie(atom.id, typeSymbol, atom.charge, atom.aromatic, atom.leavingAtom, atom.stereoConfig, atom.x, atom.y, atom.z) = cif::tie(atom.id, typeSymbol, atom.charge, atom.aromatic, atom.leavingAtom, atom.stereoConfig, atom.x, atom.y, atom.z) =
row.get("atom_id", "type_symbol", "charge", "pdbx_aromatic_flag", "pdbx_leaving_atom_flag", "pdbx_stereo_config", row.get("atom_id", "type_symbol", "charge", "pdbx_aromatic_flag", "pdbx_leaving_atom_flag", "pdbx_stereo_config",
"model_Cartn_x", "model_Cartn_y", "model_Cartn_z"); "model_Cartn_x", "model_Cartn_y", "model_Cartn_z");
atom.typeSymbol = AtomTypeTraits(typeSymbol).type(); atom.typeSymbol = AtomTypeTraits(typeSymbol).type();
mAtoms.push_back(std::move(atom)); mAtoms.push_back(std::move(atom));
} }
auto &chemCompBond = db["chem_comp_bond"]; auto &chemCompBond = db["chem_comp_bond"];
for (auto row: chemCompBond) for (auto row : chemCompBond)
{ {
CompoundBond bond; CompoundBond bond;
std::string valueOrder; std::string valueOrder;
cif::tie(bond.atomID[0], bond.atomID[1], valueOrder, bond.aromatic, bond.stereoConfig) cif::tie(bond.atomID[0], bond.atomID[1], valueOrder, bond.aromatic, bond.stereoConfig) = row.get("atom_id_1", "atom_id_2", "value_order", "pdbx_aromatic_flag", "pdbx_stereo_config");
= row.get("atom_id_1", "atom_id_2", "value_order", "pdbx_aromatic_flag", "pdbx_stereo_config");
bond.type = from_string(valueOrder); bond.type = from_string(valueOrder);
mBonds.push_back(std::move(bond)); mBonds.push_back(std::move(bond));
} }
...@@ -151,7 +158,7 @@ Compound::Compound(cif::Datablock &db, const std::string &id, const std::string ...@@ -151,7 +158,7 @@ Compound::Compound(cif::Datablock &db, const std::string &id, const std::string
, mType(type) , mType(type)
{ {
auto &chemCompAtom = db["chem_comp_atom"]; auto &chemCompAtom = db["chem_comp_atom"];
for (auto row: chemCompAtom) for (auto row : chemCompAtom)
{ {
CompoundAtom atom; CompoundAtom atom;
std::string typeSymbol; std::string typeSymbol;
...@@ -166,18 +173,20 @@ Compound::Compound(cif::Datablock &db, const std::string &id, const std::string ...@@ -166,18 +173,20 @@ Compound::Compound(cif::Datablock &db, const std::string &id, const std::string
} }
auto &chemCompBond = db["chem_comp_bond"]; auto &chemCompBond = db["chem_comp_bond"];
for (auto row: chemCompBond) for (auto row : chemCompBond)
{ {
CompoundBond bond; CompoundBond bond;
std::string type; std::string type;
cif::tie(bond.atomID[0], bond.atomID[1], type, bond.aromatic) cif::tie(bond.atomID[0], bond.atomID[1], type, bond.aromatic) = row.get("atom_id_1", "atom_id_2", "type", "aromatic");
= row.get("atom_id_1", "atom_id_2", "type", "aromatic");
using cif::iequals; using cif::iequals;
if (iequals(type, "single")) bond.type = BondType::sing; if (iequals(type, "single"))
else if (iequals(type, "double")) bond.type = BondType::doub; bond.type = BondType::sing;
else if (iequals(type, "triple")) bond.type = BondType::trip; else if (iequals(type, "double"))
bond.type = BondType::doub;
else if (iequals(type, "triple"))
bond.type = BondType::trip;
else if (iequals(type, "deloc") or iequals(type, "aromat") or iequals(type, "aromatic")) else if (iequals(type, "deloc") or iequals(type, "aromat") or iequals(type, "aromatic"))
bond.type = BondType::delo; bond.type = BondType::delo;
else else
...@@ -208,14 +217,6 @@ CompoundAtom Compound::getAtomByID(const std::string &atomID) const ...@@ -208,14 +217,6 @@ CompoundAtom Compound::getAtomByID(const std::string &atomID) const
return result; return result;
} }
const Compound *Compound::create(const std::string &id)
{
auto result = CompoundFactory::instance().get(id);
if (result == nullptr)
result = CompoundFactory::instance().create(id);
return result;
}
bool Compound::atomsBonded(const std::string &atomId_1, const std::string &atomId_2) const bool Compound::atomsBonded(const std::string &atomId_1, const std::string &atomId_2) const
{ {
auto i = find_if(mBonds.begin(), mBonds.end(), auto i = find_if(mBonds.begin(), mBonds.end(),
...@@ -226,83 +227,6 @@ bool Compound::atomsBonded(const std::string &atomId_1, const std::string &atomI ...@@ -226,83 +227,6 @@ bool Compound::atomsBonded(const std::string &atomId_1, const std::string &atomI
return i != mBonds.end(); return i != mBonds.end();
} }
// float Compound::atomBondValue(const std::string &atomId_1, const std::string &atomId_2) const
// {
// auto i = find_if(mBonds.begin(), mBonds.end(),
// [&](const CompoundBond &b) {
// return (b.atomID[0] == atomId_1 and b.atomID[1] == atomId_2) or (b.atomID[0] == atomId_2 and b.atomID[1] == atomId_1);
// });
// return i != mBonds.end() ? i->distance : 0;
// }
// float Compound::bondAngle(const std::string &atomId_1, const std::string &atomId_2, const std::string &atomId_3) const
// {
// float result = nanf("1");
// for (auto &a : mAngles)
// {
// if (not(a.atomID[1] == atomId_2 and
// ((a.atomID[0] == atomId_1 and a.atomID[2] == atomId_3) or
// (a.atomID[2] == atomId_1 and a.atomID[0] == atomId_3))))
// continue;
// result = a.angle;
// break;
// }
// return result;
// }
//static float calcC(float a, float b, float alpha)
//{
// float f = b * sin(alpha * kPI / 180);
// float d = sqrt(b * b - f * f);
// float e = a - d;
// float c = sqrt(f * f + e * e);
//
// return c;
//}
// float Compound::chiralVolume(const std::string &centreID) const
// {
// float result = 0;
// for (auto &cv : mChiralCentres)
// {
// if (cv.id != centreID)
// continue;
// // calculate the expected chiral volume
// // the edges
// float a = atomBondValue(cv.atomIDCentre, cv.atomID[0]);
// float b = atomBondValue(cv.atomIDCentre, cv.atomID[1]);
// float c = atomBondValue(cv.atomIDCentre, cv.atomID[2]);
// // the angles for the top of the tetrahedron
// float alpha = bondAngle(cv.atomID[0], cv.atomIDCentre, cv.atomID[1]);
// float beta = bondAngle(cv.atomID[1], cv.atomIDCentre, cv.atomID[2]);
// float gamma = bondAngle(cv.atomID[2], cv.atomIDCentre, cv.atomID[0]);
// float cosa = cos(alpha * kPI / 180);
// float cosb = cos(beta * kPI / 180);
// float cosc = cos(gamma * kPI / 180);
// result = (a * b * c * sqrt(1 + 2 * cosa * cosb * cosc - (cosa * cosa) - (cosb * cosb) - (cosc * cosc))) / 6;
// if (cv.volumeSign == negativ)
// result = -result;
// break;
// }
// return result;
// }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// a factory class to generate compounds // a factory class to generate compounds
...@@ -346,7 +270,7 @@ const std::map<std::string, char> kBaseMap{ ...@@ -346,7 +270,7 @@ const std::map<std::string, char> kBaseMap{
class CompoundFactoryImpl class CompoundFactoryImpl
{ {
public: public:
CompoundFactoryImpl(); CompoundFactoryImpl(CompoundFactoryImpl *next);
CompoundFactoryImpl(const std::string &file, CompoundFactoryImpl *next); CompoundFactoryImpl(const std::string &file, CompoundFactoryImpl *next);
...@@ -355,8 +279,42 @@ class CompoundFactoryImpl ...@@ -355,8 +279,42 @@ class CompoundFactoryImpl
delete mNext; delete mNext;
} }
Compound *get(std::string id); Compound *get(std::string id)
virtual Compound *create(std::string id); {
std::shared_lock lock(mMutex);
ba::to_upper(id);
Compound *result = nullptr;
// walk the list, see if any of us has the compound already
for (auto impl = this; impl != nullptr; impl = impl->mNext)
{
for (auto cmp : impl->mCompounds)
{
if (cmp->id() == id)
{
result = cmp;
break;
}
}
}
if (result == nullptr and mMissing.count(id) == 0)
{
for (auto impl = this; impl != nullptr; impl = impl->mNext)
{
result = impl->create(id);
if (result != nullptr)
break;
}
if (result == nullptr)
mMissing.insert(id);
}
return result;
}
CompoundFactoryImpl *pop() CompoundFactoryImpl *pop()
{ {
...@@ -379,6 +337,13 @@ class CompoundFactoryImpl ...@@ -379,6 +337,13 @@ class CompoundFactoryImpl
} }
protected: protected:
virtual Compound *create(const std::string &id)
{
// For the base class we assume every compound is preloaded
return nullptr;
}
std::shared_timed_mutex mMutex; std::shared_timed_mutex mMutex;
std::vector<Compound *> mCompounds; std::vector<Compound *> mCompounds;
...@@ -390,7 +355,8 @@ class CompoundFactoryImpl ...@@ -390,7 +355,8 @@ class CompoundFactoryImpl
// -------------------------------------------------------------------- // --------------------------------------------------------------------
CompoundFactoryImpl::CompoundFactoryImpl() CompoundFactoryImpl::CompoundFactoryImpl(CompoundFactoryImpl *next)
: mNext(next)
{ {
for (const auto &[key, value] : kAAMap) for (const auto &[key, value] : kAAMap)
mKnownPeptides.insert(key); mKnownPeptides.insert(key);
...@@ -405,14 +371,14 @@ CompoundFactoryImpl::CompoundFactoryImpl(const std::string &file, CompoundFactor ...@@ -405,14 +371,14 @@ CompoundFactoryImpl::CompoundFactoryImpl(const std::string &file, CompoundFactor
cif::File cifFile(file); cif::File cifFile(file);
auto compList = cifFile.get("comp_list"); auto compList = cifFile.get("comp_list");
if (compList) // So this is a CCP4 restraints file, special handling if (compList) // So this is a CCP4 restraints file, special handling
{ {
auto &chemComp = (*compList)["chem_comp"]; auto &chemComp = (*compList)["chem_comp"];
for (const auto &[id, name, group]: chemComp.rows<std::string,std::string,std::string>({"id", "name", "group"})) for (const auto &[id, name, group] : chemComp.rows<std::string, std::string, std::string>({"id", "name", "group"}))
{ {
std::string type; std::string type;
// known groups are (counted from ccp4 monomer dictionary) // known groups are (counted from ccp4 monomer dictionary)
// D-pyranose // D-pyranose
...@@ -431,7 +397,7 @@ CompoundFactoryImpl::CompoundFactoryImpl(const std::string &file, CompoundFactor ...@@ -431,7 +397,7 @@ CompoundFactoryImpl::CompoundFactoryImpl(const std::string &file, CompoundFactor
// peptide // peptide
// pyranose // pyranose
// saccharide // saccharide
if (cif::iequals(id, "gly")) if (cif::iequals(id, "gly"))
type = "peptide linking"; type = "peptide linking";
else if (cif::iequals(group, "l-peptide") or cif::iequals(group, "L-peptide linking") or cif::iequals(group, "peptide")) else if (cif::iequals(group, "l-peptide") or cif::iequals(group, "L-peptide linking") or cif::iequals(group, "peptide"))
...@@ -442,7 +408,7 @@ CompoundFactoryImpl::CompoundFactoryImpl(const std::string &file, CompoundFactor ...@@ -442,7 +408,7 @@ CompoundFactoryImpl::CompoundFactoryImpl(const std::string &file, CompoundFactor
type = "RNA linking"; type = "RNA linking";
else else
type = "non-polymer"; type = "non-polymer";
auto &db = cifFile["comp_" + id]; auto &db = cifFile["comp_" + id];
mCompounds.push_back(new Compound(db, id, name, type)); mCompounds.push_back(new Compound(db, id, name, type));
...@@ -456,111 +422,30 @@ CompoundFactoryImpl::CompoundFactoryImpl(const std::string &file, CompoundFactor ...@@ -456,111 +422,30 @@ CompoundFactoryImpl::CompoundFactoryImpl(const std::string &file, CompoundFactor
if (not cifFile.isValid()) if (not cifFile.isValid())
throw std::runtime_error("Invalid compound file"); throw std::runtime_error("Invalid compound file");
for (auto &db: cifFile) for (auto &db : cifFile)
mCompounds.push_back(new Compound(db)); mCompounds.push_back(new Compound(db));
} }
} }
Compound *CompoundFactoryImpl::get(std::string id)
{
std::shared_lock lock(mMutex);
ba::to_upper(id);
Compound *result = nullptr;
for (auto cmp : mCompounds)
{
if (cmp->id() == id)
{
result = cmp;
break;
}
}
if (result == nullptr and mNext != nullptr)
result = mNext->get(id);
return result;
}
Compound *CompoundFactoryImpl::create(std::string id)
{
ba::to_upper(id);
Compound *result = get(id);
// if (result == nullptr and mMissing.count(id) == 0 and not mFile.empty())
// {
// std::unique_lock lock(mMutex);
// auto &cat = mFile.firstDatablock()["chem_comp"];
// auto rs = cat.find(cif::Key("three_letter_code") == id);
// if (not rs.empty())
// {
// auto row = rs.front();
// std::string name, group;
// uint32_t numberAtomsAll, numberAtomsNh;
// cif::tie(name, group, numberAtomsAll, numberAtomsNh) =
// row.get("name", "group", "number_atoms_all", "number_atoms_nh");
// ba::trim(name);
// ba::trim(group);
// if (mFile.get("comp_" + id) == nullptr)
// {
// auto clibd_mon = fs::path(getenv("CLIBD_MON"));
// fs::path resFile = clibd_mon / ba::to_lower_copy(id.substr(0, 1)) / (id + ".cif");
// if (not fs::exists(resFile) and (id == "COM" or id == "CON" or "PRN")) // seriously...
// resFile = clibd_mon / ba::to_lower_copy(id.substr(0, 1)) / (id + '_' + id + ".cif");
// if (not fs::exists(resFile))
// mMissing.insert(id);
// else
// {
// mCompounds.push_back(new Compound(resFile.string(), id, name, group));
// result = mCompounds.back();
// }
// }
// else
// {
// mCompounds.push_back(new Compound(mPath, id, name, group));
// result = mCompounds.back();
// }
// }
// if (result == nullptr and mNext != nullptr)
// result = mNext->create(id);
// }
return result;
}
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// Version for the default compounds, based on the cached components.cif file from CCD // Version for the default compounds, based on the cached components.cif file from CCD
class CCDCompoundFactoryImpl : public CompoundFactoryImpl class CCDCompoundFactoryImpl : public CompoundFactoryImpl
{ {
public: public:
CCDCompoundFactoryImpl() {} CCDCompoundFactoryImpl(CompoundFactoryImpl *next)
: CompoundFactoryImpl(next)
{
}
Compound *create(std::string id) override; Compound *create(const std::string &id) override;
cif::DatablockIndex mIndex; cif::DatablockIndex mIndex;
}; };
Compound *CCDCompoundFactoryImpl::create(std::string id) Compound *CCDCompoundFactoryImpl::create(const std::string &id)
{ {
ba::to_upper(id); Compound *result = nullptr;
Compound *result = get(id);
if (result)
return result;
auto ccd = cif::loadResource("components.cif"); auto ccd = cif::loadResource("components.cif");
if (not ccd) if (not ccd)
...@@ -572,7 +457,8 @@ Compound *CCDCompoundFactoryImpl::create(std::string id) ...@@ -572,7 +457,8 @@ Compound *CCDCompoundFactoryImpl::create(std::string id)
{ {
if (cif::VERBOSE > 1) if (cif::VERBOSE > 1)
{ {
std::cout << "Creating component index " << "..."; std::cout << "Creating component index "
<< "...";
std::cout.flush(); std::cout.flush();
} }
...@@ -581,7 +467,7 @@ Compound *CCDCompoundFactoryImpl::create(std::string id) ...@@ -581,7 +467,7 @@ Compound *CCDCompoundFactoryImpl::create(std::string id)
if (cif::VERBOSE > 1) if (cif::VERBOSE > 1)
std::cout << " done" << std::endl; std::cout << " done" << std::endl;
// reload the resource, perhaps this should be improved... // reload the resource, perhaps this should be improved...
ccd = cif::loadResource("components.cif"); ccd = cif::loadResource("components.cif");
} }
...@@ -610,13 +496,115 @@ Compound *CCDCompoundFactoryImpl::create(std::string id) ...@@ -610,13 +496,115 @@ Compound *CCDCompoundFactoryImpl::create(std::string id)
} }
} }
if (result == nullptr and cif::VERBOSE > 1) if (result == nullptr and cif::VERBOSE)
std::cerr << "Could not locate compound " << id << " in the CCD components file" << std::endl; std::cerr << "Could not locate compound " << id << " in the CCD components file" << std::endl;
return result; return result;
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// Version for the default compounds, based on the data found in CCP4's monomers lib
class CCP4CompoundFactoryImpl : public CompoundFactoryImpl
{
public:
CCP4CompoundFactoryImpl(const fs::path &clibd_mon, CompoundFactoryImpl *next = nullptr);
Compound *create(const std::string &id) override;
private:
cif::File mFile;
fs::path mCLIBD_MON;
};
CCP4CompoundFactoryImpl::CCP4CompoundFactoryImpl(const fs::path &clibd_mon, CompoundFactoryImpl *next)
: CompoundFactoryImpl(next)
, mFile(clibd_mon / "list" / "mon_lib_list.cif")
, mCLIBD_MON(clibd_mon)
{
const std::regex peptideRx("(?:[lmp]-)?peptide", std::regex::icase);
auto &chemComps = mFile["comp_list"]["chem_comp"];
for (const auto &[group, threeLetterCode] : chemComps.rows<std::string, std::string>("group", "three_letter_code"))
{
if (std::regex_match(group, peptideRx))
mKnownPeptides.insert(threeLetterCode);
else if (ba::iequals(group, "DNA") or ba::iequals(group, "RNA"))
mKnownBases.insert(threeLetterCode);
}
}
Compound *CCP4CompoundFactoryImpl::create(const std::string &id)
{
Compound *result = nullptr;
auto &cat = mFile["comp_list"]["chem_comp"];
auto rs = cat.find(cif::Key("three_letter_code") == id);
if (rs.size() == 1)
{
auto row = rs.front();
std::string name, group;
uint32_t numberAtomsAll, numberAtomsNh;
cif::tie(name, group, numberAtomsAll, numberAtomsNh) =
row.get("name", "group", "number_atoms_all", "number_atoms_nh");
fs::path resFile = mCLIBD_MON / ba::to_lower_copy(id.substr(0, 1)) / (id + ".cif");
if (not fs::exists(resFile) and (id == "COM" or id == "CON" or "PRN")) // seriously...
resFile = mCLIBD_MON / ba::to_lower_copy(id.substr(0, 1)) / (id + '_' + id + ".cif");
if (fs::exists(resFile))
{
cif::File cf(resFile);
// locate the datablock
auto &db = cf["comp_" + id];
std::string type;
// known groups are (counted from ccp4 monomer dictionary)
// D-pyranose
// DNA
// L-PEPTIDE LINKING
// L-SACCHARIDE
// L-peptide
// L-pyranose
// M-peptide
// NON-POLYMER
// P-peptide
// RNA
// furanose
// non-polymer
// non_polymer
// peptide
// pyranose
// saccharide
if (cif::iequals(id, "gly"))
type = "peptide linking";
else if (cif::iequals(group, "l-peptide") or cif::iequals(group, "L-peptide linking") or cif::iequals(group, "peptide"))
type = "L-peptide linking";
else if (cif::iequals(group, "DNA"))
type = "DNA linking";
else if (cif::iequals(group, "RNA"))
type = "RNA linking";
else
type = "non-polymer";
mCompounds.push_back(new Compound(db, id, name, type));
result = mCompounds.back();
}
}
return result;
}
// --------------------------------------------------------------------
CompoundFactory *CompoundFactory::sInstance; CompoundFactory *CompoundFactory::sInstance;
thread_local std::unique_ptr<CompoundFactory> CompoundFactory::tlInstance; thread_local std::unique_ptr<CompoundFactory> CompoundFactory::tlInstance;
...@@ -628,8 +616,13 @@ void CompoundFactory::init(bool useThreadLocalInstanceOnly) ...@@ -628,8 +616,13 @@ void CompoundFactory::init(bool useThreadLocalInstanceOnly)
} }
CompoundFactory::CompoundFactory() CompoundFactory::CompoundFactory()
: mImpl(new CCDCompoundFactoryImpl) : mImpl(nullptr)
{ {
const char *clibd_mon = getenv("CLIBD_MON");
if (clibd_mon != nullptr and fs::is_directory(clibd_mon))
mImpl = new CCP4CompoundFactoryImpl(clibd_mon);
mImpl = new CCDCompoundFactoryImpl(mImpl);
} }
CompoundFactory::~CompoundFactory() CompoundFactory::~CompoundFactory()
...@@ -690,15 +683,9 @@ void CompoundFactory::popDictionary() ...@@ -690,15 +683,9 @@ void CompoundFactory::popDictionary()
mImpl = mImpl->pop(); mImpl = mImpl->pop();
} }
// id is the three letter code
const Compound *CompoundFactory::get(std::string id)
{
return mImpl->get(id);
}
const Compound *CompoundFactory::create(std::string id) const Compound *CompoundFactory::create(std::string id)
{ {
return mImpl->create(id); return mImpl->get(id);
} }
bool CompoundFactory::isKnownPeptide(const std::string &resName) const bool CompoundFactory::isKnownPeptide(const std::string &resName) const
......
...@@ -2575,7 +2575,7 @@ void PDBFileParser::ParseRemarks() ...@@ -2575,7 +2575,7 @@ void PDBFileParser::ParseRemarks()
int seq = vI(22, 25); int seq = vI(22, 25);
char iCode = vC(26); char iCode = vC(26);
auto compound = mmcif::Compound::create(res); auto compound = mmcif::CompoundFactory::instance().create(res);
if (compound == nullptr) if (compound == nullptr)
continue; continue;
...@@ -4037,7 +4037,7 @@ void PDBFileParser::ConstructEntities() ...@@ -4037,7 +4037,7 @@ void PDBFileParser::ConstructEntities()
letter = '(' + res.mMonID + ')'; letter = '(' + res.mMonID + ')';
// sja... // sja...
auto compound = mmcif::Compound::create(stdRes.empty() ? res.mMonID : stdRes); auto compound = mmcif::CompoundFactory::instance().create(stdRes.empty() ? res.mMonID : stdRes);
if (compound != nullptr and if (compound != nullptr and
not iequals(compound->type(), "L-peptide linking") and not iequals(compound->type(), "L-peptide linking") and
not iequals(compound->type(), "RNA linking")) not iequals(compound->type(), "RNA linking"))
...@@ -4193,7 +4193,7 @@ void PDBFileParser::ConstructEntities() ...@@ -4193,7 +4193,7 @@ void PDBFileParser::ConstructEntities()
{ {
if (mHetnams[hetID].empty()) if (mHetnams[hetID].empty())
{ {
auto compound = mmcif::Compound::create(hetID); auto compound = mmcif::CompoundFactory::instance().create(hetID);
if (compound != nullptr) if (compound != nullptr)
mHetnams[hetID] = compound->name(); mHetnams[hetID] = compound->name();
} }
...@@ -4330,7 +4330,7 @@ void PDBFileParser::ConstructEntities() ...@@ -4330,7 +4330,7 @@ void PDBFileParser::ConstructEntities()
for (auto cc: mChemComp) for (auto cc: mChemComp)
{ {
auto compound = mmcif::Compound::create( auto compound = mmcif::CompoundFactory::instance().create(
mMod2parent.count(cc) ? mMod2parent[cc] : cc mMod2parent.count(cc) ? mMod2parent[cc] : cc
); );
...@@ -4872,7 +4872,7 @@ static bool IsMetal(const std::string& resName, const std::string& atomID) ...@@ -4872,7 +4872,7 @@ static bool IsMetal(const std::string& resName, const std::string& atomID)
try try
{ {
auto compound = mmcif::Compound::create(resName); auto compound = mmcif::CompoundFactory::instance().create(resName);
if (compound != nullptr) if (compound != nullptr)
{ {
auto at = mmcif::AtomTypeTraits(compound->getAtomByID(atomID).typeSymbol); auto at = mmcif::AtomTypeTraits(compound->getAtomByID(atomID).typeSymbol);
......
...@@ -26,23 +26,23 @@ ...@@ -26,23 +26,23 @@
#include "cif++/Structure.hpp" #include "cif++/Structure.hpp"
#include <numeric>
#include <fstream>
#include <filesystem> #include <filesystem>
#include <fstream>
#include <numeric>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/iostreams/filtering_stream.hpp> #include <boost/format.hpp>
#include <boost/iostreams/filter/bzip2.hpp> #include <boost/iostreams/filter/bzip2.hpp>
#include <boost/iostreams/filter/gzip.hpp> #include <boost/iostreams/filter/gzip.hpp>
#include <boost/format.hpp> #include <boost/iostreams/filtering_stream.hpp>
#if __has_include("Config.hpp") #if __has_include("Config.hpp")
#include "Config.hpp" #include "Config.hpp"
#endif #endif
#include "cif++/PDB2Cif.hpp"
#include "cif++/CifParser.hpp"
#include "cif++/Cif2PDB.hpp" #include "cif++/Cif2PDB.hpp"
#include "cif++/CifParser.hpp"
#include "cif++/PDB2Cif.hpp"
// #include "cif++/AtomShape.hpp" // #include "cif++/AtomShape.hpp"
namespace fs = std::filesystem; namespace fs = std::filesystem;
...@@ -53,22 +53,22 @@ extern int cif::VERBOSE; ...@@ -53,22 +53,22 @@ extern int cif::VERBOSE;
namespace mmcif namespace mmcif
{ {
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// FileImpl // FileImpl
struct FileImpl struct FileImpl
{ {
cif::File mData; cif::File mData;
cif::Datablock* mDb = nullptr; cif::Datablock *mDb = nullptr;
void load_data(const char* data, size_t length); void load_data(const char *data, size_t length);
void load(const std::string& p); void load(const std::string &p);
void save(const std::string& p); void save(const std::string &p);
}; };
void FileImpl::load_data(const char* data, size_t length) void FileImpl::load_data(const char *data, size_t length)
{ {
bool gzipped = length > 2 and data[0] == (char)0x1f and data[1] == (char)0x8b; bool gzipped = length > 2 and data[0] == (char)0x1f and data[1] == (char)0x8b;
bool bzip2ed = length > 3 and data[0] == (char)0x42 and data[1] == (char)0x5A and data[2] == (char)0x68; bool bzip2ed = length > 3 and data[0] == (char)0x42 and data[1] == (char)0x5A and data[2] == (char)0x68;
...@@ -76,12 +76,12 @@ void FileImpl::load_data(const char* data, size_t length) ...@@ -76,12 +76,12 @@ void FileImpl::load_data(const char* data, size_t length)
try try
{ {
// First try mmCIF // First try mmCIF
struct membuf : public std::streambuf struct membuf : public std::streambuf
{ {
membuf(char* data, size_t length) { this->setg(data, data, data + length); } membuf(char *data, size_t length) { this->setg(data, data, data + length); }
} buffer(const_cast<char*>(data), length); } buffer(const_cast<char *>(data), length);
std::istream is(&buffer); std::istream is(&buffer);
io::filtering_stream<io::input> in; io::filtering_stream<io::input> in;
if (gzipped) if (gzipped)
...@@ -92,15 +92,15 @@ void FileImpl::load_data(const char* data, size_t length) ...@@ -92,15 +92,15 @@ void FileImpl::load_data(const char* data, size_t length)
mData.load(in); mData.load(in);
} }
catch (const cif::CifParserError& e) catch (const cif::CifParserError &e)
{ {
// First try mmCIF // First try mmCIF
struct membuf : public std::streambuf struct membuf : public std::streambuf
{ {
membuf(char* data, size_t length) { this->setg(data, data, data + length); } membuf(char *data, size_t length) { this->setg(data, data, data + length); }
} buffer(const_cast<char*>(data), length); } buffer(const_cast<char *>(data), length);
std::istream is(&buffer); std::istream is(&buffer);
io::filtering_stream<io::input> in; io::filtering_stream<io::input> in;
if (gzipped) if (gzipped)
...@@ -111,28 +111,28 @@ void FileImpl::load_data(const char* data, size_t length) ...@@ -111,28 +111,28 @@ void FileImpl::load_data(const char* data, size_t length)
ReadPDBFile(in, mData); ReadPDBFile(in, mData);
} }
// Yes, we've parsed the data. Now locate the datablock. // Yes, we've parsed the data. Now locate the datablock.
mDb = &mData.firstDatablock(); mDb = &mData.firstDatablock();
// And validate, otherwise lots of functionality won't work // And validate, otherwise lots of functionality won't work
// if (mData.getValidator() == nullptr) // if (mData.getValidator() == nullptr)
mData.loadDictionary("mmcif_pdbx_v50"); mData.loadDictionary("mmcif_pdbx_v50");
if (not mData.isValid()) if (not mData.isValid())
std::cerr << "Invalid mmCIF file" << (cif::VERBOSE ? "." : " use --verbose option to see errors") << std::endl; std::cerr << "Invalid mmCIF file" << (cif::VERBOSE ? "." : " use --verbose option to see errors") << std::endl;
} }
void FileImpl::load(const std::string& p) void FileImpl::load(const std::string &p)
{ {
fs::path path(p); fs::path path(p);
std::ifstream inFile(path, std::ios_base::in | std::ios_base::binary); std::ifstream inFile(path, std::ios_base::in | std::ios_base::binary);
if (not inFile.is_open()) if (not inFile.is_open())
throw std::runtime_error("No such file: " + path.string()); throw std::runtime_error("No such file: " + path.string());
io::filtering_stream<io::input> in; io::filtering_stream<io::input> in;
std::string ext = path.extension().string(); std::string ext = path.extension().string();
if (path.extension() == ".bz2") if (path.extension() == ".bz2")
{ {
in.push(io::bzip2_decompressor()); in.push(io::bzip2_decompressor());
...@@ -143,7 +143,7 @@ void FileImpl::load(const std::string& p) ...@@ -143,7 +143,7 @@ void FileImpl::load(const std::string& p)
in.push(io::gzip_decompressor()); in.push(io::gzip_decompressor());
ext = path.stem().extension().string(); ext = path.stem().extension().string();
} }
in.push(inFile); in.push(inFile);
try try
...@@ -159,56 +159,56 @@ void FileImpl::load(const std::string& p) ...@@ -159,56 +159,56 @@ void FileImpl::load(const std::string& p)
{ {
if (cif::VERBOSE) if (cif::VERBOSE)
std::cerr << "unrecognized file extension, trying cif" << std::endl; std::cerr << "unrecognized file extension, trying cif" << std::endl;
mData.load(in); mData.load(in);
} }
catch (const cif::CifParserError& e) catch (const cif::CifParserError &e)
{ {
if (cif::VERBOSE) if (cif::VERBOSE)
std::cerr << "Not cif, trying plain old PDB" << std::endl; std::cerr << "Not cif, trying plain old PDB" << std::endl;
// pffft... // pffft...
in.reset(); in.reset();
if (inFile.is_open()) if (inFile.is_open())
inFile.seekg(0); inFile.seekg(0);
else else
inFile.open(path, std::ios_base::in | std::ios::binary); inFile.open(path, std::ios_base::in | std::ios::binary);
if (path.extension() == ".bz2") if (path.extension() == ".bz2")
in.push(io::bzip2_decompressor()); in.push(io::bzip2_decompressor());
else if (path.extension() == ".gz") else if (path.extension() == ".gz")
in.push(io::gzip_decompressor()); in.push(io::gzip_decompressor());
in.push(inFile); in.push(inFile);
ReadPDBFile(in, mData); ReadPDBFile(in, mData);
} }
} }
} }
catch (const std::exception& ex) catch (const std::exception &ex)
{ {
std::cerr << "Error trying to load file " << path << std::endl; std::cerr << "Error trying to load file " << path << std::endl;
throw; throw;
} }
// Yes, we've parsed the data. Now locate the datablock. // Yes, we've parsed the data. Now locate the datablock.
mDb = &mData.firstDatablock(); mDb = &mData.firstDatablock();
// And validate, otherwise lots of functionality won't work // And validate, otherwise lots of functionality won't work
// if (mData.getValidator() == nullptr) // if (mData.getValidator() == nullptr)
mData.loadDictionary("mmcif_pdbx_v50"); mData.loadDictionary("mmcif_pdbx_v50");
if (not mData.isValid()) if (not mData.isValid())
std::cerr << "Invalid mmCIF file" << (cif::VERBOSE ? "." : " use --verbose option to see errors") << std::endl; std::cerr << "Invalid mmCIF file" << (cif::VERBOSE ? "." : " use --verbose option to see errors") << std::endl;
} }
void FileImpl::save(const std::string& p) void FileImpl::save(const std::string &p)
{ {
fs::path path(p); fs::path path(p);
std::ofstream outFile(p, std::ios_base::out | std::ios_base::binary); std::ofstream outFile(p, std::ios_base::out | std::ios_base::binary);
io::filtering_stream<io::output> out; io::filtering_stream<io::output> out;
if (path.extension() == ".gz") if (path.extension() == ".gz")
{ {
out.push(io::gzip_compressor()); out.push(io::gzip_compressor());
...@@ -219,45 +219,61 @@ void FileImpl::save(const std::string& p) ...@@ -219,45 +219,61 @@ void FileImpl::save(const std::string& p)
out.push(io::bzip2_compressor()); out.push(io::bzip2_compressor());
path = path.stem(); path = path.stem();
} }
out.push(outFile); out.push(outFile);
if (path.extension() == ".pdb") if (path.extension() == ".pdb")
WritePDBFile(out, mData); WritePDBFile(out, mData);
else else
mData.save(out); mData.save(out);
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// Atom // Atom
struct AtomImpl struct AtomImpl
{ {
AtomImpl(const AtomImpl& i) AtomImpl(const AtomImpl &i)
: mFile(i.mFile), mID(i.mID), mType(i.mType) : mFile(i.mFile)
, mAtomID(i.mAtomID), mCompID(i.mCompID), mAsymID(i.mAsymID) , mID(i.mID)
, mSeqID(i.mSeqID), mAltID(i.mAltID), mLocation(i.mLocation) , mType(i.mType)
, mRefcount(1), mRow(i.mRow), mCompound(i.mCompound) , mAtomID(i.mAtomID)
, mRadius(i.mRadius), mCachedProperties(i.mCachedProperties) , mCompID(i.mCompID)
, mSymmetryCopy(i.mSymmetryCopy), mClone(true) , mAsymID(i.mAsymID)
// , mRTop(i.mRTop), mD(i.mD) , mSeqID(i.mSeqID)
{ , mAltID(i.mAltID)
} , mLocation(i.mLocation)
, mRefcount(1)
AtomImpl(const File& f, const std::string& id) , mRow(i.mRow)
: mFile(f), mID(id), mRefcount(1), mCompound(nullptr) , mCompound(i.mCompound)
{ , mRadius(i.mRadius)
auto& db = *mFile.impl().mDb; , mCachedProperties(i.mCachedProperties)
auto& cat = db["atom_site"]; , mSymmetryCopy(i.mSymmetryCopy)
, mClone(true)
// , mRTop(i.mRTop), mD(i.mD)
{
}
AtomImpl(const File &f, const std::string &id)
: mFile(f)
, mID(id)
, mRefcount(1)
, mCompound(nullptr)
{
auto &db = *mFile.impl().mDb;
auto &cat = db["atom_site"];
mRow = cat[cif::Key("id") == mID]; mRow = cat[cif::Key("id") == mID];
prefetch(); prefetch();
} }
AtomImpl(const File& f, const std::string& id, cif::Row row) AtomImpl(const File &f, const std::string &id, cif::Row row)
: mFile(f), mID(id), mRefcount(1), mRow(row), mCompound(nullptr) : mFile(f)
, mID(id)
, mRefcount(1)
, mRow(row)
, mCompound(nullptr)
{ {
prefetch(); prefetch();
} }
...@@ -275,13 +291,23 @@ struct AtomImpl ...@@ -275,13 +291,23 @@ struct AtomImpl
// mLocation -= d; // mLocation -= d;
// } // }
AtomImpl(const AtomImpl& impl, const Point& loc, const std::string& sym_op) AtomImpl(const AtomImpl &impl, const Point &loc, const std::string &sym_op)
: mFile(impl.mFile), mID(impl.mID), mType(impl.mType), mAtomID(impl.mAtomID) : mFile(impl.mFile)
, mCompID(impl.mCompID), mAsymID(impl.mAsymID), mSeqID(impl.mSeqID) , mID(impl.mID)
, mAltID(impl.mAltID), mLocation(loc), mRefcount(1) , mType(impl.mType)
, mRow(impl.mRow), mCompound(impl.mCompound), mRadius(impl.mRadius) , mAtomID(impl.mAtomID)
, mCompID(impl.mCompID)
, mAsymID(impl.mAsymID)
, mSeqID(impl.mSeqID)
, mAltID(impl.mAltID)
, mLocation(loc)
, mRefcount(1)
, mRow(impl.mRow)
, mCompound(impl.mCompound)
, mRadius(impl.mRadius)
, mCachedProperties(impl.mCachedProperties) , mCachedProperties(impl.mCachedProperties)
, mSymmetryCopy(true), mSymmetryOperator(sym_op) , mSymmetryCopy(true)
, mSymmetryOperator(sym_op)
{ {
} }
...@@ -291,36 +317,36 @@ struct AtomImpl ...@@ -291,36 +317,36 @@ struct AtomImpl
std::string symbol; std::string symbol;
cif::tie(symbol, mAtomID, mCompID, mAsymID, mSeqID, mAltID) = cif::tie(symbol, mAtomID, mCompID, mAsymID, mSeqID, mAltID) =
mRow.get("type_symbol", "label_atom_id", "label_comp_id", "label_asym_id", "label_seq_id", "label_alt_id"); mRow.get("type_symbol", "label_atom_id", "label_comp_id", "label_asym_id", "label_seq_id", "label_alt_id");
if (symbol != "X") if (symbol != "X")
mType = AtomTypeTraits(symbol).type(); mType = AtomTypeTraits(symbol).type();
float x, y, z; float x, y, z;
cif::tie(x, y, z) = mRow.get("Cartn_x", "Cartn_y", "Cartn_z"); cif::tie(x, y, z) = mRow.get("Cartn_x", "Cartn_y", "Cartn_z");
mLocation = Point(x, y, z); mLocation = Point(x, y, z);
std::string compID; std::string compID;
cif::tie(compID) = mRow.get("label_comp_id"); cif::tie(compID) = mRow.get("label_comp_id");
mCompound = CompoundFactory::instance().get(compID); // mCompound = CompoundFactory::instance().create(compID);
} }
void reference() void reference()
{ {
++mRefcount; ++mRefcount;
} }
void release() void release()
{ {
if (--mRefcount <= 0) if (--mRefcount <= 0)
delete this; delete this;
} }
bool getAnisoU(float anisou[6]) const bool getAnisoU(float anisou[6]) const
{ {
auto& db = *mFile.impl().mDb; auto &db = *mFile.impl().mDb;
auto& cat = db["atom_site_anisotrop"]; auto &cat = db["atom_site_anisotrop"];
auto r = cat[cif::Key("id") == mID]; auto r = cat[cif::Key("id") == mID];
bool result = false; bool result = false;
...@@ -330,51 +356,51 @@ struct AtomImpl ...@@ -330,51 +356,51 @@ struct AtomImpl
cif::tie(anisou[0], anisou[1], anisou[2], anisou[3], anisou[4], anisou[5]) = cif::tie(anisou[0], anisou[1], anisou[2], anisou[3], anisou[4], anisou[5]) =
r.get("U[1][1]", "U[1][2]", "U[1][3]", "U[2][2]", "U[2][3]", "U[3][3]"); r.get("U[1][1]", "U[1][2]", "U[1][3]", "U[2][2]", "U[2][3]", "U[3][3]");
} }
return result; return result;
} }
void moveTo(const Point& p) void moveTo(const Point &p)
{ {
assert(not mSymmetryCopy); assert(not mSymmetryCopy);
if (mSymmetryCopy) if (mSymmetryCopy)
throw std::runtime_error("Moving symmetry copy"); throw std::runtime_error("Moving symmetry copy");
if (not mClone) if (not mClone)
{ {
mRow["Cartn_x"] = p.getX(); mRow["Cartn_x"] = p.getX();
mRow["Cartn_y"] = p.getY(); mRow["Cartn_y"] = p.getY();
mRow["Cartn_z"] = p.getZ(); mRow["Cartn_z"] = p.getZ();
} }
// boost::format kPosFmt("%.3f"); // boost::format kPosFmt("%.3f");
// //
// mRow["Cartn_x"] = (kPosFmt % p.getX()).str(); // mRow["Cartn_x"] = (kPosFmt % p.getX()).str();
// mRow["Cartn_y"] = (kPosFmt % p.getY()).str(); // mRow["Cartn_y"] = (kPosFmt % p.getY()).str();
// mRow["Cartn_z"] = (kPosFmt % p.getZ()).str(); // mRow["Cartn_z"] = (kPosFmt % p.getZ()).str();
mLocation = p; mLocation = p;
} }
const Compound& comp() const const Compound &comp() const
{ {
if (mCompound == nullptr) if (mCompound == nullptr)
{ {
std::string compID; std::string compID;
cif::tie(compID) = mRow.get("label_comp_id"); cif::tie(compID) = mRow.get("label_comp_id");
mCompound = Compound::create(compID); mCompound = CompoundFactory::instance().create(compID);
if (cif::VERBOSE and mCompound == nullptr) if (cif::VERBOSE and mCompound == nullptr)
std::cerr << "Compound not found: '" << compID << '\'' << std::endl; std::cerr << "Compound not found: '" << compID << '\'' << std::endl;
} }
if (mCompound == nullptr) if (mCompound == nullptr)
throw std::runtime_error("no compound"); throw std::runtime_error("no compound");
return *mCompound; return *mCompound;
} }
bool isWater() const bool isWater() const
{ {
return mCompound != nullptr and mCompound->isWater(); return mCompound != nullptr and mCompound->isWater();
...@@ -385,29 +411,29 @@ struct AtomImpl ...@@ -385,29 +411,29 @@ struct AtomImpl
return mRadius; return mRadius;
} }
const std::string& property(const std::string& name) const const std::string &property(const std::string &name) const
{ {
static std::string kEmptyString; static std::string kEmptyString;
auto i = mCachedProperties.find(name); auto i = mCachedProperties.find(name);
if (i == mCachedProperties.end()) if (i == mCachedProperties.end())
{ {
auto v = mRow[name]; auto v = mRow[name];
if (v.empty()) if (v.empty())
return kEmptyString; return kEmptyString;
return mCachedProperties[name] = v.as<std::string>(); return mCachedProperties[name] = v.as<std::string>();
} }
else else
return i->second; return i->second;
} }
void property(const std::string& name, const std::string& value) void property(const std::string &name, const std::string &value)
{ {
mRow[name] = value; mRow[name] = value;
} }
int compare(const AtomImpl& b) const int compare(const AtomImpl &b) const
{ {
int d = mAsymID.compare(b.mAsymID); int d = mAsymID.compare(b.mAsymID);
if (d == 0) if (d == 0)
...@@ -417,32 +443,32 @@ struct AtomImpl ...@@ -417,32 +443,32 @@ struct AtomImpl
return d; return d;
} }
void swapAtomLabels(AtomImpl& b) void swapAtomLabels(AtomImpl &b)
{ {
std::swap(mAtomID, b.mAtomID); std::swap(mAtomID, b.mAtomID);
} }
const File& mFile; const File &mFile;
std::string mID; std::string mID;
AtomType mType; AtomType mType;
std::string mAtomID; std::string mAtomID;
std::string mCompID; std::string mCompID;
std::string mAsymID; std::string mAsymID;
int mSeqID; int mSeqID;
std::string mAltID; std::string mAltID;
Point mLocation; Point mLocation;
int mRefcount; int mRefcount;
cif::Row mRow; cif::Row mRow;
mutable const Compound* mCompound; mutable const Compound *mCompound = nullptr;
float mRadius = nan("4"); float mRadius = nan("4");
mutable std::map<std::string,std::string> mCachedProperties; mutable std::map<std::string, std::string> mCachedProperties;
bool mSymmetryCopy = false; bool mSymmetryCopy = false;
bool mClone = false; bool mClone = false;
std::string mSymmetryOperator = "1_555"; std::string mSymmetryOperator = "1_555";
// clipper::RTop_orth mRTop; // clipper::RTop_orth mRTop;
// Point mD; // Point mD;
// int32_t mRTix; // int32_t mRTix;
...@@ -459,19 +485,19 @@ Atom::Atom() ...@@ -459,19 +485,19 @@ Atom::Atom()
{ {
} }
Atom::Atom(AtomImpl* impl) Atom::Atom(AtomImpl *impl)
: mImpl_(impl) : mImpl_(impl)
{ {
} }
AtomImpl* Atom::impl() AtomImpl *Atom::impl()
{ {
if (mImpl_ == nullptr) if (mImpl_ == nullptr)
throw std::runtime_error("atom is not set"); throw std::runtime_error("atom is not set");
return mImpl_; return mImpl_;
} }
const AtomImpl* Atom::impl() const const AtomImpl *Atom::impl() const
{ {
if (mImpl_ == nullptr) if (mImpl_ == nullptr)
throw std::runtime_error("atom is not set"); throw std::runtime_error("atom is not set");
...@@ -483,12 +509,12 @@ Atom Atom::clone() const ...@@ -483,12 +509,12 @@ Atom Atom::clone() const
return Atom(mImpl_ ? new AtomImpl(*mImpl_) : nullptr); return Atom(mImpl_ ? new AtomImpl(*mImpl_) : nullptr);
} }
Atom::Atom(const Atom& rhs, const Point& loc, const std::string& sym_op) Atom::Atom(const Atom &rhs, const Point &loc, const std::string &sym_op)
: mImpl_(new AtomImpl(*rhs.mImpl_, loc, sym_op)) : mImpl_(new AtomImpl(*rhs.mImpl_, loc, sym_op))
{ {
} }
Atom::Atom(const Atom& rhs) Atom::Atom(const Atom &rhs)
: mImpl_(rhs.mImpl_) : mImpl_(rhs.mImpl_)
{ {
if (mImpl_) if (mImpl_)
...@@ -501,7 +527,7 @@ Atom::~Atom() ...@@ -501,7 +527,7 @@ Atom::~Atom()
mImpl_->release(); mImpl_->release();
} }
Atom& Atom::operator=(const Atom& rhs) Atom &Atom::operator=(const Atom &rhs)
{ {
if (this != &rhs) if (this != &rhs)
{ {
...@@ -522,36 +548,36 @@ const cif::Row Atom::getRow() const ...@@ -522,36 +548,36 @@ const cif::Row Atom::getRow() const
const cif::Row Atom::getRowAniso() const const cif::Row Atom::getRowAniso() const
{ {
auto& db = *mImpl_->mFile.impl().mDb; auto &db = *mImpl_->mFile.impl().mDb;
auto& cat = db["atom_site_anisotrop"]; auto &cat = db["atom_site_anisotrop"];
return cat[cif::Key("id") == mImpl_->mID]; return cat[cif::Key("id") == mImpl_->mID];
} }
template<> template <>
std::string Atom::property<std::string>(const std::string& name) const std::string Atom::property<std::string>(const std::string &name) const
{ {
return impl()->property(name); return impl()->property(name);
} }
template<> template <>
int Atom::property<int>(const std::string& name) const int Atom::property<int>(const std::string &name) const
{ {
auto v = impl()->property(name); auto v = impl()->property(name);
return v.empty() ? 0 : stoi(v); return v.empty() ? 0 : stoi(v);
} }
template<> template <>
float Atom::property<float>(const std::string& name) const float Atom::property<float>(const std::string &name) const
{ {
return stof(impl()->property(name)); return stof(impl()->property(name));
} }
void Atom::property(const std::string& name, const std::string& value) void Atom::property(const std::string &name, const std::string &value)
{ {
impl()->property(name, value); impl()->property(name, value);
} }
const std::string& Atom::id() const const std::string &Atom::id() const
{ {
return impl()->mID; return impl()->mID;
} }
...@@ -569,14 +595,14 @@ int Atom::charge() const ...@@ -569,14 +595,14 @@ int Atom::charge() const
float Atom::uIso() const float Atom::uIso() const
{ {
float result; float result;
if (not property<std::string>("U_iso_or_equiv").empty()) if (not property<std::string>("U_iso_or_equiv").empty())
result = property<float>("U_iso_or_equiv"); result = property<float>("U_iso_or_equiv");
else if (not property<std::string>("B_iso_or_equiv").empty()) else if (not property<std::string>("B_iso_or_equiv").empty())
result = property<float>("B_iso_or_equiv") / (8 * kPI * kPI); result = property<float>("B_iso_or_equiv") / (8 * kPI * kPI);
else else
throw std::runtime_error("Missing B_iso or U_iso"); throw std::runtime_error("Missing B_iso or U_iso");
return result; return result;
} }
...@@ -662,11 +688,10 @@ std::string Atom::labelID() const ...@@ -662,11 +688,10 @@ std::string Atom::labelID() const
std::string Atom::pdbID() const std::string Atom::pdbID() const
{ {
return return property<std::string>("auth_comp_id") + '_' +
property<std::string>("auth_comp_id") + '_' + property<std::string>("auth_asym_id") + '_' +
property<std::string>("auth_asym_id") + '_' + property<std::string>("auth_seq_id") +
property<std::string>("auth_seq_id") + property<std::string>("pdbx_PDB_ins_code");
property<std::string>("pdbx_PDB_ins_code");
} }
Point Atom::location() const Point Atom::location() const
...@@ -709,7 +734,7 @@ std::string Atom::symmetry() const ...@@ -709,7 +734,7 @@ std::string Atom::symmetry() const
// return impl()->mRTop; // return impl()->mRTop;
// } // }
const Compound& Atom::comp() const const Compound &Atom::comp() const
{ {
return impl()->comp(); return impl()->comp();
} }
...@@ -719,10 +744,10 @@ bool Atom::isWater() const ...@@ -719,10 +744,10 @@ bool Atom::isWater() const
return impl()->isWater(); return impl()->isWater();
} }
bool Atom::operator==(const Atom& rhs) const bool Atom::operator==(const Atom &rhs) const
{ {
return impl() == rhs.impl() or return impl() == rhs.impl() or
(&impl()->mFile == &rhs.impl()->mFile and impl()->mID == rhs.impl()->mID); (&impl()->mFile == &rhs.impl()->mFile and impl()->mID == rhs.impl()->mID);
} }
// clipper::Atom Atom::toClipper() const // clipper::Atom Atom::toClipper() const
...@@ -745,7 +770,7 @@ float Atom::radius() const ...@@ -745,7 +770,7 @@ float Atom::radius() const
return impl()->mRadius; return impl()->mRadius;
} }
int Atom::compare(const Atom& b) const int Atom::compare(const Atom &b) const
{ {
return impl() == b.impl() ? 0 : impl()->compare(*b.impl()); return impl() == b.impl() ? 0 : impl()->compare(*b.impl());
} }
...@@ -755,7 +780,7 @@ void Atom::setID(int id) ...@@ -755,7 +780,7 @@ void Atom::setID(int id)
impl()->mID = std::to_string(id); impl()->mID = std::to_string(id);
} }
std::ostream& operator<<(std::ostream& os, const Atom& atom) std::ostream &operator<<(std::ostream &os, const Atom &atom)
{ {
os << atom.labelCompID() << ' ' << atom.labelAsymID() << ':' << atom.labelSeqID(); os << atom.labelCompID() << ' ' << atom.labelAsymID() << ':' << atom.labelSeqID();
...@@ -772,16 +797,18 @@ std::ostream& operator<<(std::ostream& os, const Atom& atom) ...@@ -772,16 +797,18 @@ std::ostream& operator<<(std::ostream& os, const Atom& atom)
// First constructor used to be for waters only, but now accepts sugars as well. // First constructor used to be for waters only, but now accepts sugars as well.
Residue::Residue(const Structure& structure, const std::string& compoundID, Residue::Residue(const Structure &structure, const std::string &compoundID,
const std::string& asymID, const std::string& authSeqID) const std::string &asymID, const std::string &authSeqID)
: mStructure(&structure), mCompoundID(compoundID) : mStructure(&structure)
, mAsymID(asymID), mAuthSeqID(authSeqID) , mCompoundID(compoundID)
, mAsymID(asymID)
, mAuthSeqID(authSeqID)
{ {
for (auto& a: mStructure->atoms()) for (auto &a : mStructure->atoms())
{ {
if (a.labelAsymID() != mAsymID or if (a.labelAsymID() != mAsymID or
a.labelCompID() != mCompoundID) a.labelCompID() != mCompoundID)
continue; continue;
if (compoundID == "HOH") if (compoundID == "HOH")
{ {
...@@ -793,45 +820,52 @@ Residue::Residue(const Structure& structure, const std::string& compoundID, ...@@ -793,45 +820,52 @@ Residue::Residue(const Structure& structure, const std::string& compoundID,
if (mSeqID > 0 and a.labelSeqID() != mSeqID) if (mSeqID > 0 and a.labelSeqID() != mSeqID)
continue; continue;
} }
mAtoms.push_back(a); mAtoms.push_back(a);
} }
assert(not mAtoms.empty()); assert(not mAtoms.empty());
} }
Residue::Residue(const Structure& structure, const std::string& compoundID, Residue::Residue(const Structure &structure, const std::string &compoundID,
const std::string& asymID, int seqID) const std::string &asymID, int seqID)
: mStructure(&structure), mCompoundID(compoundID) : mStructure(&structure)
, mAsymID(asymID), mSeqID(seqID) , mCompoundID(compoundID)
, mAsymID(asymID)
, mSeqID(seqID)
{ {
assert(mCompoundID != "HOH"); assert(mCompoundID != "HOH");
for (auto& a: mStructure->atoms()) for (auto &a : mStructure->atoms())
{ {
if (mSeqID > 0 and a.labelSeqID() != mSeqID) if (mSeqID > 0 and a.labelSeqID() != mSeqID)
continue; continue;
if (a.labelAsymID() != mAsymID or if (a.labelAsymID() != mAsymID or
a.labelCompID() != mCompoundID) a.labelCompID() != mCompoundID)
continue; continue;
mAtoms.push_back(a); mAtoms.push_back(a);
} }
} }
Residue::Residue(Residue&& rhs) Residue::Residue(Residue &&rhs)
: mStructure(rhs.mStructure), mCompoundID(std::move(rhs.mCompoundID)), mAsymID(std::move(rhs.mAsymID)) : mStructure(rhs.mStructure)
, mSeqID(rhs.mSeqID), mAuthSeqID(rhs.mAuthSeqID), mAtoms(std::move(rhs.mAtoms)) , mCompoundID(std::move(rhs.mCompoundID))
, mAsymID(std::move(rhs.mAsymID))
, mSeqID(rhs.mSeqID)
, mAuthSeqID(rhs.mAuthSeqID)
, mAtoms(std::move(rhs.mAtoms))
{ {
//std::cerr << "move constructor residue" << std::endl; //std::cerr << "move constructor residue" << std::endl;
rhs.mStructure = nullptr; rhs.mStructure = nullptr;
} }
Residue& Residue::operator=(Residue&& rhs) Residue &Residue::operator=(Residue &&rhs)
{ {
//std::cerr << "move assignment residue" << std::endl; //std::cerr << "move assignment residue" << std::endl;
mStructure = rhs.mStructure; rhs.mStructure = nullptr; mStructure = rhs.mStructure;
rhs.mStructure = nullptr;
mCompoundID = std::move(rhs.mCompoundID); mCompoundID = std::move(rhs.mCompoundID);
mAsymID = std::move(rhs.mAsymID); mAsymID = std::move(rhs.mAsymID);
mSeqID = rhs.mSeqID; mSeqID = rhs.mSeqID;
...@@ -843,7 +877,7 @@ Residue& Residue::operator=(Residue&& rhs) ...@@ -843,7 +877,7 @@ Residue& Residue::operator=(Residue&& rhs)
Residue::~Residue() Residue::~Residue()
{ {
//std::cerr << "~Residue" << std::endl; //std::cerr << "~Residue" << std::endl;
} }
std::string Residue::entityID() const std::string Residue::entityID() const
...@@ -856,19 +890,19 @@ std::string Residue::authInsCode() const ...@@ -856,19 +890,19 @@ std::string Residue::authInsCode() const
assert(mStructure); assert(mStructure);
std::string result; std::string result;
try try
{ {
char iCode; char iCode;
tie(std::ignore, std::ignore, iCode) = mStructure->MapLabelToAuth(mAsymID, mSeqID); tie(std::ignore, std::ignore, iCode) = mStructure->MapLabelToAuth(mAsymID, mSeqID);
result = std::string{ iCode }; result = std::string{iCode};
ba::trim(result); ba::trim(result);
} }
catch (...) catch (...)
{ {
} }
return result; return result;
} }
...@@ -877,7 +911,7 @@ std::string Residue::authAsymID() const ...@@ -877,7 +911,7 @@ std::string Residue::authAsymID() const
assert(mStructure); assert(mStructure);
std::string result; std::string result;
try try
{ {
tie(result, std::ignore, std::ignore) = mStructure->MapLabelToAuth(mAsymID, mSeqID); tie(result, std::ignore, std::ignore) = mStructure->MapLabelToAuth(mAsymID, mSeqID);
...@@ -886,7 +920,7 @@ std::string Residue::authAsymID() const ...@@ -886,7 +920,7 @@ std::string Residue::authAsymID() const
{ {
result = mAsymID; result = mAsymID;
} }
return result; return result;
} }
...@@ -895,7 +929,7 @@ std::string Residue::authSeqID() const ...@@ -895,7 +929,7 @@ std::string Residue::authSeqID() const
assert(mStructure); assert(mStructure);
std::string result; std::string result;
try try
{ {
int seqID; int seqID;
...@@ -905,19 +939,19 @@ std::string Residue::authSeqID() const ...@@ -905,19 +939,19 @@ std::string Residue::authSeqID() const
catch (...) catch (...)
{ {
} }
return result; return result;
} }
const Compound& Residue::compound() const const Compound &Residue::compound() const
{ {
auto result = Compound::create(mCompoundID); auto result = CompoundFactory::instance().create(mCompoundID);
if (result == nullptr) if (result == nullptr)
throw std::runtime_error("Failed to create compound " + mCompoundID); throw std::runtime_error("Failed to create compound " + mCompoundID);
return *result; return *result;
} }
const AtomView& Residue::atoms() const const AtomView &Residue::atoms() const
{ {
if (mStructure == nullptr) if (mStructure == nullptr)
throw std::runtime_error("Invalid Residue object"); throw std::runtime_error("Invalid Residue object");
...@@ -930,7 +964,7 @@ std::string Residue::unique_alt_id() const ...@@ -930,7 +964,7 @@ std::string Residue::unique_alt_id() const
if (mStructure == nullptr) if (mStructure == nullptr)
throw std::runtime_error("Invalid Residue object"); throw std::runtime_error("Invalid Residue object");
auto firstAlt = std::find_if(mAtoms.begin(), mAtoms.end(), [](auto& a) { return not a.labelAltID().empty(); }); auto firstAlt = std::find_if(mAtoms.begin(), mAtoms.end(), [](auto &a) { return not a.labelAltID().empty(); });
return firstAlt != mAtoms.end() ? firstAlt->labelAltID() : ""; return firstAlt != mAtoms.end() ? firstAlt->labelAltID() : "";
} }
...@@ -943,7 +977,7 @@ AtomView Residue::unique_atoms() const ...@@ -943,7 +977,7 @@ AtomView Residue::unique_atoms() const
AtomView result; AtomView result;
std::string firstAlt; std::string firstAlt;
for (auto& atom: mAtoms) for (auto &atom : mAtoms)
{ {
auto alt = atom.labelAltID(); auto alt = atom.labelAltID();
if (alt.empty()) if (alt.empty())
...@@ -963,7 +997,7 @@ AtomView Residue::unique_atoms() const ...@@ -963,7 +997,7 @@ AtomView Residue::unique_atoms() const
result.push_back(atom); result.push_back(atom);
} }
return result; return result;
} }
...@@ -971,7 +1005,7 @@ std::set<std::string> Residue::getAlternateIDs() const ...@@ -971,7 +1005,7 @@ std::set<std::string> Residue::getAlternateIDs() const
{ {
std::set<std::string> result; std::set<std::string> result;
for (auto a: mAtoms) for (auto a : mAtoms)
{ {
auto alt = a.labelAltID(); auto alt = a.labelAltID();
if (not alt.empty()) if (not alt.empty())
...@@ -981,11 +1015,11 @@ std::set<std::string> Residue::getAlternateIDs() const ...@@ -981,11 +1015,11 @@ std::set<std::string> Residue::getAlternateIDs() const
return result; return result;
} }
Atom Residue::atomByID(const std::string& atomID) const Atom Residue::atomByID(const std::string &atomID) const
{ {
Atom result; Atom result;
for (auto& a: mAtoms) for (auto &a : mAtoms)
{ {
if (a.labelAtomID() == atomID) if (a.labelAtomID() == atomID)
{ {
...@@ -1004,26 +1038,26 @@ Atom Residue::atomByID(const std::string& atomID) const ...@@ -1004,26 +1038,26 @@ Atom Residue::atomByID(const std::string& atomID) const
// to the number of atoms in this residue... hope this is correct.... // to the number of atoms in this residue... hope this is correct....
bool Residue::isEntity() const bool Residue::isEntity() const
{ {
auto& db = mStructure->datablock(); auto &db = mStructure->datablock();
auto a1 = db["atom_site"].find(cif::Key("label_asym_id") == mAsymID); auto a1 = db["atom_site"].find(cif::Key("label_asym_id") == mAsymID);
// auto a2 = atoms(); // auto a2 = atoms();
auto& a2 = mAtoms; auto &a2 = mAtoms;
return a1.size() == a2.size(); return a1.size() == a2.size();
} }
std::string Residue::authID() const std::string Residue::authID() const
{ {
std::string result; std::string result;
try try
{ {
char chainID, iCode; char chainID, iCode;
int seqNum; int seqNum;
std::tie(chainID, seqNum, iCode) = mStructure->MapLabelToAuth(mAsymID, mSeqID); std::tie(chainID, seqNum, iCode) = mStructure->MapLabelToAuth(mAsymID, mSeqID);
result = chainID + std::to_string(seqNum); result = chainID + std::to_string(seqNum);
if (iCode != ' ' and iCode != 0) if (iCode != ' ' and iCode != 0)
result += iCode; result += iCode;
...@@ -1032,7 +1066,7 @@ std::string Residue::authID() const ...@@ -1032,7 +1066,7 @@ std::string Residue::authID() const
{ {
result = mAsymID + std::to_string(mSeqID); result = mAsymID + std::to_string(mSeqID);
} }
return result; return result;
} }
...@@ -1044,43 +1078,43 @@ std::string Residue::labelID() const ...@@ -1044,43 +1078,43 @@ std::string Residue::labelID() const
return mAsymID + std::to_string(mSeqID); return mAsymID + std::to_string(mSeqID);
} }
std::tuple<Point,float> Residue::centerAndRadius() const std::tuple<Point, float> Residue::centerAndRadius() const
{ {
std::vector<Point> pts; std::vector<Point> pts;
for (auto& a: mAtoms) for (auto &a : mAtoms)
pts.push_back(a.location()); pts.push_back(a.location());
auto center = Centroid(pts); auto center = Centroid(pts);
float radius = 0; float radius = 0;
for (auto& pt: pts) for (auto &pt : pts)
{ {
auto d = Distance(pt, center); auto d = Distance(pt, center);
if (radius < d) if (radius < d)
radius = d; radius = d;
} }
return std::make_tuple(center, radius); return std::make_tuple(center, radius);
} }
bool Residue::hasAlternateAtoms() const bool Residue::hasAlternateAtoms() const
{ {
return std::find_if(mAtoms.begin(), mAtoms.end(), [](const Atom& atom) { return atom.isAlternate(); }) != mAtoms.end(); return std::find_if(mAtoms.begin(), mAtoms.end(), [](const Atom &atom) { return atom.isAlternate(); }) != mAtoms.end();
} }
std::set<std::string> Residue::getAtomIDs() const std::set<std::string> Residue::getAtomIDs() const
{ {
std::set<std::string> ids; std::set<std::string> ids;
for (auto a: mAtoms) for (auto a : mAtoms)
ids.insert(a.labelAtomID()); ids.insert(a.labelAtomID());
return ids; return ids;
} }
AtomView Residue::getAtomsByID(const std::string& atomID) const AtomView Residue::getAtomsByID(const std::string &atomID) const
{ {
AtomView atoms; AtomView atoms;
for (auto a: mAtoms) for (auto a : mAtoms)
{ {
if (a.labelAtomID() == atomID) if (a.labelAtomID() == atomID)
atoms.push_back(a); atoms.push_back(a);
...@@ -1088,7 +1122,7 @@ AtomView Residue::getAtomsByID(const std::string& atomID) const ...@@ -1088,7 +1122,7 @@ AtomView Residue::getAtomsByID(const std::string& atomID) const
return atoms; return atoms;
} }
std::ostream& operator<<(std::ostream& os, const Residue& res) std::ostream &operator<<(std::ostream &os, const Residue &res)
{ {
os << res.compoundID() << ' ' << res.asymID() << ':' << res.seqID(); os << res.compoundID() << ' ' << res.asymID() << ':' << res.seqID();
...@@ -1106,37 +1140,40 @@ std::ostream& operator<<(std::ostream& os, const Residue& res) ...@@ -1106,37 +1140,40 @@ std::ostream& operator<<(std::ostream& os, const Residue& res)
//{ //{
//} //}
Monomer::Monomer(const Polymer& polymer, uint32_t index, int seqID, const std::string& compoundID) Monomer::Monomer(const Polymer &polymer, uint32_t index, int seqID, const std::string &compoundID)
: Residue(*polymer.structure(), compoundID, polymer.asymID(), seqID) : Residue(*polymer.structure(), compoundID, polymer.asymID(), seqID)
, mPolymer(&polymer) , mPolymer(&polymer)
, mIndex(index) , mIndex(index)
{ {
} }
Monomer::Monomer(Monomer&& rhs) Monomer::Monomer(Monomer &&rhs)
: Residue(std::move(rhs)), mPolymer(rhs.mPolymer), mIndex(rhs.mIndex) : Residue(std::move(rhs))
, mPolymer(rhs.mPolymer)
, mIndex(rhs.mIndex)
{ {
std::cerr << "move constructor monomer" << std::endl; std::cerr << "move constructor monomer" << std::endl;
// mStructure = rhs.mStructure; rhs.mStructure = nullptr; // mStructure = rhs.mStructure; rhs.mStructure = nullptr;
// mCompoundID = std::move(rhs.mCompoundID); // mCompoundID = std::move(rhs.mCompoundID);
// mAsymID = std::move(rhs.mAsymID); // mAsymID = std::move(rhs.mAsymID);
// mSeqID = rhs.mSeqID; // mSeqID = rhs.mSeqID;
// mAtoms = std::move(rhs.mAtoms); // mAtoms = std::move(rhs.mAtoms);
// //
// mPolymer = rhs.mPolymer; rhs.mPolymer = nullptr; // mPolymer = rhs.mPolymer; rhs.mPolymer = nullptr;
// mIndex = rhs.mIndex; // mIndex = rhs.mIndex;
rhs.mPolymer = nullptr; rhs.mPolymer = nullptr;
} }
Monomer& Monomer::operator=(Monomer&& rhs) Monomer &Monomer::operator=(Monomer &&rhs)
{ {
std::cerr << "move assignment monomer" << std::endl; std::cerr << "move assignment monomer" << std::endl;
Residue::operator=(std::move(rhs)); Residue::operator=(std::move(rhs));
mPolymer = rhs.mPolymer; rhs.mPolymer = nullptr; mPolymer = rhs.mPolymer;
rhs.mPolymer = nullptr;
mIndex = rhs.mIndex; mIndex = rhs.mIndex;
return *this; return *this;
} }
...@@ -1152,8 +1189,7 @@ bool Monomer::is_last_in_chain() const ...@@ -1152,8 +1189,7 @@ bool Monomer::is_last_in_chain() const
bool Monomer::has_alpha() const bool Monomer::has_alpha() const
{ {
return return mIndex >= 1 and mIndex + 2 < mPolymer->size();
mIndex >= 1 and mIndex + 2 < mPolymer->size();
} }
bool Monomer::has_kappa() const bool Monomer::has_kappa() const
...@@ -1169,12 +1205,12 @@ float Monomer::phi() const ...@@ -1169,12 +1205,12 @@ float Monomer::phi() const
{ {
if (mIndex > 0) if (mIndex > 0)
{ {
auto& prev = mPolymer->operator[](mIndex - 1); auto &prev = mPolymer->operator[](mIndex - 1);
if (prev.mSeqID + 1 == mSeqID) if (prev.mSeqID + 1 == mSeqID)
result = DihedralAngle(prev.C().location(), N().location(), CAlpha().location(), C().location()); result = DihedralAngle(prev.C().location(), N().location(), CAlpha().location(), C().location());
} }
} }
catch (const std::exception& ex) catch (const std::exception &ex)
{ {
if (cif::VERBOSE) if (cif::VERBOSE)
std::cerr << ex.what() << std::endl; std::cerr << ex.what() << std::endl;
...@@ -1186,17 +1222,17 @@ float Monomer::phi() const ...@@ -1186,17 +1222,17 @@ float Monomer::phi() const
float Monomer::psi() const float Monomer::psi() const
{ {
float result = 360; float result = 360;
try try
{ {
if (mIndex + 1 < mPolymer->size()) if (mIndex + 1 < mPolymer->size())
{ {
auto& next = mPolymer->operator[](mIndex + 1); auto &next = mPolymer->operator[](mIndex + 1);
if (mSeqID + 1 == next.mSeqID) if (mSeqID + 1 == next.mSeqID)
result = DihedralAngle(N().location(), CAlpha().location(), C().location(), next.N().location()); result = DihedralAngle(N().location(), CAlpha().location(), C().location(), next.N().location());
} }
} }
catch (const std::exception& ex) catch (const std::exception &ex)
{ {
if (cif::VERBOSE) if (cif::VERBOSE)
std::cerr << ex.what() << std::endl; std::cerr << ex.what() << std::endl;
...@@ -1213,14 +1249,14 @@ float Monomer::alpha() const ...@@ -1213,14 +1249,14 @@ float Monomer::alpha() const
{ {
if (mIndex >= 1 and mIndex + 2 < mPolymer->size()) if (mIndex >= 1 and mIndex + 2 < mPolymer->size())
{ {
auto& prev = mPolymer->operator[](mIndex - 1); auto &prev = mPolymer->operator[](mIndex - 1);
auto& next = mPolymer->operator[](mIndex + 1); auto &next = mPolymer->operator[](mIndex + 1);
auto& nextNext = mPolymer->operator[](mIndex + 2); auto &nextNext = mPolymer->operator[](mIndex + 2);
result = DihedralAngle(prev.CAlpha().location(), CAlpha().location(), next.CAlpha().location(), nextNext.CAlpha().location()); result = DihedralAngle(prev.CAlpha().location(), CAlpha().location(), next.CAlpha().location(), nextNext.CAlpha().location());
} }
} }
catch (const std::exception& ex) catch (const std::exception &ex)
{ {
if (cif::VERBOSE) if (cif::VERBOSE)
std::cerr << ex.what() << std::endl; std::cerr << ex.what() << std::endl;
...@@ -1232,14 +1268,14 @@ float Monomer::alpha() const ...@@ -1232,14 +1268,14 @@ float Monomer::alpha() const
float Monomer::kappa() const float Monomer::kappa() const
{ {
double result = 360; double result = 360;
try try
{ {
if (mIndex >= 2 and mIndex + 2 < mPolymer->size()) if (mIndex >= 2 and mIndex + 2 < mPolymer->size())
{ {
auto& prevPrev = mPolymer->operator[](mIndex - 2); auto &prevPrev = mPolymer->operator[](mIndex - 2);
auto& nextNext = mPolymer->operator[](mIndex + 2); auto &nextNext = mPolymer->operator[](mIndex + 2);
if (prevPrev.mSeqID + 4 == nextNext.mSeqID) if (prevPrev.mSeqID + 4 == nextNext.mSeqID)
{ {
double ckap = CosinusAngle(CAlpha().location(), prevPrev.CAlpha().location(), nextNext.CAlpha().location(), CAlpha().location()); double ckap = CosinusAngle(CAlpha().location(), prevPrev.CAlpha().location(), nextNext.CAlpha().location(), CAlpha().location());
...@@ -1248,11 +1284,11 @@ float Monomer::kappa() const ...@@ -1248,11 +1284,11 @@ float Monomer::kappa() const
} }
} }
} }
catch (const std::exception& ex) catch (const std::exception &ex)
{ {
if (cif::VERBOSE) if (cif::VERBOSE)
std::cerr << "When trying to calculate kappa for " << asymID() << ':' << seqID() << ": " std::cerr << "When trying to calculate kappa for " << asymID() << ':' << seqID() << ": "
<< ex.what() << std::endl; << ex.what() << std::endl;
} }
return result; return result;
...@@ -1261,21 +1297,21 @@ float Monomer::kappa() const ...@@ -1261,21 +1297,21 @@ float Monomer::kappa() const
float Monomer::tco() const float Monomer::tco() const
{ {
double result = 0.0; double result = 0.0;
try try
{ {
if (mIndex > 0) if (mIndex > 0)
{ {
auto& prev = mPolymer->operator[](mIndex - 1); auto &prev = mPolymer->operator[](mIndex - 1);
if (prev.mSeqID + 1 == mSeqID) if (prev.mSeqID + 1 == mSeqID)
result = CosinusAngle(C().location(), O().location(), prev.C().location(), prev.O().location()); result = CosinusAngle(C().location(), O().location(), prev.C().location(), prev.O().location());
} }
} }
catch (const std::exception& ex) catch (const std::exception &ex)
{ {
if (cif::VERBOSE) if (cif::VERBOSE)
std::cerr << "When trying to calculate tco for " << asymID() << ':' << seqID() << ": " std::cerr << "When trying to calculate tco for " << asymID() << ':' << seqID() << ": "
<< ex.what() << std::endl; << ex.what() << std::endl;
} }
return result; return result;
...@@ -1284,43 +1320,42 @@ float Monomer::tco() const ...@@ -1284,43 +1320,42 @@ float Monomer::tco() const
float Monomer::omega() const float Monomer::omega() const
{ {
double result = 360; double result = 360;
try try
{ {
if (not is_last_in_chain()) if (not is_last_in_chain())
result = omega(*this, mPolymer->operator[](mIndex + 1)); result = omega(*this, mPolymer->operator[](mIndex + 1));
} }
catch (const std::exception& ex) catch (const std::exception &ex)
{ {
if (cif::VERBOSE) if (cif::VERBOSE)
std::cerr << "When trying to calculate omega for " << asymID() << ':' << seqID() << ": " std::cerr << "When trying to calculate omega for " << asymID() << ':' << seqID() << ": "
<< ex.what() << std::endl; << ex.what() << std::endl;
} }
return result; return result;
} }
const std::map<std::string,std::vector<std::string>> kChiAtomsMap = { const std::map<std::string, std::vector<std::string>> kChiAtomsMap = {
{ "ASP", {"CG", "OD1"} }, {"ASP", {"CG", "OD1"}},
{ "ASN", {"CG", "OD1"} }, {"ASN", {"CG", "OD1"}},
{ "ARG", {"CG", "CD", "NE", "CZ"} }, {"ARG", {"CG", "CD", "NE", "CZ"}},
{ "HIS", {"CG", "ND1"} }, {"HIS", {"CG", "ND1"}},
{ "GLN", {"CG", "CD", "OE1"} }, {"GLN", {"CG", "CD", "OE1"}},
{ "GLU", {"CG", "CD", "OE1"} }, {"GLU", {"CG", "CD", "OE1"}},
{ "SER", {"OG"} }, {"SER", {"OG"}},
{ "THR", {"OG1"} }, {"THR", {"OG1"}},
{ "LYS", {"CG", "CD", "CE", "NZ"} }, {"LYS", {"CG", "CD", "CE", "NZ"}},
{ "TYR", {"CG", "CD1"} }, {"TYR", {"CG", "CD1"}},
{ "PHE", {"CG", "CD1"} }, {"PHE", {"CG", "CD1"}},
{ "LEU", {"CG", "CD1"} }, {"LEU", {"CG", "CD1"}},
{ "TRP", {"CG", "CD1"} }, {"TRP", {"CG", "CD1"}},
{ "CYS", {"SG"} }, {"CYS", {"SG"}},
{ "ILE", {"CG1", "CD1"} }, {"ILE", {"CG1", "CD1"}},
{ "MET", {"CG", "SD", "CE"} }, {"MET", {"CG", "SD", "CE"}},
{ "MSE", {"CG", "SE", "CE"} }, {"MSE", {"CG", "SE", "CE"}},
{ "PRO", {"CG", "CD"} }, {"PRO", {"CG", "CD"}},
{ "VAL", {"CG1"} } {"VAL", {"CG1"}}};
};
size_t Monomer::nrOfChis() const size_t Monomer::nrOfChis() const
{ {
...@@ -1329,7 +1364,7 @@ size_t Monomer::nrOfChis() const ...@@ -1329,7 +1364,7 @@ size_t Monomer::nrOfChis() const
auto i = kChiAtomsMap.find(mCompoundID); auto i = kChiAtomsMap.find(mCompoundID);
if (i != kChiAtomsMap.end()) if (i != kChiAtomsMap.end())
result = i->second.size(); result = i->second.size();
return result; return result;
} }
...@@ -1342,26 +1377,27 @@ float Monomer::chi(size_t nr) const ...@@ -1342,26 +1377,27 @@ float Monomer::chi(size_t nr) const
auto i = kChiAtomsMap.find(mCompoundID); auto i = kChiAtomsMap.find(mCompoundID);
if (i != kChiAtomsMap.end() and nr < i->second.size()) if (i != kChiAtomsMap.end() and nr < i->second.size())
{ {
std::vector<std::string> atoms{ "N", "CA", "CB" }; std::vector<std::string> atoms{"N", "CA", "CB"};
atoms.insert(atoms.end(), i->second.begin(), i->second.end()); atoms.insert(atoms.end(), i->second.begin(), i->second.end());
// in case we have a positive chiral volume we need to swap atoms // in case we have a positive chiral volume we need to swap atoms
if (chiralVolume() > 0) if (chiralVolume() > 0)
{ {
if (mCompoundID == "LEU") atoms.back() = "CD2"; if (mCompoundID == "LEU")
if (mCompoundID == "VAL") atoms.back() = "CG2"; atoms.back() = "CD2";
if (mCompoundID == "VAL")
atoms.back() = "CG2";
} }
result = DihedralAngle( result = DihedralAngle(
atomByID(atoms[nr + 0]).location(), atomByID(atoms[nr + 0]).location(),
atomByID(atoms[nr + 1]).location(), atomByID(atoms[nr + 1]).location(),
atomByID(atoms[nr + 2]).location(), atomByID(atoms[nr + 2]).location(),
atomByID(atoms[nr + 3]).location() atomByID(atoms[nr + 3]).location());
);
} }
} }
catch(const std::exception& e) catch (const std::exception &e)
{ {
if (cif::VERBOSE) if (cif::VERBOSE)
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
...@@ -1374,26 +1410,30 @@ float Monomer::chi(size_t nr) const ...@@ -1374,26 +1410,30 @@ float Monomer::chi(size_t nr) const
bool Monomer::isCis() const bool Monomer::isCis() const
{ {
bool result = false; bool result = false;
if (mIndex + 1 < mPolymer->size()) if (mIndex + 1 < mPolymer->size())
{ {
auto& next = mPolymer->operator[](mIndex + 1); auto &next = mPolymer->operator[](mIndex + 1);
result = Monomer::isCis(*this, next); result = Monomer::isCis(*this, next);
} }
return result; return result;
} }
bool Monomer::isComplete() const bool Monomer::isComplete() const
{ {
int seen = 0; int seen = 0;
for (auto& a: mAtoms) for (auto &a : mAtoms)
{ {
if (a.labelAtomID() == "CA") seen |= 1; if (a.labelAtomID() == "CA")
else if (a.labelAtomID() == "C") seen |= 2; seen |= 1;
else if (a.labelAtomID() == "N") seen |= 4; else if (a.labelAtomID() == "C")
else if (a.labelAtomID() == "O") seen |= 8; seen |= 2;
else if (a.labelAtomID() == "N")
seen |= 4;
else if (a.labelAtomID() == "O")
seen |= 8;
// else if (a.labelAtomID() == "OXT") seen |= 16; // else if (a.labelAtomID() == "OXT") seen |= 16;
} }
return seen == 15; return seen == 15;
...@@ -1402,7 +1442,7 @@ bool Monomer::isComplete() const ...@@ -1402,7 +1442,7 @@ bool Monomer::isComplete() const
bool Monomer::hasAlternateBackboneAtoms() const bool Monomer::hasAlternateBackboneAtoms() const
{ {
bool result; bool result;
for (auto& a: mAtoms) for (auto &a : mAtoms)
{ {
if (not a.isAlternate()) if (not a.isAlternate())
continue; continue;
...@@ -1445,36 +1485,37 @@ float Monomer::chiralVolume() const ...@@ -1445,36 +1485,37 @@ float Monomer::chiralVolume() const
return result; return result;
} }
bool Monomer::areBonded(const Monomer& a, const Monomer& b, float errorMargin) bool Monomer::areBonded(const Monomer &a, const Monomer &b, float errorMargin)
{ {
bool result = false; bool result = false;
try try
{ {
Point atoms[4] = { Point atoms[4] = {
a.atomByID("CA").location(), a.atomByID("CA").location(),
a.atomByID("C").location(), a.atomByID("C").location(),
b.atomByID("N").location(), b.atomByID("N").location(),
b.atomByID("CA").location() b.atomByID("CA").location()};
};
auto distanceCACA = Distance(atoms[0], atoms[3]); auto distanceCACA = Distance(atoms[0], atoms[3]);
double omega = DihedralAngle(atoms[0], atoms[1], atoms[2], atoms[3]); double omega = DihedralAngle(atoms[0], atoms[1], atoms[2], atoms[3]);
bool cis = abs(omega) <= 30.0; bool cis = abs(omega) <= 30.0;
float maxCACADistance = cis ? 3.0 : 3.8; float maxCACADistance = cis ? 3.0 : 3.8;
result = abs(distanceCACA - maxCACADistance) < errorMargin; result = abs(distanceCACA - maxCACADistance) < errorMargin;
} }
catch (...) {} catch (...)
{
}
return result; return result;
} }
float Monomer::omega(const mmcif::Monomer& a, const mmcif::Monomer& b) float Monomer::omega(const mmcif::Monomer &a, const mmcif::Monomer &b)
{ {
float result = 360; float result = 360;
try try
{ {
result = DihedralAngle( result = DihedralAngle(
...@@ -1483,12 +1524,14 @@ float Monomer::omega(const mmcif::Monomer& a, const mmcif::Monomer& b) ...@@ -1483,12 +1524,14 @@ float Monomer::omega(const mmcif::Monomer& a, const mmcif::Monomer& b)
b.atomByID("N").location(), b.atomByID("N").location(),
b.atomByID("CA").location()); b.atomByID("CA").location());
} }
catch (...) {} catch (...)
{
}
return result; return result;
} }
bool Monomer::isCis(const mmcif::Monomer& a, const mmcif::Monomer& b) bool Monomer::isCis(const mmcif::Monomer &a, const mmcif::Monomer &b)
{ {
return omega(a, b) < 30.0f; return omega(a, b) < 30.0f;
} }
...@@ -1507,7 +1550,7 @@ bool Monomer::isCis(const mmcif::Monomer& a, const mmcif::Monomer& b) ...@@ -1507,7 +1550,7 @@ bool Monomer::isCis(const mmcif::Monomer& a, const mmcif::Monomer& b)
// std::string asymID, monID; // std::string asymID, monID;
// cif::tie(asymID, seqID, monID) = // cif::tie(asymID, seqID, monID) =
// polySeq[mIndex].get("asym_id", "seq_id", "mon_id"); // polySeq[mIndex].get("asym_id", "seq_id", "mon_id");
// //
// mCurrent = Monomer(*mPolymer, index, seqID, monID, ""); // mCurrent = Monomer(*mPolymer, index, seqID, monID, "");
// } // }
//} //}
...@@ -1519,12 +1562,12 @@ bool Monomer::isCis(const mmcif::Monomer& a, const mmcif::Monomer& b) ...@@ -1519,12 +1562,12 @@ bool Monomer::isCis(const mmcif::Monomer& a, const mmcif::Monomer& b)
// //
// std::string compoundID; // std::string compoundID;
// int seqID; // int seqID;
// //
// auto r = mPolySeq[index]; // auto r = mPolySeq[index];
// //
// cif::tie(seqID, compoundID) = // cif::tie(seqID, compoundID) =
// r.get("seq_id", "mon_id"); // r.get("seq_id", "mon_id");
// //
// return Monomer(const_cast<Polymer&>(*this), index, seqID, compoundID, ""); // return Monomer(const_cast<Polymer&>(*this), index, seqID, compoundID, "");
//} //}
// //
...@@ -1546,10 +1589,10 @@ bool Monomer::isCis(const mmcif::Monomer& a, const mmcif::Monomer& b) ...@@ -1546,10 +1589,10 @@ bool Monomer::isCis(const mmcif::Monomer& a, const mmcif::Monomer& b)
// std::string asymID, monID; // std::string asymID, monID;
// cif::tie(asymID, seqID, monID) = // cif::tie(asymID, seqID, monID) =
// polySeq[mIndex].get("asym_id", "seq_id", "mon_id"); // polySeq[mIndex].get("asym_id", "seq_id", "mon_id");
// //
// mCurrent = Monomer(*mPolymer, mIndex, seqID, monID, ""); // mCurrent = Monomer(*mPolymer, mIndex, seqID, monID, "");
// } // }
// //
// return *this; // return *this;
//} //}
...@@ -1563,7 +1606,7 @@ bool Monomer::isCis(const mmcif::Monomer& a, const mmcif::Monomer& b) ...@@ -1563,7 +1606,7 @@ bool Monomer::isCis(const mmcif::Monomer& a, const mmcif::Monomer& b)
// for (auto r: mPolySeq) // for (auto r: mPolySeq)
// assert(r["entity_id"] == mEntityID); // assert(r["entity_id"] == mEntityID);
//#endif //#endif
// //
//} //}
//Polymer::Polymer(Polymer&& rhs) //Polymer::Polymer(Polymer&& rhs)
...@@ -1584,22 +1627,24 @@ bool Monomer::isCis(const mmcif::Monomer& a, const mmcif::Monomer& b) ...@@ -1584,22 +1627,24 @@ bool Monomer::isCis(const mmcif::Monomer& a, const mmcif::Monomer& b)
// return *this; // return *this;
//} //}
Polymer::Polymer(const Structure& s, const std::string& entityID, const std::string& asymID) Polymer::Polymer(const Structure &s, const std::string &entityID, const std::string &asymID)
: mStructure(const_cast<Structure*>(&s)), mEntityID(entityID), mAsymID(asymID) : mStructure(const_cast<Structure *>(&s))
, mEntityID(entityID)
, mAsymID(asymID)
, mPolySeq(s.category("pdbx_poly_seq_scheme"), cif::Key("asym_id") == mAsymID and cif::Key("entity_id") == mEntityID) , mPolySeq(s.category("pdbx_poly_seq_scheme"), cif::Key("asym_id") == mAsymID and cif::Key("entity_id") == mEntityID)
{ {
std::map<uint32_t,uint32_t> ix; std::map<uint32_t, uint32_t> ix;
reserve(mPolySeq.size()); reserve(mPolySeq.size());
for (auto r: mPolySeq) for (auto r : mPolySeq)
{ {
int seqID; int seqID;
std::string compoundID; std::string compoundID;
cif::tie(seqID, compoundID) = r.get("seq_id", "mon_id"); cif::tie(seqID, compoundID) = r.get("seq_id", "mon_id");
uint32_t index = size(); uint32_t index = size();
// store only the first // store only the first
if (not ix.count(seqID)) if (not ix.count(seqID))
{ {
...@@ -1619,34 +1664,34 @@ std::string Polymer::chainID() const ...@@ -1619,34 +1664,34 @@ std::string Polymer::chainID() const
return mPolySeq.front()["pdb_strand_id"].as<std::string>(); return mPolySeq.front()["pdb_strand_id"].as<std::string>();
} }
Monomer& Polymer::getBySeqID(int seqID) Monomer &Polymer::getBySeqID(int seqID)
{ {
for (auto& m: *this) for (auto &m : *this)
if (m.seqID() == seqID) if (m.seqID() == seqID)
return m; return m;
throw std::runtime_error("Monomer with seqID " + std::to_string(seqID) + " not found in polymer " + mAsymID); throw std::runtime_error("Monomer with seqID " + std::to_string(seqID) + " not found in polymer " + mAsymID);
} }
const Monomer& Polymer::getBySeqID(int seqID) const const Monomer &Polymer::getBySeqID(int seqID) const
{ {
for (auto& m: *this) for (auto &m : *this)
if (m.seqID() == seqID) if (m.seqID() == seqID)
return m; return m;
throw std::runtime_error("Monomer with seqID " + std::to_string(seqID) + " not found in polymer " + mAsymID); throw std::runtime_error("Monomer with seqID " + std::to_string(seqID) + " not found in polymer " + mAsymID);
} }
int Polymer::Distance(const Monomer& a, const Monomer& b) const int Polymer::Distance(const Monomer &a, const Monomer &b) const
{ {
int result = std::numeric_limits<int>::max(); int result = std::numeric_limits<int>::max();
if (a.asymID() == b.asymID()) if (a.asymID() == b.asymID())
{ {
int ixa = std::numeric_limits<int>::max(), ixb = std::numeric_limits<int>::max(); int ixa = std::numeric_limits<int>::max(), ixb = std::numeric_limits<int>::max();
int ix = 0, f = 0; int ix = 0, f = 0;
for (auto& m: *this) for (auto &m : *this)
{ {
if (m.seqID() == a.seqID()) if (m.seqID() == a.seqID())
ixa = ix, ++f; ixa = ix, ++f;
...@@ -1671,13 +1716,13 @@ File::File() ...@@ -1671,13 +1716,13 @@ File::File()
{ {
} }
File::File(const char* data, size_t length) File::File(const char *data, size_t length)
: mImpl(new FileImpl) : mImpl(new FileImpl)
{ {
mImpl->load_data(data, length); mImpl->load_data(data, length);
} }
File::File(const std::string& File) File::File(const std::string &File)
: mImpl(new FileImpl) : mImpl(new FileImpl)
{ {
load(File); load(File);
...@@ -1688,47 +1733,48 @@ File::~File() ...@@ -1688,47 +1733,48 @@ File::~File()
delete mImpl; delete mImpl;
} }
void File::load(const std::string& p) void File::load(const std::string &p)
{ {
mImpl->load(p); mImpl->load(p);
} }
void File::save(const std::string& file) void File::save(const std::string &file)
{ {
mImpl->save(file); mImpl->save(file);
} }
cif::Datablock& File::data() cif::Datablock &File::data()
{ {
assert(mImpl); assert(mImpl);
assert(mImpl->mDb); assert(mImpl->mDb);
if (mImpl == nullptr or mImpl->mDb == nullptr) if (mImpl == nullptr or mImpl->mDb == nullptr)
throw std::runtime_error("No data loaded"); throw std::runtime_error("No data loaded");
return *mImpl->mDb; return *mImpl->mDb;
} }
cif::File& File::file() cif::File &File::file()
{ {
assert(mImpl); assert(mImpl);
if (mImpl == nullptr) if (mImpl == nullptr)
throw std::runtime_error("No data loaded"); throw std::runtime_error("No data loaded");
return mImpl->mData; return mImpl->mData;
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// Structure // Structure
Structure::Structure(File& f, uint32_t modelNr, StructureOpenOptions options) Structure::Structure(File &f, uint32_t modelNr, StructureOpenOptions options)
: mFile(f), mModelNr(modelNr) : mFile(f)
, mModelNr(modelNr)
{ {
auto& db = *mFile.impl().mDb; auto &db = *mFile.impl().mDb;
auto& atomCat = db["atom_site"]; auto &atomCat = db["atom_site"];
for (auto& a: atomCat) for (auto &a : atomCat)
{ {
std::string id, typeSymbol; std::string id, typeSymbol;
std::optional<uint32_t> modelNr; std::optional<uint32_t> modelNr;
...@@ -1737,23 +1783,24 @@ Structure::Structure(File& f, uint32_t modelNr, StructureOpenOptions options) ...@@ -1737,23 +1783,24 @@ Structure::Structure(File& f, uint32_t modelNr, StructureOpenOptions options)
if (modelNr and *modelNr != mModelNr) if (modelNr and *modelNr != mModelNr)
continue; continue;
if ((options bitand StructureOpenOptions::SkipHydrogen) and typeSymbol == "H") if ((options bitand StructureOpenOptions::SkipHydrogen) and typeSymbol == "H")
continue; continue;
mAtoms.emplace_back(new AtomImpl(f, id, a)); mAtoms.emplace_back(new AtomImpl(f, id, a));
} }
loadData(); loadData();
} }
Structure::Structure(const Structure& s) Structure::Structure(const Structure &s)
: mFile(s.mFile), mModelNr(s.mModelNr) : mFile(s.mFile)
, mModelNr(s.mModelNr)
{ {
mAtoms.reserve(s.mAtoms.size()); mAtoms.reserve(s.mAtoms.size());
for (auto& atom: s.mAtoms) for (auto &atom : s.mAtoms)
mAtoms.emplace_back(atom.clone()); mAtoms.emplace_back(atom.clone());
loadData(); loadData();
} }
...@@ -1765,40 +1812,40 @@ void Structure::loadData() ...@@ -1765,40 +1812,40 @@ void Structure::loadData()
{ {
updateAtomIndex(); updateAtomIndex();
auto& polySeqScheme = category("pdbx_poly_seq_scheme"); auto &polySeqScheme = category("pdbx_poly_seq_scheme");
for (auto& r: polySeqScheme) for (auto &r : polySeqScheme)
{ {
std::string asymID, entityID, seqID, monID; std::string asymID, entityID, seqID, monID;
cif::tie(asymID, entityID, seqID, monID) = cif::tie(asymID, entityID, seqID, monID) =
r.get("asym_id", "entity_id", "seq_id", "mon_id"); r.get("asym_id", "entity_id", "seq_id", "mon_id");
if (mPolymers.empty() or mPolymers.back().asymID() != asymID or mPolymers.back().entityID() != entityID) if (mPolymers.empty() or mPolymers.back().asymID() != asymID or mPolymers.back().entityID() != entityID)
mPolymers.emplace_back(*this, entityID, asymID); mPolymers.emplace_back(*this, entityID, asymID);
} }
auto& nonPolyScheme = category("pdbx_nonpoly_scheme"); auto &nonPolyScheme = category("pdbx_nonpoly_scheme");
for (auto& r: nonPolyScheme) for (auto &r : nonPolyScheme)
{ {
std::string asymID, monID, pdbSeqNum; std::string asymID, monID, pdbSeqNum;
cif::tie(asymID, monID, pdbSeqNum) = cif::tie(asymID, monID, pdbSeqNum) =
r.get("asym_id", "mon_id", "pdb_seq_num"); r.get("asym_id", "mon_id", "pdb_seq_num");
if (monID == "HOH") if (monID == "HOH")
mNonPolymers.emplace_back(*this, monID, asymID, pdbSeqNum); mNonPolymers.emplace_back(*this, monID, asymID, pdbSeqNum);
else if (mNonPolymers.empty() or mNonPolymers.back().asymID() != asymID) else if (mNonPolymers.empty() or mNonPolymers.back().asymID() != asymID)
mNonPolymers.emplace_back(*this, monID, asymID); mNonPolymers.emplace_back(*this, monID, asymID);
} }
auto& branchScheme = category("pdbx_branch_scheme"); auto &branchScheme = category("pdbx_branch_scheme");
for (auto& r: branchScheme) for (auto &r : branchScheme)
{ {
std::string asymID, monID, num; std::string asymID, monID, num;
cif::tie(asymID, monID, num) = cif::tie(asymID, monID, num) =
r.get("asym_id", "mon_id", "num"); r.get("asym_id", "mon_id", "num");
mBranchResidues.emplace_back(*this, monID, asymID, num); mBranchResidues.emplace_back(*this, monID, asymID, num);
} }
} }
...@@ -1806,18 +1853,18 @@ void Structure::loadData() ...@@ -1806,18 +1853,18 @@ void Structure::loadData()
void Structure::updateAtomIndex() void Structure::updateAtomIndex()
{ {
mAtomIndex = std::vector<size_t>(mAtoms.size()); mAtomIndex = std::vector<size_t>(mAtoms.size());
iota(mAtomIndex.begin(), mAtomIndex.end(), 0); iota(mAtomIndex.begin(), mAtomIndex.end(), 0);
sort(mAtomIndex.begin(), mAtomIndex.end(), [this](size_t a, size_t b) { return mAtoms[a].id() < mAtoms[b].id(); }); sort(mAtomIndex.begin(), mAtomIndex.end(), [this](size_t a, size_t b) { return mAtoms[a].id() < mAtoms[b].id(); });
} }
void Structure::sortAtoms() void Structure::sortAtoms()
{ {
sort(mAtoms.begin(), mAtoms.end(), [](auto& a, auto& b) { return a.compare(b) < 0; }); sort(mAtoms.begin(), mAtoms.end(), [](auto &a, auto &b) { return a.compare(b) < 0; });
int id = 1; int id = 1;
for (auto& atom: mAtoms) for (auto &atom : mAtoms)
{ {
atom.setID(id); atom.setID(id);
++id; ++id;
...@@ -1829,13 +1876,13 @@ void Structure::sortAtoms() ...@@ -1829,13 +1876,13 @@ void Structure::sortAtoms()
AtomView Structure::waters() const AtomView Structure::waters() const
{ {
AtomView result; AtomView result;
auto& db = datablock(); auto &db = datablock();
// Get the entity id for water // Get the entity id for water
auto& entityCat = db["entity"]; auto &entityCat = db["entity"];
std::string waterEntityID; std::string waterEntityID;
for (auto& e: entityCat) for (auto &e : entityCat)
{ {
std::string id, type; std::string id, type;
cif::tie(id, type) = e.get("id", "type"); cif::tie(id, type) = e.get("id", "type");
...@@ -1846,22 +1893,22 @@ AtomView Structure::waters() const ...@@ -1846,22 +1893,22 @@ AtomView Structure::waters() const
} }
} }
for (auto& a: mAtoms) for (auto &a : mAtoms)
{ {
if (a.property<std::string>("label_entity_id") == waterEntityID) if (a.property<std::string>("label_entity_id") == waterEntityID)
result.push_back(a); result.push_back(a);
} }
return result; return result;
} }
Atom Structure::getAtomByID(std::string id) const Atom Structure::getAtomByID(std::string id) const
{ {
auto i = std::lower_bound(mAtomIndex.begin(), mAtomIndex.end(), auto i = std::lower_bound(mAtomIndex.begin(), mAtomIndex.end(),
id, [this](auto& a, auto& b) { return mAtoms[a].id() < b; }); id, [this](auto &a, auto &b) { return mAtoms[a].id() < b; });
// auto i = find_if(mAtoms.begin(), mAtoms.end(), // auto i = find_if(mAtoms.begin(), mAtoms.end(),
// [&id](auto& a) { return a.id() == id; }); // [&id](auto& a) { return a.id() == id; });
if (i == mAtomIndex.end() or mAtoms[*i].id() != id) if (i == mAtomIndex.end() or mAtoms[*i].id() != id)
throw std::out_of_range("Could not find atom with id " + id); throw std::out_of_range("Could not find atom with id " + id);
...@@ -1869,9 +1916,9 @@ Atom Structure::getAtomByID(std::string id) const ...@@ -1869,9 +1916,9 @@ Atom Structure::getAtomByID(std::string id) const
return mAtoms[*i]; return mAtoms[*i];
} }
Atom Structure::getAtomByLabel(const std::string& atomID, const std::string& asymID, const std::string& compID, int seqID, const std::string& altID) Atom Structure::getAtomByLabel(const std::string &atomID, const std::string &asymID, const std::string &compID, int seqID, const std::string &altID)
{ {
for (auto& a: mAtoms) for (auto &a : mAtoms)
{ {
if (a.labelAtomID() == atomID and if (a.labelAtomID() == atomID and
a.labelAsymID() == asymID and a.labelAsymID() == asymID and
...@@ -1886,14 +1933,14 @@ Atom Structure::getAtomByLabel(const std::string& atomID, const std::string& asy ...@@ -1886,14 +1933,14 @@ Atom Structure::getAtomByLabel(const std::string& atomID, const std::string& asy
throw std::out_of_range("Could not find atom with specified label"); throw std::out_of_range("Could not find atom with specified label");
} }
const Residue& Structure::getResidue(const std::string& asymID, const std::string& compID, int seqID) const const Residue &Structure::getResidue(const std::string &asymID, const std::string &compID, int seqID) const
{ {
for (auto& poly: mPolymers) for (auto &poly : mPolymers)
{ {
if (poly.asymID() != asymID) if (poly.asymID() != asymID)
continue; continue;
for (auto& res: poly) for (auto &res : poly)
{ {
if (res.seqID() == seqID and res.compoundID() == compID) if (res.seqID() == seqID and res.compoundID() == compID)
return res; return res;
...@@ -1902,7 +1949,7 @@ const Residue& Structure::getResidue(const std::string& asymID, const std::strin ...@@ -1902,7 +1949,7 @@ const Residue& Structure::getResidue(const std::string& asymID, const std::strin
if (seqID == 0) if (seqID == 0)
{ {
for (auto& res: mNonPolymers) for (auto &res : mNonPolymers)
{ {
if (res.asymID() != asymID or res.compoundID() != compID) if (res.asymID() != asymID or res.compoundID() != compID)
continue; continue;
...@@ -1911,43 +1958,43 @@ const Residue& Structure::getResidue(const std::string& asymID, const std::strin ...@@ -1911,43 +1958,43 @@ const Residue& Structure::getResidue(const std::string& asymID, const std::strin
} }
} }
for (auto& res: mBranchResidues) for (auto &res : mBranchResidues)
{ {
if (res.asymID() != asymID or res.compoundID() != compID or res.seqID() != seqID) if (res.asymID() != asymID or res.compoundID() != compID or res.seqID() != seqID)
continue; continue;
return res; return res;
} }
throw std::out_of_range("Could not find residue " + asymID + '/' + std::to_string(seqID)); throw std::out_of_range("Could not find residue " + asymID + '/' + std::to_string(seqID));
} }
File& Structure::getFile() const File &Structure::getFile() const
{ {
return mFile; return mFile;
} }
cif::Category& Structure::category(const char* name) const cif::Category &Structure::category(const char *name) const
{ {
auto& db = datablock(); auto &db = datablock();
return db[name]; return db[name];
} }
std::tuple<char,int,char> Structure::MapLabelToAuth( std::tuple<char, int, char> Structure::MapLabelToAuth(
const std::string& asymID, int seqID) const const std::string &asymID, int seqID) const
{ {
auto& db = *getFile().impl().mDb; auto &db = *getFile().impl().mDb;
std::tuple<char,int,char> result; std::tuple<char, int, char> result;
bool found = false; bool found = false;
for (auto r: db["pdbx_poly_seq_scheme"].find( for (auto r : db["pdbx_poly_seq_scheme"].find(
cif::Key("asym_id") == asymID and cif::Key("asym_id") == asymID and
cif::Key("seq_id") == seqID)) cif::Key("seq_id") == seqID))
{ {
std::string auth_asym_id, pdb_ins_code; std::string auth_asym_id, pdb_ins_code;
int pdb_seq_num; int pdb_seq_num;
cif::tie(auth_asym_id, pdb_seq_num, pdb_ins_code) = cif::tie(auth_asym_id, pdb_seq_num, pdb_ins_code) =
r.get("pdb_strand_id", "pdb_seq_num", "pdb_ins_code"); r.get("pdb_strand_id", "pdb_seq_num", "pdb_ins_code");
...@@ -1965,13 +2012,13 @@ std::tuple<char,int,char> Structure::MapLabelToAuth( ...@@ -1965,13 +2012,13 @@ std::tuple<char,int,char> Structure::MapLabelToAuth(
{ {
std::string pdb_strand_id, pdb_ins_code; std::string pdb_strand_id, pdb_ins_code;
int pdb_seq_num; int pdb_seq_num;
cif::tie(pdb_strand_id, pdb_seq_num, pdb_ins_code) = cif::tie(pdb_strand_id, pdb_seq_num, pdb_ins_code) =
r.front().get("pdb_strand_id", "pdb_seq_num", "pdb_ins_code"); r.front().get("pdb_strand_id", "pdb_seq_num", "pdb_ins_code");
result = std::make_tuple(pdb_strand_id.front(), pdb_seq_num, result = std::make_tuple(pdb_strand_id.front(), pdb_seq_num,
pdb_ins_code.empty() ? ' ' : pdb_ins_code.front()); pdb_ins_code.empty() ? ' ' : pdb_ins_code.front());
found = true; found = true;
} }
} }
...@@ -1979,20 +2026,20 @@ std::tuple<char,int,char> Structure::MapLabelToAuth( ...@@ -1979,20 +2026,20 @@ std::tuple<char,int,char> Structure::MapLabelToAuth(
return result; return result;
} }
std::tuple<std::string,int,std::string,std::string> Structure::MapLabelToPDB( std::tuple<std::string, int, std::string, std::string> Structure::MapLabelToPDB(
const std::string& asymID, int seqID, const std::string& monID, const std::string &asymID, int seqID, const std::string &monID,
const std::string& authSeqID) const const std::string &authSeqID) const
{ {
auto& db = datablock(); auto &db = datablock();
std::tuple<std::string,int,std::string,std::string> result; std::tuple<std::string, int, std::string, std::string> result;
if (monID == "HOH") if (monID == "HOH")
{ {
for (auto r: db["pdbx_nonpoly_scheme"].find( for (auto r : db["pdbx_nonpoly_scheme"].find(
cif::Key("asym_id") == asymID and cif::Key("asym_id") == asymID and
cif::Key("pdb_seq_num") == authSeqID and cif::Key("pdb_seq_num") == authSeqID and
cif::Key("mon_id") == monID)) cif::Key("mon_id") == monID))
{ {
result = r.get("pdb_strand_id", "pdb_seq_num", "pdb_mon_id", "pdb_ins_code"); result = r.get("pdb_strand_id", "pdb_seq_num", "pdb_mon_id", "pdb_ins_code");
break; break;
...@@ -2000,18 +2047,18 @@ std::tuple<std::string,int,std::string,std::string> Structure::MapLabelToPDB( ...@@ -2000,18 +2047,18 @@ std::tuple<std::string,int,std::string,std::string> Structure::MapLabelToPDB(
} }
else else
{ {
for (auto r: db["pdbx_poly_seq_scheme"].find( for (auto r : db["pdbx_poly_seq_scheme"].find(
cif::Key("asym_id") == asymID and cif::Key("asym_id") == asymID and
cif::Key("seq_id") == seqID and cif::Key("seq_id") == seqID and
cif::Key("mon_id") == monID)) cif::Key("mon_id") == monID))
{ {
result = r.get("pdb_strand_id", "pdb_seq_num", "pdb_mon_id", "pdb_ins_code"); result = r.get("pdb_strand_id", "pdb_seq_num", "pdb_mon_id", "pdb_ins_code");
break; break;
} }
for (auto r: db["pdbx_nonpoly_scheme"].find( for (auto r : db["pdbx_nonpoly_scheme"].find(
cif::Key("asym_id") == asymID and cif::Key("asym_id") == asymID and
cif::Key("mon_id") == monID)) cif::Key("mon_id") == monID))
{ {
result = r.get("pdb_strand_id", "pdb_seq_num", "pdb_mon_id", "pdb_ins_code"); result = r.get("pdb_strand_id", "pdb_seq_num", "pdb_mon_id", "pdb_ins_code");
break; break;
...@@ -2021,53 +2068,52 @@ std::tuple<std::string,int,std::string,std::string> Structure::MapLabelToPDB( ...@@ -2021,53 +2068,52 @@ std::tuple<std::string,int,std::string,std::string> Structure::MapLabelToPDB(
return result; return result;
} }
std::tuple<std::string,int,std::string> Structure::MapPDBToLabel(const std::string& asymID, int seqID, std::tuple<std::string, int, std::string> Structure::MapPDBToLabel(const std::string &asymID, int seqID,
const std::string& compID, const std::string& iCode) const const std::string &compID, const std::string &iCode) const
{ {
auto& db = datablock(); auto &db = datablock();
std::tuple<std::string,int,std::string> result; std::tuple<std::string, int, std::string> result;
if (iCode.empty()) if (iCode.empty())
{ {
for (auto r: db["pdbx_poly_seq_scheme"].find( for (auto r : db["pdbx_poly_seq_scheme"].find(
cif::Key("pdb_strand_id") == asymID and cif::Key("pdb_strand_id") == asymID and
cif::Key("pdb_seq_num") == seqID and cif::Key("pdb_seq_num") == seqID and
cif::Key("pdb_mon_id") == compID and cif::Key("pdb_mon_id") == compID and
cif::Key("pdb_ins_code") == cif::Empty())) cif::Key("pdb_ins_code") == cif::Empty()))
{ {
result = r.get("asym_id", "seq_id", "mon_id"); result = r.get("asym_id", "seq_id", "mon_id");
break; break;
} }
for (auto r: db["pdbx_nonpoly_scheme"].find( for (auto r : db["pdbx_nonpoly_scheme"].find(
cif::Key("pdb_strand_id") == asymID and cif::Key("pdb_strand_id") == asymID and
cif::Key("pdb_seq_num") == seqID and cif::Key("pdb_seq_num") == seqID and
cif::Key("pdb_mon_id") == compID and cif::Key("pdb_mon_id") == compID and
cif::Key("pdb_ins_code") == cif::Empty())) cif::Key("pdb_ins_code") == cif::Empty()))
{ {
result = r.get("asym_id", "ndb_seq_num", "mon_id"); result = r.get("asym_id", "ndb_seq_num", "mon_id");
break; break;
} }
} }
else else
{ {
for (auto r: db["pdbx_poly_seq_scheme"].find( for (auto r : db["pdbx_poly_seq_scheme"].find(
cif::Key("pdb_strand_id") == asymID and cif::Key("pdb_strand_id") == asymID and
cif::Key("pdb_seq_num") == seqID and cif::Key("pdb_seq_num") == seqID and
cif::Key("pdb_mon_id") == compID and cif::Key("pdb_mon_id") == compID and
cif::Key("pdb_ins_code") == iCode)) cif::Key("pdb_ins_code") == iCode))
{ {
result = r.get("asym_id", "seq_id", "mon_id"); result = r.get("asym_id", "seq_id", "mon_id");
break; break;
} }
for (auto r: db["pdbx_nonpoly_scheme"].find( for (auto r : db["pdbx_nonpoly_scheme"].find(
cif::Key("pdb_strand_id") == asymID and cif::Key("pdb_strand_id") == asymID and
cif::Key("pdb_seq_num") == seqID and cif::Key("pdb_seq_num") == seqID and
cif::Key("pdb_mon_id") == compID and cif::Key("pdb_mon_id") == compID and
cif::Key("pdb_ins_code") == iCode)) cif::Key("pdb_ins_code") == iCode))
{ {
result = r.get("asym_id", "ndb_seq_num", "mon_id"); result = r.get("asym_id", "ndb_seq_num", "mon_id");
break; break;
...@@ -2077,52 +2123,46 @@ std::tuple<std::string,int,std::string> Structure::MapPDBToLabel(const std::stri ...@@ -2077,52 +2123,46 @@ std::tuple<std::string,int,std::string> Structure::MapPDBToLabel(const std::stri
return result; return result;
} }
cif::Datablock& Structure::datablock() const cif::Datablock &Structure::datablock() const
{ {
return *mFile.impl().mDb; return *mFile.impl().mDb;
} }
void Structure::insertCompound(const std::string& compoundID, bool isEntity) void Structure::insertCompound(const std::string &compoundID, bool isEntity)
{ {
auto compound = Compound::create(compoundID); auto compound = CompoundFactory::instance().create(compoundID);
if (compound == nullptr) if (compound == nullptr)
throw std::runtime_error("Trying to insert unknown compound " + compoundID + " (not found in CCD)"); throw std::runtime_error("Trying to insert unknown compound " + compoundID + " (not found in CCD)");
cif::Datablock& db = *mFile.impl().mDb; cif::Datablock &db = *mFile.impl().mDb;
auto& chemComp = db["chem_comp"]; auto &chemComp = db["chem_comp"];
auto r = chemComp.find(cif::Key("id") == compoundID); auto r = chemComp.find(cif::Key("id") == compoundID);
if (r.empty()) if (r.empty())
{ {
chemComp.emplace({ chemComp.emplace({{"id", compoundID},
{ "id", compoundID }, {"name", compound->name()},
{ "name", compound->name() }, {"formula", compound->formula()},
{ "formula", compound->formula() }, {"formula_weight", compound->formulaWeight()},
{ "formula_weight", compound->formulaWeight() }, {"type", compound->type()}});
{ "type", compound->type() }
});
} }
if (isEntity) if (isEntity)
{ {
auto& pdbxEntityNonpoly = db["pdbx_entity_nonpoly"]; auto &pdbxEntityNonpoly = db["pdbx_entity_nonpoly"];
if (not pdbxEntityNonpoly.exists(cif::Key("comp_id") == compoundID)) if (not pdbxEntityNonpoly.exists(cif::Key("comp_id") == compoundID))
{ {
auto& entity = db["entity"]; auto &entity = db["entity"];
std::string entityID = std::to_string(entity.size() + 1); std::string entityID = std::to_string(entity.size() + 1);
entity.emplace({ entity.emplace({{"id", entityID},
{ "id", entityID }, {"type", "non-polymer"},
{ "type", "non-polymer" }, {"pdbx_description", compound->name()},
{ "pdbx_description", compound->name() }, {"formula_weight", compound->formulaWeight()}});
{ "formula_weight", compound->formulaWeight() }
}); pdbxEntityNonpoly.emplace({{"entity_id", entityID},
{"name", compound->name()},
pdbxEntityNonpoly.emplace({ {"comp_id", compoundID}});
{ "entity_id", entityID },
{ "name", compound->name() },
{ "comp_id", compoundID }
});
} }
} }
} }
...@@ -2151,7 +2191,7 @@ void Structure::insertCompound(const std::string& compoundID, bool isEntity) ...@@ -2151,7 +2191,7 @@ void Structure::insertCompound(const std::string& compoundID, bool isEntity)
// else // else
// return &mStructure.mNonPolymers[mNonPolyIndex]; // return &mStructure.mNonPolymers[mNonPolyIndex];
// } // }
// Structure::residue_iterator& Structure::residue_iterator::operator++() // Structure::residue_iterator& Structure::residue_iterator::operator++()
// { // {
// if (mPolyIter != mStructure.mPolymers.end()) // if (mPolyIter != mStructure.mPolymers.end())
...@@ -2165,7 +2205,7 @@ void Structure::insertCompound(const std::string& compoundID, bool isEntity) ...@@ -2165,7 +2205,7 @@ void Structure::insertCompound(const std::string& compoundID, bool isEntity)
// } // }
// else // else
// ++mNonPolyIndex; // ++mNonPolyIndex;
// return *this; // return *this;
// } // }
...@@ -2175,7 +2215,7 @@ void Structure::insertCompound(const std::string& compoundID, bool isEntity) ...@@ -2175,7 +2215,7 @@ void Structure::insertCompound(const std::string& compoundID, bool isEntity)
// operator++(); // operator++();
// return result; // return result;
// } // }
// bool Structure::residue_iterator::operator==(const Structure::residue_iterator& rhs) const // bool Structure::residue_iterator::operator==(const Structure::residue_iterator& rhs) const
// { // {
// return mPolyIter == rhs.mPolyIter and mPolyResIndex == rhs.mPolyResIndex and mNonPolyIndex == rhs.mNonPolyIndex; // return mPolyIter == rhs.mPolyIter and mPolyResIndex == rhs.mPolyResIndex and mNonPolyIndex == rhs.mNonPolyIndex;
...@@ -2188,50 +2228,50 @@ void Structure::insertCompound(const std::string& compoundID, bool isEntity) ...@@ -2188,50 +2228,50 @@ void Structure::insertCompound(const std::string& compoundID, bool isEntity)
// -------------------------------------------------------------------- // --------------------------------------------------------------------
void Structure::removeAtom(Atom& a) void Structure::removeAtom(Atom &a)
{ {
cif::Datablock& db = *mFile.impl().mDb; cif::Datablock &db = *mFile.impl().mDb;
auto& atomSites = db["atom_site"]; auto &atomSites = db["atom_site"];
for (auto i = atomSites.begin(); i != atomSites.end(); ++i) for (auto i = atomSites.begin(); i != atomSites.end(); ++i)
{ {
std::string id; std::string id;
cif::tie(id) = i->get("id"); cif::tie(id) = i->get("id");
if (id == a.id()) if (id == a.id())
{ {
atomSites.erase(i); atomSites.erase(i);
break; break;
} }
} }
mAtoms.erase(remove(mAtoms.begin(), mAtoms.end(), a), mAtoms.end()); mAtoms.erase(remove(mAtoms.begin(), mAtoms.end(), a), mAtoms.end());
updateAtomIndex(); updateAtomIndex();
} }
void Structure::swapAtoms(Atom& a1, Atom& a2) void Structure::swapAtoms(Atom &a1, Atom &a2)
{ {
cif::Datablock& db = *mFile.impl().mDb; cif::Datablock &db = *mFile.impl().mDb;
auto& atomSites = db["atom_site"]; auto &atomSites = db["atom_site"];
auto rs1 = atomSites.find(cif::Key("id") == a1.id()); auto rs1 = atomSites.find(cif::Key("id") == a1.id());
auto rs2 = atomSites.find(cif::Key("id") == a2.id()); auto rs2 = atomSites.find(cif::Key("id") == a2.id());
if (rs1.size() != 1) if (rs1.size() != 1)
throw std::runtime_error("Cannot swap atoms since the number of atoms with id " + a1.id() + " is " + std::to_string(rs1.size())); throw std::runtime_error("Cannot swap atoms since the number of atoms with id " + a1.id() + " is " + std::to_string(rs1.size()));
if (rs2.size() != 1) if (rs2.size() != 1)
throw std::runtime_error("Cannot swap atoms since the number of atoms with id " + a2.id() + " is " + std::to_string(rs2.size())); throw std::runtime_error("Cannot swap atoms since the number of atoms with id " + a2.id() + " is " + std::to_string(rs2.size()));
auto r1 = rs1.front(); auto r1 = rs1.front();
auto r2 = rs2.front(); auto r2 = rs2.front();
auto l1 = r1["label_atom_id"]; auto l1 = r1["label_atom_id"];
auto l2 = r2["label_atom_id"]; auto l2 = r2["label_atom_id"];
l1.swap(l2); l1.swap(l2);
a1.impl()->swapAtomLabels(*a2.impl()); a1.impl()->swapAtomLabels(*a2.impl());
auto l3 = r1["auth_atom_id"]; auto l3 = r1["auth_atom_id"];
...@@ -2239,20 +2279,20 @@ void Structure::swapAtoms(Atom& a1, Atom& a2) ...@@ -2239,20 +2279,20 @@ void Structure::swapAtoms(Atom& a1, Atom& a2)
l3.swap(l4); l3.swap(l4);
} }
void Structure::moveAtom(Atom& a, Point p) void Structure::moveAtom(Atom &a, Point p)
{ {
a.location(p); a.location(p);
} }
void Structure::changeResidue(const Residue& res, const std::string& newCompound, void Structure::changeResidue(const Residue &res, const std::string &newCompound,
const std::vector<std::tuple<std::string,std::string>>& remappedAtoms) const std::vector<std::tuple<std::string, std::string>> &remappedAtoms)
{ {
using namespace cif::literals; using namespace cif::literals;
cif::Datablock& db = *mFile.impl().mDb; cif::Datablock &db = *mFile.impl().mDb;
std::string asymID = res.asymID(); std::string asymID = res.asymID();
const auto compound = Compound::create(newCompound); const auto compound = CompoundFactory::instance().create(newCompound);
if (not compound) if (not compound)
throw std::runtime_error("Unknown compound " + newCompound); throw std::runtime_error("Unknown compound " + newCompound);
...@@ -2267,25 +2307,21 @@ void Structure::changeResidue(const Residue& res, const std::string& newCompound ...@@ -2267,25 +2307,21 @@ void Structure::changeResidue(const Residue& res, const std::string& newCompound
try try
{ {
std::tie(entityID) = entity.find1<std::string>("type"_key == "non-polymer" and "pdbx_description"_key == compound->name(), { "id" }); std::tie(entityID) = entity.find1<std::string>("type"_key == "non-polymer" and "pdbx_description"_key == compound->name(), {"id"});
} }
catch (const std::exception& ex) catch (const std::exception &ex)
{ {
entityID = entity.getUniqueID(""); entityID = entity.getUniqueID("");
entity.emplace({ entity.emplace({{"id", entityID},
{ "id", entityID }, {"type", "non-polymer"},
{ "type", "non-polymer" }, {"pdbx_description", compound->name()},
{ "pdbx_description", compound->name() }, {"formula_weight", compound->formulaWeight()}});
{ "formula_weight", compound->formulaWeight() }
});
} }
auto &pdbxEntityNonpoly = db["pdbx_entity_nonpoly"]; auto &pdbxEntityNonpoly = db["pdbx_entity_nonpoly"];
pdbxEntityNonpoly.emplace({ pdbxEntityNonpoly.emplace({{"entity_id", entityID},
{ "entity_id", entityID }, {"name", compound->name()},
{ "name", compound->name() }, {"comp_id", newCompound}});
{ "comp_id", newCompound }
});
auto &pdbxNonPolyScheme = db["pdbx_nonpoly_scheme"]; auto &pdbxNonPolyScheme = db["pdbx_nonpoly_scheme"];
for (auto &nps : pdbxNonPolyScheme.find("asym_id"_key == asymID)) for (auto &nps : pdbxNonPolyScheme.find("asym_id"_key == asymID))
...@@ -2296,16 +2332,14 @@ void Structure::changeResidue(const Residue& res, const std::string& newCompound ...@@ -2296,16 +2332,14 @@ void Structure::changeResidue(const Residue& res, const std::string& newCompound
} }
// create rest // create rest
auto& chemComp = db["chem_comp"]; auto &chemComp = db["chem_comp"];
if (not chemComp.exists(cif::Key("id") == newCompound)) if (not chemComp.exists(cif::Key("id") == newCompound))
{ {
chemComp.emplace({ chemComp.emplace({{"id", newCompound},
{ "id", newCompound }, {"name", compound->name()},
{ "name", compound->name() }, {"formula", compound->formula()},
{ "formula", compound->formula() }, {"formula_weight", compound->formulaWeight()},
{ "formula_weight", compound->formulaWeight() }, {"type", compound->type()}});
{ "type", compound->type() }
});
} }
// update the struct_asym for the new entity // update the struct_asym for the new entity
...@@ -2314,15 +2348,15 @@ void Structure::changeResidue(const Residue& res, const std::string& newCompound ...@@ -2314,15 +2348,15 @@ void Structure::changeResidue(const Residue& res, const std::string& newCompound
else else
insertCompound(newCompound, false); insertCompound(newCompound, false);
auto& atomSites = db["atom_site"]; auto &atomSites = db["atom_site"];
auto atoms = res.atoms(); auto atoms = res.atoms();
for (auto& a: remappedAtoms) for (auto &a : remappedAtoms)
{ {
std::string a1, a2; std::string a1, a2;
tie(a1, a2) = a; tie(a1, a2) = a;
auto i = find_if(atoms.begin(), atoms.end(), [&](const Atom& a) { return a.labelAtomID() == a1; }); auto i = find_if(atoms.begin(), atoms.end(), [&](const Atom &a) { return a.labelAtomID() == a1; });
if (i == atoms.end()) if (i == atoms.end())
{ {
std::cerr << "Missing atom for atom ID " << a1 << std::endl; std::cerr << "Missing atom for atom ID " << a1 << std::endl;
...@@ -2333,12 +2367,12 @@ void Structure::changeResidue(const Residue& res, const std::string& newCompound ...@@ -2333,12 +2367,12 @@ void Structure::changeResidue(const Residue& res, const std::string& newCompound
if (r.size() != 1) if (r.size() != 1)
continue; continue;
if (a1 != a2) if (a1 != a2)
r.front()["label_atom_id"] = a2; r.front()["label_atom_id"] = a2;
} }
for (auto a: atoms) for (auto a : atoms)
{ {
atomSites.update_value(cif::Key("id") == a.id(), "label_comp_id", newCompound); atomSites.update_value(cif::Key("id") == a.id(), "label_comp_id", newCompound);
atomSites.update_value(cif::Key("id") == a.id(), "auth_comp_id", newCompound); atomSites.update_value(cif::Key("id") == a.id(), "auth_comp_id", newCompound);
...@@ -2349,7 +2383,7 @@ void Structure::cleanupEmptyCategories() ...@@ -2349,7 +2383,7 @@ void Structure::cleanupEmptyCategories()
{ {
using namespace cif::literals; using namespace cif::literals;
cif::Datablock& db = *mFile.impl().mDb; cif::Datablock &db = *mFile.impl().mDb;
auto &atomSite = db["atom_site"]; auto &atomSite = db["atom_site"];
...@@ -2362,7 +2396,7 @@ void Structure::cleanupEmptyCategories() ...@@ -2362,7 +2396,7 @@ void Structure::cleanupEmptyCategories()
std::string compID = chemComp["id"].as<std::string>(); std::string compID = chemComp["id"].as<std::string>();
if (atomSite.exists("label_comp_id"_key == compID or "auth_comp_id"_key == compID)) if (atomSite.exists("label_comp_id"_key == compID or "auth_comp_id"_key == compID))
continue; continue;
obsoleteChemComps.push_back(chemComp); obsoleteChemComps.push_back(chemComp);
} }
...@@ -2379,7 +2413,7 @@ void Structure::cleanupEmptyCategories() ...@@ -2379,7 +2413,7 @@ void Structure::cleanupEmptyCategories()
std::string entityID = entity["id"].as<std::string>(); std::string entityID = entity["id"].as<std::string>();
if (atomSite.exists("label_entity_id"_key == entityID)) if (atomSite.exists("label_entity_id"_key == entityID))
continue; continue;
obsoleteEntities.push_back(entity); obsoleteEntities.push_back(entity);
} }
...@@ -2388,7 +2422,7 @@ void Structure::cleanupEmptyCategories() ...@@ -2388,7 +2422,7 @@ void Structure::cleanupEmptyCategories()
// the rest? // the rest?
for (const char *cat : { "pdbx_entity_nonpoly" }) for (const char *cat : {"pdbx_entity_nonpoly"})
{ {
auto &category = db[cat]; auto &category = db[cat];
...@@ -2404,7 +2438,7 @@ void Structure::cleanupEmptyCategories() ...@@ -2404,7 +2438,7 @@ void Structure::cleanupEmptyCategories()
} }
// count molecules // count molecules
for (auto entity: entities) for (auto entity : entities)
{ {
std::string type, id; std::string type, id;
cif::tie(type, id) = entity.get("type", "id"); cif::tie(type, id) = entity.get("type", "id");
...@@ -2418,14 +2452,13 @@ void Structure::cleanupEmptyCategories() ...@@ -2418,14 +2452,13 @@ void Structure::cleanupEmptyCategories()
{ {
// is this correct? // is this correct?
std::set<std::string> asym_ids; std::set<std::string> asym_ids;
for (const auto &[asym_id] : db["pdbx_branch_scheme"].find<std::string>("entity_id"_key == id, { "asym_id" })) for (const auto &[asym_id] : db["pdbx_branch_scheme"].find<std::string>("entity_id"_key == id, {"asym_id"}))
asym_ids.insert(asym_id); asym_ids.insert(asym_id);
count = asym_ids.size(); count = asym_ids.size();
} }
entity["pdbx_number_of_molecules"] = count; entity["pdbx_number_of_molecules"] = count;
} }
} }
} } // namespace mmcif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment