Beispiel #1
0
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
Beispiel #2
0
    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
Beispiel #3
0
    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
Beispiel #4
0
    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
Beispiel #5
0
    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
Beispiel #6
0
    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
Beispiel #7
0
    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
Beispiel #8
0
                                             epsabs=1e-5,
                                             epsrel=0)
    elif integral_type == "simps":
        srange = range(len(ss))
        integrand = [[] for ii in srange]
        for ii in srange:
            for jj in srange:
                # skip ii=jj
                if ii == jj:
                    triple_scalar_product = 0
                else:
                    diff = np.array(
                        [xx[ii] - xx[jj], yy[ii] - yy[jj], zz[ii] - zz[jj]])
                    diff_mag = np.sqrt(np.dot(diff, diff))
                    diff_frac = diff / (diff_mag**3)
                    triple_scalar_product = np.dot(np.cross(tt[ii], tt[jj]),
                                                   diff_frac)
                integrand[ii].append(triple_scalar_product)
        integral = scipy.integrate.simps(scipy.integrate.simps(integrand, ss),
                                         ss)
    else:
        assert False

    writhe = float(integral) / (4 * np.pi)

    return writhe


strand = base.Strand()
get_base_spline(strand)
Beispiel #9
0
    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
Beispiel #10
0
    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
Beispiel #11
0
    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()