void OperationItemSupplier::trimExcess(bool zero_or_minimum) const { // This method can only trim operations not loading a resource if (getLoads().begin() != getLoads().end()) return; for (Operation::flowlist::const_iterator fliter = getFlows().begin(); fliter != getFlows().end(); ++fliter) { if (fliter->getQuantity() <= 0) // Strange, shouldn't really happen continue; FlowPlan* candidate = nullptr; double curmin = 0; double oh = 0; double excess_min = DBL_MAX; for (Buffer::flowplanlist::const_iterator flplniter = fliter->getBuffer()->getFlowPlans().begin(); flplniter != fliter->getBuffer()->getFlowPlans().end(); ++flplniter) { // For any operationplan we get the onhand when its successor // replenishment arrives. If that onhand is higher than the minimum // onhand value we can resize it. // This is only valid in unconstrained plans and when there are // no upstream activities. if (flplniter->getEventType() == 3 && zero_or_minimum) curmin = flplniter->getMin(); else if (flplniter->getEventType() == 1) { const FlowPlan* flpln = static_cast<const FlowPlan*>(&*flplniter); if (oh - curmin < excess_min) { excess_min = oh - curmin; if (excess_min < 0) excess_min = 0; } if (flpln->getQuantity() > 0 && !flpln->getOperationPlan()->getLocked() && (!candidate || candidate->getDate() != flpln->getDate())) { if (candidate && excess_min > ROUNDING_ERROR && candidate->getQuantity() > excess_min + ROUNDING_ERROR && candidate->getQuantity() > getSizeMinimum() + ROUNDING_ERROR ) { // This candidate can now be resized candidate->setQuantity(candidate->getQuantity() - excess_min, false); candidate = nullptr; } else if (flpln->getOperation() == this) candidate = const_cast<FlowPlan*>(flpln); else candidate = nullptr; excess_min = DBL_MAX; } } oh = flplniter->getOnhand(); } if (candidate && excess_min > ROUNDING_ERROR && candidate->getQuantity() > excess_min + ROUNDING_ERROR && candidate->getQuantity() > getSizeMinimum() + ROUNDING_ERROR ) // Resize the last candidate at the end of the horizon candidate->setQuantity(candidate->getQuantity() - excess_min, false); } }
void OperatorDelete::solve(const Buffer* b, void* v) { if (getLogLevel()>1) logger << "Scanning " << b << " for excess" << endl; Buffer::flowplanlist::const_iterator fiter = b->getFlowPlans().rbegin(); Buffer::flowplanlist::const_iterator fend = b->getFlowPlans().end(); if (fiter == fend) return; // There isn't a single flowplan in the buffer double excess = fiter->getOnhand() - fiter->getMin(); // Find the earliest occurence of the excess fiter = b->getFlowPlans().begin(); while (excess > ROUNDING_ERROR && fiter != fend) { if (fiter->getQuantity() <= 0) { // Not a producer ++fiter; continue; } FlowPlan* fp = nullptr; if (fiter->getEventType() == 1) fp = const_cast<FlowPlan*>(static_cast<const FlowPlan*>(&*fiter)); double cur_excess = b->getFlowPlans().getExcess(&*fiter); if (!fp || fp->getOperationPlan()->getLocked() || cur_excess < ROUNDING_ERROR) { // No excess producer, or it's locked ++fiter; continue; } assert(fp); // Increment the iterator here, because it can get invalidated later on while ( fiter != fend && fiter->getEventType() == 1 && static_cast<const FlowPlan*>(&*fiter)->getOperationPlan()->getTopOwner()==fp->getOperationPlan()->getTopOwner() ) ++fiter; if (cur_excess >= fp->getQuantity() - ROUNDING_ERROR) { // The complete operationplan is excess. // Reduce the excess excess -= fp->getQuantity(); // Add upstream buffers to the stack pushBuffers(fp->getOperationPlan(), true); // Log message if (getLogLevel()>0) logger << "Removing excess operationplan: '" << fp->getOperationPlan()->getOperation() << "' " << fp->getOperationPlan()->getDates() << " " << fp->getOperationPlan()->getQuantity() << endl; // Delete operationplan if (cmds) cmds->add(new CommandDeleteOperationPlan(fp->getOperationPlan())); else delete fp->getOperationPlan(); } else { // Reduce the operationplan double newsize = fp->setQuantity(fp->getQuantity() - cur_excess, false, false); if (newsize == fp->getQuantity()) // No resizing is feasible continue; // Add upstream buffers to the stack pushBuffers(fp->getOperationPlan(), true); // Reduce the excess excess -= fp->getQuantity() - newsize; if (getLogLevel()>0) logger << "Resizing excess operationplan to " << newsize << ": '" << fp->getOperationPlan()->getOperation() << "' " << fp->getOperationPlan()->getDates() << " " << fp->getOperationPlan()->getQuantity() << endl; // Resize operationplan if (cmds) cmds->add(new CommandMoveOperationPlan( fp->getOperationPlan(), Date::infinitePast, fp->getOperationPlan()->getDates().getEnd(), newsize) ); else fp->getOperationPlan()->setQuantity(newsize); } } }