| | |
| | | package com.se.nsl.service; |
| | | |
| | | import com.fasterxml.jackson.core.JsonProcessingException; |
| | | import com.fasterxml.jackson.databind.JsonNode; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import com.se.nsl.config.GaugeServer; |
| | | 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.dto.*; |
| | | import com.se.nsl.domain.po.RainGauge; |
| | | import com.se.nsl.domain.po.Simu; |
| | | import com.se.nsl.domain.po.SimuData; |
| | | 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.mapper.SimuMapper; |
| | | import com.se.nsl.utils.HttpRequestUtil; |
| | | import com.se.nsl.utils.TimeFormatUtil; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.http.ResponseEntity; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import javax.annotation.Resource; |
| | |
| | | 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; |
| | | import java.util.*; |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.stream.Collectors; |
| | | |
| | | @Slf4j |
| | | @Service |
| | | public class RealTimeSimulationService { |
| | | |
| | | public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; |
| | | public static final String JSON_EXT = ".json"; |
| | | public static final String DEM_TIF = "DEM.tif"; |
| | | public static final String RESULT_ZARR = "result.zarr"; |
| | | @Resource |
| | | PropertiesConfig config; |
| | | @Resource |
| | | TestService testService; |
| | | @Resource |
| | | ResolveService resolveService; |
| | | @Resource |
| | | SimuMapper simuMapper; |
| | | |
| | | private ObjectMapper mapper = new ObjectMapper(); |
| | | private final ObjectMapper mapper = new ObjectMapper(); |
| | | @Resource |
| | | private GaugeServer gaugeServer; |
| | | private static final long MILLIS_OF_ONE_DAY = 86400000; |
| | | |
| | | public String realTimeSimulate(RealTimeSimuParam input) throws IOException { |
| | | // List<String> deviceIds = input.getDeviceIds(); |
| | | InputStream stream = RealTimeSimulationService.class.getResourceAsStream("/a_test_device_info.json"); |
| | | public String realTimeSimulate(Simu simu) throws IOException { |
| | | InputStream stream = RealTimeSimulationService.class.getResourceAsStream("/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(); |
| | | String serviceName = simu.getServiceName(); |
| | | long currentTime = getCurrentTime(); |
| | | if (serviceName == null) { //没有进行过模拟计算 |
| | | serviceName = TimeFormatUtil.formatTime(currentTime, "yyyyMMddHHmmss"); |
| | | simu.setServiceName(serviceName); |
| | | File serviceNameDir = new File(config.getInPath(), serviceName); |
| | | //根据雨量计读取余量数据 |
| | | File newDatFile = generateNewRainfallFile(deviceInfos, serviceNameDir, currentTime); |
| | | serviceNameDir.mkdir(); |
| | | String layerJsonName = executeSimulateTask(simu, deviceInfos, serviceNameDir, currentTime, serviceName, true); |
| | | simuMapper.updates(Collections.singletonList(simu)); |
| | | return layerJsonName; |
| | | } else { |
| | | File serviceNameDir = new File(config.getInPath(), serviceName); |
| | | return executeSimulateTask(simu, deviceInfos, serviceNameDir, currentTime, serviceName ,false); |
| | | } |
| | | } |
| | | |
| | | private long getCurrentTime() { |
| | | double offsetDays = gaugeServer.getOffsetDays(); |
| | | long millis = (long) (offsetDays * MILLIS_OF_ONE_DAY); |
| | | return System.currentTimeMillis() - millis; |
| | | } |
| | | |
| | | private String executeSimulateTask(Simu simu, List<DeviceInfo> deviceInfos, File serviceNameDir, |
| | | long currentTime, String serviceName, boolean firstTime) throws IOException { |
| | | SimuData simuData = mapper.readValue(simu.getData(), SimuData.class); |
| | | simuData.setOutPath(serviceName); |
| | | simuData.setInPath(serviceName); |
| | | List<RainGauge> gauges = simuData.getGauges(); //雨量计信息 |
| | | if (firstTime) { |
| | | resolveService.initArgs(simu, simuData); |
| | | } |
| | | //根据雨量计读取余量数据 |
| | | File newDatFile = generateNewRainfallFile(gauges, deviceInfos, serviceNameDir, currentTime); |
| | | //生成一个新的生成zarr的配置文件 |
| | | ConfigVo configVo = generateNewZarrConfigFile(serviceNameDir, serviceName, currentTime, newDatFile); |
| | | File newConfigFile = new File(serviceNameDir, serviceName + ".json"); |
| | | ConfigVo configVo; |
| | | if (firstTime) { |
| | | configVo = firstTimeZarrConfigFile(serviceNameDir, currentTime, newDatFile); |
| | | } else { |
| | | configVo = generateNewZarrConfigFile(serviceNameDir, serviceName, currentTime, newDatFile); |
| | | } |
| | | File newConfigFile = new File(serviceNameDir, serviceName + JSON_EXT); |
| | | mapper.writeValue(newConfigFile, configVo); |
| | | //执行求解器运算 |
| | | String cmd = String.format("%s \"%s\"", config.getUwSolverBat(), newConfigFile); |
| | | callBat2(cmd); |
| | | callBat(cmd); |
| | | |
| | | File newZarr2TifJson; |
| | | if (firstTime) { |
| | | newZarr2TifJson = generateNewZarr2TifJson(serviceNameDir, currentTime, Collections.emptyList()); |
| | | } else { |
| | | //生成一个新的zarr转tif的json文件 |
| | | ResultVo result = configVo.getResult(); |
| | | Integer fromFrame = result.getLastFrames(); |
| | | Integer toFrame = result.getSave_frames() - 1; |
| | | File newZarr2TifJson = generateNewZarr2TifJson(serviceNameDir, currentTime, fromFrame, toFrame); |
| | | newZarr2TifJson = generateNewZarr2TifJson(serviceNameDir, currentTime, Arrays.asList(fromFrame, toFrame)); |
| | | } |
| | | //执行zarr转tif |
| | | String zarr2TifCmd = String.format("%s \"%s\"", config.getZarr2tifBat(), newZarr2TifJson); |
| | | callBat2(zarr2TifCmd); |
| | | callBat(zarr2TifCmd); |
| | | //返回新的layer.json名称 |
| | | if (firstTime) { |
| | | return generateLayerJsonAndPng(serviceName, serviceNameDir, -1); |
| | | } else { |
| | | return generateLayerJsonAndPng(serviceName, serviceNameDir, currentTime); |
| | | } |
| | | } |
| | | |
| | | private String generateLayerJsonAndPng(String serviceName, File serviceNameDir, long currentTime) throws IOException { |
| | | 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"); |
| | | File dem = new File(serviceNameDir, DEM_TIF); |
| | | resultDto.setTerrainFile(dem.getAbsolutePath()); |
| | | File newDepthDir = new File(serviceNameDir + File.separator + "depth_" + currentTime); |
| | | File newDepthDir; |
| | | if (currentTime < 0) { |
| | | newDepthDir = new File(serviceNameDir + File.separator + "depth"); |
| | | } else { |
| | | 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 layerDto = new LayerDto(config.getVer(), config.getEpsg(), config.getSizes()); |
| | | String newLayerJsonName; |
| | | if (currentTime < 0) { |
| | | newLayerJsonName = "layer.json"; |
| | | } else { |
| | | newLayerJsonName = "layer_" + currentTime + JSON_EXT; |
| | | } |
| | | layerDto.setName(newLayerJsonName); |
| | | testService.processRealTime(resultDto, layerDto); |
| | | log.info("实时模拟完成"); |
| | | return newLayerJsonName; |
| | | } |
| | | |
| | | private File generateNewZarr2TifJson(File serviceNameDir, long currentTime, int fromFrame, int toFrame) throws IOException { |
| | | private File generateNewZarr2TifJson(File serviceNameDir, long currentTime, List<Object> range) throws IOException { |
| | | Zarr2Tif zarr2Tif; |
| | | File newZarr2TifJson; |
| | | String newZarrPath; |
| | | String geotiffDir; |
| | | if (range.isEmpty()) { |
| | | zarr2Tif = new Zarr2Tif(); |
| | | newZarrPath = serviceNameDir + File.separator + RESULT_ZARR; |
| | | geotiffDir = serviceNameDir + File.separator + "depth"; |
| | | zarr2Tif.setTerrain_file(serviceNameDir + File.separator + DEM_TIF); |
| | | newZarr2TifJson = new File(serviceNameDir, "zarr2tif.json"); |
| | | } else { |
| | | File srcZarr2TifJson = new File(serviceNameDir, "zarr2tif.json"); |
| | | Zarr2Tif zarr2Tif = mapper.readValue(srcZarr2TifJson, Zarr2Tif.class); |
| | | zarr2Tif = mapper.readValue(srcZarr2TifJson, Zarr2Tif.class); |
| | | //修改zarr2tif对象中的字段 |
| | | zarr2Tif.setRange(Arrays.asList(fromFrame ,toFrame)); |
| | | String newZarrPath = serviceNameDir + File.separator + "result.zarr"; |
| | | newZarrPath = serviceNameDir + File.separator + RESULT_ZARR; |
| | | geotiffDir = serviceNameDir + File.separator + "depth_" + currentTime; |
| | | newZarr2TifJson = new File(serviceNameDir, "zarr2tif_" + currentTime + JSON_EXT); |
| | | } |
| | | zarr2Tif.setGeotiff_dir(geotiffDir); |
| | | zarr2Tif.setZarr_file(newZarrPath); |
| | | zarr2Tif.setGeotiff_dir(serviceNameDir + File.separator + "depth_" + currentTime); |
| | | File newZarr2TifJson = new File(serviceNameDir, "zarr2tif_" + currentTime + ".json"); |
| | | zarr2Tif.setRange(range); |
| | | mapper.writeValue(newZarr2TifJson, zarr2Tif); |
| | | return newZarr2TifJson; |
| | | } |
| | | |
| | | private ConfigVo firstTimeZarrConfigFile(File serviceNameDir, long currentTime, File newDatFile) { |
| | | ConfigVo configVo = new ConfigVo(); |
| | | String serviceNameDirPath = serviceNameDir.getAbsolutePath(); |
| | | configVo.setTerrain(serviceNameDirPath + File.separator + DEM_TIF); |
| | | configVo.setLanduse(serviceNameDirPath + File.separator + "Landuse.tif"); |
| | | File stationFile = new File(serviceNameDir, "Station.tif"); |
| | | if (stationFile.exists()) { |
| | | configVo.setStation(stationFile.getAbsolutePath()); |
| | | } |
| | | int realTimeSimulateTime = 300; //模拟时间,默认为5min,即300s |
| | | int realTimeInterval = 60; //每帧的间隔时间,默认为60s,60s生成一帧 |
| | | List<String> rainGauge = new ArrayList<>(); |
| | | rainGauge.add(newDatFile.getAbsolutePath());//raingage file |
| | | rainGauge.add("mm/min"); |
| | | configVo.setRaingage(rainGauge); |
| | | String saveName = serviceNameDir + File.separator + RESULT_ZARR; |
| | | ResultVo result = new ResultVo(saveName, realTimeSimulateTime / realTimeInterval, |
| | | realTimeInterval,"continue", null); |
| | | result.setSave_interval(realTimeInterval); |
| | | result.setSave_timestamp0(TimeFormatUtil.formatTime(currentTime, YYYY_MM_DD_HH_MM_SS)); |
| | | configVo.setDuration(realTimeSimulateTime); |
| | | result.setSave_name(saveName); |
| | | result.setSave_filter(config.getSaveFilter()); |
| | | configVo.setResult(result); |
| | | return configVo; |
| | | } |
| | | |
| | | private ConfigVo generateNewZarrConfigFile(File serviceNameDir, String serviceName, long currentTime, File newDatFile) throws IOException { |
| | | File configFile = new File(serviceNameDir, serviceName + ".json"); |
| | | File configFile = new File(serviceNameDir, serviceName + JSON_EXT); |
| | | ConfigVo configVo = mapper.readValue(configFile, ConfigVo.class); |
| | | File stationFile = new File(serviceNameDir, "Station.tif"); |
| | | if (stationFile.exists()) { |
| | |
| | | Integer saveStart = result.getSave_start(); |
| | | Integer saveInterval = result.getSave_interval(); |
| | | Integer saveFrames = result.getSave_frames(); |
| | | Integer newStartPoint = saveStart + (saveFrames - lastFrames) * saveInterval; |
| | | int 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, |
| | | private File generateNewRainfallFile(List<RainGauge> gauges, 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)); |
| | | Map<String, Integer> deviceInfoMap = deviceInfos.stream().collect(Collectors.toMap(DeviceInfo::getId, DeviceInfo::getMappingId)); |
| | | for (RainGauge gauge : gauges) { |
| | | String id = gauge.getId(); |
| | | Integer mappingId = deviceInfoMap.getOrDefault(id, 0); |
| | | String l = getRainGaugeResult(gauge, mappingId, currentTime); |
| | | 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(); |
| | |
| | | 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 String getRainGaugeResult(RainGauge gauge,int stationId, long currentTime) throws JsonProcessingException { |
| | | double lon = gauge.getX(); |
| | | double lat = gauge.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(); |
| | | String id = gauge.getId(); |
| | | long someMinutesAgo = currentTime - TimeUnit.MINUTES.toMillis(gaugeServer.getRequestOffsetMinutes()); |
| | | String startTime = TimeFormatUtil.formatTime(someMinutesAgo, YYYY_MM_DD_HH_MM_SS); |
| | | String endTime = TimeFormatUtil.formatTime(currentTime, YYYY_MM_DD_HH_MM_SS); |
| | | double intensity = getIntensityByDeviceId(id, startTime, endTime); //保留指定位数小数 |
| | | return String.format("%s %s %s %s %s %s %s %s %s", |
| | | stationId, lon, lat, year, month, day, hour, minute, String.format("%.6f", intensity)); |
| | | } |
| | | |
| | | 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 double getIntensityByDeviceId(String deviceId, String startTime, String endTime) throws JsonProcessingException { |
| | | RemoteGaugeInput input = new RemoteGaugeInput(); |
| | | input.setCurrentPage(1); |
| | | input.setPageSize(2); |
| | | RemoteGaugeInput.FilterObject filterObject = new RemoteGaugeInput.FilterObject(); |
| | | filterObject.setDeviceCode(deviceId); |
| | | filterObject.setSendTimeList(Arrays.asList(startTime, endTime)); |
| | | input.setFilterObject(filterObject); |
| | | String url = gaugeServer.getUrl(); |
| | | String token = gaugeServer.getToken(); |
| | | ResponseEntity<String> post = HttpRequestUtil.post(url, input, String.class, token); |
| | | String body = post.getBody(); |
| | | JsonNode jsonNode = mapper.readTree(body); |
| | | JsonNode pageData = jsonNode.get("data").get("pageData"); |
| | | if (!pageData.isEmpty()) { |
| | | return pageData.get(0).get("value").asDouble(); |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | private String callBat2(String cmd) { |
| | | |
| | | private String callBat(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(); |
| | | return "" + exitCode; // sb.toString(); |
| | | } catch (Exception ex) { |
| | | log.error(ex.getMessage(), ex); |
| | | return null; |