xyc
2024-08-02 4df461673ff8b350df032429c07bc973a3b83c7f
modules/mainPart/src/main/java/com/zt/life/modules/mainPart/taskReliability/service/SimulatAssessService.java
@@ -1,13 +1,37 @@
package com.zt.life.modules.mainPart.taskReliability.service;
import com.alibaba.fastjson.JSONObject;
import com.zt.common.service.BaseService;
import com.zt.life.modules.mainPart.taskReliability.dao.SimulatAssessDao;
import com.zt.common.servlet.Result;
import com.zt.common.utils.UUIDUtil;
import com.zt.life.modules.mainPart.basicInfo.dao.ParamDataDao;
import com.zt.life.modules.mainPart.basicInfo.dao.XhProductModelDao;
import com.zt.life.modules.mainPart.basicInfo.model.ParamData;
import com.zt.life.modules.mainPart.basicInfo.model.XhProductModel;
import com.zt.life.modules.mainPart.taskReliability.dao.*;
import com.zt.life.modules.mainPart.taskReliability.dto.ProductStatusDto;
import com.zt.life.modules.mainPart.taskReliability.model.SimulatAssess;
import com.zt.life.modules.mainPart.taskReliability.dto.TaskModelCheckResult;
import com.zt.life.modules.mainPart.taskReliability.model.*;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
@@ -17,9 +41,41 @@
 * @since 1.0.0 2024-03-20
 */
@Service
public class SimulatAssessService extends BaseService<SimulatAssessDao, SimulatAssess> {
public class SimulatAssessService  extends BaseService<SimulatAssessDao, SimulatAssess> {
    private static final Logger logger = LoggerFactory.getLogger(SimulatAssessService.class);
    private static final String RELIA_SIM_TASK_TYPE_SIMULATION = "calcreq";
    @Value("${spring.redis.host}")
    private String redisHost;
    @Value("${spring.redis.port}")
    private String redisPort;
    @Value("${data.reliaSimLib.mainPy}")
    private String reliaSimMain;
    @Value("${data.reliaSimLib.resultHome}")
    private String resultHome;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private TaskService taskService;
    @Autowired
    private TaskPhaseService taskPhaseService;
    @Autowired
    private SimulatAssessTaskPhaseModelService simulatAssessTaskPhaseModelService;
    @Autowired
    private TaskPhaseDao taskPhaseDao;
    @Autowired
    private TaskPhaseModelDao taskPhaseModelDao;
    @Autowired
    private OperatConditModelDao operatConditModelDao;
    @Autowired
    private ModelNodeAlgorithmDao modelNodeAlgorithmDao;
    @Autowired
    private AlgorithmDao algorithmDao;
    @Autowired
    private XhProductModelDao xhProductModelDao;
    @Autowired
    private ParamDataDao paramDataDao;
    /**
     * 分页查询
@@ -55,4 +111,401 @@
    public List<ProductStatusDto> getChildren(Long productId, Long taskId) {
        return baseDao.getChildren(productId, taskId);
    }
    @Transactional(rollbackFor = Exception.class)
    public Result simulate(SimulatAssess simulatAssess) {
        Result result = null;
        // 1. 检查模型完整性
        List<TaskModelCheckResult> chkResult = taskService.checkTaskModel(simulatAssess.getProductId(),
                simulatAssess.getTaskModelId());
        if (chkResult.size() > 0) {
            result = Result.error("模型不完整,请检查模型定义及参数配置。");
            return result;
        }
        // 2. 组装供算法库仿真的模型xml
        assembleModelXml(simulatAssess);
        // 3. 调用算法库,进行仿真计算
        result = callReliaSimLib(simulatAssess);
        return result;
    }
    private Result callReliaSimLib(SimulatAssess simulatAssess) {
        Result result = null;
        InputStream is = null;
        BufferedReader br = null;
        try {
            setParamToRedis(simulatAssess);
            Process process = null;
            String command = "python " + reliaSimMain;
            command += " -ip " + redisHost + " -port " + redisPort;
            command += " -taskType " + RELIA_SIM_TASK_TYPE_SIMULATION + " -taskId " + simulatAssess.getId().toString();
            logger.info("cmd命令为:" + command);
            if(System.getProperty("os.name").toLowerCase().indexOf("windows") > -1){
                process = Runtime.getRuntime().exec(new String[]{"cmd", "/c", command});
            }else if(System.getProperty("os.name").toLowerCase().indexOf("linux") > -1){
                process = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", command});
            }else{
                throw new Exception("暂不支持该操作系统,进行启动算法库计算!");
            }
            is = process.getInputStream();
            // 以命令行方式调用算法库时,接口约定返回的结果是utf-8编码
            br = new BufferedReader(new InputStreamReader(is,"utf-8"));
            String line = br.readLine();
            logger.info("算法库返回结果:" + line);
//            int exitCode = process.waitFor(); // 异步方式,不等待算法库计算完毕,所以要注释掉该行
            if (line != null) {
                ReliaSimLibResult rtn = JSONObject.parseObject(line, ReliaSimLibResult.class);
                if ("0".equals(rtn.getCode())) {
                    logger.info("启动算法库成功。");
                    result = Result.ok();
                } else {
                    String errorMsg = rtn.getErrorMsg();
                    throw new RuntimeException("启动算法库失败: errorMsg=" + errorMsg);
                }
            }
        } catch (Exception e) {
            logger.error("启动算法库仿真时发生Exception:", e);
            e.printStackTrace();
            result = Result.error(e.getMessage());
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (br != null) {
                try {
                    br.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }
    private void setParamToRedis(SimulatAssess simulatAssess) {
        String key = simulatAssess.getId().toString() + RELIA_SIM_TASK_TYPE_SIMULATION;
        logger.info("redis key:" + key);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("xmlfile", simulatAssess.getXml());
        // 仿真次数
        jsonObject.put("simulate_times", simulatAssess.getSimulatFrequency());
        // 采样周期
        jsonObject.put("timeslice", simulatAssess.getSamplPeriod()/60.0);   // 单位统一换算为小时
        jsonObject.put("result_home", resultHome);
        jsonObject.put("seed", 1000);
        redisTemplate.opsForValue().set(key, jsonObject.toJSONString());
    }
    private void assembleModelXml(SimulatAssess simulatAssess) {
        Long productId = simulatAssess.getProductId();
        List<XhProductModel> productList = xhProductModelDao.getByShipId(productId);
        List<ParamData> paramDataList = paramDataDao.getDeviceParams(productId);
        Long taskId = simulatAssess.getTaskModelId();
        Task task = taskService.get(taskId);
        // 1. 计算各任务阶段的运行时长
        List<TaskPhase> taskPhases = calcTaskPhaseDuration(task);
        // 2. 计算各工况模型的运行时长
        List<TaskPhaseModel> taskPhaseModelAll = new ArrayList<>();
        for (TaskPhase taskPhase : taskPhases) {
            calcTaskPhaseModelDuration(taskPhase, taskPhaseModelAll);
        }
        // 3. 将各工况模型递归拆解为完整的可供算法包仿真计算的模型
        try {
            List<FailureModel> failureModels = new ArrayList<>();
            List<RepairModel> repairModels = new ArrayList<>();
            Document document = DocumentHelper.createDocument();
            // 添加root节点
            Element root = document.addElement("des");
            root.addAttribute("name", "General system");
            addTasksTag(taskPhaseModelAll, root);
            addModelsTag(productId,
                    productList,
                    paramDataList,
                    taskPhaseModelAll,
                    root,
                    failureModels, repairModels);
            addFailureModelsTag(failureModels, root);
            addRepairModelsTag(repairModels, root);
            saveSimulatAssessTaskPhaseModel(simulatAssess,
                    task,
                    taskPhases,
                    taskPhaseModelAll);
            // 输出格式化xml
            XMLWriter xmlWriter = null;
            try {
                OutputFormat format = OutputFormat.createPrettyPrint();
                format.setEncoding("UTF-8");
                StringWriter writer = new StringWriter();
                xmlWriter = new XMLWriter(writer, format);
                xmlWriter.write(document);
                simulatAssess.setXml(writer.toString());
            } finally {
                if (xmlWriter != null) xmlWriter.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("组装算法库仿真计算用模型XML失败: " + e.getMessage());
        }
    }
    private void saveSimulatAssessTaskPhaseModel(SimulatAssess simulatAssess,
                                                 Task task,
                                                 List<TaskPhase> taskPhases,
                                                 List<TaskPhaseModel> taskPhaseModelAll) {
        int sort = 1;
        for (TaskPhaseModel tpm : taskPhaseModelAll) {
            TaskPhase phase = taskPhases.stream().filter(item ->
                    tpm.getPhaseId().equals(item.getId())).collect(Collectors.toList()).get(0);
            SimulatAssessTaskPhaseModel satpm = new SimulatAssessTaskPhaseModel();
            satpm.setId(UUIDUtil.generateId());
            satpm.setFzId(simulatAssess.getId());
            satpm.setTaskId(task.getId());
            satpm.setTaskName(task.getTaskName());
            satpm.setTaskDuration(task.getTaskDuration());
            satpm.setPhaseId(tpm.getPhaseId());
            satpm.setPhaseName(phase.getPhaseName());
            satpm.setPhaseDurationRate(phase.getPhaseDurationRate());
            satpm.setPhaseDuration(phase.getPhaseDuration());
            satpm.setPhaseConstraint(null); // TODO
            satpm.setGkId(tpm.getOperatConditId());
            satpm.setGkName(tpm.getOperatConditName());
            satpm.setGkDurationRate(tpm.getOperatConditDurationRate());
            satpm.setGkDuration(tpm.getOperatConditDuration());
            satpm.setSort(sort++);
            simulatAssessTaskPhaseModelService.insert(satpm);
        }
    }
    private void addTasksTag(List<TaskPhaseModel> taskPhaseModelAll,
                             Element root) {
        Element tasksTag = root.addElement("tasks");
        for (TaskPhaseModel taskPhaseModel : taskPhaseModelAll) {
            Element taskTag = tasksTag.addElement("task");
            taskTag.addAttribute("duration", String.valueOf(taskPhaseModel.getOperatConditDuration()));
            taskTag.addAttribute("model", taskPhaseModel.getOperatConditId().toString());
        }
    }
    private void addFailureModelsTag(List<FailureModel> failureModels,
                                     Element root) {
        Element ele = null;
        Element failureModelsTag = root.addElement("failure_models");
        for (FailureModel failureModel : failureModels) {
            Element failureModelTag = failureModelsTag.addElement("failure_model");
            failureModelTag.addAttribute("name", failureModel.getId().toString());
            failureModelTag.addAttribute("type", failureModel.getType());
            switch (failureModel.getType()) {
                case FailureModel.TYPE_EXP:
                    ele = failureModelTag.addElement("failure-rate");
                    ele.addAttribute("value", String.valueOf(failureModel.getParam1()));
                    break;
                case FailureModel.TYPE_BIN:
                    ele = failureModelTag.addElement("reliability");
                    ele.addAttribute("value", String.valueOf(failureModel.getParam1()));
                    ele = failureModelTag.addElement("n");
                    ele.addAttribute("value", String.valueOf(failureModel.getParam2()));
                    ele = failureModelTag.addElement("k");
                    ele.addAttribute("value", String.valueOf(failureModel.getParam3()));
                    break;
                case FailureModel.TYPE_WBL:
                    ele = failureModelTag.addElement("scale");
                    ele.addAttribute("value", String.valueOf(failureModel.getParam2()));
                    ele = failureModelTag.addElement("shape");
                    ele.addAttribute("value", String.valueOf(failureModel.getParam3()));
                    break;
                case FailureModel.TYPE_FIX:
                    ele = failureModelTag.addElement("unreliability");
                    ele.addAttribute("value", String.valueOf(failureModel.getParam1()));
                    break;
                default:
                    break;
            }
        }
    }
    private void addRepairModelsTag(List<RepairModel> repairModels,
                                     Element root) {
        Element ele = null;
        Element repairModelsTag = root.addElement("repair_models");
        for (RepairModel repairModel : repairModels) {
            Element repairModelTag = repairModelsTag.addElement("repair_model");
            repairModelTag.addAttribute("name", repairModel.getId().toString());
            repairModelTag.addAttribute("type", repairModel.getType());
            switch (repairModel.getType()) {
                case RepairModel.TYPE_EXP:
                    ele = repairModelTag.addElement("repair-rate");
                    ele.addAttribute("value", String.valueOf(repairModel.getParam1()));
                    break;
                case RepairModel.TYPE_WBL:
                    ele = repairModelTag.addElement("scale");
                    ele.addAttribute("value", String.valueOf(repairModel.getParam2()));
                    ele = repairModelTag.addElement("shape");
                    ele.addAttribute("value", String.valueOf(repairModel.getParam3()));
                    break;
                default:
                    break;
            }
        }
    }
    private void calcTaskPhaseModelDuration(TaskPhase taskPhase,
                                                            List<TaskPhaseModel> taskPhaseModelAll) {
        List<TaskPhaseModel> taskPhaseModels = taskPhaseModelDao.getListByPhaseId(taskPhase.getId());
        double totalRate = taskPhaseModels.stream().mapToDouble(TaskPhaseModel::getOperatConditDurationRate).sum();
        double sum = 0.0;
        for (TaskPhaseModel taskPhaseModel : taskPhaseModels) {
            double duration = taskPhaseModel.getOperatConditDurationRate() * taskPhase.getPhaseDuration() / totalRate;
            taskPhaseModel.setOperatConditDuration(duration);
            sum += duration;
            taskPhaseModelAll.add(taskPhaseModel);
        }
        // 把零头补到最后一个工况模型
        taskPhaseModels.get(taskPhaseModels.size()-1).setOperatConditDuration(totalRate - sum);
    }
    private List<TaskPhase> calcTaskPhaseDuration(Task task) {
        List<TaskPhase> taskPhases = taskPhaseDao.getListByTaskId(task.getId());
        double totalRate = taskPhases.stream().mapToDouble(TaskPhase::getPhaseDurationRate).sum();
        double sum = 0.0;
        for (TaskPhase taskPhase : taskPhases) {
            double duration = task.getTaskDuration() * taskPhase.getPhaseDurationRate() / totalRate;
            taskPhase.setPhaseDuration(duration);
            sum += duration;
        }
        // 把零头补到最后一个阶段
        taskPhases.get(taskPhases.size()-1).setPhaseDuration(task.getTaskDuration() - sum);
        return taskPhases;
    }
    private void addModelsTag(Long productId,
                              List<XhProductModel> productList,
                              List<ParamData> paramDataList,
                              List<TaskPhaseModel> taskPhaseModelAll,
                              Element root,
                              List<FailureModel> failureModels,
                              List<RepairModel> repairModels) {
        Element modelsTag = root.addElement("models");
        for (TaskPhaseModel taskPhaseModel : taskPhaseModelAll) {
            Element modelTag = modelsTag.addElement("model");
            modelTag.addAttribute("name", taskPhaseModel.getOperatConditId().toString());
            List<OperatConditModel> gkModelsAssembled = operatConditModelDao.getGKModelAssembled(
                    taskPhaseModel.getOperatConditId());
            OperatConditModel gkModelTop = gkModelsAssembled.stream().filter(item ->
                    productId.equals(item.getProductId())).collect(Collectors.toList()).get(0);
            List<ModelNode> modelNodeAndVnodeList = modelNodeAlgorithmDao.getListByModelId(gkModelTop.getModelId());
            List<Algorithm> algorithmList = algorithmDao.getListByModelId(gkModelTop.getModelId());
            // 将模型转换为DOM,添加到model标签
            Algorithm endAlgo = algorithmList.stream().filter(item ->
                    "end".equals(item.getAlgorithmType())).collect(Collectors.toList()).get(0);
            ModelNode computerNode = modelNodeAndVnodeList.stream().filter(item ->
                    endAlgo.getComputerList().equals(item.getId().toString())).collect(Collectors.toList()).get(0);
            node2DOM(productList,
                    paramDataList,
                    gkModelsAssembled,
                    algorithmList,
                    modelNodeAndVnodeList,
                    computerNode, modelTag,
                    failureModels, repairModels);
        }
    }
    // 递归函数
    private void node2DOM(List<XhProductModel> productList,
                          List<ParamData> paramDataList,
                          List<OperatConditModel> gkModelsAssembled,
                          List<Algorithm> algorithmList,
                          List<ModelNode> modelNodeAndVnodeList,
                          ModelNode node,
                          Element parent,
                          List<FailureModel> failureModels,
                          List<RepairModel> repairModels) {
        if ("node".equals(node.getNodeType())) {
            Long dataId = node.getDataId();
            XhProductModel product = productList.stream().filter(item ->
                    dataId.equals(item.getId())).collect(Collectors.toList()).get(0);
            if ("3,4,10".equals(product.getProductType())) {
                // 系统、分系统、虚单元
                OperatConditModel gkModel = gkModelsAssembled.stream().filter(item ->
                        dataId.equals(item.getProductId())).collect(Collectors.toList()).get(0);
                List<Algorithm> algorithmListSub = algorithmDao.getListByModelId(gkModel.getModelId());
                List<ModelNode> modelNodeAndVnodeListSub = modelNodeAlgorithmDao.getListByModelId(gkModel.getModelId());
                Algorithm endAlgo = algorithmListSub.stream().filter(item ->
                        "end".equals(item.getAlgorithmType())).collect(Collectors.toList()).get(0);
                ModelNode computerNode = modelNodeAndVnodeListSub.stream().filter(item ->
                        endAlgo.getComputerList().equals(item.getId().toString())).collect(Collectors.toList()).get(0);
                node2DOM(productList,
                        paramDataList,
                        gkModelsAssembled,
                        algorithmListSub,
                        modelNodeAndVnodeListSub,
                        computerNode, parent,
                        failureModels, repairModels);
            } else if ("5".equals(product.getProductType())) {
                // 设备
                ParamData paramData = paramDataList.stream().filter(item ->
                        dataId.equals(item.getProductId())).collect(Collectors.toList()).get(0);
                Element nodeTag = parent.addElement("node");
                nodeTag.addAttribute("name", dataId.toString());
                nodeTag.addAttribute("type", "node");
                FailureModel failureModel = new FailureModel();
                failureModel.setId(UUIDUtil.generateId());
                failureModel.setType(FailureModel.TYPE_EXP);
                failureModel.setParam1(1.0 / paramData.getTaskMtbcfRegulate());
                failureModels.add(failureModel);
                Element failureTag = nodeTag.addElement("failure_model");
                failureTag.addAttribute("name", failureModel.getId().toString());
                if (1 == paramData.getRepairable()) {
                    RepairModel repairModel = new RepairModel();
                    repairModel.setId(UUIDUtil.generateId());
                    repairModel.setType(RepairModel.TYPE_EXP);
                    repairModel.setParam1(1.0 / paramData.getRepairMttcr());
                    repairModels.add(repairModel);
                    Element repairTag = nodeTag.addElement("repair_model");
                    repairTag.addAttribute("name", repairModel.getId().toString());
                }
            }
        } else {
            // vnode(运算节点)
            Algorithm algo = algorithmList.stream().filter(item ->
                    node.getId().equals(item.getId())).collect(Collectors.toList()).get(0);
            Element element = parent.addElement("logic");
            element.addAttribute("name", algo.getId().toString());
            if ("series".equals(algo.getAlgorithmType())) {
                element.addAttribute("type", "series");
            } else if ("parallel".equals(algo.getAlgorithmType())) {
                element.addAttribute("type", "parallel");
            } else if ("vote".equals(algo.getAlgorithmType())) {
                element.addAttribute("type", "vote");
                element.addAttribute("k", algo.getVoteNum().toString());
            } else if ("switch".equals(algo.getAlgorithmType())) {
                element.addAttribute("type", "standby");
            } else if ("bridge".equals(algo.getAlgorithmType())) {
                element.addAttribute("type", "bridge");
            }
            String[] computerNodeListStr = algo.getComputerList().split(",");
            for (String nodeStr : computerNodeListStr) {
                ModelNode md = modelNodeAndVnodeList.stream().filter(item ->
                        nodeStr.equals(item.getId().toString())).collect(Collectors.toList()).get(0);
                node2DOM(productList,
                        paramDataList,
                        gkModelsAssembled,
                        algorithmList,
                        modelNodeAndVnodeList,
                        md, element,
                        failureModels, repairModels);
            }
        }
    }
}