00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "forecast.h"
00029
00030 namespace module_forecast
00031 {
00032
00033 const Keyword Forecast::tag_total("total");
00034 const Keyword Forecast::tag_net("net");
00035 const Keyword Forecast::tag_consumed("consumed");
00036 const MetaClass *Forecast::metadata;
00037 const MetaClass *ForecastBucket::metadata;
00038
00039
00040 int Forecast::initialize()
00041 {
00042
00043 metadata = new MetaClass("demand", "demand_forecast",
00044 Object::createString<Forecast>);
00045
00046
00047 FunctorStatic<Calendar,Forecast>::connect(SIG_REMOVE);
00048
00049
00050 FreppleClass<Forecast,Demand>::getType().addMethod("timeseries", Forecast::timeseries, METH_VARARGS,
00051 "Set the future based on the timeseries of historical data");
00052 return FreppleClass<Forecast,Demand>::initialize();
00053 }
00054
00055
00056 int ForecastBucket::initialize()
00057 {
00058
00059
00060 metadata = new MetaClass("demand", "demand_forecastbucket");
00061
00062
00063
00064 PythonType& x = FreppleClass<ForecastBucket,Demand>::getType();
00065 x.setName("demand_forecastbucket");
00066 x.setDoc("frePPLe forecastbucket");
00067 x.supportgetattro();
00068 x.supportsetattro();
00069 const_cast<MetaClass*>(metadata)->pythonClass = x.type_object();
00070 return x.typeReady();
00071 }
00072
00073
00074 bool Forecast::callback(Calendar* l, const Signal a)
00075 {
00076
00077
00078
00079 for (MapOfForecasts::iterator x = ForecastDictionary.begin();
00080 x != ForecastDictionary.end(); ++x)
00081 if (x->second->calptr == l)
00082
00083 x->second->calptr = NULL;
00084 return true;
00085 }
00086
00087
00088 Forecast::~Forecast()
00089 {
00090
00091 for (MapOfForecasts::iterator x=
00092 ForecastDictionary.lower_bound(make_pair(&*getItem(),&*getCustomer()));
00093 x != ForecastDictionary.end(); ++x)
00094 if (x->second == this)
00095 {
00096 ForecastDictionary.erase(x);
00097 break;
00098 }
00099
00100
00101 for(memberIterator i = beginMember(); i != endMember(); i = beginMember())
00102 delete &*i;
00103 }
00104
00105
00106 void Forecast::instantiate()
00107 {
00108 if (!calptr) throw DataException("Missing forecast calendar");
00109
00110
00111
00112 const CalendarDouble* c = dynamic_cast<const CalendarDouble*>(calptr);
00113 ForecastBucket* prev = NULL;
00114 Date prevDate;
00115 double prevValue(0.0);
00116 if (c)
00117
00118 for (CalendarDouble::EventIterator i(c); i.getDate()<=Date::infiniteFuture; ++i)
00119 {
00120 if ((prevDate || i.getDate() == Date::infiniteFuture) && prevValue > 0.0)
00121 {
00122 prev = new ForecastBucket
00123 (this, prevDate, i.getDate(), prevValue, prev);
00124 Demand::add(prev);
00125 }
00126 if (i.getDate() == Date::infiniteFuture) break;
00127 prevDate = i.getDate();
00128 prevValue = i.getValue();
00129 }
00130 else
00131 {
00132 const CalendarInt* c = dynamic_cast<const CalendarInt*>(calptr);
00133 if (c)
00134
00135 for (CalendarInt::EventIterator i(c); i.getDate()<=Date::infiniteFuture; ++i)
00136 {
00137 if ((prevDate || i.getDate() == Date::infiniteFuture) && prevValue > 0)
00138 {
00139 prev = new ForecastBucket
00140 (this, prevDate, i.getDate(), prevValue, prev);
00141 Demand::add(prev);
00142 }
00143 if (i.getDate() == Date::infiniteFuture) break;
00144 prevDate = i.getDate();
00145 prevValue = static_cast<double>(i.getValue());
00146 }
00147 else
00148 {
00149 const CalendarBool* c = dynamic_cast<const CalendarBool*>(calptr);
00150 bool prevValueBool = false;
00151 if (c)
00152
00153 for (CalendarBool::EventIterator i(c); true; ++i)
00154 {
00155 if ((prevDate || i.getDate() == Date::infiniteFuture) && prevValueBool)
00156 {
00157 prev = new ForecastBucket
00158 (this, prevDate, i.getDate(), 1.0, prev);
00159 Demand::add(prev);
00160 }
00161 if (i.getDate() == Date::infiniteFuture) break;
00162 prevDate = i.getDate();
00163 prevValueBool = i.getValue();
00164 }
00165 else
00166 {
00167
00168 for (Calendar::EventIterator i(calptr); true; ++i)
00169 {
00170 if (prevDate || i.getDate() == Date::infiniteFuture)
00171 {
00172 prev = new ForecastBucket(this, prevDate, i.getDate(), 1.0, prev);
00173 Demand::add(prev);
00174 if (i.getDate() == Date::infiniteFuture) break;
00175 }
00176 prevDate = i.getDate();
00177 }
00178 }
00179 }
00180 }
00181 }
00182
00183
00184 void Forecast::setDiscrete(const bool b)
00185 {
00186
00187 discrete = b;
00188
00189
00190 if (discrete)
00191 for (memberIterator m = beginMember(); m!=endMember(); ++m)
00192 m->setQuantity(floor(m->getQuantity()));
00193 }
00194
00195
00196 void Forecast::setTotalQuantity(const DateRange& d, double f)
00197 {
00198
00199 if (!isGroup()) instantiate();
00200
00201
00202 double weights = 0.0;
00203 for (memberIterator m = beginMember(); m!=endMember(); ++m)
00204 {
00205 ForecastBucket* x = dynamic_cast<ForecastBucket*>(&*m);
00206 if (!x)
00207 throw DataException("Invalid subdemand of forecast '" + getName() +"'");
00208 if (d.intersect(x->getDueRange()))
00209 {
00210
00211 if (!d.getDuration())
00212 {
00213
00214 x->setTotal(f);
00215 return;
00216 }
00217 weights += x->getWeight() * static_cast<long>(x->getDueRange().overlap(d));
00218 }
00219 }
00220
00221
00222 if (!weights)
00223 throw DataException("No valid forecast date in range "
00224 + string(d) + " of forecast '" + getName() +"'");
00225
00226
00227 f /= weights;
00228 double carryover = 0.0;
00229 for (memberIterator m = beginMember(); m!=endMember(); ++m)
00230 {
00231 ForecastBucket* x = dynamic_cast<ForecastBucket*>(&*m);
00232 if (d.intersect(x->getDueRange()))
00233 {
00234
00235 TimePeriod o = x->getDueRange().overlap(d);
00236 double percent = x->getWeight() * static_cast<long>(o);
00237 if (getDiscrete())
00238 {
00239
00240 carryover += f * percent;
00241 int intdelta = static_cast<int>(ceil(carryover - 0.5));
00242 carryover -= intdelta;
00243 if (o < x->getDueRange().getDuration())
00244
00245 x->incTotal(static_cast<double>(intdelta));
00246 else
00247
00248 x->setTotal(static_cast<double>(intdelta));
00249 }
00250 else
00251 {
00252
00253 if (o < x->getDueRange().getDuration())
00254
00255 x->incTotal(f * percent);
00256 else
00257
00258 x->setTotal(f * percent);
00259 }
00260 }
00261 }
00262 }
00263
00264
00265 void Forecast::writeElement(XMLOutput *o, const Keyword &tag, mode m) const
00266 {
00267
00268 if (m == REFERENCE)
00269 {
00270 o->writeElement
00271 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00272 return;
00273 }
00274
00275
00276 if (m != NOHEADER) o->BeginObject
00277 (tag, Tags::tag_name, getName(), Tags::tag_type, getType().type);
00278
00279 o->writeElement(Tags::tag_item, &*getItem());
00280 o->writeElement(Tags::tag_operation, &*getOperation());
00281 if (getPriority()) o->writeElement(Tags::tag_priority, getPriority());
00282 o->writeElement(Tags::tag_calendar, calptr);
00283 if (!getDiscrete()) o->writeElement(Tags::tag_discrete, getDiscrete());
00284
00285
00286 o->BeginObject (Tags::tag_buckets);
00287 for (memberIterator i = beginMember(); i != endMember(); ++i)
00288 {
00289 ForecastBucket* f = dynamic_cast<ForecastBucket*>(&*i);
00290 o->BeginObject(Tags::tag_bucket, Tags::tag_start, string(f->getDue()));
00291 o->writeElement(tag_total, f->getTotal());
00292 o->writeElement(Tags::tag_quantity, f->getQuantity());
00293 o->writeElement(tag_consumed, f->getConsumed());
00294 o->EndObject(Tags::tag_bucket);
00295 }
00296 o->EndObject(Tags::tag_buckets);
00297
00298 o->EndObject(tag);
00299 }
00300
00301
00302 void Forecast::endElement(XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement)
00303 {
00304
00305
00306
00307 if (pAttr.isA(Tags::tag_calendar))
00308 {
00309 Calendar *b = dynamic_cast<Calendar*>(pIn.getPreviousObject());
00310 if (b) setCalendar(b);
00311 else throw LogicException("Incorrect object type during read operation");
00312 }
00313 else if (pAttr.isA(Tags::tag_discrete))
00314 setDiscrete(pElement.getBool());
00315 else if (pAttr.isA(Tags::tag_bucket))
00316 {
00317 pair<DateRange,double> *d =
00318 static_cast< pair<DateRange,double>* >(pIn.getUserArea());
00319 if (d)
00320 {
00321
00322 setTotalQuantity(d->first, d->second);
00323
00324 d->first.setStart(Date());
00325 d->first.setEnd(Date());
00326 d->second = 0;
00327 }
00328 }
00329 else if (pIn.getParentElement().first.isA(Tags::tag_bucket))
00330 {
00331 pair<DateRange,double> *d =
00332 static_cast< pair<DateRange,double>* >(pIn.getUserArea());
00333 if (pAttr.isA(tag_total))
00334 {
00335 if (d) d->second = pElement.getDouble();
00336 else pIn.setUserArea(
00337 new pair<DateRange,double>(DateRange(),pElement.getDouble())
00338 );
00339 }
00340 else if (pAttr.isA(Tags::tag_start))
00341 {
00342 Date x = pElement.getDate();
00343 if (d)
00344 {
00345 if (!d->first.getStart()) d->first.setStartAndEnd(x,x);
00346 else d->first.setStart(x);
00347 }
00348 else pIn.setUserArea(new pair<DateRange,double>(DateRange(x,x),0));
00349 }
00350 else if (pAttr.isA(Tags::tag_end))
00351 {
00352 Date x = pElement.getDate();
00353 if (d)
00354 {
00355 if (!d->first.getStart()) d->first.setStartAndEnd(x,x);
00356 else d->first.setEnd(x);
00357 }
00358 else pIn.setUserArea(new pair<DateRange,double>(DateRange(x,x),0));
00359 }
00360 }
00361 else
00362 Demand::endElement(pIn, pAttr, pElement);
00363
00364 if (pIn.isObjectEnd())
00365 {
00366
00367 if (pIn.getUserArea())
00368 delete static_cast< pair<DateRange,double>* >(pIn.getUserArea());
00369 }
00370 }
00371
00372
00373 void Forecast::beginElement(XMLInput& pIn, const Attribute& pAttr)
00374 {
00375 if (pAttr.isA(Tags::tag_calendar))
00376 pIn.readto( Calendar::reader(Calendar::metadata, pIn.getAttributes()) );
00377 else
00378 Demand::beginElement(pIn, pAttr);
00379 }
00380
00381
00382 void Forecast::setCalendar(Calendar* c)
00383 {
00384 if (isGroup())
00385 throw DataException(
00386 "Changing the calendar of an initialized forecast isn't allowed");
00387 calptr = c;
00388 }
00389
00390
00391 void Forecast::setItem(Item* i)
00392 {
00393
00394 if (getItem() == i) return;
00395
00396
00397 for (MapOfForecasts::iterator x =
00398 ForecastDictionary.lower_bound(make_pair(
00399 &*getItem(),&*getCustomer()
00400 ));
00401 x != ForecastDictionary.end(); ++x)
00402 if (x->second == this)
00403 {
00404 ForecastDictionary.erase(x);
00405 break;
00406 }
00407 ForecastDictionary.insert(make_pair(make_pair(i,&*getCustomer()),this));
00408
00409
00410 Demand::setItem(i);
00411
00412
00413 for (memberIterator m = beginMember(); m!=endMember(); ++m)
00414 m->setItem(i);
00415 }
00416
00417
00418 void Forecast::setCustomer(Customer* i)
00419 {
00420
00421 if (getCustomer() == i) return;
00422
00423
00424 for (MapOfForecasts::iterator x =
00425 ForecastDictionary.lower_bound(make_pair(
00426 getItem(), getCustomer()
00427 ));
00428 x != ForecastDictionary.end(); ++x)
00429 if (x->second == this)
00430 {
00431 ForecastDictionary.erase(x);
00432 break;
00433 }
00434 ForecastDictionary.insert(make_pair(make_pair(&*getItem(),i),this));
00435
00436
00437 Demand::setCustomer(i);
00438
00439
00440 for (memberIterator m = beginMember(); m!=endMember(); ++m)
00441 m->setCustomer(i);
00442 }
00443
00444
00445 void Forecast::setMaxLateness(TimePeriod i)
00446 {
00447 Demand::setMaxLateness(i);
00448
00449 for (memberIterator m = beginMember(); m!=endMember(); ++m)
00450 m->setMaxLateness(i);
00451 }
00452
00453
00454 void Forecast::setMinShipment(double i)
00455 {
00456 Demand::setMinShipment(i);
00457
00458 for (memberIterator m = beginMember(); m!=endMember(); ++m)
00459 m->setMinShipment(i);
00460 }
00461
00462
00463 void Forecast::setPriority(int i)
00464 {
00465 Demand::setPriority(i);
00466
00467 for (memberIterator m = beginMember(); m!=endMember(); ++m)
00468 m->setPriority(i);
00469 }
00470
00471
00472 void Forecast::setOperation(Operation *o)
00473 {
00474 Demand::setOperation(o);
00475
00476 for (memberIterator m = beginMember(); m!=endMember(); ++m)
00477 m->setOperation(o);
00478 }
00479
00480 }