优化人工洪水预报接口;增加人工、自动预报结果保存;增加预报方案结果查看接口

master
chenxiwang 2024-08-06 11:05:18 +08:00
parent 09a84fe1b8
commit 46c146b8bb
10 changed files with 404 additions and 219 deletions

View File

@ -1,14 +1,16 @@
package com.gunshi.project.xyt.controller;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gunshi.core.result.R;
import com.gunshi.project.xyt.entity.vo.ForecastResultVo;
import com.gunshi.project.xyt.model.ForecastProject;
import com.gunshi.project.xyt.model.ForecastResults;
import com.gunshi.project.xyt.model.ForecastTask;
import com.gunshi.project.xyt.service.ForecastProjectService;
import com.gunshi.project.xyt.service.ForecastResultsService;
import com.gunshi.project.xyt.validate.markers.Insert;
@ -18,10 +20,18 @@ import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.Serializable;
import java.util.List;
import java.util.Objects;
/**
* : _
* author: cxw
@ -89,4 +99,33 @@ public class ForecastProjectController {
return R.ok(service.page(forecastProject.getPageSo().toPage(), wrapper));
}
@Operation(summary = "保存人工交互洪水预报结果")
@PostMapping("/saveHumanForecastResults")
public R<ForecastProject> saveHumanForecastResults(@RequestBody @Validated ForecastProject forecastProject) {
if (CollectionUtils.isEmpty(forecastProject.getVoList())) {
throw new IllegalArgumentException("数据格式不正确");
}
forecastProject.setId(IdWorker.getId());
boolean result = service.save(forecastProject);
if (result) {
service.saveForecastResults(forecastProject);
}
return R.ok(result ? forecastProject : null);
}
@Operation(summary = "根据方案id查看方案洪水预报结果")
@PostMapping("/getForecastProjectResults")
public R<ForecastProject> getForecastProjectResults(@Schema(name = "projectId", description = "预测方案id") @RequestParam("projectId") String projectId) {
ForecastProject forecastProject = service.getById(projectId);
if (Objects.isNull(forecastProject)) {
throw new IllegalArgumentException("当前数据不存在");
}
List<ForecastResults> resultList = forecastResultsService.list(new QueryWrapper<ForecastResults>().eq("project_id", projectId));
if(CollectionUtils.isNotEmpty(resultList)) {
forecastProject.setVoList(JSON.parseArray(JSON.toJSONString(resultList), ForecastResultVo.class));
}
return R.ok(forecastProject);
}
}

View File

@ -4,14 +4,11 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gunshi.algorithm.RrainfallForecast;
import com.gunshi.core.result.R;
import com.gunshi.model.vo.FloodAlgorithemVo;
import com.gunshi.project.xyt.entity.vo.ForecastResultVo;
import com.gunshi.project.xyt.model.ForecastTask;
import com.gunshi.project.xyt.model.ForecastProject;
import com.gunshi.project.xyt.model.ForecastResults;
import com.gunshi.project.xyt.model.ForecastTask;
import com.gunshi.project.xyt.service.ForecastTaskService;
import com.gunshi.project.xyt.service.ForecastResultsService;
import com.gunshi.project.xyt.validate.markers.Insert;
import com.gunshi.project.xyt.validate.markers.Update;
@ -25,12 +22,9 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.Serializable;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.List;
/**
* : _
@ -42,14 +36,9 @@ import java.util.List;
@RequestMapping(value="/forecastResults")
public class ForecastResultsController {
private static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Autowired
private ForecastResultsService service;
@Autowired
private ForecastTaskService forecastTaskService;
@Operation(summary = "新增")
@PostMapping("/insert")
@ -84,7 +73,7 @@ public class ForecastResultsController {
@Operation(summary = "分页")
@PostMapping("/page")
public R<Page<ForecastResults>> page(@RequestBody @Validated ForecastResults forecastResults) {
QueryWrapper<ForecastResults> wrapper = new QueryWrapper<ForecastResults>();
QueryWrapper<ForecastResults> wrapper = new QueryWrapper<>();
if(StringUtils.isNotBlank(forecastResults.getSortField())){
wrapper.orderBy(true, ObjectUtils.isEmpty(forecastResults.getIsAsc()) ? false : forecastResults.getIsAsc(), forecastResults.getSortField());
}
@ -93,37 +82,17 @@ public class ForecastResultsController {
@Operation(summary = "获取人工交互洪水预报结果")
@PostMapping("/getHumanForecastResult")
public R<List<ForecastResultVo>> getHumanForecastResult(@RequestBody ForecastTask forecastTask) throws Exception {
public R<ForecastProject> getHumanForecastResult(@RequestBody ForecastTask forecastTask) throws Exception {
ForecastProject forecastProject = new ForecastProject();
List<ForecastResultVo> voList = service.getHumanForecastResult(forecastTask);
return R.ok(voList);
forecastProject.setType("2");
forecastProject.setForecastTm(forecastTask.getForecastTime());
forecastProject.setProjectTm(forecastTask.getNowTime());
forecastProject.setStartTm(forecastTask.getStartTime());
forecastProject.setEndTm(forecastTask.getEndTime());
forecastProject.setForecastPeriod(forecastTask.getForecastPeriod());
forecastProject.setForecastWarm(forecastTask.getForecastWarm());
forecastProject.setVoList(voList);
return R.ok(forecastProject);
}
// @Operation(summary = "查看方案洪水预报结果")
// @PostMapping("/getForecastTaskResult")
// public R<List<ForecastResultVo>> getForecastTaskResult(@Schema(name = "taskId", description = "预测方案id") @RequestParam("taskId") String taskId) throws Exception {
// ForecastTask forecastTask = forecastTaskService.getById(taskId);
// List<ForecastResultVo> voList = service.getForecastTaskResult(forecastTask);
// return R.ok(voList);
// }
// @Operation(summary = "洪水预报测试")
// @PostMapping("/forecastTest")
// public R<List<FloodAlgorithemVo>> forecastTest() throws Exception {
// double[] PList = new double[] {6.5, 6.75, 7, 5.25, 3.5, 4, 4.5, 4, 3.5, 4.25, 5, 4, 3, 3, 3, 2.75, 2.5, 1.25, 0, 0.25, 0.5};
// double[] u = new double[]{1.27, 0.75, 0.45, 0.27, 0.16, 0.09, 0.07, 0.03, 0.02, 0.01, 0.01};
// return R.ok(RrainfallForecast.getData("2024-06-28 08:00:00", 0.93, 1.0, 120, 0.0, 675.94, 0.5, 100.0, PList, u, "", "716153201"));
// }
// @Operation(summary = "洪水预报测试2")
// @PostMapping("/forecastTest2")
// public R<List<ForecastResultVo>> forecastTest2() throws Exception {
// DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// ForecastTask forecastTask = new ForecastTask();
// forecastTask.setForecastTm(dateFormat.parse("2024-07-01 22:00:00"));
// forecastTask.setStartTime(dateFormat.parse("2024-07-01 16:00:00"));
// forecastTask.setEndTime(dateFormat.parse("2024-07-02 03:00:00"));
// List<ForecastResultVo> forecastResultVos = service.humanFloodForecast(forecastTask);
// return R.ok(forecastResultVos);
// }
}

View File

@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
*@description VO
@ -20,7 +21,7 @@ public class ForecastResultVo {
*
*/
@Schema(description="时间")
private String tm;
private Date tm;
/**
*
@ -64,6 +65,12 @@ public class ForecastResultVo {
@Schema(description="降雨")
private BigDecimal drp;
/**
* (0 1)
*/
@Schema(description="是否是预测雨量(0真实 1预测)")
private String ispreDrp;
/**
*
*/
@ -75,4 +82,10 @@ public class ForecastResultVo {
*/
@Schema(description="主汛期防洪限制水位")
private BigDecimal flLowLimLev;
/**
*
*/
@Schema(description="土壤含水量")
private BigDecimal pa;
}

View File

@ -486,6 +486,13 @@ public class AttResBase implements Serializable {
@Size(max = 255,message = "adcd最大长度要小于 255")
private String adcd;
/**
* ,m
*/
@TableField(value="wcrstel")
@Schema(description="堰顶高程,m")
private BigDecimal wcrstel;
@TableField(exist = false)
@Schema(description = "文件集合")

View File

@ -10,6 +10,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.gunshi.core.dateformat.DateFormatString;
import com.gunshi.project.xyt.entity.page.GenericPageParams;
import com.gunshi.project.xyt.entity.vo.ForecastResultVo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
@ -17,7 +18,9 @@ import jakarta.validation.constraints.Size;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
* : _
@ -98,7 +101,7 @@ public class ForecastProject extends GenericPageParams implements Serializable {
*/
@TableField(value="user_id")
@Schema(description="操作人id")
private Integer userId;
private Long userId;
/**
* ()
@ -131,21 +134,11 @@ public class ForecastProject extends GenericPageParams implements Serializable {
private Date updateTm;
/**
* (0: 1: 2:)
*/
@TableField(value="status")
@Schema(description="任务状态(0:正常 1:暂停 2:删除)")
@Size(max = 1,message = "任务状态(0:正常 1:暂停 2:删除)最大长度要小于 1")
@NotBlank(message = "任务状态(0:正常 1:暂停 2:删除)不能为空")
@NotNull(message = "任务状态(0:正常 1:暂停 2:删除)不能为空")
private String status;
/**
* ()
* ()
*/
@TableField(value="time_interval")
@Schema(description="任务时间间隔(分钟)")
private Integer timeInterval;
@Schema(description="任务时间间隔(小时)")
private BigDecimal timeInterval;
/**
* idtype1
@ -154,4 +147,11 @@ public class ForecastProject extends GenericPageParams implements Serializable {
@Schema(description="自动任务idtype为1时有值")
private Long taskId;
/**
* voList
*/
@Schema(description = "预报结果voList")
@TableField(exist = false)
private List<ForecastResultVo> voList;
}

View File

@ -95,6 +95,13 @@ public class ForecastResults extends GenericPageParams implements Serializable {
@Schema(description="降雨")
private BigDecimal drp;
/**
* (0 1)
*/
@TableField(value="ispre_drp")
@Schema(description="是否是预测雨量(0真实 1预测)")
private String ispreDrp;
/**
*
*/
@ -132,4 +139,11 @@ public class ForecastResults extends GenericPageParams implements Serializable {
@Schema(description="主汛期防洪限制水位")
private BigDecimal flLowLimLev;
/**
*
*/
@TableField(value="pa")
@Schema(description="土壤含水量")
private BigDecimal pa;
}

View File

@ -95,10 +95,10 @@ public class ForecastTask extends GenericPageParams implements Serializable {
private String status;
/**
* ()
* ()
*/
@TableField(value="time_interval")
@Schema(description="任务时间间隔(分钟)")
@Schema(description="任务时间间隔(小时)")
private BigDecimal timeInterval;
/**
@ -109,6 +109,14 @@ public class ForecastTask extends GenericPageParams implements Serializable {
@TableField(exist = false)
private Date forecastTime;
/**
*
*/
@Schema(description = "选择的执行当前时间")
@JsonFormat(pattern = DateFormatString.YYYY_MM_DD_HH_MM_SS, timezone = "GMT+8")
@TableField(exist = false)
private Date nowTime;
/**
*
*/

View File

@ -1,8 +1,19 @@
package com.gunshi.project.xyt.schedule;
import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.gunshi.project.xyt.entity.vo.ForecastResultVo;
import com.gunshi.project.xyt.model.AttResBase;
import com.gunshi.project.xyt.model.ForecastProject;
import com.gunshi.project.xyt.model.ForecastTask;
import com.gunshi.project.xyt.model.ForecastUseparam;
import com.gunshi.project.xyt.service.AttResBaseService;
import com.gunshi.project.xyt.service.ForecastProjectService;
import com.gunshi.project.xyt.service.ForecastResultsService;
import com.gunshi.project.xyt.service.ForecastUseparamService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobDataMap;
@ -11,9 +22,13 @@ import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* @author cxw
@ -25,24 +40,90 @@ import java.util.List;
@Slf4j
public class TaskGroupJob implements Job {
private static DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static SimpleDateFormat sdfMinute = new SimpleDateFormat("yyyy-MM-dd HH:mm:00");
private static SimpleDateFormat sdfTime = new SimpleDateFormat("yyyyMMddHHmm");
@Autowired
private ForecastResultsService forecastResultsService;
@Autowired
private ForecastUseparamService forecastUseparamService;
@Autowired
private AttResBaseService attResBaseService;
@Autowired
private ForecastProjectService forecastProjectService;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDataMap jdMap = context.getJobDetail().getJobDataMap();
String jobId = (String) jdMap.get("jobId");
ForecastTask forecastTask = (ForecastTask) jdMap.get("forecastTask");
log.info("{}----TaskGroupJob-计划执行开始===>jobId:{}", dtf.format(LocalDateTime.now()), jobId);
// 根据执行时间、预热期、预见期获取对应的预报、开始、结束时间
// todo
log.info("{}----TaskGroupJob-计划执行开始===>jobId:{}", sdf.format(LocalDateTime.now()), jobId);
try {
List<ForecastResultVo> forecastResultVo = forecastResultsService.autoFloodForecast(forecastTask);
// 根据执行时间、预热期、预见期获取对应的预报、开始、结束时间
Date nowTime = sdfMinute.parse(sdf.format(new Date()));
Date forecastTime = nowTime;
Date startTime;
Date endTime;
Integer forecastPeriod = forecastTask.getForecastPeriod();// 预见期:小时
Integer forecastWarm = forecastTask.getForecastWarm();// 预热期:天
Calendar calendar = Calendar.getInstance();
calendar.setTime(nowTime);
// 预报时间就是当前时间
forecastTask.setNowTime(nowTime);
forecastTask.setForecastTime(nowTime);
// 预热期:往前推 天
calendar.add(calendar.DATE, - forecastWarm);
startTime = calendar.getTime();
forecastTask.setStartTime(startTime);
// 预见期:先恢复,再往后推 小时
calendar.setTime(nowTime);
calendar.add(calendar.HOUR_OF_DAY, forecastPeriod);
endTime = calendar.getTime();
forecastTask.setEndTime(endTime);
List<ForecastResultVo> voList = forecastResultsService.autoFloodForecast(forecastTask);
// 符合条件就保存到数据库
if (CollectionUtils.isNotEmpty(voList)) {
Map<String, Object> map = forecastUseparamService.getMap(new QueryWrapper<ForecastUseparam>().eq("param_code", "ydgdyjz"));// 获取安全值
AttResBase attResBase = attResBaseService.getOne(new QueryWrapper<>());// 获取堰顶高程
if (MapUtil.isNotEmpty(map) && ObjectUtils.isNotEmpty(attResBase) && ObjectUtils.isNotEmpty(attResBase.getWcrstel())) {
BigDecimal ydgdyjz = new BigDecimal(map.get("ydgdyjz").toString());
BigDecimal wcrstel = attResBase.getWcrstel();
Boolean isSave = false;
for (ForecastResultVo vo : voList) {
// 当计算的预报最高水位离堰顶高程小于此安全值,或者超过堰顶高度的值时,发送系统内消息提示。同时自动滚动预报保存方案结果
if ((vo.getYcSwHValue().add(ydgdyjz)).compareTo(wcrstel) > 0) {
isSave = true;
break;
}
}
if (isSave) {
ForecastProject forecastProject = new ForecastProject();
forecastProject.setId(IdWorker.getId());
forecastProject.setName("未来" + forecastPeriod + "小时洪水预报-".concat(sdfTime.format(nowTime)));
forecastProject.setType("1");
forecastProject.setForecastTm(forecastTime);
forecastProject.setProjectTm(nowTime);
forecastProject.setStartTm(startTime);
forecastProject.setEndTm(endTime);
// forecastProject.setUserId();
forecastProject.setForecastPeriod(forecastPeriod);
forecastProject.setForecastWarm(forecastWarm);
forecastProject.setTimeInterval(forecastTask.getTimeInterval());
forecastProject.setTaskId(forecastTask.getId());
forecastProject.setVoList(voList);
forecastProjectService.saveForecastResults(forecastProject);
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
log.info("{}----TaskGroupJob-计划执行结束===>jobId:{}", dtf.format(LocalDateTime.now()), jobId);
log.info("{}----TaskGroupJob-计划执行结束===>jobId:{}", sdf.format(LocalDateTime.now()), jobId);
}
}

View File

@ -1,13 +1,18 @@
package com.gunshi.project.xyt.service;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gunshi.project.xyt.entity.vo.ForecastResultVo;
import com.gunshi.project.xyt.mapper.ForecastProjectMapper;
import com.gunshi.project.xyt.model.ForecastProject;
import com.gunshi.project.xyt.model.ForecastResults;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.ArrayList;
import java.util.List;
/**
* : _
@ -20,6 +25,38 @@ import java.util.Date;
public class ForecastProjectService extends ServiceImpl<ForecastProjectMapper, ForecastProject>
{
@Autowired
private ForecastResultsService forecastResultsService;
/**
* @description:
* @param forecastProject
* @return: void
* @auther: cxw
* @date: 2024-08-06, , 10:06:40
*/
public Boolean saveForecastResults(ForecastProject forecastProject) {
List<ForecastResults> retList = new ArrayList<>();
List<ForecastResultVo> voList = forecastProject.getVoList();
for (ForecastResultVo vo : voList) {
ForecastResults forecastResults = new ForecastResults();
forecastResults.setId(IdWorker.getId());
forecastResults.setTm(vo.getTm());
forecastResults.setYcRkQValue(vo.getYcRkQValue());
forecastResults.setRealRkQValue(vo.getRealRkQValue());
forecastResults.setYcCkQValue(vo.getYcCkQValue());
forecastResults.setRealCkQValue(vo.getRealCkQValue());
forecastResults.setYcSwHValue(vo.getYcSwHValue());
forecastResults.setRealSwHValue(vo.getRealSwHValue());
forecastResults.setDrp(vo.getDrp());
forecastResults.setIspreDrp(vo.getIspreDrp());
forecastResults.setR(vo.getR());
forecastResults.setProjectId(forecastProject.getId());
forecastResults.setFlLowLimLev(vo.getFlLowLimLev());
forecastResults.setPa(vo.getPa());
}
return forecastResultsService.saveBatch(retList);
}
}

View File

@ -51,8 +51,11 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
{
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static SimpleDateFormat sdfDay = new SimpleDateFormat("yyyy-MM-dd");
private static SimpleDateFormat eightSdf = new SimpleDateFormat("yyyy-MM-dd 08");
private static SimpleDateFormat sixteenSdf = new SimpleDateFormat("yyyy-MM-dd 16");
@Autowired
@ -92,7 +95,167 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
*/
public List<ForecastResultVo> autoFloodForecast(ForecastTask forecastTask) throws Exception {
// 获取预测数据
List<ForecastResultVo> voList = excuteForecast(forecastTask);
return voList;
}
/**
* @description:
* @param forecastTask
* @return: java.util.List<com.gunshi.project.xyt.entity.vo.ForecastResultVo>
* @auther: cxw
* @date: 2024-07-31, , 11:09:24
*/
public List<ForecastResultVo> getHumanForecastResult(ForecastTask forecastTask) throws Exception {
// 当前时间整点,作为获取雨量数据历史、预测分隔点
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
Date nowHourTime = calendar.getTime();
forecastTask.setNowTime(nowHourTime);
List<ForecastResultVo> voList = excuteForecast(forecastTask);
return voList;
}
/**
* @description: ForecastResultVo
* @param forecastTask
* @return: java.util.List<com.gunshi.project.xyt.entity.vo.ForecastResultVo>
* @auther: cxw
* @date: 2024-08-05, , 17:14:52
*/
private List<ForecastResultVo> excuteForecast(ForecastTask forecastTask) throws Exception {
List<ForecastResultVo> voList = new ArrayList<>();
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<>();
// 如果结束时间在当前时间之前,降雨序列从历史降雨表获取
if (endTime.compareTo(nowHourTime) <= 0) {
qwExisted = new QueryWrapper<StPptnR>().eq("stcd", "716153201").ge("tm", startTime).le("tm", endTime).orderBy(true, true, "tm");
} else {
qwExisted = new QueryWrapper<StPptnR>().eq("stcd", "716153201").ge("tm", startTime).le("tm", nowHourTime).orderBy(true, true, "tm");
pptnRFutureList = getForecastDrpData(nowHourTime, "716153201");
}
List<StPptnR> pptnRExistedList = stPptnRService.list(qwExisted);
pptnRAllList.addAll(pptnRExistedList);
pptnRAllList.addAll(pptnRFutureList);
// 获取配置参数
List<ForecastUseparam> paramList = forecastUseparamService.list();
List<ForecastU> uList = forecastUService.list();
if (CollectionUtils.isEmpty(paramList) || CollectionUtils.isEmpty(uList) || CollectionUtils.isEmpty(pptnRAllList)) {
return voList;
}
double dt = 0.0;
double Wm = 0.0;
// 每小时的单位径流量单位m³/s
double[] u = uList.stream().mapToDouble(forecastU -> forecastU.getUValue().doubleValue()).toArray();
Map<String, String> paramMap = paramList.stream().collect(Collectors.toMap(ForecastUseparam::getParamCode, ForecastUseparam::getParamValue));
if (paramMap.get("dt").isEmpty() || paramMap.get("Im").isEmpty()) {
return voList;
}
dt = Double.parseDouble(paramMap.get("dt"));
Wm = Double.parseDouble(paramMap.get("Im"));
// 根据开始结束时间查询pa
Calendar cal = Calendar.getInstance();
cal.setTime(startTime);
// 将日期往前推一天
cal.add(Calendar.DATE, -1);
List<ForecastPa> paList = forecastPaService.list(new QueryWrapper<ForecastPa>().eq("stcd", "716153201").ge("tm", sdfDay.format(cal.getTime())).le("tm", sdfDay.format(endTime)));
if (CollectionUtils.isEmpty(paList)) {
return voList;
}
Map<String, ForecastPa> paMap = paList.stream().collect(Collectors.toMap(ForecastPa::getTm, entity -> entity));
// 获取预测开始时间前的最后水库水位
double H1 = 0.0;// 初始水库水位可以根据H1->V1,H1->q1得到初始的水库库容和下泄流量
StRsvrR rsvrR = stRsvrRService.getOne(new QueryWrapper<StRsvrR>().eq("stcd", "716153201").le("tm", startTime).orderBy(true, false, "tm").last("limit 1"));
if (ObjectUtils.isEmpty(rsvrR)) {
return voList;
}
H1 = Double.parseDouble(rsvrR.getRz());
// 获取汛限水位
AttResBase attResBase = attResBaseService.getOne(new QueryWrapper<>());
// 泄流量
List<StZqrlB> stZqrlBList = stZqrlBService.list(new QueryWrapper<StZqrlB>().eq("stcd", "716153201"));
List<Date[]> periods = splitByDay8To8(startTime, endTime);
for (Date[] period : periods) {
// 根据每段时间的开始时间如果在08点前则采用前一天的pa值计算
if (isBeforeEightAM(period[0])) {
cal.setTime(period[0]);
// 将日期往前推一天
cal.add(Calendar.DATE, -1);
}
ForecastPa forecastPa = paMap.get(sdfDay.format(cal.getTime()));
// 根据降雨数据按照△t的颗粒度均分
List<String> pResultList = new ArrayList<>();
// 筛选时间段内的降雨数据。第一个条件时间大于等于开始时间第二个条件时间小于等于结束时间包前不包后但是需要使用最后的tm计算间隔值
List<StPptnR> filterList = pptnRAllList.stream().filter(e -> e.getTm().compareTo(period[0]) >= 0).filter(e -> e.getTm().compareTo(period[1]) <= 0).collect(Collectors.toList());
for (int i = 0; i < filterList.size(); i++) {
// 到第二天早八,包前不包后,最后一条的第二天早八剔除
if (i + 1 == filterList.size()) {
break;
}
StPptnR stPptnR = filterList.get(i);
String drp = stPptnR.getDrp();
StPptnR stPptnRNext = filterList.get(i + 1);
// 两条数据的小时差
double diffHours = dateHourDifference(stPptnR.getTm(), stPptnRNext.getTm());
// 两条数据间需要增补几条
int floorNum = (int) Math.floor(diffHours / dt);
for (int j = 0; j < floorNum; j++) {
BigDecimal add = new BigDecimal(drp).divide(BigDecimal.valueOf(floorNum)).setScale(2, BigDecimal.ROUND_HALF_UP);
pResultList.add(add.toString());
}
}
double[] PList = pResultList.stream().mapToDouble(Double::parseDouble).toArray();
// 水位历史数据
List<StRsvrR> rsvrRRealList = stRsvrRService.list(new QueryWrapper<StRsvrR>().eq("stcd", "716153201").ge("tm", period[0]).le("tm", period[1]));
rsvrRRealList = reorganizeRsvrRData(rsvrRRealList, 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, "716153201");
if (CollectionUtils.isNotEmpty(forecastVoList)) {
forecastVoList = forecastVoList.subList(0, PList.length);
for (int j = 0; j < forecastVoList.size(); j++) {
FloodAlgorithemVo floodAlgorithemVo = forecastVoList.get(j);
ForecastResultVo resultVo = new ForecastResultVo();
Date dateTm = sdf.parse(floodAlgorithemVo.getDateStr());
resultVo.setTm(dateTm);
resultVo.setYcRkQValue(floodAlgorithemVo.getRq());// 预测入库流量
// resultVo.setRealRkQValue();// 暂无真实入库流量
resultVo.setYcCkQValue(floodAlgorithemVo.getCq());// 预测出库流量
resultVo.setYcSwHValue(floodAlgorithemVo.getKh());// 预测水库水位
H1 = resultVo.getYcSwHValue().doubleValue();// 先以预测水位作为下一次预测段起始值
if (j < rsvrRRealList.size()) {
BigDecimal realSwHValue = new BigDecimal(rsvrRRealList.get(j).getRz());
resultVo.setRealSwHValue(realSwHValue);// 真实水库水位
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));
List<BigDecimal> list = stZqrlBList.stream().map(StZqrlB::getZ).collect(Collectors.toList());
resultVo.setRealCkQValue(DataHandleUtil.calcData(realSwHValue, stZvalMap, list));// 真实出库流量
}
}
}
resultVo.setDrp(floodAlgorithemVo.getDrp());
resultVo.setIspreDrp(dateTm.compareTo(nowHourTime) <= 0 ? "0" : "1");// 0真实 1预测
resultVo.setR(floodAlgorithemVo.getR());
resultVo.setFlLowLimLev(attResBase.getFlLowLimLev());
resultVo.setPa(floodAlgorithemVo.getPa());
voList.add(resultVo);
}
}
}
return voList;
}
@ -147,152 +310,6 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
return pptnRFutureList;
}
/**
* @description:
* @param forecastTask
* @return: java.util.List<com.gunshi.project.xyt.entity.vo.ForecastResultVo>
* @auther: cxw
* @date: 2024-07-31, , 11:09:24
*/
public List<ForecastResultVo> getHumanForecastResult(ForecastTask forecastTask) throws Exception {
// 获取预测数据
List<ForecastResultVo> voList = new ArrayList<>();
// 当前时间整点,作为获取雨量数据历史、预测分隔点
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
Date nowHourTime = calendar.getTime();
Date forecastTm = forecastTask.getForecastTime();
Date startTm = forecastTask.getStartTime();
Date endTm = forecastTask.getEndTime();
// 获取整个时间线的降雨数据
List<StPptnR> pptnRAllList = new ArrayList<>();
List<StPptnR> pptnRFutureList = new ArrayList<>();
QueryWrapper<StPptnR> qwExisted = new QueryWrapper<>();
// 如果结束时间在当前时间之前,降雨序列从历史降雨表获取
if (endTm.compareTo(nowHourTime) <= 0) {
qwExisted = new QueryWrapper<StPptnR>().eq("stcd", "716153201").ge("tm", startTm).le("tm", endTm).orderBy(true, true, "tm");
} else {
qwExisted = new QueryWrapper<StPptnR>().eq("stcd", "716153201").ge("tm", startTm).le("tm", nowHourTime).orderBy(true, true, "tm");
pptnRFutureList = getForecastDrpData(nowHourTime, "716153201");
}
List<StPptnR> pptnRExistedList = stPptnRService.list(qwExisted);
pptnRAllList.addAll(pptnRExistedList);
pptnRAllList.addAll(pptnRFutureList);
// 获取配置参数
List<ForecastUseparam> paramList = forecastUseparamService.list();
List<ForecastU> uList = forecastUService.list();
double dt = 0.0;
double Wm = 0.0;
// 泄流量
List<StZqrlB> stZqrlBList = stZqrlBService.list(new QueryWrapper<StZqrlB>().eq("stcd", "716153201"));
if (CollectionUtils.isEmpty(paramList) || CollectionUtils.isEmpty(uList) || CollectionUtils.isEmpty(pptnRAllList) || CollectionUtils.isEmpty(stZqrlBList)) {
return voList;
}
// 每小时的单位径流量单位m³/s
double[] u = uList.stream().mapToDouble(forecastU -> forecastU.getUValue().doubleValue()).toArray();
Map<String, String> paramMap = paramList.stream().collect(Collectors.toMap(ForecastUseparam::getParamCode, ForecastUseparam::getParamValue));
if (paramMap.get("dt").isEmpty() || paramMap.get("Im").isEmpty()) {
return voList;
}
dt = Double.parseDouble(paramMap.get("dt"));
Wm = Double.parseDouble(paramMap.get("Im"));
// 根据开始结束时间查询pa
Calendar cal = Calendar.getInstance();
cal.setTime(startTm);
// 将日期往前推一天
cal.add(Calendar.DATE, -1);
List<ForecastPa> paList = forecastPaService.list(new QueryWrapper<ForecastPa>().eq("stcd", "716153201").ge("tm",
sdfDay.format(cal.getTime())).le("tm", sdfDay.format(endTm)));
if (CollectionUtils.isEmpty(paList)) {
return voList;
}
Map<String, ForecastPa> paMap = paList.stream().collect(Collectors.toMap(ForecastPa::getTm, entity -> entity));
// 获取预测开始时间前的最后水库水位
double H1 = 0.0;// 初始水库水位可以根据H1->V1,H1->q1得到初始的水库库容和下泄流量
StRsvrR rsvrR = stRsvrRService.getOne(new QueryWrapper<StRsvrR>().eq("stcd", "716153201").le("tm", startTm).orderBy(true, false, "tm").last("limit 1"));
if (ObjectUtils.isEmpty(rsvrR)) {
return voList;
}
H1 = Double.parseDouble(rsvrR.getRz());
// 获取汛限水位
AttResBase attResBase = attResBaseService.getOne(new QueryWrapper<>());
List<Date[]> periods = splitByDay8To8(startTm, endTm);
for (Date[] period : periods) {
// 根据每段时间的开始时间如果在08点前则采用前一天的pa值计算
if (isBeforeEightAM(period[0])) {
cal.setTime(period[0]);
// 将日期往前推一天
cal.add(Calendar.DATE, -1);
}
ForecastPa forecastPa = paMap.get(sdfDay.format(cal.getTime()));
// 根据降雨数据按照△t的颗粒度均分
List<String> pResultList = new ArrayList<>();
// 筛选时间段内的降雨数据。第一个条件时间大于等于开始时间第二个条件时间小于等于结束时间包前不包后但是需要使用最后的tm计算间隔值
List<StPptnR> filterList = pptnRAllList.stream().filter(e -> e.getTm().compareTo(period[0]) >= 0).filter(e -> e.getTm().compareTo(period[1]) <= 0).collect(Collectors.toList());
for (int i = 0; i < filterList.size(); i++) {
// 到第二天早八,包前不包后,最后一条的第二天早八剔除
if (i + 1 == filterList.size()) {
break;
}
StPptnR stPptnR = filterList.get(i);
String drp = stPptnR.getDrp();
StPptnR stPptnRNext = filterList.get(i + 1);
// 两条数据的小时差
double diffHours = dateHourDifference(stPptnR.getTm(), stPptnRNext.getTm());
// 两条数据间需要增补几条
int floorNum = (int) Math.floor(diffHours / dt);
for (int j = 0; j < floorNum; j++) {
BigDecimal add = new BigDecimal(drp).divide(BigDecimal.valueOf(floorNum)).setScale(2, BigDecimal.ROUND_HALF_UP);
pResultList.add(add.toString());
}
}
double[] PList = pResultList.stream().mapToDouble(Double::parseDouble).toArray();
List<StRsvrR> rsvrRRealList = stRsvrRService.list(new QueryWrapper<StRsvrR>().eq("stcd", "716153201").ge("tm", period[0]).le("tm", period[1]));
rsvrRRealList = reorganizeRsvrRData(rsvrRRealList, 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, "716153201");
if (CollectionUtils.isNotEmpty(forecastVoList)) {
forecastVoList = forecastVoList.subList(0, PList.length);
for (int j = 0; j < forecastVoList.size(); j++) {
FloodAlgorithemVo floodAlgorithemVo = forecastVoList.get(j);
ForecastResultVo resultVo = new ForecastResultVo();
resultVo.setTm(floodAlgorithemVo.getDateStr());
resultVo.setYcRkQValue(floodAlgorithemVo.getRq());// 预测入库流量
// resultVo.setRealRkQValue();// 暂无真实入库流量
resultVo.setYcCkQValue(floodAlgorithemVo.getCq());// 预测出库流量
resultVo.setYcSwHValue(floodAlgorithemVo.getKh());// 预测水库水位
H1 = resultVo.getYcSwHValue().doubleValue();// 先以预测水位作为下一次预测段起始值
if (j < rsvrRRealList.size()) {
BigDecimal realSwHValue = new BigDecimal(rsvrRRealList.get(j).getRz());
resultVo.setRealSwHValue(realSwHValue);// 真实水库水位
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));
List<BigDecimal> list = stZqrlBList.stream().map(StZqrlB::getZ).collect(Collectors.toList());
resultVo.setRealCkQValue(DataHandleUtil.calcData(realSwHValue, stZvalMap, list));// 真实出库流量
}
}
}
resultVo.setDrp(floodAlgorithemVo.getDrp());
resultVo.setR(floodAlgorithemVo.getR());
resultVo.setFlLowLimLev(attResBase.getFlLowLimLev());
voList.add(resultVo);
}
}
}
return voList;
}
/**
* @description: T
* @param rsvrRRealList