diff --git a/doc/src/PDF/USER-CGDNA-overview.pdf b/doc/src/PDF/USER-CGDNA-overview.pdf index 092451b4612cae40a42664d0364a0f7575b5b240..b0d257adafdb81bad8335a44c0d30413515d418b 100644 Binary files a/doc/src/PDF/USER-CGDNA-overview.pdf and b/doc/src/PDF/USER-CGDNA-overview.pdf differ diff --git a/doc/src/Section_howto.txt b/doc/src/Section_howto.txt index 8cfbe1c46c9418458f691f19a73101ec1b4aac5e..887652425c9ef49ca16773dd54c59523981aa19c 100644 --- a/doc/src/Section_howto.txt +++ b/doc/src/Section_howto.txt @@ -1032,6 +1032,10 @@ profile consistent with the applied shear strain rate. An alternative method for calculating viscosities is provided via the "fix viscosity"_fix_viscosity.html command. +NEMD simulations can also be used to measure transport properties of a fluid +through a pore or channel. Simulations of steady-state flow can be performed +using the "fix flow/gauss"_fix_flow_gauss.html command. + :line 6.14 Finite-size spherical and aspherical particles :link(howto_14),h4 diff --git a/doc/src/fix_halt.txt b/doc/src/fix_halt.txt index 3f7650466f268b6b685e0a69c85c4366b5161244..ced489a54c5d58d65cefdfae16929f03e104edc8 100644 --- a/doc/src/fix_halt.txt +++ b/doc/src/fix_halt.txt @@ -121,7 +121,7 @@ halt ID, so that the same condition is not immediately triggered in a subsequent run. The optional {message} keyword determines whether a message is printed -to the screen and logfile when the half condition is triggered. If +to the screen and logfile when the halt condition is triggered. If {message} is set to yes, a one line message with the values that triggered the halt is printed. If {message} is set to no, no message is printed; the run simply exits. The latter may be desirable for diff --git a/doc/src/package.txt b/doc/src/package.txt index 02afb8d6200ed159de48fb7003c5e25e5291e87e..a0894b3128d7cf2719a40919b2379ec4b2c21645 100644 --- a/doc/src/package.txt +++ b/doc/src/package.txt @@ -62,12 +62,13 @@ args = arguments specific to the style :l {no_affinity} values = none {kokkos} args = keyword value ... zero or more keyword/value pairs may be appended - keywords = {neigh} or {newton} or {binsize} or {comm} or {comm/exchange} or {comm/forward} - {neigh} value = {full} or {half} or {n2} or {full/cluster} + keywords = {neigh} or {neigh/qeq} or {newton} or {binsize} or {comm} or {comm/exchange} or {comm/forward} + {neigh} value = {full} or {half} + full = full neighbor list + half = half neighbor list built in thread-safe manner + {neigh/qeq} value = {full} or {half} full = full neighbor list half = half neighbor list built in thread-safe manner - n2 = non-binning neighbor list build, O(N^2) algorithm - full/cluster = full neighbor list with clustered groups of atoms {newton} = {off} or {on} off = set Newton pairwise and bonded flags off (default) on = set Newton pairwise and bonded flags on @@ -392,10 +393,7 @@ default value as listed below. The {neigh} keyword determines how neighbor lists are built. A value of {half} uses a thread-safe variant of half-neighbor lists, -the same as used by most pair styles in LAMMPS. A value of -{n2} uses an O(N^2) algorithm to build the neighbor list without -binning, where N = # of atoms on a processor. It is typically slower -than the other methods, which use binning. +the same as used by most pair styles in LAMMPS. A value of {full} uses a full neighbor lists and is the default. This performs twice as much computation as the {half} option, however that @@ -403,15 +401,9 @@ is often a win because it is thread-safe and doesn't require atomic operations in the calculation of pair forces. For that reason, {full} is the default setting. However, when running in MPI-only mode with 1 thread per MPI task, {half} neighbor lists will typically be faster, -just as it is for non-accelerated pair styles. - -A value of {full/cluster} is an experimental neighbor style, where -particles interact with all particles within a small cluster, if at -least one of the clusters particles is within the neighbor cutoff -range. This potentially allows for better vectorization on -architectures such as the Intel Phi. If also reduces the size of the -neighbor list by roughly a factor of the cluster size, thus reducing -the total memory footprint considerably. +just as it is for non-accelerated pair styles. Similarly, the {neigh/qeq} +keyword determines how neighbor lists are built for "fix qeq/reax/kk"_fix_qeq_reax.html. +If not explicitly set, the value of {neigh/qeq} will match {neigh}. The {newton} keyword sets the Newton flags for pairwise and bonded interactions to {off} or {on}, the same as the "newton"_newton.html @@ -582,9 +574,9 @@ is used. If it is not used, you must invoke the package intel command in your input script or or via the "-pk intel" "command-line switch"_Section_start.html#start_7. -For the KOKKOS package, the option defaults neigh = full, newton = -off, binsize = 0.0, and comm = device. These settings are made -automatically by the required "-k on" "command-line +For the KOKKOS package, the option defaults neigh = full, neigh/qeq + = full, newton = off, binsize = 0.0, and comm = device. These settings + are made automatically by the required "-k on" "command-line switch"_Section_start.html#start_7. You can change them bu using the package kokkos command in your input script or via the "-pk kokkos" "command-line switch"_Section_start.html#start_7. diff --git a/examples/USER/cgdna/util/generate.py b/examples/USER/cgdna/util/generate.py new file mode 100644 index 0000000000000000000000000000000000000000..d5a74e9bf7f85fb7d0f9742f4c1b7895c2ce1aca --- /dev/null +++ b/examples/USER/cgdna/util/generate.py @@ -0,0 +1,630 @@ +#!/usr/bin/env python +""" +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Oliver Henrich (EPCC, University of Edinburgh) +------------------------------------------------------------------------- */ +""" + + +""" +Import basic modules +""" +import sys, os, timeit + +from timeit import default_timer as timer +start_time = timer() +""" +Try to import numpy; if failed, import a local version mynumpy +which needs to be provided +""" +try: + import numpy as np +except: + print >> sys.stderr, "numpy not found. Exiting." + sys.exit(1) + +""" +Check that the required arguments (box offset and size in simulation units +and the sequence file were provided +""" +try: + box_offset = float(sys.argv[1]) + box_length = float(sys.argv[2]) + infile = sys.argv[3] +except: + print >> sys.stderr, "Usage: %s <%s> <%s> <%s>" % (sys.argv[0], \ + "box offset", "box length", "file with sequences") + sys.exit(1) +box = np.array ([box_length, box_length, box_length]) + +""" +Try to open the file and fail gracefully if file cannot be opened +""" +try: + inp = open (infile, 'r') + inp.close() +except: + print >> sys.stderr, "Could not open file '%s' for reading. \ + Aborting." % infile + sys.exit(2) + +# return parts of a string +def partition(s, d): + if d in s: + sp = s.split(d, 1) + return sp[0], d, sp[1] + else: + return s, "", "" + +""" +Define the model constants +""" +# set model constants +PI = np.pi +POS_BASE = 0.4 +POS_BACK = -0.4 +EXCL_RC1 = 0.711879214356 +EXCL_RC2 = 0.335388426126 +EXCL_RC3 = 0.52329943261 + +""" +Define auxillary variables for the construction of a helix +""" +# center of the double strand +CM_CENTER_DS = POS_BASE + 0.2 + +# ideal distance between base sites of two nucleotides +# which are to be base paired in a duplex +BASE_BASE = 0.3897628551303122 + +# cutoff distance for overlap check +RC2 = 16 + +# squares of the excluded volume distances for overlap check +RC2_BACK = EXCL_RC1**2 +RC2_BASE = EXCL_RC2**2 +RC2_BACK_BASE = EXCL_RC3**2 + +# enumeration to translate from letters to numbers and vice versa +number_to_base = {1 : 'A', 2 : 'C', 3 : 'G', 4 : 'T'} +base_to_number = {'A' : 1, 'a' : 1, 'C' : 2, 'c' : 2, + 'G' : 3, 'g' : 3, 'T' : 4, 't' : 4} + +# auxillary arrays +positions = [] +a1s = [] +a3s = [] +quaternions = [] + +newpositions = [] +newa1s = [] +newa3s = [] + +basetype = [] +strandnum = [] + +bonds = [] + +""" +Convert local body frame to quaternion DOF +""" +def exyz_to_quat (mya1, mya3): + + mya2 = np.cross(mya3, mya1) + myquat = [1,0,0,0] + + q0sq = 0.25 * (mya1[0] + mya2[1] + mya3[2] + 1.0) + q1sq = q0sq - 0.5 * (mya2[1] + mya3[2]) + q2sq = q0sq - 0.5 * (mya1[0] + mya3[2]) + q3sq = q0sq - 0.5 * (mya1[0] + mya2[1]) + + # some component must be greater than 1/4 since they sum to 1 + # compute other components from it + + if q0sq >= 0.25: + myquat[0] = np.sqrt(q0sq) + myquat[1] = (mya2[2] - mya3[1]) / (4.0*myquat[0]) + myquat[2] = (mya3[0] - mya1[2]) / (4.0*myquat[0]) + myquat[3] = (mya1[1] - mya2[0]) / (4.0*myquat[0]) + elif q1sq >= 0.25: + myquat[1] = np.sqrt(q1sq) + myquat[0] = (mya2[2] - mya3[1]) / (4.0*myquat[1]) + myquat[2] = (mya2[0] + mya1[1]) / (4.0*myquat[1]) + myquat[3] = (mya1[2] + mya3[0]) / (4.0*myquat[1]) + elif q2sq >= 0.25: + myquat[2] = np.sqrt(q2sq) + myquat[0] = (mya3[0] - mya1[2]) / (4.0*myquat[2]) + myquat[1] = (mya2[0] + mya1[1]) / (4.0*myquat[2]) + myquat[3] = (mya3[1] + mya2[2]) / (4.0*myquat[2]) + elif q3sq >= 0.25: + myquat[3] = np.sqrt(q3sq) + myquat[0] = (mya1[1] - mya2[0]) / (4.0*myquat[3]) + myquat[1] = (mya3[0] + mya1[2]) / (4.0*myquat[3]) + myquat[2] = (mya3[1] + mya2[2]) / (4.0*myquat[3]) + + norm = 1.0/np.sqrt(myquat[0]*myquat[0] + myquat[1]*myquat[1] + \ + myquat[2]*myquat[2] + myquat[3]*myquat[3]) + myquat[0] *= norm + myquat[1] *= norm + myquat[2] *= norm + myquat[3] *= norm + + return np.array([myquat[0],myquat[1],myquat[2],myquat[3]]) + +""" +Adds a strand to the system by appending it to the array of previous strands +""" +def add_strands (mynewpositions, mynewa1s, mynewa3s): + overlap = False + + # This is a simple check for each of the particles where for previously + # placed particles i we check whether it overlaps with any of the + # newly created particles j + + print >> sys.stdout, "## Checking for overlaps" + + for i in xrange(len(positions)): + + p = positions[i] + pa1 = a1s[i] + + for j in xrange (len(mynewpositions)): + + q = mynewpositions[j] + qa1 = mynewa1s[j] + + # skip particles that are anyway too far away + dr = p - q + dr -= box * np.rint (dr / box) + if np.dot(dr, dr) > RC2: + continue + + # base site and backbone site of the two particles + p_pos_back = p + pa1 * POS_BACK + p_pos_base = p + pa1 * POS_BASE + q_pos_back = q + qa1 * POS_BACK + q_pos_base = q + qa1 * POS_BASE + + # check for no overlap between the two backbone sites + dr = p_pos_back - q_pos_back + dr -= box * np.rint (dr / box) + if np.dot(dr, dr) < RC2_BACK: + overlap = True + + # check for no overlap between the two base sites + dr = p_pos_base - q_pos_base + dr -= box * np.rint (dr / box) + if np.dot(dr, dr) < RC2_BASE: + overlap = True + + # check for no overlap between backbone site of particle p + # with base site of particle q + dr = p_pos_back - q_pos_base + dr -= box * np.rint (dr / box) + if np.dot(dr, dr) < RC2_BACK_BASE: + overlap = True + + # check for no overlap between base site of particle p and + # backbone site of particle q + dr = p_pos_base - q_pos_back + dr -= box * np.rint (dr / box) + if np.dot(dr, dr) < RC2_BACK_BASE: + overlap = True + + # exit if there is an overlap + if overlap: + return False + + # append to the existing list if no overlap is found + if not overlap: + + for p in mynewpositions: + positions.append(p) + for p in mynewa1s: + a1s.append (p) + for p in mynewa3s: + a3s.append (p) + # calculate quaternion from local body frame and append + for ia in xrange(len(mynewpositions)): + mynewquaternions = exyz_to_quat(mynewa1s[ia],mynewa3s[ia]) + quaternions.append(mynewquaternions) + + return True + + +""" +Returns the rotation matrix defined by an axis and angle +""" +def get_rotation_matrix(axis, anglest): + # The argument anglest can be either an angle in radiants + # (accepted types are float, int or np.float64 or np.float64) + # or a tuple [angle, units] where angle is a number and + # units is a string. It tells the routine whether to use degrees, + # radiants (the default) or base pairs turns. + if not isinstance (anglest, (np.float64, np.float32, float, int)): + if len(anglest) > 1: + if anglest[1] in ["degrees", "deg", "o"]: + #angle = np.deg2rad (anglest[0]) + angle = (np.pi / 180.) * (anglest[0]) + elif anglest[1] in ["bp"]: + angle = int(anglest[0]) * (np.pi / 180.) * (35.9) + else: + angle = float(anglest[0]) + else: + angle = float(anglest[0]) + else: + angle = float(anglest) # in degrees (?) + + axis = np.array(axis) + axis /= np.sqrt(np.dot(axis, axis)) + + ct = np.cos(angle) + st = np.sin(angle) + olc = 1. - ct + x, y, z = axis + + return np.array([[olc*x*x+ct, olc*x*y-st*z, olc*x*z+st*y], + [olc*x*y+st*z, olc*y*y+ct, olc*y*z-st*x], + [olc*x*z-st*y, olc*y*z+st*x, olc*z*z+ct]]) + +""" +Generates the position and orientation vectors of a +(single or double) strand from a sequence string +""" +def generate_strand(bp, sequence=None, start_pos=np.array([0, 0, 0]), \ + dir=np.array([0, 0, 1]), perp=False, double=True, rot=0.): + # generate empty arrays + mynewpositions, mynewa1s, mynewa3s = [], [], [] + + # cast the provided start_pos array into a numpy array + start_pos = np.array(start_pos, dtype=float) + + # overall direction of the helix + dir = np.array(dir, dtype=float) + if sequence == None: + sequence = np.random.randint(1, 5, bp) + + # the elseif here is most likely redundant + elif len(sequence) != bp: + n = bp - len(sequence) + sequence += np.random.randint(1, 5, n) + print >> sys.stderr, "sequence is too short, adding %d random bases" % n + + # normalize direction + dir_norm = np.sqrt(np.dot(dir,dir)) + if dir_norm < 1e-10: + print >> sys.stderr, "direction must be a valid vector, \ + defaulting to (0, 0, 1)" + dir = np.array([0, 0, 1]) + else: dir /= dir_norm + + # find a vector orthogonal to dir to act as helix direction, + # if not provided switch off random orientation + 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; + + # generate rotational matrix representing the overall rotation of the helix + R0 = get_rotation_matrix(dir, rot) + + # rotation matrix corresponding to one step along the helix + R = get_rotation_matrix(dir, [1, "bp"]) + + # set the vector a1 (backbone to base) to v1 + a1 = v1 + + # apply the global rotation to a1 + a1 = np.dot(R0, a1) + + # set the position of the fist backbone site to start_pos + rb = np.array(start_pos) + + # set a3 to the direction of the helix + a3 = dir + for i in range(bp): + # work out the position of the centre of mass of the nucleotide + rcdm = rb - CM_CENTER_DS * a1 + + # append to newpositions + mynewpositions.append(rcdm) + mynewa1s.append(a1) + mynewa3s.append(a3) + + # if we are not at the end of the helix, we work out a1 and rb for the + # next nucleotide along the helix + if i != bp - 1: + a1 = np.dot(R, a1) + rb += a3 * BASE_BASE + + # if we are working on a double strand, we do a cycle similar + # to the previous one but backwards + if double == True: + a1 = -a1 + a3 = -dir + R = R.transpose() + for i in range(bp): + rcdm = rb - CM_CENTER_DS * a1 + mynewpositions.append (rcdm) + mynewa1s.append (a1) + mynewa3s.append (a3) + a1 = np.dot(R, a1) + rb += a3 * BASE_BASE + + assert (len (mynewpositions) > 0) + + return [mynewpositions, mynewa1s, mynewa3s] + + +""" +Main function for this script. +Reads a text file with the following format: +- Each line contains the sequence for a single strand (A,C,G,T) +- Lines beginning with the keyword 'DOUBLE' produce double-stranded DNA + +Ex: Two ssDNA (single stranded DNA) +ATATATA +GCGCGCG + +Ex: Two strands, one double stranded, the other single stranded. +DOUBLE AGGGCT +CCTGTA + +""" + +def read_strands(filename): + try: + infile = open (filename) + except: + print >> sys.stderr, "Could not open file '%s'. Aborting." % filename + sys.exit(2) + + # This block works out the number of nucleotides and strands by reading + # the number of non-empty lines in the input file and the number of letters, + # taking the possible DOUBLE keyword into account. + nstrands, nnucl, nbonds = 0, 0, 0 + lines = infile.readlines() + for line in lines: + line = line.upper().strip() + if len(line) == 0: + continue + if line[:6] == 'DOUBLE': + line = line.split()[1] + length = len(line) + print >> sys.stdout, "## Found duplex of %i base pairs" % length + nnucl += 2*length + nstrands += 2 + nbonds += (2*length-2) + else: + line = line.split()[0] + length = len(line) + print >> sys.stdout, \ + "## Found single strand of %i bases" % length + nnucl += length + nstrands += 1 + nbonds += length-1 + # rewind the sequence input file + infile.seek(0) + + print >> sys.stdout, "## nstrands, nnucl = ", nstrands, nnucl + + # generate the data file in LAMMPS format + try: + out = open ("data.oxdna", "w") + except: + print >> sys.stderr, "Could not open data file for writing. Aborting." + sys.exit(2) + + lines = infile.readlines() + nlines = len(lines) + i = 1 + myns = 0 + noffset = 1 + + for line in lines: + line = line.upper().strip() + + # skip empty lines + if len(line) == 0: + i += 1 + continue + + # block for duplexes: last argument of the generate function + # is set to 'True' + if line[:6] == 'DOUBLE': + line = line.split()[1] + length = len(line) + seq = [(base_to_number[x]) for x in line] + + myns += 1 + for b in xrange(length): + basetype.append(seq[b]) + strandnum.append(myns) + + for b in xrange(length-1): + bondpair = [noffset + b, noffset + b + 1] + bonds.append(bondpair) + noffset += length + + # create the sequence of the second strand as made of + # complementary bases + seq2 = [5-s for s in seq] + seq2.reverse() + + myns += 1 + for b in xrange(length): + basetype.append(seq2[b]) + strandnum.append(myns) + + for b in xrange(length-1): + bondpair = [noffset + b, noffset + b + 1] + bonds.append(bondpair) + noffset += length + + print >> sys.stdout, "## Created duplex of %i bases" % (2*length) + + # generate random position of the first nucleotide + cdm = box_offset + np.random.random_sample(3) * box + + # generate the random direction of the helix + axis = np.random.random_sample(3) + axis /= np.sqrt(np.dot(axis, axis)) + + # use the generate function defined above to create + # the position and orientation vector of the strand + newpositions, newa1s, newa3s = generate_strand(len(line), \ + sequence=seq, dir=axis, start_pos=cdm, double=True) + + # generate a new position for the strand until it does not overlap + # with anything already present + start = timer() + while not add_strands(newpositions, newa1s, newa3s): + cdm = box_offset + np.random.random_sample(3) * box + axis = np.random.random_sample(3) + axis /= np.sqrt(np.dot(axis, axis)) + newpositions, newa1s, newa3s = generate_strand(len(line), \ + sequence=seq, dir=axis, start_pos=cdm, double=True) + print >> sys.stdout, "## Trying %i" % i + end = timer() + print >> sys.stdout, "## Added duplex of %i bases (line %i/%i) in %.2fs, now at %i/%i" % \ + (2*length, i, nlines, end-start, len(positions), nnucl) + + # block for single strands: last argument of the generate function + # is set to 'False' + else: + length = len(line) + seq = [(base_to_number[x]) for x in line] + + myns += 1 + for b in xrange(length): + basetype.append(seq[b]) + strandnum.append(myns) + + for b in xrange(length-1): + bondpair = [noffset + b, noffset + b + 1] + bonds.append(bondpair) + noffset += length + + # generate random position of the first nucleotide + cdm = box_offset + np.random.random_sample(3) * box + + # generate the random direction of the helix + axis = np.random.random_sample(3) + axis /= np.sqrt(np.dot(axis, axis)) + + print >> sys.stdout, \ + "## Created single strand of %i bases" % length + + newpositions, newa1s, newa3s = generate_strand(length, \ + sequence=seq, dir=axis, start_pos=cdm, double=False) + start = timer() + while not add_strands(newpositions, newa1s, newa3s): + cdm = box_offset + np.random.random_sample(3) * box + axis = np.random.random_sample(3) + axis /= np.sqrt(np.dot(axis, axis)) + newpositions, newa1s, newa3s = generate_strand(length, \ + sequence=seq, dir=axis, start_pos=cdm, double=False) + print >> sys.stdout, "## Trying %i" % (i) + end = timer() + print >> sys.stdout, "## Added single strand of %i bases (line %i/%i) in %.2fs, now at %i/%i" % \ + (length, i, nlines, end-start,len(positions), nnucl) + + i += 1 + + # sanity check + if not len(positions) == nnucl: + print len(positions), nnucl + raise AssertionError + + out.write('# LAMMPS data file\n') + out.write('%d atoms\n' % nnucl) + out.write('%d ellipsoids\n' % nnucl) + out.write('%d bonds\n' % nbonds) + out.write('\n') + out.write('4 atom types\n') + out.write('1 bond types\n') + out.write('\n') + out.write('# System size\n') + out.write('%f %f xlo xhi\n' % (box_offset,box_offset+box_length)) + out.write('%f %f ylo yhi\n' % (box_offset,box_offset+box_length)) + out.write('%f %f zlo zhi\n' % (box_offset,box_offset+box_length)) + + out.write('\n') + out.write('Masses\n') + out.write('\n') + out.write('1 3.1575\n') + out.write('2 3.1575\n') + out.write('3 3.1575\n') + out.write('4 3.1575\n') + + # for each nucleotide print a line under the headers + # Atoms, Velocities, Ellipsoids and Bonds + out.write('\n') + out.write(\ + '# Atom-ID, type, position, molecule-ID, ellipsoid flag, density\n') + out.write('Atoms\n') + out.write('\n') + + for i in xrange(nnucl): + out.write('%d %d %22.15le %22.15le %22.15le %d 1 1\n' \ + % (i+1, basetype[i], \ + positions[i][0], positions[i][1], positions[i][2], \ + strandnum[i])) + + out.write('\n') + out.write('# Atom-ID, translational, rotational velocity\n') + out.write('Velocities\n') + out.write('\n') + + for i in xrange(nnucl): + out.write("%d %22.15le %22.15le %22.15le %22.15le %22.15le %22.15le\n" \ + % (i+1,0.0,0.0,0.0,0.0,0.0,0.0)) + + out.write('\n') + out.write('# Atom-ID, shape, quaternion\n') + out.write('Ellipsoids\n') + out.write('\n') + + for i in xrange(nnucl): + out.write(\ + "%d %22.15le %22.15le %22.15le %22.15le %22.15le %22.15le %22.15le\n" \ + % (i+1,1.1739845031423408,1.1739845031423408,1.1739845031423408, \ + quaternions[i][0],quaternions[i][1], quaternions[i][2],quaternions[i][3])) + + out.write('\n') + out.write('# Bond topology\n') + out.write('Bonds\n') + out.write('\n') + + for i in xrange(nbonds): + out.write("%d %d %d %d\n" % (i+1,1,bonds[i][0],bonds[i][1])) + + out.close() + + print >> sys.stdout, "## Wrote data to 'data.oxdna'" + print >> sys.stdout, "## DONE" + +# call the above main() function, which executes the program +read_strands (infile) + +end_time=timer() +runtime = end_time-start_time +hours = runtime/3600 +minutes = (runtime-np.rint(hours)*3600)/60 +seconds = (runtime-np.rint(hours)*3600-np.rint(minutes)*60)%60 +print >> sys.stdout, "## Total runtime %ih:%im:%.2fs" % (hours,minutes,seconds) diff --git a/examples/USER/cgdna/util/generate_input.py b/examples/USER/cgdna/util/generate_simple.py similarity index 96% rename from examples/USER/cgdna/util/generate_input.py rename to examples/USER/cgdna/util/generate_simple.py index 25cfedaae22f15e3b809e78066999c02a4c98f8f..33cf1ee7f5faaf0d9faaff53e4af29be6e01e1b1 100644 --- a/examples/USER/cgdna/util/generate_input.py +++ b/examples/USER/cgdna/util/generate_simple.py @@ -29,7 +29,7 @@ def single(): strandstart=len(nucleotide)+1 - for letter in strand[2]: + for letter in strand[1]: temp=[] temp.append(nt2num[letter]) @@ -58,7 +58,7 @@ def single_helix(): strand = inp[1].split(':') com_start=strand[0].split(',') - twist=float(strand[1]) + twist=0.6 posx = float(com_start[0]) posy = float(com_start[1]) @@ -79,7 +79,7 @@ def single_helix(): qrot2=0 qrot3=math.sin(0.5*twist) - for letter in strand[2]: + for letter in strand[1]: temp=[] temp.append(nt2num[letter]) @@ -114,7 +114,7 @@ def duplex(): strand = inp[1].split(':') com_start=strand[0].split(',') - twist=float(strand[1]) + twist=0.6 compstrand=[] comptopo=[] @@ -145,7 +145,7 @@ def duplex(): qrot2=0 qrot3=math.sin(0.5*twist) - for letter in strand[2]: + for letter in strand[1]: temp1=[] temp2=[] @@ -189,7 +189,7 @@ def duplex(): if (len(nucleotide)+1 > strandstart): topology.append([1,len(nucleotide),len(nucleotide)+1]) - comptopo.append([1,len(nucleotide)+len(strand[2]),len(nucleotide)+len(strand[2])+1]) + comptopo.append([1,len(nucleotide)+len(strand[1]),len(nucleotide)+len(strand[1])+1]) nucleotide.append(temp1) compstrand.append(temp2) @@ -208,7 +208,7 @@ def duplex_array(): strand = inp[1].split(':') number=strand[0].split(',') posz1_0 = float(strand[1]) - twist=float(strand[2]) + twist=0.6 nx = int(number[0]) ny = int(number[1]) @@ -249,7 +249,7 @@ def duplex_array(): qrot2=0 qrot3=math.sin(0.5*twist) - for letter in strand[3]: + for letter in strand[2]: temp1=[] temp2=[] @@ -293,7 +293,7 @@ def duplex_array(): if (len(nucleotide)+1 > strandstart): topology.append([1,len(nucleotide),len(nucleotide)+1]) - comptopo.append([1,len(nucleotide)+len(strand[3]),len(nucleotide)+len(strand[3])+1]) + comptopo.append([1,len(nucleotide)+len(strand[2]),len(nucleotide)+len(strand[2])+1]) nucleotide.append(temp1) compstrand.append(temp2) diff --git a/examples/USER/cgdna/util/sequence.txt b/examples/USER/cgdna/util/sequence.txt index fff469c8be6ba2d8a04a0f6cc13d172c419b63e5..8f34319b82ab034681d83f4d0d7178f8b4000f34 100644 --- a/examples/USER/cgdna/util/sequence.txt +++ b/examples/USER/cgdna/util/sequence.txt @@ -1,4 +1,3 @@ -single 0,0,0:0.6:AAAAA -single_helix 0,0,0:0.6:AAAAA -duplex 0,0,0:0.6:AAAAA -duplex_array 10,10:-112.0:0.6:AAAAA +DOUBLE ACGTA + +ACGTA diff --git a/examples/USER/cgdna/util/sequence_simple.txt b/examples/USER/cgdna/util/sequence_simple.txt new file mode 100644 index 0000000000000000000000000000000000000000..81baac84700e731211c8932672e103a3ece89be2 --- /dev/null +++ b/examples/USER/cgdna/util/sequence_simple.txt @@ -0,0 +1,4 @@ +single 0,0,0:AAAAA +single_helix 0,0,0:AAAAA +duplex 0,0,0:AAAAA +duplex_array 10,10:-112.0:AAAAA diff --git a/src/KOKKOS/fix_qeq_reax_kokkos.cpp b/src/KOKKOS/fix_qeq_reax_kokkos.cpp index cf75a0424ef45e289c92437a5b7393ed798489d0..3b8d5a85ea600db699b128f75c59d62a33aa64c2 100644 --- a/src/KOKKOS/fix_qeq_reax_kokkos.cpp +++ b/src/KOKKOS/fix_qeq_reax_kokkos.cpp @@ -82,7 +82,7 @@ void FixQEqReaxKokkos<DeviceType>::init() FixQEqReax::init(); - neighflag = lmp->kokkos->neighflag; + neighflag = lmp->kokkos->neighflag_qeq; int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> diff --git a/src/KOKKOS/kokkos.cpp b/src/KOKKOS/kokkos.cpp index 763c97d69b407ac329842d3732619205d0de7fda..b8be74ac1ed392979f7209f1745e88daab934b62 100644 --- a/src/KOKKOS/kokkos.cpp +++ b/src/KOKKOS/kokkos.cpp @@ -119,6 +119,8 @@ KokkosLMP::KokkosLMP(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) // default settings for package kokkos command neighflag = FULL; + neighflag_qeq = FULL; + neighflag_qeq_set = 0; exchange_comm_classic = 0; forward_comm_classic = 0; exchange_comm_on_host = 0; @@ -152,6 +154,8 @@ void KokkosLMP::accelerator(int narg, char **arg) // defaults neighflag = FULL; + neighflag_qeq = FULL; + neighflag_qeq_set = 0; int newtonflag = 0; double binsize = 0.0; exchange_comm_classic = forward_comm_classic = 0; @@ -169,6 +173,19 @@ void KokkosLMP::accelerator(int narg, char **arg) neighflag = HALF; } else if (strcmp(arg[iarg+1],"n2") == 0) neighflag = N2; else error->all(FLERR,"Illegal package kokkos command"); + if (!neighflag_qeq_set) neighflag_qeq = neighflag; + iarg += 2; + } else if (strcmp(arg[iarg],"neigh/qeq") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal package kokkos command"); + if (strcmp(arg[iarg+1],"full") == 0) neighflag_qeq = FULL; + else if (strcmp(arg[iarg+1],"half") == 0) { + if (num_threads > 1 || ngpu > 0) + neighflag_qeq = HALFTHREAD; + else + neighflag_qeq = HALF; + } else if (strcmp(arg[iarg+1],"n2") == 0) neighflag_qeq = N2; + else error->all(FLERR,"Illegal package kokkos command"); + neighflag_qeq_set = 1; iarg += 2; } else if (strcmp(arg[iarg],"binsize") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal package kokkos command"); diff --git a/src/KOKKOS/kokkos.h b/src/KOKKOS/kokkos.h index 3b91a56ea7e18a2534316fa69fffd32373099ce9..8e28b38cbf45b1e14c2a6e6da7fc59ff0f7b0920 100644 --- a/src/KOKKOS/kokkos.h +++ b/src/KOKKOS/kokkos.h @@ -23,6 +23,8 @@ class KokkosLMP : protected Pointers { public: int kokkos_exists; int neighflag; + int neighflag_qeq; + int neighflag_qeq_set; int exchange_comm_classic; int forward_comm_classic; int exchange_comm_on_host; diff --git a/src/USER-CGDNA/mf_oxdna.h b/src/USER-CGDNA/mf_oxdna.h index b0d3bbe0d3f53d8533201ae1ad4b1fa85df72be0..051cea83f819c5626ca791afb6f4042fdcdb5a75 100644 --- a/src/USER-CGDNA/mf_oxdna.h +++ b/src/USER-CGDNA/mf_oxdna.h @@ -253,8 +253,8 @@ inline double MFOxdna::DF5(double x, double a, double x_ast, } /* ---------------------------------------------------------------------- - test for directionality by projecting base normal n onto delr, - returns 1 if nucleotide a to nucleotide b is 3' to 5', otherwise -1 + test for directionality by projecting base normal n onto delr = a - b, + returns 1 if nucleotide b to nucleotide a is 3' to 5', otherwise -1 ------------------------------------------------------------------------- */ inline double MFOxdna::is_3pto5p(const double * delr, const double * n) {