Apply re-formatting to C++ in src/ tree.
[alexxy/gromacs.git] / src / gromacs / fileio / mrcdensitymap.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
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.
8  *
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.
13  *
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.
18  *
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.
23  *
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.
31  *
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.
34  */
35 /*! \internal \file
36  *
37  * \brief
38  * Implements mrc/ccp4-file format handling.
39  *
40  * \author Christian Blau <blau@kth.se>
41  *
42  * \ingroup module_fileio
43  */
44 #include "gmxpre.h"
45
46 #include "mrcdensitymap.h"
47
48 #include <algorithm>
49 #include <vector>
50
51 #include "gromacs/fileio/gmxfio.h"
52 #include "gromacs/fileio/gmxfio_xdr.h"
53 #include "gromacs/fileio/mrcdensitymapheader.h"
54 #include "gromacs/utility/exceptions.h"
55 #include "gromacs/utility/inmemoryserializer.h"
56 #include "gromacs/utility/iserializer.h"
57
58 #include "mrcserializer.h"
59
60 namespace gmx
61 {
62
63 namespace
64 {
65
66 /*! \brief Read file into memory as vector of chars
67  *
68  * \param[in] filename of the file to be read
69  * \returns the file contents as a vector
70  * \throws FileIOError if file not found
71  * \throws FileIOError if reading was not successful
72  */
73 std::vector<char> readCharBufferFromFile(const std::string& filename)
74 {
75     if (!gmx_fexist(filename))
76     {
77         GMX_THROW(FileIOError("Error while reading '" + filename + "' - file not found."));
78     }
79     t_fileio* mrcFile = gmx_fio_open(filename.c_str(), "r");
80
81     // Determine file size
82     gmx_fseek(gmx_fio_getfp(mrcFile), 0, SEEK_END);
83     gmx_off_t fileSize = gmx_fio_ftell(mrcFile);
84     gmx_fseek(gmx_fio_getfp(mrcFile), 0, SEEK_SET);
85     // Read whole file into buffer the size of the file
86     std::vector<char> fileContentBuffer(fileSize);
87     size_t            readSize = fread(
88             fileContentBuffer.data(), sizeof(char), fileContentBuffer.size(), gmx_fio_getfp(mrcFile));
89     gmx_fio_close(mrcFile);
90
91     if (fileContentBuffer.size() != readSize)
92     {
93         GMX_THROW(FileIOError("Error while reading '" + filename
94                               + "' - file size and read buffer size do not match."));
95     }
96
97     return fileContentBuffer;
98 }
99
100 } // namespace
101
102 /********************************************************************
103  * MrcDensityMapOfFloatReader::Impl
104  */
105
106 /*! \internal \brief
107  * Private implementation class for MrcDensityMapOfFloatReader.
108  */
109 class MrcDensityMapOfFloatReader::Impl
110 {
111 public:
112     //! Build the map reader from a serializer.
113     explicit Impl(ISerializer* serializer);
114     ~Impl() {}
115     //! The header of the read mrc file
116     MrcDensityMapHeader header_;
117     //! The data of the mrc file
118     std::vector<float> data_;
119 };
120
121 MrcDensityMapOfFloatReader::Impl::Impl(ISerializer* serializer)
122 {
123     if (!serializer->reading())
124     {
125         GMX_THROW(InternalError("Cannot use writing serializer to read."));
126     }
127
128     header_             = deserializeMrcDensityMapHeader(serializer);
129     const auto dataSize = numberOfExpectedDataItems(header_);
130     data_.resize(dataSize);
131     for (auto& value : data_)
132     {
133         serializer->doFloat(&value);
134     }
135 }
136
137 /********************************************************************
138  * MrcDensityMapOfFloatReader
139  */
140
141 MrcDensityMapOfFloatReader::MrcDensityMapOfFloatReader(ISerializer* serializer) :
142     impl_(new Impl(serializer))
143 {
144 }
145
146 ArrayRef<const float> MrcDensityMapOfFloatReader::constView() const
147 {
148     return impl_->data_;
149 }
150
151 const MrcDensityMapHeader& MrcDensityMapOfFloatReader::header() const
152 {
153     return impl_->header_;
154 }
155
156 MrcDensityMapOfFloatReader::~MrcDensityMapOfFloatReader() {}
157
158 /********************************************************************
159  * MrcDensityMapOfFloatFromFileReader::Impl
160  */
161
162
163 class MrcDensityMapOfFloatFromFileReader::Impl
164 {
165 public:
166     explicit Impl(const std::string& fileName);
167     ~Impl() = default;
168     const MrcDensityMapOfFloatReader& reader() const;
169
170 private:
171     const std::vector<char>                     buffer_;
172     std::unique_ptr<InMemoryDeserializer>       serializer_;
173     std::unique_ptr<MrcDensityMapOfFloatReader> reader_;
174 };
175
176 MrcDensityMapOfFloatFromFileReader::Impl::Impl(const std::string& filename) :
177     buffer_(readCharBufferFromFile(filename)),
178     serializer_(std::make_unique<InMemoryDeserializer>(buffer_, false)),
179     reader_(std::make_unique<MrcDensityMapOfFloatReader>(serializer_.get()))
180 {
181     if (!mrcHeaderIsSane(reader_->header()))
182     {
183         serializer_ = std::make_unique<InMemoryDeserializer>(buffer_, false, EndianSwapBehavior::Swap);
184         reader_     = std::make_unique<MrcDensityMapOfFloatReader>(serializer_.get());
185         if (!mrcHeaderIsSane(reader_->header()))
186         {
187             GMX_THROW(FileIOError(
188                     "Header of '" + filename
189                     + "' fails sanity check for little- as well as big-endian reading."));
190         }
191     }
192
193     layout_right::mapping<dynamicExtents3D> map(getDynamicExtents3D(reader_->header()));
194     if (map.required_span_size() != reader_->constView().ssize())
195     {
196         GMX_THROW(FileIOError("File header density extent information of " + filename
197                               + "' does not match density data size"));
198     }
199 }
200
201 const MrcDensityMapOfFloatReader& MrcDensityMapOfFloatFromFileReader::Impl::reader() const
202 {
203     return *reader_;
204 }
205
206 /********************************************************************
207  * MrcDensityMapOfFloatFromFileReader
208  */
209
210 MrcDensityMapOfFloatFromFileReader::MrcDensityMapOfFloatFromFileReader(const std::string& filename) :
211     impl_(new Impl(filename))
212 {
213 }
214
215 MrcDensityMapOfFloatFromFileReader::~MrcDensityMapOfFloatFromFileReader() = default;
216
217 TranslateAndScale MrcDensityMapOfFloatFromFileReader::transformationToDensityLattice() const
218 {
219     return getCoordinateTransformationToLattice(impl_->reader().header());
220 }
221
222 MultiDimArray<std::vector<float>, dynamicExtents3D> MrcDensityMapOfFloatFromFileReader::densityDataCopy() const
223 {
224     MultiDimArray<std::vector<float>, dynamicExtents3D> result(
225             getDynamicExtents3D(impl_->reader().header()));
226     std::copy(std::begin(impl_->reader().constView()),
227               std::end(impl_->reader().constView()),
228               begin(result.asView()));
229     return result;
230 }
231
232 /********************************************************************
233  * MrcDensityMapOfFloatWriter::Impl
234  */
235
236 /*! \internal \brief
237  * Private implementation class for MrcDensityMapOfFloatWriter.
238  */
239 class MrcDensityMapOfFloatWriter::Impl
240 {
241 public:
242     //! Construct mrc file writer by providing header and data to be written.
243     Impl(const MrcDensityMapHeader& header, ArrayRef<const float> data);
244     ~Impl() {}
245     //! Write the header and data from the writer to a given serialier
246     void write(ISerializer* serializer) const;
247     //! The mrc density map header data
248     const MrcDensityMapHeader header_;
249     //! The density data
250     const ArrayRef<const float> data_;
251 };
252
253 MrcDensityMapOfFloatWriter::Impl::Impl(const MrcDensityMapHeader& header, ArrayRef<const float> data) :
254     header_(header),
255     data_(data)
256 {
257 }
258
259 void MrcDensityMapOfFloatWriter::Impl::write(ISerializer* serializer) const
260 {
261     if (serializer->reading())
262     {
263         GMX_THROW(InternalError("Cannot use reading serializer to write."));
264     }
265
266     serializeMrcDensityMapHeader(serializer, header_);
267
268     if (numberOfExpectedDataItems(header_) != data_.size())
269     {
270         GMX_THROW(InternalError("Mrc data size does not match header information."));
271     }
272
273     for (float value : data_)
274     {
275         serializer->doFloat(&value);
276     }
277 }
278
279 /********************************************************************
280  * MrcDensityMapOfFloatWriter
281  */
282
283 MrcDensityMapOfFloatWriter::MrcDensityMapOfFloatWriter(const MrcDensityMapHeader& header,
284                                                        ArrayRef<const float>      data) :
285     impl_(new Impl(header, data))
286 {
287 }
288
289 void MrcDensityMapOfFloatWriter::write(ISerializer* serializer) const
290 {
291     impl_->write(serializer);
292 }
293
294 MrcDensityMapOfFloatWriter::~MrcDensityMapOfFloatWriter() {}
295
296 } // namespace gmx