Simplified uniform GPU selection in CMake
[gromacs.git] / src / gromacs / fileio / mrcserializer.cpp
blob96899c0389beeb70c148bcecb4aeb7bccb6b0629
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2019,2020, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
35 /*! \internal \file
36 * \brief
37 * Implements methods from mrcserializer.h
39 * \author Christian Blau <cblau@gwdg.de>
40 * \ingroup module_fileio
42 #include "gmxpre.h"
44 #include "mrcserializer.h"
46 #include "config.h"
48 #include "gromacs/fileio/mrcdensitymapheader.h"
49 #include "gromacs/utility/inmemoryserializer.h"
51 namespace gmx
54 namespace
57 /*! \brief Machine stamp to indicate endianess of mrc/ccp4 file.
58 * As named in
59 * "EMDB Map Distribution Format Description Version 1.01 (c) emdatabank.org 2014"
60 * The first two bytes of a 4 byte unsigned int are used to indicate endianess:
61 * 0x11 0x11 big endian
62 * 0x44 0x44 small endian
63 * Byte-swap data if appropriate, when transferring data files between machines.
65 enum class MachineStamp : int32_t
67 bigEndian = 0x11110000, //!< big endian magic number 0x11 0x11 0x00 0x00 = 286,326,784
68 smallEndian = 0x44440000, //!< small endian magic number 0x44 0x44 0x00 0x00 = 1,145,307,136
71 /*! \brief Serialize a container of int32_t values.
72 * Serializes all containers with value_type int32_t that may looped over in a
73 * range based for loop and have modifiable elements.
75 * \tparam ContainerType type of container to be serialized
76 * \param[in,out] serializer the serializer
77 * \param[in,out] valueContainer the array to be serialized
79 template<typename ContainerType>
80 std::enable_if_t<std::is_same_v<typename ContainerType::value_type, int32_t>, void>
81 serialize(ISerializer* serializer, ContainerType* valueContainer)
83 for (auto& value : *valueContainer)
85 serializer->doInt32(&value);
89 /*! \brief Serialize a container of float values.
90 * Serializes all containers with value_type float that may looped over in a
91 * range based for loop and have modifiable elements.
93 * \tparam ContainerType type of container to be serialized
94 * \param[in,out] serializer the serializer
95 * \param[in,out] valueContainer the array to be serialized
97 template<typename ContainerType>
98 std::enable_if_t<std::is_same_v<typename ContainerType::value_type, float>, void>
99 serialize(ISerializer* serializer, ContainerType* valueContainer)
101 for (auto& value : *valueContainer)
103 serializer->doFloat(&value);
107 //! Serialize and convert from FORTRAN 1-based to C 0-based indices when reading and vice versa when writing
108 void serializeIndex(ISerializer* serializer, int32_t* index)
110 int32_t fortranIndex;
111 if (!serializer->reading())
113 fortranIndex = *index + 1;
115 serializer->doInt32(&fortranIndex);
116 if (serializer->reading())
118 *index = fortranIndex - 1;
122 /*! \brief
123 * Serializes an integer array and add unity when writing, substracting unity when reading.
125 void serializeIndices(ISerializer* serializer, std::array<int32_t, 3>* valueArray)
127 for (auto& value : *valueArray)
129 serializeIndex(serializer, &value);
133 /*! \brief Serialize input as int32_t via static casting.
134 * \tparam IntegralType type to be serialized as int32_t
136 template<class IntegralType>
137 std::enable_if_t<(std::is_integral_v<IntegralType> || std::is_enum_v<IntegralType>), void>
138 serializeAsInt32(ISerializer* serializer, IntegralType* value)
140 int32_t serializedValue;
141 if (!serializer->reading())
143 serializedValue = static_cast<int32_t>(*value);
145 serializer->doInt32(&serializedValue);
146 if (serializer->reading())
148 *value = static_cast<IntegralType>(serializedValue);
152 //! conversion constant from nm to MRC distance units (Ångström)
153 constexpr float c_nmToMrcUnits = 10;
155 //! Convert MRC distances to nm
156 float mrcUnitsToNm(float mrcValue)
158 return mrcValue / c_nmToMrcUnits;
161 //! Convert nm to MRC distances
162 float nmToMrcUnits(float nmValue)
164 return nmValue * c_nmToMrcUnits;
167 //! Serialize and convert between MRC and GROMACS distance units
168 void serializeDistance(ISerializer* serializer, float* distance)
170 float convertedDistance;
171 if (!serializer->reading())
173 convertedDistance = nmToMrcUnits(*distance);
175 serializer->doFloat(&convertedDistance);
176 if (serializer->reading())
178 *distance = mrcUnitsToNm(convertedDistance);
182 //! Serialize the skew data, words 25-37 in an mrc file.
183 void serializeCrystallographicSkewData(ISerializer* serializer, MrcDensitySkewData* skewData)
185 /* 25 | LSKFLG | signed int | emdb: 0 or 1
186 * flag for skew matrix
188 serializeAsInt32(serializer, &(skewData->valid_));
189 /* 26-34 | SKWMAT | floating pt | emdb: not set
190 * skew matrix-S11, S12, S13, S21, S22, S23, S31, S32, S33
191 * 35-37 | SKWTRN | floating pt | emdb: not set
192 * skew translation-T1, T2, T3
194 for (auto& matrixEntry : skewData->matrix_)
196 serializeDistance(serializer, &matrixEntry);
198 for (auto& translationEntry : skewData->translation_)
200 serializeDistance(serializer, &translationEntry);
204 /*! \brief Symmetrise and de-serializes the mrc density map header.
206 * Supports reading EMDB density maps in mrc format according to
207 * ftp://ftp.wwpdb.org/pub/emdb/doc/Map-format/current/EMDB_map_format.pdf
208 * \note format has small differences to http://www.ccpem.ac.uk/mrc_format/mrc2014.php
210 void doMrcDensityMapHeader(ISerializer* serializer, MrcDensityMapHeader* mrcFile)
212 // 1-3 | NC, NR, NS | signed int >0 | emdb: NC=NR=NS
213 // # of columns (fastest changing),rows, sections (slowest changing)
214 serialize(serializer, &(mrcFile->numColumnRowSection_));
216 // 4 | MODE | signed int | 0,1,2,3,4 | emdb: 2
217 serializeAsInt32(serializer, &(mrcFile->dataMode_));
219 // 5-7 | NCSTART, NRSTART, NSSTART | signed int | position of first column, first row, and first section
220 serialize(serializer, &(mrcFile->columnRowSectionStart_));
222 // 8-10 | NX, NY, NZ | signed int >0 | emdb: same as NC, NR, NS | intervals per unit cell repeat along X,Y Z
223 serialize(serializer, &(mrcFile->extent_));
225 // 11-13 | X_LENGTH, Y_LENGTH, Z_LENGTH | floating pt >0 | emdb Map lengths along X,Y,Z in
226 // Ångström Length in Ångström for a single voxel is unit_cell_length/n_voxel
227 serialize(serializer, &(mrcFile->cellLength_));
229 // 14-16 | ALPHA,BETA,GAMMA | floating pt >0, <180 | emdb: 90, 90, 90
230 // Unit Cell angles (degrees)following IUCr space group conventions for crystals
231 serialize(serializer, &(mrcFile->cellAngles_));
233 // 17-19 | MAPC, MAPR, MAPS | signed int | 1 (=X) 2 (=Y) 3 (=Z)| emdb: 1, 2, 3
234 // relationship of X,Y,Z axes to columns, rows, sections
235 // GROMACS uses C-style X=0, whereas mrc uses FORTRAN-style X=1
236 serializeIndices(serializer, &(mrcFile->columnRowSectionToXyz_));
238 // 20-22 | AMIN, AMAX, AMEAN | floating pt | Minimum, maximum, average density
239 serializer->doFloat(&(mrcFile->dataStatistics_.min_));
240 serializer->doFloat(&(mrcFile->dataStatistics_.max_));
241 serializer->doFloat(&(mrcFile->dataStatistics_.mean_));
243 // 23 | ISPG | signed int 1-230 | emdb: 1; 0 for image stacks | space group number
244 serializeAsInt32(serializer, &(mrcFile->spaceGroup_));
246 // 24 | NSYMBT | signed int | 80n | emdb: 0
247 // # of bytes in symmetry table, expected to be multiple of 80
248 int32_t numBytesExtendedHeader;
249 if (!serializer->reading())
251 numBytesExtendedHeader = mrcFile->extendedHeader_.size();
253 serializer->doInt32(&numBytesExtendedHeader);
254 if (serializer->reading())
256 mrcFile->extendedHeader_.resize(numBytesExtendedHeader);
259 // 25-37 | SKEW DATA | 1 byte flag, 9 byte matrix, 3 byte translation
260 serializeCrystallographicSkewData(serializer, &(mrcFile->skewData_));
262 // 38-52 | EXTRA | 32 bit binary
263 // 15 floats of user-defined metadata
264 // EMDB might use fields 50,51 and 52 for setting the coordinate system origin
265 for (auto& userFloat : mrcFile->userDefinedFloat_)
267 serializer->doFloat(&userFloat);
270 // 53 | MAP | ASCII char | emdb: "MAP "
271 // MRC/CCP4 MAP format identifier
272 for (auto& formatIdentifierCharacter : mrcFile->formatIdentifier_)
274 serializer->doUChar(&formatIdentifierCharacter);
277 // 54 | MACHST | 32 bit | binary machine stamp written/read as 4 hex byte sequence
278 MachineStamp machineStamp = GMX_INTEGER_BIG_ENDIAN ? MachineStamp::bigEndian : MachineStamp::smallEndian;
279 serializeAsInt32(serializer, &machineStamp);
281 // 55 | RMS | floating pt | Density root-mean-square deviation
282 serializer->doFloat(&(mrcFile->dataStatistics_.rms_));
284 // 56 | NLABL | signed int | 0-10 | Number of used user defined labels
285 serializer->doInt32(&(mrcFile->labels_.numUsedLabels_));
287 // 57-256 | LABEL_N | ASCII char | emdb : “::::EMDataBank.org::::EMD-1234::::”.
288 // 10 user-defined labels each 80 characters
289 for (auto&& label : mrcFile->labels_.labels_)
291 for (auto&& labelCharacter : label)
293 serializer->doUChar(&labelCharacter);
297 // 257-257+NSYMBT | user defined extended header information | emdb : none
298 for (auto& extendedHeaderCharacter : mrcFile->extendedHeader_)
300 serializer->doUChar(&extendedHeaderCharacter);
304 } // namespace
306 void serializeMrcDensityMapHeader(ISerializer* serializer, const MrcDensityMapHeader& mrcFile)
308 MrcDensityMapHeader mrcHeaderCopy = mrcFile;
309 doMrcDensityMapHeader(serializer, &mrcHeaderCopy);
312 MrcDensityMapHeader deserializeMrcDensityMapHeader(ISerializer* serializer)
314 MrcDensityMapHeader mrcHeader;
315 doMrcDensityMapHeader(serializer, &mrcHeader);
316 return mrcHeader;
319 } // namespace gmx