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