Controllers¶
This section describes all advanced control systems available in Cavity HOOMD for temperature management, parameter optimization, and adaptive feedback.
Note
Controllers are advanced features for specialized applications. For standard equilibrium simulations, use built-in thermostats (see Thermostats).
Overview¶
Cavity HOOMD provides a comprehensive suite of controllers for different control objectives:
PID Control: Classical three-term controller with auto-tuning
Differential Equation Controller: First-order dynamics-based control
Simple Setpoint Controller: Direct bath temperature control
Adaptive MPC Controller: Model predictive control with online adaptation
Dual Feedback Controller: Independent multi-mode temperature control
Empirical Controller: Data-driven temperature-energy relationship control
Feedback Controller: Base class for custom controller implementations
These controllers enable:
Precise temperature tracking and regulation
Smooth temperature ramps and protocols
Parameter identification and adaptation
Multi-objective control (multiple temperatures)
Disturbance rejection
Model-based optimal control
PID Control¶
Classical proportional-integral-derivative controller for robust temperature regulation.
Theory¶
The PID controller implements the standard three-term control law:
Where:
\(e(t) = T_{\text{setpoint}} - T_{\text{measured}}\): Temperature error
\(K_p\): Proportional gain (immediate response)
\(T_i\): Integral time constant (eliminates steady-state error)
\(T_d\): Derivative time constant (reduces overshoot)
\(u(t) = T_{\text{bath}}\): Control output (bath temperature)
Key Features:
Anti-windup protection for integral term
Filtered derivative to reject measurement noise
Output constraints and rate limiting
Auto-tuning via Ziegler-Nichols method
Multiple temperature signal options
Implementation¶
from cavitymd.controllers import PIDControl
from cavitymd.analysis import TemperatureTracker, ElapsedTimeTracker
# Setup tracking
time_tracker = ElapsedTimeTracker(sim)
temp_tracker = TemperatureTracker(sim, time_tracker)
# Manual tuning
pid = PIDControl(
simulation=sim,
time_tracker=time_tracker,
temperature_tracker=temp_tracker,
molecular_thermostat=bussi_thermostat,
Kp=1.0, # Proportional gain
Ti=5.0, # Integral time (ps)
Td=0.5, # Derivative time (ps)
setpoint_K=100.0, # Target temperature (K)
signal_choice='lj_coulombic', # Control signal
update_interval_ps=0.1
)
sim.operations.updaters.append(hoomd.update.CustomUpdater(
action=pid,
trigger=hoomd.trigger.Periodic(1)
))
Auto-Tuning¶
Ziegler-Nichols method from step response:
# Auto-tune based on system response
pid = PIDControl(
simulation=sim,
time_tracker=time_tracker,
temperature_tracker=temp_tracker,
molecular_thermostat=bussi_thermostat,
setpoint_K=100.0,
signal_choice='lj_coulombic',
auto_tune=True, # Enable auto-tuning
auto_tune_duration_ps=50.0, # Tuning duration
step_size=10.0 # Step size for identification
)
The controller applies a step change, measures the response, fits a First-Order Plus Dead Time (FOPDT) model, and calculates optimal PID gains using Ziegler-Nichols rules.
FOPDT Model:
Where \(K_p\) is process gain, \(\tau\) is time constant, \(\theta\) is dead time.
Ziegler-Nichols PID Gains:
Operating Modes¶
1. Setpoint Tracking:
Fixed target temperature with active control:
pid = PIDControl(
...,
mode='setpoint',
setpoint_K=100.0
)
2. Self-Loop:
Track a measured signal (e.g., harmonic temperature follows LJ temperature):
pid = PIDControl(
...,
mode='self_loop',
signal_choice='lj_coulombic', # Signal to track
control_signal='harmonic_fictive' # Signal to control
)
Use Cases¶
Temperature stabilization:
# Maintain 100K with tight regulation
pid = PIDControl(..., setpoint_K=100.0, Kp=2.0, Ti=3.0, Td=0.3)
Temperature ramping:
# Ramp from 100K to 300K
for t in np.linspace(0, 100, 1000): # Over 100 ps
T_target = 100.0 + (300.0 - 100.0) * (t / 100.0)
pid.setpoint_K = T_target
sim.run(100) # Run 0.1 ps
Multi-mode coupling:
# LJ bath follows harmonic temperature
pid = PIDControl(
...,
mode='self_loop',
signal_choice='harmonic_fictive',
control_signal='lj_coulombic'
)
Differential Equation Controller¶
Simple first-order dynamics-based temperature control.
Theory¶
The DiffEqController implements the differential equation:
Where:
\(T_{\text{signal}}\): Measured temperature (e.g., LJ+Coulombic fictive)
\(T_{\text{bath}}\): Bath temperature (control variable)
\(\tau\): Time constant (controls response speed)
This creates a first-order low-pass filter behavior where the bath temperature smoothly follows the signal temperature.
Implementation¶
from cavitymd.controllers import DiffEqController
diffeq = DiffEqController(
simulation=sim,
time_tracker=time_tracker,
temperature_tracker=temp_tracker,
molecular_thermostat=bussi_thermostat,
signal_name='lj_coulombic_bath', # Temperature to follow
time_constant_ps=2.0, # Response time
turn_on_time_ps=10.0, # Start time
turn_off_time_ps=None # Optional stop time
)
sim.operations.updaters.append(hoomd.update.CustomUpdater(
action=diffeq,
trigger=hoomd.trigger.Periodic(1)
))
Use Cases¶
Smooth temperature evolution:
Bath temperature gently follows system temperature fluctuations, avoiding abrupt changes.
Thermal equilibration:
Gradually equilibrate cavity and molecular subsystems:
diffeq = DiffEqController(
...,
signal_name='lj_coulombic_bath',
time_constant_ps=5.0 # 5 ps response time
)
Delayed activation:
Start control after initial equilibration:
diffeq = DiffEqController(
...,
turn_on_time_ps=50.0 # Activate after 50 ps
)
Simple Setpoint Controller¶
Direct bath temperature control without feedback.
Theory¶
The SimpleSetpointController directly sets the bath temperature:
With optional linear ramping between values.
Implementation¶
from cavitymd.controllers import SimpleSetpointController
# Fixed setpoint
setpoint = SimpleSetpointController(
simulation=sim,
time_tracker=time_tracker,
molecular_thermostat=bussi_thermostat,
target_temperature_K=100.0,
turn_on_time_ps=0.0
)
# With ramping
setpoint = SimpleSetpointController(
simulation=sim,
time_tracker=time_tracker,
molecular_thermostat=bussi_thermostat,
initial_temperature_K=100.0,
final_temperature_K=300.0,
ramp_duration_ps=100.0,
ramp_start_time_ps=10.0
)
Use Cases¶
Fixed temperature:
Simple constant temperature control when feedback is not needed.
Linear temperature ramps:
Controlled heating or cooling protocols:
# Cool from 300K to 100K over 50 ps
setpoint = SimpleSetpointController(
...,
initial_temperature_K=300.0,
final_temperature_K=100.0,
ramp_duration_ps=50.0
)
Adaptive MPC Controller¶
Advanced model predictive control with online parameter adaptation.
Theory¶
Model Predictive Control (MPC) solves an optimization problem at each time step:
Subject to:
Where:
\(x(k)\): State (temperature)
\(u(k)\): Control input (bath temperature, coupling strength)
\(N\): Prediction horizon
\(Q, R, S\): Cost matrices
Online Adaptation:
System matrices \(A, B\) are updated via Recursive Least Squares (RLS) based on observed system behavior.
Implementation¶
from cavitymd.controllers import AdaptiveMPCController
mpc = AdaptiveMPCController(
simulation=sim,
time_tracker=time_tracker,
temperature_tracker=temp_tracker,
target_temperature=100.0,
turn_on_time_ps=0.0,
system_id_duration_ps=50.0, # System identification phase
update_interval_ps=0.1,
prediction_horizon=10, # Look-ahead steps
Q_weight=100.0, # State cost
R_lambda_weight=0.01, # Lambda control cost
R_temp_weight=0.1, # Temperature control cost
delta_lambda_weight=0.1, # Lambda rate cost
delta_temp_weight=0.01 # Temperature rate cost
)
Three-Phase Operation:
Pre-initialization (0 to turn_on_time_ps): No control
System Identification (turn_on_time_ps to turn_on_time_ps + system_id_duration_ps): Random step changes to identify system model
Control (after system ID): MPC with continuous model updates via RLS
Use Cases¶
Multi-input control:
Simultaneously control bath temperature AND coupling strength:
mpc = AdaptiveMPCController(
...,
target_temperature=100.0,
# Optimizes both T_bath and λ
)
Adaptive systems:
Systems with time-varying dynamics benefit from online adaptation.
Constrained optimization:
Enforce physical constraints on controls:
mpc = AdaptiveMPCController(
...,
lambda_min=0.0,
lambda_max=0.1,
T_bath_min=50.0,
T_bath_max=300.0
)
Dual Feedback Controller¶
Independent control of multiple temperature modes.
Theory¶
Controls multiple subsystems independently:
Each mode (translational, rotational, vibrational, harmonic, etc.) can have independent:
Target temperature
Feedback gain
Control activation time
Implementation¶
from cavitymd.controllers.dual_feedback import DualIndependentTemperatureFeedback
dual = DualIndependentTemperatureFeedback(
simulation=sim,
time_tracker=time_tracker,
temperature_tracker=temp_tracker,
molecular_thermostat=bussi_thermostat,
target_temperatures={
'lj_coulombic': 100.0,
'harmonic_fictive': 100.0
},
gains={
'lj_coulombic': 0.1,
'harmonic_fictive': 0.05
},
turn_on_time_ps=10.0
)
Use Cases¶
Mode-selective control:
Different control for different degrees of freedom:
dual = DualIndependentTemperatureFeedback(
...,
target_temperatures={
'translational': 100.0,
'rotational': 100.0,
'vibrational': 50.0 # Colder vibrations
}
)
Staged equilibration:
Activate controls sequentially:
# Control LJ first, then harmonic later
dual = DualIndependentTemperatureFeedback(
...,
turn_on_times={
'lj_coulombic': 0.0,
'harmonic_fictive': 50.0
}
)
Empirical Controller¶
Data-driven control using empirical temperature-energy relationships.
Theory¶
Uses measured \(T_{\text{eff}}(E)\) relationship to invert and find required energy for target temperature:
Then controls bath temperature to achieve that energy.
Fitting Models:
Harmonic: \(E = \frac{aT}{1 + bT}\)
LJ+Coulombic: \(E = E_0 + \frac{AT^{3/5}}{1 + CT^{3/5}}\)
Implementation¶
from cavitymd.controllers.empirical import EmpiricalTemperatureData, EmpiricalTemperatureFeedback
# Load empirical data
emp_data = EmpiricalTemperatureData(
filename='potential_energy_vs_T.txt',
fit_type='harmonic' # or 'lj_coulombic'
)
# Create controller
emp_control = EmpiricalTemperatureFeedback(
simulation=sim,
time_tracker=time_tracker,
temperature_tracker=temp_tracker,
molecular_thermostat=bussi_thermostat,
empirical_data=emp_data,
target_temperature_K=100.0,
feedback_gain=0.1
)
Use Cases¶
Accurate temperature targeting:
When you have calibration data and need precise temperature.
Non-linear systems:
Systems where temperature-energy relationship is complex.
Model-free control:
Don’t need analytical model, just empirical data.
Feedback Controller Base Class¶
Base class for implementing custom controllers.
Implementation¶
from cavitymd.controllers.feedback import FeedbackController
class MyCustomController(FeedbackController):
def __init__(self, simulation, time_tracker, temperature_tracker, **kwargs):
super().__init__(simulation, time_tracker, temperature_tracker, **kwargs)
# Initialize custom parameters
def compute_control(self, current_time_ps):
# Implement custom control logic
T_measured = self.temperature_tracker.get_temperature('lj_coulombic')
T_bath = self.compute_custom_control(T_measured)
return T_bath
Use Cases¶
Custom control algorithms:
Implement specialized control strategies not covered by standard controllers.
Research and development:
Test new control concepts with existing infrastructure.
Controller Comparison¶
Performance Comparison¶
Controller |
Complexity |
Tuning |
Best Performance |
Best Use Case |
|---|---|---|---|---|
PID |
Medium |
Auto or manual |
Excellent |
General temperature control |
DiffEq |
Low |
Single parameter |
Good |
Smooth tracking |
Setpoint |
Very Low |
None |
N/A (open loop) |
Fixed/ramped temperatures |
Adaptive MPC |
High |
Many parameters |
Excellent (optimal) |
Multi-input control |
Dual Feedback |
Medium |
Gains per mode |
Good |
Multi-mode systems |
Empirical |
Medium |
Requires data |
Good |
Non-linear systems |
When to Use Each¶
Use PID when:
Need robust, proven controller
Want auto-tuning capability
Single temperature control
Good performance with moderate tuning effort
Use DiffEq when:
Want simplest feedback control
Smooth temperature evolution desired
Single time constant sufficient
Minimal tuning preferred
Use Setpoint when:
No feedback needed
Open-loop temperature control
Simple ramps or fixed temperatures
Minimal computational overhead
Use Adaptive MPC when:
Multi-input control (T_bath AND λ)
System dynamics change over time
Constraints on controls important
Optimal performance required
Computational cost acceptable
Use Dual Feedback when:
Multiple modes need independent control
Different temperatures for different DOFs
Staged activation desired
Simple proportional control sufficient
Use Empirical when:
Have calibration data available
Accurate temperature targeting critical
System highly non-linear
Model-free approach preferred
Troubleshooting¶
Common Issues¶
1. Controller instability (oscillations):
Symptoms: Temperature oscillates or diverges
Solutions:
PID: Reduce Kp, increase Ti, reduce Td
DiffEq: Increase time constant τ
MPC: Increase R weights (control cost), reduce Q weights
Dual: Reduce feedback gains
All: Increase update interval
2. Slow convergence:
Symptoms: Takes too long to reach target
Solutions:
PID: Increase Kp, reduce Ti
DiffEq: Reduce time constant τ
MPC: Increase Q weights, reduce R weights
Dual: Increase feedback gains
All: Decrease update interval
3. Steady-state error:
Symptoms: Never quite reaches target
Solutions:
PID: Reduce Ti (increase integral action)
DiffEq: Check for systematic bias
MPC: Verify constraints not limiting
Empirical: Check calibration data accuracy
All: Verify target is physically achievable
4. Noisy control signal:
Symptoms: Bath temperature fluctuates rapidly
Solutions:
PID: Increase Td filter time, reduce Kp
All: Increase update interval
All: Add rate limiting on control output
All: Filter measurement signal
5. Auto-tune failure:
Symptoms: PID auto-tune doesn’t converge
Solutions:
Increase auto_tune_duration_ps
Adjust step_size
Check system is at steady state before tuning
Verify measurement signal is responsive
Best Practices¶
Start simple: Try DiffEq or Setpoint before PID or MPC
Test in isolation: Validate controller before production runs
Monitor performance: Track error, control effort, convergence
Document settings: Record all controller parameters
Compare to baseline: Verify improvement over open-loop
Use auto-tuning: Let PID auto-tune when possible
Understand dynamics: Know system time constants
Respect constraints: Don’t request impossible performance
Save data: Log controller state and measurements
Validate physically: Ensure temperatures make physical sense
Advanced Topics¶
Cascaded Control¶
Combine multiple controllers for hierarchical control:
# Outer loop: Setpoint provides slow temperature ramp
setpoint = SimpleSetpointController(...)
# Inner loop: PID tracks setpoint with fast regulation
pid = PIDControl(..., setpoint_source=setpoint)
Gain Scheduling¶
Adjust controller gains based on operating point:
def update_gains(T_current):
if T_current < 100:
pid.Kp = 2.0
else:
pid.Kp = 1.0
Feedforward Control¶
Add feedforward term for known disturbances:
T_bath = pid.compute_control(T_measured) + feedforward_term(t)
Example Workflows¶
Complete Temperature Control¶
from cavitymd import CavityMDSimulation
from cavitymd.controllers import PIDControl
from cavitymd.analysis import TemperatureTracker, ElapsedTimeTracker
# Setup simulation
sim = CavityMDSimulation(
job_dir='pid_control_test',
replica=0,
temperature=100.0,
freq=2000,
couplstr=0.001,
incavity=True,
runtime_ps=1000
)
# Setup tracking
time_tracker = ElapsedTimeTracker(sim.sim)
temp_tracker = TemperatureTracker(
sim.sim, time_tracker,
output_period_ps=0.1
)
# Setup PID controller with auto-tuning
pid = PIDControl(
simulation=sim,
time_tracker=time_tracker,
temperature_tracker=temp_tracker,
molecular_thermostat=sim.bussi_thermostat,
setpoint_K=100.0,
signal_choice='lj_coulombic',
auto_tune=True,
auto_tune_duration_ps=50.0
)
# Add to simulation
sim.sim.operations.updaters.append(hoomd.update.CustomUpdater(
action=pid,
trigger=hoomd.trigger.Periodic(1)
))
# Run
sim.run()
Next Sections¶
FDR Temperature for advanced temperature measurement
Molecular Temperatures for temperature decomposition
Thermostats for standard thermostat theory
Running Simulations for basic simulation setup