c
c node.f  91/21/11 21:15:04
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 calculates the partial integral over an block 
c
c   Each node:
c	1) receives the integration parameters by invoking bcast0
c	2) calculates a partial integral over its sub-interval, and
c	3) sends its contribution to the host by invoking gsum0
c
c   Program Components:
c
c   Constants:
c
c       INITTYPE        Type of initial message received from host 
c       MSGSIZE         Size of initial message
c       PARTTYPE        Type of message holding partial integrals
c       TIMETYPE        Type of message holding timing information sent to host 
c       TIMESIZE        Size of timing message
c       ALLNODES        (= -1) Argument to represent all nodes
c
c   Variables:
c
c       msg             Message received from host. Holds a, b, & points
c
c       points          Number of points used in the integration.
c 	basicpoints     Basic number of points per node
c	extrapoints     Extra points; to be assigned to lower node
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       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       NPROCS          Cubesize being used
c       ME              My processor ID number
c       HOST            Host processor ID number
c
c       starttime       Starting time on the node
c       node_sec        Computation time on the node
c
c   Calls:
c
c	f		to evaluate the function f(x) being evaluated
c	tracenode	to start tracing on the node
c	tracelevel	to control the amount of trace data generated

	program node

c
c       Include header file with PICL call declarations
c
        include 'picl_def.h'

	external  f
	double precision f

	integer   INITTYPE, PARTTYPE, MSGSIZE, TIMESIZE, TIMETYPE

	integer*4 points, basicpoints, extrapoints, mypoints
	integer*4 i, j 
	integer*4 msg(5)

        integer*4 NPROCS, ALLNODES, TOP, ORD, DIR, HOST, ME

	double precision x, slicesize, partialint, a, b, mya, myb
	double precision work, sum
	double precision starttime,  node_sec
  
c
c	make explicit the structure of msg:
c
	equivalence (msg(1), a)
	equivalence (msg(3), b)
	equivalence (msg(5), points)

	data INITTYPE /5/, PARTTYPE /20/, MSGSIZE /20/,
     >       TIMETYPE /10/, TIMESIZE /8/

c
c	Enable tracing on the node with a buffer size of 100000 bytes
c	Flush buffer when full
c	Synchronize  node system clocks before tracing
c
cc      call tracenode(100000, 1, 1)

c
c	Generate least amount of trace dta
c
cc      call tracelevel(0 ,0, 0)

c       Allocate requested processors and enable interprocessor communication
c       Must be called on host and node
c       On node returns number of allocated processors, nodes ID number and host's ID number
c
        call open0(NPROCS,ME,HOST)

c
c       Setup the allocated processors in a Hypercube topology
c       Should be called by the host and the nodes
c
        call setarc0(NPROCS, TOP, ORD, DIR)
        
c
c 	Receive integration parameters from the host
c
        call bcast0(msg, MSGSIZE, INITTYPE, HOST)

c
c	Generate maximum trace data (event, compstats and commstats)
c
cc      call tracelevel(4 ,4, 4)

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 (ME .lt. NPROCS) then

c
c           Start the clock running
c
            starttime = clock0()

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

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

    	    if (ME .lt. extrapoints) then 
               mypoints = basicpoints + 1
     	       mya = a + slicesize * ME * mypoints
	    else 
               mypoints = basicpoints
               mya = a + slicesize * (ME * 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
c       Compute the sum of the partial integral from the nodes and
c       return in into "integral" on the host
c
        call gsum0(partialint,1,5,PARTTYPE,HOST) 

c
c       Calculate computation time on the node
c
        node_sec = clock0() - starttime

c
c       Set amount of trace data generated to minimum
c
cc      call tracelevel(0 ,0, 0)

c
c	Node 0 sends node timing information to the host
c
        if (ME .eq. 0) then
           call send0(node_sec, TIMESIZE, TIMETYPE, HOST)
        endif

c
c	Disable interprocessor communication
c
        call close0()
	end

