Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/user/bugfix.temperature-ramp-updates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Temperature ramps validate their schedule and reach the requested target across partial final intervals.
2 changes: 2 additions & 0 deletions docs/sphinx/src/userGuide/inputFile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,8 @@ Temperature Ramp Frequency

With the ``temp_ramp_frequency`` keyword the user can specify the frequency of the temperature ramping from the ``start_temp`` to the ``temp`` value. If no starting temperature is given the keyword will be ignored. If a starting temperature is given and this keyword is omitted the temperature ramping will be performed, so that each step the temperature is increased by the same value.

If the ramp length is not divisible by this frequency, the temperature increments are scaled by the number of scheduled updates so that the final update reaches the requested target temperature exactly.

.. centered:: *default value* = 1 step

.. _thermostatKey:
Expand Down
49 changes: 29 additions & 20 deletions src/setup/thermostatSetup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,45 +219,54 @@ void ThermostatSetup::setupNoseHooverThermostat()
void ThermostatSetup::setupTemperatureRamp()
{
/*************************************************************************
* If the start temperature is defined, the temperature ramp is enabled.
**
* If the start temperature is defined, the temperature ramp is enabled. *
*************************************************************************/

if (!ThermostatSettings::isStartTemperatureSet())
return;

/*************************************************************
* resetting the target temperature to the start temperature *
* If steps is 0, set the steps to the total number of steps *
*************************************************************/

const auto startTemp = ThermostatSettings::getStartTemperature();
auto steps = ThermostatSettings::getTemperatureRampSteps();
const auto useFullSimulation = steps == 0;

_engine.getThermostat().setTargetTemperature(startTemp);
ThermostatSettings::setActualTargetTemperature(startTemp);
if (useFullSimulation)
steps = TimingsSettings::getNumberOfSteps();

auto steps = ThermostatSettings::getTemperatureRampSteps();
if (steps == 0)
throw InputFileException(
"Temperature ramp requires at least one simulation step"
);

const auto frequency = ThermostatSettings::getTemperatureRampFrequency();

if (frequency == 0)
throw InputFileException(
"Temperature ramp frequency must be greater than zero"
);

if (useFullSimulation)
ThermostatSettings::setTemperatureRampSteps(steps);

/*************************************************************
* If steps is 0, set the steps to the total number of steps *
* resetting the target temperature to the start temperature *
*************************************************************/

if (steps == 0)
{
steps = TimingsSettings::getNumberOfSteps();
ThermostatSettings::setTemperatureRampSteps(steps);
}
const auto startTemp = ThermostatSettings::getStartTemperature();

_engine.getThermostat().setTargetTemperature(startTemp);
ThermostatSettings::setActualTargetTemperature(startTemp);
_engine.getThermostat().setTemperatureRampingSteps(steps);
_engine.getThermostat().setTemperatureRampingFrequency(frequency);

const auto frequency = ThermostatSettings::getTemperatureRampFrequency();

const auto targetTemp = ThermostatSettings::getTargetTemperature();
const auto tempDelta = targetTemp - startTemp;
const auto tempIncrease =
tempDelta / double(steps) * static_cast<double>(frequency);
const auto targetTemp = ThermostatSettings::getTargetTemperature();
const auto tempDelta = targetTemp - startTemp;
const auto updates = steps / frequency + (steps % frequency != 0);
const auto tempIncrease = tempDelta / double(updates);

_engine.getThermostat().setTemperatureIncrease(tempIncrease);
_engine.getThermostat().setTemperatureRampingFrequency(frequency);
}

void ThermostatSetup::writeSetupInfo() const
Expand Down
64 changes: 63 additions & 1 deletion tests/src/setup/testThermostatSetup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
#include "berendsenThermostat.hpp" // for BerendsenThermostat
#include "constants/conversionFactors.hpp" // for _FS_TO_S_, _KG_TO_GRAM_
#include "constants/natureConstants.hpp" // for _UNIVERSAL_GAS_CONSTANT_
#include "gtest/gtest.h" // for Message, TestPartResult
#include "exceptions.hpp" // for InputFileException
#include "inputFileReader.hpp" // for InputFileReader
#include "langevinThermostat.hpp" // for LangevinThermostat
#include "noseHooverThermostat.hpp" // for NoseHooverThermostat
#include "testSetup.hpp" // for TestSetup
Expand Down Expand Up @@ -100,6 +101,67 @@ TEST_F(TestSetup, setupThermostat_temp_ramping)
);
}

TEST_F(TestSetup, temperatureRampReachesEndWithPartialFinalInterval)
{
ThermostatSetup thermostatSetup(*_mdEngine);
input::InputFileReader reader("input.in", *_mdEngine);

reader.process({"nstep", "=", "10"});
reader.process({"thermostat", "=", "berendsen"});
reader.process({"temp", "=", "300"});
reader.process({"start_temp", "=", "200"});
reader.process({"temp_ramp_steps", "=", "10"});
reader.process({"temp_ramp_frequency", "=", "3"});

thermostatSetup.setup();

EXPECT_DOUBLE_EQ(
thermostatSetup.getEngine().getThermostat().getTemperatureIncrease(),
25.0
);

for (size_t step = 0; step < 10; ++step)
thermostatSetup.getEngine().getThermostat().applyTemperatureRamping();

EXPECT_DOUBLE_EQ(
thermostatSetup.getEngine().getThermostat().getTargetTemperature(),
300.0
);

settings::ThermostatSettings::setTemperatureRampSteps(0);
settings::ThermostatSettings::setTemperatureRampFrequency(1);
}

TEST_F(TestSetup, rejectsEmptyTemperatureRamp)
{
ThermostatSetup thermostatSetup(*_mdEngine);

settings::TimingsSettings::setNumberOfSteps(0);
settings::ThermostatSettings::setThermostatType("berendsen");
settings::ThermostatSettings::setTargetTemperature(300);
settings::ThermostatSettings::setStartTemperature(200);
settings::ThermostatSettings::setTemperatureRampSteps(0);

EXPECT_THROW(thermostatSetup.setup(), customException::InputFileException);
}

TEST_F(TestSetup, rejectsZeroTemperatureRampFrequency)
{
ThermostatSetup thermostatSetup(*_mdEngine);

settings::TimingsSettings::setNumberOfSteps(10);
settings::ThermostatSettings::setThermostatType("berendsen");
settings::ThermostatSettings::setTargetTemperature(300);
settings::ThermostatSettings::setStartTemperature(200);
settings::ThermostatSettings::setTemperatureRampSteps(10);
settings::ThermostatSettings::setTemperatureRampFrequency(0);

EXPECT_THROW(thermostatSetup.setup(), customException::InputFileException);

settings::ThermostatSettings::setTemperatureRampSteps(0);
settings::ThermostatSettings::setTemperatureRampFrequency(1);
}

TEST_F(TestSetup, setupThermostat_only_end_temp_defined)
{
ThermostatSetup thermostatSetup(*_mdEngine);
Expand Down
Loading