diff --git a/docs/src/NQCModels/combining_models.md b/docs/src/NQCModels/combining_models.md index 58f9edb35..205a20657 100644 --- a/docs/src/NQCModels/combining_models.md +++ b/docs/src/NQCModels/combining_models.md @@ -19,7 +19,7 @@ For example, in order to run [Molecular Dynamics with Electronic friction](@ref However, most models for potential energy surfaces only provide `potential` and `derivative`, whereas `friction!` is provided by an `ElectronicFrictionProvider`. To combine different models together for a system, we can use [`Subsystem`](@ref)s to define which atoms in the system a given model should be applied to, and a [`CompositeModel`](@ref) to combine the different models into one. -If different [`Subsystem`](@ref)s should experience different effective temperatures, a [`Thermostat`](@ref) can be provided when initialising a [`Simulation`](@ref). +If different [`Subsystem`](@ref)s should experience different effective temperatures, a [`TemperatureSetting`](@ref) can be provided when initialising a [`Simulation`](@ref). ![An overview of the different components used to combine models in NQCModels.jl](../assets/compositemodels/struct-explainer.svg) diff --git a/docs/src/dynamicssimulations/dynamicssimulations.md b/docs/src/dynamicssimulations/dynamicssimulations.md index 9a406fd4c..abfc6fe00 100644 --- a/docs/src/dynamicssimulations/dynamicssimulations.md +++ b/docs/src/dynamicssimulations/dynamicssimulations.md @@ -49,7 +49,7 @@ For time-dependent temperatures, the temperature can be set to a function. This **Different temperatures per atom** -If different parts of the simulated system should be affected by different effective temperatures, a `Vector` of [`Temperature`](@ref)s can be passed as the temperature argument. +If different parts of the simulated system should be affected by different effective temperatures, a `Vector` of [`TemperatureSetting`](@ref)s can be passed as the temperature argument. However, only one temperature should be applied to each atom in the system. ### DynamicsVariables diff --git a/docs/src/examples/mdef_multithermostat.md b/docs/src/examples/mdef_multithermostat.md index 78f918f67..6512cbc12 100644 --- a/docs/src/examples/mdef_multithermostat.md +++ b/docs/src/examples/mdef_multithermostat.md @@ -181,11 +181,11 @@ combined_model = CompositeModel( phononic_friction ) -# Create Temperature objects to apply T_el to adsorbates, T_ph to surface +# Create TemperatureSetting objects to apply T_el to adsorbates, T_ph to surface # Manually specified indices -electron_thermostat = Temperature(T_el_function, indices = [55,56]) +electron_thermostat = TemperatureSetting(T_el_function, indices = [55,56]) # Inherit indices from a Subsystem -phonon_thermostat = Temperature(T_ph_function, phononic_friction) +phonon_thermostat = TemperatureSetting(T_ph_function, phononic_friction) sim_T_el_only = Simulation{MDEF}( atoms, diff --git a/src/NQCDynamics.jl b/src/NQCDynamics.jl index 35c35dd11..bf42b9159 100644 --- a/src/NQCDynamics.jl +++ b/src/NQCDynamics.jl @@ -18,7 +18,7 @@ export Simulation, RingPolymerSimulation, natoms, masses, - Thermostat, + TemperatureSetting, get_temperature @reexport using NQCDistributions diff --git a/src/simulations.jl b/src/simulations.jl index 6eddc8d13..a57116bfb 100644 --- a/src/simulations.jl +++ b/src/simulations.jl @@ -28,12 +28,12 @@ function Simulation(atoms::Atoms{T}, model::Model, method::M; temperature=0u"K", cell::AbstractCell=InfiniteCell()) where {M,T} calc = Calculator(model, length(atoms), T) # If a thermostat is provided, check it covers the whole system. - isa(temperature, Thermostat{Vector{Int}}) ? throw(DomainError(temperature, "Thermostat must apply to all atoms.")) : nothing - # If multiple Thermostats are provided, check that each atom only has one thermostat applied to it. - if isa(temperature, Vector{<:Thermostat}) + isa(temperature, TemperatureSetting{Vector{Int}}) ? throw(DomainError(temperature, "TemperatureSetting must apply to all atoms.")) : nothing + # If multiple TemperatureSettings are provided, check that each atom only has one thermostat applied to it. + if isa(temperature, Vector{<:TemperatureSetting}) indices = vcat([thermostat.indices for thermostat in temperature]...) if length(unique(indices)) != length(atoms.masses) - throw(DomainError(temperature, "Every atom must have a Thermostat applied to it.")) + throw(DomainError(temperature, "Every atom must have a TemperatureSetting applied to it.")) end if length(indices) != length(unique(indices)) throw(DomainError(temperature, "Atoms can only have one thermostat applied to them.")) @@ -113,7 +113,7 @@ function Base.show(io::IO, sim::RingPolymerSimulation{M}) where {M} end """ -A Temperature contains both temperature information and the atom indices within a Simulation that it is applied to. +A TemperatureSetting contains both temperature information and the atom indices within a Simulation that it is applied to. **If you don't need to apply different temperatures to different parts of your Simulation, assign the `temperature` keyword argument of your simulation to a number or function.** @@ -124,16 +124,16 @@ A Temperature contains both temperature information and the atom indices within `indices`: Indices of the atoms to which this thermostat is applied. Can be a range of indices, a single `Int`, or a `Vector{Int}`. """ -struct Temperature{I} +struct TemperatureSetting{I} value::Function indices::I end -function Base.show(io::IO, temperature::Temperature) - print(io, "Temperature:\n\tT(t=0) = $(get_temperature(temperature, 0u"fs"))\n\tApplies to atoms: $(temperature.indices)\n") +function Base.show(io::IO, temperature::TemperatureSetting) + print(io, "TemperatureSetting:\n\tT(t=0) = $(get_temperature(temperature, 0u"fs"))\n\tApplies to atoms: $(temperature.indices)\n") end -function Temperature(value, indices=:) +function TemperatureSetting(value, indices=:) if isa(indices, UnitRange) indices=collect(indices) elseif isa(indices, Int) @@ -141,29 +141,29 @@ function Temperature(value, indices=:) end if !isa(value, Function) temperature_function(t)=value - return Temperature(temperature_function, indices) + return TemperatureSetting(temperature_function, indices) else - return Temperature(value, indices) + return TemperatureSetting(value, indices) end end """ - Temperature(temperature, subsystem::NQCModels.Subsystem) + TemperatureSetting(temperature, subsystem::NQCModels.Subsystem) -Apply a `Temperature` to all atoms in a `Subsystem`. +Apply a `TemperatureSetting` to all atoms in a `Subsystem`. """ -function Temperature(temperature, subsystem::NQCModels.Subsystem) - Temperature(temperature, subsystem.indices) +function TemperatureSetting(temperature, subsystem::NQCModels.Subsystem) + TemperatureSetting(temperature, subsystem.indices) end -get_temperature(thermostat::Temperature{<:Any}, t=0u"fs") = austrip(thermostat.value(t)) +get_temperature(thermostat::TemperatureSetting{<:Any}, t=0u"fs") = austrip(thermostat.value(t)) """ - get_temperature(thermostats::Vector{<:Temperature}, t=0u"fs") + get_temperature(thermostats::Vector{<:TemperatureSetting}, t=0u"fs") -Gets the temperature from multiple `Temperature`s and returns a vector of the temperature applied to each atom. +Gets the temperature from multiple `TemperatureSetting`s and returns a vector of the temperature applied to each atom. """ -function get_temperature(thermostats::Vector{<:Temperature}, t=0u"fs") +function get_temperature(thermostats::Vector{<:TemperatureSetting}, t=0u"fs") indices=vcat([thermostat.indices for thermostat in thermostats]...) temperature_vector=zeros(Number, length(indices)) for thermostat in thermostats diff --git a/test/Core/simulations.jl b/test/Core/simulations.jl index fd759f0c5..ab94a277b 100644 --- a/test/Core/simulations.jl +++ b/test/Core/simulations.jl @@ -24,17 +24,17 @@ model = NQCModels.Free() @testset "Thermostats" begin # Init thermostat with Unitful quantity - thermostat1=Thermostat(10u"K", [1,2]) + thermostat1=TemperatureSetting(10u"K", [1,2]) @test NQCDynamics.get_temperature(thermostat1, 0) == NQCDynamics.get_temperature(thermostat1, 100) # Init thermostat with function - thermostat2=Thermostat(x->(10+x*u"fs^-1")*u"K", [2,3]) + thermostat2=TemperatureSetting(x->(10+x*u"fs^-1")*u"K", [2,3]) @test NQCDynamics.get_temperature(thermostat2) == austrip(10u"K") @test NQCDynamics.get_temperature(thermostat2, 10u"fs") == austrip(20u"K") # Test that thermostats with overlapping indices throw an error @test_throws DomainError Simulation(atoms, model; temperature=[thermostat1, thermostat2]) # Test system size / total thermostat size mismatch @test_throws DomainError Simulation(Atoms([:N, :H, :H, :H,]), model; temperature=thermostat1) - thermostat3=thermostat2=Thermostat(x->(10+x*u"fs^-1")*u"K", [3,4]) + thermostat3=thermostat2=TemperatureSetting(x->(10+x*u"fs^-1")*u"K", [3,4]) # Combined temperature evaluation sim = Simulation(Atoms([:N, :H, :H, :H,]), model; temperature=[thermostat1, thermostat3]) @test NQCDynamics.get_temperature(sim, austrip(1u"fs")) == austrip.([10u"K", 10u"K", 11u"K", 11u"K"])