def Stochastic_Velocity_From_FT_no_lub(self, FT): ''' Performs one step of Euler Maruyama WITHOUT using 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) W = np.random.randn(6*r_vecs.shape[0],1) W2 = 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) drift = (self.kT/self.delta)*(MpW-MmW) def MobV(v): Mv = self.Wall_Mobility_Mult(v) return Mv Mhalf, it_lanczos = stochastic.stochastic_forcing_lanczos(factor = np.sqrt(2*self.kT / self.dt), tolerance = self.tolerance, dim = 6*r_vecs.shape[0], mobility_mult = MobV, L_mult = None, print_residual = False) MF = MobV(FT) vel = MF + drift + Mhalf return vel
def compute_stochastic_linear_velocity(self, dt): ''' Compute stochastic linear velocity v_stoch = sqrt(2*kT) * M_tt^{1/2}*W + kT*div_t(M_tt). This function returns the stochastic velocity v_stoch. ''' # Create auxiliar variables Nblobs = len(self.bodies) # Get blobs coordinates r_vectors_blobs = np.empty((Nblobs, 3)) for k, b in enumerate(self.bodies): r_vectors_blobs[k] = b.location # Generate random vector z = np.random.randn(3 * Nblobs) # Define mobility matrix def mobility_matrix(force, r_vectors = None, eta = None, a = None, periodic_length = None): return self.mobility_trans_times_force(r_vectors, force, eta, a, periodic_length = periodic_length) partial_mobility_matrix = partial(mobility_matrix, r_vectors = r_vectors_blobs, eta = self.eta, a = self.a, periodic_length = self.periodic_length) # Generate noise term sqrt(2*kT) * N^{1/2} * z velocities_noise, it_lanczos = stochastic.stochastic_forcing_lanczos(factor = np.sqrt(2*self.kT / dt), tolerance = self.tolerance, dim = self.Nblobs * 3, mobility_mult = partial_mobility_matrix, z = z, print_residual = self.print_residual) self.stoch_iterations_count += it_lanczos # Compute divergence term div_t(M_tt) # 1. Generate random displacement if self.kT > 0.0 and self.domain != 'no_wall': dx_stoch = np.reshape(np.random.randn(Nblobs * 3), (Nblobs, 3)) # 2. Displace blobs r_vectors_blobs += dx_stoch * (self.rf_delta * self.a * 0.5) # 3. Compute M_tt(r+0.5*dx) * dx_stoch div_M_tt = self.mobility_trans_times_force(r_vectors_blobs, np.reshape(dx_stoch, dx_stoch.size), self.eta, self.a, periodic_length = self.periodic_length) # 4. Displace blobs in the other direction r_vectors_blobs -= dx_stoch * self.rf_delta * self.a # 5. Compute -M_tt(r-0.5*dx) * dx_stoch div_M_tt -= self.mobility_trans_times_force(r_vectors_blobs, np.reshape(dx_stoch, dx_stoch.size), self.eta, self.a, periodic_length = self.periodic_length) # Reset blobs location r_vectors_blobs += dx_stoch * (self.rf_delta * self.a * 0.5) else: div_M_tt = np.zeros(velocities_noise.size) # Compute stochastic velocity v_stoch = sqrt(2*kT/dt) * M_tt^{1/2}*W + kT*div_t(M_tt). return velocities_noise + (self.kT / (self.rf_delta * self.a)) * div_M_tt
def compute_stochastic_linear_velocity_without_drift(self, dt): ''' Compute stochastic linear velocity v_stoch = sqrt(2*kT) * M_tt^{1/2}*W This function returns the stochastic velocity v_stoch. ''' # Create auxiliar variables Nblobs = len(self.bodies) # Get blobs coordinates r_vectors_blobs = np.empty((Nblobs, 3)) for k, b in enumerate(self.bodies): r_vectors_blobs[k] = b.location # Generate random vector z = np.random.randn(3 * Nblobs) # Define mobility matrix def mobility_matrix(force, r_vectors=None, eta=None, a=None, periodic_length=None): return self.mobility_trans_times_force( r_vectors, force, eta, a, periodic_length=periodic_length) partial_mobility_matrix = partial(mobility_matrix, r_vectors=r_vectors_blobs, eta=self.eta, a=self.a, periodic_length=self.periodic_length) # Generate noise term sqrt(2*kT) * N^{1/2} * z velocities_noise, it_lanczos = stochastic.stochastic_forcing_lanczos( factor=np.sqrt(2 * self.kT / dt), tolerance=self.tolerance, dim=self.Nblobs * 3, mobility_mult=partial_mobility_matrix, z=z, print_residual=self.print_residual) self.stoch_iterations_count += it_lanczos # Return velocity return velocities_noise
def Lub_Mobility_Root_RHS(self, print_res=False): ''' Returns both DR^{1/2} and M_RPY^{1/2} to be used in the function Lubrucation_solve to compute the square root of the lubrication corrected mobility ''' Dim = self.Delta_R.shape[1] W1 = np.transpose(np.random.randn(1, Dim)) W2 = np.transpose(np.random.randn(1, Dim)) start = time.time() small = 6.0*np.pi*self.eta*self.a*self.tolerance Eig_Shift_DR_cut = self.Delta_R + sp.diags(small*np.ones(Dim),0,format='csc') factor = cholesky(Eig_Shift_DR_cut) DRL = factor.L() DRhalf = factor.apply_Pt(DRL.dot(W1)) end = time.time() #print 'time for DR root: '+ str((end - start)) start = time.time() WallCutHalf, it_lanczos = stochastic.stochastic_forcing_lanczos(factor = 1.0, tolerance = self.tolerance, dim = Dim, mobility_mult = self.Wall_Mobility_Mult, L_mult = None, print_residual = print_res, z=W2) end = time.time() #print 'time for M + MDRM root: '+ str((end - start)) RHS_Xm = np.sqrt(2*self.kT / self.dt)*(DRhalf) RHS_X = np.sqrt(2*self.kT / self.dt)*(WallCutHalf) return RHS_Xm, RHS_X
def compute_stochastic_velocity(self, dt): ''' Compute stochastic torque and velocity. First, solve for the torque M_rr * T = -kT*div_t(M_rt) - sqrt(2*kT) * (N^{1/2}*W)_r, then set linear velocity v_stoch = M_tr * T + sqrt(2*kT) * (N^{1/2}*W)_t + kT*div_t(M_tt). Here N = (M_tt M_tr; M_rt M_rr) is the grand mobility matrix. We use random finite difference to compute the divergence terms. Note that in principle we should include the term div_r(M_rr) in the torque equation and div_r(M_tr) in the velocity equation but they are zero for a roller. This function returns the stochastic velocity v_stoch. ''' # Create auxiliar variables Nblobs = len(self.bodies) blob_mass = 1.0 # Get blobs coordinates r_vectors_blobs = np.empty((Nblobs, 3)) for k, b in enumerate(self.bodies): r_vectors_blobs[k] = b.location # Generate random vector z = np.random.randn(6 * Nblobs) # Define grand mobility matrix def grand_mobility_matrix(force_torque, r_vectors = None, eta = None, a = None, periodic_length = None): half_size = force_torque.size / 2 # velocity = self.mobility_trans_times_force_torque(r_vectors, force_torque[0:half_size], force_torque[half_size:], eta, a, periodic_length = periodic_length) velocity = self.mobility_trans_times_force(r_vectors, force_torque[0:half_size], eta, a, periodic_length = periodic_length) velocity += self.mobility_trans_times_torque(r_vectors, force_torque[half_size:], eta, a, periodic_length = periodic_length) angular_velocity = self.mobility_rot_times_force(r_vectors, force_torque[0:half_size], eta, a, periodic_length = periodic_length) angular_velocity += self.mobility_rot_times_torque(r_vectors, force_torque[half_size:], eta, a, periodic_length = periodic_length) return np.concatenate([velocity, angular_velocity]) partial_grand_mobility_matrix = partial(grand_mobility_matrix, r_vectors = r_vectors_blobs, eta = self.eta, a = self.a, periodic_length = self.periodic_length) # Generate noise term sqrt(2*kT) * N^{1/2} * z velocities_noise, it_lanczos = stochastic.stochastic_forcing_lanczos(factor = np.sqrt(2*self.kT / dt), tolerance = self.tolerance, dim = self.Nblobs * 6, mobility_mult = partial_grand_mobility_matrix, z = z, print_residual = self.print_residual) self.stoch_iterations_count += it_lanczos # Compute divergence terms div_t(M_rt) and div_t(M_tt) if self.kT > 0.0 and self.domain != 'no_wall': # 1. Generate random displacement dx_stoch = np.reshape(np.random.randn(Nblobs * 3), (Nblobs, 3)) # 2. Displace blobs r_vectors_blobs += dx_stoch * (self.rf_delta * self.a * 0.5) # 3. Compute M_rt(r+0.5*dx) * dx_stoch div_M_rt = self.mobility_rot_times_force(r_vectors_blobs, np.reshape(dx_stoch, dx_stoch.size), self.eta, self.a, periodic_length = self.periodic_length) div_M_tt = self.mobility_trans_times_force(r_vectors_blobs, np.reshape(dx_stoch, dx_stoch.size), self.eta, self.a, periodic_length = self.periodic_length) # 4. Displace blobs in the other direction r_vectors_blobs -= dx_stoch * self.rf_delta * self.a # 5. Compute -M_rt(r-0.5*dx) * dx_stoch div_M_rt -= self.mobility_rot_times_force(r_vectors_blobs, np.reshape(dx_stoch, dx_stoch.size), self.eta, self.a, periodic_length = self.periodic_length) div_M_tt -= self.mobility_trans_times_force(r_vectors_blobs, np.reshape(dx_stoch, dx_stoch.size), self.eta, self.a, periodic_length = self.periodic_length) # Reset blobs location r_vectors_blobs += dx_stoch * (self.rf_delta * self.a * 0.5) else: div_M_rt = np.zeros(Nblobs * 3) div_M_tt = np.zeros(Nblobs * 3) # Use constraint motion or free kinematics if self.free_kinematics == 'False': # Set RHS = -kT*div_t(M_rt) - sqrt(2*kT) * (N^{1/2}*W)_r, RHS = -velocities_noise[velocities_noise.size / 2:] - div_M_rt * (self.kT / (self.rf_delta * self.a)) # Set linear operator system_size = 3 * len(self.bodies) def mobility_rot_torque(torque, r_vectors = None, eta = None, a = None, periodic_length = None): return self.mobility_rot_times_torque(r_vectors, torque, eta, a, periodic_length = periodic_length) linear_operator_partial = partial(mobility_rot_torque, r_vectors = r_vectors_blobs, eta = self.eta, a = self.a, periodic_length = self.periodic_length) A = spla.LinearOperator((system_size, system_size), matvec = linear_operator_partial, dtype='float64') # Scale RHS to norm 1 RHS_norm = np.linalg.norm(RHS) if RHS_norm > 0: RHS = RHS / RHS_norm # Solve linear system counter = gmres_counter(print_residual = self.print_residual) (sol_precond, info_precond) = utils.gmres(A, RHS, tol=self.tolerance, maxiter=1000, callback=counter) self.det_iterations_count += counter.niter # Scale solution with RHS norm if RHS_norm > 0: sol_precond = sol_precond * RHS_norm else: # This is free kinematics, stochastic torque set to zero # because we only care for the translational degrees of freedom sol_precond = np.zeros(3 * Nblobs) # Compute stochastic velocity v_stoch = M_tr * T + sqrt(2*kT) * (N^{1/2}*W)_t + kT*div_t(M_tt). v_stoch = self.mobility_trans_times_torque(r_vectors_blobs, sol_precond, self.eta, self.a, periodic_length = self.periodic_length) v_stoch += velocities_noise[0 : velocities_noise.size / 2] + (self.kT / (self.rf_delta * self.a)) * div_M_tt return v_stoch