I now have a working implementation of sub function assignment.

https://bitbucket.org/fenics-project/dolfin/pull-request/60/subfunction-assignment

It uses the proposed FunctionAssigner class. It is pretty powerfull, as the
added unit test shows.

I have added a free function assign which makes the following possible:

  mesh = UnitSquareMesh(10,10)
  V = FunctionSpace(mesh, "CG", 1)
  VV = VectorFunctionSpace(mesh, "CG", 1)

  U = Function(VV)
  u0, u1 = Function(V), Function(V)

  assign(U.sub(0), u0) # 1-1
  assign(U, [u0, u1])  # N-1
  assign([u0, u1], U)  # 1-N

The FunctionAssigner class can be used to cache dof indices for the
assignment, speeding up each assignment considerably. The above assignments
would then be:

  assigner_1_1.FunctionAssigner(VV.sub(0), V)
  assigner_N_1.FunctionAssigner(VV, [V,V])
  assigner_1_N.FunctionAssigner([V,V], VV)

  assigner_1_1.assign(U.sub(0), u0) # 1-1
  assigner_N_1.assign(U, [u0, u1])  # N-1
  assigner_1_N.assign([u0, u1], U)  # 1-N

To be able to implement this I needed to make sub dofmaps carry the
ownership range from the parent dofmap. This might introduce some
regressions. I have fixed at least 2 picked up by the unit tests. To
determine if a dofmap is a view or not I just added a private flag which is
set during construction of the sub dofmap.

I hope this might be of interest.

Johan


On Tue, Sep 24, 2013 at 10:50 PM, Johan Hake <hake....@gmail.com> wrote:

> On Tue, Sep 24, 2013 at 10:38 PM, Garth N. Wells <gn...@cam.ac.uk> wrote:
>
>> On 24 September 2013 21:24, Johan Hake <hake....@gmail.com> wrote:
>> > On Tue, Sep 24, 2013 at 9:52 PM, Garth N. Wells <gn...@cam.ac.uk>
>> wrote:
>> >>
>> >> On 24 September 2013 20:18, Anders Logg <l...@chalmers.se> wrote:
>> >> > Yes, I like DofMapToDofMapMapping much better.
>> >> >
>> >>
>> >> I like the design, much the name looks horrible! :-)
>> >
>> >
>> > What design? A class that hold the mapping between 1-N,N-1,1-1 dofmaps?
>> If
>> > so I agree.
>>
>> Yes. The simple C++ approach is to just use a map class, but this is
>> hard wrap in Python.
>
>
> How would you use a map class in C++ that is general enough to hold the
> three mappings?
>
> Also for this to make any sense in a function assignment setting the
> mapping, really the dofs for each function/subfunction, need to be
> contiguous arrays that can be used efficiently in
> GenericVector::{get_local,set_local} calls.
>
> Johan
>
>
>  > But it is not clear to me what you think the syntax for the
>> > assignment statement should be.
>> >
>> > I do not think:
>> >
>> >   dmtdmm = DofMapToDofMapMapping([V,V,V], VV)
>> >   assign([u0,u1,u2],u, dmtdmm)
>> >
>> > is better than for example:
>> >
>> >   dmtdmm = DofMapToDofMapMapping([V,V,V], VV)
>> >   dmtdmm.assign([u0,u1,u2],u)
>> >
>>
>> The former is better because if 'DofMapToDofMapMapping' is just about
>> the relationship between dofmaps, in clean design it shouldn't know
>> about Functions.
>> Garth
>>
>> > The first is similar to what Martin suggested and the latter is
>> basically
>> > what I first suggested with a different naming.
>> >
>> >
>> > We can still support a more general free function:
>> >
>> >   assign([u0,u1,u2],u)
>> >
>> > where a DofMapToDofMapMapping is created inside the assign function and
>> then
>> > discarded.
>> >
>> >> > My suggestion for a short name would be
>> >> >
>> >> >   DofMapTransformation
>> >> >
>> >>
>> >> I don't like this name - it doesn't make clear that if defined a
>> >> relationship between two domps.
>> >
>> >
>> > Agree. No dofmaps are transformed.
>> >
>> >  I don't have a good name suggestion just yet, but maybe we should
>> >>
>> >> raise the abstraction. A dofmap is a type of graph, and what we want
>> >> is the relationship between a graph and some subgraph (related to
>> >> this, I'd like to use a more graph-centric approach in DofMapBuilder
>> >> to simplify it and to extend the functionality).
>> >
>> >
>> > Sounds good. I suppose a general mapping class between dofmaps could be
>> > useful for different cases. However, I am not sure what these cases
>> are, and
>> > I have therefor difficulties envision how such class should be looking.
>> I
>> > have one particular task in mind, and for that I need a mapping between
>> > 1-N,N-1,1-1 dofmaps.
>> >
>> >>
>> >> > Yes, BoundingBoxTree has a lot of methods but it is an implementation
>> >> > detail that the methods are actually implemented as part of the
>> >> > BoundingBoxTree class hierarchy (and not outsourced to algorithm
>> >> > classes as we do in other places).
>> >>
>> >
>> > And what is the difference? Couldn't an assign method be implemented as
>> part
>> > of a DofMapToDofMapMapping class?
>> >
>> >  > I just want to stay away from the horror in dolfin/common/unittest.h:
>> >>
>> >> >
>> >> >   CppUnit::TestResult result;
>> >> >   CppUnit::TestResultCollector collected_results;
>> >> >   result.addListener(&collected_results);
>> >> >   CppUnit::TestRunner runner;
>> >> >
>> >> >
>> runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
>> >> >   runner.run(result);
>> >> >   CppUnit::CompilerOutputter outputter(&collected_results,
>> std::cerr);
>> >> >   outputter.write ();
>> >> >   return collected_results.wasSuccessful () ? 0 : 1;
>> >
>> >
>> > I think this example is just stupid. It has nothing to do with what I
>> > suggested. As I said we can hide the instantiation of the class within a
>> > free function for people who wants to solve a problem with a small
>> script
>> > with nice syntax. I suggest adding a useful class that solves a problem
>> many
>> > has requested in an elegant way.
>> >
>> >> > Adding FunctionAssigner is just one class but it's a slippery
>> >> > slope... :-)
>> >
>> >
>> > The slope is as slippery as adding DOLFIN_EPS_LARGE, which easily could
>> lead
>> > to the addition of DOLFIN_EPS_NOT_SO_LARGE ;)
>> >
>> > Johan
>> >
>> >
>> >>
>> >> > --
>> >> > Anders
>> >> >
>> >> >
>> >> > On Tue, Sep 24, 2013 at 10:44:05AM +0200, Martin Sandve Alnæs wrote:
>> >> >> Would you agree that that the BoundingBoxTree represents data
>> >> >> associations, not
>> >> >> an operation, similar to my just-now suggestion
>> DofMapToDofMapMapping
>> >> >> instead
>> >> >> of FunctionAssigner? An object that represents the mapping could
>> >> >> conceivably be
>> >> >> useful for operations other than assign as well.
>> >> >>
>> >> >> Martin
>> >> >>
>> >> >>
>> >> >> On 24 September 2013 10:39, Johan Hake <hake....@gmail.com> wrote:
>> >> >>
>> >> >>     Well, we have the BoundingBoxTree, which similarly caches data
>> that
>> >> >> speed
>> >> >>     up certain operations. We also have a Solver class and a free
>> >> >> function
>> >> >>     solve, an Assembler class and a free function assemble.
>> Similarly
>> >> >> we could
>> >> >>     have a free function assign, which construct a FunctionAssign
>> >> >> object.
>> >> >>     However there is a lot of data which could be reused in the
>> >> >> FunctionAssign
>> >> >>     object. If a user want to utelize that he should instantiate the
>> >> >> object and
>> >> >>     use that in his code.
>> >> >>
>> >> >>     Johan
>> >> >>
>> >> >>
>> >> >>
>> >> >>     On Tue, Sep 24, 2013 at 10:27 AM, Anders Logg <l...@chalmers.se
>> >
>> >> >> wrote:
>> >> >>
>> >> >>         Is it possible to solve this without introducing the design
>> >> >> pattern
>> >> >>         with a class FunctionAssigner? We have been careful to avoid
>> >> >> this in
>> >> >>         other places.
>> >> >>
>> >> >>
>> >> >>
>> >> >>
>> >> >>         On Mon, Sep 23, 2013 at 07:20:03PM +0200, Johan Hake wrote:
>> >> >>         > I am working on sub-function assignment. To facilitate
>> >> >> caching of dof
>> >> >>         indices
>> >> >>         > for a particular assignment combination I suggest
>> introducing
>> >> >> a
>> >> >>         > FunctionAssigner class which caches the necessary indices
>> >> >> (dofs) for
>> >> >>         the whole
>> >> >>         > domain.
>> >> >>         >
>> >> >>         > Something like:
>> >> >>         >
>> >> >>         >   mesh = UnitSquareMesh(10,10)
>> >> >>         >   V = FunctionSpace(mesh, "CG", 1)
>> >> >>         >   VV = V*V
>> >> >>         >
>> >> >>         >   # Assign two scalar functions to the components of a
>> mixed
>> >> >> function
>> >> >>         >   assigner0 = FunctionAssigner([V, V], VV)
>> >> >>         >
>> >> >>         >   # Assign components of a mixed function to scalar
>> Functions
>> >> >>         >   assigner1 = FunctionAssigner(VV, [V, V])
>> >> >>         >
>> >> >>         >   # Assign a scalar function to a component of a mixed
>> >> >> function
>> >> >>         >   assigner2 = FunctionAssigner(V, VV.sub(1))
>> >> >>         >
>> >> >>         >   u0, u1 = Function(V), Function(V)
>> >> >>         >   U = Function(VV)
>> >> >>         >
>> >> >>         > Then in some time loop:
>> >> >>         >
>> >> >>         >   while t < tstop:
>> >> >>         >       ...
>> >> >>         >       assigner0.assign([u0, u1], U)
>> >> >>         >       ...
>> >> >>         >       assigner1.assign(U, [u0, u1])
>> >> >>         >       ...
>> >> >>         >       assigner2.assign(u0, U.sub(1))
>> >> >>         >
>> >> >>         > In C++ the equivalent to a list of Foo will be a
>> std::vector
>> >> >> of
>> >> >>         shared Foos.
>> >> >>         >
>> >> >>         > Comments?
>> >> >>         >
>> >> >>         > By using sub spaces and sub functions we avoid using
>> indices
>> >> >> in the
>> >> >>         interface,
>> >> >>         > which I think is neat. However, there are some limitations
>> >> >> with the
>> >> >>         present
>> >> >>         > interface:
>> >> >>         >
>> >> >>         > 1) The FunctionAssigner needs to have access to the local
>> >> >> ownership
>> >> >>         range of a
>> >> >>         > sub dofmap, but that is not possible as it is set to 0,0
>> >> >> during
>> >> >>         construction.
>> >> >>         > Could we add a proper local ownership range to a sub
>> dofmap?
>> >> >>         > 2) The FunctionAssigner need to be able to access the
>> private
>> >> >> _vector
>> >> >>         of a
>> >> >>         > parent Function during the assignment, as calling
>> >> >> subfunc.vector()
>> >> >>         raises an
>> >> >>         > error. This can be fixed by a friend statement. Is that
>> >> >> acceptable?
>> >> >>         >
>> >> >>         > Johan
>> >> >>
>> >> >>         > _______________________________________________
>> >> >>         > fenics mailing list
>> >> >>         > fenics@fenicsproject.org
>> >> >>         > http://fenicsproject.org/mailman/listinfo/fenics
>> >> >>
>> >> >>
>> >> >>
>> >> >>
>> >> >>     _______________________________________________
>> >> >>     fenics mailing list
>> >> >>     fenics@fenicsproject.org
>> >> >>     http://fenicsproject.org/mailman/listinfo/fenics
>> >> >>
>> >> >>
>> >> >>
>> >> > _______________________________________________
>> >> > fenics mailing list
>> >> > fenics@fenicsproject.org
>> >> > http://fenicsproject.org/mailman/listinfo/fenics
>> >> _______________________________________________
>> >> fenics mailing list
>> >> fenics@fenicsproject.org
>> >> http://fenicsproject.org/mailman/listinfo/fenics
>>
>>
>>
>> --
>> Garth N. Wells
>> Department of Engineering, University of Cambridge
>> http://www.eng.cam.ac.uk/~gnw20
>>
>
>
_______________________________________________
fenics mailing list
fenics@fenicsproject.org
http://fenicsproject.org/mailman/listinfo/fenics

Reply via email to