Ejemplo n.º 1
0
TIMESTAMP controller::sync(TIMESTAMP t0, TIMESTAMP t1){
	double bid = -1.0;
	int64 no_bid = 0; // flag gets set when the current temperature drops in between the the heating setpoint and cooling setpoint curves
	double demand = 0.0;
	double rampify = 0.0;
	extern double bid_offset;
	OBJECT *hdr = OBJECTHDR(this);



	/* short circuit if the state variable doesn't change during the specified interval */
	if((t1 < next_run) && (market->market_id == lastmkt_id)){
		if(t1 == next_run - bid_delay){
			; // continue
		} else {
			if (pState == 0)
				return next_run;
			else if (*pState == last_pState)
				return next_run;
		}
	}

	if(control_mode == CN_RAMP){
		// if market has updated, continue onwards
		if(market->market_id != lastmkt_id){// && (*pAvg == 0.0 || *pStd == 0.0 || setpoint0 == 0.0)){
			double clear_price;
			lastmkt_id = market->market_id;
			lastbid_id = -1; // clear last bid id, refers to an old market
			// update using last price
			// T_set,a = T_set + (P_clear - P_avg) * | T_lim - T_set | / (k_T * stdev24)

			clear_price = market->current_frame.clearing_price;
			if(fabs(*pStd) < bid_offset){
				set_temp = setpoint0;
			} else if(clear_price < *pAvg && range_low != 0){
				set_temp = setpoint0 + (clear_price - *pAvg) * fabs(range_low) / (ramp_low * *pStd);
			} else if(clear_price > *pAvg && range_high != 0){
				set_temp = setpoint0 + (clear_price - *pAvg) * fabs(range_high) / (ramp_high * *pStd);
			} else {
				set_temp = setpoint0;
			}

			if((use_override == OU_ON) && (pOverride != 0)){
				if(clear_price <= last_p){
					// if we're willing to pay as much as, or for more than the offered price, then run.
					*pOverride = 1;
				} else {
					*pOverride = -1;
				}
			}

			// clip
			if(set_temp > max){
				set_temp = max;
			} else if(set_temp < min){
				set_temp = min;
			}

			*pSetpoint = set_temp;
			//gl_verbose("controller::postsync(): temp %f given p %f vs avg %f",set_temp, market->next.price, market->avg24);
		}

		if(dir > 0){
			if(*pMonitor > max){
				bid = 9999.0;
			} else if (*pMonitor < min){
				bid = 0.0;
				no_bid = 1;
			}
		} else if(dir < 0){
			if(*pMonitor < min){
				bid = 9999.0;
			} else if(*pMonitor > max){
				bid = 0.0;
				no_bid = 1;
			}
		} else if(dir == 0){
			if(*pMonitor < min){
				bid = 9999.0;
			} else if(*pMonitor > max){
				bid = 0.0;
				no_bid = 1;
			} else {
				bid = *pAvg; // override due to lack of "real" curve
			}
		}

		// calculate bid price
		if(*pMonitor > setpoint0){
			k_T = ramp_high;
			T_lim = range_high;
		} else if(*pMonitor < setpoint0) {
			k_T = ramp_low;
			T_lim = range_low;
		} else {
			k_T = 0.0;
			T_lim = 0.0;
		}

		if(bid < 0.0 && *pMonitor != setpoint0) {
			bid = *pAvg + ( (fabs(*pStd) < bid_offset) ? 0.0 : (*pMonitor - setpoint0) * (k_T * *pStd) / fabs(T_lim) );
		} else if(*pMonitor == setpoint0) {
			bid = *pAvg;
		}

		// bid the response part of the load
		double residual = *pTotal;
		/* WARNING ~ bid ID check will not work properly */
		KEY bid_id = (KEY)(lastmkt_id == market->market_id ? lastbid_id : -1);
		// override
		//bid_id = -1;
		if(*pDemand > 0 && no_bid != 1){
			last_p = bid;
			last_q = *pDemand;
			if(0 != strcmp(market->unit, "")){
				if(0 == gl_convert("kW", market->unit, &(last_q))){
					gl_error("unable to convert bid units from 'kW' to '%s'", market->unit);
					return TS_INVALID;
				}
			}
			//lastbid_id = market->submit(OBJECTHDR(this), -last_q, last_p, bid_id, (BIDDERSTATE)(pState != 0 ? *pState : 0));
			if(pState != 0){
				lastbid_id = submit_bid_state(pMarket, hdr, -last_q, last_p, (*pState > 0 ? 1 : 0), bid_id);
			} else {
				lastbid_id = submit_bid(pMarket, hdr, -last_q, last_p, bid_id);
			}
			residual -= *pLoad;

		} else {
			last_p = 0;
			last_q = 0;
			gl_verbose("%s's is not bidding", hdr->name);
		}
		if(residual < -0.001)
			gl_warning("controller:%d: residual unresponsive load is negative! (%.1f kW)", hdr->id, residual);
	} else if (control_mode == CN_DOUBLE_RAMP){
		/*
		double heat_range_high;
		double heat_range_low;
		double heat_ramp_high;
		double heat_ramp_low;
		double cool_range_high;
		double cool_range_low;
		double cool_ramp_high;
		double cool_ramp_low;
		*/

		DATETIME t_next;
		gl_localtime(t1,&t_next);

		// find crossover
		double midpoint = 0.0;
		if(cool_min - heat_max < *pDeadband){
			switch(resolve_mode){
				case RM_DEADBAND:
					midpoint = (heat_max + cool_min) / 2;
					if(midpoint - *pDeadband/2 < heating_setpoint0 || midpoint + *pDeadband/2 > cooling_setpoint0) {
						gl_error("The midpoint between the max heating setpoint and the min cooling setpoint must be half a deadband away from each base setpoint");
						return TS_INVALID;
					} else {
						heat_max = midpoint - *pDeadband/2;
						cool_min = midpoint + *pDeadband/2;
					}
					break;
				case RM_SLIDING:
					if(heat_max > cooling_setpoint0 - *pDeadband) {
						gl_error("the max heating setpoint must be a full deadband less than the cooling_base_setpoint");
						return TS_INVALID;
					}

					if(cool_min < heating_setpoint0 + *pDeadband) {
						gl_error("The min cooling setpoint must be a full deadband greater than the heating_base_setpoint");
						return TS_INVALID;
					}
					if(last_mode == TM_OFF || last_mode == TM_COOL){
						heat_max = cool_min - *pDeadband;
					} else if (last_mode == TM_HEAT){
						cool_min = heat_max + *pDeadband;
					}
					break;
				default:
					gl_error("unrecognized resolve_mode when double_ramp overlap resolution is needed");
					break;
			}
		}
		// if the market has updated,
		if(lastmkt_id != market->market_id){
			lastmkt_id = market->market_id;
			lastbid_id = -1;
			// retrieve cleared price
			double clear_price;
			clear_price = market->current_frame.clearing_price;
			if(clear_price == last_p){
				// determine what to do at the marginal price
				switch(market->clearing_type){
					case CT_SELLER:	// may need to curtail
						break;
					case CT_PRICE:	// should not occur
					case CT_NULL:	// q zero or logic error ~ should not occur
						// occurs during the zero-eth market.
						//gl_warning("clearing price and bid price are equal with a market clearing type that involves inequal prices");
						break;
					default:
						break;
				}
			}
			may_run = 1;
			// calculate setpoints
			if(fabs(*pStd) < bid_offset){
				*pCoolingSetpoint = cooling_setpoint0;
				*pHeatingSetpoint = heating_setpoint0;
			} else {
				if(clear_price > *pAvg){
					*pCoolingSetpoint = cooling_setpoint0 + (clear_price - *pAvg) * fabs(cool_range_high) / (cool_ramp_high * *pStd);
					//*pHeatingSetpoint = heating_setpoint0 + (clear_price - *pAvg) * fabs(heat_range_high) / (heat_ramp_high * *pStd);
					*pHeatingSetpoint = heating_setpoint0 + (clear_price - *pAvg) * fabs(heat_range_low) / (heat_ramp_low * *pStd);
				} else if(clear_price < *pAvg){
					*pCoolingSetpoint = cooling_setpoint0 + (clear_price - *pAvg) * fabs(cool_range_low) / (cool_ramp_low * *pStd);
					//*pHeatingSetpoint = heating_setpoint0 + (clear_price - *pAvg) * fabs(heat_range_low) / (heat_ramp_low * *pStd);
					*pHeatingSetpoint = heating_setpoint0 + (clear_price - *pAvg) * fabs(heat_range_high) / (heat_ramp_high * *pStd);
				} else {
					*pCoolingSetpoint = cooling_setpoint0;
					*pHeatingSetpoint = heating_setpoint0;
				}
			}

			// apply overrides
			if((use_override == OU_ON)){
				if(last_q != 0.0){
					if(clear_price == last_p && clear_price != market->pricecap){
						if(market->margin_mode == AM_DENY){
							*pOverride = -1;
						} else if(market->margin_mode == AM_PROB){
							double r = gl_random_uniform(0, 1.0);
							if(r < market->current_frame.marginal_frac){
								*pOverride = 1;
							} else {
								*pOverride = -1;
							}
						}
					} else if(market->current_frame.clearing_price <= last_p){				
						*pOverride = 1;
					} else {
						*pOverride = -1;
					}
				} else { // equality
					*pOverride = 0; // 'normal operation'
				}
			}

			//clip
			if(*pCoolingSetpoint > cool_max)
				*pCoolingSetpoint = cool_max;
			if(*pCoolingSetpoint < cool_min)
				*pCoolingSetpoint = cool_min;
			if(*pHeatingSetpoint > heat_max)
				*pHeatingSetpoint = heat_max;
			if(*pHeatingSetpoint < heat_min)
				*pHeatingSetpoint = heat_min;

			lastmkt_id = market->market_id;


		}
		
		// submit bids
		double previous_q = last_q; //store the last value, in case we need it
		last_p = 0.0;
		last_q = 0.0;
		// We have to cool
		if(*pMonitor > cool_max){
			last_p = market->pricecap;
			last_q = *pCoolingDemand;
		}
		// We have to heat
		else if(*pMonitor < heat_min){
			last_p = market->pricecap;
			last_q = *pHeatingDemand;
		}
		// We're floating in between heating and cooling
		else if(*pMonitor > heat_max && *pMonitor < cool_min){
			last_p = 0.0;
			last_q = 0.0;
		}
		// We might heat, if the price is right
		else if(*pMonitor <= heat_max && *pMonitor >= heat_min){
			double ramp, range;
			ramp = (*pMonitor > heating_setpoint0 ? heat_ramp_high : heat_ramp_low);
			range = (*pMonitor > heating_setpoint0 ? heat_range_high : heat_range_low);
			if(*pMonitor != cooling_setpoint0){
				last_p = *pAvg + ( (fabs(*pStd) < bid_offset) ? 0.0 : (*pMonitor - heating_setpoint0) * ramp * (*pStd) / fabs(range) );
			} else {
				last_p = *pAvg;
			}
			last_q = *pHeatingDemand;
		}
		// We might cool, if the price is right
		else if(*pMonitor <= cool_max && *pMonitor >= cool_min){
			double ramp, range;
			ramp = (*pMonitor > cooling_setpoint0 ? cool_ramp_high : cool_ramp_low);
			range = (*pMonitor > cooling_setpoint0 ? cool_range_high : cool_range_low);
			if(*pMonitor != cooling_setpoint0){
				last_p = *pAvg + ( (fabs(*pStd) < bid_offset) ? 0 : (*pMonitor - cooling_setpoint0) * ramp * (*pStd) / fabs(range) );
			} else {
				last_p = *pAvg;
			}
			last_q = *pCoolingDemand;
		}
			if(last_p > market->pricecap)
				last_p = market->pricecap;
			if(last_p < -market->pricecap)
				last_p = -market->pricecap;
		if(0 != strcmp(market->unit, "")){
			if(0 == gl_convert("kW", market->unit, &(last_q))){
				gl_error("unable to convert bid units from 'kW' to '%s'", market->unit);
				return TS_INVALID;
			}
		}
		if(last_q > 0.001){
			if (pState != 0 ) {
				KEY bid = (KEY)(lastmkt_id == market->market_id ? lastbid_id : -1);
				lastbid_id = submit_bid_state(this->pMarket, OBJECTHDR(this), -last_q, last_p, (*pState > 0 ? 1 : 0), bid);
			}
			else {
				KEY bid = (KEY)(lastmkt_id == market->market_id ? lastbid_id : -1);
				lastbid_id = submit_bid(this->pMarket, OBJECTHDR(this), -last_q, last_p, bid);
			}
		}
		else
		{
			if (last_pState != *pState)
			{
				KEY bid = (KEY)(lastmkt_id == market->market_id ? lastbid_id : -1);
				double my_bid = -market->pricecap;
				if (*pState != 0)
					my_bid = last_p;

				lastbid_id = submit_bid_state(this->pMarket, OBJECTHDR(this), -last_q, my_bid, (*pState > 0 ? 1 : 0), bid);
			}
		}
	}

	if (pState != 0)
		last_pState = *pState;

	char timebuf[128];
	gl_printtime(t1,timebuf,127);
	//gl_verbose("controller:%i::sync(): bid $%f for %f kW at %s",hdr->id,last_p,last_q,timebuf);
	//return postsync(t0, t1);
	return TS_NEVER;
}
TIMESTAMP irrigation_controller::sync(TIMESTAMP t0, TIMESTAMP t1){
	double bid = -1.0;
	int64 no_bid = 0; // flag gets set when the current temperature drops in between the the heating setpoint and cooling setpoint curves
	double demand = 0.0;
	double rampify = 0.0;
	extern double bid_offset;
	double deadband_shift = 0.0;
	double shift_direction = 0.0;
	double shift_setpoint = 0.0;
	double prediction_ramp = 0.0;
	double prediction_range = 0.0;
	double midpoint = 0.0;
	OBJECT *hdr = OBJECTHDR(this);
	


if(insync==0)
{
	insync=2;
}
else if(insync==2)
{
	x=gl_get_double_by_name(parent2,"actual_power_non_zero");
//	printf("%d %f			 ",parent2->id,*x);
	//system("pause");

		insync=1;
		pDemand=x;
		initial_zipload_power=x;
}


	if(first_period==0)  //for two diffrent periods
	{

	
	//OBJECT *p=gl_get_object("sensor");
	// double *humidity=gl_get_double_by_name(p,"humidity");
	 double *humidity=gl_get_double_by_name(soil_sensor,"humidity");
		
		*pMonitor =*humidity;
		//printf("irrigaiton:%d %f	\n",soil_sensor->id,*pMonitor);
	//	system("pause");
		
	//printf("%f %f",*pMonitor,setpoint0);
	//system("pause");
	/* short circuit if the state variable doesn't change during the specified interval */
	if((t1 < next_run) && (market->market_id == lastmkt_id)){
		if(t1 <= next_run - bid_delay){
			if(use_predictive_bidding == TRUE && ((control_mode == CN_RAMP && last_setpoint != setpoint0) || (control_mode == CN_DOUBLE_RAMP && (last_heating_setpoint != heating_setpoint0 || last_cooling_setpoint != cooling_setpoint0)))) {
				;
			} else {// check to see if we have changed states
				if(pState == 0){
					return next_run;
				} else if(*pState == last_pState){
					return next_run;
				}
			}
		} else {
			return next_run;
		}
	}
	
	if(use_predictive_bidding == TRUE){
		deadband_shift = *pDeadband * 0.5;
	}

	if(control_mode == CN_RAMP){
		// if market has updated, continue onwards
		if(market->market_id != lastmkt_id){// && (*pAvg == 0.0 || *pStd == 0.0 || setpoint0 == 0.0)){
			//printf("EDWWWWWWWWWWWWWWWWWWW\n");
			//system("pause");
			lastmkt_id = market->market_id;
			lastbid_id = -1; // clear last bid id, refers to an old market
			// update using last price
			// T_set,a = T_set + (P_clear - P_avg) * | T_lim - T_set | / (k_T * stdev24)

			clear_price = market->current_frame.clearing_price;

			if(use_predictive_bidding == TRUE){
				if((dir > 0 && clear_price < last_p) || (dir < 0 && clear_price > last_p)){
					shift_direction = -1;
				} else if((dir > 0 && clear_price >= last_p) || (dir < 0 && clear_price <= last_p)){
					shift_direction = 1;
				} else {
					shift_direction = 0;
				}
			}
			if(fabs(*pStd) < bid_offset){
				set_temp = setpoint0;
			} else if(clear_price < *pAvg && range_low != 0){
				set_temp = setpoint0 + (clear_price - *pAvg) * fabs(range_low) / (ramp_low * *pStd) + deadband_shift*shift_direction;
			} else if(clear_price > *pAvg && range_high != 0){
				set_temp = setpoint0 + (clear_price - *pAvg) * fabs(range_high) / (ramp_high * *pStd) + deadband_shift*shift_direction;
			} else {
				set_temp = setpoint0 + deadband_shift*shift_direction;
			}

			if((use_override == OU_ON) && (pOverride != 0)){
				if(clear_price <= last_p){
					// if we're willing to pay as much as, or for more than the offered price, then run.
					*pOverride = 1;
				} else {
					*pOverride = -1;
				}
			}

			// clip
			if(set_temp > max){
				set_temp = max;
			} else if(set_temp < min){
				set_temp = min;
			}

			*pSetpoint = set_temp;
			//gl_verbose("irrigation_controller::postsync(): temp %f given p %f vs avg %f",set_temp, market->next.price, market->avg24);
		}
		
		if(dir > 0){
				//edw mpainei
			if(use_predictive_bidding == TRUE){
				if(*pState == 0 && *pMonitor > (max - deadband_shift)){
					bid = market->pricecap;
				} else if(*pState != 0 && *pMonitor < (min + deadband_shift)){
					bid = 0.0;
					no_bid = 1;
				} else if(*pState != 0 && *pMonitor > max){
					bid = market->pricecap;
				} else if(*pState == 0 && *pMonitor < min){
					bid = 0.0;
					no_bid = 1;
				}
			} else {
				if(*pMonitor > max){
			//		printf("sto max");
				
					bid = market->pricecap;
				} else if (*pMonitor < min){
				//	printf("sto min");
					
					bid = -1.0;
					no_bid = 0;
				}
			}
		} else if(dir < 0){
		
				
			if(use_predictive_bidding == TRUE){
				if(*pState == 0 && *pMonitor < (min + deadband_shift)){
					bid = market->pricecap;
				} else if(*pState != 0 && *pMonitor > (max - deadband_shift)){
					bid = 0.0;
					no_bid = 1;
				} else if(*pState != 0 && *pMonitor < min){
					bid = market->pricecap;
				} else if(*pState == 0 && *pMonitor > max){
					bid = 0.0;
					no_bid = 1;
				}
			} else {
				if(*pMonitor < min){
					bid = market->pricecap;
				} else if (*pMonitor > max){
					bid = 0.0;
					no_bid = 0;
				}
			}
		} else if(dir == 0){

				
			if(use_predictive_bidding == TRUE){
				if(direction == 0.0) {
					gl_error("the variable direction did not get set correctly.");
				} else if((*pMonitor > max + deadband_shift || (*pState != 0 && *pMonitor > min - deadband_shift)) && direction > 0){
					bid = market->pricecap;
				} else if((*pMonitor < min - deadband_shift || (*pState != 0 && *pMonitor < max + deadband_shift)) && direction < 0){
					bid = market->pricecap;
				} else {
					bid = 0.0;
					no_bid = 0;
				}
			} else {
				if(*pMonitor < min){
					bid = market->pricecap;
				} else if(*pMonitor > max){
					bid = 0.0;
					no_bid = 0;
				} else {
					bid = *pAvg;
				}
			}
		}
		
		// calculate bid price
	//printf("%f,monitor:%f,min:%f max:%f, setpoint:%f\n",*humidity,*pMonitor,min,max,setpoint0);
		if(*pMonitor > setpoint0){
			k_T = ramp_low;
			T_lim = range_low;
			bid=0;
			
		  // printf("values : %f %f %f \n",bid,k_T, T_lim );
		} else if(*pMonitor < setpoint0) {
			//printf("right_side ");
		    
			k_T = ramp_low;
			T_lim = range_low;
			//printf("values : %f %f %f \n",bid,k_T, T_lim );

			///////////////////close all the controllers////////////////////////////
						
				static FINDLIST *xt1=NULL;
				 xt1=gl_find_objects(FL_NEW,FT_CLASS,SAME,"controller",FT_END);
				 OBJECT *firstt1= gl_find_next(xt1,NULL);
				 OBJECT *it1;
				 for(it1=firstt1;it1!=NULL;it1=it1->next)
				 {
				
					 if(gl_object_isa(it1,"controller"))
				     {
						 gl_set_value_by_name(it1,"second_period_for_market","1")  ;
						 
				     }
			     }


		//////////////////////////////////////////////////////////////////////////////////
		} else {
			
			k_T = 0.0;
			T_lim = 0.0;
		}
	
			
		if(bid < 0.0 && *pMonitor != setpoint0) {		
			
			gl_set_value_by_name(soil_sensor,"irrigate_flag","1");
			last_q = *initial_zipload_power;
			*pDemand =*initial_zipload_power;
			
			bid = *pAvg + ( (fabs(*pStd) < bid_offset) ? 0.0 : (*pMonitor - setpoint0) * (k_T * *pStd) / fabs(T_lim) );
			//printf("price:%f %f %f %f\n",bid,(*pMonitor - setpoint0) ,(k_T * *pStd) , fabs(T_lim));
				
	
			//////////////////////////////////////
			char x_position_string[1024];
			double *prev=gl_get_double_by_name(parent2,"prev_base_power");
		    double pos_x = *prev;
			sprintf(x_position_string, "%f", pos_x);
			gl_set_value_by_name(parent2,"base_power",x_position_string);
			/////////////////////////////////////

		} else if(*pMonitor == setpoint0) {
			bid = *pAvg;
			
		}
		else
		{
		    last_q=0;
			
			gl_set_value_by_name(parent2,"base_power","0");
		}

		// bid the response part of the load
		double residual = *pTotal;
		/* WARNING ~ bid ID check will not work properly */
		KEY bid_id = (KEY)(lastmkt_id == market->market_id ? lastbid_id : -1);
		// override
		//bid_id = -1;
		
		if(last_q > 0 && no_bid != 1){
			
			last_p = bid;
			last_q= *initial_zipload_power;
		
			//if(last_p < 0)
			//{
				//last_p=clear_price;
			//}
			if(0 != strcmp(market->unit, "")){
				if(0 == gl_convert("kW", market->unit, &(last_q))){
					gl_error("unable to convert bid units from 'kW' to '%s'", market->unit.get_string());
					return TS_INVALID;
				}
			}
			//lastbid_id = market->submit(OBJECTHDR(this), -last_q, last_p, bid_id, (BIDDERSTATE)(pState != 0 ? *pState : 0));
			if(pState != 0){
				
				lastbid_id = submit_bid_state(pMarket, hdr, -last_q, last_p, (*pState > 0 ? 1 : 0), bid_id);
			} else {
				
				lastbid_id = submit_bid(pMarket, hdr, -last_q, last_p, bid_id);
			}
			residual -= *pLoad;

		} else {
			last_p = 0;
			last_q = 0;
			gl_verbose("%s's is not bidding", hdr->name);
		}
		if(residual < -0.001)
			gl_warning("irrigation_controller:%d: residual unresponsive load is negative! (%.1f kW)", hdr->id, residual);
	} 

	if (pState != 0)
		last_pState = *pState;

	
	char timebuf[128];
	gl_printtime(t1,timebuf,127);
	

	return TS_NEVER;


	//}
	
	} //end of first_period==0
}
Ejemplo n.º 3
0
int climate::init(OBJECT *parent)
{
	char *dot = 0;
	OBJECT *obj=OBJECTHDR(this);
	double meter_to_feet = 1.0;
	double tz_num_offset;

	reader_type = RT_NONE;

	// ignore "" files ~ manual climate control is a feature
	if (strcmp(tmyfile,"")==0)
		return 1;

	// open access to the TMY file
	char *found_file;
	found_file = gl_findfile(tmyfile, NULL, FF_READ);
	if (found_file == NULL) // TODO: get proper values for solar
	{
		gl_error("weather file '%s' access failed", tmyfile);
		return 0;
	}

	
	//dot = strchr(tmyfile, '.');
	//while(strchr(dot+1, '.')){ /* init time, doesn't have to be fast -MH */
	//	dot = strchr(dot, '.');
	//}
	if(strstr(tmyfile, ".tmy2") || strstr(tmyfile,".tmy")){
		reader_type = RT_TMY2;
	} else if(strstr(tmyfile, ".csv")){
		reader_type = RT_CSV;
	} else {
		gl_warning("climate: unrecognized filetype, assuming TMY2");
	}

	if(reader_type == RT_CSV){
		// may or may not have an object,
		// have not called open()
		int rv = 0;

		if(reader == NULL){
			csv_reader *creader = new csv_reader();
			reader_hndl = creader;
			rv = creader->open(found_file);
//			creader->get_data(t0, &temperature, &humidity, &solar_direct, &solar_diffuse, &wind_speed, &rainfall, &snowdepth);
		} else {
			csv_reader *my = OBJECTDATA(reader,csv_reader);
			reader_hndl = my;
			rv = my->open(my->filename);
//			my->get_data(t0, &temperature, &humidity, &solar_direct, &solar_diffuse, &wind_speed, &rainfall, &snowdepth);
			//Pull timezone information
			tz_num_offset = my->tz_numval;
			tz_offset_val = tz_num_offset;

			//Copy latitude and longitude information from CSV reader
			obj->latitude = reader->latitude;
			obj->longitude = reader->longitude;

			//CSV Reader validity check
			if (fabs(obj->latitude) > 90)
			{
				gl_error("climate:%s - Latitude is outside +/-90!",obj->name);
				//Defined below
				return 0;
			}

			if (fabs(obj->longitude) > 180)
			{
				gl_error("climate:%s - Longitude is outside +/-180!",obj->name);
				//Defined below
				return 0;
			}

			//Generic warning about southern hemisphere and Duffie-Beckman usage
			if (obj->latitude<0)
			{
				gl_warning("climate:%s - Southern hemisphere solar position model may have issues",obj->name);
				/*  TROUBLESHOOT
				The default solar position model was built around a northern hemisphere assumption.  As such,
				it doesn't always produce completely accurate results for southern hemisphere locations.  Calculated
				insolation values are approximately correct, but may show discrepancies against measured data.  If
				this climate is associated with a solar object, use the SOLAR_TILT_MODEL SOLPOS to ensure proper
				results (this warning will still pop up).
				*/
			}

			//Set the timezone offset - stolen from TMY code below
			tz_meridian =  15 * tz_num_offset;//std_meridians[-file.tz_offset-5];
		}

		return rv;
	}

	// implicit if(reader_type == RT_TMY2) ~ do the following
	if( file.open(found_file) < 3 ){
		gl_error("climate::init() -- weather file header improperly formed");
		return 0;
	}
	
	// begin parsing the TMY file
	int line=0;
	tmy = (TMYDATA*)malloc(sizeof(TMYDATA)*8760);
	if (tmy==NULL)
	{
		gl_error("TMY buffer allocation failed");
		return 0;
	}

	int month, day, hour;//, year;
	double dnr,dhr,ghr,wspeed,precip,snowdepth,pressure,extra_dni;
	//char cty[50];
	//char st[3];
	int lat_deg,lat_min,long_deg,long_min;
	/* The city/state data isn't used anywhere.  -mhauer */
	//file.header_info(cty,st,&lat_deg,&lat_min,&long_deg,&long_min);
	file.header_info(NULL,NULL,&lat_deg,&lat_min,&long_deg,&long_min);

	//Handle hemispheres
	if (lat_deg<0)
		obj->latitude = (double)lat_deg - (((double)lat_min) / 60);
	else
		obj->latitude = (double)lat_deg + (((double)lat_min) / 60);

	if (long_deg<0)
		obj->longitude = (double)long_deg - (((double)long_min) / 60);
	else
		obj->longitude = (double)long_deg + (((double)long_min) / 60);

	//Generic check for TMY files
	if (fabs(obj->latitude) > 90)
	{
		gl_error("climate:%s - Latitude is outside +/-90!",obj->name);
		/*  TROUBLESHOOT
		The value read from the weather data indicates a latitude of greater
		than 90 or less than -90 degrees.  This is not a valid value.  Please specify
		the latitude in this range, with positive values representing the northern hemisphere
		and negative values representing the southern hemisphere.
		*/
		return 0;
	}

	if (fabs(obj->longitude) > 180)
	{
		gl_error("climate:%s - Longitude is outside +/-180!",obj->name);
		/*  TROUBLESHOOT
		The value read from the weather data indicates a longitude of greater
		than 180 or less than -180 degrees.  This is not a valid value.  Please specify
		the longitude in this range, with positive values representing the eastern hemisphere
		and negative values representing the western hemisphere.
		*/
		return 0;
	}

	//Generic warning about southern hemisphere and Duffie-Beckman usage
	if (obj->latitude<0)
	{
		gl_warning("climate:%s - Southern hemisphere solar position model may have issues",obj->name);
		//Defined above
	}

	if(0 == gl_convert("m", "ft", &meter_to_feet)){
		gl_error("climate::init unable to gl_convert() 'm' to 'ft'!");
		return 0;
	}
	file.elevation *= meter_to_feet;
	tz_meridian =  15 * file.tz_offset;//std_meridians[-file.tz_offset-5];
	tz_offset_val = file.tz_offset;
	while (line<8760 && file.next())
	{

		file.read_data(&dnr,&dhr,&ghr,&temperature,&humidity,&month,&day,&hour,&wspeed,&precip,&snowdepth,&pressure,&extra_dni);

		int doy = sa->day_of_yr(month,day);
		int hoy = (doy - 1) * 24 + (hour-1);
		if (hoy>=0 && hoy<8760){
			// pre-conversion of solar data from W/m^2 to W/sf
			if(0 == gl_convert("W/m^2", "W/sf", &(dnr))){
				gl_error("climate::init unable to gl_convert() 'W/m^2' to 'W/sf'!");
				return 0;
			}
			if(0 == gl_convert("W/m^2", "W/sf", &(dhr))){
				gl_error("climate::init unable to gl_convert() 'W/m^2' to 'W/sf'!");
				return 0;
			}
			if(0 == gl_convert("W/m^2", "W/sf", &(ghr))){
				gl_error("climate::init unable to gl_convert() 'W/m^2' to 'W/sf'!");
				return 0;
			}
			if(0 == gl_convert("W/m^2", "W/sf", &(extra_dni))){
				gl_error("climate::init unable to gl_convert() 'W/m^2' to 'W/sf'!");
				return 0;
			}
			if(0 == gl_convert("mps", "mph", &(wspeed))){
				gl_error("climate::init unable to gl_convert() 'm/s' to 'miles/h'!");
				return 0;
			}
			tmy[hoy].temp_raw = temperature;
			tmy[hoy].temp = temperature;
			// post-conversion of copy of temperature from C to F
			if(0 == gl_convert("degC", "degF", &(tmy[hoy].temp))){
				gl_error("climate::init unable to gl_convert() 'degC' to 'degF'!");
				return 0;
			}
			tmy[hoy].windspeed=wspeed;
			tmy[hoy].rh = humidity;
			tmy[hoy].dnr = dnr;
			tmy[hoy].dhr = dhr;
			tmy[hoy].ghr = ghr;
			tmy[hoy].rainfall = precip;
			tmy[hoy].snowdepth = snowdepth;
			tmy[hoy].solar_raw = dnr;

			tmy[hoy].direct_normal_extra = extra_dni;
			tmy[hoy].pressure = pressure;
			
			// calculate the solar radiation - hour on here may need a -1 application (hour-1) - unsure how TMYs really code things
			double sol_time = sa->solar_time((double)hour,doy,RAD(tz_meridian),RAD(obj->longitude));
			double sol_rad = 0.0;

			tmy[hoy].solar_elevation = sa->altitude(doy, RAD(obj->latitude), sol_time);
			tmy[hoy].solar_azimuth = sa->azimuth(doy, RAD(obj->latitude), sol_time);

			for(COMPASS_PTS c_point = CP_H; c_point < CP_LAST;c_point=COMPASS_PTS(c_point+1)){
				if(c_point == CP_H)
					sol_rad = file.calc_solar(CP_E,doy,RAD(obj->latitude),sol_time,dnr,dhr,ghr,ground_reflectivity,0.0);//(double)dnr * cos_incident + dhr;
				else
					sol_rad = file.calc_solar(c_point,doy,RAD(obj->latitude),sol_time,dnr,dhr,ghr,ground_reflectivity);//(double)dnr * cos_incident + dhr;
				/* TMY2 solar radiation data is in Watt-hours per square meter. */
				tmy[hoy].solar[c_point] = sol_rad;

				/* track records */
				if (sol_rad>record.solar || record.solar==0) record.solar = sol_rad;
				if (tmy[hoy].temp>record.high || record.high==0)
				{
					record.high = tmy[hoy].temp;
					record.high_day = doy;
				}
				if (tmy[hoy].temp<record.low || record.low==0)
				{
					record.low = tmy[hoy].temp;
					record.low_day = doy;
				}
			}

		}
		else
			gl_error("%s(%d): day %d, hour %d is out of allowed range 0-8759 hours", tmyfile,line,day,hour);

		line++;
	}
	file.close();

	/* initialize climate to starttime */
	presync(gl_globalclock);

	/* enable forecasting if specified */
#if 0
	if ( strcmp(forecast,"")!=0 && gl_forecast_create(obj,"")==NULL )
	{
		char buf[1024];
		gl_error("%s: forecast '%s' is not valid", gl_name(obj,buf,sizeof(buf))?buf:"(object?)", forecast);
		return 0;
	}
	else if (obj->forecast)
	{	/* initialize the forecast data entity */
		FORECAST *fc = obj->forecast;
		fc->propref = gl_find_property(obj->oclass,"temperature");
		gl_forecast_save(fc,obj->clock,3600,0,NULL);
		obj->flags |= OF_FORECAST;
	}
#endif
	return 1;
}