Commit f5016403 by Maarten L. Hekkelman

refactored mmcif::File

parent c8f66ae6
Version 3.0.5
- mmcif::Structure redesign. It is now a wrapper around a cif::Datablock.
Version 3.0.4
- Fix in mmCIF parser, now correctly handles the unquoted
string ??
......
......@@ -2169,17 +2169,21 @@ class File
File();
File(std::istream &is, bool validate = false);
File(const std::filesystem::path &path, bool validate = false);
File(const char *data, size_t length); // good luck trying to find out what it is...
File(File &&rhs);
File(const File &rhs) = delete;
File &operator=(const File &rhs) = delete;
~File();
virtual ~File();
virtual void load(const std::filesystem::path &p);
virtual void save(const std::filesystem::path &p);
void load(const std::filesystem::path &p);
void save(const std::filesystem::path &p);
virtual void load(std::istream &is);
virtual void save(std::ostream &os);
void load(std::istream &is);
void save(std::ostream &os);
virtual void load(const char *data, std::size_t length);
/// \brief Load only the data block \a datablock from the mmCIF file
void load(std::istream &is, const std::string &datablock);
......@@ -2211,6 +2215,12 @@ class File
void append(Datablock *e);
Datablock &emplace(std::string_view name)
{
append(new Datablock(name));
return back();
}
Datablock *get(std::string_view name) const;
Datablock &operator[](std::string_view name);
......@@ -2248,6 +2258,9 @@ class File
iterator begin() const;
iterator end() const;
Datablock &front();
Datablock &back();
bool empty() const { return mHead == nullptr; }
const Validator &getValidator() const;
......
......@@ -221,7 +221,7 @@ struct PointF
FType length() const
{
return sqrt(mX * mX + mY * mY + mZ * mZ);
return std::sqrt(mX * mX + mY * mY + mZ * mZ);
}
};
......@@ -285,7 +285,7 @@ inline double DistanceSquared(const PointF<F> &a, const PointF<F> &b)
template <typename F>
inline double Distance(const PointF<F> &a, const PointF<F> &b)
{
return sqrt(
return std::sqrt(
(a.mX - b.mX) * (a.mX - b.mX) +
(a.mY - b.mY) * (a.mY - b.mY) +
(a.mZ - b.mZ) * (a.mZ - b.mZ));
......@@ -332,10 +332,10 @@ double DihedralAngle(const PointF<F> &p1, const PointF<F> &p2, const PointF<F> &
double result = 360;
if (u > 0 and v > 0)
{
u = DotProduct(p, x) / sqrt(u);
v = DotProduct(p, y) / sqrt(v);
u = DotProduct(p, x) / std::sqrt(u);
v = DotProduct(p, y) / std::sqrt(v);
if (u != 0 or v != 0)
result = atan2(v, u) * 180 / kPI;
result = std::atan2(v, u) * 180 / kPI;
}
return result;
......@@ -351,7 +351,7 @@ double CosinusAngle(const PointF<F> &p1, const PointF<F> &p2, const PointF<F> &p
double x = DotProduct(v12, v12) * DotProduct(v34, v34);
if (x > 0)
result = DotProduct(v12, v34) / sqrt(x);
result = DotProduct(v12, v34) / std::sqrt(x);
return result;
}
......@@ -436,9 +436,9 @@ class SphericalDots
double lat = std::asin((2.0 * i) / P);
double lon = std::fmod(i, kGoldenRatio) * 2 * kPI / kGoldenRatio;
p->mX = sin(lon) * cos(lat);
p->mY = cos(lon) * cos(lat);
p->mZ = sin(lat);
p->mX = std::sin(lon) * std::cos(lat);
p->mY = std::cos(lon) * std::cos(lat);
p->mZ = std::sin(lat);
++p;
}
......
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
*
* Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
......@@ -34,16 +34,16 @@
#include "cif++/Point.hpp"
/*
To modify a structure, you will have to use actions.
The currently supported actions are:
To modify a structure, you will have to use actions.
The currently supported actions are:
// - Move atom to new location
- Remove atom
- Remove atom
// - Add new atom that was formerly missing
// - Add alternate Residue
-
-
*/
namespace mmcif
......@@ -61,7 +61,6 @@ class File;
class Atom
{
private:
struct AtomImpl : public std::enable_shared_from_this<AtomImpl>
{
AtomImpl(cif::Datablock &db, const std::string &id, cif::Row row);
......@@ -99,7 +98,7 @@ class Atom
int mRefcount;
cif::Row mRow;
mutable std::vector<std::tuple<std::string,cif::detail::ItemReference>> mCachedRefs;
mutable std::vector<std::tuple<std::string, cif::detail::ItemReference>> mCachedRefs;
mutable const Compound *mCompound = nullptr;
......@@ -110,14 +109,17 @@ class Atom
};
public:
Atom() {}
Atom(std::shared_ptr<AtomImpl> impl)
: mImpl(impl) {}
: mImpl(impl)
{
}
Atom(const Atom &rhs)
: mImpl(rhs.mImpl) {}
: mImpl(rhs.mImpl)
{
}
Atom(cif::Datablock &db, cif::Row &row);
......@@ -152,10 +154,10 @@ class Atom
set_property(name, std::to_string(value));
}
const std::string &id() const { return impl().mID; }
AtomType type() const { return impl().mType; }
const std::string &id() const { return impl().mID; }
AtomType type() const { return impl().mType; }
Point location() const { return impl().mLocation; }
Point location() const { return impl().mLocation; }
void location(Point p)
{
if (not mImpl)
......@@ -176,33 +178,33 @@ class Atom
void translateRotateAndTranslate(Point t1, Quaternion q, Point t2);
// for direct access to underlying data, be careful!
const cif::Row getRow() const { return impl().mRow; }
const cif::Row getRow() const { return impl().mRow; }
const cif::Row getRowAniso() const;
bool isSymmetryCopy() const { return impl().mSymmetryCopy; }
std::string symmetry() const { return impl().mSymmetryOperator; }
bool isSymmetryCopy() const { return impl().mSymmetryCopy; }
std::string symmetry() const { return impl().mSymmetryOperator; }
const Compound &comp() const { return impl().comp(); }
bool isWater() const { return impl().mCompID == "HOH" or impl().mCompID == "H2O" or impl().mCompID == "WAT"; }
const Compound &comp() const { return impl().comp(); }
bool isWater() const { return impl().mCompID == "HOH" or impl().mCompID == "H2O" or impl().mCompID == "WAT"; }
int charge() const;
float uIso() const;
bool getAnisoU(float anisou[6]) const { return impl().getAnisoU(anisou); }
bool getAnisoU(float anisou[6]) const { return impl().getAnisoU(anisou); }
float occupancy() const;
// specifications
const std::string& labelAtomID() const { return impl().mAtomID; }
const std::string& labelCompID() const { return impl().mCompID; }
const std::string& labelAsymID() const { return impl().mAsymID; }
const std::string &labelAtomID() const { return impl().mAtomID; }
const std::string &labelCompID() const { return impl().mCompID; }
const std::string &labelAsymID() const { return impl().mAsymID; }
std::string labelEntityID() const;
int labelSeqID() const { return impl().mSeqID; }
const std::string& labelAltID() const { return impl().mAltID; }
bool isAlternate() const { return not impl().mAltID.empty(); }
int labelSeqID() const { return impl().mSeqID; }
const std::string &labelAltID() const { return impl().mAltID; }
bool isAlternate() const { return not impl().mAltID.empty(); }
std::string authAtomID() const;
std::string authCompID() const;
std::string authAsymID() const;
const std::string& authSeqID() const { return impl().mAuthSeqID; }
const std::string &authSeqID() const { return impl().mAuthSeqID; }
std::string pdbxAuthInsCode() const;
std::string pdbxAuthAltID() const;
......@@ -225,7 +227,7 @@ class Atom
std::swap(mImpl, b.mImpl);
}
int compare(const Atom &b) const { return impl().compare(*b.mImpl); }
int compare(const Atom &b) const { return impl().compare(*b.mImpl); }
bool operator<(const Atom &rhs) const
{
......@@ -487,31 +489,33 @@ class Polymer : public std::vector<Monomer>
// file is a reference to the data stored in e.g. the cif file.
// This object is not copyable.
class File : public std::enable_shared_from_this<File>
class File : public cif::File
{
public:
File();
File(const std::filesystem::path &path);
File(const char *data, size_t length); // good luck trying to find out what it is...
~File();
File() {}
File(const File &) = delete;
File &operator=(const File &) = delete;
cif::Datablock& createDatablock(const std::string_view name);
File(const std::filesystem::path &path)
{
load(path);
}
void load(const std::filesystem::path &path);
void save(const std::filesystem::path &path);
File(const char *data, size_t length)
{
load(data, length);
}
Structure *model(size_t nr = 1);
File(const File &) = delete;
File &operator=(const File &) = delete;
struct FileImpl &impl() const { return *mImpl; }
void load(const std::filesystem::path &p) override;
void save(const std::filesystem::path &p) override;
cif::Datablock &data();
cif::File &file();
void load(std::istream &is) override;
using cif::File::save;
using cif::File::load;
private:
struct FileImpl *mImpl;
cif::Datablock &data() { return front(); }
};
// --------------------------------------------------------------------
......@@ -531,14 +535,18 @@ inline bool operator&(StructureOpenOptions a, StructureOpenOptions b)
class Structure
{
public:
Structure(File &p, size_t modelNr = 1, StructureOpenOptions options = {});
Structure &operator=(const Structure &) = delete;
~Structure();
Structure(File &p, size_t modelNr = 1, StructureOpenOptions options = {})
: Structure(p.firstDatablock(), modelNr, options)
{
}
Structure(cif::Datablock &db, size_t modelNr = 1, StructureOpenOptions options = {});
// Create a read-only clone of the current structure (for multithreaded calculations that move atoms)
Structure(const Structure &);
File &getFile() const;
Structure &operator=(const Structure &) = delete;
~Structure();
const AtomView &atoms() const { return mAtoms; }
AtomView waters() const;
......@@ -655,8 +663,15 @@ class Structure
void cleanupEmptyCategories();
/// \brief Direct access to underlying data
cif::Category &category(std::string_view name) const;
cif::Datablock &datablock() const;
cif::Category &category(std::string_view name) const
{
return mDb[name];
}
cif::Datablock &datablock() const
{
return mDb;
}
private:
friend Polymer;
......@@ -671,7 +686,7 @@ class Structure
void loadAtomsForModel(StructureOpenOptions options);
File &mFile;
cif::Datablock &mDb;
size_t mModelNr;
AtomView mAtoms;
std::vector<size_t> mAtomIndex;
......
......@@ -233,7 +233,7 @@ BondMap::BondMap(const Structure &p)
link[b].insert(a);
};
cif::Datablock &db = p.getFile().data();
cif::Datablock &db = p.datablock();
// collect all compounds first
std::set<std::string> compounds;
......
......@@ -2408,7 +2408,7 @@ namespace detail
size_t writeValue(std::ostream &os, std::string value, size_t offset, size_t width)
{
if (value.find('\n') != std::string::npos or width == 0 or value.length() >= 132) // write as text field
if (value.find('\n') != std::string::npos or width == 0 or value.length() > 132) // write as text field
{
ba::replace_all(value, "\n;", "\n\\;");
......@@ -2511,7 +2511,7 @@ void Category::write(std::ostream &os, const std::vector<size_t> &order, bool in
if (not isUnquotedString(v->mText))
l += 2;
if (l >= 132)
if (l > 132)
continue;
if (columnWidths[v->mColumnIndex] < l + 1)
......@@ -2547,7 +2547,7 @@ void Category::write(std::ostream &os, const std::vector<size_t> &order, bool in
if (l < w)
l = w;
if (offset + l >= 132 and offset > 0)
if (offset + l > 132 and offset > 0)
{
os << std::endl;
offset = 0;
......@@ -2555,7 +2555,7 @@ void Category::write(std::ostream &os, const std::vector<size_t> &order, bool in
offset = detail::writeValue(os, s, offset, w);
if (offset >= 132)
if (offset > 132)
{
os << std::endl;
offset = 0;
......@@ -3367,6 +3367,11 @@ File::File(const std::filesystem::path &path, bool validate)
}
}
File::File(const char *data, std::size_t length)
{
load(data, length);
}
File::File(File &&rhs)
: mHead(nullptr)
, mValidator(nullptr)
......@@ -3483,6 +3488,25 @@ void File::load(std::istream &is, const std::string &datablock)
}
}
void File::load(const char *data, std::size_t length)
{
bool gzipped = length > 2 and data[0] == static_cast<char>(0x1f) and data[1] == static_cast<char>(0x8b);
struct membuf : public std::streambuf
{
membuf(char *data, size_t length) { this->setg(data, data, data + length); }
} buffer(const_cast<char *>(data), length);
std::istream is(&buffer);
io::filtering_stream<io::input> in;
if (gzipped)
in.push(io::gzip_decompressor());
in.push(is);
load(is);
}
void File::save(std::ostream &os)
{
Datablock *e = mHead;
......@@ -3523,6 +3547,21 @@ Datablock &File::operator[](std::string_view name)
return *result;
}
Datablock &File::front()
{
assert(mHead);
return *mHead;
}
Datablock &File::back()
{
assert(mHead);
auto *block = mHead;
while (block->mNext != nullptr)
block = block->mNext;
return *block;
}
bool File::isValid()
{
if (mValidator == nullptr)
......
......@@ -301,7 +301,7 @@ std::tuple<double,Point> QuaternionToAngleAxis(Quaternion q)
q = Normalize(q);
// angle:
double angle = 2 * acos(q.R_component_1());
double angle = 2 * std::acos(q.R_component_1());
angle = angle * 180 / kPI;
// axis:
......
......@@ -535,7 +535,7 @@ double CalculateHBondEnergy(Res &inDonor, Res &inAcceptor)
result = kCouplingConstant / distanceHO - kCouplingConstant / distanceHC + kCouplingConstant / distanceNC - kCouplingConstant / distanceNO;
// DSSP compatibility mode:
result = round(result * 1000) / 1000;
result = std::round(result * 1000) / 1000;
if (result < kMinHBondEnergy)
result = kMinHBondEnergy;
......@@ -1230,7 +1230,7 @@ DSSPImpl::DSSPImpl(const Structure &s, int min_poly_proline_stretch_length)
void DSSPImpl::calculateSecondaryStructure()
{
auto &db = mStructure.getFile().data();
auto &db = mStructure.datablock();
for (auto r : db["struct_conn"].find(cif::Key("conn_type_id") == "disulf"))
{
std::string asym1, asym2;
......
......@@ -37,7 +37,7 @@ int main(int argc, char* argv[])
structure.cleanupEmptyCategories();
f.file().save(std::cout);
f.save(std::cout);
}
catch (const std::exception& e)
{
......
......@@ -78,8 +78,8 @@ BOOST_AUTO_TEST_CASE(create_nonpoly_1)
cif::VERBOSE = 1;
mmcif::File file;
file.file().loadDictionary("mmcif_pdbx_v50.dic");
file.createDatablock("TEST"); // create a datablock
file.loadDictionary("mmcif_pdbx_v50.dic");
file.emplace("TEST"); // create a datablock
mmcif::Structure structure(file);
......@@ -171,12 +171,12 @@ _struct_asym.details ?
expected.loadDictionary("mmcif_pdbx_v50.dic");
if (not (expected.firstDatablock() == structure.getFile().data()))
if (not (expected.firstDatablock() == structure.datablock()))
{
BOOST_TEST(false);
std::cout << expected.firstDatablock() << std::endl
<< std::endl
<< structure.getFile().data() << std::endl;
<< structure.datablock() << std::endl;
}
}
......
......@@ -1626,7 +1626,7 @@ PRO OXT HXT SING N N 17
mmcif::File file(example.string());
mmcif::Structure structure(file);
(void)file.file().isValid();
(void)file.isValid();
mmcif::BondMap bm(structure);
......
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