int residential_enduse::init(OBJECT *parent) { OBJECT *hdr = OBJECTHDR(this); hdr->flags |= OF_SKIPSAFE; ATTACHFUNCTION attach = 0; // pull parent attach_enduse and attach the enduseload if(parent) attach = (ATTACHFUNCTION)(gl_get_function(parent, "attach_enduse")); if(parent && attach) pCircuit = (*attach)(parent, &load, load.breaker_amps, (load.config&EUC_IS220)!=0); else if (parent) gl_warning("%s (%s:%d) parent %s (%s:%d) does not export attach_enduse function so voltage response cannot be modeled", hdr->name?hdr->name:"(unnamed)", hdr->oclass->name, hdr->id, parent->name?parent->name:"(unnamed)", parent->oclass->name, parent->id); /* TROUBLESHOOT Enduses must have a voltage source from a parent object that exports an attach_enduse function. The residential_enduse object references a parent object that does not conform with this requirement. Fix the parent reference and try again. */ if (load.shape!=NULL) { if (load.shape->schedule==NULL) { gl_verbose("%s (%s:%d) schedule is not specified so the load may be inactive", hdr->name?hdr->name:"(unnamed)", hdr->oclass->name, hdr->id); /* TROUBLESHOOT The residential_enduse object requires a schedule that defines how the load behaves. Omitting this schedule effectively shuts the enduse load off and this is not typically intended. */ } } return 1; }
TIMESTAMP switch_object::sync(TIMESTAMP t0) { OBJECT *obj = OBJECTHDR(this); unsigned char work_phases_pre, work_phases_post; //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_SW_time != t0) //New timestep prev_SW_time = t0; //Call functionalized "pre-link" sync items BOTH_switch_sync_pre(&work_phases_pre, &work_phases_post); //Call overlying link sync TIMESTAMP t2=link_object::sync(t0); if (solver_method == SM_NR) { //Call functionalized "post-link" sync items NR_switch_sync_post(&work_phases_pre, &work_phases_post, obj, &t0, &t2); } if (t2==TS_NEVER) return(t2); else return(-t2); //Soft limit it }
int occupantload::init(OBJECT *parent) { if(parent != NULL){ if((parent->flags & OF_INIT) != OF_INIT){ char objname[256]; gl_verbose("occupantload::init(): deferring initialization on %s", gl_name(parent, objname, 255)); return 2; // defer } } if (number_of_occupants==0) number_of_occupants = 4; // defaulted to 4, but perhaps define it based on house size?? if (heatgain_per_person==0) heatgain_per_person = 400.0; // Based on DOE-2, includes latent and sensible heatgain OBJECT *hdr = OBJECTHDR(this); hdr->flags |= OF_SKIPSAFE; if (parent==NULL || (!gl_object_isa(parent,"house") && !gl_object_isa(parent,"house_e"))) { gl_error("occupantload must have a parent house"); /* TROUBLESHOOT The occupantload object, being an enduse for the house model, must have a parent house that it is connected to. Create a house object and set it as the parent of the offending occupantload object. */ return 0; } // pull parent attach_enduse and attach the enduseload FUNCTIONADDR attach = 0; load.end_obj = hdr; attach = (gl_get_function(parent, "attach_enduse")); if(attach == NULL){ gl_error("occupantload parent must publish attach_enduse()"); /* TROUBLESHOOT The occupantload object attempt to attach itself to its parent, which must implement the attach_enduse function. */ return 0; } // Needed to pass heat gain up to the house // "true" on 220 keeps the circuits "balanced" ((CIRCUIT *(*)(OBJECT *, ENDUSELOAD *, double, int))(*attach))(hdr->parent, &(this->load), 20, true); load.heatgain = number_of_occupants * occupancy_fraction * heatgain_per_person; if(shape.type != MT_UNKNOWN && shape.type != MT_ANALOG){ char outname[64]; if(hdr->name){ //sprintf(outname, "%s", hdr->name); } else { sprintf(outname, "occupancy_load:%i", hdr->id); } gl_warning("occupancy_load \'%s\' may not work properly with a non-analog load shape.", hdr->name ? hdr->name : outname); } return 1; }
/* Object initialization is called once after all object have been created */ int metrics::init(OBJECT *parent) { OBJECT *hdr = OBJECTHDR(this); int index, indexa, indexb, returnval; char work_metrics[1025]; char *startVal, *endVal, *workVal; char workbuffer[1025]; char metricbuffer[257]; FILE *FPVal; FINDLIST *CandidateObjs; OBJECT *temp_obj; bool *temp_bool; FUNCTIONADDR funadd = NULL; //Ensure our "module metrics" object is populated if (module_metrics_obj == NULL) { GL_THROW("Please specify a module metrics object for metrics:%s",hdr->name); /* TROUBLESHOOT To operate properly, the metrics object must have the corresponding module's metrics calculator linked. If this object is missing, metrics has no idea what to calculate and will not proceed. */ } //It's not null, map up the init function and call it (this must exist, even if it does nothing) funadd = (FUNCTIONADDR)(gl_get_function(module_metrics_obj,"init_reliability")); //Make sure it was found if (funadd == NULL) { GL_THROW("Unable to map reliability init function on %s in %s",module_metrics_obj->name,hdr->name); /* TROUBLESHOOT While attempting to initialize the reliability module in the "module of interest" metrics device, a error was encountered. Ensure this object fully supports reliability and try again. If the bug persists, please submit your code and a bug report to the trac website. */ } Extra_Data = ((void *(*)(OBJECT *, OBJECT *))(*funadd))(module_metrics_obj,hdr); //Make sure it worked if (Extra_Data==NULL) { GL_THROW("Unable to map reliability init function on %s in %s",module_metrics_obj->name,hdr->name); //defined above } //Figure out how many indices we should be finding index = 0; while ((metrics_oi[index] != '\0') && (index < 1024)) { if (metrics_oi[index] == ',') { num_indices++; //Increment counter } index++; //Increment pointer } //Make sure we didn't blow the top off if (index == 1024) { GL_THROW("Maximum length exceeded on metrics_of_interest in metrics:%s",hdr->name); /* TROUBLESHOOT While parsing the metrics_of_interest list, the maximum length (1024 characters) was reached. This can cause undesired behavior. Ensure the metrics list is within this character count. If it is, please try again. If the error persists, please submit your code and a bug report via the trac website. */ } //See if at least one was found. If it was, that means there are 2 (it counts commas) if (num_indices >= 1) num_indices++; //See if we were a solitary one - if so, increment accordingly if ((num_indices == 0) && (index > 1)) num_indices = 1; //Make sure at least one was found if (num_indices == 0) { GL_THROW("No indices of interest specified for metrics:%s",hdr->name); /* TROUBLESHOOT No indices were found to read. Please specify the proper indices and try again. */ } //Malloc us up! CalcIndices = (INDEXARRAY*)gl_malloc(num_indices * sizeof(INDEXARRAY)); //Make sure it worked if (CalcIndices == NULL) { GL_THROW("Failure to allocate indices memory in metrics:%s",hdr->name); /* TROUBLESHOOT While allocating the storage matrix for the indices to calculate, an error occurred. Please try again. If the error persists, please submit you code and a bug report using the trac website. */ } //Initialize these, just in case for (index=0; index<num_indices; index++) { CalcIndices[index].MetricLoc = NULL; //No address by default for (indexa=0; indexa<257; indexa++) //+1 due to end \0 CalcIndices[index].MetricName[indexa]='\0'; } //Populate it up - copy it first so we don't destroy the original metrics_oi.copy_to(work_metrics); //Set initial pointers startVal = work_metrics; endVal = work_metrics; //Loop through and find them for (index=0; index<num_indices; index++) //Loop through { //Find the next comma or end point while ((*endVal != ',') && (*endVal != '\0')) { endVal++; } //Replace us (comma) with EOS (\0) *endVal='\0'; //Copy us into the structure workVal = startVal; indexa = 0; while ((workVal<=endVal) && (indexa < 256)) { //Copy the value in CalcIndices[index].MetricName[indexa] = *workVal; //Copy into secondary metricbuffer[indexa] = *workVal; //Increment pointers indexa++; workVal++; } //apply the "_int" portion for the interval search indexb = indexa-1; //Now update pointers appropriately and proceed endVal++; startVal = endVal; //Now try to find this variable CalcIndices[index].MetricLoc = get_metric(module_metrics_obj,CalcIndices[index].MetricName); //Make sure it worked if (CalcIndices[index].MetricLoc == NULL) { GL_THROW("Unable to find metric %s in object %s for metric:%s",CalcIndices[index].MetricName.get_string(),module_metrics_obj->name,hdr->name); /* TROUBLESHOOT While attempting to map out a reliability metric, the desired metric was not found. Please check the variable name and ensure the metric is being published in the module metrics object and try again. If the error persists, please submit your code and a bug report to the trac website. */ } //Get the interval metric - if it exists - and there is room if ((indexb+4) <= 256) { metricbuffer[indexb] = '_'; metricbuffer[(indexb+1)] = 'i'; metricbuffer[(indexb+2)] = 'n'; metricbuffer[(indexb+3)] = 't'; metricbuffer[(indexb+4)] = '\0'; //Try to map it CalcIndices[index].MetricLocInterval = get_metric(module_metrics_obj,metricbuffer); //No NULL check - if it wasn't found, we won't deal with it } }//end metric traversion //Map our reset functions for ease reset_interval_func = (FUNCTIONADDR)(gl_get_function(module_metrics_obj,"reset_interval_metrics")); //Make sure it worked if (reset_interval_func == NULL) { GL_THROW("Failed to map interval reset in metrics object %s for metrics:%s",module_metrics_obj->name,hdr->name); /* TROUBLESHOOT While attempting to map the interval statistics reset function, the metrics object encountered a problem. Please make sure the module metrics object supports a "reset_interval_metrics" function. If so, please try again. If the error persists, please submit your code and a bug report using the trac website. */ } reset_annual_func = (FUNCTIONADDR)(gl_get_function(module_metrics_obj,"reset_annual_metrics")); //Make sure it worked if (reset_annual_func == NULL) { GL_THROW("Failed to map annual reset in metrics object %s for metrics:%s",module_metrics_obj->name,hdr->name); /* TROUBLESHOOT While attempting to map the annual statistics reset function, the metrics object encountered a problem. Please make sure the module metrics object supports a "reset_interval_metrics" function. If so, please try again. If the error persists, please submit your code and a bug report using the trac website. */ } compute_metrics = (FUNCTIONADDR)(gl_get_function(module_metrics_obj,"calc_metrics")); //Make sure it worked if (compute_metrics == NULL) { GL_THROW("Failed to map metric computation function in metrics object %s for metrics:%s",module_metrics_obj->name,hdr->name); /* TROUBLESHOOT While attempting to map the function to compute the desired metrics, the metrics object encountered a problem. Please make sure the module metrics object supports a "calc_metrics" function. If so, please try again. If the error persists, please submit your code and a bug report using the trac website. */ } //Call the resets - interval 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); /* TROUBLESHOOT The metrics object encountered an error while attempting to reset the interval statistics variables. Please try again. If the error persists, submit your code and a bug report via the trac website. */ } //Call the resets - annual 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); /* TROUBLESHOOT The metrics object encountered an error while attempting to reset the annual statistics variables. Please try again. If the error persists, submit your code and a bug report via the trac website. */ } //Convert our calculation interval to a timestamp metric_interval = (TIMESTAMP)metric_interval_dbl; report_interval = (TIMESTAMP)report_interval_dbl; //See if it is a year - flag appropriately if (metric_interval == 31536000) metric_equal_annual = true; //Make sure we have a file name provided if (report_file[0] == '\0') //None specified { GL_THROW("Please specify a proper report file name if you would like an output file from metrics:%s",hdr->name); /* TROUBLESHOOT While attempting to write the report file, an invalid file name was provided. Please provide a valid file name and try again. */ } //Open the file to clear it FPVal = fopen(report_file,"wt"); //Make sure it worked if (FPVal == NULL) { GL_THROW("Unable to create the report file '%s' for metrics:%s",report_file,hdr->name); /* TROUBLESHOOT While attempting to write the metrics output file, an error occurred. Please make sure you have write permissions at that location and try again. If the error persists, please submit your code and a bug report using the trac website. */ } //It must exist - write the typical header nonsense fprintf(FPVal,"Reliability report for %s\n", gl_global_getvar("modelname",workbuffer,(1025*sizeof(char)))); //Find our lucky candidate objects CandidateObjs = gl_find_objects(FL_GROUP,customer_group.get_string()); if (CandidateObjs==NULL) { GL_THROW("Failure to find devices for %s specified as: %s",hdr->name,customer_group.get_string()); /* TROUBLESHOOT While attempting to populate the list of devices to check for reliability metrics, the metrics object failed to find any desired objects. Please make sure the objects exist and try again. If the bug persists, please submit your code using the trac website. */ } //Do a zero-find check as well if (CandidateObjs->hit_count == 0) { GL_THROW("Failure to find devices for %s specified as: %s",hdr->name,customer_group.get_string()); //Defined above } //Pull the count CustomerCount = CandidateObjs->hit_count; //Make us an array! Customers = (CUSTARRAY*)gl_malloc(CustomerCount*sizeof(CUSTARRAY)); //Make sure it worked if (Customers == NULL) { GL_THROW("Failure to allocate customer list memory in metrics:%s",hdr->name); /* TROUBLESHOOT While allocating the memory for the list of customers, GridLAB-D encountered a problem. Please try again. If the error persists, please submit your code and a bug report via the trac website. */ } //Let's populate the beast now! temp_obj = NULL; for (index=0; index<CustomerCount; index++) { //Find the object temp_obj = gl_find_next(CandidateObjs, temp_obj); if (temp_obj == NULL) { GL_THROW("Failed to populate customer list in metrics: %s",hdr->name); /* TROUBLESHOOT While populating the metrics customer list, an object failed to be located. Please try again. If the error persists, please submit your code and a bug report to the trac website. */ } Customers[index].CustomerObj = temp_obj; //Try to find our "outage" indicator and map its address temp_bool = get_outage_flag(temp_obj, "customer_interrupted"); //make sure it found it if (temp_bool == NULL) { GL_THROW("Unable to find interrupted flag for customer object %s in metrics:%s",temp_obj->name,hdr->name); /* TROUBLESHOOT While attempting to link to the 'customer interrupted' flag, an error occurred. Please ensure the object supports being polled by reliability as a customer (customer_interrupted exists as a published property) and try again. If the error persists, please submit your code and a bug report via the trac website. */ } //Write this value in Customers[index].CustInterrupted = temp_bool; if (index == 0) //First customer, handle slightly different { //Populate the secondary index - needs to exist, even if never used //Try to find our secondary "outage" indicator and map its address temp_bool = get_outage_flag(temp_obj, "customer_interrupted_secondary"); //make sure it found it if (temp_bool == NULL) //Not found, assume no one else wants one { gl_warning("Unable to find secondary interruption flag, no secondary interruptions recorded in metrics:%s",hdr->name); /* TROUBLESHOOT While attempting to link to the 'secondary customer interrupted' flag, it was not found. THe object may not support "secondary interruption counts" and this message is valid. If a secondary count was desired, ensure the object supports being polled by reliability as a customer (customer_interrupted_secondary exists as a published property) and try again. If the error persists, please submit your code and a bug report via the trac website. */ } else //One found, assume all want one now { secondary_interruptions_count = true; //Write this value in Customers[index].CustInterrupted_Secondary = temp_bool; } } else if (secondary_interruptions_count == true) //Decided we want it { //Populate the secondary index - needs to exist, even if never used //Try to find our secondary "outage" indicator and map its address temp_bool = get_outage_flag(temp_obj, "customer_interrupted_secondary"); //make sure it found it if (temp_bool == NULL) { GL_THROW("Unable to find secondary interruption flag for customer object %s in metrics:%s",temp_obj->name,hdr->name); /* TROUBLESHOOT While attempting to link to the 'secondary customer interrupted' flag, an error occurred. Please ensure the object supports being polled by reliability as a customer (customer_interrupted_secondary exists as a published property) and try again. If the error persists, please submit your code and a bug report via the trac website. */ } //Write this value in Customers[index].CustInterrupted_Secondary = temp_bool; } //Defaulted else - unwanted }//end population loop //Free up list gl_free(CandidateObjs); //Write the customer count and header information to the file we have going fprintf(FPVal,"Number of customers = %d\n\n",CustomerCount); //See if the particular metrics object has any "comments" to add to the file header (units, notes, etc.) funadd = NULL; //Reset function pointer - just in case //Map up the "extra print" function - if it isn't there, well nothing is done funadd = (FUNCTIONADDR)(gl_get_function(module_metrics_obj,"logfile_extra")); //See if it was found if (funadd != NULL) { //Do the extra printing returnval = ((int (*)(OBJECT *, char *))(*funadd))(module_metrics_obj,workbuffer); //Make sure it worked if (returnval==0) { GL_THROW("Failed to write extra header material for %s in %s",module_metrics_obj->name,hdr->name); /* TROUBLESHOOT While attempting to write the extra material into the file header, an error occurred. Please try again. If the error persists, please submit your code and a bug report via the trac website. */ } //Print it out fprintf(FPVal,"%s",workbuffer); } //Close the file handle fclose(FPVal); return 1; /* return 1 on success, 0 on failure - We're so awesome we always assume we work */ }
/** Checks for climate object and maps the climate variables to the house object variables. Currently Tout, RHout and solar_service flux data from TMY files are used. If no climate object is linked, then Tout will be set to 59 degF, RHout is set to 75% and solar_service flux will be set to zero for all orientations. **/ int solar_service::init_climate() { OBJECT *hdr = OBJECTHDR(this); OBJECT *obj = NULL; // link to climate data FINDLIST *climates = NULL; if (solar_service_model_tilt != PLAYERVAL) { if (weather!=NULL) { if(!gl_object_isa(weather, "climate")){ // strcmp failure gl_error("weather property refers to a(n) \"%s\" object and not a climate object", weather->oclass->name); /* TROUBLESHOOT While attempting to map a climate property, the solar_service array encountered an object that is not a climate object. Please check to make sure a proper climate object is present, and/or specified. If the bug persists, please submit your code and a bug report via the trac website. */ return 0; } obj = weather; } else //No weather specified, search { climates = gl_find_objects(FL_NEW,FT_CLASS,SAME,"climate",FT_END); if (climates==NULL) { //Ensure weather is set to NULL - catch below weather = NULL; } else if (climates->hit_count==0) { //Ensure weather is set to NULL - catch below weather = NULL; } else //climate data must have been found { if (climates->hit_count>1) { gl_warning("solar_servicepanel: %d climates found, using first one defined", climates->hit_count); /* TROUBLESHOOT More than one climate object was found, so only the first one will be used by the solar_service array object */ } gl_verbose("solar_service init: climate data was found!"); // force rank of object w.r.t climate obj = gl_find_next(climates,NULL); weather = obj; } } //Make sure it actually found one if (weather == NULL) { //Replicate above warning gl_warning("solar_servicepanel: no climate data found, using static data"); /* TROUBLESHOOT No climate object was found and player mode was not enabled, so the solar_service array object is utilizing default values for all relevant weather variables. */ //default to mock data static double tout=59.0, rhout=0.75, solar_service=92.902, wsout=0.0, albdefault=0.2; pTout = &tout; pRhout = &rhout; psolar_serviceD = &solar_service; //Default all solar_service values to normal "optimal" 1000 W/m^2 psolar_serviceH = &solar_service; psolar_serviceG = &solar_service; pAlbedo = &albdefault; pWindSpeed = &wsout; if (orientation_type==FIXED_AXIS) { GL_THROW("FIXED_AXIS requires a climate file!"); /* TROUBLESHOOT The FIXED_AXIS model for the PV array requires climate data to properly function. Please specify such data, or consider using a different tilt model. */ } } else if (!gl_object_isa(weather,"climate")) //Semi redundant for "weather" { GL_THROW("weather object is not a climate object!"); /* TROUBLESHOOT The object specified for the weather property is not a climate object and will not work with the solar_service object. Please specify a valid climate object, or let the solar_service object automatically connect. */ } else //Must be a proper object { if((obj->flags & OF_INIT) != OF_INIT){ char objname[256]; gl_verbose("solar_service::init(): deferring initialization on %s", gl_name(obj, objname, 255)); return 2; // defer } if (obj->rank<=hdr->rank) gl_set_dependent(obj,hdr); pTout = (double*)GETADDR(obj,gl_get_property(obj,"temperature")); // pRhout = (double*)GETADDR(obj,gl_get_property(obj,"humidity")); <---- Not used anywhere yet psolar_serviceD = (double*)GETADDR(obj,gl_get_property(obj,"solar_service_direct")); psolar_serviceH = (double*)GETADDR(obj,gl_get_property(obj,"solar_service_diffuse")); psolar_serviceG = (double*)GETADDR(obj,gl_get_property(obj,"solar_service_global")); pAlbedo = (double*)GETADDR(obj,gl_get_property(obj,"ground_reflectivity")); pWindSpeed = (double*)GETADDR(obj,gl_get_property(obj,"wind_speed")); //Should probably check these if (pTout==NULL) { GL_THROW("Failed to map outside temperature"); /* TROUBLESHOOT The solar_service PV array failed to map the outside air temperature. Ensure this is properly specified in your climate data and try again. */ } //No need to error check - doesn't exist in any formulations yet //if (pRhout==NULL) //{ // GL_THROW("Failed to map outside relative humidity"); // /* TROUBLESHOOT // The solar_service PV array failed to map the outside relative humidity. Ensure this is // properly specified in your climate data and try again. // */ //} if (psolar_serviceD==NULL) { GL_THROW("Failed to map direct normal solar_service radiation"); /* TROUBLESHOOT The solar_service PV array failed to map the solar_service direct normal radiation. Ensure this is properly specified in your climate data and try again. */ } if (psolar_serviceH==NULL) { GL_THROW("Failed to map diffuse horizontal solar_service radiation"); /* TROUBLESHOOT The solar_service PV array failed to map the solar_service diffuse horizontal radiation. Ensure this is properly specified in your climate data and try again. */ } if (psolar_serviceG==NULL) { GL_THROW("Failed to map global horizontal solar_service radiation"); /* TROUBLESHOOT The solar_service PV array failed to map the solar_service global horizontal radiation. Ensure this is properly specified in your climate data and try again. */ } if (pAlbedo==NULL) { GL_THROW("Failed to map albedo/ground reflectance"); /* TROUBLESHOOT The solar_service PV array failed to map the ground reflectance. Ensure this is properly specified in your climate data and try again. */ } if (pWindSpeed==NULL) { GL_THROW("Failed to map wind speed"); /* TROUBLESHOOT The solar_service PV array failed to map the wind speed. Ensure this is properly specified in your climate data and try again. */ } //If climate data was found, check other related variables if (fix_angle_lat==true) { if (obj->latitude < 0) //Southern hemisphere { //Get the latitude from the climate file tilt_angle = -obj->latitude; } else //Northern { //Get the latitude from the climate file tilt_angle = obj->latitude; } } //Check the tilt angle for absurdity if (tilt_angle < 0) { GL_THROW("Invalid tilt_angle - tilt must be between 0 and 90 degrees"); /* TROUBLESHOOT A negative tilt angle was specified. This implies the array is under the ground and will not receive any meaningful solar_service irradiation. Please correct the tilt angle and try again. */ } else if (tilt_angle > 90.0) { GL_THROW("Invalid tilt angle - values above 90 degrees are unsupported!"); /* TROUBLESHOOT An tilt angle over 90 degrees (straight up and down) was specified. Beyond this angle, the tilt algorithm does not function properly. Please specific the tilt angle between 0 and 90 degrees and try again. */ } //Check the solar_service method if (orientation_type == FIXED_AXIS) { //See which function we want to use if (solar_service_model_tilt==LIUJORDAN) { //Map up the "classic" function calc_solar_service_radiation = (FUNCTIONADDR)(gl_get_function(obj,"calculate_solar_service_radiation_shading_degrees")); } else if (solar_service_model_tilt==SOLPOS) //Use the solpos/Perez tilt model { //Map up the "classic" function calc_solar_service_radiation = (FUNCTIONADDR)(gl_get_function(obj,"calc_solpos_radiation_shading_degrees")); } //Make sure it was found if (calc_solar_service_radiation == NULL) { GL_THROW("Unable to map solar_service radiation function on %s in %s",obj->name,hdr->name); /* TROUBLESHOOT While attempting to initialize the photovoltaic array mapping of the solar_service radiation function. Please try again. If the bug persists, please submit your GLM and a bug report via the trac website. */ } //Check azimuth for absurdity as well if ((orientation_azimuth<0.0) || (orientation_azimuth > 360.0)) { GL_THROW("orientation_azimuth must be a value representing a valid cardinal direction of 0 to 360 degrees!"); /* TROUBLESHOOT The orientation_azimuth property is expected values on the cardinal points degree system. For this convention, 0 or 360 is north, 90 is east, 180 is south, and 270 is west. Please specify a direction within the 0 to 360 degree bound and try again. */ } //Map up our azimuth now too, if needed - Liu & Jordan model assumes 0 = equator facing if (solar_service_model_tilt == LIUJORDAN) { if (obj->latitude>0.0) //North - "south" is equatorial facing { orientation_azimuth_corrected = 180.0 - orientation_azimuth; } else if (obj->latitude<0.0) //South - "north" is equatorial facing { gl_warning("solar_service:%s - Default solar_service position model is not recommended for southern hemisphere!",hdr->name); /* TROUBLESHOOT The Liu-Jordan (default) solar_service position and tilt model was built around the northern hemisphere. As such, operating in the southern hemisphere does not provide completely accurate results. They are close, but tilted surfaces are not properly accounted for. It is recommended that the solar_service_TILT_MODEL SOLPOS be used for southern hemisphere operations. */ if ((orientation_azimuth >= 0.0) && (orientation_azimuth <= 180.0)) { orientation_azimuth_corrected = orientation_azimuth; //East positive } else if (orientation_azimuth == 360.0) //Special case for those who like 360 as North { orientation_azimuth_corrected = 0.0; } else //Must be west { orientation_azimuth_corrected = orientation_azimuth - 360.0; } } else //Equator - erm.... { GL_THROW("Exact equator location of array detected - unknown how to handle orientation"); /* TROUBLESHOOT The solar_service orientation algorithm implemented inside GridLAB-D does not understand how to orient itself for an array exactly on the equator. Shift it north or south a little bit to get valid results. */ } } else //Right now only SOLPOS, which is "correct" - if another is implemented, may need another case orientation_azimuth_corrected = orientation_azimuth; } //Defaulted else for now - don't do anything }//End valid weather - mapping check } else //Player mode, just drop a message { gl_warning("solar_service object:%s is in player mode - be sure to specify relevant values",hdr->name); /* TROUBLESHOOT The solar_service array object is in player mode. It will not take values from climate files or objects. Be sure to specify the Insolation, ambient_temperature, and wind_speed values as necessary. It also will not incorporate any tilt functionality, since the Insolation value is expected to already include this adjustment. */ } return 1; }
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 }
TIMESTAMP switch_object::sync(TIMESTAMP t0) { OBJECT *obj = OBJECTHDR(this); TIMESTAMP temp_time; unsigned char work_phases, work_phases_pre, work_phases_post, work_phases_closed; char fault_val[9]; int result_val, impl_fault; bool fault_mode; //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_SW_time != t0) //New timestep prev_SW_time = t0; if ((solver_method == SM_NR) && (event_schedule != NULL)) //NR-reliability-related stuff { //Store our phases going in work_phases_pre = NR_branchdata[NR_branch_reference].phases & 0x07; //Call syncing function work_phases_post = switch_expected_sync_function(); //Store our phases going out work_phases_post &= 0x07; } else //Normal execution { //Call syncing function switch_sync_function(); //Set phases the same work_phases_pre = 0x00; work_phases_post = 0x00; } //Call overlying link sync TIMESTAMP t2=link_object::sync(t0); //See if we're in the proper cycle - NR only for now if ((solver_method == SM_NR) && (work_phases_pre != work_phases_post)) { //Find out what changed work_phases = (work_phases_pre ^ work_phases_post) & 0x07; //See if this transition is a "fault-open" or a "fault-close" work_phases_closed = work_phases & work_phases_post; //See how it looks if (work_phases_closed == work_phases) //It's a close { fault_mode = true; //work_phases = (~work_phases) & 0x07; } else //It's an open { fault_mode = false; //Work phases is already in the proper format } //Set up fault type fault_val[0] = 'S'; fault_val[1] = 'W'; fault_val[2] = '-'; //Default fault - none - will cause a failure if not caught impl_fault = -1; //Determine who opened and store the time switch (work_phases) { case 0x00: //No switches opened !?? GL_THROW("switch:%s supposedly opened, but doesn't register the right phases",obj->name); /* TROUBLESHOOT A switch reported changing to an open status. 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 action fault_val[3] = 'C'; fault_val[4] = '\0'; impl_fault = 20; break; case 0x02: //Phase B action fault_val[3] = 'B'; fault_val[4] = '\0'; impl_fault = 19; break; case 0x03: //Phase B and C action fault_val[3] = 'B'; fault_val[4] = 'C'; fault_val[5] = '\0'; impl_fault = 22; break; case 0x04: //Phase A action fault_val[3] = 'A'; fault_val[4] = '\0'; impl_fault = 18; break; case 0x05: //Phase A and C action fault_val[3] = 'A'; fault_val[4] = 'C'; fault_val[5] = '\0'; impl_fault = 23; break; case 0x06: //Phase A and B action fault_val[3] = 'A'; fault_val[4] = 'B'; fault_val[5] = '\0'; impl_fault = 21; break; case 0x07: //All three went fault_val[3] = 'A'; fault_val[4] = 'B'; fault_val[5] = 'C'; fault_val[6] = '\0'; impl_fault = 24; break; default: GL_THROW("switch:%s supposedly opened, 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 if (fault_mode == true) //Restoration - make fail time in the past { if (mean_repair_time != 0) temp_time = 50 + (TIMESTAMP)(mean_repair_time); else temp_time = 50; //Call function result_val = ((int (*)(OBJECT *, OBJECT *, char *, TIMESTAMP, TIMESTAMP, int, bool))(*event_schedule))(*eventgen_obj,obj,fault_val,(t0-50),temp_time,impl_fault,fault_mode); } else //Failing - normal { result_val = ((int (*)(OBJECT *, OBJECT *, char *, TIMESTAMP, TIMESTAMP, int, bool))(*event_schedule))(*eventgen_obj,obj,fault_val,t0,TS_NEVER,-1,fault_mode); } //Make sure it worked if (result_val != 1) { GL_THROW("Attempt to change switch:%s failed in a reliability manner",obj->name); /* TROUBLESHOOT While attempting to propagate a changed switch'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 switch changed 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 call if (t2==TS_NEVER) return(t2); else return(-t2); //Soft limit it }
//Function to change sectionalizer states - just call underlying switch routine EXPORT double change_sectionalizer_state(OBJECT *thisobj, unsigned char phase_change, bool state) { double count_values, recloser_count; char desA, desB, desC; switch_object *swtchobj; sectionalizer *sectionobj; FUNCTIONADDR funadd = NULL; bool perform_operation; //Init count_values = 0.0; if (state == false) //Check routine to find a recloser { //Map us up as a proper object sectionobj = OBJECTDATA(thisobj,sectionalizer); //Call to see if a recloser is present if (fault_check_object == NULL) { GL_THROW("Reliability call made without fault_check object present!"); /* TROUBLESHOOT A sectionalizer attempted to call a reliability-related function. However, this function requires a fault_check object to be present in the system. Please add the appropriate object. If the error persists, please submit your code and a bug report via the trac website. */ } //map the function funadd = (FUNCTIONADDR)(gl_get_function(fault_check_object,"handle_sectionalizer")); //make sure it worked if (funadd==NULL) { GL_THROW("Failed to find sectionalizer checking method on object %s",fault_check_object->name); /* TROUBLESHOOT While attempting to find the fault check method, or its subfunction to handle sectionalizers, an error was encountered. Please ensure a proper fault_check object is present in the system. If the error persists, please submit your code and a bug report via the trac website. */ } //Function call recloser_count = ((double (*)(OBJECT *, int))(*funadd))(fault_check_object,sectionobj->NR_branch_reference); if (recloser_count == 0.0) //Failed :( { GL_THROW("Failed to handle sectionalizer check on %s",thisobj->name); /* TROUBLESHOOT While attempting to handle sectionalizer actions for the specified device, an error occurred. Please try again and ensure all parameters are correct. If the error persists, please submit your code and a bug report via the trac website. */ } //Error check if (recloser_count < 0) //No recloser found, get us out of here { count_values = recloser_count; perform_operation = false; //Flag as no change allowed } else //Recloser found - pass the count out and flag a change allowed { perform_operation = true; count_values = recloser_count; } } else //No check required for reconneciton { perform_operation = true; //Flag operation as ok count_values = 1.0; //Arbitrary non-zero value so fail check doesn't go off } if (perform_operation==true) //Either is a "replace" or a recloser was found - operation is a go { //Map the switch swtchobj = OBJECTDATA(thisobj,switch_object); if (swtchobj->switch_banked_mode == switch_object::BANKED_SW) //Banked mode - all become "state", just cause { swtchobj->set_switch(state); } else //Must be individual { //Figure out what we need to call if ((phase_change & 0x04) == 0x04) { if (state==true) desA=1; //Close it else desA=0; //Open it } else //Nope, no A desA=2; //I don't care //Phase B if ((phase_change & 0x02) == 0x02) { if (state==true) desB=1; //Close it else desB=0; //Open it } else //Nope, no B desB=2; //I don't care //Phase C if ((phase_change & 0x01) == 0x01) { if (state==true) desC=1; //Close it else desC=0; //Open it } else //Nope, no A desC=2; //I don't care //Perform the switching! swtchobj->set_switch_full(desA,desB,desC); }//End individual adjustments } return count_values; }