climate_ref.solver
#
Solver to determine which diagnostics need to be calculated
This module provides a solver to determine which diagnostics need to be calculated.
DiagnosticExecution
#
Class to hold information about the execution of a diagnostic
This is a temporary class used by the solver to hold information about an execution that might be required.
Source code in packages/climate-ref/src/climate_ref/solver.py
dataset_key
property
#
Key used to uniquely identify the execution group
This key is unique to an execution group and uses unique set of metadata (selectors) that defines the group. This key is combines the selectors from each source dataset type into a single key and should be stable if new datasets are added or removed.
selectors
property
#
Collection of selectors used to identify the datasets
These are the key, value pairs that were selected during the initial group-by, for each data requirement.
build_execution_definition(output_root)
#
Build the execution definition for the current diagnostic execution.
The returned definition uses a placeholder fragment for the output directory.
solve_required_executions rewrites output_directory via
:func:attrs.evolve once the new Execution.id is known.
Source code in packages/climate-ref/src/climate_ref/solver.py
ExecutionSolver
#
A solver to determine which executions need to be calculated.
Source code in packages/climate-ref/src/climate_ref/solver.py
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 | |
build_from_db(config, db)
staticmethod
#
Initialise the solver using information from the database
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
db
|
Database
|
Database instance |
required |
Returns:
| Type | Description |
|---|---|
ExecutionSolver
|
A new ExecutionSolver instance |
Source code in packages/climate-ref/src/climate_ref/solver.py
solve(filters=None)
#
Solve which executions need to be calculated for a dataset
The solving scheme is iterative, for each iteration we find all diagnostics that can be solved and calculate them. After each iteration we check if there are any more diagnostics to solve.
Yields:
| Type | Description |
|---|---|
DiagnosticExecution
|
A class containing the information related to the execution of a diagnostic |
Source code in packages/climate-ref/src/climate_ref/solver.py
SolveFilterOptions
#
Options to filter the diagnostics that are solved
Source code in packages/climate-ref/src/climate_ref/solver.py
dataset = None
class-attribute
instance-attribute
#
Filter datasets by facet values before solving.
Keys are facet names (e.g. source_id, variable_id) and values are
lists of allowed values. Different facets are ANDed together; multiple
values for the same facet are ORed.
diagnostic = None
class-attribute
instance-attribute
#
Check if the diagnostic slug contains any of the provided values
exclude_diagnostic = None
class-attribute
instance-attribute
#
Exclude diagnostics by slug or provider/diagnostic pair.
Matching is exact and case-insensitive, unlike the fuzzy include filters.
This uses the same token format as the REF_TEST_CASES_SKIP
environment variable.
provider = None
class-attribute
instance-attribute
#
Check if the provider slug contains any of the provided values
apply_dataset_filters(data_catalog, dataset_filters)
#
Filter data catalogs by facet values
Each facet filter is applied independently to each data catalog. Different facets are ANDed together; multiple values for the same facet are ORed. Facets that do not exist as columns in a given catalog are skipped for that catalog.
When a DataCatalog is provided, the returned value preserves the DataCatalog wrapper (with adapter and database references) so that downstream finalisation still works.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data_catalog
|
Mapping[SourceDatasetType, DataCatalog | DataFrame]
|
Data catalogs keyed by source dataset type |
required |
dataset_filters
|
dict[str, list[str]]
|
Mapping of facet names to lists of allowed values |
required |
Returns:
| Type | Description |
|---|---|
dict[SourceDatasetType, DataCatalog | DataFrame]
|
Filtered data catalogs |
Source code in packages/climate-ref/src/climate_ref/solver.py
as_frame(catalog)
#
Unwrap a catalog to the DataFrame behind it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
catalog
|
DataFrame | DataCatalog
|
Either a catalog wrapper or a plain frame. |
required |
Returns:
| Type | Description |
|---|---|
DataFrame
|
The catalog as a DataFrame. |
Source code in packages/climate-ref/src/climate_ref/solver.py
catalog_for_requirement(data_catalog, requirement)
#
Resolve the catalog a requirement is solved against, folding in its declared fallbacks.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data_catalog
|
Mapping[SourceDatasetType, DataFrame | DataCatalog]
|
Data catalogs for each source dataset type. |
required |
requirement
|
DataRequirement
|
The requirement to resolve a catalog for. |
required |
Returns:
| Type | Description |
|---|---|
DataFrame | DataCatalog | None
|
The requirement's catalog, or |
Source code in packages/climate-ref/src/climate_ref/solver.py
extract_covered_datasets(data_catalog, requirement)
#
Determine the different diagnostic executions that should be performed with the current data catalog
Source code in packages/climate-ref/src/climate_ref/solver.py
fail_stale_in_progress_executions(db, *, stale_after_seconds=DEFAULT_STALE_EXECUTION_AGE_SECONDS)
#
Mark abandoned in-progress executions as failed so the next solve can retry them.
An execution is considered abandoned when it has successful=None and was
created longer ago than stale_after_seconds. This commonly happens when
a worker is killed (OOM, walltime, segfault) before its result-handling
callback ran, or when the join loop crashed mid-flight.
The execution group's dirty flag is set so the existing retry logic
(ExecutionGroup.should_run) picks the work back up on the next solve.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
db
|
Database
|
The database to inspect |
required |
stale_after_seconds
|
int
|
Minimum age in seconds before an in-progress execution is considered abandoned. Defaults to 6 hours, matching the Celery and LocalExecutor per-task time limits. |
DEFAULT_STALE_EXECUTION_AGE_SECONDS
|
Returns:
| Type | Description |
|---|---|
int
|
The number of executions that were marked failed. |
Source code in packages/climate-ref/src/climate_ref/solver.py
matches_filter(diagnostic, filters)
#
Check if a diagnostic matches the provided filters
Each filter is optional and a diagnostic will match if it satisfies all the provided filters. i.e. the filters are ANDed together.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
diagnostic
|
Diagnostic
|
Diagnostic to check against the filters |
required |
filters
|
SolveFilterOptions | None
|
Collection of filters to apply to the diagnostic If no filters are provided, the diagnostic is considered to match |
required |
Returns:
| Type | Description |
|---|---|
True if the diagnostic matches the filters, False otherwise
|
|
Source code in packages/climate-ref/src/climate_ref/solver.py
newer_rows(candidate, held)
#
Select the rows of candidate that held lacks, or holds at an older version.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
candidate
|
DataFrame
|
Rows offered by a fallback collection. |
required |
held
|
DataFrame
|
Rows already taken, which win a version tie. |
required |
Returns:
| Type | Description |
|---|---|
DataFrame
|
The subset of |
Source code in packages/climate-ref/src/climate_ref/solver.py
solve_executions(data_catalog, diagnostic, provider)
#
Calculate the diagnostic executions that need to be performed for a given diagnostic
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data_catalog
|
Mapping[SourceDatasetType, DataFrame | DataCatalog]
|
Data catalogs for each source dataset type |
required |
diagnostic
|
Diagnostic
|
Diagnostic of interest |
required |
provider
|
DiagnosticProvider
|
Provider of the diagnostic |
required |
Returns:
| Type | Description |
|---|---|
Generator[DiagnosticExecution, None, None]
|
A generator that yields the diagnostic executions that need to be performed |
Source code in packages/climate-ref/src/climate_ref/solver.py
solve_required_executions(db, dry_run=False, execute=True, solver=None, config=None, timeout=60, wait=True, one_per_provider=False, one_per_diagnostic=False, filters=None, limit=None, rerun_failed=False)
#
Solve for executions that require recalculation
This may trigger a number of additional calculations depending on what data has been ingested since the last solve.
When wait is True (the default) this blocks until all executions complete,
copying their outputs to the results directory and ingesting them.
timeout bounds that wait; a non-positive timeout (<= 0) waits with no time limit.
wait=False queues the executions and returns immediately without collecting their results.
Raises:
| Type | Description |
|---|---|
TimeoutError
|
If the executions aren't completed within a positive |
Source code in packages/climate-ref/src/climate_ref/solver.py
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 | |
union_with_fallbacks(primary, fallbacks, primary_type)
#
Fill a reference catalog from its fallback collections.
A dataset held by more than one collection is taken at its newest version, and from the primary when the versions tie. So publishing a dataset to obs4MIPs takes over from the obs4REF copy without any re-ingest, but a newer registry version is not lost to a stale published one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
primary
|
DataFrame | DataCatalog
|
The catalog the requirement asks for, which wins a version tie. |
required |
fallbacks
|
Sequence[DataFrame | DataCatalog]
|
Catalogs that may stand in for it, tried in order. |
required |
primary_type
|
SourceDatasetType
|
Source type the merged rows are delivered under. |
required |
Returns:
| Type | Description |
|---|---|
DataFrame | DataCatalog
|
The primary catalog, extended with the fallback rows that win.
The original catalog is returned untouched when nothing is added.
The added rows carry |