source: utils/Python/boxmaker.py.in@ dd6c07

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since dd6c07 was 415ddd, checked in by Frederik Heber <heber@…>, 11 years ago

ActionQueue now contains a run thread.

  • otherwise the progress bar of the QtMainWindow cannot be seen as waitForResults() takes up all of the executing thread.
  • added mutex for operations modifying the queue.
  • added ActionQueue::run() and ::stop(), used by friend stopQueue().
  • insertAction() now makes use of a tempqueue that is added to true queue during run() instead of calling the actions directly.
  • new stopQueue() in cleanUp.hpp is used by module_exit in pyMoleCuilder and in main() before saveAll().
  • cleanup: printTiming() requires now list of action tokens and added new stopAndPurgeQueue() to place waiting for Actions to end into extra function.
  • added ActionQueue::wait() which allows for synchronization in python scripts, is ignored in session python scripts. Otherwise we wait for ActionQueue's queue to empty during execution of load-session which hangs.
  • DOCU: added note to python documentation.
  • added waitQueue() also to purgeStaticInstances().
  • static UIFactory::isFactoryPresent() added that allows checking whether we have a UI or are executed within a python script (i.e. pyMoleCuilder).
  • DOCU: Extended docu on threads and who this affects python scripts.
  • TESTFIX: changed regression tests on storing python sessions.
  • Property mode set to 100755
File size: 9.3 KB
Line 
1#!@PYTHON@
2
3# Boxmaker 1.0
4# Creates tremolo-datafiles with arbitrary size and specific density from a single input molecule,
5# supporting numerous pre- and postprocessing features such as unit conversion.
6# Gregor Bollerhey - bollerhe@ins.uni-bonn.de
7
8
9import re, os, os.path, sys, operator
10import pyMoleCuilder as mol
11
12avogadro = 6.022143e23
13
14class c_opt():
15 basename = None
16 tremofiledir = './'
17 potentialsfiledir = './'
18 outfilename = 'out'
19
20 source = None
21 molarmass = None
22 density = None
23 temp = None
24
25 number = '1000'
26
27 cubicdomain = 'on'
28 cubiccell = 'off'
29 autorotate = 'off'
30 autodim = 'on'
31 postprocess = 'on'
32 automass = 'on'
33
34 def update(self, name, value):
35 shortcuts = {'tf': 'temofiledir', 'pf': 'potentialsfiledir', 'o': 'outfilename',
36 'i': 'source', 'm': 'molarmass', 'rho': 'density',
37 't': 'temp', 'n': 'number', 'cd': 'cubicdomain',
38 'cc': 'cubiccell', 'ar': 'autorotate', 'ad': 'autodim',
39 'pp': 'postprocess', 'am': 'automass'}
40
41 if name in shortcuts:
42 name = shortcuts[name]
43
44 if name in dir(self):
45 exec('self.%s = "%s"' % (name, value))
46 else:
47 print 'Warning: Unknown option:', name
48
49
50def ReadSettings(opt):
51 # Obtain basename
52 if len(sys.argv) >= 2:
53 opt.basename = sys.argv[1]
54 else:
55 print 'Usage: boxmaker.py <basename> [options]'
56 exit()
57
58 # Read settings file
59 try:
60 with open('boxmaker.' + opt.basename) as f:
61 for line in f:
62 if len(line) > 0 and line[0] != '#':
63 L, S, R = line.partition('=')
64 opt.update(L.strip(), R.strip())
65 except IOError:
66 print 'Warning: Configuration file not readable, CLI only'
67
68 # Parse parameters
69 i = 2
70 while i < len(sys.argv):
71 L = sys.argv[i]
72
73 if L[0] in '+-':
74 LN = L[1:]
75
76 if L[0] == '+':
77 R = 'on'
78 else:
79 R = 'off'
80 else:
81 LN = L
82 i += 1
83 R = sys.argv[i]
84
85 opt.update(LN, R)
86 i += 1
87
88
89def ReadUnits(opt):
90 lines = [] # The file needs to be processed twice, so we save the lines in the first run
91
92 with open(opt.tremofiledir + opt.basename + '.tremolo') as f:
93 for line in f:
94 if len(line) > 0 and line[0] != '#':
95 line = line.strip()
96 lines.append(line)
97
98 if 'systemofunits' in line:
99 L, S, SOU = line.partition('=')
100 SOU = SOU.strip()[:-1] # Remove semicolon
101
102 if SOU == 'custom':
103 units = {}
104 quantities = ['length', 'mass', 'temperature']
105
106 for quantity in quantities:
107 units[quantity] = [None, None] # Init with scaling factor and unit 'None'.
108
109 for line in lines:
110 for quantity in quantities:
111 if quantity in line:
112 L, S, R = line.partition('=')
113 R = R.strip()[:-1] # Remove semicolon
114
115 if 'scalingfactor' in line:
116 units[quantity][0] = float(R)
117 else:
118 units[quantity][1] = R
119
120 elif SOU == 'kcalpermole':
121 units = {'length': [1.0, 'angstrom'], 'mass': [1.0, 'u'], 'temperature': [503.556, 'K']}
122
123 elif SOU == 'evolt':
124 units = {'length': [1.0, 'angstrom'], 'mass': [1.0, 'u'], 'temperature': [11604.0, 'K']}
125
126 else: # SI
127 units = {'length': [1.0, 'm'], 'mass': [1.0, 'kg'], 'temperature': [1.0, 'K']}
128
129 return units
130
131
132def ConvertUnits(have, want):
133 if have[0] == '!':
134 return float(have[1:])
135
136 # Redo with pipes?
137 #sys.stdout.write("units '%s' '%s'\n" % (have, want))
138 ret = os.system("units '%s' '%s' > temp_units_output" % (have, want))
139
140 if ret == 0:
141 with open('temp_units_output') as f:
142 line = f.readline()
143
144 os.system('rm temp_units_output')
145
146 return float(line[3:-1])
147 else:
148 raise NameError('UnitError')
149
150
151def GetSourceMolareMass(opt, units):
152 mol.SelectionAllAtoms()
153 mol.wait()
154 mass_sum = mol.getSelectedMolarMass()
155 have = ("%f atomicmassunit" % mass_sum)
156 want = ("%f*%s" % tuple(units['mass']))
157 return ConvertUnits(have, want)*avogadro
158
159
160def UpdateSettingsAndSource(opt):
161 # Map boolean values
162 boolmap = {'on': True, 'off': False}
163
164 for name in ['cubicdomain', 'cubiccell', 'autorotate', 'autodim', 'postprocess', 'automass']:
165 value = eval('opt.' + name)
166
167 if value in boolmap:
168 value = boolmap[value]
169 else:
170 print 'Not a boolean value:', value
171 exit()
172
173 exec('opt.' + name + '= value')
174
175 # Convert dimensions
176 if opt.autodim:
177 units = ReadUnits(opt)
178
179 if not opt.automass:
180 have = opt.molarmass
181 want = '%f*%s / mol' % tuple(units['mass'])
182 opt.molarmass = ConvertUnits(have, want)
183
184 have = opt.density
185 want = '(%f*%s) ' % tuple(units['mass']) + '/ (%f*%s)**3' % tuple(units['length'])
186 opt.density = ConvertUnits(have, want)
187
188 if opt.temp:
189 have = opt.temp
190 want = '%f*%s' % tuple(units['temperature'])
191 opt.temp = ConvertUnits(have, want)
192 else:
193 if not opt.automass:
194 opt.molarmass = float(opt.molarmass)
195
196 opt.density = float(opt.density)
197
198 if opt.temp:
199 opt.temp = float(opt.temp)
200
201 # Number might be an integer or a 3-vector
202 nvec = opt.number.split()
203 if len(nvec) == 3:
204 opt.number = [0]*3
205
206 for i in range(3):
207 opt.number[i] = int(nvec[i])
208 else:
209 opt.number = int(opt.number)
210
211 InitialiseSource(opt)
212
213 # Automatic source mass
214 if opt.automass:
215 opt.molarmass = GetSourceMolareMass(opt, units)
216 print '======== MOLAR MASS:', opt.molarmass
217
218
219def FindBestCube(opt):
220 newroot = int( round(opt.number**(1./3)) )
221 newnumber = newroot**3
222
223 if newnumber != opt.number:
224 print 'Warning: Number changed to %d.' % newnumber
225
226 return [newroot] * 3
227
228
229def FindBestCuboid(opt):
230 n = opt.number
231
232 # Prime factors of n
233 factors = []
234
235 for i in [2, 3]:
236 while n % i == 0:
237 factors.append(i)
238 n /= 2
239
240 t = 5
241 diff = 2
242
243 while t*t <= n:
244 while n % t == 0:
245 factors.append(t)
246 n /= t
247
248 t = t + diff
249 diff = 6 - diff
250
251 if n > 1:
252 factors.append(n)
253
254 # Even distribution of current biggest prime to each vector -> similar sizes
255 if len(factors) < 3:
256 print 'Warning: Not enough prime factors - falling back to cubic placement'
257 return FindBestCube(opt)
258
259 factors.sort()
260 distri = [[],[],[]]
261 current = 0
262
263 for factor in factors:
264 distri[current].append(factor)
265 current += 1
266 if current == 3:
267 current = 0
268
269 result = [0]*3
270
271 print '======== CUBOID USED:',
272
273 for i in range(3):
274 result[i] = int( reduce(operator.mul, distri[i]) )
275
276 print result
277 return result
278
279
280def GetSourceBBabs(opt):
281 mol.WorldCenterOnEdge()
282 mol.wait()
283 bb = mol.getBoundingBox()
284 bbmin = [bb[0], bb[2], bb[4]]
285 bbmax = [bb[1], bb[3], bb[5]]
286
287 bb = [0.0]*3
288
289 for i in range(3):
290 bb[i] = abs(bbmax[i] - bbmin[i])
291
292 return bb
293
294
295def InitialiseSource(opt):
296 potfilepath = opt.potentialsfiledir + opt.basename + '.potentials'
297 mol.ParserParseTremoloPotentials(potfilepath)
298 mol.MoleculeLoad(opt.source)
299
300 if opt.autorotate:
301 mol.SelectAllAtoms()
302 mol.RotateToPrincipalAxisSystem("0 1 0")
303 mol.wait()
304
305# Global options with sensible default parameters
306opt = c_opt()
307
308ReadSettings(opt)
309UpdateSettingsAndSource(opt)
310
311if type(opt.number) == type([]):
312 # Number is a vector - use it without any modification
313 nbox = opt.number
314else:
315 if opt.cubicdomain:
316 nbox = FindBestCube(opt)
317 else:
318 nbox = FindBestCuboid(opt)
319
320VolumePerMolecule = opt.molarmass / (avogadro * opt.density)
321cell = [VolumePerMolecule**(1./3)] * 3
322
323if not opt.cubiccell:
324 try:
325 bb = GetSourceBBabs(opt)
326 print '======== BBOX:', bb
327 # Scaling factor - the molecules bounding box is scaled to fit the volume suiting the density
328 s = (VolumePerMolecule / (bb[0]*bb[1]*bb[2])) ** (1./3)
329
330 if s < 1:
331 print 'Warning: Molecular cells will overlap.'
332
333 for i in range(3):
334 cell[i] = bb[i]*s
335 except ZeroDivisionError:
336 print 'Warning: Singularity in bounding box, falling back to cubic cell.'
337
338
339print '======== CELL: ', cell
340
341mol.CommandVerbose('0')
342mol.WorldCenterInBox('%f 0 0 %f 0 %f' % tuple(cell))
343mol.WorldRepeatBox('%d %d %d' % tuple(nbox))
344mol.WorldOutputAs(opt.outfilename + '.data')
345mol.WorldOutputAs(opt.outfilename + '.xyz')
346mol.wait()
347
348domain = [0.0]*3
349
350for i in range(3):
351 domain[i] = cell[i]*nbox[i]
352
353print '======== DOMAIN: ', domain
354
355# Postprocessing
356
357if opt.postprocess:
358 with open(opt.outfilename + '.data') as f:
359 ofile = f.read()
360
361 with open(opt.outfilename + '.data', 'w') as f:
362 f.write('# INPUTCONV shift center\n')
363
364 if opt.temp:
365 f.write('# INPUTCONV temp %.4f\n' % opt.temp)
366
367 f.write(ofile)
368
369os.system('rm temp_source.data temp_source.xyz')
Note: See TracBrowser for help on using the repository browser.