def generate_vhelices_origami_he(vhelix_direction, vhelix_perp, h, sequence_file, single_strand_system, vhelix_counter): g = cu.StrandGenerator() # generate helix angles helix_angles = np.zeros(h.len - 1, dtype=float) for i in range(len(helix_angles)): modi = i % 21 if modi == 0: helix_angles[i] = 32.571 * np.pi / 180 elif modi == 1: helix_angles[i] = 36 * np.pi / 180 elif modi in (1, 2, 3): helix_angles[i] = 42 * np.pi / 180 elif modi in (5, 6, 7): helix_angles[i] = 29.143 * np.pi / 180 elif modi == 8: helix_angles[i] = 32 * np.pi / 180 elif modi in (9, 10): helix_angles[i] = 44 * np.pi / 180 elif modi in (12, 13, 14): helix_angles[i] = 28.571 * np.pi / 180 elif modi in (16, 17): helix_angles[i] = 41.5 * np.pi / 180 elif modi in (19, 20): helix_angles[i] = 28.476 * np.pi / 180 else: helix_angles[i] = 720. / 21 * (np.pi / 180.) # make sure it's periodic total_sum = 0 for i in range(20): total_sum += helix_angles[i] for i in range(len(helix_angles)): if i % 21 == 20: helix_angles[i] = 720. * np.pi / 180 - total_sum # make the virtual helices if h.num % 2 == 0: pos = np.array([ h.col * np.sqrt(3) * DIST_HEXAGONAL / 2, h.row * 3 * DIST_HEXAGONAL / 2, 0 ]) direction = vhelix_direction perp = vhelix_perp rot = 0. strands = g.generate_or_sq(h.len, start_pos=pos, direction=direction, perp=perp, double=True, rot=rot, angle=helix_angles) else: pos = np.array([ h.col * np.sqrt(3) * DIST_HEXAGONAL / 2, h.row * 3 * DIST_HEXAGONAL / 2 + DIST_HEXAGONAL / 2, (h.len - 1) * base.BASE_BASE ]) direction = -vhelix_direction perp = -vhelix_perp if base.MM_GROOVING: rot = -np.sum(helix_angles) % (2 * np.pi) - 0.07 else: rot = -np.sum(helix_angles) % (2 * np.pi) angles = np.flipud(helix_angles) strands = g.generate_or_sq(h.len, start_pos=pos, direction=direction, perp=perp, double=True, rot=rot, angle=angles) return (strands[0], strands[1]), helix_angles, pos, rot, direction, perp
def generate_vhelices_origami_sq(vhelix_direction, vhelix_perp, h, sequence_file, single_strand_system, vhelix_counter): g = cu.StrandGenerator() # generate helix angles helix_angles = np.zeros(h.len - 1, dtype=float) # hard upper limit on pitch angle seems to be between 54.5 and 55 degrees for i in range(len(helix_angles)): modi = i % 32 if modi < 2: helix_angles[i] = 28 * np.pi / 180 elif modi == 2: helix_angles[i] = 36 * np.pi / 180 elif modi == 3: helix_angles[i] = 54.375 * np.pi / 180 elif modi == 4: helix_angles[i] = 37 * np.pi / 180 elif modi in (5, 6): helix_angles[i] = 27.6666666666666 * np.pi / 180 elif modi == 7: helix_angles[i] = 30.6666666666666 * np.pi / 180 elif modi in (8, 9): helix_angles[i] = 29.3333333333 * np.pi / 180 elif modi == 10: helix_angles[i] = 34.3333333333 * np.pi / 180 elif modi == 11: helix_angles[i] = 54.5 * np.pi / 180 elif modi in (12, 13): helix_angles[i] = (28.91666666666 * np.pi / 180 ) # + 0.25) * np.pi/180 elif modi in (14, 15, 16, 17): helix_angles[i] = 31.16666666666 * np.pi / 180 elif modi == 18: helix_angles[i] = 35.5 * np.pi / 180 elif modi == 19: helix_angles[i] = 52 * np.pi / 180 elif modi == 20: helix_angles[i] = 35.5 * np.pi / 180 elif modi in (21, 22): helix_angles[i] = 27.5 * np.pi / 180 elif modi == 23: helix_angles[i] = 35.5 * np.pi / 180 elif modi >= 24 and modi < 27: helix_angles[i] = 30 * np.pi / 180 elif modi == 27: helix_angles[i] = 52 * np.pi / 180 elif modi == 28: helix_angles[i] = 35.5 * np.pi / 180 else: helix_angles[i] = 30.91666666666 * (np.pi / 180) # make sure the helices are periodic in 32 bases total_sum = 0 for i in range(31): total_sum += helix_angles[i] for i in range(len(helix_angles)): if i % 32 == 31: helix_angles[i] = 1080 * np.pi / 180 - total_sum # make the virtual helices if h.num % 2 == 0: pos = np.array([h.col * DIST_SQUARE, h.row * DIST_SQUARE, 0]) direction = vhelix_direction perp = vhelix_perp rot = 0. angles = helix_angles strands = g.generate_or_sq(h.len, start_pos=pos, direction=direction, perp=perp, double=True, rot=rot, angle=angles) else: pos = np.array([ h.col * DIST_SQUARE, h.row * DIST_SQUARE, (h.len - 1) * base.BASE_BASE ]) direction = -vhelix_direction perp = -vhelix_perp rot = -np.sum(helix_angles) % (2 * np.pi) angles = np.flipud(helix_angles) strands = g.generate_or_sq(h.len, start_pos=pos, direction=direction, perp=perp, double=True, rot=rot, angle=angles) return (strands[0], strands[1]), helix_angles, pos, rot, direction, perp
def insert_loop_skip(strands, start_pos, direction, perp, rot, helix_angles, vhelix, nodes, use_seq, seqs): # return a double strand which is a copy of the double strand in the first argument, but with skips and loops # strand is generated right to left i.e. opposite direction to even vhelix g = cu.StrandGenerator() length_change = [] length_change_total = 0 new_nodes = vh_nodes() new_angle = [] helix_angles_new = np.array(range(len(helix_angles)), dtype=float) for i in range(len(helix_angles)): helix_angles_new[i] = helix_angles[i] if vhelix.num % 2 == 1: reverse_nodes = vh_nodes() for i in range(len(nodes.begin)): reverse_nodes.add_begin(nodes.begin[i]) reverse_nodes.add_end(nodes.end[i]) reverse_nodes.begin.reverse() reverse_nodes.end.reverse() for i in range(len(nodes.begin)): # ltr: left to right; looking at the strand left to right (low to high square index), the beginning/end of the effective strand is here (before skips/loops) # gs: generated strand; the index of the nucleotide (BEFORE skips/loops are applied) on the generated strand corresponding to the beginning/end of the effective strand if vhelix.num % 2 == 0: begin_ltr = nodes.begin[i] end_ltr = nodes.end[i] begin_gs = nodes.begin[i] end_gs = nodes.end[i] else: begin_ltr = reverse_nodes.end[i] end_ltr = reverse_nodes.begin[i] begin_gs = vhelix.len - reverse_nodes.begin[i] - 1 end_gs = vhelix.len - reverse_nodes.end[i] - 1 # check for zero length effective strand if end_gs - begin_gs != 0: # get length change for this effective strand length_change.append(0) for j in vhelix.skip[begin_ltr:end_ltr + 1]: length_change[i] -= int(j) for j in vhelix.loop[begin_ltr:end_ltr + 1]: length_change[i] += int(j) # get new pitch angles for this effective strand new_angle.append( sum(helix_angles[begin_gs:end_gs]) / (end_gs - begin_gs + length_change[i])) helix_angles_new[begin_gs:end_gs] = new_angle[i] # adjust beginning/end indices according to length change begin_gs += length_change_total end_gs += length_change_total + length_change[i] new_nodes.add_begin(begin_gs) new_nodes.add_end(end_gs) # begin_gs > end_gs..... else: length_change.append(0) new_angle.append(sum(helix_angles) / len(helix_angles)) # append an average angle new_nodes.add_begin(begin_gs) new_nodes.add_end(end_gs) length_change_total += length_change[i] # adjust the new helix angle array according to skips/loops deleted = 0 inserted = 0 deleted_this_iteration = 0 inserted_this_iteration = 0 for i in range(len(nodes.begin)): deleted += deleted_this_iteration inserted += inserted_this_iteration deleted_this_iteration = 0 inserted_this_iteration = 0 if vhelix.num % 2 == 0: begin_ltr = nodes.begin[i] end_ltr = nodes.end[i] begin_gs = nodes.begin[i] end_gs = nodes.end[i] else: begin_ltr = reverse_nodes.end[i] end_ltr = reverse_nodes.begin[i] begin_gs = vhelix.len - reverse_nodes.begin[i] - 1 end_gs = vhelix.len - reverse_nodes.end[i] - 1 for j in vhelix.skip[begin_ltr:end_ltr + 1]: if j == 1: helix_angles_new = np.delete(helix_angles_new, begin_gs - deleted + inserted) deleted_this_iteration += 1 for j in vhelix.loop[begin_ltr:end_ltr + 1]: for _ in range(j): helix_angles_new = np.insert(helix_angles_new, begin_gs - deleted + inserted, new_angle[i]) inserted_this_iteration += 1 new_strands = g.generate_or_sq(len(helix_angles_new) + 1, start_pos=start_pos, direction=direction, perp=perp, double=True, rot=rot, angle=helix_angles_new, length_change=length_change, region_begin=new_nodes.begin, region_end=new_nodes.end) if use_seq: try: sequence = [x for x in seqs[vhelix.cad_index]] except IndexError: base.Logger.die( "sequence file contains too few rows compared to the number of virtual helices in the cadnano file, dying" ) if vhelix.num % 2 == 1: sequence.reverse() if new_strands[0].get_length() != len(sequence): base.Logger.log( "Cannot change sequence: lengths don't match; virtual helix %s, sequence length %s, virtual helix length %s - are skips/loops accounted for?" % (vhelix.num, len(sequence), new_strands[0].get_length()), base.Logger.WARNING) else: new_strands[0].set_sequence(sequence) sequence2 = [3 - s for s in sequence] sequence2.reverse() if new_strands[0].get_length() != len(sequence): base.Logger.log( "Cannot change sequence: lengths don't match; virtual helix %s, sequence length %s, virtual helix length %s - are skips/loops accounted for?" % (vhelix.num, len(sequence), new_strands[0].get_length()), base.Logger.WARNING) else: new_strands[1].set_sequence(sequence2) return new_strands
def rpoly_to_oxDNA(opts): # Read File # 'data' stores helix coordinates + rotaion in quaternion data = [] rev_helix_connections = [] # staple connection information, fwd_helix_connections = [] # scaffold connections count = 0 polyFile = open(opts.file_name_in, 'r') try: for line in polyFile: if line.startswith('hb'): data.insert(count, line.split(' ')) count += 1 elif line.startswith('c'): if 'f3' not in line: rev_helix_connections.append([ int(re.search('c helix_(.+?) ', line).group(1)), int(re.search('\' helix_(.+?) ', line).group(1)) ]) # Extract connection information else: fwd_helix_connections.append([ int(re.search('c helix_(.+?) ', line).group(1)), int(re.search('\' helix_(.+?) ', line).group(1)) ]) except Exception: print('Failed to read the file') generator = cu.StrandGenerator() staple_fragments = base.System( [100, 100, 100] ) # temporary system to store staple fragments before later connecting them scaffold_fragments = base.System([100, 100, 100]) # Reads orientation from the "data" and produces rotations from the Quaternian coordinates largest_size = 0.0 for n, i in enumerate(data): position = [ float(i[3]) / 0.84, float(i[4]) / 0.84, float(i[5]) / 0.84 ] # 0.84 scaling is ad hoc solution to get good looking models n_bp = int(i[2]) q = Quaternion(w=float(i[9]), x=float(i[6]), y=float(i[7]), z=float(i[8])) # find the helix roation Info from file vec = q.rotate(np.array([0.0, 0.0, 1.0])) # use it to figure out direction vec2 = q.rotate( [0.65, -0.76, 0.0]) # ad hoc onversion between rpoly rotation and cadnano utils new_position = move_along_vector( position, vec, n_bp ) # rpoly helix coordinates are defined in center of helix, cadnano utils have positions in the base of helix. for j in new_position: # go through every coordinate to find the largest coordinate to figure out box size if j > largest_size: largest_size = j else: pass # strand 0 is the scaffold and strand 1 is the staple new_strands = generator.generate_or_sq(bp=n_bp, start_pos=new_position, direction=vec, perp=vec2) fragment1, fragment2 = new_strands[1].cut_in_two( ) # cut strand 1 into two equal lengh staple fragments for later connections # store the fragments in this system for later connections staple_fragments.add_strand(fragment1) staple_fragments.add_strand(fragment2) scaffold_fragments.add_strand(new_strands[0]) output_system = base.System( [largest_size * 3.0, largest_size * 3.0, largest_size * 3.0]) for n in rev_helix_connections: # iterate through staple strand connections and connect the previously generated fragments connect_from = n[0] * 2 - 1 connect_to = n[1] * 2 - 2 staple_strand = staple_fragments._strands[connect_from].copy() staple_strand = staple_strand.append( staple_fragments._strands[connect_to].copy()) output_system.add_strand(staple_strand) scaffold_strand = scaffold_fragments._strands[0].copy() for n in fwd_helix_connections[:-1]: next_segment_adress = n[1] - 1 next_segment = scaffold_fragments._strands[next_segment_adress].copy() scaffold_strand = scaffold_strand.append(next_segment) scaffold_strand.make_circular() output_system.add_strand(scaffold_strand) basename = os.path.basename(opts.file_name_in) top_file = basename + ".top" conf_file = basename + ".oxdna" output_system.print_lorenzo_output(conf_file, top_file)