Skip to content

Commit 0fc8ec6

Browse files
committed
make QuickFF more Jupyter-friendly
1 parent 1077890 commit 0fc8ec6

File tree

6 files changed

+37
-438
lines changed

6 files changed

+37
-438
lines changed

quickff/perturbation.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ def __init__(self, term, start, end, numbers, nsteps=11):
8787
self.fc = None
8888
self.rv = None
8989

90-
def plot(self, ai, ffrefs=[], valence=None, fn=None, eunit='kjmol', suffix=''):
90+
def plot(self, ai, ffrefs=[], valence=None, fn='default', eunit='kjmol', suffix=''):
9191
'''
9292
Method to plot the energy contributions along a perturbation
9393
trajectory associated to a given ic. This method assumes that the
@@ -175,9 +175,12 @@ def add_plot(xs, ys, prefix, kwargs):
175175
ax.grid()
176176
ax.legend(loc='upper center', fontsize=16)
177177
fig.set_size_inches([8, 8])
178-
if fn is None:
179-
fn = 'trajectory-%s-%i%s.png' %(self.term.basename.replace('/', '-'),self.term.index,suffix)
180-
fig.savefig(fn)
178+
if fn is 'show':
179+
pp.show()
180+
else:
181+
if fn is 'default':
182+
fn = 'trajectory-%s-%i%s.png' %(self.term.basename.replace('/', '-'),self.term.index,suffix)
183+
fig.savefig(fn)
181184
pp.close()
182185

183186
def to_xyz(self, fn=None):

quickff/program.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -225,11 +225,11 @@ def do_pt_generate(self):
225225
#read if an existing file was specified through fn_traj
226226
fn_traj = self.settings.fn_traj
227227
if fn_traj is not None and os.path.isfile(fn_traj):
228-
self.trajectories = pickle.load(open(fn_traj, 'r'))
228+
self.trajectories = pickle.load(open(fn_traj, 'rb'))
229229
log.dump('Trajectories read from file %s' %fn_traj)
230230
self.update_trajectory_terms()
231231
newname = 'updated_'+fn_traj.split('/')[-1]
232-
pickle.dump(self.trajectories, open(newname, 'w'))
232+
pickle.dump(self.trajectories, open(newname, 'wb'))
233233
return
234234
#configure
235235
self.reset_system()
@@ -250,7 +250,7 @@ def do_pt_generate(self):
250250
#write the trajectories to the non-existing file fn_traj
251251
if fn_traj is not None:
252252
assert not os.path.isfile(fn_traj)
253-
pickle.dump(self.trajectories, open(fn_traj, 'w'))
253+
pickle.dump(self.trajectories, open(fn_traj, 'wb'))
254254
log.dump('Trajectories stored to file %s' %fn_traj)
255255

256256
def do_pt_estimate(self, do_valence=False, logger_level=3):
@@ -692,8 +692,9 @@ class MakeTrajectories(BaseProgram):
692692
'''
693693
def run(self):
694694
with log.section('PROGRAM', 2):
695-
assert self.settings.fn_traj is not None, 'It is useless to run the MakeTrajectories program without specifying a trajectory filename fn_traj!'
696-
assert not os.path.isfile(self.settings.fn_traj), 'Given file %s to store trajectories to already exists!' %fn_traj
695+
fn_traj = self.settings.fn_traj
696+
assert fn_traj is not None, 'It is useless to run the MakeTrajectories program without specifying a trajectory filename fn_traj!'
697+
assert not os.path.isfile(fn_traj), 'Given file %s to store trajectories to already exists!' %fn_traj
697698
self.do_pt_generate()
698699

699700
class PlotTrajectories(BaseProgram):
@@ -703,8 +704,9 @@ class PlotTrajectories(BaseProgram):
703704
'''
704705
def run(self):
705706
with log.section('PROGRAM', 2):
706-
assert self.settings.fn_traj is not None, 'The PlotTrajectories program requires a trajectory filename fn_traj!'
707-
assert os.path.isfile(self.settings.fn_traj), 'Given file %s to read trajectories does not exists!' %fn_traj
707+
fn_traj = self.settings.fn_traj
708+
assert fn_traj is not None, 'The PlotTrajectories program requires a trajectory filename fn_traj!'
709+
assert os.path.isfile(fn_traj), 'Given file %s to read trajectories does not exists!' %fn_traj
708710
self.settings.set('xyz_traj', True)
709711
self.settings.set('plot_traj', 'all')
710712
self.do_pt_generate()

quickff/settings.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
#
2424
#--
2525

26-
from __future__ import absolute_import
26+
from __future__ import print_function, absolute_import
2727
from io import IOBase
2828
from quickff.log import log
2929
from molmod.units import parse_unit
@@ -241,3 +241,10 @@ def dump_log(self):
241241
for key in sorted_keys:
242242
value = str(self.__dict__[key])
243243
log.dump('%s %s' %(key+' '*(30-len(key)), value))
244+
245+
def dump_file(self, fn):
246+
sorted_keys = sorted(self.__dict__.keys())
247+
with open(fn, 'w') as f:
248+
for key in sorted_keys:
249+
value = str(self.__dict__[key])
250+
print('%s: %s' %(key+' '*(30-len(key)), value), file=f)

quickff/valence.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ def to_string(self, valence, max_name=38, max_line=72):
127127
means = pars.mean(axis=0)
128128
stds = pars.std(axis=0)
129129
formats = [
130-
'fc = %%5s %s %%4s' %("\u00B1"),
131-
'rv = %%5s %s %%4s' %("\u00B1"),
130+
'fc = %%5s %s %%4s' %("+-"),
131+
'rv = %%5s %s %%4s' %("+-"),
132132
]
133133
ndigits = [(5,4), (5,4)]
134134
units = self.units
@@ -141,9 +141,9 @@ def to_string(self, valence, max_name=38, max_line=72):
141141
units = [self.units[3], 'deg']
142142
elif self.kind==3:#cross
143143
formats = [
144-
'fc = %%4s %s %%2s' %("\u00B1"),
145-
'rv0 = %%4s %s %%3s' %("\u00B1"),
146-
'rv1 = %%4s %s %%3s' %("\u00B1")
144+
'fc = %%4s %s %%2s' %("+-"),
145+
'rv0 = %%4s %s %%3s' %("+-"),
146+
'rv1 = %%4s %s %%3s' %("+-")
147147
]
148148
ndigits = [(4,2), (4,3), (4,3)]
149149
elif self.kind==4:#cosine
@@ -152,8 +152,8 @@ def to_string(self, valence, max_name=38, max_line=72):
152152
means = fc, rv, m
153153
stds = dfc, drv, np.nan
154154
formats = [
155-
'fc = %%4s %s %%3s' %("\u00B1"),
156-
'rv = %%4s %s %%3s' %("\u00B1"),
155+
'fc = %%4s %s %%3s' %("+-"),
156+
'rv = %%4s %s %%3s' %("+-"),
157157
'm = %1s%0s'
158158
]
159159
units = [self.units[1], self.units[2], 'au']
@@ -164,7 +164,7 @@ def to_string(self, valence, max_name=38, max_line=72):
164164
means = fcs.mean(), sign
165165
stds = fcs.std(), np.nan
166166
formats = [
167-
'fc = %%4s %s %%3s' %("\u00B1"),
167+
'fc = %%4s %s %%3s' %("+-"),
168168
'sgn = %3s%0s',
169169
]
170170
units = [self.units[0], 'au']

scripts/qff-input-ei.py

Lines changed: 2 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -24,148 +24,7 @@
2424
#
2525
#--
2626

27-
from argparse import ArgumentParser
28-
import os
29-
30-
import h5py as h5
31-
32-
from molmod.io.chk import load_chk
33-
from yaff import System
34-
35-
from quickff.tools import set_ffatypes, get_ei_radii, average, charges_to_bcis
36-
from quickff.io import read_abinitio, make_yaff_ei, read_bci_constraints
37-
38-
39-
description = '''\
40-
This script reads atomic charges from an input file and makes a Yaff parameters file
41-
suitable for the QuickFF option --ei.'''
42-
43-
44-
def parse_args(args=None):
45-
parser = ArgumentParser(description=description)
46-
parser.add_argument(
47-
'-v', '--verbose', default=False, action='store_true',
48-
help='Increase verbosity of the script [default=%(default)s].'
49-
)
50-
parser.add_argument(
51-
'--ffatypes', default=None,
52-
choices=['None','list_of_atypes', 'low','medium','high','highest'],
53-
help='Assign atom types in the system by parsing an ordered list of'
54-
'atom types as argument or through the automatic built-in '
55-
'detection (see documentation). By default (or if None is given), '
56-
'the atom types are assumed to be defined in the input files. '
57-
'[default=%(default)s]'
58-
)
59-
parser.add_argument(
60-
'--gaussian', default=False, action='store_true',
61-
help='Use gaussian smeared charges. The radii are taken from the input '
62-
'file fn_in (from dataset /path/radii for HDF5 file or from label '
63-
'`radii` for CHK file) if the data is present, otherwise the radii '
64-
'are estimated according to the procedure of Chen et al. See '
65-
'``quickff.tools.get_ei_radii`` for more info.'
66-
)
67-
parser.add_argument(
68-
'--bci', default=False, action='store_true',
69-
help='Convert averaged atomic charges to bond charge increments, i.e. '
70-
'charge transfers along the chemical bonds in the system. In this '
71-
'way, one is certain of ending up with a globally neutral system '
72-
'even if bcis from different systems are combined. This option '
73-
'requires the definition of bonds, if the bonds cannot be read '
74-
'from the system file, they will be estimated from the interatomic '
75-
'distances using the detect_bonds routine in the Yaff System '
76-
'class. [default=%(default)s]'
77-
)
78-
parser.add_argument(
79-
'--bci-constraints', default=None,
80-
help='A file containing constraints for the charge to bci fit in a '
81-
'master: slave0,slave1,...: sign format. A new line should be used '
82-
'for each master and the format is insensitive towards spaces.'
83-
'Sign should be 1.0 or -1.0 indicating wheter or not a sign switch '
84-
'should be introduced when mapping the slaves to the master.'
85-
)
86-
parser.add_argument(
87-
'fn_sys',
88-
help='Any file from which the system can be extracted (MolMod CHK, Gaussian '
89-
'FCHK, XYZ, ...).'
90-
)
91-
parser.add_argument(
92-
'charges',
93-
help='The atomic charges to be used. This argument has the form fn_charges:path, '
94-
'where fn_charges is a filename that contains the charges and path refers '
95-
'to a location within that file where the charges can be found. If '
96-
'fn_charges is an HDF5 file, path is the location of a dataset containing '
97-
'the charges, e.g. \'/charges\'. If fn_charges is a MolMod CHK file, path '
98-
'is the label of the dataset that contains the atomic charges.'
99-
)
100-
parser.add_argument(
101-
'fn_out', default='pars_ei.txt', nargs='?',
102-
help='Name of the Yaff file to write the parameters to. [default=%(default)s]'
103-
)
104-
if args is None:
105-
args = parser.parse_args()
106-
else:
107-
args = parser.parse_args(args.split())
108-
if args.charges.count(':') != 1:
109-
parser.error('The argument charges must contain exactly one colon.')
110-
return args
111-
112-
113-
def main(args=None):
114-
if args is None:
115-
args = parse_args()
116-
else:
117-
args = parse_args(args)
118-
# Load system file
119-
if args.fn_sys.endswith('.fchk'):
120-
numbers, coords, energy, grad, hess, masses, rvecs, pbc = read_abinitio(args.fn_sys, do_hess=False)
121-
system = System(numbers, coords, rvecs=None, charges=None, radii=None, masses=masses)
122-
system.detect_bonds()
123-
else:
124-
system = System.from_file(args.fn_sys)
125-
126-
# Guess atom types if needed
127-
if args.ffatypes is not None:
128-
set_ffatypes(system, args.ffatypes)
129-
ffatypes = [system.ffatypes[i] for i in system.ffatype_ids]
130-
131-
# Load atomic charges
132-
fn_charges, _, path = args.charges.partition(':')
133-
if fn_charges.endswith('.h5'):
134-
with h5.File(fn_charges, 'r') as f:
135-
if not path in f:
136-
raise IOError('Given HDF5 file %s does not contain a dataset %s' % (fn_charges, path))
137-
charges = f[path][:]
138-
radii = None
139-
if args.gaussian:
140-
path_radii = os.path.join(os.path.dirname(path), 'radii')
141-
if 'radii' in f[path]:
142-
radii = average(f['%s/radii' %path][:], ffatypes, fmt='dict')
143-
else:
144-
radii = average(get_ei_radii(system.numbers), ffatypes, fmt='dict')
145-
elif fn_charges.endswith('.chk'):
146-
sample = load_chk(fn_charges)
147-
if path in list(sample.keys()):
148-
charges = sample[path]
149-
else:
150-
raise IOError('Given CHK file %s does not contain a dataset with label %s' % (fn_charges, path))
151-
radii = None
152-
if args.gaussian:
153-
if 'radii' in list(sample.keys()):
154-
radii = average(sample['radii'], ffatypes, fmt='dict')
155-
else:
156-
raise IOError('Invalid extension, fn_charges should be a HDF5 or a CHK file.')
157-
158-
# Derive charge parameters
159-
if args.bci:
160-
constraints = {}
161-
if args.bci_constraints is not None:
162-
constraints = read_bci_constraints(args.bci_constraints)
163-
bcis = charges_to_bcis(charges, ffatypes, system.bonds, constraints=constraints, verbose=args.verbose)
164-
make_yaff_ei(args.fn_out, None, bcis=bcis, radii=radii)
165-
else:
166-
charges = average(charges, ffatypes, fmt='dict', verbose=args.verbose)
167-
make_yaff_ei(args.fn_out, charges, radii=radii)
168-
27+
from quickff.scripts import qff_input_ei
16928

17029
if __name__=='__main__':
171-
main()
30+
qff_input_ei()

0 commit comments

Comments
 (0)