py4sci

Source code for cern.madx

#-------------------------------------------------------------------------------
# This file is part of PyMad.
# 
# Copyright (c) 2011, CERN. All rights reserved.
# 
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
# 	http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#-------------------------------------------------------------------------------

#cython: embedsignature=True

'''
.. module:: madx
.. moduleauthor:: Yngve Inntjore Levinsen <Yngve.Inntjore.Levinsen.at.cern.ch>

Main module to interface with Mad-X library.

'''


import os,sys
import collections
import cern.pymad.globals
from cern.libmadx import _madx_tools

_madstarted=False

# I think this is deprecated..
_loaded_models=[]

# private utility functions
def _tmp_filename(operation):
    """
    Create a name for a temporary file.
    """
    tmpfile = operation + '.temp.tfs'
    i = 0
    while os.path.isfile(tmpfile):
        tmpfile = operation + '.' + str(i) + '.temp.tfs'
        i += 1
    return tmpfile

# main interface
[docs]class madx: ''' Python class which interfaces to Mad-X library ''' def __init__(self,histfile='',recursive_history=False): ''' Initializing Mad-X instance :param str histfile: (optional) name of file which will contain all Mad-X commands. :param bool recursive_history: If true, history file will contain no calls to other files. Instead, recursively writing commands from these files when called. ''' global _madstarted if not _madstarted: madx_start() _madstarted=True if histfile: self._hist=True self._hfile=file(histfile,'w') self._rechist=recursive_history elif cern.pymad.globals.MAD_HISTORY_BASE: base=cern.pymad.globals.MAD_HISTORY_BASE self._hist=True i=0 while os.path.isfile(base+str(i)+'.madx'): i+=1 self._hfile=file(base+str(i)+'.madx','w') self._rechist=recursive_history else: self._hist=False if recursive_history: print("WARNING: you cannot get recursive history without history file...") self._rechist=False def __del__(self): ''' Closes history file madx_finish should not be called since other objects might still be running.. ''' if self._rechist: self._hfile.close() #madx_finish()
[docs] def command(self,cmd): ''' Send a general Mad-X command. Some sanity checks are performed. :param string cmd: command ''' cmd=_madx_tools._fixcmd(cmd) if type(cmd)==int: # means we should not execute command return cmd if type(cmd)==list: for c in cmd: self._single_cmd(c) else: self._single_cmd(cmd)
def _single_cmd(self,cmd): if self._hist: if cmd[-1]=='\n': self._writeHist(cmd) else: self._writeHist(cmd+'\n') if _madx_tools._checkCommand(cmd.lower()): madx_input(cmd) return 0
[docs] def help(self,cmd=''): if cmd: print("Information about command: "+cmd.strip()) cmd='help,'+cmd else: cmd='help' print("Available commands in Mad-X: ") self.command(cmd)
[docs] def call(self,filename): ''' Call a file :param string filename: Name of input file to call ''' fname=filename if not os.path.isfile(fname): fname=filename+'.madx' if not os.path.isfile(fname): fname=filename+'.mad' if not os.path.isfile(fname): print("ERROR: "+filename+" not found") return 1 cmd='call,file="'+fname+'"' self.command(cmd) ## # @brief run select command for a flag.. # @param flag [string] the flag to run select on # @param pattern [list] the new pattern # @param columns [list/string] the columns you want for the flag
[docs] def select(self,flag,columns,pattern=[]): self.command('SELECT, FLAG='+flag+', CLEAR;') if type(columns)==list: clms=', '.join(columns) else: clms=columns self.command('SELECT, FLAG='+flag+', COLUMN='+clms+';') for p in pattern: self.command('SELECT, FLAG='+flag+', PATTERN='+p+';')
[docs] def twiss(self, sequence, pattern=['full'], columns='name,s,betx,bety,x,y,dx,dy,px,py,mux,muy,l,k1l,angle,k2l', madrange='', fname='', retdict=False, betx=None, bety=None, alfx=None, alfy=None, twiss_init=None, chrom=True, use=True ): ''' Runs select+use+twiss on the sequence selected :param string sequence: name of sequence :param string fname: name of file to store tfs table :param list pattern: pattern to include in table :param list/string columns: columns to include in table :param bool retdict: if true, returns tables as dictionary types :param dict twiss_init: dictionary of twiss initialization variables :param bool use: Call use before aperture. :param bool chrom: Also calculate chromatic functions (slower) ''' self.select('twiss',pattern=pattern,columns=columns) self.command('set, format="12.6F";') if use: self.use(sequence) _tmpcmd='twiss, sequence='+sequence+','+_madx_tools._add_range(madrange) if chrom: _tmpcmd+=',chrom' if _tmpcmd[-1]==',': _tmpcmd=_tmpcmd[:-1] if fname: # we only need this if user wants the file to be written.. _tmpcmd+=', file="'+fname+'"' for i_var,i_val in {'betx':betx,'bety':bety,'alfx':alfx,'alfy':alfy}.items(): if i_val!=None: _tmpcmd+=','+i_var+'='+str(i_val) if twiss_init: for i_var,i_val in twiss_init.items(): if i_var not in ['name','closed-orbit']: if i_val==True: _tmpcmd+=','+i_var else: _tmpcmd+=','+i_var+'='+str(i_val) self.command(_tmpcmd+';') return table.get_dict_from_mem('twiss',columns,retdict)
[docs] def survey(self, sequence, pattern=['full'], columns='name,l,s,angle,x,y,z,theta', madrange='', fname='', retdict=False, use=True ): ''' Runs select+use+survey on the sequence selected :param string sequence: name of sequence :param string fname: name of file to store tfs table :param list pattern: pattern to include in table :param string/list columns: Columns to include in table :param bool retdict: if true, returns tables as dictionary types :param bool use: Call use before survey. ''' tmpfile = fname or _tmp_filename('survey') self.select('survey',pattern=pattern,columns=columns) self.command('set, format="12.6F";') if use: self.use(sequence) self.command('survey,'+_madx_tools._add_range(madrange)+' file="'+tmpfile+'";') tab,param=_madx_tools._get_dict(tmpfile,retdict) if not fname: os.remove(tmpfile) return tab,param
[docs] def aperture(self, sequence, pattern=['full'], madrange='', columns='name,l,angle,x,y,z,theta', offsets='', fname='', retdict=False, use=False ): ''' Runs select+use+aperture on the sequence selected @param sequence [string] name of sequence @param fname [string,optional] name of file to store tfs table @param pattern [list, optional] pattern to include in table @param columns [string or list, optional] columns to include in table :param bool retdict: if true, returns tables as dictionary types :param bool use: Call use before aperture. ''' tmpfile = fname or _tmp_filename('aperture') self.select('aperture',pattern=pattern,columns=columns) self.command('set, format="12.6F";') if use: print "Warning, use before aperture is known to cause problems" self.use(sequence) # this seems to cause a bug? _cmd='aperture,'+_madx_tools._add_range(madrange)+_madx_tools._add_offsets(offsets) if fname: _cmd+=',file="'+fname+'"' self.command(_cmd) return table.get_dict_from_mem('aperture',columns,retdict)
[docs] def use(self,sequence): self.command('use, sequence='+sequence+';')
[docs] def match( self, sequence, constraints, vary, weight=None, method=['lmdif'], fname='', betx=None, bety=None, alfx=None, alfy=None, twiss_init=None, retdict=False): """ Perform match operation. @param sequence [string] name of sequence @param constraints [list] constraints to pose during matching @param vary [list or dict] vary commands @param weight [dict] weights for matching parameters Each item of constraints must be a list or dict directly passable to _mad_command(). If vary is a list each entry must either be list or a dict which can be passed to _mad_command(). Otherwise the value is taken to be the NAME of the variable. If vary is a dict the key corresponds to the NAME. Its value is a list or dict passable to _mad_command(). If this is not the case the value is taken as the STEP value. Examples: >>> m.match( >>> 'lhc', >>> constraints=[{'betx':3, 'range':'#e'}, [('bety','<',3)]], >>> vary=['K1', {'name':'K2', 'step':1e-6}], >>> weight=dict(betx=1, bety=2), >>> method=['lmdif', dict(calls=100, tolerance=1e-6)] >>> ) Is equivalent to: match, sequence=lhc; constraint, betx=3, range=#e; constraint, bety<3; vary, name=K1; vary, name=K2, step=1e-6; weight, betx=1, bety=2; lmdif, calls=100, tolerance=1e-6; endmatch; >>> m.match( >>> 'lhc', >>> [{'betx':3, 'range':'#e'}], >>> {'K1': {'upper':3}, 'K2':1e-6}) >>> Is equivalent to: match, sequence=lhc; constraint, betx=3, range=#e; vary, name=K1, upper=3; vary, name=K2, step=1e-6; endmatch; """ tmpfile = fname or _tmp_filename('match') if not twiss_init: twiss_init = {} for k,v in {'betx':betx,'bety':bety,'alfx':alfx,'alfy':alfy}.items(): if v is not None: twiss_init[k] = v # MATCH (=start) cmd = _madx_tools._mad_command('match', ('sequence', sequence), **twiss_init) # CONSTRAINT assert isinstance(constraints, collections.Sequence) for c in constraints: cmd += _madx_tools._mad_command_unpack('constraint', c) # VARY if isinstance(vary, collections.Mapping): for k,v in vary.items(): try: cmd += _madx_tools._mad_command_unpack('vary', v, name=k) except TypeError: cmd += _madx_tools._mad_command('vary', name=k, step=v) elif isinstance(vary, collections.Sequence): for v in vary: try: cmd += _madx_tools._mad_command_unpack('vary', v) except TypeError: cmd += _madx_tools._mad_command('vary', name=v) else: raise TypeError("vary must be list or dict.") # WEIGHT if weight: cmd += _madx_tools._mad_command_unpack('weight', weight) # METHOD cmd += _madx_tools._mad_command_unpack(method) # ENDMATCH cmd += _madx_tools._mad_command('endmatch', knobfile=tmpfile) self.command(cmd) result,initial=_madx_tools._read_knobfile(tmpfile, retdict) if not fname: os.remove(tmpfile) return result,initial # turn on/off verbose outupt..
[docs] def verbose(self,switch): if switch: self.command("option, echo, warn, info") else: self.command("option, -echo, -warn, -info")
def _writeHist(self,command): # this still brakes for "multiline commands"... if self._rechist and command.split(',')[0].strip().lower()=='call': cfile=command.split(',')[1].strip().strip('file=').strip('FILE=').strip(';\n').strip('"').strip("'") if sys.flags.debug: print("DBG: call file ",cfile) fin=file(cfile,'r') for l in fin: self._writeHist(l+'\n') else: self._hfile.write(command) self._hfile.flush()
[docs] def get_sequences(self): ''' Returns the sequences currently in memory ''' ret={} return ret #print "Currently number of sequenses available:",seqs.curr #print "Name of list:",seqs.name