Example #1
0
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);
  }
}
Example #2
0
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);
        }
    }
}