Esempio n. 1
0
TIMESTAMP house::sync_panel(TIMESTAMP t0, TIMESTAMP t1)
{
	TIMESTAMP sync_time = TS_NEVER;
	OBJECT *obj = OBJECTHDR(this);

	// clear accumulators for panel currents
	complex I[3]; I[X12] = I[X23] = I[X13] = complex(0,0);

	// clear heatgain accumulator
	double heatgain = 0;

	// gather load power and compute current for each circuit
	CIRCUIT *c;
	for (c=panel.circuits; c!=NULL; c=c->next)
	{
		// get circuit type
		int n = (int)c->type;
		if (n<0 || n>2)
			GL_THROW("%s:%d circuit %d has an invalid circuit type (%d)", obj->oclass->name, obj->id, c->id, (int)c->type);
		/*	TROUBLESHOOT
			Invalid circuit types are an internal error for the house panel.  Please report this error.  The likely causes
			include an object that is not a house is being processed by the house model, or the panel was not correctly
			initialized.
		*/

		// if breaker is open and reclose time has arrived
		if (c->status==BRK_OPEN && t1>=c->reclose)
		{
			c->status = BRK_CLOSED;
			c->reclose = TS_NEVER;
			sync_time = t1; // must immediately reevaluate devices affected
			gl_debug("house:%d panel breaker %d closed", obj->id, c->id);
		}

		// if breaker is closed
		if (c->status==BRK_CLOSED)
		{
			// compute circuit current
			if ((c->pV)->Mag() == 0)
			{
				gl_debug("house:%d circuit %d (enduse %s) voltage is zero", obj->id, c->id, c->pLoad->name);
				break;
			}
			
			complex current = ~(c->pLoad->total*1000 / *(c->pV)); 

			// check breaker
			if (c->max_amps>0 && current.Mag()>c->max_amps)
			{
				// probability of breaker failure increases over time
				if (c->tripsleft>0 && gl_random_bernoulli(RNGSTATE,1/(c->tripsleft--))==0)
				{
					// breaker opens
					c->status = BRK_OPEN;

					// average five minutes before reclosing, exponentially distributed
					c->reclose = t1 + (TIMESTAMP)(gl_random_exponential(RNGSTATE,1/300.0)*TS_SECOND); 
					gl_debug("house:%d circuit breaker %d tripped - enduse %s overload at %.0f A", obj->id, c->id,
						c->pLoad->name, current.Mag());
				}

				// breaker fails from too frequent operation
				else
				{
					c->status = BRK_FAULT;
					c->reclose = TS_NEVER;
					gl_debug("house:%d circuit breaker %d failed", obj->id, c->id);
				}

				// must immediately reevaluate everything
				sync_time = t1; 
			}

			// add to panel current
			else
			{
				tload.power += c->pLoad->power;	// reminder: |a| + |b| != |a+b|
				tload.current += c->pLoad->current;
				tload.admittance += c->pLoad->admittance; // should this be additive? I don't buy t.a = c->pL->a ... -MH
				tload.total += c->pLoad->total;
				tload.heatgain += c->pLoad->heatgain;
				tload.energy += c->pLoad->power * gl_tohours(t1-t0);
				I[n] += current;
				c->reclose = TS_NEVER;
			}
		}

		// sync time
		if (sync_time > c->reclose)
			sync_time = c->reclose;
	}

	// compute line currents and post to meter
	if (obj->parent != NULL)
		LOCK_OBJECT(obj->parent);

	pLine_I[0] = I[X13];
	pLine_I[1] = I[X23];
	pLine_I[2] = 0;
	*pLine12 = I[X12];

	if (obj->parent != NULL)
		UNLOCK_OBJECT(obj->parent);

	return sync_time;
}
Esempio n. 2
0
/**
* Fuse checking function
* Hold over code from previous functionality - lets FBS work as-is, for now.
*
* functionalized so don't have to change 4 entries in 3 different sets every time
*
* @param phase_to_check - the current phase to check fusing action for
* @param fcurr - array of from (line input) currents
*/
void fuse::fuse_check(set phase_to_check, complex *fcurr)
{
	char indexval;
	char phase_verbose;
	unsigned char work_phase;
	FUSESTATE *valstate;
	TIMESTAMP *fixtime;
	OBJECT *hdr = OBJECTHDR(this);

	if (phase_to_check == PHASE_A)
	{
		indexval = 0;
		valstate = (FUSESTATE*)&phase_A_state;
		phase_verbose='A';
		fixtime = &fix_time[0];
	}
	else if (phase_to_check == PHASE_B)
	{
		indexval = 1;
		valstate = (FUSESTATE*)&phase_B_state;
		phase_verbose='B';
		fixtime = &fix_time[1];
	}
	else if (phase_to_check == PHASE_C)
	{
		indexval = 2;
		valstate = (FUSESTATE*)&phase_C_state;
		phase_verbose='C';
		fixtime = &fix_time[2];
	}
	else
	{
		GL_THROW("Unknown phase to check in fuse:%d",OBJECTHDR(this)->id);
		/*  TROUBLESHOOT
		An invalid phase was specified for the phase check in a fuse.  Please
		check your code and continue.  If it persists, submit your code and a bug
		using the trac website.
		*/
	}

	//See which phases we need to check
	if ((phases & phase_to_check) == phase_to_check)	//Check phase
	{
		work_phase = 0x04 >> indexval;	//Working variable, primarily for NR

		if (*valstate == GOOD)	//Only bother if we are in service
		{
			//Check both directions, that way if we are reverse flowed it doesn't matter
			if (fcurr[indexval].Mag() > current_limit)	//We've exceeded the limit
			{
				*valstate = BLOWN;	//Trip us

				//Set us up appropriately
				A_mat[indexval][indexval] = d_mat[indexval][indexval] = 0.0;

				//Get an update time
				*fixtime = prev_fuse_time + (int64)(3600*gl_random_exponential(RNGSTATE,1.0/mean_replacement_time));

				//Announce it for giggles
				gl_warning("Phase %c of fuse:%d (%s) just blew",phase_verbose,hdr->id,hdr->name);
			}
			else	//Still good
			{
				//Ensure matrices are up to date in case someone manually set things
				A_mat[indexval][indexval] = d_mat[indexval][indexval] = 1.0;
			}
		}
		else						//We're blown
		{
			if (*fixtime <= prev_fuse_time)	//Technician has arrived and replaced us!!
			{
				//Fix us
				A_mat[indexval][indexval] = d_mat[indexval][indexval] = 1.0;

				*valstate = GOOD;
				*fixtime = TS_NEVER;	//Update the time check just in case

				//Send an announcement for giggles
				gl_warning("Phase %c of fuse:%d (%s) just returned to service",phase_verbose,hdr->id,hdr->name);
			}
			else //Still driving there or on break, no fixed yet
			{
				//Ensure matrices are up to date in case someone manually blew us (or a third, off state is implemented)
				A_mat[indexval][indexval] = d_mat[indexval][indexval] = 0.0;
			}
		}
	}
Esempio n. 3
0
TIMESTAMP relay::sync(TIMESTAMP t0)
{
	TIMESTAMP t1 = TS_NEVER;
	node *f;
	node *t;
	set reverse = get_flow(&f,&t);

#ifdef SUPPORT_OUTAGES
	//Handle explicit trips differently
	if (recloser_event)
	{
		//Make sure we aren't locked out
		if ((recloser_reset_time != 0) && (recloser_reset_time<=t0))	//We're done
		{
			//Reset all of the variables
			recloser_reset_time = 0;
			recloser_delay_time = 0;
			current_recloser_tries = 0;
			status = LS_CLOSED;
			t1 = TS_NEVER;	//Just flag us as something small to continue
			gl_verbose("Recloser:%d just unlocked and rejoined service",OBJECTHDR(this)->id);
		}
		else if ((recloser_reset_time != 0 ) && (recloser_reset_time>t0))	//Not done being locked out
		{
			status=LS_OPEN;	//Make sure we are still open
			t1 = recloser_reset_time;
		}
		else //Should be normal area
		{
			if (status==LS_OPEN)	//Open operations - only if a reliability event is occurring
			{
				if (recloser_delay_time<=t0)	//Time delay has passed - but we are obviously still "in fault"
				{
					recloser_tries++;			//Increment the tries counter
					current_recloser_tries++;	//Increment the current tries
					if (current_recloser_tries>recloser_limit)	//Now we need to lock out
					{
						recloser_delay_time = 0;
						recloser_reset_time = t0+(TIMESTAMP)(gl_random_exponential(3600)*TS_SECOND);	//Figure out how long to lock out
						gl_verbose("Recloser:%d just reached its limit and locked out for a while",OBJECTHDR(this)->id);
						t1 = recloser_reset_time;
					}
					else		//We're still OK to flicker
					{
						recloser_delay_time = t0+(TIMESTAMP)(recloser_delay*TS_SECOND);	//Get a new time
						gl_verbose("Recloser:%d just tried to reclose and failed",OBJECTHDR(this)->id);
						t1 = recloser_delay_time;
					}
				}
				else	//still in delay
				{
					t1 = recloser_delay_time;
				}
			}
			else					//Closed operations - only if a reliability event is occurring
			{
				status=LS_OPEN;				//Open us up, we are in an event
				current_recloser_tries = 0;	//Reset out count, just in case
				recloser_reset_time = 0;	//Reset the lockout timer, just in case

				recloser_delay_time = t0+(TIMESTAMP)(recloser_delay*TS_SECOND);	//Get a new time
				gl_verbose("Recloser:%d detected a fault and opened",OBJECTHDR(this)->id);
				t1 = recloser_delay_time;
			}
		}
	}
	else	//Older method (and catch if reliabilty ends while in lockout)
	{
		set trip = (f->is_contact_any() || t->is_contact_any());

		//Make sure aren't in overall lockout
		if ((recloser_reset_time != 0 ) && (recloser_reset_time>=t0))	//We're done being locked out
		{
			//Reset all of the variables
			recloser_reset_time = 0;
			recloser_delay_time = 0;
			recloser_tries = 0;
			status = LS_CLOSED;
			t1 = TS_NEVER;	//Just flag us as something small to continue
			gl_verbose("Recloser:%d just unlocked and rejoined service",OBJECTHDR(this)->id);
		}
		else if ((recloser_reset_time != 0 ) && (recloser_reset_time>t0))	//Not done being locked out
		{
			t1 = recloser_reset_time;
		}
		else //Should be normal area
		{
			/* perform relay operation if any line contact has occurred */
			if (status==LS_CLOSED && trip)
			{
				status = LS_OPEN;

				/* schedule recloser operation */
				recloser_delay_time=t0+(TIMESTAMP)(recloser_delay*TS_SECOND);
				gl_verbose("Recloser:%d detected a fault and opened",OBJECTHDR(this)->id);
				t1 = recloser_delay_time;
			}
			/* recloser time has arrived */
			else if (status==LS_OPEN && t0>=recloser_delay_time)
			{
				/* still have contact */
				if (trip)
				{
					/* reschedule automatic recloser if retries permits */ 
					if (recloser_limit>recloser_tries)
					{
						recloser_tries++;
						gl_verbose("Recloser:%d just tried to reclose and failed",OBJECTHDR(this)->id);
						recloser_delay_time = t0+(TIMESTAMP)(recloser_delay*TS_SECOND);

						t1 = recloser_delay_time;
					}

					/* automatic retries exhausted, manual takes an average of an hour */
					else
					{
						gl_verbose("Recloser:%d just reached its limit and locked out for a while",OBJECTHDR(this)->id);
						recloser_reset_time = t0+(TIMESTAMP)(gl_random_exponential(3600)*TS_SECOND);
						t1 = recloser_reset_time;
					}
				}
				else
					status = LS_CLOSED;
			}
			else if ((recloser_delay_time != 0) && (recloser_delay_time>t0))	//Still in delay
			{
				t1 = recloser_delay_time;
			}
			else	//Recover
			{
				if (status==LS_OPEN)
				{
					gl_verbose("Recloser:%d recovered from a fault",OBJECTHDR(this)->id);
				}

				current_recloser_tries = 0;	//Reset count variables
				recloser_tries = 0;
				status=LS_CLOSED;
			}
		}
	}
#endif

	TIMESTAMP t2=link::sync(t0);

	return t1<t2?t1:t2;
}
Esempio n. 4
0
TIMESTAMP fuse::sync(TIMESTAMP t0)
{
	OBJECT *obj = OBJECTHDR(this);
	unsigned char work_phases;
	bool fuse_blew;
	TIMESTAMP replacement_time;
	TIMESTAMP replacement_duration;
	TIMESTAMP t2;
	char fault_val[9];
	int result_val;

	//Try to map the event_schedule function address, if we haven't tried yet
	if (event_schedule_map_attempt == false)
	{
		//First check to see if a fault_check object even exists
		if (fault_check_object != NULL)
		{
			//It exists, good start! - now see if the proper variable is populated!
			eventgen_obj = get_object(fault_check_object, "eventgen_object");

			//See if it worked - if not, assume it doesn't exist
			if (*eventgen_obj != NULL)
			{
				//It's not null, map up the scheduler function
				event_schedule = (FUNCTIONADDR)(gl_get_function(*eventgen_obj,"add_event"));
								
				//Make sure it was found
				if (event_schedule == NULL)
				{
					gl_warning("Unable to map add_event function in eventgen:%s",*(*eventgen_obj)->name);
					/*  TROUBLESHOOT
					While attempting to map the "add_event" function from an eventgen object, the function failed to be
					found.  Ensure the target object in fault_check is an eventgen object and this function exists.  If
					the error persists, please submit your code and a bug report via the trac website.
					*/
				}
			}
			//Defaulted elses - just leave things as is :(
		}
		//Defaulted else - doesn't exist, so leave function address empty

		//Flag the attempt as having occurred
		event_schedule_map_attempt = true;
	}

	//Update time variable
	if (prev_fuse_time != t0)	//New timestep
		prev_fuse_time = t0;

	//Code below only applies to NR right now - FBS legacy code has no sync values
	//May need to be appropriately adjusted once FBS supports reliability
	if (solver_method == SM_NR)
	{
		//Put any fuses back in service, if they're ready
		if (((fix_time[0] <= t0) || (fix_time[1] <= t0) || (fix_time[2] <= t0)) && (event_schedule == NULL))	//Only needs to be done if reliability isn't present
		{
			//Bring the phases back that are necessary
			if ((fix_time[0] <= t0) && ((NR_branchdata[NR_branch_reference].origphases & 0x04) == 0x04))	//Phase A ready and had a phase A
			{
				//Update status
				phase_A_state = GOOD;

				//Pop in the variables for the reliability update (if it exists)
				fix_time[0] = TS_NEVER;	//Reset variables
			}

			if ((fix_time[1] <= t0) && ((NR_branchdata[NR_branch_reference].origphases & 0x02) == 0x02))	//Phase B ready and had a phase B
			{
				//Update status
				phase_B_state = GOOD;

				//Pop in the variables for the reliability update (if it exists)
				fix_time[1] = TS_NEVER;	//Reset variables
			}

			if ((fix_time[2] <= t0) && ((NR_branchdata[NR_branch_reference].origphases & 0x01) == 0x01))	//Phase C ready and had a phase C
			{
				//Update status
				phase_C_state = GOOD;

				//Pop in the variables for the reliability update (if it exists)
				fix_time[2] = TS_NEVER;	//Reset variables
			}
		}//End back in service

		//Call syncing function
		fuse_sync_function();

		//Call overlying link sync
		t2=link_object::sync(t0);

		//Always execute check code now
		//Start with no assumed outages
		fuse_blew = false;
		work_phases = 0x00;
		replacement_time = 0;

		//Check them
		if ((NR_branchdata[NR_branch_reference].phases & 0x04) == 0x04)	//Phase A valid - check it
		{
			//Link::sync is where current in is calculated.  Convert the values
			current_current_values[0] = current_in[0].Mag();

			if ((current_current_values[0] > current_limit) && (phase_A_state == GOOD))
			{
				phase_A_state = BLOWN;	//Blow the fuse
				gl_warning("Phase A of fuse:%s just blew!",obj->name);
				/*  TROUBLESHOOT
				The current through phase A of the fuse just exceeded the maximum rated value.
				Use a larger value, or otherwise change your system and try again.
				*/

				fuse_blew = true;		//Flag a change
				work_phases |= 0x04;	//Flag A change

				//See if an update is needed (it's A and first, so yes, but just to be generic)
				if (replacement_time == 0)
				{
					//Get length of outage
					if (restore_dist_type == EXPONENTIAL)
					{
						//Update mean repair time
						mean_repair_time = gl_random_exponential(RNGSTATE,1.0/mean_replacement_time);
						replacement_duration = (TIMESTAMP)(mean_repair_time);
					}
					else
					{
						//Update mean repair time - fuse always overrides link
						mean_repair_time = mean_replacement_time;
						replacement_duration = (TIMESTAMP)(mean_repair_time);
					}

					//Figure out when it is
					replacement_time = prev_fuse_time + replacement_duration;
				}
			}
			//Else is leave as is - either blown, or reliability hit it
		}

		if ((NR_branchdata[NR_branch_reference].phases & 0x02) == 0x02)	//Phase B valid - check it
		{
			//Link::sync is where current in is calculated.  Convert the values
			current_current_values[1] = current_in[1].Mag();

			if ((current_current_values[1] > current_limit) && (phase_B_state == GOOD))
			{
				phase_B_state = BLOWN;	//Blow the fuse

				gl_warning("Phase B of fuse:%s just blew!",obj->name);
				/*  TROUBLESHOOT
				The current through phase B of the fuse just exceeded the maximum rated value.
				Use a larger value, or otherwise change your system and try again.
				*/

				fuse_blew = true;		//Flag a change
				work_phases |= 0x02;	//Flag B change

				//See if an update is needed
				if (replacement_time == 0)
				{
					//Get length of outage
					if (restore_dist_type == EXPONENTIAL)
					{
						//Update mean repair time
						mean_repair_time = gl_random_exponential(RNGSTATE,1.0/mean_replacement_time);
						replacement_duration = (TIMESTAMP)(mean_repair_time);
					}
					else
					{
						//Update mean repair time - fuse always overrides link
						mean_repair_time = mean_replacement_time;
						replacement_duration = (TIMESTAMP)(mean_repair_time);
					}

					//Figure out when it is
					replacement_time = prev_fuse_time + replacement_duration;
				}
			}
			//Else is leave as is - either blown, or reliability hit it
		}

		if ((NR_branchdata[NR_branch_reference].phases & 0x01) == 0x01)	//Phase C valid - check it
		{
			//Link::sync is where current in is calculated.  Convert the values
			current_current_values[2] = current_in[2].Mag();

			if ((current_current_values[2] > current_limit) && (phase_C_state == GOOD))
			{
				phase_C_state = BLOWN;	//Blow the fuse

				gl_warning("Phase C of fuse:%s just blew!",obj->name);
				/*  TROUBLESHOOT
				The current through phase C of the fuse just exceeded the maximum rated value.
				Use a larger value, or otherwise change your system and try again.
				*/

				fuse_blew = true;		//Flag a change
				work_phases |= 0x01;	//Flag C change

				//See if an update is needed
				if (replacement_time == 0)
				{
					//Get length of outage
					if (restore_dist_type == EXPONENTIAL)
					{
						//Update mean repair time
						mean_repair_time = gl_random_exponential(RNGSTATE,1.0/mean_replacement_time);
						replacement_duration = (TIMESTAMP)(mean_repair_time);
					}
					else
					{
						//Update mean repair time - fuse always overrides link
						mean_repair_time = mean_replacement_time;
						replacement_duration = (TIMESTAMP)(mean_repair_time);
					}

					//Figure out when it is
					replacement_time = prev_fuse_time + replacement_duration;
				}
			}
			//Else is leave as is - either blown, or reliability hit it
		}

		if (fuse_blew == true)
		{
			//Set up fault type
			fault_val[0] = 'F';
			fault_val[1] = 'U';
			fault_val[2] = 'S';
			fault_val[3] = '-';

			//Determine who blew and store the time (assumes fuses can be replaced in parallel)
			switch (work_phases)
			{
			case 0x00:	//No fuses blown !??
				GL_THROW("fuse:%s supposedly blew, but doesn't register the right phases",obj->name);
				/*  TROUBLESHOOT
				A fuse reported an over-current condition and blew the appropriate link.  However, it did not appear
				to fully propogate this condition.  Please try again.  If the error persists, please submit your code
				and a bug report via the trac website.
				*/
				break;
			case 0x01:	//Phase C blew
				fix_time[2] = replacement_time;
				fault_val[4] = 'C';
				fault_val[5] = '\0';
				break;
			case 0x02:	//Phase B blew
				fix_time[1] = replacement_time;
				fault_val[4] = 'B';
				fault_val[5] = '\0';
				break;
			case 0x03:	//Phase B and C blew
				fix_time[1] = replacement_time;
				fix_time[2] = replacement_time;
				fault_val[4] = 'B';
				fault_val[5] = 'C';
				fault_val[6] = '\0';
				break;
			case 0x04:	//Phase A blew
				fix_time[0] = replacement_time;
				fault_val[4] = 'A';
				fault_val[5] = '\0';
				break;
			case 0x05:	//Phase A and C blew
				fix_time[0] = replacement_time;
				fix_time[2] = replacement_time;
				fault_val[4] = 'A';
				fault_val[5] = 'C';
				fault_val[6] = '\0';
				break;
			case 0x06:	//Phase A and B blew
				fix_time[0] = replacement_time;
				fix_time[1] = replacement_time;
				fault_val[4] = 'A';
				fault_val[5] = 'B';
				fault_val[6] = '\0';
				break;
			case 0x07:	//All three went
				fix_time[0] = replacement_time;
				fix_time[1] = replacement_time;
				fix_time[2] = replacement_time;
				fault_val[4] = 'A';
				fault_val[5] = 'B';
				fault_val[6] = 'C';
				fault_val[7] = '\0';
				break;
			default:
				GL_THROW("fuse:%s supposedly blew, but doesn't register the right phases",obj->name);
				//Defined above
			}//End switch

			if (event_schedule != NULL)	//Function was mapped - go for it!
			{
				//Call the function
				result_val = ((int (*)(OBJECT *, OBJECT *, char *, TIMESTAMP, TIMESTAMP, int, bool))(*event_schedule))(*eventgen_obj,obj,fault_val,t0,0,-1,false);

				//Make sure it worked
				if (result_val != 1)
				{
					GL_THROW("Attempt to blow fuse:%s failed in a reliability manner",obj->name);
					/*  TROUBLESHOOT
					While attempting to propagate a blown fuse's impacts, an error was encountered.  Please
					try again.  If the error persists, please submit your code and a bug report via the trac website.
					*/
				}

				//Ensure we don't go anywhere yet
				t2 = t0;

			}	//End fault object present
			else	//No object, just fail us out - save the iterations
			{
				gl_warning("No fault_check object present - Newton-Raphson solver may fail!");
				/*  TROUBLESHOOT
				A fuse blew and created an open link.  If the system is not meshed, the Newton-Raphson
				solver will likely fail.  Theoretically, this should be a quick fail due to a singular matrix.
				However, the system occasionally gets stuck and will exhaust iteration cycles before continuing.
				If the fuse is blowing and the NR solver still iterates for a long time, this may be the case.
				*/
			}
		}
	}//End NR-only reliability calls
	else	//FBS
		t2 = link_object::sync(t0);

	if (t2==TS_NEVER)
		return(t2);
	else
		return(-t2);	//Soft limit it
}