diff --git a/analysis/MCsim.py b/analysis/MCsim.py index 5f981775..fceabf07 100644 --- a/analysis/MCsim.py +++ b/analysis/MCsim.py @@ -23,6 +23,7 @@ Trial* Trajectory* Snapshot* + Chain* * can have multiple instances --------------- @@ -51,6 +52,13 @@ # we want to look at the end-to-end distance of the snapshot at "time point" 9 of the second trajetory in "trial2" dat.trials['trial2'].trajectories[2].snapshots[9].end_to_end # get end-to-end distance + +---- +TODO +---- +fix interpolation code, it works reasonably but still not perfect for fractional basepairs +micro C analysis? +more analysis functions for interaction geoemetry """ import sys from .utility import * @@ -111,7 +119,6 @@ def __init__(self, path_to_data = "%s/data/" %(default_dir), trials = [''], traj self.trials[trial] = Trial("%s%s" %(self.path_to_data, trial), time_min, time_max, trajectories, channel) print('read in %s' %(str(trial))) - self.linearizeSnapshots() # remove intermediary data structures if they do not exist self.unnest() @@ -136,16 +143,6 @@ def returnSnapshots(self): tempDict[i][j] = self.trials[i].trajectories[j].snapshots.keys() return tempDict - def linearizeSnapshots(self): - """Append all `Snapshot` objects from all `Trajectory` and `Trial` classes into the `Simulation` - object to gather metrics all at once.""" - self.linearized_snapshots = [] - snapshots=self.returnSnapshots() - for i in snapshots.keys(): - for j in snapshots[i]: - for k in snapshots[i][j]: - self.linearized_snapshots.append(self.trials[i].trajectories[j].snapshots[k]) - def unnest(self): """Remove unnecessary nesting of objects, i.e. if there is 1 `Trial` but 2 `Trajectory` classes, have the `Trajectory` objects reachable from the main `Simulation` object.""" @@ -160,42 +157,13 @@ def unnest(self): self.snapshots = {} for i in snapshots['']['']: self.snapshots[i] = self.trials[''].trajectories[''].snapshots[i] + # add trajectories reference for easy access to making pymol movies + self.trajectories = self.trials[''].trajectories elif '' not in trials: for i in trials: if '' in trajectories[i]: self.trials[i] = self.trials[i].trajectories[''] - def getCenterBeads(self): - """Find the center of each bead positon's volume for each `Snapshot` in `linearized_snapshots`. - See the centerBeads method in the `Snapshot` class for more informtion on the calculation.""" - for i in self.linearized_snapshots: - i.centerBeads() - - def getPairwiseNucleosomeDistance(self): - """Find the pairwise distances of each center of a nucleosome bead for each `Snapshot` in `linearized_snapshots`. - See the pairwiseNucleosomeDistance method in the `Snapshot` class for more informtion on the calculation.""" - for i in self.linearized_snapshots: - i.pairwiseNucleosomeDistance() - - def getReducedPairwiseNucleosomeDistance(self): - """Find the reduced pairwise distances of each center of a nucleosome bead for each `Snapshot` in `linearized_snapshots`. - See the reducedPairwiseNucleosomeDistance method in the `Snapshot` class for more informtion on the calculation.""" - for i in self.linearized_snapshots: - i.reducedPairwiseNucleosomeDistance() - - def getInterpolate(self): - """Interpolate the helical nature of DNA (to single basepair resolution) onto the coarse-grained bead positions for - each `Snapshot` in `linearized_snapshots`. - See the interpolate method in the `Snapshot` class for more informtion on the calculation.""" - for i in self.linearized_snapshots: - i.interpolate() - - def getRICCbreak(self): - """Generate the RICC-seq break patterns from the interpolated structures for each `Snapshot` in `linearized_snapshots`. - See the RICCbreak method in the `Snapshot` class for more informtion on the calculation.""" - for i in self.linearized_snapshots: - i.RICCbreak() - class Trial: """ `Trial` object to store all the different parameter/condition settings if you want to analyze several different @@ -292,7 +260,7 @@ def __init__(self, path_to_data, time_min, time_max, channel, temperature = None self.snapshots = {} # snapshots stats self.end_to_end = [] - self.reduced_pair_nucs = [] + self.reduced_pair_dist = [] self.temperature = temperature if (self.temperature != None): nodes = np.loadtxt(self.path_to_data+'nodeNumber') @@ -308,29 +276,15 @@ def setEquilibriumTime(self,time): """Set an "equilibrium" time after which "time point" you accept all succeeding snapshots to be equilibriated""" self.equilibrium_time = time - def getEndToEnd(self): - """Find the end-to-end distance of the polymer for each `Snapshot` in the `Trajectory`. - References the end_to_end field in the `Snapshot` class for more informtion on the calculation.""" - for time in range(self.equilibrium_time,self.time_max): - self.end_to_end.append(self.snapshots[time].end_to_end) def getEnergies(self): - """Determine the energetics of the polymer for each `Snapshot` in the `Trajectory`. + """Determine the energetics of the polymer(s) for each `Snapshot` in the `Trajectory`. References the energies field in the `Snapshot` class for more informtion on the calculation.""" self.energies = self.snapshots[self.equilibrium_time].energies for time in range(self.equilibrium_time+1,self.time_max): self.energies = self.energies.append(self.snapshots[time].energies) - def getReducedPairwiseNucleosomeDistance(self): - """Find the reduced pairwise distances of each center of a nucleosome bead for each `Snapshot` in the `Trajectory`. - See the reducedPairwiseNucleosomeDistance method in the `Snapshot` class for more informtion on the calculation.""" - for time in range(self.equilibrium_time,self.time_max): - self.snapshots[time].reducedPairwiseNucleosomeDistance() - self.reduced_pair_nucs.append(self.snapshots[time].reduced_pair_nucs) - nnuc = self.snapshots[time].n_nucs # assume all snapshots have the same number of nucleosomes - self.reduced_pair_nucs = np.asarray(self.reduced_pair_nucs).reshape([self.time_max-self.equilibrium_time,nnuc-1]) - - def playFineMovie(self,path=default_dir+'/analysis/pdb/',topo='linear',pymol='pymol'): + def playFineMovie(self,path=default_dir+'/analysis/pdb/',topo='linear',pymol='pymol',base=3): """Play PyMol movie of the polymer throughout the simulation "timecourse" after interpolating into a more fine-grained structure. See the saveFineGrainedPDB and interpolate methods in the `Snapshot` class for more informtion on the calculations. @@ -349,9 +303,9 @@ def playFineMovie(self,path=default_dir+'/analysis/pdb/',topo='linear',pymol='py exectable command to initiaite PyMol, i.e. "~/Applications/pymol/pymol" """ for time in range(self.time_min,self.time_max): - self.snapshots[time].saveFineGrainedPDB(path=path,topo=topo) + self.snapshots[time].saveFineGrainedPDB(path=path,topo=topo,base=base) os.system(pymol + " -r "+default_dir+"/analysis/movieFine.py -- " - + str(self.time_max-self.time_min) + " " + path) + + str(self.time_max-self.time_min) + " " + str(self.channel[-1]) + " " + path + " " + str(base)) def playCoarseMovie(self, path = default_dir+'/analysis/pdb/', topo = 'linear', pymol = 'pymol', sphere_radius = 0, show_hull = True): """Play PyMol movie of the polymer throughout the simulation "timecourse" visualizing the excluded volume of the chain. @@ -375,7 +329,7 @@ def playCoarseMovie(self, path = default_dir+'/analysis/pdb/', topo = 'linear', set what size radius to visualize a confining sphere, where 0 equates to no confinement show_hull : boolean, optional default : True - whether to construct the hulls of the excluded volume of the fiber or not + whether to construct the hulls of the excluded volume of the chain or not """ for time in range(self.time_min,self.time_max): self.snapshots[time].saveCoarseGrainedPDB(path=path,topo=topo) @@ -387,107 +341,77 @@ def playCoarseMovie(self, path = default_dir+'/analysis/pdb/', topo = 'linear', os.system(pymol + " -r "+default_dir+"/analysis/movieCoarse.py -- " + str(self.time_max-self.time_min) + " " + str(self.channel[-1]) + " 1 " + path + " " + self.path_to_data + " " + str(show_hull) + " " + str(sphere_radius)) -class Snapshot: + +class Chain: """ - `Snapshot` object to store all the positions and orientations of the computational beads for a given snapshot. - This object also calculates different polymer metrics. It is nested within the `Trajectory` object. + `Chain` object to store all the positions and orientations of the computational beads for a given chain in + a snapshot. This object also calculates different singl-polymer metrics. It is nested within the `Snapshot` object. This class contains most of the fields and functions that are useful for wlcsim analysis. Some useful class fields are: - `r` : computational bead positions - `u` : computational bead U orientation vectors - `v` : computational bead V orientation vectors - `basepairs` : discreitzation (in bp) of each computational bead - `wrap` : how much DNA (in bp) is wrapped around a computational bead, i.e. nucleosome=147 and DNA=1 - `n_beads` : number of coarse-grained computational beads in polymer - `end_to_end` : end-to-end distance of polymer - `n_bps` : number of DNA basepairs throughout polymer (including DNA wrapped around nucleosomes) + `r` : computational bead positions for the specific chain + `u` : computational bead U orientation vectors for the specific chain + `v` : computational bead V orientation vectors for the specific chain + `discretization` : discreitzation (in bp) of each computational bead for the specific chain + `wrapped` : how much DNA (in bp) is wrapped around a computational bead, i.e. nucleosome=147 and DNA=1 + `n_beads` : number of coarse-grained computational beads in the specific chain + `end_to_end` : end-to-end distance of the specific chain + `n_bps` : number of DNA basepairs throughout the specific chain (including DNA wrapped around nucleosomes) `end_to_end_norm` : end-to-end distance normalized by its contour length `n_bps` - `energies` : wlcsim defined energetics of the polymer chain (in kT) `center_r` : center positions of computational beads with respect to their excluded volume - `n_nucs` : number of nucleosomes on the chain - `pair_nucs` : nucleosome pairwise distances, i.e. all combinatorics of n choose k - `reduced_pair_nucs` : reduced nucleosome pairwise distances, i.e. n & n+1, n & n+2, etc. - `bps` : location of each interpolated phosphate-sugar-phosphate basepair throughout the chain - `break_length_s1`, `break_length_b`, `break_length_2` : RICC-seq pairwise fragment lengths using `bps` - `break_location_s1`, `break_location_b`, `break_location_s2` : RICC-seq pairwise break locations using `bps` - `break_distance_s1`, `break_distance_b`, `break_distance_s2` : RICC-seq pairwise break distances using `bps` + `n_nucs` : number of nucleosomes on the specific chain + `pair_dist` : nucleosome pairwise distances, i.e. all combinatorics of n choose k, for the specific chain + `reduced_pair_dist` : reduced nucleosome pairwise distances, i.e. n & n+1, n & n+2, etc. + `interpolated` : location of each interpolated phosphate-sugar-phosphate basepair throughout the specific chain + `break_length_s1`, `break_length_b`, `break_length_2` : RICC-seq pairwise fragment lengths using `interpolated` + `break_location_s1`, `break_location_b`, `break_location_s2` : RICC-seq pairwise break locations using `interpolated` + `break_likelihood_s1`, `break_likelihood_b`, `break_likelihood_s2` : RICC-seq pairwise break likelihood using `interpolated` """ - def __init__(self,path_to_data,time,channel): + def __init__(self,number,time,channel,r,u,v,discretization,wrapped): """ - `Snapshot` constructor to read in snaphot (bead positions and orientations) data. + `Chain` constructor to read in chain (bead positions and orientations) data from a snapshot. - This constructor is called through the `Trajectory` class, so you should not have to directly - instantiate any `Snapshot` objects directly. + This constructor is called through the `Snapshot` class, so you should not have to directly + instantiate any `Chain` objects directly. Parameters ---------- - path_to_data : string - path to either the wlcsim/data directory or the top level directory above the nested `trials` time : int "time point" of the current wlcsim output structure - channel : int - "channel"/thread value of the current wlcsim output structure """ - # path to data directory - self.path_to_data = path_to_data + # determine chain number (number is arbitrary and defined during initialization) + self.number = number # determine time of snapshot self.time = time # determine channel self.channel = channel # load position and u data of computational beads - self.r = np.loadtxt('%sr%sv%s' %(self.path_to_data,self.time,self.channel)) - self.u = np.loadtxt('%su%sv%s' %(self.path_to_data,self.time,self.channel)) - if (np.shape(self.u)[1]>3): - temp = self.u[:,0:3] - self.v = self.u[:,3:6] - self.u = temp - else: - self.v = None - # load discretization data - try: - disc = np.loadtxt('%sd%sv%s' %(self.path_to_data,self.time,self.channel), dtype='float') - self.wrap = np.asarray(disc[0],dtype='int'); self.basepairs = disc[1] - except: - self.basepairs = np.array([10.5]*len(self.r)) - self.wrap = np.array([1]*len(self.r)) + self.r = r + self.u = u + self.v = v + self.discretization = discretization + self.wrapped = wrapped # assign constants from postion data self.n_beads = len(self.r) self.end_to_end = np.linalg.norm(self.r[-1,:]-self.r[0,:]) - self.n_bps = int(np.round(np.sum(self.basepairs[self.basepairs!=0])+np.sum(self.wrap[self.wrap>1]))) + self.n_bps = int(np.sum(self.discretization)+np.sum(self.wrapped)) self.end_to_end_norm = self.end_to_end/(self.n_bps*length_per_bp) - # energies - with open('%senergiesv%s' %(self.path_to_data,self.channel)) as fp: - for i, line in enumerate(fp): - if i == 0: - # get column specifiers - cols = line.strip().split() - else: - temp = line.strip().split() - if int(temp[0]) == self.time: - # get time data - energies = temp - break - cols = cols[4:] - try: - energies = energies[2:] - except: - energies = [np.nan]*len(cols) - self.energies = pd.DataFrame([energies],columns=cols) # centered beads self.center_r = None # pairwise nucleosomes - self.n_nucs = np.sum(self.wrap>1) - self.n_pair_nucs = int(scipy.special.comb(self.n_nucs,2)) - self.pair_nucs = None - self.reduced_pair_nucs = None + self.n_nucs = np.sum(self.wrapped>1) + self.n_pair_dist = int(scipy.special.comb(self.n_nucs,2)) + self.pair_dist = None + self.reduced_pair_dist = None + self.ff_coeff = np.zeros(self.n_pair_dist); self.fs_coeff = np.zeros(self.n_pair_dist); self.ss_coeff = np.zeros(self.n_pair_dist) + self.ff_dist = np.nan*np.zeros(self.n_pair_dist); self.fs_dist = np.nan*np.zeros(self.n_pair_dist); self.ss_dist = np.nan*np.zeros(self.n_pair_dist) # interpolation/ricc-seq stuff - self.bps = None - self.n_pair_bps = int(scipy.special.comb(self.n_nucs,2)) - self.break_length_s1 = None; self.break_location_s1 = None; self.break_distance_s1 = None - self.break_length_b = None; self.break_location_b = None; self.break_distance_b = None - self.break_length_s2 = None; self.break_location_s2 = None; self.break_distance_s2 = None + self.interpolated = None + self.break_length_s1 = None; self.break_location_s1 = None; self.break_likelihood_s1 = None + self.break_length_b = None; self.break_location_b = None; self.break_likelihood_b = None + self.break_length_s2 = None; self.break_location_s2 = None; self.break_likelihood_s2 = None + self.break_FLD = None; self.break_FLFE = None # determine center of beads from regular polygons def centerBeads(self,nside=16,type='regular'): @@ -511,7 +435,7 @@ def centerBeads(self,nside=16,type='regular'): return 0 self.center_r = np.zeros((self.n_beads-1)*3).reshape([self.n_beads-1,3]) for i in range(self.n_beads-1): - if (self.wrap[i]>1): # nucleosome + if (self.wrapped[i]>0): # nucleosome # make rotation matrix uin = np.asarray(self.u[i,:]); vin = np.asarray(self.v[i,:]); cross = np.cross(uin, vin) mat = np.matrix([vin, cross, uin]).reshape([3,3]).T @@ -524,22 +448,21 @@ def centerBeads(self,nside=16,type='regular'): poly = (self.r[i,:]+self.r[i+1,:])/2.0 self.center_r[i,:] = poly - # determine the pairwise distances between nucleosomes + # determine the pairwise distances between nucleosomes on a chain def pairwiseNucleosomeDistance(self): """Get the pairwise distance between the center of each nucleosome on the chain, i.e. n choose k Generates --------- - pair_nucs : nucleosome pairwise distances, i.e. all combinatorics of n choose k + pair_dist : nucleosome pairwise distances, i.e. all combinatorics of n choose k """ try : if (self.center_r == None): self.centerBeads() except: - print('warning: this has already been run') - return - nucLocs = np.asarray(np.linspace(0,self.n_beads-1,self.n_beads)[self.wrap>1],dtype='int') - self.pair_nucs = scipy.spatial.distance.pdist(self.center_r[nucLocs,:]) + pass # centerbeads has already been run + nucLocs = np.asarray(np.linspace(0,self.n_beads-1,self.n_beads)[self.wrapped>0],dtype='int') + self.pair_dist = scipy.spatial.distance.pdist(self.center_r[nucLocs,:]) # determine the reduced pairwise distances between nucleosomes # such that n+x where x -> 1..self.n_nucs-1 @@ -549,24 +472,87 @@ def reducedPairwiseNucleosomeDistance(self): Generates --------- - reduced_pair_nucs : reduced nucleosome pairwise distances, i.e. n & n+1, n & n+2, etc. + reduced_pair_dist : reduced nucleosome pairwise distances, i.e. n & n+1, n & n+2, etc. """ try: - if (self.pair_nucs == None): + if (self.pair_dist == None): self.pairwiseNucleosomeDistance() except: - print('warning: this has already been run') - return - self.reduced_pair_nucs = np.zeros((self.n_nucs-1)).reshape([self.n_nucs-1]) + pass # pairwiseNucleosomeDistance has already been run + self.reduced_pair_dist = np.zeros((self.n_nucs-1)).reshape([self.n_nucs-1]) # sum up distances iterTemp = 0 for i in range(self.n_nucs-1): for j in range(i+1,self.n_nucs): - self.reduced_pair_nucs[j-i-1] += self.pair_nucs[iterTemp] + self.reduced_pair_dist[j-i-1] += self.pair_dist[iterTemp] iterTemp += 1 # normalize for i in range(self.n_nucs-1): - self.reduced_pair_nucs[i] /= (self.n_nucs-i-1) + self.reduced_pair_dist[i] /= (self.n_nucs-i-1) + + # determine nucleosome-nucleosome orientation + def pairwiseNucleosomeOrientation(self, cutoff=12): + """Get the pairwise orientation between the center of each nucleosome on the chain, i.e. n choose k + + Generates + --------- + pair_dist : nucleosome pairwise distances, i.e. all combinatorics of n choose k + """ + try: + if (self.pair_dist == None): + self.pairwiseNucleosomeDistance() + except: + pass # pairwiseNucleosomeDistance has already been run + # check orientation if within cutoff + nucLocs = np.asarray(np.linspace(0,self.n_beads-1,self.n_beads)[self.wrapped>0],dtype='int') + ind = 0 + for i in range(len(nucLocs)): + for j in range(i+1,len(nucLocs)): + if self.pair_dist[ind] <= cutoff: + # create rotation matrices + matI = np.matrix([self.v[nucLocs[i],:], np.cross(self.u[nucLocs[i],:], self.v[nucLocs[i],:]), self.u[nucLocs[i],:]]).T + matJ = np.matrix([self.v[nucLocs[j],:], np.cross(self.u[nucLocs[j],:], self.v[nucLocs[j],:]), self.u[nucLocs[j],:]]).T + # find center of nucs + polyI = self.r[nucLocs[i],:] + np.squeeze(np.asarray(np.matmul(matI, nucleosome_center))) + polyJ = self.r[nucLocs[j],:] + np.squeeze(np.asarray(np.matmul(matJ, nucleosome_center))) + # construct face I normal vector (pointing up through face) + faceItop = self.r[nucLocs[i],:] + np.squeeze(np.asarray(np.matmul(matI, nucleosome_center + np.array([0, nucleosome_height/2, 0])))) + faceIbot = self.r[nucLocs[i],:] + np.squeeze(np.asarray(np.matmul(matI, nucleosome_center + np.array([0, -nucleosome_height/2, 0])))) + faceI = faceItop - faceIbot + # construct face J normal vector (pointing up through face) + faceJtop = self.r[nucLocs[j],:] + np.squeeze(np.asarray(np.matmul(matJ, nucleosome_center + np.array([0, nucleosome_height/2, 0])))) + faceJbot = self.r[nucLocs[j],:] + np.squeeze(np.asarray(np.matmul(matJ, nucleosome_center + np.array([0, -nucleosome_height/2, 0])))) + faceJ = faceJtop - faceJbot + cospsi = np.dot(faceI/np.linalg.norm(faceI), faceJ/np.linalg.norm(faceJ)) + # list of combinatorial face attractions + faceDistList = np.zeros([4,3]) + faceDistList[0, :] = faceItop - faceJbot + faceDistList[1, :] = faceItop - faceJtop + faceDistList[2, :] = faceIbot - faceJbot + faceDistList[3, :] = faceIbot - faceJtop + # find the closest faces to define the face oritentation vector + indDist = np.argmin(np.linalg.norm(faceDistList, axis=1)) + distS = faceDistList[indDist, :] + costhetaI = np.dot(distS/np.linalg.norm(distS), faceI/np.linalg.norm(faceI)) + costhetaJ = np.dot(distS/np.linalg.norm(distS), faceJ/np.linalg.norm(faceJ)) + # determine frequency of face-face (histone-histone interaction) + self.ff_coeff[ind] = np.abs(costhetaI)*np.abs(costhetaJ) + self.ff_dist[ind] = np.linalg.norm(distS) + # determine other charactestic angls other than theta + distC = polyI - polyJ + cosphiI = np.dot(distC/np.linalg.norm(distC), faceI/np.linalg.norm(faceI)) + cosphiJ = np.dot(distC/np.linalg.norm(distC), faceJ/np.linalg.norm(faceJ)) + # determine frequency of face-side (histone-DNA wrapping interaction) + temp = np.abs(cosphiI) + np.abs(cosphiJ) + if temp > 1: + temp = 2 - temp + self.fs_coeff[ind] = (1 - np.abs(cospsi))*temp #np.sqrt(cosphiI**2 + cosphiJ**2) + self.fs_dist[ind] = np.linalg.norm(np.linalg.norm(distC) - nucleosome_height/2 - nucleosome_radius) + # determine frequency of face-side (histone-DNA wrapping interaction) + self.ss_coeff[ind] = (1 - np.abs(cosphiI))*(1 - np.abs(cosphiJ)) + self.ss_dist[ind] = np.linalg.norm(np.linalg.norm(distC) - 2*nucleosome_radius) + # increment index + ind += 1 # interpolate atoms into coarse grained chain def interpolate(self): @@ -575,26 +561,25 @@ def interpolate(self): Generates --------- - bps : location of each phosphate-sugar-phosphate basepair throughout the chain + interpolated : location of each phosphate-sugar-phosphate basepair throughout the chain """ # rotate DNA strand into material frame - self.bps = np.zeros(self.n_bps*3*3).reshape([self.n_bps,3,3]) - indR = 0 - connect = []; chain = [] - chainNum = 1 + self.interpolated = np.zeros(self.n_bps*3*3).reshape([self.n_bps,3,3]) + row = np.zeros(3*3).reshape([3,3]) + indR = 0; leftOver = 0; summedLeftOver = 0 + chain = []; chainNum = 1 for i in range(self.n_beads): - if self.basepairs[i] != 0: - maxBp = self.basepairs[i] - omega = default_omega + (get_uv_angle(self.v[i,:], self.v[i+1,:])%(2*np.pi) - (maxBp*default_omega)%(2*np.pi)) - v = omega/default_omega*length_per_bp - Uout, Vout, Rout = rotate_bead(self.u[i,:], self.v[i,:], self.r[i,:], self.basepairs[i], self.wrap[i]) + if self.discretization[i] != 0: + # NOT PROPERLY INTERPOLATING TWIST. ADD THIS BACK IN (AND FIX/ADAPT THIS FUNCTION) IF YOU WANT TO INTERPOLATE TWIST/SUPERCOILING + #omega = mc.get_uv_angle(self.v[i], self.v[i + 1]) / self.discretization[i] % 10.5) + #v = omega/default_omega*length_per_bp + Uout, Vout, Rout = rotate_bead(self.u[i,:], self.v[i,:], self.r[i,:], self.discretization[i], self.wrapped[i]) matIn = np.matrix([self.v[i,:], np.cross(self.u[i,:],self.v[i,:]), self.u[i,:]]).T mat = np.matrix([Vout, np.cross(Uout,Vout), Uout]).T - if (self.wrap[i] > 1): # nucleosome - for j in range(len(nucleosome_tran)): - row = np.zeros(3*3).reshape([3,3]) + if (self.wrapped[i] > 0): # nucleosome + for n_wrap,j in enumerate(np.linspace(summedLeftOver, np.floor(self.wrapped[i])+summedLeftOver, int(np.floor(self.wrapped[i])))): strand1, base, strand2 = DNAhelix(j,v=0) - Rin = np.asarray(nucleosome_tran[len(nucleosome_tran)-1-j,:]) + Rin = np.asarray(nucleosome_tran[len(nucleosome_tran)-1-n_wrap,:]) # strand 1 backbone row[0,:] = self.r[i,:] + np.matmul(matIn,Rin+strand1) # strand 2 backbone @@ -602,15 +587,14 @@ def interpolate(self): # base row[1,:] = self.r[i,:] + np.matmul(matIn,Rin+base) # save atoms - self.bps[indR,:,:] = row + self.interpolated[indR,:,:] = row indR = indR + 1 - #connect.append((indR,indR+1)) chain.extend([str(chainNum)]*3) - if (indR == self.n_bps): break - # add the extruding linker from the nucleosome - for j in range(int(np.round(maxBp))): - row = np.zeros(3*3).reshape([3,3]) - strand1, base, strand2 = DNAhelix(j)#,omega=0,v=v) + # add left over basepairs + leftOver = self.wrapped[i] - np.floor(self.wrapped[i]) + # take care of the leftover basepairs + if (summedLeftOver == 0 and leftOver > 0): + strand1, base, strand2 = DNAhelix(j + 1) # strand 1 backbone row[0,:] = Rout + np.matmul(mat, strand1) # strand 2 backbone @@ -618,14 +602,59 @@ def interpolate(self): # base row[1,:] = Rout + np.matmul(mat, base) # save atoms - self.bps[indR,:,:] = row + self.interpolated[indR,:,:] = row indR = indR + 1 chain.extend([str(chainNum)]*3) - if (indR == self.n_bps): break + # cumulative sum of left over basepairs + summedLeftOver = (summedLeftOver + leftOver) % 1 + # add the exiting linker from the nucleosome + for j in np.linspace(leftOver, np.floor(self.discretization[i])+leftOver-1, int(np.floor(self.discretization[i]))): + strand1, base, strand2 = DNAhelix(j) + # strand 1 backbone + row[0,:] = Rout + np.matmul(mat, strand1) + # strand 2 backbone + row[2,:] = Rout + np.matmul(mat, strand2) + # base + row[1,:] = Rout + np.matmul(mat, base) + # save atoms + self.interpolated[indR,:,:] = row + indR = indR + 1 + chain.extend([str(chainNum)]*3) + # add left over basepairs + leftOver = self.discretization[i] - np.floor(self.discretization[i]) + # take care of the leftover basepairs + if (summedLeftOver == 0 and leftOver > 0): + strand1, base, strand2 = DNAhelix(j + 1) + # strand 1 backbone + row[0,:] = Rout + np.matmul(mat, strand1) + # strand 2 backbone + row[2,:] = Rout + np.matmul(mat, strand2) + # base + row[1,:] = Rout + np.matmul(mat, base) + # save atoms + self.interpolated[indR,:,:] = row + indR = indR + 1 + chain.extend([str(chainNum)]*3) + # cumulative sum of left over basepairs + summedLeftOver = (summedLeftOver + leftOver) % 1 else: # dna bead - for j in range(int(np.round(maxBp))): - row = np.zeros(3*3).reshape([3,3]) - strand1, base, strand2 = DNAhelix(j)#,omega=omega,v=v) + for j in np.linspace(leftOver, np.floor(self.discretization[i])+leftOver-1, int(np.floor(self.discretization[i]))): + strand1, base, strand2 = DNAhelix(j) + # strand 1 backbone + row[0,:] = Rout + np.matmul(mat, strand1) + # strand 2 backbone + row[2,:] = Rout + np.matmul(mat, strand2) + # base + row[1,:] = Rout + np.matmul(mat, base) + # save atoms + self.interpolated[indR,:,:] = row + indR = indR + 1 + chain.extend([str(chainNum)]*3) + # add left over basepairs + leftOver = self.discretization[i] - np.floor(self.discretization[i]) + # take care of the leftover basepairs + if (summedLeftOver == 0 and leftOver > 0): + strand1, base, strand2 = DNAhelix(j + 1) # strand 1 backbone row[0,:] = Rout + np.matmul(mat, strand1) # strand 2 backbone @@ -633,44 +662,44 @@ def interpolate(self): # base row[1,:] = Rout + np.matmul(mat, base) # save atoms - self.bps[indR,:,:] = row + self.interpolated[indR,:,:] = row indR = indR + 1 chain.extend([str(chainNum)]*3) - if (indR == self.n_bps): break + # cumulative sum of left over basepairs + summedLeftOver = (summedLeftOver + leftOver) % 1 else: chainNum +=1 + # TEMPORARY FIX FOR WERID FLOAT DISCRETIZATION. + # TODO: fix this interpolation problem more permanently + tempInds = np.sum(np.sum(self.interpolated==0,1),1)!=9 + self.interpolated = self.interpolated[tempInds] + self.n_bps = len(self.interpolated) return chain # distance constraint ricc-seq - def RICCbreak(self,cutoff=3.5,noise=50.0): # units in nm or bp + def RICCbreak(self,cutoff=4.03, minFragment = 50): # units in nm or bp """Determine the RICC-seq break patterns from the interpolated fine-graied polymer structure. Parameters ---------- cutoff : float, optional - default : 3.5 nm + default : 4.03 nm RICC-seq radiolytic cleavage radius under which there will be simulated breaks - noise : float, optional - default : 50.0 bp + minFragment : integer, optional + default : 50 bp fragment length under which any breaks are considered noise and thus thrown out Generates --------- - break_length_s1, break_length_b, break_length_2 : RICC-seq pairwise fragment lengths using `bps` - break_location_s1, break_location_b, break_location_s2 : RICC-seq pairwise break locations using `bps` - break_distance_s1, break_distance_b, break_distance_s2 : RICC-seq pairwise break distances using `bps` + break_length_s1, break_length_b, break_length_2 : RICC-seq pairwise fragment lengths using `interpolated` + break_location_s1, break_location_b, break_location_s2 : RICC-seq pairwise break locations using `interpolated` + break_likelihood_s1, break_likelihood_b, break_likelihood_s2 : RICC-seq pairwise break likelihood using `interpolated` """ try : - if (self.bps == None): + if (self.interpolated == None): self.interpolate() except: - pass - try : - if (self.break_length_s1 == None): - pass - except: - print('warning: this has already been run') - return + pass # interpolate already run # figure out combinatorial correlated cleaves nPair = int(scipy.special.comb(self.n_bps,2)) indPair = np.zeros(nPair*2).reshape([nPair,2]) @@ -681,21 +710,132 @@ def RICCbreak(self,cutoff=3.5,noise=50.0): # units in nm or bp indPair[ind:ind+extension,1] = np.linspace(i+1,i+extension, extension, dtype='int') ind += extension # find 3d distance on both strands and base - pairS1 = scipy.spatial.distance.pdist(self.bps[:,0,:]) - pairB = scipy.spatial.distance.pdist(self.bps[:,1,:]) - pairS2 = scipy.spatial.distance.pdist(self.bps[:,2,:]) - cutIndS1 = pairS1 <= cutoff; cutIndB = pairB <= cutoff; cutIndS2 = pairS2 <= cutoff - indBreakS1 = np.linspace(0,nPair-1,nPair,dtype='int')[cutIndS1] - indBreakB = np.linspace(0,nPair-1,nPair,dtype='int')[cutIndB] - indBreakS2 = np.linspace(0,nPair-1,nPair,dtype='int')[cutIndS2] + pairS1 = scipy.spatial.distance.pdist(self.interpolated[:,0,:]) + pairB = scipy.spatial.distance.pdist(self.interpolated[:,1,:]) + pairS2 = scipy.spatial.distance.pdist(self.interpolated[:,2,:]) + # define exponential + weight = lambda x: np.exp(-x/cutoff) + pairS1 = weight(pairS1); pairB = weight(pairB); pairS2 = weight(pairS2) + indBreakS1 = np.linspace(0,nPair-1,nPair,dtype='int') + indBreakB = np.linspace(0,nPair-1,nPair,dtype='int') + indBreakS2 = np.linspace(0,nPair-1,nPair,dtype='int') fragBreakS1 = indPair[indBreakS1,1]-indPair[indBreakS1,0] fragBreakB = indPair[indBreakB,1]-indPair[indBreakB,0] fragBreakS2 = indPair[indBreakS2,1]-indPair[indBreakS2,0] - noiseIndS1 = fragBreakS1 >= noise; noiseIndB = fragBreakB >= noise; noiseIndS2 = fragBreakS2 >= noise - self.break_length_s1 = fragBreakS1[noiseIndS1]; self.break_location_s1 = indPair[indBreakS1][noiseIndS1]; self.break_distance_s1 = pairS1[cutIndS1][noiseIndS1] - self.break_length_b = fragBreakB[noiseIndB]; self.break_location_b = indPair[indBreakB][noiseIndB]; self.break_distance_b = pairB[cutIndB][noiseIndB] - self.break_length_s2 = fragBreakS2[noiseIndS2]; self.break_location_s2 = indPair[indBreakS2][noiseIndS2]; self.break_distance_s2 = pairS2[cutIndS2][noiseIndS2] + noiseIndS1 = fragBreakS1 >= minFragment; noiseIndB = fragBreakB >= minFragment; noiseIndS2 = fragBreakS2 >= minFragment + self.break_length_s1 = fragBreakS1[noiseIndS1]; self.break_location_s1 = indPair[indBreakS1][noiseIndS1]; self.break_likelihood_s1 = pairS1[noiseIndS1] + self.break_length_b = fragBreakB[noiseIndB]; self.break_location_b = indPair[indBreakB][noiseIndB]; self.break_likelihood_b = pairB[noiseIndB] + self.break_length_s2 = fragBreakS2[noiseIndS2]; self.break_location_s2 = indPair[indBreakS2][noiseIndS2]; self.break_likelihood_s2 = pairS2[noiseIndS2] + + def RICCbreakFLD(self, minFragment = 50, maxFragment = 500): + """Create FLD histogram for the RICC-seq break patterns (strand1/strand2/ lengths and likelihoods). + + Parameters + ---------- + minFragment : integer, optional + default : 50 bp + fragment length under which any breaks are considered noise and thus thrown out + maxFragment : intege, optional + default : 500 bp + fragment length over which any breaks are considered noise and thus thrown out + + Generates + --------- + self.break_FLD : RICC break FLD histogram from minFragment to maxFragment size + + """ + try : + if (self.break_length_s1 == None): + self.RICCbreak(minFragment=minFragment) + except: + pass # RICCbreak already run + # create historgram from both strand break information + breaklength = np.transpose(np.hstack([self.break_length_s1, self.break_length_s2])) + breaklike = np.transpose(np.hstack([self.break_likelihood_s1, self.break_likelihood_s2])) + breakhist = np.histogram(breaklength[breaklength <= maxFragment], + bins=np.arange(minFragment,maxFragment + 2), weights=breaklike[breaklength <= maxFragment])[0] + self.break_FLD = breakhist + def RICCbreakFLFE(self, lengthbias = -0.0039, minFragment = 50, maxFragment=500, startFragment = 148, + genome_norm_file = default_dir + '/analysis/' + 'RICC-BJ-2017_genome-norm.txt'): + """Calculate the FLFE (FLD enrichment over genome average) for the RICC-seq break patterns. + + Parameters + ---------- + lengthbias : float, optional + default : -0.0039 + exponential parameter to quanity a RICC-seq experiment's fragment length bias + minFragment : integer, optional + default : 50 bp + fragment length under which any breaks are considered noise and thus thrown out + maxFragment : integer, optional + default : 500 bp + fragment length over which any breaks are considered noise and thus thrown out + startFragment : integer, optional + default : 148 bp + length of fragment over which has relevant/interesting 3D spatial information encoded + within it; for example, the 80bp RICC peak is strong but not interesting for 3D info. + genome_norm_file : string, optional + default : "wlcsim/analysis/RICC-BJ-2017_genome-norm.txt" + path to where you want to read in the genome average RICC-seq break pattern FLD + + Generates + --------- + self.break_FLFE : RICC break FLFE (FLD enrichment over genome average) from minFragment to maxFragment size + """ + try : + if (self.break_FLD == None): + self.RICCbreakFLD(minFragment=minFragment, maxFragment=maxFragment) + except: + pass # RICCbreak already run + # read in the genome_norm file + genome_norm = np.loadtxt(genome_norm_file); genome_norm = genome_norm[minFragment:maxFragment + 1] + x = np.linspace(minFragment, maxFragment, maxFragment - minFragment + 1) + # maximum normalization of FLFE score + experimental length bias + temp_FLFE = self.break_FLD / np.max(self.break_FLD) * np.exp(lengthbias * x) + # second maximum normalization after length bias correction + temp_FLFE /= np.max(temp_FLFE) + # divide by genome norm from experiment + temp_FLFE /= genome_norm + # look at only relevant fragment lengths + temp_FLFE = temp_FLFE[(startFragment-minFragment):] + temp_FLFE -= np.mean(temp_FLFE) + self.break_FLFE = temp_FLFE + + def RICCmatrix(self, blur = 0, init = 0.0): + """Generate the fragment-break frequency matrix from the interpolated chain. + + Parameters + ---------- + blur : int, optional + default : 20 + Gaussian blur to apply to the frequency matrix to add "noise" and make the matrix less sparse + removeLow : boolean, optional + default : True + whether to remove frequency values less than 1 and replace them as NAN + init : float, optional + default : 0.5 + value to initialize the entries of the frequency matrix with if trying to avoid zeros in cells + + Returns + ------- + mat : matrix + RICC-seq fragment break frequency matrix + """ + self.RICCbreak() + mat = init*np.ones(self.n_bps**2).reshape([self.n_bps,self.n_bps]) + for iterN in range(len(self.break_location_s1)): + j = int(self.break_location_s1[iterN,0]) + k = int(self.break_location_s1[iterN,1]) + mat[j,k] += self.break_likelihood_s1[iterN] + for iterN in range(len(self.break_location_s2)): + j = int(self.break_location_s2[iterN,0]) + k = int(self.break_location_s2[iterN,1]) + mat[j,k] += self.break_likelihood_s2[iterN] + if (blur > 0): + mat = gaussian_filter(mat, sigma=blur) + return mat + def saveCoarseGrainedPDB(self,path=default_dir+'/analysis/pdb/',topo='linear'): """Save the coarse-grained wlcsim output in a PDB format. @@ -708,18 +848,25 @@ def saveCoarseGrainedPDB(self,path=default_dir+'/analysis/pdb/',topo='linear'): default : 'linear' topology of polymer structure (for the risca lab, it will almost always be 'linear') """ + # make intermediary directory if needed + os.makedirs(path, exist_ok=True) + # save structure chain = []; connect = [] chainNum = 1 for i in range(self.n_beads): chain.append(chainNum) - if self.basepairs[i]==0: + if self.discretization[i]==0: chainNum += 1 else: connect.append((i,i+1)) dna = mkpdb(self.r,topology=topo,chain=chain,connect=connect) - save_pdb('%scoarse%0.3d.pdb' %(path,self.time),dna) + if self.number > 0: + filename = '%scoarse%0.3dv%sf%s.pdb' %(path,self.time,self.channel,self.number) + else: + filename = '%scoarse%0.3dv%s.pdb' %(path,self.time,self.channel) + save_pdb(filename,dna) - def saveFineGrainedPDB(self,path=default_dir+'/analysis/pdb/',topo='linear'): + def saveFineGrainedPDB(self,path=default_dir+'/analysis/pdb/',topo='linear',base=3): """Save the interpolated fine-grained wlcsim structure in a PDB format. Parameters @@ -731,62 +878,82 @@ def saveFineGrainedPDB(self,path=default_dir+'/analysis/pdb/',topo='linear'): default : 'linear' topology of polymer structure (for the risca lab, it will almost always be 'linear') """ + # make intermediary directory if needed + os.makedirs(path, exist_ok=True) + # interpolate to make fine-grained structure chain = self.interpolate() - dna = mkpdb(np.asarray(self.bps).reshape([3*self.n_bps,3]),topology=topo,chain=chain)#,connect=connect) - save_pdb('%sfine%0.3d.pdb' %(path,self.time),dna) + if (base != 3): + dna = mkpdb(np.asarray(self.interpolated[:,base,:]).reshape([base*self.n_bps,3]),topology=topo,chain=chain) + else: + dna = mkpdb(np.asarray(self.interpolated).reshape([base*self.n_bps,3]),topology=topo,chain=chain) + if self.number > 0: + filename = '%sfine%0.3dv%sf%s.pdb' %(path,self.time,self.channel,self.number) + else: + filename = '%sfine%0.3dv%s.pdb' %(path,self.time,self.channel) + save_pdb(filename,dna) - def saveRICCbreak(self,path=default_dir+'/analysis/data'): - """Save the RICC-seq break patterns (strand1/strand2/base lengths and locatons) to pickle files. + def saveRICCbreakFLD(self, minFragment = 50, maxFragment = 500, path=default_dir+'/analysis/data/'): + """Save the RICC-seq break patterns (strand1/strand2/ lengths and likelihoods) to a text file. Parameters ---------- path : string, optional default : "wlcsim/analysis/data/" - path to where you want to store the RICC-seq break pattern pickle files + path to where you want to store the RICC-seq break pattern file + minFragment : integer, optional + default : 50 bp + fragment length under which any breaks are considered noise and thus thrown out + maxFragment : integer, optional + default : 500 bp + fragment length over which any breaks are considered noise and thus thrown out """ - self.RICCbreak() - tempDict = {'strand1': [self.break_length_s1, self.break_location_s1], - 'base': [self.break_length_b, self.break_location_b], - 'strand2': [self.break_length_s2, self.break_location_s2]} - f = open('%s/riccBreak%0.3d.pkl' %(path,self.time),"wb") - pickle.dump(tempDict,f) - f.close() + try : + if (self.break_FLD == None): + self.RICCbreakFLD(minFragment=minFragment, maxFragment=maxFragment) + except: + pass # RICCbreak already run + # make intermediary directory if needed + os.makedirs(path, exist_ok=True) + filename = '%sriccBreakFLD%0.3dv%s.txt' %(path,self.time,self.channel) + np.savetxt(filename, self.break_FLD, fmt='%i') - def RICCmatrix(self,blur=20,removeLow=True,init=0.5): - """Generate the fragment-break frequency matrix from the interpolated chain. + def saveRICCbreakFLFE(self, lengthbias = -0.0039, minFragment = 50, maxFragment=500, startFragment = 148, + genome_norm_file = default_dir + '/analysis/' + 'RICC-BJ-2017_genome-norm.txt', path=default_dir+'/analysis/data/'): + """Save the RICC-seq break patterns (strand1/strand2/ lengths and likelihoods) to a text file. Parameters ---------- - blur : int, optional - default : 20 - Gaussian blur to apply to the frequency matrix to add "noise" and make the matrix less sparse - removeLow : boolean, optional - default : True - whether to remove frequency values less than 1 and replace them as NAN - init : float, optional - default : 0.5 - value to initialize the entries of the frequency matrix with if trying to avoid zeros in cells - - Returns - ------- - mat : matrix - RICC-seq fragment break frequency matrix + path : string, optional + default : "wlcsim/analysis/data/" + path to where you want to store the RICC-seq break pattern file + lengthbias : float, optional + default : -0.0039 + exponential parameter to quanity a RICC-seq experiment's fragment length bias + minFragment : integer, optional + default : 50 bp + fragment length under which any breaks are considered noise and thus thrown out + maxFragment : integer, optional + default : 500 bp + fragment length over which any breaks are considered noise and thus thrown out + startFragment : integer, optional + default : 148 bp + length of fragment over which has relevant/interesting 3D spatial information encoded + within it; for example, the 80bp RICC peak is strong but not interesting for 3D info. + genome_norm_file : string, optional + default : "wlcsim/analysis/RICC-BJ-2017_genome-norm.txt" + path to where you want to read in the genome average RICC-seq break pattern FLD """ - self.RICCbreak() - mat = init*np.ones(self.n_bps**2).reshape([self.n_bps,self.n_bps]) - for iterN in range(len(self.break_location_s1)): - j = int(self.break_location_s1[iterN,0]) - k = int(self.break_location_s1[iterN,1]) - mat[j,k] += 1 - for iterN in range(len(self.break_location_s2)): - j = int(self.break_location_s2[iterN,0]) - k = int(self.break_location_s2[iterN,1]) - mat[j,k] += 1 - mat = gaussian_filter(mat, sigma=blur) - if (removeLow): - mat[mat < 1] = np.nan - return mat - + try : + if (self.break_FLFE == None): + self.RICCbreakFLFE(minFragment=minFragment, startFragment=startFragment, maxFragment=maxFragment, + lengthbias=lengthbias, genome_norm_file=genome_norm_file) + except: + pass # RICCbreak already run + # make intermediary directory if needed + os.makedirs(path, exist_ok=True) + filename = '%sriccBreakFLFE%0.3dv%s.txt' %(path,self.time,self.channel) + np.savetxt(filename, self.break_FLFE, fmt='%f') + def saveRICCmat(self,path=default_dir+'/analysis/data'): """Save the RICC-seq fragment break frequency matrix to a text file. @@ -796,8 +963,121 @@ def saveRICCmat(self,path=default_dir+'/analysis/data'): default : "wlcsim/analysis/data/" path to where you want to store the RICC-seq fragment break frequency matrix file """ - mat = self.RICCmatrix(blur=0,removeLow=False,init=0) - with open('%s/riccMat%0.3d.txt' %(path,self.time), 'w') as f: + # make intermediary directory if needed + os.makedirs(path, exist_ok=True) + # create and save matrix + mat = self.RICCmatrix() + if self.number > 0: + filename = '%s/riccMat%0.3dv%sf%s.txt' %(path,self.time,self.channel,self.number) + else: + filename = '%s/riccMat%0.3dv%s.txt' %(path,self.time,self.channel) + with open(filename, 'w') as f: for i in range(np.shape(mat)[0]): for j in range(np.shape(mat)[1]): f.write(str(i) + ' ' + str(j) + ' ' + str(mat[i,j])+ '\n') + +class Snapshot(Chain): + """ + `Snapshot` object to store all the positions and orientations of ALL the computational beads for a given snapshot. + This object also calculates different polymer metrics. It is nested within the `Trajectory` object. + + This class contains most of the fields and functions that are useful for wlcsim analysis. Some useful class + fields are: + `r` : computational bead positions + `u` : computational bead U orientation vectors + `v` : computational bead V orientation vectors + `discretization` : discreitzation (in bp) of each computational bead + `wrapped` : how much DNA (in bp) is wrapped around a computational bead, i.e. nucleosome=147 and DNA=1 + `n_beads` : number of coarse-grained computational beads in polymer + `n_bps` : number of DNA basepairs throughout polymer (including DNA wrapped around nucleosomes) + `energies` : wlcsim defined energetics of the polymer chain (in kT) + + """ + def __init__(self,path_to_data,time,channel): + """ + `Snapshot` constructor to read in snaphot (bead positions and orientations) data. + + This constructor is called through the `Trajectory` class, so you should not have to directly + instantiate any `Snapshot` objects directly. + + Parameters + ---------- + path_to_data : string + path to either the wlcsim/data directory or the top level directory above the nested `trials` + time : int + "time point" of the current wlcsim output structure + channel : int + "channel"/thread value of the current wlcsim output structure + """ + # determine time of snapshot + self.time = time + # determine channel + self.channel = channel + # load position and u data of computational beads + self.r = np.loadtxt('%sr%sv%s' %(path_to_data,self.time,self.channel)) + self.u = np.loadtxt('%su%sv%s' %(path_to_data,self.time,self.channel)) + if (np.shape(self.u)[1]>3): + temp = self.u[:,0:3] + self.v = self.u[:,3:6] + self.u = temp + else: + self.v = None + # load discretization data + try: + disc = np.loadtxt('%sd%sv%s' %(path_to_data,self.time,self.channel)) + self.discretization = disc[:,0]; self.wrapped = disc[:,1] + except: + self.discretization = np.array([10.5]*len(self.r)) # default to 10.5 discretization + self.wrapped = np.array([1]*len(self.r)) # default to all DNA + # assign constants from postion data + self.n_beads = len(self.r) + self.end_to_end = np.linalg.norm(self.r[-1,:]-self.r[0,:]) + self.n_bps = int(np.sum(self.discretization)+np.sum(self.wrapped)) + self.end_to_end_norm = self.end_to_end/(self.n_bps*length_per_bp) + # centered beads + self.center_r = None + # pairwise nucleosomes + self.n_nucs = np.sum(self.wrapped>0) + self.n_pair_dist = int(scipy.special.comb(self.n_nucs,2)) + self.pair_dist = None + self.reduced_pair_dist = None + self.ff_coeff = np.zeros(self.n_pair_dist); self.fs_coeff = np.zeros(self.n_pair_dist); self.ss_coeff = np.zeros(self.n_pair_dist) + self.ff_dist = np.nan*np.zeros(self.n_pair_dist); self.fs_dist = np.nan*np.zeros(self.n_pair_dist); self.ss_dist = np.nan*np.zeros(self.n_pair_dist) + # interpolation/ricc-seq stuff + self.interpolated = None + self.break_length_s1 = None; self.break_location_s1 = None; self.break_distance_s1 = None + self.break_length_b = None; self.break_location_b = None; self.break_distance_b = None + self.break_length_s2 = None; self.break_location_s2 = None; self.break_distance_s2 = None + self.break_FLD = None; self.break_FLFE = None + + # energies + with open('%senergiesv%s' %(path_to_data,self.channel)) as fp: + for i, line in enumerate(fp): + if i == 0: + # get column specifiers + cols = line.strip().split() + else: + temp = line.strip().split() + if int(temp[0]) == self.time: + # get time data + energies = temp + break + cols = cols[2:] # cols = cols[4:] + try: + energies = energies[0:] # energies = energies[2:] + except: + energies = [np.nan]*len(cols) + self.energies = pd.DataFrame([energies],columns=cols) + # load chains in dictionary + self.n_chains = np.sum(self.discretization==0) + self.number = 0 + if self.n_chains > 1: + self.chains = {} + nbeads = int(self.n_beads/self.n_chains) + ind = 0 + for i in range(self.n_chains): + self.chains[i] = Chain(i, self.time, self.channel, + self.r[ind:ind+nbeads,:], self.u[ind:ind+nbeads,:], self.v[ind:ind+nbeads,:], + self.discretization[ind:ind+nbeads], self.wrapped[ind:ind+nbeads]) + ind += nbeads + diff --git a/analysis/MCsim_ABC_edits.py b/analysis/MCsim_ABC_edits.py new file mode 100644 index 00000000..e0f7d0d8 --- /dev/null +++ b/analysis/MCsim_ABC_edits.py @@ -0,0 +1,1270 @@ +#/usr/bin/python +# npagane and aclerkin | simulation object class and subclasses to parse wlcsim output +""" +Simulation objects to help read in wlcsim data and perform simple analyses/visualizations. +This was specifically designed for Risca lab usage, but feel free to use/edit if it helps you +parse your wlcsim output, too. + +Generally, the data structure is assumed to be organized as follows: + +MAIN_SIMULATION_FOLDER + TRIALS_ + wlcsim + data + rv + +where there are number of trials and number of trajectories for number of snapshots. Differing +trials represent different experiements (i.e. changing condtitions/parameters) or experimental replicates +while different trajectories are essentially technical replicates--UNLESS you are parallel tempering, +which then means that the different trajectories are different "temperatures". The snapshots are wlcsim +outputs throughout the simulation "time". + +Therefore the hierarchy of these classes are nested as follows: +Simulation + Trial* + Trajectory* + Snapshot* + Chain* +* can have multiple instances + +--------------- +EXAMPLE USAGE 1 +--------------- +# we are in a Python instance from within the wlcsim directory +# we ran a simulation on 1 core (i.e. no parallelizaiton/parallel tempering) and generated 10 snapshots +dat = Simulation(time_max=10) # read in data + +# since the Trial and Trajectory objects are null, we reference them with the empty string "''" +dat.trials[''].trajectories[''].playCoarseMovie(pymol=PATH_TO_PYMOL) # visualize trajectory in PyMol + +# we want to look at the end-to-end distance of the snapshot at "time point" 1 +dat.trials[''].trajectories[''].snapshots[1].end_to_end # get end-to-end distance + +--------------- +EXAMPLE USAGE 2 +--------------- +# we are in a Python instance from NOT within the wlcsim directory +# we ran two simulations labeled "trial1" and "trial2" that live under the PATH_TO_DATA directory. +# each simulation was run on 2 cores (for parallelizaiton) and generated 10 snapshots +dat = Simulation(path_to_data=PATH_DO_DATA, trials=["trial1", "trial2"], trajectories=[1, 2], time_max=10) # read in data + +# we want to look at the movie of the "trial1" simulation's first trajectory +dat.trials['trial1'].trajectories[1].playCoarseMovie(pymol=PATH_TO_PYMOL) # visualize trajectory in PyMol + +# we want to look at the end-to-end distance of the snapshot at "time point" 9 of the second trajetory in "trial2" +dat.trials['trial2'].trajectories[2].snapshots[9].end_to_end # get end-to-end distance + +---- +TODO +---- +fix interpolation code, it works reasonably but still not perfect for fractional basepairs +more analysis functions for interaction geoemetry +""" +import sys +from .utility import * +from .r2pdb import * +import numpy as np +import pandas as pd +import os +import scipy +import scipy.special +import scipy.spatial +from scipy.ndimage import gaussian_filter +import pickle + +class Simulation: + """ + `Simulation` object to store all your data. You should only directly interface with THIS object when + loading data. It assumes you are in the top level directory of the wlcsim repo; otherwise, you can + be anywhere and specify location of data (i.e path_to/wlcsim/data/) in `path_to_data`. + + You must specify the number of "time points" to read in as `time_max`, and if you are running this + from within the wlcsim directory, you do not need to specify anything else. + If you are elsewhere, you need to not only specify `path_to_data` but also `trials`if you ran simulations + across different parameter values or conditions. + If you ran several instances of the same simulation across several cores (i.e. either for PT/replica exchange + or for general parallelization), then you must specify the `trajectories`. + """ + def __init__(self, path_to_data = "%s/data/" %(default_dir), trials = [''], trajectories = [''], + time_min = 0, time_max = 110, channel = 0): + """ + `Simulation` constructor to read in simulation data. + + Upon reading in the data, this class will try to "unnest" the nested classes as much as possible. + For example, if you have several trajectories but only one trial, then you can reference the `Trajectory` + object directly from the `Simulation` class without having to pass through a `Trial` class. + + Parameters + ---------- + path_to_data : string, optional + path to either the wlcsim/data directory or the top level directory above the nested `trials` + trials : list of strings + list of the subdirectories in `path_to_data` that specify the different trials of the simulations + trajectories : list, optional + list of the "channel"/thread values of the simulation replicas, i.e. [1,2,3,4] + time_min : int, optional + default : 0 + minimum "time point" that you want to start reading in the data from + time_max : int, optional + default : 110 + maximum "time point" that you want to end reading in the data from. + channel : int, optional + "channel"/thread value of a specific replica you want to read in + """ + # path to data directory + self.path_to_data = path_to_data + # store Trials in dictionary + self.trials = {} + for trial in trials: + self.trials[trial] = Trial("%s%s" %(self.path_to_data, trial), + time_min, time_max, trajectories, channel) + print('read in %s' %(str(trial))) + # remove intermediary data structures if they do not exist + self.unnest() + + def __enter__(self): + return "entered!" + + def __exit__(self, exc_type, exc_value, traceback): + print("exited!") + + def returnTrials(self): + """Return a list of the `Trial` subdirectory names.""" + return self.trials.keys() + + def returnTrajectories(self): + """Return a dictionary with all of the `Trajectory` values for all the `Trial` objects.""" + tempDict = {} + for i in self.trials.keys(): + tempDict[i] = self.trials[i].trajectories.keys() + return tempDict + + def returnSnapshots(self): + """Return a dictionary with all of the `Snapshot` values for all `Trajectory` classes of all + `Trial` classes.""" + tempDict = {} + for i in self.trials.keys(): + tempDict[i] = {} + for j in self.trials[i].trajectories.keys(): + tempDict[i][j] = self.trials[i].trajectories[j].snapshots.keys() + return tempDict + + def unnest(self): + """Remove unnecessary nesting of objects, i.e. if there is 1 `Trial` but 2 `Trajectory` classes, + have the `Trajectory` objects reachable from the main `Simulation` object.""" + trials=self.returnTrials() + trajectories=self.returnTrajectories() + snapshots=self.returnSnapshots() + if '' in trials and '' not in trajectories['']: + self.trajectories = {} + for i in trajectories['']: + self.trajectories[i] = self.trials[''].trajectories[i] + elif '' in trials and '' in trajectories['']: + self.snapshots = {} + for i in snapshots['']['']: + self.snapshots[i] = self.trials[''].trajectories[''].snapshots[i] + # add trajectories reference for easy access to making pymol movies + self.trajectories = self.trials[''].trajectories + elif '' not in trials: + for i in trials: + if '' in trajectories[i]: + self.trials[i] = self.trials[i].trajectories[''] + +class Trial: + """ + `Trial` object to store all the different parameter/condition settings if you want to analyze several different + simulations at once. It is nested within the `Simulation` object and further nests the `Trajectory` class. + + The `Trial` class will automatically search for and detect whether if there is parallel tempering or not and + then instanitate nested `Trajectory` classes for each "temperature". The lowest relative ranked "temperature", + i.e. "PT1" corresponds to the main trajectory with the enhanced sampling. + + There is no direct usability of this object. + """ + def __init__(self, path_to_data, time_min, time_max, trajectories, channel): + """ + `Trial` constructor to read in trial (differing parameters/conditions) data. + + This constructor is called through the `Simulation` class, so you should not have to directly + instantiate any `Trial` objects directly. + + Parameters + ---------- + path_to_data : string + path to either the wlcsim/data directory or the top level directory above the nested `trials` + trajectories : list + list of the "channel"/thread values of the simulation replicas, i.e. [1,2,3,4] + time_min : int + minimum "time point" that you want to start reading in the data from + time_max : int + maximum "time point" that you want to end reading in the data from. + channel : int + "channel"/thread value of a specific replica throughout the simulation "timecouse" + """ + # path to data directory + self.path_to_data = path_to_data + if trajectories != ['']: + self.channels = trajectories + else: + self.channels = [channel]*len(trajectories) + if type(time_max) != int: + self.time_maxs = time_max + else: + self.time_maxs = [time_max]*len(trajectories) + if type(time_min) != int: + self.time_mins = time_min + else: + self.time_mins = [time_min]*len(trajectories) + # store Trajectories in dictionary + self.trajectories = {} + for i,trajectory in enumerate(trajectories): + self.trajectories[trajectory] = Trajectory(self.path_to_data, + self.time_mins[i],self.time_maxs[i],self.channels[i]) + # check for PT + if os.path.exists(self.path_to_data+'nodeNumber'): + for i in range(1,max(self.channels)+1): + self.trajectories['PT%s'%(str(i))] = Trajectory(self.path_to_data, + max(self.time_mins), min(self.time_maxs), 1, temperature = i) + print('PT configured') + +class Trajectory: + """ + `Trajectory` object to store all the replicates of a simulation run across several threads with or without + parallel tempgering. It is nested within the `Trial` object and further nests the `Snapshot` class. + + There are a few functions that are usable from this class, namely setting up PyMol movies or determining the + "evolution" of metrics throughout the simulation. + """ + def __init__(self, path_to_data, time_min, time_max, channel, temperature = None): + """ + `Trajectory` constructor to read in trajectory (technical replicates/parallel tempering) data. + + This constructor is called through the `Trial` class, so you should not have to directly + instantiate any `Trajectory` objects directly. + + Parameters + ---------- + path_to_data : string + path to either the wlcsim/data directory or the top level directory above the nested `trials` + time_min : int + minimum "time point" that you want to start reading in the data from + time_max : int + maximum "time point" that you want to end reading in the data from. + channel : int + "channel"/thread value of a specific replica throughout the simulation "timecouse" + temperature : int, optional + default : None + the relative ranked "temperature" value of the trajectory if parallel tempering + """ + # path to data directory + self.path_to_data = path_to_data + # set time range + self.time_min = time_min + self.equilibrium_time = self.time_min + self.time_max = time_max+1 # add plus one here for iteration + # store Snapshots in dictionary + self.snapshots = {} + # snapshots stats + self.end_to_end = [] + self.reduced_pair_dist = [] + self.temperature = temperature + if (self.temperature != None): + nodes = np.loadtxt(self.path_to_data+'nodeNumber') + nodes = np.vstack((np.linspace(0, np.shape(nodes)[1]-1, np.shape(nodes)[1]), nodes)) + self.channel = np.asarray(nodes[:,temperature], 'int') + else: + self.channel = [channel]*(self.time_max-self.time_min) + # load snapshots in dictionary + for i,time in enumerate(range(self.time_min,self.time_max)): + self.snapshots[time] = Snapshot(self.path_to_data,time,self.channel[i]) + + def setEquilibriumTime(self,time): + """Set an "equilibrium" time after which "time point" you accept all succeeding snapshots to be equilibriated""" + self.equilibrium_time = time + + + def getEnergies(self): + """Determine the energetics of the polymer(s) for each `Snapshot` in the `Trajectory`. + References the energies field in the `Snapshot` class for more informtion on the calculation.""" + self.energies = self.snapshots[self.equilibrium_time].energies + for time in range(self.equilibrium_time+1,self.time_max): + self.energies = self.energies.append(self.snapshots[time].energies) + + def playFineMovie(self,path=default_dir+'/analysis/pdb/',topo='linear',pymol='pymol',base=3, color_nucs = 0): + """Play PyMol movie of the polymer throughout the simulation "timecourse" after interpolating into a more fine-grained + structure. See the saveFineGrainedPDB and interpolate methods in the `Snapshot` class for more informtion on the calculations. + + Currently, this function CAN NOT determine the simulation "timecourse" trajectory with parallel tempering. + + Parameters + ---------- + path : string, optional + default : "wlcsim/analysis/pdb/" + path to where you want to store the fine-grained PDB files that PyMol will then read in and visualize + topo : string, optional + default : 'linear' + topology of polymer structure (for the risca lab, it will almost always be 'linear') + pymol : string, optional + default : 'pymol' + exectable command to initiaite PyMol, i.e. "~/Applications/pymol/pymol" + """ + for time in range(self.time_min,self.time_max): + self.snapshots[time].saveFineGrainedPDB(path=path,topo=topo,base=base, color_nucs = color_nucs) + os.system(pymol + " -r "+default_dir+"/analysis/movieFine.py -- " + + str(self.time_max-self.time_min) + " " + str(self.channel[-1]) + " " + path + " " + str(base)) + + def playCoarseMovie(self, path = default_dir+'/analysis/pdb/', topo = 'linear', pymol = 'pymol', sphere_radius = 0, show_hull = True, repo_path = default_dir): + """Play PyMol movie of the polymer throughout the simulation "timecourse" visualizing the excluded volume of the chain. + See the saveCoarseGrainedPDB method in the `Snapshot` class for more informtion on the calculation. + + This function can determine the simulation "timecourse" trajectory with parallel tempering. + + Parameters + ---------- + path : string, optional + default : "wlcsim/analysis/pdb/" + path to where you want to store the coarse-grained PDB files that PyMol will then read in and visualize + topo : string, optional + default : 'linear' + topology of polymer structure (for the risca lab, it will almost always be 'linear') + pymol : string, optional + default : 'pymol' + exectable command to initiaite PyMol, i.e. "~/Applications/pymol/pymol" + sphere_radius : float, optional + default : 0 + set what size radius to visualize a confining sphere, where 0 equates to no confinement + show_hull : boolean, optional + default : True + whether to construct the hulls of the excluded volume of the chain or not + """ + for time in range(self.time_min,self.time_max): + self.snapshots[time].saveCoarseGrainedPDB(path=path,topo=topo) + if (self.temperature != None): + os.system(pymol + " -r "+repo_path+"/analysis/movieCoarse.py -- " + + str(self.time_max-self.time_min) + " PT " + str(self.temperature) + " " + + path + " " + self.path_to_data + " " + str(show_hull) + " " + str(sphere_radius)) + else: + os.system(pymol + " -r "+repo_path+"/analysis/movieCoarse.py -- " + + str(self.time_max-self.time_min) + " " + str(self.channel[-1]) + " 1 " + + path + " " + self.path_to_data + " " + str(show_hull) + " " + str(sphere_radius)) + +class Chain: + """ + `Chain` object to store all the positions and orientations of the computational beads for a given chain in + a snapshot. This object also calculates different singl-polymer metrics. It is nested within the `Snapshot` object. + + This class contains most of the fields and functions that are useful for wlcsim analysis. Some useful class + fields are: + `r` : wlcsim output bead positions for the specific chain + `u` : wlcsim output bead U orientation vectors for the specific chain + `v` : wlcsim output bead V orientation vectors for the specific chain + `discretization` : discreitzation (in bp) of each computational bead for the specific chain + `wrapped` : how much DNA (in bp) is wrapped around a computational bead, i.e. nucleosome=147 and DNA=1 + `n_beads` : number of coarse-grained computational beads in the specific chain + `end_to_end` : end-to-end distance of the specific chain + `n_bps` : number of DNA basepairs throughout the specific chain (including DNA wrapped around nucleosomes) + `end_to_end_norm` : end-to-end distance normalized by its contour length `n_bps` + `center_r` : center positions (with respect to their excluded volume) of polygons interpolated from `r`. + Includes nucleosome core particle center (hence, len(center_r) = len(r)-2+1) + `n_nucs` : number of nucleosomes on the specific chain + `pair_dist` : nucleosome pairwise distances, i.e. all combinatorics of n choose k, for the specific chain + `reduced_pair_dist` : reduced nucleosome pairwise distances, i.e. n & n+1, n & n+2, etc. + `interpolated` : location of each interpolated phosphate-sugar-phosphate basepair throughout the specific chain + `break_length_s1`, `break_length_b`, `break_length_2` : RICC-seq pairwise fragment lengths using `interpolated` + `break_location_s1`, `break_location_b`, `break_location_s2` : RICC-seq pairwise break locations using `interpolated` + `break_likelihood_s1`, `break_likelihood_b`, `break_likelihood_s2` : RICC-seq pairwise break likelihood using `interpolated` + + """ + def __init__(self,number,time,channel,r,u,v,discretization,wrapped): + """ + `Chain` constructor to read in chain (bead positions and orientations) data from a snapshot. + + This constructor is called through the `Snapshot` class, so you should not have to directly + instantiate any `Chain` objects directly. + + Parameters + ---------- + time : int + "time point" of the current wlcsim output structure + """ + # determine chain number (number is arbitrary and defined during initialization) + self.number = number + # determine time of snapshot + self.time = time + # determine channel + self.channel = channel + # load position and u data of computational beads + self.r = r + self.u = u + self.v = v + self.discretization = discretization + self.wrapped = wrapped + # assign constants from postion data + self.n_beads = len(self.r) + self.end_to_end = np.linalg.norm(self.r[-1,:]-self.r[0,:]) + self.n_bps = int(np.sum(self.discretization)+np.sum(self.wrapped)) + self.end_to_end_norm = self.end_to_end/(self.n_bps*length_per_bp) + # centered beads + self.center_r = None + # pairwise nucleosomes + self.n_nucs = np.sum(self.wrapped>1) + self.n_pair_dist = int(scipy.special.comb(self.n_nucs,2)) + self.pair_dist = None + self.reduced_pair_dist = None + self.ff_coeff = np.zeros(self.n_pair_dist); self.fs_coeff = np.zeros(self.n_pair_dist); self.ss_coeff = np.zeros(self.n_pair_dist) + self.ff_dist = np.nan*np.zeros(self.n_pair_dist); self.fs_dist = np.nan*np.zeros(self.n_pair_dist); self.ss_dist = np.nan*np.zeros(self.n_pair_dist) + # interpolation/ricc-seq stuff + self.interpolated = None + # self.nucleosome_indices = None + self.break_length_s1 = None; self.break_location_s1 = None; self.break_likelihood_s1 = None + self.break_length_b = None; self.break_location_b = None; self.break_likelihood_b = None + self.break_length_s2 = None; self.break_location_s2 = None; self.break_likelihood_s2 = None + self.break_FLD = None; self.break_FLFE = None + + # determine center of beads from regular polygons + def centerBeads(self,nside=16,type='regular'): + """Get the location of the center of each bead with respect to its excluded volume. + + Parameters + ---------- + nside : int, optional + default : 16 + number of sides of the modeled excluded volume + type : string, optional + default : 'regular' + whether the excluded geometry is a regular shape or not (currently can only handle regular shapes) + + Generates + --------- + center_r : center positions of computational beads with respect to their excluded volume + + + To Do + ----- + Need to have the number of sides drawn in from the defines file + + """ + if (type!='regular'): + print('can only find center of beads for regular shapes at the moment.', flush=True) + return 0 + # Initialize empty array then is rows x cols where + # rows = num_beads - 1 (because one polygon center will be inferred between each set of beads, including one nucleosome core position) + # So if each linker for a monomucleosome has 8 beads (16 beads total), 7 polygon centers will be inferred per linker in addition to 1 nuc. core center (7+7+1 = 16 -1) + # cols = 3 dimensions (x, y, and z coordinates) + + self.center_r = np.zeros((self.n_beads-1)*3).reshape([self.n_beads-1,3]) + for i in range(self.n_beads-1): + if (self.wrapped[i]>0): # nucleosome + # make rotation matrix + uin = np.asarray(self.u[i,:]); vin = np.asarray(self.v[i,:]); cross = np.cross(uin, vin) + # Note mat is a rotation matrix. + # It's determinant = 1 and its inverse equals its transpose + mat = np.matrix([vin, cross, uin]).reshape([3,3]).T + # center of nucleosome material frame + # center = np.asarray([4.8455, -2.4445, 0.6694]) + # center recalculted using wlcsim/input/nucleosomeT + # TO DO, make dynamic, y-coord should change with wrapping (wrapping used here is 127) + center = nucleosome_center# value from utility.py # np.asarray([4.1899999999999995, -2.8882080789053335, 0.22996943061202169]) + + # rotate into center of material frame + # helpful source: http://motion.cs.illinois.edu/RoboticSystems/CoordinateTransformations.html + poly = self.r[i,:] + np.matmul(mat, center) + else: # dna + # Take simple average to center linker DNA polygon between adjacent linker DNA beads + poly = (self.r[i,:]+self.r[i+1,:])/2.0 + self.center_r[i,:] = poly + + #ARIANA EDITS + def mononucAlpha(self, num_beads_for_ang = 4): + """ + For mononucleosome structures, get the entry-exit angle (alpha) + + Parameters + ---------- + num_beads_for_ang : int, optional + default : 4 + number of computational beads used to fit vector for each linker segment + type : string, optional + default : 'regular' + whether the excluded geometry is a regular shape or not (currently can only handle regular shapes) + + Generates + --------- + alpha : Entry-exit angle + """ + try: + if (self.interpolated == None): + self.interpolate() + except: + pass + + try: + if (self.center_r == None): + self.centerBeads() + except: + pass + + nuc_pos = int(np.where(self.wrapped > 0)[0]) + positions = self.center_r + # Categorize beads as linker1, linker2, or nucleosome center + linker1, linker2, nuc_center = categorizeLocs(positions, nuc_pos) + linker1 = np.flip(linker1[-num_beads_for_ang:], axis = 0) + linker2 = linker2[:num_beads_for_ang] + + # Get principal components + linker_1_pc = getPrincipalComp(linker1) + linker_2_pc = getPrincipalComp(linker2) + + # Define Orthonormal Vector from entry u and v vectors + vs = self.v[nuc_pos] + us = self.u[nuc_pos] + onm = getOrthoNormal(vs, us) + n_norm = np.sqrt(sum(onm**2)) + + proj_of_pc1_link1_on_onm = linker_1_pc - (np.dot(linker_1_pc, onm)/n_norm**2)*onm + proj_of_pc1_link2_on_onm = linker_2_pc - (np.dot(linker_2_pc, onm)/n_norm**2)*onm + alpha = angle(proj_of_pc1_link1_on_onm, proj_of_pc1_link2_on_onm) + + # "direction" array yields vector perpendicular to the plane defined by proj_of_pc1_link1_on_onm and proj_of_pc1_link2_on_onm + # TO DO THIS IS THROWING MATH DOMAIN ERRORS SOMETIMES NEED TO FIx + direction = np.cross(proj_of_pc1_link1_on_onm, proj_of_pc1_link2_on_onm) + same_dir_test = angle(direction,onm) + v1 = direction + v2 = onm + + if (same_dir_test > 179) & (same_dir_test < 181): # range 179-181 to allow for rounding errors + # Then the vectors are pointing in the opposite way and resulting alphas should be positive + # This corresponds to the state where NCPs are not overly unwrapped + ang_direction_adj = 1 + else: + ang_direction_adj = -1 + alpha = alpha * ang_direction_adj + self.alpha = alpha/2 + return alpha + + + def avgFiberAxisNucleosomeDistance(self): + ''' + Gets the fiber axis by taking PC1 of the + nucleosome centers + ARGS + centers: + OUTPUTS + Pc1: + zero_center: [x, y, z] of the center of + the PC1 line + ''' + try : + if (self.nuc_locs == None): + self.pairwiseNucleosomeDistance() + except: + pass # pairWiseNucleosomeDistance has already been run + + nuc_centers = self.center_r[self.nuc_locs] + + X = np.array(nuc_centers) + zero_center = np.average(X, axis=0) + + pca = PCA(n_components=2) + pca.fit(nuc_centers) + eigen_vecs = pca.components_ + fiber_axis = eigen_vecs[0] + midpt = zero_center + pos_on_pc1 = [get_vector_to_axis(midpt, nuc_centers[i], fiber_axis) for i in range(0,len(nuc_centers))] + rise_per_nucleosome = [np.linalg.norm(pos_on_pc1[i] - pos_on_pc1[i+1]) for i in range(0,len(nuc_centers)-1)] + average_rise_per_nucleosome = np.average(rise_per_nucleosome) + self.rise_per_nuc = average_rise_per_nucleosome + + # determine the pairwise distances between nucleosomes on a chain + def pairwiseNucleosomeDistance(self): + """Get the pairwise distance between the center of each nucleosome on the chain, i.e. n choose k + + Generates + --------- + pair_dist : nucleosome pairwise distances, i.e. all combinatorics of n choose k + """ + try : + if (self.center_r == None): + self.centerBeads() + except: + pass # centerbeads has already been run + self.nuc_locs = np.asarray(np.linspace(0,self.n_beads-1,self.n_beads)[self.wrapped>0],dtype='int') + self.pair_dist = scipy.spatial.distance.pdist(self.center_r[self.nuc_locs,:]) + + # determine the reduced pairwise distances between nucleosomes + # such that n+x where x -> 1..self.n_nucs-1 + def reducedPairwiseNucleosomeDistance(self): + """Get the pairwise distance between the center of each nucleosome on the chain, i.e. rather than + n choose k, average over n & n+1, n & n+2, etc. + + Generates + --------- + reduced_pair_dist : reduced nucleosome pairwise distances, i.e. n & n+1, n & n+2, etc. + """ + try: + if (self.pair_dist == None): + self.pairwiseNucleosomeDistance() + except: + pass # pairwiseNucleosomeDistance has already been run + self.reduced_pair_dist = np.zeros((self.n_nucs-1)).reshape([self.n_nucs-1]) + # sum up distances + iterTemp = 0 + for i in range(self.n_nucs-1): + for j in range(i+1,self.n_nucs): + self.reduced_pair_dist[j-i-1] += self.pair_dist[iterTemp] + iterTemp += 1 + # normalize + for i in range(self.n_nucs-1): + self.reduced_pair_dist[i] /= (self.n_nucs-i-1) + + # determine nucleosome-nucleosome orientation + def pairwiseNucleosomeOrientation(self, cutoff=12): + """Get the pairwise orientation between the center of each nucleosome on the chain, i.e. n choose k + + Parameters + ---------- + cutoff : int + Nanometer distance cutoff between nucleosomes to be considered a contact + Generates + --------- + pair_dist : nucleosome pairwise distances, i.e. all combinatorics of n choose k + """ + try: + if (self.pair_dist == None): + self.pairwiseNucleosomeDistance() + except: + pass # pairwiseNucleosomeDistance has already been run + # check orientation if within cutoff + nucLocs = np.asarray(np.linspace(0,self.n_beads-1,self.n_beads)[self.wrapped>0],dtype='int') + ind = 0 + for i in range(len(nucLocs)): + for j in range(i+1,len(nucLocs)): + if self.pair_dist[ind] <= cutoff: + # create rotation matrices + matI = np.matrix([self.v[nucLocs[i],:], np.cross(self.u[nucLocs[i],:], self.v[nucLocs[i],:]), self.u[nucLocs[i],:]]).T + matJ = np.matrix([self.v[nucLocs[j],:], np.cross(self.u[nucLocs[j],:], self.v[nucLocs[j],:]), self.u[nucLocs[j],:]]).T + # find center of nucs + polyI = self.r[nucLocs[i],:] + np.squeeze(np.asarray(np.matmul(matI, nucleosome_center))) + polyJ = self.r[nucLocs[j],:] + np.squeeze(np.asarray(np.matmul(matJ, nucleosome_center))) + # construct face I normal vector (pointing up through face) + faceItop = self.r[nucLocs[i],:] + np.squeeze(np.asarray(np.matmul(matI, nucleosome_center + np.array([0, nucleosome_height/2, 0])))) + faceIbot = self.r[nucLocs[i],:] + np.squeeze(np.asarray(np.matmul(matI, nucleosome_center + np.array([0, -nucleosome_height/2, 0])))) + faceI = faceItop - faceIbot + # construct face J normal vector (pointing up through face) + faceJtop = self.r[nucLocs[j],:] + np.squeeze(np.asarray(np.matmul(matJ, nucleosome_center + np.array([0, nucleosome_height/2, 0])))) + faceJbot = self.r[nucLocs[j],:] + np.squeeze(np.asarray(np.matmul(matJ, nucleosome_center + np.array([0, -nucleosome_height/2, 0])))) + faceJ = faceJtop - faceJbot + cospsi = np.dot(faceI/np.linalg.norm(faceI), faceJ/np.linalg.norm(faceJ)) + # list of combinatorial face attractions + faceDistList = np.zeros([4,3]) + faceDistList[0, :] = faceItop - faceJbot + faceDistList[1, :] = faceItop - faceJtop + faceDistList[2, :] = faceIbot - faceJbot + faceDistList[3, :] = faceIbot - faceJtop + # find the closest faces to define the face orientation vector + indDist = np.argmin(np.linalg.norm(faceDistList, axis=1)) + distS = faceDistList[indDist, :] + costhetaI = np.dot(distS/np.linalg.norm(distS), faceI/np.linalg.norm(faceI)) + costhetaJ = np.dot(distS/np.linalg.norm(distS), faceJ/np.linalg.norm(faceJ)) + # determine frequency of face-face (histone-histone interaction) + self.ff_coeff[ind] = np.abs(costhetaI)*np.abs(costhetaJ) + self.ff_dist[ind] = np.linalg.norm(distS) + # determine other charactestic angls other than theta + distC = polyI - polyJ + cosphiI = np.dot(distC/np.linalg.norm(distC), faceI/np.linalg.norm(faceI)) + cosphiJ = np.dot(distC/np.linalg.norm(distC), faceJ/np.linalg.norm(faceJ)) + # determine frequency of face-side (histone-DNA wrapping interaction) + temp = np.abs(cosphiI) + np.abs(cosphiJ) + if temp > 1: + temp = 2 - temp + self.fs_coeff[ind] = (1 - np.abs(cospsi))*temp #np.sqrt(cosphiI**2 + cosphiJ**2) + self.fs_dist[ind] = np.linalg.norm(np.linalg.norm(distC) - nucleosome_height/2 - nucleosome_radius) + # determine frequency of face-side (histone-DNA wrapping interaction) + self.ss_coeff[ind] = (1 - np.abs(cosphiI))*(1 - np.abs(cosphiJ)) + self.ss_dist[ind] = np.linalg.norm(np.linalg.norm(distC) - 2*nucleosome_radius) + # increment index + ind += 1 + + # interpolate atoms into coarse grained chain + def interpolate(self): + """Interpolate the phosphate-sugar-phosphate basepair locations between the coarse-grained computational beads. + See the rotate_bead() and DNAhelix() functions in the utility module for more information on the calculations. + + Generates + --------- + interpolated : location of each phosphate-sugar-phosphate basepair throughout the chain + """ + # rotate DNA strand into material frame + self.interpolated = np.zeros(self.n_bps*3*3).reshape([self.n_bps,3,3]) + row = np.zeros(3*3).reshape([3,3]) + indR = 0; leftOver = 0; summedLeftOver = 0 + chain = []; chainNum = 1 + # Make a new quantity that stores the nuclesome entry and exit point + nucleosome_indices = [] + for i in range(self.n_beads): + # self.discretization = bp per bead except for last bead. It is 0 for last bead. + if self.discretization[i] != 0: + # NOT PROPERLY INTERPOLATING TWIST. ADD THIS BACK IN (AND FIX/ADAPT THIS FUNCTION) IF YOU WANT TO INTERPOLATE TWIST/SUPERCOILING + #omega = mc.get_uv_angle(self.v[i], self.v[i + 1]) / self.discretization[i] % 10.5) + #v = omega/default_omega*length_per_bp + Uout, Vout, Rout = rotate_bead(self.u[i,:], self.v[i,:], self.r[i,:], self.discretization[i], self.wrapped[i]) + matIn = np.matrix([self.v[i,:], np.cross(self.u[i,:],self.v[i,:]), self.u[i,:]]).T + mat = np.matrix([Vout, np.cross(Uout,Vout), Uout]).T + # If self.wrapped[i] > 0, then interpolate nucleosomal DNA + if (self.wrapped[i] > 0): # nucleosome + for n_wrap,j in enumerate(np.linspace(summedLeftOver, np.floor(self.wrapped[i])+summedLeftOver, int(np.floor(self.wrapped[i])))): + strand1, base, strand2 = DNAhelix(j,v=0) + Rin = np.asarray(nucleosome_tran[len(nucleosome_tran)-1-n_wrap,:]) + # strand 1 backbone + row[0,:] = self.r[i,:] + np.matmul(matIn,Rin+strand1) + # strand 2 backbone + row[2,:] = self.r[i,:] + np.matmul(matIn,Rin+strand2) + # base + row[1,:] = self.r[i,:] + np.matmul(matIn,Rin+base) + # save atoms + self.interpolated[indR,:,:] = row + indR = indR + 1 + nucleosome_indices = np.append(nucleosome_indices, int(indR)) #added by ABC + chain.extend([str(chainNum)]*3) + # add left over basepairs + leftOver = self.wrapped[i] - np.floor(self.wrapped[i]) + # take care of the leftover basepairs + if (summedLeftOver == 0 and leftOver > 0): + strand1, base, strand2 = DNAhelix(j + 1) + # strand 1 backbone + row[0,:] = Rout + np.matmul(mat, strand1) + # strand 2 backbone + row[2,:] = Rout + np.matmul(mat, strand2) + # base + row[1,:] = Rout + np.matmul(mat, base) + # save atoms + self.interpolated[indR,:,:] = row + indR = indR + 1 + chain.extend([str(chainNum)]*3) + # cumulative sum of left over basepairs + summedLeftOver = (summedLeftOver + leftOver) % 1 + # add the exiting linker from the nucleosome + for j in np.linspace(leftOver, np.floor(self.discretization[i])+leftOver-1, int(np.floor(self.discretization[i]))): + strand1, base, strand2 = DNAhelix(j) + # strand 1 backbone + row[0,:] = Rout + np.matmul(mat, strand1) + # strand 2 backbone + row[2,:] = Rout + np.matmul(mat, strand2) + # base + row[1,:] = Rout + np.matmul(mat, base) + # save atoms + self.interpolated[indR,:,:] = row + indR = indR + 1 + chain.extend([str(chainNum)]*3) + # add left over basepairs + leftOver = self.discretization[i] - np.floor(self.discretization[i]) + # take care of the leftover basepairs + if (summedLeftOver == 0 and leftOver > 0): + strand1, base, strand2 = DNAhelix(j + 1) + # strand 1 backbone + row[0,:] = Rout + np.matmul(mat, strand1) + # strand 2 backbone + row[2,:] = Rout + np.matmul(mat, strand2) + # base + row[1,:] = Rout + np.matmul(mat, base) + # save atoms + self.interpolated[indR,:,:] = row + indR = indR + 1 + chain.extend([str(chainNum)]*3) + # cumulative sum of left over basepairs + summedLeftOver = (summedLeftOver + leftOver) % 1 + else: # dna bead + for j in np.linspace(leftOver, np.floor(self.discretization[i])+leftOver-1, int(np.floor(self.discretization[i]))): + strand1, base, strand2 = DNAhelix(j) + # strand 1 backbone + row[0,:] = Rout + np.matmul(mat, strand1) + # strand 2 backbone + row[2,:] = Rout + np.matmul(mat, strand2) + # base + row[1,:] = Rout + np.matmul(mat, base) + # save atoms + self.interpolated[indR,:,:] = row + indR = indR + 1 + chain.extend([str(chainNum)]*3) + # add left over basepairs + leftOver = self.discretization[i] - np.floor(self.discretization[i]) + # take care of the leftover basepairs + if (summedLeftOver == 0 and leftOver > 0): + strand1, base, strand2 = DNAhelix(j + 1) + # strand 1 backbone + row[0,:] = Rout + np.matmul(mat, strand1) + # strand 2 backbone + row[2,:] = Rout + np.matmul(mat, strand2) + # base + row[1,:] = Rout + np.matmul(mat, base) + # save atoms + self.interpolated[indR,:,:] = row + indR = indR + 1 + chain.extend([str(chainNum)]*3) + # cumulative sum of left over basepairs + summedLeftOver = (summedLeftOver + leftOver) % 1 + else: + chainNum +=1 + # TEMPORARY FIX FOR WERID FLOAT DISCRETIZATION. + # TODO: fix this interpolation problem more permanently + tempInds = np.sum(np.sum(self.interpolated==0,1),1)!=9 + self.interpolated = self.interpolated[tempInds] + self.n_bps = len(self.interpolated) + # Reformat as integers + nucleosome_indices = [int(i) for i in list(nucleosome_indices)] + self.nucleosome_indices = nucleosome_indices + return chain + + # distance constraint ricc-seq + def RICCbreak(self,cutoff=4.03, minFragment = 50): # units in nm or bp + """Determine the RICC-seq break patterns from the interpolated fine-graied polymer structure. + + Parameters + ---------- + cutoff : float, optional + default : 4.03 nm + RICC-seq radiolytic cleavage radius under which there will be simulated breaks + minFragment : integer, optional + default : 50 bp + fragment length under which any breaks are considered noise and thus thrown out + + Generates + --------- + break_length_s1, break_length_b, break_length_2 : RICC-seq pairwise fragment lengths using `interpolated` + break_location_s1, break_location_b, break_location_s2 : RICC-seq pairwise break locations using `interpolated` + break_likelihood_s1, break_likelihood_b, break_likelihood_s2 : RICC-seq pairwise break likelihood using `interpolated` + """ + try : + if (self.interpolated == None): + self.interpolate() + except: + pass # interpolate already run + # figure out combinatorial correlated cleaves + nPair = int(scipy.special.comb(self.n_bps,2)) + indPair = np.zeros(nPair*2).reshape([nPair,2]) + ind = 0 + for i in range(self.n_bps-1): + extension = self.n_bps-i-1 + indPair[ind:ind+extension,0] = int(i) + indPair[ind:ind+extension,1] = np.linspace(i+1,i+extension, extension, dtype='int') + ind += extension + # find 3d distance on both strands and base + pairS1 = scipy.spatial.distance.pdist(self.interpolated[:,0,:]) + pairB = scipy.spatial.distance.pdist(self.interpolated[:,1,:]) + pairS2 = scipy.spatial.distance.pdist(self.interpolated[:,2,:]) + # define exponential + weight = lambda x: np.exp(-x/cutoff) + pairS1 = weight(pairS1); pairB = weight(pairB); pairS2 = weight(pairS2) + indBreakS1 = np.linspace(0,nPair-1,nPair,dtype='int') + indBreakB = np.linspace(0,nPair-1,nPair,dtype='int') + indBreakS2 = np.linspace(0,nPair-1,nPair,dtype='int') + fragBreakS1 = indPair[indBreakS1,1]-indPair[indBreakS1,0] + fragBreakB = indPair[indBreakB,1]-indPair[indBreakB,0] + fragBreakS2 = indPair[indBreakS2,1]-indPair[indBreakS2,0] + noiseIndS1 = fragBreakS1 >= minFragment; noiseIndB = fragBreakB >= minFragment; noiseIndS2 = fragBreakS2 >= minFragment + self.break_length_s1 = fragBreakS1[noiseIndS1]; self.break_location_s1 = indPair[indBreakS1][noiseIndS1]; self.break_likelihood_s1 = pairS1[noiseIndS1] + self.break_length_b = fragBreakB[noiseIndB]; self.break_location_b = indPair[indBreakB][noiseIndB]; self.break_likelihood_b = pairB[noiseIndB] + self.break_length_s2 = fragBreakS2[noiseIndS2]; self.break_location_s2 = indPair[indBreakS2][noiseIndS2]; self.break_likelihood_s2 = pairS2[noiseIndS2] + + def RICCbreakFLD(self, minFragment = 50, maxFragment = 500): + """Create FLD histogram for the RICC-seq break patterns (strand1/strand2/ lengths and likelihoods). + + Parameters + ---------- + minFragment : integer, optional + default : 50 bp + fragment length under which any breaks are considered noise and thus thrown out + maxFragment : intege, optional + default : 500 bp + fragment length over which any breaks are considered noise and thus thrown out + + Generates + --------- + self.break_FLD : RICC break FLD histogram from minFragment to maxFragment size + + """ + try : + if (self.break_length_s1 == None): + self.RICCbreak(minFragment=minFragment) + except: + pass # RICCbreak already run + # create historgram from both strand break information + breaklength = np.transpose(np.hstack([self.break_length_s1, self.break_length_s2])) + breaklike = np.transpose(np.hstack([self.break_likelihood_s1, self.break_likelihood_s2])) + breakhist = np.histogram(breaklength[breaklength <= maxFragment], + bins=np.arange(minFragment,maxFragment + 2), weights=breaklike[breaklength <= maxFragment])[0] + self.break_FLD = breakhist + + def RICCbreakFLFE(self, lengthbias = -0.0039, minFragment = 50, maxFragment=500, startFragment = 148, + genome_norm_file = default_dir + '/analysis/' + 'RICC-BJ-2017_genome-norm.txt'): + """Calculate the FLFE (FLD enrichment over genome average) for the RICC-seq break patterns. + + Parameters + ---------- + lengthbias : float, optional + default : -0.0039 + exponential parameter to quanity a RICC-seq experiment's fragment length bias + minFragment : integer, optional + default : 50 bp + fragment length under which any breaks are considered noise and thus thrown out + maxFragment : integer, optional + default : 500 bp + fragment length over which any breaks are considered noise and thus thrown out + startFragment : integer, optional + default : 148 bp + length of fragment over which has relevant/interesting 3D spatial information encoded + within it; for example, the 80bp RICC peak is strong but not interesting for 3D info. + genome_norm_file : string, optional + default : "wlcsim/analysis/RICC-BJ-2017_genome-norm.txt" + path to where you want to read in the genome average RICC-seq break pattern FLD + + Generates + --------- + self.break_FLFE : RICC break FLFE (FLD enrichment over genome average) from minFragment to maxFragment size + """ + try : + if (self.break_FLD == None): + self.RICCbreakFLD(minFragment=minFragment, maxFragment=maxFragment) + except: + pass # RICCbreak already run + # read in the genome_norm file + genome_norm = np.loadtxt(genome_norm_file); genome_norm = genome_norm[minFragment:maxFragment + 1] + x = np.linspace(minFragment, maxFragment, maxFragment - minFragment + 1) + # maximum normalization of FLFE score + experimental length bias + temp_FLFE = self.break_FLD / np.max(self.break_FLD) * np.exp(lengthbias * x) + # second maximum normalization after length bias correction + temp_FLFE /= np.max(temp_FLFE) + # divide by genome norm from experiment + temp_FLFE /= genome_norm + # look at only relevant fragment lengths + temp_FLFE = temp_FLFE[(startFragment-minFragment):] + temp_FLFE -= np.mean(temp_FLFE) + self.break_FLFE = temp_FLFE + + def RICCmatrix(self, blur = 0, init = 0.0): + """Generate the fragment-break frequency matrix from the interpolated chain. + + Parameters + ---------- + blur : int, optional + default : 20 + Gaussian blur to apply to the frequency matrix to add "noise" and make the matrix less sparse + removeLow : boolean, optional + default : True + whether to remove frequency values less than 1 and replace them as NAN + init : float, optional + default : 0.5 + value to initialize the entries of the frequency matrix with if trying to avoid zeros in cells + + Returns + ------- + mat : matrix + RICC-seq fragment break frequency matrix + """ + self.RICCbreak() + mat = init*np.ones(self.n_bps**2).reshape([self.n_bps,self.n_bps]) + for iterN in range(len(self.break_location_s1)): + j = int(self.break_location_s1[iterN,0]) + k = int(self.break_location_s1[iterN,1]) + mat[j,k] += self.break_likelihood_s1[iterN] + for iterN in range(len(self.break_location_s2)): + j = int(self.break_location_s2[iterN,0]) + k = int(self.break_location_s2[iterN,1]) + mat[j,k] += self.break_likelihood_s2[iterN] + if (blur > 0): + mat = gaussian_filter(mat, sigma=blur) + return mat + + def saveCoarseGrainedPDB(self,path=default_dir+'/analysis/pdb/',topo='linear'): + """Save the coarse-grained wlcsim output in a PDB format. + + Parameters + ---------- + path : string, optional + default : "wlcsim/analysis/pdb/" + path to where you want to store the fine-grained PDB files + topo : string, optional + default : 'linear' + topology of polymer structure (for the risca lab, it will almost always be 'linear') + """ + # make intermediary directory if needed + os.makedirs(path, exist_ok=True) + # save structure + chain = []; connect = [] + chainNum = 1 + for i in range(self.n_beads): + chain.append(chainNum) + if self.discretization[i]==0: + chainNum += 1 + else: + connect.append((i,i+1)) + dna = mkpdb(self.r,topology=topo,chain=chain,connect=connect) + if self.number > 0: + filename = '%scoarse%0.3dv%sf%s.pdb' %(path,self.time,self.channel,self.number) + else: + filename = '%scoarse%0.3dv%s.pdb' %(path,self.time,self.channel) + save_pdb(filename,dna) + + def saveFineGrainedPDB(self,path=default_dir+'/analysis/pdb/',topo='linear',base=3, color_nucs = 0): + """Save the interpolated fine-grained wlcsim structure in a PDB format. + + Parameters + ---------- + path : string, optional + default : "wlcsim/analysis/pdb/" + path to where you want to store the coarse-grained PDB files + topo : string, optional + default : 'linear' + topology of polymer structure (for the risca lab, it will almost always be 'linear') + """ + # make intermediary directory if needed + os.makedirs(path, exist_ok=True) + # interpolate to make fine-grained structure + chain = self.interpolate() + + # define name based on whether or not the bp is a linker or nucleosome + if color_nucs == 1: + num_pdb_beads = len(np.asarray(self.interpolated[:,base,:]).reshape([base*self.n_bps,3])) + nuc_indices = self.nucleosome_indices + jumps = [0] + for ind in range(0, len(nuc_indices)-1): + # If neighboring list values differ by more than 1, mark as a jump between nuc indices and linker dna indices + if nuc_indices[ind+1] - nuc_indices[ind] > 1: + jumps.append(ind+1) + else: + continue + + wrapping = jumps[1]-jumps[0] + gyre_len = int(wrapping/2) + # Divide nucleosome indices into 2 lists based on gyre + gyre1 = [] + gyre2 = [] + for i in range(len(jumps)): + # print(jumps[i]) + gyre1_instance = nuc_indices[jumps[i]:jumps[i]+gyre_len] + gyre2_instance = nuc_indices[jumps[i]+gyre_len: jumps[i]+2*gyre_len] + gyre1.append(gyre1_instance) + gyre2.append(gyre2_instance) + gyre1_indices = [item for sublist in gyre1 for item in sublist] + gyre2_indices = [item for sublist in gyre2 for item in sublist] + atom_names = [] + for i in range(num_pdb_beads): + if i in gyre1_indices: + atom_names.append('G1') + elif i in gyre2_indices: + atom_names.append('G2') + else: + atom_names.append('L1') + # atom_names = ['A2' for item in range(num_pdb_beads)] + + if (base != 3): + dna = mkpdb(np.asarray(self.interpolated[:,base,:]).reshape([base*self.n_bps,3]),topology=topo,chain=chain, Atom = atom_names) + else: + dna = mkpdb(np.asarray(self.interpolated).reshape([base*self.n_bps,3]),topology=topo,chain=chain, Atom = atom_names) + ### End of nucleosome color loop + else: + if (base != 3): + dna = mkpdb(np.asarray(self.interpolated[:,base,:]).reshape([base*self.n_bps,3]),topology=topo,chain=chain) + else: + dna = mkpdb(np.asarray(self.interpolated).reshape([base*self.n_bps,3]),topology=topo,chain=chain) + if self.number > 0: + filename = '%sfine%0.3dv%sf%s.pdb' %(path,self.time,self.channel,self.number) + else: + filename = '%sfine%0.3dv%s.pdb' %(path,self.time,self.channel) + save_pdb(filename,dna) + + def saveRICCbreakFLD(self, minFragment = 50, maxFragment = 500, path=default_dir+'/analysis/data/'): + """Save the RICC-seq break patterns (strand1/strand2/ lengths and likelihoods) to a text file. + + Parameters + ---------- + path : string, optional + default : "wlcsim/analysis/data/" + path to where you want to store the RICC-seq break pattern file + minFragment : integer, optional + default : 50 bp + fragment length under which any breaks are considered noise and thus thrown out + maxFragment : integer, optional + default : 500 bp + fragment length over which any breaks are considered noise and thus thrown out + """ + try : + if (self.break_FLD == None): + self.RICCbreakFLD(minFragment=minFragment, maxFragment=maxFragment) + except: + pass # RICCbreak already run + # make intermediary directory if needed + os.makedirs(path, exist_ok=True) + filename = '%sriccBreakFLD%0.3dv%s.txt' %(path,self.time,self.channel) + np.savetxt(filename, self.break_FLD, fmt='%i') + + def saveRICCbreakFLFE(self, lengthbias = -0.0039, minFragment = 50, maxFragment=500, startFragment = 148, + genome_norm_file = default_dir + '/analysis/' + 'RICC-BJ-2017_genome-norm.txt', path=default_dir+'/analysis/data/'): + """Save the RICC-seq break patterns (strand1/strand2/ lengths and likelihoods) to a text file. + + Parameters + ---------- + path : string, optional + default : "wlcsim/analysis/data/" + path to where you want to store the RICC-seq break pattern file + lengthbias : float, optional + default : -0.0039 + exponential parameter to quanity a RICC-seq experiment's fragment length bias + minFragment : integer, optional + default : 50 bp + fragment length under which any breaks are considered noise and thus thrown out + maxFragment : integer, optional + default : 500 bp + fragment length over which any breaks are considered noise and thus thrown out + startFragment : integer, optional + default : 148 bp + length of fragment over which has relevant/interesting 3D spatial information encoded + within it; for example, the 80bp RICC peak is strong but not interesting for 3D info. + genome_norm_file : string, optional + default : "wlcsim/analysis/RICC-BJ-2017_genome-norm.txt" + path to where you want to read in the genome average RICC-seq break pattern FLD + """ + try : + if (self.break_FLFE == None): + self.RICCbreakFLFE(minFragment=minFragment, startFragment=startFragment, maxFragment=maxFragment, + lengthbias=lengthbias, genome_norm_file=genome_norm_file) + except: + pass # RICCbreak already run + # make intermediary directory if needed + os.makedirs(path, exist_ok=True) + filename = '%sriccBreakFLFE%0.3dv%s.txt' %(path,self.time,self.channel) + np.savetxt(filename, self.break_FLFE, fmt='%f') + + def saveRICCmat(self,path=default_dir+'/analysis/data'): + """Save the RICC-seq fragment break frequency matrix to a text file. + + Parameters + ---------- + path : string, optional + default : "wlcsim/analysis/data/" + path to where you want to store the RICC-seq fragment break frequency matrix file + """ + # make intermediary directory if needed + os.makedirs(path, exist_ok=True) + # create and save matrix + mat = self.RICCmatrix() + if self.number > 0: + filename = '%s/riccMat%0.3dv%sf%s.txt' %(path,self.time,self.channel,self.number) + else: + filename = '%s/riccMat%0.3dv%s.txt' %(path,self.time,self.channel) + with open(filename, 'w') as f: + for i in range(np.shape(mat)[0]): + for j in range(np.shape(mat)[1]): + f.write(str(i) + ' ' + str(j) + ' ' + str(mat[i,j])+ '\n') + +class Snapshot(Chain): + """ + `Snapshot` object to store all the positions and orientations of ALL the computational beads for a given snapshot. + This object also calculates different polymer metrics. It is nested within the `Trajectory` object. + + This class contains most of the fields and functions that are useful for wlcsim analysis. Some useful class + fields are: + `r` : wlcsim output bead positions + `u` : wlcsim output bead U orientation vectors + `v` : wlcsim output bead V orientation vectors + `discretization` : discreitzation (in bp) of each computational bead + `wrapped` : how much DNA (in bp) is wrapped around a computational bead, i.e. nucleosome=147 and DNA=1 + `n_beads` : number of coarse-grained computational beads in polymer + `n_bps` : number of DNA basepairs throughout polymer (including DNA wrapped around nucleosomes) + `energies` : wlcsim defined energetics of the polymer chain (in kT) + + """ + def __init__(self,path_to_data,time,channel): + """ + `Snapshot` constructor to read in snaphot (bead positions and orientations) data. + + This constructor is called through the `Trajectory` class, so you should not have to directly + instantiate any `Snapshot` objects directly. + + Parameters + ---------- + path_to_data : string + path to either the wlcsim/data directory or the top level directory above the nested `trials` + time : int + "time point" of the current wlcsim output structure + channel : int + "channel"/thread value of the current wlcsim output structure + """ + # determine time of snapshot + self.time = time + # determine channel + self.channel = channel + # load position and u data of computational beads + self.r = np.loadtxt('%sr%sv%s' %(path_to_data,self.time,self.channel)) + self.u = np.loadtxt('%su%sv%s' %(path_to_data,self.time,self.channel)) + if (np.shape(self.u)[1]>3): + temp = self.u[:,0:3] + self.v = self.u[:,3:6] + self.u = temp + else: + self.v = None + # load discretization data + try: + disc = np.loadtxt('%sd%sv%s' %(path_to_data,self.time,self.channel)) + self.discretization = disc[:,0]; self.wrapped = disc[:,1] + except: + self.discretization = np.array([10.5]*len(self.r)) # default to 10.5 discretization + self.wrapped = np.array([1]*len(self.r)) # default to all DNA + # assign constants from postion data + self.n_beads = len(self.r) + self.end_to_end = np.linalg.norm(self.r[-1,:]-self.r[0,:]) + self.n_bps = int(np.sum(self.discretization)+np.sum(self.wrapped)) + self.end_to_end_norm = self.end_to_end/(self.n_bps*length_per_bp) + # centered beads + self.center_r = None + self.alpha = None + # pairwise nucleosomes + self.n_nucs = np.sum(self.wrapped>0) + self.n_pair_dist = int(scipy.special.comb(self.n_nucs,2)) + self.pair_dist = None + self.reduced_pair_dist = None + # self.ff_coeff = np.zeros(self.n_pair_dist); self.fs_coeff = np.zeros(self.n_pair_dist); self.ss_coeff = np.zeros(self.n_pair_dist) + # Redid line above to instatiate as nulls so that when the distance is below the cutoff, value is recorded as nan not 0.0 + self.ff_coeff = np.full(self.n_pair_dist, np.nan); self.fs_coeff = np.full(self.n_pair_dist, np.nan); self.ss_coeff = np.full(self.n_pair_dist, np.nan) + self.ff_dist = np.nan*np.zeros(self.n_pair_dist); self.fs_dist = np.nan*np.zeros(self.n_pair_dist); self.ss_dist = np.nan*np.zeros(self.n_pair_dist) + # interpolation/ricc-seq stuff + self.interpolated = None + self.break_length_s1 = None; self.break_location_s1 = None; self.break_distance_s1 = None + self.break_length_b = None; self.break_location_b = None; self.break_distance_b = None + self.break_length_s2 = None; self.break_location_s2 = None; self.break_distance_s2 = None + self.break_FLD = None; self.break_FLFE = None + #ABC EDITS + self.nuc_locs = None + self.nucleosome_indices = None + + # energies + with open('%senergiesv%s' %(path_to_data,self.channel)) as fp: + for i, line in enumerate(fp): + if i == 0: + # get column specifiers + cols = line.strip().split() + else: + temp = line.strip().split() + if int(temp[0]) == self.time: + # get time data + energies = temp + break + cols = cols[2:] # cols = cols[4:] + try: + energies = energies[0:] # energies = energies[2:] + except: + energies = [np.nan]*len(cols) + self.energies = pd.DataFrame([energies],columns=cols) + # load chains in dictionary + self.n_chains = np.sum(self.discretization==0) + self.number = 0 + if self.n_chains > 1: + self.chains = {} + nbeads = int(self.n_beads/self.n_chains) + ind = 0 + for i in range(self.n_chains): + self.chains[i] = Chain(i, self.time, self.channel, + self.r[ind:ind+nbeads,:], self.u[ind:ind+nbeads,:], self.v[ind:ind+nbeads,:], + self.discretization[ind:ind+nbeads], self.wrapped[ind:ind+nbeads]) + ind += nbeads + diff --git a/analysis/RICC-BJ-2017_genome-norm.txt b/analysis/RICC-BJ-2017_genome-norm.txt new file mode 100644 index 00000000..04e8fbea --- /dev/null +++ b/analysis/RICC-BJ-2017_genome-norm.txt @@ -0,0 +1,700 @@ +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0.000411282 +0.000514141 +0.000641015 +0.000838112 +0.00113037 +0.00142166 +0.00188939 +0.00252647 +0.00339231 +0.00425234 +0.00514662 +0.0064618 +0.00800926 +0.00948429 +0.0118777 +0.0152107 +0.0195549 +0.0255368 +0.0321532 +0.0405949 +0.0489303 +0.0572137 +0.0642715 +0.0712517 +0.0796714 +0.0904677 +0.1043 +0.122275 +0.141215 +0.162038 +0.179468 +0.190267 +0.195968 +0.196644 +0.198579 +0.20542 +0.220651 +0.247557 +0.281794 +0.319496 +0.350914 +0.367736 +0.367994 +0.363557 +0.368953 +0.39911 +0.461753 +0.5547 +0.664083 +0.76274 +0.826462 +0.851615 +0.850945 +0.852291 +0.877489 +0.920424 +0.969666 +1 +0.99335 +0.939878 +0.846718 +0.73489 +0.625685 +0.531683 +0.463593 +0.421356 +0.403601 +0.400741 +0.399632 +0.390717 +0.368526 +0.335517 +0.298997 +0.264363 +0.23765 +0.220081 +0.211241 +0.207623 +0.20672 +0.20713 +0.204233 +0.197898 +0.188984 +0.178155 +0.167507 +0.158366 +0.152415 +0.149931 +0.151129 +0.152398 +0.15335 +0.152465 +0.151305 +0.147074 +0.14156 +0.13723 +0.133547 +0.132075 +0.1317 +0.132365 +0.132872 +0.133991 +0.134219 +0.132478 +0.130667 +0.12799 +0.126025 +0.12518 +0.124701 +0.1251 +0.125659 +0.126556 +0.127893 +0.127943 +0.127715 +0.12779 +0.127258 +0.127819 +0.127387 +0.127487 +0.128819 +0.129589 +0.130875 +0.132042 +0.133388 +0.135293 +0.134462 +0.136363 +0.136883 +0.138071 +0.140467 +0.143064 +0.146067 +0.149779 +0.153942 +0.156431 +0.157165 +0.158007 +0.157913 +0.157009 +0.157581 +0.160772 +0.164874 +0.170715 +0.177624 +0.18289 +0.185039 +0.18373 +0.179454 +0.176165 +0.173318 +0.171884 +0.174484 +0.178605 +0.183783 +0.187162 +0.189478 +0.189341 +0.186399 +0.181126 +0.174816 +0.170182 +0.167262 +0.165508 +0.166196 +0.168186 +0.170045 +0.171742 +0.171105 +0.168794 +0.165192 +0.160338 +0.156596 +0.15266 +0.151512 +0.151015 +0.151883 +0.152607 +0.15292 +0.152512 +0.151056 +0.147331 +0.143841 +0.140216 +0.137323 +0.135029 +0.134555 +0.134469 +0.134753 +0.135202 +0.13493 +0.133734 +0.131353 +0.129538 +0.126539 +0.124347 +0.123223 +0.122646 +0.122245 +0.122297 +0.122339 +0.122631 +0.121638 +0.119842 +0.118007 +0.116076 +0.114809 +0.11393 +0.113636 +0.113706 +0.113599 +0.1138 +0.114282 +0.113554 +0.112759 +0.111411 +0.110798 +0.109865 +0.109433 +0.108922 +0.109644 +0.109375 +0.109462 +0.109258 +0.109488 +0.10949 +0.108218 +0.107714 +0.107145 +0.107415 +0.106734 +0.106973 +0.106873 +0.107378 +0.107215 +0.107573 +0.107563 +0.107167 +0.107541 +0.106927 +0.10642 +0.106011 +0.105603 +0.105488 +0.105558 +0.105884 +0.106298 +0.106684 +0.106785 +0.106508 +0.105837 +0.104834 +0.10418 +0.103737 +0.103399 +0.103484 +0.103657 +0.104412 +0.104937 +0.104525 +0.104325 +0.103778 +0.102565 +0.101118 +0.10052 +0.100164 +0.0998031 +0.10059 +0.100678 +0.100886 +0.0998587 +0.10011 +0.0983299 +0.0968925 +0.096012 +0.0953399 +0.0940692 +0.0945286 +0.0943442 +0.0944915 +0.0939529 +0.0935597 +0.092195 +0.0914306 +0.0902388 +0.089401 +0.0886792 +0.0881004 +0.0882236 +0.0877624 +0.0876161 +0.0873759 +0.0864423 +0.0858372 +0.084897 +0.0840084 +0.0836619 +0.0829705 +0.0825416 +0.0827057 +0.0823031 +0.0822229 +0.0818022 +0.0814133 +0.0805678 +0.0801948 +0.0797587 +0.0790298 +0.0789509 +0.0789894 +0.0789367 +0.0791007 +0.0793625 +0.0790982 +0.0786094 +0.0781073 +0.0777632 +0.077827 +0.0780458 +0.0782419 +0.078407 +0.0785724 +0.0784283 +0.0783102 +0.0779788 +0.0777858 +0.0775599 +0.0777967 +0.078142 +0.078408 +0.07878 +0.0789318 +0.0787884 +0.0784383 +0.0784054 +0.0776633 +0.0778385 +0.0770482 +0.0776835 +0.0778427 +0.0785624 +0.0788679 +0.0784148 +0.078214 +0.0772994 +0.0773093 +0.0764846 +0.0757147 +0.0756378 +0.0756806 +0.0756938 +0.0755271 +0.0754482 +0.0748446 +0.0739212 +0.0734739 +0.0721477 +0.0712347 +0.0710105 +0.0703634 +0.0699035 +0.0695185 +0.0697623 +0.0689983 +0.0683144 +0.0673135 +0.0666324 +0.0652502 +0.0645093 +0.0641023 +0.0637125 +0.0631915 +0.0625526 +0.0622483 +0.0614199 +0.0606979 +0.0595841 +0.0589644 +0.0579659 +0.057243 +0.0567822 +0.0561261 +0.0561704 +0.0556014 +0.0549923 +0.0540247 +0.0536955 +0.053052 +0.0524474 +0.0517833 +0.0511517 +0.0506492 +0.0504999 +0.0503311 +0.0495905 +0.0494314 +0.0486021 +0.0481584 +0.0478431 +0.0470749 +0.0469141 +0.0465475 +0.0462209 +0.0461907 +0.0456699 +0.0453255 +0.0448327 +0.0447074 +0.0440976 +0.0436609 +0.0434355 +0.0436005 +0.0430655 +0.0429651 +0.0426439 +0.0422082 +0.0419295 +0.0415814 +0.0415042 +0.0411031 +0.0407565 +0.0404758 +0.0404775 +0.0403273 +0.0401944 +0.0395845 +0.0393854 +0.0391883 +0.0387322 +0.0382293 +0.0380015 +0.0379036 +0.0376278 +0.0373954 +0.0371513 +0.0366559 +0.0366362 +0.0363698 +0.0358339 +0.0354111 +0.0355067 +0.0348861 +0.0346725 +0.0344931 +0.0342618 +0.0340507 +0.0336808 +0.0335096 +0.033134 +0.0326516 +0.0323941 +0.0320473 +0.0318842 +0.0315814 +0.0314212 +0.0310601 +0.0307126 +0.0307777 +0.0302694 +0.0300501 +0.0295226 +0.0294958 +0.0293445 +0.0291316 +0.028645 +0.0285457 +0.0282781 +0.0280497 +0.027807 +0.027411 +0.0272423 +0.0271811 +0.0268764 +0.0268804 +0.0264076 +0.0263099 +0.0262241 +0.0260342 +0.0257913 +0.0254933 +0.0252234 +0.0252466 +0.0249102 +0.024796 +0.024671 +0.0244055 +0.0243734 +0.0240012 +0.0241994 +0.0238076 +0.0238273 +0.0235344 +0.0233183 +0.0233347 +0.0229511 +0.022777 +0.0226502 +0.0227548 +0.0223485 +0.0223525 +0.0220878 +0.0221672 +0.021831 +0.0221488 +0.0217004 +0.0216843 +0.0216703 +0.0215401 +0.0214825 +0.021279 +0.0210731 +0.021049 +0.020891 +0.0207524 +0.0206796 +0.0204535 +0.0203746 +0.0202791 +0.0202678 +0.0202567 +0.0199756 +0.0198666 +0.0197847 +0.0198292 +0.0195801 +0.0196751 +0.0193279 +0.0193953 +0.0190467 +0.0190321 +0.0187984 +0.0188401 +0.0188158 +0.0187726 +0.0184996 +0.0184236 +0.0182134 +0.0183315 +0.0181775 +0.0180153 +0.0178306 +0.0178372 +0.017604 +0.0175255 +0.0174782 +0.0173236 +0.0171849 +0.0170168 +0.0168244 +0.0166101 +0.0165973 +0.0166229 +0.0164884 +0.0165079 +0.0161798 +0.0161408 +0.0159423 +0.0158711 +0.0159555 +0.0156817 +0.0154698 +0.0153378 +0.0151559 +0.0153121 +0.015005 +0.0150199 +0.0149005 +0.0147565 +0.0147356 +0.0144279 +0.0144614 +0.0143191 +0.0143212 +0.0142213 +0.0141144 +0.01397 +0.0138007 +0.0137767 +0.0137976 +0.0135518 +0.0134142 +0.0133248 +0.0132892 +0.0131851 +0.0131721 +0.0130386 +0.0129139 +0.012853 +0.0126893 +0.012744 +0.0125054 +0.012448 +0.0125268 +0.012393 +0.0122048 +0.0121963 +0.0120375 +0.0119908 +0.0117927 +0.011897 +0.0116884 +0.0116109 +0.0114783 +0.0115765 +0.011396 +0.0114036 +0.0113024 +0.0111065 +0.0110202 +0.0109798 +0.0109818 +0.0107953 +0.0108362 +0.0106424 +0.0105902 +0.0104888 +0.0106332 +0.0103872 +0.0103174 +0.010315 +0.0101515 +0.0101883 +0.0101052 +0.0101086 +0.0100059 +0.0100098 +0.00983818 +0.0097655 +0.00973289 +0.00959737 +0.00960053 +0.00955361 +0.00947215 +0.00941306 +0.00934373 +0.00927149 +0.00915458 +0.00916185 +0.00903758 +0.00902537 +0.00896077 +0.00883787 +0.00872848 +0.00876541 +0.00872434 +0.00865319 +0.00865309 +0.00852316 +0.00837864 +0.00843603 +0.00828127 +0.00838464 +0.00822704 +0.00812075 +0.00814124 +0.00803571 +0.00792396 +0.00798355 +0.00784888 +0.00802626 +0.00776789 +0.00770954 +0.00769698 +0.00766687 +0.00763086 +0.00741704 +0.00752567 +0.00738478 +0.00726614 +0.00724386 +0.00722421 +0.00725928 +0.00704432 +0.00709842 +0.00716748 +0.00695367 +0.00686043 +0.00690776 +0.00688153 +0.00674351 diff --git a/analysis/brownian_dynamics/00_Brownian_Dynamics_of_Rouse_Polymer.ipynb b/analysis/brownian_dynamics/00_Brownian_Dynamics_of_Rouse_Polymer.ipynb new file mode 100644 index 00000000..1e14b708 --- /dev/null +++ b/analysis/brownian_dynamics/00_Brownian_Dynamics_of_Rouse_Polymer.ipynb @@ -0,0 +1,264 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Create Brownian Dyanmics Simulation of a Rouse Polymer" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import seaborn as sns\n", + "import numba\n", + "import matplotlib.pyplot as plt\n", + "import os" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import wlcsim\n", + "from wlcsim.bd import rouse, homolog\n", + "from wlcsim.bd import runge_kutta" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "N = int(1e2+1)\n", + "L = 17.475\n", + "b = 0.015\n", + "D = 2e1\n", + "R = 1\n", + "dt = rouse.recommended_dt(N, L, b, D)\n", + "Aex = 0; # no confinement\n", + "N_tot, loop_list = homolog.points_to_loops_list(N, []) # no loops\n", + "# tether_list = np.array([]).astype(int) # no tethered loci" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2.5196008663366337e-05" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dt" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'/ru-auth/local/home/risc_soft/miniconda3/envs/bd2/lib/python3.7/site-packages/bruno_util/__init__.py'" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import bruno_util\n", + "bruno_util.__file__" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "Nhat = L/b; L0 = L/(N-1); Dhat = D*N/Nhat; bhat = np.sqrt(L0*b)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "Nt = 1e6; # total number of equi-space time steps\n", + "Nlin = 1e4; # see docstring of loglinsample\n", + "t = np.arange(0, Nt*dt, dt) # take Nt time steps\n", + "from bruno_util import numpy as bnp\n", + "t_i, i_i = bnp.loglinsample(Nt, Nlin, 0.6)\n", + "t_save = t[t_i]" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(1000001,)" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.shape(t)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "i_i = [np.round(i).astype(int) for i in i_i] # numba workaround" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "#Run Simulation with with_integrator\n", + "# x = rouse.with_integrator(runge_kutta.srk1/runge_kutta.lena4)\n", + "bead_coords= rouse.with_integrator(N, L, b, D, t, integrator = runge_kutta.rk4_thermal_lena)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note the dimensions of `bead_coords` are `len(t)` by `N`(number of beads) by 3 (x,y,z). `bead_coord` contains the x,y,z-coordinates for each of the 101 beads at each timestep " + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(1000001, 101, 3)" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bead_coords.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Save bead_coord in your local directory:" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "local_directory = '/ru-auth/local/home/abrenner/myscratch/bd/bead_coords/'\n", + "file_name = '2021_03_09_rouse_rk4lena.npy'" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/rugpfs/fs0/risc_lab/scratch/abrenner/bd/bead_coords\n" + ] + } + ], + "source": [ + "cd $local_directory" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Subset to the first 100 snapshots" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [], + "source": [ + "subset_bead_coords = bead_coords[:100,:,:]" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "np.save(file_name, subset_bead_coords)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/analysis/brownian_dynamics/01_Brownian_Dynamics_of_WLC_Polymer.ipynb b/analysis/brownian_dynamics/01_Brownian_Dynamics_of_WLC_Polymer.ipynb new file mode 100644 index 00000000..e498ebd2 --- /dev/null +++ b/analysis/brownian_dynamics/01_Brownian_Dynamics_of_WLC_Polymer.ipynb @@ -0,0 +1,281 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Create Brownian Dynamics Simulation of a Worm-Like Chain Polymer" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import seaborn as sns\n", + "import numba\n", + "import matplotlib.pyplot as plt\n", + "import os" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "import wlcsim\n", + "from wlcsim.bd import tsswlc #No need to import the rouse module anymore\n", + "from wlcsim.bd import runge_kutta" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "N = int(1e2+1)\n", + "L = 17.475\n", + "b = 0.015\n", + "D = 2e1\n", + "R = 1\n", + "dt = rouse.recommended_dt(N, L, b, D)\n", + "Aex = 0; # no confinement\n", + "N_tot, loop_list = homolog.points_to_loops_list(N, []) # no loops\n", + "# tether_list = np.array([]).astype(int) # no tethered loci" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2.5196008663366337e-05" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dt" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'/ru-auth/local/home/risc_soft/miniconda3/envs/bd2/lib/python3.7/site-packages/bruno_util/__init__.py'" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import bruno_util\n", + "bruno_util.__file__" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "Nhat = L/b; L0 = L/(N-1); Dhat = D*N/Nhat; bhat = np.sqrt(L0*b)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "Nt = 1e6; # total number of equi-space time steps\n", + "Nlin = 1e4; # see docstring of loglinsample\n", + "t = np.arange(0, Nt*dt, dt) # take Nt time steps\n", + "from bruno_util import numpy as bnp\n", + "t_i, i_i = bnp.loglinsample(Nt, Nlin, 0.6)\n", + "t_save = t[t_i]" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(1000001,)" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.shape(t)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "i_i = [np.round(i).astype(int) for i in i_i] # numba workaround" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "By default, with_integrator uses rouse_f. We need to redirect it to use tsswlc force instead. " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "module 'wlcsim.bd.tsswlc' has no attribute 'with_integrator'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mbead_coords\u001b[0m\u001b[0;34m=\u001b[0m \u001b[0mtsswlc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwith_integrator\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mN\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mL\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mb\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mD\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mt\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mintegrator\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrunge_kutta\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrk4_thermal_lena\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m: module 'wlcsim.bd.tsswlc' has no attribute 'with_integrator'" + ] + } + ], + "source": [ + "bead_coords= tsswlc.with_integrator(N, L, b, D, t, integrator = runge_kutta.rk4_thermal_lena)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note the dimensions of `bead_coords` are `len(t)` by `N`(number of beads) by 3 (x,y,z). `bead_coord` contains the x,y,z-coordinates for each of the 101 beads at each timestep " + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(1000001, 101, 3)" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bead_coords.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Save bead_coord in your local directory:" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "local_directory = '/ru-auth/local/home/abrenner/myscratch/bd/bead_coords/'\n", + "file_name = '2021_03_09_rouse_rk4lena.npy'" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/rugpfs/fs0/risc_lab/scratch/abrenner/bd/bead_coords\n" + ] + } + ], + "source": [ + "cd $local_directory" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Subset to the first 100 snapshots" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [], + "source": [ + "subset_bead_coords = bead_coords[:100,:,:]" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "np.save(file_name, subset_bead_coords)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/analysis/movieCoarse.py b/analysis/movieCoarse.py index d5dba716..522dcb23 100644 --- a/analysis/movieCoarse.py +++ b/analysis/movieCoarse.py @@ -4,7 +4,9 @@ import colorsys import sys from pymol.cgo import * -sys.path.append('../analysis/') +#sys.path.append('../analysis/') +# May need to comment out line below and uncomment line above for general use +sys.path.insert(0, '/ru-auth/local/home/abrenner/mystore/template_wlcsim/wlcsim') from analysis.utility import * # this script is run automatically by MCsim and will need to be changed for someone else's use @@ -26,7 +28,7 @@ side = 16 incr = 2*np.pi/(side/2.0) -for idx in range(0,numFrames): cmd.load(pathPDB+"coarse%03d.pdb"%idx,"snap") +for idx in range(0,numFrames): cmd.load(pathPDB+"coarse%03dv%s.pdb"%(idx,channel[idx]),"snap") cmd.mset("1 -%d" % numFrames) cmd.color('gray80', 'snap') @@ -37,18 +39,20 @@ u = np.loadtxt('/%su%sv%s' %(input_folder,ind,channel[ind])) # load discretization data disc = np.loadtxt('/%sd%sv%s' %(input_folder,ind,channel[ind])) - wrap = disc[0]; bps = disc[1] + bps = disc[:,0]; wrap = disc[:,1] if (hull == 'True'): for i in range(len(r)): if bps[i] != 0: poly = np.zeros(side*3).reshape([side,3]) uin = np.asarray(u[i,0:3]); vin = np.asarray(u[i,3:6]); cross = np.cross(uin, vin) mat = np.matrix([vin, cross, uin]).reshape([3,3]).T - if (wrap[i]>1): + if (wrap[i]>0): space = 0 height = 5.5 radius = 5.2 - center = np.asarray([4.8455, -2.4445, 0.6694]) + #center = np.asarray([4.8455,-2.4445,0.6694]) + #center = np.asarray([4.1900, -2.022154, 0.2300]) + center = nucleosome_center for j in range(int(side/2.0)): # rotate into material frame vec = np.asarray([radius*np.cos(space), -height/2.0, radius*np.sin(space)]) diff --git a/analysis/movieFine.py b/analysis/movieFine.py index 03d944a1..7cec617a 100644 --- a/analysis/movieFine.py +++ b/analysis/movieFine.py @@ -4,14 +4,19 @@ # this script is run automatically by MCsim and will need to be changed for someone else's use numFrames = int(argv[1]) -pathPDB = argv[2] +channel = int(argv[2]) +pathPDB = argv[3] +base = int(argv[4]) -for idx in range(0,numFrames): cmd.load(pathPDB+"fine%03d.pdb"%idx,"snap") +for idx in range(0,numFrames): cmd.load(pathPDB+"fine%03dv%i.pdb"%(idx, channel),"snap") cmd.intra_fit("snap") cmd.mset("1 -%d" % numFrames) cmd.show('spheres', 'resn DNA') #cmd.show('lines', 'resn DNA') cmd.hide('sticks', 'resn DNA') cmd.spectrum('count', 'rainbow', 'resn DNA') -cmd.set("sphere_scale", 0.15) -cmd.mplay() +if base == 1: + cmd.set("sphere_scale", 0.5) +else: + cmd.set("sphere_scale", 0.15) +#cmd.mplay() diff --git a/analysis/utility.py b/analysis/utility.py index 1f3fcebe..44eea1a7 100644 --- a/analysis/utility.py +++ b/analysis/utility.py @@ -3,17 +3,35 @@ from pathlib import Path import numpy as np - +#Modules added by ABC +from pylab import * +from scipy.optimize import curve_fit +from scipy.spatial.distance import squareform +from scipy.optimize import curve_fit +import matplotlib.pyplot as plt # set parameters -length_per_bp = 0.332 # length in nm of 1 bp -default_omega = 2*np.pi/10.5 # default twist of DNA -max_bp_wrapped = 147 +helix_height = 3.4 +bp_per_turn = 10.5 +length_per_bp = helix_height/bp_per_turn # length in nm of 1 bp # changed from 0.332 (presumed typo) +default_omega = 2*np.pi/bp_per_turn # default twist of DNA +max_bp_wrapped = 160 +nucleosome_height = 5.5 # nm +nucleosome_radius = 5.2 # nm +#nucleosome_center = np.array([4.8455, -2.4445, 0.6694]) default_dir = str(Path(__file__).parent / Path('..')) # read in translation and rotation files nucleosome_tran = np.loadtxt('%s/input/nucleosomeT' %(default_dir)) nucleosome_rot = np.loadtxt('%s/input/nucleosomeR' %(default_dir)) +# Get nucleosome center +default_wrap = 127 # to do: make dynamic +nucleosome_tran_sub = nucleosome_tran[-1*default_wrap:] +xmid = (np.min(nucleosome_tran_sub[:,0]) + np.max(nucleosome_tran_sub[:,0]))/2 +ymid = (np.min(nucleosome_tran_sub[:,1]) + np.max(nucleosome_tran_sub[:,1]))/2 +zmid = (np.min(nucleosome_tran_sub[:,2]) + np.max(nucleosome_tran_sub[:,2]))/2 +nucleosome_center = np.array([xmid, ymid, zmid]) + def rotate_bead(Uin, Vin, Rin, link_bp, wrap_bp): """ Rotate and translate computational bead to account for DNA wrapping nucleosome @@ -32,19 +50,35 @@ def rotate_bead(Uin, Vin, Rin, link_bp, wrap_bp): link_bp : float or int discretization of computational bead in bp wrap_bp : int - number of basepairs wrapping bead, i.e. 147 for nucleosomes and 1 for DNA beads + number of basepairs wrapping bead, i.e. 127 for nucleosomes and 1 for DNA beads Returns ---------- Uout, Vout, Rout : list list of the resultant vectors from rotating and translating Uin, Vin, and Rin """ + + # Make a rotational matrix mat = np.matrix([Vin, np.cross(Uin, Vin), Uin]).T - Rout = Rin + np.matmul(mat, nucleosome_tran[max_bp_wrapped - wrap_bp]) - linkRot = np.matrix([[np.cos(default_omega*link_bp), -np.sin(default_omega*link_bp), 0.], + #interpolate for wrap_bp + ind_down = int(np.floor(wrap_bp)) + ind_up = int(np.ceil(wrap_bp)) + if (ind_up == 0): + ratio = 0 + else: + ratio = wrap_bp/ind_up + offratio = 1 - ratio + #max_bp_wrapped - ind_up is equiva + inter_tran = ratio*nucleosome_tran[max_bp_wrapped - ind_up] + offratio*nucleosome_tran[max_bp_wrapped - ind_down] + inter_rot = ratio*nucleosome_rot[(3*(max_bp_wrapped - ind_up)):(3*(max_bp_wrapped - ind_up) + 3),:] \ + + offratio*nucleosome_rot[(3*(max_bp_wrapped - ind_down)):(3*(max_bp_wrapped - ind_down) + 3),:] + Rout = Rin + np.matmul(mat, inter_tran) + + # Rotation matrix to propogate the double helix twist + link_rot = np.matrix([[np.cos(default_omega*link_bp), -np.sin(default_omega*link_bp), 0.], [np.sin(default_omega*link_bp), np.cos(default_omega*link_bp), 0.], [0., 0., 1.]]) - mat = np.matmul(np.matmul(mat, nucleosome_rot[(3*(max_bp_wrapped - wrap_bp)):(3*(max_bp_wrapped - wrap_bp) + 3),:]), linkRot) + mat = np.matmul(np.matmul(mat, inter_rot), link_rot) Uout = mat[: ,2]/np.linalg.norm(mat[:, 2]) Vout = mat[:, 0]/np.linalg.norm(mat[:, 0]) return np.squeeze(np.asarray(Uout)), np.squeeze(np.asarray(Vout)), np.squeeze(np.asarray(Rout)) @@ -110,3 +144,247 @@ def get_uv_angle(u1, u2): bond_angle = np.round(bond_angle, 6) # since bond_angle <=1, we can now take arccos return np.arccos(bond_angle) + +## Added by Ariana: + +### Autocorrelation Analysis +#Input: simulation object with all trials and snapshots (e.g. data=mc.Simulation(...) + +#Autocorrelation +# exponential function +def func(x, a, c, d): + return a*np.exp(-c*x)+d + +def calc_autocorr(data, trial_labels, num_snaps=100, max_lag=30, eq = 10): + num_trials = len(data.returnTrials()) + e2es = np.zeros(shape=(num_trials,num_snaps-eq+1)) +# for i in range(len(trial_labels)): + for i in range(0,num_trials): + print(i) + for snapshot in range(eq,num_snaps+1): +# print(snapshot-eq) + data.trials[trial_labels[i]].snapshots[snapshot].pairwiseNucleosomeDistance() + # Length of pair_dist is ((Num_Nucs)^2)/2 - Num_Nucs + pre = data.trials[trial_labels[i]].snapshots[snapshot].pair_dist +# print(pre) + # Put in square form to see as a Num_Nucs by Num_Nucs + # Grab the last value in the first row of squareform array + e2e = squareform(pre)[0][-1] +# print(e2e) + e2es[i,snapshot-eq] = e2e + + autocorrs_arr = np.zeros(shape=(num_trials,max_lag)) + for trial in range(0,num_trials): + row = int(trial) +# print(row) + snapshots = np.arange(num_snaps) + autocorrs = [] + for lag in range(0,max_lag): + dists_no_lag = e2es[row,:][lag:] + if lag == 0: + dists_with_lag = dists_no_lag + else: + dists_with_lag = e2es[row,:][:-1*lag] + corr = np.corrcoef(dists_no_lag,dists_with_lag)[0, 1] + autocorrs.append(corr) + autocorrs_arr[trial, :] = np.array(autocorrs) + + mean_autocorrelations = autocorrs_arr.mean(axis=0) + return mean_autocorrelations + +def calc_autocorr_all(data, trial_labels, num_snaps=100, max_lag=30, eq = 10): + """ + Modified version of calc_autocorr that returns pearson correlation values for all trials + not just the average between trials + """ + num_trials = len(data.returnTrials()) + e2es = np.zeros(shape=(num_trials,num_snaps-eq+1)) +# for i in range(len(trial_labels)): + for i in range(0,num_trials): + print(i) + for snapshot in range(eq,num_snaps+1): +# print(snapshot-eq) + data.trials[trial_labels[i]].snapshots[snapshot].pairwiseNucleosomeDistance() + # Length of pair_dist is ((Num_Nucs)^2)/2 - Num_Nucs + pre = data.trials[trial_labels[i]].snapshots[snapshot].pair_dist + print(pre) + # Put in square form to see as a Num_Nucs by Num_Nucs + # Grab the last value in the first row of squareform array + e2e = squareform(pre)[0][-1] +# print(e2e) + e2es[i,snapshot-eq] = e2e + + autocorrs_arr = np.zeros(shape=(num_trials,max_lag)) + for trial in range(0,num_trials): + row = int(trial) +# print(row) + snapshots = np.arange(num_snaps) + autocorrs = [] + for lag in range(0,max_lag): + dists_no_lag = e2es[row,:][lag:] + if lag == 0: + dists_with_lag = dists_no_lag + else: + dists_with_lag = e2es[row,:][:-1*lag] + corr = np.corrcoef(dists_no_lag,dists_with_lag)[0, 1] + autocorrs.append(corr) + autocorrs_arr[trial, :] = np.array(autocorrs) + + mean_autocorrelations = autocorrs_arr.mean(axis=0) + return autocorrs_arr, mean_autocorrelations + +def fit_exponential(mean_autocorrelations, max_lag = 30): + ''' Return a, b, and tau such that tau = 1/lambda + And the following function is fit to the data: f(x) = ae^(-lambda * x) + b + The x series is the lag intervals in terms of snapshots + The y series is the Pearson Correlation + ''' + x = np.array(range(0,max_lag)) + y = mean_autocorrelations + popt, pcov = curve_fit(func, x, y) + y_vals_of_fit = func(x, *popt) + lam = popt[1] + tau = 1/lam + a = popt[0] + b = popt[2] + return tau, a, b, y_vals_of_fit + +def plot_auto_corr(filepath, data, trial_labels, num_snaps=100, max_lag=30, eq = 10): + mean_autos = calc_autocorr(data, trial_labels, eq=eq, num_snaps=num_snaps) + tau, a, b, y_vals_of_fit = fit_exponential(mean_autos) + fig, ax = plt.subplots() + ax.scatter(range(0,len(mean_autos)),mean_autos, alpha = 0.5) + ax.plot(range(0,len(mean_autos)),y_vals_of_fit, color='r', linestyle = '-', linewidth = 3) + ax.set_xlabel('Lag Interval [Snapshots]', size=14) + ax.set_ylabel('Pearson Correlation', size=14) + ax.set_title('End-to-End Distance Autocorrelation', size=16) + ax.text(0.75, 0.7,'a$e^{-\lambda x}+b$ \n a='+str(round(a,2))+'\n \N{greek small letter tau}= '+str(round(tau,3))+'\n b= '+str(round(b, 3)), transform = ax.transAxes, size = 12) + plt.savefig(filepath+'.pdf') + plt.show() + return mean_autos, tau, a, b, y_vals_of_fit + +def categorizeLocs(locations, nuc_pos): + ''' + Categorize positions of centered beads, given the index of the nucleosome position. + + Parameters + ---------- + locations (nd.array): centered bead locations. Shape: num beads x 3 + nuc_pos (int): index of nucleosome bead + + + To Do: + Generalize for multinucleosomes, only for mononucleosomes as is. + ''' + linker1 = locations[:nuc_pos] + nuc_center = locations[nuc_pos] + linker2 = locations[(nuc_pos+1):] + return linker1, linker2, nuc_center + +def vectToSeries(vect, spread = 8, j = 100): + """ Take a 3d vector with an x, y, and z coordinate and returns 2 points where inpute are scaled by the spread""" + linepts = vect * np.mgrid[-1*spread:spread:2j][:, np.newaxis] + return linepts + +def getPrincipalComp(vector, print_info=0): + datamean = vector.mean(axis=0) + uu, dd, vv = np.linalg.svd(vector - datamean) + pc1 = vv[0] + # We could stop here, but the PC could be pointing in the negative direction of what is intended + # I think this may depend on the directions of the next two PCs, I am not sure + # Adding test to see if PC1 is pointing in intended direction (same direction as vector) + # If the vector is pointing in the correct direction, the dist1 should be less than dist 2 + # Make a vector of length spread*2 in the dir of pc1 and center it at the mean of the input vector + # If PC1 is already in the correct direction, the distance between + + spread = vectToSeries(pc1, spread = 1) + start_point = spread[0] + datamean + end_point = spread[1] + datamean + + dist1 = np.linalg.norm(start_point-vector[0]) + dist2 = np.linalg.norm(start_point-vector[-1]) + if dist1 < dist2: + pass + elif dist1 > dist2: + pc1 = -1*pc1 + else: + raise ValueError('dist 1 vs dist 2 logic issue') + + return pc1 + +def getOrthoNormal(vin, uin): + """ + Compute the orthonormal vector for the given nucleosome + + Parameters + ---------- + vin : np.ndarrary() of len 3 + v vector of the last linker bead entering the nuclesome core particle (x, y, z directions) + + uin : np.ndarrary() of len 3 + u vector of the last linker bead entering the nuclesome core particle (x, y, z directions) + + Returns + ------- + ortho_norm : np.ndarrary() of len 3 (x, y, z directions) + Orthonormal vector in the direction of the bottom face of the nucleosome (closest to DNA entry) + to the top face of the nuceolsome (closest to DNA exit). In other words, if you use the left hand rule to + wrap the fingers of your left hand in the direction of the DNA wrapping around the nucleosome core particle, + your thumb will be pointing in the direction of the ortho_norm + + """ + # nucleosome_height = 5.5 + # Take the cross product v and u to define the third axis + # which will be used in the rotation matrix + cross = np.cross(vin, uin) + + # mat is a rotation matrix. + # It's determinant = 1 and its inverse equals its transpose + mat = np.matrix([vin, cross, uin]).reshape([3,3]).T + + # Nucleosome center computed from wlcsim/input/nucleosomeT + # TO DO: Change this to new computed values + center = np.asarray([4.1899999999999995, -2.8882080789053335, 0.22996943061202169]) + + # The y-direction is the superhelical axis + # nuc_top represents a point: the center of the top face of the nucleosome + nuc_top = center + np.asarray([0, 0.5 * nucleosome_height, 0]) + # nuc_bottom represents a point: the center of the bottom face of the nucleosome + nuc_bottom = center - np.asarray([0, 0.5 * nucleosome_height, 0]) + # Apply rotation matrix to nucleosome center of the top face, and center of the bottom face + # from the origin. No need to translate in the correct place in 3D space because we just need vector direction + rot_top = np.matmul(mat, nuc_top) + rot_bottom = np.matmul(mat, nuc_bottom) + # Define vector between these two points +# ortho_norm = np.reshape(np.array(rot_top - rot_bottom), (-1,1)) + ortho_norm = np.array(rot_top - rot_bottom).flatten() + return ortho_norm + +def dotproduct(v1, v2): + return sum((a*b) for a, b in zip(v1, v2)) + +def length(v): + return math.sqrt(dotproduct(v, v)) + +def sign(num): + ''' + Return the sign of a number. -1 if the number is negative. 1 if the number is positive + ''' + return -1 if num < 0 else 1 + +def angle(v1, v2): + try: + arccos_input = dotproduct(v1, v2) / (length(v1) * length(v2)) + # arcos() input must be bound between -1 and 1 + # But decimal imprecisions cause the attempt to take arcos of impossible value (e.g. -1.000000002) + # Fix this by taking any values x where abs(x)>1 and forcing them in range + if np.abs(arccos_input) > 1: + arccos_bounds_check = sign(arccos_input) + else: + arccos_bounds_check = arccos_input + ang = math.acos(arccos_bounds_check)*180/np.pi + + except ValueError: + print("Angle computation is throwing an error", flush = True) + ang = np.nan + return ang \ No newline at end of file diff --git a/input/example_defines/LAM_attraction_base.inc b/input/example_defines/LAM_attraction_base.inc index ea1125e8..0cb6715e 100644 --- a/input/example_defines/LAM_attraction_base.inc +++ b/input/example_defines/LAM_attraction_base.inc @@ -346,6 +346,11 @@ ! DEFAULTS COMMENT: ! baseline twist density 0.0 ! TYPE: REAL(DP) +#define WLC_P__NUCLEOSOME_WRAPPING 147 +! VARIABLE COMMENT: ! How many basepairs wrap a nucleosome (this then defines the entry-exit geometry of the nucleosome) +! DEFAULTS COMMENT: ! 147 bp wrapping +! TYPE: REAL(DP) + ! ---------------------------- ! ! Length variables @@ -734,7 +739,7 @@ ! DEFAULTS COMMENT: ! From experience. ! TYPE: INTEGER -#define WLC_P__MOVESPERSTEP_NUCLEOSOMESLIDE 60 +#define WLC_P__MOVESPERSTEP_NUCLEOSOME_SLIDE 60 ! VARIABLE COMMENT: ! how many times each move is done per step ! DEFAULTS COMMENT: ! nucleosome slide (just copying bead slide) ! TYPE: INTEGER @@ -938,7 +943,7 @@ ! DEFAULTS COMMENT: ! Super Reptation ! TYPE: INTEGER -#define WLC_P__MOVEON_NUCLEOSOMESLIDE 0 +#define WLC_P__MOVEON_NUCLEOSOME_SLIDE 0 ! VARIABLE COMMENT: ! Is the move active ! DEFAULTS COMMENT: ! nucleosome slide ! TYPE: INTEGER @@ -1009,7 +1014,7 @@ ! DEFAULTS COMMENT: ! Target ! TYPE: REAL(DP) -#define WLC_P__PDESIRE_NUCLEOSOMESLIDE 0.5_DP +#define WLC_P__PDESIRE_NUCLEOSOME_SLIDE 0.5_DP ! VARIABLE COMMENT: ! desired hit rate ! DEFAULTS COMMENT: ! Target ! TYPE: REAL(DP) @@ -1369,7 +1374,7 @@ ! DEFAULTS COMMENT: ! adapt after at most 1000 steps ! TYPE: INTEGER -#define WLC_P__NADAPT_NUCLEOSOMESLIDE 1000 +#define WLC_P__NADAPT_NUCLEOSOME_SLIDE 1000 ! VARIABLE COMMENT: ! Nunber of steps between adapt ! DEFAULTS COMMENT: ! adapt after at most 1000 steps ! TYPE: INTEGER diff --git a/input/example_defines/MBS_PNAS_2018_baseCase.inc b/input/example_defines/MBS_PNAS_2018_baseCase.inc index 101f3e42..ac1808a3 100644 --- a/input/example_defines/MBS_PNAS_2018_baseCase.inc +++ b/input/example_defines/MBS_PNAS_2018_baseCase.inc @@ -338,6 +338,11 @@ ! DEFAULTS COMMENT: ! baseline twist density 0.0 ! TYPE: REAL(DP) +#define WLC_P__NUCLEOSOME_WRAPPING 147 +! VARIABLE COMMENT: ! How many basepairs wrap a nucleosome (this then defines the entry-exit geometry of the nucleosome) +! DEFAULTS COMMENT: ! 147 bp wrapping +! TYPE: REAL(DP) + ! ---------------------------- ! ! Length variables @@ -726,7 +731,7 @@ ! DEFAULTS COMMENT: ! super-reptation ! TYPE: INTEGER -#define WLC_P__MOVESPERSTEP_NUCLEOSOMESLIDE 60 +#define WLC_P__MOVESPERSTEP_NUCLEOSOME_SLIDE 60 ! VARIABLE COMMENT: ! how many times each move is done per step ! DEFAULTS COMMENT: ! nucleosome slide (just copying bead slide) ! TYPE: INTEGER @@ -930,7 +935,7 @@ ! DEFAULTS COMMENT: ! Super Reptation ! TYPE: INTEGER -#define WLC_P__MOVEON_NUCLEOSOMESLIDE 0 +#define WLC_P__MOVEON_NUCLEOSOME_SLIDE 0 ! VARIABLE COMMENT: ! Is the move active ! DEFAULTS COMMENT: ! nucleosome slide ! TYPE: INTEGER @@ -1001,7 +1006,7 @@ ! DEFAULTS COMMENT: ! Target ! TYPE: REAL(DP) -#define WLC_P__PDESIRE_NUCLEOSOMESLIDE 0.5_DP +#define WLC_P__PDESIRE_NUCLEOSOME_SLIDE 0.5_DP ! VARIABLE COMMENT: ! desired hit rate ! DEFAULTS COMMENT: ! Target ! TYPE: REAL(DP) @@ -1361,7 +1366,7 @@ ! DEFAULTS COMMENT: ! adapt after at most 1000 steps ! TYPE: INTEGER -#define WLC_P__NADAPT_NUCLEOSOMESLIDE 1000 +#define WLC_P__NADAPT_NUCLEOSOME_SLIDE 1000 ! VARIABLE COMMENT: ! Nunber of steps between adapt ! DEFAULTS COMMENT: ! adapt after at most 1000 steps ! TYPE: INTEGER diff --git a/input/example_defines/ThomasSim.inc b/input/example_defines/ThomasSim.inc index fe0ead16..9efc5377 100644 --- a/input/example_defines/ThomasSim.inc +++ b/input/example_defines/ThomasSim.inc @@ -341,6 +341,11 @@ ! DEFAULTS COMMENT: ! baseline twist density 0.0 ! TYPE: REAL(DP) +#define WLC_P__NUCLEOSOME_WRAPPING 147 +! VARIABLE COMMENT: ! How many basepairs wrap a nucleosome (this then defines the entry-exit geometry of the nucleosome) +! DEFAULTS COMMENT: ! 147 bp wrapping +! TYPE: REAL(DP) + ! ---------------------------- ! ! Length variables @@ -728,7 +733,7 @@ ! DEFAULTS COMMENT: ! super-reptation ! TYPE: INTEGER -#define WLC_P__MOVESPERSTEP_NUCLEOSOMESLIDE 60 +#define WLC_P__MOVESPERSTEP_NUCLEOSOME_SLIDE 60 ! VARIABLE COMMENT: ! how many times each move is done per step ! DEFAULTS COMMENT: ! nucleosome slide (just copying bead slide) ! TYPE: INTEGER @@ -932,7 +937,7 @@ ! DEFAULTS COMMENT: ! Super Reptation ! TYPE: INTEGER -#define WLC_P__MOVEON_NUCLEOSOMESLIDE 0 +#define WLC_P__MOVEON_NUCLEOSOME_SLIDE 0 ! VARIABLE COMMENT: ! Is the move active ! DEFAULTS COMMENT: ! nucleosome slide ! TYPE: INTEGER @@ -1003,7 +1008,7 @@ ! DEFAULTS COMMENT: ! Target ! TYPE: REAL(DP) -#define WLC_P__PDESIRE_NUCLEOSOMESLIDE 0.5_DP +#define WLC_P__PDESIRE_NUCLEOSOME_SLIDE 0.5_DP ! VARIABLE COMMENT: ! desired hit rate ! DEFAULTS COMMENT: ! Target @@ -1362,7 +1367,7 @@ ! DEFAULTS COMMENT: ! adapt after at most 1000 steps ! TYPE: INTEGER -#define WLC_P__NADAPT_NUCLEOSOMESLIDE 1000 +#define WLC_P__NADAPT_NUCLEOSOME_SLIDE 1000 ! VARIABLE COMMENT: ! Nunber of steps between adapt ! DEFAULTS COMMENT: ! adapt after at most 1000 steps ! TYPE: INTEGER diff --git a/input/example_defines/risca_nicole.inc b/input/example_defines/risca_nicole.inc index c2b76963..01cb8c7f 100644 --- a/input/example_defines/risca_nicole.inc +++ b/input/example_defines/risca_nicole.inc @@ -131,6 +131,11 @@ ! DEFAULTS COMMENT: ! We care about collisions ! TYPE: LOGICAL +#define WLC_P__GJK_NUC_ONLY .FALSE. +! VARIABLE COMMENT: ! GJK algorithm to model only nucleosomes as convex hulls +! DEFAULTS COMMENT: ! Do not check for sterics via GJK by default. +! TYPE: LOGICAL + #define WLC_P__GJK_POLYGON 16 ! VARIABLE COMMENT: ! sides of polygon to model with GJK (i.e 2*sides) ! DEFAULTS COMMENT: ! octagons seem natural choice for nucleosomes @@ -338,6 +343,10 @@ ! DEFAULTS COMMENT: ! baseline twist density 0.0 ! TYPE: REAL(DP) +#define WLC_P__NUCLEOSOME_WRAPPING 147 +! VARIABLE COMMENT: ! How many basepairs wrap a nucleosome (this then defines the entry-exit geometry of the nucleosome) +! DEFAULTS COMMENT: ! 147 bp wrapping +! TYPE: REAL(DP) ! ---------------------------- ! @@ -588,12 +597,12 @@ ! DEFAULTS COMMENT: ! ! TYPE: REAL(DP) -#define WLC_P__INTERNUCLEOSOME_ON .FALSE. +#define WLC_P__INTERNUCLEOSOME_ON .TRUE. ! VARIABLE COMMENT: ! whether or not to turn internucleosome attraction term on ! DEFAULTS COMMENT: ! toggle on or off ! TYPE: REAL(DP) -#define WLC_P__INTERNUCLEOSOME_ENERGY 1.0_DP +#define WLC_P__INTERNUCLEOSOME_ENERGY 4.0_DP ! VARIABLE COMMENT: ! nucleosome-nucleosome attraction scale-term for energy in kt ! DEFAULTS COMMENT: ! inspired by de pablos group, look at nicoles stuff for motivation ! TYPE: REAL(DP) @@ -726,7 +735,12 @@ ! DEFAULTS COMMENT: ! From experience. ! TYPE: INTEGER -#define WLC_P__MOVESPERSTEP_NUCLEOSOMESLIDE 60 +#define WLC_P__MOVESPERSTEP_NUCLEOSOME_SLIDE 60 +! VARIABLE COMMENT: ! how many times each move is done per step +! DEFAULTS COMMENT: ! nucleosome slide (just copying bead slide) +! TYPE: INTEGER + +#define WLC_P__MOVESPERSTEP_NUCLEOSOME_BREATHE 10 ! VARIABLE COMMENT: ! how many times each move is done per step ! DEFAULTS COMMENT: ! nucleosome slide (just copying bead slide) ! TYPE: INTEGER @@ -930,11 +944,16 @@ ! DEFAULTS COMMENT: ! Super Reptation ! TYPE: INTEGER -#define WLC_P__MOVEON_NUCLEOSOMESLIDE 0 +#define WLC_P__MOVEON_NUCLEOSOME_SLIDE 0 ! VARIABLE COMMENT: ! Is the move active ! DEFAULTS COMMENT: ! nucleosome slide ! TYPE: INTEGER +#define WLC_P__MOVEON_NUCLEOSOME_BREATHE 0 +! VARIABLE COMMENT: ! Is the move active +! DEFAULTS COMMENT: ! nucleosome angle +! TYPE: INTEGER + ! ---------------------------- ! ! MC Optimization @@ -1000,7 +1019,11 @@ ! VARIABLE COMMENT: ! Desired Monte-Carlo acceptance probability for move. ! DEFAULTS COMMENT: ! Target -#define WLC_P__PDESIRE_NUCLEOSOMESLIDE 0.5_DP +#define WLC_P__PDESIRE_NUCLEOSOME_SLIDE 0.5_DP +! VARIABLE COMMENT: ! desired hit rate +! DEFAULTS COMMENT: ! Target + +#define WLC_P__PDESIRE_NUCLEOSOME_BREATHE 0.5_DP ! VARIABLE COMMENT: ! desired hit rate ! DEFAULTS COMMENT: ! Target @@ -1179,6 +1202,11 @@ ! DEFAULTS COMMENT: None ! TYPE: REAL(DP) +#define WLC_P__MINAMP_NUCLEOSOME_BREATHE NAN +! VARIABLE COMMENT: ! minium amplitude +! DEFAULTS COMMENT: None +! TYPE: REAL(DP) + #define WLC_P__MAXAMP_CRANK_SHAFT 1.0_DP*PI ! VARIABLE COMMENT: ! Maximum acceptable amplitude range for this move. ! DEFAULTS COMMENT: None @@ -1244,6 +1272,11 @@ ! DEFAULTS COMMENT: None ! TYPE: REAL(DP) +#define WLC_P__MAXAMP_NUCLEOSOME_BREATHE NAN +! VARIABLE COMMENT: ! maximum amplitude +! DEFAULTS COMMENT: None +! TYPE: REAL(DP) + #define WLC_P__WINTARGET_CRANK_SHAFT 8.0_DP ! VARIABLE COMMENT: ! Target for ratio of average window to amplitude range for this move. ! DEFAULTS COMMENT: None @@ -1359,7 +1392,12 @@ ! DEFAULTS COMMENT: ! adapt after at most 1000 steps ! TYPE: INTEGER -#define WLC_P__NADAPT_NUCLEOSOMESLIDE 1000 +#define WLC_P__NADAPT_NUCLEOSOME_SLIDE 1000 +! VARIABLE COMMENT: ! Nunber of steps between adapt +! DEFAULTS COMMENT: ! adapt after at most 1000 steps +! TYPE: INTEGER + +#define WLC_P__NADAPT_NUCLEOSOME_BREATHE 1000 ! VARIABLE COMMENT: ! Nunber of steps between adapt ! DEFAULTS COMMENT: ! adapt after at most 1000 steps ! TYPE: INTEGER diff --git a/input/example_defines/sedona_base.inc b/input/example_defines/sedona_base.inc index 25d3b90a..4b82a930 100644 --- a/input/example_defines/sedona_base.inc +++ b/input/example_defines/sedona_base.inc @@ -340,6 +340,11 @@ ! DEFAULTS COMMENT: ! baseline twist density 0.0 ! TYPE: REAL(DP) +#define WLC_P__NUCLEOSOME_WRAPPING 147 +! VARIABLE COMMENT: ! How many basepairs wrap a nucleosome (this then defines the entry-exit geometry of the nucleosome) +! DEFAULTS COMMENT: ! 147 bp wrapping +! TYPE: REAL(DP) + ! ---------------------------- ! ! Length variables @@ -728,7 +733,7 @@ ! DEFAULTS COMMENT: ! super-reptation ! TYPE: INTEGER -#define WLC_P__MOVESPERSTEP_NUCLEOSOMESLIDE 60 +#define WLC_P__MOVESPERSTEP_NUCLEOSOME_SLIDE 60 ! VARIABLE COMMENT: ! how many times each move is done per step ! DEFAULTS COMMENT: ! nucleosome slide (just copying bead slide) ! TYPE: INTEGER @@ -932,7 +937,7 @@ ! DEFAULTS COMMENT: ! Super Reptation ! TYPE: INTEGER -#define WLC_P__MOVEON_NUCLEOSOMESLIDE 0 +#define WLC_P__MOVEON_NUCLEOSOME_SLIDE 0 ! VARIABLE COMMENT: ! Is the move active ! DEFAULTS COMMENT: ! nucleosome slide ! TYPE: INTEGER @@ -1003,7 +1008,7 @@ ! DEFAULTS COMMENT: ! Target ! TYPE: REAL(DP) -#define WLC_P__PDESIRE_NUCLEOSOMESLIDE 0.5_DP +#define WLC_P__PDESIRE_NUCLEOSOME_SLIDE 0.5_DP ! VARIABLE COMMENT: ! desired hit rate ! DEFAULTS COMMENT: ! Target ! TYPE: REAL(DP) @@ -1363,7 +1368,7 @@ ! DEFAULTS COMMENT: ! adapt after at most 1000 steps ! TYPE: INTEGER -#define WLC_P__NADAPT_NUCLEOSOMESLIDE 1000 +#define WLC_P__NADAPT_NUCLEOSOME_SLIDE 1000 ! VARIABLE COMMENT: ! Nunber of steps between adapt ! DEFAULTS COMMENT: ! adapt after at most 1000 steps ! TYPE: INTEGER diff --git a/input/example_defines/simple_DNA.inc b/input/example_defines/simple_DNA.inc index 013fb316..e5d0e201 100644 --- a/input/example_defines/simple_DNA.inc +++ b/input/example_defines/simple_DNA.inc @@ -337,6 +337,11 @@ ! DEFAULTS COMMENT: ! baseline twist density 0.05 ! TYPE: REAL(DP) +#define WLC_P__NUCLEOSOME_WRAPPING 147 +! VARIABLE COMMENT: ! How many basepairs wrap a nucleosome (this then defines the entry-exit geometry of the nucleosome) +! DEFAULTS COMMENT: ! 147 bp wrapping +! TYPE: REAL(DP) + ! ---------------------------- ! ! Length variables @@ -724,7 +729,7 @@ ! DEFAULTS COMMENT: ! super-reptation ! TYPE: INTEGER -#define WLC_P__MOVESPERSTEP_NUCLEOSOMESLIDE 60 +#define WLC_P__MOVESPERSTEP_NUCLEOSOME_SLIDE 60 ! VARIABLE COMMENT: ! how many times each move is done per step ! DEFAULTS COMMENT: ! nucleosome slide (just copying bead slide) ! TYPE: INTEGER @@ -928,7 +933,7 @@ ! DEFAULTS COMMENT: ! Super Reptation ! TYPE: INTEGER -#define WLC_P__MOVEON_NUCLEOSOMESLIDE 0 +#define WLC_P__MOVEON_NUCLEOSOME_SLIDE 0 ! VARIABLE COMMENT: ! Is the move active ! DEFAULTS COMMENT: ! nucleosome slide ! TYPE: INTEGER @@ -999,7 +1004,7 @@ ! DEFAULTS COMMENT: ! Target ! TYPE: REAL(DP) -#define WLC_P__PDESIRE_NUCLEOSOMESLIDE 0.5_DP +#define WLC_P__PDESIRE_NUCLEOSOME_SLIDE 0.5_DP ! VARIABLE COMMENT: ! desired hit rate ! DEFAULTS COMMENT: ! Target ! TYPE: REAL(DP) @@ -1359,7 +1364,7 @@ ! DEFAULTS COMMENT: ! adapt after at most 1000 steps ! TYPE: INTEGER -#define WLC_P__NADAPT_NUCLEOSOMESLIDE 1000 +#define WLC_P__NADAPT_NUCLEOSOME_SLIDE 1000 ! VARIABLE COMMENT: ! Nunber of steps between adapt ! DEFAULTS COMMENT: ! adapt after at most 1000 steps ! TYPE: INTEGER diff --git a/input/nucleosomeR b/input/nucleosomeR index e2fd6e0e..1968b807 100644 --- a/input/nucleosomeR +++ b/input/nucleosomeR @@ -1,3 +1,45 @@ +0.8734590841341232 0.4868975542591877 -4.877238684398718e-16 +-0.4868975542591877 0.8734590841341232 -1.2338267791434357e-17 +4.2697307420097743e-16 2.3573821041880733e-16 0.9999999999999999 +0.4286576802125755 0.9000834972187725 -0.0781171634738313 +-0.9028520225603215 0.4299513268144804 -0.0002862327805576559 +0.033328944680414446 0.07065093491873849 0.9969441442937502 +-0.17027957344560635 0.9730087155893311 -0.15575270865825308 +-0.984998211261708 -0.17256076315841143 -0.0011431664019563427 +-0.02798911714253027 0.15322148154024273 0.9877954175416054 +-0.6914281236762875 0.6840353651926221 -0.23242798660076366 +-0.7028578185036696 -0.7113257376812622 -0.002565517583460795 +-0.1670869137836694 0.16158995661242204 0.9726102246862532 +-0.9389133102252125 0.15421025137882977 -0.3076702687157337 +-0.1606199509781988 -0.9870058655917296 -0.004544517057057327 +-0.30437317100837685 0.045151075925153765 0.9514821874912355 +-0.8308965377175418 -0.40550956763431784 -0.38101566131332476 +0.4411980793523317 -0.8973819134938577 -0.0070679636329070965 +-0.33905043634364374 -0.1739761244858934 0.9245415673316445 +-0.42804112072435685 -0.7826020584375614 -0.45201196565835317 +0.8797492848767722 -0.4753301750345559 -0.01012029942373875 +-0.2069347595930763 -0.40198910785108355 0.8919544620894305 +0.09803097171669573 -0.8483864420028299 -0.5202214659258682 +0.9923060245083613 0.12305095402871233 -0.013682705764397325 +0.07562196974882199 -0.5148775657750126 0.8539217821047227 +0.5405124800175409 -0.6044498029895436 -0.5852236278647583 +0.7367224001374134 0.6759627490263989 -0.01773321923517228 +0.40630821315973453 -0.42156232943015154 0.8106780114967767 +0.7430949780255891 -0.17232357538054946 -0.6466176915312581 +0.20743834703242084 0.9779950966573744 -0.02224686707358385 +0.6362225914046169 -0.117601769893981 0.7624897624914034 +0.6585190444484547 0.26589709923114696 -0.7040251421072657 +-0.39913531591771584 0.9164886179870423 -0.027195821139768053 +0.6379997395657456 0.29891026365894946 0.7096541316679399 +0.3567522934159376 0.5473019630015702 -0.7570920435700644 +-0.8572968461462809 0.5137924124721014 -0.03254956948621248 +0.3711737042546367 0.6606647547589668 0.6524968682600443 +-0.016930489536587448 0.5923658090208539 -0.8054912208256032 +-0.9960183840004794 -0.08051332256573167 -0.038275104474059574 +-0.0875256377133308 0.8016360478374807 0.5913703658033425 +-0.31152077765817965 0.426945403136036 -0.8489242768517405 +-0.7629971614189717 -0.6448794855631259 -0.04433712627617556 +-0.5663833831900742 0.6339148774408482 0.5266514895121058 -0.4342885913498671 0.15622238982734812 -0.8871234324151178 -0.24474180849679034 -0.9682619137169162 -0.05069826051232343 -0.866888035790706 0.19509851706737052 0.4587392527798819 @@ -7,27 +49,27 @@ -0.22248486010186952 -0.23207472899640255 -0.9469117209046986 0.8381183686908293 -0.5417021070180142 -0.06415938992280662 -0.4980543013452192 -0.8078985997100688 0.31502661077762206 --0.05713539835151068 -0.24383501342545016 -0.9681322391507394 -0.9962515823959575 0.04916000088998264 -0.07117639275804642 -0.0649486784220046 -0.9685699667759202 0.24011224173483442 -0.04197508656155473 -0.17661878983908463 -0.9833839002057778 -0.7795794920006401 0.6213861047982127 -0.07832703502449577 -0.6248951174078525 -0.7633381372887653 0.1637711219975737 +-0.05713539835151069 -0.2438350134254502 -0.9681322391507394 +0.9962515823959576 0.049160000889982625 -0.07117639275804642 +0.06494867842200458 -0.9685699667759203 0.24011224173483442 +0.04197508656155474 -0.1766187898390846 -0.9833839002057778 +0.77957949200064 0.6213861047982127 -0.07832703502449577 +0.6248951174078525 -0.7633381372887652 0.1637711219975737 0.0605286568759464 -0.10552616494349633 -0.9925726725077172 0.26922953324293153 0.9592672763475737 -0.08556723063475195 0.9611720658272308 -0.26205060778602596 0.08647391995502009 0.04014123971828824 -0.08417766589523511 -0.9956419042197395 -0.3425073795664493 0.9349155778163367 -0.09285234137526872 0.9386572195516332 0.3447419076944017 0.008697198561690486 -0.04389656794583904 -0.11345739779082069 -0.9925726725077171 +0.04389656794583905 -0.11345739779082067 -0.9925726725077171 -0.8243949833097693 0.5570865302423348 -0.10013745211578552 0.5643102008791453 0.8226676222564564 -0.06907952283163912 0.1108165085118572 -0.1437908420495356 -0.9833839002057777 --0.9937196814172287 -0.03148389322913786 -0.1073776477260417 --0.015520831333505916 0.9891071520365332 -0.1463767248741927 -0.22543192209443613 -0.10908902794407763 -0.9681322391507393 --0.785900172240649 -0.6076546634919494 -0.11452828999249103 --0.5757962901694718 0.7866736260474874 -0.22271784461145344 +-0.9937196814172287 -0.031483893229137846 -0.1073776477260417 +-0.015520831333505902 0.9891071520365332 -0.1463767248741927 +0.22543192209443613 -0.10908902794407765 -0.9681322391507393 +-0.7859001722406489 -0.6076546634919495 -0.11452828999249103 +-0.5757962901694718 0.7866736260474874 -0.2227178446114535 0.320375102901612 0.026795265516210004 -0.9469117209046984 -0.2795877963982486 -0.9523956141733291 -0.12154529282773083 -0.9050914083925186 0.30368504712830885 -0.29763221365424103 @@ -44,14 +86,14 @@ 0.7829672737646498 0.6043399437922101 -0.14742957827647785 0.42987863678827887 -0.6969619394277933 -0.5739759686799613 -0.6498327071888967 0.06729851581167179 -0.757092043570064 -0.2766822217932147 0.9486782697124257 -0.15315511326432493 +0.2766822217932148 0.9486782697124257 -0.15315511326432493 0.7079296580954352 -0.308999110589309 -0.6351024711366631 --0.6211232942888735 -0.3443173718716244 -0.7040251421072653 --0.3351715078990933 0.9287276248090753 -0.15850886161076938 -0.7084249526833352 0.13751562218130525 -0.6922597345445588 --0.3338496821398629 -0.6858789621601612 -0.6466176915312576 --0.8176162473257527 0.5520735590508502 -0.16345781567695356 -0.469092807282382 0.47411479059720074 -0.745095365368022 +-0.6211232942888733 -0.34431737187162437 -0.7040251421072653 +-0.3351715078990932 0.928727624809075 -0.15850886161076935 +0.7084249526833352 0.13751562218130536 -0.6922597345445586 +-0.333849682139863 -0.6858789621601613 -0.6466176915312575 +-0.8176162473257527 0.5520735590508501 -0.16345781567695356 +0.4690928072823819 0.47411479059720074 -0.745095365368022 0.1294438194908155 -0.8004733618206422 -0.5852236278647577 -0.9851159457031352 -0.03649878033474423 -0.16797146351536513 0.11309673344993978 0.5982559954147014 -0.7932836143733953 @@ -70,75 +112,75 @@ -0.09628852017136813 0.9678356017051262 -0.2324279866007628 0.9816204197824944 0.0536786516964209 -0.18313916516707657 -0.16477218317800935 -0.24579025697559834 -0.9552158275628715 --0.6488731998085723 0.7447849785782485 -0.15575270865825228 -0.759825109820015 0.6233801802833602 -0.18456151634858103 --0.040365493397044025 -0.23810184063564724 -0.9704010204182236 --0.9692165924788595 0.23348855568201007 -0.07811716347383046 +-0.6488731998085723 0.7447849785782485 -0.15575270865825222 +0.7598251098200149 0.6233801802833602 -0.18456151634858103 +-0.04036549339704404 -0.23810184063564718 -0.9704010204182236 +-0.9692165924788595 0.23348855568201007 -0.07811716347383045 0.24424258034849178 0.9518222314883388 -0.18541844996997975 -0.031060566774913034 -0.19879017583896896 -0.9795497471703685 --0.9281441630107774 -0.3722209191716974 3.6579290132990386e-16 --0.3657463606859948 0.911999654851619 -0.18570468275053734 -0.06912316770789315 -0.17236071733867955 -0.982605602876618 +0.03106056677491302 -0.19879017583896896 -0.9795497471703685 +-0.9281441630107775 -0.3722209191716974 3.6579290132990386e-16 +-0.3657463606859948 0.9119996548516192 -0.18570468275053734 +0.06912316770789315 -0.17236071733867958 -0.982605602876618 -0.5393209865670098 -0.8384691897852836 0.07811716347383116 -0.834224685989899 0.5193160614652551 -0.18541844996997972 0.11490015984950458 -0.16516732753491364 -0.9795497471703684 0.045536198479174596 -0.986745939121962 0.15575270865825294 -0.9800041125509976 -0.0743571520853523 -0.184561516348581 0.1936966546205612 -0.14423406518597884 -0.9704010204182235 -0.5991181000468649 -0.7661819191555945 0.23242798660076355 --0.7467057471090695 -0.6394455202878452 -0.18313916516707657 -0.28894295186164565 -0.06383332470471201 -0.9552158275628714 +0.5991181000468648 -0.7661819191555945 0.23242798660076355 +-0.7467057471090696 -0.6394455202878451 -0.18313916516707657 +0.28894295186164565 -0.06383332470471204 -0.9552158275628714 0.9117831913148071 -0.27201179714154683 0.3076702687157336 -0.2245151189936182 -0.9574831359920616 -0.18116016569348006 0.3438667959822047 0.09610216702360909 -0.9340877903678536 0.8756058265117882 0.29688634595174357 0.38101566131332465 0.38477526106195814 -0.905558899827941 -0.1786367191176303 0.29199732028446845 0.30302075263887596 -0.9071471702082626 -0.5238137693545817 0.7220140704558444 0.4520119656583531 -0.8458342788545542 -0.5037206537817803 -0.17558438332679863 -0.10091336754435204 0.4743007326764727 -0.8745600649660488 -0.010328284076864258 0.8539689414363784 0.5202214659258682 -0.9806998437979252 0.0929314575830236 -0.17202197698614005 --0.19524636468511522 0.511957802219603 -0.836527384981341 --0.4595111985581261 0.6681038570375758 0.5852236278647582 -0.7373622529960069 0.654280135187642 -0.1679714635153651 --0.4951225770012182 0.3543370442253469 -0.7932836143733949 +0.5238137693545817 0.7220140704558443 0.4520119656583531 +0.8458342788545541 -0.5037206537817803 -0.17558438332679863 +0.10091336754435207 0.47430073267647266 -0.8745600649660488 +0.010328284076864251 0.8539689414363784 0.5202214659258682 +0.9806998437979252 0.09293145758302361 -0.17202197698614005 +-0.19524636468511525 0.511957802219603 -0.836527384981341 +-0.459511198558126 0.6681038570375758 0.5852236278647582 +0.7373622529960069 0.6542801351876419 -0.1679714635153651 +-0.4951225770012181 0.35433704422534695 -0.7932836143733949 -0.7152486160765689 0.26515085932227306 0.6466176915312581 0.20960251574722352 0.9640271406379358 -0.16345781567695353 -0.6666979845424674 0.018619718421773956 -0.7450953653680217 --0.6869178645394021 -0.18025661335294196 0.7040251421072656 +-0.6869178645394021 -0.1802566133529419 0.7040251421072656 -0.39940719874854175 0.9029666828730175 -0.1585088616107693 --0.6071389766474151 -0.39007527858584834 -0.6922597345445581 --0.4232662614746038 -0.49765179539535065 0.7570920435700644 --0.855503087439252 0.49462913244460194 -0.15315511326432488 --0.2982618636018022 -0.7125199729669931 -0.6351024711366625 --0.05831302785556766 -0.5897317050618824 0.8054912208256032 --0.9835778173656091 -0.10411146255587878 -0.1474295782764778 -0.1708047656496154 -0.8008603619915775 -0.5739759686799606 -0.2548736230941967 -0.4629978492634569 0.8489242768517405 --0.7346122834337524 -0.6635962680762424 -0.14136755647436183 -0.6287958566013976 -0.58759934017381 -0.5092570923887241 +-0.6071389766474151 -0.3900752785858483 -0.6922597345445581 +-0.4232662614746038 -0.49765179539535054 0.7570920435700644 +-0.8555030874392519 0.49462913244460194 -0.15315511326432488 +-0.2982618636018021 -0.7125199729669929 -0.6351024711366625 +-0.05831302785556765 -0.5897317050618825 0.8054912208256032 +-0.9835778173656091 -0.10411146255587876 -0.1474295782764778 +0.17080476564961536 -0.8008603619915774 -0.5739759686799606 +0.25487362309419676 -0.46299784926345694 0.8489242768517405 +-0.7346122834337525 -0.6635962680762425 -0.14136755647436183 +0.6287958566013976 -0.58759934017381 -0.5092570923887242 0.4109759719804125 -0.21002563204231803 0.8871234324151178 --0.20408343937978096 -0.9695995130595708 -0.13500642223821396 -0.888509257253786 -0.12556280563872585 -0.4413448556565002 -0.38979320932893424 0.043947544741090194 0.9198531770191802 -0.40503256225045703 -0.9052435109432199 -0.12838539407589153 -0.8270488966668652 0.42261424397010344 -0.3706579600058502 -0.2501143501802519 0.2019925856243553 0.9469117209046986 -0.8601720332731324 -0.4953088076808108 -0.12154529282773077 -0.44446246749154816 0.8449072022338318 -0.29763221365424036 +-0.2040834393797809 -0.9695995130595706 -0.13500642223821396 +0.8885092572537859 -0.12556280563872588 -0.4413448556565002 +0.3897932093289343 0.04394754474109022 0.9198531770191802 +0.40503256225045703 -0.9052435109432199 -0.12838539407589156 +0.8270488966668652 0.4226142439701035 -0.3706579600058503 +0.25011435018025197 0.2019925856243553 0.9469117209046986 +0.8601720332731323 -0.4953088076808109 -0.12154529282773077 +0.4444624674915483 0.8449072022338316 -0.29763221365424036 0.08759045953381071 0.23462284397652156 0.9681322391507394 0.987988322396757 0.10374172544852664 -0.11452828999249094 -0.12730666206564936 0.9665349323668189 -0.22271784461145275 --0.01924258260469977 0.18051545039351646 0.9833839002057778 -0.7401168878869882 0.6638501585699154 -0.10737764772604164 --0.6722028825281702 0.7257528085622019 -0.14637672487419198 +-0.019242582604699757 0.18051545039351646 0.9833839002057778 +0.7401168878869882 0.6638501585699152 -0.10737764772604164 +-0.6722028825281701 0.7257528085622019 -0.14637672487419198 -0.04666034658647407 0.11234901800780542 0.9925726725077172 0.21103917633916786 0.9723347966281183 -0.10013745211578545 -0.9763632920724311 0.20479927104078616 -0.0690795228316384 --0.02914427365166569 0.0885878652807919 0.9956419042197395 --0.39837963592068065 0.9125086894845641 -0.09285234137526865 --0.9167574799242287 -0.3993495733566717 0.008697198561691212 +-0.029144273651665695 0.0885878652807919 0.9956419042197395 +-0.3983796359206807 0.9125086894845641 -0.09285234137526865 +-0.9167574799242287 -0.39934957335667176 0.008697198561691212 -0.02915687654119708 0.11810743558832168 0.9925726725077171 -0.8574319824459865 0.5074333892445833 -0.08556723063475187 -0.5137706414628095 -0.8535584274895922 0.0864739199550208 @@ -148,30 +190,30 @@ -0.2097810041460446 0.13679143911975206 0.9681322391507393 -0.7541605021874817 -0.6528214595540482 -0.07117639275804635 0.6222811802069887 -0.7450585508060887 0.24011224173483514 --0.32118689412771495 0.014041789554561798 0.9469117209046984 --0.2315897123784443 -0.970695512406029 -0.06415938992280656 -0.9182620454756157 -0.23990216827053204 0.31502661077762284 --0.33974930251364 -0.19606260267887937 0.9198531770191801 -0.37804062465963034 -0.924012870718146 -0.05731928867464576 -0.8611943436579524 0.3282676812876874 0.38805235712923275 --0.20600684317463236 -0.41300508014459364 0.8871234324151178 -0.845944567303241 -0.5308554185756768 -0.050698260512323436 -0.49187292018910217 0.740013059576384 0.45873925277988187 -0.06979828834192188 -0.5238852652215826 0.8489242768517402 -0.9971521296652115 0.06100696302639706 -0.044337126276175504 --0.028562724811747993 0.8496013061112887 0.5266514895121066 -0.3970556642694828 -0.43992123459137517 0.8054912208256028 -0.7756554794639328 0.6299949154993846 -0.03827510447405953 --0.49061734238517957 0.6399810261254031 0.591370365803343 -0.6360552994038684 -0.14914856239052243 0.7570920435700641 -0.264738079836502 0.9637708620884659 -0.03254956948621244 --0.7248085300165398 0.2211344200392519 0.6524968682600449 +-0.3211868941277149 0.014041789554561812 0.9469117209046984 +-0.2315897123784443 -0.9706955124060289 -0.06415938992280655 +0.9182620454756157 -0.2399021682705321 0.3150266107776228 +-0.33974930251363994 -0.19606260267887934 0.9198531770191801 +0.37804062465963034 -0.924012870718146 -0.057319288674645766 +0.8611943436579524 0.3282676812876874 0.3880523571292327 +-0.20600684317463222 -0.41300508014459364 0.8871234324151179 +0.8459445673032412 -0.5308554185756768 -0.05069826051232345 +0.491872920189102 0.7400130595763841 0.45873925277988187 +0.06979828834192188 -0.5238852652215825 0.8489242768517402 +0.9971521296652115 0.06100696302639706 -0.04433712627617551 +-0.028562724811748 0.8496013061112888 0.5266514895121065 +0.3970556642694828 -0.4399212345913751 0.8054912208256028 +0.7756554794639327 0.6299949154993845 -0.03827510447405953 +-0.49061734238517957 0.639981026125403 0.591370365803343 +0.6360552994038683 -0.14914856239052243 0.7570920435700641 +0.264738079836502 0.9637708620884656 -0.03254956948621243 +-0.7248085300165398 0.2211344200392519 0.6524968682600448 0.659766934879312 0.2627854465544151 0.7040251421072646 -0.34471102509728996 0.9383148173661701 -0.027195821139767956 -0.6677438886401981 -0.22474232487514978 0.709654131667941 -0.4181188568151384 0.6380142495073202 0.6466176915312576 --0.8257029129813153 0.5636663697610323 -0.02224686707358381 --0.37867046500852475 -0.5246122768540877 0.7624897624914039 +0.4181188568151383 0.6380142495073202 0.6466176915312576 +-0.8257029129813153 0.5636663697610322 -0.02224686707358381 +-0.37867046500852464 -0.5246122768540877 0.7624897624914039 -0.02690600889630983 0.8104254265964779 0.5852236278647578 -0.9996349819126044 -0.020382244040942625 -0.01773321923517225 -0.0024432809619280467 -0.5854871408099176 0.8106780114967771 @@ -185,29 +227,29 @@ 0.3011019548832456 -0.9535657589571743 -0.007067963632907055 0.3653093264033997 0.10849878487172157 0.9245415673316447 -0.5721919402095116 -0.76022061883881 0.30767026871573294 -0.7980837307519285 -0.6025294234091818 -0.004544517057057313 -0.18883522517887824 0.24294629986590768 0.9514821874912356 +0.7980837307519286 -0.6025294234091818 -0.004544517057057313 +0.18883522517887824 0.2429462998659077 0.9514821874912356 -0.027201796779131347 -0.9722331476023137 0.23242798660076291 0.9995882022585845 -0.02858048328808262 -0.0025655175834607812 0.009137185422122945 0.23226248659290039 0.9726102246862534 0.5492040923983863 -0.8210456495460422 0.1557527086582515 0.8312890805725521 0.5558391473181951 -0.0011431664019563288 -0.08563486097206832 0.1301033576434492 0.9877954175416057 -0.9317901024811768 -0.3544924733882522 0.07811716347383058 -0.35560000487200755 0.9346381944933685 -0.00028623278055764205 --0.07290981726177961 0.028045172583810823 0.9969441442937503 +0.9317901024811769 -0.3544924733882522 0.07811716347383058 +0.35560000487200755 0.9346381944933686 -0.00028623278055764205 +-0.07290981726177963 0.028045172583810823 0.9969441442937503 0.9678478920094116 0.251536196069151 -2.438619342199359e-16 -0.251536196069151 0.9678478920094116 -1.2338267791434357e-17 2.365204235509872e-16 5.941944381170033e-17 0.9999999999999999 -0.6412790112224139 0.7633209931191501 -0.07811716347383106 +0.6412790112224139 0.7633209931191501 -0.07811716347383105 -0.7656751055896421 0.6432274486922069 -0.00028623278055764216 -0.050028616270025895 0.05999592246568436 0.9969441442937502 +0.05002861627002589 0.059995922465684345 0.9969441442937502 0.07994218484988584 0.9845559104627042 -0.15575270865825197 -0.9967337203583408 0.08075013232929115 -0.0011431664019563288 0.011451540597110904 0.15533536397664763 0.9877954175416055 --0.4971375982387869 0.8359613863463347 -0.23242798660076341 --0.8591836282435412 -0.5116609337029684 -0.0025655175834607812 --0.12106899427861341 0.19842290558330403 0.9726102246862532 +-0.4971375982387869 0.8359613863463348 -0.2324279866007634 +-0.8591836282435413 -0.5116609337029684 -0.0025655175834607812 +-0.1210689942786134 0.19842290558330403 0.9726102246862532 -0.8699358080543524 0.38542274921598657 -0.3076702687157334 -0.4037233818977881 -0.9148698149320105 -0.004544517057057313 -0.2832298020580349 0.12026024327706918 0.9514821874912355 @@ -217,26 +259,26 @@ -0.611131441201691 -0.6497719172728347 -0.45201196565835383 0.7319007467596907 -0.6813360965281241 -0.010120299423738792 -0.3013961819057293 -0.33701272838188684 0.8919544620894303 --0.11852082909039505 -0.8457673672243843 -0.5202214659258679 -0.9913530629477194 -0.1305062762748987 -0.013682705764397311 --0.05631978032539392 -0.5173448292881581 0.8539217821047229 +-0.11852082909039505 -0.8457673672243843 -0.520221465925868 +0.9913530629477195 -0.13050627627489872 -0.013682705764397325 +-0.05631978032539391 -0.5173448292881581 0.8539217821047229 0.3710928602310135 -0.7209739208004521 -0.5852236278647581 -0.8830643205436598 0.46891677163258066 -0.017733219235172265 -0.2872063628618453 -0.5102094342594045 0.810678011496777 -0.6758572914005849 -0.3536982932662406 -0.6466176915312579 -0.4467699332847292 0.8943722399639696 -0.02224686707358385 -0.58618559208959 -0.2738536355836445 0.7624897624914035 -0.7042290139039139 0.0917065715026267 -0.704025142107265 --0.15577221342833797 0.9874185560521789 -0.02719582113976797 -0.692673453728059 0.12881964099881488 0.7096541316679408 -0.48294820902673574 0.43996893635888884 -0.7570920435700644 --0.7004955563665652 0.7129140909232742 -0.032549569486212473 -0.5254207865212076 0.5460593685692697 0.6524968682600444 -0.13261530367386135 0.5775786304949041 -0.8054912208256031 --0.9842463082485561 0.17261002600251332 -0.038275104474059574 +0.8830643205436598 0.46891677163258066 -0.01773321923517225 +0.28720636286184537 -0.5102094342594046 0.8106780114967769 +0.6758572914005849 -0.3536982932662406 -0.646617691531258 +0.44676993328472925 0.8943722399639698 -0.02224686707358385 +0.5861855920895901 -0.27385363558364456 0.7624897624914035 +0.7042290139039138 0.09170657150262668 -0.704025142107265 +-0.1557722134283379 0.9874185560521788 -0.027195821139767984 +0.692673453728059 0.12881964099881488 0.7096541316679407 +0.48294820902673574 0.4399689363588888 -0.7570920435700644 +-0.7004955563665651 0.7129140909232742 -0.03254956948621246 +0.5254207865212076 0.5460593685692696 0.6524968682600445 +0.13261530367386132 0.5775786304949041 -0.8054912208256031 +-0.9842463082485561 0.1726100260025133 -0.038275104474059574 0.11692897814732683 0.7978776250271985 0.5913703658033426 --0.19411250533955315 0.49157695983696326 -0.8489242768517405 --0.9006757270100962 -0.4322238471074971 -0.04433712627617555 +-0.1941125053395532 0.4915769598369634 -0.8489242768517403 +-0.9006757270100962 -0.432223847107497 -0.04433712627617554 -0.38872042658655903 0.755999099568937 0.526651489512106 -0.3810297119837001 0.2604388109434495 -0.8871234324151182 -0.4804257620151855 -0.8755688285755455 -0.05069826051232348 @@ -253,9 +295,9 @@ -0.003800519504947558 -0.18149837703837904 -0.9833839002057777 0.9108154650777595 0.40531477170152086 -0.07832703502449566 0.41279625074203014 -0.8959789478402816 0.1637711219975748 -0.03203888284789305 -0.11735842439615092 -0.9925726725077172 +0.03203888284789306 -0.1173584243961509 -0.9925726725077172 0.5018636779219329 0.8607038386252088 -0.08556723063475193 -0.8643531447091108 -0.4953946935515996 0.08647391995502034 +0.8643531447091108 -0.49539469355159954 0.08647391995502034 0.017676884370721978 -0.09156815123521407 -0.9956419042197395 -0.09632993722133462 0.9910090745780606 -0.0928523413752687 0.9951924793495365 0.09755146223045902 0.008697198561690728 @@ -263,56 +305,56 @@ -0.6577615200809701 0.7465402021221164 -0.10013745211578548 0.7530971226919353 0.6542726826931421 -0.06907952283163886 0.0710849227243236 -0.16704202638063922 -0.9833839002057777 --0.9696888376482335 0.21948484892866785 -0.10737764772604176 -0.2337744466396937 0.9612093229434521 -0.14637672487419337 -0.19074397146879402 -0.16228587389322413 -0.9681322391507393 --0.9134789676113934 -0.3904349453148616 -0.114528289992491 --0.3594063342234455 0.9062140192094214 -0.22271784461145325 +-0.9696888376482337 0.21948484892866793 -0.10737764772604176 +0.23377444663969377 0.9612093229434522 -0.14637672487419334 +0.19074397146879402 -0.1622858738932241 -0.9681322391507394 +-0.9134789676113935 -0.39043494531486167 -0.11452828999249101 +-0.3594063342234454 0.9062140192094214 -0.22271784461145325 0.3168143471562332 -0.05465219345344011 -0.9469117209046984 -0.5101604293177096 -0.85144763676329 -0.12154529282773079 -0.7996030301307894 0.5215841826598429 -0.29763221365424075 0.361866371672285 0.15140297810960174 -0.9198531770191801 -0.08698148061947257 -0.9879025319419028 -0.12838539407589158 --0.9281632136009161 -0.03355183455969471 -0.3706579600058507 +0.08698148061947254 -0.9879025319419028 -0.12838539407589158 +-0.9281632136009161 -0.03355183455969468 -0.3706579600058507 0.25670972951399446 0.3835519918249303 -0.8871234324151179 0.6503541655672148 -0.7475377751550814 -0.13500642223821394 -0.7149402591141609 -0.5422869575080335 -0.4413448556564999 --0.0028108390358421442 0.5285070211034708 -0.8489242768517402 -0.9647571722235708 -0.2219432644160386 -0.14136755647436186 --0.26312677139944174 -0.8194031462135642 -0.5092570923887245 +-0.002810839035842158 0.5285070211034707 -0.8489242768517402 +0.9647571722235707 -0.22194326441603857 -0.14136755647436183 +-0.26312677139944174 -0.8194031462135642 -0.5092570923887244 -0.3380729687675431 0.48671404434388327 -0.805491220825603 0.9098065960196094 0.3879645309669833 -0.14742957827647785 0.2407459773867701 -0.7826831809550969 -0.573975968679961 -0.6120112031431744 0.22859117391130418 -0.7570920435700641 -0.506413228375974 0.8485806699464791 -0.1531551132643249 -0.6074437664122231 -0.4771340710985084 -0.6351024711366628 --0.6877611530165451 -0.17701185181280438 -0.7040251421072647 --0.09078642345293388 0.9831748400500708 -0.1585088616107694 -0.7202377536050004 -0.045100312751900615 -0.6922597345445591 +0.5064132283759741 0.8485806699464792 -0.1531551132643249 +0.6074437664122232 -0.47713407109850847 -0.6351024711366628 +-0.6877611530165451 -0.1770118518128044 -0.7040251421072647 +-0.0907864234529339 0.9831748400500708 -0.1585088616107694 +0.7202377536050004 -0.0451003127519006 -0.6922597345445591 -0.49563909621270263 -0.5798512285959588 -0.6466176915312574 -0.6524616784528667 0.7399833110581527 -0.16345781567695356 0.5732675156119724 0.3408771803027745 -0.7450953653680222 --0.07606609665921979 -0.8072962618071767 -0.5852236278647579 --0.962623155800202 0.21246705006133768 -0.16797146351536513 -0.25994347242485405 0.5505728819242659 -0.7932836143733952 -0.42481672254914027 -0.7408781132092834 -0.5202214659258682 --0.9018492867851262 -0.3963285295798667 -0.17202197698614005 --0.07873129090625974 0.5422391704852325 -0.836527384981341 +-0.07606609665921979 -0.8072962618071766 -0.5852236278647579 +-0.9626231558002017 0.21246705006133762 -0.16797146351536513 +0.25994347242485394 0.5505728819242657 -0.7932836143733952 +0.4248167225491403 -0.7408781132092834 -0.520221465925868 +-0.9018492867851262 -0.39632852957986675 -0.17202197698614005 +-0.07873129090625972 0.5422391704852324 -0.836527384981341 0.8090767802829673 -0.37560610552628 -0.4520119656583534 -0.49354128018135757 -0.8518140225945418 -0.1755843833267986 -0.3190795643156957 0.3651478117183321 -0.8745600649660485 -0.909359099024338 0.16701225959675753 -0.3810156613133238 -0.10482896643922965 -0.9783147808237244 -0.17863671911763032 --0.40258777529493733 0.12250344797683674 -0.907147170208263 -0.6639634324568493 0.6815361810707539 -0.3076702687157331 -0.6623009673693866 -0.7270064807052861 -0.18116016569348006 +0.909359099024338 0.16701225959675753 -0.38101566131332376 +0.10482896643922965 -0.9783147808237245 -0.17863671911763032 +-0.40258777529493733 0.12250344797683674 -0.9071471702082631 +0.6639634324568494 0.6815361810707539 -0.3076702687157331 +0.6623009673693865 -0.7270064807052862 -0.18116016569348006 -0.3471454867655541 -0.0834865911629345 -0.9340877903678537 -0.15025304440064094 0.9609376950110003 -0.2324279866007635 +0.15025304440064094 0.9609376950110003 -0.23242798660076347 0.9635613778977197 -0.19496029648560356 -0.18313916516707657 --0.2212995564211262 -0.19644141391567932 -0.9552158275628714 --0.4406701782151085 0.8840536679283006 -0.15575270865825164 -0.8921978100885005 0.4122136756057425 -0.18456151634858106 --0.09895888896480383 -0.2202929818812242 -0.9704010204182238 +-0.22129955642112617 -0.1964414139156793 -0.9552158275628714 +-0.4406701782151085 0.8840536679283008 -0.1557527086582516 +0.8921978100885006 0.4122136756057425 -0.18456151634858106 +-0.09895888896480387 -0.2202929818812242 -0.9704010204182238 -0.8793234128092727 0.46977446126439865 -0.07811716347383026 0.4758074099718608 0.8597832907347059 -0.18541844996997975 -0.019941020568736367 -0.2002115094522396 -0.9795497471703685 @@ -328,12 +370,12 @@ 0.38713270475368505 -0.8922474432324317 0.23242798660076375 -0.8835412770574879 -0.4310624756546666 -0.1831391651670766 0.263596435191601 -0.13446055974767723 -0.9552158275628714 -0.8140466269447304 -0.49261252004825834 0.3076702687157332 --0.45813815047002343 -0.8702243558128083 -0.18116016569348004 -0.35698392715052785 0.006517333955484705 -0.9340877903678536 -0.9221309155461649 0.06709426523900527 0.38101566131332393 +0.8140466269447303 -0.49261252004825834 0.3076702687157332 +-0.45813815047002343 -0.8702243558128082 -0.18116016569348004 +0.35698392715052785 0.006517333955484678 -0.9340877903678536 +0.9221309155461649 0.06709426523900526 0.381015661313324 0.14462308433689455 -0.9732281777978748 -0.1786367191176303 -0.35882967835851454 0.219830101469898 -0.9071471702082629 +0.3588296783585146 0.219830101469898 -0.9071471702082629 0.688584725266201 0.5670416730997309 0.45201196565835366 0.6919349466449488 -0.7002829099322644 -0.1755843833267986 0.21697259214362224 0.4336675996948103 -0.8745600649660484 @@ -342,31 +384,31 @@ -0.06019286436474587 0.5446088075452385 -0.8365273849813408 -0.2766846421008353 0.7622066086136644 0.5852236278647581 0.8782296385782083 0.4477703533813914 -0.16797146351536513 --0.39007475020606286 0.46748561092119206 -0.7932836143733951 +-0.3900747502060629 0.46748561092119206 -0.7932836143733951 -0.6255568267939668 0.43653661639116864 0.6466176915312576 0.4453510728893034 0.8803090164087071 -0.16345781567695356 -0.6405787058026589 0.18571973018310206 -0.745095365368022 -0.7101730700171743 -0.0016762765962124726 0.704025142107265 -0.15943661077509846 0.9743997680292251 -0.15850886161076938 -0.6857362304610509 -0.2248161074330869 -0.6922597345445589 --0.5348347985076322 -0.3751844557923526 0.7570920435700647 --0.7035797293455188 0.6939157555028407 -0.15315511326432488 --0.4678966795772192 -0.6145872992478106 -0.6351024711366623 +-0.5348347985076322 -0.37518445579235254 0.7570920435700647 +-0.7035797293455187 0.6939157555028407 -0.15315511326432488 +-0.46789667957721925 -0.6145872992478105 -0.6351024711366623 -0.20477701087933575 -0.556102750387196 0.8054912208256031 --0.9781415184230252 0.1466413631494161 -0.14742957827647782 --0.03613233665877999 -0.8180745941694296 -0.5739759686799608 +-0.9781415184230252 0.14664136314941606 -0.14742957827647782 +-0.03613233665877996 -0.8180745941694296 -0.5739759686799608 0.13021818104858984 -0.5122214340460058 0.8489242768517402 -0.8779114309631622 -0.4574786698423014 -0.1413675564743619 0.46077624147584895 -0.7268717006069034 -0.5092570923887247 -0.3449331795868148 -0.30664819790787895 0.887123432415118 --0.4414110998232633 -0.8870904727857551 -0.1350064222382139 -0.8283582211657874 -0.3450179354940784 -0.44134485565649967 +0.3449331795868147 -0.30664819790787895 0.887123432415118 +-0.4414110998232632 -0.8870904727857549 -0.13500642223821388 +0.8283582211657874 -0.34501793549407844 -0.44134485565649956 0.3883149341993451 -0.05551256259153163 0.9198531770191803 0.16430840231033872 -0.9780183738142153 -0.12838539407589156 0.9067603105606146 0.20099357172884752 -0.3706579600058502 -0.29288109320538364 0.13258528597141434 0.9469117209046986 -0.7079275958052715 -0.69574798662216 -0.12154529282773079 -0.6426968059203245 0.7059432562572497 -0.29763221365424053 +0.2928810932053837 0.13258528597141428 0.9469117209046986 +0.7079275958052715 -0.6957479866221601 -0.12154529282773079 +0.6426968059203246 0.7059432562572496 -0.29763221365424053 0.14379037930471614 0.20504705395684547 0.9681322391507393 0.982317214154588 -0.14810861408765363 -0.11452828999249101 0.11990503573651728 0.9674810303549383 -0.2227178446114534 @@ -375,19 +417,19 @@ -0.4680370421052974 0.8715016819446929 -0.14637672487419312 -0.016900273462359165 0.12047352633581171 0.9925726725077172 0.44883121800077613 0.8879881916060024 -0.10013745211578544 --0.8934567244723368 0.44380525123134346 -0.06907952283163821 +-0.8934567244723368 0.44380525123134346 -0.0690795228316382 -0.005924169167292852 0.09307041840116657 0.9956419042197395 -0.1560419262123073 0.9833765097688084 -0.09285234137526867 -0.9877326670125018 -0.15591195353002404 0.00869719856169097 0.001488873577392344 0.12164404237922463 0.9925726725077172 -0.7022258722627369 0.7067935153680581 -0.08556723063475194 -0.7119526722896042 -0.6968828119471048 0.08647391995502013 --0.04933173614436343 0.17470685340036343 0.9833839002057777 --0.9834821637695192 0.16317998998497335 -0.07832703502449564 --0.17415284481227244 -0.9710045346152858 0.16377112199757504 --0.16862810439535866 0.1851608217874497 0.9681322391507393 --0.8941208789274522 -0.4421332095420484 -0.07117639275804635 -0.41486433478190016 -0.8776295887759501 0.24011224173483534 +-0.049331736144363425 0.17470685340036343 0.9833839002057777 +-0.9834821637695192 0.1631799899849734 -0.07832703502449564 +-0.1741528448122725 -0.9710045346152858 0.16377112199757504 +-0.1686281043953587 0.18516082178744972 0.9681322391507393 +-0.8941208789274523 -0.4421332095420484 -0.07117639275804635 +0.41486433478190016 -0.8776295887759501 0.2401122417348354 -0.3073280400920004 0.09438044599657396 0.9469117209046984 -0.46830867166855433 -0.8812324101647464 -0.06415938992280658 0.8283939061903125 -0.4631649497627388 0.3150266107776225 @@ -397,32 +439,32 @@ -0.30326901572288895 -0.34790791851076014 0.8871234324151179 0.6852163135700291 -0.7265729763750673 -0.05069826051232346 0.6621982389888769 0.5924962364766431 0.4587392527798817 --0.0642219805529229 -0.5245980455411648 0.84892427685174 -0.9804370461225607 -0.191774393035249 -0.04433712627617549 -0.18606110771552362 0.8294693923167699 0.5266514895121066 -0.27363337375445596 -0.525650710967496 0.805491220825603 -0.9091830453123386 0.4146338221781748 -0.038275104474059546 --0.3138645677427393 0.7428123070906161 0.5913703658033429 -0.5780885186965528 -0.30434405220757815 0.7570920435700644 -0.4986494490364013 0.8661923876956872 -0.032549569486212473 --0.6458810970503154 0.39634006280455086 0.6524968682600444 +-0.06422198055292293 -0.5245980455411648 0.84892427685174 +0.9804370461225607 -0.19177439303524907 -0.04433712627617549 +0.18606110771552367 0.8294693923167699 0.5266514895121066 +0.2736333737544559 -0.5256507109674959 0.805491220825603 +0.9091830453123386 0.41463382217817474 -0.03827510447405954 +-0.31386456774273935 0.7428123070906161 0.5913703658033428 +0.5780885186965526 -0.3043440522075781 0.7570920435700644 +0.4986494490364013 0.8661923876956871 -0.03254956948621248 +-0.6458810970503154 0.3963400628045509 0.6524968682600443 0.7046540887490838 0.08838107540669464 0.7040251421072647 -0.09760769911720535 0.994853318025114 -0.027195821139767956 -0.7028053445174157 -0.049554627678727384 0.709654131667941 0.5651591315369029 0.5123287197095643 0.6466176915312575 --0.6573723292531983 0.7532374775843506 -0.022246867073583795 --0.498454387855778 -0.4124955579435052 0.7624897624914041 -0.17781040501112128 0.7911363758914086 0.585223627864758 --0.972621482156391 0.23171746887850858 -0.01773321923517225 +-0.6573723292531982 0.7532374775843504 -0.02224686707358381 +-0.4984543878557781 -0.41249555794350523 0.7624897624914039 +0.17781040501112128 0.7911363758914087 0.585223627864758 +-0.9726214821563911 0.23171746887850858 -0.01773321923517225 -0.1496359325753219 -0.5660479214324041 0.810678011496777 -0.32745124090539246 0.7887618849941087 0.5202214659258682 --0.9266519199136845 -0.3756714028020337 -0.013682705764397325 -0.18463993108155538 -0.4865446391620122 0.8539217821047229 --0.7549234334911014 0.47515870240129043 0.4520119656583535 --0.536987904946187 -0.843529234514773 -0.010120299423738764 -0.3764765590412125 -0.2503650096384139 0.8919544620894304 +-0.9266519199136845 -0.37567140280203376 -0.013682705764397325 +0.18463993108155544 -0.4865446391620122 0.8539217821047229 +-0.7549234334911015 0.47515870240129043 0.4520119656583535 +-0.536987904946187 -0.8435292345147731 -0.010120299423738764 +0.3764765590412126 -0.2503650096384139 0.8919544620894304 -0.9231957455548281 -0.05036547650361065 0.38101566131332393 -0.05156458860377627 -0.998644650059373 -0.007067963632907069 +0.051564588603776274 -0.998644650059373 -0.007067963632907069 0.3808552331156664 0.013121801871581264 0.9245415673316448 -0.745017765792603 -0.591850939343503 0.30767026871573316 0.6208656972711745 -0.7839037780982413 -0.004544517057057313 diff --git a/input/nucleosomeT b/input/nucleosomeT index 80258bc0..1f9b9ea8 100644 --- a/input/nucleosomeT +++ b/input/nucleosomeT @@ -1,8 +1,22 @@ +0.0 -4.910362785350072 0.4599388612240415 +0.012916371658194592 -4.910331243427519 0.1297533283860401 +0.0515858529063733 -4.910110683349952 -0.1984142238193375 +0.11577003353373705 -4.909513252322135 -0.5225582562811142 +0.20507319672330704 -4.908353421083564 -0.8406980362254817 +0.3189447587777101 -4.906449127758054 -1.1508898490920383 +0.4566826636507413 -4.9036229003257406 -1.4512389821803642 +0.6174377113563536 -4.899702950797102 -1.7399114061838956 +0.8002187935689715 -4.894524234343044 -2.0151450825904957 +1.0038990041358726 -4.887929466851148 -2.27526082723578 +1.2272225868283697 -4.879770094634525 -2.5186726630319027 +1.468812677496536 -4.869907210314703 -2.743897598043685 +1.727179792894539 -4.858212409231799 -2.9495647686270368 +2.000731013840177 -4.8445685811019485 -3.134423891259203 2.2877798060913035 -4.828870632041149 -3.297352970952407 2.5865564183902805 -4.8110261325040025 -3.4373652187260784 2.8952187935689717 -4.790955887142596 -3.5536151354890473 3.2118639254437595 -4.768594423072161 -3.6454037248226094 -3.53453959148143 -4.743890393533178 -3.7121828025258687 +3.5345395914814306 -4.743890393533178 -3.7121828025258687 3.861256388900337 -4.71680689446122 -3.7535583763536464 4.190000000000001 -4.687321692012787 -3.7692930751096703 4.518743611099674 -4.655427359644345 -3.759307612118946 @@ -14,15 +28,15 @@ 6.379268986159831 -4.4149118373838165 -3.1746685416163003 6.652820207105464 -4.367176130696792 -2.995558654749439 6.911187322503471 -4.317491396962819 -2.795640719931382 -7.152777413171637 -4.265974746465766 -2.576165020684901 +7.152777413171638 -4.265974746465766 -2.5761650206849005 7.3761009958641335 -4.212754583865512 -2.338502420654078 7.579781206431029 -4.157969816540533 -2.084135911774099 7.762562288643647 -4.101768998177715 -1.8146514711327995 -7.9233173363492595 -4.0443094128894765 -1.5317282828945684 +7.9233173363492595 -4.0443094128894765 -1.5317282828945686 8.061055241222293 -3.9857561055049144 -1.2371283855715363 8.174926803276692 -3.9262808640135503 -0.9326858084702867 8.264229966466264 -3.8660611604352444 -0.6202952642912126 -8.328414147093625 -3.8052790566461856 -0.30190046759474376 +8.328414147093625 -3.8052790566461856 -0.30190046759474365 8.367083628341806 -3.7441200819068765 0.020517848845340747 8.379999999999999 -3.682772089012553 0.3449541459180415 8.367083628341804 -3.621424096118229 0.6693904429907422 @@ -35,7 +49,7 @@ 7.5797812064310275 -3.2075743614845735 2.774044203610167 7.376100995864126 -3.1527895941595947 3.028410712490151 7.152777413171635 -3.099569431559342 3.2660733125209678 -6.911187322503463 -3.048052781062287 3.4855490117674544 +6.911187322503464 -3.048052781062287 3.4855490117674544 6.65282020710546 -2.998368047328316 3.6854669465855063 6.379268986159822 -2.95063234064129 3.8645768334523716 6.0922201939086955 -2.9049507548852134 4.021756677380275 @@ -48,52 +62,52 @@ 3.8612563889003297 -2.6487372835638867 4.4434666681897115 3.5345395914814275 -2.621653784491929 4.402091094361934 3.211863925443753 -2.5969497549529454 4.335312016658674 -2.8952187935689686 -2.574588290882511 4.243523427325111 -2.5865564183902743 -2.5545180455211054 4.127273510562141 +2.8952187935689686 -2.574588290882511 4.243523427325112 +2.5865564183902743 -2.554518045521105 4.127273510562142 2.287779806091301 -2.5366735459839584 3.9872612627884703 2.0007310138401717 -2.520975596923159 3.8243321830952643 1.7271797928945305 -2.5073317687933088 3.639473060463096 -1.4688126774965253 -2.4956369677104053 3.43380588987974 +1.4688126774965253 -2.4956369677104053 3.4338058898797406 1.2272225868283622 -2.485774083390583 3.2085809548679607 1.0038990041358686 -2.4776147111739606 2.9651691190718408 -0.8002187935689671 -2.4710199436820637 2.7050533744265555 +0.8002187935689671 -2.4710199436820637 2.705053374426555 0.6174377113563501 -2.4658412272280055 2.429819698019955 0.4566826636507364 -2.4619212776993677 2.1411472740164204 -0.31894475877770745 -2.4590950502670537 1.8407981409280973 +0.318944758777707 -2.4590950502670537 1.8407981409280973 0.20507319672330615 -2.4571907569415425 1.5306063280615436 0.11577003353373527 -2.456030925702972 1.2124665481171726 0.05158585290637241 -2.455433494675156 0.8883225156553921 0.012916371658193704 -2.455212934597588 0.5601549634500183 0.0 -2.455181392675036 0.22996943061202074 -0.012916371658193704 -2.4551498507524836 -0.10021610222598065 +0.012916371658193704 -2.4551498507524836 -0.1002161022259806 0.0515858529063733 -2.454929290674916 -0.4283836544313546 0.11577003353373527 -2.454331859647099 -0.7525276868931314 0.2050731967233066 -2.4531720284085288 -1.0706674668375022 0.31894475877770967 -2.451267735083018 -1.380859279704059 0.45668266365073906 -2.448441507650704 -1.6812084127923816 0.617437711356355 -2.4445215581220663 -1.9698808367959195 -0.8002187935689706 -2.4393428416680085 -2.2451145132025165 +0.8002187935689706 -2.4393428416680085 -2.245114513202517 1.00389900413587 -2.432748074176111 -2.5052302578477983 -1.2272225868283662 -2.4245887019594887 -2.748642093643921 -1.4688126774965298 -2.4147258176396673 -2.9738670286557007 +1.2272225868283666 -2.4245887019594887 -2.748642093643921 +1.4688126774965293 -2.4147258176396673 -2.9738670286557007 1.7271797928945385 -2.4030310165567634 -3.179534199239058 -2.0007310138401766 -2.389387188426913 -3.364393321871224 +2.000731013840176 -2.3893871884269124 -3.3643933218712236 2.287779806091299 -2.3736892393661133 -3.5273224015644264 2.586556418390276 -2.3558447398289664 -3.6673346493380983 2.895218793568971 -2.3357744944675605 -3.783584566101069 -3.211863925443755 -2.313413030397126 -3.8753731554346302 +3.2118639254437547 -2.313413030397126 -3.8753731554346302 3.5345395914814333 -2.2887090008581428 -3.9421522331378913 3.861256388900328 -2.2616255017861846 -3.983527806965668 4.190000000000004 -2.2321402993377526 -3.999262505721692 4.518743611099673 -2.200245966969309 -3.9892770427309685 4.8454604085185675 -2.1659499312243904 -3.9536507046684912 -5.168136074556246 -2.129274425946498 -3.892620862730532 +5.168136074556245 -2.129274425946498 -3.892620862730532 5.4847812064310295 -2.0902563552000566 -3.8065815091622706 5.793443581609724 -2.0489470657445867 -3.6960808281646007 6.092220193908701 -2.005412030464858 -3.561817816156229 -6.379268986159827 -1.9597304447087813 -3.4046379722283246 +6.379268986159827 -1.9597304447087813 -3.404637972228325 6.652820207105462 -1.9119947380217557 -3.2255280853614616 -6.911187322503471 -1.8623100042877836 -3.0256101505434043 +6.911187322503471 -1.8623100042877838 -3.0256101505434048 7.152777413171634 -1.81079335379073 -2.8061344512969253 7.37610099586413 -1.7575731911904762 -2.5684718512661036 7.579781206431029 -1.7027884238654973 -2.314105342386122 @@ -102,14 +116,14 @@ 8.061055241222292 -1.5305747128298794 -1.4670978161835624 8.174926803276694 -1.4710994713385144 -1.162655239082308 8.264229966466264 -1.4108797677602085 -0.8502646949032355 -8.328414147093627 -1.3500976639711495 -0.5318698982067629 +8.328414147093627 -1.3500976639711495 -0.5318698982067628 8.367083628341806 -1.2889386892318409 -0.2094515817666857 8.379999999999999 -1.227590696337518 0.1149847153060114 8.367083628341806 -1.1662427034431944 0.43942101237871034 8.328414147093625 -1.105083728703886 0.7618393288187855 -8.264229966466264 -1.044301624914827 1.0802341255152599 +8.264229966466264 -1.044301624914827 1.08023412551526 8.174926803276692 -0.9840819213365212 1.3926246696943323 -8.061055241222292 -0.924606679845156 1.6970672467955867 +8.061055241222292 -0.924606679845156 1.697067246795587 7.92331733634926 -0.8660533724605946 1.9916671441186105 7.762562288643645 -0.8085937871723562 2.274590332356846 7.579781206431028 -0.752392968809538 2.5440747729981448 @@ -132,12 +146,12 @@ 2.5865564183902725 -0.0993366528460694 3.8973040799501186 2.2877798060912986 -0.08149215330892245 3.7572918321764472 2.000731013840174 -0.06579420424812316 3.594362752483244 -1.7271797928945367 -0.05215037611827272 3.409503629851079 +1.7271797928945372 -0.05215037611827267 3.4095036298510792 1.4688126774965298 -0.040455575035368785 3.2038364592677224 1.2272225868283657 -0.030592690715546933 2.9786115242559417 -1.00389900413587 -0.022433318498924493 2.735199688459821 +1.0038990041358704 -0.022433318498924493 2.735199688459821 0.8002187935689702 -0.015838551007027357 2.475083943814538 -0.6174377113563532 -0.010659834552969538 2.1998502674079385 +0.6174377113563536 -0.010659834552969538 2.1998502674079385 0.4566826636507386 -0.006739885024331871 1.9111778434044024 0.31894475877770834 -0.0039136575920177274 1.6108287103160783 0.2050731967233066 -0.002009364266506955 1.3006368974495228 diff --git a/src/defines.inc b/src/defines.inc index 3a7247f6..cd0654d0 100644 --- a/src/defines.inc +++ b/src/defines.inc @@ -64,7 +64,7 @@ #define WLC_P__CHEM_STATE_FROM_FILE .FALSE. ! VARIABLE COMMENT: ! Whether to read the initial chemical sequence from a file. In the chromatin simulations this corresponds to the HP1 binding profile and is therefore FALSE. For block-copolymers this corresponds to A/B block bead pattern. Reads from "input/ab". ! DEFAULTS COMMENT: ! Don't load initial a/b states from file -! TYPE: LOGICAL +! TYPE: #define WLC_P__CHEM_SEQ_FROM_FILE .FALSE. ! VARIABLE COMMENT: ! Read the fixed methylation profile (or equivalent for other problems) from a file. Read from "input/meth" or "input/meth_..." if WLC_P__ENSEMBLE_METH. @@ -338,6 +338,11 @@ ! DEFAULTS COMMENT: ! baseline twist density 0.0 ! TYPE: REAL(DP) +#define WLC_P__NUCLEOSOME_WRAPPING 147 +! VARIABLE COMMENT: ! How many basepairs wrap a nucleosome (this then defines the entry-exit geometry of the nucleosome) +! DEFAULTS COMMENT: ! 147 bp wrapping +! TYPE: REAL(DP) + ! ---------------------------- ! ! Length variables @@ -345,8 +350,8 @@ ! ! --------------------------- -#define WLC_P__LENGTH_PER_BP 0.332_DP -! VARIABLE COMMENT: ! Length along DNA per bace pair. Currently not in use. +#define WLC_P__LENGTH_PER_BP 0.324_DP +! VARIABLE COMMENT: ! Length along DNA per bace pair. 3.4nm/10.5bp. Previous value of 0.332 was used in codebase, unsure why. ! DEFAULTS COMMENT: ! known value in nm ! TYPE: REAL(DP) @@ -592,9 +597,9 @@ ! DEFAULTS COMMENT: ! toggle on or off ! TYPE: REAL(DP) -#define WLC_P__INTERNUCLEOSOME_ENERGY 1.0_DP -! VARIABLE COMMENT: ! nucleosome-nucleosome attraction scale-term for energy in kt -! DEFAULTS COMMENT: ! inspired by de pablos group, look at nicoles stuff for motivation +#define WLC_P__INTERNUCLEOSOME_ENERGY 4.0_DP +! VARIABLE COMMENT: ! nucleosome-nucleosome attraction scale-term for energy +! DEFAULTS COMMENT: ! inspired from de pablos group, look at nucleosome.f03 for more details ! TYPE: REAL(DP) ! ---------------------------- @@ -725,18 +730,21 @@ ! DEFAULTS COMMENT: ! From experience. ! TYPE: INTEGER -#define WLC_P__MOVESPERSTEP_NUCLEOSOMESLIDE 60 +#define WLC_P__MOVESPERSTEP_NUCLEOSOME_SLIDE 60 ! VARIABLE COMMENT: ! how many times each move is done per step ! DEFAULTS COMMENT: ! nucleosome slide (just copying bead slide) ! TYPE: INTEGER +#define WLC_P__MOVESPERSTEP_NUCLEOSOME_BREATHE 10 +! VARIABLE COMMENT: ! how many times each move is done per step +! DEFAULTS COMMENT: ! nucleosome breathe +! TYPE: INTEGER + #define WLC_P__PROBSINGLESWAP 0.5_dp ! VARIABLE COMMENT: ! For TWO_TAIL simulations, what fraction of the BINDING_STATE moves to change the binding state of only one tail. ! DEFAULTS COMMENT: ! 0< x <1 ! TYPE: LOGICAL - - ! -------------------------- ! ! Parallel Tempering settings (via MPI) @@ -762,7 +770,6 @@ ! VARIABLE COMMENT: None ! DEFAULTS COMMENT: ! don't parallel temper linking number (twist) by default ! TYPE: LOGICAL - #define WLC_P__PT_CHI .FALSE. ! VARIABLE COMMENT: None ! DEFAULTS COMMENT: ! don't parallel temper chi by default @@ -777,7 +784,6 @@ ! VARIABLE COMMENT: ! Parallel temper kappa (incompressibility) energy. ! DEFAULTS COMMENT: ! don't parallel temper kap by default ! TYPE: LOGICAL - #define WLC_P__PT_MU .FALSE. ! VARIABLE COMMENT: ! Parallel temper chemical potential of HP1. ! DEFAULTS COMMENT: ! don't parallel temper mu by default @@ -787,7 +793,6 @@ ! VARIABLE COMMENT: ! Parallel temper HP1 coupling energy. ! DEFAULTS COMMENT: ! don't parallel temper HP1 binding by default ! TYPE: LOGICAL - #define WLC_P__PT_MAIERSAUPE .FALSE. ! VARIABLE COMMENT: ! Parallel temper Maier Saupe liquid crystal interaction. ! DEFAULTS COMMENT: ! don't parallel temper maier Saupe by default @@ -797,7 +802,6 @@ ! VARIABLE COMMENT: ! Parallel temper over external applied field strength. ! DEFAULTS COMMENT: ! don't parallel temper h by default ! TYPE: LOGICAL - #define WLC_P__PT_A2B .FALSE. ! VARIABLE COMMENT: ! Parallel temper two body interaction strength. ! DEFAULTS COMMENT: ! don't parallel temper. @@ -929,11 +933,16 @@ ! DEFAULTS COMMENT: ! Super Reptation ! TYPE: INTEGER -#define WLC_P__MOVEON_NUCLEOSOMESLIDE 0 +#define WLC_P__MOVEON_NUCLEOSOME_SLIDE 0 ! VARIABLE COMMENT: ! Is the move active ! DEFAULTS COMMENT: ! nucleosome slide ! TYPE: INTEGER +#define WLC_P__MOVEON_NUCLEOSOME_BREATHE 0 +! VARIABLE COMMENT: ! Is the move active +! DEFAULTS COMMENT: ! nucleosome angle +! TYPE: INTEGER + ! ---------------------------- ! ! MC Optimization @@ -1000,7 +1009,11 @@ ! DEFAULTS COMMENT: ! Target ! TYPE: REAL(DP) -#define WLC_P__PDESIRE_NUCLEOSOMESLIDE 0.5_DP +#define WLC_P__PDESIRE_NUCLEOSOME_SLIDE 0.5_DP +! VARIABLE COMMENT: ! desired hit rate +! DEFAULTS COMMENT: ! Target + +#define WLC_P__PDESIRE_NUCLEOSOME_BREATHE 0.5_DP ! VARIABLE COMMENT: ! desired hit rate ! DEFAULTS COMMENT: ! Target @@ -1179,6 +1192,11 @@ ! DEFAULTS COMMENT: None ! TYPE: REAL(DP) +#define WLC_P__MINAMP_NUCLEOSOME_BREATHE NAN +! VARIABLE COMMENT: ! minium amplitude +! DEFAULTS COMMENT: None +! TYPE: REAL(DP) + #define WLC_P__MAXAMP_CRANK_SHAFT 1.0_DP*PI ! VARIABLE COMMENT: ! Maximum acceptable amplitude range for this move. ! DEFAULTS COMMENT: None @@ -1244,6 +1262,11 @@ ! DEFAULTS COMMENT: None ! TYPE: REAL(DP) +#define WLC_P__MAXAMP_NUCLEOSOME_BREATHE NAN +! VARIABLE COMMENT: ! maximum amplitude +! DEFAULTS COMMENT: None +! TYPE: REAL(DP) + #define WLC_P__WINTARGET_CRANK_SHAFT 8.0_DP ! VARIABLE COMMENT: ! Target for ratio of average window to amplitude range for this move. ! DEFAULTS COMMENT: None @@ -1359,7 +1382,12 @@ ! DEFAULTS COMMENT: ! adapt after at most 1000 steps ! TYPE: INTEGER -#define WLC_P__NADAPT_NUCLEOSOMESLIDE 1000 +#define WLC_P__NADAPT_NUCLEOSOME_SLIDE 1000 +! VARIABLE COMMENT: ! Nunber of steps between adapt +! DEFAULTS COMMENT: ! adapt after at most 1000 steps +! TYPE: INTEGER + +#define WLC_P__NADAPT_NUCLEOSOME_BREATHE 1000 ! VARIABLE COMMENT: ! Nunber of steps between adapt ! DEFAULTS COMMENT: ! adapt after at most 1000 steps ! TYPE: INTEGER @@ -1407,4 +1435,4 @@ #define WLC_P__NO_CROSSING_CUTOFF 0.5_DP ! VARIABLE COMMENT: ! Deviation from initial linking number allowed when WLC_P__NO_SELF_CROSSING is true. ! DEFAULTS COMMENT: ! allow linking number to change by 0.5 for each move -! TYPE: REAL(DP) \ No newline at end of file +! TYPE: REAL(DP) diff --git a/src/mc/mc_elas.f03 b/src/mc/mc_elas.f03 index 1b42c9bf..f9398fee 100644 --- a/src/mc/mc_elas.f03 +++ b/src/mc/mc_elas.f03 @@ -7,7 +7,7 @@ subroutine mc_eelas(wlc_p) ! values from wlcsim_data use params, only: wlc_U, wlc_nucleosomeWrap, wlc_VP, wlc_V & , wlc_R, wlc_UP, wlc_basepairs, wlc_RP, wlc_bendPoints, wlc_nBend, & - wlc_basepairs_prop + wlc_basepairs_prop, wlc_nucleosomeWrap_prop use params, only: dp, wlcsim_params use MC_wlc, only: E_wlc, E_SSWLC, E_SSWLCWT, E_GAUSS @@ -25,6 +25,7 @@ subroutine mc_eelas(wlc_p) integer IT2M1 real(dp) energy_change(4) real(dp) basepairs(WLC_P__NT) + real(dp) wrapping(WLC_P__NT) integer ii ! Setup parameters @@ -83,21 +84,25 @@ subroutine mc_eelas(wlc_p) energyOf(stretch_)%dx = energyOf(stretch_)%dx - E_GAUSS(wlc_R(:, IT2P1), wlc_R(:, IT2), wlc_p%EPAR) endif elseif (WLC_P__ELASTICITY_TYPE == "nucleosomes") then - ! set basepairs vector - if (WLC_P__MOVEON_NUCLEOSOMESLIDE == 1) then + ! set basepairs and wrapping vector + basepairs = wlc_basepairs + wrapping = wlc_nucleosomeWrap + if (WLC_P__MOVEON_NUCLEOSOME_SLIDE == 1 .AND. WLC_P__MOVEON_NUCLEOSOME_BREATHE == 0) then basepairs = wlc_basepairs_prop - else - basepairs = wlc_basepairs - endif + endif + if (WLC_P__MOVEON_NUCLEOSOME_BREATHE == 1) then + basepairs = wlc_basepairs_prop + wrapping = wlc_nucleosomeWrap_prop + endif energy_change = energy_change + nucleosome_energy(wlc_RP(:, IT2P1), wlc_RP(:, IT2) & , wlc_UP(:, IT2P1), wlc_UP(:, IT2) & , wlc_VP(:, IT2P1), wlc_VP(:, IT2) & , basepairs(IT2) & - , wlc_nucleosomeWrap(IT2)) + , wrapping(IT2)) energy_change = energy_change - nucleosome_energy(wlc_R(:, IT2P1), wlc_R(:, IT2) & , wlc_U(:, IT2P1), wlc_U(:, IT2) & , wlc_V(:, IT2P1), wlc_V(:, IT2) & - , basepairs(IT2) & + , wlc_basepairs(IT2) & , wlc_nucleosomeWrap(IT2)) endif enddo diff --git a/src/mc/mc_internucleosome.f03 b/src/mc/mc_internucleosome.f03 index b8376a2c..ca1ed395 100644 --- a/src/mc/mc_internucleosome.f03 +++ b/src/mc/mc_internucleosome.f03 @@ -7,7 +7,7 @@ subroutine mc_internucleosome() ! values from wlcsim_data use params, only: dp, NAN, wlc_U, wlc_nucleosomeWrap, wlc_VP, wlc_V& , wlc_R, wlc_UP, wlc_RP, wlc_nPointsMoved, wlc_pointsMoved, & - wlc_bin, wlc_R_GJK + wlc_bin, wlc_R_GJK, wlc_nucleosomeWrap_prop use GJKAlgorithm, only: constructPolygonPrism use polydispersity, only: get_IP, first_bead_of_chain, last_bead_of_chain use nucleosome, only: internucleosome_energy @@ -23,6 +23,7 @@ subroutine mc_internucleosome() real(dp) RALL(3, WLC_P__NT) ! all bead R real(dp) UALL(3, WLC_P__NT) ! all bead U real(dp) VALL(3, WLC_P__NT) ! all bead V + real(dp) wrapping(WLC_P__NT) real(dp) distances(WLC_P__NT) ! Returned distances real(dp) poly(WLC_P__GJK_POLYGON, 3) integer neighbors(WLC_P__NT) ! ID of neighboring beads @@ -35,11 +36,16 @@ subroutine mc_internucleosome() UALL = wlc_U VALL = wlc_V + wrapping = wlc_nucleosomeWrap + if (WLC_P__MOVEON_NUCLEOSOME_BREATHE == 1) then + wrapping = wlc_nucleosomeWrap_prop + endif + ! check energetics of old beads ignore = NAN do k = 1, wlc_nPointsMoved i = wlc_pointsMoved(k) - if (wlc_nucleosomeWrap(i) == 1) cycle + if (wlc_nucleosomeWrap(i) == 0) cycle ignore(k) = i ! only check beads within cutoff distance, since n choose k grows quick if (WLC_P__NEIGHBOR_BINS) then @@ -51,7 +57,7 @@ subroutine mc_internucleosome() WLC_P__NT, neighbors, distances, nn) endif do j = 1, nn - if (wlc_nucleosomeWrap(neighbors(j)) == 1 .or. ANY(ignore == neighbors(j))) cycle + if (wlc_nucleosomeWrap(neighbors(j)) == 0 .or. ANY(ignore == neighbors(j))) cycle ! old config delInt = delInt - internucleosome_energy(RALL(:, i), RALL(:, neighbors(j)), & UALL(:, i), UALL(:, neighbors(j)), & @@ -61,7 +67,7 @@ subroutine mc_internucleosome() ! replace old beads with new moved beads do j = 1, wlc_nPointsMoved i = wlc_pointsMoved(j) - if (wlc_nucleosomeWrap(i) == 1) cycle ! only nucs + if (wlc_nucleosomeWrap(i) == 0) cycle ! only nucs IP = get_IP(i) ! update real bead locations RALL(:, i) = wlc_RP(:, i) @@ -71,11 +77,11 @@ subroutine mc_internucleosome() if ((i < last_bead_of_chain(IP))) then if (isnan(wlc_RP(1, i + 1))) then poly = constructPolygonPrism(wlc_RP(:, i), wlc_R(:, i + 1), & - wlc_nucleosomeWrap(i), wlc_UP(:, i), & + wrapping(i), wlc_UP(:, i), & wlc_VP(:, i)/norm2(wlc_VP(:, i)), WLC_P__GJK_POLYGON) else poly = constructPolygonPrism(wlc_RP(:, i), wlc_RP(:, i + 1), & - wlc_nucleosomeWrap(i), wlc_UP(:, i), & + wrapping(i), wlc_UP(:, i), & wlc_VP(:, i)/norm2(wlc_VP(:, i)), WLC_P__GJK_POLYGON) endif RGJK(1, i) = sum(poly(:, 1)/WLC_P__GJK_POLYGON) @@ -87,7 +93,7 @@ subroutine mc_internucleosome() ignore = NAN do k = 1, wlc_nPointsMoved i = wlc_pointsMoved(k) - if (wlc_nucleosomeWrap(i) == 1) cycle + if (wrapping(i) == 0) cycle ignore(k) = i ! only check beads within cutoff distance, since n choose k grows quick if (WLC_P__NEIGHBOR_BINS) then @@ -99,7 +105,7 @@ subroutine mc_internucleosome() WLC_P__NT, neighbors, distances, nn) endif do j = 1, nn - if (wlc_nucleosomeWrap(neighbors(j)) == 1 .or. ANY(ignore == neighbors(j))) cycle + if (wrapping(neighbors(j)) == 0 .or. ANY(ignore == neighbors(j))) cycle ! new config delInt = delInt + internucleosome_energy(RALL(:, i), RALL(:, neighbors(j)), & UALL(:, i), UALL(:, neighbors(j)), & diff --git a/src/mc/mc_move.f90 b/src/mc/mc_move.f90 index 00d2c0e4..d2b30dce 100644 --- a/src/mc/mc_move.f90 +++ b/src/mc/mc_move.f90 @@ -55,6 +55,8 @@ subroutine mc_move(IB1,IB2,IT1,IT2,IT3,IT4,MCTYPE,forward,rand_stat,dib,success) call mc_spider(wlc_MCAMP,rand_stat,success) case(13) call mc_nucleosome_slide(IB1,IB2,IT1,IT2,rand_stat,success) +case(14) +call mc_nucleosome_breathe(IB1,IB2,IT1,IT2,rand_stat,success) end select RETURN END diff --git a/src/mc/mc_nucleosome_breathe.f03 b/src/mc/mc_nucleosome_breathe.f03 new file mode 100644 index 00000000..79526fbc --- /dev/null +++ b/src/mc/mc_nucleosome_breathe.f03 @@ -0,0 +1,123 @@ +#include "../defines.inc" +!--------------------------------------------------------------* +! +! Allows nucleosomes to breathe in MC move +! +! implemented by NP, oct 2020 +! TODO: THIS IS NOT TESTED NOR FULLY DEVELOPED! +! +!--------------------------------------------------------------- + +subroutine mc_nucleosome_breathe(IB1, IB2, IT1, IT2, rand_stat, success) +! this move will "breathe" a nucleosome to allow for under and overwrapping on +! the histone octamer. ill write more here soon. + use params, only: wlc_V, wlc_R, wlc_RP, wlc_AB, wlc_U & + , wlc_UP, wlc_ABP, wlc_VP, wlc_pointsMoved, wlc_nPointsMoved, & + wlc_nucleosomeWrap, wlc_basepairs, wlc_nBend, wlc_bendPoints, & + wlc_basepairs_prop, wlc_nucleosomeWrap_prop + + use mersenne_twister + use params, only: dp + use windowTools, only: exponential_random_int + use polydispersity, only: get_IP, first_bead_of_chain, last_bead_of_chain, get_IB, length_of_chain + use nucleosome, only: nucleosome_prop + + implicit none + integer, intent(out) :: IB1 ! Test bead position 1 + integer, intent(out) :: IT1 ! Index of test bead 1 + integer, intent(out) :: IB2 ! Test bead position 2 + integer, intent(out) :: IT2 ! Index of test bead 2 + logical, intent(out) :: success ! success of move to take place + +! Things for random number generator + type(random_stat), intent(inout) :: rand_stat ! status of random number generator + real(dp) urand(1) ! single random number + real(dp) DR ! Displacement for breathe move (integer BPs) + integer I, J, K ! test bead + integer prevNuc, nextNuc, linkerSum + integer nNucs + integer nucArray(WLC_P__NT) + real(dp) tempR(3), tempU(3), tempV(3) + real(dp), parameter :: eps = 0.00001 ! rescale to avoid urand vals of 0 + integer, parameter :: max_wrap = 160 + integer, parameter :: min_base = 5 + integer, parameter :: max_base = 15 + +! initialize + success = .false. + +! find nucs + K = 1 + do I = 1, WLC_P__NT + if (wlc_nucleosomeWrap(I) == 0) cycle + nucArray(K) = I + K = K + 1 + enddo + nNucs = K - 1 + +! select nuc to move + call random_number(urand, rand_stat) + K = ceiling(nNucs*(urand(1) + eps)/(1 + 1.1*eps)) + I = nucArray(K) + +! select bp to unwrap + DR = 0.0_dp + do while (DR == 0) + call random_gauss(urand, rand_stat) + DR = urand(1) + enddo + + wlc_basepairs_prop = wlc_basepairs + wlc_nucleosomeWrap_prop = wlc_nucleosomeWrap + + + ! change JUST entry-exit angle + if (wlc_nucleosomeWrap(I) + DR <= max_wrap & + .and. wlc_basepairs(I) - DR <= max_base & + .and. wlc_basepairs(I) - DR >= min_base ) then + wlc_nucleosomeWrap_prop(I) = wlc_nucleosomeWrap(I) + DR + wlc_basepairs_prop(I) = wlc_basepairs(I) - DR + success = .true. + endif + + if (success) then + IT1 = I + IT2 = I + 1 + IB1 = get_IB(IT1) + IB2 = get_IB(IT2) + if (IB1 > 1) then + wlc_nBend = wlc_nBend + 1 + wlc_bendPoints(wlc_nBend) = IT1 + wlc_RP(:, IT1) = wlc_R(:, IT1) + wlc_UP(:, IT1) = wlc_U(:, IT1) + wlc_VP(:, IT1) = wlc_V(:, IT1) + wlc_nPointsMoved = wlc_nPointsMoved + 1 + wlc_pointsMoved(wlc_nPointsMoved) = IT1 + endif + if (IB2 < length_of_chain(get_IP(IT2))) then + wlc_nBend = wlc_nBend + 1 + wlc_bendPoints(wlc_nBend) = IT2 + J = IT2 + 1 + wlc_RP(:, J) = wlc_R(:, J) + wlc_UP(:, J) = wlc_U(:, J) + wlc_VP(:, J) = wlc_V(:, J) + wlc_nPointsMoved = wlc_nPointsMoved + 1 + wlc_pointsMoved(wlc_nPointsMoved) = J + endif + ! rotate + call nucleosome_prop(wlc_U(:, IT1), wlc_V(:, IT1), wlc_R(:, IT1), & + wlc_basepairs_prop(IT1), wlc_nucleosomeWrap_prop(IT1), & + tempU, tempV, tempR) + ! update nuc + tempR = tempR + WLC_P__LENGTH_PER_BP*tempU*wlc_basepairs_prop(IT1) + wlc_RP(:, IT2) = tempR + wlc_UP(:, IT2) = tempU + wlc_VP(:, IT2) = tempV + wlc_nPointsMoved = wlc_nPointsMoved + 1 + wlc_pointsMoved(wlc_nPointsMoved) = IT2 + else + wlc_basepairs_prop = wlc_basepairs + wlc_nucleosomeWrap_prop = wlc_nucleosomeWrap + endif + +end subroutine diff --git a/src/mc/mc_nucleosome_slide.f03 b/src/mc/mc_nucleosome_slide.f03 index 6401c9b4..0fc33026 100644 --- a/src/mc/mc_nucleosome_slide.f03 +++ b/src/mc/mc_nucleosome_slide.f03 @@ -1,9 +1,10 @@ #include "../defines.inc" !--------------------------------------------------------------* ! -! Slides nucleosomes in MC move +! Slides nucleosomes in MC move ! -! inspired by Quinn (chemMove/crank), implemented by NP 2020 +! implemented by NP may 2020 +! TODO: THIS IS NOT TESTED NOR FULLY DEVELOPED! ! !--------------------------------------------------------------- @@ -24,7 +25,8 @@ subroutine mc_nucleosome_slide(IB1, IB2, IT1, IT2, rand_stat, success) use mersenne_twister use params, only: dp use windowTools, only: exponential_random_int - use polydispersity, only: get_IP, first_bead_of_chain, last_bead_of_chain + use polydispersity, only: get_IP, first_bead_of_chain, last_bead_of_chain, & + get_IB, length_of_chain use nucleosome, only: nucleosome_prop implicit none @@ -39,23 +41,22 @@ subroutine mc_nucleosome_slide(IB1, IB2, IT1, IT2, rand_stat, success) real(dp) urand(1) ! single random number real(dp) :: MCAMP ! Amplitude of random change real(dp) DR ! Displacement for slide move (integer BPs) - real(dp), parameter :: optRatio = 0.25 ! max ratio of average discretization to allow for bp slide integer I ! test bead integer II, JJ, KK, J ! test indices - integer max_bp integer prevNuc, nextNuc, linkerSum integer nNucs integer nucArray(WLC_P__NT) real(dp), parameter :: eps = 0.00001 ! rescale to avoid urand vals of 0 + integer, parameter :: min_base = 3 + integer, parameter :: max_base = 15 ! initialize success = .false. - max_bp = 15 ! find nucs KK = 1 do II = 1, WLC_P__NT - if (wlc_nucleosomeWrap(II) == 1) cycle + if (wlc_nucleosomeWrap(II) == 0) cycle nucArray(KK) = II KK = KK + 1 enddo @@ -68,16 +69,13 @@ subroutine mc_nucleosome_slide(IB1, IB2, IT1, IT2, rand_stat, success) ! select distance to move (in bp) DR = 0.0_dp - MCAMP = max(nint(optRatio*sum(wlc_basepairs)/WLC_P__NT), 3) + MCAMP = max(nint(0.25*WLC_P__LL/WLC_P__NBPL), 1) -!call random_number(urand,rand_stat) -!if (urand(1)>=0.5) then ! 10 bp slide (half of moves) -! call random_number(urand,rand_stat) -! DR = 10*(-1)**nint(urand(1)) -!else ! few bp slide + +do while (DR == 0.0_dp) call random_number(urand, rand_stat) DR = MCAMP*(urand(1) - 0.5_dp) -!endif +enddo ! find neighboring nuclesomes prevNuc = KK - 1 @@ -103,8 +101,8 @@ subroutine mc_nucleosome_slide(IB1, IB2, IT1, IT2, rand_stat, success) ! change distance between beads outer1: do II = 1, I - prevNuc ! explore the previous linker space inner1: do JJ = 0, (nextNuc - 1) - I ! explore the next linker space - if ((wlc_basepairs(I - II) + DR > 3) .AND. (wlc_basepairs(I - II) + DR < max_bp) .AND. & - (wlc_basepairs(I + JJ) - DR > 3) .AND. (wlc_basepairs(I + JJ) - DR < max_bp)) then + if ((wlc_basepairs(I - II) + DR > min_base) .AND. (wlc_basepairs(I - II) + DR < max_base) .AND. & + (wlc_basepairs(I + JJ) - DR > min_base) .AND. (wlc_basepairs(I + JJ) - DR < max_base)) then wlc_basepairs_prop(I - II) = wlc_basepairs(I - II) + DR wlc_basepairs_prop(I + JJ) = wlc_basepairs(I + JJ) - DR success = .true. @@ -113,54 +111,32 @@ subroutine mc_nucleosome_slide(IB1, IB2, IT1, IT2, rand_stat, success) enddo inner1 enddo outer1 -! piece-wise movement of linker rather than just on one bead - linkerSum = 0 -!if (success .eqv. .false.) then -! outer2: do II = 1, I-prevNuc ! explore the previous linker space -! inner2: do JJ = 0, (nextNuc-1)-I ! explore the next linker space -! if ((wlc_basepairs(I-II)+DR/(I-prevNuc) > 3) .AND. (wlc_basepairs(I-II)+DR/(I-prevNuc) < max_bp) .AND. & -! (wlc_basepairs(I+JJ)-DR/(I-prevNuc) > 3) .AND. (wlc_basepairs(I+JJ)-DR/(I-prevNuc) < max_bp) ) then -! wlc_basepairs_prop(I-II) = wlc_basepairs(I-II) + DR/(I-prevNuc) -! wlc_basepairs_prop(I+JJ) = wlc_basepairs(I+JJ) - DR/(I-prevNuc) -! linkerSum = linkerSum + abs(DR/(I-prevNuc)) -! if (linkerSum>=10) then -! success = .true. -! !print*, 'WOO' -! exit outer2 -! endif -! endif -! enddo inner2 -! enddo outer2 -!endif - if (success) then - IB1 = I - II - IB2 = I + JJ - IT1 = IB1 + 1 - IT2 = IB2 - 1 - if (IB1 >= 1) then + IT1 = I - II + IT2 = I + JJ + IB1 = get_IB(IT1) + IB2 = get_IB(IT2) + if (IB1 > 1) then wlc_nBend = wlc_nBend + 1 - wlc_bendPoints(wlc_nBend) = IB1 - J = IB1 + wlc_bendPoints(wlc_nBend) = IT1 + wlc_RP(:, IT1) = wlc_R(:, IT1) + wlc_UP(:, IT1) = wlc_U(:, IT1) + wlc_VP(:, IT1) = wlc_V(:, IT1) + wlc_nPointsMoved = wlc_nPointsMoved + 1 + wlc_pointsMoved(wlc_nPointsMoved) = IT1 + endif + if (IB2 < length_of_chain(get_IP(IT2))) then + wlc_nBend = wlc_nBend + 1 + wlc_bendPoints(wlc_nBend) = IT2 + J = IT2 + 1 wlc_RP(:, J) = wlc_R(:, J) wlc_UP(:, J) = wlc_U(:, J) wlc_VP(:, J) = wlc_V(:, J) wlc_nPointsMoved = wlc_nPointsMoved + 1 wlc_pointsMoved(wlc_nPointsMoved) = J endif - if (IB2 < WLC_P__NT) then - wlc_nBend = wlc_nBend + 1 - wlc_bendPoints(wlc_nBend) = IB2 - do J = IB2, IB2 + 1 - wlc_RP(:, J) = wlc_R(:, J) - wlc_UP(:, J) = wlc_U(:, J) - wlc_VP(:, J) = wlc_V(:, J) - wlc_nPointsMoved = wlc_nPointsMoved + 1 - wlc_pointsMoved(wlc_nPointsMoved) = J - enddo - endif - do KK = IT1, IT2 - wlc_RP(:, KK) = wlc_R(:, KK) + wlc_U(:, KK)*WLC_P__LENGTH_PER_BP*(wlc_basepairs_prop(KK) - wlc_basepairs(KK)) + do KK = IT1 + 1, IT2 + wlc_RP(:, KK) = wlc_R(:, KK) + (wlc_U(:, KK - 1)+wlc_U(:, KK))*WLC_P__LENGTH_PER_BP*DR wlc_UP(:, KK) = wlc_U(:, KK) wlc_VP(:, KK) = wlc_V(:, KK) wlc_nPointsMoved = wlc_nPointsMoved + 1 diff --git a/src/mc/mc_sterics.f03 b/src/mc/mc_sterics.f03 index 2281787b..ba7561ce 100644 --- a/src/mc/mc_sterics.f03 +++ b/src/mc/mc_sterics.f03 @@ -1,12 +1,11 @@ #include "../defines.inc" !-------------------------------------------------------------- ! -! subroutine MC_sterics -! +! subroutine MC_sterics ! Determine if moved beads intersect old beads. -! Written by Nicole Pagane, Mar 2020 -! Inspired from Quinn's cylinder collision code -! GJK algorithm used for collision detection +! +! Written by NP, Mar 2020 +! !-------------------------------------------------------------- subroutine MC_sterics(collisions, netSterics, MCTYPE) @@ -14,7 +13,7 @@ subroutine MC_sterics(collisions, netSterics, MCTYPE) ! utils/sterics file for actual implentation of GJK. use params, only: dp, NAN, wlc_RP, wlc_UP, wlc_VP, wlc_R, wlc_U, wlc_V, wlc_GJK, & wlc_R_GJK, wlc_nucleosomeWrap, wlc_nPointsMoved, wlc_bin, wlc_basepairs, & - wlc_basepairs_prop, wlc_pointsMoved + wlc_basepairs_prop, wlc_pointsMoved, wlc_nucleosomeWrap_prop use GJKAlgorithm, only: constructPolygonPrism use polydispersity, only: get_IP, first_bead_of_chain, last_bead_of_chain use binning, only: find_neighbors @@ -29,6 +28,7 @@ subroutine MC_sterics(collisions, netSterics, MCTYPE) real(dp) SGJK(WLC_P__GJK_POLYGON, 3, WLC_P__NT) ! all vertices for GJK real(dp) RGJK(3, WLC_P__NT) ! all centers for GJK real(dp) basepairs(WLC_P__NT) ! basepairs + real(dp) wrapping(WLC_P__NT) ! wrapping real(dp) distances(WLC_P__NT) ! Returned distances integer neighbors(WLC_P__NT) ! ID of neighboring beads integer nn ! number of neighbors @@ -60,8 +60,8 @@ subroutine MC_sterics(collisions, netSterics, MCTYPE) call findNeighbors(RGJK(:, i - 1), 2*WLC_P__GJK_RADIUS, & RGJK, WLC_P__NT, WLC_P__NT, neighbors, distances, nn) ! check for collisions - call sterics_check(collisions, RALL, UALL, VALL, SGJK, wlc_basepairs, ignore, i - 1, & - nn, neighbors(1:nn), distances(1:nn), .true.) + call sterics_check(collisions, RALL, UALL, VALL, SGJK, wlc_basepairs, wlc_nucleosomeWrap, ignore, & + i - 1, nn, neighbors(1:nn), distances(1:nn), .true.) endif ! check succeeding bead if ((ANY(ignore == i) .eqv. .false.) .AND. (i < last_bead_of_chain(IP))) then @@ -70,17 +70,21 @@ subroutine MC_sterics(collisions, netSterics, MCTYPE) call findNeighbors(RGJK(:, i), 2*WLC_P__GJK_RADIUS, & RGJK, WLC_P__NT, WLC_P__NT, neighbors, distances, nn) ! check for collisions - call sterics_check(collisions, RALL, UALL, VALL, SGJK, wlc_basepairs, ignore, i, & - nn, neighbors(1:nn), distances(1:nn), .true.) + call sterics_check(collisions, RALL, UALL, VALL, SGJK, wlc_basepairs, wlc_nucleosomeWrap, ignore, & + i, nn, neighbors(1:nn), distances(1:nn), .true.) endif enddo endif - ! set basepairs vector - if (WLC_P__MOVEON_NUCLEOSOMESLIDE == 1 .AND. MCTYPE == 13) then + ! set basepairs and wrapping vector + basepairs = wlc_basepairs + wrapping = wlc_nucleosomeWrap + if (WLC_P__MOVEON_NUCLEOSOME_SLIDE == 1 .AND. WLC_P__MOVEON_NUCLEOSOME_BREATHE == 0) then basepairs = wlc_basepairs_prop - else - basepairs = wlc_basepairs - endif + endif + if (WLC_P__MOVEON_NUCLEOSOME_BREATHE == 1) then + basepairs = wlc_basepairs_prop + wrapping = wlc_nucleosomeWrap_prop + endif ! replace old beads with new moved beads k = 1 ignore = NAN @@ -97,11 +101,11 @@ subroutine MC_sterics(collisions, netSterics, MCTYPE) k = k + 1 if (isnan(wlc_RP(1, i - 1))) then poly = constructPolygonPrism(wlc_R(:, i - 1), wlc_RP(:, i), & - wlc_nucleosomeWrap(i - 1), wlc_U(:, i - 1), & + wrapping(i - 1), wlc_U(:, i - 1), & wlc_V(:, i - 1), WLC_P__GJK_POLYGON) else poly = constructPolygonPrism(wlc_RP(:, i - 1), wlc_RP(:, i), & - wlc_nucleosomeWrap(i - 1), wlc_UP(:, i - 1), & + wrapping(i - 1), wlc_UP(:, i - 1), & wlc_VP(:, i - 1)/norm2(wlc_VP(:, i - 1)), WLC_P__GJK_POLYGON) endif SGJK(:, :, i - 1) = poly @@ -115,11 +119,11 @@ subroutine MC_sterics(collisions, netSterics, MCTYPE) k = k + 1 if (isnan(wlc_RP(1, i + 1))) then poly = constructPolygonPrism(wlc_RP(:, i), wlc_R(:, i + 1), & - wlc_nucleosomeWrap(i), wlc_UP(:, i), & + wrapping(i), wlc_UP(:, i), & wlc_VP(:, i)/norm2(wlc_VP(:, i)), WLC_P__GJK_POLYGON) else poly = constructPolygonPrism(wlc_RP(:, i), wlc_RP(:, i + 1), & - wlc_nucleosomeWrap(i), wlc_UP(:, i), & + wrapping(i), wlc_UP(:, i), & wlc_VP(:, i)/norm2(wlc_VP(:, i)), WLC_P__GJK_POLYGON) endif SGJK(:, :, i) = poly @@ -129,8 +133,9 @@ subroutine MC_sterics(collisions, netSterics, MCTYPE) endif enddo collisions = -collisions - ! set up ignore beads - if (WLC_P__NEIGHBOR_BINS .AND. (MCTYPE /= 13) .AND. (netSterics .eqv. .false.)) then + ! set up ignore beads for normal MC moves where there are no expected collisions within + ! moved beads. this is the case for all EXCEPT nucleosome sliding and breathing + if (WLC_P__NEIGHBOR_BINS .AND. (MCTYPE /= 13 .AND. MCTYPE /= 14) .AND. (netSterics .eqv. .false.)) then ignore_bin = NAN ignore_bin(1:wlc_nPointsMoved) = wlc_pointsMoved(1:wlc_nPointsMoved) endif @@ -144,49 +149,49 @@ subroutine MC_sterics(collisions, netSterics, MCTYPE) if ((ANY(ignore == i - 1) .eqv. .false.) .AND. (i > first_bead_of_chain(IP))) then ignore(k) = i - 1 k = k + 1 - if (WLC_P__NEIGHBOR_BINS .AND. (MCTYPE /= 13) .AND. (netSterics .eqv. .false.)) then + if (WLC_P__NEIGHBOR_BINS .AND. (MCTYPE /= 13 .AND. MCTYPE /= 14) .AND. (netSterics .eqv. .false.)) then nn = 0 call find_neighbors(wlc_bin, RGJK(:, i - 1), 2*WLC_P__GJK_RADIUS, & wlc_R_GJK, WLC_P__NT, WLC_P__NT, neighbors, distances, nn) ! check for collisions - call sterics_check(collisions, RALL, UALL, VALL, SGJK, basepairs, ignore_bin, i - 1, & - nn, neighbors(1:nn), distances(1:nn), netSterics) + call sterics_check(collisions, RALL, UALL, VALL, SGJK, basepairs, wrapping, ignore_bin, & + i - 1, nn, neighbors(1:nn), distances(1:nn), netSterics) else call findNeighbors(RGJK(:, i - 1), 2*WLC_P__GJK_RADIUS, & RGJK, WLC_P__NT, WLC_P__NT, neighbors, distances, nn) ! check for collisions - call sterics_check(collisions, RALL, UALL, VALL, SGJK, basepairs, ignore, i - 1, & - nn, neighbors(1:nn), distances(1:nn), netSterics) + call sterics_check(collisions, RALL, UALL, VALL, SGJK, basepairs, wrapping, ignore, & + i - 1, nn, neighbors(1:nn), distances(1:nn), netSterics) endif endif ! check succeeding bead if ((ANY(ignore == i) .eqv. .false.) .AND. (i < last_bead_of_chain(IP))) then ignore(k) = i k = k + 1 - if (WLC_P__NEIGHBOR_BINS .AND. (MCTYPE /= 13) .AND. (netSterics .eqv. .false.)) then + if (WLC_P__NEIGHBOR_BINS .AND. (MCTYPE /= 13 .AND. MCTYPE /= 14) .AND. (netSterics .eqv. .false.)) then nn = 0 call find_neighbors(wlc_bin, RGJK(:, i), 2*WLC_P__GJK_RADIUS, & wlc_R_GJK, WLC_P__NT, WLC_P__NT, neighbors, distances, nn) ! check for collisions - call sterics_check(collisions, RALL, UALL, VALL, SGJK, basepairs, ignore_bin, i, & - nn, neighbors(1:nn), distances(1:nn), netSterics) + call sterics_check(collisions, RALL, UALL, VALL, SGJK, basepairs, wrapping, ignore_bin, & + i, nn, neighbors(1:nn), distances(1:nn), netSterics) else call findNeighbors(RGJK(:, i), 2*WLC_P__GJK_RADIUS, & RGJK, WLC_P__NT, WLC_P__NT, neighbors, distances, nn) ! check for collisions - call sterics_check(collisions, RALL, UALL, VALL, SGJK, basepairs, ignore, i, & - nn, neighbors(1:nn), distances(1:nn), netSterics) + call sterics_check(collisions, RALL, UALL, VALL, SGJK, basepairs, wrapping, ignore, & + i, nn, neighbors(1:nn), distances(1:nn), netSterics) endif endif enddo endif END subroutine MC_sterics -subroutine sterics_check(collisions, RALL, UALL, VALL, SGJK, basepairs, ignore, ii, nn, neighbors, distances, netSterics) +subroutine sterics_check(collisions, RALL, UALL, VALL, SGJK, basepairs, wrapping, ignore, ii, nn, neighbors, distances, netSterics) ! sterics check subroutine to check for different types of collisions (i.e. nuc vs nuc, nuc vs dna, dna vs dna) ! iterates through the nearest neighbors of the specified bead to check for any collisions use GJKAlgorithm, only: GJK, constructPolygonPrism - use params, only: dp, wlc_basepairs, wlc_nucleosomeWrap, wlc_pointsMoved, wlc_nPointsMoved + use params, only: dp use nucleosome, only: nucleosome_prop use polydispersity, only: get_IP, first_bead_of_chain, last_bead_of_chain implicit none @@ -197,6 +202,7 @@ subroutine sterics_check(collisions, RALL, UALL, VALL, SGJK, basepairs, ignore, real(dp), intent(in) :: VALL(3, WLC_P__NT) ! all bead V real(dp), intent(in) :: SGJK(WLC_P__GJK_POLYGON, 3, WLC_P__NT) ! all vertices for GJK real(dp), intent(in) :: basepairs(WLC_P__NT) ! basepair discretization + real(dp), intent(in) :: wrapping(WLC_P__NT) ! bp wrapping of beads integer, intent(in) :: ignore(WLC_P__NT) ! beads that have already been checked, i.e. ignore integer, intent(in) :: ii ! index of moved bead integer, intent(in) :: nn ! number of neighbors @@ -213,11 +219,11 @@ subroutine sterics_check(collisions, RALL, UALL, VALL, SGJK, basepairs, ignore, if (ii == last_bead_of_chain(get_IP(ii))) return ! determine identity of moving bead - if (wlc_nucleosomeWrap(ii) /= 1) then ! is nucleosome + if (wrapping(ii) /= 0) then ! is nucleosome iiIsNucleosome = .TRUE. - call nucleosome_prop(UALL(:, ii), VALL(:, ii), RALL(:, ii), basepairs(ii), wlc_nucleosomeWrap(ii), & + call nucleosome_prop(UALL(:, ii), VALL(:, ii), RALL(:, ii), basepairs(ii), wrapping(ii), & tempU, tempV, tempR) - poly1ExitDNA = constructPolygonPrism(tempR, RALL(:, ii + 1), 1, tempU, tempV, s) + poly1ExitDNA = constructPolygonPrism(tempR, RALL(:, ii + 1), 0.0_dp, tempU, tempV, s) else iiIsNucleosome = .FALSE. endif @@ -229,11 +235,11 @@ subroutine sterics_check(collisions, RALL, UALL, VALL, SGJK, basepairs, ignore, do jj = 1, nn if (ANY(ignore == neighbors(jj)) .or. (neighbors(jj) == last_bead_of_chain(get_IP(neighbors(jj))))) cycle ! determine identity of potentially collided bead - if (wlc_nucleosomeWrap(neighbors(jj)) /= 1) then ! is nucleosome + if (wrapping(neighbors(jj)) /= 0) then ! is nucleosome jjIsNucleosome = .TRUE. call nucleosome_prop(UALL(:, neighbors(jj)), VALL(:, neighbors(jj)), RALL(:, neighbors(jj)), & - basepairs(neighbors(jj)), wlc_nucleosomeWrap(neighbors(jj)), tempU, tempV, tempR) - poly2ExitDNA = constructPolygonPrism(tempR, RALL(:, neighbors(jj) + 1), 1, tempU, tempV, s) + basepairs(neighbors(jj)), wrapping(neighbors(jj)), tempU, tempV, tempR) + poly2ExitDNA = constructPolygonPrism(tempR, RALL(:, neighbors(jj) + 1), 0.0_dp, tempU, tempV, s) else jjIsNucleosome = .FALSE. endif @@ -272,6 +278,9 @@ subroutine sterics_check(collisions, RALL, UALL, VALL, SGJK, basepairs, ignore, endif endif ! check for moved bead nuc + DNA within relevant distance cutoff + ! Skip therest if you only care about nuc-nuc sterics + else if (WLC_P__GJK_NUC_ONLY) then + continue else if (iiIsNucleosome .AND. (jjIsNucleosome .EQV. .FALSE.) .AND. & distances(jj) < (2*basepairs(neighbors(jj))*WLC_P__LENGTH_PER_BP) + WLC_P__GJK_RADIUS) then ! nuc i + DNA j ! ignore 10bp nearest nuc, this is inspired from what elena koslover did in fibermodel @@ -350,4 +359,4 @@ subroutine findNeighbors(pos, radius, beads, nBeads, neighboringMax, neighbors, enddo end subroutine findNeighbors -! ---------------------------------------------------------------* \ No newline at end of file +! ---------------------------------------------------------------* diff --git a/src/mc/mcsim.f03 b/src/mc/mcsim.f03 index 4058f8dc..c83467f2 100644 --- a/src/mc/mcsim.f03 +++ b/src/mc/mcsim.f03 @@ -15,7 +15,7 @@ subroutine mcsim(wlc_p) , pack_as_para, nMoveTypes, wlc_pointsMoved, wlc_bendPoints & , wlcsim_params_recenter, wlc_Lk0, wlc_Lk, wlc_Tw, wlc_Wr & , wlc_VP, wlc_U, wlc_V, wlc_R_GJK, wlc_nucleosomeWrap, & - wlc_basepairs, wlc_basepairs_prop + wlc_basepairs, wlc_basepairs_prop, wlc_nucleosomeWrap_prop use energies use umbrella, only: umbrella_energy @@ -133,9 +133,18 @@ pure function list_confinement() endif endif - ! set wlc_basepairs to prop if not slide move - if (MCTYPE /= 13 .AND. WLC_P__MOVEON_NUCLEOSOMESLIDE == 1) then - wlc_basepairs_prop = wlc_basepairs + ! set wlc_basepairs and wrap to prop if not breathe or slide move + if (WLC_P__MOVEON_NUCLEOSOME_BREATHE == 1) then + if (MCTYPE /= 14 .AND. MCTYPE /= 13) then + wlc_basepairs_prop = wlc_basepairs + wlc_nucleosomeWrap_prop = wlc_nucleosomeWrap + else if (MCTYPE == 13) then + wlc_nucleosomeWrap_prop = wlc_nucleosomeWrap + endif + else + if (MCTYPE /= 13 .AND. WLC_P__MOVEON_NUCLEOSOME_SLIDE == 1) then + wlc_basepairs_prop = wlc_basepairs + endif endif ! sterics check here ! @@ -301,8 +310,12 @@ pure function list_confinement() wlc_AB(I) = wlc_ABP(I) ENDdo endif - if (MCTYPE == 13 .AND. WLC_P__MOVEON_NUCLEOSOMESLIDE == 1) then + if (MCTYPE == 13) then + wlc_basepairs = wlc_basepairs_prop + endif + if (MCTYPE == 14) then wlc_basepairs = wlc_basepairs_prop + wlc_nucleosomeWrap = wlc_nucleosomeWrap_prop endif if (MCTYPE /= 7) then do I = 1, wlc_nPointsMoved diff --git a/src/mc/nucleosome.f03 b/src/mc/nucleosome.f03 index 03c6e37b..ba59a0f7 100644 --- a/src/mc/nucleosome.f03 +++ b/src/mc/nucleosome.f03 @@ -11,8 +11,8 @@ module nucleosome implicit none real(dp), parameter :: basePairsPerTurn = 10.5_dp real(dp), dimension(10, WLC_P__MAX_BACEPAIRS_PER_BEAD) :: multiParams - real(dp), dimension(3, 3, 147) :: nucleosomeROT - real(dp), dimension(3, 147) :: nucleosomeTran + real(dp), dimension(3, 3, 0:160) :: nucleosomeROT + real(dp), dimension(3, 0:160) :: nucleosomeTran private :: nucleosomeROT, nucleosomeTran contains @@ -30,7 +30,7 @@ subroutine nucleosome_prop(Uin, Vin, Rin, linkBP, wrapBP, Uout, Vout, Rout) real(dp), intent(in), dimension(3) :: Vin ! Entry tangent vector real(dp), intent(in), dimension(3) :: Rin ! Position of entry real(dp), intent(in) :: linkBP - integer, intent(in) :: wrapBP + real(dp), intent(in) :: wrapBP real(dp), intent(out), dimension(3) :: Uout ! Exit position real(dp), intent(out), dimension(3) :: Vout ! Exit tangent vector real(dp), intent(out), dimension(3) :: Rout ! Exit position @@ -38,18 +38,34 @@ subroutine nucleosome_prop(Uin, Vin, Rin, linkBP, wrapBP, Uout, Vout, Rout) real(dp), dimension(3, 3) :: linkRot real(dp), dimension(3, 3) :: mtrx real(dp), parameter :: angle = 2*pi/basePairsPerTurn ! intrinsic rotation/bp + real(dp) interTran(3) + real(dp) interRot(3, 3) + integer indUp, indDown + real(dp) ratio, offratio mtrx(:, 1) = Vin mtrx(:, 2) = cross(Uin, Vin) mtrx(:, 3) = Uin - Rout = Rin + MATMUL(mtrx, nucleosomeTran(:, wrapBP)) + ! interpolate for wrapBP + indDown = floor(wrapBP) + indUp = ceiling(wrapBP) + if (indUp == 0) then + ratio = 0 + else + ratio = wrapBP/indUp + endif + offratio = 1 - ratio + interTran = ratio*nucleosomeTran(:, indUp) + offratio*nucleosomeTran(:, indDown) + interRot = ratio*nucleosomeRot(:, :, indUp) + offratio*nucleosomeRot(:, :, indDown) + + Rout = Rin + MATMUL(mtrx, interTran) linkRot(1, :) = [cos(angle*linkBP), -sin(angle*linkBP), 0.0_dp] linkRot(2, :) = [sin(angle*linkBP), cos(angle*linkBP), 0.0_dp] linkRot(3, :) = [0.0_dp, 0.0_dp, 1.0_dp] - mtrx = MATMUL(MATMUL(mtrx, nucleosomeROT(:, :, wrapBP)), linkRot) + mtrx = MATMUL(MATMUL(mtrx, interRot), linkRot) Uout = mtrx(:, 3)/norm2(mtrx(:, 3)) Vout = mtrx(:, 1)/norm2(mtrx(:, 1)) @@ -71,7 +87,7 @@ function nucleosome_energy(RP1, R, UP1, U, VP1, V, linkBP, wrapBP) real(dp), intent(in), dimension(3) :: V ! V of bead i real(dp), intent(in), dimension(3) :: VP1 ! V of bead i+1 real(dp), intent(in) :: linkBP - integer, intent(in) :: wrapBP + real(dp), intent(in) :: wrapBP real(dp) nucleosome_energy(4) real(dp) EB, EPAR, EPERP, GAM, ETA, XIR, XIU, sigma, etwist, simtype @@ -114,25 +130,25 @@ function internucleosome_energy(RI, RJ, UI, UJ, VI, VJ) real(dp), intent(in), dimension(3) :: UJ ! U of nuc j real(dp), intent(in), dimension(3) :: VI ! V of nuc i real(dp), intent(in), dimension(3) :: VJ ! V of nuc j - real(dp), parameter :: tau_faceface = 1.38 - real(dp), parameter :: e_faceface = 3.712*WLC_P__INTERNUCLEOSOME_ENERGY - real(dp), parameter :: tau_faceside = 0.82 - real(dp), parameter :: e_faceside = 1.476*WLC_P__INTERNUCLEOSOME_ENERGY - real(dp), parameter :: tau_sideside = 2.0 - real(dp), parameter :: e_sideside = 1.64*WLC_P__INTERNUCLEOSOME_ENERGY - real(dp), dimension(3), parameter :: center = [4.8455, -2.4445, 0.6694] + real(dp), parameter :: tau_faceface = 1.38_dp + real(dp), parameter :: e_faceface = 3.712_dp ! scaling in params file + real(dp), parameter :: tau_faceside = 0.82_dp + real(dp), parameter :: e_faceside = 1.476_dp ! scaling in params file + real(dp), parameter :: tau_sideside = 2.0_dp + real(dp), parameter :: e_sideside = 1.64_dp ! scaling in params file + real(dp), dimension(3), parameter :: center = [4.1900_dp, -2.022_dp, 0.2300_dp] real(dp), dimension(3, 3) :: mtrxI, mtrxJ real(dp), dimension(3) :: polyI, faceI, faceItop, faceIbot real(dp), dimension(3) :: polyJ, faceJ, faceJtop, faceJbot real(dp), dimension(4, 3) :: faceDistList real(dp), dimension(4) :: distList real(dp), dimension(3) :: distS, distC, dist - real(dp) cospsi, costhetaI, costhetaJ, cosphiI, cosphiJ + real(dp) cospsi, costhetaI, costhetaJ, cosphiI, cosphiJ, tempAngle integer i, indList(1) real(dp) internucleosome_energy ! initialiaze - internucleosome_energy = 0 + internucleosome_energy = 0.0_dp ! construct matrices mtrxI(:, 1) = VI @@ -174,10 +190,10 @@ function internucleosome_energy(RI, RJ, UI, UJ, VI, VJ) ! face-face (histone-histone attraction) if (norm2(distS) <= tau_faceface) then internucleosome_energy = internucleosome_energy & - - e_faceface*(costhetaI**2)*(costhetaJ**2)/tau_faceface + - e_faceface*abs(costhetaI)*abs(costhetaJ)/tau_faceface else internucleosome_energy = internucleosome_energy & - - e_faceface*(costhetaI**2)*(costhetaJ**2)/norm2(distS) + - e_faceface*abs(costhetaI)*abs(costhetaJ)/norm2(distS) endif distC = polyI - polyJ cosphiI = dot_product(distC/norm2(distC), faceI/norm2(faceI)) @@ -185,22 +201,26 @@ function internucleosome_energy(RI, RJ, UI, UJ, VI, VJ) ! face-side (histone-DNA wrapping attraction) dist = norm2(distC) - WLC_P__NUCLEOSOME_HEIGHT/2 - WLC_P__NUCLEOSOME_RADIUS + tempAngle = abs(cosphiI) + abs(cosphiJ) + if (tempAngle > 1) then + tempAngle = 2 - tempAngle + endif if (norm2(dist) <= tau_faceside) then internucleosome_energy = internucleosome_energy & - - e_faceside*(1 - cospsi**2)*(cosphiI**2 + cosphiJ**2)/tau_faceside + - e_faceside*(1 - abs(cospsi))*tempAngle/tau_faceside else internucleosome_energy = internucleosome_energy & - - e_faceside*(1 - cospsi**2)*(cosphiI**2 + cosphiJ**2)/norm2(dist) + - e_faceside*(1 - abs(cospsi))*tempAngle/norm2(dist) endif ! side-side (DNA wrapping-DNA wrapping attraction) dist = norm2(distC)-2*WLC_P__NUCLEOSOME_RADIUS if (norm2(dist) <= tau_sideside) then internucleosome_energy = internucleosome_energy & - - e_sideside*(1 - cosphiI**2)*(1 - cosphiJ**2)/tau_sideside + - e_sideside*(1 - abs(cosphiI))*(1 - abs(cosphiJ))/tau_sideside else internucleosome_energy = internucleosome_energy & - - e_sideside*(1 - cosphiI**2)*(1 - cosphiJ**2)/norm2(dist) + - e_sideside*(1 - abs(cosphiI))*(1 - abs(cosphiJ))/norm2(dist) endif end function internucleosome_energy @@ -278,17 +298,17 @@ subroutine setup_nucleosome_constants() enddo open (UNIT=5, FILE="input/nucleosomeR", STATUS="OLD") - do i = 1, 147 + do i = 0, 160 do j = 1, 3 - read (5, *) nucleosomeROT(j, :, 148 - i) + read (5, *) nucleosomeROT(j, :, 160 - i) enddo enddo close (5) if (WLC_P__INCLUDE_NUC_TRANS) then open (UNIT=5, FILE="input/nucleosomeT", STATUS="OLD") - do i = 1, 147 - read (5, *) nucleosomeTran(:, 148 - i) + do i = 0, 160 + read (5, *) nucleosomeTran(:, 160 - i) enddo close (5) else @@ -310,19 +330,23 @@ subroutine load_nucleosome_positions(wlc_nucleosomeWrap, wlc_basepairs) ! on the chain according to WLC_P__LINKER_TYPE, where the default is 'phased', i.e. ! the nuclesomes are separated by a constant linker length throughout the chain use precision, only: nan + use mersenne_twister ! sterics testing ! use GJKAlgorithm, only: GJK, sameShapeTest, noIntersectX, intersectX, tangentX, runtimeTest5, runtimeTest6, & noIntersectY, intersectY, tangentY, runtimeTest1, runtimeTest3, & noIntersectZ, intersectZ, tangentZ, runtimeTest2, runtimeTest4 use polydispersity, only: first_bead_of_chain, last_bead_of_chain implicit none - integer, intent(out) :: wlc_nucleosomeWrap(WLC_P__NT) + real(dp), intent(out) :: wlc_nucleosomeWrap(WLC_P__NT) real(dp), intent(out) :: wlc_basepairs(WLC_P__NT) real(dp) discretization, num_link_beads - real(dp), dimension(2, 33) :: LL_dist + !real(dp), dimension(2, 33) :: LL_dist + real(dp), allocatable, dimension(:, :):: LL_dist ! linker length distribution to sample from + type(random_stat) rand_stat real(dp) cumlinker, linker real(dp) urand(3) ! random vector integer iter, i, j, k + integer nlines, io if (WLC_P__INCLUDE_NUC_TRANS) then if (WLC_P__INCLUDE_DISCRETIZE_LINKER) then @@ -337,84 +361,109 @@ subroutine load_nucleosome_positions(wlc_nucleosomeWrap, wlc_basepairs) iter = iter + num_link_beads ! set middle linkers do j = 2, WLC_P__NUM_NUCLEOSOMES ! hanging linker off nucleosomes - wlc_nucleosomeWrap(iter) = 147 + if ( WLC_P__MOVEON_NUCLEOSOME_BREATHE == 1) then + call random_gauss(urand, rand_stat) + else + urand = 0 + endif + wlc_nucleosomeWrap(iter) = WLC_P__NUCLEOSOME_WRAPPING + urand(1) wlc_basepairs(iter) = discretization iter = iter + 1 if (iter + num_link_beads - 2 <= last_bead_of_chain(i) - num_link_beads) then wlc_basepairs(iter:iter + num_link_beads - 2) = discretization - wlc_nucleosomeWrap(iter:iter + num_link_beads - 2) = 1 + wlc_nucleosomeWrap(iter:iter + num_link_beads - 2) = 0 iter = iter + num_link_beads - 1 endif enddo ! first linker - wlc_nucleosomeWrap(first_bead_of_chain(i):first_bead_of_chain(i) + num_link_beads - 1) = 1 + wlc_nucleosomeWrap(first_bead_of_chain(i):first_bead_of_chain(i) + num_link_beads - 1) = 0 wlc_basepairs(first_bead_of_chain(i):first_bead_of_chain(i) + num_link_beads - 1) = discretization ! last linker + if ( WLC_P__MOVEON_NUCLEOSOME_BREATHE == 1) then + call random_gauss(urand, rand_stat) + else + urand = 0 + endif wlc_basepairs(iter) = discretization - wlc_nucleosomeWrap(iter) = 147 + wlc_nucleosomeWrap(iter) = WLC_P__NUCLEOSOME_WRAPPING + urand(1) iter = iter + 1 - wlc_nucleosomeWrap(iter:iter + num_link_beads - 1) = 1 + wlc_nucleosomeWrap(iter:iter + num_link_beads - 1) = 0 wlc_basepairs(iter:iter + num_link_beads - 1) = discretization ! set last wlc_basepairs to 0 as reminder that this is not an actual extension wlc_basepairs(last_bead_of_chain(i)) = 0 enddo - else if (WLC_P__LINKER_TYPE == 'voong') then - ! read in the LL distribution - open (UNIT = 5, FILE = "input/Voong_LL_23to55.txt", STATUS = "OLD") - do i = 1, 33 - read(5, *) LL_dist(:, i) + else ! any specific LL distribution file + ! read in and allocate the LL distribution + nlines = 0 + open (1, FILE = WLC_P__LINKER_TYPE, STATUS = "OLD") + do + read(1,*,iostat=io) + if (io/=0) exit + nlines = nlines + 1 + enddo + close (1) + allocate (LL_dist(2, nlines)) + ! now set LL distribuion + open (1, FILE = WLC_P__LINKER_TYPE, STATUS = "OLD") + do i = 1, nlines + read(1, *) LL_dist(:, i) enddo - close (5) + close (1) do k = 1, WLC_P__NP - linker = 0 - do while (linker <= 23 .or. linker >= 55) - ! initialize - cumlinker = 0 - iter = first_bead_of_chain(k) - ! set first linker later - iter = iter + num_link_beads - ! set middle linkers - do i = 2, WLC_P__NUM_NUCLEOSOMES ! hanging linker off nucleosomes - call random_number(urand) - do j = 1, 33 - if (LL_dist(2, j) >= urand(1)) then - exit - endif - enddo - linker = LL_dist(1, j) - discretization = linker/num_link_beads - print*, linker, discretization, num_link_beads - wlc_nucleosomeWrap(iter) = 147 - wlc_basepairs(iter) = discretization - iter = iter + 1 - if (iter + num_link_beads - 2 <= last_bead_of_chain(k) - num_link_beads) then - wlc_basepairs(iter:iter + num_link_beads - 2) = discretization - wlc_nucleosomeWrap(iter:iter + num_link_beads - 2) = 1 - iter = iter + num_link_beads - 1 + ! initialize + cumlinker = 0 + iter = first_bead_of_chain(k) + ! set first linker later + iter = iter + num_link_beads + ! set middle linkers + do i = 2, WLC_P__NUM_NUCLEOSOMES ! hanging linker off nucleosomes + call random_number(urand, rand_stat) + do j = 1, nlines + if (LL_dist(2, j) >= urand(1)) then + exit endif - cumlinker = cumlinker + linker enddo - ! set last (and first) linker to conserve contour length - linker = (WLC_P__LL*(1 + WLC_P__NUM_NUCLEOSOMES) - cumlinker)/2 - print*, 'attempted to sample from linker distribution for chain' + linker = LL_dist(1, j) + discretization = linker/num_link_beads + wlc_nucleosomeWrap(iter) = WLC_P__NUCLEOSOME_WRAPPING + wlc_basepairs(iter) = discretization + iter = iter + 1 + if (iter + num_link_beads - 2 <= last_bead_of_chain(k) - num_link_beads) then + wlc_basepairs(iter:iter + num_link_beads - 2) = discretization + wlc_nucleosomeWrap(iter:iter + num_link_beads - 2) = 0 + iter = iter + num_link_beads - 1 + endif + cumlinker = cumlinker + linker enddo - discretization = linker/num_link_beads - print*, linker, discretization, num_link_beads + !linker = (WLC_P__LL*(1 + WLC_P__NUM_NUCLEOSOMES) - cumlinker)/2 ! first linker - wlc_nucleosomeWrap(first_bead_of_chain(k):first_bead_of_chain(k) + num_link_beads - 1) = 1 + call random_number(urand, rand_stat) + do j = 1, nlines + if (LL_dist(2, j) >= urand(1)) then + exit + endif + enddo + linker = LL_dist(1, j) + discretization = linker/num_link_beads + wlc_nucleosomeWrap(first_bead_of_chain(k):first_bead_of_chain(k) + num_link_beads - 1) = 0 wlc_basepairs(first_bead_of_chain(k):first_bead_of_chain(k) + num_link_beads - 1) = discretization ! last linker + call random_number(urand, rand_stat) + do j = 1, nlines + if (LL_dist(2, j) >= urand(1)) then + exit + endif + enddo + linker = LL_dist(1, j) + discretization = linker/num_link_beads wlc_basepairs(iter) = discretization - wlc_nucleosomeWrap(iter) = 147 + wlc_nucleosomeWrap(iter) = WLC_P__NUCLEOSOME_WRAPPING iter = iter + 1 - wlc_nucleosomeWrap(iter:iter + num_link_beads - 1) = 1 + wlc_nucleosomeWrap(iter:iter + num_link_beads - 1) = 0 wlc_basepairs(iter:iter + num_link_beads - 1) = discretization ! set last wlc_basepairs to 0 as reminder that this is not an actual extension wlc_basepairs(last_bead_of_chain(k)) = 0 enddo - else - print *, 'not recognized linker length type' - stop endif ! testing sterics here ! if (WLC_P__GJK_STERICS) then @@ -440,11 +489,9 @@ subroutine load_nucleosome_positions(wlc_nucleosomeWrap, wlc_basepairs) endif endif else - wlc_nucleosomeWrap = 147 + wlc_nucleosomeWrap = WLC_P__NUCLEOSOME_WRAPPING wlc_basepairs = WLC_P__LL endif - print*, wlc_basepairs - print*, wlc_nucleosomeWrap end subroutine diff --git a/src/mc/update_r.f03 b/src/mc/update_r.f03 index 1e35d1e6..c5bc0b21 100644 --- a/src/mc/update_r.f03 +++ b/src/mc/update_r.f03 @@ -66,7 +66,7 @@ end subroutine update_r subroutine GJK_removeBead(I) ! helper function to remove beads with binning use params, only: wlc_bin, wlc_R_period, wlc_R, wlc_UP, wlc_VP & - , wlc_U, wlc_V, wlc_RP, wlc_R_GJK, wlc_GJK, wlc_nucleosomeWrap + , wlc_U, wlc_V, wlc_RP, wlc_R_GJK, wlc_GJK use params, only: dp, NAN use binning, only: removeBead use polydispersity, only: get_IP, first_bead_of_chain, last_bead_of_chain @@ -85,8 +85,8 @@ end subroutine GJK_removeBead subroutine GJK_update(I, binningBool) ! helper routine to update R in GJK simulations - use params, only: wlc_bin, wlc_R_period, wlc_R, wlc_UP, wlc_VP & - , wlc_U, wlc_V, wlc_RP, wlc_R_GJK, wlc_GJK, wlc_nucleosomeWrap + use params, only: wlc_bin, wlc_R_period, wlc_R, wlc_UP, wlc_VP, & + wlc_U, wlc_V, wlc_RP, wlc_R_GJK, wlc_GJK, wlc_nucleosomeWrap use params, only: dp, NAN use GJKAlgorithm, only: constructPolygonPrism use binning, only: addBead diff --git a/src/mc/verify_energies_from_scratch.f03 b/src/mc/verify_energies_from_scratch.f03 index bb09b730..ec5f5a0d 100644 --- a/src/mc/verify_energies_from_scratch.f03 +++ b/src/mc/verify_energies_from_scratch.f03 @@ -123,7 +123,7 @@ subroutine calculate_energies_from_scratch(wlc_p) WLC_P__NT, neighbors, distances, nn) endif ! check for collisions - call sterics_check(collisions, wlc_R, wlc_U, wlc_V, wlc_GJK, wlc_basepairs, ignore, & + call sterics_check(collisions, wlc_R, wlc_U, wlc_V, wlc_GJK, wlc_basepairs, wlc_nucleosomeWrap, ignore, & i, nn, neighbors(1:nn), distances(1:nn), .true.) enddo ! ascribe collision penalty @@ -135,7 +135,7 @@ subroutine calculate_energies_from_scratch(wlc_p) ignore = NAN k = 1 do i = 1, WLC_P__NT - if (wlc_nucleosomeWrap(i) == 1) cycle + if (wlc_nucleosomeWrap(i) == 0) cycle ignore(k) = i k = k + 1 if (WLC_P__NEIGHBOR_BINS) then @@ -147,7 +147,7 @@ subroutine calculate_energies_from_scratch(wlc_p) WLC_P__NT, neighbors, distances, nn) endif do j = 1, nn - if (wlc_nucleosomeWrap(neighbors(j)) == 1 .or. ANY(ignore == neighbors(j))) cycle + if (wlc_nucleosomeWrap(neighbors(j)) == 0 .or. ANY(ignore == neighbors(j))) cycle delInt = delInt + internucleosome_energy(wlc_R(:, i), wlc_R(:, neighbors(j)), & wlc_U(:, i), wlc_U(:, neighbors(j)), & wlc_V(:, i), wlc_V(:, neighbors(j))) diff --git a/src/util/sterics.f90 b/src/util/sterics.f90 index afeba1c4..3953bfaf 100644 --- a/src/util/sterics.f90 +++ b/src/util/sterics.f90 @@ -239,7 +239,7 @@ FUNCTION constructPolygonPrism(pos1, pos2, wrap, u, v, s) implicit none real(dp), dimension(3), intent(in) :: pos1 ! first bead position real(dp), dimension(3), intent(in) :: pos2 ! second bead position - integer, intent(in) :: wrap ! num of basepairs wrapped + real(dp), intent(in) :: wrap ! num of basepairs wrapped real(dp), dimension(3), intent(in) :: u ! u angle of bead 1 real(dp), dimension(3), intent(in) :: v ! v angle of bead 1 integer, intent(in) :: s ! num sides of desired polygon @@ -258,8 +258,8 @@ FUNCTION constructPolygonPrism(pos1, pos2, wrap, u, v, s) mtrx(:,3) = u ! determine if nucleosome or not - if (wrap /= 1) then - center = [4.84550_DP, -2.44450_DP, 0.66940_DP] + if (wrap /= 0) then + center = [4.19000_DP, -2.02220_DP, 0.23000_DP] pos = pos1 h = WLC_P__NUCLEOSOME_HEIGHT ! nm height r = WLC_P__NUCLEOSOME_RADIUS ! nm radius @@ -319,7 +319,7 @@ FUNCTION findCenterPolygonPrism(pos1, pos2, wrap, u, v) implicit none real(dp), dimension(3), intent(in) :: pos1 ! first bead position real(dp), dimension(3), intent(in) :: pos2 ! second bead position - integer, intent(in) :: wrap ! num of basepairs wrapped + real(dp), intent(in) :: wrap ! num of basepairs wrapped real(dp), dimension(3), intent(in) :: u ! u angle of bead 1 real(dp), dimension(3), intent(in) :: v ! v angle of bead 1 real(dp), dimension(3,3) :: mtrx @@ -327,12 +327,12 @@ FUNCTION findCenterPolygonPrism(pos1, pos2, wrap, u, v) real(dp), dimension(3) :: findCenterPolygonPrism ! determine if nucleosome or not - if (wrap /= 1) then + if (wrap /= 0) then ! construct material rotation matrix mtrx(:,1) = v mtrx(:,2) = cross(u,v) mtrx(:,3) = u - center = [4.84550_DP, -2.44450_DP, 0.66940_DP] + center = [4.19000_DP, -2.02220_DP, 0.2300_DP] pos = pos1 ! find center of polygon findCenterPolygonPrism = pos + MATMUL(mtrx, center) @@ -814,4 +814,4 @@ SUBROUTINE runtimeTest6() END SUBROUTINE runtimeTest6 -END MODULE \ No newline at end of file +END MODULE diff --git a/src/wlcsim/initcond.f03 b/src/wlcsim/initcond.f03 index 47643492..b653480b 100644 --- a/src/wlcsim/initcond.f03 +++ b/src/wlcsim/initcond.f03 @@ -64,6 +64,7 @@ subroutine initcond(R, U, NT, NP, FRMFILE, rand_stat, wlc_p) real(dp) nloops integer IP + LBOX(1) = WLC_P__LBOX_X LBOX(2) = WLC_P__LBOX_Y LBOX(3) = WLC_P__LBOX_Z @@ -472,9 +473,9 @@ subroutine initcond(R, U, NT, NP, FRMFILE, rand_stat, wlc_p) .OR. ANY(isnan(R(:, IB:last_bead_of_chain(IP))))) IB = first_bead_of_chain(IP) ! in case you need to do again call random_number(urand,rand_stat) - R(1, IB) = urand(1)*WLC_P__CONFINEMENT_SPHERE_DIAMETER - R(2, IB) = urand(2)*WLC_P__CONFINEMENT_SPHERE_DIAMETER - R(3, IB) = urand(3)*WLC_P__CONFINEMENT_SPHERE_DIAMETER + R(1, IB) = WLC_P__CONFINEMENT_SPHERE_DIAMETER*0.2+0.6*urand(1)*WLC_P__CONFINEMENT_SPHERE_DIAMETER + R(2, IB) = WLC_P__CONFINEMENT_SPHERE_DIAMETER*0.2+0.6*urand(2)*WLC_P__CONFINEMENT_SPHERE_DIAMETER + R(3, IB) = WLC_P__CONFINEMENT_SPHERE_DIAMETER*0.2+0.6*urand(3)*WLC_P__CONFINEMENT_SPHERE_DIAMETER call random_number(urand,rand_stat) U(1, IB) = nint(urand(1)) U(2, IB) = nint(urand(2)) diff --git a/src/wlcsim/params.f03 b/src/wlcsim/params.f03 index 74c74ce6..e7a511e4 100644 --- a/src/wlcsim/params.f03 +++ b/src/wlcsim/params.f03 @@ -26,7 +26,7 @@ module params !!! hardcoded params. will need to change if certain parts of code change ! number of wlc_p move types - integer, parameter :: nMoveTypes = 13 ! NP added nuc slide + integer, parameter :: nMoveTypes = 14 integer, parameter :: nDim = 3 !!! arbitrary technical choices @@ -48,7 +48,7 @@ module params 'chem-identity ', 'end-end filp ', & 'chain swap ', 'reptation ', & 'superReptation ', 'spider ', & - 'nucleosomeSlide '/) + 'nucleosomeSlide ', 'nucleosomeBreathe '/) !!! universal constants ! fully accurate, adaptive precision @@ -188,9 +188,10 @@ module params ! nucleosomes real(dp), allocatable, dimension(:) :: wlc_basepairs - integer, allocatable, dimension(:) :: wlc_nucleosomeWrap + real(dp), allocatable, dimension(:) :: wlc_nucleosomeWrap real(dp), allocatable, dimension(:) :: wlc_basepairs_prop ! for sliding - integer, allocatable, dimension(:) :: wlc_nucleosomeWrap_prop ! for breathing + real(dp), allocatable, dimension(:) :: wlc_nucleosomeWrap_prop ! for unwrapping (NEEDS TO BE IMPLEMENTED) + ! Linking number, Twist, and Writhe (only for one-chain simulation) ! These values are updated in mcsim, checked against and update to their values @@ -241,7 +242,8 @@ subroutine set_param_defaults(wlc_p) wlc_p%PDESIRE(10) = WLC_P__PDESIRE_REPTATION wlc_p%PDESIRE(11) = WLC_P__PDESIRE_SUPER_REPTATION wlc_p%PDESIRE(12) = WLC_P__PDESIRE_SPIDER - wlc_p%PDESIRE(13) = WLC_P__PDESIRE_NUCLEOSOMESLIDE + wlc_p%PDESIRE(13) = WLC_P__PDESIRE_NUCLEOSOME_SLIDE + wlc_p%PDESIRE(14) = WLC_P__PDESIRE_NUCLEOSOME_BREATHE wlc_p%MAXWINDOW(1) = WLC_P__MAXWINDOW_CRANK_SHAFT wlc_p%MAXWINDOW(2) = WLC_P__MAXWINDOW_SLIDE_MOVE wlc_p%MAXWINDOW(3) = WLC_P__MAXWINDOW_PIVOT_MOVE @@ -281,6 +283,7 @@ subroutine set_param_defaults(wlc_p) wlc_p%MINAMP(11) = WLC_P__MINAMP_SUPER_REPTATION wlc_p%MINAMP(12) = WLC_P__MINAMP_SPIDER wlc_p%MINAMP(13) = WLC_P__MINAMP_NUCLEOSOME_SLIDE + wlc_p%MINAMP(14) = WLC_P__MINAMP_NUCLEOSOME_BREATHE wlc_p%MAXAMP(1) = WLC_P__MAXAMP_CRANK_SHAFT wlc_p%MAXAMP(2) = WLC_P__MAXAMP_SLIDE_MOVE wlc_p%MAXAMP(3) = WLC_P__MAXAMP_PIVOT_MOVE @@ -294,6 +297,7 @@ subroutine set_param_defaults(wlc_p) wlc_p%MAXAMP(11) = WLC_P__MAXAMP_SUPER_REPTATION wlc_p%MAXAMP(12) = WLC_P__MAXAMP_SPIDER wlc_p%MAXAMP(13) = WLC_P__MAXAMP_NUCLEOSOME_SLIDE + wlc_p%MAXAMP(14) = WLC_P__MAXAMP_NUCLEOSOME_BREATHE wlc_p%MOVEON(1) = WLC_P__MOVEON_CRANK_SHAFT wlc_p%MOVEON(2) = WLC_P__MOVEON_SLIDE_MOVE wlc_p%MOVEON(3) = WLC_P__MOVEON_PIVOT_MOVE @@ -306,7 +310,8 @@ subroutine set_param_defaults(wlc_p) wlc_p%MOVEON(10) = WLC_P__MOVEON_REPTATION wlc_p%MOVEON(11) = WLC_P__MOVEON_SUPER_REPTATION wlc_p%MOVEON(12) = WLC_P__MOVEON_SPIDER - wlc_p%MOVEON(13) = WLC_P__MOVEON_NUCLEOSOMESLIDE + wlc_p%MOVEON(13) = WLC_P__MOVEON_NUCLEOSOME_SLIDE + wlc_p%MOVEON(14) = WLC_P__MOVEON_NUCLEOSOME_BREATHE wlc_p%WINTARGET(1) = WLC_P__WINTARGET_CRANK_SHAFT wlc_p%WINTARGET(2) = WLC_P__WINTARGET_SLIDE_MOVE wlc_p%WINTARGET(3) = WLC_P__WINTARGET_PIVOT_MOVE @@ -332,7 +337,8 @@ subroutine set_param_defaults(wlc_p) wlc_p%NADAPT(10) = WLC_P__NADAPT_REPTATION wlc_p%NADAPT(11) = WLC_P__NADAPT_SUPER_REPTATION wlc_p%NADAPT(12) = WLC_P__NADAPT_SPIDER - wlc_p%NADAPT(13) = WLC_P__NADAPT_NUCLEOSOMESLIDE + wlc_p%NADAPT(13) = WLC_P__NADAPT_NUCLEOSOME_SLIDE + wlc_p%NADAPT(14) = WLC_P__NADAPT_NUCLEOSOME_BREATHE wlc_p%MOVESPERSTEP(1) = WLC_P__MOVESPERSTEP_CRANK_SHAFT wlc_p%MOVESPERSTEP(2) = WLC_P__MOVESPERSTEP_SLIDE_MOVE wlc_p%MOVESPERSTEP(3) = WLC_P__MOVESPERSTEP_PIVOT_MOVE @@ -345,7 +351,8 @@ subroutine set_param_defaults(wlc_p) wlc_p%MOVESPERSTEP(10) = WLC_P__MOVESPERSTEP_REPTATION wlc_p%MOVESPERSTEP(11) = WLC_P__MOVESPERSTEP_SUPER_REPTATION wlc_p%MOVESPERSTEP(12) = WLC_P__MOVESPERSTEP_SPIDER - wlc_p%MOVESPERSTEP(13) = WLC_P__MOVESPERSTEP_NUCLEOSOMESLIDE + wlc_p%MOVESPERSTEP(13) = WLC_P__MOVESPERSTEP_NUCLEOSOME_SLIDE + wlc_p%MOVESPERSTEP(14) = WLC_P__MOVESPERSTEP_NUCLEOSOME_BREATHE end subroutine set_param_defaults @@ -397,6 +404,10 @@ subroutine idiot_checks(wlc_p) print *, 'but clearly needs to be implemented' stop endif + if ((WLC_P__MOVEON_NUCLEOSOME_SLIDE == 1) .OR. (WLC_P__MOVEON_NUCLEOSOME_BREATHE == 1) ) then + print *, 'The nuclesome slide and breathe moves are currently in development!!' + stop + endif err = WLC_P__NO_SELF_CROSSING .and. WLC_P__NP > 1 call stop_if_err(err, "linking number calculation is implemented only for one chain.") @@ -541,6 +552,7 @@ subroutine initialize_wlcsim_data(wlc_p) integer setBinShape(3)! Specify first level of binning integer len_file real(dp) poly(WLC_P__GJK_POLYGON, 3) + real(dp), parameter :: bin_offset = 2*WLC_P__GJK_RADIUS ! offset to ensure "center" beads are in bin nbin = wlc_p%NBIN #if MPI_VERSION @@ -613,8 +625,12 @@ subroutine initialize_wlcsim_data(wlc_p) if (WLC_P__ELASTICITY_TYPE == "nucleosomes") then allocate (wlc_basepairs(WLC_P__NT)) allocate (wlc_nucleosomeWrap(WLC_P__NT)) - if (WLC_P__MOVEON_NUCLEOSOMESLIDE == 1) then + if (WLC_P__MOVEON_NUCLEOSOME_SLIDE == 1 .AND. WLC_P__MOVEON_NUCLEOSOME_BREATHE == 0) then + allocate (wlc_basepairs_prop(WLC_P__NT)) + endif + if (WLC_P__MOVEON_NUCLEOSOME_BREATHE == 1) then allocate (wlc_basepairs_prop(WLC_P__NT)) + allocate (wlc_nucleosomeWrap_prop(WLC_P__NT)) endif endif if (WLC_P__EXPLICIT_BINDING) then @@ -806,8 +822,8 @@ subroutine initialize_wlcsim_data(wlc_p) ! ------------------------------------------ if (WLC_P__NEIGHBOR_BINS) then ! Set up binning object - setBinSize = [WLC_P__LBOX_X, WLC_P__LBOX_Y, WLC_P__LBOX_Z] ! size of bin - setMinXYZ = [0.0_dp, 0.0_dp, 0.0_dp] ! location of corner of bin + setBinSize = [WLC_P__LBOX_X + 2*bin_offset, WLC_P__LBOX_Y + 2*bin_offset, WLC_P__LBOX_Z + 2*bin_offset] ! size of bin + setMinXYZ = [-bin_offset, -bin_offset, -bin_offset] ! location of corner of bin setBinShape = [10, 10, 10] ! Specify first level of binning call constructBin(wlc_bin, setBinShape, setMinXYZ, setBinSize) do i = 1, WLC_P__NT @@ -1337,9 +1353,10 @@ subroutine wlcsim_params_saveDISC(fileName, stat) character(len=*), intent(in) :: stat fullName = trim(fileName)//trim(wlc_repSuffix) open (unit=outFileUnit, file=fullName, status=stat) - write (outFileUnit, *) wlc_nucleosomeWrap + !write (outFileUnit, *) wlc_nucleosomeWrap do ii = 1, WLC_P__NT - call print_11char_float(outFileUnit, wlc_basepairs(ii)) + !call print_11char_vec(outFileUnit, wlc_basepairs(ii), .FALSE.) + write (outFileUnit, "(3f10.5)") wlc_basepairs(ii), wlc_nucleosomeWrap(ii) enddo close (outFileUnit) end subroutine