Beispiel #1
0
    def compute_volume(self, pressure=0., temperature=0.):
        """
      Computes the unit cell volume of the material.
      It can compute volumes at different pressures and temperatures.

      Keywords:
         pressure:
            The pressure in GPa.  If not present then the pressure is
            assumed to be 0.
            
         temperature:
            The temperature in K.  If not present or zero, then the
            temperature is assumed to be 298K, i.e. room temperature.
            
      Procedure:
         This procedure computes the unit cell volume.  It starts with the
         volume read from the JCPDS file or computed from the zero-pressure,
         room temperature lattice constants.  It does the following:
            1) Corrects K0 for temperature if DK0DT is non-zero.
            2) Computes volume at zero-pressure and the specified temperature
               if ALPHAT0 is non-zero.
            3) Computes the volume at the specified pressure if K0 is non-zero.
               The routine uses the IDL function FX_ROOT to solve the third
               order Birch-Murnaghan equation of state.
               
      Example:
         Compute the unit cell volume of alumina at 100 GPa and 2500 K.
         j = jcpds()
         j.read_file('alumina.jcpds')
         j.compute_volume(100, 2500)
         
      """

        # Assume 0 K really means room T
        if (temperature == 0): temperature = 298.
        # Compute values of K0, K0P and alphat at this temperature
        self.alphat = self.alphat0 + self.dalphadt * (temperature - 298.)
        self.k0p = self.k0p0 + self.dk0pdt * (temperature - 298.)

        if (pressure == 0.):
            self.v = self.v0 * (1 + self.alphat * (temperature - 298.))
        else:
            if (self.k0 <= 0.):
                print 'K0 is zero, computing zero pressure volume'
                self.v = self.v0
            else:
                self.mod_pressure = pressure - \
                                        self.alphat*self.k0*(temperature-298.)
                v0_v = CARSMath.newton(self.bm3_inverse, 1.)
                self.v = self.v0 / v0_v
Beispiel #2
0
   def compute_volume(self, pressure=0., temperature=0.):
      """
      Computes the unit cell volume of the material.
      It can compute volumes at different pressures and temperatures.

      Keywords:
         pressure:
            The pressure in GPa.  If not present then the pressure is
            assumed to be 0.
            
         temperature:
            The temperature in K.  If not present or zero, then the
            temperature is assumed to be 298K, i.e. room temperature.
            
      Procedure:
         This procedure computes the unit cell volume.  It starts with the
         volume read from the JCPDS file or computed from the zero-pressure,
         room temperature lattice constants.  It does the following:
            1) Corrects K0 for temperature if DK0DT is non-zero.
            2) Computes volume at zero-pressure and the specified temperature
               if ALPHAT0 is non-zero.
            3) Computes the volume at the specified pressure if K0 is non-zero.
               The routine uses the IDL function FX_ROOT to solve the third
               order Birch-Murnaghan equation of state.
               
      Example:
         Compute the unit cell volume of alumina at 100 GPa and 2500 K.
         j = jcpds()
         j.read_file('alumina.jcpds')
         j.compute_volume(100, 2500)
         
      """

      # Assume 0 K really means room T
      if (temperature == 0): temperature=298.
      # Compute values of K0, K0P and alphat at this temperature
      self.alphat = self.alphat0 + self.dalphadt*(temperature-298.)
      self.k0p = self.k0p0 + self.dk0pdt*(temperature-298.)

      if (pressure == 0.):
       	 self.v = self.v0 * (1 + self.alphat*(temperature-298.))
      else:
         if (self.k0 <= 0.):
            print 'K0 is zero, computing zero pressure volume'
            self.v = self.v0
         else:
            self.mod_pressure = pressure - \
                                    self.alphat*self.k0*(temperature-298.)
            v0_v = CARSMath.newton(self.bm3_inverse, 1.)
            self.v = self.v0/v0_v
Beispiel #3
0
 def menu_do_fit(self):
    """ Private method """
    degree = self.widgets.fit_type.index(
                              self.widgets.fit_type.getcurselection()) + 1
    use = []
    for i in range(self.nrois):
       if (self.roi[i].use): use.append(i)
    nuse = len(use)
    if ((degree == 1) and (nuse < 2)):
       tkMessageBox.showerror(title='mcaCalibateEnergy Error', 
          message='Must have at least two valid points for linear calibration')
       return
    elif ((degree == 2) and (nuse < 3)):
       tkMessageBox.showerror(title='mcaCalibateEnergy Error', 
          message='Must have at least three valid points for quadratic calibration')
       return
    chan=Numeric.zeros(nuse, Numeric.Float)
    energy=Numeric.zeros(nuse, Numeric.Float)
    weights=Numeric.ones(nuse, Numeric.Float)
    for i in range(nuse):
       chan[i] = self.roi[use[i]].centroid
       energy[i] = self.roi[use[i]].energy
    coeffs = CARSMath.polyfitw(chan, energy, weights, degree)
    self.calibration.offset = coeffs[0]
    self.widgets.cal_offset.setentry(str(self.calibration.offset))
    self.calibration.slope = coeffs[1]
    self.widgets.cal_slope.setentry(str(self.calibration.slope))
    if (degree == 2):
       self.calibration.quad = coeffs[2]
    else:
       self.calibration.quad = 0.0
    self.widgets.cal_quad.setentry(str(self.calibration.quad))
    self.mca.set_calibration(self.calibration)
    for i in range(self.nrois):
       energy_diff = (self.roi[i].energy -
                      self.mca.channel_to_energy(self.roi[i].centroid))
       self.widgets.energy_diff[i].configure(text=('%.4f' % energy_diff))
       # Recompute FWHM
       self.roi[i].fwhm = (self.mca.channel_to_energy(self.roi[i].centroid + 
                                 self.fwhm_chan[i]/2.) - 
                         self.mca.channel_to_energy(self.roi[i].centroid -
                                 self.fwhm_chan[i]/2.))
       self.widgets.fwhm[i].configure(text=('%.3f' % self.roi[i].fwhm))
    def __init__(self, mca, command=None):
        """
      Creates a new GUI window for calibrating 2-theta for an Mca object.

      Inputs:
         mca:
            An Mca instance to be calibrated.  The Mca must have at least 1
            Regions of Interest (ROI) defined.

      Keywords:
         command:
            A callback command that will be executed if the OK button on
            the GUI window is pressed.  The callback will be invoked as:
               command(exit_status)
            where exit_status is 1 if OK was pressed, and 0 if Cancel was
            pressed or the window was closed with the window manager.

      Procedure:
         The calibration is done by determining the centroid position and
         d-spacing of each ROI.

         The centroids positions are computed by fitting the
         ROI counts to a Gaussian, using CARSMath.fit_gaussian.

         The d-spacing the ROI can be entered manually in the GUI window, or it
         can be determined automatically if the label of the ROI can be
         successfully used in jcpds.lookup_jcpds_line().

         Each ROI can be selectively used or omitted when doing the calibration.

         The errors in the 2-theta calibration, can be plotted using BltPlot.
      """
        self.input_mca = mca
        self.mca = copy.deepcopy(mca)
        self.exit_command = command
        self.roi = self.mca.get_rois()
        self.nrois = len(self.roi)
        if (self.nrois < 1):
            tkMessageBox.showerror(
                title='mcaCalibrate2theta Error',
                message='Must have at least one ROI to perform calibration')
            return
        self.calibration = self.mca.get_calibration()
        self.fwhm_chan = Numeric.zeros(self.nrois, Numeric.Float)
        self.two_theta = Numeric.zeros(self.nrois, Numeric.Float)
        self.widgets = mcaCalibrate2theta_widgets(self.nrois)
        self.data = self.mca.get_data()

        # Compute the centroid and FWHM of each ROI
        for i in range(self.nrois):
            left = self.roi[i].left
            right = self.roi[i].right
            total_counts = self.data[left:right + 1]
            n_sel = right - left + 1
            sel_chans = left + Numeric.arange(n_sel)
            left_counts = self.data[left]
            right_counts = self.data[right]
            bgd_counts = (left_counts + Numeric.arange(float(n_sel)) /
                          (n_sel - 1) * (right_counts - left_counts))
            net_counts = total_counts - bgd_counts
            net = Numeric.sum(net_counts)

            if ((net > 0.) and (n_sel >= 3)):
                amplitude, centroid, fwhm = CARSMath.fit_gaussian(
                    sel_chans, net_counts)
                self.roi[i].centroid = centroid
                self.fwhm_chan[i] = fwhm
            else:
                self.roi[i].centroid = (left + right) / 2.
                self.fwhm_chan[i] = right - left
            self.roi[i].fwhm = (
                self.mca.channel_to_energy(self.roi[i].centroid +
                                           self.fwhm_chan[i] / 2.) -
                self.mca.channel_to_energy(self.roi[i].centroid -
                                           self.fwhm_chan[i] / 2.))
            self.roi[i].energy = self.mca.channel_to_energy(
                self.roi[i].centroid)

        self.widgets.top = t = Pmw.Dialog(command=self.menu_ok_cancel,
                                          buttons=('OK', 'Apply', 'Cancel'),
                                          title='mcaCalibrate2theta')
        top = t.component('dialogchildsite')
        box = Frame(top, borderwidth=1, relief=SOLID)
        box.pack(fill=X, pady=3)

        t = Label(box, text='ROI')
        t.grid(row=0, column=0)
        t = Label(box, text='Use?')
        t.grid(row=0, column=1)
        t = Label(box, text='Energy')
        t.grid(row=0, column=2)
        t = Label(box, text='FWHM')
        t.grid(row=0, column=3)
        t = Label(box, text='D-spacing')
        t.grid(row=0, column=4)
        t = Label(box, text='HKL')
        t.grid(row=0, column=5)
        t = Label(box, text='Two-theta')
        t.grid(row=0, column=6)
        t = Label(box, text='Two-theta diff.')
        t.grid(row=0, column=7)
        text_width = 10
        for i in range(self.nrois):
            row = i + 1
            t = Label(box, text=str(i))
            t.grid(row=row, column=0)
            self.widgets.use_flag[i] = t = Pmw.OptionMenu(
                box,
                items=('No', 'Yes'),
                initialitem=self.roi[i].use,
                command=lambda e, s=self, r=i: s.menu_use(e, r))
            t.grid(row=row, column=1)
            self.widgets.energy[i] = t = Pmw.EntryField(
                box,
                value=('%.3f' % self.roi[i].energy),
                entry_width=text_width,
                entry_justify=CENTER,
                command=lambda s=self, r=i: s.menu_energy(r))
            t.grid(row=row, column=2)
            self.widgets.fwhm[i] = t = Label(box,
                                             text=('%.3f' % self.roi[i].fwhm),
                                             width=text_width,
                                             justify=CENTER,
                                             borderwidth=1,
                                             relief=SOLID)
            t.grid(row=row, column=3)
            d = jcpds.lookup_jcpds_line(self.roi[i].label)
            if (d != None): self.roi[i].d_spacing = d
            self.widgets.d_spacing[i] = t = Pmw.EntryField(
                box,
                value=('%.3f' % self.roi[i].d_spacing),
                entry_width=text_width,
                entry_justify=CENTER,
                command=lambda s=self, r=i: s.menu_d_spacing(r))
            t.grid(row=row, column=4)
            self.widgets.label[i] = t = Pmw.EntryField(
                box,
                value=str(self.roi[i].label),
                entry_width=text_width,
                entry_justify=CENTER,
                command=lambda s=self, r=i: s.menu_label(r))
            t.grid(row=row, column=5)

            self.widgets.two_theta[i] = t = Label(box,
                                                  text=('%.3f' %
                                                        self.two_theta[i]),
                                                  width=text_width,
                                                  justify=CENTER,
                                                  borderwidth=1,
                                                  relief=SOLID)
            t.grid(row=row, column=6)
            self.widgets.two_theta_diff[i] = t = Label(box,
                                                       text=('%.3f' % 0.0),
                                                       width=text_width,
                                                       justify=CENTER,
                                                       borderwidth=1,
                                                       relief=SOLID)
            t.grid(row=row, column=7)

        row = Frame(top, borderwidth=1, relief=SOLID)
        row.pack(fill=X, pady=3)
        self.widgets.do_fit = t = Button(row,
                                         text='Compute 2-theta',
                                         command=self.menu_do_fit)
        t.pack(side=LEFT, anchor=S)
        self.widgets.plot_cal = t = Button(row,
                                           text='Plot 2-theta error',
                                           command=self.menu_plot_calibration)
        t.pack(side=LEFT, anchor=S)
        self.widgets.two_theta_fit = t = Pmw.EntryField(
            row,
            label_text='Two-theta',
            labelpos=W,
            value=self.calibration.two_theta,
            entry_width=20,
            entry_justify=CENTER,
            command=self.menu_two_theta)
        t.pack(side=LEFT)
        self.menu_do_fit()
   def __init__(self, mca, command=None):
      """
      Creates a new GUI window for calibrating 2-theta for an Mca object.

      Inputs:
         mca:
            An Mca instance to be calibrated.  The Mca must have at least 1
            Regions of Interest (ROI) defined.

      Keywords:
         command:
            A callback command that will be executed if the OK button on
            the GUI window is pressed.  The callback will be invoked as:
               command(exit_status)
            where exit_status is 1 if OK was pressed, and 0 if Cancel was
            pressed or the window was closed with the window manager.

      Procedure:
         The calibration is done by determining the centroid position and
         d-spacing of each ROI.

         The centroids positions are computed by fitting the
         ROI counts to a Gaussian, using CARSMath.fit_gaussian.

         The d-spacing the ROI can be entered manually in the GUI window, or it
         can be determined automatically if the label of the ROI can be
         successfully used in jcpds.lookup_jcpds_line().

         Each ROI can be selectively used or omitted when doing the calibration.

         The errors in the 2-theta calibration, can be plotted using BltPlot.
      """
      self.input_mca = mca
      self.mca = copy.deepcopy(mca)
      self.exit_command = command
      self.roi = self.mca.get_rois()
      self.nrois = len(self.roi)
      if (self.nrois < 1):
         tkMessageBox.showerror(title='mcaCalibrate2theta Error', 
                message='Must have at least one ROI to perform calibration')
         return
      self.calibration = self.mca.get_calibration()
      self.fwhm_chan   = Numeric.zeros(self.nrois, Numeric.Float)
      self.two_theta   = Numeric.zeros(self.nrois, Numeric.Float)
      self.widgets     = mcaCalibrate2theta_widgets(self.nrois)
      self.data        = self.mca.get_data()

      # Compute the centroid and FWHM of each ROI
      for i in range(self.nrois):
         left = self.roi[i].left
         right = self.roi[i].right
         total_counts = self.data[left:right+1]
         n_sel        = right - left + 1
         sel_chans    = left + Numeric.arange(n_sel)
         left_counts  = self.data[left]
         right_counts = self.data[right]
         bgd_counts   = (left_counts + Numeric.arange(float(n_sel))/(n_sel-1) *
                                     (right_counts - left_counts))
         net_counts   = total_counts - bgd_counts
         net          = Numeric.sum(net_counts)
 
         if ((net > 0.) and (n_sel >= 3)):
            amplitude, centroid, fwhm = CARSMath.fit_gaussian(sel_chans,
                                                              net_counts)
            self.roi[i].centroid = centroid
            self.fwhm_chan[i] = fwhm
         else:
            self.roi[i].centroid = (left + right)/2.
            self.fwhm_chan[i] = right-left
         self.roi[i].fwhm = (self.mca.channel_to_energy(self.roi[i].centroid + 
                                          self.fwhm_chan[i]/2.) - 
                             self.mca.channel_to_energy(self.roi[i].centroid - 
                                          self.fwhm_chan[i]/2.))
         self.roi[i].energy = self.mca.channel_to_energy(self.roi[i].centroid)

      self.widgets.top = t = Pmw.Dialog(command=self.menu_ok_cancel,
                     buttons=('OK', 'Apply', 'Cancel'),
                     title='mcaCalibrate2theta')
      top = t.component('dialogchildsite')
      box = Frame(top, borderwidth=1, relief=SOLID); box.pack(fill=X, pady=3)

      t = Label(box, text='ROI');               t.grid(row=0, column=0)
      t = Label(box, text='Use?');              t.grid(row=0, column=1)
      t = Label(box, text='Energy');            t.grid(row=0, column=2)
      t = Label(box, text='FWHM');              t.grid(row=0, column=3)
      t = Label(box, text='D-spacing');         t.grid(row=0, column=4)
      t = Label(box, text='HKL');               t.grid(row=0, column=5)
      t = Label(box, text='Two-theta');         t.grid(row=0, column=6)
      t = Label(box, text='Two-theta diff.');   t.grid(row=0, column=7)
      text_width=10
      for i in range(self.nrois):
         row=i+1
         t = Label(box, text=str(i)); 
         t.grid(row=row, column=0)
         self.widgets.use_flag[i] = t = Pmw.OptionMenu(box,
                        items=('No','Yes'),
                        initialitem = self.roi[i].use,
                        command=lambda e, s=self, r=i: s.menu_use(e,r))
         t.grid(row=row, column=1)
         self.widgets.energy[i] = t = Pmw.EntryField(box, 
                        value=('%.3f' % self.roi[i].energy),
                        entry_width=text_width, entry_justify=CENTER, 
                        command=lambda s=self, r=i: s.menu_energy(r))
         t.grid(row=row, column=2)
         self.widgets.fwhm[i] = t = Label(box, 
                            text=('%.3f' % self.roi[i].fwhm), width=text_width,
                            justify=CENTER, borderwidth=1, relief=SOLID)
         t.grid(row=row, column=3)
         d = jcpds.lookup_jcpds_line(self.roi[i].label)
         if (d != None): self.roi[i].d_spacing = d
         self.widgets.d_spacing[i] = t = Pmw.EntryField(box, 
                        value=('%.3f' % self.roi[i].d_spacing),
                        entry_width=text_width, entry_justify=CENTER, 
                        command=lambda s=self, r=i: s.menu_d_spacing(r))
         t.grid(row=row, column=4)
         self.widgets.label[i] = t = Pmw.EntryField(box, 
                        value=str(self.roi[i].label),
                        entry_width=text_width, entry_justify=CENTER, 
                        command=lambda s=self, r=i: s.menu_label(r))
         t.grid(row=row, column=5)

         self.widgets.two_theta[i] = t = Label(box, 
                            text=('%.3f' % self.two_theta[i]), width=text_width,
                            justify=CENTER, borderwidth=1, relief=SOLID)
         t.grid(row=row, column=6)
         self.widgets.two_theta_diff[i] = t = Label(box, 
                            text=('%.3f' % 0.0), width=text_width,
                            justify=CENTER, borderwidth=1, relief=SOLID)
         t.grid(row=row, column=7)

      row = Frame(top, borderwidth=1, relief=SOLID); row.pack(fill=X, pady=3)
      self.widgets.do_fit = t = Button(row, text='Compute 2-theta', 
                                        command=self.menu_do_fit)
      t.pack(side=LEFT, anchor=S)
      self.widgets.plot_cal = t = Button(row, text='Plot 2-theta error',
                                        command=self.menu_plot_calibration)
      t.pack(side=LEFT, anchor=S)
      self.widgets.two_theta_fit = t = Pmw.EntryField(row, 
                            label_text='Two-theta', labelpos=W,
                            value=self.calibration.two_theta,
                            entry_width=20, entry_justify=CENTER, 
                            command=self.menu_two_theta)
      t.pack(side=LEFT)
      self.menu_do_fit()
Beispiel #6
0
   def __init__(self, mca, command=None):
      """
      Creates a new GUI window for calibrating energy for an Mca object.

      Inputs:
         mca:
            An Mca instance to be calibrated.  The Mca must have at least 2
            Regions of Interest (ROIs) defined for a linear calibration and
            2 ROIs defined for a quadratic calibration.

      Keywords:
         command:
            A callback command that will be executed if the OK button on
            the GUI window is pressed.  The callback will be invoked as:
               command(exit_status)
            where exit_status is 1 if OK was pressed, and 0 if Cancel was
            pressed or the window was closed with the window manager.

      Procedure:
         The calibration is done by determining the centroid position and
         energy of each ROI.

         The centroids positions are computed by fitting the
         ROI counts to a Gaussian, using CARSMath.fit_gaussian.

         The energy the ROI can be entered manually in the GUI window, or it
         can be determined automatically if the label of the ROI can be
         successfully used in Xrf.lookup_xrf_line() or Xrf.lookup_gamma_line().

         Each ROI can be selectively used or omitted when doing the calibration.

         The errors in the energy calibration and the FWHM of each ROI as a
         function of energy, can be plotted using BltPlot.
      """
      self.input_mca = mca
      self.mca = copy.copy(mca)
      self.exit_command = command
      self.roi = self.mca.get_rois()
      self.nrois = len(self.roi)
      if (self.nrois < 2):
         tkMessageBox.showerror(title='mcaCalibrateEnergy Error', 
                message='Must have at least two ROIs to perform calibration')
         return
      self.calibration = self.mca.get_calibration()
      self.fwhm_chan = Numeric.zeros(self.nrois, Numeric.Float)
      self.widgets = mcaCalibrateEnergy_widgets(self.nrois)
      self.data = self.mca.get_data()

      # Compute the centroid and FWHM of each ROI
      for i in range(self.nrois):
         left = self.roi[i].left
         right = self.roi[i].right+1
         total_counts = self.data[left:right]
         n_sel        = right - left
         sel_chans    = left + Numeric.arange(n_sel)
         left_counts  = self.data[left]
         right_counts = self.data[right]
         bgd_counts   = (left_counts + Numeric.arange(float(n_sel))/(n_sel-1) *
                                     (right_counts - left_counts))
         net_counts   = total_counts - bgd_counts
         net          = Numeric.sum(net_counts)
 
         if ((net > 0.) and (n_sel >= 3)):
            amplitude, centroid, fwhm = CARSMath.fit_gaussian(sel_chans, net_counts)
            self.roi[i].centroid = centroid
            self.fwhm_chan[i] = fwhm
         else:
            self.roi[i].centroid = (left + right)/2.
            self.fwhm_chan[i] = right-left
         self.roi[i].fwhm = (self.mca.channel_to_energy(self.roi[i].centroid + 
                                          self.fwhm_chan[i]/2.) - 
                             self.mca.channel_to_energy(self.roi[i].centroid - 
                                          self.fwhm_chan[i]/2.))

      self.widgets.top = t = Pmw.Dialog(command=self.menu_ok_cancel,
                     buttons=('OK', 'Apply', 'Cancel'),
                     title='mcaCalibrateEnergy')
      top = t.component('dialogchildsite')
      box = Frame(top, borderwidth=1, relief=SOLID); box.pack(fill=X, pady=3)
      t = Label(box, text='ROI'); t.grid(row=0, column=0)
      t = Label(box, text='Use?'); t.grid(row=0, column=1)
      t = Label(box, text='Centroid'); t.grid(row=0, column=2)
      t = Label(box, text='FWHM'); t.grid(row=0, column=3)
      t = Label(box, text='Energy'); t.grid(row=0, column=4)
      t = Label(box, text='Fluor. line'); t.grid(row=0, column=5)
      t = Label(box, text='Energy diff.'); t.grid(row=0, column=6)
      text_width=10
      for i in range(self.nrois):
         row=i+1
         t = Label(box, text=str(i)); 
         t.grid(row=row, column=0)
         self.widgets.use_flag[i] = t = Pmw.OptionMenu(box,
                        items=('No','Yes'),
                        initialitem = self.roi[i].use,
                        command=lambda e, s=self, r=i: s.menu_use(e,r))
         t.grid(row=row, column=1)
         self.widgets.centroid[i] = t = Pmw.EntryField(box, 
                        value=('%.3f' % self.roi[i].centroid),
                        entry_width=text_width, entry_justify=CENTER, 
                        command=lambda s=self, r=i: s.menu_centroid(r))
         t.grid(row=row, column=2)
         self.widgets.fwhm[i] = t = Label(box, 
                            text=('%.3f' % self.roi[i].fwhm), width=text_width,
                            justify=CENTER, borderwidth=1, relief=SOLID)
         t.grid(row=row, column=3)
         # If the ROI energy is zero, then try to use the label to lookup an
         # XRF line energy
         if (self.roi[i].energy == 0.0):
            self.roi[i].energy = Xrf.lookup_xrf_line(self.roi[i].label)
            if (self.roi[i].energy == None):
               self.roi[i].energy = Xrf.lookup_gamma_line(self.roi[i].label)
            if (self.roi[i].energy == None): self.roi[i].energy=0.0
         self.widgets.energy[i] = t = Pmw.EntryField(box, 
                        value=('%.3f' % self.roi[i].energy),
                        entry_width=text_width, entry_justify=CENTER, 
                        command=lambda s=self, r=i: s.menu_energy(r))
         t.grid(row=row, column=4)
         self.widgets.line[i] = t = Pmw.EntryField(box, 
                        value=str(self.roi[i].label),
                        entry_width=text_width, entry_justify=CENTER, 
                        command=lambda s=self, r=i: s.menu_line(r))
         t.grid(row=row, column=5)

         self.widgets.energy_diff[i] = t = Label(box, 
                            text=('%.3f' % 0.0), width=text_width,
                            justify=CENTER, borderwidth=1, relief=SOLID)
         t.grid(row=row, column=6)

      row = Frame(top, borderwidth=1, relief=SOLID); row.pack(fill=X, pady=3)
      self.widgets.fit_type = t = Pmw.OptionMenu(row, labelpos=N,
                                        label_text='Calibration type:',
                                        items=('Linear','Quadratic'))
      t.pack(side=LEFT, anchor=S)
      self.widgets.do_fit = t = Button(row, text='Compute calibration', 
                                        command=self.menu_do_fit)
      t.pack(side=LEFT, anchor=S)
      self.widgets.plot_cal = t = Button(row, text='Plot calibration error',
                                        command=self.menu_plot_calibration)
      t.pack(side=LEFT, anchor=S)
      self.widgets.plot_fwhm = t = Button(row, text='Plot FWHM',
                                        command=self.menu_plot_fwhm)
      t.pack(side=LEFT, anchor=S)

      row = Frame(top, borderwidth=1, relief=SOLID); row.pack(fill=X, pady=3)
      text_width=10
      t = Label(row, text='Calibration coefficients'); t.pack()
      self.widgets.cal_units = t = Pmw.EntryField(row, 
                            label_text='Units:', labelpos=W,
                            value=self.calibration.units,
                            entry_width=text_width, entry_justify=CENTER)
      t.pack(side=LEFT)
      self.widgets.cal_offset = t = Pmw.EntryField(row, 
                            label_text='Offset:', labelpos=W,
                            value=self.calibration.offset,
                            entry_width=text_width, entry_justify=CENTER)
      t.pack(side=LEFT)
      self.widgets.cal_slope = t = Pmw.EntryField(row, 
                            label_text='Slope:', labelpos=W,
                            value=self.calibration.slope,
                            entry_width=text_width, entry_justify=CENTER)
      t.pack(side=LEFT)
      self.widgets.cal_quad = t = Pmw.EntryField(row, 
                            label_text='Quadratic:', labelpos=W,
                            value=self.calibration.quad,
                            entry_width=text_width, entry_justify=CENTER)
      t.pack(side=LEFT)