Skip to content

Commit

Permalink
Merge pull request #24 from tnakazato/refactor-filler-field
Browse files Browse the repository at this point in the history
refactor: filler for FIELD table
  • Loading branch information
tnakazato authored Feb 3, 2025
2 parents 043c054 + 74f6429 commit 3a770b6
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 64 deletions.
7 changes: 1 addition & 6 deletions src/nro45data/psw/ms2/filler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from .antenna import fill_antenna
from .data_description import fill_data_description
from .feed import fill_feed
from .field import _fill_field_columns, _get_field_columns
from .field import fill_field
from .observation import _fill_observation_columns, _get_observation_columns
from .polarization import _fill_polarization_columns, _get_polarization_columns
from .main import fill_main
Expand All @@ -26,11 +26,6 @@
LOG = logging.getLogger(__name__)


def fill_field(msfile: str, hdu: BinTableHDU):
columns = _get_field_columns(hdu)
_fill_field_columns(msfile, columns)


def fill_observation(msfile: str, hdu: BinTableHDU):
columns = _get_observation_columns(hdu)
_fill_observation_columns(msfile, columns)
Expand Down
71 changes: 42 additions & 29 deletions src/nro45data/psw/ms2/filler/field.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
from __future__ import annotations

import logging
from typing import TYPE_CHECKING
from typing import Generator, TYPE_CHECKING

import numpy as np

from .._casa import open_table
from .._casa import datestr2mjd
from .._casa import convert_str_angle_to_rad
from .utils import fix_nrow_to
from .utils import fill_ms_table

if TYPE_CHECKING:
from astropy.io.fits.hdu.BinTableHDU import BinTableHDU

LOG = logging.getLogger(__name__)


def _get_field_columns(hdu: "BinTableHDU") -> dict:
def _get_field_row(hdu: BinTableHDU) -> Generator[dict, None, dict]:
"""Provide field row information.
Args:
hdu: NRO45m psw data in the form of BinTableHDU object.
Yields:
Dictionary containing field row information.
Returns:
Dictionary containing data-dependent column keywords.
"""
# NAME
field_name = hdu.header["OBJECT"].strip()
LOG.debug("field_name: %s", field_name)
Expand All @@ -25,8 +38,11 @@ def _get_field_columns(hdu: "BinTableHDU") -> dict:
# use start time of the observation
history_cards = hdu.header["HISTORY"]
start_time_card = [x for x in history_cards if x.startswith("NEWSTAR START-TIME")]
field_time = float(start_time_card[0].split("=")[-1].strip(" '"))
LOG.debug("field_time: %s", field_time)
sstr = start_time_card[0].split("=")[-1].strip(" '")
LOG.debug("sstr: %s", sstr)
datestr = sstr[0:4] + "/" + sstr[4:6] + "/" + sstr[6:8] + " " + sstr[8:10] + ":" + sstr[10:12] + ":" + sstr[12:14]
LOG.debug("formatted sstr: %s", datestr)
field_time = datestr2mjd(datestr) - 9 * 3600

# NUM_POLY
num_poly = 0
Expand Down Expand Up @@ -62,37 +78,34 @@ def _get_field_columns(hdu: "BinTableHDU") -> dict:
# FLAG_ROW
flag_row = False

columns = {
row = {
"NAME": field_name,
"CODE": field_code,
"TIME": field_time,
"NUM_POLY": num_poly,
"FIELD_EPOCH": field_epoch,
"DELAY_DIR": delay_dir,
"PHASE_DIR": phase_dir,
"REFERENCE_DIR": reference_dir,
"SOURCE_ID": source_id,
"FLAG_ROW": flag_row,
}

return columns


def _fill_field_columns(msfile: str, columns: dict):
with open_table(msfile + "/FIELD", read_only=False) as tb:
fix_nrow_to(1, tb)

tb.putcell("NAME", 0, columns["NAME"])
tb.putcell("CODE", 0, columns["CODE"])
tb.putcell("TIME", 0, columns["TIME"])
tb.putcell("NUM_POLY", 0, columns["NUM_POLY"])
tb.putcell("DELAY_DIR", 0, columns["DELAY_DIR"])
colkeywords = tb.getcolkeywords("DELAY_DIR")
colkeywords["MEASINFO"]["Ref"] = columns["FIELD_EPOCH"]
tb.putcolkeywords("DELAY_DIR", colkeywords)
tb.putcell("PHASE_DIR", 0, columns["PHASE_DIR"])
tb.putcolkeywords("PHASE_DIR", colkeywords)
tb.putcell("REFERENCE_DIR", 0, columns["REFERENCE_DIR"])
tb.putcolkeywords("REFERENCE_DIR", colkeywords)
tb.putcell("SOURCE_ID", 0, columns["SOURCE_ID"])
tb.putcell("FLAG_ROW", 0, columns["FLAG_ROW"])
yield row

column_keywords = {
"DELAY_DIR": {"MEASINFO": {"Ref": field_epoch}},
"PHASE_DIR": {"MEASINFO": {"Ref": field_epoch}},
"REFERENCE_DIR": {"MEASINFO": {"Ref": field_epoch}}
}

return column_keywords # noqa


def fill_field(msfile: str, hdu: BinTableHDU):
"""Fill MS FIELD table.
Args:
msfile: Name of MS file.
hdu: NRO45m psw data in the form of BinTableHDU object.
"""
fill_ms_table(msfile, hdu, "FIELD", _get_field_row)
63 changes: 34 additions & 29 deletions src/nro45data/psw/ms2/filler/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import logging
import pprint
from typing import Any, Callable, Optional, TYPE_CHECKING
from typing import Callable, TYPE_CHECKING

import numpy as np

Expand Down Expand Up @@ -281,8 +281,7 @@ def fill_ms_table(
msfile: str,
hdu: BinTableHDU,
table_name: str,
row_generator: Callable,
column_keywords: Optional[dict[str, dict[str, Any]]] = None
row_generator: Callable
):
"""Fill MS table.
Expand All @@ -291,36 +290,42 @@ def fill_ms_table(
hdu: NRO45m psw data in the form of BinTableHDU object.
table_name: Name of subtable or "MAIN" for MAIN table.
row_generator: Generator to yield table row.
column_keywords: Optional information to update column
keywords. Defaults to None.
Key is column name and value is a dictionary of
column keywords to be updated.
"""
if table_name.upper() == "MAIN":
table_path = msfile
else:
table_path = f"{msfile}/{table_name.upper()}"

with open_table(table_path, read_only=False) as tb:
# update table column keywords
if column_keywords is None:
column_keywords = {}

for colname, colkeywords_new in column_keywords.items():
colkeywords = tb.getcolkeywords(colname)
for key, value_new in colkeywords_new.items():
if key in colkeywords and isinstance(value_new, dict):
colkeywords[key].update(value_new)
else:
colkeywords[key] = value_new
tb.putcolkeywords(colname, colkeywords)

# fill table rows
for row_id, row in enumerate(row_generator(hdu)):
if tb.nrows() <= row_id:
tb.addrows(tb.nrows() - row_id + 1)

for key, value in row.items():
LOG.debug("row %d key %s", row_id, key)
tb.putcell(key, row_id, value)
LOG.debug("%s table %d row %s", table_name, row_id, row)
# iterator should provide row dictionary in order,
# and then, if necessary, column keywords dictionary
# should be returned additionally
iterator = enumerate(row_generator(hdu))
try:
# fill table rows
while True:
row_id, row = next(iterator)
if tb.nrows() <= row_id:
tb.addrows(tb.nrows() - row_id + 1)

for key, value in row.items():
LOG.debug("row %d key %s", row_id, key)
tb.putcell(key, row_id, value)
LOG.debug("%s table %d row %s", table_name, row_id, row)

except StopIteration as s:
# update column keywords if necessary
column_keywords = s.value
LOG.debug("return value: %s", s.value)
if isinstance(column_keywords, dict):
LOG.debug("column_keywords: %s", column_keywords)
for colname, colkeywords_new in column_keywords.items():
colkeywords = tb.getcolkeywords(colname)
for key, value_new in colkeywords_new.items():
if key in colkeywords and isinstance(value_new, dict):
LOG.debug("updating column keyword %s: %s, %s", colname, key, value_new)
colkeywords[key].update(value_new)
else:
LOG.debug("adding column keyword %s: %s, %s", colname, key, value_new)
colkeywords[key] = value_new
tb.putcolkeywords(colname, colkeywords)
25 changes: 25 additions & 0 deletions tests/ms2_filler/test_forest.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,31 @@ def test_forest_ms2_structure(msfile):
assert receptor_angle.shape == (2,)
assert np.all(receptor_angle == 0.0)

with open_table(os.path.join(msfile, "FIELD")) as tb:
assert tb.nrows() == 1
assert tb.getcell("NAME", 0) == "NML-Tau"
assert tb.getcell("CODE", 0) == ""
# start time: 2024/09/30 17:49:19
field_time = mjd2datetime(tb.getcell("TIME", 0))
time_expected = datetime.datetime(2024, 9, 30, 17, 49, 19, tzinfo=datetime.timezone.utc)
assert abs((field_time - time_expected).total_seconds()) < 1e-3
assert tb.getcell("NUM_POLY", 0) == 0
# RA = 03:53:28.860
# DEC = +11:24:22.40
# Epoch = J2000
ra_expected = 1.0187530477122202 # rad
dec_expected = 2.9861419948788317 # rad
for col in ["DELAY_DIR", "PHASE_DIR", "REFERENCE_DIR"]:
meas_info = tb.getcolkeyword(col, "MEASINFO")
assert "Ref" in meas_info
assert meas_info["Ref"] == "J2000"
direction = tb.getcell(col, 0)
assert direction.shape == (1, 2)
assert abs(direction[0, 0] - ra_expected) / ra_expected < 1e-6
assert abs(direction[0, 1] - dec_expected) / dec_expected < 1e-6
assert tb.getcell("SOURCE_ID", 0) == 0
assert tb.getcell("FLAG_ROW", 0) is False

with open_table(os.path.join(msfile, "STATE")) as tb:
intents_map = dict((i, v) for i, v in enumerate(tb.getcol("OBS_MODE")))

Expand Down
25 changes: 25 additions & 0 deletions tests/ms2_filler/test_h40.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,31 @@ def test_h40_ms2_structure(msfile):
assert receptor_angle.shape == (2,)
assert np.all(receptor_angle == 0.0)

with open_table(os.path.join(msfile, "FIELD")) as tb:
assert tb.nrows() == 1
assert tb.getcell("NAME", 0) == "NML-Tau"
assert tb.getcell("CODE", 0) == ""
# start time: 2024/09/25 15:58:54
field_time = mjd2datetime(tb.getcell("TIME", 0))
time_expected = datetime.datetime(2024, 9, 25, 15, 58, 54, tzinfo=datetime.timezone.utc)
assert abs((field_time - time_expected).total_seconds()) < 1e-3
assert tb.getcell("NUM_POLY", 0) == 0
# RA = 03:53:28.860
# DEC = +11:24:22.40
# Epoch = J2000
ra_expected = 1.0187530477122202 # rad
dec_expected = 2.9861419948788317 # rad
for col in ["DELAY_DIR", "PHASE_DIR", "REFERENCE_DIR"]:
meas_info = tb.getcolkeyword(col, "MEASINFO")
assert "Ref" in meas_info
assert meas_info["Ref"] == "J2000"
direction = tb.getcell(col, 0)
assert direction.shape == (1, 2)
assert abs(direction[0, 0] - ra_expected) / ra_expected < 1e-6
assert abs(direction[0, 1] - dec_expected) / dec_expected < 1e-6
assert tb.getcell("SOURCE_ID", 0) == 0
assert tb.getcell("FLAG_ROW", 0) is False

with open_table(os.path.join(msfile, "STATE")) as tb:
intents_map = dict((i, v) for i, v in enumerate(tb.getcol("OBS_MODE")))

Expand Down
25 changes: 25 additions & 0 deletions tests/ms2_filler/test_z45.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,31 @@ def test_z45_ms2_structure(msfile):
assert receptor_angle.shape == (2,)
assert np.all(receptor_angle == 0.0)

with open_table(os.path.join(msfile, "FIELD")) as tb:
assert tb.nrows() == 1
assert tb.getcell("NAME", 0) == "NML-Tau"
assert tb.getcell("CODE", 0) == ""
# start time: 2024/09/30 18:00:32
field_time = mjd2datetime(tb.getcell("TIME", 0))
time_expected = datetime.datetime(2024, 9, 30, 18, 0, 32, tzinfo=datetime.timezone.utc)
assert abs((field_time - time_expected).total_seconds()) < 1e-3
assert tb.getcell("NUM_POLY", 0) == 0
# RA = 03:53:28.860
# DEC = +11:24:22.40
# Epoch = J2000
ra_expected = 1.0187530477122202 # rad
dec_expected = 2.9861419948788317 # rad
for col in ["DELAY_DIR", "PHASE_DIR", "REFERENCE_DIR"]:
meas_info = tb.getcolkeyword(col, "MEASINFO")
assert "Ref" in meas_info
assert meas_info["Ref"] == "J2000"
direction = tb.getcell(col, 0)
assert direction.shape == (1, 2)
assert abs(direction[0, 0] - ra_expected) / ra_expected < 1e-6
assert abs(direction[0, 1] - dec_expected) / dec_expected < 1e-6
assert tb.getcell("SOURCE_ID", 0) == 0
assert tb.getcell("FLAG_ROW", 0) is False

with open_table(os.path.join(msfile, "STATE")) as tb:
intents_map = dict((i, v) for i, v in enumerate(tb.getcol("OBS_MODE")))

Expand Down

0 comments on commit 3a770b6

Please sign in to comment.