API
The main types below are exported. Remaining functions are not exported to avoid polluting the name space. Tip: To simplify calling the following functions it is possible to write import FerriteProblems as FP
as is done in the examples.
Main types
FerriteProblems.FerriteProblem
— TypeFerriteProblem(def::FEDefinition, post=nothing, io=nothing; kwargs...)
FerriteProblem(def::FEDefinition, post, savefolder::String; kwargs...)
Create a FerriteProblem from def
. Postprocessing can be added as post
, see FESolvers.postprocess!
. File input/output using FerriteIO
can be added with io
. It is also possible to just give the savefolder
, i.e. where to save the output when the default FerriteIO
can be used.
Supported keyword arguments are
autodiffbuffer::Bool
: ShouldFerriteAssembly.jl
'sAutoDiffCellBuffer
be used? This will make the assembly faster if automatic differentiation is used, and can also be used without automatic differentiation (but with a slight extra computational overhead)threading::Bool
: Should threading be used?
FerriteProblems.FEDefinition
— TypeFEDefinition(
domainspec::Union{DomainSpec,Dict{String,DomainSpec}};
ch, lh=LoadHandler(dh),
convergence_criterion=AbsoluteResidual(),
initial_conditions=NamedTuple(),
)
Create the FEDefinition
which can later be used to create a complete FerriteProblem
. domainspec
is the FerriteAssembly
domain specification.
In addition, the following keyword arguments can be given
ch
: The constraint handler,ConstraintHandler
(Ferrite.jl
)lh
: The external load handler,LoadHandler
(FerriteAssembly.jl
)initial_conditions
: NamedTuple with a functionf(x)
for each field that has a nonzero initial condition. Used by theFerrite.jl
'sapply_analytical!
function. Example:initial_conditions = (u = x -> Vec((x[1]/10, 0.0)), p = x -> -100*x[2])
. For fields not given here, the initial condition is zeros everywhere.convergence_criterion
: Determines how to calculate the convergence measure including scaling. SeeConvergenceCriterion
FerriteProblems.FerriteIO
— TypeFerriteIO(
folder::String, def::FEDefinition, post=nothing;
def_file="FEDefinition.jld2",
postfile="FEPost.jld2",
T=Float64,
nsteps_per_file=typemax(Int),
switchsize=Inf
)
Constructor for creating a FerriteIO
when simulating.
FerriteIO(filepath::String)
Constructor for reading a FerriteIO
that was saved during a simulation. The default filename is FerriteIO.jld2
, located in the savefolder
given to the FerriteProblem
constructor when setting up the simulation.
Can be called either with the do-block (recommended),
FerriteIO(filepath) do io
# Do whatever with io
end
or by manually closing,
io = FerriteIO(filepath)
# Do whatever with io
close(io)
Convergence criteria
In normal usage, the following convergence criteria can be used
FerriteProblems.ConvergenceCriterion
— TypeConvergenceCriterion
The abstract type ConvergenceCriterion
is the supertype for all convergence criteria.
FerriteProblems.AbsoluteResidual
— TypeAbsoluteResidual()
The default convergence criterion that calculates the convergence measure as √(sum([r[i]^2 for i ∈ free dofs])
without any scaling.
FerriteProblems.RelativeResidualElementScaling
— TypeRelativeResidualElementScaling(;p = 2, minfactors::Union{AbstractFloat,NamedTuple}=eps())
Use Ferriteassembly.ElementResidualScaling
with the exponent p
to calculate the scaling for each field individually, based on the Lp-norm of each cell's residual. To avoid issues when all cells have zero residual (e.g. in the first time step), supply minfactors
as the minimum scaling factor. The convergence measure is calculated with the following pseudo-code
val = 0.0
for field in Ferrite.getfieldnames(dh)
factor = max(element_residual_scaling[field], minfactors[field])
dofs = free_field_dofs[field] # Get the non-constrained dofs for `field`
val += sum(i->(r[i]/factor)^2, dofs)
end
return √val
where the same minfactor
is used for all fields if only a scalar value is given.
To create custom convergence criteria, the following functions may require overloading.
FerriteProblems.TolScaling
— TypeTolScaling(criterion::ConvergenceCriterion, def::FEDefinition)
The TolScaling
type contains the criterion
that determines how to scale the residuals to determine convergence. The constructor is specialized on typeof(criterion)
, creating the following fields:
assemscaling
:scaling
to be used byFerriteAssembly
to give potential scaling contribution based on each element's residualbuffer
: Used to pre-calculate values, such as dof-ranges for each field that is used when calculating the convergence measure.
FESolvers.calculate_convergence_measure
— Functioncalculate_convergence_measure(problem, Δa, iter) -> AbstractFloat
Calculate a value to be compared with the tolerance of the nonlinear solver. A standard case when using Ferrite.jl is norm(getresidual(problem)[Ferrite.free_dofs(ch)])
where ch::Ferrite.ConstraintHandler
. Δa
is the update of the unknowns from the previous iteration. Note that iter=1
implies Δa=0
FerriteProblems.make_assemscaling
— Functionmake_assemscaling(criterion, def)
Create the scaling
for use in FerriteAssembly
if required by the given criterion
. The default, if not overloaded, returns nothing
.
Access functions
FerriteAssembly.get_dofhandler
— MethodFerriteProblems.get_dofhandler(p::FerriteProblem)
Get dh::Ferrite.AbstractDofHandler
from the FerriteProblem
(Technically overloaded from FerriteAssembly
, but accessible via FerriteProblems
)
FerriteProblems.get_constrainthandler
— MethodFerriteProblems.get_constrainthandler(p::FerriteProblem)
Get the ConstraintHandler
from the FerriteProblem
FerriteProblems.get_loadhandler
— MethodFerriteProblems.get_loadhandler(p::FerriteProblem)
Get the LoadHandler
from the FerriteProblem
FerriteAssembly.get_material
— MethodFerriteProblems.get_material(p::FerriteProblem)
FerriteProblems.get_material(p::FerriteProblem, domain_name::String)
Get the material in p
. For multiple domains, it is necessary to give the domain_name
for where to get the material. Note that this is type-unstable and should be avoided in performance-critical code sections. This function belongs to FerriteAssembly.jl
, but can be accessed via FerriteProblems.get_material
.
FESolvers.getjacobian
— MethodFerriteProblems.getjacobian(p::FerriteProblem)
Get the current jacobian matrix from p
. Note that this function belongs to FESolvers.jl
, but can be accessed via FerriteProblems.getjacobian
FESolvers.getunknowns
— MethodFerriteProblems.getunknowns(p::FerriteProblem)
Get the current vector of unknowns from p
. Note that this function belongs to FESolvers.jl
, but can be accessed via FerriteProblems.getunknowns
FESolvers.getresidual
— MethodFerriteProblems.getresidual(p::FerriteProblem)
Get the current residual vector from p
. Note that this function belongs to FESolvers.jl
, but can be accessed via FerriteProblems.getresidual
FerriteProblems.get_external_force
— MethodFerriteProblems.getneumannforce(p::FerriteProblem)
Get the current external force vector caused by Neumann boundary conditions. Note that this vector does not include external forces added during the cell assembly; only forces added with the NeumannHandler
FerriteProblems.get_old_unknowns
— MethodFerriteProblems.get_old_unknowns(p::FerriteProblem)
Get the vector of unknowns from the previously converged step
FerriteAssembly.get_state
— MethodFerriteProblems.get_state(p::FerriteProblem)
Get the current state variables
FerriteAssembly.get_old_state
— MethodFerriteProblems.getoldstate(p::FerriteProblem)
Get the state variables from the previously converged step
FerriteProblems.get_time
— MethodFerriteProblems.get_time(p::FerriteProblem)
Get the current time
FerriteProblems.get_old_time
— MethodFerriteProblems.getoldtime(p::FerriteProblem)
Get time of the previous converged step
Saving and loading data
FESolvers.handle_notconverged!
— MethodFESolvers.handle_notconverged!(post, p::FerriteProblem, solver)
Optional overload which is called when the problem doesn't converge for the current attempt. Allows for example to modify the problem or add special postprocessing to investigate convergence issues.
If the problem is modified, and an adaptive time stepper is used, the adaptive time stepper will still consider the problem as not converged, and adapt the time-stepping accordingly. Currently, there is no interface to prevent this, and usage with a fixed time stepping might make more sense. However, by modifying the solver
's state, it is possible to trick the adaptive time stepper to not modify the time step, but this requires using non-stable and non-public API.
FESolvers.postprocess!
— MethodFESolvers.postprocess!(p::FerriteProblem, solver)
When FESolvers
call this function for p::FerriteProblem
, the following function
FESolvers.postprocess!(post, p::FerriteProblem, solver)
is called where post=p.post
(unless you define a different override). This allows you to easily define the dispatch on your postprocessing type as FESolvers.postprocess!(post::MyPostType, p, solver)
FerriteProblems.close_postprocessing
— Functionclose_postprocessing(post::MyPostType, p::FerriteProblem)
This function is called to close any open files manually created during the postprocessing with the custom postprocessing type MyPostType
. Note that the file streams in p.io::FerriteIO are automatically closed and don't require any special handling.
FerriteProblems.addstep!
— FunctionFerriteProblems.addstep!(io::FerriteIO, p::FerriteProblem)
Add a new step to be saved by io
at the time gettime(p)
Must be called before adding any new data
FerriteProblems.gettimedata
— Functiongettimedata(io::FerriteIO)
gettimedata(io::FerriteIO, step)
FerriteProblems.savedofdata!
— FunctionFerriteProblems.savedofdata!(io::FerriteIO, vals, dt_order=0, field="dof")
Save data pertaining to each degree of freedom. Use a different field than "dof"
` to save data located at each dof, but not the actual dof values (e.g. the residual vector)
FerriteProblems.getdofdata
— FunctionFerriteProblems.getdofdata(io::FerriteIO, step, field="dof"; dt_order=0)
Get the data saved by FerriteProblems.savedofdata!
in step
for field
.
FerriteProblems.savenodedata!
— FunctionFerriteProblems.savenodedata!(io::FerriteIO, vals, field, dt_order=0)
Save data located at each node. By convention this should be indexed by the node numbers in the grid. (E.g. a Vector
for all nodes or a Dict{Int}
with keys the node numbers)
FerriteProblems.getnodedata
— FunctionFerriteProblems.getnodedata(io::FerriteIO, step, field; dt_order=0)
Get the data saved by FerriteProblems.savenodedata!
in step
for field
.
FerriteProblems.savecelldata!
— FunctionFerriteProblems.savecelldata!(io::FerriteIO, vals, field, dt_order=0)
Save data for each cell. By convention this should be indexed by the cell numbers in the grid. (E.g. a Vector
for all cells or a Dict{Int}
with keys the cell indices)
FerriteProblems.getcelldata
— FunctionFerriteProblems.getcelldata(io::FerriteIO, step, field; dt_order=0)
Get the data saved by FerriteProblems.savecelldata!
in step
for field
.
FerriteProblems.saveipdata!
— FunctionFerriteProblems.saveipdata!(io::FerriteIO, vals, field, dt_order=0)
Save data for each integration point in cells in the grid. By convention the data for each cell should be indexed by the cell numbers in the grid. (E.g. a Vector
for all cells or a Dict{Int}
with keys the cell indices) Note that it is on the user to know how the integration points are numbered, i.e. which QuadratureRule
that was used.
FerriteProblems.getipdata
— FunctionFerriteProblems.getipdata(io::FerriteIO, step, field; dt_order=0)
Get the data saved by FerriteProblems.saveipdata!
in step
for field
.
FerriteProblems.saveglobaldata!
— FunctionFerriteProblems.saveglobaldata!(io::FerriteIO, vals, field, dt_order=0)
Save data that is global to the entire simulation, i.e. global quantites such as reaction forces, total dissipation, etc.
FerriteProblems.getglobaldata
— FunctionFerriteProblems.getglobaldata(io::FerriteIO, step, field; dt_order=0)
Get the data saved by FerriteProblems.saveglobaldata!
in step
for field
.
FerriteProblems.getdef
— FunctionFerriteProblems.getdef(io::FerriteIO)
Load the FEDefinition
from the results saved by io
FerriteProblems.getpost
— FunctionFerriteProblems.getpost(io::FerriteIO)
Load the user defined post
from the results saved by io