diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegratePeaksCWSD.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegratePeaksCWSD.h
index 138d93afc4c94e982cb421a1a6c972cfc6765d79..04360a2a6c4aaa783ce10adaf2cbb5446591945d 100644
--- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegratePeaksCWSD.h
+++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/IntegratePeaksCWSD.h
@@ -67,6 +67,9 @@ private:
 
   void mergePeaks();
 
+  /// Implement this method to normalize the intensity of each Pt.
+  void normalizePeaksIntensities();
+
   DataObjects::PeaksWorkspace_sptr
   createPeakworkspace(Kernel::V3D peakCenter, API::IMDEventWorkspace_sptr mdws);
 
diff --git a/Framework/MDAlgorithms/src/ConvertCWSDExpToMomentum.cpp b/Framework/MDAlgorithms/src/ConvertCWSDExpToMomentum.cpp
index 1d9c5ce5367b477928bef82b85cfc30b965825e4..99cf13f2d04bac443735b49f4e4c380e489332a7 100644
--- a/Framework/MDAlgorithms/src/ConvertCWSDExpToMomentum.cpp
+++ b/Framework/MDAlgorithms/src/ConvertCWSDExpToMomentum.cpp
@@ -612,21 +612,21 @@ ConvertCWSDExpToMomentum::loadSpiceData(const std::string &filename,
     IAlgorithm_sptr loader = createChildAlgorithm("LoadSpiceXML2DDet");
     loader->initialize();
     loader->setProperty("Filename", filename);
-    std::vector<size_t> sizelist(2);
-    sizelist[0] = 256;
-    sizelist[1] = 256;
-    loader->setProperty("DetectorGeometry", sizelist);
+    // std::vector<size_t> sizelist(2);
+    // sizelist[0] = 256;
+    // sizelist[1] = 256;
+    // loader->setProperty("DetectorGeometry", sizelist);
     loader->setProperty("LoadInstrument", true);
     loader->setProperty("ShiftedDetectorDistance", m_detSampleDistanceShift);
     loader->setProperty("DetectorCenterXShift", m_detXShift);
     loader->setProperty("DetectorCenterYShift", m_detYShift);
 
     // TODO/FIXME - This is not a nice solution for detector geometry
-    std::string idffile = getPropertyValue("InstrumentFilename");
-    if (idffile.size() > 0) {
-      loader->setProperty("InstrumentFilename", idffile);
-      loader->setProperty("DetectorGeometry", "512, 512");
-    }
+    // std::string idffile = getPropertyValue("InstrumentFilename");
+    // if (idffile.size() > 0) {
+    //   loader->setProperty("InstrumentFilename", idffile);
+    //   loader->setProperty("DetectorGeometry", "512, 512");
+    // }
 
     double wavelength = getProperty("UserDefinedWavelength");
 
diff --git a/Framework/MDAlgorithms/src/IntegratePeaksCWSD.cpp b/Framework/MDAlgorithms/src/IntegratePeaksCWSD.cpp
index b0de2bd78dd58eca7b76b22361342afad4239e53..9dccb27505ce3f4606fd5d5c930f316f823469c1 100644
--- a/Framework/MDAlgorithms/src/IntegratePeaksCWSD.cpp
+++ b/Framework/MDAlgorithms/src/IntegratePeaksCWSD.cpp
@@ -105,6 +105,8 @@ void IntegratePeaksCWSD::exec() {
   // Merge peak if necessary
   if (m_doMergePeak)
     mergePeaks();
+  else
+    normalizePeaksIntensities(); // normalize the intensity of each Pt.
 
   // Output
   DataObjects::PeaksWorkspace_sptr outws =
@@ -161,6 +163,7 @@ void IntegratePeaksCWSD::processInputs() {
         "Either being normalized by time or being normalized "
         "by monitor must be selected if merge-peak is selected.");
   m_scaleFactor = getProperty("ScaleFactor");
+  g_log.warning() << "[DB...BAT] Scale factor = " << m_scaleFactor << "\n";
 
   // monitor counts
   if (m_normalizeByMonitor)
@@ -544,9 +547,8 @@ std::map<int, double> IntegratePeaksCWSD::getMeasureTime() {
     std::string duration_str = expinfo->run().getProperty("duration")->value();
     double duration = std::stod(duration_str);
     run_time_map.insert(std::make_pair(run_number, duration));
-    g_log.information() << "MD workspace exp info " << iexpinfo << ": run "
-                        << run_number << ", measuring time = " << duration
-                        << "\n";
+    g_log.warning() << "MD workspace exp info " << iexpinfo << ": run "
+                    << run_number << ", measuring time = " << duration << "\n";
   }
 
   return run_time_map;
@@ -573,5 +575,28 @@ void IntegratePeaksCWSD::getPeakInformation() {
   }
 }
 
+//----------------------------------------------------------------------------------------------
+/** Normalize the peak's intensities per Pt. to either time or monitor counts
+ * @brief IntegratePeaksCSWD::normalizePeaksIntensities
+ */
+void IntegratePeaksCWSD::normalizePeaksIntensities() {
+  // go over each peak (of run)
+  std::map<int, double>::iterator count_iter;
+  for (count_iter = m_runPeakCountsMap.begin();
+       count_iter != m_runPeakCountsMap.end(); ++count_iter) {
+    int run_number_i = count_iter->first;
+    // get monitor value
+    std::map<int, signal_t>::iterator mon_iter =
+        m_runNormMap.find(run_number_i);
+    // normalize peak intensities stored in m_runNormMap
+    if (mon_iter != m_runNormMap.end()) {
+      signal_t monitor_i = mon_iter->second;
+      count_iter->second /= monitor_i;
+    }
+  } // END-FOR
+
+  return;
+}
+
 } // namespace Mantid
 } // namespace MDAlgorithms
diff --git a/docs/source/release/v3.10.0/diffraction.rst b/docs/source/release/v3.10.0/diffraction.rst
index e0f8179ba7ed6379fe44a594bf7ae9397e4ba3aa..13fa98c076b9236a16acc5331b9cd927d94bc4aa 100644
--- a/docs/source/release/v3.10.0/diffraction.rst
+++ b/docs/source/release/v3.10.0/diffraction.rst
@@ -41,3 +41,5 @@ Single Crystal Diffraction
 Full list of `diffraction <https://github.com/mantidproject/mantid/issues?q=is%3Aclosed+milestone%3A%22Release+3.10%22+label%3A%22Component%3A+Diffraction%22>`_
 and
 `imaging <https://github.com/mantidproject/mantid/issues?q=is%3Aclosed+milestone%3A%22Release+3.10%22+label%3A%22Component%3A+Imaging%22>`_ changes on GitHub.
+
+- HB3A reduction interface (application) now supports to integrate single crystal peaks by fitting peak intensity with 2D Gaussian with more detailed integraton information for user.
diff --git a/scripts/HFIR_4Circle_Reduction/AddUBPeaksDialog.ui b/scripts/HFIR_4Circle_Reduction/AddUBPeaksDialog.ui
new file mode 100644
index 0000000000000000000000000000000000000000..58f8cca513932caa2f6b2ed55c771cd4a02c3675
--- /dev/null
+++ b/scripts/HFIR_4Circle_Reduction/AddUBPeaksDialog.ui
@@ -0,0 +1,490 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog">
+  <property name="windowModality">
+   <enum>Qt::ApplicationModal</enum>
+  </property>
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>666</width>
+    <height>547</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <property name="modal">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2">
+   <item>
+    <widget class="QGroupBox" name="groupBox_7">
+     <property name="title">
+      <string>Add Single Peak</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout">
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_3">
+        <item>
+         <widget class="QLabel" name="label_scanNo">
+          <property name="minimumSize">
+           <size>
+            <width>120</width>
+            <height>0</height>
+           </size>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>120</width>
+            <height>16777215</height>
+           </size>
+          </property>
+          <property name="font">
+           <font>
+            <pointsize>10</pointsize>
+           </font>
+          </property>
+          <property name="text">
+           <string>Scan Number</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLineEdit" name="lineEdit_scanNumber">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="minimumSize">
+           <size>
+            <width>120</width>
+            <height>0</height>
+           </size>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>160</width>
+            <height>16777215</height>
+           </size>
+          </property>
+          <property name="font">
+           <font>
+            <pointsize>11</pointsize>
+           </font>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QPushButton" name="pushButton_findPeak">
+          <property name="font">
+           <font>
+            <pointsize>11</pointsize>
+            <weight>75</weight>
+            <bold>true</bold>
+           </font>
+          </property>
+          <property name="text">
+           <string>Find Peak</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QCheckBox" name="checkBox_loadHKLfromFile">
+          <property name="font">
+           <font>
+            <pointsize>8</pointsize>
+            <italic>true</italic>
+           </font>
+          </property>
+          <property name="text">
+           <string>Load HKL from Spice file</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <spacer name="horizontalSpacer">
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeType">
+           <enum>QSizePolicy::Preferred</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>40</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <layout class="QGridLayout" name="gridLayout">
+        <item row="1" column="1">
+         <widget class="QLineEdit" name="lineEdit_sampleQy">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>160</width>
+            <height>16777215</height>
+           </size>
+          </property>
+          <property name="font">
+           <font>
+            <pointsize>11</pointsize>
+           </font>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="0">
+         <widget class="QLabel" name="label_31">
+          <property name="minimumSize">
+           <size>
+            <width>120</width>
+            <height>0</height>
+           </size>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>120</width>
+            <height>16777215</height>
+           </size>
+          </property>
+          <property name="font">
+           <font>
+            <pointsize>10</pointsize>
+           </font>
+          </property>
+          <property name="text">
+           <string>Miller Index</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="3">
+         <widget class="QLineEdit" name="lineEdit_sampleQz">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>160</width>
+            <height>16777215</height>
+           </size>
+          </property>
+          <property name="font">
+           <font>
+            <pointsize>11</pointsize>
+           </font>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="2">
+         <widget class="QLineEdit" name="lineEdit_sampleQx">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>160</width>
+            <height>16777215</height>
+           </size>
+          </property>
+          <property name="font">
+           <font>
+            <pointsize>11</pointsize>
+           </font>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="3">
+         <widget class="QLineEdit" name="lineEdit_L">
+          <property name="maximumSize">
+           <size>
+            <width>160</width>
+            <height>16777215</height>
+           </size>
+          </property>
+          <property name="font">
+           <font>
+            <pointsize>11</pointsize>
+           </font>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="2">
+         <widget class="QLineEdit" name="lineEdit_H">
+          <property name="maximumSize">
+           <size>
+            <width>160</width>
+            <height>40</height>
+           </size>
+          </property>
+          <property name="font">
+           <font>
+            <pointsize>11</pointsize>
+           </font>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="0">
+         <widget class="QLabel" name="label_7">
+          <property name="minimumSize">
+           <size>
+            <width>120</width>
+            <height>0</height>
+           </size>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>120</width>
+            <height>16777215</height>
+           </size>
+          </property>
+          <property name="font">
+           <font>
+            <pointsize>10</pointsize>
+           </font>
+          </property>
+          <property name="text">
+           <string> Q-Sample </string>
+          </property>
+          <property name="alignment">
+           <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1">
+         <widget class="QLineEdit" name="lineEdit_K">
+          <property name="maximumSize">
+           <size>
+            <width>160</width>
+            <height>16777215</height>
+           </size>
+          </property>
+          <property name="font">
+           <font>
+            <pointsize>11</pointsize>
+           </font>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="4">
+         <spacer name="horizontalSpacer_2">
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeType">
+           <enum>QSizePolicy::Preferred</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>40</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <layout class="QHBoxLayout" name="horizontalLayout_2">
+        <item>
+         <spacer name="horizontalSpacer_3">
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeType">
+           <enum>QSizePolicy::Expanding</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>40</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item>
+         <widget class="QPushButton" name="pushButton_addPeakToCalUB">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="font">
+           <font>
+            <pointsize>11</pointsize>
+            <weight>75</weight>
+            <bold>true</bold>
+           </font>
+          </property>
+          <property name="text">
+           <string>Add Peak</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="groupBox">
+     <property name="title">
+      <string>Add Multiple Peaks</string>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout_4">
+      <item>
+       <layout class="QVBoxLayout" name="verticalLayout_3">
+        <item>
+         <widget class="QLabel" name="label">
+          <property name="font">
+           <font>
+            <pointsize>11</pointsize>
+           </font>
+          </property>
+          <property name="text">
+           <string>Scan Numbers</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <spacer name="verticalSpacer">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>40</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <layout class="QVBoxLayout" name="verticalLayout_4">
+        <item>
+         <widget class="QPlainTextEdit" name="plainTextEdit_scanList">
+          <property name="font">
+           <font>
+            <pointsize>11</pointsize>
+           </font>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <layout class="QHBoxLayout" name="horizontalLayout_5">
+          <item>
+           <widget class="QPushButton" name="pushButton_browseScansFile">
+            <property name="font">
+             <font>
+              <pointsize>11</pointsize>
+              <weight>75</weight>
+              <bold>true</bold>
+             </font>
+            </property>
+            <property name="text">
+             <string>Browse</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QLineEdit" name="lineEdit_scansFile"/>
+          </item>
+          <item>
+           <widget class="QPushButton" name="pushButton_loadScans">
+            <property name="font">
+             <font>
+              <pointsize>11</pointsize>
+              <weight>75</weight>
+              <bold>true</bold>
+             </font>
+            </property>
+            <property name="toolTip">
+             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Load scans from a plain text file (ASCII).&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Supported file format:&lt;/p&gt;&lt;p&gt;# comment&lt;/p&gt;&lt;p&gt;# comment &lt;/p&gt;&lt;p&gt;scan1, scan2, scan3, scan4-scan100&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+            </property>
+            <property name="text">
+             <string>Load Scans</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item>
+         <layout class="QHBoxLayout" name="horizontalLayout">
+          <item>
+           <spacer name="horizontalSpacer_4">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeType">
+             <enum>QSizePolicy::Expanding</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QPushButton" name="pushButton_addScans">
+            <property name="font">
+             <font>
+              <pointsize>11</pointsize>
+              <weight>75</weight>
+              <bold>true</bold>
+             </font>
+            </property>
+            <property name="toolTip">
+             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Add scans listed in the text editor above to calculate/refine UB matrix&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+            </property>
+            <property name="text">
+             <string>Add Scans</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_2">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QPushButton" name="pushButton_quit">
+     <property name="text">
+      <string>Quit</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/scripts/HFIR_4Circle_Reduction/CMakeLists.txt b/scripts/HFIR_4Circle_Reduction/CMakeLists.txt
index 36b4bb99ec77f6cfc1f796affed8ca9dc2019c71..053a1d366f695383a4c2e094896c73a87dc78931 100644
--- a/scripts/HFIR_4Circle_Reduction/CMakeLists.txt
+++ b/scripts/HFIR_4Circle_Reduction/CMakeLists.txt
@@ -2,11 +2,15 @@ include(UiToPy)
 
 # List of UIs to Auto convert
 set( UI_FILES
-  MainWindow.ui 
+  MainWindow.ui
+  messagebox.ui
   View3DWidget.ui
   OptimizeLattice.ui
   RefineUbFftDialog.ui
   SpiceViewerDialog.ui
+  UBSelectPeaksDialog.ui
+  AddUBPeaksDialog.ui
+  PeakIntegrationSpreadSheet.ui
 )
 
 UiToPy( UI_FILES CompileUIHFIR_4Circle_Reduction)
diff --git a/scripts/HFIR_4Circle_Reduction/FindUBUtility.py b/scripts/HFIR_4Circle_Reduction/FindUBUtility.py
new file mode 100644
index 0000000000000000000000000000000000000000..a41ba3cac87001777582d4b00ed43d9470fa31b3
--- /dev/null
+++ b/scripts/HFIR_4Circle_Reduction/FindUBUtility.py
@@ -0,0 +1,245 @@
+"""
+Containing a set of classes used for finding (calculating and refining) UB matrix
+"""
+import os
+
+import ui_AddUBPeaksDialog
+import ui_UBSelectPeaksDialog
+import guiutility
+
+from PyQt4 import QtGui, QtCore
+
+
+class AddScansForUBDialog(QtGui.QDialog):
+    """
+    Dialog class to add scans to UB scans' table for calculating and
+    """
+    def __init__(self, parent):
+        """
+        initialization
+        :param parent: main GUI, reductionControl
+        """
+        super(AddScansForUBDialog, self).__init__(parent)
+        self._myParent = parent
+
+        # set up UI
+        self.ui = ui_AddUBPeaksDialog.Ui_Dialog()
+        self.ui.setupUi(self)
+
+        # initialize widgets
+        self.ui.checkBox_loadHKLfromFile.setChecked(True)
+
+        # define event handling
+        self.connect(self.ui.pushButton_findPeak, QtCore.SIGNAL('clicked()'),
+                     self.do_find_peak)
+        self.connect(self.ui.pushButton_addPeakToCalUB, QtCore.SIGNAL('clicked()'),
+                     self.do_add_single_scan)
+
+        self.connect(self.ui.pushButton_loadScans, QtCore.SIGNAL('clicked()'),
+                     self.do_load_scans)
+        self.connect(self.ui.pushButton_addScans, QtCore.SIGNAL('clicked()'),
+                     self.do_add_scans)
+
+        self.connect(self.ui.pushButton_quit, QtCore.SIGNAL('clicked()'),
+                     self.do_quit)
+
+        return
+
+    def do_add_scans(self):
+        """
+        add all the scans list in the 'plainTextEdit_scanList'
+        :return:
+        """
+        scans_str = str(self.ui.plainTextEdit_scanList.toPlainText())
+        scan_list = guiutility.parse_integer_list(scans_str)
+        self._myParent.add_scans_ub_table(scan_list)
+
+        return
+
+    def do_add_single_scan(self):
+        """
+        add single scan to refine UB matrix
+        :return:
+        """
+        scan_number = int(self.ui.lineEdit_scanNumber.text())
+        self._myParent.add_scans_ub_table([scan_number])
+
+        return
+
+    def do_find_peak(self):
+        """
+        find the peak(s) in a merged scan
+        :return:
+        """
+        # get scan number
+        status, ret_obj = guiutility.parse_integers_editors([self.ui.lineEdit_scanNumber])
+        if status:
+            scan_number = ret_obj[0]
+        else:
+            # pop error message
+            self._myParent.pop_one_button_dialog(ret_obj)
+            return
+
+        # load HKL from SPICE?
+        hkl_from_spice = self.ui.checkBox_loadHKLfromFile.isChecked()
+
+        # find peak
+        status, ret_obj = self._myParent.find_peak_in_scan(scan_number, hkl_from_spice)
+
+        # set the result
+        if status:
+            hkl, vec_q = ret_obj
+            if len(hkl) > 0:
+                self.ui.lineEdit_H.setText('%.2f' % hkl[0])
+                self.ui.lineEdit_K.setText('%.2f' % hkl[1])
+                self.ui.lineEdit_L.setText('%.2f' % hkl[2])
+
+            self.ui.lineEdit_sampleQx.setText('%.5E' % vec_q[0])
+            self.ui.lineEdit_sampleQy.setText('%.5E' % vec_q[1])
+            self.ui.lineEdit_sampleQz.setText('%.5E' % vec_q[2])
+        # END-IF
+
+        return
+
+    def do_load_scans(self):
+        """
+        load an ASCII file containing scan numbers,
+        and the results are written to 'plainTextEdit_scanList'
+        :return:
+        """
+        # get file name
+        scan_file = str(self.ui.lineEdit_scansFile.text())
+        if os.path.exists(scan_file) is False:
+            raise RuntimeError('Scan file {0} does not exist.'.format(scan_file))
+
+        # parse file
+        exp_number, scans_str = guiutility.import_scans_text_file(scan_file)
+
+        self.ui.plainTextEdit_scanList.setPlainText(scans_str)
+
+        return
+
+    def do_quit(self):
+        """
+        quit
+        :return:
+        """
+        self.close()
+
+        return
+
+
+class SelectUBMatrixScansDialog(QtGui.QDialog):
+    """
+    Dialog to select scans for processing UB matrix
+    """
+    def __init__(self, parent):
+        """
+        initialization
+        :param parent:
+        """
+        super(SelectUBMatrixScansDialog, self).__init__(parent)
+        self._myParent = parent
+
+        # set ui
+        self.ui = ui_UBSelectPeaksDialog.Ui_Dialog()
+        self.ui.setupUi(self)
+
+        # define event handling methods
+        self.connect(self.ui.pushButton_selectScans, QtCore.SIGNAL('clicked()'),
+                     self.do_select_scans)
+        self.connect(self.ui.pushButton_revertCurrentSelection, QtCore.SIGNAL('clicked()'),
+                     self.do_revert_selection)
+        self.connect(self.ui.pushButton_exportSelectedScans, QtCore.SIGNAL('clicked()'),
+                     self.do_export_selected_scans)
+
+        self.connect(self.ui.pushButton_quit, QtCore.SIGNAL('clicked()'),
+                     self.do_quit)
+
+        return
+
+    def do_quit(self):
+        """
+
+        :return:
+        """
+        self.close()
+
+        return
+
+    def do_export_selected_scans(self):
+        """
+        export selected scans to a file
+        :return:
+        """
+        # get the scans
+        scans_list = self._myParent.ub_matrix_processing_table.get_selected_scans()
+        scans_list.sort()
+
+        # form the output string
+        output_str = '# Exp = {0}.\n'.format(self._myParent.current_exp_number)
+        for scan in scans_list:
+            output_str += '{0}, '.format(scan)
+
+        # trim the last
+        output_str = output_str[:-2]
+
+        # get the output file name
+        file_filter = 'Text Files (*.dat);;All Files (*.*)'
+        file_name = str(QtGui.QFileDialog.getSaveFileName(self, 'File to export selected scans',
+                        self._myParent.working_directory, file_filter))
+
+        # write file
+        out_file = open(file_name, 'w')
+        out_file.write(output_str)
+        out_file.close()
+
+        return
+
+    def do_revert_selection(self):
+        """
+        revert the current selection of the UB table
+        :return:
+        """
+        self._myParent.ub_matrix_processing_table.revert_selection()
+
+        return
+
+    def do_select_scans(self):
+        """
+
+        :return:
+        """
+        # get check box
+        if self.ui.checkBox_selectAllPeaks.isChecked():
+            self._myParent.select_ub_scans(select_all=True)
+
+        else:
+            select_args = dict()
+
+            if self.ui.checkBox_selectNuclearPeaks.isChecked():
+                status, ret_obj = guiutility.parse_float_editors([self.ui.lineEdit_nuclearPeaksTolerance],
+                                                                 allow_blank=False)
+                if not status:
+                    raise RuntimeError(ret_obj)
+                hkl_tol = ret_obj[0]
+                select_args['nuclear_peaks'] = True
+                select_args['hkl_tolerance'] = hkl_tol
+
+            if self.ui.checkBox_wavelength.isChecked():
+                # wave length selection
+                status, ret_obj = guiutility.parse_float_editors([self.ui.lineEdit_wavelength,
+                                                                  self.ui.lineEdit_wavelengthTolerance],
+                                                                 allow_blank=False)
+                if status:
+                    wave_length, wave_length_tol = ret_obj
+                    select_args['wavelength'] = wave_length
+                    select_args['wavelength_tolerance'] = wave_length_tol
+                else:
+                    select_args['wavelength'] = None
+
+            # select with filters
+            self._myParent.ub_matrix_processing_table.select_scans(**select_args)
+        # END-IF-ELSE
+
+        return
diff --git a/scripts/HFIR_4Circle_Reduction/MainWindow.ui b/scripts/HFIR_4Circle_Reduction/MainWindow.ui
index 3f4c6aa6b59885cb43f09566a4c33eff1fbb64e2..8d8c0e94c60d05cd64fe56367869dd1aea5571ce 100644
--- a/scripts/HFIR_4Circle_Reduction/MainWindow.ui
+++ b/scripts/HFIR_4Circle_Reduction/MainWindow.ui
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>1536</width>
-    <height>918</height>
+    <width>1568</width>
+    <height>1116</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -19,6 +19,41 @@
      <layout class="QVBoxLayout" name="verticalLayout_3">
       <item>
        <layout class="QHBoxLayout" name="horizontalLayout_General">
+        <item>
+         <widget class="QLabel" name="label_71">
+          <property name="font">
+           <font>
+            <weight>75</weight>
+            <bold>true</bold>
+           </font>
+          </property>
+          <property name="text">
+           <string>IPTS</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLineEdit" name="lineEdit_iptsNumber">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="minimumSize">
+           <size>
+            <width>40</width>
+            <height>0</height>
+           </size>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>60</width>
+            <height>16777215</height>
+           </size>
+          </property>
+         </widget>
+        </item>
         <item>
          <widget class="QLabel" name="label_exp">
           <property name="font">
@@ -48,6 +83,16 @@
           </property>
          </widget>
         </item>
+        <item>
+         <widget class="QComboBox" name="comboBox_expNumberList">
+          <property name="maximumSize">
+           <size>
+            <width>16777215</width>
+            <height>60</height>
+           </size>
+          </property>
+         </widget>
+        </item>
         <item>
          <widget class="QPushButton" name="pushButton_setExp">
           <property name="text">
@@ -168,7 +213,7 @@
            <bool>true</bool>
           </property>
           <property name="currentIndex">
-           <number>0</number>
+           <number>2</number>
           </property>
           <widget class="QWidget" name="tab">
            <attribute name="title">
@@ -848,6 +893,34 @@ p, li { white-space: pre-wrap; }
                  </property>
                 </widget>
                </item>
+               <item row="1" column="8">
+                <widget class="QLabel" name="label_70">
+                 <property name="text">
+                  <string>Detector Size</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="1" column="10">
+                <widget class="QPushButton" name="pushButton_applyDetectorSize">
+                 <property name="text">
+                  <string>Apply</string>
+                 </property>
+                </widget>
+               </item>
+               <item row="1" column="9">
+                <widget class="QComboBox" name="comboBox_detectorSize">
+                 <item>
+                  <property name="text">
+                   <string>256 x 256</string>
+                  </property>
+                 </item>
+                 <item>
+                  <property name="text">
+                   <string>512 x 512</string>
+                  </property>
+                 </item>
+                </widget>
+               </item>
               </layout>
              </widget>
             </item>
@@ -855,7 +928,7 @@ p, li { white-space: pre-wrap; }
           </widget>
           <widget class="QWidget" name="tab_survey">
            <attribute name="title">
-            <string>Information</string>
+            <string>List Scans</string>
            </attribute>
            <layout class="QGridLayout" name="gridLayout_8">
             <item row="0" column="0">
@@ -1038,6 +1111,33 @@ p, li { white-space: pre-wrap; }
                     </property>
                    </widget>
                   </item>
+                  <item>
+                   <widget class="QPushButton" name="pushButton_viewRawSpice">
+                    <property name="font">
+                     <font>
+                      <pointsize>12</pointsize>
+                     </font>
+                    </property>
+                    <property name="text">
+                     <string>View Spice File</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item>
+                   <widget class="QPushButton" name="pushButton_viewSurveyPeak">
+                    <property name="font">
+                     <font>
+                      <pointsize>12</pointsize>
+                     </font>
+                    </property>
+                    <property name="toolTip">
+                     <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set the selected peak to view and switch to tab 'View Raw Data'&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                    </property>
+                    <property name="text">
+                     <string>View Peak</string>
+                    </property>
+                   </widget>
+                  </item>
                   <item>
                    <spacer name="verticalSpacer_9">
                     <property name="orientation">
@@ -1055,29 +1155,71 @@ p, li { white-space: pre-wrap; }
                    </spacer>
                   </item>
                   <item>
-                   <widget class="QPushButton" name="pushButton_viewRawSpice">
-                    <property name="text">
-                     <string>View Spice File</string>
+                   <widget class="Line" name="line_23">
+                    <property name="orientation">
+                     <enum>Qt::Horizontal</enum>
                     </property>
                    </widget>
                   </item>
                   <item>
-                   <widget class="QPushButton" name="pushButton_viewSurveyPeak">
+                   <widget class="QPushButton" name="pushButton_addPeaksToRefine">
+                    <property name="font">
+                     <font>
+                      <pointsize>11</pointsize>
+                      <weight>75</weight>
+                      <bold>true</bold>
+                     </font>
+                    </property>
                     <property name="toolTip">
-                     <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set the selected peak to view and switch to tab 'View Raw Data'&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Add all the selected peaks to the table in tab 'CalculateUB and switch to tab 'CalculateUB;&lt;/p&gt;&lt;p&gt;All the Pts. in each scan will be merged and &lt;span style=&quot; font-style:italic;&quot;&gt;FindPeaks()&lt;/span&gt; will be operated on each such merged data.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
                     </property>
                     <property name="text">
-                     <string>View Peak</string>
+                     <string>Add to Calculate UB</string>
                     </property>
                    </widget>
                   </item>
                   <item>
-                   <widget class="QPushButton" name="pushButton_addPeaksToRefine">
+                   <widget class="QComboBox" name="comboBox_maskNamesSurvey">
+                    <property name="font">
+                     <font>
+                      <pointsize>11</pointsize>
+                     </font>
+                    </property>
                     <property name="toolTip">
-                     <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Add all the selected peaks to the table in tab 'CalculateUB and switch to tab 'CalculateUB;&lt;/p&gt;&lt;p&gt;All the Pts. in each scan will be merged and &lt;span style=&quot; font-style:italic;&quot;&gt;FindPeaks()&lt;/span&gt; will be operated on each such merged data.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:13pt;&quot;&gt;List of region of interest that can be applied to the selected scans that are added to tab 'Calculate UB' for UB matrix calculation.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item>
+                   <spacer name="verticalSpacer_30">
+                    <property name="orientation">
+                     <enum>Qt::Vertical</enum>
+                    </property>
+                    <property name="sizeType">
+                     <enum>QSizePolicy::Preferred</enum>
+                    </property>
+                    <property name="sizeHint" stdset="0">
+                     <size>
+                      <width>20</width>
+                      <height>40</height>
+                     </size>
+                    </property>
+                   </spacer>
+                  </item>
+                  <item>
+                   <widget class="QPushButton" name="pushButton_mergeScansSurvey">
+                    <property name="font">
+                     <font>
+                      <pointsize>11</pointsize>
+                      <weight>75</weight>
+                      <bold>true</bold>
+                     </font>
+                    </property>
+                    <property name="toolTip">
+                     <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Add selected scans to tab &amp;quot;Scans Processing&amp;quot; for merging or peak integrtoin&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
                     </property>
                     <property name="text">
-                     <string>Add Peaks</string>
+                     <string>Add to Integrate/Merge</string>
                     </property>
                    </widget>
                   </item>
@@ -1791,7 +1933,7 @@ p, li { white-space: pre-wrap; }
                    <string>Region of Interest</string>
                   </property>
                   <layout class="QGridLayout" name="gridLayout_18">
-                   <item row="3" column="0">
+                   <item row="5" column="0">
                     <widget class="QPushButton" name="pushButton_cancelROI">
                      <property name="font">
                       <font>
@@ -1842,6 +1984,31 @@ p, li { white-space: pre-wrap; }
                      </property>
                     </widget>
                    </item>
+                   <item row="3" column="0">
+                    <widget class="QPushButton" name="pushButton_integrateROI">
+                     <property name="font">
+                      <font>
+                       <pointsize>10</pointsize>
+                      </font>
+                     </property>
+                     <property name="text">
+                      <string>Integrate</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="4" column="0">
+                    <spacer name="verticalSpacer_31">
+                     <property name="orientation">
+                      <enum>Qt::Vertical</enum>
+                     </property>
+                     <property name="sizeHint" stdset="0">
+                      <size>
+                       <width>20</width>
+                       <height>40</height>
+                      </size>
+                     </property>
+                    </spacer>
+                   </item>
                   </layout>
                  </widget>
                 </item>
@@ -1888,254 +2055,19 @@ p, li { white-space: pre-wrap; }
             <string>Calculate UB</string>
            </attribute>
            <layout class="QVBoxLayout" name="verticalLayout_19">
-            <item>
-             <widget class="QGroupBox" name="groupBox_7">
-              <property name="title">
-               <string>Add Peak</string>
-              </property>
-              <layout class="QGridLayout" name="gridLayout_2">
-               <item row="0" column="8">
-                <widget class="QLineEdit" name="lineEdit_H">
-                 <property name="maximumSize">
-                  <size>
-                   <width>60</width>
-                   <height>40</height>
-                  </size>
-                 </property>
-                 <property name="font">
-                  <font>
-                   <pointsize>10</pointsize>
-                  </font>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="6">
-                <spacer name="horizontalSpacer_4">
-                 <property name="orientation">
-                  <enum>Qt::Horizontal</enum>
-                 </property>
-                 <property name="sizeType">
-                  <enum>QSizePolicy::Preferred</enum>
-                 </property>
-                 <property name="sizeHint" stdset="0">
-                  <size>
-                   <width>40</width>
-                   <height>20</height>
-                  </size>
-                 </property>
-                </spacer>
-               </item>
-               <item row="0" column="0">
-                <widget class="QLabel" name="label_scanNo">
-                 <property name="font">
-                  <font>
-                   <pointsize>10</pointsize>
-                  </font>
-                 </property>
-                 <property name="text">
-                  <string>Scan Number</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="4">
-                <widget class="QPushButton" name="pushButton_findPeak">
-                 <property name="font">
-                  <font>
-                   <pointsize>10</pointsize>
-                   <weight>75</weight>
-                   <bold>true</bold>
-                  </font>
-                 </property>
-                 <property name="text">
-                  <string>Find Peak</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="7">
-                <widget class="QLabel" name="label_31">
-                 <property name="font">
-                  <font>
-                   <pointsize>10</pointsize>
-                  </font>
-                 </property>
-                 <property name="text">
-                  <string>Miller Index</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="1">
-                <widget class="QLineEdit" name="lineEdit_scanNumber">
-                 <property name="sizePolicy">
-                  <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
-                   <horstretch>0</horstretch>
-                   <verstretch>0</verstretch>
-                  </sizepolicy>
-                 </property>
-                 <property name="maximumSize">
-                  <size>
-                   <width>60</width>
-                   <height>16777215</height>
-                  </size>
-                 </property>
-                 <property name="font">
-                  <font>
-                   <pointsize>10</pointsize>
-                  </font>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="18">
-                <widget class="QPushButton" name="pushButton_viewScan3D">
-                 <property name="font">
-                  <font>
-                   <pointsize>10</pointsize>
-                   <weight>50</weight>
-                   <bold>false</bold>
-                  </font>
-                 </property>
-                 <property name="toolTip">
-                  <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt;View peak in 3D&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-                 </property>
-                 <property name="text">
-                  <string>View Peak</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="11">
-                <widget class="QLineEdit" name="lineEdit_K">
-                 <property name="maximumSize">
-                  <size>
-                   <width>60</width>
-                   <height>16777215</height>
-                  </size>
-                 </property>
-                 <property name="font">
-                  <font>
-                   <pointsize>10</pointsize>
-                  </font>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="12">
-                <widget class="QLineEdit" name="lineEdit_L">
-                 <property name="maximumSize">
-                  <size>
-                   <width>60</width>
-                   <height>16777215</height>
-                  </size>
-                 </property>
-                 <property name="font">
-                  <font>
-                   <pointsize>10</pointsize>
-                  </font>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="5">
-                <widget class="QCheckBox" name="checkBox_loadHKLfromFile">
-                 <property name="font">
-                  <font>
-                   <pointsize>8</pointsize>
-                   <italic>true</italic>
-                  </font>
-                 </property>
-                 <property name="text">
-                  <string>Load HKL from Spice file</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="13">
-                <widget class="QLabel" name="label_7">
-                 <property name="font">
-                  <font>
-                   <pointsize>10</pointsize>
-                  </font>
-                 </property>
-                 <property name="text">
-                  <string> Q-Sample </string>
-                 </property>
-                 <property name="alignment">
-                  <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="14">
-                <widget class="QLineEdit" name="lineEdit_sampleQx">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                 <property name="maximumSize">
-                  <size>
-                   <width>120</width>
-                   <height>16777215</height>
-                  </size>
-                 </property>
-                 <property name="font">
-                  <font>
-                   <pointsize>10</pointsize>
-                  </font>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="16">
-                <widget class="QLineEdit" name="lineEdit_sampleQz">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                 <property name="maximumSize">
-                  <size>
-                   <width>120</width>
-                   <height>16777215</height>
-                  </size>
-                 </property>
-                 <property name="font">
-                  <font>
-                   <pointsize>10</pointsize>
-                  </font>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="17">
-                <widget class="QPushButton" name="pushButton_addPeakToCalUB">
-                 <property name="font">
-                  <font>
-                   <pointsize>10</pointsize>
-                   <weight>75</weight>
-                   <bold>true</bold>
-                  </font>
-                 </property>
-                 <property name="text">
-                  <string>Add Peak</string>
-                 </property>
-                </widget>
-               </item>
-               <item row="0" column="15">
-                <widget class="QLineEdit" name="lineEdit_sampleQy">
-                 <property name="enabled">
-                  <bool>false</bool>
-                 </property>
-                 <property name="maximumSize">
-                  <size>
-                   <width>120</width>
-                   <height>16777215</height>
-                  </size>
-                 </property>
-                 <property name="font">
-                  <font>
-                   <pointsize>10</pointsize>
-                  </font>
-                 </property>
-                </widget>
-               </item>
-              </layout>
-             </widget>
-            </item>
             <item>
              <layout class="QHBoxLayout" name="horizontalLayout_7">
               <item>
                <layout class="QVBoxLayout" name="verticalLayout_4">
                 <item>
-                 <widget class="UBMatrixPeakTable" name="tableWidget_peaksCalUB"/>
+                 <widget class="UBMatrixPeakTable" name="tableWidget_peaksCalUB">
+                  <property name="sizePolicy">
+                   <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+                    <horstretch>0</horstretch>
+                    <verstretch>0</verstretch>
+                   </sizepolicy>
+                  </property>
+                 </widget>
                 </item>
                 <item>
                  <layout class="QHBoxLayout" name="horizontalLayout_10">
@@ -2153,6 +2085,22 @@ p, li { white-space: pre-wrap; }
                     </property>
                    </widget>
                   </item>
+                  <item>
+                   <spacer name="horizontalSpacer_38">
+                    <property name="orientation">
+                     <enum>Qt::Horizontal</enum>
+                    </property>
+                    <property name="sizeType">
+                     <enum>QSizePolicy::Preferred</enum>
+                    </property>
+                    <property name="sizeHint" stdset="0">
+                     <size>
+                      <width>40</width>
+                      <height>20</height>
+                     </size>
+                    </property>
+                   </spacer>
+                  </item>
                   <item>
                    <widget class="QPushButton" name="pushButton_setHKL2Int">
                     <property name="font">
@@ -2165,6 +2113,9 @@ p, li { white-space: pre-wrap; }
                     </property>
                    </widget>
                   </item>
+                  <item>
+                   <widget class="QComboBox" name="comboBox_hklType"/>
+                  </item>
                   <item>
                    <widget class="QPushButton" name="pushButton_undoSetToInteger">
                     <property name="font">
@@ -2234,25 +2185,16 @@ p, li { white-space: pre-wrap; }
               <item>
                <layout class="QVBoxLayout" name="verticalLayout_8">
                 <item>
-                 <widget class="QPushButton" name="pushButton_selectAllPeaks">
-                  <property name="text">
-                   <string>Select All</string>
-                  </property>
-                 </widget>
-                </item>
-                <item>
-                 <widget class="QCheckBox" name="checkBox_ubNuclearPeaks">
-                  <property name="enabled">
-                   <bool>true</bool>
-                  </property>
+                 <widget class="QPushButton" name="pushButton_addUBScans">
                   <property name="font">
                    <font>
-                    <pointsize>9</pointsize>
-                    <italic>true</italic>
+                    <pointsize>10</pointsize>
+                    <weight>75</weight>
+                    <bold>true</bold>
                    </font>
                   </property>
                   <property name="text">
-                   <string>nuclear peaks</string>
+                   <string>Add Peaks</string>
                   </property>
                  </widget>
                 </item>
@@ -2273,13 +2215,10 @@ p, li { white-space: pre-wrap; }
                  </spacer>
                 </item>
                 <item>
-                 <spacer name="verticalSpacer_8">
+                 <spacer name="verticalSpacer_13">
                   <property name="orientation">
                    <enum>Qt::Vertical</enum>
                   </property>
-                  <property name="sizeType">
-                   <enum>QSizePolicy::Preferred</enum>
-                  </property>
                   <property name="sizeHint" stdset="0">
                    <size>
                     <width>20</width>
@@ -2289,29 +2228,92 @@ p, li { white-space: pre-wrap; }
                  </spacer>
                 </item>
                 <item>
-                 <widget class="QPushButton" name="pushButton_plotSelectedData">
-                  <property name="minimumSize">
-                   <size>
-                    <width>120</width>
-                    <height>0</height>
-                   </size>
-                  </property>
-                  <property name="maximumSize">
-                   <size>
-                    <width>120</width>
-                    <height>16777215</height>
-                   </size>
-                  </property>
-                  <property name="text">
-                   <string>Plot Scan</string>
+                 <widget class="QGroupBox" name="groupBox_24">
+                  <property name="title">
+                   <string>Peaks Filter</string>
                   </property>
+                  <layout class="QVBoxLayout" name="verticalLayout_11">
+                   <item>
+                    <widget class="QRadioButton" name="radioButton_ubSelectAllScans">
+                     <property name="font">
+                      <font>
+                       <pointsize>10</pointsize>
+                       <weight>75</weight>
+                       <bold>true</bold>
+                      </font>
+                     </property>
+                     <property name="text">
+                      <string>Select all Peaks</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item>
+                    <widget class="QRadioButton" name="radioButton_ubSelectNoScan">
+                     <property name="font">
+                      <font>
+                       <pointsize>10</pointsize>
+                       <weight>75</weight>
+                       <bold>true</bold>
+                      </font>
+                     </property>
+                     <property name="text">
+                      <string>No Peak</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item>
+                    <widget class="QRadioButton" name="radioButton_ubAdvancedSelection">
+                     <property name="font">
+                      <font>
+                       <pointsize>10</pointsize>
+                       <weight>75</weight>
+                       <bold>true</bold>
+                      </font>
+                     </property>
+                     <property name="text">
+                      <string>Advanced Setup</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item>
+                    <spacer name="verticalSpacer_10">
+                     <property name="orientation">
+                      <enum>Qt::Vertical</enum>
+                     </property>
+                     <property name="sizeType">
+                      <enum>QSizePolicy::Ignored</enum>
+                     </property>
+                     <property name="sizeHint" stdset="0">
+                      <size>
+                       <width>20</width>
+                       <height>40</height>
+                      </size>
+                     </property>
+                    </spacer>
+                   </item>
+                   <item>
+                    <widget class="QCheckBox" name="checkBox_hideUnselectedUBPeaks">
+                     <property name="font">
+                      <font>
+                       <pointsize>9</pointsize>
+                      </font>
+                     </property>
+                     <property name="text">
+                      <string>Hide Unselected</string>
+                     </property>
+                    </widget>
+                   </item>
+                  </layout>
                  </widget>
                 </item>
                 <item>
-                 <spacer name="verticalSpacer_11">
+                 <spacer name="verticalSpacer_8">
                   <property name="orientation">
                    <enum>Qt::Vertical</enum>
                   </property>
+                  <property name="sizeType">
+                   <enum>QSizePolicy::Preferred</enum>
+                  </property>
                   <property name="sizeHint" stdset="0">
                    <size>
                     <width>20</width>
@@ -2321,26 +2323,32 @@ p, li { white-space: pre-wrap; }
                  </spacer>
                 </item>
                 <item>
-                 <widget class="QPushButton" name="pushButton_deleteUBPeak">
-                  <property name="minimumSize">
-                   <size>
-                    <width>120</width>
-                    <height>0</height>
-                   </size>
+                 <widget class="Line" name="line_7">
+                  <property name="orientation">
+                   <enum>Qt::Horizontal</enum>
                   </property>
-                  <property name="maximumSize">
-                   <size>
-                    <width>120</width>
-                    <height>16777215</height>
-                   </size>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QPushButton" name="pushButton_2">
+                  <property name="font">
+                   <font>
+                    <pointsize>10</pointsize>
+                   </font>
                   </property>
                   <property name="text">
-                   <string>Delete</string>
+                   <string>Plot Scan 2D</string>
                   </property>
                  </widget>
                 </item>
                 <item>
-                 <widget class="QPushButton" name="pushButton_clearUBPeakTable">
+                 <widget class="QPushButton" name="pushButton_plotSelectedData">
+                  <property name="sizePolicy">
+                   <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                    <horstretch>0</horstretch>
+                    <verstretch>0</verstretch>
+                   </sizepolicy>
+                  </property>
                   <property name="minimumSize">
                    <size>
                     <width>120</width>
@@ -2349,25 +2357,56 @@ p, li { white-space: pre-wrap; }
                   </property>
                   <property name="maximumSize">
                    <size>
-                    <width>120</width>
+                    <width>200</width>
                     <height>16777215</height>
                    </size>
                   </property>
+                  <property name="font">
+                   <font>
+                    <pointsize>10</pointsize>
+                   </font>
+                  </property>
+                  <property name="text">
+                   <string>Plot Scan 3D</string>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QPushButton" name="pushButton_viewScan3D">
+                  <property name="font">
+                   <font>
+                    <pointsize>10</pointsize>
+                    <weight>50</weight>
+                    <bold>false</bold>
+                   </font>
+                  </property>
                   <property name="toolTip">
-                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Clear the peak table on the left&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt;View peak in 3D&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
                   </property>
                   <property name="text">
-                   <string>Clear</string>
+                   <string>View Peak</string>
                   </property>
                  </widget>
                 </item>
                 <item>
-                 <spacer name="verticalSpacer_12">
+                 <widget class="QPushButton" name="pushButton">
+                  <property name="font">
+                   <font>
+                    <pointsize>10</pointsize>
+                   </font>
+                  </property>
+                  <property name="text">
+                   <string>Show Spice File</string>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <spacer name="verticalSpacer_11">
                   <property name="orientation">
                    <enum>Qt::Vertical</enum>
                   </property>
                   <property name="sizeType">
-                   <enum>QSizePolicy::Ignored</enum>
+                   <enum>QSizePolicy::Preferred</enum>
                   </property>
                   <property name="sizeHint" stdset="0">
                    <size>
@@ -2378,9 +2417,138 @@ p, li { white-space: pre-wrap; }
                  </spacer>
                 </item>
                 <item>
-                 <spacer name="verticalSpacer_7">
+                 <widget class="Line" name="line_9">
                   <property name="orientation">
-                   <enum>Qt::Vertical</enum>
+                   <enum>Qt::Horizontal</enum>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QPushButton" name="pushButton_reCalPeakCenter">
+                  <property name="enabled">
+                   <bool>true</bool>
+                  </property>
+                  <property name="font">
+                   <font>
+                    <pointsize>11</pointsize>
+                   </font>
+                  </property>
+                  <property name="toolTip">
+                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Re-calculate selected peaks' centers with region of interest (ROI)&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                  </property>
+                  <property name="text">
+                   <string>Calculate Peak Center</string>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QComboBox" name="comboBox_maskNamesUB">
+                  <property name="enabled">
+                   <bool>true</bool>
+                  </property>
+                  <property name="font">
+                   <font>
+                    <pointsize>11</pointsize>
+                   </font>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <spacer name="verticalSpacer_29">
+                  <property name="orientation">
+                   <enum>Qt::Vertical</enum>
+                  </property>
+                  <property name="sizeType">
+                   <enum>QSizePolicy::Preferred</enum>
+                  </property>
+                  <property name="sizeHint" stdset="0">
+                   <size>
+                    <width>20</width>
+                    <height>40</height>
+                   </size>
+                  </property>
+                 </spacer>
+                </item>
+                <item>
+                 <widget class="Line" name="line_22">
+                  <property name="orientation">
+                   <enum>Qt::Horizontal</enum>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QPushButton" name="pushButton_deleteUBPeak">
+                  <property name="sizePolicy">
+                   <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                    <horstretch>0</horstretch>
+                    <verstretch>0</verstretch>
+                   </sizepolicy>
+                  </property>
+                  <property name="minimumSize">
+                   <size>
+                    <width>120</width>
+                    <height>0</height>
+                   </size>
+                  </property>
+                  <property name="maximumSize">
+                   <size>
+                    <width>200</width>
+                    <height>16777215</height>
+                   </size>
+                  </property>
+                  <property name="text">
+                   <string>Delete</string>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QPushButton" name="pushButton_clearUBPeakTable">
+                  <property name="sizePolicy">
+                   <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                    <horstretch>0</horstretch>
+                    <verstretch>0</verstretch>
+                   </sizepolicy>
+                  </property>
+                  <property name="minimumSize">
+                   <size>
+                    <width>120</width>
+                    <height>0</height>
+                   </size>
+                  </property>
+                  <property name="maximumSize">
+                   <size>
+                    <width>200</width>
+                    <height>16777215</height>
+                   </size>
+                  </property>
+                  <property name="toolTip">
+                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Clear the peak table on the left&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                  </property>
+                  <property name="text">
+                   <string>Clear</string>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <spacer name="verticalSpacer_12">
+                  <property name="orientation">
+                   <enum>Qt::Vertical</enum>
+                  </property>
+                  <property name="sizeType">
+                   <enum>QSizePolicy::Ignored</enum>
+                  </property>
+                  <property name="sizeHint" stdset="0">
+                   <size>
+                    <width>20</width>
+                    <height>40</height>
+                   </size>
+                  </property>
+                 </spacer>
+                </item>
+                <item>
+                 <spacer name="verticalSpacer_7">
+                  <property name="orientation">
+                   <enum>Qt::Vertical</enum>
                   </property>
                   <property name="sizeHint" stdset="0">
                    <size>
@@ -2463,7 +2631,22 @@ p, li { white-space: pre-wrap; }
                       <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt;Refine UB matrix by indexed peaks&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
                      </property>
                      <property name="text">
-                      <string>Refine by Indexed</string>
+                      <string>Refine by SPICE HKL</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item>
+                    <widget class="QPushButton" name="pushButton_refineUBCalIndex">
+                     <property name="font">
+                      <font>
+                       <pointsize>8</pointsize>
+                      </font>
+                     </property>
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt;Refine UB matrix by indexed peaks&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                     <property name="text">
+                      <string>Refine by Calculated HKL</string>
                      </property>
                     </widget>
                    </item>
@@ -2483,7 +2666,7 @@ p, li { white-space: pre-wrap; }
                      </property>
                      <property name="maximumSize">
                       <size>
-                       <width>120</width>
+                       <width>200</width>
                        <height>100</height>
                       </size>
                      </property>
@@ -3412,7 +3595,7 @@ p, li { white-space: pre-wrap; }
           </widget>
           <widget class="QWidget" name="tab_advsetup">
            <attribute name="title">
-            <string>Merge Scan</string>
+            <string>Scans Processing</string>
            </attribute>
            <layout class="QGridLayout" name="gridLayout_4">
             <item row="4" column="0">
@@ -3424,23 +3607,32 @@ p, li { white-space: pre-wrap; }
             </item>
             <item row="1" column="0">
              <layout class="QGridLayout" name="gridLayout_10">
-              <item row="0" column="6">
-               <spacer name="horizontalSpacer_12">
-                <property name="orientation">
-                 <enum>Qt::Horizontal</enum>
+              <item row="0" column="3">
+               <widget class="QLabel" name="label_peakIndexType">
+                <property name="font">
+                 <font>
+                  <pointsize>10</pointsize>
+                 </font>
                 </property>
-                <property name="sizeType">
-                 <enum>QSizePolicy::Preferred</enum>
+                <property name="text">
+                 <string>Peaks indexed by</string>
                 </property>
-                <property name="sizeHint" stdset="0">
+               </widget>
+              </item>
+              <item row="0" column="9">
+               <widget class="QLabel" name="label_30">
+                <property name="maximumSize">
                  <size>
-                  <width>40</width>
-                  <height>20</height>
+                  <width>100</width>
+                  <height>16777215</height>
                  </size>
                 </property>
-               </spacer>
+                <property name="text">
+                 <string>Scans List</string>
+                </property>
+               </widget>
               </item>
-              <item row="0" column="2">
+              <item row="0" column="5">
                <spacer name="horizontalSpacer_10">
                 <property name="orientation">
                  <enum>Qt::Horizontal</enum>
@@ -3456,27 +3648,7 @@ p, li { white-space: pre-wrap; }
                 </property>
                </spacer>
               </item>
-              <item row="0" column="3">
-               <widget class="QLabel" name="label_29">
-                <property name="toolTip">
-                 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For MDEventsWorkspace with merged runs&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;For example:&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-                </property>
-                <property name="text">
-                 <string>Base Workspace Name</string>
-                </property>
-               </widget>
-              </item>
-              <item row="0" column="4">
-               <widget class="QLineEdit" name="lineEdit_baseMergeMDName">
-                <property name="sizePolicy">
-                 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
-                  <horstretch>0</horstretch>
-                  <verstretch>0</verstretch>
-                 </sizepolicy>
-                </property>
-               </widget>
-              </item>
-              <item row="0" column="1">
+              <item row="0" column="10">
                <widget class="QLineEdit" name="lineEdit_listScansSliceView">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
@@ -3489,14 +3661,35 @@ p, li { white-space: pre-wrap; }
                 </property>
                </widget>
               </item>
-              <item row="0" column="0">
-               <widget class="QLabel" name="label_30">
+              <item row="0" column="7">
+               <widget class="QPushButton" name="pushButton_showIntegrateDetails">
+                <property name="font">
+                 <font>
+                  <pointsize>9</pointsize>
+                 </font>
+                </property>
                 <property name="text">
-                 <string>Scans List</string>
+                 <string>Show Integrate Details</string>
                 </property>
                </widget>
               </item>
               <item row="0" column="8">
+               <spacer name="horizontalSpacer_39">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeType">
+                 <enum>QSizePolicy::Preferred</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>40</width>
+                  <height>20</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item row="0" column="6">
                <widget class="QPushButton" name="pushButton_showUB">
                 <property name="font">
                  <font>
@@ -3508,25 +3701,38 @@ p, li { white-space: pre-wrap; }
                 </property>
                </widget>
               </item>
-              <item row="0" column="5">
-               <widget class="QCheckBox" name="checkBox_useDefaultMergedName">
+              <item row="0" column="0">
+               <widget class="QLabel" name="label_29">
+                <property name="font">
+                 <font>
+                  <pointsize>10</pointsize>
+                 </font>
+                </property>
                 <property name="text">
-                 <string>default</string>
+                 <string>Scan Merging &amp; Integration Table</string>
                 </property>
                </widget>
               </item>
-              <item row="0" column="9">
-               <widget class="QPushButton" name="pushButton_refreshMerged">
-                <property name="enabled">
-                 <bool>false</bool>
+              <item row="0" column="2">
+               <spacer name="horizontalSpacer_12">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
                 </property>
-                <property name="font">
-                 <font>
-                  <pointsize>10</pointsize>
-                 </font>
+                <property name="sizeType">
+                 <enum>QSizePolicy::Ignored</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>40</width>
+                  <height>20</height>
+                 </size>
                 </property>
+               </spacer>
+              </item>
+              <item row="0" column="4">
+               <widget class="QLabel" name="label_peaksIndexedBy">
                 <property name="text">
-                 <string>Refresh</string>
+                 <string/>
                 </property>
                </widget>
               </item>
@@ -3544,6 +3750,11 @@ p, li { white-space: pre-wrap; }
             </item>
             <item row="3" column="0">
              <widget class="ProcessTableWidget" name="tableWidget_mergeScans">
+              <property name="font">
+               <font>
+                <pointsize>9</pointsize>
+               </font>
+              </property>
               <property name="toolTip">
                <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;? columns: &lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;1. Scan number&lt;/p&gt;&lt;p&gt;2. Number of Pts.&lt;/p&gt;&lt;p&gt;3. Status: &lt;/p&gt;&lt;p&gt;(a) done&lt;/p&gt;&lt;p&gt;(b) error with error message&lt;/p&gt;&lt;p&gt;(c) on-going&lt;/p&gt;&lt;p&gt;(d) empty as not yet&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
               </property>
@@ -3596,21 +3807,76 @@ p, li { white-space: pre-wrap; }
                </widget>
               </item>
               <item>
-               <widget class="Line" name="line_8">
-                <property name="orientation">
-                 <enum>Qt::Horizontal</enum>
+               <widget class="QPushButton" name="pushButton_refreshMerged">
+                <property name="enabled">
+                 <bool>true</bool>
+                </property>
+                <property name="font">
+                 <font>
+                  <pointsize>10</pointsize>
+                 </font>
+                </property>
+                <property name="text">
+                 <string>Refresh Table</string>
                 </property>
                </widget>
               </item>
               <item>
-               <widget class="QGroupBox" name="groupBox_20">
+               <widget class="QPushButton" name="pushButton_toggleIntegrateType">
                 <property name="font">
                  <font>
-                  <pointsize>10</pointsize>
+                  <pointsize>9</pointsize>
                  </font>
                 </property>
-                <property name="title">
-                 <string>Single Scan</string>
+                <property name="text">
+                 <string>Toggle Int Type</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QPushButton" name="pushButton_exportSelectedPeaks">
+                <property name="font">
+                 <font>
+                  <pointsize>9</pointsize>
+                 </font>
+                </property>
+                <property name="text">
+                 <string>Export Selection</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <spacer name="verticalSpacer_24">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeType">
+                 <enum>QSizePolicy::Preferred</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>40</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item>
+               <widget class="Line" name="line_8">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QGroupBox" name="groupBox_20">
+                <property name="font">
+                 <font>
+                  <pointsize>10</pointsize>
+                 </font>
+                </property>
+                <property name="title">
+                 <string>Single Scan</string>
                 </property>
                 <layout class="QVBoxLayout" name="verticalLayout_20">
                  <item>
@@ -3630,6 +3896,21 @@ p, li { white-space: pre-wrap; }
                    </property>
                   </widget>
                  </item>
+                 <item>
+                  <widget class="QPushButton" name="pushButton_setupPeakIntegration">
+                   <property name="font">
+                    <font>
+                     <pointsize>10</pointsize>
+                    </font>
+                   </property>
+                   <property name="toolTip">
+                    <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Switch to tab 'Peak Integrate' to set up options for peak integration&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                   </property>
+                   <property name="text">
+                    <string>Single Pt. Set up</string>
+                   </property>
+                  </widget>
+                 </item>
                  <item>
                   <widget class="QPushButton" name="pushButton_convertMerged2HKL">
                    <property name="font">
@@ -3660,13 +3941,6 @@ p, li { white-space: pre-wrap; }
                 </layout>
                </widget>
               </item>
-              <item>
-               <widget class="Line" name="line_2">
-                <property name="orientation">
-                 <enum>Qt::Horizontal</enum>
-                </property>
-               </widget>
-              </item>
               <item>
                <spacer name="verticalSpacer_23">
                 <property name="orientation">
@@ -3683,6 +3957,13 @@ p, li { white-space: pre-wrap; }
                 </property>
                </spacer>
               </item>
+              <item>
+               <widget class="Line" name="line_2">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+               </widget>
+              </item>
               <item>
                <widget class="QGroupBox" name="groupBox_22">
                 <property name="font">
@@ -3894,7 +4175,7 @@ p, li { white-space: pre-wrap; }
                 </property>
                </widget>
               </item>
-              <item row="1" column="0">
+              <item row="2" column="0">
                <widget class="QPushButton" name="pushButton_exportPeaks">
                 <property name="font">
                  <font>
@@ -3908,28 +4189,44 @@ p, li { white-space: pre-wrap; }
                 </property>
                </widget>
               </item>
+              <item row="1" column="0">
+               <widget class="Line" name="line_14">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+               </widget>
+              </item>
              </layout>
             </item>
             <item row="5" column="0">
              <layout class="QGridLayout" name="gridLayout_22">
-              <item row="0" column="10">
-               <spacer name="horizontalSpacer_19">
-                <property name="orientation">
-                 <enum>Qt::Horizontal</enum>
+              <item row="0" column="8">
+               <widget class="QLabel" name="label_39">
+                <property name="font">
+                 <font>
+                  <pointsize>10</pointsize>
+                  <weight>75</weight>
+                  <bold>true</bold>
+                 </font>
                 </property>
-                <property name="sizeType">
-                 <enum>QSizePolicy::Preferred</enum>
+                <property name="text">
+                 <string>Scale Factor</string>
                 </property>
-                <property name="sizeHint" stdset="0">
+               </widget>
+              </item>
+              <item row="0" column="9">
+               <widget class="QLineEdit" name="lineEdit_scaleFactor">
+                <property name="maximumSize">
                  <size>
-                  <width>40</width>
-                  <height>20</height>
+                  <width>180</width>
+                  <height>16777215</height>
                  </size>
                 </property>
-               </spacer>
-              </item>
-              <item row="0" column="8">
-               <widget class="QLineEdit" name="lineEdit_scaleFactor">
+                <property name="font">
+                 <font>
+                  <pointsize>10</pointsize>
+                 </font>
+                </property>
                 <property name="toolTip">
                  <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Peak intensity scale factor&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
                 </property>
@@ -3949,7 +4246,7 @@ p, li { white-space: pre-wrap; }
                 </item>
                </widget>
               </item>
-              <item row="1" column="0">
+              <item row="2" column="0">
                <widget class="QLabel" name="label_52">
                 <property name="font">
                  <font>
@@ -3962,8 +4259,14 @@ p, li { white-space: pre-wrap; }
                 </property>
                </widget>
               </item>
-              <item row="1" column="2">
-               <widget class="QComboBox" name="comboBox_kVectors"/>
+              <item row="2" column="2">
+               <widget class="QComboBox" name="comboBox_kVectors">
+                <property name="font">
+                 <font>
+                  <pointsize>10</pointsize>
+                 </font>
+                </property>
+               </widget>
               </item>
               <item row="0" column="0">
                <widget class="QLabel" name="label_47">
@@ -3978,25 +4281,16 @@ p, li { white-space: pre-wrap; }
                 </property>
                </widget>
               </item>
-              <item row="0" column="7">
-               <widget class="QLabel" name="label_39">
+              <item row="0" column="2">
+               <widget class="QComboBox" name="comboBox_mergePeakNormType">
                 <property name="font">
                  <font>
                   <pointsize>10</pointsize>
-                  <weight>75</weight>
-                  <bold>true</bold>
                  </font>
                 </property>
-                <property name="text">
-                 <string>Scale Factor</string>
-                </property>
-               </widget>
-              </item>
-              <item row="0" column="2">
-               <widget class="QComboBox" name="comboBox_mergePeakNormType">
                 <item>
                  <property name="text">
-                  <string>Absolute</string>
+                  <string>Normalized by Time</string>
                  </property>
                 </item>
                 <item>
@@ -4006,7 +4300,7 @@ p, li { white-space: pre-wrap; }
                 </item>
                 <item>
                  <property name="text">
-                  <string>Normalized by Time</string>
+                  <string>Absolute</string>
                  </property>
                 </item>
                </widget>
@@ -4027,14 +4321,7 @@ p, li { white-space: pre-wrap; }
                 </property>
                </spacer>
               </item>
-              <item row="0" column="6">
-               <widget class="QLineEdit" name="lineEdit_numPt4BackgroundRight">
-                <property name="toolTip">
-                 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Number of background points take for the right side if it is different from that for left side&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-                </property>
-               </widget>
-              </item>
-              <item row="1" column="3">
+              <item row="2" column="3">
                <widget class="QPushButton" name="pushButton_applyKShift">
                 <property name="font">
                  <font>
@@ -4049,36 +4336,92 @@ p, li { white-space: pre-wrap; }
                 </property>
                </widget>
               </item>
-              <item row="0" column="9">
-               <widget class="QPushButton" name="pushButton_setupPeakIntegration">
+              <item row="0" column="6">
+               <widget class="QLabel" name="label_48">
                 <property name="font">
                  <font>
                   <pointsize>10</pointsize>
+                  <weight>50</weight>
+                  <bold>false</bold>
                  </font>
                 </property>
+                <property name="text">
+                 <string>Background</string>
+                </property>
+               </widget>
+              </item>
+              <item row="2" column="9">
+               <widget class="QComboBox" name="comboBox_kVectorToExport">
                 <property name="toolTip">
-                 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Switch to tab 'Peak Integrate' to set up options for peak integration&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;select the K-vector to export.  Option includes&lt;/p&gt;&lt;p&gt;1. nuclear peaks: k-vector = (0, 0, 0)&lt;/p&gt;&lt;p&gt;2. magnetic peaks with certain k-vector&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
                 </property>
-                <property name="text">
-                 <string>Single Pt. Set up</string>
+               </widget>
+              </item>
+              <item row="1" column="10">
+               <widget class="Line" name="line_17">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
                 </property>
                </widget>
               </item>
-              <item row="0" column="5">
-               <widget class="QLineEdit" name="lineEdit_numPt4Background">
-                <property name="sizePolicy">
-                 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
-                  <horstretch>0</horstretch>
-                  <verstretch>0</verstretch>
-                 </sizepolicy>
+              <item row="1" column="8">
+               <widget class="Line" name="line_11">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
                 </property>
-                <property name="toolTip">
-                 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Number of Pt. to calculate background&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+               </widget>
+              </item>
+              <item row="0" column="7">
+               <layout class="QHBoxLayout" name="horizontalLayout_23">
+                <item>
+                 <widget class="QLineEdit" name="lineEdit_numPt4Background">
+                  <property name="sizePolicy">
+                   <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                    <horstretch>0</horstretch>
+                    <verstretch>0</verstretch>
+                   </sizepolicy>
+                  </property>
+                  <property name="maximumSize">
+                   <size>
+                    <width>60</width>
+                    <height>16777215</height>
+                   </size>
+                  </property>
+                  <property name="toolTip">
+                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Number of Pt. to calculate background&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QLineEdit" name="lineEdit_numPt4BackgroundRight">
+                  <property name="sizePolicy">
+                   <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                    <horstretch>0</horstretch>
+                    <verstretch>0</verstretch>
+                   </sizepolicy>
+                  </property>
+                  <property name="maximumSize">
+                   <size>
+                    <width>60</width>
+                    <height>16777215</height>
+                   </size>
+                  </property>
+                  <property name="toolTip">
+                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Number of background points take for the right side if it is different from that for left side&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                  </property>
+                 </widget>
+                </item>
+               </layout>
+              </item>
+              <item row="1" column="0">
+               <widget class="Line" name="line_10">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
                 </property>
                </widget>
               </item>
               <item row="0" column="4">
-               <widget class="QLabel" name="label_48">
+               <widget class="QCheckBox" name="checkBox">
                 <property name="font">
                  <font>
                   <pointsize>10</pointsize>
@@ -4086,15 +4429,28 @@ p, li { white-space: pre-wrap; }
                   <bold>true</bold>
                  </font>
                 </property>
+                <property name="toolTip">
+                 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If True, then the peak intensity will be calculated for a Gaussian function, which is fit to a Pt. - Counts curve.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Function to fit is a Gaussian plus linear background&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                </property>
                 <property name="text">
-                 <string>Background</string>
+                 <string>Fit By Gaussian</string>
                 </property>
                </widget>
               </item>
-              <item row="1" column="9">
-               <widget class="QComboBox" name="comboBox_kVectorToExport"/>
+              <item row="2" column="7">
+               <widget class="QLabel" name="label_63">
+                <property name="font">
+                 <font>
+                  <weight>75</weight>
+                  <bold>true</bold>
+                 </font>
+                </property>
+                <property name="text">
+                 <string>Export Setup</string>
+                </property>
+               </widget>
               </item>
-              <item row="1" column="8">
+              <item row="2" column="8">
                <widget class="QCheckBox" name="checkBox_exportAbsorptionToFP">
                 <property name="font">
                  <font>
@@ -4110,92 +4466,148 @@ p, li { white-space: pre-wrap; }
                 </property>
                </widget>
               </item>
-             </layout>
-            </item>
-           </layout>
-          </widget>
-          <widget class="QWidget" name="tab_indexPeak">
-           <attribute name="title">
-            <string>Peak Integration</string>
-           </attribute>
-           <layout class="QVBoxLayout" name="verticalLayout_11">
-            <item>
-             <layout class="QGridLayout" name="gridLayout_13">
-              <item row="0" column="5">
-               <spacer name="horizontalSpacer_17">
+              <item row="1" column="7">
+               <widget class="Line" name="line_12">
                 <property name="orientation">
                  <enum>Qt::Horizontal</enum>
                 </property>
-                <property name="sizeType">
-                 <enum>QSizePolicy::Expanding</enum>
-                </property>
-                <property name="sizeHint" stdset="0">
-                 <size>
-                  <width>40</width>
-                  <height>20</height>
-                 </size>
-                </property>
-               </spacer>
+               </widget>
               </item>
-              <item row="0" column="10">
-               <widget class="QLineEdit" name="lineEdit_background">
-                <property name="sizePolicy">
-                 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
-                  <horstretch>0</horstretch>
-                  <verstretch>0</verstretch>
-                 </sizepolicy>
+              <item row="2" column="5">
+               <widget class="Line" name="line_15">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
                 </property>
                </widget>
               </item>
-              <item row="0" column="1">
-               <widget class="QLineEdit" name="lineEdit_scanIntegratePeak">
-                <property name="sizePolicy">
-                 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
-                  <horstretch>0</horstretch>
-                  <verstretch>0</verstretch>
-                 </sizepolicy>
+              <item row="1" column="9">
+               <widget class="Line" name="line_16">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+               </widget>
+              </item>
+              <item row="0" column="10">
+               <spacer name="horizontalSpacer_19">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeType">
+                 <enum>QSizePolicy::Preferred</enum>
                 </property>
-                <property name="readOnly">
-                 <bool>false</bool>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>42</width>
+                  <height>26</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item row="1" column="6">
+               <widget class="Line" name="line_13">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
                 </property>
                </widget>
               </item>
-              <item row="0" column="0">
-               <widget class="QLabel" name="label_5">
-                <property name="text">
-                 <string>Scan Number</string>
+              <item row="1" column="2">
+               <widget class="Line" name="line_18">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
                 </property>
                </widget>
               </item>
-              <item row="0" column="2">
-               <widget class="QPushButton" name="pushButton_nextScanIntegrate">
-                <property name="text">
-                 <string>Next</string>
+              <item row="1" column="1">
+               <widget class="Line" name="line_19">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
                 </property>
                </widget>
               </item>
-              <item row="0" column="6">
-               <widget class="QLabel" name="label_34">
-                <property name="text">
-                 <string>Peak Radius</string>
+              <item row="1" column="3">
+               <widget class="Line" name="line_20">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
                 </property>
                </widget>
               </item>
-              <item row="0" column="11">
-               <widget class="QPushButton" name="pushButton_integratePeak">
-                <property name="font">
-                 <font>
-                  <weight>50</weight>
-                  <bold>false</bold>
-                 </font>
+              <item row="1" column="4">
+               <widget class="Line" name="line_21">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </item>
+           </layout>
+          </widget>
+          <widget class="QWidget" name="tab_indexPeak">
+           <attribute name="title">
+            <string>Peak Integration</string>
+           </attribute>
+           <layout class="QGridLayout" name="gridLayout_13">
+            <item row="0" column="3">
+             <layout class="QHBoxLayout" name="horizontalLayout_21">
+              <item>
+               <layout class="QHBoxLayout" name="horizontalLayout_20">
+                <item>
+                 <widget class="QLabel" name="label_34">
+                  <property name="text">
+                   <string>Scan Number</string>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QLineEdit" name="lineEdit_scanIntegratePeak">
+                  <property name="sizePolicy">
+                   <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                    <horstretch>0</horstretch>
+                    <verstretch>0</verstretch>
+                   </sizepolicy>
+                  </property>
+                  <property name="readOnly">
+                   <bool>false</bool>
+                  </property>
+                 </widget>
+                </item>
+               </layout>
+              </item>
+              <item>
+               <widget class="QPushButton" name="pushButton_integratePt">
+                <property name="toolTip">
+                 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Function to fit Pt.&lt;/p&gt;&lt;p&gt;  A * exp( - (x-x0)**2/(2 * sigma**2) )+B&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
                 </property>
                 <property name="text">
                  <string>Integrate Peak</string>
                 </property>
                </widget>
               </item>
-              <item row="0" column="7">
-               <widget class="QLineEdit" name="lineEdit_peakRadius">
+              <item>
+               <spacer name="horizontalSpacer_17">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeType">
+                 <enum>QSizePolicy::Ignored</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>40</width>
+                  <height>20</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item>
+               <widget class="QLabel" name="label_69">
+                <property name="text">
+                 <string>Scale Factor</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QLineEdit" name="lineEdit_scaleFactorScan">
                 <property name="sizePolicy">
                  <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
                   <horstretch>0</horstretch>
@@ -4204,156 +4616,655 @@ p, li { white-space: pre-wrap; }
                 </property>
                </widget>
               </item>
-              <item row="0" column="9">
-               <widget class="QLabel" name="label_46">
+              <item>
+               <widget class="QLabel" name="label_64">
                 <property name="text">
-                 <string>Background</string>
+                 <string>Background Pts.</string>
                 </property>
                </widget>
               </item>
-             </layout>
-            </item>
-            <item>
-             <widget class="QLabel" name="label_peakIntegraeInfo">
-              <property name="text">
-               <string>TextLabel</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <layout class="QGridLayout" name="gridLayout_15">
-              <item row="0" column="0">
-               <widget class="PeakIntegrationTableWidget" name="tableWidget_peakIntegration">
+              <item>
+               <widget class="QLineEdit" name="lineEdit_backgroundPts">
                 <property name="sizePolicy">
-                 <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+                 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
                   <horstretch>0</horstretch>
                   <verstretch>0</verstretch>
                  </sizepolicy>
                 </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QComboBox" name="comboBox_ptCountType"/>
+              </item>
+              <item>
+               <widget class="QComboBox" name="comboBox_maskNames2">
+                <item>
+                 <property name="text">
+                  <string>No Mask</string>
+                 </property>
+                </item>
+               </widget>
+              </item>
+              <item>
+               <widget class="QCheckBox" name="checkBox_use3algorithms">
+                <property name="text">
+                 <string>3 algorithms</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <spacer name="horizontalSpacer_20">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeType">
+                 <enum>QSizePolicy::Preferred</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>40</width>
+                  <height>20</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item>
+               <widget class="QPushButton" name="pushButton_showIntPeakDetails">
+                <property name="enabled">
+                 <bool>true</bool>
+                </property>
                 <property name="toolTip">
-                 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Table for integrating Pts belogned to same scan.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Fit by Gaussian for background&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                </property>
+                <property name="text">
+                 <string>See Details</string>
                 </property>
                </widget>
               </item>
-              <item row="1" column="1">
-               <layout class="QGridLayout" name="gridLayout_20">
-                <item row="1" column="3">
-                 <spacer name="horizontalSpacer_20">
-                  <property name="orientation">
-                   <enum>Qt::Horizontal</enum>
+             </layout>
+            </item>
+            <item row="2" column="3">
+             <widget class="IntegratedPeakView" name="graphicsView_integratedPeakView">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="font">
+               <font>
+                <pointsize>10</pointsize>
+               </font>
+              </property>
+             </widget>
+            </item>
+            <item row="3" column="3">
+             <layout class="QHBoxLayout" name="horizontalLayout_22">
+              <item>
+               <layout class="QGridLayout" name="gridLayout_15">
+                <item row="1" column="4">
+                 <widget class="QLabel" name="label_68">
+                  <property name="font">
+                   <font>
+                    <pointsize>10</pointsize>
+                   </font>
                   </property>
-                  <property name="sizeType">
-                   <enum>QSizePolicy::Expanding</enum>
+                  <property name="text">
+                   <string>Pt. Range</string>
                   </property>
-                  <property name="sizeHint" stdset="0">
-                   <size>
-                    <width>40</width>
-                    <height>20</height>
-                   </size>
+                 </widget>
+                </item>
+                <item row="2" column="1">
+                 <widget class="QLineEdit" name="lineEdit_gaussianPeakIntensity">
+                  <property name="enabled">
+                   <bool>true</bool>
                   </property>
-                 </spacer>
+                  <property name="sizePolicy">
+                   <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                    <horstretch>0</horstretch>
+                    <verstretch>0</verstretch>
+                   </sizepolicy>
+                  </property>
+                  <property name="font">
+                   <font>
+                    <pointsize>10</pointsize>
+                   </font>
+                  </property>
+                  <property name="dragEnabled">
+                   <bool>true</bool>
+                  </property>
+                  <property name="readOnly">
+                   <bool>true</bool>
+                  </property>
+                 </widget>
+                </item>
+                <item row="0" column="0">
+                 <widget class="QLabel" name="label_32">
+                  <property name="font">
+                   <font>
+                    <pointsize>10</pointsize>
+                   </font>
+                  </property>
+                  <property name="toolTip">
+                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Intensity calculated by &lt;/span&gt;&lt;span style=&quot; font-size:12pt; font-weight:600;&quot;&gt;simple summation&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt; with &lt;/span&gt;&lt;span style=&quot; font-size:12pt; font-weight:600;&quot;&gt;averaged background&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                  </property>
+                  <property name="text">
+                   <string>Intensity 1</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="0" column="1">
+                 <widget class="QLineEdit" name="lineEdit_rawSinglePeakIntensity">
+                  <property name="enabled">
+                   <bool>true</bool>
+                  </property>
+                  <property name="sizePolicy">
+                   <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                    <horstretch>0</horstretch>
+                    <verstretch>0</verstretch>
+                   </sizepolicy>
+                  </property>
+                  <property name="font">
+                   <font>
+                    <pointsize>10</pointsize>
+                   </font>
+                  </property>
+                  <property name="toolTip">
+                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Intensity calculated by &lt;span style=&quot; font-weight:600;&quot;&gt;simple summation&lt;/span&gt; with &lt;span style=&quot; font-weight:600;&quot;&gt;averaged background&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                  </property>
+                  <property name="dragEnabled">
+                   <bool>true</bool>
+                  </property>
+                  <property name="readOnly">
+                   <bool>true</bool>
+                  </property>
+                 </widget>
+                </item>
+                <item row="0" column="4">
+                 <widget class="QLabel" name="label_46">
+                  <property name="font">
+                   <font>
+                    <pointsize>10</pointsize>
+                   </font>
+                  </property>
+                  <property name="text">
+                   <string>Background</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="0" column="5">
+                 <widget class="QLineEdit" name="lineEdit_avgBackground">
+                  <property name="sizePolicy">
+                   <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                    <horstretch>0</horstretch>
+                    <verstretch>0</verstretch>
+                   </sizepolicy>
+                  </property>
+                  <property name="font">
+                   <font>
+                    <pointsize>10</pointsize>
+                   </font>
+                  </property>
+                  <property name="readOnly">
+                   <bool>true</bool>
+                  </property>
+                 </widget>
+                </item>
+                <item row="1" column="0">
+                 <widget class="QLabel" name="label_65">
+                  <property name="font">
+                   <font>
+                    <pointsize>10</pointsize>
+                   </font>
+                  </property>
+                  <property name="toolTip">
+                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Intensity calculated by &lt;span style=&quot; font-weight:600;&quot;&gt;simple summation&lt;/span&gt; with &lt;span style=&quot; font-weight:600;&quot;&gt;fitted flat background&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Fit function: Gaussian + Flat background&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                  </property>
+                  <property name="text">
+                   <string>Intensity 2</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="1" column="1">
+                 <widget class="QLineEdit" name="lineEdit_intensity2">
+                  <property name="sizePolicy">
+                   <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                    <horstretch>0</horstretch>
+                    <verstretch>0</verstretch>
+                   </sizepolicy>
+                  </property>
+                  <property name="font">
+                   <font>
+                    <pointsize>10</pointsize>
+                   </font>
+                  </property>
+                  <property name="toolTip">
+                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Intensity calculated by &lt;span style=&quot; font-weight:600;&quot;&gt;simple summation&lt;/span&gt; with &lt;span style=&quot; font-weight:600;&quot;&gt;fitted flat background&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Fit function: Gaussian + Flat background&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                  </property>
+                  <property name="dragEnabled">
+                   <bool>true</bool>
+                  </property>
+                  <property name="readOnly">
+                   <bool>true</bool>
+                  </property>
+                 </widget>
+                </item>
+                <item row="0" column="3">
+                 <widget class="QLineEdit" name="lineEdit_errorIntensity1">
+                  <property name="sizePolicy">
+                   <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                    <horstretch>0</horstretch>
+                    <verstretch>0</verstretch>
+                   </sizepolicy>
+                  </property>
+                  <property name="font">
+                   <font>
+                    <pointsize>10</pointsize>
+                   </font>
+                  </property>
+                 </widget>
+                </item>
+                <item row="2" column="0">
+                 <widget class="QLabel" name="label_45">
+                  <property name="font">
+                   <font>
+                    <pointsize>10</pointsize>
+                   </font>
+                  </property>
+                  <property name="text">
+                   <string>Intensity 3</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="2" column="4">
+                 <widget class="QLabel" name="label_66">
+                  <property name="font">
+                   <font>
+                    <pointsize>10</pointsize>
+                   </font>
+                  </property>
+                  <property name="text">
+                   <string>Gaussian B</string>
+                  </property>
+                 </widget>
                 </item>
                 <item row="1" column="5">
-                 <widget class="QPushButton" name="pushButton_handPickBkgd">
+                 <widget class="QLineEdit" name="lineEdit_ptRange">
+                  <property name="sizePolicy">
+                   <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                    <horstretch>0</horstretch>
+                    <verstretch>0</verstretch>
+                   </sizepolicy>
+                  </property>
+                  <property name="font">
+                   <font>
+                    <pointsize>10</pointsize>
+                   </font>
+                  </property>
+                 </widget>
+                </item>
+                <item row="1" column="3">
+                 <widget class="QLineEdit" name="lineEdit_errorIntensity2">
+                  <property name="sizePolicy">
+                   <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                    <horstretch>0</horstretch>
+                    <verstretch>0</verstretch>
+                   </sizepolicy>
+                  </property>
+                  <property name="font">
+                   <font>
+                    <pointsize>10</pointsize>
+                   </font>
+                  </property>
+                 </widget>
+                </item>
+                <item row="2" column="5">
+                 <widget class="QLineEdit" name="lineEdit_peakBackground">
                   <property name="enabled">
-                   <bool>false</bool>
+                   <bool>true</bool>
+                  </property>
+                  <property name="sizePolicy">
+                   <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                    <horstretch>0</horstretch>
+                    <verstretch>0</verstretch>
+                   </sizepolicy>
                   </property>
                   <property name="font">
                    <font>
-                    <pointsize>11</pointsize>
+                    <pointsize>10</pointsize>
                    </font>
                   </property>
                   <property name="toolTip">
-                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;User hand-pick background&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Background value from fitted Gaussian&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
                   </property>
-                  <property name="text">
-                   <string>Customize Bkgd</string>
+                  <property name="dragEnabled">
+                   <bool>true</bool>
+                  </property>
+                  <property name="readOnly">
+                   <bool>true</bool>
                   </property>
                  </widget>
                 </item>
-                <item row="0" column="5">
-                 <widget class="QPushButton" name="pushButton_fitBkgd">
-                  <property name="enabled">
-                   <bool>false</bool>
-                  </property>
-                  <property name="toolTip">
-                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Fit by Gaussian for background&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                <item row="2" column="3">
+                 <widget class="QLineEdit" name="lineEdit_errorIntensity3">
+                  <property name="sizePolicy">
+                   <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                    <horstretch>0</horstretch>
+                    <verstretch>0</verstretch>
+                   </sizepolicy>
                   </property>
-                  <property name="text">
-                   <string>Fit Background</string>
+                  <property name="font">
+                   <font>
+                    <pointsize>10</pointsize>
+                   </font>
                   </property>
                  </widget>
                 </item>
-                <item row="0" column="1">
-                 <widget class="QComboBox" name="comboBox_ptCountType">
-                  <item>
-                   <property name="text">
-                    <string>Absolute</string>
-                   </property>
-                  </item>
-                  <item>
-                   <property name="text">
-                    <string>Normalized by Time</string>
-                   </property>
-                  </item>
-                  <item>
-                   <property name="text">
-                    <string>Normalized by Monitor</string>
-                   </property>
-                  </item>
+                <item row="0" column="2">
+                 <widget class="QLabel" name="label_5">
+                  <property name="text">
+                   <string>+/-</string>
+                  </property>
                  </widget>
                 </item>
-                <item row="1" column="1">
-                 <widget class="QComboBox" name="comboBox_maskNames2">
-                  <item>
-                   <property name="text">
-                    <string>No Mask</string>
-                   </property>
-                  </item>
+                <item row="1" column="2">
+                 <widget class="QLabel" name="label_7">
+                  <property name="text">
+                   <string>+/-</string>
+                  </property>
                  </widget>
                 </item>
-                <item row="0" column="6">
-                 <widget class="QCheckBox" name="checkBox_peakIntTabLorentzCorr">
+                <item row="2" column="2">
+                 <widget class="QLabel" name="label_31">
                   <property name="text">
-                   <string>Lorentz Correction</string>
+                   <string>+/-</string>
                   </property>
                  </widget>
                 </item>
                </layout>
               </item>
-              <item row="1" column="0">
-               <layout class="QGridLayout" name="gridLayout_21">
-                <item row="1" column="0">
-                 <widget class="QPushButton" name="pushButton_calBkgd">
+              <item>
+               <spacer name="horizontalSpacer_40">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeType">
+                 <enum>QSizePolicy::Preferred</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>40</width>
+                  <height>20</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item>
+               <layout class="QVBoxLayout" name="verticalLayout_23">
+                <item>
+                 <widget class="QLabel" name="label_53">
+                  <property name="maximumSize">
+                   <size>
+                    <width>16777215</width>
+                    <height>40</height>
+                   </size>
+                  </property>
                   <property name="font">
                    <font>
-                    <pointsize>11</pointsize>
+                    <pointsize>10</pointsize>
                    </font>
                   </property>
                   <property name="text">
-                   <string>Calculate Background</string>
+                   <string>Fitted Parameters</string>
                   </property>
                  </widget>
                 </item>
-                <item row="0" column="0">
-                 <widget class="QPushButton" name="pushButton_integratePt">
-                  <property name="text">
-                   <string>Integrate Pt</string>
-                  </property>
-                 </widget>
+                <item>
+                 <layout class="QGridLayout" name="gridLayout_20">
+                  <item row="1" column="3">
+                   <widget class="QLineEdit" name="lineEdit_guassX0">
+                    <property name="sizePolicy">
+                     <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                      <horstretch>0</horstretch>
+                      <verstretch>0</verstretch>
+                     </sizepolicy>
+                    </property>
+                    <property name="maximumSize">
+                     <size>
+                      <width>80</width>
+                      <height>16777215</height>
+                     </size>
+                    </property>
+                    <property name="font">
+                     <font>
+                      <pointsize>10</pointsize>
+                     </font>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="0" column="3">
+                   <widget class="QLineEdit" name="lineEdit_gaussSigma">
+                    <property name="sizePolicy">
+                     <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                      <horstretch>0</horstretch>
+                      <verstretch>0</verstretch>
+                     </sizepolicy>
+                    </property>
+                    <property name="maximumSize">
+                     <size>
+                      <width>80</width>
+                      <height>16777215</height>
+                     </size>
+                    </property>
+                    <property name="font">
+                     <font>
+                      <pointsize>10</pointsize>
+                     </font>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="0" column="2">
+                   <widget class="QLabel" name="label_61">
+                    <property name="font">
+                     <font>
+                      <pointsize>10</pointsize>
+                     </font>
+                    </property>
+                    <property name="text">
+                     <string>Sigma</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="0" column="0">
+                   <widget class="QLabel" name="label_54">
+                    <property name="font">
+                     <font>
+                      <pointsize>10</pointsize>
+                     </font>
+                    </property>
+                    <property name="text">
+                     <string>A</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="1" column="0">
+                   <widget class="QLabel" name="label_62">
+                    <property name="font">
+                     <font>
+                      <pointsize>10</pointsize>
+                     </font>
+                    </property>
+                    <property name="text">
+                     <string>B  </string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="1" column="2">
+                   <widget class="QLabel" name="label_67">
+                    <property name="font">
+                     <font>
+                      <pointsize>10</pointsize>
+                     </font>
+                    </property>
+                    <property name="text">
+                     <string>X0</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="1" column="1">
+                   <widget class="QLineEdit" name="lineEdit_gaussB">
+                    <property name="sizePolicy">
+                     <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                      <horstretch>0</horstretch>
+                      <verstretch>0</verstretch>
+                     </sizepolicy>
+                    </property>
+                    <property name="maximumSize">
+                     <size>
+                      <width>80</width>
+                      <height>16777215</height>
+                     </size>
+                    </property>
+                    <property name="font">
+                     <font>
+                      <pointsize>10</pointsize>
+                     </font>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="0" column="1">
+                   <widget class="QLineEdit" name="lineEdit_gaussA">
+                    <property name="sizePolicy">
+                     <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                      <horstretch>0</horstretch>
+                      <verstretch>0</verstretch>
+                     </sizepolicy>
+                    </property>
+                    <property name="maximumSize">
+                     <size>
+                      <width>80</width>
+                      <height>16777215</height>
+                     </size>
+                    </property>
+                    <property name="font">
+                     <font>
+                      <pointsize>10</pointsize>
+                     </font>
+                    </property>
+                   </widget>
+                  </item>
+                 </layout>
                 </item>
                </layout>
               </item>
-              <item row="0" column="1">
-               <widget class="IntegratedPeakView" name="graphicsView_integratedPeakView">
+              <item>
+               <spacer name="horizontalSpacer_37">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeType">
+                 <enum>QSizePolicy::Ignored</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>40</width>
+                  <height>20</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item>
+               <widget class="MatrixTable" name="tableWidget_covariance">
                 <property name="sizePolicy">
-                 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+                 <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
                   <horstretch>0</horstretch>
                   <verstretch>0</verstretch>
                  </sizepolicy>
                 </property>
+                <property name="font">
+                 <font>
+                  <pointsize>10</pointsize>
+                 </font>
+                </property>
+                <row>
+                 <property name="text">
+                  <string>X0</string>
+                 </property>
+                </row>
+                <row>
+                 <property name="text">
+                  <string>sigma</string>
+                 </property>
+                </row>
+                <row>
+                 <property name="text">
+                  <string>A</string>
+                 </property>
+                </row>
+                <row>
+                 <property name="text">
+                  <string>B</string>
+                 </property>
+                </row>
+                <column>
+                 <property name="text">
+                  <string>x0</string>
+                 </property>
+                </column>
+                <column>
+                 <property name="text">
+                  <string>sigma</string>
+                 </property>
+                </column>
+                <column>
+                 <property name="text">
+                  <string>A</string>
+                 </property>
+                </column>
+                <column>
+                 <property name="text">
+                  <string>B</string>
+                 </property>
+                </column>
+                <item row="0" column="0">
+                 <property name="text">
+                  <string/>
+                 </property>
+                 <property name="font">
+                  <font>
+                   <pointsize>10</pointsize>
+                  </font>
+                 </property>
+                </item>
                </widget>
               </item>
+              <item>
+               <layout class="QVBoxLayout" name="verticalLayout_24">
+                <item>
+                 <widget class="QPushButton" name="pushButton_clearPeakIntFigure">
+                  <property name="text">
+                   <string>Clear Canvas</string>
+                  </property>
+                 </widget>
+                </item>
+                <item>
+                 <spacer name="verticalSpacer_16">
+                  <property name="orientation">
+                   <enum>Qt::Vertical</enum>
+                  </property>
+                  <property name="sizeType">
+                   <enum>QSizePolicy::Preferred</enum>
+                  </property>
+                  <property name="sizeHint" stdset="0">
+                   <size>
+                    <width>20</width>
+                    <height>40</height>
+                   </size>
+                  </property>
+                 </spacer>
+                </item>
+               </layout>
+              </item>
              </layout>
             </item>
            </layout>
@@ -4833,7 +5744,7 @@ p, li { white-space: pre-wrap; }
     <rect>
      <x>0</x>
      <y>0</y>
-     <width>1536</width>
+     <width>1568</width>
      <height>25</height>
     </rect>
    </property>
@@ -4999,11 +5910,6 @@ p, li { white-space: pre-wrap; }
    <extends>QTableWidget</extends>
    <header>hfctables.h</header>
   </customwidget>
-  <customwidget>
-   <class>PeakIntegrationTableWidget</class>
-   <extends>QTableWidget</extends>
-   <header>hfctables.h</header>
-  </customwidget>
   <customwidget>
    <class>IntegratedPeakView</class>
    <extends>QGraphicsView</extends>
@@ -5019,6 +5925,11 @@ p, li { white-space: pre-wrap; }
    <extends>QTableWidget</extends>
    <header>hfctables.h</header>
   </customwidget>
+  <customwidget>
+   <class>MatrixTable</class>
+   <extends>QTableWidget</extends>
+   <header>hfctables.h</header>
+  </customwidget>
  </customwidgets>
  <resources/>
  <connections/>
diff --git a/scripts/HFIR_4Circle_Reduction/NTableWidget.py b/scripts/HFIR_4Circle_Reduction/NTableWidget.py
index e8ffda0c330e0a777e2784aa40da0dbca955ec60..e8e65036197ad3487e5bd1f67116502c3d1d9be5 100644
--- a/scripts/HFIR_4Circle_Reduction/NTableWidget.py
+++ b/scripts/HFIR_4Circle_Reduction/NTableWidget.py
@@ -1,6 +1,6 @@
 #pylint: disable=C0103,R0904
 # N(DAV)TableWidget
-
+import csv
 from PyQt4 import QtGui, QtCore
 
 try:
@@ -31,6 +31,7 @@ class NTableWidget(QtGui.QTableWidget):
         self._editableList = list()
 
         self._statusColName = 'Status'
+        self._colIndexSelect = None
 
         return
 
@@ -90,6 +91,47 @@ class NTableWidget(QtGui.QTableWidget):
 
         return
 
+    def export_table_csv(self, csv_file_name):
+        """
+
+        :return:
+        """
+        # get title as header
+        col_names = self._myColumnNameList[:]
+        # col_names_str = '{0}'.format(col_names)
+        # col_names_str = col_names_str.replace(', ', ' ')
+        # headeder = col_names_str
+
+        num_columns = self.columnCount()
+
+        num_rows = self.rowCount()
+        content_line_list = list()
+        for i_row in range(num_rows):
+            line_items = list()
+            for j_col in range(num_columns):
+                item_value = self.get_cell_value(i_row, j_col)
+                if isinstance(item_value, str):
+                    # remove tab because tab will be used as delimiter
+                    item_value = item_value.replace('\t', '')
+                elif item_value is None:
+                    item_value = ''
+                line_items.append(item_value)
+            # END-FOR
+            content_line_list.append(line_items)
+        # END-FOR (row)
+
+        with open(csv_file_name, 'w') as csv_file:
+            csv_writer = csv.writer(csv_file, delimiter=' ', quoting=csv.QUOTE_MINIMAL)
+            # write header
+            csv_writer.writerow(col_names)
+            # write content
+            for line_items in content_line_list:
+                csv_writer.writerow(line_items)
+            # END-FOR
+        # END-WITH
+
+        return
+
     def get_cell_value(self, row_index, col_index):
         """
         Purpose: Get cell value
@@ -120,7 +162,9 @@ class NTableWidget(QtGui.QTableWidget):
             assert isinstance(item_i_j, QtGui.QTableWidgetItem)
 
             return_value = str(item_i_j.text())
-            if cell_data_type == 'int':
+            if return_value == 'None':
+                return_value = None
+            elif cell_data_type == 'int':
                 return_value = int(return_value)
             elif cell_data_type == 'float' or cell_data_type == 'double':
                 return_value = float(return_value)
@@ -266,6 +310,23 @@ class NTableWidget(QtGui.QTableWidget):
 
         return error_message
 
+    def revert_selection(self):
+        """
+        revert the selection of rows
+        :return:
+        """
+        # check
+        if self._colIndexSelect is None:
+            raise RuntimeError('Column for selection is not defined yet. Unable to revert selection')
+
+        num_rows = self.rowCount()
+        for i_row in range(num_rows):
+            curr_selection = self.get_cell_value(i_row, self._colIndexSelect)
+            self.update_cell_value(i_row, self._colIndexSelect, not curr_selection)
+        # END-FOR
+
+        return
+
     def select_all_rows(self, status):
         """
         Purpose: select or deselect all rows in the table if applied
@@ -316,6 +377,41 @@ class NTableWidget(QtGui.QTableWidget):
 
         return
 
+    def select_rows_by_column_value(self, column_index, target_value, value_tolerance,
+                                    keep_current_selection):
+        """
+        select row
+        :param column_index:
+        :param target_value:
+        :param value_tolerance:
+        :param keep_current_selection:
+        :return:
+        """
+        # check inputs
+        assert isinstance(column_index, int) and 0 <= column_index < self.columnCount(),\
+            'Column index {0} must be an integer (now {1}) and in range (0, {2}]' \
+            ''.format(column_index, type(column_index), self.columnCount())
+        if self._colIndexSelect is None:
+            raise RuntimeError('Column for selection is never set up.')
+
+        # loop over lines
+        num_rows = self.rowCount()
+        for i_row in range(num_rows):
+            if keep_current_selection and self.get_cell_value(i_row, self._colIndexSelect) is False:
+                # in case to keep and based on current selection, and this row is not selected, skip
+                continue
+
+            value_i = self.get_cell_value(i_row, column_index)
+            if isinstance(target_value, str) and value_i == target_value:
+                # in case of string
+                self.update_cell_value(i_row, self._colIndexSelect, True)
+            elif (isinstance(target_value, float) or isinstance(target_value, int)) and abs(value_i - target_value) < value_tolerance:
+                # in case of integer or float, then test with consideration of tolerance
+                self.update_cell_value(i_row, self._colIndexSelect, True)
+        # END-FOR
+
+        return
+
     def set_check_box(self, row, col, state):
         """ function to add a new select checkbox to a cell in a table row
         won't add a new checkbox if one already exists
@@ -352,11 +448,16 @@ class NTableWidget(QtGui.QTableWidget):
         # check
         assert isinstance(name, str), 'Given status column name must be an integer,' \
                                       'but not %s.' % str(type(name))
-        assert name in self._myColumnNameList
+        if name not in self._myColumnNameList:
+            raise RuntimeError('Input selection/status name {0} is not in column names list {1}.'
+                               ''.format(name, self._myColumnNameList))
 
         # set value
         self._statusColName = name
 
+        # set the column index
+        self._colIndexSelect = self._myColumnNameList.index(name)
+
         return
 
     def set_value_cell(self, row, col, value=''):
diff --git a/scripts/HFIR_4Circle_Reduction/PeakIntegrationDialog.ui b/scripts/HFIR_4Circle_Reduction/PeakIntegrationDialog.ui
new file mode 100644
index 0000000000000000000000000000000000000000..5133f2667b926acf33e160dc7e1bea213441204e
--- /dev/null
+++ b/scripts/HFIR_4Circle_Reduction/PeakIntegrationDialog.ui
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>410</width>
+    <height>317</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <widget class="QLabel" name="label_34">
+     <property name="text">
+      <string>Peak Radius</string>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="1">
+    <widget class="QLineEdit" name="lineEdit_peakRadius">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QLabel" name="label_46">
+     <property name="text">
+      <string>Background</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="1">
+    <widget class="QLineEdit" name="lineEdit_background">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="1">
+    <widget class="QPushButton" name="pushButton_integratePeak">
+     <property name="font">
+      <font>
+       <weight>50</weight>
+       <bold>false</bold>
+      </font>
+     </property>
+     <property name="text">
+      <string>Integrate Peak</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/scripts/HFIR_4Circle_Reduction/PeakIntegrationSpreadSheet.ui b/scripts/HFIR_4Circle_Reduction/PeakIntegrationSpreadSheet.ui
new file mode 100644
index 0000000000000000000000000000000000000000..52b42acd4794a7881ad1f193fa38529654dde1b2
--- /dev/null
+++ b/scripts/HFIR_4Circle_Reduction/PeakIntegrationSpreadSheet.ui
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1318</width>
+    <height>613</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="PeaksIntegrationSpreadSheet" name="tableWidget_spreadsheet"/>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="pushButton_exportTable">
+       <property name="text">
+        <string>Export Table</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_2">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeType">
+        <enum>QSizePolicy::Preferred</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="pushButton_quit">
+       <property name="text">
+        <string>Quit</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>PeaksIntegrationSpreadSheet</class>
+   <extends>QTableWidget</extends>
+   <header>hfctables.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/scripts/HFIR_4Circle_Reduction/PeaksIntegrationReport.py b/scripts/HFIR_4Circle_Reduction/PeaksIntegrationReport.py
new file mode 100644
index 0000000000000000000000000000000000000000..a5f13cd30770defd2d6bc40553934c2efd92fa51
--- /dev/null
+++ b/scripts/HFIR_4Circle_Reduction/PeaksIntegrationReport.py
@@ -0,0 +1,105 @@
+import os
+
+from PyQt4 import QtGui, QtCore
+import ui_PeakIntegrationSpreadSheet
+
+
+class PeaksIntegrationReportDialog(QtGui.QDialog):
+    """
+    Dialog to report the details of peaks integration
+    """
+    def __init__(self, parent):
+        """
+        initialization
+        :param parent:
+        """
+        super(PeaksIntegrationReportDialog, self).__init__(parent)
+
+        # set up UI
+        self.ui = ui_PeakIntegrationSpreadSheet.Ui_Dialog()
+        self.ui.setupUi(self)
+
+        # initialize widget
+        self.ui.tableWidget_spreadsheet.setup()
+
+        # set up handlers
+        self.connect(self.ui.pushButton_exportTable, QtCore.SIGNAL('clicked()'),
+                     self.do_export_table)
+
+        self.connect(self.ui.pushButton_quit, QtCore.SIGNAL('clicked()'),
+                     self.do_quit)
+
+        return
+
+    def do_export_table(self):
+        """
+
+        :return:
+        """
+        default_dir = os.getcwd()
+        output_file = str(QtGui.QFileDialog.getSaveFileName(self, 'Export table to csv file', default_dir,
+                                                            'Data Files (*.dat);;All  Files (*.*)'))
+
+        # return if cancelled
+        if len(output_file) == 0:
+            return
+
+        # write
+        self.ui.tableWidget_spreadsheet.export_table_csv(output_file)
+
+        return
+
+    def do_quit(self):
+        """
+
+        :return:
+        """
+        self.close()
+
+        return
+
+    def set_report(self, peak_integration_summary):
+        """
+
+        :param peak_integration_summary: dictionary of dictionary; key is scan number
+        :return:
+        """
+        # check input
+        assert isinstance(peak_integration_summary, dict)
+
+        if len(peak_integration_summary) == 0:
+            print '[WARNING] There is no peak integration summary given for the report.'
+            return
+
+        scan_number_list = sorted(peak_integration_summary.keys())
+        for scan_number in scan_number_list:
+            print '[DB...BAT] Scan {0} Peak integration report keys: {1}' \
+                  ''.format(scan_number, peak_integration_summary[scan_number].keys())
+
+            spice_hkl = peak_integration_summary[scan_number]['SPICE HKL']
+            calculated_hkl = peak_integration_summary[scan_number]['Mantid HKL']
+            mask_name = peak_integration_summary[scan_number]['Mask']
+            intensity1 = peak_integration_summary[scan_number]['Raw Intensity']
+            error1 = peak_integration_summary[scan_number]['Raw Intensity Error']
+            intensity2 = peak_integration_summary[scan_number]['Intensity 2']
+            error2 = peak_integration_summary[scan_number]['Intensity 2 Error']
+            intensity3 = peak_integration_summary[scan_number]['Gauss Intensity']
+            error3 = peak_integration_summary[scan_number]['Gauss Error']
+            lorentz_factor = peak_integration_summary[scan_number]['Lorentz']
+            estimated_bkgd = peak_integration_summary[scan_number]['Estimated Background']
+            gauss_bkgd = peak_integration_summary[scan_number]['Fitted Background']
+            gauss_a = peak_integration_summary[scan_number]['Fitted A']
+            gauss_sigma = peak_integration_summary[scan_number]['Fitted Sigma']
+            motor_name = peak_integration_summary[scan_number]['Motor']
+            motor_step = peak_integration_summary[scan_number]['Motor Step']
+            k_shift = peak_integration_summary[scan_number]['K-vector']
+            absorption_correction = peak_integration_summary[scan_number]['Absorption Correction']
+
+            self.ui.tableWidget_spreadsheet.add_scan_information(scan_number, spice_hkl, calculated_hkl,
+                                                                 mask_name, intensity1, error1, intensity2, error2,
+                                                                 intensity3, error3, lorentz_factor, estimated_bkgd,
+                                                                 gauss_bkgd, gauss_sigma, gauss_a, motor_name,
+                                                                 motor_step, k_shift, absorption_correction)
+        # END-FOR
+
+        return
diff --git a/scripts/HFIR_4Circle_Reduction/UBSelectPeaksDialog.ui b/scripts/HFIR_4Circle_Reduction/UBSelectPeaksDialog.ui
new file mode 100644
index 0000000000000000000000000000000000000000..edf65f4801fb1558ad521c3b0b1f3fab185b7b7e
--- /dev/null
+++ b/scripts/HFIR_4Circle_Reduction/UBSelectPeaksDialog.ui
@@ -0,0 +1,440 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog">
+  <property name="windowModality">
+   <enum>Qt::WindowModal</enum>
+  </property>
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>676</width>
+    <height>303</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <property name="modal">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QCheckBox" name="checkBox_selectAllPeaks">
+       <property name="text">
+        <string>Select All Peaks</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_3">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::Ignored</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <widget class="QCheckBox" name="checkBox_selectNuclearPeaks">
+       <property name="text">
+        <string>Nuclear Peaks</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_4">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_3">
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeType">
+        <enum>QSizePolicy::Fixed</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>80</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QLabel" name="label">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>90</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>90</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>Tolerance</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLineEdit" name="lineEdit_nuclearPeaksTolerance">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>160</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>160</width>
+         <height>16777215</height>
+        </size>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="label_3">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>80</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>80</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>HKL from</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QComboBox" name="comboBox_hklType">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>160</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>160</width>
+         <height>16777215</height>
+        </size>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_5">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_2">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::Ignored</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_4">
+     <item>
+      <widget class="QCheckBox" name="checkBox_wavelength">
+       <property name="text">
+        <string>Wave Length</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_6">
+     <item>
+      <spacer name="horizontalSpacer_2">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeType">
+        <enum>QSizePolicy::Fixed</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>80</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QLabel" name="label_2">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>90</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>90</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>Wave length</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLineEdit" name="lineEdit_wavelength">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>160</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>160</width>
+         <height>16777215</height>
+        </size>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="label_4">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>80</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>80</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>Tolerance</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLineEdit" name="lineEdit_wavelengthTolerance">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>160</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>160</width>
+         <height>16777215</height>
+        </size>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_6">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <spacer name="verticalSpacer_3">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_5">
+     <item>
+      <widget class="QPushButton" name="pushButton_selectScans">
+       <property name="font">
+        <font>
+         <pointsize>12</pointsize>
+        </font>
+       </property>
+       <property name="text">
+        <string>Select</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="pushButton_revertCurrentSelection">
+       <property name="font">
+        <font>
+         <pointsize>12</pointsize>
+        </font>
+       </property>
+       <property name="text">
+        <string>Revert</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="pushButton_exportSelectedScans">
+       <property name="font">
+        <font>
+         <pointsize>12</pointsize>
+        </font>
+       </property>
+       <property name="toolTip">
+        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Export selected peaks to a file&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+       </property>
+       <property name="text">
+        <string>Export</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="pushButton_quit">
+       <property name="font">
+        <font>
+         <pointsize>12</pointsize>
+        </font>
+       </property>
+       <property name="text">
+        <string>Quit</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/scripts/HFIR_4Circle_Reduction/detector2dview.py b/scripts/HFIR_4Circle_Reduction/detector2dview.py
index f7ce4af9f5bbf16b8028aef75b05c27a6196ea78..b2bdd80c789faa0b530b6db397c1750c691c9f2f 100644
--- a/scripts/HFIR_4Circle_Reduction/detector2dview.py
+++ b/scripts/HFIR_4Circle_Reduction/detector2dview.py
@@ -1,7 +1,7 @@
 #pylint: disable=W0403,R0902,R0903,R0904,W0212
-import mpl2dgraphicsview
-
+import os
 import numpy as np
+import mpl2dgraphicsview
 
 
 class Detector2DView(mpl2dgraphicsview.Mpl2dGraphicsView):
@@ -92,6 +92,70 @@ class Detector2DView(mpl2dgraphicsview.Mpl2dGraphicsView):
 
         return
 
+    def integrate_roi_linear(self, exp_number, scan_number, pt_number, output_dir):
+        """
+        integrate the 2D data inside region of interest along both axis-0 and axis-1 individually.
+        and the result (as 1D data) will be saved to ascii file.
+        the X values will be the corresponding pixel index either along axis-0 or axis-1
+        :return:
+        """
+        def save_to_file(base_file_name, axis, array1d, start_index):
+            """
+            save the result (1D data) to an ASCII file
+            :param base_file_name:
+            :param axis:
+            :param array1d:
+            :param start_index:
+            :return:
+            """
+            file_name = '{0}_axis_{1}.dat'.format(base_file_name, axis)
+
+            wbuf = ''
+            vec_x = np.array(range(len(array1d))) + start_index
+            for i in range(len(array1d)):
+                wbuf += '{0} \t{1}\n'.format(vec_x[i], array1d[i])
+
+            ofile = open(file_name, 'w')
+            ofile.write(wbuf)
+            ofile.close()
+
+            return
+
+        matrix = self.array2d
+        assert isinstance(matrix, np.ndarray), 'A matrix must be an ndarray but not {0}.'.format(type(matrix))
+
+        # get region of interest
+        if self._roiStart is None:
+            self._roiStart = (0, 0)
+        if self._roiEnd is None:
+            self._roiEnd = matrix.shape
+
+        ll_row = min(self._roiStart[0], self._roiEnd[0])
+        ll_col = min(self._roiStart[1], self._roiEnd[1])
+
+        ur_row = max(self._roiStart[0], self._roiEnd[0])
+        ur_col = max(self._roiStart[1], self._roiEnd[1])
+
+        # print 'Row: {0} : {1}  Col: {2} : {3}'.format(ll_row, ur_row, ll_col, ur_col)
+
+        roi_matrix = matrix[ll_col:ur_col, ll_row:ur_row]
+
+        sum_0 = roi_matrix.sum(0)
+        #  print sum_0
+        sum_1 = roi_matrix.sum(1)
+        #  print sum_1
+        print '[SUM 0] Dimension: {0}'.format(sum_0.shape)
+        print '[SUM 1] Dimension: {0}'.format(sum_1.shape)
+
+        # write to file
+        base_name = os.path.join(output_dir, 'Exp{0}_Scan{1}_Pt{2}'.format(exp_number, scan_number, pt_number))
+        save_to_file(base_name, 0, sum_0, ll_row)
+        save_to_file(base_name, 1, sum_1, ll_col)
+
+        message = 'Integrated values are saved to {0}...'.format(base_name)
+
+        return message
+
     def get_roi(self):
         """
         :return: A list for polygon0
@@ -149,6 +213,9 @@ class Detector2DView(mpl2dgraphicsview.Mpl2dGraphicsView):
             # FUTURE-TO-DO: this should be replaced by some update() method of canvas
             self._myCanvas._flush()
 
+            self._roiStart = None
+            self._roiEnd = None
+
         return
 
     def on_mouse_motion(self, event):
@@ -260,7 +327,7 @@ class Detector2DView(mpl2dgraphicsview.Mpl2dGraphicsView):
         :param parent_window:
         :return:
         """
-        assert parent_window is not None, 'blabla'
+        assert parent_window is not None, 'Parent window cannot be None'
 
         self._myParentWindow = parent_window
 
@@ -273,8 +340,8 @@ class Detector2DView(mpl2dgraphicsview.Mpl2dGraphicsView):
         :return:
         """
         # check
-        assert isinstance(cursor_x, float)
-        assert isinstance(cursor_y, float)
+        assert isinstance(cursor_x, float), 'Cursor x coordination {0} must be a float.'.format(cursor_x)
+        assert isinstance(cursor_y, float), 'Cursor y coordination {0} must be a float.'.format(cursor_y)
 
         # remove the original polygon
         if self._myPolygon is not None:
diff --git a/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py b/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py
index 32a8c46649cb4b8b9520316aedae1b917f8ab2c5..2043bfe2316793c9cc36d58f4756f5a184d20ace 100644
--- a/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py
+++ b/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py
@@ -72,7 +72,7 @@ def convert_to_wave_length(m1_position):
     return wave_length
 
 
-def generate_mask_file(file_path, ll_corner, ur_corner, rectangular=True):
+def generate_mask_file(file_path, ll_corner, ur_corner, rectangular=True, num_det_row=None):
     """ Generate a Mantid RIO/Mask XML file
     Requirements:
     1. file_path is writable;
@@ -85,7 +85,12 @@ def generate_mask_file(file_path, ll_corner, ur_corner, rectangular=True):
     """
     # check
     assert isinstance(file_path, str), 'File path must be a string but not a %s.' % str(type(file_path))
-    assert len(ll_corner) == 2 and len(ur_corner) == 2
+    assert len(ll_corner) == 2 and len(ur_corner) == 2,\
+        'Left corner and right corner coordinates must be 2-tuple but not of size {0} or {1}' \
+        ''.format(len(ll_corner), len(ur_corner))
+
+    if num_det_row is None:
+        num_det_row = NUM_DET_ROW
 
     if rectangular is False:
         raise RuntimeError('Non-rectangular detector is not supported yet.')
@@ -99,20 +104,42 @@ def generate_mask_file(file_path, ll_corner, ur_corner, rectangular=True):
     xml_str += '          <detids>'
 
     # part 2: all the masked detectors
-    start_row = int(ll_corner[0])
-    start_col = int(ll_corner[1])
+    mpl_start_row = int(ll_corner[0])
+    mpl_start_col = int(ll_corner[1])
+
+    mpl_end_row = int(ur_corner[0])
+    mpl_end_col = int(ur_corner[1])
+
+    # correction:
+    if False:
+        start_row = mpl_start_col
+        start_col = 256 - mpl_end_row
 
-    end_row = int(ur_corner[0])
-    end_col = int(ur_corner[1])
+        end_row = mpl_end_col
+        end_col = mpl_start_row
+    else:
+        start_row = mpl_start_row
+        start_col = mpl_start_col
+        end_row =   mpl_end_row
+        end_col =   mpl_end_col
 
-    assert start_col < end_col
+    assert start_col < end_col, 'Start column {0} cannot be smaller than end column {1}.'.format(start_col, end_col)
 
     det_sub_xml = ''
-    for col_number in xrange(start_col, end_col+1):
-        start_det_id = 1 + col_number * NUM_DET_ROW + start_row
-        end_det_id = 1 + col_number * NUM_DET_ROW + end_row
-        det_sub_xml += '%d-%d,' % (start_det_id, end_det_id)
+    if False:
+        for col_number in xrange(start_col, end_col+1):
+            start_det_id = 1 + col_number * NUM_DET_ROW + start_row
+            end_det_id = 1 + col_number * NUM_DET_ROW + end_row
+            det_sub_xml += '%d-%d,' % (start_det_id, end_det_id)
+    else:
+        # print '[DB...BAT] Row numbers from {0} to {1}'.format(start_row, end_row)
+        # print '[DB...BAT] Col numbers from {0} to {1}'.format(start_col, end_col)
+        for row_number in range(start_row, end_row+1):
+            start_det_id = 1 + row_number * num_det_row + start_col
+            end_det_id = 1 + row_number * num_det_row + end_col
+            det_sub_xml += '{0}-{1},'.format(start_det_id, end_det_id)
     # END-FOR
+
     # remove last ','
     det_sub_xml = det_sub_xml[:-1]
     # add to xml string
@@ -136,8 +163,8 @@ def get_hb3a_wavelength(m1_motor_pos):
     :param m1_motor_pos:
     :return: wavelength.  None for no mapping
     """
-    assert isinstance(m1_motor_pos, float), 'Motor m1\'s position %s must be a float but not %s.' \
-                                            '' % (str(m1_motor_pos), type(m1_motor_pos))
+    assert isinstance(m1_motor_pos, float) or isinstance(m1_motor_pos, int),\
+        'Motor m1\'s position {0} must be a float but not {1}.'.format(m1_motor_pos, type(m1_motor_pos))
 
     # hard-coded HB3A m1 position and wavelength mapping
     m1_pos_list = [(-25.870, 1.003),
diff --git a/scripts/HFIR_4Circle_Reduction/fputility.py b/scripts/HFIR_4Circle_Reduction/fputility.py
index e893e95e190d50d7d1dbdf2ea2acdc533f200951..2c94f404153d299bd950d05c5c2edb8c4bdfebf3 100644
--- a/scripts/HFIR_4Circle_Reduction/fputility.py
+++ b/scripts/HFIR_4Circle_Reduction/fputility.py
@@ -230,7 +230,11 @@ def write_scd_fullprof_kvector(user_header, wave_length, k_vector_dict, peak_dic
         # END-IF-ELSE
 
         # peak intensity and sigma
-        part3 = '%8.2f%8.2f%4d' % (peak_dict['intensity'], peak_dict['sigma'], 1)
+        try:
+            part3 = '%8.2f%8.2f%4d' % (peak_dict['intensity'], peak_dict['sigma'], 1)
+        except TypeError as type_err:
+            raise RuntimeError('In writing Fullprof file, unable to convert intensity {0} and/or sigma {1} to '
+                               'floats. FYI: {2}'.format(peak_dict['intensity'], peak_dict['sigma'], type_err))
 
         peak_line = part1 + part2 + part3
 
@@ -275,7 +279,7 @@ def main(argv):
     """
     # get input
     if len(argv) < 4:
-        print 'Calculate the difference of two measuremnts:\n'
+        print 'Calculate the difference of two measurements:\n'
         print '> %s [intensity file 1]  [intensity file 2]  [output intensity file]' % argv[0]
         return
     else:
diff --git a/scripts/HFIR_4Circle_Reduction/guiutility.py b/scripts/HFIR_4Circle_Reduction/guiutility.py
index 3c7dea5d4b332044c74c543439eadc036b81806f..9ee8918d52e23719041b8200e1415d6cd9e381ce 100644
--- a/scripts/HFIR_4Circle_Reduction/guiutility.py
+++ b/scripts/HFIR_4Circle_Reduction/guiutility.py
@@ -3,6 +3,7 @@
 #
 import math
 import numpy
+import os
 from PyQt4 import QtGui, QtCore
 
 
@@ -41,6 +42,46 @@ def convert_str_to_matrix(matrix_str, matrix_shape):
     return matrix
 
 
+def import_scans_text_file(file_name):
+    """
+    import a plain text file containing a list of scans
+    :param file_name:
+    :return:
+    """
+    # check inputs
+    assert isinstance(file_name, str), 'File name {0} must be a string but not of type {1}.' \
+                                       ''.format(file_name, type(file_name))
+    if os.path.exists(file_name) is False:
+        raise RuntimeError('File {0} does not exist.'.format(file_name))
+
+    # import file
+    scan_file = open(file_name, 'r')
+    raw_lines = scan_file.readline()
+    scan_file.close()
+
+    # parse
+    scans_str = ''
+    for raw_line in raw_lines:
+        # get a clean line and skip empty line
+        line = raw_line.strip()
+        if len(line) == 0:
+            continue
+
+        # skip comment line
+        if line.startswith('#'):
+            continue
+
+        # form the string
+        scans_str += line
+    # END-FOR
+
+    # convert scans (in string) to list of integers
+    scan_list = parse_integer_list(scans_str)
+    scan_list.sort()
+
+    return scan_list
+
+
 def map_to_color(data_array, base_color, change_color_flag):
     """ Map 1-D data to color list
     :param data_array:
@@ -149,13 +190,18 @@ def parse_float_array(array_str):
     return True, float_list
 
 
-def parse_integer_list(array_str):
+def parse_integer_list(array_str, expected_size=None):
     """ Parse a string to an array of integer separated by ','
     also, the format as 'a-b' is supported too
+    :exception: RuntimeError
     :param array_str:
-    :return: boolean, list of floats/error message
+    :param expected_size
+    :return: list of floats/error message
     """
-    assert isinstance(array_str, str)
+    # check input type
+    assert isinstance(array_str, str), 'Input {0} must be a string but not a {1}'.format(array_str, type(array_str))
+
+    # remove space, tab and \n
     array_str = array_str.replace(' ', '')
     array_str = array_str.replace('\n', '')
     array_str = array_str.replace('\t ', '')
@@ -163,7 +209,6 @@ def parse_integer_list(array_str):
     int_str_list = array_str.split(',')
     integer_list = list()
     for int_str in int_str_list:
-
         try:
             int_value = int(int_str)
             integer_list.append(int_value)
@@ -198,6 +243,10 @@ def parse_integer_list(array_str):
             integer_list.extend(xrange(start_value, end_value+1))
     # END-FOR
 
+    # check size
+    if expected_size is not None and len(integer_list) != expected_size:
+        raise RuntimeError('It is required to have {0} integers given in {1}.'.format(expected_size, array_str))
+
     return integer_list
 
 
diff --git a/scripts/HFIR_4Circle_Reduction/hfctables.py b/scripts/HFIR_4Circle_Reduction/hfctables.py
index 4269976ed3b050608d85c7fa7908e6444c4dd3de..16fb17171b4b5a9199e73ae5b7ab1aaee71b9f07 100644
--- a/scripts/HFIR_4Circle_Reduction/hfctables.py
+++ b/scripts/HFIR_4Circle_Reduction/hfctables.py
@@ -2,6 +2,7 @@
 import numpy
 import sys
 import fourcircle_utility
+import guiutility
 
 import NTableWidget as tableBase
 
@@ -77,12 +78,207 @@ class KShiftTableWidget(tableBase.NTableWidget):
         return
 
 
-class PeakIntegrationTableWidget(tableBase.NTableWidget):
+class MatrixTable(tableBase.NTableWidget):
     """
-    Extended table widget for studying peak integration of scan on various Pts.
+
     """
+    def __init__(self, parent):
+        """
+
+        :param parent:
+        """
+        super(MatrixTable, self).__init__(parent)
+
+        return
+
+    def setup(self, num_rows, num_cols):
+        """
+        set up a table for matrix
+        :param num_rows:
+        :param num_cols:
+        :return:
+        """
+        # check inputs
+        assert isinstance(num_rows, int) and num_rows > 0, 'Number of rows larger than 0.'
+        assert isinstance(num_cols, int) and num_cols > 0, 'Number of columns larger than 0.'
+
+        # think of reset
+        if self.rowCount() != num_rows or self.columnCount() != num_cols:
+            raise RuntimeError('ASAP')
+
+        return
+
+    def set_matrix(self, matrix):
+        """
 
-    # UB peak information table
+        :param matrix:
+        :return:
+        """
+        # check inputs
+        assert isinstance(matrix, numpy.ndarray) and matrix.shape == (4, 4), 'Matrix {0} must be ndarray with {1}.' \
+                                                                             ''.format(matrix, matrix.shape)
+        for i in range(matrix.shape[0]):
+            for j in range(matrix.shape[1]):
+                self.set_value_cell(i, j, matrix[i, j])
+
+        return
+
+
+class PeaksIntegrationSpreadSheet(tableBase.NTableWidget):
+    """
+    Detailed peaks integration information table. Each row is for a peak measured in a scan containing multiple Pts.
+    It can be converted to a csv file for user to check the integration details.
+    Note: all the intensities shown below are corrected by by Lorentzian and absorption if either of them is
+          calculated and applied.
+    """
+    Table_Setup = [('Scan', 'int'),
+                   ('HKL (S)', 'str'),
+                   ('HKL (C)', 'str'),
+                   ('Mask', 'str'),
+                   ('Intensity (R)', 'float'),
+                   ('Error (R)', 'float'),
+                   ('Intensity 2', 'float'),
+                   ('Error (2)', 'float'),
+                   ('Intensity (G)', 'float'),
+                   ('Error (G)', 'float'),
+                   ('Lorentz', 'float'),
+                   ('Bkgd (E)', 'float'),
+                   ('Bkgd (G)', 'float'),
+                   ('Sigma', 'float'),
+                   ('A', 'float'),
+                   ('Motor Name', 'str'),
+                   ('Motor Step', 'float'),
+                   ('K-shift', 'str'),
+                   ('Absorption', 'float')
+                   ]
+
+    def __init__(self, parent):
+        """
+        initialization
+        :param parent:
+        """
+        super(PeaksIntegrationSpreadSheet, self).__init__(parent)
+
+        # define column indexes
+        self._colIndexScan = None
+        self._colIndexSpiceHKL = None
+        self._colIndexMantidHKL = None
+        self._colIndexMask = None
+        self._colIndexRawIntensity = None
+        self._colIndexRawError = None
+        self._colIndexIntensity2 = None
+        self._colIndexError2 = None
+        self._colIndexIntensity3 = None
+        self._colIndexError3 = None
+        self._colIndexBkgdE = None
+        self._colIndexBkgdG = None
+        self._colIndexMotorName = None
+        self._colIndexMotorStep = None
+        self._colIndexAbsorption = None
+        self._colIndexKShift = None
+        self._colIndexLorentz = None
+        self._colIndexSigma = None
+        self._colIndexA = None
+
+        return
+
+    def add_scan_information(self, scan_number, s_hkl, m_hkl, mask, raw_intensity, raw_error, intensity2, error2,
+                             intensity3, error3, lorentz, bkgd_e, bkgd_g, gauss_s, gauss_a, motor_name, motor_step,
+                             k_shift, absorption):
+        """
+        add the detailed integrating information to table
+        :param scan_number:
+        :param s_hkl:
+        :param m_hkl:
+        :param mask:
+        :param raw_intensity:
+        :param raw_error:
+        :param intensity2:
+        :param error2:
+        :param intensity3:
+        :param error3:
+        :param lorentz:
+        :param bkgd_e:
+        :param bkgd_g:
+        :param gauss_s:
+        :param gauss_a:
+        :param motor_name:
+        :param motor_step:
+        :param k_shift:
+        :param absorption:
+        :return:
+        """
+        # append an empty row
+        row_list = [None] * len(self.Table_Setup)
+        status, msg = self.append_row(row_list)
+        if not status:
+            print '[ERROR] Unable to append a new row due to {0}.'.format(msg)
+        else:
+            row_list[0] = 123
+            row_list[1] = ''
+            row_list[2] = ''
+        last_row_number = self.rowCount() - 1
+
+        # set value
+        self.update_cell_value(last_row_number, self._colIndexScan, scan_number)
+        self.update_cell_value(last_row_number, self._colIndexSpiceHKL, s_hkl)
+        self.update_cell_value(last_row_number, self._colIndexMantidHKL, m_hkl)
+        self.update_cell_value(last_row_number, self._colIndexMask, mask)
+        self.update_cell_value(last_row_number, self._colIndexRawIntensity, raw_intensity)
+        self.update_cell_value(last_row_number, self._colIndexRawError, raw_error)
+        self.update_cell_value(last_row_number, self._colIndexIntensity2, intensity2)
+        self.update_cell_value(last_row_number, self._colIndexIntensity3, intensity3)
+        self.update_cell_value(last_row_number, self._colIndexError2, error2)
+        self.update_cell_value(last_row_number, self._colIndexError3, error3)
+        self.update_cell_value(last_row_number, self._colIndexLorentz, lorentz)
+        self.update_cell_value(last_row_number, self._colIndexBkgdE, bkgd_e)
+        self.update_cell_value(last_row_number, self._colIndexBkgdG, bkgd_g)
+        self.update_cell_value(last_row_number, self._colIndexSigma, gauss_s)
+        self.update_cell_value(last_row_number, self._colIndexA, gauss_a)
+        self.update_cell_value(last_row_number, self._colIndexKShift, k_shift)
+        self.update_cell_value(last_row_number, self._colIndexAbsorption, absorption)
+        self.update_cell_value(last_row_number, self._colIndexMotorName, motor_name)
+        self.update_cell_value(last_row_number, self._colIndexMotorStep, motor_step)
+
+        return
+
+    def setup(self):
+        """
+        Init setup
+        :return:
+        """
+        self.init_setup(self.Table_Setup)
+
+        # get column names
+        col_name_list = self._myColumnNameList
+
+        self._colIndexScan = col_name_list.index('Scan')
+        self._colIndexSpiceHKL = self.Table_Setup.index(('HKL (S)', 'str'))
+        self._colIndexMantidHKL = self.Table_Setup.index(('HKL (C)', 'str'))
+        self._colIndexMask = self.Table_Setup.index(('Mask', 'str'))
+        self._colIndexRawIntensity = self.Table_Setup.index(('Intensity (R)', 'float'))
+        self._colIndexRawError = self.Table_Setup.index(('Error (R)', 'float'))
+        self._colIndexIntensity2 = self.Table_Setup.index(('Intensity 2', 'float'))
+        self._colIndexError2 = self.Table_Setup.index(('Error (2)', 'float'))
+        self._colIndexIntensity3 = self.Table_Setup.index(('Intensity (G)', 'float'))
+        self._colIndexError3 = self.Table_Setup.index(('Error (G)', 'float'))
+        self._colIndexLorentz = self.Table_Setup.index(('Lorentz', 'float'))
+        self._colIndexBkgdE = self.Table_Setup.index(('Bkgd (E)', 'float'))
+        self._colIndexBkgdG = self.Table_Setup.index(('Bkgd (G)', 'float'))
+        self._colIndexMotorName = self.Table_Setup.index(('Motor Name', 'str'))
+        self._colIndexMotorStep = self.Table_Setup.index(('Motor Step', 'float'))
+        self._colIndexKShift = self.Table_Setup.index(('K-shift', 'str'))
+        self._colIndexAbsorption = self.Table_Setup.index(('Absorption', 'float'))
+        self._colIndexSigma = self.Table_Setup.index(('Sigma', 'float'))
+        self._colIndexA = self.Table_Setup.index(('A', 'float'))
+
+        return
+
+
+class PeakIntegrationTableWidget(tableBase.NTableWidget):
+    """
+    Extended table widget for studying peak integration of a single scan on various Pts.
+    """
     Table_Setup = [('Pt', 'int'),
                    ('Raw', 'float'),
                    ('Masked', 'float'),
@@ -97,7 +293,8 @@ class PeakIntegrationTableWidget(tableBase.NTableWidget):
         self._expNumber = -1
         self._scanNumber = -1
 
-        self._intensityColIndex = None
+        self._rawIntensityColIndex = None
+        self._maskedIntensityColIndex = None
 
         return
 
@@ -110,9 +307,11 @@ class PeakIntegrationTableWidget(tableBase.NTableWidget):
         :return: 2-tuple as boolean and error message
         """
         # check requirements
-        assert isinstance(pt_number, int)
-        assert isinstance(raw_signal, int) or isinstance(raw_signal, float)
-        assert isinstance(masked_signal, float)
+        assert isinstance(pt_number, int), 'Error 920X'
+        assert isinstance(raw_signal, int) or isinstance(raw_signal, float) or raw_signal is None,\
+            'Error 920A'
+        assert isinstance(masked_signal, float) or isinstance(masked_signal, int) or masked_signal is None,\
+            'Error 920B'
 
         # form a new row and append
         status, msg = self.append_row([pt_number, raw_signal, masked_signal, False])
@@ -128,6 +327,36 @@ class PeakIntegrationTableWidget(tableBase.NTableWidget):
         """
         return self._expNumber, self._scanNumber
 
+    def sum_raw_intensity(self):
+        """
+        sum raw intensities of all Pts.
+        :return:
+        """
+        num_rows = self.rowCount()
+
+        count_sum = 0.
+        for i_row in range(num_rows):
+            pt_count = self.get_cell_value(i_row, self._rawIntensityColIndex)
+            count_sum += pt_count
+        # END-FOR
+
+        return count_sum
+
+    def sum_masked_intensity(self):
+        """
+        sum masked intensities of all Pts.
+        :return:
+        """
+        num_rows = self.rowCount()
+
+        count_sum = 0.
+        for i_row in range(num_rows):
+            pt_count = self.get_cell_value(i_row, self._maskedIntensityColIndex)
+            count_sum += pt_count
+        # END-FOR
+
+        return count_sum
+
     def setup(self):
         """
         Init setup
@@ -144,7 +373,8 @@ class PeakIntegrationTableWidget(tableBase.NTableWidget):
         self.setColumnWidth(3, 90)
 
         # Set others...
-        self._intensityColIndex = self._myColumnNameList.index('Masked')
+        self._rawIntensityColIndex = self._myColumnNameList.index('Raw')
+        self._maskedIntensityColIndex = self._myColumnNameList.index('Masked')
 
         return
 
@@ -218,7 +448,7 @@ class PeakIntegrationTableWidget(tableBase.NTableWidget):
         # Integrate
         sum_intensity = 0.
         for i_row in range(self.rowCount()):
-            intensity_i = self.get_cell_value(i_row, self._intensityColIndex)
+            intensity_i = self.get_cell_value(i_row, self._maskedIntensityColIndex)
             sum_intensity += intensity_i - background
 
         return sum_intensity
@@ -339,15 +569,12 @@ class UBMatrixTable(tableBase.NTableWidget):
 # UB peak information table
 UB_Peak_Table_Setup = [('Scan', 'int'),
                        ('Pt', 'int'),
-                       ('H', 'float'),
-                       ('K', 'float'),
-                       ('L', 'float'),
-                       ('Q_x', 'float'),
-                       ('Q_y', 'float'),
-                       ('Q_z', 'float'),
+                       ('Spice HKL', 'str'),
+                       ('Calculated HKL', 'str'),
+                       ('Q-Sample', 'str'),
                        ('Selected', 'checkbox'),
                        ('m1', 'float'),
-                       ('lambda', 'float'),  # wave length
+                       ('Wavelength', 'float'),  # wave length
                        ('Error', 'float')]
 
 
@@ -365,10 +592,62 @@ class UBMatrixPeakTable(tableBase.NTableWidget):
         tableBase.NTableWidget.__init__(self, parent)
 
         # define class variables
-        self._storedHKL = dict()
+        self._cachedSpiceHKL = dict()
+
+        # class variables for column indexes
+        self._colIndexScan = None
+        self._colIndexSpiceHKL = None
+        self._colIndexCalculatedHKL = None
+        self._colIndexQSample = None
+        self._colIndexWavelength = None
+        self._colIndexError = None
 
         return
 
+    def add_peak(self, scan_number, spice_hkl, q_sample, m1, wave_length):
+        """
+
+        :param scan_number:
+        :param spice_hkl:
+        :param q_sample:
+        :param m1:
+        :param wave_length:
+        :return:
+        """
+        # check inputs
+        assert isinstance(scan_number, int), 'Scan number integer'
+        assert len(spice_hkl) == 3, 'Spice HKL'
+        assert len(q_sample) == 3, 'Q-sample'
+        assert isinstance(m1, float) or m1 is None, 'm1'
+        assert isinstance(wave_length, float) or wave_length is None, 'wave length'
+
+        # spice_hkl_str = '{0:.4f}, {1:.4f}, {2:.4f}'.format(spice_hkl[0], spice_hkl[1], spice_hkl[2])
+        # q_sample_str = '{0:.4f}, {1:.4f}, {2:.4f}'.format(q_sample[0], q_sample[1], q_sample[2])
+        spice_hkl_str = self.format_array(spice_hkl)
+        q_sample_str = self.format_array(q_sample)
+        self.append_row([scan_number, -1, spice_hkl_str, '', q_sample_str, False, m1, wave_length, ''])
+
+        return True, ''
+
+    @staticmethod
+    def format_array(array):
+        """
+        output a formatted array with limited precision of float
+        :param array:
+        :return:
+        """
+        format_str = ''
+        for index, number in enumerate(array):
+            if index > 0:
+                format_str += ', '
+            if isinstance(number, float):
+                format_str += '{0:.4f}'.format(number)
+            else:
+                format_str += '{0}'.format(number)
+        # END-FOR
+
+        return format_str
+
     def get_exp_info(self, row_index):
         """
         Get experiment information from a row
@@ -384,21 +663,31 @@ class UBMatrixPeakTable(tableBase.NTableWidget):
 
         return scan_number, pt_number
 
-    def get_hkl(self, row_index):
+    def get_hkl(self, row_index, is_spice_hkl):
         """
         Get reflection's miller index
         :param row_index:
-        :return:
+        :param is_spice_hkl:
+        :return: 3-tuple as H, K, L
         """
-        assert isinstance(row_index, int)
+        # check input
+        assert isinstance(row_index, int), 'Row index {0} must be an integer but not a {1}.' \
+                                           ''.format(row_index, type(row_index))
 
-        m_h = self.get_cell_value(row_index, 2)
-        m_k = self.get_cell_value(row_index, 3)
-        m_l = self.get_cell_value(row_index, 4)
-
-        assert isinstance(m_h, float)
-        assert isinstance(m_k, float)
-        assert isinstance(m_l, float)
+        # get the HKL either parsed from SPICE file or from calculation
+        if is_spice_hkl:
+            hkl_str = self.get_cell_value(row_index, self._colIndexSpiceHKL)
+        else:
+            hkl_str = self.get_cell_value(row_index, self._colIndexCalculatedHKL)
+
+        # convert the recorded string to HKL
+        status, ret_obj = guiutility.parse_float_array(hkl_str)
+        if not status:
+            raise RuntimeError(ret_obj)
+        elif len(ret_obj) != 3:
+            raise RuntimeError('Unable to parse array "{0}" to 3 floating points.'.format(hkl_str))
+        else:
+            m_h, m_k, m_l = ret_obj
 
         return m_h, m_k, m_l
 
@@ -413,6 +702,20 @@ class UBMatrixPeakTable(tableBase.NTableWidget):
 
         return scan_number, pt_number
 
+    def get_selected_scans(self):
+        """
+        get the scan numbers that are selected
+        :return:
+        """
+        selected_rows = self.get_selected_rows(True)
+
+        scan_list = list()
+        for i_row in selected_rows:
+            scan_number = self.get_cell_value(i_row, self._colIndexScan)
+            scan_list.append(scan_number)
+
+        return scan_list
+
     def is_selected(self, row_index):
         """ Check whether a row is selected.
         :param row_index:
@@ -431,14 +734,28 @@ class UBMatrixPeakTable(tableBase.NTableWidget):
         :return:
         """
         self.init_setup(UB_Peak_Table_Setup)
-        self._statusColName = 'Selected'
+        self.set_status_column_name('Selected')
+
+        # define all the _colIndex
+        self._colIndexScan = self._myColumnNameList.index('Scan')
+        self._colIndexSpiceHKL = self._myColumnNameList.index('Spice HKL')
+        self._colIndexCalculatedHKL = self._myColumnNameList.index('Calculated HKL')
+        self._colIndexQSample = self._myColumnNameList.index('Q-Sample')
+        self._colIndexWavelength = self._myColumnNameList.index('Wavelength')
+        self._colIndexError = self._myColumnNameList.index('Error')
+
+        # set up the width of some columns
+        self.setColumnWidth(self._colIndexSpiceHKL, 240)
+        self.setColumnWidth(self._colIndexCalculatedHKL, 240)
+        self.setColumnWidth(4, 240)
 
         return
 
-    def select_all_nuclear_peaks(self):
+    def select_nuclear_peak_rows(self, tolerance):
         """
         select all nuclear peaks, i.e., set the flag on on 'select' for all rows if their HKL indicates that
         they are nuclear peaks
+        :param tolerance:
         :return: string as error message
         """
         num_rows = self.rowCount()
@@ -447,8 +764,8 @@ class UBMatrixPeakTable(tableBase.NTableWidget):
         for row_index in range(num_rows):
             # get the reading of HKL
             try:
-                hkl_tuple = self.get_hkl(row_index)
-                if fourcircle_utility.is_peak_nuclear(hkl_tuple[0], hkl_tuple[1], hkl_tuple[2]):
+                hkl_tuple = self.get_hkl(row_index, is_spice_hkl=True)
+                if fourcircle_utility.is_peak_nuclear(hkl_tuple[0], hkl_tuple[1], hkl_tuple[2], tolerance):
                     self.select_row(row_index, status=True)
             except RuntimeError as error:
                 error_message += 'Unable to parse HKL of line %d due to %s.' % (row_index, str(error))
@@ -456,15 +773,43 @@ class UBMatrixPeakTable(tableBase.NTableWidget):
 
         return error_message
 
-    def set_hkl(self, i_row, hkl, error=None):
+    def select_scans(self, select_all=False, nuclear_peaks=False, hkl_tolerance=None,
+                     wave_length=None, wave_length_tolerance=None):
         """
-        Set HKL to table
+        select scans in the UB matrix table
+        :param select_all:
+        :param nuclear_peaks:
+        :param hkl_tolerance:
+        :param wave_length:
+        :param wave_length_tolerance:
+        :return:
+        """
+        if select_all:
+            # select all
+            self.select_all_rows(True)
+
+        elif nuclear_peaks or wave_length_tolerance is not None:
+            # using filters
+            if nuclear_peaks:
+                self.select_nuclear_peak_rows(hkl_tolerance)
+            if wave_length_tolerance is not None:
+                self.select_rows_by_column_value(self._colIndexWavelength, wave_length, wave_length_tolerance,
+                                                 keep_current_selection=True)
+        else:
+            raise RuntimeError('Must pick up one option to do filter.')
+
+        return
+
+    def set_hkl(self, i_row, hkl, is_spice_hkl, error=None):
+        """
+        Set HKL to a row in the table. Show H/K/L with 4 decimal pionts
         :param i_row:
         :param hkl: HKL is a list of tuple
+        :param is_spice_hkl: If true, then set input to cell for SPICE-imported HKL. Otherwise to calculated HKL.
         :param error: error of HKL
         """
         # Check
-        assert isinstance(i_row, int), 'Row number (index) must be integer but not %s.' % type(i_row)
+        assert isinstance(i_row, int), 'Row number (index) must be integer but not %s.'.format(type(i_row))
 
         if isinstance(hkl, list) or isinstance(hkl, tuple):
             assert len(hkl) == 3, 'In case HKL is list of tuple, its size must be equal to 3 but not %d.' \
@@ -475,39 +820,41 @@ class UBMatrixPeakTable(tableBase.NTableWidget):
         else:
             raise AssertionError('HKL of type %s is not supported. Supported types include list, tuple '
                                  'and numpy array.' % type(hkl))
+        assert isinstance(is_spice_hkl, bool), 'Flag {0} for SPICE-HKL must be a boolean but not a {1}.' \
+                                               ''.format(is_spice_hkl, type(is_spice_hkl))
 
-        # get columns
-        i_col_h = UB_Peak_Table_Setup.index(('H', 'float'))
-        i_col_k = UB_Peak_Table_Setup.index(('K', 'float'))
-        i_col_l = UB_Peak_Table_Setup.index(('L', 'float'))
+        # convert to a string with 4 decimal points
+        hkl_str = '%.4f, %.4f, %.4f' % (hkl[0], hkl[1], hkl[2])
 
-        self.update_cell_value(i_row, i_col_h, hkl[0])
-        self.update_cell_value(i_row, i_col_k, hkl[1])
-        self.update_cell_value(i_row, i_col_l, hkl[2])
+        if is_spice_hkl:
+            self.update_cell_value(i_row, self._colIndexSpiceHKL, hkl_str)
+        else:
+            self.update_cell_value(i_row, self._colIndexCalculatedHKL, hkl_str)
 
+        # set error
         if error is not None:
             i_col_error = UB_Peak_Table_Setup.index(('Error', 'float'))
             self.update_cell_value(i_row, i_col_error, error)
 
         return
 
-    def restore_cached_indexing(self):
+    def restore_cached_indexing(self, is_spice=True):
         """
         Restore the previously saved value to HKL
         :return:
         """
         # check first such that all the stored value are to be
-        stored_line_index = sorted(self._storedHKL.keys())
+        stored_line_index = sorted(self._cachedSpiceHKL.keys())
         assert len(stored_line_index) == self.rowCount(), 'The current rows and cached row counts do not match.'
 
         # restore
         for row_index in stored_line_index:
-            hkl = self._storedHKL[row_index]
-            self.set_hkl(row_index, hkl)
+            hkl = self._cachedSpiceHKL[row_index]
+            self.set_hkl(row_index, hkl, is_spice_hkl=is_spice)
         # END-FOR
 
         # clear
-        self._storedHKL.clear()
+        self._cachedSpiceHKL.clear()
 
         return
 
@@ -517,13 +864,13 @@ class UBMatrixPeakTable(tableBase.NTableWidget):
         :return:
         """
         # clear the previous value
-        self._storedHKL.clear()
+        self._cachedSpiceHKL.clear()
 
         # store
         num_rows = self.rowCount()
         for row_index in range(num_rows):
-            peak_indexing = self.get_hkl(row_index)
-            self._storedHKL[row_index] = peak_indexing
+            peak_indexing = self.get_hkl(row_index, is_spice_hkl=True)
+            self._cachedSpiceHKL[row_index] = peak_indexing
         # END-FOR
 
         return
@@ -535,30 +882,29 @@ class UBMatrixPeakTable(tableBase.NTableWidget):
         :param k:
         :param l:
         """
-        assert isinstance(i_row, int)
+        assert isinstance(i_row, int), 'row number {0} must be an integer but not a {1}.' \
+                                       ''.format(i_row, type(i_row))
 
-        self.update_cell_value(i_row, 2, h)
-        self.update_cell_value(i_row, 3, k)
-        self.update_cell_value(i_row, 4, l)
+        self.update_cell_value(i_row, self._colIndexCalculatedHKL, self.format_array([h, k, l]))
 
         return
 
 
 class ProcessTableWidget(tableBase.NTableWidget):
     """
-    Extended table for peaks used to calculate UB matrix
+    Extended table for peaks used to process scans including peak integration, scan merging and etc.
     """
     TableSetup = [('Scan', 'int'),
-                  ('Intensity', 'float'),
-                  ('Corrected', 'float'),
                   ('Status', 'str'),
-                  ('Peak', 'str'),  # peak center can be either HKL or Q depending on the unit
+                  ('Intensity', 'float'),
+                  ('Corrected', 'float'),  # Lorenzian corrected
+                  ('Error', 'float'),
+                  ('Integrate', 'str'),  # integration type, Gaussian fit / simple summation
+                  ('Mask', 'str'),  # '' for no mask
                   ('HKL', 'str'),
-                  ('Index From', 'str'),  # source of HKL index, either SPICE or calculation
                   ('Motor', 'str'),
                   ('Motor Step', 'str'),
                   ('Wavelength', 'float'),
-                  ('Workspace', 'str'),
                   ('K-Index', 'int'),
                   ('Select', 'checkbox')]
 
@@ -574,16 +920,22 @@ class ProcessTableWidget(tableBase.NTableWidget):
         self._colIndexScan = None
         self._colIndexIntensity = None
         self._colIndexCorrInt = None
+        self._colIndexErrorBar = None
+        self._colIndexMask = None
+        self._colIndexIntType = None
         self._colIndexHKL = None
         self._colIndexStatus = None
         self._colIndexPeak = None
-        self._colIndexIndexFrom = None
+        # self._colIndexIndexFrom = None
         self._colIndexMotor = None
         self._colIndexMotorStep = None
         self._colIndexWaveLength = None
         self._colIndexKIndex = None
         self._colIndexWorkspace = None
 
+        # cache dictionaries
+        self._workspaceCacheDict = dict()
+
         return
 
     @staticmethod
@@ -591,7 +943,6 @@ class ProcessTableWidget(tableBase.NTableWidget):
         """ Generate a list for empty row with scan number
         :param scan_number:
         :param status:
-        :param frame: HKL or QSample
         :param ws_name
         :return:
         """
@@ -601,15 +952,16 @@ class ProcessTableWidget(tableBase.NTableWidget):
 
         intensity = None
         corr_int = None
+        error = None
+        mask = ''
+        integrate_type = 'sum'
         motor_name = None
         motor_step = None
         wave_length = 0
-        peak_center = ''
         hkl = ''
-        hkl_from = ''
 
-        new_row = [scan_number, intensity, corr_int, status, peak_center, hkl, hkl_from,
-                   motor_name, motor_step, wave_length, ws_name, 0, False]
+        new_row = [scan_number, status, intensity, corr_int, error, integrate_type, mask,  # peak_center,
+                   hkl, motor_name, motor_step, wave_length, 0, False]
 
         return new_row
 
@@ -622,9 +974,12 @@ class ProcessTableWidget(tableBase.NTableWidget):
         :return:
         """
         # check
-        assert isinstance(exp_number, int)
-        assert isinstance(scan_number, int)
-        assert isinstance(ws_name, str)
+        assert isinstance(exp_number, int), 'Experiment number {0} must be an integer but not a {1}.' \
+                                            ''.format(exp_number, type(exp_number))
+        assert isinstance(scan_number, int), 'Scan number {0} must be an integer but not a {1}.' \
+                                             ''.format(scan_number, type(scan_number))
+        assert isinstance(ws_name, str), 'Workspace name {0} must be a string but not a {1}.' \
+                                         ''.format(ws_name, type(ws_name))
 
         # construct a row
         new_row = self._generate_empty_row(scan_number, ws_name=ws_name)
@@ -665,6 +1020,18 @@ class ProcessTableWidget(tableBase.NTableWidget):
 
         return
 
+    def get_integration_type(self):
+        """
+        get the peak integration type
+        :return:
+        """
+        if self.rowCount() == 0:
+            raise RuntimeError('Empty table!')
+
+        integrate_type = self.get_cell_value(0, self._colIndexIntType)
+
+        return integrate_type
+
     def get_row_by_scan(self, scan_number):
         """
         get the row number for a gien scan
@@ -696,7 +1063,8 @@ class ProcessTableWidget(tableBase.NTableWidget):
         :return:
         """
         # Check
-        assert isinstance(target_state, str), 'blabla'
+        assert isinstance(target_state, str), 'State {0} must be a string but not a {1}.' \
+                                              ''.format(target_state, type(target_state))
 
         # Loop around to check
         return_list = list()
@@ -761,7 +1129,8 @@ class ProcessTableWidget(tableBase.NTableWidget):
         :param i_row:
         :return:
         """
-        return self.get_cell_value(i_row, self._colIndexWorkspace)
+        #  return self.get_cell_value(i_row, self._colIndexWorkspace)
+        return self._workspaceCacheDict[i_row]
 
     def get_scan_list(self, output_row_number=True):
         """
@@ -845,9 +1214,6 @@ class ProcessTableWidget(tableBase.NTableWidget):
         hkl_str = '%.3f, %.3f, %.3f' % (hkl[0], hkl[1], hkl[2])
         self.update_cell_value(row_number, self._colIndexHKL, hkl_str)
 
-        if hkl_source is not None:
-            self.update_cell_value(row_number, self._colIndexIndexFrom, hkl_source)
-
         return
 
     def set_k_shift_index(self, row_number, k_index):
@@ -908,24 +1274,31 @@ class ProcessTableWidget(tableBase.NTableWidget):
 
         return
 
-    def set_peak_intensity(self, row_number, peak_intensity, lorentz_corrected=False):
-        """ Set peak intensity to a row or scan
-        Requirement: Either row number or scan number must be given
+    def set_peak_intensity(self, row_number, peak_intensity, corrected_intensity, standard_error, integrate_method):
+        """
+        Set peak intensity to a row in the table
         Guarantees: peak intensity is set
         :param row_number:
         :param peak_intensity:
-        :param lorentz_corrected:
+        :param corrected_intensity:
+        :param standard_error:
+        :param integrate_method: must be '', simple or gaussian for simple counts summation or Gaussian fit, respectively
         :return:
         """
         # check requirements
         assert isinstance(peak_intensity, float), 'Peak intensity must be a float.'
+        assert isinstance(integrate_method, str), 'Integrated method {0} must be a string but not {1}.' \
+                                                  ''.format(integrate_method, type(integrate_method))
+        if integrate_method not in ['', 'simple', 'mixed', 'gaussian']:
+            raise RuntimeError('Peak integration {0} not in list. Method must be in ["" (Not defined), "simple"'
+                               ', "gaussian"]'.format(integrate_method))
 
-        if lorentz_corrected:
-            col_index = self._colIndexCorrInt
-        else:
-            col_index = self._colIndexIntensity
+        self.update_cell_value(row_number, self._colIndexIntensity, peak_intensity)
+        self.update_cell_value(row_number, self._colIndexIntType, integrate_method)
+        self.update_cell_value(row_number, self._colIndexCorrInt, corrected_intensity)
+        self.update_cell_value(row_number, self._colIndexErrorBar, standard_error)
 
-        return self.update_cell_value(row_number, col_index, peak_intensity)
+        return
 
     def set_status(self, row_number, status):
         """
@@ -965,7 +1338,9 @@ class ProcessTableWidget(tableBase.NTableWidget):
         # Check
         assert isinstance(merged_md_name, str), 'Merged MDWorkspace name must be a string.'
 
-        self.update_cell_value(row_number, self._colIndexWorkspace, merged_md_name)
+        #  self.update_cell_value(row_number, self._colIndexWorkspace, merged_md_name)
+
+        self._workspaceCacheDict[row_number] = merged_md_name
 
         return
 
@@ -981,15 +1356,18 @@ class ProcessTableWidget(tableBase.NTableWidget):
         self._colIndexScan = ProcessTableWidget.TableSetup.index(('Scan', 'int'))
         self._colIndexIntensity = self.TableSetup.index(('Intensity', 'float'))
         self._colIndexCorrInt = self.TableSetup.index(('Corrected', 'float'))
+        self._colIndexMask = self.TableSetup.index(('Mask', 'str'))
+        self._colIndexIntType = self.TableSetup.index(('Integrate', 'str'))
         self._colIndexStatus = self.TableSetup.index(('Status', 'str'))
         self._colIndexHKL = ProcessTableWidget.TableSetup.index(('HKL', 'str'))
-        self._colIndexPeak = self.TableSetup.index(('Peak', 'str'))
-        self._colIndexIndexFrom = self.TableSetup.index(('Index From', 'str'))
+        # self._colIndexPeak = self.TableSetup.index(('Peak', 'str'))
+        # self._colIndexIndexFrom = self.TableSetup.index(('Index From', 'str'))
         self._colIndexMotor = ProcessTableWidget.TableSetup.index(('Motor', 'str'))
         self._colIndexMotorStep = ProcessTableWidget.TableSetup.index(('Motor Step', 'str'))
         self._colIndexWaveLength = self.TableSetup.index(('Wavelength', 'float'))
         self._colIndexKIndex = self.TableSetup.index(('K-Index', 'int'))
-        self._colIndexWorkspace = self.TableSetup.index(('Workspace', 'str'))
+        self._colIndexErrorBar = self.TableSetup.index(('Error', 'float'))
+        # self._colIndexWorkspace = self.TableSetup.index(('Workspace', 'str'))
 
         return
 
@@ -1137,24 +1515,42 @@ class ScanSurveyTable(tableBase.NTableWidget):
 
         return scan_list
 
-    def get_selected_run_surveyed(self):
+    def get_selected_run_surveyed(self, required_size=1):
         """
         Purpose: Get selected pt number and run number that is set as selected
         Requirements: there must be one and only one run that is selected
         Guarantees: a 2-tuple for integer for return as scan number and Pt. number
-        :return: a 2-tuple of integer
+        :param required_size: if specified as an integer, then if the number of selected rows is different,
+                              an exception will be thrown.
+        :return: a 2-tuple of integer if required size is 1 (as old implementation) or a list of 2-tuple of integer
         """
+        # check required size?
+        assert isinstance(required_size, int) or required_size is None, 'Required number of runs {0} must be None ' \
+                                                                        'or an integer but not a {1}.' \
+                                                                        ''.format(required_size, type(required_size))
+
         # get the selected row indexes and check
         row_index_list = self.get_selected_rows(True)
-        assert len(row_index_list) == 1, 'There must be exactly one run that is selected. Now' \
-                                         'there are %d runs that are selected' % len(row_index_list)
 
-        # get scan and pt
-        row_index = row_index_list[0]
-        scan_number = self.get_cell_value(row_index, 0)
-        pt_number = self.get_cell_value(row_index, 1)
-
-        return scan_number, pt_number
+        if required_size is not None and required_size != len(row_index_list):
+            raise RuntimeError('It is required to have {0} runs selected, but now there are {1} runs that are '
+                               'selected.'.format(required_size, row_index_list))
+
+        # get all the scans and rows that are selected
+        scan_run_list = list()
+        for i_row in row_index_list:
+            # get scan and pt.
+            scan_number = self.get_cell_value(i_row, 0)
+            pt_number = self.get_cell_value(i_row, 1)
+            scan_run_list.append((scan_number, pt_number))
+
+        # special case for only 1 run that is selected
+        if len(row_index_list) == 1 and required_size is not None:
+            # get scan and pt
+            return scan_run_list[0]
+        # END-IF
+
+        return scan_run_list
 
     def show_reflections(self, num_rows):
         """
diff --git a/scripts/HFIR_4Circle_Reduction/integratedpeakview.py b/scripts/HFIR_4Circle_Reduction/integratedpeakview.py
index 7c737b52ff192a603b004ed2865a882a2adca911..6ea8f631586722766915b949116b8c8fe62ac0f0 100644
--- a/scripts/HFIR_4Circle_Reduction/integratedpeakview.py
+++ b/scripts/HFIR_4Circle_Reduction/integratedpeakview.py
@@ -1,4 +1,5 @@
 #pylint: disable=W0403,R0904,R0903
+import numpy
 import mplgraphicsview
 
 
@@ -31,6 +32,10 @@ class IntegratedPeakView(mplgraphicsview.MplGraphicsView):
         self._currX = 0.
         self._currY = 0.
 
+        # data managing
+        self._rawDataID = None
+        self._modelDataID = None
+
         return
 
     def add_background_indictor(self):
@@ -42,6 +47,20 @@ class IntegratedPeakView(mplgraphicsview.MplGraphicsView):
 
         return
 
+    def get_raw_data(self):
+        """
+        :exception: RuntimeError if no plot on canvas
+        :return: 2-tuple as vec_x and vec_y
+        """
+        if self._rawDataID is None:
+            raise RuntimeError('There is no raw data plot on the canvas')
+
+        data_set = self.canvas().get_data(self._rawDataID)
+        vec_x = data_set[0]
+        vec_y = data_set[1]
+
+        return vec_x, vec_y
+
     def on_mouse_motion(self, event):
         """
 
@@ -73,7 +92,69 @@ class IntegratedPeakView(mplgraphicsview.MplGraphicsView):
         """
         self._mousePressed = self.MousePress.RELEASED
 
-        print event.y, event.ydata
+        return
+
+    def plot_raw_data(self, vec_x, vec_y):
+        """
+        plot raw data, which will be recorded by _rawDataID
+        :param vec_x:
+        :param vec_y:
+        :return:
+        """
+        # plot data
+        self._rawDataID = self.add_plot_1d(vec_x, vec_y,  color='blue')
+        self.set_smart_y_limit(vec_y)
+
+        return
+
+    def plot_model(self, vec_x, model_vec_y, title=None):
+        """
+        plot model data which will be recorded by
+        :param vec_x:
+        :param model_vec_y:
+        :param title:
+        :return:
+        """
+        # plot data
+        self._modelDataID = self.add_plot_1d(vec_x, model_vec_y)
+        if title is not None:
+            self.set_title(title)
+        self.set_smart_y_limit(model_vec_y)
+
+        self.setXYLimit(xmin=vec_x[0] - 1., xmax=vec_x[-1] + 1.)
+
+        return
+
+    def remove_model(self):
+        """
+        remove the plot for model
+        :return:
+        """
+        if self._modelDataID is None:
+            raise RuntimeError('There is no model plot on canvas')
+
+        # reset title
+        self.set_title('')
+        self.remove_line(self._modelDataID)
+
+        self._modelDataID = None
+
+        return
+
+    def reset(self):
+        """
+        reset the canvas and thus the handler to the plots
+        :return:
+        """
+        # clear all lines
+        self.clear_all_lines()
+
+        # reset handlers
+        self._rawDataID = None
+        self._modelDataID = None
+
+        # reset title
+        self.set_title('')
 
         return
 
@@ -85,11 +166,14 @@ class IntegratedPeakView(mplgraphicsview.MplGraphicsView):
         :return:
         """
         # check
-        assert len(vec_y) > 0
+        assert isinstance(vec_y, numpy.ndarray) and len(vec_y) > 0, 'Vector Y must be a numpy array and not empty.'
 
         # find y's minimum and maximum
-        min_y = min(vec_y)
-        max_y = max(vec_y)
+        try:
+            min_y = numpy.min(vec_y)
+            max_y = numpy.max(vec_y)
+        except ValueError as value_err:
+            raise RuntimeError(str(value_err))
 
         d_y = max_y - min_y
 
diff --git a/scripts/HFIR_4Circle_Reduction/message_dialog.py b/scripts/HFIR_4Circle_Reduction/message_dialog.py
new file mode 100644
index 0000000000000000000000000000000000000000..1e1d7385e1cc40282e117f65547f9c549ccf5cde
--- /dev/null
+++ b/scripts/HFIR_4Circle_Reduction/message_dialog.py
@@ -0,0 +1,72 @@
+# Dialog for message
+from PyQt4 import QtGui, QtCore
+
+import ui_messagebox
+
+
+class MessageDialog(QtGui.QDialog):
+    """
+    extension of QDialog
+    """
+    def __init__(self, parent):
+        """
+        initialization of customized dialog box
+        :param parent:
+        :return:
+        """
+        super(MessageDialog, self).__init__(parent)
+
+        # set up UI
+        self.ui = ui_messagebox.Ui_Dialog()
+        self.ui.setupUi(self)
+
+        # define operation
+        self.connect(self.ui.pushButton_close, QtCore.SIGNAL('clicked()'),
+                     self.do_quit)
+
+        return
+
+    def do_quit(self):
+        """
+
+        :return:
+        """
+        self.close()
+
+    def set_text(self, text):
+        """
+        set text to the text editor
+        :param text:
+        :return:
+        """
+        assert isinstance(text, str), 'Input text of type {0} must be a string.'.format(type(text))
+        self.ui.plainTextEdit_message.setPlainText(text)
+
+        return
+
+    def set_peak_integration_details(self, motor_pos_vec, pt_intensity_vec):
+        """
+        set the  details information of integrated peak including the peak intensities of
+        each Pt.
+        :param motor_pos_vec:
+        :param pt_intensity_vec:
+        :return:
+        """
+        text = '# Pt. \tIntensity \tMotor Position\n'
+        num_loops = max(len(motor_pos_vec), len(pt_intensity_vec))
+
+        for pt in range(num_loops):
+            text += '{0} \t'.format(pt+1)
+            if pt < len(pt_intensity_vec):
+                text += '{0} \t'.format(pt_intensity_vec[pt])
+            else:
+                text += '     \t'
+            if pt < len(motor_pos_vec):
+                text += '{0}\n'.format(motor_pos_vec[pt])
+            else:
+                text += '   \n'
+        # END-FOR
+
+        self.set_text(text)
+
+        return
diff --git a/scripts/HFIR_4Circle_Reduction/messagebox.ui b/scripts/HFIR_4Circle_Reduction/messagebox.ui
new file mode 100644
index 0000000000000000000000000000000000000000..397cab0b38e171c43a45809b390ad247c801dd7e
--- /dev/null
+++ b/scripts/HFIR_4Circle_Reduction/messagebox.ui
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>865</width>
+    <height>1001</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <widget class="QPlainTextEdit" name="plainTextEdit_message"/>
+   </item>
+   <item row="1" column="0">
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="pushButton_close">
+       <property name="text">
+        <string>Close</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/scripts/HFIR_4Circle_Reduction/mpl2dgraphicsview.py b/scripts/HFIR_4Circle_Reduction/mpl2dgraphicsview.py
index 1a53ba0ffe3a39ca6306371c6509464c2e9a6dc2..f49c1e9235fdc23a40511bd6b1caca53d3ba8e61 100644
--- a/scripts/HFIR_4Circle_Reduction/mpl2dgraphicsview.py
+++ b/scripts/HFIR_4Circle_Reduction/mpl2dgraphicsview.py
@@ -37,6 +37,14 @@ class Mpl2dGraphicsView(QtGui.QWidget):
 
         return
 
+    @property
+    def array2d(self):
+        """
+        return the matrix (2d-array) plot on the canvas
+        :return:
+        """
+        return self._myCanvas.array2d
+
     def add_plot_2d(self, array2d, x_min, x_max, y_min, y_max, hold_prev_image=True, y_tick_label=None):
         """
         Add a 2D image to canvas
@@ -148,6 +156,9 @@ class Qt4Mpl2dCanvas(FigureCanvas):
         # polygon
         self._myPolygon = None
 
+        # Buffer of data
+        self._currentArray2D = None
+
         # image management data structure
         self._currIndex = 0
         self._imagePlotDict = dict()
@@ -158,6 +169,14 @@ class Qt4Mpl2dCanvas(FigureCanvas):
 
         return
 
+    @property
+    def array2d(self):
+        """
+        get the matrix plot now
+        :return:
+        """
+        return self._currentArray2D
+
     def add_2d_plot(self, array2d, x_min, x_max, y_min, y_max, hold_prev, yticklabels=None):
         """ Add a 2D plot
         Requirements:
@@ -187,6 +206,7 @@ class Qt4Mpl2dCanvas(FigureCanvas):
         img_plot = self.axes.imshow(array2d,
                                     extent=[x_min, x_max, y_min, y_max],
                                     interpolation='none')
+        self._currentArray2D = array2d
 
         # set y ticks as an option:
         if yticklabels is not None:
diff --git a/scripts/HFIR_4Circle_Reduction/mplgraphicsview.py b/scripts/HFIR_4Circle_Reduction/mplgraphicsview.py
index 83115051cad2cfe50bfaa7b031a88466ee7ff105..a9ba39c9dc4e98f96e022d47581a88bb54fce0da 100644
--- a/scripts/HFIR_4Circle_Reduction/mplgraphicsview.py
+++ b/scripts/HFIR_4Circle_Reduction/mplgraphicsview.py
@@ -1,8 +1,9 @@
-#pylint: disable=invalid-name,too-many-public-methods,too-many-arguments,non-parent-init-called,R0901,R0902,too-many-branches,C0302,W0231
+#pylint: disable=invalid-name,too-many-public-methods,too-many-arguments,non-parent-init-called,R0902,too-many-branches,C0302
 import os
 import numpy as np
 
 from PyQt4 import QtGui
+from PyQt4.QtCore import pyqtSignal
 
 from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
 from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar2
@@ -55,7 +56,6 @@ class IndicatorManager(object):
     - 1: vertical. moving along X-direction. [x, x], [y_min, y_max];
     - 2: 2-way. moving in any direction. [x_min, x_max], [y, y], [x, x], [y_min, y_max].
     """
-
     def __init__(self):
         """
 
@@ -143,6 +143,16 @@ class IndicatorManager(object):
 
         return this_id
 
+    def delete(self, indicator_id):
+        """
+        Delete indicator
+        """
+        del self._lineManager[indicator_id]
+        del self._canvasLineKeyDict[indicator_id]
+        del self._indicatorTypeDict[indicator_id]
+
+        return
+
     def get_canvas_line_index(self, indicator_id):
         """
         Get a line's ID (on canvas) from an indicator ID
@@ -171,8 +181,8 @@ class IndicatorManager(object):
         :param line_id:
         :return:
         """
-        assert line_id in self._indicatorTypeDict
-        assert self._indicatorTypeDict[line_id] == 2
+        assert line_id in self._indicatorTypeDict, 'blabla'
+        assert self._indicatorTypeDict[line_id] == 2, 'blabla'
 
         vec_set = [self._lineManager[line_id][0:2], self._lineManager[line_id][2:4]]
 
@@ -233,13 +243,13 @@ class IndicatorManager(object):
         """
         return sorted(self._lineManager.keys())
 
-    def get_marker(self):
+    @staticmethod
+    def get_marker():
         """
         Get the marker a line
-        :param line_id:
         :return:
         """
-        return 'o'
+        return '.'
 
     def get_next_color(self):
         """
@@ -346,7 +356,6 @@ class MplGraphicsView(QtGui.QWidget):
 
     Note: Merged with HFIR_Powder_Reduction.MplFigureCAnvas
     """
-
     def __init__(self, parent):
         """ Initialization
         """
@@ -357,6 +366,11 @@ class MplGraphicsView(QtGui.QWidget):
         self._myCanvas = Qt4MplCanvas(self)
         self._myToolBar = MyNavigationToolbar(self, self._myCanvas)
 
+        # state of operation
+        self._isZoomed = False
+        # X and Y limit with home button
+        self._homeXYLimit = None
+
         # set up layout
         self._vBox = QtGui.QVBoxLayout(self)
         self._vBox.addWidget(self._myCanvas)
@@ -367,12 +381,19 @@ class MplGraphicsView(QtGui.QWidget):
         self._myLineMarkerColorIndex = 0
         self.setAutoLineMarkerColorCombo()
 
+        # records for all the lines that are plot on the canvas
+        self._my1DPlotDict = dict()
+
         # Declaration of class variables
         self._indicatorKey = None
 
         # Indicator manager
         self._myIndicatorsManager = IndicatorManager()
 
+        # some statistic recorder for convenient operation
+        self._statDict = dict()
+        self._statRightPlotDict = dict()
+
         return
 
     def add_arrow(self, start_x, start_y, stop_x, stop_y):
@@ -407,14 +428,27 @@ class MplGraphicsView(QtGui.QWidget):
 
         return key_list
 
-    def add_plot_1d(self, vec_x, vec_y, y_err=None, color=None, label="", x_label=None, y_label=None,
-                    marker=None, line_style=None, line_width=1):
-        """ Add a new plot
+    def add_plot_1d(self, vec_x, vec_y, y_err=None, color=None, label='', x_label=None, y_label=None,
+                    marker=None, line_style=None, line_width=1, show_legend=True):
         """
-        line_key = self._myCanvas.add_plot_1d(vec_x, vec_y, y_err, color, label, x_label, y_label, marker, line_style,
-                                              line_width)
+        Add a 1-D plot to canvas
+        :param vec_x:
+        :param vec_y:
+        :param y_err:
+        :param color:
+        :param label:
+        :param x_label:
+        :param y_label:
+        :param marker:
+        :param line_style:
+        :param line_width:
+        :param show_legend:
+        :return: line ID (key to the line)
+        """
+        line_id = self._myCanvas.add_plot_1d(vec_x, vec_y, y_err, color, label, x_label, y_label, marker, line_style,
+                                             line_width, show_legend)
 
-        return line_key
+        return line_id
 
     def add_plot_1d_right(self, vec_x, vec_y, color=None, label='', marker=None, line_style=None, line_width=1):
         """
@@ -432,6 +466,8 @@ class MplGraphicsView(QtGui.QWidget):
                                                     color=color, marker=marker,
                                                     linestyle=line_style, linewidth=line_width)
 
+        self._statRightPlotDict[line_key] = (min(vec_x), max(vec_x), min(vec_y), max(vec_y))
+
         return line_key
 
     def add_2way_indicator(self, x=None, y=None, color=None, master_line=None):
@@ -505,12 +541,13 @@ class MplGraphicsView(QtGui.QWidget):
 
         return my_id
 
-    def add_vertical_indicator(self, x=None, color=None):
+    def add_vertical_indicator(self, x=None, color=None, style=None, line_width=1):
         """
         Add a vertical indicator line
         Guarantees: an indicator is plot and its ID is returned
         :param x: None as the automatic mode using default from middle of canvas
         :param color: None as the automatic mode using default
+        :param style:
         :return: indicator ID
         """
         # For indicator line's position
@@ -528,6 +565,10 @@ class MplGraphicsView(QtGui.QWidget):
         else:
             assert isinstance(color, str)
 
+        # style
+        if style is None:
+            style = self._myIndicatorsManager.get_line_style()
+
         # Form
         my_id = self._myIndicatorsManager.add_vertical_indicator(x, y_min, y_max, color)
         vec_x, vec_y = self._myIndicatorsManager.get_data(my_id)
@@ -579,9 +620,27 @@ class MplGraphicsView(QtGui.QWidget):
         """
         self._myCanvas.clear_all_1d_plots()
 
+        self._statRightPlotDict.clear()
+        self._statDict.clear()
+        self._my1DPlotDict.clear()
+
+        # about zoom
+        self._isZoomed = False
+        self._homeXYLimit = None
+
+        return
+
     def clear_canvas(self):
         """ Clear canvas
         """
+        # clear all the records
+        self._statDict.clear()
+        self._my1DPlotDict.clear()
+
+        # about zoom
+        self._isZoomed = False
+        self._homeXYLimit = None
+
         return self._myCanvas.clear_canvas()
 
     def draw(self):
@@ -589,6 +648,21 @@ class MplGraphicsView(QtGui.QWidget):
         """
         return self._myCanvas.draw()
 
+    def evt_toolbar_home(self):
+        """
+
+        Parameters
+        ----------
+
+        Returns
+        -------
+
+        """
+        # turn off zoom mode
+        self._isZoomed = False
+
+        return
+
     def evt_view_updated(self):
         """ Event handling as canvas size updated
         :return:
@@ -606,6 +680,24 @@ class MplGraphicsView(QtGui.QWidget):
 
         return
 
+    def evt_zoom_released(self):
+        """
+        event for zoom is release
+        Returns
+        -------
+
+        """
+        # record home XY limit if it is never zoomed
+        if self._isZoomed is False:
+            self._homeXYLimit = list(self.getXLimit())
+            self._homeXYLimit.extend(list(self.getYLimit()))
+        # END-IF
+
+        # set the state of being zoomed
+        self._isZoomed = True
+
+        return
+
     def getPlot(self):
         """
         """
@@ -627,6 +719,38 @@ class MplGraphicsView(QtGui.QWidget):
         """
         return self._myCanvas.getYLimit()
 
+    def get_y_min(self):
+        """
+        Get the minimum Y value of the plots on canvas
+        :return:
+        """
+        if len(self._statDict) == 0:
+            return 1E10
+
+        line_id_list = self._statDict.keys()
+        min_y = self._statDict[line_id_list[0]][2]
+        for i_plot in range(1, len(line_id_list)):
+            if self._statDict[line_id_list[i_plot]][2] < min_y:
+                min_y = self._statDict[line_id_list[i_plot]][2]
+
+        return min_y
+
+    def get_y_max(self):
+        """
+        Get the maximum Y value of the plots on canvas
+        :return:
+        """
+        if len(self._statDict) == 0:
+            return -1E10
+
+        line_id_list = self._statDict.keys()
+        max_y = self._statDict[line_id_list[0]][3]
+        for i_plot in range(1, len(line_id_list)):
+            if self._statDict[line_id_list[i_plot]][3] > max_y:
+                max_y = self._statDict[line_id_list[i_plot]][3]
+
+        return max_y
+
     def move_indicator(self, line_id, dx, dy):
         """
         Move the indicator line in horizontal
@@ -661,6 +785,7 @@ class MplGraphicsView(QtGui.QWidget):
         #
         plot_id = self._myIndicatorsManager.get_canvas_line_index(indicator_key)
         self._myCanvas.remove_plot_1d(plot_id)
+        self._myIndicatorsManager.delete(indicator_key)
 
         return
 
@@ -669,8 +794,18 @@ class MplGraphicsView(QtGui.QWidget):
         :param line_id:
         :return:
         """
+        # remove line
         self._myCanvas.remove_plot_1d(line_id)
 
+        # remove the records
+        if line_id in self._statDict:
+            del self._statDict[line_id]
+            del self._my1DPlotDict[line_id]
+        else:
+            del self._statRightPlotDict[line_id]
+
+        return
+
     def set_indicator_position(self, line_id, pos_x, pos_y):
         """ Set the indicator to new position
         :param line_id:
@@ -702,9 +837,27 @@ class MplGraphicsView(QtGui.QWidget):
         """
         return self._myCanvas.remove_plot_1d(ikey)
 
-    def updateLine(self, ikey, vecx, vecy, linestyle=None, linecolor=None, marker=None, markercolor=None):
+    def updateLine(self, ikey, vecx=None, vecy=None, linestyle=None, linecolor=None, marker=None, markercolor=None):
         """
+        update a line's set up
+        Parameters
+        ----------
+        ikey
+        vecx
+        vecy
+        linestyle
+        linecolor
+        marker
+        markercolor
+
+        Returns
+        -------
+
         """
+        # check
+        assert isinstance(ikey, int), 'Line key must be an integer.'
+        assert ikey in self._my1DPlotDict, 'Line with ID %d is not on canvas. ' % ikey
+
         return self._myCanvas.updateLine(ikey, vecx, vecy, linestyle, linecolor, marker, markercolor)
 
     def update_indicator(self, i_key, color):
@@ -730,6 +883,28 @@ class MplGraphicsView(QtGui.QWidget):
 
         return
 
+    def get_canvas(self):
+        """
+        get canvas
+        Returns:
+
+        """
+        return self._myCanvas
+
+    def get_current_plots(self):
+        """
+        Get the current plots on canvas
+        Returns
+        -------
+        list of 2-tuple: integer (plot ID) and string (label)
+        """
+        tuple_list = list()
+        line_id_list = sorted(self._my1DPlotDict.keys())
+        for line_id in line_id_list:
+            tuple_list.append((line_id, self._my1DPlotDict[line_id]))
+
+        return tuple_list
+
     def get_indicator_key(self, x, y):
         """ Get the key of the indicator with given position
         :param picker_pos:
@@ -800,12 +975,23 @@ class MplGraphicsView(QtGui.QWidget):
 
         return marker, color
 
-    def resetLineColorStyle(self):
+    def reset_line_color_marker_index(self):
         """ Reset the auto index for line's color and style
         """
         self._myLineMarkerColorIndex = 0
         return
 
+    def set_title(self, title, color='black'):
+        """
+        set title to canvas
+        :param title:
+        :param color:
+        :return:
+        """
+        self._myCanvas.set_title(title, color)
+
+        return
+
     def setXYLimit(self, xmin=None, xmax=None, ymin=None, ymax=None):
         """ Set X-Y limit automatically
         """
@@ -817,12 +1003,12 @@ class MplGraphicsView(QtGui.QWidget):
         return
 
     def setAutoLineMarkerColorCombo(self):
+        """ Set the default/auto line marker/color combination list
         """
-        """
-        self._myLineMarkerColorList = []
+        self._myLineMarkerColorList = list()
         for marker in MplLineMarkers:
             for color in MplBasicColors:
-                self._myLineMarkerColorList.append( (marker, color) )
+                self._myLineMarkerColorList.append((marker, color))
 
         return
 
@@ -838,7 +1024,6 @@ class Qt4MplCanvas(FigureCanvas):
     """  A customized Qt widget for matplotlib figure.
     It can be used to replace GraphicsView of QtGui
     """
-
     def __init__(self, parent):
         """  Initialization
         """
@@ -851,7 +1036,8 @@ class Qt4MplCanvas(FigureCanvas):
         self.fig.patch.set_facecolor('white')
 
         if True:
-            self.axes = self.fig.add_subplot(111) # return: matplotlib.axes.AxesSubplot
+            self.axes = self.fig.add_subplot(111)  # return: matplotlib.axes.AxesSubplot
+            self.fig.subplots_adjust(bottom=0.15)
             self.axes2 = None
         else:
             self.axes = self.fig.add_host_subplot(111)
@@ -870,9 +1056,20 @@ class Qt4MplCanvas(FigureCanvas):
 
         # legend and color bar
         self._colorBar = None
+        self._isLegendOn = False
+        self._legendFontSize = 8
 
         return
 
+    @property
+    def is_legend_on(self):
+        """
+        check whether the legend is shown or hide
+        Returns:
+        boolean
+        """
+        return self._isLegendOn
+
     def add_arrow(self, start_x, start_y, stop_x, stop_y):
         """
         0, 0, 0.5, 0.5, head_width=0.05, head_length=0.1, fc='k', ec='k')
@@ -889,7 +1086,7 @@ class Qt4MplCanvas(FigureCanvas):
         return
 
     def add_plot_1d(self, vec_x, vec_y, y_err=None, color=None, label="", x_label=None, y_label=None,
-                    marker=None, line_style=None, line_width=1):
+                    marker=None, line_style=None, line_width=1, show_legend=True):
         """
 
         :param vec_x: numpy array X
@@ -902,11 +1099,13 @@ class Qt4MplCanvas(FigureCanvas):
         :param marker:
         :param line_style:
         :param line_width:
+        :param show_legend:
         :return: new key
         """
         # Check input
         if isinstance(vec_x, np.ndarray) is False or isinstance(vec_y, np.ndarray) is False:
-            raise NotImplementedError('Input vec_x or vec_y for addPlot() must be numpy.array.')
+            raise NotImplementedError('Input vec_x {0} or vec_y {1} for addPlot() must be numpy.array, but they are '
+                                      '{2} and {3}.'.format(vec_x, vec_y, type(vec_x), type(vec_y)))
         plot_error = y_err is not None
         if plot_error is True:
             if isinstance(y_err, np.ndarray) is False:
@@ -920,19 +1119,25 @@ class Qt4MplCanvas(FigureCanvas):
         # Hold previous data
         self.axes.hold(True)
 
+        # set x-axis and y-axis label
+        if x_label is not None:
+            self.axes.set_xlabel(x_label, fontsize=16)
+        if y_label is not None:
+            self.axes.set_ylabel(y_label, fontsize=16)
+
         # process inputs and defaults
         if color is None:
             color = (0, 1, 0, 1)
         if marker is None:
-            marker = 'o'
+            marker = 'None'
         if line_style is None:
             line_style = '-'
 
         # color must be RGBA (4-tuple)
         if plot_error is False:
-            r = self.axes.plot(vec_x, vec_y, color=color, marker=marker, linestyle=line_style,
-                               label=label, linewidth=line_width)
             # return: list of matplotlib.lines.Line2D object
+            r = self.axes.plot(vec_x, vec_y, color=color, marker=marker, markersize=1, linestyle=line_style,
+                               label=label, linewidth=line_width)
         else:
             r = self.axes.errorbar(vec_x, vec_y, yerr=y_err, color=color, marker=marker, linestyle=line_style,
                                    label=label, linewidth=line_width)
@@ -946,15 +1151,25 @@ class Qt4MplCanvas(FigureCanvas):
             self.axes.set_ylabel(y_label, fontsize=20)
 
         # set/update legend
-        self._setupLegend()
+        if show_legend:
+            self._setup_legend()
 
         # Register
         line_key = self._lineIndex
-        if len(r) == 1:
+        if plot_error:
+            msg = 'Return from plot is a {0}-tuple: {1} with plot error is {2}\n'.format(len(r), r, plot_error)
+            for i_r in range(len(r)):
+                msg += 'r[%d] = %s\n' % (i_r, str(r[i_r]))
+            raise NotImplementedError(msg)
+        else:
+            assert len(r) > 0, 'There must be at least 1 figure returned'
             self._lineDict[line_key] = r[0]
             self._lineIndex += 1
-        else:
-            print "Impoooooooooooooooosible!  Return from plot is a %d-tuple. " % (len(r))
+
+            for i_r in range(1, len(r)):
+                # remove the un-defined extra lines
+                self.axes.lines.remove(r[i_r])
+        # END-IF-ELSE
 
         # Flush/commit
         self.draw()
@@ -998,7 +1213,7 @@ class Qt4MplCanvas(FigureCanvas):
             self.axes2.set_ylabel(ylabel, fontsize=20)
 
         # set/update legend
-        self._setupLegend()
+        self._setup_legend()
 
         # Register
         line_key = -1
@@ -1029,7 +1244,9 @@ class Qt4MplCanvas(FigureCanvas):
         # self.axes.set_yticks(yticks)
 
         # show image
-        imgplot = self.axes.imshow(array2d, extent=[xmin,xmax,ymin,ymax], interpolation='none')
+        imgplot = self.axes.imshow(array2d, extent=[xmin, xmax, ymin, ymax], interpolation='none')
+
+        # TODO/ISSUE/55: how to make this part more powerful
         # set y ticks as an option:
         if yticklabels is not None:
             # it will always label the first N ticks even image is zoomed in
@@ -1052,6 +1269,51 @@ class Qt4MplCanvas(FigureCanvas):
 
         return
 
+    def add_contour_plot(self, vec_x, vec_y, matrix_z):
+        """
+
+        :param vec_x:
+        :param vec_y:
+        :param matrix_z:
+        :return:
+        """
+        # create mesh grid
+        grid_x, grid_y = np.meshgrid(vec_x, vec_y)
+
+        # check size
+        assert grid_x.shape == matrix_z.shape, 'Size of X (%d) and Y (%d) must match size of Z (%s).' \
+                                               '' % (len(vec_x), len(vec_y), matrix_z.shape)
+
+        # Release the current image
+        self.axes.hold(False)
+
+        # Do plot
+        contour_plot = self.axes.contourf(grid_x, grid_y, matrix_z, 100)
+
+        labels = [item.get_text() for item in self.axes.get_yticklabels()]
+        print '[DB...BAT] Number of Y labels = ', len(labels), ', Number of Y = ', len(vec_y)
+
+        # TODO/ISSUE/55: how to make this part more powerful
+        if len(labels) == 2*len(vec_y) - 1:
+            new_labels = [''] * len(labels)
+            for i in range(len(vec_y)):
+                new_labels[i*2] = '%d' % int(vec_y[i])
+            self.axes.set_yticklabels(new_labels)
+
+        # explicitly set aspect ratio of the image
+        self.axes.set_aspect('auto')
+
+        # Set color bar.  plt.colorbar() does not work!
+        if self._colorBar is None:
+            # set color map type
+            contour_plot.set_cmap('spectral')
+            self._colorBar = self.fig.colorbar(contour_plot)
+        else:
+            self._colorBar.update_bruteforce(contour_plot)
+
+        # Flush...
+        self._flush()
+
     def addImage(self, imagefilename):
         """ Add an image by file
         """
@@ -1090,7 +1352,7 @@ class Qt4MplCanvas(FigureCanvas):
                 except ValueError as e:
                     print "[Error] Plot %s is not in axes.lines which has %d lines. Error mesage: %s" % (
                         str(plot), len(self.axes.lines), str(e))
-                self._lineDict[ikey] = None
+                del self._lineDict[ikey]
             else:
                 # error bar
                 plot[0].remove()
@@ -1098,11 +1360,11 @@ class Qt4MplCanvas(FigureCanvas):
                     line.remove()
                 for line in plot[2]:
                     line.remove()
-                self._lineDict[ikey] = None
+                del self._lineDict[ikey]
             # ENDIF(plot)
         # ENDFOR
 
-        self._setupLegend()
+        self._setup_legend()
 
         self.draw()
 
@@ -1127,12 +1389,30 @@ class Qt4MplCanvas(FigureCanvas):
             self.fig.clear()
             # Re-create subplot
             self.axes = self.fig.add_subplot(111)
+            self.fig.subplots_adjust(bottom=0.15)
 
         # flush/commit
         self._flush()
 
         return
 
+    def decrease_legend_font_size(self):
+        """
+        reset the legend with the new font size
+        Returns:
+
+        """
+        # minimum legend font size is 2! return if it already uses the smallest font size.
+        if self._legendFontSize <= 2:
+            return
+
+        self._legendFontSize -= 1
+        self._setup_legend(font_size=self._legendFontSize)
+
+        self.draw()
+
+        return
+
     def getLastPlotIndexKey(self):
         """ Get the index/key of the last added line
         """
@@ -1153,6 +1433,35 @@ class Qt4MplCanvas(FigureCanvas):
         """
         return self.axes.get_ylim()
 
+    def hide_legend(self):
+        """
+        hide the legend if it is not None
+        Returns:
+
+        """
+        if self.axes.legend() is not None:
+            # set visible to be False and re-draw
+            self.axes.legend().set_visible(False)
+            self.draw()
+
+        self._isLegendOn = False
+
+        return
+
+    def increase_legend_font_size(self):
+        """
+        reset the legend with the new font size
+        Returns:
+
+        """
+        self._legendFontSize += 1
+
+        self._setup_legend(font_size=self._legendFontSize)
+
+        self.draw()
+
+        return
+
     def setXYLimit(self, xmin, xmax, ymin, ymax):
         """
         """
@@ -1179,6 +1488,27 @@ class Qt4MplCanvas(FigureCanvas):
 
         return
 
+    def set_title(self, title, color, location='center'):
+        """
+        set title to the figure (canvas) with default location at center
+        :param title:
+        :param color:
+        :param location
+        :return:
+        """
+        # check input
+        assert isinstance(title, str), 'Title {0} must be a string but not a {1}.'.format(title, type(title))
+        assert isinstance(color, str) and len(color) > 0, 'Color {0} must be a non-empty string but not a {1}.' \
+                                                          ''.format(color, type(color))
+        assert isinstance(location, str) and len(location) > 0, 'Location {0} must be a non-empty string but not a {1}.' \
+                                                                ''.format(location, type(location))
+
+        # set title and re-draw to apply
+        self.axes.set_title(title, loc=location, color=color)
+        self.draw()
+
+        return
+
     def remove_plot_1d(self, plot_key):
         """ Remove the line with its index as key
         :param plot_key:
@@ -1186,23 +1516,63 @@ class Qt4MplCanvas(FigureCanvas):
         """
         # Get all lines in list
         lines = self.axes.lines
-        assert isinstance(lines, list)
+        assert isinstance(lines, list), 'Lines must be list'
 
         if plot_key in self._lineDict:
-            self.axes.lines.remove(self._lineDict[plot_key])
-            self._lineDict[plot_key] = None
+            try:
+                self.axes.lines.remove(self._lineDict[plot_key])
+            except ValueError as r_error:
+                error_message = 'Unable to remove to 1D line %s (ID=%d) due to %s.' % (str(self._lineDict[plot_key]),
+                                                                                       plot_key, str(r_error))
+                raise RuntimeError(error_message)
+            # remove the plot key from dictionary
+            del self._lineDict[plot_key]
         else:
             raise RuntimeError('Line with ID %s is not recorded.' % plot_key)
 
+        self._setup_legend(location='best', font_size=self._legendFontSize)
+
         # Draw
         self.draw()
 
         return
 
-    def updateLine(self, ikey, vecx, vecy, linestyle=None, linecolor=None, marker=None, markercolor=None):
+    def show_legend(self):
+        """
+        show the legend if the legend is not None
+        Returns:
+
+        """
+        if self.axes.legend() is not None:
+            # set visible to be True and re-draw
+            # self.axes.legend().set_visible(True)
+            self._setup_legend(font_size=self._legendFontSize)
+            self.draw()
+
+            # set flag on
+            self._isLegendOn = True
+
+        return
+
+    def updateLine(self, ikey, vecx=None, vecy=None, linestyle=None, linecolor=None, marker=None, markercolor=None):
         """
+        Update a plot line or a series plot line
+        Args:
+            ikey:
+            vecx:
+            vecy:
+            linestyle:
+            linecolor:
+            marker:
+            markercolor:
+
+        Returns:
+
         """
         line = self._lineDict[ikey]
+        if line is None:
+            print '[ERROR] Line (key = %d) is None. Unable to update' % ikey
+            return
 
         if vecx is not None and vecy is not None:
             line.set_xdata(vecx)
@@ -1223,13 +1593,30 @@ class Qt4MplCanvas(FigureCanvas):
         oldlabel = line.get_label()
         line.set_label(oldlabel)
 
-        self.axes.legend()
+        self._setup_legend()
 
         # commit
         self.draw()
 
         return
 
+    def get_data(self, line_id):
+        """
+        Get vecX and vecY from line object in matplotlib
+        :param line_id:
+        :return: 2-tuple as vector X and vector Y
+        """
+        # check
+        if line_id not in self._lineDict:
+            raise KeyError('Line ID %s does not exist.' % str(line_id))
+
+        # get line
+        line = self._lineDict[line_id]
+        if line is None:
+            raise RuntimeError('Line ID %s has been removed.' % line_id)
+
+        return line.get_xdata(), line.get_ydata()
+
     def getLineStyleList(self):
         """
         """
@@ -1249,19 +1636,19 @@ class Qt4MplCanvas(FigureCanvas):
         """ Get a list of line/marker color and marker style combination
         as default to add more and more line to plot
         """
-        combolist = []
-        nummarkers = len(MplLineMarkers)
-        numcolors = len(MplBasicColors)
+        combo_list = list()
+        num_markers = len(MplLineMarkers)
+        num_colors = len(MplBasicColors)
 
-        for i in xrange(nummarkers):
+        for i in xrange(num_markers):
             marker = MplLineMarkers[i]
-            for j in xrange(numcolors):
+            for j in xrange(num_colors):
                 color = MplBasicColors[j]
-                combolist.append( (marker, color) )
+                combo_list.append((marker, color))
             # ENDFOR (j)
         # ENDFOR(i)
 
-        return combolist
+        return combo_list
 
     def _flush(self):
         """ A dirty hack to flush the image
@@ -1272,12 +1659,18 @@ class Qt4MplCanvas(FigureCanvas):
 
         return
 
-    def _setupLegend(self, location='best'):
-        """ Set up legend
-        self.axes.legend()
-        Handler is a Line2D object. Lable maps to the line object
+    def _setup_legend(self, location='best', font_size=10):
+        """
+        Set up legend
+        self.axes.legend(): Handler is a Line2D object. Lable maps to the line object
+        Args:
+            location:
+            font_size:
+
+        Returns:
+
         """
-        loclist = [
+        allowed_location_list = [
             "best",
             "upper right",
             "upper left",
@@ -1291,11 +1684,13 @@ class Qt4MplCanvas(FigureCanvas):
             "center"]
 
         # Check legend location valid or not
-        if location not in loclist:
+        if location not in allowed_location_list:
             location = 'best'
 
         handles, labels = self.axes.get_legend_handles_labels()
-        self.axes.legend(handles, labels, loc=location)
+        self.axes.legend(handles, labels, loc=location, fontsize=font_size)
+
+        self._isLegendOn = True
 
         return
 
@@ -1315,21 +1710,46 @@ class MyNavigationToolbar(NavigationToolbar2):
     NAVIGATION_MODE_PAN = 1
     NAVIGATION_MODE_ZOOM = 2
 
+    # This defines a signal called 'home_button_pressed' that takes 1 boolean
+    # argument for being in zoomed state or not
+    home_button_pressed = pyqtSignal()
+
+    # This defines a signal called 'canvas_zoom_released'
+    canvas_zoom_released = pyqtSignal()
+
     def __init__(self, parent, canvas):
         """ Initialization
+        built-in methods
+        - drag_zoom(self, event): triggered during holding the mouse and moving
         """
         NavigationToolbar2.__init__(self, canvas, canvas)
 
+        # parent
         self._myParent = parent
-        self._navigationMode = MyNavigationToolbar.NAVIGATION_MODE_NONE
+        # tool bar mode
+        self._myMode = MyNavigationToolbar.NAVIGATION_MODE_NONE
+
+        # connect the events to parent
+        self.home_button_pressed.connect(self._myParent.evt_toolbar_home)
+        self.canvas_zoom_released.connect(self._myParent.evt_zoom_released)
 
         return
 
+    @property
+    def is_zoom_mode(self):
+        """
+        check whether the tool bar is in zoom mode
+        Returns
+        -------
+
+        """
+        return self._myMode == MyNavigationToolbar.NAVIGATION_MODE_ZOOM
+
     def get_mode(self):
         """
         :return: integer as none/pan/zoom mode
         """
-        return self._navigationMode
+        return self._myMode
 
     # Overriding base's methods
     def draw(self):
@@ -1343,6 +1763,25 @@ class MyNavigationToolbar(NavigationToolbar2):
 
         return
 
+    def home(self, *args):
+        """
+
+        Parameters
+        ----------
+        args
+
+        Returns
+        -------
+
+        """
+        # call super's home() method
+        NavigationToolbar2.home(self, args)
+
+        # send a signal to parent class for further operation
+        self.home_button_pressed.emit()
+
+        return
+
     def pan(self, *args):
         """
 
@@ -1351,12 +1790,14 @@ class MyNavigationToolbar(NavigationToolbar2):
         """
         NavigationToolbar2.pan(self, args)
 
-        if self._navigationMode == MyNavigationToolbar.NAVIGATION_MODE_PAN:
+        if self._myMode == MyNavigationToolbar.NAVIGATION_MODE_PAN:
             # out of pan mode
-            self._navigationMode = MyNavigationToolbar.NAVIGATION_MODE_NONE
+            self._myMode = MyNavigationToolbar.NAVIGATION_MODE_NONE
         else:
             # into pan mode
-            self._navigationMode = MyNavigationToolbar.NAVIGATION_MODE_PAN
+            self._myMode = MyNavigationToolbar.NAVIGATION_MODE_PAN
+
+        print 'PANNED'
 
         return
 
@@ -1368,12 +1809,29 @@ class MyNavigationToolbar(NavigationToolbar2):
         """
         NavigationToolbar2.zoom(self, args)
 
-        if self._navigationMode == MyNavigationToolbar.NAVIGATION_MODE_ZOOM:
+        if self._myMode == MyNavigationToolbar.NAVIGATION_MODE_ZOOM:
             # out of zoom mode
-            self._navigationMode = MyNavigationToolbar.NAVIGATION_MODE_NONE
+            self._myMode = MyNavigationToolbar.NAVIGATION_MODE_NONE
         else:
             # into zoom mode
-            self._navigationMode = MyNavigationToolbar.NAVIGATION_MODE_ZOOM
+            self._myMode = MyNavigationToolbar.NAVIGATION_MODE_ZOOM
+
+        return
+
+    def release_zoom(self, event):
+        """
+        override zoom released method
+        Parameters
+        ----------
+        event
+
+        Returns
+        -------
+
+        """
+        self.canvas_zoom_released.emit()
+
+        NavigationToolbar2.release_zoom(self, event)
 
         return
 
diff --git a/scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py b/scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py
index 7bc322f9e753afe495ab9c611587a7018b788509..5fd1e648ba1c729c9026be73b734131da09c6a5a 100644
--- a/scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py
+++ b/scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py
@@ -1,9 +1,9 @@
 #pylint: disable=W0403,R0913,R0902
-
 from PyQt4 import QtCore
 from PyQt4.QtCore import QThread
 
 import reduce4circleControl as r4c
+import peak_integration_utility
 
 
 class AddPeaksThread(QThread):
@@ -115,7 +115,7 @@ class IntegratePeaksThread(QThread):
     mergeMsgSignal = QtCore.pyqtSignal(int, int, int, str)
 
     def __init__(self, main_window, exp_number, scan_tuple_list, mask_det, mask_name, norm_type, num_pt_bg_left,
-                 num_pt_bg_right):
+                 num_pt_bg_right, scale_factor=1.000):
         """
 
         :param main_window:
@@ -140,8 +140,12 @@ class IntegratePeaksThread(QThread):
         assert isinstance(mask_name, str), 'Name of mask must be a string but not %s.' % str(type(mask_name))
         assert isinstance(norm_type, str), 'Normalization type must be a string but not %s.' \
                                            '' % str(type(norm_type))
-        assert isinstance(num_pt_bg_left, int) and num_pt_bg_left >= 0
-        assert isinstance(num_pt_bg_right, int) and num_pt_bg_right >= 0
+        assert isinstance(num_pt_bg_left, int) and num_pt_bg_left >= 0,\
+            'Number of Pt at left for background {0} must be non-negative integers but not of type {1}.' \
+            ''.format(num_pt_bg_left, type(num_pt_bg_left))
+        assert isinstance(num_pt_bg_right, int) and num_pt_bg_right >= 0,\
+            'Number of Pt at right for background {0} must be non-negative integers but not of type {1}.' \
+            ''.format(num_pt_bg_right, type(num_pt_bg_right))
 
         # set values
         self._mainWindow = main_window
@@ -152,6 +156,7 @@ class IntegratePeaksThread(QThread):
         self._selectedMaskName = mask_name
         self._numBgPtLeft = num_pt_bg_left
         self._numBgPtRight = num_pt_bg_right
+        self._scaleFactor = scale_factor
 
         # link signals
         self.peakMergeSignal.connect(self._mainWindow.update_merge_value)
@@ -238,8 +243,9 @@ class IntegratePeaksThread(QThread):
             # check given mask workspace
             if self._maskDetector:
                 self._mainWindow.controller.check_generate_mask_workspace(self._expNumber, scan_number,
-                                                                          self._selectedMaskName)
+                                                                          self._selectedMaskName, check_throw=True)
 
+            bkgd_pt_list = (self._numBgPtLeft, self._numBgPtRight)
             # integrate peak
             try:
                 status, ret_obj = self._mainWindow.controller.integrate_scan_peaks(exp=self._expNumber,
@@ -249,33 +255,39 @@ class IntegratePeaksThread(QThread):
                                                                                    merge_peaks=False,
                                                                                    use_mask=self._maskDetector,
                                                                                    normalization=self._normalizeType,
-                                                                                   mask_ws_name=self._selectedMaskName)
+                                                                                   mask_ws_name=self._selectedMaskName,
+                                                                                   scale_factor=self._scaleFactor,
+                                                                                   background_pt_tuple=bkgd_pt_list)
             except ValueError as val_err:
                 status = False
                 ret_obj = 'Unable to integrate scan {0} due to {1}.'.format(scan_number, str(val_err))
+            except RuntimeError as run_err:
+                status = False
+                ret_obj = 'Unable to integrate scan {0}: {1}.'.format(scan_number, run_err)
 
             # handle integration error
             if status:
                 # get PT dict
                 pt_dict = ret_obj
+                assert isinstance(pt_dict, dict), 'dictionary must'
+                self.set_integrated_peak_info(scan_number, pt_dict)
+                # information setup include
+                # - lorentz correction factor
+                # - peak integration dictionary
+                # - motor information: peak_info_obj.set_motor(motor_name, motor_step, motor_std_dev)
             else:
                 # integration failed
                 error_msg = str(ret_obj)
                 self.mergeMsgSignal.emit(self._expNumber, scan_number, 0, error_msg)
                 continue
 
-            # calculate background value
-            background_pt_list = pt_number_list[:self._numBgPtLeft] + pt_number_list[-self._numBgPtRight:]
-            avg_bg_value = self._mainWindow.controller.estimate_background(pt_dict, background_pt_list)
-
-            # correct intensity by background value
-            intensity_i = self._mainWindow.controller.simple_integrate_peak(pt_dict, avg_bg_value)
+            intensity1 = pt_dict['simple intensity']
             peak_centre = self._mainWindow.controller.get_peak_info(self._expNumber, scan_number).get_peak_centre()
 
             # emit signal to main app for peak intensity value
             mode = 1
             # center_i
-            self.peakMergeSignal.emit(self._expNumber, scan_number, float(intensity_i), list(peak_centre), mode)
+            self.peakMergeSignal.emit(self._expNumber, scan_number, float(intensity1), list(peak_centre), mode)
         # END-FOR
 
         # terminate the process
@@ -284,3 +296,43 @@ class IntegratePeaksThread(QThread):
         # self._mainWindow.ui.tableWidget_mergeScans.select_all_rows(False)
 
         return
+
+    def set_integrated_peak_info(self, scan_number, peak_integration_dict):
+        """
+        set the integrated peak information including
+        * calculate Lorentz correction
+        * add the integration result dictionary
+        * add motor step information
+        :return:
+        """
+        # print '[DB...BAT] Set Integrated Peak Info is called for exp {0} scan {1}.' \
+        #       ''.format(self._expNumber, scan_number)
+
+        # get peak information
+        peak_info_obj = self._mainWindow.controller.get_peak_info(self._expNumber, scan_number)
+
+        # get Q-vector of the peak center and calculate |Q| from it
+        peak_center_q = peak_info_obj.get_peak_centre_v3d().norm()
+        # get wave length
+        wavelength = self._mainWindow.controller.get_wave_length(self._expNumber, [scan_number])
+
+        # get motor step (choose from omega, phi and chi)
+        try:
+            motor_move_tup = self._mainWindow.controller.get_motor_step(self._expNumber, scan_number)
+            motor_name, motor_step, motor_std_dev = motor_move_tup
+        except RuntimeError as run_err:
+            return str(run_err)
+        except AssertionError as ass_err:
+            return str(ass_err)
+
+        # calculate lorentz correction
+        lorentz_factor = peak_integration_utility.calculate_lorentz_correction_factor(peak_center_q, wavelength,
+                                                                                      motor_step)
+
+        peak_info_obj.lorentz_correction_factor = lorentz_factor
+        # set motor
+        peak_info_obj.set_motor(motor_name, motor_step, motor_std_dev)
+        # set peak integration dictionary
+        peak_info_obj.set_integration(peak_integration_dict)
+
+        return
diff --git a/scripts/HFIR_4Circle_Reduction/peak_integration_info.ui b/scripts/HFIR_4Circle_Reduction/peak_integration_info.ui
new file mode 100644
index 0000000000000000000000000000000000000000..45065d1f824ff19a1644405d5e1c280fadc4933a
--- /dev/null
+++ b/scripts/HFIR_4Circle_Reduction/peak_integration_info.ui
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1073</width>
+    <height>785</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QTableWidget" name="tableWidget"/>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="pushButton">
+       <property name="text">
+        <string>Hide</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/scripts/HFIR_4Circle_Reduction/peak_integration_utility.py b/scripts/HFIR_4Circle_Reduction/peak_integration_utility.py
new file mode 100644
index 0000000000000000000000000000000000000000..ef5464087af3f60d518061adb381bbdb609df17d
--- /dev/null
+++ b/scripts/HFIR_4Circle_Reduction/peak_integration_utility.py
@@ -0,0 +1,772 @@
+# Utility methods to do peak integration
+import numpy
+import math
+from scipy.optimize import curve_fit
+import mantid.simpleapi as mantidsimple
+from mantid.api import AnalysisDataService
+
+
+def apply_lorentz_correction(peak_intensity, q, wavelength, step_omega):
+    """ Apply lorentz correction to intensity """
+    # calculate theta
+    sin_theta = q * wavelength / (4 * numpy.pi)
+    theta = math.asin(sin_theta)
+    corrected_intensity = peak_intensity * numpy.sin(2 * theta) * step_omega
+
+    return corrected_intensity
+
+
+def calculate_lorentz_correction_factor(q_sample, wavelength, motor_step):
+    """
+
+    :param q_sample:
+    :param wavelength:
+    :param motor_step:
+    :return:
+    """
+    sin_theta = q_sample * wavelength / (4 * numpy.pi)
+    theta = math.asin(sin_theta)
+    factor = numpy.sin(2 * theta) * motor_step
+
+    # print '[DB...BAT Lorentz] Q-sample = {0}, wavelength = {1}, motor step = {2}, theta = {3} --> factor = {4}.' \
+    #       ''.format(q_sample, wavelength, motor_step, theta, factor)
+
+    return factor
+
+
+def calculate_motor_step(motor_pos_array, motor_step_tolerance=0.5):
+    """
+    calculate the motor steps
+    :param motor_step_tolerance:
+    :param motor_pos_array:
+    :return:
+    """
+    assert isinstance(motor_pos_array, numpy.ndarray), 'Motor positions {0} must be given as a numpy array but not ' \
+                                                       'a {1}.'.format(motor_pos_array, type(motor_pos_array))
+    # need to check somewhere: assert len(pt_motor_dict) == len(pt_intensity_dict), 'blabla 3'
+
+    motor_step_vector = motor_pos_array[1:] - motor_pos_array[:-1]
+
+    motor_step = numpy.average(motor_step_vector)
+    motor_step_std = motor_step_vector.std()
+
+    if motor_step_std > motor_step_tolerance:
+        raise RuntimeError('Step deviation too large. Cannot use average!')
+
+    return motor_step
+
+
+def convert_motor_pos_intensity(integrated_pt_dict, motor_pos_dict):
+    """
+    :except: raise RuntimeError if
+    :param integrated_pt_dict:
+    :param motor_pos_dict:
+    :return: motor_pos_vec, pt_intensity_vec
+    """
+    pt_list = sorted(integrated_pt_dict.keys())
+
+    if len(motor_pos_dict) != len(pt_list):
+        raise RuntimeError('Integrated Pt intensities does not match motor positions')
+
+    pt_intensity_vec = numpy.ndarray(shape=(len(pt_list), ), dtype='float')
+    motor_pos_vec = numpy.ndarray(shape=(len(pt_list), ), dtype='float')
+
+    for i_pt, pt in enumerate(pt_list):
+        pt_intensity_vec[i_pt] = integrated_pt_dict[pt]
+        motor_pos_vec[i_pt] = motor_pos_dict[pt]
+
+    return motor_pos_vec, pt_intensity_vec
+
+
+def calculate_penalty(model_vec_y, exp_vec_y):
+    """
+    calculate the penalty/cost of the model to experimental data
+    say: error = 1/(N-1)sqrt(\sum(y_i - m_i)**2)
+    :param model_vec_y:
+    :param exp_vec_y:
+    :return:
+    """
+    # check inputs
+    assert isinstance(model_vec_y, numpy.ndarray), 'Model vec Y cannot be {0}.' \
+                                                   ''.format(type(model_vec_y))
+    assert isinstance(exp_vec_y, numpy.ndarray), 'Experimental vec Y cannot be {0}.' \
+                                                 ''.format(type(exp_vec_y))
+    if model_vec_y.shape != exp_vec_y.shape or len(model_vec_y) <= 1:
+        raise RuntimeError('Model and experimental data array do not match! Or too short!')
+
+    # calculate
+    diff_y = model_vec_y - exp_vec_y
+
+    diff_y2 = numpy.ndarray(shape=(len(diff_y),), dtype='float')
+    numpy.power(diff_y, 2, out=diff_y2)
+
+    cost = numpy.sqrt(diff_y2.sum()) / (len(model_vec_y) - 1.)
+
+    return cost
+
+
+def estimate_background(pt_intensity_dict, bg_pt_list):
+    """
+    Estimate background value by average the integrated counts of some Pt.
+    :param pt_intensity_dict:
+    :param bg_pt_list: Pt. for the first N and last M Pt.
+    :return:
+    """
+    # Check
+    assert isinstance(pt_intensity_dict, dict), 'Peak (Pt) intensities {0} must be given by dictionary but not {1}.' \
+                                                ''.format(pt_intensity_dict, type(pt_intensity_dict))
+    assert (isinstance(bg_pt_list, tuple) or isinstance(bg_pt_list, list)) and len(bg_pt_list) > 0,\
+        'background points {0} must be a 2-element tuple or list but not a {1}.'.format(bg_pt_list, type(bg_pt_list))
+
+    # from bg_pt_list
+    bg_sum = 0.
+    background_points = list()
+    pt_list = sorted(pt_intensity_dict.keys())
+    left_bgs = pt_list[0:bg_pt_list[0]]
+    background_points.extend(left_bgs)
+    right_bgs = pt_list[-bg_pt_list[1]:]
+    background_points.extend(right_bgs)
+
+    for bg_pt in background_points:
+        assert bg_pt in pt_intensity_dict, 'Pt. %d is not calculated.' % bg_pt
+        bg_sum += pt_intensity_dict[bg_pt]
+
+    avg_bg = float(bg_sum) / len(bg_pt_list)
+
+    return avg_bg
+
+
+def find_gaussian_start_values_by_observation(vec_x, vec_y):
+    """
+    find out the starting values of a gaussian + linear background with observation
+    :param vec_x:
+    :param vec_y:
+    :return: must be the same order as gaussian linear background function as x0, sigma, a, b
+    """
+    # assume that it is a quasi-ideal Gaussian
+    # find out the maximum Y with x
+    max_y_index = vec_y.argmax()
+
+    x0 = vec_x[max_y_index]
+    max_y = vec_y[max_y_index]
+    est_background = 0.5 * (vec_y[0] + vec_y[-1])
+    est_sigma = (vec_x[-1] - vec_x[0]) * 0.1
+    est_a = max(1.0, max_y - est_background)
+
+    return [x0, est_sigma, est_a, est_background]
+
+
+def fit_gaussian_linear_background(vec_x, vec_y, vec_e, start_value_list=None, find_start_value_by_fit=False):
+    """
+    Fit a curve with Gaussian + linear background
+    The starting value can be
+    1. specified by caller
+    2. guessed by fitting a pure gaussian to the data
+    3. guessed by observing the data
+    :param vec_x:
+    :param vec_y:
+    :param vec_e:
+    :param start_value_list: if not None, then it must have 4 elements:  x0, sigma, A, and b (for background)
+    :param find_start_value_by_fit: if it is True, then fit the curve with a Gaussian without background
+    :return: 3-tuple (1) float as error, (2) list/tuple as x0, sigma, a, b , (3) 4 x 4 covariance matrix
+    """
+    # check input
+    assert isinstance(vec_x, numpy.ndarray), 'Input vec_x must be a numpy.ndarray but not a {0}.'.format(vec_x)
+    assert isinstance(vec_y, numpy.ndarray), 'Input vec_y must be a numpy.ndarray but not a {0}.'.format(vec_y)
+    assert isinstance(vec_e, numpy.ndarray), 'Input vec_e must be a numpy.ndarray but not a {0}.'.format(vec_e)
+
+    # print '[DB] Vec X: ', vec_x
+    # print '[DB] Vec Y: ', vec_y
+    # print '[DB] Vec e: ', vec_e
+    # print '[DB] Start values: ', start_value_list
+    # print '[DB] Find start value by fit: ', find_start_value_by_fit
+
+    # starting value
+    if isinstance(start_value_list, list):
+        assert len(start_value_list) == 4, 'If specified, there must be 4 values: a, x0, sigma and b but not {0}.' \
+                                           ''.format(start_value_list)
+    elif find_start_value_by_fit:
+        # find out the starting value by fit a Gaussian without background
+        fit1_coeff, fit1_cov_matrix = curve_fit(gaussian, vec_x, vec_y)
+        start_x0, start_sigma, start_a = fit1_coeff
+        # get result
+        start_value_list = [start_x0, start_sigma, start_a, 0.0]
+
+        # print '[DB] Start value by fit: ', start_value_list
+
+    else:
+        # guess starting value via observation
+        start_value_list = find_gaussian_start_values_by_observation(vec_x, vec_y)
+
+        # print '[DB] Start value by observation: ', start_value_list
+    # END-IF-ELSE
+
+    """
+    [DB] Start values:  None
+    [DB] Find start value by fit:  False
+    [DB] Start value by observation:  [21, 19.0, 10.5, 100.0]: should be
+    """
+
+    # do second round fit
+    assert isinstance(start_value_list, list) and len(start_value_list) == 4, 'Starting value list must have 4 elements'
+    fit2_coeff, fit2_cov_matrix = curve_fit(gaussian_linear_background, vec_x, vec_y,  sigma=vec_e, p0=start_value_list)
+    # take sigma=vec_e,  out as it increases unstable
+
+    # calculate the model
+    x0, sigma, a, b = fit2_coeff
+    model_vec_y = gaussian_linear_background(vec_x, x0, sigma, a, b)
+
+    print 'Covariance matrix: ', fit2_cov_matrix
+
+    cost = calculate_penalty(model_vec_y, vec_y)
+
+    return cost, fit2_coeff, fit2_cov_matrix
+
+
+def fit_motor_intensity_model(motor_pos_dict, integrated_pt_dict):
+    """
+    construct a data as motor position vs counts, and do the fit with Gaussian + flat background
+    :param motor_pos_dict:
+    :param integrated_pt_dict:
+    :return: 3-tuple: dictionary for fitted parameter, dictionary for fitting error, covariance matrix
+    """
+    # check inputs
+    assert isinstance(motor_pos_dict, dict), 'Input motor position {0} must be a dictionary but not a {1}.' \
+                                             ''.format(motor_pos_dict, type(motor_pos_dict))
+    assert isinstance(integrated_pt_dict, dict), 'Input integrated Pt. intensity {0} must be a dictionary but not a ' \
+                                                 '{1}.'.format(integrated_pt_dict, type(integrated_pt_dict))
+
+    # construct the data
+    list_motor_pos = list()
+    list_intensity = list()
+
+    pt_list = motor_pos_dict.keys()
+    pt_list.sort()
+
+    for pt in pt_list:
+        if pt not in integrated_pt_dict:
+            raise RuntimeError('Pt. {0} does not exist in integrated intensity dictionary {1}'
+                               ''.format(pt, integrated_pt_dict))
+        list_motor_pos.append(motor_pos_dict[pt])
+        list_intensity.append(integrated_pt_dict[pt])
+    # END-FOR
+
+    vec_x = numpy.array(list_motor_pos)
+    vec_y = numpy.array(list_intensity)
+    # try to avoid negative Y value
+    vec_e = numpy.ndarray(shape=(len(vec_x),), dtype='float')
+    for index in range(len(vec_y)):
+        if vec_y[index] > 1.:
+            vec_e[index] = numpy.sqrt(vec_y[index])
+        else:
+            vec_e[index] = 1.
+    # END-FOR
+
+    # fit
+    gauss_error, gauss_parameters, cov_matrix = fit_gaussian_linear_background(vec_x, vec_y, vec_e)
+    # print '[DB] Overall Gaussian error = ', gauss_error
+    # print '[DB] Gaussian fitted parameters = ', gauss_parameters
+    # print '[DB] Gaussian covariance matrix = ', cov_matrix
+
+    # function parameters (in order): x0, sigma, a, b
+    # construct parameter dictionary and error dictionary
+    gauss_parameter_dict = dict()
+    gauss_error_dict = dict()
+
+    gauss_parameter_dict['x0'] = gauss_parameters[0]
+    gauss_parameter_dict['s'] = gauss_parameters[1]
+    gauss_parameter_dict['A'] = gauss_parameters[2]
+    gauss_parameter_dict['B'] = gauss_parameters[3]
+
+    if str(cov_matrix).count('inf') > 0:
+        # gaussian fit fails
+        cov_matrix = None
+    else:
+        # good
+        assert isinstance(cov_matrix, numpy.ndarray), 'Covarance matrix must be a numpy array'
+        gauss_error_dict['x02'] = cov_matrix[0, 0]
+        gauss_error_dict['s2'] = cov_matrix[1, 1]
+        gauss_error_dict['A2'] = cov_matrix[2, 2]
+        gauss_error_dict['B2'] = cov_matrix[3, 3]
+        gauss_error_dict['s_A'] = cov_matrix[1, 2]
+        gauss_error_dict['A_s'] = cov_matrix[2, 1]
+
+    return gauss_parameter_dict, gauss_error_dict, cov_matrix
+
+
+def get_motor_step_for_intensity(motor_pos_dict):
+    """
+    get the motor step for each measurement Pts.
+    if it is the first or last Pt. then use the difference between this Pt and its nearest Pts as motor step
+    else use 1/2 as the motor step to its previous one and 1/2 as the motor step to its following one.
+    :param motor_pos_dict:
+    :return: dictionary of motor steps for calculating intensity
+    """
+    # check
+    assert isinstance(motor_pos_dict, dict), 'Input motor position must in dictionary.'
+
+    # get Pt list
+    pt_list = motor_pos_dict.keys()
+    pt_list.sort()
+    if len(pt_list) < 2:
+        raise RuntimeError('Motor position dictionary has too few Pt (FYI: Motor positions: {0}'
+                           ''.format(motor_pos_dict))
+
+    # get step dictionary
+    motor_step_dict = dict()
+
+    for i_pt in range(len(pt_list)):
+        if i_pt == 0:
+            # first motor position
+            motor_step = motor_pos_dict[pt_list[1]] - motor_pos_dict[pt_list[0]]
+        elif i_pt == len(pt_list) - 1:
+            # last motor position
+            motor_step = motor_pos_dict[pt_list[-1]] - motor_pos_dict[pt_list[-2]]
+        else:
+            # regular
+            motor_step = 0.5 * (motor_pos_dict[pt_list[i_pt+1]] - motor_pos_dict[pt_list[i_pt-1]])
+        pt = pt_list[i_pt]
+        motor_step_dict[pt] = motor_step
+
+    return motor_step_dict
+
+
+def get_moving_motor_information(spice_table_name):
+    """
+
+    :param spice_table_name:
+    :return:
+    """
+    table = AnalysisDataService.retrieve(spice_table_name)
+
+    col_names = table.getColumnNames()
+    pt_index = col_names.index('Pt.')
+    omega_index = col_names.index('omega')
+    chi_index = col_names.index('chi')
+    phi_index = col_names.index('phi')
+
+    col_tup_dict = {'omega': omega_index, 'phi': phi_index, 'chi': chi_index}
+
+    std_list = list()
+    motor_vector_dict = dict()
+    for motor in col_tup_dict:
+        motor_index = col_tup_dict[motor]
+        motor_vector = numpy.array(table.column(motor_index))
+        motor_vector_dict[motor] = motor_vector
+        std_list.append((motor_vector.std(), motor))
+    std_list.sort()
+    moving_motor = std_list[-1][1]
+    pt_list = table.column(pt_index)
+
+    motor_pos_dict = dict()
+    for i_m in range(len(pt_list)):
+        motor_pos_dict[pt_list[i_m]] = motor_vector_dict[moving_motor][i_m]
+
+    return moving_motor, motor_pos_dict
+
+
+def gaussian_linear_background(x, x0, sigma, a, b):
+    """
+    Gaussian + linear background: y = a * exp( -(x-x0)**2/2*sigma**2 ) + b
+    :param x:
+    :param x0:
+    :param sigma:
+    :param a: maximum value
+    :param b: linear background
+    :return:
+    """
+    # gaussian + linear background
+
+    # print '[DB] Input x0 = ', x0, ', sigma = ', sigma, ', a = ', a, ', b = ', b
+    return a * numpy.exp(-(x - x0) ** 2 / (2. * sigma ** 2)) + b
+
+
+def gaussian(x, a, b, c):
+    # pure gaussian
+    return c*numpy.exp(-(x-a)**2/(2. * b * b))
+
+
+def gaussian_peak_intensity(parameter_dict, error_dict):
+    """
+    calculate peak intensity as a Gaussian
+    the equation to calculate Gaussian from -infinity to +infinity is
+    I = A\times s\times\sqrt{2\pi}
+    :param parameter_dict:
+    :param error_dict:
+    :return:
+    """
+    # check input
+    assert isinstance(parameter_dict, dict), 'Parameters {0} must be given as a dictionary but not a {1}.' \
+                                             ''.format(parameter_dict, type(parameter_dict))
+    assert isinstance(error_dict, dict), 'Errors {0} must be given as a dictionary but not a {1}.' \
+                                         ''.format(error_dict, type(error_dict))
+
+    # get the parameters from the dictionary
+    try:
+        gauss_a = parameter_dict['A']
+        gauss_sigma = parameter_dict['s']
+    except KeyError as key_err:
+        raise RuntimeError('Parameter dictionary must have "A", "s" (for sigma) but now only {0}. Error message: {1}'
+                           ''.format(parameter_dict.keys(), key_err))
+
+    # I = A\times s\times\sqrt{2 pi}
+    peak_intensity = gauss_a * gauss_sigma * numpy.sqrt(2. * numpy.pi)
+    # print '[DB] Gaussian Peak Intensity: A * S * sqrt(2 Pi) == ', gauss_a, gauss_sigma, ' --> peak intensity = ', peak_intensity
+
+    # calculate error
+    # \sigma_I^2 = 2\pi (A^2\cdot \sigma_s^2 + \sigma_A^2\cdot s^2 + 2\cdot A\cdot s\cdot \sigma_{As})
+    try:
+        error_a_sq = error_dict['A2']
+        error_s_sq = error_dict['s2']
+        error_a_s = error_dict['A_s']
+    except KeyError as key_err:
+        raise RuntimeError('Error dictionary must have "A2", "s2", "A_s" but not only found {0}. FYI: {1}'
+                           ''.format(error_dict.keys(), key_err))
+    intensity_error = numpy.sqrt(2/numpy.pi * (gauss_a**2 * error_s_sq + error_a_sq * gauss_sigma**2 +
+                                               2 * gauss_a * gauss_sigma * error_a_s))
+
+    return peak_intensity, intensity_error
+
+
+def calculate_peak_intensity_gauss(gauss_a, gauss_sigma, error_a_sq=None, error_sigma_sq=None,
+                                   error_a_sigma=None):
+    """
+    calculate the peak intensity, which is the area under the peak
+    if sigma == 1, then the integral is sqrt(pi);
+    then the value is sqrt(pi) * e^{-1/(2.*sigma**2)}
+    :param gauss_a:
+    :param gauss_sigma:
+    :param error_a_sq: error(a)**2
+    :param error_sigma_sq: error(sigma)**2
+    :param error_a_sigma: correlated error for a and sigma
+    :return:
+    """
+    integral = numpy.sqrt(2. * numpy.pi) * gauss_a * gauss_sigma
+
+    if error_a_sq is not None:
+        # calculate integral intensity error by propagation
+        # check
+        assert isinstance(error_a_sq, float), 'Error(a)**2 must be a float but not a {0}.'.format(type(error_a_sq))
+        assert isinstance(error_sigma_sq, float), 'Error(sigma)**2 must be a float but not a {0}.' \
+                                                  ''.format(type(error_sigma_sq))
+        assert isinstance(error_a_sigma, float), 'Error(a,sigma) must be a float but not a {0}.' \
+                                                 ''.format(type(error_a_sigma))
+        # calculate
+        error2 = gauss_a**2 * error_sigma_sq + error_a_sq * gauss_sigma**2 + 2. * gauss_a * gauss_sigma * error_a_sigma
+        error = numpy.sqrt(error2)
+    else:
+        error = numpy.sqrt(integral)
+
+    return integral, error
+
+
+def get_finer_grid(vec_x, factor):
+    """
+    insert values to a vector (grid) to make it finer
+    :param vec_x:
+    :param factor:
+    :return:
+    """
+    assert isinstance(factor, int), 'Insertion factor {0} must be an integer but not a {1}'.format(factor, type(factor))
+
+    orig_size = len(vec_x)
+    new_list = list()
+    for i in range(orig_size-1):
+        d_x = vec_x[i+1] - vec_x[i]
+        for j in range(factor):
+            temp_x = vec_x[i] + d_x * float(j) / float(factor)
+            new_list.append(temp_x)
+        # END-FOR
+    # END-FOR
+
+    # don't forget the last
+    new_list.append(vec_x[-1])
+
+    new_vector = numpy.array(new_list)
+
+    return new_vector
+
+
+def integrate_single_scan_peak(merged_scan_workspace_name, integrated_peak_ws_name,
+                               peak_radius, peak_centre,
+                               merge_peaks=True,
+                               normalization='', mask_ws_name=None,
+                               scale_factor=1):
+
+    """ Integrate the peak in a single scan with merged Pt.
+    :param merged_scan_workspace_name: MDEventWorkspace with merged Pts.
+    :param integrated_peak_ws_name: output PeaksWorkspace for integrated peak
+    :param peak_radius:
+    :param peak_centre:  a float radius or None for not using
+    :param merge_peaks: If selected, merged all the Pts can return 1 integrated peak's value;
+                        otherwise, integrate peak for each Pt.
+    :param normalization: normalization set up (by time or ...)
+    :param mask_ws_name: mask workspace name or None
+    :param scale_factor: integrated peaks' scaling factor
+    :return: dictionary of Pts.
+    """
+    # check
+    # assert isinstance(exp, int)
+    # assert isinstance(scan, int)
+    assert isinstance(peak_radius, float) or peak_radius is None, 'Peak radius {0} must be of type float but not ' \
+                                                                  '{1}.'.format(peak_radius, type(peak_radius))
+    assert len(peak_centre) == 3, 'Peak center {0} of type {1} must have 3 elements but not {2}.' \
+                                  ''.format(peak_centre, type(peak_centre), len(peak_centre))
+    assert isinstance(merge_peaks, bool), 'Flag to merge peak must be a boolean but not {0}.'.format(type(merge_peaks))
+
+    try:
+        peak_centre_str = '%f, %f, %f' % (peak_centre[0], peak_centre[1],
+                                          peak_centre[2])
+    except IndexError:
+        raise RuntimeError('Peak center {0} must have 3 elements.'.format(peak_centre))
+    except ValueError:
+        raise RuntimeError('Peak center {0} must have floats.'.format(peak_centre))
+
+    # normalization
+    norm_by_mon = False
+    norm_by_time = False
+    if normalization == 'time':
+        norm_by_time = True
+    elif normalization == 'monitor':
+        norm_by_mon = True
+
+    # integrate peak of a scan
+    mantidsimple.IntegratePeaksCWSD(InputWorkspace=merged_scan_workspace_name,
+                                    OutputWorkspace=integrated_peak_ws_name,
+                                    PeakRadius=peak_radius,
+                                    PeakCentre=peak_centre_str,
+                                    MergePeaks=merge_peaks,
+                                    NormalizeByMonitor=norm_by_mon,
+                                    NormalizeByTime=norm_by_time,
+                                    MaskWorkspace=mask_ws_name,
+                                    ScaleFactor=scale_factor)
+
+    # process the output workspace
+    pt_dict = dict()
+    out_peak_ws = AnalysisDataService.retrieve(integrated_peak_ws_name)
+    num_peaks = out_peak_ws.rowCount()
+
+    for i_peak in xrange(num_peaks):
+        peak_i = out_peak_ws.getPeak(i_peak)
+        run_number_i = peak_i.getRunNumber() % 1000
+        intensity_i = peak_i.getIntensity()
+        pt_dict[run_number_i] = intensity_i
+    # END-FOR
+
+    # # store the data into peak info
+    # if (exp, scan) not in self._myPeakInfoDict:
+    #     raise RuntimeError('Exp %d Scan %d is not recorded in PeakInfo-Dict' % (exp, scan))
+    # self._myPeakInfoDict[(exp, scan)].set_pt_intensity(pt_dict)
+
+    return True, pt_dict
+
+
+def integrate_peak_full_version(scan_md_ws_name, spice_table_name, output_peak_ws_name,
+                                peak_center, mask_workspace_name, norm_type,
+                                intensity_scale_factor, background_pt_tuple):
+    """
+    Integrate peak with the full version including
+    1. simple summation
+    2. simple summation with gaussian fit
+    3. integrate with fitted gaussian
+    :return: peak integration result in dictionary
+    """
+    def create_peak_integration_dict():
+        """
+        create a standard dictionary for recording peak integration result
+        keys are
+         - simple intensity
+         - simple error
+         - simple background
+         - intensity 2
+         - error 2
+         - gauss intensity
+         - gauss error
+         - gauss background
+         - gauss parameters
+         - motor positions: numpy array of motor positions
+         - pt intensities: numpy array of integrated intensities per Pt.
+        :return:
+        """
+        info_dict = {'simple intensity': 0.,
+                     'simple error': 0.,
+                     'simple background': 0.,
+                     'intensity 2': 0.,
+                     'error 2': 0.,
+                     'pt_range': '',
+                     'gauss intensity': 0.,
+                     'gauss error': 0.,
+                     'gauss background': 0.,
+                     'gauss parameters': None,
+                     'gauss errors': None,
+                     'motor positions': None,
+                     'pt intensities': None,
+                     'covariance matrix': None
+                     }
+
+        return info_dict
+    # END-DEF: create_peak_integration_dict()
+
+    # integrate the peak in MD workspace
+    try:
+        status, ret_obj = integrate_single_scan_peak(merged_scan_workspace_name=scan_md_ws_name,
+                                                     integrated_peak_ws_name=output_peak_ws_name,
+                                                     peak_radius=1.0,
+                                                     peak_centre=peak_center,
+                                                     merge_peaks=False,
+                                                     mask_ws_name=mask_workspace_name,
+                                                     normalization=norm_type,
+                                                     scale_factor=intensity_scale_factor)
+    except RuntimeError as run_err:
+        raise RuntimeError('Failed to integrate peak at {0} due to {1}'.format(scan_md_ws_name, run_err))
+    except Exception as run_err:
+        raise RuntimeError('Failed (2) to integrate peak at {0} due to {1}'.format(scan_md_ws_name, run_err))
+
+    # result due to error
+    if status is False:
+        error_message = ret_obj
+        raise RuntimeError('Unable to integrate peak of workspace {0} due to {1}.'
+                           ''.format(scan_md_ws_name, error_message))
+    else:
+        # process result
+        integrated_pt_dict = ret_obj
+        assert isinstance(integrated_pt_dict, dict), 'Returned masked Pt dict must be a dictionary'
+
+    # create output dictionary
+    peak_int_dict = create_peak_integration_dict()
+
+    # get moving motor information. candidates are 2theta, phi and chi
+    motor, motor_pos_dict = get_moving_motor_information(spice_table_name)
+
+    # check motor position dictionary and integrated per Pt. peak intensity
+    motor_pos_vec, pt_intensity_vec = convert_motor_pos_intensity(integrated_pt_dict, motor_pos_dict)
+    peak_int_dict['motor positions'] = motor_pos_vec
+    peak_int_dict['pt intensities'] = pt_intensity_vec
+    peak_int_dict['mask'] = mask_workspace_name
+
+    # get motor step per pt.
+    try:
+        motor_step_dict = get_motor_step_for_intensity(motor_pos_dict)
+    except RuntimeError as run_err:
+        raise RuntimeError('Unable to integrate workspace {0} due to {1}.'.format(scan_md_ws_name, run_err))
+
+    # calculate the intensity with background removed and correct intensity by background value
+    averaged_background = estimate_background(integrated_pt_dict, background_pt_tuple)
+    simple_intensity, simple_intensity_error, pt_range = simple_integrate_peak(integrated_pt_dict, averaged_background,
+                                                                               motor_step_dict)
+    peak_int_dict['simple background'] = averaged_background
+    peak_int_dict['simple intensity'] = simple_intensity
+    peak_int_dict['simple error'] = simple_intensity_error
+    peak_int_dict['simple background'] = averaged_background
+
+    # fit gaussian + flat background
+    parameters, errors, covariance_matrix = fit_motor_intensity_model(motor_pos_dict, integrated_pt_dict)
+    peak_int_dict['gauss parameters'] = parameters
+    peak_int_dict['gauss errors'] = errors
+    peak_int_dict['covariance matrix'] = covariance_matrix
+
+    if covariance_matrix is None or parameters['B'] < 0.:
+        # gaussian fit fails or output result is not correct
+        peak_int_dict['intensity 2'] = None
+        peak_int_dict['error 2'] = None
+
+        peak_int_dict['gauss intensity'] = None
+        peak_int_dict['gauss error'] = None
+
+    else:
+        # calculate intensity with method 2
+        motor_pos_center = parameters['x0']
+        motor_pos_sigma = parameters['s']
+        intensity_m2, error_m2, pt_range = simple_integrate_peak(integrated_pt_dict, parameters['B'],
+                                                                 motor_step_dict,
+                                                                 peak_center=motor_pos_center,
+                                                                 peak_sigma=motor_pos_sigma,
+                                                                 motor_pos_dict=motor_pos_dict,
+                                                                 sigma_range=2.)
+
+        peak_int_dict['intensity 2'] = intensity_m2
+        peak_int_dict['error 2'] = error_m2
+        peak_int_dict['pt_range'] = pt_range
+
+        # calculate gaussian (method 3)
+        intensity_gauss, intensity_gauss_error = gaussian_peak_intensity(parameters, errors)
+        peak_int_dict['gauss intensity'] = intensity_gauss
+        peak_int_dict['gauss error'] = intensity_gauss_error
+    # END-IF-ELSE
+
+    return peak_int_dict
+
+
+def simple_integrate_peak(pt_intensity_dict, bg_value, motor_step_dict, peak_center=None,
+                          peak_sigma=None, motor_pos_dict=None, sigma_range=2.):
+    """
+    A simple approach to integrate peak in a cuboid with background removed.
+    :param pt_intensity_dict:
+    :param bg_value:
+    :param motor_step_dict:
+    :param peak_center:
+    :param peak_sigma:
+    :param motor_pos_dict:
+    :param sigma_range:
+    :return:
+    """
+    # check
+    assert isinstance(pt_intensity_dict, dict), 'Pt. intensities {0} should be a dictionary but not a {1}.' \
+                                                ''.format(pt_intensity_dict, type(pt_intensity_dict))
+    assert isinstance(bg_value, float) and bg_value >= 0., 'Background value {0} must be a non-negative float.' \
+                                                           ''.format(bg_value)
+    assert isinstance(motor_step_dict, dict), 'Motor steps {0} must be given as a dictionary of Pt but not a {1}.' \
+                                              ''.format(motor_step_dict, type(motor_step_dict))
+
+    if peak_center is not None:
+        assert peak_sigma is not None and motor_pos_dict is not None and sigma_range is not None,\
+            'Must be specified'
+
+    pt_list = pt_intensity_dict.keys()
+    pt_list.sort()
+
+    # loop over Pt. to sum for peak's intensity
+    sum_intensity = 0.
+    error_2 = 0.
+    used_pt_list = list()
+
+    # raw intensity
+    sum_raw_int = 0.
+
+    motor_step = 0.
+    for pt in pt_list:
+        # check the motor position if required
+        if peak_center is not None:
+            motor_pos = motor_pos_dict[pt]
+            if abs(motor_pos - peak_center) > sigma_range * peak_sigma:
+                # peak is out of range
+                continue
+        # END-IF
+
+        intensity = pt_intensity_dict[pt]
+        motor_step_i = motor_step_dict[pt]
+        sum_intensity += (intensity - bg_value) * motor_step_i
+        motor_step = motor_step_i
+
+        if 0:
+            pass
+            # error_2 += numpy.sqrt(intensity) * motor_step_i
+        else:
+            sum_raw_int += intensity
+
+        used_pt_list.append(pt)
+
+        # print '[DB...BAT] Motor step size {0} = {1}'.format(pt, motor_step_i)
+    # END-FOR
+
+    # error = sqrt(sum I_i) * delta
+    error_2 = numpy.sqrt(sum_raw_int) * motor_step
+
+    # convert the Pt to list
+    if len(used_pt_list) > 0:
+        used_pt_list.sort()
+        pt_list_range = '{0} - {1}'.format(used_pt_list[0], used_pt_list[-1])
+    else:
+        pt_list_range = 'N/A'
+
+    return sum_intensity, error_2, pt_list_range
diff --git a/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py b/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py
index c35242b3627d25d1b0bb1eacd947b2ef477dda8a..a418d0158086db36f200cd9e31a9054a0c1c8743 100644
--- a/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py
+++ b/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py
@@ -1,5 +1,6 @@
 #pylint: disable=W0403,R0902
-import numpy
+import time
+import random
 from fourcircle_utility import *
 from mantid.api import AnalysisDataService
 from mantid.kernel import V3D
@@ -26,7 +27,6 @@ class PeakProcessRecord(object):
                                                             'exist.' % peak_ws_name
 
         # set
-        self._isCurrentUserHKL = True
         self._myExpNumber = exp_number
         self._myScanNumber = scan_number
         self._myPeakWorkspaceName = peak_ws_name
@@ -36,20 +36,38 @@ class PeakProcessRecord(object):
 
         # Define class variable
         # HKL list
-        self._userHKL = None    # user specified HKL
+        self._calculatedHKL = None    # user specified HKL
         self._spiceHKL = None                        # spice HKL
         self._prevHKL = numpy.array([0., 0., 0.])    # previous HKL
 
+        # magnetic peak set up
+        self._kShiftVector = [0, 0, 0]
+        self._absorptionCorrection = 1.
+
+        # peak center and PeaksWorkspace
         self._avgPeakCenter = None
         self._myPeakWSKey = (None, None, None)
         self._myPeakIndex = None
-        self._ptIntensityDict = None
 
         self._myLastPeakUB = None
 
-        self._myIntensity = 0.
-        self._mySigma = 0.
+        self._myIntensity = None
+        self._gaussIntensity = 0.
+        self._gaussStdDev = 0.
+        self._lorenzFactor = None
+
+        # peak integration result
+        self._integrationDict = None
+        self._ptIntensityDict = None
+
+        # some motor/goniometer information for further correction
+        self._movingMotorTuple = None
+
+        # Figure print
+        self._fingerPrint = '{0:.7f}.{1}'.format(time.time(), random.randint(0, 10000000))
 
+        # print '[DB...BAT] Create PeakProcessRecord for Exp {0} Scan {1} ({2} | {3}).' \
+        #       ''.format(self._myExpNumber, self._myScanNumber, self._fingerPrint, hex(id(self)))
         return
 
     def calculate_peak_center(self, allow_bad_monitor=True):
@@ -115,6 +133,112 @@ class PeakProcessRecord(object):
 
         return
 
+    def generate_integration_report(self):
+        """
+        generate a dictionary for this PeakInfo
+        :return:
+        """
+        # print '[DB...BAT] PeakInfo (Scan: {0}, ID: {1}) generate report.  Spice HKL: {2}' \
+        #       ''.format(self._myScanNumber, hex(id(self)), self._spiceHKL)
+
+        report = dict()
+
+        if self._spiceHKL is not None:
+            report['SPICE HKL'] = str_format(self._spiceHKL)
+        else:
+            report['SPICE HKL'] = ''
+        if self._calculatedHKL is not None:
+            report['Mantid HKL'] = str_format(self._calculatedHKL)
+        else:
+            report['Mantid HKL'] = None
+        if self._integrationDict:
+            report['Mask'] = self._integrationDict['mask']
+            report['Raw Intensity'] = self._integrationDict['simple intensity']
+            report['Raw Intensity Error'] = self._integrationDict['simple error']
+            report['Intensity 2'] = self._integrationDict['intensity 2']
+            report['Intensity 2 Error'] = self._integrationDict['error 2']
+            report['Gauss Intensity'] = self._integrationDict['gauss intensity']
+            report['Gauss Error'] = self._integrationDict['gauss error']
+            report['Estimated Background'] = self._integrationDict['simple background']
+            if 'gauss parameters' in self._integrationDict:
+                report['Fitted Background'] = self._integrationDict['gauss parameters']['B']
+                report['Fitted A'] = self._integrationDict['gauss parameters']['A']
+                report['Fitted Sigma'] = self._integrationDict['gauss parameters']['s']
+            else:
+                report['Fitted Background'] = ''
+                report['Fitted A'] = ''
+                report['Fitted Sigma'] = ''
+        else:
+            report['Raw Intensity'] = ''
+            report['Raw Intensity Error'] = ''
+            report['Intensity 2'] = ''
+            report['Intensity 2 Error'] = ''
+            report['Gauss Intensity'] = ''
+            report['Gauss Error'] = ''
+            report['Lorentz'] = ''
+            report['Estimated Background'] = ''
+            report['Fitted Background'] = ''
+            report['Fitted A'] = ''
+            report['Fitted Sigma'] = ''
+            report['Mask'] = ''
+
+        report['Lorentz'] = self._lorenzFactor
+        if self._movingMotorTuple is None:
+            report['Motor'] = ''
+            report['Motor Step'] = None
+        else:
+            report['Motor'] = self._movingMotorTuple[0]
+            report['Motor Step'] = self._movingMotorTuple[1]
+        report['K-vector'] = self._kShiftVector
+        report['Absorption Correction'] = self._absorptionCorrection
+
+        return report
+
+    def get_intensity(self, algorithm_type, lorentz_corrected):
+        """
+        get the integrated intensity with specified integration algorithm and whether
+        the result should be corrected by Lorentz correction factor
+        :param algorithm_type:
+        :param lorentz_corrected:
+        :return:
+        """
+        # check
+        if self._integrationDict is None and self._myIntensity is None:
+            raise RuntimeError('PeakInfo of Exp {0} Scan {1} ({2} | {3}) has not integrated setup.'
+                               ''.format(self._myExpNumber, self._myScanNumber, self._fingerPrint, hex(id(self))))
+        elif self._myIntensity is not None:
+            # return ZERO intensity due to previously found error
+            return self._myIntensity, 0.
+
+        try:
+            if algorithm_type == 0 or algorithm_type.startswith('simple'):
+                # simple
+                intensity = self._integrationDict['simple intensity']
+                std_dev = self._integrationDict['simple error']
+            elif algorithm_type == 1 or algorithm_type.count('mixed') > 0:
+                # intensity 2: mixed simple and gaussian
+                intensity = self._integrationDict['intensity 2']
+                std_dev = self._integrationDict['error 2']
+            elif algorithm_type == 2 or algorithm_type.count('gauss') > 0:
+                # gaussian
+                intensity = self._integrationDict['gauss intensity']
+                std_dev = self._integrationDict['gauss error']
+            else:
+                raise RuntimeError('Type {0} not supported yet.')
+        except KeyError as key_err:
+            err_msg = 'Some key(s) does not exist in dictionary with keys {0}. FYI: {1}' \
+                      ''.format(self._integrationDict.keys(), key_err)
+            raise RuntimeError(err_msg)
+
+        if intensity is None:
+            intensity = 0.
+            std_dev = 0.
+        elif lorentz_corrected:
+            intensity *= self._lorenzFactor
+            std_dev *= self._lorenzFactor
+
+        return intensity, std_dev
+
     def get_peak_centre(self):
         """ get weighted peak centre
         :return: Qx, Qy, Qz (3-double-tuple)
@@ -148,16 +272,37 @@ class PeakProcessRecord(object):
         """
         if user_hkl:
             # return user-specified HKL
-            assert self._userHKL is not None, 'User HKL is None (not set up yet)'
-            ret_hkl = self._userHKL
+            assert self._calculatedHKL is not None, 'User HKL is None (not set up yet)'
+            ret_hkl = self._calculatedHKL
         else:
             # get HKL from SPICE file
             # if self._spiceHKL is None:
             self.retrieve_hkl_from_spice_table()
             ret_hkl = self._spiceHKL
 
+            # print '[DB...BAT] PeakInfo (Scan: {0}, ID: {1}) SPICE HKL: {2}' \
+            #       ''.format(self._myScanNumber, hex(id(self)), self._spiceHKL)
+
         return ret_hkl
 
+    def get_experiment_info(self):
+        """
+
+        :return: 2-tuple of integer as experiment number
+        """
+        return self._myExpNumber, self._myScanNumber
+
+    def get_sample_frame_q(self, peak_index):
+        """
+        Get Q in sample frame
+        :return: 3-tuple of floats as Qx, Qy, Qz
+        """
+        peak_ws = AnalysisDataService.retrieve(self._myPeakWorkspaceName)
+        peak = peak_ws.getPeak(peak_index)
+        q_sample = peak.getQSampleFrame()
+
+        return q_sample.getX(), q_sample.getY(), q_sample.getZ()
+
     def get_weighted_peak_centres(self):
         """ Get the peak centers found in peak workspace.
         Guarantees: the peak centers and its weight (detector counts) are exported
@@ -184,6 +329,61 @@ class PeakProcessRecord(object):
 
         return peak_center_list, peak_intensity_list
 
+    def set_k_vector(self, k_vector):
+        """
+
+        :param k_vector:
+        :return:
+        """
+        # check input
+        assert not isinstance(k_vector, str) and len(k_vector) == 3, 'K-vector {0} must have 3 items.'.format(k_vector)
+
+        self._kShiftVector = k_vector[:]
+
+        return
+
+    @property
+    def lorentz_correction_factor(self):
+        """
+
+        :return:
+        """
+        if self._lorenzFactor is None:
+            raise RuntimeError('Lorentz factor has not been calculated for Exp {0} Scan {1} ({2} | {3}).'
+                               ''.format(self._myExpNumber, self._myScanNumber, self._fingerPrint, hex(id(self))))
+        return self._lorenzFactor
+
+    @lorentz_correction_factor.setter
+    def lorentz_correction_factor(self, factor):
+        """
+        get lorenz factor
+        :param factor:
+        :return:
+        """
+        assert isinstance(factor, float), 'Lorentz correction factor'
+        self._lorenzFactor = factor
+
+        # print '[DB...BAT] Exp {0} Scan {1}  ({2} | {3}) has Lorentz factor set up.' \
+        #       ''.format(self._myExpNumber, self._myScanNumber, self._fingerPrint, hex(id(self)))
+
+        return
+
+    @property
+    def md_workspace(self):
+        """
+        give out MDEventWorkspace name for merged scan
+        :return:
+        """
+        return self._myDataMDWorkspaceName
+
+    @property
+    def peaks_workspace(self):
+        """
+        give out PeaksWorkspace
+        :return:
+        """
+        return self._myPeakWorkspaceName
+
     def retrieve_hkl_from_spice_table(self):
         """ Get averaged HKL from SPICE table
         HKL will be averaged from SPICE table by assuming the value in SPICE might be right
@@ -191,7 +391,7 @@ class PeakProcessRecord(object):
         """
         # get SPICE table
         spice_table_name = get_spice_table_name(self._myExpNumber, self._myScanNumber)
-        assert AnalysisDataService.doesExist(spice_table_name), 'Spice table for exp %d scan %d cannot be found.' \
+        assert AnalysisDataService.doesExist(spice_table_name), 'Spice table for Exp %d Scan %d cannot be found.' \
                                                                 '' % (self._myExpNumber, self._myScanNumber)
 
         spice_table_ws = AnalysisDataService.retrieve(spice_table_name)
@@ -216,6 +416,19 @@ class PeakProcessRecord(object):
 
         return
 
+    def set_absorption_factor(self, abs_factor):
+        """
+        set absorption correction factor
+        :return:
+        """
+        # check
+        assert isinstance(abs_factor, float) or isinstance(abs_factor, int),\
+            'Absorption correction {0} must be an integer but not {1}.'.format(abs_factor, type(abs_factor))
+
+        self._absorptionCorrection = abs_factor
+
+        return
+
     def set_data_ws_name(self, md_ws_name):
         """ Set the name of MDEventWorkspace with merged Pts.
         :param md_ws_name:
@@ -238,9 +451,9 @@ class PeakProcessRecord(object):
         assert hkl.shape == (3,), 'HKL must be a 3-element 1-D array but not %s.' % str(hkl.shape)
 
         # store the HKL
-        if self._userHKL is not None:
-            self._prevHKL = self._userHKL[:]
-        self._userHKL = hkl
+        if self._calculatedHKL is not None:
+            self._prevHKL = self._calculatedHKL[:]
+        self._calculatedHKL = hkl
 
         return
 
@@ -262,83 +475,75 @@ class PeakProcessRecord(object):
             mi_l = float(mi_l)
         # END-IF
 
-        if self._userHKL is None:
+        if self._calculatedHKL is None:
             # init HKL
-            self._userHKL = numpy.ndarray(shape=(3,), dtype='float')
+            self._calculatedHKL = numpy.ndarray(shape=(3,), dtype='float')
         else:
             # save previous HKL
-            self._prevHKL = self._userHKL[:]
+            self._prevHKL = self._calculatedHKL[:]
 
         # set current
-        self._userHKL[0] = mi_h
-        self._userHKL[1] = mi_k
-        self._userHKL[2] = mi_l
+        self._calculatedHKL[0] = mi_h
+        self._calculatedHKL[1] = mi_k
+        self._calculatedHKL[2] = mi_l
 
         return
 
-    def get_intensity(self):
-        """ Get current peak intensity
-        :return:
+    def set_motor(self, motor_name, motor_step, motor_std_dev):
         """
-        return self._myIntensity
-
-    def set_intensity(self, peak_intensity):
-        """ Set peak intensity
-        :param peak_intensity:
+        set motor step information
+        :param motor_name:
+        :param motor_step:
+        :param motor_std_dev:
         :return:
         """
-        assert isinstance(peak_intensity, float), 'Input peak intensity %s is not a float.' % str(peak_intensity)
-        assert peak_intensity >= -0., 'Input peak intensity %f is negative.' % peak_intensity
+        assert isinstance(motor_name, str), 'Motor name {0} must be a string but not {1}.' \
+                                            ''.format(motor_name, type(motor_name))
+        assert isinstance(motor_step, float), 'Motor float {0} must be a string but not {1}.' \
+                                              ''.format(motor_step, type(motor_step))
+        assert isinstance(motor_std_dev, float), 'Standard deviation type must be float'
 
-        self._myIntensity = peak_intensity
+        self._movingMotorTuple = (motor_name, motor_step, motor_std_dev)
 
         return
 
-    def set_pt_intensity(self, pt_intensity_dict):
+    def set_integration(self, peak_integration_dict):
         """
-        Set Pt. intensity
-        :param pt_intensity_dict:
+        set the integration result by information stored in a dictionary
+        :param peak_integration_dict:
         :return:
         """
-        assert isinstance(pt_intensity_dict, dict)
+        assert isinstance(peak_integration_dict, dict),\
+            'Integrated peak information {0} must be given by a dictionary but not a {1}.' \
+            ''.format(peak_integration_dict, type(peak_integration_dict))
 
-        self._ptIntensityDict = pt_intensity_dict
+        # print '[DB...BAT] Exp {0} Scan {1}  ({2} | {3}) has integrated dictionary set up.' \
+        #       ''.format(self._myExpNumber, self._myScanNumber, self._fingerPrint, hex(id(self)))
+
+        self._integrationDict = peak_integration_dict
 
         return
 
-    def get_sigma(self):
-        """ Get peak intensity's sigma
-        :return:
+    def set_intensity_to_zero(self):
         """
-        return self._mySigma
-
-    def set_sigma(self, sigma):
-        """ set peak intensity's sigma
+        if peak integration is wrong, then set the intensity to zero
         :return:
         """
-        assert isinstance(sigma, float) and sigma > -0.
-
-        self._mySigma = sigma
+        self._myIntensity = -0.
 
         return
 
-    def get_experiment_info(self):
+    def set_pt_intensity(self, pt_intensity_dict):
         """
-
-        :return: 2-tuple of integer as experiment number
+        Set Pt. intensity
+        :param pt_intensity_dict:
+        :return:
         """
-        return self._myExpNumber, self._myScanNumber
+        assert isinstance(pt_intensity_dict, dict)
 
-    def get_sample_frame_q(self, peak_index):
-        """
-        Get Q in sample frame
-        :return: 3-tuple of floats as Qx, Qy, Qz
-        """
-        peak_ws = AnalysisDataService.retrieve(self._myPeakWorkspaceName)
-        peak = peak_ws.getPeak(peak_index)
-        q_sample = peak.getQSampleFrame()
+        self._ptIntensityDict = pt_intensity_dict
 
-        return q_sample.getX(), q_sample.getY(), q_sample.getZ()
+        return
 
 
 def build_pt_spice_table_row_map(spice_table_ws):
@@ -356,3 +561,22 @@ def build_pt_spice_table_row_map(spice_table_ws):
         pt_spice_row_dict[pt_number] = i_row
 
     return pt_spice_row_dict
+
+
+def str_format(float_items):
+    """
+
+    :param float_items:
+    :return:
+    """
+    format_str = ''
+    for index, value in enumerate(float_items):
+        if index > 0:
+            format_str += ', '
+        if isinstance(value, float):
+            format_str += '{0:.4f}'.format(value)
+        else:
+            format_str += '{0}'.format(value)
+    # END-FOR
+
+    return format_str
diff --git a/scripts/HFIR_4Circle_Reduction/project_manager.py b/scripts/HFIR_4Circle_Reduction/project_manager.py
index 0d2463d4ed5d5a709458d7e20b4d1d7e8f742f72..656a158e8e6d92b81944520aa3553752e3a51ed8 100644
--- a/scripts/HFIR_4Circle_Reduction/project_manager.py
+++ b/scripts/HFIR_4Circle_Reduction/project_manager.py
@@ -82,7 +82,14 @@ class ProjectManager(object):
         for ws_name in self._wsList:
             md_file_name = os.path.join(self._wsDir, ws_name + '.nxs')
             if overwrite or not os.path.exists(md_file_name):
-                mantidsimple.SaveMD(InputWorkspace=ws_name, Filename=md_file_name)
+                try:
+                    mantidsimple.SaveMD(InputWorkspace=ws_name, Filename=md_file_name)
+                except RuntimeError as run_err:
+                    print '[ERROR] Unable to save {0} due to RuntimeError {1}.'.format(ws_name, run_err)
+                except Exception as arb_err:
+                    print '[ERROR] Unable to save {0} due to arbitrary exception {1}.'.format(ws_name, arb_err)
+            # END-IF
+        # END-FOR (ws_name)
 
         with open(self._projectPath, 'w') as pickle_file:
             pickle.dump(self._variableDict, pickle_file, pickle.HIGHEST_PROTOCOL)
@@ -103,7 +110,14 @@ class ProjectManager(object):
         # load data
         for ws_name in self._wsList:
             md_file_path = os.path.join(self._wsDir, ws_name + '.nxs')
-            mantidsimple.LoadMD(Filename=md_file_path, OutputWorkspace=ws_name)
+            try:
+                mantidsimple.LoadMD(Filename=md_file_path, OutputWorkspace=ws_name)
+            except RuntimeError as run_err:
+                print '[DB] Unable to load file {0} due to RuntimeError {1}.'.format(md_file_path, run_err)
+            except OSError as run_err:
+                print '[DB] Unable to load file {0} due to OSError {1}.'.format(md_file_path, run_err)
+            except IOError as run_err:
+                print '[DB] Unable to load file {0} due to IOError {1}.'.format(md_file_path, run_err)
         # END-FOR
 
         return
diff --git a/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py b/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py
index 998e74ac3ec2a3f19ccd7270b96007e807dccfe2..0df9b5082a500e2c32d2e7dca38ac2cdba5d6029 100644
--- a/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py
+++ b/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py
@@ -16,6 +16,8 @@ from fourcircle_utility import *
 from peakprocesshelper import PeakProcessRecord
 import fputility
 import project_manager
+import peak_integration_utility
+import absorption
 
 import mantid
 import mantid.simpleapi as mantidsimple
@@ -25,9 +27,8 @@ from mantid.kernel import V3D
 
 DebugMode = True
 
-# TODO - changed without configuration
-DET_X_SIZE = 512
-DET_Y_SIZE = 512
+# DET_X_SIZE = 512
+# DET_Y_SIZE = 512
 
 MAX_SCAN_NUMBER = 100000
 
@@ -107,6 +108,12 @@ class CWSCDReductionControl(object):
         self._detSampleDistanceDict = dict()
         self._detCenterDict = dict()
 
+        # detector geometry: initialized to unphysical value
+        self._detectorSize = [-1, -1]
+
+        # reference workspace for LoadMask
+        self._refWorkspaceForMask = None
+
         # register startup
         mantid.UsageService.registerFeatureUsage("Interface","4-Circle Reduction",False)
 
@@ -142,9 +149,9 @@ class CWSCDReductionControl(object):
         :return: k_index of the (k_x, k_y, k_z)
         """
         # check
-        assert isinstance(k_x, float)
-        assert isinstance(k_y, float)
-        assert isinstance(k_z, float)
+        assert isinstance(k_x, float), 'Kx is wrong'
+        assert isinstance(k_y, float), 'Ky is wrong'
+        assert isinstance(k_z, float), 'Kz is wrong'
 
         k_shift_vector = (k_x, k_y, k_z)
         self._kShiftDict[self._kVectorIndex] = [k_shift_vector, []]
@@ -189,16 +196,6 @@ class CWSCDReductionControl(object):
 
         return
 
-    @staticmethod
-    def apply_lorentz_correction(peak_intensity, q, wavelength, step_omega):
-        """ Apply lorentz correction to intensity """
-        # calculate theta
-        sin_theta = q * wavelength/(4*math.pi)
-        theta = math.asin(sin_theta)
-        corrected_intensity = peak_intensity * math.sin(2*theta) * step_omega
-
-        return corrected_intensity
-
     def find_peak(self, exp_number, scan_number, pt_number_list=None):
         """ Find 1 peak in sample Q space for UB matrix
         :param exp_number:
@@ -230,7 +227,8 @@ class CWSCDReductionControl(object):
                                  PeakDistanceThreshold=5.,
                                  DensityThresholdFactor=0.1,
                                  OutputWorkspace=peak_ws_name)
-        assert AnalysisDataService.doesExist(peak_ws_name)
+        assert AnalysisDataService.doesExist(peak_ws_name), 'PeaksWorkspace {0} does not exist in ADS.' \
+                                                            ''.format(peak_ws_name)
 
         # add peak to UB matrix workspace to manager
         self._set_peak_info(exp_number, scan_number, peak_ws_name, merged_ws_name)
@@ -242,6 +240,29 @@ class CWSCDReductionControl(object):
 
         return True, peak_center
 
+    @staticmethod
+    def find_detector_size(exp_directory, exp_number):
+        """
+        find detector size from experiment directory
+        :param exp_directory:
+        :param exp_number
+        :return:
+        """
+        # guess the file name
+        first_xm_file = os.path.join(exp_directory, 'HB3A_Exp{0}_Scan0001_00001.xml'.format(exp_number))
+        if os.path.exists(first_xm_file):
+            file_size = os.path.getsize(first_xm_file)
+            if file_size < 136132 * 2:
+                det_size = 256, 256
+            elif file_size < 529887 * 2:
+                det_size = 512, 512
+            else:
+                raise RuntimeError('File size is over {0}.  It is not supported.')
+
+            return True, det_size
+
+        return False, 'Unable to find first Pt file {0}'.format(first_xm_file)
+
     def calculate_ub_matrix(self, peak_info_list, a, b, c, alpha, beta, gamma):
         """
         Calculate UB matrix
@@ -420,20 +441,28 @@ class CWSCDReductionControl(object):
 
         return True, error_message
 
-    def check_generate_mask_workspace(self, exp_number, scan_number, mask_tag):
+    def check_generate_mask_workspace(self, exp_number, scan_number, mask_tag, check_throw):
         """
-        Check whether a workspace does exist.
+        Check whether a MaskWorkspace exists according to the tag
         If it does not, then generate one according to the tag
+
+        A MaskWorkspace's name is exactly the same as the tag of the mask specified by user in
+        reduction GUI.
+
         :param exp_number:
         :param scan_number:
-        :param mask_tag:
+        :param mask_tag: string as the tag of the mask.
+        :param check_throw
         :return:
         """
         # Check
-        assert isinstance(exp_number, int)
-        assert isinstance(scan_number, int)
-        assert isinstance(mask_tag, str)
+        assert isinstance(exp_number, int), 'Experiment number {0} must be an integer but not a {1}.' \
+                                            ''.format(exp_number, type(exp_number))
+        assert isinstance(scan_number, int), 'Scan number {0} ({1}) must be an integer.' \
+                                             ''.format(scan_number, type(scan_number))
+        assert isinstance(mask_tag, str), 'Mask tag {0} ({1}) must be a string.'.format(mask_tag, type(mask_tag))
 
+        # MaskWorkspace's name is same as mask's tag
         mask_ws_name = mask_tag
 
         if AnalysisDataService.doesExist(mask_ws_name) is False:
@@ -444,7 +473,11 @@ class CWSCDReductionControl(object):
             ur = region_of_interest[1]
             self.generate_mask_workspace(exp_number, scan_number, ll, ur, mask_ws_name)
 
-        return
+        if check_throw:
+            assert AnalysisDataService.doesExist(mask_ws_name), 'MaskWorkspace %s does not exist.' \
+                                                                 '' % mask_ws_name
+
+        return mask_ws_name
 
     def does_file_exist(self, exp_number, scan_number, pt_number=None):
         """
@@ -553,8 +586,10 @@ class CWSCDReductionControl(object):
         :return:
         """
         # check
-        assert isinstance(exp_number, int)
-        assert isinstance(scan_number, int)
+        assert isinstance(exp_number, int), 'Experiment number {0} must be an integer but not a {1}.' \
+                                            ''.format(exp_number, type(scan_number))
+        assert isinstance(scan_number, int), 'Scan number {0} must be an integer but not a {1}.' \
+                                             ''.format(scan_number, type(scan_number))
 
         # get SPICE table
         spice_table_name = get_spice_table_name(exp_number, scan_number)
@@ -625,49 +660,65 @@ class CWSCDReductionControl(object):
         assert len(scan_kindex_dict) == 0 or len(scan_kindex_dict) >= len(scan_number_list), error_message
 
         # form peaks
-        peaks = list()
         no_shift = len(scan_kindex_dict) == 0
 
         # get ub matrix
         ub_matrix = self.get_ub_matrix(exp_number)
 
-        for scan_number in scan_number_list:
-            peak_dict = dict()
-            try:
-                peak_dict['hkl'] = self._myPeakInfoDict[(exp_number, scan_number)]. get_hkl(user_hkl=True)
-            except RuntimeError as run_err:
-                return False, str('Peak index error: %s.' % run_err)
+        for algorithm_type in ['simple', 'mixed', 'gauss']:
+            # set list of peaks for exporting
+            peaks = list()
+            for scan_number in scan_number_list:
+                peak_dict = dict()
+                try:
+                    peak_dict['hkl'] = self._myPeakInfoDict[(exp_number, scan_number)].get_hkl(user_hkl=True)
+                except RuntimeError as run_err:
+                    return False, str('Peak index error: %s.' % run_err)
 
-            peak_dict['intensity'] = self._myPeakInfoDict[(exp_number, scan_number)].get_intensity()
-            peak_dict['sigma'] = self._myPeakInfoDict[(exp_number, scan_number)].get_sigma()
-            if no_shift:
-                peak_dict['kindex'] = 0
-            else:
-                peak_dict['kindex'] = scan_kindex_dict[scan_number]
+                intensity, std_dev = self._myPeakInfoDict[(exp_number, scan_number)].get_intensity(
+                    algorithm_type, lorentz_corrected=True)
 
-            if export_absorption:
-                # calculate absorption correction
-                import absorption
+                if intensity < std_dev:
+                    # error is huge, very likely bad gaussian fit
+                    print '[INFO] Integration Type {0}: Scan {1} Intensity {2} < Std Dev {2} Excluded from exporting.' \
+                          ''.format(algorithm_type, scan_number, intensity, std_dev)
+                    continue
+                # END-IF
 
-                spice_ub = convert_mantid_ub_to_spice(ub_matrix)
-                up_cart, us_cart = absorption.calculate_absorption_correction_2(
-                    exp_number, scan_number, spice_ub)
-                peak_dict['up'] = up_cart
-                peak_dict['us'] = us_cart
+                peak_dict['intensity'] = intensity
+                peak_dict['sigma'] = std_dev
+                if no_shift:
+                    peak_dict['kindex'] = 0
+                else:
+                    peak_dict['kindex'] = scan_kindex_dict[scan_number]
+
+                if export_absorption:
+                    # calculate absorption correction
+                    spice_ub = convert_mantid_ub_to_spice(ub_matrix)
+                    up_cart, us_cart = absorption.calculate_absorption_correction_2(
+                        exp_number, scan_number, spice_ub)
+                    peak_dict['up'] = up_cart
+                    peak_dict['us'] = us_cart
+
+                # append peak (in dict) to peaks
+                peaks.append(peak_dict)
+            # END-FOR (scan_number)
 
-            # append peak (in dict) to peaks
-            peaks.append(peak_dict)
-        # END-FOR (scan_number)
+            # get file name for this type
+            this_file_name = fullprof_file_name.split('.')[0] + '_' + algorithm_type + '.dat'
 
-        try:
-            file_content = fputility.write_scd_fullprof_kvector(
-                user_header=user_header, wave_length=exp_wave_length,
-                k_vector_dict=k_shift_dict, peak_dict_list=peaks,
-                fp_file_name=fullprof_file_name, with_absorption=export_absorption)
-        except AssertionError as error:
-            return False, 'AssertionError: %s.' % str(error)
-        except RuntimeError as error:
-            return False, 'RuntimeError: %s.' % str(error)
+            try:
+                file_content = fputility.write_scd_fullprof_kvector(
+                    user_header=user_header, wave_length=exp_wave_length,
+                    k_vector_dict=k_shift_dict, peak_dict_list=peaks,
+                    fp_file_name=this_file_name, with_absorption=export_absorption)
+            except AssertionError as error:
+                return False, 'AssertionError: %s.' % str(error)
+            except RuntimeError as error:
+                return False, 'RuntimeError: %s.' % str(error)
+
+            continue
+        # END-FOR
 
         return True, file_content
 
@@ -750,13 +801,13 @@ class CWSCDReductionControl(object):
         raw_ws = self.get_raw_data_workspace(exp_no, scan_no, pt_no)
         if raw_ws is None:
             return False, 'Raw data for Exp %d Scan %d Pt %d is not loaded.' % (exp_no, scan_no, pt_no)
-        print '[DB...BAT] Raw workspace size: ', raw_ws.getNumberHistograms()
 
         # Convert to numpy array
-        array2d = numpy.ndarray(shape=(DET_X_SIZE, DET_Y_SIZE), dtype='float')
-        for i in xrange(DET_X_SIZE):
-            for j in xrange(DET_Y_SIZE):
-                array2d[i][j] = raw_ws.readY(j * DET_X_SIZE + i)[0]
+        det_shape = (self._detectorSize[0], self._detectorSize[1])
+        array2d = numpy.ndarray(shape=det_shape, dtype='float')
+        for i in xrange(det_shape[0]):
+            for j in xrange(det_shape[1]):
+                array2d[i][j] = raw_ws.readY(j * det_shape[0] + i)[0]
 
         # Flip the 2D array to look detector from sample
         array2d = numpy.flipud(array2d)
@@ -777,11 +828,12 @@ class CWSCDReductionControl(object):
         """ Get region of interest
         :param exp_number:
         :param scan_number:
-        :return:
+        :return: region of interest
         """
         # check
-        assert isinstance(exp_number, int)
-        assert isinstance(scan_number, int) or scan_number is None
+        assert isinstance(exp_number, int), 'Experiment number {0} must be an integer.'.format(exp_number)
+        assert isinstance(scan_number, int) or scan_number is None, 'Scan number {0} must be either an integer or None.' \
+                                                                    ''.format(scan_number)
 
         if (exp_number, scan_number) in self._roiDict:
             # able to find region of interest for this scan
@@ -872,6 +924,9 @@ class CWSCDReductionControl(object):
                                                                 'it is of type %s now.' % (str(pt_number),
                                                                                            type(pt_number))
 
+        # print '[DB...BAT] Retrieve: Exp {0} Scan {1} Peak Info Object. Current keys are {0}.' \
+        #       ''.format(exp_number, scan_number, self._myPeakInfoDict.keys())
+
         # construct key
         if pt_number is None:
             p_key = (exp_number, scan_number)
@@ -881,6 +936,8 @@ class CWSCDReductionControl(object):
         # Check for existence
         if p_key in self._myPeakInfoDict:
             ret_value = self._myPeakInfoDict[p_key]
+            # print '[DB...BAT] Retrieved: Exp {0} Scan {1} Peak Info Object {2}.'.format(exp_number, scan_number,
+            #                                                                             hex(id(ret_value)))
         else:
             ret_value = None
 
@@ -937,8 +994,10 @@ class CWSCDReductionControl(object):
         :return:
         """
         # assert ...
-        assert isinstance(exp_number, int)
-        assert isinstance(scan_number, int)
+        assert isinstance(exp_number, int), 'Experiment number {0} ({1}) must be an integer.' \
+                                            ''.format(exp_number, type(exp_number))
+        assert isinstance(scan_number, int), 'Scan number {0} ({1}) must be an integer.' \
+                                             ''.format(scan_number, type(scan_number))
 
         # create an xml file
         mask_file_name = get_mask_xml_temp(self._workDir, exp_number, scan_number)
@@ -954,9 +1013,14 @@ class CWSCDReductionControl(object):
             # use given name
             mask_ws_name = str(mask_tag)
 
+        if self._refWorkspaceForMask is None:
+            return False, 'There is no reference workspace. Plot a Pt. first!'
+        elif AnalysisDataService.doesExist(self._refWorkspaceForMask) is False:
+            return False, 'Previous reference workspace has been deleted. Plot a Pt. first'
         mantidsimple.LoadMask(Instrument='HB3A',
                               InputFile=mask_file_name,
-                              OutputWorkspace=mask_ws_name)
+                              OutputWorkspace=mask_ws_name,
+                              RefWorkspace=self._refWorkspaceForMask)
         mantidsimple.InvertMask(InputWorkspace=mask_ws_name,
                                 OutputWorkspace=mask_ws_name)
 
@@ -1117,7 +1181,7 @@ class CWSCDReductionControl(object):
         temp_index_ws = AnalysisDataService.retrieve(temp_index_ws_name)
 
         if num_peak_index == 0:
-            return False, 'No peak can be indexed.'
+            return False, 'No peak can be indexed: {0}.'.format(error)
         elif num_peak_index > 1:
             raise RuntimeError('Case for PeaksWorkspace containing more than 1 peak is not '
                                'considered. Contact developer for this issue.')
@@ -1133,10 +1197,70 @@ class CWSCDReductionControl(object):
 
         return True, (hkl, error)
 
+    def integrate_scan_peak(self, exp_number, scan_number, peak_centre, mask_name, normalization,
+                            scale_factor, background_pt_tuple):
+        """
+        new way to integrate a peak in a scan
+        Note: it is going to replace "integrate_scan_peaks()"
+        :param exp_number:
+        :param scan_number:
+        :param peak_centre:
+        :param mask_name:
+        :param normalization:
+        :param scale_factor:
+        :param background_pt_tuple:
+        :return:
+        """
+        # check inputs
+        assert isinstance(exp_number, int), 'Experiment number {0} must be an integer but not a {1}.' \
+                                            ''.format(exp_number, type(exp_number))
+        assert isinstance(scan_number, int), 'Scan number {0} must be an integer but not a {1}.' \
+                                             ''.format(scan_number, type(scan_number))
+        assert isinstance(mask_name, str), 'Mask name {0} must be a string but not a {1}.' \
+                                           ''.format(mask_name, type(mask_name))
+        assert isinstance(normalization, str), 'Normalization type {0} must be a string but not a {1}.' \
+                                               ''.format(normalization, type(normalization))
+        assert isinstance(scale_factor, float) or isinstance(scale_factor, int),\
+            'Scale factor {0} must be a float or integer but not a {1}.'.format(scale_factor, type(scale_factor))
+        assert len(peak_centre) == 3, 'Peak center {0} must have 3 elements for (Qx, Qy, Qz).'.format(peak_centre)
+        # print '[DB...BAT] Background tuple {0} is of type {1}.'.format(background_pt_tuple, type(background_pt_tuple))
+        assert len(background_pt_tuple) == 2, 'Background tuple {0} must be of length 2.'.format(background_pt_tuple)
+
+        # get input MDEventWorkspace name for merged scan
+        status, ret_obj = self.get_pt_numbers(exp_number, scan_number)
+        if status:
+            pt_list = ret_obj
+        else:
+            raise RuntimeError('Unable to get Pt. list from Exp {0} Scan {1} due to {2}'
+                               ''.format(exp_number,scan_number, ret_obj))
+        md_ws_name = get_merged_md_name(self._instrumentName, exp_number, scan_number, pt_list)
+
+        # get the TableWorkspace name for Spice
+        spice_table_ws = get_spice_table_name(exp_number, scan_number)
+
+        # output PeaksWorkspace name and MaskWorkspace
+        if len(mask_name) > 0:
+            mask_ws_name = self.check_generate_mask_workspace(exp_number, scan_number, mask_name, check_throw=True)
+        else:
+            mask_ws_name = None
+        peak_ws_name = get_integrated_peak_ws_name(exp_number, scan_number, pt_list, mask_name)
+
+        # peak center
+        int_peak_dict = peak_integration_utility.integrate_peak_full_version(scan_md_ws_name=md_ws_name,
+                                                                             spice_table_name=spice_table_ws,
+                                                                             output_peak_ws_name=peak_ws_name,
+                                                                             peak_center=peak_centre,
+                                                                             mask_workspace_name=mask_ws_name,
+                                                                             norm_type=normalization,
+                                                                             intensity_scale_factor=scale_factor,
+                                                                             background_pt_tuple=background_pt_tuple)
+
+        return int_peak_dict
+
     def integrate_scan_peaks(self, exp, scan, peak_radius, peak_centre,
                              merge_peaks=True, use_mask=False,
                              normalization='', mask_ws_name=None,
-                             scale_factor=1):
+                             scale_factor=1.00, background_pt_tuple=None):
         """
         :param exp:
         :param scan:
@@ -1148,7 +1272,7 @@ class CWSCDReductionControl(object):
         :param normalization: normalization set up (by time or ...)
         :param mask_ws_name: mask workspace name or None
         :param scale_factor: integrated peaks' scaling factor
-        :return:
+        :return: dictionary of Pts.
         """
         # check
         assert isinstance(exp, int)
@@ -1157,208 +1281,58 @@ class CWSCDReductionControl(object):
         assert len(peak_centre) == 3
         assert isinstance(merge_peaks, bool)
 
-        # VZ-FUTURE - combine the download and naming for common use
-        # get spice file
-        spice_table_name = get_spice_table_name(exp, scan)
-        if AnalysisDataService.doesExist(spice_table_name) is False:
-            self.download_spice_file(exp, scan, False)
-            self.load_spice_scan_file(exp, scan)
-
-        # get MD workspace name
-        status, pt_list = self.get_pt_numbers(exp, scan)
-        assert status, str(pt_list)
-        md_ws_name = get_merged_md_name(self._instrumentName, exp, scan, pt_list)
-
-        peak_centre_str = '%f, %f, %f' % (peak_centre[0], peak_centre[1],
-                                          peak_centre[2])
-
-        # mask workspace
-        if use_mask:
-            if mask_ws_name is None:
-                # get default mask workspace name
-                mask_ws_name = get_mask_ws_name(exp, scan)
-            elif not AnalysisDataService.doesExist(mask_ws_name):
-                # the appointed mask workspace has not been loaded
-                # then load it from saved mask
-                self.check_generate_mask_workspace(exp, scan, mask_ws_name)
-
-            assert AnalysisDataService.doesExist(mask_ws_name), 'MaskWorkspace %s does not exist.' \
-                                                                '' % mask_ws_name
-
-            integrated_peak_ws_name = get_integrated_peak_ws_name(exp, scan, pt_list, use_mask)
-        else:
-            mask_ws_name = ''
-            integrated_peak_ws_name = get_integrated_peak_ws_name(exp, scan, pt_list)
-
-        # normalization
-        norm_by_mon = False
-        norm_by_time = False
-        if normalization == 'time':
-            norm_by_time = True
-        elif normalization == 'monitor':
-            norm_by_mon = True
-
-        # integrate peak of a scan
-        mantidsimple.IntegratePeaksCWSD(InputWorkspace=md_ws_name,
-                                        OutputWorkspace=integrated_peak_ws_name,
-                                        PeakRadius=peak_radius,
-                                        PeakCentre=peak_centre_str,
-                                        MergePeaks=merge_peaks,
-                                        NormalizeByMonitor=norm_by_mon,
-                                        NormalizeByTime=norm_by_time,
-                                        MaskWorkspace=mask_ws_name,
-                                        ScaleFactor=scale_factor)
-
-        # process the output workspace
-        pt_dict = dict()
-        out_peak_ws = AnalysisDataService.retrieve(integrated_peak_ws_name)
-        num_peaks = out_peak_ws.rowCount()
-
-        for i_peak in xrange(num_peaks):
-            peak_i = out_peak_ws.getPeak(i_peak)
-            run_number_i = peak_i.getRunNumber() % 1000
-            intensity_i = peak_i.getIntensity()
-            pt_dict[run_number_i] = intensity_i
-        # END-FOR
+        peak_int_dict = self.integrate_scan_peak(exp_number=exp, scan_number=scan, peak_centre=peak_centre,
+                                                 mask_name=mask_ws_name, normalization=normalization,
+                                                 scale_factor=scale_factor, background_pt_tuple=background_pt_tuple)
 
+        #
         # store the data into peak info
         if (exp, scan) not in self._myPeakInfoDict:
             raise RuntimeError('Exp %d Scan %d is not recorded in PeakInfo-Dict' % (exp, scan))
-        self._myPeakInfoDict[(exp, scan)].set_pt_intensity(pt_dict)
-
-        return True, pt_dict
-
-    def integrate_peaks_q(self, exp_no, scan_no):
-        """
-        Integrate peaks in Q-space
-        :param exp_no:
-        :param scan_no:
-        :return:
-        """
-        # Check inputs
-        assert isinstance(exp_no, int)
-        assert isinstance(scan_no, int)
-
-        # Get the SPICE file
-        spice_table_name = get_spice_table_name(exp_no, scan_no)
-        if AnalysisDataService.doesExist(spice_table_name) is False:
-            self.download_spice_file(exp_no, scan_no, False)
-            self.load_spice_scan_file(exp_no, scan_no)
-
-        # Find peaks & get the peak centers
-        spice_table = AnalysisDataService.retrieve(spice_table_name)
-        num_rows = spice_table.rowCount()
-
-        sum_peak_center = [0., 0., 0.]
-        sum_bin_counts = 0.
-
-        for i_row in xrange(num_rows):
-            pt_no = spice_table.cell(i_row, 0)
-            self.download_spice_xml_file(scan_no, pt_no, exp_no)
-            # self.load_spice_xml_file(exp_no, scan_no, pt_no)
-            self.find_peak(exp_no, scan_no, pt_no)
-            peak_ws_name = get_peak_ws_name(exp_no, scan_no, pt_no)
-            peak_ws = AnalysisDataService.retrieve(peak_ws_name)
-            if peak_ws.getNumberPeaks() == 1:
-                peak = peak_ws.getPeak(0)
-                peak_center = peak.getQSampleFrame()
-                bin_count = peak.getBinCount()
-
-                sum_peak_center[0] += bin_count * peak_center.X()
-                sum_peak_center[1] += bin_count * peak_center.Y()
-                sum_peak_center[2] += bin_count * peak_center.Z()
-
-                sum_bin_counts += bin_count
-
-            elif peak_ws.getNumberPeaks() > 1:
-                raise NotImplementedError('More than 1 peak???')
-        # END-FOR
-
-        final_peak_center = [0., 0., 0.]
-        for i in xrange(3):
-            final_peak_center[i] = sum_peak_center[i] * (1./sum_bin_counts)
-        #final_peak_center = sum_peak_center * (1./sum_bin_counts)
-
-        print '[INFO] Avg peak center = ', final_peak_center, 'Total counts = ', sum_bin_counts
-
-        # Integrate peaks
-        total_intensity = 0.
-        for i_row in xrange(num_rows):
-            pt_no = spice_table.cell(i_row, 0)
-            md_ws_name = get_single_pt_md_name(exp_no, scan_no, pt_no)
-            peak_ws_name = get_peak_ws_name(exp_no, scan_no, pt_no)
-            out_ws_name = peak_ws_name + '_integrated'
-            mantidsimple.IntegratePeaksCWSD(InputWorkspace=md_ws_name,
-                                            PeaksWorkspace=peak_ws_name,
-                                            OutputWorkspace=out_ws_name)
-            out_peak_ws = AnalysisDataService.retrieve(out_ws_name)
-            peak = out_peak_ws.getPeak(0)
-            intensity = peak.getIntensity()
-            total_intensity += intensity
-        # END-FOR
+        self._myPeakInfoDict[(exp, scan)].set_pt_intensity(peak_int_dict)
 
-        return total_intensity
+        return True, peak_int_dict
 
-    def integrate_peaks(self, exp_no, scan_no, pt_list, md_ws_name,
-                        peak_radius, bkgd_inner_radius, bkgd_outer_radius,
-                        is_cylinder):
+    @staticmethod
+    def gauss_correction_peak_intensity(pt_dict):
         """
-        Integrate peaks
-        :return: Boolean as successful or failed
+        fit a peak along Pt. with Gaussian and thus calculate background automatically
+        :param pt_dict:
+        :return: 3-tuple (intensity, background and information string)
         """
-        # Check input
-        if is_cylinder is True:
-            raise RuntimeError('Cylinder peak shape has not been implemented yet!')
-
-        if exp_no is None:
-            exp_no = self._expNumber
-        assert isinstance(exp_no, int)
-        assert isinstance(scan_no, int)
-        assert isinstance(peak_radius, float)
-        assert isinstance(bkgd_inner_radius, float)
-        assert isinstance(bkgd_outer_radius, float)
-        assert bkgd_inner_radius >= peak_radius
-        assert bkgd_outer_radius >= bkgd_inner_radius
-
-        # NEXT - Need to re-write this method according to documentation of IntegratePeaksCWSD()
-
-        # Get MD WS
-        if md_ws_name is None:
-            raise RuntimeError('Implement how to locate merged MD workspace name from '
-                               'Exp %d Scan %d Pt %s' % (exp_no, scan_no, str(pt_list)))
-        # Peak workspace
-        # create an empty peak workspace
-        if AnalysisDataService.doesExist('spicematrixws') is False:
-            raise RuntimeError('Workspace spicematrixws does not exist.')
-        mantidsimple.LoadInstrument(Workspace='', InstrumentName='HB3A')
-        target_peak_ws_name = 'MyPeakWS'
-        mantidsimple.CreatePeaksWorkspace(InstrumentWorkspace='spicematrixws', OutputWorkspace=target_peak_ws_name)
-        target_peak_ws = AnalysisDataService.retrieve(target_peak_ws_name)
-        # copy a peak
-        temp_peak_ws_name = 'peak1'
-        mantidsimple.FindPeaksMD(InputWorkspace='MergedSan0017_QSample',
-                                 PeakDistanceThreshold=0.5,
-                                 MaxPeaks=10,
-                                 DensityThresholdFactor=100,
-                                 OutputWorkspace=temp_peak_ws_name)
-
-        src_peak_ws = AnalysisDataService.retrieve(temp_peak_ws_name)
-        centre_peak = src_peak_ws.getPeak(0)
-        target_peak_ws.addPeak(centre_peak)
-        target_peak_ws.removePeak(0)
-
-        # Integrate peak
-        mantidsimple.IntegratePeaksMD(InputWorkspace='MergedSan0017_QSample',
-                                      PeakRadius=1.5,
-                                      BackgroundInnerRadius=1.5,
-                                      BackgroundOuterRadius=3,
-                                      PeaksWorkspace=target_peak_ws_name,
-                                      OutputWorkspace='SinglePeak1',
-                                      IntegrateIfOnEdge=False,
-                                      AdaptiveQBackground=True,
-                                      Cylinder=False)
-
-        raise RuntimeError('Implement ASAP!')
+        # check
+        assert isinstance(pt_dict, dict), 'Input must be a dictionary but not {0}'.format(type(pt_dict))
+
+        # convert to vector
+        tup_list = list()
+        for pt in pt_dict.keys():
+            tup_list.append((pt, pt_dict[pt]))
+        tup_list.sort()
+        list_x = list()
+        list_y = list()
+        for tup in tup_list:
+            list_x.append(float(tup[0]))
+            list_y.append(float(tup[1]))
+        vec_x = numpy.array(list_x)
+        vec_y = numpy.array(list_y)
+        vec_e = numpy.sqrt(vec_y)
+
+        # do fit
+        error, gauss_params, model_vec_y = peak_integration_utility.fit_gaussian_linear_background(vec_x, vec_y, vec_e)
+        x0, gauss_sigma, gauss_a, gauss_bkgd = gauss_params
+        if not (0 < x0 < vec_x[-1]):
+            raise RuntimeError('Fitted center of the peak {0} is out of range, which is not correct'.format(x0))
+        if gauss_a <= 0.:
+            raise RuntimeError('Fitted peak height {0} is negative!'.format(gauss_a))
+
+        # calculate the peak intensity
+        peak_intensity = peak_integration_utility.calculate_peak_intensity_gauss(gauss_a, gauss_sigma)
+
+        # information
+        info_str = 'Fit error = {0}: a = {1}, x0 = {2}, sigma = {3}, b = {4}'.format(error, gauss_a, x0, gauss_sigma,
+                                                                                     gauss_bkgd)
+
+        return peak_intensity, gauss_bkgd, info_str
 
     @staticmethod
     def load_scan_survey_file(csv_file_name):
@@ -1475,29 +1449,25 @@ class CWSCDReductionControl(object):
 
         # load SPICE Pt.  detector file
         pt_ws_name = get_raw_data_workspace_name(exp_no, scan_no, pt_no)
-        # new_idf_name = '/home/wzz/Projects/HB3A/NewDetector/HB3A_ND_Definition.xml'
-        new_idf_name = '/SNS/users/wzz/Projects/HB3A/HB3A_ND_Definition.xml'
-        if os.path.exists(new_idf_name) is False:
-            raise RuntimeError('Instrument file {0} cannot be found!'.format(new_idf_name))
         try:
             mantidsimple.LoadSpiceXML2DDet(Filename=xml_file_name,
                                            OutputWorkspace=pt_ws_name,
-                                           # FIXME - Need UI input
-                                           DetectorGeometry='512,512',
-                                           InstrumentFilename=new_idf_name,
                                            SpiceTableWorkspace=spice_table_name,
                                            PtNumber=pt_no)
+            if self._refWorkspaceForMask is None or AnalysisDataService.doesExist(pt_ws_name) is False:
+                self._refWorkspaceForMask = pt_ws_name
         except RuntimeError as run_err:
             return False, str(run_err)
 
         # Add data storage
-        assert AnalysisDataService.doesExist(pt_ws_name), 'blabla'
+        assert AnalysisDataService.doesExist(pt_ws_name), 'Unable to locate workspace {0}.'.format(pt_ws_name)
         raw_matrix_ws = AnalysisDataService.retrieve(pt_ws_name)
         self._add_raw_workspace(exp_no, scan_no, pt_no, raw_matrix_ws)
 
         return True, pt_ws_name
 
-    def merge_multiple_scans(self, scan_md_ws_list, scan_peak_centre_list, merged_ws_name):
+    @staticmethod
+    def merge_multiple_scans(scan_md_ws_list, scan_peak_centre_list, merged_ws_name):
         """
         Merge multiple scans
         :param scan_md_ws_list: List of MDWorkspace, each of which is for a scan.
@@ -1720,13 +1690,6 @@ class CWSCDReductionControl(object):
                 if exp_no in self._userWavelengthDict:
                     alg_args['UserDefinedWavelength'] = self._userWavelengthDict[exp_no]
 
-                # TODO/FIXME/NOW - Should get a flexible way to define IDF or no IDF
-                # new_idf_name = '/home/wzz/Projects/HB3A/NewDetector/HB3A_ND_Definition.xml'
-                new_idf_name = '/SNS/users/wzz/Projects/HB3A/HB3A_ND_Definition.xml'
-                if os.path.exists(new_idf_name) is False:
-                    raise RuntimeError('Instrument file {0} cannot be found!'.format(new_idf_name))
-                alg_args['InstrumentFilename'] = new_idf_name
-
                 # call:
                 mantidsimple.ConvertCWSDExpToMomentum(**alg_args)
 
@@ -1801,7 +1764,7 @@ class CWSCDReductionControl(object):
         ur_x = int(upper_right_corner[0])
         ur_y = int(upper_right_corner[1])
         assert ll_x < ur_x and ll_y < ur_y, 'Lower left corner (%.5f, %.5f) vs. upper right corner ' \
-                                            '(%.5f, %.5f)' % (ll_x, ll_y, ur_x, ur_y)
+                                            '(%.5f, %.5f) ' % (ll_x, ll_y, ur_x, ur_y)
 
         # Add to dictionary.  Because usually one ROI is defined for all scans in an experiment,
         # then it is better and easier to support client to search this ROI by experiment number
@@ -1834,6 +1797,24 @@ class CWSCDReductionControl(object):
 
         return
 
+    def set_detector_geometry(self, size_x, size_y):
+        """
+        set the detector's geometry, i.e., size
+        :param size_x:
+        :param size_y:
+        :return:
+        """
+        # check inputs
+        assert isinstance(size_x, int) and size_x > 0, 'Input detector size-X {0} must be a positive integer.' \
+                                                       ''.format(size_x)
+        assert isinstance(size_y, int) and size_y > 0, 'Input detector size-Y {0} must be a positive integer.' \
+                                                       ''.format(size_y)
+
+        self._detectorSize[0] = size_x
+        self._detectorSize[1] = size_y
+
+        return
+
     def set_detector_sample_distance(self, exp_number, sample_det_distance):
         """
         set instrument's detector - sample distance
@@ -2304,6 +2285,10 @@ class CWSCDReductionControl(object):
             if k_index > 0 and scan_number not in self._kShiftDict[k_index][1]:
                 self._kShiftDict[k_index][1].append(scan_number)
 
+            # add to the peak info
+            peak_info = self.get_peak_info(self._expNumber, scan_number)
+            peak_info.set_k_vector(self._kShiftDict[k_index][0])
+
             # remove from the previous placeholder
             for k_i in self._kShiftDict.keys():
                 # skip current one
@@ -2352,10 +2337,22 @@ class CWSCDReductionControl(object):
         :return: (boolean, PeakInfo/string)
         """
         # check
-        assert isinstance(exp_number, int)
-        assert isinstance(scan_number, int)
-        assert isinstance(peak_ws_name, str)
-        assert isinstance(md_ws_name, str)
+        assert isinstance(exp_number, int), 'Experiment number must be an integer.'
+        assert isinstance(scan_number, int), 'Scan number must an be integer.'
+        assert isinstance(peak_ws_name, str), 'PeaksWorkspace must be a string.'
+        assert isinstance(md_ws_name, str), 'MDEventWorkspace name must be a string.'
+
+        # check whether there is a redundant creation of PeakProcessRecord for the same (exp, scan) combination
+        if (exp_number, scan_number) in self._myPeakInfoDict:
+            peak_info = self._myPeakInfoDict[(exp_number, scan_number)]
+            print '[ERROR] PeakProcessRecord for Exp {0} Scan {1} shall not be created twice!' \
+                  ''.format(exp_number, scan_number)
+            print '[CONTINUE] New PeaksWorkspace = {0} vs Existing PeaksWorkspace = {1}.' \
+                  ''.format(peak_ws_name, peak_info.peaks_workspace)
+            print '[CONTINUE] New MDEventWorkspace = {0} vs Existing MDEventWorkspace = {1}.' \
+                  ''.format(md_ws_name, peak_info.md_workspace)
+            return False, peak_info
+        # END-IF
 
         # create a PeakInfo instance if it does not exist
         peak_info = PeakProcessRecord(exp_number, scan_number, peak_ws_name)
@@ -2422,7 +2419,7 @@ class CWSCDReductionControl(object):
 
         return ptlist
 
-    def set_peak_intensity(self, exp_number, scan_number, intensity):
+    def set_zero_peak_intensity(self, exp_number, scan_number):
         """
         Set peak intensity to a scan and set to PeakInfo
         :param exp_number:
@@ -2433,7 +2430,6 @@ class CWSCDReductionControl(object):
         # check
         assert isinstance(exp_number, int)
         assert isinstance(scan_number, int)
-        assert isinstance(intensity, float)
 
         # get dictionary item
         err_msg = 'Exp %d Scan %d does not exist in peak information' \
@@ -2442,17 +2438,7 @@ class CWSCDReductionControl(object):
         peak_info = self._myPeakInfoDict[(exp_number, scan_number)]
 
         # set intensity
-        try:
-            peak_info.set_intensity(intensity)
-        except AssertionError as ass_error:
-            return False, 'Unable to set peak intensity due to %s.' % str(ass_error)
-
-        # calculate sigma by simple square root
-        if intensity > 0:
-            sigma = math.sqrt(intensity)
-        else:
-            sigma = 1.
-        peak_info.set_sigma(sigma)
+        peak_info.set_intensity_to_zero()
 
         return True, ''
 
@@ -2496,7 +2482,7 @@ class CWSCDReductionControl(object):
         error_message = ''
 
         # Download and
-        for scan_number in xrange(start_scan, end_scan):
+        for scan_number in range(start_scan, end_scan+1):
             # check whether file exists
             if self.does_file_exist(exp_number, scan_number) is False:
                 # SPICE file does not exist in data directory. Download!
@@ -2570,6 +2556,7 @@ class CWSCDReductionControl(object):
                 wavelength = get_hb3a_wavelength(m1)
                 if wavelength is None:
                     q_range = 0.
+                    print '[ERROR] Scan number {0} has invalid m1 for wavelength.'.format(scan_number)
                 else:
                     q_range = 4.*math.pi*math.sin(two_theta/180.*math.pi*0.5)/wavelength
 
@@ -2591,7 +2578,7 @@ class CWSCDReductionControl(object):
 
         return True, scan_sum_list, error_message
 
-    def export_project(self, project_file_name, ui_dict):
+    def save_project(self, project_file_name, ui_dict):
         """ Export project
         - the data structure and information will be written to a ProjectManager file
         :param project_file_name:
diff --git a/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py b/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py
index 87709d85f007ed6b9a26b1db984fb43bb2cbe55c..d40ab566cd03f5ce842531c0021bbe674096083c 100644
--- a/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py
+++ b/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py
@@ -11,8 +11,6 @@ import time
 import datetime
 import random
 import numpy
-from scipy.optimize import curve_fit
-
 
 from PyQt4 import QtCore, QtGui
 try:
@@ -35,10 +33,14 @@ import plot3dwindow
 from multi_threads_helpers import *
 import optimizelatticewindow as ol_window
 import viewspicedialog
+import peak_integration_utility
+import FindUBUtility
+import message_dialog
 
 # import line for the UI python class
 from ui_MainWindow import Ui_MainWindow
 
+
 # define constants
 IndexFromSpice = 'From Spice (pre-defined)'
 IndexFromUB = 'From Calculation By UB'
@@ -51,7 +53,8 @@ class MainWindow(QtGui.QMainWindow):
     TabPage = {'View Raw Data': 2,
                'Calculate UB': 3,
                'UB Matrix': 4,
-               'Peak Integration': 6}
+               'Peak Integration': 6,
+               'Scans Processing': 5}
 
     def __init__(self, parent=None):
         """ Initialization and set up
@@ -63,6 +66,15 @@ class MainWindow(QtGui.QMainWindow):
         self.ui = Ui_MainWindow()
         self.ui.setupUi(self)
 
+        # children windows
+        self._my3DWindow = None
+        self._refineConfigWindow = None
+        self._peakIntegrationInfoWindow = None
+        self._addUBPeaksDialog = None
+        self._spiceViewer = None
+        self._mySinglePeakIntegrationDialog = None
+        self._singlePeakIntegrationDialogBuffer = ''
+
         # Make UI scrollable
         if NO_SCROLL is False:
             self._scrollbars = MantidQt.API.WidgetScrollbarDecorator(self)
@@ -103,6 +115,37 @@ class MainWindow(QtGui.QMainWindow):
                      self.do_set_user_detector_center)
         self.connect(self.ui.pushButton_applyUserWavelength, QtCore.SIGNAL('clicked()'),
                      self.do_set_user_wave_length)
+        self.connect(self.ui.pushButton_applyDetectorSize, QtCore.SIGNAL('clicked()'),
+                     self.do_set_detector_size)
+
+        # Tab survey
+        self.connect(self.ui.pushButton_survey, QtCore.SIGNAL('clicked()'),
+                     self.do_survey)
+        self.connect(self.ui.pushButton_saveSurvey, QtCore.SIGNAL('clicked()'),
+                     self.do_save_survey)
+        self.connect(self.ui.pushButton_loadSurvey, QtCore.SIGNAL('clicked()'),
+                     self.do_load_survey)
+        self.connect(self.ui.pushButton_viewSurveyPeak, QtCore.SIGNAL('clicked()'),
+                     self.do_view_survey_peak)
+        self.connect(self.ui.pushButton_addPeaksToRefine, QtCore.SIGNAL('clicked()'),
+                     self.do_add_peaks_for_ub)
+        self.connect(self.ui.pushButton_mergeScansSurvey, QtCore.SIGNAL('clicked()'),
+                     self.do_merge_scans_survey)
+        self.connect(self.ui.pushButton_selectAllSurveyPeaks, QtCore.SIGNAL('clicked()'),
+                     self.do_select_all_survey)
+        self.connect(self.ui.pushButton_sortInfoTable, QtCore.SIGNAL('clicked()'),
+                     self.do_filter_sort_survey_table)
+        self.connect(self.ui.pushButton_clearSurvey, QtCore.SIGNAL('clicked()'),
+                     self.do_clear_survey)
+        self.connect(self.ui.pushButton_viewRawSpice, QtCore.SIGNAL('clicked()'),
+                     self.do_show_spice_file)
+
+        self.connect(self.ui.lineEdit_numSurveyOutput, QtCore.SIGNAL('editingFinished()'),
+                     self.evt_show_survey)
+        self.connect(self.ui.lineEdit_numSurveyOutput, QtCore.SIGNAL('returnPressed()'),
+                     self.evt_show_survey)
+        self.connect(self.ui.lineEdit_numSurveyOutput, QtCore.SIGNAL('textEdited(const QString&)'),
+                     self.evt_show_survey)
 
         # Tab 'View Raw Data'
         self.connect(self.ui.pushButton_setScanInfo, QtCore.SIGNAL('clicked()'),
@@ -129,12 +172,14 @@ class MainWindow(QtGui.QMainWindow):
                      self.do_mask_pt_2d)
         self.connect(self.ui.pushButton_saveMask, QtCore.SIGNAL('clicked()'),
                      self.do_save_roi)
+        self.connect(self.ui.pushButton_integrateROI, QtCore.SIGNAL('clicked()'),
+                     self.do_integrate_roi)
 
         # Tab 'calculate ub matrix'
-        self.connect(self.ui.pushButton_findPeak, QtCore.SIGNAL('clicked()'),
-                     self.do_find_peak)
-        self.connect(self.ui.pushButton_addPeakToCalUB, QtCore.SIGNAL('clicked()'),
-                     self.do_add_ub_peak)
+        self.connect(self.ui.pushButton_addUBScans, QtCore.SIGNAL('clicked()'),
+                     self.do_add_ub_peaks)
+        # self.connect(self.ui.pushButton_addPeakToCalUB, QtCore.SIGNAL('clicked()'),
+        #              self.do_add_ub_peak)
         self.connect(self.ui.pushButton_calUB, QtCore.SIGNAL('clicked()'),
                      self.do_cal_ub_matrix)
         self.connect(self.ui.pushButton_acceptUB, QtCore.SIGNAL('clicked()'),
@@ -147,8 +192,8 @@ class MainWindow(QtGui.QMainWindow):
                      self.do_clear_ub_peaks)
         self.connect(self.ui.pushButton_resetPeakHKLs, QtCore.SIGNAL('clicked()'),
                      self.do_reset_ub_peaks_hkl)
-        self.connect(self.ui.pushButton_selectAllPeaks, QtCore.SIGNAL('clicked()'),
-                     self.do_select_all_peaks)
+        # self.connect(self.ui.pushButton_selectAllPeaks, QtCore.SIGNAL('clicked()'),
+        #              self.do_select_all_peaks)
         self.connect(self.ui.pushButton_viewScan3D, QtCore.SIGNAL('clicked()'),
                      self.do_view_data_3d)
         self.connect(self.ui.pushButton_plotSelectedData, QtCore.SIGNAL('clicked()'),
@@ -162,11 +207,21 @@ class MainWindow(QtGui.QMainWindow):
 
         self.connect(self.ui.pushButton_refineUB, QtCore.SIGNAL('clicked()'),
                      self.do_refine_ub_indexed_peaks)
+        self.connect(self.ui.pushButton_refineUBCalIndex, QtCore.SIGNAL('clicked()'),
+                     self.do_refine_ub_cal_indexed_peaks)
+
         self.connect(self.ui.pushButton_refineUBFFT, QtCore.SIGNAL('clicked()'),
                      self.do_refine_ub_fft)
         self.connect(self.ui.pushButton_findUBLattice, QtCore.SIGNAL('clicked()'),
                      self.do_refine_ub_lattice)
 
+        self.connect(self.ui.radioButton_ubAdvancedSelection, QtCore.SIGNAL('toggled(bool)'),
+                     self.do_select_all_peaks)
+        self.connect(self.ui.radioButton_ubSelectAllScans, QtCore.SIGNAL('toggled(bool)'),
+                     self.do_select_all_peaks)
+        self.connect(self.ui.radioButton_ubSelectNoScan, QtCore.SIGNAL('toggled(bool)'),
+                     self.do_select_all_peaks)
+
         # Tab 'Setup'
         self.connect(self.ui.pushButton_useDefaultDir, QtCore.SIGNAL('clicked()'),
                      self.do_setup_dir_default)
@@ -185,7 +240,7 @@ class MainWindow(QtGui.QMainWindow):
         self.connect(self.ui.pushButton_saveUB, QtCore.SIGNAL('clicked()'),
                      self.do_save_ub)
 
-        # Tab 'Merge'
+        # Tab 'Scans Processing'
         self.connect(self.ui.pushButton_addScanSliceView, QtCore.SIGNAL('clicked()'),
                      self.do_add_scans_merge)
         self.connect(self.ui.pushButton_mergeScans, QtCore.SIGNAL('clicked()'),
@@ -216,50 +271,22 @@ class MainWindow(QtGui.QMainWindow):
                      self.do_convert_merged_to_hkl)
         self.connect(self.ui.pushButton_showScanWSInfo, QtCore.SIGNAL('clicked()'),
                      self.do_show_workspaces)
-
-        # Tab 'Integrate Peaks'
+        self.connect(self.ui.pushButton_showIntegrateDetails, QtCore.SIGNAL('clicked()'),
+                     self.do_show_integration_details)
+        self.connect(self.ui.pushButton_toggleIntegrateType, QtCore.SIGNAL('clicked()'),
+                     self.do_toggle_table_integration)
+        self.connect(self.ui.pushButton_exportSelectedPeaks, QtCore.SIGNAL('clicked()'),
+                     self.do_export_selected_peaks_to_integrate)
+
+        # Tab 'Integrate (single) Peaks'
         self.connect(self.ui.pushButton_integratePt, QtCore.SIGNAL('clicked()'),
-                     self.do_integrate_per_pt)
+                     self.do_integrate_single_scan)
         self.connect(self.ui.comboBox_ptCountType, QtCore.SIGNAL('currentIndexChanged(int)'),
-                     self.do_plot_pt_peak)
-
-        self.connect(self.ui.pushButton_integratePeak, QtCore.SIGNAL('clicked()'),
-                     self.do_integrate_peak)
-
-        self.connect(self.ui.pushButton_fitBkgd, QtCore.SIGNAL('clicked()'),
-                     self.do_fit_bkgd)
-        self.connect(self.ui.pushButton_handPickBkgd, QtCore.SIGNAL('clicked()'),
-                     self.do_manual_bkgd)
-        self.connect(self.ui.pushButton_calBkgd, QtCore.SIGNAL('clicked()'),
-                     self.do_cal_background)
-
-        # Tab survey
-        self.connect(self.ui.pushButton_survey, QtCore.SIGNAL('clicked()'),
-                     self.do_survey)
-        self.connect(self.ui.pushButton_saveSurvey, QtCore.SIGNAL('clicked()'),
-                     self.do_save_survey)
-        self.connect(self.ui.pushButton_loadSurvey, QtCore.SIGNAL('clicked()'),
-                     self.do_load_survey)
-        self.connect(self.ui.pushButton_viewSurveyPeak, QtCore.SIGNAL('clicked()'),
-                     self.do_view_survey_peak)
-        self.connect(self.ui.pushButton_addPeaksToRefine, QtCore.SIGNAL('clicked()'),
-                     self.do_add_peaks_for_ub)
-        self.connect(self.ui.pushButton_selectAllSurveyPeaks, QtCore.SIGNAL('clicked()'),
-                     self.do_select_all_survey)
-        self.connect(self.ui.pushButton_sortInfoTable, QtCore.SIGNAL('clicked()'),
-                     self.do_filter_sort_survey_table)
-        self.connect(self.ui.pushButton_clearSurvey, QtCore.SIGNAL('clicked()'),
-                     self.do_clear_survey)
-
-        self.connect(self.ui.lineEdit_numSurveyOutput, QtCore.SIGNAL('editingFinished()'),
-                     self.evt_show_survey)
-        self.connect(self.ui.lineEdit_numSurveyOutput, QtCore.SIGNAL('returnPressed()'),
-                     self.evt_show_survey)
-        self.connect(self.ui.lineEdit_numSurveyOutput, QtCore.SIGNAL('textEdited(const QString&)'),
-                     self.evt_show_survey)
-
-        self.connect(self.ui.pushButton_viewRawSpice, QtCore.SIGNAL('clicked()'),
-                     self.do_show_spice_file)
+                     self.evt_change_normalization)  # calculate the normalized data again
+        self.connect(self.ui.pushButton_showIntPeakDetails, QtCore.SIGNAL('clicked()'),
+                     self.do_show_single_peak_integration)
+        self.connect(self.ui.pushButton_clearPeakIntFigure, QtCore.SIGNAL('clicked()'),
+                     self.do_clear_peak_integration_canvas)
 
         # Tab k-shift vector
         self.connect(self.ui.pushButton_addKShift, QtCore.SIGNAL('clicked()'),
@@ -287,6 +314,9 @@ class MainWindow(QtGui.QMainWindow):
         # Validator ... (NEXT)
 
         # Declaration of class variable
+        # IPTS number
+        self._iptsNumber = None
+
         # some configuration
         self._homeSrcDir = os.getcwd()
         self._homeDir = os.getcwd()
@@ -298,9 +328,10 @@ class MainWindow(QtGui.QMainWindow):
         self._surveyTableFlag = True
         self._ubPeakTableFlag = True
 
+        # set the detector geometry
+        self.do_set_detector_size()
+
         # Sub window
-        self._my3DWindow = None
-        self._refineConfigWindow = None
         self._baseTitle = 'Title is not initialized'
 
         # Timing and thread 'global'
@@ -310,9 +341,6 @@ class MainWindow(QtGui.QMainWindow):
         # QSettings
         self.load_settings()
 
-        # pre-define child windows
-        self._spiceViewer = None
-
         return
 
     @property
@@ -331,13 +359,15 @@ class MainWindow(QtGui.QMainWindow):
         :return:
         """
         self._baseTitle = str(self.windowTitle())
-        self.setWindowTitle('%s: No Experiment Is Set' % self._baseTitle)
+        self.setWindowTitle('No Experiment Is Set')
+
+        # detector geometry (set to 256 x 256)
+        self.ui.comboBox_detectorSize.setCurrentIndex(0)
 
         # Table widgets
         self.ui.tableWidget_peaksCalUB.setup()
         self.ui.tableWidget_ubMatrix.setup()
         self.ui.tableWidget_surveyTable.setup()
-        self.ui.tableWidget_peakIntegration.setup()
         self.ui.tableWidget_mergeScans.setup()
         self.ui.tableWidget_ubInUse.setup()
         self.ui.tableWidget_kShift.setup()
@@ -363,14 +393,24 @@ class MainWindow(QtGui.QMainWindow):
         self.ui.comboBox_indexFrom.addItem('By calculation')
         self.ui.comboBox_indexFrom.addItem('From SPICE')
 
+        self.ui.comboBox_hklType.clear()
+        self.ui.comboBox_hklType.addItem('SPICE')
+        self.ui.comboBox_hklType.addItem('Calculated')
+
+        # normalization to peak
+        self.ui.comboBox_ptCountType.clear()
+        self.ui.comboBox_ptCountType.addItem('Time')
+        self.ui.comboBox_ptCountType.addItem('Monitor')
+        self.ui.comboBox_ptCountType.addItem('Absolute')
+
         # tab
         self.ui.tabWidget.setCurrentIndex(0)
 
         self.ui.radioButton_ubMantidStyle.setChecked(True)
         self.ui.lineEdit_numSurveyOutput.setText('50')
-        self.ui.checkBox_loadHKLfromFile.setChecked(True)
         self.ui.checkBox_sortDescending.setChecked(False)
         self.ui.radioButton_sortByCounts.setChecked(True)
+        self.ui.radioButton_ubSelectNoScan.setChecked(True)
 
         # Tab 'Access'
         self.ui.lineEdit_url.setText('http://neutron.ornl.gov/user_data/hb3a/')
@@ -385,9 +425,12 @@ class MainWindow(QtGui.QMainWindow):
         # check boxes
         self.ui.graphicsView_detector2dPlot.set_parent_window(self)
 
+        # background points
+        self.ui.lineEdit_backgroundPts.setText('1, 1')
+
         return
 
-    def _build_peak_info_list(self, zero_hkl):
+    def _build_peak_info_list(self, zero_hkl, is_spice=True):
         """ Build a list of PeakInfo to build peak workspace
         peak HKL can be set to zero or from table
         :return: list of peak information, which is a PeakProcessRecord instance
@@ -414,10 +457,13 @@ class MainWindow(QtGui.QMainWindow):
             if zero_hkl:
                 # set HKL to zero
                 peak_info.set_hkl(0., 0., 0.)
-            else:
+            elif is_spice:
                 # set from table
-                miller_index = self.ui.tableWidget_peaksCalUB.get_hkl(i_row)
-                peak_info.set_hkl_np_array(numpy.array(miller_index))
+                spice_hkl = self.ui.tableWidget_peaksCalUB.get_hkl(i_row, True)
+                peak_info.set_hkl_np_array(numpy.array(spice_hkl))
+            else:
+                calculated_hkl = self.ui.tableWidget_peaksCalUB.get_hkl(i_row, False)
+                peak_info.set_hkl_np_array(numpy.array(calculated_hkl))
             # END-IF-ELSE
 
             peak_info_list.append(peak_info)
@@ -482,17 +528,36 @@ class MainWindow(QtGui.QMainWindow):
         ui_dict['survey start'] = str(self.ui.lineEdit_surveyStartPt.text())
         ui_dict['survey stop'] = str(self.ui.lineEdit_surveyEndPt.text())
 
-        # export/save project
-        self._myControl.export_project(project_file_name, ui_dict)
+        # detector-sample distance
+        det_distance_str = str(self.ui.lineEdit_infoDetSampleDistance.text()).strip()
+        if len(det_distance_str) > 0:
+            ui_dict['det_sample_distance'] = det_distance_str
+
+        # wave length
+        wave_length_str = str(self.ui.lineEdit_infoWavelength.text()).strip()
+        if len(wave_length_str) > 0:
+            ui_dict['wave_length'] = wave_length_str
+
+        # calibrated detector center
+        det_center_str = str(self.ui.lineEdit_infoDetCenter.text())
+        if len(det_center_str) > 0:
+            ui_dict['det_center'] = det_center_str
 
         # register and make it as a queue for last n opened/saved project
         last_1_path = str(self.ui.label_last1Path.text())
         if last_1_path != project_file_name:
             self.ui.label_last3Path.setText(self.ui.label_last2Path.text())
             self.ui.label_last2Path.setText(self.ui.label_last1Path.text())
-            self.ui.label_last1Path.setText(last_1_path)
+            self.ui.label_last1Path.setText(project_file_name)
         # END-IF
 
+        self._myControl.save_project(project_file_name, ui_dict)
+
+        # TODO/NOW/TODAY - Implement a pop-up dialog for this
+        information = 'Project has been saved to {0}\n'.format(project_file_name),
+        information += 'Including dictionary keys: {0}'.format(ui_dict)
+        print '[INFO]\n{0}'.format(information)
+
         return
 
     def action_load_project(self):
@@ -501,6 +566,9 @@ class MainWindow(QtGui.QMainWindow):
         :return:
         """
         project_file_name = str(QtGui.QFileDialog.getOpenFileName(self, 'Choose Project File', os.getcwd()))
+        if len(project_file_name) == 0:
+            # return if cancelled
+            return
 
         # make it as a queue for last n opened/saved project
         last_1_path = str(self.ui.label_last1Path.text())
@@ -514,34 +582,6 @@ class MainWindow(QtGui.QMainWindow):
 
         return
 
-    def load_project(self, project_file_name):
-        """
-        Load a saved project
-        :param project_file_name:
-        :return:
-        """
-        assert isinstance(project_file_name, str), 'Project file name %s must be a string but not %s.' \
-                                                   '' % (str(project_file_name), type(project_file_name))
-        assert os.path.exists(project_file_name), 'Project file "%s" cannot be found.' % project_file_name
-
-        # load project
-        ui_dict = self._myControl.load_project(project_file_name)
-
-        # set the UI parameters to GUI
-        try:
-            self.ui.lineEdit_localSpiceDir.setText(ui_dict['local spice dir'])
-            self.ui.lineEdit_workDir.setText(ui_dict['work dir'])
-            self.ui.lineEdit_surveyStartPt.setText(ui_dict['survey start'])
-            self.ui.lineEdit_surveyEndPt.setText(ui_dict['survey stop'])
-
-            # now try to call some actions
-            self.do_apply_setup()
-            self.do_set_experiment()
-        except KeyError:
-            print '[Error] Some field cannot be found.'
-
-        return
-
     def action_load_last_project(self):
         """
         Load last project
@@ -626,6 +666,32 @@ class MainWindow(QtGui.QMainWindow):
 
         return
 
+    def add_scans_ub_table(self, scan_list):
+        """
+
+        :param scan_list:
+        :return:
+        """
+        # TODO/FIXME/ISSUE/NOW - consider to refactor with do_add_peaks_for_ub() and
+        # get experiment number
+        status, exp_number = gutil.parse_integers_editors(self.ui.lineEdit_exp)
+        if not status:
+            self.pop_one_button_dialog('Unable to get experiment number\n  due to %s.' % str(exp_number))
+            return
+
+        # switch to tab-3
+        # self.ui.tabWidget.setCurrentIndex(MainWindow.TabPage['Calculate UB'])
+
+        # prototype for a new thread
+        self.ui.progressBar_add_ub_peaks.setRange(0, len(scan_list))
+        self._addUBPeaksThread = AddPeaksThread(self, exp_number, scan_list)
+        self._addUBPeaksThread.start()
+
+        # set the flag/notification where the indexing (HKL) from
+        self.ui.lineEdit_peaksIndexedBy.setText(IndexFromSpice)
+
+        return
+
     def do_add_roi(self):
         """ Add region of interest to 2D image
         :return:
@@ -659,51 +725,136 @@ class MainWindow(QtGui.QMainWindow):
 
         return
 
-    def do_add_ub_peak(self):
-        """ Add current to ub peaks
+    def do_add_ub_peaks(self):
+        """
+        Launch dialog to add UB peaks
+        :return:
+        """
+        if self._addUBPeaksDialog is None:
+            self._addUBPeaksDialog = FindUBUtility.AddScansForUBDialog(self)
+
+        self._addUBPeaksDialog.show()
+
+        return
+
+    # def do_add_ub_peak(self):
+    #     """ Add current to ub peaks
+    #     :return:
+    #     """
+    #     # TODO/FIXME/ISSUE/NOW - Find out whether this method is still needed
+    #     # Add peak
+    #     status, int_list = gutil.parse_integers_editors([self.ui.lineEdit_exp,
+    #                                                      self.ui.lineEdit_scanNumber])
+    #     if status is False:
+    #         self.pop_one_button_dialog(int_list)
+    #         return
+    #     exp_no, scan_no = int_list
+    #
+    #     # Get HKL from GUI
+    #     status, float_list = gutil.parse_float_editors([self.ui.lineEdit_H,
+    #                                                     self.ui.lineEdit_K,
+    #                                                     self.ui.lineEdit_L])
+    #     if status is False:
+    #         err_msg = float_list
+    #         self.pop_one_button_dialog(err_msg)
+    #         return
+    #     h, k, l = float_list
+    #
+    #     try:
+    #         peak_info_obj = self._myControl.get_peak_info(exp_no, scan_no)
+    #     except AssertionError as ass_err:
+    #         self.pop_one_button_dialog(str(ass_err))
+    #         return
+    #
+    #     assert isinstance(peak_info_obj, r4c.PeakProcessRecord)
+    #     peak_info_obj.set_hkl(h, k, l)
+    #     self.set_ub_peak_table(peak_info_obj)
+    #
+    #     # Clear
+    #     self.ui.lineEdit_scanNumber.setText('')
+    #
+    #     self.ui.lineEdit_sampleQx.setText('')
+    #     self.ui.lineEdit_sampleQy.setText('')
+    #     self.ui.lineEdit_sampleQz.setText('')
+    #
+    #     self.ui.lineEdit_H.setText('')
+    #     self.ui.lineEdit_K.setText('')
+    #     self.ui.lineEdit_L.setText('')
+    #
+    #     # set the flag/notification where the indexing (HKL) from
+    #     self.ui.lineEdit_peaksIndexedBy.setText(IndexFromSpice)
+    #
+    #     return
+
+    def do_add_k_shift_vector(self):
+        """ Add a k-shift vector
         :return:
         """
-        # Add peak
-        status, int_list = gutil.parse_integers_editors([self.ui.lineEdit_exp,
-                                                         self.ui.lineEdit_scanNumber])
+        # parse the k-vector
+        status, ret_obj = gutil.parse_float_editors([self.ui.lineEdit_kX, self.ui.lineEdit_kY, self.ui.lineEdit_kZ],
+                                                    allow_blank=False)
         if status is False:
-            self.pop_one_button_dialog(int_list)
+            error_message = ret_obj
+            self.pop_one_button_dialog(error_message)
             return
-        exp_no, scan_no = int_list
+        else:
+            k_x, k_y, k_z = ret_obj
 
-        # Get HKL from GUI
-        status, float_list = gutil.parse_float_editors([self.ui.lineEdit_H,
-                                                        self.ui.lineEdit_K,
-                                                        self.ui.lineEdit_L])
-        if status is False:
-            err_msg = float_list
-            self.pop_one_button_dialog(err_msg)
-            return
-        h, k, l = float_list
+        # add to controller
+        k_index = self._myControl.add_k_shift_vector(k_x, k_y, k_z)
 
-        try:
-            peak_info_obj = self._myControl.get_peak_info(exp_no, scan_no)
-        except AssertionError as ass_err:
-            self.pop_one_button_dialog(str(ass_err))
-            return
+        # add to table and combo-box
+        self.ui.tableWidget_kShift.add_k_vector(k_index, k_x, k_y, k_z)
+
+        combo_message = '%d: (%.5f, %.5f, %.5f)' % (k_index, k_x, k_y, k_z)
+        self.ui.comboBox_kVectors.addItem(combo_message)
+
+        return
+
+    def do_apply_k_shift(self):
+        """ Apply k-shift to selected reflections
+        :return:
+        """
+        # get the selected scans
+        scan_list = list()
+        selected_row_numbers = self.ui.tableWidget_mergeScans.get_selected_rows(True)
+        for row_index in selected_row_numbers:
+            scan_number = self.ui.tableWidget_mergeScans.get_scan_number(row_index)
+            scan_list.append(scan_number)
 
-        assert isinstance(peak_info_obj, r4c.PeakProcessRecord)
-        peak_info_obj.set_hkl(h, k, l)
-        self.set_ub_peak_table(peak_info_obj)
+        # get the k-vector
+        k_shift_message = str(self.ui.comboBox_kVectors.currentText())
+        k_index = int(k_shift_message.split(':')[0])
 
-        # Clear
-        self.ui.lineEdit_scanNumber.setText('')
+        # set to controller
+        self._myControl.set_k_shift(scan_list, k_index)
 
-        self.ui.lineEdit_sampleQx.setText('')
-        self.ui.lineEdit_sampleQy.setText('')
-        self.ui.lineEdit_sampleQz.setText('')
+        # set k-shift to table
+        # exp_number = int(self.ui.lineEdit_exp.text())
+        for row_index in selected_row_numbers:
+            self.ui.tableWidget_mergeScans.set_k_shift_index(row_index, k_index)
+            # scan_number = self.ui.tableWidget_mergeScans.get_scan_number(row_index)
 
-        self.ui.lineEdit_H.setText('')
-        self.ui.lineEdit_K.setText('')
-        self.ui.lineEdit_L.setText('')
+        return
 
-        # set the flag/notification where the indexing (HKL) from
-        self.ui.lineEdit_peaksIndexedBy.setText(IndexFromSpice)
+    def do_apply_roi(self):
+        """ Save current selection of region of interest
+        :return:
+        """
+        lower_left_c, upper_right_c = self.ui.graphicsView_detector2dPlot.get_roi()
+        # at the very beginning, the lower left and upper right are same
+        if lower_left_c[0] == upper_right_c[0] or lower_left_c[1] == upper_right_c[1]:
+            return
+
+        status, par_val_list = gutil.parse_integers_editors([self.ui.lineEdit_exp, self.ui.lineEdit_run])
+        assert status, str(par_val_list)
+        exp_number = par_val_list[0]
+        scan_number = par_val_list[1]
+
+        try:
+            self._myControl.set_roi(exp_number, scan_number, lower_left_c, upper_right_c)
+        except AssertionError as ass_err:
+            print '[ERROR] Unable to set ROI due to {0}.'.format(ass_err)
 
         return
 
@@ -824,29 +975,6 @@ class MainWindow(QtGui.QMainWindow):
 
         return
 
-    def do_cal_background(self):
-        """
-        calculate background
-        algorithm 1: average the selected pt's intensity.
-        :return:
-        """
-        # get the selected rows in table
-        background_rows = self.ui.tableWidget_peakIntegration.get_selected_rows(True)
-
-        # loop through the selected rows and do the average
-        intensity_sum = 0.
-        for i_row in background_rows:
-            tmp_intensity = self.ui.tableWidget_peakIntegration.get_cell_value(i_row, 2)
-            intensity_sum += tmp_intensity
-
-        # calculate background value
-        background = intensity_sum / float(len(background_rows))
-
-        # set the value
-        self.ui.lineEdit_background.setText('%.7f' % background)
-
-        return
-
     def do_cal_ub_matrix(self):
         """ Calculate UB matrix by 2 or 3 reflections
         """
@@ -932,7 +1060,9 @@ class MainWindow(QtGui.QMainWindow):
         """
         num_rows = self.ui.tableWidget_peaksCalUB.rowCount()
         for i_row in range(num_rows):
-            self.ui.tableWidget_peaksCalUB.set_hkl(i_row, [0., 0., 0.])
+            self.ui.tableWidget_peaksCalUB.set_hkl(i_row, [0., 0., 0.], is_spice_hkl=False)
+
+        return
 
     def do_clear_merge_table(self):
         """
@@ -942,6 +1072,22 @@ class MainWindow(QtGui.QMainWindow):
         # clear
         self.ui.tableWidget_mergeScans.remove_all_rows()
 
+    def do_clear_peak_integration_canvas(self):
+        """
+        clear the peak integration canvas and the integrated values
+        :return:
+        """
+        self.ui.graphicsView_integratedPeakView.clear_all_lines()
+
+        self.ui.lineEdit_rawSinglePeakIntensity.setText('')
+        self.ui.lineEdit_intensity2.setText('')
+        self.ui.lineEdit_gaussianPeakIntensity.setText('')
+        self.ui.lineEdit_errorIntensity1.setText('')
+        self.ui.lineEdit_errorIntensity2.setText('')
+        self.ui.lineEdit_errorIntensity3.setText('')
+
+        return
+
     def do_clear_survey(self):
         """
         Clear survey and survey table.
@@ -1058,85 +1204,68 @@ class MainWindow(QtGui.QMainWindow):
 
         return
 
-    def do_find_peak(self):
+    def find_peak_in_scan(self , scan_number, load_spice_hkl):
         """ Find peak in a given scan and record it
         """
         # Get experiment, scan and pt
-        status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_exp,
-                                                        self.ui.lineEdit_scanNumber])
+        status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_exp])
         if status is True:
-            exp_no, scan_no = ret_obj
+            exp_no = ret_obj
         else:
             self.pop_one_button_dialog(ret_obj)
             return
 
         # merge peak if necessary
-        if self._myControl.has_merged_data(exp_no, scan_no) is False:
-            status, err_msg = self._myControl.merge_pts_in_scan(exp_no, scan_no, [])
+        if self._myControl.has_merged_data(exp_no, scan_number) is False:
+            status, err_msg = self._myControl.merge_pts_in_scan(exp_no, scan_number, [])
             if status is False:
                 self.pop_one_button_dialog(err_msg)
 
         # Find peak
-        status, err_msg = self._myControl.find_peak(exp_no, scan_no)
+        status, err_msg = self._myControl.find_peak(exp_no, scan_number)
         if status is False:
             self.pop_one_button_dialog(ret_obj)
             return
 
         # Get information from the latest (integrated) peak
-        if self.ui.checkBox_loadHKLfromFile.isChecked() is True:
-            # This is the first time that in the workflow to get HKL from MD workspace
-            peak_info = self._myControl.get_peak_info(exp_no, scan_no)
-            assert peak_info is not None, 'Unable to locate PeakProcessRecord (peak info).'
-            # try:
-            #     peak_info.retrieve_hkl_from_spice_table()
-            # except RuntimeError as run_err:
-            #     self.pop_one_button_dialog('Unable to locate peak info due to %s.' % str(run_err))
-        # END-IF
+        # if load_spice_hkl:
+        #     # This is the first time that in the workflow to get HKL from MD workspace
+        #     peak_info = self._myControl.get_peak_info(exp_no, scan_number)
+        #     assert peak_info is not None, 'Unable to locate PeakProcessRecord (peak info).'
+        # # END-IF
 
         # Set up correct values to table tableWidget_peaksCalUB
-        peak_info = self._myControl.get_peak_info(exp_no, scan_no)
-        h, k, l = peak_info.get_spice_hkl()
-        self.ui.lineEdit_H.setText('%.2f' % h)
-        self.ui.lineEdit_K.setText('%.2f' % k)
-        self.ui.lineEdit_L.setText('%.2f' % l)
+        peak_info = self._myControl.get_peak_info(exp_no, scan_number)
+        assert peak_info is not None, 'Unable to locate PeakProcessRecord (peak info).'
+
+        if load_spice_hkl:
+            h, k, l = peak_info.get_hkl()
+            hkl = (h, k, l)
+        else:
+            hkl = ()
 
         q_x, q_y, q_z = peak_info.get_peak_centre()
-        self.ui.lineEdit_sampleQx.setText('%.5E' % q_x)
-        self.ui.lineEdit_sampleQy.setText('%.5E' % q_y)
-        self.ui.lineEdit_sampleQz.setText('%.5E' % q_z)
+        vec_q = (q_x, q_y, q_z)
 
-        return
+        return hkl, vec_q
 
-    def do_fit_bkgd(self):
-        """ Purpose: fit the Pt.-integrated peak intensity curve with Gaussian to find out the background
+    def do_export_selected_peaks_to_integrate(self):
+        """
+        export (to file or just print out) the scans that are selected for integration
+        :param self:
         :return:
         """
-        def gauss(x, a, b, c):
-            return c*numpy.exp(-(x-a)**2/b)
-
-        def gauss4(x, a, b, c, d):
-            return c*numpy.exp(-(x-a)**2/b)+d
-
-        # get the curve
-        vec_x, vec_y, vec_e = self.ui.graphicsView_integratedPeakView.get_xye()
-
-        # fit Gaussian for starting value of a, b and c
-        fit_result1 = curve_fit(gauss, vec_x, vec_y)
-        popt = fit_result1[0]  # popt, pcov
-        # gauss_fit = gauss(vec_x, popt[0], popt[1], popt[2])
-
-        # fit Gaussian again including background
-        p0 = [popt[0], popt[1], popt[2], 0.]
-        fit_result2 = curve_fit(gauss4, vec_x, vec_y, sigma=vec_e,  p0=p0)
-        popt2 = fit_result2[0]  # popt2, pcov2
-        gauss_fit4 = gauss4(vec_x, popt2[0], popt2[1], popt2[2], popt2[3])
+        # get selected rows' scan numbers
+        scan_tuple_list = self.ui.tableWidget_mergeScans.get_selected_scans()
+        scan_number_list = list()
+        for tup in scan_tuple_list:
+            scan_number_list.append(tup[0])
+        scan_number_list.sort()
 
-        # plot the result
-        self.ui.graphicsView_integratedPeakView.add_plot_1d(vec_x, gauss_fit4, color='red', marker='-')
+        info_str = '# Selected scans: \n'
+        info_str += '{0}'.format(scan_number_list)
 
-        # write out the result
-        background_value = popt2[3]
-        self.ui.lineEdit_background.setText('%.7f' % background_value)
+        print '[TEMP] Selected scans:\n{0}'.format(info_str)
 
         return
 
@@ -1166,15 +1295,6 @@ class MainWindow(QtGui.QMainWindow):
         # write
         user_header = str(self.ui.lineEdit_fpHeader.text())
         try:
-            # # get lattice parameters from UB tab
-            # a = float(self.ui.lineEdit_aUnitCell.text())
-            # b = float(self.ui.lineEdit_bUnitCell.text())
-            # c = float(self.ui.lineEdit_cUnitCell.text())
-            # alpha = float(self.ui.lineEdit_alphaUnitCell.text())
-            # beta = float(self.ui.lineEdit_betaUnitCell.text())
-            # gamma = float(self.ui.lineEdit_gammaUnitCell.text())
-            # lattice = absorption.Lattice(a, b, c, alpha, beta, gamma)
-
             export_absorption = self.ui.checkBox_exportAbsorptionToFP.isChecked()
 
             status, file_content = self._myControl.export_to_fullprof(exp_number, scan_number_list,
@@ -1188,6 +1308,8 @@ class MainWindow(QtGui.QMainWindow):
         except AssertionError as a_err:
             self.pop_one_button_dialog(str(a_err))
             return
+        except KeyError as key_err:
+            self.pop_one_button_dialog(str(key_err))
 
         return
 
@@ -1255,55 +1377,13 @@ class MainWindow(QtGui.QMainWindow):
 
         return
 
-    def do_integrate_peak(self):
-        """ Integrate a peak in tab peak integration
-        :return:
+    def do_integrate_single_scan(self):
         """
-        # only support the simple cuboid counts summing algorithm
-
-        # get experiment number and scan number
-        status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_exp, self.ui.lineEdit_scanIntegratePeak],
-                                                       allow_blank=False)
-        if status is False:
-            err_msg = ret_obj
-            self.pop_one_button_dialog(err_msg)
-            return
-
-        # check table
-        table_exp, table_scan = self.ui.tableWidget_peakIntegration.get_exp_info()
-        if (table_exp, table_scan) != tuple(ret_obj):
-            err_msg = 'Table has value of a different experiment/scan (%d/%d vs %d/%d). Integrate Pt. first!' \
-                      '' % (table_exp, table_scan, ret_obj[0], ret_obj[1])
-            self.pop_one_button_dialog(err_msg)
-            return
-
-        # integrate by take account of background value
-        status, ret_obj = gutil.parse_float_editors(self.ui.lineEdit_background, allow_blank=True)
-        assert status, ret_obj
-        if ret_obj is None:
-            background = 0.
-        else:
-            background = ret_obj
-        peak_intensity = self.ui.tableWidget_peakIntegration.simple_integrate_peak(background)
-
-        # write result to label
-        norm_type = str(self.ui.comboBox_ptCountType.currentText())
-        label_str = 'Experiment %d Scan %d: Peak intensity = %.7f, Normalized by %s, Background = %.7f.' \
-                    '' % (table_exp, table_scan, peak_intensity, norm_type, background)
-        self.ui.label_peakIntegraeInfo.setText(label_str)
-
-        # set value to previous table
-        self.ui.tableWidget_mergeScans.set_peak_intensity(None, table_scan, peak_intensity)
-
-        return
-
-    def do_integrate_per_pt(self):
-        """
-        Integrate and plot per Pt.
+        integrate a single scan in 'Peak Integration' tab
+        Note: this is an experimenntal replacement for do_integrate_per_pt
         :return:
         """
-        # VZ-FUTURE: consider to compare and merge with method do_plot_pt_peak()
-        # get experiment and scan number
+        # parse experiment and scan number
         status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_exp,
                                                         self.ui.lineEdit_scanIntegratePeak])
         if not status:
@@ -1312,6 +1392,7 @@ class MainWindow(QtGui.QMainWindow):
         else:
             exp_number, scan_number = ret_obj
 
+        # parse normalization type
         normalization = str(self.ui.comboBox_ptCountType.currentText())
         if normalization.count('Time') > 0:
             norm_type = 'time'
@@ -1320,7 +1401,13 @@ class MainWindow(QtGui.QMainWindow):
         else:
             norm_type = ''
 
-        # get peak center (weighted)
+        # parse scale factor
+        try:
+            intensity_scale_factor = float(self.ui.lineEdit_scaleFactorScan.text())
+        except ValueError:
+            intensity_scale_factor = 1.
+
+        # calculate peak center (weighted)
         status, ret_obj = self._myControl.find_peak(exp_number, scan_number)
         if status is False:
             error_message = ret_obj
@@ -1329,69 +1416,131 @@ class MainWindow(QtGui.QMainWindow):
         else:
             this_peak_centre = ret_obj
 
-        # scale factor
+        # mask workspace
+        mask_name = str(self.ui.comboBox_maskNames2.currentText())
+        if mask_name.lower() == 'no mask':
+            mask_name = ''
+
+        # ui.lineEdit_backgroundPts and set default in init_widgets
+        bkgd_pt_tuple = gutil.parse_integer_list(str(self.ui.lineEdit_backgroundPts.text()), 2)
+
+        # integrate peak
         try:
-            intensity_scale_factor = float(self.ui.lineEdit_scaleFactor.text())
-        except ValueError:
-            intensity_scale_factor = 1.
+            int_peak_dict = self._myControl.integrate_scan_peak(exp_number=exp_number,
+                                                                scan_number=scan_number,
+                                                                peak_centre=this_peak_centre,
+                                                                mask_name=mask_name,
+                                                                normalization=norm_type,
+                                                                scale_factor=intensity_scale_factor,
+                                                                background_pt_tuple=bkgd_pt_tuple)
+        except RuntimeError as run_error:
+            self.pop_one_button_dialog('Unable to integrate peak for scan {0} due to {1}.'
+                                       ''.format(scan_number, run_error))
+            return
+
+        # plot calculated motor position (or Pt.) - integrated intensity per Pts.
+        motor_pos_vec = int_peak_dict['motor positions']
+        pt_intensity_vec = int_peak_dict['pt intensities']
+        # print '[DB...BAT] motor position vector: {0} of type {1}'.format(motor_pos_vec, type(motor_pos_vec))
+        motor_std = motor_pos_vec.std()
+        if motor_std > 0.005:
+            self.ui.graphicsView_integratedPeakView.plot_raw_data(motor_pos_vec, pt_intensity_vec)
+        else:
+            # motor position fixed
+            # KEEP-IN-MIND:  Make this an option from
+            self.ui.graphicsView_integratedPeakView.plot_raw_data(numpy.array(range(1, len(pt_intensity_vec)+1)),
+                                                                  pt_intensity_vec)
 
-        # get masked workspace
-        mask_name = str(self.ui.comboBox_maskNames2.currentText())
-        if mask_name.startswith('No Mask'):
-            mask_name = None
-        # mask workspace?
-        mask_detectors = mask_name is not None
-
-        status, ret_obj = self._myControl.integrate_scan_peaks(exp=exp_number,
-                                                               scan=scan_number,
-                                                               peak_radius=1.0,
-                                                               peak_centre=this_peak_centre,
-                                                               merge_peaks=False,
-                                                               use_mask=mask_detectors,
-                                                               mask_ws_name=mask_name,
-                                                               normalization=norm_type,
-                                                               scale_factor=intensity_scale_factor)
-
-        # result due to error
-        if status is False:
-            error_message = ret_obj
-            self.pop_one_button_dialog(error_message)
-            return
+        if self._mySinglePeakIntegrationDialog is None:
+            self._mySinglePeakIntegrationDialog = message_dialog.MessageDialog(self)
+        self._mySinglePeakIntegrationDialog.set_peak_integration_details(motor_pos_vec, pt_intensity_vec)
+
+        # set calculated values
+        try:
+            self.ui.lineEdit_rawSinglePeakIntensity.setText('{0:.7f}'.format(int_peak_dict['simple intensity']))
+            self.ui.lineEdit_errorIntensity1.setText('{0:.7f}'.format(int_peak_dict['simple error']))
+            self.ui.lineEdit_avgBackground.setText('{0:.7f}'.format(int_peak_dict['simple background']))
+            self.ui.lineEdit_intensity2.setText('{0:.7f}'.format(int_peak_dict['intensity 2']))
+            if int_peak_dict['error 2'] is None:
+                self.ui.lineEdit_errorIntensity2.setText('inf')
+            else:
+                self.ui.lineEdit_errorIntensity2.setText('{0:.7f}'.format(int_peak_dict['error 2']))
+            self.ui.lineEdit_ptRange.setText('{0}'.format(int_peak_dict['pt_range']))
+            self.ui.lineEdit_gaussianPeakIntensity.setText('{0:.7f}'.format(int_peak_dict['gauss intensity']))
+            if int_peak_dict['gauss error'] is None:
+                self.ui.lineEdit_errorIntensity3.setText('inf')
+            else:
+                self.ui.lineEdit_errorIntensity3.setText('{0:.7f}'.format(int_peak_dict['gauss error']))
+            self.ui.tableWidget_covariance.set_matrix(int_peak_dict['covariance matrix'])
+
+            fit_param_dict = int_peak_dict['gauss parameters']
+            # {'A': 1208.4097237325959, 'x0': 32.175524426773507, 'B': 23.296505385975976, 's': 0.47196665622701633}
+            self.ui.lineEdit_peakBackground.setText('{0:.4f}'.format(fit_param_dict['B']))
+            self.ui.lineEdit_gaussA.setText('{0:.4f}'.format(fit_param_dict['A']))
+            self.ui.lineEdit_gaussSigma.setText('{0:.4f}'.format(fit_param_dict['s']))
+            self.ui.lineEdit_gaussB.setText('{0:.4f}'.format(fit_param_dict['B']))
+
+            # plot fitted Gaussian
+            fit_gauss_dict = int_peak_dict['gauss parameters']
+        except KeyError as key_err:
+            raise RuntimeError('Peak integration result dictionary has keys {0}. Error is caused by {1}.'
+                               ''.format(int_peak_dict.keys(), key_err))
+        except ValueError as value_err:
+            print '[ERROR] Unable to fit by Gaussian due to {0}.'.format(value_err)
+        else:
+            self.plot_model_data(motor_pos_vec, fit_gauss_dict)
 
-        # process result
-        pt_dict = ret_obj
-        assert isinstance(pt_dict, dict)
+        return
 
-        # clear table
-        if self.ui.tableWidget_peakIntegration.rowCount() > 0:
-            self.ui.tableWidget_peakIntegration.remove_all_rows()
+    def plot_model_data(self, vec_x, params):
+        """
+        calculate the Y value by the model and plot them.
+        the sparse X values will be expanded
+        :return:
+        """
+        # check inputs
+        assert isinstance(vec_x, numpy.ndarray), 'vec X {0} must be a numpy.ndarray but not a {1}.' \
+                                                 ''.format(vec_x, type(vec_x))
+        assert isinstance(params, dict), 'Model parameters {0} must be given by a dictionary but not by a {1}.' \
+                                         ''.format(params, type(params))
 
-        # Append new lines
-        pt_list = sorted(pt_dict.keys())
-        intensity_list = list()
-        for pt in pt_list:
-            pt_intensity = pt_dict[pt]
-            intensity_list.append(pt_intensity)
-            status, msg = self.ui.tableWidget_peakIntegration.append_pt(pt, -1, pt_intensity)
-            if not status:
-                error_msg = '[Error!] Unable to add Pt %d due to %s.' % (pt, msg)
-                self.pop_one_button_dialog(error_msg)
+        # get parameters
+        x0 = params['x0']
+        gauss_sigma = params['s']
+        gauss_a = params['A']
+        background = params['B']
+        info_str = 'Gaussian fit'
 
-        # Set up the experiment information to table
-        self.ui.tableWidget_peakIntegration.set_exp_info(exp_number, scan_number)
+        # plot the data
+        # make modelX and modelY for more fine grids
+        model_x = peak_integration_utility.get_finer_grid(vec_x, 10)
+        model_y = peak_integration_utility.gaussian_linear_background(model_x, x0, gauss_sigma,
+                                                                      gauss_a, background)
 
-        # Clear previous line and plot the Pt.
-        self.ui.graphicsView_integratedPeakView.clear_all_lines()
-        x_array = numpy.array(pt_list)
-        y_array = numpy.array(intensity_list)
-        self.ui.graphicsView_integratedPeakView.add_plot_1d(x_array, y_array,
-                                                            color='blue')
-        self.ui.graphicsView_integratedPeakView.set_smart_y_limit(y_array)
+        # plot the model
+        self.ui.graphicsView_integratedPeakView.plot_model(model_x, model_y, title=info_str)
+
+        return
+
+    def do_integrate_roi(self):
+        """
+        integrate the detector counts in the region of interest (2D) along axis-0 and axis-1 respectively.
+        and save the result (1D data) to file
+        :return:
+        """
+        exp_number = str(self.ui.lineEdit_exp.text())
+        scan_number = str(self.ui.lineEdit_run.text())
+        pt_number = str(self.ui.lineEdit_rawDataPtNo.text())
+        working_dir = str(self.ui.lineEdit_workDir.text())
+
+        msg = self.ui.graphicsView_detector2dPlot.integrate_roi_linear(exp_number, scan_number, pt_number, working_dir)
+
+        self.pop_one_button_dialog(msg)
 
         return
 
     def do_integrate_peaks(self):
-        """ Integrate selected peaks tab-merged scans.
+        """ Integrate selected peaks tab-'scan processing'.
         If any scan is not merged, then it will merge the scan first.
         Integrate peaks from the table of merged peak.
         It will so the simple cuboid integration with region of interest and background subtraction.
@@ -1445,8 +1594,9 @@ class MainWindow(QtGui.QMainWindow):
             if status is False:
                 error_msg = 'Unable to get Pt. of experiment %d scan %d due to %s.' % (exp_number, scan_number,
                                                                                        str(pt_number_list))
-                self.controller.set_peak_intensity(exp_number, scan_number, 0.)
-                self.ui.tableWidget_mergeScans.set_peak_intensity(row_number, scan_number, 0., False)
+                self.controller.set_zero_peak_intensity(exp_number, scan_number)
+                self.ui.tableWidget_mergeScans.set_peak_intensity(row_number, scan_number, 0., False,
+                                                                  integrate_method='')
                 self.ui.tableWidget_mergeScans.set_status(scan_number, error_msg)
                 continue
 
@@ -1499,7 +1649,8 @@ class MainWindow(QtGui.QMainWindow):
             if status is True:
                 hkl_value = ret_obj[0]
                 hkl_error = ret_obj[1]
-                self.ui.tableWidget_peaksCalUB.set_hkl(i_peak, hkl_value, hkl_error)
+                self.ui.tableWidget_peaksCalUB.set_hkl(i_peak, hkl_value, is_spice_hkl=False,
+                                                       error=hkl_error)
             else:
                 err_msg += ret_obj + '\n'
         # END-FOR
@@ -1512,8 +1663,8 @@ class MainWindow(QtGui.QMainWindow):
         self.ui.lineEdit_peaksIndexedBy.setText(IndexFromUB)
 
         # enable/disable push buttons
-        self.ui.pushButton_setHKL2Int.setEnabled(True)
-        self.ui.pushButton_undoSetToInteger.setEnabled(False)
+        # self.ui.pushButton_setHKL2Int.setEnabled(True)
+        # self.ui.pushButton_undoSetToInteger.setEnabled(True)
 
         return
 
@@ -1602,49 +1753,15 @@ class MainWindow(QtGui.QMainWindow):
 
         return
 
-    def do_plot_pt_peak(self):
+    def evt_change_normalization(self):
         """
         Integrate Pt. vs integrated intensity of detectors of that Pt. if it is not calculated before
         and then plot pt vs. integrated intensity on
         :return:
         """
-        # Find out the current condition including (1) absolute (2) normalized by time
-        # (3) normalized by monitor counts
-        be_norm_str = str(self.ui.comboBox_ptCountType.currentText())
-
-        norm_by_time = False
-        norm_by_monitor = False
-
-        if be_norm_str.startswith('Absolute'):
-            # no normalization
-            pass
-        elif be_norm_str.count('Time') > 0:
-            # norm by time
-            norm_by_time = True
-        elif be_norm_str.count('Monitor') > 0:
-            # norm by monitor counts
-            norm_by_monitor = True
-        else:
-            # exception!
-            raise RuntimeError('Normalization mode %s is not supported.' % be_norm_str)
-
-        # Integrate peak if the integrated peak workspace does not exist
-        # get experiment number and scan number from the table
-        exp_number, scan_number = self.ui.tableWidget_peakIntegration.get_exp_info()
-
-        mask_name = str(self.ui.comboBox_maskNames2.currentText())
-        masked = not mask_name.startswith('No Mask')
-        has_integrated = self._myControl.has_integrated_peak(exp_number, scan_number, pt_list=None,
-                                                             normalized_by_monitor=norm_by_monitor,
-                                                             normalized_by_time=norm_by_time,
-                                                             masked=masked)
-
-        # integrate and/or plot
-        if has_integrated:
-            self.plot_pt_intensity()
-        else:
-            # VZ-FUTURE: implement this new method!
-            self.do_integrate_per_pt()
+        # integrate any how
+        # self.do_integrate_per_pt()
+        self.do_integrate_single_scan()
 
         return
 
@@ -1795,34 +1912,6 @@ class MainWindow(QtGui.QMainWindow):
 
         return
 
-    def do_manual_bkgd(self):
-        """ Select background by moving indicator manually
-        :return:
-        """
-        if str(self.ui.pushButton_handPickBkgd.text()) == 'Customize Bkgd':
-            # get into customize background mode.  add an indicator to the line and make it movable
-            self.ui.graphicsView_integratedPeakView.add_background_indictor()
-
-            # modify the push buttons status
-            self.ui.pushButton_handPickBkgd.setText('Done')
-
-        elif str(self.ui.pushButton_handPickBkgd.text()) == 'Done':
-            # get out from the customize-background mode.  get the vertical indicator's position as background
-            background_value = self.ui.graphicsView_integratedPeakView.get_indicator_position(self._bkgdIndicatorKey)
-
-            # set the ground value to UI
-            self._myControl.set_background_value(background_value)
-            self.ui.lineEdit_bkgdValue.setText('%.7f' % background_value)
-
-            # modify the push button status
-            self.ui.pushButton_handPickBkgd.setText('Customize Bkgd')
-
-        else:
-            raise RuntimeError('Push button in state %s is not supported.' %
-                               str(self.ui.pushButton_handPickBkgd.text()))
-
-        return
-
     def do_mask_pt_2d(self):
         """ Mask a Pt and re-plot
         :return:
@@ -1840,11 +1929,14 @@ class MainWindow(QtGui.QMainWindow):
         # get the mask
         status, ret_obj = self._myControl.get_region_of_interest(exp, scan)
         if status is False:
+            # unable to get region of interest
             self.pop_one_button_dialog(ret_obj)
             return
+        else:
+            corner1, corner2 = ret_obj
 
         # create mask workspace
-        status, error = self._myControl.generate_mask_workspace(exp, scan, ret_obj[0], ret_obj[1])
+        status, error = self._myControl.generate_mask_workspace(exp, scan, corner1, corner2)
         if status is False:
             self.pop_one_button_dialog(error)
             return
@@ -1914,7 +2006,7 @@ class MainWindow(QtGui.QMainWindow):
         self._myControl.set_ub_matrix(exp_number=None, ub_matrix=ub_matrix)
 
         # Warning
-        self.pop_one_button_dialog('Data processing is long. Be patient!')
+        self.pop_one_button_dialog('Merging scans can take long time. Please be patient!')
 
         # Process
         row_number_list = self.ui.tableWidget_mergeScans.get_selected_rows(True)
@@ -1940,10 +2032,6 @@ class MainWindow(QtGui.QMainWindow):
                                                                 pt_num_list=[])
             # find peaks too
             status, ret_obj = self._myControl.find_peak(exp_number, scan_number)
-            if status:
-                peak_centre = ret_obj
-            else:
-                peak_centre = None
 
             # process output
             if status:
@@ -1954,15 +2042,38 @@ class MainWindow(QtGui.QMainWindow):
                 merge_status = 'Failed. Reason: %s' % ret_tup
                 merged_name = 'x'
 
-            # update table
-            self.ui.tableWidget_mergeScans.set_status(row_number, merge_status)
-            self.ui.tableWidget_mergeScans.set_ws_name(row_number, merged_name)
-            if peak_centre is not None:
-                self.ui.tableWidget_mergeScans.set_peak_centre(row_number, peak_centre)
+            # update table
+            self.ui.tableWidget_mergeScans.set_status(row_number, merge_status)
+            self.ui.tableWidget_mergeScans.set_ws_name(row_number, merged_name)
+            # if peak_centre is not None:
+            #     self.ui.tableWidget_mergeScans.set_peak_centre(row_number, peak_centre)
+
+            # Sleep for a while
+            time.sleep(0.1)
+        # END-FOR
+
+        return
+
+    def do_merge_scans_survey(self):
+        """
+        Merge each selected scans in the 'List Scans' tab to Q-sample space
+        :return:
+        """
+        # get the selected scans
+        scan_run_list = self.ui.tableWidget_surveyTable.get_selected_run_surveyed(required_size=None)
+        if len(scan_run_list) == 0:
+            self.pop_one_button_dialog('There is no run that is selected.')
+
+        # start to add scan/run to table
+        # Set table
+        scan_list = list()
+        for scan, pt in scan_run_list:
+            scan_list.append(scan)
+        scan_list.sort()
+        self.ui.tableWidget_mergeScans.append_scans(scans=scan_list, allow_duplicate_scans=False)
 
-            # Sleep for a while
-            time.sleep(0.1)
-        # END-FOR
+        # switch tab
+        self.ui.tabWidget.setCurrentIndex(MainWindow.TabPage['Scans Processing'])
 
         return
 
@@ -1986,6 +2097,26 @@ class MainWindow(QtGui.QMainWindow):
 
         return
 
+    def do_refine_ub_cal_indexed_peaks(self):
+        """
+        refine UB matrix by indexed peaks with HKL calculated
+        :return:
+        """
+        # refine UB matrix by indexed peak
+        peak_info_list = self._build_peak_info_list(zero_hkl=False, is_spice=False)
+
+        # Refine UB matrix
+        try:
+            self._myControl.refine_ub_matrix_indexed_peaks(peak_info_list)
+        except AssertionError as error:
+            self.pop_one_button_dialog(str(error))
+            return
+
+        # show result
+        self._show_refined_ub_result()
+
+        return
+
     def do_refine_ub_lattice(self):
         """
         Calculate UB matrix constrained by lattice parameters
@@ -2000,6 +2131,65 @@ class MainWindow(QtGui.QMainWindow):
 
         return
 
+    def load_project(self, project_file_name):
+        """
+        Load a saved project with all the setup loaded to memory
+        :param project_file_name:
+        :return:
+        """
+        assert isinstance(project_file_name, str), 'Project file name %s must be a string but not %s.' \
+                                                   '' % (str(project_file_name), type(project_file_name))
+        assert os.path.exists(project_file_name), 'Project file "%s" cannot be found.' % project_file_name
+
+        # load project
+        ui_dict = self._myControl.load_project(project_file_name)
+
+        # get experiment number and IPTS number
+        exp_number = int(ui_dict['exp number'])
+        self.ui.lineEdit_exp.setText(str(exp_number))
+        if 'ipts' in ui_dict and ui_dict['ipts'] is not None:
+            self.ui.lineEdit_iptsNumber.setText(str(ui_dict['ipts']))
+
+        # set the UI parameters to GUI
+        try:
+            self.ui.lineEdit_localSpiceDir.setText(ui_dict['local spice dir'])
+            self.ui.lineEdit_workDir.setText(ui_dict['work dir'])
+            self.ui.lineEdit_surveyStartPt.setText(ui_dict['survey start'])
+            self.ui.lineEdit_surveyEndPt.setText(ui_dict['survey stop'])
+
+            # now try to call some actions
+            self.do_apply_setup()
+            self.do_set_experiment()
+
+        except KeyError:
+            print '[Error] Some field cannot be found.'
+
+        # set experiment configurations
+        # set sample distance
+        if 'det_sample_distance' in ui_dict and ui_dict['det_sample_distance'] is not None:
+            det_sample_distance = float(ui_dict['det_sample_distance'])
+            self.ui.lineEdit_infoDetSampleDistance.setText(str(det_sample_distance))
+            self._myControl.set_default_detector_sample_distance(det_sample_distance)
+
+        # set user-specified wave length
+        if 'wave_length' in ui_dict and ui_dict['wave_length'] is not None:
+            wave_length = float(ui_dict['wave_length'])
+            self.ui.lineEdit_infoWavelength.setText(str(wave_length))
+            self._myControl.set_user_wave_length(exp_number, wave_length)
+
+        if 'det_center' in ui_dict and ui_dict['det_center'] is not None:
+            det_center_str = ui_dict['det_center'].strip()
+            terms = det_center_str.split(',')
+            center_row = int(terms[0].strip())
+            center_col = int(terms[1].strip())
+            self.ui.lineEdit_infoDetCenter.setText('{0}, {1}'.format(center_row, center_col))
+            self._myControl.set_detector_center(exp_number, center_row, center_col)
+
+        # TODO/ISSUE/NOW/TODAY - Shall pop out a dialog to notify the completion
+        print '[INFO] Project from file {0} is loaded.'.format(project_file_name)
+
+        return
+
     # add slot for UB refinement configuration window's signal to connect to
     @QtCore.pyqtSlot(int)
     def refine_ub_lattice(self, val):
@@ -2122,8 +2312,10 @@ class MainWindow(QtGui.QMainWindow):
         """
         # get experiment number
         status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_exp])
-        assert status, ret_obj
-        exp_number = ret_obj[0]
+        if not status:
+            raise RuntimeError(ret_obj)
+        else:
+            exp_number = ret_obj[0]
 
         # reset all rows back to SPICE HKL
         num_rows = self.ui.tableWidget_peaksCalUB.rowCount()
@@ -2172,73 +2364,6 @@ class MainWindow(QtGui.QMainWindow):
 
         return
 
-    def do_add_k_shift_vector(self):
-        """ Add a k-shift vector
-        :return:
-        """
-        # parse the k-vector
-        status, ret_obj = gutil.parse_float_editors([self.ui.lineEdit_kX, self.ui.lineEdit_kY, self.ui.lineEdit_kZ],
-                                                    allow_blank=False)
-        if status is False:
-            error_message = ret_obj
-            self.pop_one_button_dialog(error_message)
-            return
-        else:
-            k_x, k_y, k_z = ret_obj
-
-        # add to controller
-        k_index = self._myControl.add_k_shift_vector(k_x, k_y, k_z)
-
-        # add to table and combo-box
-        self.ui.tableWidget_kShift.add_k_vector(k_index, k_x, k_y, k_z)
-
-        combo_message = '%d: (%.5f, %.5f, %.5f)' % (k_index, k_x, k_y, k_z)
-        self.ui.comboBox_kVectors.addItem(combo_message)
-
-        return
-
-    def do_apply_k_shift(self):
-        """ Apply k-shift to selected reflections
-        :return:
-        """
-        # get the selected scans
-        scan_list = list()
-        selected_row_numbers = self.ui.tableWidget_mergeScans.get_selected_rows(True)
-        for row_index in selected_row_numbers:
-            scan_number = self.ui.tableWidget_mergeScans.get_scan_number(row_index)
-            scan_list.append(scan_number)
-
-        # get the k-vector
-        k_shift_message = str(self.ui.comboBox_kVectors.currentText())
-        k_index = int(k_shift_message.split(':')[0])
-
-        # set to controller
-        self._myControl.set_k_shift(scan_list, k_index)
-
-        # set to table
-        for row_index in selected_row_numbers:
-            self.ui.tableWidget_mergeScans.set_k_shift_index(row_index, k_index)
-
-        return
-
-    def do_apply_roi(self):
-        """ Save current selection of region of interest
-        :return:
-        """
-        lower_left_c, upper_right_c = self.ui.graphicsView_detector2dPlot.get_roi()
-        # at the very beginning, the lower left and upper right are same
-        if lower_left_c[0] == upper_right_c[0] or lower_left_c[1] == upper_right_c[1]:
-            return
-
-        status, par_val_list = gutil.parse_integers_editors([self.ui.lineEdit_exp, self.ui.lineEdit_run])
-        assert status, str(par_val_list)
-        exp_number = par_val_list[0]
-        scan_number = par_val_list[1]
-
-        self._myControl.set_roi(exp_number, scan_number, lower_left_c, upper_right_c)
-
-        return
-
     def do_save_survey(self):
         """
         Save the survey to a file
@@ -2291,19 +2416,33 @@ class MainWindow(QtGui.QMainWindow):
         Purpose: select all peaks in table tableWidget_peaksCalUB
         :return:
         """
-        if not self._ubPeakTableFlag:
-            # turn to deselect all
-            self.ui.tableWidget_peaksCalUB.select_all_rows(self._ubPeakTableFlag)
-        elif self.ui.checkBox_ubNuclearPeaks.isChecked() is False:
-            # all peaks are subjected to select
-            self.ui.tableWidget_peaksCalUB.select_all_rows(self._ubPeakTableFlag)
-        else:
-            # only nuclear peaks to get selected
-            self.ui.tableWidget_peaksCalUB.select_all_nuclear_peaks()
-        # END-IF-ELSE
+        if self.ui.radioButton_ubSelectAllScans.isChecked() and self._ubPeakTableFlag != 0:
+            self.ui.tableWidget_peaksCalUB.select_all_rows(True)
+            self._ubPeakTableFlag = 0
+        elif self.ui.radioButton_ubSelectNoScan.isChecked() and self._ubPeakTableFlag != 1:
+            self.ui.tableWidget_peaksCalUB.select_all_rows(False)
+            self._ubPeakTableFlag = 1
+        elif self.ui.radioButton_ubAdvancedSelection.isChecked() and self._ubPeakTableFlag != 2:
+            # advanced
+            import FindUBUtility
+            self._selectUBScanDialog = FindUBUtility.SelectUBMatrixScansDialog(self)
+            self._selectUBScanDialog.show()
+            self._ubPeakTableFlag = 2
+        # END-IF
 
-        # revert the flag
-        self._ubPeakTableFlag = not self._ubPeakTableFlag
+        # if not self._ubPeakTableFlag:
+        #     # turn to deselect all
+        #     self.ui.tableWidget_peaksCalUB.select_all_rows(self._ubPeakTableFlag)
+        # elif self.ui.checkBox_ubNuclearPeaks.isChecked() is False:
+        #     # all peaks are subjected to select
+        #     self.ui.tableWidget_peaksCalUB.select_all_rows(self._ubPeakTableFlag)
+        # else:
+        #     # only nuclear peaks to get selected
+        #     self.ui.tableWidget_peaksCalUB.select_all_nuclear_peaks()
+        # # END-IF-ELSE
+        #
+        # # revert the flag
+        # self._ubPeakTableFlag = not self._ubPeakTableFlag
 
         return
 
@@ -2354,10 +2493,64 @@ class MainWindow(QtGui.QMainWindow):
 
         return
 
+    def do_set_detector_size(self):
+        """
+        set the detector size to controller
+        :return:
+        """
+        det_size_str = str(self.ui.comboBox_detectorSize.currentText())
+
+        if det_size_str.count('256') > 0:
+            # 256 by 256 pixels
+            det_size_row = 256
+            det_size_col = 256
+        elif det_size_str.count('512') > 0:
+            # 512 x 512
+            det_size_row = 512
+            det_size_col = 512
+        else:
+            # unsupported case yet
+            raise NotImplementedError('Detector with size {0} is not supported yet.'.format(det_size_str))
+
+        # set to controller
+        self._myControl.set_detector_geometry(det_size_row, det_size_col)
+
+        return
+
+    def do_set_ipts_number(self):
+        """
+        set IPTS number
+        :return:
+        """
+        # get IPTS number
+        status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_iptsNumber])
+        if status:
+            # a valid IPTS number
+
+            raise NotImplementedError('The following section commented out now will be implemented when IPTS is ready.')
+            # ipts_number = ret_obj[0]
+            # search archive for available experiment number under this IPTS
+            # status, ret_obj = self._myControl.check_ipts(ipts_number=ipts_number)
+            # if status:
+            #     exp_number_list = ret_obj
+            #     self._iptsNumber = ipts_number
+            #     self.ui.comboBox_expInIPTS.clear()
+            #     for exp_number in exp_number_list:
+            #         self.ui.comboBox_expInIPTS.addItem(str(exp_number))
+            # else:
+            #     self.pop_one_button_dialog('Unable to locate IPTS {0} due to {1}'.format(ipts_number, ret_obj))
+            #     return
+        else:
+            # error
+            self.pop_one_button_dialog('User specified IPTS number {0} is not correct.'
+                                       ''.format(str(self.ui.lineEdit_iptsNumber.text())))
+            return
+
     def do_set_experiment(self):
         """ Set experiment
         :return:
         """
+        # get exp number
         status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_exp])
         if status:
             # new experiment number
@@ -2370,12 +2563,18 @@ class MainWindow(QtGui.QMainWindow):
             # set the new experiment number
             self._myControl.set_exp_number(exp_number)
             self.ui.lineEdit_exp.setStyleSheet('color: black')
-            self.setWindowTitle('%s: Experiment %d' % (self._baseTitle, exp_number))
+            self.setWindowTitle('Experiment %d' % exp_number)
 
             # try to set the default
-            default_data_dir = '/HFIR/HB3A/exp%d/Datafiles' % exp_number
+            if self._iptsNumber is not None:
+                default_data_dir = '/HFIR/HB3A/IPTS-{0}/exp{1}/Datafiles'.format(self._iptsNumber, exp_number)
+            else:
+                default_data_dir = '/HFIR/HB3A/exp{0}/Datafiles'.format(exp_number)
             if os.path.exists(default_data_dir):
+                # set the directory in
                 self.ui.lineEdit_localSpiceDir.setText(default_data_dir)
+                # find out the detector type
+                status, ret_obj = self._myControl.find_detector_size(default_data_dir, exp_number)
 
         else:
             err_msg = ret_obj
@@ -2418,19 +2617,62 @@ class MainWindow(QtGui.QMainWindow):
         Change to these HKL values is only related to GUI, i.e., the table
         :return:
         """
+        # get the current index source
+        hkl_type_str = str(self.ui.comboBox_hklType.currentText())
+        if hkl_type_str.lower().count('spice') > 0:
+            # set spice HKL to integer
+            is_spice = True
+        else:
+            is_spice = False
+
         # store the current value
         self.ui.tableWidget_peaksCalUB .store_current_indexing()
 
         # set the index to integer
         num_rows = self.ui.tableWidget_peaksCalUB.rowCount()
         for row_index in range(num_rows):
-            m_h, m_l, m_k = self.ui.tableWidget_peaksCalUB.get_hkl(row_index)
-            peak_indexing, round_error = hb3a_util.convert_hkl_to_integer(m_h, m_l, m_k, MAGNETIC_TOL)
-            self.ui.tableWidget_peaksCalUB.set_hkl(row_index, peak_indexing, round_error)
+            try:
+                m_h, m_l, m_k = self.ui.tableWidget_peaksCalUB.get_hkl(row_index, is_spice_hkl=is_spice)
+                peak_indexing, round_error = hb3a_util.convert_hkl_to_integer(m_h, m_l, m_k, MAGNETIC_TOL)
+                self.ui.tableWidget_peaksCalUB.set_hkl(row_index, peak_indexing, is_spice, round_error)
+            except RuntimeError as run_err:
+                scan_number, pt_number = self.ui.tableWidget_peaksCalUB.get_scan_pt(row_index)
+                print '[ERROR] Unable to convert HKL to integer for scan {0} due to {1}.' \
+                      ''.format(scan_number, run_err)
+        # END-FOR
 
         # disable the set to integer button and enable the revert/undo button
-        self.ui.pushButton_setHKL2Int.setEnabled(False)
-        self.ui.pushButton_undoSetToInteger.setEnabled(True)
+        # self.ui.pushButton_setHKL2Int.setEnabled(False)
+        # self.ui.pushButton_undoSetToInteger.setEnabled(True)
+
+        return
+
+    def do_toggle_table_integration(self):
+        """
+        change the type
+        :return:
+        """
+        exp_number = int(self.ui.lineEdit_exp.text())
+
+        integrate_type = self.ui.tableWidget_mergeScans.get_integration_type()
+        if integrate_type == 'simple':
+            integrate_type = 'mixed'
+        elif integrate_type == 'mixed':
+            integrate_type = 'gaussian'
+        else:
+            integrate_type = 'simple'
+
+        for i_row in range(self.ui.tableWidget_mergeScans.rowCount()):
+            scan_number = self.ui.tableWidget_mergeScans.get_scan_number(i_row)
+            peak_info_obj = self._myControl.get_peak_info(exp_number, scan_number)
+            try:
+                intensity1, error1 = peak_info_obj.get_intensity(integrate_type, False)
+                intensity2, error2 = peak_info_obj.get_intensity(integrate_type, True)
+                self.ui.tableWidget_mergeScans.set_peak_intensity(i_row, intensity1, intensity2, error2, integrate_type)
+            except RuntimeError as run_err:
+                print '[ERROR] Unable to get peak intensity of scan {0} due to {1}.' \
+                      ''.format(self.ui.tableWidget_mergeScans.get_scan_number(i_row), run_err)
+        # END-FOR
 
         return
 
@@ -2439,12 +2681,19 @@ class MainWindow(QtGui.QMainWindow):
         After the peaks' indexing are set to integer, undo the action (i.e., revert to the original value)
         :return:
         """
+        # get the column
+        hkl_type = str(self.ui.comboBox_hklType.currentText())
+        if hkl_type.lower().count('spice') > 0:
+            is_spice = True
+        else:
+            is_spice = False
+
         # restore the value
-        self.ui.tableWidget_peaksCalUB.restore_cached_indexing()
+        self.ui.tableWidget_peaksCalUB.restore_cached_indexing(is_spice)
 
         # enable and disable the buttons
-        self.ui.pushButton_setHKL2Int.setEnabled(True)
-        self.ui.pushButton_undoSetToInteger.setEnabled(False)
+        # self.ui.pushButton_setHKL2Int.setEnabled(True)
+        # self.ui.pushButton_undoSetToInteger.setEnabled(False)
 
         return
 
@@ -2638,6 +2887,38 @@ class MainWindow(QtGui.QMainWindow):
 
         return
 
+    def do_show_integration_details(self):
+        """
+        show the details (in table) about the integration of scans
+        :return:
+        """
+        import PeaksIntegrationReport
+
+        # check whether the integration information table
+        if self._peakIntegrationInfoWindow is None:
+            self._peakIntegrationInfoWindow = PeaksIntegrationReport.PeaksIntegrationReportDialog(self)
+
+        # show
+        self._peakIntegrationInfoWindow.show()
+
+        # report
+        report_dict = self.generate_peaks_integration_report()
+        self._peakIntegrationInfoWindow.set_report(report_dict)
+
+        return
+
+    def do_show_single_peak_integration(self):
+        """
+        pop out a dialog box to show the detailed integration information
+        :return:
+        """
+        if self._mySinglePeakIntegrationDialog is None:
+            self._mySinglePeakIntegrationDialog = message_dialog.MessageDialog(self)
+
+        self._mySinglePeakIntegrationDialog.show()
+
+        return
+
     def do_show_spice_file(self):
         """
         Show SPICE file in a window
@@ -2679,8 +2960,9 @@ class MainWindow(QtGui.QMainWindow):
         try:
             scan_number = int(str(self.ui.lineEdit_run.text()))
         except ValueError as val_err:
-            self.pop_one_button_dialog('Scan number %s in raw-data-view-tab is invalid. Error: %s'
-                                       '' % str(self.ui.lineEdit_run.text()), str(val_err))
+            error_msg = 'Scan number {0} in raw-data-view-tab is invalid. FYI: {1}.' \
+                        ''.format(self.ui.lineEdit_run.text(), val_err)
+            self.pop_one_button_dialog(error_msg)
             return
 
         # get spice file
@@ -2874,10 +3156,11 @@ class MainWindow(QtGui.QMainWindow):
 
     def do_view_data_3d(self):
         """
-        View merged scan data in 3D after FindPeaks
+        View merged scan data in 3D after FindPeaks.
         :return:
         """
         # get experiment and scan number
+        scan_number = self.ui.tableWidget_peaksCalUB.get_selected_scans()
         status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_exp,
                                                         self.ui.lineEdit_scanNumber])
         if status:
@@ -3012,6 +3295,10 @@ class MainWindow(QtGui.QMainWindow):
             return
 
         max_number = int(self.ui.lineEdit_numSurveyOutput.text())
+
+        # ignore the situation that this line edit is cleared
+        if max_number <= 0:
+            return
         if max_number != self.ui.tableWidget_surveyTable.rowCount():
             # re-show survey
             self.ui.tableWidget_surveyTable.remove_all_rows()
@@ -3019,6 +3306,30 @@ class MainWindow(QtGui.QMainWindow):
 
         return
 
+    def generate_peaks_integration_report(self):
+        """
+        generate a report for all integrated peaks
+        :return:
+        """
+        # get experiment number
+        exp_number = int(self.ui.lineEdit_exp.text())
+
+        # get all the selected peaks from table
+        row_number_list = self.ui.tableWidget_mergeScans.get_selected_rows()
+
+        # collection all the information
+        report_dict = dict()
+        print '[DB] Selected rows: {0}'.format(row_number_list)
+        for row_number in row_number_list:
+            scan_number = self.ui.tableWidget_mergeScans.get_scan_number(row_number)
+            peak_info = self._myControl.get_peak_info(exp_number, scan_number)
+            peak_integrate_dict = peak_info.generate_integration_report()
+            report_dict[scan_number] = peak_integrate_dict
+            print '[DB] Report Scan {0}. Keys: {1}'.format(scan_number, peak_integrate_dict.keys())
+        # END-FOR
+
+        return report_dict
+
     def get_ub_from_text(self):
         """ Purpose: Set UB matrix in use from plain text edit plainTextEdit_ubInput.
         Requirements:
@@ -3089,58 +3400,7 @@ class MainWindow(QtGui.QMainWindow):
         self._myControl.set_working_directory(str(self.ui.lineEdit_workDir.text()))
         self._myControl.set_server_url(str(self.ui.lineEdit_url.text()))
 
-        return
-
-    def ui_apply_lorentz_correction_mt(self):
-        """
-        Apply Lorentz corrections to the integrated peak intensities of all the selected peaks
-        at the UI level
-        :return:
-        """
-        # get experiment number
-        exp_number = int(self.ui.lineEdit_exp.text())
-
-        # select rows
-        selected_rows = self.ui.tableWidget_mergeScans.get_selected_rows(True)
-
-        # apply for each row selected for Lorentz correction
-        error_message = ''
-        for row_number in selected_rows:
-            # get scan number
-            scan_number = self.ui.tableWidget_mergeScans.get_scan_number(row_number)
-            # get peak information object
-            peak_info_obj = self._myControl.get_peak_info(exp_number, scan_number)
-            if peak_info_obj is None:
-                error_message += 'Unable to get peak information from scan %d\n' % scan_number
-                continue
-            # get intensity
-            peak_intensity = peak_info_obj.get_intensity()
-            # get Q-vector of the peak center and calculate |Q| from it
-            q = peak_info_obj.get_peak_centre_v3d().norm()
-            # get wave length
-            wavelength = self._myControl.get_wave_length(exp_number, [scan_number])
-            self.ui.tableWidget_mergeScans.set_wave_length(row_number, wavelength)
-            # get motor step (choose from omega, phi and chi)
-            try:
-                motor_move_tup = self._myControl.get_motor_step(exp_number, scan_number)
-            except RuntimeError as run_err:
-                self.ui.tableWidget_mergeScans.set_status(row_number, str(run_err))
-                continue
-            except AssertionError as ass_err:
-                self.ui.tableWidget_mergeScans.set_status(row_number, str(ass_err))
-                continue
-            # set motor information (the moving motor)
-            self.ui.tableWidget_mergeScans.set_motor_info(row_number, motor_move_tup)
-            motor_step = motor_move_tup[1]
-            # apply the Lorentz correction to the intensity
-            corrected = self._myControl.apply_lorentz_correction(peak_intensity, q, wavelength, motor_step)
-
-            self.ui.tableWidget_mergeScans.set_peak_intensity(row_number, corrected, lorentz_corrected=True)
-            self._myControl.set_peak_intensity(exp_number, scan_number, corrected)
-        # END-FOR (row_number)
-
-        if len(error_message) > 0:
-            self.pop_one_button_dialog(error_message)
+        print '[INFO] Session {0} has been loaded.'.format(filename)
 
         return
 
@@ -3181,7 +3441,6 @@ class MainWindow(QtGui.QMainWindow):
 
         # Experiment
         save_dict['lineEdit_exp'] = str(self.ui.lineEdit_exp.text())
-        save_dict['lineEdit_scanNumber'] = self.ui.lineEdit_scanNumber.text()
 
         # Lattice
         save_dict['lineEdit_a'] = str(self.ui.lineEdit_a.text())
@@ -3193,7 +3452,6 @@ class MainWindow(QtGui.QMainWindow):
 
         # Merge scan
         save_dict['lineEdit_listScansSliceView'] = str(self.ui.lineEdit_listScansSliceView.text())
-        save_dict['lineEdit_baseMergeMDName'] = str(self.ui.lineEdit_baseMergeMDName.text())
 
         # Save to csv file
         if filename is None:
@@ -3269,11 +3527,12 @@ class MainWindow(QtGui.QMainWindow):
         h, k, l = peak_info.get_hkl(user_hkl=False)
         q_x, q_y, q_z = peak_info.get_peak_centre()
         m1 = self._myControl.get_sample_log_value(exp_number, scan_number, 1, '_m1')
+        # TODO/ISSUE/NOW consider user specified
         wave_length = hb3a_util.convert_to_wave_length(m1_position=m1)
 
         # Set to table
-        status, err_msg = self.ui.tableWidget_peaksCalUB.append_row(
-            [scan_number, -1, h, k, l, q_x, q_y, q_z, False, m1, wave_length, ''])
+        status, err_msg = self.ui.tableWidget_peaksCalUB.add_peak(scan_number, (h, k, l), (q_x, q_y, q_z), m1,
+                                                                  wave_length)
         if status is False:
             self.pop_one_button_dialog(err_msg)
 
@@ -3310,6 +3569,19 @@ class MainWindow(QtGui.QMainWindow):
         lattice_gamma = str(self.ui.lineEdit_gamma.text())
         settings.setValue('gamma', lattice_gamma)
 
+        # calibrated instrument configurations
+        user_wave_length = str(self.ui.lineEdit_userWaveLength.text())
+        settings.setValue('wave_length', user_wave_length)
+
+        det_row_center = str(self.ui.lineEdit_detCenterPixHorizontal.text())
+        settings.setValue('row_center', det_row_center)
+
+        det_col_center = str(self.ui.lineEdit_detCenterPixVertical.text())
+        settings.setValue('col_center', det_col_center)
+
+        det_sample_distance_str = str(self.ui.lineEdit_userDetSampleDistance.text())
+        settings.setValue('det_sample_distance', det_sample_distance_str)
+
         # last project
         last_1_project_path = str(self.ui.label_last1Path.text())
         settings.setValue('last1path', last_1_project_path)
@@ -3348,6 +3620,19 @@ class MainWindow(QtGui.QMainWindow):
             lattice_gamma = settings.value('gamma')
             self.ui.lineEdit_gamma.setText(str(lattice_gamma))
 
+            # calibrated instrument configurations
+            user_wave_length = settings.value('wave_length')
+            self.ui.lineEdit_userWaveLength.setText(user_wave_length)
+
+            det_row_center = settings.value('row_center')
+            self.ui.lineEdit_detCenterPixHorizontal.setText(det_row_center)
+
+            det_col_center = settings.value('col_center')
+            self.ui.lineEdit_detCenterPixVertical.setText(det_col_center)
+
+            det_sample_distance = settings.value('det_sample_distance')
+            self.ui.lineEdit_userDetSampleDistance.setText(det_sample_distance)
+
             # last project
             last_1_project_path = str(settings.value('last1path'))
             self.ui.label_last1Path.setText(last_1_project_path)
@@ -3417,8 +3702,15 @@ class MainWindow(QtGui.QMainWindow):
         raw_det_data = self._myControl.get_raw_detector_counts(exp_no, scan_no, pt_no)
         # raw_det_data = numpy.rot90(raw_det_data, 1)
         self.ui.graphicsView_detector2dPlot.clear_canvas()
-        # TODO/FIXME - changed to 512 from 256 as prototype.  Should be via configuration
-        self.ui.graphicsView_detector2dPlot.add_plot_2d(raw_det_data, x_min=0, x_max=512, y_min=0, y_max=512,
+        # get the configuration of detector from GUI
+        #  FIXME/TODO/ISSUE/NOW/TODAY - use the detector size wrong!
+        if 0:
+            ret_obj = gutil.parse_integer_list(str(self.ui.lineEdit_detectorGeometry.text()), expected_size=2)
+            x_max, y_max = ret_obj
+        else:
+            x_max, y_max = 256, 256
+
+        self.ui.graphicsView_detector2dPlot.add_plot_2d(raw_det_data, x_min=0, x_max=x_max, y_min=0, y_max=y_max,
                                                         hold_prev_image=False)
         status, roi = self._myControl.get_region_of_interest(exp_no, scan_number=None)
         if status:
@@ -3481,53 +3773,53 @@ class MainWindow(QtGui.QMainWindow):
 
         elif mode == 1:
             # receive signal from the end of processing one peak: complete the row
-            # get row number
+            # get the peak object
+            peak_info_obj = self._myControl.get_peak_info(exp_number, scan_number)
+
+            # get row number to set up the table
             try:
                 row_number = self.ui.tableWidget_mergeScans.get_row_by_scan(scan_number)
             except RuntimeError as run_err:
-                self.pop_one_button_dialog(str(run_err))
-                return
+                raise RuntimeError('Unable to find scan {0} in Peak-Processing table due to {1}.'
+                                   ''.format(scan_number, run_err))
 
-            # gather values for updating
-            intensity = sig_value
+            # get peak: simple summation intensity
+            intensity, int_std_dev = peak_info_obj.get_intensity('simple intensity', False)
 
             # check intensity value
             is_error = False
             if intensity < 0:
                 # set to status
-                error_msg = 'Negative intensity: %.3f' % intensity
+                error_msg = 'Negative intensity (simple): %.3f' % intensity
                 self.ui.tableWidget_mergeScans.set_status(row_number=row_number, status=error_msg)
                 # reset intensity to 0.
                 intensity = 0.
                 is_error = True
-
-            if len(peak_centre) != 3:
-                self.pop_one_button_dialog('Peak centre %s is not correct.' % str(peak_centre))
-                return
-
-            # set the calculated peak intensity to _peakInfoDict
-            status, error_msg = self._myControl.set_peak_intensity(exp_number, scan_number, intensity)
-            if status:
-                # set the value to table
-                self.ui.tableWidget_mergeScans.set_peak_intensity(row_number=row_number,
-                                                                  peak_intensity=intensity,
-                                                                  lorentz_corrected=False)
-                self.ui.tableWidget_mergeScans.set_peak_centre(row_number=row_number,
-                                                               peak_centre=peak_centre)
-                if is_error:
-                    self.ui.tableWidget_mergeScans.set_status(row_number, 'Intensity Error')
-                else:
-                    self.ui.tableWidget_mergeScans.set_status(row_number, 'Good')
-
+                int_std_dev = 0.
+
+            # get the corrected value
+            corrected_intensity = intensity * peak_info_obj.lorentz_correction_factor
+            corrected_std_dev = int_std_dev * peak_info_obj.lorentz_correction_factor
+
+            # status, error_msg = self._myControl.set_peak_intensity(exp_number, scan_number, intensity)
+            # if status:
+            #     # set the value to table
+            self.ui.tableWidget_mergeScans.set_peak_intensity(row_number=row_number,
+                                                              peak_intensity=intensity,
+                                                              corrected_intensity=corrected_intensity,
+                                                              standard_error=corrected_std_dev,
+                                                              integrate_method='simple')
+
+            if is_error:
+                self.ui.tableWidget_mergeScans.set_status(row_number, 'Integration Error')
             else:
-                self._errorMessageEnsemble += error_msg + '\n'
-                self.ui.tableWidget_mergeScans.set_status(row_number, error_msg)
+                self.ui.tableWidget_mergeScans.set_status(row_number, 'Integrated')
 
         elif mode == 2:
             # get signal from the end of all selected scans being integrated
 
             # apply Lorentz correction
-            self.ui_apply_lorentz_correction_mt()
+            # self.ui_apply_lorentz_correction_mt()
 
             # set progress bar
             progress = int(sig_value+0.5)
@@ -3581,12 +3873,12 @@ class MainWindow(QtGui.QMainWindow):
         # set intensity, state to table
         if mode == 0:
             # error message
-            self.ui.tableWidget_mergeScans.set_peak_intensity(row_number=row_number, peak_intensity=0.,
-                                                              lorentz_corrected=False)
+            self.ui.tableWidget_mergeScans.set_peak_intensity(row_number, peak_intensity=0., corrected_intensity=0.,
+                                                              standard_error=0., integrate_method='simple')
             self.ui.tableWidget_mergeScans.set_status(row_number=row_number, status=message)
 
             # set peak value
-            status, ret_message = self._myControl.set_peak_intensity(exp_number, scan_number, 0.)
+            status, ret_message = self._myControl.set_zero_peak_intensity(exp_number, scan_number)
             if not status:
                 self.pop_one_button_dialog(ret_message)
 
@@ -3615,12 +3907,23 @@ class MainWindow(QtGui.QMainWindow):
         peak_info = self._myControl.get_peak_info(exp_number, scan_number)
         assert isinstance(peak_info, r4c.PeakProcessRecord)
 
-        # retrieve and set HKL from spice table
-        # peak_info.retrieve_hkl_from_spice_table()
-
         # add to table
         self.set_ub_peak_table(peak_info)
 
         return
 
-    # END-OF-DEFINITION (MainWindow)
+    @property
+    def ub_matrix_processing_table(self):
+        """
+        return the handler to the UB matrix
+        :return:
+        """
+        return self.ui.tableWidget_peaksCalUB
+
+    @property
+    def working_directory(self):
+        """
+        return the current working directory
+        :return:
+        """
+        return self._myControl._workDir