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();
}
Example #2
0
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);
}
Example #3
0
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);
}
Example #4
0
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);
}
Example #5
0
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);
}
Example #6
0
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);
}