def test_parameter_slicing(): # Tests whether parameters coming from a Fit can be sliced by a data handle, # i.e. fit.params[data_handle] def dummy(t, p1, p2, p3): return t * p1 + t * p2 * p2 + t * p3 * p3 * p3 model = Model("dummy", dummy, p2=Parameter(2), p3=Parameter(3), p1=Parameter(1)) fit = Fit(model) data_set = fit._add_data("data1", [1, 1, 1], [1, 2, 3], {"dummy/p2": "dummy/p2_b"}) parameter_slice = fit.params[data_set] assert parameter_slice["dummy/p1"].value == 1 assert parameter_slice["dummy/p2"].value == 2 assert parameter_slice["dummy/p3"].value == 3 data_set2 = fit._add_data("data2", [1, 1, 1], [1, 2, 3], {"dummy/p2": "dummy/p2_c"}) fit.params["dummy/p2_c"] = 5 parameter_slice = fit.params[data_set] assert parameter_slice["dummy/p2"].value == 2 parameter_slice = fit.params[data_set2] assert parameter_slice["dummy/p2"].value == 5
def test_model_defaults(): """Test whether model defaults propagate to the fit object correctly""" def g(data, mu, sig, a, b, c, d, e, f, q): del sig, a, b, c, d, e, f, q return (data - mu) * 2 model = Model("M", g, f=Parameter(5)) fit = Fit(model) fit._add_data("test", [1, 2, 3], [2, 3, 4]) fit._add_data("test2", [1, 2, 3], [2, 3, 4], params={"M/f": "f/new"}) fit._build_fit() assert fit["M/a"].value == Parameter().value assert fit.params["M/a"].value == Parameter().value assert fit.params["f/new"].value == 5 assert fit.params["M/f"].value == 5 # Check whether each parameter is actually unique fit.params["f/new"] = 6 assert fit.params["f/new"].value == 6 assert fit.params["M/f"].value == 5 # Test whether providing a default for a parameter that doesn't exist throws with pytest.raises(AssertionError): Model("M", g, z=Parameter(5)) # Verify that the defaults are in fact copies default = Parameter(5) model = Model("M", g, f=default) model._params["M/f"].value = 6 assert default.value == 5
def test_plotting(): x = np.arange(10.0) / 100.0 y = [ 1.37272429, 1.14759176, 1.2080786, 1.79293398, 1.22606946, 1.55293523, 1.73564261, 1.49623027, 1.81209629, 1.69464097, ] F = Fit( Model( "exponential", exp_charge, jacobian=exp_charge_jac, mag=Parameter(value=1.0), k=Parameter(value=1.0), )) F._add_data("exponential", x, y) F.fit() profile = F.profile_likelihood("exponential/k") profile.plot() profile.plot_relations()
def test_custom_legend_labels(): """Test whether users can provide a custom label for plotting""" def test_labels(labels): for legend_entry, label in zip(plt.gca().get_legend().texts, labels): assert label == legend_entry.get_text() fit = Fit(odijk("m")) fit._add_data("data_1", [1, 2, 3], [2, 3, 4]) fit.plot() test_labels(["data_1 (model)", "data_1 (data)"]) plt.gca().clear() fit.plot(label="custom label") test_labels(["custom label (model)", "custom label (data)"])
def test_parameter_inversion(): def f(independent, a, b): return a + b * independent def f_jac(independent, a, b): del a, b return np.vstack((np.ones((1, len(independent))), independent)) def g(independent, a, d, b): return a - b * independent + d * independent * independent def g_jac(independent, a, d, b): del a, d, b return np.vstack((np.ones( (1, len(independent))), independent * independent, -independent)) def f_der(independent, a, b): del independent, a return b * np.ones((len(x))) def g_der(independent, a, d, b): del independent, a return -b * np.ones((len(independent))) + 2.0 * d * independent x = np.array([1.0, 2.0, 3.0, 4.0, 5.0]) a_true = 5.0 b_true = np.array([1.0, 2.0, 3.0, 4.0, 10.0]) f_data = f(x, a_true, b_true) model = Model("f", f, jacobian=f_jac, derivative=f_der) fit = Fit(model) fit._add_data("test", x, f_data) fit.params["f/a"].value = a_true fit.params["f/b"].value = 1.0 np.testing.assert_allclose( parameter_trace(model, fit.params, "f/b", x, f_data), b_true) a_true = 5.0 b_true = 3.0 d_true = np.array([1.0, 2.0, 3.0, 4.0, 10.0]) f_plus_g_data = f(x, a_true, b_true) + g(x, a_true, d_true, b_true) model = Model("f", f, jacobian=f_jac, derivative=f_der) + Model( "f", g, jacobian=g_jac, derivative=g_der) fit = Fit(model) fit._add_data("test", x, f_data) fit.params["f/a"].value = a_true fit.params["f/b"].value = b_true fit.params["f/d"].value = 1.0 np.testing.assert_allclose( parameter_trace(model, fit.params, "f/d", x, f_plus_g_data), d_true)
def test_jacobian_test_fit(): def f(independent, a, b): return a + b * independent def f_jac(independent, a, b): del a, b return np.vstack((np.ones((1, len(independent))), independent)) def f_der(independent, a, b): del a return b * np.ones((len(independent))) def f_jac_wrong(independent, a, b): del a, b return np.vstack((2.0 * np.ones((1, len(independent))), independent)) x = np.array([1.0, 2.0, 3.0, 4.0, 5.0]) a_true, b_true = (5.0, 5.0) f_data = f(x, a_true, b_true) model = Model("f", f, jacobian=f_jac, derivative=f_der) fit = Fit(model) fit._add_data("test", x, f_data) fit.params["f/a"].value = a_true fit.params["f/b"].value = b_true assert fit.verify_jacobian(fit.params.values) model_bad = Model("f", f, jacobian=f_jac_wrong, derivative=f_der) fit = Fit(model_bad) fit._add_data("test", x, f_data) fit.params["f/a"].value = a_true fit.params["f/b"].value = b_true assert not fit.verify_jacobian(fit.params.values) with pytest.raises(ValueError): assert odijk("WLC").verify_jacobian([1.0, 2.0, 3.0], [1.0, 2.0]) with pytest.raises(ValueError): odijk("WLC").verify_derivative([1, 2, 3], [1, 2, 3])
def test_no_jac(): x, y = test_data() linear_model = Model("linear", linear_func()["model_function"]) linear_fit = Fit(linear_model) linear_fit._add_data("test", x, y, {"linear/a": 5}) linear_fit.fit() with pytest.raises(NotImplementedError): linear_fit.cov
def test_fit_metrics(model_funcs, sigma, aic, aicc, bic): x, y = test_data() fit = Fit(Model("linear", **model_funcs())) fit._add_data("test", x, y) fit.fit() np.testing.assert_allclose(fit.sigma[0], sigma) np.testing.assert_allclose(fit.aic, aic) np.testing.assert_allclose(fit.aicc, aicc) np.testing.assert_allclose(fit.bic, bic)
def validate_profile(name, func, jac, x, y, parameter, stderr, lb, ub): F = Fit(Model(name, func, jacobian=jac)) F._add_data(name, x, y) F.fit() profile = F.profile_likelihood(name + "/" + parameter) assert (F[name + "/" + parameter].stderr - stderr) < eps assert F[name + "/" + parameter].profile == profile assert abs(profile.lower_bound - lb) < eps assert abs(profile.upper_bound - ub) < eps assert len(profile.chi2) == len(profile.p) # Validate asymptotic confidence intervals based on comparing them with the profiles assert abs(F[name + "/" + parameter].ci(0.95)[0] - profile.lower_bound) < 1e-2 assert abs(F[name + "/" + parameter].ci(0.95)[1] - profile.upper_bound) < 1e-2
def test_parameter_availability(): x = np.arange(10) y = np.array([ 8.24869073, 7.77648717, 11.9436565, 14.85406276, 22.73081526, 20.39692261, 32.48962353, 31.4775862, 37.63807819, 40.50125925, ]) def linear(independent, a=1, b=1): return a * independent + b def linear_jac(independent, a, b): del a, b return np.vstack((independent, np.ones(len(independent)))) linear_model = Model("linear", linear, jacobian=linear_jac) linear_fit = Fit(linear_model) with pytest.raises(IndexError): linear_fit.params["linear/a"] linear_fit._add_data("test", x, y, {"linear/a": 5}) linear_fit = Fit(linear_model) # Parameter linear_a is not actually a parameter in the fit object at this point (it was set # to 5) with pytest.raises(IndexError): linear_fit.params["linear/a"] linear_fit._add_data("test", x, y) assert "linear/a" in linear_fit.params
def test_non_identifiability(): x = np.arange(10.0) / 100.0 y = [ 1.37272429, 1.14759176, 1.2080786, 1.79293398, 1.22606946, 1.55293523, 1.73564261, 1.49623027, 1.81209629, 1.69464097, ] F = Fit( Model( "exponential", exp_charge, jacobian=exp_charge_jac, mag=Parameter(value=1.0), k=Parameter(value=1.0), )) F._add_data("exponential", x, y) F.fit() num_steps = 100 profile = F.profile_likelihood("exponential/k", num_steps=num_steps) # This model does not have an upper bound for its 95% confidence interval (we're fitting a # constant with an exponential rise. The exponential rise is non-identifiable since it can be # infinitely fast. assert profile.lower_bound is not None assert profile.upper_bound is None assert len(profile.p) < 2 * num_steps assert str(profile) == dedent("""\ Profile likelihood for exponential/k (121 points) - chi2 - p - lower_bound: 20.36 - upper_bound: undefined """)
def test_asymptotic_errs_all_parameters(): """Tests whether the covariance matrix is computed correctly""" x, y = test_data() quadratic_fit = Fit(Model("quadratic", **quadratic_func())) quadratic_fit._add_data("test", x, y) quadratic_fit.fit() np.testing.assert_allclose( quadratic_fit.cov, np.array([ [0.001465292918082, -0.013187636262741, 0.017583515016988], [-0.013187636262741, 0.128066601040397, -0.200452071193665], [0.017583515016988, -0.200452071193665, 0.478271608462078], ]), ) np.testing.assert_allclose(quadratic_fit["quadratic/a"].stderr, 0.038279144688489905) np.testing.assert_allclose(quadratic_fit["quadratic/b"].stderr, 0.35786394207910477) np.testing.assert_allclose(quadratic_fit["quadratic/c"].stderr, 0.6915718389741429)
def test_integration_test_fitting(): def linear(independent, a, b): f = a * independent + b return f def linear_jac(independent, a, b): del a, b jacobian = np.vstack((independent, np.ones(len(independent)))) return jacobian def linear_jac_wrong(independent, a, b): del a, b jacobian = np.vstack((np.ones(len(independent)), independent)) return jacobian assert Model("M", linear, jacobian=linear_jac).has_jacobian assert not Model("M", linear).has_jacobian with pytest.raises(RuntimeError): Model("M", linear).jacobian([1.0, 2.0, 3.0], [1.0, 2.0, 3.0]) with pytest.raises(RuntimeError): Model("M", linear).derivative([1.0, 2.0, 3.0], [1.0, 2.0, 3.0]) model = Model("M", linear, jacobian=linear_jac_wrong) assert not model.verify_jacobian([1, 2, 3], [1, 1]) model = Model("M", linear, jacobian=linear_jac) fit = Fit(model) x = np.arange(3) for i in np.arange(3): y = 4.0 * x * i + 5.0 fit._add_data(f"test {i}", x, y, params={"M/a": f"slope_{i}"}) y = 4.0 * x + 10.0 fit._add_data("test x", x, y, params={"M/a": "slope_1", "M/b": "M/b_2"}) # Test whether fixed parameters are not fitted fit["slope_2"].fixed = True fit.fit() assert np.isclose(fit["slope_2"].value, 0) fit["slope_2"].fixed = False fit.fit() assert len(fit.params.values) == 5 assert len(fit.params) == 5 assert fit.n_residuals == 12 assert fit.n_params == 5 assert np.isclose(fit.params["slope_0"].value, 0) assert np.isclose(fit.params["slope_1"].value, 4) assert np.isclose(fit.params["slope_2"].value, 8) assert np.isclose(fit.params["M/b"].value, 5) assert np.isclose(fit.params["M/b_2"].value, 10) # Verify that fixed parameters are correctly removed from sub-models model = Model("M", linear, jacobian=linear_jac) fit = Fit(model) fit._add_data("test1", x, 4.0 * x + 5.0, {"M/a": 4}) fit._add_data("test2", x, 8.0 * x + 10.0, {"M/b": 10}) fit.fit() assert np.isclose(fit.params["M/b"].value, 5) assert np.isclose(fit.params["M/a"].value, 8) fit["M/a"].upper_bound = 4 fit["M/a"].value = 5 with pytest.raises(ValueError): fit.fit()
def test_model_fit_object_linking(): def fetch_params(parameters, indices): p_list = list(parameters.keys()) return [p_list[x] if x is not None else None for x in indices] def g(data, mu, sig, a, b, c, d, e, f, q): del sig, a, b, c, d, e, f, q return (data - mu) * 2 def h(data, mu, e, q, c, r): del e, q, c, r return (data - mu) * 2 all_params = ["M/mu", "M/sig", "M/a", "M/b", "M/d", "M/e", "M/f", "M/q"] m = Model("M", g, d=Parameter(4)) m2 = Model("M", h) # Model should not be built fit = Fit(m, m2) fit[m]._add_data("test", [1, 2, 3], [2, 3, 4], {"M/c": 4}) assert fit.dirty # Asking for the parameters should have triggered a build fit.params assert not fit.dirty assert set(fit.params.keys()) == set(all_params) # Check the parameters included in the model np.testing.assert_allclose(fit.datasets[id(m)]._conditions[0].p_external, [0, 1, 2, 3, 5, 6, 7, 8]) assert np.all(fit.datasets[id(m)]._conditions[0].p_local == [None, None, None, None, 4, None, None, None, None]) params = ["M/mu", "M/sig", "M/a", "M/b", None, "M/d", "M/e", "M/f", "M/q"] assert fetch_params( fit.params, fit.datasets[id(m)]._conditions[0]._p_global_indices) == params # Loading data should make it dirty again fit[m]._add_data("test2", [1, 2, 3], [2, 3, 4], { "M/c": 4, "M/e": "M/e_new" }) assert fit.dirty # Check the parameters included in the model fit._rebuild() np.testing.assert_allclose(fit.datasets[id(m)]._conditions[0].p_external, [0, 1, 2, 3, 5, 6, 7, 8]) assert np.all(fit.datasets[id(m)]._conditions[0].p_local == [None, None, None, None, 4, None, None, None, None]) params = ["M/mu", "M/sig", "M/a", "M/b", None, "M/d", "M/e", "M/f", "M/q"] assert fetch_params( fit.params, fit.datasets[id(m)]._conditions[0]._p_global_indices) == params np.testing.assert_allclose(fit.datasets[id(m)]._conditions[1].p_external, [0, 1, 2, 3, 5, 6, 7, 8]) assert np.all(fit.datasets[id(m)]._conditions[1].p_local == [None, None, None, None, 4, None, None, None, None]) params = [ "M/mu", "M/sig", "M/a", "M/b", None, "M/d", "M/e_new", "M/f", "M/q" ] assert fetch_params( fit.params, fit.datasets[id(m)]._conditions[1]._p_global_indices) == params # Load data into model 2 fit[m2]._add_data("test", [1, 2, 3], [2, 3, 4], {"M/c": 4, "M/r": 6}) assert fit.dirty # Since M/r is set fixed in that model, it should not appear as a parameter all_params = [ "M/mu", "M/sig", "M/a", "M/b", "M/d", "M/e", "M/e_new", "M/f", "M/q" ] assert set(fit.params.keys()) == set(all_params) all_params = [ "M/mu", "M/sig", "M/a", "M/b", "M/d", "M/e", "M/e_new", "M/f", "M/q", "M/r" ] fit[m2]._add_data("test2", [1, 2, 3], [2, 3, 4], {"M/c": 4, "M/e": 5}) assert set(fit.params.keys()) == set(all_params) np.testing.assert_allclose(fit.datasets[id(m)]._conditions[0].p_external, [0, 1, 2, 3, 5, 6, 7, 8]) assert np.all(fit.datasets[id(m)]._conditions[0].p_local == [None, None, None, None, 4, None, None, None, None]) params = ["M/mu", "M/sig", "M/a", "M/b", None, "M/d", "M/e", "M/f", "M/q"] assert fetch_params( fit.params, fit.datasets[id(m)]._conditions[0]._p_global_indices) == params np.testing.assert_allclose(fit.datasets[id(m)]._conditions[1].p_external, [0, 1, 2, 3, 5, 6, 7, 8]) assert np.all(fit.datasets[id(m)]._conditions[1].p_local == [None, None, None, None, 4, None, None, None, None]) params = [ "M/mu", "M/sig", "M/a", "M/b", None, "M/d", "M/e_new", "M/f", "M/q" ] assert fetch_params( fit.params, fit.datasets[id(m)]._conditions[1]._p_global_indices) == params np.testing.assert_allclose(fit.datasets[id(m2)]._conditions[0].p_external, [0, 1, 2]) assert np.all(fit.datasets[id(m2)]._conditions[0].p_local == [None, None, None, 4, 6]) params = ["M/mu", "M/e", "M/q", None, None] assert fetch_params( fit.params, fit.datasets[id(m2)]._conditions[0]._p_global_indices) == params params = ["M/mu", None, "M/q", None, "M/r"] assert fetch_params( fit.params, fit.datasets[id(m2)]._conditions[1]._p_global_indices) == params fit.update_params(Params(**{"M/mu": 4, "M/sig": 6})) assert fit["M/mu"].value == 4 assert fit["M/sig"].value == 6 f2 = Fit(m) f2._add_data("test", [1, 2, 3], [2, 3, 4]) f2["M/mu"].value = 12 fit.update_params(f2) assert fit["M/mu"].value == 12 with pytest.raises(RuntimeError): fit.update_params(5) # noqa
def test_data_loading(): m = Model("M", lambda x, a: a * x) fit = Fit(m) fit._add_data("test", [1, np.nan, 3], [2, np.nan, 4]) np.testing.assert_allclose(fit[m].data["test"].x, [1, 3]) np.testing.assert_allclose(fit[m].data["test"].y, [2, 4]) np.testing.assert_allclose(fit[m].data["test"].independent, [1, 3]) np.testing.assert_allclose(fit[m].data["test"].dependent, [2, 4]) # Name must be unique with pytest.raises(KeyError): fit._add_data("test", [1, 3, 5], [2, 4, 5]) with pytest.raises(AssertionError): fit._add_data("test2", [1, 3], [2, 4, 5]) with pytest.raises(AssertionError): fit._add_data("test3", [1, 3, 5], [2, 4]) with pytest.raises(AssertionError): fit._add_data("test4", [[1, 3, 5]], [[2, 4, 5]])
def test_asymptotic_errs_subset_parameters(): """Check whether the asymptotic uncertainty handling is correct by checking a nested model Fixing a parameter in quadratic function converts it to a linear one. This should result in identical standard errors and covariance matrix""" x, y = test_data() linear_fit = Fit(Model("m", **linear_func())) linear_fit._add_data("test", x, y) linear_fit.fit() quadratic_fit = Fit(Model("m", **quadratic_func())) quadratic_fit._add_data("test", x, y) quadratic_fit["m/a"].fixed = True quadratic_fit.fit() np.testing.assert_allclose(linear_fit.cov, quadratic_fit.cov) np.testing.assert_allclose(quadratic_fit["m/b"].stderr, linear_fit["m/a"].stderr) np.testing.assert_allclose(quadratic_fit["m/c"].stderr, linear_fit["m/b"].stderr) assert quadratic_fit["m/a"].stderr is None
def test_fd_variable_order(): # Fit takes dependent, then independent m = odijk("M") fit = Fit(m) fit._add_data("test", [1, 2, 3], [2, 3, 4]) np.testing.assert_allclose(fit[m].data["test"].x, [1, 2, 3]) np.testing.assert_allclose(fit[m].data["test"].y, [2, 3, 4]) fit[m]._add_data("test2", [1, 2, 3], [2, 3, 4]) np.testing.assert_allclose(fit[m].data["test2"].x, [1, 2, 3]) np.testing.assert_allclose(fit[m].data["test2"].y, [2, 3, 4]) m = inverted_odijk("M") fit = Fit(m) fit._add_data("test", [1, 2, 3], [2, 3, 4]) np.testing.assert_allclose(fit[m].data["test"].x, [1, 2, 3]) np.testing.assert_allclose(fit[m].data["test"].y, [2, 3, 4]) fit[m]._add_data("test2", [1, 2, 3], [2, 3, 4]) np.testing.assert_allclose(fit[m].data["test2"].x, [1, 2, 3]) np.testing.assert_allclose(fit[m].data["test2"].y, [2, 3, 4]) # FdFit always takes f, d and maps it to the correct values m = odijk("M") fit = FdFit(m) # Test the FdFit interface fit.add_data("test", [1, 2, 3], [2, 3, 4]) np.testing.assert_allclose(fit[m].data["test"].x, [1, 2, 3]) np.testing.assert_allclose(fit[m].data["test"].y, [2, 3, 4]) # Test the FdDatasets interface fit[m].add_data("test2", [3, 4, 5], [4, 5, 6]) np.testing.assert_allclose(fit[m].data["test2"].x, [3, 4, 5]) np.testing.assert_allclose(fit[m].data["test2"].y, [4, 5, 6]) m = inverted_odijk("M") fit = FdFit(m) fit.add_data("test", [1, 2, 3], [2, 3, 4]) np.testing.assert_allclose(fit[m].data["test"].x, [2, 3, 4]) np.testing.assert_allclose(fit[m].data["test"].y, [1, 2, 3]) # Test the FdDatasets interface fit[m].add_data("test2", [3, 4, 5], [4, 5, 6]) np.testing.assert_allclose(fit[m].data["test2"].x, [4, 5, 6]) np.testing.assert_allclose(fit[m].data["test2"].y, [3, 4, 5])
def test_plotting(): m = odijk("DNA") m2 = odijk("protein") # Test single model plotting fit = Fit(m) fit[m]._add_data("data_1", [1, 2, 3], [2, 3, 4]) fit.plot() fit.plot("data_1") with pytest.raises(AssertionError): fit.plot("non-existent-data") fit.plot(overrides={"DNA/Lc": 12}) with pytest.raises(KeyError): fit.plot(overrides={"DNA/c": 12}) fit.plot(overrides={"DNA/Lc": 12}, independent=np.arange(1.0, 5.0, 1.0)) with pytest.raises(KeyError): fit[m2].plot() # Test multi-model plotting fit = Fit(m, m2) fit[m]._add_data("data_1", [1, 2, 3], [2, 3, 4]) fit[m]._add_data("dataset_2", [1, 2, 3], [2, 3, 4], {"DNA/Lc": "DNA/Lc_2"}) fit[m2]._add_data("data_1", [1, 2, 3], [2, 3, 4]) fit[m2]._add_data("dataset_2", [1, 2, 3], [2, 3, 4], {"protein/Lc": "protein/Lc_2"}) fit[m2]._add_data("dataset 3", [1, 2, 3], [2, 3, 4], {"protein/Lc": "protein/Lc_2"}) with pytest.raises(AssertionError): fit.plot() fit[m].plot() fit[m2].plot() fit[m].plot("data_1") with pytest.raises(AssertionError): fit.plot(m, "non-existent-data") fit[m2].plot("dataset 3") with pytest.raises(AssertionError): fit[m].plot("dataset 3") fit[m].plot(overrides={"DNA/Lc": 12}) with pytest.raises(KeyError): fit[m].plot(overrides={"DNA/c": 12}) independent = np.arange(0.15, 2, 0.25) params = [38.18281266, 0.37704827, 278.50103452, 4.11] odijk("WLC").verify_jacobian(independent, params, plot=1) params = [38.18281266, 0.37704827, 278.50103452, 4.11] fit = FdFit(odijk("WLC")) fit.add_data("dataset 3", [1, 2, 3], [2, 3, 4]) plt.figure() fit.verify_jacobian(params, plot=1) # Test live fit plotting fit = Fit(m, m2) fit[m]._add_data("data_1", [1, 2, 3], [2, 3, 4]) fit[m]._add_data("dataset_2", [1, 2, 3], [2, 3, 4], {"DNA/Lc": "DNA/Lc_2"}) fit[m2]._add_data("data_1", [1, 2, 3], [2, 3, 4]) fit.fit(show_fit=True, max_nfev=1)
def test_fit_reprs(): m = odijk("DNA") fit = Fit(m) d1 = fit._add_data("data_1", [1, 2, 3], [2, 3, 4]) assert d1.__repr__() == "FitData(data_1, N=3)" d2 = fit._add_data("dataset_2", [1, 2, 3], [2, 3, 4], {"DNA/Lc": "DNA/Lc_2"}) assert d2.__repr__( ) == "FitData(dataset_2, N=3, Transformations: DNA/Lc → DNA/Lc_2)" f = Fit(m) assert f.__repr__() assert f._repr_html_() fit._add_data("data_3", [1, 2, 3], [2, 3, 4], {"DNA/Lc": 5}) assert fit.__repr__() assert fit._repr_html_() m = inverted_odijk("DNA") fit = FdFit(m) fit._add_data("RecA", [1, 2, 3], [1, 2, 3]) fit._add_data("RecA2", [1, 2, 3], [1, 2, 3]) fit._add_data("RecA3", [1, 2, 3], [1, 2, 3]) assert fit[m].__repr__( ) == "lumicks.pylake.FdDatasets(datasets={RecA, RecA2, RecA3}, N=9)" assert ( fit[m].__str__() == "Data sets:\n- FitData(RecA, N=3)\n- FitData(RecA2, N=3)\n- FitData(RecA3, N=3)\n" ) assert fit[m]._repr_html_() == ("  FitData(RecA, N=3)<br>\n" "  FitData(RecA2, N=3)<br>\n" "  FitData(RecA3, N=3)<br>\n") assert fit.__repr__() == "lumicks.pylake.FdFit(models={DNA}, N=9)" assert fit.__str__() == ( "Fit\n - Model: DNA\n - Equation:\n" " f(d) = argmin[f](norm(DNA.Lc * (1 - (1/2)*sqrt(kT/(f*DNA.Lp)) + f/DNA.St)-d))\n\n" " - Data sets:\n - FitData(RecA, N=3)\n - FitData(RecA2, N=3)\n " "- FitData(RecA3, N=3)\n\n " "- Fitted parameters:\n" " Name Value Unit Fitted Lower bound Upper bound\n" " ------ ------- -------- -------- ------------- -------------\n" " DNA/Lp 40 [nm] True 0 100\n" " DNA/Lc 16 [micron] True 0 inf\n" " DNA/St 1500 [pN] True 0 inf\n" " kT 4.11 [pN*nm] False 0 8" )