From ee1e32647cae9fc96d57ebcc8a9df388f8e860f0 Mon Sep 17 00:00:00 2001 From: Chris Maffeo <cmaffeo2@illinois.edu> Date: Mon, 24 Feb 2020 12:14:40 -0600 Subject: [PATCH] Various changes to make it easy to run circular structures --- mrdna/segmentmodel.py | 67 +++++++++++++++++++++++++++---------------- mrdna/simulate.py | 2 ++ 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/mrdna/segmentmodel.py b/mrdna/segmentmodel.py index 6a8c6a6..33db573 100644 --- a/mrdna/segmentmodel.py +++ b/mrdna/segmentmodel.py @@ -199,8 +199,7 @@ class ConnectableElement(): self.connections.append(connection) if other is not self: other.connections.append(connection) - else: - raise NotImplementedError("Segments cannot yet be connected to themselves; if you are attempting to make a circular object, try breaking the object into multiple segments") + l = A.container.locations if A not in l: l.append(A) l = B.container.locations @@ -977,7 +976,6 @@ class Segment(ConnectableElement, Group): def _generate_beads(self, bead_model, max_basepairs_per_bead, max_nucleotides_per_bead): - """ Generate beads (positions, types, etc) and bonds, angles, dihedrals, exclusions """ ## TODO: decide whether to remove bead_model argument ## (currently unused) @@ -1003,7 +1001,7 @@ class Segment(ConnectableElement, Group): ## Add ends if they don't exist yet ## TODOTODO: test 1 nt segments? - if len(existing_beads) == 0 or existing_beads[0][0].get_nt_position(self,0) >= 0.5: + if len(existing_beads) == 0 or (existing_beads[0][0].get_nt_position(self,0) >= 0.5 and 'is_circular_bead' not in existing_beads[0][0].__dict__): # if len(existing_beads) > 0: # assert(existing_beads[0].get_nt_position(self) >= 0.5) c = self.nt_pos_to_contour(0) @@ -1011,7 +1009,7 @@ class Segment(ConnectableElement, Group): b = self._generate_one_bead(c, 0) existing_beads = [(b,0)] + existing_beads - if existing_beads[-1][0].get_nt_position(self,1)-(self.num_nt-1) < -0.5 or len(existing_beads)==1: + if (existing_beads[-1][0].get_nt_position(self,1)-(self.num_nt-1) < -0.5 and 'is_circular_bead' not in existing_beads[0][0].__dict__) or len(existing_beads)==1: c = self.nt_pos_to_contour(self.num_nt-1) if self.num_nt == 1: c += 0.4 b = self._generate_one_bead(c, 0) @@ -2141,6 +2139,7 @@ class SegmentModel(ArbdModel): """ Generate beads at intrahelical junctions """ if self.DEBUG: print( "Adding intrahelical beads at junctions" ) + ## Loop through all connections, generating beads at appropriate locations for c,A,B in self.get_connections("intrahelical"): s1,s2 = [l.container for l in (A,B)] @@ -2155,21 +2154,22 @@ class SegmentModel(ArbdModel): assert( np.isclose(a,0) or np.isclose(a,1) ) ## TODO improve this for combinations of ssDNA and dsDNA (maybe a1/a2 should be calculated differently) - """ Search to see whether bead at location is already found """ - b = None - if isinstance(s1,DoubleStrandedSegment): - b = s1.get_nearest_bead(a1) + + def _get_nearest(seg,address): + b = seg.get_nearest_bead(address) if b is not None: - assert( b.parent is s1 ) + assert( b.parent is seg ) """ if above assertion is true, no problem here """ - if np.abs(b.get_nt_position(s1) - s1.contour_to_nt_pos(a1)) > 0.5: - b = None - if b is None and isinstance(s2,DoubleStrandedSegment): - b = s2.get_nearest_bead(a2) - if b is not None: - if np.abs(b.get_nt_position(s2) - s2.contour_to_nt_pos(a2)) > 0.5: + if np.abs(b.get_nt_position(seg) - seg.contour_to_nt_pos(address)) > 0.5: b = None + return b + """ Search to see whether bead at location is already found """ + b = None + if isinstance(s1,DoubleStrandedSegment): + b = _get_nearest(s1,a1) + if b is None and isinstance(s2,DoubleStrandedSegment): + b = _get_nearest(s2,a2) if b is not None and b.parent not in (s1,s2): b = None @@ -2183,6 +2183,8 @@ class SegmentModel(ArbdModel): A.particle = B.particle = b b.is_intrahelical = True b.locations.extend([A,B]) + if s1 is s2: + b.is_circular_bead = True # pdb.set_trace() @@ -2242,12 +2244,27 @@ class SegmentModel(ArbdModel): # pdb.set_trace() """ Add intrahelical neighbors at connections """ - + special_seps = dict() for c,A,B in self.get_connections("intrahelical"): b1,b2 = [l.particle for l in (A,B)] if b1 is b2: - ## already handled by Segment._generate_beads - pass + ## already handled by Segment._generate_beads, unless A,B are on same segment + if A.container == B.container: + sorted_sites = sorted([(abs(L.address-b1.contour_position),L) + for L in (A,B)]) + close_site, far_site = [s[1] for s in sorted_sites] + + b3 = far_site.container.get_nearest_bead(far_site.address) + b1.intrahelical_neighbors.append(b3) + b3.intrahelical_neighbors.append(b1) + + if far_site.address > 0.5: + sep = b1.contour_position + (1-b3.contour_position) + else: + sep = b3.contour_position + (1-b1.contour_position) + sep = A.container.num_nt * sep + special_seps[(b1,b3)] = special_seps[(b3,b1)] = sep + else: for b in (b1,b2): assert( b is not None ) b1.make_intrahelical_neighbor(b2) @@ -2358,10 +2375,12 @@ class SegmentModel(ArbdModel): parent = self._getParent(b1,b2) - seg = b2.parent - c0 = b2.contour_position - sep = np.abs(b1.get_nt_position(seg,c0)-b2.get_nt_position(seg)) - + if (b1,b2) in special_seps: + sep = special_seps[(b1,b2)] + else: + seg = b2.parent + c0 = b2.contour_position + sep = np.abs(b1.get_nt_position(seg,c0)-b2.get_nt_position(seg)) is_dsdna = b1.type_.name[0] == "D" and b2.type_.name[0] == "D" if is_dsdna: @@ -2426,7 +2445,7 @@ class SegmentModel(ArbdModel): parent = self._getParent(b1,b2,b3) seg = b2.parent c0 = b2.contour_position - sep = np.abs(b1.get_nt_position(seg,c0)-b2.get_nt_position(seg)) + np.abs(b3.get_nt_position(seg,c0)-b2.get_nt_position(seg)) + sep = dists[b2][b1] + dists[b2][b3] if b1.type_.name[0] == "D" and b2.type_.name[0] == "D" and b3.type_.name[0] == "D": diff --git a/mrdna/simulate.py b/mrdna/simulate.py index b685098..1d040ac 100644 --- a/mrdna/simulate.py +++ b/mrdna/simulate.py @@ -10,6 +10,8 @@ import numpy as np def _remove_bonds_beyond(model, cutoff): bonds = model.get_bonds() + for seg in model.segments: + bonds.extend(seg.get_bonds()) new_bonds = [] for bond in bonds: n1,n2,b,ex = bond -- GitLab