洪水-调度演算

master
yangzhe123 2026-01-21 16:21:56 +08:00
parent accdfb627a
commit c43f3f16af
3 changed files with 146 additions and 138 deletions

View File

@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gunshi.core.result.R; import com.gunshi.core.result.R;
import com.gunshi.project.ss.entity.dto.DispatchResultDto;
import com.gunshi.project.ss.entity.vo.ForecastResultVo; import com.gunshi.project.ss.entity.vo.ForecastResultVo;
import com.gunshi.project.ss.model.*; import com.gunshi.project.ss.model.*;
import com.gunshi.project.ss.service.ForecastProjectService; import com.gunshi.project.ss.service.ForecastProjectService;
@ -146,16 +147,16 @@ public class ForecastProjectController {
} }
@Operation(summary = "调度计算-闸门开放关闭时间") @Operation(summary = "调度计算-闸门开放关闭时间")
@GetMapping("/caculate/{waterLevel}") @GetMapping("/caculate/{id}/{waterLevel}")
public R<List<ForecastDispatchCommand>> caculate(@PathVariable("waterLevel") String waterLevel) { public R<List<ForecastDispatchCommand>> caculate(@PathVariable("id") String id,@PathVariable("waterLevel") String waterLevel) {
List<ForecastDispatchCommand> res = service.caculate(waterLevel); List<ForecastDispatchCommand> res = service.caculate(id,waterLevel);
return R.ok(res); return R.ok(res);
} }
@Operation(summary = "调度计算-调度结果") @Operation(summary = "调度计算-调度结果")
@GetMapping("/dispatch/result") @PostMapping("/dispatch/result")
public R<ForecastDispatchResult> getDispatchResult(){ public R<ForecastDispatchResult> getDispatchResult(@RequestBody DispatchResultDto dto){
ForecastDispatchResult result = service.getDispatchResult(); ForecastDispatchResult result = service.getDispatchResult(dto);
return R.ok(result); return R.ok(result);
} }

View File

@ -0,0 +1,13 @@
package com.gunshi.project.ss.entity.dto;
import com.gunshi.db.dto.DateTimeRangeSo;
import lombok.Data;
@Data
public class DispatchResultDto {
private String projectId;
private DateTimeRangeSo dateTimeRangeSo;
}

View File

@ -1,14 +1,21 @@
package com.gunshi.project.ss.service; package com.gunshi.project.ss.service;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gunshi.db.dto.DateTimeRangeSo;
import com.gunshi.project.ss.common.util.LocalDateTimeConverter; import com.gunshi.project.ss.common.util.LocalDateTimeConverter;
import com.gunshi.project.ss.entity.TimeCapacity; import com.gunshi.project.ss.entity.TimeCapacity;
import com.gunshi.project.ss.entity.TimeNetWater; import com.gunshi.project.ss.entity.TimeNetWater;
import com.gunshi.project.ss.entity.dto.DispatchResultDto;
import com.gunshi.project.ss.entity.vo.ForecastResultVo; import com.gunshi.project.ss.entity.vo.ForecastResultVo;
import com.gunshi.project.ss.mapper.ForecastProjectMapper; import com.gunshi.project.ss.mapper.ForecastProjectMapper;
import com.gunshi.project.ss.model.*; import com.gunshi.project.ss.model.*;
import com.gunshi.project.ss.service.AttResBaseService;
import com.gunshi.project.ss.service.ForecastResultsService;
import com.gunshi.project.ss.service.ForecastUseparamService;
import com.gunshi.project.ss.service.StZvarlBService;
import com.itextpdf.io.font.PdfEncodings; import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.kernel.colors.DeviceRgb; import com.itextpdf.kernel.colors.DeviceRgb;
import com.itextpdf.kernel.events.Event; import com.itextpdf.kernel.events.Event;
@ -41,7 +48,6 @@ import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -167,29 +173,15 @@ public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, F
} }
} }
public List<ForecastDispatchCommand> caculate(String rz) { public List<ForecastDispatchCommand> caculate(String id, String rz) {
BigDecimal openDoorFlow = new BigDecimal(5);//开闸门放水流量 5立方米/秒 BigDecimal openDoorFlow = new BigDecimal("5");//开闸门放水流量 5立方米/秒
ForecastProject forecastProjectResults = getForecastProjectResults(id);
ForecastTask forecastTask = new ForecastTask(); List<ForecastResultVo> humanForecastResult = forecastProjectResults.getVoList();
// 设置当前时间整点
LocalDateTime now = LocalDateTime.now();
LocalDateTime nowHour = now.withMinute(0).withSecond(0).withNano(0);
forecastTask.setNowTime(LocalDateTimeConverter.toDate(nowHour));
// 设置开始时间(当前时间减去一天)
LocalDateTime startTime = nowHour.minusDays(1);
forecastTask.setStartTime(LocalDateTimeConverter.toDate(startTime));
// 设置结束时间当前时间加上durationHours
LocalDateTime endTime = nowHour.plusHours(24);
forecastTask.setEndTime(LocalDateTimeConverter.toDate(endTime));
forecastTask.setForecastWarm(1);
forecastTask.setForecastPeriod(24); // 设置预报时长
List<ForecastResultVo> humanForecastResult = forecastResultsService.getHumanForecastResult(forecastTask);
if(humanForecastResult.isEmpty()){ if(humanForecastResult.isEmpty()){
throw new IllegalArgumentException("对不起,暂无预报数据"); throw new IllegalArgumentException("对不起,暂无预报数据");
} }
Date forecastTm = forecastProjectResults.getForecastTm();
LocalDateTime nowHour = LocalDateTimeConverter.fromDate(forecastTm);
//过滤出大于等于nowHour的数据 //过滤出大于等于nowHour的数据
// 获取当前时间的格式化字符串与tm格式一致 // 获取当前时间的格式化字符串与tm格式一致
String nowHourStr = nowHour.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); String nowHourStr = nowHour.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
@ -203,17 +195,25 @@ public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, F
return vo.getTm().compareTo(nowHourStr) >= 0; return vo.getTm().compareTo(nowHourStr) >= 0;
}) })
.collect(Collectors.toList()); .collect(Collectors.toList());
// filteredResults.stream().forEach(o ->{
// o.setYcRkQValue(new BigDecimal("10"));
// o.setYcCkQValue(new BigDecimal("0"));
// });
ForecastResultVo forecastResultVo = filteredResults.get(0);//a点 ForecastResultVo forecastResultVo = filteredResults.get(0);//a点
//b点为filteredResults的最后一条数据 //b点为filteredResults的最后一条数据
//c点为waterLevel //c点为waterLevel
BigDecimal waterLevel = new BigDecimal(rz);//c点 BigDecimal waterLevel = new BigDecimal(rz);//c点
LocalDateTime start = null; LocalDateTime start = null;
LocalDateTime end = null; LocalDateTime end = null;
List<StZvarlB> stZvarlBList = stZvarlBService.list(); List<StZvarlB> stZvarlBList = stZvarlBService.lambdaQuery()
.orderByAsc(StZvarlB::getRz)
.list();
if(rz != null){
BigDecimal minRZ = stZvarlBList.get(0).getRz();
BigDecimal maxRZ = stZvarlBList.get(stZvarlBList.size() - 1).getRz();
BigDecimal curRZ = new BigDecimal(rz);
if(curRZ.compareTo(minRZ) < 0){
throw new IllegalArgumentException("对不起,水位控制值小于了库容曲线的最小值");
}else if(curRZ.compareTo(maxRZ) > 0){
throw new IllegalArgumentException("对不起,水位控制值大于了库容曲线的最大值");
}
}
// 获取配置参数 // 获取配置参数
List<ForecastUseparam> paramList = forecastUseparamService.list(new QueryWrapper<ForecastUseparam>().isNotNull("param_code").isNotNull("param_value")); List<ForecastUseparam> paramList = forecastUseparamService.list(new QueryWrapper<ForecastUseparam>().isNotNull("param_code").isNotNull("param_value"));
if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(paramList)) { if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(paramList)) {
@ -231,8 +231,10 @@ public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, F
timeInterval = new BigDecimal("3600"); timeInterval = new BigDecimal("3600");
} }
if(forecastResultVo.getYcSwHValue().compareTo(waterLevel) > 0){ if(forecastResultVo.getYcSwHValue().compareTo(waterLevel) > 0){
log.info("实际水位大于输入水位哦");
//如果实际水位已经大于了输入的水位的话,那么闸门开门时间就设置为当前时间 //如果实际水位已经大于了输入的水位的话,那么闸门开门时间就设置为当前时间
start = nowHour;// start = nowHour;//
log.info("开始时间为{}",start);
//计算闸门关门时间 //计算闸门关门时间
//计算a点库容 //计算a点库容
//库容单位 万m³ //库容单位 万m³
@ -298,6 +300,7 @@ public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, F
} }
} }
if(dTime == null){ if(dTime == null){
log.info("dTime is null");
//如果a~b之间不存在d点,则闸门关闭时间 = a时间点 + [(a~b之间净入库水量) + aSubC] /5先精确时分秒向上取整再精确到时分 //如果a~b之间不存在d点,则闸门关闭时间 = a时间点 + [(a~b之间净入库水量) + aSubC] /5先精确时分秒向上取整再精确到时分
//计算净入库水量 //计算净入库水量
BigDecimal pureRKWater = BigDecimal.ZERO;//净入库水量 BigDecimal pureRKWater = BigDecimal.ZERO;//净入库水量
@ -311,20 +314,21 @@ public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, F
} }
// aSubC是万m³需要转换为m³ // aSubC是万m³需要转换为m³
BigDecimal aSubCInM3 = aSubC.multiply(new BigDecimal("10000")); // 转换为m³ BigDecimal aSubCInM3 = aSubC.multiply(new BigDecimal("10000")); // 转换为m³
log.info("aSubCinM3 {}",aSubCInM3);
// 计算公式:[(a~b之间净入库水量) + aSubC] / 5 // 计算公式:[(a~b之间净入库水量) + aSubC] / 5
// pureRKWater单位已经是m³因为timeInterval是秒流量是m³/s // pureRKWater单位已经是m³因为timeInterval是秒流量是m³/s
BigDecimal totalWater = pureRKWater.add(aSubCInM3); // 总水量 = 净入库水量 + aSubC转换后的水量 BigDecimal totalWater = pureRKWater.add(aSubCInM3); // 总水量 = 净入库水量 + aSubC转换后的水量
// 除以5开闸门放水流量5立方米/秒) // 除以5开闸门放水流量5立方米/秒)
BigDecimal timeSeconds = totalWater.divide(openDoorFlow, 10, BigDecimal.ROUND_HALF_UP); BigDecimal timeSeconds = totalWater.divide(openDoorFlow, 10, BigDecimal.ROUND_HALF_UP);
log.info("时间差{}",timeSeconds.toString());
// 先精确时分秒,向上取整 // 先精确时分秒,向上取整
long timeSecondsLong = timeSeconds.setScale(0, BigDecimal.ROUND_UP).longValue(); long timeSecondsLong = timeSeconds.setScale(0, BigDecimal.ROUND_UP).longValue();
// 计算闸门关闭时间 = a时间点 + 计算出的时间 // 计算闸门关闭时间 = a时间点 + 计算出的时间
LocalDateTime aTime = LocalDateTime.parse(forecastResultVo.getTm(), formatter); LocalDateTime aTime = LocalDateTime.parse(forecastResultVo.getTm(), formatter);
log.info("aTime {}",aTime);
LocalDateTime closeTime = aTime.plusSeconds(timeSecondsLong); LocalDateTime closeTime = aTime.plusSeconds(timeSecondsLong);
log.info("closeTime {}",closeTime);
// 如果有秒数或者分钟数有小数部分即秒数不为0则分钟向上取整 // 如果有秒数或者分钟数有小数部分即秒数不为0则分钟向上取整
if (closeTime.getSecond() > 0) { if (closeTime.getSecond() > 0) {
// 分钟加1 // 分钟加1
@ -333,7 +337,9 @@ public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, F
// 再精确到时分分钟和秒设为0 // 再精确到时分分钟和秒设为0
closeTime = closeTime.withSecond(0).withNano(0); closeTime = closeTime.withSecond(0).withNano(0);
end = closeTime; end = closeTime;
log.info("结束时间{}",end);
}else{ }else{
log.info("存在dTime{}",dTime);
/** /**
* d * d
* d<=ced(pse * d<=ced(pse
@ -367,14 +373,11 @@ public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, F
BigDecimal dMinus1CkQ = dMinus1Vo.getYcCkQValue() != null ? dMinus1Vo.getYcCkQValue() : BigDecimal.ZERO; BigDecimal dMinus1CkQ = dMinus1Vo.getYcCkQValue() != null ? dMinus1Vo.getYcCkQValue() : BigDecimal.ZERO;
// 计算d-1的出库流量 + 5 - d-1的入库流量 // 计算d-1的出库流量 + 5 - d-1的入库流量
BigDecimal flowRateDiff = dMinus1CkQ.add(openDoorFlow).subtract(dMinus1RkQ); // m³/s BigDecimal flowRateDiff = dMinus1CkQ.add(openDoorFlow).subtract(dMinus1RkQ); // m³/s
// 防止除数为0或负数
// if (flowRateDiff.compareTo(BigDecimal.ZERO) <= 0) {
// flowRateDiff = new BigDecimal("0.001"); // 设置一个很小的正数
// }
// 计算往前倒推的时长c水位值对应的库容 - d点库容) / d-1的出库流量 + 5 - d-1的入库流量 // 计算往前倒推的时长c水位值对应的库容 - d点库容) / d-1的出库流量 + 5 - d-1的入库流量
BigDecimal backwardSeconds = capacityDiffInM3.divide(flowRateDiff, 10, BigDecimal.ROUND_HALF_UP); BigDecimal backwardSeconds = capacityDiffInM3.divide(flowRateDiff, 10, BigDecimal.ROUND_HALF_UP);
// 不进行四舍五入,若存在小数点则向下取整 // 转为分钟,向下取整,再转回秒
long backwardSecondsLong = backwardSeconds.setScale(0, BigDecimal.ROUND_DOWN).longValue(); long minutesLong = backwardSeconds.divide(new BigDecimal(60), 0, BigDecimal.ROUND_DOWN).longValue();
long backwardSecondsLong = minutesLong * 60;
// 计算e点时间 = d点时间 - 倒推时长 // 计算e点时间 = d点时间 - 倒推时长
LocalDateTime eTime = dTime.minusSeconds(backwardSecondsLong); LocalDateTime eTime = dTime.minusSeconds(backwardSecondsLong);
// 检查e点是否在filteredResults集合中存在 // 检查e点是否在filteredResults集合中存在
@ -394,46 +397,41 @@ public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, F
// 2. 计算e~b之间的净入库水量f // 2. 计算e~b之间的净入库水量f
BigDecimal f = BigDecimal.ZERO; BigDecimal f = BigDecimal.ZERO;
// 找到e点在filteredResults中的索引 //找到eTime之后的第一个整点数据的索引
int eIndex = -1; int firstWholeHourIndex = -1;
LocalDateTime firstWholeHourTime = null;
for (int i = 0; i < filteredResults.size(); i++) { for (int i = 0; i < filteredResults.size(); i++) {
LocalDateTime voTime = LocalDateTime.parse(filteredResults.get(i).getTm(), formatter); LocalDateTime voTime = LocalDateTime.parse(filteredResults.get(i).getTm(), formatter);
if (voTime.equals(eTime) || voTime.isBefore(eTime)) { // e点或之后的时间 // 找到第一个大于eTime的整点时间比如eTime=18:48找19:00
eIndex = i; if (voTime.isAfter(eTime) && voTime.getMinute() == 0 && voTime.getSecond() == 0) {
}else{ firstWholeHourIndex = i;
firstWholeHourTime = voTime;
break; break;
} }
} }
// 2.1 计算第一段eTime 到 第一个整点比如18:48 ~ 19:00的净入库水量
// 获取第一个整点前的那条数据18:00的数据因为流量数据是按整点存储的
ForecastResultVo preVo = filteredResults.get(firstWholeHourIndex - 1);
BigDecimal preRkQ = preVo.getYcRkQValue() != null ? preVo.getYcRkQValue() : BigDecimal.ZERO;
BigDecimal preCkQ = preVo.getYcCkQValue() != null ? preVo.getYcCkQValue() : BigDecimal.ZERO;
BigDecimal preGapQ = preRkQ.subtract(preCkQ);
if (eIndex == -1) { // 计算eTime到第一个整点的时间间隔分钟向下取整
eIndex = 0; // 如果没找到,从第一个开始 long minutesDiffFirst = ChronoUnit.MINUTES.between(eTime, firstWholeHourTime);
} // 累加第一段水量(分钟转为秒)
f = f.add(preGapQ.multiply(new BigDecimal(minutesDiffFirst * 60)));
// 计算e~b之间的净入库水量 // 2.2 计算第二段:第一个整点 到 后续数据的净入库水量19:00~20:00, 20:00~21:00...
for (int i = eIndex; i < filteredResults.size() - 1; i++) { for (int i = firstWholeHourIndex; i < filteredResults.size() - 1; i++) {
ForecastResultVo currentVo = filteredResults.get(i); ForecastResultVo currentVo = filteredResults.get(i);
BigDecimal ycRkQValue = currentVo.getYcRkQValue() != null ? currentVo.getYcRkQValue() : BigDecimal.ZERO; BigDecimal currentRkQ = currentVo.getYcRkQValue() != null ? currentVo.getYcRkQValue() : BigDecimal.ZERO;
BigDecimal ycCkQValue = currentVo.getYcCkQValue() != null ? currentVo.getYcCkQValue() : BigDecimal.ZERO; BigDecimal currentCkQ = currentVo.getYcCkQValue() != null ? currentVo.getYcCkQValue() : BigDecimal.ZERO;
BigDecimal currentGapQ = currentRkQ.subtract(currentCkQ);
// (入库流量 - 出库流量) * 时间间隔 // 整点间隔固定为timeInterval比如1小时
BigDecimal gapQValue = ycRkQValue.subtract(ycCkQValue); BigDecimal timeSum = currentGapQ.multiply(timeInterval);
if (i == eIndex) {
// 对于eIndex处的数据使用eTime与下一条数据的时间间隔
ForecastResultVo nextVo = filteredResults.get(i + 1);
LocalDateTime nextTime = LocalDateTime.parse(nextVo.getTm(), formatter);
// 计算eTime到nextTime的时间差小时
long minutesDiff = ChronoUnit.MINUTES.between(eTime, nextTime);
BigDecimal currentTimeInterval = BigDecimal.valueOf(minutesDiff).divide(BigDecimal.valueOf(60), 10, RoundingMode.HALF_UP);
BigDecimal timeSum = gapQValue.multiply(currentTimeInterval);
f = f.add(timeSum); f = f.add(timeSum);
} else { log.info("第" + i + "段水量(" + currentVo.getTm() + "~" + filteredResults.get(i+1).getTm() + "" + currentGapQ + " * " + timeInterval + " = " + timeSum);
// 其他情况使用固定的timeInterval
BigDecimal timeSum = gapQValue.multiply(timeInterval);
f = f.add(timeSum);
}
} }
// 3. 计算持续开闸时长g = f / 5 // 3. 计算持续开闸时长g = f / 5
@ -452,6 +450,7 @@ public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, F
} }
closeTime = closeTime.withSecond(0).withNano(0); closeTime = closeTime.withSecond(0).withNano(0);
end = closeTime; end = closeTime;
log.info("关闭时间2",end);
} }
}else{ }else{
@ -474,7 +473,7 @@ public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, F
BigDecimal ycCkQValue = currentVo.getYcCkQValue() != null ? currentVo.getYcCkQValue() : BigDecimal.ZERO; BigDecimal ycCkQValue = currentVo.getYcCkQValue() != null ? currentVo.getYcCkQValue() : BigDecimal.ZERO;
// (入库流量 - 出库流量) * 时间间隔 // (入库流量 - 出库流量) * 时间间隔
BigDecimal gapQValue = ycRkQValue.subtract(ycCkQValue).subtract(openDoorFlow); BigDecimal gapQValue = ycRkQValue.subtract(ycCkQValue);
BigDecimal timeSum = gapQValue.multiply(timeInterval); BigDecimal timeSum = gapQValue.multiply(timeInterval);
netInflow = netInflow.add(timeSum); netInflow = netInflow.add(timeSum);
} }
@ -514,7 +513,7 @@ public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, F
// 计算公式Vt+1 = Vt + (预测入库流量 - 预测出库流量 - 5) * 时间间隔 // 计算公式Vt+1 = Vt + (预测入库流量 - 预测出库流量 - 5) * 时间间隔
// 注意单位转换流量是m³/s库容是万m³时间间隔是秒 // 注意单位转换流量是m³/s库容是万m³时间间隔是秒
BigDecimal flowDiff = ycRkQValue.subtract(ycCkQValue).subtract(openDoorFlow); // m³/s BigDecimal flowDiff = ycRkQValue.subtract(ycCkQValue); // m³/s
BigDecimal volumeChange = flowDiff.multiply(timeInterval); // m³ BigDecimal volumeChange = flowDiff.multiply(timeInterval); // m³
// 转换为万m³1万m³ = 10000 m³ // 转换为万m³1万m³ = 10000 m³
@ -548,6 +547,9 @@ public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, F
} }
} }
} }
if(tTime == null){
tTime = timeCapacities.get(0).getTime();
}
if(tTime != null){ if(tTime != null){
//计算t0 //计算t0
BigDecimal tCapacity = timeCapacities.get(tIndex).getCapacity(); BigDecimal tCapacity = timeCapacities.get(tIndex).getCapacity();
@ -567,7 +569,7 @@ public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, F
BigDecimal tCkQ = tVo.getYcCkQValue() != null ? tVo.getYcCkQValue() : BigDecimal.ZERO; BigDecimal tCkQ = tVo.getYcCkQValue() != null ? tVo.getYcCkQValue() : BigDecimal.ZERO;
// 计算流量差 // 计算流量差
BigDecimal flowRateDiff = tRkQ.subtract(tCkQ).subtract(openDoorFlow); BigDecimal flowRateDiff = tRkQ.subtract(tCkQ);
// 计算t到t0的持续时长 // 计算t到t0的持续时长
BigDecimal durationSeconds = capacityDiffInM3.divide(flowRateDiff, 10, BigDecimal.ROUND_HALF_UP); BigDecimal durationSeconds = capacityDiffInM3.divide(flowRateDiff, 10, BigDecimal.ROUND_HALF_UP);
@ -739,7 +741,8 @@ public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, F
BigDecimal dtSeconds = maxNetWater.divide(openDoorFlow, 10, BigDecimal.ROUND_HALF_UP); BigDecimal dtSeconds = maxNetWater.divide(openDoorFlow, 10, BigDecimal.ROUND_HALF_UP);
// 向上取整 // 向上取整
long dtSecondsLong = dtSeconds.setScale(0, BigDecimal.ROUND_UP).longValue(); // 转为分钟,向上取整,再转为秒
long dtSecondsLong = dtSeconds.divide(new BigDecimal(60), 0, BigDecimal.ROUND_UP).longValue() * 60;
// 计算实际开闸时间j = t0 - dt // 计算实际开闸时间j = t0 - dt
LocalDateTime jTime = t0Time.minusSeconds(dtSecondsLong); LocalDateTime jTime = t0Time.minusSeconds(dtSecondsLong);
@ -927,24 +930,14 @@ public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, F
@Autowired @Autowired
private AttResBaseService attResBaseService; private AttResBaseService attResBaseService;
public ForecastDispatchResult getDispatchResult() { public ForecastDispatchResult getDispatchResult(DispatchResultDto dto) {
ForecastTask forecastTask = new ForecastTask(); ForecastProject forecastProjectResults = getForecastProjectResults(dto.getProjectId());
// 设置当前时间整点 List<ForecastResultVo> humanForecastResult = forecastProjectResults.getVoList();
LocalDateTime now = LocalDateTime.now(); if(humanForecastResult.isEmpty()){
LocalDateTime nowHour = now.withMinute(0).withSecond(0).withNano(0); throw new IllegalArgumentException("对不起,暂无预报数据");
forecastTask.setNowTime(LocalDateTimeConverter.toDate(nowHour)); }
Date forecastTm = forecastProjectResults.getForecastTm();
// 设置开始时间(当前时间减去一天) LocalDateTime nowHour = LocalDateTimeConverter.fromDate(forecastTm);
LocalDateTime startTime = nowHour.minusDays(1);
forecastTask.setStartTime(LocalDateTimeConverter.toDate(startTime));
// 设置结束时间当前时间加上durationHours
LocalDateTime endTime = nowHour.plusHours(24);
forecastTask.setEndTime(LocalDateTimeConverter.toDate(endTime));
forecastTask.setForecastWarm(1);
forecastTask.setForecastPeriod(24); // 设置预报时长
List<ForecastResultVo> humanForecastResult = forecastResultsService.getHumanForecastResult(forecastTask);
//过滤出大于等于nowHour的数据 //过滤出大于等于nowHour的数据
// 获取当前时间的格式化字符串与tm格式一致 // 获取当前时间的格式化字符串与tm格式一致
String nowHourStr = nowHour.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); String nowHourStr = nowHour.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
@ -979,13 +972,6 @@ public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, F
LocalDateTime maxRKDate = null; LocalDateTime maxRKDate = null;
BigDecimal totalRKWater = BigDecimal.ZERO; BigDecimal totalRKWater = BigDecimal.ZERO;
BigDecimal totalCKWater = BigDecimal.ZERO; BigDecimal totalCKWater = BigDecimal.ZERO;
BigDecimal maxRz = BigDecimal.ZERO;
LocalDateTime maxRzDate = null;
BigDecimal overLimit = BigDecimal.ZERO;
LocalDateTime start = null;
LocalDateTime end = null;
AttResBase attResBase = attResBaseService.list().get(0);
BigDecimal flLowLimLev = attResBase.getFlLowLimLev();//汛限水位
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
for (int i = 0; i < filteredResults.size(); i++) { for (int i = 0; i < filteredResults.size(); i++) {
ForecastResultVo vo = filteredResults.get(i); ForecastResultVo vo = filteredResults.get(i);
@ -993,60 +979,68 @@ public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, F
//计算总入库水量和总出库水量 //计算总入库水量和总出库水量
BigDecimal ycRkQValue = vo.getYcRkQValue(); BigDecimal ycRkQValue = vo.getYcRkQValue();
BigDecimal ycCkQValue = vo.getYcCkQValue(); BigDecimal ycCkQValue = vo.getYcCkQValue();
ycRkQValue = ycRkQValue.multiply(timeInterval).divide(new BigDecimal("10000")).setScale(2, BigDecimal.ROUND_HALF_UP); ycRkQValue = ycRkQValue.multiply(timeInterval);
totalRKWater = totalRKWater.add(ycRkQValue); totalRKWater = totalRKWater.add(ycRkQValue);
ycCkQValue = ycCkQValue.multiply(timeInterval).divide(new BigDecimal("10000")).setScale(2, BigDecimal.ROUND_HALF_UP); ycCkQValue = ycCkQValue.multiply(timeInterval);
totalCKWater = totalCKWater.add(ycCkQValue); totalCKWater = totalCKWater.add(ycCkQValue);
} }
//最高库水位
if(vo.getYcSwHValue().compareTo(maxRz) > 0){
maxRz = vo.getYcSwHValue();
maxRzDate = LocalDateTime.parse(vo.getTm(),formatter);
}
//最大入库流量 //最大入库流量
if(vo.getYcRkQValue().compareTo(maxRKQ) >0){ if(vo.getYcRkQValue().compareTo(maxRKQ) >0){
maxRKQ = vo.getYcRkQValue(); maxRKQ = vo.getYcRkQValue();
maxRKDate = LocalDateTime.parse(vo.getTm(),formatter); maxRKDate = LocalDateTime.parse(vo.getTm(),formatter);
} }
if(start == null){
if(vo.getYcSwHValue().compareTo(flLowLimLev) > 0){
start = LocalDateTime.parse(vo.getTm(),formatter);
}
}
if(vo.getYcSwHValue().compareTo(flLowLimLev) > 0){
//如果预测水位高于汛限水位
BigDecimal gap = vo.getYcSwHValue().subtract(flLowLimLev);
if(gap.compareTo(overLimit) > 0){
overLimit = gap;
}
} }
if(start != null && end == null){ DateTimeRangeSo dateTimeRangeSo = dto.getDateTimeRangeSo();
if(vo.getYcSwHValue().compareTo(flLowLimLev) <= 0){ if(dateTimeRangeSo != null){
end = LocalDateTime.parse(vo.getTm(),formatter); Date start = dateTimeRangeSo.getStart();
} Date end = dateTimeRangeSo.getEnd();
} long timeSeconds = (end.getTime() - start.getTime()) / 1000;
totalCKWater = totalCKWater.add(new BigDecimal("5").multiply(new BigDecimal(timeSeconds)));
} }
result.setTotalOutflowVolume(totalCKWater.divide(new BigDecimal("10000").setScale(2,RoundingMode.HALF_UP)));
result.setTotalInflowVolume(totalRKWater.divide(new BigDecimal("10000").setScale(2,RoundingMode.HALF_UP)));
result.setMaxInflow(maxRKQ); result.setMaxInflow(maxRKQ);
if(maxRKQ.compareTo(BigDecimal.ZERO) == 0){ if(maxRKQ.compareTo(BigDecimal.ZERO) == 0){
result.setMaxInflowDate(nowHour); result.setMaxInflowDate(nowHour);
}else{ }else{
result.setMaxInflowDate(maxRKDate); result.setMaxInflowDate(maxRKDate);
} }
result.setExceedLimitStart(start); return result;
result.setExceedLimitEnd(end);
if(start == null && end == null){
result.setExceedLimitValue(null);
}else{
result.setExceedLimitValue(overLimit);
} }
result.setMaxReservoirLevel(maxRz); public ForecastProject getForecastProjectResults(String projectId) {
result.setMaxReservoirLevelDate(maxRzDate); ForecastProject forecastProject = getById(projectId);
if (Objects.isNull(forecastProject)) {
result.setTotalInflowVolume(totalRKWater); throw new IllegalArgumentException("抱歉,该预报方案不存在");
result.setTotalOutflowVolume(totalCKWater); }
return result; List<ForecastResults> resultList = forecastResultsService.list(new QueryWrapper<ForecastResults>().eq("project_id", projectId).orderBy(true, true, "tm"));
if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isNotEmpty(resultList)) {
List<ForecastResultVo> vos = resultList.stream()
.map(result -> {
ForecastResultVo vo = new ForecastResultVo();
vo.setTm(sdf.format(result.getTm()));
vo.setYcRkQValue(result.getYcRkQValue());
vo.setRealRkQValue(result.getRealRkQValue());
vo.setYcCkQValue(result.getYcCkQValue());
vo.setRealCkQValue(result.getRealCkQValue());
vo.setYcSwHValue(result.getYcSwHValue());
vo.setRealSwHValue(result.getRealSwHValue());
BigDecimal ycSwHValue = result.getYcSwHValue() == null ? BigDecimal.ZERO : result.getYcSwHValue();
BigDecimal realSwHValue = result.getRealSwHValue() == null ? BigDecimal.ZERO : result.getRealSwHValue();
vo.setSwHDValue(ycSwHValue.subtract(realSwHValue));// 处理预测与实测水位差
vo.setDrp(result.getDrp());
vo.setIspreDrp(result.getIspreDrp());
vo.setR(result.getR());
vo.setFlLowLimLev(result.getFlLowLimLev());
vo.setCurrentYdgdyjz(result.getCurrentYdgdyjz());
vo.setPa(result.getPa());
return vo;
}).collect(Collectors.toList());
forecastProject.setVoList(vos);
forecastResultsService.handleVoList(forecastProject);
}
return forecastProject;
} }
// 页码事件处理器 - 简化版本 // 页码事件处理器 - 简化版本