Example #1
0
//Perform post-event analysis (update computations, write event file if necessary) - no secondary count
void metrics::event_ended(OBJECT *event_obj, OBJECT *fault_obj, OBJECT *faulting_obj, TIMESTAMP event_start_time, TIMESTAMP event_end_time, char *fault_type, char *impl_fault, int number_customers_int)
{
	DATETIME start_dt, end_dt;
	TIMESTAMP outage_length;
	OBJECT *hdr = OBJECTHDR(this);
	int returnval;
	FILE *FPVal;

	//Determine the actual outage length (may be off due to iterations and such)
	outage_length = event_end_time - event_start_time;

	//Perform the calculation
	returnval = ((int (*)(OBJECT *, OBJECT *, int, int, TIMESTAMP, TIMESTAMP))(*compute_metrics))(hdr,module_metrics_obj,number_customers_int,CustomerCount,outage_length,metric_interval);

	//Make sure it worked
	if (returnval != 1)
	{
		GL_THROW("Metrics:%s failed to perform a post-event metric update",hdr->name);
		/*  TROUBLESHOOT
		While attempting to provide a post-fault update of relevant metrics, the metrics
		object encountered an error.  Please try your code again.  If the error persists,
		please submit your code and a bug report using the trac website.
		*/
	}

	//Increment the counters
	metric_interval_event_count++;
	annual_interval_event_count++;

	//Now that that's done, let's see if we need to write a file output
	if (report_event_log == true)
	{
		//Convert the times
		gl_localtime(event_start_time,&start_dt);
		gl_localtime(event_end_time,&end_dt);

		//Open the file handle
		FPVal = fopen(report_file,"at");

		//Print the name of the "safety" device?
		if (faulting_obj==NULL)
		{
		//Print the details out
			fprintf(FPVal,"%d,%d,%04d-%02d-%02d %02d:%02d:%02d,%04d-%02d-%02d %02d:%02d:%02d,%s,%s,%s,N/A,%s,%s,%d\n",annual_interval_event_count,metric_interval_event_count,start_dt.year,start_dt.month,start_dt.day,start_dt.hour,start_dt.minute,start_dt.second,end_dt.year,end_dt.month,end_dt.day,end_dt.hour,end_dt.minute,end_dt.second,fault_obj->oclass->name,fault_obj->name,event_obj->name,fault_type,impl_fault,number_customers_int);
		}
		else
		{
			//Print the details out
			fprintf(FPVal,"%d,%d,%04d-%02d-%02d %02d:%02d:%02d,%04d-%02d-%02d %02d:%02d:%02d,%s,%s,%s,%s,%s,%s,%d\n",annual_interval_event_count,metric_interval_event_count,start_dt.year,start_dt.month,start_dt.day,start_dt.hour,start_dt.minute,start_dt.second,end_dt.year,end_dt.month,end_dt.day,end_dt.hour,end_dt.minute,end_dt.second,fault_obj->oclass->name,fault_obj->name,event_obj->name,faulting_obj->name,fault_type,impl_fault,number_customers_int);
		}

		//Close the file
		fclose(FPVal);
	}
}
Example #2
0
static TIMESTAMP collector_write(OBJECT *obj)
{
	struct collector *my = OBJECTDATA(obj,struct collector);
	char ts[64];
	if (my->format==0)
	{
		//time_t t = (time_t)(my->last.ts*TS_SECOND);
		//strftime(ts,sizeof(ts),timestamp_format, gmtime(&t));

		DATETIME dt;
		gl_localtime(my->last.ts, &dt);
		gl_strtime(&dt, ts, sizeof(ts));
	}
	else
		sprintf(ts,"%" FMT_INT64 "d", my->last.ts);
	if ((my->limit>0 && my->samples>my->limit) /* limit reached */
		|| write_collector(my,ts,my->last.value)==0) /* write failed */
	{
		if (my->ops){
			close_collector(my);
		} else {
			gl_error("collector_write: no TAPEOP structure when closing the tape");
		}
		my->status = TS_DONE;
	}
	else
		my->samples++;
	return TS_NEVER;
}
Example #3
0
//sjin: add solar azimuth wrapper funcions
EXPORT int64 calculate_solar_azimuth(OBJECT *obj, double lititude, double *value)
{
	static SolarAngles sa; // just for the functions
	double std_time = 0.0;
	double solar_time = 0.0;
	short int doy = 0;
	DATETIME dt;

	climate *cli;
	if (obj == 0 || value == 0){
		//throw "climate/calc_solar: null object pointer in arguement";
		return 0;
	}
	cli = OBJECTDATA(obj, climate);
	if(gl_object_isa(obj, "climate", "climate") == 0){
		//throw "climate/calc_solar: input object is not a climate object";
		return 0;
	}

	gl_localtime(obj->clock, &dt);
	std_time = (double)(dt.hour) + ((double)dt.minute)/60.0 + (dt.is_dst ? -1:0);
	solar_time = sa.solar_time(std_time, doy, RAD(cli->tz_meridian), RAD(obj->longitude));

	double hr_ang = -(15.0 * PI_OVER_180)*(solar_time-12.0); // morning +, afternoon -

    double decl = 0.409280*sin(2.0*PI*(284+doy)/365);

	double alpha = (90.0 * PI_OVER_180) - lititude + decl;

	*value = acos( (sin(decl)*cos(lititude) - cos(decl)*sin(lititude)*cos(hr_ang))/cos(alpha) );

    return 1;
}
/**
	@return 1 on successful write, 0 on unsuccessful write, error, or when not ready
 **/
int group_recorder::write_line(TIMESTAMP t1){
	char time_str[64];
	DATETIME dt;

	if(TS_OPEN != tape_status){
		gl_error("group_recorder::write_line(): trying to write line when the tape is not open");
		// could be ERROR or CLOSED, should not have happened
		return 0;
	}
	if(0 == rec_file){
		gl_error("group_recorder::write_line(): no output file open and state is 'open'");
		/* TROUBLESHOOT
			group_recorder claimed to be open and attempted to write to a file when
			a file had not successfully	opened.
		 */
		tape_status = TS_ERROR;
		return 0;
	}

	// check that buffer needs were pre-calculated
	if(line_size <= 0 || line_buffer == 0){
		gl_error("group_recorder::write_line(): output buffer not initialized (read_line() not called)");
		/* TROUBLESHOOT
			read_line was not called before write_line, indicating an internal logic error.
		 */
		tape_status = TS_ERROR;
		return 0;
	}

	// write time_str
	// recorder.c uses multiple formats, in the sense of "formatted or not".  This does not.
	if(0 == gl_localtime(t1, &dt)){
		gl_error("group_recorder::write_line(): error when converting the sync time");
		/* TROUBLESHOOT
			Unprintable timestamp.
		 */
		tape_status = TS_ERROR;
		return 0;
	}
	if(0 == gl_strtime(&dt, time_str, sizeof(time_str) ) ){
		gl_error("group_recorder::write_line(): error when writing the sync time as a string");
		/* TROUBLESHOOT
			Error printing the timestamp.
		 */
		tape_status = TS_ERROR;
		return 0;
	}
	// print line to file
	if(0 >= fprintf(rec_file, "%s%s\n", time_str, line_buffer)){
		gl_error("group_recorder::write_line(): error when writing to the output file");
		/* TROUBLESHOOT
			File I/O error.
		 */
		tape_status = TS_ERROR;
		return 0;
	}
	++write_count;
	
	return 1;
}
Example #5
0
/* Sync is called when the clock needs to advance on the bottom-up pass */
TIMESTAMP office::presync(TIMESTAMP t0, TIMESTAMP t1) 
{
	DATETIME dt;

	/* reset the multizone heat transfer */
	Qz = 0;
	
	/* update out_temp */ 
	zone.current.out_temp = *(zone.current.pTemperature);

	/* get the occupancy mode from the schedule, if any */
	if (t0>0)
	{
		int day;// = gl_getweekday(t0);
		int hour;// = gl_gethour(t0);
		
		gl_localtime(t0, &dt);
		
		day = dt.weekday;
		hour = dt.hour;

		if (zone.design.schedule[0]!='\0' )
			zone.current.occupancy = IS_OCCUPIED(day,hour);
	}
	return TS_NEVER;
}
Example #6
0
double meter::process_bill(TIMESTAMP t1){
	DATETIME dtime;
	gl_localtime(t1,&dtime);

	monthly_energy = measured_real_energy/1000 - previous_energy_total;
	monthly_bill = monthly_fee;
	switch(bill_mode){
		case BM_NONE:
			break;
		case BM_UNIFORM:
			monthly_bill += monthly_energy * price;
			break;
		case BM_TIERED:
			if(monthly_energy < tier_energy[0])
				monthly_bill += last_price * monthly_energy;
			else if(monthly_energy < tier_energy[1])
				monthly_bill += last_price*tier_energy[0] + last_tier_price[0]*(monthly_energy - tier_energy[0]);
			else if(monthly_energy < tier_energy[2])
				monthly_bill += last_price*tier_energy[0] + last_tier_price[0]*(tier_energy[1] - tier_energy[0]) + last_tier_price[1]*(monthly_energy - tier_energy[1]);
			else
				monthly_bill += last_price*tier_energy[0] + last_tier_price[0]*(tier_energy[1] - tier_energy[0]) + last_tier_price[1]*(tier_energy[2] - tier_energy[1]) + last_tier_price[2]*(monthly_energy - tier_energy[2]);
			break;
		case BM_HOURLY:
			monthly_bill += hourly_acc;
			break;
		case BM_TIERED_RTP:
			monthly_bill += hourly_acc;
			if(monthly_energy < tier_energy[0])
				monthly_bill += last_price_base * monthly_energy;
			else if(monthly_energy < tier_energy[1])
				monthly_bill += last_price_base*tier_energy[0] + last_tier_price[0]*(monthly_energy - tier_energy[0]);
			else if(monthly_energy < tier_energy[2])
				monthly_bill += last_price_base*tier_energy[0] + last_tier_price[0]*(tier_energy[1] - tier_energy[0]) + last_tier_price[1]*(monthly_energy - tier_energy[1]);
			else
				monthly_bill += last_price_base*tier_energy[0] + last_tier_price[0]*(tier_energy[1] - tier_energy[0]) + last_tier_price[1]*(tier_energy[2] - tier_energy[1]) + last_tier_price[2]*(monthly_energy - tier_energy[2]);
			break;
	}

	if (dtime.day == bill_day && dtime.hour == 0 && dtime.month != last_bill_month)
	{
		previous_monthly_bill = monthly_bill;
		previous_monthly_energy = monthly_energy;
		previous_energy_total = measured_real_energy/1000;
		last_bill_month = dtime.month;
		hourly_acc = 0;
	}

	last_price = price;
	last_price_base = price_base;
	last_tier_price[0] = tier_price[0];
	last_tier_price[1] = tier_price[1];
	last_tier_price[2] = tier_price[2];

	return monthly_bill;
}
Example #7
0
TIMESTAMP schedule::presync(TIMESTAMP t0, TIMESTAMP t1){
	/* get localtime & run rules */
	DATETIME dt;
	TIMESTAMP min = TS_NEVER; // earliest start of next state
	TIMESTAMP max = TS_NEVER; // earliest end of current state
	int res = 0;

	schedule_list *lptr = 0, *child = 0;

	//	skip if t0 < next_ts ... we should know when this needs to change

	gl_localtime(t1, &dt);

	currval = default_value;

	for(lptr = sched_list; lptr != NULL; lptr = lptr->next){
		// process lptr rule
		// traverse lptr children
		// track when current state ends OR when next state begins

		/* group_right & group_left should actually be used ... coming soon! */
		for(child = lptr; child != NULL; child = child->group_right){
			res = test_sched_dt(child->moy_start, child->moy_end, dt.month);
			if(res == 0){
				continue;
			}
			if(child->dow_or_dom == schedule_list::wor_skip){
				res = 1; /* short circuit, both are '*' */
			} else if(child->dow_or_dom == schedule_list::wor_month){
				res = test_sched_dt(child->dom_start, child->dom_end, dt.day);
			} else if(child->dow_or_dom == schedule_list::wor_week){
				res = test_sched_dt(child->dow_start, child->dow_end, dt.weekday);
			} else if(child->dow_or_dom == schedule_list::wor_both){
				res = test_sched_dt(child->dom_start, child->dom_end, dt.day) + test_sched_dt(child->dow_start, child->dow_end, dt.weekday);
			} else {
				gl_verbose("invalid day of week/day of month flag");
				continue;
			}
			if(res == 0){
				continue;
			}
			res = test_sched_dt(child->hod_start, child->hod_end, dt.hour);
			res += test_sched_dt(child->moh_start, child->moh_end, dt.minute > 59 ? 59 : dt.minute);
			if(res == 2){
				currval = child->scale;
				break; /* found rule in the group that matches, on to the next group */
			}
		}
	}

	return TS_NEVER;
}
Example #8
0
void climate::update_forecasts(TIMESTAMP t0)
{
	static const int Nh = 72; /* number of hours in forecast */
	static const int dt = 3600; /* number of seconds in forecast interval */


#if 0
	OBJECT *my = OBJECTHDR(this);
	FORECAST *fc;
	
	for ( fc=my->forecast ; fc!=NULL ; fc=fc->next )
	{
		/* don't update forecasts that are already current */
		if ( t0/dt==(fc->starttime/dt) ) continue;

		int h, hoy;
		double t[Nh];
		for ( h=0 ; h<Nh ; h++ )
		{
			if (h==0)
			{
				/* actual values */
				DATETIME ts;
				if ( !gl_localtime(t0+(h*dt),&ts) )
				{
					GL_THROW("climate::sync -- unable to resolve localtime!");
				}
				int doy = sa->day_of_yr(ts.month,ts.day);
				hoy = (doy - 1) * 24 + (ts.hour);
			}
			else if ( hoy==8760 )
				hoy = 0;
			else
				hoy++;

			/* this is an extremely naive model of forecast error */
			t[h] = tmy[hoy].temp + gl_random_normal(RNGSTATE,0,h/10.0);
		}
		gl_forecast_save(fc,t0,dt,Nh,t);
#ifdef NEVER
		char buffer[1024];
		int len = sprintf(buffer,"%d",fc->starttime);
		for ( h=3; h<72; h+=3 )
			len += sprintf(buffer+len,",%.1f",fc->values[h]);
		printf("%s\n",buffer);
#endif
	}
#endif
}
EXPORT TIMESTAMP sync_residential_enduse(OBJECT *obj, TIMESTAMP t1)
{
	residential_enduse *my = OBJECTDATA(obj,residential_enduse);
	try {
		TIMESTAMP t2 = my->sync(obj->clock, t1);
		obj->clock = t1;
		return t2;
	}
	catch (char *msg)
	{
		DATETIME dt;
		char ts[64];
		gl_localtime(t1,&dt);
		gl_strtime(&dt,ts,sizeof(ts));
		gl_error("%s::%s.init(OBJECT **obj={name='%s', id=%d},TIMESTAMP t1='%s'): %s", obj->oclass->module->name, obj->oclass->name, obj->name, obj->id, ts, msg);
		return 0;
	}
}
Example #10
0
EXPORT TIMESTAMP sync_network(OBJECT *obj, TIMESTAMP t1)
{
	network *my = OBJECTDATA(obj,network);
	try {
		TIMESTAMP t2 = my->sync(obj->clock, t1);
		//obj->clock = t1; // update in commit
		return t2;
	}
	catch (char *msg)
	{
		DATETIME dt;
		char ts[64];
		gl_localtime(t1,&dt);
		gl_strtime(&dt,ts,sizeof(ts));
		gl_error("%s::%s.init(OBJECT **obj={name='%s', id=%d},TIMESTAMP t1='%s'): %s", obj->oclass->module->name, obj->oclass->name, obj->name, obj->id, ts, msg);
		return 0;
	}
}
EXPORT TIMESTAMP sync_thermal_storage(OBJECT *obj, TIMESTAMP t1)
{
	thermal_storage *my = OBJECTDATA(obj,thermal_storage);
	try {
		TIMESTAMP t2 = my->sync(obj->clock, t1);
		obj->clock = t1;
		return t2;
	}
	catch (char *msg)
	{
		DATETIME dt;
		char ts[64];
		gl_localtime(t1,&dt);
		gl_strtime(&dt,ts,sizeof(ts));
		gl_error("%s::%s.init(OBJECT **obj={name='%s', id=%d},TIMESTAMP t1='%s'): %s", obj->oclass->module->name, obj->oclass->name, obj->name, obj->id, ts, msg);
		/* TROUBLESHOOT
			The synchronization operation of the specified object failed.
			The message given provide additional details and can be looked up under the Exceptions section.
		 */
		return 0;
	}
}
EXPORT TIMESTAMP sync_transmissioncom(OBJECT *obj, TIMESTAMP t1, PASSCONFIG pass){
	transmissioncom *my = OBJECTDATA(obj,transmissioncom);
	try {
		TIMESTAMP t2 = TS_NEVER;
		if(pass == PC_BOTTOMUP){
			t2 = my->sync(obj->clock, t1);
		} else if(pass == PC_POSTTOPDOWN){
			t2 = my->postsync(obj->clock, t1);
		} else if(pass == PC_PRETOPDOWN){
			t2 = my->presync(obj->clock, t1);
		}
		obj->clock = t1;
		return t2;
	}
	catch (const char *msg)
	{
		DATETIME dt;
		char ts[64];
		gl_localtime(t1,&dt);
		gl_strtime(&dt,ts,sizeof(ts));
		gl_error("%s::%s.init(OBJECT **obj={name='%s', id=%d},TIMESTAMP t1='%s'): %s", obj->oclass->module->name, obj->oclass->name, obj->name, obj->id, ts, msg);
		return 0;
	}
}
Example #13
0
EXPORT int64 calculate_solar_radiation_shading_radians(OBJECT *obj, double tilt, double orientation, double shading_value, double *value){
	static SolarAngles sa; // just for the functions
	double ghr, dhr, dnr = 0.0;
	double cos_incident = 0.0;
	double std_time = 0.0;
	double solar_time = 0.0;
	short int doy = 0;
	DATETIME dt;

	climate *cli;
	if(obj == 0 || value == 0){
		//throw "climate/calc_solar: null object pointer in arguement";
		return 0;
	}
	cli = OBJECTDATA(obj, climate);
	if(gl_object_isa(obj, "climate", "climate") == 0){
		//throw "climate/calc_solar: input object is not a climate object";
		return 0;
	}
	ghr = cli->solar_global;
	dhr = cli->solar_diffuse;
	dnr = shading_value * cli->solar_direct;

	gl_localtime(obj->clock, &dt);

	std_time = (double)(dt.hour) + ((double)dt.minute)/60.0  + (dt.is_dst ? -1.0:0.0);

	doy=sa.day_of_yr(dt.month,dt.day);

	solar_time = sa.solar_time(std_time, doy, RAD(cli->tz_meridian), RAD(obj->longitude));
	cos_incident = sa.cos_incident(RAD(obj->latitude), tilt, orientation, solar_time, doy);

	*value = dnr * cos_incident + dhr * (1 + cos(tilt)) / 2 + ghr * (1 - cos(tilt)) * cli->ground_reflectivity / 2;

	return 1;
}
Example #14
0
/* Sync is called when the clock needs to advance on the bottom-up pass */
TIMESTAMP office::sync(TIMESTAMP t0, TIMESTAMP t1) 
{	
	/* load calculations */
	update_lighting(t0,t1);
	update_plugs(t0,t1);
	
	/* local aliases */
	const double &Tout = (*(zone.current.pTemperature));
	const double &Ua = (zone.design.exterior_ua);
	const double &Cm = (zone.design.interior_mass);
	const double &Um = (zone.design.interior_ua);
	double &Ti = (zone.current.air_temperature);
	double &dTi = (zone.current.temperature_change);
	double &Tm = (zone.current.mass_temperature);
	HCMODE &mode = (zone.hvac.mode);

	/* advance the thermal state of the building */

	const double dt1 = t0>0 ? (double)(t1-t0)*TS_SECOND : 0;
	if (dt1>0)
	{
		const double dt = dt1/3600; /* model operates in units of hours */

		/* calculate model update */
		if (c2!=0)
		{
			/* update temperatures */
			const double e1 = k1*exp(r1*dt);
			const double e2 = k2*exp(r2*dt);
			Ti = e1 + e2 + Teq;
			Tm = ((r1-c1)*e1 + (r2-c1)*e2 + c6)/c2 + Teq;

			if (warn_control)
			{
				/* check for air temperature excursion */
				if (Ti<warn_low_temp || Ti>warn_high_temp)
				{
					OBJECT *obj = OBJECTHDR(this);
					DATETIME dt0, dt1;
					gl_localtime(t0,&dt0);
					gl_localtime(t1,&dt1);
					char ts0[64], ts1[64];
					gl_warning("office:%d (%s) air temperature excursion (%.1f degF) at between %s and %s", 
						obj->id, obj->name?obj->name:"anonymous", Ti,
						gl_strtime(&dt0,ts0,sizeof(ts0))?ts0:"UNKNOWN", gl_strtime(&dt1,ts1,sizeof(ts1))?ts1:"UNKNOWN");
				}

				/* check for mass temperature excursion */
				if (Tm<warn_low_temp || Tm>warn_high_temp)
				{
					OBJECT *obj = OBJECTHDR(this);
					DATETIME dt0, dt1;
					gl_localtime(t0,&dt0);
					gl_localtime(t1,&dt1);
					char ts0[64], ts1[64];
					gl_warning("office:%d (%s) mass temperature excursion (%.1f degF) at between %s and %s", 
						obj->id, obj->name?obj->name:"anonymous", Tm,
						gl_strtime(&dt0,ts0,sizeof(ts0))?ts0:"UNKNOWN", gl_strtime(&dt1,ts1,sizeof(ts1))?ts1:"UNKNOWN");
				}
			}

			/* calculate the power consumption */
			zone.total.energy += zone.total.power * dt;
		}

		const double Ca = 0.2402 * 0.0735 * zone.design.floor_height * zone.design.floor_area;

		/* update enduses and get internal heat gains */
		Qi = zone.lights.enduse.heatgain + zone.plugs.enduse.heatgain;

		/* compute solar gains */
		Qs = 0; 
		int i;
		for (i=0; i<9; i++)
			Qs += zone.design.window_area[i] * zone.current.pSolar[i]/10;
		Qs *= 3.412;
		if (Qs<0)
			throw "solar gain is negative?!?";

		/* compute heating/cooling effect */
		Qh = update_hvac(); 

		if (Ca<=0)
			throw "Ca must be positive";
		if (Cm<=0)
			throw "Cm must be positive";

		// split gains to air and mass
		double f_air = 1.0; /* adjust the fraction of gains that goes to air vs mass */
		double Qa = Qh + f_air*(Qi + Qs);
		double Qm = (1-f_air)*(Qi + Qs);

		c1 = -(Ua + Um)/Ca;
		c2 = Um/Ca;
		c3 = (Qa + Tout*Ua)/Ca;
		c6 = Qm/Cm;
		c7 = Qa/Ca;
		double p1 = 1/c2;
		if (Cm<=0)
			throw "Cm must be positive";
		c4 = Um/Cm;
		c5 = -c4;
		if (c2<=0)
			throw "Um must be positive";
		double p2 = -(c5+c1)/c2;
		double p3 = c1*c5/c2 - c4;
		double p4 = -c3*c5/c2 + c6;
		if (p3==0)
			throw "Teq is not finite";
		Teq = p4/p3;

		/* compute solution roots */
		if (p1==0)
			throw "internal error (p1==0 -> Ca==0 which should have caught)";
		const double ra = 2*p1;
		const double rb = -p2/ra;
		const double rr = p2*p2-4*p1*p3;
		if (rr<0)
			throw "thermal solution does not exist";
		const double rc = sqrt(rr)/ra;
		r1 = rb+rc;
		r2 = rb-rc;
		if (r1>0 || r2>0)
			throw "thermal solution has runaway condition";
	
		/* compute next initial condition */
		dTi = c2*Tm + c1*Ti - (c1+c2)*Tout + c7;
		k1 = (r2*Ti - r2*Teq - dTi)/(r2-r1);
		k2 = (dTi - r1*k1)/r2;

		/* calculate power */
		zone.total.power = zone.lights.enduse.power + zone.plugs.enduse.power + zone.hvac.enduse.power;

		if (warn_control)
		{
			/* check for heating equipment sizing problem */
			if ((mode==HC_HEAT || mode==HC_AUX) && Teq<TheatOff)
			{
				OBJECT *obj = OBJECTHDR(this);
				DATETIME dt0, dt1;
				gl_localtime(t0,&dt0);
				gl_localtime(t1,&dt1);
				char ts0[64], ts1[64];
				gl_warning("office:%d (%s) %s heating undersized between %s and %s", 
					obj->id, obj->name?obj->name:"anonymous", mode==HC_HEAT?"primary":"auxiliary", 
					gl_strtime(&dt0,ts0,sizeof(ts0))?ts0:"UNKNOWN", gl_strtime(&dt1,ts1,sizeof(ts1))?ts1:"UNKNOWN");
			}

			/* check for cooling equipment sizing problem */
			else if (mode==HC_COOL && Teq>TcoolOff)
			{
				OBJECT *obj = OBJECTHDR(this);
				DATETIME dt0, dt1;
				gl_localtime(t0,&dt0);
				gl_localtime(t1,&dt1);
				char ts0[64], ts1[64];
				gl_warning("office:%d (%s) cooling undersized between %s and %s", 
					obj->id, obj->name?obj->name:"anonymous", mode==HC_COOL?"COOL":"ECON", 
					gl_strtime(&dt0,ts0,sizeof(ts0))?ts0:"UNKNOWN", gl_strtime(&dt1,ts1,sizeof(ts1))?ts1:"UNKNOWN");
			}

			/* check for economizer control problem */
			else if (mode==HC_ECON && Teq>TcoolOff)
			{
				OBJECT *obj = OBJECTHDR(this);
				DATETIME dt;
				gl_localtime(t1,&dt);
				char ts[64];
				gl_warning("office:%d (%s) insufficient economizer control at %s", 
					obj->id, obj->name?obj->name:"anonymous", gl_strtime(&dt,ts,sizeof(ts))?ts:"UNKNOWN");
			}
		}
	}

	/* determine the temperature of the next event */
	if (Tevent == Teq)
		return -(t1+(TIMESTAMP)(3600*TS_SECOND)); /* soft return not more than an hour */

	/* solve for the time to the next event */
	double dt2=(double)TS_NEVER;
	dt2 = e2solve(k1,r1,k2,r2,Teq-Tevent)*3600;
	if (isnan(dt2) || !isfinite(dt2) || dt2<0)
	{
		if (dTi==0)
			/* never more than an hour because of the occupancy schedule */
			return -(t1+(TIMESTAMP)(3600*TS_SECOND)); /* soft return */

		/* do not allow more than 1 degree/hour temperature change before solving again */
		dt2 = fabs(3600/dTi);
		if (dt2>3600)
			dt2 = 3600; /* never more than an hour because of the occupancy schedule */
		return -(t1+(TIMESTAMP)(dt2*TS_SECOND)); /* soft return */
	}
	if (dt2<TS_SECOND)
		return t1+1; /* need to do a second pass to get next state */
	else
		return t1+(TIMESTAMP)(dt2*TS_SECOND); /* return t2>t1 on success, t2=t1 for retry, t2<t1 on failure */
}
Example #15
0
TIMESTAMP metrics::postsync(TIMESTAMP t0, TIMESTAMP t1)
{
	DATETIME dt;
	int returnval;
	bool metrics_written;
	OBJECT *hdr = OBJECTHDR(this);
	FILE *FPVal;

	//Initialization
	if (curr_time == TS_NEVER)
	{
		//Update time value trackers
		if (metric_interval == 0)	//No metric update interval - ensure never goes off
		{
			next_metric_interval = TS_NEVER;
		}
		else	//OK, proceed
		{
			next_metric_interval = t1 + metric_interval;
		}

		next_report_interval = t1 + report_interval;
		next_annual_interval = t1 + 31536000;	//t1 + 365 days of seconds

		//Outputs in CSV format - solves issue of column alignment - assuming we want event log
		if (report_event_log == true)
		{
			//Open the file
			FPVal = fopen(report_file,"at");

			//Figure out when we are, roughly (use t1 here)
			gl_localtime(t1,&dt);

			//Write header stuffs
			fprintf(FPVal,"Events for year starting at %04d-%02d-%02d %02d:%02d:%02d\n",dt.year,dt.month,dt.day,dt.hour,dt.minute,dt.second);

			//Determine which header to write
			if (secondary_interruptions_count == true)
			{
				fprintf(FPVal,"Annual Event #,Metric Interval Event #,Starting DateTime (YYYY-MM-DD hh:mm:ss),Ending DateTime (YYYY-MM-DD hh:mm:ss),Object type,Object Name,Inducing Object,\"Protective\" Device,Desired Fault type,Implemented Fault Type,Number customers affected,Secondary number of customers affected\n");
			}
			else //Nope
			{
				fprintf(FPVal,"Annual Event #,Metric Interval Event #,Starting DateTime (YYYY-MM-DD hh:mm:ss),Ending DateTime (YYYY-MM-DD hh:mm:ss),Object type,Object Name,Inducing Object,\"Protective\" Device,Desired Fault type,Implemented Fault Type,Number customers affected\n");
			}

			//Close the file handle
			fclose(FPVal);
		}

		//First run - t1 = t0 (t0 is zero)
		curr_time = t1;
	}

	//Only worry about checks once per timestep
	if (curr_time != t0)
	{
		//Reset temp flag
		metrics_written = false;

		if (t0 >= next_report_interval)
		{
			//Write the output metric values
			write_metrics();

			//Update variable
			metrics_written = true;

			//Update the interval
			next_report_interval = t0 + report_interval;
		}

		//See if it is time to write an update
		if (t0 >= next_metric_interval)
		{
			//See if the metrics were written - if not, dumb them again for posterity
			if (metrics_written == false)
				write_metrics();

			//Update the interval
			next_metric_interval = t0 + metric_interval;

			//Reset the stat variables
			returnval = ((int (*)(OBJECT *, OBJECT *))(*reset_interval_func))(hdr,module_metrics_obj);

			if (returnval != 1)	//See if it failed
			{
				GL_THROW("Failed to reset interval metrics for %s by metrics:%s",module_metrics_obj->name,hdr->name);
				//Defined above
			}

			//Reset the counter
			metric_interval_event_count = 0;

			//Indicate a new interval is going on - if we aren't a year (otherwise it happens below)
			if ((report_event_log == true) && (metric_equal_annual == false))
			{
				//Open the file
				FPVal = fopen(report_file,"at");

				//Figure out when we are
				gl_localtime(t0,&dt);

				//Write header stuffs
				fprintf(FPVal,"\nNew Metric Interval started at %04d-%02d-%02d %02d:%02d:%02d\n\n",dt.year,dt.month,dt.day,dt.hour,dt.minute,dt.second);

				//Close the file handle
				fclose(FPVal);
			}
		}//End interval metrics update

		//See if we've exceeded a year
		if (t0 >= next_annual_interval)
		{
			//See if we need to write the file - if "metric_interval" just went off, no sense writing the same thing again
			if (metrics_written == false)
				write_metrics();

			//Update interval
			next_annual_interval = t0 + 31536000;	//t0 + 365 days of seconds

			//Reset the stats
			returnval = ((int (*)(OBJECT *, OBJECT *))(*reset_annual_func))(hdr,module_metrics_obj);

			if (returnval != 1)	//See if it failed
			{
				GL_THROW("Failed to reset annual metrics for %s by metrics:%s",module_metrics_obj->name,hdr->name);
				//Defined above
			}

			//Reset the counter
			annual_interval_event_count = 0;

			//Indicate a new interval is going on
			if (report_event_log == true)
			{
				//Open the file
				FPVal = fopen(report_file,"at");

				//Figure out when we are
				gl_localtime(t0,&dt);

				//Write header stuffs
				fprintf(FPVal,"\nNew Annual Interval started at %04d-%02d-%02d %02d:%02d:%02d\n\n",dt.year,dt.month,dt.day,dt.hour,dt.minute,dt.second);

				//Close the file handle
				fclose(FPVal);
			}
		}//End annual update

		//Update tracking variable
		curr_time = t0;
	}

	//See who to return
	if (next_metric_interval < next_annual_interval)
	{
		if (next_metric_interval < next_report_interval)
			return -next_metric_interval;
		else
			return -next_report_interval;
	}
	else
	{
		if (next_annual_interval < next_report_interval)
			return -next_annual_interval;
		else
			return -next_report_interval;
	}
}
Example #16
0
TIMESTAMP house::sync_thermal(TIMESTAMP t1, double nHours){
	DATETIME tv;
	double t = 0.0;
	gl_localtime(t1, &tv);
	
	Tout = *pTout;

	Tsolar = get_Tsolar(tv.hour, tv.month, Tair, *pTout);
	solar_load = 0.0;

	for (int i = 1; i<9; i++)
	{
		solar_load += (gross_wall_area*window_wall_ratio/8.0) * glazing_shgc * pSolar[i];
	}
	double netHeatrate = /*hvac_rated_capacity +*/ tload.heatgain*BTUPHPW + solar_load;
	double Q1 = M_inv11*Tair + M_inv12*Tmaterials;
	double Q2 = M_inv21*Tair + M_inv22*Tmaterials;

	if (nHours > ROUNDOFF)
	{
		double q1 = exp(s1*nHours)*(Q1 + BB11*Tsolar/s1 + BB12*netHeatrate/s1) - BB11*Tsolar/s1 
			- BB12*netHeatrate/s1;
		double q2 = exp(s2*nHours)*(Q2 - BB11*Tsolar/s2 - BB12*netHeatrate/s2) + BB11*Tsolar/s2 
			+ BB12*netHeatrate/s2;

		Tair = q1*(s1-A22)/A21 + q2*(s2-A22)/A21;
		Tmaterials = q1 + q2;
	}
    else
        return TS_NEVER;

	// calculate constants for solving time "t" to reach Tevent
	const double W = (Q1 + (BB11*Tsolar)/s1 + BB12*netHeatrate/s1)*(s1-A22)/A21;
	const double X = (BB11*Tsolar/s1 + BB12*netHeatrate/s1)*(s1-A22)/A21;
	const double Y = (Q2 - (BB11*Tsolar)/s2 - BB12*netHeatrate/s2)*(s2-A22)/A21;
	const double Z = (BB11*Tsolar/s2 + BB12*netHeatrate/s2)*(s2-A22)/A21;
	// end new solution

	// determine next internal event temperature
	int n_solutions = 0;
	double Tevent;
	const double TcoolOn = cooling_setpoint+thermostat_deadband;
	const double TcoolOff = cooling_setpoint-thermostat_deadband;
	const double TheatOn = heating_setpoint-thermostat_deadband;
	const double TheatOff = heating_setpoint+thermostat_deadband;

	/* determine the temperature of the next event */
#define TPREC 0.01
	if (hvac_rated_capacity < 0.0)
		Tevent = TcoolOff;
	else if (hvac_rated_capacity > 0.0)
		Tevent = TheatOff;
	else if (Tair <= TheatOn+TPREC)
		Tevent = TheatOn;
	else if (Tair >= TcoolOn-TPREC)
		Tevent = TcoolOn;
	else
		return TS_NEVER;

#ifdef OLD_SOLVER
    if (nHours > TPREC)
		// int dual_decay_solve(double *ans, double prec, double start, double end, int f, double a, double n, double b, double m, double c)
		n_solutions = dual_decay_solve(&t,TPREC,0.0 ,nHours,W,s1,Y,s2,Z-X-Tevent);

	Tair = Tevent;

	if (n_solutions<0)
		gl_error("house: solver error");
	else if (n_solutions == 0)
		return TS_NEVER;
	else if (t == 0)
		t = 1.0/3600.0;  // one second
	return t1+(TIMESTAMP)(t*3600*TS_SECOND);
#else
	t =  e2solve(W,s1,Y,s2,Z-X-Tevent);
	    Tair = Tevent;

	if (isfinite(t))
    {
		return t1+(TIMESTAMP)(t*3600*TS_SECOND);
    }
	else
		return TS_NEVER;
#endif
}
Example #17
0
/* Postsync is called when the clock needs to advance on the second top-down pass */
TIMESTAMP stubauction::postsync(TIMESTAMP t0, TIMESTAMP t1)
{
	int64 i = 0;
	int64 j = 0;
	DATETIME dt;
	
	retry = 0;

	if (t1>=clearat)
	{

		gl_localtime(clearat,&dt);
//		if (verbose) gl_output("   ...%s clearing process started at %s", gl_name(OBJECTHDR(this),myname,sizeof(myname)), gl_strtime(&dt,buffer,sizeof(buffer))?buffer:"unknown time");

		/* clear market */
		thishr = dt.hour;
		
		last_price = next_price;
		++market_id;

//		if(lasthr != thishr){
		if(t0 != t1 && 0 == t1 % 3600){
			/* add price/quantity to the history */
			prices[count%168] = next_price;
			++count;
			
			/* update the daily and weekly averages */
			if(control_mode == CON_NORMAL){
				avg168 = 0.0;
				for(i = 0; i < count && i < 168; ++i){
					avg168 += prices[i];
				}
				avg168 /= (count > 168 ? 168 : count);

				avg24 = 0.0;
				for(i = 1; i <= 24 && i <= count; ++i){
					j = (168 - i + count) % 168;
					avg24 += prices[j];
				}
				avg24 /= (count > 24 ? 24 : count);

				avg72 = 0.0;
				for(i = 1; i <= 72 && i <= count; ++i){
					j = (168 - i + count) % 168;
					avg72 += prices[j];
				}
				avg72 /= (count > 72 ? 72 : count);

				/* update the daily & weekly standard deviations */
				std168 = 0.0;
				for(i = 0; i < count && i < 168; ++i){
					std168 += prices[i] * prices[i];
				}
				std168 /= (count > 168 ? 168 : count);
				std168 -= avg168*avg168;
				std168 = sqrt(fabs(std168));

				std24 = 0.0;
				for(i = 1; i <= 24 && i <= count; ++i){
					j = (168 - i + count) % 168;
					std24 += prices[j] * prices[j];
				}
				std24 /= (count > 24 ? 24 : count);
				std24 -= avg24*avg24;
				std24 = sqrt(fabs(std24));

				std72 = 0.0;
				for(i = 1; i <= 72 && i <= count; ++i){
					j = (168 - i + count) % 168;
					std72 += prices[j] * prices[j];
				}
				std72 /= (count > 72 ? 72 : count);
				std72 -= avg72*avg72;
				std72 = sqrt(fabs(std72));

				retry = 1;
			}

			/* update reference hour */
			lasthr = thishr;
		}

		market_id++;

		clearat = nextclear();
		gl_localtime(clearat,&dt);
//		if (verbose) gl_output("   ...%s opens for clearing of market_id %d at %s", gl_name(OBJECTHDR(this),name,sizeof(name)), (int32)market_id, gl_strtime(&dt,buffer,sizeof(buffer))?buffer:"unknown time");
	}
	return (retry ? t1 : -clearat); /* soft return t2>t1 on success, t2=t1 for retry, t2<t1 on failure */
}
Example #18
0
TIMESTAMP meter::postsync(TIMESTAMP t0, TIMESTAMP t1)
{
	measured_voltage[0] = voltageA;
	measured_voltage[1] = voltageB;
	measured_voltage[2] = voltageC;

	measured_voltageD[0] = voltageA - voltageB;
	measured_voltageD[1] = voltageB - voltageC;
	measured_voltageD[2] = voltageC - voltageA;

	if ((solver_method == SM_NR && NR_cycle == true)||solver_method  == SM_FBS)
	{
		//Reliability addition - if momentary flag set - clear it
		if (meter_interrupted_secondary == true)
			meter_interrupted_secondary = false;

		if (t1 > last_t)
		{
			dt = t1 - last_t;
			last_t = t1;
		}
		else
			dt = 0;
		
		measured_current[0] = current_inj[0];
		measured_current[1] = current_inj[1];
		measured_current[2] = current_inj[2];

		// compute energy use from previous cycle
		// - everything below this can moved to commit function once tape player is collecting from commit function7
		if (dt > 0 && last_t != dt)
		{	
			measured_real_energy += measured_real_power * TO_HOURS(dt);
			measured_reactive_energy += measured_reactive_power * TO_HOURS(dt);
		}

		// compute demand power
		indiv_measured_power[0] = measured_voltage[0]*(~measured_current[0]);
		indiv_measured_power[1] = measured_voltage[1]*(~measured_current[1]);
		indiv_measured_power[2] = measured_voltage[2]*(~measured_current[2]);

		measured_power = indiv_measured_power[0] + indiv_measured_power[1] + indiv_measured_power[2];

		measured_real_power = (indiv_measured_power[0]).Re()
							+ (indiv_measured_power[1]).Re()
							+ (indiv_measured_power[2]).Re();

		measured_reactive_power = (indiv_measured_power[0]).Im()
								+ (indiv_measured_power[1]).Im()
								+ (indiv_measured_power[2]).Im();

		if (measured_real_power > measured_demand) 
			measured_demand = measured_real_power;

		if (bill_mode == BM_UNIFORM || bill_mode == BM_TIERED)
		{
			if (dt > 0)
				process_bill(t1);

			// Decide when the next billing HAS to be processed (one month later)
			if (monthly_bill == previous_monthly_bill)
			{
				DATETIME t_next;
				gl_localtime(t1,&t_next);

				t_next.day = bill_day;

				if (t_next.month != 12)
					t_next.month += 1;
				else
				{
					t_next.month = 1;
					t_next.year += 1;
				}
				t_next.tz[0] = 0;
				next_time =	gl_mktime(&t_next);
			}
		}

		if( (bill_mode == BM_HOURLY || bill_mode == BM_TIERED_RTP) && power_market != NULL && price_prop != NULL){
			double seconds;
			if (dt != last_t)
				seconds = (double)(dt);
			else
				seconds = 0;
			
			if (seconds > 0)
			{
				hourly_acc += seconds/3600 * price * last_measured_real_power/1000;
				process_bill(t1);
			}

			// Now that we've accumulated the bill for the last time period, update to the new price
			double *pprice = (gl_get_double(power_market, price_prop));
			last_price = price = *pprice;
			last_measured_real_power = measured_real_power;

			if (monthly_bill == previous_monthly_bill)
			{
				DATETIME t_next;
				gl_localtime(t1,&t_next);

				t_next.day = bill_day;

				if (t_next.month != 12)
					t_next.month += 1;
				else
				{
					t_next.month = 1;
					t_next.year += 1;
				}
				t_next.tz[0] = 0;
				next_time =	gl_mktime(&t_next);
			}
		}
	}

	return node::postsync(t1);
}
Example #19
0
TIMESTAMP meter::postsync(TIMESTAMP t0, TIMESTAMP t1)
{
	OBJECT *obj = OBJECTHDR(this);
	complex temp_current;
	TIMESTAMP tretval;

	//Perform node update - do it now, otherwise current_inj isn't populated
	tretval = node::postsync(t1);

	measured_voltage[0] = voltageA;
	measured_voltage[1] = voltageB;
	measured_voltage[2] = voltageC;

	measured_voltageD[0] = voltageA - voltageB;
	measured_voltageD[1] = voltageB - voltageC;
	measured_voltageD[2] = voltageC - voltageA;

	if ((solver_method == SM_NR)||solver_method  == SM_FBS)
	{
		if (t1 > last_t)
		{
			dt = t1 - last_t;
			last_t = t1;
		}
		else
			dt = 0;
		
		measured_current[0] = current_inj[0];
		measured_current[1] = current_inj[1];
		measured_current[2] = current_inj[2];

		// compute energy use from previous cycle
		// - everything below this can moved to commit function once tape player is collecting from commit function7
		if (dt > 0 && last_t != dt)
		{	
			measured_real_energy += measured_real_power * TO_HOURS(dt);
			measured_reactive_energy += measured_reactive_power * TO_HOURS(dt);
		}

		// compute demand power
		indiv_measured_power[0] = measured_voltage[0]*(~measured_current[0]);
		indiv_measured_power[1] = measured_voltage[1]*(~measured_current[1]);
		indiv_measured_power[2] = measured_voltage[2]*(~measured_current[2]);

		measured_power = indiv_measured_power[0] + indiv_measured_power[1] + indiv_measured_power[2];

		measured_real_power = (indiv_measured_power[0]).Re()
							+ (indiv_measured_power[1]).Re()
							+ (indiv_measured_power[2]).Re();

		measured_reactive_power = (indiv_measured_power[0]).Im()
								+ (indiv_measured_power[1]).Im()
								+ (indiv_measured_power[2]).Im();

		if (measured_real_power > measured_demand) 
			measured_demand = measured_real_power;

		if (bill_mode == BM_UNIFORM || bill_mode == BM_TIERED)
		{
			if (dt > 0)
				process_bill(t1);

			// Decide when the next billing HAS to be processed (one month later)
			if (monthly_bill == previous_monthly_bill)
			{
				DATETIME t_next;
				gl_localtime(t1,&t_next);

				t_next.day = bill_day;

				if (t_next.month != 12)
					t_next.month += 1;
				else
				{
					t_next.month = 1;
					t_next.year += 1;
				}
				t_next.tz[0] = 0;
				next_time =	gl_mktime(&t_next);
			}
		}

		if( (bill_mode == BM_HOURLY || bill_mode == BM_TIERED_RTP) && power_market != NULL && price_prop != NULL){
			double seconds;
			if (dt != last_t)
				seconds = (double)(dt);
			else
				seconds = 0;
			
			if (seconds > 0)
			{
				hourly_acc += seconds/3600 * price * last_measured_real_power/1000;
				process_bill(t1);
			}

			// Now that we've accumulated the bill for the last time period, update to the new price
			double *pprice = (gl_get_double(power_market, price_prop));
			last_price = price = *pprice;
			last_measured_real_power = measured_real_power;

			if (monthly_bill == previous_monthly_bill)
			{
				DATETIME t_next;
				gl_localtime(t1,&t_next);

				t_next.day = bill_day;

				if (t_next.month != 12)
					t_next.month += 1;
				else
				{
					t_next.month = 1;
					t_next.year += 1;
				}
				t_next.tz[0] = 0;
				next_time =	gl_mktime(&t_next);
			}
		}
	}

	//Multi run (for now) updates to power values
	if (meter_NR_servered)
	{
		// compute demand power
		indiv_measured_power[0] = voltage[0]*(~current_inj[0]);
		indiv_measured_power[1] = voltage[1]*(~current_inj[1]);
		indiv_measured_power[2] = voltage[2]*(~current_inj[2]);
	}

	return tretval;
}
Example #20
0
//EXPORT for object-level call (as opposed to module-level)
EXPORT SIMULATIONMODE update_double_assert(OBJECT *obj, TIMESTAMP t0, unsigned int64 delta_time, unsigned long dt, unsigned int iteration_count_val)
{
	char buff[64];
	char dateformat[8]="";
	char error_output_buff[1024];
	char datebuff[64];
	double_assert *da = OBJECTDATA(obj,double_assert);
	DATETIME delta_dt_val;
	double del_clock;
	TIMESTAMP del_clock_int;
	int del_microseconds;
	double *x;

	if(da->get_once() == da->ONCE_TRUE){
		da->set_once_value(da->get_value());
		da->set_once(da->ONCE_DONE);
	} else if (da->get_once() == da->ONCE_DONE){
		if(da->get_once_value() == da->get_value()){
			gl_verbose("Assert skipped with ONCE logic");
			return SM_EVENT;
		} else {
			da->set_once_value(da->get_value());
		}
	}

	// get the within range
	double range = 0.0;
	if ( da->get_within_mode() == da->IN_RATIO ) 
	{
		range = da->get_value() * da->get_within();

		//if ( range<0.001 ) //minimum bounds removed since many deltamode items are small
		//{	// minimum bounds
		//	range = 0.001;
		//}
	} 
	else if ( da->get_within_mode()== da->IN_ABS ) 
	{
		range = da->get_within();
	}
		
	//Iteration checker - assert only valid on the first timestep
	if (iteration_count_val == 0)
	{
		//Skip first timestep of any delta iteration -- nature of delta means it really isn't checking the right one
		if (delta_time>=dt)
		{
			//Get value
			x = (double*)gl_get_double_by_name(obj->parent,da->get_target());

			if (x==NULL) 
			{
				gl_error("Specified target %s for %s is not valid.",da->get_target(),gl_name(obj->parent,buff,64));
				/*  TROUBLESHOOT
				Check to make sure the target you are specifying is a published variable for the object
				that you are pointing to.  Refer to the documentation of the command flag --modhelp, or 
				check the wiki page to determine which variables can be published within the object you
				are pointing to with the assert function.
				*/
				return SM_ERROR;
			}
			else if (da->get_status() == da->ASSERT_TRUE)
			{
				double m = fabs(*x-da->get_value());
				if (_isnan(m) || m>range)
				{
					//Calculate time
					if (delta_time>=dt)	//After first iteration
						del_clock  = (double)t0 + (double)(delta_time-dt)/(double)DT_SECOND;
					else	//First second different, don't back out
						del_clock  = (double)t0 + (double)(delta_time)/(double)DT_SECOND;

					del_clock_int = (TIMESTAMP)del_clock;	/* Whole seconds - update from global clock because we could be in delta for over 1 second */
					del_microseconds = (int)((del_clock-(int)(del_clock))*1000000+0.5);	/* microseconds roll-over - biased upward (by 0.5) */
					
					//Convert out
					gl_localtime(del_clock_int,&delta_dt_val);

					//Determine output format
					gl_global_getvar("dateformat",dateformat,sizeof(dateformat));

					//Output date appropriately
					if ( strcmp(dateformat,"ISO")==0)
						sprintf(datebuff,"ERROR    [%04d-%02d-%02d %02d:%02d:%02d.%.06d %s] : ",delta_dt_val.year,delta_dt_val.month,delta_dt_val.day,delta_dt_val.hour,delta_dt_val.minute,delta_dt_val.second,del_microseconds,delta_dt_val.tz);
					else if ( strcmp(dateformat,"US")==0)
						sprintf(datebuff,"ERROR    [%02d-%02d-%04d %02d:%02d:%02d.%.06d %s] : ",delta_dt_val.month,delta_dt_val.day,delta_dt_val.year,delta_dt_val.hour,delta_dt_val.minute,delta_dt_val.second,del_microseconds,delta_dt_val.tz);
					else if ( strcmp(dateformat,"EURO")==0)
						sprintf(datebuff,"ERROR    [%02d-%02d-%04d %02d:%02d:%02d.%.06d %s] : ",delta_dt_val.day,delta_dt_val.month,delta_dt_val.year,delta_dt_val.hour,delta_dt_val.minute,delta_dt_val.second,del_microseconds,delta_dt_val.tz);
					else
						sprintf(datebuff,"ERROR    .09f : ",del_clock);

					//Actual error part
					sprintf(error_output_buff,"Assert failed on %s - %s (%g) not within %f of given value %g",gl_name(obj->parent, buff, 64),da->get_target(), *x, da->get_within(), da->get_value());

					//Send it out
					gl_output("%s%s",datebuff,error_output_buff);

					return SM_ERROR;
				}
				gl_verbose("Assert passed on %s", gl_name(obj->parent, buff, 64));
				return SM_EVENT;
			}
			else if (da->get_status() == da->ASSERT_FALSE)
			{
				double m = fabs(*x-da->get_value());
				if (_isnan(m) || m<range)
				{				
					//Calculate time
					if (delta_time>=dt)	//After first iteration
						del_clock  = (double)t0 + (double)(delta_time-dt)/(double)DT_SECOND;
					else	//First second different, don't back out
						del_clock  = (double)t0 + (double)(delta_time)/(double)DT_SECOND;

					del_clock_int = (TIMESTAMP)del_clock;	/* Whole seconds - update from global clock because we could be in delta for over 1 second */
					del_microseconds = (int)((del_clock-(int)(del_clock))*1000000+0.5);	/* microseconds roll-over - biased upward (by 0.5) */
					
					//Convert out
					gl_localtime(del_clock_int,&delta_dt_val);

					//Determine output format
					gl_global_getvar("dateformat",dateformat,sizeof(dateformat));

					//Output date appropriately
					if ( strcmp(dateformat,"ISO")==0)
						sprintf(datebuff,"ERROR    [%04d-%02d-%02d %02d:%02d:%02d.%.06d %s] : ",delta_dt_val.year,delta_dt_val.month,delta_dt_val.day,delta_dt_val.hour,delta_dt_val.minute,delta_dt_val.second,del_microseconds,delta_dt_val.tz);
					else if ( strcmp(dateformat,"US")==0)
						sprintf(datebuff,"ERROR    [%02d-%02d-%04d %02d:%02d:%02d.%.06d %s] : ",delta_dt_val.month,delta_dt_val.day,delta_dt_val.year,delta_dt_val.hour,delta_dt_val.minute,delta_dt_val.second,del_microseconds,delta_dt_val.tz);
					else if ( strcmp(dateformat,"EURO")==0)
						sprintf(datebuff,"ERROR    [%02d-%02d-%04d %02d:%02d:%02d.%.06d %s] : ",delta_dt_val.day,delta_dt_val.month,delta_dt_val.year,delta_dt_val.hour,delta_dt_val.minute,delta_dt_val.second,del_microseconds,delta_dt_val.tz);
					else
						sprintf(datebuff,"ERROR    .09f : ",del_clock);

					//Actual error part
					sprintf(error_output_buff,"Assert failed on %s - %s (%g) not within %f of given value %g",gl_name(obj->parent, buff, 64),da->get_target(), *x, da->get_within(), da->get_value());

					//Send it out
					gl_output("%s%s",datebuff,error_output_buff);

					return SM_ERROR;
				}
				gl_verbose("Assert passed on %s", gl_name(obj->parent, buff, 64));
				return SM_EVENT;
			}
			else
			{
				gl_verbose("Assert test is not being run on %s", gl_name(obj->parent, buff, 64));
				return SM_EVENT;
			}
		}
		else	//First pass, just proceed
			return SM_EVENT;
	}
	else	//Iteration, so don't care
		return SM_EVENT;
}
Example #21
0
TIMESTAMP csv_reader::get_data(TIMESTAMP t0, double *temp, double *humid, double *direct, double *diffuse, double *global, double *wind, double *rain, double *snow){
	DATETIME now, then;
//	TIMESTAMP until;
	int next_year = 0;
	int i = 0;
	int idx = index;
	int start = index;

	int localres;

	if(t0 < next_ts){ /* still good ~ go home */
		return -next_ts;
	}

	localres = gl_localtime(t0, &now); // error check

	if(next_ts == 0){
		//	initialize to the correct index & next_ts
		DATETIME guess_dt;
		TIMESTAMP guess_ts;
		int i;
		for(i = 0; i < sample_ct; ++i){
			guess_dt.year = now.year;
			guess_dt.month = samples[sample_ct-i-1]->month;
			guess_dt.day = samples[sample_ct-i-1]->day;
			guess_dt.hour = samples[sample_ct-i-1]->hour;
			guess_dt.minute = samples[sample_ct-i-1]->minute;
			guess_dt.second = samples[sample_ct-i-1]->second;
			strcpy(guess_dt.tz, now.tz);
//			strcpy(guess_dt.tz, "GMT");
			guess_ts = (TIMESTAMP)gl_mktime(&guess_dt);

			if(guess_ts <= t0){
				break;
			}
		}
		index = sample_ct - i - 1;

		if(index > -1){
			*temp = samples[index]->temperature;
			*humid = samples[index]->humidity;
			*direct = samples[index]->solar_dir;
			*diffuse = samples[index]->solar_diff;
			*global = samples[index]->solar_global;
			*wind = samples[index]->wind_speed;
			*rain = samples[index]->rainfall;
			*snow = samples[index]->snowdepth;
		} else {
			*temp = samples[sample_ct - 1]->temperature;
			*humid = samples[sample_ct - 1]->humidity;
			*direct = samples[sample_ct - 1]->solar_dir;
			*diffuse = samples[sample_ct - 1]->solar_diff;
			*global = samples[sample_ct - 1]->solar_global;
			*wind = samples[sample_ct - 1]->wind_speed;
			*rain = samples[sample_ct - 1]->rainfall;
			*snow = samples[sample_ct - 1]->snowdepth;
		}

		then.year = now.year + (index+1 == sample_ct ? 1 : 0);
		then.month = samples[(index+1)%sample_ct]->month;
		then.day = samples[(index+1)%sample_ct]->day;
		then.hour = samples[(index+1)%sample_ct]->hour;
		then.minute = samples[(index+1)%sample_ct]->minute;
		then.second = samples[(index+1)%sample_ct]->second;
		strcpy(then.tz, now.tz);

		next_ts = (TIMESTAMP)gl_mktime(&then);
		//next_ts = (TIMESTAMP)gl_mktime(&then);

		return -next_ts;
	}

	if(sample_ct == 1){ /* only one sample ~ ignore it and keep feeding the same data back, but in a year */
		next_ts += 365 * 24 * 3600;
		return -next_ts;
	}

	do{
		// should we roll the year over?
		if(index+1 >= sample_ct){
			index = 0;
		} else {
			++index;
		}

		if(index+1 == sample_ct){
			next_year = 1;
		} else {
			next_year = 0;
		}

		then.year = now.year + next_year;
		then.month = samples[(index+1)%sample_ct]->month;
		then.day = samples[(index+1)%sample_ct]->day;
		then.hour = samples[(index+1)%sample_ct]->hour;
		then.minute = samples[(index+1)%sample_ct]->minute;
		then.second = samples[(index+1)%sample_ct]->second;
		strcpy(then.tz, now.tz);

		// next_ts is the time the current sample is overwritten by another sample.
		next_ts = (TIMESTAMP)gl_mktime(&then);
	} while (next_ts < t0 && index != start); // skip samples that try to reverse the time
	
	*temp = samples[index]->temperature;
	*humid = samples[index]->humidity;
	*direct = samples[index]->solar_dir;
	*diffuse = samples[index]->solar_diff;
	*global = samples[index]->solar_global;
	*wind = samples[index]->wind_speed;
	*rain = samples[index]->rainfall;
	*snow = samples[index]->snowdepth;

	// having found the index, update the data
	if(index == start){
		GL_THROW("something strange happened with the schedule in csv_reader");
		/*	TROUBLESHOOT
			An unidentified error occured while reading data and constructing the weather
			data schedule.  Please post a ticket detailing this event on the GridLAB-D
			SourceForge page.
		*/
	}
	
	return -next_ts;
}
Example #22
0
// Synchronize a distribution triplex_meter
TIMESTAMP triplex_meter::postsync(TIMESTAMP t0, TIMESTAMP t1)
{
	OBJECT *obj = OBJECTHDR(this);
	TIMESTAMP rv = TS_NEVER;
	TIMESTAMP hr = TS_NEVER;

	//Call node postsync now, otherwise current_inj isn't right
	rv = triplex_node::postsync(t1);

	//measured_voltage[0] = voltageA;
	//measured_voltage[1] = voltageB;
	//measured_voltage[2] = voltageC;
	measured_voltage[0].SetPolar(voltageA.Mag(),voltageA.Arg());
	measured_voltage[1].SetPolar(voltageB.Mag(),voltageB.Arg());
	measured_voltage[2].SetPolar(voltageC.Mag(),voltageC.Arg());

	if (t1 > last_t)
	{
		dt = t1 - last_t;
		last_t = t1;
	}
	else
		dt = 0;

	//READLOCK_OBJECT(obj);
	measured_current[0] = current_inj[0];
	measured_current[1] = current_inj[1];
	//READUNLOCK_OBJECT(obj);
	measured_current[2] = -(measured_current[1]+measured_current[0]);

//		if (dt > 0 && last_t != dt)
	if (dt > 0)
	{
		measured_real_energy += measured_real_power * TO_HOURS(dt);
		measured_reactive_energy += measured_reactive_power * TO_HOURS(dt);
	}

	indiv_measured_power[0] = measured_voltage[0]*(~measured_current[0]);
	indiv_measured_power[1] = complex(-1,0) * measured_voltage[1]*(~measured_current[1]);
	indiv_measured_power[2] = measured_voltage[2]*(~measured_current[2]);

	measured_power = indiv_measured_power[0] + indiv_measured_power[1] + indiv_measured_power[2];

	measured_real_power = (indiv_measured_power[0]).Re()
						+ (indiv_measured_power[1]).Re()
						+ (indiv_measured_power[2]).Re();

	measured_reactive_power = (indiv_measured_power[0]).Im()
							+ (indiv_measured_power[1]).Im()
							+ (indiv_measured_power[2]).Im();

	if (measured_real_power>measured_demand)
		measured_demand=measured_real_power;



	if (bill_mode == BM_UNIFORM || bill_mode == BM_TIERED)
	{
		if (dt > 0)
			process_bill(t1);

		// Decide when the next billing HAS to be processed (one month later)
		if (monthly_bill == previous_monthly_bill)
		{
			DATETIME t_next;
			gl_localtime(t1,&t_next);

			t_next.day = bill_day;

			if (t_next.month != 12)
				t_next.month += 1;
			else
			{
				t_next.month = 1;
				t_next.year += 1;
			}
			t_next.tz[0] = 0;
			next_time =	gl_mktime(&t_next);
		}
	}

	if( (bill_mode == BM_HOURLY || bill_mode == BM_TIERED_RTP) && power_market != NULL && price_prop != NULL){
		double seconds;
		if (dt != last_t)
			seconds = (double)(dt);
		else
			seconds = 0;
		
		if (seconds > 0)
		{
			hourly_acc += seconds/3600 * price * last_measured_real_power/1000;
			process_bill(t1);
		}

		// Now that we've accumulated the bill for the last time period, update to the new price
		double *pprice = (gl_get_double(power_market, price_prop));
		last_price = price = *pprice;
		last_measured_real_power = measured_real_power;

		if (monthly_bill == previous_monthly_bill)
		{
			DATETIME t_next;
			gl_localtime(t1,&t_next);

			t_next.day = bill_day;

			if (t_next.month != 12)
				t_next.month += 1;
			else
			{
				t_next.month = 1;
				t_next.year += 1;
			}
			t_next.tz[0] = 0;
			next_time =	gl_mktime(&t_next);
		}
	}

	if (next_time != 0 && next_time < rv)
		return -next_time;
	else
		return rv;
}
Example #23
0
//Solar radiation calcuation based on solpos and Perez tilt models
EXPORT int64 calc_solar_solpos_shading_rad(OBJECT *obj, double tilt, double orientation, double shading_value, double *value)
{
	static SolarAngles sa; // just for the functions
	double ghr, dhr, dnr;
	double cos_incident;
	double temp_value;
	DATETIME dt;
	TIMESTAMP offsetclock;

	climate *cli;
	if(obj == 0 || value == 0){
		return 0;
	}
	cli = OBJECTDATA(obj, climate);
	if(gl_object_isa(obj, "climate", "climate") == 0){
		return 0;
	}
	ghr = cli->solar_global;
	dhr = cli->solar_diffuse;
	dnr = cli->solar_direct;

	if (cli->reader_type==cli->RT_TMY2)
	{
		//Adjust time by half an hour - adjusts per TMY "reading" intervals - what they really represent
		offsetclock = obj->clock + 1800;
	}
	else	//Just pass it in
	{
		offsetclock = obj->clock;
	}
	
	gl_localtime(offsetclock, &dt);

	//Convert temperature back to centrigrade - since we seem to like imperial units
	temp_value = ((cli->temperature - 32.0)*5.0/9.0);

	//Initialize solpos algorithm
	sa.S_init(&sa.solpos_vals);

	//Assign in values
	sa.solpos_vals.longitude = obj->longitude;
	sa.solpos_vals.latitude = RAD(obj->latitude);
	if (dt.is_dst == 1)
	{
		sa.solpos_vals.timezone = cli->tz_offset_val-1.0;
	}
	else
	{
		sa.solpos_vals.timezone = cli->tz_offset_val;
	}
	sa.solpos_vals.year = dt.year;
	sa.solpos_vals.daynum = (dt.yearday+1);
	sa.solpos_vals.hour = dt.hour;
	sa.solpos_vals.minute = dt.minute;
	sa.solpos_vals.second = dt.second;
	sa.solpos_vals.temp = temp_value;
	sa.solpos_vals.press = cli->pressure;

	// Solar constant associated with extraterrestrial DNI, 1367 W/sq m - pull from TMY for now
	//sa.solpos_vals.solcon = 126.998456;	//Use constant value for direct normal extraterrestrial irradiance - doesn't seem right to me
	sa.solpos_vals.solcon = cli->direct_normal_extra;	//Use weather-read version (TMY)

	sa.solpos_vals.aspect = orientation;
	sa.solpos_vals.tilt = tilt;
	sa.solpos_vals.diff_horz = dhr;
	sa.solpos_vals.dir_norm = dnr;

	//Calculate different solar position values
	sa.S_solpos(&sa.solpos_vals);

	//Pull off new cosine of incidence
	if (sa.solpos_vals.cosinc >= 0.0)
		cos_incident = sa.solpos_vals.cosinc;
	else
		cos_incident = 0.0;

	//Apply the adjustment
	*value = (shading_value*dnr*cos_incident) + dhr*sa.solpos_vals.perez_horz + ghr*((1 - cos(tilt))*cli->ground_reflectivity/2.0);

	return 1;
}
// Synchronize a distribution triplex_meter
TIMESTAMP triplex_meter::postsync(TIMESTAMP t0, TIMESTAMP t1)
{
	TIMESTAMP rv = TS_NEVER;
	TIMESTAMP hr = TS_NEVER;

	//measured_voltage[0] = voltageA;
	//measured_voltage[1] = voltageB;
	//measured_voltage[2] = voltageC;
	measured_voltage[0].SetPolar(voltageA.Mag(),voltageA.Arg());
	measured_voltage[1].SetPolar(voltageB.Mag(),voltageB.Arg());
	measured_voltage[2].SetPolar(voltageC.Mag(),voltageC.Arg());

	if ((solver_method == SM_NR && NR_cycle == true)||solver_method  == SM_FBS)
	{
		//Reliability addition - clear momentary flag if set
		if (tpmeter_interrupted_secondary == true)
			tpmeter_interrupted_secondary = false;

		if (t1 > last_t)
		{
			dt = t1 - last_t;
			last_t = t1;
		}
		else
			dt = 0;

		measured_current[0] = current_inj[0];
		measured_current[1] = current_inj[1];
		measured_current[2] = -(measured_current[1]+measured_current[0]);

//		if (dt > 0 && last_t != dt)
		if (dt > 0)
		{
			measured_real_energy += measured_real_power * TO_HOURS(dt);
			measured_reactive_energy += measured_reactive_power * TO_HOURS(dt);
		}

		indiv_measured_power[0] = measured_voltage[0]*(~measured_current[0]);
		indiv_measured_power[1] = complex(-1,0) * measured_voltage[1]*(~measured_current[1]);
		indiv_measured_power[2] = measured_voltage[2]*(~measured_current[2]);

		measured_power = indiv_measured_power[0] + indiv_measured_power[1] + indiv_measured_power[2];

		measured_real_power = (indiv_measured_power[0]).Re()
							+ (indiv_measured_power[1]).Re()
							+ (indiv_measured_power[2]).Re();

		measured_reactive_power = (indiv_measured_power[0]).Im()
								+ (indiv_measured_power[1]).Im()
								+ (indiv_measured_power[2]).Im();

		if (measured_real_power>measured_demand)
			measured_demand=measured_real_power;



		if (bill_mode == BM_UNIFORM || bill_mode == BM_TIERED)
		{
			if (dt > 0)
				process_bill(t1);

			// Decide when the next billing HAS to be processed (one month later)
			if (monthly_bill == previous_monthly_bill)
			{
				DATETIME t_next;
				gl_localtime(t1,&t_next);

				t_next.day = bill_day;

				if (t_next.month != 12)
					t_next.month += 1;
				else
				{
					t_next.month = 1;
					t_next.year += 1;
				}
				t_next.tz[0] = 0;
				next_time =	gl_mktime(&t_next);
			}
		}

		if( (bill_mode == BM_HOURLY || bill_mode == BM_TIERED_RTP) && power_market != NULL && price_prop != NULL){
			double seconds;
			if (dt != last_t)
				seconds = (double)(dt);
			else
				seconds = 0;
			
			if (seconds > 0)
			{
				hourly_acc += seconds/3600 * price * measured_real_power/1000;
				process_bill(t1);
			}

			// Now that we've accumulated the bill for the last time period, update to the new price
			double *pprice = (gl_get_double(power_market, price_prop));
			last_price = price = *pprice;

			if (monthly_bill == previous_monthly_bill)
			{
				DATETIME t_next;
				gl_localtime(t1,&t_next);

				t_next.day = bill_day;

				if (t_next.month != 12)
					t_next.month += 1;
				else
				{
					t_next.month = 1;
					t_next.year += 1;
				}
				t_next.tz[0] = 0;
				next_time =	gl_mktime(&t_next);
			}
		}
	}
	rv = triplex_node::postsync(t1);

	if (next_time != 0 && next_time < rv)
		return -next_time;
	else
		return rv;
	//return triplex_node::postsync(t1);

}
Example #25
0
TIMESTAMP climate::presync(TIMESTAMP t0) /* called in presync */
{
	TIMESTAMP rv = 0;
	if(t0 > TS_ZERO && reader_type == RT_CSV){
		DATETIME now;
		gl_localtime(t0, &now);
		//OBJECT *obj = OBJECTHDR(this);
		csv_reader *cr = OBJECTDATA(reader,csv_reader);
		rv = cr->get_data(t0, &temperature, &humidity, &solar_direct, &solar_diffuse, &solar_global, &wind_speed, &rainfall, &snowdepth, &pressure);
		// calculate the solar radiation
		double sol_time = sa->solar_time((double)now.hour+now.minute/60.0+now.second/3600.0 + (now.is_dst ? -1:0),now.yearday,RAD(tz_meridian),RAD(reader->longitude));
		double sol_rad = 0.0;

		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,now.yearday,RAD(reader->latitude),sol_time,solar_direct,solar_diffuse,solar_global,ground_reflectivity,0.0);//(double)dnr * cos_incident + dhr;
			else
				sol_rad = file.calc_solar(c_point,now.yearday,RAD(reader->latitude),sol_time,solar_direct,solar_diffuse,solar_global,ground_reflectivity);//(double)dnr * cos_incident + dhr;
			/* TMY2 solar radiation data is in Watt-hours per square meter. */
			solar_flux[c_point] = sol_rad;
		}
		return rv;
	}
	if (t0>TS_ZERO && tmy!=NULL)
	{
		DATETIME ts;
		int localres = gl_localtime(t0,&ts);
		int hoy;
		double now, hoy0, hoy1, hoy2;
		if(localres == 0){
			GL_THROW("climate::sync -- unable to resolve localtime!");
		}
		int doy = sa->day_of_yr(ts.month,ts.day);
		hoy = (doy - 1) * 24 + (ts.hour);
		switch(interpolate){
			case CI_NONE:
				temperature = tmy[hoy].temp;
				temperature_raw = tmy[hoy].temp_raw;
				humidity = tmy[hoy].rh;
				solar_direct = tmy[hoy].dnr;
				solar_diffuse = tmy[hoy].dhr;
				solar_global = tmy[hoy].ghr;
				solar_raw = tmy[hoy].solar_raw;
				solar_azimuth = tmy[hoy].solar_azimuth;
				solar_elevation = tmy[hoy].solar_elevation;

				pressure = tmy[hoy].pressure;
				direct_normal_extra = tmy[hoy].direct_normal_extra;

				this->wind_speed = tmy[hoy].windspeed;
				this->rainfall = tmy[hoy].rainfall;
				this->snowdepth = tmy[hoy].snowdepth;

				if(memcmp(solar_flux,tmy[hoy].solar,CP_LAST*sizeof(double)))
					memcpy(solar_flux,tmy[hoy].solar,CP_LAST*sizeof(double));
				break;
			case CI_LINEAR:
				now = hoy+ts.minute/60.0;
				hoy0 = hoy;
				hoy1 = hoy+1.0;
				temperature = gl_lerp(now, hoy0, tmy[hoy].temp, hoy1, tmy[hoy+1%8760].temp);
				temperature_raw = gl_lerp(now, hoy0, tmy[hoy].temp_raw, hoy1, tmy[hoy+1%8760].temp_raw);
				humidity = gl_lerp(now, hoy0, tmy[hoy].rh, hoy1, tmy[hoy+1%8760].rh);
				solar_direct = gl_lerp(now, hoy0, tmy[hoy].dnr, hoy1, tmy[hoy+1%8760].dnr);
				solar_diffuse = gl_lerp(now, hoy0, tmy[hoy].dhr, hoy1, tmy[hoy+1%8760].dhr);
				solar_global = gl_lerp(now, hoy0, tmy[hoy].ghr, hoy1, tmy[hoy+1%8760].ghr);
				solar_azimuth = gl_lerp(now, hoy0, tmy[hoy].solar_azimuth, hoy1, tmy[hoy+1%8760].solar_azimuth);
				solar_elevation = gl_lerp(now, hoy0, tmy[hoy].solar_elevation, hoy1, tmy[hoy+1%8760].solar_elevation);
				wind_speed = gl_lerp(now, hoy0, tmy[hoy].windspeed, hoy1, tmy[hoy+1%8760].windspeed);
				rainfall = gl_lerp(now, hoy0, tmy[hoy].rainfall, hoy1, tmy[hoy+1%8760].rainfall);
				snowdepth = gl_lerp(now, hoy0, tmy[hoy].snowdepth, hoy1, tmy[hoy+1%8760].snowdepth);
				solar_raw = gl_lerp(now, hoy0, tmy[hoy].solar_raw, hoy1, tmy[hoy+1%8760].solar_raw);
				pressure = gl_lerp(now, hoy0, tmy[hoy].pressure, hoy1, tmy[hoy+1%8760].pressure);
				direct_normal_extra = gl_lerp(now, hoy0, tmy[hoy].direct_normal_extra, hoy1, tmy[hoy+1%8760].direct_normal_extra);
				for(int pt = 0; pt < CP_LAST; ++pt){
					solar_flux[pt] = gl_lerp(now, hoy0, tmy[hoy].solar[pt], hoy1, tmy[hoy+1%8760].solar[pt]);
				}
				break;
			case CI_QUADRATIC:
				now = hoy+ts.minute/60.0;
				hoy0 = hoy;
				hoy1 = hoy+1.0;
				hoy2 = hoy+2.0;
				temperature = gl_qerp(now, hoy0, tmy[hoy].temp, hoy1, tmy[hoy+1%8760].temp, hoy2, tmy[hoy+2%8760].temp);
				temperature_raw = gl_qerp(now, hoy0, tmy[hoy].temp_raw, hoy1, tmy[hoy+1%8760].temp_raw, hoy2, tmy[hoy+2%8760].temp_raw);
				humidity = gl_qerp(now, hoy0, tmy[hoy].rh, hoy1, tmy[hoy+1%8760].rh, hoy2, tmy[hoy+2%8760].rh);
				if(humidity < 0.0){
					humidity = 0.0;
					gl_verbose("Setting humidity to zero. Quadratic interpolation caused the humidity to drop below zero.");
				}
				solar_direct = gl_qerp(now, hoy0, tmy[hoy].dnr, hoy1, tmy[hoy+1%8760].dnr, hoy2, tmy[hoy+2%8760].dnr);
				if(solar_direct < 0.0){
					solar_direct = 0.0;
					gl_verbose("Setting solar_direct to zero. Quadratic interpolation caused the solar_direct to drop below zero.");
				}
				solar_diffuse = gl_qerp(now, hoy0, tmy[hoy].dhr, hoy1, tmy[hoy+1%8760].dhr, hoy2, tmy[hoy+2%8760].dhr);
				if(solar_diffuse < 0.0){
					solar_diffuse = 0.0;
					gl_verbose("Setting solar_diffuse to zero. Quadratic interpolation caused the solar_diffuse to drop below zero.");
				}
				solar_global = gl_qerp(now, hoy0, tmy[hoy].ghr, hoy1, tmy[hoy+1%8760].ghr, hoy2, tmy[hoy+2%8760].ghr);
				if(solar_global < 0.0){
					solar_global = 0.0;
					gl_verbose("Setting solar_global to zero. Quadratic interpolation caused the solar_global to drop below zero.");
				}
				solar_azimuth = gl_qerp(now, hoy0, tmy[hoy].solar_azimuth, hoy1, tmy[hoy+1%8760].solar_azimuth, hoy2, tmy[hoy+2%8760].solar_azimuth);
				solar_elevation = gl_qerp(now, hoy0, tmy[hoy].solar_elevation, hoy1, tmy[hoy+1%8760].solar_elevation, hoy2, tmy[hoy+2%8760].solar_elevation);
				wind_speed = gl_qerp(now, hoy0, tmy[hoy].windspeed, hoy1, tmy[hoy+1%8760].windspeed, hoy2, tmy[hoy+2%8760].windspeed);
				if(wind_speed < 0.0){
					wind_speed = 0.0;
					gl_verbose("Setting wind_speed to zero. Quadratic interpolation caused the wind_speed to drop below zero.");
				}
				rainfall = gl_qerp(now, hoy0, tmy[hoy].rainfall, hoy1, tmy[hoy+1%8760].rainfall, hoy2, tmy[hoy+2%8760].rainfall);
				if(rainfall < 0.0){
					rainfall = 0.0;
					gl_verbose("Setting rainfall to zero. Quadratic interpolation caused the rainfall to drop below zero.");
				}
				snowdepth = gl_qerp(now, hoy0, tmy[hoy].snowdepth, hoy1, tmy[hoy+1%8760].snowdepth, hoy2, tmy[hoy+2%8760].snowdepth);
				if(snowdepth < 0.0){
					snowdepth = 0.0;
					gl_verbose("Setting snowdepth to zero. Quadratic interpolation caused the snowdepth to drop below zero.");
				}
				solar_raw = gl_qerp(now, hoy0, tmy[hoy].solar_raw, hoy1, tmy[hoy+1%8760].solar_raw, hoy2, tmy[hoy+2%8760].solar_raw);
				if(solar_raw < 0.0){
					solar_raw = 0.0;
					gl_verbose("Setting solar_raw to zero. Quadratic interpolation caused the solar_raw to drop below zero.");
				}
				pressure = gl_qerp(now, hoy0, tmy[hoy].pressure, hoy1, tmy[hoy+1%8760].pressure, hoy2, tmy[hoy+2%8760].pressure);
				if(pressure < 0.0){
					pressure = 0.0;
					gl_verbose("Setting pressure to zero. Quadratic interpolation caused the pressure to drop below zero.");
				}
				direct_normal_extra = gl_qerp(now, hoy0, tmy[hoy].direct_normal_extra, hoy1, tmy[hoy+1%8760].direct_normal_extra, hoy2, tmy[hoy+2%8760].direct_normal_extra);
				if(direct_normal_extra < 0.0){
					direct_normal_extra = 0.0;
					gl_verbose("Setting extraterrestrial_direct_normal to zero. Quadratic interpolation caused the extraterrestrial_direct_normal to drop below zero.");
				}
				for(int pt = 0; pt < CP_LAST; ++pt){
					if(tmy[hoy].solar[pt] == tmy[hoy+1].solar[pt]){
						solar_flux[pt] = tmy[hoy].solar[pt];
					} else {
						solar_flux[pt] = gl_qerp(now, hoy0, tmy[hoy].solar[pt], hoy1, tmy[hoy+1%8760].solar[pt], hoy2, tmy[hoy+2%8760].solar[pt]);
						if(solar_flux[pt] < 0.0)
							solar_flux[pt] = 0.0; /* quadratic isn't always cooperative... */
					}
				}
				break;
			default:
				GL_THROW("climate::sync -- unrecognize interpolation mode!");
		}
		update_forecasts(t0);
		return -(t0+(3600*TS_SECOND-t0%(3600 *TS_SECOND))); /// negative means soft event
	}
	return TS_NEVER;
}
Example #26
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;
}
Example #27
0
TIMESTAMP histogram::sync(TIMESTAMP t0, TIMESTAMP t1)
{
	int i = 0;
	double value = 0.0;
	OBJECT *obj = OBJECTHDR(this);

	if((sampling_interval == -1.0 && t_count > t1) ||
		sampling_interval == 0.0 ||
		(sampling_interval > 0.0 && t1 >= next_sample))
	{
		if(group_list == NULL){
			feed_bins(obj->parent);
		} else {
			OBJECT *obj = gl_find_next(group_list, NULL);
			for(; obj != NULL; obj = gl_find_next(group_list, obj)){
				feed_bins(obj);
			}
		}
		t_sample = t1;
		if(sampling_interval > 0.0001){
			next_sample = t1 + (int64)(sampling_interval/TS_SECOND);
		} else {
			next_sample = TS_NEVER;
		}
	}

	if((counting_interval == -1.0 && t_count < t1) ||
		counting_interval == 0.0 ||
		(counting_interval > 0.0 && t1 >= next_count))
	{
		char line[1025];
		char ts[64];
		int off=0, i=0;
		DATETIME dt;

		/* write the timestamp */
		gl_localtime(t1,&dt);
		gl_strtime(&dt,ts,64);
		
		/* write bins */
		for(i = 0; i < bin_count; ++i){
			off += sprintf(line+off, "%i", binctr[i]);
			if(i != bin_count){
				off += sprintf(line+off, ",");
			}
		}

		/* write line */
		ops->write(this, ts, line);
		
		/* cleanup */
		for(i = 0; i < bin_count; ++i){
			binctr[i] = 0;
		}
		t_count = t1;
		if(counting_interval > 0){
			next_count = t_count + (int64)(counting_interval/TS_SECOND);
		} else {
			next_count = TS_NEVER;
		}


		if(--limit < 1){
			ops->close(this);
			next_count = TS_NEVER;
			next_sample = TS_NEVER;
		}
	}
	return ( next_count < next_sample && counting_interval > 0.0 ? next_count : next_sample );
}