diff --git a/setup.cfg b/setup.cfg index 7a3f26ccb2021fa2ebe1b3720d29c4e0261b59b2..be6d021087a09e00af932a53c682c65d3440e1a0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -36,6 +36,9 @@ console_scripts = dbcredentials = pycommon.entrypoints.dbcredentials:main oracle = pycommon.entrypoints.oracle:main +[options.package_data] +* = *.conf, *.parset + [flake8] max-line-length = 88 extend-ignore = E203 diff --git a/tests/data/__init__.py b/tests/data/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/data/test_files.py b/tests/data/test_files.py new file mode 100644 index 0000000000000000000000000000000000000000..c9e41e360577ad19734b4ac7808cdfe2a84b5177 --- /dev/null +++ b/tests/data/test_files.py @@ -0,0 +1,78 @@ +# Copyright (C) 2024 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: GPL-3.0-or-later + +import logging +import os +import unittest +from importlib import resources +from unittest import mock + +from tmss_pycommon.data import files + +logger = logging.getLogger(__name__) + + +class TestFiles(unittest.TestCase): + + def setUp(self): + + self.p_path = mock.patch.object(files, "Path", autospec=True) + self.m_path = self.p_path.start() + self.addCleanup(self.p_path.stop) + + def test_lofarroot_env_set(self): + """Test if we correctly determine if LOFARROOT is set""" + + self.assertFalse(files._lofarroot_env_set()) + + os.environ["LOFARROOT"] = "test" + self.addCleanup(os.environ.pop, "LOFARROOT") + + self.assertTrue(files._lofarroot_env_set()) + + def test_path_contains_lofarroot(self): + """Test if we can determine if paths contain LOFARROOT reference""" + + m_path_lofar = "${LOFARROOT}/test/test" + self.assertTrue(files._path_contains_lofarroot(m_path_lofar)) + + m_path_lofar2 = "/etc/$LOFARROOT/test" + self.assertTrue(files._path_contains_lofarroot(m_path_lofar2)) + + m_path = "/etc/test/station.parset" + self.assertFalse(files._path_contains_lofarroot(m_path)) + + def test_path_lofarroot(self): + """Test path expansion when LOFARROOT is set""" + + self.m_path.return_value.is_file.return_value = True + + # Test case 2, $LOFARROOT unset but file exists with bare path + self.assertEqual( + "/chicken.coup", files.lofar_expand_file_path("$LOFARROOT/chicken.coup") + ) + + os.environ["LOFARROOT"] = "/media/lofar" + self.addCleanup(os.environ.pop, "LOFARROOT") + + # Test case 1, LOFARROOT set and path exists + self.assertEqual( + "/media/lofar/chicken.coup", files.lofar_expand_file_path("$LOFARROOT/chicken.coup") + ) + + # Test case 3, LOFARROOT set but files don't exist, load from package data + self.m_path.return_value.is_file.side_effect = [ + False, False, True + ] + self.assertEqual( + resources.files("tmss_pycommon.data").joinpath("StationPositions.parset"), + files.lofar_expand_file_path("$LOFARROOT/StationPositions.parset") + ) + + # Test case 4, nothing exists, empty path is returned + self.m_path.return_value.is_file.side_effect = [ + False, False, False, False + ] + self.assertEqual( + "", files.lofar_expand_file_path("$LOFARROOT/StationPositions.parset") + ) diff --git a/tests/test_antennasets_parser.py b/tests/test_antennasets_parser.py index c93914ed2b01f55ab3d91ddbd29ba5cfca3398e9..8d3801b4e7331f960702e4806fb39879b4d02ff7 100755 --- a/tests/test_antennasets_parser.py +++ b/tests/test_antennasets_parser.py @@ -10,9 +10,7 @@ from tmss_pycommon.test.utils import unit_test class TestAntennaSetsParser(unittest.TestCase): def setUp(self): - self.working_dir = os.environ.get('srcdir', os.path.dirname(os.path.abspath(__file__))) - self.test_filepath = os.path.join(self.working_dir, "datasets", - "t_antennasets_parser.antennaset_conf_test_sample") + self.test_filepath = "t_antennasets_parser.antennaset_conf_test_sample" @unit_test def test_default_config_path(self): @@ -21,12 +19,11 @@ class TestAntennaSetsParser(unittest.TestCase): self.assertRaises(Exception, AntennaSetsParser, None) @unit_test - def test_bad_config_file_five_columns(self): - """ Verify that an exception is raised by the AntennaSetsParser constructor when parsing a configuration file - with a number of columns not equaling four. """ - test_filepath = os.path.join(self.working_dir, "datasets", - "t_antennasets_parser.bad_antennaset_conf_test_sample_five_columns") - self.assertRaises(Exception, AntennaSetsParser, test_filepath) + def test_file_not_found(self): + test_filepath = os.path.join( + "datasets", "t_antennasets_parser.bad_antennaset_conf_test_sample_five_columns" + ) + self.assertRaises(FileNotFoundError, AntennaSetsParser, test_filepath) @unit_test def test_antennaset_names(self): diff --git a/tests/test_station_coordinates.py b/tests/test_station_coordinates.py new file mode 100644 index 0000000000000000000000000000000000000000..18be0a24eafe41432e0f9ca62eb59c32b833886e --- /dev/null +++ b/tests/test_station_coordinates.py @@ -0,0 +1,19 @@ +# Copyright (C) 2024 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: GPL-3.0-or-later + +import logging +import unittest +from tmss_pycommon.station_coordinates import parse_station_coordinates + +logger = logging.getLogger(__name__) + + +class TestStationCoordinates(unittest.TestCase): + + def test_parse_station_coordinates(self): + """Package must be able to load StationPositions without $LOFARROOT""" + + data = parse_station_coordinates() + + self.assertIn("DE605HBA", data) + self.assertIn("epoch", data["DE605HBA"]) diff --git a/tmss_pycommon/antennasets_parser.py b/tmss_pycommon/antennasets_parser.py index c8f63fedf417d1fac8c34b069f40f2e66dcf462f..5c8dd1ae240708d2c515c7476b10204728e8ca0c 100755 --- a/tmss_pycommon/antennasets_parser.py +++ b/tmss_pycommon/antennasets_parser.py @@ -4,17 +4,21 @@ import re import os -DEFAULT_ANTENNASETS_CONF_FILEPATH = os.path.expandvars("$LOFARROOT/etc/AntennaSets.conf") +from tmss_pycommon.data.files import lofar_expand_file_path + +DEFAULT_ANTENNASETS_CONF_FILEPATH = "$LOFARROOT/etc/AntennaSets.conf" class AntennaSetsParser(object): """ Parses an antenna sets configuration file and makes it available in various forms """ def __init__(self, conf_filepath=DEFAULT_ANTENNASETS_CONF_FILEPATH): - if not self.__file_exists(conf_filepath): - raise Exception("Configuration file doesn't exist") - self.antenna_sets = self.__parse_from_file(conf_filepath) + file = lofar_expand_file_path(conf_filepath) + if not self.__file_exists(file): + raise FileNotFoundError("Configuration file doesn't exist") + + self.antenna_sets = self.__parse_from_file(file) def __file_exists(self, filepath): return os.path.isfile(filepath) diff --git a/tmss_pycommon/data/AntennaSets.conf b/tmss_pycommon/data/AntennaSets.conf new file mode 100644 index 0000000000000000000000000000000000000000..20223ce37dc1a75f42abae3f4ffbf99edea31536 --- /dev/null +++ b/tmss_pycommon/data/AntennaSets.conf @@ -0,0 +1,107 @@ +# +# AntennaSet.conf +# +# This file defines subsets of the (physical) antennafields that can be used +# in observations as 'the' antennafield. +# +# Since there are 3 different station layout each subset must be defined for +# each stationtype (Core, Remote and Europe). +# +# A Subset is defined for specifying for each stationtypes for each RCU which +# input is used. +# +# Allowed values for the RCU input selection are: +# H : HBA input +# h : LBH input +# l : LBL input +# . : RCU not included +# +# To diminish the typing-work to syntax of an rcu definition is: +# input-selector ::= H | h | l | . +# rcu_definition ::= number input-selector [ number inputselector ...] +# +# E.g. when on a station on all RCUs the HBA input must be used this can be defined as +# 192H in stead of 192 'H' after each other. +# +# Or when all even RCUs should use LBL and all even RCUs shoud use LBH: +# 96hl +# +# The total number of assigned RCUs MUST match the total number for each station: +# +# RCU counts LBA HBA +# Europe 192 192 +# Remote 96 96 +# Core 96 96 +# +# Use inner half of the LBAs on Core and Remote +LBA_INNER LBA Europe 192h +LBA_INNER LBA Remote 46hh2.. +LBA_INNER LBA Core 46hh2.. +# +# Use outer half of the LBAs on Core and Remote +LBA_OUTER LBA Europe 192h +LBA_OUTER LBA Remote 96l +LBA_OUTER LBA Core 96l +# +# Use half of inner and outer LBAs on Core and Remote [TBC] +LBA_SPARSE_EVEN LBA Europe 192h +LBA_SPARSE_EVEN LBA Remote 23hhll1..ll +LBA_SPARSE_EVEN LBA Core 23hhll1..ll +# +# Use half of inner and outer LBAs on Core and Remote [TBC] +LBA_SPARSE_ODD LBA Europe 192h +LBA_SPARSE_ODD LBA Remote 23llhh1ll.. +LBA_SPARSE_ODD LBA Core 23llhh1ll.. +# +# Use X dipole of all LBAs +LBA_X LBA Europe 96h. +LBA_X LBA Remote 46hl2.l +LBA_X LBA Core 46hl2.l +# +# Use Y dipole of all LBAs +LBA_Y LBA Europe 96.h +LBA_Y LBA Remote 46lh2l. +LBA_Y LBA Core 46lh2l. + +# Note: On Core stations the Serdes splitter is always on for HBA + +# Use 'ear' 0 in Core stations (antennas 0-23) +HBA_ZERO HBA Europe 192H +HBA_ZERO HBA Remote 96H +HBA_ZERO HBA0 Core 48H48. +# +# Use 'ear' 1 in Core stations (antennas 24-47) +HBA_ONE HBA Europe 192H +HBA_ONE HBA Remote 96H +HBA_ONE HBA1 Core 48.48H +# +# Use both 'ears' in the Core (microstationmode for EOR) +HBA_DUAL HBA Europe 192H +HBA_DUAL HBA Remote 96H +HBA_DUAL HBA Core 96H +# +# Use both 'ears' in the Core added together (pulsar mode) +HBA_JOINED HBA Europe 192H +HBA_JOINED HBA Remote 96H +HBA_JOINED HBA Core 96H +# +# Use both 'ears' in the Core and 24 tiles in remote (microstationmode for EOR) +HBA_ZERO_INNER HBA Europe 192H +HBA_ZERO_INNER HBA Remote 10.4H6.8H6.12H4.12H6.8H6.4H10. +HBA_ZERO_INNER HBA0 Core 48H48. +# +# Use both 'ears' in the Core and 24 tiles in remote (microstationmode for EOR) +HBA_ONE_INNER HBA Europe 192H +HBA_ONE_INNER HBA Remote 10.4H6.8H6.12H4.12H6.8H6.4H10. +HBA_ONE_INNER HBA1 Core 48.48H +# +# Use both 'ears' in the Core and 24 tiles in remote (microstationmode for EOR) +HBA_DUAL_INNER HBA Europe 192H +HBA_DUAL_INNER HBA Remote 10.4H6.8H6.12H4.12H6.8H6.4H10. +HBA_DUAL_INNER HBA Core 96H +# +# Use both 'ears' in the Core and 24 tiles in remote (microstationmode for EOR) +HBA_JOINED_INNER HBA Europe 192H +HBA_JOINED_INNER HBA Remote 10.4H6.8H6.12H4.12H6.8H6.4H10. +HBA_JOINED_INNER HBA Core 96H + diff --git a/tmss_pycommon/data/StationPositions.parset b/tmss_pycommon/data/StationPositions.parset new file mode 100644 index 0000000000000000000000000000000000000000..7535793435631b7c6208f5053f01818073869292 --- /dev/null +++ b/tmss_pycommon/data/StationPositions.parset @@ -0,0 +1,213 @@ +# $Id$ +# Phase centers +# +# EPOCH: 2015.5 +# + +# Note: Reference phase center coordinates are EPOCH 2012.5 +Observation.referencePhaseCenter = [3826577.066, 461022.948, 5064892.786] + +PIC.Core.CS001LBA.phaseCenter = [3826923.503, 460915.488, 5064643.517] +PIC.Core.CS001HBA.phaseCenter = [3826937.767, 460938.573, 5064630.724] +PIC.Core.CS001HBA0.phaseCenter = [3826896.192, 460979.502, 5064658.231] +PIC.Core.CS001HBA1.phaseCenter = [3826979.341, 460897.644, 5064603.217] + +PIC.Core.CS002LBA.phaseCenter = [3826577.023, 461022.995, 5064892.814] +PIC.Core.CS002HBA.phaseCenter = [3826583.235, 460955.803, 5064894.225] +PIC.Core.CS002HBA0.phaseCenter = [3826600.918, 460953.449, 5064881.164] +PIC.Core.CS002HBA1.phaseCenter = [3826565.551, 460958.157, 5064907.286] + +PIC.Core.CS003LBA.phaseCenter = [3826516.705, 460930.113, 5064946.485] +PIC.Core.CS003HBA.phaseCenter = [3826494.537, 461017.745, 5064955.204] +PIC.Core.CS003HBA0.phaseCenter = [3826471.305, 461000.185, 5064974.229] +PIC.Core.CS003HBA1.phaseCenter = [3826517.769, 461035.305, 5064936.178] + +PIC.Core.CS004LBA.phaseCenter = [3826654.154, 460939.623, 5064842.454] +PIC.Core.CS004HBA.phaseCenter = [3826582.513, 460891.709, 5064900.560] +PIC.Core.CS004HBA0.phaseCenter = [3826585.583, 460865.891, 5064900.589] +PIC.Core.CS004HBA1.phaseCenter = [3826579.443, 460917.527, 5064900.530] + +PIC.Core.CS005LBA.phaseCenter = [3826668.707, 461069.597, 5064819.782] +PIC.Core.CS005HBA.phaseCenter = [3826666.134, 461005.580, 5064827.500] +PIC.Core.CS005HBA0.phaseCenter = [3826701.117, 460989.297, 5064802.713] +PIC.Core.CS005HBA1.phaseCenter = [3826631.151, 461021.862, 5064852.287] + +PIC.Core.CS006LBA.phaseCenter = [3826596.687, 461145.225, 5064867.006] +PIC.Core.CS006HBA.phaseCenter = [3826633.098, 461108.416, 5064843.003] +PIC.Core.CS006HBA0.phaseCenter = [3826653.740, 461136.487, 5064824.971] +PIC.Core.CS006HBA1.phaseCenter = [3826612.456, 461080.345, 5064861.034] + +PIC.Core.CS007LBA.phaseCenter = [3826533.318, 461099.013, 5064918.749] +PIC.Core.CS007HBA.phaseCenter = [3826508.325, 461126.773, 5064935.000] +PIC.Core.CS007HBA0.phaseCenter = [3826478.672, 461083.767, 5064961.145] +PIC.Core.CS007HBA1.phaseCenter = [3826537.978, 461169.778, 5064908.855] + +PIC.Core.CS011LBA.phaseCenter = [3826667.026, 461285.896, 5064801.620] +PIC.Core.CS011HBA.phaseCenter = [3826643.148, 461290.840, 5064819.097] +PIC.Core.CS011HBA0.phaseCenter = [3826637.378, 461227.392, 5064829.162] +PIC.Core.CS011HBA1.phaseCenter = [3826648.918, 461354.288, 5064809.031] + +PIC.Core.CS013LBA.phaseCenter = [3826346.222, 460792.158, 5065087.164] +PIC.Core.CS013HBA.phaseCenter = [3826360.486, 460815.243, 5065074.371] +PIC.Core.CS013HBA0.phaseCenter = [3826318.911, 460856.172, 5065101.878] +PIC.Core.CS013HBA1.phaseCenter = [3826402.060, 460774.314, 5065046.864] + +PIC.Core.CS017LBA.phaseCenter = [3826462.011, 461501.997, 5064935.855] +PIC.Core.CS017HBA.phaseCenter = [3826452.396, 461530.026, 5064940.539] +PIC.Core.CS017HBA0.phaseCenter = [3826405.052, 461507.507, 5064978.111] +PIC.Core.CS017HBA1.phaseCenter = [3826499.740, 461552.545, 5064902.966] + +PIC.Core.CS021LBA.phaseCenter = [3826406.500, 460538.651, 5065064.898] +PIC.Core.CS021HBA.phaseCenter = [3826416.115, 460510.623, 5065060.215] +PIC.Core.CS021HBA0.phaseCenter = [3826463.459, 460533.141, 5065022.642] +PIC.Core.CS021HBA1.phaseCenter = [3826368.770, 460488.104, 5065097.787] + +PIC.Core.CS024LBA.phaseCenter = [3827161.191, 461409.455, 5064421.074] +PIC.Core.CS024HBA.phaseCenter = [3827170.806, 461381.426, 5064416.390] +PIC.Core.CS024HBA0.phaseCenter = [3827218.150, 461403.945, 5064378.818] +PIC.Core.CS024HBA1.phaseCenter = [3827123.461, 461358.908, 5064453.963] + +PIC.Core.CS026LBA.phaseCenter = [3826390.873, 461869.899, 5064955.941] +PIC.Core.CS026HBA.phaseCenter = [3826376.610, 461846.814, 5064968.734] +PIC.Core.CS026HBA0.phaseCenter = [3826418.184, 461805.884, 5064941.227] +PIC.Core.CS026HBA1.phaseCenter = [3826335.035, 461887.743, 5064996.241] + +PIC.Core.CS028LBA.phaseCenter = [3825600.402, 461260.640, 5065604.353] +PIC.Core.CS028HBA.phaseCenter = [3825614.666, 461283.725, 5065591.560] +PIC.Core.CS028HBA0.phaseCenter = [3825573.091, 461324.654, 5065619.067] +PIC.Core.CS028HBA1.phaseCenter = [3825656.240, 461242.796, 5065564.053] + +PIC.Core.CS030LBA.phaseCenter = [3826014.223, 460387.436, 5065372.356] +PIC.Core.CS030HBA.phaseCenter = [3825999.960, 460364.350, 5065385.149] +PIC.Core.CS030HBA0.phaseCenter = [3826041.534, 460323.421, 5065357.642] +PIC.Core.CS030HBA1.phaseCenter = [3825958.385, 460405.280, 5065412.656] + +PIC.Core.CS031LBA.phaseCenter = [3826439.953, 460273.880, 5065063.622] +PIC.Core.CS031HBA.phaseCenter = [3826430.338, 460301.909, 5065068.306] +PIC.Core.CS031HBA0.phaseCenter = [3826382.994, 460279.390, 5065105.878] +PIC.Core.CS031HBA1.phaseCenter = [3826477.682, 460324.428, 5065030.733] + +PIC.Core.CS032LBA.phaseCenter = [3826891.530, 460387.957, 5064715.320] +PIC.Core.CS032HBA.phaseCenter = [3826905.794, 460411.042, 5064702.527] +PIC.Core.CS032HBA0.phaseCenter = [3826864.219, 460451.971, 5064730.034] +PIC.Core.CS032HBA1.phaseCenter = [3826947.368, 460370.113, 5064675.020] + +PIC.Core.CS101LBA.phaseCenter = [3825842.923, 461704.496, 5065381.501] +PIC.Core.CS101HBA.phaseCenter = [3825852.538, 461676.468, 5065376.818] +PIC.Core.CS101HBA0.phaseCenter = [3825899.882, 461698.986, 5065339.245] +PIC.Core.CS101HBA1.phaseCenter = [3825805.193, 461653.949, 5065414.390] + +PIC.Core.CS103LBA.phaseCenter = [3826304.236, 462823.136, 5064934.362] +PIC.Core.CS103HBA.phaseCenter = [3826289.973, 462800.050, 5064947.155] +PIC.Core.CS103HBA0.phaseCenter = [3826331.547, 462759.121, 5064919.648] +PIC.Core.CS103HBA1.phaseCenter = [3826248.398, 462840.980, 5064974.662] + +PIC.Core.CS201LBA.phaseCenter = [3826708.886, 461913.794, 5064713.866] +PIC.Core.CS201HBA.phaseCenter = [3826685.008, 461918.738, 5064731.343] +PIC.Core.CS201HBA0.phaseCenter = [3826679.238, 461855.290, 5064741.408] +PIC.Core.CS201HBA1.phaseCenter = [3826690.778, 461982.186, 5064721.277] + +PIC.Core.CS301LBA.phaseCenter = [3827412.822, 460992.390, 5064269.972] +PIC.Core.CS301HBA.phaseCenter = [3827436.700, 460987.447, 5064252.496] +PIC.Core.CS301HBA0.phaseCenter = [3827442.469, 461050.894, 5064242.431] +PIC.Core.CS301HBA1.phaseCenter = [3827430.930, 460923.999, 5064262.561] + +PIC.Core.CS302LBA.phaseCenter = [3827945.873, 459792.686, 5063990.045] +PIC.Core.CS302HBA.phaseCenter = [3827931.609, 459769.601, 5064002.836] +PIC.Core.CS302HBA0.phaseCenter = [3827973.183, 459728.671, 5063975.329] +PIC.Core.CS302HBA1.phaseCenter = [3827890.034, 459810.530, 5064030.342] + +PIC.Core.CS401LBA.phaseCenter = [3826766.063, 460100.435, 5064836.498] +PIC.Core.CS401HBA.phaseCenter = [3826789.939, 460095.491, 5064819.024] +PIC.Core.CS401HBA0.phaseCenter = [3826795.709, 460158.941, 5064808.957] +PIC.Core.CS401HBA1.phaseCenter = [3826784.168, 460032.040, 5064829.090] + +PIC.Core.CS501LBA.phaseCenter = [3825625.736, 460642.157, 5065640.800] +PIC.Core.CS501HBA.phaseCenter = [3825616.121, 460670.186, 5065645.484] +PIC.Core.CS501HBA0.phaseCenter = [3825568.777, 460647.667, 5065683.056] +PIC.Core.CS501HBA1.phaseCenter = [3825663.465, 460692.705, 5065607.911] + +PIC.Core.DE601LBA.phaseCenter = [4034038.204, 487026.614, 4900280.359] +PIC.Core.DE601HBA.phaseCenter = [4034101.470, 487012.792, 4900230.512] + +PIC.Core.DE602LBA.phaseCenter = [4152560.612, 828869.127, 4754357.186] +PIC.Core.DE602HBA.phaseCenter = [4152567.960, 828789.204, 4754362.234] + +PIC.Core.DE603LBA.phaseCenter = [3940284.862, 816802.383, 4932393.051] +PIC.Core.DE603HBA.phaseCenter = [3940295.660, 816722.914, 4932394.446] + +PIC.Core.DE604LBA.phaseCenter = [3796327.130, 877591.683, 5032757.536] +PIC.Core.DE604HBA.phaseCenter = [3796379.775, 877614.177, 5032712.556] + +# Note: DE605 coordinates are EPOCH 2017.5 +PIC.Core.DE605LBA.phaseCenter = [4005681.285, 450968.703, 4926457.990] +PIC.Core.DE605HBA.phaseCenter = [4005717.990, 451028.465, 4926424.423] + +PIC.Core.DE609LBA.phaseCenter = [3727207.316, 655185.261, 5117000.905] +PIC.Core.DE609HBA.phaseCenter = [3727217.666, 655109.182, 5117003.127] + +PIC.Core.FR606LBA.phaseCenter = [4323979.772, 165608.826, 4670303.127] +PIC.Core.FR606HBA.phaseCenter = [4324016.671, 165545.578, 4670271.396] + +PIC.Core.IE613LBA.phaseCenter = [3801633.528, -529021.899, 5076997.185] +PIC.Core.IE613HBA.phaseCenter = [3801691.943, -528983.966, 5076957.924] + +PIC.Core.PL610LBA.phaseCenter = [3738425.932, 1148187.176, 5021750.597] +PIC.Core.PL610HBA.phaseCenter = [3738462.416, 1148244.316, 5021710.658] + +PIC.Core.PL611LBA.phaseCenter = [3850973.987, 1439061.041, 4860478.994] +PIC.Core.PL611HBA.phaseCenter = [3850980.881, 1438994.879, 4860498.993] + +PIC.Core.PL612LBA.phaseCenter = [3551478.643, 1334128.493, 5110179.160] +PIC.Core.PL612HBA.phaseCenter = [3551481.817, 1334203.573, 5110157.410] + +PIC.Core.RS106LBA.phaseCenter = [3829261.381, 469162.332, 5062137.339] +PIC.Core.RS106HBA.phaseCenter = [3829205.554, 469142.580, 5062181.031] + +PIC.Core.RS205LBA.phaseCenter = [3831438.520, 463435.488, 5061025.495] +PIC.Core.RS205HBA.phaseCenter = [3831479.627, 463487.577, 5060989.932] + +PIC.Core.RS208LBA.phaseCenter = [3847810.007, 466929.754, 5048357.251] +PIC.Core.RS208HBA.phaseCenter = [3847753.266, 466962.857, 5048397.273] + +PIC.Core.RS210LBA.phaseCenter = [3877847.404, 467456.975, 5025437.636] +PIC.Core.RS210HBA.phaseCenter = [3877827.519, 467536.653, 5025445.613] + +PIC.Core.RS305LBA.phaseCenter = [3828720.715, 454781.458, 5063851.111] +PIC.Core.RS305HBA.phaseCenter = [3828732.668, 454692.451, 5063850.344] + +PIC.Core.RS306LBA.phaseCenter = [3829791.765, 452829.895, 5063221.619] +PIC.Core.RS306HBA.phaseCenter = [3829771.206, 452761.749, 5063243.210] + +PIC.Core.RS307LBA.phaseCenter = [3837940.905, 449560.803, 5057381.316] +PIC.Core.RS307HBA.phaseCenter = [3837964.476, 449627.308, 5057357.613] + +PIC.Core.RS310LBA.phaseCenter = [3845433.009, 413580.936, 5054756.199] +PIC.Core.RS310HBA.phaseCenter = [3845376.247, 413616.612, 5054796.370] + +PIC.Core.RS406LBA.phaseCenter = [3818467.590, 451974.648, 5071790.625] +PIC.Core.RS406HBA.phaseCenter = [3818424.895, 452020.316, 5071817.672] + +PIC.Core.RS407LBA.phaseCenter = [3811595.818, 453444.729, 5076770.457] +PIC.Core.RS407HBA.phaseCenter = [3811649.412, 453459.942, 5076728.980] + +PIC.Core.RS409LBA.phaseCenter = [3824755.810, 426178.894, 5069289.897] +PIC.Core.RS409HBA.phaseCenter = [3824812.578, 426130.377, 5069251.783] + +PIC.Core.RS503LBA.phaseCenter = [3824090.409, 459438.330, 5066898.218] +PIC.Core.RS503HBA.phaseCenter = [3824138.523, 459477.020, 5066858.606] + +PIC.Core.RS508LBA.phaseCenter = [3797202.072, 463087.556, 5086605.065] +PIC.Core.RS508HBA.phaseCenter = [3797136.440, 463114.494, 5086651.314] + +PIC.Core.RS509LBA.phaseCenter = [3783579.088, 450178.929, 5097830.864] +PIC.Core.RS509HBA.phaseCenter = [3783537.482, 450130.111, 5097866.175] + +PIC.Core.SE607LBA.phaseCenter = [3370286.883, 712053.913, 5349991.484] +PIC.Core.SE607HBA.phaseCenter = [3370271.609, 712125.923, 5349991.190] + +PIC.Core.UK608LBA.phaseCenter = [4008438.421, -100309.676, 4943735.858] +PIC.Core.UK608HBA.phaseCenter = [4008461.905, -100376.560, 4943716.904] + +PIC.Core.LV614LBA.phaseCenter = [3183318.032, 1276777.655, 5359435.077] +PIC.Core.LV614HBA.phaseCenter = [3183249.286, 1276801.742, 5359469.949] \ No newline at end of file diff --git a/tmss_pycommon/data/__init__.py b/tmss_pycommon/data/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tmss_pycommon/data/files.py b/tmss_pycommon/data/files.py new file mode 100644 index 0000000000000000000000000000000000000000..2bec1c7f57e651262b3a76204d190fc74d99439e --- /dev/null +++ b/tmss_pycommon/data/files.py @@ -0,0 +1,59 @@ +# Copyright (C) 2024 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: GPL-3.0-or-later + +import os +import re +from importlib.abc import Traversable +from importlib.resources import files +from os import PathLike +from pathlib import Path + +_LOFARROOT_REGEX_EXPRESSION = "\$[{]?LOFARROOT[}]?" +_LOFARROOT_REGEX_PATTERN = re.compile(_LOFARROOT_REGEX_EXPRESSION) + + +def lofar_expand_file_path(path: str) -> str | bytes | PathLike | Traversable: + """Attempt to fully expand file path to a file found on storage + + 1. Try $LOFARROOT first if set and present in path + 2. Try path without $LOFARROOT if unset or not present + 3. Try load full path from package_data + 4. Try load basename (file) from package_data + 5. Give up return empty string + """ + + result = os.path.expandvars(path) + if _path_contains_lofarroot(path) and _lofarroot_env_set() and Path(result).is_file(): + return result + + result = _LOFARROOT_REGEX_PATTERN.sub('', path) + if _path_contains_lofarroot(path) and Path(result).is_file(): + return result + + result = files("tmss_pycommon.data").joinpath(_LOFARROOT_REGEX_PATTERN.sub('', path).strip("/")) + if Path(result).is_file(): + return result + + result = files("tmss_pycommon.data").joinpath(os.path.basename(_LOFARROOT_REGEX_PATTERN.sub('', path).strip("/"))) + if Path(result).is_file(): + return result + + return "" + + +def _path_contains_lofarroot(path: str) -> bool: + """Test if path contains reference to LOFARROOT env var""" + + if _LOFARROOT_REGEX_PATTERN.search(path) is not None: + return True + else: + return False + + +def _lofarroot_env_set() -> bool: + """Test if $LOFARROOT is set""" + + if os.getenv("LOFARROOT") is not None: + return True + else: + return False diff --git a/tests/datasets/t_antennasets_parser.antennaset_conf_test_sample b/tmss_pycommon/data/t_antennasets_parser.antennaset_conf_test_sample similarity index 100% rename from tests/datasets/t_antennasets_parser.antennaset_conf_test_sample rename to tmss_pycommon/data/t_antennasets_parser.antennaset_conf_test_sample diff --git a/tmss_pycommon/station_coordinates.py b/tmss_pycommon/station_coordinates.py index 0ea0b6d2dbb840df9e27b51306153dc4fca0aa7d..ed53369abf51fd4b0dabbacd199d94af49513485 100644 --- a/tmss_pycommon/station_coordinates.py +++ b/tmss_pycommon/station_coordinates.py @@ -2,10 +2,11 @@ # SPDX-License-Identifier: GPL-3.0-or-later from ast import literal_eval -import os import functools -DEFAULT_STATION_POSITIONS_PARSET_FILEPATH = os.path.expandvars("$LOFARROOT/etc/StaticMetaData/StationPositions.parset") +from tmss_pycommon.data.files import lofar_expand_file_path + +DEFAULT_STATION_POSITIONS_PARSET_FILEPATH = "$LOFARROOT/etc/StaticMetaData/StationPositions.parset" @functools.lru_cache() def parse_station_coordinates() -> dict: @@ -14,7 +15,7 @@ def parse_station_coordinates() -> dict: """ station_coordinates = {} expected_comment_found = False - with open(os.path.expandvars(DEFAULT_STATION_POSITIONS_PARSET_FILEPATH), 'r') as f: + with open(lofar_expand_file_path(DEFAULT_STATION_POSITIONS_PARSET_FILEPATH), 'r') as f: for line in f.readlines(): if "Note: DE605 coordinates are EPOCH 2017.5" in line: expected_comment_found = True