[Numpy-discussion] Numeric3

Fernando Perez Fernando.Perez at colorado.edu
Tue Feb 8 13:30:35 EST 2005


Gary Strangman wrote:

> In sum, I pretty much agree with most previous contributors. With one 
> exception. I do agree with Konrad that, theory, the best analysis approach 
> is to build a custom class for each domain of investigation. I've even 
> done that a couple times. However, of the dozens of researchers (i.e., 
> users, not developers) I've talked about this with, almost none have the 
> time (or even desire) to design and develop a class-based approach. Their 
> goal is data analysis and evaluation. So, they pull the data into python 
> (or, more typically, matlab or IDL), analyze it, plot the results, try to 
> get a plot that's pretty enough for publication, and then go on to the 
> next project ... no time for deciding what functionality should be a 
> method or an attribute, subclassing hierarchies, etc. In those rare 
> cases where they have the desire, matlab (I don't know about IDL) doesn't 
> give you the option, meaning that users (as opposed to developers) 
> probably won't go the (unfamiliar and more time consuming) route.

I have to say that in most cases, the approach you describe from colleagues is 
an unfortunately common, but still very shortsighted one (except in cases so 
trivial that it doesn't really matter).  I'm attaching a real-world example of 
a 3d Poisson solver which uses a new algorithm combining some neat ideas.  The 
papers are being only written right now, so the only reference I can offer is 
this:

http://amath.colorado.edu/faculty/fperez/talks/0403_ams_athens.pdf

The point is that anyone should be able to read that script and understand 
what it does.  A few things worth pointing out from that code:

print "Building rho (Right Hand Side)..."
rho = FunctionFromCode(nnod,cutoff,rho_code,norm_type)

print "Building phi (Left Hand Side), analytical solution..."
phi_exact = FunctionFromCode(nnod,cutoff,phi_exact_code,norm_type)

This builds multiwavelet, adaptively decomposed objects which are quite 
complex internally, yet they behave like functions.  Likewise, this line:

print "Computing phi = poisson(rho) explicitly..."
phi  = poisson(rho)

returns another function (even though this one was constructed as a numerical 
solution instead of having an analytical representation).  So checking for 
validity, in this case where we have the exact anwer, is as simple as:

print "Building error function..."
error = phi - phi_exact
enorm = error.norm()

This subtracts two multiwavelet-represented functions in 3d, and returns 
another function of the same kind.  Furthermore, all these objects have 
plot/info methods which you can then use to visualize info or print relevant 
numerical stuff:

print "Norm info (L-%s):" % norm_type
print "rho    = %.3e" % rho.norm()
print "phi    = %.3e" % phi.norm()
print "error  = %.3e" % enorm

Plotting is equally easy:

# Surface plots across z=0.5 for rho and phi, uses MayaVi
rho.plot_surf()
phi.plot_surf()

# Interpolation error for the multiwavelet representation of the rhs/lhs
rho.plot_line(ptype='error',title='Interpolation error for charge density')
phi_exact.plot_line(ptype='error',
                     title='Interpolation error for exact solution')

# Pointwise interpolation error in the Green function's kernel
poisson.plot_kernel_error()

The point is, by making these objects 'smart', the top-level code reads like a 
regular mathematical solution of Poisson's equation, and extracting useful 
info is trivial.  And I can guarantee that in the long run, I've saved myself 
A LOT of time by writing the code in this way, rather than spitting out arrays 
left, right and center, and calling manual plot routines on them all the time. 
  When I need plots for a talk or paper, there is nothing more to do, just 
call the objects.

I should add that having this kind of design in scientific codes makes 
interactive exploration and debugging a very pleasant process: whenever 
something doesn't look right, my objects have a ton of self-diagnostic methods 
which I can quickly use to pinpoint the problem.  And this is not a 
theoretical statement, I have already many times saved myself much grief by 
being able to instantly see where the problem is, thanks to this kind of design.

So while I agree that having plain array access is needed for quick and dirty 
one-off things, basically anything beyond 50-100 lines of code is probably 
best written with a tiny bit of design.  Those 10 minutes invested thinking 
about a design sketch will pay for themselves many times over.

Regards,

f
-------------- next part --------------
A non-text attachment was scrubbed...
Name: demo_poisson_3d.py
Type: application/x-python
Size: 3596 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/numpy-discussion/attachments/20050208/2ba88da0/attachment.bin>


More information about the NumPy-Discussion mailing list