Source code for dolfinx_adjoint.function

from __future__ import annotations

import typing

import dolfinx
import numpy
import ufl
from pyadjoint.overloaded_type import (
    create_overloaded_object,
)
from pyadjoint.tape import annotate_tape, get_working_tape, stop_annotating

from .blocks.function_assigner import FunctionAssignBlock
from .types.function import Function as _Function
from .utils import ad_kwargs, assign_linear_combination


[docs] def assign(value: typing.Union[numpy.inexact, float, int], function: _Function, **kwargs: typing.Unpack[ad_kwargs]): """Assign a `value` to a :py:func:`dolfinx_adjoint.Function`. Args: value: The value to assign to the function. function: The function to assign the value to. *args: Additional positional arguments to pass to the assign method. **kwargs: Additional keyword arguments to pass to the assign method. """ # do not annotate in case of self assignment ad_block_tag = kwargs.pop("ad_block_tag", None) annotate = annotate_tape(kwargs) and value != function if annotate: if not isinstance(value, ufl.core.operator.Operator): value = create_overloaded_object(value) block = FunctionAssignBlock(value, function, ad_block_tag=ad_block_tag) tape = get_working_tape() tape.add_block(block) with stop_annotating(): if isinstance(value, (numpy.inexact, float, int)): function.x.array[:] = value elif isinstance(value, dolfinx.fem.Function): if value.function_space == function.function_space: function.x.array[:] = value.x.array[:] elif ufl.checks.is_scalar_constant_expression(value): function.x.array[:] = value.x.array[0] else: raise ValueError("Function spaces of the value and function must match for assignment.") elif isinstance(value, ufl.core.expr.Expr): # Linear combination of functions, e.g., 2*u + 3*v assign_linear_combination(value, function) else: raise ValueError(f"Unsupported value type for assignment: {type(value)})") if annotate: block.add_output(function.create_block_variable())