feat: add dice input generation and player routines for NVT/NPT simulations

This commit is contained in:
2026-03-14 18:28:15 -03:00
parent 53eb34a83e
commit 9f22304dd8
10 changed files with 534 additions and 51 deletions

View File

@@ -0,0 +1,186 @@
from diceplayer.config import PlayerConfig
from typing_extensions import Self
import random
from abc import ABC
from dataclasses import dataclass, fields
from typing import Any, Sequence, TextIO
@dataclass(slots=True)
class BaseConfig(ABC):
ncores: int
ljname: str
outname: str
nmol: Sequence[int]
temp: float
seed: int
isave: int
press: float = 1.0
def write_dice_config(self, io_writer: TextIO) -> None:
for field in fields(self):
key = field.name
value = getattr(self, key)
if value is None:
continue
io_writer.write(f"{key} = {self._serialize_value(value)}\n")
io_writer.write("$end\n")
@classmethod
def from_config(cls, config: PlayerConfig, **kwargs) -> Self:
base_fields = cls._extract_base_fields(config)
return cls(**base_fields, **kwargs)
@staticmethod
def _extract_base_fields(config: PlayerConfig) -> dict[str, Any]:
seed: int
if config.dice.seed is not None:
seed = config.dice.seed
else:
seed = random.randint(0, 2**32 - 1)
return dict(
ncores=config.ncores,
ljname=config.dice.ljname,
outname=config.dice.outname,
nmol=config.dice.nmol,
temp=config.dice.temp,
seed=seed,
isave=config.dice.isave,
press=config.dice.press,
)
@staticmethod
def _get_nstep(config: PlayerConfig, idx: int) -> int:
if len(config.dice.nstep) > idx:
return config.dice.nstep[idx]
return config.dice.nstep[-1]
@staticmethod
def _serialize_value(value: Any) -> str:
if value is None:
raise ValueError("DICE configuration cannot serialize None values")
if isinstance(value, bool):
return "yes" if value else "no"
if isinstance(value, (list, tuple)):
return " ".join(str(v) for v in value)
return str(value)
# -----------------------------------------------------
# NVT BASE
# -----------------------------------------------------
@dataclass(slots=True)
class NVTConfig(BaseConfig):
title: str = "Diceplayer Run - NVT"
dens: float = 0.0
nstep: int = 0
vstep: int = 0
# -----------------------------------------------------
# NVT THERMALIZATION
# -----------------------------------------------------
@dataclass(slots=True)
class NVTTerConfig(NVTConfig):
title: str = "Diceplayer Run - NVT Thermalization"
upbuf: int = 360
@classmethod
def from_config(cls, config: PlayerConfig, **kwargs) -> Self:
return super(NVTTerConfig, cls).from_config(
config,
dens=config.dice.dens,
nstep=cls._get_nstep(config, 0),
upbuf=config.dice.upbuf,
vstep=0,
**kwargs,
)
# -----------------------------------------------------
# NVT PRODUCTION
# -----------------------------------------------------
@dataclass(slots=True)
class NVTEqConfig(NVTConfig):
title: str = "Diceplayer Run - NVT Production"
irdf: int = 0
@classmethod
def from_config(cls, config: PlayerConfig, **kwargs) -> Self:
return super(NVTEqConfig, cls).from_config(
config,
dens=config.dice.dens,
nstep=cls._get_nstep(config, 1),
irdf=config.dice.irdf,
vstep=0,
**kwargs,
)
# -----------------------------------------------------
# NPT BASE
# -----------------------------------------------------
@dataclass(slots=True)
class NPTConfig(BaseConfig):
title: str = "Diceplayer Run - NPT"
nstep: int = 0
vstep: int = 5000
# -----------------------------------------------------
# NPT THERMALIZATION
# -----------------------------------------------------
@dataclass(slots=True)
class NPTTerConfig(NPTConfig):
title: str = "Diceplayer Run - NPT Thermalization"
dens: float | None = None
@classmethod
def from_config(cls, config: PlayerConfig, **kwargs) -> Self:
return super(NPTTerConfig, cls).from_config(
config,
dens=config.dice.dens,
nstep=cls._get_nstep(config, 1),
vstep=config.dice.vstep,
**kwargs,
)
# -----------------------------------------------------
# NPT PRODUCTION
# -----------------------------------------------------
@dataclass(slots=True)
class NPTEqConfig(NPTConfig):
title: str = "Diceplayer Run - NPT Production"
dens: float | None = None
@classmethod
def from_config(cls, config: PlayerConfig, **kwargs) -> Self:
return super(NPTEqConfig, cls).from_config(
config,
dens=config.dice.dens,
nstep=cls._get_nstep(config, 2),
vstep=config.dice.vstep,
**kwargs,
)