Skip to content

Commit

Permalink
Added a process factory to be used by custom workflows (in C++)
Browse files Browse the repository at this point in the history
The factory first needs to be populated with creators for concrete
process types that need to be produced. On request, it will produce a
smart pointer to a `Process` instance, thereby supplying a uniform and
consistent interface to the processes.

This commit includes the implementation of the factory and a set of unit
tests. The actual usage by a custom workflow will be part of another
commit.
  • Loading branch information
avdg81 committed Sep 13, 2023
1 parent b22f60b commit a4592db
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// KRATOS___
// // ) )
// // ___ ___
// // ____ //___) ) // ) )
// // / / // // / /
// ((____/ / ((____ ((___/ / MECHANICS
//
// License: geo_mechanics_application/license.txt
//
// Main authors: Wijtze Pieter Kikstra
// Anne van de Graaf
//

#include "custom_utilities/process_factory.hpp"
#include "includes/kratos_parameters.h"


namespace Kratos
{

ProcessFactory::ProductType ProcessFactory::Create(const std::string& rProcessClassName,
const Parameters& rProcessSettings) const
{
auto pos = mCreatorMap.find(rProcessClassName);
if (pos == mCreatorMap.end()) {
return nullptr;
}

return pos->second ? pos->second(rProcessSettings) : nullptr;
}

void ProcessFactory::AddCreator(const std::string& rProcessClassName,
std::function<ProductType(const Parameters&)> Creator)
{
mCreatorMap[rProcessClassName] = std::move(Creator);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// KRATOS___
// // ) )
// // ___ ___
// // ____ //___) ) // ) )
// // / / // // / /
// ((____/ / ((____ ((___/ / MECHANICS
//
// License: geo_mechanics_application/license.txt
//
// Main authors: Wijtze Pieter Kikstra
// Anne van de Graaf
//

#pragma once

#include "processes/process.h"

#include <map>
#include <memory>
#include <string>


namespace Kratos
{

class Parameters;

class ProcessFactory
{
public:
using ProductType = std::unique_ptr<Process>;

[[nodiscard]] ProductType Create(const std::string& rProcessClassName,
const Parameters& rProcessSettings) const;
void AddCreator(const std::string& rProcessClassName,
std::function<ProductType(const Parameters&)> Creator);

private:
std::map<std::string, std::function<ProductType(const Parameters&)>, std::less<>> mCreatorMap;
};

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// KRATOS___
// // ) )
// // ___ ___
// // ____ //___) ) // ) )
// // / / // // / /
// ((____/ / ((____ ((___/ / MECHANICS
//
// License: geo_mechanics_application/license.txt
//
// Main authors: Wijtze Pieter Kikstra
// Anne van de Graaf
//

#include "testing/testing.h"
#include "custom_utilities/process_factory.hpp"

using namespace Kratos;


namespace
{

class FooProcess : public Process
{
};

class BarProcess : public Process
{
};

}


namespace Kratos::Testing
{

KRATOS_TEST_CASE_IN_SUITE(CreateNothingWhenNoCreatorWasAddedForRequestedProcess, KratosGeoMechanicsFastSuite)
{
ProcessFactory factory;

const Parameters process_settings;
const auto process = factory.Create("UnknownProcess", process_settings);

KRATOS_EXPECT_EQ(process.get(), nullptr);
}

KRATOS_TEST_CASE_IN_SUITE(CreateNothingWhenTheAddedCreatorIsEmpty, KratosGeoMechanicsFastSuite)
{
ProcessFactory factory;
factory.AddCreator("TestProcess", {});

const Parameters process_settings;
const auto process = factory.Create("TestProcess", process_settings);

KRATOS_EXPECT_EQ(process.get(), nullptr);
}

KRATOS_TEST_CASE_IN_SUITE(CreateFooProcessAfterCreatorWasAdded, KratosGeoMechanicsFastSuite)
{
ProcessFactory factory;
factory.AddCreator("FooProcess", [](const Parameters&){return std::make_unique<FooProcess>();});

const Parameters process_settings;
const auto process = factory.Create("FooProcess", process_settings);

KRATOS_EXPECT_NE(dynamic_cast<FooProcess*>(process.get()), nullptr);
KRATOS_EXPECT_EQ(dynamic_cast<BarProcess*>(process.get()), nullptr);
}

KRATOS_TEST_CASE_IN_SUITE(CreateDifferentKindsOfProcessesAfterAddingCreators, KratosGeoMechanicsFastSuite)
{
ProcessFactory factory;
factory.AddCreator("FooProcess", [](const Parameters&){return std::make_unique<FooProcess>();});
factory.AddCreator("BarProcess", [](const Parameters&){return std::make_unique<BarProcess>();});

const Parameters foo_process_settings;
const auto foo_process = factory.Create("FooProcess", foo_process_settings);
const Parameters bar_process_settings;
const auto bar_process = factory.Create("BarProcess", bar_process_settings);

KRATOS_EXPECT_NE(dynamic_cast<FooProcess*>(foo_process.get()), nullptr);
KRATOS_EXPECT_NE(dynamic_cast<BarProcess*>(bar_process.get()), nullptr);
}

KRATOS_TEST_CASE_IN_SUITE(CreatorReceivesGivenSettingsWhenMakingNewProcess, KratosGeoMechanicsFastSuite)
{
ProcessFactory factory;
const Parameters* received_settings = nullptr;
auto creator = [&received_settings](const Parameters& rProcessSettings){
received_settings = &rProcessSettings;
return std::make_unique<FooProcess>();
};
factory.AddCreator("FooProcess", creator);

const Parameters process_settings;
const auto foo_process = factory.Create("FooProcess", process_settings);

KRATOS_EXPECT_EQ(&process_settings, received_settings);
}

KRATOS_TEST_CASE_IN_SUITE(AddingCreatorWithSameProcessNameOverwritesPreviousOne, KratosGeoMechanicsFastSuite)
{
ProcessFactory factory;
auto creator_id = 0;
auto creator1 = [&creator_id](const Parameters&){
creator_id = 1;
return std::make_unique<FooProcess>();
};
auto creator2 = [&creator_id](const Parameters&){
creator_id = 2;
return std::make_unique<FooProcess>();
};

factory.AddCreator("FooProcess", creator1);
auto foo_process = factory.Create("FooProcess", {});
KRATOS_EXPECT_EQ(1, creator_id);

factory.AddCreator("FooProcess", creator2);
foo_process = factory.Create("FooProcess", {});
KRATOS_EXPECT_EQ(2, creator_id);
}

}

0 comments on commit a4592db

Please sign in to comment.