Parameter descriptor#

In various simulations, it is necessary to have the possibility to define a parameter in several different ways. The most common case is to define a different value of a parameter in different regions of the mesh. This can be, for example, achieved by passing a dictionary, whose keys are the names of regions (strings), and values are the values of the parameter. On the other hand, if the parameter is not spatially varying, it is common to provide a single value.

Let us say we have a temperature parameter. We can pass the temperature as a single value for all discretisation cells (T = 300) or as a dictionary (T = {'region1': 250, 'region2': 300}) defining the temperature in different regions. Accordingly, we need a descriptor which would be able to accept both values. More precisely, the passed value has to satisy the following checks:

  1. If the value is not a dictionary, does it satisfy the rules of a descriptor passed as descriptor argument.

  2. If the value is a dictionary, are all its keys valid Python variable names (ubermagutil.typesystem.Name) and all its values satisfy the rules of a descriptor passed as descriptor argument.

Let us now impose the typesystem using ubermagutil.typesystem.Parameter descriptor.

[1]:
import ubermagutil.typesystem as ts


@ts.typesystem(T=ts.Parameter(descriptor=ts.Scalar()))
class Weather:
    def __init__(self, T):
        self.T = T

We can now instantiate the class and set T attribute.

[2]:
w = Weather(T=300)
w.T
[2]:
300

We can also change its value to be a dictionary.

[3]:
w.T = {"region1": 250, "region2": 300}
w.T
[3]:
{'region1': 250, 'region2': 300}

However, if we attempt to pass a tuple, an exception is raised:

[4]:
try:
    w.T = (250, 300)
except TypeError:
    print("Exception raised.")
Exception raised.

An exception will also be raised if we attempt to pass an empty dictionary:

[5]:
try:
    w.T = {}
except ValueError:
    print("Exception raised.")
Exception raised.

Similarly, if the dictionary is not well defined, the value is rejected.

[6]:
try:
    w.T = {"region1": 250, "region2": (300, 200)}
except TypeError:
    print("Exception raised.")
Exception raised.

ValueError would also be raised if one of the keys of the dictionary is not a valid Python variable name.

[7]:
try:
    w.T = {"region1": 250, "region 2": (300, 200)}
except ValueError:
    print("Exception raised.")
Exception raised.

Similar to other descriptors, we can also pass const=True to forbid changing the value of the attribute.

[8]:
@ts.typesystem(T=ts.Parameter(descriptor=ts.Scalar(), const=True))
class Weather:
    def __init__(self, T):
        self.T = T


w = Weather(T=300)
w.T
[8]:
300

If we try to change its value:

[9]:
try:
    w.T = 250
except AttributeError:
    print("Exception raised.")
Exception raised.