TIMESTAMP collector::commit(TIMESTAMP t0, TIMESTAMP t1) { TIMESTAMP dt = (TIMESTAMP)get_interval(); if ( dt==0 || ( t1==next_t && next_t!=TS_NEVER ) ) { char buffer[4096]; size_t eos = sprintf(buffer,"INSERT INTO `%s` (t", get_table()); int n; for ( n=0 ; n<n_aggregates ; n++ ) eos += sprintf(buffer+eos,",`%s`",names[n]); eos += sprintf(buffer+eos,") VALUES (from_unixtime(%lli)",gl_globalclock); for ( n=0 ; n<n_aggregates ; n++ ) eos += sprintf(buffer+eos,",%g",list[n].get_value()); sprintf(buffer+eos,"%s",")"); if ( !db->query(buffer) ) exception("unable to add data to '%s' - %s", get_table(), mysql_error(mysql)); else gl_verbose("%s: sample added to '%s' ok", get_name(), get_table()); // check limit if ( get_limit()>0 && db->get_last_index()>=get_limit() ) { gl_verbose("%s: limit of %d records reached", get_name(), get_limit()); next_t = TS_NEVER; } else { next_t = (dt==0 ? TS_NEVER : (TIMESTAMP)(t1/dt+1)*dt); } set_clock(t1); } return TS_NEVER; }
TIMESTAMP transmissioncom::presync(TIMESTAMP t0, TIMESTAMP t1) { complex temp = complex(0,0); complex last_voltage = complex(0,0); if(t0 < t1 && myinterface->hasMoreMessages()){ last_voltage = *datatogld; temp = getFromTransmissionSolver(); if(last_voltage.Mag() != 0.0){ complex volt_diff = last_voltage - temp; double perc_diff = volt_diff.Mag()/last_voltage.Mag(); if(perc_diff >= 0.5){ if(last_voltage.Im() >= 0.0){ gl_verbose("previous voltage: %lf+j%lf V.\n",last_voltage.Re(),last_voltage.Im()); } else { gl_verbose("previous voltage: %lf+j%lf V.\n",last_voltage.Re(),-1.0*last_voltage.Im()); } if(temp.Im() >= 0.0){ gl_verbose("current voltage: %lf+j%lf V.\n",temp.Re(),temp.Im()); } else { gl_verbose("current voltage: %lf+j%lf V.\n",temp.Re(),-1.0*temp.Im()); } gl_verbose("voltage changed more that 50 percent. Something isn't right in transmission. Using previous voltage.\n"); } else { *datatogld = temp; } } else if(temp.Mag() > 0.0){ *datatogld = temp; } } return TS_NEVER; }
MYSQL_RES *database::select(char *fmt,...) { char command[1024]; va_list ptr; va_start(ptr,fmt); vsnprintf(command,sizeof(command),fmt,ptr); // query mysql if ( mysql_query(mysql,command)!=0 ) exception("%s->select[%s] query failed - %s", get_name(), command, mysql_error(mysql)); else if ( get_options()&DBO_SHOWQUERY ) gl_verbose("%s->select[%s] ok", get_name(), command); // get result MYSQL_RES *res = mysql_store_result(mysql); if ( res==NULL ) exception("%s->select[%s] result failed - %s", get_name(), command, mysql_error(mysql)); int n = mysql_num_rows(res); gl_verbose("%s->select[%s] %d rows returned", get_name(), command, n); //if ( n==0 ) // return mysql_free_result(res),NULL; // TODO map variables va_end(ptr); return res; }
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; }
/** Initialize water heater model properties - randomized defaults for all published variables **/ int virtual_battery::init(OBJECT *parent) { parent2=parent; first_time=0; first_time2=0; actual=0; temp_capacity=0; if(parent != NULL){ if((parent->flags & OF_INIT) != OF_INIT){ char objname[256]; gl_verbose("virtual_battery::init(): deferring initialization on %s", gl_name(parent, objname, 255)); return 2; // defer } } OBJECT *hdr = OBJECTHDR(this); hdr->flags |= OF_SKIPSAFE; ///////////////////////////////find auction object///////////////////////////////////// static FINDLIST *xt1=NULL; xt1=gl_find_objects(FL_NEW,FT_CLASS,SAME,"auction",FT_END); OBJECT *firstt1= gl_find_next(xt1,NULL); OBJECT *it1; for(it1=firstt1;it1!=NULL;it1=it1->next) { if(gl_object_isa(it1,"auction")) { auction_object=it1; } } ///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////find climate object /////////////////////////////////////// FINDLIST *climates = NULL; OBJECT *obj; climates = gl_find_objects(FL_NEW,FT_CLASS,SAME,"climate",FT_END); obj = gl_find_next(climates,NULL); if (gl_object_isa(obj,"climate")) { climate_object=obj; } /////////////////////////////////////////////////////////////////////////////////////// // check the load configuration before initializing the parent class return 1; }
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; }
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; }
TIMESTAMP residential_enduse::sync(TIMESTAMP t0, TIMESTAMP t1) { OBJECT *obj = OBJECTHDR(this); gl_debug("%s shape load = %8g", obj->name, gl_get_loadshape_value(&shape)); if (load.voltage_factor>1.2 || load.voltage_factor<0.8) gl_verbose("%s voltage is out of normal +/- 20%% range of nominal (vf=%.2f)", obj->name, load.voltage_factor); /* TROUBLESHOOTING The voltage on the enduse circuit is outside the expected range for that enduse. This is usually caused by an impropely configure circuit (e.g., 110V on 220V or vice versa). Fix the circuit configuration for that enduse and try again. */ return shape.t2>t1 ? shape.t2 : TS_NEVER; }
int database::init(OBJECT *parent) { gld_string flags = get_clientflags_property().get_string(); gl_verbose("mysql_connect(hostname='%s',username='******',password='******',schema='%s',port=%u,socketname='%s',clientflags=0x%016llx[%s])", (const char*)hostname,(const char*)username,(const char*)password,(const char*)schema,port,(const char*)socketname,get_clientflags(),(const char*)flags); mysql = mysql_real_connect(mysql_client,hostname,username,strcpy(password,"")?password:NULL,NULL,port,socketname,(unsigned long)clientflags); if ( mysql==NULL ) exception("mysql connect failed - %s", mysql_error(mysql_client)); else gl_verbose("MySQL server info: %s", mysql_get_server_info(mysql)); // autoname schema if ( strcmp(get_schema(),"")==0 ) { char buffer[1024]; gld_global model("modelname"); if ( model.to_string(buffer,sizeof(buffer))>0 ) set_schema(buffer); } // drop schema if ( get_options()&DBO_DROPSCHEMA && query("DROP DATABASE IF EXISTS `%s`", get_schema()) ) { if ( strcmp(get_schema(),"gridlabd")==0 ) gl_warning("%s uses NEWDB option on the default schema '%s' - this is extremely risky", get_name(), get_schema()); gl_verbose("schema '%s' dropped ok", get_schema()); } // check schema MYSQL_RES *res = mysql_list_dbs(mysql,get_schema()); if ( mysql_num_rows(res)==0 ) { if ( !(get_options()&DBO_NOCREATE) ) { if ( query("CREATE DATABASE IF NOT EXISTS `%s`", get_schema()) ) gl_verbose("created schema '%s' ok", get_schema()); } else exception("NOCREATE option prevents automatic creation of schema '%s'", get_schema()); } else gl_verbose("schema '%s' found ok", get_schema()); // use schema if ( mysql_select_db(mysql,get_schema())!=0 ) exception("unable to select schema '%s'", get_schema()); // execute on_init script if ( strcmp(get_on_init(),"")!=0 ) { gl_verbose("%s running on_init script '%s'", get_name(), get_on_init()); int res = run_script(get_on_init()); if ( res<=0 ) exception("on_init script '%s' failed at line %d: %s", get_on_init(), -res, get_last_error()); } return 1; }
static mxArray* matlab_exec(MATLABLINK *matlab, char *format, ...) { char cmd[4096]; va_list ptr; va_start(ptr,format); vsprintf(cmd,format,ptr); va_end(ptr); engEvalString(matlab->engine,cmd); if ( matlab->output_buffer && strcmp(matlab->output_buffer,"")!=0 ) gl_verbose( "%s", matlab->output_buffer ); mxArray *ans = engGetVariable(matlab->engine,"ans"); return ans; // failed }
EXPORT void submit_bid_state(char *from, char *to, char *function_name, char *function_class, void *bidding_buffer, size_t bid_len)//(char *obj, char *from, double quantity, double price, unsigned int is_on, KEY bid_id) { char biddername[64]; int rv; OBJECT *obj = NULL; BIDINFO *bidding_info = (BIDINFO *)bidding_buffer; if( strncmp(function_name, "submit_bid_state", 16)== 0){ obj = gl_get_object(to); if( obj == NULL){ gl_error("bid::submit_bid_state: No auction object exists with given name %s.", to); bidding_info->bid_accepted = false; } if (obj->oclass==auction::oclass) { if(bidding_info->state == BS_UNKNOWN) {// not a stateful bid gl_verbose("%s submits stateless bid for Q:%.2f at P:%.4f", from,bidding_info->quantity,bidding_info->price); auction *mkt = OBJECTDATA(obj,auction); rv = mkt->submit(from,bidding_info->quantity,bidding_info->price,bidding_info->bid_id,bidding_info->state,bidding_info->rebid, bidding_info->market_id); } else { gl_verbose("%s submits stateful (%s) bid for Q:%.2f at P:%.4f", from,bidding_info->state,bidding_info->quantity,bidding_info->price); auction *mkt = OBJECTDATA(obj,auction); rv = mkt->submit(from,bidding_info->quantity,bidding_info->price,bidding_info->bid_id,bidding_info->state,bidding_info->rebid, bidding_info->market_id); } if(rv == 0) { bidding_info->bid_accepted = false; } } else if(obj->oclass == stubauction::oclass){ gl_error("bid::submit_bid_state: market object is not an auction object."); bidding_info->bid_accepted = false; } else { gl_error("bid::submit_bid_state: market object is not an auction object."); bidding_info->bid_accepted = false; } } else { gl_error("bid::submit_bid_state: This function is not the intended function. %s was the intended function to call. Ignoring bid", function_name); } }
database::database(MODULE *module) { if (oclass==NULL) { // register to receive notice for first top down. bottom up, and second top down synchronizations oclass = gld_class::create(module,"database",sizeof(database),PC_AUTOLOCK); if (oclass==NULL) throw "unable to register class database"; else oclass->trl = TRL_PROTOTYPE; defaults = this; if (gl_publish_variable(oclass, PT_char256,"hostname",get_hostname_offset(),PT_ACCESS,PA_PUBLIC,PT_DESCRIPTION,"server hostname", PT_char256,"schema",get_schema_offset(),PT_ACCESS,PA_PUBLIC,PT_DESCRIPTION,"schema name", PT_char32,"username",get_username_offset(),PT_ACCESS,PA_PUBLIC,PT_DESCRIPTION,"user name", PT_char32,"password",get_password_offset(),PT_ACCESS,PA_PUBLIC,PT_DESCRIPTION,"user password", PT_int32,"port",get_port_offset(),PT_ACCESS,PA_PUBLIC,PT_DESCRIPTION,"TCP port number", PT_char1024,"socketname",get_socketname_offset(),PT_ACCESS,PA_PUBLIC,PT_DESCRIPTION,"unix socket name", PT_set,"clientflags",get_clientflags_offset(),PT_ACCESS,PA_PUBLIC,PT_DESCRIPTION,"mysql client flags", PT_KEYWORD,"COMPRESS",(int64)CLIENT_COMPRESS, PT_KEYWORD,"FOUND_ROWS",(int64)CLIENT_FOUND_ROWS, PT_KEYWORD,"IGNORE_SIGPIPE",(int64)CLIENT_IGNORE_SIGPIPE, PT_KEYWORD,"INTERACTIVE",(int64)CLIENT_INTERACTIVE, PT_KEYWORD,"LOCAL_FILES",(int64)CLIENT_LOCAL_FILES, PT_KEYWORD,"MULTI_RESULTS",(int64)CLIENT_MULTI_RESULTS, PT_KEYWORD,"MULTI_STATEMENTS",(int64)CLIENT_MULTI_STATEMENTS, PT_KEYWORD,"NO_SCHEMA",(int64)CLIENT_NO_SCHEMA, PT_KEYWORD,"ODBC",(int64)CLIENT_ODBC, PT_KEYWORD,"SSL",(int64)CLIENT_SSL, PT_KEYWORD,"REMEMBER_OPTIONS",(int64)CLIENT_REMEMBER_OPTIONS, PT_set,"options",get_options_offset(),PT_ACCESS,PA_PUBLIC,PT_DESCRIPTION,"database connection options", PT_KEYWORD,"SHOWQUERY",(int64)DBO_SHOWQUERY,PT_DESCRIPTION,"show SQL queries when running", PT_KEYWORD,"NOCREATE",(int64)DBO_NOCREATE,PT_DESCRIPTION,"prevent automatic creation of non-existent schemas", PT_KEYWORD,"NEWDB",(int64)DBO_DROPSCHEMA,PT_DESCRIPTION,"destroy existing schemas before use them (risky)", PT_KEYWORD,"OVERWRITE",(int64)DBO_OVERWRITE,PT_DESCRIPTION,"destroy existing files before output dump/backup results (risky)", PT_char1024,"on_init",get_on_init_offset(),PT_ACCESS,PA_PUBLIC,PT_DESCRIPTION,"SQL script to run when initializing", PT_char1024,"on_sync",get_on_sync_offset(),PT_ACCESS,PA_PUBLIC,PT_DESCRIPTION,"SQL script to run when synchronizing", PT_char1024,"on_term",get_on_term_offset(),PT_ACCESS,PA_PUBLIC,PT_DESCRIPTION,"SQL script to run when terminating", PT_double,"sync_interval[s]",get_sync_interval_offset(),PT_ACCESS,PA_PUBLIC,PT_DESCRIPTION,"interval at which on_sync is called", NULL)<1){ char msg[256]; sprintf(msg, "unable to publish properties in %s",__FILE__); throw msg; } memset(this,0,sizeof(database)); gl_verbose("MySQL client info: %s", mysql_get_client_info()); } }
int player::precommit(TIMESTAMP t0) { if ( row && t0==next_t) { target.from_string(row[1]); row = mysql_fetch_row(data); if ( row==NULL ) return 1; row_num++; gl_verbose("%s: row %d, %s='%s', %s='%s'", get_name(), row_num, fields[0].name, row[0], fields[1].name, row[1]); gld_clock next(row[0]); next_t = next.get_timestamp(); } return 1; }
bool database::query(char *fmt,...) { char command[1024]; va_list ptr; va_start(ptr,fmt); vsnprintf(command,sizeof(command),fmt,ptr); va_end(ptr); // query mysql if ( mysql_query(mysql,command)!=0 ) exception("%s->query[%s] failed - %s", get_name(), command, mysql_error(mysql)); else if ( get_options()&DBO_SHOWQUERY ) gl_verbose("%s->query[%s] ok", get_name(), command); return true; }
void database::term(void) { if ( strcmp(get_on_term(),"")!=0 ) { gl_verbose("%s running on_term script '%s'", get_name(), get_on_term()); try { int res = run_script(get_on_term()); if ( res<=0 ) exception("on_term script '%s' failed at line %d: %s", get_on_term(), -res, get_last_error()); } catch (const char *msg) { gl_error("%s", msg); } mysql_close(mysql); } }
int microwave::init(OBJECT *parent) { if(parent != NULL){ if((parent->flags & OF_INIT) != OF_INIT){ char objname[256]; gl_verbose("microwave::init(): deferring initialization on %s", gl_name(parent, objname, 255)); return 2; // defer } } OBJECT *hdr = OBJECTHDR(this); hdr->flags |= OF_SKIPSAFE; if (load.voltage_factor==0) load.voltage_factor = 1.0; if(shape.type == MT_UNKNOWN){ init_noshape(); gl_warning("This device, %s, is considered very experimental and has not been validated.", get_name()); // initial demand update_state(0.0); } else if(shape.type == MT_ANALOG){ if(1){ ; } } else if(shape.type == MT_PULSED){ if(1){ ; } } else if(shape.type == MT_MODULATED){ if(1){ ; } } else if(shape.type == MT_QUEUED){ gl_error("queued loadshapes not supported ~ will attempt to run as an unshaped load"); shape.type = MT_UNKNOWN; init_noshape(); // initial demand update_state(0.0); } else { gl_error("unrecognized loadshape"); return 0; } load.total = load.power = standby_power; // waiting this long to initialize the parent class is normal return residential_enduse::init(parent); }
/** Initialize the new object */ int plc::init(OBJECT *parent) { if (strcmp(source,"")==0 && parent!=NULL) /* default source */ sprintf(source.get_string(),"%s.plc",parent->oclass->name); if (controller->compile(source)<0) GL_THROW("%s: PLC compile failed", source.get_string()); if (controller->init(parent)<0) GL_THROW("%s: PLC init failed", source.get_string()); parent->flags |= OF_HASPLC; /* enable external PLC flag */ if (network) { controller->connect(OBJECTDATA(network,comm)); gl_verbose("machine %x has connected to network '%s'", controller, network->name?network->name:"anonymous"); } return 1; // return 0 on failure }
TIMESTAMP database::commit(TIMESTAMP t0, TIMESTAMP t1) { set_clock(); if ( get_sync_interval()>0 ) { gld_clock ts(t1); int mod = ts.get_localtimestamp()%(TIMESTAMP)get_sync_interval(); if ( strcmp(get_on_sync(),"")!=0 && mod==0 ) { int mod1 = t1%86400, mod2 = ts.get_timestamp()%86400, mod3 = ts.get_localtimestamp()%86400; gld_clock ts(t0); char buffer[64]; gl_verbose("%s running on_init script '%s' at %s", get_name(), get_on_sync(), ts.to_string(buffer,sizeof(buffer))?buffer:"(unknown time)"); int res = run_script(get_on_sync()); if ( res<=0 ) exception("on_init script '%s' failed at line %d: %s", get_on_sync(), -res, get_last_error()); } return -(t1+get_sync_interval()-mod); } return TS_NEVER; }
// Initialize a distribution meter, return 1 on success int substation::init(OBJECT *parent) { OBJECT *hdr = OBJECTHDR(this); int i,n; //Base check higher so can be used below if(base_power <= 0){ gl_warning("substation:%i is using the default base power of 100 VA. This could cause instability on your system.", hdr->id); base_power = 100;//default gives a max power error of 1 VA. } //Check convergence-posting criterion if (power_convergence_value<=0.0) { gl_warning("power_convergence_value not set - defaulting to 0.01 base_power"); /* TROUBLESHOOT A value was not specified for the convergence criterion required before posting an answer up to pw_load. This value has defaulted to 1% of base_power. If a different threshold is desired, set it explicitly. */ power_convergence_value = 0.01*base_power; }//End convergence value check //Check to see if it has a parent (no sense to ISAs if it is empty) if (parent != NULL) { if (gl_object_isa(parent,"pw_load","network")) { //Make sure it is done, otherwise defer if((parent->flags & OF_INIT) != OF_INIT){ char objname[256]; gl_verbose("substation::init(): deferring initialization on %s", gl_name(parent, objname, 255)); return 2; // defer } //Map up the appropriate variables- error checks mostly inside fetch_complex(&pPositiveSequenceVoltage,"load_voltage",parent); fetch_complex(&pConstantPowerLoad,"load_power",parent); fetch_complex(&pConstantCurrentLoad,"load_current",parent); fetch_complex(&pConstantImpedanceLoad,"load_impedance",parent); fetch_double(&pTransNominalVoltage,"bus_nom_volt",parent); //Do a general check for nominal voltages - make sure they match if (fabs(*pTransNominalVoltage-nominal_voltage)>0.001) { gl_error("Nominal voltages of tranmission node (%.1f V) and substation (%.1f) do not match!",*pTransNominalVoltage,nominal_voltage); /* TROUBLESHOOT The nominal voltage of the transmission node in PowerWorld does not match that of the value inside GridLAB-D's substation's nominal_voltage. This could cause information mismatch and is therefore not allowed. Please set the substation to the same nominal voltage as the transmission node. Use transformers to step the voltage down to an appropriate distribution or sub-transmission level. */ return 0; //Fail } //Check our bustype - otherwise we may get overridden (NR-esque check) if (bustype != SWING) { gl_warning("substation attached to pw_load and not a SWING bus - forcing to SWING"); /* TROUBLESHOOT When a substation object is connected to PowerWorld via a pw_load object, the substation must be designated as a SWING bus. This designation will now be forced upon the bus. */ bustype = SWING; }//End bus check //Flag us as pw_load connected has_parent = 1; } else //Parent isn't a pw_load, so we just become a normal node - let it handle things { has_parent = 2; //Flag as "normal" - let node checks sort out if we are really valid or not } }//End parent else //Parent is null, see what mode we're in { //Check for sequence voltages - if not set, we're normal (let node checks handle if we're valid) if ((seq_mat[0] != 0.0) || (seq_mat[1] != 0.0) || (seq_mat[2] != 0.0)) { //See if we're a swing, if not, this is meaningless if (bustype != SWING) { gl_warning("substation is not a SWING bus, so answers may be unexpected"); /* TROUBLESHOOT A substation object appears set to accept sequence voltage values, but it is not a SWING bus. This may end up causing the voltages to be converted from sequence, but then overridden by the distribution powerflow solver. */ } //Explicitly set has_parent = 0; } else //Else, nothing set, we're a normal old node { has_parent = 2; //Normal node //Warn that nothing was found gl_warning("substation:%s is set up as a normal node, no sequence values will be calculated",hdr->name); /* TROUBLESHOOT A substation is currently behaving just like a normal powerflow node. If it was desired that it convert a schedule or player of sequence values, please initialize those values to non-zero along with the player attachment. */ } }//End no parent //Set up reference items if they are needed if (has_parent != 2) //Not a normal node { //New requirement to maintain positive sequence ability - three phases must be had, unless //we're just a normal node. Then, we don't care. if (!has_phase(PHASE_A|PHASE_B|PHASE_C)) { gl_error("substation needs to have all three phases!"); /* TROUBLESHOOT To meet the requirements for sequence voltage conversions, the substation node must have all three phases at the connection point. If only a single phase or subset of full three phase is needed, those must be set in the distribution network, typically after a delta-ground wye transformer. */ return 0; } }//End not a normal node //set the reference phase number to shift the phase voltages appropriatly with the positive sequence voltage if(reference_phase == R_PHASE_A){ reference_number.SetPolar(1,0); } else if(reference_phase == R_PHASE_B){ reference_number.SetPolar(1,2*PI/3); } else if(reference_phase == R_PHASE_C){ reference_number.SetPolar(1,-2*PI/3); } //create the sequence to phase transformation matrix for(i=0; i<3; i++){ for(n=0; n<3; n++){ if((i==1 && n==1) || (i==2 && n==2)){ transformation_matrix[i][n].SetPolar(1,-2*PI/3); } else if((i==2 && n==1) || (i==1 && n==2)){ transformation_matrix[i][n].SetPolar(1,2*PI/3); } else { transformation_matrix[i][n].SetPolar(1,0); } } } return node::init(parent); }
/* Sync is called when the clock needs to advance on the bottom-up pass */ TIMESTAMP microturbine::sync(TIMESTAMP t0, TIMESTAMP t1) { //gather V_Out for each phase //gather I_Out for each phase //gather VA_Out for each phase //gather Q_Out //gather S_Out //gather Pf_Out phaseA_V_Out = pCircuit_V_A[0]; phaseB_V_Out = pCircuit_V_B[0]; phaseC_V_Out = pCircuit_V_C[0]; phaseA_I_Out = pLine_I_A[0]; phaseB_I_Out = pLine_I_B[0]; phaseC_I_Out = pLine_I_C[0]; gl_verbose("microturbine sync: phaseA_V_Out from parent is: (%f , %f)", phaseA_V_Out.Re(), phaseA_V_Out.Im()); gl_verbose("microturbine sync: phaseB_V_Out from parent is: (%f , %f)", phaseB_V_Out.Re(), phaseB_V_Out.Im()); gl_verbose("microturbine sync: phaseC_V_Out from parent is: (%f , %f)", phaseC_V_Out.Re(), phaseC_V_Out.Im()); gl_verbose("microturbine sync: phaseA_I_Out from parent is: (%f , %f)", phaseA_I_Out.Re(), phaseA_I_Out.Im()); gl_verbose("microturbine sync: phaseB_I_Out from parent is: (%f , %f)", phaseB_I_Out.Re(), phaseB_I_Out.Im()); gl_verbose("microturbine sync: phaseC_I_Out from parent is: (%f , %f)", phaseC_I_Out.Re(), phaseC_I_Out.Im()); power_A_Out = (~phaseA_I_Out) * phaseA_V_Out; power_B_Out = (~phaseB_I_Out) * phaseB_V_Out; power_C_Out = (~phaseC_I_Out) * phaseC_V_Out; gl_verbose("microturbine sync: power_A_Out from parent is: (%f , %f)", power_A_Out.Re(), power_A_Out.Im()); gl_verbose("microturbine sync: power_B_Out from parent is: (%f , %f)", power_B_Out.Re(), power_B_Out.Im()); gl_verbose("microturbine sync: power_C_Out from parent is: (%f , %f)", power_C_Out.Re(), power_C_Out.Im()); VA_Out = power_A_Out + power_B_Out + power_C_Out; E_A_Internal = determine_source_voltage(phaseA_V_Out, Rinternal, Rload); E_B_Internal = determine_source_voltage(phaseB_V_Out, Rinternal, Rload); E_C_Internal = determine_source_voltage(phaseC_V_Out, Rinternal, Rload); gl_verbose("microturbine sync: E_A_Internal calc is: (%f , %f)", E_A_Internal.Re(), E_A_Internal.Im()); gl_verbose("microturbine sync: E_B_Internal calc is: (%f , %f)", E_B_Internal.Re(), E_B_Internal.Im()); gl_verbose("microturbine sync: E_C_Internal calc is: (%f , %f)", E_C_Internal.Re(), E_C_Internal.Im()); frequency = determine_frequency(VA_Out); gl_verbose("microturbine sync: determined frequency is: %f", frequency); if(frequency > Max_Frequency){ throw ("the frequency asked for from the microturbine is too high!"); } if(frequency < Min_Frequency){ throw ("the frequency asked for from the microturbine is too low!"); } double loss = calculate_loss(frequency); efficiency = 1 - loss; Heat_Out = determine_heat(VA_Out, loss); Fuel_Used = Heat_Out + VA_Out.Mag(); gl_verbose("microturbine sync: about to exit"); return TS_NEVER; }
/* Object initialization is called once after all object have been created */ int microturbine::init(OBJECT *parent) { //generator_mode_choice = CONSTANT_PQ; gen_status_v = ONLINE; Rinternal = 0.05; Rload = 1; V_Max = complex(10000); I_Max = complex(1000); frequency = 0; Max_Frequency = 2000; Min_Frequency = 0; Fuel_Used = 0; Heat_Out = 0; KV = 1; //voltage constant Power_Angle = 1; Max_P = 100;//< maximum real power capacity in kW Min_P = 0;//< minimus real power capacity in kW Max_Q = 100;//< maximum reactive power capacity in kVar Min_Q = 0;//< minimus reactive power capacity in kVar Rated_kVA = 150; //< nominal capacity in kVA //double Rated_kV; //< nominal line-line voltage in kV efficiency = 0; pf_Out = 1; gl_verbose("microturbine init: finished initializing variables"); struct { complex **var; char *varname; } map[] = { // local object name, meter object name {&pCircuit_V_A, "phaseA_V_In"}, {&pCircuit_V_B, "phaseB_V_In"}, {&pCircuit_V_C, "phaseC_V_In"}, {&pLine_I_A, "phaseA_I_In"}, {&pLine_I_B, "phaseB_I_In"}, {&pLine_I_C, "phaseC_I_In"}, /// @todo use triplex property mapping instead of assuming memory order for meter variables (residential, low priority) (ticket #139) }; static complex default_line_voltage[1], default_line_current[1]; int i; // find parent meter, if not defined, use a default meter (using static variable 'default_meter') if (parent!=NULL && strcmp(parent->oclass->name,"meter")==0) { for (i=0; i<sizeof(map)/sizeof(map[0]); i++) *(map[i].var) = get_complex(parent,map[i].varname); gl_verbose("microturbine init: mapped METER objects to internal variables"); } else if (parent!=NULL && strcmp(parent->oclass->name,"rectifier")==0){ gl_verbose("microturbine init: parent WAS found, is an rectifier!"); // construct circuit variable map to meter /// @todo use triplex property mapping instead of assuming memory order for meter variables (residential, low priority) (ticket #139) for (i=0; i<sizeof(map)/sizeof(map[0]); i++){ *(map[i].var) = get_complex(parent,map[i].varname); } gl_verbose("microturbine init: mapped RECTIFIER objects to internal variables"); } else{ // construct circuit variable map to meter /// @todo use triplex property mapping instead of assuming memory order for meter variables (residential, low priority) (ticket #139) gl_verbose("microturbine init: mapped meter objects to internal variables"); OBJECT *obj = OBJECTHDR(this); gl_verbose("microturbine init: no parent meter defined, parent is not a meter"); gl_warning("microturbine:%d %s", obj->id, parent==NULL?"has no parent meter defined":"parent is not a meter"); // attach meter variables to each circuit in the default_meter *(map[0].var) = &default_line_voltage[0]; *(map[1].var) = &default_line_current[0]; // provide initial values for voltages default_line_voltage[0] = complex(V_Max.Re()/sqrt(3.0),0); default_line_current[0] = complex(I_Max.Re()); //default_line123_voltage[1] = complex(V_Max/sqrt(3.0)*cos(2*PI/3),V_Max/sqrt(3.0)*sin(2*PI/3)); //default_line123_voltage[2] = complex(V_Max/sqrt(3.0)*cos(-2*PI/3),V_Max/sqrt(3.0)*sin(-2*PI/3)); } gl_verbose("microturbine init: finished connecting with meter"); /* TODO: set the context-dependent initial value of properties */ //double ZB, SB, EB; //complex tst; if (gen_mode_v==UNKNOWN) { OBJECT *obj = OBJECTHDR(this); throw("Generator control mode is not specified"); } if (gen_status_v==0) { //OBJECT *obj = OBJECTHDR(this); throw("Generator is out of service!"); }else { return 1; } return 1; /* return 1 on success, 0 on failure */ }
TIMESTAMP inverter::sync(TIMESTAMP t0, TIMESTAMP t1) { if (*NR_mode == false) { phaseA_V_Out = pCircuit_V[0]; //Syncs the meter parent to the generator. phaseB_V_Out = pCircuit_V[1]; phaseC_V_Out = pCircuit_V[2]; internal_losses = 1 - calculate_loss(Rtotal, Ltotal, Ctotal, DC, AC); //gl_verbose("inverter sync: internal losses are: %f", 1 - internal_losses); frequency_losses = 1 - calculate_frequency_loss(output_frequency, Rtotal,Ltotal, Ctotal); //gl_verbose("inverter sync: frequency losses are: %f", 1 - frequency_losses); switch(gen_mode_v) { case CONSTANT_PF: { VA_In = V_In * ~ I_In; //DC // need to differentiate between different pulses... VA_Out = VA_In * efficiency * internal_losses * frequency_losses; //losses = VA_Out * Rtotal / (Rtotal + Rload); //VA_Out = VA_Out * Rload / (Rtotal + Rload); if (number_of_phases_out == 4) //Triplex-line -> Assume it's only across the 240 V for now. { power_A = complex(VA_Out.Mag()*abs(power_factor),power_factor/abs(power_factor)*VA_Out.Mag()*sin(acos(power_factor))); if (phaseA_V_Out.Mag() != 0.0) phaseA_I_Out = ~(power_A / phaseA_V_Out); else phaseA_I_Out = complex(0.0,0.0); *pLine12 += -phaseA_I_Out; //Update this value for later removal last_current[3] = -phaseA_I_Out; //Get rid of these for now //complex phaseA_V_Internal = filter_voltage_impact_source(phaseA_I_Out, phaseA_V_Out); //phaseA_I_Out = filter_current_impact_out(phaseA_I_Out, phaseA_V_Internal); } else if (number_of_phases_out == 3) { power_A = power_B = power_C = complex(VA_Out.Mag()*abs(power_factor),power_factor/abs(power_factor)*VA_Out.Mag()*sin(acos(power_factor)))/3; if (phaseA_V_Out.Mag() != 0.0) phaseA_I_Out = ~(power_A / phaseA_V_Out); // /sqrt(2.0); else phaseA_I_Out = complex(0.0,0.0); if (phaseB_V_Out.Mag() != 0.0) phaseB_I_Out = ~(power_B / phaseB_V_Out); // /sqrt(2.0); else phaseB_I_Out = complex(0.0,0.0); if (phaseC_V_Out.Mag() != 0.0) phaseC_I_Out = ~(power_C / phaseC_V_Out); // /sqrt(2.0); else phaseC_I_Out = complex(0.0,0.0); pLine_I[0] += -phaseA_I_Out; pLine_I[1] += -phaseB_I_Out; pLine_I[2] += -phaseC_I_Out; //Update this value for later removal last_current[0] = -phaseA_I_Out; last_current[1] = -phaseB_I_Out; last_current[2] = -phaseC_I_Out; //complex phaseA_V_Internal = filter_voltage_impact_source(phaseA_I_Out, phaseA_V_Out); //complex phaseB_V_Internal = filter_voltage_impact_source(phaseB_I_Out, phaseB_V_Out); //complex phaseC_V_Internal = filter_voltage_impact_source(phaseC_I_Out, phaseC_V_Out); //phaseA_I_Out = filter_current_impact_out(phaseA_I_Out, phaseA_V_Internal); //phaseB_I_Out = filter_current_impact_out(phaseB_I_Out, phaseB_V_Internal); //phaseC_I_Out = filter_current_impact_out(phaseC_I_Out, phaseC_V_Internal); } else if(number_of_phases_out == 2) { OBJECT *obj = OBJECTHDR(this); node *par = OBJECTDATA(obj->parent, node); if (par->has_phase(PHASE_A) && phaseA_V_Out.Mag() != 0) { power_A = complex(VA_Out.Mag()*abs(power_factor),power_factor/abs(power_factor)*VA_Out.Mag()*sin(acos(power_factor)))/2;; phaseA_I_Out = ~(power_A / phaseA_V_Out); } else phaseA_I_Out = complex(0,0); if (par->has_phase(PHASE_B) && phaseB_V_Out.Mag() != 0) { power_B = complex(VA_Out.Mag()*abs(power_factor),power_factor/abs(power_factor)*VA_Out.Mag()*sin(acos(power_factor)))/2;; phaseB_I_Out = ~(power_B / phaseB_V_Out); } else phaseB_I_Out = complex(0,0); if (par->has_phase(PHASE_C) && phaseC_V_Out.Mag() != 0) { power_C = complex(VA_Out.Mag()*abs(power_factor),power_factor/abs(power_factor)*VA_Out.Mag()*sin(acos(power_factor)))/2;; phaseC_I_Out = ~(power_C / phaseC_V_Out); } else phaseC_I_Out = complex(0,0); pLine_I[0] += -phaseA_I_Out; pLine_I[1] += -phaseB_I_Out; pLine_I[2] += -phaseC_I_Out; //Update this value for later removal last_current[0] = -phaseA_I_Out; last_current[1] = -phaseB_I_Out; last_current[2] = -phaseC_I_Out; } else if(number_of_phases_out == 1) { if(phaseA_V_Out.Mag() != 0) { power_A = complex(VA_Out.Mag()*abs(power_factor),power_factor/abs(power_factor)*VA_Out.Mag()*sin(acos(power_factor))); phaseA_I_Out = ~(power_A / phaseA_V_Out); //complex phaseA_V_Internal = filter_voltage_impact_source(phaseA_I_Out, phaseA_V_Out); //phaseA_I_Out = filter_current_impact_out(phaseA_I_Out, phaseA_V_Internal); } else if(phaseB_V_Out.Mag() != 0) { power_B = complex(VA_Out.Mag()*abs(power_factor),power_factor/abs(power_factor)*VA_Out.Mag()*sin(acos(power_factor))); phaseB_I_Out = ~(power_B / phaseB_V_Out); //complex phaseB_V_Internal = filter_voltage_impact_source(phaseB_I_Out, phaseB_V_Out); //phaseB_I_Out = filter_current_impact_out(phaseB_I_Out, phaseB_V_Internal); } else if(phaseC_V_Out.Mag() != 0) { power_C = complex(VA_Out.Mag()*abs(power_factor),power_factor/abs(power_factor)*VA_Out.Mag()*sin(acos(power_factor))); phaseC_I_Out = ~(power_C / phaseC_V_Out); //complex phaseC_V_Internal = filter_voltage_impact_source(phaseC_I_Out, phaseC_V_Out); //phaseC_I_Out = filter_current_impact_out(phaseC_I_Out, phaseC_V_Internal); } else { gl_warning("None of the phases specified have voltages!"); phaseA_I_Out = phaseB_I_Out = phaseC_I_Out = complex(0.0,0.0); } pLine_I[0] += -phaseA_I_Out; pLine_I[1] += -phaseB_I_Out; pLine_I[2] += -phaseC_I_Out; //Update this value for later removal last_current[0] = -phaseA_I_Out; last_current[1] = -phaseB_I_Out; last_current[2] = -phaseC_I_Out; } else { throw ("The number of phases given is unsupported."); } return TS_NEVER; } break; case CONSTANT_PQ: { GL_THROW("Constant PQ mode not supported at this time"); /* TROUBLESHOOT This will be worked on at a later date and is not yet correctly implemented. */ gl_verbose("inverter sync: constant pq"); //TODO //gather V_Out for each phase //gather V_In (DC) from line -- can not gather V_In, for now set equal to V_Out //P_Out is either set or input from elsewhere //Q_Out is either set or input from elsewhere //Gather Rload if(parent_string = "meter") { VA_Out = complex(P_Out,Q_Out); } else if (parent_string = "triplex_meter") { VA_Out = complex(P_Out,Q_Out); } else { phaseA_I_Out = pLine_I[0]; phaseB_I_Out = pLine_I[1]; phaseC_I_Out = pLine_I[2]; //Erm, there's no good way to handle this from a "multiply attached" point of view. //TODO: Think about how to do this if the need arrises VA_Out = phaseA_V_Out * (~ phaseA_I_Out) + phaseB_V_Out * (~ phaseB_I_Out) + phaseC_V_Out * (~ phaseC_I_Out); } pf_out = P_Out/VA_Out.Mag(); //VA_Out = VA_In * efficiency * internal_losses; if (number_of_phases_out == 3) { power_A = power_B = power_C = VA_Out /3; phaseA_I_Out = (power_A / phaseA_V_Out); // /sqrt(2.0); phaseB_I_Out = (power_B / phaseB_V_Out); // /sqrt(2.0); phaseC_I_Out = (power_C / phaseC_V_Out); // /sqrt(2.0); phaseA_I_Out = ~ phaseA_I_Out; phaseB_I_Out = ~ phaseB_I_Out; phaseC_I_Out = ~ phaseC_I_Out; } else if(number_of_phases_out == 1) { if(phaseAOut) { power_A = VA_Out; phaseA_I_Out = (power_A / phaseA_V_Out); // /sqrt(2); phaseA_I_Out = ~ phaseA_I_Out; } else if(phaseBOut) { power_B = VA_Out; phaseB_I_Out = (power_B / phaseB_V_Out); // /sqrt(2); phaseB_I_Out = ~ phaseB_I_Out; } else if(phaseCOut) { power_C = VA_Out; phaseC_I_Out = (power_C / phaseC_V_Out); // /sqrt(2); phaseC_I_Out = ~ phaseC_I_Out; } else { throw ("none of the phases have voltages!"); } } else { throw ("unsupported number of phases"); } VA_In = VA_Out / (efficiency * internal_losses * frequency_losses); losses = VA_Out * (1 - (efficiency * internal_losses * frequency_losses)); //V_In = complex(0,0); // ////is there a better way to do this? //if(phaseAOut){ // V_In += abs(phaseA_V_Out.Re()); //} //if(phaseBOut){ // V_In += abs(phaseB_V_Out.Re()); //} //if(phaseCOut){ // V_In += abs(phaseC_V_Out.Re()); //}else{ // throw ("none of the phases have voltages!"); //} V_In = Vdc; I_In = VA_In / V_In; I_In = ~I_In; V_In = filter_voltage_impact_source(I_In, V_In); I_In = filter_current_impact_source(I_In, V_In); gl_verbose("Inverter sync: V_In asked for by inverter is: (%f , %f)", V_In.Re(), V_In.Im()); gl_verbose("Inverter sync: I_In asked for by inverter is: (%f , %f)", I_In.Re(), I_In.Im()); pLine_I[0] += phaseA_I_Out; pLine_I[1] += phaseB_I_Out; pLine_I[2] += phaseC_I_Out; //Update this value for later removal last_current[0] = phaseA_I_Out; last_current[1] = phaseB_I_Out; last_current[2] = phaseC_I_Out; return TS_NEVER; } break; case CONSTANT_V: { GL_THROW("Constant V mode not supported at this time"); /* TROUBLESHOOT This will be worked on at a later date and is not yet correctly implemented. */ gl_verbose("inverter sync: constant v"); bool changed = false; //TODO //Gather V_Out //Gather VA_Out //Gather Rload if(phaseAOut) { if (phaseA_V_Out.Re() < (V_Set_A - margin)) { phaseA_I_Out = phaseA_I_Out_prev + I_step_max/2; changed = true; } else if (phaseA_V_Out.Re() > (V_Set_A + margin)) { phaseA_I_Out = phaseA_I_Out_prev - I_step_max/2; changed = true; } else { changed = false; } } if (phaseBOut) { if (phaseB_V_Out.Re() < (V_Set_B - margin)) { phaseB_I_Out = phaseB_I_Out_prev + I_step_max/2; changed = true; } else if (phaseB_V_Out.Re() > (V_Set_B + margin)) { phaseB_I_Out = phaseB_I_Out_prev - I_step_max/2; changed = true; } else { changed = false; } } if (phaseCOut) { if (phaseC_V_Out.Re() < (V_Set_C - margin)) { phaseC_I_Out = phaseC_I_Out_prev + I_step_max/2; changed = true; } else if (phaseC_V_Out.Re() > (V_Set_C + margin)) { phaseC_I_Out = phaseC_I_Out_prev - I_step_max/2; changed = true; } else { changed = false; } } power_A = (~phaseA_I_Out) * phaseA_V_Out; power_B = (~phaseB_I_Out) * phaseB_V_Out; power_C = (~phaseC_I_Out) * phaseC_V_Out; //check if inverter is overloaded -- if so, cap at max power if (((power_A + power_B + power_C) > Rated_kVA) || ((power_A.Re() + power_B.Re() + power_C.Re()) > Max_P) || ((power_A.Im() + power_B.Im() + power_C.Im()) > Max_Q)) { VA_Out = Rated_kVA / number_of_phases_out; //if it's maxed out, don't ask for the simulator to re-call changed = false; if(phaseAOut) { phaseA_I_Out = VA_Out / phaseA_V_Out; phaseA_I_Out = (~phaseA_I_Out); } if(phaseBOut) { phaseB_I_Out = VA_Out / phaseB_V_Out; phaseB_I_Out = (~phaseB_I_Out); } if(phaseCOut) { phaseC_I_Out = VA_Out / phaseC_V_Out; phaseC_I_Out = (~phaseC_I_Out); } } //check if power is negative for some reason, should never be if(power_A < 0) { power_A = 0; phaseA_I_Out = 0; throw("phaseA power is negative!"); } if(power_B < 0) { power_B = 0; phaseB_I_Out = 0; throw("phaseB power is negative!"); } if(power_C < 0) { power_C = 0; phaseC_I_Out = 0; throw("phaseC power is negative!"); } VA_In = VA_Out / (efficiency * internal_losses * frequency_losses); losses = VA_Out * (1 - (efficiency * internal_losses * frequency_losses)); //V_In = complex(0,0); // ////is there a better way to do this? //if(phaseAOut){ // V_In += abs(phaseA_V_Out.Re()); //} //if(phaseBOut){ // V_In += abs(phaseB_V_Out.Re()); //} //if(phaseCOut){ // V_In += abs(phaseC_V_Out.Re()); //}else{ // throw ("none of the phases have voltages!"); //} V_In = Vdc; I_In = VA_In / V_In; I_In = ~I_In; gl_verbose("Inverter sync: I_In asked for by inverter is: (%f , %f)", I_In.Re(), I_In.Im()); V_In = filter_voltage_impact_source(I_In, V_In); I_In = filter_current_impact_source(I_In, V_In); //TODO: check P and Q components to see if within bounds if(changed) { pLine_I[0] += phaseA_I_Out; pLine_I[1] += phaseB_I_Out; pLine_I[2] += phaseC_I_Out; //Update this value for later removal last_current[0] = phaseA_I_Out; last_current[1] = phaseB_I_Out; last_current[2] = phaseC_I_Out; TIMESTAMP t2 = t1 + 10 * 60 * TS_SECOND; return t2; } else { pLine_I[0] += phaseA_I_Out; pLine_I[1] += phaseB_I_Out; pLine_I[2] += phaseC_I_Out; //Update this value for later removal last_current[0] = phaseA_I_Out; last_current[1] = phaseB_I_Out; last_current[2] = phaseC_I_Out; return TS_NEVER; } } break; case SUPPLY_DRIVEN: { GL_THROW("SUPPLY_DRIVEN mode for inverters not supported at this time"); } default: { pLine_I[0] += phaseA_I_Out; pLine_I[1] += phaseB_I_Out; pLine_I[2] += phaseC_I_Out; //Update this value for later removal last_current[0] = phaseA_I_Out; last_current[1] = phaseB_I_Out; last_current[2] = phaseC_I_Out; return TS_NEVER; } break; } if (number_of_phases_out == 4) { *pLine12 += phaseA_I_Out; //Update this value for later removal last_current[3] = phaseA_I_Out; } else { pLine_I[0] += phaseA_I_Out; pLine_I[1] += phaseB_I_Out; pLine_I[2] += phaseC_I_Out; //Update this value for later removal last_current[0] = phaseA_I_Out; last_current[1] = phaseB_I_Out; last_current[2] = phaseC_I_Out; } return TS_NEVER; } else { if (number_of_phases_out == 4) { *pLine12 += last_current[3]; } else { pLine_I[0] += last_current[0]; pLine_I[1] += last_current[1]; pLine_I[2] += last_current[2]; } return TS_NEVER; } }
/* Object initialization is called once after all object have been created */ int micro_service::init(OBJECT *parent) { price = pmy_microturbine->microturbine_init(); struct { complex **var; char *varname; } map[] = { // local object name, meter object name {&pCircuit_V_A, "phaseA_V_In"}, {&pCircuit_V_B, "phaseB_V_In"}, {&pCircuit_V_C, "phaseC_V_In"}, {&pLine_I_A, "phaseA_I_In"}, {&pLine_I_B, "phaseB_I_In"}, {&pLine_I_C, "phaseC_I_In"}, /// @todo use triplex property mapping instead of assuming memory order for meter variables (residential, low priority) (ticket #139) }; static complex default_line_voltage[1], default_line_current[1]; int i; // find parent meter, if not defined, use a default meter (using static variable 'default_meter') if (parent!=NULL && strcmp(parent->oclass->name,"meter")==0) { for (i=0; i<sizeof(map)/sizeof(map[0]); i++) *(map[i].var) = get_complex(parent,map[i].varname); gl_verbose("micro_service init: mapped METER objects to internal variables"); } else if (parent!=NULL && strcmp(parent->oclass->name,"rectifier")==0){ gl_verbose("micro_service init: parent WAS found, is an rectifier!"); // construct circuit variable map to meter /// @todo use triplex property mapping instead of assuming memory order for meter variables (residential, low priority) (ticket #139) for (i=0; i<sizeof(map)/sizeof(map[0]); i++){ *(map[i].var) = get_complex(parent,map[i].varname); } gl_verbose("micro_service init: mapped RECTIFIER objects to internal variables"); } else{ // construct circuit variable map to meter /// @todo use triplex property mapping instead of assuming memory order for meter variables (residential, low priority) (ticket #139) gl_verbose("micro_service init: mapped meter objects to internal variables"); OBJECT *obj = OBJECTHDR(this); gl_verbose("micro_service init: no parent meter defined, parent is not a meter"); gl_warning("micro_service:%d %s", obj->id, parent==NULL?"has no parent meter defined":"parent is not a meter"); // attach meter variables to each circuit in the default_meter *(map[0].var) = &default_line_voltage[0]; *(map[1].var) = &default_line_current[0]; // provide initial values for voltages default_line_voltage[0] = complex(V_Max.Re()/sqrt(3.0),0); default_line_current[0] = complex(I_Max.Re()); //default_line123_voltage[1] = complex(V_Max/sqrt(3.0)*cos(2*PI/3),V_Max/sqrt(3.0)*sin(2*PI/3)); //default_line123_voltage[2] = complex(V_Max/sqrt(3.0)*cos(-2*PI/3),V_Max/sqrt(3.0)*sin(-2*PI/3)); } gl_verbose("micro_service init: finished connecting with meter"); /* TODO: set the context-dependent initial value of properties */ //double ZB, SB, EB; //complex tst; if (gen_mode_v==UNKNOWN) { OBJECT *obj = OBJECTHDR(this); throw("Generator control mode is not specified"); } if (gen_status_v==0) { //OBJECT *obj = OBJECTHDR(this); throw("Generator is out of service!"); }else { return 1; } return 1; /* return 1 on success, 0 on failure */ }
TIMESTAMP complex_assert::commit(TIMESTAMP t1, TIMESTAMP t2) { // handle once mode if ( once==ONCE_TRUE) { once_value = value; once = ONCE_DONE; } else if ( once==ONCE_DONE) { if ( once_value.Re()==value.Re() && once_value.Im()==value.Im() ) { gl_verbose("Assert skipped with ONCE logic"); return TS_NEVER; } else { once_value = value; } } // get the target property gld_property target_prop(get_parent(),get_target()); if ( !target_prop.is_valid() || target_prop.get_type()!=PT_complex ) { gl_error("Specified target %s for %s is not valid.",get_target(),get_parent()->get_name()); /* 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 0; } // test the target value complex x; target_prop.getp(x); if ( status==ASSERT_TRUE ) { if ( operation==FULL || operation==REAL || operation==IMAGINARY ) { complex error = x - value; double real_error = error.Re(); double imag_error = error.Im(); if ( ( _isnan(real_error) || fabs(real_error)>within ) && ( operation==FULL || operation==REAL ) ) { gl_error("Assert failed on %s: real part of %s %g not within %f of given value %g", get_parent()->get_name(), get_target(), x.Re(), within, value.Re()); return 0; } if ( ( _isnan(imag_error) || fabs(imag_error)>within ) && ( operation==FULL || operation==IMAGINARY ) ) { gl_error("Assert failed on %s: imaginary part of %s %+gi not within %f of given value %+gi", get_parent()->get_name(), get_target(), x.Im(), within, value.Im()); return 0; } } else if ( operation==MAGNITUDE ) { double magnitude_error = x.Mag() - value.Mag(); if ( _isnan(magnitude_error) || fabs(magnitude_error)>within ) { gl_error("Assert failed on %s: Magnitude of %s (%g) not within %f of given value %g", get_parent()->get_name(), get_target(), x.Mag(), within, value.Mag()); return 0; } } else if (get_operation() == ANGLE) { double angle_error = x.Arg() - value.Arg(); if ( _isnan(angle_error) || fabs(angle_error)>within ) { gl_error("Assert failed on %s: Angle of %s (%g) not within %f of given value %g", get_parent()->get_name(), get_target(), x.Arg(), within, value.Arg()); return 0; } } } else if (get_status() == ASSERT_FALSE) { complex error = x - value; double real_error = error.Re(); double imag_error = error.Im(); if ( ( _isnan(real_error) || fabs(real_error)<within ) || ( _isnan(imag_error) || fabs(imag_error)<within ) ) { if ( _isnan(real_error) || fabs(real_error)<within ) { gl_error("Assert failed on %s: real part of %s %g is within %f of %g", get_parent()->get_name(), get_target(), x.Re(), within, value.Re()); } if ( _isnan(imag_error) || fabs(imag_error)<within ) { gl_error("Assert failed on %s: imaginary part of %s %+gi is within %f of %gi", get_parent()->get_name(), get_target(), x.Im(), within, value.Im()); } return 0; } } else { gl_verbose("Assert test is not being run on %s", get_parent()->get_name()); return TS_NEVER; } gl_verbose("Assert passed on %s",get_parent()->get_name()); return TS_NEVER; }
/** 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; }
int collector::init(OBJECT *parent) { // check the connection if ( get_connection()!=NULL ) db = (database*)(get_connection()+1); if ( db==NULL ) exception("no database connection available or specified"); if ( !db->isa("database") ) exception("connection is not a mysql database"); gl_verbose("connection to mysql server '%s', schema '%s' ok", db->get_hostname(), db->get_schema()); // check mode if ( strlen(mode)>0 ) { options = 0xffffffff; struct { char *str; set bits; } modes[] = { {"r", 0xffff}, {"r+", 0xffff}, {"w", MO_DROPTABLES}, {"w+", MO_DROPTABLES}, {"a", 0x0000}, {"a+", 0x0000}, }; int n; for ( n=0 ; n<sizeof(modes)/sizeof(modes[0]) ; n++ ) { if ( strcmp(mode,modes[n].str)==0 ) { options = modes[n].bits; break; } } if ( options==0xffffffff ) exception("mode '%s' is not recognized",(const char*)mode); else if ( options==0xffff ) exception("mode '%s' is not valid for a recorder", (const char*)mode); } // verify group is defined if ( strcmp(get_group(),"")==0 ) exception("group must be specified"); // verify property is defined if ( strcmp(get_property(),"")==0 ) exception("at least one property aggregation must be specified"); // copy property spec into working buffer char1024 propspecs; strcpy(propspecs,get_property()); // count properties in specs char *p = propspecs; n_aggregates = 0; do { n_aggregates++; p = strchr(p,','); } while (p++!=NULL); list = new gld_aggregate[n_aggregates]; names = new char*[n_aggregates]; // load property structs int n; for ( p=propspecs,n=0 ; n<n_aggregates ; n++ ) { char *np = strchr(p,','); if ( np!=NULL ) *np='\0'; while ( *p!='\0' && isspace(*p) ) p++; // left trim int len = strlen(p); while ( len>0 && isspace(p[len-1]) ) p[--len]='\0'; // right trim if ( !list[n].set_aggregate(p,get_group()) ) exception("unable to aggregate '%s' over group '%s'", p, get_group()); gl_debug("%s: group '%s' aggregate '%s' initial value is '%lf'", get_name(), get_group(), p, list[n].get_value()); names[n] = new char[strlen(p)+1]; strcpy(names[n],p); p = np+1; } gl_debug("%s: %d aggregates ok", get_name(), n_aggregates); // drop table if exists and drop specified if ( db->table_exists(get_table()) ) { if ( get_options()&MO_DROPTABLES && !db->query("DROP TABLE IF EXISTS `%s`", get_table()) ) exception("unable to drop table '%s'", get_table()); } // create table if not exists if ( !db->table_exists(get_table()) ) { if ( !(options&MO_NOCREATE) ) { char buffer[4096]; size_t eos = sprintf(buffer,"CREATE TABLE IF NOT EXISTS `%s` (" "id INT AUTO_INCREMENT PRIMARY KEY, " "t TIMESTAMP, ", get_table()); int n; for ( n=0 ; n<n_aggregates ; n++ ) eos += sprintf(buffer+eos,"`%s` double, ",names[n]); eos += sprintf(buffer+eos,"%s","INDEX i_t (t))"); if ( !db->query(buffer) ) exception("unable to create table '%s' in schema '%s'", get_table(), db->get_schema()); else gl_verbose("table %s created ok", get_table()); } else exception("NOCREATE option prevents creation of table '%s'", get_table()); } // check row count else { if ( db->select("SELECT count(*) FROM `%s`", get_table())==NULL ) exception("unable to get row count of table '%s'", get_table()); gl_verbose("table '%s' ok", get_table()); } // first event time TIMESTAMP dt = (TIMESTAMP)get_interval(); if ( dt>0 ) next_t = (TIMESTAMP)(gl_globalclock/dt+1)*dt; else if ( dt==0 ) next_t = TS_NEVER; else exception("%s: interval must be zero or positive"); // @todo use prepared statement instead of insert // set heartbeat if ( interval>0 ) set_heartbeat((TIMESTAMP)interval); return 1; }
/** Initialize water heater model properties - randomized defaults for all published variables **/ int waterheater::init(OBJECT *parent) { OBJECT *hdr = OBJECTHDR(this); if(parent != NULL){ if((parent->flags & OF_INIT) != OF_INIT){ char objname[256]; gl_verbose("waterheater::init(): deferring initialization on %s", gl_name(parent, objname, 255)); return 2; // defer } } hdr->flags |= OF_SKIPSAFE; static double sTair = 74; static double sTout = 68; if(parent){ pTair = gl_get_double_by_name(parent, "air_temperature"); pTout = gl_get_double_by_name(parent, "outdoor_temperature"); } if(pTair == 0){ pTair = &sTair; gl_warning("waterheater parent lacks \'air_temperature\' property, using default"); } if(pTout == 0){ pTout = &sTout; gl_warning("waterheater parent lacks \'outside_temperature\' property, using default"); } /* sanity checks */ /* initialize water tank volume */ if(tank_volume <= 0.0){ // tank_volume = 5*floor((1.0/5.0)*gl_random_uniform(0.90, 1.10) * 50.0 * (pHouse->get_floor_area() /2000.0)); // [gal] if (tank_volume > 100.0) tank_volume = 100.0; else if (tank_volume < 20.0) tank_volume = 20.0; } else { if (tank_volume > 100.0 || tank_volume < 20.0){ gl_error("watertank volume of %f outside the volume bounds of 20 to 100 gallons.", tank_volume); /* TROUBLESHOOT All waterheaters must be set between 40 and 100 gallons. Most waterheaters are assumed to be 50 gallon tanks. */ } } if (tank_setpoint<90 || tank_setpoint>160) gl_error("watertank thermostat is set to %f and is outside the bounds of 90 to 160 degrees Fahrenheit (32.2 - 71.1 Celsius).", tank_setpoint); /* TROUBLESHOOT All waterheaters must be set between 90 degF and 160 degF. /* initialize water tank deadband */ if (thermostat_deadband>10 || thermostat_deadband < 0.0) GL_THROW("watertank deadband of %f is outside accepted bounds of 0 to 10 degrees (5.6 degC).", thermostat_deadband); // initial tank UA if (tank_UA <= 0.0) GL_THROW("Tank UA value is negative."); // Set heating element capacity if not provided by the user if (heating_element_capacity <= 0.0) { if (tank_volume >= 50) heating_element_capacity = 4.500; else { // Smaller tanks can be either 3200, 3500, or 4500... double randVal = gl_random_uniform(RNGSTATE,0,1); if (randVal < 0.33) heating_element_capacity = 3.200; else if (randVal < 0.67) heating_element_capacity = 3.500; else heating_element_capacity = 4.500; } } // set gas electric loads, if not provided by the user if(0 > gas_fan_power){ gas_fan_power = heating_element_capacity * 0.01; } if(0 > gas_standby_power){ gas_standby_power = 0.0; // some units consume 3-5W } // Other initial conditions if(Tw < Tinlet){ // uninit'ed temperature Tw = gl_random_uniform(RNGSTATE,tank_setpoint - thermostat_deadband, tank_setpoint + thermostat_deadband); } current_model = NONE; load_state = STABLE; // initial demand Tset_curtail = tank_setpoint - thermostat_deadband/2 - 10; // Allow T to drop only 10 degrees below lower cut-in T... // Setup derived characteristics... area = (pi * pow(tank_diameter,2))/4; height = tank_volume/GALPCF / area; Cw = tank_volume/GALPCF * RHOWATER * Cp; // [Btu/F] h = height; // initial water temperature if(h == 0){ // discharged Tlower = Tinlet; Tupper = Tinlet + TSTAT_PRECISION; } else { Tlower = Tinlet; } /* schedule checks */ switch(shape.type){ case MT_UNKNOWN: /* normal, undriven behavior. */ break; case MT_ANALOG: if(shape.params.analog.energy == 0.0){ GL_THROW("waterheater does not support fixed energy shaping"); /* TROUBLESHOOT Though it is possible to drive the water demand of a water heater, it is not possible to shape its power or energy draw. Its heater is either on or off, not in between. Change the load shape to not specify the power or energy and try again. */ } else if (shape.params.analog.power == 0){ /* power-driven ~ cheat with W/degF*gpm */ // double heat_per_gallon = RHOWATER * // lb/cf // CFPGAL * // lb/gal // CWATER * // BTU/degF / gal // KWBTUPH / // kW/gal // 1000.0; // W/gal water_demand = gl_get_loadshape_value(&shape) / 2.4449; } else { water_demand = gl_get_loadshape_value(&shape); /* unitless ~ drive gpm */ } break; case MT_PULSED: /* pulsed loadshapes "emit one or more pulses at random times s. t. the total energy is accumulated over the period of the loadshape". * pulsed loadshapes can either user time or kW values per pulse. */ if(shape.params.pulsed.pulsetype == MPT_TIME){ ; /* constant time pulse ~ consumes X gallons to drive heater for Y hours ~ but what's Vdot, what's t? */ } else if(shape.params.pulsed.pulsetype == MPT_POWER){ ; /* constant power pulse ~ draws water to consume X kW, limited by C + Q * h ~ Vdot proportional to power/time */ water_demand = gl_get_loadshape_value(&shape) / 2.4449; } break; case MT_MODULATED: if(shape.params.modulated.pulsetype == MPT_TIME){ GL_THROW("Amplitude modulated water usage is nonsensical for residential water heaters"); /* TROUBLESHOOT Though it is possible to put a constant, low-level water draw on a water heater, it is thoroughly counterintuitive to the normal usage of the waterheater. */ } else if(shape.params.modulated.pulsetype == MPT_POWER){ /* frequency modulated */ /* fixed-amplitude, varying length pulses at regular intervals. */ water_demand = gl_get_loadshape_value(&shape) / 2.4449; } break; case MT_QUEUED: if(shape.params.queued.pulsetype == MPT_TIME){ ; /* constant time pulse ~ consumes X gallons/minute to consume Y thermal energy */ } else if(shape.params.queued.pulsetype == MPT_POWER){ ; /* constant power pulse ~ draws water to consume X kW, limited by C + Q * h */ water_demand = gl_get_loadshape_value(&shape) / 2.4449; } break; default: GL_THROW("waterheater load shape has an unknown state!"); break; } return residential_enduse::init(parent); }
int refrigerator::init(OBJECT *parent) { if(parent != NULL){ if((parent->flags & OF_INIT) != OF_INIT){ char objname[256]; gl_verbose("refrigerator::init(): deferring initialization on %s", gl_name(parent, objname, 255)); return 2; // defer } } OBJECT *hdr = OBJECTHDR(this); hdr->flags |= OF_SKIPSAFE; // defaults for unset values */ if (size==0) size = gl_random_uniform(&hdr->rng_state,20,40); // cf if (thermostat_deadband==0) thermostat_deadband = gl_random_uniform(&hdr->rng_state,2,3); if (Tset==0) Tset = gl_random_uniform(&hdr->rng_state,35,39); if (UA == 0) UA = 0.6; if (UAr==0) UAr = UA+size/40*gl_random_uniform(&hdr->rng_state,0.9,1.1); if (UAf==0) UAf = gl_random_uniform(&hdr->rng_state,0.9,1.1); if (COPcoef==0) COPcoef = gl_random_uniform(&hdr->rng_state,0.9,1.1); if (Tout==0) Tout = 59.0; if (load.power_factor==0) load.power_factor = 0.95; pTout = (double*)gl_get_addr(parent, "air_temperature"); if (pTout==NULL) { static double default_air_temperature = 72; gl_warning("%s (%s:%d) parent object lacks air temperature, using %0f degF instead", hdr->name, hdr->oclass->name, hdr->id, default_air_temperature); pTout = &default_air_temperature; } /* derived values */ Tair = gl_random_uniform(&hdr->rng_state,Tset-thermostat_deadband/2, Tset+thermostat_deadband/2); // size is used to couple Cw and Qrated Cf = size/10.0 * RHOWATER * CWATER; // cf * lb/cf * BTU/lb/degF = BTU / degF rated_capacity = BTUPHPW * size*10; // BTU/h ... 10 BTU.h / cf (34W/cf, so ~700 for a full-sized refrigerator) start_time = 0; if(compressor_off_normal_energy==0) compressor_off_normal_energy=15*45*60; //watt-secs if(compressor_off_normal_power==0) compressor_off_normal_power=15; //watt if(long_compressor_cycle_energy==0) long_compressor_cycle_energy=120*100*60; //watt-secs if(long_compressor_cycle_power==0) long_compressor_cycle_power=120; //watt if(compressor_on_normal_energy==0) compressor_on_normal_energy=120*35*60; //watt-secs if(compressor_on_normal_power==0) compressor_on_normal_power=120; //watt if(defrost_energy==0) defrost_energy=40*550*60; //watt-secs if(defrost_power==0) defrost_power=550; //watt if(icemaking_energy==0) icemaking_energy=300*60; //watt-secs if(icemaking_power==0) icemaking_power=300; //watt if(ice_making_probability==0) ice_making_probability=0.02; //watt if(DO_Thershold==0) DO_Thershold=24; if(long_compressor_cycle_threshold==0) long_compressor_cycle_threshold=0.05; if(FF_Door_Openings==0) FF_Door_Openings=0; if(door_opening_power==0) door_opening_power=16; if(delay_defrost_time==0) delay_defrost_time=28800; if(defrost_criterion==0) defrost_criterion=DC_TIMED; refrigerator_power = 0; return_time = 0; no_of_defrost = 0; total_compressor_time = 0; if(door_open_time==0) door_open_time=7; long_compressor_cycle_due=false; door_energy_calc = false; ice_making_time = new double[1,2,3]; icemaker_running = false; check_defrost = false; switch(state){ case RS_DEFROST: if(energy_needed==0) energy_needed = defrost_energy; cycle_time = ceil((energy_needed - energy_used)/defrost_power); break; case RS_COMPRESSSOR_OFF_NORMAL: if(energy_needed==0) energy_needed = compressor_off_normal_energy; cycle_time = ceil((energy_needed - energy_used)/compressor_off_normal_power); break; case RS_COMPRESSSOR_ON_NORMAL: if(energy_needed==0) energy_needed = compressor_on_normal_energy; cycle_time = ceil((energy_needed - energy_used)/compressor_on_normal_power); break; } run_defrost = false; if (is_240) { load.config = EUC_IS220; } load.total = Qr * KWPBTUPH; return residential_enduse::init(parent); }
int dishwasher::init(OBJECT *parent) { // @todo This class has serious problems and should be deleted and started from scratch. Fuller 9/27/2013. OBJECT *hdr = OBJECTHDR(this); if(parent != NULL){ if((parent->flags & OF_INIT) != OF_INIT){ char objname[256]; gl_verbose("dishwasher::init(): deferring initialization on %s", gl_name(parent, objname, 255)); return 2; // defer } } int rv = 0; // default properties if (motor_power==0) motor_power = gl_random_uniform(&hdr->rng_state,150,350); if (heat_fraction==0) heat_fraction = 0.2; if (is_240) { load.config = EUC_IS220; if (stall_voltage==0) stall_voltage = 0.6*240; } else if (stall_voltage==0) stall_voltage = 0.6*120; if (trip_delay==0) trip_delay = 10; if (reset_delay==0) reset_delay = 60; count_motor_only = 0; count_motor_only1 =0; count_motor_only_25 = 0; count_coil_only = 0; count_control_only =0; count_control_only1 =0; count_motor_only_68 =0; pulse_interval[0] = 8; pulse_interval[1] = 18; pulse_interval[2] = 21; pulse_interval[3] = 28; pulse_interval[4] = 38; pulse_interval[5] = 50; pulse_interval[6] = 65; pulse_interval[7] = 118; pulse_interval[8] = 150; pulse_interval[9] = 220; pulse_interval[10] = 320; pulse_interval[11] = 355; pulse_interval[12] = 460; pulse_interval[13] = 580; pulse_interval[14] = 615; pulse_interval[15] = 780; pulse_interval[16] = 800; pulse_interval[17] = 950; pulse_interval[18] = 1150; if (coil_power[0]==-1) coil_power[0] = 5800; coil_power[0] = 10; coil_power[1] = 580; coil_power[2] = 695; coil_power[3] = 950; motor_power = 250; enduse_queue = 1; queue_min = 0; queue_max = 2; control_check1 = false; control_check2 = false; control_check3 = false; control_check4 = false; control_check5 = false; control_check6 = false; control_check7 = false; control_check8 = false; control_check9 = false; control_check10 = false; control_check11 = false; control_check12 = false; motor_only_check1 = false; motor_only_check2 = false; motor_only_check3 = false; motor_only_check4 = false; motor_only_check5 = false; motor_only_check6 = false; motor_only_check7 = false; motor_only_check8 = false; motor_only_check9 = false; motor_coil_only_check1 = false; motor_coil_only_check2 = false; heateddry_check1 = false; heateddry_check2 = false; coil_only_check1 = false; coil_only_check2 = false; coil_only_check3 = false; //Heateddry_option_check = false; hdr->flags |= OF_SKIPSAFE; load.power_factor = 0.95; load.breaker_amps = 30; actual_dishwasher_demand = 0; energy_needed = 0; rv = residential_enduse::init(parent); if (rv==SUCCESS) update_state(0.0); /* schedule checks */ switch(shape.type){ case MT_UNKNOWN: gl_warning("This device, %s, is considered very experimental and has not been validated.", get_name()); break; case MT_ANALOG: if(shape.params.analog.energy == 0.0){ GL_THROW("dishwasher does not support fixed energy shaping"); } else if (shape.params.analog.power == 0){ daily_dishwasher_demand = gl_get_loadshape_value(&shape) / 2.4449; } else { daily_dishwasher_demand = gl_get_loadshape_value(&shape); /* unitless ~ drive gpm */ } break; case MT_PULSED: /* pulsed loadshapes "emit one or more pulses at random times s. t. the total energy is accumulated over the period of the loadshape". * pulsed loadshapes can either user time or kW values per pulse. */ if(shape.params.pulsed.pulsetype == MPT_TIME){ ; /* constant time pulse ~ consumes X gallons to drive heater for Y hours ~ but what's Vdot, what's t? */ } else if(shape.params.pulsed.pulsetype == MPT_POWER){ ; /* constant power pulse ~ dishwasher demand X kW, limited by C + Q * h ~ Vdot proportional to power/time */ daily_dishwasher_demand = gl_get_loadshape_value(&shape) / 2.4449; } break; case MT_MODULATED: if(shape.params.modulated.pulsetype == MPT_TIME){ GL_THROW("Amplitude modulated dishwasher usage is nonsensical for residential dishwashers"); /* TROUBLESHOOT Though it is possible to put a constant, low-level dishwasher demand, it is thoroughly counterintuitive to the normal usage of the dishwasher. */ } else if(shape.params.modulated.pulsetype == MPT_POWER){ /* frequency modulated */ /* fixed-amplitude, varying length pulses at regular intervals. */ daily_dishwasher_demand = gl_get_loadshape_value(&shape) / 2.4449; } break; case MT_QUEUED: if(shape.params.queued.pulsetype == MPT_TIME){ ; /* constant time pulse ~ consumes X gallons/minute to consume Y thermal energy */ } else if(shape.params.queued.pulsetype == MPT_POWER){ ; /* constant power pulse ~ dishwasher demand X kW, limited by C + Q * h */ daily_dishwasher_demand = gl_get_loadshape_value(&shape) / 2.4449; } break; default: GL_THROW("dishwasher load shape has an unknown state!"); break; } return residential_enduse::init(parent); //} // must run before update_state() so that pCircuit can be set // return rv; }
int ZIPload::init(OBJECT *parent) { ////////////////////////////////////SEARCH//////////////////////////////////// static FINDLIST *xt2=NULL; xt2=gl_find_objects(FL_NEW,FT_CLASS,SAME,"irrigation_controller",FT_END); OBJECT *firstt2= gl_find_next(xt2,NULL); OBJECT *it2; for(it2=firstt2;it2!=NULL;it2=it2->next) { if(gl_object_isa(it2,"irrigation_controller")) { if(OBJECTHDR(this)->id==it2->parent->id) { irrigation_contr_object=it2; // printf("%d %d",OBJECTHDR(this)->id,irrigation_contr_object->id); //system("pause"); } else { // irrigation_contr_object=NULL; } } } static FINDLIST *xt1=NULL; xt1=gl_find_objects(FL_NEW,FT_CLASS,SAME,"auction",FT_END); OBJECT *firstt1= gl_find_next(xt1,NULL); OBJECT *it1; for(it1=firstt1;it1!=NULL;it1=it1->next) { if(gl_object_isa(it1,"auction")) { auction_object=it1; } } ////////////////////////////////////////////////////////////////////////////// if(parent != NULL){ if((parent->flags & OF_INIT) != OF_INIT){ char objname[256]; gl_verbose("zipload::init(): deferring initialization on %s", gl_name(parent, objname, 255)); return 2; // defer } } OBJECT *hdr = OBJECTHDR(this); hdr->flags |= OF_SKIPSAFE; if (demand_response_mode == true) { gl_warning("zipload_init: The demand response zipload is an experimental model at this time."); /* TROUBLESHOOT The warning is pretty obvious. However, over time, we will be developing this model further. If you have any questions about it, please see the Matlab files found in ../design/dr_model/ or read the paper titled "On the Equilibrium Dynamics of Demand Response" submitted to HICSS 2011 or post your questions on the WIKI forum. */ // Initial error checks if (abs(eta) > 1) { GL_THROW("zipload_init: demand_rate (eta) must be between -1 and 1."); /* TROUBLESHOOT The demand rate is limited to values between -1 and 1 (inclusive). Please reset to an appropriate value. */ } if (phi < 0 || phi > 1) { GL_THROW("zipload_init: duty_cycle (phi) must be between 0 and 1."); /* TROUBLESHOOT The duty cycle is only explicitly used if ron and roff are not set. In normal operation, phi will be calculated from ron and roff as a function of time. However, if ron and roff are not set, the initial values for ron and roff are calculated from phi. Please set to a value between 1 and 0 (inclusive). */ } // Set up the buffers and perform some error checks if (L > 0) if (L < 70) drm.nbins = L; else { gl_warning("zipload_init: Using a value for thermostatic_control_range (L) greater than 50 may cause some instabilities."); /* TROUBLESHOOT This warning is shown only as a reminder. Large values of L (thermostatic_control_range) can cause instabilities for some combinations of ron and roff. If you receive inderminant numbers as part of the solution, try reducing L. */ } else { GL_THROW("zipload_init: thermostatic_control_range (L) must be greater than 0."); /* TROUBLESHOOT The thermostatic control range must be a positive integer value, since this is used to create the number of bins for the discrete solution. */ } drm.off = (double*)malloc(sizeof(double)*L); drm.on = (double*)malloc(sizeof(double)*L); if (drm.off==NULL || drm.on==NULL) { GL_THROW("zipload_init: memory allocation error. Please report this error."); /* TROUBLESHOOT If you receive this error, something went horribly wrong with a memory allocation. Please report this to TRAC and provide the glm file that caused it. */ } /* setup the initial population */ if (ron == -1 || roff == -1) { if (phi <= 0.5) { roff = phi/(1-phi); ron = 1; gl_warning("ron or roff was not set. Using phi to calculate. Step changes in demand rates as a function of time will be ignored."); /* TROUBLESHOOT Ideally, in the method currently being used, ron and roff (heating and cooling rates) should be used to calculate phi. If you receive this error, the phi is being used to calculate ron and roff initially. However, phi does not update ron and roff at each time step, so you will not be able to perform disturbances of demand. If you wish this, please use ron and roff as a function of time instead. This can also be caused by using a schedule or player transform to describe the ron or roff values - essentially during the initialization, the value is not described yet. There is no current fix for this, but can be "faked" by setting phi to the correct initial value and waiting a couple of timesteps for things to settle. */ } else { roff = 1; ron = (1-phi)/phi; gl_warning("ron or roff was not set. Using phi to calculate. Step changes in demand rates as a function of time will be ignored."); /* TROUBLESHOOT Ideally, in the method currently being used, ron and roff (heating and cooling rates) should be used to calculate phi. If you receive this error, the phi is being used to calculate ron and roff initially. However, phi does not update ron and roff at each time step, so you will not be able to perform disturbances of demand. If you wish this, please use ron and roff as a function of time instead. This can also be caused by using a schedule or player transform to describe the ron or roff values - essentially during the initialization, the value is not described yet. There is no current fix for this, but can be "faked" by setting phi to the correct initial value and waiting a couple of timesteps for things to settle. */ } } else phi = roff / (ron + roff); if (roff < 0 || ron < 0) { GL_THROW("zipload_init: rate_of_cooling and rate_of_heating must be greater than or equal to 0."); /* TROUBLESHOOT Rates of heating and cooling should be positive or zero values. These values describe how fast objects transition from a cooler to hotter temperature, or vice versa, and have been defined as positive values in this model. */ } non = noff = 0; double test_N = 0; for (x=0; x<L; x++) { /* exponential distribution */ if (eta != 0) { drm.on[x] = N * eta * (1-phi) * exp(eta*(L-0.5-x)/roff) / (exp(eta*L/roff)-1); drm.off[x] = drm.on[x] * ron/roff; test_N += drm.on[x] + drm.off[x]; //non += drm.on[x] = eta * (1-phi) * exp(eta*(L-x+0.5)/roff) / (exp(eta*L/roff)-1); //noff += drm.off[x] = drm.on[x]*ron/roff; } /* uniform distribution */ else { non += drm.on[x] = N * phi/L; noff += drm.off[x] = N * (1-phi)/L; printf("testsfsdfsdfs : : : ;%f %f",non,noff); } } /* check for valid population */ if (abs(test_N - N) != 0) { double extra = N - test_N; drm.off[0] += extra; } } if (duty_cycle > 1 || duty_cycle < 0) { if (duty_cycle != -1) { GL_THROW("Value of duty cycle is set to a value outside of 0-1."); /* TROUBLESHOOT By definition, a duty cycle must be between, and including, 0 and 1. Zero will turn the duty cycle function OFF. Please specify a duty_cycle value between 0 and 1. */ } } // We're using a duty cycle mode if (duty_cycle != -1) { if (period <= 0) { GL_THROW("Period is less than or equal to zero."); /* TROUBLESHOOT When using duty cycle mode, the period must be a positive value. */ } if (phase < 0 || phase > 1) { GL_THROW("Phase is not between zero and one."); /* TROUBLESHOOT When using duty cycle mode, the phase must be specified as a value between 0 and 1. This will set the initial phase as a percentage of the period. The "duty" will assume to be applied at the beginning of each period. Randomizing this input value will prevent syncing of objects. */ } } if (heatgain_only == true) { load.config = EUC_HEATLOAD; load.power_fraction = load.current_fraction = load.impedance_fraction = 0.0; } if (is_240) //See if the 220/240 flag needs to be set { load.config |= EUC_IS220; } load.breaker_amps = breaker_val; only_once=0; first_time=0; return residential_enduse::init(parent); }