Source code for gamdpy.simulation_boxes.orthorhombic

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Jun 13 11:41:24 2024

@author: nbailey
"""

import numpy as np
import numba
from numba import cuda
from .simulationbox import SimulationBox

[docs] class Orthorhombic(SimulationBox): """ Standard rectangular simulation box class Parameters ---------- D: int Spatial dimension lengths: list of floats The box lengths in each spatial dimension. Raises ------ ValueError If the length of ``lengths`` is not equal to ``D``. Example ------- >>> import gamdpy as gp >>> simbox = gp.Orthorhombic(D=3, lengths=[3, 4, 5]) """ def __init__(self, D: int, lengths: list): if len(lengths) != D: raise ValueError("Length of lengths must be equal to D") self.D = D # This parameter is not needed, since it is determined by the length of the box self.data_array = np.array(lengths, dtype=np.float32) # ensure single precision self.len_sim_box_data = D # not true for other Simbox classes. Want to remove this and just use len(self.data_array) return
[docs] def get_name(self) -> str: return "Orthorhombic"
[docs] def copy_to_device(self) -> None: # Copy data from host to device memory (CPU to GPU). self.d_data = cuda.to_device(self.data_array)
[docs] def copy_to_host(self) -> None: # Copy data from device to host memory (GPU to CPU). self.data_array = self.d_data.copy_to_host()
[docs] def get_dist_sq_dr_function(self) -> callable: D = self.D # A function which computes displacement and distance squared for one neighbor def dist_sq_dr_function(ri, rj, sim_box, dr): ''' Returns the squared distance between ri and rj applying MIC and saves ri-rj in dr ''' dist_sq = numba.float32(0.0) for k in range(D): dr[k] = ri[k] - rj[k] box_k = sim_box[k] dr[k] += (-box_k if numba.float32(2.0) * dr[k] > +box_k else (+box_k if numba.float32(2.0) * dr[k] < -box_k else numba.float32(0.0))) # MIC dist_sq = dist_sq + dr[k] * dr[k] return dist_sq return dist_sq_dr_function
[docs] def get_dist_sq_function(self) -> callable: D = self.D # Generates function dist_sq_function which computes distance squared for one neighbor def dist_sq_function(ri, rj, sim_box): ''' Returns the squared distance between ri and rj applying MIC''' dist_sq = numba.float32(0.0) for k in range(D): dr_k = ri[k] - rj[k] box_k = sim_box[k] dr_k += (-box_k if numba.float32(2.0) * dr_k > +box_k else (+box_k if numba.float32(2.0) * dr_k < -box_k else numba.float32(0.0))) # MIC dist_sq = dist_sq + dr_k * dr_k return dist_sq return dist_sq_function
[docs] def get_apply_PBC(self): D = self.D def apply_PBC(r, image, sim_box): for k in range(D): if r[k] * numba.float32(2.0) > +sim_box[k]: r[k] -= sim_box[k] image[k] += 1 if r[k] * numba.float32(2.0) < -sim_box[k]: r[k] += sim_box[k] image[k] -= 1 return return apply_PBC
[docs] def get_lengths(self) -> np.ndarray: """ Return the box lengths as a numpy array Returns ------- numpy.ndarray The box lengths in each spatial dimension. """ return self.data_array.copy()
[docs] def get_volume(self) -> float: r""" Return the box volume, :math:`V = \prod_{i=1}^{D} L_i` Returns ------- float Volume of the box. """ #self.copy_to_host() # not necessary if volume is fixed and if not fixed then presumably stuff like normalizing stress by volume should be done in the device anyway return float(self.get_volume_function()(self.data_array))
[docs] def get_volume_function(self): D = self.D def volume(sim_box): ''' Returns volume of the rectangular box ''' vol = sim_box[0] for i in range(1,D): vol *= sim_box[i] return vol return volume
[docs] def scale(self, scale_factor: float) -> None: """ Scale the box lengths by scale_factor """ self.data_array *= scale_factor
#def get_dist_moved_sq_function(self): # D = self.D # def dist_moved_sq_function(r_current, r_last, sim_box, sim_box_last): # ''' Returns squared distance between vectors r_current and r_last ''' # dist_sq = numba.float32(0.0) # for k in range(D): # dr_k = r_current[k] - r_last[k] # box_k = sim_box[k] # dr_k += (-box_k if numba.float32(2.0) * dr_k > +box_k else # (+box_k if numba.float32(2.0) * dr_k < -box_k else numba.float32(0.0))) # MIC # dist_sq = dist_sq + dr_k * dr_k # return dist_sq # return dist_moved_sq_function
[docs] def get_dist_moved_exceeds_limit_function(self): D = self.D def dist_moved_exceeds_limit_function(r_current, r_last, sim_box, sim_box_last, skin, cut): """ Returns True if squared distance between r_current and r_last exceeds half skin. Parameters sim_box_last and cut are not used here, but are needed for the Lees-Edwards type of Simbox""" dist_sq = numba.float32(0.0) for k in range(D): dr_k = r_current[k] - r_last[k] box_k = sim_box[k] dr_k += (-box_k if numba.float32(2.0) * dr_k > +box_k else (+box_k if numba.float32(2.0) * dr_k < -box_k else numba.float32(0.0))) # MIC dist_sq = dist_sq + dr_k * dr_k return dist_sq > skin*skin*numba.float32(0.25) return dist_moved_exceeds_limit_function
[docs] def get_loop_x_addition(self): return 0
[docs] def get_loop_x_shift_function(self): def loop_x_shift_function(sim_box, cell_length_x): # pragma: no cover return 0 return loop_x_shift_function