// This file is part of the ESPResSo distribution (http://www.espresso.mpg.de). // It is therefore subject to the ESPResSo license agreement which you accepted upon receiving the distribution // and by which you are legally bound while utilizing this file in any form or way. // There is NO WARRANTY, not even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // You should have received a copy of that license along with this program; // if not, refer to http://www.espresso.mpg.de/license.html where its current version can be found, or // write to Max-Planck-Institute for Polymer Research, Theory Group, PO Box 3148, 55021 Mainz, Germany. // Copyright (c) 2002-2006; all rights reserved unless otherwise stated. #ifndef COMM_H #define COMM_H /** \file communication.h This file contains the asynchronous MPI communication. Responsible: Axel It is the header file for \ref communication.c "communication.c". The asynchronous MPI communication is used during the script evaluation. Except for the master node that interpretes the Tcl script, all other nodes wait in \ref mpi_loop for the master node to issue an action using \ref mpi_issue. \ref mpi_loop immediately executes an MPI_Bcast and therefore waits for the master node to broadcast a command, which is done by \ref mpi_issue. The request consists of three integers, the first one describing the action issued, the second and third an arbitrary parameter depending on the action issued. If applicable, the second parameter is the node number of the slave this request is dedicated to. Adding new actions (e. g. to implement new Tcl commands) is simple. First, the action has to be assigned a new action number (the defines like \ref REQ_BCAST_PAR) by adding a new define and increasing \ref REQ_MAXIMUM. Then you write a mpi_* procedure that does a \verbatim mpi_issue(request, node, param)\endverbatim where pnode and param are arbitrary values which will be passed to the slave procedure. After this your procedure is free to do anything. However, it has to be in (MPI) sync with what your new mpi_*_slave does. This procedure is called immediately after the broadcast with the arbitrary integer as parameter. To this aim it has also to be added to \ref #callbacks (the array index gives your action number. Last but not least for debugging purposes you can add a nice name to \ref #names in the same way. */ /* from here we borrow the enumeration of the global variables */ #include "global.h" #include "particle_data.h" #include "random.h" #include "topology.h" /************************************************** * exported variables **************************************************/ /** \name Exported Variables */ /address@hidden/ /** The number of this node. */ extern int this_node; /** The total number of nodes. */ extern int n_nodes; /address@hidden/ /************************************************** * for every procedure requesting a MPI negotiation * a slave exists which processes this request on * the slave nodes. It is denoted by *_slave. **************************************************/ /** \name Exported Functions */ /address@hidden/ /** Initialize MPI and determine \ref n_nodes and \ref this_node. */ void mpi_init(int *argc, char ***argv); /** Process requests from master node. Slave nodes main loop. */ void mpi_loop(); /** Issue REQ_TERM: stop Espresso, all slave nodes exit. */ void mpi_stop(); /** Finalize MPI. Called by all nodes upon exit */ void mpi_finalize(); /** Issue REQ_BCAST_PAR: broadcast a parameter from datafield. @param i the number from \ref global.h "global.h" referencing the datafield. @return nonzero on error */ int mpi_bcast_parameter(int i); /** Issue REQ_WHO_HAS: ask nodes for their attached particles. */ void mpi_who_has(); /** Issue REQ_EVENT: tells all clients of some system change. The events are: Then all nodes execute the respective on_* procedure from \ref initialize.c Note that not all of these codes are used. Since some actions (like placing a particle) include communication anyways, this is handled by the way. */ void mpi_bcast_event(int event); /** Issue REQ_PLACE: move particle to a position on a node. Also calls \ref on_particle_change. \param id the particle to move. \param new if non-zero, the particle is new \param node the node to attach it to. \param pos the particles position. */ void mpi_place_particle(int node, int id, int new, double pos[3]); /** Issue REQ_SET_V: send particle velocity. Also calls \ref on_particle_change. \param part the particle. \param node the node it is attached to. \param v its new velocity. */ void mpi_send_v(int node, int part, double v[3]); /** Issue REQ_SET_F: send particle force. Also calls \ref on_particle_change. \param part the particle. \param node the node it is attached to. \param F its new force. */ void mpi_send_f(int node, int part, double F[3]); /** Issue REQ_SET_M: send particle mass. Also calls \ref on_particle_change. \param part the particle. \param node the node it is attached to. \param mass its new mass. */ void mpi_send_mass(int node, int part, double mass); /** Issue REQ_SET_Q: send particle charge. Also calls \ref on_particle_change. \param part the particle. \param node the node it is attached to. \param q its new charge. */ void mpi_send_q(int node, int part, double q); #ifdef ROTATIONAL_INERTIA /** Issue REQ_SET_ROTATIONAL_INERTIA: send particle rotational inertia. Also calls \ref on_particle_change. \param part the particle. \param node the node it is attached to. \param rinertia its new rotational inertia. */ void mpi_send_rotational_inertia(int node, int part, double rinertia[3]); #endif #ifdef ROTATION /** Issue REQ_SET_QUAT: send particle orientation. Also calls \ref on_particle_change. \param part the particle. \param node the node it is attached to. \param quat its new quaternions. */ void mpi_send_quat(int node, int part, double quat[4]); /** Issue REQ_SET_QUATU: send 0 0 1 orientation. Also calls \ref on_particle_change. \param part the particle. \param node the node it is attached to. \param quatu is derived from the quaternion. */ void mpi_send_quatu(int node, int part, double quatu[3]); /** Issue REQ_SET_LAMBDA: send particle angular velocity. Also calls \ref on_particle_change. \param part the particle. \param node the node it is attached to. \param omega its new angular velocity. */ void mpi_send_omega(int node, int part, double omega[3]); /** Issue REQ_SET_TORQUE: send particle torque. Also calls \ref on_particle_change. \param part the particle. \param node the node it is attached to. \param torque its new torque. */ void mpi_send_torque(int node, int part, double torque[3]); #endif #ifdef DIPOLES /** Issue REQ_SET_DIP: send particle dipole orientation. Also calls \ref on_particle_change. \param part the particle. \param node the node it is attached to. \param dip its new dipole orientation. */ void mpi_send_dip(int node, int part, double dip[3]); /** Issue REQ_SET_DIPM: send particle dipole moment. Also calls \ref on_particle_change. \param part the particle. \param node the node it is attached to. \param dipm its new dipole moment (absolut value). */ void mpi_send_dipm(int node, int part, double dipm); #endif #ifdef VIRTUAL_SITES /** Issue REQ_SET_DIPM: send particle dipole moment. Also calls \ref on_particle_change. \param part the particle. \param node the node it is attached to. \param isVirtual its new isVirtual. */ void mpi_send_isVirtual(int node, int part, int isVirtual); #endif /** Issue REQ_SET_TYPE: send particle type. Also calls \ref on_particle_change. \param part the particle. \param node the node it is attached to. \param type its new type. */ void mpi_send_type(int node, int part, int type); /** Issue REQ_SET_MOL_ID: send molecule id. Also calls \ref on_particle_change. \param part the particle. \param node the node it is attached to. \param mid its new mol_id. */ void mpi_send_mol_id(int node, int part, int mid); /** Issue REQ_SET_BOND: send bond. Also calls \ref on_particle_change. \param pnode node it is attached to. \param part identity of principal atom of the bond. \param bond field containing the bond type number and the identity of all bond partners (secundary atoms of the bond). \param delete if true, do not add the bond, rather delete it if found \return 1 on success or 0 if not (e. g. bond to delete does not exist) */ int mpi_send_bond(int pnode, int part, int *bond, int delete); /** Issue REQ_SET_EXCLUSION: send exclusions. Also calls \ref on_particle_change. \param part identity of first particle of the exclusion. \param part2 identity of secnd particle of the exclusion. \param delete if true, do not add the exclusion, rather delete it if found */ void mpi_send_exclusion(int part, int part2, int delete); /** Issue REQ_REM_PART: remove a particle. Also calls \ref on_particle_change. \param id the particle to remove. \param node the node it is attached to. */ void mpi_remove_particle(int node, int id); /** Issue REQ_GET_PART: recv particle data. The data has to be freed later using \ref free_particle, otherwise the dynamically allocated parts, bonds and exclusions are left over. \param part the particle. \param node the node it is attached to. \param part_data where to store the received data. \note Gets a copy of the particle data not a pointer to the actual particle used in integration */ void mpi_recv_part(int node, int part, Particle *part_data); /** Issue REQ_INTEGRATE: start integrator. @param n_steps how many steps to do. @return nonzero on error */ int mpi_integrate(int n_steps); /** Issue REQ_BCAST_IA: send new ia params. Also calls \ref on_short_range_ia_change. mpi_bcast_ia_params is used for both, bonded and non-bonded interaction parameters. Therefor i and j are used depending on their value: \param i particle type for non bonded interaction parameters / bonded interaction type number. \param j if not negative: particle type for non bonded interaction parameters / if negative: flag for bonded interaction */ void mpi_bcast_ia_params(int i, int j); /** Issue REQ_BCAST_IA_SIZE: send new size of \ref ia_params. \param s the new size for \ref ia_params. */ void mpi_bcast_n_particle_types(int s); /** Issue REQ_GATHER: gather data for analysis in \ref #analyze. \param job what to do: \param result where to store the gathered value(s):