/* Copyright 2000 Charles G. Wright
* This software may be distributed under the terms of the
* GNU General Public License.
*
* $Id: SOLlocation.java,v 1.1 2000-06-15 10:15:00-05 chuckles Exp chuckles $
*/
import java.math.*;
import java.util.*;
/**
This class represents a location on the surface of planet Earth.
* Its class variables define a position on Earth and its time zone.
* Methods for this class deal with solar time and the position
* of the sun in the sky at this location.
* At this location can be defined one or more orientations,
* defined by the SOLorientation object, of surfaces exposed to the sun.
* These are all contained the linked list "orientations" attached to
* this location object.
*/
public class SOLlocation implements CWmonitorable{
/** Values accessible using the getValue() method.*/
public static final String[] fields = {"Solar Altitude",
"Solar Azimuth"};
public static final int[] field_types = {UnitConverter.NOTHING,
UnitConverter.NOTHING};
// Constant:
private static final double FEET_PER_METER = 3.2808389850;
// locale
/** Latitude of the surface, in degrees. */
public double latitude;
/** Longitude of the surface, in degrees. */
public double longitude;
/** Longitude of the standard time zone in degrees. */
public int time_zone;
/** Elevation at this location, in meters. */
public double elevation;
/** Name of this location. */
public String name;
/** List of orientations associated with this location.*/
public Vector orientations;
public TMYdata tmystuff;
//-------------------- Constructor -----------------------------
/**
Create an SOLlocation object, which represents a location on the
* surface of planet Earth. The parameters defining the location
* are its:
- latitude, in degrees - North is positive
*
- longitude, in degrees - West is positive
*
- standard time zone, in degrees - West is positive
*
- elevation, in meters
*
*/
public SOLlocation(double latitude,
double longitude,
int time_zone,
double elevation,
String name){
this.latitude = latitude;
this.longitude = longitude;
this.time_zone = time_zone;
this.elevation = elevation;
this.name = name;
orientations = new Vector();
CWmonitoredElements.addElements(this);
}
//------------------- Methods ------------------------------------
//---- utility methods ------
static public double toRadians(double angle){
return(angle * 0.0174532925);
}
static public double toDegrees(double angle){
return(angle / 0.0174532925);
}
//-----------------------------
/** Returns the latitude of the location station. */
public double getLatitude(){
return latitude;
}
/** Returns the longitude of the location. */
public double getLongitude(){
return longitude;
}
/** Returns the time zone of the data location, in degrees
* (longitude of standard meridian). */
public int getTimeZone(){
return time_zone;
}
/** Returns the elevation of the location. */
public double getElevation(){
return (double)elevation;
}
public String getName(){
return(name);
}
/** Returns the list of monitorable fields. Part of the CWmonitorable
* interface.*/
public String[] getFields(){
return fields;
}
/** Returns the list of types of the monitorable fields. Part of the CWmonitorable
* interface. Used for unit conversions. Types are defined in class UnitConverter.*/
public int[] getFieldTypes(){
return(field_types);
}
//---------------------- Solar Declination ------------------------
/** Returns solar declination, in degrees (angle between
* ecliptic and equator), given a day number.
*/
public double getDeclination(int daynum){
return 23.45 * Math.sin(toRadians((360 * (284 + daynum))/ 365));
}
//------------------ Equation of time -----------------------------
/** Returns local solar time, in seconds, given the day number (in the year) and the
* local standard time (in seconds). */
public int getSolarTime(int daynum, int standard_time){
// convert daynum to radians
int solar_time;
double D = 2 * Math.PI * daynum / 365;
double eot = -1 *
((445 * Math.sin(D)) - (15.4 * Math.cos(D)) + (554 * Math.sin(2 * D)) + (217.0 * Math.cos(2 * D)));
solar_time = (int)(standard_time + (240.0 * (time_zone - longitude)) + eot);
//System.out.println("[getSolarTime]: standard_time = " + standard_time + "solar_time = " + solar_time);
return solar_time;
}
//------------------------- HMS to Sec ----------------------------
/** Returns time of day in seconds. Inputs are the hour of the day (0-23),
* the minute of the hour (0-59), and second of the minute (0-59).
*/
public int timeInSeconds(int hour, int minute, int second){
return (((hour) * 3600) + ((minute) * 60) + (second));
}
//------------------------ Hour Angle -----------------------------
/** Returns Hour Angle, in degrees. Input is the local solar time, in seconds.
*/
public double getHourAngle(int solar_time){
return(15.0 * ((solar_time / 3600.0) - 12.0));
}
//-------------------------- Solar Altitude ---------------------
/** Returns solar altitude, in degrees, given solar time and declination.
*/
public double getSolarAltitude(double decl, int solar_time){
double hourAngle = getHourAngle(solar_time);
// Calculate sine of altitude
// System.out.println("[getSolarAltitude]: decl="+decl+" hourAngle="+hourAngle);
double sinAlt = (Math.cos(toRadians(latitude))
* Math.cos(toRadians(decl))
* Math.cos(toRadians(hourAngle)))
+ (Math.sin(toRadians(latitude)) * Math.sin(toRadians(decl)));
double alt = Math.max(0.0, toDegrees(Math.asin(sinAlt)));
return alt;
}
/** Returns solar altitude, in degrees, given solar time and day number.
*/
public double getSolarAltitude(int daynum, int solar_time){
double decl = getDeclination(daynum);
return(getSolarAltitude(decl, solar_time));
}
//---------------------------- Solar Azimuth ------------------------
/** Returns solar azimuth, in degrees, given solar time and declination.
*/
public double getSolarAzimuth(double decl, int solar_time){
double alt = getSolarAltitude(decl, solar_time);
// Calculate cosine of solar azimuth
double cosAzi =
((Math.sin(toRadians(alt)) * Math.sin(toRadians(latitude))) - Math.sin(toRadians(decl)))
/ (Math.cos(toRadians(alt)) * Math.cos(toRadians(latitude)));
double result = toDegrees(Math.acos(cosAzi));
if (solar_time < 43200) result *= -1.0;
// System.out.println("[getSolarAzimuth]: decl="+decl+" alt="+alt+" latitude="+latitude+" azi="+result+" solar_time="+solar_time);
return(result);
}
/** Returns solar azimuth, in degrees, given solar time and day number.
*/
public double getSolarAzimuth(int daynum, int solar_time){
double decl = getDeclination(daynum);
return(getSolarAzimuth(decl, solar_time));
}
/** Provides access to this classes methods in common getValue() format. */
public double getValue(int month, int day, int hour, int fieldnum) {
double result = 0.0;
int daynum = TMYdata.dayOfYear(month, day);
int solar_time = getSolarTime(daynum, timeInSeconds(hour-1, 0, 0));
switch (fieldnum){
case 0: result = getSolarAltitude(daynum, solar_time); break;
case 1: result = getSolarAzimuth(daynum, solar_time); break;
}
return(result);
}
}