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

EXPERIMENTAL: Add support for fragments and degridding #350

Draft
wants to merge 35 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
3d0535c
Use nearest-neighbour interpolation in regions where extrapolation is…
JSKenyon Jul 26, 2023
3d1d5a6
Merge branch 'v0.2.1-dev' of github.com:ratt-ru/QuartiCal into v0.2.1…
JSKenyon Jul 26, 2023
6b22750
Add interface for degrid models.
JSKenyon Jul 28, 2023
e1e3dcb
Commit initial, semi-working code for generating model visibilities f…
JSKenyon Jul 28, 2023
d7e69e9
Add ducc0 and sympy as extras under degrid banner in pyproject.toml.
JSKenyon Jul 31, 2023
0b26002
Add/change functionlity to enable new-style models.
JSKenyon Jul 31, 2023
aed942a
Change advanced model to a simple boolean flag.
JSKenyon Jul 31, 2023
0d43f3e
Renaming.
JSKenyon Jul 31, 2023
6aa67f2
Fix tag format.
JSKenyon Jul 31, 2023
bba12a2
Make dask usage less unholy.
JSKenyon Jul 31, 2023
808e17a
Add clone.
JSKenyon Jul 31, 2023
519106b
Don't init vis as empty - duh.
JSKenyon Jul 31, 2023
58eff19
Fix correlation handling in degrid code.
JSKenyon Aug 1, 2023
2371715
Expose degrid (predict) threading in model arguments.
JSKenyon Aug 1, 2023
7f1bc9a
Disable degrid inputs in non-advanced mode.
JSKenyon Aug 1, 2023
00af518
Use legacy models in tests until such time as I can reconfigure them.
JSKenyon Aug 1, 2023
aaaf76a
Utilise environment variable when dask.address is unset. (#288)
JSKenyon Aug 3, 2023
5f0368c
Merge branch 'v0.2.1-dev' of github.com:ratt-ru/QuartiCal into v0.2.1…
JSKenyon Aug 4, 2023
a5b6650
Merge branch 'v0.2.1-dev' into v0.2.1-degridder
JSKenyon Aug 4, 2023
ad4f91b
Fix incorrect import in tests.
JSKenyon Aug 4, 2023
232ae41
Commit WIP code for experimental fragment branch.
JSKenyon Aug 4, 2023
ec2f496
Import from fragments.
JSKenyon Aug 4, 2023
1bb7448
Add output.fragment_path, which, if set, causes QC to write columns t…
JSKenyon Aug 10, 2023
e734507
Add plotting functionality (#290)
JSKenyon Aug 25, 2023
b23b168
Merge branch 'v0.2.1-dev' of github.com:ratt-ru/QuartiCal into v0.2.1…
JSKenyon Aug 29, 2023
d6d8701
Merge in plotter.
JSKenyon Aug 29, 2023
2e0b9e8
Fix #293 - OOB access caused by `output.subtract_directions` (#294)
JSKenyon Aug 30, 2023
5cfadc4
Merge branch 'v0.2.1-dev' of github.com:ratt-ru/QuartiCal into v0.2.1…
JSKenyon Sep 13, 2023
9a28794
Namedbackups (#296)
landmanbester Sep 13, 2023
b740a37
Merge branch 'v0.2.1-dev' of github.com:ratt-ru/QuartiCal into v0.2.1…
JSKenyon Sep 13, 2023
5a1d5c7
Merge branch 'v0.2.1-dev' into v0.2.1-experimental-dask-ms
JSKenyon Sep 15, 2023
d8a9719
Depend on dask-ms master.
JSKenyon Sep 21, 2023
75fa1d8
Merge in main.
JSKenyon Nov 29, 2024
2cdaf80
Fix old usage.
JSKenyon Nov 29, 2024
7b9cf90
Fix uncommited pyproject.
JSKenyon Nov 29, 2024
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
31 changes: 17 additions & 14 deletions quartical/apps/summary.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import argparse
from pathlib import Path
from daskms import xds_from_storage_ms, xds_from_storage_table
from daskms.experimental.fragments import (
xds_from_ms_fragment,
xds_from_table_fragment
)
from daskms.fsspec_store import DaskMSStore
import numpy as np
import dask.array as da
Expand Down Expand Up @@ -44,7 +47,7 @@ def configure_loguru(output_dir):
def antenna_info(path):

# NOTE: Assume one dataset for now.
ant_xds = xds_from_storage_table(path + "::ANTENNA")[0]
ant_xds = xds_from_table_fragment(path + "::ANTENNA")[0]

antenna_names = ant_xds.NAME.values
antenna_mounts = ant_xds.MOUNT.values
Expand All @@ -64,7 +67,7 @@ def antenna_info(path):

def data_desc_info(path):

dd_xds_list = xds_from_storage_table( # noqa
dd_xds_list = xds_from_table_fragment( # noqa
path + "::DATA_DESCRIPTION",
group_cols=["__row__"],
chunks={"row": 1, "chan": -1}
Expand All @@ -76,7 +79,7 @@ def data_desc_info(path):

def feed_info(path):

feed_xds_list = xds_from_storage_table(
feed_xds_list = xds_from_table_fragment(
path + "::FEED",
group_cols=["SPECTRAL_WINDOW_ID"],
chunks={"row": -1}
Expand Down Expand Up @@ -106,15 +109,15 @@ def feed_info(path):

def flag_cmd_info(path):

flag_cmd_xds = xds_from_storage_table(path + "::FLAG_CMD") # noqa
flag_cmd_xds = xds_from_table_fragment(path + "::FLAG_CMD") # noqa

# Not printing any summary information for this subtable yet - not sure
# what is relevant.


def field_info(path):

field_xds = xds_from_storage_table(path + "::FIELD")[0]
field_xds = xds_from_table_fragment(path + "::FIELD")[0]

field_ids = list(range(field_xds.sizes['row']))
source_ids = [i for i in field_xds.SOURCE_ID.values]
Expand Down Expand Up @@ -148,23 +151,23 @@ def field_info(path):

def history_info(path):

history_xds = xds_from_storage_table(path + "::HISTORY")[0] # noqa
history_xds = xds_from_table_fragment(path + "::HISTORY")[0] # noqa

# Not printing any summary information for this subtable yet - not sure
# what is relevant.


def observation_info(path):

observation_xds = xds_from_storage_table(path + "::OBSERVATION")[0] # noqa
observation_xds = xds_from_table_fragment(path + "::OBSERVATION")[0] # noqa

# Not printing any summary information for this subtable yet - not sure
# what is relevant.


def polarization_info(path):

polarization_xds = xds_from_storage_table(path + "::POLARIZATION")[0]
polarization_xds = xds_from_table_fragment(path + "::POLARIZATION")[0]

corr_types = polarization_xds.CORR_TYPE.values

Expand All @@ -182,15 +185,15 @@ def polarization_info(path):

def processor_info(path):

processor_xds = xds_from_storage_table(path + "::PROCESSOR")[0] # noqa
processor_xds = xds_from_table_fragment(path + "::PROCESSOR")[0] # noqa

# Not printing any summary information for this subtable yet - not sure
# what is relevant.


def spw_info(path):

spw_xds_list = xds_from_storage_table(
spw_xds_list = xds_from_table_fragment(
path + "::SPECTRAL_WINDOW",
group_cols=["__row__"],
chunks={"row": 1, "chan": -1}
Expand All @@ -214,7 +217,7 @@ def spw_info(path):

def state_info(path):

state_xds = xds_from_storage_table(path + "::STATE")[0] # noqa
state_xds = xds_from_table_fragment(path + "::STATE")[0] # noqa

# Not printing any summary information for this subtable yet - not sure
# what is relevant.
Expand All @@ -233,7 +236,7 @@ def source_info(path):

def pointing_info(path):

pointing_xds = xds_from_storage_table(path + "::POINTING")[0] # noqa
pointing_xds = xds_from_table_fragment(path + "::POINTING")[0] # noqa

# Not printing any summary information for this subtable yet - not sure
# what is relevant.
Expand Down Expand Up @@ -362,7 +365,7 @@ def summary():
# Open the data, grouping by the usual columns. Use these datasets to
# produce some useful summaries.

data_xds_list = xds_from_storage_ms(
data_xds_list = xds_from_ms_fragment(
path,
index_cols=("TIME",),
columns=("TIME", "FLAG", "FLAG_ROW", "DATA"),
Expand Down
22 changes: 20 additions & 2 deletions quartical/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
class _GainSchema(object):
gain: Dict[str, Parameter]

# The gain section is loaded explicitly, since we need to form up multiple
# instances.
# The gain and model sections are loaded explicitly, since we need to form
# up multiple instances.
gain_schema = oc.merge(
oc.structured(_GainSchema),
oc.load(f"{dirname}/gain_schema.yaml")
Expand All @@ -42,3 +42,21 @@ class _GainSchema(object):
bases=(BaseConfigSection,),
post_init=POST_INIT_MAP['gain']
)

@dataclass
class _ModelComponentSchema(object):
model_component: Dict[str, Parameter]

model_component_schema = oc.merge(
oc.structured(_ModelComponentSchema),
oc.load(f"{dirname}/model_component_schema.yaml")
)
model_component_schema = model_component_schema.model_component

# Create model dataclass.
ModelComponent = schema_utils.schema_to_dataclass(
model_component_schema,
"ModelComponent",
bases=(BaseConfigSection,),
post_init=POST_INIT_MAP['model_component']
)
25 changes: 25 additions & 0 deletions quartical/config/argument_schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,22 @@ input_model:
given by the dE tagged clusters in LSM1. Leaving this value unset
(the default) will use an identity model.

advanced_recipe:
dtype: bool
default: false
info:
Enable advanced recipe specification for use with degridder/more
complicated modes of model construction.

threads:
dtype: int
default: 1
info:
Controls the number of threads used internally by the various predict
methods. This should typically be set to the same value as
solver.threads if solver.threads is in use. Currently only supported
for degridding.

beam:
dtype: Optional[str]
info:
Expand Down Expand Up @@ -183,6 +199,15 @@ output:
Name of directory in which QuartiCal logging outputs will be stored.
s3 is not currently supported for these outputs.

fragment_path:
dtype: Optional[str]
info:
If set, instead of mutating the input by e.g. writing flags, instead
writes a fragment to this location. A fragment is a zarr backed data
format that is read and dynamically combined with any parent datasets.
This allows QuartiCal to operate in an entirely read-only fashion.
This option is experimental.

log_to_terminal:
default: true
dtype: bool
Expand Down
6 changes: 6 additions & 0 deletions quartical/config/config_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ def __input_model_post_init__(self):
self.__validate_element_choices__()


def __model_component_post_init__(self):
self.__validate_choices__()
self.__validate_element_choices__()


def __output_post_init__(self):

self.__validate_choices__()
Expand Down Expand Up @@ -182,6 +187,7 @@ def __gain_post_init__(self):
POST_INIT_MAP = {
"input_ms": __input_ms_post_init__,
"input_model": __input_model_post_init__,
"model_component": __model_component_post_init__,
"output": __output_post_init__,
"mad_flags": __mad_flags_post_init__,
"solver": __solver_post_init__,
Expand Down
17 changes: 16 additions & 1 deletion quartical/config/external.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from omegaconf import OmegaConf as oc
from typing import Dict, Any
from scabha.cargo import Parameter
from quartical.config import Gain, BaseConfig, gain_schema
from quartical.config import Gain, ModelComponent, BaseConfig, gain_schema


def finalize_structure(additional_config):
Expand All @@ -18,6 +18,21 @@ def finalize_structure(additional_config):
# Use the default terms if no alternative is specified.
terms = terms or BaseConfig.solver.terms

recipe = None
models = [] # No components by default.

# Get last specified version of input_model.recipe.
for cfg in additional_config[::-1]:
advanced_recipe = oc.select(cfg, "input_model.advanced_recipe")
recipe = oc.select(cfg, "input_model.recipe")
if recipe is not None and advanced_recipe:
ingredients = re.split(r'([\+~:])', recipe)
ingredients = [
i for i in ingredients if not bool(re.search(r'([\+~:])', i))
]
models = list(dict.fromkeys(i.split("@")[0] for i in ingredients))
break

FinalConfig = make_dataclass(
"FinalConfig",
[(t, Gain, field(default_factory=Gain)) for t in terms],
Expand Down
11 changes: 9 additions & 2 deletions quartical/config/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,15 @@ def help():
if len(sys.argv) != 1 and not help_arg:
return

# Include a generic gain term in the help config.
additional_config = [oc.from_dotlist(["solver.terms=['gain']"])]
# Include a generic gain term and model component in the help config.
additional_config = [
oc.from_dotlist(
[
"input_model.advanced_recipe=model_component",
"solver.terms=['gain']"
]
)
]
help_class = finalize_structure(additional_config)
HelpConfig = help_class()

Expand Down
10 changes: 10 additions & 0 deletions quartical/config/internal.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
from daskms.fsspec_store import DaskMSStore
from quartical.gains import TERM_TYPES
from quartical.config import ModelComponent


def get_component_dict(opts):

return {
k: getattr(opts, k)
for k in opts.__dataclass_fields__.keys()
if isinstance(getattr(opts, k), ModelComponent)
}


def gains_to_chain(opts):
Expand Down
61 changes: 61 additions & 0 deletions quartical/config/model_component_schema.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
model_component:
path_or_name:
dtype: str
required: true
info:
Path to model/name of column.
type:
dtype: str
choices:
- mds # Replace with awesome acronym eventually.
- tigger-lsm
- column
default: column
info:
Type of model component
tags:
dtype: Optional[List[str]]
info:
Tag for use in the predict.
# region: # Add when implemented.
# dtype: Optional[str]
# info:
# Name of region file to use in degridder.
npix_x:
dtype: Optional[int]
info:
Image x size in pixels for use in degridding.
npix_y:
dtype: Optional[int]
info:
Image y size in pixels for use in degridding.
cellsize_x:
dtype: Optional[float]
info:
Pixel x cellsize in radians.
cellsize_y:
dtype: Optional[float]
info:
Pixel y cellsize in radians.
centre_x:
dtype: int
default: 0
info:
x coordinate of central pixel.
centre_y:
dtype: int
default: 0
info:
y coordinate of central pixel.
integrations_per_image:
dtype: int
default: 0
info:
Number of integrations per image to use in degridding. The default
(zero) is all times in a chunk.
channels_per_image:
dtype: int
default: 0
info:
Number of channels per image to use in degridding. The default
(zero) is all channels in a chunk.
Loading