-
Notifications
You must be signed in to change notification settings - Fork 14
bugfix-ncycles-computed #80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| __version__ = "0.4.1" | ||
| __version__ = "0.4.2" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -117,9 +117,13 @@ class SomdConfig(_EngineConfig): | |
|
|
||
| ### Integrator - ncycles modified as required by a3fe ### | ||
| timestep: float = _Field(4.0, description="Timestep in femtoseconds(fs)") | ||
| nmoves: int = _Field( | ||
| 25000, | ||
| description="Number of moves per cycle. Default 25000 provides optimal checkpoint frequency.", | ||
| ) | ||
| runtime: _Union[int, float] = _Field( | ||
| 5.0, | ||
| description="Runtime in nanoseconds(ns), and must be a multiple of timestep", | ||
| description="Runtime in nanoseconds(ns), must be a multiple of timestep and ncycles will be calculated from runtime and nmoves", | ||
| ) | ||
|
|
||
| ### Constraints ### | ||
|
|
@@ -225,29 +229,37 @@ class SomdConfig(_EngineConfig): | |
| ) | ||
|
|
||
| @property | ||
| def nmoves(self) -> int: | ||
| def ncycles(self) -> int: | ||
| """ | ||
| Make sure runtime is a multiple of timestep | ||
| Calculate number of cycles from runtime, nmoves and timestep. | ||
| Formula: runtime = nmoves × ncycles × timestep | ||
| """ | ||
| # Convert runtime to femtoseconds (ns -> fs) | ||
| runtime_fs = _Decimal(str(self.runtime)) * _Decimal("1_000_000") | ||
| timestep = _Decimal(str(self.timestep)) | ||
| nmoves_dec = _Decimal(str(self.nmoves)) | ||
|
|
||
| # Check if runtime is a multiple of timestep | ||
| remainder = runtime_fs % timestep | ||
| if round(float(remainder), 4) != 0: | ||
| raise ValueError( | ||
| ( | ||
| "Runtime must be a multiple of the timestep. " | ||
| f"Runtime is {self.runtime} ns ({runtime_fs} fs), " | ||
| f"and timestep is {self.timestep} fs." | ||
| ) | ||
| f"Runtime must be a multiple of timestep. " | ||
| f"Runtime is {self.runtime} ns ({runtime_fs} fs), " | ||
| f"timestep is {self.timestep} fs." | ||
| ) | ||
|
|
||
| # Calculate the number of moves | ||
| nmoves = round(float(runtime_fs) / float(timestep)) | ||
| # Calculate ncycles | ||
| total_steps = runtime_fs / timestep | ||
| ncycles = total_steps / nmoves_dec | ||
| ncycles_int = round(float(ncycles)) | ||
|
|
||
| if ncycles_int < 1: | ||
| raise ValueError( | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know this was done before for timestep and runtime, but I think it might be better to validate all of this stuff in a validator, rather than in the property. Then, an error will be raised on instantiation/ assignment (we've set it to validate on assignment) rather than later when the user tries to call the property. The property can then just compute |
||
| f"Runtime {self.runtime} ns is too short for nmoves={self.nmoves}. " | ||
| f"Decrease nmoves or increase runtime." | ||
| ) | ||
|
|
||
| return nmoves | ||
| return ncycles_int | ||
|
|
||
| @_model_validator(mode="after") | ||
| def _check_rf_dielectric(self): | ||
|
|
@@ -336,6 +348,7 @@ def write_config( | |
| config_lines = [ | ||
| "### Integrator ###", | ||
| f"timestep = {self.timestep} * femtosecond", | ||
| f"ncycles = {self.ncycles}", | ||
| f"nmoves = {self.nmoves}", | ||
| f"constraint = {self.constraint}", | ||
| f"hydrogen mass repartitioning factor = {self.hydrogen_mass_factor}", | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might not be remembering how these settings work, but my main comment is: do we know if this will work with adaptive computations where the assigned times may be pretty short? 25000 * 4 fs = 100 ps which is a fairly large smallest runtime. Have you tried this with the adaptive runs?
A simple way to make this more flexible would be to replace
nmoveswithmax_nmoves. This would modify the behaviour of the previousnmovesproperty so that the behaviour stays as it was unless runtime > max_nmoves * timestep, in which case thenmovesgets e.g. halved andncyclesdoubled or something similar. We'll need to be careful to make sure you get a validnmovesandncyclesin this case (easiest way might be to enforce that runtime must be a multiple of 2 * timestep).