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

Allow to reprocess configuration #184

Merged
merged 8 commits into from
May 5, 2022
129 changes: 119 additions & 10 deletions python/jaeger/fvc.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
from jaeger.ieb import IEB
from jaeger.kaiju import get_path_pair_in_executor, get_robot_grid
from jaeger.plotting import plot_fvc_distances
from jaeger.target.tools import wok_to_positioner
from jaeger.target import Configuration, Design
from jaeger.target.tools import read_confSummary, wok_to_positioner
from jaeger.utils import run_in_executor


Expand Down Expand Up @@ -266,6 +267,8 @@ def process_fvc_image(

if plot is True:
plot_path_root = proc_path_root
elif plot is False or plot is None:
plot_path_root = None
elif isinstance(plot, str):
plot_path_root = os.path.join(plot, "proc-" + base[0 : base.find(".fit")])
else:
Expand Down Expand Up @@ -817,7 +820,12 @@ async def apply_correction(
self.correction_applied = True
self.log("Correction applied.")

async def write_summary_F(self):
async def write_summary_F(
self,
path: str | pathlib.Path | None = None,
plot: bool = True,
extra_headers: dict = {},
):
"""Updates data with the last measured positions and write confSummaryF."""

if self.fps is None or self.fps.configuration is None:
Expand Down Expand Up @@ -863,20 +871,24 @@ async def write_summary_F(self):
update=True,
)

headers = {
"fvc_centroid_method": self.centroid_method or "?",
"fvc_rms": self.fitrms,
"fvc_90_perc": self.perc_90,
"fvc_percent_reached": self.fvc_percent_reached,
"fvc_image_path": self.proc_image_path if self.proc_image_path else "",
}
headers.update(extra_headers)

await configuration_copy.write_summary(
path=path,
flavour="F",
headers={
"fvc_centroid_method": self.centroid_method or "?",
"fvc_rms": self.fitrms,
"fvc_90_perc": self.perc_90,
"fvc_percent_reached": self.fvc_percent_reached,
"fvc_image_path": self.proc_image_path if self.proc_image_path else "",
},
headers=headers,
overwrite=True,
)

# Plot analysis of FVC loop.
if self.proc_image_path:
if plot and self.proc_image_path:
self.log("Creating FVC plots", level=logging.DEBUG)

outpath = str(self.proc_image_path).replace(".fits", "_distances.pdf")
Expand All @@ -886,3 +898,100 @@ async def write_summary_F(self):
configuration_copy.assignment_data.fibre_table,
path=outpath,
)


async def reprocess_configuration(
configuration_id: int,
path: pathlib.Path | str | None = None,
centroid_method: str | None = None,
use_suffix: bool = True,
):
"""Reprocesses the FVC image from a configuration with a different centroid method.

Outputs a new ``confSummaryF`` file.

Parameters
----------
configuration_id
The configuration ID for which to reprocess data. Must have an existing
``confSummaryF`` file in ``$SDSSCORE_DIR``.
path
The path where to write the new ``confSummaryF`` file. If `None`, defaults
to ``$SDSSCORE_DIR``.
centroid_method
The centroid method to use, one of ``"nudge"``, ``"sep"``, ``"winpos"``,
or ``"simple"``.
use_suffix
If `True`, the new ``confSummaryF`` path file will have a suffix
including the centroid mode used.

Returns
-------
path
The path to the new ``confSummaryF`` file.

"""

site = config["observatory"]
confSummaryF_path = Configuration._get_summary_file_path(
configuration_id,
site,
"F",
)

if not os.path.exists(confSummaryF_path):
raise FileNotFoundError(
f"Cannot find a confSummaryF file for {configuration_id}."
)

header, _ = read_confSummary(confSummaryF_path)

design = Design(
header["design_id"],
epoch=header["epoch"],
scale=header["focal_scale"],
)

fps = FPS.get_instance()
assert not fps.can, "This function cannot be called on a running FPS instance."

fps.configuration = design.configuration
fps.configuration.configuration_id = configuration_id

fvc = FVC(site)

proc_fimg = header["fvc_image_path"]
fimg = proc_fimg.replace("proc-", "")

posangles = fits.getdata(proc_fimg, "POSANGLES")
fiber_data = pandas.DataFrame(fits.getdata(proc_fimg, "FIBERDATA"))

positioner_coords = {}
for row in posangles:
positioner_coords[row["positionerID"]] = (row["alphaReport"], row["betaReport"])

fvc.process_fvc_image(
fimg,
positioner_coords,
fibre_data=fiber_data,
centroid_method=centroid_method,
plot=False,
)

if path is None:
path = confSummaryF_path

path = str(path)

if use_suffix:
path = path.replace(".par", f"_{fvc.centroid_method}.par")

await fvc.write_summary_F(
path=path,
plot=False,
extra_headers={
"MJD": header["MJD"],
"obstime": header["obstime"],
"temperature": header["temperature"],
},
)
15 changes: 9 additions & 6 deletions python/jaeger/target/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import logging
import os
import pathlib
import warnings
from copy import deepcopy
from time import time
Expand Down Expand Up @@ -703,6 +704,7 @@ def _get_summary_file_path(configuration_id: int, observatory: str, flavour: str
async def write_summary(
self,
flavour: str = "",
path: str | pathlib.Path | None = None,
overwrite: bool = False,
headers: dict = {},
fibre_table: pandas.DataFrame | None = None,
Expand Down Expand Up @@ -866,11 +868,12 @@ async def write_summary(
fibermap = Table(fibermap)
fibermap.sort(["positionerId", "fiberType"])

path = self._get_summary_file_path(
self.configuration_id,
self.assignment_data.observatory,
flavour,
)
if path is None:
path = self._get_summary_file_path(
self.configuration_id,
self.assignment_data.observatory,
flavour,
)

if os.path.exists(path):
if overwrite:
Expand All @@ -882,7 +885,7 @@ async def write_summary(
os.makedirs(os.path.dirname(path), exist_ok=True)

write_ndarray_to_yanny(
path,
str(path),
[fibermap],
structnames=["FIBERMAP"],
hdr=header,
Expand Down
2 changes: 1 addition & 1 deletion python/jaeger/target/design.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def __init__(

self.configuration: Configuration
if load_configuration:
self.configuration = Configuration(self, epoch=epoch)
self.configuration = Configuration(self, epoch=epoch, scale=scale)

def get_target_data(self) -> dict[str, dict]:
"""Retrieves target data as a dictionary."""
Expand Down
34 changes: 33 additions & 1 deletion python/jaeger/target/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
from typing import TYPE_CHECKING

import numpy
import pandas
from pydl.pydlutils.sdss import yanny

from coordio.conv import (
positionerToTangent,
Expand All @@ -38,7 +40,12 @@
from jaeger import FPS


__all__ = ["wok_to_positioner", "positioner_to_wok", "copy_summary_file"]
__all__ = [
"wok_to_positioner",
"positioner_to_wok",
"copy_summary_file",
"read_confSummary",
]


def wok_to_positioner(
Expand Down Expand Up @@ -357,3 +364,28 @@ def copy_summary_file(

with open(new_path, "w") as f:
f.write(summary_data)


def read_confSummary(path: str | pathlib.Path) -> tuple:

y = yanny(str(path))
header = dict(y)

fibermap = header.pop("FIBERMAP")
fibermap = fibermap[[col for col in fibermap.dtype.names if col != "mag"]]

df = pandas.DataFrame(fibermap)

for col in df.select_dtypes("object").columns:
df[col] = df[col].str.decode("utf-8")

for key, value in header.items():
try:
header[key] = int(value)
except ValueError:
try:
header[key] = float(value)
except ValueError:
pass

return header, df.set_index(["positionerId", "fiberType"])