source: utils/boxmaker.py@ 32bc47

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 32bc47 was 32bc47, checked in by Frederik Heber <heber@…>, 13 years ago

Update: autorotate

Not tested yet, but it seems like it does *something* (means: paths etc. are correctly handled).

  • Property mode set to 100644
File size: 8.4 KB
Line 
1import re, os, os.path, sys, operator
2
3class c_opt():
4 basename = None
5 tremofiledir = './'
6 potentialsfiledir = './'
7 outfilename = 'out'
8
9 source = None
10 molarmass = None
11 density = None
12 temp = None
13
14 number = '1000'
15
16 cubicdomain = 'on'
17 cubiccell = 'off'
18 autorotate = 'off'
19 autodim = 'on'
20 postprocess = 'on'
21
22 def update(self, name, value):
23 if name in dir(self):
24 exec('self.%s = "%s"' % (name, value))
25 else:
26 print 'Warning: Unknown option:', name
27
28
29def ReadSettings(opt):
30 # Obtain basename
31 if len(sys.argv) >= 2:
32 opt.basename = sys.argv[1]
33 else:
34 print 'Usage: boxmaker.py <basename> [options]'
35 exit()
36
37 # Read settings file
38 with open('boxmaker.' + opt.basename) as f:
39 for line in f:
40 if len(line) > 0 and line[0] != '#':
41 L, S, R = line.partition('=')
42 opt.update(L.strip(), R.strip())
43
44 # Parse parameters
45 i = 2
46 while i < len(sys.argv):
47 L = sys.argv[i]
48
49 if L[0] in '+-':
50 LN = L[1:]
51
52 if L[0] == '+':
53 R = 'on'
54 else:
55 R = 'off'
56 else:
57 LN = L
58 i += 1
59 R = sys.argv[i]
60
61 opt.update(LN, R)
62 i += 1
63
64
65def ReadUnits(opt):
66 lines = [] # The file needs to be processed twice, so we save the lines in the first run
67
68 with open(opt.tremofiledir + opt.basename + '.tremolo') as f:
69 for line in f:
70 if len(line) > 0 and line[0] != '#':
71 line = line.strip()
72 lines.append(line)
73
74 if 'systemofunits' in line:
75 L, S, SOU = line.partition('=')
76 SOU = SOU.strip()[:-1] # Remove semicolon
77
78 if SOU == 'custom':
79 units = {}
80 quantities = ['length', 'mass']
81
82 for quantity in quantities:
83 units[quantity] = [None, None] # Init with scaling factor and unit 'None'.
84
85 for line in lines:
86 for quantity in quantities:
87 if quantity in line:
88 L, S, R = line.partition('=')
89 R = R.strip()[:-1] # Remove semicolon
90
91 if 'scalingfactor' in line:
92 units[quantity][0] = R
93 else:
94 units[quantity][1] = R
95
96 elif SOU == 'kcalpermole':
97 units = {'length': ['1', 'angstrom'], 'mass': ['1', 'u']}
98
99 elif SOU == 'evolt':
100 units = {'length': ['1', 'angstrom'], 'mass': ['1', 'u']}
101
102 else: # SI
103 units = {'length': ['1', 'm'], 'mass': ['1', 'kg']}
104
105 return units
106
107
108def ConvertUnits(have, want):
109 # Redo with pipes?
110 ret = os.system("units '%s' '%s' > temp_units_output" % (have, want))
111
112 if ret == 0:
113 with open('temp_units_output') as f:
114 line = f.readline()
115
116 os.system('rm temp_units_output')
117
118 return float(line[3:-1])
119 else:
120 raise NameError('UnitError')
121
122
123def UpdateSettings(opt):
124 # Map boolean values
125 for name in ['cubicdomain', 'cubiccell', 'autorotate', 'autodim', 'postprocess']:
126 value = eval('opt.' + name)
127
128 if value == 'on':
129 value = True
130 elif value == 'off':
131 value = False
132 else:
133 print 'Not a boolean value:', value
134 exit()
135
136 exec('opt.' + name + '= value')
137
138 # Convert dimensions
139 if opt.autodim:
140 units = ReadUnits(opt)
141
142 have = opt.molarmass
143 want = '%s*%s / mol' % tuple(units['mass'])
144 opt.molarmass = ConvertUnits(have, want)
145
146 have = opt.density
147 want = '(%s*%s) ' % tuple(units['mass']) + '/ (%s*%s)**3' % tuple(units['length'])
148 opt.density = ConvertUnits(have, want)
149 else:
150 opt.molarmass = float(opt.molarmass)
151 opt.density = float(opt.density)
152
153 # Number might be an integer or a 3-vector
154 nvec = opt.number.split()
155 if len(nvec) == 3:
156 opt.number = [0]*3
157
158 for i in range(3):
159 opt.number[i] = int(nvec[i])
160 else:
161 opt.number = int(opt.number)
162
163 # Temp should be float or None
164 if opt.temp:
165 opt.temp = float(opt.temp)
166
167
168def FindBestCube(opt):
169 newroot = int( round(opt.number**(1./3)) )
170 newnumber = newroot**3
171
172 if newnumber != opt.number:
173 print 'Warning: Number changed to %d.' % newnumber
174
175 return [newroot] * 3
176
177
178def FindBestCuboid(opt):
179 n = opt.number
180
181 # Prime factors of n
182 factors = []
183
184 for i in [2, 3]:
185 while n % i == 0:
186 factors.append(i)
187 n /= 2
188
189 t = 5
190 diff = 2
191
192 while t*t <= n:
193 while n % t == 0:
194 factors.append(t)
195 n /= t
196
197 t = t + diff
198 diff = 6 - diff
199
200 if n > 1:
201 factors.append(n)
202
203 # Even distribution of current biggest prime to each vector -> similar sizes
204 if len(factors) < 3:
205 print 'Warning: Not enough prime factors - falling back to cubic placement'
206 return FindBestCube(opt)
207
208 factors.sort()
209 distri = [[],[],[]]
210 current = 0
211
212 for factor in factors:
213 distri[current].append(factor)
214 current += 1
215 if current == 3:
216 current = 0
217
218 result = [0]*3
219
220 print '======== CUBOID USED:',
221
222 for i in range(3):
223 result[i] = int( reduce(operator.mul, distri[i]) )
224
225 print result
226 return result
227
228
229def GetSourceBBabs(opt):
230 bbmax = [0.0]*3
231 bbmin = [float('inf')]*3
232
233 s_name_ext = os.path.basename(opt.source).rsplit('.', 1)
234 s_namepart = s_name_ext[0]
235
236 if len(s_name_ext) > 1:
237 s_ext = s_name_ext[1]
238 else:
239 s_ext = ''
240
241 # Convert from any format to xyz
242 os.system('molecuilder -o xyz --parse-tremolo-potentials %s -i temp_source.xyz -l %s' % (opt.potentialsfiledir+opt.basename+'.potentials', opt.source))
243
244 # Calculate bounding box from xyz-file
245 with open('temp_source.xyz') as f:
246 N = int(f.readline())
247 comment = f.readline()
248
249 for i in xrange(N):
250 buf = f.readline()
251 xyz = buf.split()[1:]
252
253 for i in range(3):
254 bbmax[i] = max(bbmax[i], float(xyz[i]))
255 bbmin[i] = min(bbmin[i], float(xyz[i]))
256
257 bb = [0.0]*3
258
259 for i in range(3):
260 bb[i] = abs(bbmax[i] - bbmin[i])
261
262 os.system('rm temp_source.*')
263 return bb
264
265# Global options with sensible default parameters
266opt = c_opt()
267
268ReadSettings(opt)
269UpdateSettings(opt)
270
271if type(opt.number) == type([]):
272 # Number is a vector - use it without any modification
273 nbox = opt.number
274else:
275 if opt.cubicdomain:
276 nbox = FindBestCube(opt)
277 else:
278 nbox = FindBestCuboid(opt)
279
280# Autorotate
281if opt.autorotate:
282 os.system('molecuilder --parse-tremolo-potentials %s -i rotated_temp_source.data -l %s --rotate-to-principal-axis-system "1, 0, 0"' % (opt.potentialsfiledir+opt.basename+'.potentials', opt.source))
283 opt.source = 'rotated_temp_source.data'
284
285avogadro = 6.022143e23
286VolumePerMolecule = opt.molarmass / (avogadro * opt.density)
287cell = [VolumePerMolecule**(1./3)] * 3
288
289if not opt.cubiccell:
290 try:
291 bb = GetSourceBBabs(opt)
292 print '======== BBOX:', bb
293 # Scaling factor - the molecules bounding box is scaled to fit the volume suiting the density
294 s = (VolumePerMolecule / (bb[0]*bb[1]*bb[2])) ** (1./3)
295
296 if s < 1:
297 print 'Warning: Molecular cells will overlap.'
298
299 for i in range(3):
300 cell[i] = bb[i]*s
301 except ZeroDivisionError:
302 print 'Warning: Singularity in bounding box, falling back to cubic cell.'
303
304
305print '======== CELL: ', cell
306
307import pyMoleCuilder as mol
308mol.CommandVerbose('0')
309mol.ParserParseTremoloPotentials(opt.potentialsfiledir + opt.basename + '.potentials')
310mol.WorldInput(opt.source)
311mol.WorldCenterInBox('%f 0 0 %f 0 %f' % tuple(cell))
312mol.WorldRepeatBox('%d %d %d' % tuple(nbox))
313mol.WorldOutput(opt.outfilename + '.data')
314mol.WorldOutput(opt.outfilename + '.xyz')
315
316domain = [0.0]*3
317
318for i in range(3):
319 domain[i] = cell[i]*nbox[i]
320
321print '======== DOMAIN: ', domain
322
323# Postprocessing
324
325if opt.postprocess:
326 with open(opt.outfilename + '.data') as f:
327 ofile = f.read()
328
329 with open(opt.outfilename + '.data', 'w') as f:
330 f.write('# INPUTCONV shift center\n')
331
332 if opt.temp:
333 f.write('# INPUTCONV temp %.4f\n' % opt.temp)
334
335 f.write(ofile)
336
337if opt.autorotate:
338 os.system('rm ' + opt.source)
Note: See TracBrowser for help on using the repository browser.