dcb
2025-06-30 59b432c883011119649c283cc9d4c1d357599802
src/main/java/com/se/nsl/service/ResolveService.java
@@ -4,8 +4,9 @@
import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.se.nsl.config.PropertiesConfig;
import com.se.nsl.domain.dto.Zarr2Tif;
import com.se.nsl.domain.dto.*;
import com.se.nsl.domain.po.Rainfall;
import com.se.nsl.domain.po.Simu;
import com.se.nsl.domain.po.SimuData;
@@ -14,6 +15,10 @@
import com.se.nsl.helper.GdalHelper;
import com.se.nsl.helper.StringHelper;
import com.se.nsl.helper.WebHelper;
import com.se.nsl.utils.AreaType;
import com.se.nsl.utils.RainFallUnit;
import com.se.nsl.utils.SimulateType;
import com.se.nsl.utils.TimeFormatUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.gdal.gdal.Band;
@@ -30,14 +35,11 @@
import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.*;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.Instant;
@@ -62,6 +64,8 @@
    @Resource
    TestService testService;
    private ObjectMapper mapper = new ObjectMapper();
    Integer DIGIT = 1000000;
@@ -121,7 +125,7 @@
            createRainfallFile(simu, data);
            update(simu, 2, "调用求解器");
            callUwSolver(data);
            callUwSolver(simu, data);
            update(simu, 3, "调用Zarr转Tif");
            callZarr2tif(data);
@@ -130,6 +134,7 @@
            createNsl(data);
            update(simu, 10, "完成");
            log.info("模拟完成");
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            update(simu, 20, ex.getMessage());
@@ -147,12 +152,39 @@
    /**
     * 初始化参数
     */
    public void initArgs(Simu simu, SimuData data) throws IOException {
    public void initArgs(Simu simu, SimuData data) {
        String inPath = config.getInPath() + File.separator + data.getInPath();
        createDir(inPath);
        createDir(inPath + File.separator + "depth");
        createDir(inPath + File.separator + "velocity");
        createDir(config.getOutPath() + File.separator + data.getOutPath());
        Short areaType = simu.getAreaType();
        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();
            Optional<File> first = Arrays.stream(keyDitchDir.listFiles()).filter(f -> f.getName().equals(areaName)).findFirst();
            if (first.isPresent()) {
                File targetTifDir = first.get();
                File[] files = targetTifDir.listFiles();
                for (File file : files) {
                    String name = file.getName();
                    if (name.toLowerCase().contains("dem")) {
                        terrainTif = file.getAbsolutePath();
                    }
                    if (name.toLowerCase().contains("landuse")) {
                        landuseTif = file.getAbsolutePath();
                    }
                    if (name.toLowerCase().contains("station")) {
                        stationTif = file.getAbsolutePath();
                    }
                }
            }
        }
        Geometry geom = Geometry.CreateFromWkt(simu.getGeom());
        if (geom.GetGeometryType() == ogr.wkbMultiPolygon) geom = geom.GetGeometryRef(0);
@@ -163,17 +195,26 @@
        String wkt = geom.ExportToWkt();
        String terrainFile = inPath + File.separator + config.getTerrainFile();
        Dataset dsDem = gdal.Open(config.getSourceDem(), gdalconstConstants.GA_ReadOnly);
        ComHelper.Resample(dsDem, null, terrainFile, null, wkt, null, null);
        Dataset dsDem = gdal.Open(terrainTif, gdalconstConstants.GA_ReadOnly);
        ComHelper.cutAndResample(dsDem, null, terrainFile, null, wkt, null, null);
        dsDem.delete();
        String landuseFile = inPath + File.separator + config.getLanduseFile();
        Dataset dsLanduse = gdal.Open(config.getSourceLanduse(), gdalconstConstants.GA_ReadOnly);
        ComHelper.Resample(dsLanduse, null, landuseFile, null, wkt, null, null);
        Dataset dsLanduse = gdal.Open(landuseTif, gdalconstConstants.GA_ReadOnly);
        ComHelper.cutAndResample(dsLanduse, null, landuseFile, null, wkt, null, null);
        dsLanduse.delete();
        if (stationTif != null) {
            String stationFile = inPath + File.separator + "Station.tif";
            Dataset dsStation = gdal.Open(stationTif, gdalconstConstants.GA_ReadOnly);
            ComHelper.cutAndResample(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);
@@ -210,30 +251,6 @@
        }
        f.mkdirs();
    }
    enum RainFallUnit {
        MM_H("mm/h", 60),
        MM_15MIN("mm/15min", 15),
        MM_5MIN("mm/5min", 5),
        MM_MIN("mm/min", 1);
        private String unit;
        private int c; //系数
        RainFallUnit(String unit, int c) {
            this.unit = unit;
            this.c = c;
        }
        public static RainFallUnit of(String unit) {
            RainFallUnit[] values = values();
            for (RainFallUnit v : values) {
                if (v.unit.equals(unit)) {
                    return v;
                }
            }
            return MM_H; //默认按照mm/h计算
        }
    }
    public void createRainfallFile(Simu simu, SimuData data) throws Exception {
        List<Rainfall> rainfalls = data.getRainfalls();
@@ -256,8 +273,8 @@
//        int unit = StringUtils.isEmpty(data.getIntensityUnit()) || "mm/h".equals(data.getIntensityUnit()) ? 60 : 5;
        String iu = data.getIntensityUnit();
        RainFallUnit rfUnit = RainFallUnit.of(iu);
        data.setIntensityUnit(rfUnit.unit);
        int unit = rfUnit.c;
        data.setIntensityUnit(rfUnit.getUnit());
        int unit = rfUnit.getC();
        int c = rainfalls.size() - 1;
        for (int i = 0; i < c; i++) {
            Rainfall r1 = rainfalls.get(i);
@@ -267,7 +284,7 @@
        }
        //list.add(prefix + YYYYMDHM.format(rainfalls.get(c).getTime()) + getMinVal(rainfalls.get(c).getIntensity() / unit, DIGIT));
        list.add(String.format("%s%s%f", prefix, YYYYMDHM.format(rainfalls.get(c).getTime()), getMinVal(rainfalls.get(c).getIntensity() / unit, DIGIT)));
        list.add(0, "1 " + (list.size() - 1));
//        list.add(0, "1 " + (list.size() - 1));
        Files.write(Paths.get(rainfallFile), list, StandardCharsets.UTF_8);
    }
@@ -298,9 +315,7 @@
    /**
     * 调用UWSolver
     */
    public String callUwSolver(SimuData data) throws Exception {
        File uwBat = new File(config.getUwSolverBat());
    public String callUwSolver(Simu simu, SimuData data) throws Exception {
        int duration = 3600 * data.getDuration(); // 秒数
        if (null != data.getRainfalls() && data.getRainfalls().size() > 1) {
            List<Rainfall> rainfalls = data.getRainfalls();
@@ -321,13 +336,17 @@
//        ConfigVo vo = new ConfigVo(terrainFile, landuseFile, terrainFile, rainfallFile, saveName, duration, config.getSaveFrames());
        Integer saveFrameInterval = config.getSaveFrameInterval();
        int saveFrames = duration / 60 / saveFrameInterval;
        ConfigVo vo = new ConfigVo(terrainFile, landuseFile, terrainFile, rainfallFile, saveName, duration, saveFrames);
        Short type = simu.getType();
        SimulateType simulateType = SimulateType.of(type);
        String saveMode = simulateType.getSaveMode();
        String startTime = TimeFormatUtil.formatDate(data.getStartTime());
        ConfigVo vo = new ConfigVo(terrainFile, landuseFile, terrainFile, rainfallFile,
                saveName, duration, saveFrames, saveMode, startTime);
        vo.getResult().setSave_filter(config.getSaveFilter());
        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);
    }
@@ -340,10 +359,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);
@@ -357,12 +375,10 @@
            Process process = pb.start();
            process.getOutputStream().close();
            //StringBuilder sb = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "GBK"))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println(line);
                    //sb.append(line);
                    log.info(line);
                }
            }
@@ -374,18 +390,6 @@
            return null;
        }
    }
    /*private String callZarr2tif(SimuData data) throws Exception {
        File uwBat = new File(config.getUwSolverBat());
        String zarrFile = uwBat.getParent() + File.separator + "result.zarr";
        String inPath = config.getInPath() + File.separator + data.getInPath();
        String terrainFile = inPath + File.separator + config.getTerrainFile();
        String waterPath = inPath + File.separator + "depth";
        String cmd = String.format("%s \"%s\" \"%s\" \"%s\" \"%s\"", config.getZarr2tifBat(), "depth", zarrFile, terrainFile, waterPath);
        return callBat(cmd);
    }*/
    private String callBat(String cmd) {
        try {
@@ -414,9 +418,6 @@
    }
    private void createNsl(SimuData data) throws Exception {
        /*String inPath = config.getInPath() + File.separator + data.getInPath() + File.separator + "depth";
        procTifs(inPath, inPath, data.getStartTime());*/
        testService.test(data);
    }
@@ -444,7 +445,6 @@
    public String createRainfallCsv(String csvPath, String mode, double total, double intensity, int hours) {
        // python 脚本名.py <参数1-csv文件名> <参数2-降雨模式:正态分布|平均分布|波动平均分布|持续上升> <参数3-降雨总量> <参数4-最大雨强> <参数5-降雨时间(分钟)>
        String cmd = String.format("%s \"%s\" \"%s\" %f %f %d", config.getCreateRainfall(), csvPath, mode, total, intensity, hours * 60);
        return callBat(cmd);
    }
@@ -478,11 +478,10 @@
    }
    private List<Double> getValues(String csvPath) throws Exception {
        if (!new File(csvPath).exists()) return null;
        if (!new File(csvPath).exists()) return Collections.emptyList();
        List<String> list = Files.readAllLines(Paths.get(csvPath));
        list.remove(0);
        //list.remove(list.size() - 1);
        return list.stream()
                .map(s -> new BigDecimal(s).setScale(6, RoundingMode.HALF_DOWN).doubleValue())
@@ -513,8 +512,120 @@
            cal.add(Calendar.MINUTE, 1);
        }
        list.add(0, "1 " + (list.size() - 1));
//        list.add(0, "1 " + (list.size() - 1));
        Files.write(Paths.get(dat), list, StandardCharsets.UTF_8);
    }
    //实时模拟
//    public String realTimeSimulate(RealTimeInput input) throws IOException {
//        long currentTime = System.currentTimeMillis();
//        //根据服务找到指定的文件夹
//        String serviceName = input.getServiceName();
//        File serviceNameDir = new File(config.getInPath(), serviceName);
//        //生成一个新的雨量文件,需要原先雨量文件的一些信息,所以需要先读取旧的
//        String[] values = readTheOldFirstLineRainfallValue(serviceNameDir);
//        File newDatFile = generateNewRainfallFile(input, values, serviceNameDir, currentTime);
//
//        //生成一个新的生成zarr的配置文件
//        File newConfigFile = generateNewZarrConfigFile(serviceNameDir, serviceName, currentTime, newDatFile);
//        //执行求解器运算
//        String cmd = String.format("%s \"%s\"", config.getUwSolverBat(), newConfigFile);
//        callBat2(cmd);
//
//        //生成一个新的zarr转tif的json文件
//        File newZarr2TifJson = generateNewZarr2TifJson(serviceNameDir, currentTime);
//        //执行zarr转tif
//        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) throws IOException {
//        File srcZarr2TifJson = new File(serviceNameDir, "zarr2tif.json");
//        Zarr2Tif zarr2Tif = mapper.readValue(srcZarr2TifJson, Zarr2Tif.class);
//        //修改zarr2tif对象中的字段
////        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);
//        zarr2Tif.setGeotiff_dir(serviceNameDir + File.separator + "depth_" + currentTime);
//        File newZarr2TifJson = new File(serviceNameDir, "zarr2tif_" + currentTime + ".json");
//        mapper.writeValue(newZarr2TifJson, zarr2Tif);
//        return newZarr2TifJson;
//    }
//    private File 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);
//        int simulateTime = 300; //模拟时间,默认为5min,即300s
//        int intervalTime = 60; //每帧的间隔时间,默认为60s,60s生成一帧
//        configVo.getRaingage().set(0, newDatFile.getAbsolutePath()); //raingage file
//        ResultVo result = configVo.getResult();
//        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);
//        File newConfigFile = new File(serviceNameDir, currentTime + ".json");
//        mapper.writeValue(newConfigFile, configVo);
//        return newConfigFile;
//    }
//    private File generateNewRainfallFile(RealTimeInput input, String[] values, File serviceNameDir, long currentTime) throws IOException {
//        String station = values[0];
//        double lon = Double.parseDouble(values[1]);
//        double lat = Double.parseDouble(values[2]);
//        String title = config.getRainfallTitle();
//        List<String> newLines = new ArrayList<>();
//        newLines.add(title);
//        List<RealTimeInput.RealTimeData> data = input.getData();
//        for (RealTimeInput.RealTimeData rd : data) {
//            LocalDateTime dateTime = rd.getDateTime();
//            int year = dateTime.getYear();
//            int month = dateTime.getMonthValue();
//            int day = dateTime.getDayOfMonth();
//            int hour = dateTime.getHour();
//            int minute = dateTime.getMinute();
//            double intensity = rd.getIntensity(); //保留指定位数小数
//            String l = String.format("%s %s %s %s %s %s %s %s %s",
//                    station, lon, lat, year, month, day, hour, minute, String.format("%.6f", intensity));
//            newLines.add(l);
//        }
//        File newDatFile = new File(serviceNameDir, "rainfall_" + currentTime + ".dat");
//        if (!newDatFile.exists()) newDatFile.createNewFile();
//        Files.write(newDatFile.toPath(), newLines, StandardOpenOption.TRUNCATE_EXISTING);
//        return newDatFile;
//    }
//    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(" ");
//    }
}