Commit 419dc1e4 authored by Damien Naudet's avatar Damien Naudet

Fit refactoring.

parent af50e6c2
......@@ -37,7 +37,7 @@ from ...io.FitH5 import FitH5Writer, FitH5QAxis
from ..widgets.Containers import GroupBox
from ..widgets.Input import StyledLineEdit
from ..widgets.FileChooser import FileChooser
from ...process.peak_fit import peak_fit, FitTypes
from ...process.peak_fit import PeakFitter, FitTypes
class RangeWidget(Qt.QWidget):
......@@ -178,9 +178,11 @@ class FitWidget(Qt.QDialog):
def __onAccept(self):
self.__fitFile = None
results = peak_fit(self.__qspaceFile,
fit_type=self.__fitType,
roiIndices=self.__roiIndices)
fitter = PeakFitter(self.__qspaceFile,
fit_type=self.__fitType,
roi_indices=self.__roiIndices)
results = fitter.peak_fit()
with FitH5Writer(self.__selectedFile, mode='w') as fitH5:
entry = results.entry
......
......@@ -298,7 +298,7 @@ class FitH5(XsocsH5Base):
header_process.append(process)
header_list.append('status_' + axis)
header = ' '.join(header_process) + '\n' + ' '.join(header_list)
header = '; '.join(header_process) + '\n' + '; '.join(header_list)
results = np.zeros((len(x), len(header_list)))
......@@ -325,7 +325,8 @@ class FitH5(XsocsH5Base):
results,
fmt='%.10g',
header=header,
comments='')
comments='',
delimiter='; ')
class FitH5Writer(FitH5):
......
......@@ -103,3 +103,18 @@ def centroid(x, y, p):
idx = np.abs(x - com).argmin()
i_max = y.max()
return [y[idx], com, i_max]
def _gauss_first_guess(x, y):
i_max = y.argmax()
y_max = y[i_max]
p1 = x[i_max]
i_fwhm = np.where(y >= y_max / 2.)[0]
fwhm = (x[1] - x[0]) * len(i_fwhm)
p2 = fwhm / np.sqrt(2 * np.log(2)) # 2.35482
p0 = y_max * np.sqrt(2 * np.pi) * p2
return [p0, p1, p2]
if __name__ == '__main__':
pass
#!/usr/bin/python
# coding: utf8
# /*##########################################################################
#
# Copyright (c) 2015-2016 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ###########################################################################*/
from __future__ import absolute_import
__authors__ = ["D. Naudet"]
__date__ = "01/06/2016"
__license__ = "MIT"
from collections import OrderedDict
class FitResult(object):
"""
Fit results
"""
_AXIS = QX_AXIS, QY_AXIS, QZ_AXIS = range(3)
_AXIS_NAMES = ('qx', 'qy', 'qz')
def __init__(self, entry,
q_x, q_y, q_z,
sample_x, sample_y):
super(FitResult, self).__init__()
self._entry = entry
self._sample_x = sample_x
self._sample_y = sample_y
self._q_x = q_x
self._q_y = q_y
self._q_z = q_z
self._processes = OrderedDict()
def processes(self):
"""
Returns the process names
:return:
"""
return self._processes.keys()
def params(self, process):
return self._get_process(process, create=False)['params'].keys()
def status(self, process, axis):
assert axis in self._AXIS
process = self._get_process(process, create=False)
return process['status'][self._AXIS_NAMES[axis]]
def qx_status(self, process):
"""
Returns qx fit status the given process
:param process:
:return:
"""
return self.status(process, self.QX_AXIS)
def qy_status(self, process):
"""
Returns qy fit status the given process
:param process:
:return:
"""
return self.status(process, self.QY_AXIS)
def qz_status(self, process):
"""
Returns qz fit status the given process
:param process:
:return:
"""
return self.status(process, self.QZ_AXIS)
def results(self, process, param, axis=None):
"""
Returns the fitted parameter results for a given process.
:param process: process name
:param param: param name
:param axis: if provided, returns only the result for the given axis
:return:
"""
param = self._get_param(process, param, create=False)
if axis is not None:
assert axis in self._AXIS
return param[self._AXIS_NAMES[axis]]
return param
def qx_results(self, process, param):
"""
Returns qx fit results for the given process
:param process:
:param param: param name
:return:
"""
return self.results(process, param, axis=self.QX_AXIS)
def qy_results(self, process, param):
"""
Returns qy fit results for the given process
:param process:
:param param: param name
:return:
"""
return self.results(process, param, axis=self.QY_AXIS)
def qz_results(self, process, param):
"""
Returns qz fit results for the given process
:param process:
:param param: param name
:return:
"""
return self.results(process, param, axis=self.QZ_AXIS)
def add_qx_result(self, process, param, result):
self._add_axis_result(process, self.QX_AXIS, param, result)
def add_qy_result(self, process, param, result):
self._add_axis_result(process, self.QY_AXIS, param, result)
def add_qz_result(self, process, param, result):
self._add_axis_result(process, self.QZ_AXIS, param, result)
def _add_axis_result(self, process, axis, param, result):
assert axis in self._AXIS
param_data = self._get_param(process, param)
param_data[self._AXIS_NAMES[axis]] = result
def set_qx_status(self, process, status):
self._set_axis_status(process, self.QX_AXIS, status)
def set_qy_status(self, process, status):
self._set_axis_status(process, self.QY_AXIS, status)
def set_qz_status(self, process, status):
self._set_axis_status(process, self.QZ_AXIS, status)
def _set_axis_status(self, process, axis, status):
assert axis in self._AXIS
_process = self._get_process(process)
statuses = _process['status']
statuses[self._AXIS_NAMES[axis]] = status
def _get_process(self, process, create=True):
if process not in self._processes:
if not create:
raise KeyError('Unknown process {0}.'.format(process))
status = OrderedDict([('qx_status', None),
('qy_status', None),
('qz_status', None)])
_process = OrderedDict([('params', OrderedDict()),
('status', status)])
self._processes[process] = _process
else:
_process = self._processes[process]
return _process
def _get_param(self, process, param, create=True):
process = self._get_process(process, create=create)
params = process['params']
if param not in params:
if not create:
raise KeyError('Unknown param {0}.'.format(param))
_param = OrderedDict()
for axis in self._AXIS_NAMES:
_param[axis] = None
params[param] = _param
else:
_param = params[param]
return _param
entry = property(lambda self: self._entry)
sample_x = property(lambda self: self._sample_x)
sample_y = property(lambda self: self._sample_y)
q_x = property(lambda self: self._q_x)
q_y = property(lambda self: self._q_y)
q_z = property(lambda self: self._q_z)
if __name__ == '__main__':
pass
This diff is collapsed.
#!/usr/bin/python
# coding: utf8
# /*##########################################################################
#
# Copyright (c) 2015-2016 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ###########################################################################*/
from __future__ import absolute_import
__authors__ = ["D. Naudet"]
__date__ = "01/06/2016"
__license__ = "MIT"
import ctypes
import multiprocessing.sharedctypes as mp_sharedctypes
import numpy as np
from .fitresults import FitResult
class FitTypes(object):
ALLOWED = range(2)
LEASTSQ, CENTROID = ALLOWED
class FitSharedResults(object):
def __init__(self,
n_points=None,
n_params=None,
shared_results=None,
shared_status=None):
super(FitSharedResults, self).__init__()
assert n_points is not None, n_params is not None
self._shared_qx_results = None
self._shared_qy_results = None
self._shared_qz_results = None
self._shared_qx_status = None
self._shared_qy_status = None
self._shared_qz_status = None
self._npy_qx_results = None
self._npy_qy_results = None
self._npy_qz_results = None
self._npy_qx_status = None
self._npy_qy_status = None
self._npy_qz_status = None
self._n_points = n_points
self._n_params = n_params
self._init_shared_results(shared_results)
self._init_shared_status(shared_status)
self._init_npy_results()
self._init_npy_status()
def _init_shared_results(self, shared_results=None):
if shared_results is None:
self._shared_qx_results = mp_sharedctypes.RawArray(
ctypes.c_double, self._n_points * self._n_params)
self._shared_qy_results = mp_sharedctypes.RawArray(
ctypes.c_double, self._n_points * self._n_params)
self._shared_qz_results = mp_sharedctypes.RawArray(
ctypes.c_double, self._n_points * self._n_params)
else:
self._shared_qx_results = shared_results[0]
self._shared_qy_results = shared_results[1]
self._shared_qz_results = shared_results[2]
def _init_shared_status(self, shared_status=None):
if shared_status is None:
self._shared_qx_status = mp_sharedctypes.RawArray(
ctypes.c_bool, self._n_points)
self._shared_qy_status = mp_sharedctypes.RawArray(
ctypes.c_bool, self._n_points)
self._shared_qz_status = mp_sharedctypes.RawArray(
ctypes.c_bool, self._n_points)
else:
self._shared_qx_status = shared_status[0]
self._shared_qy_status = shared_status[1]
self._shared_qz_status = shared_status[2]
def _init_npy_results(self):
self._npy_qx_results = np.frombuffer(self._shared_qx_results)
self._npy_qx_results.shape = self._n_points, self._n_params
self._npy_qy_results = np.frombuffer(self._shared_qy_results)
self._npy_qy_results.shape = self._n_points, self._n_params
self._npy_qz_results = np.frombuffer(self._shared_qz_results)
self._npy_qz_results.shape = self._n_points, self._n_params
def _init_npy_status(self):
self._npy_qx_status = np.frombuffer(self._shared_qx_status,
dtype=bool)
self._npy_qy_status = np.frombuffer(self._shared_qy_status,
dtype=bool)
self._npy_qz_status = np.frombuffer(self._shared_qz_status,
dtype=bool)
def set_qx_results(self, idx, results, status):
self._npy_qx_results[idx] = results
self._npy_qx_status[idx] = status
def set_qy_results(self, idx, results, status):
self._npy_qy_results[idx] = results
self._npy_qy_status[idx] = status
def set_qz_results(self, idx, results, status):
self._npy_qz_results[idx] = results
self._npy_qz_status[idx] = status
def local_copy(self):
shared_results = (self._shared_qx_results,
self._shared_qy_results,
self._shared_qz_results)
shared_status = (self._shared_qx_status,
self._shared_qy_status,
self._shared_qz_status)
return FitSharedResults(n_points=self._n_points,
n_params=self._n_params,
shared_results=shared_results,
shared_status=shared_status)
def fit_results(self, *args, **kwargs):
raise NotImplementedError('')
class GaussianResults(FitSharedResults):
def __init__(self,
n_points=None,
shared_results=None,
shared_status=None):
super(GaussianResults, self).__init__(n_points=n_points,
n_params=3,
shared_results=shared_results,
shared_status=shared_status)
def fit_results(self, *args, **kwargs):
qx_results = self._npy_qx_results
qy_results = self._npy_qy_results
qz_results = self._npy_qz_results
qx_status = self._npy_qx_status
qy_status = self._npy_qy_status
qz_status = self._npy_qz_status
fit_name = 'Gaussian'
results = FitResult(fit_name, *args, **kwargs)
results.add_qx_result('gaussian', 'intensity', qx_results[:, 0].ravel())
results.add_qx_result('gaussian', 'position', qx_results[:, 1].ravel())
results.add_qx_result('gaussian', 'width', qx_results[:, 2].ravel())
results.set_qx_status('gaussian', qx_status)
results.add_qy_result('gaussian', 'intensity', qy_results[:, 0].ravel())
results.add_qy_result('gaussian', 'position', qy_results[:, 1].ravel())
results.add_qy_result('gaussian', 'width', qy_results[:, 2].ravel())
results.set_qy_status('gaussian', qy_status)
results.add_qz_result('gaussian', 'intensity', qz_results[:, 0].ravel())
results.add_qz_result('gaussian', 'position', qz_results[:, 1].ravel())
results.add_qz_result('gaussian', 'width', qz_results[:, 2].ravel())
results.set_qz_status('gaussian', qz_status)
return results
class CentroidResults(FitSharedResults):
def __init__(self,
n_points=None,
shared_results=None,
shared_status=None):
super(CentroidResults, self).__init__(n_points=n_points,
n_params=3,
shared_results=shared_results,
shared_status=shared_status)
def fit_results(self, *args, **kwargs):
qx_results = self._npy_qx_results
qy_results = self._npy_qy_results
qz_results = self._npy_qz_results
qx_status = self._npy_qx_status
qy_status = self._npy_qy_status
qz_status = self._npy_qz_status
fit_name = 'Centroid'
results = FitResult(fit_name, *args, **kwargs)
results.add_qx_result('centroid', 'I(COM)', qx_results[:, 0].ravel())
results.add_qx_result('centroid', 'C. of Mass',
qx_results[:, 1].ravel())
results.add_qx_result('centroid', 'maximum',
qx_results[:, 2].ravel())
results.set_qx_status('centroid', qx_status)
results.add_qy_result('centroid', 'I(COM)', qy_results[:, 0].ravel())
results.add_qy_result('centroid',
'C. of Mass',
qy_results[:, 1].ravel())
results.add_qy_result('centroid', 'maximum',
qy_results[:, 2].ravel())
results.set_qy_status('centroid', qy_status)
results.add_qz_result('centroid', 'I(COM)', qz_results[:, 0].ravel())
results.add_qz_result('centroid',
'C. of Mass',
qz_results[:, 1].ravel())
results.add_qz_result('centroid', 'maximum',
qz_results[:, 2].ravel())
results.set_qz_status('centroid', qz_status)
return results
if __name__ == '__main__':
pass
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment