|
@@ -1,10 +1,13 @@
|
|
|
package com.rongwei.rwapsserver.aps.taskassigning.tado;
|
|
|
|
|
|
-import com.rongwei.rwapsserver.aps.domain.EquipmentRunTime;
|
|
|
+import com.rongwei.rwapsserver.aps.domain.*;
|
|
|
+import com.rongwei.rwapsserver.aps.util.ApsUtils;
|
|
|
import com.rongwei.rwapsserver.aps.util.ObjectNull;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.optaplanner.core.api.domain.variable.ListVariableListener;
|
|
|
import org.optaplanner.core.api.score.director.ScoreDirector;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
import java.time.LocalDateTime;
|
|
|
import java.time.Month;
|
|
|
import java.util.*;
|
|
@@ -73,25 +76,61 @@ public class TaskStartTimeListenerTa implements ListVariableListener<ApsSolution
|
|
|
}
|
|
|
LocalDateTime previousEndTime = index == 0 ? apsStartTime : tasks.get(index - 1).getEndTime();
|
|
|
|
|
|
- for (int i = index; i < tasks.size(); i++) {
|
|
|
- ProductionProcessesTa t = tasks.get(i);
|
|
|
- LocalDateTime previousLastEndTime = getEarlyStartTime(t, equipmentTa,allProcessesList);
|
|
|
- if(previousLastEndTime != null && previousLastEndTime.compareTo(previousEndTime)>0){
|
|
|
- previousEndTime = previousLastEndTime;
|
|
|
- }
|
|
|
- // 过滤设备占用时间
|
|
|
- previousEndTime = eqRunTimeDistinct(equipmentTa,t,previousEndTime);
|
|
|
- if (!Objects.equals(t.getStartTime(), previousEndTime)) {
|
|
|
- scoreDirector.beforeVariableChanged(t, "startTime");
|
|
|
- t.setStartTime(previousEndTime);
|
|
|
- scoreDirector.afterVariableChanged(t, "startTime");
|
|
|
+ // 退火
|
|
|
+ if("成退,中退,小卷成退".contains(tasks.get(0).getProcessType())){
|
|
|
+ for (int i = index; i < tasks.size(); i++) {
|
|
|
+ ProductionProcessesTa t = tasks.get(i);
|
|
|
+ LocalDateTime previousLastEndTime = getEarlyStartTime(t, equipmentTa,allProcessesList);
|
|
|
+ if(i>0){
|
|
|
+ ProductionProcessesTa pret = tasks.get(i-1);
|
|
|
+ if(previousLastEndTime.compareTo(pret.getStartTime())<=0){
|
|
|
+ // 设置当前工序和上道工序开始时间一样(即合并为同一炉)
|
|
|
+ if(thMerge(tasks,i,equipmentTa)){
|
|
|
+ previousEndTime = pret.getStartTime();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(previousLastEndTime != null && previousLastEndTime.compareTo(previousEndTime)>0){
|
|
|
+ previousEndTime = previousLastEndTime;
|
|
|
+ }
|
|
|
+ // 过滤设备占用时间
|
|
|
+ previousEndTime = eqRunTimeDistinct(equipmentTa,t,previousEndTime);
|
|
|
+ if (!Objects.equals(t.getStartTime(), previousEndTime)) {
|
|
|
+ scoreDirector.beforeVariableChanged(t, "startTime");
|
|
|
+ t.setStartTime(previousEndTime);
|
|
|
+ scoreDirector.afterVariableChanged(t, "startTime");
|
|
|
+ }
|
|
|
+
|
|
|
+ LocalDateTime specificDateTime = LocalDateTime.of(2026, Month.JANUARY, 1, 12, 30);
|
|
|
+ if(previousEndTime.compareTo(specificDateTime)>0){
|
|
|
+ int aa = 0;
|
|
|
+ }
|
|
|
+ previousEndTime = t.getEndTime();
|
|
|
}
|
|
|
+ }
|
|
|
+ // 非退火
|
|
|
+ else{
|
|
|
+ for (int i = index; i < tasks.size(); i++) {
|
|
|
+ ProductionProcessesTa t = tasks.get(i);
|
|
|
+ LocalDateTime previousLastEndTime = getEarlyStartTime(t, equipmentTa,allProcessesList);
|
|
|
+ if(previousLastEndTime != null && previousLastEndTime.compareTo(previousEndTime)>0){
|
|
|
+ previousEndTime = previousLastEndTime;
|
|
|
+ }
|
|
|
+ // 过滤设备占用时间
|
|
|
+ previousEndTime = eqRunTimeDistinct(equipmentTa,t,previousEndTime);
|
|
|
+ if (!Objects.equals(t.getStartTime(), previousEndTime)) {
|
|
|
+ scoreDirector.beforeVariableChanged(t, "startTime");
|
|
|
+ t.setStartTime(previousEndTime);
|
|
|
+ scoreDirector.afterVariableChanged(t, "startTime");
|
|
|
+ }
|
|
|
|
|
|
- LocalDateTime specificDateTime = LocalDateTime.of(2026, Month.JANUARY, 1, 12, 30);
|
|
|
- if(previousEndTime.compareTo(specificDateTime)>0){
|
|
|
- int aa = 0;
|
|
|
+ LocalDateTime specificDateTime = LocalDateTime.of(2026, Month.JANUARY, 1, 12, 30);
|
|
|
+ if(previousEndTime.compareTo(specificDateTime)>0){
|
|
|
+ int aa = 0;
|
|
|
+ }
|
|
|
+ previousEndTime = t.getEndTime();
|
|
|
}
|
|
|
- previousEndTime = t.getEndTime();
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -166,6 +205,232 @@ public class TaskStartTimeListenerTa implements ListVariableListener<ApsSolution
|
|
|
return previousLastEndTime;
|
|
|
}
|
|
|
|
|
|
+ private Boolean thMerge(List<ProductionProcessesTa> tasks,int i, EquipmentTa equipmentTa){
|
|
|
+ // 前道作业
|
|
|
+ ProductionProcessesTa processbf = tasks.get(i-1);
|
|
|
+ // 当前作业
|
|
|
+ ProductionProcessesTa process = tasks.get(i);
|
|
|
+
|
|
|
+ Boolean hasMergeTh = false;
|
|
|
+ if(process.getProcessType().equals(processbf.getProcessType())){
|
|
|
+ // 递归前道工序获取当前工序的前一炉退火工序
|
|
|
+ List<ProductionProcessesTa> mergePros = new ArrayList<>();
|
|
|
+ for (int j = i-1; j >= 0 ; j--) {
|
|
|
+ if(mergePros.size() == 0){
|
|
|
+ mergePros.add(tasks.get(j));
|
|
|
+ }else{
|
|
|
+ if(tasks.get(j).getStartTime().compareTo(mergePros.get(0).getStartTime()) == 0){
|
|
|
+ mergePros.add(tasks.get(j));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(process.getProcessType().equals("成退") || process.getProcessType().equals("中退")){
|
|
|
+ if(process.getProcessType().equals(processbf.getProcessType())
|
|
|
+ && process.getVolumeMetal().equals(processbf.getVolumeMetal())
|
|
|
+ && process.getVolumeMetalstate() != null && process.getVolumeMetalstate().equals(processbf.getVolumeMetalstate())){
|
|
|
+ // 获取最大、最小宽度厚度重量等
|
|
|
+ BigDecimal hasMergeMaxWidth = null;
|
|
|
+ BigDecimal hasMergeMinWidth = null;
|
|
|
+ BigDecimal hasMergeMaxThickness = null;
|
|
|
+ BigDecimal hasMergeMinThickness = null;
|
|
|
+ BigDecimal hasMergeMaxWeight = null;
|
|
|
+ BigDecimal hasMergeMinWeight = null;
|
|
|
+ if(mergePros.size()>0){
|
|
|
+ for (ProductionProcessesTa mergePro : mergePros) {
|
|
|
+ // 最大宽度
|
|
|
+ if(hasMergeMaxWidth == null){
|
|
|
+ hasMergeMaxWidth = mergePro.getVolumeWidth();
|
|
|
+ }else{
|
|
|
+ if(mergePro.getVolumeWidth().compareTo(hasMergeMaxWidth)>0){
|
|
|
+ hasMergeMaxWidth = mergePro.getVolumeWidth();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 最小宽度
|
|
|
+ if(hasMergeMinWidth == null){
|
|
|
+ hasMergeMinWidth = mergePro.getVolumeWidth();
|
|
|
+ }else{
|
|
|
+ if(mergePro.getVolumeWidth().compareTo(hasMergeMinWidth)<0){
|
|
|
+ hasMergeMinWidth = mergePro.getVolumeWidth();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 最大厚度
|
|
|
+ if(hasMergeMaxThickness == null){
|
|
|
+ hasMergeMaxThickness = mergePro.getVolumeThickness();
|
|
|
+ }else{
|
|
|
+ if(mergePro.getVolumeThickness().compareTo(hasMergeMaxThickness)>0){
|
|
|
+ hasMergeMaxThickness = mergePro.getVolumeThickness();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 最小厚度
|
|
|
+ if(hasMergeMinThickness == null){
|
|
|
+ hasMergeMinThickness = mergePro.getVolumeThickness();
|
|
|
+ }else{
|
|
|
+ if(mergePro.getVolumeThickness().compareTo(hasMergeMinThickness)<0){
|
|
|
+ hasMergeMinThickness = mergePro.getVolumeThickness();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 最大重量
|
|
|
+ if(hasMergeMaxWeight == null){
|
|
|
+ hasMergeMaxWeight = mergePro.getSinglerollweight();
|
|
|
+ }else{
|
|
|
+ if(mergePro.getSinglerollweight().compareTo(hasMergeMaxWeight)>0){
|
|
|
+ hasMergeMaxWeight = mergePro.getSinglerollweight();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 最小重量
|
|
|
+ if(hasMergeMinWeight == null){
|
|
|
+ hasMergeMinWeight = mergePro.getSinglerollweight();
|
|
|
+ }else{
|
|
|
+ if(mergePro.getSinglerollweight().compareTo(hasMergeMinWeight)<0){
|
|
|
+ hasMergeMinWeight = mergePro.getSinglerollweight();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 最大、最小宽度
|
|
|
+ BigDecimal maxVolumeWidth = hasMergeMaxWidth;
|
|
|
+ BigDecimal minVolumeWidth = hasMergeMinWidth;
|
|
|
+ if(process.getVolumeWidth().compareTo(maxVolumeWidth)>0){
|
|
|
+ maxVolumeWidth = process.getVolumeWidth();
|
|
|
+ }
|
|
|
+ if(process.getVolumeWidth().compareTo(minVolumeWidth)<0){
|
|
|
+ minVolumeWidth = process.getVolumeWidth();
|
|
|
+ }
|
|
|
+ // 最大、最小厚度
|
|
|
+ BigDecimal maxVolumeThickness = hasMergeMaxThickness;
|
|
|
+ BigDecimal minVolumeThickness = hasMergeMinThickness;
|
|
|
+ if(process.getVolumeThickness().compareTo(maxVolumeThickness)>0){
|
|
|
+ maxVolumeThickness = process.getVolumeThickness();
|
|
|
+ }
|
|
|
+ if(process.getVolumeThickness().compareTo(minVolumeThickness)<0){
|
|
|
+ minVolumeThickness = process.getVolumeThickness();
|
|
|
+ }
|
|
|
+ // 最大、最小重量
|
|
|
+ BigDecimal maxSinglerollweight = hasMergeMaxWeight;
|
|
|
+ BigDecimal minSinglerollweight = hasMergeMinWeight;
|
|
|
+ if(process.getSinglerollweight().compareTo(maxSinglerollweight)>0){
|
|
|
+ maxSinglerollweight = process.getSinglerollweight();
|
|
|
+ }
|
|
|
+ if(process.getSinglerollweight().compareTo(minSinglerollweight)<0){
|
|
|
+ minSinglerollweight = process.getSinglerollweight();
|
|
|
+ }
|
|
|
+ // 根据最小厚度查询厚差
|
|
|
+ BigDecimal ztkc = new BigDecimal("250");
|
|
|
+ BigDecimal ctkc = new BigDecimal("200");
|
|
|
+ if(process.getApsOverallConfig().getMiddifference() != null && process.getApsOverallConfig().getMiddifference()>0){
|
|
|
+ ztkc = new BigDecimal(process.getApsOverallConfig().getMiddifference());
|
|
|
+ }
|
|
|
+ if(process.getApsOverallConfig().getFurnacedifference() != null && process.getApsOverallConfig().getFurnacedifference()>0){
|
|
|
+ ctkc = new BigDecimal(process.getApsOverallConfig().getFurnacedifference());
|
|
|
+ }
|
|
|
+ // 读取配置中的卷重差
|
|
|
+ BigDecimal ztjzc = new BigDecimal("4");
|
|
|
+ BigDecimal ctjzc = new BigDecimal("2");
|
|
|
+ if(process.getApsOverallConfig().getWeightdifference() != null){
|
|
|
+ ztjzc = process.getApsOverallConfig().getWeightdifference();
|
|
|
+ }
|
|
|
+ if(process.getApsOverallConfig().getMidweightdifference() != null){
|
|
|
+ ctjzc = process.getApsOverallConfig().getMidweightdifference();
|
|
|
+ }
|
|
|
+
|
|
|
+ BigDecimal zthc = new BigDecimal("0.05");
|
|
|
+ BigDecimal cthc = new BigDecimal("0.05");
|
|
|
+ List<ApsAnnealingDifferenceDo> apsAnnealingDifferences = process.getApsOverallConfig().getApsAnnealingDifferences();
|
|
|
+ if(apsAnnealingDifferences != null && apsAnnealingDifferences.size()>0){
|
|
|
+ for (ApsAnnealingDifferenceDo apsAnnealingDifference : apsAnnealingDifferences) {
|
|
|
+ BigDecimal startthickness = apsAnnealingDifference.getStartthickness();
|
|
|
+ BigDecimal endthickness = apsAnnealingDifference.getEndthickness();
|
|
|
+ if(startthickness == null && endthickness == null){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ boolean fl = true;
|
|
|
+ if(startthickness != null){
|
|
|
+ if(minVolumeThickness.compareTo(startthickness)<0){
|
|
|
+ fl = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(endthickness != null){
|
|
|
+ if(minVolumeThickness.compareTo(endthickness)>0){
|
|
|
+ fl = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(fl){
|
|
|
+ BigDecimal declinedifference = apsAnnealingDifference.getDeclinedifference();
|
|
|
+ BigDecimal moderatedifference = apsAnnealingDifference.getModeratedifference();
|
|
|
+ if(declinedifference != null){
|
|
|
+ cthc = declinedifference;
|
|
|
+ }
|
|
|
+ if(moderatedifference != null){
|
|
|
+ zthc = moderatedifference;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ BigDecimal btVolumeWidth = null;
|
|
|
+ BigDecimal btVolumeThickness = null;
|
|
|
+ BigDecimal btSinglerollweight = null;
|
|
|
+ if("成退".equals(process.getProcessType())){
|
|
|
+ btVolumeWidth = ctkc;
|
|
|
+ btVolumeThickness = cthc;
|
|
|
+ btSinglerollweight = ctjzc;
|
|
|
+ }else if ("中退".equals(process.getProcessType())){
|
|
|
+ btVolumeWidth = ztkc;
|
|
|
+ btVolumeThickness = zthc;
|
|
|
+ btSinglerollweight = ztjzc;
|
|
|
+ }
|
|
|
+ if(maxVolumeWidth.subtract(minVolumeWidth).compareTo(btVolumeWidth)<=0 && maxVolumeThickness.subtract(minVolumeThickness).compareTo(btVolumeThickness)<=0
|
|
|
+ && maxSinglerollweight.subtract(minSinglerollweight).compareTo(btSinglerollweight)<=0){
|
|
|
+ hasMergeTh = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }else{
|
|
|
+ // 小卷成退合并工序
|
|
|
+ String groupname = ApsUtils.getGroupNameMinTh(process);
|
|
|
+ String bfgroupname = ApsUtils.getGroupNameMinTh(processbf);
|
|
|
+ Set<String> minThGroupNames = new HashSet<>();
|
|
|
+ minThGroupNames.add(groupname);
|
|
|
+ minThGroupNames.add(bfgroupname);
|
|
|
+ // 获取前一炉合并工序的总重量
|
|
|
+ BigDecimal totalWeight = null;
|
|
|
+ for (ProductionProcessesTa mergePro : mergePros) {
|
|
|
+ if(totalWeight == null){
|
|
|
+ totalWeight = mergePro.getSinglerollweight();
|
|
|
+ }else{
|
|
|
+ totalWeight = totalWeight.add(mergePro.getSinglerollweight());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ totalWeight = totalWeight.add(process.getSinglerollweight());
|
|
|
+ if(totalWeight.compareTo(equipmentTa.getEquipmentParameter().getEquipmentBearing())<=0 && process.getProcessType().equals(processbf.getProcessType())){
|
|
|
+ if(minThGroupNames.size() == 1){
|
|
|
+ hasMergeTh = true;
|
|
|
+ }else if(minThGroupNames.size() > 1){
|
|
|
+ boolean a = false;
|
|
|
+ for (ApsMergeFurnaceDo mergeFurnace : process.getApsOverallConfig().getMergeFurnaces()) {
|
|
|
+ boolean ab = true;
|
|
|
+ for (String groupname1 : minThGroupNames) {
|
|
|
+ if(!mergeFurnace.getCompatibilitygroup().contains(groupname1)){
|
|
|
+ ab = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(ab){
|
|
|
+ a = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(a){
|
|
|
+ hasMergeTh = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return hasMergeTh;
|
|
|
+ }
|
|
|
+
|
|
|
/*public void updateTaskStartTime(ScoreDirector<ApsSolutionTa> scoreDirector, EquipmentTa resource, int fromIndex) {
|
|
|
List<ProductionProcessesTa> allTasks = scoreDirector.getWorkingSolution().getProcessesList();
|
|
|
LocalDateTime beginTime = allTasks.get(0).getApsOverallConfig().getStartTime();
|