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 #define FREPPLE_CORE
00028 #include "frepple/solver.h"
00029
00030 namespace frepple
00031 {
00032
00033
00034 void SolverMRP::solve(const Load* l, void* v)
00035 {
00036 SolverMRPdata* data = static_cast<SolverMRPdata*>(v);
00037 if (data->state->q_qty >= 0.0)
00038 {
00039
00040
00041
00042 data->state->a_qty = data->state->q_qty;
00043 data->state->a_date = data->state->q_date;
00044 }
00045 else
00046
00047 l->getResource()->solve(*this,v);
00048 }
00049
00050
00051
00052 DECLARE_EXPORT void SolverMRP::solve(const Resource* res, void* v)
00053 {
00054 SolverMRPdata* data = static_cast<SolverMRPdata*>(v);
00055
00056
00057 if (data->getSolver()->getLogLevel()>1)
00058 logger << indent(res->getLevel()) << " Resource '" << res->getName()
00059 << "' is asked: " << (-data->state->q_qty) << " "
00060 << data->state->q_operationplan->getDates() << endl;
00061
00062
00063 double orig_q_qty = -data->state->q_qty;
00064 Date currentOpplanEnd = data->state->q_operationplan->getDates().getEnd();
00065 double currentQuantity = data->state->q_operationplan->getQuantity();
00066 Resource::loadplanlist::const_iterator cur = res->getLoadPlans().end();
00067 Date curdate;
00068 double curMax, prevMax;
00069 bool HasOverload;
00070
00071
00072 data->state->a_date = data->state->q_date;
00073 data->state->a_qty = orig_q_qty;
00074
00075
00076 if (!data->state->forceLate)
00077 do
00078 {
00079
00080 HasOverload = false;
00081 Date earliestdate = data->state->q_operationplan->getDates().getStart();
00082 curdate = data->state->q_loadplan->getDate();
00083 curMax = data->state->q_loadplan->getMax(false);
00084 prevMax = curMax;
00085 for (cur = res->getLoadPlans().begin(data->state->q_loadplan);
00086 cur!=res->getLoadPlans().end() && cur->getDate()>=earliestdate;
00087 --cur)
00088 {
00089
00090 prevMax = curMax;
00091 if (cur->getType() == 4)
00092 curMax = cur->getMax(false);
00093
00094
00095 if (cur->getDate() == curdate) continue;
00096 if (cur->getOnhand() > prevMax + ROUNDING_ERROR)
00097 {
00098
00099
00100
00101
00102
00103 HasOverload = true;
00104 break;
00105 }
00106 curdate = cur->getDate();
00107 }
00108
00109
00110
00111
00112
00113 if (HasOverload && curdate < data->state->q_loadplan->getDate())
00114 {
00115 Date currentEnd = data->state->q_operationplan->getDates().getEnd();
00116 data->state->q_operationplan->getOperation()->setOperationPlanParameters(
00117 data->state->q_operationplan,
00118 currentQuantity,
00119 curdate,
00120 currentEnd
00121 );
00122 if (data->state->q_operationplan->getQuantity() > 0
00123 && data->state->q_operationplan->getDates().getEnd() <= currentEnd
00124 && data->state->q_operationplan->getDates().getStart() >= curdate)
00125 {
00126
00127
00128
00129
00130 HasOverload = false;
00131 }
00132 else
00133 {
00134
00135
00136
00137
00138
00139 data->state->q_operationplan->getOperation()->setOperationPlanParameters(
00140 data->state->q_operationplan,
00141 currentQuantity,
00142 Date::infinitePast,
00143 currentEnd
00144 );
00145 }
00146 }
00147
00148
00149 if (HasOverload)
00150 {
00151
00152 curMax = cur->getMax(false);
00153 prevMax = curMax;
00154 curdate = cur->getDate();
00155 for (; cur!=res->getLoadPlans().end(); --cur)
00156 {
00157
00158 prevMax = curMax;
00159 if (cur->getType() == 4)
00160 curMax = cur->getMax(false);
00161
00162
00163 if (cur->getDate() == curdate) continue;
00164
00165
00166 if (cur->getOnhand() < prevMax + ROUNDING_ERROR) break;
00167 curdate = cur->getDate();
00168 }
00169
00170
00171
00172
00173
00174 if (cur != res->getLoadPlans().end())
00175 {
00176
00177 data->state->q_operationplan->setEnd(curdate);
00178
00179
00180 if (isLeadtimeConstrained() || isFenceConstrained())
00181
00182
00183 checkOperationLeadtime(data->state->q_operationplan,*data,false);
00184 }
00185 else
00186
00187 data->state->a_qty = 0.0;
00188 }
00189 }
00190 while (HasOverload && data->state->a_qty!=0.0);
00191
00192
00193
00194
00195
00196
00197 if (data->state->a_qty == 0.0 || data->state->forceLate)
00198 {
00199
00200 if (!data->state->forceLate)
00201 {
00202 data->state->q_operationplan->setQuantity(currentQuantity);
00203 data->state->q_operationplan->setEnd(currentOpplanEnd);
00204 }
00205
00206
00207
00208 data->state->q_loadplan = data->state->q_loadplan->getOtherLoadPlan();
00209
00210
00211 Date newDate;
00212 do
00213 {
00214
00215
00216 HasOverload = false;
00217 newDate = Date::infinitePast;
00218 curMax = data->state->q_loadplan->getMax();
00219 double curOnhand = data->state->q_loadplan->getOnhand();
00220 for (cur=res->getLoadPlans().begin(data->state->q_loadplan);
00221 !(HasOverload && newDate) && cur != res->getLoadPlans().end(); )
00222 {
00223
00224 if (cur->getType() == 4)
00225 curMax = cur->getMax();
00226
00227
00228 const TimeLine<LoadPlan>::Event *loadpl = &*(cur++);
00229 if (cur!=res->getLoadPlans().end() && cur->getDate()==loadpl->getDate())
00230 continue;
00231 curOnhand = loadpl->getOnhand();
00232
00233
00234 if (loadpl->getOnhand() > curMax + ROUNDING_ERROR)
00235
00236 HasOverload = true;
00237 else if (!HasOverload && loadpl->getDate() > data->state->q_operationplan->getDates().getEnd())
00238
00239
00240 break;
00241 else if (!newDate && loadpl->getDate()!=data->state->q_loadplan->getDate())
00242 {
00243
00244
00245 newDate = loadpl->getDate();
00246
00247 }
00248 }
00249
00250
00251 if (HasOverload && newDate)
00252 {
00253
00254 int parallelOps = static_cast<int>((curMax - curOnhand) / data->state->q_loadplan->getQuantity());
00255 if (parallelOps <= 0) parallelOps = 1;
00256
00257 data->state->q_operationplan->getOperation()->setOperationPlanParameters(
00258 data->state->q_operationplan,
00259 currentQuantity / parallelOps,
00260 newDate,
00261 Date::infinitePast
00262 );
00263 HasOverload = true;
00264 }
00265 }
00266 while (HasOverload && newDate);
00267
00268
00269 if (HasOverload)
00270
00271 data->state->a_date = Date::infiniteFuture;
00272 else
00273 data->state->a_date = data->state->q_operationplan->getDates().getEnd();
00274
00275
00276 data->state->a_qty = 0.0;
00277 }
00278
00279 if (data->state->a_qty == 0.0
00280 && data->state->q_operationplan->getQuantity() != 0.0)
00281
00282
00283
00284 data->state->q_operationplan->setQuantity(0.0);
00285
00286
00287 if (data->state->a_qty > 0.0)
00288 data->state->a_cost += data->state->a_qty * res->getCost()
00289 * data->state->q_operationplan->getDates().getDuration();
00290
00291
00292 if (data->getSolver()->getLogLevel()>1)
00293 {
00294 logger << indent(res->getLevel()) << " Resource '" << res << "' answers: "
00295 << data->state->a_qty << " " << data->state->a_date;
00296 if (currentOpplanEnd > data->state->q_operationplan->getDates().getEnd())
00297 logger << " using earlier capacity "
00298 << data->state->q_operationplan->getDates().getEnd();
00299 if (data->state->a_qty>0.0 && data->state->q_operationplan->getQuantity() < currentQuantity)
00300 logger << " with reduced quantity " << data->state->q_operationplan->getQuantity();
00301 logger << endl;
00302 }
00303
00304 }
00305
00306
00307 DECLARE_EXPORT void SolverMRP::solve(const ResourceInfinite* res, void* v)
00308 {
00309 SolverMRPdata* data = static_cast<SolverMRPdata*>(v);
00310
00311
00312 if (data->getSolver()->getLogLevel()>1 && data->state->q_qty < 0)
00313 logger << indent(res->getLevel()) << " Resource '" << res << "' is asked: "
00314 << (-data->state->q_qty) << " " << data->state->q_operationplan->getDates() << endl;
00315
00316
00317 data->state->a_qty = data->state->q_qty;
00318 data->state->a_date = data->state->q_date;
00319 data->state->a_cost += data->state->a_qty * res->getCost()
00320 * data->state->q_operationplan->getDates().getDuration();
00321
00322
00323 if (data->getSolver()->getLogLevel()>1 && data->state->q_qty < 0)
00324 logger << indent(res->getLevel()) << " Resource '" << res << "' answers: "
00325 << (-data->state->a_qty) << " " << data->state->a_date << endl;
00326 }
00327
00328
00329 }