From Dirk.Engelmann@IWR.Uni-Heidelberg.De  Wed Jun  3 12:34:35 1998
From: Dirk.Engelmann@IWR.Uni-Heidelberg.De (Dirk Engelmann)
Date: Wed, 3 Jun 1998 13:34:35 +0200 (CEST)
Subject: [Matrix-SIG] CXX extension
Message-ID: <Pine.LNX.3.95.980603125037.18187A-100000@klimt.iwr.uni-heidelberg.de>

Hi!


I tried to get the CXX extension module (version a6) running for linux.
Is there a way to get it compiling with gcc (2.8) or egcs (1.02) ?
I got problems with namespace, even if telling in file CXX_Config.h for
not supporting namespace. 
The problem occurs in CXX_Extension.h ,  getting the messages

                 from ./Demo/r.cxx:1:
Include/CXX_Exception.h:24: parse error before `&'
Include/CXX_Exception.h:28: parse error before `&'
Include/CXX_Exception.h:28: semicolon missing after declaration of `class
Exception'


Has this to do with  STD class or namespace ?

Thanks for help!


Cheers,

Dirk Engelmann



From da@skivs.ski.org  Wed Jun  3 17:49:36 1998
From: da@skivs.ski.org (David Ascher)
Date: Wed, 3 Jun 1998 09:49:36 -0700 (PDT)
Subject: [Matrix-SIG] CXX extension
In-Reply-To: <Pine.LNX.3.95.980603125037.18187A-100000@klimt.iwr.uni-heidelberg.de>
Message-ID: <Pine.SUN.3.96.980603094900.24083A-100000@skivs.ski.org>

On Wed, 3 Jun 1998, Dirk Engelmann wrote:

> I tried to get the CXX extension module (version a6) running for linux.
> Is there a way to get it compiling with gcc (2.8) or egcs (1.02) ?

Nope.  AFAIK, gcc/egcs only support one namespace (called standard or
something like that).  

--da



From miller5@uiuc.edu  Thu Jun  4 19:26:58 1998
From: miller5@uiuc.edu (Mike Miller)
Date: 04 Jun 1998 13:26:58 -0500
Subject: [Matrix-SIG] TableIO once again...
Message-ID: <t9hg2181l9.fsf@uinpluxb.npl.uiuc.edu>

Dear matrix folks,

The recent discussion on comp.lang.python about finding help and
such has prompted me to post TableIO to c.l.p.  This falls into
the category of "here's how I do that".  If anyone is using an
older version that I announced here, this version is slightly
tweaked.  You can now specify any collection of comment
characters.  Plus trailing blank lines are no longer a problem.
The interface has changed - any call that used to include a file
name parameter now includes a file name parameter and a string
containing comment characters.

Regards, Mike

<http://www.npl.uiuc.edu/~miller/python>


-- 
Michael A. Miller                                miller5@uiuc.edu
  Department of Physics, University of Illinois, Urbana-Champaign
  PGP public key available on request


From aaron@cs.rutgers.edu  Fri Jun  5 13:08:23 1998
From: aaron@cs.rutgers.edu (Aaron Watters)
Date: Fri, 05 Jun 1998 08:08:23 -0400
Subject: [Matrix-SIG] reAnnounce PySimplex Mixed Integer Linear Programming
Message-ID: <3577DFB7.AA0CC143@cs.rutgers.edu>

This is a major bugfix and enhancement announcement.
Many thanks to those who commented especially
Hans D. Mittelmann of ASU who helped me flush out several
MPS interpretation errors.  Now I get the results advertised
by netlib (they weren't wrong after all!).

ANNOUNCE PySimplex Mixed Integer Linear Programming 0.1
===================================================

Readers are asked to take a look at and maybe try out
my newly released PySimplex beta Python modules
for Linear Programming.  This software is available
for any purpose, provided as is with no warrantee.
Please see the COPYRIGHT for details.

http://www.pythonpros.com/arw/pysimplex

Pysimplex provides some basic symbolic programming
tools for constructing, solving and optimizing
systems of linear equations and inequalities.
It includes an implementation of the classical
SIMPLEX linear optimization algorithm as well as a filter for parsing
and
optimizing linear models encoded using the standard MPS format.

Perhaps the most compelling aspect of these modules is the way they
allow the user or programmer to construct models in a straightforward
symbolic manner.  For example the following constraint model

  x>=1 and y>=1 and
  x+2*y-1.5 >= 0 and
  y-3*x-0.9 >= 0

may be constructed at the python command line as follows:

>>> v = VariableNamer()
>>> x,y = v.x, v.y
>>> constraints = all_positive(v, x-1, y-1, x+2*y-1.5, y-3*x-0.9)

and the following interaction computes the maximal value for the
objective
function -x-y within this system of constraints.

>>> (sys, ob) = constraints.rsimplex(-x-y)
>>>
>>> sys({})
{'_free20': 7.3, 'x': 1.0, 'y': 3.9, '_free19': 2.9}

Thus the maximum value for -x-y is achieved at x=1.0 and y=3.9.

More interestingly these modules also allow the optimization of
an objective function subject to linear constraints and additional
constraints that some of the variables must have integer or binary
(0 or 1) values.  The function below finds the smallest number of
whole currency units whose value sum to within 3 cents less than 1199.03

dollars.
<pre>
def currencytest():
    """find the smallest number of whole currency units no more
       than 3 cents less than $1199.03 (within 1% of optimal)"""
    # set the goal in dollars, and discrepancy allowed
    goalamount = 1199.03
    error_dollars = 0.03
    # create variables for the model
    v = VariableNamer()
    dollar = v.dollar; franc = v.franc;  yen = v.yen
    pound = v.pound; mark = v.mark; peseta = v.peseta
    yuan = v.yuan;  ruble = v.ruble; candollar = v.candollar
    diff = v.diff; currencyvalue = v.currencyvalue
    # jun 5 1998, conversion rates
    yendollar = 1/138.0; poundollar = 1/0.61; francdollar = 1/5.74
    markdollar = 1/1.78; pesetadollar = 1/151.0
    yuandollar = 1/8.28; rubledollar = 1/6.0; candollardollar = 1/1.46
    # define equalities for amount and discrepancy
    amount = NamedTransform(v,
      diff =          goalamount - currencyvalue,
      currencyvalue = +dollar +yendollar*yen +poundollar*pound
                      +francdollar* +markdollar*mark
+pesetadollar*peseta
                      +yuandollar*yuan +rubledollar*ruble
                      +candollardollar*candollar )
    # define error tolerance
    error_allowed = all_positive(v, error_dollars-diff)
    constraints = amount & error_allowed
    print "constraints"
    print constraints
    # define the objective: minimize number of whole units
    units = dollar+yen+pound+franc+mark+peseta+yuan+ruble+candollar
    # minimize
    (s,o) = constraints.nsimplex(
              -units,
              integervars= [franc, pound, yen, dollar, mark, peseta,
yuan,
                            ruble,  candollar],
              near=0.01)
    # print a report on minimization
    sub = s({})
    items = sub.items()
    items.sort()
    for (a,b) in items:
        if b>0.01:
            print "hand the customer %s %s's" % (b,a)
    total = sub["currencyvalue"]
    print "total is worth %s dollars" % total
    print "units", units.evalconst(sub)
</pre>
When evaluated this function prints
<pre>
hand the customer 1199.00875109 currencyvalue's
hand the customer 0.0212489110635 diff's
hand the customer 2.0 dollar's
hand the customer 730.0 pound's
hand the customer 1.0 ruble's
hand the customer 1.0 yuan's
total is worth 1199.00875109 dollars
units 734.0
</pre>
Thus 2 dollars and 730 pounds and 1 ruble and 1 yuan sum to value
1199.0087 which is within 3 cents of 1199.03, and these 734 currency
units are within 7 units of the least number of currency units
with value within 3 cents
less than 1199.03. (In fact rerunning the function with near=0
shows that this is the optimal such number of units.  Note that reducing

the error tolerance to 1 cent makes it a noticably harder,
i.e., slower, problem.)

Requirements
============

This software requires Python and the Python Numeric extensions.
Easy installations for Python and the Numeric extensions may be obtained

via links starting at http://www.python.org
for Windows 95, NT and many other platforms.

Thanks
======

Many thanks to Guido van Rossum, Jim Hugunin (the primary developers of
Python
and Numpy respectively) as well as the other contributors to Numpy,
especially Dave Ascher and Paul F. Dubois, and to
John W. Gregory and Robert Fourer of the Linear Programming FAQ, as well
as to
<a href="http://www-leland.stanford.edu/~digenova/dantzig/">George
Dantzig</a>
pioneer of the simplex method.

   -- Aaron Watters
===
Yet what are such gaieties to me
Whose thoughts are full of indices and surds?
x**2 + 7*x + 53
= 11/3
 -- Lewis Carroll




From hinsen@cnrs-orleans.fr  Fri Jun  5 23:02:08 1998
From: hinsen@cnrs-orleans.fr (hinsen@cnrs-orleans.fr)
Date: Fri, 5 Jun 1998 17:02:08 -0500 (CDT)
Subject: [Matrix-SIG] Re: [PSA MEMBERS] Numeric Python Set function
In-Reply-To: <Pine.SGI.3.96.980604203406.4077A-100000@solomon> (message from
 Michel Sanner on Thu, 4 Jun 1998 20:36:53 -0700 (PDT))
References: <Pine.SGI.3.96.980604203406.4077A-100000@solomon>
Message-ID: <199806052202.RAA13580@dirac.cnrs-orleans.fr>

> I was wondering if there is something like a "set" function in
> Numeric Python that would allow to set values in an array given
> an array of indices and an array of values. (somehow the same
> operation as take() but to set values).

[Note: I have CCed this to the Matrix-SIG, which is a more
appropriate place for this topic.]

No, there is no such function in the current NumPy; it's one of
important holes in the system. Various proposals have been made
to get this functionality (and also that of take()) via extended
indexing expressions. I think some people wanted to investigate
an implementation, but I may be wrong. If anyone has news on this
topic, please let us know...
-- 
-------------------------------------------------------------------------------
Konrad Hinsen                            | E-Mail: hinsen@cnrs-orleans.fr
Centre de Biophysique Moleculaire (CNRS) | Tel.: +33-2.38.25.55.69
Rue Charles Sadron                       | Fax:  +33-2.38.63.15.17
45071 Orleans Cedex 2                    | Deutsch/Esperanto/English/
France                                   | Nederlands/Francais
-------------------------------------------------------------------------------


From Paul F. Dubois" <dubois1@llnl.gov  Fri Jun  5 16:51:05 1998
From: Paul F. Dubois" <dubois1@llnl.gov (Paul F. Dubois)
Date: Fri, 5 Jun 1998 08:51:05 -0700
Subject: [Matrix-SIG] [PSA MEMBERS] Numeric Python Set function
Message-ID: <004601bd9099$bfe517a0$52120f80@pduboispc.llnl.gov>

Since it is nice to have a positive answer to a question, I want to make
sure Zane's answer reaches the matrix-sig. Please excuse if you already saw
it.

Is this function, or others in arrayfns, something we should move into NumPy
proper? I think array_set does sound like an important function.

-----Original Message-----
From: Zane Motteler <zcm@llnl.gov>
To: Michel Sanner <sanner@scripps.edu>
Cc: psa-members@python.org <psa-members@python.org>
Date: Friday, June 05, 1998 7:23 AM
Subject: Re: [PSA MEMBERS] Numeric Python Set function


>Michel,
>
>You wrote:
>
>>I was wondering if there is something like a "set" function in
>>Numeric Python that would allow to set values in an array given
>>an array of indices and an array of values. (somehow the same
>>operation as take() but to set values).
>
>Not in numeric python. However, when I was writing the PyGist
>graphics interface, I found the need for such a function.
>I wrote a module called 'arrayfnsmodule' which contains a
>function array_set which takes three arguments: the first
>is a one-dimensional array, the second is a one-dimensional
>array of valid subscripts into the first, and the third
>is either a scalar or an array of the same length as the
>second argument, to be assigned to the specified places in
>the first array.
>
>This module and all others for which we are responsible at LLNL
>can be found at our anonymous ftp site, ftp-icf.llnl.gov,
>at /ftp/pub/python/LLNLPython1.tgz. If you gunzip and untar
>this file, the source is found in
>LLNLDistribution/Graphics/Arrayfcns/Src.
>You can build a shared object for this module (and others in
>the Graphics subdirectory) by moving Makefile.pre.in from
>Python-1.5.1/Misc to Graphics, and then typing 'python makethis.py'.
>
>Hope this helps.
>
>Zane
>
>-----------------------------------------------------------------
>                      Zane C. Motteler, Ph. D.
>Computer Scientist             | Professor Emeritus of
>Lawrence Livermore National    |    Computer Science and Engineering
>   Laboratory                  | California Polytechnic
>P. O. Box 808, L-038           |    State University
>Livermore, CA 94551-9900       | San Luis Obispo, CA 93407
>925/423-2143, FAX 925/423-9208 | zmottel@phoenix.csc.calpoly.edu
>zcm@llnl.gov
>(For FedEx, UPS, etc. use street address 7000 East Avenue, zip 94550)
>
>
>
>_______________
>PSA-MEMBERS  --  Python Software Activity Members
>
>send messages to: psa-members@python.org
>administrivia to: psa-members-request@python.org
>_______________
>



From aaron@cs.rutgers.edu  Fri Jun  5 17:26:07 1998
From: aaron@cs.rutgers.edu (Aaron Watters)
Date: Fri, 05 Jun 1998 12:26:07 -0400
Subject: [Matrix-SIG] Re: [PSA MEMBERS] Numeric Python Set function
References: <v0300781eb19dbae82d4a@[128.115.36.161]>
Message-ID: <35781C1F.90AA5328@cs.rutgers.edu>

"Inverse of take" reprise.

I can't tell you how often I need this functionality.
Somebody once told me they were working on it.
Any luck?  -- Aaron Watters

Zane Motteler wrote:

> Michel,
>
> You wrote:
>
> >I was wondering if there is something like a "set" function in
> >Numeric Python that would allow to set values in an array given
> >an array of indices and an array of values. (somehow the same
> >operation as take() but to set values).
>
> Not in numeric python. However, when I was writing the PyGist
> graphics interface, I found the need for such a function.
> I wrote a module called 'arrayfnsmodule' which contains a
> function array_set which takes three arguments: the first
> is a one-dimensional array, the second is a one-dimensional
> array of valid subscripts into the first, and the third
> is either a scalar or an array of the same length as the
> second argument, to be assigned to the specified places in
> the first array.
>
> This module and all others for which we are responsible at LLNL
> can be found at our anonymous ftp site, ftp-icf.llnl.gov,
> at /ftp/pub/python/LLNLPython1.tgz. If you gunzip and untar
> this file, the source is found in
> LLNLDistribution/Graphics/Arrayfcns/Src.
> You can build a shared object for this module (and others in
> the Graphics subdirectory) by moving Makefile.pre.in from
> Python-1.5.1/Misc to Graphics, and then typing 'python makethis.py'.
>
> Hope this helps.
>
> Zane
>
> -----------------------------------------------------------------
>                       Zane C. Motteler, Ph. D.
> Computer Scientist             | Professor Emeritus of
> Lawrence Livermore National    |    Computer Science and Engineering
>    Laboratory                  | California Polytechnic
> P. O. Box 808, L-038           |    State University
> Livermore, CA 94551-9900       | San Luis Obispo, CA 93407
> 925/423-2143, FAX 925/423-9208 | zmottel@phoenix.csc.calpoly.edu
> zcm@llnl.gov
> (For FedEx, UPS, etc. use street address 7000 East Avenue, zip 94550)
>
> _______________
> PSA-MEMBERS  --  Python Software Activity Members
>
> send messages to: psa-members@python.org
> administrivia to: psa-members-request@python.org
> _______________





From phil@geog.ubc.ca  Fri Jun  5 17:33:20 1998
From: phil@geog.ubc.ca (Phil Austin)
Date: Fri, 5 Jun 1998 09:33:20 -0700
Subject: [Matrix-SIG] [PSA MEMBERS] Numeric Python Set function
In-Reply-To: <004601bd9099$bfe517a0$52120f80@pduboispc.llnl.gov>
References: <004601bd9099$bfe517a0$52120f80@pduboispc.llnl.gov>
Message-ID: <199806051633.JAA00891@curlew.geog.ubc.ca>

>>>>> "Paul" == Paul F Dubois <dubois1@llnl.gov> writes:


    Paul> Is this function, or others in arrayfns, something we should
    Paul> move into NumPy proper? I think array_set does sound like an
    Paul> important function.


Definitely. This was news to me and I've been using Gist for a year now.

Phil



From Paul F. Dubois" <dubois1@llnl.gov  Fri Jun  5 23:50:08 1998
From: Paul F. Dubois" <dubois1@llnl.gov (Paul F. Dubois)
Date: Fri, 5 Jun 1998 15:50:08 -0700
Subject: [Matrix-SIG] LLNLPython2 released
Message-ID: <001a01bd90d4$4a45d940$52120f80@pduboispc.llnl.gov>

ftp://ftp-icf.llnl.gov/pub/python/LLNLPython2.tgz is now available. Also
available are windows installers for NumPy and RNG.

It contains the beta release of CXX, Release 1.2 of NumPy, and all the other
LLNL-distributed packages. The file README.html in that same directory
explains the different packages.

Documentation for each package is either included in a Doc subdirectory or
is at:
http://xfiles.llnl.gov. Below are the release notes which are available as
HTML files in the release.

LLNLPython is distributed as a public service by X-Division at Lawrence
Livermore National Laboratory. Please read the legal notice which explains
in more detail that we are doing this only as a public service and are not
responsible for this open-source community-based software, which you use at
your own risk.

Release 2 (June, 1998)
General
Several "Setup" files had a space after the *shared* which mixed up FreeBSD.
(Thomas Gellekum).
NumPy
See Numerical/README.htm (below)
Gist
Bug fixes in Gist3D/Demo/gistdemohigh.py, Gist3D/Lib/quadmesh.py (Thomas
Gellekum).

Numerical Python Version 1.2
Release Notes (June 5, 1998) Paul F. Dubois
Changes from version 1.1:
General Changes
Lib/Numeric.py: Added very inefficient (but working) pickling of arrays
based on the copy_reg
mechanisms. Should be replaced by a __reduce__ method someday. (David
Ascher)
Made comparisons of NumPy arrays raise TypeErrors.
Fixed slice bug reported by Andrew Mullhaupt and fixed by Chris Chase a very
long time ago but never integrated into the souce. See:
http://www.findmail.com/listsaver/matrix-sig/?start=464 (David Ascher).
Unfortunately, the fix itself had an error, so I fixed the fix. (Dubois).
Removed a memory leak in a slicing routine. (Dubois)
Removed a space in Setup that was confusing FreeBSD. (Thomas Gellekum).
Fixed the following operators: <<, >>, &, |, ^.  These had been totally
nooperative due to an error in which the implementing functions were
transferred from one module to another via a dictionary lookup and the name
used was wrong but the lookup status was not checked. The internal names are
now left_shift, right_shift, bitwise_and, bitwise_or, and bitwise_xor.
(Dubois).
Henk Jansen pointed out that UserArray has a typecode() method that is
destroyed by assignment to self.typecode. Instead, the data member was
renamed self._typecode and typecode() taught to use it, as he suggested. I
didn't try to get into the other issues about UserArray that have been
raised. (Dubois)
MacIntosh changes (Rob Managan & Jack Jensen)
In f2c.h we added a #ifndef so abs is not redefined.
#ifndef abs
#define abs(x) ((x) >= 0 ? (x) : -(x))
#endif
in fast_umath and umath we just had to replace <math.h> with "mymath.h".
mymath.h basically does some stuff before including math.h due to funny
stuff CW does for 68K machines. Mainly hypot crashes since it returns 10
byte floats. This file is included in Jack's stuff, not NumPy.
In zlapack_lite Jack Jensen added a hack to allow one long routine to
compile for 68K machines. Not sure if that is well tested or not.




From amullhau@nospam.ix.netcom.com  Sat Jun  6 05:47:37 1998
From: amullhau@nospam.ix.netcom.com (Andrew P. Mullhaupt)
Date: Sat, 06 Jun 1998 00:47:37 -0400
Subject: [Matrix-SIG] Re: [PSA MEMBERS] Numeric Python Set function
References: <Pine.SGI.3.96.980604203406.4077A-100000@solomon> <199806052202.RAA13580@dirac.cnrs-orleans.fr>
Message-ID: <3578C9E9.1111@ix.netcom.com>

hinsen@cnrs-orleans.fr wrote:
> 
> No, there is no such function in the current NumPy; it's one of
> important holes in the system. Various proposals have been made
> to get this functionality (and also that of take()) via extended
> indexing expressions. I think some people wanted to investigate
> an implementation, but I may be wrong. If anyone has news on this
> topic, please let us know...

It's really pretty much a done deal for years in several well known
interpreted languages - APL, S, etc.

Later,
Andrew Mullhaupt


From amullhau@nospam.ix.netcom.com  Sat Jun  6 05:51:11 1998
From: amullhau@nospam.ix.netcom.com (Andrew P. Mullhaupt)
Date: Sat, 06 Jun 1998 00:51:11 -0400
Subject: [Matrix-SIG] [PSA MEMBERS] Numeric Python Set function
References: <004601bd9099$bfe517a0$52120f80@pduboispc.llnl.gov> <199806051633.JAA00891@curlew.geog.ubc.ca>
Message-ID: <3578CABF.1F4E@ix.netcom.com>

Phil Austin wrote:
> 
> >>>>> "Paul" == Paul F Dubois <dubois1@llnl.gov> writes:
> 
>     Paul> Is this function, or others in arrayfns, something we should
>     Paul> move into NumPy proper? I think array_set does sound like an
>     Paul> important function.

Well, a workaround is better than nothing, but NumPy will lag behind
languages
which are decades older if this isn't incorporated into indexing, where
it
belongs.

Later,
Andrew Mullhaupt


From ffjhl@aurora.alaska.edu  Sat Jun  6 17:56:36 1998
From: ffjhl@aurora.alaska.edu (Jonah Lee)
Date: Sat, 6 Jun 1998 08:56:36 -0800 (AKDT)
Subject: [Matrix-SIG] Re: Numeric Python Set function
In-Reply-To: <199806061600.MAA25752@python.org>
Message-ID: <Pine.OSF.3.95.980606085147.10510B-100000@mealpha.engr.uaf.edu>

> >I was wondering if there is something like a "set" function in
> >Numeric Python that would allow to set values in an array given
> >an array of indices and an array of values. (somehow the same
> >operation as take() but to set values).

It is certainly a good idea. Some C++ library has it. For my own work,
using numerical Python, I have a wrapper function to do the same thing
because I need it all the time.

Regards,

Jonah



From h.jansen@math.tudelft.nl  Mon Jun  8 13:22:32 1998
From: h.jansen@math.tudelft.nl (Henk Jansen)
Date: Mon, 08 Jun 1998 14:22:32 +0200
Subject: [Matrix-SIG] fast_umathmodule (Numeric v.1.2)
Message-ID: <357BD788.863@math.tudelft.nl>

It seems that in boolean_XXX functions in the fast_umath module
(version 1.2) have had their names changed into bitwise_XXX functions.
The documentation doesn't mention this. 

I've downloaded LLNLPython2.tgz and tried to compile the modules
separately. As far as I can see, PyGraphics still needs boolean_XXX
functionality which it can't find (some trouble here...?).

Regards,

Henk
 
-- 
 Henk Jansen                        hjansen@math.tudelft.nl
 Delft University of Technology     Delft, The Netherlands 
 Information Technoloy and Systems  phone: +31(0)15.278.7295 
 Mathematics (ITS/TWI/TA/WAGM)      fax:   +31(0)15.278.7209


From h.jansen@math.tudelft.nl  Mon Jun  8 13:35:11 1998
From: h.jansen@math.tudelft.nl (Henk Jansen)
Date: Mon, 08 Jun 1998 14:35:11 +0200
Subject: [Matrix-SIG] umath (version 1.2)
Message-ID: <357BDA7F.4A32@math.tudelft.nl>

In a previous posting I wrote:

> It seems that in boolean_XXX functions in the fast_umath module
> (version 1.2) have had their names changed into bitwise_XXX functions.
> The documentation doesn't mention this. 
> 
> I've downloaded LLNLPython2.tgz and tried to compile the modules
> separately. As far as I can see, PyGraphics still needs boolean_XXX
> functionality which it can't find (some trouble here...?).

Obviously, this applies to the umath module as well.

Further, the documentation says there should be a boolean_not
umath function. I can't find it, neither its bitwise_not equivalent.


-- 
 Henk Jansen                        hjansen@math.tudelft.nl
 Delft University of Technology     Delft, The Netherlands 
 Information Technoloy and Systems  phone: +31(0)15.278.7295 
 Mathematics (ITS/TWI/TA/WAGM)      fax:   +31(0)15.278.7209


From da@skivs.ski.org  Mon Jun  8 18:21:32 1998
From: da@skivs.ski.org (David Ascher)
Date: Mon, 8 Jun 1998 10:21:32 -0700 (PDT)
Subject: [Matrix-SIG] [PSA MEMBERS] Numeric Python Set function
In-Reply-To: <004601bd9099$bfe517a0$52120f80@pduboispc.llnl.gov>
Message-ID: <Pine.SUN.3.96.980608100648.19182A-100000@skivs.ski.org>

On Fri, 5 Jun 1998, Paul F. Dubois wrote:

> Since it is nice to have a positive answer to a question, I want to make
> sure Zane's answer reaches the matrix-sig. Please excuse if you already saw
> it.
> 
> Is this function, or others in arrayfns, something we should move into NumPy
> proper? I think array_set does sound like an important function.

I don't remember the exact specifics of Zane's function.  Something like
it needs to be incorporated not only in NumPy, but in the *indexing*
(setitem) mechanism.  I've done some preliminary work on this, and there
are a couple of non-trivial issues -- specifically, it'd be nice to be
able to do: 

   a[a>100] = 100

as well as a more general form,

   a[b] = c

where b contains some description of the indices of a which need to get
their values from c.

Note that a simplistic implementation will act strangely for at least one
of these under some conditions (since the first index (a>100) corresponds
(or will, someday) to an array of 1's and 0's.  Replace the RHS of the
first example with an array, and you have an ambiguity).  There are ways
around this, which, I believe, localize the complexity to the array
object.  I've been playing with one way to deal with this, which is
basically to usurp the tp_call/__call__ slots, just because they were
there (and because Don Beaudry has, as we know, a twisted mind). Upon
further reflection, I think that coming up with a specialized new slot
(for arrays and arraylike instances) is the right thing to do.

The nice thing about this approach is that arrays of different species can
define different ways to do the indexing (thus arrays which correspond to
logical operations on arrays would "know" that they are masks, whereas
arrays which are returned by other functions would know that they are
indices, etc). It also means that one could have a version of NumPy which
just provides the hooks for this, and various folk can propose specific
mechanisms (see the old debate on S+ vs.  APL vs. etc. indexing).

I'd hoped to post about this when I had a proof-of-concept finished. 
Sadly, that task is on my stack under the rich comparisons, which are
under a fair amount of other stuff.  It's nice to see that there is a
constituency out there, though. =)

--david

PS: Folks should also definitely remember Chris Chase's effort, which is a
    Python-only solution (hence lacked the speed I often need), but
    defined a fuller set of features (ellipses, NewAxis, etc.).  It's
    available on the findmail archives.  I don't remember the exact name
    of the file, but I can resurrect it if it's hard to find.  I vaguely
    remember some discussion where Zane was saying that he didn't
    implement all of these (which I think would be nice to have, at least
    in the final version).
  



From hinsen@cnrs-orleans.fr  Tue Jun  9 02:09:28 1998
From: hinsen@cnrs-orleans.fr (hinsen@cnrs-orleans.fr)
Date: Mon, 8 Jun 1998 20:09:28 -0500 (CDT)
Subject: [Matrix-SIG] [PSA MEMBERS] Numeric Python Set function
In-Reply-To: <004601bd9099$bfe517a0$52120f80@pduboispc.llnl.gov>
 (dubois1@llnl.gov)
References: <004601bd9099$bfe517a0$52120f80@pduboispc.llnl.gov>
Message-ID: <199806090109.UAA18862@dirac.cnrs-orleans.fr>

> Is this function, or others in arrayfns, something we should move into NumPy
> proper? I think array_set does sound like an important function.

Definitely. If it fits into the other array functions (i.e. if its
parameter list is a reasonable extension from that of take()), let's
have it in NumPy.
-- 
-------------------------------------------------------------------------------
Konrad Hinsen                            | E-Mail: hinsen@cnrs-orleans.fr
Centre de Biophysique Moleculaire (CNRS) | Tel.: +33-2.38.25.55.69
Rue Charles Sadron                       | Fax:  +33-2.38.63.15.17
45071 Orleans Cedex 2                    | Deutsch/Esperanto/English/
France                                   | Nederlands/Francais
-------------------------------------------------------------------------------


From jhauser@ifm.uni-kiel.de  Mon Jun  8 20:56:03 1998
From: jhauser@ifm.uni-kiel.de (Janko Hauser)
Date: Mon, 8 Jun 1998 21:56:03 +0200 (CEST)
Subject: [Matrix-SIG] [PSA MEMBERS] Numeric Python Set function
In-Reply-To: <Pine.SUN.3.96.980608100648.19182A-100000@skivs.ski.org>
References: <004601bd9099$bfe517a0$52120f80@pduboispc.llnl.gov> <Pine.SUN.3.96.980608100648.19182A-100000@skivs.ski.org>
Message-ID: <13692.16186.16446.103908@lisboa.ifm.uni-kiel.de>

David Ascher writes:
 > I don't remember the exact specifics of Zane's function.  Something like
 > it needs to be incorporated not only in NumPy, but in the *indexing*
 > (setitem) mechanism.  I've done some preliminary work on this, and there
 > are a couple of non-trivial issues -- specifically, it'd be nice to be
 > able to do: 
 > 
 >    a[a>100] = 100
 > 
 > as well as a more general form,
 > 
 >    a[b] = c
 > 
 > where b contains some description of the indices of a which need to get
 > their values from c.
 > 
 > Note that a simplistic implementation will act strangely for at least one
 > of these under some conditions (since the first index (a>100) corresponds
 > (or will, someday) to an array of 1's and 0's.  Replace the RHS of the
 > first example with an array, and you have an ambiguity).  There are ways
 > around this, which, I believe, localize the complexity to the array
 > object.  I've been playing with one way to deal with this, which is
 > basically to usurp the tp_call/__call__ slots, just because they were
 > there (and because Don Beaudry has, as we know, a twisted mind). Upon
 > further reflection, I think that coming up with a specialized new slot
 > (for arrays and arraylike instances) is the right thing to do.

Am I right, that these forms of indexing are only possible with a
ravel(a) array? Isn't it possible to expand the slice type, so one can 
define indexes along each dimension? (give me any row, where soem
value is bigger than 10)

If the slice type defines something like this other sequence objects
can start to use this way of indexing with the definition of an
additional method (is it getitem or getslice?).

 > under a fair amount of other stuff.  It's nice to see that there is a
 > constituency out there, though. =)
 > 
 > --david

 > 
 > PS: Folks should also definitely remember Chris Chase's effort, which is a
 >     Python-only solution (hence lacked the speed I often need), but
 >     defined a fuller set of features (ellipses, NewAxis, etc.).  It's
 >     available on the findmail archives.  I don't remember the exact name
 >     of the file, but I can resurrect it if it's hard to find.  I vaguely
 >     remember some discussion where Zane was saying that he didn't
 >     implement all of these (which I think would be nice to have, at least
 >     in the final version).
 >   

Also Timothy Hochberg has something along this line implemented in
Python in his FancyArray - UserArray class. It's at his Starship site.

__Janko


From amullhau@nospam.ix.netcom.com  Tue Jun  9 00:20:15 1998
From: amullhau@nospam.ix.netcom.com (Andrew P. Mullhaupt)
Date: Mon, 08 Jun 1998 19:20:15 -0400
Subject: [Matrix-SIG] [PSA MEMBERS] Numeric Python Set function
References: <Pine.SUN.3.96.980608100648.19182A-100000@skivs.ski.org>
Message-ID: <357C71AF.3D6@ix.netcom.com>

David Ascher wrote:
> 
> On Fri, 5 Jun 1998, Paul F. Dubois wrote:
> 
> > I think array_set does sound like an important function.
> 
> I don't remember the exact specifics of Zane's function.  Something like
> it needs to be incorporated not only in NumPy, but in the *indexing*
> (setitem) mechanism.

Correct. And without any real doubt at the end of several decades of
numerical computing with interpreted array languages.

>  I've done some preliminary work on this, and there
> are a couple of non-trivial issues -- specifically, it'd be nice to be
> able to do:
> 
>    a[a>100] = 100
> 
> as well as a more general form,
> 
>    a[b] = c
> 
> where b contains some description of the indices of a which need to get
> their values from c.

No problem.
 
> Note that a simplistic implementation will act strangely for at least one
> of these under some conditions (since the first index (a>100) corresponds
> (or will, someday) to an array of 1's and 0's.  Replace the RHS of the
> first example with an array, and you have an ambiguity).  There are ways
> around this, which, I believe, localize the complexity to the array
> object.  I've been playing with one way to deal with this, which is
> basically to usurp the tp_call/__call__ slots, just because they were
> there (and because Don Beaudry has, as we know, a twisted mind). Upon
> further reflection, I think that coming up with a specialized new slot
> (for arrays and arraylike instances) is the right thing to do.

Yup.
 
> The nice thing about this approach is that arrays of different species can
> define different ways to do the indexing (thus arrays which correspond to
> logical operations on arrays would "know" that they are masks, whereas
> arrays which are returned by other functions would know that they are
> indices, etc). It also means that one could have a version of NumPy which
> just provides the hooks for this, and various folk can propose specific
> mechanisms (see the old debate on S+ vs.  APL vs. etc. indexing).

Yes, but either one is better than what NumPy currently provides. S
style indexing is better, but in full generality relies on using a nice
representation for unavailable elements.

Aaron Watters knows about seventeen flavors of how to handle
unavailables, but one good way for array computation is the S way.

But if people are going to have a fight over NAs to hang up indexing,
then let's at least get APL style going.
 
> I'd hoped to post about this when I had a proof-of-concept finished.

Tell me about it.

Later,
Andrew Mullhaupt


From aaron@cs.rutgers.edu  Tue Jun  9 22:10:58 1998
From: aaron@cs.rutgers.edu (Aaron Watters)
Date: Tue, 9 Jun 1998 17:10:58 -0400 (EDT)
Subject: [Matrix-SIG] network max-flow interesting examples?
Message-ID: <199806092110.RAA03413@athos.rutgers.edu>

I just posted this to sci.math.num-analysis: thought I might
as well ask the matrix-sig too: Got any good example problems
for network flow optimization? Pointers?

If anyone is interested the alpha code is at
http://athos.rutgers.edu/~aaron/MPM.py
As I say, it's not ready for prime time yet, 
and incidentally doesn't use Numeric (very set/graph
oriented ;) ).  You'd need kjbuckets or kjbuckets0 to run it.

=== post:

Hi there kind generous people!

I think I've implemented the MPM network flow maximization
algorithm described in:

V.M. Malhotra, M. Pramodh-Kumar and S.N. Maheshwari
"An O(V**3) algorithm for finding maximum flows in networks"
Information Processing Letters, 7 (1978), 277-278.

It seems to work great for the stupid tiny examples I get
out of various textbooks, but I'd really like to pound it a
bit more before releasing it.  Where can I get some good
example problems (ala the netlib LP example problems) of
interesting size and difficulty?

Please reply!  thanks.  -- Aaron Watters

"Pay no attention to the man behind the curtain!"


From Paul F. Dubois" <dubois1@llnl.gov  Tue Jun  9 22:19:49 1998
From: Paul F. Dubois" <dubois1@llnl.gov (Paul F. Dubois)
Date: Tue, 9 Jun 1998 14:19:49 -0700
Subject: [Matrix-SIG] Errors in Gist files in LLNLPython2
Message-ID: <001401bd93ec$57520580$52120f80@pduboispc.llnl.gov>

This is a multi-part message in MIME format.

------=_NextPart_000_0011_01BD93B1.A9ACA3C0
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

I accidentally missed the one Python file in the LLNL distribution that used
the routines whose names were changed to bitwise_and, bitwise_or, and
bitwise_xor. File Graphics/OOG/Lib/slice3.py needs all "boolean_and" changed
to "bitwise_and".

The corrected version is attached for you convenience. Since this is
something that one can fix in ten seconds with a text editor I won't make a
new release just to fix it (as I expect to make a new release relatively
soon anyway). I apologize for any inconvenience.

Apparently some previous version of NumPy actually had these functions
working. I think we probably lost them on the "Hinsen change" where the
repairs were made to enable NumPy to be a shared library on more platforms.
If your software like Gist was using them, I just broke your software with
this name change. Since nobody who used these functions evidently upgraded
to the previous NumPy, there can't be too many of you...but my apologies
anyway. I wanted this change in before we wrote a lot of documentation.

The second file is one that Zane had announced a bug fix for, and I thought
he had checked in, but he hadn't. It is Graphics/Gist/Lib/gist.py.

------=_NextPart_000_0011_01BD93B1.A9ACA3C0
Content-Type: application/octet-stream;
	name="slice3.py"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="slice3.py"

# Copyright (c) 1996, 1997, The Regents of the University of California.
# All rights reserved.  See LEGAL.LLNL for full text and disclaimer.

#  SLICE3.PY
# find 2D slices of a 3D hexahedral mesh

#  $Id: slice3.py,v 1.9 1997/11/12 21:51:52 motteler Exp $
#

# Change (ZCM 12/4/96) Apparently _draw3_list, which is global in
# pl3d.py, can be fetched from there, but once this has been done,
# assignments to it over there are not reflected in the copy here.
# This has been fixed by creating an access function.

from Numeric import *
from shapetest import *
from types import *
from pl3d import *
from arrayfns import *
from gistC import *

 #
 # Caveats:
 # (A) Performance is reasonably good, but may still be a factor of
 #     several slower than what could be achieved in compiled code.
 # (B) Only a simple in-memory mesh model is implemented here.
 #     However, hooks are supplied for more interesting possibilities,
 #     such as a large binary file resident mesh data base.
 # (C) There is a conceptual difficulty with _walk3 for the case
 #     of a quad face all four of whose edges are cut by the slicing
 #     plane.  This can only happen when two opposite corners are
 #     above and the other two below the slicing plane.  There are
 #     three possible ways to connect the four intersection points in
 #     two pairs: (1) // (2) \\ and (3) X  There is a severe problem
 #     with (1) and (2) in that a consistent decision must be made
 #     when connecting the points on the two cells which share the
 #     face - that is, each face must carry information on which way
 #     it is triangulated.  For a regular 3D mesh, it is relatively
 #     easy to come up with a consistent scheme for triangulating faces,
 #     but for a general unstructured mesh, each face itself must carry
 #     this information.  This presents a huge challenge for data flow,
 #     which I don't believe is worthwhile.  Because the X choice is
 #     unique, and I don't see why we shouldn't use it here.
 #     For contouring routines, we reject the X choice on esthetic
 #     grounds, and perhaps that will prove to be the case here as
 #     well - but I believe we should try the simple way out first.
 #     In this case, we are going to be filling these polygons with
 #     a color representing a function value in the cell.  Since the
 #     adjacent cells should have nearly the same values, the X-traced
 #     polygons will have nearly the same color, and I doubt there will
 #     be an esthetic problem.  Anyway, the slice3 implemented
 #     below produces the unique X (bowtied) polygons, rather than
 #     attempting to choose between // or \\ (non-bowtied) alternatives.
 #     Besides, in the case of contours, the trivial alternating
 #     triangulation scheme is just as bad esthetically as every
 #     zone triangulated the same way!

def plane3 (normal, point) :
#  plane3(normal, point)
#        or plane3([nx,ny,nz], [px,py,pz])

#    returns [nx,ny,nz,pp] for the specified plane.

   # the normal doesn't really need to be normalized, but this
   # has the desirable side effect of blowing up if normal=3D=3D0
   newnorm =3D zeros (4, Float)
   newnorm [0:3] =3D normal / sqrt (sum (normal*normal))
   newnorm [3] =3D sum (multiply (normal, point))
   return newnorm

_Mesh3Error =3D "Mesh3Error"

def mesh3 (x, y =3D None, z =3D None, ** kw) :
#   mesh3(x,y,z)
#        or mesh3(x,y,z, funcs =3D [f1,f2,...])
#        or mesh3(xyz, funcs =3D [f1,f2,...])
#        or mesh3(nxnynz, dxdydz, x0y0z0, funcs =3D [f1,f2,...])

#    make mesh3 argument for slice3, xyz3, getv3, etc., functions.
#    X, Y, and Z are each 3D coordinate arrays.  The optional F1, F2,
#    etc. are 3D arrays of function values (e.g. density, temperature)
#    which have one less value along each dimension than the coordinate
#    arrays.  The "index" of each zone in the returned mesh3 is
#    the index in these cell-centered Fi arrays, so every index from
#    one through the total number of cells indicates one real cell.
#    The Fi arrays can also have the same dimensions as X, Y, or Z
#    in order to represent point-centered quantities.

#    If X has four dimensions and the length of the first is 3, then
#    it is interpreted as XYZ (which is the quantity actually stored
#    in the returned cell list).

#    If X is a vector of 3 integers, it is interpreted as [nx,ny,nz]
#    of a uniform 3D mesh, and the second and third arguments are
#    [dx,dy,dz] and [x0,y0,z0] respectively.  (DXDYDZ represent the
#    size of the entire mesh, not the size of one cell, and NXNYNZ are
#    the number of cells, not the number of points.)

#    Added by ZCM 1/13/97: if x, y, and z are one-dimensional of
#    the same length and if the keyword verts exists and yields
#    an NCELLS by 8 integer array, then we have an unstructured
#    rectangular mesh, and the subscripts of cell i's vertices
#    are verts[i, 0:8].

#    Added by ZCM 10/10/97: if x, y, and z are one-dimensional
#    of the same length or not, and verts does not exist, then
#    we have a structured reectangular mesh with unequally spaced
#    nodes.

#    other sorts of meshes are possible -- a mesh which lives
#    in a binary file is an obvious example -- which would need
#    different workers for xyz3, getv3, getc3, and iterator3
#    iterator3_rect may be more general than the other three;
#    as long as the cell dimensions are the car of the list
#    which is the 2nd car of m3, it will work=20

   dims =3D shape (x)
   if len (dims) =3D=3D 1 and y !=3D None and len (x) =3D=3D len (y) \
      and z !=3D None and len(x) =3D=3D len (z) and kw.has_key ("verts") =
:
      virtuals =3D [xyz3_irreg, getv3_irreg,
                  getc3_irreg, iterator3_irreg]
      dims =3D kw ["verts"]
      if type (dims) !=3D ListType :
         m3 =3D [virtuals, [dims, array ( [x, y, z])], []]
      else : # Irregular mesh with more than one cell type
         sizes =3D ()
         for nv in dims :
            sizes =3D sizes + (shape (nv) [0],) # no. cells of this type
         totals =3D [sizes [0]]
         for i in range (1, len (sizes)) :
            totals.append (totals [i - 1] + sizes [i]) #total cells so =
far
         m3 =3D [virtuals, [dims, array ( [x, y, z]), sizes, totals], =
[]]
      if kw.has_key ("funcs") :
         funcs =3D kw ["funcs"]
      else :
         funcs =3D []
      i =3D 0
      for f in funcs:
         if len (f) !=3D len (x) and len (f) !=3D shape (dims) [0] :
            # if vertex-centered, f must be same size as x.
            # if zone centered, its length must match number of cells.
            raise _Mesh3Error, "F" + `i` + " is not a viable 3D cell =
value"
         m3 [2] =3D m3 [2] + [f]
         i =3D i + 1
      return m3

   virtuals =3D [xyz3_rect, getv3_rect, getc3_rect, iterator3_rect]
   if len (dims) =3D=3D 4 and dims [0] =3D=3D 3 and min (dims) >=3D 2 :
      xyz =3D x
      dims =3D dims [1:4]
   elif len (dims) =3D=3D 1 and len (x) =3D=3D 3 and type (x [0]) =3D=3D =
IntType \
      and y !=3D None and z !=3D None and len (y) =3D=3D len (z) =3D=3D =
3 :
      xyz =3D array ([y, z])
      dims =3D (1 + x [0], 1 + x [1], 1 + x [2])
      virtuals [0] =3D xyz3_unif
   elif len (dims) =3D=3D 1 and y !=3D None and z !=3D None and len =
(y.shape) =3D=3D 1 \
      and len (z.shape) =3D=3D 1 and x.typecode () =3D=3D y.typecode () =
=3D=3D \
      z.typecode () =3D=3D Float :=20
      # regular mesh with unequally spaced points
      dims =3D array ( [len (x), len (y), len (z)], Int)
      xyz =3D [x, y, z] # has to be a list since could be different =
lengths
      virtuals [0] =3D xyz3_unif
   else :
      if len (dims) !=3D 3 or min (dims) < 2 or \
         y =3D=3D None or len (shape (y)) !=3D 3 or shape (y) !=3D dims =
or \
         z =3D=3D None or len (shape (z)) !=3D 3 or shape (z) !=3D dims:
         raise _Mesh3Error, "X,Y,Z are not viable 3D coordinate mesh =
arrays"
      xyz =3D array ( [x, y, z])
   dim_cell =3D (dims [0] - 1, dims [1] - 1, dims [2] - 1)
   m3 =3D [virtuals, [dim_cell, xyz], []]
   if kw.has_key ("funcs") :
      funcs =3D kw ["funcs"]
   else :
      funcs =3D []
   i =3D 0
   for f in funcs:
      if len (f.shape) =3D=3D 3 and \
         ( (f.shape [0] =3D=3D dims [0] and f.shape [1] =3D=3D dims [1] =
and
            f.shape [2] =3D=3D dims [2]) or (f.shape [0] =3D=3D dim_cell =
[0] and
            f.shape [1] =3D=3D dim_cell [1] and f.shape [2] =3D=3D =
dim_cell [2])) :
         m3 [2] =3D m3 [2] + [f]
         i =3D i + 1
      else :
         raise _Mesh3Error, "F" + `i` + " is not a viable 3D cell value"

   return m3

 # Ways that a list of polygons can be extracted:
 # Basic idea:
 #   (1) At each *vertex* of the cell list, a function value is defined.
 #       This is the "slicing function", perhaps the equation of a =
plane,
 #       perhaps some other vertex-centered function.
 #   (2) The slice3 routine returns a list of cells for which the
 #       function value changes sign -- that is, cells for which some
 #       vertices have positive function values, and some negative.
 #       The function values and vertex coordinates are also returned.
 #   (3) The slice3 routine computes the points along the *edges*
 #       of each cell where the function value is zero (assuming linear
 #       variation along each edge).  These points will be vertices of
 #       the polygons.  The routine also sorts the vertices into cyclic
 #       order.
 #   (4) A "color function" can be used to assign a "color" or other
 #       value to each polygon.  If this function depends only on the
 #       coordinates of the polygon vertices (e.g.- 3D lighting), then
 #       the calculation can be done elsewhere.  There are two other
 #       possibilities:  The color function might be a cell-centered
 #       quantity, or a vertex-centered quantity (like the slicing
 #       function) on the mesh.  In these cases, slice3 already
 #       has done much of the work, since it "knows" cell indices,
 #       edge interpolation coefficients, and the like.
 #
 # There are two particularly important cases:
 # (1) Slicing function is a plane, coloring function is either a
 #     vertex or cell centered mesh function.  Coloring function
 #     might also be a *function* of one or more of the predefined
 #     mesh functions.  If you're eventually going to sweep the whole
 #     mesh, you want to precalculate it, otherwise on-the-fly might
 #     be better.
 # (2) Slicing function is a vertex centered mesh function,
 #     coloring function is 3D shading (deferred).
 #
 # fslice(m3, vertex_list)
 # vertex_list_iterator(m3, vertex_list, mesh3)
 # fcolor(m3, vertex_list, fslice_1, fslice_2)
 #   the coloring function may need the value of fslice at the vertices
 #   in order to compute the color values by interpolation
 # two "edge functions": one to detect edges where sign of fslice =
changes,
 #   second to interpolate for fcolor
 #   second to interpolate for fcolor
 #
 # slice3(m3, fslice, &nverts, &xyzverts, <fcolor>)

_Slice3Error =3D "Slice3Error"


def slice3 (m3, fslice, nverts, xyzverts, * args, ** kw) :
#  slice3 (m3, fslice, nverts, xyzverts)
#        or color_values=3D slice3(m3, fslice, nverts, xyzverts, fcolor)
#        or color_values=3D slice3(m3, fslice, nverts, xyzverts, fcolor, =
1)

#    slice the 3D mesh M3 using the slicing function FSLICE, returning
#    the list [NVERTS, XYZVERTS, color].  Note that it is impossible to
#    pass arguments as addresses, as yorick does in this routine.
#    NVERTS is the number of vertices in each polygon of the slice, and
#    XYZVERTS is the 3-by-sum(NVERTS) list of polygon vertices.  If the
#    FCOLOR argument is present, the values of that coloring function on
#    the polygons are returned as the value of the slice3 function
#    (numberof(color_values) =3D=3D numberof(NVERTS) =3D=3D number of =
polygons).

#    If the slice function FSLICE is a function, it should be of the
#    form:
#       func fslice(m3, chunk)
#    returning a list of function values on the specified chunk of the
#    mesh m3.  The format of chunk depends on the type of m3 mesh, so
#    you should use only the other mesh functions xyz3 and getv3 which
#    take m3 and chunk as arguments.  The return value of fslice should
#    have the same dimensions as the return value of getv3; the return
#    value of xyz3 has an additional first dimension of length 3.
#    N. B. (ZCM 2/24/97) I have eliminated the globals iso_index
#    and _value, so for isosurface_slicer only, the call must be
#    of the form fslice (m3, chunk, iso_index, _value).
#       Likewise, I have eliminated normal and projection, so
#    for plane slicer only, we do fslice (m3, chunk, normal, =
projection).

#    If FSLICE is a list of 4 numbers, it is taken as a slicing plane
#    with the equation FSLICE(+:1:3)*xyz(+)-FSLICE(4), as returned by
#    plane3.

#    If FSLICE is a single integer, the slice will be an isosurface for
#    the FSLICEth variable associated with the mesh M3.  In this case,
#    the keyword value=3D must also be present, representing the value
#    of that variable on the isosurface.

#    If FCOLOR is nil, slice3 returns nil.  If you want to color the
#    polygons in a manner that depends only on their vertex coordinates
#    (e.g.- by a 3D shading calculation), use this mode.

#    If FCOLOR is a function, it should be of the form:
#       func fcolor(m3, cells, l, u, fsl, fsu, ihist)
#    returning a list of function values on the specified cells of the
#    mesh m3.  The cells argument will be the list of cell indices in
#    m3 at which values are to be returned.  l, u, fsl, fsu, and ihist
#    are interpolation coefficients which can be used to interpolate
#    from vertex centered values to the required cell centered values,
#    ignoring the cells argument.  See getc3 source code.
#    The return values should always have dimsof(cells).

#    If FCOLOR is a single integer, the slice will be an isosurface for
#    the FCOLORth variable associated with the mesh M3.

#    If the optional argument after FCOLOR is non-nil and non-zero,
#    then the FCOLOR function is called with only two arguments:
#       func fcolor(m3, cells)

#    The keyword argument NODE, if present and nonzero, is a signal
#       to return node-centered values rather than cell-centered
#       values. (ZCM 4/16/97)


   global _poly_permutations

   iso_index =3D None
   if type (fslice) !=3D FunctionType :
      if not kw.has_key ("value") and not is_scalar (fslice) and \
         len (shape (fslice)) =3D=3D 1 and len (fslice) =3D=3D 4 :
         normal =3D fslice [0:3]
         projection =3D fslice [3]
         fslice =3D _plane_slicer
      elif is_scalar (fslice) and type (fslice) =3D=3D IntType :
         if not kw.has_key ("value") :
            raise _Slice3Error, \
               "value=3D keyword required when FSLICE is mesh variable"
         _value =3D kw ["value"]
         iso_index =3D fslice
         fslice =3D _isosurface_slicer
      else :
         raise _Slice3Error, \
            "illegal form of FSLICE argument, try help,slice3"

   if kw.has_key ("node") :
      node =3D kw ["node"]
   else :
      node =3D 0

   # will need cell list if fcolor function to be computed
   need_clist =3D len (args) > 0
   if len (args) > 1 :
      nointerp =3D args [1]
   else :
      nointerp =3D None

   if need_clist :
      fcolor =3D args [0]
      if fcolor =3D=3D None :
         need_clist =3D 0
   else :
      fcolor =3D None
  =20
   # test the different possibilities for fcolor
   if need_clist and type (fcolor) !=3D FunctionType :
      if not is_scalar (fcolor) or type (fcolor) !=3D IntType :
         raise _Slice3Error, \
            "illegal form of FCOLOR argument, try help,slice3"

   # chunk up the m3 mesh and evaluate the slicing function to
   # find those cells cut by fslice=3D=3D0
   # chunking avoids potentially disastrously large temporaries
   got_xyz =3D 0
   ntotal =3D 0
   # The following are used only for an irregular mesh, to
   # give the sizes of each portion of the mesh.
   ntotal8 =3D 0
   ntotal6 =3D 0
   ntotal5 =3D 0
   ntotal4 =3D 0
   # The following are used only for an irregular mesh, to
   # give the indices of the different types of chunk in the
   # results list.
   i8 =3D []
   i6 =3D []
   i5 =3D []
   i4 =3D []
   itot =3D [i4, i5, i6, i8]
   nchunk =3D 0
   results =3D []
   chunk =3D iterator3 (m3)
   cell_offsets =3D [0, 0, 0, 0]
   while chunk !=3D None :

      # get the values of the slicing function at the vertices of
      # this chunk
      if fslice =3D=3D _isosurface_slicer :
         fs =3D fslice (m3, chunk, iso_index, _value)
         # an isosurface slicer brings back a list [vals, None]
         # where vals is simply an array of the values of the
         # iso_index'th function on the vertices of the specified
         # chunk, or a triple, consisting of the array of
         # values, an array of relative cell numbers in the
         # chunk, and an offset to add to the preceding to
         # get absolute cell numbers.
      elif fslice =3D=3D _plane_slicer :
         fs =3D fslice (m3, chunk, normal, projection)
         # In the case of a plane slice, fs is a list [vals, _xyz3]
         # (or [ [vals, clist, cell_offset], _xyz3] in the irregular =
case)
         # where _xyz3 is the array of vertices of the chunk. _xyz3
         # is ncells by 3 by something (in the irregular case),
         # ncells by 3 by 2 by 2 by 2 in the regular case,
         # and 3 by ni by nj by nk otherwise. vals will be
         # the values of the projections of the corresponding
         # vertex on the normal to the plane, positive if in
         # front, and negative if in back.
      else :
         fs =3D fslice (m3, chunk)
      if node =3D=3D 1 and fcolor !=3D None and fcolor !=3D FunctionType =
:
         # need vertex-centered data
         col =3D getv3 (fcolor, m3, chunk)
         if type (col) =3D=3D ListType :
            col =3D col [0]
      else :
         col =3D None
      # ZCM 2/24/97 Elimination of _xyz3 as a global necessitates the =
following:
      # (_xyz3 comes back as the last element of the list fs)
      _xyz3 =3D fs [1]
      fs =3D fs [0]
      irregular =3D type (fs) =3D=3D ListType
      if irregular :
         cell_offset =3D fs [2]

      # will need cell list if fslice did not compute xyz
      got_xyz =3D _xyz3 !=3D None
      need_clist =3D need_clist or not got_xyz

      # If the m3 mesh is totally unstructured, the chunk should be
      # arranged so that fslice returns an ncells-by-2-by-2-by-2
      # (or ncells-by-3-by-2 or ncells-by-5 or ncells-by-4) array
      # of vertex values of the slicing function. Note that a
      # chunk of an irregular mesh always consists of just one
      # kind of cell.
      # On the other hand, if the mesh vertices are arranged in a
      # rectangular grid (or a few patches of rectangular grids), the
      # chunk should be the far less redundant rectangular patch.
      if (irregular) :
         # fs is a 2-sequence, of which the first element is an =
ncells-by-
         # 2-by-2-by-2 (by-3-by-2, by-5, or by-4) array, and the second
         # is the array of corresponding cell numbers.
         # here is the fastest way to generate the required cell list
         dims =3D shape (fs [0])
         dim1 =3D dims [0]
         slice3_precision =3D 0.0
         if len (dims) =3D=3D 4 : # hex case
            # Note that the sum below will be between 1 and 7
            # precisely if f changes sign in the cell.
            critical_cells =3D bitwise_and (add.reduce \
               (reshape (ravel (transpose (less (fs [0], =
slice3_precision))), \
               (8, dim1))), 7)
            if (sum (critical_cells) !=3D 0) :
               clist =3D take (fs [1], nonzero (critical_cells))
               ntotal8 =3D ntotal8 + len (clist)
            else :
               clist =3D None
            i8.append (len (results))
            cell_offsets [3] =3D cell_offset
         elif len (dims) =3D=3D 3 : # prism case
            # Note that the sum below will be between 1 and 5
            # precisely if f changes sign in the cell.
            critical_cells =3D add.reduce \
               (reshape (ravel (transpose (less (fs [0], =
slice3_precision))), \
               (6, dim1)))
            critical_cells =3D logical_and (greater (critical_cells, 0),
                                         less (critical_cells, 6))
            if (sum (critical_cells) !=3D 0) :
               clist =3D take (fs [1], nonzero (critical_cells))
               ntotal6 =3D ntotal6 + len (clist)
            else :
               clist =3D None
            i6.append (len (results))
            cell_offsets [2] =3D cell_offset
         elif dims [1] =3D=3D 5 : # pyramid case
            # Note that the sum below will be between 1 and 4
            # precisely if f changes sign in the cell.
            critical_cells =3D add.reduce \
               (reshape (ravel (transpose (less (fs [0], =
slice3_precision))), \
               (5, dim1)))
            critical_cells =3D logical_and (greater (critical_cells, 0),
                                         less (critical_cells, 5))
            if (sum (critical_cells) !=3D 0) :
               clist =3D take (fs [1], nonzero (critical_cells))
               ntotal5 =3D ntotal5 + len (clist)
            else :
               clist =3D None
            i5.append (len (results))
            cell_offsets [1] =3D cell_offset
         else : # tet case
            # Note that the sum below will be between 1 and 3
            # precisely if f changes sign in the cell.
            critical_cells =3D bitwise_and (add.reduce \
               (reshape (ravel (transpose (less (fs [0], =
slice3_precision))), \
               (4, dim1))), 3)
            if (sum (critical_cells) !=3D 0) :
               clist =3D take (fs [1], nonzero (critical_cells))
               ntotal4 =3D ntotal4 + len (clist)
            else :
               clist =3D None
            i4.append (len (results))
            cell_offsets [0] =3D cell_offset
      else :
         dims =3D shape (fs)
         # fs is an ni-by-nj-by-nk array
         # result of the zcen is 0, 1/8, 2/8, ..., 7/8, or 1
#        slice3_precision =3D max (ravel (abs (fs))) * (-1.e-12)
         slice3_precision =3D 0
         clist1 =3D ravel (zcen_ (zcen_ (zcen_
            (array (less (fs, slice3_precision), Float), 0), 1), 2))
         clist1 =3D logical_and (less (clist1, .9), greater (clist1, =
.1))
         if sum (clist1) > 0 :
            clist =3D nonzero (clist1)
            ntotal =3D ntotal + len (clist)
         else :
            clist =3D None
         i8.append (len (results)) # Treat regular case as hex

      if clist !=3D None :
         #  we need to save:
         # (1) the absolute cell indices of the cells in clist
         # (2) the corresponding ncells-by-2-by-2-by-2 (by-3-by-2,
         #     by-5, or by-4) list of fslice
         #     values at the vertices of these cells
         if (irregular) :
            # extract the portions of the data indexed by clist
            fs =3D take (fs [0], clist)
            if got_xyz :
               _xyz3 =3D take (_xyz3, clist)
            if col :
               col =3D take (col, clist)
         else :
            # extract the to_corners portions of the data indexed by =
clist
            indices =3D to_corners3 (clist, dims [1], dims [2])
            no_cells =3D shape (indices) [0]
            indices =3D ravel (indices)
            fs =3D reshape (take (ravel (fs), indices),\
               (no_cells, 2, 2, 2))
            if got_xyz :
               new_xyz3 =3D zeros ( (no_cells, 3, 2, 2, 2), Float )
               new_xyz3 [:, 0, ...] =3D reshape (take (ravel (_xyz3 [0, =
...]),\
                  indices), (no_cells, 2, 2, 2))
               new_xyz3 [:, 1, ...] =3D reshape (take (ravel (_xyz3 [1, =
...]),\
                  indices), (no_cells, 2, 2, 2))
               new_xyz3 [:, 2, ...] =3D reshape (take (ravel (_xyz3 [2, =
...]),\
                  indices), (no_cells, 2, 2, 2))
               _xyz3 =3D new_xyz3
               del new_xyz3
            if col !=3D None :
               col =3D reshape (take (ravel (col), indices), (no_cells, =
2, 2, 2))
               # NB: col represents node colors, and is only used
               # if those are requested.
         # here, the iterator converts to absolute cell indices without
         # incrementing the chunk
         if (need_clist) :
            clist =3D iterator3 (m3, chunk, clist)
         else :
            clist =3D None
         nchunk =3D nchunk + 1
         need_vert_col =3D col !=3D None
         results.append ( [clist, fs, _xyz3, col])
      else :
         results.append ( [None, None, None, None])
      chunk =3D iterator3 (m3, chunk)
      # endwhile chunk !=3D None

   # collect the results of the chunking loop
   if not ntotal and not (ntotal8 + ntotal6 + ntotal5 + ntotal4) :
      return None
   if ntotal : # (regular mesh, but can be handled same as hex)
      ntotal8 =3D ntotal
      i8 =3D range (len (results))
      itot [3] =3D i8
   ntot =3D [ntotal4, ntotal5, ntotal6, ntotal8]
   new_results =3D []
   for i in range (len (ntot)) :
      # This loop processes each kind of cell independently,
      # the results to be combined at the end.
      if ntot [i] =3D=3D 0 : # No cells of type i
         continue
      if need_clist :
         clist =3D zeros (ntot [i], Int)
         fs =3D zeros ( (ntot [i], _no_verts [i]), Float )
         if got_xyz :
            xyz =3D zeros ( (ntot [i], 3, _no_verts [i]), Float )
         else :
            xyz =3D None
      if need_vert_col :
         col =3D zeros ( (ntot [i], _no_verts [i]), Float )
      else :
         col =3D None
      k =3D 0

     # collect the results of the chunking loop
      for j in range (len (itot [i])) :
         l =3D k
         k =3D k + len (results [itot [i] [j]] [0])
         if need_clist :
            clist [l:k] =3D results [itot [i] [j]] [0]
         fs [l:k] =3D reshape (results [itot [i] [j]] [1], (k - l, =
_no_verts [i]))
         if xyz !=3D None :
            xyz [l:k] =3D reshape (results [itot [i] [j]] [2],
               (k - l, 3, _no_verts [i]))
         if col !=3D None :
            col [l:k] =3D reshape (results [itot [i] [j]] [3],
               (k - l, _no_verts [i]))
      if not got_xyz :
         # zcm 2/4/97 go to absolute cell list again
         if i > 0 and len (m3 [1]) > 2 :
            adder =3D m3 [1] [3] [i - 1]
         else :
            adder =3D 0
         xyz =3D reshape (xyz3 (m3, clist + adder), (ntot [i], 3, =
_no_verts [i]))
      # produce the lists of edge intersection points
      # -- generate (nsliced)x12 (9, 8, 6) array of edge mask values
      # (mask non-zero if edge is cut by plane)
      below =3D less (fs, 0.0)
      # I put the following into C for speed
      mask =3D find_mask (below, _node_edges [i])
      list =3D nonzero (mask)
      edges =3D array (list, copy =3D 1)
      cells =3D edges / _no_edges [i]
      edges =3D edges % _no_edges [i]
      # construct edge endpoint indices in fs, xyz arrays
      # the numbers are the endpoint indices corresponding to
      # the order of the _no_edges [i] edges in the mask array
      lower =3D take (_lower_vert [i], edges) + _no_verts [i] * cells
      upper =3D take (_upper_vert [i], edges) + _no_verts [i] * cells
      fsl =3D take (ravel (fs), lower)
      fsu =3D take (ravel (fs), upper)
      # following denominator guaranteed non-zero
      denom =3D fsu - fsl
      fsu =3D fsu / denom
      fsl =3D fsl / denom
      new_xyz =3D zeros ( (len (lower), 3), Float )
      new_xyz [:, 0] =3D reshape ( (take (ravel (xyz [:, 0]), lower) * =
fsu - \
         take (ravel (xyz [:, 0]), upper) * fsl), (len (lower),))
      new_xyz [:, 1] =3D reshape ( (take (ravel (xyz [:, 1]), lower) * =
fsu - \
         take (ravel (xyz [:, 1]), upper) * fsl), (len (lower),))
      new_xyz [:, 2] =3D reshape ( (take (ravel (xyz [:, 2]), lower) * =
fsu - \
         take (ravel (xyz [:, 2]), upper) * fsl), (len (lower),))
      xyz =3D new_xyz
      del new_xyz
      if col !=3D None :
         # Extract subset of the data the same way
         col =3D take (ravel (col), lower) * fsu - \
            take (ravel (col), upper) * fsl
      # The xyz array is now the output xyzverts array,
      # but for the order of the points within each cell.

      # give each sliced cell a "pattern index" between 0 and 255
      # (non-inclusive) representing the pattern of its 8 corners
      # above and below the slicing plane
      p2 =3D left_shift (ones (_no_verts [i], Int) , array (
         [0, 1, 2, 3, 4, 5, 6, 7], Int) [0: _no_verts [i]])
      pattern =3D transpose (sum (transpose (multiply (below, p2))))

      # broadcast the cell's pattern onto each of its sliced edges
      pattern =3D take (pattern, list / _no_edges [i])
      # Let ne represent the number of edges of this type of cell,
      # and nv the number of vertices.
      # To each pattern, there corresponds a permutation of the
      # twelve edges so that they occur in the order in which the
      # edges are to be connected.  Let each such permuation be
      # stored as a list of integers from 0 to ne - 1 such that
      # sorting the integers into increasing order rearranges the edges =
at
      # the corresponding indices into the correct order.  (The position
      # of unsliced edges in the list is arbitrary as long as the sliced
      # edges are in the proper order relative to each other.)
      # Let these permutations be stored in a ne-by-2**nv - 2 array
      # _poly_permutations (see next comment for explanation of 4 * ne):
      pattern =3D take (ravel (transpose (_poly_permutations [i])),=20
         _no_edges [i] * (pattern - 1) + edges) + 4 * _no_edges [i] * =
cells
      order =3D argsort (pattern)
      xyz1 =3D zeros ( (len (order), 3), Float )
      xyz1 [:,0] =3D take (ravel (xyz [:,0]), order)
      xyz1 [:,1] =3D take (ravel (xyz [:,1]), order)
      xyz1 [:,2] =3D take (ravel (xyz [:,2]), order)
      xyz =3D xyz1
      if col !=3D None :
         col =3D take (col, order)
      edges =3D take (edges, order)
      pattern =3D take (pattern, order)
      # cells(order) is same as cells by construction */

      # There remains only the question of splitting the points in
      # a single cell into multiple disjoint polygons.
      # To do this, we need one more precomputed array: poly_splits
      # should be another ne-by-2**nv - 2 array with values between 0 =
and 3
      # 0 for each edge on the first part, 1 for each edge on the
      # second part, and so on up to 3 for each edge on the fourth
      # part.  The value on unsliced edges can be anything, say 0.
      # With a little cleverness poly_splits can be combined with
      # _poly_permutations, by putting _poly_permutations =3D
      # _poly_permutations(as described above) + _no_edges =
[i]*poly_splits
      # (this doesn't change the ordering of _poly_permutations).
      # I assume this has been done here:
      pattern =3D pattern / _no_edges [i]
      # now pattern jumps by 4 between cells, smaller jumps within cells
      # get the list of places where a new value begins, and form a
      # new pattern with values that increment by 1 between each plateau
      pattern =3D dif_ (pattern, 0)
      nz =3D nonzero (pattern)
      list =3D zeros (len (nz) + 1, Int)
      list [1:] =3D nz + 1
      newpat =3D zeros (len (pattern) + 1, Int)
      newpat [0] =3D 1
      newpat [1:] =3D cumsum (not_equal (pattern, 0)) + 1
      pattern =3D newpat
      nverts =3D histogram (pattern) [1:]
      xyzverts =3D xyz

      # finally, deal with any fcolor function
      if fcolor =3D=3D None :
         new_results.append ( [nverts, xyzverts, None])
         continue

      # if some polys have been split, need to split clist as well
      if len (list) > len (clist) :
         clist =3D take (clist, take (cells, list))
      if col =3D=3D None :
         if nointerp =3D=3D None :
            if type (fcolor) =3D=3D FunctionType :
               col =3D fcolor (m3, clist + cell_offsets [i], lower, =
upper, fsl,
                  fsu, pattern - 1)
            else :
               col =3D getc3 (fcolor, m3, clist + cell_offsets [i], =
lower, upper,
                  fsl, fsu, pattern - 1)
         else :
            if type (fcolor) =3D=3D FunctionType :
               col =3D fcolor (m3, clist + cell_offsets [i])
            else :
               col =3D getc3 (fcolor, m3, clist + cell_offsets [i])
      new_results.append ( [nverts, xyzverts, col])
   # New loop to consolidate the return values
   nv_n =3D 0
   xyzv_n =3D 0
   col_n =3D 0
   for i in range (len (new_results)) :
      nv_n =3D nv_n + len (new_results [i] [0])
      xyzv_n =3D xyzv_n + shape (new_results [i] [1]) [0]
      if new_results [i] [2] !=3D None :
         col_n =3D col_n + len (new_results [i] [2])
   nverts =3D zeros (nv_n, Int)
   xyzverts =3D zeros ( (xyzv_n, 3), Float )
   if col_n !=3D 0 :
      col =3D zeros (col_n, Float )
   else :
      col =3D None
   nv_n1 =3D 0
   xyzv_n1 =3D 0
   col_n1 =3D 0
   for i in range (len (new_results)) :
      nv_n2 =3D len (new_results [i] [0])
      xyzv_n2 =3D shape (new_results [i] [1]) [0]
      nverts [nv_n1:nv_n1 + nv_n2] =3D new_results [i] [0]
      xyzverts [xyzv_n1:xyzv_n1 + xyzv_n2] =3D new_results [i] [1]
      if new_results [i] [2] !=3D None :
         col_n2 =3D len (new_results [i] [2])
         col [col_n1:col_n1 + col_n2] =3D new_results [i] [2]
         col_n1 =3D col_n1 + col_n2
      nv_n1 =3D nv_n1 + nv_n2
      xyzv_n1 =3D xyzv_n1 + xyzv_n2
   return [nverts, xyzverts, col]

 # The iterator3 function combines three distinct operations:
 # (1) If only the M3 argument is given, return the initial
 #     chunk of the mesh.  The chunk will be no more than
 #     _chunk3_limit cells of the mesh.
 # (2) If only M3 and CHUNK are given, return the next CHUNK,
 #     or [] if there are no more chunks.
 # (3) If M3, CHUNK, and CLIST are all specified, return the
 #     absolute cell index list corresponding to the index list
 #     CLIST of the cells in the CHUNK.
 #     Do not increment the chunk in this case.
 #
 # The form of the CHUNK argument and return value for cases (1)
 # and (2) is not specified, but it must be recognized by the
 # xyz3 and getv3 functions which go along with this iterator3.
 # (For case (3), CLIST and the return value are both ordinary
 #  index lists.)

_Slice3MeshError =3D "Slice3MeshError"

def slice3mesh (xyz, * args, ** kw) :
   # slice3mesh (z, color =3D None, smooth =3D 0)
   # slice3mesh (nxny, dxdy, x0y0, z, color =3D None, smooth =3D 0)
   # slice3mesh (x, y, z, color =3D None, smooth =3D 0)
   #
   # slice3mesh returns a triple [nverts, xyzverts, color]
   #  nverts is no_cells long and the ith entry tells how many
   #     vertices the ith cell has.
   #  xyzverts is sum (nverts) by 3 and gives the vertex
   #     coordinates of the cells in order.
   #  color, if present, is len (nverts) long and contains
   #     a color value for each cell in the mesh if smooth =3D=3D 0;
   #     sum (nverts) long and contains a color value for each
   #     node in the mesh if smooth =3D=3D 1.
   # There are a number of ways to call slice3mesh:
   #    slice3mesh (z, color =3D None, smooth =3D 0)
   # z is a two dimensional array of function values, assumed
   # to be on a uniform mesh nx by ny nodes (assuming z is nx by ny)
   # nx being the number of nodes in the x direction, ny the number
   # in the y direction.
   # color, if specified, is either an nx - 1 by ny - 1 array
   # of cell-centered values by which the surface is to
   # be colored, or an nx by ny array of vertex-
   # centered values, which will be averaged over each
   # cell to give cell-centered values if smooth =3D=3D 0, or
   # returned as a node-centered array sum (nverts) long if
   # smooth =3D=3D 1.
   #    slice3mesh (nxny, dxdy, x0y0, z, color =3D None, smooth =3D 0)
   # In this case, slice3mesh accepts the specification for
   # a regular 2d mesh: nxny is the number of cells in the
   # x direction and the y direction (i. e., its two components
   # are nx - 1 and ny - 1, nx by ny being the node size;
   # x0y0 are the initial
   # values of x and y; and dxdy are the increments in the
   # two directions. z is the height of a surface above
   # the xy plane and must be dimensioned nx by ny.=20
   # color, if specified, is as above.
   #   slice3mesh (x, y, z, color =3D None, smooth =3D 0)
   # z is as above, an nx by ny array of function values
   # on a mesh of the same dimensions. There are two choices
   # for x and y: they can both be one-dimensional, dimensioned
   # nx and ny respectively, in which case they represent a
   # mesh whose edges are parallel to the axes; or else they
   # can both be nx by ny, in which case they represent a
   # general quadrilateral mesh.
   # color, if specified, is as above.
   two_d =3D 0
   if kw.has_key ("smooth") :
      smooth =3D kw ["smooth"]
   else :
      smooth =3D 0
   if len (args) =3D=3D 0 :
      # Only the z argument is present
      if len (shape (xyz)) !=3D 2 :
         raise _Slice3MeshError, \
            "z must be two dimensional."
      else :
         z =3D xyz
         ncx =3D shape (xyz) [0]
         ncy =3D shape (xyz) [1]
         x =3D arange (ncx, typecode =3D Float )
         y =3D arange (ncy, typecode =3D Float )
   elif len (args) =3D=3D 3 :
      # must be the (nxny, dxdy, x0y0, z...) form
      ncx =3D xyz [0] + 1
      ncy =3D xyz [1] + 1
      x =3D arange (ncx, typecode =3D Float ) * args [0] [0] + args [1] =
[0]
      y =3D arange (ncy, typecode =3D Float ) * args [0] [1] + args [1] =
[1]
      z =3D args [2]
      if (ncx, ncy) !=3D shape (z) :
         raise _Slice3MeshError, \
            "The shape of z must match the shape of x and y."
   elif len (args) =3D=3D 2 :
      # must be the x, y, z format
      x =3D xyz
      y =3D args [0]
      z =3D args [1]
      dims =3D shape (x)
      if len (dims) =3D=3D 2 :
         two_d =3D 1
         if dims !=3D shape (y) or dims !=3D shape (z) :
            raise _Slice3MeshError, \
               "The shapes of x, y, and z must match."
         ncx =3D dims [0]
         ncy =3D dims [1]
      elif len (dims) =3D=3D 1 :
         ncx =3D dims [0]
         ncy =3D len (y)
         if (ncx, ncy) !=3D shape (z) :
            raise _Slice3MeshError, \
               "The shape of z must match the shape of x and y."
      else :
         raise _Slice3MeshError, \
            "Unable to decipher arguments to slice3mesh."
   else :
      raise _Slice3MeshError, \
         "Unable to decipher arguments to slice3mesh."

   nverts =3D ones ( (ncx - 1) *  (ncy - 1), Int) * 4

   ncxx =3D arange (ncx - 1, typecode =3D Int) * (ncy)
   ncyy =3D arange (ncy - 1, typecode =3D Int)

   if kw.has_key ("color") :
      color =3D kw ["color"]
   else :
      color =3D None
   if color !=3D None :
#     col =3D array (len (nverts), Float )
      if shape (color) =3D=3D (ncx - 1, ncy - 1) :
         col =3D color
      elif shape (color) =3D=3D (ncx, ncy) and smooth =3D=3D 0 :
         col =3D ravel (color)
         # Lower left, upper left, upper right, lower right
         col =3D 0.25 * (take (col, ravel (add.outer ( ncxx, ncyy))) +
            take (col, ravel (add.outer ( ncxx, ncyy + 1))) +
            take (col, ravel (add.outer ( ncxx + ncy, ncyy + 1))) +
            take (col, ravel (add.outer ( ncxx + ncy, ncyy))))
      elif shape (color) =3D=3D (ncx, ncy) and smooth !=3D 0 :
         # Node-centered colors are wanted (smooth plots)
         col =3D ravel (color)
         col =3D ravel (transpose (array ( [
            take (col, ravel (add.outer ( ncxx, ncyy))),
            take (col, ravel (add.outer ( ncxx, ncyy + 1))),
            take (col, ravel (add.outer ( ncxx + ncy, ncyy + 1))),
            take (col, ravel (add.outer ( ncxx + ncy, ncyy)))])))
      else :
         raise _Slice3MeshError, \
            "color must be cell-centered or vertex centered."
   else :
      col =3D None
   xyzverts =3D zeros ( (4 * (ncx -1) * (ncy -1), 3), Float )

   if not two_d :
      x1 =3D multiply.outer (ones (ncy - 1, Float), x [0:ncx - 1])
      x2 =3D multiply.outer (ones (ncy - 1, Float), x [1:ncx])
      xyzverts [:, 0] =3D ravel (transpose (array ([x1, x1, x2, x2])))
      del x1, x2
      y1 =3D multiply.outer (y [0:ncy - 1], ones (ncx - 1))
      y2 =3D multiply.outer (y [1:ncy], ones (ncx - 1))
      xyzverts [:, 1] =3D ravel (transpose (array ([y1, y2, y2, y1])))
      del y1, y2
   else :
      newx =3D ravel (x)
      xyzverts [:, 0] =3D ravel (transpose (array ( [
         take (newx, ravel (add.outer ( ncxx, ncyy))),
         take (newx, ravel (add.outer ( ncxx, ncyy + 1))),
         take (newx, ravel (add.outer ( ncxx + ncy, ncyy + 1))),
         take (newx, ravel (add.outer ( ncxx + ncy, ncyy)))])))
      newy =3D ravel (y)
      xyzverts [:, 1] =3D ravel (transpose (array ( [
         take (newy, ravel (add.outer ( ncxx, ncyy))),
         take (newy, ravel (add.outer ( ncxx, ncyy + 1))),
         take (newy, ravel (add.outer ( ncxx + ncy, ncyy + 1))),
         take (newy, ravel (add.outer ( ncxx + ncy, ncyy)))])))
   newz =3D ravel (z)
   xyzverts [:, 2] =3D ravel (transpose (array ( [
      take (newz, ravel (add.outer ( ncxx, ncyy))),
      take (newz, ravel (add.outer ( ncxx, ncyy + 1))),
      take (newz, ravel (add.outer ( ncxx + ncy, ncyy + 1))),
      take (newz, ravel (add.outer ( ncxx + ncy, ncyy)))])))
     =20
   return [nverts, xyzverts, col]
  =20
def iterator3 (m3 , chunk =3D None, clist =3D None) :
   return m3 [0] [3] (m3, chunk, clist)

# biggest temporary is 3 doubles times this,
# perhaps 4 or 5 doubles times this is most at one time
_chunk3_limit =3D 10000

def iterator3_rect (m3, chunk, clist) :

#  Note: if you look at the yorick version of this routine, you
#  will see that the significance of the subscripts is reversed.
#  This is because we do things in row-major order.

   global _chunk3_limit
  =20
   if chunk =3D=3D None :
      dims =3D m3 [1] [0]      # [ni,nj,nk] cell dimensions
      [ni, nj, nk] =3D [dims [0], dims [1], dims [2]]
      njnk =3D nj * nk
      if _chunk3_limit <=3D nk :
         # stuck with 1D chunks
         ck =3D (nk - 1) / _chunk3_limit + 1
         cj =3D ci =3D 0
      elif _chunk3_limit <=3D njnk :
         # 2D chunks
         ci =3D ck =3D 0
         cj =3D (njnk - 1) / _chunk3_limit + 1
      else :
         # 3D chunks
         cj =3D ck =3D 0
         ci =3D (njnk * ni - 1) / _chunk3_limit + 1
      chunk =3D array ( [[ci =3D=3D 0, cj =3D=3D 0, ck =3D=3D 0],
                       [not ci, nj * (ci !=3D 0) + (ck !=3D 0),
                        nk * ( (cj + ci) !=3D 0)],
                       [ci, cj, ck], [ni, nj, nk]])
   else :
      ni =3D chunk [3,0]
      nj =3D chunk [3,1]
      nk =3D chunk [3,2]
      njnk =3D nj * nk
      offsets =3D array ( [njnk, nj, 1], Int)
      if clist !=3D None :
         # add offset for this chunk to clist and return
         return sum (offsets * ( chunk [0] - 1)) + clist

   # increment to next chunk
   xi =3D chunk [1, 0]
   xj =3D chunk [1, 1]
   xk =3D chunk [1, 2]

   np =3D chunk [2, 2]
   if (np) :
      # 1D chunks
      if xk =3D=3D nk :
         if xj =3D=3D nj :
            if xi =3D=3D ni : return None
            xi =3D xi + 1
            xj =3D 1;
         else :
            xj =3D xj + 1
         xk =3D 0
      ck =3D xk + 1
      step =3D ck / np=20
      frst =3D ck % np     # first frst steps are step+1
      if (xk < (step + 1) * frst) : step =3D step + 1
      xk =3D xk + step
      chunk [0] =3D array ( [xi, xj, ck])
      chunk [1] =3D array ( [xi, xj, xk])
   else :
      np =3D chunk [2, 1]
      if (np) :
         if (xj =3D=3D nj) :
            if (xi =3D=3D ni) : return None
            xi =3D xi + 1
            xj =3D 0
         cj =3D xj + 1
         step =3D nj / np
         frst =3D nj % np    # first frst steps are step+1
         if (xj < (step + 1) * frst) : step =3D step + 1
         xj =3D xj + step
         chunk [0, 0:2] =3D array ( [xi, cj])
         chunk [1, 0:2] =3D array ( [xi, xj])
      else :
         if xi =3D=3D ni : return None
         ci =3D xi + 1
         np =3D chunk [2, 0]
         step =3D ni / np
         frst =3D ni % np    # first frst steps are step+1
         if (xi < (step + 1) * frst) : step =3D step + 1
         xi =3D xi + step
         chunk [0, 0] =3D ci
         chunk [1, 0] =3D xi
   return chunk

def iterator3_irreg (m3, chunk, clist) :
#  Does the same thing as iterator3_rect only for an irregular
#  rectangular mesh. It simply splits a large mesh into smaller
#  parts. Whether this is necessary I am not sure.
#  Certainly it makes it easier in the irregular case to handle
#  the four different types of cells separately.
#  if clist is present, in the irregular case it is already
#  the list of absolute cell indices, so it is simply returned.
#  This and other routines to do with irregular meshes return a
#  chunk which is a 2-list. The first item delimits the chunk;
#  the second gives a list of corresponding cell numbers.

   global _chunk3_limit

   if clist !=3D None:
      return clist

   dims =3D m3 [1] [0]     # ncells by _no_verts array of subscripts
                         # (or a list of from one to four of same)

   if type (dims) !=3D ListType :
      if chunk =3D=3D None:     # get the first chunk
         return [ [0, min (shape (dims) [0], _chunk3_limit)],
                  arange (0, min (shape (dims) [0], _chunk3_limit),
                  typecode =3D Int)]
      else :                # iterate to next chunk
         start =3D chunk [0] [1]
         if start >=3D shape(dims) [0] :
            return None
         else :
            return [ [start, min (shape (dims) [0], start + =
_chunk3_limit)],
                     arange (start, min (shape (dims) [0],
                                               start + _chunk3_limit),
                     typecode =3D Int)]
   else :
      totals =3D m3 [1] [3] # cumulative totals of numbers of cells
      if chunk =3D=3D None :
         return [ [0, min (totals [0], _chunk3_limit)],
                  arange (0, min (totals [0], _chunk3_limit),
                  typecode =3D Int)]
      else :                # iterate to next chunk
         start =3D chunk [0] [1]
         if start >=3D totals [-1] :
            return None
         else :
            for i in range (len (totals)) :
               if start < totals [i] :
                  break
            return [ [start, min (totals [i], start + _chunk3_limit)],
                     arange (start,
                        min (totals [i], start + _chunk3_limit),=20
                        typecode =3D Int)]


def getv3 (i, m3, chunk) :
#  getv3(i, m3, chunk)

#    return vertex values of the Ith function attached to 3D mesh M3
#    for cells in the specified CHUNK.  The CHUNK may be a list of
#    cell indices, in which case getv3 returns a 2x2x2x(dimsof(CHUNK))
#    list of vertex coordinates.  CHUNK may also be a mesh-specific data
#    structure used in the slice3 routine, in which case getv3 may
#    return a (ni)x(nj)x(nk) array of vertex values.  For meshes which
#    are logically rectangular or consist of several rectangular
#    patches, this is up to 8 times less data, with a concomitant
#    performance advantage.  Use getv3 when writing slicing functions
#    for slice3.

   return m3 [0] [1] (i, m3, chunk)

_Getv3Error =3D "Getv3Error"

def getv3_rect (i, m3, chunk) :
   fi =3D m3 [2]
   i =3D i - 1
   if i < 0 or is_scalar (fi) or i >=3D len (fi) :
      raise _Getv3Error, "no such mesh function as F" + `i`
   dims =3D m3 [1] [0]
   if dims =3D=3D shape (fi [i]) :
      raise _Getv3Error, "mesh function F" + `i` + " is not =
vertex-centered"
   if len (shape (chunk)) !=3D 1 :
      c =3D chunk
      # The difference here is that our arrays are 0-based, while
      # yorick's are 1-based; and the last element in a range is not
      # included in the result array.
      return fi [i] [c [0, 0] - 1:1 + c [1, 0], c [0, 1] - 1:1 + c [1, =
1] ,
                     c [0, 2] - 1:1 + c [1, 2]]
   else :
      # Need to create an array of fi values the same size and shape
      # as what to_corners3 returns.
      # To avoid exceedingly arcane calculations attempting to
      # go backwards to a cell list, this branch returns the list
      # [<function values>, chunk]
      # Then it is trivial for slice3 to find a list of cell
      # numbers in which fi changes sign.
      indices =3D to_corners3 (chunk, dims [0] + 1, dims [1] + 1)
      no_cells =3D shape (indices) [0]
      indices =3D ravel (indices)
      retval =3D reshape (take (ravel (fi [i]), indices), (no_cells, 2, =
2, 2))

      return [retval, chunk]

def getv3_irreg (i, m3, chunk) :
#  for an irregular mesh, returns a 3-list whose elements are:
#  (1) the function values for the ith function on the vertices of the
#  given chunk. (The function values must have the same dimension
#  as the coordinates; there is no attempt to convert zone-centered
#  values to vertex-centered values.)
#  (2) an array of relative cell numbers within the list of cells
#  of this type.
#  (3) a number that can be added to these relative numbers to gives
#  the absolute cell numbers for correct access to their coordinates
#  and function values.
  =20
   fi =3D m3 [2]
   i =3D i - 1
   if i < 0 or is_scalar (fi) or i >=3D len (fi) :
      raise _Getv3Error, "no such function as F" + `i`
   # len (fi [i]) and the second dimension of m3 [1] [1] (xyz) should
   # be the same, i. e., there is a value associated with each =
coordinate.
   if len (fi [i]) !=3D len (m3 [1] [1] [0]) :
      raise _Getv3Error, "mesh function F" + `i` + " is not =
vertex-centered."

   verts =3D m3 [1] [0]
   oldstart =3D chunk [0] [0]
   oldfin =3D chunk [0] [1]
   no_cells =3D oldfin - oldstart

   if type (verts) !=3D ListType : # Only one kind of cell in mesh
      indices =3D ravel (verts [oldstart:oldfin])
   else : # A list of possibly more than one kind
      sizes =3D m3 [1] [2]
      totals =3D m3 [1] [3]
      for j in range (len (totals)) :
         if oldfin <=3D totals [j] :
            break
      verts =3D verts [j]
      if j > 0 :
         start =3D oldstart - totals [j - 1]
         fin =3D oldfin - totals [j - 1]
      else :
         start =3D oldstart=20
         fin =3D oldfin
      indices =3D ravel (verts [start:fin])

   tc =3D shape (verts) [1]
   # ZCM 2/4/97 the array of cell numbers must be relative
   if tc =3D=3D 8 : # hex cells
      return [ reshape (take (fi [i], indices), (no_cells, 2, 2, 2)),
              arange (0, no_cells, typecode =3D Int), oldstart]
   elif tc =3D=3D 6 : # pyramids
      return [ reshape (take (fi [i], indices), (no_cells, 3, 2)),
              arange (0, no_cells, typecode =3D Int), oldstart]
   else : # tetrahedron or pyramid
      return [ reshape (take (fi [i], indices), (no_cells, tc)),
              arange (0, no_cells, typecode =3D Int), oldstart]

_Getc3Error =3D "Getc3Error"

def getc3 (i, m3, chunk, *args) :
#  getc3(i, m3, chunk)
#        or getc3(i, m3, clist, l, u, fsl, fsu, cells)

#    return cell values of the Ith function attached to 3D mesh M3
#    for cells in the specified CHUNK.  The CHUNK may be a list of
#    cell indices, in which case getc3 returns a (dimsof(CHUNK))
#    list of vertex coordinates.  CHUNK may also be a mesh-specific data
#    structure used in the slice3 routine, in which case getc3 may
#    return a (ni)x(nj)x(nk) array of vertex values.  There is no
#    savings in the amount of data for such a CHUNK, but the gather
#    operation is cheaper than a general list of cell indices.
#    Use getc3 when writing colorng functions for slice3.

#    If CHUNK is a CLIST, the additional arguments L, U, FSL, and FSU
#    are vertex index lists which override the CLIST if the Ith attached
#    function is defined on mesh vertices.  L and U are index lists into
#    the (dimsof(CLIST))x2x2x2 vertex value array, say vva, and FSL
#    and FSU are corresponding interpolation coefficients; the zone
#    centered value is computed as a weighted average of involving these
#    coefficients.  The CELLS argument is required by histogram to do
#    the averaging.  See the source code for details.
#    By default, this conversion (if necessary) is done by averaging
#    the eight vertex-centered values.

   if len (args) =3D=3D 0 :
      l =3D None
      u =3D None
      fsl =3D None
      fsu =3D None
      cells =3D None
   elif len (args) =3D=3D 5 :
      l =3D args [0]
      u =3D args [1]
      fsl =3D args [2]
      fsu =3D args [3]
      cells =3D args [4]
   else :
      raise _Getc3Error, "getc3 requires either three or eight =
parameters."

   return m3 [0] [2] (i, m3, chunk, l, u, fsl, fsu, cells)

def getc3_rect (i, m3, chunk, l, u, fsl, fsu, cells) :
   fi =3D m3 [2]
   m3 =3D m3 [1]
   if ( i < 1 or i > len (fi)) :
      raise _Getc3Error, "no such mesh function as F" + `i - 1`
   dims =3D m3 [0]
   if shape (fi [i - 1]) =3D=3D dims :
      # it is a cell-centered quantity
      if len (shape (chunk)) !=3D 1 :
         c =3D chunk
         # The difference here is that our arrays are 0-based, while
         # yorick's are 1-based; and the last element in a range is not
         # included in the result array.
         return fi [i - 1] [c [0, 0] - 1:1 + c [1, 0],
                            c [0, 1] - 1:1 + c [1, 1] ,
                            c [0, 2] - 1:1 + c [1, 2]]
      else :
         [k, l. m] =3D dims
         return reshape (take (ravel (fi [i - 1]), chunk),
            (len (chunk), k, l, m))
   else :
      # it is vertex-centered, so we take averages to get cell quantity
      if len (shape (chunk)) !=3D 1 :
         c =3D chunk
         # The difference here is that our arrays are 0-based, while
         # yorick's are 1-based; and the last element in a range is not
         # included in the result array.
         return zcen_ (zcen_( zcen_ (
               (fi [i - 1] [c [0, 0] - 1:1 + c [1, 0],
                            c [0, 1] - 1:1 + c [1, 1] ,
                            c [0, 2] - 1:1 + c [1, 2]]), 0), 1), 2)
      else :
         indices =3D to_corners3 (chunk, dims [1] + 1,  dims [2] + 1)
         no_cells =3D shape (indices) [0]
         indices =3D ravel (indices)
         corners =3D take (ravel (fi [i - 1]), indices)
         if l =3D=3D None :
            return 0.125 * sum (transpose (reshape (corners, (no_cells, =
8))))
         else :
            # interpolate corner values to get edge values
            corners =3D (take (corners, l) * fsu -
               take (corners, u) * fsl) / (fsu -fsl)
            # average edge values (vertex values of polys) on each poly
            return histogram (cells, corners) / histogram (cells)

def getc3_irreg (i, m3, chunk, l, u, fsl, fsu, cells) :
#  Same thing as getc3_rect, i. e., returns the same type of
#  data structure, but from an irregular rectangular mesh.
#     m3 [1] is a 2-list; m3[1] [0] is an array whose ith element
#        is an array of coordinate indices for the ith cell,
#        or a list of up to four such arrays.
#        m3 [1] [1] is the 3 by nverts array of coordinates.
#     m3 [2] is a list of arrays of vertex-centered or cell-centered
#        data.
#  chunk may be a list, in which case chunk [0] is a 2-sequence
#     representing a range of cell indices; or it may be a =
one-dimensional
#     array, in which case it is a nonconsecutive set of cell indices.
#     It is guaranteed that all cells indexed by the chunk are the
#     same type.

   fi =3D m3 [2]
   if i < 1 or i > len (fi) :
      raise _Getc3Error, "no such mesh function as F" + `i - 1`
   verts =3D m3 [1] [0]
   if type (verts) =3D=3D ListType :
      sizes =3D m3 [1] [2]
      totals =3D m3 [1] [3]
   if type (verts) =3D=3D ListType and totals [-1] =3D=3D len (fi [i - =
1]) or \
      type (verts) !=3D ListType and shape (verts) [0] =3D=3D len (fi [i =
- 1]) :
      # cell-centered case
      if type (chunk) =3D=3D ListType :
         return fi [i - 1] [chunk [0] [0]:chunk [0] [1]]
      elif type (chunk) =3D=3D ArrayType and len (shape (chunk)) =3D=3D =
1 :
         return take (fi [i - 1], chunk)
      else :
         raise _Getc3Error, "chunk argument is incomprehensible."

   if len (fi [i - 1]) !=3D shape (m3 [1] [1]) [1] :
      raise _Getc3Error, "F" + `i - 1` + " has the wrong size to be " \
         "either zone-centered or node-centered."
   # vertex-centered case
   # First we need to pick up the vertex subscripts, which are
   # also the fi [i - 1] subscripts.
   if type (verts) !=3D ListType :
      if type (chunk) =3D=3D ListType :
         indices =3D verts [chunk [0] [0]:chunk [0] [1]]
      elif type (chunk) =3D=3D ArrayType and len (shape (chunk)) =3D=3D =
1 :
         indices =3D take (verts, chunk)
      else :
         raise _Getc3Error, "chunk argument is incomprehensible."
   else :
      # We have a list of vertex subscripts, each for a different
      # type of cell; need to extract the correct list:
      if type (chunk) =3D=3D ListType :
         start =3D chunk [0] [0]
         fin =3D chunk [0] [1]
         for j in range (len (totals)) :
            if fin <=3D totals [j] :
               break
         verts =3D verts [j]
         if j > 0 :
            start =3D start - totals [j - 1]
            fin =3D fin - totals [j - 1]
         indices =3D verts [start:fin]
      elif type (chunk) =3D=3D ArrayType and len (shape (chunk)) =3D=3D =
1 :
         for j in range (len (totals)) :
            if chunk [-1] <=3D totals [j] :
               break
         verts =3D verts [j]
         ch =3D chunk
         if j > 0 :
            ch =3D chunk - totals [j - 1]
         indices =3D take (verts, ch)
      else :
         raise _Getc3Error, "chunk argument is incomprehensible."

   shp =3D shape (indices)
   no_cells =3D shp [0]
   indices =3D ravel (indices)
   corners =3D take (fi [i - 1], indices)
   if l =3D=3D None :
      return (1. / shp [1]) * transpose ((sum (transpose (reshape =
(corners,
         (no_cells, shp [1]))) [0:shp [1]])))
   else :
      # interpolate corner values to get edge values
      corners =3D (take (corners, l) * fsu -
         take (corners, u) * fsl) / (fsu -fsl)
      # average edge values (vertex values of polys) on each poly
      return histogram (cells, corners) / histogram (cells)

_no_verts =3D array ( [4, 5, 6, 8])
_no_edges =3D array ( [6, 8, 9, 12])

# Lower and upper vertex subscripts for each edge
_lower_vert4 =3D array ( [0, 0, 0, 1, 2, 3], Int)
_lower_vert5 =3D array ( [0, 0, 0, 0, 1, 2, 3, 4], Int)
_lower_vert6 =3D array ( [0, 1, 0, 1, 2, 3, 0, 2, 4], Int)
_lower_vert8 =3D array ( [0, 1, 2, 3, 0, 1, 4, 5, 0, 2, 4, 6], Int)
_lower_vert =3D [_lower_vert4, _lower_vert5, _lower_vert6, _lower_vert8]
_upper_vert4 =3D array ( [1, 2, 3, 2, 3, 1], Int)
_upper_vert5 =3D array ( [1, 2, 3, 4, 2, 3, 4, 1], Int)
_upper_vert6 =3D array ( [4, 5, 2, 3, 4, 5, 1, 3, 5], Int)
_upper_vert8 =3D array ( [4, 5, 6, 7, 2, 3, 6, 7, 1, 3, 5, 7], Int)
_upper_vert =3D [_upper_vert4, _upper_vert5, _upper_vert6, _upper_vert8]

_node_edges8_s =3D array ( [ [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
                        [0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
                        [0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0],
                        [0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0],
                        [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0],
                        [0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0],
                        [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1],
                        [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]], Int)
_node_edges8 =3D array ( [ [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1],
                        [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1],
                        [0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0],
                        [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0],
                        [0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0],
                        [0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0],
                        [0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
                        [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]], Int)
_node_edges6_s =3D array ( [ [1, 0, 1, 0, 0, 0, 1, 0, 0],
                        [0, 1, 0, 1, 0, 0, 1, 0, 0],
                        [0, 0, 1, 0, 1, 0, 0, 1, 0],
                        [0, 0, 0, 1, 0, 1, 0, 1, 0],
                        [1, 0, 0, 0, 1, 0, 0, 0, 1],
                        [0, 1, 0, 0, 0, 1, 0, 0, 1]], Int)
_node_edges6 =3D array ( [ [0, 1, 0, 0, 0, 1, 0, 0, 1],
                        [1, 0, 0, 0, 1, 0, 0, 0, 1],
                        [0, 0, 0, 1, 0, 1, 0, 1, 0],
                        [0, 0, 1, 0, 1, 0, 0, 1, 0],
                        [0, 1, 0, 1, 0, 0, 1, 0, 0],
                        [1, 0, 1, 0, 0, 0, 1, 0, 0]], Int)
_node_edges4_s =3D array ( [ [1, 1, 1, 0, 0, 0],
                        [1, 0, 0, 1, 0, 1],
                        [0, 1, 0, 1, 1, 0],
                        [0, 0, 1, 0, 1, 1]], Int)
_node_edges4 =3D array ( [ [0, 0, 1, 0, 1, 1],
                        [0, 1, 0, 1, 1, 0],
                        [1, 0, 0, 1, 0, 1],
                        [1, 1, 1, 0, 0, 0]], Int)
_node_edges5_s =3D array ( [ [1, 1, 1, 1, 0, 0, 0, 0],
                        [1, 0, 0, 0, 1, 0, 0, 1],
                        [0, 1, 0, 0, 1, 1, 0, 0],
                        [0, 0, 1, 0, 0, 1, 1, 0],
                        [0, 0, 0, 1, 0, 0, 1, 1]], Int)
_node_edges5 =3D array ( [ [0, 0, 0, 1, 0, 0, 1, 1],
                        [0, 0, 1, 0, 0, 1, 1, 0],
                        [0, 1, 0, 0, 1, 1, 0, 0],
                        [1, 0, 0, 0, 1, 0, 0, 1],
                        [1, 1, 1, 1, 0, 0, 0, 0]], Int)

_node_edges =3D [_node_edges4_s, _node_edges5_s, _node_edges6_s, =
_node_edges8_s]
_node_edges3 =3D [_node_edges4, _node_edges5, _node_edges6, =
_node_edges8]

def _construct3 (itype) :
   global _node_edges
   global _no_verts
   global _no_edges
   i =3D arange (1, 2**_no_verts [itype] - 1, typecode =3D Int)
   if itype =3D=3D 0 :
      below =3D transpose (not_equal (array ( [bitwise_and (i, 8),
                                             bitwise_and (i, 4),
                                             bitwise_and (i, 2),
                                             bitwise_and (i, 1)]), 0))
   elif itype =3D=3D 1 :
      below =3D transpose (not_equal (array ( [bitwise_and (i, 16),
                                             bitwise_and (i, 8),
                                             bitwise_and (i, 4),
                                             bitwise_and (i, 2),
                                             bitwise_and (i, 1)]), 0))
   elif itype =3D=3D 2 :
      below =3D transpose (not_equal (array ( [bitwise_and (i, 32),
                                             bitwise_and (i, 16),
                                             bitwise_and (i, 8),
                                             bitwise_and (i, 4),
                                             bitwise_and (i, 2),
                                             bitwise_and (i, 1)]), 0))
   elif itype =3D=3D 3 :
      below =3D transpose (not_equal (array ( [bitwise_and (i, 128),
                                             bitwise_and (i, 64),
                                             bitwise_and (i, 32),
                                             bitwise_and (i, 16),
                                             bitwise_and (i, 8),
                                             bitwise_and (i, 4),
                                             bitwise_and (i, 2),
                                             bitwise_and (i, 1)]), 0))
   # For some reason the node edges for a cell need to be in different =
order
   # here than in slice3 to get the correct results. Hence _node_edges3.
   mask =3D find_mask (below, _node_edges3 [itype])

   return construct3 (mask, itype)

# =
------------------------------------------------------------------------

_poly_permutations4 =3D _construct3 (0)
_poly_permutations5 =3D _construct3 (1)
_poly_permutations6 =3D _construct3 (2)
_poly_permutations8 =3D _construct3 (3)

_poly_permutations =3D [_poly_permutations4, _poly_permutations5,=20
                     _poly_permutations6, _poly_permutations8]

_ContourError =3D "ContourError"

# =
------------------------------------------------------------------------

def plzcont (nverts, xyzverts, contours =3D 8, scale =3D "lin", clear =
=3D 1,
   edges =3D 0, color =3D None, cmin =3D None, cmax =3D None,=20
   zaxis_min =3D None, zaxis_max =3D None, split =3D 0) :
#  plzcont (nverts, xyzverts, contours =3D 8, scale =3D "lin", clear =3D =
1,
#  edges =3D 0, color =3D None, cmin =3D None, cmax =3D None, split =3D =
0
#  zaxis_min =3D None, zaxis_max =3D None, )

#    Plot filled z contours on the specified surface. NVERTS and
#    XYZVERTS arrays specify the polygons for the surface being
#    drawn. CONTOURS can be one of the following:
#       N, an integer: Plot N contours (therefore, N+1 colored
#       components of the surface)
#       CVALS, a vector of floats: draw the contours at the
#       specified levels.
#    SCALE can be "lin", "log", or "normal" specifying the
#    contour scale. (Only applicable if contours =3D N, of course).
#    If CLEAR =3D 1, clear the display list first.
#    If EDGES =3D 1, plot the edges.
#    The algorithm is to apply slice2x repeatedly to the surface.
#    If color =3D=3D None, then bytscl the palette into N + 1 colors
#    and send each of the slices to pl3tree with the appropriate color.
#    If color =3D=3D "bg", will plot only the edges.
#    If CMIN is given, use it instead of the minimum z actually
#    being plotted in the computation of contour levels. If CMAX is =
given,
#    use it instead of the maximum z actually being plotted in the
#    computation of contour levels. This is done so that a component
#    of a larger graph will have the same colors at the same levels
#    as every other component, rather than its levels being based
#    on its own max and min, which may lie inside those of the
#    rest of the graph.
#    ZAXIS_MIN and ZAXIS_MAX represent axis limits on z as expressed
#    by the user. If present, ZAXIS_MIN will inhibit plotting of all
#    lesser z values, and ZAXIS_MAX will inhibit the plotting of all
#    greater z values.

# =
------------------------------------------------------------------------
     # 1. Get contour colors
     if type (contours) =3D=3D IntType :
        n =3D contours
        if cmin !=3D None :
           vcmin =3D cmin
           minz =3D min (xyzverts [:, 2])
        else :
           vcmin =3D min (xyzverts [:, 2])
           minz =3D vcmin
        if cmax !=3D None :
           vcmax =3D cmax
           maxz =3D max (xyzverts [:, 2])
        else :
           vcmax =3D max (xyzverts [:, 2])
           maxz =3D vcmax
        if scale =3D=3D "lin" :
            vc =3D vcmin + arange (1, n + 1, typecode =3D Float) * \
               (vcmax - vcmin) / (n + 1)
        elif scale =3D=3D "log" :
            vc =3D vcmin + exp (arange (1, n + 1, typecode =3D Float) * =
\
               log (vcmax - vcmin) / (n + 1))
        elif scale =3D=3D "normal" :
            zlin =3D xyzverts [:, 2]
            lzlin =3D len (zlin)
            zbar =3D add.reduce (zlin) / lzlin
            zs =3D sqrt ( (add.reduce (zlin ** 2) - lzlin * zbar ** 2) /
                (lzlin - 1))
            z1 =3D zbar - 2. * zs
            z2 =3D zbar + 2. * zs
            diff =3D (z2 - z1) / (n - 1)
            vc =3D z1 + arange (n) * diff
        else :
            raise _ContourError, "Incomprehensible scale parameter."
     elif type (contours) =3D=3D ArrayType and contours.typecode () =
=3D=3D Float :
        n =3D len (contours)
        vc =3D sort (contours)
     else :
        raise _ContourError, "Incorrect contour specification."
     if split =3D=3D 0 :
        colors =3D (arange (n + 1, typecode =3D Float) * (199. / =
n)).astype ('b')
     else :
        colors =3D (arange (n + 1, typecode =3D Float) * (99. / =
n)).astype ('b')
     # 2. Loop through slice2x calls
     nv =3D array (nverts, copy =3D 1)
     xyzv =3D array (xyzverts, copy =3D 1)
     if clear =3D=3D 1 :
        clear3 ( ) # Clear any previous plot or we're in trouble
     # find imin--contours below this number need not be computed,
     # and imax--contours at this level and above need not be computed.
     imin =3D imax =3D 0
     for i in range (n) :
        if vc [i] <=3D minz :
           imin =3D i + 1
        if vc [i] >=3D maxz :
           imax =3D i
           break
        if i =3D=3D n - 1 :
           imax =3D n
     # now make sure that the minimum and maximum contour levels =
computed
     # are not outside the axis limits.
     if zaxis_min !=3D None and zaxis_min > vc [imin] :
        for i in range (imin, imax) :
           if i + 1 < imax and zaxis_min > vc [i + 1] :
              imin =3D i + 1
           else :
              break
        vc [imin] =3D zaxis_min
     if zaxis_max !=3D None and zaxis_max < vc [imax - 1] :
        for i in range (imax - imin) :
           if imax - 2 >=3D imin and zaxis_max < vc [imax - 2] :
              imax =3D imax - 1
           else :
              break
        vc [imax - 1] =3D zaxis_max
     for i in range (imin, imax) :
        [nv, xyzv, d1, nvb, xyzvb, d2] =3D \
           slice2x (array ( [0., 0., 1., vc [i]], Float) , nv, xyzv, =
None)
        if i =3D=3D imin and zaxis_min !=3D None and zaxis_min =3D=3D vc =
[i]:
           # Don't send the "back" surface if it's below zaxis_min.
           continue
        else:
           if color =3D=3D None :
              pl3tree (nvb, xyzvb, (ones (len (nvb)) * colors =
[i]).astype ('b'),
                 split =3D 0, edges =3D edges)
           else :
              # N. B. Force edges to be on, otherwise the graph is =
empty.
              pl3tree (nvb, xyzvb, "bg", split =3D 0, edges =3D 1)
     if zaxis_max =3D=3D None or vc [imax - 1] < zaxis_max:
        # send "front" surface if it's not beyond zaxis_max
        if color =3D=3D None :
           pl3tree (nv, xyzv, (ones (len (nv)) * colors [i]).astype =
('b'),
              split =3D 0, edges =3D edges)
        else :
           pl3tree (nv, xyzv, "bg", split =3D 0, edges =3D 1)

def pl4cont (nverts, xyzverts, values, contours =3D 8, scale =3D "lin", =
clear =3D 1,
   edges =3D 0, color =3D None, cmin =3D None, cmax =3D None,
   caxis_min =3D None, caxis_max =3D None, split =3D 0) :
#  pl4cont (nverts, xyzverts, values, contours =3D 8, scale =3D "lin", =
clear =3D 1,
#  edges =3D 0, color =3D None, cmin =3D None, cmax =3D None,
#  caxis_min =3D None, caxis_max =3D None, split =3D 0)

#    Plot filled z contours on the specified surface. VALUES is
#    a node-centered array the same length as SUM (NVERTS) whose
#    contours will be drawn. NVERTS and
#    XYZVERTS arrays specify the polygons for the surface being
#    drawn. CONTOURS can be one of the following:
#       N, an integer: Plot N contours (therefore, N+1 colored
#       components of the surface)
#       CVALS, a vector of floats: draw the contours at the
#       specified levels.
#    SCALE can be "lin", "log", or "normal" specifying the
#    contour scale. (Only applicable if contours =3D N, of course).
#    If CLEAR =3D=3D 1, clear the display list first.
#    If EDGES =3D=3D 1, plot the edges.
#    The algorithm is to apply slice2x repeatedly to the surface.
#    If color =3D=3D None, then bytscl the palette into N + 1 colors
#    and send each of the slices to pl3tree with the appropriate color.
#    If color =3D=3D "bg", will plot only the edges.
#    If CMIN is given, use it instead of the minimum c actually
#    being plotted in the computation of contour levels. If CMAX is =
given,
#    use it instead of the maximum c actually being plotted in the
#    computation of contour levels. This is done so that a component
#    of a larger graph will have the same colors at the same levels
#    as every other component, rather than its levels being based
#    on its own max and min, which may lie inside those of the
#    rest of the graph.
#    CAXIS_MIN and CAXIS_MAX represent axis limits on c as expressed
#    by the user. If present, CAXIS_MIN will inhibit plotting of all
#    lesser c values, and CAXIS_MAX will inhibit the plotting of all
#    greater c values.

# =
------------------------------------------------------------------------
     # 1. Get contour colors
     if type (contours) =3D=3D IntType :
        n =3D contours
        if cmin !=3D None :
            vcmin =3D cmin
            minz =3D min (values)
        else :
            vcmin =3D min (values)
            minz =3D vcmin
        if cmax !=3D None :
            vcmax =3D cmax
            maxz =3D max (values)
        else :
            vcmax =3D max (values)
            maxz =3D vcmax
        if scale =3D=3D "lin" :
            vc =3D vcmin + arange (1, n + 1, \
               typecode =3D Float) * \
               (vcmax - vcmin) / (n + 1)
        elif scale =3D=3D "log" :
            vc =3D vcmin + exp (arange (1, n + 1, \
               typecode =3D Float) * \
               log (vcmax - vcmin) / (n + 1))
        elif scale =3D=3D "normal" :
            zbar =3D add.reduce (values) / lzlin
            zs =3D sqrt ( (add.reduce (values ** 2) - lzlin * zbar ** 2) =
/
                (lzlin - 1))
            z1 =3D zbar - 2. * zs
            z2 =3D zbar + 2. * zs
            diff =3D (z2 - z1) / (n - 1)
            vc =3D z1 + arange (n) * diff
        else :
            raise _ContourError, "Incomprehensible scale parameter."
     elif type (contours) =3D=3D ArrayType and contours.typecode () =
=3D=3D Float :
        n =3D len (contours)
        vc =3D sort (contours)
     else :
        raise _ContourError, "Incorrect contour specification."
     if split =3D=3D 0 :
        colors =3D (arange (n + 1, typecode =3D Float) * (199. / =
n)).astype ('b')
     else :
        colors =3D (arange (n + 1, typecode =3D Float) * (99. / =
n)).astype ('b')
     # 2. Loop through slice2x calls
     nv =3D array (nverts, copy =3D 1)
     xyzv =3D array (xyzverts, copy =3D 1)
     vals =3D array (values, copy =3D 1)
     if clear =3D=3D 1 :
        clear3 ( ) # Clear any previous plot or we're in trouble
     # find imin--contours below this number need not be computed,
     # and imax--contours at this level and above need not be computed.
     imin =3D imax =3D 0
     for i in range (n) :
        if vc [i] <=3D minz :
           imin =3D i + 1
        if vc [i] >=3D maxz :
           imax =3D i
           break
        if i =3D=3D n - 1 :
           imax =3D n
     # now make sure that the minimum and maximum contour levels =
computed
     # are not outside the axis limits.
     if caxis_min !=3D None and caxis_min > vc [imin] :
        for i in range (imin, imax) :
           if i + 1 < imax and caxis_min > vc [i + 1] :
              imin =3D i + 1
           else :
              break
        vc [imin] =3D caxis_min
     if caxis_max !=3D None and caxis_max < vc [imax - 1] :
        for i in range (imax - imin) :
           if imax - 2 >=3D imin and caxis_max < vc [imax - 2] :
              imax =3D imax - 1
           else :
              break
        vc [imax - 1] =3D caxis_max
     for i in range (n) :
        if vc [i] <=3D minz :
           continue
        if vc [i] >=3D maxz :
           break
        [nv, xyzv, vals, nvb, xyzvb, d2] =3D \
           slice2x (vc [i], nv, xyzv, vals)
        if i =3D=3D imin and caxis_min !=3D None and caxis_min =3D=3D vc =
[i]:
           # Don't send the "back" surface if it's below caxis_min.
           continue
        else:
           if color =3D=3D None :
              pl3tree (nvb, xyzvb, (ones (len (nvb)) * colors =
[i]).astype ('b'),
                 split =3D 0, edges =3D edges)
           else :
              # N. B. Force edges to be on, otherwise the graph is =
empty.
              pl3tree (nvb, xyzvb, "bg", split =3D 0, edges =3D 1)
     if caxis_max =3D=3D None or vc [imax - 1] < caxis_max:
        # send "front" surface if it's not beyond caxis_max
        if color =3D=3D None :
           pl3tree (nv, xyzv, (ones (len (nv)) * colors [i]).astype =
('b'),
              split =3D 0, edges =3D edges)
        else :
           pl3tree (nv, xyzv, "bg", split =3D 0, edges =3D 1)

def slice2x (plane, nverts, xyzverts, values =3D None) :
#  slice2x (plane, nverts, xyzverts, values =3D None)

#    Slice a polygon list, retaining only those polygons or
#    parts of polygons on the positive side of PLANE, that is,
#    the side where xyz(+)*PLANE(+:1:3)-PLANE(4) > 0.0.
#    The NVERTS, VALUES, and XYZVERTS arrays serve as both
#    input and output, and have the meanings of the return
#    values from the slice3 function.
#    Actually, since Python can't treat an argument as an output,
#    this routine will return a sextuple of values (None for
#    missing args).=20
#    Note (ZCM 2/24/97) Reomved _slice2x as a global and added
#    it as a final argument to slice2.

   retval =3D slice2 (plane, nverts, xyzverts, values, 1)
   retval =3D retval + [None] * (6 - len (retval))
   return retval


_Pl3surfError =3D "Pl3surfError"

def pl3surf(nverts, xyzverts =3D None, values =3D None, cmin =3D None, =
cmax =3D None,
            lim =3D None, edges =3D 0) :
#  pl3surf (nverts, xyzverts)
#        or pl3surf (nverts, xyzverts, values)

#    Perform simple 3D rendering of an object created by slice3
#    (possibly followed by slice2).  NVERTS and XYZVERTS are polygon
#    lists as returned by slice3, so XYZVERTS is sum(NVERTS)-by-3,
#    where NVERTS is a list of the number of vertices in each polygon.
#    If present, the VALUES should have the same length as NVERTS;
#    they are used to color the polygon.  If VALUES is not specified,
#    the 3D lighting calculation set up using the light3 function
#    will be carried out.  Keywords cmin=3D and cmax=3D as for plf, pli,
#    or plfp are also accepted.  (If you do not supply VALUES, you
#    probably want to use the ambient=3D keyword to light3 instead of
#    cmin=3D here, but cmax=3D may still be useful.)

   _draw3 =3D get_draw3_ ( )
   if type (nverts) =3D=3D ListType :
      list =3D nverts
      nverts =3D list [0]
      xyzverts =3D array (list [1], copy =3D 1)
      values =3D list [2]
      cmin =3D list [3]
      cmax =3D list [4]
      edges =3D list [6]
      ## Scale xyzverts to avoid loss of accuracy
      minx =3D min (xyzverts [:, 0])
      maxx =3D max (xyzverts [:, 0])
      miny =3D min (xyzverts [:, 1])
      maxy =3D max (xyzverts [:, 1])
      minz =3D min (xyzverts [:, 2])
      maxz =3D max (xyzverts [:, 2])
      xyzverts [:, 0] =3D (xyzverts [:, 0] - minx) / (maxx - minx)
      xyzverts [:, 1] =3D (xyzverts [:, 1] - miny) / (maxy - miny)
      xyzverts [:, 2] =3D (xyzverts [:, 2] - minz) / (maxz - minz)
      xyztmp =3D get3_xy (xyzverts, 1)
      x =3D xyztmp [:, 0]
      y =3D xyztmp [:, 1]
      z =3D xyztmp [:, 2]
      if values =3D=3D None :
#        xyzverts [:, 0] =3D x
#        xyzverts [:, 1] =3D y
#        xyzverts [:, 2] =3D z
         values =3D get3_light (xyztmp, nverts)
      [list, vlist] =3D sort3d (z, nverts)
      nverts =3D take (nverts, list)
      values =3D take (values, list)
      x =3D take (x, vlist)
      y =3D take (y, vlist)
      _square =3D get_square_ ( )
      [_xfactor, _yfactor] =3D get_factors_ ()
      xmax =3D max (x)
      xmin =3D min (x)
      ymax =3D max (y)
      ymin =3D min (y)
      xdif =3D xmax - xmin
      ydif =3D ymax - ymin
      if _xfactor !=3D 1. :
         xmax =3D xmax + (_xfactor - 1.) * xdif /2.
         xmin =3D xmin - (_xfactor - 1.) * xdif /2.
      if _yfactor !=3D 1. :
         ymax =3D ymax + (_yfactor - 1.) * ydif /2.
         ymin =3D ymin - (_yfactor - 1.) * ydif /2.
      if _square :
         xdif =3D xmax - xmin
         ydif =3D ymax - ymin
         if xdif > ydif :
            dif =3D (xdif - ydif) / 2.
            ymin =3D ymin - dif
            ymax =3D ymax + dif
         elif ydif > xdif :
            dif =3D (ydif - xdif) / 2.
            xmin =3D xmin - dif
            xmax =3D xmax + dif

      plfp (values, y, x, nverts, cmin =3D cmin, cmax =3D cmax, legend =
=3D "",
         edges =3D edges)
      return [xmin, xmax, ymin, ymax]

   nverts =3D array (nverts, Int)
   xyzverts =3D array (xyzverts, Float )

   if shape (xyzverts) [0] !=3D sum (nverts) or sum (less (nverts, 3)) =
or \
      nverts.typecode () !=3D Int :
      raise _Pl3surfError, "illegal or inconsistent polygon list"
   if values !=3D None and len (values) !=3D len (nverts) :
      raise _Pl3surfError, "illegal or inconsistent polygon color =
values"

   if values !=3D None :
      values =3D array (values, Float )

   clear3 ( )
   set3_object ( pl3surf, [nverts, xyzverts, values, cmin, cmax, lim, =
edges])
   if (_draw3) :
      # Plot the current list if _draw3 has been set.
      call_idler ( )
   if lim :
      tmp =3D get3_xy (xyzverts, 1)
      return max ( max (abs (tmp [:,0:2])))
   else :
      return None


# =
------------------------------------------------------------------------

_Pl3treeError =3D "Pl3treeError"

def pl3tree (nverts, xyzverts =3D None, values =3D None, plane =3D None,
             cmin =3D None, cmax =3D None, split =3D 1, edges =3D 0) :
#  pl3tree, nverts, xyzverts
#        or pl3tree, nverts, xyzverts, values, plane

#    Add the polygon list specified by NVERTS (number of vertices in
#    each polygon) and XYZVERTS (3-by-sum(NVERTS) vertex coordinates)
#    to the currently displayed b-tree.  If VALUES is specified, it
#    must have the same dimension as NVERTS, and represents the color
#    of each polygon.  (ZCM 7/18/97) Or, if VALUES =3D=3D "bg" =
("background")
#    Then each polygon will be filled with the background color,
#    giving just a wire frame. If VALUES is not specified, the polygons
#    are assumed to form an isosurface which will be shaded by the
#    current 3D lighting model; the isosurfaces are at the leaves of
#    the b-tree, sliced by all of the planes.  If PLANE is specified,
#    the XYZVERTS must all lie in that plane, and that plane becomes
#    a new slicing plane in the b-tree.

#    Each leaf of the b-tree consists of a set of sliced isosurfaces.
#    A node of the b-tree consists of some polygons in one of the
#    planes, a b-tree or leaf entirely on one side of that plane, and
#    a b-tree or leaf on the other side.  The first plane you add
#    becomes the root node, slicing any existing leaf in half.  When
#    you add an isosurface, it propagates down the tree, getting
#    sliced at each node, until its pieces reach the existing leaves,
#    to which they are added.  When you add a plane, it also propagates
#    down the tree, getting sliced at each node, until its pieces
#    reach the leaves, which it slices, becoming the nodes closest to
#    the leaves.

#    This structure is relatively easy to plot, since from any
#    viewpoint, a node can always be plotted in the order from one
#    side, then the plane, then the other side.

#    This routine assumes a "split palette"; the colors for the
#    VALUES will be scaled to fit from color 0 to color 99, while
#    the colors from the shading calculation will be scaled to fit
#    from color 100 to color 199.  (If VALUES is specified as a char
#    array, however, it will be used without scaling.)
#    You may specifiy a cmin=3D or cmax=3D keyword to affect the
#    scaling; cmin is ignored if VALUES is not specified (use the
#    ambient=3D keyword from light3 for that case).

#    (ZCM 4/23/97) Add the split keyword. This will determine
#    whether or not to split the palette (half to the isosurfaces
#    for shading and the other half to plane sections for contouring).

#    (ZCM 7/17/97) Add a calculation of the maximum and minimum
#    of everything that is put into the tree. This cures distortion
#    caused by loss of accuracy in orientation calculations.
#    What is now put on the display list is pl3tree and [tree, minmax];
#    both components are passed to _pl3tree to normalize results.

   # avoid overhead of local variables for _pl3tree and _pl3leaf
   # -- I don't know if this is such a big deal
   _draw3 =3D get_draw3_ ()
   if type (nverts) =3D=3D ListType :
      _nverts =3D []
      for i in range (len (nverts)) :
         _nverts.append (nverts [i])
      return _pl3tree (_nverts [0], nverts [1])

   # We need copies of everything, or else arrays get clobbered.
   nverts =3D array (nverts, Int)
   xyzverts =3D array (xyzverts, Float )
   if values =3D=3D "background" :
      values =3D "bg"
   elif values !=3D None and values !=3D "bg" :
      values =3D array (values, values.typecode ())
   if plane !=3D None :
      plane =3D plane.astype (Float)

   if shape (xyzverts) [0] !=3D sum (nverts) or sum (less (nverts, 3)) > =
0 or \
      type (nverts [0]) !=3D IntType :
      print "Dim1 of xyzverts ", shape (xyzverts) [0], " sum (nverts) =
",\
         sum (nverts), " sum (less (nverts, 3)) ", sum (less (nverts, =
3)), \
         " type (nverts [0]) ", `type (nverts [0])`
      raise _Pl3treeError, "illegal or inconsistent polygon list."
   if type (values) =3D=3D ArrayType and len (values) !=3D len (nverts) =
and \
      len (values) !=3D sum (nverts) :
      raise _Pl3treeError, "illegal or inconsistent polygon color =
values"
   if type (values) =3D=3D ArrayType and len (values) =3D=3D sum =
(nverts) :
      # We have vertex-centered values, which for Gist must be
      # averaged over each cell
      list =3D zeros (sum (nverts), Int)
      array_set (list, cumsum (nverts) [0:-1], ones (len (nverts), Int))
      tpc =3D values.typecode ()
      values =3D (histogram (cumsum (list), values) / nverts).astype =
(tpc)
   if plane !=3D None :
      if (len (shape (plane)) !=3D 1 or shape (plane) [0] !=3D 4) :
         raise _Pl3treeError, "illegal plane format, try plane3 =
function"

   # Note: a leaf is going to be a list of lists.
   leaf =3D [ [nverts, xyzverts, values, cmin, cmax, split, edges]]

   ## max and min of current leaf
   minmax =3D array ( [min (xyzverts [:, 0]), max (xyzverts [:, 0]),
                     min (xyzverts [:, 1]), max (xyzverts [:, 1]),
                     min (xyzverts [:, 2]), max (xyzverts [:, 2])])

   # retrieve current b-tree (if any) from 3D display list
   _draw3_list =3D get_draw3_list_ ()
   _draw3_n =3D get_draw3_n_ ()
   try :
      tree =3D _draw3_list [_draw3_n:]
   except :
      tree =3D []
   if tree =3D=3D [] or tree [0] !=3D pl3tree :
      tree =3D [plane, [], leaf, []]
   else :
      oldminmax =3D tree [1] [1]
      tree =3D tree [1] [0]
      ## Find new minmax for whole tree
      minmax =3D array ( [min (minmax [0], oldminmax [0]),
                        max (minmax [1], oldminmax [1]),
                        min (minmax [2], oldminmax [2]),
                        max (minmax [3], oldminmax [3]),
                        min (minmax [4], oldminmax [4]),
                        max (minmax [5], oldminmax [5])])
      _pl3tree_add (leaf, plane, tree)
      set_multiple_components (1)

   tmp =3D has_multiple_components ()
   clear3 ()
   set_multiple_components (tmp)
#  plist (tree)
   set3_object (pl3tree, [tree, minmax])
   if (_draw3) :
      ## Plot the current list
      call_idler ( )

palette_dict =3D {
   "earth.gp" :
      [array ([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8,
               8, 9, 10, 11, 11, 12, 13, 14, 15, 15, 16, 17, 18, 18, 19,
               20, 21, 22, 22, 23, 24, 25, 26, 26, 27, 28, 29, 30, 31, =
31,
               32, 33, 34, 35, 36, 36, 37, 38, 39, 40, 41, 41, 42, 43, =
44,
               45, 46, 47, 48, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, =
53,
               53, 54, 54, 55, 55, 56, 56, 57, 57, 58, 58, 59, 59, 60, =
61,
               61, 62, 62, 63, 63, 64, 64, 65, 65, 66, 67, 67, 68, 68, =
69,
               69, 70, 71, 73, 76, 78, 81, 83, 86, 88, 91, 94, 96, 99, =
101,
               104, 106, 109, 111, 114, 117, 119, 121, 122, 124, 126, =
128,
               129, 131, 133, 135, 136, 138, 140, 141, 143, 145, 147, =
149,
               150, 152, 154, 156, 157, 159, 161, 163, 165, 166, 168, =
170,
               172, 174, 175, 177, 179, 181, 183, 183, 184, 184, 185, =
185,
               186, 186, 187, 187, 187, 188, 188, 189, 189, 190, 190, =
190,
               191, 191, 192, 192, 193, 195, 196, 197, 198, 199, 201, =
202,
               203, 204, 205, 207, 208, 209, 210, 211, 213, 214, 215, =
216,
               217, 219, 220, 221, 222, 223, 225, 226, 227, 228, 229, =
231,
               232, 233, 234, 235, 237, 238, 239, 240, 241, 243, 244, =
245,
               246, 247, 249, 250, 251, 252, 253, 255], 'b'),
      array ( [0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 8, 11, 13, 16, 18, 21, 23, =
26,
               28, 31, 33, 36, 38, 41, 43, 45, 48, 50, 52, 55, 57, 59, =
61,
               64, 66, 68, 70, 72, 74, 77, 79, 81, 83, 85, 87, 89, 91, =
93,
               95, 97, 99, 100, 102, 104, 106, 108, 109, 111, 113, 115,
               116, 118, 120, 121, 123, 125, 126, 128, 128, 129, 129, =
130,
               131, 131, 132, 133, 133, 134, 134, 135, 136, 136, 137, =
138,
               138, 139, 140, 140, 141, 141, 142, 143, 143, 144, 145, =
145,
               146, 146, 147, 148, 148, 149, 150, 150, 151, 151, 152, =
153,
               153, 154, 155, 155, 156, 156, 157, 158, 158, 159, 160, =
160,
               161, 161, 162, 163, 163, 164, 165, 165, 166, 166, 167, =
168,
               168, 168, 169, 169, 170, 170, 171, 171, 172, 172, 172, =
173,
               173, 174, 174, 175, 175, 175, 176, 176, 177, 177, 178, =
178,
               179, 179, 179, 180, 180, 181, 181, 182, 182, 183, 183, =
182,
               181, 181, 180, 179, 178, 177, 176, 175, 174, 173, 172, =
171,
               170, 169, 168, 167, 166, 165, 164, 163, 163, 164, 164, =
165,
               165, 166, 167, 167, 168, 169, 170, 171, 172, 173, 174, =
175,
               176, 177, 178, 179, 181, 182, 184, 185, 187, 188, 190, =
192,
               194, 196, 198, 200, 202, 204, 206, 208, 211, 213, 215, =
218,
               221, 223, 226, 229, 232, 235, 238, 241, 244, 248, 251, =
255],
               'b'),
      array ( [0, 46, 58, 69, 81, 92, 104, 116, 116, 116, 116, 116, 117,
               117, 117, 117, 117, 118, 118, 118, 118, 118, 119, 119, =
119,
               119, 119, 120, 120, 120, 120, 120, 121, 121, 121, 121, =
121,
               122, 122, 122, 122, 122, 123, 123, 123, 123, 123, 124, =
124,
               124, 124, 124, 125, 125, 125, 125, 125, 126, 126, 126, =
126,
               126, 127, 127, 127, 127, 127, 128, 126, 125, 124, 123, =
122,
               120, 119, 118, 117, 115, 114, 113, 111, 110, 109, 108, =
106,
               105, 104, 102, 101, 100, 98, 97, 96, 94, 93, 92, 90, 89, =
88,
               86, 85, 84, 82, 81, 80, 78, 77, 76, 74, 73, 71, 70, 71, =
72,
               72, 73, 73, 74, 75, 75, 76, 76, 77, 77, 78, 79, 79, 80, =
80,
               81, 82, 82, 82, 83, 83, 83, 84, 84, 84, 85, 85, 85, 86, =
86,
               86, 87, 87, 87, 88, 88, 88, 89, 89, 89, 90, 90, 90, 91, =
91,
               91, 92, 92, 92, 93, 93, 93, 94, 94, 94, 95, 95, 95, 96, =
96,
               97, 97, 97, 98, 98, 98, 99, 99, 99, 100, 100, 100, 101, =
101,
               104, 106, 108, 111, 113, 116, 118, 121, 123, 126, 129, =
131,
               134, 137, 139, 142, 145, 148, 150, 153, 156, 159, 162, =
165,
               168, 170, 173, 176, 179, 182, 185, 189, 192, 195, 198, =
201,
               204, 207, 211, 214, 217, 220, 224, 227, 230, 234, 237, =
241,
               244, 248, 251, 255] , 'b')],
   "gray.gp" : [
      array ( [
               0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, =
17,
               18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 30, 31, 32, =
33,
               34, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 47, 48, =
49,
               50, 51, 52, 53, 54, 55, 57, 58, 59, 60, 61, 62, 63, 64, =
65,
               66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77, 78, 79, 80, =
81,
               82, 83, 84, 85, 86, 87, 89, 90, 91, 92, 93, 94, 95, 96, =
97,
               98, 99, 100, 101, 102, 103, 105, 106, 107, 108, 109, 110,
               111, 112, 113, 114, 115, 116, 117, 118, 119, 121, 122, =
123,
               124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, =
135,
               137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, =
148,
               149, 150, 151, 153, 154, 155, 156, 157, 158, 159, 160, =
161,
               162, 163, 164, 165, 166, 167, 169, 170, 171, 172, 173, =
174,
               175, 176, 177, 178, 179, 180, 181, 182, 183, 185, 186, =
187,
               188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, =
199,
               201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, =
212,
               213, 214, 215, 217, 218, 219, 220, 221, 222, 223, 224, =
225,
               226, 227, 228, 229, 230, 231, 233, 234, 235, 236, 237, =
238,
               239, 240, 241, 242, 243, 244, 245, 246, 247, 249, 250, =
251,
               252, 253, 254, 255
              ] , 'b'),
      array ( [
               0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, =
17,
               18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 30, 31, 32, =
33,
               34, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 47, 48, =
49,
               50, 51, 52, 53, 54, 55, 57, 58, 59, 60, 61, 62, 63, 64, =
65,
               66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77, 78, 79, 80, =
81,
               82, 83, 84, 85, 86, 87, 89, 90, 91, 92, 93, 94, 95, 96, =
97,
               98, 99, 100, 101, 102, 103, 105, 106, 107, 108, 109, 110,
               111, 112, 113, 114, 115, 116, 117, 118, 119, 121, 122, =
123,
               124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, =
135,
               137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, =
148,
               149, 150, 151, 153, 154, 155, 156, 157, 158, 159, 160, =
161,
               162, 163, 164, 165, 166, 167, 169, 170, 171, 172, 173, =
174,
               175, 176, 177, 178, 179, 180, 181, 182, 183, 185, 186, =
187,
               188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, =
199,
               201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, =
212,
               213, 214, 215, 217, 218, 219, 220, 221, 222, 223, 224, =
225,
               226, 227, 228, 229, 230, 231, 233, 234, 235, 236, 237, =
238,
               239, 240, 241, 242, 243, 244, 245, 246, 247, 249, 250, =
251,
               252, 253, 254, 255
              ] , 'b'),
      array ( [
               0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, =
17,
               18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 30, 31, 32, =
33,
               34, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 47, 48, =
49,
               50, 51, 52, 53, 54, 55, 57, 58, 59, 60, 61, 62, 63, 64, =
65,
               66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77, 78, 79, 80, =
81,
               82, 83, 84, 85, 86, 87, 89, 90, 91, 92, 93, 94, 95, 96, =
97,
               98, 99, 100, 101, 102, 103, 105, 106, 107, 108, 109, 110,
               111, 112, 113, 114, 115, 116, 117, 118, 119, 121, 122, =
123,
               124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, =
135,
               137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, =
148,
               149, 150, 151, 153, 154, 155, 156, 157, 158, 159, 160, =
161,
               162, 163, 164, 165, 166, 167, 169, 170, 171, 172, 173, =
174,
               175, 176, 177, 178, 179, 180, 181, 182, 183, 185, 186, =
187,
               188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, =
199,
               201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, =
212,
               213, 214, 215, 217, 218, 219, 220, 221, 222, 223, 224, =
225,
               226, 227, 228, 229, 230, 231, 233, 234, 235, 236, 237, =
238,
               239, 240, 241, 242, 243, 244, 245, 246, 247, 249, 250, =
251,
               252, 253, 254, 255
              ] , 'b')
      ],
   "heat.gp" : [
      array ( [
               0, 1, 2, 4, 5, 7, 8, 10, 11, 13, 15, 17, 18, 20, 21, 23, =
24,
               26, 27, 28, 30, 31, 33, 34, 36, 37, 39, 40, 42, 43, 46, =
47,
               49, 50, 52, 53, 55, 56, 57, 59, 60, 62, 63, 65, 66, 68, =
69,
               70, 72, 73, 76, 78, 79, 81, 82, 84, 85, 86, 88, 89, 92, =
94,
               95, 97, 98, 99, 101, 102, 104, 105, 108, 110, 111, 113, =
114,
               115, 117, 118, 120, 121, 123, 124, 126, 127, 128, 130, =
131,
               133, 134, 136, 139, 140, 141, 143, 144, 146, 147, 149, =
150,
               152, 153, 155, 156, 157, 159, 160, 162, 163, 165, 166, =
169,
               170, 172, 173, 175, 176, 178, 179, 181, 182, 185, 186, =
188,
               189, 191, 192, 194, 195, 197, 198, 201, 202, 204, 205, =
207,
               208, 210, 211, 212, 214, 215, 217, 218, 220, 221, 223, =
224,
               226, 227, 228, 231, 233, 234, 236, 237, 239, 240, 241, =
243,
               244, 246, 247, 249, 250, 252, 253, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255
              ] , 'b'),
      array ( [
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 5, 7, 9, =
11,
               15, 17, 18, 20, 22, 24, 26, 28, 30, 32, 35, 37, 39, 41, =
43,
               45, 47, 49, 51, 52, 54, 56, 58, 60, 62, 64, 66, 68, 69, =
71,
               75, 77, 79, 81, 83, 85, 86, 88, 90, 92, 94, 96, 98, 100,
               102, 103, 105, 107, 109, 111, 115, 117, 119, 120, 122, =
124,
               126, 128, 130, 132, 136, 137, 139, 141, 143, 145, 147, =
149,
               151, 153, 156, 158, 160, 162, 164, 166, 168, 170, 171, =
173,
               175, 177, 179, 181, 183, 185, 187, 188, 190, 192, 196, =
198,
               200, 202, 204, 205, 207, 209, 211, 213, 215, 217, 219, =
221,
               222, 224, 226, 228, 230, 232, 236, 238, 239, 241, 243, =
245,
               247, 249, 251, 253
              ] , 'b'),
      array ( [
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 51, 54, 58, 62, =
66,
               70, 74, 78, 82, 86, 90, 94, 98, 102, 105, 109, 113, 117,
               121, 125, 133, 137, 141, 145, 149, 153, 156, 160, 164, =
168,
               172, 176, 180, 184, 188, 192, 196, 200, 204, 207, 215, =
219,
               223, 227, 231, 235, 239, 243, 247, 251
              ] , 'b')
      ],
   "rainbow.gp" : [
      array ( [
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 245, 240, 235, 229, 224, 219, =
213,
               208, 202, 197, 192, 186, 181, 175, 170, 159, 154, 149, =
143,
               138, 132, 127, 122, 116, 111, 106, 100, 95, 89, 84, 73, =
68,
               63, 57, 52, 46, 41, 36, 30, 25, 19, 14, 9, 3, 0, 0, 0, 0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 2, 7, 18, 24, 29, 34, 40, 45, 50, 56, 61, =
67,
               72, 77, 83, 88, 93, 104, 110, 115, 120, 126, 131, 136, =
142,
               147, 153, 158, 163, 169, 174, 180, 190, 196, 201, 206, =
212,
               217, 223, 228, 233, 239, 244, 249, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255
              ] , 'b'),
      array ( [
               0, 0, 0, 0, 0, 0, 0, 0, 5, 11, 16, 22, 27, 32, 38, 43, =
48,
               54, 59, 65, 70, 75, 81, 91, 97, 102, 108, 113, 118, 124,
               129, 135, 140, 145, 151, 156, 161, 167, 178, 183, 188, =
194,
               199, 204, 210, 215, 221, 226, 231, 237, 242, 247, 253, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 250, 239, 234, 228, 223, 218, 212, =
207,
               201, 196, 191, 185, 180, 174, 169, 164, 153, 148, 142, =
137,
               131, 126, 121, 115, 110, 105, 99, 94, 88, 83, 78, 67, 62,
               56, 51, 45, 40, 35, 29, 24, 18, 13, 8, 2, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0
              ] , 'b'),
      array ( [
               42, 36, 31, 26, 20, 15, 10, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
0,
               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, =
1,
               12, 17, 23, 28, 33, 39, 44, 49, 55, 60, 66, 71, 76, 82, =
87,
               98, 103, 109, 114, 119, 125, 130, 135, 141, 146, 152, =
157,
               162, 168, 173, 184, 189, 195, 200, 205, 211, 216, 222, =
227,
               232, 238, 243, 248, 254, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, =
255,
               255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 249, =
243,
               233, 227, 222, 217, 211, 206, 201
              ] , 'b')
      ],
   "stern.gp" : [
      array ( [
               0, 18, 36, 54, 72, 90, 108, 127, 145, 163, 199, 217, 235,
               254, 249, 244, 239, 234, 229, 223, 218, 213, 208, 203, =
197,
               192, 187, 182, 177, 172, 161, 156, 151, 146, 140, 135, =
130,
               125, 120, 115, 109, 104, 99, 94, 89, 83, 78, 73, 68, 63, =
52,
               47, 42, 37, 32, 26, 21, 16, 11, 6, 64, 65, 66, 67, 68, =
69,
               70, 71, 72, 73, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, =
85,
               86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, 98, 99, 100,
               101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, =
112,
               113, 114, 115, 117, 118, 119, 120, 121, 122, 123, 124, =
125,
               126, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, =
139,
               140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, =
151,
               152, 153, 154, 155, 156, 157, 158, 160, 161, 162, 163, =
164,
               165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, =
176,
               177, 178, 179, 181, 182, 183, 184, 185, 186, 187, 188, =
189,
               190, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, =
203,
               204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, =
215,
               216, 217, 218, 219, 220, 221, 222, 224, 225, 226, 227, =
228,
               229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, =
240,
               241, 242, 243, 245, 246, 247, 248, 249, 250, 251, 252, =
253,
               254
              ] , 'b'),
      array ( [
               0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, =
18,
               19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 33, =
34,
               35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, =
49,
               50, 51, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 64, 65, =
66,
               67, 68, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 80, 81, =
82,
               83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 97, =
98,
               99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, =
110,
               111, 112, 113, 114, 115, 117, 118, 119, 120, 121, 122, =
123,
               124, 125, 126, 128, 129, 130, 131, 132, 133, 134, 135, =
136,
               137, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, =
149,
               150, 151, 152, 153, 154, 155, 156, 157, 158, 160, 161, =
162,
               163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, =
174,
               175, 176, 177, 178, 179, 181, 182, 183, 184, 185, 186, =
187,
               188, 189, 190, 192, 193, 194, 195, 196, 197, 198, 199, =
200,
               201, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, =
213,
               214, 215, 216, 217, 218, 219, 220, 221, 222, 224, 225, =
226,
               227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, =
238,
               239, 240, 241, 242, 243, 245, 246, 247, 248, 249, 250, =
251,
               252, 253, 254
              ] , 'b'),
      array ( [
               0, 1, 3, 5, 7, 9, 11, 13, 15, 17, 21, 23, 25, 27, 29, 31,
               33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, =
63,
               65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, =
93,
               95, 97, 99, 101, 105, 107, 109, 111, 113, 115, 117, 119,
               121, 123, 127, 129, 131, 133, 135, 137, 139, 141, 143, =
145,
               149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, =
171,
               173, 175, 177, 179, 181, 183, 185, 187, 191, 193, 195, =
197,
               199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, =
221,
               223, 225, 227, 229, 233, 235, 237, 239, 241, 243, 245, =
247,
               249, 251, 255, 251, 247, 243, 238, 234, 230, 226, 221, =
217,
               209, 204, 200, 196, 192, 187, 183, 179, 175, 170, 166, =
162,
               158, 153, 149, 145, 141, 136, 132, 128, 119, 115, 111, =
107,
               102, 98, 94, 90, 85, 81, 77, 73, 68, 64, 60, 56, 51, 47, =
43,
               39, 30, 26, 22, 17, 13, 9, 5, 0, 3, 7, 15, 19, 22, 26, =
30,
               34, 38, 41, 45, 49, 57, 60, 64, 68, 72, 76, 79, 83, 87, =
91,
               95, 98, 102, 106, 110, 114, 117, 121, 125, 129, 137, 140,
               144, 148, 152, 156, 159, 163, 167, 171, 175, 178, 182, =
186,
               190, 194, 197, 201, 205, 209, 216, 220, 224, 228, 232, =
235,
               239, 243, 247, 251
              ] , 'b')
      ],
   "yarg.gp" : [
      array ( [
               255, 254, 253, 252, 251, 250, 249, 248, 246, 245, 244, =
243,
               242, 241, 240, 239, 238, 237, 236, 235, 234, 233, 232, =
230,
               229, 228, 227, 226, 225, 224, 223, 222, 221, 220, 219, =
218,
               217, 216, 214, 213, 212, 211, 210, 209, 208, 207, 206, =
205,
               204, 203, 202, 201, 200, 198, 197, 196, 195, 194, 193, =
192,
               191, 190, 189, 188, 187, 186, 185, 184, 182, 181, 180, =
179,
               178, 177, 176, 175, 174, 173, 172, 171, 170, 169, 168, =
166,
               165, 164, 163, 162, 161, 160, 159, 158, 157, 156, 155, =
154,
               153, 152, 150, 149, 148, 147, 146, 145, 144, 143, 142, =
141,
               140, 139, 138, 137, 136, 134, 133, 132, 131, 130, 129, =
128,
               127, 126, 125, 124, 123, 122, 121, 120, 118, 117, 116, =
115,
               114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, =
102,
               101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88,
               86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, =
72,
               70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, =
56,
               54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, =
40,
               38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, =
24,
               22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, =
6,
               5, 4, 3, 2, 1, 0
              ] , 'b'),
      array ( [
               255, 254, 253, 252, 251, 250, 249, 248, 246, 245, 244, =
243,=20
               242, 241, 240, 239, 238, 237, 236, 235, 234, 233, 232, =
230,=20
               229, 228, 227, 226, 225, 224, 223, 222, 221, 220, 219, =
218,=20
               217, 216, 214, 213, 212, 211, 210, 209, 208, 207, 206, =
205,=20
               204, 203, 202, 201, 200, 198, 197, 196, 195, 194, 193, =
192,=20
               291, 190, 189, 188, 187, 186, 185, 184, 182, 181, 180, =
179,=20
               278, 177, 176, 175, 174, 173, 172, 171, 170, 169, 168, =
166,=20
               265, 164, 163, 162, 161, 160, 159, 158, 157, 156, 155, =
154,=20
               253, 152, 150, 149, 148, 147, 146, 145, 144, 143, 142, =
141,=20
               240, 139, 138, 137, 136, 134, 133, 132, 131, 130, 129, =
128,=20
               127, 126, 125, 124, 123, 122, 121, 120, 118, 117, 116, =
115,
               114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, =
102,
               101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, =
86,
               85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, =
70,
               69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, =
54,
               53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, =
38,
               37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, =
22,
               21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 6, =
5,
               4, 3, 2, 1, 0
              ] , 'b'),
      array ( [
               255, 254, 253, 252, 251, 250, 249, 248, 246, 245, 244, =
243,
               242, 241, 240, 239, 238, 237, 236, 235, 234, 233, 232, =
230,
               229, 228, 227, 226, 225, 224, 223, 222, 221, 220, 219, =
218,
               217, 216, 214, 213, 212, 211, 210, 209, 208, 207, 206, =
205,
               204, 203, 202, 201, 200, 198, 197, 196, 195, 194, 193, =
192,
               191, 190, 189, 188, 187, 186, 185, 184, 182, 181, 180, =
179,
               178, 177, 176, 175, 174, 173, 172, 171, 170, 169, 168, =
166,
               165, 164, 163, 162, 161, 160, 159, 158, 157, 156, 155, =
154,
               153, 152, 150, 149, 148, 147, 146, 145, 144, 143, 142, =
141,
               140, 139, 138, 137, 136, 134, 133, 132, 131, 130, 129, =
128,
               127, 126, 125, 124, 123, 122, 121, 120, 118, 117, 116, =
115,
               114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, =
102,
               101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88,
               86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, =
72,
               70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, =
56,
               54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, =
40,
               38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, =
24,
               22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8,
               6, 5, 4, 3, 2, 1, 0
              ] , 'b')
      ]
   }

def split_palette ( * name) :
#  split_palette
#        or split_palette ("palette_name.gp")
#    split the current palette or the specified palette into two
#    parts; colors 0 to 99 will be a compressed version of the
#    original, while colors 100 to 199 will be a gray scale.

   if len (name) > 0 :
      dum =3D palette (name [0])
      del dum
   r =3D zeros (240, 'b')
   g =3D zeros (240, 'b')
   b =3D zeros (240, 'b')
   dum =3D palette (r, g, b, query =3D 1)
   del dum
   try : # r may be all zeros, in which case the following will fail:
      n =3D max (nonzero (r)) + 1 # (Figure out how many entries there =
are)
   except :
      n =3D 0
   if n < 100 :
      dum =3D palette ("earth.gp")
      dum =3D palette (r, g, b, query =3D 1)
      del dum
      n =3D max (max (nonzero (r)), max (nonzero (g)),
               max (nonzero (b))) + 1
   newr =3D zeros (200, 'b')
   newg =3D zeros (200, 'b')
   newb =3D zeros (200, 'b')
   newr [0:100] =3D interp (r [0:n].astype (Float), arange (n, typecode =
=3D Float ),
      arange (100, typecode =3D Float ) * n / 100).astype ('b')
   newg [0:100] =3D interp (g [0:n].astype (Float), arange (n, typecode =
=3D Float ),
      arange (100, typecode =3D Float ) * n / 100).astype ('b')
   newb [0:100] =3D interp (b [0:n].astype (Float), arange (n, typecode =
=3D Float ),
      arange (100, typecode =3D Float ) * n / 100).astype ('b')
   newr [100:200] =3D (arange (100, typecode =3D Int) * 255 / 99).astype =
('b')
   newg [100:200] =3D (arange (100, typecode =3D Int) * 255 / 99).astype =
('b')
   newb [100:200] =3D (arange (100, typecode =3D Int) * 255 / 99).astype =
('b')
   palette (newr, newg, newb)

def split_bytscl (x, upper, cmin =3D None, cmax =3D None) :
#  split_bytscl(x, 0)
#        or split_bytscl(x, 1)
#    as bytscl function, but scale to the lower half of a split
#    palette (0-99, normally the color scale) if the second parameter
#    is zero or nil, or the upper half (100-199, normally the gray
#    scale) if the second parameter is non-zero.

   x =3D bytscl (x, cmin =3D cmin, cmax =3D cmax, top =3D =
99).astype('b')

   if upper :
      x =3D x + 100
   return x

def _pl3tree (tree, minmax) :
   #  tree is a 4-element list like this:
   #  [plane, back_tree, inplane_leaf, front_tree]
   #   plane=3D tree [0]  is None if this is just a leaf
   #                    in which case, only inplane_leaf is not None
   #   back_tree=3D tree [1]    is the part behind plane
   #   inplane_leaf=3D tree [2] is the part in the plane itself
   #   front_tree=3D tree [3]   is the part in front of plane
   if tree =3D=3D None or tree =3D=3D [] :
      return None
   if tree [0] =3D=3D None or tree [0] =3D=3D [] :
      # only the leaf is non-nil (but not a plane)
      return _pl3leaf ( tree [2], 1, minmax)

   # apply the 3D coordinate transform to two points along the
   # normal of the splitting plane to judge which is in front
   xyz =3D get3_xy (array ( [ [0., 0., 0.],
                  [tree [0] [0], tree [0] [1], tree [0] [2]]], Float), =
1)
   [x, y, z] =3D [xyz [:, 0], xyz [:, 1], xyz [:, 2]]

   # plot the parts in order toward the current viewpoint
   if z [1] >=3D z [0] :
      q1 =3D _pl3tree (tree [1], minmax)
      q2 =3D _pl3leaf (tree [2], 0, minmax)
      q3 =3D _pl3tree (tree [3], minmax)
   else :
      q1 =3D _pl3tree (tree [3], minmax)
      q2 =3D _pl3leaf (tree [2], 0, minmax)
      q3 =3D _pl3tree (tree [1], minmax)
   if q1 !=3D None :
      if q2 !=3D None and q3 =3D=3D None :
         return [min (q2 [0], q1 [0]),
                 max (q2 [1], q1 [1]),
                 min (q2 [2], q1 [2]),
                 max (q2 [3], q1 [3])]
      elif q2 =3D=3D None and q3 !=3D None :
         return [min (q3 [0], q1 [0]),
                 max (q3 [1], q1 [1]),
                 min (q3 [2], q1 [2]),
                 max (q3 [3], q1 [3])]
      elif q2 !=3D None and q3 !=3D None :
         return [min (q3 [0], q2 [0], q1 [0]),
                 max (q3 [1], q2 [1], q1 [1]),
                 min (q3 [2], q2 [2], q1 [2]),
                 max (q3 [3], q2 [3], q1 [3])]
      else :
         return q1
   elif q2 !=3D None :
      if q3 =3D=3D None :
         return q2
      else :
         return [min (q2 [0], q3 [0]),
                 max (q2 [1], q3 [1]),
                 min (q2 [2], q3 [2]),
                 max (q2 [3], q3 [3])]
   elif q3 !=3D None :
      return q3
   else :
      return None

## from lp import *

def _pl3leaf (leaf, not_plane, minmax) :
  =20
   # count number of polys, number of vertices
   _nverts =3D _xyzverts =3D 0
   if type (leaf) =3D=3D ListType and type (leaf [0]) =3D=3D ListType :
       for i in range (len (leaf)) :
         [_nverts, _xyzverts] =3D _pl3tree_count ( leaf [i], _nverts, =
_xyzverts )
   else :
      [_nverts, _xyzverts] =3D _pl3tree_count ( leaf , _nverts, =
_xyzverts)

   # accumulate polys and vertices into a single polygon list
   # The type of array required for palettes is "Py_GpColor",
   # which translates to "PyArray_UBYTE", which is selected
   # with a second argument of 'b' to the zeros() function.
## _values =3D zeros (_nverts, 'b') # See below
   old_nverts =3D _nverts
   _nverts =3D zeros (_nverts, Int)
   _x =3D zeros (_xyzverts, Float )
   _y =3D zeros (_xyzverts, Float )
   if (not_plane) :
      # Not just straight assignment; make _z a separate copy
      _z =3D zeros (_xyzverts, Float )
   else :
      _z =3D None
   _list =3D 1
   _vlist =3D 1
   if type (leaf) =3D=3D ListType and type (leaf [0]) =3D=3D ListType :
       if leaf [0] [2] !=3D "bg" :
          _values =3D zeros (old_nverts, 'b')
       else :
          _values =3D "bg"
       for i in range (len (leaf)) :
         [_list, _vlist, _edges] =3D _pl3tree_accum ( leaf [i] , =
not_plane,
            _x, _y, _z, _list, _vlist, _values, _nverts, minmax)
   else :
      if leaf [2] !=3D "bg" :
         _values =3D zeros (old_nverts, 'b')
      else :
         _values =3D "bg"
      [_list, _vlist, _edges] =3D _pl3tree_accum ( leaf , not_plane,
         _x, _y, _z, _list, _vlist, _values, _nverts, minmax)

   # sort the single polygon list
   if not_plane :
      [_list, _vlist] =3D sort3d (_z, _nverts)
      _nverts =3D take (_nverts, _list)
      if _values !=3D "bg" :
         _values =3D take (_values, _list)
      _x =3D take (_x, _vlist)
      _y =3D take (_y, _vlist)

   _square =3D get_square_ ( )
   [_xfactor, _yfactor] =3D get_factors_ ()
   xmax =3D max (_x)
   xmin =3D min (_x)
   ymax =3D max (_y)
   ymin =3D min (_y)
   xdif =3D xmax - xmin
   ydif =3D ymax - ymin
   if _xfactor !=3D 1. :
      xmax =3D xmax + (_xfactor - 1.) * xdif /2.
      xmin =3D xmin - (_xfactor - 1.) * xdif /2.
   if _yfactor !=3D 1. :
      ymax =3D ymax + (_yfactor - 1.) * ydif /2.
      ymin =3D ymin - (_yfactor - 1.) * ydif /2.
   if _square :
      xdif =3D xmax - xmin
      ydif =3D ymax - ymin
      if xdif > ydif :
         dif =3D (xdif - ydif) / 2.
         ymin =3D ymin - dif
         ymax =3D ymax + dif
      elif ydif > xdif :
         dif =3D (ydif - xdif) / 2.
         xmin =3D xmin - dif
         xmax =3D xmax + dif

   if _values =3D=3D "bg" :
      _values =3D None
   plfp (_values, _y, _x, _nverts, legend =3D "", edges =3D _edges)
   return [xmin, xmax, ymin, ymax]

def _pl3tree_count (item, _nverts, _xyzverts) :
   return [_nverts + len (item [0]), _xyzverts  + len (ravel (item [1])) =
/ 3]

def _pl3tree_accum (item, not_plane, _x, _y, _z, _list, _vlist, _values,
   _nverts, minmax) :
   # (ZCM 2/24/97) Add _x, _y, _z , _list, _vlist, _nverts as parameters =
to
   # avoid use of globals. return the new values of _list, _vlist.
   # (ZCM 7/16/97) Return item [6] (whether to show edges)
   # (ZCM 7/17/97) Add parameter minmax to normalize values

   # N. B.:
   # item [0] is nverts
   # item [1] is xyzverts
   # item [2] is values   (if present)
   # item [3] is cmin   (if present)
   # item [4] is cmax   (if present)
   # item [5] is split (1 =3D split the palette, 0 =3D do not split)
   # item [6] is edges (1 =3D show edges, 0 =3D do not show edges)
   # I have cleaned up what I think is extremely obscure Yorick code
   # apparently designed to avoid some overhead.
   # N. B. avoid splitting the palette if split is 0. (ZCM 4/23/97)

   _xyzverts =3D array (item [1], copy =3D 1) # protect copy in tree
   # Normalize copy  (I'm only going to do this if it's an
   # isosurface or is not a plane or has multiple components.=20
   # There is a real problem here.
   # You get bad distortion without doing this if one coordinate
   # is many orders of magnitude larger than the others but the
   # others have significant figues. You also get bad distortion
   # by doing this in the case of a single plane section
   # when one coordinate is insignificant with
   # respect to the others and doesn't have significant digits.
   # It is awfully hard to come up with a numerical criterion for this.)
   if item [2] =3D=3D None or not_plane or has_multiple_components ():
      minx =3D minmax [0]
      maxx =3D minmax [1]
      miny =3D minmax [2]
      maxy =3D minmax [3]
      minz =3D minmax [4]
      maxz =3D minmax [5]
      _xyzverts [:, 0] =3D (_xyzverts [:, 0] - minx) / (maxx - minx)
      _xyzverts [:, 1] =3D (_xyzverts [:, 1] - miny) / (maxy - miny)
      _xyzverts [:, 2] =3D (_xyzverts [:, 2] - minz) / (maxz - minz)
   if  item [2] =3D=3D None :
      # this is an isosurface to be shaded (no values specified)
      _xyzverts =3D get3_xy (_xyzverts, 1)
      # accumulate nverts and values
      incr =3D len (item [0])
      _nverts [ _list - 1: _list - 1 + incr] =3D item [0]
      if item [5] !=3D 0 :
         _values [ _list - 1: _list - 1 + incr] =3D split_bytscl (
            get3_light (_xyzverts, item [0]), 1, cmin =3D 0.0,
            cmax =3D item [4]).astype ('b')
      else : # no split
         _values [ _list - 1: _list - 1 + incr] =3D bytscl (
            get3_light (_xyzverts, item [0]), cmin =3D 0.0,
            cmax =3D item [4]).astype ('b')
      _list =3D _list + incr
      # accumulate x, y, and z
      incr =3D shape (_xyzverts) [0]
      _x [_vlist - 1:_vlist - 1 + incr] =3D _xyzverts [:, 0]
      _y [_vlist - 1:_vlist - 1 + incr] =3D _xyzverts [:, 1]
      if not_plane :
         _z [_vlist - 1:_vlist - 1 + incr] =3D _xyzverts [:, 2]
      _vlist =3D _vlist + incr
   else :
      # this is to be pseudo-colored since values are given
      if (not_plane) :
         __xyz =3D get3_xy (_xyzverts, 1)
      else :
         __xyz =3D get3_xy (_xyzverts, 0)
      # accumulate nverts and values
      incr =3D len (item [0])
      _nverts [ _list - 1: _list - 1 + incr] =3D item [0]
      if item [2] !=3D "bg" :
         if (item [2]).typecode () !=3D 'b' :
            if item [5] !=3D 0 :
               _values [ _list - 1: _list - 1 + incr] =3D split_bytscl (
                  item [2], 0, cmin =3D item [3], cmax =3D item =
[4]).astype ('b')
            else :
               _values [ _list - 1: _list - 1 + incr] =3D bytscl (
                  item [2], cmin =3D item [3], cmax =3D item [4]).astype =
('b')
         else :
            _values [ _list - 1: _list - 1 + incr] =3D item [2]
      _list =3D _list + incr
      # accumulate x, y, and z
      incr =3D shape (__xyz) [0]
      _x [_vlist - 1:_vlist - 1 + incr] =3D __xyz [:, 0]
      _y [_vlist - 1:_vlist - 1 + incr] =3D __xyz [:, 1]
      if not_plane :
         _z [_vlist - 1:_vlist - 1 + incr] =3D __xyz [:, 2]
      _vlist =3D _vlist + incr

   return [_list, _vlist, item [6]]

def _pl3tree_add (leaf, plane, tree) :
   if tree !=3D None and tree !=3D [] and \
      not is_scalar (tree) and tree [0] !=3D None :
      # tree has slicing plane, slice new leaf or plane and descend
      [back, leaf] =3D _pl3tree_slice (tree [0], leaf)
      if back :
         if len (tree) >=3D 2 and tree [1] !=3D None and tree [1] !=3D =
[] :
            _pl3tree_add (back, plane, tree [1])
         else :
            tree [1] =3D [None, [], back, []]
      if (leaf) :
         if len (tree) >=3D 4 and tree [3] !=3D None and tree [3] !=3D =
[] :
            _pl3tree_add (leaf, plane, tree [3])
         else :
            tree [3] =3D [None, [], leaf, []]

   elif plane !=3D None :
      # tree is just a leaf, but this leaf has slicing plane
      tree [0] =3D plane
      tmp =3D tree [2]
      tree [2] =3D leaf
      leaf =3D tmp   # swap new leaf with original leaf
      [back, leaf] =3D _pl3tree_slice (plane, leaf)
      if (back) :
         tree [1] =3D [None, [], back, []]
      if (leaf) :
         tree [3] =3D [None, [], leaf, []]
   else :
      # tree is just a leaf and this leaf has no slicing plane
      tree [2] =3D leaf + tree [2]

def _pl3tree_slice (plane, leaf) :
   back =3D frnt =3D None
   for ll in leaf :
      # each item in the leaf list is itself a list
      nvf =3D ll [0]
      if nvf !=3D None :
         nvb =3D array (nvf, copy =3D 1)
      else :
         nvb =3D None
      xyzf =3D ll [1]
      if xyzf !=3D None :
         xyzb =3D array (xyzf, copy =3D 1)
      else :
         xyzb =3D None
      valf =3D ll [2]
      if valf !=3D None :
         valb =3D array (valf, copy =3D 1)
      else :
         valb =3D None
      if len (ll) > 4 :
         ll4 =3D ll [4]
      else :
         ll4 =3D None
      if len (ll) > 5 :
         ll5 =3D ll [5]
      else :
         ll5 =3D 1
      if len (ll) > 6 :
         ll6 =3D ll [6]
      else :
         ll6 =3D 0
      [nvf, xyzf, valf, nvb, xyzb, valb] =3D \
         slice2x (plane, nvf, xyzf, valf)
      if nvf !=3D None :
         if frnt !=3D None :
            frnt =3D [ [nvf, xyzf, valf, ll [3], ll4, ll5, ll6]] + frnt
         else :
            frnt =3D [ [nvf, xyzf, valf, ll [3], ll4, ll5, ll6]]
      if nvb !=3D None :
         if back !=3D None :
            back =3D [ [nvb, xyzb, valb, ll [3], ll4, ll5, ll6]] + back
         else :
            back =3D [ [nvb, xyzb, valb, ll [3], ll4, ll5, ll6]]
      return [back, frnt]

_Pl3tree_prtError =3D "Pl3tree_prtError"

def pl3tree_prt () :
   _draw3_list =3D get_draw3_list ()
   _draw3_n =3D get_draw3_n_ ()
   if len (_draw3_list) >=3D _draw3_n :
      tree =3D _draw3_list [_draw3_n:]
      if tree =3D=3D None or tree =3D=3D [] or tree [0] !=3D pl3tree :
         raise _Pl3tree_prtError, "<current 3D display not a pl3tree>"
      else :
         tree =3D tree [1]
         _pl3tree_prt (tree, 0)

def _pl3tree_prt (tree, depth) :
   if tree =3D=3D None or tree =3D=3D [] :
      return
   indent =3D (" " * (1 + 2 * depth)) [0:-1]
   print indent + "+DEPTH=3D " + `depth`
   if len (tree) !=3D 4 :
      print indent + "***error - not a tree"
      print indent + "plane=3D " + `tree [0]`
      back =3D tree [1]
      list =3D tree [2]
      frnt =3D tree [3]
      if back =3D=3D None or back =3D=3D [] :
         print indent + "back =3D []"
      else :
         _pl3tree_prt (back, depth + 1)

   for leaf in list :
      print indent + "leaf length=3D " + `len (leaf)`
      print indent + "npolys=3D " + `len (leaf [0])` + \
         ", nverts=3D " + `sum (leaf [0])`
      print indent + "nverts=3D " + `shape (leaf [1]) [0]` + \
         ", nvals=3D " + `len (leaf [2])`

   if frnt =3D=3D None or frnt =3D=3D [] :
      print  indent + "frnt =3D []"
   else :
         _pl3tree_prt (frnt, depth + 1)
   print indent + "+DEPTH=3D " + `depth`

# =
------------------------------------------------------------------------

def _isosurface_slicer (m3, chunk, iso_index, _value) :
#  Have to remember here that getv3 can either return an array of=20
#  values, or a 2-list consisting of values and the corresponding cell
#  indices, the latter in the case of an irregular grid.
# Note: (ZCM 2/24/97) I have fixed slicers to return the vertex
# information and what used to be the global _xyz3, or None. Hence
# returning the tuple [tmp, None].

   tmp =3D getv3 (iso_index, m3, chunk)
   if type (tmp) =3D=3D ListType :
      tmp[0] =3D tmp [0] - _value
   else :
      tmp =3D tmp - _value
   return [tmp, None]

def _plane_slicer (m3, chunk, normal, projection) :
   # (ZCM 2/24/97) In all cases, return x as the last element of
   # the tuple. This eliminates the global _xyz3.

   x =3D xyz3(m3,chunk)
   irregular =3D type (chunk) =3D=3D ListType and len (chunk) =3D=3D 2 \
      or type (chunk) =3D=3D ArrayType and len (shape (chunk)) =3D=3D 1 =
\
      and type (chunk [0]) =3D=3D IntType
   if irregular :
      # Need to return a list, the first component being the x's,
      # the second being the relative cell list, and the third an offset
      verts =3D m3 [1] [0]
      cell_offset =3D 0
      if type (verts) =3D=3D ListType :
         totals =3D m3 [1] [3]
         if type (chunk) =3D=3D ListType :
            fin =3D chunk [0] [1]
         else :
            fin =3D chunk [-1]
         for j in range (len (verts)) :
            if fin <=3D totals [j] :
               break
         if j > 0 :
            cell_offset =3D totals [j - 1]
      if type (chunk) =3D=3D ListType :
         clist =3D arange (0, chunk [0] [1] - chunk [0] [0], typecode =
=3D Int)
      else :
         clist =3D chunk - cell_offset
      # In the irregular case we know x is ncells by 3 by something
      return [ [x [:,0] * normal [0] + x [:,1] * normal [1] + \
         x [:,2] * normal [2] - projection, clist, cell_offset], x]
   elif len (shape (x)) =3D=3D 5 : # It's ncells X 3 X 2 X 2 X 2
      return [x [:,0] * normal [0] + x [:,1] * normal [1] + \
         x [:,2] * normal [2] - projection, x]
   else :                    # It's 3 X ni X nj X nk
      return [x [0] * normal [0] + x [1] * normal [1] + x [2] * normal =
[2] -\
         projection, x]

def xyz3 (m3, chunk) :
#  xyz3 (m3, chunk)

#    return vertex coordinates for CHUNK of 3D mesh M3.  The CHUNK
#    may be a list of cell indices, in which case xyz3 returns a
#    (dimsof(CHUNK))x3x2x2x2 list of vertex coordinates.  CHUNK may
#    also be a mesh-specific data structure used in the slice3
#    routine, in which case xyz3 may return a 3x(ni)x(nj)x(nk)
#    array of vertex coordinates.  For meshes which are logically
#    rectangular or consist of several rectangular patches, this
#    is up to 8 times less data, with a concomitant performance
#    advantage.  Use xyz3 when writing slicing functions or coloring
#    functions for slice3.

   xyz =3D m3 [0] [0] (m3, chunk)
   return xyz

def xyz3_rect (m3, chunk) :
   m3 =3D m3 [1]
   if len (shape (chunk)) !=3D 1 :
      c =3D chunk
      # The difference here is that our arrays are 0-based, while
      # yorick's are 1-based; and the last element in a range is not
      # included in the result array.
      return m3 [1] [:,c [0, 0] - 1:1 + c [1, 0], c [0, 1] - 1:1 + c [1, =
1] ,
                     c [0, 2] - 1:1 + c [1, 2]]
   else :
      # Need to create an array of m3 [1] values the same size and shape
      # as what to_corners3 returns.
      # To avoid exceedingly arcane calculations attempting to
      # go backwards to a cell list, this branch returns the list
      # [<function values>, chunk]
      # ???????????? ^^^^^^^^^^^^
      # Then it is trivial for slice3 to find a list of cell
      # numbers in which fi has a negative value.
      dims =3D m3 [0]
      indices =3D to_corners3 (chunk, dims [1] + 1, dims [2] + 1)
      no_cells =3D shape (indices) [0]
      indices =3D ravel (indices)
      retval =3D zeros ( (no_cells, 3, 2, 2, 2), Float )
      m30 =3D ravel (m3 [1] [0, ...])
      retval [:, 0, ...] =3D reshape (take (m30, indices), (no_cells, 2, =
2, 2))
      m31 =3D ravel (m3 [1] [1, ...])
      retval [:, 1, ...] =3D reshape (take (m31, indices), (no_cells, 2, =
2, 2))
      m32 =3D ravel (m3 [1] [2, ...])
      retval [:, 2, ...] =3D reshape (take (m32, indices), (no_cells, 2, =
2, 2))
      return retval

_xyz3Error =3D "xyz3Error"

def xyz3_irreg (m3, chunk) :
   xyz =3D m3 [1] [1]
   if type (chunk) =3D=3D ListType and len (chunk) =3D=3D 2 :
      no_cells =3D chunk [0] [1] - chunk [0] [0]
      if type (m3 [1] [0]) =3D=3D ListType :
         totals =3D m3 [1] [3]
         start =3D chunk [0] [0]
         fin =3D chunk [0] [1]
         for i in range (len (totals)) :
            if fin <=3D totals [i] :
               break
         verts =3D m3 [1] [0] [i]
         if i > 0 :
            start =3D start - totals [i - 1]
            fin =3D fin - totals [i - 1]
         ns =3D verts [start:fin]
         shp =3D shape (verts)
      else :
         ns =3D m3 [1] [0] [chunk [0] [0]:chunk [0] [1]]   # This is a =
kXnv array
         shp =3D shape (m3 [1] [0])
   elif type (chunk) =3D=3D ArrayType and len (shape (chunk)) =3D=3D 1 =
and \
      type (chunk [0]) =3D=3D IntType :
      # chunk is an absolute cell list
      no_cells =3D len (chunk)
      if type (m3 [1] [0]) =3D=3D ListType :
         totals =3D m3 [1] [3]
         fin =3D max (chunk)
         for i in range (len (totals)) :
            if fin <=3D totals [i] :
               break
         verts =3D m3 [1] [0] [i]
         if i > 0 :
            start =3D totals [i - 1]
         else :
            start =3D 0
         verts =3D m3 [1] [0] [i]
         ns =3D take (verts, chunk - start)
         shp =3D shape (verts)
      else :
         ns =3D take (m3 [1] [0], chunk)
         shp =3D shape (m3 [1] [0])
   else :
      raise _xyz3Error, "chunk parameter has the wrong type."
   if shp [1] =3D=3D 8 : # hex
      retval =3D zeros ( (no_cells, 3, 2, 2, 2), Float)
      retval [:, 0] =3D \
         reshape (take (xyz [0], ravel (ns)), (no_cells, 2, 2, 2))
      retval [:, 1] =3D \
         reshape (take (xyz [1], ravel (ns)), (no_cells, 2, 2, 2))
      retval [:, 2] =3D \
         reshape (take (xyz [2], ravel (ns)), (no_cells, 2, 2, 2))
   elif shp [1] =3D=3D 6 : # prism
      retval =3D zeros ( (no_cells, 3, 3, 2), Float)
      retval [:, 0] =3D \
         reshape (take (xyz [0], ravel (ns)), (no_cells, 3, 2))
      retval [:, 1] =3D \
         reshape (take (xyz [1], ravel (ns)), (no_cells, 3, 2))
      retval [:, 2] =3D \
         reshape (take (xyz [2], ravel (ns)), (no_cells, 3, 2))
   elif shp [1] =3D=3D 5 : # pyramid
      retval =3D zeros ( (no_cells, 3, 5), Float)
      retval [:, 0] =3D \
         reshape (take (xyz [0], ravel (ns)), (no_cells, 5))
      retval [:, 1] =3D \
         reshape (take (xyz [1], ravel (ns)), (no_cells, 5))
      retval [:, 2] =3D \
         reshape (take (xyz [2], ravel (ns)), (no_cells, 5))
   elif shp [1] =3D=3D 4 : # tet
      retval =3D zeros ( (no_cells, 3, 4), Float)
      retval [:, 0] =3D \
         reshape (take (xyz [0], ravel (ns)), (no_cells, 4))
      retval [:, 1] =3D \
         reshape (take (xyz [1], ravel (ns)), (no_cells, 4))
      retval [:, 2] =3D \
         reshape (take (xyz [2], ravel (ns)), (no_cells, 4))
   else :
      raise _xyz3Error, "Funny number of cell faces: " + `shp [1]`
   return retval

def xyz3_unif (m3, chunk) :
   m3 =3D m3 [1]
   n =3D m3 [1]
   if len (chunk.shape) !=3D 1 :
      c =3D chunk
      i =3D c [0] - 1
      dn =3D c [1] + 1 - i
      xyz =3D zeros ( (3, dn [0], dn [1], dn [2]), Float)
   else :
      dims =3D m3 [0]
      nj =3D dims [1]
      nk =3D dims [2]
      njnk =3D nj * nk
      zchunk =3D chunk % nk
      ychunk =3D chunk / nk % nj
      xchunk =3D chunk / njnk
      xyz =3D zeros ( (len (chunk), 3, 2, 2, 2), Float )
      ijk0 =3D array ( [zeros ( (2, 2), Int ), ones ( (2, 2), Int )])
      ijk1 =3D array ( [ [0, 0], [1, 1]], Int )
      ijk1 =3D array ( [ijk1, ijk1] , Int )
      ijk2 =3D array ( [ [0, 1], [0, 1]], Int )
      ijk2 =3D array ( [ijk2, ijk2] , Int )
   if len (n) =3D=3D 2: # we have dxdydz and x0y0z0
      dxdydz =3D n [0]
      x0y0z0 =3D n [1]
      if len (shape (chunk)) !=3D 1:
         # Convert the increment and size into array coordinates
         # -- consecutive values
         xx =3D arange (dn [0], typecode =3D Float ) * dxdydz [0] / (dn =
[0] - 1)
         yy =3D arange (dn [1], typecode =3D Float ) * dxdydz [1] / (dn =
[1] - 1)
         zz =3D arange (dn [2], typecode =3D Float ) * dxdydz [2] / (dn =
[2] - 1)
         xyz [0] =3D x0y0z0 [0] + i [0] * dxdydz [0] + multiply.outer (
            multiply.outer ( xx, ones (dn [1], Float )),
            ones (dn [2], Float ))
         xyz [1] =3D x0y0z0 [1] + i [1] * dxdydz [0] + \
            multiply.outer ( ones (dn [0], Float ), \
            multiply.outer ( yy, ones (dn [2], Float )))
         xyz [2] =3D x0y0z0 [2] + i [2] * dxdydz [0] + \
            multiply.outer ( ones (dn [0], Float ), \
            multiply.outer ( ones (dn [1], Float ), zz))
      else :
         # -- nonconsecutive values
         xyz [:, 0] =3D add.outer ( xchunk, ijk0) * dxdydz [0] + x0y0z0 =
[0]
         xyz [:, 1] =3D add.outer ( ychunk, ijk1) * dxdydz [1] + x0y0z0 =
[1]
         xyz [:, 2] =3D add.outer ( zchunk, ijk2) * dxdydz [2] + x0y0z0 =
[2]
   elif type (n) =3D=3D ListType and len (n) =3D=3D 3: # We have three =
one-dimensional arrays.
      xx =3D n [0]
      yy =3D n [1]
      zz =3D n [2]
      n0 =3D len (xx)
      n1 =3D len (yy)
      n2 =3D len (zz)
      if len (shape (chunk)) !=3D 1:
         # Convert the increment and size into array coordinates
         # -- consecutive values
         xyz [0] =3D multiply.outer (
            multiply.outer ( xx [i [0]:i [0] + n0],  ones (n1, Float )), =
\
            ones (n2, Float ))
         xyz [1] =3D  multiply.outer ( ones (n0, Float ), \
            multiply.outer ( yy [i [1]: i[1] + n1], ones (n2, Float )))
         xyz [2] =3D multiply.outer ( ones (n0, Float ), \
            multiply.outer ( ones (n1, Float ), zz [i [2]: i[2] + n2]))
      else :
         # -- nonconsecutive values
         xyz [:, 0] =3D reshape (take (xx, ravel (add.outer (xchunk, =
ijk0))),
            (len (chunk),  2, 2, 2))
         xyz [:, 1] =3D reshape (take (yy, ravel (add.outer (ychunk, =
ijk1))),
            (len (chunk),  2, 2, 2))
         xyz [:, 2] =3D reshape (take (zz, ravel (add.outer (zchunk, =
ijk2))),
            (len (chunk),  2, 2, 2))
   return xyz

def to_corners3 (list, nj, nk) :
#  to_corners3(list, nj, nk)
#    convert an array of cell indices in an (ni-1)-by-(NJ-1)-by-(NK-1)
#    logically rectangular grid of cells into the list of
#    len(LIST)-by-2-by-2-by-2 cell corner indices in the
#    corresponding ni-by-NJ-by-NK array of vertices.
#    Note that this computation in Yorick gives an absolute offset
#    for each cell quantity in the grid. In Yorick it is legal to
#    index a multidimensional array with an absolute offset. In
#    Python it is not. However, an array can be flattened if
#    necessary.
#    Other changes from Yorick were necessitated by row-major
#    order and 0-origin indices, and of course the lack of
#    Yorick array facilities.

   njnk =3D nj * nk
   kk =3D list / (nk - 1)
   list =3D list + kk + nk * (kk / (nj - 1))
   adder =3D array ( [ [ [0, 1], [nk, nk + 1]],
                     [ [njnk, njnk + 1], [nk + njnk, nk + njnk + 1]]])
   res =3D zeros ( (len (list), 2, 2, 2), Int)
   for i in range (len(list)):
      res [i] =3D adder + list [i]
   return res

------=_NextPart_000_0011_01BD93B1.A9ACA3C0
Content-Type: application/octet-stream;
	name="gist.py"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="gist.py"

# Copyright (c) 1996, 1997, The Regents of the University of California.
# All rights reserved.  See LEGAL.LLNL for full text and disclaimer.
from Numeric import *
import sys, os	# To be sure expand_path has posixpath and we have =
sys.path
from gistC import *
from help import help
from shapetest import *

# Parameters used by pltitle and xytitles
pltitle_height=3D 18;
pltitle_font=3D "helvetica";

# Parameters used by plmk and plmk_default
_plmk_count =3D 0
_plmk_msize =3D _plmk_color =3D _plmk_width =3D None

# delete the current graphics window, or graphics window N (0-7).
def winkill(*N):
  if N:
    window(N[0], display=3D"", hcp=3D"")
  else:
    window(display=3D"", hcp=3D"")

# Plot TITLE centered above the coordinate system for any of the
# standard Gist styles.  You will need to customize this for other
# plot styles.
def pltitle(title):
  vp =3D viewport()
  xmidpt =3D (vp[0] + vp[1])/2.0
  plt( title, xmidpt, vp[3] + 0.02,
       font=3Dpltitle_font, justify=3D"CB", height=3Dpltitle_height)

# Set limits on the y-axis
def ylimits(ymin=3D'u',ymax=3D'u'): limits('u','u',ymin,ymax)

# Return the 1-origin zone index for the point clicked in
# for the default mesh, or for the mesh (X,Y) (region array IREG).
# Number of args can be 0, 2, or 3.
def moush(*arg):
  narg =3D len(arg)
  if narg =3D=3D 3: # (y, x, ireg)
    xy =3D mouse (-1, 0, "<Click mouse in mesh>")
    if xy =3D=3D None: return None
    return mesh_loc (xy[1], xy[0], arg[0], arg[1], arg[2]);
  elif narg =3D=3D 2: # (y, x)
    xy =3D mouse (-1, 0, "<Click mouse in mesh>")
    if xy =3D=3D None: return None
    return mesh_loc (xy[1], xy[0], arg[0], arg[1]);
  elif narg =3D=3D 0: # ()
    xy =3D mouse (-1, 0, "<Click mouse in mesh>")
    if xy =3D=3D None: return None
    return mesh_loc (xy[1], xy[0]);
  else:
    print "Moush takes 0, 2, or 3 args: ( [ y, x [ , ireg ] ] )"
    return None

# Create an encapsulated PostScript file.  Requires Ghostscript and its
# associated ps2epsi utility.
def eps(name):
  import os
  name =3D name + ".ps"
  window (hcp =3D name, dump =3D 1, legends =3D 0)
  hcp ()
  window (hcp=3D"")
  os.system ("ps2epsi " + name)
  os.system ("rm " + name)

def xytitles(xtitle =3D "", ytitle =3D "", delta =3D (0.,0.)):
  vp =3D viewport()
  xmidpt =3D (vp[0] + vp[1])/2.0
  ymidpt =3D (vp[2] + vp[3])/2.0
  if len(xtitle) > 0:
    plt(xtitle, xmidpt, vp[2] - 0.050 + delta[1],
        font=3Dpltitle_font, justify=3D"CT", height=3Dpltitle_height)
  if len(ytitle) > 0:
    plt(ytitle, vp[0] - 0.050 + delta[0], ymidpt,
        font=3Dpltitle_font, justify=3D"CB", height=3Dpltitle_height, =
orient=3D1)

def _spanz(lb,ub,n):
  if n < 3: raise ValueError, '3rd arg must be at least 3'
  c =3D 0.5*(ub - lb)/(n - 1.0)
  b =3D lb + c
  a =3D (ub - c - b)/(n - 2.0)
  return map(lambda x,A=3Da,B=3Db: A*x + B, arange(n-1))

# predefined markers: square, +, delta, circle, diamond, x, grad
_seq =3D _spanz(-pi,pi,37)
_plmk_markers =3D (
  array([[-1,1,1,-1],[-1,-1,1,1]])*.007,
  array([[-4,-1,-1,1,1,4,4,1,1,-1,-1,-4],
    [-1,-1,-4,-4,-1,-1,1,1,4,4,1,1]])*.007/sqrt(7),
  array([[-sqrt(3),sqrt(3),0],[-1,-1,2]])*.007/sqrt(.75*sqrt(3)),
  array([cos(_seq),sin(_seq)])*.007/(pi/4.),
  array([[-1,0,1,0],[0,-1,0,1]])*.007*sqrt(2),
  array([[-1,-2.5,-1.5,0,1.5,2.5,1,2.5,1.5,0,-1.5,-2.5],
    =
[0,-1.5,-2.5,-1,-2.5,-1.5,0,1.5,2.5,1,2.5,1.5]])*.007*sqrt(2)/sqrt(7),
  array([[0,sqrt(3),-sqrt(3)],[-2,1,1]])*.007/sqrt(.75*sqrt(3))
  )
del(_seq)

def =
plmk(y,x=3DNone,marker=3DNone,width=3DNone,color=3DNone,msize=3DNone):
  global _plmk_count
  global _plmk_color, _plmk_width, _plmk_msize
  color_dict =3D { 'bg':-1, 'fg':-2, 'black':-3, 'white':-4, 'red':-5,
    'green':-6, 'blue':-7, 'cyan':-8, 'magenta':-9, 'yellow':-10 }

  z =3D None

  if marker =3D=3D None:
    marker =3D _plmk_markers[(_plmk_count)%7]
    _plmk_count =3D _plmk_count + 1
  elif type(marker) =3D=3D type(0):
    marker =3D _plmk_markers[marker-1];

  xm =3D marker[0]
  ym =3D marker[1]
  if not msize: msize =3D _plmk_msize;
  if msize:
    xm =3D xm * msize;
    ym =3D ym * msize;

  if not color: color =3D _plmk_color;
  ecolor =3D color;
  if type(color) =3D=3D type(""):
    color =3D color_dict[color];
 =20
  if not width: width =3D _plmk_width;
  if width >=3D 10:
    if not color:
      color =3D ecolor =3D -2 # magic number for "fg"
    z =3D ones(1+len(y)) * color
    z =3D z.astype(UnsignedInt8) # convert array to type <unsigned char>
    width =3D None

  n =3D ones(1+len(y));
  n[0] =3D len(ym);
  if not x: x =3D 1 + arange(len(y));
  plfp( z, concatenate((ym,y)), concatenate((xm,x)),n,
        edges=3D1, ewidth=3Dwidth, ecolor=3Decolor)

# Set default color, msize, and width values for plmk.  Use
# width=3D10 to get solid fills.  With no parameters, plmk_default
# restores the initial default values.
def plmk_default(color=3DNone, msize=3DNone, width=3DNone):
  global _plmk_color, _plmk_width, _plmk_msize
  if color: _plmk_color =3D color
  if width: _plmk_width =3D width
  if msize: _plmk_msize =3D msize
  if not (color or width or msize):
    _plmk_msize =3D _plmk_color =3D _plmk_width =3D None

from arrayfns import *
from types import *

def spann (zmin, zmax, n =3D 8, fudge =3D 0, force =3D 0) :
#    return no more than N equally spaced "nice" numbers between
#    ZMIN and ZMAX.
#    HAR! I added a "force" parameter to force exactly n values
#    to be returned.
   dz =3D (zmax - zmin) / max (float (n), 0.)
   if dz =3D=3D 0. :
      dz =3D abs (zmin)
   if (dz !=3D 0.) :
      power =3D floor (log10 (dz) + 0.00001)
      base =3D dz / (10. ** power)
      if base > 5.00001 :
         base =3D 1.0
         power =3D power + 1.0
      elif base > 2.00001 :
         base =3D 5.0
      else :
         base =3D 2.0
      # Round dz up to nearest "nice" number
      dz =3D base * 10.0 ** power
      zmin =3D ceil (zmin / dz - fudge)
      zmax =3D floor (zmax / dz + fudge)
      if (force =3D=3D 0) :
         nz =3D int (zmax - zmin + 1.0)
      else :
         nz =3D n
      if nz > 1 :
         levs =3D span (zmin * dz, zmax * dz, nz)
      else :
         if nz < 1 :
            if base < 1.5 :
               base =3D 5.0
               power =3D power - 1
            elif base < 2.5 :
               base =3D 1.0
            else :
               base =3D 2.0
            dz =3D base * 10.0 ** power
            zmin =3D ceil (zmin / dz + 0.001)
         levs =3D array ( [zmin * dz])
   else :
      levs =3D array ( [-1.0, 1.0])
   return (levs)

_ContourError =3D "ContourError"

def plfc (z, y, x, ireg, contours =3D 20, colors =3D None, region =3D 0,
   triangle =3D None, scale =3D "lin") :
#
# plfc (z, y, x, ireg, contours =3D 20, colors =3D None, region =3D 0,
#  triangle =3D None, scale =3D "lin")
#

     # 1. Get contour colors
     vcmin =3D min (ravel (z))
     vcmax =3D max (ravel (z))
     if type (contours) =3D=3D IntType :
        n =3D contours
        vc =3D zeros (n + 2, Float)
        vc [0] =3D vcmin
        vc [n + 1] =3D vcmax
        if scale =3D=3D "lin" or scale =3D=3D None :
            #    This stuff is in lieu of the spann stuff in Yorick.
            # Note that my calculation and spann give different
            # results, and both are different from how plc plots
            # the contour lines. Thus if you want filled contours
            # with lines superimposed on top, the lines will not
            # match the contours.
            # The only way to get around this is to send both
            # plc and plfc the array of levels that you want.
            vc [1:n + 1] =3D vcmin + arange (1, n + 1, typecode =3D =
Float) * \
               (vcmax - vcmin) / (n + 1)
#           vc [1:n + 1] =3D spann (vcmin, vcmax, n, force =3D 1)
        elif scale =3D=3D "log" :
            vc [1:n + 1] =3D vcmin + exp (arange (1, n + 1, typecode =3D =
Float) * \
               log (vcmax - vcmin) / (n + 1))
        elif scale =3D=3D "normal" :
            zlin =3D ravel (z)
            lzlin =3D len (zlin)
            zbar =3D add.reduce (zlin) / lzlin
            zs =3D sqrt ( (add.reduce (zlin ** 2) - lzlin * zbar ** 2) /
                (lzlin - 1))
            z1 =3D zbar - 2. * zs
            z2 =3D zbar + 2. * zs
            diff =3D (z2 - z1) / (n - 1)
            vc [1:n + 1] =3D z1 + arange (n) * diff
        else :
            raise _ContourError, "Incomprehensible scale parameter."
     elif type (contours) =3D=3D ArrayType and contours.typecode () =
=3D=3D Float :
        n =3D len (contours)
        vc =3D zeros (n + 2, Float)
        vc [0] =3D vcmin
        vc [n + 1] =3D vcmax
        vc [1:n + 1] =3D sort (contours)
     else :
        raise _ContourError, "Incorrect contour specification."
     if colors =3D=3D None :
        colors =3D (arange (n + 1, typecode =3D Float) * (199. / =
n)).astype ('b')
     else :
        colors =3D array (colors)
        if len (colors) !=3D n + 1 :
           raise "PLFC_Error", \
              "colors must specify one more color than contours."
        if colors.typecode !=3D 'b' :
           colors =3D bytscl (colors)

     if triangle =3D=3D None :
        triangle =3D zeros (z.shape, Int16)

     # Set mesh first
     plmesh (y, x, ireg, triangle =3D triangle)
     for i in range (n + 1) :
        [nc, yc, xc] =3D contour (array ( [vc [i], vc [i + 1]]), z)
        if (is_scalar(nc) and nc =3D=3D 0 or nc =3D=3D None) :
           continue
        plfp ( (ones (len (nc)) * colors [i]).astype ('b'),
           yc, xc, nc, edges =3D 0)

------=_NextPart_000_0011_01BD93B1.A9ACA3C0--




From David Ascher <da@skivs.ski.org>  Tue Jun  9 22:44:11 1998
From: David Ascher <da@skivs.ski.org> (David Ascher)
Date: Tue, 9 Jun 1998 14:44:11 -0700 (PDT)
Subject: [Matrix-SIG] [PSA MEMBERS] Numeric Python Set function
In-Reply-To: <13692.16186.16446.103908@lisboa.ifm.uni-kiel.de>
Message-ID: <Pine.SUN.3.96.980608131635.25459A-100000@skivs.ski.org>

On Mon, 8 Jun 1998, Janko Hauser wrote:

> Am I right, that these forms of indexing are only possible with a
> ravel(a) array? Isn't it possible to expand the slice type, so one can 
> define indexes along each dimension? (give me any row, where soem
> value is bigger than 10)

No and yes, respectively.  

x[sometrue(x>10)] or x[sometrue(swapaxes(x,0,N) > 10)]

or some other variant for higher rank forms should work.

Isn't this just a 'mask' variant?

as far as multiple axes is concerned, there's nothing to prevent something
like:

x[x>100,sin(x)==1,:,NewAxis] = 3 

from working.  The hard part is determining what 'working' means. =)

> If the slice type defines something like this other sequence objects
> can start to use this way of indexing with the definition of an
> additional method (is it getitem or getslice?).

I'm not sure I understand this sentence.

--david





From aaron@cs.rutgers.edu  Wed Jun 10 11:33:14 1998
From: aaron@cs.rutgers.edu (Aaron Watters)
Date: Wed, 10 Jun 1998 06:33:14 -0400
Subject: [Matrix-SIG] [PSA MEMBERS] Numeric Python Set function
References: <Pine.SUN.3.96.980608100648.19182A-100000@skivs.ski.org> <357C71AF.3D6@ix.netcom.com>
Message-ID: <357E60EA.FC064DE2@cs.rutgers.edu>

> Aaron Watters knows about seventeen flavors of how to handle
> unavailables, but one good way for array computation is the S way.

Yes, anything please.  I'm a big believer in precedent.
If Paul has experience with something that worked, Numeric should
use it.

BTW, this is where it'd be nice to have Jim H. back, just deciding
to do it one way and then doing it.  I think this subject has been coming
up for well over a year now, and that's just since I started following the
list.  Design by committee -- not known to be the ideal technique
to get things done.  -- Aaron Watters




From aaron@cs.rutgers.edu  Fri Jun 12 15:36:41 1998
From: aaron@cs.rutgers.edu (Aaron Watters)
Date: Fri, 12 Jun 1998 10:36:41 -0400
Subject: [Matrix-SIG] ANN: Network maximum flow module
Message-ID: <35813CF9.29DA0DA1@cs.rutgers.edu>

ANNOUNCE MPM.py Network Maximum flow algorithm implementation

  GO: http://www.pythonpros.com/arw/MPM/

MPM.py provides a Python based implementation of the
MPM network maximum-flow algorithm from

V.M. Malhotra, M. Pramodh-Kumar and S.N. Maheshwari
"An O(V**3) algorithm for finding maximum flows in networks"
Information Processing Letters, 7 (1978), 277-278.

The module is implemented in Python.
The MPM algorithm is one of the better algorithms for finding network
maximum flows.

This module will certainly be easy to use and fast enough for network
flow maximization problems with thousands of nodes and edges.

For example:
============

A simple motivating example may be stolen from

A Quantitative Approach to Management
Levin, Ruben, and Stinson
McGraw Hill, 1986. p.542

There are a number of freeways connected by intersections
(interchanges).  Each of the freeways has a maximum number of
cars that can pass across it per hour in each direction (and
for some "one way" freeways the capacity in one direction is
zero).  We number the intersections 1 through 6 and depict the
freeways as "arcs" between the intersections:

   6      0
(1)--------(2)
 | \        | \
 |  \5      |  \4
 |3  \      |7  \
 |    \     |    \
 |     \    |     \
 |      \9  |2     \5
 |0      \  |       \
 |  5  3  \ |  5  4  \
(4)--------(3)-------(5)
  \                  /
   \                /2
    \7             /
     \            /
      \          /
       \        /
        \0     /0
         \    /
          \  /
           (6)

Furthermore we make the somewhat artificial assumption that
the only "exits" from the freeway system are at intersection 6
(the sink) and the only "onramps" are at intersection 1 (the source)
<b>and no rest stops are permitted!</b>
Above

    6     0
(1)---------(2)

Indicates that intersection 1 is connected by a freeway
to intersection 2 and the maximum cars-per-hour from 1 to 2
is 6000 and the maximum from 2 to 1 is 0.

The network maximum flow problem is to determine the maximum
flow assignment for a network.  In the above network we want to
determine
the maximal number of cars per hour that can pass across the network
(without stopping) entering at intersection 1 and leaving at
intersection 6.

Using MPM.py this model may be encoded and maximized as follows:

def test2():
    D = {}
    # 6000 cars/hour can travel from intersection 1 to intersection 2
    D[1,2] = 6000
    D[1,3] = 5000
    D[1,4] = 3000
    D[2,3] = 7000 #capacities from intersection 2
    D[2,5] = 4000
    D[3,2] = 2000 #capacities from intersection 3
    D[3,1] = 9000
    D[3,2] = 2000
    D[3,4] = 3000
    D[3,5] = 5000
    D[4,3] = 5000 #capacities from intersection 4
    D[4,6] = 7000
    D[5,3] = 4000 #capacities from intersection 5
    D[5,6] = 2000
    (total, flow, net) = maxflow(source=1, sink=6, capacities=D)
    print "maximum at", total, "cars per hour"
    print "travelling"
    edges = flow.keys()
    edges.sort()
    for edge in edges:
        (i1, i2) = edge
        fl = flow[edge]
        if fl>0:
           print fl, "cars from intersection", i1, "to", i2

When executed the function prints

maximum at 8000 cars per hour
travelling
5000 cars from intersection 1 to 3
3000 cars from intersection 1 to 4
3000 cars from intersection 3 to 4
2000 cars from intersection 3 to 5
6000 cars from intersection 4 to 6
2000 cars from intersection 5 to 6

Thus the following flow assignment maximizes conservative flow
on the network:

     0   0
(1)--------(2)
 | \        | \
 |  \5      |  \0
 |3  \      |0  \
 |    \     |    \
 |     \    |     \
 |      \0  |0     \0
 |0      \  |       \
 |  0  3  \ |  2  0  \
(4)--------(3)-------(5)
  \                  /
   \                /
    \6             /2
     \            /
      \          /
       \        /
        \0     /0
         \    /
          \  /
           (6)

Please look at http://www.pythonpros.com/arw/MPM for
more information and downloads.

   -- Aaron Watters
===
"To repeat that, this time a little more slowly..." -Wilf




From Paul F. Dubois" <dubois1@llnl.gov  Mon Jun 15 22:38:17 1998
From: Paul F. Dubois" <dubois1@llnl.gov (Paul F. Dubois)
Date: Mon, 15 Jun 1998 14:38:17 -0700
Subject: [Matrix-SIG] LLNLPython3
Message-ID: <001101bd98a5$e8ca74d0$2d247380@xfiles.llnl.gov>

A new release of LLNL's Python extensions distribution is available at
ftp-icf.llnl.gov/pub/python. File README.html explains things; file
LLNLPython.tgz is now a link that points you to the latest and greatest, in
this case LLNLPython3.tgz.

Similarly, there are now links NumPy.exe and RNG.exe for Windows users.

These links enable CNRI (and you) to reference this distribution without
keeping up with our releases.

This release contains some fixes for the graphics packages, NumPy's
documentation, and a bug in UserArray. If you got LLNLPython2.tgz and you
aren't having a problem, you probably don't need to bother. Please see the
release notes for details.

There are links to these files, and lots of documentation, at
http://xfiles.llnl.gov




From bsd@scripps.edu  Tue Jun 16 23:04:12 1998
From: bsd@scripps.edu (Bruce Duncan)
Date: Tue, 16 Jun 1998 15:04:12 -0700 (PDT)
Subject: [Matrix-SIG] Simple Suggestion for extending Numeric: Max/Min constants
Message-ID: <Pine.SGI.3.96.980616150035.19144A-100000@solomon>

Greetings,

Because Numeric deals primarily with well-defined floating point and
integer types, I suggest that symbolic constants for MinFloat, MaxFloat,
MinDouble, MaxDouble, etc., be added in some "portable" way;
perhaps as a Python package under Numeric, e.g., Numeric.limits.

-bsd-

Bruce Duncan
The Scripps Research Institute 
bsd "is located at" scripps "in the domain" edu  # anti spam...



From Oliphant.Travis@mayo.edu  Thu Jun 18 09:01:33 1998
From: Oliphant.Travis@mayo.edu (Travis E. Oliphant)
Date: Thu, 18 Jun 1998 03:01:33 -0500
Subject: [Matrix-SIG] Reading binary data from file into NumPy arrays: numpyio
Message-ID: <3588C95D.B6EAC783@mayo.edu>

Hello all,

I needed a relatively low-level method to load arbitrary binary data
files 
into NumPy arrays, so I wrote C-extension code to do it after learning 
a little about the NumPy API through the source code.

I've called the module numpyio and it allows reading and writing
aribrary data-types to an open file stream.  There are options to do
byte-swapping as well as type-casting on read-in.

There is also a packbits and unpackbits function as part of the module
to read and write binary-valued data (each element is only 0 or 1).

This module has come in handy as I've used it to create another module
(written in Python) to read and write Analyze-format medical imaging
volumes into Python for data analysis.

If anyone is interested in my source code, let me know and I will send
it to you or let me know where to put it.


Travis Oliphant


From Oliphant.Travis@mayo.edu  Thu Jun 18 09:06:19 1998
From: Oliphant.Travis@mayo.edu (Travis E. Oliphant)
Date: Thu, 18 Jun 1998 03:06:19 -0500
Subject: [Matrix-SIG] Python binding of FFTW package
Message-ID: <3588CA7B.50CFA8B@mayo.edu>

Hello,

I wanted to make anyone who is interested aware that I've wrapped up the
FFTW package (using SWIG) for use as an extension module for python and
NumPy.

Two versions are available: fftwF and fftwD for doing N-D (fast,
optionally in-place) FFT's in python on Complex-Float and ComplexDouble
arrays.

Let me know if you want the source code of the wrapper module which was
constructed with SWIG (with suitable uses of typemaps to point data to
NumPy) arrays.

Thanks,

Travis Oliphant


From H.Jansen@math.tudelft.nl  Thu Jun 18 13:56:33 1998
From: H.Jansen@math.tudelft.nl (Henk Jansen)
Date: Thu, 18 Jun 1998 14:56:33 +0200 (METDST)
Subject: [Matrix-SIG] int[] -> array (in C)
Message-ID: <01IYDWFLNBUQ000WVF@TUDRNV.TUDelft.NL>

Bit overwhelmed (and confused) by the variety of array assignment
methods in "arrayobject.c", I just can't work out how to do a simple
thing like this (assignment of ints to an array): 

  ...
  int nd=2, n=100, k=5;
  int shape[nd];
  int tmp[k];

  shape[0] = n;
  shape[1] = k;

  array = (PyArrayObject*)PyArray_FromDims (nd, shape, PyArray_INT);

  for (i=0, i<n, ++i){
	a_func (tmp);       /* just a function which modifies tmp */
        for (j=0, j<k, ++i){

        # and now in Python syntax :

	array[i,:k] = tmp[:k]   /* How to do this in C ??? */

	}
  }

  Can anyone share with me his/her experience?

  Thanks,

  Henk.

-- 
  -----------------------------------------------------------------------
 | Henk Jansen                                hjansen@math.tudelft.nl    |
 | Delft University of Technology             P.O.Box 5031  (Mekelweg 4) |
 | > Information Technoloy and Systems (ITS)  2600 GA  Delft             |
 | >> Mathematics (TWI)                       The Netherlands            |
 | >>> Applied Analysis (TA)                  phone: +31(0)15.278.7295   |
 | >>>> Large Scale Models (WAGM)             fax:   +31(0)15.278.7209   |
  -----------------------------------------------------------------------



From hinsen@cnrs-orleans.fr  Thu Jun 18 14:22:23 1998
From: hinsen@cnrs-orleans.fr (hinsen@cnrs-orleans.fr)
Date: Thu, 18 Jun 1998 15:22:23 +0200 (DFT)
Subject: [Matrix-SIG] int[] -> array (in C)
In-Reply-To: <01IYDWFLNBUQ000WVF@TUDRNV.TUDelft.NL> (message from Henk Jansen
 on Thu, 18 Jun 1998 14:56:33 +0200 (METDST))
References: <01IYDWFLNBUQ000WVF@TUDRNV.TUDelft.NL>
Message-ID: <199806181322.PAA12412@dirac.cnrs-orleans.fr>

> Bit overwhelmed (and confused) by the variety of array assignment
> methods in "arrayobject.c", I just can't work out how to do a simple

Are there any? The C API deals only with creating array objects in
many different ways. I do assignments by explicit assignment to the
elements in the array data space, i.e. by treating the array data
space as a C array. The details depend on the number of dimensions, of
course.

It would be nice to have some API functions for accessing and
changing array elements, but I am not even sure what form they
should take.
-- 
-------------------------------------------------------------------------------
Konrad Hinsen                            | E-Mail: hinsen@cnrs-orleans.fr
Centre de Biophysique Moleculaire (CNRS) | Tel.: +33-2.38.25.55.69
Rue Charles Sadron                       | Fax:  +33-2.38.63.15.17
45071 Orleans Cedex 2                    | Deutsch/Esperanto/English/
France                                   | Nederlands/Francais
-------------------------------------------------------------------------------


From hinsen@cnrs-orleans.fr  Thu Jun 18 14:25:14 1998
From: hinsen@cnrs-orleans.fr (hinsen@cnrs-orleans.fr)
Date: Thu, 18 Jun 1998 15:25:14 +0200 (DFT)
Subject: [Matrix-SIG] Reading binary data from file into NumPy arrays: numpyio
In-Reply-To: <3588C95D.B6EAC783@mayo.edu> (Oliphant.Travis@mayo.edu)
References: <3588C95D.B6EAC783@mayo.edu>
Message-ID: <199806181325.PAA11444@dirac.cnrs-orleans.fr>

[Description of a very interesting module deleted.]

> If anyone is interested in my source code, let me know and I will send
> it to you or let me know where to put it.

That again raises the issue of distributing NumPy-related code.
How about creating an archive on starship? I'd volunteer to take care
of it. Or does someone have a better idea?

Konrad.
-- 
-------------------------------------------------------------------------------
Konrad Hinsen                            | E-Mail: hinsen@cnrs-orleans.fr
Centre de Biophysique Moleculaire (CNRS) | Tel.: +33-2.38.25.55.69
Rue Charles Sadron                       | Fax:  +33-2.38.63.15.17
45071 Orleans Cedex 2                    | Deutsch/Esperanto/English/
France                                   | Nederlands/Francais
-------------------------------------------------------------------------------


From jhauser@ifm.uni-kiel.de  Thu Jun 18 17:27:51 1998
From: jhauser@ifm.uni-kiel.de (Janko Hauser)
Date: Thu, 18 Jun 1998 18:27:51 +0200 (CEST)
Subject: [Matrix-SIG] Reading binary data from file into NumPy arrays:
 numpyio
In-Reply-To: <199806181325.PAA11444@dirac.cnrs-orleans.fr>
References: <3588C95D.B6EAC783@mayo.edu> <199806181325.PAA11444@dirac.cnrs-orleans.fr>
Message-ID: <13705.15902.306063.877986@lisboa.ifm.uni-kiel.de>

hinsen writes:
 > [Description of a very interesting module deleted.]
 > 
 > > If anyone is interested in my source code, let me know and I will send
 > > it to you or let me know where to put it.
 > 
 > That again raises the issue of distributing NumPy-related code.
 > How about creating an archive on starship? I'd volunteer to take care
 > of it. Or does someone have a better idea?

I think we definetly need something like an archive. But I fear that
we also need some tests for quality (justifing from my own attempts
to give other some code).

So my wish is make more code public available for testing and also
different solutions to a given problem. Than in a second pass collect
the more useful pieces and make a central archive of them. I fear if
we only have a contrib-like directory and there is some bad or
not enough tested code in it, the hole package (NumPy) get bad
credits. If we can separate this and perhaps also have some ways for
regression tests for the released code all will look better.

__Janko




From hinsen@cnrs-orleans.fr  Thu Jun 18 17:50:25 1998
From: hinsen@cnrs-orleans.fr (hinsen@cnrs-orleans.fr)
Date: Thu, 18 Jun 1998 18:50:25 +0200 (DFT)
Subject: [Matrix-SIG] Reading binary data from file into NumPy arrays:
 numpyio
In-Reply-To: <13705.15902.306063.877986@lisboa.ifm.uni-kiel.de> (message from
 Janko Hauser on Thu, 18 Jun 1998 18:27:51 +0200 (CEST))
References: <3588C95D.B6EAC783@mayo.edu> <199806181325.PAA11444@dirac.cnrs-orleans.fr> <13705.15902.306063.877986@lisboa.ifm.uni-kiel.de>
Message-ID: <199806181650.SAA20212@dirac.cnrs-orleans.fr>

> I think we definetly need something like an archive. But I fear that
> we also need some tests for quality (justifing from my own attempts
> to give other some code).

We could have a two-level archive:
- contributed code, offered as-is without any verification
- tested code, which has been compiled on a variety of machines
  and comes with some documentation and test cases.

In a research environment (where many of us work) it is necessary to
share also less stable code; many highly specific modules might never
make it to an "official" level. As long as this is made clear, I see
no problem.
-- 
-------------------------------------------------------------------------------
Konrad Hinsen                            | E-Mail: hinsen@cnrs-orleans.fr
Centre de Biophysique Moleculaire (CNRS) | Tel.: +33-2.38.25.55.69
Rue Charles Sadron                       | Fax:  +33-2.38.63.15.17
45071 Orleans Cedex 2                    | Deutsch/Esperanto/English/
France                                   | Nederlands/Francais
-------------------------------------------------------------------------------


From Paul F. Dubois" <dubois1@llnl.gov  Thu Jun 18 17:47:03 1998
From: Paul F. Dubois" <dubois1@llnl.gov (Paul F. Dubois)
Date: Thu, 18 Jun 1998 09:47:03 -0700
Subject: [Matrix-SIG] Reading binary data from file into NumPy arrays:         numpyio
Message-ID: <003001bd9ad8$b9b1e9a0$52120f80@pduboispc.llnl.gov>

This is part of the dilemma I face with even the parts I have already
inherited in the distribution. With the exception of the core pieces the
rest of the modules such as the lapack, fft, ..., are all just extras. Now
for the random array facility, for example, there is one in the distribution
that looks more "official" than the other one but it isn't of higher
quality, it is just different. Now I see someone posting FFT and binary data
readers; we have an FFT package and we have something that is superior to
binary data for Unix, and it will soon be available on Windows. So how do I
decide what to "bless" and what not to? I suspect blessing and regression
testing all that stuff would soon be a full-time job.

Maybe the right idea is like Amazon.com; you list all the books but have
places for reader and author "reviews". This makes it cavaet emptor but
wasn't it always so? I'm thinking of web site that is a guide to the
contributed packages. Actually, I even think I know how to write such a site
pretty easily. Then we could just have the sources to all the packages
available on an even footing.

This is clearly identical to the general problem of what Guido "blesses" or
not. I think it less likely that you can pick a computer-science area that
Guido doesn't know anything about than you can pick some area of numerical
analysis, probability, and statistics that I know nothing about. Clearly
nobody is capable of knowing all this stuff. The documentation for the NAG
library runs nine volumes.

-----Original Message-----
From: Janko Hauser <jhauser@ifm.uni-kiel.de>
To: hinsen <hinsen@cnrs-orleans.fr>
Cc: matrix-sig@python.org <matrix-sig@python.org>
Date: Thursday, June 18, 1998 9:22 AM
Subject: Re: [Matrix-SIG] Reading binary data from file into NumPy arrays:
numpyio


>
>hinsen writes:
> > [Description of a very interesting module deleted.]
> >
> > > If anyone is interested in my source code, let me know and I will send
> > > it to you or let me know where to put it.
> >
> > That again raises the issue of distributing NumPy-related code.
> > How about creating an archive on starship? I'd volunteer to take care
> > of it. Or does someone have a better idea?
>
>I think we definetly need something like an archive. But I fear that
>we also need some tests for quality (justifing from my own attempts
>to give other some code).
>
>So my wish is make more code public available for testing and also
>different solutions to a given problem. Than in a second pass collect
>the more useful pieces and make a central archive of them. I fear if
>we only have a contrib-like directory and there is some bad or
>not enough tested code in it, the hole package (NumPy) get bad
>credits. If we can separate this and perhaps also have some ways for
>regression tests for the released code all will look better.
>
>__Janko
>
>
>
>_______________________________________________
>Matrix-SIG maillist  -  Matrix-SIG@python.org
>http://www.python.org/mailman/listinfo/matrix-sig
>



From da@skivs.ski.org  Thu Jun 18 19:38:46 1998
From: da@skivs.ski.org (David Ascher)
Date: Thu, 18 Jun 1998 11:38:46 -0700 (PDT)
Subject: [Matrix-SIG] Reading binary data from file into NumPy arrays:         numpyio
In-Reply-To: <003001bd9ad8$b9b1e9a0$52120f80@pduboispc.llnl.gov>
Message-ID: <Pine.SUN.3.96.980618112905.8993A-100000@skivs.ski.org>

On Thu, 18 Jun 1998, Paul F. Dubois wrote:

> Maybe the right idea is like Amazon.com; you list all the books but have
> places for reader and author "reviews". This makes it cavaet emptor but
> wasn't it always so? I'm thinking of web site that is a guide to the
> contributed packages. Actually, I even think I know how to write such a site
> pretty easily. Then we could just have the sources to all the packages
> available on an even footing.

Just a suggestion: I wouldn't dream of setting up a from-scratch CGI-based
website without doing it in Bobo these days.  There's a little learning
curve, but then there's a nice steep schuss just over that hill, or at
least that's the very definite impression I get.  I haven't done it
because I haven't had to do anything CGI-based recently.

For a quick-and-dirty solution, just use Guido's faqwizard.

A little point of history: A while back I wrote a web-database product in
Python, which I then saw being spiffed up and sold and all that -- at
around the same time I went to SPAM in DC, where I saw what the Digital
Creations folks were doing, and I knew they'd done it right and I'd done
it wrong.  Now before I start any big project i go and steal what Jim
Fulton lets me steal.

--david 

PS: Sadly, my memory isn't all that hot -- I just realized that a hairy
    thing I just did for dealing with curried functions should really be
    rewritten using Don Beaudry's 'functor' module, and when I do it it'll
    be smaller, faster and definitely meaner.




From jhauser@ifm.uni-kiel.de  Thu Jun 18 20:27:52 1998
From: jhauser@ifm.uni-kiel.de (Janko Hauser)
Date: Thu, 18 Jun 1998 21:27:52 +0200 (CEST)
Subject: [Matrix-SIG] Public source (was) Reading binary data ...
In-Reply-To: <Pine.SUN.3.96.980618112905.8993A-100000@skivs.ski.org>
References: <003001bd9ad8$b9b1e9a0$52120f80@pduboispc.llnl.gov> <Pine.SUN.3.96.980618112905.8993A-100000@skivs.ski.org>
Message-ID: <13705.26625.529515.432890@lisboa.ifm.uni-kiel.de>

As David is reading this, for a public souce repository it would be
good to have some guidelines regarding the format of the doc_strings
of the more or less function based modules. This should not be strict, 
but should lead to a more consistent document base and perhaps also a
way to implement some form of a help system.

It is not so easy to have a consistent documentation of class based
numerical routines, as someone can use a class in different contexts.

Some suggestions?

My follows now:

def foo(m1, m2, par1='spam'):
        """foo(m1, m2, par1='spam')

        a oneliner for foo, can be used for an index page

        more info about the arguments a purpose of foo
        Perhaps some magic to add an author here from the __author__
        in the module head, plus date or version?
        """


__Janko




From hinsen@cnrs-orleans.fr  Fri Jun 19 13:32:03 1998
From: hinsen@cnrs-orleans.fr (hinsen@cnrs-orleans.fr)
Date: Fri, 19 Jun 1998 14:32:03 +0200 (DFT)
Subject: [Matrix-SIG] Reading binary data from file into NumPy arrays:         numpyio
In-Reply-To: <003001bd9ad8$b9b1e9a0$52120f80@pduboispc.llnl.gov>
 (dubois1@llnl.gov)
References: <003001bd9ad8$b9b1e9a0$52120f80@pduboispc.llnl.gov>
Message-ID: <199806191232.OAA19672@dirac.cnrs-orleans.fr>

> This is part of the dilemma I face with even the parts I have already
> inherited in the distribution. With the exception of the core pieces the
> rest of the modules such as the lapack, fft, ..., are all just extras. Now

Right, they could be the first candidates for becoming add-ons. On the
other hand, I worry a bit about installation headaches for potential
users. If I distribute a program and tell people to download and
install 15 packages first, they will probably give up immediately.
Even a perfectly simple installation procedure wouldn't help much;
after all, everybody claims to offer simple installation nowadays.

I could think of a couple of advanced distribution mechanisms, but
they are far from trivial to implement. Example: everything would be
cut into small pieces, and the installation program for any end-user
code would download and install exactly the required stuff
automatically.

> Maybe the right idea is like Amazon.com; you list all the books but have
> places for reader and author "reviews". This makes it cavaet emptor but
> wasn't it always so? I'm thinking of web site that is a guide to the

That's an interesting idea, which I think could work well for
scientific code distribution. It would still be good to establish
certain standards for installation and documentation, and clearly mark
packages that follow these standards and are thus presumably easier to
use. Code quality is of course an entirely different issue.

> This is clearly identical to the general problem of what Guido "blesses" or
> not. I think it less likely that you can pick a computer-science area that
> Guido doesn't know anything about than you can pick some area of numerical
> analysis, probability, and statistics that I know nothing about. Clearly
> nobody is capable of knowing all this stuff. The documentation for the NAG
> library runs nine volumes.

One could have a team of "moderators" for the main subareas. But then
the open review approach would probably lead to the same result anyway,
with some people's opinion on certain subjects being respected more
than others.
-- 
-------------------------------------------------------------------------------
Konrad Hinsen                            | E-Mail: hinsen@cnrs-orleans.fr
Centre de Biophysique Moleculaire (CNRS) | Tel.: +33-2.38.25.55.69
Rue Charles Sadron                       | Fax:  +33-2.38.63.15.17
45071 Orleans Cedex 2                    | Deutsch/Esperanto/English/
France                                   | Nederlands/Francais
-------------------------------------------------------------------------------


From Oliphant.Travis@mayo.edu  Fri Jun 19 18:49:36 1998
From: Oliphant.Travis@mayo.edu (Travis E. Oliphant)
Date: Fri, 19 Jun 1998 12:49:36 -0500
Subject: [Matrix-SIG] Python binding of FFTW package
References: <Pine.SOL.3.91-941213.980618133139.2362A-100000@duss0.dur.ac.uk>
Message-ID: <358AA4B0.5B279EB9@mayo.edu>

I'm placing the binary file reading package as well as the fftw packgage
on

ftp.mayo.edu

in the directory 

/pub/olipt

numpyio.tgz is there already and
numpy_fftw.tgz should be there by the end of the day.

I'm looking in to binding the rfftw routines. (shouldn't be too hard)


Travis Oliphant


From Oliphant.Travis@mayo.edu  Fri Jun 19 23:32:36 1998
From: Oliphant.Travis@mayo.edu (Travis E. Oliphant)
Date: Fri, 19 Jun 1998 17:32:36 -0500
Subject: [Matrix-SIG] numpyio and fftw modules
Message-ID: <358AE704.A7C03F29@mayo.edu>

The numpyio and fftw modules (including rfftw) are available.

Both modules are available at ftp.mayo.edu under /pub/olipt

I can't guarantee how long they will be there but they should be there
for
at least 5 days.

I think they idea of a repository somewhere such as at starship is
a great idea.

With fftw you can do N-D (1-D,2-D,3-D,etc.) Fourier transforms on much
larger
data sets than is possible with MATLAB (especially because of the
in-place
feature).

Best,

Travis
Oliphant


From Paul F. Dubois" <dubois1@llnl.gov  Sat Jun 20 06:31:40 1998
From: Paul F. Dubois" <dubois1@llnl.gov (Paul F. Dubois)
Date: Fri, 19 Jun 1998 22:31:40 -0700
Subject: [Matrix-SIG] Re: Trouble downloading NumPy.exe
Message-ID: <000401bd9c0c$b41ecd20$52120f80@pduboispc.llnl.gov>

Weird. In fact, the file was bad on my machine after Wise made it. I have no
idea what I did. I made a new one and it is nice and long. Sorry. I had in
fact tested the installer but then made a legendary one last change to a
documentation file and redid it to pick that up and didn't test again. Dumb.
Didn't notice the shortness. Dumb again.

Thanks to you and others who wrote.


-----Original Message-----
From: Carl Feynman <carlf@alum.mit.edu>
To: support@icf.llnl.gov <support@icf.llnl.gov>
Date: Friday, June 19, 1998 8:38 PM
Subject: Trouble downloading NumPy.exe


>I tried downloading ftp://ftp-icf.llnl.gov/pub/python/NumPy.exe onto my
>Win95 machine, and running it.  The installer created a bunch of
>reasonable-looking files, but they were all of length 0.  Then the
>installer crashed.  I was surprised by the fact that the installer was only
>81 KB long.  Is ftp://ftp-icf.llnl.gov/pub/python/NumPy-13.exe really only
>80Kb long when ftp://ftp-icf.llnl.gov/pub/python/NumPy-12.exe is 736 Kb
long?
>
>I can give more details if this isn't enough to debug the problem.
>
>--Carl Feynman
>
>



From klm@python.org  Tue Jun 23 17:08:00 1998
From: klm@python.org (Ken Manheimer)
Date: Tue, 23 Jun 1998 12:08:00 -0400 (EDT)
Subject: [Matrix-SIG] Lost maillist messages thursday eve (6/18) to friday noon (6/19)
Message-ID: <199806231608.MAA13068@glyph.cnri.reston.va.us>

Some of you may have lost postings posted to one of the following
maillists between last thursday (6/18) evening and friday (6/19)
noon.

Mailman-Developers (1 msg)
Matrix-SIG (8 msgs)
DB-SIG (3 msgs)
Doc-SIG (4 msgs)
Pythonmac-SIG (3 msgs)
XML-SIG (1 msg)
Trove-Dev (6 msgs)

This happened accompanying an upgrade of our maillist software,
mailman, due to an bad interaction between a new mailman feature and
an anti-spam (anti-relay) mechanism applied to python.org's sendmail
configuration.  This problem did not show during testing because our
test recipients were all local, and not subject to the anti-relay
constraints.

If you sent something to any of these lists during that time frame and
never saw it show, you may want to resend.  Archiving was not
affected, so you should be able to find the messages in the maillist
archives.  People receiving the lists in digest format were not
affected, since the delivery problem was fixed before the digest
delivery time.

My apologies for the disruption!

Ken Manheimer		  klm@python.org	    703 620-8990 x268
	    (orporation for National Research |nitiatives

	# If you appreciate Python, consider joining the PSA! #
		  # <http://www.python.org/psa/>. #


From miller5@uiuc.edu  Thu Jun 25 15:10:23 1998
From: miller5@uiuc.edu (Mike Miller)
Date: 25 Jun 1998 09:10:23 -0500
Subject: [Matrix-SIG] Numeric version IDs?
Message-ID: <t9wwa5r2r4.fsf@uinpluxb.npl.uiuc.edu>

I just sent a bug report off about a bug in Matrix.py in the
Debian python-numeric package (which has already been corrected
in the LLNLPython distribution).  While describing the problem, I
realized that there is (AFAIK) no version info included in NumPy.
If I am wrong, would someone let me know where it is?  Otherwise,
I suggest that, in order to facilitate upgrades for people not
using the full LLNL distribution, some __version__'s be added in
the appropriate places.

Regards, Mike

-- 
Michael A. Miller                                miller5@uiuc.edu
  Department of Physics, University of Illinois, Urbana-Champaign
  PGP public key available on request