def read_tom_strand_from_string(strandline, box): dvals = strandline.split('(') if (len(dvals) != 2): raise IOError vals = dvals[1].replace('\"', ' ').split(',') length = int(vals[0]) s = base.Strand() valindex = 1 for i in range(length): #valindex += i*9+1 posback = [] posbackbase = [] posalign = [] nuctype = int(vals[valindex]) valindex += 1 for j in range(3): posback.append(float(vals[valindex])) valindex += 1 for j in range(3): posbackbase.append(float(vals[valindex])) valindex += 1 for j in range(3): posalign.append(float(vals[valindex])) valindex += 1 poscm = np.array(posback) - np.array(posbackbase) * base.POS_BACK #poscm = poscm % box n = base.Nucleotide(poscm, posbackbase, posalign, nuctype) s.add_nucleotide(n) return s
def generate(self, cm_pos=np.array([0, 0, 0])): seqs = [[base.base_to_number[x] for x in s] for s in TetramerGenerator.seqs] strands = [base.Strand() for i in range(4)] half_strand_len = base.BASE_BASE * 21.; sqrt1_3 = 1 / np.sqrt(3.) sqrt1_2 = 1 / np.sqrt(2.) cube_side = half_strand_len * sqrt1_3; rb = cm_pos + np.array([cube_side, -cube_side, -cube_side]) # this initial direction will give us a 0, -1, +1 direction in the center a1 = np.array([-0.438110, -0.815750, 0.377640]) a1 /= np.sqrt(np.dot(a1, a1)) a3 = np.array([-sqrt1_3, sqrt1_3, sqrt1_3]) a3s = [[-sqrt1_3, sqrt1_3, -sqrt1_3], [sqrt1_3, sqrt1_3, sqrt1_3], [-sqrt1_3, -sqrt1_3, sqrt1_3], [sqrt1_3, -sqrt1_3, -sqrt1_3]] a1s = [[0, sqrt1_2, sqrt1_2], [0, -sqrt1_2, sqrt1_2], [0, -sqrt1_2, -sqrt1_2], [0, sqrt1_2, -sqrt1_2]] R = utils.get_rotation_matrix(a3, np.pi/180*(35.9)) for s in range(4): for i in range(49): strands[s].add_nucleotide(base.Nucleotide(rb - base.CM_CENTER_DS*a1, a1, a3, seqs[s][i])) if i == 21: a1old = a1 a1 = np.array(a1s[s]) rback = rb - (base.CM_CENTER_DS - base.POS_BACK) * a1old rback -= (a1 + a1old) * base.BASE_BASE a3 = np.array(a3s[s]) rb = rback + (base.CM_CENTER_DS - base.POS_BACK) * a1 R = utils.get_rotation_matrix(a3, np.pi/180*(35.9)) else: a1 = np.dot(R, a1) rb += a3 * base.BASE_BASE # the next strand will begin from this base if i == 40: na1 = -a1 na3 = -a3 nrb = np.copy(rb) a1 = na1 a3 = na3 R = utils.get_rotation_matrix(a3, np.pi/180*(35.9)) rb = nrb return strands
def generate_rw(self, sequence, start_pos=np.array([0., 0., 0.])): """ Generate ssDNA as a random walk (high-energy configurations are possible): generate(bp=45,double=False,circular=False,random_walk=True) """ # random walk generator base.Logger.log( "Generating strand as a random walk. Remember to equilibrate the configuration with MC", base.Logger.WARNING) d = np.array([0.7525, 0., 0.]) pos = start_pos rw = [] rw.append(pos) for i, _ in enumerate(sequence[1:]): overlap = True while overlap: overlap = False R = utils.get_random_rotation_matrix() dd = np.dot(R, d) trypos = pos + np.dot(R, d) overlap = False for r in rw: dd = trypos - r if np.dot(dd, dd) < 0.40 * 0.40: overlap = True pos = trypos rw.append(pos) # print >> sys.stderr, "# nucleotide", i + 1, "inserted" # we get the a1 vectors in a smart way a1s = [] d = rw[1] - rw[0] a1s.append(d / np.sqrt(np.dot(d, d))) for i in range(1, len(rw) - 1): d = (rw[i + 1] + rw[i - 1]) * 0.5 d = rw[i] - d a1s.append(d / np.sqrt(np.dot(d, d))) d = rw[len(rw) - 1] - rw[len(rw) - 2] a1s.append(d / np.sqrt(np.dot(d, d))) s = base.Strand() for i, r in enumerate(rw): a1, _, a3 = utils.get_orthonormalized_base( a1s[i], utils.get_random_vector(), utils.get_random_vector()) # print np.dot(a1, a1), np.dot(a2, a2), np.dot(a3, a3), np.dot(a1, a2), np.dot(a1, a3), np.dot(a2, a3) # # POS_BACK is negative! cm = r + a1s[i] * abs(base.POS_BACK) s.add_nucleotide(base.Nucleotide(cm, a1, a3, sequence[i])) return s
def _read(self, only_strand_ends=False, skip=False): timeline = self._conf.readline() time = 0. if len(timeline) == 0: return False else: time = float(timeline.split()[2]) box = np.array([float(x) for x in self._conf.readline().split()[2:]]) [E_tot, E_pot, E_kin] = [float(x) for x in self._conf.readline().split()[2:5]] if skip: for tl in self._top_lines: self._conf.readline() return False system = base.System(box, time=time, E_pot=E_pot, E_kin=E_kin) base.Nucleotide.index = 0 base.Strand.index = 0 s = False strandid_current = 0 for tl in self._top_lines: tls = tl.split() n3 = int(tls[2]) n5 = int(tls[3]) strandid = int(tls[0]) if (len(tls[1]) == 1): b = base.base_to_number[tls[1]] bb = b else: try: tmp = int(tls[1]) except: raise ValueError ("problems in topology file with specific base pairing") if tmp > 0: b = tmp % 4 else: b = (3 - ((3 - tmp) % 4)) bb = tmp if strandid != strandid_current: # check for circular strand if n3 != -1: iscircular = True else: iscircular = False if s: system.add_strand(s, self._check_overlap) s = base.Strand() if iscircular: s.make_circular() strandid_current = strandid ls = self._conf.readline().split() cm = [float(x) for x in ls[0:3]] a1 = [float(x) for x in ls[3:6]] a3 = [float(x) for x in ls[6:9]] v = [float(x) for x in ls[9:12]] L = [float(x) for x in ls[12:15]] if not only_strand_ends or n3 == -1 or n5 == -1: s.add_nucleotide(base.Nucleotide(cm, a1, a3, b, bb, v, L, n3)) system.add_strand(s, self._check_overlap) return system
def generate(self, bp, sequence=None, start_pos=np.array([0, 0, 0]), dir=np.array([0, 0, 1]), perp=None, rot=0., double=True, circular=False, DELTA_LK=0, BP_PER_TURN=10.34, ds_start=None, ds_end=None, force_helicity=False): """ Generate a strand of DNA. - linear, circular (circular) - ssDNA, dsDNA (double) - Combination of ss/dsDNA (ds_start, ds_end) Note: Relevent argument(s) in parentheses. Arguments: bp --- Integer number of bp/nt (required) sequence --- Array of integers or string. Should be same length as bp (default None) Default (None) generates a random sequence. Ex: [0,1,2,3,0] Ex: "AGCTA" See dictionary base.base_to_number for int/char conversion {0:'A'} start_pos --- Location to begin building the strand (default np.array([0, 0, 0])) dir --- a3 vector, orientation of the base (default np.array([0, 0, 1])) perp --- Sets a1 vector, the orientation of the backbone. (default False) Must be perpendicular to dir (as a1 must be perpendicular to a3) If perp is None or False, perp is set to a random orthogonal angle rot --- Rotation of first bp (default 0.) double --- Generate dsDNA (default True) circular --- Generate closed circular DNA (defalt False) Limitations... For ssDNA (double=False): bp >= 4 For dsDNA (double=True) : bp >= 30 Will throw warnings. Allowed, but use at your own risk. DELTA_LK --- Integer change in linking number from Lk0 (default 0) Only valid if circular==True BP_PER_TURN --- Base pairs per complete 2*pi helix turn. (default 10.34) Only valid if circular==True ds_start --- Index (from 0) to begin double stranded region (default None) ds_end --- Index (from 0) to end double stranded region (default None) Default is None, which is entirely dsDNA; sets ds_start = 0, ds_end=bp Ex: ds_start=0, ds_end=10 will create a double stranded region on bases range(0,10): [0,1,2,3,4,5,6,7,8,9] Note: To generate a nicked circular dsDNA, manually change state with {Strand}.make_noncircular() force_helicity --- Force generation of helical strands. Use helicity by default for bp > 30. Warns from 18 to 29. Will crash oxDNA below 18. (default False) Note: Minimuim circular duplex is 18. Shorter circular strands disobey FENE. For shorter strands, circular ssDNA is generated in a circle instead of having imposed helicity. Examples: Generate ssDNA: generate(bp=4,sequence=[0,1,2,3],double=False,circular=False) Generate circular dsDNA with +2 Linking number: generate(bp=45,double=True,circular=True,DELTA_LK=2) Generate a circular ssDNA (45nt) with ssDNA (25nt) annealed to indices 0 to 24: generate(bp=45,double=True,circular=True,ds_start=0,ds_end=25) """ # we need numpy array for these start_pos = np.array(start_pos, dtype=float) dir = np.array(dir, dtype=float) if isinstance(sequence, list): sequence = np.array(sequence) # Loads of input checking... if isinstance(sequence, str): try: sequence = [base.base_to_number[x] for x in sequence] except KeyError: base.Logger.die("Key Error: sequence is invalid" % n) if sequence == None: sequence = np.random.randint(0, 4, bp) elif len(sequence) != bp: n = bp - len(sequence) sequence = np.append(sequence, np.random.randint(0, 4, n)) base.Logger.log("sequence is too short, adding %d random bases" % n, base.Logger.WARNING) if circular == True and bp < 30: # 30 is about the cut off for circular dsDNA. Anything shorter will probably clash. # oxDNA can relax down to 18. # 4 is about the cut off for circular ssDNA. Use dsDNA cutoff for saftey. base.Logger.log("sequence is too short! Proceed at your own risk", base.Logger.WARNING) option_use_helicity = True if circular == True and bp < 30 and double == False: base.Logger.log("sequence is too short! Generating ssDNA without imposed helicity", base.Logger.WARNING) # Do not impose helcity to generate shorter circular ssDNA if not force_helicity: option_use_helicity = False if ds_start == None: ds_start = 0 if ds_end == None: ds_end = bp if ds_start > ds_end: base.Logger.die("ds_end > ds_start") if ds_end > bp: base.Logger.die("ds_end > bp") # we need to find a vector orthogonal to dir dir_norm = np.sqrt(np.dot(dir,dir)) if dir_norm < 1e-10: base.Logger.log("direction must be a valid vector, defaulting to (0, 0, 1)", base.Logger.WARNING) dir = np.array([0, 0, 1]) else: dir /= dir_norm if perp is None or perp is False: v1 = np.random.random_sample(3) v1 -= dir * (np.dot(dir, v1)) v1 /= np.sqrt(sum(v1*v1)) else: v1 = perp; # Setup initial parameters ns1 = base.Strand() # and we need to generate a rotational matrix R0 = utils.get_rotation_matrix(dir, rot) #R = get_rotation_matrix(dir, np.deg2rad(35.9)) R = utils.get_rotation_matrix(dir, [1, BP]) a1 = v1 a1 = np.dot (R0, a1) rb = np.array(start_pos) a3 = dir # Circular strands require a continuious deformation of the ideal helical pitch if circular == True: # Unit vector orthogonal to plane of torus # Note: Plane of torus defined by v1,dir torus_perp = np.cross(v1,dir) # bp-bp rotation factor to yield a smooth deformation along the torus smooth_factor = np.mod(bp,BP_PER_TURN)/float(bp) + 1 # Angle between base pairs along torus angle = 2. * np.pi / float(bp) # Radius of torus radius = base.FENE_R0_OXDNA / math.sqrt(2. * (1. - math.cos(angle))); if circular == True and option_use_helicity: # Draw backbone in a helical spiral around a torus # Draw bases pointing to center of torus for i in range(bp): # Torus plane defined by dir and v1 v_torus = v1 *base.BASE_BASE * math.cos(i * angle) + \ dir * base.BASE_BASE * math.sin(i * angle) rb += v_torus # a3 is tangent to the torus a3 = v_torus/np.linalg.norm(v_torus) R = utils.get_rotation_matrix(a3, [i * (round(bp/BP_PER_TURN) + DELTA_LK)/float(bp) * 360, DEGREES]) # a1 is orthogonal to a3 and the torus normal a1 = np.cross (a3, torus_perp) # Apply the rotation matrix a1 = np.dot(R, a1) ns1.add_nucleotide(base.Nucleotide(rb - base.CM_CENTER_DS * a1, a1, a3, sequence[i])) ns1.make_circular(check_join_len=True) elif circular == True and not option_use_helicity: for i in xrange(bp): rbx = math.cos (i * angle) * radius + 0.34 * math.cos(i * angle) rby = math.sin (i * angle) * radius + 0.34 * math.sin(i * angle) rbz = 0. rb = np.array([rbx, rby, rbz]) a1x = math.cos (i * angle) a1y = math.sin (i * angle) a1z = 0. a1 = np.array([a1x, a1y, a1z]) ns1.add_nucleotide(base.Nucleotide(rb, a1, np.array([0, 0, 1]), sequence[i])) ns1.make_circular(check_join_len=True) else: # Add nt in canonical double helix for i in range(bp): ns1.add_nucleotide(base.Nucleotide(rb - base.CM_CENTER_DS * a1, a1, a3, sequence[i])) if i != bp-1: a1 = np.dot(R, a1) rb += a3 * base.BASE_BASE # Fill in complement strand if double == True: ns2 = base.Strand() for i in reversed(range(ds_start, ds_end)): # Note that the complement strand is built in reverse order nt = ns1._nucleotides[i] a1 = -nt._a1 a3 = -nt._a3 nt2_cm_pos = -(base.FENE_EPS + 2*base.POS_BACK) * a1 + nt.cm_pos ns2.add_nucleotide(base.Nucleotide(nt2_cm_pos, a1, a3, 3-sequence[i])) if ds_start == 0 and ds_end == bp and circular == True: ns2.make_circular(check_join_len=True) return ns1, ns2 else: return ns1
def generate_or_sq(self, bp, sequence=None, start_pos=np.array([0,0,0]), dir=np.array([0, 0, 1]), perp=None, double=True, rot=0., angle=np.pi/180*33.75, length_change=0, region_begin=0, region_end=0): # we need numpy array for these start_pos = np.array(start_pos, dtype=float) dir = np.array(dir, dtype=float) if sequence == None: sequence = np.random.randint(0, 4, bp) elif len(sequence) != bp: n = bp - len(sequence) sequence += np.random.randint(0, 4, n) base.Logger.log("sequence is too short, adding %d random bases" % n, base.Logger.WARNING) # angle should be an array, with a length 1 less than the # of base pairs if not isinstance(angle, np.ndarray): angle = np.ones(bp) * angle elif len(angle) != bp - 1: base.Logger.log("generate_or_sq: incorrect angle array length, should be 1 less than number of base pairs", base.Logger.CRITICAL) # create the sequence of the second strand as made of complementary bases sequence2 = [3-s for s in sequence] sequence2.reverse() # we need to find a vector orthogonal to dir dir_norm = np.sqrt(np.dot(dir,dir)) if dir_norm < 1e-10: base.Logger.log("direction must be a valid vector, defaulting to (0, 0, 1)", base.Logger.WARNING) dir = np.array([0, 0, 1]) else: dir /= dir_norm if perp is None: v1 = np.random.random_sample(3) v1 -= dir * (np.dot(dir, v1)) v1 /= np.sqrt(sum(v1*v1)) else: v1 = perp; # and we need to generate a rotational matrix R0 = utils.get_rotation_matrix(dir, rot) # R = utils.get_rotation_matrix(dir, angle) #R = get_rotation_matrix(dir, [1, BP]) ns1 = base.Strand() a1 = v1 a1 = np.dot (R0, a1) rb = np.array(start_pos) a3 = dir for i in range(bp): ns1.add_nucleotide(base.Nucleotide(rb - base.CM_CENTER_DS * a1, a1, a3, sequence[i])) if i != bp-1: R = utils.get_rotation_matrix(dir, angle[i]) a1 = np.dot(R, a1) rb += a3 * base.BASE_BASE if length_change: for j in range(len(length_change)): if i >= region_begin[j] and i < region_end[j]: if length_change[j]: rb += a3 * base.BASE_BASE * (- (float(length_change[j])/(region_end[j] - region_begin[j]))) if double == True: angle = np.flipud(angle) a1 = -a1 a3 = -dir ns2 = base.Strand() for i in range(bp): ns2.add_nucleotide(base.Nucleotide(rb - base.CM_CENTER_DS * a1, a1, a3, sequence2[i])) if i != bp - 1: R = utils.get_rotation_matrix(dir,angle[i]).transpose() a1 = np.dot(R, a1) rb += a3 * base.BASE_BASE if length_change: for j in range(len(length_change)): if bp - 2 - i >= region_begin[j] and bp - 2 - i < region_end[j]: if length_change[j]: rb += a3 * base.BASE_BASE * (- (float(length_change[j])/(region_end[j] - region_begin[j]))) return ns1, ns2 else: return ns1
def generate_or_sq(self, bp, sequence=None, start_pos=np.array([0., 0., 0.]), direction=np.array([0., 0., 1.]), perp=None, double=True, rot=0., angle=np.pi / 180 * 33.75, length_change=0, region_begin=0, region_end=0): if length_change and len(region_begin) != len(region_end): if (len(region_end) + 1) == len(region_begin): base.Logger.log( "the lengths of begin (%d) and end (%d) arrays are mismatched; I will try to proceed by using the number of basepairs as the last element of the end array" % (len(region_begin), len(region_end)), base.Logger.WARNING) region_end.append(bp + 1) else: base.Logger.die( "the lengths of begin (%d) and end (%d) arrays are unrecoverably mismatched" % (len(region_begin), len(region_end))) # we need numpy array for these start_pos = np.array(start_pos, dtype=float) direction = np.array(direction, dtype=float) if sequence == None: sequence = np.random.randint(0, 4, bp) elif len(sequence) != bp: n = bp - len(sequence) sequence += np.random.randint(0, 4, n) base.Logger.log( "sequence is too short, adding %d random bases" % n, base.Logger.WARNING) # angle should be an array, with a length 1 less than the # of base pairs if not isinstance(angle, np.ndarray): angle = np.ones(bp) * angle elif len(angle) != bp - 1: base.Logger.log( "generate_or_sq: incorrect angle array length, should be 1 less than number of base pairs", base.Logger.CRITICAL) # create the sequence of the second strand as made of complementary bases sequence2 = [3 - s for s in sequence] sequence2.reverse() # we need to find a vector orthogonal to direction dir_norm = np.sqrt(np.dot(direction, direction)) if dir_norm < 1e-10: base.Logger.log( "direction must be a valid vector, defaulting to (0, 0, 1)", base.Logger.WARNING) direction = np.array([0, 0, 1]) else: direction /= dir_norm if perp is None: v1 = np.random.random_sample(3) v1 -= direction * (np.dot(direction, v1)) v1 /= np.sqrt(sum(v1 * v1)) else: v1 = perp # and we need to generate a rotational matrix R0 = utils.get_rotation_matrix(direction, rot) ns1 = base.Strand() a1 = v1 a1 = np.dot(R0, a1) rb = np.array(start_pos) a3 = direction Rs = [] for i in range(bp): ns1.add_nucleotide( base.Nucleotide(rb - base.CM_CENTER_DS * a1, a1, a3, sequence[i])) if i != bp - 1: R = utils.get_rotation_matrix(direction, angle[i]) Rs.append(R) a1 = np.dot(R, a1) rb += a3 * base.BASE_BASE if length_change: for j in range(len(length_change)): if i >= region_begin[j] and i < region_end[j]: if length_change[j]: rb += a3 * base.BASE_BASE * ( -(float(length_change[j]) / (region_end[j] - region_begin[j]))) if double == True: a1 = -a1 a3 = -direction ns2 = base.Strand() for i in range(bp): ns2.add_nucleotide( base.Nucleotide(rb - base.CM_CENTER_DS * a1, a1, a3, sequence2[i])) if i != bp - 1: # we loop over the rotation matrices in the reverse order, and use the transpose of each matrix a1 = np.dot(Rs.pop().transpose(), a1) rb += a3 * base.BASE_BASE if length_change: for j in range(len(length_change)): if bp - 2 - i >= region_begin[ j] and bp - 2 - i < region_end[j]: if length_change[j]: rb += a3 * base.BASE_BASE * ( -(float(length_change[j]) / (region_end[j] - region_begin[j]))) return ns1, ns2 else: return ns1
def generate(self, bp, sequence=None, start_pos=np.array([0, 0, 0]), dir=np.array([0, 0, 1]), perp=False, double=True, rot=None, base_base_distance=None): base.CM_CENTER_DS -= 0. if (base_base_distance == None): base_base_distance = base.BASE_BASE if (rot == None): rot = 35.9 # we need numpy array for these start_pos = np.array(start_pos, dtype=float) dir = np.array(dir, dtype=float) if sequence == None: sequence = np.random.randint(0, 4, bp) elif len(sequence) != bp: n = bp - len(sequence) sequence += np.random.randint(0, 4, n) base.Logger.log( "sequence is too short, adding %d random bases" % n, Logger.WARNING) # create the sequence of the second strand as made of complementary bases sequence2 = [3 - s for s in sequence] sequence2.reverse() # we need to find a vector orthogonal to dir dir_norm = np.sqrt(np.dot(dir, dir)) if dir_norm < 1e-10: base.Logger.log( "direction must be a valid vector, defaulting to (0, 0, 1)", base.Logger.WARNING) dir = np.array([0, 0, 1]) else: dir /= dir_norm if perp is None or perp is False: v1 = np.random.random_sample(3) v1 -= dir * (np.dot(dir, v1)) v1 /= np.sqrt(sum(v1 * v1)) else: v1 = perp # and we need to generate a rotational matrix R = utils.get_rotation_matrix(dir, np.deg2rad(rot)) #R = get_rotation_matrix(dir, np.deg2rad(35.9)) #R = utils.get_rotation_matrix(dir, [1, BP]) ns1 = base.Strand() a1 = v1 #a1 = np.dot (R0, a1) rb = np.array(start_pos) a3 = dir for i in range(bp): ns1.add_nucleotide( base.Nucleotide(rb - base.CM_CENTER_DS * a1, a1, a3, sequence[i])) if i != bp - 1: a1 = np.dot(R, a1) rb += a3 * base_base_distance if double == True: a1 = -a1 a3 = -dir R = R.transpose() ns2 = base.Strand() for i in range(bp): ns2.add_nucleotide( base.Nucleotide(rb - base.CM_CENTER_DS * a1, a1, a3, sequence2[i])) a1 = np.dot(R, a1) rb += a3 * base_base_distance return ns1, ns2 else: return ns1
def a_generate(self, bp, sequence=None, start_pos=np.array([0, 0, 0]), dir=np.array([0, 0, 1]), perp=False, double=True, rot=None, base_base_distance=None, inclination=None, diameter=2.35): if inclination == None: inclination = 15.5 bp_backback_distance = 2.0 cord = math.cos(np.deg2rad(inclination)) * bp_backback_distance center_to_cord = math.sqrt((diameter / 2.)**2 - (cord / 2.)**2) if (base_base_distance == None): base_base_distance = 0.3287 #a-rna, source: neidle book if (rot == None): rot = 32.7 #a-dna, source: wiki # we need numpy array for these start_pos = np.array(start_pos, dtype=float) dir = np.array(dir, dtype=float) if sequence == None: sequence = np.random.randint(0, 4, bp) elif len(sequence) != bp: n = bp - len(sequence) sequence += np.random.randint(0, 4, n) base.Logger.log( "sequence is too short, adding %d random bases" % n, Logger.WARNING) # create the sequence of the second strand as made of complementary bases sequence2 = [3 - s for s in sequence] sequence2.reverse() # we need to find a vector orthogonal to dir dir_norm = np.sqrt(np.dot(dir, dir)) if dir_norm < 1e-10: base.Logger.log( "direction must be a valid vector, defaulting to (0, 0, 1)", base.Logger.WARNING) dir = np.array([0, 0, 1]) else: dir /= dir_norm #x1, y1, z1 = center_to_cord, cord / 2., -(bp_backback_distance / 2.) * np.sin (np.deg2rad(inclination)) #x2, y2, z2 = center_to_cord, -cord / 2., +(bp_backback_distance / 2.) * np.sin (np.deg2rad(inclination)) x2, y2, z2 = center_to_cord, -cord / 2., +( bp_backback_distance / 2.) * np.sin(np.deg2rad(inclination)) x1, y1, z1 = center_to_cord, +cord / 2., -( bp_backback_distance / 2.) * np.sin(np.deg2rad(inclination)) r1 = np.array([x1, y1, z1]) r2 = np.array([x2, y2, z2]) r1_to_r2 = r2 - r1 ZAXIS = np.array([0., 0., 1.]) RISE = base_base_distance R = utils.get_rotation_matrix(ZAXIS, np.deg2rad(rot)) ns1 = base.Strand() for i in xrange(len(sequence)): r1 = np.dot(R, r1) + RISE * ZAXIS r2 = np.dot(R, r2) + RISE * ZAXIS r1_to_r2 = r2 - r1 a1 = r1_to_r2 / math.sqrt(np.dot(r1_to_r2, r1_to_r2)) a1proj = np.array([a1[0], a1[1], 0.]) a1projnorm = math.sqrt(np.dot(a1proj, a1proj)) a3 = -(-math.cos(np.deg2rad(inclination)) * ZAXIS + math.sin(np.deg2rad(inclination)) * a1proj / a1projnorm) #a3 = math.cos(np.deg2rad(inclination)) * ZAXIS - math.sin(np.deg2rad(inclination))* a1proj / a1projnorm ns1.add_nucleotide( base.Nucleotide(r1 + base.CM_CENTER_DS * a1, a1, a3, sequence[i])) if double == True: a1 = -a1 a3 = -dir R = R.transpose() ns2 = base.Strand() for i in xrange(len(sequence)): r1_to_r2 = r2 - r1 a1 = -r1_to_r2 / math.sqrt(np.dot(r1_to_r2, r1_to_r2)) a1proj = np.array([a1[0], a1[1], 0.]) a1projnorm = math.sqrt(np.dot(a1proj, a1proj)) a3 = -(math.cos(np.deg2rad(inclination)) * ZAXIS + math.sin(np.deg2rad(inclination)) * a1proj / a1projnorm) #a3 = -math.cos(np.deg2rad(inclination)) * ZAXIS - math.sin(np.deg2rad(inclination))* a1proj / a1projnorm ns2.add_nucleotide( base.Nucleotide(r2 + base.CM_CENTER_DS * a1, a1, a3, sequence2[i])) r1 = np.dot(R, r1) - RISE * ZAXIS r2 = np.dot(R, r2) - RISE * ZAXIS #display_info(ns1,ns2,np.deg2rad(rot),RISE,diameter/2.) return ns1, ns2 else: return ns1
def _read(self, only_strand_ends=False, skip=False): try: timeline = self._conf.readline() time = float(timeline.split()[2]) box = np.array([float(x) for x in self._conf.readline().split()[2:]]) self._conf.readline() except Exception as e: raise Exception("The header lines of the configuration file are invalid (caught a '%s' exception)" % e) if skip: for tl in self._top_lines: self._conf.readline() return False system = base.System(box, time=time) base.Nucleotide.index = 0 base.Strand.index = 0 s = False strandid_current = 0 for i_line, tl in enumerate(self._top_lines): tls = tl.split() n3 = int(tls[2]) n5 = int(tls[3]) strandid = int(tls[0]) if (len (tls[1]) == 1): b = base.base_to_number[tls[1]] bb = b else: try: tmp = int (tls[1]) except: raise Exception("The line n. %d in the topology file contains an incorrect specific base pairing" % i_line) if tmp > 0: b = tmp % 4 else: b = (3 - ((3 - tmp) % 4)) bb = tmp if strandid != strandid_current: # check for circular strand if n3 != -1: iscircular = True else: iscircular = False if s: system.add_strand(s) s = base.Strand() if iscircular: s.make_circular() strandid_current = strandid ls = self._conf.readline().split() if len(ls) == 0: raise Exception("The %d-th nucleotide line in the configuration file is empty" % i_line) elif len(ls) != 15: raise Exception("The %d-th nucleotide line in the configuration file is invalid" % i_line) cm = [float(x) for x in ls[0:3]] a1 = [float(x) for x in ls[3:6]] a3 = [float(x) for x in ls[6:9]] v = [float(x) for x in ls[9:12]] L = [float(x) for x in ls[12:15]] if not only_strand_ends or n3 == -1 or n5 == -1: s.add_nucleotide(base.Nucleotide(cm, a1, a3, b, bb, v, L, n3)) system.add_strand(s) return system
def main(): vh_vb2nuc = oru.vhelix_vbase_to_nucleotide() vh_vb2nuc_final = oru.vhelix_vbase_to_nucleotide() if len(sys.argv) < 3: print_usage() origami_sq = False origami_he = False if sys.argv[2] == "sq": origami_sq = True elif sys.argv[2] == "he": origami_he = True else: print_usage() source_file = sys.argv[1] nupack = 0 side = False if len(sys.argv) > 3: if sys.argv[3] == "nupack": # nupack option prints a scaffold pattern file for use (indirectly) in nupack nupack = 1 base.Logger.log("using nupack option; scaffold pattern file will be generated. Assuming a single origami with saturated hydrogen bonds", base.Logger.INFO) else: # read 4th arg as system size in oxDNA simulation units side = float(sys.argv[3]) base.Logger.log("using side option; system will be in a box of side %s in simulation units" % str(side), base.Logger.INFO) cadsys = parse_cadnano (source_file) base.Logger.log("using json file %s" % source_file, base.Logger.INFO) # define sequences by vhelix sequence_file = 0 single_strand_system = False if nupack == 0: try: sequence_file = open("caca.sqs", "r") except: base.Logger.log("no sequence file found, using random sequence", base.Logger.INFO) sequences = [] block_seq = True if sequence_file: base.Logger.log("using sequence file caca.sqs", base.Logger.INFO) lines = sequence_file.readlines() for line in lines: seq = [] for x in line.replace("\n","").replace(" ",""): if x in ["R","r"]: seq.append(np.random.randint(0, 4)) else: try: seq.append(base.base_to_number[x]) except KeyError: base.Logger.log("KeyError while converting base to integer; check caca.sqs", base.Logger.CRITICAL) sys.exit() sequences.append(seq) else: for ii in range(len(cadsys.vhelices)): seq = [] for jj in range(cadsys.vhelices[ii].skiploop_bases): seq.append(np.random.randint(0,4)) sequences.append(seq) # check whether we're dealing with a 1 strand system (i.e. NOT double helix) across many vhelices and defined with 1 .sqs line if len(sequences) == 1 and len(cadsys.vhelices) > 1: base.Logger.log("1 .sqs line detected and more than 1 cadnano virtual helix detected; assuming using sequence from file assuming a single strand system", base.Logger.INFO) single_strand_system = True block_seq = False if nupack: staple_to_scaffold = [] staple_to_vhelix = {} staple_to_vhelix_final = {} vhelix_to_scaffold = {} scaf_count = 0 vhelix_to_scaffold_final = {} record_joined = [] vhelix_counter = 0 if not side: side = cadsys.bbox() if not nupack: base.Logger.log("using default box size, a factor %s larger than size of cadnano system" % str(BOX_FACTOR), base.Logger.INFO) vhelix_direction_initial = np.array([0,0,1]) vhelix_perp_initial = np.array([1,0,0]) if origami_sq: vhelix_perp_initial = vhelix_rotation_origami_sq(vhelix_direction_initial, vhelix_perp_initial) period = 21 elif origami_he: vhelix_perp_initial = vhelix_rotation_origami_he(vhelix_direction_initial, vhelix_perp_initial) period = 32 g = gen.StrandGenerator () slice_sys = base.System([side,side,side]) final_sys = base.System([side,side,side]) strand_number = -1 partner_list_scaf = [] partner_list_stap = [] found_partner = False join_list_scaf = [] join_list_stap = [] for h in cadsys.vhelices: h.cad_index = vhelix_counter if origami_sq: strands, helix_angles, pos, rot, vhelix_direction, vhelix_perp = generate_vhelices_origami_sq(vhelix_direction_initial, vhelix_perp_initial, h, sequence_file, single_strand_system, vhelix_counter) elif origami_he: strands, helix_angles, pos, rot, vhelix_direction, vhelix_perp = generate_vhelices_origami_he(vhelix_direction_initial, vhelix_perp_initial, h, sequence_file, single_strand_system, vhelix_counter) nodes = build_nodes(h) # read the scaffold squares and add strands to slice_sys i = 0 for s in h.scaf: if s.V_0 == -1 and s.b_0 == -1: if s.V_1 == -1 and s.b_0 == -1: pass elif s.V_1 == h.num: if h.num % 2 == 0: strand_number += 1 begin_helix = i if h.num % 2 == 1: if nupack: vhelix_to_scaffold = add_slice_nupack(h, strand_number, begin_helix, end_helix, vhelix_to_scaffold, 0) else: slice_sys = add_slice(slice_sys, h, begin_helix, end_helix, nodes, strands, pos, vhelix_direction, vhelix_perp, rot, helix_angles, 0, block_seq, sequences) vh_vb2nuc = add_slice_nupack(h, strand_number, begin_helix, end_helix, vh_vb2nuc, 2) else: base.Logger.log("unexpected square array", base.Logger.WARNING) elif s.V_0 == h.num: if s.V_1 == -1 and s.b_1 == -1: if h.num % 2 == 1: strand_number += 1 end_helix = i if h.num % 2 == 0: if nupack: vhelix_to_scaffold = add_slice_nupack(h, strand_number, begin_helix, end_helix, vhelix_to_scaffold, 0) else: slice_sys = add_slice(slice_sys, h, begin_helix, end_helix, nodes, strands, pos, vhelix_direction, vhelix_perp, rot, helix_angles, 0, block_seq, sequences) vh_vb2nuc = add_slice_nupack(h, strand_number, begin_helix, end_helix, vh_vb2nuc, 2) elif s.V_1 == h.num: pass else: if h.num % 2 == 1: strand_number += 1 end_helix = i if h.num % 2 == 0 : if nupack: vhelix_to_scaffold = add_slice_nupack(h, strand_number, begin_helix, end_helix, vhelix_to_scaffold, 0) else: slice_sys = add_slice(slice_sys, h, begin_helix, end_helix, nodes, strands, pos, vhelix_direction, vhelix_perp, rot, helix_angles, 0, block_seq, sequences) vh_vb2nuc = add_slice_nupack(h, strand_number, begin_helix, end_helix, vh_vb2nuc, 2) if h.num % 2 == 1: column = i else: column = i for j in range(len(partner_list_scaf)): if [h.num, column] == partner_list_scaf[j]: join_list_scaf[j].insert(0,strand_number) found_partner = True if found_partner == False: join_list_scaf.append([strand_number]) partner_list_scaf.append([s.V_1, s.b_1]) found_partner = False else: if s.V_1 == -1 and s.b_1 == -1: base.Logger.log("unexpected square array", base.Logger.WARNING) elif s.V_1 == h.num: if h.num % 2 == 0: strand_number += 1 begin_helix = i if h.num % 2 == 1: if nupack: vhelix_to_scaffold = add_slice_nupack(h, strand_number, begin_helix, end_helix, vhelix_to_scaffold, 0) else: slice_sys = add_slice(slice_sys, h, begin_helix, end_helix, nodes, strands, pos, vhelix_direction, vhelix_perp, rot, helix_angles, 0, block_seq, sequences) vh_vb2nuc = add_slice_nupack(h, strand_number, begin_helix, end_helix, vh_vb2nuc, 2) for j in range(len(partner_list_scaf)): if h.num % 2 == 1: column = i else: column = i if [h.num, column] == partner_list_scaf[j]: join_list_scaf[j].append(strand_number) found_partner = True if found_partner == False: join_list_scaf.append([strand_number]) partner_list_scaf.append([s.V_0, s.b_0]) found_partner = False else: base.Logger.log("unexpected square array", base.Logger.WARNING) i += 1 # read the staple squares and add strands to slice_sys i = 0 for s in h.stap: if s.V_0 == -1 and s.b_0 == -1: if s.V_1 == -1 and s.b_0 == -1: pass elif s.V_1 == h.num: if h.num % 2 == 1: strand_number += 1 begin_helix = i if h.num % 2 == 0: if nupack: staple_to_vhelix = add_slice_nupack(h, strand_number, begin_helix, end_helix, staple_to_vhelix, 1) else: slice_sys = add_slice(slice_sys, h, begin_helix, end_helix, nodes, strands, pos, vhelix_direction, vhelix_perp, rot, helix_angles, 1, block_seq, sequences) vh_vb2nuc = add_slice_nupack(h, strand_number, begin_helix, end_helix, vh_vb2nuc, 3) else: base.Logger.log("unexpected square array", base.Logger.WARNING) elif s.V_0 == h.num: if s.V_1 == -1 and s.b_1 == -1: if h.num % 2 == 0: strand_number += 1 end_helix = i if h.num % 2 == 1: if nupack: staple_to_vhelix = add_slice_nupack(h, strand_number, begin_helix, end_helix, staple_to_vhelix, 1) else: slice_sys = add_slice(slice_sys, h, begin_helix, end_helix, nodes, strands, pos, vhelix_direction, vhelix_perp, rot, helix_angles, 1, block_seq, sequences) vh_vb2nuc = add_slice_nupack(h, strand_number, begin_helix, end_helix, vh_vb2nuc, 3) elif s.V_1 == h.num: pass else: if h.num % 2 == 0: strand_number += 1 end_helix = i if h.num % 2 == 1: if nupack: staple_to_vhelix = add_slice_nupack(h, strand_number, begin_helix, end_helix, staple_to_vhelix, 1) else: slice_sys = add_slice(slice_sys, h, begin_helix, end_helix, nodes, strands, pos, vhelix_direction, vhelix_perp, rot, helix_angles, 1, block_seq, sequences) vh_vb2nuc = add_slice_nupack(h, strand_number, begin_helix, end_helix, vh_vb2nuc, 3) if h.num % 2 == 0: column = i else: column = i for j in range(len(partner_list_stap)): if [h.num, column] == partner_list_stap[j]: join_list_stap[j].insert(0,strand_number) found_partner = True if found_partner == False: join_list_stap.append([strand_number]) partner_list_stap.append([s.V_1, s.b_1]) found_partner = False else: if s.V_1 == -1 and s.b_1 == -1: base.Logger.log("unexpected square array", base.Logger.WARNING) elif s.V_1 == h.num: if h.num % 2 == 1: strand_number += 1 begin_helix = i if h.num % 2 == 0: if nupack: staple_to_vhelix = add_slice_nupack(h, strand_number, begin_helix, end_helix, staple_to_vhelix, 1) else: slice_sys = add_slice(slice_sys, h, begin_helix, end_helix, nodes, strands, pos, vhelix_direction, vhelix_perp, rot, helix_angles, 1, block_seq, sequences) vh_vb2nuc = add_slice_nupack(h, strand_number, begin_helix, end_helix, vh_vb2nuc, 3) for j in range(len(partner_list_stap)): if h.num % 2 == 0: column = i else: column = i if [h.num, column] == partner_list_stap[j]: join_list_stap[j].append(strand_number) found_partner = True if found_partner == False: join_list_stap.append([strand_number]) partner_list_stap.append([s.V_0, s.b_0]) found_partner = False else: base.Logger.log("unexpected square array", base.Logger.WARNING) i += 1 vhelix_counter += 1 join_lists = [join_list_scaf, join_list_stap] # add strands to final_sys that aren't joined join_list_unpacked = [] for a in range(2): for i in join_lists[a]: join_list_unpacked.extend(i) for i in range(len(slice_sys._strands)): if i not in join_list_unpacked: final_sys.add_strand(slice_sys._strands[i], check_overlap = False) vh_vb2nuc_final.add_strand(i, vh_vb2nuc) for a in range(2): join_list = join_lists[a] all_are_joined = False restart = False if not nupack: # check distance between the backbones we are about to join for pair in join_list: strand1 = slice_sys._strands[pair[0]] strand2 = slice_sys._strands[pair[1]] backbone_backbone_dist = strand1._nucleotides[-1].distance(strand2._nucleotides[0], PBC=False) absolute_bb_dist = np.sqrt(np.dot(backbone_backbone_dist, backbone_backbone_dist)) if absolute_bb_dist > 1.0018 or absolute_bb_dist < 0.5525: base.Logger.log("backbone-backbone distance across join the wrong length: %f" % absolute_bb_dist, base.Logger.WARNING) # match up all the pairs of joins that involve the same strand circular = [] while all_are_joined == False: restart = False for i in range(len(join_list)): if restart == True: break for j in range(len(join_list)): if restart == True: break if join_list[i][0] == join_list[j][-1]: if i != j: join_list[j].extend(join_list[i][1:]) join_list.pop(i) restart = True break else: if i not in circular: circular.append(i) if restart == False: all_are_joined = True # add joined strands for ii, join in enumerate(join_list): if not nupack: joined_strand = slice_sys._strands[join[0]] if ii in circular: for k in range(1, len(join)-1): joined_strand = joined_strand.append(slice_sys._strands[join[k]]) joined_strand.make_circular(check_join_len=True) else: for k in range(1, len(join)): joined_strand = joined_strand.append(slice_sys._strands[join[k]]) final_sys.add_strand(joined_strand, check_overlap = False) # This is a bug fix. Ben 12/2/14 # for a circular strand we need to terminate the strand one element early (so reduce the length # of the range by 1), since the final element is just a repeat of the first one. if joined_strand._circular: joining_range = range(len(join) - 2) else: joining_range = range(len(join) - 1) # add joined strands to v2n index for k in joining_range: vh_vb2nuc_final.add_strand(join[k], vh_vb2nuc, continue_join = True) vh_vb2nuc_final.add_strand(join[k + 1], vh_vb2nuc, continue_join = False) if single_strand_system == 1: final_sys._strands[0].set_sequence(sequences[0]) if nupack: per_strand_nucleotide_counter = 0 found_staple = False for k in range(len(join)): record_joined.append(join[k]) nucleotide_counter = 0 for (vhelix,vbase), [scaf_index, scaf_nucleotide] in vhelix_to_scaffold.iteritems(): if scaf_index == join[k]: vhelix_to_scaffold_final[(vhelix, vbase)] = [0, scaf_nucleotide + per_strand_nucleotide_counter] nucleotide_counter += 1 for (staple_index, staple_nucleotide), [vhelix, vbase] in staple_to_vhelix.iteritems(): if staple_index == join[k]: staple_to_vhelix_final[(len(staple_to_scaffold), staple_nucleotide + per_strand_nucleotide_counter)] = [vhelix, vbase] nucleotide_counter += 1 found_staple = True per_strand_nucleotide_counter += nucleotide_counter if k == len(join) - 1 and found_staple: staple_to_scaffold.append(range(per_strand_nucleotide_counter)) for staple_nucleotide in staple_to_scaffold[-1]: staple_nucleotide = -1 if sequence_file and single_strand_system: if len(final_sys._strands) > 1: base.Logger.log("more than one strand detected - sequence file will not be read", base.Logger.WARNING) final_sys._strands[0].set_sequence(np.random.randint(0, 4, len(final_sys._strands[0]._nucleotides))) # this line does not work ## Fix to reverse the direction of every strand so that the 3' to 5' direction is the same ## as in Cadnano. In cadnano the strands point in the 5' to 3' direction, whereas in oxDNA ## they point in the 3' to 5' direction. Ben 29/11/13 rev_sys = base.System(final_sys._box) for strand in final_sys._strands: reverse_nucs = [nuc for nuc in strand._nucleotides] reverse_nucs.reverse() rev_strand = base.Strand() for nuc in reverse_nucs: rev_strand.add_nucleotide(base.Nucleotide(nuc.cm_pos, nuc._a1, -nuc._a3, nuc._base, nuc._btype)) if strand._circular: rev_strand.make_circular(check_join_len=True) rev_sys.add_strand(rev_strand, check_overlap = False) ## also reverse the vhelix_vbase_to_nucleotide order so it corresponds to the reversed system vh_vb2nuc_rev = oru.vhelix_vbase_to_nucleotide() # count up the number of nucleotides up to but not including the nucleotides in strand ii nnucs_to_here = range(rev_sys._N_strands) nuc_total = 0 for strandii, strand in enumerate(rev_sys._strands): nnucs_to_here[strandii] = nuc_total nuc_total += len(strand._nucleotides) # fill in the _scaf and _stap dicts for the reverse vhelix_vbase_to_nucleotide object for vh, vb in vh_vb2nuc_final._scaf.keys(): strandii, nuciis = vh_vb2nuc_final._scaf[(vh, vb)] rev_nuciis = [] for nucii in nuciis: rev_nuciis.append(len(rev_sys._strands[strandii]._nucleotides) - 1 - (nucii - nnucs_to_here[strandii]) + nnucs_to_here[strandii]) vh_vb2nuc_rev.add_scaf(vh, vb, strandii, rev_nuciis) for vh, vb in vh_vb2nuc_final._stap.keys(): strandii, nuciis = vh_vb2nuc_final._stap[(vh, vb)] rev_nuciis = [] for nucii in nuciis: rev_nuciis.append(len(rev_sys._strands[strandii]._nucleotides) - 1 - (nucii - nnucs_to_here[strandii]) + nnucs_to_here[strandii]) vh_vb2nuc_rev.add_stap(vh, vb, strandii, rev_nuciis) # dump spatial arrangement of vhelices to a file vhelix_pattern = {} for i in range(len(cadsys.vhelices)): vhelix_pattern[cadsys.vhelices[i].num] = (cadsys.vhelices[i].row,cadsys.vhelices[i].col) fout = open("virt2nuc", "w") pickle.dump((vh_vb2nuc_rev, vhelix_pattern), fout) #pickle.dump((vh_vb2nuc_final, vhelix_pattern), fout) fout.close() base.Logger.log("printed index file virt2nuc", base.Logger.INFO) if nupack == 0: #final_sys.print_lorenzo_output ("prova.conf", "prova.top") rev_sys.print_lorenzo_output ("prova.conf", "prova.top") base.Logger.log("printed lorenzo output files prova.conf, prova.top", base.Logger.INFO) else: # check for unjoined strands if len(vhelix_to_scaffold_final) == 0: vhelix_to_scaffold_final = vhelix_to_scaffold # get a list of staple indices staple_indices = [] for (staple_index, staple_nucleotide) in staple_to_vhelix.keys(): if staple_index not in staple_indices: staple_indices.append(staple_index) for recorded_staple_index in staple_indices: if recorded_staple_index not in record_joined: nucleotide_counter = 0 for (staple_index, staple_nucleotide), [vhelix, vbase] in staple_to_vhelix.iteritems(): if staple_index == recorded_staple_index: staple_to_vhelix_final[(len(staple_to_scaffold), staple_nucleotide)] = [vhelix, vbase] nucleotide_counter += 1 staple_to_scaffold.append(range(nucleotide_counter)) for staple_nucleotide in staple_to_scaffold[-1]: staple_nucleotide = -1 for key in staple_to_vhelix_final: staple, staple_nucleotide = key [vhelix, vbase] = staple_to_vhelix_final[key] [partner_scaf_index, partner_scaf_nucleotide] = vhelix_to_scaffold_final[(vhelix,vbase)] staple_to_scaffold[staple][staple_nucleotide] = partner_scaf_nucleotide base.Logger.log("dumping staple to scaffold pattern to output.sts", base.Logger.INFO) fout = open("output.sts", "w") pickle.dump(staple_to_scaffold, fout) fout.close()