Operator interface
This page lists the dispatch points that a new format, sparsity pattern, or conversion path can hook into. The surrounding narrative for how to extend Quoll is in Defining new methods; this page is the reference.
All methods below live in the Quoll namespace. They are not exported, but they are stable and may be specialised by downstream code without touching Quoll.jl itself.
Metadata hooks (required per format)
A format is identified by its metadata type (e.g. FHIaimsCSCRealMetadata). Every format must resolve these type-level queries:
| Function | Returns |
|---|---|
op_data_type(::Type{M}) | The DataContainer alias for the operator's data |
op_source_type(::Type{M}) | The AbstractSource singleton type |
op_sparsity_type(::Type{M}) | The AbstractSparsity subtype |
op_keydata_type(::Type{M}) | The DataContainer alias for keyed data (needed only if your format works with KeyedOperator) |
See src/operators/fhiaims.jl for a minimal example.
Loading
To load operators from disk in your format, implement:
| Function | Purpose |
|---|---|
load_metadata_basic(::Type{M}, dir, kind) | Build a BasicMetadataContainer from files on disk |
load_metadata(::Type{M}, dir, basic_metadata) | Wrap the basic container into the concrete metadata type (Real/Recip/SpinReal/SpinRecip) |
load_data(::Type{M}, dir, kind) | Read the data array from disk |
get_avail_filenames(::Type{M}, kind) | Return candidate on-disk filenames for this operator kind |
get_avail_operatorkinds(::Type{M}) | Return the list of operator kinds this format supports |
load_operator (the entry point used by the pipeline) is already implemented generically — it composes the methods above.
Quoll.load_operator — Function
load_operator(::Type{OP}, ::Type{M}, dir, kind) -> OPLoad a single operator of type OP from directory dir. Loads metadata and data for the given OperatorKind, then assembles via build_operator. Format-specific loading is dispatched through load_metadata_basic, load_metadata, and load_data methods defined per format.
Quoll.load_operators — Function
load_operators(::Type{OP}, ::Type{M}, dir, kinds) -> Vector{OP}Load multiple operators from disk. Calls load_operator for each OperatorKind in kinds.
Quoll.find_operatorkinds — Function
find_operatorkinds(::Type{M}, dir) -> Vector{OperatorKind}Scan directory dir for available operator data files matching metadata format M. Returns the list of OperatorKinds whose files are found on disk.
Writing
Implement write_operators(::Type{M}, dir, operators) for your metadata type. For multi-file layouts it is usually convenient to split the implementation into metadata-writing and data-writing helpers — see src/operators/deeph.jl for the shape.
Quoll.write_operators — Function
write_operators(::Type{M}, dir, operators)Write a collection of operators to disk in the format determined by metadata type M. Creates the directory if it doesn't exist.
Building
For build_operator to produce zero-initialised operators in your format:
Quoll.build_data — Function
build_data(metadata; value=0.0, type=Nothing, initialised=true)Allocate a DataContainer matching the format described by metadata. Dispatches to format-specific build_data methods based on op_data_type(M).
build_keydata(::Type{KD}, metadata, data) is additionally required if your format should work with KeyedOperator.
Converting
To support conversion between your format and another, dispatch on the pair of metadata types (input and output):
Quoll.convert_metadata — Function
convert_metadata(::Type{Mₒᵤₜ}, in_metadata; kwargs...) -> AbstractMetadataConvert metadata from one format to another. This is a three-stage pipeline:
convert_metadata_basic— convert source, SH convention, sparsity, basis.convert_metadata_extra— convert extra fields (k-point, spins) via trait dispatch.convert_metadata_final— assemble the concrete output metadata type.
Mₒᵤₜ may be a union type (e.g. CanonicalBlockRealMetadata); the concrete subtype is chosen automatically based on which extra fields are present.
Keyword arguments
radii=nothing: build sparsity from neighbour list instead of converting.hermitian=nothing: override hermicity (defaults to input's).out_shconv=nothing: explicit output SH convention.subbasis=nothing: reduce basis to this subset of orbitals.inverted=false: iftrue, keep the complement ofsubbasis.source_kwargs=NamedTuple(): extra arguments for constructing the output source.extra_kwargs=NamedTuple(): extra arguments for trait-based conversion (e.g.kpoint).
Quoll.convert_metadata_basic — Function
convert_metadata_basic(::Type{Mₒᵤₜ}, in_metadata; kwargs...) -> BasicMetadataContainerConvert the core metadata fields: derives the output source, computes the SH convention delta, converts sparsity (optionally from radii), reorders the basis set to the output SH convention, and optionally reduces it with a subbasis.
Quoll.convert_data! — Function
convert_data!(out_operator, in_operator)Transfer and transform data from in_operator into out_operator (mutating out_operator in place). Currently dispatches on the KeyedTrait of both operators to select the correct data types for conversion:
(NoKeydata, NoKeydata)→ route on(Dₒᵤₜ, Dᵢₙ)(HasKeydata, NoKeydata)→ route on(KDₒᵤₜ, Dₒᵤₜ, Dᵢₙ)(NoKeydata, HasKeydata)→ route on(Dₒᵤₜ, KDᵢₙ, Dᵢₙ)(HasKeydata, HasKeydata)→ route on(KDₒᵤₜ, Dₒᵤₜ, KDᵢₙ, Dᵢₙ)
Concrete conversion methods are defined per format pair in src/conversions/.
Quoll.convert_sparsity — Function
convert_sparsity(::Type{Sₒᵤₜ}, in_sparsity, basisset; hermitian=false)Convert a sparsity pattern to type Sₒᵤₜ, optionally changing hermicity. When input and output types match, only the hermicity is adjusted. Cross-type conversions (e.g. CSCRealSparsity → BlockRealSparsity, BlockRealSparsity → DenseRecipSparsity) are also supported.
convert_sparsity(::Type{Sₒᵤₜ}, in_metadata; radii=nothing, hermitian=nothing)Metadata-level sparsity conversion wrapper. If radii is provided, builds a new sparsity pattern from a neighbour list; otherwise converts the input metadata's existing sparsity to type Sₒᵤₜ, optionally changing hermicity.
In practice, most conversions between your format and the rest of Quoll will go through CanonicalBlockRealMetadata, so the pair to implement is usually (YourMetadata, CanonicalBlockRealMetadata) and vice versa. Direct conversions to any other format are also supported — just add the method for that pair.
TOML parsing
If you want your format to be selectable from input_file.toml, register it with the parser's format lookup table:
Quoll.get_readformat(::Val{:myformat}) = MyFormatMetadata
Quoll.get_writeformat(::Val{:myformat}) = MyFormatMetadataThe string after Val( is matched against the format field after case/whitespace/punctuation normalisation, so "MyFormat", "my-format", and "my_format" all resolve to the same symbol.
Similarly, custom core-projection schemes register themselves via:
Quoll.Projections.get_basis_projection(::Val{:myscheme}) = MySchemeHoly traits
Dispatch on behavioural traits rather than concrete types is used in a handful of places (real vs. reciprocal space, spin vs. no-spin, keyed vs. unkeyed operator).
Quoll.SpaceTrait — Type
Trait distinguishing real-space and reciprocal-space metadata.
Quoll.SpinTrait — Type
Trait distinguishing spin-polarised and non-spin-polarised metadata.
Quoll.KeyedTrait — Type
Trait distinguishing operators that carry keydata from those that do not.