diff --git a/apps/cli/executables/pexable/ingest_envoy/ingest_envoy/classes.py b/apps/cli/executables/pexable/ingest_envoy/ingest_envoy/classes.py deleted file mode 100644 index a9ae7667010099ba79b602c4aa432ccea193861f..0000000000000000000000000000000000000000 --- a/apps/cli/executables/pexable/ingest_envoy/ingest_envoy/classes.py +++ /dev/null @@ -1,49 +0,0 @@ -""" Objects pertaining to the various ingestion manifests """ - -from enum import Enum - - -class Telescope(Enum): - """Codifying the names of our telescopes, because Janet can't abide magic strings""" - - VLA = 1 - EVLA = 2 - ALMA = 3 - VLBA = 4 - GBT = 5 - NONE = 6 - - -class IngestionType(Enum): - """Types of ingestion we'll have to do""" - - # ALMA products - ALMA_SDM = Telescope.ALMA - ALMA_CAL = Telescope.ALMA - ALMA_AUDI = Telescope.ALMA - - # EVLA products - EVLA_SDM = Telescope.EVLA - EVLA_BDF = Telescope.EVLA - EVLA_CAL = Telescope.EVLA - - # RealFast projects - REALFAST_SDM = Telescope.EVLA - - # VLASS projects - VLASS_QUICKLOOK = Telescope.EVLA - - # VLBA ingestion. (IDI and UVFITS products are treated the same.) - VLBA_FITS = Telescope.VLBA - - # Coming Real Soon Now: VLBA Mark 4 product ingestion - VLBA_MARK4 = Telescope.VLBA - - # Also coming Real Soon: GBT execution block ingestion - GBT_EB = Telescope.GBT - - # Hot on its heels: LVLA execution block ingestion - LVLA_EB = Telescope.VLA - - # When we just don't know what we're dealing with - UNKNOWN = Telescope.NONE diff --git a/apps/cli/executables/pexable/ingest_envoy/ingest_envoy/ingestion_manifest.py b/apps/cli/executables/pexable/ingest_envoy/ingest_envoy/ingestion_manifest.py new file mode 100644 index 0000000000000000000000000000000000000000..dc3865179363a0e5666f400cc5662737b5958f51 --- /dev/null +++ b/apps/cli/executables/pexable/ingest_envoy/ingest_envoy/ingestion_manifest.py @@ -0,0 +1,83 @@ +""" The ingestion manifest """ + +from pathlib import Path + +from .utilities import ( + Telescope, + ScienceProduct, +) + + +class Parameters: + """a manifest's various input parameters""" + + def __init__( + self, + telescope: Telescope, + ingestion_path: Path, + additional_metadata: str, + collection_metadata: str, + reingest: bool = False, + ngas_ingest: bool = False, + ): + self.telescope = telescope + self.ingestion_path = ingestion_path + self.additional_metadata = additional_metadata + self.collection_metadata = collection_metadata + self.reingest = reingest + self.ngas_ingest = ngas_ingest + + +class InputGroup: + """ + This represents the starting point for processing which generated a science product. + + There is not always an input group for every output group (rawdata, for instance). + + Initial assumption: Input groups consist only of science products. + """ + + def __init__(self): + self.science_products = [] + + +class IngestionManifest: + """Represents JSON layout of ingestion information, encompassing several potential scenarios. + see ingest_envoy/test/examples, nicked from https://open-confluence.nrao.edu/x/roPCAQ + """ + + def __init__(self, parameters: Parameters): + self.parameters = parameters + + # to be an InputGroup + self.input_group = None + # to be an OutputGroup + self.output_group = None + # to be an AssociateGroup (not required?) + self.associate_group = None + self.science_products = [] + self.ancillary_products = [] + + +class OutputGroup: + """Represents result of data processing""" + + def __init__(self): + self.science_products = [] + self.ancillary_products = [] + + +class AssociateGroup: + """ + A representation of Science Products which are not part of the same Input or Output groups + but are still fundamentally linked. Created for RealFast project, to link the RealFast + specific execution block & image to the execution block during which a transient was + discovered. + + Associate groups also, by definition, include any science product(s) within the output + group to be ingested. The new locators generated at ingestion time will be added to any + which compose an associate group in the manifest. + """ + + def __init__(self): + self.science_products = [] diff --git a/apps/cli/executables/pexable/ingest_envoy/ingest_envoy/ingestion_manifest_builder.py b/apps/cli/executables/pexable/ingest_envoy/ingest_envoy/ingestion_manifest_builder.py new file mode 100644 index 0000000000000000000000000000000000000000..fcce3d452d6bef884e831ac211ec43299551fa97 --- /dev/null +++ b/apps/cli/executables/pexable/ingest_envoy/ingest_envoy/ingestion_manifest_builder.py @@ -0,0 +1,22 @@ +"""Build an ingestion manifest file""" + +from .ingestion_manifest import ( + Parameters, + IngestionManifest, +) + + +class IngestionManifestBuilder: + """Uses supplied parameters to build ingestion manifest files + for the various types of ingestion""" + + def __init__(self, parameters: Parameters): + self.parameters = parameters + + def build(self) -> IngestionManifest: + """ + Create the ingestion manifest indicated by the parameters. + + :return: the ingestion manifest constructed from the parameters + """ + raise NotImplementedError diff --git a/apps/cli/executables/pexable/ingest_envoy/ingest_envoy/utilities.py b/apps/cli/executables/pexable/ingest_envoy/ingest_envoy/utilities.py new file mode 100644 index 0000000000000000000000000000000000000000..09366f128bed2c6ad85023d50e2aadc25894793c --- /dev/null +++ b/apps/cli/executables/pexable/ingest_envoy/ingest_envoy/utilities.py @@ -0,0 +1,105 @@ +""" Objects pertaining to the various ingestion manifests """ + +from enum import Enum + + +class Telescope(Enum): + """Codifying the names of our telescopes, because Janet can't abide magic strings""" + + VLA = 1 + EVLA = 2 + ALMA = 3 + VLBA = 4 + GBT = 5 + NONE = 6 + + +class IngestionType(Enum): + """Types of ingestion we'll have to do""" + + # ALMA products + ALMA_SDM = Telescope.ALMA + ALMA_CAL = Telescope.ALMA + ALMA_AUDI = Telescope.ALMA + + # EVLA products + EVLA_SDM = Telescope.EVLA + EVLA_BDF = Telescope.EVLA + EVLA_CAL = Telescope.EVLA + + # RealFast projects + REALFAST_SDM = Telescope.EVLA + + # VLASS projects + VLASS_QUICKLOOK = Telescope.EVLA + + # VLBA ingestion. (IDI and UVFITS products are treated the same.) + VLBA_FITS = Telescope.VLBA + + # Coming Real Soon Now: VLBA Mark 4 product ingestion + VLBA_MARK4 = Telescope.VLBA + + # Also coming Real Soon: GBT execution block ingestion + GBT_EB = Telescope.GBT + + # Hot on its heels: LVLA execution block ingestion + LVLA_EB = Telescope.VLA + + # When we just don't know what we're dealing with + UNKNOWN = Telescope.NONE + + +class ScienceProductType(Enum): + """Canonical collection of ingestible types of science products""" + + EXEC_BLOCK = "execution_block" + CAL = "calibration" + CATALOG = "catalog" + IMAGE = "image" + + +class ScienceProduct: + """Represents a science product in an ingestion manifest""" + + def __init__(self, sp_type: ScienceProductType, filename: str, locator: str, group_with: str): + self.sp_type = sp_type + self.filename = filename + # product locator, used for input groups; locator for a known science product + self.locator = locator + # for "late" science products; they get added to an existing output group + self.group_with = group_with + + +class AncillaryProductType: + """The various types of ancillary products we'll encounter""" + + INGESTION_ARTIFACTS = "ingestion_artifacts" + PIPELINE_ARTIFACTS = "pipeline_artifacts" + PIPELINE_WEBLOG = "pipeline_weblog" + LOG = "log_file" + + ### Images ### + + # our default FITS type + FITS = "fits_image" + + VLASS_QUICKLOOK = "quicklook_rms_image" + AUDI_FITS_MASK = "clean_mask" + AUDI_PB_FITS = "primary_beam" + ALPHA_FITS = "spectral_index" + CANDIDATE_IMG = "candidate_image" + THUMBNAIL_IMG = "thumbnail_image" + + +class AncillaryProduct: + """Represents an ancillary product in an ingestion manifest""" + + def __init__( + self, type: AncillaryProductType, filename: str, science_associate: str, group_with: str + ): + self.type = type + self.filename = filename + # make this an ancillary to a particular science product (assumes locator string) + self.science_associate = science_associate # TODO: enum? + # make this an ancillary to the group of a science product (assumes locator string) + self.group_with = group_with diff --git a/apps/cli/executables/pexable/ingest_envoy/test/examples/evla_calibration_manifest.json b/apps/cli/executables/pexable/ingest_envoy/test/examples/evla_calibration_manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..87a5dd84cd935b0d367a62fa33c8ebc70466460c --- /dev/null +++ b/apps/cli/executables/pexable/ingest_envoy/test/examples/evla_calibration_manifest.json @@ -0,0 +1,30 @@ +{ + "parameters": { + "reingest": "false", + "ngas-ingest": "false", + "calibrate": "false", + "ingestion_path": "/lustre/...../" + }, + "input-group": { + "science_products": [ + { + "type": "execution-block", + "locator": "......" + } + ] + }, + "output-group": { + "science_products": [ + { + "type": "calibration", + "filename": "19A-321_2019......tar" + } + ], + "ancillary_products": [ + { + "type": "weblog", + "filename": "weblog.tgz" + } + ] + } +} diff --git a/apps/cli/executables/pexable/ingest_envoy/test/examples/evla_eb_manifest.json b/apps/cli/executables/pexable/ingest_envoy/test/examples/evla_eb_manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..0a2ad890c042fabf420ee9e14fcb142f76000c33 --- /dev/null +++ b/apps/cli/executables/pexable/ingest_envoy/test/examples/evla_eb_manifest.json @@ -0,0 +1,22 @@ +{ + "parameters": { + "reingest": false, + "ngas_ingest": false, + "telescope": "EVLA", + "ingestion_path": "/home/mchammer/evla/parallel-prod" + }, + "output_group": { + "science_products": [ + { + "type": "execution_block", + "filename": "X_osro_000.59368.65423814815" + } + ], + "ancillary_products": [ + { + "type": "ingestion_artifacts", + "filename": "ingestion_artifacts_2021_06_03_T15_52_35.031.tar" + } + ] + } +} diff --git a/apps/cli/executables/pexable/ingest_envoy/test/examples/image_set_manifest.json b/apps/cli/executables/pexable/ingest_envoy/test/examples/image_set_manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..8d27af401d24ac614dd618a8b48996fe2d39972d --- /dev/null +++ b/apps/cli/executables/pexable/ingest_envoy/test/examples/image_set_manifest.json @@ -0,0 +1,60 @@ +{ + "parameters": { + "reingest": "false", + "ngas-ingest": "false", + "calibrate": "false", + "ingestion_path": "/lustre/.." + }, + "input-group": { + "science_products": [ + { + "type": "calibration", + "locator": "...." + } + ] + }, + "output-group": { + "science_products": [ + { + "type": "image", + "filename": "image1.fits", + "ancillary-products": [ + { + "type": "image_mask", + "filename": "image1.mask.fits" + } + ] + }, + { + "type": "image", + "filename": "image2.fits", + "ancillary-products": [ + { + "type": "image_mask", + "filename": "image2.mask.fits" + } + ] + }, + { + "type": "image", + "filename": "image3.fits", + "ancillary-products": [ + { + "type": "image_mask", + "filename": "image3.mask.fits" + } + ] + } + ], + "ancillary-products": [ + { + "type": "weblog", + "filename": "weblog.tgz" + }, + { + "type": "tar", + "filename": "imaging_extras.tar" + } + ] + } +} diff --git a/apps/cli/executables/pexable/ingest_envoy/test/examples/quicklook_manifest.json b/apps/cli/executables/pexable/ingest_envoy/test/examples/quicklook_manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..72a30aec21e9b04a7f3008e7969e8dd78ab554be --- /dev/null +++ b/apps/cli/executables/pexable/ingest_envoy/test/examples/quicklook_manifest.json @@ -0,0 +1,40 @@ +{ + "parameters": { + "reingest": "false", + "ngas-ingest": "false", + "calibrate": "false", + "ingestion_path": "/lustre/aoc/cluster/pipeline/vlass_auto/cache/quicklook/VLASS1.1/T29t04/VLASS1.1.ql.T29t04.J094850+743000.10.2048.v5" + }, + "input-group": { + "science_products": [ + { + "type": "calibration", + "locator": "uid://evla/calibration/a47c2e78-4f4e-4516-ab95-8bbb4057e9bb" + }, + { + "type": "execution_block", + "locator": "uid://evla/execblock/52dd9e10-63fb-4fa8-b6ff-fcf6240b97f4" + } + ] + }, + "output-group": { + "science_products": [ + { + "type": "quicklook_image", + "filename": "VLASS1.1.ql.T29t04.J094850+743000.10.2048.v5.I.iter1.image.pbcor.tt0.subim.fits", + "ancillary-products": [ + { + "type": "quicklook_rms", + "filename": "VLASS1.1.ql.T29t04.J094850+743000.10.2048.v5.I.iter1.image.pbcor.tt0.rms.subim.fits" + } + ] + } + ], + "ancillary-products": [ + { + "type": "tar", + "filename": "VLASS1.1.ql.T29t04.J094850+743000.10.2048.v5.tar" + } + ] + } +} diff --git a/apps/cli/executables/pexable/ingest_envoy/test/examples/vlass_catalog_manifest.json b/apps/cli/executables/pexable/ingest_envoy/test/examples/vlass_catalog_manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..5306a3d5dfa029e145e453d55a0cbed3a49c0835 --- /dev/null +++ b/apps/cli/executables/pexable/ingest_envoy/test/examples/vlass_catalog_manifest.json @@ -0,0 +1,15 @@ +{ + "parameters": { + "reingest": "false", + "ngas-ingest": "false", + "calibrate": "false", + "ingestion_path": "/lustre/...../" + }, + "science-products": [ + { + "type": "vlass_catalog", + "filename": "imaging_catalog_example.cat", + "group_with": ".... (locator for an image)" + } + ] +} diff --git a/apps/cli/executables/pexable/ingest_envoy/test/test_evla_ing_manifests.py b/apps/cli/executables/pexable/ingest_envoy/test/test_evla_ing_manifests.py index 5d6bff8d57655411d7b46dff34cc5915833ce7ed..319074aba62cd286928ae4332e73e7cbc250d8b7 100644 --- a/apps/cli/executables/pexable/ingest_envoy/test/test_evla_ing_manifests.py +++ b/apps/cli/executables/pexable/ingest_envoy/test/test_evla_ing_manifests.py @@ -1,7 +1,12 @@ """ Test for the various types of EVLA ingestion manifests """ +from pathlib import Path import pytest +from ..ingest_envoy.ingestion_manifest import Parameters +from ..ingest_envoy.ingestion_manifest_builder import IngestionManifestBuilder +from apps.cli.executables.pexable.ingest_envoy.ingest_envoy.utilities import Telescope + @pytest.mark.skip("TODO: test_builds_evla_sdm_manifest") def test_builds_evla_sdm_manifest(): @@ -10,7 +15,13 @@ def test_builds_evla_sdm_manifest(): :return: """ - raise NotImplementedError + parameters = Parameters(Telescope.EVLA, Path("/path/TODO"), None, None) + manifest = IngestionManifestBuilder(parameters).build() + assert manifest.input_group is not None + assert manifest.output_group is not None + assert len(manifest.science_products) > 0 + assert len(manifest.ancillary_products) > 0 + # TODO: tests for manifest parameters @pytest.mark.skip("TODO: test_builds_evla_bdf_manifest")