State variables
The state variable for a given cell is determined by the material type, via overloading the create_cell_state function. To update old states to the new (just-converged) states, use update_states!, which by default copies the values so that both old and new states hold the converged values directly afterwards (safe to read immediately, e.g. for postprocessing).
Special cases
Two typical cases are considered by default. A type, CS, which defines the state for the entire cell and a cell state that consists of an AbstractVector{QS} where the type QS is the type of the state for each quadrature point. In the following both cases are described considering the type of the state CS or QS being denoted S as the type of the state.
Non isbits state
If S is not a bits type (isbitstype(S) = false), then the user must define either FerriteAssembly.copy_state or a FerriteAssembly.copy_state! for the default update_states! to work.
Alternatively, update_states! can be called with the keyword argument mode = :flip to just flip the references. However, this comes with the important caveat that one should never read values from the current state, see details in update_states!. This is useful for cases when the state consists of large data structures such as with $\mathrm{FE}^2$ simulations.
Reverting the states
If the current (new) state is used in the element routines (e.g. as initial guess), the function revert_states! can be used to update the states such that states = old_states before retrying to find the solution after a failed time step.
The state variable datastructure
The state variables are created when calling setup_domainbuffer or setup_domainbuffers, and stored inside the buffers. The states for a given domain are accessed with get_state and get_old_state, where the state for a particular cell is indexed by its cell number. (The output from the mentioned functions are Dict{Int})
API
FerriteAssembly.create_cell_state — Functioncreate_cell_state(material, cellvalues, x, ae, dofrange)Defaults to returning nothing.
Overload this function to create the state which should be passed into the element_routine!/element_residual! for the given material and cellvalues. x is the cell's coordinates, ae the element degree of freedom values, and dofrange::NamedTuple containing the local dof range for each field. As for the element routines, ae, is filled with NaN unless the global degree of freedom vector is given to the setup_domainbuffer function.
FerriteAssembly.create_cell_state(m::MMB.AbstractMaterial, cv::AbstractCellValues, args...)Create a Vector{<:MMM.AbstractMaterialState} where each element is the output from MMB.initial_material_state(m) and the length is the number of quadrature points in cv.
FerriteAssembly.update_states! — Functionupdate_states!(db::Dict{String,AbstractDomainBuffer}; mode::Symbol = :copy)
update_states!(db::AbstractDomainBuffer; mode::Symbol = :copy)
update_states!(sim::Simulation; mode::Symbol = :copy)Update the states such that old_states = states (the just-converged values) for the states stored in db.
mode selects how this is done:
mode = :copy(default): copies the values fromstatesintoold_states;statesitself is left untouched. This means bothold_statesandstatescorrectly hold the just-converged values directly after the call — safe to read (e.g. for postprocessing) immediately afterwards. Ifcreate_cell_statereturns a mutableAbstractArray, this reuses that array's own storage (no allocation for the array itself, though copying non-isbitselements into it may still allocate — unlessFerriteAssembly.copy_state!is overloaded for the element type, see below), and it must therefore keep the same axes between calls (ArgumentErrorotherwise). Any other non-isbitscell state must have aFerriteAssembly.copy_stateorFerriteAssembly.copy_state!method — otherwise aMethodErroris thrown. This is a breaking change from previous releases (which behaved likemode = :flip): a mutable, non-array cell state without acopy_state/copy_state!overload that used to work now throws; usemode = :flipto keep the old behavior for such states.mode = :flip: cheaply swaps the references ofold_statesandstates(no copying, no allocation, and nocopy_staterequirement — this is the behavior ofupdate_states!in releases prior to this change). After the call,states(the "new" container) holds the stale values from before this step, not the just-converged ones.Warning Under
mode = :flip,statesmust not be read again until it has been overwritten by the next call towork!— including implicitly, e.g. via a defaultQuadPointEvaluatorreadingget_state/sduring postprocessing right afterupdate_states!. Reading it earlier silently observes the previous step's data. If you need to read the just-converged state after updating (e.g. for postprocessing), use the defaultmode = :copyinstead.
FerriteAssembly.revert_states! — Functionrevert_states!(db::Dict{String,AbstractDomainBuffer})
revert_states!(db::AbstractDomainBuffer)
revert_states!(sim::Simulation)Update the states such that states = old_states for the states stored in db, i.e. the opposite direction of update_states!. This is useful when retrying a time increment after a non-converged solution, when the current (new) state is used as an initial guess (typical in staggered solution schemes). Requires FerriteAssembly.copy_state or FerriteAssembly.copy_state! for non isbits with the same requirements as stated in update_states! with mode = :copy.
FerriteAssembly.copy_state — Functioncopy_state(state)Return a copy of state such that the intended mutation of the returned value does not affect state. Used by update_states!'s default mode = :copy and by revert_states! to copy one state into the other, when copy_state! is not applicable for that value.
For a cell state that is a mutable AbstractArray (ismutable(state) == true), these functions apply this check element-wise; for any other cell state (including an immutable AbstractArray, e.g. built from NTuples or StaticArrays), it applies to the whole state. In both cases, values for which isbits(value) == true are copied by identity internally, without calling copy_state or copy_state!. This function has no default method, so it must be overloaded for the type of any value (the whole cell state, a whole immutable array, or a mutable array's element) for which isbits(value) == false, unless copy_state! is overloaded for that value's type instead.
FerriteAssembly.copy_state! — Functioncopy_state!(dst, src)Overwrite dst in place so that it matches the value of src; the return value is ignored.
An optional, allocation-avoiding alternative to copy_state for a value that is itself immutable (so copy_state would otherwise need to allocate a full replacement every time) but wraps a mutable payload that can instead be updated in place, e.g. struct MyState; vals::Vector{Float64}; end. A value's type needs at most one of copy_state!(dst, src) or copy_state(src) overloaded — never both — and if copy_state!(dst, src) is applicable, it takes precedence over copy_state(src). Neither is needed for isbits values.
FerriteAssembly.remove_dual — Functionremove_dual(x::T) where {T <: Number}
remove_dual(x::AbstractTensor{<:Any, <:Any, T}) where {T}Removes the dual part if T <: ForwardDiff.Dual, extract the value part. Typically used when assigning state variables during differentiation calls.