From 6c76a45d3f860eb90c2712166b4174b4cd8d93e1 Mon Sep 17 00:00:00 2001 From: Bogdan Kostov Date: Wed, 19 Jun 2024 10:01:11 +0200 Subject: [PATCH] [Fix #116] Implement fault tree evaluation using operational data and operational data filter - Add BaseRepositoryService.getToolContext to get aa FTA tool specific context for a given URI. This is used to generate an FTA tool specific context for a given system uri where the tool can store all system related entities created by the tool, e.g. global operational failure rate estimates, system specific operational data filters. --- .../analysis/dao/FailureRateEstimateDao.java | 28 ++++++ .../cvut/kbss/analysis/dao/FaultEventDao.java | 6 ++ .../service/BaseRepositoryService.java | 7 ++ .../service/FaultTreeRepositoryService.java | 85 +++++++++++++------ .../service/OperationalDataFilterService.java | 2 +- 5 files changed, 102 insertions(+), 26 deletions(-) create mode 100644 src/main/java/cz/cvut/kbss/analysis/dao/FailureRateEstimateDao.java diff --git a/src/main/java/cz/cvut/kbss/analysis/dao/FailureRateEstimateDao.java b/src/main/java/cz/cvut/kbss/analysis/dao/FailureRateEstimateDao.java new file mode 100644 index 00000000..5b6dfa13 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/analysis/dao/FailureRateEstimateDao.java @@ -0,0 +1,28 @@ +package cz.cvut.kbss.analysis.dao; + +import cz.cvut.kbss.analysis.config.conf.PersistenceConf; +import cz.cvut.kbss.analysis.model.FailureRateEstimate; +import cz.cvut.kbss.analysis.service.IdentifierService; +import cz.cvut.kbss.analysis.util.Vocabulary; +import cz.cvut.kbss.jopa.model.EntityManager; +import org.springframework.stereotype.Repository; + +import java.net.URI; + +@Repository +public class FailureRateEstimateDao extends BaseDao{ + protected final static URI HAS_ESTIMATE_PROP = URI.create(Vocabulary.s_p_has_estimate); + protected final static URI VALUE_PROP = URI.create(Vocabulary.s_p_value); + + public FailureRateEstimateDao(EntityManager em, PersistenceConf config, IdentifierService identifierService) { + super(FailureRateEstimate.class, em, config, identifierService); + } + + public void setHasEstimate(URI failureRateUri, FailureRateEstimate estimate, URI context) { + addOrReplaceValue(failureRateUri, HAS_ESTIMATE_PROP, estimate.getUri(), context); + } + + public void setValue(URI failureRateEstimateUri, Double value, URI context) { + addOrReplaceValue(failureRateEstimateUri, VALUE_PROP, value, context); + } +} diff --git a/src/main/java/cz/cvut/kbss/analysis/dao/FaultEventDao.java b/src/main/java/cz/cvut/kbss/analysis/dao/FaultEventDao.java index 253eca24..834130a4 100755 --- a/src/main/java/cz/cvut/kbss/analysis/dao/FaultEventDao.java +++ b/src/main/java/cz/cvut/kbss/analysis/dao/FaultEventDao.java @@ -17,6 +17,8 @@ @Repository public class FaultEventDao extends NamedEntityDao { + public static final URI PROBABILITY_PROP = URI.create(Vocabulary.s_p_probability); + @Autowired protected FaultEventDao(EntityManager em, PersistenceConf config, IdentifierService identifierService) { super(FaultEvent.class, em, config, identifierService); @@ -52,6 +54,10 @@ protected EntityDescriptor getEntityDescriptorInContext(URI graph){ return entityDescriptor; } + public void setProbability(URI faultEventUri, Double probability, URI context){ + addOrReplaceValue(faultEventUri, PROBABILITY_PROP, probability, context); + } + public EntityDescriptor getRectangleDescriptor(URI uri){ URI graph = getContext(uri); EntityDescriptor entityDescriptor = new EntityDescriptor(graph); diff --git a/src/main/java/cz/cvut/kbss/analysis/service/BaseRepositoryService.java b/src/main/java/cz/cvut/kbss/analysis/service/BaseRepositoryService.java index 458f0c6d..d2323357 100755 --- a/src/main/java/cz/cvut/kbss/analysis/service/BaseRepositoryService.java +++ b/src/main/java/cz/cvut/kbss/analysis/service/BaseRepositoryService.java @@ -271,4 +271,11 @@ protected void validate(T instance) { } } + public URI getToolContext(URI uri){ + return getToolContext(uri.toString()); + } + + public URI getToolContext(String uri){ + return URI.create(uri + "-jopa"); + } } diff --git a/src/main/java/cz/cvut/kbss/analysis/service/FaultTreeRepositoryService.java b/src/main/java/cz/cvut/kbss/analysis/service/FaultTreeRepositoryService.java index 67bd39ea..296972a4 100755 --- a/src/main/java/cz/cvut/kbss/analysis/service/FaultTreeRepositoryService.java +++ b/src/main/java/cz/cvut/kbss/analysis/service/FaultTreeRepositoryService.java @@ -3,6 +3,7 @@ import cz.cvut.kbss.analysis.dao.*; import cz.cvut.kbss.analysis.exception.EntityNotFoundException; import cz.cvut.kbss.analysis.model.*; +import cz.cvut.kbss.analysis.model.ava.ATASystem; import cz.cvut.kbss.analysis.model.ava.FHAEventType; import cz.cvut.kbss.analysis.model.diagram.Rectangle; import cz.cvut.kbss.analysis.model.fta.CutSetExtractor; @@ -45,7 +46,7 @@ public class FaultTreeRepositoryService extends ComplexManagedEntityRepositorySe private final FailureModeDao failureModeDao; private final OperationalDataService operationalDataService; private final FaultEventTypeService faultEventTypeService; - private final FaultEventTypeDao faultEventTypeDao; + private final FailureRateEstimateDao failureRateEstimateDao; @Autowired public FaultTreeRepositoryService(@Qualifier("defaultValidator") Validator validator, @@ -61,7 +62,7 @@ public FaultTreeRepositoryService(@Qualifier("defaultValidator") Validator valid FailureModeDao failureModeDao, OperationalDataService operationalDataService, FaultEventTypeService faultEventTypeService, - FaultEventTypeDao faultEventTypeDao) { + FailureRateEstimateDao failureRateEstimateDao) { super(validator, userDao, securityUtils); this.faultTreeDao = faultTreeDao; this.faultEventScenarioDao = faultEventScenarioDao; @@ -73,7 +74,7 @@ public FaultTreeRepositoryService(@Qualifier("defaultValidator") Validator valid this.failureModeDao = failureModeDao; this.operationalDataService = operationalDataService; this.faultEventTypeService = faultEventTypeService; - this.faultEventTypeDao = faultEventTypeDao; + this.failureRateEstimateDao = failureRateEstimateDao; } @Override @@ -547,14 +548,43 @@ public FaultTree evaluate(URI faultTreeUri, OperationalDataFilter filter) { return evaluate(faultTree); } - protected void updateFaultTreeOperationalFailureRates(FaultTree faultTree, OperationalDataFilter filter){ + /** + * Updates the provided fault tree sns' failures with operational failure rate calculated based on filter. The update + * is reflected in the persistent storage and in the input fault tree. + * + * The procedure can be summarized as follows: + * 1. Extracts sns failures from input fault tree + * 2. Fetches operational failure rate taking based on provided filter for sns failures in the supplied faultTree + * 3. Updates operational estimates of sns failures in the provided tree + * 4. Updates fault event probabilities of sns fault events which have selected operational failure rate. + * + * @param faultTree + * @param filter + */ + @Transactional + public void updateFaultTreeOperationalFailureRates(FaultTree faultTree, OperationalDataFilter filter) { URI faultTreeUri = faultTree.getUri(); // fetch get map between SNS component uris and fault events which will store the calculated failure rate Map> map = new HashMap<>(); faultTree.getAllEvents().stream() .filter(e -> e.getEventType() == FtaEventType.BASIC && e.getSupertypes() != null && !e.getSupertypes().isEmpty()) - .flatMap(e -> e.getSupertypes().stream().map(t -> Pair.of(e,t))).forEach(p -> { - URI componentURI = Optional.ofNullable(p.getFirst().getBehavior()) + .flatMap(e -> e.getSupertypes().stream().map(t -> { + Event type = null; + + if(t.getSupertypes() != null) { + type = t.getSupertypes().stream() + .filter(st -> Optional.ofNullable(st.getBehavior()) + .map(b -> b.getItem() instanceof ATASystem) + .isPresent()).findFirst().orElse(null); + } + + // TODO - workaround - using system specific event when general ROLE event is missing. + if(type == null) + type = t; + + return Pair.of(e, type); + })).forEach(p -> { + URI componentURI = Optional.ofNullable(p.getSecond().getBehavior()) .map(b -> b.getItem()) .map(i -> i.getUri()) .orElse(null); @@ -562,35 +592,40 @@ protected void updateFaultTreeOperationalFailureRates(FaultTree faultTree, Opera map.put(componentURI, p); }); + if (map.isEmpty()) + return; + ItemFailureRate[] operationalFailureRateEstimates = operationalDataService.fetchFailureRates(filter, map.keySet()); + URI systemContext = getToolContext(faultTree.getSystem().getUri()); for(ItemFailureRate estimate : operationalFailureRateEstimates){ if(estimate.getFailureRate() == null) continue; Pair p = map.get(estimate.getUri()); FaultEvent ft = p.getFirst(); + FailureRate fr = ((FaultEventType)p.getSecond()).getFailureRate(); - FaultEventType evt = (FaultEventType) p.getSecond(); - FailureRateEstimate frEstimate = evt.getFailureRate().getEstimate(); - if(frEstimate == null){ - frEstimate = new FailureRateEstimate(); - evt.getFailureRate().setEstimate(frEstimate); - } - - evt.getFailureRate().getEstimate().setValue(estimate.getFailureRate()); - - evt.getFailureRate().setContext(faultTreeUri); - faultEventTypeDao.update(evt); - - if(ft.getSelectedEstimate() != null && - ft.getSelectedEstimate().getUri() != null && - ft.getSelectedEstimate().getUri().equals(frEstimate.getUri())) { + updateOperationalFailureRate(systemContext, faultTreeUri, estimate, ft, fr); + } + } - ft.setProbability(frEstimate.getValue()); + protected void updateOperationalFailureRate(URI systemContext, URI faultTreeUri, ItemFailureRate estimate, FaultEvent ft, FailureRate fr){ + FailureRateEstimate frEstimate = fr.getEstimate(); + if(frEstimate == null) { + frEstimate = new FailureRateEstimate(); + frEstimate.setValue(estimate.getFailureRate()); + frEstimate.setContext(systemContext); + failureRateEstimateDao.persist(frEstimate); + failureRateEstimateDao.setHasEstimate(fr.getUri(), frEstimate, systemContext); + fr.setEstimate(frEstimate); + }else{ + frEstimate.setValue(estimate.getFailureRate()); + failureRateEstimateDao.setValue(frEstimate.getUri(), estimate.getFailureRate(), systemContext); + } - ft.setContext(faultTreeUri); - faultEventDao.update(ft); - } + if(ft.getSelectedEstimate() != null && ft.getSelectedEstimate().equals(frEstimate.getUri())) { + ft.setProbability(frEstimate.getValue()); + faultEventDao.setProbability(ft.getUri(), frEstimate.getValue(), faultTreeUri); } } diff --git a/src/main/java/cz/cvut/kbss/analysis/service/OperationalDataFilterService.java b/src/main/java/cz/cvut/kbss/analysis/service/OperationalDataFilterService.java index bdabacd2..56617cae 100644 --- a/src/main/java/cz/cvut/kbss/analysis/service/OperationalDataFilterService.java +++ b/src/main/java/cz/cvut/kbss/analysis/service/OperationalDataFilterService.java @@ -73,7 +73,7 @@ public OperationalDataFilter getFaultTreeFilter(URI faultTreeURI, URI systemURI) @Transactional public void updateSystemFilter(URI systemURI, OperationalDataFilter newFilter){ - URI context = URI.create(systemURI.toString() + "-jopa"); + URI context = getToolContext(systemURI); updateFilter(systemURI, newFilter, context); }