Files
Jungfraujoch/gemmi_gph/calculate.cpp
T
leonarski_fandClaude Opus 4.8 5addb4483c gemmi_gph: vendor the model / structure-factor headers into the single gemmi target
Extend the vendored GEMMI subset (v0.7.5) with the atomic-model, structure-factor,
bulk-solvent and map machinery so the whole thing builds as one static `gemmi`
library instead of a separate target:

  - add the model/SF/map sources compiled into `gemmi`:
    pdb, resinfo, polyheur, calculate, eig3, ccp4
  - add the v0.7.5 headers these pull in (model.hpp, dencalc.hpp, sfcalc.hpp,
    solmask.hpp, scaling.hpp, fourier.hpp, grid.hpp, ccp4.hpp, it92.hpp, ...)
    plus third_party/pocketfft (FFT), half, tinydir

Only the low-level string/math/symmetry headers were present before; this makes
the vendored copy a complete, self-consistent gemmi that can read a PDB and do
density / structure-factor / map calculations.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 21:27:44 +02:00

78 lines
2.9 KiB
C++

// Copyright 2018 Global Phasing Ltd.
#include "gemmi/calculate.hpp"
#include "gemmi/eig3.hpp"
namespace gemmi {
std::array<double, 4> find_best_plane(const std::vector<Atom*>& atoms) {
Vec3 mean;
for (const Atom* atom : atoms)
mean += atom->pos;
mean /= (double) atoms.size();
SMat33<double> m{0, 0, 0, 0, 0, 0};
for (const Atom* atom : atoms) {
Vec3 p = Vec3(atom->pos) - mean;
m.u11 += p.x * p.x;
m.u22 += p.y * p.y;
m.u33 += p.z * p.z;
m.u12 += p.x * p.y;
m.u13 += p.x * p.z;
m.u23 += p.y * p.z;
}
double eig[3] = {};
Mat33 V = eigen_decomposition(m, eig);
int smallest_idx = std::fabs(eig[0]) < std::fabs(eig[1]) ? 0 : 1;
if (std::fabs(eig[2]) < std::fabs(eig[smallest_idx]))
smallest_idx = 2;
Vec3 eigvec = V.column_copy(smallest_idx);
if (eigvec.x < 0)
eigvec *= -1;
return {{eigvec.x, eigvec.y, eigvec.z, -eigvec.dot(mean)}};
}
FTransform parse_triplet_as_ftransform(const std::string& s) {
// c.f. parse_triplet()
if (std::count(s.begin(), s.end(), ',') != 2)
fail("expected exactly two commas in triplet");
size_t comma1 = s.find(',');
size_t comma2 = s.find(',', comma1 + 1);
FTransform frac_tr;
auto set_ftransform_row = [](FTransform& tr, int i, const std::string& part) {
const double mult = 1. / Op::DEN;
double decfr[4] = {};
char x_ = 'x';
const auto op_row = parse_triplet_part(part, x_, decfr);
for (int j = 0; j < 3; ++j)
tr.mat[i][j] = decfr[j] == 0. ? mult * op_row[j] : decfr[j];
tr.vec.at(i) = decfr[3] == 0. ? mult * op_row[3] : decfr[3];
};
set_ftransform_row(frac_tr, 0, s.substr(0, comma1));
set_ftransform_row(frac_tr, 1, s.substr(comma1 + 1, comma2 - (comma1 + 1)));
set_ftransform_row(frac_tr, 2, s.substr(comma2 + 1));
return frac_tr;
}
SMat33<double> calculate_u_from_tls(const TlsGroup& tls, const Position& pos) {
Position r = (pos - tls.origin) * rad(1);
SMat33<double> l_contrib = {
r.y * r.y * tls.L.u33 + r.z * r.z * tls.L.u22 - 2 * r.z * r.y * tls.L.u23,
r.x * r.x * tls.L.u33 + r.z * r.z * tls.L.u11 - 2 * r.z * r.x * tls.L.u13,
r.x * r.x * tls.L.u22 + r.y * r.y * tls.L.u11 - 2 * r.y * r.x * tls.L.u12,
-r.x * r.y * tls.L.u33 + r.z * ( r.x * tls.L.u23 + r.y * tls.L.u13 - r.z * tls.L.u12),
-r.x * r.z * tls.L.u22 + r.y * ( r.x * tls.L.u23 - r.y * tls.L.u13 + r.z * tls.L.u12),
-r.y * r.z * tls.L.u11 + r.x * (-r.x * tls.L.u23 + r.y * tls.L.u13 + r.z * tls.L.u12)
};
SMat33<double> s_contrib = {
2 * (tls.S[1][0] * r.z - tls.S[2][0] * r.y),
2 * (tls.S[2][1] * r.x - tls.S[0][1] * r.z),
2 * (tls.S[0][2] * r.y - tls.S[1][2] * r.x),
tls.S[2][0] * r.x - tls.S[2][1] * r.y + (tls.S[1][1] - tls.S[0][0]) * r.z,
tls.S[1][2] * r.z - tls.S[1][0] * r.x + (tls.S[0][0] - tls.S[2][2]) * r.y,
tls.S[0][1] * r.y - tls.S[0][2] * r.z + (tls.S[2][2] - tls.S[1][1]) * r.x
};
return tls.T + l_contrib + s_contrib;
}
} // namespace gemmi