htpolynet 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- htpolynet/__init__.py +2 -0
- htpolynet/analysis/__init__.py +0 -0
- htpolynet/analysis/analyze.py +256 -0
- htpolynet/analysis/plot.py +588 -0
- htpolynet/analysis/postsim.py +444 -0
- htpolynet/analysis/utils.py +399 -0
- htpolynet/cli.py +488 -0
- htpolynet/core/__init__.py +0 -0
- htpolynet/core/bondtemplate.py +112 -0
- htpolynet/core/configuration.py +83 -0
- htpolynet/core/coordinates.py +644 -0
- htpolynet/core/molecule.py +998 -0
- htpolynet/core/projectfilesystem.py +616 -0
- htpolynet/core/runtime.py +774 -0
- htpolynet/core/topocoord.py +2044 -0
- htpolynet/core/topology.py +1138 -0
- htpolynet/cure/__init__.py +0 -0
- htpolynet/cure/chain.py +135 -0
- htpolynet/cure/curecontroller.py +746 -0
- htpolynet/cure/expandreactions.py +294 -0
- htpolynet/cure/reaction.py +280 -0
- htpolynet/external/__init__.py +0 -0
- htpolynet/external/ambertools.py +97 -0
- htpolynet/external/command.py +73 -0
- htpolynet/external/gromacs.py +308 -0
- htpolynet/external/slurm.py +111 -0
- htpolynet/external/software.py +183 -0
- htpolynet/geometry/__init__.py +0 -0
- htpolynet/geometry/bondlist.py +205 -0
- htpolynet/geometry/lattice.py +32 -0
- htpolynet/geometry/linkcell.py +210 -0
- htpolynet/geometry/matrix4.py +110 -0
- htpolynet/geometry/ring.py +274 -0
- htpolynet/io/__init__.py +6 -0
- htpolynet/io/gro.py +195 -0
- htpolynet/io/mol2.py +210 -0
- htpolynet/io/pdb.py +157 -0
- htpolynet/resources/README.md +20 -0
- htpolynet/resources/__init__.py +0 -0
- htpolynet/resources/cfg/DGE-PAC-hi.yaml +115 -0
- htpolynet/resources/cfg/DGE-PAC-lo.yaml +115 -0
- htpolynet/resources/cfg/FDE-DFDA-hi.yaml +116 -0
- htpolynet/resources/cfg/FDE-DFDA-lo.yaml +116 -0
- htpolynet/resources/cfg/GMASTY-hi.yaml +158 -0
- htpolynet/resources/cfg/GMASTY-lo.yaml +158 -0
- htpolynet/resources/cfg/README.md +1 -0
- htpolynet/resources/cfg/STY.yaml +23 -0
- htpolynet/resources/cfg/pMSTY-hi.yaml +101 -0
- htpolynet/resources/cfg/pMSTY-lo.yaml +101 -0
- htpolynet/resources/cfg/pSTY-hi.yaml +101 -0
- htpolynet/resources/cfg/pSTY-lo.yaml +101 -0
- htpolynet/resources/example_depot/0-liquid-styrene.sh +134 -0
- htpolynet/resources/example_depot/0-liquid-styrene.tgz +0 -0
- htpolynet/resources/example_depot/1-polystyrene.sh +202 -0
- htpolynet/resources/example_depot/1-polystyrene.tgz +0 -0
- htpolynet/resources/example_depot/2-bisgma-styrene-thermoset.sh +353 -0
- htpolynet/resources/example_depot/2-bisgma-styrene-thermoset.tgz +0 -0
- htpolynet/resources/example_depot/3-pacm-dgeba-epoxy-thermoset.sh +242 -0
- htpolynet/resources/example_depot/3-pacm-dgeba-epoxy-thermoset.tgz +0 -0
- htpolynet/resources/example_depot/4-dfda-fde-epoxy-thermoset.sh +216 -0
- htpolynet/resources/example_depot/4-dfda-fde-epoxy-thermoset.tgz +0 -0
- htpolynet/resources/mdp/README.md +1 -0
- htpolynet/resources/mdp/drag-min.mdp +13 -0
- htpolynet/resources/mdp/drag-npt.mdp +36 -0
- htpolynet/resources/mdp/drag-nvt.mdp +31 -0
- htpolynet/resources/mdp/min.mdp +14 -0
- htpolynet/resources/mdp/npt.mdp +37 -0
- htpolynet/resources/mdp/nvt.mdp +29 -0
- htpolynet/resources/mdp/relax-min.mdp +13 -0
- htpolynet/resources/mdp/relax-npt.mdp +37 -0
- htpolynet/resources/mdp/relax-nvt.mdp +31 -0
- htpolynet/resources/mdp/single-molecule-min.mdp +12 -0
- htpolynet/resources/mdp/single-molecule-nvt.mdp +25 -0
- htpolynet/resources/molecules/inputs/DFA.pdb +62 -0
- htpolynet/resources/molecules/inputs/DGE.mol2 +115 -0
- htpolynet/resources/molecules/inputs/EMB.mol2 +50 -0
- htpolynet/resources/molecules/inputs/FDE.pdb +72 -0
- htpolynet/resources/molecules/inputs/GMA.mol2 +163 -0
- htpolynet/resources/molecules/inputs/PAC.mol2 +91 -0
- htpolynet/resources/molecules/inputs/STY.mol2 +44 -0
- htpolynet/resources/molecules/make-monomers.sh +64 -0
- htpolynet/resources/molecules/pics/DFA.png +0 -0
- htpolynet/resources/molecules/pics/DGE.png +0 -0
- htpolynet/resources/molecules/pics/EMB.png +0 -0
- htpolynet/resources/molecules/pics/FDE.png +0 -0
- htpolynet/resources/molecules/pics/GMA.png +0 -0
- htpolynet/resources/molecules/pics/PAC.png +0 -0
- htpolynet/resources/molecules/pics/STY.png +0 -0
- htpolynet/resources/molecules/sample-inputs/DFA.pdb +62 -0
- htpolynet/resources/molecules/sample-inputs/DGE.mol2 +115 -0
- htpolynet/resources/molecules/sample-inputs/EMB.mol2 +50 -0
- htpolynet/resources/molecules/sample-inputs/FDE.pdb +72 -0
- htpolynet/resources/molecules/sample-inputs/GMA.mol2 +163 -0
- htpolynet/resources/molecules/sample-inputs/PAC.mol2 +91 -0
- htpolynet/resources/molecules/sample-inputs/STY.mol2 +44 -0
- htpolynet/resources/tcl/readbonds.tcl +32 -0
- htpolynet/resources/tcl/readgrx.tcl +46 -0
- htpolynet/resources/tcl/render.tcl +74 -0
- htpolynet/utils/__init__.py +0 -0
- htpolynet/utils/banner.py +34 -0
- htpolynet/utils/checkpoint.py +85 -0
- htpolynet/utils/dataframetools.py +92 -0
- htpolynet/utils/inputcheck.py +49 -0
- htpolynet/utils/logsetup.py +44 -0
- htpolynet/utils/stringthings.py +39 -0
- htpolynet-2.0.0.dist-info/METADATA +78 -0
- htpolynet-2.0.0.dist-info/RECORD +110 -0
- htpolynet-2.0.0.dist-info/WHEEL +4 -0
- htpolynet-2.0.0.dist-info/entry_points.txt +2 -0
- htpolynet-2.0.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
"""Handles the postsim subcommand.
|
|
2
|
+
|
|
3
|
+
Author: Cameron F. Abrams <cfa22@drexel.edu>
|
|
4
|
+
"""
|
|
5
|
+
import json
|
|
6
|
+
import logging
|
|
7
|
+
import os
|
|
8
|
+
import shutil
|
|
9
|
+
|
|
10
|
+
import yaml
|
|
11
|
+
|
|
12
|
+
import numpy as np
|
|
13
|
+
|
|
14
|
+
from ..analysis.plot import scatter
|
|
15
|
+
from ..core import projectfilesystem as pfs
|
|
16
|
+
from ..core.configuration import Configuration
|
|
17
|
+
from ..core.topocoord import TopoCoord
|
|
18
|
+
from ..external import software as software
|
|
19
|
+
from ..external.gromacs import mdp_get, mdp_modify, gmx_energy_trace
|
|
20
|
+
from ..utils.logsetup import setup_logging
|
|
21
|
+
|
|
22
|
+
logger=logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
class PostSimMD:
|
|
25
|
+
""" Generic class for handling post-cure md simulations; this one just does simple NPT MD equilibration;
|
|
26
|
+
Classes that inherit from this class should define their own default_params and build_npt
|
|
27
|
+
"""
|
|
28
|
+
default_params={
|
|
29
|
+
'subdir': f'{pfs.Dirs.postsim}/equilibrate',
|
|
30
|
+
'input_top': f'{pfs.Dirs.systems_final}/final.top',
|
|
31
|
+
'input_gro': f'{pfs.Dirs.systems_final}/final.gro',
|
|
32
|
+
'input_grx': f'{pfs.Dirs.systems_final}/final.grx',
|
|
33
|
+
'gromacs' : {
|
|
34
|
+
'gmx': 'gmx',
|
|
35
|
+
'mdrun': 'gmx mdrun',
|
|
36
|
+
'options': '-quiet -nobackup',
|
|
37
|
+
'mdrun_single_molecule': 'gmx mdrun mdrun'
|
|
38
|
+
},
|
|
39
|
+
'ps': 1000,
|
|
40
|
+
'T': 300,
|
|
41
|
+
'P':1,
|
|
42
|
+
'output_deffnm': 'equilibrate',
|
|
43
|
+
'traces': ['Temperature','Density','Volume'],
|
|
44
|
+
'scatter': ('time(ps)',['Density'],'rho_v_ns.png')
|
|
45
|
+
}
|
|
46
|
+
def __init__(self,indict,strict=True):
|
|
47
|
+
self.params={}
|
|
48
|
+
for p,v in self.default_params.items():
|
|
49
|
+
self.params[p]=indict.get(p,v)
|
|
50
|
+
for p,v in indict.items():
|
|
51
|
+
if not p in self.default_params:
|
|
52
|
+
if strict:
|
|
53
|
+
logger.info(f'Ignoring directive \'{p}\' in yaml input file')
|
|
54
|
+
else:
|
|
55
|
+
self.params[p]=v
|
|
56
|
+
|
|
57
|
+
def do(self,mdp_pfx='npt',**gromacs_dict):
|
|
58
|
+
"""Handles executing the postsim MD simulation.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
mdp_pfx (str): filename prefix for output files, defaults to 'npt'
|
|
62
|
+
"""
|
|
63
|
+
p=self.params
|
|
64
|
+
logger.info(f'do {p}')
|
|
65
|
+
# if a gromacs dict is passed in, assume this overrides the one read in from the file
|
|
66
|
+
if gromacs_dict:
|
|
67
|
+
software.set_gmx_preferences(gromacs_dict)
|
|
68
|
+
else:
|
|
69
|
+
software.set_gmx_preferences(p['gromacs'])
|
|
70
|
+
logger.info(f'going to {p["subdir"]}')
|
|
71
|
+
pfs.go_to(p['subdir'])
|
|
72
|
+
for input_file in ['input_top','input_gro','input_grx']:
|
|
73
|
+
srcnm=os.path.join(pfs.proj(),p[input_file])
|
|
74
|
+
shutil.copy(srcnm,'.')
|
|
75
|
+
local_top=os.path.basename(p['input_top'])
|
|
76
|
+
local_gro=os.path.basename(p['input_gro'])
|
|
77
|
+
local_grx=os.path.basename(p['input_grx'])
|
|
78
|
+
TC=TopoCoord(topfilename=local_top,grofilename=local_gro,grxfilename=local_grx)
|
|
79
|
+
logger.info(f'{TC.Coordinates.A.shape[0]} atoms {TC.Topology.total_mass(units="gromacs"):.2f} amu')
|
|
80
|
+
box=TC.Coordinates.box
|
|
81
|
+
pfs.checkout(pfs.Dirs.mdp_file('npt'))
|
|
82
|
+
os.rename('npt.mdp',f'{mdp_pfx}.mdp')
|
|
83
|
+
self.build_mdp(f'{mdp_pfx}.mdp',box=box)
|
|
84
|
+
msg=TC.grompp_and_mdrun(out=p['output_deffnm'],mdp=mdp_pfx,quiet=False,mylogger=logger.info,**gromacs_dict)
|
|
85
|
+
df=gmx_energy_trace(p['output_deffnm'],p['traces'])
|
|
86
|
+
use_scatter=p['scatter']
|
|
87
|
+
temp_x=None
|
|
88
|
+
temp_y=None
|
|
89
|
+
scat_file=use_scatter[2]
|
|
90
|
+
for sznm in ['Box-X','Box-Y','Box-Z']:
|
|
91
|
+
if sznm in p['traces']:
|
|
92
|
+
L0=box[0][0] if sznm=='Box-X' else box[1][1] if sznm=='Box-Y' else box[2][2]
|
|
93
|
+
temp_x=f'{sznm}-strain'
|
|
94
|
+
df[temp_x]=df[sznm]/L0-1.0
|
|
95
|
+
for sznm in ['Pres-XX','Pres-YY','Pres-ZZ']:
|
|
96
|
+
if sznm in p['traces']:
|
|
97
|
+
df[f'{sznm}-stress']=df[sznm]*(-1)
|
|
98
|
+
temp_y=[f'{sznm}-stress']
|
|
99
|
+
if temp_x and temp_y:
|
|
100
|
+
use_scatter=(temp_x,temp_y,scat_file)
|
|
101
|
+
df.to_csv(f'{p["output_deffnm"]}.csv',header=True,index=False)
|
|
102
|
+
scatter(df,*use_scatter)
|
|
103
|
+
logger.info(f'Final coordinates in {p["output_deffnm"]}.gro')
|
|
104
|
+
logger.info(f'Traces saved in {p["output_deffnm"]}.csv')
|
|
105
|
+
|
|
106
|
+
def build_mdp(self,mdpname,**kwargs):
|
|
107
|
+
"""Builds the GROMACS mdp file required for an NPT equilibration.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
mdpname (str): name of mdp file
|
|
111
|
+
"""
|
|
112
|
+
params=self.params
|
|
113
|
+
timestep=float(mdp_get(mdpname,'dt'))
|
|
114
|
+
duration=params['ps']
|
|
115
|
+
nsteps=int(duration/timestep)
|
|
116
|
+
mod_dict={
|
|
117
|
+
'ref_t':params['T'],
|
|
118
|
+
'ref_p':params['P'],
|
|
119
|
+
'gen-temp':params['T'],
|
|
120
|
+
'gen-vel':'yes',
|
|
121
|
+
'nsteps':nsteps,
|
|
122
|
+
'tcoupl':'v-rescale','tau_t':0.5
|
|
123
|
+
}
|
|
124
|
+
mdp_modify(mdpname,mod_dict)
|
|
125
|
+
|
|
126
|
+
class PostSimAnneal(PostSimMD):
|
|
127
|
+
""" a class to handle temperature annealing MD simulation
|
|
128
|
+
"""
|
|
129
|
+
default_params={
|
|
130
|
+
'subdir': f'{pfs.Dirs.postsim}/anneal',
|
|
131
|
+
'input_top': f'{pfs.Dirs.systems_final}/final.top',
|
|
132
|
+
'input_gro': f'{pfs.Dirs.systems_final}/final.gro',
|
|
133
|
+
'input_grx': f'{pfs.Dirs.systems_final}/final.grx',
|
|
134
|
+
'gromacs' : {
|
|
135
|
+
'gmx': 'gmx',
|
|
136
|
+
'mdrun': 'gmx mdrun',
|
|
137
|
+
'options': '-quiet -nobackup',
|
|
138
|
+
'mdrun_single_molecule': 'gmx mdrun'
|
|
139
|
+
},
|
|
140
|
+
'output_deffnm':'anneal',
|
|
141
|
+
'traces': ['Temperature','Density','Volume'],
|
|
142
|
+
'scatter': ('time(ps)',['Density'],'rho_v_ns.png'),
|
|
143
|
+
'T0': 300,
|
|
144
|
+
'T1': 600,
|
|
145
|
+
'ncycles': 1,
|
|
146
|
+
'T0_to_T1_ps': 1000,
|
|
147
|
+
'T1_ps': 1000,
|
|
148
|
+
'T1_to_T0_ps': 1000,
|
|
149
|
+
'T0_ps': 1000,
|
|
150
|
+
'P':1
|
|
151
|
+
}
|
|
152
|
+
def build_mdp(self,mdpname,**kwargs):
|
|
153
|
+
"""Builds the GROMACS mdp file required for an annealing MD simulation.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
mdpname (str): name of mdp file
|
|
157
|
+
"""
|
|
158
|
+
params=self.params
|
|
159
|
+
timestep=float(mdp_get(mdpname,'dt'))
|
|
160
|
+
timeints=[0.0,params['T0_to_T1_ps'],params['T1_ps'],params['T1_to_T0_ps'],params['T0_ps']]
|
|
161
|
+
timepoints=[0.0]
|
|
162
|
+
temppoints=[params['T0'],params['T1'],params['T1'],params['T0'],params['T0']]
|
|
163
|
+
for i in range(1,len(timeints)):
|
|
164
|
+
timepoints.append(timepoints[-1]+timeints[i])
|
|
165
|
+
duration=timepoints[-1]
|
|
166
|
+
nsteps=int(duration/timestep)*params['ncycles']
|
|
167
|
+
mod_dict={
|
|
168
|
+
'ref_t':params['T0'],
|
|
169
|
+
'ref_p':params['P'],
|
|
170
|
+
'gen-temp':params['T0'],
|
|
171
|
+
'gen-vel':'yes',
|
|
172
|
+
'annealing-npoints':len(timepoints),
|
|
173
|
+
'annealing-temp':' '.join([str(x) for x in temppoints]),
|
|
174
|
+
'annealing-time':' '.join([str(x) for x in timepoints]),
|
|
175
|
+
'annealing':'periodic' if params['ncycles']>1 else 'single',
|
|
176
|
+
'nsteps':nsteps,
|
|
177
|
+
'tcoupl':'v-rescale','tau_t':0.5
|
|
178
|
+
}
|
|
179
|
+
mdp_modify(mdpname,mod_dict)
|
|
180
|
+
|
|
181
|
+
class PostSimLadder(PostSimMD):
|
|
182
|
+
""" a class to handle a temperature-ladder MD simulation
|
|
183
|
+
"""
|
|
184
|
+
default_params={
|
|
185
|
+
'subdir': f'{pfs.Dirs.postsim}/ladder',
|
|
186
|
+
'input_top': f'{pfs.Dirs.systems_final}/final.top',
|
|
187
|
+
'input_gro': f'{pfs.Dirs.systems_final}/final.gro',
|
|
188
|
+
'input_grx': f'{pfs.Dirs.systems_final}/final.grx',
|
|
189
|
+
'gromacs' : {
|
|
190
|
+
'gmx': 'gmx',
|
|
191
|
+
'mdrun': 'gmx mdrun',
|
|
192
|
+
'options': '-quiet -nobackup',
|
|
193
|
+
'mdrun_single_molecule': 'gmx mdrun mdrun'
|
|
194
|
+
},
|
|
195
|
+
'output_deffnm':'ladder',
|
|
196
|
+
'traces': ['Temperature','Density','Volume'],
|
|
197
|
+
'scatter': ('time(ps)',['Density'],'rho_v_ns.png'),
|
|
198
|
+
'Tlo':300.0,
|
|
199
|
+
'Thi':600.0,
|
|
200
|
+
'deltaT':5,
|
|
201
|
+
'ps_per_run':1000,
|
|
202
|
+
'ps_per_rise':1000,
|
|
203
|
+
'warmup_ps':5000,
|
|
204
|
+
'P':1
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
def build_mdp(self,mdpname,**kwargs):
|
|
208
|
+
"""Builds the GROMACS mdp file required for a temperature-ladder MD simulation.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
mdpname (str): name of mdp file
|
|
212
|
+
"""
|
|
213
|
+
params=self.params
|
|
214
|
+
timestep=float(mdp_get(mdpname,'dt'))
|
|
215
|
+
Tdomain=params['Thi']-params['Tlo']
|
|
216
|
+
nSteps=int(Tdomain/np.abs(params['deltaT']))+1
|
|
217
|
+
T0=params['Tlo'] if params['deltaT']>0.0 else params['Thi']
|
|
218
|
+
T1=params['Thi'] if params['deltaT']>0.0 else params['Tlo']
|
|
219
|
+
Tladder=np.linspace(T0,T1,nSteps)
|
|
220
|
+
timepoints=[0.0,params['warmup_ps']]
|
|
221
|
+
temppoints=[T0,T0]
|
|
222
|
+
for i in range(nSteps):
|
|
223
|
+
cT=Tladder[i]
|
|
224
|
+
timepoints.append(timepoints[-1]+params['ps_per_rise'])
|
|
225
|
+
temppoints.append(cT)
|
|
226
|
+
timepoints.append(timepoints[-1]+params['ps_per_run'])
|
|
227
|
+
temppoints.append(cT)
|
|
228
|
+
duration=timepoints[-1]
|
|
229
|
+
nMDsteps=int(duration/timestep)
|
|
230
|
+
mod_dict={
|
|
231
|
+
'ref_t':T0,
|
|
232
|
+
'ref_p':params['P'],
|
|
233
|
+
'gen-temp':T0,
|
|
234
|
+
'gen-vel':'yes',
|
|
235
|
+
'annealing-npoints':len(timepoints),
|
|
236
|
+
'annealing-temp':' '.join([str(x) for x in temppoints]),
|
|
237
|
+
'annealing-time':' '.join([str(x) for x in timepoints]),
|
|
238
|
+
'annealing':'single',
|
|
239
|
+
'nsteps':nMDsteps,
|
|
240
|
+
'tcoupl':'v-rescale','tau_t':0.5
|
|
241
|
+
}
|
|
242
|
+
mdp_modify(mdpname,mod_dict)
|
|
243
|
+
|
|
244
|
+
class PostSimDeform(PostSimMD):
|
|
245
|
+
""" a class to handle a uniaxial deformation MD simulation
|
|
246
|
+
"""
|
|
247
|
+
default_params={
|
|
248
|
+
'subdir': f'{pfs.Dirs.postsim}/deform-x',
|
|
249
|
+
'input_top': f'{pfs.Dirs.systems_final}/final.top',
|
|
250
|
+
'input_gro': f'{pfs.Dirs.postsim}/equilibrate/equilibrate.gro',
|
|
251
|
+
'input_grx': f'{pfs.Dirs.systems_final}/final.grx',
|
|
252
|
+
'gromacs' : {
|
|
253
|
+
'gmx': 'gmx',
|
|
254
|
+
'mdrun': 'gmx mdrun',
|
|
255
|
+
'options': '-quiet -nobackup',
|
|
256
|
+
'mdrun_single_molecule': 'gmx mdrun mdrun'
|
|
257
|
+
},
|
|
258
|
+
'output_deffnm':'deform-x',
|
|
259
|
+
'traces': ['Box-X','Pres-XX'],
|
|
260
|
+
'scatter': ('Box-X',['Pres-XX'],'tension_v_xlength.png'),
|
|
261
|
+
'direction':'x',
|
|
262
|
+
'T':300.0,
|
|
263
|
+
'P':1.0,
|
|
264
|
+
'ps':1000,
|
|
265
|
+
'edot': 0.001 # strain rate in ps^-1
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
def build_mdp(self,mdpname,**kwargs):
|
|
269
|
+
"""Builds the GROMACS mdp file required for a uniaxial deformation MD simulation.
|
|
270
|
+
|
|
271
|
+
Args:
|
|
272
|
+
mdpname (str): name of mdp file
|
|
273
|
+
"""
|
|
274
|
+
params=self.params
|
|
275
|
+
timestep=float(mdp_get(mdpname,'dt'))
|
|
276
|
+
duration=params['ps']
|
|
277
|
+
nsteps=int(duration/timestep)
|
|
278
|
+
box=kwargs.get('box',np.array([[0.0,0.0,0.0],[0.0,0.0,0.0],[0.0,0.0,0.0]]))
|
|
279
|
+
edot=params.get('edot',0.0)
|
|
280
|
+
direction=params.get('direction','x')
|
|
281
|
+
mod_dict={
|
|
282
|
+
'ref_t':params['T'],
|
|
283
|
+
'ref_p':params['P'],
|
|
284
|
+
'gen-temp':params['T'],
|
|
285
|
+
'gen-vel':'yes',
|
|
286
|
+
'tcoupl':'v-rescale',
|
|
287
|
+
'nsteps': nsteps,
|
|
288
|
+
'rlist': 1.2,
|
|
289
|
+
'rcoulomb': 1.2,
|
|
290
|
+
'rvdw': 1.2,
|
|
291
|
+
'tau_t':0.5,
|
|
292
|
+
'tau_p':1.0,
|
|
293
|
+
'refcoord_scaling': 'com',
|
|
294
|
+
'pcoupltype': 'anisotropic'
|
|
295
|
+
}
|
|
296
|
+
if direction=='x':
|
|
297
|
+
strain_vel=box[0][0]*edot
|
|
298
|
+
mod_dict['ref_p']='0.0 1.0 1.0 0 0 0'
|
|
299
|
+
mod_dict['compressibility']='0.0 4.5e-5 4.5e-5 0 0 0'
|
|
300
|
+
mod_dict['deform']=f'{strain_vel:.3e} 0 0 0 0 0'
|
|
301
|
+
params['output_deffnm'] = 'deform-x'
|
|
302
|
+
params['traces']=['Box-X','Pres-XX']
|
|
303
|
+
params['scatter']=('Box-X',['Pres-XX'],'tension_v_xlength.png')
|
|
304
|
+
elif direction=='y':
|
|
305
|
+
strain_vel=box[1][1]*edot
|
|
306
|
+
mod_dict['ref_p']='1.0 0.0 1.0 0 0 0'
|
|
307
|
+
mod_dict['compressibility']='4.5e-5 0.0 4.5e-5 0 0 0'
|
|
308
|
+
mod_dict['deform']=f'0 {strain_vel:.3e} 0 0 0 0'
|
|
309
|
+
params['output_deffnm'] = 'deform-y'
|
|
310
|
+
params['traces']=['Box-Y','Pres-YY']
|
|
311
|
+
params['scatter']=('Box-Y',['Pres-YY'],'tension_v_ylength.png')
|
|
312
|
+
elif direction=='z':
|
|
313
|
+
strain_vel=box[2][2]*edot
|
|
314
|
+
mod_dict['ref_p']='1.0 1.0 0.0 0 0 0'
|
|
315
|
+
mod_dict['compressibility']='4.5e-5 4.5e-5 0.0 0 0 0'
|
|
316
|
+
mod_dict['deform']=f'0 0 {strain_vel:.3e} 0 0 0'
|
|
317
|
+
params['output_deffnm'] = 'deform-z'
|
|
318
|
+
params['traces']=['Box-Z','Pres-ZZ']
|
|
319
|
+
params['scatter']=('Box-Z',['Pres-ZZ'],'tension_v_zlength.png')
|
|
320
|
+
else:
|
|
321
|
+
logger.error(f'Bad direction for uniaxial strain {direction}')
|
|
322
|
+
|
|
323
|
+
mdp_modify(mdpname,mod_dict)
|
|
324
|
+
|
|
325
|
+
class PostsimConfiguration:
|
|
326
|
+
""" handles reading and parsing a postcure simulation input config file.
|
|
327
|
+
Config file format
|
|
328
|
+
|
|
329
|
+
- { key1: {<paramdict>}}
|
|
330
|
+
- { key2: {<paramdict>}}
|
|
331
|
+
|
|
332
|
+
...
|
|
333
|
+
|
|
334
|
+
The config file is a list of single-element dictionaries, whose single keyword
|
|
335
|
+
indicates the type of MD simulation to be run; simulations are run in the order
|
|
336
|
+
they appear in the config file.
|
|
337
|
+
|
|
338
|
+
Currently allowed simulation types:
|
|
339
|
+
|
|
340
|
+
- 'equilibrate': simple NPT equilibration;
|
|
341
|
+
- 'anneal': simple simulated annealing;
|
|
342
|
+
- 'ladder': temperature ladder;
|
|
343
|
+
- 'deform: constant strain-rate uniaxial deformation;
|
|
344
|
+
|
|
345
|
+
"""
|
|
346
|
+
default_classes={'equilibrate':PostSimMD,'anneal':PostSimAnneal,'ladder':PostSimLadder,'deform':PostSimDeform}
|
|
347
|
+
def __init__(self):
|
|
348
|
+
self.cfgFile=''
|
|
349
|
+
self.baselist=[]
|
|
350
|
+
self.stagelist=[]
|
|
351
|
+
|
|
352
|
+
@classmethod
|
|
353
|
+
def read(cls,filename,parse=True,**kwargs):
|
|
354
|
+
"""Generates a new PostsimConfiguration object by reading in the JSON or YAML file indicated by filename.
|
|
355
|
+
|
|
356
|
+
Args:
|
|
357
|
+
filename (str): name of file from which to read new PostsimConfiguration object
|
|
358
|
+
parse (bool): if True, parse the input configuration file, defaults to True
|
|
359
|
+
|
|
360
|
+
Raises:
|
|
361
|
+
Exception: if extension of filename is not '.json' or '.yaml' or '.yml'
|
|
362
|
+
|
|
363
|
+
Returns:
|
|
364
|
+
PostsimConfiguration: a new PostsimConfiguration object
|
|
365
|
+
"""
|
|
366
|
+
basename,extension=os.path.splitext(filename)
|
|
367
|
+
if extension=='.json':
|
|
368
|
+
return cls._read_json(filename,parse,**kwargs)
|
|
369
|
+
elif extension=='.yaml' or extension=='.yml':
|
|
370
|
+
return cls._read_yaml(filename,parse,**kwargs)
|
|
371
|
+
else:
|
|
372
|
+
raise Exception(f'Unknown config file extension {extension}')
|
|
373
|
+
|
|
374
|
+
@classmethod
|
|
375
|
+
def _read_json(cls,filename,parse=True,**kwargs):
|
|
376
|
+
"""Creates a new PostsimConfiguration object by reading from JSON input.
|
|
377
|
+
|
|
378
|
+
Args:
|
|
379
|
+
filename (str): name of JSON file
|
|
380
|
+
parse (bool): if True, parse the JSON data, defaults to True
|
|
381
|
+
|
|
382
|
+
Returns:
|
|
383
|
+
PostsimConfiguration: a new PostsimConfiguration object
|
|
384
|
+
"""
|
|
385
|
+
inst=cls()
|
|
386
|
+
inst.cfgFile=filename
|
|
387
|
+
with open(filename,'r') as f:
|
|
388
|
+
inst.baselist=json.load(f)
|
|
389
|
+
assert type(inst.baselist)==list,f'Poorly formatted {filename}'
|
|
390
|
+
if parse: inst.parse(**kwargs)
|
|
391
|
+
return inst
|
|
392
|
+
|
|
393
|
+
@classmethod
|
|
394
|
+
def _read_yaml(cls,filename,parse=True,**kwargs):
|
|
395
|
+
"""Creates a new PostsimConfiguration object by reading from YAML input.
|
|
396
|
+
|
|
397
|
+
Args:
|
|
398
|
+
filename (str): name of YAML file
|
|
399
|
+
parse (bool): if True, parse the YAML data, defaults to True
|
|
400
|
+
|
|
401
|
+
Returns:
|
|
402
|
+
PostsimConfiguration: a new PostsimConfiguration object
|
|
403
|
+
"""
|
|
404
|
+
inst=cls()
|
|
405
|
+
inst.cfgFile=filename
|
|
406
|
+
with open(filename,'r') as f:
|
|
407
|
+
inst.baselist=yaml.safe_load(f)
|
|
408
|
+
assert type(inst.baselist)==list,f'Poorly formatted {filename}'
|
|
409
|
+
if parse: inst.parse(**kwargs)
|
|
410
|
+
return inst
|
|
411
|
+
|
|
412
|
+
def parse(self,**kwargs):
|
|
413
|
+
"""Parses a PostsimConfiguration file to build the list of stages to run."""
|
|
414
|
+
for p in self.baselist:
|
|
415
|
+
assert len(p)==1,f'Poorly formatted {self.cfgFile}; each stanza may have only one keyword'
|
|
416
|
+
simtype=list(p.keys())[0]
|
|
417
|
+
assert simtype in self.default_classes,f'Simulation type "{simtype}" in {self.cfgFile} not understood.'
|
|
418
|
+
logger.info(f'passing in {p[simtype]}')
|
|
419
|
+
self.stagelist.append(self.default_classes[simtype](p[simtype]))
|
|
420
|
+
|
|
421
|
+
def postsim(args):
|
|
422
|
+
"""Handles the postsim subcommand for managing post-cure production MD simulations.
|
|
423
|
+
|
|
424
|
+
Args:
|
|
425
|
+
args (argparse.Namespace): command-line arguments
|
|
426
|
+
"""
|
|
427
|
+
setup_logging(args.loglevel, no_banner=args.no_banner)
|
|
428
|
+
ess='y' if len(args.proj)==0 else 'ies'
|
|
429
|
+
ogromacs={}
|
|
430
|
+
if args.ocfg:
|
|
431
|
+
ocfg=Configuration.read(args.ocfg)
|
|
432
|
+
ogromacs=ocfg.gromacs
|
|
433
|
+
cfg=PostsimConfiguration.read(args.cfg)
|
|
434
|
+
logger.debug(f'{cfg.baselist}')
|
|
435
|
+
logger.info(f'Project director{ess}: {args.proj}')
|
|
436
|
+
software.sw_setup()
|
|
437
|
+
logger.debug(f'ogromacs {ogromacs}')
|
|
438
|
+
for d in args.proj:
|
|
439
|
+
pfs.pfs_setup(root=os.getcwd(),topdirs=pfs.Dirs.postsim_topdirs,verbose=True,projdir=d,reProject=False,userlibrary=args.lib)
|
|
440
|
+
pfs.go_to(pfs.Dirs.postsim)
|
|
441
|
+
for stage in cfg.stagelist:
|
|
442
|
+
stage.do(mdp_pfx='local',**ogromacs)
|
|
443
|
+
pfs.go_root()
|
|
444
|
+
|