2025-07-17 15:26:39 +08:00
|
|
|
|
package com.gunshi.project.hsz.service;
|
2024-07-08 17:47:02 +08:00
|
|
|
|
|
|
|
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
2025-07-17 15:26:39 +08:00
|
|
|
|
import com.gunshi.project.hsz.entity.vo.RsvrComplexVo;
|
|
|
|
|
|
import com.gunshi.project.hsz.mapper.StZqrlBMapper;
|
|
|
|
|
|
import com.gunshi.project.hsz.model.StRsvrR;
|
|
|
|
|
|
import com.gunshi.project.hsz.model.StZqrlB;
|
2024-07-08 17:47:02 +08:00
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
|
2025-04-08 17:59:39 +08:00
|
|
|
|
import java.math.BigDecimal;
|
|
|
|
|
|
import java.math.RoundingMode;
|
2025-09-16 14:25:13 +08:00
|
|
|
|
import java.time.Duration;
|
2025-04-08 17:59:39 +08:00
|
|
|
|
import java.util.*;
|
|
|
|
|
|
import java.util.stream.Collectors;
|
2024-07-08 17:47:02 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 描述: 水位流量关系曲线表
|
|
|
|
|
|
* author: xusan
|
|
|
|
|
|
* date: 2024-07-08 17:30:38
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Service
|
|
|
|
|
|
@Slf4j
|
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
2025-04-08 17:59:39 +08:00
|
|
|
|
public class StZqrlBService extends ServiceImpl<StZqrlBMapper, StZqrlB> {
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 计算溢洪量
|
2025-04-09 14:01:44 +08:00
|
|
|
|
*
|
2025-04-08 17:59:39 +08:00
|
|
|
|
* @param rz 计算溢洪的起始水位
|
|
|
|
|
|
* @param seconds 溢洪时间,是两条水位数据的时间差,单位秒
|
|
|
|
|
|
* @param zqrlList 水位流量关系曲线
|
|
|
|
|
|
* @return 溢洪量
|
|
|
|
|
|
* @author lyf
|
|
|
|
|
|
*/
|
|
|
|
|
|
public BigDecimal calculateSpilledVolume(BigDecimal rz, long seconds, List<StZqrlB> zqrlList) {
|
|
|
|
|
|
return getQFromZqrl(rz, zqrlList).multiply(BigDecimal.valueOf(seconds));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 计算溢洪量
|
2025-04-09 14:01:44 +08:00
|
|
|
|
*
|
|
|
|
|
|
* @param rz 计算溢洪的起始水位
|
|
|
|
|
|
* @param seconds 溢洪时间,是两条水位数据的时间差,单位秒
|
2025-04-08 17:59:39 +08:00
|
|
|
|
* @return 溢洪量
|
|
|
|
|
|
* @author lyf
|
|
|
|
|
|
*/
|
|
|
|
|
|
public BigDecimal calculateSpilledVolume(BigDecimal rz, long seconds) {
|
|
|
|
|
|
return calculateSpilledVolume(rz, seconds, list());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 批量计算溢洪量
|
2025-04-09 14:01:44 +08:00
|
|
|
|
*
|
2025-04-08 17:59:39 +08:00
|
|
|
|
* @param rsvrList 要计算的水位数据
|
|
|
|
|
|
* @param zqrlList 水位流量关系曲线
|
|
|
|
|
|
* @return 计算后的水位数据(时间倒序),含每条水位对应的流量和与上一条水位对应的溢洪量
|
2025-04-09 14:01:44 +08:00
|
|
|
|
* @author lyf
|
2025-04-08 17:59:39 +08:00
|
|
|
|
*/
|
|
|
|
|
|
public List<RsvrComplexVo> calculateSpilledVolumeList(List<StRsvrR> rsvrList, List<StZqrlB> zqrlList) {
|
|
|
|
|
|
rsvrList.sort(Comparator.comparing(StRsvrR::getTm).reversed());
|
|
|
|
|
|
List<RsvrComplexVo> ret = new ArrayList<>();
|
|
|
|
|
|
for (int i = 0; i < rsvrList.size(); i++) {
|
|
|
|
|
|
StRsvrR rsvr = rsvrList.get(i);
|
|
|
|
|
|
BigDecimal rz = new BigDecimal(rsvr.getRz());
|
|
|
|
|
|
Date tm = rsvr.getTm();
|
|
|
|
|
|
RsvrComplexVo vo = RsvrComplexVo.of(rz, tm);
|
2025-09-16 14:25:13 +08:00
|
|
|
|
BigDecimal q = getQFromZqrl(rz, zqrlList);
|
|
|
|
|
|
//TODO 这个需要公式进行对水位->流量的转换
|
2025-04-08 17:59:39 +08:00
|
|
|
|
if (i == 0) {
|
|
|
|
|
|
vo.setQ(getQFromZqrl(rz, zqrlList));
|
|
|
|
|
|
vo.setSv(BigDecimal.ZERO);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
StRsvrR rsvrPrev = rsvrList.get(i - 1);
|
|
|
|
|
|
Date tmPrev = rsvrPrev.getTm();
|
|
|
|
|
|
long seconds = tm.getTime() - tmPrev.getTime();
|
|
|
|
|
|
vo.setQ(getQFromZqrl(rz, zqrlList));
|
2025-09-16 14:25:13 +08:00
|
|
|
|
//TODO 这里有个函数调用,记得到时候也替换一下计算公式
|
2025-04-08 17:59:39 +08:00
|
|
|
|
vo.setSv(calculateSpilledVolume(rz, seconds));
|
|
|
|
|
|
}
|
|
|
|
|
|
ret.add(vo);
|
|
|
|
|
|
}
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 批量计算溢洪量
|
2025-04-09 14:01:44 +08:00
|
|
|
|
*
|
2025-04-08 17:59:39 +08:00
|
|
|
|
* @param rsvrList 要计算的水位数据
|
|
|
|
|
|
* @return 计算后的水位数据(时间倒序),含每条水位对应的流量和与上一条水位对应的溢洪量
|
2025-04-09 14:01:44 +08:00
|
|
|
|
* @author lyf
|
2025-04-08 17:59:39 +08:00
|
|
|
|
*/
|
|
|
|
|
|
public List<RsvrComplexVo> calculateSpilledVolumeList(List<StRsvrR> rsvrList) {
|
|
|
|
|
|
return calculateSpilledVolumeList(rsvrList, list());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-09 14:01:44 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 根据水位查表得流量
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param rz 水位
|
|
|
|
|
|
* @return 查表流量
|
|
|
|
|
|
* @author lyf
|
|
|
|
|
|
*/
|
2025-04-08 17:59:39 +08:00
|
|
|
|
public BigDecimal getQFromZqrl(BigDecimal rz) {
|
|
|
|
|
|
return getQFromZqrl(rz, list());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-09 14:01:44 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 根据水位查表得流量
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param rz 水位
|
|
|
|
|
|
* @param zqrlList 水位流量关系曲线
|
|
|
|
|
|
* @return 查表流量
|
|
|
|
|
|
* @author lyf
|
|
|
|
|
|
*/
|
2025-04-08 17:59:39 +08:00
|
|
|
|
public BigDecimal getQFromZqrl(BigDecimal rz, List<StZqrlB> zqrlList) {
|
|
|
|
|
|
return toMap(zqrlList).getOrDefault(rz.setScale(3, RoundingMode.DOWN), BigDecimal.ZERO);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-09 14:01:44 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 将水位流量曲线列表转为字典,水位作为键,注意BigDecimal做键的时候要匹配值和精度
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param zqrlList 水位流量曲线列表
|
|
|
|
|
|
* @return 水位流量曲线字典
|
|
|
|
|
|
* @author lyf
|
|
|
|
|
|
*/
|
2025-04-08 17:59:39 +08:00
|
|
|
|
private Map<BigDecimal, BigDecimal> toMap(List<StZqrlB> zqrlList) {
|
|
|
|
|
|
return zqrlList.stream()
|
|
|
|
|
|
.map(item -> Map.entry(item.getZ().setScale(3, RoundingMode.DOWN), item.getQ()))
|
|
|
|
|
|
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
|
|
|
|
|
}
|
2024-07-08 17:47:02 +08:00
|
|
|
|
|
2025-09-16 14:25:13 +08:00
|
|
|
|
public BigDecimal getQByZqrl(List<StZqrlB> zqrlBList, BigDecimal rz) {
|
2025-10-13 10:01:13 +08:00
|
|
|
|
// 1. 参数校验
|
|
|
|
|
|
if (zqrlBList == null || zqrlBList.isEmpty()) {
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (rz.compareTo(maxRz) > 0) {
|
|
|
|
|
|
// 高于最高水位,返回0流量
|
2025-09-16 14:25:13 +08:00
|
|
|
|
return BigDecimal.ZERO;
|
|
|
|
|
|
}
|
2025-10-13 10:01:13 +08:00
|
|
|
|
|
|
|
|
|
|
// 3. 二分查找水位区间
|
|
|
|
|
|
int l = 0;
|
|
|
|
|
|
int r = zqrlBList.size() - 1;
|
|
|
|
|
|
|
|
|
|
|
|
while (l <= r) {
|
2025-09-16 14:25:13 +08:00
|
|
|
|
int mid = l + (r - l) / 2;
|
2025-10-13 10:01:13 +08:00
|
|
|
|
BigDecimal midRz = zqrlBList.get(mid).getZ();
|
|
|
|
|
|
int compareResult = midRz.compareTo(rz);
|
|
|
|
|
|
|
|
|
|
|
|
if (compareResult == 0) {
|
|
|
|
|
|
// 找到完全匹配的水位,直接返回对应的流量
|
2025-09-16 14:25:13 +08:00
|
|
|
|
return zqrlBList.get(mid).getQ();
|
2025-10-13 10:01:13 +08:00
|
|
|
|
} else if (compareResult < 0) {
|
2025-09-16 14:25:13 +08:00
|
|
|
|
l = mid + 1;
|
2025-10-13 10:01:13 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
r = mid - 1;
|
2025-09-16 14:25:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-13 10:01:13 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 此时:
|
|
|
|
|
|
* l 指向第一个大于rz的位置
|
|
|
|
|
|
* r 指向最后一个小于rz的位置
|
|
|
|
|
|
* 即:r为 (x1, y1) - 下限水位和流量
|
|
|
|
|
|
* l为 (x2, y2) - 上限水位和流量
|
|
|
|
|
|
*/
|
|
|
|
|
|
if (l >= zqrlBList.size() || r < 0) {
|
|
|
|
|
|
return BigDecimal.ZERO;
|
2025-09-16 14:25:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-13 10:01:13 +08:00
|
|
|
|
// 获取前后相邻的两个点
|
|
|
|
|
|
StZqrlB lowerPoint = zqrlBList.get(r);
|
|
|
|
|
|
StZqrlB upperPoint = zqrlBList.get(l);
|
2025-09-16 14:25:13 +08:00
|
|
|
|
|
2025-10-13 10:01:13 +08:00
|
|
|
|
// 使用线性插值计算流量
|
|
|
|
|
|
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);
|
2025-09-16 14:25:13 +08:00
|
|
|
|
|
2025-10-13 10:01:13 +08:00
|
|
|
|
// 计算: slope * (x - x1)
|
|
|
|
|
|
BigDecimal xDiff = x.subtract(x1);
|
|
|
|
|
|
BigDecimal product = slope.multiply(xDiff);
|
2025-09-16 14:25:13 +08:00
|
|
|
|
|
2025-10-13 10:01:13 +08:00
|
|
|
|
// 计算最终结果: y1 + product
|
|
|
|
|
|
return y1.add(product);
|
2025-09-16 14:25:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 计算累计溢洪量
|
|
|
|
|
|
* @param complexList
|
|
|
|
|
|
* @return
|
|
|
|
|
|
*/
|
|
|
|
|
|
public BigDecimal getFlowQSum(List<RsvrComplexVo> complexList) {
|
|
|
|
|
|
BigDecimal sum = BigDecimal.ZERO;
|
|
|
|
|
|
for (int i = 0; i < complexList.size(); i++) {
|
|
|
|
|
|
RsvrComplexVo current = complexList.get(i);
|
|
|
|
|
|
if (i == 0) {
|
|
|
|
|
|
// 第一条数据,累计量为0
|
|
|
|
|
|
sum = BigDecimal.ZERO;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
RsvrComplexVo previous = complexList.get(i - 1);
|
|
|
|
|
|
|
|
|
|
|
|
// 计算时间间隔(秒)
|
|
|
|
|
|
long timeDiffSeconds = Duration.between(previous.getTm().toInstant(),
|
|
|
|
|
|
current.getTm().toInstant()).getSeconds();
|
|
|
|
|
|
|
|
|
|
|
|
if (timeDiffSeconds > 0) {
|
|
|
|
|
|
// 使用梯形法则计算这段时间内的溢洪量:(上一个流量 + 当前流量) / 2 * 时间间隔
|
|
|
|
|
|
BigDecimal avgFlow = previous.getSv().add(current.getSv())
|
|
|
|
|
|
.divide(BigDecimal.valueOf(2), 10, RoundingMode.HALF_UP);
|
|
|
|
|
|
BigDecimal increment = avgFlow.multiply(BigDecimal.valueOf(timeDiffSeconds));
|
|
|
|
|
|
sum = sum.add(increment);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return sum;
|
|
|
|
|
|
}
|
2024-07-08 17:47:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|