14 public IReadOnlyList<SolutionCheckIssue>
Validate(
15 LotSizingInstance instance,
16 LotSizingSolution solution)
18 ArgumentNullException.ThrowIfNull(instance);
19 ArgumentNullException.ThrowIfNull(solution);
20 var issues =
new List<SolutionCheckIssue>();
22 var expected = instance.SupplyChain.Plants
23 .SelectMany(plant => plant.WorkCenters
24 .Where(workCenter => workCenter.SchedulingProfile?.BucketMode == SchedulingBucketMode.MacroMicro)
25 .Select(workCenter => (PlantId: plant.Id, WorkCenter: workCenter)))
28 foreach (var entry
in expected)
30 WorkCenterSchedulingDecision? schedule =
31 solution.WorkCenterSchedulingDecisions.SingleOrDefault(candidate =>
32 candidate.WorkCenter.PlantId == entry.PlantId &&
33 candidate.WorkCenter.WorkCenterId == entry.WorkCenter.Id);
38 $
"DECSCHED005: Missing macro/micro schedule for Plant:{entry.PlantId}/WorkCenter:{entry.WorkCenter.Id}."));
42 ProductionSchedulingProfile profile = entry.WorkCenter.SchedulingProfile!;
43 foreach (ProductionMicroPeriodReference microPeriod
in profile.EnumerateMicroPeriods())
45 if (!schedule.MicroPeriods.Any(decision =>
46 decision.MicroPeriod.RefersToSameMicroPeriod(microPeriod)))
49 $
"DECSCHED006: Missing decision for micro-period {microPeriod} on {schedule.WorkCenter}."));
54 foreach (WorkCenterSchedulingDecision schedule
in solution.WorkCenterSchedulingDecisions)
56 WorkCenter? workCenter = instance.SupplyChain.Plants
57 .Where(plant => plant.Id == schedule.WorkCenter.PlantId)
58 .SelectMany(plant => plant.WorkCenters)
59 .SingleOrDefault(candidate => candidate.Id == schedule.WorkCenter.WorkCenterId);
61 if (workCenter is
null)
63 issues.Add(Error($
"REFSCHED001: Unknown scheduling work center {schedule.WorkCenter}."));
67 ProductionSchedulingProfile? profile = workCenter.SchedulingProfile;
68 if (profile is
null ||
69 profile.BucketMode != SchedulingBucketMode.MacroMicro ||
70 profile.MicroPeriodCount is
null)
73 $
"DECSCHED001: Work center {schedule.WorkCenter} does not expose an explicit macro/micro scheduling grid."));
77 foreach (ProductionMicroPeriodDecision decision
in schedule.MicroPeriods)
79 int macro = decision.MicroPeriod.MacroPeriod;
80 int micro = decision.MicroPeriod.MicroPeriodIndex;
82 if (macro <= 0 || macro > instance.PlanningHorizon ||
83 micro <= 0 || micro > profile.MicroPeriodCount.GetCount(macro))
86 $
"DECSCHED002: Micro-period {decision.MicroPeriod} is outside the instance scheduling grid."));
90 if (decision.SetupItemId <= 0 ||
91 !instance.SupplyChain.Items.Any(item => item.Id == decision.SetupItemId))
94 $
"REFSCHED002: Unknown or missing setup item {decision.SetupItemId} at {decision.MicroPeriod}."));
97 if (decision.RoutingId <= 0)
99 if (decision.Quantity > 0.0)
102 $
"DECSCHED007: Positive production at {decision.MicroPeriod} has no routing."));
107 ProductionRouting? routing = instance.SupplyChain.ProductionRoutings
108 .SingleOrDefault(candidate => candidate.Id == decision.RoutingId);
113 $
"REFSCHED003: Unknown production routing {decision.RoutingId} at {decision.MicroPeriod}."));
117 if (routing.ItemId != decision.SetupItemId)
120 $
"DECSCHED003: Routing {routing.Id} produces item {routing.ItemId}, not setup item {decision.SetupItemId}."));
123 if (!routing.WorkCenters.Any(reference =>
124 reference.RefersToSameWorkCenter(schedule.WorkCenter)))
127 $
"DECSCHED004: Routing {routing.Id} does not use work center {schedule.WorkCenter}."));