Changeset 0c83d8 for utils/boxmaker.py


Ignore:
Timestamp:
Nov 7, 2011, 4:12:24 PM (13 years ago)
Author:
Frederik Heber <heber@…>
Branches:
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
Children:
32bc47
Parents:
5735ba
git-author:
Gregor Bollerhey <bollerhe@…> (10/17/11 11:03:12)
git-committer:
Frederik Heber <heber@…> (11/07/11 16:12:24)
Message:

Less ugly advanced version

  • Class (struct) based global options
  • Minor bugfixes
  • Feature: Cubic cell
  • Feature: Skip unit conversion
  • Feature: Options via cmd line
  • Feature: More settings

TODO:

  • Output postprocessing (INPUTCONVs)
  • Auto-rotate to minimum BBox
  • Documentation
File:
1 edited

Legend:

Unmodified
Added
Removed
  • utils/boxmaker.py

    r5735ba r0c83d8  
    11import re, os, os.path, sys, operator
    22
    3 def ReadSettings():
     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' # Not implemented yet
     19    autodim = 'on'
     20
     21    def update(self, name, value):
     22        if name in dir(self):
     23            exec('self.%s = "%s"' % (name, value))
     24        else:
     25            print 'Warning: Unknown option:', name
     26
     27
     28def ReadSettings(opt):
     29    # Obtain basename
    430    if len(sys.argv) >= 2:
    5         global opt_basename
    6         opt_basename = sys.argv[1]
    7     else:
    8         print 'usage: boxmaker.py <basename>'
     31        opt.basename = sys.argv[1]
     32    else:
     33        print 'Usage: boxmaker.py <basename> [options]'
    934        exit()
    10    
    11     with open('boxmaker.'+opt_basename) as f:
     35
     36    # Read settings file
     37    with open('boxmaker.' + opt.basename) as f:
    1238        for line in f:
    1339            if len(line) > 0 and line[0] != '#':
    1440                L, S, R = line.partition('=')
    15                 varname = 'opt_' + L.strip()
    16                
    17                 exec('global %s\n%s="%s"' % (varname, varname, R.strip()))
    18                
    19     # IT'S A HACK
    20     global opt_number
    21    
    22     if len(sys.argv) == 3:
    23         opt_number = sys.argv[2]
    24    
    25    
    26 def ReadUnits():   
    27     lines = []
    28     with open(opt_tremofiledir+opt_basename+'.tremolo') as f:
     41                opt.update(L.strip(), R.strip())
     42
     43    # Parse parameters
     44    i = 2
     45    while i < len(sys.argv):
     46        L = sys.argv[i]
     47
     48        if L[0] in '+-':
     49            LN = L[1:]
     50
     51            if L[0] == '+':
     52                R = 'on'
     53            else:
     54                R = 'off'
     55        else:
     56            LN = L
     57            i += 1
     58            R = sys.argv[i]
     59       
     60        opt.update(LN, R)
     61        i += 1
     62
     63
     64def ReadUnits(opt):
     65    lines = [] # The file needs to be processed twice, so we save the lines in the first run
     66
     67    with open(opt.tremofiledir + opt.basename + '.tremolo') as f:
    2968        for line in f:
    3069            if len(line) > 0 and line[0] != '#':
    3170                line = line.strip()
    32                 lines.append(line.strip())
    33                
     71                lines.append(line)
     72
    3473                if 'systemofunits' in line:
    3574                    L, S, SOU = line.partition('=')
    36                     SOU = SOU.strip()[:-1]
    37                    
     75                    SOU = SOU.strip()[:-1] # Remove semicolon
     76
    3877    if SOU == 'custom':
    3978        units = {}
    4079        quantities = ['length', 'mass']
    41        
     80
    4281        for quantity in quantities:
    43             units[quantity] = [None, None] # scaling factor and unit.
    44        
     82            units[quantity] = [None, None] # Init with scaling factor and unit 'None'.
     83
    4584        for line in lines:
    4685            for quantity in quantities:
    4786                if quantity in line:
    4887                    L, S, R = line.partition('=')
    49                     R = R.strip()[:-1] # remove semicolon
    50                    
     88                    R = R.strip()[:-1] # Remove semicolon
     89
    5190                    if 'scalingfactor' in line:
    5291                        units[quantity][0] = R
    5392                    else:
    5493                        units[quantity][1] = R
    55                        
     94
    5695    elif SOU == 'kcalpermole':
    5796        units = {'length': ['1', 'angstrom'], 'mass': ['1', 'u']}
    58    
     97
    5998    elif SOU == 'evolt':
    6099        units = {'length': ['1', 'angstrom'], 'mass': ['1', 'u']}
    61        
     100
    62101    else: # SI
    63102        units = {'length': ['1', 'm'], 'mass': ['1', 'kg']}
    64                                          
     103
    65104    return units
    66    
    67    
     105
     106
    68107def ConvertUnits(have, want):
    69     # redo with pipes?
     108    # Redo with pipes?
    70109    ret = os.system("units '%s' '%s' > temp_units_output" % (have, want))
    71    
     110
    72111    if ret == 0:
    73112        with open('temp_units_output') as f:
    74113            line = f.readline()
     114
     115        os.system('rm temp_units_output')
     116
     117        return float(line[3:-1])
     118    else:
     119        raise NameError('UnitError')
     120
     121
     122def UpdateSettings(opt):
     123    # Map boolean values
     124    for name in ['cubicdomain', 'cubiccell', 'autorotate', 'autodim']:
     125        value = eval('opt.' + name)
     126       
     127        if value == 'on':
     128            value = True
     129        elif value == 'off':
     130            value = False
     131        else:
     132            print 'Not a boolean value:', value
     133            exit()
    75134           
    76         os.system('rm temp_units_output')
    77            
    78         return float(line[3:-1])
    79     else:
    80         raise NameError('UnitError')
    81    
    82    
    83 def UpdateSettings():
    84     global opt_molarmass, opt_density, opt_number
    85    
    86     units = ReadUnits()
    87    
    88     have = opt_molarmass
    89     want = '%s*%s / mol' % tuple(units['mass'])
    90     opt_molarmass = ConvertUnits(have, want)
    91    
    92     have = opt_density
    93     want = '(%s*%s) ' % tuple(units['mass']) + '/ (%s*%s)**3' % tuple(units['length'])
    94     opt_density = ConvertUnits(have, want)
    95    
    96     nvec = opt_number.split()
     135        exec('opt.' + name + '= value')
     136
     137    # Convert dimensions
     138    if opt.autodim:
     139        units = ReadUnits(opt)
     140
     141        have = opt.molarmass
     142        want = '%s*%s / mol' % tuple(units['mass'])
     143        opt.molarmass = ConvertUnits(have, want)
     144
     145        have = opt.density
     146        want = '(%s*%s) ' % tuple(units['mass']) + '/ (%s*%s)**3' % tuple(units['length'])
     147        opt.density = ConvertUnits(have, want)
     148    else:
     149        opt.molarmass = float(opt.molarmass)
     150        opt.density = float(opt.density)
     151
     152    # Number might be an integer or a 3-vector
     153    nvec = opt.number.split()
    97154    if len(nvec) == 3:
    98         opt_number = [0]*3
    99        
     155        opt.number = [0]*3
     156
    100157        for i in range(3):
    101             opt_number[i] = int(nvec[i])
    102     else:
    103         opt_number = int(opt_number)
    104        
    105        
    106 def FindNearestCube(n):
    107     global opt_number
    108    
    109     newroot = round(opt_number**(1./3))
    110    
    111     opt_number = int(newroot**3)
    112     print 'warning: number changed to %d' % opt_number
    113    
    114     return [int(newroot)] * 3
    115        
    116        
    117 def FindBestCuboid(n):
    118     # prime factors of n
    119     # taken from http://www.hsg-kl.de/faecher/inf/python/listen/index.php, "Beispiel 2"
    120    
    121     F = []
    122 
    123     while n%2 == 0:
    124         F.append(2)
    125         n = n/2
    126     while n%3 == 0:
    127         F.append(3)
    128         n = n/3
    129    
     158            opt.number[i] = int(nvec[i])
     159    else:
     160        opt.number = int(opt.number)
     161
     162
     163def FindBestCube(opt):
     164    newroot = int( round(opt.number**(1./3)) )
     165    newnumber = newroot**3
     166
     167    if newnumber != opt.number:
     168        print 'Warning: Number changed to %d.' % newnumber
     169
     170    return [newroot] * 3
     171
     172
     173def FindBestCuboid(opt):
     174    n = opt.number
     175
     176    # Prime factors of n
     177    factors = []
     178
     179    for i in [2, 3]:
     180        while n % i == 0:
     181            factors.append(i)
     182            n /= 2
     183
    130184    t = 5
    131185    diff = 2
    132    
     186
    133187    while t*t <= n:
    134         while n%t == 0:
    135             F.append(t)
    136             n = n/t
     188        while n % t == 0:
     189            factors.append(t)
     190            n /= t
     191
    137192        t = t + diff
    138193        diff = 6 - diff
     194
    139195    if n > 1:
    140         F.append(n)
    141        
    142     # even distribution of current biggest prime to each vector -> similar sizes
    143     if len(F) < 3:
    144         print 'warning: not enough prime factors - falling back to cubic placement'
    145         return FindNearestCube(n, mlen)
    146    
    147     F.sort()
     196        factors.append(n)
     197
     198    # Even distribution of current biggest prime to each vector -> similar sizes
     199    if len(factors) < 3:
     200        print 'Warning: Not enough prime factors - falling back to cubic placement'
     201        return FindBestCube(opt)
     202
     203    factors.sort()
    148204    distri = [[],[],[]]
    149205    current = 0
    150    
    151     for primfaktor in F:
    152         distri[current].append(primfaktor)
     206
     207    for factor in factors:
     208        distri[current].append(factor)
    153209        current += 1
    154210        if current == 3:
    155211            current = 0
    156            
    157     result = []
    158    
    159     print 'box used:',
    160    
     212
     213    result = [0]*3
     214
     215    print '======== CUBOID USED:',
     216
    161217    for i in range(3):
    162         a = reduce(operator.mul, distri[i])
    163         print a,
    164         result.append(int(a))
    165        
    166     print
     218        result[i] = int( reduce(operator.mul, distri[i]) )
     219
     220    print result
    167221    return result
    168    
    169    
    170 def GetSourceBBabs():
     222
     223
     224def GetSourceBBabs(opt):
    171225    bbmax = [0.0]*3
    172     bbmin = [0.0]*3
    173    
    174     s_name_ext = os.path.basename(opt_source).rsplit('.',1)
     226    bbmin = [float('inf')]*3
     227
     228    s_name_ext = os.path.basename(opt.source).rsplit('.', 1)
    175229    s_namepart = s_name_ext[0]
    176    
    177     if len(s_name_ext[0])> 1:
     230
     231    if len(s_name_ext) > 1:
    178232        s_ext = s_name_ext[1]
    179233    else:
    180234        s_ext = ''
    181    
    182     # convert from any format to xyz
    183     os.system('molecuilder -o xyz --parse-tremolo-potentials %s -i temp_source.xyz -l %s' % (opt_potentialsfiledir+opt_basename+'.potentials', opt_source))
    184        
     235
     236    # Convert from any format to xyz
     237    os.system('molecuilder -o xyz --parse-tremolo-potentials %s -i temp_source.xyz -l %s' % (opt.potentialsfiledir+opt.basename+'.potentials', opt.source))
     238
     239    # Calculate bounding box from xyz-file
    185240    with open('temp_source.xyz') as f:
    186241        N = int(f.readline())
    187242        comment = f.readline()
    188            
     243
    189244        for i in xrange(N):
    190245            buf = f.readline()
    191246            xyz = buf.split()[1:]
    192            
     247
    193248            for i in range(3):
    194249                bbmax[i] = max(bbmax[i], float(xyz[i]))
     
    196251
    197252    bb = [0.0]*3
    198    
     253
    199254    for i in range(3):
    200         bb[i] = bbmax[i] - bbmin[i]
    201        
    202    
     255        bb[i] = abs(bbmax[i] - bbmin[i])
     256
    203257    os.system('rm temp_source.*')
    204258    return bb
    205259
    206 
    207 ReadSettings()
    208 UpdateSettings()
    209 
    210 
    211 if type(opt_number) == type([]):
    212     nbox = opt_number
     260# Global options with sensible default parameters
     261opt = c_opt()
     262
     263ReadSettings(opt)
     264UpdateSettings(opt)
     265
     266if type(opt.number) == type([]):
     267    # Number is a vector - use it without any modification
     268    nbox = opt.number
    213269else:
    214     if opt_constraint == 'cube':
    215         nbox = FindNearestCube(opt_number)
    216     else:
    217         nbox = FindBestCuboid(opt_number)
     270    if opt.cubicdomain:
     271        nbox = FindBestCube(opt)
     272    else:
     273        nbox = FindBestCuboid(opt)
    218274
    219275avogadro =  6.022143e23
    220 VolumePerMolecule = opt_molarmass / (avogadro * opt_density)
    221 
    222 try:
    223     bb = GetSourceBBabs()
    224     print '======== BBOX:', bb
    225     s = (VolumePerMolecule / (bb[0]*bb[1]*bb[2])) ** (1./3)
    226    
    227     if s < 0:
    228         print 'warning: molecular cells will overlap'
    229    
    230     for i in range(3):
    231         bb[i] = bb[i]*s
     276VolumePerMolecule = opt.molarmass / (avogadro * opt.density)
     277cell = [VolumePerMolecule**(1./3)] * 3
     278
     279if not opt.cubiccell:
     280    try:
     281        bb = GetSourceBBabs(opt)
     282        print '======== BBOX:', bb
     283        # Scaling factor - the molecules bounding box is scaled to fit the volume suiting the density
     284        s = (VolumePerMolecule / (bb[0]*bb[1]*bb[2])) ** (1./3)
     285
     286        if s < 1:
     287            print 'Warning: Molecular cells will overlap.'
     288
     289        for i in range(3):
     290            cell[i] = bb[i]*s
     291    except ZeroDivisionError:
     292        print 'Warning:  Singularity in bounding box, falling back to cubic cell.'
    232293       
    233     cell = bb
    234 except ZeroDivisionError:
    235     print 'warning:  singularity in bounding box, using cubic cell'
    236     cell = [VolumePerMolecule**(1./3)] * 3
    237    
     294
    238295print '======== CELL: ', cell
    239296
     
    241298
    242299mol.CommandVerbose('0')
    243 mol.ParserParseTremoloPotentials(opt_potentialsfiledir+opt_basename+'.potentials')
    244 mol.WorldInput(opt_source)
     300mol.ParserParseTremoloPotentials(opt.potentialsfiledir + opt.basename + '.potentials')
     301mol.WorldInput(opt.source)
    245302mol.WorldCenterInBox('%f 0 0 %f 0 %f' % tuple(cell))
    246303mol.WorldRepeatBox('%d %d %d' % tuple(nbox))
    247 mol.WorldOutput('out.data')
    248 mol.WorldOutput('out.xyz')
     304mol.WorldOutput(opt.outfilename + '.data')
     305mol.WorldOutput(opt.outfilename + '.xyz')
    249306
    250307domain = [0.0]*3
     
    252309for i in range(3):
    253310    domain[i] = cell[i]*nbox[i]
    254    
     311
    255312print  '======== DOMAIN: ', domain
Note: See TracChangeset for help on using the changeset viewer.