/*
heatslv.c
    The slaves receive the initial data from the host, 
    exchange boundary information with neighbors, 
    and calculate the heat change in the wire. 
    This is done for a number of iterations, sent by the master.
*/
#include "pvm3.h"
#include <stdio.h>
int num_data;
main()
{
    int mytid, left, right, i, j, master;
    int timestep;
    double *init, *A;
    double leftdata, rightdata, delta, leftside, rightside; 
/* enroll in pvm */
    mytid = pvm_mytid();
    master = pvm_parent();
/* receive my data from the master program */
  while(1) {
    pvm_recv(master, 4);
    pvm_upkint(&left, 1, 1);
    pvm_upkint(&right, 1, 1);
    pvm_upkint(×tep, 1, 1);
    pvm_upkdouble(&delta, 1, 1);
    pvm_upkint(&num_data, 1, 1);
    init = (double *) malloc(num_data*sizeof(double)); 
    pvm_upkdouble(init, num_data, 1);
/* copy the initial data into my working array */
    A = (double *) malloc(num_data * timestep * sizeof(double)); 
    for (i = 0; i < num_data; i++) A[i] = init[i];
/* perform the calculation */
  for (i = 0; i < timestep-1; i++) {
    /* trade boundary info with my neighbors */
    /*  send left, receive right    */
    if (left != 0) {
        pvm_initsend(PvmDataDefault);
        pvm_pkdouble(&A[wh(i,0)],1,1);
        pvm_send(left, 5);
        }
    if (right != 0) {
        pvm_recv(right, 5);
        pvm_upkdouble(&rightdata, 1, 1);
    /* send right, receive left */
        pvm_initsend(PvmDataDefault);
        pvm_pkdouble(&A[wh(i,num_data-1)],1,1);
        pvm_send(right, 6);
        }
    if (left != 0) {
        pvm_recv(left, 6);
        pvm_upkdouble(&leftdata,1,1);
        }
    
/* do the calculations for this iteration */
    for (j = 0; j < num_data; j++) {
        leftside = (j == 0) ? leftdata : A[wh(i,j-1)]; 
        rightside = (j == (num_data-1)) ? rightdata : A[wh(i,j+1)]; 
        if ((j==0)&&(left==0))
            A[wh(i+1,j)] = 0.0;
        else if ((j==(num_data-1))&&(right==0))
            A[wh(i+1,j)] = 0.0;
        else
            A[wh(i+1,j)]=
                A[wh(i,j)]+delta*(rightside-2*A[wh(i,j)]+leftside); 
        }
  }
/* send the results back to the master program */
    pvm_initsend(PvmDataDefault);
    pvm_pkdouble(&A[0],num_data*timestep,1); 
    pvm_send(master,7);
  }
    
/* just for good measure */
  pvm_exit();
}
int wh(x, y)
int x, y;
{
    return(x*num_data+y);
}