Source code for sorcha.readers.OrbitAuxReader

import logging
import sys
import numpy as np

from sorcha.readers.CSVReader import CSVDataReader


[docs] class OrbitAuxReader(CSVDataReader): """A class to read in the auxiliary orbit data files.""" def __init__(self, filename, sep="csv", header=-1, **kwargs): """A class for reading the object data from a CSV file. Parameters ----------- filename : string location/name of the data file. sep : string, optional format of input file ("whitespace"/"csv"). Default = "csv" header : int The row number of the header. If not provided, does an automatic search. Default = -1 **kwargs : dictionary, optional Extra arguments """ super().__init__(filename, sep, header, **kwargs)
[docs] def get_reader_info(self): """Return a string identifying the current reader name and input information (for logging and output). Returns -------- : string The reader information. """ return f"OrbitAuxReader:{self.filename}"
[docs] def _process_and_validate_input_table(self, input_table, **kwargs): """Perform any input-specific processing and validation on the input table. Modifies the input dataframe in place. Parameters ----------- input_table : pandas dataframe A loaded table. **kwargs : dictionary, optional Returns ----------- res_df : pandas dataframe Returns the input dataframe modified in-place. Notes ------ The base implementation includes filtering that is common to most input types. Subclasses should call super.process_and_validate() to ensure that the ancestor’s validation is also applied. """ # Do standard CSV file processing super()._process_and_validate_input_table(input_table, **kwargs) if len(input_table) == 0: return input_table pplogger = logging.getLogger(__name__) if "FORMAT" not in input_table.columns: pplogger.error("ERROR: PPReadOrbitFile: Orbit format must be provided.") sys.exit("ERROR: PPReadOrbitFile: Orbit format must be provided.") if len(input_table.columns) != 9: pplogger.error("ERROR: Please only provide the required columns in your orbits file.") sys.exit("ERROR: Please only provide the required columns in your orbits file.") orb_format = input_table["FORMAT"].iloc[0] if len(input_table["FORMAT"].unique()) != 1: pplogger.error("ERROR: Orbit file must have a consistent FORMAT (COM, KEP, or CART).") sys.exit("ERROR: Orbit file must have a consistent FORMAT (COM, KEP, or CART).") keplerian_elements = ["ObjID", "a", "e", "inc", "node", "argPeri", "ma", "epochMJD_TDB"] cometary_elements = ["ObjID", "q", "e", "inc", "node", "argPeri", "t_p_MJD_TDB", "epochMJD_TDB"] cartesian_elements = ["ObjID", "x", "y", "z", "xdot", "ydot", "zdot", "epochMJD_TDB"] if orb_format in ["KEP", "BKEP"]: if not all(column in input_table.columns for column in keplerian_elements): pplogger.error("ERROR: PPReadOrbitFile: Must provide all keplerian orbital elements.") sys.exit("ERROR: PPReadOrbitFile: Must provide all keplerian orbital elements.") filtered_df = input_table.loc[(input_table["inc"] < 0) | (input_table["inc"] > 180), ["ObjID"]] if not filtered_df.empty: pplogger.warning( f"WARNING: For Object(s) {', '.join(filtered_df['ObjID'].astype(str))}. Inclination (inc) is outside the valid range (0 180 degrees), which may cause the orbits to be mirrored affecting orbital calculations." ) filtered_df = input_table.loc[ ~( ( (input_table["argPeri"] >= 0) & (input_table["argPeri"] <= 360) & (input_table["node"] >= 0) & (input_table["node"] <= 360) & (input_table["ma"] >= 0) & (input_table["ma"] <= 360) ) | ( (input_table["argPeri"] >= -180) & (input_table["argPeri"] <= 180) & (input_table["node"] >= -180) & (input_table["node"] <= 180) & (input_table["ma"] >= -180) & (input_table["ma"] <= 180) ) ), ["ObjID"], ] if not filtered_df.empty: pplogger.warning( f"WARNING: For Object(s) {', '.join(filtered_df['ObjID'].astype(str))}. The argument of Perihelion (argPeri), the Longitude of the Ascending Node (node), and the Mean Anomaly (ma) are not in the same bounds (either [0 360] or [-180 180] degrees), which may lead to incorrect orbital calculations." ) error_raised = False # checks all objects before a system exit filtered_df = input_table.loc[(input_table["e"] >= 1), ["ObjID"]] if not filtered_df.empty: error_raised = True pplogger.error( f"ERROR: For Object(s) {', '.join(filtered_df['ObjID'].astype(str))}. Parabolic orbit (e == 1) and Hyperbolic orbit (e > 1) are not supported for Keplerian elements." ) filtered_df = input_table.loc[(input_table["e"] < 0), ["ObjID"]] if not filtered_df.empty: error_raised = True pplogger.error( f"ERROR: For Object(s) {', '.join(filtered_df['ObjID'].astype(str))}. Eccentricity (e) cannot be less than 0." ) filtered_df = input_table.loc[(input_table["e"] < 1) & (input_table["a"] < 0), ["ObjID"]] if not filtered_df.empty: error_raised = True pplogger.error( f"ERROR: For Object(s) {', '.join(filtered_df['ObjID'].astype(str))}. Bound orbit (e < 1) with negative semi-major axis (a < 0) is not physical." ) if error_raised: pplogger.error("ERROR: Invalid Keplerian elements detected for one or more objects.") sys.exit( "ERROR: Invalid Keplerian elements detected for one or more objects (check log for information)" ) elif orb_format in ["COM", "BCOM"]: if not all(column in input_table.columns for column in cometary_elements): pplogger.error("ERROR: PPReadOrbitFile: Must provide all cometary orbital elements.") sys.exit("ERROR: PPReadOrbitFile: Must provide all cometary orbital elements.") if np.any(input_table["t_p_MJD_TDB"] > 2400000.5): pplogger.warning( "WARNING: At least one t_p_MJD_TDB is above 2400000.5 - make sure your t_p are MJD and not in JD" ) error_raised = False filtered_df = input_table.loc[(input_table["q"] == 0), ["ObjID"]] if not filtered_df.empty: pplogger.warning( f"WARNING: For Object(s) {', '.join(filtered_df['ObjID'].astype(str))}. q==0 is technically correct but suggests a collisional path with an object instead of an orbital path." ) filtered_df = input_table.loc[(input_table["inc"] < 0) | (input_table["inc"] > 180), ["ObjID"]] if not filtered_df.empty: pplogger.warning( f"WARNING: For Object(s) {', '.join(filtered_df['ObjID'].astype(str))}. Inclination (inc) is outside the valid range (0 180 degrees), which may cause the orbits to be mirrored affecting orbital calculations." ) filtered_df = input_table.loc[(input_table["q"] < 0), ["ObjID"]] if not filtered_df.empty: error_raised = True pplogger.error( f"ERROR: For Object(s) {', '.join(filtered_df['ObjID'].astype(str))}. Perihelion distance (q) cannot be less than 0." ) filtered_df = input_table.loc[(input_table["e"] < 0), ["ObjID"]] if not filtered_df.empty: error_raised = True pplogger.error( f"ERROR: For Object(s) {', '.join(filtered_df['ObjID'].astype(str))}. Eccentricity (e) cannot be less than 0." ) if error_raised: pplogger.error("ERROR: Invalid cometary elements detected for one or more objects") sys.exit( "ERROR: Invalid cometary elements detected for one or more objects (check log for information)" ) elif orb_format in ["CART", "BCART"]: if not all(column in input_table.columns for column in cartesian_elements): pplogger.error("ERROR: PPReadOrbitFile: Must provide all cartesian coordinate values.") sys.exit("ERROR: PPReadOrbitFile: Must provide all cartesian coordinate values.") else: pplogger.error( "ERROR: PPReadOrbitFile: Orbit format must be one of cometary (COM), keplerian (KEP), cartesian (CART)," "barycentric cometary (BCOM), barycentric keplerian (BKEP), or barycentric cartesian (BCART)." ) sys.exit( "ERROR: PPReadOrbitFile: Orbit format must be one of cometary (COM), keplerian (KEP), cartesian (CART)," "barycentric cometary (BCOM), barycentric keplerian (BKEP), or barycentric cartesian (BCART)." ) return input_table