/// <summary> /// Calculates the part of the day, using the given parameters /// </summary> /// <param name="observationTime">The date and time of observation</param> /// <param name="timezone">The observer's time zone</param> /// <param name="deltaUT1">The "delta UT1" parameter, retrieved from observation in seconds</param> /// <param name="deltaT">The "delta T" parameter, retrieved from observation in seconds</param> /// <param name="latitude">The observer's latitude in degrees (negative south of the Equator)</param> /// <param name="longitude">The observer's longitude in degrees (negative west of Greenwich)</param> /// <param name="elevation">The observer's elevation in meters</param> /// <param name="temperature">The annual average local temperature in degrees Celsius</param> /// <param name="pressure">The annual average local pressure in millibars</param> /// <param name="refraction">The atmospheric refraction at the horizon (at sunrise / sunset) in degrees</param> /// <returns>Returns the part of the day. In case of invalid input data, returns Unknown</returns> public static PartOfDay GetPartOfDay( DateTime observationTime, TimeSpan timezone, double deltaUT1, double?deltaT, double latitude, double longitude, double elevation, double temperature, double pressure, double?refraction) { var sunData = new SunData(observationTime, timezone.TotalHours, deltaUT1, deltaT, latitude, longitude, elevation, temperature, pressure, refraction); try { SunPositionCalculator.CalculateSunPosition(sunData); } catch (ArgumentException) { // Invalid input data - should return an Unknown value return(PartOfDay.Unknown); } var azimuth = sunData.AstronomicalTopocentricAzimuth; var zenithAngle = sunData.TopocentricZenithAngle; if (zenithAngle < 90) { return(PartOfDay.Day); } else if (zenithAngle >= 90 + TwilightElevation) { return(PartOfDay.Night); } else { if (azimuth > 180) { return(PartOfDay.Dawn); } else { return(PartOfDay.Dusk); } } }
private static void CalculateSunGeocentricEquatorialCoordinates(SunData data) { double[] correctionTerms = new double[Constants.TermsXCount]; data.JulianCentury = CalculateJulianCentury(data.JulianDay); data.JulianEphemerisDay = CalculateJulianEphemerisDay(data.JulianDay, data.DeltaT); data.JulianEphemerisCentury = CalculateJulianEphemerisCentury(data.JulianEphemerisDay); data.JulianEphemerisMillennium = CalculateJulianEphemerisMillennium(data.JulianEphemerisCentury); data.EarthHeliocentricLongitude = CalculateEarthHeliocentricLongitude(data.JulianEphemerisMillennium); data.EarthHeliocentricLatitude = CalculateEarthHeliocentricLatitude(data.JulianEphemerisMillennium); data.EarthRadiusVector = CalculateEarthRadiusVector(data.JulianEphemerisMillennium); data.GeocentricLongitude = CalculateGeocentricLongitude(data.EarthHeliocentricLongitude); data.GeocentricLatitude = CalculateGeocentricLatitude(data.EarthHeliocentricLatitude); correctionTerms[Constants.TermX0] = data.MeanElongationOfTheMoonFromTheSun = CalculateTheMeanElongationOfTheMoonFromTheSun(data.JulianEphemerisCentury); correctionTerms[Constants.TermX1] = data.MeanSunAnomaly = CalculateTheMeanSunAnomaly(data.JulianEphemerisCentury); correctionTerms[Constants.TermX2] = data.MeanMoonAnomaly = CalculateTheMeanMoonAnomaly(data.JulianEphemerisCentury); correctionTerms[Constants.TermX3] = data.MoonArgumentOfLatitude = CalculateTheMoonArgumentOfLatitude(data.JulianEphemerisCentury); correctionTerms[Constants.TermX4] = data.MoonAscendingNodeLongitude = CalculateTheMoonAscendingNodeLongitude(data.JulianEphemerisCentury); double longitudeNutation; double obliquityNutation; CalculateTheNutationInLongitudeAndObliquity(data.JulianEphemerisCentury, correctionTerms, out longitudeNutation, out obliquityNutation); data.LongitudeNutation = longitudeNutation; data.ObliquityNutation = obliquityNutation; data.MeanEclipticObliquity = CalculateTheMeanEclipticObliquity(data.JulianEphemerisMillennium); data.TrueEclipticObliquity = CalculateTheTrueEclipticObliquity(data.ObliquityNutation, data.MeanEclipticObliquity); data.AberrationCorrection = CalculateAberrationCorrection(data.EarthRadiusVector); data.ApparentSunLongitude = CalculateApparentSunLongitude(data.GeocentricLongitude, data.LongitudeNutation, data.AberrationCorrection); data.GreenwichMeanSiderealTime = CalculateTheGreenwichMeanSiderealTime(data.JulianDay, data.JulianCentury); data.GreenwichSiderealTime = CalculateTheGreenwichSiderealTime(data.GreenwichMeanSiderealTime, data.LongitudeNutation, data.TrueEclipticObliquity); data.SunRightAscension = CalculateTheSunGeocentricRightAscension(data.ApparentSunLongitude, data.TrueEclipticObliquity, data.GeocentricLatitude); data.SunDeclination = CalculateTheSunGeocentricDeclination(data.GeocentricLatitude, data.TrueEclipticObliquity, data.ApparentSunLongitude); }
/// <summary> /// Calculates the position of the Sun (zenith angle and azimuth) for a given SunData object /// </summary> /// <param name="data">An object holding information about the place and time of observation</param> public static void CalculateSunPosition(SunData data) { SunDataValidator.ValidateSunData(data); data.JulianDay = CalculateJulianDay(data.ObservationTime, data.Timezone, data.DeltaUT1); CalculateSunGeocentricEquatorialCoordinates(data); data.ObserverHourAngle = CalculateObserverHourAngle(data.GreenwichSiderealTime, data.Longitude, data.SunRightAscension); data.SunEquatorialHorizontalParallax = CalculateTheSunEquatorialHorizontalParallax(data.EarthRadiusVector); double rightAscensionParallax; double topocentricSunDeclination; CalculateRightAscensionParallaxAndTopocentricDeclination( data.Latitude, data.Elevation, data.SunEquatorialHorizontalParallax, data.ObserverHourAngle, data.SunDeclination, out rightAscensionParallax, out topocentricSunDeclination); data.RightAscensionParallax = rightAscensionParallax; data.TopocentricSunDeclination = topocentricSunDeclination; data.TopocentricSunRightAscension = CalculateTopocentricRightAscension(data.SunRightAscension, data.RightAscensionParallax); data.TopocentricLocalHourAngle = CalculateTopocentricHourAngle(data.ObserverHourAngle, data.RightAscensionParallax); data.TopocentricElevation = CalculateTopocentricElevationAngle(data.Latitude, data.TopocentricSunDeclination, data.TopocentricLocalHourAngle); data.RefractionCorrection = CalculateAtmosphericRefraction(data.Pressure, data.Temperature, data.Refraction.Value, data.TopocentricElevation); data.TopocentricElevationCorrected = CalculateTopocentricElevationAngleWithRefractionCorrection(data.TopocentricElevation, data.RefractionCorrection); data.TopocentricZenithAngle = CalculateTopocentricZenithAngle(data.TopocentricElevationCorrected); data.AstronomicalTopocentricAzimuth = CalculateAstronomicalTopocentricAzimuth(data.TopocentricLocalHourAngle, data.Latitude, data.TopocentricSunDeclination); data.TopocentricAzimuth = CalculateTopocentricAzimuth(data.AstronomicalTopocentricAzimuth); }
public static void ValidateSunData(SunData data) { if (Math.Abs(data.Timezone) > MaxAbsTimeZone) { throw new ArgumentException(string.Format( "The timezone is invalid. It should be between -{0} and {0}.", MaxAbsTimeZone)); } if (data.DeltaUT1 <= MinDeltaUT1 || data.DeltaUT1 >= MaxDeltaUT1) { throw new ArgumentException(string.Format( "The delta UT1 parameter is invalid. It should be between {0} and {1} seconds.", MinDeltaUT1, MaxDeltaUT1)); } if (data.DeltaT.HasValue && Math.Abs(data.DeltaT.Value) > MaxAbsDeltaT) { throw new ArgumentException(string.Format( "The delta T parameter is invalid. It should be between -{0} and {0} seconds.", MaxAbsDeltaT)); } if (Math.Abs(data.Latitude) > MaxAbsLatitude) { throw new ArgumentException(string.Format( "The latitude is invalid. It should be between -{0} and {0} degrees.", MaxAbsLatitude)); } if (Math.Abs(data.Longitude) > MaxAbsLongitude) { throw new ArgumentException(string.Format( "The longitude is invalid. It should be between -{0} and {0} degrees.", MaxAbsLongitude)); } if (data.Elevation < MinElevation) { throw new ArgumentException(string.Format( "The elevation is invalid. It should be at least {0} meters.", MinElevation)); } if (data.Temperature <= MinTemperature || data.Temperature >= MaxTemperature) { throw new ArgumentException(string.Format( "The temperature is invalid. It should be between {0} and {1} degrees Celsius.", MinTemperature, MaxTemperature)); } if (data.Pressure < MinAtmosphericPressure || data.Pressure > MaxAtmosphericPressure) { throw new ArgumentException(string.Format( "The atmospheric pressure is invalid. It should be between {0} and {1} millibars.", MinAtmosphericPressure, MaxAtmosphericPressure)); } if (data.Refraction.HasValue && data.Refraction > MaxRefraction) { throw new ArgumentException(string.Format( "The refraction at the horizon is invalid. It should be at most {0} degrees.", MaxRefraction)); } }