diff --git a/src/MolecularDynamics/Config.jl b/src/MolecularDynamics/Config.jl new file mode 100644 index 00000000..b1e9e252 --- /dev/null +++ b/src/MolecularDynamics/Config.jl @@ -0,0 +1,70 @@ +module Config + +using Configurations: from_dict, @option +using EasyConfig: Config as Conf +using ExpressBase: Calculation +using ExpressBase.Config: AbstractConfig, SoftwareConfig, SamplingPoints, IO, list_io +using Unitful: FreeUnits + +@option "pressures" struct Pressures <: SamplingPoints + numbers::Vector{Float64} + unit::FreeUnits + Pressures(numbers, unit="GPa") = new(numbers, unit) +end + +@option "volumes" struct Volumes <: SamplingPoints + numbers::Vector{Float64} + unit::FreeUnits + Volumes(numbers, unit="bohr^3") = new(numbers, unit) +end + +@option struct Data <: AbstractConfig + static::String = "energies.json" +end + +@option struct StaticConfig <: AbstractConfig + recipe::String + templates::Vector{String} + at::Union{Pressures,Volumes} + io::IO = IO() + data::Data = Data() + cli::SoftwareConfig + function StaticConfig(recipe, templates, at, io, data, cli) + @assert recipe in ("md", "vc-md") + for template in templates + if !isfile(template) + @warn "I cannot find template file `$template`!" + end + end + return new(recipe, templates, at, io, data, cli) + end +end + +function _update!(conf::Conf, at::Union{Pressures,Volumes}) + conf.at = collect(number for number in at) + return conf +end +function _update!(conf::Conf, io::IO, at::Union{Pressures,Volumes}) + conf.io = collect( + list_io(io, number, string(nameof(typeof(conf.calculation)))) for + number in at.numbers + ) + return conf +end +function _update!(conf::Conf, data::Data) + conf.data.static = abspath(expanduser(data.static)) + return conf +end + +function expand(config::StaticConfig, calculation::Calculation) + conf = Conf() + conf.cli = config.cli + conf.calculation = calculation + _update!(conf, config.templates) + _update!(conf, config.at) + _update!(conf, config.io, config.at) + _update!(conf, config.data) + return conf +end + +end diff --git a/src/MolecularDynamics/MolecularDynamics.jl b/src/MolecularDynamics/MolecularDynamics.jl index ddcd9c98..ff09cd5e 100644 --- a/src/MolecularDynamics/MolecularDynamics.jl +++ b/src/MolecularDynamics/MolecularDynamics.jl @@ -1,5 +1,8 @@ module MolecularDynamics - +include("Config.jl") +include("actions.jl") +include("think.jl") +include("Recipes.jl") end diff --git a/src/MolecularDynamics/Recipes.jl b/src/MolecularDynamics/Recipes.jl new file mode 100644 index 00000000..1a52f7b0 --- /dev/null +++ b/src/MolecularDynamics/Recipes.jl @@ -0,0 +1,51 @@ +module Recipes + +struct IonDynamicsRecipe <: Recipe + config +end +struct VDOSRecipe <: Recipe + config +end + +function stage(::IonDynamics, r::IonDynamicsRecipe) + conf = expand(r.config, IonDynamics()) + steps = map(( + DownloadPotentials(IonDynamics()), + CreateInput(IonDynamics()), + WriteInput(IonDynamics()), + RunCmd(IonDynamics()), + # ExtractData(IonDynamics()), + # GatherData(IonDynamics()), + # SaveData(IonDynamics()), + )) do action + think(action, conf) + end + steps = Iterators.Stateful(steps) + download = Job(first(iterate(steps)); name="download potentials") + makeinputs = map(thunk -> Job(thunk; name="update input in MD"), first(iterate(steps))) + writeinputs = map( + thunk -> ArgDependentJob(thunk; name="write input in MD"), first(iterate(steps)) + ) + runcmds = map( + thunk -> ConditionalJob(thunk; name="run ab initio software in MD"), + first(iterate(steps)), + ) + # extractdata = map( + # thunk -> ConditionalJob(thunk; name="extract E(V) data in MD"), + # first(iterate(steps)), + # ) + # gatherdata = ArgDependentJob(first(iterate(steps)); name="gather E(V) data in MD") + # savedata = ArgDependentJob(first(iterate(steps)); name="save E(V) data in MD") + download .→ makeinputs .→ runcmds + return steps = (; + download=download, + makeinputs=makeinputs, + writeinputs=writeinputs, + runcmds=runcmds, + # extractdata=extractdata, + # gatherdata=gatherdata, + # savedata=savedata, + ) +end + +end diff --git a/src/MolecularDynamics/actions.jl b/src/MolecularDynamics/actions.jl new file mode 100644 index 00000000..23d57abf --- /dev/null +++ b/src/MolecularDynamics/actions.jl @@ -0,0 +1,34 @@ +using AbInitioSoftwareBase: Input +using EasyJobsBase: Job +using ExpressBase: + IonDynamics, + VariableCellMolecularDynamics, + Action, + DownloadPotentials, + RunCmd, + WriteInput +using ExpressBase.Files: save + +struct CreateInput{T} <: Action{T} + calculation::T +end +(action::CreateInput)(template::Input) = Base.Fix1(action, template) + +struct ExtractTrajectory{T} <: Action{T} + calculation::T +end + +struct GatherTrajectories{T} <: Action{T} + calculation::T +end +(::GatherTrajectories)(iter) = collect(iter) + +struct SaveTrajectory{T} <: Action{T} + calculation::T +end +function (action::SaveTrajectory)(path, raw) + raw = collect(raw) # In case the data is not sorted + data = Dict("volume" => (string ∘ first).(raw), "energy" => (string ∘ last).(raw)) + return save(path, data) +end +(action::SaveTrajectory)(path) = Base.Fix1(action, path)