00001
00113 #include <stdlib.h>
00114 #include <stdio.h>
00115 #include <errno.h>
00116 #include <math.h>
00117 #include "solvers.h"
00118 #include "house_a.h"
00119
00120 EXPORT CIRCUIT *attach_enduse_house_a(OBJECT *obj, enduse *target, double breaker_amps, int is220)
00121 {
00122 house *pHouse = 0;
00123 CIRCUIT *c = 0;
00124
00125 if(obj == NULL){
00126 GL_THROW("attach_house_a: null object reference");
00127 }
00128 if(target == NULL){
00129 GL_THROW("attach_house_a: null enduse target data");
00130 }
00131 if(breaker_amps < 0 || breaker_amps > 1000){
00132 GL_THROW("attach_house_a: breaker amps of %i unrealistic", breaker_amps);
00133 }
00134
00135 pHouse = OBJECTDATA(obj,house);
00136 return pHouse->attach(target,breaker_amps,is220);
00137 }
00138
00140
00142 CLASS* house::oclass = NULL;
00143 CLASS* house::pclass = NULL;
00144
00148 house::house(MODULE *mod) : residential_enduse(mod)
00149 {
00150
00151 if (oclass==NULL)
00152 {
00153
00154 oclass = gl_register_class(mod,"house_a",sizeof(house),PC_PRETOPDOWN|PC_BOTTOMUP|PC_AUTOLOCK);
00155 if (oclass==NULL)
00156 throw "unable to register class house_a";
00157 else
00158 oclass->trl = TRL_DEMONSTRATED;
00159
00160
00161 if (gl_publish_variable(oclass,
00162 PT_INHERIT, "residential_enduse",
00163 PT_double,"floor_area[sf]",PADDR(floor_area), PT_DESCRIPTION, "area of the house's ground floor",
00164 PT_double,"gross_wall_area[sf]",PADDR(gross_wall_area), PT_DESCRIPTION, "total exterior wall area",
00165 PT_double,"ceiling_height[ft]",PADDR(ceiling_height), PT_DESCRIPTION, "height of the house's ceiling, across all floors",
00166 PT_double,"aspect_ratio",PADDR(aspect_ratio), PT_DESCRIPTION, "ratio of the length to the width of the house's ground footprint",
00167 PT_double,"envelope_UA[Btu/degF*h]",PADDR(envelope_UA), PT_DESCRIPTION, "insulative UA value of the house, based on insulation thickness and surface area",
00168 PT_double,"window_wall_ratio",PADDR(window_wall_ratio), PT_DESCRIPTION, "ratio of exterior window area to exterior wall area",
00169 PT_double,"glazing_shgc",PADDR(glazing_shgc), PT_DESCRIPTION, "siding glazing solar heat gain coeffient",
00170 PT_double,"airchange_per_hour",PADDR(airchange_per_hour), PT_DESCRIPTION, "volume of air exchanged between the house and exterior per hour",
00171 PT_double,"solar_gain[Btu/h]",PADDR(solar_load), PT_DESCRIPTION, "thermal solar input",
00172 PT_double,"heat_cool_gain[Btu/h]",PADDR(hvac_rated_capacity), PT_DESCRIPTION, "thermal gain rate of the installed HVAC",
00173 PT_double,"thermostat_deadband[degF]",PADDR(thermostat_deadband), PT_DESCRIPTION, "",
00174 PT_double,"heating_setpoint[degF]",PADDR(heating_setpoint), PT_DESCRIPTION, "",
00175 PT_double,"cooling_setpoint[degF]",PADDR(cooling_setpoint), PT_DESCRIPTION, "",
00176 PT_double, "design_heating_capacity[Btu*h]",PADDR(design_heating_capacity), PT_DESCRIPTION, "",
00177 PT_double,"design_cooling_capacity[Btu*h]",PADDR(design_cooling_capacity), PT_DESCRIPTION, "",
00178 PT_double,"heating_COP",PADDR(heating_COP), PT_DESCRIPTION, "",
00179 PT_double,"cooling_COP",PADDR(cooling_COP), PT_DESCRIPTION, "",
00180 PT_double,"COP_coeff",PADDR(COP_coeff), PT_DESCRIPTION, "",
00181 PT_double,"air_temperature[degF]",PADDR(Tair), PT_DESCRIPTION, "",
00182 PT_double,"outside_temp[degF]",PADDR(Tout), PT_DESCRIPTION, "",
00183 PT_double,"mass_temperature[degF]",PADDR(Tmaterials), PT_DESCRIPTION, "",
00184 PT_double,"mass_heat_coeff",PADDR(house_content_heat_transfer_coeff), PT_DESCRIPTION, "",
00185 PT_double,"outdoor_temperature[degF]",PADDR(outside_temp), PT_DESCRIPTION, "",
00186 PT_double,"house_thermal_mass[Btu/degF]",PADDR(house_content_thermal_mass), PT_DESCRIPTION, "thermal mass of the house's contained mass",
00187 PT_enumeration,"heat_mode",PADDR(heat_mode), PT_DESCRIPTION, "",
00188 PT_KEYWORD,"ELECTRIC",(enumeration)ELECTRIC,
00189 PT_KEYWORD,"GASHEAT",(enumeration)GASHEAT,
00190 PT_enumeration,"hc_mode",PADDR(heat_cool_mode), PT_DESCRIPTION, "",
00191 PT_KEYWORD,"OFF",(enumeration)OFF,
00192 PT_KEYWORD,"HEAT",(enumeration)HEAT,
00193 PT_KEYWORD,"COOL",(enumeration)COOL,
00194 PT_enduse,"houseload",PADDR(tload), PT_DESCRIPTION, "",
00195 NULL)<1)
00196 GL_THROW("unable to publish properties in %s",__FILE__);
00197 gl_publish_function(oclass, "attach_enduse", (FUNCTIONADDR)&attach_enduse_house_a);
00198 }
00199 }
00200
00201 int house::create()
00202 {
00203 int res = residential_enduse::create();
00204
00205 static char tload_name[32] = "house_total";
00206 static char load_name[32] = "house_hvac";
00207
00208 tload.name = tload_name;
00209 tload.power = complex(0,0,J);
00210 tload.admittance = complex(0,0,J);
00211 tload.current = complex(0,0,J);
00212 load.name = load_name;
00213 load.power = complex(0,0,J);
00214 load.admittance = complex(0,0,J);
00215 load.current = complex(0,0,J);
00216
00217 tload.end_obj = OBJECTHDR(this);
00218
00219
00220 heat_mode = ELECTRIC;
00221 floor_area = 0.0;
00222 ceiling_height = 0.0;
00223 envelope_UA = 0.0;
00224 airchange_per_hour = 0.0;
00225 thermostat_deadband = 0.0;
00226 heating_setpoint = 0.0;
00227 cooling_setpoint = 0.0;
00228 window_wall_ratio = 0.0;
00229 gross_wall_area = 0.0;
00230 glazing_shgc = 0.0;
00231 design_heating_capacity = 0.0;
00232 design_cooling_capacity = 0.0;
00233 heating_COP = 3.0;
00234 cooling_COP = 3.0;
00235 aspect_ratio = 1.0;
00236 air_density = 0.0735;
00237 air_heat_capacity = 0.2402;
00238 house_content_thermal_mass = 10000.0;
00239
00240
00241 panel.circuits=NULL;
00242 panel.max_amps=200;
00243
00244 return res;
00245
00246 }
00247
00252 int house::init_climate()
00253 {
00254 OBJECT *hdr = OBJECTHDR(this);
00255
00256
00257 static FINDLIST *climates = NULL;
00258 int not_found = 0;
00259 if (climates==NULL && not_found==0)
00260 {
00261 climates = gl_find_objects(FL_NEW,FT_CLASS,SAME,"climate",FT_END);
00262 if (climates==NULL)
00263 {
00264 not_found = 1;
00265 gl_warning("house: no climate data found, using static data");
00266
00267
00268 static double tout=74.0, rhout=0.75, solar[8] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
00269 pTout = &tout;
00270 pRhout = &rhout;
00271 pSolar = &solar[0];
00272 }
00273 else if (climates->hit_count>1)
00274 {
00275 gl_warning("house: %d climates found, using first one defined", climates->hit_count);
00276 }
00277 }
00278 if (climates!=NULL)
00279 {
00280 if (climates->hit_count==0)
00281 {
00282
00283 static double tout=74.0, rhout=0.75, solar[8] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
00284 pTout = &tout;
00285 pRhout = &rhout;
00286 pSolar = &solar[0];
00287 }
00288 else
00289 {
00290
00291 OBJECT *obj = gl_find_next(climates,NULL);
00292 if (obj->rank<=hdr->rank)
00293 gl_set_dependent(obj,hdr);
00294 pTout = (double*)GETADDR(obj,gl_get_property(obj,"temperature"));
00295 pRhout = (double*)GETADDR(obj,gl_get_property(obj,"humidity"));
00296 pSolar = (double*)GETADDR(obj,gl_get_property(obj,"solar_flux"));
00297 }
00298 }
00299 return 1;
00300 }
00301
00306 int house::init(OBJECT *parent)
00307 {
00308 OBJECT *hdr = OBJECTHDR(this);
00309 hdr->flags |= OF_SKIPSAFE;
00310
00311
00312 struct {
00313 complex **var;
00314 char *varname;
00315 } map[] = {
00316
00317 {&pCircuit_V, "voltage_12"},
00318 {&pLine_I, "current_1"},
00319 {&pLine12, "current_12"},
00321 };
00322
00323 extern complex default_line_voltage[3], default_line_current[3];
00324 static complex default_line_current_12;
00325 int i;
00326
00327
00328 OBJECT *obj = OBJECTHDR(this);
00329 if (parent!=NULL && gl_object_isa(parent,"triplex_meter"))
00330 {
00331
00332 for (i=0; i<sizeof(map)/sizeof(map[0]); i++)
00333 {
00334 if ((*(map[i].var) = get_complex(parent,map[i].varname))==NULL)
00335 GL_THROW("%s (%s:%d) does not implement triplex_meter variable %s for %s (house:%d)",
00336
00337
00338
00339
00340
00341
00342 parent->name?parent->name:"unnamed object", parent->oclass->name, parent->id, map[i].varname, obj->name?obj->name:"unnamed", obj->id);
00343 }
00344 }
00345 else
00346 {
00347 gl_error("house:%d %s; using static voltages", obj->id, parent==NULL?"has no parent triplex_meter defined":"parent is not a triplex_meter");
00348
00349
00350
00351
00352
00353
00354
00355 *(map[0].var) = &default_line_voltage[0];
00356 *(map[1].var) = &default_line_current[0];
00357 *(map[2].var) = &default_line_current_12;
00358 }
00359
00360 while (floor_area <= 500)
00361 floor_area = gl_random_normal(RNGSTATE,2500,300);
00362
00363 if (ceiling_height <= ROUNDOFF)
00364 ceiling_height = 8.0;
00365
00366 if (envelope_UA <= ROUNDOFF)
00367 envelope_UA = gl_random_uniform(RNGSTATE,0.15,0.2)*floor_area;
00368
00369 if (aspect_ratio <= ROUNDOFF)
00370 aspect_ratio = 1.0;
00371
00372 if (gross_wall_area <= ROUNDOFF)
00373 gross_wall_area = 4.0 * 2.0 * (aspect_ratio + 1.0) * ceiling_height * sqrt(floor_area/aspect_ratio);
00374
00375 if (airchange_per_hour <= ROUNDOFF)
00376 airchange_per_hour = gl_random_uniform(RNGSTATE,4,6);
00377
00378 if (thermostat_deadband <= ROUNDOFF)
00379 thermostat_deadband = 2;
00380
00381 if (heating_setpoint <= ROUNDOFF)
00382 heating_setpoint = gl_random_uniform(RNGSTATE,68,72);
00383
00384 if (cooling_setpoint <= ROUNDOFF)
00385 cooling_setpoint = gl_random_uniform(RNGSTATE,76,80);
00386
00387 if (window_wall_ratio <= ROUNDOFF)
00388 window_wall_ratio = 0.15;
00389
00390 if (glazing_shgc <= ROUNDOFF)
00391 glazing_shgc = 0.65;
00392
00393 if (design_cooling_capacity <= ROUNDOFF)
00394 design_cooling_capacity = gl_random_uniform(RNGSTATE,18,24);
00395
00396 if (design_heating_capacity <= ROUNDOFF)
00397 design_heating_capacity = gl_random_uniform(RNGSTATE,18,24);
00398
00399
00400
00401 if (COP_coeff <= ROUNDOFF)
00402 COP_coeff = gl_random_uniform(RNGSTATE,0.9,1.1);
00403
00404 if (Tair <= ROUNDOFF)
00405 Tair = gl_random_uniform(RNGSTATE,heating_setpoint+thermostat_deadband, cooling_setpoint-thermostat_deadband);
00406
00407 if (over_sizing_factor <= ROUNDOFF)
00408 over_sizing_factor = gl_random_uniform(RNGSTATE,0.98,1.3);
00409
00410 heat_cool_mode = house::OFF;
00411
00412 if (house_content_heat_transfer_coeff <= ROUNDOFF)
00413 house_content_heat_transfer_coeff = gl_random_uniform(RNGSTATE,0.5,1.0)*floor_area;
00414
00415
00416 volume = 8*floor_area;
00417 air_mass = air_density*volume;
00418 air_thermal_mass = air_heat_capacity*air_mass;
00419 Tmaterials = Tair;
00420 hvac_rated_power = 24*floor_area*over_sizing_factor;
00421
00422 if (set_Eigen_values() == FALSE)
00423 return 0;
00424
00425 if (hdr->latitude < 24 || hdr->latitude > 48)
00426 {
00427
00428 hdr->latitude = hdr->latitude<24 ? 24 : 48;
00429 gl_error("Latitude beyond the currently supported range 24 - 48 N, Simulations will continue assuming latitude %.0fN",hdr->latitude);
00430
00431
00432
00433
00434 }
00435
00436
00437
00438 hvac_circuit = attach_enduse_house_a(hdr, &load, 50, TRUE);
00439
00440 return 1;
00441 }
00442
00447 CIRCUIT *house::attach(enduse *pLoad,
00448 double breaker_amps,
00449 int is220
00450 )
00451 {
00452 if (pLoad==NULL){
00453 GL_THROW("end-use load couldn't be connected because it was not provided");
00454
00455
00456
00457
00458
00459 }
00460
00461
00462 CIRCUIT *c = new CIRCUIT;
00463 if (c==NULL)
00464 {
00465 GL_THROW("memory allocation failure");
00466
00467 gl_error("memory allocation failure");
00468 return 0;
00469
00470
00471 }
00472 c->next = panel.circuits;
00473 c->id = panel.circuits ? panel.circuits->id+1 : 1;
00474
00475
00476 c->max_amps = breaker_amps;
00477
00478
00479 c->pLoad = pLoad;
00480
00481 if (is220 == 1)
00482 {
00483 c->type = X12;
00484 c->id++;
00485 }
00486 else if (c->id&0x01)
00487 c->type = X13;
00488 else
00489 c->type = X23;
00490
00491
00492 panel.circuits = c;
00493
00494
00495 c->pV = &(pCircuit_V[(int)c->type]);
00496
00497
00498 c->status = BRK_CLOSED;
00499
00500
00501
00502 c->tripsleft = 100;
00503
00504 return c;
00505 }
00506
00510 TIMESTAMP house::sync_thermostat(TIMESTAMP t0, TIMESTAMP t1)
00511 {
00512 const double TcoolOn = cooling_setpoint+thermostat_deadband;
00513 const double TcoolOff = cooling_setpoint-thermostat_deadband;
00514 const double TheatOn = heating_setpoint-thermostat_deadband;
00515 const double TheatOff = heating_setpoint+thermostat_deadband;
00516
00517
00518 if (TcoolOff<TheatOff)
00519 {
00520 gl_error("house: thermostat setpoints deadbands overlap (TcoolOff=%.1f < TheatOff=%.1f)", TcoolOff,TheatOff);
00521
00522
00523
00524
00525
00526
00527 return TS_INVALID;
00528 }
00529
00530
00531 if (Tair<=TheatOn+0.01)
00532 heat_cool_mode = HEAT;
00533 else if (Tair>=TheatOff-0.01 && Tair<=TcoolOff+0.01)
00534 heat_cool_mode = OFF;
00535 else if (Tair>=TcoolOn-0.01)
00536 heat_cool_mode = COOL;
00537
00538 return TS_NEVER;
00539 }
00540
00541 TIMESTAMP house::sync_panel(TIMESTAMP t0, TIMESTAMP t1)
00542 {
00543 TIMESTAMP sync_time = TS_NEVER;
00544 OBJECT *obj = OBJECTHDR(this);
00545
00546
00547 complex I[3]; I[X12] = I[X23] = I[X13] = complex(0,0);
00548
00549
00550 double heatgain = 0;
00551
00552
00553 CIRCUIT *c;
00554 for (c=panel.circuits; c!=NULL; c=c->next)
00555 {
00556
00557 int n = (int)c->type;
00558 if (n<0 || n>2)
00559 GL_THROW("%s:%d circuit %d has an invalid circuit type (%d)", obj->oclass->name, obj->id, c->id, (int)c->type);
00560
00561
00562
00563
00564
00565
00566
00567 if (c->status==BRK_OPEN && t1>=c->reclose)
00568 {
00569 c->status = BRK_CLOSED;
00570 c->reclose = TS_NEVER;
00571 sync_time = t1;
00572 gl_debug("house:%d panel breaker %d closed", obj->id, c->id);
00573 }
00574
00575
00576 if (c->status==BRK_CLOSED)
00577 {
00578
00579 if ((c->pV)->Mag() == 0)
00580 {
00581 gl_debug("house:%d circuit %d (enduse %s) voltage is zero", obj->id, c->id, c->pLoad->name);
00582 break;
00583 }
00584
00585 complex current = ~(c->pLoad->total*1000 / *(c->pV));
00586
00587
00588 if (c->max_amps>0 && current.Mag()>c->max_amps)
00589 {
00590
00591 if (c->tripsleft>0 && gl_random_bernoulli(RNGSTATE,1/(c->tripsleft--))==0)
00592 {
00593
00594 c->status = BRK_OPEN;
00595
00596
00597 c->reclose = t1 + (TIMESTAMP)(gl_random_exponential(RNGSTATE,1/300.0)*TS_SECOND);
00598 gl_debug("house:%d circuit breaker %d tripped - enduse %s overload at %.0f A", obj->id, c->id,
00599 c->pLoad->name, current.Mag());
00600 }
00601
00602
00603 else
00604 {
00605 c->status = BRK_FAULT;
00606 c->reclose = TS_NEVER;
00607 gl_debug("house:%d circuit breaker %d failed", obj->id, c->id);
00608 }
00609
00610
00611 sync_time = t1;
00612 }
00613
00614
00615 else
00616 {
00617 tload.power += c->pLoad->power;
00618 tload.current += c->pLoad->current;
00619 tload.admittance += c->pLoad->admittance;
00620 tload.total += c->pLoad->total;
00621 tload.heatgain += c->pLoad->heatgain;
00622 tload.energy += c->pLoad->power * gl_tohours(t1-t0);
00623 I[n] += current;
00624 c->reclose = TS_NEVER;
00625 }
00626 }
00627
00628
00629 if (sync_time > c->reclose)
00630 sync_time = c->reclose;
00631 }
00632
00633
00634 if (obj->parent != NULL)
00635 LOCK_OBJECT(obj->parent);
00636
00637 pLine_I[0] = I[X13];
00638 pLine_I[1] = I[X23];
00639 pLine_I[2] = 0;
00640 *pLine12 = I[X12];
00641
00642 if (obj->parent != NULL)
00643 UNLOCK_OBJECT(obj->parent);
00644
00645 return sync_time;
00646 }
00647
00648
00652 TIMESTAMP house::presync(TIMESTAMP t0, TIMESTAMP t1)
00653 {
00654 if (t0>0 && t1>t0)
00655 load.energy += load.total.Mag() * gl_tohours(t1-t0);
00656
00657
00658
00659 load.heatgain = 0;
00660 load.total = complex(0,0,J);
00661 load.admittance = complex(0,0,J);
00662 load.current = complex(0,0,J);
00663
00664
00665 tload.heatgain = 0;
00666 tload.total = complex(0,0,J);
00667 tload.admittance = complex(0,0,J);
00668 tload.current = complex(0,0,J);
00669
00670 return TS_NEVER;
00671 }
00672
00673
00674 TIMESTAMP house::sync_thermal(TIMESTAMP t1, double nHours){
00675 DATETIME tv;
00676 double t = 0.0;
00677 gl_localtime(t1, &tv);
00678
00679 Tout = *pTout;
00680
00681 Tsolar = get_Tsolar(tv.hour, tv.month, Tair, *pTout);
00682 solar_load = 0.0;
00683
00684 for (int i = 1; i<9; i++)
00685 {
00686 solar_load += (gross_wall_area*window_wall_ratio/8.0) * glazing_shgc * pSolar[i];
00687 }
00688 double netHeatrate = tload.heatgain*BTUPHPW + solar_load;
00689 double Q1 = M_inv11*Tair + M_inv12*Tmaterials;
00690 double Q2 = M_inv21*Tair + M_inv22*Tmaterials;
00691
00692 if (nHours > ROUNDOFF)
00693 {
00694 double q1 = exp(s1*nHours)*(Q1 + BB11*Tsolar/s1 + BB12*netHeatrate/s1) - BB11*Tsolar/s1
00695 - BB12*netHeatrate/s1;
00696 double q2 = exp(s2*nHours)*(Q2 - BB11*Tsolar/s2 - BB12*netHeatrate/s2) + BB11*Tsolar/s2
00697 + BB12*netHeatrate/s2;
00698
00699 Tair = q1*(s1-A22)/A21 + q2*(s2-A22)/A21;
00700 Tmaterials = q1 + q2;
00701 }
00702 else
00703 return TS_NEVER;
00704
00705
00706 const double W = (Q1 + (BB11*Tsolar)/s1 + BB12*netHeatrate/s1)*(s1-A22)/A21;
00707 const double X = (BB11*Tsolar/s1 + BB12*netHeatrate/s1)*(s1-A22)/A21;
00708 const double Y = (Q2 - (BB11*Tsolar)/s2 - BB12*netHeatrate/s2)*(s2-A22)/A21;
00709 const double Z = (BB11*Tsolar/s2 + BB12*netHeatrate/s2)*(s2-A22)/A21;
00710
00711
00712
00713 int n_solutions = 0;
00714 double Tevent;
00715 const double TcoolOn = cooling_setpoint+thermostat_deadband;
00716 const double TcoolOff = cooling_setpoint-thermostat_deadband;
00717 const double TheatOn = heating_setpoint-thermostat_deadband;
00718 const double TheatOff = heating_setpoint+thermostat_deadband;
00719
00720
00721 #define TPREC 0.01
00722 if (hvac_rated_capacity < 0.0)
00723 Tevent = TcoolOff;
00724 else if (hvac_rated_capacity > 0.0)
00725 Tevent = TheatOff;
00726 else if (Tair <= TheatOn+TPREC)
00727 Tevent = TheatOn;
00728 else if (Tair >= TcoolOn-TPREC)
00729 Tevent = TcoolOn;
00730 else
00731 return TS_NEVER;
00732
00733 #ifdef OLD_SOLVER
00734 if (nHours > TPREC)
00735
00736 n_solutions = dual_decay_solve(&t,TPREC,0.0 ,nHours,W,s1,Y,s2,Z-X-Tevent);
00737
00738 Tair = Tevent;
00739
00740 if (n_solutions<0)
00741 gl_error("house: solver error");
00742 else if (n_solutions == 0)
00743 return TS_NEVER;
00744 else if (t == 0)
00745 t = 1.0/3600.0;
00746 return t1+(TIMESTAMP)(t*3600*TS_SECOND);
00747 #else
00748 t = e2solve(W,s1,Y,s2,Z-X-Tevent);
00749 Tair = Tevent;
00750
00751 if (isfinite(t))
00752 {
00753 return t1+(TIMESTAMP)(t*3600*TS_SECOND);
00754 }
00755 else
00756 return TS_NEVER;
00757 #endif
00758 }
00759
00764 TIMESTAMP house::sync(TIMESTAMP t0, TIMESTAMP t1)
00765 {
00766 OBJECT *obj = OBJECTHDR(this);
00767 double nHours = (gl_tohours(t1)- gl_tohours(t0));
00768
00769 sync_hvac_load(t1, nHours);
00770
00771
00772 TIMESTAMP panel_time = sync_panel(t0,t1);
00773 TIMESTAMP sync_time = sync_thermal(t1, nHours);
00774
00775 if (panel_time < sync_time)
00776 sync_time = panel_time;
00777
00779 return sync_time;
00780
00781 }
00782
00790 TIMESTAMP house::sync_hvac_load(TIMESTAMP t1, double nHours)
00791 {
00792
00793 outside_temp = *pTout;
00794 const double heating_cop_adj = (-0.0063*(*pTout)+1.5984);
00795 const double cooling_cop_adj = -(-0.0108*(*pTout)+2.0389);
00796 const double heating_capacity_adj = (-0.0063*(*pTout)+1.5984);
00797 const double cooling_capacity_adj = -(-0.0063*(*pTout)+1.5984);
00798
00799 double t = 0.0;
00800
00801 if (heat_cool_mode == HEAT)
00802 {
00803 hvac_rated_capacity = design_heating_capacity*floor_area*heating_capacity_adj;
00804 hvac_rated_power = hvac_rated_capacity/(heating_COP * heating_cop_adj);
00805 }
00806 else if (heat_cool_mode == COOL)
00807 {
00808 hvac_rated_capacity = design_cooling_capacity*floor_area*cooling_capacity_adj;
00809 hvac_rated_power = hvac_rated_capacity/(cooling_COP * cooling_cop_adj);
00810 }
00811 else
00812 {
00813 hvac_rated_capacity = 0.0;
00814 hvac_rated_power = 0.0;
00815 }
00816
00817 gl_enduse_sync(&(residential_enduse::load),t1);
00818 load.power = hvac_rated_power*KWPBTUPH * ((heat_cool_mode == HEAT) && (heat_mode == GASHEAT) ? 0.01 : 1.0);
00819
00820 load.heatgain = hvac_rated_capacity;
00821
00822
00823
00824 return TS_NEVER;
00825 }
00826
00827 int house::set_Eigen_values()
00828 {
00829
00830
00831
00832 if (envelope_UA <= ROUNDOFF || house_content_heat_transfer_coeff <= ROUNDOFF ||
00833 air_thermal_mass <= ROUNDOFF || house_content_thermal_mass <= ROUNDOFF)
00834 {
00835 gl_error("House thermal mass or UA invalid. Eigen values not set.");
00836
00837
00838
00839
00840 return FALSE;
00841 }
00842
00843 double ra = 1/envelope_UA;
00844 double rm = 1/house_content_heat_transfer_coeff;
00845
00846 A11 = -1.0/(air_thermal_mass*rm) - 1.0/(ra*air_thermal_mass);
00847 A12 = 1.0/(rm*air_thermal_mass);
00848 A21 = 1.0/(rm*house_content_thermal_mass);
00849 A22 = -1.0/(rm*house_content_thermal_mass);
00850
00851 B11 = 1.0/(air_thermal_mass*ra);
00852 B12 = 1.0/air_thermal_mass;
00853 B21 = 0.0;
00854 B22 = 0.0;
00855
00856
00857 s1 = (A11 + A22 + sqrt((A11 + A22)*(A11 + A22) - 4*(A11*A22 - A21*A12)))/2.0;
00858 s2 = (A11 + A22 - sqrt((A11 + A22)*(A11 + A22) - 4*(A11*A22 - A21*A12)))/2.0;
00859
00860
00861 double M11 = (s1 - A22)/A21;
00862 double M12 = (s2 - A22)/A21;
00863 double M21 = 1.0;
00864 double M22 = 1.0;
00865
00866 double demoninator = (s1 - A22)/A21 - (s2-A22)/A21;
00867 M_inv11 = 1.0/demoninator;
00868 M_inv12 = -((s2 - A22)/A21)/demoninator;
00869 M_inv21 = -1.0/demoninator;
00870 M_inv22 = ((s1-A22)/A21)/demoninator;
00871
00872 BB11 = M_inv11*B11 + M_inv12*B21;
00873 BB21 = M_inv21*B11 + M_inv22*B21;
00874 BB12 = M_inv11*B12 + M_inv12*B22;
00875 BB22 = M_inv21*B12 + M_inv22*B22;
00876
00877 return TRUE;
00878 }
00884 double house::get_Tsolar(int hour, int month, double Tair, double Tout)
00885 {
00886
00887 static double CLTD[] = {4.25, 2.75, 1.63, 0.50, -0.50, 3.50, 11.25, 17.88, 22.50, 25.88, 27.88, 29.25, 31.63, 35.13, 38.50, 40.38, 36.88, 28.00, 19.00, 14.00, 11.13, 8.63, 6.25};
00888
00889 static double LM[4][24] = {
00890 {-1.33, -1.44, -0.89, -1.00, -0.67, -0.44, -0.67, -1.00, -0.89, -1.44, -1.33, -1.22},
00891 {-2.89, -1.89, -0.78, -0.44, -0.11, -0.11, -0.11, -0.44, -0.78, -1.89, -2.89, -4.67},
00892 {-5.44, -3.22, -1.11, -0.11, 0.22, 0.67, 0.22, -0.11, -1.11, -3.22, -5.44, -6.33},
00893 {-7.56, -5.11, -1.78, -0.11, 1.33, 2.00, 1.33, -0.11, -1.78, -5.11, -7.56}
00894 };
00895
00896 static double ColorSurface = 0.75;
00897 static double DR = 15.0;
00898 double solarTemp = Tair;
00899 double LMnow = 0.0;
00900 int LMcol = month-1;
00901
00902 OBJECT *hdr = OBJECTHDR(this);
00903
00904 if (hdr->latitude <= 24.0)
00905 LMnow = LM[0][LMcol];
00906 else if (hdr->latitude <= 32.)
00907 LMnow = LM[0][LMcol] + ((LM[1][LMcol]-LM[0][LMcol])*(hdr->latitude-24.0)/12.0);
00908 else if (hdr->latitude <= 40.)
00909 LMnow = LM[1][LMcol] + ((LM[2][LMcol]-LM[1][LMcol])*(hdr->latitude-32.0)/12.0);
00910 else if (hdr->latitude <= 48.)
00911 LMnow = LM[2][LMcol] + ((LM[3][LMcol]-LM[2][LMcol])*(hdr->latitude-40.0)/12.0);
00912 else
00913 LMnow = LM[3][LMcol];
00914
00915 solarTemp += (CLTD[hour] + LMnow)*ColorSurface + (78. - Tair) + ((*pTout) - DR/2. - 85.);
00916
00917 return solarTemp;
00918 }
00919
00920
00921
00922 complex *house::get_complex(OBJECT *obj, char *name)
00923 {
00924 PROPERTY *p = gl_get_property(obj,name);
00925 if (p==NULL || p->ptype!=PT_complex)
00926 return NULL;
00927 return (complex*)GETADDR(obj,p);
00928 }
00929
00931
00933
00934 EXPORT int create_house_a(OBJECT **obj, OBJECT *parent)
00935 {
00936 try
00937 {
00938 *obj = gl_create_object(house::oclass);
00939 if (*obj!=NULL)
00940 {
00941 house *my = OBJECTDATA(*obj,house);;
00942 gl_set_parent(*obj,parent);
00943 my->create();
00944 return 1;
00945 }
00946 else
00947 return 0;
00948 }
00949 CREATE_CATCHALL(house_a);
00950 }
00951
00952 EXPORT int init_house_a(OBJECT *obj)
00953 {
00954 try
00955 {
00956 house *my = OBJECTDATA(obj,house);
00957 my->init_climate();
00958 return my->init(obj->parent);
00959 }
00960 INIT_CATCHALL(house_a);
00961 }
00962
00963 EXPORT TIMESTAMP sync_house_a(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
00964 {
00965 try {
00966 house *my = OBJECTDATA(obj,house);
00967 TIMESTAMP t1 = TS_NEVER;
00968 if (obj->clock <= ROUNDOFF)
00969 obj->clock = t0;
00970 switch (pass)
00971 {
00972 case PC_PRETOPDOWN:
00973 t1 = my->presync(obj->clock, t0);
00974 break;
00975
00976 case PC_BOTTOMUP:
00977 t1 = my->sync(obj->clock, t0);
00978 obj->clock = t0;
00979 break;
00980
00981 default:
00982 gl_error("house::sync- invalid pass configuration");
00983 t1 = TS_INVALID;
00984 }
00985 return t1;
00986 }
00987 SYNC_CATCHALL(house_a);
00988 }
00989
00990 EXPORT TIMESTAMP plc_house_a(OBJECT *obj, TIMESTAMP t0)
00991 {
00992
00993 if (obj->clock <= ROUNDOFF)
00994 obj->clock = t0;
00995
00996 house *my = OBJECTDATA(obj,house);
00997 return my->sync_thermostat(obj->clock, t0);
00998 }
00999