diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake
index 51372468d..f4aa0dec2 100644
--- a/CMakeLists_files.cmake
+++ b/CMakeLists_files.cmake
@@ -90,6 +90,7 @@ list (APPEND MAIN_SOURCE_FILES
opm/simulators/flow/BlackoilModelParameters.cpp
opm/simulators/flow/BlackoilModelConvergenceMonitor.cpp
opm/simulators/flow/CollectDataOnIORank.cpp
+ opm/simulators/flow/CompositionalContainer.cpp
opm/simulators/flow/ConvergenceOutputConfiguration.cpp
opm/simulators/flow/EclGenericWriter.cpp
opm/simulators/flow/ExtboContainer.cpp
@@ -821,6 +822,7 @@ list (APPEND PUBLIC_HEADER_FILES
opm/simulators/flow/BlackoilModelProperties.hpp
opm/simulators/flow/CollectDataOnIORank.hpp
opm/simulators/flow/CollectDataOnIORank_impl.hpp
+ opm/simulators/flow/CompositionalContainer.hpp
opm/simulators/flow/ConvergenceOutputConfiguration.hpp
opm/simulators/flow/countGlobalCells.hpp
opm/simulators/flow/CpGridVanguard.hpp
diff --git a/opm/simulators/flow/CompositionalContainer.cpp b/opm/simulators/flow/CompositionalContainer.cpp
new file mode 100644
index 000000000..28135641d
--- /dev/null
+++ b/opm/simulators/flow/CompositionalContainer.cpp
@@ -0,0 +1,183 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/*
+ This file is part of the Open Porous Media project (OPM).
+
+ OPM 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 2 of the License, or
+ (at your option) any later version.
+
+ OPM 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 OPM. If not, see .
+ Consult the COPYING file in the top-level source directory of this
+ module for the precise wording of the license and the list of
+ copyright holders.
+*/
+
+#include
+#include
+
+#include
+
+#include
+
+#include
+#include
+
+#include
+
+namespace Opm {
+
+template
+void CompositionalContainer::
+allocate(const unsigned bufferSize,
+ std::map& rstKeywords)
+{
+ if (auto& zmf = rstKeywords["ZMF"]; zmf > 0) {
+ this->allocated_ = true;
+ zmf = 0;
+ for (int i = 0; i < numComponents; ++i) {
+ moleFractions_[i].resize(bufferSize, 0.0);
+ }
+ }
+
+ if (auto& xmf = rstKeywords["XMF"]; xmf > 0 && FluidSystem::phaseIsActive(oilPhaseIdx)) {
+ this->allocated_ = true;
+ xmf = 0;
+ for (int i = 0; i < numComponents; ++i) {
+ phaseMoleFractions_[oilPhaseIdx][i].resize(bufferSize, 0.0);
+ }
+ }
+
+ if (auto& ymf = rstKeywords["YMF"]; ymf > 0 && FluidSystem::phaseIsActive(gasPhaseIdx)) {
+ this->allocated_ = true;
+ ymf = 0;
+ for (int i = 0; i < numComponents; ++i) {
+ phaseMoleFractions_[gasPhaseIdx][i].resize(bufferSize, 0.0);
+ }
+ }
+}
+
+template
+void CompositionalContainer::
+assignGasFractions(const unsigned globalDofIdx,
+ const AssignFunction& fractions)
+{
+ if (phaseMoleFractions_[gasPhaseIdx][0].empty()) {
+ return;
+ }
+
+ std::for_each(phaseMoleFractions_[gasPhaseIdx].begin(),
+ phaseMoleFractions_[gasPhaseIdx].end(),
+ [globalDofIdx, &fractions, c = 0](auto& comp) mutable
+ { comp[globalDofIdx] = fractions(c++); });
+}
+
+template
+void CompositionalContainer::
+assignMoleFractions(const unsigned globalDofIdx,
+ const AssignFunction& fractions)
+{
+ if (moleFractions_.empty()) {
+ return;
+ }
+
+ std::for_each(moleFractions_.begin(), moleFractions_.end(),
+ [&fractions, globalDofIdx, c = 0](auto& comp) mutable
+ { comp[globalDofIdx] = fractions(c++); });
+}
+
+template
+void CompositionalContainer::
+assignOilFractions(const unsigned globalDofIdx,
+ const AssignFunction& fractions)
+{
+ if (phaseMoleFractions_[oilPhaseIdx][0].empty()) {
+ return;
+ }
+
+ std::for_each(phaseMoleFractions_[oilPhaseIdx].begin(),
+ phaseMoleFractions_[oilPhaseIdx].end(),
+ [globalDofIdx, &fractions, c = 0](auto& comp) mutable
+ { comp[globalDofIdx] = fractions(c++); });
+}
+
+template
+void CompositionalContainer::
+outputRestart(data::Solution& sol,
+ ScalarBuffer& oil_saturation)
+{
+ using DataEntry =
+ std::tuple&>;
+
+ auto doInsert = [&sol](DataEntry& entry,
+ const data::TargetType target)
+ {
+ if (std::get<2>(entry).empty()) {
+ return;
+ }
+
+ sol.insert(std::get(entry),
+ std::get(entry),
+ std::move(std::get<2>(entry)),
+ target);
+ };
+
+ auto entries = std::vector{};
+
+ // ZMF
+ if (!moleFractions_[0].empty()) {
+ for (int i = 0; i < numComponents; ++i) {
+ const auto name = fmt::format("ZMF{}", i + 1); // Generate ZMF1, ZMF2, ...
+ entries.emplace_back(name, UnitSystem::measure::identity, moleFractions_[i]);
+ }
+ }
+
+ // XMF
+ if (!phaseMoleFractions_[oilPhaseIdx][0].empty()) {
+ for (int i = 0; i < numComponents; ++i) {
+ const auto name = fmt::format("XMF{}", i + 1); // Generate XMF1, XMF2, ...
+ entries.emplace_back(name, UnitSystem::measure::identity,
+ phaseMoleFractions_[oilPhaseIdx][i]);
+ }
+ }
+
+ // YMF
+ if (!phaseMoleFractions_[gasPhaseIdx][0].empty()) {
+ for (int i = 0; i < numComponents; ++i) {
+ const auto name = fmt::format("YMF{}", i + 1); // Generate YMF1, YMF2, ...
+ entries.emplace_back(name, UnitSystem::measure::identity,
+ phaseMoleFractions_[gasPhaseIdx][i]);
+ }
+ }
+
+ if (!oil_saturation.empty()) {
+ entries.emplace_back("SOIL", UnitSystem::measure::identity, oil_saturation);
+ }
+
+ std::for_each(entries.begin(), entries.end(),
+ [&doInsert](auto& array)
+ { doInsert(array, data::TargetType::RESTART_SOLUTION); });
+
+ this->allocated_ = false;
+}
+
+#define INSTANTIATE_COMP(NUM) \
+ template using FS##NUM = GenericOilGasFluidSystem; \
+ template class CompositionalContainer>;
+
+INSTANTIATE_COMP(0)
+INSTANTIATE_COMP(2)
+INSTANTIATE_COMP(3)
+INSTANTIATE_COMP(4)
+INSTANTIATE_COMP(5)
+INSTANTIATE_COMP(6)
+INSTANTIATE_COMP(7)
+
+} // namespace Opm
diff --git a/opm/simulators/flow/CompositionalContainer.hpp b/opm/simulators/flow/CompositionalContainer.hpp
new file mode 100644
index 000000000..67a9ca4f9
--- /dev/null
+++ b/opm/simulators/flow/CompositionalContainer.hpp
@@ -0,0 +1,83 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/*
+ This file is part of the Open Porous Media project (OPM).
+
+ OPM 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 2 of the License, or
+ (at your option) any later version.
+
+ OPM 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 OPM. If not, see .
+ Consult the COPYING file in the top-level source directory of this
+ module for the precise wording of the license and the list of
+ copyright holders.
+*/
+/*!
+ * \file
+ * \copydoc Opm::OutputBlackOilModule
+ */
+#ifndef OPM_COMPOSITIONAL_CONTAINER_HPP
+#define OPM_COMPOSITIONAL_CONTAINER_HPP
+
+#include
+#include
+#include