From 46c146b8bbe990de34eae844eebbf6623b2e156e Mon Sep 17 00:00:00 2001 From: chenxiwang <1520264117@qq.com> Date: Tue, 6 Aug 2024 11:05:18 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BA=BA=E5=B7=A5=E6=B4=AA?= =?UTF-8?q?=E6=B0=B4=E9=A2=84=E6=8A=A5=E6=8E=A5=E5=8F=A3=EF=BC=9B=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E4=BA=BA=E5=B7=A5=E3=80=81=E8=87=AA=E5=8A=A8=E9=A2=84?= =?UTF-8?q?=E6=8A=A5=E7=BB=93=E6=9E=9C=E4=BF=9D=E5=AD=98=EF=BC=9B=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E9=A2=84=E6=8A=A5=E6=96=B9=E6=A1=88=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E6=9F=A5=E7=9C=8B=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ForecastProjectController.java | 43 ++- .../controller/ForecastResultsController.java | 57 +--- .../xyt/entity/vo/ForecastResultVo.java | 15 +- .../gunshi/project/xyt/model/AttResBase.java | 11 +- .../project/xyt/model/ForecastProject.java | 28 +- .../project/xyt/model/ForecastResults.java | 14 + .../project/xyt/model/ForecastTask.java | 12 +- .../project/xyt/schedule/TaskGroupJob.java | 95 +++++- .../xyt/service/ForecastProjectService.java | 39 ++- .../xyt/service/ForecastResultsService.java | 309 +++++++++--------- 10 files changed, 404 insertions(+), 219 deletions(-) diff --git a/src/main/java/com/gunshi/project/xyt/controller/ForecastProjectController.java b/src/main/java/com/gunshi/project/xyt/controller/ForecastProjectController.java index a387d3e..015740c 100644 --- a/src/main/java/com/gunshi/project/xyt/controller/ForecastProjectController.java +++ b/src/main/java/com/gunshi/project/xyt/controller/ForecastProjectController.java @@ -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 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 getForecastProjectResults(@Schema(name = "projectId", description = "预测方案id") @RequestParam("projectId") String projectId) { + ForecastProject forecastProject = service.getById(projectId); + if (Objects.isNull(forecastProject)) { + throw new IllegalArgumentException("当前数据不存在"); + } + List resultList = forecastResultsService.list(new QueryWrapper().eq("project_id", projectId)); + if(CollectionUtils.isNotEmpty(resultList)) { + forecastProject.setVoList(JSON.parseArray(JSON.toJSONString(resultList), ForecastResultVo.class)); + } + return R.ok(forecastProject); + } } diff --git a/src/main/java/com/gunshi/project/xyt/controller/ForecastResultsController.java b/src/main/java/com/gunshi/project/xyt/controller/ForecastResultsController.java index 434ac15..aa391d6 100644 --- a/src/main/java/com/gunshi/project/xyt/controller/ForecastResultsController.java +++ b/src/main/java/com/gunshi/project/xyt/controller/ForecastResultsController.java @@ -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(@RequestBody @Validated ForecastResults forecastResults) { - QueryWrapper wrapper = new QueryWrapper(); + QueryWrapper 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> getHumanForecastResult(@RequestBody ForecastTask forecastTask) throws Exception { + public R getHumanForecastResult(@RequestBody ForecastTask forecastTask) throws Exception { + ForecastProject forecastProject = new ForecastProject(); List 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> getForecastTaskResult(@Schema(name = "taskId", description = "预测方案id") @RequestParam("taskId") String taskId) throws Exception { -// ForecastTask forecastTask = forecastTaskService.getById(taskId); -// List voList = service.getForecastTaskResult(forecastTask); -// return R.ok(voList); -// } - - -// @Operation(summary = "洪水预报测试") -// @PostMapping("/forecastTest") -// public R> 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> 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 forecastResultVos = service.humanFloodForecast(forecastTask); -// return R.ok(forecastResultVos); -// } } diff --git a/src/main/java/com/gunshi/project/xyt/entity/vo/ForecastResultVo.java b/src/main/java/com/gunshi/project/xyt/entity/vo/ForecastResultVo.java index c2e536d..837d317 100644 --- a/src/main/java/com/gunshi/project/xyt/entity/vo/ForecastResultVo.java +++ b/src/main/java/com/gunshi/project/xyt/entity/vo/ForecastResultVo.java @@ -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; } diff --git a/src/main/java/com/gunshi/project/xyt/model/AttResBase.java b/src/main/java/com/gunshi/project/xyt/model/AttResBase.java index a6e464c..1086a1c 100644 --- a/src/main/java/com/gunshi/project/xyt/model/AttResBase.java +++ b/src/main/java/com/gunshi/project/xyt/model/AttResBase.java @@ -423,7 +423,7 @@ public class AttResBase implements Serializable { private String stcd; /** - * 是否病险 1:病 + * 是否病险 1:病 */ @TableField(value="is_danger") @Schema(description="是否病险 1:病 ") @@ -486,8 +486,15 @@ 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 = "文件集合") private List files; -} \ No newline at end of file +} diff --git a/src/main/java/com/gunshi/project/xyt/model/ForecastProject.java b/src/main/java/com/gunshi/project/xyt/model/ForecastProject.java index 76a0519..ab29ec1 100644 --- a/src/main/java/com/gunshi/project/xyt/model/ForecastProject.java +++ b/src/main/java/com/gunshi/project/xyt/model/ForecastProject.java @@ -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; /** * 自动任务id(type为1时有值) @@ -154,4 +147,11 @@ public class ForecastProject extends GenericPageParams implements Serializable { @Schema(description="自动任务id(type为1时有值)") private Long taskId; + /** + * 预报结果voList + */ + @Schema(description = "预报结果voList") + @TableField(exist = false) + private List voList; + } diff --git a/src/main/java/com/gunshi/project/xyt/model/ForecastResults.java b/src/main/java/com/gunshi/project/xyt/model/ForecastResults.java index 54e13ee..723f4e8 100644 --- a/src/main/java/com/gunshi/project/xyt/model/ForecastResults.java +++ b/src/main/java/com/gunshi/project/xyt/model/ForecastResults.java @@ -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; + } diff --git a/src/main/java/com/gunshi/project/xyt/model/ForecastTask.java b/src/main/java/com/gunshi/project/xyt/model/ForecastTask.java index fb9c0fc..ae5fec5 100644 --- a/src/main/java/com/gunshi/project/xyt/model/ForecastTask.java +++ b/src/main/java/com/gunshi/project/xyt/model/ForecastTask.java @@ -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; + /** * 选择的起始时间 */ diff --git a/src/main/java/com/gunshi/project/xyt/schedule/TaskGroupJob.java b/src/main/java/com/gunshi/project/xyt/schedule/TaskGroupJob.java index 0fe8f76..81776c2 100644 --- a/src/main/java/com/gunshi/project/xyt/schedule/TaskGroupJob.java +++ b/src/main/java/com/gunshi/project/xyt/schedule/TaskGroupJob.java @@ -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 = 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 voList = forecastResultsService.autoFloodForecast(forecastTask); + // 符合条件就保存到数据库 + if (CollectionUtils.isNotEmpty(voList)) { + Map map = forecastUseparamService.getMap(new QueryWrapper().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); } } diff --git a/src/main/java/com/gunshi/project/xyt/service/ForecastProjectService.java b/src/main/java/com/gunshi/project/xyt/service/ForecastProjectService.java index 7368786..5f5b7ff 100644 --- a/src/main/java/com/gunshi/project/xyt/service/ForecastProjectService.java +++ b/src/main/java/com/gunshi/project/xyt/service/ForecastProjectService.java @@ -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 { + @Autowired + private ForecastResultsService forecastResultsService; + + /** + * @description: 保存预报结果 + * @param forecastProject + * @return: void + * @auther: cxw + * @date: 2024-08-06, 周二, 10:06:40 + */ + public Boolean saveForecastResults(ForecastProject forecastProject) { + List retList = new ArrayList<>(); + List 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); + } } diff --git a/src/main/java/com/gunshi/project/xyt/service/ForecastResultsService.java b/src/main/java/com/gunshi/project/xyt/service/ForecastResultsService.java index 493f8fd..49364da 100644 --- a/src/main/java/com/gunshi/project/xyt/service/ForecastResultsService.java +++ b/src/main/java/com/gunshi/project/xyt/service/ForecastResultsService.java @@ -51,8 +51,11 @@ public class ForecastResultsService extends ServiceImpl autoFloodForecast(ForecastTask forecastTask) throws Exception { // 获取预测数据 + List voList = excuteForecast(forecastTask); + return voList; + } + + /** + * @description: 获取人工交互洪水预报结果 + * @param forecastTask + * @return: java.util.List + * @auther: cxw + * @date: 2024-07-31, 周三, 11:09:24 + */ + public List 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 voList = excuteForecast(forecastTask); + return voList; + } + + /** + * @description: 组装洪水预报ForecastResultVo + * @param forecastTask + * @return: java.util.List + * @auther: cxw + * @date: 2024-08-05, 周一, 17:14:52 + */ + private List excuteForecast(ForecastTask forecastTask) throws Exception { List voList = new ArrayList<>(); + Date nowHourTime = forecastTask.getNowTime(); + Date startTime = forecastTask.getStartTime(); + Date endTime = forecastTask.getEndTime(); + // 获取整个时间线的降雨数据 + List pptnRAllList = new ArrayList<>(); + List pptnRFutureList = new ArrayList<>(); + QueryWrapper qwExisted = new QueryWrapper<>(); + // 如果结束时间在当前时间之前,降雨序列从历史降雨表获取 + if (endTime.compareTo(nowHourTime) <= 0) { + qwExisted = new QueryWrapper().eq("stcd", "716153201").ge("tm", startTime).le("tm", endTime).orderBy(true, true, "tm"); + } else { + qwExisted = new QueryWrapper().eq("stcd", "716153201").ge("tm", startTime).le("tm", nowHourTime).orderBy(true, true, "tm"); + pptnRFutureList = getForecastDrpData(nowHourTime, "716153201"); + } + List pptnRExistedList = stPptnRService.list(qwExisted); + pptnRAllList.addAll(pptnRExistedList); + pptnRAllList.addAll(pptnRFutureList); + // 获取配置参数 + List paramList = forecastUseparamService.list(); + List 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 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 paList = forecastPaService.list(new QueryWrapper().eq("stcd", "716153201").ge("tm", sdfDay.format(cal.getTime())).le("tm", sdfDay.format(endTime))); + if (CollectionUtils.isEmpty(paList)) { + return voList; + } + Map paMap = paList.stream().collect(Collectors.toMap(ForecastPa::getTm, entity -> entity)); + // 获取预测开始时间前的最后水库水位 + double H1 = 0.0;// 初始水库水位,可以根据H1->V1,H1->q1得到初始的水库库容和下泄流量 + StRsvrR rsvrR = stRsvrRService.getOne(new QueryWrapper().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 stZqrlBList = stZqrlBService.list(new QueryWrapper().eq("stcd", "716153201")); + List 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 pResultList = new ArrayList<>(); + // 筛选时间段内的降雨数据。第一个条件:时间大于等于开始时间;第二个条件:时间小于等于结束时间(包前不包后,但是需要使用最后的tm计算间隔值) + List 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 rsvrRRealList = stRsvrRService.list(new QueryWrapper().eq("stcd", "716153201").ge("tm", period[0]).le("tm", period[1])); + rsvrRRealList = reorganizeRsvrRData(rsvrRRealList, dt); + // 预测执行 + List 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 stZvalMap = stZqrlBList.stream().collect(Collectors.toMap(StZqrlB::getZ, StZqrlB::getQ)); + List 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 - * @auther: cxw - * @date: 2024-07-31, 周三, 11:09:24 - */ - public List getHumanForecastResult(ForecastTask forecastTask) throws Exception { - // 获取预测数据 - List 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 pptnRAllList = new ArrayList<>(); - List pptnRFutureList = new ArrayList<>(); - QueryWrapper qwExisted = new QueryWrapper<>(); - // 如果结束时间在当前时间之前,降雨序列从历史降雨表获取 - if (endTm.compareTo(nowHourTime) <= 0) { - qwExisted = new QueryWrapper().eq("stcd", "716153201").ge("tm", startTm).le("tm", endTm).orderBy(true, true, "tm"); - } else { - qwExisted = new QueryWrapper().eq("stcd", "716153201").ge("tm", startTm).le("tm", nowHourTime).orderBy(true, true, "tm"); - pptnRFutureList = getForecastDrpData(nowHourTime, "716153201"); - } - List pptnRExistedList = stPptnRService.list(qwExisted); - pptnRAllList.addAll(pptnRExistedList); - pptnRAllList.addAll(pptnRFutureList); - // 获取配置参数 - List paramList = forecastUseparamService.list(); - List uList = forecastUService.list(); - double dt = 0.0; - double Wm = 0.0; - // 泄流量 - List stZqrlBList = stZqrlBService.list(new QueryWrapper().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 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 paList = forecastPaService.list(new QueryWrapper().eq("stcd", "716153201").ge("tm", - sdfDay.format(cal.getTime())).le("tm", sdfDay.format(endTm))); - if (CollectionUtils.isEmpty(paList)) { - return voList; - } - Map paMap = paList.stream().collect(Collectors.toMap(ForecastPa::getTm, entity -> entity)); - // 获取预测开始时间前的最后水库水位 - double H1 = 0.0;// 初始水库水位,可以根据H1->V1,H1->q1得到初始的水库库容和下泄流量 - StRsvrR rsvrR = stRsvrRService.getOne(new QueryWrapper().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 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 pResultList = new ArrayList<>(); - // 筛选时间段内的降雨数据。第一个条件:时间大于等于开始时间;第二个条件:时间小于等于结束时间(包前不包后,但是需要使用最后的tm计算间隔值) - List 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 rsvrRRealList = stRsvrRService.list(new QueryWrapper().eq("stcd", "716153201").ge("tm", period[0]).le("tm", period[1])); - rsvrRRealList = reorganizeRsvrRData(rsvrRRealList, dt); - // 预测执行 - List 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 stZvalMap = stZqrlBList.stream().collect(Collectors.toMap(StZqrlB::getZ, StZqrlB::getQ)); - List 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