Commit c7bfda5c authored by Tong Li's avatar Tong Li

Merge remote-tracking branch 'origin/tl'

parents 6430785e a0c8a9c1
......@@ -16,7 +16,7 @@ public class ScheduleResultDetail {
private int EndTime; // 相对结束时间(秒)
private double OneTime; // 单件工时
private double Quantity; // 时间段
private double efficiency=1;//效率
private List<TimeSegment> usedSegment;
......
......@@ -710,8 +710,9 @@ if(finishedOrder==null||finishedOrder.size()==0)
List<GAScheduleResult> newScheduleResult = new ArrayList<>();
List<ScheduleResultDetail> newScheduleResultDetails = new ArrayList<>();
for (OperationDependency opid : SSOperations) {
for (int j=0;j<SSOperations.size();j++)
{
OperationDependency opid=SSOperations.get(j);
List<GAScheduleResult> prevOperations = chromosome.getResult().stream()
.filter(t -> t.getGroupId() == currentOp.getGroupId() && t.getOperationId() == opid.getPrevOperationId())
.collect(Collectors.toList());//多台
......@@ -719,51 +720,84 @@ if(finishedOrder==null||finishedOrder.size()==0)
newScheduleResult.add(prevOp);
newScheduleResultDetails.addAll(prevOp.getGeneDetails());
}
if(j==SSOperations.size()-1)
{
int prevtime1 = CalSSPrevtime(newScheduleResult,newScheduleResultDetails, prevtime, currentOp, chromosome, processTime, machine);
prevtime = Math.max(prevtime, prevtime1);
}else {
Entry entry= chromosome.getAllOperations().stream()
.filter(t->t.getId()==opid.getPrevOperationId())
.findFirst().orElse(null);
OperationDependency opid2=SSOperations.get(j+1);
Entry entry1= chromosome.getAllOperations().stream()
.filter(t->t.getId()==opid2.getPrevOperationId())
.findFirst().orElse(null);
if(entry.getRoutingDetailId()!=entry1.getRoutingDetailId())
{
int prevtime1 = CalSSPrevtime(newScheduleResult,newScheduleResultDetails, prevtime, currentOp, chromosome, processTime, machine);
prevtime = Math.max(prevtime, prevtime1);
newScheduleResult.clear();
newScheduleResultDetails.clear();
}
}
}
int prevperationEndTime = newScheduleResult.stream()
.mapToInt(GAScheduleResult::getEndTime)
.max()
.orElse(0);
prevtime = calculateNextOperationStartTime(newScheduleResult, newScheduleResultDetails, 0, processTime);
// 下一工序结束时间需晚于上一工序结束时间一个产品加工时间
// int ssStartTimeWithCalendar = calculateSSStartTimeWithCalendar(
// newScheduleResult,
// newScheduleResultDetails,
// currentOp,
// machine,
// processTime,
// prevtime);
}
return prevtime;
}
private int CalSSPrevtime(List<GAScheduleResult> newScheduleResult,List<ScheduleResultDetail> newScheduleResultDetails,int prevtime,Entry currentOp,Chromosome chromosome,double processTime,Machine machine)
{
int prevperationEndTime = newScheduleResult.stream()
.mapToInt(GAScheduleResult::getEndTime)
.max()
.orElse(0);
// prevtime = calculateNextOperationStartTime(newScheduleResult, newScheduleResultDetails, 0, processTime);
// 下一工序结束时间需晚于上一工序结束时间一个产品加工时间
int ssStartTimeWithCalendar = calculateSSStartTimeWithCalendar(
newScheduleResult,
newScheduleResultDetails,
currentOp,
machine,
processTime,
prevtime);
//
// prevtime = Math.max(prevtime, ssStartTimeWithCalendar);
prevtime = Math.max(prevtime, ssStartTimeWithCalendar);
double nextopplanend = prevperationEndTime + processTime;
double nextopplanend = prevperationEndTime + processTime;
List<ScheduleResultDetail> geneDetails1 = machineCalculator.checkMachineStartTime(machine, (int) (processTime * currentOp.getQuantity()),
baseTime.plusSeconds((int) nextopplanend),
baseTime.plusSeconds(prevtime),
chromosome.getResult());
List<ScheduleResultDetail> geneDetails1 = machineCalculator.checkMachineStartTime(machine, (int) (processTime * currentOp.getQuantity()),
baseTime.plusSeconds((int) nextopplanend),
baseTime.plusSeconds(prevtime),
chromosome.getResult());
if (geneDetails1 != null && !geneDetails1.isEmpty()) {
prevtime = Math.max(prevtime,
geneDetails1.stream()
.mapToInt(ScheduleResultDetail::getStartTime)
.min()
.orElse(prevtime)
);
if (geneDetails1 != null && !geneDetails1.isEmpty()) {
prevtime = Math.max(prevtime,
geneDetails1.stream()
.mapToInt(ScheduleResultDetail::getStartTime)
.min()
.orElse(prevtime)
);
}
}
return prevtime;
}
private int getOperationBOMTime(Entry currentOp, Chromosome chromosome) {
List<OrderMaterialRequirement> opboms= currentOp.getMaterialRequirements();
if(opboms==null)
if(opboms==null||!_globalParam.isIsCheckMp())
{
return 0;
}
......@@ -772,7 +806,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
int rawTime = 0, sfTime = 0;
if (opboms != null && !opboms.isEmpty()) {
// 计算RawTime
if(_globalParam.isIsCheckMp()) {
Optional<LocalDateTime> rawDateOpt = opboms.stream()
.filter(t -> t.getMaterialTypeName().equals("MP"))
.map(OrderMaterialRequirement::getUseTime)
......@@ -781,7 +815,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
rawTime = (int) Duration.between(baseTime, rawDateOpt.get()).getSeconds();
}
}
// 计算SFTime
List<OrderMaterialRequirement> sfBoms = opboms.stream()
......@@ -1096,32 +1130,38 @@ if(MaterialRequirements==null||MaterialRequirements.size()==0)
return prevtime;
}
double prevTimePerUnit = prevScheduleResults.stream()
.mapToDouble(r -> r.getOneTime())
.sum() / qty;
double totalPrevProcessTime = prevScheduleResults.stream()
.mapToDouble(r -> r.getOneTime() * r.getQuantity())
.sum();
double prevTimePerUnit = totalPrevProcessTime / qty;
double currentTimePerUnit = processTime;
//前工序生产多少个后工序可以开工
int leadCount = (int) calculateLeadProductionItems(qty, prevTimePerUnit, currentTimePerUnit);
int productionTimeForLeadCount = calculateProductionTimeWithCalendar(
prevDetails, leadCount, machine, currentOp);
int prevEndTime = prevScheduleResults.stream()
.mapToInt(GAScheduleResult::getEndTime)
.max()
.orElse(0);
int minEndTimeForContinuity = prevEndTime - (int) ((qty - leadCount) * prevTimePerUnit);
// int prevEndTime = prevScheduleResults.stream()
// .mapToInt(GAScheduleResult::getEndTime)
// .max()
// .orElse(0);
//
// int minEndTimeForContinuity = prevEndTime - (int) ((qty - leadCount) * prevTimePerUnit);
int adjustedStartTime = Math.max(productionTimeForLeadCount, minEndTimeForContinuity);
adjustedStartTime = Math.max(adjustedStartTime, prevtime);
// int adjustedStartTime = Math.max(productionTimeForLeadCount, minEndTimeForContinuity);
// int adjustedStartTime = Math.max(productionTimeForLeadCount, prevtime);
int totalProcessingTime = (int) (currentTimePerUnit * qty);
int continuityAdjustedTime = ensureContinuousProduction(machine, adjustedStartTime,
totalProcessingTime, currentOp);
// int totalProcessingTime = (int) (currentTimePerUnit * qty);
// int continuityAdjustedTime = ensureContinuousProduction(machine, adjustedStartTime,
// totalProcessingTime, currentOp);
return Math.max(adjustedStartTime, continuityAdjustedTime);
return productionTimeForLeadCount; //Math.max(adjustedStartTime, continuityAdjustedTime);
}
/**
* 确保下一工序能够连续生产(不中断)
......@@ -1178,42 +1218,56 @@ if(MaterialRequirements==null||MaterialRequirements.size()==0)
if (details == null || details.isEmpty() || leadCount <= 0) {
return 0;
}
List<ScheduleResultDetail> alldetails=new ArrayList<>();
Set<Integer> timePoints = new TreeSet<>();
for (ScheduleResultDetail detail : details) {
timePoints.add(detail.getStartTime());
timePoints.add(detail.getEndTime());
}
List<Integer> sortedTimes = new ArrayList<>(timePoints);
if(detail.getUsedSegment()!=null&&detail.getUsedSegment().size()>0)
{
for (TimeSegment slot: detail.getUsedSegment()) {
LocalDateTime startCandidate = slot.getStart();
LocalDateTime endCandidate = slot.getEnd();
double accumulatedQty = 0.0;
for (int i = 0; i < sortedTimes.size() - 1; i++) {
int startTime = sortedTimes.get(i);
int endTime = sortedTimes.get(i + 1);
int duration = endTime - startTime;
if (duration <= 0) continue;
ScheduleResultDetail time = new ScheduleResultDetail();
time.setKey(slot.getKey());
time.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, startCandidate));
time.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, endCandidate));
time.setOneTime(detail.getOneTime());
alldetails.add(time);
}
}else {
double efficiency = details.stream()
.filter(d -> d.getStartTime() <= startTime && d.getEndTime() >= endTime)
.mapToDouble(d -> d.getProcessingTime() > 0 ? 1.0 / d.getOneTime() : 0)
.sum();
alldetails.add(ProductionDeepCopyUtil.deepCopy(detail));
}
}
alldetails.stream().sorted(Comparator.comparingInt(ScheduleResultDetail::getStartTime));
int EndTime=0;
double accumulatedQty = 0.0;
for (ScheduleResultDetail detail : alldetails) {
double segmentQty = efficiency * duration;
int startTime = detail.getStartTime();
int endTime = detail.getEndTime();
//实际可用时长
double duration = (endTime - startTime)*detail.getEfficiency();
if (accumulatedQty + segmentQty >= leadCount) {
double cQty=accumulatedQty+duration/ detail.getOneTime();//实际可生产数量
if(cQty>leadCount)
{
double remainingQty = leadCount - accumulatedQty;
int requiredTime = (int) Math.ceil(remainingQty / efficiency);
int requiredTime = (int) Math.ceil(remainingQty*detail.getOneTime() / detail.getEfficiency());
return startTime + requiredTime;
}else
{
accumulatedQty=cQty;
EndTime=endTime;
}
accumulatedQty += segmentQty;
}
return details.stream()
.mapToInt(ScheduleResultDetail::getEndTime)
.max()
.orElse(0);
return EndTime;
}
/**
......@@ -1350,7 +1404,7 @@ if(MaterialRequirements==null||MaterialRequirements.size()==0)
* @return 工序1需要提前生产的件数
*/
private double calculateLeadProductionItems(double qty, double time1, double time2) {
if (time1 < time2) {
if (time1 <= time2) {
return 1;
}
if (qty <= 0 || time1 <= 0 || time2 <= 0) {
......@@ -1358,7 +1412,7 @@ if(MaterialRequirements==null||MaterialRequirements.size()==0)
}
double totalTime1 = qty * time1;
double totalTime2 = qty * time2;
double timeDifference = totalTime2 - totalTime1;
double timeDifference =0-( totalTime2 - totalTime1);
return (timeDifference / time1) > qty ? qty : (timeDifference / time1);
}
......
......@@ -10,6 +10,7 @@ import com.aps.service.plan.MachineSchedulerService;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
......@@ -272,7 +273,7 @@ public class MachineCalculator {
String prevtime, CopyOnWriteArrayList<GAScheduleResult> existingTasks,double oneTime,double quantity, boolean checkprevtime, boolean islockMachineTime
,boolean isInterrupt) {
CopyOnWriteArrayList<GAScheduleResult> machineTasks=null;
if(existingTasks!=null) {
if(existingTasks!=null&&existingTasks.size()>0) {
machineTasks = existingTasks.stream()
.filter(t -> t.getMachineId() == machine.getId())
.sorted(Comparator.comparingInt(GAScheduleResult::getStartTime))
......@@ -506,6 +507,7 @@ public class MachineCalculator {
CopyOnWriteArrayList<ScheduleResultDetail> times = new CopyOnWriteArrayList<>();
//第一个数据
TimeSegment shiftfrist= timeSegments.get(0);
Map<Integer, Object> outMap= CreateScheduleResultDetail(shiftfrist,st,remainingTime,oneTime);
......@@ -517,7 +519,7 @@ public class MachineCalculator {
usedSegments.addAll(usedSegments1);
}
// 计算有效时间
//中间的数据
CopyOnWriteArrayList<TimeSegment> timeSegments2= new CopyOnWriteArrayList<>(timeSegments.subList(1,timeSegments.size()-1));
......@@ -531,7 +533,14 @@ public class MachineCalculator {
time.setKey(UUID.randomUUID().toString());
time.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, effectiveStart));
time.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, effectiveend));
time.setQuantity((int)(processable/oneTime));
BigDecimal bd = new BigDecimal(String.valueOf(processable/oneTime));
BigDecimal roundedBd = bd.setScale(4, RoundingMode.HALF_UP);
time.setQuantity(roundedBd.doubleValue());
time.setOneTime(oneTime);
time.setUsedSegment(timeSegments2);
timeSegments2.forEach(t->t.setUsed(true));
......@@ -540,7 +549,7 @@ public class MachineCalculator {
times.add(time);
//最后的时间段
TimeSegment shiftlast= timeSegments.get(timeSegments.size()-1);
Map<Integer, Object> outMaplast= CreateScheduleResultDetail(shiftlast,st,remainingTime,oneTime);
......@@ -586,7 +595,12 @@ public class MachineCalculator {
time.setStartTime(Math.abs ((int) ChronoUnit.SECONDS.between(baseTime, effectiveStart)));
time.setEndTime(Math.abs ((int) ChronoUnit.SECONDS.between(baseTime, currentTime)));
time.setQuantity((int)(processable/oneTime));
time.setEfficiency(shift.getEfficiency());
BigDecimal bd = new BigDecimal(String.valueOf(processable/oneTime));
BigDecimal roundedBd = bd.setScale(4, RoundingMode.HALF_UP);
time.setQuantity(roundedBd.doubleValue());
time.setOneTime(oneTime);
Map<Integer, Object> outMap=new HashMap<>();
outMap.put(1, remainingTime);
......@@ -737,7 +751,7 @@ public class MachineCalculator {
if (currentTotal >= requiredMinutes) {
// ✔️ 总时长满足,尝试往前减索引,找「最小满足索引」(减少后续裁剪的工作量)
// 总时长满足,尝试往前减索引,找「最小满足索引」(减少后续裁剪的工作量)
if (targetIndex > 0) {
double prevTotal = calculateTotalMinutesByIndex(availableSegments, currentTime, targetIndex - 1);
if (prevTotal >= requiredMinutes) {
......@@ -750,7 +764,7 @@ public class MachineCalculator {
double syday= (int)Math.ceil((requiredMinutes-currentTotal)/(double) ONE_DAY_MINUTES);
// 总时长不足,往后加索引(每次加5,大步前进,加快逼近速度)
// 总时长不足,往后加索引(每次加5,大步前进,加快逼近速度)
targetIndex +=Math.max(syday, 5);
if (targetIndex >= totalSegmentCount) {
// 所有片段总时长不足,抛出异常
......@@ -1026,6 +1040,7 @@ public class MachineCalculator {
LocalDateTime taskStart = baseTime.plusSeconds(t.getStartTime());
return taskStart.isAfter(finalPrevEnd) && taskStart.isBefore(shiftStart);
});
if (!hasTask) {
// 检查班次间维修窗口
if (machine.getMaintenanceWindows() != null) {
......@@ -1107,9 +1122,9 @@ public class MachineCalculator {
if (slot == null) {
return null;
}
int processingTime1=(int)Math.ceil( processingTime/slot.getEfficiency());
// 计算候选开始/结束时间(当前时间往前推加工时长)
LocalDateTime startCandidate = currentTime.minusSeconds(processingTime);
LocalDateTime startCandidate = currentTime.minusSeconds(processingTime1);
LocalDateTime endCandidate = currentTime;
// 检查是否在可用时间段内
......@@ -1225,8 +1240,8 @@ public class MachineCalculator {
.filter(t -> baseTime.plusSeconds(t.getStartTime()).isAfter(shiftStart)
&& baseTime.plusSeconds(t.getStartTime()).isBefore(finalPrevEnd))
.findFirst();
if (task.isPresent()) {
boolean hasTask= CheckTask( machine, machineTasks, prevEnd, shiftStart);
if (hasTask) {
// 班次间有任务,重置状态重新查找
currentTime = shiftStart;
remainingTime = processingTime;
......@@ -1236,23 +1251,6 @@ public class MachineCalculator {
}
}
// 检查维护窗口
if (machine.getMaintenanceWindows() != null && !machine.getMaintenanceWindows().isEmpty()) {
LocalDateTime finalPrevEnd = prevEnd;
Optional<MaintenanceWindow> maintenanceTask = machine.getMaintenanceWindows().stream()
.filter(t -> t.getStartTime().isAfter(shiftStart)
&& t.getStartTime().isBefore(finalPrevEnd))
.findFirst();
if (maintenanceTask.isPresent()) {
// 班次间有维护任务,重置状态重新查找
currentTime = shiftStart;
remainingTime = processingTime;
prevEnd = LocalDateTime.of(2000, 1, 1, 0, 0);
times.clear();
continue;
}
}
}
// 调整班次有效结束时间(不超过当前时间)
......@@ -1262,11 +1260,14 @@ public class MachineCalculator {
Duration availableDuration = Duration.between(shiftStart, effectiveEnd);
long availableMinutes = availableDuration.getSeconds();
// 当前班次可处理的时长(不超过剩余需要的时长)
int processableMinutes = (int) Math.min(remainingTime, availableMinutes);
long availableSeconds_e =Math.round(processableMinutes/shift.getEfficiency()) ;
// 计算当前班次的有效开始时间
LocalDateTime effectiveStart = effectiveEnd.minusSeconds(processableMinutes);
LocalDateTime effectiveStart = effectiveEnd.minusSeconds(availableSeconds_e);
prevEnd = effectiveStart; // 更新上一班次结束时间
remainingTime -= processableMinutes; // 剩余时长递减
currentTime = effectiveStart; // 更新当前时间,继续循环
......
......@@ -98,12 +98,12 @@ public class RoutingDataService {
Map<Integer, Object> list=new HashMap<>();
List<String> soutceExecId = ProdOrderProcesss.stream()
.map(ProdOrderProcess::getExecId)
.distinct() // 提取Exec_ID
// .distinct() // 提取Exec_ID
.collect(Collectors.toList());
List<String> targetExecId = ProdOrderProcesss.stream()
.map(ProdOrderProcess::getTargetExecId)
.distinct() // 提取TARGET_Exec_ID
// .distinct() // 提取TARGET_Exec_ID
.collect(Collectors.toList());
List<String> ExecIdNoChild= ProdProcessExecs.stream()
......
......@@ -42,7 +42,7 @@ public class PlanResultServiceTest {
// planResultService.execute2("5475E00B844847ACB6DC20227967BA2F");
// planResultService.execute2("00E0C5D3E4AD4F36B56C39395906618D");
planResultService.execute2("92BB773E1E2447C99D8176C991D5C9D2");
// planResultService.execute2("92BB773E1E2447C99D8176C991D5C9D2");
// planResultService.execute2("265F24B6DF3C40E4B17D193B0CC8AAF2");
// LocalDateTime t= LocalDateTime.of(2026, 02, 14, 1, 25, 52);
// List<Integer> opids=new ArrayList<>();//BCA6FA43FFA444D3952CF8F6E1EA291B
......@@ -56,8 +56,8 @@ public class PlanResultServiceTest {
// maintenanceWindow.setEndTime(LocalDateTime.of(2025, 9, 19, 0, 0, 0));
// planResultService.AddMaintenanceWindow("5475E00B844847ACB6DC20227967BA2F",2488l,maintenanceWindow);
// // planResultService.DelOperation("B6AE363FF5044DDF8DECE32D5FE0F7EA",7);
// planResultService.SpiltOrder("A41D662EE0764D008173C5A0E42B15F6","5f9d5383-b89a-4a4f-8805-2f617c711968",new Double[]{500d, 500d});
planResultService.SpiltOperation("92BB773E1E2447C99D8176C991D5C9D2",1,new Double[]{50d, 50d});
// planResultService.SpiltOrder("A41D662EE0764D008173C5A0E42B15F6","5f9d5383-b89a-4a4f-8805-2f617c711968",new Double[]{500d, 500d});
}
@Test
......
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