c
c node.f 8.1 91/04/04 11:07:58
c
c This program calculates the value of pi, using numerical integration
c with parallel processing, and clocks the solution time. 
c
c   This is the node program, which shows how the iPSC/2 nodes can be
c   used to calculate the definite integral of a function f(x).
c
c   Each node: 
c   	1) receives the integration parameters by invoking crecv,
c	2) calculates a partial integral over its sub-interval, and
c	3) sends its contribution to node 0, which adds the
c	   integral and sends the total back to the host.
c
c
c   Program Components:
c
c   Constants:
c
c	INITTYPE	Type of initial message to the cube
c	PARTTYPE	Type of message holding partial integral
c	MSGSIZE		Size of messages to and from the cube
c
c   Variables:
c
c	worknodes	total number of participating nodes in the cube
c	mynod		node id returned by mynode()
c	size		holds cube size
c
c	points		total number of points to use in integration
c	basicpoints	basic number of points per node
c	extrapoints	extra points; to be assigned to lower nodes
c	mypoints	number of points assigned to a node process
c	
c	a		lower limit of integration
c	b		upper limit of integration
c	mya		this node's lower limit of partial integration
c	myb		this node's upper limit of partial integration
c	
c	msg		initial message received from host. Holds parameters of
c			integration (a, b, points)
c	x		independent variable of integration
c	f		function to integrate (external)
c	slicesize	size of integration slice
c	partialint	partial integral calculated on node
c	i		loop counter
c	
c   External Routines: 
c
c	f		to evaluate the function f(x) being integrated
c	mynode		to obtain the node id for this process
c	mypid		to obtain the process id of this process
c	numnodes	to determine the size of cube being used 
c	

	program node

	include 'fcube.h'

	integer SIZETYPE, INITTYPE, PARTTYPE, MSGSIZE, CUBESIZE,
     >		  HOST, HOSTPID, APPLPID, DOUBLESIZE

	integer*4 worknodes, mynod, pid, size
	integer*4 basicpoints, extrapoints, mypoints, i, j
	integer*4 starttime, points
	integer*4 msg(5)

	double precision x, slicesize, partialint, a, b, mya, myb
	double precision work, sum
  
        character*50 cpyright  
  
	external  f
	double precision f
c
c	make explicit the structure of msg:
c
	equivalence (msg(1), a)
	equivalence (msg(3), b)
	equivalence (msg(5), points)

	data SIZETYPE /0/, INITTYPE /5/, PARTTYPE /20/, MSGSIZE /20/,
     >       CUBESIZE /4/, VECTORLEN / 1/, HOSTPID /100/,
     >       APPLPID /0/, DOUBLESIZE /8/

        cpyright = 'Copyright (c) 1989,1990 Intel Corporation'      

	HOST = myhost()
	pid = mypid()
  	mynod = mynode()
 
c	
c	get the size of the cube to put to work on problem
c
100	call crecv(SIZETYPE, size, CUBESIZE)
  	worknodes = size

c
c 	receive integration parameters 
c
	call crecv(INITTYPE, msg, MSGSIZE)

c
c	if this node is not among the worker nodes it returns to the  
c 	beginning to wait for another chance to work 
c
	partialint = 0.0
	if (mynod .lt. worknodes) then

c start the clock running
            starttime = mclock()

c calculate slice size:
    	    slicesize = (b - a) / points

c calculate # of points per node & local sub-interval:
	    basicpoints = points/worknodes
	    extrapoints = mod(points, worknodes)

    	    if (mynod.lt.extrapoints) then 
               mypoints = basicpoints + 1
       	       mya = a + slicesize * mynod * mypoints
	    else 
               mypoints = basicpoints
               mya = a + slicesize * (mynod * mypoints + extrapoints)
	    endif

	    myb = mya + slicesize * mypoints

c calculate the partial integral of the function over my sub-interval:
	    do 200 i=1, mypoints
	       x = mya + (i - 0.5D0)*slicesize
               partialint = partialint + f(x) * slicesize
200	    continue
	endif

c if we're node 0, gather all the contributions from all the other
c nodes, add them up, and send the result to the host
c also, figure elapsed time and send in message
c
c the nodes that didn't do any work also participate in the gdsum(),
c but their partialint is 0.0

	call gdsum(partialint, 1, work)
	if (mynode() .eq. 0) then
	    a = partialint
	    points = mclock() - starttime
	    call csend(PARTTYPE, msg, MSGSIZE, HOST, HOSTPID)
	endif

	goto 100
	end

