2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2019, 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.
38 * Implements mrc/ccp4-file format handling.
40 * \author Christian Blau <blau@kth.se>
42 * \ingroup module_fileio
46 #include "mrcdensitymap.h"
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"
58 #include "mrcserializer.h"
66 /*! \brief Read file into memory as vector of chars
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
73 std::vector<char> readCharBufferFromFile(const std::string& filename)
75 if (!gmx_fexist(filename))
77 GMX_THROW(FileIOError("Error while reading '" + filename + "' - file not found."));
79 t_fileio* mrcFile = gmx_fio_open(filename.c_str(), "r");
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(fileContentBuffer.data(), sizeof(char), fileContentBuffer.size(),
88 gmx_fio_getfp(mrcFile));
89 gmx_fio_close(mrcFile);
91 if (fileContentBuffer.size() != readSize)
93 GMX_THROW(FileIOError("Error while reading '" + filename
94 + "' - file size and read buffer size do not match."));
97 return fileContentBuffer;
102 /********************************************************************
103 * MrcDensityMapOfFloatReader::Impl
107 * Private implementation class for MrcDensityMapOfFloatReader.
109 class MrcDensityMapOfFloatReader::Impl
112 //! Build the map reader from a serializer.
113 explicit Impl(ISerializer* serializer);
115 //! The header of the read mrc file
116 MrcDensityMapHeader header_;
117 //! The data of the mrc file
118 std::vector<float> data_;
121 MrcDensityMapOfFloatReader::Impl::Impl(ISerializer* serializer)
123 if (!serializer->reading())
125 GMX_THROW(InternalError("Cannot use writing serializer to read."));
128 header_ = deserializeMrcDensityMapHeader(serializer);
129 const auto dataSize = numberOfExpectedDataItems(header_);
130 data_.resize(dataSize);
131 for (auto& value : data_)
133 serializer->doFloat(&value);
137 /********************************************************************
138 * MrcDensityMapOfFloatReader
141 MrcDensityMapOfFloatReader::MrcDensityMapOfFloatReader(ISerializer* serializer) :
142 impl_(new Impl(serializer))
146 ArrayRef<const float> MrcDensityMapOfFloatReader::constView() const
151 const MrcDensityMapHeader& MrcDensityMapOfFloatReader::header() const
153 return impl_->header_;
156 MrcDensityMapOfFloatReader::~MrcDensityMapOfFloatReader() {}
158 /********************************************************************
159 * MrcDensityMapOfFloatFromFileReader::Impl
163 class MrcDensityMapOfFloatFromFileReader::Impl
166 explicit Impl(const std::string& fileName);
168 const MrcDensityMapOfFloatReader& reader() const;
171 const std::vector<char> buffer_;
172 std::unique_ptr<InMemoryDeserializer> serializer_;
173 std::unique_ptr<MrcDensityMapOfFloatReader> reader_;
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()))
181 if (!mrcHeaderIsSane(reader_->header()))
183 serializer_ = std::make_unique<InMemoryDeserializer>(buffer_, false, EndianSwapBehavior::Swap);
184 reader_ = std::make_unique<MrcDensityMapOfFloatReader>(serializer_.get());
185 if (!mrcHeaderIsSane(reader_->header()))
187 GMX_THROW(FileIOError(
188 "Header of '" + filename
189 + "' fails sanity check for little- as well as big-endian reading."));
193 layout_right::mapping<dynamicExtents3D> map(getDynamicExtents3D(reader_->header()));
194 if (map.required_span_size() != reader_->constView().ssize())
196 GMX_THROW(FileIOError("File header density extent information of " + filename
197 + "' does not match density data size"));
201 const MrcDensityMapOfFloatReader& MrcDensityMapOfFloatFromFileReader::Impl::reader() const
206 /********************************************************************
207 * MrcDensityMapOfFloatFromFileReader
210 MrcDensityMapOfFloatFromFileReader::MrcDensityMapOfFloatFromFileReader(const std::string& filename) :
211 impl_(new Impl(filename))
215 MrcDensityMapOfFloatFromFileReader::~MrcDensityMapOfFloatFromFileReader() = default;
217 TranslateAndScale MrcDensityMapOfFloatFromFileReader::transformationToDensityLattice() const
219 return getCoordinateTransformationToLattice(impl_->reader().header());
222 MultiDimArray<std::vector<float>, dynamicExtents3D> MrcDensityMapOfFloatFromFileReader::densityDataCopy() const
224 MultiDimArray<std::vector<float>, dynamicExtents3D> result(
225 getDynamicExtents3D(impl_->reader().header()));
226 std::copy(std::begin(impl_->reader().constView()), std::end(impl_->reader().constView()),
227 begin(result.asView()));
231 /********************************************************************
232 * MrcDensityMapOfFloatWriter::Impl
236 * Private implementation class for MrcDensityMapOfFloatWriter.
238 class MrcDensityMapOfFloatWriter::Impl
241 //! Construct mrc file writer by providing header and data to be written.
242 Impl(const MrcDensityMapHeader& header, ArrayRef<const float> data);
244 //! Write the header and data from the writer to a given serialier
245 void write(ISerializer* serializer) const;
246 //! The mrc density map header data
247 const MrcDensityMapHeader header_;
249 const ArrayRef<const float> data_;
252 MrcDensityMapOfFloatWriter::Impl::Impl(const MrcDensityMapHeader& header, ArrayRef<const float> data) :
258 void MrcDensityMapOfFloatWriter::Impl::write(ISerializer* serializer) const
260 if (serializer->reading())
262 GMX_THROW(InternalError("Cannot use reading serializer to write."));
265 serializeMrcDensityMapHeader(serializer, header_);
267 if (numberOfExpectedDataItems(header_) != data_.size())
269 GMX_THROW(InternalError("Mrc data size does not match header information."));
272 for (float value : data_)
274 serializer->doFloat(&value);
278 /********************************************************************
279 * MrcDensityMapOfFloatWriter
282 MrcDensityMapOfFloatWriter::MrcDensityMapOfFloatWriter(const MrcDensityMapHeader& header,
283 ArrayRef<const float> data) :
284 impl_(new Impl(header, data))
288 void MrcDensityMapOfFloatWriter::write(ISerializer* serializer) const
290 impl_->write(serializer);
293 MrcDensityMapOfFloatWriter::~MrcDensityMapOfFloatWriter() {}