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
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 IMDInterface.cc
53 \brief Defines the IMDInterface class
57 #pragma warning( push )
58 #pragma warning( disable : 4103 4244 )
61 #include <boost/python.hpp>
62 #include <boost/shared_array.hpp>
63 using namespace boost::python
;
64 using namespace boost
;
66 #include "IMDInterface.h"
67 #include "SignalHandler.h"
70 #include "Communicator.h"
81 /*! After construction, IMDInterface is listening for connections on port \a port.
82 analyze() must be called to handle any incoming connections.
83 \param sysdef SystemDefinition containing the ParticleData that will be transmitted to VMD
84 \param port port number to listen for connections on
85 \param pause Set to true to pause the simulation and waith for IMD_GO before continuing
86 \param rate Initial rate at which to send data
87 \param force Constant force used to apply forces received from VMD
88 \param force_scale Factor by which to scale all forces from IMD
90 IMDInterface::IMDInterface(boost::shared_ptr
<SystemDefinition
> sysdef
,
94 boost::shared_ptr
<ConstForceCompute
> force
,
98 m_exec_conf
->msg
->notice(5) << "Constructing IMDInterface: " << port
<< " " << pause
<< " " << rate
<< " " << force_scale
<< endl
;
102 m_exec_conf
->msg
->error() << "analyze.imd: Invalid port specified" << endl
;
103 throw runtime_error("Error initializing IMDInterface");
112 m_force_scale
= force_scale
;
115 m_force
->setForce(0,0,0);
117 // TCP socket will be initialized later
118 m_is_initialized
= false;
121 void IMDInterface::initConnection()
125 // start by initializing memory
126 m_tmp_coords
= new float[m_pdata
->getNGlobal() * 3];
128 // intialize the listening socket
130 m_listen_sock
= vmdsock_create();
133 if (m_listen_sock
== NULL
)
135 m_exec_conf
->msg
->error() << "analyze.imd: Unable to create listening socket" << endl
;
136 throw runtime_error("Error initializing IMDInterface");
139 // bind the socket and start listening for connections on that port
140 m_connected_sock
= NULL
;
141 err
= vmdsock_bind(m_listen_sock
, m_port
);
145 m_exec_conf
->msg
->error() << "analyze.imd: Unable to bind listening socket" << endl
;
146 throw runtime_error("Error initializing IMDInterface");
149 err
= vmdsock_listen(m_listen_sock
);
153 m_exec_conf
->msg
->error() << "analyze.imd: Unable to listen on listening socket" << endl
;
154 throw runtime_error("Error initializing IMDInterface");
157 m_exec_conf
->msg
->notice(2) << "analyze.imd: listening on port " << m_port
<< endl
;
159 m_is_initialized
= true;
162 IMDInterface::~IMDInterface()
164 m_exec_conf
->msg
->notice(5) << "Destroying IMDInterface" << endl
;
166 if (m_is_initialized
)
168 // free all used memory
169 delete[] m_tmp_coords
;
170 vmdsock_destroy(m_connected_sock
);
171 vmdsock_destroy(m_listen_sock
);
174 m_connected_sock
= NULL
;
175 m_listen_sock
= NULL
;
179 /*! If there is no active connection, analyze() will check to see if a connection attempt
180 has been made since the last call. If so, it will attempt to handshake with VMD and
181 on success will start transmitting data every time analyze() is called
183 \param timestep Current time step of the simulation
185 void IMDInterface::analyze(unsigned int timestep
)
193 is_root
= m_exec_conf
->isRoot();
195 if (is_root
&& ! m_is_initialized
)
200 if (! m_is_initialized
)
208 // establish a connection if one has not been made
209 if (m_connected_sock
== NULL
)
210 establishConnectionAttempt();
212 // dispatch incoming commands
213 if (m_connected_sock
)
219 while (m_connected_sock
&& messagesAvailable());
222 // quit if cntrl-C was pressed
226 throw runtime_error("SIG INT received while paused in IMD");
233 unsigned char send_coords
= 0;
234 if (is_root
&& m_connected_sock
&& m_active
&& (m_trate
== 0 || m_count
% m_trate
== 0))
239 bcast(send_coords
, 0, m_exec_conf
->getMPICommunicator());
243 sendCoords(timestep
);
245 // send data when active, connected, and the rate matches
246 if (m_connected_sock
&& m_active
&& (m_trate
== 0 || m_count
% m_trate
== 0))
247 sendCoords(timestep
);
254 /*! \pre \a m_connected_sock is connected and handshaking has occured
256 void IMDInterface::dispatch()
258 assert(m_connected_sock
!= NULL
);
260 // wait for messages, but only when paused
265 // begin by checking to see if any commands have been received
267 int res
= vmdsock_selread(m_connected_sock
, timeout
);
268 // check to see if there are any errors
271 m_exec_conf
->msg
->notice(3) << "analyze.imd: connection appears to have been terminated" << endl
;
272 processDeadConnection();
275 // if a command is waiting
278 // receive the header
279 IMDType header
= imd_recv_header(m_connected_sock
, &length
);
284 processIMD_DISCONNECT();
293 processIMD_MDCOMM(length
);
296 processIMD_TRATE(length
);
302 processIMD_IOERROR();
305 m_exec_conf
->msg
->notice(3) << "analyze.imd: received an unimplemented command (" << header
<< "), disconnecting" << endl
;
306 processDeadConnection();
310 // otherwise no message was received, do nothing
313 /*! \pre m_connected_sock is connected
315 bool IMDInterface::messagesAvailable()
317 int res
= vmdsock_selread(m_connected_sock
, 0);
321 m_exec_conf
->msg
->notice(3) << "analyze.imd: connection appears to have been terminated" << endl
;
322 processDeadConnection();
331 void IMDInterface::processIMD_DISCONNECT()
333 // cleanly disconnect and continue running the simulation. This is no different than what we do with a dead
335 processDeadConnection();
338 void IMDInterface::processIMD_GO()
340 // unpause and start transmitting data
343 m_exec_conf
->msg
->notice(3) << "analyze.imd: Received IMD_GO, transmitting data now" << endl
;
346 void IMDInterface::processIMD_KILL()
348 // disconnect (no different from handling a dead connection)
349 processDeadConnection();
350 // terminate the simulation
351 m_exec_conf
->msg
->notice(3) << "analyze.imd: Received IMD_KILL message, stopping the simulation" << endl
;
352 throw runtime_error("Received IMD_KILL message");
355 void IMDInterface::processIMD_MDCOMM(unsigned int n
)
357 // mdcomm is not currently handled
358 shared_array
<int32
> indices(new int32
[n
]);
359 shared_array
<float> forces(new float[3*n
]);
361 int err
= imd_recv_mdcomm(m_connected_sock
, n
, &indices
[0], &forces
[0]);
365 m_exec_conf
->msg
->error() << "analyze.imd: Error receiving mdcomm data, disconnecting" << endl
;
366 processDeadConnection();
373 m_exec_conf
->msg
->warning() << "analyze.imd: mdcomm currently not supported in MPI simulations." << endl
;
379 ArrayHandle
< unsigned int > h_rtag(m_pdata
->getRTags(), access_location::host
, access_mode::read
);
380 m_force
->setForce(0,0,0);
381 for (unsigned int i
= 0; i
< n
; i
++)
383 unsigned int j
= h_rtag
.data
[indices
[i
]];
384 m_force
->setParticleForce(j
,
385 forces
[3*i
+0]*m_force_scale
,
386 forces
[3*i
+1]*m_force_scale
,
387 forces
[3*i
+2]*m_force_scale
);
392 m_exec_conf
->msg
->warning() << "analyze.imd: Receiving forces over IMD, but no force was given to analyze.imd. Doing nothing" << endl
;
396 void IMDInterface::processIMD_TRATE(int rate
)
398 m_exec_conf
->msg
->notice(3) << "analyze.imd: Received IMD_TRATE, setting trate to " << rate
<< endl
;
402 void IMDInterface::processIMD_PAUSE()
406 m_exec_conf
->msg
->notice(3) << "analyze.imd: Received IMD_PAUSE, pausing simulation" << endl
;
411 m_exec_conf
->msg
->notice(3) << "analyze.imd: Received IMD_PAUSE, unpausing simulation" << endl
;
416 void IMDInterface::processIMD_IOERROR()
418 // disconnect (no different from handling a dead connection)
419 processDeadConnection();
420 // terminate the simulation
421 m_exec_conf
->msg
->error() << "analyze.imd: Received IMD_IOERROR message, dropping the connection" << endl
;
424 void IMDInterface::processDeadConnection()
426 vmdsock_destroy(m_connected_sock
);
427 m_connected_sock
= NULL
;
431 m_force
->setForce(0,0,0);
434 /*! \pre \a m_connected_sock is not connected
435 \pre \a m_listen_sock is listening
437 \a m_listen_sock is checked for any incoming connections. If an incoming connection is found, a handshake is made
438 and \a m_connected_sock is set. If no connection is established, \a m_connected_sock is set to NULL.
440 void IMDInterface::establishConnectionAttempt()
442 assert(m_listen_sock
!= NULL
);
443 assert(m_connected_sock
== NULL
);
445 // wait for messages, but only when paused
450 // check to see if there is an incoming connection
451 if (vmdsock_selread(m_listen_sock
, timeout
) > 0)
453 // create the connection
454 m_connected_sock
= vmdsock_accept(m_listen_sock
);
455 if (imd_handshake(m_connected_sock
))
457 vmdsock_destroy(m_connected_sock
);
458 m_connected_sock
= NULL
;
463 m_exec_conf
->msg
->notice(2) << "analyze.imd: accepted connection" << endl
;
468 /*! \param timestep Current time step of the simulation
469 \pre A connection has been established
471 Sends the current coordinates to VMD for display.
473 void IMDInterface::sendCoords(unsigned int timestep
)
475 // take a snapshot of the particle data
476 SnapshotParticleData
snapshot(m_pdata
->getNGlobal());
477 m_pdata
->takeSnapshot(snapshot
);
480 // return now if not root rank
482 if (! m_exec_conf
->isRoot()) return;
485 assert(m_connected_sock
!= NULL
);
487 // setup and send the energies structure
488 IMDEnergies energies
;
489 energies
.tstep
= timestep
;
491 energies
.Etot
= 0.0f
;
492 energies
.Epot
= 0.0f
;
493 energies
.Evdw
= 0.0f
;
494 energies
.Eelec
= 0.0f
;
495 energies
.Ebond
= 0.0f
;
496 energies
.Eangle
= 0.0f
;
497 energies
.Edihe
= 0.0f
;
498 energies
.Eimpr
= 0.0f
;
500 int err
= imd_send_energies(m_connected_sock
, &energies
);
503 m_exec_conf
->msg
->error() << "analyze.imd: I/O error while sending energies, disconnecting" << endl
;
504 processDeadConnection();
508 // copy the particle data to the holding array and send it
509 for (unsigned int tag
= 0; tag
< m_pdata
->getNGlobal(); tag
++)
511 m_tmp_coords
[tag
*3] = float(snapshot
.pos
[tag
].x
);
512 m_tmp_coords
[tag
*3 + 1] = float(snapshot
.pos
[tag
].y
);
513 m_tmp_coords
[tag
*3 + 2] = float(snapshot
.pos
[tag
].z
);
515 err
= imd_send_fcoords(m_connected_sock
, m_pdata
->getNGlobal(), m_tmp_coords
);
519 m_exec_conf
->msg
->error() << "analyze.imd: I/O error while sending coordinates, disconnecting" << endl
;
520 processDeadConnection();
525 void export_IMDInterface()
527 class_
<IMDInterface
, boost::shared_ptr
<IMDInterface
>, bases
<Analyzer
>, boost::noncopyable
>
528 ("IMDInterface", init
< boost::shared_ptr
<SystemDefinition
>, int, bool, unsigned int, boost::shared_ptr
<ConstForceCompute
> >())
533 #pragma warning( pop )