00001
00006 #include <stdlib.h>
00007 #include <stdio.h>
00008 #include <errno.h>
00009 #include <math.h>
00010
00011 #include "climate.h"
00012 #include "solar_angles.h"
00013
00014 #define RAD(x) (x*PI)/180
00015
00016 double std_meridians[] = {75,90,105,120,135,150};
00017 double surface_angles[8] = {0,45,-45,90,-90,135,-135,180};
00018
00028 int tmy2_reader::open(const char *file){
00029 char *newname = gl_findfile((char *)file, NULL, 2);
00030 if (newname==NULL)
00031 return 0;
00032 fp = fopen(newname, "r");
00033
00034 if(fp == NULL){
00035 return 0;
00036 }
00037
00038
00039 fgets(buf,500,fp);
00040 sscanf(buf,"%*s %s %s %d %*s %d %d %*s %d %d",data_city,data_state,&tz_offset,&lat_degrees,&lat_minutes,&long_degrees,&long_minutes);
00041 return 4;
00042 }
00043
00044 int tmy2_reader::next(){
00045
00046 char *val;
00047 val = fgets(buf,500,fp);
00048
00049 if(val != NULL)
00050 return 1;
00051 else
00052 return 0;
00053 }
00054
00055 int tmy2_reader::header_info(char* city, char* state, int* degrees, int* minutes, int* long_deg, int* long_min){
00056 strcpy(city,data_city);
00057 strcpy(state,data_state);
00058 *degrees = lat_degrees;
00059 *minutes = lat_minutes;
00060 *long_deg = long_degrees;
00061 *long_min = long_minutes;
00062 return 1;
00063 }
00064
00065 int tmy2_reader::read_data(double *dnr, double *dhr, double *tdb, double *rh, int* month, int* day, int* hour){
00066 int tmp_dnr, tmp_dhr, tmp_tdb, tmp_rh;
00067
00068 sscanf(buf, "%*2s%2d%2d%2d%*14s%4d%*2s%4d%*34s%4d%8*s%3d%*s",month,day,hour,&tmp_dnr,&tmp_dhr,&tmp_tdb,&tmp_rh);
00069
00070 *dnr = tmp_dnr;
00071 *dhr = tmp_dhr;
00072 *tdb = ((double)tmp_tdb)/10.0;
00073
00074 *rh = ((double)tmp_rh)/100.0;
00075 return 1;
00076 }
00077
00078 double tmy2_reader::calc_solar(COMPASS_PTS cpt, short doy, double lat, double sol_time, double dnr, double dhr,double vert_angle = 90)
00079 {
00080 SolarAngles *sa = new SolarAngles();
00081 double surface_angle = surface_angles[cpt];
00082 double cos_incident = sa->cos_incident(lat,RAD(vert_angle),RAD(surface_angle),sol_time,doy);
00083
00084 return (double)dnr * cos_incident + dhr;
00085 }
00086
00087 void tmy2_reader::close(){
00088 fclose(fp);
00089 }
00090
00099 CLASS *climate::oclass = NULL;
00100 climate *climate::defaults = NULL;
00101
00102 climate::climate(MODULE *module)
00103 {
00104 if (oclass==NULL)
00105 {
00106 oclass = gl_register_class(module,"climate",PC_BOTTOMUP);
00107 if (gl_publish_variable(oclass,
00108 PT_char32, "city", PADDR(city),
00109 PT_char1024,"tmyfile",PADDR(tmyfile),
00110 PT_double,"temperature[degF]",PADDR(temperature),
00111 PT_double,"humidity[%]",PADDR(humidity),
00112 PT_double,"solar_flux[W/sf]",PADDR(solar_flux),
00113 PT_SIZE, 9,
00114 NULL)<1) GL_THROW("unable to publish properties in %s",__FILE__);
00115 strcpy(city,"");
00116 strcpy(tmyfile,"");
00117 temperature = 59.0;
00118 temperature_raw = 15.0;
00119 humidity = 0.75;
00120
00121 solar_flux[0] = solar_flux[1] = solar_flux[2] = solar_flux[3] = solar_flux[4] = solar_flux[5] = solar_flux[6] = solar_flux[7] = solar_flux[8] = 0.0;
00122
00123 tmy = NULL;
00124 defaults = this;
00125 }
00126 }
00127
00128 int climate::create(void)
00129 {
00130 memcpy(this,defaults,sizeof(*this));
00131 return 1;
00132 }
00133
00134 int climate::init(OBJECT *parent)
00135 {
00136
00137 if (strcmp(tmyfile,"")==0)
00138 return 1;
00139
00140
00141 char *found_file = gl_findfile(tmyfile,getenv("GLPATH"),FF_READ);
00142 if (found_file==NULL || file.open(found_file)<3)
00143 {
00144 gl_error("weather file '%s' access failed", tmyfile);
00145 return 0;
00146 }
00147
00148
00149 int line=0;
00150 tmy = (TMYDATA*)malloc(sizeof(TMYDATA)*8760);
00151 if (tmy==NULL)
00152 {
00153 gl_error("TMY buffer allocation failed");
00154 return 0;
00155 }
00156
00157 int month,day, hour;
00158 double dnr,dhr;
00159 char cty[50];
00160 char st[3];
00161 int lat_deg,lat_min,long_deg,long_min;
00162 file.header_info(cty,st,&lat_deg,&lat_min,&long_deg,&long_min);
00163 double degrees = (double)lat_deg + ((double)lat_min) / 60;
00164 double long_degrees = (double)long_deg + ((double)long_min) / 60;
00165 SolarAngles *sa = new SolarAngles();
00166 double tz_meridian = 15 * abs(file.tz_offset);
00167 while (line<8760 && file.next())
00168 {
00169
00170 file.read_data(&dnr,&dhr,&temperature,&humidity,&month,&day,&hour);
00171 int doy = sa->day_of_yr(month,day);
00172 int hoy = (doy - 1) * 24 + (hour-1);
00173 if (hoy>=0 && hoy<8760){
00174 tmy[hoy].temp_raw = temperature;
00175 tmy[hoy].temp = temperature;
00176 if(0 == gl_convert("degC", "degF", &(tmy[hoy].temp))){
00177 gl_error("climate::init unable to gl_convert() 'degC' to 'degF'!");
00178 return 0;
00179 }
00180 tmy[hoy].rh = humidity;
00181
00182 double sol_time = sa->solar_time((double)hour,doy,RAD(tz_meridian),RAD(long_degrees));
00183 double sol_rad = 0.0;
00184
00185 for(COMPASS_PTS c_point = CP_S; c_point < CP_LAST;c_point=COMPASS_PTS(c_point+1)){
00186 if(c_point == CP_H)
00187 sol_rad = file.calc_solar(CP_E,doy,RAD(degrees),sol_time,dnr,dhr,0.0);
00188 else
00189 sol_rad = file.calc_solar(c_point,doy,RAD(degrees),sol_time,dnr,dhr);
00190
00191 if(0 == gl_convert("W/m^2", "W/sf", &(sol_rad))){
00192 gl_error("climate::init unable to gl_convert() 'W/m^2' to 'W/sf'!");
00193 return 0;
00194 }
00195 tmy[hoy].solar[c_point] = sol_rad;
00196 }
00197
00198 }
00199 else
00200 gl_error("%s(%d): day %d, hour %d is out of allowed range 0-8759 hours", tmyfile,line,day,hour);
00201
00202 line++;
00203 }
00204 file.close();
00205 return 1;
00206 }
00207
00208 TIMESTAMP climate::sync(TIMESTAMP t0)
00209 {
00210 if (tmy!=NULL)
00211 {
00212 DATETIME ts;
00213 gl_localtime(t0,&ts);
00214 int hoy = ts.yearday*24 + ts.hour;
00215 temperature = tmy[hoy].temp;
00216 temperature_raw = tmy[hoy].temp_raw;
00217 humidity = tmy[hoy].rh;
00221 memcpy(solar_flux,tmy[hoy].solar,CP_LAST*sizeof(double));
00222 return -(t0+(3600*TS_SECOND-t0%(3600 *TS_SECOND)));
00223 }
00224 return TS_NEVER;
00225 }
00226
00228
00230
00232 EXPORT int create_climate(OBJECT **obj,
00233 OBJECT *parent)
00234 {
00235 *obj = gl_create_object(climate::oclass,sizeof(climate));
00236 if (*obj!=NULL)
00237 {
00238 climate *my = OBJECTDATA(*obj,climate);
00239 gl_set_parent(*obj,parent);
00240 my->create();
00241 return 1;
00242 }
00243 return 0;
00244 }
00245
00247 EXPORT int init_climate(OBJECT *obj,
00248 OBJECT *parent)
00249 {
00250 if (obj!=NULL)
00251 {
00252 climate *my = OBJECTDATA(obj,climate);
00253 return my->init(parent);
00254 }
00255 return 0;
00256 }
00257
00259 EXPORT TIMESTAMP sync_climate(OBJECT *obj,
00260 TIMESTAMP t0)
00261 {
00262 TIMESTAMP t1 = OBJECTDATA(obj,climate)->sync(t0);
00263 obj->clock = t0;
00264 return t1;
00265 }
00266
00278 csv::csv()
00279 {
00280 fp=NULL;
00281 hdr=NULL;
00282 data=NULL;
00283 cols=0;
00284 }
00285
00286 csv::~csv()
00287 {
00288 if (fp) fclose(fp);
00289 if (hdr) delete [] hdr;
00290 if (data) delete [] data;
00291 }
00292
00293 int csv::open(const char *file, const unsigned n, ...)
00294 {
00295 char *ff = gl_findfile((char*)file,NULL,FF_READ);
00296 if (ff==NULL) return 0;
00297 fp = fopen(ff,"r");
00298 if (fp==NULL) return 0;
00299 if (fgets(buffer,sizeof(buffer),fp)==NULL) return 0;
00300 char temp[sizeof(buffer)];
00301 strcpy(temp,buffer);
00302 hdr = new int[cols=n];
00303 if (hdr==NULL) return 0;
00304
00305
00306 va_list ptr;
00307 va_start(ptr,n);
00308 unsigned ncol;
00309 for (ncol=0; ncol<n; ncol++)
00310 {
00311 const char *arg=va_arg(ptr,const char*);
00312 char *p;
00313 int i=0;
00314
00315
00316 strcpy(buffer,temp);
00317 for (p=strtok(buffer,","); p!=NULL; p=strtok(NULL,","),i++)
00318 {
00319 if (strcmp(p,arg)==0)
00320 {
00321 hdr[ncol] = i;
00322 break;
00323 }
00324 }
00325
00326
00327 if (p==NULL)
00328 return ncol;
00329 }
00330 data = new char*[ncol];
00331 return ncol;
00332 }
00333
00334 int csv::next(void)
00335 {
00336 if (fgets(buffer,sizeof(buffer),fp)==NULL) return 0;
00337 unsigned n, i=0;
00338 char *p;
00339 for (p=strtok(buffer,","); p!=NULL; p=strtok(NULL,","),i++)
00340 {
00341 for (n=0; n<cols; n++)
00342 {
00343 if (hdr[n]==i)
00344 {
00345 data[n]=p;
00346 break;
00347 }
00348 }
00349 }
00350 return cols;
00351 }
00352
00353 char *csv::read(unsigned n)
00354 {
00355 if (n>=0 && n<cols)
00356 return data[n];
00357 else
00358 return NULL;
00359 }