solverprocure.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #define FREPPLE_CORE
00029 #include "frepple/solver.h"
00030
00031 namespace frepple
00032 {
00033
00034
00035 double suggestQuantity(const BufferProcure* b, double f)
00036 {
00037
00038 double order_qty = f;
00039
00040
00041 if (b->getSizeMultiple()>0.0)
00042 {
00043 int mult = static_cast<int>(order_qty / b->getSizeMultiple() + 0.99999999);
00044 order_qty = mult * b->getSizeMultiple();
00045 }
00046
00047
00048 if (order_qty < b->getSizeMinimum())
00049 {
00050 order_qty = b->getSizeMinimum();
00051
00052 if (b->getSizeMultiple()>0.0)
00053 {
00054 int mult = static_cast<int>(order_qty / b->getSizeMultiple() + 0.99999999);
00055 order_qty = mult * b->getSizeMultiple();
00056 }
00057
00058 if (order_qty > b->getSizeMaximum())
00059 throw DataException("Inconsistent procurement parameters on buffer '"
00060 + b->getName() + "'");
00061 }
00062
00063
00064 if (order_qty > b->getSizeMaximum())
00065 {
00066 order_qty = b->getSizeMaximum();
00067
00068 if (b->getSizeMultiple()>0.0)
00069 {
00070 int mult = static_cast<int>(order_qty / b->getSizeMultiple());
00071 order_qty = mult * b->getSizeMultiple();
00072 }
00073
00074 if (order_qty < b->getSizeMinimum())
00075 throw DataException("Inconsistent procurement parameters on buffer '"
00076 + b->getName() + "'");
00077 }
00078
00079
00080 return order_qty;
00081 }
00082
00083
00084 DECLARE_EXPORT void SolverMRP::solve(const BufferProcure* b, void* v)
00085 {
00086 SolverMRPdata* data = static_cast<SolverMRPdata*>(v);
00087
00088
00089 if (userexit_buffer) userexit_buffer.call(b, PythonObject(data->constrainedPlanning));
00090
00091
00092 if (data->getSolver()->getLogLevel()>1)
00093 logger << indent(b->getLevel()) << " Procurement buffer '" << b->getName()
00094 << "' is asked: " << data->state->q_qty << " " << data->state->q_date << endl;
00095
00096
00097 data->state->a_date = Date::infiniteFuture;
00098
00099
00100 OperationPlan *last_operationplan = NULL;
00101 OperationPlan::iterator curProcure(b->getOperation());
00102 while (curProcure != OperationPlan::end() && curProcure->getLocked())
00103 ++curProcure;
00104 set<OperationPlan*> moved;
00105
00106
00107
00108 Date earliest_next;
00109 for (OperationPlan::iterator procs(b->getOperation());
00110 procs != OperationPlan::end(); ++procs)
00111 if (procs->getLocked())
00112 earliest_next = procs->getDates().getEnd();
00113 Date latest_next = Date::infiniteFuture;
00114
00115
00116 if (earliest_next && b->getMaximumInterval())
00117 latest_next = earliest_next + b->getMaximumInterval();
00118 if (earliest_next && b->getMinimumInterval())
00119 earliest_next += b->getMinimumInterval();
00120 if (data->constrainedPlanning)
00121 {
00122 if (data->getSolver()->isLeadtimeConstrained()
00123 && earliest_next < Plan::instance().getCurrent() + b->getLeadtime())
00124 earliest_next = Plan::instance().getCurrent() + b->getLeadtime();
00125 if (data->getSolver()->isFenceConstrained()
00126 && earliest_next < Plan::instance().getCurrent() + b->getFence())
00127 earliest_next = Plan::instance().getCurrent() + b->getFence();
00128 }
00129
00130
00131 Date current_date;
00132 double produced = 0.0;
00133 double consumed = 0.0;
00134 double current_inventory = 0.0;
00135 const FlowPlan* current_flowplan = NULL;
00136 for (Buffer::flowplanlist::const_iterator cur=b->getFlowPlans().begin();
00137 latest_next != Date::infiniteFuture || cur != b->getFlowPlans().end(); )
00138 {
00139 if (cur==b->getFlowPlans().end() || latest_next < cur->getDate())
00140 {
00141
00142 current_date = latest_next;
00143 current_flowplan = NULL;
00144 }
00145 else if (earliest_next && earliest_next < cur->getDate())
00146 {
00147
00148 current_date = earliest_next;
00149 current_flowplan = NULL;
00150 }
00151 else
00152 {
00153
00154 if (current_date && current_date >= cur->getDate())
00155 {
00156
00157
00158 cur++;
00159 continue;
00160 }
00161 current_date = cur->getDate();
00162 bool noConsumers = true;
00163 do
00164 {
00165 if (cur->getType() != 1)
00166 {
00167 cur++;
00168 continue;
00169 }
00170 current_flowplan = static_cast<const FlowPlan*>(&*(cur++));
00171 if (current_flowplan->getQuantity() < 0)
00172 {
00173 consumed -= current_flowplan->getQuantity();
00174 noConsumers = false;
00175 }
00176 else if (current_flowplan->getOperationPlan()->getLocked())
00177 produced += current_flowplan->getQuantity();
00178 }
00179
00180 while (cur != b->getFlowPlans().end() && cur->getDate() == current_date);
00181
00182 if (noConsumers) continue;
00183 }
00184
00185
00186
00187 current_inventory = produced - consumed;
00188
00189
00190 if (current_date < earliest_next)
00191 {
00192 if (current_inventory < -ROUNDING_ERROR
00193 && current_date >= data->state->q_date
00194 && b->getMinimumInterval()
00195 && data->state->a_date > earliest_next
00196 && data->getSolver()->isMaterialConstrained()
00197 && data->constrainedPlanning)
00198
00199
00200 data->state->a_date = earliest_next;
00201 continue;
00202 }
00203
00204
00205 if (current_inventory >= b->getMinimumInventory()
00206 && current_date < latest_next)
00207 {
00208 if (current_date == earliest_next) earliest_next = Date::infinitePast;
00209 continue;
00210 }
00211
00212
00213
00214 if (current_date == earliest_next
00215 && last_operationplan
00216 && current_inventory < b->getMinimumInventory())
00217 {
00218 double origqty = last_operationplan->getQuantity();
00219 last_operationplan->setQuantity(suggestQuantity(b,
00220 last_operationplan->getQuantity()
00221 + b->getMinimumInventory() - current_inventory));
00222 produced += last_operationplan->getQuantity() - origqty;
00223 current_inventory = produced - consumed;
00224 if (current_inventory < -ROUNDING_ERROR
00225 && data->state->a_date > earliest_next + b->getMinimumInterval()
00226 && earliest_next + b->getMinimumInterval() > data->state->q_date
00227 && data->getSolver()->isMaterialConstrained()
00228 && data->constrainedPlanning)
00229
00230 data->state->a_date = earliest_next + b->getMinimumInterval();
00231 }
00232
00233
00234 earliest_next = Date::infinitePast;
00235 double order_qty = suggestQuantity(b,
00236 b->getMaximumInventory() - current_inventory);
00237 if (order_qty > 0)
00238 {
00239
00240 if (curProcure == OperationPlan::end())
00241 {
00242
00243 CommandCreateOperationPlan *a =
00244 new CommandCreateOperationPlan(b->getOperation(), order_qty,
00245 Date::infinitePast, current_date, data->state->curDemand);
00246 last_operationplan = a->getOperationPlan();
00247 last_operationplan->insertInOperationplanList();
00248 produced += last_operationplan->getQuantity();
00249 data->add(a);
00250 }
00251 else if (curProcure->getDates().getEnd() == current_date
00252 && curProcure->getQuantity() == order_qty)
00253 {
00254
00255 produced += order_qty;
00256 last_operationplan = &*curProcure;
00257 moved.insert(last_operationplan);
00258 do
00259 ++curProcure;
00260 while (curProcure != OperationPlan::end()
00261 && curProcure->getLocked() && moved.find(&*curProcure)!=moved.end());
00262 }
00263 else
00264 {
00265
00266 CommandMoveOperationPlan *a =
00267 new CommandMoveOperationPlan(&*curProcure, Date::infinitePast, current_date, order_qty);
00268 last_operationplan = a->getOperationPlan();
00269 moved.insert(last_operationplan);
00270 data->add(a);
00271 produced += last_operationplan->getQuantity();
00272 do
00273 ++curProcure;
00274 while (curProcure != OperationPlan::end()
00275 && curProcure->getLocked() && moved.find(&*curProcure)!=moved.end());
00276 }
00277 if (b->getMinimumInterval())
00278 earliest_next = current_date + b->getMinimumInterval();
00279 }
00280 if (b->getMaximumInterval())
00281 {
00282 current_inventory = produced - consumed;
00283 if (current_inventory >= b->getMaximumInventory()
00284 && cur == b->getFlowPlans().end())
00285
00286
00287 latest_next = Date::infiniteFuture;
00288 else
00289 latest_next = current_date + b->getMaximumInterval();
00290 }
00291 }
00292
00293
00294 while (curProcure != OperationPlan::end())
00295 {
00296 OperationPlan *opplan = &*(curProcure++);
00297 if (!opplan->getLocked() && moved.find(opplan)!=moved.end())
00298 data->add(new CommandDeleteOperationPlan(opplan));
00299 }
00300
00301
00302 if (data->constrainedPlanning && (data->getSolver()->isFenceConstrained()
00303 || data->getSolver()->isLeadtimeConstrained()
00304 || data->getSolver()->isMaterialConstrained()))
00305 {
00306
00307 double shortage = 0;
00308 for (Buffer::flowplanlist::const_iterator cur=b->getFlowPlans().begin();
00309 cur != b->getFlowPlans().end(); ++cur)
00310 if (cur->getDate() >= data->state->q_date
00311 && cur->getOnhand() < -ROUNDING_ERROR
00312 && cur->getOnhand() < shortage)
00313 {
00314 shortage = cur->getOnhand();
00315 if (-shortage >= data->state->q_qty) break;
00316 }
00317 if (shortage < 0)
00318 {
00319
00320 data->state->a_qty = data->state->q_qty + shortage;
00321
00322 if (data->state->a_qty < 0) data->state->a_qty = 0;
00323
00324 if (data->constrainedPlanning)
00325 {
00326 if (data->getSolver()->isFenceConstrained()
00327 && data->state->q_date < Plan::instance().getCurrent() + b->getFence()
00328 && data->state->a_date > Plan::instance().getCurrent() + b->getFence())
00329 data->state->a_date = Plan::instance().getCurrent() + b->getFence();
00330 if (data->getSolver()->isLeadtimeConstrained()
00331 && data->state->q_date < Plan::instance().getCurrent() + b->getLeadtime()
00332 && data->state->a_date > Plan::instance().getCurrent() + b->getLeadtime())
00333 data->state->a_date = Plan::instance().getCurrent() + b->getLeadtime();
00334 }
00335 }
00336 else
00337
00338 data->state->a_qty = data->state->q_qty;
00339 }
00340 else
00341
00342 data->state->a_qty = data->state->q_qty;
00343
00344
00345 if (b->getItem() && data->state->a_qty > 0.0)
00346 data->state->a_cost += data->state->a_qty * b->getItem()->getPrice();
00347
00348
00349 if (data->getSolver()->getLogLevel()>1)
00350 logger << indent(b->getLevel()) << " Procurement buffer '" << b
00351 << "' answers: " << data->state->a_qty << " " << data->state->a_date
00352 << " " << data->state->a_cost << " " << data->state->a_penalty << endl;
00353 }
00354
00355
00356 }