Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

{dontmerge]Scraping result #823

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
0e8f113
Added basic project class for experimenting
joernweissenborn Aug 8, 2021
3b68cc6
Basic project idea
joernweissenborn Aug 8, 2021
90d4fe3
Added test for project create and open
joernweissenborn Aug 12, 2021
76f49ad
Added test fparallel model generator
joernweissenborn Aug 12, 2021
bb743cf
Added test for project model generation
joernweissenborn Aug 12, 2021
e9ca6d3
Added project parameter generation generation
jsnel Aug 13, 2021
0f863d4
Added csv to parameter generation
joernweissenborn Aug 13, 2021
a6c1910
Tweaked result saving as yaml
joernweissenborn Aug 13, 2021
816eff7
Added dataset import to project
joernweissenborn Aug 13, 2021
5c8312f
Added sequential model generator
joernweissenborn Aug 13, 2021
b92fff4
Example model is now generated
joernweissenborn Aug 13, 2021
647e6b5
Added scheme generation
joernweissenborn Aug 13, 2021
f2234e5
Changed dataset fixture in project test
joernweissenborn Aug 14, 2021
e9f1ae4
Fix scheme test
joernweissenborn Aug 14, 2021
cef2221
Added basic project run
joernweissenborn Aug 14, 2021
eea1a74
Made save_result only serializ the Result object
joernweissenborn Aug 14, 2021
e892fa6
Rewrote Result.save
joernweissenborn Aug 14, 2021
4781ed4
Added project modul to linters
joernweissenborn Aug 14, 2021
538af32
Added Model.as_dict
joernweissenborn Aug 14, 2021
b99c73d
Added save_model yml implementation
joernweissenborn Aug 14, 2021
d9f82a0
Added test to save result
joernweissenborn Aug 14, 2021
1b714ab
Added test for load result
joernweissenborn Aug 14, 2021
74921ee
Added Result.verify
joernweissenborn Aug 14, 2021
0e0bcac
🔧 Activated mypy for project submodule
s-weigand Aug 14, 2021
dbbf880
Created glotran.project.dataclasses module
joernweissenborn Aug 15, 2021
78d7078
Adressed mypy issues
joernweissenborn Aug 15, 2021
7c5dbea
Created stub for Model.py
joernweissenborn Aug 15, 2021
48b0d3a
Changed scheme saving to new saving method
joernweissenborn Aug 19, 2021
ce3c74a
Added save/load result file to io
joernweissenborn Aug 19, 2021
1765841
Added data_filters to save_dataset
joernweissenborn Aug 19, 2021
968ebb8
Readded folder plugin
joernweissenborn Aug 20, 2021
9d61605
Removed Generator and project
joernweissenborn Sep 17, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ repos:
rev: 6.1.1
hooks:
- id: pydocstyle
files: "^glotaran/(plugin_system|utils|deprecation|testing)"
exclude: "docs|tests?/"
files: "^glotaran/(plugin_system|utils|deprecation|project)"
exclude: "docs|tests?"
# this is needed due to the following issue:
# https://github.com/PyCQA/pydocstyle/issues/368
args: [--ignore-decorators=wrap_func_as_method]
Expand All @@ -87,14 +87,14 @@ repos:
rev: v1.8.0
hooks:
- id: darglint
files: "^glotaran/(plugin_system|utils|deprecation|testing)"
exclude: "docs|tests?/"
files: "^glotaran/(plugin_system|utils|deprecation|project)"
exclude: "docs|tests?"

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.910
hooks:
- id: mypy
files: "^glotaran/(plugin_system|utils|deprecation|testing)"
files: "^glotaran/(plugin_system|utils|deprecation|project)"
exclude: "docs"
additional_dependencies: [types-all]

Expand Down
24 changes: 13 additions & 11 deletions glotaran/analysis/optimize.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from scipy.optimize import OptimizeResult
from scipy.optimize import least_squares

from glotaran import __version__ as glotaran_version
from glotaran.analysis.problem import Problem
from glotaran.analysis.problem_grouped import GroupedProblem
from glotaran.analysis.problem_ungrouped import UngroupedProblem
Expand Down Expand Up @@ -94,13 +95,13 @@ def _create_result(
ls_result.nfev if ls_result is not None else len(problem.parameter_history)
)
number_of_jacobian_evaluation = ls_result.njev if success else None
optimality = ls_result.optimality if success else None
optimality = float(ls_result.optimality) if success else None
number_of_data_points = ls_result.fun.size if success else None
number_of_variables = ls_result.x.size if success else None
degrees_of_freedom = number_of_data_points - number_of_variables if success else None
chi_square = np.sum(ls_result.fun ** 2) if success else None
chi_square = float(np.sum(ls_result.fun ** 2)) if success else None
reduced_chi_square = chi_square / degrees_of_freedom if success else None
root_mean_square_error = np.sqrt(reduced_chi_square) if success else None
root_mean_square_error = float(np.sqrt(reduced_chi_square)) if success else None
jacobian = ls_result.jac if success else None

if success:
Expand All @@ -123,23 +124,24 @@ def _create_result(

return Result(
additional_penalty=problem.additional_penalty,
chi_square=chi_square,
cost=problem.cost,
covariance_matrix=covariance_matrix,
data=data,
degrees_of_freedom=degrees_of_freedom,
free_parameter_labels=free_parameter_labels,
number_of_function_evaluations=number_of_function_evaluation,
glotaran_version=glotaran_version,
initial_parameters=problem.scheme.parameters,
optimized_parameters=parameters,
scheme=problem.scheme,
success=success,
termination_reason=termination_reason,
chi_square=chi_square,
covariance_matrix=covariance_matrix,
degrees_of_freedom=degrees_of_freedom,
jacobian=jacobian,
number_of_data_points=number_of_data_points,
number_of_function_evaluations=number_of_function_evaluation,
number_of_jacobian_evaluations=number_of_jacobian_evaluation,
number_of_variables=number_of_variables,
optimality=optimality,
optimized_parameters=parameters,
reduced_chi_square=reduced_chi_square,
root_mean_square_error=root_mean_square_error,
scheme=problem.scheme,
success=success,
termination_reason=termination_reason,
)
1 change: 0 additions & 1 deletion glotaran/analysis/problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ def __init__(self, scheme: Scheme):
self._residual_function = (
residual_nnls if scheme.non_negative_least_squares else residual_variable_projection
)
self._parameters = None
self._dataset_models = None

self._overwrite_index_dependent = self.model.need_index_dependent()
Expand Down
2 changes: 1 addition & 1 deletion glotaran/analysis/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def simulate(
noise: bool = False,
noise_std_dev: float = 1.0,
noise_seed: int | None = None,
):
) -> xr.Dataset:
"""Simulates a model.

Parameters
Expand Down
82 changes: 51 additions & 31 deletions glotaran/builtin/io/folder/folder_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,19 @@

from __future__ import annotations

import os
from pathlib import Path
from typing import TYPE_CHECKING

from glotaran.io import save_dataset
from glotaran.io import save_model
from glotaran.io import save_parameters
from glotaran.io import save_result_file
from glotaran.io import save_scheme
from glotaran.io.interface import ProjectIoInterface
from glotaran.plugin_system.project_io_registration import register_project_io

if TYPE_CHECKING:
from glotaran.io import SavingOptions
from glotaran.project import Result


Expand All @@ -24,7 +30,9 @@ class FolderProjectIo(ProjectIoInterface):
a markdown summary output and the important data saved to files.
"""

def save_result(self, result: Result, result_path: str) -> list[str]:
def save_result(
self, result: Result, folder: str, saving_options: SavingOptions, allow_overwrite: bool
):
"""Save the result to a given folder.

Returns a list with paths of all saved items.
Expand All @@ -37,38 +45,50 @@ def save_result(self, result: Result, result_path: str) -> list[str]:
----------
result : Result
Result instance to be saved.
result_path : str
folder : str
The path to the folder in which to save the result.

Returns
-------
list[str]
List of file paths which were created.
saving_options : SavingOptions
Options for saving the the result.
allow_overwrite : bool
Whether or not to allow overwriting existing files, by default False

Raises
------
ValueError
If ``result_path`` is a file.
If ``folder`` is a file.
FileExistsError
If ``folder`` is exists and ``allow_overwrite`` is ``False``.
"""
if not os.path.exists(result_path):
os.makedirs(result_path)
if not os.path.isdir(result_path):
raise ValueError(f"The path '{result_path}' is not a directory.")

paths = []

md_path = os.path.join(result_path, "result.md")
with open(md_path, "w") as f:
f.write(str(result.markdown()))
paths.append(md_path)

csv_path = os.path.join(result_path, "optimized_parameters.csv")
result.optimized_parameters.to_csv(csv_path)
paths.append(csv_path)

for label, data in result.data.items():
nc_path = os.path.join(result_path, f"{label}.nc")
data.to_netcdf(nc_path, engine="netcdf4")
paths.append(nc_path)

return paths
result_folder = Path(folder)
if not result_folder.exists():
result_folder.mkdir()
elif result_folder.is_file():
raise ValueError(f"The path '{result_folder}' is not a directory.")
elif not allow_overwrite:
raise FileExistsError

if saving_options.report:
report_file = result_folder / "result.md"
with open(report_file, "w") as f:
f.write(str(result.markdown()))

result.scheme.model_file = "model.yml"
save_model(result.scheme.model, result_folder / result.scheme.model_file)
result.scheme.parameters_file = "initial_parameters.csv"
result.initial_parameters_file = result.scheme.parameters_file
save_parameters(result.scheme.parameters, result_folder / result.scheme.parameters_file)
result.optimized_parameters_file = "optimized_parameters.csv"
save_parameters(
result.optimized_parameters, result_folder / result.optimized_parameters_file
)
result.scheme_file = "scheme.yml"
save_scheme(result.scheme, result_folder / result.scheme_file)

result.data_files = {
label: f"{label}.{saving_options.data_format}" for label in result.data
}

for label, data_file in result.data_files.items():
save_dataset(result.data[label], result_folder / data_file)

save_result_file(result, result_folder / "glotaran_result.yml")
74 changes: 43 additions & 31 deletions glotaran/builtin/io/folder/test/test_folder_plugin.py
Original file line number Diff line number Diff line change
@@ -1,54 +1,66 @@
from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING

import pytest

from glotaran.analysis.optimize import optimize
from glotaran.examples.sequential import scheme
from glotaran.io import save_result
from glotaran.project.test.test_result import dummy_result # noqa: F401

if TYPE_CHECKING:
from typing import Literal

from py.path import local as TmpDir

from glotaran.project.result import Result


@pytest.mark.parametrize("format_name", ("folder", "legacy"))
@pytest.fixture(scope="session")
def dummy_result():
"""Dummy result for testing."""
scheme.maximum_number_function_evaluations = 1
yield optimize(scheme)


def test_save_result_folder(
tmpdir: TmpDir,
dummy_result: Result, # noqa: F811
format_name: Literal["folder", "legacy"],
dummy_result: Result,
):
"""Check all files exist."""

result_dir = Path(tmpdir / "testresult")
save_result(result_path=str(result_dir), format_name=format_name, result=dummy_result)
result_dir = tmpdir / "test_result"
save_result(dummy_result, str(result_dir), format_name="folder")

assert (result_dir / "result.md").exists()
assert (result_dir / "optimized_parameters.csv").exists()
assert (result_dir / "dataset1.nc").exists()
assert (result_dir / "dataset2.nc").exists()
assert (result_dir / "dataset3.nc").exists()
assert result_dir.exists()

wanted_files = [
"result.md",
"glotaran_result.yml",
"scheme.yml",
"model.yml",
"initial_parameters.csv",
"optimized_parameters.csv",
"dataset_1.nc",
]
for wanted in wanted_files:
assert (result_dir / wanted).exists()

@pytest.mark.parametrize("format_name", ("folder", "legacy"))
def test_save_result_folder_error_path_is_file(
tmpdir: TmpDir,
dummy_result: Result, # noqa: F811
format_name: Literal["folder", "legacy"],
):
"""Raise error if result_path is a file without extension and overwrite is true."""

result_dir = Path(tmpdir / "testresult")
result_dir.touch()

with pytest.raises(ValueError, match="The path '.+?' is not a directory."):
save_result(
result_path=str(result_dir),
format_name=format_name,
result=dummy_result,
allow_overwrite=True,
)

# @pytest.mark.parametrize("format_name", ("folder", "legacy"))
# def test_save_result_folder_error_path_is_file(
# tmpdir: TmpDir,
# dummy_result: Result,
# format_name: Literal["folder", "legacy"],
# ):
# """Raise error if result_path is a file without extension and overwrite is true."""
#
# result_dir = Path(tmpdir / "testresult")
# result_dir.touch()
#
# with pytest.raises(ValueError, match="The path '.+?' is not a directory."):
# save_result(
# result_path=str(result_dir),
# format_name=format_name,
# result=dummy_result,
# allow_overwrite=True,
# )
26 changes: 8 additions & 18 deletions glotaran/builtin/io/netCDF/netCDF.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from __future__ import annotations

import os

import xarray as xr

from glotaran.io import DataIoInterface
from glotaran.io import register_data_io
from glotaran.project import SavingOptions
from glotaran.project import default_data_filters


@register_data_io("nc")
Expand All @@ -17,22 +17,12 @@ def save_dataset(
self,
dataset: xr.Dataset,
file_name: str,
data_filters: list[str] | None = None,
*,
saving_options: SavingOptions = SavingOptions(),
allow_overwrite: bool = False,
):
if not allow_overwrite and os.path.exists(file_name):
raise FileExistsError

data_to_save = dataset

data_filter = (
saving_options.data_filter
if saving_options.data_filter is not None
else default_data_filters[saving_options.level]
)

if data_filter is not None:

data_to_save = xr.Dataset()
for item in data_filter:
data_to_save[item] = dataset[item]

data_to_save.to_netcdf(file_name)
data_to_save = dataset if data_filters is None else dataset[data_filters]
data_to_save.to_netcdf(file_name, mode="w")
Loading