solver
The solver module defines solvers for problems of the kind res = 0 or
∂inertia/∂t + res = 0, where res is a
nutils.evaluable.AsEvaluableArray. To demonstrate this consider the
following setup:
>>> from nutils import mesh, function, solver
>>> ns = function.Namespace()
>>> domain, ns.x = mesh.rectilinear([4,4])
>>> ns.basis = domain.basis('spline', degree=2)
>>> cons = domain.boundary['left,top'].project(0, onto=ns.basis, geometry=ns.x, ischeme='gauss4')
project > constrained 11/36 dofs, error 0.00e+00/area
>>> ns.u = 'basis_n ?lhs_n'
Function u represents an element from the discrete space but cannot not
evaluated yet as we did not yet establish values for ?lhs. It can,
however, be used to construct a residual functional res. Aiming to solve
the Poisson problem u_,kk = f we define the residual functional res = v,k
u,k + v f and solve for res == 0 using solve_linear:
>>> res = domain.integral('(basis_n,i u_,i + basis_n) d:x' @ ns, degree=2)
>>> lhs = solver.solve_linear('lhs', residual=res, constrain=cons)
solve > solving for argument lhs (36) using direct method
solve > residual norm: 1.5e-15
The coefficients lhs represent the solution to the Poisson problem.
In addition to solve_linear the solver module defines newton and
pseudotime for solving nonlinear problems, as well as impliciteuler for
time dependent problems.
- class nutils.solver.NormBased(minscale=0.01, acceptscale=0.6666666666666666, maxscale=2.0)
Bases:
objectLine search abstraction for Newton-like iterations, computing relaxation values that correspond to greatest reduction of the residual norm.
- Parameters:
minscale (
float) – Minimum relaxation scaling per update. Must be strictly greater than zero.acceptscale (
float) – Relaxation scaling that is considered close enough to optimality to to accept the current Newton update. Must lie between minscale and one.maxscale (
float) – Maximum relaxation scaling per update. Must be greater than one, and therefore always coincides with acceptance, determining how fast relaxation values rebound to one if not bounded by optimality.
- __weakref__
list of weak references to the object
- class nutils.solver.MedianBased(minscale=0.01, acceptscale=0.6666666666666666, maxscale=2.0, quantile=0.5)
Bases:
objectLine search abstraction for Newton-like iterations, computing relaxation values such that half (or any other configurable quantile) of the residual vector has its optimal reduction beyond it. Unline the
NormBasedapproach this is invariant to constant scaling of the residual items.- Parameters:
minscale (
float) – Minimum relaxation scaling per update. Must be strictly greater than zero.acceptscale (
float) – Relaxation scaling that is considered close enough to optimality to to accept the current Newton update. Must lie between minscale and one.maxscale (
float) – Maximum relaxation scaling per update. Must be greater than one, and therefore always coincides with acceptance, determining how fast relaxation values rebound to one if not bounded by optimality.quantile (
float) – Fraction of the residual vector that is aimed to have its optimal reduction at a smaller relaxation value. The default value of one half corresponds to the median. A value close to zero means tighter control, resulting in strong relaxation.
- __weakref__
list of weak references to the object
- class nutils.solver.System(residual, /, trial, test=None)
Bases:
objectSystem of one or more variables.
The System class represents a linear or nonlinear problem of one or more variables, and offers several methods to solve it. The main solution method is
solve, which serves as a general entry point that offloads the problem to specialized solvers. The other prominent method isstep, which adds functionality to deal with time dependent problems.- __init__(self, residual, /, trial, test=None)
Construct a system.
- Parameters:
residual – Any object that supports conversion to a scalar evaluable Array via the AsEvaluableArray protocol. This is the function that the trial arguments will seek to make constant in all the test arguments, or zero in all the derivatives. If provided as a tuple of vectors then these are already the derivatives to be made zero, and no test arguments may be specified.
trial – Names of the trial arguments, provided as a string (‘arg1,arg2’) or tuple of strings ((‘arg1’, ‘arg2’)).
test – Names of the test arguments (optional) provided as a string or tuple of strings. Must be omitted if residual is a tuple of vectors; otherwise, may be omitted if test and trial are equal.
- solve(self, *, arguments={}, constrain={}, tol=0.0, miniter=0, maxiter=None, method=None)
Solve the system.
Determines the trial arguments for which the derivatives of the system’s scalar functional are zero in all the test arguments.
- Parameters:
arguments – Arguments required to evaluate the system. Arguments that coincide with the system’s trial arguments serve as initial guess.
constrain – Constrained values for any of the trial arguments, supplied as float vectors with NaN entries or boolean vectors, the latter holding values at those of the initial guess.
tol – Maximum residual norm, stopping criterion for the iterative solver. Required for nonlinear problems.
miniter – Minimum number of iterations for the iterative solver, overruling to
tolbased stopping criterion.maxiter – Maximum number of iterations, after which a
SolverErroris raised.method – Iterative solution method, in the form of a callable that returns an iterator of (arguments, resnorm, value) triplets.
- step(self, *, arguments, suffix, timearg=None, timesteparg=None, timestep=None, maxretry=2, **solveargs)
Advance a time step.
This method is best described by an example. Let
timeargequal ‘t’ andsuffix‘0’, and let our system’s trial arguments be ‘u’ and ‘v’. This method then creates argument copies ‘t0’, ‘u0’, ‘v0’, advances ‘t’ bytimestep, and solves for the new ‘u’ and ‘v’.- Parameters:
arguments – Arguments required to evaluate the system. Arguments that coincide with the system’s trial arguments serve as initial value.
suffix – String suffix to add to argument names to denote their value at the beginning of the time step.
timearg – Name of the scalar argument that tracks the time (optional).
timesteparg – Name of the scalar argument that tracks the timestep (optional).
timestep – Size of the time increment (required if either timearg or timesteparg are specified).
maxretry – If either timearg or timesteparg are specified and affecting the system, then this positive integer determines how many levels of timestep bisections will be considered to recover from solver or matrix errors.
solveargs – Remaining keyword arguments are passed on to the
solvermethod.
- solve_constraints(self, *, droptol, arguments={}, constrain={}, linargs={})
Solve for Dirichlet constraints.
This method is similar to
solve, but with two key differences.The method is limited to linear systems, but adds the ability to solve a limited class of singular systems. It does so by isolating the subset of arguments that contribute (up to droptol) to the residual, and solving the corresponding submatrix. The remaining argument values are returned as NaN (not a number).
The second key difference with solve is that the returned dictionary is augmented with the remaining _constrain_ items, rather than those from _arguments_, reflecting the method’s main utility of forming Dirichlet constraints. This allows for the aggregation of constraints by calling the method multiple times in series.
- Parameters:
arguments – Arguments required to evaluate the system. Any arguments that coincide with the system’s trial arguments serve as initial guess.
constrain – Constrained values for any of the trial arguments, supplied as float vectors with NaN entries or boolean vectors, the latter holding values at those of the initial guess.
linargs – Keyword arguments to be passed on to the linear solver.
droptol – Minimum absolute value if matrix entries for rows and columns to participate in the optimization problem.
- __weakref__
list of weak references to the object
- class nutils.solver.Direct(**linargs)
Bases:
objectDirect solution of a linear system.
- __weakref__
list of weak references to the object
- class nutils.solver.Newton(**linargs)
Bases:
objectNewton solver.
This solver generates the iterates
x_n+1 = x_n - J(x_n)^-1 r(x_n)consistent with a standard Newton process.- __weakref__
list of weak references to the object
- class nutils.solver.ReuseNewton(require=0.5, **linargs)
Bases:
objectNewton with approximate Jacobians.
This is a modification of the vanilla Newton process, in which a new Jacobian matrix is NOT created for every update, but an existing matrix is reused instead for as long as
|res(x - J^-1 res(x))| < require |res(x)|.When the condition no longer holds, a new Jacobian matrix is assembled and a standard Newton update is performed without regard for the
requireparameter.- __weakref__
list of weak references to the object
- class nutils.solver.LinesearchNewton(strategy=NormBased(minscale=0.01, acceptscale=0.6666666666666666, maxscale=2.0), failrelax=1e-06, relax0=1.0, **linargs)
Bases:
objectNewton solver with automatic relaxation.
This solver generates the iterates
x_n+1 = x_n - α J(x_n)^-1 r(x_n), where0 < α <= 1is a relaxation value. The value forαis initiallyrelax0, and subsequently determined by a configurablestrategy. If the value falls belowfailrelaxthen the solver fails with aSolverError.The default strategy is
NormBased, which employs a polynomial interpolation of the residual norm between the current value ofxand the prospective next value to determine at what value ofαthe residual norm is likely minimal.- __weakref__
list of weak references to the object
- class nutils.solver.Minimize(rampup=0.5, rampdown=-1.0, failrelax=-10.0, **linargs)
Bases:
objectDirect minimization of scalar functional.
This solver constructs a trajectory of steepest descent to find the minimizer of a locally convex scalar function.
- __weakref__
list of weak references to the object
- class nutils.solver.Arnoldi(maxiter=2, **linargs)
Bases:
objectArnoldi iterations for linear systems.
Upon first use, the Arnoldi solver behaves identically to Direct, in that it returns the solution to the linear system
A x = b.The difference arises when the method is reused. If the matrix and residual depend on a second set of arguments, as in
A(y) x = b(y), then the Arnoldi solver will aim to benefit from an existing factorization ofP = A(y_previous)^-1by projectingxon the growing subspace[P b(y), P^2 b(y), P^3 b(y), ..).If the desired tolerance is not reached at a configurable subspace dimension of
maxiter, then the system is solved withA(y)and the cached matrix updated for subsequent reuse.- __weakref__
list of weak references to the object
- class nutils.solver.Pseudotime(inertia, timestep, **linargs)
Bases:
objectInertia assisted Newton.
This solver is a variant of the Newton solver for problems that do not converge along the standard Newton path. For problems that represent the steady state solution of a dynamic system, the pseudo-time solver uses a provided inertia matrix to progress towards the steady state along the (approximately) physical path using ever larger time steps.
Concretely, rather than forming updates of the form
J(x) dx = r(x), the pseudo-time solver solves(J(x) + dJ / dt) dx = r(x), wheredJis the provided inertia matrix anddtis the configured initialtimestepscaled by the ratio of|r(x0)| / |r(x)|.- __weakref__
list of weak references to the object
- nutils.solver.solve_linear(target, residual, *, constrain=None, lhs0=None, arguments={}, **kwargs)
solve linear problem
- Parameters:
target (
str) – Name of the target: anutils.function.Argumentinresidual.residual (
nutils.evaluable.AsEvaluableArray) – Residual integral, depends ontargetconstrain (
numpy.ndarraywith dtypefloat) – Defines the fixed entries of the coefficient vectorarguments (
collections.abc.Mapping) – Defines the values fornutils.function.Argumentobjects in residual. Thetargetshould not be present inarguments. Optional.
- Returns:
Array of
targetvalues for whichresidual == 0- Return type:
- nutils.solver.newton(target, residual, *, jacobian=None, lhs0=None, relax0=1.0, constrain=None, linesearch=NormBased(minscale=0.01, acceptscale=0.6666666666666666, maxscale=2.0), failrelax=1e-06, arguments={}, **kwargs)
iteratively solve nonlinear problem by gradient descent
Generates targets such that residual approaches 0 using Newton procedure with line search based on the residual norm. Suitable to be used inside
solve.An optimal relaxation value is computed based on the following cubic assumption:
|res(lhs + r * dlhs)|^2 = A + B * r + C * r^2 + D * r^3
where
A,B,CandDare determined based on the current residual and tangent, the new residual, and the new tangent. If this value is found to be close to 1 then the newton update is accepted.- Parameters:
target (
str) – Name of the target: anutils.function.Argumentinresidual.residual (
nutils.evaluable.AsEvaluableArray)relax0 (
float) – Initial relaxation value.constrain (
numpy.ndarraywith dtypeboolorfloat) – Masks the free vector entries asFalse(boolean) or NaN (float). In the remaining positions the values oflhs0are returned unchanged (boolean) or overruled by the values in constrain (float).linesearch (Callable[[float, float, float, float], Tuple[float, bool]]) – Callable that defines relaxation logic. The callable takes four arguments: the current residual and directional derivative, and the candidate residual and directional derivative, with derivatives normalized to unit length; and returns the optimal scaling and a boolean flag that marks whether the candidate should be accepted.
failrelax (
float) – Fail with exception if relaxation reaches this lower limit.arguments (
collections.abc.Mapping) – Defines the values fornutils.function.Argumentobjects in residual. Iftargetis present inargumentsthen it is used as the initial guess for the iterative procedure.
- Yields:
numpy.ndarray– Coefficient vector that approximates residual==0 with increasing accuracy
- nutils.solver.minimize(target, energy, *, lhs0=None, constrain=None, rampup=0.5, rampdown=-1.0, failrelax=-10.0, arguments={}, **kwargs)
iteratively minimize nonlinear functional by gradient descent
Generates targets such that residual approaches 0 using Newton procedure with line search based on the energy. Suitable to be used inside
solve.An optimal relaxation value is computed based on the following assumption:
energy(lhs + r * dlhs) = A + B * r + C * r^2 + D * r^3 + E * r^4 + F * r^5
where
A,B,C,D,EandFare determined based on the current and new energy, residual and tangent. If this value is found to be close to 1 then the newton update is accepted.- Parameters:
target (
str) – Name of the target: anutils.function.Argumentinresidual.residual (
nutils.evaluable.AsEvaluableArray)constrain (
numpy.ndarraywith dtypeboolorfloat) – Masks the free vector entries asFalse(boolean) or NaN (float). In the remaining positions the values oflhs0are returned unchanged (boolean) or overruled by the values in constrain (float).rampup (
float) – Value to increase the relaxation power by in case energy is decreasing.rampdown (
float) – Value to decrease the relaxation power by in case energy is increasing.failrelax (
float) – Fail with exception if relaxation reaches this lower limit.arguments (
collections.abc.Mapping) – Defines the values fornutils.function.Argumentobjects in residual. Iftargetis present inargumentsthen it is used as the initial guess for the iterative procedure.
- Yields:
numpy.ndarray– Coefficient vector that approximates residual==0 with increasing accuracy
- nutils.solver.pseudotime(target, residual, inertia, timestep, *, lhs0=None, constrain=None, arguments={}, **kwargs)
iteratively solve nonlinear problem by pseudo time stepping
Generates targets such that residual approaches 0 using hybrid of Newton and time stepping. Requires an inertia term and initial timestep. Suitable to be used inside
solve.- Parameters:
target (
str) – Name of the target: anutils.function.Argumentinresidual.residual (
nutils.evaluable.AsEvaluableArray)inertia (
nutils.evaluable.AsEvaluableArray)timestep (
float) – Initial time step, will scale up as residual decreasesconstrain (
numpy.ndarraywith dtypeboolorfloat) – Masks the free vector entries asFalse(boolean) or NaN (float). In the remaining positions the values oflhs0are returned unchanged (boolean) or overruled by the values in constrain (float).arguments (
collections.abc.Mapping) – Defines the values fornutils.function.Argumentobjects in residual. Iftargetis present inargumentsthen it is used as the initial guess for the iterative procedure.
- Yields:
numpy.ndarraywith dtypefloat– Tuple of coefficient vector and residual norm
- nutils.solver.thetamethod(target, residual, inertia, timestep, theta, *, lhs0=None, constrain=None, newtontol=1e-10, arguments={}, newtonargs={}, timetarget='_thetamethod_time', time0=0.0, historysuffix='0')
solve time dependent problem using the theta method
- Parameters:
target (
str) – Name of the target: anutils.function.Argumentinresidual.residual (
nutils.evaluable.AsEvaluableArray)inertia (
nutils.evaluable.AsEvaluableArray)timestep (
float) – The time step.theta (
float) – Theta value (theta=1 for implicit Euler, theta=0.5 for Crank-Nicolson)residual0 (
nutils.evaluable.AsEvaluableArray) – Optional additional residual component evaluated in previous timestepconstrain (
numpy.ndarraywith dtypeboolorfloat) – Masks the free vector entries asFalse(boolean) or NaN (float). In the remaining positions the values oflhs0are returned unchanged (boolean) or overruled by the values in constrain (float).newtontol (
float) – Residual tolerance of individual timestepsarguments (
collections.abc.Mapping) – Defines the values fornutils.function.Argumentobjects in residual. Iftargetis present inargumentsthen it is used as the initial condition.timetarget (
str) – Name of thenutils.function.Argumentthat represents time. Optional.time0 (
float) – The intial time. Default:0.0.
- Yields:
numpy.ndarray– Coefficient vector for all timesteps after the initial condition.
- nutils.solver.impliciteuler(target, residual, inertia, timestep, *, theta=1, lhs0=None, constrain=None, newtontol=1e-10, arguments={}, newtonargs={}, timetarget='_thetamethod_time', time0=0.0, historysuffix='0')
solve time dependent problem using the theta method
- Parameters:
target (
str) – Name of the target: anutils.function.Argumentinresidual.residual (
nutils.evaluable.AsEvaluableArray)inertia (
nutils.evaluable.AsEvaluableArray)timestep (
float) – The time step.theta (
float) – Theta value (theta=1 for implicit Euler, theta=0.5 for Crank-Nicolson)residual0 (
nutils.evaluable.AsEvaluableArray) – Optional additional residual component evaluated in previous timestepconstrain (
numpy.ndarraywith dtypeboolorfloat) – Masks the free vector entries asFalse(boolean) or NaN (float). In the remaining positions the values oflhs0are returned unchanged (boolean) or overruled by the values in constrain (float).newtontol (
float) – Residual tolerance of individual timestepsarguments (
collections.abc.Mapping) – Defines the values fornutils.function.Argumentobjects in residual. Iftargetis present inargumentsthen it is used as the initial condition.timetarget (
str) – Name of thenutils.function.Argumentthat represents time. Optional.time0 (
float) – The intial time. Default:0.0.
- Yields:
numpy.ndarray– Coefficient vector for all timesteps after the initial condition.
- nutils.solver.cranknicolson(target, residual, inertia, timestep, *, theta=0.5, lhs0=None, constrain=None, newtontol=1e-10, arguments={}, newtonargs={}, timetarget='_thetamethod_time', time0=0.0, historysuffix='0')
solve time dependent problem using the theta method
- Parameters:
target (
str) – Name of the target: anutils.function.Argumentinresidual.residual (
nutils.evaluable.AsEvaluableArray)inertia (
nutils.evaluable.AsEvaluableArray)timestep (
float) – The time step.theta (
float) – Theta value (theta=1 for implicit Euler, theta=0.5 for Crank-Nicolson)residual0 (
nutils.evaluable.AsEvaluableArray) – Optional additional residual component evaluated in previous timestepconstrain (
numpy.ndarraywith dtypeboolorfloat) – Masks the free vector entries asFalse(boolean) or NaN (float). In the remaining positions the values oflhs0are returned unchanged (boolean) or overruled by the values in constrain (float).newtontol (
float) – Residual tolerance of individual timestepsarguments (
collections.abc.Mapping) – Defines the values fornutils.function.Argumentobjects in residual. Iftargetis present inargumentsthen it is used as the initial condition.timetarget (
str) – Name of thenutils.function.Argumentthat represents time. Optional.time0 (
float) – The intial time. Default:0.0.
- Yields:
numpy.ndarray– Coefficient vector for all timesteps after the initial condition.
- nutils.solver.optimize(target, functional, *, tol=0.0, arguments={}, droptol=None, constrain=None, lhs0=None, relax0=1.0, linesearch=NormBased(minscale=0.01, acceptscale=0.6666666666666666, maxscale=2.0), failrelax=1e-06, **kwargs)
find the minimizer of a given functional
- Parameters:
target (
str) – Name of the target: anutils.function.Argumentinresidual.functional (scalar
nutils.evaluable.AsEvaluableArray) – The functional the should be minimized by varying targettol (
float) – Target residual norm.arguments (
collections.abc.Mapping) – Defines the values fornutils.function.Argumentobjects in residual. Iftargetis present inargumentsthen it is used as the initial guess.droptol (
float) – Threshold for leaving entries in the return value at NaN if they do not contribute to the value of the functional.constrain (
numpy.ndarraywith dtypefloat) – Defines the fixed entries of the coefficient vectorrelax0 (
float) – Initial relaxation value.linesearch (Callable[[float, float, float, float], Tuple[float, bool]]) – Callable that defines relaxation logic. The callable takes four arguments: the current residual and directional derivative, and the candidate residual and directional derivative, with derivatives normalized to unit length; and returns the optimal scaling and a boolean flag that marks whether the candidate should be accepted.
failrelax (
float) – Fail with exception if relaxation reaches this lower limit.
- Yields:
numpy.ndarray– Coefficient vector corresponding to the functional optimum