def test_logic(types): for option_set in [ types["scalar"], types["vector"], types["matrix"], ]: for x in option_set: for y in option_set: ### Comparisons """ Note: if warnings appear here, they're from `np.array(1) == cas.MX(1)` - sensitive to order, as `cas.MX(1) == np.array(1)` is fine. However, checking the outputs, these seem to be yielding correct results despite the warning sooo... """ x == y # Warnings coming from here x != y # Warnings coming from here x > y x >= y x < y x <= y ### Conditionals np.where(x > 1, x**2, 0) ### Elementwise min/max np.fmax(x, y) np.fmin(x, y) for x in types["all"]: np.fabs(x) np.floor(x) np.ceil(x) np.clip(x, 0, 1)
def solar_azimuth_angle(latitude, day_of_year, time): """ Azimuth angle of the sun [degrees] for a local observer. :param latitude: Latitude [degrees] :param day_of_year: Julian day (1 == Jan. 1, 365 == Dec. 31) :param time: Time after local solar noon [seconds] :return: Solar azimuth angle [degrees] (the compass direction from which the sunlight is coming). """ # Solar azimuth angle (including seasonality, latitude, and time of day) # Source: https://www.pveducation.org/pvcdrom/properties-of-sunlight/azimuth-angle declination = declination_angle(day_of_year) sdec = np.sind(declination) cdec = np.cosd(declination) slat = np.sind(latitude) clat = np.cosd(latitude) ctime = np.cosd(time / 86400 * 360) elevation = solar_elevation_angle(latitude, day_of_year, time) cele = np.cosd(elevation) cos_azimuth = (sdec * clat - cdec * slat * ctime) / cele cos_azimuth = np.clip(cos_azimuth, -1, 1) azimuth_raw = np.arccosd(cos_azimuth) is_solar_morning = np.mod(time, 86400) > 43200 solar_azimuth_angle = np.where( is_solar_morning, azimuth_raw, 360 - azimuth_raw ) return solar_azimuth_angle
def oswalds_efficiency( taper_ratio: float, aspect_ratio: float, sweep: float = 0., fuselage_diameter_to_span_ratio: float = 0., ) -> float: """ Computes the Oswald's efficiency factor for a planar, tapered, swept wing. Based on "Estimating the Oswald Factor from Basic Aircraft Geometrical Parameters" by M. Nita, D. Scholz; Hamburg Univ. of Applied Sciences, 2012. Implementation of Section 5 from the above paper. Only valid for backwards-swept wings; i.e. 0 <= sweep < 90. Args: taper_ratio: Taper ratio of the wing (tip_chord / root_chord) [-] aspect_ratio: Aspect ratio of the wing (b^2 / S) [-] sweep: Wing quarter-chord sweep angle [deg] Returns: Oswald's efficiency factor [-] """ sweep = np.clip(sweep, 0, 90) # TODO input proper analytic continuation def f(l): # f(lambda), given as Eq. 36 in the Nita and Scholz paper (see parent docstring). return ( 0.0524 * l ** 4 - 0.15 * l ** 3 + 0.1659 * l ** 2 - 0.0706 * l + 0.0119 ) delta_lambda = -0.357 + 0.45 * np.exp(-0.0375 * sweep) # Eq. 37 in Nita & Scholz. # Note: there is a typo in the cited paper; the negative in the exponent was omitted. # A bit of thinking about this reveals that this omission must be erroneous. e_theo = 1 / ( 1 + f(taper_ratio - delta_lambda) * aspect_ratio ) fuselage_wake_contraction_correction_factor = 1 - 2 * (fuselage_diameter_to_span_ratio) ** 2 e = e_theo * fuselage_wake_contraction_correction_factor return e
def scattering_factor(elevation_angle): """ Calculates a scattering factor (a factor that gives losses due to atmospheric scattering at low elevation angles). Source: AeroSandbox/studies/SolarPanelScattering :param elevation_angle: Angle between the horizon and the sun [degrees] :return: Fraction of the light that is not lost to scattering. """ elevation_angle = np.clip(elevation_angle, 0, 90) theta = 90 - elevation_angle # Angle between panel normal and the sun, in degrees # # Model 1 # c = ( # 0.27891510500505767300438719757949, # -0.015994330894744987481281839336589, # -19.707332432605799255043166340329, # -0.66260979582573353852126274432521 # ) # scattering_factor = c[0] + c[3] * theta_rad + cas.exp( # c[1] * ( # cas.tan(theta_rad) + c[2] * theta_rad # ) # ) # Model 2 c = ( -0.04636, -0.3171 ) scattering_factor = np.exp( c[0] * ( np.tand(theta * 0.999) + c[1] * np.radians(theta) ) ) # # Model 3 # p1 = -21.74 # p2 = 282.6 # p3 = -1538 # p4 = 1786 # q1 = -923.2 # q2 = 1456 # x = theta_rad # scattering_factor = ((p1*x**3 + p2*x**2 + p3*x + p4) / # (x**2 + q1*x + q2)) # Keep this: # scattering_factor = cas.fmin(cas.fmax(scattering_factor, 0), 1) return scattering_factor
def length_day(latitude, day_of_year): """ For what length of time is the sun above the horizon on a given day? :param latitude: Latitude [degrees] :param day_of_year: Julian day (1 == Jan. 1, 365 == Dec. 31) :return: Seconds of sunlight in a given day """ dec = declination_angle(day_of_year) constant = -np.sind(dec) * np.sind(latitude) / (np.cosd(dec) * np.cosd(latitude)) constant = np.clip(constant, -1, 1) sun_time_nondim = 2 * np.arccos(constant) sun_time = sun_time_nondim / (2 * np.pi) * 86400 return sun_time
def optimal_taper_ratio(sweep=0., ) -> float: """ Computes the optimal (minimum-induced-drag) taper ratio for a given quarter-chord sweep angle. Based on "Estimating the Oswald Factor from Basic Aircraft Geometrical Parameters" by M. Nita, D. Scholz; Hamburg Univ. of Applied Sciences, 2012. Only valid for backwards-swept wings; i.e. 0 <= sweep < 90. Args: sweep: Wing quarter-chord sweep angle [deg] Returns: Optimal taper ratio """ sweep = np.clip(sweep, 0, 90) # TODO input proper analytic continuation return 0.45 * np.exp(-0.0375 * sweep)