def tanh_fit(x, y, iqr_multiplier=None): from scitbx.math import curve_fitting tf = curve_fitting.tanh_fit(x, y) f = curve_fitting.tanh(*tf.params) if iqr_multiplier is not None: assert iqr_multiplier > 0 yc = f(x) dy = y - yc from scitbx.math import five_number_summary min_x, q1_x, med_x, q3_x, max_x = five_number_summary(dy) iqr_x = q3_x - q1_x cut_x = iqr_multiplier * iqr_x outliers = (dy > q3_x + cut_x) | (dy < q1_x - cut_x) if outliers.count(True) > 0: xo = x.select(~outliers) yo = y.select(~outliers) tf = curve_fitting.tanh_fit(xo, yo) f = curve_fitting.tanh(*tf.params) return f(x)
def tanh_fit(x, y, iqr_multiplier=None): """ Fit a tanh function to the values y(x) and return this fit x, y should be iterables containing floats of the same size. This is used for fitting a curve to CC½. """ tf = curve_fitting.tanh_fit(x, y) f = curve_fitting.tanh(*tf.params) if iqr_multiplier: assert iqr_multiplier > 0 yc = f(x) dy = y - yc min_x, q1_x, med_x, q3_x, max_x = five_number_summary(dy) iqr_x = q3_x - q1_x cut_x = iqr_multiplier * iqr_x outliers = (dy > q3_x + cut_x) | (dy < q1_x - cut_x) if outliers.count(True) > 0: xo = x.select(~outliers) yo = y.select(~outliers) tf = curve_fitting.tanh_fit(xo, yo) f = curve_fitting.tanh(*tf.params) return f(x)
def exercise_tanh_fit(): # Curve fitting as used by Aimless for fitting CC1/2 plot: # Curve fitting as suggested by Ed Pozharski to a tanh function # of the form (1/2)(1 - tanh(z)) where z = (s - d0)/r, # s = 1/d^2, d0 is the value of s at the half-falloff value, and r controls # the steepness of falloff d = flex.double( [2.71, 2.15, 1.88, 1.71, 1.59, 1.49, 1.42, 1.36, 1.31, 1.26]) x_obs = 1 / d**2 y_obs = flex.double( [0.999, 0.996, 0.993, 0.984, 0.972, 0.948, 0.910, 0.833, 0.732, 0.685]) fit = curve_fitting.tanh_fit(x_obs, y_obs, r=1, s0=1) r, s0 = fit.params f = curve_fitting.tanh(r, s0) y_calc = flex.double(f(x_obs)) residual = flex.sum(flex.pow2(y_obs - y_calc)) assert approx_equal(residual, 0.0023272873437026106) assert approx_equal(fit.params, (0.17930695756689238, 0.6901032957705017))