def generateParticleList(state, boxsize, D, Drot, randomSeed = -1): ''' Generate a random particle list of two particles corresponding to either state A or state B. As each state has several different configurations, this functions picks one randomly. The definition of the states is taken form patchyDimer.cpp :param state: bound state in which the two particle list should be in, A or B :param D and Drot: diffusion coefficients of particles. :param randomSeed: seed for python random generator. Important to specify in parallel runs. Default value of -1 will use the default seed. :return: random particle list corresponding to either state A or state B. ''' # Transform boxsize to vector if neccesarry. boxsize = boxsize - 1 # to ensure the whole compund is initially inside box (1 is the norm of relpos below) if np.isscalar(boxsize): boxsize = np.array([boxsize, boxsize, boxsize]) position1 = np.array([0.0, 0.0, 0.0]) #position1 = np.array([boxsize[0]*random.random()-0.5*boxsize[0], # boxsize[1]*random.random()-0.5*boxsize[1], # boxsize[2]*random.random()-0.5*boxsize[2]]) orientation1 = np.array([1.0, 0.0, 0.0, 0.0]) # Define relative position relpos1 = np.array([np.cos(angleDiff / 2.0),np.sin(angleDiff / 2.0), 0]) relpos2 = np.array([np.cos(angleDiff / 2.0),np.sin(-1*angleDiff / 2.0), 0]) relPos1orthogonal = np.array([-1.0 * np.sin(angleDiff / 2.0), np.cos(angleDiff / 2.0), 0.0]) relPos2orthogonal = np.array([np.sin(angleDiff / 2.0), np.cos(angleDiff / 2.0), 0.0]) # Define relative rotations rotations = [None]*8 rotations[0] = np.pi * relPos1orthogonal rotations[1] = np.array([0.0, 0.0, -2 * np.pi / 5.0]) rotations[2] = np.array([0.0, 0.0, np.pi]) rotations[3] = np.array([0.0, np.pi, 0.0]) # --first 4 rotations correspond to binding on top patch of particle 1, next 4 rotations to bottom patch rotations[4] = np.pi * relPos2orthogonal rotations[5] = np.array([0.0, 0.0, 2 * np.pi / 5.0]) rotations[6] = np.array([0.0, 0.0, np.pi]) rotations[7] = np.array([0.0, np.pi, 0.0]) # Convert axis-angle rotations to quaternions quatRotations = [None]*8 for i in range(8): quatRotations[i] = quaternions.angle2quat(rotations[i]) # Assign correct position2 depending on the states pos2 = [None]*8 pos2[0:4] = [position1 + relpos1]*4 pos2[4:8] = [position1 + relpos2]*4 # Assign position and orientation depending on initial state A or B if state == 'A': substate = random.choice([1,2,5,6]) position2 = pos2[substate - 1] orientation2 = quatRotations[substate - 1] if state == 'B': substate = random.choice([3,4,7,8]) position2 = pos2[substate - 1] orientation2 = quatRotations[substate - 1] part1 = msmrd2.particle(D, Drot, position1, orientation1) part2 = msmrd2.particle(D, Drot, position2, orientation2) partlist = msmrd2.integrators.particleList([part1, part2]) return partlist
def generateParticleList(state, boxsize, types, unboundMSMs, randomSeed=-1): ''' Generate a random particle list of two particles corresponding to an initial unbound state. As each state has several different configurations, this functions picks one randomly. The definition of the states is taken form patchyProtein.cpp (trajectory) :param state: bound state in which the two particle list should begin in (can be a list of states) :param boxsize: size of simulation box, if scalar it assumes the three box edges are the same in all dimensions :param types: array containing the particle types. The index should correspond to that of of the particle list. :param unboundMSMs: list of unboundMSM, needed to extract diffusion coefficients of particles. :param randomSeed: seed for python random generator. Important to specify in parallel runs. Default value of -1 will use the default seed. :return: random particle list corresponding to one of the initialBoundstates. ''' # Transform boxsize to vector if neccesarry. boxsize = boxsize - 1 # to ensure the whole compund is initially inside box (1 is the norm of relpos below) if np.isscalar(boxsize): boxsize = np.array([boxsize, boxsize, boxsize]) # Transform state to list if neccesary if np.isscalar(state): state = [state] position1 = np.array([0.0, 0.0, 0.0]) orientation1 = np.array([1.0, 0.0, 0.0, 0.0]) # Define relative positions relPos = [None] * numBoundStates relPos[0] = np.array([1., 0., 0.]) relPos[1] = np.array([0., 1., 0.]) relPos[2] = np.array([0., 0., 1.]) relPos[3] = np.array([-1., 0., 0.]) relPos[4] = np.array([0., -1., 0.]) relPos[5] = np.array([0., 0., -1.]) # Define relative rotations rotations = [None] * numBoundStates rotations[0] = np.array([0.0, 0.0, np.pi]) rotations[1] = np.array([0.0, 0.0, -np.pi / 2.0]) rotations[2] = np.array([0.0, np.pi / 2.0, 0.0]) rotations[3] = np.array([0.0, 0.0, 0.0]) rotations[4] = np.array([0.0, 0.0, np.pi / 2.0]) rotations[5] = np.array([0.0, -np.pi / 2.0, 0.0]) # Convert axis-angle rotations to quaternions quatRotations = [None] * numBoundStates for i in range(numBoundStates): quatRotations[i] = quaternions.angle2quat(rotations[i]) # Assign position and orientation depending on initial bound state (between 0 and 5) substate = np.random.choice( state) # if states was originally a scalar, always picks that value. position2 = relPos[substate - 1] orientation2 = quatRotations[substate - 1] p1State = 0 p2State = 0 # Obtain diffusion coefficients from unboundMSM D1 = unboundMSMs[types[0]].D[p1State] Drot1 = unboundMSMs[types[0]].Drot[p1State] D2 = unboundMSMs[types[1]].D[p2State] Drot2 = unboundMSMs[types[1]].Drot[p2State] # Define particles part1 = msmrd2.particle(0, p1State, D1, Drot1, position1, orientation1) part2 = msmrd2.particle(1, p2State, D2, Drot2, position2, orientation2) part1.setMSMoff() #Important or it will yield error. partlist = msmrd2.integrators.particleList([part1, part2]) return partlist
def randomParticleList(numparticles, boxsize, separationDistance, D, Drot, randomSeed=-1): ''' :param numparticles: number of particles in list :param boxsize: size of simulation box, if scalar it assumes the three box edges are the same in all dimensions :param separationDistance: separation distance between particle to avoid overlapping :param D and Drot: diffusion coefficients of particles. :param randomSeed seed for python random generator. Important to specify in parallel runs. Default value of -1 will use the default seed. :return: Generates particle list with uniformly random position and orientation. It also enforces the particles don't overlap over a distance given by the relative distance cut off. ''' # Set numpy seed if provided (important when running parallel processes, otherwise not required) if randomSeed != -1: random.seed(randomSeed) #better than np.random for parallel seeding # Warning in case of not ideal parameters. if separationDistance > boxsize: warnings.warn( "The separation distance between particles should be much smaller than the " "boxsize. Otherwise risk of infinite loop.") # Transform boxsize to vector if neccesarry. if np.isscalar(boxsize): boxsize = np.array([boxsize, boxsize, boxsize]) # Create non-overlapping particle list pyPartlist = [] for i in range(numparticles): overlap = True numTrials = 0 while overlap: numTrials = numTrials + 1 position = np.array([ boxsize[0] * random.random() - 0.5 * boxsize[0], boxsize[1] * random.random() - 0.5 * boxsize[1], boxsize[2] * random.random() - 0.5 * boxsize[2] ]) overlap = False for j in range(len(pyPartlist)): if np.linalg.norm(position - pyPartlist[j].position) < separationDistance: overlap = True continue if numTrials >= 100000: warnings.warn( "Cannot easily set nonoverlapping particles with current setup. Check boxsize, " "number of particles and separation distance.") orientation = np.array([ random.random(), random.random(), random.random(), random.random() ]) orientation = orientation / np.linalg.norm(orientation) part = msmrd2.particle(D, Drot, position, orientation) part.setID(i) pyPartlist.append(part) partlist = msmrd2.integrators.particleList(pyPartlist) return partlist
def randomParticleMSList(numparticles, boxsize, separationDistance, types, unboundMSMs, randomSeed=-1): ''' :param numparticles: number of particles in list :param boxsize: size of simulation box, if scalar it assumes the three box edges are the same in all dimensions :param separationDistance: separation distance between particle to avoid overlapping :param types types of particles (can be array of integers or integer if all particles are the same) :param unboundMSMs: list of unboundMSM, needed to extract diffusion coefficients of particles. :param randomSeed seed for pyton random generator. Important to specify in parallel runs. Default value of -1 will use the default seed. :return: Generates list of particles (with Markovian switch) with uniformly random position and orientation. It also enforces the particles don't overlap over a distance given by the relative distance cut off. ''' # Set numpy seed if provided (important when running parallel processes, otherwise not required) if randomSeed != -1: random.seed(randomSeed) # Warning in case of not ideal parameters. if separationDistance > boxsize: warnings.warn( "The separation distance between particles should be much smaller than the " "boxsize. Otherwise risk of infinite loop.") # Transform boxsize, diffusion coefficients, type and state to vectors if neccesarry. if np.isscalar(boxsize): boxsize = np.array([boxsize, boxsize, boxsize]) if np.isscalar(types): newtypes = np.ones(numparticles, dtype='int') types = (types * newtypes).astype(int) # Obtain initial state randomly from all available states states = np.zeros(numparticles, dtype='int') for i in range(numparticles): maxstates = len(unboundMSMs[types[i]].D) states[i] = random.randint(0, maxstates - 1) # Create non-overlapping particle list pyPartlist = [] for i in range(numparticles): numTrials = 0 overlap = True while overlap: numTrials = numTrials + 1 position = np.array([ boxsize[0] * random.random() - 0.5 * boxsize[0], boxsize[1] * random.random() - 0.5 * boxsize[1], boxsize[2] * random.random() - 0.5 * boxsize[2] ]) overlap = False for j in range(len(pyPartlist)): if np.linalg.norm(position - pyPartlist[j].position) < separationDistance: overlap = True continue if numTrials >= 100000: warnings.warn( "Cannot easily set nonoverlapping particles with current setup. Check boxsize, " "number of particles and separation distance.") orientation = np.array([ random.random(), random.random(), random.random(), random.random() ]) orientation = orientation / np.linalg.norm(orientation) D = unboundMSMs[types[i]].D[states[i]] Drot = unboundMSMs[types[i]].Drot[states[i]] part = msmrd2.particle(types[i], states[i], D, Drot, position, orientation) part.setID(i) # Deactivate inner unbound MSM if there is only one state. if len(unboundMSMs[types[i]].D) == 1: part.deactivateMSM() pyPartlist.append(part) partlist = msmrd2.integrators.particleList(pyPartlist) return partlist
def calculateDiffusionCoefficeints(numparticles): ''' :param numparticles: must have a value between 1 and 5 :return: translational diffusion coefficeint and rotational diffusion coefficient ''' simulationSuccess = False # Define particle list with between two and five particles to estimate the diffusion # of dimers/ trimers / cuatrimers? and pentamer pyPartlist = [] # Position List for pentamer IC for i in range(numparticles): position = 0.85 * np.array([np.cos(th * i), np.sin(th * i), 0.0]) orientation = np.array([ np.cos(0.5 * (thextra - th * i)), 0, 0, np.sin(0.5 * (thextra - th * i)) ]) part = msmrd2.particle(D, Drot, position, quats.conjugate(orientation)) pyPartlist.append(part) # Create list of particles that can be read from msmrd # Note the particles in this list will be independent from the python list. partlist = msmrd2.integrators.particleList(pyPartlist) # Over-damped Langevin integrator definition #0.000005 seed = -1 #1 #-1 # Negative seed, uses random device as seed bodytype = 'rigidbody' integrator = odLangevin(dt, seed, bodytype) # Define Patchy Particle potential if numparticles > 1: potentialPatchyParticleAngular2 = patchyParticleAngular2( sigma, strength, angularStrength, patchesCoordinates) integrator.setPairPotential(potentialPatchyParticleAngular2) # Define arrays to calculate autocorrelation functions pentamerPositionArray = [] pentamerOrientationArray = [] #Integrate particle list and print only positions cross = [None] * 2 if outputVMD: datafile = open('../../data/vmd/pentamerTest.xyz', 'w') for i in range(timesteps): if i % stride == 0: if outputVMD: datafile.write(str(3 * len(partlist) + 3) + '\n') datafile.write(str(0) + '\n') if numparticles == 1: pentamerPositionArray.append(partlist[0].position) pentamerOrientationArray.append(partlist[0].orientation) else: # Calculate and plot center of pentamer position relpos = partlist[1].position - partlist[0].position relposnorm = np.linalg.norm(relpos) if (relposnorm >= 1.5): return simulationSuccess, 0, 0 relpos = relpos / relposnorm patch1 = 0.5 * sigma * quats.rotateVec(patchesCoordinates[0], partlist[0].orientation) patch2 = 0.5 * sigma * quats.rotateVec(patchesCoordinates[1], partlist[0].orientation) cross[0] = np.cross(relpos, patch1) cross[1] = np.cross(relpos, patch2) maxIndex = np.argmax(np.linalg.norm(cross, axis=1)) rotAxis = cross[maxIndex] / np.linalg.norm(cross[maxIndex]) rotation = 3 * np.pi * rotAxis / 10.0 quatRotation = quats.angle2quat(rotation) pentamerCenter = 0.85 * quats.rotateVec(relpos, quatRotation) pentamerCenter = pentamerCenter + partlist[0].position pentamerPositionArray.append(pentamerCenter) # Calculate and plot orientation of pentamer (using only the orientation of particle 0) orientation0 = np.array( [np.cos(0.5 * (thextra)), 0, 0, np.sin(0.5 * (thextra))]) vec1 = 0.85 * np.array( [1., 0., 0.]) + 0.5 * sigma * quats.rotateVec( patchesCoordinates[0], orientation0) vec2 = 0.85 * np.array( [1., 0., 0.]) + 0.5 * sigma * quats.rotateVec( patchesCoordinates[1], orientation0) rotVec1 = partlist[0].position + 0.5 * sigma * quats.rotateVec( patchesCoordinates[0], partlist[0].orientation) rotVec2 = partlist[0].position + 0.5 * sigma * quats.rotateVec( patchesCoordinates[1], partlist[0].orientation) pentamerOrientation = quats.recoverRotationFromVectors(np.array([0.,0.,0.]), vec1, vec2, \ pentamerCenter, rotVec1, rotVec2) pentamerOrientationArray.append(pentamerOrientation) if outputVMD: # Calculate cross reference v0 = pentamerCenter v1 = v0 + 0.25 * quats.rotateVec(refVec4, pentamerOrientation) v2 = v0 + 0.25 * quats.rotateVec(refVec5, pentamerOrientation) # Plot cross reference datafile.write('type_2' + ' ' + ' '.join(map(str, v0)) + '\n') datafile.write('type_3' + ' ' + ' '.join(map(str, v1)) + '\n') datafile.write('type_3' + ' ' + ' '.join(map(str, v2)) + '\n') if outputVMD: for j, part in enumerate(partlist): if i % stride == 0: v0 = part.position v1 = v0 + 0.5 * sigma * quats.rotateVec( patchesCoordinates[0], part.orientation) v2 = v0 + 0.5 * sigma * quats.rotateVec( patchesCoordinates[1], part.orientation) datafile.write('type_0' + ' ' + ' '.join(map(str, v0)) + '\n') datafile.write('type_1' + ' ' + ' '.join(map(str, v1)) + '\n') datafile.write('type_1' + ' ' + ' '.join(map(str, v2)) + '\n') integrator.integrate(partlist) if i % 10000 == 0: print("Percentage complete: ", 100 * i / timesteps, "%", end="\r") if outputVMD: datafile.close() # Generate TCL script to visualize with VMD msmrdvis.generateTCL_pentamerTest( numparticles=numparticles, outfname='pentamerTest', tclfname='../../data/vmd/pentamerTest_2vmd.tcl') print("Simulation complete: ", 100, " % w/", numparticles, " particles") # Calculate auto-correlation/mean-square displacement for several lagtimes tsteps = len(pentamerPositionArray) lagtimesIndexes = np.arange(100, 2000, 100) #np.arange(1,20,1) lagtimes = np.zeros(len(lagtimesIndexes) + 1) MSD_3D = np.zeros(len(lagtimesIndexes) + 1) MSD_3D_orientation = np.zeros(len(lagtimesIndexes) + 1) for i, lagtimeIndex in enumerate(lagtimesIndexes): lagtimes[i + 1] = dt * lagtimeIndex * stride MSD = 0.0 MSD_orientation = 0.0 for j in range(tsteps - lagtimeIndex): dr = pentamerPositionArray[j + lagtimeIndex] - pentamerPositionArray[j] dq = pentamerOrientationArray[ j + lagtimeIndex] - pentamerOrientationArray[j] MSD += dr * dr MSD_orientation += dq * dq MSD = MSD / (tsteps - lagtimeIndex + 1) MSD_3D[i + 1] = sum(MSD) # D = sum(MSD)/(6*lagtime) MSD_orientation = MSD_orientation / (tsteps - lagtimeIndex + 1) MSD_3D_orientation[i + 1] = sum(MSD_orientation[1:]) # Least square approximation with numpy A = np.vstack([lagtimes, np.ones(len(lagtimes))]).T slope, b = np.linalg.lstsq(A, MSD_3D / 6, rcond=None)[0] #print(slope,b) # Least square approximation with numpy (rotation) y = -np.log(1 - 4 * MSD_3D_orientation / 3.0) / 2 slope2, b2 = np.linalg.lstsq(A, y, rcond=None)[0] #print(slope2,b2) print("Estimated diffusion coefficients") # Plot MSD against lagtime and fits plt.plot(lagtimes, MSD_3D / 6, 'o', label='position') plt.plot(lagtimes, -np.log(1 - 4 * MSD_3D_orientation / 3.0) / 2, 'o', label='orientation') plt.plot(lagtimes, slope * lagtimes + b, '-', label='position fit') plt.plot(lagtimes, slope2 * lagtimes + b2, '-', label='orientation fit') plt.legend() plt.savefig(Diffdirectory + 'diffusionFitPentamer_' + str(numparticles) + 'particles.pdf', bbox_inches='tight') plt.close() print("Finished plots") Dapprox = slope DrotApprox = slope2 simulationSuccess = True return simulationSuccess, Dapprox, DrotApprox
import msmrd2 as m import numpy as np assert m.__version__ == '0.0.1' assert m.add(1, 2) == 3 assert m.subtract(1, 2) == -1 particles = [] for i in range(10): particles.append( m.particle(i, 1, 2., 3., np.random.rand(4), np.random.rand(3))) sim = m.simulation(particles) sim.run(0.1, 100)
def generateParticleList(state, boxsize, types, couplingMSM, randomSeed=-1): ''' Generate a random particle list of two particles corresponding to either state A or state B. As each state has several different configurations, this functions picks one randomly. The definition of the states is taken form patchyDimer.cpp :param state: bound state in which the two particle list should be in, A or B :param boxsize: size of simulation box, if scalar it assumes the three box edges are the same in all dimensions :param couplingMSM: MSM for MSM/RD, needed to extract diffusion coefficients of particles. :param randomSeed: seed for python random generator. Important to specify in parallel runs. Default value of -1 will use the default seed. :return: random particle list corresponding to either state A or state B. ''' # Transform boxsize and type to vector if neccesary. boxsize = boxsize - 1 # to ensure the whole compund is initially inside box (1 is the norm of relpos below) if np.isscalar(boxsize): boxsize = np.array([boxsize, boxsize, boxsize]) if np.isscalar(types): newtypes = np.ones(2, dtype='int') types = (types * newtypes).astype(int) position1 = np.array([0.0, 0.0, 0.0]) #position1 = np.array([boxsize[0]*random.random()-0.5*boxsize[0], # boxsize[1]*random.random()-0.5*boxsize[1], # boxsize[2]*random.random()-0.5*boxsize[2]]) orientation1 = np.array([1.0, 0.0, 0.0, 0.0]) # Define relative position relpos1 = np.array([np.cos(angleDiff / 2.0), np.sin(angleDiff / 2.0), 0]) relpos2 = np.array( [np.cos(angleDiff / 2.0), np.sin(-1 * angleDiff / 2.0), 0]) relPos1orthogonal = np.array( [-1.0 * np.sin(angleDiff / 2.0), np.cos(angleDiff / 2.0), 0.0]) relPos2orthogonal = np.array( [np.sin(angleDiff / 2.0), np.cos(angleDiff / 2.0), 0.0]) # Define relative rotations rotations = [None] * 8 rotations[0] = np.pi * relPos1orthogonal rotations[1] = np.array([0.0, 0.0, -2 * np.pi / 5.0]) rotations[2] = np.array([0.0, 0.0, np.pi]) rotations[3] = np.array([0.0, np.pi, 0.0]) # --first 4 rotations correspond to binding on top patch of particle 1, next 4 rotations to bottom patch rotations[4] = np.pi * relPos2orthogonal rotations[5] = np.array([0.0, 0.0, 2 * np.pi / 5.0]) rotations[6] = np.array([0.0, 0.0, np.pi]) rotations[7] = np.array([0.0, np.pi, 0.0]) # Convert axis-angle rotations to quaternions quatRotations = [None] * 8 for i in range(8): quatRotations[i] = quaternions.angle2quat(rotations[i]) # Assign correct position2 depending on the states pos2 = [None] * 8 pos2[0:4] = [position1 + relpos1] * 4 pos2[4:8] = [position1 + relpos2] * 4 # Assign position and orientation depending on initial state A or B substate = 0 if state == 'A': substate = random.choice([1, 2, 5, 6]) position2 = pos2[substate - 1] orientation2 = quatRotations[substate - 1] if state == 'B': substate = random.choice([3, 4, 7, 8]) position2 = pos2[substate - 1] orientation2 = quatRotations[substate - 1] # Obtain diffusion coefficients from unboundMSM Dbound = couplingMSM.D[substate - 1] DrotBound = couplingMSM.Drot[substate - 1] # Define particles part1 = msmrd2.particle(types[0], -1, Dbound, DrotBound, position1, orientation1) part2 = msmrd2.particle(types[1], -1, 0., 0., position2, orientation2) # Set up bound particles as if done by the code (deactivate one of them) part1.setBoundState(substate) part2.setBoundState(substate) part1.setBoundTo(1) part2.setBoundTo(0) part1.deactivateMSM() part2.deactivateMSM() part2.deactivate() part2.setPosition([10000000.0, 10000000.0, 10000000.0]) partlist = msmrd2.integrators.particleList([part1, part2]) return partlist