Enable parallel tests.
[hoomd-blue.git] / libhoomd / analyzers / HOOMDBinaryDumpWriter.cc
blob3abd27b52d89bdaae88e9efc3bae6d7a65a8dca7
1 /*
2 Highly Optimized Object-oriented Many-particle Dynamics -- Blue Edition
3 (HOOMD-blue) Open Source Software License Copyright 2009-2014 The Regents of
4 the University of Michigan All rights reserved.
6 HOOMD-blue may contain modifications ("Contributions") provided, and to which
7 copyright is held, by various Contributors who have granted The Regents of the
8 University of Michigan the right to modify and/or distribute such Contributions.
10 You may redistribute, use, and create derivate works of HOOMD-blue, in source
11 and binary forms, provided you abide by the following conditions:
13 * Redistributions of source code must retain the above copyright notice, this
14 list of conditions, and the following disclaimer both in the code and
15 prominently in any materials provided with the distribution.
17 * Redistributions in binary form must reproduce the above copyright notice, this
18 list of conditions, and the following disclaimer in the documentation and/or
19 other materials provided with the distribution.
21 * All publications and presentations based on HOOMD-blue, including any reports
22 or published results obtained, in whole or in part, with HOOMD-blue, will
23 acknowledge its use according to the terms posted at the time of submission on:
24 http://codeblue.umich.edu/hoomd-blue/citations.html
26 * Any electronic documents citing HOOMD-Blue will link to the HOOMD-Blue website:
27 http://codeblue.umich.edu/hoomd-blue/
29 * Apart from the above required attributions, neither the name of the copyright
30 holder nor the names of HOOMD-blue's contributors may be used to endorse or
31 promote products derived from this software without specific prior written
32 permission.
34 Disclaimer
36 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' AND
37 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
38 WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR ANY
39 WARRANTIES THAT THIS SOFTWARE IS FREE OF INFRINGEMENT ARE DISCLAIMED.
41 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
42 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
43 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
45 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
46 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
47 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50 // Maintainer: joaander
52 /*! \file HOOMDBinaryDumpWriter.cc
53 \brief Defines the HOOMDBinaryDumpWriter class
56 #ifdef WIN32
57 #pragma warning( push )
58 #pragma warning( disable : 4244 )
59 #endif
61 #include <boost/python.hpp>
62 using namespace boost::python;
64 #include <sstream>
65 #include <fstream>
66 #include <stdexcept>
67 #include <iomanip>
68 #include <boost/shared_ptr.hpp>
70 #include <boost/iostreams/device/file.hpp>
71 #include <boost/iostreams/filtering_stream.hpp>
72 #ifdef ENABLE_ZLIB
73 #include <boost/iostreams/filter/gzip.hpp>
74 #endif
76 #include "HOOMDBinaryDumpWriter.h"
77 #include "BondedGroupData.h"
78 #include "WallData.h"
80 using namespace std;
81 using namespace boost;
82 using namespace boost::iostreams;
84 //! Helper function to write a string out to a file in binary mode
85 static void write_string(ostream &f, const string& str)
87 unsigned int len = (unsigned int)str.size();
88 f.write((char*)&len, sizeof(unsigned int));
89 if (len != 0)
90 f.write(str.c_str(), len*sizeof(char));
93 /*! \param sysdef SystemDefinition containing the ParticleData to dump
94 \param base_fname The base name of the file xml file to output the information
96 \note .timestep.xml will be apended to the end of \a base_fname when analyze() is called.
98 HOOMDBinaryDumpWriter::HOOMDBinaryDumpWriter(boost::shared_ptr<SystemDefinition> sysdef, std::string base_fname)
99 : Analyzer(sysdef), m_base_fname(base_fname), m_alternating(false), m_cur_file(1), m_enable_compression(false)
101 m_exec_conf->msg->notice(5) << "Constructing HOOMDBinaryDumpWriter: " << base_fname << endl;
104 HOOMDBinaryDumpWriter::~HOOMDBinaryDumpWriter()
106 m_exec_conf->msg->notice(5) << "Destroying HOOMDBinaryDumpWriter" << endl;
109 /*! \param fname File name to write
110 \param timestep Current time step of the simulation
112 void HOOMDBinaryDumpWriter::writeFile(std::string fname, unsigned int timestep)
114 // check the file extension and warn the user
115 string ext = fname.substr(fname.size()-3, fname.size());
116 bool gz_ext = false;
117 if (ext == string(".gz"))
118 gz_ext = true;
120 if (!gz_ext && m_enable_compression)
122 m_exec_conf->msg->warning() << "dump.bin: Writing compressed binary file without a .gz extension." << endl;
123 m_exec_conf->msg->warning() << "init.read_bin will not recognize that this file is compressed" << endl;
125 if (gz_ext && !m_enable_compression)
127 m_exec_conf->msg->warning() << "dump.bin: Writing uncompressed binary file with a .gz extension." << endl;
128 m_exec_conf->msg->warning() << "init.read_bin will not recognize that this file is uncompressed" << endl;
131 // setup the file output for compression
132 filtering_ostream f;
133 #ifdef ENABLE_ZLIB
134 if (m_enable_compression)
135 f.push(gzip_compressor());
136 #endif
137 f.push(file_sink(fname.c_str(), ios::out | ios::binary));
139 if (!f.good())
141 m_exec_conf->msg->error() << "dump.bin: Unable to open dump file for writing: " << fname << endl;
142 throw runtime_error("Error writing hoomd binary dump file");
145 // write a magic number identifying the file format
146 unsigned int magic = 0x444d4f48;
147 f.write((char*)&magic, sizeof(unsigned int));
148 // write the version of the binary format used
149 int version = 3;
150 f.write((char*)&version, sizeof(int));
152 // acquire the particle data
153 ArrayHandle<Scalar4> h_pos(m_pdata->getPositions(), access_location::host, access_mode::read);
154 ArrayHandle<Scalar4> h_vel(m_pdata->getVelocities(), access_location::host, access_mode::read);
155 ArrayHandle<Scalar3> h_accel(m_pdata->getAccelerations(), access_location::host, access_mode::read);
156 ArrayHandle<int3> h_image(m_pdata->getImages(), access_location::host, access_mode::read);
157 ArrayHandle<unsigned int> h_body(m_pdata->getBodies(), access_location::host, access_mode::read);
158 ArrayHandle<unsigned int> h_tag(m_pdata->getTags(), access_location::host, access_mode::read);
159 ArrayHandle<unsigned int> h_rtag(m_pdata->getRTags(), access_location::host, access_mode::read);
160 ArrayHandle<Scalar> h_charge(m_pdata->getCharges(), access_location::host, access_mode::read);
161 ArrayHandle<Scalar> h_diameter(m_pdata->getDiameters(), access_location::host, access_mode::read);
163 BoxDim box = m_pdata->getBox();
164 Scalar3 L = box.getL();
165 unsigned int dimensions = m_sysdef->getNDimensions();
167 //write out the timestep, dimensions, and box
168 f.write((char*)&timestep, sizeof(unsigned int));
169 f.write((char*)&dimensions, sizeof(unsigned int));
170 f.write((char*)&L.x, sizeof(Scalar));
171 f.write((char*)&L.y, sizeof(Scalar));
172 f.write((char*)&L.z, sizeof(Scalar));
174 //write out particle data
175 unsigned int np = m_pdata->getN();
176 f.write((char*)&np, sizeof(unsigned int));
177 f.write((char*)h_tag.data, np*sizeof(unsigned int));
178 f.write((char*)h_rtag.data, np*sizeof(unsigned int));
179 for (unsigned int i = 0; i < np; i++)
180 f.write((char*)&h_pos.data[i].x, sizeof(Scalar));
181 for (unsigned int i = 0; i < np; i++)
182 f.write((char*)&h_pos.data[i].y, sizeof(Scalar));
183 for (unsigned int i = 0; i < np; i++)
184 f.write((char*)&h_pos.data[i].z, sizeof(Scalar));
185 for (unsigned int i = 0; i < np; i++)
186 f.write((char*)&h_image.data[i].x, sizeof(int));
187 for (unsigned int i = 0; i < np; i++)
188 f.write((char*)&h_image.data[i].y, sizeof(int));
189 for (unsigned int i = 0; i < np; i++)
190 f.write((char*)&h_image.data[i].z, sizeof(int));
191 for (unsigned int i = 0; i < np; i++)
192 f.write((char*)&h_vel.data[i].x, sizeof(Scalar));
193 for (unsigned int i = 0; i < np; i++)
194 f.write((char*)&h_vel.data[i].y, sizeof(Scalar));
195 for (unsigned int i = 0; i < np; i++)
196 f.write((char*)&h_vel.data[i].z, sizeof(Scalar));
197 for (unsigned int i = 0; i < np; i++)
198 f.write((char*)&h_accel.data[i].x, sizeof(Scalar));
199 for (unsigned int i = 0; i < np; i++)
200 f.write((char*)&h_accel.data[i].y, sizeof(Scalar));
201 for (unsigned int i = 0; i < np; i++)
202 f.write((char*)&h_accel.data[i].z, sizeof(Scalar));
203 for (unsigned int i = 0; i < np; i++)
204 f.write((char*)&h_vel.data[i].w, sizeof(Scalar));
205 f.write((char*)h_diameter.data, np*sizeof(Scalar));
206 f.write((char*)h_charge.data, np*sizeof(Scalar));
207 f.write((char*)h_body.data, np*sizeof(unsigned int));
209 //write out types and type mapping
210 unsigned int ntypes = m_pdata->getNTypes();
211 f.write((char*)&ntypes, sizeof(unsigned int));
212 for (unsigned int i = 0; i < ntypes; i++)
214 std::string name = m_pdata->getNameByType(i);
215 write_string(f, name);
217 for (unsigned int i = 0; i < np; i++)
218 f.write((char*)&h_pos.data[i].w, sizeof(unsigned int));
220 if (!f.good())
222 m_exec_conf->msg->error() << "dump.bin: I/O error writing HOOMD dump file" << endl;
223 throw runtime_error("Error writing HOOMD dump file");
226 //Output the integrator states to the binary file
228 boost::shared_ptr<IntegratorData> integrator_data = m_sysdef->getIntegratorData();
229 unsigned int ni = integrator_data->getNumIntegrators();
230 f.write((char*)&ni, sizeof(unsigned int));
231 for (unsigned int j = 0; j < ni; j++)
233 IntegratorVariables v = integrator_data->getIntegratorVariables(j);
234 write_string(f, v.type);
236 unsigned int nv = (unsigned int)v.variable.size();
237 f.write((char*)&nv, sizeof(unsigned int));
238 for (unsigned int k=0; k<nv; k++)
240 Scalar var = v.variable[k];
241 f.write((char*)&var, sizeof(Scalar));
246 // Output the bonds to the binary file
248 //write out type mapping
249 ntypes = m_sysdef->getBondData()->getNTypes();
250 f.write((char*)&ntypes, sizeof(unsigned int));
251 for (unsigned int i = 0; i < ntypes; i++)
253 std::string name = m_sysdef->getBondData()->getNameByType(i);
254 write_string(f, name);
257 unsigned int nb = m_sysdef->getBondData()->getN();
258 f.write((char*)&nb, sizeof(unsigned int));
259 boost::shared_ptr<BondData> bond_data = m_sysdef->getBondData();
261 // loop over all bonds and write them out
262 for (unsigned int i = 0; i < bond_data->getN(); i++)
264 BondData::members_t bond = bond_data->getMembersByIndex(i);
265 unsigned int type = bond_data->getTypeByIndex(i);
266 f.write((char*)&type, sizeof(unsigned int));
267 f.write((char*)&bond.tag[0], sizeof(unsigned int));
268 f.write((char*)&bond.tag[1], sizeof(unsigned int));
272 // Output the angles to the binary file
274 //write out type mapping
275 ntypes = m_sysdef->getAngleData()->getNTypes();
276 f.write((char*)&ntypes, sizeof(unsigned int));
277 for (unsigned int i = 0; i < ntypes; i++)
279 std::string name = m_sysdef->getAngleData()->getNameByType(i);
280 write_string(f, name);
283 unsigned int na = m_sysdef->getAngleData()->getN();
284 f.write((char*)&na, sizeof(unsigned int));
286 boost::shared_ptr<AngleData> angle_data = m_sysdef->getAngleData();
288 // loop over all angles and write them out
289 for (unsigned int i = 0; i < angle_data->getN(); i++)
291 AngleData::members_t angle = angle_data->getMembersByIndex(i);
292 unsigned int type = angle_data->getTypeByIndex(i);
294 f.write((char*)&type, sizeof(unsigned int));
295 f.write((char*)&angle.tag[0], sizeof(unsigned int));
296 f.write((char*)&angle.tag[1], sizeof(unsigned int));
297 f.write((char*)&angle.tag[2], sizeof(unsigned int));
301 // Write out dihedrals to the binary file
303 //write out type mapping
304 ntypes = m_sysdef->getDihedralData()->getNTypes();
305 f.write((char*)&ntypes, sizeof(unsigned int));
306 for (unsigned int i = 0; i < ntypes; i++)
308 std::string name = m_sysdef->getDihedralData()->getNameByType(i);
309 write_string(f, name);
312 unsigned int nd = m_sysdef->getDihedralData()->getNGlobal();
313 f.write((char*)&nd, sizeof(unsigned int));
315 boost::shared_ptr<DihedralData> dihedral_data = m_sysdef->getDihedralData();
317 // loop over all angles and write them out
318 for (unsigned int i = 0; i < dihedral_data->getNGlobal(); i++)
320 DihedralData::members_t dihedral = dihedral_data->getMembersByIndex(i);
321 unsigned int type = dihedral_data->getTypeByIndex(i);
323 f.write((char*)&type, sizeof(unsigned int));
324 f.write((char*)&dihedral.tag[0], sizeof(unsigned int));
325 f.write((char*)&dihedral.tag[1], sizeof(unsigned int));
326 f.write((char*)&dihedral.tag[2], sizeof(unsigned int));
327 f.write((char*)&dihedral.tag[3], sizeof(unsigned int));
331 // Write out impropers to the binary file
333 ntypes = m_sysdef->getImproperData()->getNTypes();
334 f.write((char*)&ntypes, sizeof(unsigned int));
335 for (unsigned int i = 0; i < ntypes; i++)
337 std::string name = m_sysdef->getImproperData()->getNameByType(i);
338 write_string(f, name);
341 unsigned int ni = m_sysdef->getImproperData()->getNGlobal();
342 f.write((char*)&ni, sizeof(unsigned int));
344 boost::shared_ptr<ImproperData> improper_data = m_sysdef->getImproperData();
346 // loop over all angles and write them out
347 for (unsigned int i = 0; i < improper_data->getNGlobal(); i++)
349 ImproperData::members_t improper = improper_data->getMembersByIndex(i);
350 unsigned int type = improper_data->getTypeByIndex(i);
352 f.write((char*)&type, sizeof(unsigned int));
353 f.write((char*)&improper.tag[0], sizeof(unsigned int));
354 f.write((char*)&improper.tag[1], sizeof(unsigned int));
355 f.write((char*)&improper.tag[2], sizeof(unsigned int));
356 f.write((char*)&improper.tag[3], sizeof(unsigned int));
360 // Output the walls to the binary file
362 boost::shared_ptr<WallData> wall_data = m_sysdef->getWallData();
364 unsigned int nw = wall_data->getNumWalls();
365 f.write((char*)&nw, sizeof(unsigned int));
367 // loop over all walls and write them out
368 for (unsigned int i = 0; i < nw; i++)
370 Wall wall = wall_data->getWall(i);
372 f.write((char*)&(wall.origin_x), sizeof(Scalar));
373 f.write((char*)&(wall.origin_y), sizeof(Scalar));
374 f.write((char*)&(wall.origin_z), sizeof(Scalar));
375 f.write((char*)&(wall.normal_x), sizeof(Scalar));
376 f.write((char*)&(wall.normal_y), sizeof(Scalar));
377 f.write((char*)&(wall.normal_z), sizeof(Scalar));
381 // Output the rigid bodies to the binary file
383 boost::shared_ptr<RigidData> rigid_data = m_sysdef->getRigidData();
385 unsigned int n_bodies = rigid_data->getNumBodies();
386 f.write((char*)&n_bodies, sizeof(unsigned int));
388 if (n_bodies <= 0)
390 return;
393 // We don't need to write forces, torques and orientation/quaternions because as the rigid bodies are constructed
394 // from restart files, the orientation is recalculated for the moment of inertia- using the old one will cause mismatches in angular velocities.
395 // Below are the minimal data required for a smooth restart with rigid bodies, assuming that RigidData::initializeData() already invoked.
397 ArrayHandle<Scalar4> com_handle(rigid_data->getCOM(), access_location::host, access_mode::read);
398 ArrayHandle<Scalar4> vel_handle(rigid_data->getVel(), access_location::host, access_mode::read);
399 ArrayHandle<Scalar4> angmom_handle(rigid_data->getAngMom(), access_location::host, access_mode::read);
400 ArrayHandle<int3> body_image_handle(rigid_data->getBodyImage(), access_location::host, access_mode::read);
402 for (unsigned int body = 0; body < n_bodies; body++)
404 f.write((char*)&(com_handle.data[body].x), sizeof(Scalar));
405 f.write((char*)&(com_handle.data[body].y), sizeof(Scalar));
406 f.write((char*)&(com_handle.data[body].z), sizeof(Scalar));
407 f.write((char*)&(com_handle.data[body].w), sizeof(Scalar));
409 f.write((char*)&(vel_handle.data[body].x), sizeof(Scalar));
410 f.write((char*)&(vel_handle.data[body].y), sizeof(Scalar));
411 f.write((char*)&(vel_handle.data[body].z), sizeof(Scalar));
412 f.write((char*)&(vel_handle.data[body].w), sizeof(Scalar));
414 f.write((char*)&(angmom_handle.data[body].x), sizeof(Scalar));
415 f.write((char*)&(angmom_handle.data[body].y), sizeof(Scalar));
416 f.write((char*)&(angmom_handle.data[body].z), sizeof(Scalar));
417 f.write((char*)&(angmom_handle.data[body].w), sizeof(Scalar));
419 f.write((char*)&(body_image_handle.data[body].x), sizeof(int));
420 f.write((char*)&(body_image_handle.data[body].y), sizeof(int));
421 f.write((char*)&(body_image_handle.data[body].z), sizeof(int));
426 if (!f.good())
428 m_exec_conf->msg->error() << "dump.bin: I/O error writing HOOMD dump file" << endl;
429 throw runtime_error("Error writing HOOMD dump file");
434 /*! \param timestep Current time step of the simulation
435 Writes a snapshot of the current state of the ParticleData to a hoomd_xml file.
437 void HOOMDBinaryDumpWriter::analyze(unsigned int timestep)
439 if (m_prof)
440 m_prof->push("Dump BIN");
442 if (!m_alternating)
444 ostringstream full_fname;
445 string filetype = ".bin";
446 if (m_enable_compression)
447 filetype += ".gz";
449 // Generate a filename with the timestep padded to ten zeros
450 full_fname << m_base_fname << "." << setfill('0') << setw(10) << timestep << filetype;
451 writeFile(full_fname.str(), timestep);
453 else
455 // write out to m_fname1 and m_fname2, alternating between the two
456 string fname;
457 if (m_cur_file == 1)
459 fname = m_fname1;
460 m_cur_file = 2;
462 else
464 fname = m_fname2;
465 m_cur_file = 1;
467 writeFile(fname, timestep);
470 if (m_prof)
471 m_prof->pop();
474 /*! \param fname1 File name of the first file to write
475 \param fname2 File nmae of the second file to write
477 void HOOMDBinaryDumpWriter::setAlternatingWrites(const std::string& fname1, const std::string& fname2)
479 m_alternating = true;
480 m_fname1 = fname1;
481 m_fname2 = fname2;
484 /* \param enable_compression Set to true to enable compression, falst to disable it
486 void HOOMDBinaryDumpWriter::enableCompression(bool enable_compression)
488 #ifdef ENABLE_ZLIB
489 m_enable_compression = enable_compression;
490 #else
491 m_enable_compression = false;
492 if (enable_compression)
494 m_exec_conf->msg->warning() << "dump.bin: This build of hoomd was compiled with ENABLE_ZLIB=off.";
495 m_exec_conf->msg->warning() << "binary data output will NOT be compressed" << endl;
497 #endif
500 void export_HOOMDBinaryDumpWriter()
502 class_<HOOMDBinaryDumpWriter, boost::shared_ptr<HOOMDBinaryDumpWriter>, bases<Analyzer>, boost::noncopyable>
503 ("HOOMDBinaryDumpWriter", init< boost::shared_ptr<SystemDefinition>, std::string >())
504 .def("writeFile", &HOOMDBinaryDumpWriter::writeFile)
505 .def("setAlternatingWrites", &HOOMDBinaryDumpWriter::setAlternatingWrites)
506 .def("enableCompression", &HOOMDBinaryDumpWriter::enableCompression)
510 #ifdef WIN32
511 #pragma warning( pop )
512 #endif