更新洪水预报代码-copy from tsg

master
yangzhe123 2025-10-13 10:01:13 +08:00
parent 322ad91129
commit 29a0b7bd42
6 changed files with 475 additions and 89 deletions

View File

@ -46,7 +46,7 @@ public class RiverWaterController {
return R.ok(riverWaterService.list()); return R.ok(riverWaterService.list());
} }
@Get(path = "/zqrl", summary = "水位流量关系") @Get(path = "/zqrl", summary = "某个站点的水位流量关系曲线")
public R<List<StZqrlB>> zqrl(@Schema(name = "stcd") @RequestParam("stcd") String stcd) { public R<List<StZqrlB>> zqrl(@Schema(name = "stcd") @RequestParam("stcd") String stcd) {
return R.ok(riverWaterService.zqrl(stcd)); return R.ok(riverWaterService.zqrl(stcd));
} }

View File

@ -15,7 +15,7 @@ public class AttRiverNowDataVo extends StPptnRReal {
private Date waterTm; private Date waterTm;
@Schema(description = "监测水位") @Schema(description = "监测水位")
private BigDecimal waterVal; private BigDecimal rz;
@Schema(description = "警戒水位") @Schema(description = "警戒水位")

View File

@ -105,4 +105,16 @@ public class ForecastResultVo {
*/ */
@Schema(description = "水库当前库容") @Schema(description = "水库当前库容")
private BigDecimal nowCap; private BigDecimal nowCap;
/**
* R
*/
@Schema(description = "累积R")
private BigDecimal rSum;
/**
* P
*/
@Schema(description = "累积P")
private BigDecimal pSum = BigDecimal.ZERO;
} }

View File

@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gunshi.algorithm.RrainfallForecast; import com.gunshi.algorithm.RrainfallForecast;
import com.gunshi.algorithm.RunoffService; import com.gunshi.algorithm.RunoffService;
import com.gunshi.model.vo.FloodAlgorithemVo; import com.gunshi.model.vo.FloodAlgorithemVo;
import com.gunshi.project.hsz.service.*;
import com.gunshi.project.hsz.entity.vo.ForeRainStatVo; import com.gunshi.project.hsz.entity.vo.ForeRainStatVo;
import com.gunshi.project.hsz.entity.vo.ForeRainTimeVo; import com.gunshi.project.hsz.entity.vo.ForeRainTimeVo;
import com.gunshi.project.hsz.entity.vo.ForecastResultVo; import com.gunshi.project.hsz.entity.vo.ForecastResultVo;
@ -113,7 +114,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
/** /**
* @description: * @description:
* @param forecastTask * @param forecastTask
* @return: java.util.List<com.gunshi.project.hsz.entity.vo.ForecastResultVo> * @return: java.util.List<com.gunshi.project.xyt.entity.vo.ForecastResultVo>
* @auther: cxw * @auther: cxw
* @date: 2024-07-31, , 11:09:24 * @date: 2024-07-31, , 11:09:24
*/ */
@ -139,7 +140,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
/** /**
* @description: ForecastResultVo * @description: ForecastResultVo
* @param forecastTask * @param forecastTask
* @return: java.util.List<com.gunshi.project.hsz.entity.vo.ForecastResultVo> * @return: java.util.List<com.gunshi.project.xyt.entity.vo.ForecastResultVo>
* @auther: cxw * @auther: cxw
* @date: 2024-08-05, , 17:14:52 * @date: 2024-08-05, , 17:14:52
*/ */
@ -153,7 +154,9 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
// 获取系统当前的水库站编码、汛限水位 // 获取系统当前的水库站编码、汛限水位
AttResBase attResBase = attResBaseService.getOne(new QueryWrapper<>()); AttResBase attResBase = attResBaseService.getOne(new QueryWrapper<>());
// 多站点水库面雨量 // 多站点水库面雨量
List<StStbprpB> stbs = stStbprpBService.list(new QueryWrapper<StStbprpB>().eq("res_code", attResBase.getResCode())); // List<StStbprpB> stbs = stStbprpBService.list(new QueryWrapper<StStbprpB>().eq("res_code", attResBase.getResCode()));
// 单站点
List<StStbprpB> stbs = stStbprpBService.list(new QueryWrapper<StStbprpB>().eq("stcd", attResBase.getStcd()));
if (CollectionUtils.isEmpty(stbs)) { if (CollectionUtils.isEmpty(stbs)) {
return voList; return voList;
} }
@ -193,7 +196,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
qwExisted = new QueryWrapper<StPptnR>().in("stcd", stbs.stream().map(StStbprpB::getStcd).toArray(String[]::new)).ge("tm", startTime).le("tm", nowHourTime).orderBy(true, true, "tm"); qwExisted = new QueryWrapper<StPptnR>().in("stcd", stbs.stream().map(StStbprpB::getStcd).toArray(String[]::new)).ge("tm", startTime).le("tm", nowHourTime).orderBy(true, true, "tm");
// 获取预报数据 // 获取预报数据
try { try {
pptnRFutureList = getForecastDrpData(nowHourTime, ""); pptnRFutureList = getForecastDrpData(nowHourTime, attResBase.getStcd());
if(CollectionUtils.isEmpty(pptnRFutureList)) { if(CollectionUtils.isEmpty(pptnRFutureList)) {
isHaveFuturePPtn = false; isHaveFuturePPtn = false;
log.error("该时间无预报数据"); log.error("该时间无预报数据");
@ -226,7 +229,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
double dt = 0.0; double dt = 0.0;
double Wm = 0.0; double Wm = 0.0;
double qOther = 0.0; double qOther = 0.0;
Map<String, String> paramMap = paramList.stream().collect(Collectors.toMap(ForecastUseparam::getParamCode, ForecastUseparam::getParamValue)); Map<String, String> paramMap = paramList.stream().collect(Collectors.toMap(ForecastUseparam::getParamCode, ForecastUseparam::getParamValue, (existing, replacement) -> existing));
if (paramMap.get("dt").isEmpty()) { if (paramMap.get("dt").isEmpty()) {
throw new IllegalArgumentException("温馨提示当前洪水预报所依赖的数据尚不完整请检查时间单元△T是否缺失。"); throw new IllegalArgumentException("温馨提示当前洪水预报所依赖的数据尚不完整请检查时间单元△T是否缺失。");
} }
@ -237,6 +240,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
qOther = Double.parseDouble(paramMap.get("qOther")); qOther = Double.parseDouble(paramMap.get("qOther"));
} }
dt = Double.parseDouble(paramMap.get("dt")); dt = Double.parseDouble(paramMap.get("dt"));
// dt = Double.parseDouble("1.0");
Wm = Double.parseDouble(paramMap.get("Im")); Wm = Double.parseDouble(paramMap.get("Im"));
List<ForecastU> uList = forecastUService.list(); List<ForecastU> uList = forecastUService.list();
if (CollectionUtils.isEmpty(uList)) { if (CollectionUtils.isEmpty(uList)) {
@ -253,7 +257,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
if (CollectionUtils.isEmpty(paList)) { if (CollectionUtils.isEmpty(paList)) {
throw new IllegalArgumentException("温馨提示当前洪水预报所依赖的数据尚不完整请检查每日土壤含水量Pa是否缺失。"); throw new IllegalArgumentException("温馨提示当前洪水预报所依赖的数据尚不完整请检查每日土壤含水量Pa是否缺失。");
} }
Map<String, ForecastPa> paMap = paList.stream().collect(Collectors.toMap(ForecastPa::getTm, entity -> entity)); Map<String, ForecastPa> paMap = paList.stream().collect(Collectors.toMap(ForecastPa::getTm, entity -> entity, (existing, replacement) -> existing));
// 获取预测开始时间前的最后水库水位 // 获取预测开始时间前的最后水库水位
double H1 = 0.0;// 初始水库水位可以根据H1->V1,H1->q1得到初始的水库库容和下泄流量 double H1 = 0.0;// 初始水库水位可以根据H1->V1,H1->q1得到初始的水库库容和下泄流量
StRsvrR rsvrR = stRsvrRService.getOne(new QueryWrapper<StRsvrR>().eq("stcd", attResBase.getStcd()).le("tm", startTime).orderBy(true, false, "tm").last("limit 1")); StRsvrR rsvrR = stRsvrRService.getOne(new QueryWrapper<StRsvrR>().eq("stcd", attResBase.getStcd()).le("tm", startTime).orderBy(true, false, "tm").last("limit 1"));
@ -269,7 +273,15 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
List<StRsvrR> rsvrRRealList = stRsvrRService.list(new QueryWrapper<StRsvrR>().eq("stcd", attResBase.getStcd()).ge("tm", startTime).le("tm", endTime)); List<StRsvrR> rsvrRRealList = stRsvrRService.list(new QueryWrapper<StRsvrR>().eq("stcd", attResBase.getStcd()).ge("tm", startTime).le("tm", endTime));
List<StRsvrR> resultList = reorganizeRsvrRData(rsvrRRealList, dt); List<StRsvrR> resultList = reorganizeRsvrRData(rsvrRRealList, dt);
List<Date[]> periods = splitByDay8To8(startTime, endTime); List<Date[]> periods = splitByDay8To8(startTime, endTime);
for (Date[] period : periods) { // v累计降雨
BigDecimal vValue = BigDecimal.ZERO;
BigDecimal vSum = BigDecimal.ZERO;
// Rsum累计径流深
BigDecimal Rsum = BigDecimal.ZERO;
BigDecimal Psum = BigDecimal.ZERO;
// 存储最后u的长度-1个r值
for (int k = 0; k < periods.size(); k++) {
Date[] period = periods.get(k);
Calendar calNew = Calendar.getInstance(); Calendar calNew = Calendar.getInstance();
calNew.setTime(period[0]); calNew.setTime(period[0]);
// 根据每段时间的开始时间如果在08点前则采用前一天的pa值计算 // 根据每段时间的开始时间如果在08点前则采用前一天的pa值计算
@ -299,22 +311,48 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
if (ObjectUtils.isEmpty(retMap.get("listForReal"))) { if (ObjectUtils.isEmpty(retMap.get("listForReal"))) {
continue; continue;
} }
Map<String, String> pRealMap = retMap.get("listForReal").stream().collect(Collectors.toMap(pptnR -> sdfMinute.format(pptnR.getTm()), StPptnR::getDrp)); Map<String, String> pRealMap = retMap.get("listForReal").stream().collect(Collectors.toMap(pptnR -> sdfMinute.format(pptnR.getTm()), StPptnR::getDrp, (existing, replacement) -> existing));
double[] PList = pForecastList.stream().mapToDouble(Double::parseDouble).toArray(); double[] PList = pForecastList.stream().mapToDouble(Double::parseDouble).toArray();
vSum = vSum.add(vValue);
vValue = BigDecimal.ZERO;
for (double value : PList) {
BigDecimal bd = BigDecimal.valueOf(value);
// 累加到总和中
vValue = vValue.add(bd);
}
// 存储上一次的径流深r最开始默认全部为0
List<Double> lastRArr = new ArrayList<>();
for (int i = 0; i < u.length - 1; i++) {
lastRArr.add(0.0); // 填充初始值
}
// 从后往前遍历不定长的实体列表
for (int i = voList.size() - 1; i >= 0; i--) {
int index = lastRArr.size() - 1 - (voList.size() - 1 - i);
lastRArr.set(index, voList.get(i).getR().doubleValue());
if(index <= 0){
break;
}
}
// 预测执行 // 预测执行
List<FloodAlgorithemVo> forecastVoList = RrainfallForecast.getData(sdf.format(period[0]), forecastPa.getK().doubleValue(), forecastPa.getPa0().doubleValue(), Wm, forecastPa.getPt0().doubleValue(), H1, dt, List<FloodAlgorithemVo> forecastVoList = RrainfallForecast.getData(sdf.format(period[0]), forecastPa.getK().doubleValue(), forecastPa.getPa0().doubleValue(), Wm, forecastPa.getPt0().doubleValue(), H1, dt,
forecastPa.getPa().doubleValue(), PList, u, attResBase.getStcd(), qOther); forecastPa.getPa().doubleValue(), PList, u, attResBase.getStcd(), qOther, vSum.doubleValue(), Rsum.doubleValue(), lastRArr);
if (CollectionUtils.isNotEmpty(forecastVoList)) { if (CollectionUtils.isNotEmpty(forecastVoList)) {
// 筛选同时段的真实水位数据 // 筛选同时段的真实水位数据
List<StRsvrR> realRsvrList = resultList.stream().filter(item -> item.getTm().compareTo(period[0]) >= 0 && item.getTm().compareTo(period[1]) <= 0).collect(Collectors.toList()); List<StRsvrR> realRsvrList = resultList.stream().filter(item -> item.getTm().compareTo(period[0]) >= 0 && item.getTm().compareTo(period[1]) <= 0).collect(Collectors.toList());
Map<String, String> realRsvrMap = realRsvrList.stream().collect(Collectors.toMap(rsvr -> sdfMinute.format(rsvr.getTm()), StRsvrR::getRz)); Map<String, String> realRsvrMap = realRsvrList.stream().collect(Collectors.toMap(rsvr -> sdfMinute.format(rsvr.getTm()), StRsvrR::getRz, (existing, replacement) -> existing));
forecastVoList = forecastVoList.subList(0, PList.length); forecastVoList = forecastVoList.subList(0, PList.length + 1);
// 去除预测出来的最后一条与第二次实际的相同时间的数据 // 去除预测出来的最后一条与第二次实际的相同时间的数据
if (voList.size() > 0 && voList.get(voList.size() - 1).getTm().equals(forecastVoList.get(0).getDateStr())) { if (voList.size() > 0 && voList.get(voList.size() - 1).getTm().equals(forecastVoList.get(0).getDateStr())) {
voList.remove(voList.size() - 1); voList.remove(voList.size() - 1);
} }
for (int j = 0; j < forecastVoList.size(); j++) { for (int j = 0; j < forecastVoList.size(); j++) {
FloodAlgorithemVo floodAlgorithemVo = forecastVoList.get(j); FloodAlgorithemVo floodAlgorithemVo = forecastVoList.get(j);
// dt不同预测结果的条数不同跟new_q参数有关
if (floodAlgorithemVo.getDateStr().substring(0, 15).compareTo(sdfMinute.format(period[1])) > 0) {
break;
}
String dateStr = floodAlgorithemVo.getDateStr(); String dateStr = floodAlgorithemVo.getDateStr();
ForecastResultVo resultVo = new ForecastResultVo(); ForecastResultVo resultVo = new ForecastResultVo();
resultVo.setTm(dateStr); resultVo.setTm(dateStr);
@ -338,7 +376,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
if (realSwHValue.compareTo(minZ) < 0 || realSwHValue.compareTo(maxZ) > 0) { if (realSwHValue.compareTo(minZ) < 0 || realSwHValue.compareTo(maxZ) > 0) {
resultVo.setRealCkQValue(BigDecimal.ZERO);// 真实出库流量 resultVo.setRealCkQValue(BigDecimal.ZERO);// 真实出库流量
} else { } else {
Map<BigDecimal, BigDecimal> stZvalMap = stZqrlBList.stream().collect(Collectors.toMap(StZqrlB::getZ, StZqrlB::getQ)); Map<BigDecimal, BigDecimal> stZvalMap = stZqrlBList.stream().collect(Collectors.toMap(StZqrlB::getZ, StZqrlB::getQ, (existing, replacement) -> existing));
List<BigDecimal> list = stZqrlBList.stream().map(StZqrlB::getZ).collect(Collectors.toList()); List<BigDecimal> list = stZqrlBList.stream().map(StZqrlB::getZ).collect(Collectors.toList());
resultVo.setRealCkQValue(DataHandleUtil.calcData(realSwHValue, stZvalMap, list));// 真实出库流量 resultVo.setRealCkQValue(DataHandleUtil.calcData(realSwHValue, stZvalMap, list));// 真实出库流量
} }
@ -347,15 +385,28 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
// 没有真实水位就用预测水位算(作为预测库容) // 没有真实水位就用预测水位算(作为预测库容)
calculateCap(zvarlBS, resultVo, resultVo.getYcSwHValue()); calculateCap(zvarlBS, resultVo, resultVo.getYcSwHValue());
} }
BigDecimal drp = new BigDecimal(pRealMap.get(dateMinuteStr));// 根据时间取更准确
String pRealDrp = "0.0";
if (pRealMap.containsKey(dateMinuteStr)) {
pRealDrp = pRealMap.get(dateMinuteStr);
}
BigDecimal drp = new BigDecimal(pRealDrp);// 根据时间取更准确
if (drp.compareTo(BigDecimal.ZERO) < 0) { if (drp.compareTo(BigDecimal.ZERO) < 0) {
resultVo.setDrp(null); resultVo.setDrp(BigDecimal.ZERO);
} else { } else {
resultVo.setDrp(drp); resultVo.setDrp(drp);
} }
Psum = Psum.add(resultVo.getDrp());
resultVo.setPSum(Psum);
Date dateTm = sdf.parse(floodAlgorithemVo.getDateStr()); Date dateTm = sdf.parse(floodAlgorithemVo.getDateStr());
resultVo.setIspreDrp(dateTm.compareTo(nowHourTime) <= 0 ? "0" : "1");// 0真实 1预测 resultVo.setIspreDrp(dateTm.compareTo(nowHourTime) <= 0 ? "0" : "1");// 0真实 1预测
resultVo.setR(floodAlgorithemVo.getR()); resultVo.setR(floodAlgorithemVo.getR());
if (resultVo.getR() != null) {
Rsum = Rsum.add(resultVo.getR());
} else {
continue;
}
resultVo.setRSum(Rsum);
resultVo.setFlLowLimLev(attResBase.getFlLowLimLev()); resultVo.setFlLowLimLev(attResBase.getFlLowLimLev());
resultVo.setCurrentYdgdyjz(MapUtil.get(paramMap, "ydgdyjz", BigDecimal.class, BigDecimal.ZERO)); resultVo.setCurrentYdgdyjz(MapUtil.get(paramMap, "ydgdyjz", BigDecimal.class, BigDecimal.ZERO));
resultVo.setPa(floodAlgorithemVo.getPa()); resultVo.setPa(floodAlgorithemVo.getPa());
@ -366,6 +417,300 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
return voList; return voList;
} }
private List<Map<String, Object>> excuteForecastDebug(ForecastTask forecastTask) throws Exception {
List<ForecastResultVo> voList = new ArrayList<>();
// 获取配置参数
List<ForecastUseparam> paramList = forecastUseparamService.list(new QueryWrapper<ForecastUseparam>().isNotNull("param_code").isNotNull("param_value"));
if (CollectionUtils.isEmpty(paramList)) {
throw new IllegalArgumentException("温馨提示:当前洪水预报所依赖的数据尚不完整,请检查入参是否缺失。");
}
// 获取系统当前的水库站编码、汛限水位
AttResBase attResBase = attResBaseService.getOne(new QueryWrapper<>());
// 多站点水库面雨量
// List<StStbprpB> stbs = stStbprpBService.list(new QueryWrapper<StStbprpB>().eq("res_code", attResBase.getResCode()));
// 单站点
List<StStbprpB> stbs = stStbprpBService.list(new QueryWrapper<StStbprpB>().eq("stcd", attResBase.getStcd()));
if (CollectionUtils.isEmpty(stbs)) {
return null;
}
Date nowHourTime = forecastTask.getNowTime();
Date startTime = forecastTask.getStartTime();
Date endTime = forecastTask.getEndTime();
// 获取整个时间线的降雨数据
List<StPptnR> pptnRAllList = new ArrayList<>();
List<StPptnR> pptnRFutureList = new ArrayList<>();
QueryWrapper<StPptnR> qwExisted = new QueryWrapper<>();
Boolean isHaveFuturePPtn = true;
// 檀树岗修改实测降雨查询表数据预测降雨使用geom参数。最后按时间算数平均
// for(StStbprpB b : stbs){
// String stcd = b.getStcd();
// // 如果结束时间在当前时间之前,降雨序列从历史降雨表获取
// if (endTime.compareTo(nowHourTime) <= 0) {
// qwExisted = new QueryWrapper<StPptnR>().eq("stcd", stcd).ge("tm", startTime).le("tm", endTime).orderBy(true, true, "tm");
// } else {
// qwExisted = new QueryWrapper<StPptnR>().eq("stcd", stcd).ge("tm", startTime).le("tm", nowHourTime).orderBy(true, true, "tm");
// try {
// // 获取预报数据
// pptnRFutureList = getForecastDrpData(nowHourTime, stcd);
// } catch (IllegalArgumentException e) {
// if(stcd.equals(attResBase.getStcd())){
// isHaveFuturePPtn = false;
// }
// log.error("该时间无预报数据");
// }
// }
// List<StPptnR> pptnRExistedList = stPptnRService.list(qwExisted);
// pptnRAllList.addAll(pptnRExistedList);
// pptnRAllList.addAll(pptnRFutureList);
// }
if (endTime.compareTo(nowHourTime) <= 0) {
qwExisted = new QueryWrapper<StPptnR>().in("stcd", stbs.stream().map(StStbprpB::getStcd).toArray(String[]::new)).ge("tm", startTime).le("tm", endTime).orderBy(true, true, "tm");
} else {
qwExisted = new QueryWrapper<StPptnR>().in("stcd", stbs.stream().map(StStbprpB::getStcd).toArray(String[]::new)).ge("tm", startTime).le("tm", nowHourTime).orderBy(true, true, "tm");
// 获取预报数据
try {
pptnRFutureList = getForecastDrpData(nowHourTime, attResBase.getStcd());
if(CollectionUtils.isEmpty(pptnRFutureList)) {
isHaveFuturePPtn = false;
log.error("该时间无预报数据");
}
} catch (IllegalArgumentException e) {
isHaveFuturePPtn = false;
log.error("该时间无预报数据");
}
}
List<StPptnR> pptnRExistedList = stPptnRService.list(qwExisted);
pptnRAllList.addAll(pptnRExistedList);
pptnRAllList.addAll(pptnRFutureList);
if (CollectionUtils.isEmpty(pptnRAllList)) {
return null;
}
// 多站点面雨量结果list
List<StPptnR> polyPptnRList = pptnRAllList.stream()
.collect(Collectors.groupingBy(
StPptnR::getTm,
Collectors.mapping(
pptn -> Double.parseDouble(pptn.getDrp()), // 将String转换为double
Collectors.averagingDouble(d -> d) // 计算平均值
)
))
.entrySet().stream()
.map(entry -> new StPptnRAverage(entry.getKey(), String.valueOf(entry.getValue())))
.sorted(Comparator.comparing(StPptnRAverage::getTm))
.collect(Collectors.toList());
double dt = 0.0;
double Wm = 0.0;
double qOther = 0.0;
Map<String, String> paramMap = paramList.stream().collect(Collectors.toMap(ForecastUseparam::getParamCode, ForecastUseparam::getParamValue, (existing, replacement) -> existing));
if (paramMap.get("dt").isEmpty()) {
throw new IllegalArgumentException("温馨提示当前洪水预报所依赖的数据尚不完整请检查时间单元△T是否缺失。");
}
if (paramMap.get("Im").isEmpty()) {
throw new IllegalArgumentException("温馨提示当前洪水预报所依赖的数据尚不完整请检查最大初损值Im是否缺失。");
}
if (!paramMap.get("qOther").isEmpty()) {
qOther = Double.parseDouble(paramMap.get("qOther"));
}
dt = Double.parseDouble(paramMap.get("dt"));
// dt = Double.parseDouble("1.0");
Wm = Double.parseDouble(paramMap.get("Im"));
List<ForecastU> uList = forecastUService.list();
if (CollectionUtils.isEmpty(uList)) {
throw new IllegalArgumentException("温馨提示当前洪水预报所依赖的数据尚不完整请检查U(I)单位线是否缺失。");
}
// 每小时的单位径流量单位m³/s
double[] u = uList.stream().mapToDouble(forecastU -> forecastU.getUValue().doubleValue()).toArray();
// 根据开始结束时间查询pa
Calendar cal = Calendar.getInstance();
cal.setTime(startTime);
// 将日期往前推一天
cal.add(Calendar.DATE, -1);
List<ForecastPa> paList = forecastPaService.list(new QueryWrapper<ForecastPa>().eq("stcd", attResBase.getStcd()).ge("tm", sdfDay.format(cal.getTime())).le("tm", sdfDay.format(endTime)));
if (CollectionUtils.isEmpty(paList)) {
throw new IllegalArgumentException("温馨提示当前洪水预报所依赖的数据尚不完整请检查每日土壤含水量Pa是否缺失。");
}
Map<String, ForecastPa> paMap = paList.stream().collect(Collectors.toMap(ForecastPa::getTm, entity -> entity, (existing, replacement) -> existing));
// 获取预测开始时间前的最后水库水位
double H1 = 0.0;// 初始水库水位可以根据H1->V1,H1->q1得到初始的水库库容和下泄流量
StRsvrR rsvrR = stRsvrRService.getOne(new QueryWrapper<StRsvrR>().eq("stcd", attResBase.getStcd()).le("tm", startTime).orderBy(true, false, "tm").last("limit 1"));
if (ObjectUtils.isEmpty(rsvrR)) {
return null;
}
H1 = Double.parseDouble(rsvrR.getRz());
// 泄流量
List<StZqrlB> stZqrlBList = stZqrlBService.list(new QueryWrapper<StZqrlB>().eq("stcd", attResBase.getStcd()).orderBy(true, true, "z"));
// 库容曲线
List<StZvarlB> zvarlBS = stZvarlBService.list(new QueryWrapper<StZvarlB>().eq("stcd", attResBase.getStcd()).orderBy(true, true, "rz"));
// 水位历史数据
List<StRsvrR> rsvrRRealList = stRsvrRService.list(new QueryWrapper<StRsvrR>().eq("stcd", attResBase.getStcd()).ge("tm", startTime).le("tm", endTime));
List<StRsvrR> resultList = reorganizeRsvrRData(rsvrRRealList, dt);
List<Date[]> periods = splitByDay8To8(startTime, endTime);
// v累计降雨
BigDecimal vValue = BigDecimal.ZERO;
BigDecimal vSum = BigDecimal.ZERO;
// Rsum累计径流深
BigDecimal Rsum = BigDecimal.ZERO;
BigDecimal Psum = BigDecimal.ZERO;
List<Map<String, Object>> res = new ArrayList<>();
// 存储最后u的长度-1个r值
for (int k = 0; k < periods.size(); k++) {
Date[] period = periods.get(k);
Calendar calNew = Calendar.getInstance();
calNew.setTime(period[0]);
// 根据每段时间的开始时间如果在08点前则采用前一天的pa值计算
if (isBeforeEightAM(period[0])) {
// 将日期往前推一天
calNew.add(Calendar.DATE, -1);
}
ForecastPa forecastPa = paMap.get(sdfDay.format(calNew.getTime()));
if (ObjectUtils.isEmpty(forecastPa)) {
continue;
// throw new IllegalArgumentException("温馨提示当前洪水预报所依赖的数据尚不完整请检查每日土壤含水量Pa、K值是否缺失。");
}
// 根据降雨数据按照△t的颗粒度均分
// 筛选时间段内的降雨数据。不包前但包后
List<StPptnR> filterList = polyPptnRList.stream().filter(e -> e.getTm().compareTo(period[0]) >= 0).filter(e -> e.getTm().compareTo(period[1]) <= 0).collect(Collectors.toList());
Map<String, List<StPptnR>> retMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(filterList)) {
retMap = reorganizePptnRData(filterList, dt, period[0], period[1], nowHourTime, isHaveFuturePPtn);
}
if (ObjectUtils.isEmpty(retMap.get("listForForecast"))) {
continue;
}
List<String> pForecastList = retMap.get("listForForecast").stream().map(s -> s.getDrp()).collect(Collectors.toList());
if (pForecastList.size() == 0) {
continue;
}
if (ObjectUtils.isEmpty(retMap.get("listForReal"))) {
continue;
}
Map<String, String> pRealMap = retMap.get("listForReal").stream().collect(Collectors.toMap(pptnR -> sdfMinute.format(pptnR.getTm()), StPptnR::getDrp, (existing, replacement) -> existing));
double[] PList = pForecastList.stream().mapToDouble(Double::parseDouble).toArray();
vSum = vSum.add(vValue);
vValue = BigDecimal.ZERO;
for (double value : PList) {
BigDecimal bd = BigDecimal.valueOf(value);
// 累加到总和中
vValue = vValue.add(bd);
}
// 存储上一次的径流深r最开始默认全部为0
List<Double> lastRArr = new ArrayList<>();
for (int i = 0; i < u.length - 1; i++) {
lastRArr.add(0.0); // 填充初始值
}
// 从后往前遍历不定长的实体列表
for (int i = voList.size() - 1; i >= 0; i--) {
int index = lastRArr.size() - 1 - (voList.size() - 1 - i);
lastRArr.set(index, voList.get(i).getR().doubleValue());
if(index <= 0){
break;
}
}
// 预测执行
Map<String,Object> map = new HashMap<>();
map.put("in period" + k, sdf.format(period[0]));
map.put("in K" + k, forecastPa.getK().doubleValue());
map.put("in pa0" + k, forecastPa.getPa0().doubleValue());
map.put("in Wm" + k, Wm);
map.put("in pt0" + k, forecastPa.getPt0().doubleValue());
map.put("in H1" + k, H1);
map.put("in dt" + k, dt);
map.put("in pa" + k, forecastPa.getPa().doubleValue());
map.put("in PList" + k, PList);
map.put("in u" + k, u);
map.put("in stcd" + k, attResBase.getStcd());
map.put("in qOther" + k, qOther);
map.put("in vSum" + k, vSum.doubleValue());
map.put("in Rsum" + k, Rsum.doubleValue());
map.put("in lastRArr" + k, lastRArr);
List<FloodAlgorithemVo> forecastVoList = RrainfallForecast.getData(sdf.format(period[0]), forecastPa.getK().doubleValue(), forecastPa.getPa0().doubleValue(), Wm, forecastPa.getPt0().doubleValue(), H1, dt,
forecastPa.getPa().doubleValue(), PList, u, attResBase.getStcd(), qOther, vSum.doubleValue(), Rsum.doubleValue(), lastRArr);
map.put("out res" + k, forecastVoList);
res.add(map);
if (CollectionUtils.isNotEmpty(forecastVoList)) {
// 筛选同时段的真实水位数据
List<StRsvrR> realRsvrList = resultList.stream().filter(item -> item.getTm().compareTo(period[0]) >= 0 && item.getTm().compareTo(period[1]) <= 0).collect(Collectors.toList());
Map<String, String> realRsvrMap = realRsvrList.stream().collect(Collectors.toMap(rsvr -> sdfMinute.format(rsvr.getTm()), StRsvrR::getRz, (existing, replacement) -> existing));
forecastVoList = forecastVoList.subList(0, PList.length + 1);
// 去除预测出来的最后一条与第二次实际的相同时间的数据
if (voList.size() > 0 && voList.get(voList.size() - 1).getTm().equals(forecastVoList.get(0).getDateStr())) {
voList.remove(voList.size() - 1);
}
for (int j = 0; j < forecastVoList.size(); j++) {
FloodAlgorithemVo floodAlgorithemVo = forecastVoList.get(j);
// dt不同预测结果的条数不同跟new_q参数有关
if (floodAlgorithemVo.getDateStr().substring(0, 15).compareTo(sdfMinute.format(period[1])) > 0) {
break;
}
String dateStr = floodAlgorithemVo.getDateStr();
ForecastResultVo resultVo = new ForecastResultVo();
resultVo.setTm(dateStr);
resultVo.setYcRkQValue(floodAlgorithemVo.getRq());// 预测入库流量
// resultVo.setRealRkQValue();// 暂无真实入库流量
resultVo.setYcCkQValue(floodAlgorithemVo.getCq());// 预测出库流量
resultVo.setYcSwHValue(floodAlgorithemVo.getKh());// 预测水库水位
H1 = resultVo.getYcSwHValue().doubleValue();// 以预测水位作为下一次预测段起始值
String dateMinuteStr = dateStr.substring(0, dateStr.length() - 3);// 年月日 时分
if (realRsvrMap.containsKey(dateMinuteStr)) {
BigDecimal realSwHValue = new BigDecimal(realRsvrMap.get(dateMinuteStr));// 根据时间取更准确
resultVo.setRealSwHValue(realSwHValue);// 真实水库水位
calculateCap(zvarlBS, resultVo, realSwHValue);// 有真实水位就用真实水位算(作为实测库容)
resultVo.setSwHDValue(resultVo.getYcSwHValue().subtract(resultVo.getRealSwHValue()));// 预测与真实水位差
// 注释修复跨8点时的陡升陡降
// H1 = realSwHValue.doubleValue();// 如果有真实水位,将最后一条的真实水位作为下一次预测段的初始水位
// 真实出库流量=真实水库水位与泄流量曲线差值法
if (realSwHValue != null && CollectionUtils.isNotEmpty(stZqrlBList)) {
BigDecimal maxZ = stZqrlBList.stream().max(Comparator.comparing(StZqrlB::getZ)).get().getZ();
BigDecimal minZ = stZqrlBList.stream().min(Comparator.comparing(StZqrlB::getZ)).get().getZ();
if (realSwHValue.compareTo(minZ) < 0 || realSwHValue.compareTo(maxZ) > 0) {
resultVo.setRealCkQValue(BigDecimal.ZERO);// 真实出库流量
} else {
Map<BigDecimal, BigDecimal> stZvalMap = stZqrlBList.stream().collect(Collectors.toMap(StZqrlB::getZ, StZqrlB::getQ, (existing, replacement) -> existing));
List<BigDecimal> list = stZqrlBList.stream().map(StZqrlB::getZ).collect(Collectors.toList());
resultVo.setRealCkQValue(DataHandleUtil.calcData(realSwHValue, stZvalMap, list));// 真实出库流量
}
}
} else {
// 没有真实水位就用预测水位算(作为预测库容)
calculateCap(zvarlBS, resultVo, resultVo.getYcSwHValue());
}
String pRealDrp = "0.0";
if (pRealMap.containsKey(dateMinuteStr)) {
pRealDrp = pRealMap.get(dateMinuteStr);
}
BigDecimal drp = new BigDecimal(pRealDrp);// 根据时间取更准确
if (drp.compareTo(BigDecimal.ZERO) < 0) {
resultVo.setDrp(BigDecimal.ZERO);
} else {
resultVo.setDrp(drp);
}
Psum = Psum.add(resultVo.getDrp());
resultVo.setPSum(Psum);
Date dateTm = sdf.parse(floodAlgorithemVo.getDateStr());
resultVo.setIspreDrp(dateTm.compareTo(nowHourTime) <= 0 ? "0" : "1");// 0真实 1预测
resultVo.setR(floodAlgorithemVo.getR());
if (resultVo.getR() != null) {
Rsum = Rsum.add(resultVo.getR());
} else {
continue;
}
resultVo.setRSum(Rsum);
resultVo.setFlLowLimLev(attResBase.getFlLowLimLev());
resultVo.setCurrentYdgdyjz(MapUtil.get(paramMap, "ydgdyjz", BigDecimal.class, BigDecimal.ZERO));
resultVo.setPa(floodAlgorithemVo.getPa());
voList.add(resultVo);
}
}
}
return res;
}
/** /**
* @description: * @description:
* @param zvarlBS 线 * @param zvarlBS 线
@ -382,7 +727,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
if(rz.compareTo(minRz) < 0 || rz.compareTo(maxRz) > 0){ if(rz.compareTo(minRz) < 0 || rz.compareTo(maxRz) > 0){
return; return;
} }
Map<BigDecimal, BigDecimal> stZvalMap = zvarlBS.stream().collect(Collectors.toMap(StZvarlB::getRz, StZvarlB::getW)); Map<BigDecimal, BigDecimal> stZvalMap = zvarlBS.stream().collect(Collectors.toMap(StZvarlB::getRz, StZvarlB::getW, (existing, replacement) -> existing));
List<BigDecimal> list = zvarlBS.stream().map(StZvarlB::getRz).sorted().collect(Collectors.toList()); List<BigDecimal> list = zvarlBS.stream().map(StZvarlB::getRz).sorted().collect(Collectors.toList());
resultVo.setNowCap(DataHandleUtil.calcData(rz,stZvalMap,list)); resultVo.setNowCap(DataHandleUtil.calcData(rz,stZvalMap,list));
} }
@ -452,7 +797,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
* @description: T * @description: T
* @param rsvrRRealList * @param rsvrRRealList
* @param dt * @param dt
* @return: java.util.List<com.gunshi.project.hsz.model.StRsvrR> * @return: java.util.List<com.gunshi.project.xyt.model.StRsvrR>
* @auther: cxw * @auther: cxw
*/ */
private List<StRsvrR> reorganizeRsvrRData(List<StRsvrR> rsvrRRealList, double dt) { private List<StRsvrR> reorganizeRsvrRData(List<StRsvrR> rsvrRRealList, double dt) {
@ -513,10 +858,11 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
* @param endTm * @param endTm
* @param nowHourTime * @param nowHourTime
* @param isHaveFuturePPtn * @param isHaveFuturePPtn
* @return: java.util.List<com.gunshi.project.hsz.model.StPptnR> * @return: java.util.List<com.gunshi.project.xyt.model.StPptnR>
* @auther: cxw * @auther: cxw
*/ */
private Map<String, List<StPptnR>> reorganizePptnRData(List<StPptnR> filterList, double dt, Date startTm, Date endTm, Date nowHourTime, Boolean isHaveFuturePPtn) { private Map<String, List<StPptnR>> reorganizePptnRData(List<StPptnR> filterList, double dt, Date startTm, Date endTm, Date nowHourTime, Boolean isHaveFuturePPtn) {
// 目前dt适配0.5和1
// 只保留整小时的数据 // 只保留整小时的数据
filterList = filterList.stream().filter(entity -> { filterList = filterList.stream().filter(entity -> {
Date date = entity.getTm(); Date date = entity.getTm();
@ -528,7 +874,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
)).values().stream().collect(Collectors.toList()); )).values().stream().collect(Collectors.toList());
filterList.sort(Comparator.comparing(StPptnR::getTm)); filterList.sort(Comparator.comparing(StPptnR::getTm));
Map<String, List<StPptnR>> retMap = new HashMap<>(); Map<String, List<StPptnR>> retMap = new HashMap<>();
Map<String, String> tmDrpMap = filterList.stream().collect(Collectors.toMap(pptnR -> sdfMinute.format(pptnR.getTm()), StPptnR::getDrp)); Map<String, String> tmDrpMap = filterList.stream().collect(Collectors.toMap(pptnR -> sdfMinute.format(pptnR.getTm()), StPptnR::getDrp, (existing, replacement) -> existing));
List<StPptnR> listForForecast = new ArrayList<>();// 传给预测程序使用缺失的数据为0 List<StPptnR> listForForecast = new ArrayList<>();// 传给预测程序使用缺失的数据为0
List<StPptnR> listForReal = new ArrayList<>();// 返回给前端数据使用缺失的数据为null List<StPptnR> listForReal = new ArrayList<>();// 返回给前端数据使用缺失的数据为null
Calendar calendar = Calendar.getInstance(); Calendar calendar = Calendar.getInstance();
@ -549,17 +895,20 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
StPptnR stPptnRHour = new StPptnR(); StPptnR stPptnRHour = new StPptnR();
stPptnRHour.setTm(calendar.getTime());// 整点时间 stPptnRHour.setTm(calendar.getTime());// 整点时间
String dataTmDrpHalf = tmDrpMap.get(sdfMinute.format(calendar.getTime())); String dataTmDrpHalf = tmDrpMap.get(sdfMinute.format(calendar.getTime()));
BigDecimal drp = new BigDecimal(dataTmDrpHalf).divide(new BigDecimal(2), 2, BigDecimal.ROUND_HALF_UP); // 按照dt分
BigDecimal drp = new BigDecimal(dataTmDrpHalf).multiply(new BigDecimal(dt));
shareDrp = String.valueOf(drp); shareDrp = String.valueOf(drp);
stPptnRHalf.setDrp(shareDrp); stPptnRHalf.setDrp(shareDrp);
stPptnRHour.setDrp(shareDrp); stPptnRHour.setDrp(shareDrp);
// 往前推半小时 // 往前推半小时
calendar.add(Calendar.MINUTE, -(int) (dt * 60)); calendar.add(Calendar.MINUTE, -(int) (dt * 60));
stPptnRHalf.setTm(calendar.getTime()); stPptnRHalf.setTm(calendar.getTime());
// 先存半小时数据 if (BigDecimal.ONE.compareTo(BigDecimal.valueOf(dt)) != 0) {
// 存半小时数据
listForForecast.add(stPptnRHalf); listForForecast.add(stPptnRHalf);
listForReal.add(stPptnRHalf); listForReal.add(stPptnRHalf);
// 再存整小时数据 }
// 存整小时数据
listForForecast.add(stPptnRHour); listForForecast.add(stPptnRHour);
listForReal.add(stPptnRHour); listForReal.add(stPptnRHour);
} else { } else {
@ -573,12 +922,14 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
calendar.add(Calendar.MINUTE, -(int) (dt * 60)); calendar.add(Calendar.MINUTE, -(int) (dt * 60));
stPptnRHalfForecast.setTm(calendar.getTime()); stPptnRHalfForecast.setTm(calendar.getTime());
stPptnRHalfReal.setTm(calendar.getTime()); stPptnRHalfReal.setTm(calendar.getTime());
// 先存半小时数据 if(BigDecimal.ONE.compareTo(BigDecimal.valueOf(dt)) != 0){
// 存半小时数据
stPptnRHalfForecast.setDrp("0.00"); stPptnRHalfForecast.setDrp("0.00");
listForForecast.add(stPptnRHalfForecast); listForForecast.add(stPptnRHalfForecast);
stPptnRHalfReal.setDrp("-1"); stPptnRHalfReal.setDrp("-1");
listForReal.add(stPptnRHalfReal); listForReal.add(stPptnRHalfReal);
// 再存整小时数据 }
// 存整小时数据
stPptnRHourForecast.setDrp("0.00"); stPptnRHourForecast.setDrp("0.00");
listForForecast.add(stPptnRHourForecast); listForForecast.add(stPptnRHourForecast);
stPptnRHourReal.setDrp("-1"); stPptnRHourReal.setDrp("-1");
@ -767,4 +1118,5 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
jsonBuilder.append("}"); // 闭合JSON对象 jsonBuilder.append("}"); // 闭合JSON对象
return jsonBuilder.toString(); return jsonBuilder.toString();
} }
} }

View File

@ -144,6 +144,7 @@ public class RiverWaterService {
BigDecimal oldRz = attRvBaseMapper.oldRz(stcd,1,Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant())); BigDecimal oldRz = attRvBaseMapper.oldRz(stcd,1,Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant()));
if(oldRz != null){ if(oldRz != null){
//设置水位涨跌情况
vo.setRzDiff(rz.subtract(oldRz)); vo.setRzDiff(rz.subtract(oldRz));
} }
//本年最高水位 //本年最高水位
@ -193,7 +194,7 @@ public class RiverWaterService {
return vo; return vo;
} }
BigDecimal z = stRiverRReal.getZ() == null ? BigDecimal.ZERO : stRiverRReal.getZ(); BigDecimal z = stRiverRReal.getZ() == null ? BigDecimal.ZERO : stRiverRReal.getZ();
vo.setWaterVal(z); vo.setRz(z);
vo.setWaterAlarmGap(z.subtract(vo.getWaterAlarm())); vo.setWaterAlarmGap(z.subtract(vo.getWaterAlarm()));
vo.setWaterPromiseGap(z.subtract(vo.getWaterPromise())); vo.setWaterPromiseGap(z.subtract(vo.getWaterPromise()));
return vo; return vo;

View File

@ -132,71 +132,92 @@ public class StZqrlBService extends ServiceImpl<StZqrlBMapper, StZqrlB> {
} }
public BigDecimal getQByZqrl(List<StZqrlB> zqrlBList, BigDecimal rz) { public BigDecimal getQByZqrl(List<StZqrlB> zqrlBList, BigDecimal rz) {
int l =0; // 1. 参数校验
int r = zqrlBList.size() - 1; if (zqrlBList == null || zqrlBList.isEmpty()) {
if(rz.compareTo(zqrlBList.get(0).getZ()) < 0){ throw new IllegalArgumentException("水位-流量关系列表不能为空");
}
if (rz == null) {
throw new IllegalArgumentException("水位值不能为空");
}
// 2. 检查边界情况:如果目标水位低于最低水位或高于最高水位
BigDecimal minRz = zqrlBList.get(0).getZ();
BigDecimal maxRz = zqrlBList.get(zqrlBList.size() - 1).getZ();
if (rz.compareTo(minRz) < 0) {
// 低于最低水位返回0流量
return BigDecimal.ZERO; return BigDecimal.ZERO;
} }
//使用二分法,来获取 避免On的查询时间复杂度 if (rz.compareTo(maxRz) > 0) {
while(l < r){ // 高于最高水位返回0流量
return BigDecimal.ZERO;
}
// 3. 二分查找水位区间
int l = 0;
int r = zqrlBList.size() - 1;
while (l <= r) {
int mid = l + (r - l) / 2; int mid = l + (r - l) / 2;
if(zqrlBList.get(mid).getZ().compareTo(rz) ==0){ BigDecimal midRz = zqrlBList.get(mid).getZ();
int compareResult = midRz.compareTo(rz);
if (compareResult == 0) {
// 找到完全匹配的水位,直接返回对应的流量
return zqrlBList.get(mid).getQ(); return zqrlBList.get(mid).getQ();
}else if(zqrlBList.get(mid).getZ().compareTo(rz) >0){ } else if (compareResult < 0) {
r = mid - 1;
}else{
l = mid + 1; l = mid + 1;
}
}
// 现在 l 是最接近的索引,但需要比较前后三个值
int closestIndex = l;
// 处理边界情况
if (l == 0) {
// 只有第一个元素,或者比较第一个和第二个哪个更接近
if (zqrlBList.size() > 1) {
BigDecimal diff1 = rz.subtract(zqrlBList.get(0).getZ()).abs();
BigDecimal diff2 = rz.subtract(zqrlBList.get(1).getZ()).abs();
closestIndex = diff1.compareTo(diff2) <= 0 ? 0 : 1;
}
//TODO 这里找到最接近的值后,仍然要通过公式,计算出真正的流量
return zqrlBList.get(closestIndex).getQ();
}
if (l == zqrlBList.size() - 1) {
// 只有最后一个元素,或者比较最后两个哪个更接近
if (zqrlBList.size() > 1) {
BigDecimal diff1 = rz.subtract(zqrlBList.get(l - 1).getZ()).abs();
BigDecimal diff2 = rz.subtract(zqrlBList.get(l).getZ()).abs();
closestIndex = diff1.compareTo(diff2) <= 0 ? l - 1 : l;
}
//TODO 这里找到最接近的值后,仍然要通过公式,计算出真正的流量
return zqrlBList.get(closestIndex).getQ();
}
// 正常情况:比较前一个、当前、后一个三个值,找到最接近的
BigDecimal preVal = zqrlBList.get(l - 1).getZ();
BigDecimal curVal = zqrlBList.get(l).getZ();
BigDecimal nextVal = zqrlBList.get(l + 1).getZ();
//计算他们与目标的插值
BigDecimal diffPre = rz.subtract(preVal).abs();
BigDecimal diffCur = rz.subtract(curVal).abs();
BigDecimal diffNext = rz.subtract(nextVal).abs();
// 找到最小的差值
if (diffPre.compareTo(diffCur) <= 0 && diffPre.compareTo(diffNext) <= 0) {
closestIndex = l - 1;
} else if (diffCur.compareTo(diffPre) <= 0 && diffCur.compareTo(diffNext) <= 0) {
closestIndex = l;
} else { } else {
closestIndex = l + 1; r = mid - 1;
}
} }
//TODO 这里找到最接近的值后,仍然要通过公式,计算出真正的流量 /**
*
* l rz
* r rz
* r (x1, y1) -
* l (x2, y2) -
*/
if (l >= zqrlBList.size() || r < 0) {
return BigDecimal.ZERO;
}
return zqrlBList.get(closestIndex).getQ(); // 获取前后相邻的两个点
StZqrlB lowerPoint = zqrlBList.get(r);
StZqrlB upperPoint = zqrlBList.get(l);
// 使用线性插值计算流量
return linearInterpolation(
lowerPoint.getZ(), lowerPoint.getQ(),
upperPoint.getZ(), upperPoint.getQ(),
rz
).setScale(3, RoundingMode.HALF_UP);
}
/**
* 线
* @param x1 1
* @param y1 1
* @param x2 2
* @param y2 2
* @param x
* @return
*/
private BigDecimal linearInterpolation(BigDecimal x1, BigDecimal y1,
BigDecimal x2, BigDecimal y2,
BigDecimal x) {
// 使用公式: y = y1 + ( (y2 - y1) / (x2 - x1) ) * (x - x1)
// 计算斜率: (y2 - y1) / (x2 - x1)
BigDecimal slope = y2.subtract(y1)
.divide(x2.subtract(x1), 10, RoundingMode.HALF_UP);
// 计算: slope * (x - x1)
BigDecimal xDiff = x.subtract(x1);
BigDecimal product = slope.multiply(xDiff);
// 计算最终结果: y1 + product
return y1.add(product);
} }
/** /**