Commit 31d2cb46 authored by Tong Li's avatar Tong Li

bom

parent b1b2a85e
......@@ -42,7 +42,7 @@ public class GlobalParam {
/// <summary>
/// 是否全局倒排
/// </summary>
private boolean isJit = true;
private boolean isJit = false;
private boolean _smoothSetup = false; // 设置时间平滑 工序的前处理是否提前
......
......@@ -61,13 +61,15 @@ public class GeneticDecoder {
private GlobalParam _globalParam;
private MachineCalculator machineCalculator;
private GeneticDecoderBom bom;
private MaterialRequirementService materialRequirementService;
private DiscreteParameterMatrixService discreteParameterMatrixService;
private String sceneId;
private boolean rebuildStructureForCurrentDecode = false;
private boolean rebuildStructureForCurrentDecode = true;
......@@ -82,6 +84,8 @@ public class GeneticDecoder {
_globalParam=globalParam;
machineCalculator=new MachineCalculator(baseTime,machines,machineScheduler);
materialRequirementService=_materialRequirementService;
bom=new GeneticDecoderBom(this.baseTime,machineCalculator,materialRequirementService);
sceneId=_sceneId;
// this.orderMaxID = orders.stream().mapToInt(Order::getId).max().orElse(0);
}
......@@ -493,24 +497,52 @@ public class GeneticDecoder {
// 步骤2:按OperationSequencing顺序调度工序
Map<Integer, Integer> orderProcessCounter = new HashMap<>();
Map<Integer, Integer> orderLastEndTime = new HashMap<>();
Map<Integer, Integer> orderDueDate = new HashMap<>();
Map<Integer, Entry> entryIndexById = new HashMap<>();
Map<Integer, List<Entry>> entrysBygroupId = new HashMap<>();
//工序对应的排产结果
Map<Integer, GAScheduleResult> scheduleIndexById = new ConcurrentHashMap<>();
for (Order order : chromosome.getOrders()) {
int end = (int) ChronoUnit.SECONDS.between(baseTime, order.getDueDate());
orderDueDate.putIfAbsent(order.getId(), end);
}
Map<Integer, Entry> entryIndexById = new HashMap<>();
Map<Integer, List<Entry>> entrysBygroupId = new HashMap<>();
for (Entry op : allOperations) {
int groupId = op.getGroupId();
orderProcessCounter.putIfAbsent(groupId, 0);
orderLastEndTime.putIfAbsent(groupId, 0);
//工序
entryIndexById.put(op.getId(),op);
//订单下全部工序
entrysBygroupId.computeIfAbsent(groupId, k -> new ArrayList<>()).add(op);
//scheduleIndexById.put(op.getId(),null);
}
Map<Integer, Integer> orderDueDate = new HashMap<>();
Map<Integer, AbstractMap.SimpleEntry<Boolean, Integer>> orderSchedulingInfo = new HashMap<>();
for (Order order : chromosome.getOrders()) {
int end = (int) ChronoUnit.SECONDS.between(baseTime, order.getDueDate());
orderDueDate.putIfAbsent(order.getId(), end);
//存储锚点时间
if(isJit)
{
orderSchedulingInfo.put(order.getId(), new AbstractMap.SimpleEntry<>(false, end));
}else {
orderSchedulingInfo.put(order.getId(), new AbstractMap.SimpleEntry<>(false, 0));
}
}
for (Map.Entry<Integer, List<Entry>> entry : entrysBygroupId.entrySet()) {
int groupId = entry.getKey();
Entry firstOp = entry.getValue().get(0);
if (Entry.SchedulingMode.BACKWARD.name().equals(
firstOp.getSchedulingMode())) {
orderSchedulingInfo.put(groupId,
new AbstractMap.SimpleEntry<>(true, 0));
}
}
// Map<Long, String> machineState = chromosome.getMachines().stream()
// .collect(Collectors.toMap(Machine::getId, m -> ""));
......@@ -528,17 +560,39 @@ public class GeneticDecoder {
boolean orderIsJit=orderDueDate.get(groupId)>0;
if(isJit&&orderIsJit)
AbstractMap.SimpleEntry<Boolean, Integer> schedInfo = orderSchedulingInfo.get(groupId);
orderIsJit = schedInfo != null && schedInfo.getKey();
int orderAnchor = schedInfo != null ? schedInfo.getValue() : 0;
// 半成品订单首次处理时,延迟计算锚点:沿依赖链找到根成品工序并正推
if (orderIsJit && orderAnchor == 0) {
orderAnchor =bom.computeSemiFinishedAnchor(groupId, entrysBygroupId,
opMachineKeyMap, chromosome,
scheduleIndexById, machineTasksCache);
if(orderAnchor<0) {
orderIsJit=false;
orderSchedulingInfo.put(groupId,
new AbstractMap.SimpleEntry<>(false, -1));
}else {
orderSchedulingInfo.put(groupId,
new AbstractMap.SimpleEntry<>(true, orderAnchor));
}
}
if(orderIsJit)
{
orderOps = entrysBygroupId.get(groupId).stream()
.sorted(Comparator.comparing(Entry::getSequence).reversed())
.collect(Collectors.toList());
orderIsJit=true;
}else {
orderOps = entrysBygroupId.get(groupId).stream()
.sorted(Comparator.comparing(Entry::getSequence))
.collect(Collectors.toList());
orderIsJit=false;
}
......@@ -570,7 +624,13 @@ public class GeneticDecoder {
long opStart = System.nanoTime();
int actualEndTime = processOperation(currentOp,machineId,processTime,machineOption,chromosome,machineIdMap,machineTasksCache,entryIndexById,scheduleIndexById,(int)orderDueDate.get(groupId),orderIsJit);
boolean opIsJit = orderIsJit
||( Entry.SchedulingMode.BACKWARD.name().equals(
currentOp.getSchedulingMode())&&orderAnchor>=0);
int dueDateForOp = opIsJit ? orderAnchor
: (schedInfo != null ? schedInfo.getValue() : 0);
int actualEndTime = processOperation(currentOp,machineId,processTime,machineOption,chromosome,machineIdMap,machineTasksCache,entryIndexById,scheduleIndexById,dueDateForOp,opIsJit);
long opElapsed = System.nanoTime() - opStart;
opCount++;
......@@ -1129,7 +1189,12 @@ public class GeneticDecoder {
{
int endTime=0;
int startTime=0;
processingTimeTotal=(int)Math.ceil (processingTime);
if(operation.getQuantity()==0)
{
processingTimeTotal=0;
}else {
processingTimeTotal = (int) Math.ceil(processingTime);
}
if(isJit)
{
endTime=earliestStartTime;
......@@ -1148,159 +1213,34 @@ public class GeneticDecoder {
return endTime;
}
// baseEarliestStartTime:不考虑 BOM 推迟时的理论最早开工时间。
// candidateStartTime:固定点迭代时本轮尝试的开工时间。
// bomtime:按当前候选开工时间试算出来的物料最早可开工时间。
int baseEarliestStartTime = earliestStartTime;
int candidateStartTime = earliestStartTime;
if (operation.getTargetFinishedOperationId() != null &&
!operation.getTargetFinishedOperationId().isEmpty()) {
// 1. 计算成品可用时间
GeneticDecoderBom bom=new GeneticDecoderBom();
int finishedAvailableTime = bom.calculateFinishedAvailableTime(
operation, chromosome, baseTime, machineTasksCache, entryIndexById, scheduleIndexById);
if (finishedAvailableTime > 0) {
// 2. 计算半成品最晚开工时间(倒排:半成品结束时间 = 成品可用时间,然后往前推加工时间)
// 加上JIT缓冲时间(如果有)
int semiBufferMinutes = _globalParam.getSemiJitBufferMinutes();
int semiBufferSeconds = semiBufferMinutes * 60;
// 半成品最晚结束时间 = 成品可用时间 - 缓冲
int semiLatestEndTime = Math.max(0, finishedAvailableTime - semiBufferSeconds);
// 半成品最晚开工时间 = 半成品最晚结束时间 - 加工总时长
int semiLatestStartTime = Math.max(0, semiLatestEndTime - processingTimeTotal);
// 3. 计算半成品物料的BOM齐套时间(正向)
int semiBomTime = getOperationBOMTime(operation, chromosome);
// 4. 比较:如果倒排的开工时间早于基准时间或BOM齐套时间,则从基准时间或BOM齐套时间开始正排
int semiForwardStartTime = Math.max(baseEarliestStartTime, semiBomTime);
if (semiLatestStartTime >= semiForwardStartTime) {
// 倒排可行:使用倒排的最晚开工时间
candidateStartTime = semiLatestStartTime;
} else {
// 倒排不可行:使用正排的最早开工时间
candidateStartTime = semiForwardStartTime;
}
// 更新基准最早开工时间
baseEarliestStartTime = candidateStartTime;
}
}
int setupTime=0;
long machineId = machine.getId();
// 只有存在物料约束(或本次被强制要求重算 BOM)的工序,才需要联立求解“机台何时能排”和“物料何时可用”。
// targetFinishedOperationId != null 的工序通常由前置成品工序驱动,这里不再额外触发一轮 BOM 试算。
boolean needMaterialCheck =false;//(operation.getMaterialRequirements()!=null&&operation.getMaterialRequirements().size()>0&&operation.getTargetFinishedOperationId()==null)||calbom;
// 正式落排后还要再做一次带提交的物料校验,把试算阶段推导出的 BOM 状态真正写回 chromosome。
boolean commitMaterialCheck = needMaterialCheck;
// baseEarliestStartTime:不考虑 BOM 推迟时的理论最早开工时间。
// candidateStartTime:固定点迭代时本轮尝试的开工时间。
// bomtime:按当前候选开工时间试算出来的物料最早可开工时间。
baseEarliestStartTime = earliestStartTime;
candidateStartTime = earliestStartTime;
int bomtime=0;
// 机台时间和物料时间可能会互相推动,最多迭代 maxSolveIterations 次来找收敛点。
int maxSolveIterations = Math.max(1, _globalParam.getMaterialSolveMaxIterations());
boolean converged = !needMaterialCheck;
Entry scheduledOperation = operation;
Machine scheduledMachine = machine;
boolean needMaterialCheck =(operation.getMaterialRequirements()!=null&&operation.getMaterialRequirements().size()>0&&operation.getTargetFinishedOperationId()==null)||calbom;
CopyOnWriteArrayList<GAScheduleResult> machineTasks = getMachineTasks(machineId, chromosome, machineTasksCache);
GAScheduleResult lastGeneOnMachine = getLastMachineTask(machineTasks);
MachineSchedulePreview machinePreview = null;
CopyOnWriteArrayList<ScheduleResultDetail> geneDetails=new CopyOnWriteArrayList<>();
// 固定点求解过程:
// 1. 先按 candidateStartTime 试排机台;
// 2. 再按试排结果试算物料/BOM 的最早可开工时间;
// 3. 如果物料时间继续把开工点往后推,就用新时间再次试排,直到收敛。
int bomtime=0;
if(needMaterialCheck) {
for (int iteration = 0; iteration < maxSolveIterations; iteration++) {
// trial BOM 试算会在内部恢复快照,因此每轮都重新从最新 chromosome 中取对象,避免拿到旧引用。
Entry refreshedOperation = entryIndexById.get(operationId);
if (refreshedOperation != null) {
scheduledOperation = refreshedOperation;
}
Machine refreshedMachine = getMachineById(chromosome, machineId);
if (refreshedMachine != null) {
scheduledMachine = refreshedMachine;
}
machineTasks = getMachineTasks(machineId, chromosome, machineTasksCache);
lastGeneOnMachine = getLastMachineTask(machineTasks);
if(lastGeneOnMachine!=null&&_globalParam.is_smoothChangeOver())
{
candidateStartTime = Math.max(candidateStartTime,lastGeneOnMachine.getEndTime());
}
// 先在机台侧做一次”试排”,geneDetails 中会记录本轮临时占用的机台时间段。
long iterStart = System.nanoTime();
long previewStart = System.nanoTime();
machinePreview = buildMachinePreview(scheduledOperation, scheduledMachine, processingTime, processingTimeTotal,
candidateStartTime, lastGeneOnMachine, machineTasks, chromosome);
long previewTime = System.nanoTime() - previewStart;
long bomTimeStart = System.nanoTime();
try {
// 物料侧只做试算,不提交最终状态;本轮只关心 BOM 约束会把开工时间推迟到哪里。
bomtime = EditOperationBOMTime(scheduledOperation,chromosome,machinePreview.getStartTime(),machineTasksCache, entryIndexById, scheduleIndexById, false);
} finally {
// buildMachinePreview 会临时锁住机台 availability,这里无论成功或异常都必须释放,
// 否则下一轮迭代会被本轮的试排残留状态污染。
Machine liveMachineAfterTrial = getMachineById(chromosome, machineId);
if (liveMachineAfterTrial != null) {
AddMachineAvailable(liveMachineAfterTrial, machinePreview.getGeneDetails());
} else {
AddMachineAvailable(scheduledMachine, machinePreview.getGeneDetails());
}
}
// long bomTimeElapsed = System.nanoTime() - bomTimeStart;
// long iterElapsed = System.nanoTime() - iterStart;
// if (iterElapsed > 200_000_000L) { // 200ms
// FileHelper.writeLogFile("[PERF] processWithSingleMachine 固定点迭代慢 opId=" + operationId
// + ", iter=" + iteration + ", preview=" + fmtMs(previewTime)
// + ", BOM=" + fmtMs(bomTimeElapsed) + ", total=" + fmtMs(iterElapsed));
// }
// 下一轮候选开工时间取“基准最早开工”和“物料最早可开工”两者中的较晚值。
int nextCandidateStartTime = Math.max(baseEarliestStartTime, bomtime);
// 如果物料时间已经不再把机台试排结果往后推,说明机台时间与物料时间达成一致。
if (nextCandidateStartTime <= machinePreview.getStartTime()) {
converged = true;
candidateStartTime = nextCandidateStartTime;
break;
}
candidateStartTime = nextCandidateStartTime;
}
// 固定点求解结束后,用收敛得到的候选开工时间作为正式排产的最早开工时间。
earliestStartTime = candidateStartTime;
Entry refreshedOperation = entryIndexById.get(operationId);
if (refreshedOperation != null) {
scheduledOperation = refreshedOperation;
operation = refreshedOperation;
}
Machine refreshedMachine = getMachineById(chromosome, machineId);
if (refreshedMachine != null) {
scheduledMachine = refreshedMachine;
machine = refreshedMachine;
}
machineTasks = getMachineTasks(machineId, chromosome, machineTasksCache);
lastGeneOnMachine = getLastMachineTask(machineTasks);
needMaterialCheck = false;
bomtime = getOperationBOMTime(operation, chromosome, 2);
earliestStartTime=Math.max(earliestStartTime,bomtime);
}
// 正式落排前,再取一次当前机台最后一道工序,保证换型计算基于最新排程结果。
if(machineTasks!=null&&machineTasks.size()>0&&_globalParam.is_smoothChangeOver())
{
lastGeneOnMachine=machineTasks.get(machineTasks.size()-1);
}
CopyOnWriteArrayList<ScheduleResultDetail> geneDetails=new CopyOnWriteArrayList<>();
// 下面开始生成正式的 geneDetails。
// 与 buildMachinePreview 的区别是:这里得到的结果会继续向下写入 GAScheduleResult,成为真正排程结果。
//if (_globalParam.is_smoothChangeOver()) {
if (false) {
if (_globalParam.is_smoothChangeOver()) {
//是否考虑换型时间
Map<Integer,Object> reslte = calculateSetupTime(lastGeneOnMachine, operation, machine,earliestStartTime,processingTimeTotal, _globalParam.is_smoothChangeOverInWeek(),chromosome.getAllOperations());
setupTime=(int)reslte.get(1);//换型时间
......@@ -1317,7 +1257,7 @@ public class GeneticDecoder {
CopyOnWriteArrayList<TimeSegment> AvailableTimeSegment = (CopyOnWriteArrayList<TimeSegment>) reslte.get(6);
Map<Integer,Object> result = machineCalculator.CreateScheduleResult(machine, operation, processingTimeTotal, earliestStartTime,
AvailableTimeSegment, processingTime, operation.getQuantity(), operation.getIsInterrupt() != 1, setupTime, _globalParam.is_smoothChangeOverInWeek(), setupStartTime,isJit);
AvailableTimeSegment, processingTime, operation.getQuantity(), operation.getIsInterrupt() != 1, setupTime, _globalParam.is_smoothChangeOverInWeek(), setupStartTime,true,isJit);
......@@ -1352,7 +1292,10 @@ public class GeneticDecoder {
.mapToInt(ScheduleResultDetail::getEndTime)
.max()
.orElse(0);
//扣库存
if(needMaterialCheck) {
EditOperationBOMTime(operation, chromosome, startTime, machineTasksCache, entryIndexById, scheduleIndexById);
}
//换型时间是否占用设备加工时间
//10:00 开始上班 前面的任务:24:00 结束 开始换型 休息时间 10小时
// 换型时间 12小时
......@@ -1363,29 +1306,7 @@ public class GeneticDecoder {
// 准备工时 加入到加工时间里
// 后处理时间 相同任务的前一工序的结束时间+后处理时间 =当前工序最早开工时间
// 正式提交 BOM 校验:
// 1. 按最终 startTime 重新计算一次物料占用,并把状态真正写回;
// 2. 如果提交后的 BOM 时间仍然晚于 startTime,说明机台时间与物料时间没有收敛,需要直接报错。
if (commitMaterialCheck) {
long commitStart = System.nanoTime();
int committedBomTime = EditOperationBOMTime(operation,chromosome,startTime,machineTasksCache, entryIndexById, scheduleIndexById, true);
long commitElapsed = System.nanoTime() - commitStart;
// if (commitElapsed > 200_000_000L) {
// FileHelper.writeLogFile("[PERF] processWithSingleMachine 正式提交BOM慢 opId=" + operationId
// + ", startTime=" + startTime + ", commitBomTime=" + committedBomTime
// + ", 耗时=" + fmtMs(commitElapsed));
// }
bomtime = Math.max(bomtime, committedBomTime);
if (committedBomTime > startTime) {
// throw new IllegalStateException(String.format(
// "工序固定点求解未收敛,operationId=%d, groupId=%d, startTime=%d, bomTime=%d, maxIterations=%d",
// operation.getId(),
// operation.getGroupId(),
// startTime,
// committedBomTime,
// maxSolveIterations));
}
}
GAScheduleResult result= CreateResult(operation,machine.getId(),startTime,endTime,processingTime,setupTime,preTime,teardownTime,bomtime,geneDetails,existingResult);
......@@ -1400,7 +1321,6 @@ public class GeneticDecoder {
if (machineTasks != null) {
machineTasks.add(result);
}
updateSemiJitTargets(operation, startTime, chromosome);
scheduleIndexById.put(operation.getId(),result);
// long pwsElapsed = System.nanoTime() - pwsStart;
// if (pwsElapsed > 500_000_000L) {
......@@ -1537,7 +1457,7 @@ if(geneDetails!=null&&geneDetails.size()>0)
// 有换型占用时,需要把换型段和加工段一起拼成完整的试排结果。
CopyOnWriteArrayList<TimeSegment> AvailableTimeSegment = (CopyOnWriteArrayList<TimeSegment>) reslte.get(6);
Map<Integer,Object> result = machineCalculator.CreateScheduleResult(machine, operation, previewProcessingTotal, previewStart,
AvailableTimeSegment, processingTime, operation.getQuantity(), operation.getIsInterrupt() != 1, setupTime, _globalParam.is_smoothChangeOverInWeek(), setupStartTime,false);
AvailableTimeSegment, processingTime, operation.getQuantity(), operation.getIsInterrupt() != 1, setupTime, _globalParam.is_smoothChangeOverInWeek(), setupStartTime,true,false);
setupTime=(int)result.get(1);
geneDetails=(CopyOnWriteArrayList<ScheduleResultDetail>) result.get(2);
......@@ -1561,7 +1481,7 @@ if(geneDetails!=null&&geneDetails.size()>0)
}
// 按机台缓存已排结果,避免固定点迭代期间反复全表扫描 chromosome.getResult()。
private CopyOnWriteArrayList<GAScheduleResult> getMachineTasks(long machineId, Chromosome chromosome,
public CopyOnWriteArrayList<GAScheduleResult> getMachineTasks(long machineId, Chromosome chromosome,
Map<Long, CopyOnWriteArrayList<GAScheduleResult>> machineTasksCache) {
if (machineTasksCache.containsKey(machineId)) {
return machineTasksCache.get(machineId);
......@@ -1776,7 +1696,7 @@ if(geneDetails!=null&&geneDetails.size()>0)
* 汇总当前工序的物料约束,返回所有原料/半成品中最晚满足的那个时刻。
* 返回值含义是“这道工序最早允许因物料而开工的秒数”。
*/
private int getOperationBOMTime(Entry currentOp, Chromosome chromosome) {
private int getOperationBOMTime(Entry currentOp, Chromosome chromosome,int bomtype) {
List<OrderMaterialRequirement> opboms= currentOp.getMaterialRequirements();
if(opboms==null||!_globalParam.isIsCheckMp())
......@@ -1788,258 +1708,72 @@ if(geneDetails!=null&&geneDetails.size()>0)
int rawTime = 0, sfTime = 0;
if (opboms != null && !opboms.isEmpty()) {
// 计算RawTime
Optional<LocalDateTime> rawDateOpt = opboms.stream()
.filter(t -> "MP".equals(t.getMaterialTypeName()))
.map(OrderMaterialRequirement::getUseTime)
.filter(Objects::nonNull)
.max(LocalDateTime::compareTo);
if (rawDateOpt.isPresent()) {
rawTime = (int) Duration.between(baseTime, rawDateOpt.get()).getSeconds();
if (bomtype == 0 || bomtype == 1) {
Optional<LocalDateTime> rawDateOpt = opboms.stream()
.filter(t -> "MP".equals(t.getMaterialTypeName()))
.map(OrderMaterialRequirement::getUseTime)
.filter(Objects::nonNull)
.max(LocalDateTime::compareTo);
if (rawDateOpt.isPresent()) {
rawTime = (int) Duration.between(baseTime, rawDateOpt.get()).getSeconds();
}
}
if (bomtype == 0 || bomtype == 2) {
// 计算SFTime
List<OrderMaterialRequirement> sfBoms = opboms.stream()
.filter(t -> !"MP".equals(t.getMaterialTypeName())
&& t.getProductOrderID() != null && !t.getProductOrderID().isEmpty())
.collect(Collectors.toList());
// 计算SFTime
List<OrderMaterialRequirement> sfBoms = opboms.stream()
.filter(t -> !"MP".equals(t.getMaterialTypeName())
&& t.getProductOrderID() != null && !t.getProductOrderID().isEmpty())
.collect(Collectors.toList());
if (!sfBoms.isEmpty()&&sfBoms.size()>0) {
for (OrderMaterialRequirement sf : sfBoms) {
for (int orderid : sf.getProductOrderID()) {
int sfTime1 = 0;
List<GAScheduleResult> result=chromosome.getResult();
List<GAScheduleResult> oe = result.stream()
.filter(t -> t.getGroupId() == orderid)
.collect(Collectors.toList());
if (!oe.isEmpty()) {
int CkeckLeadTime=0;
if(sf.getCheckLeadTime()!=null)
{
CkeckLeadTime=(int) (sf.getCheckLeadTime()*24*60);
if (!sfBoms.isEmpty() && sfBoms.size() > 0) {
for (OrderMaterialRequirement sf : sfBoms) {
for (int orderid : sf.getProductOrderID()) {
int sfTime1 = 0;
List<GAScheduleResult> result = chromosome.getResult();
List<GAScheduleResult> oe = result.stream()
.filter(t -> t.getGroupId() == orderid)
.collect(Collectors.toList());
if (!oe.isEmpty()) {
int CkeckLeadTime = 0;
if (sf.getCheckLeadTime() != null) {
CkeckLeadTime = (int) (sf.getCheckLeadTime() * 24 * 60);
}
sfTime1 = oe.stream().mapToInt(GAScheduleResult::getEndTime).max().orElse(0)
+ CkeckLeadTime;
sf.setUseTime(baseTime.plusSeconds(sfTime1));
}
sfTime1 = oe.stream().mapToInt(GAScheduleResult::getEndTime).max().orElse(0)
+CkeckLeadTime;
sf.setUseTime(baseTime.plusSeconds(sfTime1));
sfTime = Math.max(sfTime, sfTime1);
}
sfTime = Math.max(sfTime, sfTime1);
}
}
}
Optional<LocalDateTime> sfDateOpt = opboms.stream()
.filter(t -> !"MP".equals(t.getMaterialTypeName())&&(t.getProductOrderID() == null || t.getProductOrderID().isEmpty()))
.map(OrderMaterialRequirement::getUseTime)
.filter(Objects::nonNull)
.max(LocalDateTime::compareTo);
if (sfDateOpt.isPresent()) {
sfTime =Math.max(sfTime, (int) Duration.between(baseTime, sfDateOpt.get()).getSeconds());
}
Optional<LocalDateTime> sfDateOpt = opboms.stream()
.filter(t -> !"MP".equals(t.getMaterialTypeName()) && (t.getProductOrderID() == null || t.getProductOrderID().isEmpty()))
.map(OrderMaterialRequirement::getUseTime)
.filter(Objects::nonNull)
.max(LocalDateTime::compareTo);
if (sfDateOpt.isPresent()) {
sfTime = Math.max(sfTime, (int) Duration.between(baseTime, sfDateOpt.get()).getSeconds());
}
}
}
return Math.max(rawTime, sfTime);
}
// 默认走正式提交路径,调用方不传 commitChanges 时认为要把物料状态真实写回。
private int EditOperationBOMTime(Entry currentOp, Chromosome chromosome,int earliestStartTime,Map<Long, CopyOnWriteArrayList<GAScheduleResult>> machineTasksCache,Map<Integer, Entry> entryIndexById,Map<Integer, GAScheduleResult> scheduleIndexById) {
return EditOperationBOMTime(currentOp, chromosome, earliestStartTime, machineTasksCache, entryIndexById, scheduleIndexById, true);
}
/**
* 按指定 earliestStartTime 重新计算当前工序的 BOM 可开工时间。
* commitChanges=true:正式提交,真实修改物料/订单/排程状态。
* commitChanges=false:只做试算,方法结束后恢复 chromosome 和相关索引缓存。
*/
private int EditOperationBOMTime(Entry currentOp, Chromosome chromosome,int earliestStartTime,Map<Long, CopyOnWriteArrayList<GAScheduleResult>> machineTasksCache,Map<Integer, Entry> entryIndexById,Map<Integer, GAScheduleResult> scheduleIndexById, boolean commitChanges) {
long t0 = System.nanoTime();
List<OrderMaterialRequirement> opboms= currentOp.getMaterialRequirements();
if(opboms==null)
{
return 0;
}
LocalDateTime earliestStartTime1=baseTime.plusSeconds(earliestStartTime);
if(commitChanges) {
// 正式提交模式:直接把当前开工时间对应的物料占用/供应结果写回业务对象。
materialRequirementService.EditOperationBOM(currentOp,chromosome,earliestStartTime1,this,machineTasksCache, entryIndexById, scheduleIndexById, baseTime, true);
int bomTime = getOperationBOMTime(currentOp, chromosome);
long elapsed = System.nanoTime() - t0;
// if (elapsed > 200_000_000L) {
// FileHelper.writeLogFile("[PERF] EditOperationBOMTime 正式提交慢 opId=" + currentOp.getId()
// + ", 耗时=" + fmtMs(elapsed));
// }
return bomTime;
}
long snapStart = System.nanoTime();
TrialDecodeSnapshot snapshot = createTrialDecodeSnapshot(currentOp, chromosome);
long snapElapsed = System.nanoTime() - snapStart;
try {
materialRequirementService.EditOperationBOM(currentOp,chromosome,earliestStartTime1,this,machineTasksCache, entryIndexById, scheduleIndexById, baseTime, false);
return getOperationBOMTime(currentOp, chromosome);
} finally {
// long restoreStart = System.nanoTime();
restoreTrialDecodeSnapshot(snapshot);
// long restoreElapsed = System.nanoTime() - restoreStart;
// long total = System.nanoTime() - t0;
// if (total > 200_000_000L) {
// FileHelper.writeLogFile("[PERF] EditOperationBOMTime 试算慢 opId=" + currentOp.getId()
// + ", 快照=" + fmtMs(snapElapsed) + ", 恢复=" + fmtMs(restoreElapsed)
// + ", 总耗时=" + fmtMs(total));
// }
}
}
private TrialDecodeSnapshot createTrialDecodeSnapshot(Entry currentOp, Chromosome chromosome) {
TrialDecodeSnapshot snapshot = new TrialDecodeSnapshot();
long t0 = System.nanoTime();
if (currentOp.getMaterialRequirements() != null) {
for (OrderMaterialRequirement requirement : currentOp.getMaterialRequirements()) {
snapshot.requirementStates.add(new RequirementSnapshot(requirement));
snapshot.captureStocks(chromosome, requirement.getMaterialId());
if (requirement.getReplaceMaterial() != null) {
for (OrderMaterialRequirement replace : requirement.getReplaceMaterial()) {
snapshot.captureStocks(chromosome, replace.getMaterialId());
}
}
}
}
// long total = System.nanoTime() - t0;
// if (total > 100_000_000L) {
// FileHelper.writeLogFile("[PERF] createTrialDecodeSnapshot 慢 requirements=" + snapshot.requirementStates.size()
// + ", stocks=" + snapshot.stockStates.size() + ", transit=" + snapshot.transitStates.size()
// + ", total=" + fmtMs(total));
// }
return snapshot;
}
private void restoreTrialDecodeSnapshot(TrialDecodeSnapshot snapshot) {
for (RequirementSnapshot requirementState : snapshot.requirementStates) {
requirementState.restore();
}
for (StockSnapshot stockState : snapshot.stockStates) {
stockState.restore();
}
for (MaterialSupplySnapshot transitState : snapshot.transitStates) {
transitState.restore();
}
}
private static class TrialDecodeSnapshot {
private final List<RequirementSnapshot> requirementStates = new ArrayList<>();
private final List<StockSnapshot> stockStates = new ArrayList<>();
private final List<MaterialSupplySnapshot> transitStates = new ArrayList<>();
private final Set<Stock> seenStocks = Collections.newSetFromMap(new IdentityHashMap<>());
private final Set<MaterialSupply> seenTransit = Collections.newSetFromMap(new IdentityHashMap<>());
private void captureStocks(Chromosome chromosome, String materialId) {
if (materialId == null) {
return;
}
Material material = chromosome.getMaterials().stream()
.filter(t -> materialId.equals(t.getId()))
.findFirst()
.orElse(null);
if (material == null) {
return;
}
if (material.getMaterialStocks() != null) {
for (Stock stock : material.getMaterialStocks()) {
if (seenStocks.add(stock)) {
stockStates.add(new StockSnapshot(stock));
}
}
}
if (material.getInTransit() != null) {
for (MaterialSupply supply : material.getInTransit()) {
if (seenTransit.add(supply)) {
transitStates.add(new MaterialSupplySnapshot(supply));
}
}
}
}
}
private static class RequirementSnapshot {
private final OrderMaterialRequirement requirement;
private final double requiredQuantity;
private final double ypQty;
private final double qjQty;
private final double useStock;
private final double useTransit;
private final LocalDateTime arrivalTime;
private final LocalDateTime useTime;
private final LocalDateTime purchaseStartTime;
private final LocalDateTime purchaseEndTime;
private final Integer checkLeadTime;
private final Integer purchaseTime;
private final List<OrderMaterialRequirement> replaceMaterial;
private RequirementSnapshot(OrderMaterialRequirement requirement) {
this.requirement = requirement;
this.requiredQuantity = requirement.getRequiredQuantity();
this.ypQty = requirement.getYpQty();
this.qjQty = requirement.getQjQty();
this.useStock = requirement.getUseStock();
this.useTransit = requirement.getUseTransit();
this.arrivalTime = requirement.getArrivalTime();
this.useTime = requirement.getUseTime();
this.purchaseStartTime = requirement.getPurchaseStartTime();
this.purchaseEndTime = requirement.getPurchaseEndTime();
this.checkLeadTime = requirement.getCheckLeadTime();
this.purchaseTime = requirement.getPurchaseTime();
this.replaceMaterial = ProductionDeepCopyUtil.deepCopyList(requirement.getReplaceMaterial(), OrderMaterialRequirement.class);
}
private void restore() {
requirement.setRequiredQuantity(requiredQuantity);
requirement.setYpQty(ypQty);
requirement.setQjQty(qjQty);
requirement.setUseStock(useStock);
requirement.setUseTransit(useTransit);
requirement.setArrivalTime(arrivalTime);
requirement.setUseTime(useTime);
requirement.setPurchaseStartTime(purchaseStartTime);
requirement.setPurchaseEndTime(purchaseEndTime);
requirement.setCheckLeadTime(checkLeadTime);
requirement.setPurchaseTime(purchaseTime);
requirement.setReplaceMaterial(replaceMaterial == null ? new ArrayList<>() : ProductionDeepCopyUtil.deepCopyList(replaceMaterial, OrderMaterialRequirement.class));
}
}
LocalDateTime earliestStartTime1 = baseTime.plusSeconds(earliestStartTime);
private static class StockSnapshot {
private final Stock stock;
private final double usedInventory;
materialRequirementService.EditOperationBOM(currentOp, chromosome, earliestStartTime1, this, machineTasksCache, entryIndexById, scheduleIndexById, baseTime, true);
private StockSnapshot(Stock stock) {
this.stock = stock;
this.usedInventory = stock.getUsedInventory();
}
private void restore() {
stock.setUsedInventory(usedInventory);
}
return 0;
}
private static class MaterialSupplySnapshot {
private final MaterialSupply supply;
private final double quantity;
private MaterialSupplySnapshot(MaterialSupply supply) {
this.supply = supply;
this.quantity = supply.getQuantity();
}
private void restore() {
supply.setQuantity(quantity);
}
}
public void EditorderOperation(Chromosome chromosome, int groupId,double needed,Map<Long, CopyOnWriteArrayList<GAScheduleResult>> machineTasksCache,Map<Integer, Entry> entryIndexById,Map<Integer, GAScheduleResult> scheduleIndexById){
List<Entry> orderOps = chromosome.getAllOperations().stream()
......@@ -2173,6 +1907,9 @@ if(geneDetails!=null&&geneDetails.size()>0)
.collect(Collectors.toList());
int GroupId=0;
chromosome.getReOrderids().add(groupid);
for (Entry entry : sourceOps) {
if(!entry.isNewCreate())
......@@ -2183,6 +1920,10 @@ if(geneDetails!=null&&geneDetails.size()>0)
entry.getTargetFinishedOperationId().remove(orderMaterialRequirement.getOperationId());
continue;
}
orderMaterialRequirement.setProductOrderID(null);
List<OrderMaterialRequirement> orderMaterialRequirements= entry.getMaterialRequirements().stream().filter(t-> !"MP".equals(t.getMaterialTypeName())
&& t.getProductOrderID() != null && !t.getProductOrderID().isEmpty()
).collect(Collectors.toList());
......
package com.aps.service.Algorithm;
import com.aps.entity.Algorithm.Chromosome;
import com.aps.entity.Algorithm.GAScheduleResult;
import com.aps.entity.Algorithm.OperationDependency;
import com.aps.entity.Algorithm.OrderMaterialRequirement;
import com.aps.entity.basic.Entry;
import com.aps.entity.basic.Machine;
import com.aps.common.util.ProductionDeepCopyUtil;
import com.aps.entity.Algorithm.*;
import com.aps.entity.basic.*;
import com.aps.service.plan.MachineSchedulerService;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
/**
* 作者:佟礼
* 时间:2026-04-28
*/
public class GeneticDecoderBom {
/**
* 计算成品可用时间(用于半成品排程)
*
* @param semiFinishedOperation 半成品工序
* @param chromosome 染色体
* @param baseTime 基准时间
* @param machineTasksCache 设备任务缓存
* @param entryIndexById 工序索引
* @param scheduleIndexById 排程索引
* @return 成品可用时间(秒)
*/
public int calculateFinishedAvailableTime(Entry semiFinishedOperation, Chromosome chromosome,
LocalDateTime baseTime,
Map<Long, CopyOnWriteArrayList<GAScheduleResult>> machineTasksCache,
Map<Integer, Entry> entryIndexById,
Map<Integer, GAScheduleResult> scheduleIndexById) {
// 如果没有关联的成品工序,返回0
if (semiFinishedOperation.getTargetFinishedOperationId() == null ||
semiFinishedOperation.getTargetFinishedOperationId().isEmpty()) {
return 0;
public class GeneticDecoderBom {
private MachineCalculator machineCalculator;
private MaterialRequirementService materialRequirementService;
private LocalDateTime baseTime;
GeneticDecoderBom(LocalDateTime _baseTime,MachineCalculator _machineCalculator,MaterialRequirementService _materialRequirementService)
{
baseTime=_baseTime;
machineCalculator=_machineCalculator;
materialRequirementService=_materialRequirementService;
}
public int computeSemiFinishedAnchor(int semiGroupId,
Map<Integer, List<Entry>> entrysBygroupId,
Map<String, OpMachine> opMachineKeyMap,
Chromosome chromosome,
Map<Integer, GAScheduleResult> scheduleIndexById,
Map<Long, CopyOnWriteArrayList<GAScheduleResult>> machineTasksCache) {
List<Entry> semiOps = entrysBygroupId.get(semiGroupId);
if (semiOps == null || semiOps.isEmpty()) return 0;
int currentGroupId = semiGroupId;
List<Integer> intermediateGroupIds = new ArrayList<>();
intermediateGroupIds.add(semiGroupId);
boolean isFORWARD=false;
while (true) {
List<Entry> ops = entrysBygroupId.get(currentGroupId);
Entry lastOp = ops.stream()
.max(Comparator.comparingInt(Entry::getSequence)).orElse(null);
if (lastOp == null || lastOp.getTargetFinishedOperationId() == null
|| lastOp.getTargetFinishedOperationId().isEmpty()) break;
int targetOpId = lastOp.getTargetFinishedOperationId().get(0);
int targetGroupId = findGroupForOperation(targetOpId, entrysBygroupId);
if (targetGroupId < 0) break;
List<Entry> targetOps = entrysBygroupId.get(targetGroupId);
if (targetOps == null || targetOps.isEmpty()) break;
Entry firstTargetOp = targetOps.get(0);
if (Entry.SchedulingMode.FORWARD.name().equals(
firstTargetOp.getSchedulingMode())) {
int rootStart = forwardEstimateToOperation(targetOpId, targetGroupId,0,
entrysBygroupId, opMachineKeyMap, chromosome,
scheduleIndexById, machineTasksCache,false);
List<Integer> chainGroupIds = new ArrayList<>(intermediateGroupIds);
chainGroupIds.add(targetGroupId);
rootStart = correctByRawMaterialStockForChain(chainGroupIds,targetGroupId,targetOpId,
rootStart, entrysBygroupId,chromosome);
int anchor = rootStart;
for (int i = intermediateGroupIds.size() - 1; i >= 0; i--) {
int start1= forwardEstimateToOperation(0, intermediateGroupIds.get(i),anchor,
entrysBygroupId, opMachineKeyMap, chromosome,
scheduleIndexById, machineTasksCache,true);
if(start1<0) {
isFORWARD=true;
break;
}
if(i!=0)
{
anchor -= start1;
if(anchor<0)
{
isFORWARD=true;
break;
}
}else {
if(anchor-start1<0)
{
isFORWARD=true;
break;
}
}
}
if(isFORWARD)
{
for (int i = intermediateGroupIds.size() - 1; i >= 0; i--) {
List<Entry> ops1 = entrysBygroupId.get(intermediateGroupIds.get(i));
ops1.forEach(t->t.setSchedulingMode(Entry.SchedulingMode.FORWARD.name()));
}
return -1;
}
return Math.max(0, anchor);
}
intermediateGroupIds.add(targetGroupId);
currentGroupId = targetGroupId;
}
return 0;
}
private int findGroupForOperation(int opId,
Map<Integer, List<Entry>> entrysBygroupId) {
for (Map.Entry<Integer, List<Entry>> e : entrysBygroupId.entrySet()) {
for (Entry op : e.getValue()) {
if (op.getId() == opId) return e.getKey();
}
}
return -1;
}
private int forwardEstimateToOperation(int targetOpId, int groupId,int startSecond,
Map<Integer, List<Entry>> entrysBygroupId,
Map<String, OpMachine> opMachineKeyMap,
Chromosome chromosome,
Map<Integer, GAScheduleResult> scheduleIndexById,
Map<Long, CopyOnWriteArrayList<GAScheduleResult>> machineTasksCache,boolean isJit) {
List<Entry> ops = entrysBygroupId.get(groupId);
if (ops == null) return 0;
List<Entry> sorted = new ArrayList<>();
if(isJit)
{
sorted = ops.stream()
.sorted(Comparator.comparingInt(Entry::getSequence).reversed())
.collect(Collectors.toList());
}else {
sorted = ops.stream()
.sorted(Comparator.comparingInt(Entry::getSequence))
.collect(Collectors.toList());
}
Map<Long, Machine> machineById = chromosome.getMachines().stream()
.collect(Collectors.toMap(Machine::getId, m -> m, (a, b) -> a));
int nextAvailableStart = startSecond;
Map<Long, Integer> machineLastEndInOrder = new HashMap<>();
int maxFinishedTime = 0;
for (Entry op : sorted) {
String key = groupId + "_" + op.getSequence();
OpMachine mo = opMachineKeyMap.get(key);
if (mo == null) continue;
Long mId = mo.getMachineId();
Machine machine = machineById.get(mId);
// 遍历所有关联的成品工序,计算每个的可用时间,取最大值
for (Integer finishedOperationId : semiFinishedOperation.getTargetFinishedOperationId()) {
Entry finishedOperation = entryIndexById.get(finishedOperationId);
if (finishedOperation == null) {
int start = nextAvailableStart;
int end=start;
// 该工序已排产 → 直接用真实结束时间作为后续工序的基准
GAScheduleResult prevResult = scheduleIndexById != null
? scheduleIndexById.get(op.getId()) : null;
if (prevResult != null) {
int scheduledEnd = prevResult.getEndTime();
start = Math.max(start, scheduledEnd);
if (op.getId() == targetOpId) return prevResult.getStartTime();
machineLastEndInOrder.put(mId, scheduledEnd);
nextAvailableStart = Math.max(nextAvailableStart, scheduledEnd);
continue;
}
// 计算该成品工序的可用时间
int finishedAvailableTime = calculateSingleFinishedAvailableTime(
finishedOperation, chromosome, baseTime, machineTasksCache, entryIndexById, scheduleIndexById);
if(!isJit) {
// 同一订单内该设备已有工序的结束时间
Integer lastInOrder = machineLastEndInOrder.get(mId);
if (lastInOrder != null) start = Math.max(start, lastInOrder);
maxFinishedTime = Math.min(maxFinishedTime, finishedAvailableTime);
}
// 该设备上已排产的其他任务(半成品占位)的结束时间
if (machineTasksCache != null) {
CopyOnWriteArrayList<GAScheduleResult> tasks = machineTasksCache.get(mId);
if (tasks != null) {
for (GAScheduleResult t : tasks) {
start = Math.max(start, t.getEndTime());
}
}
}
}
return maxFinishedTime;
}
int rawDur=0;
if(op.getConstTime()==1||machine.getCapacityTypeName().equals("Infinite"))
{
if(op.getQuantity()==0)
{
rawDur=0;
}else {
/**
* 计算单个成品工序的可用时间
*
* @param finishedOperation 成品工序
* @param chromosome 染色体
* @param baseTime 基准时间
* @param machineTasksCache 设备任务缓存
* @param entryIndexById 工序索引
* @param scheduleIndexById 排程索引
* @return 成品工序可用时间(秒)
*/
private int calculateSingleFinishedAvailableTime(Entry finishedOperation, Chromosome chromosome,
LocalDateTime baseTime,
Map<Long, CopyOnWriteArrayList<GAScheduleResult>> machineTasksCache,
Map<Integer, Entry> entryIndexById,
Map<Integer, GAScheduleResult> scheduleIndexById) {
int maxTime = 0;
// 1. 计算成品前一序时间
int prevOperationEndTime = 0;
if (!finishedOperation.getPrevEntryIds().isEmpty()) {
for (OperationDependency prevOp : finishedOperation.getPrevEntryIds()) {
GAScheduleResult prevResult = scheduleIndexById.get(prevOp.getPrevOperationId());
if (prevResult != null) {
prevOperationEndTime = Math.max(prevOperationEndTime, prevResult.getEndTime());
rawDur = (int) Math.ceil(mo.getProcessingTime());
}
}else {
rawDur = (int) Math.ceil(mo.getRuntime().doubleValue()
/ mo.getSingleOut().doubleValue() * op.getQuantity());
}
}
//成品时间一定晚于prevOperationEndTime
//半成品库存只能用
maxTime = Math.max(maxTime, prevOperationEndTime);
if (machine != null&&!machine.getCapacityTypeName().equals("Infinite")) {
CopyOnWriteArrayList<GAScheduleResult> machineTasks = getMachineTasks(mId, chromosome, machineTasksCache);
// 2. 计算成品当前序所用设备最后一个任务的结束时间
Long machineId = finishedOperation.getSelectMachineID();
if (machineId == null && finishedOperation.getMachineOptions() != null &&
!finishedOperation.getMachineOptions().isEmpty()) {
// 如果设备还未选择,使用第一个可用设备
machineId = finishedOperation.getMachineOptions().get(0).getMachineId();
}
CopyOnWriteArrayList<ScheduleResultDetail> geneDetails = estimateCalendarAwareDuration(machine,op,machineTasks, start, rawDur,mo.getProcessingTime(),isJit);
if(geneDetails!=null) {
start = geneDetails.stream()
.mapToInt(ScheduleResultDetail::getStartTime)
.min()
.orElse(0);
end = geneDetails.stream()
.mapToInt(ScheduleResultDetail::getEndTime)
.max()
.orElse(0);
}else {
return -1;
}
}else {
if(isJit)
{
start=start-rawDur;
end=start;
}else {
start=end;
end=start+rawDur;
}
}
if (op.getId() == targetOpId) return start;
if (machineId != null) {
Long machineId1=machineId;
Machine machine= chromosome.getMachines().stream().filter(t->t.getId()==machineId1).findFirst().orElse(null);
GAScheduleResult machineTask = machine.getLastGene();
if (machineTask != null ) {
int lastEndTime =machineTask.getEndTime();
maxTime = Math.max(maxTime, lastEndTime);
machineLastEndInOrder.put(mId, end);
if(isJit)
{
nextAvailableStart = Math.min(nextAvailableStart, start);
}else {
nextAvailableStart = Math.max(nextAvailableStart, end);
}
}
// 3. 原材料0库存计算齐套最大时间(只计算原材料,不计算半成品)
int rawMaterialBomTime = calculateRawMaterialBomTimeForFinished(finishedOperation, chromosome);
maxTime = Math.max(maxTime, rawMaterialBomTime);
// targetOpId 不在该订单工序内:返回前序工序全部处理后的最早可用开工时间
return nextAvailableStart;
}
private CopyOnWriteArrayList<ScheduleResultDetail> estimateCalendarAwareDuration(Machine machine,Entry operation,CopyOnWriteArrayList<GAScheduleResult> machineTasks, int startSecond,
int rawDurationSecond,double processingTime,boolean isJit) {
CopyOnWriteArrayList<ScheduleResultDetail> geneDetails=new CopyOnWriteArrayList<>();
return maxTime;
geneDetails= machineCalculator.getNextAvailableTime(machine, operation, startSecond, -1,
rawDurationSecond, machineTasks, operation.getIsInterrupt()!=1, true,processingTime, operation.getQuantity(), false,isJit);
return geneDetails;
}
/**
* 计算成品工序的原材料齐套时间(只计算原材料MP,不计算半成品)
*/
private int calculateRawMaterialBomTimeForFinished(Entry finishedOperation, Chromosome chromosome) {
List<OrderMaterialRequirement> materialReqs = finishedOperation.getMaterialRequirements();
if (materialReqs == null) {
return 0;
public CopyOnWriteArrayList<GAScheduleResult> getMachineTasks(long machineId, Chromosome chromosome,
Map<Long, CopyOnWriteArrayList<GAScheduleResult>> machineTasksCache) {
if (machineTasksCache.containsKey(machineId)) {
return machineTasksCache.get(machineId);
}
CopyOnWriteArrayList<GAScheduleResult> machineTasks = chromosome.getResult().stream()
.filter(t -> t.getMachineId() == machineId)
.sorted(Comparator.comparingInt(GAScheduleResult::getStartTime))
.collect(Collectors.toCollection(CopyOnWriteArrayList::new));
machineTasksCache.put(machineId, machineTasks);
return machineTasks;
}
private int correctByRawMaterialStockForChain(List<Integer> chainGroupIds,int pfGroupId,int pfOpId,
int estimatedStartTime,
Map<Integer, List<Entry>> entrysBygroupId,
Chromosome chromosome) {
List<Material> materials = chromosome.getMaterials();
if (materials == null || materials.isEmpty()) return estimatedStartTime;
List<OrderMaterialRequirement> remove=new ArrayList<>();
int maxTime = 0;
Map<String, OrderMaterialRequirement> totalNeededByMaterial = new HashMap<>();
for (OrderMaterialRequirement req : materialReqs) {
if ("MP".equals(req.getMaterialTypeName())) { // 只计算原材料
// 计算原材料采购提前期
int purchaseTime = req.getPurchaseTime() != null ? req.getPurchaseTime() : 0;
int checkLeadTime = req.getCheckLeadTime() != null ? req.getCheckLeadTime() : 0;
int totalDays = purchaseTime + checkLeadTime;
int totalSeconds = totalDays * 24 * 3600;
maxTime = Math.max(maxTime, totalSeconds);
List<Entry> pfops = entrysBygroupId.get(pfGroupId);
for (Entry op : pfops) {
if (op.getMaterialRequirements() == null) continue;
if(pfOpId!=op.getId())
{
continue;
}
for (OrderMaterialRequirement req : op.getMaterialRequirements()) {
if (!"MP".equals(req.getMaterialTypeName())) {
OrderMaterialRequirement reqq = totalNeededByMaterial.get(req.getMaterialId());
if (reqq != null) {
double allneeded = req.getSpentQty() / req.getMainQty() * op.getQuantity();
allneeded = reqq.getRequiredQuantity() + allneeded;
reqq.setRequiredQuantity(allneeded);
reqq.setQjQty(allneeded);
} else {
OrderMaterialRequirement reqq1 = ProductionDeepCopyUtil.deepCopy(req);
double allneeded = req.getSpentQty() / req.getMainQty() * op.getQuantity();
reqq1.setRequiredQuantity(allneeded);
reqq1.setQjQty(allneeded);
totalNeededByMaterial.put(req.getMaterialId(), reqq1);
}
}
}
}
//结合库存计算半成品生产数量,因为可能会修改生产数量所以和原材料分开
materialRequirementService.CalBom(chromosome,0, totalNeededByMaterial,materials,baseTime.plusSeconds(estimatedStartTime) ,false,remove,entrysBygroupId,true);
totalNeededByMaterial.clear();
for (int groupId : chainGroupIds) {
List<Entry> ops = entrysBygroupId.get(groupId);
if (ops == null) continue;
for (Entry op : ops) {
if (op.getMaterialRequirements() == null) continue;
if(pfGroupId==op.getGroupId()&&pfOpId!=op.getId())
{
continue;
}
for (OrderMaterialRequirement req : op.getMaterialRequirements()) {
if (!"MP".equals(req.getMaterialTypeName()))
continue;
OrderMaterialRequirement reqq= totalNeededByMaterial.get(req.getMaterialId());
if(reqq!=null)
{
double allneeded = req.getSpentQty() / req.getMainQty() * op.getQuantity();
allneeded=reqq.getRequiredQuantity()+allneeded;
reqq.setRequiredQuantity(allneeded);
reqq.setQjQty(allneeded);
}else {
OrderMaterialRequirement reqq1= ProductionDeepCopyUtil.deepCopy(req);
double allneeded = req.getSpentQty() / req.getMainQty() * op.getQuantity();
reqq1.setRequiredQuantity(allneeded);
reqq1.setQjQty(allneeded);
totalNeededByMaterial.put(req.getMaterialId(),reqq1);
}
}
}
}
return maxTime;
LocalDateTime estimatedStartTime1= materialRequirementService.CalBom(chromosome,0, totalNeededByMaterial,materials,baseTime.plusSeconds(estimatedStartTime) ,false,remove,entrysBygroupId,false);
int rawTime = (int) Duration.between(baseTime, estimatedStartTime1).getSeconds();
return Math.max(estimatedStartTime, rawTime);
}
}
......@@ -76,7 +76,7 @@ public class MachineCalculator {
public Map<Integer,Object> CreateScheduleResult(
Machine machine,Entry operation, int processingTime, int proposedStartTime,CopyOnWriteArrayList<TimeSegment> timeSegments,
double oneTime,double quantity
,boolean isInterrupt,int changeOvertTime,boolean changeOverInWeek,int setupStartTime,boolean isJit) {
,boolean isInterrupt,int changeOvertTime,boolean changeOverInWeek,int setupStartTime,boolean islockMachineTime,boolean isJit) {
LocalDateTime startTime = baseTime.plus(proposedStartTime, ChronoUnit.SECONDS);
......@@ -167,7 +167,7 @@ public class MachineCalculator {
times= CaldScheduleResult(
machine, operation, processingTime, startTime,
timeSegments, oneTime, quantity,isJit
timeSegments, oneTime, quantity,islockMachineTime,isJit
);
}else {
......@@ -238,7 +238,7 @@ public class MachineCalculator {
.collect(Collectors.toCollection(CopyOnWriteArrayList::new));
times= CaldScheduleResult(
machine, operation, processingTime, startTime,
timeSegments1, oneTime, quantity,isJit);
timeSegments1, oneTime, quantity,islockMachineTime,isJit);
} else {
double e= (double)processingTime/slot.getEfficiency();
......@@ -285,6 +285,18 @@ public class MachineCalculator {
CopyOnWriteArrayList<ScheduleResultDetail> times = new CopyOnWriteArrayList<>();
if(operation.getQuantity()==0)
{
ScheduleResultDetail time = new ScheduleResultDetail();
time.setKey("");
time.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, currentTime));
time.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, currentTime));
time.setOneTime(oneTime);
time.setQuantity(quantity);
times.add(time);
return times;
}
TimeSegment slot = GetCurrentOrNextShift(machine, currentTime, prevtime, checkprevtime,isJit);
if (slot == null) return times;
LocalDateTime startCandidate=null;
......@@ -333,10 +345,12 @@ public class MachineCalculator {
times.add(time);
CopyOnWriteArrayList<TimeSegment> usedSegments = RemoveMachineAvailable(machine, time, slot);
if (usedSegments != null && usedSegments.size() > 0) {
machine.getAvailability().addAll(usedSegments);
machine.getAvailability().sort(Comparator.comparing(TimeSegment::getStart));
if(islockMachineTime) {
CopyOnWriteArrayList<TimeSegment> usedSegments = RemoveMachineAvailable(machine, time, slot);
if (usedSegments != null && usedSegments.size() > 0) {
machine.getAvailability().addAll(usedSegments);
machine.getAvailability().sort(Comparator.comparing(TimeSegment::getStart));
}
}
return times;
}
......@@ -426,10 +440,12 @@ public class MachineCalculator {
CopyOnWriteArrayList<ScheduleResultDetail> times = new CopyOnWriteArrayList<>();
CopyOnWriteArrayList<TimeSegment> timeSegments= findAvailableSegments(machine, currentTime, machineTasks, remainingTime, isInterrupt,isJit);
if (timeSegments == null || timeSegments.isEmpty()) {
return null;
}
times= CaldScheduleResult(
machine, operation, processingTime, currentTime,
timeSegments, oneTime, quantity,isJit
timeSegments, oneTime, quantity,islockMachineTime,isJit
);
// int estimateIndex= (int) Math.ceil(remainingTime / (double) ONE_DAY_MINUTES);
......@@ -472,7 +488,7 @@ public class MachineCalculator {
private CopyOnWriteArrayList<ScheduleResultDetail> CaldScheduleResult(
Machine machine,Entry operation, int processingTime, LocalDateTime currentTime,
CopyOnWriteArrayList<TimeSegment> timeSegments,double oneTime,double quantity
,boolean isJit) {
, boolean islockMachineTime,boolean isJit) {
int remainingTime = processingTime;
CopyOnWriteArrayList<ScheduleResultDetail> times = new CopyOnWriteArrayList<>();
......@@ -480,16 +496,12 @@ public class MachineCalculator {
int estimateIndex= (int) Math.ceil(remainingTime / (double) ONE_DAY_MINUTES);
CopyOnWriteArrayList<TimeSegment> timeSegments1=null;
if(estimateIndex>10)
{
timeSegments1= getEnoughSegmentsByEstimateIndex(timeSegments,currentTime,remainingTime,isJit);
if(timeSegments1.size()==2)
{
timeSegments1= getEnoughSegmentsByEstimateIndex(timeSegments,currentTime,remainingTime,isJit);
int i=0;
}
}
if(timeSegments1==null) {
......@@ -503,10 +515,11 @@ public class MachineCalculator {
ScheduleResultDetail time = (ScheduleResultDetail) outMap.get(2);
times.add(time);
// 还原未使用的时间段
CopyOnWriteArrayList<TimeSegment> usedSegments1= RemoveMachineAvailable(machine, time,shift);
if(usedSegments1!=null&&usedSegments1.size()>0)
{
usedSegments.addAll(usedSegments1);
if(islockMachineTime) {
CopyOnWriteArrayList<TimeSegment> usedSegments1 = RemoveMachineAvailable(machine, time, shift);
if (usedSegments1 != null && usedSegments1.size() > 0) {
usedSegments.addAll(usedSegments1);
}
}
i++;
}
......@@ -516,13 +529,13 @@ public class MachineCalculator {
machine.getAvailability().sort(Comparator.comparing(TimeSegment::getStart));
}
}else {
times= CaldScheduleResultDetail(timeSegments1,machine, operation,currentTime,remainingTime,oneTime,isJit);
times= CaldScheduleResultDetail(timeSegments1,machine, operation,currentTime,remainingTime,oneTime,islockMachineTime,isJit);
}
return times;
}
private CopyOnWriteArrayList<ScheduleResultDetail> CaldScheduleResultDetail(CopyOnWriteArrayList<TimeSegment> timeSegments,Machine machine,Entry operation,LocalDateTime st,int remainingTime,double oneTime,boolean isJit)
private CopyOnWriteArrayList<ScheduleResultDetail> CaldScheduleResultDetail(CopyOnWriteArrayList<TimeSegment> timeSegments,Machine machine,Entry operation,LocalDateTime st,int remainingTime,double oneTime,boolean islockMachineTime,boolean isJit)
{
int processable1 =(int)calculateTotalAvailableSecond(timeSegments, st,isJit);
......@@ -538,19 +551,16 @@ public class MachineCalculator {
remainingTime=(int)outMap.get(1);
ScheduleResultDetail time1=(ScheduleResultDetail)outMap.get(2);
times.add(time1);
CopyOnWriteArrayList<TimeSegment> usedSegments1 = RemoveMachineAvailable(machine, time1,shiftfrist);
if (usedSegments1 != null && usedSegments1.size() > 0) {
usedSegments.addAll(usedSegments1);
if(islockMachineTime) {
CopyOnWriteArrayList<TimeSegment> usedSegments1 = RemoveMachineAvailable(machine, time1, shiftfrist);
if (usedSegments1 != null && usedSegments1.size() > 0) {
usedSegments.addAll(usedSegments1);
}
}
// 计算有效时间
//中间的数据
CopyOnWriteArrayList<TimeSegment> timeSegments2= new CopyOnWriteArrayList<>(timeSegments.subList(1,timeSegments.size()-1));
if(timeSegments2==null||timeSegments2.size()==0)
{
int i=0;
}
LocalDateTime effectiveStart=timeSegments2.get(0).getStart();
LocalDateTime effectiveend=timeSegments2.get(timeSegments2.size()-1).getEnd();
......@@ -570,8 +580,10 @@ if(timeSegments2==null||timeSegments2.size()==0)
time.setOneTime(oneTime);
time.setUsedSegment(timeSegments2);
timeSegments2.forEach(t->t.setUsed(true));
remainingTime-=processable;
if(islockMachineTime) {
timeSegments2.forEach(t -> t.setUsed(true));
remainingTime -= processable;
}
times.add(time);
......@@ -584,14 +596,16 @@ if(timeSegments2==null||timeSegments2.size()==0)
ScheduleResultDetail timelast=(ScheduleResultDetail)outMaplast.get(2);
times.add(timelast);
CopyOnWriteArrayList<TimeSegment> usedSegments2 = RemoveMachineAvailable(machine, timelast,shiftlast);
if (usedSegments2 != null && usedSegments2.size() > 0) {
usedSegments.addAll(usedSegments2);
}
if(islockMachineTime) {
CopyOnWriteArrayList<TimeSegment> usedSegments2 = RemoveMachineAvailable(machine, timelast, shiftlast);
if (usedSegments2 != null && usedSegments2.size() > 0) {
usedSegments.addAll(usedSegments2);
}
if (usedSegments != null && usedSegments.size() > 0) {
machine.getAvailability().addAll(usedSegments);
machine.getAvailability().sort(Comparator.comparing(TimeSegment::getStart));
if (usedSegments != null && usedSegments.size() > 0) {
machine.getAvailability().addAll(usedSegments);
machine.getAvailability().sort(Comparator.comparing(TimeSegment::getStart));
}
}
return times;
......@@ -1060,7 +1074,7 @@ if(timeSegments2==null||timeSegments2.size()==0)
if (!requireContinuous || requiredMinutes <= 0) {
return baseValidSegments;
}
//不可中断,中间不能休息
if(isJit)
{
......
......@@ -20,6 +20,7 @@ import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
......@@ -141,10 +142,7 @@ public class MaterialRequirementService {
List<Entry> Operations= _allOperations.stream().filter(t -> t.getOrderId() != null)
.filter(t->t.getOrderId().equals(orderId))
.collect(Collectors.toList());
if(Operations==null)
{
int i=1;
}
for (Entry operation : Operations) {
List<Routingsupporting> MaterialRequirement_entrys = routingsupportings.stream()
.filter(t -> t.getRoutingDetailId().equals(operation.getRoutingDetailId()))
......@@ -1033,11 +1031,11 @@ if(demand==null)
return new BOMBuildResult(materialRequirements, _childorders,_newEntrys);
}
private OrderMaterialRequirement MaterialStock(Material material,String materialId,String orderId, String childorderId, Entry operation,double allneeded, double needed,LocalDateTime earliestStartTime, boolean commitChanges ) {
private OrderMaterialRequirement MaterialStock(Material material,String materialId,String orderId, String childorderId, int operationId,double allneeded, double needed,LocalDateTime earliestStartTime, boolean commitChanges ) {
OrderMaterialRequirement orderMaterial = new OrderMaterialRequirement();
orderMaterial.setOrderId(orderId);
orderMaterial.setOperationId(operation.getId());
orderMaterial.setOperationId(operationId);
orderMaterial.setChildOrderId(StringUtils.isBlank(childorderId) ? orderId : childorderId);
orderMaterial.setRequiredQuantity(allneeded);
orderMaterial.setQjQty(allneeded);
......@@ -1082,19 +1080,24 @@ if(demand==null)
private void resetRequirementCalc(OrderMaterialRequirement orderMaterial) {
orderMaterial.setUseStock(0);
orderMaterial.setUseTransit(0);
orderMaterial.setArrivalTime(null);
orderMaterial.setPurchaseStartTime(null);
orderMaterial.setPurchaseEndTime(null);
orderMaterial.setUseTime(null);
// orderMaterial.setArrivalTime(null);
orderMaterial.setPurchaseStartTime(baseTime);
orderMaterial.setPurchaseEndTime(baseTime.plusDays(orderMaterial.getPurchaseTime()));
orderMaterial.setUseTime(baseTime.plusDays(orderMaterial.getPurchaseTime()+orderMaterial.getCheckLeadTime()));
if (orderMaterial.getReplaceMaterial() != null && !orderMaterial.getReplaceMaterial().isEmpty()) {
for (OrderMaterialRequirement replace : orderMaterial.getReplaceMaterial()) {
replace.setUseStock(0);
replace.setUseTransit(0);
replace.setArrivalTime(null);
replace.setPurchaseStartTime(null);
replace.setPurchaseEndTime(null);
replace.setUseTime(null);
}
}
}
}
......@@ -1178,223 +1181,23 @@ if(demand==null)
List<Material> materials=chromosome.getMaterials();
List<OrderMaterialRequirement> remove=new ArrayList<>();
Map<String, OrderMaterialRequirement> totalNeededByMaterial = new HashMap<>();
if (MaterialRequirements != null&&MaterialRequirements.size()>0) {
for (OrderMaterialRequirement orderMaterial : MaterialRequirements) {
double allneeded = orderMaterial.getSpentQty()/ orderMaterial.getMainQty() * operation.getQuantity();
double needed = allneeded;
resetRequirementCalc(orderMaterial);
orderMaterial.setRequiredQuantity(needed);
orderMaterial.setQjQty(needed);
// 查找物料(流式处理替代First)
Material material = materials.stream()
.filter(m -> m.getId().equals(orderMaterial.getMaterialId()))
.findFirst()
.orElse(null);
if (material == null) {
return ;
}
double useStock=0;
List<Stock> stocks= material.getMaterialStocks().stream()
.filter(t -> isStockValid(t, earliestStartTime) && t.getAvailableInventory() > 0)
.sorted(Comparator.comparing(Stock::getExpiryDate, Comparator.nullsLast(LocalDateTime::compareTo))
.thenComparing(Stock::getWarehousingDate, Comparator.nullsLast(LocalDateTime::compareTo)))
.collect(Collectors.toList());
if(stocks!=null)
{
for (Stock s:stocks) {
double useStock1 = Math.min(needed,s.getAvailableInventory());
needed -=useStock1;
useStock+=useStock1;
if(commitChanges) {
s.setUsedInventory(s.getUsedInventory()+useStock1);
}
orderMaterial.setUseStock( useStock);
if(needed==0)
{
break;
}
}
}
if (needed <= 0) {
orderMaterial.setYpQty(allneeded - needed);
orderMaterial.setQjQty(needed);
if(commitChanges) {
remove.add(orderMaterial);
}
continue;
}
List<RoutingSupportingReplace> routingsupportingreplaces= GetRoutingSupportingReplaces(sceneId);
List<RoutingSupportingReplace> routingsupportingreplaces2=null;
if (routingsupportingreplaces != null && routingsupportingreplaces.size() > 1) {
routingsupportingreplaces2 = routingsupportingreplaces.
stream()
.filter(t -> t.getStrsupid().equals(orderMaterial.getBomId())
&& t.getMaterialid().equals(orderMaterial.getMaterialId()))
.collect(Collectors.toList());
if (routingsupportingreplaces2 != null && routingsupportingreplaces2.size() > 0) {
for (RoutingSupportingReplace rsr : routingsupportingreplaces2) {
Material material1 = materials.stream()
.filter(m -> m.getId().equals(rsr.getTargetmaterialid()))
.findFirst()
.orElse(null);
if (material1 == null) {
break;
}
OrderMaterialRequirement orderMaterial1 = MaterialStock(material1, rsr.getTargetmaterialid(), orderMaterial.getOrderId(), orderMaterial.getChildOrderId(), operation, allneeded, needed, earliestStartTime, commitChanges);
if (orderMaterial1 != null) {
useStock = orderMaterial1.getUseStock();
needed -= useStock;
orderMaterial.setUseStock(orderMaterial.getUseStock() + useStock);
orderMaterial.getReplaceMaterial().add(orderMaterial1);
if (needed <= 0) {
break;
}
}
}
}
}
if (needed <= 0) {
orderMaterial.setYpQty(allneeded - needed);
orderMaterial.setQjQty(needed);
if(commitChanges) {
remove.add(orderMaterial);
}
continue;
}
MaterialInTransit(material,"",orderMaterial,needed,earliestStartTime, materials, commitChanges);
needed -= orderMaterial.getUseTransit();
if (routingsupportingreplaces2 != null && routingsupportingreplaces2.size() > 1)
{
for (RoutingSupportingReplace rsr:routingsupportingreplaces2) {
OrderMaterialRequirement orderMaterial1= orderMaterial.getReplaceMaterial().stream()
.filter(t->t.getMaterialId().equals(rsr.getTargetmaterialid()))
.findFirst()
.orElse(null);
Material material1 = materials.stream()
.filter(m -> m.getId().equals(orderMaterial1.getMaterialId()))
.findFirst()
.orElse(null);
if (material1 == null) {
break;
}
MaterialInTransit(material1,rsr.getMaterialid(),orderMaterial1,needed,earliestStartTime, materials, commitChanges);
needed -= orderMaterial1.getUseTransit();
LocalDateTime earliestTime= orderMaterial.getArrivalTime().compareTo(orderMaterial1.getArrivalTime())>0?orderMaterial.getArrivalTime():orderMaterial1.getArrivalTime();
orderMaterial.setArrivalTime(earliestTime);
orderMaterial.setUseTransit(orderMaterial.getUseTransit()+orderMaterial1.getUseTransit());
if (needed <= 0) {
break;
}
}
}
if (needed <= 0) {
orderMaterial.setYpQty(allneeded - needed);
orderMaterial.setQjQty(needed);
if(commitChanges) {
remove.add(orderMaterial);
}
continue;
}
if (needed > 0) {
orderMaterial.setYpQty(allneeded - needed);
orderMaterial.setQjQty(needed);
if (material.getMaterialTypeName().equals("MP") ) {
// 处理原材料采购时间
orderMaterial.setPurchaseStartTime(baseTime);
// 采购结束时间 = 采购开始时间 + 采购提前期(天)
List<MaterialPurchase> materialPurchaseList=material.getMaterialPurchases();
if(materialPurchaseList!=null&&materialPurchaseList.size()>0) {
int randomSeq = rnd.nextInt(materialPurchaseList.size());
MaterialPurchase result = materialPurchaseList.get(randomSeq);
orderMaterial.setPurchaseTime(result.getPurchaseCycle());
orderMaterial.setCheckLeadTime(result.getInspectionCycle());
LocalDateTime purchaseEndTime = baseTime.plusDays(orderMaterial.getPurchaseTime() + orderMaterial.getCheckLeadTime());
orderMaterial.setPurchaseEndTime(purchaseEndTime);
}
} else {
// 处理半成品/成品的现有订单
double allneeded = orderMaterial.getSpentQty() / orderMaterial.getMainQty() * operation.getQuantity();
orderMaterial.setRequiredQuantity(allneeded);
orderMaterial.setQjQty(allneeded);
List<Integer> orderids= orderMaterial.getProductOrderID();
if(orderids!=null&&orderids.size()>0) {
if(commitChanges) {
for (Integer orderid : orderids) {
coder.ClearorderOperationResult(chromosome, orderid);
coder.EditorderOperation(chromosome, orderid, needed,machineTasksCache, entryIndexById, scheduleIndexById);
}
}
}else {
List<MaterialPurchase> materialPurchaseList=material.getMaterialPurchases();
if(materialPurchaseList!=null&&materialPurchaseList.size()>0) {
int randomSeq = rnd.nextInt(materialPurchaseList.size());
MaterialPurchase result = materialPurchaseList.get(randomSeq);
orderMaterial.setPurchaseTime(result.getPurchaseCycle());
orderMaterial.setCheckLeadTime(result.getInspectionCycle());
LocalDateTime purchaseEndTime = baseTime.plusDays(orderMaterial.getPurchaseTime() + orderMaterial.getCheckLeadTime());
orderMaterial.setPurchaseEndTime(purchaseEndTime);
}
}
}
if(commitChanges) {
orderMaterial.getReplaceMaterial().removeIf(t->t.getUseStock()==0&&t.getUseTransit()==0);
}
}
// 计算预计可用时间
LocalDateTime arrivalTime = orderMaterial.getArrivalTime();
LocalDateTime purchaseEndTime = orderMaterial.getPurchaseEndTime();
LocalDateTime useTime = null;
if (arrivalTime == null) {
useTime = purchaseEndTime;
} else {
if (purchaseEndTime != null && purchaseEndTime.isAfter(arrivalTime)) {
useTime = purchaseEndTime;
} else {
useTime = arrivalTime;
}
}
orderMaterial.setUseTime(useTime);
totalNeededByMaterial.put(orderMaterial.getMaterialId(),orderMaterial);
}
}
CalBom(chromosome,operation.getId(), totalNeededByMaterial,materials,earliestStartTime,commitChanges,remove,null,false);
if (commitChanges && remove != null&&remove.size()>0) {
if (commitChanges && remove != null&&remove.size()>0) {
//删除先删排产结果,然后记录orderID,到排产方案里,最后一起删除
for (OrderMaterialRequirement mr:remove) {
List<Integer> orderids= mr.getProductOrderID();
......@@ -1408,6 +1211,322 @@ if(demand==null)
}
}
public LocalDateTime CalBom(Chromosome chromosome,int operationId,Map<String, OrderMaterialRequirement> MaterialRequirements,List<Material> materials,LocalDateTime earliestStartTime,boolean commitChanges,List<OrderMaterialRequirement> remove,Map<Integer, List<Entry>> entrysBygroupId,boolean isSf)
{
String sceneId=chromosome.getScenarioID();
Random rnd = new Random();
LocalDateTime useTime1 = earliestStartTime;
if (MaterialRequirements != null&&MaterialRequirements.size()>0) {
for( Map.Entry<String, OrderMaterialRequirement> entry : MaterialRequirements.entrySet()) {
OrderMaterialRequirement orderMaterial = entry.getValue();
double allneeded = orderMaterial.getRequiredQuantity();
double needed = allneeded;
resetRequirementCalc(orderMaterial);
// 查找物料(流式处理替代First)
Material material = materials.stream()
.filter(m -> m.getId().equals(orderMaterial.getMaterialId()))
.findFirst()
.orElse(null);
if (material == null) {
return useTime1;
}
double useStock = 0;
List<Stock> stocks = material.getMaterialStocks().stream()
.filter(t -> isStockValid(t, earliestStartTime) && t.getAvailableInventory() > 0)
.sorted(Comparator.comparing(Stock::getExpiryDate, Comparator.nullsLast(LocalDateTime::compareTo))
.thenComparing(Stock::getWarehousingDate, Comparator.nullsLast(LocalDateTime::compareTo)))
.collect(Collectors.toList());
if (stocks != null) {
for (Stock s : stocks) {
double useStock1 = Math.min(needed, s.getAvailableInventory());
needed -= useStock1;
useStock += useStock1;
if (commitChanges) {
s.setUsedInventory(s.getUsedInventory() + useStock1);
}
orderMaterial.setUseStock(useStock);
if (needed == 0) {
break;
}
}
}
if (needed <= 0) {
orderMaterial.setYpQty(allneeded - needed);
orderMaterial.setQjQty(needed);
if (commitChanges) {
remove.add(orderMaterial);
}
if (isSf) {
if (!material.getMaterialTypeName().equals("MP")) {
List<Integer> orderids = orderMaterial.getProductOrderID();
for (Integer orderid : orderids) {
EditOrderOperation(chromosome, orderid, needed, entrysBygroupId);
}
}
}
continue;
}
List<RoutingSupportingReplace> routingsupportingreplaces = GetRoutingSupportingReplaces(sceneId);
List<RoutingSupportingReplace> routingsupportingreplaces2 = null;
if (routingsupportingreplaces != null && routingsupportingreplaces.size() > 1) {
routingsupportingreplaces2 = routingsupportingreplaces.
stream()
.filter(t -> t.getStrsupid().equals(orderMaterial.getBomId())
&& t.getMaterialid().equals(orderMaterial.getMaterialId())
&& !t.getTargetmaterialid().equals(orderMaterial.getMaterialId()))
.collect(Collectors.toList());
if (routingsupportingreplaces2 != null && routingsupportingreplaces2.size() > 0) {
for (RoutingSupportingReplace rsr : routingsupportingreplaces2) {
Material material1 = materials.stream()
.filter(m -> m.getId().equals(rsr.getTargetmaterialid()))
.findFirst()
.orElse(null);
if (material1 == null) {
break;
}
OrderMaterialRequirement orderMaterial1 = MaterialStock(material1, rsr.getTargetmaterialid(), orderMaterial.getOrderId(), orderMaterial.getChildOrderId(), operationId, allneeded, needed, earliestStartTime, commitChanges);
if (orderMaterial1 != null) {
useStock = orderMaterial1.getUseStock();
needed -= useStock;
orderMaterial.setUseStock(orderMaterial.getUseStock() + useStock);
orderMaterial.getReplaceMaterial().add(orderMaterial1);
if (needed <= 0) {
break;
}
}
}
}
}
if (needed <= 0) {
orderMaterial.setYpQty(allneeded - needed);
orderMaterial.setQjQty(needed);
if (commitChanges) {
remove.add(orderMaterial);
}
if (isSf) {
if (!material.getMaterialTypeName().equals("MP")) {
List<Integer> orderids = orderMaterial.getProductOrderID();
for (Integer orderid : orderids) {
EditOrderOperation(chromosome, orderid, needed, entrysBygroupId);
}
}
}
continue;
}
MaterialInTransit(material, "", orderMaterial, needed, earliestStartTime, materials, commitChanges);
needed -= orderMaterial.getUseTransit();
if (routingsupportingreplaces2 != null && routingsupportingreplaces2.size() > 1) {
for (RoutingSupportingReplace rsr : routingsupportingreplaces2) {
OrderMaterialRequirement orderMaterial1 = orderMaterial.getReplaceMaterial().stream()
.filter(t -> t.getMaterialId().equals(rsr.getTargetmaterialid()))
.findFirst()
.orElse(null);
Material material1 = materials.stream()
.filter(m -> m.getId().equals(orderMaterial1.getMaterialId()))
.findFirst()
.orElse(null);
if (material1 == null) {
break;
}
MaterialInTransit(material1, rsr.getMaterialid(), orderMaterial1, needed, earliestStartTime, materials, commitChanges);
needed -= orderMaterial1.getUseTransit();
if (orderMaterial.getArrivalTime() != null && orderMaterial1.getArrivalTime() != null) {
LocalDateTime earliestTime = orderMaterial.getArrivalTime().compareTo(orderMaterial1.getArrivalTime()) > 0 ? orderMaterial.getArrivalTime() : orderMaterial1.getArrivalTime();
orderMaterial.setArrivalTime(earliestTime);
orderMaterial.setUseTransit(orderMaterial.getUseTransit() + orderMaterial1.getUseTransit());
} else if (orderMaterial.getArrivalTime() != null) {
LocalDateTime earliestTime = orderMaterial.getArrivalTime();
orderMaterial.setArrivalTime(earliestTime);
orderMaterial.setUseTransit(orderMaterial.getUseTransit() + orderMaterial1.getUseTransit());
} else if (orderMaterial1.getArrivalTime() != null) {
LocalDateTime earliestTime = orderMaterial1.getArrivalTime();
orderMaterial.setArrivalTime(earliestTime);
orderMaterial.setUseTransit(orderMaterial.getUseTransit() + orderMaterial1.getUseTransit());
}
if (needed <= 0) {
break;
}
}
}
if (needed <= 0) {
orderMaterial.setYpQty(allneeded - needed);
orderMaterial.setQjQty(needed);
if (commitChanges) {
remove.add(orderMaterial);
}
if (isSf) {
if (!material.getMaterialTypeName().equals("MP")) {
List<Integer> orderids = orderMaterial.getProductOrderID();
for (Integer orderid : orderids) {
EditOrderOperation(chromosome, orderid, needed, entrysBygroupId);
}
}
}
continue;
}
if (needed > 0) {
orderMaterial.setYpQty(allneeded - needed);
orderMaterial.setQjQty(needed);
if (material.getMaterialTypeName().equals("MP")) {
// 处理原材料采购时间
orderMaterial.setPurchaseStartTime(baseTime);
// 采购结束时间 = 采购开始时间 + 采购提前期(天)
List<MaterialPurchase> materialPurchaseList = material.getMaterialPurchases();
if (materialPurchaseList != null && materialPurchaseList.size() > 0) {
int randomSeq = rnd.nextInt(materialPurchaseList.size());
MaterialPurchase result = materialPurchaseList.get(randomSeq);
orderMaterial.setPurchaseTime(result.getPurchaseCycle());
orderMaterial.setCheckLeadTime(result.getInspectionCycle());
LocalDateTime purchaseEndTime = baseTime.plusDays(orderMaterial.getPurchaseTime() + orderMaterial.getCheckLeadTime());
orderMaterial.setPurchaseEndTime(purchaseEndTime);
}
} else {
// 处理半成品/成品的现有订单
List<Integer> orderids = orderMaterial.getProductOrderID();
if (orderids != null && orderids.size() > 0) {
if (isSf) {
for (Integer orderid : orderids) {
EditOrderOperation(chromosome, orderid, needed, entrysBygroupId);
}
}
} else {
List<MaterialPurchase> materialPurchaseList = material.getMaterialPurchases();
if (materialPurchaseList != null && materialPurchaseList.size() > 0) {
int randomSeq = rnd.nextInt(materialPurchaseList.size());
MaterialPurchase result = materialPurchaseList.get(randomSeq);
orderMaterial.setPurchaseTime(result.getPurchaseCycle());
orderMaterial.setCheckLeadTime(result.getInspectionCycle());
LocalDateTime purchaseEndTime = baseTime.plusDays(orderMaterial.getPurchaseTime() + orderMaterial.getCheckLeadTime());
orderMaterial.setPurchaseEndTime(purchaseEndTime);
}
}
}
if (commitChanges) {
orderMaterial.getReplaceMaterial().removeIf(t -> t.getUseStock() == 0 && t.getUseTransit() == 0);
}
}
// 计算预计可用时间
LocalDateTime arrivalTime = orderMaterial.getArrivalTime();
LocalDateTime purchaseEndTime = orderMaterial.getPurchaseEndTime();
LocalDateTime useTime = null;
if (arrivalTime == null) {
useTime = purchaseEndTime;
} else {
if (purchaseEndTime != null && purchaseEndTime.isAfter(arrivalTime)) {
useTime = purchaseEndTime;
} else {
useTime = arrivalTime;
}
}
useTime1 = useTime.compareTo(useTime1) > 0 ? useTime1 : useTime;
orderMaterial.setUseTime(useTime);
if(commitChanges)
{
orderMaterial.setUseTime(earliestStartTime);
orderMaterial.setPurchaseEndTime(earliestStartTime.plusDays(-orderMaterial.getCheckLeadTime()));
orderMaterial.setPurchaseStartTime(orderMaterial.getPurchaseEndTime().plusDays(-orderMaterial.getPurchaseTime()));
}
}
}
return useTime1;
}
public void EditOrderOperation(Chromosome chromosome, int groupId,double needed,Map<Integer, List<Entry>> entrysBygroupId) {
Order order= chromosome.getOrders().stream()
.filter(m -> m.getId()==groupId)
.findFirst()
.orElse(null);
if(order!=null) {
if (needed == order.getQuantity()) {
return;
}else {
order.setQuantity(needed);
}
}
List<Entry> orderOps = entrysBygroupId.get(groupId);
if(orderOps!=null) {
for (Entry currentOp : orderOps) {
if (!currentOp.isNewCreate()) {
break;
}
currentOp.setQuantity(needed);
if(currentOp.getMaterialRequirements()!=null) {
for (OrderMaterialRequirement orderMaterial : currentOp.getMaterialRequirements()) {
List<Integer> orderids = orderMaterial.getProductOrderID();
if (orderids != null && orderids.size() > 0) {
for (Integer orderid : orderids) {
double allneeded = orderMaterial.getSpentQty() / orderMaterial.getMainQty() * currentOp.getQuantity();
EditOrderOperation(chromosome, orderid,allneeded,entrysBygroupId);
}
}
}
}
}
}
}
......
......@@ -45,7 +45,7 @@ import static org.springframework.beans.BeanUtils.copyProperties;
@RequiredArgsConstructor
public class LanuchServiceImpl implements LanuchService {
private static final BigDecimal MAX_PROCESS_DURATION_DAYS = BigDecimal.valueOf(30);
private static final BigDecimal MAX_PROCESS_DURATION_DAYS = BigDecimal.valueOf(90);
private static final BigDecimal SECONDS_PER_DAY = BigDecimal.valueOf(24L * 3600L);
private static final BigDecimal MAX_PROCESS_DURATION_SECONDS =
SECONDS_PER_DAY.multiply(MAX_PROCESS_DURATION_DAYS);
......
......@@ -1911,7 +1911,7 @@ public class PlanResultService {
.collect(Collectors.joining(","));
}
sb.append(String.format(
"[%d-%d]:[%s-%s] Order %d,OrderID %s, Machine %d, Operation %d, Batch %.1f, processingTime %.1f, 前处理 %d, 后处理 %d, 离散参数 %d, bomtime %s,TargetOperationId %s",
"[%d-%d]:[%s-%s] Order %d,OrderID %s, Machine %d, Operation %d, Quantity %.1f, processingTime %.1f, 前处理 %d, 后处理 %d, 离散参数 %d, bomtime %s,TargetOperationId %s",
job.getStartTime(),
job.getEndTime(),
ConvertTime(job.getStartTime()),
......
......@@ -40,9 +40,9 @@ public class PlanResultServiceTest {
// sortService.test1();
// nsgaiiUtils.Test();
// planResultService.execute2("AD62106303684459949A7323D114BF60");//2000
planResultService.execute2("6D7C59CF2576457EBCB5F6CCDF5AF342");//2000
planResultService.execute2("15210B13B88A453F8B84AAC7F16C7541");//2000
// planResultService.execute2("15210B13B88A453F8B84AAC7F16C7541");//2000
// planResultService.execute2("E29F2B3ADA8149F6B916B5119296A92B");//2000
// planResultService.execute2("E2CD1FC6FF9B4B19A59FEC7F846D4952");//600
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment