Coverage for gamdpy/simulation_boxes/orthorhombic.py: 99%
81 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3"""
4Created on Thu Jun 13 11:41:24 2024
6@author: nbailey
7"""
9import numpy as np
10import numba
11from numba import cuda
12from .simulationbox import SimulationBox
14class Orthorhombic(SimulationBox):
15 """ Standard rectangular simulation box class
17 Example
18 -------
20 >>> import gamdpy as gp
21 >>> import numpy as np
22 >>> simbox = gp.Orthorhombic(D=3, lengths=np.array([3,4,5]))
24 """
25 def __init__(self, D, lengths):
26 self.D = D
27 self.data_array = np.array(lengths, dtype=np.float32) # ensure single precision
28 self.len_sim_box_data = D # not true for other Simbox classes. Want to remove this and just use len(self.data_array)
29 return
31 def get_name(self):
32 return "Orthorhombic"
35 def copy_to_device(self):
36 self.d_data = cuda.to_device(self.data_array)
38 def copy_to_host(self):
39 self.data_array = self.d_data.copy_to_host()
41 def get_dist_sq_dr_function(self):
42 """Generates function dist_sq_dr which computes displacement and distance squared for one neighbor """
43 D = self.D
44 def dist_sq_dr_function(ri, rj, sim_box, dr):
46 ''' Returns the squared distance between ri and rj applying MIC and saves ri-rj in dr '''
47 dist_sq = numba.float32(0.0)
48 for k in range(D):
49 dr[k] = ri[k] - rj[k]
50 box_k = sim_box[k]
51 dr[k] += (-box_k if numba.float32(2.0) * dr[k] > +box_k else
52 (+box_k if numba.float32(2.0) * dr[k] < -box_k else numba.float32(0.0))) # MIC
53 dist_sq = dist_sq + dr[k] * dr[k]
54 return dist_sq
56 return dist_sq_dr_function
58 def get_dist_sq_function(self):
59 """Generates.function dist_sq_function which computes distance squared for one neighbor """
60 D = self.D
61 def dist_sq_function(ri, rj, sim_box):
62 ''' Returns the squared distance between ri and rj applying MIC'''
63 dist_sq = numba.float32(0.0)
64 for k in range(D):
65 dr_k = ri[k] - rj[k]
66 box_k = sim_box[k]
67 dr_k += (-box_k if numba.float32(2.0) * dr_k > +box_k else
68 (+box_k if numba.float32(2.0) * dr_k < -box_k else numba.float32(0.0))) # MIC
69 dist_sq = dist_sq + dr_k * dr_k
70 return dist_sq
72 return dist_sq_function
74 def get_apply_PBC(self):
75 D = self.D
76 def apply_PBC(r, image, sim_box):
77 for k in range(D):
78 if r[k] * numba.float32(2.0) > +sim_box[k]:
79 r[k] -= sim_box[k]
80 image[k] += 1
81 if r[k] * numba.float32(2.0) < -sim_box[k]:
82 r[k] += sim_box[k]
83 image[k] -= 1
84 return
85 return apply_PBC
87 def get_lengths(self):
88 """ Return the box lengths as a numpy array """
89 return self.data_array.copy()
91 def get_volume(self):
92 """ Return the box volume """
93 #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
94 return self.get_volume_function()(self.data_array)
96 def get_volume_function(self):
97 """ Return the box volume """
98 D = self.D
99 def volume(sim_box):
100 ''' Returns volume of the rectangular box '''
101 vol = sim_box[0]
102 for i in range(1,D):
103 vol *= sim_box[i]
104 return vol
105 return volume
107 def scale(self, scale_factor):
108 """ Scale the box lengths by scale_factor """
109 self.data_array *= scale_factor
111 #def get_dist_moved_sq_function(self):
112 # D = self.D
113 # def dist_moved_sq_function(r_current, r_last, sim_box, sim_box_last):
114 # ''' Returns squared distance between vectors r_current and r_last '''
115 # dist_sq = numba.float32(0.0)
116 # for k in range(D):
117 # dr_k = r_current[k] - r_last[k]
118 # box_k = sim_box[k]
119 # dr_k += (-box_k if numba.float32(2.0) * dr_k > +box_k else
120 # (+box_k if numba.float32(2.0) * dr_k < -box_k else numba.float32(0.0))) # MIC
121 # dist_sq = dist_sq + dr_k * dr_k
123 # return dist_sq
124 # return dist_moved_sq_function
126 def get_dist_moved_exceeds_limit_function(self):
127 D = self.D
129 def dist_moved_exceeds_limit_function(r_current, r_last, sim_box, sim_box_last, skin, cut):
130 """ Returns True if squared distance between r_current and r_last exceeds half skin.
131 Parameters sim_box_last and cut are not used here, but are needed for the Lees-Edwards type of Simbox"""
132 dist_sq = numba.float32(0.0)
133 for k in range(D):
134 dr_k = r_current[k] - r_last[k]
135 box_k = sim_box[k]
136 dr_k += (-box_k if numba.float32(2.0) * dr_k > +box_k else
137 (+box_k if numba.float32(2.0) * dr_k < -box_k else numba.float32(0.0))) # MIC
138 dist_sq = dist_sq + dr_k * dr_k
140 return dist_sq > skin*skin*numba.float32(0.25)
141 return dist_moved_exceeds_limit_function
143 def get_loop_x_addition(self):
144 return 0
146 def get_loop_x_shift_function(self):
148 def loop_x_shift_function(sim_box, cell_length_x):
149 return 0
150 return loop_x_shift_function