Source code for mdpy.core.ensemble

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
file : ensemble.py
created time : 2021/09/28
author : Zhenyu Wei
copyright : (C)Copyright 2021-present, mdpy organization
"""

import numpy as np
import cupy as cp
import numba.cuda as cuda
import mdpy as md
from mdpy.environment import *
from mdpy.core import Topology, State, TileList
from mdpy.error import *
from mdpy.unit import *


[docs]class Ensemble:
[docs] def __init__( self, topology: Topology, pbc_matrix: np.ndarray, is_use_tile_list=True ) -> None: if not topology.is_joined: topology.join() self._is_use_tile_list = is_use_tile_list # Read input self._topology = topology self._state = State(self._topology, pbc_matrix.copy()) self._tile_list = TileList(pbc_matrix.copy()) self._matrix_shape = self._state.matrix_shape self._forces = cp.zeros(self._matrix_shape, CUPY_FLOAT) self._total_energy = 0 self._potential_energy = 0 self._kinetic_energy = 0 self._constraints = [] self._num_constraints = 0
def __repr__(self) -> str: return "<mdpy.Ensemble object: %d constraints at %x>" % ( self._num_constraints, id(self), ) __str__ = __repr__ def add_constraints(self, *constraints): for constraint in constraints: if constraint in self._constraints: raise ConstraintConflictError( "%s has added twice to %s" % (constraint, self) ) self._constraints.append(constraint) constraint.bind_ensemble(self) if constraint.cutoff_radius > self._tile_list.cutoff_radius: self._tile_list.set_cutoff_radius(constraint.cutoff_radius) self._num_constraints += 1 def update_constraints(self): self._forces = cp.zeros(self._matrix_shape, CUPY_FLOAT) self._potential_energy = cp.zeros([1], CUPY_FLOAT) if self._is_use_tile_list: self._state.sorted_positions = self._tile_list.sort_matrix( self._state.positions ) self._total_energy, self._kinetic_energy = 0, 0 for constraint in self._constraints: constraint.update() cuda.synchronize() for constraint in self._constraints: self._forces += constraint.forces self._potential_energy += constraint.potential_energy self._update_kinetic_energy() self._total_energy = self._potential_energy + self._kinetic_energy def update_tile_list(self): self._tile_list.update(self._state.positions) # sort topology attribute self._topology.device_sorted_charges = self._tile_list.sort_matrix( self._topology.device_charges ) self._topology.device_exclusion_map = ( self._tile_list.generate_exclusion_mask_map( self._topology.device_excluded_particles ) ) # sort constraint attribute for constraint in self._constraints: constraint.sort_attributes() def _update_kinetic_energy(self): # Without reshape, the result of the first sum will be a 1d vector # , which will be a matrix after multiple with a 2d vector self._kinetic_energy = ( (self._state.velocities**2).sum(1) * self._topology.device_masses[:, 0] ).sum() / 2 @property def topology(self) -> Topology: return self._topology @property def state(self) -> State: return self._state @property def tile_list(self) -> TileList: return self._tile_list @property def constraints(self): return self._constraints @property def num_constraints(self) -> int: return self._num_constraints @property def forces(self) -> cp.ndarray: return self._forces @property def total_energy(self) -> float: return self._total_energy @property def potential_energy(self) -> float: return self._potential_energy @property def kinetic_energy(self) -> float: return self._kinetic_energy