@@ -146,25 +146,21 @@ following *run()* method to the *MinimizeEnergy* class:
146146 # First, meevaluate the initial energy and max force
147147 self .update_neighbor_lists() # Rebuild neighbor list, if necessary
148148 self .update_cross_coefficients() # Recalculate the cross coefficients, if necessary
149- try : # try using the last saved Epot and MaxF, if it exists
150- init_Epot = self .Epot
151- init_MaxF = self .MaxF
152- except : # If Epot/MaxF do not exists yet, calculate them both
153- init_Epot = self .compute_potential(output = " potential" )
154- forces = self .compute_potential(output = " force-vector" )
155- init_MaxF = np.max(np.abs(forces))
149+ if self .step == 0 : # At the first step, Epot/MaxF do not exists yet, calculate them both
150+ init_Epot = self .compute_potential()
151+ forces, init_MaxF = self .compute_vector_force()
156152 # Save the current atom positions
157153 init_positions = copy.deepcopy(self .atoms_positions)
158154 # Move the atoms in the opposite direction of the maximum force
159155 self .atoms_positions = self .atoms_positions \
160156 + forces/ init_MaxF* self .displacement
161157 # Recalculate the energy
162- trial_Epot = self .compute_potential(output = " potential " )
158+ trial_Epot = self .compute_potential()
163159 # Keep the more favorable energy
164160 if trial_Epot < init_Epot: # accept new position
165161 self .Epot = trial_Epot
166162 # calculate the new max force and save it
167- forces = self .compute_potential( output = " force-vector " )
163+ forces, init_MaxF = self .compute_vector_force( )
168164 self .MaxF = np.max(np.abs(forces))
169165 self .wrap_in_box() # Wrap atoms in the box, if necessary
170166 self .displacement *= 1.2 # Multiply the displacement by a factor 1.2
@@ -274,42 +270,92 @@ class.
274270
275271.. code-block :: python
276272
277- def compute_potential (self , output ):
278- if output == " force-vector" :
279- forces = np.zeros((self .total_number_atoms,3 ))
280- elif output == " force-matrix" :
281- forces = np.zeros((self .total_number_atoms,self .total_number_atoms,3 ))
273+ def compute_potential (self ):
274+ """ Compute the potential energy by summing up all pair contributions."""
282275 energy_potential = 0
283- box_size = self .box_size[:3 ]
284- half_box_size = self .box_size[:3 ]/ 2.0
285276 for Ni in np.arange(self .total_number_atoms- 1 ):
286- # Read information about atom i
287- position_i = self .atoms_positions[Ni]
277+ # Read neighbor list
288278 neighbor_of_i = self .neighbor_lists[Ni]
289- # Read information about neighbors j and cross coefficient
290- positions_j = self .atoms_positions[neighbor_of_i]
279+ # Measure distance
280+ rij = self .compute_distance(self .atoms_positions[Ni],
281+ self .atoms_positions[neighbor_of_i],
282+ self .box_size[:3 ])
283+ # Measure potential using information about cross coefficients
291284 sigma_ij = self .sigma_ij_list[Ni]
292285 epsilon_ij = self .epsilon_ij_list[Ni]
293- # Measure distances
294- # Measure distances
295- # The nan_to_num is crutial in 2D to avoid nan value along third dimension
296- rij_xyz = np.nan_to_num(np.remainder(position_i - positions_j
297- + half_box_size, box_size) - half_box_size)
298- rij = np.linalg.norm(rij_xyz, axis = 1 )
299- # Measure potential
300- if output == " potential" :
301- energy_potential += np.sum(potentials(self .potential_type, epsilon_ij, sigma_ij, rij))
302- else :
303- derivative_potential = potentials(self .potential_type, epsilon_ij, sigma_ij, rij, derivative = True )
304- if output == " force-vector" :
305- forces[Ni] += np.sum((derivative_potential* rij_xyz.T/ rij).T, axis = 0 )
306- forces[neighbor_of_i] -= (derivative_potential* rij_xyz.T/ rij).T
307- elif output == " force-matrix" :
308- forces[Ni][neighbor_of_i] += (derivative_potential* rij_xyz.T/ rij).T
309- if output== " potential" :
310- return energy_potential
311- elif (output == " force-vector" ) | (output == " force-matrix" ):
312- return forces
286+ energy_potential += np.sum(potentials(self .potential_type,
287+ epsilon_ij, sigma_ij, rij))
288+ return energy_potential
289+
290+ .. label :: end_Utilities_class
291+
292+ .. label :: start_Utilities_class
293+
294+ .. code-block :: python
295+
296+ def compute_distance (self ,position_i , positions_j , box_size , only_norm = True ):
297+ """
298+ Measure the distances between two particles.
299+ The nan_to_num is crutial in 2D to avoid nan value along third dimension.
300+ # TOFIX: Move as function instead of a method?
301+ """
302+ rij_xyz = np.nan_to_num(np.remainder(position_i - positions_j
303+ + box_size[:3 ]/ 2.0 , box_size) - box_size[:3 ]/ 2.0 )
304+ if only_norm:
305+ return np.linalg.norm(rij_xyz, axis = 1 )
306+ else :
307+ return np.linalg.norm(rij_xyz, axis = 1 ), rij_xyz
308+
309+ .. label :: end_Utilities_class
310+
311+ .. label :: start_Utilities_class
312+
313+ .. code-block :: python
314+
315+ def compute_vector_force (self ):
316+ force_vector = np.zeros((self .total_number_atoms,3 ))
317+ for Ni in np.arange(self .total_number_atoms- 1 ):
318+ # Read neighbor list
319+ neighbor_of_i = self .neighbor_lists[Ni]
320+ # Measure distance
321+ rij, rij_xyz = self .compute_distance(self .atoms_positions[Ni],
322+ self .atoms_positions[neighbor_of_i],
323+ self .box_size[:3 ], only_norm = False )
324+ # Measure force using information about cross coefficients
325+ sigma_ij = self .sigma_ij_list[Ni]
326+ epsilon_ij = self .epsilon_ij_list[Ni]
327+ fij_xyz = potentials(self .potential_type, epsilon_ij,
328+ sigma_ij, rij, derivative = True )
329+ # Add the contribution to both Ni and its neighbors
330+ force_vector[Ni] += np.sum((fij_xyz* rij_xyz.T/ rij).T, axis = 0 )
331+ force_vector[neighbor_of_i] -= (fij_xyz* rij_xyz.T/ rij).T
332+ max_force = np.max(np.abs(force_vector))
333+ return force_vector, max_force
334+
335+ .. label :: end_Utilities_class
336+
337+ .. label :: start_Utilities_class
338+
339+ .. code-block :: python
340+
341+ def compute_vector_matrix (self ):
342+ force_matrix = np.zeros((self .total_number_atoms,
343+ self .total_number_atoms,3 ))
344+ for Ni in np.arange(self .total_number_atoms- 1 ):
345+ # Read neighbor list
346+ neighbor_of_i = self .neighbor_lists[Ni]
347+ # Measure distance
348+ rij, rij_xyz = self .compute_distance(self .atoms_positions[Ni],
349+ self .atoms_positions[neighbor_of_i],
350+ self .box_size[:3 ], only_norm = False )
351+ # Measure force using information about cross coefficients
352+ sigma_ij = self .sigma_ij_list[Ni]
353+ epsilon_ij = self .epsilon_ij_list[Ni]
354+ fij_xyz = potentials(self .potential_type, epsilon_ij,
355+ sigma_ij, rij, derivative = True )
356+ # Add the contribution to the force matrix
357+ force_matrix[Ni][neighbor_of_i] += (fij_xyz* rij_xyz.T/ rij).T
358+ return force_matrix
313359
314360 .. label :: end_Utilities_class
315361
0 commit comments