def test_string_to_frame(self): """ string_to_frame tests """ frame_ITRF_1 = orekit_utils.string_to_frame("ITRF") frame_ITRF_2 = FramesFactory.getITRF(IERSConventions.IERS_2010, True) self.assertTrue(frame_ITRF_1.equals(frame_ITRF_2)) frame_EME2000_1 = orekit_utils.string_to_frame("EME") frame_EME2000_2 = FramesFactory.getEME2000() frame_EME2000_3 = orekit_utils.string_to_frame("J2000") self.assertTrue(frame_EME2000_1.equals(frame_EME2000_2) and frame_EME2000_1.equals(frame_EME2000_3)) frame_TEME_1 = orekit_utils.string_to_frame("TEME") frame_TEME_2 = FramesFactory.getTEME() self.assertTrue(frame_TEME_1.equals(frame_TEME_2)) frame_Topo_1 = orekit_utils.string_to_frame("Topocentric", 5., 5., 5., "groundstation_1") earth = OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, Constants.WGS84_EARTH_FLATTENING, FramesFactory.getITRF(IERSConventions.IERS_2010, True)) location = GeodeticPoint(radians(5.), radians(5.), 5.) frame_Topo_2 = TopocentricFrame(earth, location, "groundstation_1") self.assertTrue(frame_Topo_1.getNadir().equals(frame_Topo_2.getNadir()))
def check_iot_in_range(propagator, grstn_latitude, grstn_longitude, grstn_altitude, time): """ Determines whether a satellite is above the horizon at a specific time in the reference frame of a ground station Args: propagator: orekit propagator object of overhead satellite grstn_latitude (float): (degrees) groudn station latitude grstn_longitude (float): (degrees) ground station longitude grstn_altitude (float): (meters) ground station altitude time (string): time at which the range check is to occur. """ ITRF = FramesFactory.getITRF(IERSConventions.IERS_2010, True) earth = OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, Constants.WGS84_EARTH_FLATTENING, ITRF) gs_location = GeodeticPoint(radians(grstn_latitude), radians(grstn_longitude), float(grstn_altitude)) gs_frame = TopocentricFrame(earth, gs_location, "ground station") pv = propagator.getPVCoordinates(time, propagator.getFrame()) elevation = degrees( gs_frame.getElevation(pv.getPosition(), propagator.getFrame(), time)) if elevation > 0: return True return False
def __init__(self, lat=48.58, longi=7.75, alt=142.0, loc="Strasbourg Frame", time_zone=1.0, gnomon_length=1.0): """ Initiate the Sundial instance. The default is a sundial located in Strasbourg. Parameters ---------- lat : float, optional Latitude of the murial sundial. The default is 48.58 (Strasbourg). longi : float, optional Longitude of the mural sundial. The default is 7.75 (Strasbourg). alt : float, optional Altitude of the mural sundial. The default is 142.0 (Strasbourg). loc : str, optional Name of the place where the murial sundial will stand. The default is "Strasbourg". time_zone : int, optional Time zone of the place where the murial sundial will stand . The default is 1 (Strasbourg). gnomon_length : float, optional Length of the gnomon of the murial Sundial. The default is 1.0. Returns ------- None. """ self.latitude = radians(lat) self.longitude = radians(longi) self.altitude = alt # utc = TimeScalesFactory.getUTC() # date = AbsoluteDate(year, month, 1, 0, 0, 0.0, utc) # self.date = date self.location = loc self.time_zone = time_zone # self.summer_time = summer_time self.gnomon_length = gnomon_length self.station_geo_point = GeodeticPoint(self.latitude, self.longitude, self.altitude) itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, True) earth = OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, Constants.WGS84_EARTH_FLATTENING, itrf) self.station_frame = TopocentricFrame(earth, self.station_geo_point, self.location) self.pv_sun = CelestialBodyFactory.getSun() self.pv_sun = PVCoordinatesProvider.cast_(self.pv_sun)
def _initialize_dipole_model(self, model): """Initializes dipole Model. This method uses the simplified dipole model implemented in DipoleModel.py Which needs to initialize the induced Magnetic density in the hysteresis rods. It also adds the hysteresis rods and bar magnets specified in the settings file to the satellite using the DipoleModel class. Args: model: dictionary holding information about hysteresis rods and bar magnets of the satellite """ for key, hyst in model['Hysteresis'].items(): direction = np.array([float(x) for x in hyst['dir'].split(" ")]) self.dipoleM.addHysteresis(direction, hyst['vol'], hyst['Hc'], hyst['Bs'], hyst['Br']) # initialize values for Hysteresis (need B-field @ initial position) spacecraft_state = self.state_observer.spacecraftState self.inertial2Sat = spacecraft_state.getAttitude().getRotation() self.satPos_i = spacecraft_state.getPVCoordinates().getPosition() gP = self.earth.transform(self.satPos_i, self.in_frame, self.in_date) topoframe = TopocentricFrame(self.earth, gP, 'ENU') topo2inertial = topoframe.getTransformTo(self.in_frame, self.in_date) lat = gP.getLatitude() lon = gP.getLongitude() alt = gP.getAltitude() / 1e3 # Mag. Field needs degrees and [km] # get B-field in geodetic system (X:East, Y:North, Z:Nadir) B_geo = FileDataHandler.mag_field_model.calculateField( degrees(lat), degrees(lon), alt).getFieldVector() # convert geodetic frame to inertial and from [nT] to [T] B_i = topo2inertial.transformVector(Vector3D(1e-9, B_geo)) B_b = self.inertial2Sat.applyTo(B_i) B_field = np.array([B_b.x, B_b.y, B_b.z]) self.dipoleM.initializeHysteresisModel(B_field) # add bar magnets to satellite for key, bar in model['BarMagnet'].items(): direction = np.array([float(x) for x in bar['dir'].split(" ")]) self.dipoleM.addBarMagnet(direction, bar['m'])
def get_station(longi, lat, name, planet=OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, Constants.WGS84_EARTH_FLATTENING, FramesFactory.getITRF(IERSConventions.IERS_2010, True))): """ Returns the wanted Topocentric Frame computed thanks to its coordinates Parameters ---------- longi : float longitude of the wanted Topocentric Frame. lat : float Latitude of the wanted Topocentric Frame. name : str Wanted name for the Topocentric Frame. planet : OnesAxisEllipsoid, optional Planet where the Topocentric Frame should be associated to. The default is our planet, the Earth. Returns ------- station_frame : Topocentric Frame Wanted Topocentric Frame. """ longitude = radians(longi) latitude = radians(lat) station = GeodeticPoint(latitude, longitude, 0.0) station_frame = TopocentricFrame(planet, station, name) return station_frame
def orekit_station_by_geodetic_point(body, station_name, pos, displacements=[]): frame_history = FramesFactory.findEOP(body.getBodyFrame()) topo_frame = TopocentricFrame(body, pos, station_name) ground_station = GroundStation(topo_frame, frame_history, displacements) return ground_station
def _compute_magnetic_torque(self, curr_date): """Compute magnetic torque if magnetic model provided. This method converts the satellite's position into Longitude, Latitude, Altitude representation to determine the geo. magnetic field at that position and then computes based on those values the magnetic torque. Args: curr_date: Absolute date of current epoch Returns: Vector3D: magnetic torque at satellite position in satellite frame along principal axes """ if self._to_add[1]: gP = self.earth.transform(self.satPos_i, self.in_frame, curr_date) topoframe = TopocentricFrame(self.earth, gP, 'ENU') topo2inertial = topoframe.getTransformTo(self.in_frame, curr_date) lat = gP.getLatitude() lon = gP.getLongitude() alt = gP.getAltitude() / 1e3 # Mag. Field needs degrees and [km] # get B-field in geodetic system (X:East, Y:North, Z:Nadir) B_geo = FileDataHandler.mag_field_model.calculateField( degrees(lat), degrees(lon), alt).getFieldVector() # convert geodetic frame to inertial and from [nT] to [T] B_i = topo2inertial.transformVector(Vector3D(1e-9, B_geo)) B_b = self.inertial2Sat.applyTo(B_i) B_b = np.array([B_b.x, B_b.y, B_b.z]) dipoleVector = self.dipoleM.getDipoleVectors(B_b) torque = np.sum(np.cross(dipoleVector, B_b), axis=0) self._mTorque = Vector3D(float(torque[0]), float(torque[1]), float(torque[2])) else: self._mTorque = Vector3D.ZERO
def orekit_station_by_coords(body, station_name, lat, lon, alt, displacements=[]): pos = GeodeticPoint(lat, lon, alt) frame_history = FramesFactory.findEOP(body.getBodyFrame()) topo_frame = TopocentricFrame(body, pos, station_name) displacements = [] ground_station = GroundStation(topo_frame, frame_history, displacements) return ground_station
def _calculate_magnetic_field(self, oDate): """Calculate the magnetic field at position of the spacecraft (Internal Method).""" space_state = self._propagator_num.getInitialState() satPos = space_state.getPVCoordinates().getPosition() inertial2Sat = space_state.getAttitude().getRotation() frame = space_state.getFrame() gP = self._earth.transform(satPos, frame, oDate) topoframe = TopocentricFrame(self._earth, gP, 'ENU') topo2inertial = topoframe.getTransformTo(frame, oDate) lat = gP.getLatitude() lon = gP.getLongitude() alt = gP.getAltitude() / 1e3 # Mag. Field needs degrees and [km] # get B-field in geodetic system (X:East, Y:North, Z:Nadir) B_geo = FileDataHandler.mag_field_model.calculateField( degrees(lat), degrees(lon), alt).getFieldVector() # convert geodetic frame to inertial and from [nT] to [T] B_i = topo2inertial.transformVector(Vector3D(1e-9, B_geo)) return inertial2Sat.applyTo(B_i)
def string_to_frame(frame_name, latitude=0., longitude=0., altitude=0., name=""): """ Given a string with the following defined options below, the fucntion returns the orekit associated frame object. Args: frame_name: (string) with the following options... "ITRF" ... returns the ITRF (geocentric and rotates with earth for use for points near or on earth's surface--very accurate) "EME2000"/"J2000" ... Earth Centered Inertial (ECI) Frame the frame is fixed to the celetial grid and doesn't rotate with the earth "TEME" ... another ECI frame, but specifically used by NORAD TLEs "Topocentric" ... very specific frame defined at an coordinate on or near the surface of an object (here we define earth). Rotates with body defined by ITRF frame (can think as an offset of ITRF frame for things like ground stations) latitude, longitude: (float in degrees) for defining the topocentric frame origin--not required otherwise altitude: (float in meters) for defining the topocentric frame origin--not required otherwise name: (string) for defining the topocentric frame origin label--not required otherwise Returns: orekit frame object OR -1 if undefined string """ if (frame_name == utils.ITRF): return FramesFactory.getITRF(IERSConventions.IERS_2010, True) elif ((frame_name == utils.EME) or (frame_name == "J2000")): return FramesFactory.getEME2000() elif (frame_name == utils.TEME): return FramesFactory.getTEME() elif (frame_name == utils.TOPOCENTRIC): earth = OneAxisEllipsoid( Constants.WGS84_EARTH_EQUATORIAL_RADIUS, Constants.WGS84_EARTH_FLATTENING, FramesFactory.getITRF(IERSConventions.IERS_2010, True)) location = GeodeticPoint(radians(latitude), radians(longitude), float(altitude)) return TopocentricFrame(earth, location, name) else: return -1
############################################################################## ############################################################################## # Create the GCRF (ECI) and ITRF (ECEF) Frames GCRF_Frame = FramesFactory.getGCRF() J2000_Frame = FramesFactory.getEME2000() ITRF_Frame = FramesFactory.getITRF(IERSConventions.IERS_2010, True) earth = OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, Constants.WGS84_EARTH_FLATTENING, ITRF_Frame) # CREATE THE GROUND STATION # First create the Topocentric Frame station_coord = GeodeticPoint(radians(40), radians(-110), 2000.0) station_frame = TopocentricFrame(earth, station_coord, 'MyGndStation') # Now create the Ground station itself and the satellite object GndStation = GroundStation(station_frame) Sat = ObservableSatellite(1) # create the observable satellite object, name it 1 as default # SET THE DAY OF THE OBSERVATIONS yr_mo_day = (2012, 8, 20) utc = TimeScalesFactory.getUTC() # OPEN THE CSV FILE CONTAINING THE OBSERVATIONS data = open('Observations.csv') csv_data = csv.reader(data) data_lines = list(csv_data)
def field_of_view_detector(sat_propagator, latitude, longitude, altitude, start_time, degree_fov, duration=0, stepsize=1): """ Determines if a ground point will be within the field of view (defined as a circular feild of view of however many degrees from the sat) for a specific sat_propagator that should include an integrated attitude provider. Args: sat_propagator: orekit propagator object that should include at the least an internal orbit and attitude law (this law should either be ground pointing or nadir pointing) latitude, longitude, altitude: (floats in degrees and meters) coordinate point to be checked if within feild of view of camera start_time: orekit absolute time object (start time of checking) degree_fov: (float in degrees) the full degree field of view of the camera/instrument duration: (int in seconds) duration to check after start time, if not inputed will default to zero, and function will return a boolean for the state at only the start time stepsize: (int >= 1) size in seconds between each prediction (smallest step is 1 second) Returns: duration=0: bool value that tells if the ground point is in the feild of view at the start time else: array of structure [[time_start, end_time], ... ,[start_end, end_time]] that contains the entry/exit times of the feild of view prediction. """ earth = OneAxisEllipsoid( Constants.WGS84_EARTH_EQUATORIAL_RADIUS, Constants.WGS84_EARTH_FLATTENING, FramesFactory.getITRF(IERSConventions.IERS_2010, True)) ground_target = GeodeticPoint(radians(float(latitude)), radians(float(longitude)), float(altitude)) ground_target_frame = TopocentricFrame(earth, ground_target, "ground_target") circular_fov = CircularFieldOfView(Vector3D.PLUS_K, radians(float(degree_fov / 2)), radians(0.)) fov_detector = FieldOfViewDetector( ground_target_frame, circular_fov).withHandler(ContinueOnEvent()) elevation_detector = ElevationDetector( ground_target_frame).withConstantElevation(0.0).withHandler( ContinueOnEvent()) if (duration <= 0): return ( (fov_detector.g(sat_propagator.propagate(start_time)) < 0) and (elevation_detector.g(sat_propagator.propagate(start_time)) > 0)) time_within_fov = [] time_array = [ start_time.shiftedBy(float(time)) for time in np.arange(0, duration, stepsize) ] entry_empty = True entry_time = 0 for time in time_array: within_fov = ( (fov_detector.g(sat_propagator.propagate(time)) < 0) and (elevation_detector.g(sat_propagator.propagate(time)) > 0)) if (entry_empty and within_fov): entry_time = time entry_empty = False elif ((not entry_empty) and (not within_fov)): time_within_fov.append([entry_time, time]) entry_empty = True entry_time = 0 elif ((not entry_empty) and (time == time_array[-1])): time_within_fov.append([entry_time, time]) return time_within_fov
def get_ground_passes(propagator, grstn_latitude, grstn_longitude, grstn_altitude, start, stop, ploting_param=False): """ Gets all passes for a specific satellite occuring during the given range. Pass is defined as 10° above the horizon, below this is unusable (for our purposes) Args: propagator ([any] OreKit orbit propagator): propagator, TLEPropagator or KeplerianPropagator for the satellite in question grstn_latitude (Float): latitude of the ground station in degrees grstn_longitude (Float): longitude of the ground station in degrees start (OreKit AbsoluteDate): the beginning of the desired time interval stop (OreKit AbsoluteDate): the end of the desired time interval plotting_param (Boolean): do not use, used by potential plotter Return value: A dictionary with {"start":[OreKit AbsoluteDate], "stop":[OreKit AbsoluteDate], "duration": (seconds) [float]} Alternatively, returns a queue of times in reference to the start time for ease of plotting ground passes. Notes: use absolutedate_to_datetime() to convert from AbsoluteDate TODO: add ElevationMask around ground station to deal with topography blocking communications """ ITRF = FramesFactory.getITRF(IERSConventions.IERS_2010, True) earth = OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, Constants.WGS84_EARTH_FLATTENING, ITRF) gs_location = GeodeticPoint(radians(grstn_latitude), radians(grstn_longitude), float(grstn_altitude)) gs_frame = TopocentricFrame(earth, gs_location, "ground station") elevation_detector = ElevationDetector(gs_frame).withConstantElevation( 0.0).withHandler(ContinueOnEvent()) logger = EventsLogger() logged_detector = logger.monitorDetector(elevation_detector) propagator.addEventDetector(logged_detector) state = propagator.propagate(start, stop) events = logger.getLoggedEvents() pass_start_time = None result = [] if not ploting_param: for event in logger.getLoggedEvents(): if event.isIncreasing(): pass_start_time = event.getState().getDate() else: stop_time = event.getState().getDate() result.append({ "start": pass_start_time, "stop": stop_time, "duration": stop_time.durationFrom(start) / 60 }) pass_start_time = None else: result = queue.Queue(0) for event in logger.getLoggedEvents(): if event.isIncreasing(): pass_start_time = event.getState().getDate() else: pass_stop_time = event.getState().getDate() result.put(pass_start_time.durationFrom( start)) # start is the initial time of interest result.put(pass_stop_time.durationFrom(start)) pass_start_time = None return result
def parseStationData(stationFile, stationEccFile, epoch): """ Parses the two files containing the coordinates of laser ranging ground stations :param stationFile: str, path to the station coordinates file :param stationEccFile: str, path to the station eccentricities file :param epoch: datetime object. used to compute the station position based on the velocity data :return: a pandas DataFrame containing: - index: str, 8-digit id of the ground station - columns: - CODE: int, 4-digit station code (including possibly several receivers) - PT: str, usually A - Latitude: float, station latitude in degrees - Longitude: float, station longitude in degrees - Altitude: float, station altitude above WGS84 reference sea level in meters - OrekitGroundStation: Orekit GroundStation object """ from org.orekit.utils import IERSConventions from org.orekit.frames import FramesFactory itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, True) from org.orekit.models.earth import ReferenceEllipsoid wgs84ellipsoid = ReferenceEllipsoid.getWgs84(itrf) from org.hipparchus.geometry.euclidean.threed import Vector3D from org.orekit.frames import TopocentricFrame from org.orekit.estimation.measurements import GroundStation from numpy import rad2deg from orekit.pyhelpers import datetime_to_absolutedate import pandas as pd stationData = pd.DataFrame(columns=[ 'CODE', 'PT', 'Latitude', 'Longitude', 'Altitude', 'OrekitGroundStation' ]) stationxyz = pd.DataFrame(columns=[ 'CODE', 'PT', 'TYPE', 'SOLN', 'REF_EPOCH', 'UNIT', 'S', 'ESTIMATED_VALUE', 'STD_DEV' ]) # First run on the file to initialize the ground stations using the approximate lat/lon/alt data with open(stationFile) as f: line = '' while not line.startswith('+SITE/ID'): line = f.readline() line = f.readline() # Skipping +SITE/ID line = f.readline() # Skipping column header while not line.startswith('-SITE/ID'): stationCode = int(line[1:5]) pt = line[7] l = line[44:] #lon_deg = float(l[0:3]) + float(l[3:6]) / 60.0 + float(l[6:11]) / 60.0 / 60.0 #lat_deg = float(l[12:15]) + float(l[15:18]) / 60.0 + float(l[18:23]) / 60.0 / 60.0 #alt_m = float(l[24:31]) station_id = l[36:44] #geodeticPoint = GeodeticPoint(float(deg2rad(lat_deg)), float(deg2rad(lon_deg)), alt_m) #topocentricFrame = TopocentricFrame(wgs84ellipsoid, geodeticPoint, str(station_id)) #groundStation = GroundStation(topocentricFrame) #stationData.loc[station_id] = [stationCode, pt, lat_deg, lon_deg, alt_m, groundStation] stationData.loc[station_id, ['CODE', 'PT']] = [ stationCode, pt ] # Only filling the station code and id line = f.readline() # Parsing accurate ground station position from XYZ while not line.startswith('+SOLUTION/ESTIMATE'): line = f.readline() line = f.readline() # Skipping +SOLUTION/ESTIMATE line = f.readline() # Skipping column header while not line.startswith('-SOLUTION/ESTIMATE'): index = int(line[1:6]) lineType = line[7:11] code = int(line[14:18]) pt = line[20:21] soln = int(line[22:26]) refEpochStr = line[27:39] refEpoch = epochStringToDatetime(refEpochStr) unit = line[40:44] s = int(line[45:46]) estimatedValue = float(line[47:68]) stdDev = float(line[69:80]) stationxyz.loc[index] = [ code, pt, lineType, soln, refEpoch, unit, s, estimatedValue, stdDev ] line = f.readline() pivotTable = stationxyz.pivot_table(index=['CODE', 'PT'], columns=['TYPE'], values=['ESTIMATED_VALUE', 'STD_DEV']) stationxyz.set_index(['CODE', 'PT'], inplace=True) # Reading the eccentricities data stationEcc = pd.DataFrame(columns=[ 'SITE', 'PT', 'SOLN', 'T', 'DATA_START', 'DATA_END', 'XYZ', 'X', 'Y', 'Z' ]) with open(stationEccFile) as f: line = '' while not line.startswith('+SITE/ECCENTRICITY'): line = f.readline() line = f.readline() # skipping +SITE/ECCENTRICITY line = f.readline() # skipping table header while not line.startswith('-SITE/ECCENTRICITY'): site = int(line[0:5]) pt = line[7:8] soln = int(line[9:13]) t = line[14:15] dataStartStr = line[16:28] dataStart = epochStringToDatetime(dataStartStr) dataEndStr = line[29:41] dataEnd = epochStringToDatetime(dataEndStr) xyz = line[42:45] x = float(line[46:54]) y = float(line[55:63]) z = float(line[64:72]) stationId = line[80:88] stationEcc.loc[stationId] = [ site, pt, soln, t, dataStart, dataEnd, xyz, x, y, z ] line = f.readline() stationEcc.index.name = 'CDP-SOD' # A loop is needed here to create the Orekit objects for stationId, staData in stationData.iterrows(): indexTuple = (staData['CODE'], staData['PT']) refEpoch = stationxyz.loc[indexTuple, 'REF_EPOCH'][0] yearsSinceEpoch = (epoch - refEpoch).days / 365.25 pv = pivotTable.loc[indexTuple]['ESTIMATED_VALUE'] x = float(pv['STAX'] + # Station coordinates pv['VELX'] * yearsSinceEpoch + # Station displacements stationEcc.loc[stationId]['X']) # Station eccentricities y = float(pv['STAY'] + pv['VELY'] * yearsSinceEpoch + stationEcc.loc[stationId]['Y']) z = float(pv['STAZ'] + pv['VELZ'] * yearsSinceEpoch + stationEcc.loc[stationId]['Z']) station_xyz_m = Vector3D(x, y, z) geodeticPoint = wgs84ellipsoid.transform( station_xyz_m, itrf, datetime_to_absolutedate(epoch)) lon_deg = rad2deg(geodeticPoint.getLongitude()) lat_deg = rad2deg(geodeticPoint.getLatitude()) alt_m = geodeticPoint.getAltitude() topocentricFrame = TopocentricFrame(wgs84ellipsoid, geodeticPoint, str(indexTuple[0])) groundStation = GroundStation(topocentricFrame) stationData.loc[stationId] = [ staData['CODE'], staData['PT'], lat_deg, lon_deg, alt_m, groundStation ] return stationData
class Sundial: def __init__(self, lat=48.58, longi=7.75, alt=142.0, loc="Strasbourg Frame", time_zone=1.0, gnomon_length=1.0): """ Initiate the Sundial instance. The default is a sundial located in Strasbourg. Parameters ---------- lat : float, optional Latitude of the murial sundial. The default is 48.58 (Strasbourg). longi : float, optional Longitude of the mural sundial. The default is 7.75 (Strasbourg). alt : float, optional Altitude of the mural sundial. The default is 142.0 (Strasbourg). loc : str, optional Name of the place where the murial sundial will stand. The default is "Strasbourg". time_zone : int, optional Time zone of the place where the murial sundial will stand . The default is 1 (Strasbourg). gnomon_length : float, optional Length of the gnomon of the murial Sundial. The default is 1.0. Returns ------- None. """ self.latitude = radians(lat) self.longitude = radians(longi) self.altitude = alt # utc = TimeScalesFactory.getUTC() # date = AbsoluteDate(year, month, 1, 0, 0, 0.0, utc) # self.date = date self.location = loc self.time_zone = time_zone # self.summer_time = summer_time self.gnomon_length = gnomon_length self.station_geo_point = GeodeticPoint(self.latitude, self.longitude, self.altitude) itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, True) earth = OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, Constants.WGS84_EARTH_FLATTENING, itrf) self.station_frame = TopocentricFrame(earth, self.station_geo_point, self.location) self.pv_sun = CelestialBodyFactory.getSun() self.pv_sun = PVCoordinatesProvider.cast_(self.pv_sun) def get_lat(self): """ Getter for the latitude of the sundial. Returns ------- flaot Latitude of the sundial. """ return self.latitude def get_long(self): """ Getter for the longitude of the sundial. Returns ------- float Longitude of the sundial. """ return self.longitude def get_alt(self): """ Getter for the altitude of the sundial. Returns ------- float Altitude of the sundial. """ return self.altitude def get_station_geo_point(self): """ Getter for the Geodetic Point of the sundial station on Earth. Returns ------- Geodetic Point Geodetic Point of the sundial station on Earth. """ return self.station_geo_point def get_station_frame(self): """ Getter of the sundial station frame. Returns ------- Topocentric Frame Sundial station frame. """ return self.station_frame def get_sun_pos_station_frame(self, utc_date): """ Returns the position of the Sun in the sundial station frame. Parameters ---------- utc_date : Absolute Date Date (in UTC) when the position of the sun should be computed. Returns ------- Vector3D Position vector of the Sun in the sundial station frame. """ j2000 = FramesFactory.getEME2000() sun_pos_j2000 = self.pv_sun.getPVCoordinates(utc_date, j2000).getPosition() j2000_to_topocentric = j2000.getTransformTo(self.station_frame, utc_date) sun_pos_topo = j2000_to_topocentric.transformPosition(sun_pos_j2000) return sun_pos_topo def get_sun_elevation(self, utc_date): """ Returns the elevation (in radians) of the Sun at a given date in the sundial reference frame. Parameters ---------- utc_date : Absolute Date Date in UTC. Returns ------- float Elevation (in radians) of the Sun. """ return self.station_frame.getElevation( self.get_sun_pos_station_frame(utc_date), self.station_frame, utc_date) def get_sun_elevation_degrees(self, utc_date): """ Returns the elevation (in degrees) of the Sun at a given date in the sundial reference frame. Parameters ---------- utc_date : Absolute Date Date in UTC. Returns ------- float Elevation (in radians) of the Sun. """ return degrees( self.station_frame.getElevation( self.get_sun_pos_station_frame(utc_date), self.station_frame, utc_date)) def get_gnomon_shadow_length(self, utc_date): """ Returns the length of the gnomon shadow. Parameters ---------- utc_date : Absolute Date Date (in UTC) when the length should be computed. Returns ------- float Length of the gnomon shadow. """ return self.gnomon_length / tan(self.get_sun_elevation(utc_date)) def get_gnomon_shadow_azimtuh(self, utc_date): """ Returns the azimuth angle (in radians) of the gnomon shadow. Parameters ---------- utc_date : Absolute Date Date (in UTC) when the azimuth angle should be computed. Returns ------- float Azimuth (in radians) of the gnonom shadow. """ return self.station_frame.getAzimuth( self.get_sun_pos_station_frame(utc_date), self.station_frame, utc_date) def get_gnomon_shadow_azimtuh_degrees(self, utc_date): """ Returns the azimuth angle (in radians) of the gnomon shadow. Parameters ---------- utc_date : Absolute Date Date (in UTC) when the azimuth angle should be computed. Returns ------- float Azimuth (in degrees) of the gnonom shadow. """ return degrees( self.station_frame.getAzimuth( self.get_sun_pos_station_frame(utc_date), self.station_frame, utc_date)) def get_gnomon_shadow_angle_wrtx(self, utc_date): """ Returns the angle (in radians) between the gnomon shadow and the X axis (the East). Parameters ---------- utc_date : Absolute Date Date when the angle should be computed. Returns ------- float Angle (in radians) between the gnomon shadow and the X axis (the East).. """ return 3 * pi / 2 - self.get_gnomon_shadow_azimtuh(utc_date) def get_gnomon_shadow_angle_wrtx_degrees(self, utc_date): """ Returns the angle (in degrees) between the gnomon shadow and the X axis (the East). Parameters ---------- utc_date : Absolute Date Date when the angle should be computed. Returns ------- float Angle (in degrees) between the gnomon shadow and the X axis (the East). """ return degrees(3 * pi / 2 - self.get_gnomon_shadow_azimtuh(utc_date)) def get_sun_max_elevation(self, year, month, day): """ Returns the maximum elevation angle (in radians) of the Sun (that is the zenith) a given day. Parameters ---------- year : int Year. month : int Month. day : int Day. Returns ------- current_ele0 : TYPE DESCRIPTION. currentutc_date : TYPE DESCRIPTION. """ currentutc_date = AbsoluteDate(year, month, day, 0, 0, 0.0, TimeScalesFactory.getUTC()) is_max_elevation = False time_step = 10.0 current_ele0 = self.get_sun_elevation(currentutc_date) current_ele1 = self.get_sun_elevation( currentutc_date.shiftedBy(time_step)) if current_ele0 > current_ele1: is_max_elevation = True while not is_max_elevation: current_ele0 = current_ele1 current_ele1 = self.get_sun_elevation( currentutc_date.shiftedBy(time_step)) if current_ele0 > current_ele1: is_max_elevation = True currentutc_date.shiftedBy(-time_step) currentutc_date = currentutc_date.shiftedBy(time_step) return current_ele0, currentutc_date def get_zenith_local_time(self, year, month, day, summer_time): _, zenith_utc = self.get_sun_max_elevation(year, month, day) return utc2local_time(zenith_utc, self.time_zone, summer_time) def get_zenith_utc(self, year, month, day): _, zenith_utc = self.get_sun_max_elevation(year, month, day) return zenith_utc def get_gnomon_shadow_angle_zenith(self, year, month, day): """ Returns the angle (in radians) between the gnomon shadow and the X axis (the East) at the zenith. Parameters ---------- year : int Year. month : int Month. day : TYPE Day. Returns ------- TYPE Angle (in radians) between the gnomon shadow and the X axis (the East) at the zenith. """ utc_date = self.get_zenith_utc(year, month, day) return self.get_gnomon_shadow_angle_wrtx(utc_date) def get_all_gnomon_shadow_angle_degrees(self, year, month, day): """ Returns all (each hour) angles (in degrees) between the gnomon shadow and the X axis (the East) beginning with the zenith angle. Parameters ---------- year : int Year. month : int Month. day : int Day. Returns ------- gnomon_shadow_angles : list of float All (each hour) angles (in degrees) between the gnomon shadow and the X axis (the East) beginning beginning with the zenith angle. """ zenith_utc = self.get_zenith_utc(year, month, day) gnomon_shadow_angles = [ degrees(self.get_gnomon_shadow_angle_zenith(year, month, day)) ] assert self.get_gnomon_shadow_angle_zenith(year, month, day) == \ self.get_gnomon_shadow_angle_wrtx(zenith_utc) for i in range(1, 12): gnomon_shadow_angles.append( self.get_gnomon_shadow_angle_wrtx_degrees( zenith_utc.shiftedBy(i * 3600.0))) return gnomon_shadow_angles def get_all_gnomon_shadow_angle(self, year, month, day): """ Returns all (each hour) angles (in radians) between the gnomon shadow and the X axis (the East) beginning with the zenith angle. Parameters ---------- year : int Year. month : int Month. day : int Day. Returns ------- gnomon_shadow_angles : list of float All (each hour) angles (in radians) between the gnomon shadow and the X axis (the East) beginning beginning with the zenith angle. """ zenith_utc = self.get_zenith_utc(year, month, day) gnomon_shadow_angles = [ self.get_gnomon_shadow_angle_zenith(year, month, day) ] assert self.get_gnomon_shadow_angle_zenith(year, month, day) == \ self.get_gnomon_shadow_angle_wrtx(zenith_utc) for i in range(1, 12): gnomon_shadow_angles.append( self.get_gnomon_shadow_angle_wrtx( zenith_utc.shiftedBy(i * 3600.0))) return gnomon_shadow_angles