q2m3.sampling.mc_moves 源代码

# Copyright (c) 2026 Ye Jun <yjmaxpayne@hotmail.com>
# SPDX-License-Identifier: MIT

"""
Monte Carlo move generator for water molecules.

This module provides random translation and rotation moves for
Monte Carlo sampling of water configurations.
"""

from __future__ import annotations

from dataclasses import dataclass

import numpy as np

from .water_molecule import WaterMolecule

# Default MC step sizes
DEFAULT_TRANSLATION_STEP = 0.3  # Angstrom
DEFAULT_ROTATION_STEP = np.radians(15.0)  # radians (~15 degrees)


[文档] @dataclass class MCMoveGenerator: """ Generator for Monte Carlo moves (translation and rotation). Attributes: translation_step: Maximum translation in each direction (Angstrom) rotation_step: Maximum rotation in each Euler angle (radians) """ translation_step: float = DEFAULT_TRANSLATION_STEP rotation_step: float = DEFAULT_ROTATION_STEP
[文档] def propose_translation(self, water: WaterMolecule) -> WaterMolecule: """ Propose a random translation move. Args: water: Original water molecule Returns: New water molecule with translated position """ # Random displacement in [-step, +step] for each dimension displacement = np.random.uniform(-self.translation_step, self.translation_step, size=3) new_position = water.position + displacement return WaterMolecule( position=new_position, euler_angles=water.euler_angles.copy(), )
[文档] def propose_rotation(self, water: WaterMolecule) -> WaterMolecule: """ Propose a random rotation move. Args: water: Original water molecule Returns: New water molecule with rotated orientation """ # Random rotation in [-step, +step] for each Euler angle delta_angles = np.random.uniform(-self.rotation_step, self.rotation_step, size=3) new_euler_angles = water.euler_angles + delta_angles return WaterMolecule( position=water.position.copy(), euler_angles=new_euler_angles, )
[文档] def propose_move(self, water: WaterMolecule) -> WaterMolecule: """ Propose either a translation or rotation move with equal probability. Args: water: Original water molecule Returns: New water molecule with proposed move applied """ if np.random.random() < 0.5: return self.propose_translation(water) else: return self.propose_rotation(water)
[文档] def propose_move_for_system( self, waters: list[WaterMolecule] ) -> tuple[list[WaterMolecule], int]: """ Propose a move for one randomly selected water in the system. Args: waters: List of water molecules Returns: Tuple of (new_waters, moved_index): - new_waters: Copy of waters list with one water moved - moved_index: Index of the water that was moved """ n_waters = len(waters) if n_waters == 0: raise ValueError("Cannot propose move for empty water list") # Select random water idx = np.random.randint(n_waters) # Create new list with copies new_waters = [w.copy() for w in waters] # Apply move to selected water new_waters[idx] = self.propose_move(waters[idx]) return new_waters, idx