def get_declination(app_long: FlexNum, oblique_corr: FlexNum): """ solar declination angle at ref_datetime""" sal = radians(app_long) oc = radians(oblique_corr) declination = degrees(arcsin((sin(oc) * sin(sal)))) return declination
def get_right_ascension(app_long: FlexNum, oblique_corr: FlexNum): """ calculates the suns right ascension angle """ sal = radians(app_long) oc = radians(oblique_corr) right_ascension = degrees(arctan2(cos(oc) * sin(sal), cos(sal))) return right_ascension
def get_zenith(declination: FlexNum, hour_angle: FlexNum, lat_r: FlexNum): """ calculates solar zenith angle at ref_datetime""" d = radians(declination) ha = radians(hour_angle) lat = lat_r zenith = degrees(arccos(sin(lat) * sin(d) + cos(lat) * cos(d) * cos(ha))) return zenith
def get_hour_angle_sunrise(declination: FlexNum, lat_r: FlexNum): """ calculates the hour angle of sunrise """ d = radians(declination) lat = lat_r # radians hour_angle_sunrise = degrees( arccos( (cos(radians(90.833)) / (cos(lat) * cos(d)) - tan(lat) * tan(d)))) return hour_angle_sunrise
def normalize_asteroids(df): df.rename(columns={'e': 'ecce', 'i': 'incl', 'a': 'semiax', 'om': 'Omega', 'w': 'omegap'}, inplace=True) # it's ugly but it seems to work only in this way df['incl'] = radians(df['incl']) df['Omega'] = radians(df['Omega']) df['omegap'] = radians(df['omegap']) return df
def _polar_to_cartesian(phi: FlexNum, theta: FlexNum): """ Converts polar to cartesian coordinate unit vector (vector length of one). :param phi: phi is measured as an azimuth or aspect angle in the x,y plane. (degrees) :param theta: theta is measured as an angle from vertical, as zenith or slope angle. (degrees) note that phi may be 'Nan' where theta is zero (perfect z vector) """ theta_r = radians(theta) phi_r = radians(phi) y = np.sin(theta_r) * np.cos(phi_r) x = np.sin(theta_r) * np.sin(phi_r) z = np.cos(theta_r) return np.stack([x, y, z], axis=-1)
def get_oblique_corr(ajc: FlexNum, oblique_mean_ellipse: FlexNum): """ calculates the oblique correction """ ome = oblique_mean_ellipse oblique_corr = ome + 0.00256 * cos(radians(125.04 - 1934.136 * ajc)) return oblique_corr
def get_rad_vector(earth_eccent: FlexNum, true_anom: FlexNum): """ calculates incident radiation vector to surface at ref_datetime (AUs)""" ec = earth_eccent ta = radians(true_anom) rad_vector = (1.000001018 * (1 - ec**2)) / (1 + ec * cos(ta)) return rad_vector
def get_equation_of_time(oblique_corr: FlexNum, geomean_long: FlexNum, geomean_anom: FlexNum, earth_eccent: FlexNum): """ calculates the equation of time in minutes """ oc = radians(oblique_corr) gml = radians(geomean_long) gma = radians(geomean_anom) ec = earth_eccent vary = tan(oc / 2)**2 equation_of_time = 4 * degrees( vary * sin(2 * gml) - 2 * ec * sin(gma) + \ 4 * ec * vary * sin(gma) * cos(2 * gml) - \ 0.5 * vary * vary * sin(4 * gml) - \ 1.25 * ec * ec * sin(2 * gma)) return equation_of_time
def get_sun_eq_of_center(ajc: FlexNum, geomean_anom: FlexNum): """calculates the suns equation of center""" gma = radians(geomean_anom) sun_eq_of_center = \ sin(gma) * (1.914602 - ajc * (0.004817 + 0.000014 * ajc)) + \ sin(2 * gma) * (0.019993 - 0.000101 * ajc) + \ sin(3 * gma) * 0.000289 return sun_eq_of_center
def get_elevation(zenith: FlexNum): """ calculates solar elevation angle at ref_datetime""" # perform an approximate atmospheric refraction correction # matrix hour_angle calculations # these equations are hideous, but im not sure how to improve them without adding computational complexity if isinstance(zenith, np.ndarray) and zenith.shape: e = 90.0 - zenith ar = e * 0 ar[e > 85] = 0 ar[(e > 5) & (e <= 85)] = 58.1 / tan(radians(e[(e > 5) & (e <= 85)])) - \ 0.07 / tan(radians(e[(e > 5) & (e <= 85)])) ** 3 + \ 0.000086 / tan(radians(e[(e > 5) & (e <= 85)])) ** 5 ar[(e > -0.575) & (e <= 5)] = 1735 + e[(e > -0.575) & (e <= 5)] * \ (103.4 + e[(e > -0.575) & (e <= 5)] * ( -12.79 + e[(e > -0.575) & (e <= 5)] * 0.711)) ar[e <= -0.575] = -20.772 / tan(radians(e[e <= -0.575])) # scalar hour_angle calculations else: e = 90.0 - zenith er = radians(e) if e > 85: ar = 0 elif e > 5: ar = 58.1 / tan(er) - 0.07 / tan(er)**3 + 0.000086 / tan(er)**5 elif e > -0.575: ar = 1735 + e * (103.4 + e * (-12.79 + e * 0.711)) else: ar = -20.772 / tan(er) elevation_noatmo = e atmo_refraction = ar / 3600 elevation = elevation_noatmo + atmo_refraction return elevation
def get_air_mass(zenith: FlexNum, method: str = None): """ air mass is a concept from the solar power world that accounts for the mass of air between a point on the earths surface and the sun as a function of zenith angle. This method implements the Kasten-Young formula as well as a simple spherical approximation https://www.osapublishing.org/ao/abstract.cfm?uri=ao-28-22-4735 :param method: Either "kasten-young" or "spherical". """ if method is None: method = "kasten-young" # default if method == "spherical": z_r = radians(zenith) r = CONSTANTS.earth_radius / CONSTANTS.atm_height return (r * (cos(z_r)**2) + (2 * r) + 1)**0.5 - (r * cos(z_r)) elif method == "kasten-young": z_r = radians(zenith) return 1.0 / (cos(z_r) + 0.50572 * (96.07995 - zenith)**(-1.6364))
def get_surf_norm_toa_irradiance(sun_surf_angle: FlexNum, sun_norm_irradiance: FlexNum): """ gets the irradiance intensity normal to a surface. If slope and aspect inputs were used this accounts for the angle of the earths surface. """ ssa_r = radians(sun_surf_angle) srf = cos( ssa_r ) * sun_norm_irradiance # a theta of zero results in full norm irradiance # set negative values to zero. if isinstance(srf, np.ndarray) and srf.shape: srf[srf <= 0] = 0 return srf else: return max([srf, 0.0])
def get_all_pos(drawable: drawable_types, car_length: float = None, car_width: float = None) \ -> List[Tuple[float, float]]: """ Returns all corner points in anti-clockwise order. :param drawable: The objects whose corner positions have to be calculated. :param car_length: Only used if the drawable represents a car. :param car_width: Only used if the drawable represents a car. :return: The corner positions of the given object. """ if isinstance(drawable, Rectangle): if car_length and car_width: right_bottom_pos: ndarray = asanyarray(drawable.get_xy()) orientation: float = radians(drawable.angle) length_vec: ndarray = CoordsHelp.pol2cart(car_length, orientation) width_vec: ndarray = CoordsHelp.pol2cart(car_width, orientation + pi / 2) positions = [tuple(right_bottom_pos), tuple(right_bottom_pos + length_vec), tuple(right_bottom_pos + length_vec + width_vec), tuple(right_bottom_pos + width_vec)] else: raise Exception("For calculating the points of a car the car length and width is needed.") else: raise Exception("Objects of type " + str(type(drawable)) + " are not supported.") return positions
def test_radians(self): assert_almost_equal(ncu.radians(180.0), np.pi) assert_almost_equal(ncu.radians(-90.0), -0.5 * np.pi)
def check_radians(self): assert_almost_equal(ncu.radians(180.0), pi) assert_almost_equal(ncu.degrees(-90.0), -0.5 * pi)
def get_app_long(true_long: FlexNum, ajc: FlexNum): """ calculates apparent longitude of the sun""" app_long = true_long - 0.00569 - 0.00478 * sin( radians(125.04 - 1934.136 * ajc)) return app_long
def get_azimuth(lat_r: FlexNum, declination: FlexNum, hour_angle: FlexNum, zenith: FlexNum) -> FlexNum: """ calculates solar azimuth angle. Function requires special treatment of different cases of combine vectorize inputs Case 1: all scalar inputs all scalar inputs are simple, and a scalar will be output. Case 2: Time constant, spatial variation (declination is scalar) lat_r: vector (x,y) declination: scalar (z) hour_angle: vector (x,y) zenith: vector (x,y) azimuth output vector (x,y) Case 3: Space constant, time variation (lat_r in radians is scalar) lat_r: scalar (x) declination: vector (y) hour_angle: vector (y) zenith: vector (y) azimuth output vector (y) case 4: Both space and time variation lat_r: vector (x,y,z) # duplicated across z axis declination: vector (z) # will be duplicated to dims (x,y,z) hour_angle: vector (x,y,z) # duplicated across z axis zenith: vector (x,y,z) # duplicated across z axis azimuth output vector (x,y,z) # duplicated across z axis In either case 2 or 3, all vector inputs must be identical shapes. """ lat = lat_r d = radians(declination) # always returns numpy arrays, even if 1x1 ha = radians(hour_angle) # always returns numpy arrays, even if 1x1 z = radians(zenith) # always returns numpy arrays, even if 1x1 # are the inputs vectorized in space? (lat_r will be a vector) if isinstance(lat_r, np.ndarray): if lat_r.shape: lat_vec = True else: lat_vec = False # ndarray with no dimensions is a scalar! else: lat_vec = False if isinstance(d, np.ndarray): if d.shape: time_vec = True else: time_vec = False # ndarray with no dimensions is a scalar! else: time_vec = False # Case 4: Both space and time variation if time_vec and lat_vec: # if both time and space are vectorized, we must cast declination(time) # to the third dimension. by duplicating for all lat/lon pairs. if len(lat_r.shape) == 3 and len(d.shape) == 1: if lat_r.shape[2] == d.shape[0]: d = np.repeat(d[np.newaxis, :], lat_r.shape[1], axis=0) d = np.repeat(d[np.newaxis, :], lat_r.shape[0], axis=0) az = ha * 0 ha_p = (ha > 0) # positive ha indices ha_n = (ha <= 0) # negative ha indices az_ha_p = arccos(((sin(lat[ha_p]) * cos(z[ha_p])) - sin(d[ha_p])) / (cos(lat[ha_p]) * sin(z[ha_p]))) az[ha_p] = (degrees(az_ha_p) + 180) % 360 az_ha_n = arccos(((sin(lat[ha_n]) * cos(z[ha_n])) - sin(d[ha_n])) / (cos(lat[ha_n]) * sin(z[ha_n]))) az[ha_n] = (540 - degrees(az_ha_n)) % 360 azimuth = az # Case 3: Space constant, time variation (lat_r in radians is scalar) elif time_vec and not lat_vec: az = ha * 0 ha_p = (ha > 0) # positive ha indices ha_n = (ha <= 0) # negative ha indices az_ha_p = arccos(((sin(lat) * cos(z[ha_p])) - sin(d[ha_p])) / (cos(lat) * sin(z[ha_p]))) az[ha_p] = (degrees(az_ha_p) + 180) % 360 az_ha_n = arccos(((sin(lat) * cos(z[ha_n])) - sin(d[ha_n])) / (cos(lat) * sin(z[ha_n]))) az[ha_n] = (540 - degrees(az_ha_n)) % 360 azimuth = az # Case 2: Time constant, spatial variation (declination is scalar) elif lat_vec and not time_vec: az = ha * 0 ha_p = (ha > 0) # positive ha indices ha_n = (ha <= 0) # negative ha indices az_ha_p = arccos(((sin(lat[ha_p]) * cos(z[ha_p])) - sin(d)) / (cos(lat[ha_p]) * sin(z[ha_p]))) az[ha_p] = (degrees(az_ha_p) + 180) % 360 az_ha_n = arccos(((sin(lat[ha_n]) * cos(z[ha_n])) - sin(d)) / (cos(lat[ha_n]) * sin(z[ha_n]))) az[ha_n] = (540 - degrees(az_ha_n)) % 360 azimuth = az # case 1, all inputs are scalar. else: if ha > 0: azimuth = (degrees( arccos(((sin(lat) * cos(z)) - sin(d)) / (cos(lat) * sin(z)))) + 180) % 360 else: azimuth = (540 - degrees( arccos(((sin(lat) * cos(z)) - sin(d)) / (cos(lat) * sin(z))))) % 360 return azimuth