diff --git a/examples/BADAData.py b/examples/BADAData.py index e38c8d2..149272f 100644 --- a/examples/BADAData.py +++ b/examples/BADAData.py @@ -5,16 +5,15 @@ Example of BADA parametes retrieval for specific aircraft """ -from pyBADA.bada3 import Bada3Aircraft from pyBADA.bada3 import Parser as Bada3Parser +from pyBADA.aircraft import Bada -badaVersion = "DUMMY" # loading all the BADA data into a dataframe -allData = Bada3Parser.parseAll(badaVersion=badaVersion) +allData = Bada3Parser.parseAll(badaVersion="DUMMY") # retrieve specific data from the whole database, including synonyms -params = Bada3Parser.getBADAParameters( +params = Bada.getBADAParameters( df=allData, acName=["B737", "A1", "P38", "AT45", "DA42"], parameters=["VMO", "MMO", "MTOW", "engineType"], @@ -22,7 +21,7 @@ print(params) print("\n") -params = Bada3Parser.getBADAParameters( +params = Bada.getBADAParameters( df=allData, acName=["B737"], parameters=["VMO", "MMO", "MTOW", "engineType"], @@ -30,14 +29,12 @@ print(params) print("\n") -params = Bada3Parser.getBADAParameters( +params = Bada.getBADAParameters( df=allData, acName="DA42", parameters=["VMO", "MMO", "MTOW", "engineType"] ) print(params) print("\n") -params = Bada3Parser.getBADAParameters( - df=allData, acName="DA42", parameters="VMO" -) +params = Bada.getBADAParameters(df=allData, acName="DA42", parameters="VMO") print(params) print("\n") diff --git a/examples/file_parser.py b/examples/file_parser.py index c1b4979..5e28a13 100644 --- a/examples/file_parser.py +++ b/examples/file_parser.py @@ -8,23 +8,30 @@ from pyBADA.bada3 import Bada3Aircraft from pyBADA.bada4 import Bada4Aircraft from pyBADA.badaH import BadaHAircraft -from pyBADA.bada3 import Parser as Bada3Parser -from pyBADA.bada4 import Parser as Bada4Parser -from pyBADA.badaH import Parser as BadaHParser +# initialization of BADAH +AC = BadaHAircraft(badaVersion="DUMMY", acName="DUMH") -# initialization of BADA3, BADA4 and BADAH -# uncomment for testing different BADA family if available # BADAH -badaVersion = "DUMMY" -AC = BadaHAircraft(badaVersion=badaVersion, acName="DUMH") - -# BADA4 -# AC = Bada4Aircraft(badaVersion=badaVersion, acName='Dummy-TBP') - -# BADA3 -# AC = Bada3Aircraft(badaVersion=badaVersion, acName='BZJT') +if AC.BADAFamily.BADAH: + ICAO = AC.ICAO + WTC = AC.WTC + MTOW = AC.MTOW + print( + "BADA Family:", + AC.BADAFamilyName, + "| BADA Version:", + AC.BADAVersion, + "| ICAO:", + ICAO, + "| WTC:", + WTC, + "| MTOW =", + MTOW, + ) +# initialization of BADA4 +AC = Bada4Aircraft(badaVersion="DUMMY", acName="Dummy-TBP") # BADA3 or BADA4 if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4: @@ -50,10 +57,15 @@ MTOW, ) -# BADAH -if AC.BADAFamily.BADAH: +# initialization of BADA3 +AC = Bada3Aircraft(badaVersion="DUMMY", acName="BZJT") + +# BADA3 or BADA4 +if AC.BADAFamily.BADA3 or AC.BADAFamily.BADA4: ICAO = AC.ICAO WTC = AC.WTC + VMO = AC.VMO + MMO = AC.MMO MTOW = AC.MTOW print( "BADA Family:", @@ -62,8 +74,12 @@ AC.BADAVersion, "| ICAO:", ICAO, - " |WTC:", + "| WTC:", WTC, + "| VMO =", + VMO, + "| MMO =", + MMO, "| MTOW =", MTOW, ) diff --git a/src/pyBADA/aircraft.py b/src/pyBADA/aircraft.py index d58ae87..13c2d35 100644 --- a/src/pyBADA/aircraft.py +++ b/src/pyBADA/aircraft.py @@ -21,30 +21,55 @@ def checkArgument(argument, **kwargs): raise TypeError("Missing " + argument + " argument") -class BadaFamily(object): - """This class sets the token for the respected BADA Family.""" +class Bada(object): + """This class implements the mechanisms applicable across all BADA families.""" - def __init__(self, BADA3=False, BADA4=False, BADAH=False, BADAE=False): - self.BADA3 = BADA3 - self.BADA4 = BADA4 - self.BADAH = BADAH - self.BADAE = BADAE + def __init__(self): + pass + @staticmethod + def getBADAParameters(df, acName, parameters): + """ + Retrieves specified parameters for a given aircraft name from a DataFrame. + + :param df: DataFrame containing BADA aircraft data. + :param acName: Name of the aircraft or list of aircraft names to search for. + :param parameters: List of column names (or a single column name) to retrieve. + :type df: pd.DataFrame + :type acName: list or str + :type parameters: list or str + :returns: A DataFrame containing the specified parameters for the given aircraft. + :rtype: pd.DataFrame + :raises ValueError: If any of the specified columns or aircraft names are not found. + """ -class Airplane(object): - """This is a generic airplane class based on a three-degrees-of-freedom point mass model (where all the forces - are applied at the center of gravity). + # Ensure parameters is a list + if isinstance(parameters, str): + parameters = [parameters] - .. note::this generic class only implements basic aircraft dynamics - calculations, aircraft performance and optimisation can be obtained - from its inherited classes + # Ensure acName is a list + if isinstance(acName, str): + acName = [acName] - """ + # Ensure all requested parameters exist in the DataFrame + missing_cols = [col for col in parameters if col not in df.columns] + if missing_cols: + raise ValueError( + f"The following parameters are not in the DataFrame columns: {missing_cols}" + ) - __metaclass__ = abc.ABCMeta + # Filter rows where 'acName' matches any of the specified aircraft names + filtered_df = df[df["acName"].isin(acName)] - def __init__(self): - pass + # Check if any rows were found + if filtered_df.empty: + raise ValueError(f"No entries found for aircraft(s): {acName}.") + else: + # Select the required columns + result_df = filtered_df[["acName"] + parameters].reset_index( + drop=True + ) + return result_df @staticmethod def loadFactor(fi): @@ -81,6 +106,21 @@ def bankAngle(rateOfTurn, v): BA = atan((ROT * v) / const.g) return conv.rad2deg(BA) + @staticmethod + def rateOfTurn(v, nz=1.0): + """ + Computes the rate of turn based on true airspeed (TAS) and load factor. + + :param v: True airspeed (TAS) in meters per second (m/s). + :param nz: Load factor (default is 1.0), dimensionless. + :type v: float + :type nz: float + :returns: Rate of turn in degrees per second (deg/s). + :rtype: float + """ + + return degrees((const.g / v) * sqrt(nz * nz - 1)) + @staticmethod def rateOfTurn_bankAngle(TAS, bankAngle): """ @@ -98,21 +138,6 @@ def rateOfTurn_bankAngle(TAS, bankAngle): return degrees(ROT) - @staticmethod - def rateOfTurn(v, nz=1.0): - """ - Computes the rate of turn based on true airspeed (TAS) and load factor. - - :param v: True airspeed (TAS) in meters per second (m/s). - :param nz: Load factor (default is 1.0), dimensionless. - :type v: float - :type nz: float - :returns: Rate of turn in degrees per second (deg/s). - :rtype: float - """ - - return degrees((const.g / v) * sqrt(nz * nz - 1)) - @staticmethod def turnRadius(v, nz=1.0): """ @@ -160,6 +185,30 @@ def GS(tas, gamma, Ws): return tas * cos(radians(gamma)) + Ws + +class BadaFamily(object): + """This class sets the token for the respected BADA Family.""" + + def __init__(self, BADA3=False, BADA4=False, BADAH=False, BADAE=False): + self.BADA3 = BADA3 + self.BADA4 = BADA4 + self.BADAH = BADAH + self.BADAE = BADAE + + +class Airplane(object): + """This is a generic airplane class based on a three-degrees-of-freedom point mass model (where all the forces + are applied at the center of gravity). + + .. note::this generic class only implements basic aircraft dynamics + calculations, aircraft performance and optimisation can be obtained + from its inherited classes + + """ + + def __init__(self): + pass + @staticmethod def esf(**kwargs): """ @@ -278,90 +327,9 @@ class Helicopter(object): """ - __metaclass__ = abc.ABCMeta - def __init__(self): pass - @staticmethod - def loadFactor(fi): - """ - Computes the load factor from a given bank angle. - - The load factor is calculated based on the cosine of the bank angle, - which is expressed in degrees. A small rounding operation is applied - to avoid precision issues with small decimal places. - - :param fi: Bank angle in degrees. - :type fi: float - :returns: The load factor (dimensionless). - :rtype: float - """ - - return 1 / round(cos(radians(fi)), 10) - - @staticmethod - def rateOfTurn(v, nz=1.0): - """ - Computes the rate of turn based on true airspeed (TAS) and load factor. - - :param v: True airspeed (TAS) in meters per second (m/s). - :param nz: Load factor (default is 1.0), dimensionless. - :type v: float - :type nz: float - :returns: Rate of turn in degrees per second (deg/s). - :rtype: float - """ - - return degrees((const.g / v) * sqrt(nz * nz - 1)) - - @staticmethod - def rateOfTurn_bankAngle(TAS, bankAngle): - """ - Computes the rate of turn based on true airspeed (TAS) and bank angle. - - :param TAS: True airspeed (TAS) in meters per second (m/s). - :param bankAngle: Bank angle in degrees. - :type TAS: float - :type bankAngle: float - :returns: Rate of turn in degrees per second (deg/s). - :rtype: float - """ - - ROT = tan(radians(bankAngle)) * const.g / TAS - - return degrees(ROT) - - @staticmethod - def turnRadius(v, nz=1.0): - """ - Computes the turn radius based on true airspeed (TAS) and load factor. - - :param v: True airspeed (TAS) in meters per second (m/s). - :param nz: Load factor (default is 1.0), dimensionless. - :type v: float - :type nz: float - :returns: Turn radius in meters. - :rtype: float - """ - - return (v * v / const.g) * (1 / sqrt(nz * nz - 1)) - - @staticmethod - def turnRadius_bankAngle(v, ba): - """ - Computes the turn radius based on true airspeed (TAS) and bank angle. - - :param v: True airspeed (TAS) in meters per second (m/s). - :param ba: Bank angle in degrees. - :type v: float - :type ba: float - :returns: Turn radius in meters. - :rtype: float - """ - - return (v * v / const.g) * (1 / tan(conv.deg2rad(ba))) - @staticmethod def esf(**kwargs): """ @@ -429,21 +397,3 @@ def esf(**kwargs): ESF = float("Nan") return ESF - - @staticmethod - def bankAngle(rateOfTurn, v): - """ - Computes the bank angle based on true airspeed (TAS) and rate of turn. - - :param v: True airspeed (TAS) in meters per second (m/s). - :param rateOfTurn: Rate of turn in degrees per second (deg/s). - :type v: float - :type rateOfTurn: float - :returns: Bank angle in degrees. - :rtype: float - """ - - ROT = conv.deg2rad(rateOfTurn) - - BA = atan((ROT * v) / const.g) - return conv.rad2deg(BA) diff --git a/src/pyBADA/bada3.py b/src/pyBADA/bada3.py index 325c392..b9260a7 100644 --- a/src/pyBADA/bada3.py +++ b/src/pyBADA/bada3.py @@ -18,7 +18,7 @@ from pyBADA import conversions as conv from pyBADA import atmosphere as atm from pyBADA import configuration as configuration -from pyBADA.aircraft import Airplane, BadaFamily +from pyBADA.aircraft import Airplane, BadaFamily, Bada def proper_round(num, dec=0): @@ -41,32 +41,6 @@ class Parser(object): def __init__(self): pass - @staticmethod - def list_subfolders(folderPath): - """ - Lists all subfolders within a specified directory. - - :param folderPath: Path to the directory where subfolders are to be listed. - :type folderPath: str - :returns: A list of subfolder names within the specified directory. - :rtype: list of str - - This function retrieves all entries in the given directory and filters out - the ones that are not directories. Only the names of the subfolders are returned. - """ - - # List all entries in the directory - entries = os.listdir(folderPath) - - # Filter out entries that are directories - subfolders = [ - entry - for entry in entries - if os.path.isdir(os.path.join(folderPath, entry)) - ] - - return subfolders - @staticmethod def parseXML(filePath, badaVersion, acName): """ @@ -1542,7 +1516,7 @@ def parseAll(badaVersion, filePath=None): # try to get subfolders, if they exist # get names of all the folders in the main BADA model folder to search for XML files folderPath = os.path.join(filePath, "BADA3", badaVersion) - subfolders = Parser.list_subfolders(folderPath) + subfolders = configuration.list_subfolders(folderPath) if not subfolders: # use APF and OPF files @@ -1602,72 +1576,8 @@ def parseAll(badaVersion, filePath=None): return merged_df - @staticmethod - def getBADAParameters(df, acName, parameters): - """ - Retrieves specified parameters for a given aircraft name from a DataFrame. - - :param df: DataFrame containing BADA aircraft data. - :param acName: Name of the aircraft or list of aircraft names to search for. - :param parameters: List of column names (or a single column name) to retrieve. - :type df: pd.DataFrame - :type acName: list or str - :type parameters: list or str - :returns: A DataFrame containing the specified parameters for the given aircraft. - :rtype: pd.DataFrame - :raises ValueError: If any of the specified columns or aircraft names are not found. - """ - - # Ensure parameters is a list - if isinstance(parameters, str): - parameters = [parameters] - - # Ensure acName is a list - if isinstance(acName, str): - acName = [acName] - - # Ensure all requested parameters exist in the DataFrame - missing_cols = [col for col in parameters if col not in df.columns] - if missing_cols: - raise ValueError( - f"The following parameters are not in the DataFrame columns: {missing_cols}" - ) - - # Filter rows where 'acName' matches any of the specified aircraft names - filtered_df = df[df["acName"].isin(acName)] - # Check if any rows were found - if filtered_df.empty: - raise ValueError(f"No entries found for aircraft(s): {acName}.") - else: - # Select the required columns - result_df = filtered_df[["acName"] + parameters].reset_index( - drop=True - ) - return result_df - - @staticmethod - def safe_get(df, column_name, default_value=None): - """ - Safely retrieves a column's value from a DataFrame, returning a default value if the column does not exist. - - :param df: DataFrame to retrieve the value from. - :param column_name: Name of the column to retrieve. - :param default_value: Value to return if the column does not exist. Default is None. - :type df: pd.DataFrame - :type column_name: str - :type default_value: any - :returns: The value from the specified column or the default value if the column is missing. - :rtype: any - """ - - if column_name in df.columns: - return df[column_name].iloc[0] - else: - return default_value - - -class BADA3(Airplane): +class BADA3(Airplane, Bada): """This class implements the part of BADA3 performance model that will be used in other classes following the BADA3 manual. :param AC: Aircraft object {BADA3}. @@ -4835,69 +4745,83 @@ def __init__(self, badaVersion, acName, filePath=None, allData=None): if allData is not None and acName in allData["acName"].values: filtered_df = allData[allData["acName"] == acName] - self.acName = Parser.safe_get(filtered_df, "acName", None) - self.xmlFiles = Parser.safe_get(filtered_df, "xmlFiles", None) + self.acName = configuration.safe_get(filtered_df, "acName", None) + self.xmlFiles = configuration.safe_get( + filtered_df, "xmlFiles", None + ) - self.modificationDateOPF = Parser.safe_get( + self.modificationDateOPF = configuration.safe_get( filtered_df, "modificationDateOPF", None ) - self.modificationDateAPF = Parser.safe_get( + self.modificationDateAPF = configuration.safe_get( filtered_df, "modificationDateAPF", None ) - self.ICAO = Parser.safe_get(filtered_df, "ICAO", None) - self.numberOfEngines = Parser.safe_get( + self.ICAO = configuration.safe_get(filtered_df, "ICAO", None) + self.numberOfEngines = configuration.safe_get( filtered_df, "numberOfEngines", None ) - self.engineType = Parser.safe_get(filtered_df, "engineType", None) - self.engines = Parser.safe_get(filtered_df, "engines", None) - self.WTC = Parser.safe_get(filtered_df, "WTC", None) - self.mass = Parser.safe_get(filtered_df, "mass", None) - - self.MTOW = Parser.safe_get(filtered_df, "MTOW", None) - self.OEW = Parser.safe_get(filtered_df, "OEW", None) - self.MPL = Parser.safe_get(filtered_df, "MPL", None) - self.MREF = Parser.safe_get(filtered_df, "MREF", None) - self.VMO = Parser.safe_get(filtered_df, "VMO", None) - self.MMO = Parser.safe_get(filtered_df, "MMO", None) - self.hmo = Parser.safe_get(filtered_df, "hmo", None) - self.Hmax = Parser.safe_get(filtered_df, "Hmax", None) - self.tempGrad = Parser.safe_get(filtered_df, "tempGrad", None) - - self.S = Parser.safe_get(filtered_df, "S", None) - self.Clbo = Parser.safe_get(filtered_df, "Clbo", None) - self.k = Parser.safe_get(filtered_df, "k", None) - self.Vstall = Parser.safe_get(filtered_df, "Vstall", None) - self.CD0 = Parser.safe_get(filtered_df, "CD0", None) - self.CD2 = Parser.safe_get(filtered_df, "CD2", None) - self.HLids = Parser.safe_get(filtered_df, "HLids", None) - self.Ct = Parser.safe_get(filtered_df, "Ct", None) - self.CTdeslow = Parser.safe_get(filtered_df, "CTdeslow", None) - self.CTdeshigh = Parser.safe_get(filtered_df, "CTdeshigh", None) - self.CTdesapp = Parser.safe_get(filtered_df, "CTdesapp", None) - self.CTdesld = Parser.safe_get(filtered_df, "CTdesld", None) - self.HpDes = Parser.safe_get(filtered_df, "HpDes", None) - self.Cf = Parser.safe_get(filtered_df, "Cf", None) - self.CfDes = Parser.safe_get(filtered_df, "CfDes", None) - self.CfCrz = Parser.safe_get(filtered_df, "CfCrz", None) - self.TOL = Parser.safe_get(filtered_df, "TOL", None) - self.LDL = Parser.safe_get(filtered_df, "LDL", None) - self.span = Parser.safe_get(filtered_df, "span", None) - self.length = Parser.safe_get(filtered_df, "length", None) - - self.V1 = Parser.safe_get(filtered_df, "V1", None) - self.V2 = Parser.safe_get(filtered_df, "V2", None) - self.M = Parser.safe_get(filtered_df, "M", None) - - self.GPFdata = Parser.safe_get(filtered_df, "GPFdata", None) - - self.drone = Parser.safe_get(filtered_df, "drone", None) - - self.DeltaCD = Parser.safe_get(filtered_df, "DeltaCD", None) - self.speedSchedule = Parser.safe_get( + self.engineType = configuration.safe_get( + filtered_df, "engineType", None + ) + self.engines = configuration.safe_get(filtered_df, "engines", None) + self.WTC = configuration.safe_get(filtered_df, "WTC", None) + self.mass = configuration.safe_get(filtered_df, "mass", None) + + self.MTOW = configuration.safe_get(filtered_df, "MTOW", None) + self.OEW = configuration.safe_get(filtered_df, "OEW", None) + self.MPL = configuration.safe_get(filtered_df, "MPL", None) + self.MREF = configuration.safe_get(filtered_df, "MREF", None) + self.VMO = configuration.safe_get(filtered_df, "VMO", None) + self.MMO = configuration.safe_get(filtered_df, "MMO", None) + self.hmo = configuration.safe_get(filtered_df, "hmo", None) + self.Hmax = configuration.safe_get(filtered_df, "Hmax", None) + self.tempGrad = configuration.safe_get( + filtered_df, "tempGrad", None + ) + + self.S = configuration.safe_get(filtered_df, "S", None) + self.Clbo = configuration.safe_get(filtered_df, "Clbo", None) + self.k = configuration.safe_get(filtered_df, "k", None) + self.Vstall = configuration.safe_get(filtered_df, "Vstall", None) + self.CD0 = configuration.safe_get(filtered_df, "CD0", None) + self.CD2 = configuration.safe_get(filtered_df, "CD2", None) + self.HLids = configuration.safe_get(filtered_df, "HLids", None) + self.Ct = configuration.safe_get(filtered_df, "Ct", None) + self.CTdeslow = configuration.safe_get( + filtered_df, "CTdeslow", None + ) + self.CTdeshigh = configuration.safe_get( + filtered_df, "CTdeshigh", None + ) + self.CTdesapp = configuration.safe_get( + filtered_df, "CTdesapp", None + ) + self.CTdesld = configuration.safe_get(filtered_df, "CTdesld", None) + self.HpDes = configuration.safe_get(filtered_df, "HpDes", None) + self.Cf = configuration.safe_get(filtered_df, "Cf", None) + self.CfDes = configuration.safe_get(filtered_df, "CfDes", None) + self.CfCrz = configuration.safe_get(filtered_df, "CfCrz", None) + self.TOL = configuration.safe_get(filtered_df, "TOL", None) + self.LDL = configuration.safe_get(filtered_df, "LDL", None) + self.span = configuration.safe_get(filtered_df, "span", None) + self.length = configuration.safe_get(filtered_df, "length", None) + + self.V1 = configuration.safe_get(filtered_df, "V1", None) + self.V2 = configuration.safe_get(filtered_df, "V2", None) + self.M = configuration.safe_get(filtered_df, "M", None) + + self.GPFdata = configuration.safe_get(filtered_df, "GPFdata", None) + + self.drone = configuration.safe_get(filtered_df, "drone", None) + + self.DeltaCD = configuration.safe_get(filtered_df, "DeltaCD", None) + self.speedSchedule = configuration.safe_get( filtered_df, "speedSchedule", None ) - self.aeroConfig = Parser.safe_get(filtered_df, "aeroConfig", None) + self.aeroConfig = configuration.safe_get( + filtered_df, "aeroConfig", None + ) self.flightEnvelope = FlightEnvelope(self) self.ARPM = ARPM(self) @@ -4977,89 +4901,119 @@ def __init__(self, badaVersion, acName, filePath=None, allData=None): OPF_APF_combined_df, GPFDataFrame ) - self.acName = Parser.safe_get(combined_df, "acName", None) - self.xmlFiles = Parser.safe_get( + self.acName = configuration.safe_get( + combined_df, "acName", None + ) + self.xmlFiles = configuration.safe_get( combined_df, "xmlFiles", None ) - self.modificationDateOPF = Parser.safe_get( + self.modificationDateOPF = configuration.safe_get( combined_df, "modificationDateOPF", None ) - self.modificationDateAPF = Parser.safe_get( + self.modificationDateAPF = configuration.safe_get( combined_df, "modificationDateAPF", None ) - self.ICAO = Parser.safe_get(combined_df, "ICAO", None) - self.numberOfEngines = Parser.safe_get( + self.ICAO = configuration.safe_get( + combined_df, "ICAO", None + ) + self.numberOfEngines = configuration.safe_get( combined_df, "numberOfEngines", None ) - self.engineType = Parser.safe_get( + self.engineType = configuration.safe_get( combined_df, "engineType", None ) - self.engines = Parser.safe_get( + self.engines = configuration.safe_get( combined_df, "engines", None ) - self.WTC = Parser.safe_get(combined_df, "WTC", None) - self.mass = Parser.safe_get(combined_df, "mass", None) - - self.MTOW = Parser.safe_get(combined_df, "MTOW", None) - self.OEW = Parser.safe_get(combined_df, "OEW", None) - self.MPL = Parser.safe_get(combined_df, "MPL", None) - self.MREF = Parser.safe_get(combined_df, "MREF", None) - self.VMO = Parser.safe_get(combined_df, "VMO", None) - self.MMO = Parser.safe_get(combined_df, "MMO", None) - self.hmo = Parser.safe_get(combined_df, "hmo", None) - self.Hmax = Parser.safe_get(combined_df, "Hmax", None) - self.tempGrad = Parser.safe_get( + self.WTC = configuration.safe_get(combined_df, "WTC", None) + self.mass = configuration.safe_get( + combined_df, "mass", None + ) + + self.MTOW = configuration.safe_get( + combined_df, "MTOW", None + ) + self.OEW = configuration.safe_get(combined_df, "OEW", None) + self.MPL = configuration.safe_get(combined_df, "MPL", None) + self.MREF = configuration.safe_get( + combined_df, "MREF", None + ) + self.VMO = configuration.safe_get(combined_df, "VMO", None) + self.MMO = configuration.safe_get(combined_df, "MMO", None) + self.hmo = configuration.safe_get(combined_df, "hmo", None) + self.Hmax = configuration.safe_get( + combined_df, "Hmax", None + ) + self.tempGrad = configuration.safe_get( combined_df, "tempGrad", None ) - self.S = Parser.safe_get(combined_df, "S", None) - self.Clbo = Parser.safe_get(combined_df, "Clbo", None) - self.k = Parser.safe_get(combined_df, "k", None) - self.Vstall = Parser.safe_get(combined_df, "Vstall", None) - self.CD0 = Parser.safe_get(combined_df, "CD0", None) - self.CD2 = Parser.safe_get(combined_df, "CD2", None) - self.HLids = Parser.safe_get(combined_df, "HLids", None) - self.Ct = Parser.safe_get(combined_df, "Ct", None) - self.CTdeslow = Parser.safe_get( + self.S = configuration.safe_get(combined_df, "S", None) + self.Clbo = configuration.safe_get( + combined_df, "Clbo", None + ) + self.k = configuration.safe_get(combined_df, "k", None) + self.Vstall = configuration.safe_get( + combined_df, "Vstall", None + ) + self.CD0 = configuration.safe_get(combined_df, "CD0", None) + self.CD2 = configuration.safe_get(combined_df, "CD2", None) + self.HLids = configuration.safe_get( + combined_df, "HLids", None + ) + self.Ct = configuration.safe_get(combined_df, "Ct", None) + self.CTdeslow = configuration.safe_get( combined_df, "CTdeslow", None ) - self.CTdeshigh = Parser.safe_get( + self.CTdeshigh = configuration.safe_get( combined_df, "CTdeshigh", None ) - self.CTdesapp = Parser.safe_get( + self.CTdesapp = configuration.safe_get( combined_df, "CTdesapp", None ) - self.CTdesld = Parser.safe_get( + self.CTdesld = configuration.safe_get( combined_df, "CTdesld", None ) - self.HpDes = Parser.safe_get(combined_df, "HpDes", None) - self.Cf = Parser.safe_get(combined_df, "Cf", None) - self.CfDes = Parser.safe_get(combined_df, "CfDes", None) - self.CfCrz = Parser.safe_get(combined_df, "CfCrz", None) - self.TOL = Parser.safe_get(combined_df, "TOL", None) - self.LDL = Parser.safe_get(combined_df, "LDL", None) - self.span = Parser.safe_get(combined_df, "span", None) - self.length = Parser.safe_get(combined_df, "length", None) - - self.V1 = Parser.safe_get(combined_df, "V1", None) - self.V2 = Parser.safe_get(combined_df, "V2", None) - self.M = Parser.safe_get(combined_df, "M", None) - - self.GPFdata = Parser.safe_get( + self.HpDes = configuration.safe_get( + combined_df, "HpDes", None + ) + self.Cf = configuration.safe_get(combined_df, "Cf", None) + self.CfDes = configuration.safe_get( + combined_df, "CfDes", None + ) + self.CfCrz = configuration.safe_get( + combined_df, "CfCrz", None + ) + self.TOL = configuration.safe_get(combined_df, "TOL", None) + self.LDL = configuration.safe_get(combined_df, "LDL", None) + self.span = configuration.safe_get( + combined_df, "span", None + ) + self.length = configuration.safe_get( + combined_df, "length", None + ) + + self.V1 = configuration.safe_get(combined_df, "V1", None) + self.V2 = configuration.safe_get(combined_df, "V2", None) + self.M = configuration.safe_get(combined_df, "M", None) + + self.GPFdata = configuration.safe_get( combined_df, "GPFdata", None ) - self.drone = Parser.safe_get(combined_df, "drone", None) + self.drone = configuration.safe_get( + combined_df, "drone", None + ) - self.DeltaCD = Parser.safe_get( + self.DeltaCD = configuration.safe_get( combined_df, "DeltaCD", None ) - self.speedSchedule = Parser.safe_get( + self.speedSchedule = configuration.safe_get( combined_df, "speedSchedule", None ) - self.aeroConfig = Parser.safe_get( + self.aeroConfig = configuration.safe_get( combined_df, "aeroConfig", None ) @@ -5079,89 +5033,119 @@ def __init__(self, badaVersion, acName, filePath=None, allData=None): XMLDataFrame, GPFDataFrame ) - self.acName = Parser.safe_get(combined_df, "acName", None) - self.xmlFiles = Parser.safe_get( + self.acName = configuration.safe_get( + combined_df, "acName", None + ) + self.xmlFiles = configuration.safe_get( combined_df, "xmlFiles", None ) - self.modificationDateOPF = Parser.safe_get( + self.modificationDateOPF = configuration.safe_get( combined_df, "modificationDateOPF", None ) - self.modificationDateAPF = Parser.safe_get( + self.modificationDateAPF = configuration.safe_get( combined_df, "modificationDateAPF", None ) - self.ICAO = Parser.safe_get(combined_df, "ICAO", None) - self.numberOfEngines = Parser.safe_get( + self.ICAO = configuration.safe_get( + combined_df, "ICAO", None + ) + self.numberOfEngines = configuration.safe_get( combined_df, "numberOfEngines", None ) - self.engineType = Parser.safe_get( + self.engineType = configuration.safe_get( combined_df, "engineType", None ) - self.engines = Parser.safe_get( + self.engines = configuration.safe_get( combined_df, "engines", None ) - self.WTC = Parser.safe_get(combined_df, "WTC", None) - self.mass = Parser.safe_get(combined_df, "mass", None) - - self.MTOW = Parser.safe_get(combined_df, "MTOW", None) - self.OEW = Parser.safe_get(combined_df, "OEW", None) - self.MPL = Parser.safe_get(combined_df, "MPL", None) - self.MREF = Parser.safe_get(combined_df, "MREF", None) - self.VMO = Parser.safe_get(combined_df, "VMO", None) - self.MMO = Parser.safe_get(combined_df, "MMO", None) - self.hmo = Parser.safe_get(combined_df, "hmo", None) - self.Hmax = Parser.safe_get(combined_df, "Hmax", None) - self.tempGrad = Parser.safe_get( + self.WTC = configuration.safe_get(combined_df, "WTC", None) + self.mass = configuration.safe_get( + combined_df, "mass", None + ) + + self.MTOW = configuration.safe_get( + combined_df, "MTOW", None + ) + self.OEW = configuration.safe_get(combined_df, "OEW", None) + self.MPL = configuration.safe_get(combined_df, "MPL", None) + self.MREF = configuration.safe_get( + combined_df, "MREF", None + ) + self.VMO = configuration.safe_get(combined_df, "VMO", None) + self.MMO = configuration.safe_get(combined_df, "MMO", None) + self.hmo = configuration.safe_get(combined_df, "hmo", None) + self.Hmax = configuration.safe_get( + combined_df, "Hmax", None + ) + self.tempGrad = configuration.safe_get( combined_df, "tempGrad", None ) - self.S = Parser.safe_get(combined_df, "S", None) - self.Clbo = Parser.safe_get(combined_df, "Clbo", None) - self.k = Parser.safe_get(combined_df, "k", None) - self.Vstall = Parser.safe_get(combined_df, "Vstall", None) - self.CD0 = Parser.safe_get(combined_df, "CD0", None) - self.CD2 = Parser.safe_get(combined_df, "CD2", None) - self.HLids = Parser.safe_get(combined_df, "HLids", None) - self.Ct = Parser.safe_get(combined_df, "Ct", None) - self.CTdeslow = Parser.safe_get( + self.S = configuration.safe_get(combined_df, "S", None) + self.Clbo = configuration.safe_get( + combined_df, "Clbo", None + ) + self.k = configuration.safe_get(combined_df, "k", None) + self.Vstall = configuration.safe_get( + combined_df, "Vstall", None + ) + self.CD0 = configuration.safe_get(combined_df, "CD0", None) + self.CD2 = configuration.safe_get(combined_df, "CD2", None) + self.HLids = configuration.safe_get( + combined_df, "HLids", None + ) + self.Ct = configuration.safe_get(combined_df, "Ct", None) + self.CTdeslow = configuration.safe_get( combined_df, "CTdeslow", None ) - self.CTdeshigh = Parser.safe_get( + self.CTdeshigh = configuration.safe_get( combined_df, "CTdeshigh", None ) - self.CTdesapp = Parser.safe_get( + self.CTdesapp = configuration.safe_get( combined_df, "CTdesapp", None ) - self.CTdesld = Parser.safe_get( + self.CTdesld = configuration.safe_get( combined_df, "CTdesld", None ) - self.HpDes = Parser.safe_get(combined_df, "HpDes", None) - self.Cf = Parser.safe_get(combined_df, "Cf", None) - self.CfDes = Parser.safe_get(combined_df, "CfDes", None) - self.CfCrz = Parser.safe_get(combined_df, "CfCrz", None) - self.TOL = Parser.safe_get(combined_df, "TOL", None) - self.LDL = Parser.safe_get(combined_df, "LDL", None) - self.span = Parser.safe_get(combined_df, "span", None) - self.length = Parser.safe_get(combined_df, "length", None) - - self.V1 = Parser.safe_get(combined_df, "V1", None) - self.V2 = Parser.safe_get(combined_df, "V2", None) - self.M = Parser.safe_get(combined_df, "M", None) - - self.GPFdata = Parser.safe_get( + self.HpDes = configuration.safe_get( + combined_df, "HpDes", None + ) + self.Cf = configuration.safe_get(combined_df, "Cf", None) + self.CfDes = configuration.safe_get( + combined_df, "CfDes", None + ) + self.CfCrz = configuration.safe_get( + combined_df, "CfCrz", None + ) + self.TOL = configuration.safe_get(combined_df, "TOL", None) + self.LDL = configuration.safe_get(combined_df, "LDL", None) + self.span = configuration.safe_get( + combined_df, "span", None + ) + self.length = configuration.safe_get( + combined_df, "length", None + ) + + self.V1 = configuration.safe_get(combined_df, "V1", None) + self.V2 = configuration.safe_get(combined_df, "V2", None) + self.M = configuration.safe_get(combined_df, "M", None) + + self.GPFdata = configuration.safe_get( combined_df, "GPFdata", None ) - self.drone = Parser.safe_get(combined_df, "drone", None) + self.drone = configuration.safe_get( + combined_df, "drone", None + ) - self.DeltaCD = Parser.safe_get( + self.DeltaCD = configuration.safe_get( combined_df, "DeltaCD", None ) - self.speedSchedule = Parser.safe_get( + self.speedSchedule = configuration.safe_get( combined_df, "speedSchedule", None ) - self.aeroConfig = Parser.safe_get( + self.aeroConfig = configuration.safe_get( combined_df, "aeroConfig", None ) diff --git a/src/pyBADA/bada4.py b/src/pyBADA/bada4.py index d030d3d..c16dab7 100644 --- a/src/pyBADA/bada4.py +++ b/src/pyBADA/bada4.py @@ -20,7 +20,7 @@ from pyBADA import conversions as conv from pyBADA import atmosphere as atm from pyBADA import configuration as configuration -from pyBADA.aircraft import Airplane, BadaFamily +from pyBADA.aircraft import Airplane, BadaFamily, Bada def proper_round(num, dec=0): @@ -43,31 +43,6 @@ class Parser: def __init__(self): pass - @staticmethod - def list_subfolders(folderPath): - """ - Lists all subfolders within a specified directory. - - :param folderPath: Path to the directory where subfolders are to be listed. - :type folderPath: str - :returns: A list of subfolder names within the specified directory. - :rtype: list of str - - This function retrieves all entries in the given directory and filters out - the ones that are not directories. Only the names of the subfolders are returned. - """ - # List all entries in the directory - entries = os.listdir(folderPath) - - # Filter out entries that are directories - subfolders = [ - entry - for entry in entries - if os.path.isdir(os.path.join(folderPath, entry)) - ] - - return subfolders - @staticmethod def readMappingFile(filePath, badaVersion): """ @@ -696,7 +671,7 @@ def parseAll(badaVersion, filePath=None): code_fileName = Parser.readMappingFile(filePath, badaVersion) # get names of all the folders in the main BADA model folder to search for XML files - subfolders = Parser.list_subfolders( + subfolders = configuration.list_subfolders( os.path.join(filePath, "BADA4", badaVersion) ) @@ -766,72 +741,8 @@ def parseAll(badaVersion, filePath=None): return merged_final_df - @staticmethod - def getBADAParameters(df, acName, parameters): - """ - Retrieves specified parameters for a given aircraft name from a DataFrame. - - :param df: DataFrame containing BADA aircraft data. - :param acName: Name of the aircraft or list of aircraft names to search for. - :param parameters: List of column names (or a single column name) to retrieve. - :type df: pd.DataFrame - :type acName: list or str - :type parameters: list or str - :returns: A DataFrame containing the specified parameters for the given aircraft. - :rtype: pd.DataFrame - :raises ValueError: If any of the specified columns or aircraft names are not found. - """ - # Ensure parameters is a list - if isinstance(parameters, str): - parameters = [parameters] - - # Ensure acName is a list - if isinstance(acName, str): - acName = [acName] - - # Ensure all requested parameters exist in the DataFrame - missing_cols = [col for col in parameters if col not in df.columns] - if missing_cols: - raise ValueError( - f"The following parameters are not in the DataFrame columns: {missing_cols}" - ) - - # Filter rows where 'acName' matches any of the specified aircraft names - filtered_df = df[df["acName"].isin(acName)] - - # Check if any rows were found - if filtered_df.empty: - raise ValueError(f"No entries found for aircraft(s): {acName}.") - else: - # Select the required columns - result_df = filtered_df[["acName"] + parameters].reset_index( - drop=True - ) - return result_df - - @staticmethod - def safe_get(df, column_name, default_value=None): - """ - Safely retrieves a column's value from a DataFrame, returning a default value if the column does not exist. - - :param df: DataFrame to retrieve the value from. - :param column_name: Name of the column to retrieve. - :param default_value: Value to return if the column does not exist. Default is None. - :type df: pd.DataFrame - :type column_name: str - :type default_value: any - :returns: The value from the specified column or the default value if the column is missing. - :rtype: any - """ - - if column_name in df.columns: - return df[column_name].iloc[0] - else: - return default_value - - -class BADA4(Airplane): +class BADA4(Airplane, Bada): """This class implements the part of BADA4 performance model that will be used in other classes following the BADA4 manual. :param AC: Aircraft object {BADA4}. @@ -5807,74 +5718,96 @@ def __init__(self, badaVersion, acName, filePath=None, allData=None): if allData is not None and acName in allData["acName"].values: filtered_df = allData[allData["acName"] == acName] - self.model = Parser.safe_get(filtered_df, "model", None) - self.engineType = Parser.safe_get(filtered_df, "engineType", None) - self.engines = Parser.safe_get(filtered_df, "engines", None) - self.WTC = Parser.safe_get(filtered_df, "WTC", None) - self.ICAO = Parser.safe_get(filtered_df, "ICAO", None) - self.MREF = Parser.safe_get(filtered_df, "MREF", None) - self.WREF = Parser.safe_get(filtered_df, "WREF", None) - self.LHV = Parser.safe_get(filtered_df, "LHV", None) - self.n_eng = Parser.safe_get(filtered_df, "n_eng", None) - self.rho = Parser.safe_get(filtered_df, "rho", None) - self.TFA = Parser.safe_get(filtered_df, "TFA", None) - self.p_delta = Parser.safe_get(filtered_df, "p_delta", None) - self.p_theta = Parser.safe_get(filtered_df, "p_theta", None) - self.kink = Parser.safe_get(filtered_df, "kink", None) - self.b = Parser.safe_get(filtered_df, "b", None) - self.c = Parser.safe_get(filtered_df, "c", None) - self.max_power = Parser.safe_get(filtered_df, "max_power", None) - self.p = Parser.safe_get(filtered_df, "p", None) - self.a = Parser.safe_get(filtered_df, "a", None) - self.f = Parser.safe_get(filtered_df, "f", None) - self.ti = Parser.safe_get(filtered_df, "ti", None) - self.fi = Parser.safe_get(filtered_df, "fi", None) - self.throttle = Parser.safe_get(filtered_df, "throttle", None) - self.prop_dia = Parser.safe_get(filtered_df, "prop_dia", None) - self.max_eff = Parser.safe_get(filtered_df, "max_eff", None) - self.Hd_turbo = Parser.safe_get(filtered_df, "Hd_turbo", None) - self.CPSFC = Parser.safe_get(filtered_df, "CPSFC", None) - self.P = Parser.safe_get(filtered_df, "P", None) - self.S = Parser.safe_get(filtered_df, "S", None) - self.HLPosition = Parser.safe_get(filtered_df, "HLPosition", None) - self.configName = Parser.safe_get(filtered_df, "configName", None) - self.VFE = Parser.safe_get(filtered_df, "VFE", None) - self.d = Parser.safe_get(filtered_df, "d", None) - self.CL_max = Parser.safe_get(filtered_df, "CL_max", None) - self.bf = Parser.safe_get(filtered_df, "bf", None) - self.HLids = Parser.safe_get(filtered_df, "HLids", None) - self.CL_clean = Parser.safe_get(filtered_df, "CL_clean", None) - self.M_max = Parser.safe_get(filtered_df, "M_max", None) - self.scalar = Parser.safe_get(filtered_df, "scalar", None) - self.Mmin = Parser.safe_get(filtered_df, "Mmin", None) - self.Mmax = Parser.safe_get(filtered_df, "Mmax", None) - self.CL_Mach0 = Parser.safe_get(filtered_df, "CL_Mach0", None) - self.MTOW = Parser.safe_get(filtered_df, "MTOW", None) - self.OEW = Parser.safe_get(filtered_df, "OEW", None) - self.MFL = Parser.safe_get(filtered_df, "MFL", None) - self.MTW = Parser.safe_get(filtered_df, "MTW", None) - self.MZFW = Parser.safe_get(filtered_df, "MZFW", None) - self.MPL = Parser.safe_get(filtered_df, "MPL", None) - self.MLW = Parser.safe_get(filtered_df, "MLW", None) - self.hmo = Parser.safe_get(filtered_df, "hmo", None) - self.mfa = Parser.safe_get(filtered_df, "mfa", None) - self.MMO = Parser.safe_get(filtered_df, "MMO", None) - self.MLE = Parser.safe_get(filtered_df, "MLE", None) - self.VLE = Parser.safe_get(filtered_df, "VLE", None) - self.VMO = Parser.safe_get(filtered_df, "VMO", None) - self.span = Parser.safe_get(filtered_df, "span", None) - self.length = Parser.safe_get(filtered_df, "length", None) - self.aeroConfig = Parser.safe_get(filtered_df, "aeroConfig", None) - self.speedSchedule = Parser.safe_get( + self.model = configuration.safe_get(filtered_df, "model", None) + self.engineType = configuration.safe_get( + filtered_df, "engineType", None + ) + self.engines = configuration.safe_get(filtered_df, "engines", None) + self.WTC = configuration.safe_get(filtered_df, "WTC", None) + self.ICAO = configuration.safe_get(filtered_df, "ICAO", None) + self.MREF = configuration.safe_get(filtered_df, "MREF", None) + self.WREF = configuration.safe_get(filtered_df, "WREF", None) + self.LHV = configuration.safe_get(filtered_df, "LHV", None) + self.n_eng = configuration.safe_get(filtered_df, "n_eng", None) + self.rho = configuration.safe_get(filtered_df, "rho", None) + self.TFA = configuration.safe_get(filtered_df, "TFA", None) + self.p_delta = configuration.safe_get(filtered_df, "p_delta", None) + self.p_theta = configuration.safe_get(filtered_df, "p_theta", None) + self.kink = configuration.safe_get(filtered_df, "kink", None) + self.b = configuration.safe_get(filtered_df, "b", None) + self.c = configuration.safe_get(filtered_df, "c", None) + self.max_power = configuration.safe_get( + filtered_df, "max_power", None + ) + self.p = configuration.safe_get(filtered_df, "p", None) + self.a = configuration.safe_get(filtered_df, "a", None) + self.f = configuration.safe_get(filtered_df, "f", None) + self.ti = configuration.safe_get(filtered_df, "ti", None) + self.fi = configuration.safe_get(filtered_df, "fi", None) + self.throttle = configuration.safe_get( + filtered_df, "throttle", None + ) + self.prop_dia = configuration.safe_get( + filtered_df, "prop_dia", None + ) + self.max_eff = configuration.safe_get(filtered_df, "max_eff", None) + self.Hd_turbo = configuration.safe_get( + filtered_df, "Hd_turbo", None + ) + self.CPSFC = configuration.safe_get(filtered_df, "CPSFC", None) + self.P = configuration.safe_get(filtered_df, "P", None) + self.S = configuration.safe_get(filtered_df, "S", None) + self.HLPosition = configuration.safe_get( + filtered_df, "HLPosition", None + ) + self.configName = configuration.safe_get( + filtered_df, "configName", None + ) + self.VFE = configuration.safe_get(filtered_df, "VFE", None) + self.d = configuration.safe_get(filtered_df, "d", None) + self.CL_max = configuration.safe_get(filtered_df, "CL_max", None) + self.bf = configuration.safe_get(filtered_df, "bf", None) + self.HLids = configuration.safe_get(filtered_df, "HLids", None) + self.CL_clean = configuration.safe_get( + filtered_df, "CL_clean", None + ) + self.M_max = configuration.safe_get(filtered_df, "M_max", None) + self.scalar = configuration.safe_get(filtered_df, "scalar", None) + self.Mmin = configuration.safe_get(filtered_df, "Mmin", None) + self.Mmax = configuration.safe_get(filtered_df, "Mmax", None) + self.CL_Mach0 = configuration.safe_get( + filtered_df, "CL_Mach0", None + ) + self.MTOW = configuration.safe_get(filtered_df, "MTOW", None) + self.OEW = configuration.safe_get(filtered_df, "OEW", None) + self.MFL = configuration.safe_get(filtered_df, "MFL", None) + self.MTW = configuration.safe_get(filtered_df, "MTW", None) + self.MZFW = configuration.safe_get(filtered_df, "MZFW", None) + self.MPL = configuration.safe_get(filtered_df, "MPL", None) + self.MLW = configuration.safe_get(filtered_df, "MLW", None) + self.hmo = configuration.safe_get(filtered_df, "hmo", None) + self.mfa = configuration.safe_get(filtered_df, "mfa", None) + self.MMO = configuration.safe_get(filtered_df, "MMO", None) + self.MLE = configuration.safe_get(filtered_df, "MLE", None) + self.VLE = configuration.safe_get(filtered_df, "VLE", None) + self.VMO = configuration.safe_get(filtered_df, "VMO", None) + self.span = configuration.safe_get(filtered_df, "span", None) + self.length = configuration.safe_get(filtered_df, "length", None) + self.aeroConfig = configuration.safe_get( + filtered_df, "aeroConfig", None + ) + self.speedSchedule = configuration.safe_get( filtered_df, "speedSchedule", None ) # GPF data (temporary) - self.CVminTO = Parser.safe_get(filtered_df, "CVminTO", None) - self.CVmin = Parser.safe_get(filtered_df, "CVmin", None) - self.HmaxPhase = Parser.safe_get(filtered_df, "HmaxPhase", None) - self.V_des = Parser.safe_get(filtered_df, "V_des", None) - self.V_cl = Parser.safe_get(filtered_df, "V_cl", None) + self.CVminTO = configuration.safe_get(filtered_df, "CVminTO", None) + self.CVmin = configuration.safe_get(filtered_df, "CVmin", None) + self.HmaxPhase = configuration.safe_get( + filtered_df, "HmaxPhase", None + ) + self.V_des = configuration.safe_get(filtered_df, "V_des", None) + self.V_cl = configuration.safe_get(filtered_df, "V_cl", None) self.flightEnvelope = FlightEnvelope(self) self.ARPM = ARPM(self) @@ -5947,106 +5880,146 @@ def __init__(self, badaVersion, acName, filePath=None, allData=None): self.acName = self.SearchedACName - self.model = Parser.safe_get(combined_df, "model", None) - self.engineType = Parser.safe_get( + self.model = configuration.safe_get( + combined_df, "model", None + ) + self.engineType = configuration.safe_get( combined_df, "engineType", None ) - self.engines = Parser.safe_get( + self.engines = configuration.safe_get( combined_df, "engines", None ) - self.WTC = Parser.safe_get(combined_df, "WTC", None) - self.ICAO = Parser.safe_get(combined_df, "ICAO", None) - self.MREF = Parser.safe_get(combined_df, "MREF", None) - self.WREF = Parser.safe_get(combined_df, "WREF", None) - self.LHV = Parser.safe_get(combined_df, "LHV", None) - self.n_eng = Parser.safe_get(combined_df, "n_eng", None) - self.rho = Parser.safe_get(combined_df, "rho", None) - self.TFA = Parser.safe_get(combined_df, "TFA", None) - self.p_delta = Parser.safe_get( + self.WTC = configuration.safe_get(combined_df, "WTC", None) + self.ICAO = configuration.safe_get( + combined_df, "ICAO", None + ) + self.MREF = configuration.safe_get( + combined_df, "MREF", None + ) + self.WREF = configuration.safe_get( + combined_df, "WREF", None + ) + self.LHV = configuration.safe_get(combined_df, "LHV", None) + self.n_eng = configuration.safe_get( + combined_df, "n_eng", None + ) + self.rho = configuration.safe_get(combined_df, "rho", None) + self.TFA = configuration.safe_get(combined_df, "TFA", None) + self.p_delta = configuration.safe_get( combined_df, "p_delta", None ) - self.p_theta = Parser.safe_get( + self.p_theta = configuration.safe_get( combined_df, "p_theta", None ) - self.kink = Parser.safe_get(combined_df, "kink", None) - self.b = Parser.safe_get(combined_df, "b", None) - self.c = Parser.safe_get(combined_df, "c", None) - self.max_power = Parser.safe_get( + self.kink = configuration.safe_get( + combined_df, "kink", None + ) + self.b = configuration.safe_get(combined_df, "b", None) + self.c = configuration.safe_get(combined_df, "c", None) + self.max_power = configuration.safe_get( combined_df, "max_power", None ) - self.p = Parser.safe_get(combined_df, "p", None) - self.a = Parser.safe_get(combined_df, "a", None) - self.f = Parser.safe_get(combined_df, "f", None) - self.ti = Parser.safe_get(combined_df, "ti", None) - self.fi = Parser.safe_get(combined_df, "fi", None) - self.throttle = Parser.safe_get( + self.p = configuration.safe_get(combined_df, "p", None) + self.a = configuration.safe_get(combined_df, "a", None) + self.f = configuration.safe_get(combined_df, "f", None) + self.ti = configuration.safe_get(combined_df, "ti", None) + self.fi = configuration.safe_get(combined_df, "fi", None) + self.throttle = configuration.safe_get( combined_df, "throttle", None ) - self.prop_dia = Parser.safe_get( + self.prop_dia = configuration.safe_get( combined_df, "prop_dia", None ) - self.max_eff = Parser.safe_get( + self.max_eff = configuration.safe_get( combined_df, "max_eff", None ) - self.Hd_turbo = Parser.safe_get( + self.Hd_turbo = configuration.safe_get( combined_df, "Hd_turbo", None ) - self.CPSFC = Parser.safe_get(combined_df, "CPSFC", None) - self.P = Parser.safe_get(combined_df, "P", None) - self.S = Parser.safe_get(combined_df, "S", None) - self.HLPosition = Parser.safe_get( + self.CPSFC = configuration.safe_get( + combined_df, "CPSFC", None + ) + self.P = configuration.safe_get(combined_df, "P", None) + self.S = configuration.safe_get(combined_df, "S", None) + self.HLPosition = configuration.safe_get( combined_df, "HLPosition", None ) - self.configName = Parser.safe_get( + self.configName = configuration.safe_get( combined_df, "configName", None ) - self.VFE = Parser.safe_get(combined_df, "VFE", None) - self.d = Parser.safe_get(combined_df, "d", None) - self.CL_max = Parser.safe_get(combined_df, "CL_max", None) - self.bf = Parser.safe_get(combined_df, "bf", None) - self.HLids = Parser.safe_get(combined_df, "HLids", None) - self.CL_clean = Parser.safe_get( + self.VFE = configuration.safe_get(combined_df, "VFE", None) + self.d = configuration.safe_get(combined_df, "d", None) + self.CL_max = configuration.safe_get( + combined_df, "CL_max", None + ) + self.bf = configuration.safe_get(combined_df, "bf", None) + self.HLids = configuration.safe_get( + combined_df, "HLids", None + ) + self.CL_clean = configuration.safe_get( combined_df, "CL_clean", None ) - self.M_max = Parser.safe_get(combined_df, "M_max", None) - self.scalar = Parser.safe_get(combined_df, "scalar", None) - self.Mmin = Parser.safe_get(combined_df, "Mmin", None) - self.Mmax = Parser.safe_get(combined_df, "Mmax", None) - self.CL_Mach0 = Parser.safe_get( + self.M_max = configuration.safe_get( + combined_df, "M_max", None + ) + self.scalar = configuration.safe_get( + combined_df, "scalar", None + ) + self.Mmin = configuration.safe_get( + combined_df, "Mmin", None + ) + self.Mmax = configuration.safe_get( + combined_df, "Mmax", None + ) + self.CL_Mach0 = configuration.safe_get( combined_df, "CL_Mach0", None ) - self.MTOW = Parser.safe_get(combined_df, "MTOW", None) - self.OEW = Parser.safe_get(combined_df, "OEW", None) - self.MFL = Parser.safe_get(combined_df, "MFL", None) - self.MTW = Parser.safe_get(combined_df, "MTW", None) - self.MZFW = Parser.safe_get(combined_df, "MZFW", None) - self.MPL = Parser.safe_get(combined_df, "MPL", None) - self.MLW = Parser.safe_get(combined_df, "MLW", None) - self.hmo = Parser.safe_get(combined_df, "hmo", None) - self.mfa = Parser.safe_get(combined_df, "mfa", None) - self.MMO = Parser.safe_get(combined_df, "MMO", None) - self.MLE = Parser.safe_get(combined_df, "MLE", None) - self.VLE = Parser.safe_get(combined_df, "VLE", None) - self.VMO = Parser.safe_get(combined_df, "VMO", None) - self.span = Parser.safe_get(combined_df, "span", None) - self.length = Parser.safe_get(combined_df, "length", None) - self.aeroConfig = Parser.safe_get( + self.MTOW = configuration.safe_get( + combined_df, "MTOW", None + ) + self.OEW = configuration.safe_get(combined_df, "OEW", None) + self.MFL = configuration.safe_get(combined_df, "MFL", None) + self.MTW = configuration.safe_get(combined_df, "MTW", None) + self.MZFW = configuration.safe_get( + combined_df, "MZFW", None + ) + self.MPL = configuration.safe_get(combined_df, "MPL", None) + self.MLW = configuration.safe_get(combined_df, "MLW", None) + self.hmo = configuration.safe_get(combined_df, "hmo", None) + self.mfa = configuration.safe_get(combined_df, "mfa", None) + self.MMO = configuration.safe_get(combined_df, "MMO", None) + self.MLE = configuration.safe_get(combined_df, "MLE", None) + self.VLE = configuration.safe_get(combined_df, "VLE", None) + self.VMO = configuration.safe_get(combined_df, "VMO", None) + self.span = configuration.safe_get( + combined_df, "span", None + ) + self.length = configuration.safe_get( + combined_df, "length", None + ) + self.aeroConfig = configuration.safe_get( combined_df, "aeroConfig", None ) - self.speedSchedule = Parser.safe_get( + self.speedSchedule = configuration.safe_get( combined_df, "speedSchedule", None ) # GPF data (temporary) - self.CVminTO = Parser.safe_get( + self.CVminTO = configuration.safe_get( combined_df, "CVminTO", None ) - self.CVmin = Parser.safe_get(combined_df, "CVmin", None) - self.HmaxPhase = Parser.safe_get( + self.CVmin = configuration.safe_get( + combined_df, "CVmin", None + ) + self.HmaxPhase = configuration.safe_get( combined_df, "HmaxPhase", None ) - self.V_des = Parser.safe_get(combined_df, "V_des", None) - self.V_cl = Parser.safe_get(combined_df, "V_cl", None) + self.V_des = configuration.safe_get( + combined_df, "V_des", None + ) + self.V_cl = configuration.safe_get( + combined_df, "V_cl", None + ) # BADA4.__init__(self, AC_parsed) self.flightEnvelope = FlightEnvelope(self) diff --git a/src/pyBADA/badaH.py b/src/pyBADA/badaH.py index eac9efb..c811eef 100644 --- a/src/pyBADA/badaH.py +++ b/src/pyBADA/badaH.py @@ -19,7 +19,7 @@ from pyBADA import conversions as conv from pyBADA import atmosphere as atm from pyBADA import configuration as configuration -from pyBADA.aircraft import Helicopter, BadaFamily +from pyBADA.aircraft import Helicopter, BadaFamily, Bada def proper_round(num, dec=0): @@ -42,31 +42,6 @@ class Parser: def __init__(self): pass - @staticmethod - def list_subfolders(folderPath): - """ - Lists all subfolders within a specified directory. - - :param folderPath: Path to the directory where subfolders are to be listed. - :type folderPath: str - :returns: A list of subfolder names within the specified directory. - :rtype: list of str - - This function retrieves all entries in the given directory and filters out - the ones that are not directories. Only the names of the subfolders are returned. - """ - # List all entries in the directory - entries = os.listdir(folderPath) - - # Filter out entries that are directories - subfolders = [ - entry - for entry in entries - if os.path.isdir(os.path.join(folderPath, entry)) - ] - - return subfolders - @staticmethod def parseXML(filePath, badaVersion, acName): """ @@ -284,7 +259,7 @@ def parseAll(badaVersion, filePath=None): # get names of all the folders in the main BADA model folder to search for XML files folderPath = os.path.join(filePath, "BADAH", badaVersion) - subfolders = Parser.list_subfolders(folderPath) + subfolders = configuration.list_subfolders(folderPath) merged_df = pd.DataFrame() @@ -312,72 +287,8 @@ def parseAll(badaVersion, filePath=None): return merged_df - @staticmethod - def getBADAParameters(df, acName, parameters): - """ - Retrieves specified parameters for a given aircraft name from a DataFrame. - - :param df: DataFrame containing BADA aircraft data. - :param acName: Name of the aircraft or list of aircraft names to search for. - :param parameters: List of column names (or a single column name) to retrieve. - :type df: pd.DataFrame - :type acName: list or str - :type parameters: list or str - :returns: A DataFrame containing the specified parameters for the given aircraft. - :rtype: pd.DataFrame - :raises ValueError: If any of the specified columns or aircraft names are not found. - """ - - # Ensure parameters is a list - if isinstance(parameters, str): - parameters = [parameters] - - # Ensure acName is a list - if isinstance(acName, str): - acName = [acName] - - # Ensure all requested parameters exist in the DataFrame - missing_cols = [col for col in parameters if col not in df.columns] - if missing_cols: - raise ValueError( - f"The following parameters are not in the DataFrame columns: {missing_cols}" - ) - - # Filter rows where 'acName' matches any of the specified aircraft names - filtered_df = df[df["acName"].isin(acName)] - - # Check if any rows were found - if filtered_df.empty: - raise ValueError(f"No entries found for aircraft(s): {acName}.") - else: - # Select the required columns - result_df = filtered_df[["acName"] + parameters].reset_index( - drop=True - ) - return result_df - - @staticmethod - def safe_get(df, column_name, default_value=None): - """ - Safely retrieves a column's value from a DataFrame, returning a default value if the column does not exist. - - :param df: DataFrame to retrieve the value from. - :param column_name: Name of the column to retrieve. - :param default_value: Value to return if the column does not exist. Default is None. - :type df: pd.DataFrame - :type column_name: str - :type default_value: any - :returns: The value from the specified column or the default value if the column is missing. - :rtype: any - """ - - if column_name in df.columns: - return df[column_name].iloc[0] - else: - return default_value - -class BADAH(Helicopter): +class BADAH(Helicopter, Bada): """This class implements the part of BADAH performance model that will be used in other classes following the BADAH manual. :param AC: Aircraft object {BADAH}. @@ -4101,28 +4012,34 @@ def __init__(self, badaVersion, acName, filePath=None, allData=None): if allData is not None and acName in allData["acName"].values: filtered_df = allData[allData["acName"] == acName] - self.model = Parser.safe_get(filtered_df, "model", None) - self.engineType = Parser.safe_get(filtered_df, "engineType", None) - self.engines = Parser.safe_get(filtered_df, "engines", None) - self.WTC = Parser.safe_get(filtered_df, "WTC", None) - self.ICAO = Parser.safe_get(filtered_df, "ICAO", None) - self.MR_radius = Parser.safe_get(filtered_df, "MR_radius", None) - self.MR_Speed = Parser.safe_get(filtered_df, "MR_Speed", None) - self.cpr = Parser.safe_get(filtered_df, "cpr", None) - self.n_eng = Parser.safe_get(filtered_df, "n_eng", None) - self.P0 = Parser.safe_get(filtered_df, "P0", None) - self.cf = Parser.safe_get(filtered_df, "cf", None) - self.Pmax_ = Parser.safe_get(filtered_df, "Pmax_", None) - self.cpa = Parser.safe_get(filtered_df, "cpa", None) - self.hmo = Parser.safe_get(filtered_df, "hmo", None) - self.vne = Parser.safe_get(filtered_df, "vne", None) - self.MTOW = Parser.safe_get(filtered_df, "MTOW", None) - self.OEW = Parser.safe_get(filtered_df, "OEW", None) - self.MFL = Parser.safe_get(filtered_df, "MFL", None) - self.MREF = Parser.safe_get(filtered_df, "MREF", None) - self.MPL = Parser.safe_get(filtered_df, "MPL", None) - self.VMO = Parser.safe_get(filtered_df, "VMO", None) - self.MMO = Parser.safe_get(filtered_df, "MMO", None) + self.model = configuration.safe_get(filtered_df, "model", None) + self.engineType = configuration.safe_get( + filtered_df, "engineType", None + ) + self.engines = configuration.safe_get(filtered_df, "engines", None) + self.WTC = configuration.safe_get(filtered_df, "WTC", None) + self.ICAO = configuration.safe_get(filtered_df, "ICAO", None) + self.MR_radius = configuration.safe_get( + filtered_df, "MR_radius", None + ) + self.MR_Speed = configuration.safe_get( + filtered_df, "MR_Speed", None + ) + self.cpr = configuration.safe_get(filtered_df, "cpr", None) + self.n_eng = configuration.safe_get(filtered_df, "n_eng", None) + self.P0 = configuration.safe_get(filtered_df, "P0", None) + self.cf = configuration.safe_get(filtered_df, "cf", None) + self.Pmax_ = configuration.safe_get(filtered_df, "Pmax_", None) + self.cpa = configuration.safe_get(filtered_df, "cpa", None) + self.hmo = configuration.safe_get(filtered_df, "hmo", None) + self.vne = configuration.safe_get(filtered_df, "vne", None) + self.MTOW = configuration.safe_get(filtered_df, "MTOW", None) + self.OEW = configuration.safe_get(filtered_df, "OEW", None) + self.MFL = configuration.safe_get(filtered_df, "MFL", None) + self.MREF = configuration.safe_get(filtered_df, "MREF", None) + self.MPL = configuration.safe_get(filtered_df, "MPL", None) + self.VMO = configuration.safe_get(filtered_df, "VMO", None) + self.MMO = configuration.safe_get(filtered_df, "MMO", None) self.flightEnvelope = FlightEnvelope(self) self.OPT = Optimization(self) @@ -4182,36 +4099,48 @@ def __init__(self, badaVersion, acName, filePath=None, allData=None): self.OPTFilePath = OPTFilePath - self.model = Parser.safe_get(ACparsed_df, "model", None) - self.engineType = Parser.safe_get( + self.model = configuration.safe_get( + ACparsed_df, "model", None + ) + self.engineType = configuration.safe_get( ACparsed_df, "engineType", None ) - self.engines = Parser.safe_get( + self.engines = configuration.safe_get( ACparsed_df, "engines", None ) - self.WTC = Parser.safe_get(ACparsed_df, "WTC", None) - self.ICAO = Parser.safe_get(ACparsed_df, "ICAO", None) - self.MR_radius = Parser.safe_get( + self.WTC = configuration.safe_get(ACparsed_df, "WTC", None) + self.ICAO = configuration.safe_get( + ACparsed_df, "ICAO", None + ) + self.MR_radius = configuration.safe_get( ACparsed_df, "MR_radius", None ) - self.MR_Speed = Parser.safe_get( + self.MR_Speed = configuration.safe_get( ACparsed_df, "MR_Speed", None ) - self.cpr = Parser.safe_get(ACparsed_df, "cpr", None) - self.n_eng = Parser.safe_get(ACparsed_df, "n_eng", None) - self.P0 = Parser.safe_get(ACparsed_df, "P0", None) - self.cf = Parser.safe_get(ACparsed_df, "cf", None) - self.Pmax_ = Parser.safe_get(ACparsed_df, "Pmax_", None) - self.cpa = Parser.safe_get(ACparsed_df, "cpa", None) - self.hmo = Parser.safe_get(ACparsed_df, "hmo", None) - self.vne = Parser.safe_get(ACparsed_df, "vne", None) - self.MTOW = Parser.safe_get(ACparsed_df, "MTOW", None) - self.OEW = Parser.safe_get(ACparsed_df, "OEW", None) - self.MFL = Parser.safe_get(ACparsed_df, "MFL", None) - self.MREF = Parser.safe_get(ACparsed_df, "MREF", None) - self.MPL = Parser.safe_get(ACparsed_df, "MPL", None) - self.VMO = Parser.safe_get(ACparsed_df, "VMO", None) - self.MMO = Parser.safe_get(ACparsed_df, "MMO", None) + self.cpr = configuration.safe_get(ACparsed_df, "cpr", None) + self.n_eng = configuration.safe_get( + ACparsed_df, "n_eng", None + ) + self.P0 = configuration.safe_get(ACparsed_df, "P0", None) + self.cf = configuration.safe_get(ACparsed_df, "cf", None) + self.Pmax_ = configuration.safe_get( + ACparsed_df, "Pmax_", None + ) + self.cpa = configuration.safe_get(ACparsed_df, "cpa", None) + self.hmo = configuration.safe_get(ACparsed_df, "hmo", None) + self.vne = configuration.safe_get(ACparsed_df, "vne", None) + self.MTOW = configuration.safe_get( + ACparsed_df, "MTOW", None + ) + self.OEW = configuration.safe_get(ACparsed_df, "OEW", None) + self.MFL = configuration.safe_get(ACparsed_df, "MFL", None) + self.MREF = configuration.safe_get( + ACparsed_df, "MREF", None + ) + self.MPL = configuration.safe_get(ACparsed_df, "MPL", None) + self.VMO = configuration.safe_get(ACparsed_df, "VMO", None) + self.MMO = configuration.safe_get(ACparsed_df, "MMO", None) self.flightEnvelope = FlightEnvelope(self) self.OPT = Optimization(self) diff --git a/src/pyBADA/configuration.py b/src/pyBADA/configuration.py index ff53259..d1040a1 100644 --- a/src/pyBADA/configuration.py +++ b/src/pyBADA/configuration.py @@ -10,6 +10,54 @@ import importlib.resources +@staticmethod +def list_subfolders(folderPath): + """ + Lists all subfolders within a specified directory. + + :param folderPath: Path to the directory where subfolders are to be listed. + :type folderPath: str + :returns: A list of subfolder names within the specified directory. + :rtype: list of str + + This function retrieves all entries in the given directory and filters out + the ones that are not directories. Only the names of the subfolders are returned. + """ + + # List all entries in the directory + entries = os.listdir(folderPath) + + # Filter out entries that are directories + subfolders = [ + entry + for entry in entries + if os.path.isdir(os.path.join(folderPath, entry)) + ] + + return subfolders + + +@staticmethod +def safe_get(df, column_name, default_value=None): + """ + Safely retrieves a column's value from a DataFrame, returning a default value if the column does not exist. + + :param df: DataFrame to retrieve the value from. + :param column_name: Name of the column to retrieve. + :param default_value: Value to return if the column does not exist. Default is None. + :type df: pd.DataFrame + :type column_name: str + :type default_value: any + :returns: The value from the specified column or the default value if the column is missing. + :rtype: any + """ + + if column_name in df.columns: + return df[column_name].iloc[0] + else: + return default_value + + def getVersionsList(badaFamily): """Retrieve a list of available BADA versions for a given BADA family.