Nutils 3 Dragon Beard
Nutils 3.0 was released on August 22nd, 2018.
Nutils 3.1 was released on February 5th, 2018.
What's New?
These are the main additions and changes since Nutils 2 Chuka Men.
New: function.Namespace
The nutils.function.Namespace
object represents a container of
nutils.function.Array
instances:
ns = function.Namespace()
ns.x = geom
ns.basis = domain.basis('std', degree=1).vector(2)
In addition to bundling arrays, arrays can be manipulated using index notation
via string expressions using the nutils.expression
syntax:
ns.sol_i = 'basis_ni ?dofs_n'
f = ns.eval_i('sol_i,j n_j')
New: Topology.integral
Analogous to nutils.topology.Topology.integrate
, which integrates a function
and returns the result as a (sparse) array, the new method
nutils.topology.Topology.integral
with identical arguments results in an
nutils.sample.Integral
object for postponed evaluation:
x = domain.integrate(f, geometry=geom, degree=2) # direct
integ = domain.integral(f, geometry=geom, degree=2) # indirect
x = integ.eval()
Integral objects support linear transformations, derivatives and substitutions.
Their main use is in combination with routines from the nutils.solver
module.
Removed: TransformChain, CanonicalTransformChain
Transformation chains (sequences of transform items) are stored as standard tuples. Former class methods are replaced by module methods:
elem.transform.promote(ndims) # no longer valid
transform.promote(elem.transform, ndims) # new syntax
In addition, every edge_transform
and child_transform
of Reference objects
is changed from (typically unit-length) TransformChain
to
nutils.transform.TransformItem
.
Changed: command line interface
Command line parsers nutils.cli.run
or nutils.cli.choose
dropped support
for space separated arguments (--arg value), requiring argument and value to be
joined by an equals sign instead:
python script.py --arg=value
Boolean arguments are specified by omitting the value and prepending 'no' to the argument name for negation:
python script.py --pdb --norichoutput
For convenience, leading dashes have been made optional:
python script.py arg=value pdb norichoutput
New: Topology intersections (deprecates common_refinement)
Intersections between topologies can be made using the &
operator. In case
the operands have different refinement patterns, the resulting topology will
consist of the common refinements of the intersection:
intersection = topoA & topoB
interface = topo['fluid'].boundary & ~topo['solid'].boundary
Changed: Topology.indicator
The nutils.topology.Topology.indicator
method is moved from subtopology to
parent topology, i.e. the topology you want to evaluate the indicator on, and
now takes the subtopology is an argument:
ind = domain.boundary['top'].indicator() # no longer valid ind = domain.boundary.indicator(domain.boundary['top']) # new syntax ind = domain.boundary.indicator('top') # equivalent shorthand
Changed: Evaluable.eval
The nutils.function.Evaluable.eval
method accepts a flexible number of
keyword arguments, which are accessible to evalf
by depending on the
EVALARGS
token. Standard keywords are _transforms
for transformation
chains, _points
for integration points, and _cache
for the cache object:
f.eval(elem, 'gauss2') # no longer valid
ip, iw = elem.getischeme('gauss2')
tr = elem.transform, elem.opposite
f.eval(_transforms=tr, _points=ip) # new syntax
New: numeric.const
The numeric.const
array represents an immutable, hashable array:
A = numeric.const([[1,2],[3,4]])
d = {A: 1}
Existing arrays can be wrapped into a const
object by adding copy=False
.
The writeable
flag of the original array is set to False to prevent
subsequent modification:
A = numpy.array([1,2,3])
Aconst = numeric.const(A, copy=False)
A[1] = 4
# ValueError: assignment destination is read-only
New: function annotations
The util.enforcetypes
decorator applies conversion methods to annotated
arguments:
@util.enforcetypes
def f(a:float, b:tuple)
print(type(a), type(b))
f(1, [2])
# <class 'float'> <class 'tuple'>
The decorator is by default active to constructors of cache.Immutable derived objects, such as function.Evaluable.
Changed: Evaluable._edit
Evaluable objects have a default edit implementation that re-instantiates the
object with the operand applied to all constructor arguments. In situations
where the default implementation is not sufficient it can be overridden by
implementing the edit
method (note: without the underscore):
class B(function.Evaluable):
def __init__(self, d):
assert isinstance(d, dict)
self.d = d
def edit(self, op):
return B({key: op(value) for key, value in self.d.items()})
Changed: function derivatives
The nutils.function.derivative
axes
argument has been removed;
derivative(func, var)
now takes the derivative of func
to all the axes in
var
:
der = function.derivative(func, var,
axes=numpy.arange(var.ndim)) # no longer valid
der = function.derivative(func, var) # new syntax
New module: cli
The nutils.util.run
function is deprecated and replaced by two new functions,
nutils.cli.choose
and nutils.cli.run
. The new functions are very similar to
the original, but have a few notable differences:
cli.choose
requires the name of the function to be executed (typically 'main'), followed by any optional argumentscli.run
does not require the name of the function to be executed, but only a single one can be specified- argument conversions follow the type of the argument's default value, instead
of the result of
eval
- the
--tbexplore
option for post-mortem debugging is replaced by--pdb
, replacing Nutils' own traceback explorer by Python's builtin debugger - on-line debugging is provided via the ctrl+c signal handler
- function annotations can be used to describe arguments in both help messages and logging output (see examples)
New module: solver
The nutils.solver
module provides infrastructure to facilitate formulating
and solving complicated nonlinear problems in a structured and largely
automated fashion.
New: topology.with{subdomain,boundary,interfaces,points}
Topologies have been made fully immutable, which means that the old setitem
operation is no longer supported. Instead, to add a subtopology to the domain,
its boundary, its interfaces, or points, any of the methods withsubdomain
,
withboundary
, withinterfaces
, and withpoints
, respectively, will return a
copy of the topology with the desired groups added:
topo.boundary['wall'] = topo.boundary['left,top'] # no longer valid
newtopo = topo.withboundary(wall=topo.boundary['left,top']) # new syntax
newtopo = topo.withboundary(wall='left,top') # equivalent shorthand
newtopo.boundary['wall'].integrate(...)
New: circular symmetry
Any topology can be revolved using the new nutils.topology.Topology.revolved
method, which interprets the first geometry dimension as a radius and replaces
it by two new dimensions, shifting the remaining axes backward. In addition to
the modified topology and geometry, simplifying function is returned as the
third return value which replaces all occurrences of the revolution angle by
zero. This should only be used after all gradients have been computed:
rdomain, rgeom, simplify = domain.revolved(geom)
basis = rdomain.basis('spline', degree=2)
M = function.outer(basis.grad(rgeom)).sum(-1)
rdomain.integrate(M, geometry=rgeom, ischeme='gauss2', edit=simplify)
Renamed mesh.gmesh to mesh.gmsh; added support for periodicity
The gmsh importer was unintentionally misnamed as gmesh; this has been fixed. With that the old name is deprecated and will be removed in future. In addition, support for the non-physical mesh format and externally supplied boundary labels has been removed (see the unit test tests/mesh.py for examples of valid .geo format). Support is added for periodicity and interface groups.