diff --git a/mrdna/arbdmodel/__init__.py b/mrdna/arbdmodel/__init__.py index 63d03973478890c63bd7e1c84400326a16edd439..51c26bd9d342a05df71d266bf5f90ff58790253e 100644 --- a/mrdna/arbdmodel/__init__.py +++ b/mrdna/arbdmodel/__init__.py @@ -71,6 +71,7 @@ class Parent(): self.dihedrals = [] self.impropers = [] self.exclusions = [] + self.bond_angles = [] self.rigid = False @@ -148,6 +149,13 @@ class Parent(): # for b in (i,j): assert(b in beads) self.exclusions.append( (i,j) ) + def add_bond_angle(self, i,j,k, bond_angle, exclude=False): + assert( len(set((i,j,k))) == 3 ) + ## TODO: how to handle duplicating and cloning bonds + # beads = [b for b in self] + # for b in (i,j): assert(b in beads) + self.bond_angles.append( (i,j,k, bond_angle) ) + def get_restraints(self): ret = [] for c in self.children: @@ -200,6 +208,27 @@ class Parent(): else: return ret + def get_bond_angles(self): + ret = self.bond_angles + for c in self.children: + if isinstance(c,Parent): ret.extend( c.get_bond_angles() ) + if self.remove_duplicate_bonded_terms: + return list(set(ret)) + else: + return ret + + def _get_bond_potentials(self): + bonds = [b for i,j,b,ex in self.get_bonds()] + bondangles1 = [b[1] for i,j,k,b in self.get_bond_angles()] + bondangles2 = [b[2] for i,j,k,b in self.get_bond_angles()] + return list(set( bonds+bondangles1+bondangles2 )) + + def _get_angle_potentials(self): + angles = [b for i,j,k,b in self.get_angles()] + bondangles = [b[0] for i,j,k,b in self.get_bond_angles()] + return list(set( angles+bondangles )) + + ## Removed because prohibitively slow # def remove_duplicate_terms(self): # for key in "bonds angles dihedrals impropers exclusions".split(): @@ -863,6 +892,7 @@ class ArbdModel(PdbModel): self._angle_filename = "%s/%s.angles.txt" % (d, prefix) self._dihedral_filename = "%s/%s.dihedrals.txt" % (d, prefix) self._exclusion_filename = "%s/%s.exculsions.txt" % (d, prefix) + self._bond_angle_filename = "%s/%s.bondangles.txt" % (d, prefix) # self._writeArbdCoordFile( prefix + ".coord.txt" ) self._writeArbdParticleFile( prefix + ".particles.txt" ) @@ -871,6 +901,7 @@ class ArbdModel(PdbModel): self._writeArbdAngleFile() self._writeArbdDihedralFile() self._writeArbdExclusionFile() + self._writeArbdBondAngleFile() self._writeArbdPotentialFiles( prefix, directory = d ) self._writeArbdConf( prefix, numSteps=numSteps, outputPeriod=outputPeriod, restart_file=restart_file ) @@ -1066,13 +1097,13 @@ tabulatedPotential 1 angles = self.get_angles() dihedrals = self.get_dihedrals() exclusions = self.get_exclusions() - + bond_angles = self.get_bond_angles() if len(bonds) > 0: - for b in list(set([b for i,j,b,ex in bonds])): + for b in self._get_bond_potentials(): fh.write("tabulatedBondFile %s\n" % b) if len(angles) > 0: - for b in list(set([b for i,j,k,b in angles])): + for b in self._get_angle_potentials(): fh.write("tabulatedAngleFile %s\n" % b) if len(dihedrals) > 0: @@ -1089,6 +1120,8 @@ tabulatedPotential 1 fh.write("inputDihedrals %s\n" % self._dihedral_filename) if len(exclusions) > 0: fh.write("inputExcludes %s\n" % self._exclusion_filename) + if len(bond_angles) > 0: + fh.write("inputBondAngles %s\n" % self._bond_angle_filename) write_null_dx = False for pt,num in self.getParticleTypesAndCounts(): @@ -1164,7 +1197,7 @@ component "data" value 3 fh.write("RESTRAINT %d %f %f %f %f\n" % tuple(item)) def _writeArbdBondFile( self ): - for b in list( set( [b for i,j,b,ex in self.get_bonds()] ) ): + for b in self._get_bond_potentials(): if type(b) is not str and not isinstance(b, Path): b.write_file() @@ -1177,7 +1210,7 @@ component "data" value 3 fh.write("BOND ADD %d %d %s\n" % item) def _writeArbdAngleFile( self ): - for b in list( set( [b for i,j,k,b in self.get_angles()] ) ): + for b in self._get_angle_potentials(): if type(b) is not str and not isinstance(b, Path): b.write_file() @@ -1202,6 +1235,13 @@ component "data" value 3 item = tuple(int(p.idx) for p in ex) fh.write("EXCLUDE %d %d\n" % item) + def _writeArbdBondAngleFile( self ): + if len(self.bond_angles) > 0: + with open(self._bond_angle_filename,'w') as fh: + for b in self.get_bond_angles(): + item = tuple([p.idx for p in b[:-1]] + [str(p) for p in b[-1]]) + fh.write("BONDANGLE %d %d %d %s %s %s\n" % item) + def dimensions_from_structure( self, padding_factor=1.5, isotropic=False ): ## TODO: cache coordinates using numpy arrays for quick min/max raise(NotImplementedError) diff --git a/mrdna/arbdmodel/nonbonded.py b/mrdna/arbdmodel/nonbonded.py index f7de00d677b87f554cb1e7bb276ec8a7edd099bb..a9339882acabb531042431c72774793dc2822b6d 100644 --- a/mrdna/arbdmodel/nonbonded.py +++ b/mrdna/arbdmodel/nonbonded.py @@ -58,12 +58,13 @@ class TabulatedPotential(NonbondedScheme): ## Bonded potentials class BasePotential(): - def __init__(self, r0, rRange=(0,50), resolution=0.1, maxForce=None, max_potential=None, prefix="potentials/"): + def __init__(self, r0, rRange=(0,50), resolution=0.1, maxForce=None, max_potential=None, zero="min", prefix="potentials/"): self.r0 = r0 self.rRange = rRange self.resolution = resolution self.maxForce = maxForce self.prefix = prefix + self.zero = zero self.periodic = False self.type_ = "None" self.max_potential = max_potential @@ -111,15 +112,16 @@ class BasePotential(): u[0] = 0 u[1:] = np.cumsum(f*np.diff(r)) - u = u - np.min(u) + if self.zero == "min": + u = u - np.min(u) np.savetxt( self.filename(), np.array([r, u]).T, fmt="%f" ) class HarmonicPotential(BasePotential): - def __init__(self, k, r0, rRange, resolution, maxForce, max_potential, prefix, correct_geometry=False): + def __init__(self, k, r0, rRange, resolution, maxForce, max_potential, zero="min", correct_geometry=False, prefix='./'): self.k = k self.kscale_ = None - BasePotential.__init__(self, r0, rRange, resolution, maxForce, max_potential, prefix) + BasePotential.__init__(self, r0, rRange, resolution, maxForce, max_potential, zero, prefix) def filename(self): return "%s%s-%.3f-%.3f.dat" % (self.prefix, self.type_, @@ -143,8 +145,8 @@ class HarmonicPotential(BasePotential): # self.kscale_ = 1.0 class HarmonicBond(HarmonicPotential): - def __init__(self, k, r0, rRange=(0,50), resolution=0.1, maxForce=None, max_potential=None, prefix="potentials/", correct_geometry=False, temperature=295): - HarmonicPotential.__init__(self, k, r0, rRange, resolution, maxForce, max_potential, prefix) + def __init__(self, k, r0, rRange=(0,50), resolution=0.1, maxForce=None, max_potential=None, prefix="potentials/", zero="min", correct_geometry=False, temperature=295): + HarmonicPotential.__init__(self, k, r0, rRange, resolution, maxForce, max_potential, zero=zero, correct_geometry=correct_geometry, prefix=prefix) self.type_ = "gbond" if correct_geometry else "bond" self.kscale_ = 1.0 self.correct_geometry = correct_geometry @@ -161,22 +163,22 @@ class HarmonicBond(HarmonicPotential): class HarmonicAngle(HarmonicPotential): - def __init__(self, k, r0, rRange=(0,181), resolution=0.1, maxForce=None, max_potential=None, prefix="potentials/"): - HarmonicPotential.__init__(self, k, r0, rRange, resolution, maxForce, max_potential, prefix) + def __init__(self, k, r0, rRange=(0,181), resolution=0.1, maxForce=None, max_potential=None, zero="min", prefix="potentials/"): + HarmonicPotential.__init__(self, k, r0, rRange, resolution, maxForce, max_potential, zero=zero, prefix=prefix) self.type_ = "angle" self.kscale_ = (180.0/np.pi)**2 class HarmonicDihedral(HarmonicPotential): - def __init__(self, k, r0, rRange=(-180,180), resolution=0.1, maxForce=None, max_potential=None, prefix="potentials/"): - HarmonicPotential.__init__(self, k, r0, rRange, resolution, maxForce, max_potential, prefix) + def __init__(self, k, r0, rRange=(-180,180), resolution=0.1, maxForce=None, max_potential=None, zero="min", prefix="potentials/"): + HarmonicPotential.__init__(self, k, r0, rRange, resolution, maxForce, max_potential, zero=zero, prefix=prefix) self.periodic = True self.type_ = "dihedral" self.kscale_ = (180.0/np.pi)**2 class WLCSKBond(BasePotential): """ ## https://aip.scitation.org/doi/full/10.1063/1.4968020 """ - def __init__(self, d, lp, kT, rRange=(0,50), resolution=0.02, maxForce=100, max_potential=None, prefix="potentials/"): - BasePotential.__init__(self, 0, rRange, resolution, maxForce, max_potential, prefix) + def __init__(self, d, lp, kT, rRange=(0,50), resolution=0.02, maxForce=100, max_potential=None, zero="min", prefix="potentials/"): + BasePotential.__init__(self, 0, rRange, resolution, maxForce, max_potential, zero, prefix) self.type_ = "wlcbond" self.d = d # separation self.lp = lp # persistence length @@ -213,8 +215,8 @@ class WLCSKBond(BasePotential): class WLCSKAngle(BasePotential): ## https://aip.scitation.org/doi/full/10.1063/1.4968020 - def __init__(self, d, lp, kT, rRange=(0,181), resolution=0.5, maxForce=None, max_potential=None, prefix="potentials/"): - BasePotential.__init__(self, 180, rRange, resolution, maxForce, max_potential, prefix) + def __init__(self, d, lp, kT, rRange=(0,181), resolution=0.5, maxForce=None, max_potential=None, zero="min", prefix="potentials/"): + BasePotential.__init__(self, 180, rRange, resolution, maxForce, max_potential, zero, prefix) self.type_ = "wlcangle" self.d = d # separation self.lp = lp # persistence length