1.完成源项处理模块新增源项重建任务、获取源项重建监测数据、导出模版、导入源项重建监测数据、执行重建任务、获取单条源项重建任务记录、修改源项重建任务、删除源项重建任务、查询源项重建任务列表、获取源项重建任务过程日志、获取概率分布图数据、获取观测值和模拟值的活度浓度比较结果数据、获取单变量后验分布接口

This commit is contained in:
panbaolin 2025-09-15 19:47:17 +08:00
parent 9020bc96fc
commit 00d013ec55
43 changed files with 2564 additions and 13 deletions

View File

@ -0,0 +1,26 @@
package org.jeecg.common.constant.enums;
/**
* 源项重建释放源是否已知枚举状态说明枚举
*/
public enum SourceRebuildReleaseSourceEnum {
/**
* 未知
*/
UNKNOWN(0),
/**
* 已知
*/
KNOWN(1);
private Integer value;
SourceRebuildReleaseSourceEnum(Integer value) {
this.value = value;
}
public Integer getValue(){
return this.value;
}
}

View File

@ -0,0 +1,34 @@
package org.jeecg.common.constant.enums;
/**
* 源项重建任务状态说明枚举
*/
public enum SourceRebuildTaskStatusEnum {
/**
* 未开始
*/
ERROR(-1),
/**
* 未开始
*/
NOT_STARTED(0),
/**
* 执行中
*/
IN_OPERATION(1),
/**
* 已完成
*/
COMPLETED(2);
private Integer value;
SourceRebuildTaskStatusEnum(Integer value) {
this.value = value;
}
public Integer getValue(){
return this.value;
}
}

View File

@ -0,0 +1,37 @@
package org.jeecg.common.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "source-rebuild")
public class SourceRebuildParams {
/**
* Rserve 服务地址
*/
private String serverAddr;
/**
* Rserve端口
*/
private Integer port;
/**
* Rserve 用户名称
*/
private String username;
/**
* Rserve密码
*/
private String password;
/**
* R项目工作空间
*/
private String workSpace;
}

View File

@ -28,4 +28,29 @@ public class SystemStorageProperties {
* 再分析数据存储路径
*/
private String reAnalysis;
/**
* R项目所在路径
*/
private String rProject;
/**
* R项目输入目录
*/
private String rInput;
/**
* R项目输出目录
*/
private String rOutput;
/**
* srs 文件路径
*/
private String srsFilePath;
/**
* xe文件srs文件所在的目录
*/
private String xeGZFileDirSign;
}

View File

@ -0,0 +1,94 @@
package org.jeecg.modules.base.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.jeecg.common.validgroup.InsertGroup;
import org.jeecg.common.validgroup.UpdateGroup;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.util.Date;
/**
* 源项重建监测数据表
*/
@Data
@TableName("stas_source_rebuild_monitoring_data")
public class SourceRebuildMonitoringData implements Serializable {
/**
* ID
*/
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 任务ID
*/
@Excel(name = "任务主键", width = 10,height = 20,orderNum="0")
@TableField(value = "task_id")
private Integer taskId;
/**
* 台站名称
*/
@Excel(name = "台站名称", width = 20,height = 20,orderNum="1")
@NotBlank(message = "台站名称不能为空", groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "station")
private String station;
/**
* 核素名称
*/
@Excel(name = "核素名称", width = 20,height = 20,orderNum="2")
@NotBlank(message = "核素名称不能为空", groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "nuclide")
private String nuclide;
/**
* 测量停止时间
*/
@Excel(name = "测量停止时间", width = 25,height = 20,format = "yyyy-MM-dd HH:mm:ss",orderNum="3")
@NotNull(message = "测量停止时间不能为空", groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "collect_stop")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private Date collectStop;
/**
* 活度浓度
*/
@Excel(name = "活度浓度", width = 25,height = 20,orderNum="4")
@NotBlank(message = "活度浓度不能为空", groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "activity")
private String activity;
/**
* 不确定度
*/
@Excel(name = "不确定度", width = 25,height = 20,orderNum="5")
@NotBlank(message = "不确定度不能为空", groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "uncertainty")
private String uncertainty;
/**
* mdc
*/
@Excel(name = "MDC", width = 25,height = 20,orderNum="6")
@NotBlank(message = "mdc不能为空", groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "mdc")
private String mdc;
/**
* 创建时间
*/
@TableField(value = "create_time")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
}

View File

@ -0,0 +1,206 @@
package org.jeecg.modules.base.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Null;
import lombok.Data;
import org.jeecg.common.validgroup.InsertGroup;
import org.jeecg.common.validgroup.UpdateGroup;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.util.Date;
/**
* 源项重建任务表
*/
@Data
@TableName("stas_source_rebuild")
public class SourceRebuildTask implements Serializable {
/**
* ID
*/
@Null(message = "ID必须为空",groups = { InsertGroup.class})
@NotNull(message = "ID不能为空",groups = { UpdateGroup.class})
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 任务名称
*/
@NotBlank(message = "任务名称不能为空",groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "task_name")
private String taskName;
/**
* 任务状态-1执行错误0-未开始1进行中2已完成
*/
@Null(message = "任务状态必须为空",groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "task_status")
private Integer taskStatus;
/**
* 最小经度
*/
@NotNull(message = "最小经度不能为空",groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "lonmin")
private Double lonmin;
/**
* 最小纬度
*/
@NotNull(message = "最小纬度不能为空",groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "latmin")
private Double latmin;
/**
* 最大经度
*/
@NotNull(message = "最大经度不能为空",groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "lonmax")
private Double lonmax;
/**
* 最大纬度
*/
@NotNull(message = "最大纬度不能为空",groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "latmax")
private Double latmax;
/**
* 分辨率
*/
@NotNull(message = "分辨率不能为空",groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "resolution")
private String resolution;
/**
* srs时间周期-开始日期
*/
@NotNull(message = "srs时间周期-开始日期不能为空",groups = {InsertGroup.class, UpdateGroup.class})
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
@TableField(value = "srs_start_time")
private Date srsStartTime;
/**
* srs时间周期-结束日期
*/
@NotNull(message = "srs时间周期-结束日期不能为空",groups = {InsertGroup.class, UpdateGroup.class})
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
@TableField(value = "srs_end_time")
private Date srsEndTime;
/**
* 释放类型,1-持续释放2-均匀释放3-非均匀释放
*/
@NotNull(message = "释放源类型不能为空",groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "release_type")
private Integer releaseType;
/**
* 释放源位置0-未知1已知
*/
@NotNull(message = "是否已知释放源不能为空",groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "release_source_location")
private Integer releaseSourceLocation;
/**
* 释放源经度
*/
@TableField(value = "source_lon")
private Double sourceLon;
/**
* 释放源纬度
*/
@TableField(value = "source_lat")
private Double sourceLat;
/**
* 释放源开始释放时间
*/
@TableField(value = "release_start_time")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
private Date releaseStartTime;
/**
* 释放源结束释放时间
*/
@TableField(value = "release_end_time")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
private Date releaseEndTime;
/**
* 源强
*/
@TableField(value = "source_strength")
private Integer sourceStrength;
/**
* 耗时
*/
@Null(message = "耗时必须为空",groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "time_consuming")
private Integer timeConsuming;
/**
* 半衰期
*/
@NotNull(message = "半衰期不能为空",groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "halflife")
private Double halflife;
/**
* 最小总累积源项Bq
*/
@NotNull(message = "最小总累积源项Bq不能为空",groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "qmin")
private Integer qmin;
/**
* 最大总累积源项Bq
*/
@NotNull(message = "最大总累积源项Bq不能为空",groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "qmax")
private Integer qmax;
/**
* 结果存储地址
*/
@Null(message = "结果存储地址必须为空",groups = {InsertGroup.class, UpdateGroup.class})
@TableField(value = "result_address")
private String resultAddress;
/**
* 创建人
*/
@TableField(value = "create_by")
private String createBy;
/**
* 创建时间
*/
@TableField(value = "create_time")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 更新人
*/
@TableField(value = "update_by")
private String updateBy;
/**
* 更新时间
*/
@TableField(value = "update_time")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}

View File

@ -0,0 +1,51 @@
package org.jeecg.modules.base.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.util.Date;
/**
* 源项重建任务日志表
*/
@Data
@NoArgsConstructor
@TableName("stas_source_rebuild_task_log")
public class SourceRebuildTaskLog implements Serializable {
/**
* ID
*/
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 任务id
*/
@TableField(value = "task_id")
private Integer taskId;
/**
* 创建时间
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 日志内容
*/
@TableField(value = "log_content")
private String logContent;
public SourceRebuildTaskLog(Integer taskId, String logContent) {
this.taskId = taskId;
this.logContent = logContent;
}
}

View File

@ -7,6 +7,8 @@ import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
@ -15,7 +17,7 @@ import java.util.Date;
*/
@Data
@TableName("stas_weather_data")
public class WeatherData {
public class WeatherData implements Serializable {
/**
* ID

View File

@ -7,6 +7,8 @@ import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
@ -14,7 +16,7 @@ import java.time.LocalDateTime;
*/
@Data
@TableName("stas_weather_task_log")
public class WeatherTaskLog{
public class WeatherTaskLog implements Serializable {
/**
* ID

View File

@ -0,0 +1,7 @@
package org.jeecg.modules.base.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.base.entity.SourceRebuildMonitoringData;
public interface SourceRebuildMonitoringDataMapper extends BaseMapper<SourceRebuildMonitoringData> {
}

View File

@ -0,0 +1,8 @@
package org.jeecg.modules.base.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.base.entity.SourceRebuildTaskLog;
public interface SourceRebuildTaskLogMapper extends BaseMapper<SourceRebuildTaskLog> {
}

View File

@ -0,0 +1,7 @@
package org.jeecg.modules.base.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.base.entity.SourceRebuildTask;
public interface SourceRebuildTaskMapper extends BaseMapper<SourceRebuildTask> {
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.base.mapper.SourceRebuildMonitoringDataMapper">
</mapper>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.base.mapper.SourceRebuildTaskLogMapper">
</mapper>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.base.mapper.SourceRebuildTaskMapper">
</mapper>

View File

@ -9,12 +9,14 @@
<version>3.8.1</version>
</parent>
<artifactId>jeecg-module-sourceitem-reconstruction</artifactId>
<artifactId>jeecg-module-source-rebuild</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<rEngine.version>2.1.0</rEngine.version>
<rserve.version>1.8.1</rserve.version>
</properties>
<dependencies>
@ -23,5 +25,15 @@
<artifactId>jeecg-boot-base-core</artifactId>
<version>${jeecgboot.version}</version>
</dependency>
<dependency>
<groupId>org.rosuda.REngine</groupId>
<artifactId>REngine</artifactId>
<version>${rEngine.version}</version>
</dependency>
<dependency>
<groupId>org.rosuda.REngine</groupId>
<artifactId>Rserve</artifactId>
<version>${rserve.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,90 @@
package org.jeecg.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.system.query.PageRequest;
import org.jeecg.common.validgroup.InsertGroup;
import org.jeecg.common.validgroup.UpdateGroup;
import org.jeecg.modules.base.entity.SourceRebuildTask;
import org.jeecg.service.SourceRebuildTaskService;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
/**
* 源项重建
*/
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("source")
public class SourceRebuildTaskController{
private final SourceRebuildTaskService sourceRebuildTaskService;
@AutoLog(value = "查询源项重建任务列表")
@Operation(summary = "查询源项重建任务列表")
@GetMapping(value = "page")
public Result<?> page(PageRequest pageRequest, String taskName, Integer taskStatus,
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) {
IPage<SourceRebuildTask> page = sourceRebuildTaskService.page(pageRequest, taskName, taskStatus, startDate,endDate);
Map<String, Object> rspData = new HashMap<>();
rspData.put("rows", page.getRecords());
rspData.put("total", page.getTotal());
return Result.OK(rspData);
}
@AutoLog(value = "新增源项重建任务")
@Operation(summary = "新增源项重建任务")
@PostMapping("create")
public Result<?> create(@RequestBody @Validated(value = InsertGroup.class) SourceRebuildTask sourceRebuildTask){
sourceRebuildTaskService.cteate(sourceRebuildTask);
return Result.OK();
}
@AutoLog(value = "获取单条源项重建任务记录")
@Operation(summary = "获取单条源项重建任务记录")
@GetMapping("getById")
public Result<?> getById(@NotNull(message = "ID不能为空") String id){
return Result.OK(sourceRebuildTaskService.getById(id));
}
@AutoLog(value = "修改源项重建任务")
@Operation(summary = "修改源项重建任务")
@PutMapping("update")
public Result<?> update(@RequestBody @Validated(value = UpdateGroup.class) SourceRebuildTask sourceRebuildTask){
sourceRebuildTaskService.update(sourceRebuildTask);
return Result.OK();
}
@AutoLog(value = "删除源项重建任务")
@Operation(summary = "删除源项重建任务")
@DeleteMapping("delete")
public Result<?> delete(@NotNull(message = "id不能为空") Integer id){
sourceRebuildTaskService.delete(id);
return Result.OK();
}
@AutoLog(value = "获取源项重建任务过程日志")
@Operation(summary = "获取源项重建任务过程日志")
@GetMapping("getTaskLog")
public Result<?> getTaskLog(@NotNull(message = "任务ID不能为空") Integer taskId){
return Result.OK(sourceRebuildTaskService.getTaskLog(taskId));
}
@AutoLog(value = "启动任务")
@Operation(summary = "启动任务")
@PutMapping("runTask")
public Result<?> runTask(@NotNull(message = "任务ID不能为空") Integer taskId){
sourceRebuildTaskService.runTask(taskId);
return Result.OK();
}
}

View File

@ -0,0 +1,95 @@
package org.jeecg.controller;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.modules.base.entity.SourceRebuildMonitoringData;
import org.jeecg.service.SourceRebuildMonitoringDataService;
import org.jeecgframework.poi.excel.ExcelExportUtil;
import org.jeecgframework.poi.excel.ExcelImportCheckUtil;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
import org.springframework.beans.BeanUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 源项重建任务监测数据
*/
@Slf4j
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("source")
public class TaskMonitoringDataController {
private final SourceRebuildMonitoringDataService monitoringDataService;
@AutoLog(value = "获取源项重建监测数据")
@Operation(summary = "获取源项重建监测数据")
@GetMapping("getTaskMonitoringData")
public Result<?> getTaskMonitoringData(@NotNull(message = "任务ID不能为空") Integer taskId){
return Result.OK(monitoringDataService.getTaskMonitoringData(taskId));
}
@AutoLog(value = "导出模版")
@Operation(summary = "导出模版")
@GetMapping("exportTemplate")
public void exportTemplate(HttpServletResponse response) throws IOException {
ExportParams params = new ExportParams();
params.setTitle("台站监测数据");
params.setFixedTitle(true);
params.setTitleHeight((short) 8);
params.setType(ExcelType.XSSF);
ExcelExportUtil.exportExcel(params,SourceRebuildMonitoringData.class,new ArrayList<>()).write(response.getOutputStream());
}
@AutoLog(value = "导入源项重建监测数据")
@Operation(summary = "导入源项重建监测数据")
@PostMapping("importTaskMonitoringData")
public Result<?> importTaskMonitoringData(HttpServletRequest request, HttpServletResponse response){
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
// 获取上传文件对象
MultipartFile file = entity.getValue();
ImportParams params = new ImportParams();
params.setTitleRows(1);
params.setHeadRows(2);
params.setNeedSave(true);
try {
ExcelImportCheckUtil.check(file.getInputStream(), SourceRebuildMonitoringData.class, params);
List<SourceRebuildMonitoringData> list = ExcelImportUtil.importExcel(file.getInputStream(), SourceRebuildMonitoringData.class, params);
System.out.println(list);
monitoringDataService.cteate(list);
return Result.ok("文件导入成功!");
} catch (Exception e) {
log.error(e.getMessage(), e);
return Result.error("文件导入失败:" + e.getMessage());
} finally {
try {
file.getInputStream().close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return Result.error("文件导入失败!");
}
}

View File

@ -0,0 +1,57 @@
package org.jeecg.controller;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.service.SourceRebuildMonitoringDataService;
import org.jeecg.service.TaskResultDataService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
/**
* 源项重建任务运行结果数据
*/
@Slf4j
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("source")
public class TaskResultDataController {
private final TaskResultDataService taskResultDataService;
@AutoLog(value = "获取概率分布数据")
@Operation(summary = "获取概率分布数据")
@GetMapping("getBayesProbLoc")
public Result<?> getBayesProbLoc(@NotNull(message = "任务ID不能为空") Integer taskId){
return Result.OK(taskResultDataService.getBayesProbLoc(taskId));
}
@AutoLog(value = "获取观测值和模拟值的活度浓度比较结果数据")
@Operation(summary = "获取观测值和模拟值的活度浓度比较结果数据")
@GetMapping("getBayesAcTimeSeries")
public Result<?> getBayesAcTimeSeries(@NotNull(message = "任务ID不能为空") Integer taskId){
return Result.OK(taskResultDataService.getBayesAcTimeSeries(taskId));
}
@AutoLog(value = "获取单变量后验分布")
@Operation(summary = "获取单变量后验分布")
@GetMapping("getBayesMonovarPosterior")
public Result<?> getBayesMonovarPosterior(@NotNull(message = "任务ID不能为空") Integer taskId){
return Result.OK(taskResultDataService.getBayesMonovarPosterior(taskId));
}
@AutoLog(value = "导出TXT")
@Operation(summary = "导出TXT")
@GetMapping("exportTxt")
public void exportTxt(HttpServletResponse response) throws IOException {
}
}

View File

@ -0,0 +1,31 @@
package org.jeecg.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.jeecg.modules.base.entity.SourceRebuildMonitoringData;
import java.util.List;
/**
* 源项重建任务监测数据
*/
public interface SourceRebuildMonitoringDataService extends IService<SourceRebuildMonitoringData> {
/**
* 保存源项重建任务监测数据
* @param monitoringDatas
*/
void cteate(List<SourceRebuildMonitoringData> monitoringDatas);
/**
* 删除源项重建任务监测数据
* @param taskId
*/
void delete(Integer taskId);
/**
* 获取任务所属监测数据
* @param taskId
* @return
*/
List<SourceRebuildMonitoringData> getTaskMonitoringData(Integer taskId);
}

View File

@ -0,0 +1,36 @@
package org.jeecg.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.jeecg.modules.base.entity.SourceRebuildTaskLog;
import java.util.List;
/**
* 源项重建任务日志数据
*/
public interface SourceRebuildTaskLogService extends IService<SourceRebuildTaskLog> {
/**
* 保存源项重建任务运行过程日志
* @param sourceRebuildTaskLog
*/
void cteate(SourceRebuildTaskLog sourceRebuildTaskLog);
/**
* 删除任务运行过程日志
* @param taskId
*/
void delete(Integer taskId);
/**
* 获取任务运行过程日志
* @param taskId
* @return
*/
List<SourceRebuildTaskLog> getTaskLogs(Integer taskId);
/**
* 批量保存日志
* @param logs
*/
void batchCteate(List<SourceRebuildTaskLog> logs);
}

View File

@ -0,0 +1,79 @@
package org.jeecg.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import org.jeecg.common.system.query.PageRequest;
import org.jeecg.modules.base.entity.SourceRebuildTask;
import org.jeecg.modules.base.entity.SourceRebuildTaskLog;
import java.time.LocalDate;
import java.util.List;
/**
* 源项重建任务
*/
public interface SourceRebuildTaskService extends IService<SourceRebuildTask> {
/**
* 分页查询任务列表
* @param pageRequest
* @param taskName
* @param taskStatus
* @param startDate
* @param endDate
* @return
*/
IPage<SourceRebuildTask> page(PageRequest pageRequest, String taskName, Integer taskStatus, LocalDate startDate, LocalDate endDate);
/**
* 创建源项重建任务
* @param sourceItemRebuildTask
*/
void cteate(SourceRebuildTask sourceItemRebuildTask);
/**
* 获取单条任务数据
* @param id
* @return
*/
SourceRebuildTask getById(Integer id);
/**
* 修改源项重建任务
* @param sourceRebuildTask
*/
void update(SourceRebuildTask sourceRebuildTask);
/**
* 删除源项重建任务
* @param id
*/
void delete(Integer id);
/**
* 运行任务
* @param id
*/
void runTask(Integer id);
/**
* 获取任务运行日志
* @param taskId
* @return
*/
List<SourceRebuildTaskLog> getTaskLog(Integer taskId);
/**
* 修改任务状态
* @param taskId
* @param taskStatus
*/
void updateTaskStatus(Integer taskId, Integer taskStatus);
/**
* 任务耗时
* @param taskId
* @param taskTimeConsuming
*/
void updateTaskTimeConsuming(Integer taskId, Integer taskTimeConsuming);
}

View File

@ -0,0 +1,38 @@
package org.jeecg.service;
import org.jeecg.vo.ActivityConcComparResult;
import org.jeecg.vo.SourceProbabilityGrid;
import java.util.Map;
/**
* 任务结果数据
*/
public interface TaskResultDataService {
/**
* 获取概率分布数据
* @param taskId
* @return
*/
SourceProbabilityGrid getBayesProbLoc(Integer taskId);
/**
* 获取观测值和模拟值的活度浓度比较结果数据
* @param taskId
* @return
*/
ActivityConcComparResult getBayesAcTimeSeries(Integer taskId);
/**
* 获取双变量后验分布
* @param taskId
*/
void getBayesBivarPosterior(Integer taskId);
/**
* 获取单变量后验分布
* @param taskId
*/
Map<String,Object> getBayesMonovarPosterior(Integer taskId);
}

View File

@ -0,0 +1,58 @@
package org.jeecg.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.jeecg.modules.base.entity.SourceRebuildMonitoringData;
import org.jeecg.modules.base.mapper.SourceRebuildMonitoringDataMapper;
import org.jeecg.service.SourceRebuildMonitoringDataService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* 源项重建任务监测数据
*/
@Service
@RequiredArgsConstructor
public class SourceRebuildMonitoringDataServiceImpl extends ServiceImpl<SourceRebuildMonitoringDataMapper, SourceRebuildMonitoringData> implements SourceRebuildMonitoringDataService {
/**
* 保存源项重建任务监测数据
*
* @param monitoringDatas
*/
@Transactional(rollbackFor = RuntimeException.class)
@Override
public void cteate(List<SourceRebuildMonitoringData> monitoringDatas) {
this.saveBatch(monitoringDatas);
}
/**
* 删除源项重建任务监测数据
*
* @param taskId
*/
@Transactional(rollbackFor = RuntimeException.class)
@Override
public void delete(Integer taskId) {
LambdaQueryWrapper<SourceRebuildMonitoringData> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SourceRebuildMonitoringData::getTaskId, taskId);
this.remove(queryWrapper);
}
/**
* 获取任务所属监测数据
*
* @param taskId
* @return
*/
@Override
public List<SourceRebuildMonitoringData> getTaskMonitoringData(Integer taskId) {
LambdaQueryWrapper<SourceRebuildMonitoringData> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SourceRebuildMonitoringData::getTaskId, taskId);
queryWrapper.ne(SourceRebuildMonitoringData::getStation,"USX77");
queryWrapper.orderByAsc(SourceRebuildMonitoringData::getCollectStop);
return this.baseMapper.selectList(queryWrapper);
}
}

View File

@ -0,0 +1,63 @@
package org.jeecg.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jeecg.modules.base.entity.SourceRebuildTaskLog;
import org.jeecg.modules.base.mapper.SourceRebuildTaskLogMapper;
import org.jeecg.service.SourceRebuildTaskLogService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class SourceRebuildTaskLogServiceImpl extends ServiceImpl<SourceRebuildTaskLogMapper, SourceRebuildTaskLog> implements SourceRebuildTaskLogService {
/**
* 保存源项重建任务运行过程日志
*
* @param sourceRebuildTaskLog
*/
@Transactional(rollbackFor = RuntimeException.class)
@Override
public void cteate(SourceRebuildTaskLog sourceRebuildTaskLog) {
this.baseMapper.insert(sourceRebuildTaskLog);
}
/**
* 删除任务运行过程日志
*
* @param taskId
*/
@Transactional(rollbackFor = RuntimeException.class)
@Override
public void delete(Integer taskId) {
LambdaQueryWrapper<SourceRebuildTaskLog> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SourceRebuildTaskLog::getTaskId, taskId);
this.baseMapper.delete(queryWrapper);
}
/**
* 获取任务运行过程日志
*
* @param taskId
* @return
*/
@Override
public List<SourceRebuildTaskLog> getTaskLogs(Integer taskId) {
LambdaQueryWrapper<SourceRebuildTaskLog> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SourceRebuildTaskLog::getTaskId, taskId);
return this.baseMapper.selectList(queryWrapper);
}
/**
* 批量保存日志
*
* @param logs
*/
@Transactional(rollbackFor = RuntimeException.class)
@Override
public void batchCteate(List<SourceRebuildTaskLog> logs) {
this.saveBatch(logs);
}
}

View File

@ -0,0 +1,233 @@
package org.jeecg.service.impl;
import cn.hutool.core.io.FileUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.constant.enums.SourceRebuildTaskStatusEnum;
import org.jeecg.common.properties.SourceRebuildParams;
import org.jeecg.common.properties.SystemStorageProperties;
import org.jeecg.common.system.query.PageRequest;
import org.jeecg.modules.base.entity.SourceRebuildMonitoringData;
import org.jeecg.modules.base.entity.SourceRebuildTask;
import org.jeecg.modules.base.entity.SourceRebuildTaskLog;
import org.jeecg.modules.base.mapper.SourceRebuildTaskLogMapper;
import org.jeecg.modules.base.mapper.SourceRebuildTaskMapper;
import org.jeecg.service.SourceRebuildMonitoringDataService;
import org.jeecg.service.SourceRebuildTaskLogService;
import org.jeecg.service.SourceRebuildTaskService;
import org.jeecg.task.SourceRebuildTaskExec;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
/**
* 源项重建任务
*/
@Service
@RequiredArgsConstructor
public class SourceRebuildTaskServiceImpl extends ServiceImpl<SourceRebuildTaskMapper, SourceRebuildTask> implements SourceRebuildTaskService {
private final SourceRebuildTaskLogMapper sourceRebuildTaskLogMapper;
private final SourceRebuildMonitoringDataService monitoringDataService;
private final SourceRebuildTaskLogService sourceRebuildTaskLogService;
private final SystemStorageProperties systemStorageProperties;
private final SourceRebuildParams sourceRebuildParams;
/**
* 分页查询任务列表
* @param pageRequest
* @param taskName
* @param taskStatus
* @param startDate
* @param endDate
* @return
*/
@Override
public IPage<SourceRebuildTask> page(PageRequest pageRequest, String taskName, Integer taskStatus, LocalDate startDate, LocalDate endDate) {
LambdaQueryWrapper<SourceRebuildTask> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Objects.nonNull(taskStatus),SourceRebuildTask::getTaskStatus, taskStatus);
if(Objects.nonNull(startDate) && Objects.nonNull(endDate)){
LocalDateTime startDateTime = startDate.atTime(0, 0, 0);
LocalDateTime endDateTime = endDate.atTime(23, 59, 59);
queryWrapper.between(SourceRebuildTask::getCreateTime,startDateTime,endDateTime);
}
queryWrapper.like(StringUtils.isNotBlank(taskName),SourceRebuildTask::getTaskName,taskName);
queryWrapper.orderByDesc(SourceRebuildTask::getCreateTime);
IPage<SourceRebuildTask> iPage = new Page<>(pageRequest.getPageNum(), pageRequest.getPageSize());
return this.page(iPage, queryWrapper);
}
/**
* 创建源项重建任务
* @param sourceRebuildTask
*/
@Transactional(rollbackFor = RuntimeException.class)
@Override
public void cteate(SourceRebuildTask sourceRebuildTask) {
LambdaQueryWrapper<SourceRebuildTask> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SourceRebuildTask::getTaskName, sourceRebuildTask.getTaskName());
SourceRebuildTask checkNameResult = this.baseMapper.selectOne(queryWrapper);
if (Objects.nonNull(checkNameResult)) {
throw new RuntimeException("此任务已存在");
}
sourceRebuildTask.setTaskStatus(SourceRebuildTaskStatusEnum.NOT_STARTED.getValue());
this.baseMapper.insert(sourceRebuildTask);
}
/**
* 获取单条任务数据
* @param id
* @return
*/
@Override
public SourceRebuildTask getById(Integer id) {
SourceRebuildTask sourceRebuildTask = this.baseMapper.selectById(id);
if(Objects.isNull(sourceRebuildTask)){
throw new RuntimeException("此任务不存在");
}
return sourceRebuildTask;
}
/**
* 修改源项重建任务
* @param sourceRebuildTask
*/
@Transactional(rollbackFor = RuntimeException.class)
@Override
public void update(SourceRebuildTask sourceRebuildTask) {
SourceRebuildTask checkIdResult = this.baseMapper.selectById(sourceRebuildTask.getId());
if (Objects.isNull(checkIdResult)) {
throw new RuntimeException("此任务不存在");
}
LambdaQueryWrapper<SourceRebuildTask> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SourceRebuildTask::getTaskName, sourceRebuildTask.getTaskName());
SourceRebuildTask checkcheckNameResult = this.baseMapper.selectOne(queryWrapper);
if (Objects.nonNull(checkcheckNameResult) && !sourceRebuildTask.getId().equals(checkcheckNameResult.getId())) {
throw new RuntimeException(""+sourceRebuildTask.getTaskName()+"为名称的任务已存在");
}
checkIdResult.setTaskName(sourceRebuildTask.getTaskName());
checkIdResult.setLatmin(sourceRebuildTask.getLatmin());
checkIdResult.setLonmin(sourceRebuildTask.getLonmin());
checkIdResult.setLatmax(sourceRebuildTask.getLatmax());
checkIdResult.setLonmax(sourceRebuildTask.getLonmax());
checkIdResult.setResolution(sourceRebuildTask.getResolution());
checkIdResult.setSrsStartTime(sourceRebuildTask.getSrsStartTime());
checkIdResult.setSrsEndTime(sourceRebuildTask.getSrsEndTime());
checkIdResult.setReleaseType(sourceRebuildTask.getReleaseType());
checkIdResult.setReleaseSourceLocation(sourceRebuildTask.getReleaseSourceLocation());
checkIdResult.setSourceLon(sourceRebuildTask.getSourceLon());
checkIdResult.setSourceLat(sourceRebuildTask.getSourceLat());
checkIdResult.setReleaseStartTime(sourceRebuildTask.getReleaseStartTime());
checkIdResult.setReleaseEndTime(sourceRebuildTask.getReleaseEndTime());
checkIdResult.setSourceStrength(sourceRebuildTask.getSourceStrength());
checkIdResult.setHalflife(sourceRebuildTask.getHalflife());
checkIdResult.setQmin(sourceRebuildTask.getQmin());
checkIdResult.setQmax(sourceRebuildTask.getQmax());
this.updateById(checkIdResult);
}
/**
* 删除源项重建任务
* @param id
*/
@Transactional(rollbackFor = RuntimeException.class)
@Override
public void delete(Integer id) {
SourceRebuildTask sourceRebuildTask = this.baseMapper.selectById(id);
if (Objects.isNull(sourceRebuildTask)) {
throw new RuntimeException("此任务不存在");
}
//删除结果文件
StringBuilder outputPath = new StringBuilder();
outputPath.append(systemStorageProperties.getRootPath());
outputPath.append("/");
outputPath.append(systemStorageProperties.getROutput());
outputPath.append("/");
outputPath.append(sourceRebuildTask.getTaskName());
if(FileUtil.exist(outputPath.toString())){
FileUtil.del(outputPath.toString());
}
//删除日志及上传的监测数据
this.sourceRebuildTaskLogService.delete(id);
this.monitoringDataService.delete(id);
this.baseMapper.deleteById(id);
}
/**
* 运行任务
* @param id
*/
@Override
public void runTask(Integer id) {
SourceRebuildTask sourceRebuildTask = this.baseMapper.selectById(id);
if(Objects.isNull(sourceRebuildTask)){
throw new RuntimeException("此任务不存在");
}
//校验监测数据
List<SourceRebuildMonitoringData> taskMonitoringDatas = this.monitoringDataService.getTaskMonitoringData(id);
if(CollectionUtils.isEmpty(taskMonitoringDatas)){
throw new RuntimeException("监测数据为空,请补充监测数据");
}
SourceRebuildTaskExec sourceRebuildTaskExec = new SourceRebuildTaskExec();
sourceRebuildTaskExec.init(
systemStorageProperties,
taskMonitoringDatas,
sourceRebuildTask,
sourceRebuildTaskLogService,
sourceRebuildParams,this);
sourceRebuildTaskExec.setName(sourceRebuildTask.getId()+"_任务执行线程");
sourceRebuildTaskExec.start();
}
/**
* 获取任务运行日志
* @param taskId
* @return
*/
@Override
public List<SourceRebuildTaskLog> getTaskLog(Integer taskId) {
LambdaQueryWrapper<SourceRebuildTaskLog> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SourceRebuildTaskLog::getTaskId, taskId);
queryWrapper.select(SourceRebuildTaskLog::getCreateTime,SourceRebuildTaskLog::getLogContent);
return sourceRebuildTaskLogMapper.selectList(queryWrapper);
}
/**
* 修改任务状态
*
* @param taskId
* @param taskStatus
*/
@Transactional(rollbackFor = RuntimeException.class)
@Override
public void updateTaskStatus(Integer taskId, Integer taskStatus) {
SourceRebuildTask sourceRebuildTask = this.baseMapper.selectById(taskId);
sourceRebuildTask.setTaskStatus(taskStatus);
this.updateById(sourceRebuildTask);
}
/**
* 任务耗时
*
* @param taskId
* @param taskTimeConsuming
*/
@Transactional(rollbackFor = RuntimeException.class)
@Override
public void updateTaskTimeConsuming(Integer taskId, Integer taskTimeConsuming) {
SourceRebuildTask sourceRebuildTask = this.baseMapper.selectById(taskId);
sourceRebuildTask.setTimeConsuming(taskTimeConsuming);
this.updateById(sourceRebuildTask);
}
}

View File

@ -0,0 +1,512 @@
package org.jeecg.service.impl;
import cn.hutool.core.date.DateUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.properties.SourceRebuildParams;
import org.jeecg.modules.base.entity.SourceRebuildTask;
import org.jeecg.service.SourceRebuildTaskService;
import org.jeecg.service.TaskResultDataService;
import org.jeecg.vo.*;
import org.rosuda.REngine.REXP;
import org.rosuda.REngine.REXPMismatchException;
import org.rosuda.REngine.RList;
import org.rosuda.REngine.Rserve.RConnection;
import org.rosuda.REngine.Rserve.RserveException;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.*;
@Service
@RequiredArgsConstructor
public class TaskResultDataServiceImpl implements TaskResultDataService {
private final SourceRebuildTaskService sourceRebuildTaskService;
private final SourceRebuildParams sourceRebuildParams;
/**
* 获取Rserve连接
* @return
*/
private RConnection getRConnection(){
RConnection conn = null;
try {
conn = new RConnection(sourceRebuildParams.getServerAddr(),sourceRebuildParams.getPort());
conn.login(sourceRebuildParams.getUsername(), sourceRebuildParams.getPassword());
} catch (RserveException e) {
throw new RuntimeException("Rserve连接失败");
}
return conn;
}
/**
* 关闭Rserve连接
* @param connection
*/
private void closeRConnection(RConnection connection){
if(Objects.nonNull(connection) && connection.isConnected()){
connection.close();
}
}
/**
* @param taskId
* @return
*/
@Override
public SourceProbabilityGrid getBayesProbLoc(Integer taskId) {
SourceRebuildTask task = this.sourceRebuildTaskService.getById(taskId);
if(StringUtils.isBlank(task.getResultAddress())){
throw new RuntimeException("此任务运行结果不存在,请检查运行日志");
}
RConnection conn = this.getRConnection();
if(!conn.isConnected()){
throw new RuntimeException("Rserve连接不可用");
}
SourceProbabilityGrid sourceProbabilityGrid = new SourceProbabilityGrid();
try {
String rdsPath = task.getResultAddress()+"/probloc.RDS";
REXP result = conn.eval("readRDS('" + rdsPath + "')");
if (result.isNumeric()) {
sourceProbabilityGrid.setData(result.asDoubleMatrix());
sourceProbabilityGrid.setLonmin(task.getLonmin());
sourceProbabilityGrid.setLonmax(task.getLonmax());
sourceProbabilityGrid.setLatmin(task.getLatmin());
sourceProbabilityGrid.setLatmax(task.getLatmax());
sourceProbabilityGrid.setRows(result.asDoubleMatrix().length);
sourceProbabilityGrid.setCols(result.asDoubleMatrix()[0].length);
}
} catch (RserveException e) {
throw new RuntimeException("RDS读取异常",e);
} catch (REXPMismatchException e) {
throw new RuntimeException("概率图矩阵数据解析异常",e);
}finally {
this.closeRConnection(conn);
}
return sourceProbabilityGrid;
}
/**
* 获取观测值和模拟值的活度浓度比较结果数据
* @param taskId
* @return
*/
@Override
public ActivityConcComparResult getBayesAcTimeSeries(Integer taskId) {
SourceRebuildTask task = this.sourceRebuildTaskService.getById(taskId);
if(StringUtils.isBlank(task.getResultAddress())){
throw new RuntimeException("此任务运行结果不存在,请检查运行日志");
}
RConnection conn = this.getRConnection();
if(!conn.isConnected()){
throw new RuntimeException("Rserve连接不可用");
}
ActivityConcComparResult activityConcComparResult = new ActivityConcComparResult();
try {
String obsRdsPath = task.getResultAddress()+"/obs.RDS";
REXP obsResult = conn.eval("readRDS('" + obsRdsPath + "')");
if (obsResult.isNumeric()) {
activityConcComparResult.setObsValues(obsResult.asDoubles());
}
String modRdsPath = task.getResultAddress()+"/mod.RDS";
REXP modResult = conn.eval("readRDS('" + modRdsPath + "')");
if (modResult.isNumeric()) {
activityConcComparResult.setModValues(modResult.asDoubles());
}
String mdcRdsPath = task.getResultAddress()+"/MDC.RDS";
REXP mdcResult = conn.eval("readRDS('" + mdcRdsPath + "')");
if (mdcResult.isNumeric()) {
activityConcComparResult.setMdcValues(mdcResult.asDoubles());
}
String stationsTxtPath = task.getResultAddress()+"/statnames.txt";
REXP stationsResult = conn.eval("readLines('" + stationsTxtPath + "')");
if (stationsResult.isString()) {
activityConcComparResult.setStations(stationsResult.asStrings());
}
} catch (RserveException e) {
throw new RuntimeException("RDS读取异常",e);
} catch (REXPMismatchException e) {
throw new RuntimeException("概率图矩阵数据解析异常",e);
}finally {
this.closeRConnection(conn);
}
return activityConcComparResult;
}
/**
* 获取双变量后验分布
*
* @param taskId
*/
@Override
public void getBayesBivarPosterior(Integer taskId) {
SourceRebuildTask task = this.sourceRebuildTaskService.getById(taskId);
if(StringUtils.isBlank(task.getResultAddress())){
throw new RuntimeException("此任务运行结果不存在,请检查运行日志");
}
RConnection conn = this.getRConnection();
if(!conn.isConnected()){
throw new RuntimeException("Rserve连接不可用");
}
}
/**
* 获取单变量后验分布
*
* @param taskId
*/
@Override
public Map<String,Object> getBayesMonovarPosterior(Integer taskId) {
SourceRebuildTask task = this.sourceRebuildTaskService.getById(taskId);
if(StringUtils.isBlank(task.getResultAddress())){
throw new RuntimeException("此任务运行结果不存在,请检查运行日志");
}
RConnection conn = this.getRConnection();
if(!conn.isConnected()){
throw new RuntimeException("Rserve连接不可用");
}
Map<String,Object> result = new HashMap<>();
try {
String posteriorRdsPath = task.getResultAddress()+"/bayes_monovarPosterior_aux.RDS";
REXP posteriorResult = conn.eval("readRDS('" + posteriorRdsPath + "')");
if (posteriorResult.isList()) {
//list是一个列表拥有chaindf, post_median, breaks, zprior多个嵌套对象
RList list = posteriorResult.asList();
//chaindf它是一个R的DataFrame存储的是抽样数据
REXP chaindf = list.at("chaindf");
//trueValues存储的是已知的释放源信息
//REXP trueValues = list.at("trueValues");
//存储的是lonlatlog10_Qtstarttstop的中位数
REXP post_median = list.at("post_median");
//存储的是lonlatlog10_Qtstarttstop的X轴的边界数据
REXP breaks = list.at("breaks");
//先验密度 breaks 点上
REXP zprior = list.at("zprior");
Map<String, Object> lonChartDataMap = this.processLonChart(chaindf, post_median, breaks, zprior);
Map<String, Object> latChartDataMap = this.processLatChart(chaindf, post_median, breaks, zprior);
Map<String, Object> log10ChartDataMap = this.processLog10Chart(chaindf, post_median, breaks, zprior);
Map<String, Object> startChartDataMap = this.processStartChart(chaindf, post_median, breaks, zprior);
Map<String, Object> stopChartDataMap = this.processStopChart(chaindf, post_median, breaks, zprior);
result.putAll(lonChartDataMap);
result.putAll(latChartDataMap);
result.putAll(log10ChartDataMap);
result.putAll(startChartDataMap);
result.putAll(stopChartDataMap);
}
} catch (RserveException e) {
throw new RuntimeException("RDS读取异常",e);
} catch (REXPMismatchException e) {
throw new RuntimeException("RDS 文件不是一个列表结构",e);
}
return result;
}
/**
* 处理lon图表数据
* @param chaindf
* @param postMedian
* @param breaks
* @param zprior
* @return
*/
private Map<String,Object> processLonChart(REXP chaindf,REXP postMedian,REXP breaks,REXP zprior) throws REXPMismatchException {
Map<String,Object> map = new HashMap<>();
//封装对象
HistogramChartStru histogramChartStru = new HistogramChartStru();
//设置中位数蓝色线
REXP lon = postMedian.asList().at("lon");
histogramChartStru.setPostMedian(lon.asDouble());
//设置先验分布数据绿色线
REXP break1 = breaks.asList().at(0);
if(break1.isNumeric() && zprior.isNumeric()){
double[] break1Data = break1.asDoubles();
double[][] zprio1Data = zprior.asDoubleMatrix();
//设置X轴边界
histogramChartStru.setXMin(break1Data[0]);
histogramChartStru.setXMax(break1Data[break1Data.length-1]);
if(break1Data.length != zprio1Data.length){
throw new RuntimeException("RDS读取异常,break数据和zprio长度不一致");
}
List<PriorDistribution> priorDistributionList = new ArrayList<>();
for (int i = 0; i < break1Data.length; i++) {
PriorDistribution priorDistribution = new PriorDistribution();
priorDistribution.setXValue(break1Data[i]);
priorDistribution.setYValue(zprio1Data[i][0]);
priorDistributionList.add(priorDistribution);
}
histogramChartStru.setPriorDistributionList(priorDistributionList);
}
//获取lon列数据
REXP column = chaindf.asList().at(0);
if(column.isNumeric()){
double[] break1Data = break1.asDoubles();
double[] columnVals = column.asDoubles();
List<HistogramChartBarData> histogramChartBarDataList = new ArrayList<>();
for (int i= 0; i < break1Data.length; i++) {
if(i==break1Data.length-1){
break;
}
int finalI = i;
long countVal = Arrays.stream(columnVals).parallel().filter(colVals -> (colVals >= break1Data[finalI] && colVals <= break1Data[finalI + 1])).count();
HistogramChartBarData histogramChartBarData = new HistogramChartBarData();
histogramChartBarData.setXLeftVal(break1Data[i]);
histogramChartBarData.setXRightVal(break1Data[i+1]);
histogramChartBarData.setYValue(countVal);
histogramChartBarDataList.add(histogramChartBarData);
}
histogramChartStru.setHistogramChartBarDataList(histogramChartBarDataList);
}
map.put("lonChartStru",histogramChartStru);
return map;
}
/**
* 处理lat图表数据
* @param chaindf
* @param postMedian
* @param breaks
* @param zprior
* @return
*/
private Map<String,Object> processLatChart(REXP chaindf,REXP postMedian,REXP breaks,REXP zprior) throws REXPMismatchException {
Map<String,Object> map = new HashMap<>();
//封装对象
HistogramChartStru histogramChartStru = new HistogramChartStru();
//设置中位数蓝色线
REXP lat = postMedian.asList().at("lat");
histogramChartStru.setPostMedian(lat.asDouble());
//设置先验分布数据绿色线
REXP break2 = breaks.asList().at(1);
if(break2.isNumeric() && zprior.isNumeric()){
double[] break2Data = break2.asDoubles();
double[][] zprio2Data = zprior.asDoubleMatrix();
//设置X轴边界
histogramChartStru.setXMin(break2Data[0]);
histogramChartStru.setXMax(break2Data[break2Data.length-1]);
if(break2Data.length != zprio2Data.length){
throw new RuntimeException("RDS读取异常,break数据和zprio长度不一致");
}
List<PriorDistribution> priorDistributionList = new ArrayList<>();
for (int i = 0; i < break2Data.length; i++) {
PriorDistribution priorDistribution = new PriorDistribution();
priorDistribution.setXValue(break2Data[i]);
priorDistribution.setYValue(zprio2Data[i][1]);
priorDistributionList.add(priorDistribution);
}
histogramChartStru.setPriorDistributionList(priorDistributionList);
}
//获取lat列数据
REXP column = chaindf.asList().at(1);
if(column.isNumeric()){
double[] break1Data = break2.asDoubles();
double[] columnVals = column.asDoubles();
List<HistogramChartBarData> histogramChartBarDataList = new ArrayList<>();
for (int i= 0; i < break1Data.length; i++) {
if(i==break1Data.length-1){
break;
}
int finalI = i;
long countVal = Arrays.stream(columnVals).parallel().filter(colVals -> (colVals >= break1Data[finalI] && colVals <= break1Data[finalI + 1])).count();
HistogramChartBarData histogramChartBarData = new HistogramChartBarData();
histogramChartBarData.setXLeftVal(break1Data[i]);
histogramChartBarData.setXRightVal(break1Data[i+1]);
histogramChartBarData.setYValue(countVal);
histogramChartBarDataList.add(histogramChartBarData);
}
histogramChartStru.setHistogramChartBarDataList(histogramChartBarDataList);
}
map.put("latChartStru",histogramChartStru);
return map;
}
/**
* 处理log10_Q图表数据
* @param chaindf
* @param postMedian
* @param breaks
* @param zprior
* @return
*/
private Map<String,Object> processLog10Chart(REXP chaindf,REXP postMedian,REXP breaks,REXP zprior) throws REXPMismatchException {
Map<String,Object> map = new HashMap<>();
//封装对象
HistogramChartStru histogramChartStru = new HistogramChartStru();
//设置中位数蓝色线
REXP log10_Q = postMedian.asList().at("log10_Q");
histogramChartStru.setPostMedian(log10_Q.asDouble());
//设置先验分布数据绿色线
REXP break3 = breaks.asList().at(2);
if(break3.isNumeric() && zprior.isNumeric()){
double[] break3Data = break3.asDoubles();
double[][] zprio3Data = zprior.asDoubleMatrix();
//设置X轴边界
histogramChartStru.setXMin(break3Data[0]);
histogramChartStru.setXMax(break3Data[break3Data.length-1]);
if(break3Data.length != zprio3Data.length){
throw new RuntimeException("RDS读取异常,break数据和zprio长度不一致");
}
List<PriorDistribution> priorDistributionList = new ArrayList<>();
for (int i = 0; i < break3Data.length; i++) {
PriorDistribution priorDistribution = new PriorDistribution();
priorDistribution.setXValue(break3Data[i]);
priorDistribution.setYValue(zprio3Data[i][2]);
priorDistributionList.add(priorDistribution);
}
histogramChartStru.setPriorDistributionList(priorDistributionList);
}
//获取log10_Q列数据
REXP column = chaindf.asList().at(2);
if(column.isNumeric()){
double[] break1Data = break3.asDoubles();
double[] columnVals = column.asDoubles();
List<HistogramChartBarData> histogramChartBarDataList = new ArrayList<>();
for (int i= 0; i < break1Data.length; i++) {
if(i==break1Data.length-1){
break;
}
int finalI = i;
long countVal = Arrays.stream(columnVals).parallel().filter(colVals -> (colVals >= break1Data[finalI] && colVals <= break1Data[finalI + 1])).count();
HistogramChartBarData histogramChartBarData = new HistogramChartBarData();
histogramChartBarData.setXLeftVal(break1Data[i]);
histogramChartBarData.setXRightVal(break1Data[i+1]);
histogramChartBarData.setYValue(countVal);
histogramChartBarDataList.add(histogramChartBarData);
}
histogramChartStru.setHistogramChartBarDataList(histogramChartBarDataList);
}
map.put("log10_QChartStru",histogramChartStru);
return map;
}
/**
* 处理tstart图表数据
* @param chaindf
* @param postMedian
* @param breaks
* @param zprior
* @return
*/
private Map<String,Object> processStartChart(REXP chaindf,REXP postMedian,REXP breaks,REXP zprior) throws REXPMismatchException {
Map<String,Object> map = new HashMap<>();
//封装对象
HistogramChartStru histogramChartStru = new HistogramChartStru();
//设置中位数蓝色线
REXP tstart = postMedian.asList().at("rstart");
histogramChartStru.setPostMedian(this.posixctToCSTString(tstart.asDouble()));
//设置先验分布数据绿色线
REXP break4 = breaks.asList().at(3);
if(break4.isNumeric() && zprior.isNumeric()){
double[] break4Data = break4.asDoubles();
double[][] zprio4Data = zprior.asDoubleMatrix();
//设置X轴边界
histogramChartStru.setXMin(this.posixctToCSTString(break4Data[0]));
histogramChartStru.setXMax(this.posixctToCSTString(break4Data[break4Data.length-1]));
if(break4Data.length != zprio4Data.length){
throw new RuntimeException("RDS读取异常,break数据和zprio长度不一致");
}
List<PriorDistribution> priorDistributionList = new ArrayList<>();
for (int i = 0; i < break4Data.length; i++) {
PriorDistribution priorDistribution = new PriorDistribution();
priorDistribution.setXValue(this.posixctToCSTString(break4Data[i]));
priorDistribution.setYValue(String.format("%.20f",zprio4Data[i][3]));
priorDistributionList.add(priorDistribution);
}
histogramChartStru.setPriorDistributionList(priorDistributionList);
}
//获取tstart列数据
REXP column = chaindf.asList().at(3);
if(column.isNumeric()){
double[] break1Data = break4.asDoubles();
double[] columnVals = column.asDoubles();
List<HistogramChartBarData> histogramChartBarDataList = new ArrayList<>();
for (int i= 0; i < break1Data.length; i++) {
if(i==break1Data.length-1){
break;
}
int finalI = i;
long countVal = Arrays.stream(columnVals).parallel().filter(colVals -> (colVals >= break1Data[finalI] && colVals <= break1Data[finalI + 1])).count();
HistogramChartBarData histogramChartBarData = new HistogramChartBarData();
histogramChartBarData.setXLeftVal(this.posixctToCSTString(break1Data[i]));
histogramChartBarData.setXRightVal(this.posixctToCSTString(break1Data[i+1]));
histogramChartBarData.setYValue(countVal);
histogramChartBarDataList.add(histogramChartBarData);
}
histogramChartStru.setHistogramChartBarDataList(histogramChartBarDataList);
}
map.put("startChartStru",histogramChartStru);
return map;
}
/**
* 处理tstop图表数据
* @param chaindf
* @param postMedian
* @param breaks
* @param zprior
* @return
*/
private Map<String,Object> processStopChart(REXP chaindf,REXP postMedian,REXP breaks,REXP zprior) throws REXPMismatchException {
Map<String,Object> map = new HashMap<>();
//封装对象
HistogramChartStru histogramChartStru = new HistogramChartStru();
//设置中位数蓝色线
REXP tstart = postMedian.asList().at("rstop");
histogramChartStru.setPostMedian(this.posixctToCSTString(tstart.asDouble()));
//设置先验分布数据绿色线
REXP break5 = breaks.asList().at(4);
if(break5.isNumeric() && zprior.isNumeric()){
double[] break5Data = break5.asDoubles();
double[][] zprio5Data = zprior.asDoubleMatrix();
//设置X轴边界
histogramChartStru.setXMin(this.posixctToCSTString(break5Data[0]));
histogramChartStru.setXMax(this.posixctToCSTString(break5Data[break5Data.length-1]));
if(break5Data.length != zprio5Data.length){
throw new RuntimeException("RDS读取异常,break数据和zprio长度不一致");
}
List<PriorDistribution> priorDistributionList = new ArrayList<>();
for (int i = 0; i < break5Data.length; i++) {
PriorDistribution priorDistribution = new PriorDistribution();
priorDistribution.setXValue(this.posixctToCSTString(break5Data[i]));
priorDistribution.setYValue(String.format("%.20f",zprio5Data[i][4]));
priorDistributionList.add(priorDistribution);
}
histogramChartStru.setPriorDistributionList(priorDistributionList);
}
//获取tstop列数据
REXP column = chaindf.asList().at(4);
if(column.isNumeric()){
double[] break1Data = break5.asDoubles();
double[] columnVals = column.asDoubles();
List<HistogramChartBarData> histogramChartBarDataList = new ArrayList<>();
for (int i= 0; i < break1Data.length; i++) {
if(i==break1Data.length-1){
break;
}
int finalI = i;
long countVal = Arrays.stream(columnVals).parallel().filter(colVals -> (colVals >= break1Data[finalI] && colVals <= break1Data[finalI + 1])).count();
HistogramChartBarData histogramChartBarData = new HistogramChartBarData();
histogramChartBarData.setXLeftVal(this.posixctToCSTString(break1Data[i]));
histogramChartBarData.setXRightVal(this.posixctToCSTString(break1Data[i+1]));
histogramChartBarData.setYValue(countVal);
histogramChartBarDataList.add(histogramChartBarData);
}
histogramChartStru.setHistogramChartBarDataList(histogramChartBarDataList);
}
map.put("stopChartStru",histogramChartStru);
return map;
}
/**
* 转换R语言项目的时间
* @param posixctSeconds
* @return
*/
private String posixctToCSTString(double posixctSeconds){
Date date = new Date((long) posixctSeconds * 1000);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
return sdf.format(date);
}
}

View File

@ -0,0 +1,386 @@
package org.jeecg.task;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ArrayUtil;
import org.apache.commons.lang3.time.StopWatch;
import org.jeecg.common.constant.enums.SourceRebuildReleaseSourceEnum;
import org.jeecg.common.constant.enums.SourceRebuildTaskStatusEnum;
import org.jeecg.common.properties.SourceRebuildParams;
import org.jeecg.common.properties.SystemStorageProperties;
import org.jeecg.modules.base.entity.SourceRebuildMonitoringData;
import org.jeecg.modules.base.entity.SourceRebuildTask;
import org.jeecg.modules.base.entity.SourceRebuildTaskLog;
import org.jeecg.service.SourceRebuildTaskLogService;
import org.jeecg.service.SourceRebuildTaskService;
import org.rosuda.REngine.REXP;
import org.rosuda.REngine.REXPDouble;
import org.rosuda.REngine.REXPInteger;
import org.rosuda.REngine.REXPMismatchException;
import org.rosuda.REngine.Rserve.RConnection;
import org.rosuda.REngine.Rserve.RserveException;
import org.springframework.util.CollectionUtils;
import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
public class SourceRebuildTaskExec extends Thread{
private SystemStorageProperties systemStorageProperties;
private List<SourceRebuildMonitoringData> taskMonitoringDatas;
private SourceRebuildTaskLogService sourceRebuildTaskLogService;
private SourceRebuildTask sourceRebuildTask;
private SourceRebuildParams sourceRebuildParams;
private SourceRebuildTaskService sourceRebuildTaskService;
/**
* 初始化
*/
public void init(SystemStorageProperties systemStorageProperties,
List<SourceRebuildMonitoringData> taskMonitoringDatas,
SourceRebuildTask sourceRebuildTask,
SourceRebuildTaskLogService sourceRebuildTaskLogService,
SourceRebuildParams sourceRebuildParams,
SourceRebuildTaskService sourceRebuildTaskService){
this.systemStorageProperties = systemStorageProperties;
this.taskMonitoringDatas = taskMonitoringDatas;
this.sourceRebuildTask = sourceRebuildTask;
this.sourceRebuildTaskLogService = sourceRebuildTaskLogService;
this.sourceRebuildParams = sourceRebuildParams;
this.sourceRebuildTaskService = sourceRebuildTaskService;
}
@Override
public void run() {
this.execute();
}
/**
* 执行任务
*/
public void execute(){
StopWatch stopWatch = new StopWatch();
stopWatch.start();
try{
//修改任务状态为执行中
this.sourceRebuildTaskService.updateTaskStatus(this.sourceRebuildTask.getId(), SourceRebuildTaskStatusEnum.IN_OPERATION.getValue());
//如果此任务已存在历史日志先清除
sourceRebuildTaskLogService.delete(this.sourceRebuildTask.getId());
String startRunLog = "----------------------------------------开始执行任务----------------------------------------";
this.generateLog(startRunLog);
//生成重建需要的监测数据
String monitorDataLog = "----------------------------------------生成监测数据输入文件----------------------------------------";
String titleLog = "Entity,Metric,Date,Value,Uncertainty,MDC Value";
this.generateLog(monitorDataLog);
this.generateLog(titleLog);
// this.generateMonitoringDataFile();
//生成SRS关系文件
String srsDataLog = "----------------------------------------生成SRS数据输入文件----------------------------------------";
this.generateLog(srsDataLog);
// this.generateSRSDataFile();
String sourceProcessDataLog = "----------------------------------------配置源项分析参数并执行源项重建----------------------------------------";
this.generateLog(sourceProcessDataLog);
this.execSourceRebuild();
String genStopLog = "----------------------------------------任务执行结束----------------------------------------";
this.generateLog(genStopLog);
}catch (Exception e){
String taskErrorLog = "任务执行失败,原因:"+e.getMessage();
this.generateLog(taskErrorLog);
throw e;
}finally {
//添加任务耗时
stopWatch.stop();
Integer time = Long.valueOf(stopWatch.getTime(TimeUnit.MINUTES)).intValue();
this.sourceRebuildTaskService.updateTaskTimeConsuming(this.sourceRebuildTask.getId(),time);
}
}
/**
* 生成重建需要的监测数据
*/
private void generateMonitoringDataFile(){
//根据监测数据生成文件input_subexp1.dat
String inputPath = this.getInputPath();
File inputSubexp1 = new File(inputPath.toString() +File.separator+ "input_subexp1.dat");
if(!FileUtil.exist(inputSubexp1)){
FileUtil.touch(inputSubexp1);
}
//格式化监测数据
String title = "Entity,Metric,Date,Value,Uncertainty,MDC Value";
List<String> lines = new ArrayList<>();
lines.add(title);
for(SourceRebuildMonitoringData taskMonitoringData : taskMonitoringDatas){
String station = taskMonitoringData.getStation();
String nuclide = taskMonitoringData.getNuclide();
String date = DateUtil.format(taskMonitoringData.getCollectStop(),"yyyy-MM-dd HH:mm");
String activity = this.formatSCI(taskMonitoringData.getActivity());
String uncertainty = this.formatSCI(taskMonitoringData.getUncertainty());
String mdc = this.formatSCI(taskMonitoringData.getMdc());
String formattedLine = String.format("%s, %s, %s, %s, %s, %s",station,nuclide,date,activity,uncertainty,mdc);
lines.add(formattedLine);
//把监测数据详情保存到日志
this.generateLog(formattedLine);
}
FileUtil.writeLines(lines,inputSubexp1,"UTF-8");
}
/**
* 生成SRS关系数据文件
*/
private void generateSRSDataFile(){
//以日期为key以文件相对路径为value
Map<Date,String> allSRSFileMap = new HashMap<>();
Map<Date,String> finalSRSFileMap = new TreeMap<>();
//根据监测数据校验SRS文件如果缺少SRS文件也报错
String srsFilePath = this.getSRSFilePath();
Path dirpath = Paths.get(srsFilePath);
try(Stream<Path> walk = Files.walk(dirpath)) {
walk.filter(Files::isRegularFile)
.filter(path -> path.toAbsolutePath().toString().contains(systemStorageProperties.getXeGZFileDirSign()))
.forEach(filePath -> {
//USX77.fp.2024112115.f9.srm
String[] nameArr = filePath.getFileName().toString().split("\\.");
Date date = DateUtil.parse(nameArr[2],"yyyyMMddHH");
String relativePath = filePath.toAbsolutePath().toString().substring(filePath.toAbsolutePath().toString().indexOf("srs"));
allSRSFileMap.put(date,relativePath);
});
//如果遍历指定目录没有找到SRS数据文件则结束
if(CollectionUtils.isEmpty(allSRSFileMap)){
String srsNotExistLog = "SRS 文件存储目录中没有SRS数据文件";
throw new RuntimeException(srsNotExistLog);
}
//根据监测数据多线程找对应的SRS数据文件每一个没找到都写入日志
int srsNotExistCount = 0;
for(SourceRebuildMonitoringData monitoringData : this.taskMonitoringDatas){
boolean flag = false;
String station = monitoringData.getStation();
Date collectStop = monitoringData.getCollectStop();
for (Map.Entry<Date, String> entry : allSRSFileMap.entrySet()) {
Date date = entry.getKey();
String srsFile = entry.getValue();
if(srsFile.contains(station)){
boolean withinSixHours = this.isWithinSixHours(collectStop, date);
if (withinSixHours) {
finalSRSFileMap.put(collectStop, srsFile);
flag = true;
break;
}
}
}
if (!flag){
srsNotExistCount ++;
String targetSRSNotExist = "监测数据:"+DateUtil.format(collectStop,"yyyyMMddHH")+"所对应的SRS文件不存在";
this.generateLog(targetSRSNotExist);
}
}
//当监测数据都寻找完对应的SRS数据文件后未寻找到的结果如果大于0则结束流程并写入日志
if(srsNotExistCount > 0){
String countSRSNotExist = "共有:"+srsNotExistCount+"条监测数据找不到对应的SRS数据文件";
this.generateLog(countSRSNotExist);
throw new RuntimeException(countSRSNotExist);
}
//每条监测数据都找到SRS数据文件后生成文件srsfilelist_subexp1.dat
String inputPath = getInputPath();
File srsSubexp1 = new File(inputPath +File.separator+ "srsfilelist_subexp1.dat");
if(!FileUtil.exist(srsSubexp1)){
FileUtil.touch(srsSubexp1);
}
//去重并格式化监测数据
List<String> lines = new ArrayList<>(finalSRSFileMap.values());
//把SRS数据详情保存到日志
lines.forEach(this::generateLog);
//写入到文件
FileUtil.writeLines(lines,srsSubexp1,"UTF-8");
}catch (Exception e){
throw new RuntimeException(e.getMessage());
}
}
/**
* 执行源项重建
*/
private void execSourceRebuild(){
RConnection conn = null;
try {
conn = new RConnection(this.sourceRebuildParams.getServerAddr(), this.sourceRebuildParams.getPort());
conn.login(this.sourceRebuildParams.getUsername(), this.sourceRebuildParams.getPassword());
if(conn.isConnected()){
String log = "Rserve 连接成功,设置运行参数";
this.generateLog(log);
//重建任务名称
conn.assign("experiment", "FREAR_syntheticTestCase");
//重建任务输入数据目录
conn.assign("expdir", this.getInputPath());
conn.assign("datadir", this.getSRSFilePath());
//重建任务输出数据目录
conn.assign("outbasedir", this.getOutputPath());
//数据库相关
conn.assign("dbHost", "192.168.42.54");
conn.assign("dbPort", new REXPInteger(5432));
conn.assign("dbName", "stas");
conn.assign("dbUser", "stas");
conn.assign("dbPassword", "123456");
//任务关联ID
conn.assign("taskId", this.sourceRebuildTask.getId().toString());
//半衰期
// conn.assign("halflife", new REXPDouble(this.sourceRebuildTask.getHalflife()));
//设置最小总累积源项Bq
conn.assign("Qmin", new REXPDouble(Math.pow(10, this.sourceRebuildTask.getQmin())));
//设置最大总累积源项Bq
conn.assign("Qmax", new REXPDouble(Math.pow(10, this.sourceRebuildTask.getQmax())));
//重建经纬度分辨率
Double lonmin = this.sourceRebuildTask.getLonmin();
Double latmin = this.sourceRebuildTask.getLatmin();
Double lonmax = this.sourceRebuildTask.getLonmax();
Double latmax = this.sourceRebuildTask.getLatmax();
String resolution = this.sourceRebuildTask.getResolution();
String domain = String.format("domain <- list(lonmin=%s,latmin=%s,lonmax=%s,latmax=%s,dx=%s,dy=%s)",lonmin,latmin,lonmax,latmax,resolution,resolution);
conn.eval(domain);
//设置时间范围
String srsStartTime = DateUtil.format(this.sourceRebuildTask.getSrsStartTime(), "yyyy-MM-dd");
String srsEndTime = DateUtil.format(this.sourceRebuildTask.getSrsEndTime(), "yyyy-MM-dd");
String times = String.format("times <- expression(seq(as.POSIXct('%s'),as.POSIXct('%s'),by=3*3600))",srsStartTime,srsEndTime);
conn.eval(times);
//如果已知排放源位置
if(SourceRebuildReleaseSourceEnum.KNOWN.getValue().equals(this.sourceRebuildTask.getReleaseSourceLocation())){
//已知源位置经度
Double lon = this.sourceRebuildTask.getSourceLon();
//已知源位置纬度
Double lat = this.sourceRebuildTask.getSourceLat();
//已知源位置源强
Integer sourceStrength = this.sourceRebuildTask.getSourceStrength();
//已知源位置开始时间
String releaseStartTime = DateUtil.format(this.sourceRebuildTask.getReleaseStartTime(),"yyyy-MM-dd HH:mm:ss");
//已知源结束时间
String releaseEndTime = DateUtil.format(this.sourceRebuildTask.getReleaseEndTime(),"yyyy-MM-dd HH:mm:ss");
String formattedLine = String.format("trueValues <- c(%s,%s,%s,%s,%s)",lon,lat,sourceStrength,releaseStartTime,releaseEndTime);
conn.eval(formattedLine);
}else {
//未知源
conn.eval("trueValues <- c(NA,NA,NA,NA,NA)");
}
//设置工作目录
conn.eval("setwd(\""+this.sourceRebuildParams.getWorkSpace()+"\")");
//执行脚本
conn.eval("source(\"test_case/expdir/set_up.R\")");
REXP outputREXP = conn.eval("capture.output({source(\"test_case/expdir/main.R\")})");
// 将输出作为字符串数组获取
String[] outputLines = outputREXP.asStrings();
if(ArrayUtil.isNotEmpty(outputLines)){
this.batchGenerateLog(outputLines);
}
}
} catch (RserveException e) {
String log = "Rserve 执行过程报错,请检查配置参数";
throw new RuntimeException(log);
} catch (REXPMismatchException e) {
throw new RuntimeException(e);
}
}
/**
* 判断两个时间误差是否在2小时内
* @param date1
* @param date2
* @return
*/
private boolean isWithinSixHours(Date date1, Date date2){
long diffInMillis = Math.abs(date2.getTime() - date1.getTime());// 毫秒差绝对值
long sixHoursInMillis = 6 * 60 * 60 * 1000; // 6小时
return diffInMillis <= sixHoursInMillis;
}
/**
* 格式化为科学计数法
* @param value
* @return
*/
private String formatSCI(String value){
BigDecimal divideVal = new BigDecimal("1000");
BigDecimal bigDecimal = new BigDecimal(value);
BigDecimal result = bigDecimal.divide(divideVal,RoundingMode.HALF_UP);
// 设置科学计数法格式保留6位小数
DecimalFormat df = new DecimalFormat("0.######E0");
df.setMaximumFractionDigits(6); // 最多6位小数
df.setMinimumFractionDigits(6); // 强制补零到6位
return df.format(result);
}
/**
* 获取R项目运行输入监测数据及监测数据和srs对应关系文件地址
* @return
*/
private String getInputPath(){
StringBuilder inputPath = new StringBuilder();
inputPath.append(systemStorageProperties.getRootPath());
inputPath.append("/");
inputPath.append(systemStorageProperties.getRInput());
if(!FileUtil.exist(inputPath.toString())){
FileUtil.mkdir(inputPath.toString());
}
return inputPath.toString();
}
/**
* 获取SRS 文件存储路径
* @return
*/
private String getSRSFilePath(){
StringBuilder srsFilePath = new StringBuilder();
srsFilePath.append(systemStorageProperties.getRootPath());
srsFilePath.append("/");
srsFilePath.append(systemStorageProperties.getSrsFilePath());
// if(!FileUtil.exist(srsFilePath.toString())){
// String srsNotExistLog = "SRS 文件存储目录不存在";
// throw new RuntimeException(srsNotExistLog);
// }
return srsFilePath.toString();
}
/**
* 获取R项目运行结果输出地址
* @return
*/
private String getOutputPath(){
StringBuilder outputPath = new StringBuilder();
outputPath.append(systemStorageProperties.getRootPath());
outputPath.append("/");
outputPath.append(systemStorageProperties.getROutput());
outputPath.append("/");
outputPath.append(sourceRebuildTask.getTaskName());
if(!FileUtil.exist(outputPath.toString())){
FileUtil.mkdir(outputPath.toString());
}
return outputPath.toString();
}
/**
* 保存任务运行过程日志
* @param logContent
*/
private void generateLog(String logContent){
sourceRebuildTaskLogService.cteate(new SourceRebuildTaskLog(sourceRebuildTask.getId(),logContent));
}
/**
* 保存任务运行过程日志
* @param logContents
*/
private void batchGenerateLog(String[] logContents){
List<SourceRebuildTaskLog> logs = new ArrayList<>();
for(String logContent : logContents){
logs.add(new SourceRebuildTaskLog(sourceRebuildTask.getId(),logContent));
}
sourceRebuildTaskLogService.batchCteate(logs);
}
}

View File

@ -0,0 +1,29 @@
package org.jeecg.vo;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* 活度浓度比较结果
*/
@Data
public class ActivityConcComparResult implements Serializable {
/**
* 观测值
*/
private double[] obsValues;
/**
* 模拟值
*/
private double[] modValues;
/**
* mdc值
*/
private double[] mdcValues;
/**
* 台站列表
*/
private String[] stations;
}

View File

@ -0,0 +1,23 @@
package org.jeecg.vo;
import lombok.Data;
/**
* lonlatlog10_Qtstarttstop直方图数据
*/
@Data
public class HistogramChartBarData {
/**
* 每个柱子的左边界值
*/
private Object xLeftVal;
/**
* 每个柱子的右边界值
*/
private Object xRightVal;
/**
* 每个柱子的Y轴值
*/
private Long yValue;
}

View File

@ -0,0 +1,37 @@
package org.jeecg.vo;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* lonlatlog10_Qtstarttstop直方图数据结构
*/
@Data
public class HistogramChartStru implements Serializable {
/**
* X轴最小值
*/
private Object xMin;
/**
* X轴最大值
*/
private Object xMax;
/**
* 中位数
*/
private Object postMedian;
/**
* 柱状图bar数据
*/
private List<HistogramChartBarData> histogramChartBarDataList;
/**
* 先验分布List
*/
private List<PriorDistribution> priorDistributionList;
}

View File

@ -0,0 +1,16 @@
package org.jeecg.vo;
import lombok.Data;
import java.io.Serializable;
/**
* 直方图先验分布数据
*/
@Data
public class PriorDistribution implements Serializable {
private Object xValue;
private Object yValue;
}

View File

@ -0,0 +1,41 @@
package org.jeecg.vo;
import lombok.Data;
import java.io.Serializable;
/**
* 概率分布图数据
*/
@Data
public class SourceProbabilityGrid implements Serializable {
/**
* 概率分布数据
*/
private double[][] data;
/**
* 最小经度
*/
private double lonmin;
/**
* 最小纬度
*/
private double latmin;
/**
* 最大经度
*/
private double lonmax;
/**
* 最大纬度
*/
private double latmax;
/**
* 行数
*/
private int rows;
/**
* 列数
*/
private int cols;
}

View File

@ -0,0 +1,91 @@
import org.rosuda.REngine.*;
import org.rosuda.REngine.Rserve.RConnection;
import org.rosuda.REngine.Rserve.RserveException;
public class RTest {
public static void main(String[] args) throws RserveException, REXPMismatchException {
String host = "192.168.186.142";
int port = 6311;
// 如果有认证
String user = "rserve";
String password = "123456";
String scriptPath = "/home/centos/r_workspace/FREAR-master/test_case/expdir/main.R";
RConnection conn = new RConnection(host, port);
conn.login(user, password);
System.out.println(conn.isConnected());
if(conn.isConnected()){
//重建任务名称
conn.assign("experiment", "test");
//重建任务输入数据目录
conn.assign("expdir", "test_case/expdir");
conn.assign("datadir", "test_case/data");
//重建任务输出数据目录
conn.assign("outbasedir", "/home/centos/r_workspace/work_output");
//数据库相关
conn.assign("dbHost", "192.168.42.54");
conn.assign("dbPort", new REXPInteger(5432));
conn.assign("dbName", "stas");
conn.assign("dbUser", "stas");
conn.assign("dbPassword", "123456");
//任务关联ID
conn.assign("taskId", "8");
//半衰期
conn.assign("halflife", new REXPDouble(5.243));
//设置最小总累积源项Bq
conn.assign("Qmin", new REXPDouble(Math.pow(10, 5)));
//设置最大总累积源项Bq
conn.assign("Qmax", new REXPDouble(Math.pow(10, 15)));
//未知源#settings$trueValues <- c(NA,NA,NA,NA,NA)
//已知源位置经度
//已知源位置纬度
//已知源位置源强
//已知源位置开始时间
//已知源结束时间
// 反演经纬度分辨率
conn.eval("domain <- list(lonmin=125, latmin=38, lonmax=130, latmax=40, dx=.5, dy=.5)");
//设置工作目录
conn.eval("setwd(\"/home/centos/r_workspace/FREAR-master\")");
//执行脚本
conn.eval("source(\"test_case/expdir/set_up.R\")");
REXP outputREXP = conn.eval("capture.output({source(\"test_case/expdir/main.R\")})");
// 将输出作为字符串数组获取
String[] outputLines = outputREXP.asStrings();
for (String line : outputLines) {
System.out.println("[R LOG] " + line); // 在Java控制台打印日志
// 你也可以将日志存入变量文件或发送到日志系统
}
//读取数据
// String rdsPath = "/home/centos/r_workspace/work_output/测试任务1/FREAR_syntheticTestCase_subexp1_20250909_1128/probloc.RDS";
// REXP result = conn.eval("readRDS('" + rdsPath + "')");
//
// if (result.isNumeric()) {
// double[][] values = result.asDoubleMatrix();
// System.out.println("Numeric vector, length: " + values.length);
// for (int i = 0; i < values.length; i++) {
// for (int j = 0; j < values[i].length; j++) {
// System.out.print(values[i][j] + " ");
// }
// System.out.println(); // 换行
// }
// }
// else if (result.isString()) {
// String[] strings = result.asStrings();
// System.out.println("String vector:");
// for (String s : strings) System.out.println(s);
// }
// else if (result.isList()) {
// // 如果是列表list可以进一步解析
// System.out.println("It's a list with " + result.length() + " elements");
// // 可递归处理
// }
}
conn.close();
}
}

View File

@ -0,0 +1,6 @@
public class RTest1 {
public static void main(String[] args) {
System.out.println(Math.pow(10, 15));
}
}

View File

@ -5,7 +5,6 @@ import com.baomidou.mybatisplus.extension.service.IService;
import org.jeecg.common.system.query.PageRequest;
import org.jeecg.modules.base.entity.WeatherTask;
import org.jeecg.modules.base.entity.WeatherTaskLog;
import java.time.LocalDate;
import java.util.List;

View File

@ -5,7 +5,6 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.constant.enums.WeatherTaskStatusEnum;
import org.jeecg.common.system.query.PageRequest;
@ -18,6 +17,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
@ -43,7 +43,11 @@ public class WeatherTaskServiceImpl extends ServiceImpl<WeatherTaskMapper, Weath
public IPage<WeatherTask> page(PageRequest pageRequest, String taskName, Integer taskStatus, LocalDate startDate,LocalDate endDate) {
LambdaQueryWrapper<WeatherTask> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Objects.nonNull(taskStatus),WeatherTask::getTaskStatus, taskStatus);
queryWrapper.between((Objects.nonNull(startDate) && Objects.nonNull(endDate)),WeatherTask::getStartDate,startDate,endDate);
if(Objects.nonNull(startDate) && Objects.nonNull(endDate)){
LocalDateTime startDateTime = startDate.atTime(0, 0, 0);
LocalDateTime endDateTime = endDate.atTime(23, 59, 59);
queryWrapper.between(WeatherTask::getStartDate,startDateTime,endDateTime);
}
queryWrapper.like(StringUtils.isNotBlank(taskName),WeatherTask::getTaskName,taskName);
queryWrapper.orderByDesc(WeatherTask::getStartDate);

View File

@ -9,7 +9,7 @@
<version>3.8.1</version>
</parent>
<artifactId>jeecg-sourceitem-reconstruction-start</artifactId>
<artifactId>jeecg-source-rebuild-start</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
@ -29,7 +29,7 @@
</dependency>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-module-sourceitem-reconstruction</artifactId>
<artifactId>jeecg-module-source-rebuild</artifactId>
<version>${jeecgboot.version}</version>
</dependency>
</dependencies>

View File

@ -22,17 +22,17 @@ import java.net.UnknownHostException;
@SpringBootApplication
@RequiredArgsConstructor
@EnableFeignClients
public class JeecgSourceItemReconstructionCloudApplication extends SpringBootServletInitializer implements CommandLineRunner {
public class JeecgSourceRebuildCloudApplication extends SpringBootServletInitializer implements CommandLineRunner {
private final RedisTemplate<String, Object> redisTemplate;
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(JeecgSourceItemReconstructionCloudApplication.class);
return application.sources(JeecgSourceRebuildCloudApplication.class);
}
public static void main(String[] args) throws UnknownHostException {
ConfigurableApplicationContext application = SpringApplication.run(JeecgSourceItemReconstructionCloudApplication.class, args);
ConfigurableApplicationContext application = SpringApplication.run(JeecgSourceRebuildCloudApplication.class, args);
Environment env = application.getEnvironment();
String ip = InetAddress.getLocalHost().getHostAddress();
String port = env.getProperty("server.port");

View File

@ -0,0 +1,24 @@
server:
port: 8002
spring:
application:
name: jeecg-source-rebuild
cloud:
nacos:
config:
server-addr: @config.server-addr@
group: @config.group@
namespace: @config.namespace@
username: @config.username@
password: @config.password@
discovery:
server-addr: ${spring.cloud.nacos.config.server-addr}
group: @config.group@
namespace: @config.namespace@
username: @config.username@
password: @config.password@
config:
import:
- optional:nacos:jeecg.yaml
- optional:nacos:jeecg-@profile.name@.yaml

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 -->
<property name="LOG_HOME" value="../logs" />
<!--<property name="COLOR_PATTERN" value="%black(%contextName-) %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta( %replace(%caller{1}){'\t|Caller.{1}0|\r\n', ''})- %gray(%msg%xEx%n)" />-->
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期%thread表示线程名%-5level级别从左显示5个字符宽度%msg日志消息%n是换行符
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n</pattern>-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{50}:%L) - %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--日志文件输出的文件名 -->
<FileNamePattern>${LOG_HOME}/jeecg-system-%d{yyyy-MM-dd}.%i.log</FileNamePattern>
<!--日志文件保留天数 -->
<MaxHistory>30</MaxHistory>
<maxFileSize>10MB</maxFileSize>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期%thread表示线程名%-5level级别从左显示5个字符宽度%msg日志消息%n是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n</pattern>
</encoder>
</appender>
<!-- 生成 error html格式日志开始 -->
<appender name="HTML" class="ch.qos.logback.core.FileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!--设置日志级别,过滤掉info日志,只输入error日志-->
<level>ERROR</level>
</filter>
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="ch.qos.logback.classic.html.HTMLLayout">
<pattern>%p%d%msg%M%F{32}%L</pattern>
</layout>
</encoder>
<file>${LOG_HOME}/error-log.html</file>
</appender>
<!-- 生成 error html格式日志结束 -->
<!-- 每天生成一个html格式的日志开始 -->
<appender name="FILE_HTML" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--日志文件输出的文件名 -->
<FileNamePattern>${LOG_HOME}/jeecg-system-%d{yyyy-MM-dd}.%i.html</FileNamePattern>
<!--日志文件保留天数 -->
<MaxHistory>30</MaxHistory>
<MaxFileSize>10MB</MaxFileSize>
</rollingPolicy>
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="ch.qos.logback.classic.html.HTMLLayout">
<pattern>%p%d%msg%M%F{32}%L</pattern>
</layout>
</encoder>
</appender>
<!-- 每天生成一个html格式的日志结束 -->
<!--myibatis log configure -->
<logger name="com.apache.ibatis" level="TRACE" />
<logger name="java.sql.Connection" level="DEBUG" />
<logger name="java.sql.Statement" level="DEBUG" />
<logger name="java.sql.PreparedStatement" level="DEBUG" />
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
<appender-ref ref="HTML" />
<appender-ref ref="FILE_HTML" />
</root>
</configuration>

View File

@ -22,7 +22,7 @@
<module>jeecg-visual</module>
<module>jeecg-weather-start</module>
<module>jeecg-data-analyze-start</module>
<module>jeecg-sourceitem-reconstruction-start</module>
<module>jeecg-source-rebuild-start</module>
</modules>
</project>

View File

@ -86,7 +86,7 @@
<module>jeecg-module-system</module>
<module>jeecg-module-weather</module>
<module>jeecg-module-data-analyze</module>
<module>jeecg-module-sourceitem-reconstruction</module>
<module>jeecg-module-source-rebuild</module>
</modules>
<repositories>