void Operation::updateProblems() { // Find all operationplans, and delegate the problem detection to them if (getDetectProblems()) for (OperationPlan *o = first_opplan; o; o = o->next) o->updateProblems(); }
void ResourceBuckets::updateProblems() { // Delete existing problems for this resource Problem::clearProblems(*this, true, false); // Problem detection disabled on this resource if (!getDetectProblems()) return; // Loop over all events Date startdate = Date::infinitePast; double load = 0.0; for (loadplanlist::const_iterator iter = loadplans.begin(); iter != loadplans.end(); iter++) { if (iter->getEventType() != 2) load = iter->getOnhand(); else { // Evaluate previous bucket if (load < 0.0) new ProblemCapacityOverload(this, startdate, iter->getDate(), -load); // Reset evaluation for the new bucket startdate = iter->getDate(); load = 0.0; } } // Evaluate the final bucket if (load < 0.0) new ProblemCapacityOverload(this, startdate, Date::infiniteFuture, -load); }
DECLARE_EXPORT void Plannable::writeElement (XMLOutput* o, const Keyword& tag, mode m) const { // We don't bother about the mode, since this method is only called from // within the writeElement() method of other classes. // Problem detection flag only written if different from the default value if (!getDetectProblems()) o->writeElement(Tags::tag_detectproblems, false); }
DECLARE_EXPORT void Demand::updateProblems() { // The relation between the demand and the related problem classes is such // that the demand object is the only active one. The problem objects are // fully controlled and managed by the associated demand object. // A flag for each problem type that may need to be created bool needsNotPlanned(false); bool needsEarly(false); bool needsLate(false); bool needsShort(false); bool needsExcess(false); // Problem detection disabled on this demand if (!getDetectProblems()) return; // Check which problems need to be created if (deli.empty()) { // Check if a new ProblemDemandNotPlanned needs to be created if (getQuantity()>0.0) needsNotPlanned = true; } else { // Loop through the deliveries for (OperationPlanList::iterator i = deli.begin(); i!=deli.end(); ++i) { // Check for ProblemLate problem long d(getDue() - (*i)->getDates().getEnd()); if (d < 0L) needsLate = true; // Check for ProblemEarly problem else if (d > 0L) needsEarly = true; } // Check for ProblemShort problem double plannedqty = getPlannedQuantity(); if (plannedqty + ROUNDING_ERROR < qty) needsShort = true; // Check for ProblemExcess Problem if (plannedqty - ROUNDING_ERROR > qty) needsExcess = true; } // Loop through the existing problems for (Problem::iterator j = Problem::begin(this, false); j!=Problem::end(); ) { // Need to increment now and define a pointer to the problem, since the // problem can be deleted soon (which invalidates the iterator). Problem& curprob = *j; ++j; // The if-statement keeps the problem detection code concise and // concentrated. However, a drawback of this design is that a new Problem // subclass will also require a new Demand subclass. I think such a link // is acceptable. if (typeid(curprob) == typeid(ProblemEarly)) { // if: problem needed and it exists already if (needsEarly) needsEarly = false; // else: problem not needed but it exists already else delete &curprob; } else if (typeid(curprob) == typeid(ProblemDemandNotPlanned)) { if (needsNotPlanned) needsNotPlanned = false; else delete &curprob; } else if (typeid(curprob) == typeid(ProblemLate)) { if (needsLate) needsLate = false; else delete &curprob; } else if (typeid(curprob) == typeid(ProblemShort)) { if (needsShort) needsShort = false; else delete &curprob; } else if (typeid(curprob) == typeid(ProblemExcess)) { if (needsExcess) needsExcess = false; else delete &curprob; } // Note that there may be other demand exceptions that are not caught in // this loop. These are problems defined and managed by subclasses. } // Create the problems that are required but aren't existing yet. if (needsNotPlanned) new ProblemDemandNotPlanned(this); if (needsLate) new ProblemLate(this); if (needsEarly) new ProblemEarly(this); if (needsShort) new ProblemShort(this); if (needsExcess) new ProblemExcess(this); }
DECLARE_EXPORT void Buffer::updateProblems() { // Delete existing problems for this buffer Problem::clearProblems(*this); // Problem detection disabled on this buffer if (!getDetectProblems()) return; // Loop through the flowplans Date excessProblemStart; Date shortageProblemStart; bool shortageProblem = false; bool excessProblem = false; double curMax(0.0); double shortageQty(0.0); double curMin(0.0); double excessQty(0.0); for (flowplanlist::const_iterator iter = flowplans.begin(); iter != flowplans.end(); ) { // Process changes in the maximum or minimum targets if (iter->getEventType() == 4) curMax = iter->getMax(); else if (iter->getEventType() == 3) curMin = iter->getMin(); // Only consider the last flowplan for a certain date const TimeLine<FlowPlan>::Event *f = &*(iter++); if (iter!=flowplans.end() && iter->getDate()==f->getDate()) continue; // Check against minimum target double delta = f->getOnhand() - curMin; if (delta < -ROUNDING_ERROR) { if (!shortageProblem) { // Start of a problem shortageProblemStart = f->getDate(); shortageQty = delta; shortageProblem = true; } else if (delta < shortageQty) // New shortage qty shortageQty = delta; } else { if (shortageProblem) { // New problem now ends if (f->getDate() != shortageProblemStart) new ProblemMaterialShortage (this, shortageProblemStart, f->getDate(), -shortageQty); shortageProblem = false; } } // Check against maximum target delta = f->getOnhand() - (curMin<curMax ? curMax : curMin); if (delta > ROUNDING_ERROR) { if (!excessProblem) { // New problem starts here excessProblemStart = f->getDate(); excessQty = delta; excessProblem = true; } else if (delta > excessQty) excessQty = delta; } else { if (excessProblem) { // New excess qty // New problem now ends if (f->getDate() != excessProblemStart) new ProblemMaterialExcess (this, excessProblemStart, f->getDate(), excessQty); excessProblem = false; } } } // End of for-loop through the flowplans // The excess lasts till the end of the horizon... if (excessProblem) new ProblemMaterialExcess (this, excessProblemStart, Date::infiniteFuture, excessQty); // The shortage lasts till the end of the horizon... if (shortageProblem) new ProblemMaterialShortage (this, shortageProblemStart, Date::infiniteFuture, -shortageQty); }
void Resource::updateProblems() { // Delete existing problems for this resource Problem::clearProblems(*this, true, false); // Problem detection disabled on this resource if (!getDetectProblems()) return; // Loop through the loadplans Date excessProblemStart; Date shortageProblemStart; bool excessProblem = false; bool shortageProblem = false; double curMax(0.0); double shortageQty(0.0); double curMin(0.0); double excessQty(0.0); for (loadplanlist::const_iterator iter = loadplans.begin(); iter != loadplans.end(); ) { // Process changes in the maximum or minimum targets if (iter->getEventType() == 4) curMax = iter->getMax(); else if (iter->getEventType() == 3) curMin = iter->getMin(); // Only consider the last loadplan for a certain date const TimeLine<LoadPlan>::Event *f = &*(iter++); if (iter!=loadplans.end() && iter->getDate()==f->getDate()) continue; // Check against minimum target double delta = f->getOnhand() - curMin; if (delta < -ROUNDING_ERROR) { if (!shortageProblem) { shortageProblemStart = f->getDate(); shortageQty = delta; shortageProblem = true; } else if (delta < shortageQty) // New shortage qty shortageQty = delta; } else { if (shortageProblem) { // New problem now ends if (f->getDate() != shortageProblemStart) new ProblemCapacityUnderload(this, DateRange(shortageProblemStart, f->getDate()), -shortageQty); shortageProblem = false; } } // Note that theoretically we can have a minimum and a maximum problem for // the same moment in time. // Check against maximum target delta = f->getOnhand() - curMax; if (delta > ROUNDING_ERROR) { if (!excessProblem) { excessProblemStart = f->getDate(); excessQty = delta; excessProblem = true; } else if (delta > excessQty) excessQty = delta; } else { if (excessProblem) { // New problem now ends if (f->getDate() != excessProblemStart) new ProblemCapacityOverload(this, excessProblemStart, f->getDate(), excessQty); excessProblem = false; } } } // End of for-loop through the loadplans // The excess lasts till the end of the horizon... if (excessProblem) new ProblemCapacityOverload(this, excessProblemStart, Date::infiniteFuture, excessQty); // The shortage lasts till the end of the horizon... if (shortageProblem) new ProblemCapacityUnderload(this, DateRange(shortageProblemStart, Date::infiniteFuture), -shortageQty); }