def simulator(oriConc = 10, # the max concentration released from the source of chemoattractant cellConc = 1, # the max concentration released by cells (determining the degree of intercellular communication) Diff = 10, # the diffusion rate of chemoattractant kd = 10, # constant associated with Hills coefficient for autocrinic release DispScale = 100000, # Displacement Scale ... wrong name I guess searchingRange = 0.1, # searching range around the cell numOfCells1 = 50, # a total number of cells in the 1st section of simulation box numOfCells2 = 50, # a total number of cells in the 2nd section of simulation box CentoR = None, # this will determine the size of 1st section of simulation box in x axis pdbFileName = 'temp', # generated PDB file name dcdfilename = 'test_output2', # generated DCD file name lowlimBoxlen =0, # in angstrom = 1/10 of nanometer (REMEMBER!!) ??? do I need this? highlimBoxlen =1000, # in angstrom = 1/10 of nanometer (REMEMBER!!) simLength = 10000, # a total number of the simulation steps dumpSize = 100, # dump size in the dcd generation process restingRatio1 = 0.8, # the proportion of resting cells in the overall population of cells in the 1st section restingRatio2 = 0.8, # the proportion of resting cells in the overall population of cells in the 2nd section restMig = 0.5, # the degree of migratory response of resting cells actMig = 0.1, # the degree of migratory response of activated cells restAuto = 10, # the degree of autocrinic release of resting cells: the larger, the less insensitive actAuto = 0.1, # the degree of autocrinic release of activated cells shape = 'slab', # shape of simulation box: either slab or square DiffState = 'steady', # the characteristics of diffusion of chemoattractant: steady, error, or linear NoParticleZone = None, cellPerdead = 50, stateVar = 'on', placement = 'far' ): # This will generate the random structure that makes no sence but will be processed again ## Note: This will generate dummy pdb file that will pass the test run but it is irrelevant to the actual calculation. if cellPerdead > 0: num_dead_cell_core = 50 #num_dead_cell_core = round((numOfCells1+numOfCells2)/cellPerdead) dead_cell = np.random.randint(150,200, size=(num_dead_cell_core)) elif cellPerdead == 0: num_dead_cell_core = 1 dead_cell = [1] num_dead_cell = np.sum(dead_cell) calc.PDBgenNoPBC(pdbFileName, numOfCells1, numOfCells2, restingRatio1, restingRatio2, num_dead_cell, num_dead_cell_core) # Dead cell must be placed in here first pdb = PDBFile(pdbFileName+'.pdb') # Configure Dumping frequency dumpingstep = dumpSize dcdReporter = DCDReporter(dcdfilename+'.dcd', dumpingstep) # Simulation Box Dimension in angstrom ## Slab case if shape == 'slab': shape_factor = 10 # What where this goes to. dummy = (np.int(highlimBoxlen*shape_factor))/(10) OriginOfExternalSignal = [dummy,0,0] # in nanometer # This indicates the far end of X-axis ## Square case elif shape == 'square': shape_factor = 1 dummy = (np.int(highlimBoxlen))/(10) OriginOfExternalSignal = [dummy/2,dummy/2,0] # This indicates the center of simulation box # Defining the dimension of simulation box x = [lowlimBoxlen,highlimBoxlen*shape_factor] y = [lowlimBoxlen,highlimBoxlen] z = [0,0] highBC = np.array([x[1],y[1],z[1]]) # Configure Simulation Length Repeat = simLength stepFreq = 1 # Parameters determining the dynamics of cells MassOfCell = 50 MassOfDead = 1000 RepulsiveScale = 0.05 # this can determine the distance among cells themselves RepulsiveScaleDead = 0.15 ### Simulation parameters temperature = 1.0 #0.0 # K <---- set to 0 to get rid of wiggling for now frictionCoeff = 1.0 # 1/ps step_size = 0.002 # ps ########################################################## ### OpenMM Simulation Control ### ########################################################## # Create an OpenMM System object system = System() # Create CustomNonbondedForce. We use it to implement repulsive potential between particles. # Only keep repulsive part of L-J potential #nonbond = CustomNonbondedForce("(sigma/r)^12; sigma=0.5*(sigma1+sigma2)") nonbond = CustomNonbondedForce("(sigma/r)^12-delta*(sigma/r)^6; sigma=0.5*(sigma1+sigma2); delta=0.5*(delta1+delta2)") nonbond.addPerParticleParameter("sigma") nonbond.addPerParticleParameter("delta") # Here we don't use cutoff for repulsive potential, but adding cutoff might speed things up a bit as interaction # strength decays very fast. #nonbond.setNonbondedMethod(CustomNonbondedForce.NoCutoff) nonbond.setCutoffDistance(9) # Add force to the System system.addForce(nonbond) # FeedInForce is an OpenMM Force object that serves as the interface to feed forces into the simulation. It stores # additional forces that we want to introduce internally and has a method # .updateForceInContext(OpenMM::Context context, vector< vector<double> > in_forces). in_forces should be a vector of # 3d vectors - one 3d vector per particle and each 3d vector should contain X,Y,Z components of the force. # updateForceInContext() will copy forces from in_forces into internal variable that will keep them # until updateForceInContext() is called again. Every simulation step OpenMM will add forces stored in FeedInForce to # the simulation. You don't need to call updateForceInContext() every step if the forces didn't change - OpenMM will # use the forces from the last call of updateForceInContext(). in_force = FeedInForce() # Add in_force to the system system.addForce(in_force) num_particles = len(pdb.getPositions()) ### Make it 2D energy_expression = 'k * (z^2)' force = openmm.CustomExternalForce(energy_expression) force.addGlobalParameter('k', 999) for particle_index in range(num_particles): force.addParticle(particle_index, []) system.addForce(force) ## This will generate more reasonable structure but still needs to take number of particle from the arbitrary structure ## The reason I choose to do so is generating PDB file is little tricky due to its sensitivity to line arrangement min_dist_among_cells = 2.5 xlow_end = x[0] xhigh_end = x[1] ylow_end = y[0] yhigh_end = y[1] ''' [Outcomes of genCellCoord3D] initPosInNm: coordnates of cells in array format (num_particles by [x,y,z]) marker: a list of markers for resting and activated cells (length of num_particles) migration_factor: a list of constants for migration degree for resting and activated (length of num_particles) autocrine_factor: a list of constants for autocrinic degree for resting and activated (lengh of num_particles) ''' initPosInNm, marker, mig_factor, auto_factor, Cell_Constitution = calc.genCellCoord3D(numOfCells1, numOfCells2, dead_cell, min_dist_among_cells, CentoR, xlow_end, xhigh_end, ylow_end, yhigh_end, restingRatio1, restingRatio2, restMig, actMig, restAuto, actAuto, shape_factor, NoParticleZone, placement) DeadCellRef1 = Cell_Constitution['Dead'] for i in range(num_particles): if i <= DeadCellRef1: system.addParticle(MassOfDead) sigma = RepulsiveScaleDead delta = 1 nonbond.addParticle([sigma,delta]) #nonbond.addParticle([sigma]) else: # Populate the system with particles. # system.addParticle(mass in atomic mass units) system.addParticle(MassOfCell) # 100.0 is a particle mass # Add particles to CustomNonbondedForce. Here we define repulsion strength sigma for each particle. If particles # have different value of sigma, combination rule sigma=0.5*(sigma1+sigma2) will be applied as defined in # CustomNonbondedForce force expression. sigma = RepulsiveScale delta = 0 nonbond.addParticle([sigma,delta]) #nonbond.addParticle([sigma]) # Create integrator integrator = BrownianIntegrator(temperature, frictionCoeff, step_size) # Create platform platform = Platform.getPlatformByName('CUDA') # Create simulation simulation = Simulation(pdb.topology, system, integrator, platform) print('Simulation is initiated') print('REMARK Using OpenMM platform %s' % simulation.context.getPlatform().getName()) # Set initial positions for the particles simulation.context.setPositions(initPosInNm) # Simulate # We can add dcd or other reporters to the simulation to get desired output with ## Note: Ben's version simulation.reporters.append(dcdReporter) time = 0.001 # <----- can't start at 0; Otherwise, the calculation blows up ## Set the initial stateVariable: Starting from 0 for now. #odeiter = 5 live_num_cells = numOfCells1 + numOfCells2 stateVariable = np.ones([live_num_cells]) positions = simulation.context.getState(getPositions=True).getPositions() print("|------ calibration initiated -----|") for num_iter in range(1, 10000): ### What is this? positions = simulation.context.getState(getPositions=True).getPositions() simulation.step(stepFreq) state = simulation.context.getState(getEnergy=True, getForces=True) time += stepFreq print("|----- simulation initiated -----|") time_state = 1e-14 Ix = np.ones(live_num_cells) Iy = np.ones(live_num_cells) DMx = np.zeros(live_num_cells) DMy = np.zeros(live_num_cells) UMx = np.zeros(live_num_cells) UMy = np.zeros(live_num_cells) odes = {'Ix': Ix, 'Iy': Iy, 'DMx': DMx, 'DMy': DMy, 'UMx': UMx, 'UMy': UMy} dummy_force_x = [] for num_iter in range(1, Repeat): ### What is this? positions = simulation.context.getState(getPositions=True).getPositions() # forces_vec will contain external forces that we want to feed into OpenMM. # Get current positions of the particles for concentration field/forces calculation ################################################################################################################## ### Where All the Magical Things Happen ### ################################################################################################################## if num_iter == 1: ConcByCell = np.zeros(live_num_cells) + 1e-14 fvX, fvY, fvZ, ConcbyCell, odes, ConcbyOrigin = calc.calcForce(positions, live_num_cells, DeadCellRef1, OriginOfExternalSignal, oriConc, cellConc, Diff, time_state, kd, highBC, DispScale, searchingRange, marker, auto_factor, DiffState, ConcByCell, odes, step_size, shape_factor) stateVariable, stateDepFactor = calc.calcStateVariable(live_num_cells, time_state, ConcbyCell, stateVariable) forces_vec = calc.calcForceModified(num_particles, DeadCellRef1, fvX, fvY, fvZ, stateDepFactor, mig_factor, stateVar) #print(forces_vec[1]) # Feed external forces into OpenMM in_force.updateForceInContext(simulation.context, forces_vec) # Advance simulation for 1 steps simulation.step(stepFreq) state = simulation.context.getState(getEnergy=True, getForces=True) time += stepFreq time_state += stepFreq #plt.plot(range(1,Repeat),dummy_force_x) #plt.savefig("force.png") #print(ConcbyOrigin) if state == 'steady': print('from ',num_particles,' of cells, total of ',np.sum(ConcbyOrigin),' is being released by Cells with given conditions')
def simulator( oriConc=10, # the max concentration released from the source of chemoattractant cellConc=1, # the max concentration released by cells (determining the degree of intercellular communication) Diff=10, # the diffusion rate of chemoattractant kd=10, # constant associated with Hills coefficient for autocrinic release DispScale=100000, # Displacement Scale ... wrong name I guess searchingRange=0.1, # searching range around the cell numOfCells1=50, # a total number of cells in the 1st section of simulation box numOfCells2=50, # a total number of cells in the 2nd section of simulation box CentoR=0, # this will determine the size of 1st section of simulation box in x axis pdbFileName='temp', # generated PDB file name dcdfilename='test_output2', # generated DCD file name lowlimBoxlen=0, # in angstrom = 1/10 of nanometer (REMEMBER!!) ??? do I need this? highlimBoxlen=1000, # in angstrom = 1/10 of nanometer (REMEMBER!!) SourceOfOrigin=None, # None = One end of simulation box in x axis, Center = the center of simulation box simLength=10000, # a total number of the simulation steps dumpSize=100, # dump size in the dcd generation process restingRatio1=0.8, # the proportion of resting cells in the overall population of cells in the 1st section restingRatio2=0.8, # the proportion of resting cells in the overall population of cells in the 2nd section restMig=0.5, # the degree of migratory response of resting cells actMig=0.1, # the degree of migratory response of activated cells restAuto=10, # the degree of autocrinic release of resting cells: the larger, the less insensitive actAuto=0.1, # the degree of autocrinic release of activated cells shape='slab', # shape of simulation box: either slab or square DiffState='steady' # the characteristics of diffusion of chemoattractant: steady, error, or linear ): # This will generate the random structure that makes no sence but will be processed again ## Note: This will generate dummy pdb file that will pass the test run but it is irrelevant to the actual calculation. calc.PDBgenNoPBC(pdbFileName, numOfCells1, numOfCells2, restingRatio1, restingRatio2) pdb = PDBFile(pdbFileName + '.pdb') # Configure Dumping frequency dumpingstep = dumpSize dcdReporter = DCDReporter(dcdfilename + '.dcd', dumpingstep) # Simulation Box Dimension in angstrom if shape == 'slab': shape_factor = 3 elif shape == 'square': shape_factor = 1 ## Configure the coordinate of origin of external signal cascades if SourceOfOrigin is None: dummy = (np.int(highlimBoxlen * shape_factor)) / (10) OriginOfExternalSignal = [dummy, 0, 0] # in nanometer elif SourceOfOrigin == 'Center': dummy = (np.int(highlimBoxlen)) / (10) OriginOfExternalSignal = [dummy * shape_factor / 2, dummy / 2, 0] # Defining the dimension of simulation box x = [lowlimBoxlen, highlimBoxlen * shape_factor] y = [lowlimBoxlen, highlimBoxlen] z = [0, 0] highBC = np.array([x[1], y[1], z[1]]) # Configure Simulation Length Repeat = simLength stepFreq = 1 # Parameters determining the dynamics of cells MassOfCell = 100 RepulsiveScale = 0.01 # this can determine the distance among cells themselves ### Simulation parameters temperature = 295 #0.0 # K <---- set to 0 to get rid of wiggling for now frictionCoeff = 1.0 # 1/ps step_size = 0.002 # ps ########################################################## ### OpenMM Simulation Control ### ########################################################## # Create an OpenMM System object system = System() # Create CustomNonbondedForce. We use it to implement repulsive potential between particles. # Only keep repulsive part of L-J potential nonbond = CustomNonbondedForce("(sigma/r)^12; sigma=0.5*(sigma1+sigma2)") nonbond.addPerParticleParameter("sigma") # Here we don't use cutoff for repulsive potential, but adding cutoff might speed things up a bit as interaction # strength decays very fast. nonbond.setNonbondedMethod(CustomNonbondedForce.NoCutoff) # Add force to the System system.addForce(nonbond) # FeedInForce is an OpenMM Force object that serves as the interface to feed forces into the simulation. It stores # additional forces that we want to introduce internally and has a method # .updateForceInContext(OpenMM::Context context, vector< vector<double> > in_forces). in_forces should be a vector of # 3d vectors - one 3d vector per particle and each 3d vector should contain X,Y,Z components of the force. # updateForceInContext() will copy forces from in_forces into internal variable that will keep them # until updateForceInContext() is called again. Every simulation step OpenMM will add forces stored in FeedInForce to # the simulation. You don't need to call updateForceInContext() every step if the forces didn't change - OpenMM will # use the forces from the last call of updateForceInContext(). in_force = FeedInForce() # Add in_force to the system system.addForce(in_force) num_particles = len(pdb.getPositions()) ### Make it 2D energy_expression = 'k * (z^2)' force = openmm.CustomExternalForce(energy_expression) force.addGlobalParameter('k', 999) for particle_index in range(num_particles): force.addParticle(particle_index, []) system.addForce(force) ## This will generate more reasonable structure but still needs to take number of particle from the arbitrary structure ## The reason I choose to do so is generating PDB file is little tricky due to its sensitivity to line arrangement min_dist_among_cells = 5 xlow_end = x[0] xhigh_end = x[1] ylow_end = y[0] yhigh_end = y[1] ''' [Outcomes of genCellCoord3D] initPosInNm: coordnates of cells in array format (num_particles by [x,y,z]) marker: a list of markers for resting and activated cells (length of num_particles) migration_factor: a list of constants for migration degree for resting and activated (length of num_particles) autocrine_factor: a list of constants for autocrinic degree for resting and activated (lengh of num_particles) ''' initPosInNm, marker, mig_factor, auto_factor = calc.genCellCoord3D( numOfCells1, numOfCells2, min_dist_among_cells, CentoR, xlow_end, xhigh_end, ylow_end, yhigh_end, restingRatio1, restingRatio2, restMig, actMig, restAuto, actAuto) for i in range(num_particles): # Populate the system with particles. # system.addParticle(mass in atomic mass units) system.addParticle(MassOfCell) # 100.0 is a particle mass # Add particles to CustomNonbondedForce. Here we define repulsion strength sigma for each particle. If particles # have different value of sigma, combination rule sigma=0.5*(sigma1+sigma2) will be applied as defined in # CustomNonbondedForce force expression. sigma = RepulsiveScale nonbond.addParticle([sigma]) # Create integrator integrator = BrownianIntegrator(temperature, frictionCoeff, step_size) # Create platform platform = Platform.getPlatformByName('CUDA') # Create simulation simulation = Simulation(pdb.topology, system, integrator, platform) print('Simulation is initiated') print('REMARK Using OpenMM platform %s' % simulation.context.getPlatform().getName()) # Set initial positions for the particles simulation.context.setPositions(initPosInNm) # Simulate # We can add dcd or other reporters to the simulation to get desired output with ## Note: Ben's version simulation.reporters.append(dcdReporter) time = 0.001 # <----- can't start at 0; Otherwise, the calculation blows up ## Set the initial stateVariable: Starting from 0 for now. #odeiter = 5 stateVariable = np.ones([num_particles]) # storing initial position rest_cell_no = int(numOfCells1 * restingRatio1) + int( numOfCells2 * restingRatio2) + 2 act_cell_no = num_particles - rest_cell_no resting_start = np.zeros([2, rest_cell_no]) activated_start = np.zeros([2, act_cell_no]) positions = simulation.context.getState(getPositions=True).getPositions() rest_cnt = 0 act_cnt = 0 cell_cnt = 0 for pos in enumerate(positions): if marker[cell_cnt] == 'resting': resting_start[0][rest_cnt] = pos[1][0].value_in_unit(angstroms) resting_start[1][rest_cnt] = pos[1][1].value_in_unit(angstroms) rest_cnt += 1 elif marker[cell_cnt] == 'activated': activated_start[0][act_cnt] = pos[1][0].value_in_unit(angstroms) activated_start[1][act_cnt] = pos[1][1].value_in_unit(angstroms) act_cnt += 1 cell_cnt += 1 print("|------ calibration initiated -----|") for num_iter in range(1, 5000): ### What is this? positions = simulation.context.getState( getPositions=True).getPositions() simulation.step(stepFreq) state = simulation.context.getState(getEnergy=True, getForces=True) time += stepFreq print("|----- simulation initiated -----|") time_state = 1e-14 for num_iter in range(1, Repeat): ### What is this? positions = simulation.context.getState( getPositions=True).getPositions() # forces_vec will contain external forces that we want to feed into OpenMM. # Get current positions of the particles for concentration field/forces calculation ################################################################################################################## ### Where All the Magical Things Happen ### ################################################################################################################## if num_iter == 1: ConcByCell = np.zeros(num_particles) + 1e-14 fvX, fvY, fvZ, ConcbyCell = calc.calcForce( positions, num_particles, OriginOfExternalSignal, SourceOfOrigin, oriConc, cellConc, Diff, time_state, kd, highBC, DispScale, searchingRange, marker, auto_factor, DiffState, ConcByCell) #print(ConcbyCell[1]) stateVariable, stateDepFactor = calc.calcStateVariable( num_particles, time_state, ConcbyCell, stateVariable) if num_iter == 1: print('#********* The Beginning **********#') print(fvX[1], fvY[1]) elif num_iter == Repeat - 1: print('#********* The Ending **********#') print(fvX[1], fvY[1]) forces_vec = calc.calcForceModified(num_particles, fvX, fvY, fvZ, stateDepFactor, mig_factor) #print(forces_vec[1]) # Feed external forces into OpenMM in_force.updateForceInContext(simulation.context, forces_vec) # Advance simulation for 1 steps simulation.step(stepFreq) state = simulation.context.getState(getEnergy=True, getForces=True) time += stepFreq time_state += stepFreq