climate/solar_angles.cpp

00001 #include "complex.h"
00002 #include "solar_angles.h"
00003 
00004 
00005 
00006 SolarAngles::SolarAngles()
00007 {
00008 }
00009 
00010 SolarAngles::~SolarAngles()
00011 {
00012 }
00013 
00014 
00015 
00016 /******************function eq_time****************************/
00017 // PURPOSE: Compute equation of time (a measure of the earth's
00018 //          "wobble" thoughout the year).
00019 // EXPECTS: Day of year from Jan 1.
00020 // RETURNS: Equation of time in hours.
00021 // SOURCE:  Prof. Bill Murphy, Texas A&M U.
00022 //
00023 double SolarAngles::eq_time(short day_of_yr)
00024 {
00025     double rad = (2.0 * PI * day_of_yr) / 365.0;
00026     return(
00027         ( 0.5501*cos(rad) - 3.0195*cos(2*rad) - 0.0771*cos(3*rad)
00028         -7.3403*sin(rad) - 9.4583*sin(2*rad) - 0.3284*sin(3*rad) ) / 60.0
00029     );
00030 }
00031 
00032 /******************function solar_time*************************/
00033 // PURPOSE: Compute apparent solar time given local standard (not
00034 //          daylight savings) time and location.
00035 // EXPECTS: Local standard time, day of year, local standard
00036 //          meridian, and local longitude.
00037 // RETURNS: Local solar time in hours (military time)
00038 // SOURCE:  Duffie & Beckman.
00039 //
00040 double SolarAngles::solar_time(
00041     double std_time,    // Local standard time in decimal hours (e.g., 7:30 is 7.5)
00042     short day_of_yr,    // Day of year from Jan 1
00043     double std_meridian,    // Standard meridian (longitude) of local time zone (radians---e.g., Pacific timezone is 120 degrees times pi/180)
00044     double longitude    // Local longitude (radians west)
00045 )
00046 {
00047     return std_time + eq_time(day_of_yr) + HR_PER_RADIAN * (std_meridian-longitude);
00048 }
00049 
00050 
00051 /*****************function local_time*************************/
00052 // PURPOSE: Compute local standard (not daylight savings) time from
00053 //          apparent solar time and location.
00054 // EXPECTS: Apparent solar time, day of year, local standard
00055 //          meridian, and local longitude.
00056 // RETURNS: Local solar time in decimal hours.
00057 // SOURCE:  Duffie & Beckman.
00058 //
00059 double SolarAngles::local_time(
00060     double sol_time,    // Local solar time (decimal hours--7:30 is 7.5)
00061     short day_of_yr,    // Day of year from Jan 1
00062     double std_meridian,    // Standard meridian (longitude) of local time zone (radians---e.g., Pacific timezone is 120 times pi/180)
00063     double longitude    // Local longitude (radians west)
00064 )
00065 {
00066     return sol_time - eq_time(day_of_yr) - HR_PER_RADIAN * (std_meridian-longitude);
00067 }
00068 
00069 
00070 /*****************function declination***********************/
00071 // PURPOSE: Compute the solar declination angle (radians)
00072 // EXPECTS: Day of year from Jan 1.
00073 // RETURNS: Declination angle in radians.
00074 // SOURCE:  Duffie & Beckman.
00075 //
00076 double SolarAngles::declination(short day_of_yr)
00077 {
00078     return( 0.409280*sin(2.0*PI*(284+day_of_yr)/365) );
00079 }
00080 
00081 
00082 /******************function cos_incident******************/
00083 // PURPOSE: Compute cosine of angle of incidence of solar beam radiation
00084 //          on a surface
00085 // EXPECTS: latitude, surface slope,
00086 //          surface azimuth angle, solar time, day of year.
00087 // RETURNS: Cosine of angle of incidence (angle between solar beam and
00088 //          surface normal)
00089 //          !!! Note that this function is ignorant of the presence !!!
00090 //          !!! of the horizon.                                     !!!
00091 // SOURCE:  Duffie & Beckman.
00092 //
00093 double SolarAngles::cos_incident(
00094     double latitude,    // Latitude (radians north)
00095     double slope,       // Slope of surface relative to horizontal (radians)
00096     double az,      // Azimuth angle of surface rel. to South (E+, W-) (radians)
00097     double sol_time,    // Solar time (decimal hours)
00098     short day_of_yr     // Day of year from Jan 1
00099 )
00100 {
00101     double sindecl,cosdecl,sinlat,coslat,sinslope,cosslope,sinaz,cosaz,sinhr,coshr; // For efficiency
00102 
00103     double hr_ang = -(15.0 * PI_OVER_180)*(sol_time-12.0);  // morning +, afternoon -
00104 
00105     double decl = declination(day_of_yr);
00106 
00107     // Precalculate
00108     sindecl  = sin(decl);       cosdecl  = cos(decl);
00109     sinlat   = sin(latitude);   coslat   = cos(latitude);
00110     sinslope = sin(slope);      cosslope = cos(slope);
00111     sinaz    = sin(az);     cosaz    = cos(az);
00112     sinhr    = sin(hr_ang);     coshr    = cos(hr_ang);
00113 
00114     // The answer...
00115     double answer = sindecl*sinlat*cosslope
00116         -sindecl*coslat*sinslope*cosaz
00117         +cosdecl*coslat*cosslope*coshr
00118         +cosdecl*sinlat*sinslope*cosaz*coshr
00119         +cosdecl*sinslope*sinaz*sinhr;
00120 
00121     // Deal with the sun being below the horizon...
00122     return(answer<0.0 ? (double)0.0 : answer);
00123 }
00124 
00125 
00126 
00127 /******************function incident******************/
00128 // PURPOSE: Compute the angle of incidence of solar
00129 //          beam radiation on a surface.
00130 // EXPECTS: latitude, surface slope,
00131 //          surface azimuth angle, solar time, day of year.
00132 // RETURNS: Angle of incidence (angle between solar beam and
00133 //          surface normal) in radians.
00134 // SOURCE:  Duffie & Beckman.
00135 //
00136 double SolarAngles::incident(
00137     double latitude,    // Latitude (radians)
00138     double slope,       // Slope of surface relative to horizontal (radians)
00139     double az,      // Azimuth angle of surface rel. to South (radians, E+, W-)
00140     double sol_time,    // Solar time (decimal hours)
00141     short day_of_yr     // Day of year from Jan 1
00142 )
00143 {
00144     return acos(cos_incident(latitude, slope, az, sol_time, day_of_yr));
00145 }
00146 
00147 
00148 /*****************function zenith*****************************/
00149 // PURPOSE: Compute the solar zenith angle (radians, the angle between solar beam
00150 //          and the veritical.  This could be calculated as the incident
00151 //          angle on a horizontal surface, but is more efficient with
00152 //          this dedicated function.
00153 // EXPECTS: Day of year, latitude, solar time.
00154 // RETURNS: Zenith angle in radians.
00155 // SOURCE:  Duffy & Beckman.
00156 //
00157 double SolarAngles::zenith(
00158     short day_of_yr,    // day of year from Jan 1
00159     double latitude,    // latitude (radians)
00160     double sol_time     // solar time (decimal hours)
00161 )
00162 {
00163     double hr_ang = -(15.0 * PI_OVER_180)*(sol_time-12.0); // morning +, afternoon -
00164 
00165     double decl = declination(day_of_yr);
00166 
00167     return acos(sin(decl)*sin(latitude) + cos(decl)*cos(latitude)*cos(hr_ang));
00168 }
00169 
00170 
00171 
00172 /*****************function altitude*****************************/
00173 // PURPOSE: Compute the solar altitude angle (radians, angle between solar beam
00174 //          and the veritical.  This could be calculated as the incident
00175 //          angle on a vertical surface, but is more efficient with
00176 //          this dedicated function.
00177 // EXPECTS: Day of year, latitude, solar time.
00178 // RETURNS: Altitude angle (angle above horizon) in radians.
00179 // SOURCE:  Duffy & Beckman.
00180 //
00181 double SolarAngles::altitude(
00182     short day_of_yr,    // day of year from Jan 1
00183     double latitude,    // latitude (radians)
00184     double sol_time     // solar time (hours)
00185 )
00186 {
00187     return (90.0 * PI_OVER_180) - zenith(day_of_yr,latitude,sol_time);
00188 }
00189 
00190 
00191 
00192 /*****************function hr_sunrise*****************************/
00193 // PURPOSE: Compute the hour of sunrise.
00194 // EXPECTS: Declination angle, latitude.
00195 // RETURNS: Solar hour of sunrise.
00196 // SOURCE:  Duffy & Beckman.
00197 //
00198 double SolarAngles::hr_sunrise(
00199     short day_of_yr,    // solar declination angle (radians)
00200     double latitude     // latitude (radians)
00201 )
00202 {
00203     // Calculate hour angle of sunrise (converted to degrees)
00204     double hr_ang = acos( -tan(latitude)*tan(declination(day_of_yr)) ) / PI_OVER_180;
00205 
00206     // Convert hour angle to solar time
00207     return( (-hr_ang/15.0) + 12.0 );
00208 }
00209 
00210 
00211 
00212 /*****************function day_len********************************/
00213 // PURPOSE: Compute the length of a given day.
00214 // EXPECTS: Day of year, latitude.
00215 // RETURNS: Day length (hours).
00216 // SOURCE:  Duffy & Beckman.
00217 //
00218 double SolarAngles::day_len(
00219     short day_of_yr,    // Day of year from Jan 1
00220     double latitude     // latitude (radians)
00221 )
00222 {
00223     return 2.0 * acos( -tan(latitude)*tan(declination(day_of_yr)) ) / (15.0 * PI_OVER_180);
00224 }
00225 
00226 
00227 
00228 /*****************function day_of_yr********************************/
00229 // PURPOSE: Compute julian day of year.
00230 // EXPECTS: Month, day, year, all as integers.
00231 // RETURNS: Day length (hours).
00232 //
00233 // This ignores leap years but that's okay...the other functions always
00234 // assume a year has only 365 days.
00235 //
00236 short SolarAngles::day_of_yr(
00237     short month,        // Month of year (1-12)
00238     short day       // Day of month (1-31)
00239 )
00240 {
00241 
00242     // TODO:  Error checking on the 1-12 and 1-31...
00243 
00244     return days_thru_month[month-1] + day;
00245 }

GridLAB-DTM Version 1.0
An open-source project initiated by the US Department of Energy