DECLARE_EXPORT PeggingIterator::PeggingIterator(const Demand* d) : downstream(false), firstIteration(true), first(false) { initType(metadata); const Demand::OperationPlanList &deli = d->getDelivery(); for (Demand::OperationPlanList::const_iterator opplaniter = deli.begin(); opplaniter != deli.end(); ++opplaniter) { OperationPlan *t = (*opplaniter)->getTopOwner(); updateStack(t, t->getQuantity(), 0.0, 0); } }
PeggingIterator::PeggingIterator(const Demand* d) : downstream(false), firstIteration(true), first(false), second_pass(false) { initType(metadata); const Demand::OperationPlanList &deli = d->getDelivery(); for (Demand::OperationPlanList::const_iterator opplaniter = deli.begin(); opplaniter != deli.end(); ++opplaniter) { OperationPlan *t = (*opplaniter)->getTopOwner(); updateStack(t, t->getQuantity(), 0.0, 0); } // Bring all pegging information to a second stack. // Only in this way can we avoid that the same operationplan is returned // multiple times while (operator bool()) { /** Check if already found in the vector. */ bool found = false; state& curtop = states.back(); for (deque<state>::iterator it = states_sorted.begin(); it != states_sorted.end() && !found; ++it) if (it->opplan == curtop.opplan) { // Update existing element in sorted stack it->quantity += curtop.quantity; if (it->level > curtop.level) it->level = curtop.level; found = true; } if (!found) // New element in sorted stack states_sorted.push_back( state(curtop.opplan, curtop.quantity, curtop.offset, curtop.level) ); if (downstream) ++*this; else --*this; } // The normal iteration will use the sorted results second_pass = true; }
DECLARE_EXPORT void Buffer::followPegging (PeggingIterator& iter, FlowPlan* curflowplan, double qty, double offset, short lvl) { if (!curflowplan->getOperationPlan()->getQuantity() || curflowplan->getBuffer()->getTool()) // Flowplans with quantity 0 have no pegging. // Flowplans for buffers representing tools have no pegging either. return; Buffer::flowplanlist::iterator f = getFlowPlans().begin(curflowplan); if (curflowplan->getQuantity() < -ROUNDING_ERROR && !iter.isDownstream()) { // CASE 1: // This is a flowplan consuming from a buffer. Navigating upstream means // finding the flowplans producing this consumed material. double scale = - curflowplan->getQuantity() / curflowplan->getOperationPlan()->getQuantity(); double startQty = f->getCumulativeConsumed() + f->getQuantity() + offset * scale; double endQty = startQty + qty * scale; if (f->getCumulativeProduced() <= startQty + ROUNDING_ERROR) { // CASE 1A: Not produced enough yet: move forward while (f!=getFlowPlans().end() && f->getCumulativeProduced() <= startQty) ++f; while (f!=getFlowPlans().end() && ( (f->getQuantity()<=0 && f->getCumulativeProduced() < endQty) || (f->getQuantity()>0 && f->getCumulativeProduced()-f->getQuantity() < endQty)) ) { if (f->getQuantity() > ROUNDING_ERROR) { double newqty = f->getQuantity(); double newoffset = 0.0; if (f->getCumulativeProduced()-f->getQuantity() < startQty) { newoffset = startQty - (f->getCumulativeProduced()-f->getQuantity()); newqty -= newoffset; } if (f->getCumulativeProduced() > endQty) newqty -= f->getCumulativeProduced() - endQty; OperationPlan *opplan = dynamic_cast<const FlowPlan*>(&(*f))->getOperationPlan(); OperationPlan *topopplan = opplan->getTopOwner(); if (topopplan->getOperation()->getType() == *OperationSplit::metadata) topopplan = opplan; iter.updateStack( topopplan, topopplan->getQuantity() * newqty / f->getQuantity(), topopplan->getQuantity() * newoffset / f->getQuantity(), lvl ); } ++f; } } else { // CASE 1B: Produced too much already: move backward while ( f!=getFlowPlans().end() && ((f->getQuantity()<=0 && f->getCumulativeProduced() > endQty) || (f->getQuantity()>0 && f->getCumulativeProduced()-f->getQuantity() > endQty))) --f; while (f!=getFlowPlans().end() && f->getCumulativeProduced() > startQty) { if (f->getQuantity() > ROUNDING_ERROR) { double newqty = f->getQuantity(); double newoffset = 0.0; if (f->getCumulativeProduced()-f->getQuantity() < startQty) { newoffset = startQty - (f->getCumulativeProduced()-f->getQuantity()); newqty -= newoffset; } if (f->getCumulativeProduced() > endQty) newqty -= f->getCumulativeProduced() - endQty; OperationPlan *opplan = dynamic_cast<FlowPlan*>(&(*f))->getOperationPlan(); OperationPlan *topopplan = opplan->getTopOwner(); if (topopplan->getOperation()->getType() == *OperationSplit::metadata) topopplan = opplan; iter.updateStack( topopplan, topopplan->getQuantity() * newqty / f->getQuantity(), topopplan->getQuantity() * newoffset / f->getQuantity(), lvl ); } --f; } } return; } if (curflowplan->getQuantity() > ROUNDING_ERROR && iter.isDownstream()) { // CASE 2: // This is a flowplan producing in a buffer. Navigating downstream means // finding the flowplans consuming this produced material. double scale = curflowplan->getQuantity() / curflowplan->getOperationPlan()->getQuantity(); double startQty = f->getCumulativeProduced() - f->getQuantity() + offset * scale; double endQty = startQty + qty * scale; if (f->getCumulativeConsumed() <= startQty + ROUNDING_ERROR) { // CASE 2A: Not consumed enough yet: move forward while (f!=getFlowPlans().end() && f->getCumulativeConsumed() <= startQty) ++f; while (f!=getFlowPlans().end() && ( (f->getQuantity()<=0 && f->getCumulativeConsumed()+f->getQuantity() < endQty) || (f->getQuantity()>0 && f->getCumulativeConsumed() < endQty)) ) { if (f->getQuantity() < -ROUNDING_ERROR) { double newqty = - f->getQuantity(); double newoffset = 0.0; if (f->getCumulativeConsumed()+f->getQuantity() < startQty) { newoffset = startQty - (f->getCumulativeConsumed()+f->getQuantity()); newqty -= newoffset; } if (f->getCumulativeConsumed() > endQty) newqty -= f->getCumulativeConsumed() - endQty; OperationPlan *opplan = dynamic_cast<FlowPlan*>(&(*f))->getOperationPlan(); OperationPlan *topopplan = opplan->getTopOwner(); if (topopplan->getOperation()->getType() == *OperationSplit::metadata) topopplan = opplan; iter.updateStack( topopplan, - topopplan->getQuantity() * newqty / f->getQuantity(), - topopplan->getQuantity() * newoffset / f->getQuantity(), lvl ); } ++f; } } else { // CASE 2B: Consumed too much already: move backward while ( f!=getFlowPlans().end() && ((f->getQuantity()<=0 && f->getCumulativeConsumed()+f->getQuantity() < endQty) || (f->getQuantity()>0 && f->getCumulativeConsumed() < endQty))) --f; while (f!=getFlowPlans().end() && f->getCumulativeConsumed() > startQty) { if (f->getQuantity() < -ROUNDING_ERROR) { double newqty = - f->getQuantity(); double newoffset = 0.0; if (f->getCumulativeConsumed()+f->getQuantity() < startQty) newqty -= startQty - (f->getCumulativeConsumed()+f->getQuantity()); if (f->getCumulativeConsumed() > endQty) newqty -= f->getCumulativeConsumed() - endQty; OperationPlan *opplan = dynamic_cast<FlowPlan*>(&(*f))->getOperationPlan(); OperationPlan *topopplan = opplan->getTopOwner(); if (topopplan->getOperation()->getType() == *OperationSplit::metadata) topopplan = opplan; iter.updateStack( topopplan, - topopplan->getQuantity() * newqty / f->getQuantity(), - topopplan->getQuantity() * newoffset / f->getQuantity(), lvl ); } --f; } } } }
int main (int argc, char *argv[]) { try { // 0: Initialize FreppleInitialize(); // 1: Read the model FreppleReadXMLFile("problems.xml",true,false); reportProblems("reading input"); // 2: Plan the model FreppleReadXMLData( "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" \ "<plan xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" \ "<?python\n" \ "frepple.solver_mrp(name=\"MRP\", constraints=0).solve()\n" \ "?>\n" \ "</plan>", true, false ); reportProblems("planning"); // Define variables for each of the 2 operation_plans Operation *buildoper = Operation::find("make end item"); OperationPlan *build = &*OperationPlan::iterator(buildoper); Operation *deliveroper = Operation::find("delivery end item"); OperationPlan *deliver = &*OperationPlan::iterator(deliveroper); if (!deliver || !build) throw DataException("Can't find operationplans"); // 3: Increase quantity of the delivery & report float oldqty = deliver->getQuantity(); deliver->setQuantity(100); reportProblems("increasing delivery quantity"); // 4: Reduce the quantity of the delivey & report deliver->setQuantity(1); reportProblems("decreasing delivery quantity"); // 5: Move the delivery early & report Date oldstart = deliver->getDates().getStart(); deliver->setStart(oldstart - Duration(86400)); reportProblems("moving delivery early"); // 6: Move the delivery late & report deliver->setStart(oldstart + Duration(86400)); reportProblems("moving delivery late"); // 7: Restoring original delivery plan & report deliver->setQuantity(oldqty); deliver->setStart(oldstart); reportProblems("restoring original delivery plan"); // 8: Deleting delivery delete deliver; reportProblems("deleting delivery plan"); // 9: Move the make operation before current & report oldstart = build->getDates().getStart(); build->setStart(Plan::instance().getCurrent() - Duration(1)); reportProblems("moving build early"); // 10: Restoring the original build plan & report build->setStart(oldstart); reportProblems("restoring original build plan"); } catch (...) { logger << "Error: Caught an exception in main routine:" << endl; try { throw; } catch (const exception& e) {logger << " " << e.what() << endl;} catch (...) {logger << " Unknown type" << endl;} return EXIT_FAILURE; } return EXIT_SUCCESS; }