00001
00030 #include <stdlib.h>
00031 #include <stdarg.h>
00032 #include <ctype.h>
00033
00034 #include "platform.h"
00035 #include "output.h"
00036 #include "loadshape.h"
00037 #include "exception.h"
00038 #include "convert.h"
00039 #include "globals.h"
00040 #include "random.h"
00041 #include "schedule.h"
00042
00043 static loadshape *loadshape_list = NULL;
00044
00045 static void sync_analog(loadshape *ls, double dt)
00046 {
00047 if (ls->params.analog.energy>0)
00048
00049
00050 ls->load = ls->schedule->value * ls->params.analog.energy * ls->schedule->fraction * ls->dPdV;
00051 else if (ls->params.analog.power>0)
00052
00053
00054 ls->load = ls->schedule->value * ls->params.analog.power * ls->dPdV;
00055 else
00056
00057
00058 ls->load = ls->schedule->value * ls->dPdV;
00059 }
00060
00061 static void sync_pulsed(loadshape *ls, double dt)
00062 {
00063
00064 if (ls->r >= 0)
00065 {
00066
00067 if (ls->r!=0 && ls->q >= ls->d[0] - ls->r/3600)
00068 {
00069
00070 ls->q = 1;
00071 #ifdef _DEBUG
00072 output_debug("loadshape %s: turns on", ls->schedule->name);
00073 #endif
00074 goto TurnOn;
00075 }
00076 TurnOff:
00077
00078 ls->s = 0;
00079
00080
00081 ls->load = 0;
00082
00083
00084 if (ls->schedule->value>0)
00085 {
00086
00087 ls->r = ls->schedule->value * ls->params.pulsed.scalar / (ls->params.pulsed.energy);
00088 if (ls->r<0)
00089 output_warning("loadshape %s: r not positive while load is off!", ls->schedule->name);
00090 }
00091
00092
00093 else if (ls->schedule->duration>0)
00094 {
00095
00096 ls->r = 0;
00097 output_warning("loadshape %s: pulsed shape suspended because schedule has zero value", ls->schedule->name);
00098 }
00099 }
00100
00101
00102 else
00103 {
00104
00105 if (ls->r!=0 && ls->q <= ls->d[1] - ls->r/3600)
00106 {
00107
00108 ls->q = 0;
00109 #ifdef _DEBUG
00110 output_debug("loadshape %s: turns off", ls->schedule->name);
00111 #endif
00112 goto TurnOff;
00113 }
00114 TurnOn:
00115
00116 ls->s = 1;
00117
00118
00119 if (ls->params.pulsed.pulsetype==MPT_POWER)
00120 {
00121
00122 ls->load = ls->params.pulsed.pulsevalue * ls->dPdV;
00123
00124
00125 ls->r = -ls->params.pulsed.scalar * ls->load / (ls->params.pulsed.energy);
00126 if (ls->r>=0)
00127 output_warning("loadshape %s: r not negative while load is on!", ls->schedule->name);
00128 }
00129 else if (ls->params.pulsed.pulsevalue!=0)
00130 {
00131
00132 ls->load = ls->params.pulsed.energy / (ls->params.pulsed.pulsevalue/3600 * ls->params.pulsed.scalar) * ls->dPdV;
00133
00134
00135 ls->r = -3600 /ls->params.pulsed.pulsevalue;
00136 if (ls->r>=0)
00137 output_warning("loadshape %s: r not negative while load is on!", ls->schedule->name);
00138 }
00139 else
00140 {
00141
00142 output_warning("loadshape %s: load value is zero in 'on' state", ls->schedule->name);
00143 }
00144 }
00145 }
00146
00147 static void sync_modulated(loadshape *ls, double dt)
00148 {
00149
00150 if (ls->r >= 0)
00151 {
00152 if (ls->r!=0 && ls->q >= ls->d[0] - ls->r/3600)
00153 {
00154 ls->q = 1;
00155 #ifdef _DEBUG
00156 output_debug("loadshape %s: turns on", ls->schedule->name);
00157 #endif
00158 goto TurnOn;
00159 }
00160 TurnOff:
00161 ls->s = 0;
00162 ls->load = 0;
00163
00164
00165 if (ls->schedule->value>0)
00166 {
00167 if (ls->params.modulated.modulation==MMT_AMPLITUDE)
00168 {
00169
00170 double period = ls->schedule->duration / ls->params.modulated.scalar;
00171 double duty_cycle = (ls->params.modulated.pulsetype==MPT_TIME)
00172 ? ls->params.modulated.pulsevalue / period
00173 : ls->params.modulated.energy * 3600 / ls->params.modulated.pulsevalue / period;
00174 ls->r = 3600 / (period - duty_cycle * period);
00175 }
00176
00177
00178 else if (ls->params.modulated.modulation==MMT_PULSEWIDTH)
00179 {
00180
00181 double power = (ls->params.modulated.pulsetype==MPT_TIME)
00182 ? ls->params.modulated.energy * 3600 / ls->params.modulated.pulsevalue
00183 : ls->params.modulated.pulsevalue;
00184 double period = ls->schedule->duration / ls->params.modulated.scalar;
00185 double ton = ls->schedule->value * ls->params.modulated.scalar / ls->params.modulated.energy / ls->params.modulated.scalar;
00186 ls->r = 3600 / (period - ton);
00187 }
00188
00189
00190 else if (ls->params.modulated.modulation==MMT_FREQUENCY)
00191 {
00192 double ton = ls->params.modulated.pulsevalue;
00193 double power = ls->params.modulated.pulsevalue;
00194 double dutycycle, period, toff;
00195 if (ls->params.modulated.pulsetype==MPT_TIME)
00196 power = ls->params.modulated.pulseenergy * ls->params.modulated.scalar / ton * 3600;
00197 else
00198 ton = ls->params.modulated.pulseenergy * ls->params.modulated.scalar / power * 3600;
00199 dutycycle = ls->schedule->value / ls->params.modulated.energy / ls->params.modulated.scalar;
00200 if (dutycycle<1)
00201 {
00202 period = ton / dutycycle;
00203 toff = period - ton;
00204 ls->r = 3600/toff;
00205 }
00206 else
00207 ls->r = 0;
00208 }
00209 else
00210 output_warning("loadshape %s: modulation type is not determined!", ls->schedule->name);
00211 }
00212 else
00213 {
00214 ls->r = 0;
00215 output_warning("loadshape %s: modulated shape suspended because schedule has zero value", ls->schedule->name);
00216 }
00217 }
00218
00219
00220 else
00221 {
00222
00223 if (ls->r!=0 && ls->q <= ls->d[1] - ls->r/3600)
00224 {
00225 ls->q = 0;
00226 #ifdef _DEBUG
00227 output_debug("loadshape %s: turns off", ls->schedule->name);
00228 #endif
00229 goto TurnOff;
00230 }
00231 TurnOn:
00232 ls->s = 1;
00233
00234
00235 if (ls->params.modulated.modulation==MMT_AMPLITUDE)
00236 {
00237
00238 double period = ls->schedule->duration / ls->params.modulated.scalar;
00239 double duty_cycle = (ls->params.modulated.pulsetype==MPT_TIME)
00240 ? ls->params.modulated.pulsevalue / period
00241 : ls->params.modulated.energy * 3600 / ls->params.modulated.pulsevalue / period;
00242 ls->r = -3600 / (duty_cycle * period);
00243 ls->load = ls->schedule->value * ls->params.modulated.scalar;
00244 }
00245
00246
00247 else if (ls->params.modulated.modulation==MMT_PULSEWIDTH)
00248 {
00249
00250 double power = (ls->params.modulated.pulsetype==MPT_TIME)
00251 ? ls->params.modulated.energy * 3600 / ls->params.modulated.pulsevalue
00252 : ls->params.modulated.pulsevalue;
00253 double pulsecount = ls->params.modulated.energy / power * ls->schedule->duration / 3600;
00254 double period = ls->schedule->duration / pulsecount;
00255 double ton = ls->schedule->value * ls->params.modulated.scalar / ls->params.modulated.energy / pulsecount;
00256 ls->r = -3600 / ton;
00257 ls->load = power;
00258 }
00259
00260
00261 else if (ls->params.modulated.modulation==MMT_FREQUENCY)
00262 {
00263 double ton = ls->params.modulated.pulsevalue;
00264 double power = ls->params.modulated.pulsevalue;
00265 if (ls->params.modulated.pulsetype==MPT_TIME)
00266 power = ls->params.modulated.pulseenergy * ls->params.modulated.scalar / ton * 3600;
00267 else
00268 ton = ls->params.modulated.pulseenergy * ls->params.modulated.scalar / power * 3600;
00269 if (ton>0)
00270 ls->r = -3600/ton;
00271 else
00272 ls->r = 0;
00273 ls->load = power;
00274 }
00275 else
00276 output_warning("loadshape %s: modulation type is not determined!", ls->schedule->name);
00277 }
00278 }
00279
00280 static void sync_queued(loadshape *ls, double dt)
00281 {
00282 double queue_value = (ls->d[1] - ls->d[0]);
00283 if (ls->params.queued.pulsetype==MPT_POWER)
00284 ls->load = ls->s * ls->params.queued.pulsevalue * ls->dPdV;
00285 else
00286 ls->load = ls->s * ls->params.queued.energy / ls->params.queued.pulsevalue / ls->params.queued.scalar * ls->dPdV;
00287
00288 #define duration ((ls->params.queued.energy*queue_value)/ ls->load)
00289
00290
00291 if (ls->q > ls->d[0])
00292 {
00293 ls->s = 1;
00294
00295 ls->r = -1/duration;
00296
00297 }
00298 else if (ls->q < ls->d[1])
00299 {
00300 ls->s = 0;
00301 ls->r = 1/random_exponential(ls->schedule->value*ls->params.pulsed.scalar*queue_value);
00302 }
00303
00304 #undef duration
00305
00306 }
00307
00308 static void sync_scheduled(loadshape *ls, TIMESTAMP t1)
00309 {
00310 double dt = ls->t0>0 ? (double)(t1 - ls->t0)/3600 : 0.0;
00311 if (t1>=ls->t2)
00312 {
00313
00314 if (ls->t2==TS_ZERO)
00315 {
00316 DATETIME now;
00317 double hour;
00318 int skipday;
00319 if (!local_datetime(t1,&now))
00320 throw_exception("unable to determine schedule loadshape initial state: time is not valid");
00321 hour = now.hour + now.minute/60.0 + now.second/3600.0;
00322 skipday = !(ls->params.scheduled.weekdays & (1<<now.weekday));
00323
00324 if (hour < ls->params.scheduled.on_time)
00325 {
00326 ls->s = MS_OFF;
00327 ls->q = ls->params.scheduled.low;
00328 ls->r = 0;
00329 dt = ls->params.scheduled.on_time - hour;
00330 }
00331 else if (hour < ls->params.scheduled.on_time + (ls->params.scheduled.high-ls->params.scheduled.low)/ls->params.scheduled.on_ramp)
00332 {
00333 ls->s = MS_RAMPUP;
00334 ls->q = ls->params.scheduled.low;
00335 ls->r = skipday ? 0 : ls->params.scheduled.on_ramp;
00336 dt = hour - ls->params.scheduled.on_time + (ls->params.scheduled.high-ls->params.scheduled.low)/ls->params.scheduled.on_ramp;
00337 }
00338 else if (hour < ls->params.scheduled.off_time)
00339 {
00340 ls->s = MS_ON;
00341 ls->q = skipday ? ls->params.scheduled.low : ls->params.scheduled.high;
00342 ls->r = 0;
00343 dt = hour - ls->params.scheduled.off_time;
00344 }
00345 else if (hour < ls->params.scheduled.off_time - ls->params.scheduled.on_time - (ls->params.scheduled.high-ls->params.scheduled.low)/ls->params.scheduled.on_ramp)
00346 {
00347 ls->s = MS_RAMPDOWN;
00348 ls->q = skipday ? ls->params.scheduled.low : ls->params.scheduled.high;
00349 ls->r = skipday ? 0 : ls->params.scheduled.off_ramp;
00350 dt = hour - ls->params.scheduled.off_time - ls->params.scheduled.on_time - (ls->params.scheduled.high-ls->params.scheduled.low)/ls->params.scheduled.on_ramp;
00351 }
00352 else
00353 {
00354 ls->s = MS_OFF;
00355 ls->q = ls->params.scheduled.low;
00356 ls->r = 0;
00357 dt = 24-hour+ls->params.scheduled.on_time;;
00358 }
00359 }
00360
00361
00362 else
00363 {
00364 int weekday = ((int)(t1/86400)+4)%7;
00365 int skipday = !(ls->params.scheduled.weekdays & (1<<weekday));
00366 switch (ls->s) {
00367 case MS_OFF:
00368 ls->r = ls->params.scheduled.on_ramp;
00369 ls->q = ls->params.scheduled.low;
00370 ls->s = MS_RAMPUP;
00371 dt = (ls->params.scheduled.high-ls->params.scheduled.low)/ls->params.scheduled.on_ramp;
00372 break;
00373 case MS_RAMPUP:
00374 ls->r = 0;
00375 ls->q = ls->params.scheduled.low;
00376 ls->s = MS_ON;
00377 dt = (ls->params.scheduled.off_time - ls->params.scheduled.on_time - (ls->params.scheduled.high-ls->params.scheduled.low)/ls->params.scheduled.on_ramp);
00378 break;
00379 case MS_ON:
00380 ls->r = ls->params.scheduled.off_ramp;
00381 ls->q = skipday ? ls->params.scheduled.low : ls->params.scheduled.high;
00382 ls->s = MS_RAMPDOWN;
00383 dt = (ls->params.scheduled.low-ls->params.scheduled.high)/ls->params.scheduled.off_ramp;
00384 break;
00385 case MS_RAMPDOWN:
00386 ls->r = 0;
00387 ls->q = skipday ? ls->params.scheduled.low : ls->params.scheduled.high;
00388 ls->s = MS_OFF;
00389 dt = (24-ls->params.scheduled.off_time + ls->params.scheduled.on_time);
00390 break;
00391 default:
00392 dt = 0;
00393 break;
00394 }
00395 }
00396 ls->t2 = t1 + (TIMESTAMP)dt*3600;
00397 }
00398 else
00399 ls->q += ls->r * dt;
00400
00401 ls->load = ls->q;
00402 }
00403
00407 static char *weekdays="UMTWRFSH";
00408 char *schedule_weekday_to_string(unsigned char days)
00409 {
00410 static char result[9];
00411 int i;
00412 int n=0;
00413 for (i=0; i<8; i++)
00414 {
00415 if ((days&(1<<i))!=0)
00416 result[n++] = weekdays[i];
00417 }
00418 result[n++] = '\0';
00419 return result;
00420 }
00424 unsigned char schedule_string_to_weekday(char *days)
00425 {
00426 unsigned char result=0;
00427 int i;
00428 for (i=0; i<8; i++)
00429 {
00430 if (strchr(days,weekdays[i]))
00431 result |= (1<<i);
00432 }
00433 return result;
00434 }
00438 int sample_from_diversity(double *param, char *value)
00439 {
00440 float min, mean, stdev, max;
00441 if (sscanf(value,"%f<%f~%f<%f", &min, &mean, &stdev, &max)==4)
00442 {
00443 }
00444 else if (sscanf(value,"%f<%f~%f", &min, &mean, &stdev)==3)
00445 {
00446 max = mean + 3*stdev;
00447 }
00448 else if (sscanf(value,"%f~%f<%f", &mean, &stdev, &max)==3)
00449 {
00450 min = mean - 3*stdev;
00451 }
00452 else if (sscanf(value,"%f~%f", &mean, &stdev)==2)
00453 {
00454 max = mean + 3*stdev;
00455 min = mean - 3*stdev;
00456 }
00457 else if (sscanf(value,"%f", &mean)==1)
00458 {
00459 min = max = mean ;
00460 stdev = 0;
00461 }
00462 else
00463 return 0;
00464 if (min <= mean && mean <= max && stdev >=0)
00465 {
00466
00467 if (stdev==0)
00468 *param = mean;
00469 else do {
00470 *param = random_normal(mean,stdev);
00471 } while (*param<min || *param>max);
00472 return 1;
00473 }
00474 else
00475 return 0;
00476 }
00477
00481 int loadshape_create(loadshape *data)
00482 {
00483
00484 memset(data,0,sizeof(loadshape));
00485 data->next = loadshape_list;
00486 loadshape_list = data;
00487 return 1;
00488 }
00489
00490 int loadshape_initall(void)
00491 {
00492 loadshape *ls;
00493 for (ls=loadshape_list; ls!=NULL; ls=ls->next)
00494 {
00495 if (loadshape_init(ls)==1)
00496 return FAILED;
00497 }
00498 return SUCCESS;
00499 }
00500
00501 void loadshape_recalc(loadshape *ls)
00502 {
00503 switch (ls->type) {
00504 case MT_ANALOG:
00505 break;
00506 case MT_PULSED:
00507 ls->d[MS_OFF] = 1;
00508 ls->d[MS_ON] = 0;
00509 ls->q = random_uniform(0,1);
00510 sync_pulsed(ls,0);
00511 break;
00512 case MT_MODULATED:
00513 ls->d[MS_OFF] = 1;
00514 ls->d[MS_ON] = 0;
00515 break;
00516 case MT_QUEUED:
00517 ls->d[MS_OFF] = ls->params.queued.q_off;
00518 ls->d[MS_ON] = ls->params.queued.q_on;
00519 if (ls->s == 0 && ls->schedule!=NULL)
00520 {
00521
00522 ls->r = 1/random_exponential(ls->schedule->value * ls->params.pulsed.scalar * (ls->params.queued.q_on - ls->params.queued.q_off));
00523 }
00524 break;
00525 case MT_SCHEDULED:
00526 ls->d[MS_OFF] = ls->params.scheduled.low;
00527 ls->d[MS_ON] = ls->params.scheduled.high;
00528 default:
00529 break;
00530 }
00531
00532 if (ls->schedule!=NULL && ls->schedule->duration==0)
00533 {
00534 ls->load = 0;
00535 ls->t2=TS_NEVER;
00536 return;
00537 }
00538 }
00539
00540 int loadshape_init(loadshape *ls)
00541 {
00542
00543 if(ls->type == MT_UNKNOWN){
00544 ls->t2 = TS_NEVER;
00545 return 0;
00546 }
00547
00548
00549 if (ls->schedule==NULL && ls->type!=MT_SCHEDULED){
00550 output_error("loadshape_init(): a loadshape without a schedule is meaningless");
00551 ls->t2 = TS_NEVER;
00552 return 0;
00553 }
00554
00555
00556 switch (ls->type) {
00557 case MT_ANALOG:
00558 if (ls->params.analog.energy<0)
00559 {
00560 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) analog energy must be a positive number",ls->schedule->name);
00561 return 1;
00562 }
00563 else if (ls->params.analog.power<0)
00564 {
00565 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) analog power must be a positive number",ls->schedule->name);
00566 return 1;
00567 }
00568 break;
00569 case MT_PULSED:
00570 if (ls->params.pulsed.energy<=0)
00571 {
00572 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) pulsed energy must be a positive number",ls->schedule->name);
00573 return 1;
00574 }
00575 if (ls->params.pulsed.pulsetype==MPT_UNKNOWN)
00576 {
00577 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) pulse type could not be inferred because either duration or power is missing",ls->schedule->name);
00578 return 1;
00579 }
00580 if (ls->params.pulsed.pulsetype==MPT_TIME && ls->params.pulsed.pulsevalue<=0)
00581 {
00582 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) pulse duration must be a positive number",ls->schedule->name);
00583 return 1;
00584 }
00585 if (ls->params.pulsed.pulsetype==MPT_POWER && ls->params.pulsed.pulsevalue<=0)
00586 {
00587 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) pulse power must be a positive number",ls->schedule->name);
00588 return 1;
00589 }
00590 if (ls->params.pulsed.scalar<=0)
00591 {
00592 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) pulse count must be a positive number",ls->schedule->name);
00593 return 1;
00594 }
00595 break;
00596 case MT_MODULATED:
00597 if (ls->params.modulated.energy<=0)
00598 {
00599 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) modulated energy must be a positive number",ls->schedule->name);
00600 return 1;
00601 }
00602 if (ls->params.modulated.pulsetype==MT_UNKNOWN)
00603 {
00604 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) modulated pulse type could not be inferred because either duration or power is missing",ls->schedule->name);
00605 return 1;
00606 }
00607 if (ls->params.modulated.pulsetype==MPT_TIME && ls->params.modulated.pulsevalue<=0)
00608 {
00609 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) modulated pulse period must be a positive number",ls->schedule->name);
00610 return 1;
00611 }
00612 if (ls->params.modulated.pulsetype==MPT_POWER && ls->params.modulated.pulsevalue<=0)
00613 {
00614 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) modulated pulse power must be a positive number",ls->schedule->name);
00615 return 1;
00616 }
00617 if (ls->params.modulated.scalar<=0)
00618 {
00619 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) modulated pulse count must be a positive number",ls->schedule->name);
00620 return 1;
00621 }
00622 if (ls->params.modulated.pulseenergy<=0)
00623 {
00624 if (ls->params.modulated.pulseenergy==0 && ls->params.modulated.pulsevalue==0)
00625 {
00626 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) either modulated pulse or count must be a positive number",ls->schedule->name);
00627 return 1;
00628 }
00629 else if (ls->params.modulated.pulseenergy<0)
00630 {
00631 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) modulated pulse must be a positive number",ls->schedule->name);
00632 return 1;
00633 }
00634 else
00635 ls->params.modulated.pulseenergy = ls->params.modulated.energy/ls->params.modulated.pulsevalue;
00636 }
00637 if (ls->params.modulated.modulation<=MMT_UNKNOWN || ls->params.modulated.modulation>MMT_FREQUENCY)
00638 {
00639 char *modulation[] = {"unknown","amplitude","pulsewidth","frequency"};
00640 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) modulation type %s is invalid",ls->schedule->name,modulation[ls->params.modulated.modulation]);
00641 return 1;
00642 }
00643 break;
00644 case MT_QUEUED:
00645 if (ls->params.queued.energy<=0)
00646 {
00647 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) queue energy must be a positive number",ls->schedule->name);
00648 return 1;
00649 }
00650 if (ls->params.queued.pulsetype==MT_UNKNOWN)
00651 {
00652 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) queue pulse type could not be inferred because either duration or power is missing",ls->schedule->name);
00653 return 1;
00654 }
00655 if (ls->params.queued.pulsetype==MPT_TIME && ls->params.queued.pulsevalue<=0)
00656 {
00657 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) queue pulse duration must be a positive number",ls->schedule->name);
00658 return 1;
00659 }
00660 if (ls->params.queued.pulsetype==MPT_POWER && ls->params.queued.pulsevalue<=0)
00661 {
00662 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) queue pulse power must be a positive number",ls->schedule->name);
00663 return 1;
00664 }
00665 if (ls->params.queued.scalar<=0)
00666 {
00667 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) queue pulse count must be a positive number",ls->schedule->name);
00668 return 1;
00669 }
00670 if (ls->params.queued.q_on<=ls->params.queued.q_off)
00671 {
00672 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) queue q_on threshold must be greater than q_off threshold (q_off=%f, q_on=%f)",ls->schedule->name,ls->params.queued.q_off,ls->params.queued.q_on);
00673 return 1;
00674 }
00675 break;
00676 case MT_SCHEDULED:
00677
00678 if (ls->params.scheduled.on_time<0 || ls->params.scheduled.on_time>24)
00679 {
00680 output_error("loadshape_init() scheduled on-time must be between 0 and 24");
00681 return 1;
00682 }
00683
00684 if (ls->params.scheduled.off_time<0 || ls->params.scheduled.off_time>24)
00685 {
00686 output_error("loadshape_init() scheduled off-time must be between 0 and 24");
00687 return 1;
00688 }
00689
00690 if (ls->params.scheduled.on_ramp<=0)
00691 {
00692 output_error("loadshape_init() scheduled on-ramp must be positive");
00693 return 1;
00694 }
00695
00696 if (ls->params.scheduled.off_ramp>=0)
00697 {
00698 output_error("loadshape_init() scheduled off-ramp must be negative");
00699 return 1;
00700 }
00701
00702
00703 ls->params.scheduled.on_end = ls->params.scheduled.on_time + (ls->params.scheduled.high-ls->params.scheduled.low)/ls->params.scheduled.on_ramp;
00704 ls->params.scheduled.off_end = ls->params.scheduled.off_time + (ls->params.scheduled.low-ls->params.scheduled.high)/ls->params.scheduled.off_ramp;
00705
00706 if (ls->params.scheduled.off_time<=ls->params.scheduled.on_end && ls->params.scheduled.on_end <=ls->params.scheduled.off_end)
00707 {
00708 output_error("loadshape_init() scheduled on ramp overlaps with off time");
00709 return 1;
00710 }
00711
00712 if (ls->params.scheduled.on_time<=ls->params.scheduled.off_end && ls->params.scheduled.off_end <=ls->params.scheduled.on_end)
00713 {
00714 output_error("loadshape_init() scheduled off ramp overlaps with on time");
00715 return 1;
00716 }
00717
00718
00719 ls->dPdV = 1.0;
00720
00721 return 0;
00722 default:
00723 output_error("loadshape_init(loadshape *ls={schedule->name='%s',...}) load shape type is invalid",ls->schedule->name);
00724 return 1;
00725 break;
00726 }
00727
00728
00729 loadshape_recalc(ls);
00730
00731
00732 if (ls->q==0) ls->q = ls->d[0]<ls->d[1] ? random_uniform(ls->d[0], ls->d[1]) : random_uniform(ls->d[1], ls->d[0]); ;
00733
00734
00735 if (ls->dPdV==0) ls->dPdV = 1.0;
00736
00737 return 0;
00738 }
00739
00740 TIMESTAMP loadshape_sync(loadshape *ls, TIMESTAMP t1)
00741 {
00742 #ifdef _DEBUG
00743
00744 #endif
00745
00746
00747 if (ls->schedule!=NULL && t1 > ls->t0)
00748 {
00749 double dt = ls->t0>0 ? (double)(t1 - ls->t0)/3600 : 0.0;
00750
00751
00752 if (ls->schedule->duration<=0)
00753 {
00754 ls->t0 = t1;
00755 return TS_NEVER;
00756 }
00757
00758 switch (ls->type) {
00759 case MT_ANALOG:
00760
00761 sync_analog(ls, dt);
00762
00763
00764 ls->t2 = ls->schedule->next_t;
00765 break;
00766
00767 case MT_PULSED:
00768
00769
00770 ls->q += ls->r * dt;
00771
00772 sync_pulsed(ls, dt);
00773
00774 #ifdef _DEBUG
00775 if (ls->s==0 && ls->r<0)
00776 {
00777 output_error("loadshape %s: state inconsistent (s=on, r<0)!", ls->schedule->name);
00778 return ls->t2 = TS_NEVER;
00779 }
00780 else if (ls->s==1 && ls->r>0)
00781 {
00782 output_error("loadshape %s: state inconsistent (s=off, r>0)!", ls->schedule->name);
00783 return ls->t2 = TS_NEVER;
00784 }
00785 #endif
00786
00787
00788 ls->t2 = ls->r!=0 ? t1 + (TIMESTAMP)(( ls->d[ls->s] - ls->q) / ls->r * 3600) : TS_NEVER;
00789 #ifdef _DEBUG
00790 {
00791 char buf[64];
00792 output_debug("schedule %s: value = %5.3f, q = %5.3f, r = %+5.3f, t2 = '%s'", ls->schedule->name, ls->schedule->value, ls->q, ls->r, convert_from_timestamp(ls->t2,buf,sizeof(buf))?buf:"(error)");
00793 }
00794 #endif
00795
00796 if (ls->schedule->next_t < ls->t2) ls->t2 = ls->schedule->next_t;
00797 break;
00798
00799 case MT_MODULATED:
00800
00801
00802 ls->q += ls->r * dt;
00803
00804 sync_modulated(ls, dt);
00805
00806
00807 ls->t2 = ls->r!=0 ? t1 + (TIMESTAMP)(( ls->d[ls->s] - ls->q) / ls->r * 3600) + 1 : TS_NEVER;
00808
00809
00810 if (ls->schedule->next_t < ls->t2) ls->t2 = ls->schedule->next_t;
00811 break;
00812
00813 case MT_QUEUED:
00814
00815
00816
00817 ls->q += ls->r * dt;
00818
00819 sync_queued(ls, dt);
00820
00821
00822 ls->t2 = ls->r!=0 ? t1 + (TIMESTAMP)(( ls->d[ls->s] - ls->q) / ls->r * 3600) + 1 : TS_NEVER;
00823
00824
00825 if (ls->schedule->next_t < ls->t2) ls->t2 = ls->schedule->next_t;
00826 break;
00827
00828
00829 default:
00830 break;
00831 }
00832 }
00833
00834
00835 else {
00836 switch (ls->type) {
00837 case MT_SCHEDULED:
00838 sync_scheduled(ls,t1);
00839 break;
00840 default:
00841 break;
00842 }
00843 }
00844 #ifdef _DEBUG
00845
00846
00847 #endif
00848 ls->t0 = t1;
00849 return ls->t2>0?ls->t2:TS_NEVER;
00850 }
00851
00852 TIMESTAMP loadshape_syncall(TIMESTAMP t1)
00853 {
00854 loadshape *s;
00855 TIMESTAMP t2 = TS_NEVER;
00856 for (s=loadshape_list; s!=NULL; s=s->next)
00857 {
00858 TIMESTAMP t3 = loadshape_sync(s,t1);
00859 if (t3<t2) t2 = t3;
00860 }
00861 return t2;
00862 }
00863
00864 int convert_from_loadshape(char *string,int size,void *data, PROPERTY *prop)
00865 {
00866 char *modulation[] = {"unknown","amplitude","pulsewidth","frequency"};
00867 loadshape *ls = (loadshape*)data;
00868 switch (ls->type) {
00869 case MT_ANALOG:
00870 if (ls->params.analog.energy>0)
00871 return sprintf(string,"type: analog; schedule: %s; energy: %g kWh", ls->schedule->name, ls->params.analog.energy);
00872 else if (ls->params.analog.power>0)
00873 return sprintf(string,"type: analog; schedule: %s; power: %g kW", ls->schedule->name, ls->params.analog.power);
00874 else
00875 return sprintf(string,"type: analog; schedule: %s", ls->schedule->name);
00876 break;
00877 case MT_PULSED:
00878 if (ls->params.pulsed.pulsetype==MPT_TIME)
00879 return sprintf(string,"type: pulsed; schedule: %s; energy: %g kWh; count: %d; duration: %g s",
00880 ls->schedule->name, ls->params.pulsed.energy, ls->params.pulsed.scalar, ls->params.pulsed.pulsevalue);
00881 else if (ls->params.pulsed.pulsetype==MPT_POWER)
00882 return sprintf(string,"type: pulsed; schedule: %s; energy: %g kWh; count: %d; power: %g kW",
00883 ls->schedule->name, ls->params.pulsed.energy, ls->params.pulsed.scalar, ls->params.pulsed.pulsevalue);
00884 else
00885 {
00886 output_error("convert_from_loadshape(...,data={schedule->name='%s',...},prop={name='%s',...}) has an invalid pulsetype", ls->schedule->name, prop->name);
00887 return 0;
00888 }
00889 break;
00890 case MT_MODULATED:
00891 if (ls->params.pulsed.pulsetype==MPT_TIME)
00892 return sprintf(string,"type: modulated; schedule: %s; energy: %g kWh; count: %d; duration: %g s; pulse: %g kWh; modulation: %s",
00893 ls->schedule->name, ls->params.modulated.energy, ls->params.modulated.scalar, ls->params.modulated.pulsevalue, ls->params.modulated.pulseenergy, modulation[ls->params.modulated.modulation]);
00894 else if (ls->params.pulsed.pulsetype==MPT_POWER)
00895 return sprintf(string,"type: modulated; schedule: %s; energy: %g kWh; count: %d; power: %g kW; pulse: %g kWh; modulation: %s",
00896 ls->schedule->name, ls->params.modulated.energy, ls->params.modulated.scalar, ls->params.modulated.pulsevalue, ls->params.modulated.pulseenergy, modulation[ls->params.modulated.modulation]);
00897 else
00898 {
00899 output_error("convert_from_loadshape(...,data={schedule->name='%s',...},prop={name='%s',...}) has an invalid pulsetype", ls->schedule->name, prop->name);
00900 return 0;
00901 }
00902 break;
00903 case MT_QUEUED:
00904 if (ls->params.pulsed.pulsetype==MPT_TIME)
00905 return sprintf(string,"type: queue; schedule: %s; energy: %g kWh; count: %d; duration: %g s; q_on: %g; q_off: %g",
00906 ls->schedule->name, ls->params.queued.energy, ls->params.queued.scalar, ls->params.queued.pulsevalue, ls->params.queued.q_on, ls->params.queued.q_off);
00907 else if (ls->params.pulsed.pulsetype==MPT_POWER)
00908 return sprintf(string,"type: queued; schedule: %s; energy: %g kWh; count: %d; power: %g kW; q_on: %g; q_off: %g",
00909 ls->schedule->name, ls->params.queued.energy, ls->params.queued.scalar, ls->params.queued.pulsevalue, ls->params.queued.q_on, ls->params.queued.q_off);
00910 else
00911 {
00912 output_error("convert_from_loadshape(...,data={schedule->name='%s',...},prop={name='%s',...}) has an invalid pulsetype", ls->schedule->name, prop->name);
00913 return 0;
00914 }
00915 break;
00916 case MT_SCHEDULED:
00917 return sprintf(string,"type: scheduled; weekdays: %s; on-time: %.3g; off-time: %.3g; on-ramp: %.3g; off-ramp: %.3g; low: %.3g; high: %.3g; dt: %.3g m",
00918 schedule_weekday_to_string(ls->params.scheduled.weekdays), ls->params.scheduled.on_time, ls->params.scheduled.off_time,
00919 ls->params.scheduled.on_ramp, ls->params.scheduled.off_ramp, ls->params.scheduled.low, ls->params.scheduled.high, ls->params.scheduled.dt/60);
00920 }
00921 return 1;
00922 }
00923 int convert_to_loadshape(char *string, void *data, PROPERTY *prop)
00924 {
00925 loadshape *ls = (loadshape*)data;
00926 char buffer[1024];
00927 char *token = NULL;
00928
00929
00930 if (strlen(string)>sizeof(buffer)-1)
00931 {
00932 output_error("convert_to_loadshape(string='%-.64s...', ...) input string is too long (max is 1023)",string);
00933 return 0;
00934 }
00935 strcpy(buffer,string);
00936
00937
00938 ls->type = MT_UNKNOWN;
00939
00940
00941 while ((token=strtok(token==NULL?buffer:NULL,";"))!=NULL)
00942 {
00943
00944 char *param = token;
00945 char *value = strchr(token,':');
00946
00947
00948 while (*param!='\0' && (isspace(*param) || iscntrl(*param))) param++;
00949 if (value==NULL)
00950 value="1";
00951 else
00952 *value++ = '\0';
00953 while (isspace(*value) || iscntrl(*value)) value++;
00954
00955
00956 if (strcmp(param,"type")==0)
00957 {
00958 if (strcmp(value,"analog")==0)
00959 {
00960 ls->type = MT_ANALOG;
00961 ls->params.analog.energy = 0.0;
00962 }
00963 else if (strcmp(value,"pulsed")==0)
00964 {
00965 ls->type = MT_PULSED;
00966 ls->params.pulsed.energy = 0.0;
00967 ls->params.pulsed.pulsetype = MPT_UNKNOWN;
00968 ls->params.pulsed.pulsetype = 0.0;
00969 ls->params.pulsed.scalar = 0,0;
00970 }
00971 else if (strcmp(value,"modulated")==0)
00972 {
00973 ls->type = MT_MODULATED;
00974 ls->params.modulated.energy = 0.0;
00975 ls->params.modulated.pulsetype = MPT_UNKNOWN;
00976 ls->params.modulated.pulsetype = 0.0;
00977 ls->params.modulated.scalar = 0,0;
00978 }
00979 else if (strcmp(value,"queued")==0)
00980 {
00981 ls->type = MT_QUEUED;
00982 ls->params.queued.energy = 0.0;
00983 ls->params.queued.pulsetype = MPT_UNKNOWN;
00984 ls->params.queued.pulsetype = 0.0;
00985 ls->params.queued.scalar = 0,0;
00986 ls->params.queued.q_on = 0,0;
00987 ls->params.queued.q_off = 0,0;
00988 }
00989 else if (strcmp(value,"scheduled")==0)
00990 {
00991 ls->type = MT_SCHEDULED;
00992 memset(&(ls->params.scheduled),0,sizeof(ls->params.scheduled));
00993
00994 ls->params.scheduled.dt = 3600;
00995 ls->params.scheduled.weekdays = 0x3e;
00996 ls->params.scheduled.low = 0.0;
00997 ls->params.scheduled.on_time = 8.0;
00998 ls->params.scheduled.on_ramp = 1.0;
00999 ls->params.scheduled.high = 1.0;
01000 ls->params.scheduled.off_time = 16.0;
01001 ls->params.scheduled.off_ramp = -1.0;
01002 }
01003 else
01004 {
01005 output_error("convert_to_loadshape(string='%-.64s...', ...) type '%s' is invalid",string,value);
01006 return 0;
01007 }
01008 }
01009 else if (strcmp(param,"schedule")==0)
01010 {
01011 SCHEDULE *s = schedule_find_byname(value);
01012 if (s==NULL)
01013 {
01014 output_error("convert_to_loadshape(string='%-.64s...', ...) schedule '%s' does not exist",string,value);
01015 return 0;
01016 }
01017 ls->schedule = s;
01018 }
01019 else if (strcmp(param,"energy")==0)
01020 {
01021 int result;
01022 if (ls->type==MT_ANALOG)
01023 result=convert_unit_double(value,"kWh",&ls->params.analog.energy);
01024 else if (ls->type==MT_PULSED)
01025 result=convert_unit_double(value,"kWh",&ls->params.pulsed.energy);
01026 else if (ls->type==MT_MODULATED)
01027 result=convert_unit_double(value,"kWh",&ls->params.modulated.energy);
01028 else if (ls->type==MT_QUEUED)
01029 result=convert_unit_double(value,"kWh",&ls->params.queued.energy);
01030 else
01031 {
01032 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to parse energy before type is specified",string);
01033 return 0;
01034 }
01035 if (result==0)
01036 {
01037 output_error("convert_to_loadshape(string='%-.64s...', ...) unit of energy parameter '%s' is incompatible with kWh",string, value);
01038 return 0;
01039 }
01040 }
01041 else if (strcmp(param,"count")==0)
01042 {
01043 if (ls->type==MT_ANALOG)
01044 output_warning("convert_to_loadshape(string='%-.64s...', ...) count is not used by analog loadshapes",string);
01045 else if (ls->type==MT_PULSED)
01046 ls->params.pulsed.scalar = atof(value);
01047 else if (ls->type==MT_MODULATED)
01048 ls->params.modulated.scalar = atof(value);
01049 else if (ls->type==MT_QUEUED)
01050 ls->params.queued.scalar = atof(value);
01051 else
01052 {
01053 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to parse count before type is specified",string);
01054 return 0;
01055 }
01056 }
01057 else if (strcmp(param,"duration")==0)
01058 {
01059 if (ls->type==MT_ANALOG)
01060 output_warning("convert_to_loadshape(string='%-.64s...', ...) duration is not used by analog loadshapes",string);
01061 else if (ls->type==MT_PULSED)
01062 {
01063 if (ls->params.pulsed.pulsetype==MPT_POWER)
01064 output_warning("convert_to_loadshape(string='%-.64s...', ...) duration ignored because power has already been specified and is mutually exclusive",string);
01065 else
01066 {
01067 ls->params.pulsed.pulsetype = MPT_TIME;
01068 if (!convert_unit_double(value,"s",&ls->params.pulsed.pulsevalue))
01069 {
01070 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to convert duration '%s' to seconds",string, value);
01071 return 0;
01072 }
01073 }
01074 }
01075 else if (ls->type==MT_MODULATED)
01076 output_warning("convert_to_loadshape(string='%-.64s...', ...) duration is not used by modulated loadshapes",string);
01077 else if (ls->type==MT_QUEUED)
01078 {
01079 if (ls->params.queued.pulsetype==MPT_POWER)
01080 output_warning("convert_to_loadshape(string='%-.64s...', ...) duration ignored because power has already been specified and is mutually exclusive",string);
01081 else
01082 {
01083 ls->params.queued.pulsetype = MPT_TIME;
01084 if (!convert_unit_double(value,"s",&ls->params.queued.pulsevalue))
01085 {
01086 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to convert duration '%s' to seconds",string,value);
01087 return 0;
01088 }
01089 }
01090 }
01091 else
01092 {
01093 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to parse duration before type is specified",string);
01094 return 0;
01095 }
01096 }
01097 else if (strcmp(param,"period")==0)
01098 {
01099 if (ls->type==MT_ANALOG)
01100 output_warning("convert_to_loadshape(string='%-.64s...', ...) period is not used by analog loadshapes",string);
01101 else if (ls->type==MT_PULSED)
01102 output_warning("convert_to_loadshape(string='%-.64s...', ...) duration is not used by modulated loadshapes",string);
01103 else if (ls->type==MT_MODULATED)
01104 {
01105 if (ls->params.modulated.pulsetype==MPT_POWER)
01106 output_warning("convert_to_loadshape(string='%-.64s...', ...) period ignored because power has already been specified and is mutually exclusive",string);
01107 else
01108 {
01109 ls->params.modulated.pulsetype = MPT_TIME;
01110 if (!convert_unit_double(value,"s",&ls->params.modulated.pulsevalue))
01111 {
01112 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to convert period '%s' to seconds",string, value);
01113 return 0;
01114 }
01115 }
01116 }
01117 else if (ls->type==MT_QUEUED)
01118 output_warning("convert_to_loadshape(string='%-.64s...', ...) duration is not used by modulated loadshapes",string);
01119 else
01120 {
01121 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to parse duration before type is specified",string);
01122 return 0;
01123 }
01124 }
01125 else if (strcmp(param,"power")==0)
01126 {
01127 if (ls->type==MT_ANALOG)
01128 {
01129 if (!convert_unit_double(value,"kW",&ls->params.analog.power))
01130 {
01131 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to convert power '%s' to unit kW",string, value);
01132 return 0;
01133 }
01134 }
01135 else if (ls->type==MT_PULSED)
01136 if (ls->params.pulsed.pulsetype==MPT_TIME)
01137 output_warning("convert_to_loadshape(string='%-.64s...', ...) power ignored because duration has already been specified and is mutually exclusive",string);
01138 else
01139 {
01140 ls->params.pulsed.pulsetype = MPT_POWER;
01141 if (!convert_unit_double(value,"kW",&ls->params.pulsed.pulsevalue))
01142 {
01143 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to convert power '%s' to unit kW",string, value);
01144 return 0;
01145 }
01146 }
01147 else if (ls->type==MT_MODULATED)
01148 if (ls->params.modulated.pulsetype==MPT_TIME)
01149 output_warning("convert_to_loadshape(string='%-.64s...', ...) power ignored because period has already been specified and is mutually exclusive",string);
01150 else
01151 {
01152 ls->params.modulated.pulsetype = MPT_POWER;
01153 if (!convert_unit_double(value,"kW",&ls->params.modulated.pulsevalue))
01154 {
01155 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to convert power '%s' to unit kW",string, value);
01156 return 0;
01157 }
01158 }
01159 else if (ls->type==MT_QUEUED)
01160 if (ls->params.queued.pulsetype==MPT_TIME)
01161 output_warning("convert_to_loadshape(string='%-.64s...', ...) power ignored because duration has already been specified and is mutually exclusive",string);
01162 else
01163 {
01164 ls->params.queued.pulsetype = MPT_POWER;
01165 if (!convert_unit_double(value,"kW",&ls->params.queued.pulsevalue))
01166 {
01167 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to convert power '%s' to unit kW",string, value);
01168 return 0;
01169 }
01170 }
01171 else
01172 {
01173 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to parse count before type is specified",string);
01174 return 0;
01175 }
01176 }
01177 else if (strcmp(param,"stdev")==0)
01178 {
01179 double dev = atof(value);
01180 double err = random_triangle(-3,3);
01181 if (ls->type==MT_ANALOG)
01182 {
01183 if (ls->params.analog.energy!=0)
01184 {
01185 if (!convert_unit_double(value,"kWh",&dev))
01186 {
01187 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to convert stdev '%s' to unit kWh",string, value);
01188 return 0;
01189 }
01190 ls->params.analog.energy += dev*err;
01191 }
01192 else
01193 {
01194 if (!convert_unit_double(value,"kW",&dev))
01195 {
01196 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to convert stdev '%s' to unit kW",string, value);
01197 return 0;
01198 }
01199 ls->params.analog.power += dev*err;
01200 }
01201 }
01202 else if (ls->type==MT_PULSED)
01203 {
01204 if (ls->params.pulsed.pulsetype == MPT_TIME)
01205 {
01206 if (!convert_unit_double(value,"s",&dev))
01207 {
01208 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to convert stdev '%s' to unit s",string, value);
01209 return 0;
01210 }
01211 ls->params.pulsed.pulsevalue += dev*err;
01212 }
01213 else if (ls->params.pulsed.pulsetype == MPT_POWER)
01214 {
01215 if (!convert_unit_double(value,"kW",&dev))
01216 {
01217 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to convert stdev '%s' to unit kW",string, value);
01218 return 0;
01219 }
01220 ls->params.pulsed.pulsevalue += dev*err;
01221 }
01222 }
01223 else if (ls->type==MT_MODULATED)
01224 {
01225 if (ls->params.modulated.pulsetype == MPT_TIME)
01226 {
01227 if (!convert_unit_double(value,"s",&dev))
01228 {
01229 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to convert stdev '%s' to unit s",string, value);
01230 return 0;
01231 }
01232 ls->params.modulated.pulsevalue += dev*err;
01233 }
01234 else if (ls->params.modulated.pulsetype == MPT_POWER)
01235 {
01236 if (!convert_unit_double(value,"kW",&dev))
01237 {
01238 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to convert stdev '%s' to unit kW",string, value);
01239 return 0;
01240 }
01241 ls->params.modulated.pulsevalue += dev*err;
01242 }
01243 }
01244 else if (ls->type==MT_QUEUED)
01245 {
01246 if (ls->params.queued.pulsetype == MPT_TIME)
01247 {
01248 if (!convert_unit_double(value,"s",&dev))
01249 {
01250 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to convert stdev '%s' to unit s",string, value);
01251 return 0;
01252 }
01253 ls->params.queued.pulsevalue += dev*err;
01254 }
01255 else if (ls->params.queued.pulsetype == MPT_POWER)
01256 {
01257 if (!convert_unit_double(value,"kW",&dev))
01258 {
01259 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to convert stdev '%s' to unit kW",string, value);
01260 return 0;
01261 }
01262 ls->params.queued.pulsevalue += dev*err;
01263 }
01264 }
01265 }
01266 else if (strcmp(param,"modulation")==0)
01267 {
01268 if (ls->type==MT_ANALOG)
01269 output_warning("convert_to_loadshape(string='%-.64s...', ...) modulation is not used by analog loadshapes",string);
01270 else if (ls->type==MT_PULSED)
01271 output_warning("convert_to_loadshape(string='%-.64s...', ...) modulation is not used by pulsed loadshapes",string);
01272 else if (ls->type==MT_MODULATED)
01273 {
01274 if (strcmp(value,"amplitude")==0)
01275 {
01276 output_warning("convert_to_loadshape(string='%-.64s...', ...) amplitude modulation is not fully supported",string);
01277 ls->params.modulated.modulation = MMT_AMPLITUDE;
01278 }
01279 else if (strcmp(value,"pulsewidth")==0)
01280 {
01281 ls->params.modulated.modulation = MMT_PULSEWIDTH;
01282 }
01283 else if (strcmp(value,"frequency")==0)
01284 {
01285 ls->params.modulated.modulation = MMT_FREQUENCY;
01286 }
01287 else
01288 {
01289 output_error("convert_to_loadshape(string='%-.64s...', ...) '%s' is not a recognized modulation",string,value);
01290 return 0;
01291 }
01292 }
01293 else if (ls->type==MT_QUEUED)
01294 output_warning("convert_to_loadshape(string='%-.64s...', ...) modulation is not used by queued loadshapes",string);
01295 }
01296 else if (strcmp(param,"pulse")==0)
01297 {
01298 if (ls->type==MT_ANALOG)
01299 output_warning("convert_to_loadshape(string='%-.64s...', ...) pulse energy is not used by analog loadshapes",string);
01300 else if (ls->type==MT_PULSED)
01301 output_warning("convert_to_loadshape(string='%-.64s...', ...) pulse energy is not used by pulsed loadshapes",string);
01302 else if (ls->type==MT_MODULATED)
01303 {
01304 if (!convert_unit_double(value,"kWh",&ls->params.modulated.pulseenergy))
01305 {
01306 output_error("convert_to_loadshape(string='%-.64s...', ...) unable to convert pulse energy '%s' to unit kWh",string, value);
01307 return 0;
01308 }
01309 }
01310 else if (ls->type==MT_QUEUED)
01311 output_warning("convert_to_loadshape(string='%-.64s...', ...) pulse energy is not used by queued loadshapes",string);
01312 }
01313 else if (strcmp(param,"q_on")==0)
01314 {
01315 if (ls->type==MT_ANALOG)
01316 output_warning("convert_to_loadshape(string='%-.64s...', ...) q_on is not used by analog loadshapes",string);
01317 else if (ls->type==MT_PULSED)
01318 output_warning("convert_to_loadshape(string='%-.64s...', ...) q_on is not used by pulsed loadshapes",string);
01319 else if (ls->type==MT_MODULATED)
01320 output_warning("convert_to_loadshape(string='%-.64s...', ...) q_on is not used by modulated loadshapes",string);
01321 else if (ls->type==MT_QUEUED)
01322 ls->params.queued.q_on = atof(value);
01323 }
01324 else if (strcmp(param,"q_off")==0)
01325 {
01326 if (ls->type==MT_ANALOG)
01327 output_warning("convert_to_loadshape(string='%-.64s...', ...) q_off is not used by analog loadshapes",string);
01328 else if (ls->type==MT_PULSED)
01329 output_warning("convert_to_loadshape(string='%-.64s...', ...) q_off is not used by pulsed loadshapes",string);
01330 else if (ls->type==MT_MODULATED)
01331 output_warning("convert_to_loadshape(string='%-.64s...', ...) q_off is not used by modulated loadshapes",string);
01332 else if (ls->type==MT_QUEUED)
01333 ls->params.queued.q_off = atof(value);
01334 }
01335 else if (strcmp(param,"weekdays")==0)
01336 {
01337 if (ls->type!=MT_SCHEDULED)
01338 output_warning("convert_to_loadshape(string='%-.64s...', ...) %s is not used by analog loadshapes",string, param);
01339 else
01340 ls->params.scheduled.weekdays = schedule_string_to_weekday(value);
01341 }
01342 else if (strcmp(param,"low")==0)
01343 {
01344 if (ls->type!=MT_SCHEDULED)
01345 output_warning("convert_to_loadshape(string='%-.64s...', ...) %s is not used by analog loadshapes",string, param);
01346 else if (sample_from_diversity(&ls->params.scheduled.low,value)==0)
01347 output_error("convert_to_loadshape(string='%-.64s...', ...) %s syntax error, '%s' not valid", string, param, value);
01348 }
01349 else if (strcmp(param,"on-time")==0)
01350 {
01351 if (ls->type!=MT_SCHEDULED)
01352 output_warning("convert_to_loadshape(string='%-.64s...', ...) %s is not used by analog loadshapes",string, param);
01353 else if (sample_from_diversity(&ls->params.scheduled.on_time,value)==0)
01354 output_error("convert_to_loadshape(string='%-.64s...', ...) %s syntax error, '%s' not valid", string, param, value);
01355 }
01356 else if (strcmp(param,"on-ramp")==0)
01357 {
01358 if (ls->type!=MT_SCHEDULED)
01359 output_warning("convert_to_loadshape(string='%-.64s...', ...) %s is not used by analog loadshapes",string, param);
01360 else if (sample_from_diversity(&ls->params.scheduled.on_ramp,value)==0)
01361 output_error("convert_to_loadshape(string='%-.64s...', ...) %s syntax error, '%s' not valid", string, param, value);
01362 }
01363 else if (strcmp(param,"high")==0)
01364 {
01365 if (ls->type!=MT_SCHEDULED)
01366 output_warning("convert_to_loadshape(string='%-.64s...', ...) %s is not used by analog loadshapes",string, param);
01367 else if (sample_from_diversity(&ls->params.scheduled.high,value)==0)
01368 output_error("convert_to_loadshape(string='%-.64s...', ...) %s syntax error, '%s' not valid", string, param, value);
01369 }
01370 else if (strcmp(param,"off-time")==0)
01371 {
01372 if (ls->type!=MT_SCHEDULED)
01373 output_warning("convert_to_loadshape(string='%-.64s...', ...) %s is not used by analog loadshapes",string, param);
01374 else if (sample_from_diversity(&ls->params.scheduled.off_time,value)==0)
01375 output_error("convert_to_loadshape(string='%-.64s...', ...) %s syntax error, '%s' not valid", string, param, value);
01376 }
01377 else if (strcmp(param,"off-ramp")==0)
01378 {
01379 if (ls->type!=MT_SCHEDULED)
01380 output_warning("convert_to_loadshape(string='%-.64s...', ...) %s is not used by analog loadshapes",string, param);
01381 else if (sample_from_diversity(&ls->params.scheduled.off_ramp,value)==0)
01382 output_error("convert_to_loadshape(string='%-.64s...', ...) %s syntax error, '%s' not valid", string, param, value);
01383 }
01384 else if (strcmp(param,"")!=0)
01385 {
01386 output_error("convert_to_loadshape(string='%-.64s...', ...) parameter '%s' is not valid",string,param);
01387 return 0;
01388 }
01389 }
01390
01391
01392 if (loadshape_init((loadshape*)data))
01393 return 0;
01394
01395
01396 return 1;
01397 }
01398
01399 int loadshape_test(void)
01400 {
01401 int failed = 0;
01402 int ok = 0;
01403 int errorcount = 0;
01404
01405
01406 struct s_test {
01407 char *name;
01408 } *p, test[] = {
01409 "TODO",
01410 };
01411
01412 output_test("\nBEGIN: loadshape tests");
01413 for (p=test;p<test+sizeof(test)/sizeof(test[0]);p++)
01414 {
01415 }
01416
01417
01418
01419
01420 if (failed)
01421 {
01422 output_error("loadshapetest: %d loadshape tests failed--see test.txt for more information",failed);
01423 output_test("!!! %d loadshape tests failed, %d errors found",failed,errorcount);
01424 }
01425 else
01426 {
01427 output_verbose("%d loadshape tests completed with no errors--see test.txt for details",ok);
01428 output_test("loadshapetest: %d loadshape tests completed, %d errors found",ok,errorcount);
01429 }
01430 output_test("END: loadshape tests");
01431 return failed;
01432 }
01433