diff --git a/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/DownloadUtils.java b/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/DownloadUtils.java new file mode 100644 index 0000000..ae5b992 --- /dev/null +++ b/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/DownloadUtils.java @@ -0,0 +1,59 @@ +package org.jeecg.common.util; + +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.http.MediaType; +import java.io.*; +import java.net.URLEncoder; + +/** + * 下载文件工具 + * + */ +public class DownloadUtils { + + public static void downloadTxt(HttpServletResponse response,InputStream is,String fileName){ + download(response,is,fileName,MediaType.TEXT_PLAIN_VALUE); + } + + private static void download(HttpServletResponse response,InputStream is,String fileName,String contentType){ + response.reset(); + response.setContentType(contentType); + response.setCharacterEncoding("utf-8"); + try { + response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); + response.setHeader("Access-Control-Expose-Headers","Content-disposition"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + BufferedInputStream bis = null; + BufferedOutputStream bos = null; + try { + bis = new BufferedInputStream(is); + bos = new BufferedOutputStream(response.getOutputStream()); + byte[] buff = new byte[1024]; + int bytesRead; + try { + while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) { + bos.write(buff, 0, bytesRead); + } + } catch (IOException e) { + e.printStackTrace(); + } + } catch (IOException e1) { + e1.printStackTrace(); + }finally{ + try { + if(bis!=null){ + bis.close(); + } + if(bis!=null){ + bos.flush(); + bos.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + +} \ No newline at end of file diff --git a/jeecg-module-source-rebuild/src/main/java/org/jeecg/controller/TaskResultDataController.java b/jeecg-module-source-rebuild/src/main/java/org/jeecg/controller/TaskResultDataController.java index dfea540..8877524 100644 --- a/jeecg-module-source-rebuild/src/main/java/org/jeecg/controller/TaskResultDataController.java +++ b/jeecg-module-source-rebuild/src/main/java/org/jeecg/controller/TaskResultDataController.java @@ -48,10 +48,38 @@ public class TaskResultDataController { return Result.OK(taskResultDataService.getBayesMonovarPosterior(taskId)); } - @AutoLog(value = "导出TXT") - @Operation(summary = "导出TXT") - @GetMapping("exportTxt") - public void exportTxt(HttpServletResponse response) throws IOException { + @AutoLog(value = "获取双变量后验分布") + @Operation(summary = "获取双变量后验分布") + @GetMapping("getBayesBivarPosterior") + public Result getBayesBivarPosterior(@NotNull(message = "任务ID不能为空") Integer taskId){ + return Result.OK(taskResultDataService.getBayesBivarPosterior(taskId)); + } + @AutoLog(value = "导出概率分布图数据") + @Operation(summary = "导出概率分布图数据") + @GetMapping("exportBayesProbLocTxt") + public void exportBayesProbLocTxt(@NotNull(message = "任务ID不能为空") Integer taskId,HttpServletResponse response) throws IOException { + taskResultDataService.exportBayesProbLocTxt(taskId,response); + } + + @AutoLog(value = "导出观测值和模拟值的活度浓度比较结果数据") + @Operation(summary = "导出观测值和模拟值的活度浓度比较结果数据") + @GetMapping("exportBayesAcTimeSeriesTxt") + public void exportBayesAcTimeSeriesTxt(@NotNull(message = "任务ID不能为空") Integer taskId,HttpServletResponse response) throws IOException { + taskResultDataService.exportBayesAcTimeSeriesTxt(taskId,response); + } + + @AutoLog(value = "导出单变量后验分布结果数据") + @Operation(summary = "导出单变量后验分布结果数据") + @GetMapping("exportBayesMonovarPosterior") + public void exportBayesMonovarPosterior(@NotNull(message = "任务ID不能为空") Integer taskId,HttpServletResponse response) throws IOException { + taskResultDataService.exportBayesMonovarPosterior(taskId,response); + } + + @AutoLog(value = "导出双变量后验分布结果数据") + @Operation(summary = "导出双变量后验分布结果数据") + @GetMapping("exportBayesBivarPosterior") + public void exportBayesBivarPosterior(@NotNull(message = "任务ID不能为空") Integer taskId,HttpServletResponse response) throws IOException { + taskResultDataService.exportBayesBivarPosterior(taskId,response); } } diff --git a/jeecg-module-source-rebuild/src/main/java/org/jeecg/service/TaskResultDataService.java b/jeecg-module-source-rebuild/src/main/java/org/jeecg/service/TaskResultDataService.java index 63458a0..04b3ff0 100644 --- a/jeecg-module-source-rebuild/src/main/java/org/jeecg/service/TaskResultDataService.java +++ b/jeecg-module-source-rebuild/src/main/java/org/jeecg/service/TaskResultDataService.java @@ -1,5 +1,7 @@ package org.jeecg.service; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotNull; import org.jeecg.vo.ActivityConcComparResult; import org.jeecg.vo.SourceProbabilityGrid; @@ -28,11 +30,39 @@ public interface TaskResultDataService { * 获取双变量后验分布 * @param taskId */ - void getBayesBivarPosterior(Integer taskId); + Map getBayesBivarPosterior(Integer taskId); /** * 获取单变量后验分布 * @param taskId */ Map getBayesMonovarPosterior(Integer taskId); + + /** + * 导出概率分布图数据 + * @param taskId + * @param response + */ + void exportBayesProbLocTxt(@NotNull(message = "任务ID不能为空") Integer taskId, HttpServletResponse response); + + /** + * 导出观测值和模拟值的活度浓度比较结果数据 + * @param taskId + * @param response + */ + void exportBayesAcTimeSeriesTxt(@NotNull(message = "任务ID不能为空") Integer taskId, HttpServletResponse response); + + /** + * 导出单变量后验分布结果数据 + * @param taskId + * @param response + */ + void exportBayesMonovarPosterior(@NotNull(message = "任务ID不能为空") Integer taskId, HttpServletResponse response); + + /** + * 导出双变量后验分布结果数据 + * @param taskId + * @param response + */ + void exportBayesBivarPosterior(@NotNull(message = "任务ID不能为空") Integer taskId, HttpServletResponse response); } diff --git a/jeecg-module-source-rebuild/src/main/java/org/jeecg/service/impl/TaskResultDataServiceImpl.java b/jeecg-module-source-rebuild/src/main/java/org/jeecg/service/impl/TaskResultDataServiceImpl.java index 723423a..92dd5f8 100644 --- a/jeecg-module-source-rebuild/src/main/java/org/jeecg/service/impl/TaskResultDataServiceImpl.java +++ b/jeecg-module-source-rebuild/src/main/java/org/jeecg/service/impl/TaskResultDataServiceImpl.java @@ -1,9 +1,10 @@ package org.jeecg.service.impl; -import cn.hutool.core.date.DateUtil; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.jeecg.common.properties.SourceRebuildParams; +import org.jeecg.common.util.DownloadUtils; import org.jeecg.modules.base.entity.SourceRebuildTask; import org.jeecg.service.SourceRebuildTaskService; import org.jeecg.service.TaskResultDataService; @@ -15,6 +16,9 @@ import org.rosuda.REngine.Rserve.RConnection; import org.rosuda.REngine.Rserve.RserveException; import org.springframework.stereotype.Service; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.*; @@ -51,6 +55,7 @@ public class TaskResultDataServiceImpl implements TaskResultDataService { } /** + * 获取概率分布数据 * @param taskId * @return */ @@ -140,7 +145,7 @@ public class TaskResultDataServiceImpl implements TaskResultDataService { * @param taskId */ @Override - public void getBayesBivarPosterior(Integer taskId) { + public Map getBayesBivarPosterior(Integer taskId) { SourceRebuildTask task = this.sourceRebuildTaskService.getById(taskId); if(StringUtils.isBlank(task.getResultAddress())){ throw new RuntimeException("此任务运行结果不存在,请检查运行日志"); @@ -149,6 +154,60 @@ public class TaskResultDataServiceImpl implements TaskResultDataService { if(!conn.isConnected()){ throw new RuntimeException("Rserve连接不可用"); } + Map result = new HashMap<>(); + try { + String posteriorRdsPath = task.getResultAddress()+"/bayes_bivarPosterior_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"); + //存储的是lon、lat、log10_Q、tstart、tstop的中位数 + REXP post_median = list.at("post_median"); + //存储的是lon、lat、log10_Q、tstart、tstop的X轴的边界数据 + REXP breaks = list.at("breaks"); + //先验密度(在 breaks 点上) + REXP zprior = list.at("zprior"); + Map lonChartDataMap = this.processLonChart(chaindf, post_median, breaks, zprior); + Map latChartDataMap = this.processLatChart(chaindf, post_median, breaks, zprior); + Map log10ChartDataMap = this.processLog10Chart(chaindf, post_median, breaks, zprior); + Map startChartDataMap = this.processStartChart(chaindf, post_median, breaks, zprior); + Map stopChartDataMap = this.processStopChart(chaindf, post_median, breaks, zprior); + Map lonAndLatChartDataMap = this.processLonAndLatChart(chaindf, post_median, breaks); + Map lonAndLog10ChartDataMap = this.processLonAndLog10Chart(chaindf, post_median, breaks); + Map lonAndStartChartDataMap = this.processLonAndStartChart(chaindf, post_median, breaks); + Map lonAndStopChartDataMap = this.processLonAndStopChart(chaindf, post_median, breaks); + Map latAndLog10ChartDataMap = this.processLatAndLog10Chart(chaindf, post_median, breaks); + Map latAndStartChartDataMap = this.processLatAndStartChart(chaindf, post_median, breaks); + Map latAndStopChartDataMap = this.processLatAndStopChart(chaindf, post_median, breaks); + Map log10AndStartChartDataMap = this.processLog10AndStartChart(chaindf, post_median, breaks); + Map log10AndStopChartDataMap = this.processLog10AndStopChart(chaindf, post_median, breaks); + Map startAndStopChartDataMap = this.processStartAndStopChart(chaindf, post_median, breaks); + result.putAll(lonChartDataMap); + result.putAll(latChartDataMap); + result.putAll(log10ChartDataMap); + result.putAll(startChartDataMap); + result.putAll(stopChartDataMap); + result.putAll(lonAndLatChartDataMap); + result.putAll(lonAndLog10ChartDataMap); + result.putAll(lonAndStartChartDataMap); + result.putAll(lonAndStopChartDataMap); + result.putAll(latAndLog10ChartDataMap); + result.putAll(latAndStartChartDataMap); + result.putAll(latAndStopChartDataMap); + result.putAll(log10AndStartChartDataMap); + result.putAll(log10AndStopChartDataMap); + result.putAll(startAndStopChartDataMap); + } + } catch (RserveException e) { + throw new RuntimeException("RDS读取异常",e); + } catch (REXPMismatchException e) { + throw new RuntimeException("RDS 文件不是一个列表结构",e); + } + return result; } @@ -203,6 +262,163 @@ public class TaskResultDataServiceImpl implements TaskResultDataService { return result; } + /** + * 导出概率分布图数据 + * + * @param taskId + * @param response + */ + @Override + public void exportBayesProbLocTxt(Integer taskId, HttpServletResponse response) { + 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连接不可用"); + } + try { + String rdsPath = task.getResultAddress()+"/probloc.RDS"; + REXP result = conn.eval("readRDS('" + rdsPath + "')"); + if (result.isNumeric()) { + StringBuilder sb = new StringBuilder(); + double[][] doubleMatrix = result.asDoubleMatrix(); + for (int i = 0; i < doubleMatrix.length; i++) { + for (int j = 0; j < doubleMatrix[i].length; j++) { + sb.append(doubleMatrix[i][j]); + if (j < doubleMatrix[i].length - 1) { + sb.append(" "); + } + } + sb.append("\n"); + } + InputStream inputStream = new ByteArrayInputStream(sb.toString().getBytes(StandardCharsets.UTF_8)); + String fileName = task.getTaskName()+"_概率分布数据.txt"; + DownloadUtils.downloadTxt(response,inputStream,fileName); + } + } catch (RserveException e) { + throw new RuntimeException("RDS读取异常",e); + } catch (REXPMismatchException e) { + throw new RuntimeException("RDS 文件不是一个矩阵结构",e); + } + } + + /** + * 导出观测值和模拟值的活度浓度比较结果数据 + * + * @param taskId + * @param response + */ + @Override + public void exportBayesAcTimeSeriesTxt(Integer taskId, HttpServletResponse response) { + 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连接不可用"); + } + try { + StringBuilder sb = new StringBuilder(); + String obsRdsPath = task.getResultAddress()+"/obs.RDS"; + REXP obsResult = conn.eval("readRDS('" + obsRdsPath + "')"); + if (obsResult.isNumeric()) { + sb.append("#obs\n"); + double[] obsData = obsResult.asDoubles(); + for (int i = 0; i < obsData.length; i++) { + sb.append(obsData[i]); + if (i < obsData.length - 1) { + sb.append(" "); + } + if(i>0 && (i+1)%10==0){ + sb.append("\n"); + } + } + sb.append("\n\n"); + } + String modRdsPath = task.getResultAddress()+"/mod.RDS"; + REXP modResult = conn.eval("readRDS('" + modRdsPath + "')"); + if (modResult.isNumeric()) { + sb.append("#mod\n"); + double[] modData = modResult.asDoubles(); + for (int i = 0; i < modData.length; i++) { + sb.append(modData[i]); + if (i < modData.length - 1) { + sb.append(" "); + } + if(i>0 && (i+1)%10==0){ + sb.append("\n"); + } + } + sb.append("\n\n"); + } + String mdcRdsPath = task.getResultAddress()+"/MDC.RDS"; + REXP mdcResult = conn.eval("readRDS('" + mdcRdsPath + "')"); + if (mdcResult.isNumeric()) { + sb.append("#mdc\n"); + double[] mdcData = mdcResult.asDoubles(); + for (int i = 0; i < mdcData.length; i++) { + sb.append(mdcData[i]); + if (i < mdcData.length - 1) { + sb.append(" "); + } + if(i>0 && (i+1)%10==0){ + sb.append("\n"); + } + } + sb.append("\n\n"); + } + String stationsTxtPath = task.getResultAddress()+"/statnames.txt"; + REXP stationsResult = conn.eval("readLines('" + stationsTxtPath + "')"); + if (stationsResult.isString()) { + sb.append("#stations\n"); + String[] stationsData = stationsResult.asStrings(); + for (int i = 0; i < stationsData.length; i++) { + sb.append(stationsData[i]); + if (i < stationsData.length - 1) { + sb.append(" "); + } + if(i>0 && (i+1)%10==0){ + sb.append("\n"); + } + } + sb.append("\n"); + } + InputStream inputStream = new ByteArrayInputStream(sb.toString().getBytes(StandardCharsets.UTF_8)); + String fileName = task.getTaskName()+"_观测值与模拟值对比数据.txt"; + DownloadUtils.downloadTxt(response,inputStream,fileName); + } catch (RserveException e) { + throw new RuntimeException("RDS读取异常",e); + } catch (REXPMismatchException e) { + throw new RuntimeException("RDS 文件不是一个数组结构",e); + } + } + + /** + * 导出单变量后验分布结果数据 + * + * @param taskId + * @param response + */ + @Override + public void exportBayesMonovarPosterior(Integer taskId, HttpServletResponse response) { + this.getBayesAuxData(taskId,response,"bayes_monovarPosterior_aux.RDS"); + } + + /** + * 导出双变量后验分布结果数据 + * + * @param taskId + * @param response + */ + @Override + public void exportBayesBivarPosterior(Integer taskId, HttpServletResponse response) { + this.getBayesAuxData(taskId,response,"bayes_bivarPosterior_aux.RDS"); + } + + /** * 处理lon图表数据 * @param chaindf @@ -498,6 +714,622 @@ public class TaskResultDataServiceImpl implements TaskResultDataService { return map; } + /** + * 处理lon&lat图表数据 + * @param chaindf + * @param postMedian + * @param breaks + * @return + * @throws REXPMismatchException + */ + private Map processLonAndLatChart(REXP chaindf,REXP postMedian,REXP breaks) throws REXPMismatchException { + Map map = new HashMap<>(); + //封装对象 + ScatterPlotChartStru scatterPlotChartStru = new ScatterPlotChartStru(); + //设置中位数点(蓝色点) + REXP lon = postMedian.asList().at("lon"); + REXP lat = postMedian.asList().at("lat"); + PriorDistribution postMedianPoint = new PriorDistribution(); + postMedianPoint.setXValue(lon.asDouble()); + postMedianPoint.setYValue(lat.asDouble()); + scatterPlotChartStru.setPriorDistribution(postMedianPoint); + //设置X轴边界 + REXP break1 = breaks.asList().at(0); + if(break1.isNumeric()){ + double[] break1Data = break1.asDoubles(); + scatterPlotChartStru.setXMin(break1Data[0]); + scatterPlotChartStru.setXMax(break1Data[break1Data.length-1]); + } + //设置散点坐标 + REXP lons = chaindf.asList().at(0); + REXP lats = chaindf.asList().at(1); + if(lons.isNumeric() && lats.isNumeric()){ + double[] lonData = lons.asDoubles(); + double[] latData = lats.asDoubles(); + List priorDistributionList = new ArrayList<>(); + //lonData和latData长度肯定一致,循环一个获取同样下表即可 + for (int i= 0; i < lonData.length; i++) { + PriorDistribution scatterPoint = new PriorDistribution(); + scatterPoint.setXValue(lonData[i]); + scatterPoint.setYValue(latData[i]); + priorDistributionList.add(scatterPoint); + } + scatterPlotChartStru.setPriorDistributionList(priorDistributionList); + } + map.put("lonAndLatChartStru",scatterPlotChartStru); + return map; + } + + /** + * 处理lon&log10图表数据 + * @param chaindf + * @param postMedian + * @param breaks + * @return + * @throws REXPMismatchException + */ + private Map processLonAndLog10Chart(REXP chaindf,REXP postMedian,REXP breaks) throws REXPMismatchException { + Map map = new HashMap<>(); + //封装对象 + ScatterPlotChartStru scatterPlotChartStru = new ScatterPlotChartStru(); + //设置中位数点(蓝色点) + REXP lon = postMedian.asList().at("lon"); + REXP log10 = postMedian.asList().at("log10_Q"); + PriorDistribution postMedianPoint = new PriorDistribution(); + postMedianPoint.setXValue(lon.asDouble()); + postMedianPoint.setYValue(log10.asDouble()); + scatterPlotChartStru.setPriorDistribution(postMedianPoint); + //设置X轴边界 + REXP break1 = breaks.asList().at(0); + if(break1.isNumeric()){ + double[] break1Data = break1.asDoubles(); + scatterPlotChartStru.setXMin(break1Data[0]); + scatterPlotChartStru.setXMax(break1Data[break1Data.length-1]); + } + //设置散点坐标 + REXP lons = chaindf.asList().at(0); + REXP log10s = chaindf.asList().at(2); + if(lons.isNumeric() && log10s.isNumeric()){ + double[] lonData = lons.asDoubles(); + double[] log10Data = log10s.asDoubles(); + List priorDistributionList = new ArrayList<>(); + //lonData和log10Data长度肯定一致,循环一个获取同样下表即可 + for (int i= 0; i < lonData.length; i++) { + PriorDistribution scatterPoint = new PriorDistribution(); + scatterPoint.setXValue(lonData[i]); + scatterPoint.setYValue(log10Data[i]); + priorDistributionList.add(scatterPoint); + } + scatterPlotChartStru.setPriorDistributionList(priorDistributionList); + } + map.put("lonAndLog10ChartStru",scatterPlotChartStru); + return map; + } + + /** + * 处理lon&tstart图表数据 + * @param chaindf + * @param postMedian + * @param breaks + * @return + * @throws REXPMismatchException + */ + private Map processLonAndStartChart(REXP chaindf,REXP postMedian,REXP breaks) throws REXPMismatchException { + Map map = new HashMap<>(); + //封装对象 + ScatterPlotChartStru scatterPlotChartStru = new ScatterPlotChartStru(); + //设置中位数点(蓝色点) + REXP lon = postMedian.asList().at("lon"); + REXP rstart = postMedian.asList().at("rstart"); + PriorDistribution postMedianPoint = new PriorDistribution(); + postMedianPoint.setXValue(lon.asDouble()); + postMedianPoint.setYValue(this.posixctToCSTString(rstart.asDouble())); + scatterPlotChartStru.setPriorDistribution(postMedianPoint); + //设置X轴边界 + REXP break1 = breaks.asList().at(0); + if(break1.isNumeric()){ + double[] break1Data = break1.asDoubles(); + scatterPlotChartStru.setXMin(break1Data[0]); + scatterPlotChartStru.setXMax(break1Data[break1Data.length-1]); + } + //设置散点坐标 + REXP lons = chaindf.asList().at(0); + REXP rstarts = chaindf.asList().at(3); + if(lons.isNumeric() && rstarts.isNumeric()){ + double[] lonData = lons.asDoubles(); + double[] rstartData = rstarts.asDoubles(); + List priorDistributionList = new ArrayList<>(); + //lonData和rstartData长度肯定一致,循环一个获取同样下表即可 + for (int i= 0; i < lonData.length; i++) { + PriorDistribution scatterPoint = new PriorDistribution(); + scatterPoint.setXValue(lonData[i]); + scatterPoint.setYValue(this.posixctToCSTString(rstartData[i])); + priorDistributionList.add(scatterPoint); + } + scatterPlotChartStru.setPriorDistributionList(priorDistributionList); + } + map.put("lonAndStartChartStru",scatterPlotChartStru); + return map; + } + + /** + * 处理lon&tstop图表数据 + * @param chaindf + * @param postMedian + * @param breaks + * @return + * @throws REXPMismatchException + */ + private Map processLonAndStopChart(REXP chaindf,REXP postMedian,REXP breaks) throws REXPMismatchException { + Map map = new HashMap<>(); + //封装对象 + ScatterPlotChartStru scatterPlotChartStru = new ScatterPlotChartStru(); + //设置中位数点(蓝色点) + REXP lon = postMedian.asList().at("lon"); + REXP rstop = postMedian.asList().at("rstop"); + PriorDistribution postMedianPoint = new PriorDistribution(); + postMedianPoint.setXValue(lon.asDouble()); + postMedianPoint.setYValue(this.posixctToCSTString(rstop.asDouble())); + scatterPlotChartStru.setPriorDistribution(postMedianPoint); + //设置X轴边界 + REXP break1 = breaks.asList().at(0); + if(break1.isNumeric()){ + double[] break1Data = break1.asDoubles(); + scatterPlotChartStru.setXMin(break1Data[0]); + scatterPlotChartStru.setXMax(break1Data[break1Data.length-1]); + } + //设置散点坐标 + REXP lons = chaindf.asList().at(0); + REXP rstops = chaindf.asList().at(4); + if(lons.isNumeric() && rstops.isNumeric()){ + double[] lonData = lons.asDoubles(); + double[] rstopData = rstops.asDoubles(); + List priorDistributionList = new ArrayList<>(); + //lonData和rstopData长度肯定一致,循环一个获取同样下表即可 + for (int i= 0; i < lonData.length; i++) { + PriorDistribution scatterPoint = new PriorDistribution(); + scatterPoint.setXValue(lonData[i]); + scatterPoint.setYValue(this.posixctToCSTString(rstopData[i])); + priorDistributionList.add(scatterPoint); + } + scatterPlotChartStru.setPriorDistributionList(priorDistributionList); + } + map.put("lonAndStopChartStru",scatterPlotChartStru); + return map; + } + + /** + * 处理lat&log10图表数据 + * @param chaindf + * @param postMedian + * @param breaks + * @return + * @throws REXPMismatchException + */ + private Map processLatAndLog10Chart(REXP chaindf,REXP postMedian,REXP breaks) throws REXPMismatchException { + Map map = new HashMap<>(); + //封装对象 + ScatterPlotChartStru scatterPlotChartStru = new ScatterPlotChartStru(); + //设置中位数点(蓝色点) + REXP lat = postMedian.asList().at("lat"); + REXP log10 = postMedian.asList().at("log10_Q"); + PriorDistribution postMedianPoint = new PriorDistribution(); + postMedianPoint.setXValue(lat.asDouble()); + postMedianPoint.setYValue(log10.asDouble()); + scatterPlotChartStru.setPriorDistribution(postMedianPoint); + //设置X轴边界 + REXP break2 = breaks.asList().at(1); + if(break2.isNumeric()){ + double[] break2Data = break2.asDoubles(); + scatterPlotChartStru.setXMin(break2Data[0]); + scatterPlotChartStru.setXMax(break2Data[break2Data.length-1]); + } + //设置散点坐标 + REXP lats = chaindf.asList().at(1); + REXP log10s = chaindf.asList().at(2); + if(lats.isNumeric() && log10s.isNumeric()){ + double[] latData = lats.asDoubles(); + double[] log10Data = log10s.asDoubles(); + List priorDistributionList = new ArrayList<>(); + //latData和log10Data长度肯定一致,循环一个获取同样下表即可 + for (int i= 0; i < latData.length; i++) { + PriorDistribution scatterPoint = new PriorDistribution(); + scatterPoint.setXValue(latData[i]); + scatterPoint.setYValue(log10Data[i]); + priorDistributionList.add(scatterPoint); + } + scatterPlotChartStru.setPriorDistributionList(priorDistributionList); + } + map.put("latAndLog10ChartStru",scatterPlotChartStru); + return map; + } + + /** + * 处理lat&tstart图表数据 + * @param chaindf + * @param postMedian + * @param breaks + * @return + * @throws REXPMismatchException + */ + private Map processLatAndStartChart(REXP chaindf,REXP postMedian,REXP breaks) throws REXPMismatchException { + Map map = new HashMap<>(); + //封装对象 + ScatterPlotChartStru scatterPlotChartStru = new ScatterPlotChartStru(); + //设置中位数点(蓝色点) + REXP lat = postMedian.asList().at("lat"); + REXP rstart = postMedian.asList().at("rstart"); + PriorDistribution postMedianPoint = new PriorDistribution(); + postMedianPoint.setXValue(lat.asDouble()); + postMedianPoint.setYValue(this.posixctToCSTString(rstart.asDouble())); + scatterPlotChartStru.setPriorDistribution(postMedianPoint); + //设置X轴边界 + REXP break2 = breaks.asList().at(1); + if(break2.isNumeric()){ + double[] break2Data = break2.asDoubles(); + scatterPlotChartStru.setXMin(break2Data[0]); + scatterPlotChartStru.setXMax(break2Data[break2Data.length-1]); + } + //设置散点坐标 + REXP lats = chaindf.asList().at(1); + REXP rstarts = chaindf.asList().at(3); + if(lats.isNumeric() && rstarts.isNumeric()){ + double[] latData = lats.asDoubles(); + double[] rstartData = rstarts.asDoubles(); + List priorDistributionList = new ArrayList<>(); + //latData和rstartData长度肯定一致,循环一个获取同样下表即可 + for (int i= 0; i < latData.length; i++) { + PriorDistribution scatterPoint = new PriorDistribution(); + scatterPoint.setXValue(latData[i]); + scatterPoint.setYValue(this.posixctToCSTString(rstartData[i])); + priorDistributionList.add(scatterPoint); + } + scatterPlotChartStru.setPriorDistributionList(priorDistributionList); + } + map.put("latAndStartChartStru",scatterPlotChartStru); + return map; + } + + /** + * 处理lat&tstop图表数据 + * @param chaindf + * @param postMedian + * @param breaks + * @return + * @throws REXPMismatchException + */ + private Map processLatAndStopChart(REXP chaindf,REXP postMedian,REXP breaks) throws REXPMismatchException { + Map map = new HashMap<>(); + //封装对象 + ScatterPlotChartStru scatterPlotChartStru = new ScatterPlotChartStru(); + //设置中位数点(蓝色点) + REXP lat = postMedian.asList().at("lat"); + REXP rstop = postMedian.asList().at("rstop"); + PriorDistribution postMedianPoint = new PriorDistribution(); + postMedianPoint.setXValue(lat.asDouble()); + postMedianPoint.setYValue(this.posixctToCSTString(rstop.asDouble())); + scatterPlotChartStru.setPriorDistribution(postMedianPoint); + //设置X轴边界 + REXP break2 = breaks.asList().at(1); + if(break2.isNumeric()){ + double[] break2Data = break2.asDoubles(); + scatterPlotChartStru.setXMin(break2Data[0]); + scatterPlotChartStru.setXMax(break2Data[break2Data.length-1]); + } + //设置散点坐标 + REXP lats = chaindf.asList().at(1); + REXP rstops = chaindf.asList().at(4); + if(lats.isNumeric() && rstops.isNumeric()){ + double[] latData = lats.asDoubles(); + double[] rstopData = rstops.asDoubles(); + List priorDistributionList = new ArrayList<>(); + //latData和rstopData长度肯定一致,循环一个获取同样下表即可 + for (int i= 0; i < latData.length; i++) { + PriorDistribution scatterPoint = new PriorDistribution(); + scatterPoint.setXValue(latData[i]); + scatterPoint.setYValue(this.posixctToCSTString(rstopData[i])); + priorDistributionList.add(scatterPoint); + } + scatterPlotChartStru.setPriorDistributionList(priorDistributionList); + } + map.put("latAndStopChartStru",scatterPlotChartStru); + return map; + } + + /** + * 处理log10&tstart图表数据 + * @param chaindf + * @param postMedian + * @param breaks + * @return + * @throws REXPMismatchException + */ + private Map processLog10AndStartChart(REXP chaindf,REXP postMedian,REXP breaks) throws REXPMismatchException { + Map map = new HashMap<>(); + //封装对象 + ScatterPlotChartStru scatterPlotChartStru = new ScatterPlotChartStru(); + //设置中位数点(蓝色点) + REXP log10 = postMedian.asList().at("log10_Q"); + REXP rstart = postMedian.asList().at("rstart"); + PriorDistribution postMedianPoint = new PriorDistribution(); + postMedianPoint.setXValue(log10.asDouble()); + postMedianPoint.setYValue(this.posixctToCSTString(rstart.asDouble())); + scatterPlotChartStru.setPriorDistribution(postMedianPoint); + //设置X轴边界 + REXP break3 = breaks.asList().at(2); + if(break3.isNumeric()){ + double[] break3Data = break3.asDoubles(); + scatterPlotChartStru.setXMin(break3Data[0]); + scatterPlotChartStru.setXMax(break3Data[break3Data.length-1]); + } + //设置散点坐标 + REXP log10s = chaindf.asList().at(2); + REXP rstarts = chaindf.asList().at(3); + if(log10s.isNumeric() && rstarts.isNumeric()){ + double[] log10Data = log10s.asDoubles(); + double[] rstartData = rstarts.asDoubles(); + List priorDistributionList = new ArrayList<>(); + //log10Data和rstartData长度肯定一致,循环一个获取同样下表即可 + for (int i= 0; i < log10Data.length; i++) { + PriorDistribution scatterPoint = new PriorDistribution(); + scatterPoint.setXValue(log10Data[i]); + scatterPoint.setYValue(this.posixctToCSTString(rstartData[i])); + priorDistributionList.add(scatterPoint); + } + scatterPlotChartStru.setPriorDistributionList(priorDistributionList); + } + map.put("log10AndStartChartStru",scatterPlotChartStru); + return map; + } + + /** + * 处理log10&tstop图表数据 + * @param chaindf + * @param postMedian + * @param breaks + * @return + * @throws REXPMismatchException + */ + private Map processLog10AndStopChart(REXP chaindf,REXP postMedian,REXP breaks) throws REXPMismatchException { + Map map = new HashMap<>(); + //封装对象 + ScatterPlotChartStru scatterPlotChartStru = new ScatterPlotChartStru(); + //设置中位数点(蓝色点) + REXP log10 = postMedian.asList().at("log10_Q"); + REXP rstop = postMedian.asList().at("rstop"); + PriorDistribution postMedianPoint = new PriorDistribution(); + postMedianPoint.setXValue(log10.asDouble()); + postMedianPoint.setYValue(this.posixctToCSTString(rstop.asDouble())); + scatterPlotChartStru.setPriorDistribution(postMedianPoint); + //设置X轴边界 + REXP break3 = breaks.asList().at(2); + if(break3.isNumeric()){ + double[] break3Data = break3.asDoubles(); + scatterPlotChartStru.setXMin(break3Data[0]); + scatterPlotChartStru.setXMax(break3Data[break3Data.length-1]); + } + //设置散点坐标 + REXP log10s = chaindf.asList().at(2); + REXP rstops = chaindf.asList().at(4); + if(log10s.isNumeric() && rstops.isNumeric()){ + double[] log10Data = log10s.asDoubles(); + double[] rstopData = rstops.asDoubles(); + List priorDistributionList = new ArrayList<>(); + //log10Data和rstopData长度肯定一致,循环一个获取同样下表即可 + for (int i= 0; i < log10Data.length; i++) { + PriorDistribution scatterPoint = new PriorDistribution(); + scatterPoint.setXValue(log10Data[i]); + scatterPoint.setYValue(this.posixctToCSTString(rstopData[i])); + priorDistributionList.add(scatterPoint); + } + scatterPlotChartStru.setPriorDistributionList(priorDistributionList); + } + map.put("log10AndStopChartStru",scatterPlotChartStru); + return map; + } + + /** + * 处理tstart&tstop图表数据 + * @param chaindf + * @param postMedian + * @param breaks + * @return + * @throws REXPMismatchException + */ + private Map processStartAndStopChart(REXP chaindf,REXP postMedian,REXP breaks) throws REXPMismatchException { + Map map = new HashMap<>(); + //封装对象 + ScatterPlotChartStru scatterPlotChartStru = new ScatterPlotChartStru(); + //设置中位数点(蓝色点) + REXP rstart = postMedian.asList().at("rstart"); + REXP rstop = postMedian.asList().at("rstop"); + PriorDistribution postMedianPoint = new PriorDistribution(); + postMedianPoint.setXValue(this.posixctToCSTString(rstart.asDouble())); + postMedianPoint.setYValue(this.posixctToCSTString(rstop.asDouble())); + scatterPlotChartStru.setPriorDistribution(postMedianPoint); + //设置X轴边界 + REXP break4 = breaks.asList().at(3); + if(break4.isNumeric()){ + double[] break4Data = break4.asDoubles(); + scatterPlotChartStru.setXMin(break4Data[0]); + scatterPlotChartStru.setXMax(break4Data[break4Data.length-1]); + } + //设置散点坐标 + REXP rstarts = chaindf.asList().at(3); + REXP rstops = chaindf.asList().at(4); + if(rstarts.isNumeric() && rstops.isNumeric()){ + double[] rstartData = rstarts.asDoubles(); + double[] rstopData = rstops.asDoubles(); + List priorDistributionList = new ArrayList<>(); + //log10Data和rstopData长度肯定一致,循环一个获取同样下表即可 + for (int i= 0; i < rstartData.length; i++) { + PriorDistribution scatterPoint = new PriorDistribution(); + scatterPoint.setXValue(this.posixctToCSTString(rstartData[i])); + scatterPoint.setYValue(this.posixctToCSTString(rstopData[i])); + priorDistributionList.add(scatterPoint); + } + scatterPlotChartStru.setPriorDistributionList(priorDistributionList); + } + map.put("startAndStopChartStru",scatterPlotChartStru); + return map; + } + + /** + * 导出单变量和双变量后验分布数据 + * @param taskId + * @param response + * @param rdsFileName + */ + private void getBayesAuxData(Integer taskId, HttpServletResponse response,String rdsFileName) { + 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连接不可用"); + } + try { + String posteriorRdsPath = task.getResultAddress()+"/"+rdsFileName; + REXP posteriorResult = conn.eval("readRDS('" + posteriorRdsPath + "')"); + if (posteriorResult.isList()) { + StringBuilder sb = new StringBuilder(); + //list是一个列表,拥有chaindf, post_median, breaks, zprior多个嵌套对象 + RList list = posteriorResult.asList(); + //chaindf,它是一个R的DataFrame,存储的是抽样数据 + REXP chaindf = list.at("chaindf"); + sb.append("#chaindf\n"); + String title = String.format("%-9s %-9s %-9s %-20s %-20s","lon","lat","log10_Q","tstart","tstop"); + sb.append(title); + sb.append("\n"); + double[] lonData = chaindf.asList().at(0).asDoubles(); + double[] latData = chaindf.asList().at(1).asDoubles(); + double[] log10Data = chaindf.asList().at(2).asDoubles(); + double[] tstartData = chaindf.asList().at(3).asDoubles(); + double[] tstopData = chaindf.asList().at(4).asDoubles(); + for (int i = 0; i < lonData.length; i++) { + String line = String.format("%-9.5f %-9.5f %-9.5f %-20s %-20s",lonData[i],latData[i],log10Data[i],this.posixctToCSTString(tstartData[i]),this.posixctToCSTString(tstopData[i])); + sb.append(line); + sb.append("\n"); + } + sb.append("\n"); + + //trueValues存储的是已知的释放源信息 +// REXP trueValues = list.at("trueValues"); + //存储的是lon、lat、log10_Q、tstart、tstop的中位数 + REXP postMedian = list.at("post_median"); + sb.append("#post_median\n"); + double lon = postMedian.asList().at("lon").asDouble(); + double lat = postMedian.asList().at("lat").asDouble(); + double log10_Q = postMedian.asList().at("log10_Q").asDouble(); + double rstart = postMedian.asList().at("rstart").asDouble(); + double rstop = postMedian.asList().at("rstop").asDouble(); + String postMedianTitle = String.format("%-9s %-9s %-9s %-20s %-20s","lon","lat","log10_Q","tstart","tstop"); + sb.append(postMedianTitle); + sb.append("\n"); + String line = String.format("%-9.5f %-9.5f %-9.5f %-20s %-20s",lon,lat,log10_Q,this.posixctToCSTString(rstart),this.posixctToCSTString(rstop)); + sb.append(line); + sb.append("\n\n"); + + //存储的是lon、lat、log10_Q、tstart、tstop的X轴的边界数据 + REXP breaks = list.at("breaks"); + sb.append("#breaks\n"); + double[] breakLonData = breaks.asList().at(0).asDoubles(); + sb.append("#breaks:lon\n"); + for (int i = 0; i < breakLonData.length; i++) { + String breakLonDataStr = String.format("%-9.5f",breakLonData[i]); + sb.append(breakLonDataStr); + if (i < breakLonData.length - 1) { + sb.append(" "); + } + if(i>0 && (i+1)%15==0){ + sb.append("\n"); + } + } + sb.append("\n"); + + double[] breakLatData = breaks.asList().at(1).asDoubles(); + sb.append("#breaks:lat\n"); + for (int i = 0; i < breakLatData.length; i++) { + String breakLatDataStr = String.format("%-9.5f",breakLatData[i]); + sb.append(breakLatDataStr); + if (i < breakLatData.length - 1) { + sb.append(" "); + } + if(i>0 && (i+1)%15==0){ + sb.append("\n"); + } + } + sb.append("\n"); + + double[] breakLog10Data = breaks.asList().at(2).asDoubles(); + sb.append("#breaks:log10_Q\n"); + for (int i = 0; i < breakLog10Data.length; i++) { + String breakLog10DataStr = String.format("%-9.5f",breakLog10Data[i]); + sb.append(breakLog10DataStr); + if (i < breakLog10Data.length - 1) { + sb.append(" "); + } + if(i>0 && (i+1)%15==0){ + sb.append("\n"); + } + } + sb.append("\n"); + + double[] breakRstartData = breaks.asList().at(3).asDoubles(); + sb.append("#breaks:rstart\n"); + for (int i = 0; i < breakRstartData.length; i++) { + String breakRstartDataStr = String.format("%-20s",this.posixctToCSTString(breakRstartData[i])); + sb.append(breakRstartDataStr); + if (i < breakRstartData.length - 1) { + sb.append(" "); + } + if(i>0 && (i+1)%6==0){ + sb.append("\n"); + } + } + sb.append("\n"); + + double[] breakRstopData = breaks.asList().at(4).asDoubles(); + sb.append("#breaks:rstop\n"); + for (int i = 0; i < breakRstopData.length; i++) { + String breakRstopDataStr = String.format("%-20s",this.posixctToCSTString(breakRstopData[i])); + sb.append(breakRstopDataStr); + if (i < breakRstopData.length - 1) { + sb.append(" "); + } + if(i>0 && (i+1)%6==0){ + sb.append("\n"); + } + } + sb.append("\n\n"); + + //先验密度(在 breaks 点上) + REXP zprior = list.at("zprior"); + sb.append("#zprior\n"); + double[][] zpriorMatrix = zprior.asDoubleMatrix(); + for (int i = 0; i < zpriorMatrix.length; i++) { + double zpriorLonVal = zpriorMatrix[i][0]; + double zpriorLatVal = zpriorMatrix[i][1]; + double zpriorLog10Val = zpriorMatrix[i][2]; + double zpriorStartVal = zpriorMatrix[i][3]; + double zpriorStopVal = zpriorMatrix[i][4]; + String zpriorLine = String.format("%-12.1f %-12.1f %-12.1f %-12.6e %-12.6e",zpriorLonVal,zpriorLatVal,zpriorLog10Val,zpriorStartVal,zpriorStopVal); + sb.append(zpriorLine); + sb.append("\n"); + } + + InputStream inputStream = new ByteArrayInputStream(sb.toString().getBytes(StandardCharsets.UTF_8)); + String fileName = task.getTaskName()+"_单变量后验分布结果数据.txt"; + DownloadUtils.downloadTxt(response,inputStream,fileName); + } + } catch (RserveException e) { + throw new RuntimeException("RDS读取异常",e); + } catch (REXPMismatchException e) { + throw new RuntimeException("RDS 文件不是一个列表结构",e); + } + } + /** * 转换R语言项目的时间 * @param posixctSeconds diff --git a/jeecg-module-source-rebuild/src/main/java/org/jeecg/vo/PriorDistribution.java b/jeecg-module-source-rebuild/src/main/java/org/jeecg/vo/PriorDistribution.java index 1ed9143..513e547 100644 --- a/jeecg-module-source-rebuild/src/main/java/org/jeecg/vo/PriorDistribution.java +++ b/jeecg-module-source-rebuild/src/main/java/org/jeecg/vo/PriorDistribution.java @@ -5,7 +5,7 @@ import lombok.Data; import java.io.Serializable; /** - * 直方图先验分布数据 + * 先验分布数据 */ @Data public class PriorDistribution implements Serializable { diff --git a/jeecg-module-source-rebuild/src/main/java/org/jeecg/vo/ScatterPlotChartStru.java b/jeecg-module-source-rebuild/src/main/java/org/jeecg/vo/ScatterPlotChartStru.java new file mode 100644 index 0000000..42ade82 --- /dev/null +++ b/jeecg-module-source-rebuild/src/main/java/org/jeecg/vo/ScatterPlotChartStru.java @@ -0,0 +1,33 @@ +package org.jeecg.vo; + +import lombok.Data; +import java.io.Serializable; +import java.util.List; + +/** + * 双变量分布图散点图数据 + */ +@Data +public class ScatterPlotChartStru implements Serializable { + + /** + * X轴最小值 + */ + private Object xMin; + + /** + * X轴最大值 + */ + private Object xMax; + + /** + * 散点图 + */ + private List priorDistributionList; + + /** + * 中位数点位 + */ + private PriorDistribution priorDistribution; + +}