From 34ca4bd5256b8e52cd89fe25b3421ca2a8127fab Mon Sep 17 00:00:00 2001 From: rakhimov Date: Wed, 9 Aug 2017 23:15:29 -0700 Subject: [PATCH] Add Alignment and Phase classes Issue #153 --- src/CMakeLists.txt | 1 + src/alignment.cc | 49 +++++++++++++++++++++ src/alignment.h | 93 ++++++++++++++++++++++++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/alignment_tests.cc | 78 +++++++++++++++++++++++++++++++++ 5 files changed, 222 insertions(+) create mode 100644 src/alignment.cc create mode 100644 src/alignment.h create mode 100644 tests/alignment_tests.cc diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9457a3a502..393d68b72b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,6 +42,7 @@ set(SCRAM_CORE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/ccf_group.cc" "${CMAKE_CURRENT_SOURCE_DIR}/fault_tree.cc" "${CMAKE_CURRENT_SOURCE_DIR}/event_tree.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/alignment.cc" "${CMAKE_CURRENT_SOURCE_DIR}/model.cc" "${CMAKE_CURRENT_SOURCE_DIR}/pdag.cc" "${CMAKE_CURRENT_SOURCE_DIR}/preprocessor.cc" diff --git a/src/alignment.cc b/src/alignment.cc new file mode 100644 index 0000000000..b862298305 --- /dev/null +++ b/src/alignment.cc @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2017 Olzhas Rakhimov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/// @file alignment.cc +/// Implementation of alignment and phase classes. + +#include "alignment.h" + +#include "error.h" + +namespace scram { +namespace mef { + +Phase::Phase(std::string name, double time_fraction) + : Element(std::move(name)), time_fraction_(time_fraction) { + if (time_fraction_ <= 0 || time_fraction_ > 1) + throw InvalidArgument("The phase fraction must be in (0, 1]."); +} + +void Alignment::Add(PhasePtr phase) { + AddElement(std::move(phase), &phases_, + "Duplicate phase: "); +} + +void Alignment::Validate() { + double sum = 0; + for (const PhasePtr& phase : phases_) + sum += phase->time_fraction(); + if (sum != 1) + throw ValidationError("The phases of alignment '" + Element::name() + + "' do not sum to 1."); +} + +} // namespace mef +} // namespace scram diff --git a/src/alignment.h b/src/alignment.h new file mode 100644 index 0000000000..60add3585e --- /dev/null +++ b/src/alignment.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2017 Olzhas Rakhimov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/// @file alignment.h +/// Mission and phase constructs. + +#ifndef SCRAM_SRC_ALIGNMENT_H_ +#define SCRAM_SRC_ALIGNMENT_H_ + +#include +#include +#include + +#include + +#include "element.h" +#include "instruction.h" + +namespace scram { +namespace mef { + +/// Phases of alignments the models spends its time fraction. +class Phase : public Element, private boost::noncopyable { + public: + /// @copydoc Element::Element + /// + /// @param[in] time_fraction The fraction of mission-time spent in the phase. + /// + /// @throws InvalidArgument The fraction is not a valid value in (0, 1]. + Phase(std::string name, double time_fraction); + + /// @returns The positive fraction of mission-time spent in this phase. + double time_fraction() const { return time_fraction_; } + + /// @returns The instructions applied in this phase. + const std::vector& instructions() const { + return instructions_; + } + + /// @param[in] instructions Zero or more instructions for this phase. + void instructions(std::vector instructions) { + instructions_ = std::move(instructions); + } + + public: + double time_fraction_; ///< The positive fraction of the mission time. + std::vector instructions_; ///< The phase modifiers. +}; + +using PhasePtr = std::unique_ptr; ///< Phases are unique to alignments. + +/// Alignment configuration for the whole model per analysis. +class Alignment : public Element, private boost::noncopyable { + public: + using Element::Element; + + /// @returns The phases defined in the alignment. + const ElementTable& phases() const { return phases_; } + + /// Adds a phase into alignment. + /// + /// @param[in] phase One of the unique phases for the alignment. + /// + /// @throws DuplicateArgumentError The phase is duplicate. + void Add(PhasePtr phase); + + /// Ensures that all phases add up to be valid for the alignment. + /// + /// @throws ValidationError Phases are incomplete (e.g., don't sum to 1). + void Validate(); + + private: + ElementTable phases_; ///< The partitioning of the alignment. +}; + +} // namespace mef +} // namespace scram + +#endif // SCRAM_SRC_ALIGNMENT_H_ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index febd9d35e7..b275e282f5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -25,6 +25,7 @@ set(SCRAM_CORE_TEST_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/expression_tests.cc" "${CMAKE_CURRENT_SOURCE_DIR}/ccf_group_tests.cc" "${CMAKE_CURRENT_SOURCE_DIR}/fault_tree_tests.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/alignment_tests.cc" "${CMAKE_CURRENT_SOURCE_DIR}/pdag_tests.cc" "${CMAKE_CURRENT_SOURCE_DIR}/initializer_tests.cc" "${CMAKE_CURRENT_SOURCE_DIR}/risk_analysis_tests.cc" diff --git a/tests/alignment_tests.cc b/tests/alignment_tests.cc new file mode 100644 index 0000000000..35263005af --- /dev/null +++ b/tests/alignment_tests.cc @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2017 Olzhas Rakhimov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "alignment.h" + +#include + +#include "error.h" + +namespace scram { +namespace mef { +namespace test { + +TEST(PhaseTest, TimeFraction) { + EXPECT_NO_THROW(Phase("phase", 0.5)); + EXPECT_NO_THROW(Phase("phase", 0.1)); + EXPECT_NO_THROW(Phase("phase", 1)); + + EXPECT_THROW(Phase("phase", 0), InvalidArgument); + EXPECT_THROW(Phase("phase", 1.1), InvalidArgument); + EXPECT_THROW(Phase("phase", -0.1), InvalidArgument); +} + +TEST(AlignmentTest, AddPhase) { + Alignment alignment("mission"); + auto phase_one = std::make_unique("one", 0.5); + auto phase_two = std::make_unique("one", 0.1); // Duplicate name. + auto phase_three = std::make_unique("three", 0.1); + + EXPECT_TRUE(alignment.phases().empty()); + auto* phase_one_address = phase_one.get(); + ASSERT_NO_THROW(alignment.Add(std::move(phase_one))); + EXPECT_EQ(1, alignment.phases().size()); + EXPECT_EQ(phase_one_address, alignment.phases().begin()->get()); + + EXPECT_THROW(alignment.Add(std::move(phase_two)), DuplicateArgumentError); + EXPECT_EQ(1, alignment.phases().size()); + EXPECT_EQ(phase_one_address, alignment.phases().begin()->get()); + + ASSERT_NO_THROW(alignment.Add(std::move(phase_three))); + EXPECT_EQ(2, alignment.phases().size()); +} + +TEST(AlignmentTest, Validation) { + Alignment alignment("mission"); + auto phase_one = std::make_unique("one", 0.5); + auto phase_two = std::make_unique("two", 0.5); + auto phase_three = std::make_unique("three", 0.1); + + EXPECT_THROW(alignment.Validate(), ValidationError); + + ASSERT_NO_THROW(alignment.Add(std::move(phase_one))); + EXPECT_THROW(alignment.Validate(), ValidationError); + + ASSERT_NO_THROW(alignment.Add(std::move(phase_two))); + EXPECT_NO_THROW(alignment.Validate()); + + ASSERT_NO_THROW(alignment.Add(std::move(phase_three))); + EXPECT_THROW(alignment.Validate(), ValidationError); +} + +} // namespace test +} // namespace mef +} // namespace scram