コード例 #1
0
    def load_file(self, path, callback, user_metadata):
        """Load a data file, optionally asking for missing metadata

        Parameters
        ----------
        path: str or pathlib.Path
            path to the data file
        callback: callable
            function for tracking loading progress
        user_metadata: dict
            dictionary holding the user-defined metadata; this
            dictionary is edited in-place (i.e. the user only needs
            to specify missing metadata once per import) if the
            `user_metadata` is used consistently in an import loop
            (like in `self.add_files`). Note that only the metadata
            that is missing are used from user_metadata.
        """
        try:
            grp = nanite.IndentationGroup(path, callback=callback)
        except afmformats.errors.MissingMetaDataError as e:
            custom_metadata = {}
            for key in e.meta_keys:
                # check if the keys are in user_metadata
                if key not in user_metadata:
                    # show dialog asking for missing metadata
                    name, si_unit, _ = afmformats.meta.DEF_ALL[key]
                    hr_unit = units.hrunit(name, si_unit)
                    scale_unit = units.hrscale(name, si_unit)
                    value, ok_pressed = QtWidgets.QInputDialog.getDouble(
                        self,
                        f"Missing metadata '{name}'",
                        f"Please specify the {name}"
                        + (f" [{hr_unit}]" if hr_unit else "")
                        + ":",
                        .0,
                        .0,
                        99999,
                        6,
                        )
                    if not ok_pressed:
                        # if user pressed cancel, raise AbortError
                        raise AbortProgress(f"User did not enter {key}!")
                    # add new keys in user_metadata
                    user_metadata[key] = value / scale_unit
                # populate custom_metadata with the user_metadata
                custom_metadata[key] = user_metadata[key]
            # now loading the data should work
            grp = nanite.IndentationGroup(path,
                                          callback=callback,
                                          meta_override=custom_metadata)
        return grp
コード例 #2
0
ファイル: test_indent.py プロジェクト: AFM-analysis/nanite
def test_apply_preprocessing_remember_fit_properties():
    """
    Normally, the fit properties would be overridden
    if the preprocessing changes. For user convenience,
    nanite remembers it. This is the test
    """
    ds1 = nanite.IndentationGroup(jpkfile)
    idnt = ds1[0]
    idnt.apply_preprocessing(["compute_tip_position"])

    inparams = nanite.model.model_hertz_paraboloidal.get_parameter_defaults()
    inparams["baseline"].vary = True
    cp1 = 1.8029310065572342e-05
    inparams["contact_point"].set(cp1)
    inparams["contact_point"].vary = False

    # Fit with absolute full range
    idnt.fit_model(model_key="hertz_para",
                   params_initial=inparams,
                   range_x=(0, 0),
                   range_type="absolute",
                   x_axis="tip position",
                   y_axis="force",
                   segment="approach",
                   weight_cp=False)
    assert cp1 == idnt.fit_properties["params_initial"]["contact_point"].value
    assert cp1 == idnt.fit_properties["params_fitted"]["contact_point"].value

    # Change preprocessing
    idnt.apply_preprocessing(["compute_tip_position", "correct_force_offset"])
    assert cp1 == idnt.fit_properties["params_initial"]["contact_point"].value
コード例 #3
0
ファイル: test_indent.py プロジェクト: AFM-analysis/nanite
def test_preprocessing_reset():
    fd = nanite.IndentationGroup(jpkfile)[0]
    fd.apply_preprocessing(
        ["compute_tip_position", "correct_force_offset", "correct_tip_offset"],
        options={"correct_tip_offset": {
            "method": "fit_constant_line"
        }})

    inparams = nanite.model.model_hertz_paraboloidal.get_parameter_defaults()
    inparams["baseline"].vary = True
    inparams["contact_point"].set(1.8e-5)

    # Perform fit and make sure that all properties are set
    fd.fit_model(model_key="hertz_para",
                 params_initial=inparams,
                 range_x=(0, 0),
                 range_type="absolute",
                 x_axis="tip position",
                 y_axis="force",
                 segment="approach",
                 weight_cp=False)
    fd.rate_quality(training_set="zef18", regressor="Extra Trees")
    assert fd._rating is not None
    assert fd.preprocessing == [
        "compute_tip_position", "correct_force_offset", "correct_tip_offset"
    ]
    assert fd.preprocessing_options == {
        "correct_tip_offset": {
            "method": "fit_constant_line"
        }
    }
    assert not fd._preprocessing_details
    assert np.allclose(
        fd._fit_properties["params_fitted"]["contact_point"].value,
        -3.5147555568064786e-06,
        atol=0)
    assert "tip position" in fd

    # Change preprocessing and make sure properties are reset
    fd.apply_preprocessing(
        ["compute_tip_position", "correct_force_offset", "correct_tip_offset"],
        options={"correct_tip_offset": {
            "method": "fit_constant_polynomial"
        }})
    assert fd._rating is None
    assert fd.preprocessing == [
        "compute_tip_position", "correct_force_offset", "correct_tip_offset"
    ]
    assert fd.preprocessing_options == {
        "correct_tip_offset": {
            "method": "fit_constant_polynomial"
        }
    }
    assert not fd._preprocessing_details
    assert "params_fitted" not in fd._fit_properties
    assert "tip position" in fd

    # Change preprocessing, removing tip position
    fd.apply_preprocessing(["correct_force_offset"])
    assert "tip position" not in fd
コード例 #4
0
def test_export():
    ds1 = nanite.IndentationGroup(jpkfile)
    idnt = ds1[0]
    # tip-sample separation
    idnt.apply_preprocessing(["compute_tip_position"])
    # create temporary file
    _, path = tempfile.mkstemp(suffix=".tab", prefix="nanite_idnt_export")
    idnt.export(path)
    data = afmformats.load_data(path)[0]
    assert len(data) == 4000
    assert np.allclose(data["force"][100], -4.853736717639109e-10)
    assert np.allclose(data["height (measured)"][100],
                       2.256791903750211e-05,
                       atol=1e-10,
                       rtol=0)
    assert data["segment"][100] == 0
    assert np.allclose(data["time"][100], 0.04999999999999999)
    assert np.allclose(data["tip position"][100],
                       2.255675939721752e-05,
                       atol=1e-10,
                       rtol=0)
    assert data["segment"][3000] == 1

    try:
        pathlib.Path(path).unlink()
    except OSError:
        pass
コード例 #5
0
ファイル: test_indent.py プロジェクト: AFM-analysis/nanite
def test_repr_str():
    ds1 = nanite.IndentationGroup(jpkfile)
    idnt = ds1[0]
    assert "AFMForceDistance" not in str(idnt)
    assert "Indentation" in str(idnt)
    assert "fmt-jpk-fd_spot3-0192.jpk-force" in str(idnt)
    assert "Indentation" in repr(idnt)
    assert "fmt-jpk-fd_spot3-0192.jpk-force" in repr(idnt)
コード例 #6
0
 def selected_curves(self):
     """IndentationGroup with all curves selected by the user"""
     curves = nanite.IndentationGroup()
     for ar in self.data_set:
         idx = self.data_set.index(ar)
         item = self.list_curves.topLevelItem(idx)
         if item.checkState(3) == QtCore.Qt.Checked:
             curves.append(ar)
     return curves
コード例 #7
0
ファイル: test_indent.py プロジェクト: AFM-analysis/nanite
def test_basic():
    ds1 = nanite.IndentationGroup(jpkfile)
    idnt = ds1[0]
    # tip-sample separation
    idnt.apply_preprocessing(["compute_tip_position"])
    assert idnt.preprocessing == ["compute_tip_position"]
    assert idnt["tip position"][0] == 2.2803841798545836e-05
    # correct for an offset in the tip
    idnt.apply_preprocessing(["compute_tip_position", "correct_tip_offset"])
    # This value is subject to change if a better way to estimate the
    # contact point is found:
    assert idnt["tip position"][0] == 4.765854684370548e-06
コード例 #8
0
ファイル: test_indent.py プロジェクト: AFM-analysis/nanite
def test_fitting():
    ds1 = nanite.IndentationGroup(jpkfile)
    idnt = ds1[0]
    idnt.apply_preprocessing(["compute_tip_position"])

    inparams = nanite.model.model_hertz_paraboloidal.get_parameter_defaults()
    inparams["baseline"].vary = True
    inparams["contact_point"].set(1.8e-5)

    # Fit with absolute full range
    idnt.fit_model(model_key="hertz_para",
                   params_initial=inparams,
                   range_x=(0, 0),
                   range_type="absolute",
                   x_axis="tip position",
                   y_axis="force",
                   segment="approach",
                   weight_cp=False)
    params = idnt.fit_properties["params_fitted"]
    assert np.allclose(params["contact_point"].value, 1.8029310201193193e-05)
    assert np.allclose(params["E"].value, 14741.958242422093)

    # Fit with absolute short
    idnt.fit_model(model_key="hertz_para",
                   params_initial=inparams,
                   range_x=(17e-06, 19e-6),
                   range_type="absolute",
                   x_axis="tip position",
                   y_axis="force",
                   segment="approach",
                   weight_cp=False)
    params2 = idnt.fit_properties["params_fitted"]
    assert np.allclose(params2["contact_point"].value, 1.8028461828272924e-05)
    assert np.allclose(params2["E"].value, 14840.840404880484)

    # Fit with relative to initial fit
    idnt.fit_model(model_key="hertz_para",
                   params_initial=params2,
                   range_x=(-2e-6, 1e-6),
                   range_type="relative cp",
                   x_axis="tip position",
                   y_axis="force",
                   segment="approach",
                   weight_cp=False)
    params3 = idnt.fit_properties["params_fitted"]
    # These results are subject to change if the "relative cp" method is
    # changed.
    assert np.allclose(params3["contact_point"].value, 1.8028478083499856e-05)
    assert np.allclose(params3["E"].value, 14839.821714634612)
コード例 #9
0
ファイル: test_indent.py プロジェクト: AFM-analysis/nanite
def test_rate_quality_disabled():
    ds1 = nanite.IndentationGroup(jpkfile)
    idnt = ds1[0]
    idnt.apply_preprocessing(["compute_tip_position"])

    inparams = nanite.model.model_hertz_paraboloidal.get_parameter_defaults()
    inparams["baseline"].vary = True
    inparams["contact_point"].set(1.8e-5)

    # Fit with absolute full range
    idnt.fit_model(model_key="hertz_para",
                   params_initial=inparams,
                   range_x=(0, 0),
                   range_type="absolute",
                   x_axis="tip position",
                   y_axis="force",
                   segment="approach",
                   weight_cp=False)

    r1 = idnt.rate_quality(training_set="zef18", regressor="none")
    assert r1 == -1
コード例 #10
0
ファイル: test_indent.py プロジェクト: AFM-analysis/nanite
def test_get_initial_fit_parameters():
    """This is a convenience function"""
    ds1 = nanite.IndentationGroup(jpkfile)
    idnt = ds1[0]
    # A: sanity check
    fp = idnt.get_initial_fit_parameters()
    assert fp["contact_point"].value == 0, "need to get tip position first"
    # B: get default fit parameters (hertz_para)
    idnt.apply_preprocessing(["compute_tip_position"])
    fp = idnt.get_initial_fit_parameters()
    for kk in ['E', 'R', 'nu', 'contact_point', 'baseline']:
        assert kk in fp.keys()
    # C: set other model and get fit parameters
    idnt.fit_properties["model_key"] = "hertz_pyr3s"
    fp2 = idnt.get_initial_fit_parameters()
    for kk in ['E', 'alpha', 'nu', 'contact_point', 'baseline']:
        assert kk in fp2.keys()
    # D: fit and get from fit_properties
    idnt.fit_model(params_initial=fp2)
    fp3 = idnt.get_initial_fit_parameters()
    assert fp2 == fp3
コード例 #11
0
def test_simple_ancillary_override_nan():
    """nan values are not used and should be ignored"""
    ds1 = nanite.IndentationGroup(jpkfile)
    idnt = ds1[0]

    with MockModelModule(compute_ancillaries=lambda x: {"E": np.nan},
                         parameter_anc_keys=["E"],
                         parameter_anc_names=["ancillary E guess"],
                         parameter_anc_units=["Pa"],
                         model_key="test2"):
        # We need to perform preprocessing first, if we want to get the
        # correct initial contact point.
        idnt.apply_preprocessing(["compute_tip_position"])
        # We set the baseline fixed, because this test was written so)
        params_initial = idnt.get_initial_fit_parameters(model_key="test2")
        params_initial["baseline"].set(vary=False)
        idnt.fit_model(model_key="test2", params_initial=params_initial)
        assert idnt.fit_properties["params_initial"]["E"].value == 3000
        assert np.allclose(idnt.fit_properties["params_fitted"]["E"].value,
                           1584.8876592662375,
                           atol=0,
                           rtol=1e-5)
コード例 #12
0
def test_simple_ancillary_override():
    """basic test for ancillary parameters"""
    ds1 = nanite.IndentationGroup(jpkfile)
    idnt = ds1[0]

    with MockModel(
        compute_ancillaries=lambda x: {"E": 1580},
        parameter_anc_keys=["E"],
        parameter_anc_names=["ancillary E guess"],
        parameter_anc_units=["Pa"],
            model_key="test1"):
        # We need to perform preprocessing first, if we want to get the
        # correct initial contact point.
        idnt.apply_preprocessing(["compute_tip_position"])
        # We set the baseline fixed, because this test was written so)
        params_initial = idnt.get_initial_fit_parameters(model_key="test1")
        params_initial["baseline"].set(vary=False)
        idnt.fit_model(model_key="test1",
                       params_initial=params_initial)
        assert idnt.fit_properties["params_initial"]["E"].value == 1580
        assert np.allclose(idnt.fit_properties["params_fitted"]["E"].value,
                           1572.7685940809245,
                           atol=0,
                           rtol=1e-5)
コード例 #13
0
ファイル: test_indent.py プロジェクト: AFM-analysis/nanite
def test_rate_quality_nofit():
    ds1 = nanite.IndentationGroup(jpkfile)
    idnt = ds1[0]
    r1 = idnt.rate_quality()
    assert r1 == -1
コード例 #14
0
ファイル: test_indent.py プロジェクト: AFM-analysis/nanite
def test_apply_preprocessing():
    ds1 = nanite.IndentationGroup(jpkfile)
    idnt = ds1[0]
    # apply preprocessing by manually setting the list
    idnt.preprocessing = ["compute_tip_position"]
    idnt.apply_preprocessing()
コード例 #15
0
    def __init__(self, *args, **kwargs):
        """Base class for force-indentation analysis"""
        super(UiForceDistance, self).__init__(*args, **kwargs)
        path_ui = pkg_resources.resource_filename("pyjibe.fd", "main.ui")
        uic.loadUi(path_ui, self)

        self.settings = QtCore.QSettings()
        self.settings.setIniCodec("utf-8")
        if not self.settings.value("force-distance/rate ts path", ""):
            dataloc = pathlib.Path(QtCore.QStandardPaths.writableLocation(
                QtCore.QStandardPaths.AppDataLocation))
            ts_import_path = dataloc / "force-distance_rate-ts-user"
            self.settings.setValue("force-distance/rate ts path",
                                   str(ts_import_path))

        UiForceDistance._instance_counter += 1
        title = "Force-Distance #{}".format(self._instance_counter)
        self.parent().setWindowTitle(title)

        self.data_set = nanite.IndentationGroup()

        # rating scheme
        self.rating_scheme_setup()

        # Signals
        # tabs
        self.tabs.currentChanged.connect(self.on_tab_changed)
        # fitting / parameters
        self.tab_edelta.sp_delta_num_samples.valueChanged.connect(
            self.on_params_init)
        self.btn_fitall.clicked.connect(self.on_fit_all)
        self.tab_fit.cb_delta_select.currentIndexChanged.connect(
            self.tab_edelta.cb_delta_select.setCurrentIndex)
        self.tab_edelta.cb_delta_select.currentIndexChanged.connect(
            self.tab_fit.cb_delta_select.setCurrentIndex)
        self.tab_fit.sp_range_1.valueChanged["double"].connect(
            self.tab_edelta.on_delta_change_spin)
        self.tab_fit.sp_range_1.valueChanged.connect(self.on_params_init)
        self.tab_fit.sp_range_2.valueChanged.connect(self.on_params_init)

        # rating
        self.btn_rating_filter.clicked.connect(self.on_rating_threshold)
        self.cb_rating_scheme.currentTextChanged.connect(
            self.on_cb_rating_scheme)
        self.btn_rater.clicked.connect(self.on_user_rate)
        # plotting parameters
        self.cb_mpl_rescale_plot_x.stateChanged.connect(
            self.on_mpl_curve_update)
        self.cb_mpl_rescale_plot_x_min.valueChanged.connect(
            self.on_mpl_curve_update)
        self.cb_mpl_rescale_plot_x_max.valueChanged.connect(
            self.on_mpl_curve_update)
        self.cb_mpl_rescale_plot_y.stateChanged.connect(
            self.on_mpl_curve_update)
        self.cb_mpl_rescale_plot_y_min.valueChanged.connect(
            self.on_mpl_curve_update)
        self.cb_mpl_rescale_plot_y_max.valueChanged.connect(
            self.on_mpl_curve_update)

        # Random string for identification of autosaved results
        self._autosave_randstr = hashlib.md5(time.ctime().encode("utf-8")
                                             ).hexdigest()[:5]
        # Initialize `override` parameter:
        # -1: not decided
        #  0: do not override existing files
        #  1: override existing files
        #  2: create additional file with date
        self._autosave_override = -1
        # Filenames that were created by this instance
        self._autosave_original_files = []