ESPResSo 3.2.0-167-g2c9ead1-git
Extensible Simulation Package for Soft Matter Research
communication.c
Go to the documentation of this file.
00001 /*
00002   Copyright (C) 2010,2011,2012,2013 The ESPResSo project
00003   Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 
00004     Max-Planck-Institute for Polymer Research, Theory Group
00005   
00006   This file is part of ESPResSo.
00007   
00008   ESPResSo is free software: you can redistribute it and/or modify
00009   it under the terms of the GNU General Public License as published by
00010   the Free Software Foundation, either version 3 of the License, or
00011   (at your option) any later version.
00012   
00013   ESPResSo is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016   GNU General Public License for more details.
00017   
00018   You should have received a copy of the GNU General Public License
00019   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
00020 */
00021 #include <mpi.h>
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include "utils.h"
00026 #include "communication.h"
00027 #include "interaction_data.h"
00028 #include "particle_data.h"
00029 #include "integrate.h"
00030 #include "cells.h"
00031 #include "global.h"
00032 #include "grid.h"
00033 #include "initialize.h"
00034 #include "forces.h"
00035 #include "rotation.h"
00036 #include "p3m.h"
00037 #include "statistics.h"
00038 #include "energy.h"
00039 #include "pressure.h"
00040 #include "random.h"
00041 #include "lj.h"
00042 #include "lb.h"
00043 #include "lb-boundaries.h"
00044 #include "morse.h"
00045 #include "buckingham.h"
00046 #include "tab.h"
00047 #include "overlap.h"
00048 #include "ljcos.h"
00049 #include "ljangle.h"
00050 #include "gb.h"
00051 #include "mmm1d.h"
00052 #include "mmm2d.h"
00053 #include "maggs.h"
00054 #include "elc.h"
00055 #include "iccp3m.h"
00056 #include "statistics_chain.h"
00057 #include "statistics_fluid.h"
00058 #include "virtual_sites.h"
00059 #include "topology.h"
00060 #include "errorhandling.h"
00061 #include "molforces.h"
00062 #include "mdlc_correction.h"
00063 #include "reaction.h"
00064 #include "galilei.h"
00065 #include "cuda_common.h"
00066 
00067 
00068 int this_node = -1;
00069 int n_nodes = -1;
00070 MPI_Comm comm_cart;
00071 /**********************************************
00072  * slave callbacks.
00073  **********************************************/
00074 typedef void (SlaveCallback)(int node, int param);
00075 
00076 // if you want to add a callback, add it here, and here only
00077 #define CALLBACK_LIST \
00078   CB(mpi_stop_slave) \
00079   CB(mpi_bcast_parameter_slave) \
00080   CB(mpi_who_has_slave) \
00081   CB(mpi_bcast_event_slave) \
00082   CB(mpi_place_particle_slave) \
00083   CB(mpi_send_v_slave) \
00084   CB(mpi_send_f_slave) \
00085   CB(mpi_send_q_slave) \
00086   CB(mpi_send_type_slave) \
00087   CB(mpi_send_bond_slave) \
00088   CB(mpi_recv_part_slave) \
00089   CB(mpi_integrate_slave) \
00090   CB(mpi_bcast_ia_params_slave) \
00091   CB(mpi_bcast_n_particle_types_slave) \
00092   CB(mpi_gather_stats_slave) \
00093   CB(mpi_set_time_step_slave) \
00094   CB(mpi_get_particles_slave) \
00095   CB(mpi_bcast_coulomb_params_slave) \
00096   CB(mpi_send_ext_force_slave) \
00097   CB(mpi_send_ext_torque_slave) \
00098   CB(mpi_place_new_particle_slave) \
00099   CB(mpi_remove_particle_slave) \
00100   CB(mpi_bcast_constraint_slave) \
00101   CB(mpi_random_seed_slave) \
00102   CB(mpi_random_stat_slave) \
00103   CB(mpi_cap_forces_slave) \
00104   CB(mpi_bit_random_seed_slave) \
00105   CB(mpi_bit_random_stat_slave) \
00106   CB(mpi_get_constraint_force_slave) \
00107   CB(mpi_rescale_particles_slave) \
00108   CB(mpi_bcast_cell_structure_slave) \
00109   CB(mpi_send_quat_slave) \
00110   CB(mpi_send_omega_slave) \
00111   CB(mpi_send_torque_slave) \
00112   CB(mpi_send_mol_id_slave) \
00113   CB(mpi_bcast_nptiso_geom_slave) \
00114   CB(mpi_update_mol_ids_slave) \
00115   CB(mpi_sync_topo_part_info_slave) \
00116   CB(mpi_send_mass_slave) \
00117   CB(mpi_send_solvation_slave) \
00118   CB(mpi_gather_runtime_errors_slave) \
00119   CB(mpi_send_exclusion_slave) \
00120   CB(mpi_bcast_lb_params_slave) \
00121   CB(mpi_bcast_cuda_global_part_vars_slave) \
00122   CB(mpi_send_dip_slave) \
00123   CB(mpi_send_dipm_slave) \
00124   CB(mpi_send_fluid_slave) \
00125   CB(mpi_recv_fluid_slave) \
00126   CB(mpi_local_stress_tensor_slave) \
00127   CB(mpi_send_virtual_slave) \
00128   CB(mpi_bcast_tf_params_slave) \
00129   CB(mpi_iccp3m_iteration_slave) \
00130   CB(mpi_iccp3m_init_slave) \
00131   CB(mpi_send_rotational_inertia_slave) \
00132   CB(mpi_bcast_lbboundary_slave) \
00133   CB(mpi_send_mu_E_slave) \
00134   CB(mpi_bcast_max_mu_slave) \
00135   CB(mpi_send_vs_relative_slave) \
00136   CB(mpi_recv_fluid_populations_slave) \
00137   CB(mpi_send_fluid_populations_slave) \
00138   CB(mpi_recv_fluid_boundary_flag_slave) \
00139   CB(mpi_set_particle_temperature_slave) \
00140   CB(mpi_set_particle_gamma_slave) \
00141   CB(mpi_kill_particle_motion_slave) \
00142   CB(mpi_kill_particle_forces_slave) \
00143   CB(mpi_system_CMS_slave) \
00144   CB(mpi_system_CMS_velocity_slave) \
00145   CB(mpi_galilei_transform_slave) \
00146   CB(mpi_setup_reaction_slave) \
00147   CB(mpi_send_rotation_slave) \
00148 
00149 // create the forward declarations
00150 #define CB(name) void name(int node, int param);
00151 CALLBACK_LIST
00152 
00153 // create the list of callbacks
00154 #undef CB
00155 #define CB(name) name,
00156 static SlaveCallback *slave_callbacks[] = {
00157   CALLBACK_LIST
00158 };
00159 
00160 const int N_CALLBACKS = sizeof(slave_callbacks)/sizeof(SlaveCallback*);
00161 
00162 // create the list of names
00163 #undef CB
00164 #define CB(name) #name,
00165 
00166 char *names[] = {
00167   CALLBACK_LIST
00168 };
00169 
00170 // tag which is used by MPI send/recv inside the slave functions
00171 #define SOME_TAG 42
00172 
00173 
00174 /** The requests are compiled statically here, so that after a crash
00175     you can get the last issued request from the debugger. */ 
00176 static int request[3];
00177 
00178 /**********************************************
00179  * procedures
00180  **********************************************/
00181 
00182 #ifdef MPI_CORE
00183 void mpi_core(MPI_Comm *comm, int *errcode,...) {
00184   int len;
00185   char string[1024];
00186   MPI_Error_string(*errcode, string, &len);
00187   fprintf(stderr, "%d: Aborting due to MPI error %d: %s. Forcing core dump.\n", this_node, *errcode, string);
00188   core();
00189 }
00190 #endif
00191 
00192 void mpi_init(int *argc, char ***argv)
00193 {
00194 #ifdef MPI_CORE
00195   MPI_Errhandler mpi_errh;
00196 #endif
00197 
00198   MPI_Init(argc, argv);
00199 
00200   MPI_Comm_size(MPI_COMM_WORLD, &n_nodes);
00201 
00202   int periodic[3]={1,1,1}, reorder = 1;
00203   MPI_Dims_create(n_nodes, 3, node_grid);
00204 
00205   MPI_Cart_create(MPI_COMM_WORLD, 3, node_grid, periodic, reorder, &comm_cart);
00206 
00207   MPI_Comm_rank(comm_cart, &this_node);
00208 
00209   MPI_Cart_coords(comm_cart, this_node, 3, node_pos);
00210 
00211 #ifdef MPI_CORE
00212   MPI_Errhandler_create((MPI_Handler_function *)mpi_core, &mpi_errh);
00213   MPI_Errhandler_set(comm_cart, mpi_errh);
00214 #endif
00215 }
00216 
00217 static void mpi_call(SlaveCallback cb, int node, int param) {
00218   // find req number in callback array
00219   int reqcode;
00220   for (reqcode = 0; reqcode < N_CALLBACKS; reqcode++) {
00221     if (cb == slave_callbacks[reqcode]) break;
00222   }
00223 
00224   if (reqcode >= N_CALLBACKS) {
00225     fprintf(stderr, "%d: INTERNAL ERROR: unknown callback %d called\n", this_node, reqcode);
00226     errexit();
00227   }
00228 
00229   request[0] = reqcode;
00230   request[1] = node;
00231   request[2] = param;
00232 
00233   COMM_TRACE(fprintf(stderr, "%d: issuing %s %d %d\n",
00234                      this_node, names[reqcode], node, param));
00235 #ifdef ASYNC_BARRIER
00236   MPI_Barrier(comm_cart);
00237 #endif
00238   MPI_Bcast(request, 3, MPI_INT, 0, comm_cart);
00239   COMM_TRACE(fprintf(stderr, "%d: finished sending.\n", this_node));
00240 }
00241 
00242 /**************** REQ_TERM ************/
00243 
00244 static int terminated = 0;
00245 
00246 void mpi_stop()
00247 {
00248   if (terminated)
00249     return;
00250 
00251   mpi_call(mpi_stop_slave, -1, 0);
00252 
00253   MPI_Barrier(comm_cart);
00254   MPI_Finalize();
00255   regular_exit = 1;
00256   terminated = 1;
00257 }
00258 
00259 void mpi_stop_slave(int node, int param)
00260 {
00261   COMM_TRACE(fprintf(stderr, "%d: exiting\n", this_node));
00262 
00263   MPI_Barrier(comm_cart);
00264   MPI_Finalize();
00265   regular_exit = 1;
00266   exit(0);
00267 }
00268 
00269 /*************** REQ_BCAST_PAR ************/
00270 static void common_bcast_parameter(int i)
00271 {
00272   switch (fields[i].type) {
00273   case TYPE_INT:
00274     MPI_Bcast((int *)fields[i].data, fields[i].dimension,
00275               MPI_INT, 0, comm_cart);
00276     break;
00277   case TYPE_BOOL:
00278     MPI_Bcast((int *)fields[i].data, 1,
00279               MPI_INT, 0, comm_cart);
00280     break;
00281   case TYPE_DOUBLE:
00282     MPI_Bcast((double *)fields[i].data, fields[i].dimension,
00283               MPI_DOUBLE, 0, comm_cart);
00284     break;
00285   default: break;
00286   }
00287 
00288   on_parameter_change(i);
00289 }
00290 
00291 int mpi_bcast_parameter(int i)
00292 {
00293   mpi_call(mpi_bcast_parameter_slave, -1, i);
00294 
00295   common_bcast_parameter(i);
00296 
00297   return check_runtime_errors();
00298 }
00299 
00300 void mpi_bcast_parameter_slave(int node, int i)
00301 {
00302   common_bcast_parameter(i);
00303   check_runtime_errors();
00304 }
00305 
00306 /*************** REQ_WHO_HAS ****************/
00307 
00308 void mpi_who_has()
00309 {
00310   Cell *cell;
00311   int *sizes = malloc(sizeof(int)*n_nodes);
00312   int *pdata = NULL;
00313   int pdata_s = 0, i, c;
00314   int pnode;
00315   int n_part;
00316 
00317   mpi_call(mpi_who_has_slave, -1, 0);
00318 
00319   n_part = cells_get_n_particles();
00320   /* first collect number of particles on each node */
00321   MPI_Gather(&n_part, 1, MPI_INT, sizes, 1, MPI_INT, 0, comm_cart);
00322 
00323   for (i = 0; i <= max_seen_particle; i++)
00324     particle_node[i] = -1;
00325 
00326   /* then fetch particle locations */
00327   for (pnode = 0; pnode < n_nodes; pnode++) {
00328     COMM_TRACE(fprintf(stderr, "node %d reports %d particles\n",
00329                        pnode, sizes[pnode]));
00330     if (pnode == this_node) {
00331       for (c = 0; c < local_cells.n; c++) {
00332         cell = local_cells.cell[c];
00333         for (i = 0; i < cell->n; i++)
00334           particle_node[cell->part[i].p.identity] = this_node;
00335       }
00336     }
00337     else if (sizes[pnode] > 0) {
00338       if (pdata_s < sizes[pnode]) {
00339         pdata_s = sizes[pnode];
00340         pdata = (int *)realloc(pdata, sizeof(int)*pdata_s);
00341       }
00342       MPI_Recv(pdata, sizes[pnode], MPI_INT, pnode, SOME_TAG,
00343                comm_cart, MPI_STATUS_IGNORE);
00344       for (i = 0; i < sizes[pnode]; i++)
00345         particle_node[pdata[i]] = pnode;
00346     }
00347   }
00348 
00349   free(pdata);
00350   free(sizes);
00351 }
00352 
00353 void mpi_who_has_slave(int node, int param)
00354 {
00355   Cell *cell;
00356   int npart, i, c;
00357   int *sendbuf;
00358   int n_part;
00359 
00360   n_part = cells_get_n_particles();
00361   MPI_Gather(&n_part, 1, MPI_INT, NULL, 0, MPI_INT, 0, comm_cart);
00362   if (n_part == 0)
00363     return;
00364 
00365   sendbuf = malloc(sizeof(int)*n_part);
00366   npart = 0;
00367   for (c = 0; c < local_cells.n; c++) {
00368     cell = local_cells.cell[c];
00369     for (i = 0; i < cell->n; i++)
00370       sendbuf[npart++] = cell->part[i].p.identity;
00371   }
00372   MPI_Send(sendbuf, npart, MPI_INT, 0, SOME_TAG, comm_cart);
00373   free(sendbuf);
00374 }
00375 
00376 /**************** REQ_CHTOPL ***********/
00377 void mpi_bcast_event(int event)
00378 {
00379   mpi_call(mpi_bcast_event_slave, -1, event);
00380   mpi_bcast_event_slave(-1, event);
00381 }
00382 
00383 void mpi_bcast_event_slave(int node, int event)
00384 {
00385   switch (event) {
00386 #ifdef ELECTROSTATICS
00387 #ifdef P3M
00388   case P3M_COUNT_CHARGES:
00389     p3m_count_charged_particles();
00390     break;
00391 #endif
00392   case MAGGS_COUNT_CHARGES:
00393     maggs_count_charged_particles();
00394     break; 
00395 #endif
00396   case INVALIDATE_SYSTEM:
00397     local_invalidate_system();
00398     break;
00399 #ifdef ADDITIONAL_CHECKS
00400   case CHECK_PARTICLES:
00401     check_particles();
00402     break;
00403 #endif
00404 
00405 #ifdef DP3M
00406   case P3M_COUNT_DIPOLES:
00407     dp3m_count_magnetic_particles();
00408     break;
00409 #endif
00410 
00411   default:;
00412   }
00413 }
00414 
00415 /****************** REQ_PLACE/REQ_PLACE_NEW ************/
00416 
00417 void mpi_place_particle(int pnode, int part, double p[3])
00418 {
00419   mpi_call(mpi_place_particle_slave, pnode, part);
00420 
00421   if (pnode == this_node)
00422     local_place_particle(part, p, 0);
00423   else
00424     MPI_Send(p, 3, MPI_DOUBLE, pnode, SOME_TAG, comm_cart);
00425 
00426   on_particle_change();
00427 }
00428 
00429 void mpi_place_particle_slave(int pnode, int part)
00430 {
00431   double p[3];
00432   
00433   if (pnode == this_node) {
00434     MPI_Recv(p, 3, MPI_DOUBLE, 0, SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
00435     local_place_particle(part, p, 0);
00436   }
00437 
00438   on_particle_change();
00439 }
00440 
00441 void mpi_place_new_particle(int pnode, int part, double p[3])
00442 {
00443   mpi_call(mpi_place_new_particle_slave, pnode, part);
00444   added_particle(part);
00445 
00446   if (pnode == this_node)
00447     local_place_particle(part, p, 1);
00448   else
00449     MPI_Send(p, 3, MPI_DOUBLE, pnode, SOME_TAG, comm_cart);
00450 
00451   on_particle_change();
00452 }
00453 
00454 
00455 void mpi_place_new_particle_slave(int pnode, int part)
00456 {
00457   double p[3];
00458   
00459   added_particle(part);
00460 
00461   if (pnode == this_node) {
00462     MPI_Recv(p, 3, MPI_DOUBLE, 0, SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
00463     local_place_particle(part, p, 1);
00464   }
00465 
00466   on_particle_change();
00467 }
00468 
00469 /****************** REQ_SET_V ************/
00470 void mpi_send_v(int pnode, int part, double v[3])
00471 {
00472   mpi_call(mpi_send_v_slave, pnode, part);
00473 
00474   if (pnode == this_node) {
00475     Particle *p = local_particles[part];
00476     memcpy(p->m.v, v, 3*sizeof(double));
00477   }
00478   else
00479     MPI_Send(v, 3, MPI_DOUBLE, pnode, SOME_TAG, comm_cart);
00480 
00481   on_particle_change();
00482 }
00483 
00484 void mpi_send_v_slave(int pnode, int part)
00485 {
00486   if (pnode == this_node) {
00487     Particle *p = local_particles[part];
00488         MPI_Recv(p->m.v, 3, MPI_DOUBLE, 0, SOME_TAG,
00489              comm_cart, MPI_STATUS_IGNORE);
00490   }
00491 
00492   on_particle_change();
00493 }
00494 
00495 /****************** REQ_SET_F ************/
00496 void mpi_send_f(int pnode, int part, double F[3])
00497 {
00498   mpi_call(mpi_send_f_slave, pnode, part);
00499 
00500   if (pnode == this_node) {
00501     Particle *p = local_particles[part];
00502     memcpy(p->f.f, F, 3*sizeof(double));
00503   }
00504   else
00505     MPI_Send(F, 3, MPI_DOUBLE, pnode, SOME_TAG, comm_cart);
00506 
00507   on_particle_change();
00508 }
00509 
00510 void mpi_send_f_slave(int pnode, int part)
00511 {
00512   if (pnode == this_node) {
00513     Particle *p = local_particles[part];
00514         MPI_Recv(p->f.f, 3, MPI_DOUBLE, 0, SOME_TAG,
00515              comm_cart, MPI_STATUS_IGNORE);
00516   }
00517 
00518   on_particle_change();
00519 }
00520 
00521 /********************* REQ_SET_Q ********/
00522 void mpi_send_q(int pnode, int part, double q)
00523 {
00524 #ifdef ELECTROSTATICS
00525   mpi_call(mpi_send_q_slave, pnode, part);
00526 
00527   if (pnode == this_node) {
00528     Particle *p = local_particles[part];
00529     p->p.q = q;
00530   }
00531   else {
00532     MPI_Send(&q, 1, MPI_DOUBLE, pnode, SOME_TAG, comm_cart);
00533   }
00534 
00535   on_particle_change();
00536 #endif
00537 }
00538 
00539 void mpi_send_q_slave(int pnode, int part)
00540 {
00541 #ifdef ELECTROSTATICS
00542   if (pnode == this_node) {
00543     Particle *p = local_particles[part];
00544         MPI_Recv(&p->p.q, 1, MPI_DOUBLE, 0, SOME_TAG,
00545              comm_cart, MPI_STATUS_IGNORE);
00546   }
00547 
00548   on_particle_change();
00549 #endif
00550 }
00551 
00552 /********************* REQ_SET_MU_E ********/
00553 void mpi_send_mu_E(int pnode, int part, double mu_E[3])
00554 {
00555 #ifdef LB_ELECTROHYDRODYNAMICS
00556   mpi_call(mpi_send_mu_E_slave, pnode, part);
00557 
00558   if (pnode == this_node) {
00559     Particle *p = local_particles[part];
00560     p->p.mu_E[0] = mu_E[0];
00561     p->p.mu_E[1] = mu_E[1];
00562     p->p.mu_E[2] = mu_E[2];
00563   }
00564   else {
00565     MPI_Send(&mu_E, 3, MPI_DOUBLE, pnode, SOME_TAG, comm_cart);
00566   }
00567 
00568   on_particle_change();
00569 #endif
00570 }
00571 
00572 void mpi_send_mu_E_slave(int pnode, int part)
00573 {
00574 #ifdef LB_ELECTROHYDRODYNAMICS
00575   if (pnode == this_node) {
00576     Particle *p = local_particles[part];
00577         MPI_Recv(&p->p.mu_E, 3, MPI_DOUBLE, 0, SOME_TAG,
00578              comm_cart, MPI_STATUS_IGNORE);
00579   }
00580 
00581   on_particle_change();
00582 #endif
00583 }
00584 
00585 /********************* REQ_SET_SOLV ********/
00586 void mpi_send_solvation(int pnode, int part, double* solvation)
00587 {
00588 #ifdef SHANCHEN
00589   int ii;
00590   mpi_call(mpi_send_solvation_slave, pnode, part);
00591 
00592   if (pnode == this_node) {
00593     Particle *p = local_particles[part];
00594     for(ii=0;ii<2*LB_COMPONENTS;ii++)
00595        p->p.solvation[ii]= solvation[ii];
00596   }
00597   else {
00598     MPI_Send(&solvation, LB_COMPONENTS, MPI_DOUBLE, pnode, SOME_TAG, comm_cart);
00599   }
00600 
00601   on_particle_change();
00602 #endif
00603 }
00604 
00605 void mpi_send_solvation_slave(int pnode, int part)
00606 {
00607 #ifdef SHANCHEN
00608   if (pnode == this_node) {
00609     Particle *p = local_particles[part];
00610         MPI_Recv(&p->p.solvation, 2*LB_COMPONENTS, MPI_DOUBLE, 0, SOME_TAG,
00611              comm_cart, MPI_STATUS_IGNORE);
00612   }
00613 
00614   on_particle_change();
00615 #endif
00616 }
00617 
00618 /********************* REQ_SET_M ********/
00619 void mpi_send_mass(int pnode, int part, double mass)
00620 {
00621 #ifdef MASS
00622   mpi_call(mpi_send_mass_slave, pnode, part);
00623 
00624   if (pnode == this_node) {
00625     Particle *p = local_particles[part];
00626     p->p.mass = mass;
00627   }
00628   else {
00629     MPI_Send(&mass, 1, MPI_DOUBLE, pnode, SOME_TAG, comm_cart);
00630   }
00631 
00632   on_particle_change();
00633 #endif
00634 }
00635 
00636 void mpi_send_mass_slave(int pnode, int part)
00637 {
00638 #ifdef MASS
00639   if (pnode == this_node) {
00640     Particle *p = local_particles[part];
00641         MPI_Recv(&p->p.mass, 1, MPI_DOUBLE, 0, SOME_TAG,
00642              comm_cart, MPI_STATUS_IGNORE);
00643   }
00644 
00645   on_particle_change();
00646 #endif
00647 }
00648 
00649 /********************* REQ_SET_RINERTIA ********/
00650 
00651 void mpi_send_rotational_inertia(int pnode, int part, double rinertia[3])
00652 {
00653 #ifdef ROTATIONAL_INERTIA
00654   mpi_call(mpi_send_rotational_inertia_slave, pnode, part);
00655 
00656   if (pnode == this_node) {
00657     Particle *p = local_particles[part];
00658     p->p.rinertia[0] = rinertia[0];
00659     p->p.rinertia[1] = rinertia[1];
00660     p->p.rinertia[2] = rinertia[2];
00661   }
00662   else {
00663     MPI_Send(rinertia, 3, MPI_DOUBLE, pnode, SOME_TAG, comm_cart);
00664   }
00665 
00666   on_particle_change();
00667 #endif
00668 }
00669 
00670 void mpi_send_rotational_inertia_slave(int pnode, int part)
00671 {
00672 #ifdef ROTATIONAL_INERTIA
00673   if (pnode == this_node) {
00674     Particle *p = local_particles[part];
00675         MPI_Recv(p->p.rinertia, 3, MPI_DOUBLE, 0, SOME_TAG,
00676              comm_cart, MPI_STATUS_IGNORE);
00677   }
00678 
00679   on_particle_change();
00680 #endif
00681 }
00682 
00683 /********************* REQ_SET_TYPE ********/
00684 void mpi_send_type(int pnode, int part, int type)
00685 {
00686   mpi_call(mpi_send_type_slave, pnode, part);
00687 
00688   if (pnode == this_node) {
00689     Particle *p = local_particles[part];
00690     p->p.type = type;
00691   }
00692   else
00693     MPI_Send(&type, 1, MPI_INT, pnode, SOME_TAG, comm_cart);
00694 
00695   on_particle_change();
00696 }
00697 
00698 void mpi_send_type_slave(int pnode, int part)
00699 {
00700   if (pnode == this_node) {
00701     Particle *p = local_particles[part];
00702         MPI_Recv(&p->p.type, 1, MPI_INT, 0, SOME_TAG,
00703              comm_cart, MPI_STATUS_IGNORE);
00704   }
00705 
00706   on_particle_change();
00707 }
00708 
00709 /********************* REQ_SET_MOLID ********/
00710 void mpi_send_mol_id(int pnode, int part, int mid)
00711 {
00712   mpi_call(mpi_send_mol_id_slave, pnode, part);
00713 
00714   if (pnode == this_node) {
00715     Particle *p = local_particles[part];
00716     p->p.mol_id = mid;
00717   }
00718   else
00719     MPI_Send(&mid, 1, MPI_INT, pnode, SOME_TAG, comm_cart);
00720 
00721   on_particle_change();
00722 }
00723 
00724 void mpi_send_mol_id_slave(int pnode, int part)
00725 {
00726   if (pnode == this_node) {
00727     Particle *p = local_particles[part];
00728         MPI_Recv(&p->p.mol_id, 1, MPI_INT, 0, SOME_TAG,
00729              comm_cart, MPI_STATUS_IGNORE);
00730   }
00731 
00732   on_particle_change();
00733 }
00734 
00735 /********************* REQ_SET_QUAT ********/
00736 
00737 void mpi_send_quat(int pnode, int part, double quat[4])
00738 {
00739 #ifdef ROTATION
00740   mpi_call(mpi_send_quat_slave, pnode, part);
00741 
00742   if (pnode == this_node) {
00743     Particle *p = local_particles[part];
00744     p->r.quat[0] = quat[0];
00745     p->r.quat[1] = quat[1];
00746     p->r.quat[2] = quat[2];
00747     p->r.quat[3] = quat[3];
00748     convert_quat_to_quatu(p->r.quat, p->r.quatu);
00749 #ifdef DIPOLES
00750     convert_quatu_to_dip(p->r.quatu, p->p.dipm, p->r.dip);
00751 #endif
00752   }
00753   else {
00754     MPI_Send(quat, 4, MPI_DOUBLE, pnode, SOME_TAG, comm_cart);
00755   }
00756 
00757   on_particle_change();
00758 #endif
00759 }
00760 
00761 void mpi_send_quat_slave(int pnode, int part)
00762 {
00763 #ifdef ROTATION
00764   if (pnode == this_node) {
00765     Particle *p = local_particles[part];
00766         MPI_Recv(p->r.quat, 4, MPI_DOUBLE, 0, SOME_TAG,
00767              comm_cart, MPI_STATUS_IGNORE);
00768     convert_quat_to_quatu(p->r.quat, p->r.quatu);
00769 #ifdef DIPOLES
00770     convert_quatu_to_dip(p->r.quatu, p->p.dipm, p->r.dip);
00771 #endif
00772   }
00773 
00774   on_particle_change();
00775 #endif
00776 }
00777 
00778 /********************* REQ_SET_OMEGA ********/
00779 
00780 void mpi_send_omega(int pnode, int part, double omega[3])
00781 {
00782 #ifdef ROTATION
00783   mpi_call(mpi_send_omega_slave, pnode, part);
00784 
00785   if (pnode == this_node) {
00786    Particle *p = local_particles[part];
00787 /*  memcpy(p->omega, omega, 3*sizeof(double));*/
00788     p->m.omega[0] = omega[0];
00789     p->m.omega[1] = omega[1];
00790     p->m.omega[2] = omega[2];
00791   }
00792   else {
00793     MPI_Send(omega, 3, MPI_DOUBLE, pnode, SOME_TAG, comm_cart);
00794   }
00795 
00796   on_particle_change();
00797 #endif
00798 }
00799 
00800 void mpi_send_omega_slave(int pnode, int part)
00801 {
00802 #ifdef ROTATION
00803   if (pnode == this_node) {
00804     Particle *p = local_particles[part];
00805         MPI_Recv(p->m.omega, 3, MPI_DOUBLE, 0, SOME_TAG,
00806              comm_cart, MPI_STATUS_IGNORE);
00807   }
00808 
00809   on_particle_change();
00810 #endif
00811 }
00812 
00813 /********************* REQ_SET_TORQUE ********/
00814 
00815 void mpi_send_torque(int pnode, int part, double torque[3])
00816 {
00817 #ifdef ROTATION
00818   mpi_call(mpi_send_torque_slave, pnode, part);
00819 
00820   if (pnode == this_node) {
00821     Particle *p = local_particles[part];
00822     p->f.torque[0] = torque[0];
00823     p->f.torque[1] = torque[1];
00824     p->f.torque[2] = torque[2];
00825   }
00826   else {
00827     MPI_Send(torque, 3, MPI_DOUBLE, pnode, SOME_TAG, comm_cart);
00828   }
00829 
00830   on_particle_change();
00831 #endif
00832 }
00833 
00834 void mpi_send_torque_slave(int pnode, int part)
00835 {
00836 #ifdef ROTATION
00837   if (pnode == this_node) {
00838     Particle *p = local_particles[part];
00839         MPI_Recv(p->f.torque, 3, MPI_DOUBLE, 0, SOME_TAG,
00840              comm_cart, MPI_STATUS_IGNORE);
00841   }
00842 
00843   on_particle_change();
00844 #endif
00845 }
00846 
00847 /********************* REQ_SET_DIP ********/
00848 
00849 void mpi_send_dip(int pnode, int part, double dip[3])
00850 {
00851 #ifdef DIPOLES
00852   mpi_call(mpi_send_dip_slave, pnode, part);
00853 
00854   if (pnode == this_node) {
00855     Particle *p = local_particles[part];
00856     p->r.dip[0] = dip[0];
00857     p->r.dip[1] = dip[1];
00858     p->r.dip[2] = dip[2];
00859 #ifdef ROTATION
00860     convert_dip_to_quat(p->r.dip, p->r.quat, &p->p.dipm);
00861     convert_quat_to_quatu(p->r.quat, p->r.quatu);
00862 #else
00863     p->p.dipm = sqrt(p->r.dip[0]*p->r.dip[0] + p->r.dip[1]*p->r.dip[1] + p->r.dip[2]*p->r.dip[2]);
00864 #endif
00865   }
00866   else {
00867     MPI_Send(dip, 3, MPI_DOUBLE, pnode, SOME_TAG, comm_cart);
00868   }
00869 
00870   on_particle_change();
00871 #endif
00872 }
00873 
00874 void mpi_send_dip_slave(int pnode, int part)
00875 {
00876 #ifdef DIPOLES
00877   if (pnode == this_node) {
00878     Particle *p = local_particles[part];
00879         MPI_Recv(p->r.dip, 3, MPI_DOUBLE, 0, SOME_TAG,
00880              comm_cart, MPI_STATUS_IGNORE);
00881 #ifdef ROTATION
00882     convert_dip_to_quat(p->r.dip, p->r.quat, &p->p.dipm);
00883     convert_quat_to_quatu(p->r.quat, p->r.quatu);
00884 #else
00885     p->p.dipm = sqrt(p->r.dip[0]*p->r.dip[0] + p->r.dip[1]*p->r.dip[1] + p->r.dip[2]*p->r.dip[2]);
00886 #endif
00887   }
00888 
00889   on_particle_change();
00890 #endif
00891 }
00892 
00893 /********************* REQ_SET_DIPM ********/
00894 
00895 void mpi_send_dipm(int pnode, int part, double dipm)
00896 {
00897 #ifdef DIPOLES
00898   mpi_call(mpi_send_dipm_slave, pnode, part);
00899 
00900   if (pnode == this_node) {
00901     Particle *p = local_particles[part];
00902     p->p.dipm = dipm;
00903 #ifdef ROTATION
00904     convert_quatu_to_dip(p->r.quatu, p->p.dipm, p->r.dip);
00905 #endif
00906   }
00907   else {
00908     MPI_Send(&dipm, 1, MPI_DOUBLE, pnode, SOME_TAG, comm_cart);
00909   }
00910 
00911   on_particle_change();
00912 #endif
00913 }
00914 
00915 void mpi_send_dipm_slave(int pnode, int part)
00916 {
00917 #ifdef DIPOLES
00918   if (pnode == this_node) {
00919     Particle *p = local_particles[part];
00920         MPI_Recv(&p->p.dipm, 1, MPI_DOUBLE, 0, SOME_TAG,
00921              comm_cart, MPI_STATUS_IGNORE);
00922 #ifdef ROTATION
00923     convert_quatu_to_dip(p->r.quatu, p->p.dipm, p->r.dip);
00924 #endif
00925   }
00926 
00927   on_particle_change();
00928 #endif
00929 }
00930 
00931 /********************* REQ_SET_ISVI ********/
00932 
00933 void mpi_send_virtual(int pnode, int part, int isVirtual)
00934 {
00935 #ifdef VIRTUAL_SITES
00936   mpi_call(mpi_send_virtual_slave, pnode, part);
00937 
00938   if (pnode == this_node) {
00939     Particle *p = local_particles[part];
00940     p->p.isVirtual = isVirtual;
00941   }
00942   else {
00943     MPI_Send(&isVirtual, 1, MPI_INT, pnode, SOME_TAG, comm_cart);
00944   }
00945 
00946   on_particle_change();
00947 #endif
00948 }
00949 
00950 void mpi_send_virtual_slave(int pnode, int part)
00951 {
00952 #ifdef VIRTUAL_SITES
00953   if (pnode == this_node) {
00954     Particle *p = local_particles[part];
00955         MPI_Recv(&p->p.isVirtual, 1, MPI_INT, 0, SOME_TAG,
00956              comm_cart, MPI_STATUS_IGNORE);
00957   }
00958 
00959   on_particle_change();
00960 #endif
00961 }
00962 
00963 /********************* REQ_SET_BOND ********/
00964 
00965 void mpi_send_vs_relative(int pnode, int part, int vs_relative_to, double vs_distance)
00966 {
00967 #ifdef VIRTUAL_SITES_RELATIVE
00968   mpi_call(mpi_send_vs_relative_slave, pnode, part);
00969 
00970   // If the particle is on the node on which this function was called
00971   // set the values locally
00972   if (pnode == this_node) {
00973     Particle *p = local_particles[part];
00974     p->p.vs_relative_to_particle_id = vs_relative_to;
00975     p->p.vs_relative_distance = vs_distance;
00976   }
00977   else {
00978     MPI_Send(&vs_relative_to, 1, MPI_INT, pnode, SOME_TAG, comm_cart);
00979     MPI_Send(&vs_distance, 1, MPI_DOUBLE, pnode, SOME_TAG, comm_cart);
00980   }
00981 
00982   on_particle_change();
00983 #endif
00984 }
00985 
00986 void mpi_send_vs_relative_slave(int pnode, int part)
00987 {
00988 #ifdef VIRTUAL_SITES_RELATIVE
00989   if (pnode == this_node) {
00990     Particle *p = local_particles[part];
00991         MPI_Recv(&p->p.vs_relative_to_particle_id, 1, MPI_INT, 0, SOME_TAG,
00992              comm_cart, MPI_STATUS_IGNORE);
00993     MPI_Recv(&p->p.vs_relative_distance, 1, MPI_DOUBLE, 0, SOME_TAG,
00994              comm_cart, MPI_STATUS_IGNORE);
00995   }
00996 
00997   on_particle_change();
00998 #endif
00999 }
01000 
01001 // ********************************
01002 
01003 void mpi_send_rotation(int pnode, int part, int rot)
01004 {
01005 #ifdef ROTATION_PER_PARTICLE
01006   mpi_call(mpi_send_rotation_slave, pnode, part);
01007 
01008   if (pnode == this_node) {
01009     Particle *p = local_particles[part];
01010     p->p.rotation = rot;
01011   }
01012   else {
01013     MPI_Send(&rot, 1, MPI_INT, pnode, SOME_TAG, MPI_COMM_WORLD);
01014   }
01015 
01016   on_particle_change();
01017 #endif
01018 }
01019 
01020 void mpi_send_rotation_slave(int pnode, int part)
01021 {
01022 #ifdef ROTATION_PER_PARTICLE
01023   if (pnode == this_node) {
01024     Particle *p = local_particles[part];
01025     MPI_Status status;
01026     MPI_Recv(&p->p.rotation, 1, MPI_INT, 0, SOME_TAG,
01027              MPI_COMM_WORLD, &status);
01028   }
01029 
01030   on_particle_change();
01031 #endif
01032 }
01033 
01034 /********************* REQ_SET_BOND ********/
01035 
01036 
01037 int mpi_send_bond(int pnode, int part, int *bond, int delete)
01038 {
01039   int bond_size, stat=0;
01040   
01041   mpi_call(mpi_send_bond_slave, pnode, part);
01042 
01043   bond_size = (bond) ? bonded_ia_params[bond[0]].num + 1 : 0;
01044 
01045   if (pnode == this_node) {
01046     stat = local_change_bond(part, bond, delete);
01047     on_particle_change();
01048     return stat;
01049   }
01050   /* else */
01051   MPI_Send(&bond_size, 1, MPI_INT, pnode, SOME_TAG, comm_cart);
01052   if (bond_size)
01053     MPI_Send(bond, bond_size, MPI_INT, pnode, SOME_TAG, comm_cart);
01054   MPI_Send(&delete, 1, MPI_INT, pnode, SOME_TAG, comm_cart);
01055   MPI_Recv(&stat, 1, MPI_INT, pnode, SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
01056   on_particle_change();
01057   return stat;
01058 }
01059 
01060 void mpi_send_bond_slave(int pnode, int part)
01061 {
01062   int bond_size=0, *bond, delete=0, stat;
01063   
01064   if (pnode == this_node) {
01065     MPI_Recv(&bond_size, 1, MPI_INT, 0, SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
01066     if (bond_size) {
01067       bond = (int *)malloc(bond_size*sizeof(int));
01068       MPI_Recv(bond, bond_size, MPI_INT, 0, SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
01069     }
01070     else
01071       bond = NULL;
01072     MPI_Recv(&delete, 1, MPI_INT, 0, SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
01073     stat = local_change_bond(part, bond, delete);
01074     if (bond)
01075       free(bond);
01076     MPI_Send(&stat, 1, MPI_INT, 0, SOME_TAG, comm_cart);
01077   }
01078 
01079   on_particle_change();
01080 }
01081 
01082 /****************** REQ_GET_PART ************/
01083 void mpi_recv_part(int pnode, int part, Particle *pdata)
01084 {
01085   IntList *bl = &(pdata->bl);
01086 #ifdef EXCLUSIONS
01087   IntList *el = &(pdata->el);
01088 #endif
01089   
01090   /* fetch fixed data */
01091   if (pnode == this_node)
01092     memcpy(pdata, local_particles[part], sizeof(Particle));
01093   else {
01094     mpi_call(mpi_recv_part_slave, pnode, part);
01095     MPI_Recv(pdata, sizeof(Particle), MPI_BYTE, pnode,
01096              SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
01097   }
01098 
01099   /* copy dynamic data */
01100   /* bonds */
01101   bl->max = bl->n;
01102   if (bl->n > 0) {
01103     alloc_intlist(bl, bl->n);
01104     if (pnode == this_node)
01105       memcpy(bl->e, local_particles[part]->bl.e, sizeof(int)*bl->n);
01106     else
01107       MPI_Recv(bl->e, bl->n, MPI_INT, pnode,
01108                SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
01109   }
01110   else
01111     bl->e = NULL;
01112 
01113 #ifdef EXCLUSIONS
01114   /* exclusions */
01115   el->max = el->n;
01116   if (el->n > 0) {
01117     alloc_intlist(el, el->n);
01118     if (pnode == this_node)
01119       memcpy(el->e, local_particles[part]->el.e, sizeof(int)*el->n);
01120     else
01121       MPI_Recv(el->e, el->n, MPI_INT, pnode,
01122                SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
01123   }
01124   else
01125     el->e = NULL;
01126 #endif
01127 }
01128 
01129 void mpi_recv_part_slave(int pnode, int part)
01130 {
01131   Particle *p;
01132   if (pnode != this_node)
01133     return;
01134 
01135   p = local_particles[part];
01136 
01137   MPI_Send(p, sizeof(Particle), MPI_BYTE, 0, SOME_TAG,
01138            comm_cart);
01139   if (p->bl.n > 0)
01140     MPI_Send(p->bl.e, p->bl.n, MPI_INT, 0, SOME_TAG,
01141              comm_cart);
01142 #ifdef EXCLUSIONS
01143   if (p->el.n > 0)
01144     MPI_Send(p->el.e, p->el.n, MPI_INT, 0, SOME_TAG,
01145              comm_cart);
01146 #endif
01147 }
01148 
01149 /****************** REQ_REM_PART ************/
01150 void mpi_remove_particle(int pnode, int part)
01151 {
01152   mpi_call(mpi_remove_particle_slave, pnode, part);
01153   mpi_remove_particle_slave(pnode, part);
01154 }
01155 
01156 void mpi_remove_particle_slave(int pnode, int part)
01157 {
01158   if (part != -1) {
01159     n_total_particles--;
01160 
01161     if (pnode == this_node)
01162       local_remove_particle(part);
01163     
01164     remove_all_bonds_to(part);
01165   }
01166   else
01167     local_remove_all_particles();
01168 
01169   on_particle_change();
01170 }
01171 
01172 /********************* REQ_INTEGRATE ********/
01173 int mpi_integrate(int n_steps)
01174 {
01175   mpi_call(mpi_integrate_slave, -1, n_steps);
01176 
01177   integrate_vv(n_steps);
01178 
01179   COMM_TRACE(fprintf(stderr, "%d: integration task %d done.\n", this_node, n_steps));
01180 
01181   return check_runtime_errors();
01182 }
01183 
01184 void mpi_integrate_slave(int pnode, int task)
01185 {
01186   integrate_vv(task);
01187   COMM_TRACE(fprintf(stderr, "%d: integration task %d done.\n", this_node, task));
01188 
01189   check_runtime_errors();
01190 }
01191 
01192 /*************** REQ_BCAST_IA ************/
01193 void mpi_bcast_ia_params(int i, int j)
01194 {
01195   mpi_call(mpi_bcast_ia_params_slave, i, j);
01196 #ifdef TABULATED
01197   int tablesize = tabulated_forces.max;
01198 #endif
01199 #ifdef INTERFACE_CORRECTION
01200   int adress_tablesize = adress_tab_forces.max;
01201 #endif
01202   
01203   if (j>=0) {
01204     /* non-bonded interaction parameters */
01205     /* INCOMPATIBLE WHEN NODES USE DIFFERENT ARCHITECTURES */
01206     MPI_Bcast(get_ia_param(i, j), sizeof(IA_parameters), MPI_BYTE,
01207               0, comm_cart);
01208 
01209     copy_ia_params(get_ia_param(j, i), get_ia_param(i, j));
01210 
01211 #ifdef TABULATED
01212     /* If there are tabulated forces broadcast those as well */
01213     if ( get_ia_param(i,j)->TAB_maxval > 0) {
01214       /* First let all nodes know the new size for force and energy tables */
01215       MPI_Bcast(&tablesize, 1, MPI_INT, 0, comm_cart);
01216 
01217       /* Communicate the data */
01218       MPI_Bcast(tabulated_forces.e,tablesize, MPI_DOUBLE, 0 , comm_cart);
01219       MPI_Bcast(tabulated_energies.e,tablesize, MPI_DOUBLE, 0 , comm_cart);
01220     }    
01221 #endif
01222 #ifdef INTERFACE_CORRECTION
01223     if(get_ia_param(i,j)->ADRESS_TAB_maxval > 0) {
01224       MPI_Bcast(&adress_tablesize, 1, MPI_INT, 0, comm_cart);
01225       
01226       /* Communicate the data */
01227       MPI_Bcast(adress_tab_forces.e, adress_tablesize, MPI_DOUBLE, 0, comm_cart);
01228       MPI_Bcast(adress_tab_energies.e, adress_tablesize, MPI_DOUBLE, 0, comm_cart);
01229     }
01230     /* NO IC FOR TABULATED BONDED INTERACTIONS YET!! */
01231 #endif
01232   }
01233   else {
01234     /* bonded interaction parameters */
01235     /* INCOMPATIBLE WHEN NODES USE DIFFERENT ARCHITECTURES */
01236     MPI_Bcast(&(bonded_ia_params[i]),sizeof(Bonded_ia_parameters), MPI_BYTE,
01237               0, comm_cart);
01238 #ifdef TABULATED
01239     /* For tabulated potentials we have to send the tables extra */
01240     if(bonded_ia_params[i].type == BONDED_IA_TABULATED) {
01241       int size = bonded_ia_params[i].p.tab.npoints;
01242       MPI_Bcast(bonded_ia_params[i].p.tab.f, size, MPI_DOUBLE, 0 , comm_cart);
01243       MPI_Bcast(bonded_ia_params[i].p.tab.e, size, MPI_DOUBLE, 0 , comm_cart);
01244     }
01245 #endif
01246 #ifdef OVERLAPPED
01247     /* For overlapped potentials we have to send the ovelapped-functions extra */
01248     if(bonded_ia_params[i].type == BONDED_IA_OVERLAPPED) {
01249       int size = bonded_ia_params[i].p.overlap.noverlaps;
01250       MPI_Bcast(bonded_ia_params[i].p.overlap.para_a, size, MPI_DOUBLE, 0 , comm_cart);
01251       MPI_Bcast(bonded_ia_params[i].p.overlap.para_b, size, MPI_DOUBLE, 0 , comm_cart);
01252       MPI_Bcast(bonded_ia_params[i].p.overlap.para_c, size, MPI_DOUBLE, 0 , comm_cart);
01253     }
01254 #endif
01255   }
01256   
01257   on_short_range_ia_change();
01258 }
01259 
01260 void mpi_bcast_ia_params_slave(int i, int j)
01261 {
01262   if(j >= 0) { /* non-bonded interaction parameters */
01263     /* INCOMPATIBLE WHEN NODES USE DIFFERENT ARCHITECTURES */
01264     MPI_Bcast(get_ia_param(i, j), sizeof(IA_parameters), MPI_BYTE,
01265               0, comm_cart);
01266 
01267     copy_ia_params(get_ia_param(j, i), get_ia_param(i, j));
01268 
01269 #ifdef TABULATED
01270     {
01271       int tablesize=0;
01272       /* If there are tabulated forces broadcast those as well */
01273       if ( get_ia_param(i,j)->TAB_maxval > 0) {
01274         /* Determine the new size for force and energy tables */
01275         MPI_Bcast(&tablesize,1,MPI_INT,0,comm_cart);
01276         /* Allocate sizes accordingly */
01277         realloc_doublelist(&tabulated_forces, tablesize);
01278         realloc_doublelist(&tabulated_energies, tablesize);
01279         /* Now communicate the data */
01280         MPI_Bcast(tabulated_forces.e,tablesize, MPI_DOUBLE, 0 , comm_cart);
01281         MPI_Bcast(tabulated_energies.e,tablesize, MPI_DOUBLE, 0 , comm_cart);
01282       }
01283     }
01284 #endif
01285 #ifdef INTERFACE_CORRECTION 
01286     {
01287       int adress_tabsize=0;
01288       if ( get_ia_param(i,j)->ADRESS_TAB_maxval > 0) {
01289         MPI_Bcast(&adress_tabsize,1,MPI_INT,0,comm_cart);
01290         realloc_doublelist(&adress_tab_forces, adress_tabsize);
01291         realloc_doublelist(&adress_tab_energies, adress_tabsize);
01292         MPI_Bcast(adress_tab_forces.e,adress_tabsize, MPI_DOUBLE, 0, comm_cart);
01293         MPI_Bcast(adress_tab_energies.e,adress_tabsize, MPI_DOUBLE, 0, comm_cart);
01294       }
01295     }
01296 #endif
01297   }
01298   else { /* bonded interaction parameters */
01299     make_bond_type_exist(i); /* realloc bonded_ia_params on slave nodes! */
01300     MPI_Bcast(&(bonded_ia_params[i]),sizeof(Bonded_ia_parameters), MPI_BYTE,
01301               0, comm_cart);
01302 #ifdef TABULATED
01303     /* For tabulated potentials we have to send the tables extra */
01304     if(bonded_ia_params[i].type == BONDED_IA_TABULATED) {
01305       int size = bonded_ia_params[i].p.tab.npoints;
01306       /* alloc force and energy tables on slave nodes! */
01307       bonded_ia_params[i].p.tab.f = (double*)malloc(size*sizeof(double));
01308       bonded_ia_params[i].p.tab.e = (double*)malloc(size*sizeof(double));
01309       MPI_Bcast(bonded_ia_params[i].p.tab.f, size, MPI_DOUBLE, 0 , comm_cart);
01310       MPI_Bcast(bonded_ia_params[i].p.tab.e, size, MPI_DOUBLE, 0 , comm_cart);
01311     }
01312 #endif
01313 #ifdef OVERLAPPED
01314     /* For overlapped potentials we have to send the ovelapped-functions extra */
01315     if(bonded_ia_params[i].type == BONDED_IA_OVERLAPPED) {
01316       int size = bonded_ia_params[i].p.overlap.noverlaps;
01317       /* alloc overlapped parameter arrays on slave nodes! */
01318       bonded_ia_params[i].p.overlap.para_a = (double*)malloc(size*sizeof(double));
01319       bonded_ia_params[i].p.overlap.para_b = (double*)malloc(size*sizeof(double));
01320       bonded_ia_params[i].p.overlap.para_c = (double*)malloc(size*sizeof(double));
01321       MPI_Bcast(bonded_ia_params[i].p.overlap.para_a, size, MPI_DOUBLE, 0 , comm_cart);
01322       MPI_Bcast(bonded_ia_params[i].p.overlap.para_b, size, MPI_DOUBLE, 0 , comm_cart);
01323       MPI_Bcast(bonded_ia_params[i].p.overlap.para_c, size, MPI_DOUBLE, 0 , comm_cart);
01324     }
01325 #endif
01326   }
01327 
01328   on_short_range_ia_change();
01329 }
01330 
01331 /*************** REQ_BCAST_IA_SIZE ************/
01332 
01333 /* #ifdef THERMODYNAMIC_FORCE */
01334 void mpi_bcast_tf_params(int i)
01335 {
01336 #ifdef ADRESS
01337   int tablesize=0;
01338   
01339   mpi_call(mpi_bcast_tf_params_slave, i, i);
01340   tablesize = thermodynamic_forces.max;
01341   
01342   /* thermodynamic force parameters */
01343   /* non-bonded interaction parameters */
01344   /* INCOMPATIBLE WHEN NODES USE DIFFERENT ARCHITECTURES */
01345   MPI_Bcast(get_tf_param(i), sizeof(TF_parameters), MPI_BYTE,
01346             0, comm_cart);
01347   
01348   /* If there are tabulated forces broadcast those as well */
01349   if ( get_tf_param(i)->TF_TAB_maxval > 0) {
01350     /* First let all nodes know the new size for force and energy tables */
01351     MPI_Bcast(&tablesize, 1, MPI_INT, 0, comm_cart);
01352     MPI_Barrier(comm_cart); // Don't do anything until all nodes have this information
01353     
01354     /* Communicate the data */
01355     MPI_Bcast(thermodynamic_forces.e,tablesize, MPI_DOUBLE, 0 , comm_cart);
01356     MPI_Bcast(thermodynamic_f_energies.e,tablesize, MPI_DOUBLE, 0 , comm_cart);
01357     //MPI_Bcast(TF_prefactor, 1, MPI_DOUBLE, 0, comm_cart);
01358   }
01359   
01360   //on_short_range_ia_change();
01361 #endif
01362 }
01363 
01364 void mpi_bcast_tf_params_slave(int i, int j)
01365 {
01366 #ifdef ADRESS
01367   int tablesize;
01368   /* INCOMPATIBLE WHEN NODES USE DIFFERENT ARCHITECTURES */
01369   MPI_Bcast(get_tf_param(i), sizeof(TF_parameters), MPI_BYTE,
01370             0, comm_cart);
01371   tablesize=0;
01372   /* If there are tabulated forces broadcast those as well */
01373   if ( get_tf_param(i)->TF_TAB_maxval > 0) {
01374     /* Determine the new size for force and energy tables */
01375     MPI_Bcast(&tablesize,1,MPI_INT,0,comm_cart);
01376     MPI_Barrier(comm_cart);
01377     /* Allocate sizes accordingly */
01378     realloc_doublelist(&thermodynamic_forces, tablesize);
01379     realloc_doublelist(&thermodynamic_f_energies, tablesize);
01380     /* Now communicate the data */
01381     MPI_Bcast(thermodynamic_forces.e,tablesize, MPI_DOUBLE, 0 , comm_cart);
01382     MPI_Bcast(thermodynamic_f_energies.e,tablesize, MPI_DOUBLE, 0 , comm_cart);
01383   }
01384 #endif
01385 }
01386 
01387 
01388 void mpi_bcast_n_particle_types(int ns)
01389 {
01390   mpi_call(mpi_bcast_n_particle_types_slave, -1, ns);
01391   mpi_bcast_n_particle_types_slave(-1, ns);
01392 
01393 }
01394 
01395 void mpi_bcast_n_particle_types_slave(int pnode, int ns)
01396 {
01397 #ifdef ADRESS
01398   /* #ifdef THERMODYNAMIC_FORCE */
01399   realloc_tf_params(ns);
01400   /* #endif */
01401 #endif
01402   realloc_ia_params(ns);
01403 }
01404 
01405 /*************** REQ_GATHER ************/
01406 void mpi_gather_stats(int job, void *result, void *result_t, void *result_nb, void *result_t_nb)
01407 {
01408   switch (job) {
01409   case 1:
01410     mpi_call(mpi_gather_stats_slave, -1, 1);
01411     energy_calc(result);
01412     break;
01413   case 2:
01414     /* calculate and reduce (sum up) virials for 'analyze pressure' or 'analyze stress_tensor'*/
01415     mpi_call(mpi_gather_stats_slave, -1, 2);
01416     pressure_calc(result,result_t,result_nb,result_t_nb,0);
01417     break;
01418   case 3:
01419     mpi_call(mpi_gather_stats_slave, -1, 3);
01420     pressure_calc(result,result_t,result_nb,result_t_nb,1);
01421     break;
01422   case 4:
01423     mpi_call(mpi_gather_stats_slave, -1, 4);
01424     predict_momentum_particles(result);
01425     break;
01426 #ifdef LB
01427   case 5:
01428     mpi_call(mpi_gather_stats_slave, -1, 5);
01429     lb_calc_fluid_mass(result);
01430     break;
01431   case 6: 
01432     mpi_call(mpi_gather_stats_slave, -1, 6);
01433     lb_calc_fluid_momentum(result);
01434     break;
01435   case 7:
01436     mpi_call(mpi_gather_stats_slave, -1, 7);
01437     lb_calc_fluid_temp(result);
01438     break;
01439 #ifdef LB_BOUNDARIES
01440   case 8:
01441     mpi_call(mpi_gather_stats_slave, -1, 8);
01442     lb_collect_boundary_forces(result);
01443     break;
01444 #endif
01445 #endif
01446   default:
01447     fprintf(stderr, "%d: INTERNAL ERROR: illegal request %d for mpi_gather_stats_slave\n", this_node, job);
01448     errexit();
01449   }
01450 }
01451 
01452 void mpi_gather_stats_slave(int ana_num, int job)
01453 {
01454   switch (job) {
01455   case 1:
01456     /* calculate and reduce (sum up) energies */
01457     energy_calc(NULL);
01458     break;
01459   case 2:
01460     /* calculate and reduce (sum up) virials for 'analyze pressure' or 'analyze stress_tensor'*/
01461     pressure_calc(NULL,NULL,NULL,NULL,0);
01462     break;
01463   case 3:
01464     /* calculate and reduce (sum up) virials, revert velocities half a timestep for 'analyze p_inst' */
01465     pressure_calc(NULL,NULL,NULL,NULL,1);
01466     break;
01467   case 4:
01468     predict_momentum_particles(NULL);
01469     break;
01470 #ifdef LB
01471   case 5:
01472     lb_calc_fluid_mass(NULL);
01473     break;
01474   case 6:
01475     lb_calc_fluid_momentum(NULL);
01476     break;
01477   case 7:
01478     lb_calc_fluid_temp(NULL);
01479     break;
01480 #ifdef LB_BOUNDARIES
01481   case 8:
01482     lb_collect_boundary_forces(NULL);
01483     break;
01484 #endif
01485 #endif
01486   default:
01487     fprintf(stderr, "%d: INTERNAL ERROR: illegal request %d for mpi_gather_stats_slave\n", this_node, job);
01488     errexit();
01489   }
01490 }
01491 
01492 /*************** REQ_GET_LOCAL_STRESS_TENSOR ************/
01493 void mpi_local_stress_tensor(DoubleList *TensorInBin, int bins[3], int periodic[3], double range_start[3], double range[3]) {
01494   
01495   int i,j;
01496   DoubleList *TensorInBin_;
01497   PTENSOR_TRACE(fprintf(stderr,"%d: mpi_local_stress_tensor: Broadcasting local_stress_tensor parameters\n",this_node));
01498 
01499 
01500   mpi_call(mpi_local_stress_tensor_slave,-1,0);
01501 
01502   TensorInBin_ = malloc(bins[0]*bins[1]*bins[2]*sizeof(DoubleList));
01503   for ( i = 0 ; i < bins[0]*bins[1]*bins[2]; i++ ) {
01504     init_doublelist(&TensorInBin_[i]);
01505     alloc_doublelist(&TensorInBin_[i],9);
01506     for ( j = 0 ; j < 9 ; j++ ) {
01507       TensorInBin_[i].e[j] = TensorInBin[i].e[j];
01508       TensorInBin[i].e[j] = 0;
01509     }
01510   }
01511   
01512   MPI_Bcast(bins, 3, MPI_INT, 0, comm_cart);
01513   MPI_Bcast(periodic, 3, MPI_INT, 0, comm_cart);
01514   MPI_Bcast(range_start, 3, MPI_DOUBLE, 0, comm_cart);
01515   MPI_Bcast(range, 3, MPI_DOUBLE, 0, comm_cart);
01516   
01517   PTENSOR_TRACE(fprintf(stderr,"%d: mpi_local_stress_tensor: Call local_stress_tensor_calc\n",this_node));
01518   local_stress_tensor_calc(TensorInBin_, bins, periodic, range_start, range);
01519   
01520   PTENSOR_TRACE(fprintf(stderr,"%d: mpi_local_stress_tensor: Reduce local stress tensors with MPI_Reduce\n",this_node));
01521   for (i=0;i<bins[0]*bins[1]*bins[2];i++) {
01522     MPI_Reduce(TensorInBin_[i].e, TensorInBin[i].e, 9, MPI_DOUBLE, MPI_SUM, 0, comm_cart); 
01523   }
01524   
01525 }
01526 
01527 void mpi_local_stress_tensor_slave(int ana_num, int job) {
01528   int bins[3] = {0,0,0};
01529   int periodic[3]= {0,0,0};
01530   double range_start[3]= {0,0,0};
01531   double range[3]= {0,0,0};
01532   DoubleList *TensorInBin;
01533   int i, j;
01534 
01535   MPI_Bcast(bins, 3, MPI_INT, 0, comm_cart);
01536   MPI_Bcast(periodic, 3, MPI_INT, 0, comm_cart);
01537   MPI_Bcast(range_start, 3, MPI_DOUBLE, 0, comm_cart);
01538   MPI_Bcast(range, 3, MPI_DOUBLE, 0, comm_cart);
01539   
01540   TensorInBin = malloc(bins[0]*bins[1]*bins[2]*sizeof(DoubleList));
01541   for ( i = 0 ; i < bins[0]*bins[1]*bins[2]; i++ ) {
01542     init_doublelist(&TensorInBin[i]);
01543     alloc_doublelist(&TensorInBin[i],9);
01544     for ( j = 0 ; j < 9 ; j++ ) {
01545       TensorInBin[i].e[j] = 0.0;
01546     }
01547   }
01548   
01549   local_stress_tensor_calc(TensorInBin, bins, periodic, range_start, range);
01550 
01551   for (i=0;i<bins[0]*bins[1]*bins[2];i++) {
01552     MPI_Reduce(TensorInBin[i].e, NULL, 9, MPI_DOUBLE, MPI_SUM, 0, comm_cart);
01553     PTENSOR_TRACE(fprintf(stderr,"%d: mpi_local_stress_tensor: Tensor sent in bin %d is {",this_node,i));
01554     for (j=0; j<9;j++) {
01555       PTENSOR_TRACE(fprintf(stderr,"%f ",TensorInBin[i].e[j]));
01556     }
01557     PTENSOR_TRACE(fprintf(stderr,"}\n"));
01558   }
01559 
01560   for ( i = 0 ; i < bins[0]*bins[1]*bins[2] ; i++ ) {
01561     realloc_doublelist(&TensorInBin[i],0);
01562   }
01563   free(TensorInBin);
01564 }
01565 
01566 /*************** REQ_GETPARTS ************/
01567 void mpi_get_particles(Particle *result, IntList *bi)
01568 {
01569   IntList local_bi;
01570   int n_part;
01571   int tot_size, i, g, pnode;
01572   int *sizes;
01573   Cell *cell;
01574   int c;
01575   
01576   mpi_call(mpi_get_particles_slave, -1, bi != NULL);
01577 
01578   sizes = malloc(sizeof(int)*n_nodes);
01579   n_part = cells_get_n_particles();
01580 
01581   /* first collect number of particles on each node */
01582   MPI_Gather(&n_part, 1, MPI_INT, sizes, 1, MPI_INT, 0, comm_cart);
01583   tot_size = 0;
01584   for (i = 0; i < n_nodes; i++)
01585     tot_size += sizes[i];
01586 
01587   if (tot_size!=n_total_particles) {
01588     fprintf(stderr,"%d: ERROR: mpi_get_particles: n_total_particles %d, but I counted %d. Exiting...\n",
01589             this_node, n_total_particles, tot_size);
01590     errexit();
01591   }
01592 
01593   /* fetch particle informations into 'result' */
01594   init_intlist(&local_bi);
01595   g = 0;
01596   for (pnode = 0; pnode < n_nodes; pnode++) {
01597     if (sizes[pnode] > 0) {
01598       if (pnode == this_node) {
01599         for (c = 0; c < local_cells.n; c++) {
01600           Particle *part;
01601           int npart;
01602           cell = local_cells.cell[c];
01603           part = cell->part;
01604           npart = cell->n;
01605           memcpy(&result[g], part, npart*sizeof(Particle));
01606           g += npart;
01607           if (bi) {
01608             int pc;
01609             for (pc = 0; pc < npart; pc++) {
01610               Particle *p = &part[pc];
01611               realloc_intlist(&local_bi, local_bi.n + p->bl.n);
01612               memcpy(&local_bi.e[local_bi.n], p->bl.e, p->bl.n*sizeof(int));
01613               local_bi.n += p->bl.n;
01614             }
01615           }
01616         }
01617       }
01618       else {
01619         MPI_Recv(&result[g], sizes[pnode]*sizeof(Particle), MPI_BYTE, pnode, SOME_TAG,
01620                  comm_cart, MPI_STATUS_IGNORE);
01621         g += sizes[pnode];
01622       }
01623     }
01624   }
01625 
01626   /* perhaps add some debugging output */
01627 #ifdef ELECTROSTATICS
01628   COMM_TRACE(for(i = 0; i < tot_size; i++) {
01629     printf("%d: %d -> %d %d %f (%f, %f, %f)\n", this_node, i, result[i].p.identity, result[i].p.type,
01630            result[i].p.q, result[i].r.p[0], result[i].r.p[1], result[i].r.p[2]);
01631   });
01632 #endif
01633 
01634 #ifdef DIPOLES
01635   COMM_TRACE(for(i = 0; i < tot_size; i++) {
01636     printf("%d: %d -> %d %d  (%f, %f, %f) (%f, %f, %f)\n", this_node, i, result[i].p.identity, result[i].p.type,
01637            result[i].r.p[0], result[i].r.p[1], result[i].r.p[2], result[i].r.dip[0],
01638            result[i].r.dip[1], result[i].r.dip[2]);
01639   });
01640 #endif
01641 
01642   /* gather bonding information */
01643   if (bi) {
01644     int *bonds;
01645 
01646     init_intlist(bi);
01647     MPI_Gather(&local_bi.n, 1, MPI_INT, sizes, 1, MPI_INT, 0, comm_cart);
01648     for (pnode = 0; pnode < n_nodes; pnode++) {
01649       if (sizes[pnode] > 0) {
01650         realloc_intlist(bi, bi->n + sizes[pnode]);
01651 
01652         if (pnode == this_node)
01653           memcpy(&bi->e[bi->n], local_bi.e, sizes[pnode]*sizeof(int));
01654         else
01655           MPI_Recv(&bi->e[bi->n], sizes[pnode], MPI_INT, pnode, SOME_TAG,
01656                    comm_cart, MPI_STATUS_IGNORE);
01657 
01658         bi->n += sizes[pnode];
01659       }
01660     }
01661 
01662     /* setup particle bond pointers into bi */
01663     bonds = bi->e;
01664     for (i = 0; i < tot_size; i++) {
01665       result[i].bl.e = bonds;
01666       bonds += result[i].bl.n;
01667       COMM_TRACE(if (result[i].bl.n > 0) {
01668         printf("(%d) part %d: bonds ", i, result[i].p.identity);
01669         for(g = 0; g < result[i].bl.n; g++) printf("%d ", result[i].bl.e[g]);
01670         printf("\n");
01671       });
01672     }
01673     realloc_intlist(&local_bi, 0);
01674   }
01675 
01676   COMM_TRACE(fprintf(stderr, "%d: finished\n", this_node));
01677 
01678   free(sizes);
01679 }
01680 
01681 void mpi_get_particles_slave(int pnode, int bi)
01682 {
01683   int n_part;
01684   int g;
01685   Particle *result;
01686   Cell *cell;
01687   int c;
01688 
01689   n_part = cells_get_n_particles();
01690 
01691   COMM_TRACE(fprintf(stderr, "%d: get_particles_slave, %d particles\n", this_node, n_part));
01692 
01693   /* first collect number of particles on each node */
01694   MPI_Gather(&n_part, 1, MPI_INT, NULL, 1, MPI_INT,
01695              0, comm_cart);
01696 
01697   if (n_part > 0) {
01698     IntList local_bi;
01699 
01700     /* get (unsorted) particle informations as an array of type 'particle' */
01701     /* then get the particle information */
01702     result = malloc(n_part*sizeof(Particle));
01703 
01704     init_intlist(&local_bi);
01705     
01706     g = 0;
01707     for (c = 0; c < local_cells.n; c++) {
01708       Particle *part;
01709       int npart;
01710       cell = local_cells.cell[c];
01711       part = cell->part;
01712       npart = cell->n;
01713       memcpy(&result[g],part,npart*sizeof(Particle));
01714       g+=cell->n;
01715       if (bi) {
01716         int pc;
01717         for (pc = 0; pc < npart; pc++) {
01718           Particle *p = &part[pc];
01719           realloc_intlist(&local_bi, local_bi.n + p->bl.n);
01720           memcpy(&local_bi.e[local_bi.n], p->bl.e, p->bl.n*sizeof(int));
01721           local_bi.n += p->bl.n;
01722         }
01723       }
01724     }
01725     /* and send it back to the master node */
01726     MPI_Send(result, n_part*sizeof(Particle), MPI_BYTE, 0, SOME_TAG, comm_cart);
01727     free(result);
01728 
01729     if (bi) {
01730       COMM_TRACE(fprintf(stderr, "%d: sending bonds\n", this_node));
01731 
01732       MPI_Gather(&local_bi.n, 1, MPI_INT, NULL, 1, MPI_INT, 0, comm_cart);      
01733       if (local_bi.n > 0)
01734         MPI_Send(local_bi.e, local_bi.n, MPI_INT, 0, SOME_TAG, comm_cart);
01735       realloc_intlist(&local_bi, 0);
01736     }
01737   }
01738   else {
01739     if (bi) {
01740       /* inform master node that we do not have bonds (as we don't have particles) */
01741       g = 0;
01742       MPI_Gather(&g, 1, MPI_INT, NULL, 1, MPI_INT, 0, comm_cart);      
01743     }
01744   }
01745 }
01746 
01747 /*************** REQ_SET_TIME_STEP ************/
01748 void mpi_set_time_step(double time_s)
01749 {
01750   double old_ts = time_step;
01751 
01752   mpi_call(mpi_set_time_step_slave, -1, 0);
01753 
01754   time_step = time_s;
01755 
01756   time_step_squared=time_step * time_step;
01757   time_step_squared_half = time_step_squared /2.;
01758   time_step_half= time_step / 2.;
01759 
01760   MPI_Bcast(&time_step, 1, MPI_DOUBLE, 0, comm_cart);
01761 
01762   rescale_velocities(time_step / old_ts);
01763   on_parameter_change(FIELD_TIMESTEP);
01764 }
01765 
01766 void mpi_set_time_step_slave(int node, int i)
01767 {
01768   double old_ts = time_step;
01769 
01770   MPI_Bcast(&time_step, 1, MPI_DOUBLE, 0, comm_cart);
01771   rescale_velocities(time_step / old_ts);
01772   on_parameter_change(FIELD_TIMESTEP);
01773   time_step_squared=time_step * time_step;
01774   time_step_squared_half = time_step_squared /2.;
01775   time_step_half= time_step / 2.;
01776 }
01777 
01778 /*************** REQ_BCAST_COULOMB ************/
01779 void mpi_bcast_coulomb_params()
01780 {
01781 #if  defined(ELECTROSTATICS) || defined(DIPOLES)
01782   mpi_call(mpi_bcast_coulomb_params_slave, 1, 0);
01783   mpi_bcast_coulomb_params_slave(-1, 0);
01784 #endif
01785 }
01786 
01787 void mpi_bcast_coulomb_params_slave(int node, int parm)
01788 {   
01789 #if defined(ELECTROSTATICS) || defined(DIPOLES)
01790   MPI_Bcast(&coulomb, sizeof(Coulomb_parameters), MPI_BYTE, 0, comm_cart);
01791 
01792 #ifdef ELECTROSTATICS
01793   switch (coulomb.method) {
01794   case COULOMB_NONE:
01795     break;
01796 #ifdef P3M
01797   case COULOMB_ELC_P3M:
01798     MPI_Bcast(&elc_params, sizeof(ELC_struct), MPI_BYTE, 0, comm_cart);
01799     // fall through
01800   case COULOMB_P3M_GPU:
01801   case COULOMB_P3M:
01802     MPI_Bcast(&p3m.params, sizeof(p3m_parameter_struct), MPI_BYTE, 0, comm_cart);
01803     break;
01804 #endif
01805   case COULOMB_DH:
01806   case COULOMB_DH_PW:
01807     MPI_Bcast(&dh_params, sizeof(Debye_hueckel_params), MPI_BYTE, 0, comm_cart);
01808     break;
01809   case COULOMB_MMM1D:
01810     MPI_Bcast(&mmm1d_params, sizeof(MMM1D_struct), MPI_BYTE, 0, comm_cart);
01811     break;
01812   case COULOMB_MMM2D:
01813     MPI_Bcast(&mmm2d_params, sizeof(MMM2D_struct), MPI_BYTE, 0, comm_cart);
01814     break;  
01815   case COULOMB_MAGGS:
01816     MPI_Bcast(&maggs, sizeof(MAGGS_struct), MPI_BYTE, 0, comm_cart); 
01817     break;
01818   case COULOMB_RF:
01819   case COULOMB_INTER_RF:
01820     MPI_Bcast(&rf_params, sizeof(Reaction_field_params), MPI_BYTE, 0, comm_cart);
01821     break;
01822   default:
01823     fprintf(stderr, "%d: INTERNAL ERROR: cannot bcast coulomb params for unknown method %d\n", this_node, coulomb.method);
01824     errexit();
01825   }
01826 #endif
01827 
01828 #ifdef DIPOLES
01829   switch (coulomb.Dmethod) {
01830   case DIPOLAR_NONE:
01831     break;
01832 #ifdef DP3M
01833   case DIPOLAR_MDLC_P3M:
01834     MPI_Bcast(&dlc_params, sizeof(DLC_struct), MPI_BYTE, 0, comm_cart);
01835     // fall through
01836   case DIPOLAR_P3M:
01837     MPI_Bcast(&dp3m.params, sizeof(p3m_parameter_struct), MPI_BYTE, 0, comm_cart);
01838     break;
01839 #endif
01840   case DIPOLAR_ALL_WITH_ALL_AND_NO_REPLICA :
01841    break;
01842  case  DIPOLAR_MDLC_DS:
01843      //fall trough
01844  case  DIPOLAR_DS:
01845     break;   
01846   default:
01847     fprintf(stderr, "%d: INTERNAL ERROR: cannot bcast dipolar params for unknown method %d\n", this_node, coulomb.Dmethod);
01848     errexit();
01849   }
01850 
01851 #endif  
01852   
01853   on_coulomb_change();
01854 #endif
01855 }
01856 
01857 /****************** REQ_SET_EXT ************/
01858 
01859 void mpi_send_ext_torque(int pnode, int part, int flag, int mask, double torque[3])
01860 {
01861 #ifdef EXTERNAL_FORCES
01862   #ifdef ROTATION
01863     int s_buf[2];
01864     mpi_call(mpi_send_ext_torque_slave, pnode, part);
01865 
01866     if (pnode == this_node) {
01867       Particle *p = local_particles[part];
01868       /* mask out old flags */
01869       p->l.ext_flag &= ~mask;
01870       /* set new values */
01871       p->l.ext_flag |= flag;
01872 
01873       if (mask & PARTICLE_EXT_TORQUE) 
01874         memcpy(p->l.ext_torque, torque, 3*sizeof(double));
01875     }
01876     else {
01877       s_buf[0] = flag; s_buf[1] = mask;
01878       MPI_Send(s_buf, 2, MPI_INT, pnode, SOME_TAG, comm_cart);
01879       if (mask & PARTICLE_EXT_TORQUE)
01880         MPI_Send(torque, 3, MPI_DOUBLE, pnode, SOME_TAG, comm_cart);
01881     }
01882 
01883     on_particle_change();
01884   #endif
01885 #endif
01886 }
01887 
01888 void mpi_send_ext_torque_slave(int pnode, int part)
01889 {
01890 #ifdef EXTERNAL_FORCES
01891   #ifdef ROTATION
01892     int s_buf[2]={0,0};
01893     if (pnode == this_node) {
01894       Particle *p = local_particles[part];
01895           MPI_Recv(s_buf, 2, MPI_INT, 0, SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
01896       /* mask out old flags */
01897       p->l.ext_flag &= ~s_buf[1];
01898       /* set new values */
01899       p->l.ext_flag |= s_buf[0];
01900       
01901       if (s_buf[1] & PARTICLE_EXT_TORQUE)
01902         MPI_Recv(p->l.ext_torque, 3, MPI_DOUBLE, 0, SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
01903     }
01904 
01905     on_particle_change();
01906   #endif
01907 #endif
01908 }
01909 
01910 void mpi_send_ext_force(int pnode, int part, int flag, int mask, double force[3])
01911 {
01912 #ifdef EXTERNAL_FORCES
01913   int s_buf[2];
01914   mpi_call(mpi_send_ext_force_slave, pnode, part);
01915 
01916   if (pnode == this_node) {
01917     Particle *p = local_particles[part];
01918     /* mask out old flags */
01919     p->l.ext_flag &= ~mask;
01920     /* set new values */
01921     p->l.ext_flag |= flag;
01922     if (mask & PARTICLE_EXT_FORCE)
01923       memcpy(p->l.ext_force, force, 3*sizeof(double));
01924   }
01925   else {
01926     s_buf[0] = flag; s_buf[1] = mask;
01927     MPI_Send(s_buf, 2, MPI_INT, pnode, SOME_TAG, comm_cart);
01928     if (mask & PARTICLE_EXT_FORCE)
01929       MPI_Send(force, 3, MPI_DOUBLE, pnode, SOME_TAG, comm_cart);
01930   }
01931 
01932   on_particle_change();
01933 #endif
01934 }
01935 
01936 void mpi_send_ext_force_slave(int pnode, int part)
01937 {
01938 #ifdef EXTERNAL_FORCES
01939   int s_buf[2]={0,0};
01940   if (pnode == this_node) {
01941     Particle *p = local_particles[part];
01942         MPI_Recv(s_buf, 2, MPI_INT, 0, SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
01943     /* mask out old flags */
01944     p->l.ext_flag &= ~s_buf[1];
01945     /* set new values */
01946     p->l.ext_flag |= s_buf[0];
01947     
01948     if (s_buf[1] & PARTICLE_EXT_FORCE)
01949       MPI_Recv(p->l.ext_force, 3, MPI_DOUBLE, 0, SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
01950   }
01951 
01952   on_particle_change();
01953 #endif
01954 }
01955 
01956 /*************** REQ_BCAST_CONSTR ************/
01957 void mpi_bcast_constraint(int del_num)
01958 {
01959 #ifdef CONSTRAINTS
01960   mpi_call(mpi_bcast_constraint_slave, 0, del_num);
01961 
01962   if (del_num == -1) {
01963     /* bcast new constraint */
01964     MPI_Bcast(&constraints[n_constraints-1], sizeof(Constraint), MPI_BYTE, 0, comm_cart);
01965   }
01966   else if (del_num == -2) {
01967     /* delete all constraints */
01968     n_constraints = 0;
01969     constraints = realloc(constraints,n_constraints*sizeof(Constraint));
01970   }
01971   else {
01972     memcpy(&constraints[del_num],&constraints[n_constraints-1],sizeof(Constraint));
01973     n_constraints--;
01974     constraints = realloc(constraints,n_constraints*sizeof(Constraint));
01975   }
01976 
01977   on_constraint_change();
01978 #endif
01979 }
01980 
01981 void mpi_bcast_constraint_slave(int node, int parm)
01982 {   
01983 #ifdef CONSTRAINTS
01984   if(parm == -1) {
01985     n_constraints++;
01986     constraints = realloc(constraints,n_constraints*sizeof(Constraint));
01987     MPI_Bcast(&constraints[n_constraints-1], sizeof(Constraint), MPI_BYTE, 0, comm_cart);
01988   }
01989   else if (parm == -2) {
01990     /* delete all constraints */
01991     n_constraints = 0;
01992     constraints = realloc(constraints,n_constraints*sizeof(Constraint));
01993   }
01994   else {
01995     memcpy(&constraints[parm],&constraints[n_constraints-1],sizeof(Constraint));
01996     n_constraints--;
01997     constraints = realloc(constraints,n_constraints*sizeof(Constraint));    
01998   }
01999 
02000   on_constraint_change();
02001 #endif
02002 }
02003 
02004 /*************** REQ_BCAST_LBBOUNDARY ************/
02005 void mpi_bcast_lbboundary(int del_num)
02006 {
02007 #if defined(LB_BOUNDARIES) || defined(LB_BOUNDARIES_GPU)
02008   mpi_call(mpi_bcast_lbboundary_slave, 0, del_num);
02009   
02010   if (del_num == -1) {
02011     /* bcast new boundaries */
02012     MPI_Bcast(&lb_boundaries[n_lb_boundaries-1], sizeof(LB_Boundary), MPI_BYTE, 0, comm_cart);
02013   }
02014   else if (del_num == -2) {
02015     /* delete all boundaries */
02016     n_lb_boundaries = 0;
02017     lb_boundaries = realloc(lb_boundaries,n_lb_boundaries*sizeof(LB_Boundary));
02018   }
02019 #if defined(LB_BOUNDARIES_GPU)
02020   else if (del_num == -3) {
02021   //nothing, GPU code just requires to call on_lbboundary_change()
02022   }
02023 #endif
02024   else {
02025     memcpy(&lb_boundaries[del_num],&lb_boundaries[n_lb_boundaries-1],sizeof(LB_Boundary));
02026     n_lb_boundaries--;
02027     lb_boundaries = realloc(lb_boundaries,n_lb_boundaries*sizeof(LB_Boundary));
02028   }
02029 
02030   on_lbboundary_change();
02031 #endif
02032 }
02033 
02034 void mpi_bcast_lbboundary_slave(int node, int parm)
02035 {   
02036 #if defined(LB_BOUNDARIES) || defined(LB_BOUNDARIES_GPU)
02037 
02038 #if defined(LB_BOUNDARIES)
02039   if(parm == -1) {
02040     n_lb_boundaries++;
02041     lb_boundaries = realloc(lb_boundaries,n_lb_boundaries*sizeof(LB_Boundary));
02042     MPI_Bcast(&lb_boundaries[n_lb_boundaries-1], sizeof(LB_Boundary), MPI_BYTE, 0, comm_cart);
02043   }
02044   else if (parm == -2) {
02045     /* delete all boundaries */
02046     n_lb_boundaries = 0;
02047     lb_boundaries = realloc(lb_boundaries,n_lb_boundaries*sizeof(LB_Boundary));
02048   }
02049 #if defined(LB_BOUNDARIES_GPU)
02050   else if (parm == -3) {
02051   //nothing, GPU code just requires to call on_lbboundary_change()
02052   }
02053 #endif
02054   else {
02055     memcpy(&lb_boundaries[parm],&lb_boundaries[n_lb_boundaries-1],sizeof(LB_Boundary));
02056     n_lb_boundaries--;
02057     lb_boundaries = realloc(lb_boundaries,n_lb_boundaries*sizeof(LB_Boundary));    
02058   }
02059 #endif
02060 
02061   on_lbboundary_change();
02062 #endif
02063 }
02064 
02065 /*************** REQ_RANDOM_SEED ************/
02066 void mpi_random_seed(int cnt, long *seed) {
02067   long this_idum = print_random_seed();
02068 
02069   mpi_call(mpi_random_seed_slave, -1, cnt);
02070 
02071   if (cnt==0) {
02072     RANDOM_TRACE(printf("%d: Have seed %ld\n",this_node,this_idum));
02073     MPI_Gather(&this_idum,1,MPI_LONG,seed,1,MPI_LONG,0,comm_cart); }
02074   else {
02075     MPI_Scatter(seed,1,MPI_LONG,&this_idum,1,MPI_LONG,0,comm_cart);
02076     RANDOM_TRACE(printf("%d: Received seed %ld\n",this_node,this_idum));
02077     init_random_seed(this_idum);
02078   }
02079 }
02080 
02081 void mpi_random_seed_slave(int pnode, int cnt) {
02082   long this_idum = print_random_seed();
02083 
02084   if (cnt==0) {
02085     RANDOM_TRACE(printf("%d: Have seed %ld\n",this_node,this_idum));
02086     MPI_Gather(&this_idum,1,MPI_LONG,NULL,0,MPI_LONG,0,comm_cart); }
02087   else {
02088     MPI_Scatter(NULL,1,MPI_LONG,&this_idum,1,MPI_LONG,0,comm_cart);
02089     RANDOM_TRACE(printf("%d: Received seed %ld\n",this_node,this_idum));
02090     init_random_seed(this_idum);
02091   }
02092 }
02093 
02094 /*************** REQ_RANDOM_STAT ************/
02095 void mpi_random_stat(int cnt, RandomStatus *stat) {
02096   RandomStatus this_stat = print_random_stat();
02097 
02098   mpi_call(mpi_random_stat_slave, -1, cnt);
02099 
02100   if (cnt==0) {
02101     RANDOM_TRACE(printf("%d: Have status %ld/%ld/...\n",this_node,this_stat.idum,this_stat.iy));
02102     MPI_Gather(&this_stat,1*sizeof(RandomStatus),MPI_BYTE,stat,1*sizeof(RandomStatus),MPI_BYTE,0,comm_cart); }
02103   else {
02104     MPI_Scatter(stat,1*sizeof(RandomStatus),MPI_BYTE,&this_stat,1*sizeof(RandomStatus),MPI_BYTE,0,comm_cart);
02105     RANDOM_TRACE(printf("%d: Received status %ld/%ld/...\n",this_node,this_stat.idum,this_stat.iy));
02106     init_random_stat(this_stat);
02107   }
02108 }
02109 
02110 void mpi_random_stat_slave(int pnode, int cnt) {
02111   RandomStatus this_stat = print_random_stat();
02112 
02113   if (cnt==0) {
02114     RANDOM_TRACE(printf("%d: Have status %ld/%ld/...\n",this_node,this_stat.idum,this_stat.iy));
02115     MPI_Gather(&this_stat,1*sizeof(RandomStatus),MPI_BYTE,NULL,0,MPI_BYTE,0,comm_cart); }
02116   else {
02117     MPI_Scatter(NULL,0,MPI_BYTE,&this_stat,1*sizeof(RandomStatus),MPI_BYTE,0,comm_cart);
02118     RANDOM_TRACE(printf("%d: Received status %ld/%ld/...\n",this_node,this_stat.idum,this_stat.iy));
02119     init_random_stat(this_stat);
02120   }
02121 }
02122 
02123 /*************** REQ_BCAST_LJFORCECAP ************/
02124 /*************** REQ_BCAST_LJANGLEFORCECAP ************/
02125 /*************** REQ_BCAST_MORSEFORCECAP ************/
02126 /*************** REQ_BCAST_BUCKFORCECAP ************/
02127 /*************** REQ_BCAST_TABFORCECAP ************/
02128 void mpi_cap_forces(double fc)
02129 {
02130   force_cap = fc;
02131   mpi_call(mpi_cap_forces_slave, 1, 0);
02132   mpi_cap_forces_slave(1, 0);
02133 }
02134 
02135 void mpi_cap_forces_slave(int node, int parm)
02136 {
02137 #ifdef LENNARD_JONES
02138   MPI_Bcast(&force_cap, 1, MPI_DOUBLE, 0, comm_cart);
02139   calc_lj_cap_radii();
02140 #ifdef LENNARD_JONES_GENERIC
02141   calc_ljgen_cap_radii();
02142 #endif
02143 #ifdef LJCOS2
02144   calc_ljcos2_cap_radii();
02145 #endif
02146   on_short_range_ia_change();
02147 #endif
02148 #ifdef LJ_ANGLE
02149   MPI_Bcast(&force_cap, 1, MPI_DOUBLE, 0, comm_cart);
02150   calc_ljangle_cap_radii();
02151   on_short_range_ia_change();
02152 #endif
02153 #ifdef MORSE
02154   MPI_Bcast(&force_cap, 1, MPI_DOUBLE, 0, comm_cart);
02155   calc_morse_cap_radii();
02156   on_short_range_ia_change();
02157 #endif
02158 #ifdef BUCKINGHAM
02159   MPI_Bcast(&force_cap, 1, MPI_DOUBLE, 0, comm_cart);
02160   calc_buck_cap_radii();
02161   on_short_range_ia_change();
02162 #endif
02163 #ifdef TABULATED
02164   MPI_Bcast(&force_cap, 1, MPI_DOUBLE, 0, comm_cart);
02165 /* to do: check if "check_tab_forcecap" is still useful since force capping
02166    is defined globally now -- the cap for other forces would be removed too! 
02167   check_tab_forcecap(force_cap);
02168 */
02169   on_short_range_ia_change();
02170 #endif
02171 }
02172 
02173 /*************** REQ_GET_CONSFOR ************/
02174 void mpi_get_constraint_force(int cons, double force[3])
02175 {
02176 #ifdef CONSTRAINTS
02177   mpi_call(mpi_get_constraint_force_slave, -1, cons);
02178   MPI_Reduce(constraints[cons].part_rep.f.f, force, 3, MPI_DOUBLE, MPI_SUM, 0, comm_cart);
02179 #endif
02180 }
02181 
02182 void mpi_get_constraint_force_slave(int node, int parm)
02183 {
02184 #ifdef CONSTRAINTS
02185   MPI_Reduce(constraints[parm].part_rep.f.f, NULL, 3, MPI_DOUBLE, MPI_SUM, 0, comm_cart);
02186 #endif
02187 }
02188 
02189 /*************** REQ_BIT_RANDOM_SEED ************/
02190 void mpi_bit_random_seed(int cnt, int *seed) {
02191   int this_idum = print_bit_random_seed();
02192 
02193   mpi_call(mpi_bit_random_seed_slave, -1, cnt);
02194 
02195   if (cnt==0) {
02196     RANDOM_TRACE(printf("%d: Have seed %d\n",this_node,this_idum));
02197     MPI_Gather(&this_idum,1,MPI_INT,seed,1,MPI_INT,0,comm_cart); }
02198   else {
02199     MPI_Scatter(seed,1,MPI_INT,&this_idum,1,MPI_INT,0,comm_cart);
02200     RANDOM_TRACE(printf("%d: Received seed %d\n",this_node,this_idum));
02201     init_bit_random_generator(this_idum);
02202   }
02203 }
02204 
02205 void mpi_bit_random_seed_slave(int pnode, int cnt) {
02206   int this_idum = print_bit_random_seed();
02207 
02208   if (cnt==0) {
02209     RANDOM_TRACE(printf("%d: Have seed %d\n",this_node,this_idum));
02210     MPI_Gather(&this_idum,1,MPI_INT,NULL,0,MPI_INT,0,comm_cart); }
02211   else {
02212     MPI_Scatter(NULL,1,MPI_INT,&this_idum,1,MPI_INT,0,comm_cart);
02213     RANDOM_TRACE(printf("%d: Received seed %d\n",this_node,this_idum));
02214     init_bit_random_generator(this_idum);
02215   }
02216 }
02217 
02218 /*************** REQ_BIT_RANDOM_STAT ************/
02219 void mpi_bit_random_stat(int cnt, BitRandomStatus *stat) {
02220   BitRandomStatus this_stat = print_bit_random_stat();
02221 
02222   mpi_call(mpi_bit_random_stat_slave, -1, cnt);
02223 
02224   if (cnt==0) {
02225     RANDOM_TRACE(printf("%d: Have status %d/%d/...\n",this_node,this_stat.random_pointer_1,this_stat.random_pointer_2));
02226     MPI_Gather(&this_stat,1*sizeof(BitRandomStatus),MPI_BYTE,stat,1*sizeof(BitRandomStatus),MPI_BYTE,0,comm_cart); }
02227   else {
02228     MPI_Scatter(stat,1*sizeof(BitRandomStatus),MPI_BYTE,&this_stat,1*sizeof(BitRandomStatus),MPI_BYTE,0,comm_cart);
02229     RANDOM_TRACE(printf("%d: Received status %d/%d/...\n",this_node,this_stat.random_pointer_1,this_stat.random_pointer_2));
02230     init_bit_random_stat(this_stat);
02231   }
02232 }
02233 
02234 void mpi_bit_random_stat_slave(int pnode, int cnt) {
02235   BitRandomStatus this_stat = print_bit_random_stat();
02236 
02237   if (cnt==0) {
02238     RANDOM_TRACE(printf("%d: Have status %d/%d/...\n",this_node,this_stat.random_pointer_1,this_stat.random_pointer_2));
02239     MPI_Gather(&this_stat,1*sizeof(BitRandomStatus),MPI_BYTE,NULL,0,MPI_BYTE,0,comm_cart); }
02240   else {
02241     MPI_Scatter(NULL,0,MPI_BYTE,&this_stat,1*sizeof(BitRandomStatus),MPI_BYTE,0,comm_cart);
02242     RANDOM_TRACE(printf("%d: Received status %d/%d/...\n",this_node,this_stat.random_pointer_1,this_stat.random_pointer_2));
02243     init_bit_random_stat(this_stat);
02244   }
02245 }
02246 
02247 /****************** REQ_RESCALE_PART ************/
02248 
02249 void mpi_rescale_particles(int dir, double scale) {
02250   int pnode;
02251 
02252   mpi_call(mpi_rescale_particles_slave, -1, dir);
02253   for (pnode = 0; pnode < n_nodes; pnode++) {
02254     if (pnode == this_node) {
02255       local_rescale_particles(dir, scale); }
02256     else {
02257       MPI_Send(&scale, 1, MPI_DOUBLE, pnode, SOME_TAG, comm_cart); }
02258   }
02259   on_particle_change();
02260 }
02261 
02262 void mpi_rescale_particles_slave(int pnode, int dir) {
02263   double scale=0.0; 
02264   MPI_Recv(&scale, 1, MPI_DOUBLE, 0, SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
02265   local_rescale_particles(dir, scale);
02266   on_particle_change();
02267 }
02268 
02269 /*************** REQ_BCAST_CS *****************/
02270 
02271 void mpi_bcast_cell_structure(int cs)
02272 {
02273   mpi_call(mpi_bcast_cell_structure_slave, -1, cs);
02274   cells_re_init(cs);
02275 }
02276 
02277 void mpi_bcast_cell_structure_slave(int pnode, int cs)
02278 {
02279   cells_re_init(cs);
02280 }
02281 
02282 /*************** REQ_BCAST_NPTISO_GEOM *****************/
02283 
02284 void mpi_bcast_nptiso_geom()
02285 {
02286   mpi_call(mpi_bcast_nptiso_geom_slave, -1 , 0);
02287   mpi_bcast_nptiso_geom_slave(-1,0);
02288 
02289 }
02290 
02291 void mpi_bcast_nptiso_geom_slave(int node,int parm)
02292 {
02293   MPI_Bcast(&nptiso.geometry, 1,MPI_INT, 0, comm_cart);
02294   MPI_Bcast(&nptiso.dimension, 1,MPI_INT, 0, comm_cart);
02295   MPI_Bcast(&nptiso.cubic_box, 1,MPI_INT, 0, comm_cart);
02296   MPI_Bcast(&nptiso.non_const_dim, 1,MPI_INT, 0, comm_cart);
02297 
02298 }
02299 
02300 /***************REQ_UPDATE_MOL_IDS *********************/
02301 
02302 void mpi_update_mol_ids()
02303 {
02304   mpi_call(mpi_update_mol_ids_slave, -1, 0);
02305   mpi_update_mol_ids_slave(-1, 0);
02306 }
02307 
02308 void mpi_update_mol_ids_slave(int node,int parm)
02309 {
02310   update_mol_ids_setchains();
02311 }
02312 
02313 /******************* REQ_SYNC_TOPO ********************/
02314 int mpi_sync_topo_part_info() {
02315   int i;
02316   int molsize=0;
02317   int moltype=0;
02318   int n_mols=0;
02319   
02320   mpi_call(mpi_sync_topo_part_info_slave,-1,0);
02321   n_mols = n_molecules;
02322   MPI_Bcast(&n_mols,1,MPI_INT,0,comm_cart);
02323 
02324   for ( i = 0 ; i < n_molecules ; i++) {
02325     molsize = topology[i].part.n;
02326     moltype = topology[i].type;
02327 
02328 #ifdef MOLFORCES
02329     MPI_Bcast(&(topology[i].trap_flag),1,MPI_INT,0,comm_cart);
02330     MPI_Bcast(topology[i].trap_center,3,MPI_DOUBLE,0,comm_cart);
02331     MPI_Bcast(&(topology[i].trap_spring_constant),1,MPI_DOUBLE,0,comm_cart);
02332     MPI_Bcast(&(topology[i].drag_constant),1,MPI_DOUBLE,0,comm_cart);
02333     MPI_Bcast(&(topology[i].noforce_flag),1,MPI_INT,0,comm_cart);
02334     MPI_Bcast(&(topology[i].isrelative),1,MPI_INT,0,comm_cart);
02335     MPI_Bcast(&(topology[i].favcounter),1,MPI_INT,0,comm_cart);
02336     if (topology[i].favcounter == -1)
02337       MPI_Bcast(topology[i].fav,3,MPI_DOUBLE,0,comm_cart);
02338     /* check if any molecules are trapped */
02339     if  ((topology[i].trap_flag != 32) && (topology[i].noforce_flag != 32)) {
02340       IsTrapped = 1;
02341     }
02342 #endif
02343 
02344     MPI_Bcast(&molsize,1,MPI_INT,0,comm_cart);
02345     MPI_Bcast(&moltype,1,MPI_INT,0,comm_cart);
02346     MPI_Bcast(topology[i].part.e,topology[i].part.n,MPI_INT,0,comm_cart);
02347     MPI_Bcast(&topology[i].type,1,MPI_INT,0,comm_cart);
02348     
02349   }
02350   
02351   sync_topo_part_info();
02352 
02353   return 1;
02354 }
02355 
02356 void mpi_sync_topo_part_info_slave(int node,int parm ) {
02357   int i;
02358   int molsize=0;
02359   int moltype=0;
02360   int n_mols=0;
02361 
02362   MPI_Bcast(&n_mols,1,MPI_INT,0,comm_cart);
02363   realloc_topology(n_mols);
02364   for ( i = 0 ; i < n_molecules ; i++) {
02365 
02366 #ifdef MOLFORCES
02367     MPI_Bcast(&(topology[i].trap_flag),1,MPI_INT,0,comm_cart);
02368     MPI_Bcast(topology[i].trap_center,3,MPI_DOUBLE,0,comm_cart);
02369     MPI_Bcast(&(topology[i].trap_spring_constant),1,MPI_DOUBLE,0,comm_cart);
02370     MPI_Bcast(&(topology[i].drag_constant),1,MPI_DOUBLE,0,comm_cart);
02371     MPI_Bcast(&(topology[i].noforce_flag),1,MPI_INT,0,comm_cart);
02372     MPI_Bcast(&(topology[i].isrelative),1,MPI_INT,0,comm_cart);
02373     MPI_Bcast(&(topology[i].favcounter),1,MPI_INT,0,comm_cart);
02374     if (topology[i].favcounter == -1)
02375       MPI_Bcast(topology[i].fav,3,MPI_DOUBLE,0,comm_cart);
02376     /* check if any molecules are trapped */
02377     if  ((topology[i].trap_flag != 32) && (topology[i].noforce_flag != 32)) {
02378       IsTrapped = 1;
02379     }
02380 #endif
02381 
02382     MPI_Bcast(&molsize,1,MPI_INT,0,comm_cart);
02383     MPI_Bcast(&moltype,1,MPI_INT,0,comm_cart);
02384     topology[i].type = moltype;
02385     realloc_intlist(&topology[i].part,topology[i].part.n = molsize);
02386 
02387     MPI_Bcast(topology[i].part.e,topology[i].part.n,MPI_INT,0,comm_cart);
02388     MPI_Bcast(&topology[i].type,1,MPI_INT,0,comm_cart);
02389 
02390   }
02391   
02392 
02393   sync_topo_part_info();
02394 
02395 }
02396 
02397 /******************* REQ_BCAST_LBPAR ********************/
02398 
02399 void mpi_bcast_lb_params(int field)
02400 {
02401 #ifdef LB
02402   mpi_call(mpi_bcast_lb_params_slave, -1, field);
02403   mpi_bcast_lb_params_slave(-1, field);
02404 #endif
02405 }
02406 
02407 void mpi_bcast_lb_params_slave(int node, int field)
02408 {
02409 #ifdef LB
02410   MPI_Bcast(&lbpar, sizeof(LB_Parameters), MPI_BYTE, 0, comm_cart);
02411   on_lb_params_change(field);
02412 #endif
02413 }
02414 
02415 
02416 /******************* REQ_BCAST_CUDA_GLOBAL_PART_VARS ********************/
02417 
02418 void mpi_bcast_cuda_global_part_vars() {
02419 #ifdef CUDA
02420   mpi_call(mpi_bcast_cuda_global_part_vars_slave, 1, 0); // third parameter is meaningless
02421   mpi_bcast_cuda_global_part_vars_slave(-1,0);
02422 #endif
02423 }
02424 
02425 void mpi_bcast_cuda_global_part_vars_slave(int node, int dummy)
02426 {
02427 #ifdef CUDA
02428   MPI_Bcast(gpu_get_global_particle_vars_pointer_host(), sizeof(CUDA_global_part_vars), MPI_BYTE, 0, comm_cart);
02429 #endif
02430 }
02431 
02432 
02433 
02434 /******************* REQ_GET_ERRS ********************/
02435 
02436 int mpi_gather_runtime_errors(char **errors)
02437 {
02438   // Tell other processors to send their erros
02439   mpi_call(mpi_gather_runtime_errors_slave, -1, 0);
02440 
02441   // If no processor encountered an error, return
02442   if (!check_runtime_errors())
02443     return ES_OK;
02444 
02445   // gather the maximum length of the error messages
02446   int *errcnt = malloc(n_nodes*sizeof(int));
02447   MPI_Gather(&n_error_msg, 1, MPI_INT, errcnt, 1, MPI_INT, 0, comm_cart);
02448 
02449   for (int node = 0; node < n_nodes; node++) {
02450     if (errcnt[node] > 0) {
02451       errors[node] = (char *)malloc(errcnt[node]);
02452 
02453       if (node == 0)
02454         strcpy(errors[node], error_msg);
02455       else 
02456         MPI_Recv(errors[node], errcnt[node], MPI_CHAR, node, 0, comm_cart, MPI_STATUS_IGNORE);
02457     }
02458     else
02459       errors[node] = NULL;
02460   }
02461 
02462   /* reset error message on master node */
02463   error_msg = realloc(error_msg, n_error_msg = 0);
02464 
02465   free(errcnt);
02466 
02467   return ES_ERROR;
02468 }
02469 
02470 void mpi_gather_runtime_errors_slave(int node, int parm)
02471 {
02472   if (!check_runtime_errors())
02473     return;
02474 
02475   MPI_Gather(&n_error_msg, 1, MPI_INT, NULL, 0, MPI_INT, 0, comm_cart);
02476   if (n_error_msg > 0) {
02477     MPI_Send(error_msg, n_error_msg, MPI_CHAR, 0, 0, comm_cart);
02478     /* reset error message on slave node */
02479     error_msg = realloc(error_msg, n_error_msg = 0);
02480   }
02481 }
02482 
02483 /********************* REQ_SET_EXCL ********/
02484 void mpi_send_exclusion(int part1, int part2, int delete)
02485 {
02486 #ifdef EXCLUSIONS
02487   mpi_call(mpi_send_exclusion_slave, part1, part2);
02488 
02489   MPI_Bcast(&delete, 1, MPI_INT, 0, comm_cart);
02490   local_change_exclusion(part1, part2, delete);
02491   on_particle_change();
02492 #endif
02493 }
02494 
02495 void mpi_send_exclusion_slave(int part1, int part2)
02496 {
02497 #ifdef EXCLUSIONS
02498   int delete=0;
02499   MPI_Bcast(&delete, 1, MPI_INT, 0, comm_cart);  
02500   local_change_exclusion(part1, part2, delete);
02501   on_particle_change();
02502 #endif
02503 }
02504 
02505 /************** REQ_SET_FLUID **************/
02506 void mpi_send_fluid(int node, int index, double rho, double *j, double *pi) {
02507 #ifdef LB
02508   if (node==this_node) {
02509     lb_calc_n_equilibrium(index, rho, j, pi);
02510   } else {
02511     double data[10] = { rho, j[0], j[1], j[2], pi[0], pi[1], pi[2], pi[3], pi[4], pi[5] };
02512     mpi_call(mpi_send_fluid_slave, node, index);
02513     MPI_Send(data, 10, MPI_DOUBLE, node, SOME_TAG, comm_cart);
02514   }
02515 #endif
02516 }
02517 
02518 void mpi_send_fluid_slave(int node, int index) {
02519 #ifdef LB
02520   if (node==this_node) {
02521     double data[10];
02522     MPI_Recv(data, 10, MPI_DOUBLE, 0, SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
02523 
02524     lb_calc_n_equilibrium(index, data[0], &data[1], &data[4]);
02525   }
02526 #endif
02527 }
02528 
02529 /************** REQ_GET_FLUID **************/
02530 void mpi_recv_fluid(int node, int index, double *rho, double *j, double *pi) {
02531 #ifdef LB
02532   if (node==this_node) {
02533     lb_calc_local_fields(index, rho, j, pi);
02534   } else {
02535     double data[10];
02536     mpi_call(mpi_recv_fluid_slave, node, index);
02537         MPI_Recv(data, 10, MPI_DOUBLE, node, SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
02538     *rho = data[0];
02539     j[0] = data[1];
02540     j[1] = data[2];
02541     j[2] = data[3];
02542     pi[0] = data[4];
02543     pi[1] = data[5];
02544     pi[2] = data[6];
02545     pi[3] = data[7];
02546     pi[4] = data[8];
02547     pi[5] = data[9];
02548 
02549   }
02550 #endif
02551 }
02552 
02553 void mpi_recv_fluid_slave(int node, int index) {
02554 #ifdef LB
02555   if (node==this_node) {
02556     double data[10];
02557     lb_calc_local_fields(index, &data[0], &data[1], &data[4]);
02558     MPI_Send(data, 10, MPI_DOUBLE, 0, SOME_TAG, comm_cart);
02559   }
02560 #endif
02561 }
02562 
02563 /************** REQ_LB_GET_BOUNDARY_FLAG **************/
02564 void mpi_recv_fluid_boundary_flag(int node, int index, int *boundary) {
02565 #ifdef LB_BOUNDARIES
02566   if (node==this_node) {
02567     lb_local_fields_get_boundary_flag(index, boundary);
02568   } else {
02569     int data = 0;
02570     mpi_call(mpi_recv_fluid_boundary_flag_slave, node, index);
02571     MPI_Recv(&data, 1, MPI_INT, node, SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
02572     *boundary = data;
02573   }
02574 #endif
02575 }
02576 
02577 void mpi_recv_fluid_boundary_flag_slave(int node, int index) {
02578 #ifdef LB_BOUNDARIES
02579   if (node==this_node) {
02580     int data;
02581     lb_local_fields_get_boundary_flag(index, &data);
02582     MPI_Send(&data, 1, MPI_INT, 0, SOME_TAG, comm_cart);
02583   }
02584 #endif
02585 }
02586 
02587 /********************* REQ_ICCP3M_ITERATION ********/
02588 int mpi_iccp3m_iteration(int dummy)
02589 {
02590 #ifdef ELECTROSTATICS
02591   mpi_call(mpi_iccp3m_iteration_slave, -1, 0);
02592 
02593   iccp3m_iteration();
02594 
02595   COMM_TRACE(fprintf(stderr, "%d: iccp3m iteration task %d done.\n", this_node, dummy));
02596 
02597   return check_runtime_errors();
02598 #else
02599   return 0;
02600 #endif
02601 
02602 }
02603 
02604 void mpi_iccp3m_iteration_slave(int dummy, int dummy2)
02605 {
02606 #ifdef ELECTROSTATICS
02607   iccp3m_iteration();
02608   COMM_TRACE(fprintf(stderr, "%d: iccp3m iteration task %d done.\n", dummy, dummy2));
02609 
02610   check_runtime_errors();
02611 #endif
02612 }
02613 
02614 /********************* REQ_ICCP3M_INIT********/
02615 int mpi_iccp3m_init(int n_induced_charges)
02616 {
02617 #ifdef ELECTROSTATICS
02618   /* nothing has to be done on the master node, this 
02619    * passes only the number of induced charges, in order for
02620    * slaves to allocate memory */
02621   
02622   mpi_call(mpi_iccp3m_init_slave, -1, n_induced_charges);
02623    
02624   bcast_iccp3m_cfg();
02625 
02626   COMM_TRACE(fprintf(stderr, "%d: iccp3m init task %d done.\n", this_node, n_induced_charges));
02627 
02628   return check_runtime_errors();
02629 #else
02630   return 0;
02631 #endif
02632 
02633 }
02634 
02635 void mpi_iccp3m_init_slave(int node, int dummy)
02636 {
02637 #ifdef ELECTROSTATICS
02638   COMM_TRACE(fprintf(stderr, "%d: iccp3m iteration task %d done.\n", this_node, dummy));
02639 
02640   if(iccp3m_initialized==0){
02641     iccp3m_init();
02642     iccp3m_initialized=1;
02643  }
02644 
02645   bcast_iccp3m_cfg();
02646   
02647   check_runtime_errors();
02648 #endif
02649 }
02650 
02651 void mpi_recv_fluid_populations(int node, int index, double *pop) {
02652 #ifdef LB
02653   if (node==this_node) {
02654     lb_get_populations(index, pop);
02655   } else {
02656     mpi_call(mpi_recv_fluid_populations_slave, node, index);
02657     MPI_Recv(pop, 19, MPI_DOUBLE, node, SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
02658   }
02659   lbpar.resend_halo=1;
02660 #endif
02661 }
02662 
02663 void mpi_recv_fluid_populations_slave(int node, int index) {
02664 #ifdef LB
02665   if (node==this_node) {
02666     double data[19];
02667     lb_get_populations(index, data);
02668     MPI_Send(data, 19, MPI_DOUBLE, 0, SOME_TAG, comm_cart);
02669   }
02670   lbpar.resend_halo=1;
02671 #endif
02672 }
02673 
02674 void mpi_send_fluid_populations(int node, int index, double *pop) {
02675 #ifdef LB
02676   if (node==this_node) {
02677     lb_set_populations(index, pop);
02678   } else {
02679     mpi_call(mpi_send_fluid_populations_slave, node, index);
02680     MPI_Send(pop, 19, MPI_DOUBLE, node, SOME_TAG, comm_cart);
02681   }
02682 #endif
02683 }
02684 
02685 void mpi_send_fluid_populations_slave(int node, int index) {
02686 #ifdef LB
02687   if (node==this_node) {
02688     double data[19];
02689     MPI_Recv(data, 19, MPI_DOUBLE, 0, SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
02690     lb_set_populations(index, data);
02691   }
02692 #endif
02693 }
02694 
02695 /****************************************************/
02696 
02697 void mpi_bcast_max_mu() {
02698 #ifdef DIPOLES
02699   mpi_call(mpi_bcast_max_mu_slave, -1, 0);
02700   
02701   calc_mu_max();
02702   
02703 #endif
02704 }
02705 
02706 void mpi_bcast_max_mu_slave(int node, int dummy) {
02707 #ifdef DIPOLES
02708   
02709   calc_mu_max();
02710  
02711 #endif
02712 }
02713 
02714 #ifdef LANGEVIN_PER_PARTICLE
02715 
02716 /******************** REQ_SEND_PARTICLE_T ********************/
02717 void mpi_set_particle_temperature(int pnode, int part, double _T)
02718 {
02719   mpi_call(mpi_set_particle_temperature_slave, pnode, part);
02720 
02721   if (pnode == this_node) {
02722     Particle *p = local_particles[part];
02723     /* here the setting actually happens, if the particle belongs to the local node */
02724     p->p.T = _T;
02725   }
02726   else {
02727     MPI_Send(&_T, 1, MPI_DOUBLE, pnode, SOME_TAG, comm_cart);
02728   }
02729 
02730   on_particle_change();
02731 }
02732 #endif
02733 
02734 void mpi_set_particle_temperature_slave(int pnode, int part)
02735 {
02736 #ifdef LANGEVIN_PER_PARTICLE
02737   double s_buf = 0.;
02738   if (pnode == this_node) {
02739     Particle *p = local_particles[part];
02740     MPI_Status status;
02741     MPI_Recv(&s_buf, 1, MPI_DOUBLE, 0, SOME_TAG, comm_cart, &status);
02742     /* here the setting happens for nonlocal nodes */
02743     p->p.T = s_buf;
02744   }
02745 
02746   on_particle_change();
02747 #endif
02748 }
02749 
02750 #ifdef LANGEVIN_PER_PARTICLE
02751 void mpi_set_particle_gamma(int pnode, int part, double gamma)
02752 {
02753   mpi_call(mpi_set_particle_gamma_slave, pnode, part);
02754 
02755   if (pnode == this_node) {
02756     Particle *p = local_particles[part];
02757     /* here the setting actually happens, if the particle belongs to the local node */
02758     p->p.gamma = gamma;
02759   }
02760   else {
02761     MPI_Send(&gamma, 1, MPI_DOUBLE, pnode, SOME_TAG, comm_cart);
02762   }
02763 
02764   on_particle_change();
02765 }
02766 #endif
02767 
02768 void mpi_set_particle_gamma_slave(int pnode, int part)
02769 {
02770 #ifdef LANGEVIN_PER_PARTICLE
02771   double s_buf = 0.;
02772   if (pnode == this_node) {
02773     Particle *p = local_particles[part];
02774     MPI_Status status;
02775     MPI_Recv(&s_buf, 1, MPI_DOUBLE, 0, SOME_TAG, comm_cart, &status);
02776     /* here the setting happens for nonlocal nodes */
02777     p->p.gamma = s_buf;
02778   }
02779 
02780   on_particle_change();
02781 #endif
02782 }
02783 
02784 /***** GALILEI TRANSFORM AND ASSOCIATED FUNCTIONS ****/
02785 
02786 void mpi_kill_particle_motion( int rotation )
02787 {
02788   mpi_call(mpi_kill_particle_motion_slave, -1, rotation );
02789   local_kill_particle_motion( rotation );
02790   on_particle_change();
02791 }
02792 
02793 void mpi_kill_particle_motion_slave(int pnode, int rotation )
02794 {
02795   local_kill_particle_motion( rotation );
02796   on_particle_change();
02797 }
02798 
02799 void mpi_kill_particle_forces( int torque )
02800 {
02801   mpi_call(mpi_kill_particle_forces_slave, -1, torque );
02802   local_kill_particle_forces( torque );
02803   on_particle_change();
02804 }
02805 
02806 void mpi_kill_particle_forces_slave(int pnode, int torque)
02807 {
02808   local_kill_particle_forces( torque );
02809   on_particle_change();
02810 }
02811 
02812 void mpi_system_CMS() {
02813   int pnode;
02814   double data[4];
02815   double rdata[4];
02816   double *pdata = rdata;
02817 
02818   data[0] = 0.0; 
02819   data[1] = 0.0;
02820   data[2] = 0.0;
02821   data[3] = 0.0;
02822 
02823   mpi_call(mpi_system_CMS_slave, -1, 0);
02824 
02825   for (pnode = 0; pnode < n_nodes; pnode++) {
02826     if (pnode==this_node) {
02827       local_system_CMS( pdata );
02828       data[0] += rdata[0];
02829       data[1] += rdata[1];
02830       data[2] += rdata[2];
02831       data[3] += rdata[3];
02832     } else {
02833       MPI_Recv(rdata, 4, MPI_DOUBLE, MPI_ANY_SOURCE, SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
02834       data[0] += rdata[0];
02835       data[1] += rdata[1];
02836       data[2] += rdata[2];
02837       data[3] += rdata[3];
02838     }
02839   }
02840 
02841   gal.cms[0] = data[0]/data[3];
02842   gal.cms[1] = data[1]/data[3];
02843   gal.cms[2] = data[2]/data[3];
02844 }
02845 
02846 void mpi_system_CMS_slave(int node, int index) {
02847   double rdata[4];
02848   double *pdata = rdata;
02849   local_system_CMS( pdata );
02850   MPI_Send(rdata, 4, MPI_DOUBLE, 0, SOME_TAG, comm_cart);
02851 }
02852 
02853 void mpi_system_CMS_velocity() {
02854   int pnode;
02855   double data[4];
02856   double rdata[4];
02857   double *pdata = rdata;
02858 
02859   data[0] = 0.0; 
02860   data[1] = 0.0;
02861   data[2] = 0.0;
02862   data[3] = 0.0;
02863 
02864   mpi_call(mpi_system_CMS_velocity_slave, -1, 0);
02865 
02866   for (pnode = 0; pnode < n_nodes; pnode++) {
02867     if (pnode==this_node) {
02868       local_system_CMS_velocity( pdata );
02869       data[0] += rdata[0];
02870       data[1] += rdata[1];
02871       data[2] += rdata[2];
02872       data[3] += rdata[3];
02873     } else {
02874       MPI_Recv(rdata, 4, MPI_DOUBLE, MPI_ANY_SOURCE, SOME_TAG, comm_cart, MPI_STATUS_IGNORE);
02875       data[0] += rdata[0];
02876       data[1] += rdata[1];
02877       data[2] += rdata[2];
02878       data[3] += rdata[3];
02879     }
02880   }
02881 
02882   gal.cms_vel[0] = data[0]/data[3];
02883   gal.cms_vel[1] = data[1]/data[3];
02884   gal.cms_vel[2] = data[2]/data[3];
02885 }
02886 
02887 void mpi_system_CMS_velocity_slave(int node, int index) {
02888   double rdata[4];
02889   double *pdata = rdata;
02890   local_system_CMS_velocity( pdata );
02891   MPI_Send(rdata, 4, MPI_DOUBLE, 0, SOME_TAG, comm_cart);
02892 }
02893 
02894 void mpi_galilei_transform()
02895 {
02896   double cmsvel[3];
02897 
02898   mpi_system_CMS_velocity();
02899   memcpy(cmsvel, gal.cms_vel, 3*sizeof(double));
02900 
02901   mpi_call(mpi_galilei_transform_slave, -1, 0);
02902   MPI_Bcast(cmsvel, 3, MPI_DOUBLE, 0, comm_cart);
02903 
02904   local_galilei_transform( cmsvel );
02905 
02906   on_particle_change();
02907 }
02908 
02909 void mpi_galilei_transform_slave(int pnode, int i)
02910 {
02911   double cmsvel[3];
02912   MPI_Bcast(cmsvel, 3, MPI_DOUBLE, 0, comm_cart);
02913 
02914   local_galilei_transform( cmsvel );
02915   on_particle_change();
02916 }
02917 
02918 /******************** REQ_CATALYTIC_REACTIONS ********************/
02919 
02920 void mpi_setup_reaction()
02921 {
02922 #ifdef CATALYTIC_REACTIONS
02923   mpi_call(mpi_setup_reaction_slave, -1, 0);
02924   local_setup_reaction();
02925 #endif
02926 }
02927 
02928 void mpi_setup_reaction_slave(int pnode, int i)
02929 {
02930 #ifdef CATALYTIC_REACTIONS
02931   local_setup_reaction();
02932 #endif
02933 }
02934 
02935 /*********************** MAIN LOOP for slaves ****************/
02936 
02937 void mpi_loop()
02938 {
02939   for (;;) {
02940 #ifdef ASYNC_BARRIER
02941     MPI_Barrier(comm_cart);
02942 #endif
02943     MPI_Bcast(request, 3, MPI_INT, 0, comm_cart);
02944     COMM_TRACE(fprintf(stderr, "%d: processing %s %d %d...\n", this_node,
02945                        names[request[0]], request[1], request[2]));
02946     if ((request[0] < 0) || (request[0] >= N_CALLBACKS)) {
02947       fprintf(stderr, "%d: INTERNAL ERROR: unknown request %d\n", this_node, request[0]);
02948       errexit();
02949     }
02950     slave_callbacks[request[0]](request[1], request[2]);
02951     COMM_TRACE(fprintf(stderr, "%d: finished %s %d %d\n", this_node,
02952                        names[request[0]], request[1], request[2]));
02953   }
02954 }
02955