def Update_Bodies(self, FT): ''' Updates the positions and orientations of the bodies using stochastic velocity from Euler Maruyama (computed from `Stochastic_Velocity_From_FT') ''' velocities = self.Stochastic_Velocity_From_FT(FT) for k, b in enumerate(self.bodies): b.location_new = b.location + velocities[6 * k:6 * k + 3] * self.dt quaternion_dt = Quaternion.from_rotation( (velocities[6 * k + 3:6 * k + 6]) * self.dt) b.orientation_new = quaternion_dt * b.orientation reject_wall = 0 reject_jump = 0 reject_wall, reject_jump = self.Check_Update_With_Jump() self.num_rejections_wall += reject_wall self.num_rejections_jump += reject_jump if (reject_wall + reject_jump) == 0: L = self.periodic_length for b in self.bodies: b.location = b.location_new b.orientation = b.orientation_new self.Set_R_Mats() ######## VERY IMPORTANT return reject_wall, reject_jump
def Update_Bodies_no_lub(self, FT_calc): ''' Euler Maruyama method with no lubrication corrections (just RPY) ''' r_vecs_np = [b.location for b in self.bodies] r_vecs = self.put_r_vecs_in_periodic_box(r_vecs_np, self.periodic_length) FT = FT_calc(self.bodies, r_vecs) FT = FT.flatten() FT = FT[:, np.newaxis] velocities = self.Stochastic_Velocity_From_FT_no_lub(FT) for k, b in enumerate(self.bodies): b.location_new = b.location + velocities[6 * k:6 * k + 3] * self.dt quaternion_dt = Quaternion.from_rotation( (velocities[6 * k + 3:6 * k + 6]) * self.dt) b.orientation_new = quaternion_dt * b.orientation reject_wall = 0 reject_jump = 0 reject_wall, reject_jump = self.Check_Update_With_Jump() self.num_rejections_wall += reject_wall self.num_rejections_jump += reject_jump if (reject_wall + reject_jump) == 0: L = self.periodic_length for b in self.bodies: b.location = b.location_new b.orientation = b.orientation_new return reject_wall, reject_jump
# quaternion to be used for disturbing the orientation of each body quaternion_shift = Quaternion(np.array([1, 0, 0, 0])) # for each step in the Markov chain, disturb each body's location and orientation and obtain the new list of r_vectors # of each blob. Calculate the potential of the new state, and accept or reject it according to the Markov chain rules: # 1. if Ej < Ei, always accept the state 2. if Ej < Ei, accept the state according to the probability determined by # exp(-(Ej-Ei)/kT). Then record data. # Important: record data also when staying in the same state (i.e. when a sample state is rejected) for step in range(read.initial_step, read.n_steps): blob_index = 0 for i, body in enumerate(bodies): # distrub bodies body.location_new = body.location + np.random.uniform( -max_translation, max_translation, 3) # make small change to location quaternion_shift = Quaternion.from_rotation( np.random.normal(0, 1, 3) * max_angle_shift) body.orientation_new = quaternion_shift * body.orientation sample_r_vectors[blob_index:blob_index + bodies[i].Nblobs] = body.get_r_vectors( body.location_new, body.orientation_new) blob_index += body.Nblobs # calculate potential of proposed new state sample_state_energy = many_body_potential_pycuda.compute_total_energy( bodies, sample_r_vectors, periodic_length=periodic_length, debye_length_wall=read.debye_length_wall, repulsion_strength_wall=read.repulsion_strength_wall, debye_length=read.debye_length, repulsion_strength=read.repulsion_strength,
weight = weight, blob_radius = blob_radius) # quaternion to be used for disturbing the orientation of each body quaternion_shift = Quaternion(np.array([1,0,0,0])) # for each step in the Markov chain, disturb each body's location and orientation and obtain the new list of r_vectors # of each blob. Calculate the potential of the new state, and accept or reject it according to the Markov chain rules: # 1. if Ej < Ei, always accept the state 2. if Ej < Ei, accept the state according to the probability determined by # exp(-(Ej-Ei)/kT). Then record data. # Important: record data also when staying in the same state (i.e. when a sample state is rejected) for step in range(read.initial_step, read.n_steps): blob_index = 0 for i, body in enumerate(bodies): # distrub bodies body.location_new = body.location + np.random.uniform(-max_translation, max_translation, 3) # make small change to location quaternion_shift = Quaternion.from_rotation(np.random.normal(0,1,3) * max_angle_shift) body.orientation_new = quaternion_shift * body.orientation sample_r_vectors[blob_index : blob_index + bodies[i].Nblobs] = body.get_r_vectors(body.location_new, body.orientation_new) blob_index += body.Nblobs # calculate potential of proposed new state sample_state_energy = many_body_potential_pycuda.compute_total_energy(bodies, sample_r_vectors, periodic_length = periodic_length, debye_length_wall = read.debye_length_wall, repulsion_strength_wall = read.repulsion_strength_wall, debye_length = read.debye_length, repulsion_strength = read.repulsion_strength, weight = weight, blob_radius = blob_radius)
def Update_Bodies_Trap(self, FT_calc, Omega=None, Out_Torque=False, Cut_Torque=None): L = self.periodic_length # Save initial configuration for k, b in enumerate(self.bodies): np.copyto(b.location_old, b.location) b.orientation_old = copy.copy(b.orientation) # compute forces for predictor step r_vecs_np = [b.location for b in self.bodies] r_vecs = self.put_r_vecs_in_periodic_box(r_vecs_np, self.periodic_length) start = time.time() FT = FT_calc(self.bodies, r_vecs) end = time.time() print(('F calc time : ' + str((end - start)))) FT = FT.flatten() FT = FT[:, np.newaxis] # If Omega Specified, add torques VO_guess = None if Omega is not None: FTrs = np.reshape(FT, (len(self.bodies), 6)) F = FTrs[:, 0:3] start = time.time() T_omega, VO_guess = self.Torque_from_Omega(Omega, F) if Cut_Torque is not None: Tn = np.linalg.norm(T_omega, axis=1) NewNorm = np.minimum(Tn, Cut_Torque) / Tn T_omega = NewNorm[:, None] * T_omega end = time.time() print(('Omega time : ' + str((end - start)))) FTrs[:, 3::] += T_omega FT = np.reshape(FTrs, (6 * len(self.bodies), 1)) # compute relevant matrix root for pred. and corr. steps start = time.time() Root_Xm, Root_X = self.Lub_Mobility_Root_RHS() X = Root_X[:, np.newaxis] MXm = self.Wall_Mobility_Mult(Root_Xm) MXm = MXm[:, np.newaxis] Mhalf = X + MXm end = time.time() print(('root time : ' + str((end - start)))) # compute predictor velocities and update positions start = time.time() vel_p, res_p = self.Lubrucation_solve(X=Mhalf, Xm=FT, X0=VO_guess) end = time.time() print(('solve 1 : ' + str((end - start)))) for k, b in enumerate(self.bodies): b.location = b.location_old + vel_p[6 * k:6 * k + 3] * self.dt quaternion_dt = Quaternion.from_rotation( (vel_p[6 * k + 3:6 * k + 6]) * self.dt) b.orientation = quaternion_dt * b.orientation_old r_vecs_np = [b.location for b in self.bodies] r_vecs_c = self.put_r_vecs_in_periodic_box(r_vecs_np, self.periodic_length) self.Set_R_Mats(r_vecs_np=r_vecs_c) # VERY IMPORTANT # compute rfd for M W = np.random.randn(6 * r_vecs.shape[0], 1) Wrfd = np.reshape(W, (r_vecs.shape[0], 6)) Wrfd = Wrfd[:, 0:3] Qp = r_vecs + (self.delta / 2.0) * Wrfd Qm = r_vecs - (self.delta / 2.0) * Wrfd MpW = self.Wall_Mobility_Mult(W, r_vecs_np=Qp) MmW = self.Wall_Mobility_Mult(W, r_vecs_np=Qm) D_M = 2.0 * (self.kT / self.delta) * (MpW - MmW) D_M = D_M[:, np.newaxis] # compute RHSs for the corr. step RHS_X_C = D_M + Mhalf start = time.time() FT_C = FT_calc(self.bodies, r_vecs_c) end = time.time() print(('F calc time : ' + str((end - start)))) FT_C = FT_C.flatten() FT_C = FT_C[:, np.newaxis] # If Omega Specified, add torques VO_guessc = vel_p second_order = False if Omega is not None: FTrsc = np.reshape(FT_C, (len(self.bodies), 6)) Fc = FTrsc[:, 0:3] if second_order: # you could use the previous Torque_from_Omega solve as an initial guess here and it should work very well Tc, VO_guessc = self.Torque_from_Omega(Omega, Fc) if Cut_Torque is not None: Tn = np.linalg.norm(Tc, axis=1) NewNorm = np.minimum(Tn, Cut_Torque) / Tn Tc = NewNorm[:, None] * Tc else: Tc = T_omega FTrsc[:, 3::] += Tc FT_C = np.reshape(FTrsc, (6 * len(self.bodies), 1)) RHS_Xm_C = FT_C # compute for corrected velocity and update positions start = time.time() vel_c, res_c = self.Lubrucation_solve(X=RHS_X_C, Xm=RHS_Xm_C, X0=VO_guessc) end = time.time() print(('solve 2 : ' + str((end - start)))) vel_trap = 0.5 * (vel_c + vel_p) for k, b in enumerate(self.bodies): b.location_new = b.location_old + vel_trap[6 * k:6 * k + 3] * self.dt quaternion_dt = Quaternion.from_rotation( (vel_trap[6 * k + 3:6 * k + 6]) * self.dt) b.orientation_new = quaternion_dt * b.orientation_old reject_wall = 0 reject_jump = 0 reject_wall, reject_jump = self.Check_Update_With_Jump_Trap() self.num_rejections_wall += reject_wall self.num_rejections_jump += reject_jump if (reject_wall + reject_jump) == 0: for b in self.bodies: np.copyto(b.location, b.location_new) b.orientation = copy.copy(b.orientation_new) else: for b in self.bodies: np.copyto(b.location, b.location_old) b.orientation = copy.copy(b.orientation_old) self.Set_R_Mats() ######## VERY IMPORTANT if Out_Torque: return reject_wall, reject_jump, T_omega.flatten() else: return reject_wall, reject_jump