示例#1
0
 def createSampleWorkspace(self):
     """ Create a dummy workspace that looks like a sample run"""
     #create a dummy workspace
     function = "name=Lorentzian,Amplitude=1,PeakCentre=5,FWHM=1"
     ws = CreateSampleWorkspace("Histogram", Function="User Defined", UserDefinedFunction=function, XMin=0, XMax=10, BinWidth=0.01, XUnit="DeltaE")
     ws = ScaleX(ws, -5, "Add") #shift to center on 0
     ws = ScaleX(ws, 0.1) #scale to size
     LoadInstrument(ws, InstrumentName='IRIS', RewriteSpectraMap=True)
     return ws
示例#2
0
    def createSampleWorkspace(self):
        function = "name=Lorentzian,Amplitude=1,PeakCentre=5,FWHM=1"

        workspace = CreateSampleWorkspace(WorkspaceType="Histogram",
                                          Function="User Defined",
                                          UserDefinedFunction=function,
                                          XMin=0,
                                          XMax=10,
                                          BinWidth=0.01,
                                          XUnit="DeltaE")

        # Shift to center on 0 and then scale to size
        workspace = ScaleX(workspace, -5, "Add")
        workspace = ScaleX(workspace, 0.1)
        LoadInstrument(Workspace=workspace, InstrumentName='IRIS', RewriteSpectraMap=True)
        return workspace
示例#3
0
def _generate_big_sample_ws(ws_name, n_spec):
    sample_data_x = np.arange(0, 10, 0.01)
    sample_data_y = _rayleigh(sample_data_x, 1)

    data_x = np.empty(0)
    data_y = np.empty(0)
    v_axis = list()
    for idx in range(0, n_spec):
        data_x = np.append(data_x, sample_data_x)
        data_y = np.append(data_y, sample_data_y)
        v_axis.append(str(0.1 * idx))

    # Create the workspace and give it some units
    CreateWorkspace(OutputWorkspace=ws_name,
                    DataX=data_x,
                    DataY=data_y,
                    NSpec=n_spec,
                    UnitX='MomentumTransfer',
                    VerticalAxisUnit='QSquared',
                    VerticalAxisValues=','.join(v_axis))
    # Centre the peak over 0
    ScaleX(InputWorkspace=ws_name,
           Factor=-1,
           Operation="Add",
           OutputWorkspace=ws_name)

    return mtd[ws_name]
示例#4
0
def create_test_ws_and_group():
    myFunc = "name=Gaussian, PeakCentre=2, Height=100, Sigma=0.01;" + \
        "name=Gaussian, PeakCentre=1, Height=100, Sigma=0.01;" + \
        "name=Gaussian, PeakCentre=4, Height=100, Sigma=0.01"
    ws = CreateSampleWorkspace("Event",
                               "User Defined",
                               myFunc,
                               BankPixelWidth=1,
                               XUnit='dSpacing',
                               XMax=5,
                               BinWidth=0.001,
                               NumEvents=100000,
                               NumBanks=8)
    for n in range(1, 5):
        MoveInstrumentComponent(ws,
                                ComponentName=f'bank{n}',
                                X=1 + n / 10,
                                Y=0,
                                Z=1 + n / 10,
                                RelativePosition=False)
        MoveInstrumentComponent(ws,
                                ComponentName=f'bank{n+4}',
                                X=2 + n / 10,
                                Y=0,
                                Z=2 + n / 10,
                                RelativePosition=False)

    MaskDetectors(ws, WorkspaceIndexList=[3, 7])

    ws = ScaleX(ws, Factor=1.05, IndexMin=1, IndexMax=1)
    ws = ScaleX(ws, Factor=0.95, IndexMin=2, IndexMax=2)
    ws = ScaleX(ws, Factor=1.05, IndexMin=4, IndexMax=6)
    ws = ScaleX(ws, Factor=1.02, IndexMin=5, IndexMax=5)
    ws = ScaleX(ws, Factor=0.98, IndexMin=6, IndexMax=6)
    ws = Rebin(ws, '0,0.001,5')
    ws = ConvertUnits(ws, Target='TOF')

    groups, _, _ = CreateGroupingWorkspace(InputWorkspace=ws,
                                           ComponentName='basic_rect',
                                           CustomGroupingString='1-4,5-8')

    return ws, groups
示例#5
0
def modelB_EC_C(model, resolution, convolved, qvalues, assembled, expdata=None, costfile=None):
  """Assemble the Background, Elastic line and Convolution of the resolution with the simulated S(Q,E)
  This is a hard-coded model consisting of a linear background, and elastic line, and a convolution:
    b0+b1*E  +  +EC(Q)*e0*exp(-e1*Q^2)*Elastic(E)  +  c0*Resolution(E)xSimulated(Q,E)
    We load Resolution(E)xSimulated(Q,E) as Convolved(Q,E)
    EC(Q) is a fit to the Q-dependence of the integrated intensity of the empty can
    EC(Q) = 2.174495971 - 2.065826056*Q + 0.845367259*Q^2
    
  Arguments:
    model: beamline model file is a single line, e.g,
           b0=1.3211; b1=0.00 e0=0.99; e1=1.9; c0=2.3
    resolution: Nexus file containing the resolution. This will be used to produce a elastic line.
    convolved: Nexus file containing the convolution of the simulated S(Q,E) with the resolution.
    qvalues: single-column file containing list of Q-values
    assembled: output Nexus file containing the assembled S(Q,E) of the beamline model and the simulated S(Q,E)
    expdata: Optional, experimental nexus file. If passed, output convolved will be binned as expdata.
    costfile: Optional, file to store cost. If passed, the cost of comparing convolved and expdata will be saved.

  Returns:
    workspace containing the assembled S(Q,E)
  """
  import numpy
  from mantid.simpleapi import (LoadNexus, ScaleX, ConvertToPointData, SaveNexus, DakotaChiSquared)
  EC = lambda Q: 2.174495971 - 2.065826056*Q + 0.845367259*Q*Q
  Q=[float(q) for q in open(qvalues,'r').read().split('\n')]
  p={}
  for pair in open(model,'r').readline().split(';'):
    key,val=pair.split('=')
    p[key.strip()]=float(val.strip())
  wsr=LoadNexus(Filename=resolution,OutputWorkspace='resolution')
  wsr=ConvertToPointData(wsr)
  E=wsr.readX(0)
  wse=ScaleX(InputWorkspace=wsr, OutputWorkspace='elastic',factor=-1) # elastic line
  wsc=LoadNexus(Filename=convolved,OutputWorkspace='convolved')
  for i in range(wsc.getNumberHistograms()):
    elastic=wse.readY(i) # elastic spectrum at a given Q
    convolved=wsc.readY(i) # convolved spectrum at a given Q
    wsc.setY(i, (p['b0']+p['b1']*E) + (EC(Q[i])*p['e0']*numpy.exp(-p['e1']*Q[i])*elastic) + (p['c0']*convolved) ) # overwrite spectrum
  SaveNexus(InputWorkspace=wsc, Filename=assembled)
  if expdata and costfile:
    DakotaChiSquared(DataFile=assembled,CalculatedFile=expdata,OutputFile=costfile)
  return wsc
示例#6
0
def _generate_sample_ws(ws_name):
    data_x = np.arange(0, 10, 0.01)
    data_y = _rayleigh(data_x, 1)

    # Create the workspace and give it some units
    CreateWorkspace(OutputWorkspace=ws_name, DataX=data_x, DataY=data_y, \
                    UnitX='MomentumTransfer', VerticalAxisUnit='QSquared', VerticalAxisValues='0.2')
    # Centre the peak over 0
    ScaleX(InputWorkspace=ws_name, Factor=-1, Operation="Add", OutputWorkspace=ws_name)

    return mtd[ws_name]
 def convertToWavenumber(self, ws):
     mev2cm = (constants.elementary_charge / 1000) / (constants.h * constants.c * 100)
     u0 = ws.getAxis(0).getUnit().unitID()
     u1 = ws.getAxis(1).getUnit().unitID()
     if u0 == 'DeltaE' or u1 == 'DeltaE':
         if u0 == 'MomentumTransfer':
             ws = Transpose(ws)
         ws.getAxis(0).setUnit('DeltaE_inWavenumber')
         ws = ScaleX(ws, mev2cm)
         ws = Scale(ws, 1/mev2cm)
         if u0 == 'MomentumTransfer':
             ws = Transpose(ws)
     return ws
示例#8
0
    def add_previous_pulse(w):
        """
        Duplicate the events but shift them by one pulse, then add to
        input workspace

        Parameters
        ----------
        w: Mantid.EventsWorkspace

        Returns
        -------
        Mantid.EventsWorkspace
        """
        pulse_width = 1.e6 / 60  # in micro-seconds
        _t_w = ScaleX(w, Factor=-pulse_width, Operation='Add')
        _t_w = Plus(w, _t_w, OutputWorkspace=w.name())
        return _t_w
示例#9
0
 def _shift_workspace(self, workspace, shift_factor):
     return ScaleX(InputWorkspace=workspace,
                   Factor=shift_factor,
                   OutputWorkspace="__shifted",
                   Operation="Add",
                   StoreInADS=False)
示例#10
0
def modelB_freeE_C(model, resolution, convolved, assembled, expdata=None, costfile=None, derivdata=None, derivexclude=[], doshift=None):
  """Assemble the Background, Elastic line and Convolution of the resolution with the simulated S(Q,E)
  This is a hard-coded model consisting of a linear background, and elastic line, and a convolution:
    b0+b1*E  +  +e0(Q)*Elastic(E)  +  c0*Resolution(E)xSimulated(Q,E)
    We load Resolution(E)xSimulated(Q,E) as Convolved(Q,E)
    e0(Q) are a set of fitting parameters, one for each Q
    
  Arguments:
    model: beamline model file is a single line, e.g,
           b0=1.3211; b1=0.00; e0.0=0.99; e0.1=0.99; e0.2=0.99;...e0.N=0.99; e1=1.9; c0=2.3
    resolution: Nexus file containing the resolution. This will be used to produce a elastic line.
    convolved: Nexus file containing the convolution of the simulated S(Q,E) with the resolution.
    assembled: output Nexus file containing the assembled S(Q,E) of the beamline model and the simulated S(Q,E)
    expdata: Optional, experimental nexus file. If passed, output convolved will be binned as expdata.
    costfile: Optional, file to store cost. If passed, residuals and (optionally) partial derivatives will be stored
    derivdata: Optional, perform analytic derivatives (store in costfile if provided)
    derivexclude: list of fitting parameters for which partial derivatives will not be computed
    doshift: Optional, perform the shift of the model function

  Returns:
    wsm: workspace containing the assembled S(Q,E)
    gradients: dictionary of partial derivatives with respect to model parameters
  """
  import numpy
  from copy import copy,deepcopy
  from mantid.simpleapi import (LoadNexus, ScaleX, ConvertToPointData, SaveNexus, DakotaChiSquared, AddSampleLog)
  from math import sqrt

  def shiftalongX(*kargs,**kwargs):
    """ Function to do the shift along the E-axis. By default, does nothing """
    pass
  import interpX
  if doshift: # replace the dummy function with the real thing
    if doshift in dir(interpX):
      shiftalongX=getattr(__import__('interpX'), doshift)
    else:
      shiftalongX = getattr(__import__('interpX'), 'itp_simple')

  def computemodel(p,wse,wsc):
    """Assemble the model
    Arguments
      p: dictionary with parameter values
      wse: Mantid workspace holding the elastic line
      wsc: Mantid workspace holding the convolution of the resolution and the simulation
    Returns:
      wsm: Mantid workspace holding the resulting model
    """
    from mantid.simpleapi import CloneWorkspace
    wsm=CloneWorkspace(wsc)
    E=wse.readX(0) # energy values, bins boundary values
    Eshifted=(E[1:]+E[:-1])/2 # energy values, center bin values
    for i in range(wsc.getNumberHistograms()):
      elastic=wse.readY(i)   # elastic spectrum at a given Q
      convolved=wsc.readY(i) # convolved spectrum at a given Q
      wsm.setY(i, p['b0']+p['b1']*Eshifted + p['e0.'+str(i)]*elastic + p['c0']*convolved) # overwrite spectrum
    return wsm

  # init list of parameters names for which analytical derivative exists, same order as in the input model file
  derivparnames=[] # filled only if derivdata different than None
  p={}
  for pair in open(model,'r').readline().split(';'):
    key,val=[x.strip() for x in pair.split('=')]
    if derivdata and key not in derivexclude: derivparnames.append(key)
    p[key]=float(val)

  # read various inputs
  wsr=LoadNexus(Filename=resolution,OutputWorkspace='resolution')
  wse=ScaleX(InputWorkspace=wsr, OutputWorkspace='elastic',factor=-1) # elastic line
  wsc=LoadNexus(Filename=convolved,OutputWorkspace='convolved')
  E=wsr.readX(0) # energy values, bins boundary values
  de=E[1]-E[0]   # assume all bins have same bin width
  Eshifted=(E[1:]+E[:-1])/2 # energy values, center bin values
  nhist=wsc.getNumberHistograms()
  nrsl=len(Eshifted)*nhist # number of residuals

  # calculate partial numerical derivative with respect to eshift 
  gradients={}
  if 'eshift' in derivparnames: 
    wsm=computemodel(p,wse,wsc)
    eshiftderiv=(shiftalongX(wsm,p['eshift']+0.5*de,newWorkspace='wsplus') - shiftalongX(wsm,p['eshift']-0.5*de,newWorkspace='wsminus')) / de # forward-backward difference with a 0.5*de step
    gradients['eshift']=numpy.zeros(0)
    for i in range(eshiftderiv.getNumberHistograms()): gradients['eshift'] = numpy.concatenate([gradients['eshift'], eshiftderiv.readY(i)])

  # do eshift of component workspaces
  if doshift: Eshifted-=p['eshift']
  wse=shiftalongX(wse,p['eshift']) # shift the spectrum, does nothing if shiftalongX is the dummy function
  wsc=shiftalongX(wsc,p['eshift']) # shift the spectrum, does nothing if shiftalongX is the dummy function

  # find difference in convolutions with FF1 changed
  if 'FF1' not in derivexclude:
    derivparnames.append('FF1')
    # difference in FF1 workspaces
    convolvedf=convolved.replace('.nxs','_1.nxs')
    wscf=LoadNexus(Filename=convolvedf,OutputWorkspace='convolvedf')
    convolvedb=convolved.replace('.nxs','_0.nxs')
    wscb=LoadNexus(Filename=convolvedb,OutputWorkspace='convolvedb')
    wksp_diff=wscf-wscb
 
  # calculate analytic partial derivatives with respect to the fit parameters
  if derivparnames:
    gradients['b0']=numpy.ones(nrsl)
    gradients['b1']=numpy.zeros(0)
    gradients['c0']=numpy.zeros(0)
    gradients['FF1']=numpy.zeros(0)
    for i in range(nhist):
      gradients['b1'] = numpy.concatenate([gradients['b1'], Eshifted])
      gradients['c0'] = numpy.concatenate([gradients['c0'], wsc.readY(i)])
      if 'FF1' not in derivexclude:
        gradients['FF1'] = numpy.concatenate([gradients['FF1'], wksp_diff.readY(i)])
      gradients['e0.'+str(i)]=numpy.zeros(0)
      for j in range(nhist):
        if i==j: 
          gradients['e0.'+str(i)] = numpy.concatenate([gradients['e0.'+str(i)], wse.readY(i)])
        else:
          gradients['e0.'+str(i)] = numpy.concatenate([gradients['e0.'+str(i)], numpy.zeros(len(Eshifted))])

  if 'FF1' not in derivexclude:
    FF1_f=wscf.getRun().getLogData('FF1').value
    FF1_b=wscb.getRun().getLogData('FF1').value
    gradients['FF1'] *= p['c0']/(FF1_f-FF1_b)

  # save model to file
  wsm=computemodel(p,wse,wsc)
  # add all parameters to assembled file
  for pair in open(model,'r').readline().split(';'):
    key,val=[x.strip() for x in pair.split('=')]
    AddSampleLog(Workspace=wsm,LogName=key,LogText=str(p[key]),LogType='Number')
    print key, "=",  p[key]
  print "FF1 =", wsm.getRun().getLogData('FF1').value

  SaveNexus(InputWorkspace=wsm, Filename=assembled)

  # save residuals and partial derivatives
  buf=''
  if expdata and costfile:
    wex=LoadNexus(Filename=expdata,OutputWorkspace='experiment')
    chisq,wR=DakotaChiSquared(DataFile=expdata,CalculatedFile=assembled,OutputFile=costfile,ResidualsWorkspace='wR')
    Xe=numpy.zeros(0) # list of errors for each residual
    for i in range(nhist):
      Xe = numpy.concatenate([Xe, wex.readE(i)])
      Ry=wR.readY(i)
      for j in range(len(Ry)):
        buf+=str(Ry[j])+" least_sq_term_"+str(i*len(Ry)+j+1)+"\n"
    for parname in derivparnames: gradients[parname]/=numpy.where(Xe>0,Xe,1) # divide by experimental error (with non-positive elements replaced by one)
    if derivparnames:
      for i in range(nrsl):
        buf+="["
        for parname in derivparnames: buf+=" %.10e"%(-gradients[parname][i])
        buf+=" ]\n"
    open(costfile,'w').write(buf)

  AddSampleLog(Workspace=wsm,LogName="chisq",LogText=str(chisq),LogType='Number')
  norm_chisq=chisq/(len(Ry)-len(derivparnames))
  print costfile, " R = ", sqrt(norm_chisq)
  AddSampleLog(Workspace=wsm,LogName="norm_chisq",LogText=str(norm_chisq),LogType='Number')
  AddSampleLog(Workspace=wsm,LogName="norm_chi",LogText=str(sqrt(norm_chisq)),LogType='Number')
  SaveNexus(InputWorkspace=wsm, Filename=assembled)

  return {'model':wsm, 'gradients':gradients}