### How do I set metadata of an existing Measure instance?

91
views
0
11 weeks ago by
I want to be able to set metadata, specifically the quadrature degree, of an already existing Measure instance.

Based on what I read from help(fenics.Measure),

Help on class Measure in module ufl.measure:

class Measure(builtins.object)
| Methods defined here:
|
|
| Creates an intermediate object used for the notation
|
| expr * (dx(1) + dx(2)) := expr * dx(1) + expr * dx(2)
|
| __call__(self, subdomain_id=None, metadata=None, domain=None, subdomain_data=None, degree=None, scheme=None, rule=None)
| Reconfigure measure with new domain specification or metadata.
|

I tried

import fenics

dx = fenics.Measure("dx")

​

but unfortunately, Measure.__call__, actually returns a new instance, and does not modify the caller in place as I had expected from reading the doc.

I also tried
dx.metadata()["quadrature_degree"] = 8​

which throws the error

This is a frozen unique empty dictionary object, inserting values is an error.

So how can I do this? Essentially I am looking for setter method for Measure.metadata. I've read the whole doc and tried digging around with dx.__dict__ or dx._asdict(). I haven't looked at the source code of Measure yet.

I'm using FEniCS 2017.2.0.

Edit: AllAnswered isn't indenting the outputs that I tried to indent, so feel free to suggest a way to format the output from help and the error.
Community: FEniCS Project
Also since I am essentially looking for a "setter", now I tried doing this directly:

dx.metadata = dx(metadata={"quadrature_degree":  8}).metadata()​

but this throws the error "AttributeError: 'Measure' object attribute 'metadata' is read-only".

so perhaps FEniCS purposefully does not allow me to do this.
written 11 weeks ago by Alexander G. Zimmerman
You could always do
dx._metadata = dx(metadata={"quadrature_degree":  8}).metadata()​​
but I don't think that's considered best practice...

I did some tinkering and found that the "reconstruct" method seems to be a reliable way to set specific attributes (without altering others on a seemingly-random basis, the way __call__ does).  It still technically creates a new instance, but you may or may not find the below test code useful:

from dolfin import *

# This adds to and/or overwrites specific attributes of the an
import ufl.utils.dicts
if(not isinstance(m1,ufl.utils.dicts.EmptyDictType)):
return m1.update(m2)
return m2

print(repr(dx)+'\n')

print(repr(dx)+'\n')

dx = dx.reconstruct(subdomain_id=0)

print(repr(dx)+'\n')

dx = dx.reconstruct(subdomain_data
=MeshFunction("size_t",UnitSquareMesh(10,10),2))

print(repr(dx)+'\n')

print(repr(dx)+'\n')

print(repr(dx)+'\n')

written 11 weeks ago by David Kamensky
Unfortunately creating a new instance doesn't solve my current problem; but thanks for pointing out the difference between __call__ and reconstruct. I'm sure I would have been perplexed by this at some point.
written 10 weeks ago by Alexander G. Zimmerman

2
10 weeks ago by
As David suggested in the comments, the following runs without error:

import fenics

dx = fenics.Measure("dx")

​