esrf

Beamline Instrument Software Support
SPEC Macro documentation: [ Macro Index | BCU Home ]

#%TITLE% MXUTILS.MAC
#%NAME% 
#   Utility macros and function for the MX beamlines
#
#%CATEGORY% MX
#

#%END%

#%UU% ([inp])
#%MDESC% Get the MXCOLLECT_PARS paaremeter(s). With no argument returns the
#list of all the existing %B%COLLECT%B% parameters. The input argument
#%B%inp%B% can be a string or an associative array of strings. In both cases
#the return value is either the value of the inp parameter, or an empty string,
#if the specified parameter in not set beforehand. E.g. inp = "mypar" to get
#the MXCOLLECT_PARS[mypar] value; inp[0]="my", inp[1]="par" to get the
#MXCOLLECT_PARS[my][par] value.
def getMxCollectPars(inp) '{
local mask

  mask = 0x01000000

  if ((whatis("inp")&mask) != mask) {
    if (!inp)
      return(MXCOLLECT_PARS)
    if (!(inp in MXCOLLECT_PARS))
      return("")
    else
      return(MXCOLLECT_PARS[inp])
  } else {
    if (!(inp[0] in MXCOLLECT_PARS) && !(inp[1] in MXCOLLECT_PARS[inp[0]]))
      return("")
    else
     return(MXCOLLECT_PARS[inp[0]][inp[1]])
  }
  return("")

}'

#%UU% (inp,val)
#%MDESC%Set the MXCOLLECT_PARS paaremeter %B%inp%B% to a value %B%val%B%. The
#input parameter is a string or an associative array of strings.
def setMxCollectPars(inp,val) '{
local mask

  mask = 0x01000000
  if ((whatis("inp")&mask) != mask) {
    MXCOLLECT_PARS[inp] = val
  } else {
    MXCOLLECT_PARS[inp[0]][inp[1]] = val
  }
}'

#%UU% ([inp])
#%MDESC% Get the MXBCM_PARS paaremeter(s). With no argument returns the
#list of all the existing %B%BCM%B% parameters. The input argument
#%B%inp%B% can be a string or an associative array of strings. In both cases
#the return value is either the value of the inp parameter, or an empty string,
#if the specified parameter in not set beforehand. E.g. inp = "mypar" to get
#the MXBCM_PARS[mypar] value; inp[0]="my", inp[1]="par" to get the
#MXBCM_PARS[my][par] value.
def getMxBcmPars(inp) '{
local mask

  mask = 0x01000000

  if ((whatis("inp")&mask) != mask) {
    if (!inp)
      return(MXBCM_PARS)
    if (!(inp in MXBCM_PARS))
      return("")
    else
      return(MXBCM_PARS[inp])
  } else {
    if (!(inp[0] in MXBCM_PARS) && !(inp[1] in MXBCM_PARS[inp[0]]))
      return("")
    else
     return(MXBCM_PARS[inp[0]][inp[1]])
  }
  return("")

}'

#%UU% (inp,val)
#%MDESC%Set the MXBCM_PARS paaremeter %B%inp%B% to a value %B%val%B%. The
#input parameter is a string or an associative array of strings.
def setMxBcmPars(inp,val) '{
local mask

  mask = 0x01000000
  if ((whatis("inp")&mask) != mask) {
    MXBCM_PARS[inp] = val
  } else {
    MXBCM_PARS[inp[0]][inp[1]] = val
  }
}'

#%UU% ([inp])
#%MDESC% Get the MXSPEC_PARS paaremeter(s). With no argument returns the
#list of all the existing %B%SPEC%B% parameters. The input argument
#%B%inp%B% can be a string or an associative array of strings. In both cases
#the return value is either the value of the inp parameter, or an empty string,
#if the specified parameter in not set beforehand. E.g. inp = "mypar" to get
#the MXSPEC_PARS[mypar] value; inp[0]="my", inp[1]="par" to get the
#MXSPEC_PARS[my][par] value.
def getMxSpecPars(inp) '{
local mask

  mask = 0x01000000

  if ((whatis("inp")&mask) != mask) {
    if (!inp)
      return(MXSPEC_PARS)
    if (!(inp in MXSPEC_PARS))
      return("")
    else
      return(MXSPEC_PARS[inp])
  } else {
    if (!(inp[0] in MXSPEC_PARS) && !(inp[1] in MXSPEC_PARS[inp[0]]))
      return("")
    else
     return(MXSPEC_PARS[inp[0]][inp[1]])
  }
  return("")

}'

#%UU% (inp,val)
#%MDESC%Set the MXSPEC_PARS paaremeter %B%inp%B% to a value %B%val%B%. The
#input parameter is a string or an associative array of strings.
def setMxSpecPars(inp,val) '{
local mask

  mask = 0x01000000
  if ((whatis("inp")&mask) != mask) {
    MXSPEC_PARS[inp] = val
  } else {
    MXSPEC_PARS[inp[0]][inp[1]] = val
  }
}'

#%UU% ()
#%MDESC% Get the wavelength. Returns the current wavelength (for the MAD
#beamlines), the default wavelength or LAMBDA, in case a pseudo motor is set.
def getMxWavelength() '{
local wavelength
local wavmot motnb energymot

  wavmot = getMxSpecPars("wavmot")
  if (wavmot == "LAMBDA")
    return(LAMBDA)
  motnb = motor_num(wavmot)

  if (motnb == -1) {
    energymot = getMxSpecPars("emot")
    motnb = motor_num(energymot)
    if (motnb == -1)
      return(wavmot)
    return(hc_over_e/A[motnb])
  } else {
    return(A[motnb])
  }
}'


def getMxEnergy() '{
  return(hc_over_e/getMxWavelength())
}'


#%UU% ()
#%MDESC% Get the current detector distance. Returns the current distance 
def getMxCurrentDistance() '{
local distance
local  motnb

  motnb = motor_num(getMxSpecPars("detdistmot"))
  if (motnb == -1)
    return(-1)
  else {
    get_angles
    return(A[motnb])
  }
}'

#%UU% ()
#%MDESC% Get the current transmission
def getMxCurrentTransmission() '{
  global ATT_FACTOR
  if (whatis("ATT_FACTOR")>>16&0x0400) {
    if (whatis("ATT_FACTOR")>>16&0x0800) {
    } else {
      MXBCM_PARS["curr_transmission"]=ATT_FACTOR
    }
  }
  return(MXBCM_PARS["curr_transmission"])
}'

#%UU% ()
#%MDESC% Get the maximum exposure for a given transmission
def getMxMaximumExposure() '{
  MXBCM_PARS["maximum_exposure"]= MXSPEC_PARS["maximum_counts"] * \
                                  MXSPEC_PARS["intensity_calibration_constant"] * \
                                  getMxCurrentTransmission()
}'

#%UU% ()
#%MDESC% Get the detector binning mode (if applicable).
def getMxDetectorBinMode() '{
  if (whatis("COLLECT_SEQ[\"detector_mode\"]")>>16&0x8000) {
    print "Binning set by data collection parameters"
  } else {
    print "No binning set by data collection, use default"
    COLLECT_SEQ["detector_mode"] = MXSPEC_PARS["detector"]["binning"]
  }
  return(COLLECT_SEQ["detector_mode"])
}'

#%UU% ()
#%MDESC% Get the detector binning mode (if applicable).
def getMxDetectorFileSuffix() '{
    return MXBCM_PARS["FileSuffix"]
}'

#%IU% (diameter)
#%MDESC% Get the detector resolution.
def getMxResolution(diameter) '{
  wavelength = getMxWavelength()
  distance = dist == 0 ? A[motor_num(getMxSpecPars("detdistmot"))] : dist
  distance = distance/1000
  
  corner_angle = atan(diameter/(2*distance))
  
  tsincorner = 2*sin(0.5*corner_angle)
  
  resAtCorner = wavelength/ tsincorner

  return(resAtCorner)

}'

#%IU% ()
#%MDESC% Get the detectoer resolution in the corners.
def getMxResolutionAtCorner() '{
  diameter = getMxDiameter()/1000
  distToCorner = 2*(diameter/pow(2,0.5))

  return(getMxResolution(distToCorner))
}'

#%IU% ()
#%MDESC% Get the detectoer resolution at half radius.
def getMxResolutionAtHalfCorner() '{
  diameter = getMxDiameter()/1000
  distToHalfCorner = (diameter/2+diameter/pow(2,0.5))

  return(getMxResolution(distToHalfCorner))
}'

def getMxBeamShape(flag) '{
  local shape

  if (MXBCM_PARS["original_beam_shape"]=="circular") {
    bsx = getMxBeamSizeX(flag)
    bsy = getMxBeamSizeY(flag)
    if (bsx!=bsy) {
      MXBCM_PARS["beam_shape"]="elliptical"  
    } else {
      MXBCM_PARS["beam_shape"]="circular"
    } 
  }
  
  shape = MXBCM_PARS["beam_shape"]
  if (shape == 0) { shape = "" }
  return shape
}'

#%IU% ()
#%MDESC% Get the  detector radius.
def _getRadius() '{
  global MXBCM_PARS
  float array tmp[4]

  diameter = 2*getMxBcmPars("detector_radius")

  tmp[0] = diameter - MXBCM_PARS["beam"]["x"]
  tmp[1] = diameter - MXBCM_PARS["beam"]["y"]
  tmp[2] = MXBCM_PARS["beam"]["x"]
  tmp[3] = MXBCM_PARS["beam"]["y"]

  return array_op("min", tmp)
}'

#%IU% ()
#%MDESC% Get the  detector diameter.
def getMxDiameter() '{
  return(2*getMxBcmPars("detector_radius"))
}'


#%IU% ()
#%MDESC% Get current filename (set by the detector macros).
def getMxCurrentFilename() '{
  return MXCOLLECT_PARS["current_filename"]
}'

#%IU% ()
#%MDESC% Set current filename.
def setMxCurrentFilename(file) '{
  setMxCollectPars("current_filename",file)
}'

#%IU% (dist)
#%MDESC%Calculate the resolution as function of the %B%dist%B% from the sample.
def CalculateResolutionFromDistance(dist) '{
  local wavelength diameter radius ttheta resolution detdistmot tmp 

  wavelength = getMxWavelength() 
  radius = _getRadius()

  if (radius == 0) {
    return(0)
  }

  distance = dist == 0 ? A[motor_num(getMxSpecPars("detdistmot"))] : dist
  ttheta = atan( radius / distance )
  resolution = wavelength/(2*sin(ttheta/2))

  return(resolution)
}'

#%IU% (resol)
#%MDESC% Calculate the distance from the sample as function of the %B%resol%B%.
def CalculateDistanceFromResolution(resol) '{
   local wavelength ttheta radius distance resolution

   # should we take the current resolution or the resolution asked for?
   resolution = resol == 0 ? A[res] : resol
   wavelength = getMxWavelength()
   ttheta = 2*asin(wavelength/(2*resolution))
   radius = _getRadius()

   distance = radius / tan(ttheta)
     
   return(distance)
}'

#%IU% ()
#%MDESC% Get current Beam centre for X.
def getMxBeamCentreX() '{
  beam_centre_update()
  return MXBCM_PARS["beam"]["x"]
}'

#%IU% ()
#%MDESC% Get current Beam Centre Y.
def getMxBeamCentreY() '{
  beam_centre_update()
  return MXBCM_PARS["beam"]["y"]
}'

def getMxUndulatorGap(which) '{
  local gap key
  key = sprintf("/beamline_pars/BCM_PARS/undulator[%d]", which)
  gap = -1
  
  if (xml_read("/mxlocal", sprintf("%s/device_uri", key)) >= 0) {
    local out[]
    esrf_io(XML_tmp[0]["__value__"], "DevReadSigValues", out)
    if (xml_read("/mxlocal", sprintf("%s/gap_index", key)) >= 0) {
      gap = out[XML_tmp[0]["__value__"]]
    }  
  }

  return gap
}' 

def getMxUndulatorType(which) '{
  local type key
  key = sprintf("/beamline_pars/BCM_PARS/undulator[%d]", which)
  type = ""

  if (xml_read("/mxlocal", sprintf("%s/type", key)) >= 0) {
    type = XML_tmp[0]["__value__"]
  }

  return type
}'


def getMxKappaValue() '{
  global KAPPA_IN_USE
  motpos = -9999
  if (KAPPA_IN_USE == 1) {
    get_angles
    #kappamot = motor_num(MXBCM_PARS["kappaSpecMne"])
    #if (kappamot != -1) {
    #  motpos = A[kappamot]
    #}
    motpos = A[kap1]
  }
  return motpos
}'

def getMxPhiValue() '{
  get_angles
  return A[phi]
#  global KAPPA_IN_USE
#  motpos = -1
#  if (KAPPA_IN_USE == 1) {
#    phimot = motor_num(MXBCM_PARS["phiSpecMne"])
#    if (phimot != -1) {
#      motpos = A[phimot]
#    } 
#    }
#  }
#  return motpos
}'

def getMxKappaPhiValue() '{
  if (getMxOscillationAxisName() == "Omega") {
    return A[kap2]
  } else {
    return -9999
  }
}'

def getMxOscillationAxisName() '{
  if ((KAPPA_IN_USE == 1) && (fabs(getMxKappaValue()) < 1E6)) {
    return "Omega"
  } else {
    return "Phi"
  }
}'

def getMxSlitGapHorizontal() '{ 
  local x1 x2 xs

  getangles
  x1=A[motor_num(MXSPEC_PARS["slits"]["s1h"])]
  x2=A[motor_num(MXSPEC_PARS["slits"]["s2h"])]
  if (x2<x1) {
    xs = x2
  } else {
    xs = x1
  }
   
  return (xs)
}'

def getMxSlitGapVertical() '{
  local y1 y2 ys

  getangles
  y1=A[motor_num(MXSPEC_PARS["slits"]["s1v"])]
  y2=A[motor_num(MXSPEC_PARS["slits"]["s2v"])]
  if (y2<y1) {
    ys = y2
  } else {
    ys = y1
  }
  return(ys)
}'

cdef ("local_get_beamsize","","_beamsize")

def getMxBeamSizeX(dont_get_beamsize) '{
  local slit_size
  local ret

  if (! dont_get_beamsize) {
    local_get_beamsize
  }

  if (MXSPEC_PARS["beamsize"]["x"] > 0) {
    if ((MXSPEC_PARS["beamsize"]["max_hor"]>0) && (MXSPEC_PARS["beamsize"]["x"] > MXSPEC_PARS["beamsize"]["max_hor"])) {
      ret = MXSPEC_PARS["beamsize"]["max_hor"]
    } else {
      ret = MXSPEC_PARS["beamsize"]["x"]
    }
    if (ret > 1) {
      # we are in microns, ISPyB wants millimeters
      return ret/1000.0
    } else {
      return ret
    }
  } else {
    slit_size = getMxSlitGapHorizontal()
  
    if (slit_size <= MXSPEC_PARS["beamsize"]["max_hor"]) {
      return slit_size
    } else {
      return MXSPEC_PARS["beamsize"]["max_hor"]
    }
  }
}'

def getMxBeamInfo() '{
  return ["size_x": getMxBeamSizeX(), "size_y": getMxBeamSizeY(1), "shape": getMxBeamShape(1)]
}'

def getMxBeamSizeY(dont_get_beamsize)  '{  
  local slit_size
  local ret

  if (! dont_get_beamsize) {
    local_get_beamsize
  }

  if (MXSPEC_PARS["beamsize"]["y"] > 0) {
    if ((MXSPEC_PARS["beamsize"]["max_ver"]>0) && (MXSPEC_PARS["beamsize"]["y"] > MXSPEC_PARS["beamsize"]["max_ver"])) {
      ret = MXSPEC_PARS["beamsize"]["max_ver"]
    } else {
      ret = MXSPEC_PARS["beamsize"]["y"]
    }
    if (ret > 1) {
      # we are in microns, ISPyB wants millimeters
      return ret/1000.0
    } else {
      return ret
    }
  } else {
    slit_size = getMxSlitGapVertical()

    if (slit_size <= MXSPEC_PARS["beamsize"]["max_ver"]) {
      return slit_size
    } else {
      return MXSPEC_PARS["beamsize"]["max_ver"]
    }
  }
}'

cdef ("local_get_totals","","_totals")

def getMxTotalParams() '{
  MXCOLLECT_PARS["tot_exposure_time"] = 0
  MXCOLLECT_PARS["tot_range"] = 0

  local_get_totals
  if (MXCOLLECT_PARS["tot_exposure_time"] == 0) {
    MXCOLLECT_PARS["tot_exposure_time"] = \
	(COLLECT_SEQ["exposure_time"] + 0.003)*COLLECT_SEQ["number_of_images"]
  }
  if (MXCOLLECT_PARS["tot_range"] == 0) {
    MXCOLLECT_PARS["tot_range"] = \
	COLLECT_SEQ["range"]*COLLECT_SEQ["number_of_images"]
  }
}'

#%UU% ()
#%MDESC% calculate the latest beam centre given the current detector distance
def beam_centre_update() '{
  global MXSPEC_PARS MXBCM_PARS
  local AXBeam AYBeam BXBeam BYBeam XBeam YBeam
  AXBeam = MXSPEC_PARS["beam"]["ax"]
  AYBeam = MXSPEC_PARS["beam"]["ay"]
  BXBeam = MXSPEC_PARS["beam"]["bx"]
  BYBeam = MXSPEC_PARS["beam"]["by"]

  if ( !(AXBeam == 0 || BXBeam == 0 )) {
    # Calculate correct X and Y beam position to be put into the header
    get_angles
    XBeam = (AXBeam * A[motor_num(MXSPEC_PARS["detdistmot"])]) + BXBeam
    YBeam = (AYBeam * A[motor_num(MXSPEC_PARS["detdistmot"])]) + BYBeam
  
  } else {
    egui_logmsg(sprintf("Warning:The beam centre is NOT calibrated, one of AXBeam (%6.6f),BXBeam (%6.2f),AYBeam (%6.6f),BYBeam (%6.2f) are 0",AXBeam,BXBeam,AYBeam,BYBeam))
    return -1
  }
  # These variables can be used by other spec macros, so update them
  MXBCM_PARS["beam"]["x"]=XBeam
  MXBCM_PARS["beam"]["y"]=YBeam

  if (XBeam == 0 || YBeam == 0) {
    egui_logmsg("One or both of the beam centre parameters are 0")
    return -1
  }
  return 1
}'

#%UU% ()
#%MDESC% Initialise the MXCOLLECT_PARS, MXBCM_PARS and MXSPEC_PARS with the
#default values (generic and beamline specific).
def pars_init() '{
  # common parameters go here, local parameters go in mxlocal
  # so far I do not know any common parameters...
  # not even the detector distance motor name. 
  local_pars_init()

  beam_centre_update()
}'

def local_pars_init() '{
  if (xml_read("/mxlocal", "/beamline_pars") != 0) {
    printf("Could not read MX local beamline parameters in file %s:\n  -> %s\n", "/mxlocal", XML_tmp["__error__"])
    exit
  }

  local tmp[] tmp2[] i n
  n = split(XML_tmp[0]["__children__"], tmp)

  for (i=0;i<n;i++) {
    split(tmp[i], tmp2, ":")

    _mxlocal_read_pars(sprintf("MX%s", tmp2[0]), tmp2[1])
  }

  # I do not like very much the following :
  MXBCM_PARS["maximum_exposure"]= MXSPEC_PARS["maximum_counts"] * \
                                  MXSPEC_PARS["intensity_calibration_constant"] * \
                                  getMxCurrentTransmission()

  # save original beam shape (from XML file)
  MXBCM_PARS["original_beam_shape"]=MXBCM_PARS["beam_shape"]

}'


def _mxlocal_read_pars(name, path) '{
  local tmp0[] k name2 
  
  unglobal @name
  global @name[]
  name2 = sprintf("_%s", name)
  unglobal @name2
  global @name2
 
  if (xml_readProperties("/mxlocal", path) >= 0) {
    tmp0=asso_keys(XML_tmp)

    for (k in tmp0) {
      @name[k] = XML_tmp[k]["__value__"]
      @name2[k] = XML_tmp[k]["__path__"]
    }
  }

  if (xml_read("/mxlocal", path) != 0) {
    printf("Could not read parameters under %s:\n  -> %s\n", path, XML_tmp["__error__"])
    return
  }

  local tmp[] tmp2[] i childnamee childpathh
  n = split(XML_tmp[0]["__children__"], tmp)

  for (i=0;i<n;i++) {
    split(tmp[i], tmp2, ":")

    childname = tmp2[0]
    childpath = tmp2[1]

    if (!(childname in @name)) {
      if (xml_readProperties("/mxlocal", childpath) != 0) {
        printf("Could not read parameters under %s:\n  -> %s\n", childpath, XML_tmp["__error__"])
        return
      }

      tmp0 = asso_keys(XML_tmp)
      for (k in tmp0) {
        @name[childname][k]=XML_tmp[k]["__value__"]
	@name2[childname][k]=XML_tmp[k]["__path__"]
      }
    }
  }
}'


def local_pars_commit() '{
  local tmp[] tmp2[] i n name name2

  if (xml_read("/mxlocal", "/beamline_pars") != 0) {
    printf("Could not read MX local beamline parameters in file %s:\n  -> %s\n", "/mxlocal", XML_tmp["__error__"])
    exit
  }

  n = split(XML_tmp[0]["__children__"], tmp)

  for (i=0;i<n;i++) {
    split(tmp[i], tmp2, ":")

    name = sprintf("MX%s", tmp2[0])
    name2 = sprintf("_MX%s", tmp2[0])

    if ((whatis(name)&0x05)&&(whatis(name2)&0x05)) {
      for (k in @name) {
        xml_cache_write("/mxlocal", @name2[k], @name[k]) 
      }  
    }
  }  
 
  xml_do_write()
}'


def check_beam() '{
  local countdown
  if ((countdown = mi_refilltime()) != -1) {
    if (countdown < 300) {
      print "beam checking: next refill in less than 5 minutes, aborting"
      egui_fatal("beam checking: next refill in less than 5 minutes, aborting")
      exit
    }
  } else {
    egui_logmsg("WARNING: COULD NOT CHECK FOR BEAM, CANNOT COMMUNICATE WITH FRONTEND DEVICE SERVER")
    printf("WARNING: COULD NOT CHECK FOR BEAM, CANNOT COMMUNICATE WITH FRONTEND DEVICE SERVER\n")
    return(-1)
  }

  return(0)
}'

#%MACROS%
#%IMACROS%
#%TOC%
#%AUTHOR% BLISS%BR%
#$Revision: 3.28 $ $Date: 2013/02/05 13:28:17 $%BR%
#%END%
#%LOG%
#$Log: mxutils.mac,v $
#Revision 3.28  2013/02/05 13:28:17  guijarro
#removed calls to getangles
#
#Revision 3.27  2012/05/11 07:31:27  witsch
#old macros still use esrf_io(FEIDDEV...
#
#_read_mach_current()
#
#called by check_beam()
#
#delete the first and make the second use mi_refilltime()
#
#Revision 1.25  2012/05/11 07:25:45  witsch
#old macros still use esrf_io(FEIDDEV...
#
#_read_mach_current()
#
#called by check_beam()
#
#delete the first and make the second use mi_refilltime()
#
#Revision 1.24  2011/02/25 18:54:17  guijarro
#added getMxBeamInfo() function, to get beam shape and size in one call
#
#Revision 1.23  2010/09/09 13:05:45  beteva
#added getMxTotalParams() to be used by the shutterless datacollection
#
#Revision 1.21  2010/03/29 07:45:40  guijarro
#added code for beamline parameters
#
#Revision 1.20  2010/02/09 15:52:40  blissadm
#do the right thing for undulator type and gaps
#
#Revision 1.19  2009/11/05 16:30:40  beteva
#changed getMxBeamSizeX and getMxBeamSizeY to cope with an aperture.
#
#Revision 1.18  2008/08/12 14:39:32  rey
#documentation changes
#
#Revision 1.17  2008/07/28 12:21:36  guijarro
#display fatal and log error messages in mxCuBE when check_beam fails
#
#Revision 1.16  2008/07/09 15:14:09  guijarro
#added functions to check for refill (check_beam() )
#
#Revision 1.15  2008/07/08 13:34:57  guijarro
#new getMxBeamSizeX and getMxBeamSizeY functions ;
#need a new 'beamsize' section in mxlocal.xml
#
#Revision 1.14  2008/05/22 13:42:06  guijarro
#added missing { }
#
#Revision 1.13  2008/04/29 14:27:15  gabadinh
#minor bug fix
#
#Revision 1.12  2008/04/16 12:56:19  gabadinh
#if no wavelength motor defined, tries to find the wavelength with the energy motor
#
#Revision 1.11  2008/04/15 08:54:51  spruce
#remove the check for aybeam and bybeam being 0 because if the beamlines
#are really well aligned it should be possible to have a 0 value
#
#Revision 1.10  2008/01/17 16:41:47  blissadm
#added halfcorner calculation, just in case we want to display it in mxcube
#
#Revision 1.8  2007/11/02 09:09:54  guijarro
#compatibility with beamlines with no undulators (like BM14)
#
#Revision 1.7  2007/10/03 13:19:30  spruce
#small bug fix
#
#Revision 1.6  2007/10/03 13:15:46  spruce
#*** empty log message ***
#
#Revision 1.5  2007/10/03 13:14:10  spruce
#added methods for 1.38 mxcollect.mac
#
#Revision 1.4  2006/09/26 12:46:27  spruce
#revise getDetectorBinningmode function
#
#Revision 1.3  2006/07/05 11:43:16  guijarro
#added local_pars_commit
#
#Revision 1.2  2006/07/04 12:55:49  guijarro
#added local_pars_init (reads mxlocal XML file, and creates associative arrays in Spec)
#
#Revision 1.1  2006/04/11 14:10:27  guijarro
#Initial revision
#