← Back to team overview

ffc team mailing list archive

Re: Tensors

 

Quoting Anders Logg <logg@xxxxxxxxx>:

> Of course, FFC is still very experimental but I don't think it would
> be a good idea to base the FFC algebra on Numeric.array.
> 
> 1. I think the best solution to Garth's problem would be to let the
> constructor of an Index accept one optional extra argument to allow
> specification of ranges. Then one can do stuff like
> 
>     i = Index(0, d)
>     j = Index(0, d)
>     a = u[i].dx(i) * v[j].dx(j)
> 
> This would force corresponding Indices to match and I think it would
> allow Garth to do what he likes. Correct me if I'm wrong.

This would be good.


> 
> 2. Then Johan's suggestion. If you write
> 
>     epsilonu = 0.5 * (u[i].dx(i) * v[j].dx(j))
> 
> then this is a scalar since repeating an Index twice means summation
> over that Index. I think the tensor notation has proven to be quite
> powerful so I would like to keep it.
> 
> On the other hand, you can do everything you need by indexing basis
> functions and derivatives by integers (not Index) as you have noted.
> This allows a user to define arbitrary operators as you have done:
> 
> def epsilon(u):
>     return [ [u[i].dx(j) + u[j].dx(i) for i in range(d)] for j in range(d) ]
> 
> The only thing that needs to be added to FFC is then the identity as
> far as I can see.
> 
> I'm planning to add a list of predefined operators and operands to FFC
> to simplify and beautify the notation anyway, so this would fit well
> into that category.
> 
> Operators that will be added include grad(), rot() and div().
> 
> Operands that will be added include h (mesh size) and d (space dimension).
> 
> Any other suggestions?
> 
> All these can be added on top of the existing machinery (I think). As
> far as possible, I would like to keep the basic layer simple and add
> complexity by combining the simple primitives.
> 
> /Anders
> 
> On Tue, Aug 30, 2005 at 05:48:24AM -1100, kirby@xxxxxxxxxxxx wrote:
> 
> > This leads to maintaing two different kinds of tensors -- one 
> > for FFC and one in Numeric.  In my opinion (but perhaps not 
> > Anders' :)), FFC is still very experimental.  Your email 
> > leads one to speculate whether it would be a better practice 
> > to make everything in FFC a Numeric.array of objects.  Then, 
> > so long as we overload operators appropriately for the scalar 
> > objects, we're set for vectors and tensors. 
> >  
> > Rob 
> >  
> >  
> > ---- Original message ---- 
> > >Date: Mon, 29 Aug 2005 15:56:56 +0200 
> > >From: Johan Jansson <johanjan@xxxxxxxxxxxxxxxx>   
> > >Subject: Re: [FFC-dev] Tensors   
> > >To: "Garth N. Wells" <g.n.wells@xxxxxxxxxxxxxxx> 
> > >Cc: ffc-dev@xxxxxxxxxx 
> > > 
> > >On Wed, Aug 24, 2005 at 01:32:19PM +0200, Garth N. Wells 
> > wrote: 
> > >> Hi Johan, 
> > >>  
> > >> For me, tensor notation would be really useful.  
> > >>  
> > > 
> > >Hi! 
> > > 
> > >I've experimented a bit with different approaches to tensor 
> > notation, 
> > >and I've found one that works pretty well, some feedback 
> > would be 
> > >nice. The approach I've gotten to work is to simply define 
> > matrices of 
> > >objects in the FFC algebra, I've done it using multiarrays 
> > from the 
> > >Numeric module, but any capable multiarray/matrix class 
> > could probably 
> > >be used, or we could write our own if we need special 
> > capabilities. 
> > > 
> > >What I would like to be able to do is write: 
> > > 
> > >epsilonu = 0.5 * (u[i].dx(i) * v[j].dx(j)) 
> > > 
> > >and then treat epsilonu as a tensor. But as far as I can 
> > see, epsilonu 
> > >is not a tensor in the FFC algebra. At least indexing is not 
> > yet 
> > >supported for such objects, so I cannot write epsilonu[1, 2] 
> > or even 
> > >epsilonu[1]. I'm not sure epsilonu is supposed to fit the 
> > tensor 
> > >concept here. 
> > > 
> > >What I did instead is to explicitly construct a tensor 
> > (matrix): 
> > > 
> > >from Numeric import * 
> > >from math import * 
> > > 
> > >def epsilon(u): 
> > >    eu = ffczeros(3, 3) 
> > > 
> > >    for ii in range(3): 
> > >        for jj in range(3): 
> > >            eu[ii, jj] = 0.5 * (u[ii].dx(jj) + u[jj].dx(ii)) 
> > > 
> > >    return eu 
> > > 
> > >also defining the function ffczeros(): 
> > > 
> > >global zero 
> > >zero = 0.0 * Constant() 
> > > 
> > >def ffczeros(m, n): 
> > >    A = array((zero)) 
> > >    A = resize(A, (m, n)) 
> > >    A *= 0.0 
> > > 
> > >    return A 
> > > 
> > >array() and resize() are Numeric.array() and 
> > Numeric.resize(). The 
> > >array in Numeric is not really made for arbitrary types, it 
> > seems to 
> > >only officially support builtin types, but this works well 
> > >enough. There is an array class in numarray which does 
> > support general 
> > >types, but it is not well developed. As I mentioned, we can 
> > write our 
> > >own matrix/tensor class if needed. 
> > > 
> > >I can now write: 
> > > 
> > >epsilonu = epsilon(u) 
> > > 
> > >to achieve what I want. 
> > > 
> > >It's then very easy to write forms using the same notation 
> > as in the 
> > >original PDEs. For example, here is the E() linear 
> > transformation from 
> > >linear elasticity: 
> > > 
> > >def E(e, lmbda, mu): 
> > >    Ee = 2.0 * multiply(mu, e) 
> > >    for ii in range(3): 
> > >        for jj in range(3): 
> > >            if ii == jj: 
> > >                Ee[ii, jj] += lmbda * trace(e) 
> > > 
> > >    return Ee 
> > > 
> > >I would have liked to write it like so: 
> > > 
> > >def E(e, lmbda, mu): 
> > >    Ee = 2.0 * multiply(mu, e) + lmbda * trace(e) * 
> > ffcidentity(3) 
> > >    return Ee 
> > > 
> > >but I have not yet succeeded in constructing an identity 
> > matrix of FFC 
> > >algebra objects. It would be nice to have a zero and 
> > identity element 
> > >in the FFC algebra, they should just be a Constant() with a 
> > 0.0 or 1.0 
> > >value. I'm not really clear on the Python operators yet 
> > either, there 
> > >seems to be some ambiguity between when an operator is used 
> > from FFC 
> > >or Numeric.array. 
> > > 
> > >I have attached the elasticity form from the DOLFIN module 
> > written in 
> > >the new notation (Elasticity-alternative.form), I've 
> > verified that it 
> > >produces the same result, so it works. FFC seems to have 
> > some problems 
> > >with namespaces though, so you need to compile it like so: 
> > > 
> > >ffc Elasticity-alternative.form 
> > >python Elasticity-alternative.py 
> > > 
> > >> Related to the issue of taking slices and indexing, I had 
> > some 
> > >> exchanges with Anders a while ago about the possibility of 
> > being 
> > >> able to specify the range of the summation when using the 
> > index 
> > >> summation convention. This would be a big help when 
> > examining 
> > >> coupled problems. At the moment I'm not able (or don't 
> > know how) to 
> > >> use the index notation for these problems, so I'm writing 
> > out the 
> > >> bilinear form for explicitly. As an example, I'm looking 
> > at a 
> > >> coupled elasticity-diffusion equation at the moment. In 2D 
> > (3 dof 
> > >> per node), part of th bilinear form looks like 
> > > 
> > >>  
> > >> a = ( lmbda * (u[0].dx(0) + u[1].dx(1))*(v[0].dx(0) + 
> > v[1].dx(1))  + \ 
> > >>        mu * ( \ 
> > >>         (u[0].dx(0)+u[0].dx(0))*(v[0].dx(0)) + \ 
> > >>         (u[0].dx(1)+u[1].dx(0))*(v[0].dx(1)) + \ 
> > >>         (u[1].dx(0)+u[0].dx(1))*(v[1].dx(0)) + \ 
> > >>         (u[1].dx(1)+u[1].dx(1))*(v[1].dx(1)) ) )* dx + \ 
> > >>      -Beta*( u[2]*v[0].dx(0) + u[2]*v[1].dx(1) )* dx 
> > >>  
> > > 
> > >> For 3D, I need to add a bunch of terms. What I would like 
> > to able to 
> > >> do is use something like: 
> > > 
> > > 
> > >> a = ( lmbda * u[i:0,n].dx(i:0,n) * v[j:0,n].dx(j:0,n) + mu 
> > * ( 
> > >> u[i:0,n].dx(j:0,n) + u[j:0,n].dx(i:0,n) ) * 
> > v[i:0,n].dx(j:0,n) )* dx 
> > >> + -Beta * u[n+1]*v[i:0,n].dx(i:0,n) * dx 
> > > 
> > >> where n is the range of the summation. Setting n = 1 would 
> > then be 
> > >> for 2D, and n = 2 for 3D. It might then be an idea to make 
> > the 
> > >> spatial dimension available within ffc.  Garth 
> > > 
> > >I think this could be done much simpler with the separate 
> > >tensor/matrix class approach. You would do: 
> > > 
> > >def epsilon(u, n): 
> > >    eu = ffczeros(n, n) 
> > > 
> > >    for ii in range(n): 
> > >        for jj in range(n): 
> > >            eu[ii, jj] = 0.5 * (u[ii].dx(jj) + u[jj].dx(ii)) 
> > > 
> > >    return eu 
> > > 
> > >and then: 
> > > 
> > >a = epsilon(u, n) * ... -Beta * u[n+1] * ... 
> > > 
> > >Since slicing is supported by Numeric.array, and would be 
> > supported by 
> > >any other tensor/matrix representation we would choose, it 
> > would not 
> > >be necessary to add it to the FFC algebra. It would make the 
> > matrix 
> > >initialization much more compact though, if we could just 
> > write: 
> > > 
> > >epsilonu = matrix(u[i:0,n].dx(j:0,n) + u[i:0,n].dx(j:0,n)) 
> > > 
> > >(or some other slicing convention), but perhaps it's best to 
> > keep the 
> > >FFC algebra as simple as possible. 
> > > 
> > >Please tell me what you think about this, if it seems to 
> > cover the 
> > >necessary functionality etc. I'm going to try to use it for 
> > some other 
> > >problems and see if it's usable. 
> > > 
> > >  Johan 
> > >________________ 
> > ># Copyright (c) 2004 Anders Logg (logg@xxxxxxxxx) 
> > ># Licensed under the GNU GPL Version 2 
> > ># 
> > ># The bilinear form for a mass matrix. 
> > ># 
> > ># Compile this form with FFC: ffc Mass.form 
> > > 
> > >from Numeric import * 
> > >from math import * 
> > > 
> > >element = FiniteElement("Vector Lagrange", "tetrahedron", 1) 
> > > 
> > >v = BasisFunction(element) 
> > >u = BasisFunction(element) 
> > > 
> > >lmbda = Constant() # Lame coefficient 
> > >mu    = Constant() # Lame coefficient 
> > > 
> > >f = Function(element) # Source 
> > > 
> > >global zero 
> > >zero = 0.0 * Constant() 
> > > 
> > >def ffczeros(m, n): 
> > >    A = array((zero)) 
> > >    A = resize(A, (m, n)) 
> > >    A *= 0.0 
> > >     
> > >    return A 
> > > 
> > >def ffcidentity(m): 
> > >    A = myzeros(m, m) 
> > > 
> > >    for ii in range(m): 
> > >        for jj in range(m): 
> > >            if ii == jj: 
> > >                A[ii, jj] = 1.0 
> > >                     
> > >    return A 
> > > 
> > >def epsilon(u): 
> > >    eu = ffczeros(3, 3) 
> > > 
> > >    for ii in range(3): 
> > >        for jj in range(3): 
> > >            eu[ii, jj] = 0.5 * (u[ii].dx(jj) + u[jj].dx(ii)) 
> > > 
> > >    return eu 
> > > 
> > > 
> > >def E(e, lmbda, mu): 
> > >    Ee = 2.0 * multiply(mu, e) 
> > >    for ii in range(3): 
> > >        for jj in range(3): 
> > >            if ii == jj: 
> > >                Ee[ii, jj] += lmbda * trace(e) 
> > > 
> > >    return Ee 
> > > 
> > >sigma = E(epsilon(u), lmbda, mu) 
> > > 
> > >a = vdot(sigma, epsilon(v)) * dx 
> > >L = f[i] * v[i] * dx 
> > >________________ 
> > >_______________________________________________ 
> > >FFC-dev mailing list 
> > >FFC-dev@xxxxxxxxxx 
> > >http://www.fenics.org/cgi-bin/mailman/listinfo/ffc-dev 
> > 
> > _______________________________________________
> > FFC-dev mailing list
> > FFC-dev@xxxxxxxxxx
> > http://www.fenics.org/cgi-bin/mailman/listinfo/ffc-dev
> > 
> 
> -- 
> Anders Logg
> Research Assistant Professor
> Toyota Technological Institute at Chicago
> http://www.tti-c.org/logg/
> 
> _______________________________________________
> FFC-dev mailing list
> FFC-dev@xxxxxxxxxx
> http://www.fenics.org/cgi-bin/mailman/listinfo/ffc-dev
> 



Follow ups

References