JuliaAtoms / AtomicLevels.jl

https://juliaatoms.org/AtomicLevels.jl
Other
12 stars 3 forks source link

Serialization of orbitals and configurations #73

Closed jagot closed 3 years ago

jagot commented 3 years ago

Increasingly, the need to save computations arises and with it, the description of what the computations actually contain. To this end, it is necessary to be able to serialize orbitals and configurations, both to text and binary files, such that they can be unambiguously deserialized again. It's preferable if the text serialization at the same time is pretty to look at; this ties in with #41, #56, and #58.

mortenpi commented 3 years ago

Aside from the format of the serialized strings, what methods do you have in mind? Serialization.(de)serialize for all the types?

jagot commented 3 years ago

No, I don't think that would work, since the docs explicitly say that it's not compatible between versions of Julia. I think it is better just to overload the read!(io::IO, t::T) and write(io::IO, t::T) methods.

Let's start humbly with

abstract type AbstractOrbital end

const MQ = Union{Int,Symbol}

struct Orbital{N<:MQ} <: AbstractOrbital
    n::N
    ℓ::Int
    function Orbital(n::Int, ℓ::Int)
        n ≥ 1 || throw(ArgumentError("Invalid principal quantum number $(n)"))
        0 ≤ ℓ && ℓ < n || throw(ArgumentError("Angular quantum number has to be ∈ [0,$(n-1)] when n = $(n)"))
        new{Int}(n, ℓ)
    end
    function Orbital(n::Symbol, ℓ::Int)
        new{Symbol}(n, ℓ)
    end
end

we need to store a Union{Int,Symbol} and an Int; the latter is easy, but for the former we need to store 1) a flag that tells us what kind n has and 2) then write n. How about

Base.write(io::IO, o::Orbital{Int}) = write(io, 'i', o.n, o.ℓ)
Base.write(io::IO, o::Orbital{Symbol}) = write(io, 's', sizeof(o.n), o.n, o.ℓ)

function Base.read(io::IO, ::Type{Orbital})
    kind = read(io, Char)
    n = if kind == 'i'
        read(io, Int)
    elseif kind == 's'
        b = Vector{UInt8}(undef, read(io, Int))
        readbytes!(io, b)
        Symbol(b)
    else
        error("Unknown Orbital type $(kind)")
    end
    ℓ = read(io, Int)
    Orbital(n, ℓ)
end

which seems to work.

EDIT: We would of course need matching routines for writing to/reading from text files.

The full hierarchy I need at the moment is