Index: /branches/numpy_misc/tools/acceptance_tests/README
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/README	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/README	(revision 6991)
@@ -0,0 +1,14 @@
+This directory contains the python cluster acceptance test system code.
+
+The programs here are designed to be run as a complete suite as well
+as individually.  The suite writes to a log file as well as standard out.
+
+To run all tests in sequence, do:
+    python test_all.py [<logfile>]
+If no logfile is supplied, ./test.log is assumed.
+
+--------------------------------------------------------------------------------
+
+To run these tests on another cluster:
+1. Modify the Cluster_Data structure in test_utils.py to match the new cluster 
+   information.
Index: /branches/numpy_misc/tools/acceptance_tests/ctiming.c
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/ctiming.c	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/ctiming.c	(revision 6991)
@@ -0,0 +1,188 @@
+/*
+  Estimate bandwidth and latency of a parallel computer using MPI.
+  Ole Moller Nielsen - 1998
+*/
+	
+#include <stdio.h>
+#include <stdlib.h>
+#include <mpi.h>
+
+
+#define MAXI  10         /* Number of blocks */
+#define MAXM  500000     /* Largest block */
+#define BLOCK MAXM/MAXI  /* Block size */
+
+
+double linfit(double* x, double* y, int N, double* a, double* b) 
+{
+  /* Given vectors y and x fit a and b to the model y = ax + b */
+  
+  double Sx=0, Sy=0, SxoN=0, SSoN=0, t=0;
+  double res, varest=0, norm=0; 
+  int i;
+  
+  for (i=0; i<N; i++)
+  {
+    /*printf("x,y = %f, %f\n",x[i],y[i]);*/
+    Sx  = Sx + x[i];
+    Sy  = Sy + y[i];
+  }
+
+  SxoN = Sx/N;
+  
+  *a = 0.0; 
+  for (i=0; i<N; i++)
+  {
+    t    = x[i] - SxoN;
+    SSoN = SSoN + t*t;
+    *a   = *a + t*y[i];
+  }
+
+  *a = (*a)/SSoN;          /* a = (N Sxy - SxSy)/(NSxx - Sx^2) */
+  *b = (Sy - Sx*(*a))/N;
+  
+  /* Quality - variance estimate \sum_i r_i^2 /(m-n) */
+  for (i=0; i<N; i++)
+  {
+    norm = norm + x[i]*x[i];
+    res = y[i] - (*a)*x[i] - (*b);
+    varest = varest + res*res;
+  } 
+  varest = varest/norm/(N-2); 
+  return(varest);
+}
+
+main(int argc, char **argv) 
+{
+   int repeats = 10, msgid = 0;
+   int myid, procs;
+   int i,j,k,m;
+
+   double t1, t2, cpuOH; 
+   double Tbw, Tlat;
+   double varest;
+      
+   int noelem[MAXI];
+   double bytes[MAXI];   
+   double mintime[MAXI];   
+   double maxtime[MAXI];      
+   double avgtime[MAXI];         
+   double A[MAXM]; 
+
+   int  namelen;
+   char processor_name[MPI_MAX_PROCESSOR_NAME];
+   
+   MPI_Status stat;
+  
+   
+   /* Initialize */
+
+   MPI_Init(&argc,&argv);
+   MPI_Comm_size(MPI_COMM_WORLD,&procs);
+   MPI_Comm_rank(MPI_COMM_WORLD,&myid);
+   MPI_Get_processor_name(processor_name,&namelen);
+   
+   if (myid==0)
+   {
+     printf("MAXM = %d, number of processors = %d\n",MAXM,procs);         
+     printf("Measurements are repeated %d times for reliability\n",repeats);
+   } 
+   
+   if (procs < 2) {
+     printf("Program needs at least two processors - aborting\n");
+     MPI_Abort(MPI_COMM_WORLD,999);
+   }
+   
+   MPI_Barrier(MPI_COMM_WORLD); /* Synchronize */   
+   printf("I am process %d on %s\n",myid,processor_name);   
+      
+   for (j=0; j<MAXM; j++) 
+   {
+      A[j]=rand();
+   }   
+   for (i=0; i<MAXI; i++) 
+   {
+      avgtime[i] =  0;         
+      mintime[i] =  1000000;      
+      maxtime[i] = -1000000;            
+   }
+   
+   /* Determine timer overhead */
+   if (myid == 0) {   
+     cpuOH = 1.0;
+     for (k=0; k<repeats; k++)   /* Repeat to get reliable timings */
+     { 
+       t1 = MPI_Wtime();
+       t2 = MPI_Wtime();
+       if (t2-t1 < cpuOH) cpuOH = t2-t1;
+     }  
+     printf("Timing overhead is %f seconds\n\n", cpuOH);              
+   }
+
+   
+        
+   /* Pass msg circularly */
+     
+   for (k=0; k<repeats; k++) {
+     if (myid == 0) {  
+       printf("Run %d of %d\n", k+1, repeats);
+     }  
+
+     for (i=0; i<MAXI; i++) {
+       /*m=BLOCK*(i+1);*/
+       m=BLOCK*i+1;       
+      
+       noelem[i] = m;
+      
+       MPI_Barrier(MPI_COMM_WORLD); /* Synchronize */
+      
+       if (myid == 0) {
+         t1=MPI_Wtime();
+         MPI_Send(&A[0],m,MPI_DOUBLE,1,msgid,MPI_COMM_WORLD);
+         MPI_Recv(&A[0],m,MPI_DOUBLE,procs-1,msgid,MPI_COMM_WORLD,&stat);
+         t2=MPI_Wtime() - t1 - cpuOH;
+	 t2 = t2/procs;
+	 avgtime[i] = avgtime[i] + t2;
+         if (t2 < mintime[i]) mintime[i] = t2;
+         if (t2 > maxtime[i]) maxtime[i] = t2;	 
+       } else {
+         MPI_Recv(&A[0],m,MPI_DOUBLE,myid-1,msgid,MPI_COMM_WORLD,&stat);
+         MPI_Send(&A[0],m,MPI_DOUBLE,(myid+1)%procs,msgid,MPI_COMM_WORLD);
+       }
+     } 
+   }
+
+   if (myid == 0) {
+     printf("Bytes transferred   time (micro seconds)\n");
+     printf("                    min        avg        max \n");     
+     printf("----------------------------------------------\n");      
+        
+     for (i=0; i<MAXI; i++) {
+       avgtime[i] = avgtime[i]/repeats*1.0e6; /*Average micro seconds*/
+       mintime[i] = mintime[i]*1.0e6;         /*Min micro seconds*/       
+       maxtime[i] = maxtime[i]*1.0e6;         /*Min micro seconds*/              
+             
+       m = noelem[i];
+       bytes[i] = (double) 8*noelem[i];       
+	 
+       /* printf("m=%d, time(min)=%lf, time(avg)=%lf, time(max)=%lf\n",
+	       m,mintime[i],avgtime[i],maxtime[i]); */
+       printf("%10d    %10d %10d %10d\n",
+	 (int) bytes[i], (int) mintime[i], (int) avgtime[i], (int)maxtime[i]); 
+     }		 
+   
+     varest=linfit(bytes, mintime, MAXI, &Tbw, &Tlat);
+     printf("\nLinear regression on best timings (t = t_l + t_b * bytes):\n");
+
+     printf("  t_b = %f\n  t_l = %f\n", Tbw, Tlat);
+     printf("  Estimated relative variance = %.9f\n\n",varest);     
+
+     printf("Estimated bandwith (1/t_b):  %.3f Mb/s\n", (1.0/Tbw));         
+     printf("Estimated latency:           %d micro s\n", 
+             (int) (mintime[0] - (float) bytes[0]* (float)Tbw));         
+     
+   }
+
+   MPI_Finalize();
+}
+
Index: /branches/numpy_misc/tools/acceptance_tests/mandelbrot/README
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/mandelbrot/README	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/mandelbrot/README	(revision 6991)
@@ -0,0 +1,18 @@
+Files in this directory gives examples of different parallel strategies using the mandbrot fractal as example. The codes need PIL (Python Imaging Library) to
+show the results, but the computational bit will still work without PIL.
+It also tries to show images using either xv of eog (EyeOfGnome).
+
+This material was developed as part of a teaching module and is documented 
+further at 
+
+http://datamining.anu.edu.au/~ole/work/teaching/summerschool2005/
+
+
+To compile C extensions in this directory
+
+python compile_mandelbrot_extensions.py
+
+or
+python compile.py mandel_ext.c
+python compile.py mandelplot_ext.c
+
Index: /branches/numpy_misc/tools/acceptance_tests/mandelbrot/compile.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/mandelbrot/compile.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/mandelbrot/compile.py	(revision 6991)
@@ -0,0 +1,205 @@
+"""compile.py - compile Python C-extension
+
+   Commandline usage: 
+     python compile.py <filename>
+
+   Usage from within Python:
+     import compile
+     compile.compile(<filename>,..)
+
+   Ole Nielsen, Oct 2001      
+"""   
+
+import numpy
+def compile(FNs=None, CC=None, LD = None, SFLAG = None, verbose = 1):
+  """compile(FNs=None, CC=None, LD = None, SFLAG = None):
+  
+     Compile FN(s) using compiler CC (e.g. mpicc), 
+     Loader LD and shared flag SFLAG.
+     If CC is absent use default compiler dependent on platform
+     if LD is absent CC is used.
+     if SFLAG is absent platform default is used
+     FNs can be either one filename or a list of filenames
+     In the latter case, the first will be used to name so file.
+  """
+  import os, string, sys, types
+  
+  # Input check
+  #
+  assert not FNs is None, "No filename provided"
+
+  if not type(FNs) == types.ListType:
+    FNs = [FNs]
+
+  # Determine platform and compiler
+  #
+  if sys.platform == 'sunos5':  #Solaris
+    if CC:
+      compiler = CC
+    else:  
+      compiler = 'gcc'
+    if LD:
+      loader = LD
+    else:  
+      loader = compiler
+    if SFLAG:
+      sharedflag = SFLAG
+    else:  
+      sharedflag = 'G'
+      
+  elif sys.platform == 'osf1V5':  #Compaq AlphaServer
+    if CC:
+      compiler = CC
+    else:  
+      compiler = 'cc'
+    if LD:
+      loader = LD
+    else:  
+      loader = compiler
+    if SFLAG:
+      sharedflag = SFLAG
+    else:  
+      sharedflag = 'shared'    
+      
+  elif sys.platform == 'linux2':  #Linux
+    if CC:
+      compiler = CC
+    else:  
+      compiler = 'gcc'
+    if LD:
+      loader = LD
+    else:  
+      loader = compiler
+    if SFLAG:
+      sharedflag = SFLAG
+    else:  
+      sharedflag = 'shared'    
+      
+  elif sys.platform == 'darwin':  #Mac OS X:
+    if CC:
+      compiler = CC
+    else:  
+      compiler = 'cc'
+    if LD:
+      loader = LD
+    else:  
+      loader = compiler
+    if SFLAG:
+      sharedflag = SFLAG
+    else:  
+      sharedflag = 'bundle -flat_namespace -undefined suppress'
+      
+  else:
+    if verbose: print "Unrecognised platform %s - revert to default"\
+                %sys.platform
+    
+    if CC:
+      compiler = CC
+    else:  
+      compiler = 'cc'
+    if LD:
+      loader = LD
+    else:  
+      loader = 'ld'
+    if SFLAG:
+      sharedflag = SFLAG
+    else:  
+      sharedflag = 'G'
+
+            
+  # Find location of include files
+  #
+  python_include = os.path.join(os.path.join(sys.exec_prefix, 'include'),
+                                'python'+sys.version[:3])
+  
+  
+  # Check existence of Python.h
+  #
+  headerfile = python_include + '/Python.h'
+  try:
+    open(headerfile, 'r')
+  except:
+    raise """Did not find Python header file %s.
+    Make sure files for Python C-extensions are installed. 
+    In debian linux, for example, you need to install a
+    package called something like python2.1-dev""" %headerfile
+
+
+  # Get numpy include
+  numpy_include = numpy.get_include()
+  
+  
+  # Check filename(s)
+  #
+  object_files = ''
+  for FN in FNs:        
+    root, ext = os.path.splitext(FN)
+    if ext == '':
+      FN = FN + '.c'
+    elif ext.lower() != '.c':
+      raise Exception, "Unrecognised extension: " + FN
+    
+    try:
+      open(FN,'r')
+    except:    
+      raise Exception, "Could not open: " + FN
+
+    if not object_files: root1 = root  #Remember first filename        
+    object_files += root + '.o '  
+  
+  
+    # Compile
+    #
+    s = "%s -c %s -I%s -I%s -o %s.o -Wall" %(compiler, FN,
+                                       python_include, numpy_include,
+                                       root)
+    if os.name == 'posix' and os.uname()[4] == 'x86_64':
+      #Extra flags for 64 bit architectures
+      s += ' -fPIC -m64' #gcc
+      #s += ' -fPIC -tp amd64' #pgcc
+    
+    if verbose:
+      print s
+    else:
+      s = s + ' 2> /dev/null' #Suppress errors
+  
+    try:
+      os.system(s)
+    except:
+      raise 'Could not compile %s - please try manually' %FN  
+
+  
+  # Make shared library (*.so)
+  s = "%s -%s %s -o %s.so" %(loader, sharedflag, object_files, root1)
+
+  if os.name == 'posix' and os.uname()[4] == 'x86_64':
+      pass
+      #Extra flags for 64 bit architectures using Portland compilers
+      s += ' -mcmodel=medium'
+  
+  if verbose:
+    print s
+  else:
+    s = s + ' 2> /dev/null' #Suppress warnings
+  
+  try:  
+    err=os.system(s)
+  except:
+    raise 'Could not link %s - please try manually' %root1
+    
+
+
+
+if __name__ == '__main__':
+
+  import sys
+  
+  # Get file to compile
+  #
+  if len(sys.argv) < 2:
+    print "Usage:"
+    print "  python compile.py <filename>"
+    sys.exit()
+
+  compile(sys.argv[1], verbose=1)
+
Index: /branches/numpy_misc/tools/acceptance_tests/mandelbrot/compile_mandelbrot_c_extensions.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/mandelbrot/compile_mandelbrot_c_extensions.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/mandelbrot/compile_mandelbrot_c_extensions.py	(revision 6991)
@@ -0,0 +1,12 @@
+"""This module will compile the necessary c-extensions for the mandelbrot demos
+"""
+
+import os
+
+s = 'python compile.py mandel_ext.c'
+print
+os.system(s)
+
+s = 'python compile.py mandelplot_ext.c'
+print
+os.system(s)
Index: /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandel_ext.c
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandel_ext.c	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandel_ext.c	(revision 6991)
@@ -0,0 +1,69 @@
+/* Python - C extension for fast computation of the Mandelbrot iteration
+//
+// To compile:
+//  python compile.py mandel_ext.c
+//
+// Example of how to use within Python:
+//
+// from mandel_ext import calculate_point
+//
+// kmax = 256
+// c = complex(0.5, 0.5)
+// k = calculate_point(c, kmax)
+//
+// Ole Nielsen, SUT 2003 */
+	
+#include "Python.h"
+
+/* Computational function */
+int _calculate_point(Py_complex c, int kmax) {
+  int count;
+  double temp, lengthsq = 0.0;  
+  Py_complex z;
+  
+  z.real = 0.0; z.imag = 0.0; 
+  count = 0;
+
+  while (count < kmax && lengthsq <= 4) {
+       temp = z.real * z.real - z.imag * z.imag + c.real;
+       z.imag = 2.0 * z.real * z.imag + c.imag;
+       z.real = temp;
+       lengthsq = z.real * z.real + z.imag * z.imag;
+       count++;    
+  }
+
+  return count;
+}
+
+
+/* Interface to Python */
+PyObject *calculate_point(PyObject *self, PyObject *args) {
+  PyComplexObject *C;  /* Python Complex object */
+  Py_complex c;        /* C Complex structure */
+  int kmax, count;
+
+  /* Convert Python arguments to C  */
+  if (!PyArg_ParseTuple(args, "Oi", &C, &kmax))
+    return NULL;
+  c = PyComplex_AsCComplex((PyObject*) C);   
+  
+  /* Call underlying routine */
+  count = _calculate_point(c, kmax); 
+
+  /* Return results as a Python object */
+  return Py_BuildValue("i", count);
+}
+
+
+/* Method table for python module */
+static struct PyMethodDef MethodTable[] = {
+  {"calculate_point", calculate_point, METH_VARARGS},  
+  {NULL, NULL}
+};
+
+
+/* Module initialisation  */
+void initmandel_ext(void){
+  Py_InitModule("mandel_ext", MethodTable);
+}
+
Index: /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandel_parallel_blockwise.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandel_parallel_blockwise.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandel_parallel_blockwise.py	(revision 6991)
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+	
+"""Parallel program computing the Mandelbrot set using static partitioned 
+load balancing.
+
+   Due to the uneven work load of different regions,
+   this strategy will *not* generally lead to linear speedup
+
+   See mandel_parallel_dynamic.py for a better approach.
+
+   Ole Nielsen, SUT 2003
+"""
+
+from mandelbrot import calculate_region, balance
+from mandelplot import plot
+import pypar
+
+# User definable parameters
+kmax = 2**15   # Maximal number of iterations (=number of colors)
+M = N = 700    # width = height = N (200 or 700)
+
+# Region in complex plane
+real_min = -2.0
+real_max =  1.0
+imag_min = -1.5
+imag_max =  1.5
+
+#Initialise
+t = pypar.time()
+P = pypar.size()
+p = pypar.rank()
+processor_name = pypar.get_processor_name()
+
+print 'Processor %d initialised on node %s' %(p,processor_name)
+
+
+# Balanced work partitioning (row wise)
+Mlo, Mhi = pypar.balance(M, P, p)
+print 'p%d: [%d, %d], Interval length=%d' %(p, Mlo, Mhi, Mhi-Mlo)
+
+# Parallel computation 
+A = calculate_region(real_min, real_max, imag_min, imag_max, kmax,
+                     M, N, Mlo = Mlo, Mhi = Mhi)
+
+print 'Processor %d: time = %.2f' %(p, pypar.time() - t)
+
+
+# Communication phase
+if p == 0:
+    for d in range(1, P):
+        A += pypar.receive(source=d)
+
+    print 'Computed region in %.2f seconds' %(pypar.time()-t)
+    plot(A, kmax)        
+else:
+    pypar.send(A, destination=0)
+
+pypar.finalize()                
+
+
+
+
+
Index: /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandel_parallel_cyclic.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandel_parallel_cyclic.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandel_parallel_cyclic.py	(revision 6991)
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+	
+"""Parallel program computing the Mandelbrot set using static,
+   cyclic load balancing.
+
+   This is probably the best approach for this problem.
+
+   Ole Nielsen, SUT 2003
+"""
+
+from mandelbrot import calculate_region_cyclic
+from mandelplot import plot
+import pypar
+
+# User definable parameters
+kmax = 2**15  # Maximal number of iterations (=number of colors)
+M = N = 700   # width = height = N (200 or 700)
+
+# Region in complex plane [-2:2]
+real_min = -2.0
+real_max =  1.0
+imag_min = -1.5
+imag_max =  1.5
+
+#Initialise
+t = pypar.time()
+P = pypar.size()
+p = pypar.rank()
+processor_name = pypar.get_processor_name()
+
+print 'Processor %d initialised on node %s' %(p,processor_name)
+
+
+# Parallel computation 
+A = calculate_region_cyclic(real_min, real_max, imag_min,
+                            imag_max, kmax,
+                            M, N, p, P)
+
+print 'Processor %d: time = %.2f' %(p, pypar.time() - t)
+
+
+# Communication phase
+if p == 0:
+    for d in range(1, P):
+        A += pypar.receive(source=d)
+
+    print 'Computed region in %.2f seconds' %(pypar.time()-t)
+    #plot(A, kmax)        
+else:
+    pypar.send(A, destination=0)
+
+pypar.finalize()                
+
+
+
+
+
Index: /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandel_parallel_dynamic.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandel_parallel_dynamic.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandel_parallel_dynamic.py	(revision 6991)
@@ -0,0 +1,104 @@
+#!/usr/bin/env python
+
+"""Parallel program computing the Mandelbrot set using dynamic load balancing.
+   Simplified version for use with exercise 15.
+
+   To keep master process busy, run with P+1 processes
+   where P is the number of physical processors.
+   
+   Ole Nielsen, SUT 2003
+"""
+
+from mandelbrot import calculate_region, balance
+from mandelplot import plot
+import pypar, numpy
+
+
+# User definable parameters
+kmax = 2**15  # Maximal number of iterations (=number of colors)
+M = N = 700   # width = height = N
+B = 24        # Number of blocks (first dim)
+
+
+# Region in complex plane [-2:2]
+real_min = -2.0
+real_max =  1.0
+imag_min = -1.5
+imag_max =  1.5
+
+# MPI controls
+work_tag = 0
+result_tag = 1
+
+#Initialise
+t = pypar.time()
+P = pypar.size()
+p = pypar.rank()
+processor_name = pypar.get_processor_name()
+
+print 'Processor %d initialised on node %s' %(p,processor_name)
+
+assert P > 1, 'Must have at least one slave'
+assert B > P-1, 'Must have more work packets than slaves'
+
+
+A = numpy.zeros((M,N), dtype='i')
+if p == 0:
+    # Create work pool (B blocks)
+    # using balanced work partitioning
+    workpool = []
+    for i in range(B):
+        Mlo, Mhi = balance(M, B, i)    
+        workpool.append( (Mlo, Mhi) )
+
+
+    # Distribute initial work to slaves
+    w = 0 
+    for d in range(1, P):
+        pypar.send(workpool[w], destination=d, tag=work_tag)
+        w += 1
+
+    #Receive computed work and distribute more
+    terminated = 0
+    while(terminated < P-1):
+        R, status = pypar.receive(pypar.any_source, tag=result_tag,
+                                  return_status=True)
+        A += R            #Aggregate data        
+        d = status.source #Id of slave that just finished        
+
+        if w < len(workpool):
+            #Send new work to slave d
+            pypar.send(workpool[w], destination=d, tag=work_tag)
+            w += 1
+        else:
+            #Tell slave d to terminate
+            pypar.send(None, destination=d, tag=work_tag) 
+            terminated += 1
+        
+    print 'Computed region in %.2f seconds' %(pypar.time()-t)
+    plot(A, kmax)        
+
+else:
+    while(True):
+        #Receive work (or None)
+        W = pypar.receive(source=0, tag=work_tag)
+        
+        if W is None:
+            print 'Slave p%d finished: time = %.2f' %(p, pypar.time() - t)
+            break
+
+        #Compute allocated work
+        A = calculate_region(real_min, real_max, imag_min, imag_max, kmax,
+                             M, N, Mlo = W[0], Mhi = W[1])
+
+        #Return result
+        pypar.send(A, destination=0, tag=result_tag)
+
+pypar.finalize()
+
+
+
+
+
+
+
Index: /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandel_sequential.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandel_sequential.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandel_sequential.py	(revision 6991)
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+"""Sequential program computing the Mandelbrot set.
+
+Ole Nielsen, SUT 2003
+"""
+
+from mandelbrot import calculate_region
+from mandelplot import plot
+import time
+
+# User definable parameters
+kmax = 2**15  # Maximal number of iterations (=number of colors)
+M = N = 700   # width = height = N (200, 400, 600, 700 are good)
+#M = N = 400   # width = height = N (200, 400, 600, 700 are good)
+
+# Region in complex plane
+real_min = -2.0
+real_max =  1.0
+imag_min = -1.5
+imag_max =  1.5
+
+# Compute Mandelbrot set
+t0 = time.time()
+A = calculate_region(real_min, real_max, imag_min, imag_max, kmax, M, N)
+print 'Computed region in %.2f seconds' %(time.time()-t0)
+
+# Plot result
+plot(A, kmax)
+
+
+
+
Index: /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandelbrot.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandelbrot.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandelbrot.py	(revision 6991)
@@ -0,0 +1,97 @@
+"""Fundamental routines for computing the Mandelbrot set
+
+   Ole Nielsen, SUT 2003
+"""
+
+def balance(N, P, p):
+    """Compute p'th interval when N is distributed over P bins.
+    """
+
+    from math import floor
+
+    L = int(floor(float(N)/P))
+    K = N - P*L
+    if p < K:
+        Nlo = p*L + p
+        Nhi = Nlo + L + 1
+    else:
+        Nlo = p*L + K
+        Nhi = Nlo + L
+
+    return Nlo, Nhi
+
+
+def calculate_point(c, kmax):
+    """Python version for calculating on point of the set
+       This is slow and for reference purposes only.
+       Use version from mandel_ext instead.
+    """
+
+    z = complex(0,0)
+
+    count = 0
+    while count < kmax and abs(z) <= 2:
+        z = z*z + c
+        count += 1
+
+    return count    
+
+
+def calculate_region(real_min, real_max, imag_min, imag_max, kmax, M, N,
+                     Mlo = 0, Mhi = None, Nlo = 0, Nhi = None):
+    """Calculate the mandelbrot set in the given region with resolution M by N
+       If Mlo, Mhi or Nlo, Nhi are specified computed only given subinterval.
+    """
+
+    from numpy import zeros
+    from mandel_ext import calculate_point  #Fast C implementation
+
+    if Mhi is None: Mhi = M
+    if Nhi is None: Nhi = N    
+
+    real_step = (real_max-real_min)/M
+    imag_step = (imag_max-imag_min)/N
+
+    A = zeros((M, N), dtype='i')   # Create M x N matrix
+
+    for i in range(Mlo, Mhi):
+        for j in range(Nlo, Nhi):
+            c = complex(real_min + i*real_step, imag_min + j*imag_step)
+            A[i,j] = calculate_point(c, kmax)
+
+    return A
+
+
+
+def calculate_region_cyclic(real_min, real_max, imag_min, imag_max, kmax,
+                            M, N, p=0, P=1, row = 1):
+    """Calculate rows p+nP, n in N of the mandelbrot set in the given region
+    with resolution M by N
+
+    This is the most efficient way of partitioning the work.
+    """
+
+
+    from numpy import zeros
+    from mandel_ext import calculate_point  #Fast C implementation
+
+    real_step = (real_max-real_min)/M
+    imag_step = (imag_max-imag_min)/N
+
+    A = zeros((M, N), dtype='i')   # Create M x N matrix
+
+    if row:
+        for i in range(M):
+            if i%P == p:
+                for j in range(N):
+                    c = complex(real_min + i*real_step, imag_min + j*imag_step)
+                    A[i,j] = calculate_point(c, kmax)
+    else:
+        for j in range(N):        
+            if j%P == p:
+                for i in range(M):
+                    c = complex(real_min + i*real_step, imag_min + j*imag_step)
+                    A[i,j] = calculate_point(c, kmax)
+    return A
+
+    
Index: /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandelplot.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandelplot.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandelplot.py	(revision 6991)
@@ -0,0 +1,98 @@
+"""Plotting routine for use with the mandelbrot set
+
+   Ole Nielsen, SUT 2003
+"""
+
+
+def plot(A, kmax = None):
+    """Plot matrix A as an RGB image using the Python Imaging Library and Tkinter
+
+       A is converted to an RGB image using PIL and saved to disk
+       Then it is displayed using PhotoImage
+
+       A must be square, integer valued, two dimensional and non-negative
+
+       If kmax is omitted it will be set to the max value of A
+       
+       Ole Nielsen, SUT 2003
+    """
+    
+    from Tkinter import Frame, Canvas, TOP, NW, PhotoImage
+    from numpy import transpose
+    from Image import new             # PIL    
+    import time
+
+    t0 = time.time()
+
+    # User definable parameters
+
+    imtype = 'ppm'      # Image format (e.g 'ppm', 'bmp', 'tiff')
+    filename ='mandel'  # Base filename
+    
+    exponent = 0.998    # Exponent for morphing colors, good with kmax = 2**15
+    rgbmax = 2**24      # Normalisation constant for RGB
+    
+
+    # Input check
+    assert len(A.shape) == 2, 'Matrix must be 2 dimensional'
+    assert A.shape[0] == A.shape[1], 'Matrix must be square'
+    msg = 'A must contain integers, I got %c' %A.dtype.char
+    assert A.dtype.char in 'iIbBhHl', msg
+    assert min(A.flat)>=0, 'A must be non-negative'
+
+    if kmax is None:
+        kmax = max(A.flat)
+
+    # Convert values from A into RGB values (0 to 255) in each band
+    N = A.shape[0]
+    A = transpose(A).astype('d') # Cast as double         
+
+    im = new("RGB", A.shape)
+
+    
+    L = []        
+    try:
+        from mandelplot_ext import normalise_and_convert
+        normalise_and_convert(A, L, kmax, rgbmax, exponent)
+        
+    except:
+        print 'WARNING: Could not import C extension from mandelplot_ext'
+                
+    
+        for i in range(A.shape[0]):
+            for j in range(A.shape[1]):    
+                
+                c = A[i,j]/kmax
+
+                if c == 1: c = 0       #Map convergent point (kmax) to black (0)
+                c = c**exponent        #Morph slightly
+                
+                c = int(c * rgbmax)    #Normalise to 256 levels per channel
+                
+                red   = c / 256 / 256
+                green = (c / 256) % 256
+                blue  = c % 256
+    
+                L.append( (red, green, blue) )
+            
+            
+    
+    # Save image to file        
+    im.putdata(L)
+    im.save(filename + '.' + imtype, imtype)
+    print 'Computed plot in %.2f seconds: ' %(time.time()-t0)
+
+    # Display image on screen
+    #answer = raw_input('Show image [Y/N][Y]?')
+    #if answer.lower() in ['n', 'no']:
+    #   import sys
+    #   sys.exit()
+
+    # Try to display using a image viewer
+    import os
+    os.system('eog %s' %(filename + '.' + imtype))
+    #os.system('xv %s' %(filename + '.' + imtype))    
+
+
+
+ 
Index: /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandelplot_ext.c
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandelplot_ext.c	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/mandelbrot/mandelplot_ext.c	(revision 6991)
@@ -0,0 +1,117 @@
+// Python - C extension for fast computation of the Mandelbrot plot routine
+//
+// To compile (Python2.3):
+//  gcc -c mandelplot_ext.c -I/usr/include/python2.3 -o mandelplot_ext.o -Wall -O3 
+//  gcc -shared mandelplot_ext.o  -o mandelplot_ext.so	
+//
+// kmax = 256
+// c = complex(0.5, 0.5)
+// k = calculate_point(c, kmax)
+//
+// Ole Nielsen, ANU 2004
+	
+	
+#include "Python.h"
+#include "numpy/arrayobject.h"
+
+// Computational function
+int  _normalise_and_convert(double* A, 
+			    int M, 
+			    int N,
+			    PyObject* L, 
+			    int kmax, 
+			    int rgbmax, 
+			    double exponent) {
+			     
+  /*			     
+  for i in range(A.shape[0]):
+    for j in range(A.shape[1]):    
+      
+      c = A[i,j]/kmax
+      if c == 1: c = 0       #Map convergent point (kmax) to black (0)
+      c = c**exponent        #Morph slightly
+      c = int(c * rgbmax)    #Normalise to 256 levels per channel
+ 		
+      red   = c / 256 / 256
+      green = (c / 256) % 256
+      blue  = c % 256
+      
+      L.append( (red, green, blue) ) */
+	    
+
+  
+  PyObject *tuple;
+  int i, j, iN, red, green, blue, ci;
+  double c;
+  
+  for (i=0; i<M; i++) {
+    iN = i*N;
+    
+    for (j=0; j<N; j++) {  
+    
+      c = A[iN  + j]/kmax;     //Normalise to unit interval	    	    
+      c = pow(c, exponent);        //Morph slightly
+      ci = (int) (c*rgbmax);       //Normalise to rgbmax levels per channel
+      if (ci == rgbmax) ci = 0.0;  //Map convergent point (kmax) to black (0)
+      
+
+      //Convert to RGB
+      red   = ci / 256 / 256;
+      green = (ci / 256) % 256;
+      blue  = ci % 256;			     			     
+      
+      tuple = Py_BuildValue("iii", red, green, blue);
+      PyList_Append(L, tuple);
+    }
+  }
+	
+  return 0;
+}
+
+
+// Interface to Python
+PyObject *normalise_and_convert(PyObject *self, PyObject *args) {
+  
+  //Called 
+  //normalise_and_convert(A, L, kmax, rgbmax, exponent)    
+  
+  int kmax, rgbmax, M, N;
+  double exponent;
+  PyObject *L;
+  PyArrayObject *A;
+
+  // Convert Python arguments to C  
+  if (!PyArg_ParseTuple(args, "OOiid", &A, &L, &kmax, &rgbmax, &exponent))
+    return NULL;
+    
+  M = A -> dimensions[0];
+  N = A -> dimensions[1];  
+  
+
+  // Call underlying routine
+  _normalise_and_convert((double *) A -> data, M, N, L, 
+			 kmax, rgbmax, exponent); 
+  
+  // Return None
+  return Py_BuildValue("");
+}
+
+
+// Method table for python module
+static struct PyMethodDef MethodTable[] = {
+  {"normalise_and_convert", normalise_and_convert, METH_VARARGS},  
+  {NULL, NULL}
+};
+
+
+// Module initialisation   
+void initmandelplot_ext(void){
+  Py_InitModule("mandelplot_ext", MethodTable);
+  import_array();     //Necessary for handling of numpy structures
+}
+
+
+
+
+
+
Index: /branches/numpy_misc/tools/acceptance_tests/mandelbrot/test_calculate_point.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/mandelbrot/test_calculate_point.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/mandelbrot/test_calculate_point.py	(revision 6991)
@@ -0,0 +1,84 @@
+"""
+  Test of calculate_point within mandelbrot.py
+"""
+
+import unittest
+import Numeric
+from mandelbrot import calculate_point
+#from mandel_ext import calculate_point
+
+
+#-------------------------------------------------------------
+
+class TestCase(unittest.TestCase):
+
+    def setUp(self):
+	pass
+
+	
+    def test_basic(self):
+        """Test that c==0 always returns kmax
+	"""
+
+	c = complex(0, 0)
+	
+	for kmax in [0,1,2,3,4,10, 20, 33, 45, 100]:
+	    count = calculate_point(c, kmax)	
+            assert count == kmax    	
+
+	    
+    def test_points_clearly_outside_set(self):	
+    
+    	for kmax in [1,2,3,5,10,20,100]:
+	    for c in [complex(5, 4), complex(2,1), complex(-2,1),
+	    	      complex(2,-1), complex(-2,-1)]:
+	        count = calculate_point(c, kmax)
+	        assert count == 1
+	
+		
+    def test_arbitrary_points(self):
+    	for kmax in [10,20,100]:	    
+	    c = complex(1, 1.5)
+	    count = calculate_point(c, kmax)
+	    assert count == 2    
+	    
+	    c = complex(-1, 1.5)
+	    count = calculate_point(c, kmax)
+	    assert count == 2    	    
+	    
+	    c = complex(-1, -1.5)
+	    count = calculate_point(c, kmax)
+	    assert count == 2    	    	    
+	    
+	    c = complex(1, -1.5)
+	    count = calculate_point(c, kmax)
+	    assert count == 2    	    	    	    
+	    
+	    c = complex(1, 0)
+	    count = calculate_point(c, kmax)
+	    assert count == 3    	    	    	    	    
+	    
+	    c = complex(0.2, 1)
+	    count = calculate_point(c, kmax)
+	    assert count == 4    	    	    	    	    	    
+	    
+	    c = complex(0.2, 0.7)
+	    count = calculate_point(c, kmax)
+	    assert count == 6    	    	    	    	    	    	    
+	    
+	    c = complex(-0.2, 0.9)
+	    count = calculate_point(c, kmax)
+	    assert count == 9
+            
+
+    def test_another_known_point(self):
+        c = complex(0.5, 0.5)
+        count = calculate_point(c, 256)
+        assert count == 5        
+
+#-------------------------------------------------------------
+if __name__ == "__main__":
+
+    mysuite = unittest.makeSuite(TestCase,'test')
+    runner = unittest.TextTestRunner()
+    runner.run(mysuite)
Index: /branches/numpy_misc/tools/acceptance_tests/mandelbrot/test_calculate_region.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/mandelbrot/test_calculate_region.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/mandelbrot/test_calculate_region.py	(revision 6991)
@@ -0,0 +1,83 @@
+"""
+  Test of calculate_region within mandelbrot.py
+"""
+
+import unittest
+import numpy
+from mandelbrot import calculate_region
+
+
+#-------------------------------------------------------------
+
+class TestCase(unittest.TestCase):
+
+    def setUp(self):
+	pass
+
+	
+    def test1(self):
+	kmax = 16
+	M = N = 5
+	
+	real_min = -2.0
+	real_max =  1.0
+	imag_min = -1.5
+	imag_max =  1.5
+        A = calculate_region(real_min, real_max, 
+		imag_min, imag_max, kmax, M, N)
+
+	assert numpy.allclose(A,  		
+	[[ 1,  1,  1,  1,  1],
+ 	[ 1,  3,  5,  5,  3],
+ 	[ 2,  4,  9,  9,  4],
+ 	[ 2,  9, 16, 16,  9],
+ 	[ 2,  3, 15, 15,  3]])
+
+
+    def test2(self):
+	kmax = 32
+	M = N = 5
+	
+	real_min = -2.0
+	real_max =  1.0
+	imag_min = -1.5
+	imag_max =  1.5
+        A = calculate_region(real_min, real_max, 
+		imag_min, imag_max, kmax, M, N)
+
+	assert numpy.allclose(A,  		
+	[[ 1,  1,  1,  1,  1],
+ 	[ 1,  3,  5,  5,  3],
+ 	[ 2,  4,  9,  9,  4],
+ 	[ 2,  9, 32, 32,  9],
+ 	[ 2,  3, 15, 15,  3]])
+	
+
+    def test3(self):
+	kmax = 32
+	M = N = 100
+	
+	real_min = -2.0
+	real_max =  1.0
+	imag_min = -1.5
+	imag_max =  1.5
+        A = calculate_region(real_min, real_max, 
+		imag_min, imag_max, kmax, M, N)
+
+	assert numpy.allclose(A[:, 50], 
+	[32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
+	 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+         32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
+         32, 32, 32, 32, 32, 32, 32, 32,
+         32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 
+         32, 32, 32, 32, 32, 32, 32, 32,
+         32, 32, 16, 11,  9,  7,  7,  6,  5,  5,  5,  4,  4,  4,  4,  4,  
+         3, 3,  3,  3,  3,  3,  3,  3, 3,  3])
+
+	
+#-------------------------------------------------------------
+if __name__ == "__main__":
+
+    mysuite = unittest.makeSuite(TestCase,'test')
+    runner = unittest.TextTestRunner()
+    runner.run(mysuite)
Index: /branches/numpy_misc/tools/acceptance_tests/quadrature_parallel_interleaved.c
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/quadrature_parallel_interleaved.c	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/quadrature_parallel_interleaved.c	(revision 6991)
@@ -0,0 +1,134 @@
+// This is an alternative parallel version of quadrature_sequential.c 
+//
+// It differs from quadratur_parallel.c by the way work is distributed.
+// This one uses a 'round robin' strategy.
+// 
+// To compile: mpicc quadrature_parallel.c -lm
+//
+// This code also exhibits linear speedup. See listed output at the 
+// bottom of this file.
+//
+// Ole Nielsen, SUT 2003
+
+	
+#include <math.h>
+#include <stdio.h>
+#include <time.h>
+#include <mpi.h>
+
+
+//Define the circle arc to be integrated.
+long double fct(long double x) {
+  return sqrt(1.0-x*x);
+}
+
+
+int main(argc,argv)
+     int argc;
+     char *argv[];
+{
+  int N, i, lo, hi;
+  long double result=0.0, my_result=0.0;
+  long double reference = 3.1415926535897932; //Reference value, 17 digits
+
+  
+  double t0;
+  int p;  // Myid
+  int P;  // Number of processors 
+
+  int namelen, tag=0, j, k;
+  char processor_name[MPI_MAX_PROCESSOR_NAME];  
+  int *C;
+
+  MPI_Status status;
+    
+  MPI_Init(&argc, &argv);
+  MPI_Comm_rank(MPI_COMM_WORLD, &p);
+  MPI_Comm_size(MPI_COMM_WORLD, &P);
+  MPI_Get_processor_name(processor_name, &namelen);  
+   
+  printf("This is process %d of %d running on %s\n", 
+	 p, P, processor_name);
+
+  N = 100000000;   // Resolution  
+  //N = 29;   // Resolution  
+  
+  if (p == 0) {
+    printf("Resolution = %d\n", N);
+  }
+
+  // Begin computation
+  t0 = MPI_Wtime();
+
+  
+  for (k=0; k<15; k++) {
+    //Each process p handles own stride of points
+    my_result = 0.0;
+    for (i=p; i<N; i+=P) {
+      my_result += fct( (i+0.5)/N );
+    } 
+
+    my_result = 4*my_result/N;
+  }
+	 
+  printf("P%d: Partial result = %.16Lf\n", p, my_result);   
+
+  
+  // Communication phase
+  if (p == 0) {
+  
+    //Receive results from others 
+    result = my_result;  
+    for (j=1; j<P; j++) {          
+      printf("P%d: receiving from P%d\n", p, j);
+      MPI_Recv(&my_result, 1, MPI_LONG_DOUBLE, j, tag,
+	       MPI_COMM_WORLD, &status);
+      result += my_result;
+    }
+     
+    printf("Error  = %.2e\n", fabs(result-reference)); 
+    printf("Time   = %.2f sec\n", MPI_Wtime() - t0);
+    
+  } else {
+    // send my_result to intended proc 0
+    MPI_Send(&my_result, 1, MPI_LONG_DOUBLE, 0, tag,
+	     MPI_COMM_WORLD);     
+  }  
+
+  MPI_Finalize();
+  return 0;
+}
+
+//Observed output, Resolution = 100000000
+//P = 1
+//Error = 3.44e-13
+//Time = 13.52 sec
+//
+//P = 2
+//Error = 3.44e-13
+//Time = 6.76 sec
+//
+//P = 4
+//Error = 3.44e-13
+//Time = 3.39 sec
+//
+//P = 8
+//Error = 3.44e-13
+//Time = 1.69 sec
+//
+//
+//SPEEDUP & EFFICIENCY
+//t = array([13.52, 6.76, 3.39, 1.69])
+//
+//t[0]/t
+//
+//array([ 1.        ,  2.        ,  3.98820059,  8.        ])
+//
+//p = [1, 2, 4, 8]
+//
+//t[0]/t/p
+//array([ 1.        ,  1.        ,  0.99705015,  1.        ])
+
+
+
+
Index: /branches/numpy_misc/tools/acceptance_tests/test_all.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/test_all.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/test_all.py	(revision 6991)
@@ -0,0 +1,39 @@
+#!/bin/env python
+
+'''Run all acceptance tests in order.'''
+
+import os
+import sys
+import time
+import test_utils as util
+
+
+# the test files, in desired order
+Tests = ['test_dump_python_environment.py',
+         'test_python_packages.py',
+         'test_filesystem_accessibility.py',
+         'test_ssh_to_compute_nodes.py',
+         'test_quadrature_parallel_interleaved.py',
+         'test_latency_bandwidth.py',
+         'test_test_pypar.py',
+         'test_test_all.py']
+
+
+if __name__ == '__main__':
+    home_directory = os.getcwd()
+    logfile = os.path.join(home_directory, 'test.log')
+    if len(sys.argv) > 1:
+        logfile = sys.argv[1]
+
+    try:
+        os.remove(logfile)
+    except:
+        pass
+
+    # run the tests
+    for test_module in Tests:
+        (import_name, _) = test_module.split('.', 1)
+        test_code = ("import %s\n%s.test('%s')"
+                     % (import_name, import_name, logfile))
+
+        exec test_code
Index: /branches/numpy_misc/tools/acceptance_tests/test_dump_python_environment.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/test_dump_python_environment.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/test_dump_python_environment.py	(revision 6991)
@@ -0,0 +1,64 @@
+#!/bin/env python
+
+'''Testlet to dump the acceptance environment.'''
+
+import os
+import sys
+import time
+import test_utils as util
+
+
+def test(logfile):
+    start_time = time.time()
+
+    (cluster, domain) = util.get_hostname()
+
+    util.header(logfile, 'Dump of the acceptance test environment on %s.' % cluster)
+
+    # show the hostname
+    util.log_print_nl(logfile, 'Hostname: %s.%s' % (cluster, domain))
+    util.log_print_nl(logfile)
+
+    # show python version being used
+    util.log_print_nl(logfile, 'Python version: %s' % sys.version.replace('\n', ' '))
+    util.log_print_nl(logfile)
+
+    # show PYTHONPATH value
+    pythonpath = os.getenv('PYTHONPATH')
+    util.log_print_nl(logfile, 'PYTHONPATH: %s' % pythonpath)
+    util.log_print_nl(logfile)
+
+    # show contents of ~/.machines_<machine>
+    home = os.getenv('HOME')
+    machines_file = os.path.join(home, '.machines_%s' % cluster)
+    try:
+        fd = open(machines_file, 'r')
+        data = fd.read()
+        fd.close()
+    except:
+        data = '***** NO FILE FOUND *****\n'
+
+    util.log_print_nl(logfile, '%s:' % machines_file)
+    util.log_print_nl(logfile, '-' * 30)
+    util.log_print(logfile, data)
+    util.log_print_nl(logfile, '-' * 30)
+    util.log_print_nl(logfile)
+
+    util.footer(logfile, start_time)
+    return True
+
+
+if __name__ == '__main__':
+    logfile = 'test.log'
+    if len(sys.argv) > 1:
+        logfile = sys.argv[1]
+
+    try:
+        os.remove(logfile)
+    except:
+        pass
+
+    if not test(logfile):
+        sys.exit(10)
+
+    sys.exit(0)
Index: /branches/numpy_misc/tools/acceptance_tests/test_filesystem_accessibility.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/test_filesystem_accessibility.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/test_filesystem_accessibility.py	(revision 6991)
@@ -0,0 +1,57 @@
+#!/bin/env python
+
+'''Testlet to check that various filesystems are accessible'''
+
+import os
+import time
+import test_utils as util
+
+
+# paths we are testig
+Test_Paths = ('/nas/gemd/georisk_models',
+              '/nas/gemd'	# just to get 2 paths
+             )
+
+def test(logfile):
+    result = True
+    start_time = time.time()
+
+    (cluster, domain) = util.get_hostname()
+
+    util.header(logfile, 'Test of filesystem accessibility on %s.' % cluster)
+
+    # get max width of the filesystem paths
+    width = 0
+    for path in Test_Paths:
+        width = max(len(path), width)
+
+    # test each path
+    for path in Test_Paths:
+        util.log_print(logfile, "Testing: %s" % path.ljust(width+2))
+        if os.path.isdir(path):
+            util.log_print_nl(logfile, 'OK')
+        else:
+            util.log_print_nl(logfile, 'NOT ACCESSIBLE')
+            result = False
+
+    util.footer(logfile, start_time)
+    return result
+
+
+if __name__ == '__main__':
+    import sys
+
+    logfile = 'test.log'
+    if len(sys.argv) > 1:
+        logfile = sys.argv[1]
+
+    try:
+        os.remove(logfile)
+    except:
+        pass
+
+    if not test(logfile):
+        sys.exit(10)
+
+    sys.exit(0)
+
Index: /branches/numpy_misc/tools/acceptance_tests/test_latency_bandwidth.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/test_latency_bandwidth.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/test_latency_bandwidth.py	(revision 6991)
@@ -0,0 +1,102 @@
+#!/bin/env python
+
+'''Testlet to run the LatencyBandwidth test.'''
+
+import os
+import time
+import test_utils as util
+
+Processor_Numbers = [2, 4, 8, 16]
+
+def test(logfile):
+    result = True
+    start_time = time.time()
+
+    (cluster, domain) = util.get_hostname()
+
+    util.header(logfile, 'Running latency/bandwidth test on %s.' % cluster)
+
+    # compile C code
+    obj_file = 'ctiming_%s' % cluster
+    cmd = ('mpicc ctiming.c -lm -o %s' % obj_file)
+    util.log_print(logfile, 'Compiling ctiming.c ...')
+    (_, fd) = os.popen4(cmd)
+    output = fd.read()
+    status = fd.close()
+    if status:
+        util.log_print_nl(logfile, 'ERRORS COMPILING')
+        util.log_print(logfile, output)
+        util.footer(logfile, start_time)
+        return False
+
+    util.log_print_nl(logfile, 'OK\n')
+
+    # run the tests
+    results = []
+    for num_procs in Processor_Numbers:
+        machines_file = '~/.machines_%s' % cluster
+
+        cmd = ('mpirun -np %2d -hostfile %s %s'
+               % (num_procs, machines_file, obj_file))
+        util.log_print(logfile, cmd + ' ...')
+        (_, fd) = os.popen4(cmd)
+        output = fd.readlines()
+        status = fd.close()
+        if status:
+            util.log_print_nl(logfile, 'ERRORS')
+            util.log_print(logfile, '\n'.join(output))
+            util.footer(logfile, start_time)
+            return False
+
+        estimated_bandwidth = None
+        estimated_latency = None
+        for line in output:
+            if line.startswith('Estimated bandwith'):
+                (_, estimated_bandwidth) = line.split(': ', 1)
+                estimated_bandwidth = estimated_bandwidth.strip()
+                (estimated_bandwidth, _) = estimated_bandwidth.split(' ', 1)
+            if line.startswith('Estimated latency'):
+                (_, estimated_latency) = line.split(': ', 1)
+                estimated_latency = estimated_latency.strip()
+                (estimated_latency, _) = estimated_latency.split(' ', 1)
+
+        if estimated_bandwidth is None or estimated_latency is None:
+            util.log_print_nl(logfile, 'ERRORS')
+            util.log_print(logfile, '\n'.join(output))
+            util.footer(logfile, start_time)
+            return False
+            
+        results.append((num_procs, float(estimated_bandwidth), int(estimated_latency)))
+        util.log_print_nl(logfile, 'done')
+
+    # interpret the results
+    util.log_print(logfile, '\nResults of latency/bandwidth test on %s\n' % cluster)
+    util.log_print(logfile, '%s\t%s\t%s\n' % ('#procs', 'b/width', 'latency'))
+    
+    for (num_processors, estimated_bandwidth, estimated_latency) in results:
+        util.log_print(logfile, '%d\t%.1f\t%d\n'
+                       % (num_processors, estimated_bandwidth, estimated_latency))
+
+    util.footer(logfile, start_time)
+
+    os.remove(obj_file)
+
+    return result
+
+
+if __name__ == '__main__':
+    import sys
+
+    logfile = 'test.log'
+    if len(sys.argv) > 1:
+        logfile = sys.argv[1]
+
+    try:
+        os.remove(logfile)
+    except:
+        pass
+
+    if not test(logfile):
+        sys.exit(10)
+
+    sys.exit(0)
Index: /branches/numpy_misc/tools/acceptance_tests/test_pypar.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/test_pypar.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/test_pypar.py	(revision 6991)
@@ -0,0 +1,1193 @@
+#!/usr/bin/env python
+# Test of MPI module 'pypar' for Python
+# 
+# Run as 
+#   python testpypar.py
+# or 
+#   mpirun -np 2 testpypar.py
+# (perhaps try number of processors more than 2)
+#
+# To verify bandwidth of your architecture please run pytiming (and ctiming) 
+#
+# OMN, GPC FEB 2002
+
+
+try:
+  import numpy
+except:
+  raise 'Module numpy must be present to run pypar'
+
+
+#print "Importing pypar"
+import pypar
+methods = dir(pypar)
+assert 'abort' in methods
+assert 'finalize' in methods
+assert 'get_processor_name' in methods
+assert 'time' in methods
+assert 'rank' in methods
+assert 'receive' in methods
+assert 'send' in methods
+assert 'broadcast' in methods
+assert 'size' in methods
+
+#print "Module pypar imported OK"
+#pypar.Barrier()
+
+
+
+# Shorthands as tests were written prior to version 2.0
+# Eventually, modify all tests to use buffers and remove
+# the 'raw' form.
+def raw_send(x, destination, tag=pypar.default_tag, vanilla=0):
+    pypar.send(x, destination, use_buffer=True, tag=tag, vanilla=vanilla) 
+
+def raw_receive(x, source, tag=pypar.default_tag, vanilla=0, return_status=0):
+    x = pypar.receive(source, tag=tag, vanilla=vanilla,
+                      return_status=return_status, buffer=x)
+    return x
+
+def raw_scatter(x, buffer, source, vanilla=0):
+    pypar.scatter(x, source, buffer=buffer, vanilla=vanilla)
+
+
+def raw_gather(x, buffer, source, vanilla=0):
+    pypar.gather(x, source, buffer=buffer, vanilla=0)  
+
+def raw_reduce(x, buffer, op, source, vanilla=0):
+    pypar.reduce(x, op, source, buffer=buffer, vanilla=0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+myid =    pypar.rank()
+numproc = pypar.size()
+node =    pypar.get_processor_name()
+
+print 'I am processor %d of %d on node %s' %(myid, numproc, node)
+pypar.barrier()
+
+
+if numproc > 1:
+  # Test simple raw communication (arrays, strings and general)
+  #
+  N = 17 #Number of elements
+  
+  if myid == 0:
+    # Integer arrays
+    #
+    A = numpy.array(range(N)).astype('i')
+    B = numpy.zeros(N).astype('i')
+    raw_send(A,1)
+    raw_receive(B,numproc-1)
+
+    assert numpy.allclose(A, B)
+    print 'Raw communication of numeric integer arrays OK'
+
+
+    # Long integer arrays
+    #
+    A = numpy.array(range(N)).astype('l')
+    B = numpy.zeros(N).astype('l')    
+    raw_send(A,1)
+    raw_receive(B,numproc-1)
+    
+    assert numpy.allclose(A, B)
+    print "Raw communication of numeric long integer arrays OK"
+
+    # Real arrays
+    #
+    A = numpy.array(range(N)).astype('f')
+    B = numpy.zeros(N).astype('f')    
+    raw_send(A,1)
+    raw_receive(B,numproc-1)
+    
+    assert numpy.allclose(A, B)    
+    print "Raw communication of numeric real arrays OK"
+
+    # Complex arrays
+    #
+    A = numpy.array(range(N)).astype('D')
+    A += 3j
+    B = numpy.zeros(N).astype('D')
+    raw_send(A, 1)
+    B = raw_receive(B, numproc-1)
+
+    assert numpy.allclose(A, B)    
+    print "Raw communication of numeric complex arrays OK"
+
+    # Strings (< 256 characters)
+    #
+    A = "and now to something completely different !"
+    B = " "*len(A)
+    raw_send(A,1)
+    B, status = raw_receive(B,numproc-1,return_status=True)
+
+    assert A == B
+    print "Raw communication of strings OK"
+    
+    # A more general structure
+    #
+    A = ['ABC', (1,2,3.14), {8: 'Monty'}, numpy.array([13.45, 1.2])]
+    B = ['   ', (0,0,0.0) , {0: '     '}, numpy.zeros(2).astype('f')]    
+    raw_send(A,1)
+    B, status = raw_receive(B,numproc-1, return_status=True)
+
+    OK = True
+    for i, a in enumerate(A):
+      b = B[i]
+
+      if type(a).__name__ == 'ndarray':
+        if not numpy.allclose(a, b):
+          OK = False
+          break
+      elif a != b:
+        OK = False
+        break
+
+    if OK is True:
+      print 'Raw communication of general structures OK' 
+    else:
+      raise Exception    
+
+    
+  else:  
+    # Integers
+    #
+    X = numpy.zeros(N).astype('i')    
+    raw_receive(X, myid-1)  
+    raw_send(X, (myid+1)%numproc)
+  
+    # Long integers
+    #
+    X = numpy.zeros(N).astype('l')
+    raw_receive(X, myid-1)  
+    raw_send(X, (myid+1)%numproc)    
+
+    # Floats
+    #
+    X = numpy.zeros(N).astype('f')
+    raw_receive(X, myid-1)  
+    raw_send(X, (myid+1)%numproc)    
+
+    # Complex
+    #
+    X = numpy.zeros(N).astype('D')
+    X = raw_receive(X, myid-1)  
+    raw_send(X, (myid+1)%numproc)    
+
+    # Strings
+    #
+    X = " "*256
+    raw_receive(X, myid-1)  
+    raw_send(X.strip(), (myid+1)%numproc)    
+
+    # General
+    #
+    X = ['   ', (0,0,0.0), {0: '     '}, numpy.zeros(2).astype('f')]
+    X = raw_receive(X, myid-1)  
+    raw_send(X, (myid+1)%numproc)    
+    
+
+
+
+
+  #Test (raw communication of) multi dimensional arrays
+
+  M = 13  #Number of elements in dim 1
+  N = 17  #Number of elements in higher dims
+  
+  if myid == 0:
+    # 2D real arrays
+    #
+    A = numpy.array(range(M*N)).astype('f')
+    B = numpy.zeros(M*N).astype('f')
+
+    A = numpy.reshape(A, (M,N))
+    B = numpy.reshape(B, (M,N))    
+    
+    raw_send(A,1)
+    raw_receive(B,numproc-1)
+    
+    assert numpy.allclose(A, B)    
+    print "Raw communication of 2D real arrays OK"
+
+    # 2D complex arrays
+    #
+    A = numpy.array(range(M*N)).astype('D')
+    B = numpy.zeros(M*N).astype('D')
+
+    A = numpy.reshape(A, (M,N))
+    B = numpy.reshape(B, (M,N))    
+
+    raw_send(A,1)
+    raw_receive(B,numproc-1)
+    
+    assert numpy.allclose(A, B)    
+    print "Raw communication of 2D complex arrays OK"
+
+    # 3D real arrays
+    #
+    A = numpy.array(range(M*N*N)).astype('f')
+    B = numpy.zeros(M*N*N).astype('f')
+
+    A = numpy.reshape(A, (M,N,N))
+    B = numpy.reshape(B, (M,N,N))    
+    
+    raw_send(A,1)
+    raw_receive(B,numproc-1)
+    
+    assert numpy.allclose(A, B)    
+    print "Raw communication of 3D real real arrays OK"
+
+    # 4D real arrays
+    #
+    A = numpy.array(range(M*N*N*M)).astype('f')
+    B = numpy.zeros(M*N*N*M).astype('f')
+
+    A = numpy.reshape(A, (M,N,N,M))
+    B = numpy.reshape(B, (M,N,N,M))    
+    
+    raw_send(A,1)
+    raw_receive(B,numproc-1)
+    
+    assert numpy.allclose(A, B)    
+    print "Raw communication of 4D real real arrays OK"
+
+    # 5D real arrays
+    #
+    A = numpy.array(range(M*N*2*N*M)).astype('f')
+    B = numpy.zeros(M*N*2*N*M).astype('f')
+
+    A = numpy.reshape(A, (M,N,2,N,M))
+    B = numpy.reshape(B, (M,N,2,N,M))    
+    
+    raw_send(A,1)
+    raw_receive(B,numproc-1)
+    
+    assert numpy.allclose(A, B)    
+    print "Raw communication of 5D real real arrays OK"
+
+    # 5D double arrays
+    #
+    A = numpy.array(range(M*N*2*N*M)).astype('d')
+    B = numpy.zeros(M*N*2*N*M).astype('d')
+
+    A = numpy.reshape(A, (M,N,2,N,M))
+    B = numpy.reshape(B, (M,N,2,N,M))    
+    
+    raw_send(A,1)
+    raw_receive(B,numproc-1)
+    
+    assert numpy.allclose(A, B)    
+    print "Raw communication of 5D double arrays OK"
+
+    # 5D complex arrays
+    #
+    A = numpy.array(range(M*N*2*N*M)).astype('D')
+    B = numpy.zeros(M*N*2*N*M).astype('D')
+
+    A = numpy.reshape(A, (M,N,2,N,M))
+    B = numpy.reshape(B, (M,N,2,N,M))    
+    
+    raw_send(A,1)
+    raw_receive(B,numproc-1)
+    
+    assert numpy.allclose(A, B)    
+    print "Raw communication of 5D complex arrays OK"
+  else:  
+    # 2D real arrays
+    #
+    X = numpy.zeros(M*N).astype('f')
+    X = numpy.reshape(X, (M,N))
+    
+    raw_receive(X, myid-1)  
+    raw_send(X, (myid+1)%numproc)
+  
+    # 2D complex arrays
+    #
+    X = numpy.zeros(M*N).astype('D')
+    X = numpy.reshape(X, (M,N))
+
+    X = raw_receive(X, myid-1)
+    raw_send(X, (myid+1)%numproc)
+  
+    # 3D real arrays
+    #
+    X = numpy.zeros(M*N*N).astype('f')
+    X = numpy.reshape(X, (M,N,N))
+    
+    raw_receive(X, myid-1)  
+    raw_send(X, (myid+1)%numproc)
+
+    # 4D real arrays
+    #
+    X = numpy.zeros(M*N*N*M).astype('f')
+    X = numpy.reshape(X, (M,N,N,M))
+    
+    raw_receive(X, myid-1)  
+    raw_send(X, (myid+1)%numproc)
+
+    # 5D real arrays
+    #
+    X = numpy.zeros(M*N*2*N*M).astype('f')
+    X = numpy.reshape(X, (M,N,2,N,M))
+    
+    raw_receive(X, myid-1)  
+    raw_send(X, (myid+1)%numproc)
+
+    # 5D double arrays
+    #
+    X = numpy.zeros(M*N*2*N*M).astype('d')
+    X = numpy.reshape(X, (M,N,2,N,M))
+    
+    raw_receive(X, myid-1)  
+    raw_send(X, (myid+1)%numproc)
+
+    # 5D complex arrays
+    #
+    X = numpy.zeros(M*N*2*N*M).astype('D')
+    X = numpy.reshape(X, (M,N,2,N,M))
+    
+    raw_receive(X, myid-1)  
+    raw_send(X, (myid+1)%numproc)
+
+  # Test easy communication  - without buffers (arrays, strings and general)
+  #
+  N = 17 #Number of elements
+  
+  if myid == 0:
+    # Integer arrays
+    #
+    A = numpy.array(range(N))
+
+    pypar.send(A,1)
+    B = pypar.receive(numproc-1)
+    
+
+    assert numpy.allclose(A, B)
+    print "Simplified communication of numeric integer arrays OK"
+
+    # Long integer arrays
+    #
+    A = numpy.array(range(N)).astype('l')
+    pypar.send(A,1)
+    B=pypar.receive(numproc-1)
+    
+    assert numpy.allclose(A, B)    
+    print "Simplified communication of long integer real arrays OK"
+
+    # Real arrays
+    #
+    A = numpy.array(range(N)).astype('f')
+    pypar.send(A,1)
+    B=pypar.receive(numproc-1)
+    
+    assert numpy.allclose(A, B)    
+    print "Simplified communication of numeric real arrays OK"
+
+    # Complex arrays
+    #
+    A = numpy.array(range(N)).astype('D')
+    A += 3j
+    pypar.send(A,1)
+    B=pypar.receive(numproc-1)
+
+    assert numpy.allclose(A, B)    
+    print "Simplified communication of numeric complex arrays OK"
+
+
+    # Strings
+    #
+    A = "and now to something completely different !"
+    pypar.send(A,1)
+    B=pypar.receive(numproc-1)
+    
+    assert A == B
+    print "Simplified communication of strings OK"
+    
+    # A more general structure
+    #
+    A = ['ABC', (1,2,3.14), {8: 'Monty'}, numpy.array([13.45, 1.2])]
+    pypar.send(A,1)
+    B = pypar.receive(numproc-1)
+
+    OK = True
+    for i, a in enumerate(A):
+      b = B[i]
+
+      if type(a).__name__ == 'ndarray':
+        if not numpy.allclose(a, b):
+          OK = False
+          break
+      elif a != b:
+        OK = False
+        break
+
+    if OK is True:
+      print 'Simplified communication of general structures OK' 
+    else:
+      raise Exception    
+    
+  else:  
+    # Integers
+    #
+    X=pypar.receive(myid-1)  
+    pypar.send(X, (myid+1)%numproc)
+  
+    # Long integers
+    #
+    X=pypar.receive(myid-1)  
+    pypar.send(X, (myid+1)%numproc)    
+
+    # Floats
+    #
+    X=pypar.receive(myid-1)  
+    pypar.send(X, (myid+1)%numproc)    
+
+    # Complex
+    #
+    X=pypar.receive(myid-1)  
+    pypar.send(X, (myid+1)%numproc)    
+
+    # Strings
+    #
+    X=pypar.receive(myid-1)  
+    pypar.send(X, (myid+1)%numproc)    
+
+    # General
+    #
+    X = pypar.receive(myid-1)  
+    pypar.send(X, (myid+1)%numproc)    
+
+
+
+
+    
+  #Test (easy communication of) multi dimensional arrays
+
+  M = 13  #Number of elements in dim 1
+  N = 17  #Number of elements in higher dims
+  
+  if myid == 0:
+    # 2D real arrays
+    #
+    A = numpy.array(range(M*N)).astype('f')
+
+    A = numpy.reshape(A, (M,N))
+    
+    pypar.send(A,1)
+    B = pypar.receive(numproc-1)
+    
+    assert numpy.allclose(A, B)    
+    print "Simplified communication of 2D real arrays OK"
+
+    # 3D real arrays
+    #
+    A = numpy.array(range(M*N*N)).astype('f')
+    A = numpy.reshape(A, (M,N,N))
+    
+    pypar.send(A,1)
+    B=pypar.receive(numproc-1)
+    
+    assert numpy.allclose(A, B)    
+    print "Simplified communication of 3D real arrays OK"
+
+    # 4D real arrays
+    #
+    A = numpy.array(range(M*N*N*M)).astype('f')
+    A = numpy.reshape(A, (M,N,N,M))
+    
+    pypar.send(A,1)
+    B=pypar.receive(numproc-1)
+    
+    assert numpy.allclose(A, B)    
+    print "Simplified communication of 4D real arrays OK"
+
+    # 5D real arrays
+    #
+    A = numpy.array(range(M*N*2*N*M)).astype('f')
+    A = numpy.reshape(A, (M,N,2,N,M))
+    
+    pypar.send(A,1)
+    B=pypar.receive(numproc-1)
+    
+    assert numpy.allclose(A, B)    
+    print "Simplified communication of 5D real arrays OK"
+
+    # 5D double arrays
+    #
+    A = numpy.array(range(M*N*2*N*M)).astype('d')
+    A = numpy.reshape(A, (M,N,2,N,M))
+    
+    pypar.send(A,1)
+    B=pypar.receive(numproc-1)
+    
+    assert numpy.allclose(A, B)    
+    print "Simplified communication of 5D double arrays OK"
+
+    # 5D complex arrays
+    #
+    A = numpy.array(range(M*N*2*N*M)).astype('D')
+    A = numpy.reshape(A, (M,N,2,N,M))
+    
+    pypar.send(A,1)
+    B=pypar.receive(numproc-1)
+    
+    assert numpy.allclose(A, B)    
+    print "Simplified communication of 5D complex real arrays OK"
+
+  else:  
+    # 2D real arrays
+    #
+    
+    X = pypar.receive(myid-1)  
+    pypar.send(X, (myid+1)%numproc)
+  
+    # 3D real arrays
+    #
+    X=pypar.receive(myid-1)  
+    pypar.send(X, (myid+1)%numproc)
+
+    # 4D real arrays
+    #
+    X = pypar.receive(myid-1)  
+    pypar.send(X, (myid+1)%numproc)
+
+    # 5D real arrays
+    #
+    X=pypar.receive(myid-1)  
+    pypar.send(X, (myid+1)%numproc)
+
+    # 5D double arrays
+    #
+    X=pypar.receive(myid-1)  
+    pypar.send(X, (myid+1)%numproc)
+
+    # 5D complex arrays
+    #
+    X=pypar.receive(myid-1)  
+    pypar.send(X, (myid+1)%numproc)
+
+  # Test broadcast  - with buffers (arrays, strings and general)
+  #
+      
+  testString = ('test' + str(myid)).ljust(10)  #Buffers must have the same length on all procs!
+  pypar.broadcast(testString, 0)
+  assert testString.strip() == 'test0'
+  
+  testString = ('test' + str(myid)).ljust(10)  #Buffers must have the same length on all procs!
+  pypar.broadcast(testString, numproc-1)
+  assert testString.strip() == 'test' + str(numproc-1)
+  
+  if myid == 0:
+    print "Broadcast communication of strings OK"
+
+  ####################################################  
+  N = 17 #Number of elements
+  testArray = myid * numpy.array(range(N))
+  pypar.broadcast(testArray, 1)
+  assert numpy.allclose(testArray, 1 * testArray)
+  
+  if myid == 0:    
+    print "Broadcast communication of numeric integer array OK"
+
+
+  testArray = myid * numpy.array(range(N)).astype('f')
+  pypar.broadcast(testArray, 1)
+  assert numpy.allclose(testArray, 1 * testArray)
+  if myid == 0:
+    print "Broadcast communication of numeric real array OK"
+
+
+  M = 13
+  testArray = myid * numpy.array(range(M*N)).astype('f')
+  testArray = numpy.reshape(testArray, (M,N))  
+  pypar.broadcast(testArray, 1)
+  assert numpy.allclose(testArray, 1 * testArray)
+  if myid == 0:
+    print "Broadcast communication of 2D numeric real array OK"
+
+  testArray = myid * numpy.array(range(M*2*N)).astype('f')
+  testArray = numpy.reshape(testArray, (M,2,N))  
+  pypar.broadcast(testArray, 1)
+  assert numpy.allclose(testArray, 1 * testArray)
+  if myid == 0:
+    print "Broadcast communication of 3D numeric real array OK"
+
+  testArray = myid * numpy.array(range(M*2*N)).astype('D')
+  testArray = numpy.reshape(testArray, (M,2,N))  
+  pypar.broadcast(testArray, 1)
+  assert numpy.allclose(testArray, 1 * testArray)
+  if myid == 0:
+    print "Broadcast communication of 3D numeric complex array OK"
+
+    
+  A_x = ['ABC', myid, (1,2,3), {8: 'Monty'}, numpy.array([13.45, 1.2])]
+  A_1 = ['ABC',    1, (1,2,3), {8: 'Monty'}, numpy.array([13.45, 1.2])]
+  B = pypar.broadcast(A_x, 1)
+
+  OK = True
+  for i, a in enumerate(A_1):
+    b = B[i]
+
+    if type(a).__name__ == 'ndarray':
+      if not numpy.allclose(a, b):
+        OK = False
+        break
+    elif a != b:
+      OK = False
+      break
+
+  if OK is False:
+    raise Exception    
+    
+  if myid == 0:
+    print "Broadcast communication of general structures OK"
+  
+
+
+
+  # Test scatter  - with/without buffers (arrays, strings)
+  #
+  N = 16 #Number of elements
+
+  NP = N/numproc
+  
+  testString = 'ABCDEFGHIJKLMNOP'  #Length = 16
+  X = ' '*NP
+
+  #print 'P%d: s=%s, r=%s' %(myid, testString, X)
+  #raw_scatter(testString, X, 2)
+  #Y = pypar.scatter(testString, 2)
+
+
+  #assert X==Y, 'X=%s, Y=%s' %(X,Y)
+  #assert Y == testString[myid*NP:(myid+1)*NP]
+  #assert X == testString[myid*NP:(myid+1)*NP]
+
+  #if myid == 0:    
+  #  print "Scatter communication of strings OK"
+    
+
+  #Scatter Arrays
+  testArray = numpy.array(range(N)).astype('i')
+  X = numpy.zeros(NP).astype('i')
+  raw_scatter(testArray, X, 0)
+  Y = pypar.scatter(testArray, 0)
+
+  assert numpy.allclose(X, Y)  
+  assert numpy.allclose(X, testArray[myid*NP:(myid+1)*NP])
+  assert numpy.allclose(Y, testArray[myid*NP:(myid+1)*NP])   
+
+  if myid == 0:
+    print "Scatter communication of numeric integer array OK"
+
+
+  testArray = numpy.array(range(N)).astype('f')
+  X = numpy.zeros(NP).astype('f')
+  raw_scatter(testArray, X, 0)
+    
+  Y = pypar.scatter(testArray, 0)
+
+  assert numpy.allclose(X, Y)  
+  assert numpy.allclose(X, testArray[myid*NP:(myid+1)*NP])
+  assert numpy.allclose(Y, testArray[myid*NP:(myid+1)*NP])   
+
+  if myid == 0:
+    print "Scatter communication of numeric real arrays OK"
+  #else:
+  #  print X, testArray, Y
+  #  assert numpy.allclose(X, Y)
+
+  testArray = numpy.array(range(N)).astype('D')
+  X = numpy.zeros(NP).astype('D')
+  raw_scatter(testArray, X, 0)
+    
+  Y = pypar.scatter(testArray, 0)
+
+  assert numpy.allclose(X, Y)  
+  assert numpy.allclose(X, testArray[myid*NP:(myid+1)*NP])
+  assert numpy.allclose(Y, testArray[myid*NP:(myid+1)*NP])   
+
+  if myid == 0:
+    print "Scatter communication of numeric complex array OK"
+
+
+###################################################
+#FIXME: 2D scatter doesn't work yet    
+#   M = 16
+#   N = 13
+#   MP = M/numproc
+  
+#   testArray = numpy.array(range(M*N)).astype('D')
+#   testArray = numpy.reshape(testArray, (M,N))    
+#   X = numpy.zeros(MP*N).astype('D')
+#   X = numpy.reshape(X, (MP,N))
+  
+#   raw_scatter(testArray, X, 0)
+#   Y = pypar.scatter(testArray, 0)
+  
+#   assert numpy.allclose(X, Y)  
+#   assert numpy.allclose(X, testArray[myid*MP:(myid+1)*MP,:])
+#   assert numpy.allclose(Y, testArray[myid*MP:(myid+1)*MP,:])   
+
+#   if myid == 0:
+#     print "Scatter communication of 2D numeric complex array OK"
+
+
+
+  # Test gather  - with/without buffers (arrays, strings)
+  #
+  N = 17 #Number of elements
+      
+  testString = 'AB'
+  X = '_'*(len(testString)*numproc)    #Blanks caused errors when numproc >= 6 
+  raw_gather(testString, X, 0)
+
+  Y =  pypar.gather(testString, 0) 
+  
+  if myid == 0:
+    assert X == 'AB' * numproc
+    assert Y == 'AB' * numproc
+    print "Gather communication of strings OK"
+  
+
+  testArray = numpy.array(range(N)).astype('i')
+  X = numpy.zeros(N*numproc).astype('i')
+  raw_gather(testArray, X, 0)
+
+  Y = pypar.gather(testArray, 0)
+  
+  if myid == 0:
+    for i in range(numproc):       
+      assert numpy.allclose(testArray, X[(i * N): ((i+1)*N)])
+
+    assert numpy.allclose(X, Y)
+    print "Gather communication of numeric integer array OK"
+    
+    
+  testArray = numpy.array(range(N)).astype('f')
+  X = numpy.zeros(N*numproc).astype('f')
+  raw_gather(testArray, X, 0)
+  
+  Y = pypar.gather(testArray, 0)
+  if myid == 0:
+    for i in range(numproc):       
+      assert numpy.allclose(testArray, X[(i * N): ((i+1)*N)])
+    assert numpy.allclose(X, Y)      
+    print "Gather communication of numeric real array OK"
+    
+  
+  testArray = numpy.array(range(N)).astype('D')
+  X = numpy.zeros(N*numproc).astype('D')
+  raw_gather(testArray, X, 0)
+  
+  Y = pypar.gather(testArray, 0)
+  if myid == 0:
+    for i in range(numproc):       
+      assert numpy.allclose(testArray, X[(i * N): ((i+1)*N)])
+    assert numpy.allclose(X, Y)      
+    print "Gather communication of numeric complex arrays OK"
+
+  M = 13  
+  testArray = numpy.array(range(M*N)).astype('D')
+  testArray = numpy.reshape(testArray, (M,N))
+  X = numpy.zeros(M*N*numproc).astype('D')
+  X = numpy.reshape(X, (M*numproc,N))
+  
+  raw_gather(testArray, X, 0)
+  
+  Y = pypar.gather(testArray, 0)
+  if myid == 0:
+    for i in range(numproc):       
+      assert numpy.allclose(testArray, X[(i * M): ((i+1)*M), :])
+    assert numpy.allclose(X, Y)      
+    print "Gather communication of 2D numeric complex arrays OK"
+    
+  
+  ########################################################
+  # Test reduce
+  #######################################################
+  N = 17 #Number of elements
+  
+  # Create one (different) array on each processor
+  #    
+  testArray = numpy.array(range(N)).astype('i') * (myid+1)
+  #print testArray
+  X = numpy.zeros(N).astype('i') # Buffer for results
+
+  raw_reduce(testArray, X, pypar.SUM, 0)
+  if myid == 0:
+    Y = numpy.zeros(N).astype('i')
+    for i in range(numproc):
+      Y = Y+numpy.array(range(N)).astype('i')*(i+1)    
+    #print X
+    #print Y  
+    assert numpy.allclose(X, Y)
+    print "Raw reduce using pypar.SUM OK"
+        
+  raw_reduce(testArray, X, pypar.MAX, 0, 0)
+  if myid == 0:
+    Y = numpy.array(range(N))*numproc
+    assert numpy.allclose(X, Y)
+    print "Raw reduce using pypar.MAX OK"
+
+  raw_reduce(testArray, X, pypar.MIN, 0, 0)
+  if myid == 0:
+    Y = numpy.array(range(N))
+    assert numpy.allclose(X, Y)
+    print "Raw reduce using pypar.MIN OK"
+    
+  if numproc <= 20:
+    testArray_float = testArray.astype('f')  #Make room for big results
+    X_float = X.astype('f')
+    raw_reduce(testArray_float, X_float, pypar.PROD, 0, 0)
+    if myid == 0:
+      Y = numpy.ones(N).astype('f')    
+      for i in range(numproc):
+        Y = Y*numpy.array(range(N))*(i+1)    
+      #print X_float
+      #print Y  
+      assert numpy.allclose(X_float, Y)
+      print "Raw reduce using pypar.PROD OK"
+  else:
+    if myid == 0:
+      print "Skipping product-reduce - try again with numproc < 20"    
+
+  raw_reduce(testArray, X, pypar.LAND, 0, 0)
+  if myid == 0:  
+    Y = numpy.ones(N).astype('i')    
+    for i in range(numproc):
+      Y = numpy.logical_and(Y, numpy.array(range(N)).astype('i')*(i+1))  
+    assert numpy.allclose(X, Y)
+    print "Raw reduce using pypar.LAND OK"    
+    
+  raw_reduce(testArray, X, pypar.BAND, 0, 0)
+  if myid == 0:
+    Y = numpy.ones(N).astype('i')*255  #Neutral element for &   
+    for i in range(numproc):
+      Y = numpy.bitwise_and(Y, numpy.array(range(N))*(i+1))
+    assert numpy.allclose(X, Y)
+    print "Raw reduce using pypar.BAND OK"    
+
+  raw_reduce(testArray, X, pypar.LOR, 0, 0)
+  if myid == 0:  
+    Y = numpy.zeros(N).astype('i')    
+    for i in range(numproc):
+      Y = numpy.logical_or(Y, numpy.array(range(N)).astype('i')*(i+1))  
+    assert numpy.allclose(X, Y)
+    print "Raw reduce using pypar.LOR OK"    
+  
+  raw_reduce(testArray, X, pypar.BOR, 0, 0)
+  if myid == 0:
+    Y = numpy.zeros(N).astype('i')   #Neutral element for |   
+    for i in range(numproc):
+      Y = numpy.bitwise_or(Y, numpy.array(range(N)).astype('i')*(i+1))
+    assert numpy.allclose(X, Y)
+    print "Raw reduce using pypar.BOR OK"    
+
+  raw_reduce(testArray, X, pypar.LXOR, 0, 0)
+  if myid == 0:  
+    Y = numpy.zeros(N).astype('i')    
+    for i in range(numproc):
+      Y = numpy.logical_xor(Y, numpy.array(range(N)).astype('i')*(i+1))  
+    assert numpy.allclose(X, Y)
+    print "Raw reduce using pypar.LXOR OK"    
+
+  raw_reduce(testArray, X, pypar.BXOR, 0, 0)
+  if myid == 0:
+    Y = numpy.zeros(N).astype('i')   #Neutral element for xor ?   
+    for i in range(numproc):
+      Y = numpy.bitwise_xor(Y, numpy.array(range(N)).astype('i')*(i+1))
+    assert numpy.allclose(X, Y)
+    print "Raw reduce using pypar.BXOR OK"    
+
+  # NOT YET SUPPORTED
+  #  
+  #raw_reduce(testArray, X, N, pypar.MAXLOC, 0, 0)  
+  #if myid == 0:
+  #  print 'MAXLOC', X
+  #raw_reduce(testArray, X, N, pypar.MINLOC, 0, 0)
+  #if myid == 0:
+  #  print 'MINLOC', X
+  
+  #
+  #  FIXME
+  # Don't know how to test this (not available on all MPI systems)
+  #
+  #raw_reduce(testArray, X, N, pypar.REPLACE, 0, 0)
+  #if myid == 0:
+  #  print 'REPLACE', X
+
+
+
+  # Test status block (simple communication)
+  N = 17  
+  if myid == 0:
+    # Integer arrays
+    #
+    A = numpy.array(range(N)).astype('i')
+
+    pypar.send(A,1)
+    B, status = pypar.receive(numproc-1, return_status = True)
+
+    repr(status)  # Check that status can be printed
+
+    sz = A.itemsize
+    assert numpy.allclose(A, B)
+    assert len(B) == status.length, 'Reported length == %d should be %d'\
+           %(status.length, len(B))
+    assert status.size == sz, 'Reported size == %d should be %d'\
+           %(status.size, sz)
+    assert status.tag == pypar.default_tag, 'Reported tag == %d should be %d'\
+           %(status.tag, pypar.default_tag)
+    assert status.error == 0
+    assert status.source == numproc-1, 'Reported source == %d should be %d'\
+           %(status.source, numproc-1)
+
+    print "Status object (numeric integer arrays) OK"
+           
+    # Real arrays
+    #
+    A = numpy.array(range(N)).astype('f')
+    pypar.send(A,1)
+    B, status = pypar.receive(numproc-1, return_status = True)    
+
+    sz = A.itemsize    
+    assert numpy.allclose(A, B)
+    assert len(B) == status.length, 'Reported length == %d should be %d'\
+           %(status.length, len(B))
+    assert status.size == sz, 'Reported size == %d should be %d'\
+           %(status.size, sz)
+    assert status.tag == pypar.default_tag, 'Reported tag == %d should be %d'\
+           %(status.tag, pypar.default_tag)
+    assert status.error == 0
+    assert status.source == numproc-1, 'Reported source == %d should be %d'\
+           %(status.source, numproc-1)
+    
+    print "Status object (numeric real arrays) OK"
+
+    # Strings
+    #
+    A = "and now to something completely different !"
+    pypar.send(A,1)
+    B, status = pypar.receive(numproc-1, return_status = True)        
+
+    sz = 1 #Characters are one byte long
+    assert A == B
+    assert len(B) == status.length, 'Reported length == %d should be %d'\
+           %(status.length, len(B))
+    assert status.size == sz, 'Reported size == %d should be %d'\
+           %(status.size, sz)
+    assert status.tag == pypar.default_tag, 'Reported tag == %d should be %d'\
+           %(status.tag, pypar.default_tag)
+    assert status.error == 0
+    assert status.source == numproc-1, 'Reported source == %d should be %d'\
+           %(status.source, numproc-1)
+    
+    print "Status object (strings) OK"
+    
+    # A more general structure
+    #
+    A = ['ABC', (1,2,3.14), {8: 'Monty'}, numpy.array([13.45, 1.2])]
+    pypar.send(A,1)
+    B, status = pypar.receive(numproc-1, return_status = True)            
+
+    OK = True
+    for i, a in enumerate(A):
+      b = B[i]
+
+      if type(a).__name__ == 'ndarray':
+        if not numpy.allclose(a, b):
+          OK = False
+          break
+      elif a != b:
+        OK = False
+        break
+
+    if OK is True:
+      print 'Status object (more general structures) OK' 
+    else:
+      raise Exception    
+    
+
+    #Length is the number of characters needed to encode the structure
+    #Can't think of a test.
+
+    sz = 1
+    assert status.size == sz, 'Reported size == %d should be %d'\
+           %(status.size, sz)
+    assert status.tag == pypar.default_tag, 'Reported tag == %d should be %d'\
+           %(status.tag, pypar.default_tag)
+    assert status.error == 0
+    assert status.source == numproc-1, 'Reported source == %d should be %d'\
+           %(status.source, numproc-1)
+
+    print "Status object (general structures) OK"
+    
+  else:  
+    # Integers
+    #
+    X=pypar.receive(myid-1)  
+    pypar.send(X, (myid+1)%numproc)
+  
+    # Floats
+    #
+    X=pypar.receive(myid-1)  
+    pypar.send(X, (myid+1)%numproc)    
+
+    # Strings
+    #
+    X=pypar.receive(myid-1)  
+    pypar.send(X, (myid+1)%numproc)    
+
+    # General
+    #
+    X = pypar.receive(myid-1)  
+    pypar.send(X, (myid+1)%numproc)    
+
+
+
+
+
+
+
+
+  # Test status block (raw communication)
+  N = 17 #Number of elements
+  if myid == 0:
+    # Integer arrays
+    #
+    A = numpy.array(range(N)).astype('i')
+    B = numpy.zeros(N).astype('i')    
+    raw_send(A,1)
+    B, status = raw_receive(B,numproc-1,return_status=True)
+    
+    assert numpy.allclose(A, B)
+
+    sz = A.itemsize
+    assert numpy.allclose(A, B)
+    assert len(B) == status.length, 'Reported length == %d should be %d'\
+           %(status.length, len(B))
+    assert status.size == sz, 'Reported size == %d should be %d'\
+           %(status.size, sz)
+    assert status.tag == pypar.default_tag, 'Reported tag == %d should be %d'\
+           %(status.tag, pypar.default_tag)
+    assert status.error == 0
+    assert status.source == numproc-1, 'Reported source == %d should be %d'\
+           %(status.source, numproc-1)
+
+    print "Status object (raw numeric integer arrays) OK"
+
+
+    # Real arrays
+    #
+    A = numpy.array(range(N)).astype('f')
+    B = numpy.zeros(N).astype('f')    
+    raw_send(A,1)
+    B, status = raw_receive(B,numproc-1,return_status=True)    
+    
+    assert numpy.allclose(A, B)
+    sz = A.itemsize
+    assert numpy.allclose(A, B)
+    assert len(B) == status.length, 'Reported length == %d should be %d'\
+           %(status.length, len(B))
+    assert status.size == sz, 'Reported size == %d should be %d'\
+           %(status.size, sz)
+    assert status.tag == pypar.default_tag, 'Reported tag == %d should be %d'\
+           %(status.tag, pypar.default_tag)
+    assert status.error == 0
+    assert status.source == numproc-1, 'Reported source == %d should be %d'\
+           %(status.source, numproc-1)
+
+    print "Status object (raw numeric real arrays) OK"
+
+    # Strings (< 256 characters)
+    #
+    A = "and now to something completely different !"
+    B = " "*len(A)
+    raw_send(A,1)
+    B, status = raw_receive(B,numproc-1,return_status=True)
+
+
+    sz = 1 #Characters are one byte long
+    assert A == B
+    assert len(B) == status.length, 'Reported length == %d should be %d'\
+           %(status.length, len(B))
+    assert status.size == sz, 'Reported size == %d should be %d'\
+           %(status.size, sz)
+    assert status.tag == pypar.default_tag, 'Reported tag == %d should be %d'\
+           %(status.tag, pypar.default_tag)
+    assert status.error == 0
+    assert status.source == numproc-1, 'Reported source == %d should be %d'\
+           %(status.source, numproc-1)
+
+    print "Status object (raw strings) OK"
+    
+
+    
+    # A more general structure
+    #
+    A = ['ABC', (1,2,3.14), {8: 'Monty'}, numpy.array([13.45, 1.2])]
+    B = ['   ', (0,0,0.0), {0: '     '}, numpy.zeros(2).astype('f')]    
+    raw_send(A,1)
+    B, status = raw_receive(B,numproc-1, return_status=True)
+
+
+    #assert A == B
+    sz = 1
+    assert status.size == sz, 'Reported size == %d should be %d'\
+           %(status.size, sz)
+    assert status.tag == pypar.default_tag, 'Reported tag == %d should be %d'\
+           %(status.tag, pypar.default_tag)
+    assert status.error == 0
+    assert status.source == numproc-1, 'Reported source == %d should be %d'\
+           %(status.source, numproc-1)
+
+    
+    print "Status object (raw general structures) OK"
+    
+   
+  else:  
+    # Integers
+    #
+    X = numpy.zeros(N).astype('i')    
+    raw_receive(X, myid-1)  
+    raw_send(X, (myid+1)%numproc)
+  
+    # Floats
+    #
+    X = numpy.zeros(N).astype('f')
+    raw_receive(X, myid-1)  
+    raw_send(X, (myid+1)%numproc)    
+
+    
+    # Strings
+    #
+    X = " "*256
+    X = raw_receive(X, myid-1)  
+    raw_send(X.strip(), (myid+1)%numproc)    
+
+    # General
+    #
+    X = ['   ', (0,0,0.0), {0: '     '}, numpy.zeros(2).astype('f')]
+    X = raw_receive(X, myid-1)  
+    raw_send(X, (myid+1)%numproc)    
+    
+
+
+pypar.finalize()
+
+
+
+
Index: /branches/numpy_misc/tools/acceptance_tests/test_python_packages.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/test_python_packages.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/test_python_packages.py	(revision 6991)
@@ -0,0 +1,97 @@
+#!/bin/env python
+
+'''Testlet to check that packages required are importable'''
+
+import sys
+import time
+import test_utils as util
+
+
+# packages we are testing
+Package_Imports = ('from Scientific.IO.NetCDF import NetCDFFile',
+                   'import numpy',
+                   'import Numeric',
+                   'import RandomArray',
+                   'import pypar',
+                   'import matplotlib',
+                   'import pylab')
+
+def test(logfile):
+    result = True
+    start_time = time.time()
+
+    (cluster, domain) = util.get_hostname()
+
+    util.header(logfile, 'Test if python packages are importable on %s.' % cluster)
+
+    # get max width of the import tests
+    width = 0
+    for pkg in Package_Imports:
+        width = max(len(pkg), width)
+
+    # create a 'null' stdout object
+    null_stdout = open('/dev/null', 'w')
+
+    # test each import
+    num_errors = 0
+    error_packages = []
+    
+    for pkg in Package_Imports:
+        util.log_print(logfile, "Testing: %s" % pkg.ljust(width+2))
+        try:
+            # turn off stdout while doing this
+            save_stdout = sys.stdout
+            sys.stdout = null_stdout
+
+            exec pkg
+
+            sys.stdout = save_stdout
+            util.log_print_nl(logfile, 'OK')
+        except ImportError, e:
+            sys.stdout = save_stdout
+            util.log_print_nl(logfile, 'ERROR')
+            error_packages.append(pkg)
+            num_errors += 1
+            result = False
+        except:
+            sys.stdout = save_stdout
+            util.log_print_nl(logfile, 'EXCEPTION')
+            error_packages.append(pkg)
+            num_errors += 1
+            result = False
+
+    # close the 'null' stdout
+    null_stdout.close()
+
+    # report errors
+    util.log_print_nl(logfile)
+    if num_errors == 0:
+        util.log_print_nl(logfile, 'All OK.')
+    else:
+        if num_errors == 1:
+            util.log_print_nl(logfile, '\nGot %d error: ' % num_errors)
+        else:
+            util.log_print_nl(logfile, '\nGot %d errors: ' % num_errors)
+        for pkg in error_packages:
+            util.log_print_nl(logfile, '\t%s' % pkg)
+    
+    util.footer(logfile, start_time)
+    return result
+
+
+if __name__ == '__main__':
+    import os
+
+    logfile = 'test.log'
+    if len(sys.argv) > 1:
+        logfile = sys.argv[1]
+
+    try:
+        os.remove(logfile)
+    except:
+        pass
+
+    if not test(logfile):
+        sys.exit(10)
+
+    sys.exit(0)
Index: /branches/numpy_misc/tools/acceptance_tests/test_quadrature_parallel_interleaved.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/test_quadrature_parallel_interleaved.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/test_quadrature_parallel_interleaved.py	(revision 6991)
@@ -0,0 +1,105 @@
+#!/bin/env python
+
+'''Testlet to run the QuadratureParallelInterleaved test.'''
+
+import os
+import time
+import test_utils as util
+
+Processor_Numbers = [1, 2, 4, 8, 16]
+
+def test(logfile):
+    result = True
+    start_time = time.time()
+
+    (cluster, domain) = util.get_hostname()
+
+    util.header(logfile, 'Running quadrature parallel interleaved test on %s.' % cluster)
+
+    # compile C code
+    obj_file = 'quadrature_parallel_interleaved'
+    cmd = ('mpicc quadrature_parallel_interleaved.c -lm -o %s' % obj_file)
+    util.log_print(logfile, 'Compiling quadrature_parallel_interleaved.c ...')
+    (_, fd) = os.popen4(cmd)
+    output = fd.read()
+    status = fd.close()
+    if status:
+        util.log_print_nl(logfile, 'ERRORS COMPILING')
+        util.log_print(logfile, output)
+        util.footer(logfile, start_time)
+        return False
+
+    util.log_print_nl(logfile, 'OK\n')
+
+    # run the tests
+    results = []
+    machines_file = '~/.machines_%s' % cluster
+    single_processor_time = None
+    for num_procs in Processor_Numbers:
+        cmd = ('mpirun -np %2d -hostfile %s %s'
+               % (num_procs, machines_file, obj_file))
+        util.log_print(logfile, cmd + ' ...')
+        (_, fd) = os.popen4(cmd)
+        output = fd.readlines()
+        status = fd.close()
+        if status:
+            util.log_print_nl(logfile, 'ERRORS')
+            util.log_print(logfile, '\n'.join(output))
+            util.footer(logfile, start_time)
+            return False
+
+        for line in output:
+            if line.startswith('Time'):
+                (_, elapsed_time) = line.split(' = ', 1)
+                elapsed_time = elapsed_time.strip()
+                (elapsed_time, _) = elapsed_time.split(' ', 1)
+                elapsed_time = float(elapsed_time)
+
+        if elapsed_time is None:
+            util.log_print_nl(logfile, 'ERRORS')
+            util.log_print(logfile, '\n'.join(output))
+            util.footer(logfile, start_time)
+            return False
+            
+        results.append((num_procs, elapsed_time))
+        util.log_print_nl(logfile, 'took %.1fs' % elapsed_time)
+
+    # interpret the results
+    util.log_print(logfile, '\nResults of quadrature interleaved parallel test on %s\n' % cluster)
+    util.log_print(logfile, '%s\t%s\t%s\t%s\n' % ('#procs', 'time', 'speedup', 'parallel efficiency'))
+
+    single_processor_time = None
+    for (num_processors, elapsed_time) in results:
+        num_processors = int(num_processors)
+        if num_processors == 1:
+            single_processor_time = elapsed_time
+
+        speedup = single_processor_time / elapsed_time
+        parallel_efficiency = speedup / num_processors
+
+        util.log_print(logfile, '%d\t%.2f\t%.2f\t%.2f\n'
+                       % (num_processors, elapsed_time, speedup, parallel_efficiency))
+
+    util.footer(logfile, start_time)
+
+    os.remove(obj_file)
+
+    return result
+
+
+if __name__ == '__main__':
+    import sys
+
+    logfile = 'test.log'
+    if len(sys.argv) > 1:
+        logfile = sys.argv[1]
+
+    try:
+        os.remove(logfile)
+    except:
+        pass
+
+    if not test(logfile):
+        sys.exit(10)
+
+    sys.exit(0)
Index: /branches/numpy_misc/tools/acceptance_tests/test_ssh_to_compute_nodes.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/test_ssh_to_compute_nodes.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/test_ssh_to_compute_nodes.py	(revision 6991)
@@ -0,0 +1,64 @@
+#!/bin/env python
+
+'''Testlet to check that can ssh to each subordinate node of the cluster.'''
+
+import os
+import time
+import test_utils as util
+
+
+def test(logfile):
+    result = True
+    start_time = time.time()
+
+    (cluster, domain) = util.get_hostname()
+
+    util.header(logfile, 'Test of compute-node accessibility via ssh on %s.' % cluster)
+
+    # get cluster-specific information
+    cluster_dict = util.get_cluster_info(cluster)
+    if cluster_dict is None:
+        util.log_print_nl(logfile, 'Sorry, you must be on one of these clusters:')
+        for name in Cluster_Info:
+            util.log_print_nl(logfile, '\t%s' % name)
+        util.log_print_nl(logfile, 'You are on the %s machine.' % cluster)
+        util.footer(logfile, start_time)
+        return False
+
+    # get max width of the compute node names
+    width = len(cluster_dict['node_stem']) + len(str(cluster_dict['num_nodes']))
+
+    # test each node
+    for node_num in range(cluster_dict['num_nodes']):
+        node_name = cluster_dict['node_stem'] % node_num
+        util.log_print(logfile, "Testing: %s" % node_name.ljust(width+2))
+        (_, fd) = os.popen4('ssh %s exit' % node_name)
+        data = fd.read()
+        status = fd.close()
+        #if status is None:
+        if len(data) == 0:
+            util.log_print_nl(logfile, 'OK')
+        else:
+            util.log_print(logfile, data)
+            result = False
+
+    util.footer(logfile, start_time)
+    return result
+
+
+if __name__ == '__main__':
+    import sys
+
+    logfile = 'test.log'
+    if len(sys.argv) > 1:
+        logfile = sys.argv[1]
+
+    try:
+        os.remove(logfile)
+    except:
+        pass
+
+    if not test(logfile):
+        sys.exit(10)
+
+    sys.exit(0)
Index: /branches/numpy_misc/tools/acceptance_tests/test_test_all.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/test_test_all.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/test_test_all.py	(revision 6991)
@@ -0,0 +1,61 @@
+#!/bin/env python
+
+'''Testlet to run the 'test_all.py' ANUGA script.'''
+
+import os
+import time
+import test_utils as util
+
+
+def test(logfile):
+    result = True
+    start_time = time.time()
+
+    (cluster, domain) = util.get_hostname()
+
+    util.header(logfile, 'Running ANUGA test_all.py on %s.' % cluster)
+
+    # remember the directory we are in and go to ANUGA test directory
+    home_directory = os.getcwd()
+    pythonpath = os.getenv('PYTHONPATH')
+    newpath = os.path.join(pythonpath, 'anuga')
+    os.chdir(newpath)
+
+    # compile C code
+    util.log_print_nl(logfile, 'python compile_all.py')
+    (_, fd) = os.popen4('python compile_all.py')
+    compile_result = fd.read()
+    status = fd.close()
+    util.log_print(logfile, compile_result)
+
+    # run test_all.py
+    util.log_print_nl(logfile, 'python test_all.py')
+    (_, fd) = os.popen4('python test_all.py')
+    test_result = fd.read()
+    status = fd.close()
+    util.log_print(logfile, test_result)
+
+    # return to original directory
+    os.chdir(home_directory)
+
+    util.footer(logfile, start_time)
+    return result
+
+
+if __name__ == '__main__':
+    import sys
+
+    home_directory = os.getcwd()
+    logfile = os.path.join(home_directory, 'test.log')
+    if len(sys.argv) > 1:
+        logfile = sys.argv[1]
+
+    try:
+        os.remove(logfile)
+    except:
+        pass
+
+    if not test(logfile):
+        sys.exit(10)
+
+    sys.exit(0)
Index: /branches/numpy_misc/tools/acceptance_tests/test_test_pypar.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/test_test_pypar.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/test_test_pypar.py	(revision 6991)
@@ -0,0 +1,127 @@
+#!/bin/env python
+
+'''Testlet to run the pypar tests.'''
+
+import os
+import time
+import test_utils as util
+
+Processor_Numbers = [1, 2, 4, 8, 16]
+
+def test(logfile):
+    result = True
+    start_time = time.time()
+
+    (cluster, domain) = util.get_hostname()
+
+    util.header(logfile, 'Running pypar test on %s.' % cluster)
+
+    # run the test_pypar.py tests
+    machines_file = '~/.machines_%s' % cluster
+    for num_procs in Processor_Numbers:
+        cmd = ('mpirun -np %2d -hostfile %s python test_pypar.py'
+               % (num_procs, machines_file))
+        util.log_print(logfile, cmd + ' ...')
+        fd = os.popen(cmd)
+        output = fd.readlines()
+        status = fd.close()
+        if status:
+            util.log_print_nl(logfile, 'ERRORS')
+            util.log_print(logfile, '\n'.join(output))
+            util.footer(logfile, start_time)
+            result = False
+        else:
+            util.log_print_nl(logfile, 'OK')
+
+    util.log_print_nl(logfile)
+
+    if result is True:
+        util.log_print_nl(logfile, 'test_pypar.py results: GOOD')
+    else:
+        util.log_print_nl(logfile, 'test_pypar.py results: ***** FAILED *****')
+
+    util.log_print_nl(logfile)
+
+    # now for the mandelbrot test
+    home_directory = os.getcwd()
+    os.chdir('mandelbrot')
+    
+    util.log_print_nl(logfile, 'python compile_mandelbrot_c_extensions.py')
+    fd = os.popen('python compile_mandelbrot_c_extensions.py')
+    compile_result = fd.read()
+    status = fd.close()
+    util.log_print(logfile, compile_result)
+    if status:
+        return False
+
+    # run tests
+    machines_file = '~/.machines_%s' % cluster
+    result_data = []
+    for num_procs in Processor_Numbers:
+        cmd = ('mpirun -np %2d -hostfile %s python mandel_parallel_cyclic.py'
+               % (num_procs, machines_file))
+        util.log_print(logfile, cmd + ' ...')
+        fd = os.popen(cmd)
+        output = fd.readlines()
+        status = fd.close()
+        if status:
+            util.log_print_nl(logfile, 'ERRORS (see logfile %s)' % logfile)
+            util.log(logfile, '\n'.join(output))
+        else:
+            for line in output:
+                if line.startswith('Computed region in'):
+                    line = line.replace('Computed region in ', '')
+                    (line, _) = line.split(' ', 1)
+                    compute_time = float(line)
+                    util.log_print_nl(logfile, 'computed in %.1fs' % compute_time)
+                    break
+            result_data.append((num_procs, compute_time))
+
+    # reduce results
+    one_proc_time = None
+    for (num_procs, compute_time) in result_data:
+        if num_procs == 1:
+            one_proc_time = compute_time
+            break
+
+    if one_proc_time is None:
+        util.log_print_nl(logfile, 'ERROR, cannot find single processor compute time!?')
+        return False
+
+    util.log_print_nl(logfile)
+    util.log_print_nl(logfile, 'Results for Mandelbrot Parallel Cyclic test:')
+    util.log_print_nl(logfile, '%s\t%s\t%s\t%s' % ('#procs', 'time', 'speedup', 'parallel_efficiency'))
+    for res in result_data:
+        (num_procs, compute_time) = res
+        
+        speedup = one_proc_time / compute_time
+        parallel_efficiency = speedup / num_procs
+
+        util.log_print_nl(logfile, '%d\t%.2f\t%.3f\t%.3f'
+                          % (num_procs, compute_time, speedup, parallel_efficiency))
+
+    # return to original directory
+    os.chdir(home_directory)
+
+    util.footer(logfile, start_time)
+
+    return result
+
+
+if __name__ == '__main__':
+    import sys
+    
+    logfile = os.path.join(os.getcwd(), 'test.log')
+    if len(sys.argv) > 1:
+        logfile = sys.argv[1]
+
+    try:
+        os.remove(logfile)
+    except:
+        pass
+
+    if not test(logfile):
+        sys.exit(10)
+
+    sys.exit(0)
+
Index: /branches/numpy_misc/tools/acceptance_tests/test_utils.py
===================================================================
--- /branches/numpy_misc/tools/acceptance_tests/test_utils.py	(revision 6991)
+++ /branches/numpy_misc/tools/acceptance_tests/test_utils.py	(revision 6991)
@@ -0,0 +1,110 @@
+#!/bin/env python
+
+'''Utility functions for the cluster acceptance test suite.'''
+
+import os
+import sys
+import time
+
+
+# information about each cluster.
+# 'node_stem' key defines a compute node name.
+# update this if adding a new cluster.
+# should get this from the ~/.machines_<cluster> file?
+Cluster_Info = {'cyclone': {'num_nodes': 23,
+                            'node_stem': 'compute-1-%d'},
+                'tornado': {'num_nodes': 20,
+                            'node_stem': 'compute-0-%d'}
+               }
+
+
+def log(logfile, msg=''):
+    '''Write a message to the log file.'''
+
+    fd = open(logfile, 'a')
+    fd.write(msg)
+    fd.close()
+
+
+def log_nl(logfile, msg=''):
+    '''Write a message to the log file, with a newline added.'''
+
+    log(logfile, msg)
+    log(logfile, '\n')
+
+
+def log_print(logfile, msg=''):
+    '''Write a message to the log file and stdout.
+
+    The message doesn't have a '\n' added to it.
+    '''
+
+    log(logfile, msg)
+    print msg,
+    sys.stdout.flush()
+
+
+def log_print_nl(logfile, msg=''):
+    '''Write a message to the log file and stdout, with a newline added.
+
+    Appends '\n' to msg.
+    '''
+
+    log_nl(logfile, msg)
+    print msg
+    sys.stdout.flush()
+
+
+def header(logfile, msg):
+    '''Write testlet header to log and stdout.'''
+
+    # current time
+    time_now = time.strftime('%H:%M:%S %Y-%m-%d')
+
+    log_print_nl(logfile, '#' * 80)
+    log_print_nl(logfile, '# ' + time_now + ' - ' + msg)
+    log_print_nl(logfile, '#' * 80)
+    log_print_nl(logfile)
+
+
+def footer(logfile, start_time=None):
+    '''Write testlet footer to log and stdout.'''
+
+    if start_time:
+        end_time = time.time()
+        msg = 'Test took %.1f s' % (end_time - start_time)
+    else:
+        msg = 'Finished at %s' % time.ctime()
+        
+    log_nl(logfile)
+    log_nl(logfile, '# ' + msg)
+    log_print_nl(logfile)
+
+
+def get_hostname():
+    '''Return (<host>, <domain>) for machine.
+
+    For example, on the GA cyclone main node, return ('cyclone', 'agso.gov.au').
+    '''
+
+    fd = os.popen('hostname')
+    hostname = fd.read()
+    fd.close()
+
+    try:
+        result = hostname.strip().split('.', 1)
+    except:
+        result = (hostname, '')
+
+    return result
+
+
+def get_cluster_info(cluster):
+    '''Get dictionary containing information for 'cluster'.
+
+    If 'cluster' is not recognized, return None.
+    '''
+
+    return Cluster_Info.get(cluster, None)
+
+
