From 4c4d0f591f94428ed7e5d2f4ae5df5c5087d8c26 Mon Sep 17 00:00:00 2001
From: dcb <xgybdcb@163.com>
Date: 星期三, 18 六月 2025 09:51:35 +0800
Subject: [PATCH] 求解器版本升级到2.2

---
 src/main/java/com/se/nsl/controller/SimuController.java         |   21 +
 src/main/java/com/se/nsl/domain/dto/DeviceInfo.java             |   58 ++++
 src/main/java/com/se/nsl/domain/vo/ResultVo.java                |   35 ++
 src/main/java/com/se/nsl/service/ResolveService.java            |   48 ++-
 src/main/java/com/se/nsl/utils/TimeFormatUtil.java              |   11 
 src/main/java/com/se/nsl/domain/vo/RealTimeSimuParam.java       |   34 ++
 src/main/java/com/se/nsl/service/RealTimeSimulationService.java |  210 +++++++++++++++++
 src/main/resources/a_test_device_info.json                      |   66 +++++
 src/main/resources/application-dev.yml                          |   12 
 src/main/java/com/se/nsl/domain/dto/Zarr2Tif.java               |   59 +++-
 src/main/java/com/se/nsl/utils/HttpRequestUtil.java             |  133 +++++++++++
 src/main/java/com/se/nsl/domain/vo/ConfigVo.java                |   10 
 12 files changed, 639 insertions(+), 58 deletions(-)

diff --git a/src/main/java/com/se/nsl/controller/SimuController.java b/src/main/java/com/se/nsl/controller/SimuController.java
index 8477d8b..e7b52b0 100644
--- a/src/main/java/com/se/nsl/controller/SimuController.java
+++ b/src/main/java/com/se/nsl/controller/SimuController.java
@@ -5,10 +5,8 @@
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.se.nsl.domain.po.Simu;
 import com.se.nsl.domain.po.SimuData;
-import com.se.nsl.domain.vo.R;
-import com.se.nsl.domain.vo.RealTimeInput;
-import com.se.nsl.domain.vo.SimuResult;
-import com.se.nsl.domain.vo.SimuVo;
+import com.se.nsl.domain.vo.*;
+import com.se.nsl.service.RealTimeSimulationService;
 import com.se.nsl.service.ResolveService;
 import com.se.nsl.service.SimuService;
 import io.swagger.annotations.Api;
@@ -39,6 +37,9 @@
 
     @Resource
     ResolveService resolveService;
+
+    @Resource
+    RealTimeSimulationService rts;
 
     /**
      * 鍒嗛〉鏌ヨ鎺ㄦ紨妯℃嫙
@@ -223,4 +224,16 @@
             return fail("瀹炴椂妯℃嫙寮傚父");
         }
     }
+
+    @ApiOperation(value = "realTime")
+    @PostMapping("/realTime2")
+    public R<Object> realTimeSimulate(@RequestBody RealTimeSimuParam param) {
+        try {
+            String layerJsonName = rts.realTimeSimulate(param);
+            return success(layerJsonName);
+        } catch (IOException e) {
+            log.error("real-time simulate exception:", e);
+            return fail("瀹炴椂妯℃嫙寮傚父");
+        }
+    }
 }
diff --git a/src/main/java/com/se/nsl/domain/dto/DeviceInfo.java b/src/main/java/com/se/nsl/domain/dto/DeviceInfo.java
new file mode 100644
index 0000000..5989ea7
--- /dev/null
+++ b/src/main/java/com/se/nsl/domain/dto/DeviceInfo.java
@@ -0,0 +1,58 @@
+package com.se.nsl.domain.dto;
+
+public class DeviceInfo {
+    private String id;
+    private String name;
+    private double x; //缁忓害
+    private double y; //缁村害
+    private double r;
+    private int mappingId;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public double getX() {
+        return x;
+    }
+
+    public void setX(double x) {
+        this.x = x;
+    }
+
+    public double getY() {
+        return y;
+    }
+
+    public void setY(double y) {
+        this.y = y;
+    }
+
+    public double getR() {
+        return r;
+    }
+
+    public void setR(double r) {
+        this.r = r;
+    }
+
+    public int getMappingId() {
+        return mappingId;
+    }
+
+    public void setMappingId(int mappingId) {
+        this.mappingId = mappingId;
+    }
+}
diff --git a/src/main/java/com/se/nsl/domain/dto/Zarr2Tif.java b/src/main/java/com/se/nsl/domain/dto/Zarr2Tif.java
index ac573b0..4233587 100644
--- a/src/main/java/com/se/nsl/domain/dto/Zarr2Tif.java
+++ b/src/main/java/com/se/nsl/domain/dto/Zarr2Tif.java
@@ -17,9 +17,11 @@
 
     private String terrain_file;
 
-    private String start_timestamp;
+//    private String start_timestamp;
 
-    private List<Integer> frame_range;
+//    private List<Integer> frame_range;
+
+    private List<Object> range;
 
     private boolean fliplr;
 
@@ -27,23 +29,32 @@
 
     public Zarr2Tif() {
         variables = new ArrayList<>(Arrays.asList("depth", "xmomentum", "ymomentum"));
-        frame_range = null;
+//        frame_range = null;
         fliplr = false;
         flipud = false;
     }
 
-    public Zarr2Tif(String zarrFile, String geotiffDir, String terrainFile, String startTimestamp) {
+//    public Zarr2Tif(String zarrFile, String geotiffDir, String terrainFile, String startTimestamp) {
+//        this();
+//
+//        this.zarr_file = zarrFile.replace("\\", "/");
+//        this.geotiff_dir = geotiffDir.replace("\\", "/");
+//        this.terrain_file = terrainFile.replace("\\", "/");
+//        this.start_timestamp = startTimestamp;
+//    }
+
+    public Zarr2Tif(String zarrFile, String geotiffDir, String terrainFile, List<Object> range) {
         this();
 
         this.zarr_file = zarrFile.replace("\\", "/");
         this.geotiff_dir = geotiffDir.replace("\\", "/");
         this.terrain_file = terrainFile.replace("\\", "/");
-        this.start_timestamp = startTimestamp;
+        this.range = range;
     }
 
-    public Zarr2Tif(String zarrFile, String geotiffDir, String terrainFile, Date startTime) {
-        this(zarrFile, geotiffDir, terrainFile, StringHelper.YMDHMS_FORMAT.format(startTime));
-    }
+//    public Zarr2Tif(String zarrFile, String geotiffDir, String terrainFile, Date startTime) {
+//        this(zarrFile, geotiffDir, terrainFile, StringHelper.YMDHMS_FORMAT.format(startTime));
+//    }
 
     public List<String> getVariables() {
         return variables;
@@ -77,20 +88,28 @@
         this.terrain_file = terrain_file;
     }
 
-    public String getStart_timestamp() {
-        return start_timestamp;
+//    public String getStart_timestamp() {
+//        return start_timestamp;
+//    }
+//
+//    public void setStart_timestamp(String start_timestamp) {
+//        this.start_timestamp = start_timestamp;
+//    }
+
+//    public List<Integer> getFrame_range() {
+//        return frame_range;
+//    }
+//
+//    public void setFrame_range(List<Integer> frame_range) {
+//        this.frame_range = frame_range;
+//    }
+
+    public List<Object> getRange() {
+        return range;
     }
 
-    public void setStart_timestamp(String start_timestamp) {
-        this.start_timestamp = start_timestamp;
-    }
-
-    public List<Integer> getFrame_range() {
-        return frame_range;
-    }
-
-    public void setFrame_range(List<Integer> frame_range) {
-        this.frame_range = frame_range;
+    public void setRange(List<Object> range) {
+        this.range = range;
     }
 
     public boolean isFliplr() {
diff --git a/src/main/java/com/se/nsl/domain/vo/ConfigVo.java b/src/main/java/com/se/nsl/domain/vo/ConfigVo.java
index cd8eafe..bbf08e7 100644
--- a/src/main/java/com/se/nsl/domain/vo/ConfigVo.java
+++ b/src/main/java/com/se/nsl/domain/vo/ConfigVo.java
@@ -9,7 +9,7 @@
 
     private String landuse;
 
-    private int station;
+    private Object station;
 
     private Integer kSt;
 
@@ -48,7 +48,7 @@
 
     public ConfigVo(String terrain, String landuse, String station,
                     String raingage, String saveName, int duration,
-                    int frames, String saveMode) {
+                    int frames, String saveMode, String startTime) {
         this();
 
 //        this.terrain.set(0, terrain.replace("\\", "/")); // 鍦板舰楂樼▼鏁版嵁
@@ -60,7 +60,7 @@
         this.raingage = Arrays.asList(raingage, "mm/min");
         this.duration = duration;
         int saveInterval = duration / frames - 5; // 淇鏈�鍚庝竴甯у彲鑳戒负绌烘暟鎹�
-        this.result = new ResultVo(saveName, frames, saveInterval, saveMode);
+        this.result = new ResultVo(saveName, frames, saveInterval, saveMode, startTime);
     }
 
     public String getTerrain() {
@@ -79,11 +79,11 @@
         this.landuse = landuse;
     }
 
-    public int getStation() {
+    public Object getStation() {
         return station;
     }
 
-    public void setStation(int station) {
+    public void setStation(Object station) {
         this.station = station;
     }
 
diff --git a/src/main/java/com/se/nsl/domain/vo/RealTimeSimuParam.java b/src/main/java/com/se/nsl/domain/vo/RealTimeSimuParam.java
new file mode 100644
index 0000000..2f21b05
--- /dev/null
+++ b/src/main/java/com/se/nsl/domain/vo/RealTimeSimuParam.java
@@ -0,0 +1,34 @@
+package com.se.nsl.domain.vo;
+
+import java.util.List;
+
+public class RealTimeSimuParam {
+
+    private String startTime;
+    private String serviceName;
+    private List<String> deviceIds;
+
+    public String getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(String startTime) {
+        this.startTime = startTime;
+    }
+
+    public String getServiceName() {
+        return serviceName;
+    }
+
+    public void setServiceName(String serviceName) {
+        this.serviceName = serviceName;
+    }
+
+    public List<String> getDeviceIds() {
+        return deviceIds;
+    }
+
+    public void setDeviceIds(List<String> deviceIds) {
+        this.deviceIds = deviceIds;
+    }
+}
diff --git a/src/main/java/com/se/nsl/domain/vo/ResultVo.java b/src/main/java/com/se/nsl/domain/vo/ResultVo.java
index 88b7058..43c0f67 100644
--- a/src/main/java/com/se/nsl/domain/vo/ResultVo.java
+++ b/src/main/java/com/se/nsl/domain/vo/ResultVo.java
@@ -1,5 +1,7 @@
 package com.se.nsl.domain.vo;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -12,21 +14,27 @@
 
     private List<String> save_variables;
 
+    private String save_timestamp0;
+
     private Integer save_frames;
+
+//    @JsonIgnore
+    private Integer lastFrames;
 
     private Integer save_interval;
 
     private Integer save_start;
 
-    private Integer save_filter;
+    private Double save_filter;
 
     public ResultVo() {
         this.save_variables = new ArrayList<>(Arrays.asList("depth", "xmomentum", "ymomentum"));
         this.save_start = 0;
-        this.save_filter = 0;
+        this.save_filter = 0D;
     }
 
-    public ResultVo(String saveName, int frames, int saveInterval, String saveMode) {
+    public ResultVo(String saveName, int frames, int saveInterval,
+                    String saveMode, String startTime) {
         this();
 
         this.save_name = saveName.replace("\\", "/");
@@ -34,6 +42,7 @@
         // 缁撴灉鏁版嵁涓浉閭诲抚鐨勬ā鎷熸椂闂撮棿闅旓紙鍗曚綅锛氱锛夛紝save_start + save_frames * save_interval <= duration
         this.save_interval = saveInterval;
         this.save_mode = saveMode;
+        this.save_timestamp0 = startTime;
     }
 
     public String getSave_name() {
@@ -60,12 +69,28 @@
         this.save_variables = save_variables;
     }
 
+    public String getSave_timestamp0() {
+        return save_timestamp0;
+    }
+
+    public void setSave_timestamp0(String save_timestamp0) {
+        this.save_timestamp0 = save_timestamp0;
+    }
+
     public Integer getSave_frames() {
         return save_frames;
     }
 
     public void setSave_frames(Integer save_frames) {
         this.save_frames = save_frames;
+    }
+
+    public Integer getLastFrames() {
+        return lastFrames;
+    }
+
+    public void setLastFrames(Integer lastFrames) {
+        this.lastFrames = lastFrames;
     }
 
     public Integer getSave_interval() {
@@ -84,11 +109,11 @@
         this.save_start = save_start;
     }
 
-    public Integer getSave_filter() {
+    public Double getSave_filter() {
         return save_filter;
     }
 
-    public void setSave_filter(Integer save_filter) {
+    public void setSave_filter(Double save_filter) {
         this.save_filter = save_filter;
     }
 }
diff --git a/src/main/java/com/se/nsl/service/RealTimeSimulationService.java b/src/main/java/com/se/nsl/service/RealTimeSimulationService.java
new file mode 100644
index 0000000..a6b3bc7
--- /dev/null
+++ b/src/main/java/com/se/nsl/service/RealTimeSimulationService.java
@@ -0,0 +1,210 @@
+package com.se.nsl.service;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.se.nsl.config.PropertiesConfig;
+import com.se.nsl.domain.dto.DeviceInfo;
+import com.se.nsl.domain.dto.LayerDto;
+import com.se.nsl.domain.dto.ResultDto;
+import com.se.nsl.domain.dto.Zarr2Tif;
+import com.se.nsl.domain.vo.ConfigVo;
+import com.se.nsl.domain.vo.RealTimeSimuParam;
+import com.se.nsl.domain.vo.ResultVo;
+import com.se.nsl.utils.TimeFormatUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+@Slf4j
+@Service
+public class RealTimeSimulationService {
+
+    public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
+    @Resource
+    PropertiesConfig config;
+    @Resource
+    TestService testService;
+
+    private ObjectMapper mapper = new ObjectMapper();
+
+    public String realTimeSimulate(RealTimeSimuParam input) throws IOException {
+//        List<String> deviceIds = input.getDeviceIds();
+        InputStream stream = RealTimeSimulationService.class.getResourceAsStream("/a_test_device_info.json");
+        List<DeviceInfo> deviceInfos = mapper.readValue(stream,
+                mapper.getTypeFactory().constructCollectionType(List.class, DeviceInfo.class));
+        String startTime = input.getStartTime();
+        long currentTime = TimeFormatUtil.toMillis(startTime, YYYY_MM_DD_HH_MM_SS);
+        //鏍规嵁鏈嶅姟鎵惧埌鎸囧畾鐨勬枃浠跺す
+        String serviceName = input.getServiceName();
+        File serviceNameDir = new File(config.getInPath(), serviceName);
+        //鏍规嵁闆ㄩ噺璁¤鍙栦綑閲忔暟鎹�
+        File newDatFile = generateNewRainfallFile(deviceInfos, serviceNameDir, currentTime);
+
+        //鐢熸垚涓�涓柊鐨勭敓鎴恴arr鐨勯厤缃枃浠�
+        ConfigVo configVo = generateNewZarrConfigFile(serviceNameDir, serviceName, currentTime, newDatFile);
+        File newConfigFile = new File(serviceNameDir, serviceName + ".json");
+        mapper.writeValue(newConfigFile, configVo);
+        //鎵ц姹傝В鍣ㄨ繍绠�
+        String cmd = String.format("%s \"%s\"", config.getUwSolverBat(), newConfigFile);
+        callBat2(cmd);
+
+        //鐢熸垚涓�涓柊鐨剒arr杞瑃if鐨刯son鏂囦欢
+        ResultVo result = configVo.getResult();
+        Integer fromFrame = result.getLastFrames();
+        Integer toFrame = result.getSave_frames() - 1;
+        File newZarr2TifJson = generateNewZarr2TifJson(serviceNameDir, currentTime, fromFrame, toFrame);
+        //鎵цzarr杞瑃if
+        String zarr2TifCmd = String.format("%s \"%s\"", config.getZarr2tifBat(), newZarr2TifJson);
+        callBat2(zarr2TifCmd);
+        //杩斿洖鏂扮殑layer.json鍚嶇О
+        return generateLayerJsonAndPng(serviceName, serviceNameDir, currentTime);
+    }
+
+    private String generateLayerJsonAndPng(String serviceName, File serviceNameDir, long currentTime) throws IOException {
+        ResultDto resultDto = new ResultDto();
+        resultDto.setServiceName(serviceName);
+        File temp = Paths.get(config.getOutPath(), serviceName, "temp").toFile();
+        if (!temp.exists()) temp.mkdir();
+        resultDto.setTemp(temp.getAbsolutePath());
+        resultDto.setOutPath(Paths.get(config.getOutPath(), serviceName).toString());
+        File dem = new File(serviceNameDir, "DEM.tif");
+        resultDto.setTerrainFile(dem.getAbsolutePath());
+        File newDepthDir = new File(serviceNameDir + File.separator + "depth_" + currentTime);
+        resultDto.setWaterPath(newDepthDir.getAbsolutePath());
+        LayerDto layerDto = new LayerDto(config.getVer(), 4548, config.getSizes());
+        String newLayerJsonName = "layer_" + currentTime + ".json";
+        layerDto.setName(newLayerJsonName);
+        testService.processRealTime(resultDto, layerDto);
+        return newLayerJsonName;
+    }
+
+    private File generateNewZarr2TifJson(File serviceNameDir, long currentTime, int fromFrame, int toFrame) throws IOException {
+        File srcZarr2TifJson = new File(serviceNameDir, "zarr2tif.json");
+        Zarr2Tif zarr2Tif = mapper.readValue(srcZarr2TifJson, Zarr2Tif.class);
+        //淇敼zarr2tif瀵硅薄涓殑瀛楁
+        zarr2Tif.setRange(Arrays.asList(fromFrame ,toFrame));
+        String newZarrPath = serviceNameDir + File.separator + "result.zarr";
+        zarr2Tif.setZarr_file(newZarrPath);
+        zarr2Tif.setGeotiff_dir(serviceNameDir + File.separator + "depth_" + currentTime);
+        File newZarr2TifJson = new File(serviceNameDir, "zarr2tif_" + currentTime + ".json");
+        mapper.writeValue(newZarr2TifJson, zarr2Tif);
+        return newZarr2TifJson;
+    }
+
+    private ConfigVo generateNewZarrConfigFile(File serviceNameDir, String serviceName, long currentTime, File newDatFile) throws IOException {
+        File configFile = new File(serviceNameDir, serviceName + ".json");
+        ConfigVo configVo = mapper.readValue(configFile, ConfigVo.class);
+        File stationFile = new File(serviceNameDir, "Station.tif");
+        if (stationFile.exists()) {
+            configVo.setStation(stationFile.getAbsolutePath());
+        }
+        int realTimeSimulateTime = 300; //妯℃嫙鏃堕棿锛岄粯璁や负5min锛屽嵆300s
+        int realTimeInterval = 60; //姣忓抚鐨勯棿闅旀椂闂达紝榛樿涓�60s,60s鐢熸垚涓�甯�
+        configVo.getRaingage().set(0, newDatFile.getAbsolutePath()); //raingage file
+        ResultVo result = configVo.getResult();
+        Integer lastFrames = result.getLastFrames();
+        if (lastFrames == null) {
+            lastFrames = 0;
+        }
+        Integer saveStart = result.getSave_start();
+        Integer saveInterval = result.getSave_interval();
+        Integer saveFrames = result.getSave_frames();
+        Integer newStartPoint = saveStart + (saveFrames - lastFrames) * saveInterval;
+        int newSaveFrames = saveFrames + (realTimeSimulateTime / realTimeInterval);
+        result.setSave_start(newStartPoint); //璧峰鏃堕棿瑕佸湪涓婃鏃堕棿鐨勫熀纭�涓婂紑濮�
+        result.setSave_interval(realTimeInterval);
+        result.setLastFrames(saveFrames);
+        result.setSave_frames(newSaveFrames); //淇濈暀5甯э紝鍦ㄥ師鏉ョ殑鍩虹涓婂鍔�5甯�
+        result.setSave_mode("continue");
+        result.setSave_timestamp0(TimeFormatUtil.formatTime(currentTime, YYYY_MM_DD_HH_MM_SS));
+        configVo.setDuration(newStartPoint + realTimeSimulateTime);
+        String newZarrPath = serviceNameDir + File.separator + "result.zarr";
+        result.setSave_name(newZarrPath);
+        return configVo;
+    }
+
+    private File generateNewRainfallFile(List<DeviceInfo> deviceInfos,
+                                         File serviceNameDir, long currentTime) throws IOException {
+        String title = config.getRainfallTitle();
+        List<String> newLines = new ArrayList<>();
+        newLines.add(title);
+        for (DeviceInfo deviceInfo : deviceInfos) {
+            int stationId = deviceInfo.getMappingId();
+            double lon = deviceInfo.getX();
+            double lat = deviceInfo.getY();
+            LocalDateTime dateTime = TimeFormatUtil.toDate(currentTime);
+            int year = dateTime.getYear();
+            int month = dateTime.getMonthValue();
+            int day = dateTime.getDayOfMonth();
+            int hour = dateTime.getHour();
+            int minute = dateTime.getMinute();
+            double intensity = randomIntensity(); //淇濈暀鎸囧畾浣嶆暟灏忔暟
+            String l = String.format("%s %s %s %s %s %s %s %s %s",
+                    stationId, lon, lat, year, month, day, hour, minute, String.format("%.6f", intensity));
+            newLines.add(l);
+            LocalDateTime dateTime1 = dateTime.plusMinutes(5);
+            year = dateTime1.getYear();
+            month = dateTime1.getMonthValue();
+            day = dateTime1.getDayOfMonth();
+            hour = dateTime1.getHour();
+            minute = dateTime1.getMinute();
+            intensity = randomIntensity();
+            String l2 = String.format("%s %s %s %s %s %s %s %s %s",
+                    stationId, lon, lat, year, month, day, hour, minute, String.format("%.6f", intensity));
+            newLines.add(l2);
+        }
+        File newDatFile = new File(serviceNameDir, "rainfall_" + currentTime + ".dat");
+        if (!newDatFile.exists()) newDatFile.createNewFile();
+        Files.write(newDatFile.toPath(), newLines, StandardOpenOption.TRUNCATE_EXISTING);
+        return newDatFile;
+    }
+
+    private double randomIntensity() {
+        Random random = new Random();
+        // 鐢熸垚0.2鍒�1涔嬮棿鐨勯殢鏈烘暟
+        double min = 0.2;
+        double max = 1.0;
+        return min + random.nextDouble() * (max - min);
+    }
+
+    private static String[] readTheOldFirstLineRainfallValue(File serviceNameDir) throws IOException {
+        File srcRailfallFile = new File(serviceNameDir, "rainfall.dat");
+        List<String> lines = Files.readAllLines(srcRailfallFile.toPath());
+        String secondLine = lines.get(1);
+        return secondLine.split(" ");
+    }
+
+    private String callBat2(String cmd) {
+        try {
+            ProcessBuilder pb = new ProcessBuilder("cmd", "/c", cmd);
+            pb.redirectErrorStream(true); // 鍚堝苟閿欒娴佸埌鏍囧噯杈撳嚭
+
+            Process process = pb.start();
+            process.getOutputStream().close();
+
+            try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "GBK"))) {
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    log.info(line);
+                }
+            }
+
+            int exitCode = process.waitFor();
+
+            return "ok"; // sb.toString();
+        } catch (Exception ex) {
+            log.error(ex.getMessage(), ex);
+            return null;
+        }
+    }
+
+}
diff --git a/src/main/java/com/se/nsl/service/ResolveService.java b/src/main/java/com/se/nsl/service/ResolveService.java
index 4cd5f04..bccb075 100644
--- a/src/main/java/com/se/nsl/service/ResolveService.java
+++ b/src/main/java/com/se/nsl/service/ResolveService.java
@@ -69,6 +69,8 @@
     @Resource
     TestService testService;
 
+    private ObjectMapper mapper = new ObjectMapper();
+
     Integer DIGIT = 1000000;
 
     SimpleDateFormat YYYYMDHM = new SimpleDateFormat("yyyy M d H m ");
@@ -165,6 +167,7 @@
         AreaType at = AreaType.of(areaType);
         String terrainTif = config.getSourceDem();
         String landuseTif = config.getSourceLanduse();
+        String stationTif = null;
         if (at == AreaType.KEY_DITCH) {
             File keyDitchDir = new File(config.getKeyDitch());
             String areaName = simu.getAreaName();
@@ -179,6 +182,9 @@
                     }
                     if (name.toLowerCase().contains("landuse")) {
                         landuseTif = file.getAbsolutePath();
+                    }
+                    if (name.toLowerCase().contains("station")) {
+                        stationTif = file.getAbsolutePath();
                     }
                 }
             }
@@ -203,9 +209,14 @@
         Dataset dsLanduse = gdal.Open(landuseTif, gdalconstConstants.GA_ReadOnly);
         ComHelper.Resample(dsLanduse, null, landuseFile, null, wkt, null, null);
         dsLanduse.delete();
+
+        String stationFile = inPath + File.separator + "Station.tif";
+        Dataset dsStation = gdal.Open(stationTif, gdalconstConstants.GA_ReadOnly);
+        ComHelper.Resample(dsStation, null, stationFile, null, wkt, null, null);
+        dsStation.delete();
     }
 
-    public void updateTif(Simu simu, SimuData data2) throws IOException {
+    public void updateTif(Simu simu, SimuData data2) {
         Dataset ds = gdal.Open(config.getSourceLanduse(), gdalconstConstants.GA_Update); // 浠ヨ鍐欐ā寮忔墦寮�TIFF鏂囦欢
 
         Band band = ds.GetRasterBand(1);
@@ -332,13 +343,13 @@
         Short type = simu.getType();
         SimulateType simulateType = SimulateType.of(type);
         String saveMode = simulateType.getSaveMode();
-        ConfigVo vo = new ConfigVo(terrainFile, landuseFile, terrainFile, rainfallFile, saveName, duration, saveFrames, saveMode);
-
+        String startTime = TimeFormatUtil.formatDate(data.getStartTime());
+        ConfigVo vo = new ConfigVo(terrainFile, landuseFile, terrainFile, rainfallFile,
+                saveName, duration, saveFrames, saveMode, startTime);
         String configFile = config.getInPath() + File.separator + data.getInPath() + File.separator + data.getInPath() + ".json";
-        ComHelper.writeJson(configFile, JSON.toJSONString(vo));
-
+//        ComHelper.writeJson(configFile, JSON.toJSONString(vo));
+        mapper.writeValue(new File(configFile), vo);
         String cmd = String.format("%s \"%s\"", config.getUwSolverBat(), configFile);
-
         return callBat2(cmd);
     }
 
@@ -351,10 +362,9 @@
         String geotiffDir = inPath + File.separator + "depth";
         String terrainFile = inPath + File.separator + config.getTerrainFile();
         String jsonPath = inPath + File.separator + "zarr2tif.json";
-
-        Zarr2Tif zarr2Tif = new Zarr2Tif(zarrFile, geotiffDir, terrainFile, data.getStartTime());
-        ComHelper.writeJson(jsonPath, JSON.toJSONString(zarr2Tif));
-
+        Zarr2Tif zarr2Tif = new Zarr2Tif(zarrFile, geotiffDir, terrainFile, Collections.emptyList());
+//        ComHelper.writeJson(jsonPath, JSON.toJSONString(zarr2Tif));
+        mapper.writeValue(new File(jsonPath), zarr2Tif);
         String cmd = String.format("%s \"%s\"", config.getZarr2tifBat(), jsonPath);
 
         return callBat2(cmd);
@@ -556,13 +566,12 @@
         return newLayerJsonName;
     }
 
-    private static File generateNewZarr2TifJson(File serviceNameDir, long currentTime) throws IOException {
+    private File generateNewZarr2TifJson(File serviceNameDir, long currentTime) throws IOException {
         File srcZarr2TifJson = new File(serviceNameDir, "zarr2tif.json");
-        ObjectMapper mapper = new ObjectMapper();
         Zarr2Tif zarr2Tif = mapper.readValue(srcZarr2TifJson, Zarr2Tif.class);
         //淇敼zarr2tif瀵硅薄涓殑瀛楁
-        String stamp = TimeFormatUtil.formatTime(currentTime, "yyyy-MM-dd HH:mm:ss");
-        zarr2Tif.setStart_timestamp(stamp);
+//        String stamp = TimeFormatUtil.formatTime(currentTime, "yyyy-MM-dd HH:mm:ss");
+//        zarr2Tif.setStart_timestamp(stamp);
 //        String newZarrPath = serviceNameDir + File.separator + "result_" + currentTime + ".zarr";
         String newZarrPath = serviceNameDir + File.separator + "result.zarr";
         zarr2Tif.setZarr_file(newZarrPath);
@@ -574,13 +583,16 @@
 
     private File generateNewZarrConfigFile(File serviceNameDir, String serviceName, long currentTime, File newDatFile) throws IOException {
         File configFile = new File(serviceNameDir, serviceName + ".json");
-        ObjectMapper mapper = new ObjectMapper();
         ConfigVo configVo = mapper.readValue(configFile, ConfigVo.class);
-        configVo.setDuration(configVo.getDuration() + 300); //鍥哄畾涓�5min
+        int simulateTime = 300; //妯℃嫙鏃堕棿锛岄粯璁や负5min锛屽嵆300s
+        int intervalTime = 60; //姣忓抚鐨勯棿闅旀椂闂达紝榛樿涓�60s,60s鐢熸垚涓�甯�
         configVo.getRaingage().set(0, newDatFile.getAbsolutePath()); //raingage file
         ResultVo result = configVo.getResult();
-        result.setSave_interval(60); //60s鐢熸垚涓�甯�
-        result.setSave_frames(result.getSave_frames() + 5); //淇濈暀5甯э紝鍦ㄥ師鏉ョ殑鍩虹涓婂鍔�5甯�
+        Integer oldDuration = configVo.getDuration();
+//        result.setSave_start(oldDuration); //璧峰鏃堕棿瑕佸湪涓婃鏃堕棿鐨勫熀纭�涓婂紑濮�
+        configVo.setDuration(oldDuration + simulateTime); //鍥哄畾涓�5min
+        result.setSave_interval(intervalTime);
+        result.setSave_frames(result.getSave_frames() + (simulateTime / intervalTime)); //淇濈暀5甯э紝鍦ㄥ師鏉ョ殑鍩虹涓婂鍔�5甯�
 //        String newZarrPath = serviceNameDir + File.separator + "result_" + currentTime + ".zarr";
         String newZarrPath = serviceNameDir + File.separator + "result.zarr";
         result.setSave_name(newZarrPath);
diff --git a/src/main/java/com/se/nsl/utils/HttpRequestUtil.java b/src/main/java/com/se/nsl/utils/HttpRequestUtil.java
new file mode 100644
index 0000000..2dce247
--- /dev/null
+++ b/src/main/java/com/se/nsl/utils/HttpRequestUtil.java
@@ -0,0 +1,133 @@
+package com.se.nsl.utils;
+
+import org.springframework.http.*;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * HTTP 璇锋眰宸ュ叿绫伙紝鏀寔甯�/涓嶅甫 Token 鐨勮姹�
+ */
+public class HttpRequestUtil {
+
+    private static final RestTemplate restTemplate = new RestTemplate();
+
+    /**
+     * 鍙戦�� GET 璇锋眰锛堜笉甯� Token锛�
+     */
+    public static <T> ResponseEntity<T> get(String url, Map<String, String> params, Class<T> responseType) {
+        return get(url, params, responseType, null);
+    }
+
+    /**
+     * 鍙戦�� GET 璇锋眰锛堝甫 Token锛�
+     */
+    public static <T> ResponseEntity<T> get(String url, Map<String, String> params, Class<T> responseType, String token) {
+        HttpEntity<String> entity = new HttpEntity<>(null, createHeaders(token));
+
+        // 鏋勫缓甯﹀弬鏁扮殑 URL
+        if (params != null && !params.isEmpty()) {
+            StringBuilder urlBuilder = new StringBuilder(url).append("?");
+            params.forEach((key, value) -> urlBuilder.append(key).append("=").append(value).append("&"));
+            url = urlBuilder.substring(0, urlBuilder.length() - 1);
+        }
+
+        return restTemplate.exchange(url, HttpMethod.GET, entity, responseType);
+    }
+
+    /**
+     * 鍙戦�� POST 璇锋眰锛堜笉甯� Token锛�
+     */
+    public static <T, B> ResponseEntity<T> post(String url, B body, Class<T> responseType) {
+        return post(url, body, responseType, null);
+    }
+
+    /**
+     * 鍙戦�� POST 璇锋眰锛堝甫 Token锛�
+     */
+    public static <T, B> ResponseEntity<T> post(String url, B body, Class<T> responseType, String token) {
+        HttpHeaders headers = createHeaders(token);
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        HttpEntity<B> entity = new HttpEntity<>(body, headers);
+
+        return restTemplate.exchange(url, HttpMethod.POST, entity, responseType);
+    }
+
+    /**
+     * 鍙戦�佽〃鍗� POST 璇锋眰锛堜笉甯� Token锛�
+     */
+    public static <T> ResponseEntity<T> postForm(String url, Map<String, Object> formData, Class<T> responseType) {
+        return postForm(url, formData, responseType, null);
+    }
+
+    /**
+     * 鍙戦�佽〃鍗� POST 璇锋眰锛堝甫 Token锛�
+     */
+    public static <T> ResponseEntity<T> postForm(String url, Map<String, Object> formData, Class<T> responseType, String token) {
+        HttpHeaders headers = createHeaders(token);
+        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+
+        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
+        if (formData != null) {
+            formData.forEach(map::add);
+        }
+
+        HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(map, headers);
+
+        return restTemplate.exchange(url, HttpMethod.POST, entity, responseType);
+    }
+
+    /**
+     * 鍙戦�� PUT 璇锋眰锛堜笉甯� Token锛�
+     */
+    public static <T, B> ResponseEntity<T> put(String url, B body, Class<T> responseType) {
+        return put(url, body, responseType, null);
+    }
+
+    /**
+     * 鍙戦�� PUT 璇锋眰锛堝甫 Token锛�
+     */
+    public static <T, B> ResponseEntity<T> put(String url, B body, Class<T> responseType, String token) {
+        HttpHeaders headers = createHeaders(token);
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        HttpEntity<B> entity = new HttpEntity<>(body, headers);
+
+        return restTemplate.exchange(url, HttpMethod.PUT, entity, responseType);
+    }
+
+    /**
+     * 鍙戦�� DELETE 璇锋眰锛堜笉甯� Token锛�
+     */
+    public static <T> ResponseEntity<T> delete(String url, Class<T> responseType) {
+        return delete(url, responseType, null);
+    }
+
+    /**
+     * 鍙戦�� DELETE 璇锋眰锛堝甫 Token锛�
+     */
+    public static <T> ResponseEntity<T> delete(String url, Class<T> responseType, String token) {
+        HttpEntity<String> entity = new HttpEntity<>(null, createHeaders(token));
+
+        return restTemplate.exchange(url, HttpMethod.DELETE, entity, responseType);
+    }
+
+    /**
+     * 鍒涘缓 HTTP 澶�
+     * @param token 璁よ瘉 Token锛屽彲涓� null
+     * @return HTTP 澶�
+     */
+    private static HttpHeaders createHeaders(String token) {
+        HttpHeaders headers = new HttpHeaders();
+        headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
+
+        // 濡傛灉鎻愪緵浜� Token锛屽垯娣诲姞鍒拌姹傚ご
+        Optional.ofNullable(token)
+                .ifPresent(t -> headers.set("Authorization", "Bearer " + t));
+
+        return headers;
+    }
+}
+
diff --git a/src/main/java/com/se/nsl/utils/TimeFormatUtil.java b/src/main/java/com/se/nsl/utils/TimeFormatUtil.java
index 28f6c38..1f4cdc2 100644
--- a/src/main/java/com/se/nsl/utils/TimeFormatUtil.java
+++ b/src/main/java/com/se/nsl/utils/TimeFormatUtil.java
@@ -2,6 +2,7 @@
 
 import java.time.*;
 import java.time.format.DateTimeFormatter;
+import java.util.Date;
 
 /**
  * @author dcb
@@ -22,6 +23,16 @@
         return dateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
     }
 
+    public static LocalDateTime toDate(long time) {
+        Instant instant = Instant.ofEpochMilli(time);
+        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
+        return localDateTime;
+    }
+
+    public static String formatDate(Date date) {
+        return formatTime(date.getTime(), "yyyy-MM-dd HH:mm:ss");
+    }
+
     public static void main(String[] args) {
         String s = "20250606142122";
         String pattern = "yyyyMMddHHmmss";
diff --git a/src/main/resources/a_test_device_info.json b/src/main/resources/a_test_device_info.json
new file mode 100644
index 0000000..a62f956
--- /dev/null
+++ b/src/main/resources/a_test_device_info.json
@@ -0,0 +1,66 @@
+[
+  {
+    "id": "1101161102180100010065",
+    "name": "鎬�鏌斿尯鐞夌拑搴欓晣瀛欒儭娌熸ご鏍戝簳涓嬩笢娌熼洦閲忚0065",
+    "x": 116.59585,
+    "y": 40.543104,
+    "r": 10000,
+    "mappingId": 0
+  },
+  {
+    "id": "1101161102180100010064",
+    "name": "鎬�鏌斿尯鐞夌拑搴欓晣瀛欒儭娌熸潙涓婂彴瀛愭渤涓滃崡娌熼洦閲忚0064",
+    "x": 116.586304,
+    "y": 40.545741,
+    "r": 10000,
+    "mappingId": 1
+  },
+  {
+    "id": "1101161102180100010063",
+    "name": "鎬�鏌斿尯鐞夌拑搴欓晣瀛欒儭娌熷肮瀹惰タ娌熼洦閲忚0063",
+    "x": 116.579459,
+    "y": 40.556589,
+    "r": 10000,
+    "mappingId": 2
+  },
+  {
+    "id": "1101161102180100010062",
+    "name": "鎬�鏌斿尯鐞夌拑搴欓晣瀛欒儭娌熸潙浜庡瑗挎矡闆ㄩ噺璁�0062",
+    "x": 116.586892,
+    "y": 40.558778,
+    "r": 10000,
+    "mappingId": 3
+  },
+  {
+    "id": "1101160300550102",
+    "name": "鎬�鏌斿尯鐞夌拑搴欓晣瀛欒儭娌熷肮瀹惰タ娌熼洦閲忚0063",
+    "x": 116.57845,
+    "y": 40.56715,
+    "r": 10000,
+    "mappingId": 4
+  },
+  {
+    "id": "1101160300540101",
+    "name": "鎬�鏌斿尯鐞夌拑搴欓晣瀛欒儭娌熸潙浜庡瑗挎矡闆ㄩ噺璁�0062",
+    "x": 116.59064,
+    "y": 40.56122,
+    "r": 10000,
+    "mappingId": 5
+  },
+  {
+    "id": "1101160300420103",
+    "name": "鎬�鏌斿尯鐞夌拑搴欓晣瀛欒儭娌熸潙涓婂彴瀛愭渤涓滃崡娌熼洦閲忚0064",
+    "x": 116.60498,
+    "y": 40.56032,
+    "r": 10000,
+    "mappingId": 6
+  },
+  {
+    "id": "1101160300400103",
+    "name": "鎬�鏌斿尯鐞夌拑搴欓晣瀛欒儭娌熸ご鏍戝簳涓嬩笢娌熼洦閲忚0065",
+    "x": 116.60578,
+    "y": 40.55423,
+    "r": 10000,
+    "mappingId": 7
+  }
+]
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
index 3eafa1d..6cf3fe5 100644
--- a/src/main/resources/application-dev.yml
+++ b/src/main/resources/application-dev.yml
@@ -141,16 +141,16 @@
   flowUnits: CMS
   solverBat: D:\other\simu\uwsolver\run_solver.bat
   sww2tifBat: D:\other\simu\uwsolver\sww2tif.bat
-  uwSolverBat: D:\other\simu\CudaUWSolver-2.1.1\cuws.bat
+  uwSolverBat: D:\other\simu\CudaUWSolver-2.2\cuws.bat
 #  uwSolverBat: D:\other\simu\CudaUWSolver-2.0\start.bat
-  zarr2tifBat: D:\other\simu\zarr2tif-2.1\start.bat
+  zarr2tifBat: D:\other\simu\CudaUWSolver-2.2\zarr2tif.bat
   createRainfall: '"C:\Program Files\Python310\python.exe" D:\terrait\NslServer\data\CreatRainfall.py'
   rainfallTitle: Station Longitude Latitude Year Month Day Hour Minute Intensity
   rainfallSite: beijing
   epsg: 4548
 #  saveFrames: 3
   #鐢熸垚甯ф暟鐨勯棿闅旀椂闂达紝鍗曚綅鏄垎閽燂紝璁剧疆涓�5琛ㄧず姣忛殧5鍒嗛挓鐢熸垚涓�甯�
-  saveFrameInterval: 10
+  saveFrameInterval: 20
   # 鍦熷湴鍒╃敤锛�1-Cropland,2-Forest,3-Shrub,4-Grassland,5-Water,6-Snow/Ice,7-Barren,8-Impervious,9-Wetland
   landuse: 2
   #sizes: 64,128,256,512,1024,2048,4096
@@ -163,10 +163,10 @@
   waterPath: depth
   flowPath: velocity
   landuseFile: Landuse.tif
-  sourceDem: D:\other\simu\CudaUWSolver-2.1.1\Beijing-Data-10m\Beijing-4548-ASTERDEMV3-10m.tif
-  sourceLanduse: D:\other\simu\CudaUWSolver-2.1.1\Beijing-Data-10m\Beijing-4548-Landuse-10m-Nonodata.tif
+  sourceDem: D:\other\simu\CudaUWSolver-2.2\Beijing-Data-10m\Beijing-4548-ASTERDEMV3-10m-f32.tif
+  sourceLanduse: D:\other\simu\CudaUWSolver-2.2\Beijing-Data-10m\Beijing-4548-Landuse-10m-Nonodata.tif
   copyTif: false
   tifPath: D:\other\simu\uwsolver\5ca43c87cd8e48c5a9c5399a5da46dbc\tongzhou_raster_4548_1m_clip_river_fill.tif
   #tif涓殑楂樼▼鏂囦欢鍚嶈鍚湁dem锛屽湡鍦板埄鐢ㄨ鍚湁landuse锛岀珯鐐硅鍚湁station锛屼笉闄愬埗澶у皬鍐欙紝鏂囧瓧灏介噺鐢ㄨ嫳鏂囧瓧姣嶈〃杈�
-  keyDitch: D:\other\simu\CudaUWSolver-2.1.1\KeyDitch
+  keyDitch: D:\other\simu\CudaUWSolver-2.2\KeyDitch
 

--
Gitblit v1.9.3