summaryrefslogtreecommitdiff
path: root/lpic/src/network.C
diff options
context:
space:
mode:
Diffstat (limited to 'lpic/src/network.C')
-rw-r--r--lpic/src/network.C1235
1 files changed, 1235 insertions, 0 deletions
diff --git a/lpic/src/network.C b/lpic/src/network.C
new file mode 100644
index 0000000..8075d79
--- /dev/null
+++ b/lpic/src/network.C
@@ -0,0 +1,1235 @@
+/*
+ This file is part of LPIC++, a particle-in-cell code for
+ simulating the interaction of laser light with plasma.
+
+ Copyright (C) 1994-1997 Roland Lichters
+
+ LPIC++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <config.h>
+
+#ifdef LPIC_PARALLEL
+#ifdef LPIC_PVM
+
+#include <network.h>
+
+network::network( parameter &p )
+{
+ sprintf( errname, "%s/error-%d", p.path, p.domain_number );
+ static error_handler bob("network::Constructor",errname);
+
+ domain_number = p.domain_number;
+ n_domains = p.n_domains;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::start_next_task( parameter &p )
+{
+ static error_handler bob("network::start_next_task",errname);
+
+ if ( p.n_domains > 1 ) // spawn task for following domain
+ { // this needs the pvmd running
+ tid = pvm_mytid();
+ if (tid<0) bob.error("Maybe you should start the pvm daemon?");
+
+ if (domain_number>1) tid_prev = pvm_parent();
+ else tid_prev = -1;
+
+ bob.message("my tid: ", tid );
+ bob.message("tid_prev: ", tid_prev );
+
+ if (domain_number<p.n_domains)
+ {
+ char **arg;
+ arg = new (char* [3]);
+ arg[0] = new (char [100]);
+ arg[1] = new (char [100]);
+ arg[2] = new (char [100]);
+ sprintf( arg[0], "%d", domain_number+1 );
+ sprintf( arg[1], "%s", p.input_file_name );
+ arg[2] = NULL;
+
+ bob.message("spawn: ", p.my_name, arg[0], arg[1] );
+
+ int numt = pvm_spawn( p.my_name, arg, PvmTaskDefault, "", 1, &tid_next );
+
+ if (numt!=1) bob.error("cannot start task no.", domain_number+1 );
+ else bob.message("new task: ", domain_number+1 );
+ }
+ else tid_next = -1;
+
+ bob.message("tid_next: ", tid_next );
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::field( int time_step, domain* grid )
+{
+ static error_handler bob("network::field",errname);
+
+ if ( domain_number > 1 ) { // exchange field copies
+ field_send_cpy( grid->left, tid_prev, time_step );
+ field_get_cpy( grid->lbuf, tid_prev, time_step );
+ }
+ if ( domain_number < n_domains ) {
+ field_send_cpy( grid->right, tid_next, time_step );
+ field_get_cpy( grid->rbuf, tid_next, time_step );
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::field_get_cpy( struct cell* cell, int ptid, int time_step )
+// recieve from ptid
+// store in cell
+{
+ static error_handler bob("network::field_get",errname);
+
+ int msgtag = time_step;
+ double data[9];
+ // recieve from ptid and store in cell
+ pvm_recv( ptid, msgtag );
+ pvm_upkdouble( data, 9, 1 );
+
+ cell->fp = data[0];
+ cell->gm = data[1];
+ cell->fm = data[2];
+ cell->gp = data[3];
+ cell->ex = data[4];
+ cell->ey = data[5];
+ cell->ez = data[6];
+ cell->by = data[7];
+ cell->bz = data[8];
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::field_send_cpy( struct cell* cell, int ptid, int time_step )
+// get from cell
+// send to ptid
+{
+ static error_handler bob("network::field_send",errname);
+
+ int msgtag = time_step;
+ double data[9];
+ // send to the next domain
+ data[0] = cell->fp;
+ data[1] = cell->gm;
+ data[2] = cell->fm;
+ data[3] = cell->gp;
+ data[4] = cell->ex;
+ data[5] = cell->ey;
+ data[6] = cell->ez;
+ data[7] = cell->by;
+ data[8] = cell->bz;
+
+ pvm_initsend( PvmDataDefault );
+ pvm_pkdouble( data, 9, 1 );
+ pvm_send( ptid, msgtag );
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::particles( int time_step, domain *grid )
+{
+ static error_handler bob("network::particles",errname);
+ int el_count, ion_count;
+
+ if ( domain_number > 1 ) { // exchange particles
+ particles_send( grid->lbuf, tid_prev, time_step, &el_count, &ion_count );
+ // send particles in lbuf to tid_prev
+
+ grid->n_el -= el_count;
+ grid->n_ion -= ion_count;
+ grid->n_part -= ( el_count + ion_count);
+
+ particles_get( grid->left, tid_prev, time_step, &el_count, &ion_count );
+ // get particles from tid_prev into left
+
+ grid->n_el += el_count;
+ grid->n_ion += ion_count;
+ grid->n_part += ( el_count + ion_count);
+ }
+ if ( domain_number < n_domains ) {
+ particles_send( grid->rbuf, tid_next, time_step, &el_count, &ion_count );
+ // send particles in rbuf to tid_next
+
+ grid->n_el -= el_count;
+ grid->n_ion -= ion_count;
+ grid->n_part -= ( el_count + ion_count);
+
+ particles_get( grid->right, tid_next, time_step, &el_count, &ion_count );
+ // get particles from tid_next into right
+
+ grid->n_el += el_count;
+ grid->n_ion += ion_count;
+ grid->n_part += ( el_count + ion_count);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::particles_send( struct cell* cell, int ptid, int time_step,
+ int *el_count, int *ion_count )
+// cell: take particles from cell
+// ptid: send them to tid
+{
+ static error_handler bob("network::particles_send",errname);
+
+ int msgtag = time_step;
+ int npart = cell->npart;
+ struct particle *part, *old;
+
+ pvm_initsend( PvmDataDefault ); // send number of particles
+ pvm_pkint( &npart, 1, 1 );
+ pvm_send( ptid, msgtag );
+
+ *el_count = *ion_count = 0;
+
+ if ( npart > 0 ) {
+
+ pvm_initsend( PvmDataDefault ); // send particles
+
+ for( part=cell->first; part!=NULL; part=part->next ) {
+
+ pack_particle( part );
+
+ if ( (part->x < cell->x) || (part->x > cell->next->x) )
+ bob.error( "particle link to buffer is wrong" );
+ }
+
+ part = cell->first; // delete particles
+ do
+ { cell->npart --;
+ cell->np[part->species] --;
+ switch (part->species){ // counters for updating domain's particle
+ case 0: // numbers grid.n_el, grid.n_ion, grid.n_part
+ (*el_count) ++;
+ break;
+ case 1:
+ (*ion_count) ++;
+ break;
+ }
+ old = part;
+ part = part->next;
+ delete old;
+ }
+ while( part!=NULL );
+ cell->first=NULL;
+ cell->last=NULL;
+
+ pvm_send( ptid, msgtag+1 );
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::particles_get( struct cell* cell, int ptid, int time_step,
+ int *el_count, int *ion_count )
+// ptid: recieve particles from tid
+// cell: put them into this cell
+{
+ static error_handler bob("network::particles_get",errname);
+
+ int msgtag = time_step;
+ int i, npart; // recieve from next domain
+ struct particle *part, *insert_pointer;
+
+ pvm_recv( ptid, msgtag ); // recieve the number of particles to recieve
+ pvm_upkint( &npart, 1, 1 );
+
+ *el_count = *ion_count = 0;
+
+ if (npart>0) {
+
+ pvm_recv( ptid, msgtag+1 ); // recieve particles
+
+ insert_pointer = cell->first;
+
+ for( i=0; i<npart; i++ ) {
+ part = new( struct particle ); // create a new particle
+ if (!part) bob.error("allocation error: part");
+
+ if ( ptid == tid_prev ) {
+
+ unpack_particle( part );
+
+ part->cell = cell;
+ if (insert_pointer!=NULL){ // insert always in front of insert pointer
+ part->next = insert_pointer;
+ part->prev = insert_pointer->prev;
+ part->next->prev = part;
+ if (part->prev==NULL) cell->first = part;
+ else part->prev->next = part;
+ }
+ else{ // insert always on bottom
+ part->next = NULL;
+ part->prev = cell->last;
+ if (part->prev!=NULL) part->prev->next = part;
+ else cell->first = part;
+ cell->last = part;
+ }
+ }
+ else if ( ptid == tid_next ) {
+
+ unpack_particle( part );
+
+ part->cell = cell;
+ if (cell->insert!=NULL) part->prev = cell->insert->prev;
+ else part->prev = NULL;
+ part->next = cell->insert;
+ if (part->prev!=NULL) part->prev->next = part;
+ else cell->first = part;
+ if (part->next!=NULL) part->next->prev = part;
+ else cell->last = part;
+ }
+ else {
+ bob.error( "ptid neither tid_next nor tid_prev" );
+ exit(-1);
+ }
+
+ cell->npart ++; // update cell's particle bookkeeping
+ cell->np[part->species] ++;
+ switch (part->species){ // counters for updating domain's particle
+ case 0: // numbers grid.n_el, grid.n_ion, grid.n_part
+ (*el_count) ++;
+ break;
+ case 1:
+ (*ion_count) ++;
+ break;
+ }
+
+ if ( (part->x < cell->x) || (part->x > cell->next->x) )
+ bob.error( "particle link to new cell in new domain is wrong" );
+ }
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::current( int time_step, domain* grid )
+{
+ static error_handler bob("network::current",errname);
+
+ if ( domain_number > 1 ) {
+ current_send( grid->Lbuf, tid_prev, time_step );
+ // exchange current contributions to cells
+ current_get( grid->left, tid_prev, time_step );
+ // ""
+ current_get_cpy( grid->lbuf, tid_prev, time_step );
+ // get a copy of jy and jz into lbuf
+
+ // A copy of currents jy and jz is needed ONLY at the left boundary ( in lbuf )
+ // in order to propagate the fields Fplus and Gminus in cell "left".
+ // For the propagation of Fminus and Gplus at the right boundary "right",
+ // the currents in cell "right" are sufficient!
+ // see MPQ-Report 219 p. 22 or propagate::fields in propagate.C
+ }
+ if ( domain_number < n_domains ) {
+ current_send( grid->rbuf, tid_next, time_step );
+ // exchange current contributions to cells
+ current_get( grid->right->prev, tid_next, time_step );
+ // ""
+ current_send_cpy( grid->right, tid_next, time_step );
+ // send copies of jy and jz to the right __AFTER__ recieving!!
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::density( int time_step, domain* grid )
+{
+ static error_handler bob("network::density",errname);
+
+ if ( domain_number > 1 ) {
+ density_send( grid->lbuf, tid_prev, time_step );
+ // exchange density contributions to cells
+ density_get( grid->left, tid_prev, time_step );
+ // ""
+ }
+ if ( domain_number < n_domains ) {
+ density_send( grid->rbuf, tid_next, time_step );
+ // exchange density contributions to cells
+ density_get( grid->right, tid_next, time_step );
+ // ""
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::current_send( struct cell* cell, int ptid, int time_step )
+// get currents from cell and cell->next
+// send to ptid
+{
+ static error_handler bob("network::current_send",errname);
+
+ int msgtag = time_step;
+ double data[6];
+ // send to the next domain
+ data[0] = cell->jx;
+ data[1] = cell->jy;
+ data[2] = cell->jz;
+ data[3] = cell->next->jx;
+ data[4] = cell->next->jy;
+ data[5] = cell->next->jz;
+
+ pvm_initsend( PvmDataDefault );
+ pvm_pkdouble( data, 6, 1 );
+ pvm_send( ptid, msgtag );
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::current_get( struct cell* cell, int ptid, int time_step )
+// recieve from ptid
+// add to currents in cell and cell->next
+{
+ static error_handler bob("network::current_get",errname);
+
+ int msgtag = time_step;
+ double data[6];
+ // recieve from ptid and store in cell
+ pvm_recv( ptid, msgtag );
+ pvm_upkdouble( data, 6, 1 );
+ cell->jx += data[0];
+ cell->jy += data[1];
+ cell->jz += data[2];
+ cell->next->jx += data[3];
+ cell->next->jy += data[4];
+ cell->next->jz += data[5];
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::current_send_cpy( struct cell* cell, int ptid, int time_step )
+// send jy, jz from cell to ptid
+{
+ static error_handler bob("network::current_send",errname);
+
+ int msgtag = time_step;
+ double data[2];
+ // send to the next domain
+ data[0] = cell->jy;
+ data[1] = cell->jz;
+
+ pvm_initsend( PvmDataDefault );
+ pvm_pkdouble( data, 2, 1 );
+ pvm_send( ptid, msgtag );
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::current_get_cpy( struct cell* cell, int ptid, int time_step )
+// recieve from ptid copies of jy and jz
+// store in cell
+{
+ static error_handler bob("network::current_get",errname);
+
+ int msgtag = time_step;
+ double data[2];
+ // recieve from ptid and store in cell
+ pvm_recv( ptid, msgtag );
+ pvm_upkdouble( data, 2, 1 );
+ cell->jy = data[0];
+ cell->jz = data[1];
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::density_send( struct cell* cell, int ptid, int time_step )
+// send densities from cell to ptid
+{
+ static error_handler bob("network::density_send",errname);
+
+ int msgtag = time_step;
+ double data[3];
+
+ data[0] = cell->charge;
+ data[1] = cell->dens[0];
+ data[2] = cell->dens[1];
+
+ pvm_initsend( PvmDataDefault );
+ pvm_pkdouble( data, 3, 1 );
+ pvm_send( ptid, msgtag );
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::density_get( struct cell* cell, int ptid, int time_step )
+// recieve from ptid
+// add to density in cell
+{
+ static error_handler bob("network::density_get",errname);
+
+ int msgtag = time_step;
+ double data[3];
+
+ pvm_recv( ptid, msgtag );
+ pvm_upkdouble( data, 3, 1 );
+ cell->charge += data[0];
+ cell->dens[0] += data[1];
+ cell->dens[1] += data[2];
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::current_1( int time_step, domain* grid )
+{
+ static error_handler bob("network::current_1",errname);
+
+ if ( domain_number > 1 ) {
+ current_get_12( grid->Lbuf, tid_prev, time_step );
+ // copy current contributions from previous domain into Lbuf, lbuf, left, left->next
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::current_get_12( struct cell* cell, int ptid, int time_step )
+// recieve from ptid
+// add to currents in cell and cell->next
+{
+ static error_handler bob("network::current_get_12",errname);
+
+ int msgtag = time_step;
+ double data[12];
+ // recieve from ptid and store in cell
+ pvm_recv( ptid, msgtag );
+ pvm_upkdouble( data, 12, 1 );
+ cell->jx = data[0];
+ cell->jy = data[1];
+ cell->jz = data[2];
+ cell->next->jx = data[3];
+ cell->next->jy = data[4];
+ cell->next->jz = data[5];
+ cell->next->next->jx = data[6];
+ cell->next->next->jy = data[7];
+ cell->next->next->jz = data[8];
+ cell->next->next->next->jx = data[9];
+ cell->next->next->next->jy = data[10];
+ cell->next->next->next->jz = data[11];
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::current_2( int time_step, domain* grid )
+{
+ static error_handler bob("network::current_2",errname);
+
+ if ( domain_number > 1 ) {
+ current_send_12( grid->Lbuf, tid_prev, time_step );
+ }
+ if ( domain_number < n_domains ) {
+ current_send_12( grid->right->prev, tid_next, time_step );
+ current_get_12( grid->right->prev, tid_next, time_step );
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::current_send_12( struct cell* cell, int ptid, int time_step )
+{
+ static error_handler bob("network::current_send_12",errname);
+
+ int msgtag = time_step;
+ double data[12];
+ // send to the next domain
+ data[0] = cell->jx;
+ data[1] = cell->jy;
+ data[2] = cell->jz;
+ data[3] = cell->next->jx;
+ data[4] = cell->next->jy;
+ data[5] = cell->next->jz;
+ data[6] = cell->next->next->jx;
+ data[7] = cell->next->next->jy;
+ data[8] = cell->next->next->jz;
+ data[9] = cell->next->next->next->jx;
+ data[10] = cell->next->next->next->jy;
+ data[11] = cell->next->next->next->jz;
+
+ pvm_initsend( PvmDataDefault );
+ pvm_pkdouble( data, 12, 1 );
+ pvm_send( ptid, msgtag );
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::get_part_numbers_from_prev( int *number, int n )
+ // in domain #1 : number[i] := 0 (0<=i<n)
+ // else : number[i] = data recieved from previous domain
+{
+ static error_handler bob("network::get_part_numbers_from_prev",errname);
+
+ int msgtag = domain_number;
+ int i;
+
+ if (domain_number > 1) {
+
+ pvm_recv( tid_prev, msgtag );
+ pvm_upkint( number, n, 1 );
+
+ bob.message( "recieved n_el =", number[0], "n_ion =", number[1] );
+ }
+ else {
+
+ for( i=0; i<n; i++ ) number[i] = 0;
+
+ bob.message( "nothing recieved: domain #", domain_number );
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::send_part_numbers_to_next( int *number, int n )
+ // in domain #n_doms : -------
+ // else : data sent to next domain = number[i] (0<=i<n)
+{
+ static error_handler bob("network::send_part_numbers_to_next",errname);
+
+ int msgtag = domain_number+1;
+
+ if (domain_number < n_domains) {
+
+ pvm_initsend( PvmDataDefault );
+ pvm_pkint( number, n, 1 );
+ pvm_send( tid_next, msgtag );
+
+ bob.message( "sent n_el =", number[0], "n_ion =", number[1] );
+ }
+ else bob.message( "nothing to send: domain #", domain_number );
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void network::get_total_numbers_from_next( int *number, int n )
+ // in domain #n_domains : -------
+ // else : number[i] = data recieved from next domain (0<=i<n)
+{
+ static error_handler bob("network::get_total_numbers_from_next",errname);
+
+ int msgtag = domain_number;
+
+ if (domain_number < n_domains) {
+
+ pvm_recv( tid_next, msgtag );
+ pvm_upkint( number, n, 1 );
+
+ bob.message( "recieved n_el =", number[0], "n_ion =", number[1] );
+ }
+ else bob.message( "nothing to recieve: domain #", domain_number );
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::send_total_numbers_to_prev( int *number, int n )
+ // in domain #1 : -------
+ // else : data sent to previous domain = number[i] (0<=i<n)
+{
+ static error_handler bob("network::send_total_numbers_to_prev",errname);
+
+ int msgtag = domain_number-1;
+
+ if (domain_number > 1) {
+
+ pvm_initsend( PvmDataDefault );
+ pvm_pkint( number, n, 1 );
+ pvm_send( tid_prev, msgtag );
+
+ bob.message( "sent n_el =", number[0], "n_ion =", number[1] );
+ }
+ else bob.message( "nothing to send: domain #", domain_number );
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void network::reo_get_mesg_from_prev( int* exchange )
+ // in domain # 1 : return 0
+ // else : return number of particles to send to ( - )
+ // or to recieve from ( + ) previous domain
+{
+ static error_handler bob("network::reo_get_mesg_from_prev",errname);
+
+ int msgtag = domain_number;
+
+ if (domain_number > 1) {
+
+ pvm_recv( tid_prev, msgtag );
+ pvm_upkint( exchange, 1, 1 );
+
+ bob.message( "recieved reo_mesg =", *exchange );
+ }
+ else {
+ bob.message( "no reo_mesg to recieve: domain #", domain_number );
+ *exchange = 0;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void network::reo_send_mesg_to_next( int *exchange )
+ // in domain #1 : -------
+ // else : data sent to previous domain = number[i] (0<=i<n)
+{
+ static error_handler bob("network::reo_send_mesg_to_next",errname);
+
+ int msgtag = domain_number+1;
+
+ if (domain_number < n_domains) {
+
+ pvm_initsend( PvmDataDefault );
+ pvm_pkint( exchange, 1, 1 );
+ pvm_send( tid_next, msgtag );
+
+ bob.message( "sent reo_mesg =", *exchange );
+ }
+ else {
+ bob.message( "no reo_mesg to send: domain #", domain_number );
+ *exchange = 0;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void network::reo_from_prev( int *cells_from_prev, int *parts_from_prev )
+{
+ static error_handler bob("network::reo_from_prev",errname);
+
+ int msgtag = domain_number;
+
+ int data[2];
+
+ if (domain_number > 1) {
+
+ pvm_recv( tid_prev, msgtag );
+ pvm_upkint( data, 2, 1 );
+
+ *cells_from_prev = data[0];
+ *parts_from_prev = data[1];
+
+ bob.message( "recieve from previous: cells =", data[0], "parts =", data[1] );
+ }
+ else {
+ bob.error( "no previous domain" );
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void network::reo_from_next( int *cells_from_next, int *parts_from_next )
+{
+ static error_handler bob("network::reo_from_next",errname);
+
+ int msgtag = domain_number;
+
+ int data[2];
+
+ if (domain_number < n_domains) {
+
+ pvm_recv( tid_next, msgtag );
+ pvm_upkint( data, 2, 1 );
+
+ *cells_from_next = data[0];
+ *parts_from_next = data[1];
+
+ bob.message( "recieve from next: cells =", data[0], "parts =", data[1] );
+ }
+ else {
+ bob.error( "no next domain" );
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void network::reo_recieve_from_prev_and_unpack( int cells_from_prev, int parts_from_prev,
+ struct cell* firstcell, int *el_count, int *ion_count )
+{
+ static error_handler bob("network::reo_recieve_from_prev_and_unpack",errname);
+
+ int msgtag = domain_number;
+ int i,k;
+ int partcount=0;
+ struct cell *cell;
+ struct particle *part, *part_next;
+
+ *el_count = 0;
+ *ion_count = 0;
+
+ if (cells_from_prev > 0) {
+
+ pvm_recv( tid_prev, msgtag );
+
+ cell = firstcell;
+ part = cell->first;
+
+ cell = cell->prev->prev;
+
+ for(i=0;i<cells_from_prev + 2;i++,cell=cell->next) {
+
+ unpack_cell( cell );
+ cell->domain = domain_number;
+
+ for(k=0;k<cell->npart;k++) {
+
+ unpack_particle( part );
+ part_next = part->next;
+
+ if (part->prev!=NULL) part->prev->next = part->next;
+ else part->cell->first = part->next;
+ if (part->next!=NULL) part->next->prev = part->prev;
+ else part->cell->last = part->prev;
+ part->next = NULL;
+ part->prev = cell->last;
+ if (cell->last!=NULL) cell->last->next = part;
+ part->cell = cell;
+ cell->last = part;
+ if (part->prev==NULL) cell->first = part;
+
+ switch (part->species){
+ case 0:
+ (*el_count) ++;
+ partcount ++;
+ break;
+ case 1:
+ (*ion_count) ++;
+ partcount ++;
+ break;
+ }
+ part = part_next;
+ }
+ }
+
+ if (partcount!=parts_from_prev) {
+ bob.message( "number of particles recieved from prev does" );
+ bob.message( "NOT match intended number to receive" );
+ bob.error("");
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void network::reo_recieve_from_next_and_unpack( int cells_from_next, int parts_from_next,
+ struct cell* lastcell, int *el_count, int *ion_count )
+{
+ static error_handler bob("network::reo_recieve_from_next_and_unpack",errname);
+
+ int msgtag = domain_number;
+ int i,k;
+ int partcount=0;
+ struct cell *cell;
+ struct particle *part, *part_next;
+
+ *el_count = 0;
+ *ion_count = 0;
+
+ if ( cells_from_next > 0 ) {
+
+ pvm_recv( tid_next, msgtag );
+
+ cell = lastcell;
+ part = cell->first;
+
+ for(i=0;i<(cells_from_next - 1);i++, cell=cell->prev);
+
+ for(i=0;i<cells_from_next + 2;i++,cell=cell->next) {
+
+ unpack_cell( cell );
+ cell->domain = domain_number;
+
+ for(k=0;k<cell->npart;k++) {
+
+ unpack_particle( part );
+ part_next = part->next;
+
+ if (part->prev!=NULL) part->prev->next = part->next;
+ else part->cell->first = part->next;
+ if (part->next!=NULL) part->next->prev = part->prev;
+ else part->cell->last = part->prev;
+ part->next = NULL;
+ part->prev = cell->last;
+ if (cell->last!=NULL) cell->last->next = part;
+ part->cell = cell;
+ cell->last = part;
+ if (part->prev==NULL) cell->first = part;
+
+ switch (part->species){
+ case 0:
+ (*el_count) ++;
+ partcount ++;
+ break;
+ case 1:
+ (*ion_count) ++;
+ partcount ++;
+ break;
+ }
+
+ part = part_next;
+ }
+ }
+
+ if (partcount!=parts_from_next) {
+ bob.message( "number of particles recieved from next does" );
+ bob.message( "NOT match intended number to receive" );
+ bob.error("");
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void network::reo_to_prev( int cells_to_prev, int parts_to_prev )
+ // send cells_from_prev and parts_from_prev to previous domain
+{
+ static error_handler bob("network::reo_to_prev",errname);
+
+ int msgtag = domain_number-1;
+
+ int data[2];
+
+ data[0] = cells_to_prev;
+ data[1] = parts_to_prev;
+
+ if (domain_number > 1) {
+
+ pvm_initsend( PvmDataDefault );
+ pvm_pkint( data, 2, 1 );
+ pvm_send( tid_prev, msgtag );
+
+ bob.message( "send to previous: cells =", data[0], "parts =", data[1] );
+ }
+ else bob.message( "no previous domain" );
+
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void network::reo_to_next( int cells_to_next, int parts_to_next )
+ // send cells_from_next and parts_from_next to next domain
+{
+ static error_handler bob("network::reo_to_next",errname);
+
+ int msgtag = domain_number+1;
+
+ int data[2];
+
+ data[0] = cells_to_next;
+ data[1] = parts_to_next;
+
+ if (domain_number < n_domains) {
+
+ pvm_initsend( PvmDataDefault );
+ pvm_pkint( data, 2, 1 );
+ pvm_send( tid_next, msgtag );
+
+ bob.message( "send to next: cells =", data[0], "parts =", data[1] );
+ }
+ else bob.message( "no next domain" );
+
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void network::reo_pack_and_send_to_prev( int cells_to_prev, int parts_to_prev,
+ struct cell* firstcell )
+{
+ static error_handler bob("network::reo_pack_and_send_to_prev",errname);
+
+ int msgtag = domain_number-1;
+ int i;
+ int partcount=0;
+ struct cell *cell;
+ struct particle *part;
+
+ if ( cells_to_prev > 0 ) {
+
+ pvm_initsend( PvmDataDefault );
+ cell = firstcell;
+
+ for(i=0;i<cells_to_prev;i++,cell=cell->next) {
+ pack_cell( cell );
+ part = cell->first;
+ while(part != NULL)
+ {
+ pack_particle( part );
+ part = part->next;
+ partcount ++;
+ }
+ }
+
+ // send two more cells at the right end of the package which
+ // will be copied into rbuf and Rbuf in the previous domain
+ pack_cell_as_buffer( cell );
+ pack_cell_as_buffer( cell->next );
+
+ if (partcount!=parts_to_prev) {
+ bob.message( "number of particles sent to prev does" );
+ bob.message( "NOT match intended number to send" );
+ bob.error("");
+ }
+
+ pvm_send( tid_prev, msgtag );
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void network::reo_pack_and_send_to_next( int cells_to_next, int parts_to_next,
+ struct cell* lastcell )
+{
+ static error_handler bob("network::reo_pack_and_send_to_next",errname);
+
+ int msgtag = domain_number+1;
+ int i;
+ int partcount=0;
+ struct cell *cell;
+ struct particle *part;
+
+ if ( cells_to_next > 0 ) {
+
+ pvm_initsend( PvmDataDefault );
+ cell = lastcell;
+
+ for(i=0;i<(cells_to_next + 1);i++, cell=cell->prev);
+
+ // also send two more cells at the right end of package which will
+ // be copied into Lbuf and lbuf in the next domain
+ pack_cell_as_buffer( cell );
+ cell = cell->next;
+ pack_cell_as_buffer( cell );
+ cell = cell->next;
+
+ for(i=0;i<cells_to_next;i++,cell=cell->next) {
+ pack_cell( cell );
+ part = cell->first;
+ while(part != NULL)
+ {
+ pack_particle( part );
+ part = part->next;
+ partcount ++;
+ }
+ }
+
+ if (partcount!=parts_to_next) {
+ bob.message( "number of particles sent to next does" );
+ bob.message( "NOT match intended number to send" );
+ bob.error("");
+ }
+
+ pvm_send( tid_next, msgtag );
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::pack_particle( struct particle *part )
+{
+ static error_handler bob("network::pack_particle",errname);
+
+ pvm_pkint( &(part->number), 1, 1 );
+ pvm_pkint( &(part->species), 1, 1 );
+ pvm_pkint( &(part->fix), 1, 1 );
+ pvm_pkdouble( &(part->z), 1, 1 );
+ pvm_pkdouble( &(part->m), 1, 1 );
+ pvm_pkdouble( &(part->zm), 1, 1 );
+ pvm_pkdouble( &(part->x), 1, 1 );
+ pvm_pkdouble( &(part->dx), 1, 1 );
+ pvm_pkdouble( &(part->igamma), 1, 1 );
+ pvm_pkdouble( &(part->ux), 1, 1 );
+ pvm_pkdouble( &(part->uy), 1, 1 );
+ pvm_pkdouble( &(part->uz), 1, 1 );
+ pvm_pkdouble( &(part->n), 1, 1 );
+ pvm_pkdouble( &(part->zn), 1, 1 );
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::unpack_particle( struct particle *part )
+{
+ static error_handler bob("network::unpack_particle",errname);
+
+ pvm_upkint( &(part->number), 1, 1 );
+ pvm_upkint( &(part->species), 1, 1 );
+ pvm_upkint( &(part->fix), 1, 1 );
+ pvm_upkdouble( &(part->z), 1, 1 );
+ pvm_upkdouble( &(part->m), 1, 1 );
+ pvm_upkdouble( &(part->zm), 1, 1 );
+ pvm_upkdouble( &(part->x), 1, 1 );
+ pvm_upkdouble( &(part->dx), 1, 1 );
+ pvm_upkdouble( &(part->igamma), 1, 1 );
+ pvm_upkdouble( &(part->ux), 1, 1 );
+ pvm_upkdouble( &(part->uy), 1, 1 );
+ pvm_upkdouble( &(part->uz), 1, 1 );
+ pvm_upkdouble( &(part->n), 1, 1 );
+ pvm_upkdouble( &(part->zn), 1, 1 );
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::pack_cell( struct cell *cell )
+{
+ static error_handler bob("network::pack_cell",errname);
+
+ pvm_pkint( &(cell->number), 1, 1 );
+ pvm_pkdouble( &(cell->x), 1, 1 );
+ pvm_pkdouble( &(cell->charge), 1, 1 );
+ pvm_pkdouble( &(cell->jx), 1, 1 );
+ pvm_pkdouble( &(cell->jy), 1, 1 );
+ pvm_pkdouble( &(cell->jz), 1, 1 );
+ pvm_pkdouble( &(cell->ex), 1, 1 );
+ pvm_pkdouble( &(cell->ey), 1, 1 );
+ pvm_pkdouble( &(cell->ez), 1, 1 );
+ pvm_pkdouble( &(cell->bx), 1, 1 );
+ pvm_pkdouble( &(cell->by), 1, 1 );
+ pvm_pkdouble( &(cell->bz), 1, 1 );
+ pvm_pkdouble( &(cell->fp), 1, 1 );
+ pvm_pkdouble( &(cell->fm), 1, 1 );
+ pvm_pkdouble( &(cell->gp), 1, 1 );
+ pvm_pkdouble( &(cell->gm), 1, 1 );
+ pvm_pkdouble( (cell->dens), 2, 1 );
+ pvm_pkint( (cell->np), 2, 1 );
+ pvm_pkint( &(cell->npart), 1, 1 );
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::unpack_cell( struct cell *cell )
+{
+ static error_handler bob("network::unpack_cell",errname);
+
+ pvm_upkint( &(cell->number), 1, 1 );
+ pvm_upkdouble( &(cell->x), 1, 1 );
+ pvm_upkdouble( &(cell->charge), 1, 1 );
+ pvm_upkdouble( &(cell->jx), 1, 1 );
+ pvm_upkdouble( &(cell->jy), 1, 1 );
+ pvm_upkdouble( &(cell->jz), 1, 1 );
+ pvm_upkdouble( &(cell->ex), 1, 1 );
+ pvm_upkdouble( &(cell->ey), 1, 1 );
+ pvm_upkdouble( &(cell->ez), 1, 1 );
+ pvm_upkdouble( &(cell->bx), 1, 1 );
+ pvm_upkdouble( &(cell->by), 1, 1 );
+ pvm_upkdouble( &(cell->bz), 1, 1 );
+ pvm_upkdouble( &(cell->fp), 1, 1 );
+ pvm_upkdouble( &(cell->fm), 1, 1 );
+ pvm_upkdouble( &(cell->gp), 1, 1 );
+ pvm_upkdouble( &(cell->gm), 1, 1 );
+ pvm_upkdouble( (cell->dens), 2, 1 );
+ pvm_upkint( (cell->np), 2, 1 );
+ pvm_upkint( &(cell->npart), 1, 1 );
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::pack_cell_as_buffer( struct cell *cell )
+ // this cell is packed without particle information since
+ // it will be unpacked into a buffer cell
+{
+ static error_handler bob("network::pack_cell_as_buffer",errname);
+ int np[2],npart;
+ np[0] = 0;
+ np[1] = 0;
+ npart = 0;
+
+ pvm_pkint( &(cell->number), 1, 1 );
+ pvm_pkdouble( &(cell->x), 1, 1 );
+ pvm_pkdouble( &(cell->charge), 1, 1 );
+ pvm_pkdouble( &(cell->jx), 1, 1 );
+ pvm_pkdouble( &(cell->jy), 1, 1 );
+ pvm_pkdouble( &(cell->jz), 1, 1 );
+ pvm_pkdouble( &(cell->ex), 1, 1 );
+ pvm_pkdouble( &(cell->ey), 1, 1 );
+ pvm_pkdouble( &(cell->ez), 1, 1 );
+ pvm_pkdouble( &(cell->bx), 1, 1 );
+ pvm_pkdouble( &(cell->by), 1, 1 );
+ pvm_pkdouble( &(cell->bz), 1, 1 );
+ pvm_pkdouble( &(cell->fp), 1, 1 );
+ pvm_pkdouble( &(cell->fm), 1, 1 );
+ pvm_pkdouble( &(cell->gp), 1, 1 );
+ pvm_pkdouble( &(cell->gm), 1, 1 );
+ pvm_pkdouble( (cell->dens), 2, 1 );
+ pvm_pkint( np, 2, 1 );
+ pvm_pkint( &npart, 1, 1 );
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+void network::end_task( void )
+{
+ printf( "\n end of task in domain #%d\n\n", domain_number );
+ if (n_domains>1) pvm_exit();
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+//eof
+
+#endif
+#endif