61 fail(
"invalid end of string");
62 return std::string(
reinterpret_cast<const char*
>(
header_word(w)), len);
80 std::memcpy(
header_word(w), str.c_str(), str.size());
86 std::array<int, 3> pos{{-1, -1, -1}};
87 for (
int i = 0;
i != 3; ++
i) {
90 fail(
"Incorrect MAPC/MAPR/MAPS records");
107 for (
int i = 0;
i < 3; ++
i) {
108 double scale = 1. /
sampl[
i];
110 box.minimum.at(
i) = scale * start[
p] - 1
e-9;
111 box.maximum.at(
i) = scale * (start[
p] + size[
p] - 1) + 1
e-9;
188 bool full_cell_(
const GridMeta& grid)
const {
198 void read_ccp4_header_(GridMeta* grid, AnyStream& f,
const std::string& path) {
199 const size_t hsize = 256;
202 fail(
"Failed to read map header: " + path);
204 fail(
"Not a CCP4 map: " + path);
206 if (machst[0] != 0x44 && machst[0] != 0x11)
207 fail(
"Unsupported machine stamp (endianness) in the file?");
212 fail(
"Unexpectedly long extended header: " + path);
214 if (!f.read(
ccp4_header.data() + hsize, 4 * ext_w))
215 fail(
"Failed to read extended header: " + path);
217 for (
int i = 0; i < 3; ++i) {
219 if (axis < 1 || axis > 3)
220 fail(
"Unexpected axis value in word " + std::to_string(17 + i)
221 +
": " + std::to_string(axis));
236 if (pos[0] == 0 && pos[1] == 1 && pos[2] == 2 && full_cell_(*grid))
242template<
typename T=
float>
250 fail(
"Only modes 0, 1, 2 and 6 are supported.");
252 fail(
"update_ccp4_header(): set the grid first (it has size 0)");
254 fail(
"update_ccp4_header(): run setup() first");
263 fail(
"update_ccp4_header: specify map mode explicitly (usually 2)");
269 if (std::is_same<T, std::int8_t>::value)
271 if (std::is_same<T, std::int16_t>::value)
273 if (std::is_same<T, float>::value)
275 if (std::is_same<T, std::uint16_t>::value)
283 read_ccp4_header_(&
grid, f, path);
303 template<
typename Input>
305 std::unique_ptr<AnyStream>
stream =
input.create_stream();
315template<
typename From,
typename To>
316To translate_map_point(From f) {
return static_cast<To
>(f); }
319std::int8_t translate_map_point<float,std::int8_t>(
float f) {
return f != 0; }
321template<
typename TFile,
typename TMem>
322void read_data(AnyStream& f, std::vector<TMem>& content) {
323 if (std::is_same<TFile, TMem>::value) {
324 size_t len = content.size();
325 if (!f.read(content.data(),
sizeof(TMem) * len))
326 fail(
"Failed to read all the data from the map file.");
328 constexpr size_t chunk_size = 64 * 1024;
329 std::vector<TFile> work(chunk_size);
330 for (
size_t i = 0; i < content.size(); i += chunk_size) {
331 size_t len = std::min(chunk_size, content.size() - i);
332 if (!f.read(work.data(),
sizeof(TFile) * len))
333 fail(
"Failed to read all the data from the map file.");
334 for (
size_t j = 0; j < len; ++j)
335 content[i+j] = translate_map_point<TFile,TMem>(work[j]);
340template<
typename TFile,
typename TMem>
341void write_data(
const std::vector<TMem>& content, FILE* f) {
342 if (std::is_same<TMem, TFile>::value) {
343 size_t len = content.size();
344 if (std::fwrite(content.data(),
sizeof(TFile), len, f) != len)
345 sys_fail(
"Failed to write data to the map file");
347 constexpr size_t chunk_size = 64 * 1024;
348 std::vector<TFile> work(chunk_size);
349 for (
size_t i = 0; i < content.size(); i += chunk_size) {
350 size_t len = std::min(chunk_size, content.size() - i);
351 for (
size_t j = 0; j < len; ++j)
352 work[j] =
static_cast<TFile
>(content[i+j]);
353 if (std::fwrite(work.data(),
sizeof(TFile), len, f) != len)
354 sys_fail(
"Failed to write data to the map file");
366 grid.data.resize(grid.point_count());
367 int mode = header_i32(4);
369 impl::read_data<std::int8_t>(f, grid.data);
371 impl::read_data<std::int16_t>(f, grid.data);
373 impl::read_data<float>(f, grid.data);
375 impl::read_data<std::uint16_t>(f, grid.data);
377 fail(
"Mode " + std::to_string(
mode) +
" is not supported "
378 "(only 0, 1, 2 and 6 are supported).");
382 if (!same_byte_order) {
384 for (
T&
value : grid.data)
386 else if (
sizeof(
T) == 4)
387 for (
T&
value : grid.data)
397 const std::array<int, 3>
sampl = header_3i32(8);
399 const std::array<int, 3> pos = axis_positions();
400 std::array<int, 3> start = header_3i32(5);
401 int end[3] = { start[0] + grid.nu, start[1] + grid.nv, start[2] + grid.nw };
404 set_header_3i32(5, start[pos[0]], start[pos[1]], start[pos[2]]);
405 for (
int i = 0;
i < 3; ++
i) {
409 int crs[3] = { grid.nu, grid.nv, grid.nw };
410 grid.nu =
crs[pos[0]];
411 grid.nv =
crs[pos[1]];
412 grid.nw =
crs[pos[2]];
417 set_header_3i32(5, 0, 0, 0);
419 set_header_3i32(1, grid.nu, grid.nv, grid.nw);
420 set_header_3i32(17, 1, 2, 3);
423 grid.calculate_spacing();
430 for (
it[2] = start[2];
it[2] < end[2];
it[2]++)
431 for (
it[1] = start[1];
it[1] < end[1];
it[1]++)
432 for (
it[0] = start[0];
it[0] < end[0];
it[0]++) {
433 T val = grid.data[idx++];
437 grid.data = std::move(
full);
442 (end[pos[0]] - start[pos[0]] <
sampl[0] ||
443 end[pos[1]] - start[pos[1]] <
sampl[1] ||
444 end[pos[2]] - start[pos[2]] <
sampl[2]))
450 if (ccp4_header.empty())
451 fail(
"set_extent(): no header in the map. Call update_ccp4_header() first");
453 fail(
"Ccp4::set_extent() works only after setup()");
455 fail(
"Ccp4::set_extent() works only with XYZ order");
456 int u0 = (
int)std::ceil(
box.minimum.x * grid.nu);
457 int v0 = (
int)std::ceil(
box.minimum.y * grid.nv);
458 int w0 = (
int)std::ceil(
box.minimum.z * grid.nw);
459 int nu = (
int)std::floor(
box.maximum.x * grid.nu) -
u0 + 1;
460 int nv = (
int)std::floor(
box.maximum.y * grid.nv) -
v0 + 1;
461 int nw = (
int)std::floor(
box.maximum.z * grid.nw) -
w0 + 1;
463 std::vector<T>
new_data((
size_t)nu * nv * nw);
464 grid.get_subarray(
new_data.data(), {u0, v0, w0}, {nu, nv, nw});
470 set_header_3i32(1, grid.nu, grid.nv, grid.nw);
471 set_header_3i32(5,
u0,
v0,
w0);
478 assert(ccp4_header.size() >= 256);
480 std::fwrite(ccp4_header.data(), 4, ccp4_header.size(), f.get());
481 int mode = header_i32(4);
483 impl::write_data<std::int8_t>(grid.data, f.get());
485 impl::write_data<std::int16_t>(grid.data, f.get());
487 impl::write_data<float>(grid.data, f.get());
489 impl::write_data<std::uint16_t>(grid.data, f.get());
fail(), unreachable() and __declspec/__attribute__ macros
3d grids used by CCP4 maps, cell-method search and hkl data.
void swap_four_bytes(void *start)
GEMMI_DLL Ccp4< float > read_ccp4_map(const std::string &path, bool setup)
GEMMI_DLL Ccp4Base read_ccp4_header(const std::string &path)
const SpaceGroup * find_spacegroup_by_number(int ccp4) noexcept
fileptr_t file_open(const char *path, const char *mode)
void swap_two_bytes(void *start)
GEMMI_COLD void sys_fail(const std::string &msg)
DataStats calculate_data_statistics(const std::vector< T > &data)
GEMMI_DLL Ccp4< int8_t > read_ccp4_mask(const std::string &path, bool setup)
void fail(const std::string &msg)
std::unique_ptr< std::FILE, needs_fclose > fileptr_t
void set_header_str(int w, const std::string &str)
std::string header_str(int w, size_t len=80) const
std::array< int, 3 > axis_positions() const
void set_header_i32(int w, int32_t value)
void set_header_3i32(int w, int32_t x, int32_t y, int32_t z)
Position get_origin() const
void prepare_ccp4_header_except_mode_and_stats(GridMeta &grid)
std::array< int, 3 > header_3i32(int w) const
Box< Fractional > get_extent() const
int32_t header_i32(int w) const
float header_float(int w) const
void * header_word(int w)
double header_rfloat(int w) const
void set_header_float(int w, float value)
const void * header_word(int w) const
Transform get_skew_transformation() const
bool has_skew_transformation() const
void update_header_mode_and_stats(int mode)
std::vector< int32_t > ccp4_header
void read_ccp4_from_memory(const char *data, size_t size, const std::string &name)
void update_ccp4_header(int mode=-1, bool update_stats=true)
If the header is empty, prepare it; otherwise, update only MODE and, if update_stats==true,...
void read_ccp4_stream(AnyStream &f, const std::string &path)
void setup(T default_value, MapSetup mode=MapSetup::Full)
static int mode_for_data()
void read_ccp4_file(const std::string &path)
void write_ccp4_map(const std::string &path) const
void set_extent(const Box< Fractional > &box)
void read_ccp4_header(AnyStream &f, const std::string &path)
void read_ccp4(Input &&input)
void calculate_spacing()
set spacing and orth_n
Coordinates in Angstroms - orthogonal (Cartesian) coordinates.
Crystallographic Symmetry. Space Groups. Coordinate Triplets.