diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a02f1bf1e..0fa09677b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,51 +2,61 @@ name: CI Pipeline on: push: - branches: [ "main", "Assignment3" ] + branches: [ "main", "Assignment*" ] pull_request: - branches: [ "main", "Assignment3" ] + branches: [ "main", "Assignment*" ] jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Dependencies - run: sudo apt install libxerces-c-dev + - name: Install Dependencies + run: sudo apt install libxerces-c-dev - - name: Create build directory - run: mkdir -p ${{github.workspace}}/build + - name: Create build directory + run: mkdir -p ${{github.workspace}}/build - - name: CMake Configure - run: cmake -D CMAKE_CXX_FLAGS="-fsanitize=address" -B ${{github.workspace}}/build ${{github.workspace}} + - name: CMake Configure + run: cmake -D CMAKE_CXX_FLAGS="-fsanitize=address" -B ${{github.workspace}}/build ${{github.workspace}} - - name: Build - run: cmake --build ${{github.workspace}}/build - - - name: Save build environment - uses: actions/upload-artifact@v4 - with: - name: built - path: ${{github.workspace}}/build + - name: Build + run: cmake --build ${{github.workspace}}/build test: needs: build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Dependencies + run: sudo apt install libxerces-c-dev + + - name: Create build directory + run: mkdir -p ${{github.workspace}}/build + + - name: CMake Configure + run: cmake -B ${{github.workspace}}/build ${{github.workspace}} + + - name: Build + run: cmake --build ${{github.workspace}}/build + + - name: Set execute permissions for tests + run: chmod +x ${{ github.workspace }}/build/MolSimTests ${{ github.workspace }}/build/MolSimBenchmark + + - name: Check current location + run: pwd - - name: Reload build environment - uses: actions/download-artifact@v4 - with: - name: built - path: ${{github.workspace}}/build + - name: list files + run: ls -l ${{ github.workspace }} - - name: Set execute permissions for tests - run: chmod +x ${{github.workspace}}/build/MolSimTests ${{github.workspace}}/build/MolSimBenchmark + - name: list files in build directory + run: ls -l ${{ github.workspace }}/build - - name: Tests - working-directory: ${{github.workspace}}/build - run: ctest -V -R '.*Test' + - name: Tests + working-directory: ${{ github.workspace }}/build + run: ctest -V -R '.*Test' \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 116941a81..d560033c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,85 +10,100 @@ project(PSEMolDyn_GroupC VERSION 0.0.1) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug;Release;RelWithDebInfo;MinSizeRel") # set Release as the default build type if it is not yet set. -if(NOT CMAKE_BUILD_TYPE) +if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) -endif(NOT CMAKE_BUILD_TYPE) +endif (NOT CMAKE_BUILD_TYPE) # ----------------------------------------Adding Libraries------------------------------------------------- # Fetch spdlog from GitHub FetchContent_Declare( spdlog GIT_REPOSITORY https://github.com/gabime/spdlog - GIT_TAG v1.x + GIT_TAG v1.x ) FetchContent_MakeAvailable(spdlog) FetchContent_Declare( - cxxopts - GIT_REPOSITORY https://github.com/jarro2783/cxxopts - GIT_TAG master + cxxopts + GIT_REPOSITORY https://github.com/jarro2783/cxxopts + GIT_TAG master ) FetchContent_MakeAvailable(cxxopts) FetchContent_Declare( gtest GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG main + GIT_TAG main ) FetchContent_MakeAvailable(gtest) FetchContent_Declare( benchmark GIT_REPOSITORY https://github.com/google/benchmark - GIT_TAG main + GIT_TAG main ) FetchContent_MakeAvailable(benchmark) find_package(OpenMP) if (OPENMP_FOUND) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") -endif() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") +endif () + # ------------------------------------------------------------------------------------------------------------ # collect all cpp files file(GLOB_RECURSE MY_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/io/in/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/io/in/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/io/in/input_schema.cxx" ) file(GLOB_RECURSE TEST_SOURCES - "${CMAKE_CURRENT_SOURCE_DIR}/tests/**/*.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/tests/**/*.h" - "${CMAKE_CURRENT_SOURCE_DIR}/src/io/in/*.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/src/objects/*.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/src/calculators/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/tests/**/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/tests/**/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/io/in/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/objects/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/calculators/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/boundaries/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/utils/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/utils/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/io/in/input_schema.cxx" ) file(GLOB_RECURSE BENCHMARK_SOURCES - "${CMAKE_CURRENT_SOURCE_DIR}/benchmark/*.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/benchmark/*.h" - "${CMAKE_CURRENT_SOURCE_DIR}/src/objects/*.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/src/objects/*.h" - "${CMAKE_CURRENT_SOURCE_DIR}/src/io/in/*.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/src/io/in/*.h" - "${CMAKE_CURRENT_SOURCE_DIR}/src/calculators/*.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/src/calculators/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/benchmark/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/benchmark/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/objects/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/objects/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/io/in/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/io/in/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/calculators/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/calculators/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/utils/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/utils/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/io/in/input_schema.cxx" ) #------------------------------------------LOGGING--------------------------------------------------------- -# get the log level from the command line -set(log_level "INFO" CACHE STRING "Log level") +# check if the log level is defined in the environment +if (DEFINED ENV{LOG_LEVEL}) + set(log_level $ENV{LOG_LEVEL}) +else () + set(log_level "INFO") +endif () # define the valid log levels set(valid_log_levels "TRACE" "DEBUG" "INFO" "WARN" "ERROR" "CRITICAL" "OFF") # check if the log level is valid -if(NOT log_level IN_LIST valid_log_levels) +if (NOT log_level IN_LIST valid_log_levels) message(FATAL_ERROR "Invalid log level: ${log_level}. Valid log levels are: ${valid_log_levels}") -endif() +endif () # define the SPDLOG_ACTIVE_LEVEL macro add_compile_definitions(SPDLOG_ACTIVE_LEVEL=${log_level}) @@ -96,57 +111,65 @@ add_compile_definitions(LOG_LEVEL="${log_level}") message(STATUS "Log level: ${log_level}") #----------------------------------------------------------------------------------------------------------- # create make target -add_executable(MolSim ${MY_SRC}) -add_executable(MolSimTests ${TEST_SOURCES}) +add_executable(MolSim ${MY_SRC} + tests/io/in/XMLReaderTest.cpp) +add_executable(MolSimTests ${TEST_SOURCES} + tests/io/in/XMLReaderTest.cpp) add_executable(MolSimBenchmark ${BENCHMARK_SOURCES}) # set cxx standard. You may raise this if you want. target_compile_features(MolSim PRIVATE - cxx_std_17 + cxx_std_17 ) target_include_directories(MolSim PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/libs/libxsd + ${CMAKE_CURRENT_SOURCE_DIR}/libs/libxsd PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_CURRENT_SOURCE_DIR}/src ) -target_include_directories(MolSimTests - PRIVATE +target_include_directories(MolSimTests + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tests + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_CURRENT_SOURCE_DIR}/libs/libxsd ) -target_include_directories(MolSimBenchmark - PRIVATE +target_include_directories(MolSimBenchmark + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/benchmark + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_CURRENT_SOURCE_DIR}/libs/libxsd ) target_link_libraries(MolSim # stuff that is used in headers and source files PUBLIC - xerces-c + xerces-c PRIVATE - spdlog::spdlog $<$:ws2_32> - gtest - gtest_main - cxxopts + spdlog::spdlog $<$:ws2_32> + gtest + gtest_main + cxxopts ) target_link_libraries(MolSimTests - PRIVATE - gtest - gtest_main - spdlog::spdlog $<$:ws2_32> + PRIVATE + xerces-c + gtest + gtest_main + spdlog::spdlog $<$:ws2_32> ) target_link_libraries(MolSimBenchmark - PRIVATE - benchmark - spdlog::spdlog $<$:ws2_32> - gtest - gtest_main + PRIVATE + xerces-c + benchmark + spdlog::spdlog $<$:ws2_32> + gtest + gtest_main ) add_test(NAME MolSimTests COMMAND MolSimTests) @@ -155,10 +178,10 @@ add_test(NAME MolSimTests COMMAND MolSimTests) # depending on the compiler different flags are used target_compile_options(MolSim PRIVATE - $<$:-Wall -fopenmp> + $<$:-Wall -fopenmp> ) list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules) include(doxygen) -include(CTest) +include(CTest) \ No newline at end of file diff --git a/README.md b/README.md index 0d9bff855..ec6239ede 100644 --- a/README.md +++ b/README.md @@ -20,10 +20,16 @@ In order to build and run this code, you need the following tools installed on y 2. Build the code: - `cmake -Dlog_level={WANTED_LOG_LEVEL} ..` + `cmake ..` + + The default log level is `INFO`. + + If you wish to set the log level manually, run: + `LOG_LEVEL={WANTED_LOG_LEVEL} cmake ..` Valid log levels are: `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `CRITICAL`, `OFF`. + 3. Make: `make -j $(nproc)` @@ -34,12 +40,13 @@ In order to build and run this code, you need the following tools installed on y 4. Run the code: - `./MolSim {INPUT} {DELTA_T} {END_TIME} {OUTPUT_WRITER} {CALCULATOR}` + `./MolSim {INPUT} {DELTA_T} {END_TIME} {OUTPUT_WRITER} {CALCULATOR} {BOUNDARIES}` - Example calls: - - `./MolSim --help` - - `./MolSim --input=../resources/input-sun.txt --delta_t=0.014 --end_time=1000 --output=vtk --calculator=sv` - - `./MolSim --input=../resources/input-cuboid.txt --delta_t=0.0002 --end_time=5 --output=vtk --calculator=lj` + Example calls: + - `./MolSim --help` + - `./MolSim --input=../resources/input-sun.txt --delta_t=0.014 --end_time=1000 --output=vtk --calculator=sv` + - `./MolSim --input=../resources/input-cuboid.txt --delta_t=0.0002 --end_time=5 --output=vtk --calculator=lj` + - `./MolSim --input=../resources/input-cuboid.xml --output=vtk --calculator=lj` 5. Available options for arguments: @@ -56,9 +63,9 @@ In order to build and run this code, you need the following tools installed on y `{CALCULATOR}`: The calculator to use. Available options are sv, lj or dummy. 6. If you wish to execute the tests: - - `./MolSimTests` - or - - `ctest -V -R '.*Test'` + - `./MolSimTests` + or + - `ctest -V -R '.*Test'` 7. If you wish to execute the benchmarks: - - `./MolSimBenchmark` + - `./MolSimBenchmark` \ No newline at end of file diff --git a/benchmark/CalculatorLJBenchmark.cpp b/benchmark/CalculatorLJBenchmark.cpp index 8b6e570f2..637f97a57 100644 --- a/benchmark/CalculatorLJBenchmark.cpp +++ b/benchmark/CalculatorLJBenchmark.cpp @@ -2,6 +2,7 @@ #include "../src/calculators/LJCalculator.h" #include "../src/objects/ParticleContainer.h" #include "../src/io/in/FileReader.h" +#include "../src/io/in/TXTReader.h" #include "benchmark/benchmark.h" #include @@ -11,8 +12,11 @@ static void BM_LJCalculator(benchmark::State& state) { state.range(0) == 2 ? 0.001 : state.range(0) == 3 ? 0.0005 : 5; const double end_time = 5.0; - std::unique_ptr calculator = std::make_unique(1, 5, 5.31608); - ParticleContainer particleContainer = FileReader::readFile("../resources/input-cuboid.txt"); + std::unique_ptr calculator = std::make_unique(5.31608); + + fileReaders::TXTReader fileReader = fileReaders::TXTReader(); + SimulationDataContainer simulationDataContainer = fileReader.readFile("../resources/input-cuboid.txt"); + ParticleContainer particleContainer = *simulationDataContainer.getParticleContainer(); for (auto _ : state) { double current_time = 0; diff --git a/resources/input-cuboid.txt b/resources/input-cuboid.txt index a2259e4e3..d9fe6a7a7 100644 --- a/resources/input-cuboid.txt +++ b/resources/input-cuboid.txt @@ -9,6 +9,8 @@ # # The second line indicates the number of data sets (e.g. number of particles or cuboids). # +# The third line indicates the dimension of the simulation. +# # Cuboid data consists of # * coordinates of lower left front corner (3 double values) # * number of particles per dimension (3 size_t values) @@ -17,9 +19,13 @@ # * initial velocities of particles per dimension (3 double value) # * mean velocity of the Brownian Motion (1 double value) # -# llf-coord numParticles distance mass startV meanV +# Data type 1 +# Number of data sets 2 -0.0 0.0 0.0 40 8 1 1.1225 1.0 0.0 0.0 0.0 0.1 -15.0 15.0 0.0 8 8 1 1.1225 1.0 0.0 -10.0 0.0 0.1 - +# Dimension +2 +# llf-coord numParticles distance mass startV meanV + 0.5 0.5 0.0 40 8 1 1.1225 1.0 0.0 0.0 0.0 0.1 + 15.0 15.0 0.0 8 8 1 1.1225 1.0 0.0 -10.0 0.0 0.1 +# 43 0.0 0.0 2 2 1 1 1.0 0.0 0.0 0.0 0.1 \ No newline at end of file diff --git a/resources/input-cuboid.xml b/resources/input-cuboid.xml new file mode 100644 index 000000000..2c131f6ef --- /dev/null +++ b/resources/input-cuboid.xml @@ -0,0 +1,53 @@ + + + Simulation1 + 10 + + + 25 + 0.0005 + -12.44 + 2 + + + 40.0 + 20.0 + 1000 + 10.0 + 3 + + + true + 2.5 + + + 63.0 36.0 3.0 + REFLECTING + REFLECTING + REFLECTING + REFLECTING + REFLECTING + REFLECTING + + + 0.6 2.0 0.0 + 50 14 1 + 1.2 + 1.0 + 0.0 0.0 0.0 + 0.1 + 1.0 + 1.0 + + + 0.6 19.0 0.0 + 50 14 1 + 1.2 + 2.0 + 0.0 0.0 0.0 + 0.1 + 0.9 + 1.0 + + diff --git a/resources/input-disc.txt b/resources/input-disc.txt new file mode 100644 index 000000000..37a22877e --- /dev/null +++ b/resources/input-disc.txt @@ -0,0 +1,29 @@ +# +# file format: +# Lines of comment start with '#' and are only allowed at the beginning of the file +# Empty lines are not allowed. +# The first line not being a comment has to be one integer, indicating the type of data +# represented in the file. +# - '0' stands for particle data +# - '1' stands for cuboid data +# - '2' stands for disc data +# +# The second line indicates the number of data sets (e.g. number of particles or cuboids). +# +# The third line indicates the dimension of the simulation. +# +# Disc data consists of +# * coordinates of the disc center (3 double values) +# * start velocities of all particles in the disc (3 double value) +# * number of particles along the radius of the disc (1 integer value) +# * distance ( = meshwidth between the particles) (1 double value) +# * mass of the particles (1 double value) +# +# Data type +2 +# Number of data sets +1 +# Dimension +2 +# center-coord startV numParticlesAlongRadius distance mass +60 25 0 0 -10 0 15 1.1225 1.0 \ No newline at end of file diff --git a/resources/input-disc.xml b/resources/input-disc.xml new file mode 100644 index 000000000..bf6437198 --- /dev/null +++ b/resources/input-disc.xml @@ -0,0 +1,42 @@ + + + Simulation1 + 10 + + + 100.0 + 0.001 + -9.81 + 2 + + + 0.0 + 0.0 + 100 + 10.0 + 3 + + + true + 3.0 + + + 180.0 90.0 3.0 + REFLECTING + REFLECTING + REFLECTING + REFLECTING + REFLECTING + REFLECTING + + + 60.0 25.0 0.0 + 0.0 -10.0 0.0 + 15 + 1.1225 + 1.0 + 1.0 + 1.0 + + diff --git a/resources/input-sun.txt b/resources/input-sun.txt index 0fcc7ffd0..285dd5a02 100644 --- a/resources/input-sun.txt +++ b/resources/input-sun.txt @@ -9,15 +9,21 @@ # # The second line indicates the number of data sets (e.g. number of particles or cuboids). # +# The third line indicates the dimension of the simulation. +# # Particle data consists of # * xyz-coordinates (3 double values) # * velocities (2 or 3 double values) # * mass (1 double value) # -# xyz-coord velocity mass +# Data type 0 +# Number of data sets 4 +# Dimension +3 +# xyz-coord velocity mass 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 1.0 0.0 -1.0 0.0 0.0 3.0e-6 0.0 5.36 0.0 -0.425 0.0 0.0 9.55e-4 -34.75 0.0 0.0 0.0 0.0296 0.0 1.0e-14 +34.75 0.0 0.0 0.0 0.0296 0.0 1.0e-14 \ No newline at end of file diff --git a/src/Main.cpp b/src/Main.cpp index 0c5f646da..20bd8b143 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -1,8 +1,10 @@ #include "calculators/SVCalculator.h" -#include "calculators/DummyCalculator.h" #include "calculators/LJCalculator.h" #include "io/in/FileReader.h" +#include "io/in/TXTReader.h" +#include "io/in/XMLReader.h" #include "objects/ParticleContainer.h" +#include "objects/LinkedCellContainer.h" #include "io/out/FileWriter.h" #include "io/out/VTKWriter.h" #include "io/out/XYZWriter.h" @@ -11,6 +13,9 @@ #include "MolSim.h" #include #include +#include +#include "boundaries/BoundaryHandler.h" +#include "calculators/Thermostat.h" /** * @brief The main function of the program. @@ -24,32 +29,34 @@ * @return The exit status of the program. */ int main(int argc, char *argsv[]) { - // Example calls: - // ./MolSim --help - // ./MolSim ../resources/input-sun.txt --delta_t=0.001 --end_time=5 --output=vtk --calculator=sv - // ./MolSim ../resources/input-cuboid.txt --delta_t=0.001 --end_time=5 --output=vtk --calculator=lj - // Set the log level to the wanted level std::string log_level = LOG_LEVEL; MolSim::setLogLevel(log_level); - std::string inputFilePath; - double delta_t; - double end_time; - std::unique_ptr outputWriter; - std::unique_ptr calculator; + double delta_t = -1.0; + double end_time = -1.0; + std::unique_ptr fileReader; + std::unique_ptr outputWriter; + std::shared_ptr calculator; + std::unique_ptr thermostat = std::make_unique(10, 20, 5, 1, 3); if (!MolSim::processArguments(argc, argsv, inputFilePath, delta_t, end_time, outputWriter, calculator)) { return 1; } - ParticleContainer particleContainer = FileReader::readFile(inputFilePath); - - SPDLOG_INFO("Starting simulation with delta_t: {}, end_time: {}", delta_t, end_time); + if (inputFilePath.length() >= 4 && inputFilePath.substr(inputFilePath.length() - 4) == ".xml") { + SPDLOG_INFO("Processing XML input file: {}", inputFilePath); + fileReader = std::make_unique(); + } else { + SPDLOG_INFO("Processing TXT input file: {}", inputFilePath); + fileReader = std::make_unique(); + } - MolSim::performSimulation(particleContainer, delta_t, end_time, outputWriter, calculator); + SimulationDataContainer simulationDataContainer = fileReader->readFile(inputFilePath); + MolSim::updateSimulationParameters(simulationDataContainer, delta_t, end_time); + MolSim::performSimulation(simulationDataContainer, outputWriter, calculator); SPDLOG_INFO("Simulation completed."); return 0; -} +} \ No newline at end of file diff --git a/src/MolSim.h b/src/MolSim.h index 4e74b0da9..a9274729e 100644 --- a/src/MolSim.h +++ b/src/MolSim.h @@ -1,19 +1,27 @@ // // Created by kimj2 on 14.05.2024. // +#include #include "calculators/SVCalculator.h" -#include "calculators/DummyCalculator.h" #include "calculators/LJCalculator.h" +#include "calculators/LC_LJCalculator.h" #include "io/in/FileReader.h" +#include "io/in/TXTReader.h" +#include "io/in/XMLReader.h" #include "objects/ParticleContainer.h" +#include "objects/LinkedCellContainer.h" #include "io/out/FileWriter.h" #include "io/out/VTKWriter.h" #include "io/out/XYZWriter.h" #include "spdlog/spdlog.h" #include "cxxopts.hpp" +#include "boundaries/BoundaryHandler.h" +#include "calculators/Thermostat.h" class MolSim { public: + constexpr static const double COMPARISON_TOLERANCE = 1e-6; + /** * @brief Sets the log level for the program. * @@ -68,18 +76,20 @@ class MolSim { * @return True if the arguments were processed successfully and a valid calculator and output writer were selected, false otherwise. */ static bool processArguments(int argc, char *argv[], std::string &inputFilePath, - double &delta_t, double &end_time, - std::unique_ptr &outputWriter, - std::unique_ptr &calculator) { + double &delta_t, double &end_time, + std::unique_ptr &outputWriter, + std::shared_ptr &calculator) { cxxopts::Options options("MolSim", "Molecular Simulation Program"); options.add_options() - ("help", "Produce help message") - ("input", "Input file path", cxxopts::value()) - ("delta_t", "Set delta_t", cxxopts::value()->default_value("0.014")) - ("end_time", "Set end_time", cxxopts::value()->default_value("1000")) - ("output", "Output writer (vtk or xyz)", cxxopts::value()) - ("calculator", "Calculator (sv, lj or dummy)", cxxopts::value()); + ("help", "Produce help message") + ("input", "Input file path", cxxopts::value()) + ("delta_t", "Set delta_t", cxxopts::value()->default_value("0.014")) + ("end_time", "Set end_time", cxxopts::value()->default_value("1000")) + ("output", "Output writer (vtk or xyz)", cxxopts::value()) + ("calculator", "Calculator (sv, lj or dummy)", cxxopts::value()) + ("boundaries", "Boundary conditions (0000 to 3333)", + cxxopts::value()->default_value("3333")); auto result = options.parse(argc, argv); @@ -91,6 +101,12 @@ class MolSim { if (result.count("input")) { inputFilePath = result["input"].as(); SPDLOG_INFO("Input file path: {}", inputFilePath); + + if (inputFilePath.length() >= 4 && inputFilePath.substr(inputFilePath.length() - 4) == ".xml") { + calculator = std::make_unique(); + outputWriter = std::make_unique(); + return true; + } } delta_t = result["delta_t"].as(); @@ -117,14 +133,11 @@ class MolSim { calculator = std::make_unique(); SPDLOG_INFO("Selected calculator: sv"); } else if (calculatorArg == "lj") { - calculator = std::make_unique(1, 5, 5.31608); + calculator = std::make_unique(5.31608); SPDLOG_INFO("Selected calculator: lj"); - } else if (calculatorArg == "dummy") { - calculator = std::make_unique(); - SPDLOG_INFO("Selected calculator: dummy"); } else { SPDLOG_ERROR("Invalid option for calculator: {}", calculatorArg); - SPDLOG_ERROR("Only 'sv', 'lj', or 'dummy' are allowed."); + SPDLOG_ERROR("Only 'sv' and 'lj' are allowed."); return false; } } @@ -143,10 +156,66 @@ class MolSim { SPDLOG_ERROR("Invalid input; please select a calculator."); return false; } + /** + if (result.count("boundaries")) { + std::string boundariesArg = result["boundaries"].as(); + if (boundariesArg.size() == 4) { + std::array directions = { + boundaries::BoundaryDirection::LEFT, + boundaries::BoundaryDirection::BOTTOM, + boundaries::BoundaryDirection::RIGHT, + boundaries::BoundaryDirection::TOP + }; + for (int i = 0; i < 4; ++i) { + switch (boundariesArg[i]) { + case '0': + boundaryMap[directions[i]] = boundaries::BoundaryType::OFF; + break; + case '1': + boundaryMap[directions[i]] = boundaries::BoundaryType::REFLECTING; + break; + case '2': + boundaryMap[directions[i]] = boundaries::BoundaryType::OUTFLOW; + break; + case '3': + boundaryMap[directions[i]] = boundaries::BoundaryType::PERIODIC; + break; + default: + SPDLOG_WARN("Invalid boundary value '{}', defaulting all to PERIODIC", boundariesArg[i]); + boundaryMap[directions[i]] = boundaries::BoundaryType::PERIODIC; + } + } + } else { + SPDLOG_WARN("Invalid boundary string length, defaulting all boundaries to REFLECTING"); + boundaryMap[boundaries::BoundaryDirection::LEFT] = boundaries::BoundaryType::REFLECTING; + boundaryMap[boundaries::BoundaryDirection::BOTTOM] = boundaries::BoundaryType::REFLECTING; + boundaryMap[boundaries::BoundaryDirection::RIGHT] = boundaries::BoundaryType::REFLECTING; + boundaryMap[boundaries::BoundaryDirection::TOP] = boundaries::BoundaryType::REFLECTING; + } + } else { + SPDLOG_WARN("No boundary conditions specified, defaulting all boundaries to REFLECTING"); + boundaryMap[boundaries::BoundaryDirection::LEFT] = boundaries::BoundaryType::REFLECTING; + boundaryMap[boundaries::BoundaryDirection::BOTTOM] = boundaries::BoundaryType::REFLECTING; + boundaryMap[boundaries::BoundaryDirection::RIGHT] = boundaries::BoundaryType::REFLECTING; + boundaryMap[boundaries::BoundaryDirection::TOP] = boundaries::BoundaryType::REFLECTING; + } + **/ return true; } + static void updateSimulationParameters(SimulationDataContainer &simulationDataContainer, + double &delta_t, double &end_time) { + if (std::abs(delta_t - (-1.0)) > COMPARISON_TOLERANCE) { + simulationDataContainer.getSimulationParameters()->setDelta_t(delta_t); + SPDLOG_INFO("Delta_t set to {}.", delta_t); + } + if (std::abs(end_time - (-1.0)) > COMPARISON_TOLERANCE) { + simulationDataContainer.getSimulationParameters()->setEnd_t(end_time); + SPDLOG_INFO("End time set to {}.", end_time); + } + } + /** * @brief Performs the simulation. * @@ -156,32 +225,130 @@ class MolSim { * @param particleContainer The particle container containing the particles. * @param delta_t The time step size. * @param end_time The end time of the simulation. - * @param outputWriter The output writer to be used. + * @param outputWriter The file writer to be used. * @param calculator The calculator to be used. + * @param boundaryMap The boundary conditions to be used. + * @param thermostat The thermostat to be used. */ - static void performSimulation(ParticleContainer &particleContainer, double &delta_t, double &end_time, - std::unique_ptr &outputWriter, - std::unique_ptr &calculator) { - const std::string &filename = "MD"; + static void performSimulation(SimulationDataContainer &simulationDataContainer, + std::unique_ptr &outputWriter, + std::shared_ptr &calculator) { + if (!simulationDataContainer.getParticleContainer() || + !simulationDataContainer.getLinkedCellContainer() || + !simulationDataContainer.getFileWriterParameters() || + !simulationDataContainer.getSimulationParameters() || + !simulationDataContainer.getThermostatParameters() || + !simulationDataContainer.getLinkedCellsParameters() || + !simulationDataContainer.getBoundaryParameters()) { + SPDLOG_ERROR("One or more required components are missing in the SimulationDataContainer"); + return; + } + + ParticleContainer &particleContainer = *simulationDataContainer.getParticleContainer(); + LinkedCellContainer &linkedCellContainer = *simulationDataContainer.getLinkedCellContainer(); + FileWriterParameters &fileWriterParameters = *simulationDataContainer.getFileWriterParameters(); + SimulationParameters &simulationParameters = *simulationDataContainer.getSimulationParameters(); + ThermostatParameters &thermostatParameters = *simulationDataContainer.getThermostatParameters(); + LinkedCellsParameters &linkedCellsParameters = *simulationDataContainer.getLinkedCellsParameters(); + BoundaryParameters &boundaryParameters = *simulationDataContainer.getBoundaryParameters(); - double current_time = 0; // start_time + const double delta_t = simulationParameters.getDelta_t(); + const double end_time = simulationParameters.getEnd_t(); + SPDLOG_INFO("Simulation started with delta_T: {}, end_t: {}.", delta_t, end_time); + + Thermostat thermostat(thermostatParameters.getStartTemp(), thermostatParameters.getTargetTemp(), + thermostatParameters.getApplyFrequency(), thermostatParameters.getMaxDeltaTemp(), + thermostatParameters.getDimension()); + SPDLOG_INFO( + "Thermostat initialized with start_temp: {}, target_temp: {}, apply_frequency: {}, max_delta_temp: {}, dimension: {}.", + thermostatParameters.getStartTemp(), thermostatParameters.getTargetTemp(), + thermostatParameters.getApplyFrequency(), thermostatParameters.getMaxDeltaTemp(), + thermostatParameters.getDimension()); + const auto &boundaryMap = boundaryParameters.getBoundaryMap(); + SPDLOG_INFO("Boundary conditions initialized."); + + // retrieve required parameters + double current_time = 0.0; // start_time int iteration = 0; + const int thermostatApplyFrequency = thermostat.getApplyFrequency(); + SPDLOG_INFO("Thermostat apply frequency set to {}.", thermostatApplyFrequency); + const std::array domain = boundaryParameters.getDomain(); + SPDLOG_INFO("Domain set to {}.", ArrayUtils::to_string(domain)); + const boundaries::BoundaryProperties properties{domain, boundaryMap}; + const boundaries::BoundaryHandler handler{properties, calculator}; + const bool linkedCellsUsed = linkedCellsParameters.isLinkedCellsUsed(); + const std::string &filename = fileWriterParameters.getBaseName(); + SPDLOG_INFO("Output filename set to {}.", filename); + const double gravity = simulationParameters.getGravity(); + calculator->setGravity(gravity); + SPDLOG_INFO("Gravity set to {}.", gravity); - while (current_time < end_time) { - calculator->calculate(particleContainer, delta_t); + auto start = std::chrono::high_resolution_clock::now(); - iteration++; - if (iteration % 10 == 0) { - outputWriter->plotParticles(iteration, particleContainer, filename); - } + if (linkedCellsUsed) { + SPDLOG_INFO("Linked cells used in this simulation."); + thermostat.initializeTemp(linkedCellContainer); + + while (current_time < end_time) { + SPDLOG_TRACE("Starting iteration {} with time {}.", iteration, current_time); + handler.preProcessBoundaries(linkedCellContainer); + calculator->calculateLC(linkedCellContainer, delta_t); + handler.postProcessBoundaries(linkedCellContainer); - if (iteration % 100 == 0) { - SPDLOG_INFO("Iteration {} finished.", iteration); + iteration++; + if (iteration % thermostatApplyFrequency == 0) { + thermostat.setTempGradually(linkedCellContainer); + SPDLOG_INFO("Thermostat applied at iteration {}.", iteration); + } + + if (iteration % 10 == 0) { + outputWriter->plotParticlesLC(iteration, linkedCellContainer, filename); + SPDLOG_INFO("Output written for iteration {}.", iteration); + } + + if (iteration % 100 == 0) { + SPDLOG_INFO("Iteration {} finished.", iteration); + } + current_time += delta_t; } + } else { + SPDLOG_INFO("Linked cells not used in this simulation."); + thermostat.initializeTemp(particleContainer); - current_time += delta_t; + while (current_time < end_time) { + SPDLOG_TRACE("Starting iteration {} with time {}.", iteration, current_time); + handler.preProcessBoundaries(particleContainer); + calculator->calculate(particleContainer, delta_t); + handler.postProcessBoundaries(particleContainer); + + iteration++; + if (iteration % thermostatApplyFrequency == 0) { + thermostat.setTempGradually(particleContainer); + SPDLOG_DEBUG("Thermostat applied at iteration {}.", iteration); + } + + if (iteration % 10 == 0) { + outputWriter->plotParticles(iteration, particleContainer, filename); + SPDLOG_DEBUG("Output written for iteration {}.", iteration); + } + + if (iteration % 100 == 0) { + SPDLOG_INFO("Iteration {} finished.", iteration); + } + current_time += delta_t; + } } + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + size_t totalMolecules = linkedCellsUsed ? linkedCellContainer.getSize() * iteration : + particleContainer.getSize() * iteration; + double MUPS = totalMolecules / elapsed.count(); + + SPDLOG_INFO("Simulation completed in {} seconds.", elapsed.count()); + SPDLOG_INFO("Molecule-updates per second (MUPS): {}", MUPS); + SPDLOG_INFO("Output written. Terminating..."); } -}; +}; \ No newline at end of file diff --git a/src/boundaries/BoundaryEnums.h b/src/boundaries/BoundaryEnums.h new file mode 100644 index 000000000..00b7d5562 --- /dev/null +++ b/src/boundaries/BoundaryEnums.h @@ -0,0 +1,32 @@ +// +// Created by houj on 5/23/24. +// +#pragma once + +#include + +namespace boundaries { + /** + * @enum BoundaryType + * @brief Defines the types of boundary conditions for the simulation. + */ + enum class BoundaryType { + REFLECTING, /**< Boundary reflects particles. */ + OUTFLOW, /**< Boundary allows particles to flow out. */ + PERIODIC, + OFF /**< Boundary is turned off. */ + }; + + /** + * @enum BoundaryDirection + * @brief Defines the possible directions for boundaries in the simulation. + */ + enum class BoundaryDirection { + TOP, /**< Upper boundary (Y-axis High). */ + RIGHT, /**< Right boundary (X-axis High). */ + BOTTOM, /**< Lower boundary (Y-axis Low). */ + LEFT, /**< Left boundary (X-axis Low). */ + FRONT, /**< Front boundary (Z-axis High). */ + BACK /**< Back boundary (Z-axis Low). */ + }; +} \ No newline at end of file diff --git a/src/boundaries/BoundaryHandler.cpp b/src/boundaries/BoundaryHandler.cpp new file mode 100644 index 000000000..a1a6ff6a3 --- /dev/null +++ b/src/boundaries/BoundaryHandler.cpp @@ -0,0 +1,253 @@ +// +// Created by houj on 5/23/24. +// + +#include "BoundaryHandler.h" +#include "calculators/LC_LJCalculator.h" +#include + +namespace boundaries { + constexpr int boundaryWidthInNumCells = 2; + + + void BoundaryHandler::preProcessBoundaries(ParticleContainer &container) const { + for (auto it : properties.getBoundaryMap()) { + if (it.second == BoundaryType::REFLECTING) { + handleReflection(container, it.first); + } + } + } + + void BoundaryHandler::preProcessBoundaries(LinkedCellContainer &linkedCellContainer) const { + for (auto it : properties.getBoundaryMap()) { + if (it.second == BoundaryType::REFLECTING) { + handleReflection(linkedCellContainer, it.first); + } + } + } + + void BoundaryHandler::postProcessBoundaries(ParticleContainer &container) const { + for (auto it : properties.getBoundaryMap()) { + if (it.second == BoundaryType::OUTFLOW) + handleOutflow(container, it.first); + else if (it.second == BoundaryType::PERIODIC) + handlePeriodic(container, it.first); + } + } + + void BoundaryHandler::postProcessBoundaries(LinkedCellContainer &linkedCellContainer) const { + for (auto it : properties.getBoundaryMap()) { + if (it.second == BoundaryType::OUTFLOW) + handleOutflow(linkedCellContainer, it.first); + else if (it.second == BoundaryType::PERIODIC) + handlePeriodic(linkedCellContainer, it.first); + } + } + + void BoundaryHandler::handleReflection(ParticleContainer &container, BoundaryDirection direction) const { + const int relevantIndex = retrieveRelevantPositionIndex(direction); + const bool isLowerBound = retrieveIsLowerBound(direction); + + double boundary = properties.getDomain()[relevantIndex]; + // If selected index is lower boundary (lowerX, lowerY, lowerZ) + if (isLowerBound) { + // for indexing x, y, z coordinate +//#pragma omp parallel for + for (auto &p: container) { + double distanceToBoundary = p.getX().at(relevantIndex); + double tolerance = pow(2, 1 / 6) * p.getSigma(); + // only calculate reflection if near boundary + if (distanceToBoundary < tolerance) { + Particle ghost{p}; + if (relevantIndex == 0) + ghost.setX({-distanceToBoundary, p.getX().at(1), p.getX().at(2)}); + else if (relevantIndex == 1) + ghost.setX({p.getX().at(0), -distanceToBoundary, p.getX().at(2)}); + else + ghost.setX({p.getX().at(0), p.getX().at(1), -distanceToBoundary}); + calculator->calculateFPairwise(p, ghost); + } + } + return; + } +//#pragma omp parallel for + for (auto &p: container) { + double distanceToBoundary = boundary - p.getX().at(relevantIndex); + // only calculate reflection if near boundary + double tolerance = pow(2, 1 / 6) * p.getSigma(); + if (distanceToBoundary < tolerance) { + Particle ghost{p}; + if (relevantIndex == 0) + ghost.setX({boundary + distanceToBoundary, p.getX().at(1), p.getX().at(2)}); + else if (relevantIndex == 1) + ghost.setX({p.getX().at(0), boundary + distanceToBoundary, p.getX().at(2)}); + else + ghost.setX({p.getX().at(0), p.getX().at(1), boundary + distanceToBoundary}); + calculator->calculateFPairwise(p, ghost); + } + } + } + + void + BoundaryHandler::handleReflection(LinkedCellContainer &linkedCellContainer, BoundaryDirection direction) const { + const int relevantIndex = retrieveRelevantPositionIndex(direction); + const bool isLowerBound = retrieveIsLowerBound(direction); + std::vector> boundaryCells = linkedCellContainer.getBoundaryCells( + boundaryWidthInNumCells); + + double boundaryPosition = properties.getDomain()[relevantIndex]; + // If selected index is lower boundary (lowerX, lowerY, lowerZ) + // for indexing x, y, z coordinate + //#pragma omp parallel for + for (const auto &cell: boundaryCells) { + for (auto &p: cell->getParticles()) { + double distanceToBoundary = isLowerBound ? p->getX().at(relevantIndex) : boundaryPosition - + p->getX().at(relevantIndex); + double tolerance = pow(2, 1.0 / 6) * p->getSigma(); + // only calculate reflection if near boundary + if (distanceToBoundary < tolerance) { + SPDLOG_DEBUG("Particle at position {} is near boundary", ArrayUtils::to_string(p->getX())); + Particle ghost{*p}; + ghost.setV({0, 0, 0}); + ghost.setF({0, 0, 0}); + const double ghostPosition = isLowerBound ? -distanceToBoundary : boundaryPosition + + distanceToBoundary; + if (relevantIndex == 0) + ghost.setX({ghostPosition, p->getX().at(1), p->getX().at(2)}); + else if (relevantIndex == 1) + ghost.setX({p->getX().at(0), ghostPosition, p->getX().at(2)}); + else + ghost.setX({p->getX().at(0), p->getX().at(1), ghostPosition}); + SPDLOG_DEBUG("Ghost particle created at position {}", ArrayUtils::to_string(ghost.getX())); + // Downcast from Calculator to LC_LJCalculator + auto lc_calculator = std::dynamic_pointer_cast(calculator); + if (lc_calculator) { + // If the downcast is successful, call the method + lc_calculator->calculateFPairwise(*p, ghost); + } else { + // Handle the error case where the downcast fails + SPDLOG_ERROR("Failed to downcast from Calculator to LC_LJCalculator"); + } + } + } + } + } + + void BoundaryHandler::handleOutflow(ParticleContainer &container, BoundaryDirection direction) const { + const int relevantIndex = retrieveRelevantPositionIndex(direction); + const bool isLowerBound = retrieveIsLowerBound(direction); + + for (auto &p: container) { + auto &relevantParticlePositionValue = p.getX().at(relevantIndex); + if ((isLowerBound && relevantParticlePositionValue <= 0) || + (!isLowerBound && relevantParticlePositionValue >= properties.getDomain()[relevantIndex])) { + container.deleteParticle(p); + } + } + } + + void BoundaryHandler::handleOutflow(LinkedCellContainer &linkedCellContainer, BoundaryDirection direction) const { + const int relevantIndex = retrieveRelevantPositionIndex(direction); + const bool isLowerBound = retrieveIsLowerBound(direction); + std::vector> boundaryCells = linkedCellContainer.getBoundaryCells( + boundaryWidthInNumCells); + + for (const auto &cell: boundaryCells) { + for (auto &p: cell->getParticles()) { + auto &relevantParticlePositionValue = p->getX().at(relevantIndex); + if ((isLowerBound && relevantParticlePositionValue <= 0) || + (!isLowerBound && relevantParticlePositionValue >= properties.getDomain()[relevantIndex])) { + linkedCellContainer.removeParticle(p); + } + } + } + } + + void BoundaryHandler::handlePeriodic(ParticleContainer &container, BoundaryDirection direction) const { + const int relevantIndex = retrieveRelevantPositionIndex(direction); + const bool isLowerBound = retrieveIsLowerBound(direction); + + double boundary = properties.getDomain()[relevantIndex]; + // If selected index is lower boundary (lowerX, lowerY, lowerZ) + if (isLowerBound) { +//#pragma omp parallel for + for (auto &p: container) { + if (p.getX().at(relevantIndex) < 0) { + if (relevantIndex == 0) + p.setX({boundary + p.getX().at(0), p.getX().at(1), p.getX().at(2)}); + if (relevantIndex == 1) + p.setX({p.getX().at(0), boundary + p.getX().at(1), p.getX().at(2)}); + if (relevantIndex == 2) + p.setX({p.getX().at(0), p.getX().at(1), boundary + p.getX().at(2)}); + } + } + return; + } +//#pragma omp parallel for + for (auto &p: container) { + if (p.getX().at(relevantIndex) >= boundary) { + if (relevantIndex == 0) + p.setX({p.getX().at(0) - boundary, p.getX().at(1), p.getX().at(2)}); + if (relevantIndex == 1) + p.setX({p.getX().at(0), p.getX().at(1) - boundary, p.getX().at(2)}); + if (relevantIndex == 2) + p.setX({p.getX().at(0), p.getX().at(1), p.getX().at(2) - boundary}); + } + } + } + + void BoundaryHandler::handlePeriodic(LinkedCellContainer &linkedCellContainer, BoundaryDirection direction) const { + const int relevantIndex = retrieveRelevantPositionIndex(direction); + const bool isLowerBound = retrieveIsLowerBound(direction); + std::vector> boundaryCells = linkedCellContainer.getBoundaryCells( + boundaryWidthInNumCells); + + const double boundary = properties.getDomain()[relevantIndex]; + // If selected index is lower boundary (lowerX, lowerY, lowerZ) + for (const auto &cell: boundaryCells) { + for (auto &p: cell->getParticles()) { + const double newParticlePosition = isLowerBound ? boundary + p->getX().at(relevantIndex) : + p->getX().at(relevantIndex) - boundary; + if (p->getX().at(relevantIndex) < 0) { + if (relevantIndex == 0) + p->setX({newParticlePosition, p->getX().at(1), p->getX().at(2)}); + if (relevantIndex == 1) + p->setX({p->getX().at(0), newParticlePosition, p->getX().at(2)}); + if (relevantIndex == 2) + p->setX({p->getX().at(0), p->getX().at(1), newParticlePosition}); + } + } + } + } + + bool BoundaryHandler::retrieveIsLowerBound(const BoundaryDirection &direction) const { + switch (direction) { + case BoundaryDirection::LEFT: + case BoundaryDirection::BOTTOM: + case BoundaryDirection::FRONT: + return true; + case BoundaryDirection::RIGHT: + case BoundaryDirection::TOP: + case BoundaryDirection::BACK: + return false; + default: + throw std::invalid_argument("Invalid direction " + std::to_string(static_cast(direction))); + } + } + + int BoundaryHandler::retrieveRelevantPositionIndex(const BoundaryDirection &direction) const { + switch (direction) { + case BoundaryDirection::LEFT: + case BoundaryDirection::RIGHT: + return 0; + case BoundaryDirection::BOTTOM: + case BoundaryDirection::TOP: + return 1; + case BoundaryDirection::FRONT: + case BoundaryDirection::BACK: + return 2; + default: + throw std::invalid_argument("Invalid direction " + std::to_string(static_cast(direction))); + } + } +} \ No newline at end of file diff --git a/src/boundaries/BoundaryHandler.h b/src/boundaries/BoundaryHandler.h new file mode 100644 index 000000000..4fed89b60 --- /dev/null +++ b/src/boundaries/BoundaryHandler.h @@ -0,0 +1,102 @@ +// +// Created by houj on 5/23/24. +// + +#pragma once + +#include +#include + +#include "BoundaryEnums.h" +#include "BoundaryProperties.h" +#include "../objects/ParticleContainer.h" +#include "calculators/Calculator.h" + + +namespace boundaries { + /** + * @class BoundaryHandler + * @brief Handles boundary conditions for a 2D simulation domain. + */ + class BoundaryHandler{ + public: + /** + * @brief Constructor for BoundaryHandler. + * + * @param properties The boundary properties. + * @param calculator Pointer to the calculator used for force calculations. + */ + BoundaryHandler(BoundaryProperties properties, std::shared_ptr calculator) + : properties(std::move(properties)), calculator(std::move(calculator)) {} + + /** + * @brief Pre-processes boundaries before the main particle calculations. + * + * @param container The particle container holding all particles. + */ + void preProcessBoundaries(ParticleContainer &container) const; + /** + * @brief Post-processes boundaries after the main particle calculations. + * + * @param container The particle container holding all particles. + */ + void postProcessBoundaries(ParticleContainer &container) const; + + void preProcessBoundaries(LinkedCellContainer &linkedCellContainer) const; + + void postProcessBoundaries(LinkedCellContainer &linkedCellContainer) const; + + + private: + const BoundaryProperties properties; + std::shared_ptr calculator; + + /** + * @brief Handles reflection for particles near the reflecting boundary. + * + * @param container The particle container holding all particles. + * @param direction The boundary direction to process. + */ + void handleReflection(ParticleContainer &container, BoundaryDirection direction) const; + /** + * @brief Handles outflow for particles outside the domain. + * + * @param container The particle container holding all particles. + * @param direction The boundary direction to process. + */ + void handleOutflow(ParticleContainer &container, BoundaryDirection direction) const; + /** + * @brief Handles periodic for particles outside the domain. + * For x-domain {0, 20} 0 will be included, 20 will be excluded -> [0, 20) + * + * @param container The particle container holding all particles. + * @param direction The boundary direction to process. + */ + void handlePeriodic(ParticleContainer &container, BoundaryDirection direction) const; + + void handleReflection(LinkedCellContainer &linkedCellContainer, BoundaryDirection direction) const; + + void handleOutflow(LinkedCellContainer &linkedCellContainer, BoundaryDirection direction) const; + + void handlePeriodic(LinkedCellContainer &linkedCellContainer, BoundaryDirection direction) const; + + + //---------------------------------------Helper methods--------------------------------------- + int retrieveRelevantPositionIndex(const BoundaryDirection &direction) const; + + bool retrieveIsLowerBound(const BoundaryDirection &direction) const; + +/** + * Class section end + * + * + * + * --------------------------------------------TEST SECTION------------------------------------------------------------ + * To be able to use the private methods and attributes in testing, FRIEND_TESTs are declared here. + */ + FRIEND_TEST(BoundaryHandlerTest, BasicReflection); + FRIEND_TEST(BoundaryHandlerTest, CornerReflection); + FRIEND_TEST(BoundaryHandlerTest, BasicOutflow); + FRIEND_TEST(BoundaryHandlerTest, MixedBoundaries); + }; +}; \ No newline at end of file diff --git a/src/boundaries/BoundaryProperties.h b/src/boundaries/BoundaryProperties.h new file mode 100644 index 000000000..9bec75f2e --- /dev/null +++ b/src/boundaries/BoundaryProperties.h @@ -0,0 +1,78 @@ +// +// Created by Ujin on 27.05.2024. +// +#pragma once +#include +#include +#include "BoundaryEnums.h" + +namespace boundaries { + /** + * @class BoundaryProperties + * @brief Holds the properties of the simulation boundaries. + */ + class BoundaryProperties{ + public: + /** + * @brief Constructor for BoundaryProperties with 2D domain parameter. + * + * @param domain The domain size. + * @param boundaryMap A map defining the boundary types for each direction. + */ + BoundaryProperties(std::array domain, const std::map& boundaryMap) + : domain({domain[0], domain[1], domain[2]}), boundaryMap(getBoundaryMapWithDefaults(boundaryMap)) {} + + /** + * @brief Gets the domain size. + * + * @return The 3D domain size. + */ + [[nodiscard]] const std::array &getDomain() const { + return domain; + } + + /** + * @brief Gets the boundary map. + * + * @return The boundary map. + */ + [[nodiscard]] const std::map &getBoundaryMap() const { + return boundaryMap; + } + + private: + const std::array domain; + + const std::map boundaryMap; + + /** + * @brief Generates a boundary map with default values. + * + * @param originalMap The original boundary map. + * @return The boundary map with remaining directions filled with "Reflecting" + * Since it's in 2D, the Front and Back + */ + static std::map getBoundaryMapWithDefaults(const std::map& originalMap) { + std::map mapWithDefaults = originalMap; + + // Ensure FRONT and BACK are set to OFF if not already present + if (mapWithDefaults.find(BoundaryDirection::FRONT) == mapWithDefaults.end()) { + mapWithDefaults[BoundaryDirection::FRONT] = BoundaryType::OFF; + } + if (mapWithDefaults.find(BoundaryDirection::BACK) == mapWithDefaults.end()) { + mapWithDefaults[BoundaryDirection::BACK] = BoundaryType::OFF; + } + + // Set default for remaining directions to REFLECTING if not already present + for (const auto &direction: {BoundaryDirection::TOP, + BoundaryDirection::BOTTOM, + BoundaryDirection::LEFT, + BoundaryDirection::RIGHT}) { + if (mapWithDefaults.find(direction) == mapWithDefaults.end()) { + mapWithDefaults[direction] = BoundaryType::REFLECTING; + } + } + return mapWithDefaults; + } + }; +} \ No newline at end of file diff --git a/src/calculators/Calculator.h b/src/calculators/Calculator.h index 1bfefb887..9bd8417b7 100644 --- a/src/calculators/Calculator.h +++ b/src/calculators/Calculator.h @@ -1,3 +1,4 @@ + // // Created by kimj2 on 01.05.2024. // @@ -5,8 +6,10 @@ #pragma once #include "../objects/ParticleContainer.h" +#include "../objects/LinkedCellContainer.h" #include "../utils/ArrayUtils.h" #include +#include "spdlog/spdlog.h" namespace calculators { /** @@ -33,10 +36,59 @@ namespace calculators { */ virtual void calculate(ParticleContainer &particleContainer, double delta_t) { calculateF(particleContainer); + if (std::abs(g_grav) > COMPARISON_TOLERANCE) { + calculateGravity(particleContainer); + } calculateX(particleContainer, delta_t); calculateV(particleContainer, delta_t); } + virtual void calculateLC(LinkedCellContainer &linkedCellContainer, double delta_t) = 0; + + /** + * @brief Performs the gravity force calculation on the particles in the container in y-direction + * @param particleContainer The container of particles to perform the calculations on. + */ + void calculateGravity(ParticleContainer &particleContainer) { + for (Particle &p: particleContainer) { + double grav_force = p.getM() * g_grav; + const std::array newForce{p.getF()[0], p.getF()[1] + grav_force, p.getF()[2]}; + SPDLOG_DEBUG("Updating particle's force {} with new force including gravity {}", + ArrayUtils::to_string(p.getF()), ArrayUtils::to_string(newForce)); + p.setF(newForce); + } + } + + /** + * @param gravity The g_grav value + */ + void setGravity(double g_arg) { + g_grav = g_arg; + } + + /** + * @brief Calculates the forces acting on particles. + * + * This method is responsible for calculating the forces acting on all particles in the provided particle container. + * + * @param particleContainer The container of particles to calculate the forces for. + */ + virtual void calculateF(ParticleContainer &particleContainer) { +#pragma omp parallel for + for (auto &p: particleContainer) { + p.setOldF(p.getF()); // Update oldF with currentF + p.setF({0, 0, 0}); // Reset F to zeros + } + + // Iterate over all unique pairs of particles +#pragma omp parallel for + for (auto pair = particleContainer.pair_begin(); pair != particleContainer.pair_end(); ++pair) { + Particle &particle1 = pair->first.get(); + Particle &particle2 = pair->second.get(); + calculateFPairwise(particle1, particle2); + } + } + /** * @brief Calculates the new velocities of particles. * @@ -46,7 +98,7 @@ namespace calculators { * @param delta_t The time step used for the calculations. */ virtual void calculateV(ParticleContainer &particleContainer, double delta_t) { - #pragma omp parallel for +#pragma omp parallel for for (auto &p: particleContainer) { // Get the current position, velocity, force and mass of the particle std::array v = p.getV(); @@ -64,7 +116,17 @@ namespace calculators { const std::array delta_v = ArrayUtils::elementWiseScalarOp(delta_t / m, avg_f, std::multiplies<>()); v = ArrayUtils::elementWisePairOp(v, delta_v, std::plus<>()); + p.setV(v); + if (!warned) { + for (int i = 0; i < 3; i++) { + if (abs(v[i]) > 0.56121 / (2 * delta_t)) { + warned = true; + SPDLOG_WARN("Particles might be too fast and fly out of reflecting boundaries!\n" + "Maybe try a smaller delta_t"); + } + } + } } } @@ -77,7 +139,7 @@ namespace calculators { * @param delta_t The time step used for the calculations. */ virtual void calculateX(ParticleContainer &particleContainer, double delta_t) { - #pragma omp parallel for +#pragma omp parallel for for (auto &p: particleContainer) { // Get the current position, velocity, force and mass of the particle std::array x = p.getX(); @@ -104,8 +166,13 @@ namespace calculators { p.setX(x); } } - + + virtual void calculateFPairwise(Particle &particle1, Particle &particle2) const {}; + protected: + constexpr static const double COMPARISON_TOLERANCE = 10e-6; + double g_grav = 0.0; + /** * @brief Determines if two points are far apart based on a given threshold. * @@ -118,7 +185,7 @@ namespace calculators { * @param threshold The threshold value to compare the Manhattan distance with. * @return True if the points are considered "far", false otherwise. */ - virtual bool isFar(const std::array &x1, const std::array &x2, double threshold) { + virtual bool isFar(const std::array &x1, const std::array &x2, double threshold) const { const std::array absDiff = ArrayUtils::elementWisePairOp(x1, x2, [](double a, double b) { return std::abs(a - b); @@ -129,13 +196,6 @@ namespace calculators { } private: - /** - * @brief Calculates the forces acting on particles. - * - * This method is responsible for calculating the forces acting on all particles in the provided particle container. - * - * @param particleContainer The container of particles to calculate the forces for. - */ - virtual void calculateF(ParticleContainer &particleContainer) = 0; + bool warned = false; }; -} +}; diff --git a/src/calculators/DummyCalculator.cpp b/src/calculators/DummyCalculator.cpp deleted file mode 100644 index a99ad561b..000000000 --- a/src/calculators/DummyCalculator.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// -// Created by kimj2 on 01.05.2024. -// -#include "DummyCalculator.h" - -namespace calculators { - - void DummyCalculator::calculate(ParticleContainer &particleContainer, double delta_t) { - calculateF(particleContainer); - calculateX(particleContainer, delta_t); - calculateV(particleContainer, delta_t); - } - - void DummyCalculator::calculateF(ParticleContainer &particleContainer) {} - - void DummyCalculator::calculateX(ParticleContainer &particleContainer, double delta_t) {} - - void DummyCalculator::calculateV(ParticleContainer &particleContainer, double delta_t) {} -} diff --git a/src/calculators/DummyCalculator.h b/src/calculators/DummyCalculator.h deleted file mode 100644 index 4f9568905..000000000 --- a/src/calculators/DummyCalculator.h +++ /dev/null @@ -1,60 +0,0 @@ -// -// Created by kimj2 on 01.05.2024. -// - -#pragma once - -#include "../objects/ParticleContainer.h" -#include "Calculator.h" - -namespace calculators { - /** - * @class DummyCalculator - * @brief Concrete calculator class that does nothing. - * - * This class is a placeholder for a calculator that does not perform any actual calculations - * and only exists to test the strategy pattern of calculators. - * It inherits from the `Calculator` base class and provides empty implementations for the `calculate`, `calculateX`, `calculateF`, and `calculateV` methods. - */ - class DummyCalculator : public Calculator { - public: - DummyCalculator() = default; - - /** - * - * This method is a dummy method and does nothing. - * - * @param particleContainer The container of particles to perform the calculations on. - * @param delta_t The time step used for the calculations. - */ - void calculate(ParticleContainer &particleContainer, double delta_t); - - private: - /** - * - * This method is a dummy method and does nothing. - * - * @param particleContainer The container of particles to calculate the forces for. - */ - void calculateF(ParticleContainer &particleContainer); - - /** - * - * This method is a dummy method and does nothing. - * - * @param particleContainer The container of particles to update the positions of. - * @param delta_t The time step used for the calculations. - */ - void calculateX(ParticleContainer &particleContainer, double delta_t); - - /** - * @brief Calculates the new velocities of particles. - * - * This method is a placeholder and does nothing. It is intended to be overridden by derived classes to provide actual velocity calculation logic. - * - * @param particleContainer The container of particles to update the velocities of. - * @param delta_t The time step used for the calculations. - */ - void calculateV(ParticleContainer &particleContainer, double delta_t); - }; -} \ No newline at end of file diff --git a/src/calculators/LC_LJCalculator.cpp b/src/calculators/LC_LJCalculator.cpp new file mode 100644 index 000000000..85de30d7a --- /dev/null +++ b/src/calculators/LC_LJCalculator.cpp @@ -0,0 +1,214 @@ +#include "LC_LJCalculator.h" +#include "spdlog/spdlog.h" + +namespace calculators { + + void LC_LJCalculator::calculateLC(LinkedCellContainer &linkedCellContainer, double delta_t) { + calculateLC_F(linkedCellContainer); + if (std::abs(this->g_grav) > COMPARISON_TOLERANCE) // If gravity is not zero, calculate gravity + calculateGravityLC(linkedCellContainer); + calculateLC_X(linkedCellContainer, delta_t); + calculateLC_V(linkedCellContainer, delta_t); + linkedCellContainer.updateCells(); + } + + void LC_LJCalculator::calculateGravityLC(LinkedCellContainer &linkedCellContainer) { + for (auto &p: linkedCellContainer) { + const double grav_force = p->getM() * this->g_grav; + const std::array newForce{p->getF()[0], p->getF()[1] + grav_force, p->getF()[2]}; + SPDLOG_DEBUG("Applying gravity {}. Current F of Particle at {} is ({}, {}, {})", + grav_force, + ArrayUtils::to_string(p->getX()), + p->getF()[0], p->getF()[1], p->getF()[2]); + p->setF(newForce); + SPDLOG_DEBUG("Updated F of Particle at {} to ({}, {}, {})", + ArrayUtils::to_string(p->getX()), + p->getF()[0], p->getF()[1], p->getF()[2]); + } + } + + void LC_LJCalculator::calculateLC_F(LinkedCellContainer &linkedCellContainer) { + for (auto &p: linkedCellContainer) { + p->setOldF(p->getF()); // Update oldF with currentF + p->setF({0, 0, 0}); // Reset F to zeros + SPDLOG_DEBUG("Reset force of Particle at {} to ({}, {}, {})", ArrayUtils::to_string(p->getX()), 0, 0, 0); + SPDLOG_DEBUG("Updated old force of Particle at {} to {}", + ArrayUtils::to_string(p->getX()), + ArrayUtils::to_string(p->getOldF())); + } + + for (auto &particle1: linkedCellContainer) { + std::array x1 = particle1->getX(); + SPDLOG_DEBUG("Processing Particle at position ({}, {}, {})", x1[0], x1[1], x1[2]); + std::vector> &neighboringCells = linkedCellContainer.getNeighboringCellsIncludingSelf(*particle1); + for (auto &cell : neighboringCells) { + SPDLOG_DEBUG("Processing Cell at index ({}, {}, {})", cell->getIndex()[0], cell->getIndex()[1], + cell->getIndex()[2]); + for (auto &particle2 : cell->getParticles()) { + if (particle1 == particle2 || particle1->getID() > particle2->getID()) { + continue; // Skip the force calculation for the same particle or duplicate pair + } + + // LJ force calculation + const std::array x2 = particle2->getX(); + + // Calculate the distance vector and its norm + const std::array dx = ArrayUtils::elementWisePairOp(x1, x2, std::minus<>()); + const double distance = ArrayUtils::L2Norm(dx); + + double epsilon = pow((particle1->getEpsilon() * particle2->getEpsilon()), 0.5); + double sigma = 0.5 * (particle1->getSigma() + particle2->getSigma()); + // Calculate the force between the two particles + const double forceMagnitude = -(24 * epsilon / (distance * distance)) * + ((pow(sigma / distance, 6) - 2 * pow(sigma / distance, 12))); + + std::array force = ArrayUtils::elementWiseScalarOp(forceMagnitude, dx, + std::multiplies<>()); + + // Check if force is NaN + if (std::isnan(force[0]) || std::isnan(force[1]) || std::isnan(force[2])) { + SPDLOG_ERROR("NaN force detected! epsilon: {}, sigma: {}, distance: {}, dx: ({}, {}, {})", + epsilon, sigma, distance, dx[0], dx[1], dx[2]); + } + + // Add the force to the first particle and subtract it from the second particle (Newton's Third Law) + const std::array newF1 = ArrayUtils::elementWisePairOp(particle1->getF(), force, + std::plus<>()); + const std::array newF2 = ArrayUtils::elementWisePairOp(particle2->getF(), force, + std::minus<>()); + SPDLOG_DEBUG("Updating force of P1 at {} from {} to {}", + ArrayUtils::to_string(particle1->getX()), + ArrayUtils::to_string(particle1->getF()), + ArrayUtils::to_string(newF1)); + particle1->setF(newF1); + SPDLOG_DEBUG("Updating force of P2 at {} from {} to {}", + ArrayUtils::to_string(particle2->getX()), + ArrayUtils::to_string(particle2->getF()), + ArrayUtils::to_string(newF2)); + particle2->setF(newF2); + } + } + } + } + + void LC_LJCalculator::calculateLC_X(LinkedCellContainer &linkedCellContainer, double delta_t) { + for (auto &p: linkedCellContainer) { + // Get the current position, velocity, force and mass of the particle + std::array x = p->getX(); + const std::array v = p->getV(); + const std::array f = p->getF(); + + const double m = p->getM(); + + // Calculate the acceleration + const std::array a = ArrayUtils::elementWiseScalarOp(1.0 / m, f, std::multiplies<>()); + + if (std::isnan(a[0]) || std::isnan(a[1]) || std::isnan(a[2])) { + SPDLOG_ERROR("NaN acceleration detected! f: ({}, {}, {}), m: {}", f[0], f[1], f[2], m); + } + + // Update the particles new position using the Velocity-Störmer-Verlet method + const std::array v_summand = ArrayUtils::elementWiseScalarOp(delta_t, v, + std::multiplies<>()); + const std::array a_summand = ArrayUtils::elementWiseScalarOp((delta_t * delta_t / 2), a, + std::multiplies<>()); + // Combine v_summand and a_summand into a single summand + const std::array summand = ArrayUtils::elementWisePairOp(v_summand, a_summand, + std::plus<>()); + + x = ArrayUtils::elementWisePairOp(x, summand, std::plus<>()); + + if (std::isnan(x[0]) || std::isnan(x[1]) || std::isnan(x[2])) { + SPDLOG_ERROR("NaN position detected! x: ({}, {}, {}), summand: ({}, {}, {})", x[0], x[1], x[2], + summand[0], summand[1], summand[2]); + } + SPDLOG_DEBUG("Updating position of Particle at {} with velocities {} and force{} to new position {}", + ArrayUtils::to_string(p->getX()), + ArrayUtils::to_string(v), + ArrayUtils::to_string(f), + ArrayUtils::to_string(x)); + p->setX(x); + } + } + + void LC_LJCalculator::calculateLC_V(LinkedCellContainer &linkedCellContainer, double delta_t) { + for (auto &p: linkedCellContainer) { + // Get the current position, velocity, force and mass of the particle + std::array v = p->getV(); + const std::array f = p->getF(); + const std::array old_f = p->getOldF(); + const double m = p->getM(); + + // Calculate the average force + std::array avg_f = ArrayUtils::elementWisePairOp( + f, old_f, + [](double a, double b) { return (a + b) / 2.0; } // Lambda function to calculate average + ); + + if (std::isnan(avg_f[0]) || std::isnan(avg_f[1]) || std::isnan(avg_f[2])) { + SPDLOG_ERROR("NaN average force detected! f: ({}, {}, {}), old_f: ({}, {}, {})", f[0], f[1], f[2], + old_f[0], old_f[1], old_f[2]); + } + + // Update the particles new velocity using the Velocity-Störmer-Verlet method + const std::array delta_v = ArrayUtils::elementWiseScalarOp(delta_t / m, avg_f, + std::multiplies<>()); + v = ArrayUtils::elementWisePairOp(v, delta_v, std::plus<>()); + + if (std::isnan(v[0]) || std::isnan(v[1]) || std::isnan(v[2])) { + SPDLOG_ERROR("NaN velocity detected! v: ({}, {}, {}), delta_v: ({}, {}, {})", v[0], v[1], v[2], + delta_v[0], delta_v[1], delta_v[2]); + } + + SPDLOG_DEBUG("Updating velocity of Particle at {} with current force {} and old force{} to new velocity {}", + ArrayUtils::to_string(p->getX()), + ArrayUtils::to_string(f), + ArrayUtils::to_string(old_f), + ArrayUtils::to_string(v)); + p->setV(v); + } + } + + void LC_LJCalculator::calculateFPairwise(Particle &particle1, Particle &particle2) { + // Get the positions and masses of the two particles + const std::array x1 = particle1.getX(); + const std::array x2 = particle2.getX(); + + SPDLOG_DEBUG("Calculating pairwise force between particles at positions P1 {} and P2 {}", + ArrayUtils::to_string(x1), + ArrayUtils::to_string(x2)); + + // Calculate the distance vector and its norm + const std::array dx = ArrayUtils::elementWisePairOp(x1, x2, std::minus<>()); + const double distance = ArrayUtils::L2Norm(dx); + if (distance == 0.0) + return; + + double epsilon = pow((particle1.getEpsilon() * particle2.getEpsilon()), 0.5); + double sigma = 0.5 * (particle1.getSigma() + particle2.getSigma()); + // Calculate the force between the two particles + const double forceMagnitude = -(24 * epsilon / (distance * distance)) * + ((pow(sigma / distance, 6) - 2 * pow(sigma / distance, 12))); + std::array force = ArrayUtils::elementWiseScalarOp(forceMagnitude, dx, + std::multiplies<>()); + // Limitation of Force so they don't move too quickly + for (int i = 0; i < 3; i++) { + double f = force[i]; + if (f > 20000) + force[i] = 20000; + if (f < -20000) + force[i] = -20000; + } + // Add the force to the first particle and subtract it from the second particle (Newton's Third Law) + const std::array newF1 = ArrayUtils::elementWisePairOp(particle1.getF(), force, + std::plus<>()); + const std::array newF2 = ArrayUtils::elementWisePairOp(particle2.getF(), force, + std::minus<>()); + SPDLOG_DEBUG("Updating force of P1 from {} to {}", ArrayUtils::to_string(particle1.getF()), + ArrayUtils::to_string(newF1)); + particle1.setF(newF1); + SPDLOG_DEBUG("Updating force of P2 from {} to {}", ArrayUtils::to_string(particle2.getF()), + ArrayUtils::to_string(newF2)); + particle2.setF(newF2); + } +} diff --git a/src/calculators/LC_LJCalculator.h b/src/calculators/LC_LJCalculator.h new file mode 100644 index 000000000..aba62a01a --- /dev/null +++ b/src/calculators/LC_LJCalculator.h @@ -0,0 +1,22 @@ +#pragma once + +#include "../objects/LinkedCellContainer.h" +#include "Calculator.h" + +namespace calculators { + + class LC_LJCalculator : public Calculator { + + public: + + LC_LJCalculator() = default; + + void calculateLC(LinkedCellContainer &linkedCellContainer, double delta_t) override; + void calculateLC_X(LinkedCellContainer &linkedCellContainer, double delta_t); + void calculateLC_V(LinkedCellContainer &linkedCellContainer, double delta_t); + void calculateLC_F(LinkedCellContainer &linkedCellContainer); + void calculateFPairwise(Particle &particle1, Particle &particle2); + + void calculateGravityLC(LinkedCellContainer &linkedCellContainer); + }; +} diff --git a/src/calculators/LJCalculator.cpp b/src/calculators/LJCalculator.cpp index 8d39ef1b5..37525af8c 100644 --- a/src/calculators/LJCalculator.cpp +++ b/src/calculators/LJCalculator.cpp @@ -9,43 +9,41 @@ namespace calculators { - void LJCalculator::calculateF(ParticleContainer &particleContainer) { - #pragma omp parallel for - for (auto & p : particleContainer) { - p.setOldF(p.getF()); // Update oldF with currentF - p.setF({0, 0, 0}); // Reset F to zeros - } - - // Iterate over all unique pairs of particles - #pragma omp parallel for - for (auto pair = particleContainer.pair_begin(); pair != particleContainer.pair_end(); ++pair) { - // Get both particles - Particle &particle1 = pair->first.get(); - Particle &particle2 = pair->second.get(); - - // Get the positions and masses of the two particles - const std::array x1 = particle1.getX(); - const std::array x2 = particle2.getX(); - - if (isFar(x1, x2, threshold)) continue; - - // Calculate the distance vector and its norm - const std::array dx = ArrayUtils::elementWisePairOp(x1, x2, std::minus<>()); - const double distance = ArrayUtils::L2Norm(dx); - - // Calculate the force between the two particles - const double forceMagnitude = -(24 * epsilon / (distance * distance)) * - ((pow(sigma / distance, 6) - 2 * pow(sigma / distance, 12))); - std::array force = ArrayUtils::elementWiseScalarOp(forceMagnitude, dx, - std::multiplies<>()); - - // Add the force to the first particle and subtract it from the second particle (Newton's Third Law) - const std::array newF1 = ArrayUtils::elementWisePairOp(particle1.getF(), force, - std::plus<>()); - const std::array newF2 = ArrayUtils::elementWisePairOp(particle2.getF(), force, - std::minus<>()); - particle1.setF(newF1); - particle2.setF(newF2); + void LJCalculator::calculateFPairwise(Particle &particle1, Particle &particle2) const { + // Get the positions and masses of the two particles + const std::array x1 = particle1.getX(); + const std::array x2 = particle2.getX(); + + if (isFar(x1, x2, threshold)) + return; + + // Calculate the distance vector and its norm + const std::array dx = ArrayUtils::elementWisePairOp(x1, x2, std::minus<>()); + const double distance = ArrayUtils::L2Norm(dx); + if (distance == 0.0) + return; + + double epsilon = pow((particle1.getEpsilon() * particle2.getEpsilon()), 0.5); + double sigma = 0.5 * (particle1.getSigma() + particle2.getSigma()); + // Calculate the force between the two particles + const double forceMagnitude = -(24 * epsilon / (distance * distance)) * + ((pow(sigma / distance, 6) - 2 * pow(sigma / distance, 12))); + std::array force = ArrayUtils::elementWiseScalarOp(forceMagnitude, dx, + std::multiplies<>()); + // Limitation of Force so they don't move too quickly + for (int i = 0; i < 3; i++) { + double f = force[i]; + if (f > 20000) + force[i] = 20000; + if (f < -20000) + force[i] = -20000; } + // Add the force to the first particle and subtract it from the second particle (Newton's Third Law) + const std::array newF1 = ArrayUtils::elementWisePairOp(particle1.getF(), force, + std::plus<>()); + const std::array newF2 = ArrayUtils::elementWisePairOp(particle2.getF(), force, + std::minus<>()); + particle1.setF(newF1); + particle2.setF(newF2); } -} +} \ No newline at end of file diff --git a/src/calculators/LJCalculator.h b/src/calculators/LJCalculator.h index 7fe28a4e0..3a0f3e692 100644 --- a/src/calculators/LJCalculator.h +++ b/src/calculators/LJCalculator.h @@ -16,8 +16,6 @@ namespace calculators { */ class LJCalculator : public Calculator { private: - const double sigma; - const double epsilon; const double threshold; public: @@ -26,13 +24,17 @@ namespace calculators { * * Initializes the SVCalculator object. */ - LJCalculator(double sigma, double epsilon, double threshold) : sigma(sigma), epsilon(epsilon), threshold(threshold) {} + LJCalculator(double threshold) : threshold(threshold) {} /** - * Calculates the force between all pairs of unique particles considering the third Newton's law. + * Calculates the force between two particles considering the third Newton's law. * * @param particleContainer The ParticleContainer containing the particles to calculate the forces for. */ - void calculateF(ParticleContainer &particleContainer) override; + void calculateFPairwise(Particle &particle1, Particle &particle2) const override; + + void calculateLC(LinkedCellContainer &linkedCellContainer, double delta_t) override { + // Implementation of the calculateLC function + } }; -} +} \ No newline at end of file diff --git a/src/calculators/SVCalculator.cpp b/src/calculators/SVCalculator.cpp index 989af11db..10b4e8b60 100644 --- a/src/calculators/SVCalculator.cpp +++ b/src/calculators/SVCalculator.cpp @@ -5,45 +5,26 @@ namespace calculators { - void SVCalculator::calculate(ParticleContainer &particleContainer, double delta_t) { - calculateX(particleContainer, delta_t); - calculateF(particleContainer); - calculateV(particleContainer, delta_t); + void SVCalculator::calculateFPairwise(Particle &particle1, Particle &particle2) const { + // Get the positions and masses of the two particles + const std::array x1 = particle1.getX(); + const std::array x2 = particle2.getX(); + + const double m1 = particle1.getM(); + const double m2 = particle2.getM(); + + // Calculate the distance vector and its norm + const std::array dx = ArrayUtils::elementWisePairOp(x2, x1, std::minus<>()); + const double distance = ArrayUtils::L2Norm(dx); + + // Calculate the force between the two particles + const double scalar = (m1 * m2) / std::pow(distance, 3); + const std::array force = ArrayUtils::elementWiseScalarOp(scalar, dx, std::multiplies<>()); + + // Add the force to the first particle and subtract it from the second particle (Newton's Third Law) + const std::array newF1 = ArrayUtils::elementWisePairOp(particle1.getF(), force, std::plus<>()); + const std::array newF2 = ArrayUtils::elementWisePairOp(particle2.getF(), force, std::minus<>()); + particle1.setF(newF1); + particle2.setF(newF2); } - - void SVCalculator::calculateF(ParticleContainer &particleContainer) { - for (auto p = particleContainer.begin(); p != particleContainer.end(); ++p) { - p->setOldF(p->getF()); // Update oldF with currentF - p->setF({0, 0, 0}); // Reset F to zeros - } - - // Iterate over all unique pairs of particles - for (auto pair = particleContainer.pair_begin(); pair != particleContainer.pair_end(); ++pair) { - // Get both particles - Particle& particle1 = pair->first.get(); - Particle& particle2 = pair->second.get(); - - // Get the positions and masses of the two particles - const std::array x1 = particle1.getX(); - const std::array x2 = particle2.getX(); - - const double m1 = particle1.getM(); - const double m2 = particle2.getM(); - - // Calculate the distance vector and its norm - const std::array dx = ArrayUtils::elementWisePairOp(x2, x1, std::minus()); - const double distance = ArrayUtils::L2Norm(dx); - - // Calculate the force between the two particles - const double scalar = (m1 * m2) / std::pow(distance, 3); - const std::array force = ArrayUtils::elementWiseScalarOp(scalar, dx, std::multiplies()); - - // Add the force to the first particle and subtract it from the second particle (Newton's Third Law) - const std::array newF1 = ArrayUtils::elementWisePairOp(particle1.getF(), force, std::plus()); - const std::array newF2 = ArrayUtils::elementWisePairOp(particle2.getF(), force, std::minus()); - particle1.setF(newF1); - particle2.setF(newF2); - } - } -} - +} \ No newline at end of file diff --git a/src/calculators/SVCalculator.h b/src/calculators/SVCalculator.h index 9b3b77b7e..33c19d3e5 100644 --- a/src/calculators/SVCalculator.h +++ b/src/calculators/SVCalculator.h @@ -27,13 +27,20 @@ namespace calculators { * @param particleContainer The ParticleContainer containing the particles to update. * @param delta_t The time step used in the calculations. */ - void calculate(ParticleContainer &particleContainer, double delta_t) override; +// void calculate(ParticleContainer &particleContainer, double delta_t) override; /** * Calculates the force between all pairs of unique particles considering the third Newton's law. * * @param particleContainer The ParticleContainer containing the particles to calculate the forces for. */ - void calculateF(ParticleContainer &particleContainer) override; +// void calculateF(ParticleContainer &particleContainer) override; + +// void calculateReflection(Particle &p, Particle &ghost) override; + void calculateFPairwise(Particle &particle1, Particle &particle2) const override; + + void calculateLC(LinkedCellContainer &linkedCellContainer, double delta_t) override { + // Implementation of the calculateLC function + } }; } \ No newline at end of file diff --git a/src/calculators/Thermostat.cpp b/src/calculators/Thermostat.cpp new file mode 100644 index 000000000..593b08558 --- /dev/null +++ b/src/calculators/Thermostat.cpp @@ -0,0 +1,154 @@ +// +// Created by kimj2 on 11.06.2024. +// +#include "../objects/ParticleContainer.h" +#include "Thermostat.h" +#include "../utils/ArrayUtils.h" +#include "../utils/MaxwellBoltzmannDistribution.h" +#include "spdlog/spdlog.h" + +const double COMPARISON_TOLERANCE = 1e-9; + +void Thermostat::initializeTemp(ParticleContainer &particleContainer) const { + if (particleContainer.hasZeroVelocities()) { // Check if all velocities are zero + // Initialize velocities by applying Brownian motion + double maxwellBoltzmannFactor; + + for (auto &particle: particleContainer) { + maxwellBoltzmannFactor = sqrt(start_temp / particle.getM()); + + std::array v = particle.getV(); + const std::array deltaV = maxwellBoltzmannDistributedVelocity(maxwellBoltzmannFactor, 3); + + for (int i = 0; i < dimension; ++i) { + v[i] += deltaV[i]; + } + + particle.setV(v); + } + SPDLOG_INFO("Initialized velocities with Brownian motion"); + } + + // Velocity scaling to initial temperature + setTemp(particleContainer, start_temp); + SPDLOG_INFO("Scaled velocities to initial temperature"); +} + +void Thermostat::initializeTemp(LinkedCellContainer &linkedCellContainer) const { + if (linkedCellContainer.hasZeroVelocities()) { // Check if all velocities are zero + SPDLOG_INFO("All particles have zero velocities, initializing velocities with Brownian motion"); + // Initialize velocities by applying Brownian motion + double maxwellBoltzmannFactor; + + for (auto &particle: linkedCellContainer) { + maxwellBoltzmannFactor = sqrt(start_temp / particle->getM()); + + std::array v = particle->getV(); + const std::array deltaV = maxwellBoltzmannDistributedVelocity(maxwellBoltzmannFactor, 3); + + for (int i = 0; i < dimension; ++i) { + v[i] += deltaV[i]; + } + + particle->setV(v); + SPDLOG_DEBUG("Updated particle at position {} to new velocities {} (brownian motion)", + ArrayUtils::to_string(particle->getX()), ArrayUtils::to_string(particle->getV())); + + } + SPDLOG_INFO("Initialized velocities with Brownian motion"); + } + + // Velocity scaling to initial temperature + setTemp(linkedCellContainer, start_temp); + SPDLOG_INFO("Scaled velocities to initial temperature {}", start_temp); +} + +void Thermostat::setTempDirectly(ParticleContainer &particleContainer) const { + setTemp(particleContainer, target_temp); +} + + +void Thermostat::setTempDirectly(LinkedCellContainer &linkedCellContainer) const { + setTemp(linkedCellContainer, target_temp); +} + +void Thermostat::setTempGradually(ParticleContainer &particleContainer) const { + const double currentTemp = calculateCurrentTemp(particleContainer); + const double delta_temp = std::min(std::abs(target_temp - currentTemp), this->max_delta_temp); + const double updatedTemp = this->target_temp > currentTemp ? currentTemp + delta_temp : currentTemp - delta_temp; + setTemp(particleContainer, updatedTemp); +} + +void Thermostat::setTempGradually(LinkedCellContainer &linkedCellContainer) const { + const double currentTemp = calculateCurrentTemp(linkedCellContainer); + const double delta_temp = std::min(std::abs(target_temp - currentTemp), this->max_delta_temp); + const double updatedTemp = this->target_temp > currentTemp ? currentTemp + delta_temp : currentTemp - delta_temp; + setTemp(linkedCellContainer, updatedTemp); +} + +double Thermostat::calculateCurrentTemp(ParticleContainer &particleContainer) const { + double kinEnergy = calculateKinEnergy(particleContainer); + return 2.0 / (this->dimension * particleContainer.getSize()) * kinEnergy; +} + +double Thermostat::calculateCurrentTemp(LinkedCellContainer &linkedCellContainer) const { + double kinEnergy = calculateKinEnergy(linkedCellContainer); + return 2.0 / (this->dimension * linkedCellContainer.getSize()) * kinEnergy; +} + +//----------------------------------------Helper functions---------------------------------------------------- + + +double Thermostat::calculateKinEnergy(ParticleContainer &particleContainer) const { + double kinEnergy = 0.0; + for (auto &particle: particleContainer) { + kinEnergy += 0.5 * particle.getM() * ArrayUtils::dotProduct(particle.getV(), particle.getV()); + } + return kinEnergy; +} + +double Thermostat::calculateKinEnergy(LinkedCellContainer &linkedCellContainer) const { + double kinEnergy = 0.0; + for (auto &particle: linkedCellContainer) { + kinEnergy += 0.5 * particle->getM() * ArrayUtils::dotProduct(particle->getV(), particle->getV()); + } + return kinEnergy; +} + +void Thermostat::scaleV(double beta, ParticleContainer &particleContainer) const { + for (auto &particle: particleContainer) { + std::array v = particle.getV(); + v = beta * v; + particle.setV(v); + } +} + +void Thermostat::scaleV(double beta, LinkedCellContainer &linkedCellContainer) const { + for (auto &particle: linkedCellContainer) { + std::array v = particle->getV(); + v = beta * v; + particle->setV(v); + } +} + +void Thermostat::setTemp(ParticleContainer &particleContainer, double newTemp) const { + const double currentTemp = calculateCurrentTemp(particleContainer); + double beta; + if (std::abs(currentTemp) < COMPARISON_TOLERANCE) { // Check if currentTemp is zero + beta = sqrt(newTemp / COMPARISON_TOLERANCE); // or some default value + } else { + beta = sqrt(newTemp / currentTemp); + } + scaleV(beta, particleContainer); +} + +void Thermostat::setTemp(LinkedCellContainer &linkedCellContainer, double newTemp) const { + const double currentTemp = calculateCurrentTemp(linkedCellContainer); + double beta; + if (std::abs(currentTemp) < COMPARISON_TOLERANCE) { // Check if currentTemp is zero + beta = sqrt(newTemp / COMPARISON_TOLERANCE); // or some default value + } else { + beta = sqrt(newTemp / currentTemp); + } + scaleV(beta, linkedCellContainer); +} diff --git a/src/calculators/Thermostat.h b/src/calculators/Thermostat.h new file mode 100644 index 000000000..5449a5744 --- /dev/null +++ b/src/calculators/Thermostat.h @@ -0,0 +1,66 @@ +// +// Created by kimj2 on 11.06.2024. +// + +#pragma once + +#include "../objects/ParticleContainer.h" +#include "objects/LinkedCellContainer.h" + +class Thermostat { +public: + Thermostat() = default; + + Thermostat(double start_temp, double target_temp, int applyFrequency, double max_delta_temp, + int dimension) : + start_temp(start_temp), target_temp(target_temp), applyFrequency(applyFrequency), + max_delta_temp(max_delta_temp), dimension(dimension) {} + + void setTempDirectly(ParticleContainer &particleContainer) const; + void setTempDirectly(LinkedCellContainer &linkedCellContainer) const; + + void setTempGradually(ParticleContainer &particleContainer) const; + void setTempGradually(LinkedCellContainer &linkedCellContainer) const; + + void initializeTemp(ParticleContainer &particleContainer) const; + void initializeTemp(LinkedCellContainer &linkedCellContainer) const; + + double calculateCurrentTemp(ParticleContainer &particleContainer) const; + double calculateCurrentTemp(LinkedCellContainer &linkedCellContainer) const; + + [[nodiscard]] double getStartTemp() const { + return start_temp; + } + + [[nodiscard]] double getTargetTemp() const { + return target_temp; + } + + [[nodiscard]] int getApplyFrequency() const { + return applyFrequency; + } + + [[nodiscard]] double getMaxDeltaTemp() const { + return max_delta_temp; + } + + [[nodiscard]] int getDimension() const { + return dimension; + } + +private: + double start_temp; + double target_temp; + int applyFrequency; + double max_delta_temp; + int dimension; + + double calculateKinEnergy(ParticleContainer &particleContainer) const; + double calculateKinEnergy(LinkedCellContainer &linkedCellContainer) const; + + void scaleV(double beta, ParticleContainer &particleContainer) const; + void scaleV(double beta, LinkedCellContainer &linkedCellContainer) const; + + void setTemp(ParticleContainer &particleContainer, double newTemp) const; + void setTemp(LinkedCellContainer &linkedCellContainer, double newTemp) const; +}; \ No newline at end of file diff --git a/src/io/in/CuboidParameters.h b/src/io/in/CuboidParameters.h deleted file mode 100644 index 1766c512f..000000000 --- a/src/io/in/CuboidParameters.h +++ /dev/null @@ -1,61 +0,0 @@ -// -// Created by kimj2 on 07.05.2024. -// -#pragma once - -#include - -/** - * @struct CuboidParameters - * @brief Structure to hold the parameters for a cuboid in the simulation. - */ -struct CuboidParameters { - /** - * @brief Coordinate of the lower left front-side corner of the cuboid. - */ - std::array lowerLeftFrontCorner; - - /** - * @brief Number of particles in each dimension of the cuboid. - */ - std::array numParticlesPerDimension; - - /** - * @brief Distance between particles (mesh width of the grid). - */ - double distance; - - /** - * @brief Mass of one particle. - */ - double m; - - /** - * @brief Initial velocity of the particles in each dimension. - */ - std::array startV; - - /** - * @brief Mean-value of the velocity of the Brownian Motion. - */ - double meanV; - - - /** - * @brief Constructor to initialize the parameters. - * - * This constructor initializes the parameters for a cuboid in the simulation. - * - * @param llfCorner The coordinate of the lower left front-side corner of the cuboid. - * @param numParticles The number of particles in each dimension of the cuboid. - * @param pDistance The distance between particles (mesh width of the grid). - * @param pMass The mass of one particle. - * @param startV The initial velocity of the particles in each dimension. - * @param meanV The mean-value of the velocity of the Brownian Motion. - */ - CuboidParameters(std::array llfCorner, std::array numParticles, double pDistance, - double pMass, - std::array startV, double meanV) - : lowerLeftFrontCorner(llfCorner), numParticlesPerDimension(numParticles), distance(pDistance), - m(pMass), startV(startV), meanV(meanV){} -}; \ No newline at end of file diff --git a/src/io/in/FileReader.cpp b/src/io/in/FileReader.cpp deleted file mode 100644 index ef414a107..000000000 --- a/src/io/in/FileReader.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * FileReader.cpp - * - * Created on: 23.02.2010 - * Author: eckhardw - */ - -#include "FileReader.h" -#include "spdlog/spdlog.h" -#include -#include -#include -#include - -ParticleContainer FileReader::readFile(const std::string &filepath) { - auto lines = readFileLines(filepath); - - // Check if there are lines in the file - if (lines.empty()) { - SPDLOG_ERROR("File is empty: ", filepath); - throw std::runtime_error("File is empty: " + filepath); - } - - // Parse the data code - int dataCode; - try { - dataCode = std::stoi(lines[0]); - // Remove the first element of lines - lines.erase(lines.begin()); - } catch (const std::invalid_argument &e) { - throw std::runtime_error( - "Invalid data code in file '" + filepath + "': " + e.what() + ". Data code must be an integer."); - } catch (const std::out_of_range &e) { - throw std::runtime_error( - "Data code out of range in file '" + filepath + "': " + e.what() + ". Data code must be an integer."); - } - - // Log the data code - SPDLOG_INFO("Data Code of file '{}': {}", filepath, dataCode); - // Load particles or cuboid based on data code - ParticleContainer particleContainer; - switch (dataCode) { - case 0: - loadParticles(lines, particleContainer); - break; - case 1: - loadCuboids(lines, particleContainer); - break; - default: - SPDLOG_ERROR("Invalid data code in file '", filepath + "': Only data codes 0 and 1 are supported."); - throw std::runtime_error( - "Invalid data code in file '" + filepath + "': Only data codes 0 and 1 are supported."); - } - - return particleContainer; -} - -void FileReader::loadParticles(const std::vector &lines, ParticleContainer &particleContainer) { - std::array x{}, v{}; - double m; - - int num_particles = std::stoi(lines[0]); - SPDLOG_DEBUG("Number of particles to load: {}", num_particles); - - for (int i = 1; i < num_particles + 1; ++i) { - std::istringstream datastream(lines[i]); - parseDataFromLine(datastream, x); - parseDataFromLine(datastream, v); - datastream >> m; - - ParticleParameters parameters(x, v, m, 0, 0); - Particle newParticle = ParticleGenerator::generateParticle(parameters); - particleContainer.addParticle(newParticle); - } - - particleContainer.initializePairs(); - particleContainer.setVolumes(); -} - -void FileReader::loadCuboids(const std::vector &lines, ParticleContainer &particles) { - SPDLOG_INFO("Starting to load cuboids..."); - std::array llf{}, startV{}; - std::array numParticles{}; - double distance, mass, meanV; - - int num_cuboids = std::stoi(lines[0]); - SPDLOG_DEBUG("Number of cuboids to load: {}", num_cuboids); - - for (int i = 1; i < num_cuboids + 1; ++i) { - std::istringstream datastream(lines[i]); - parseDataFromLine(datastream, llf); - parseDataFromLine(datastream, numParticles); - datastream >> distance >> mass; - parseDataFromLine(datastream, startV); - datastream >> meanV; - - if (datastream.fail()) { - SPDLOG_ERROR("Error reading file: unexpected data format on line {}", i + 1); - exit(-1); - } - - CuboidParameters cuboidParams(llf, numParticles, distance, mass, startV, meanV); - ParticleGenerator::generateCuboid(cuboidParams, particles); - SPDLOG_DEBUG("Completed generating cuboid {}", i); - particles.initializePairs(); - } - SPDLOG_INFO("Finished loading cuboids!"); -} -// ------------------------------------------- Helper methods -------------------------------------------------- -template -void FileReader::parseDataFromLine(std::istringstream &datastream, std::array &data) { - for (auto &value: data) { - datastream >> value; - } - if (datastream.fail()) { - SPDLOG_ERROR("Error reading file: unexpected data format"); - exit(-1); - } -} - -std::vector FileReader::readFileLines(const std::string &filepath) { - std::vector lines; - std::ifstream input_file(filepath); - std::string tmp_string; - bool num_data_read = false; - - if (input_file.is_open()) { - while (std::getline(input_file, tmp_string)) { - if (!tmp_string.empty() && tmp_string[0] != '#') { - if (!num_data_read) { - int num_data = std::stoi(tmp_string); - if (num_data < 0) { - SPDLOG_ERROR("Error: Number of data sets cannot be negative."); - exit(-1); - } - - // Reserve space in the vector to avoid reallocations - lines.reserve(num_data + 1); - num_data_read = true; - } - lines.push_back(tmp_string); - } - } - } else { - SPDLOG_ERROR("Error: could not open file {}", filepath); - exit(-1); - } - return lines; -} \ No newline at end of file diff --git a/src/io/in/FileReader.h b/src/io/in/FileReader.h index e67de6c8f..a34eb6854 100644 --- a/src/io/in/FileReader.h +++ b/src/io/in/FileReader.h @@ -1,85 +1,19 @@ -/* - * FileReader.h - * - * Created on: 23.02.2010 - * Author: eckhardw - */ - #pragma once -#include - #include "../../objects/ParticleContainer.h" -#include "CuboidParameters.h" +#include "io/in/parameters/CuboidParameters.h" #include "ParticleGenerator.h" +#include "io/in/parameters/SimulationDataContainer.h" +namespace fileReaders { -/** - * @class FileReader - * A class responsible for reading particle data from a file. - */ -class FileReader { - -public: - /** - * Constructor that initializes the particleGenerator. - * - * @param generator The ParticleGenerator to use for particle data. - */ - FileReader() = default; - - - ~FileReader() = default; - - static ParticleContainer readFile(const std::string& filepath); - -private: - /** - * Reads particle data from a file and returns a ParticleContainer. - * - * @param filepath The path to the file to read particle data from. - * @return A ParticleContainer containing the particles read from the file. - */ - static void loadParticles(const std::vector& lines, ParticleContainer& particles); - - static void loadCuboids(const std::vector& lines, ParticleContainer& particles); - - - - /** - * This method parses an array of values from a single line (string) - * and update the data object, specified as parameter, accordingly. - * - * @tparam T type of 'data' - * @tparam N array size of 'data' - * @param line current file line - * @param data data object to update according to the given line - */ - template - static void parseDataFromLine(std::istringstream &datastream, std::array &data); - - /** - * This method reads the file specified by the parameter 'filepath' - * and returns only relevant lines (that are no comments) in the file as a vector strings. - * - * Moreover, this functions checks if the given "number of cuboid" in the input file is non-negative or not. - * - * @param filepath - * @return vector of strings - */ - static std::vector readFileLines(const std::string &filepath); + class FileReader { + public: + FileReader() = default; + virtual ~FileReader() = default; -/** - * Class section end - * - * - * - * --------------------------------------------TEST SECTION------------------------------------------------------------ - * To be able to use the private methods and attributes in testing, FRIEND_TESTs are declared here. - */ - FRIEND_TEST(FileReaderTest, LoadParticles); - FRIEND_TEST(FileReaderTest, LoadCuboids); - FRIEND_TEST(FileReaderTest, readFileLinesBasicTest); -}; \ No newline at end of file + virtual SimulationDataContainer readFile(const std::string& filePath) = 0; + }; +}// namespace fileReaders \ No newline at end of file diff --git a/src/io/in/ParticleGenerator.cpp b/src/io/in/ParticleGenerator.cpp index 951b04dff..4b676ab03 100644 --- a/src/io/in/ParticleGenerator.cpp +++ b/src/io/in/ParticleGenerator.cpp @@ -15,23 +15,24 @@ Particle ParticleGenerator::generateParticle(const ParticleParameters ¶meter SPDLOG_DEBUG("Generated particle: [Position: [{}, {}, {}], Velocity: [{}, {}, {}], Mass: {}, Volume: {}, Type: {}]", x[0], x[1], x[2], v[0], v[1], v[2], m, volume, type); return {parameters.getPosition(), - parameters.getVelocity(), - parameters.getMass(), - parameters.getVolume(), - parameters.getType()}; + parameters.getVelocity(), + parameters.getMass(), + parameters.getVolume(), + parameters.getType()}; } -void ParticleGenerator::generateCuboid(const CuboidParameters ¶meters, ParticleContainer& particleContainer) { +void ParticleGenerator::generateCuboid(const CuboidParameters ¶meters, ParticleContainer &particleContainer) { // Extract parameters for easier access - const auto &lowerLeftFrontCorner = parameters.lowerLeftFrontCorner; - const auto &numParticlesPerDimension = parameters.numParticlesPerDimension; - const auto &distance = parameters.distance; - const auto &m = parameters.m; - const auto &startV = parameters.startV; - const auto &meanV = parameters.meanV; - SPDLOG_DEBUG("Generating cuboid: LLF [{} {} {}], NumParticles [{} {} {}], Distance {}, Mass {}, StartV [{} {} {}], MeanV {}", - lowerLeftFrontCorner[0], lowerLeftFrontCorner[1], lowerLeftFrontCorner[2], numParticlesPerDimension[0], numParticlesPerDimension[1], - numParticlesPerDimension[2], distance, m, startV[0], startV[1], startV[2], meanV); + const auto &lowerLeftFrontCorner = parameters.getLowerLeftFrontCorner(); + const auto &numParticlesPerDimension = parameters.getNumParticlesPerDimension(); + const auto &distance = parameters.getDistance(); + const auto &m = parameters.getMass(); + const auto &startV = parameters.getStartV(); + const auto &meanV = parameters.getMeanV(); + const auto &dimension = parameters.getDimension(); + SPDLOG_DEBUG("Generating cuboid: LLF {}, NumParticles {}, Distance {}, Mass {}, StartV {}, MeanV {}", + ArrayUtils::to_string(lowerLeftFrontCorner), ArrayUtils::to_string(numParticlesPerDimension), distance, + m, ArrayUtils::to_string(startV), meanV); // Generate particles for the cuboid for (std::size_t xIndex = 0; xIndex < numParticlesPerDimension[0]; ++xIndex) { @@ -47,13 +48,119 @@ void ParticleGenerator::generateCuboid(const CuboidParameters ¶meters, Parti // Simulate Brownian Motion by using MaxwellBoltzmannDistribution const std::array deltaV = maxwellBoltzmannDistributedVelocity(meanV, 3); - // Add deltaV to v + std::array v = startV; + // Add elements of deltaV to v based on dimension + for (int i = 0; i < dimension; ++i) { + v[i] += deltaV[i]; + } + // Create a new particle and add it to the container + Particle newParticle(x, v, m, 0, 0); // Set volume and type to zero for now + particleContainer.addParticle(newParticle); + } + } + } +} + +void ParticleGenerator::generateCuboid(const CuboidParameters ¶meters, LinkedCellContainer &linkedCellContainer, size_t &id_arg) { + const auto &lowerLeftFrontCorner = parameters.getLowerLeftFrontCorner(); + const auto &numParticlesPerDimension = parameters.getNumParticlesPerDimension(); + const auto &distance = parameters.getDistance(); + const auto &m = parameters.getMass(); + const auto &startV = parameters.getStartV(); + const auto &meanV = parameters.getMeanV(); + const auto &sigma = parameters.getSigma(); + const auto &epsilon = parameters.getEpsilon(); + + for (std::size_t xIndex = 0; xIndex < numParticlesPerDimension[0]; ++xIndex) { + for (std::size_t yIndex = 0; yIndex < numParticlesPerDimension[1]; ++yIndex) { + for (std::size_t zIndex = 0; zIndex < numParticlesPerDimension[2]; ++zIndex) { + const std::array x = { + lowerLeftFrontCorner[0] + xIndex * distance, + lowerLeftFrontCorner[1] + yIndex * distance, + lowerLeftFrontCorner[2] + zIndex * distance + }; + const std::array deltaV = maxwellBoltzmannDistributedVelocity(meanV, 2); const std::array v = ArrayUtils::elementWisePairOp(startV, deltaV, std::plus<>()); + auto newParticle = std::make_shared(x, v, m, 0, 0, sigma, epsilon, id_arg); + SPDLOG_DEBUG("Generated particle at position {} with velocities {}", + ArrayUtils::to_string(x), + ArrayUtils::to_string(v)); + linkedCellContainer.addParticle(newParticle); + id_arg++; + } + } + } + SPDLOG_INFO( + "Finished generating cuboid with LLF [{}, {}, {}], NumParticles [{}, {}, {}], Distance {}, Mass {}, StartV [{}, {}, {}], MeanV {}", + lowerLeftFrontCorner[0], lowerLeftFrontCorner[1], lowerLeftFrontCorner[2], numParticlesPerDimension[0], + numParticlesPerDimension[1], + numParticlesPerDimension[2], distance, m, startV[0], startV[1], startV[2], meanV); +} + +void ParticleGenerator::generateDisc(const DiscParameters ¶meters, ParticleContainer &particleContainer) { + // Extract parameters for easier access + const auto ¢er = parameters.getCenter(); + const auto &startV = parameters.getStartV(); + const int numParticlesAlongRadius = parameters.getNumParticlesAlongRadius(); + const double distance = parameters.getDistance(); + const double mass = parameters.getMass(); + + SPDLOG_DEBUG("Generating disc: Center {}, startV {}, numParticlesAlongRadius {}, Distance {}", + ArrayUtils::to_string(center), ArrayUtils::to_string(startV), numParticlesAlongRadius, distance); + + // Generate particles for the disc + for (int i = -numParticlesAlongRadius; i <= numParticlesAlongRadius; ++i) { + for (int j = -numParticlesAlongRadius; j <= numParticlesAlongRadius; ++j) { + if (i * i + j * j <= + numParticlesAlongRadius * numParticlesAlongRadius) { // Check if the position is inside the disc + // Calculate the position of the particle + const std::array x = { + center[0] + i * distance, + center[1] + j * distance, + center[2] + }; + // Create a new particle and add it to the container - Particle newParticle(x, v, m, 0, 0); // Set volume and type to zero for now + Particle newParticle(x, startV, mass, 0, 0); particleContainer.addParticle(newParticle); } } } } + +void ParticleGenerator::generateDisc(const DiscParameters ¶meters, LinkedCellContainer &linkedCellContainer, size_t &id_arg) { + // Extract parameters for easier access + const auto ¢er = parameters.getCenter(); + const auto &startV = parameters.getStartV(); + const int numParticlesAlongRadius = parameters.getNumParticlesAlongRadius(); + const double distance = parameters.getDistance(); + const double mass = parameters.getMass(); + const double sigma = parameters.getSigma(); + const double epsilon = parameters.getEpsilon(); + + SPDLOG_DEBUG("Generating disc: Center {}, startV {}, numParticlesAlongRadius {}, Distance {}", + ArrayUtils::to_string(center), ArrayUtils::to_string(startV), numParticlesAlongRadius, distance); + + // Generate particles for the disc + for (int i = -numParticlesAlongRadius; i <= numParticlesAlongRadius; ++i) { + for (int j = -numParticlesAlongRadius; j <= numParticlesAlongRadius; ++j) { + if (i * i + j * j <= + numParticlesAlongRadius * numParticlesAlongRadius) { // Check if the position is inside the disc + // Calculate the position of the particle + const std::array x = { + center[0] + i * distance, + center[1] + j * distance, + center[2] + }; + + // Create a new particle and add it to the container + auto newParticle = std::make_shared(x, startV, mass, 0, 0, sigma, epsilon, id_arg); + linkedCellContainer.addParticle(newParticle); + id_arg++; + } + } + } +} + + diff --git a/src/io/in/ParticleGenerator.h b/src/io/in/ParticleGenerator.h index 5a91cc9ff..6d471b9a4 100644 --- a/src/io/in/ParticleGenerator.h +++ b/src/io/in/ParticleGenerator.h @@ -4,8 +4,10 @@ #pragma once #include "../../objects/ParticleContainer.h" -#include "CuboidParameters.h" -#include "ParticleParameters.h" +#include "io/in/parameters/CuboidParameters.h" +#include "io/in/parameters/ParticleParameters.h" +#include "io/in/parameters/DiscParameters.h" +#include "objects/LinkedCellContainer.h" class ParticleGenerator { @@ -17,4 +19,10 @@ class ParticleGenerator { static Particle generateParticle(const ParticleParameters ¶meters); static void generateCuboid(const CuboidParameters ¶meters, ParticleContainer& particleContainer); + + static void generateCuboid(const CuboidParameters ¶meters, LinkedCellContainer& linkedCellContainer, size_t &id_arg); + + static void generateDisc(const DiscParameters ¶meters, ParticleContainer& particleContainer); + + static void generateDisc(const DiscParameters ¶meters, LinkedCellContainer& linkedCellContainer, size_t &id_arg); }; diff --git a/src/io/in/TXTReader.cpp b/src/io/in/TXTReader.cpp new file mode 100644 index 000000000..fa53e08cf --- /dev/null +++ b/src/io/in/TXTReader.cpp @@ -0,0 +1,273 @@ +/* + * FileReader.cpp + * + * Created on: 23.02.2010 + * Author: eckhardw + */ + +#include "FileReader.h" +#include "TXTReader.h" +#include "spdlog/spdlog.h" +#include "io/in/parameters/DiscParameters.h" +#include "objects/LinkedCellContainer.h" +#include +#include +#include +#include + +namespace fileReaders { + + SimulationDataContainer TXTReader::readFile(const std::string &filepath) { + auto lines = readFileLines(filepath); + + // Check if there are lines in the file + if (lines.empty()) { + SPDLOG_ERROR("File is empty: ", filepath); + throw std::runtime_error("File is empty: " + filepath); + } + + // Validate the header lines + validateHeaderLines(lines); + + // Parse the data code + int dataCode = std::stoi(lines[0]); + lines.erase(lines.begin()); + + // Log the data code + SPDLOG_INFO("Data Code of file '{}': {}", filepath, dataCode); + // Load particles or cuboid based on data code + std::unique_ptr particleContainer = std::make_unique(); + switch (dataCode) { + case 0: + loadParticles(lines, *particleContainer); + break; + case 1: + loadCuboids(lines, *particleContainer); + break; + case 2: + loadDiscs(lines, *particleContainer); + break; + default: + SPDLOG_ERROR("Invalid data code in file '", filepath + "': Only data codes 0 and 1 are supported."); + throw std::runtime_error( + "Invalid data code in file '" + filepath + "': Only data codes 0 and 1 are supported."); + } + + std::unique_ptr linkedCellContainer = std::make_unique(); + std::unique_ptr fileWriterParameters = std::make_unique(); + std::unique_ptr simulationParameters = std::make_unique(); + std::unique_ptr thermostatParameters = std::make_unique(); + std::unique_ptr linkedCellsParameters = std::make_unique(); + std::unique_ptr boundaryParameters = std::make_unique(); + SimulationDataContainer simulationDataContainer(std::move(particleContainer), + std::move(linkedCellContainer), + std::move(fileWriterParameters), + std::move(simulationParameters), + std::move(thermostatParameters), + std::move(linkedCellsParameters), + std::move(boundaryParameters)); + return simulationDataContainer; + } + + void TXTReader::loadParticles(const std::vector &lines, ParticleContainer &particleContainer) { + std::array x{}, v{}; + double m; + + int num_particles = std::stoi(lines[0]); + int dimension = std::stoi(lines[1]); + SPDLOG_DEBUG("Number of particles to load: {}", num_particles); + SPDLOG_DEBUG("Dimension of simulation: {}", dimension); + + for (int i = 2; i < num_particles + 2; ++i) { + std::istringstream datastream(lines[i]); + parseDataFromLine(datastream, x); + parseDataFromLine(datastream, v); + datastream >> m; + + ParticleParameters parameters(x, v, m, 0, 0, dimension); + Particle newParticle = ParticleGenerator::generateParticle(parameters); + particleContainer.addParticle(newParticle); + } + + particleContainer.initializePairs(); + particleContainer.setVolumes(); + } + + void TXTReader::loadCuboids(const std::vector &lines, ParticleContainer &particles) { + SPDLOG_INFO("Starting to load cuboids..."); + std::array llf{}, startV{}; + std::array numParticles{}; + double distance, mass, meanV; + + int num_cuboids = std::stoi(lines[0]); + int dimension = std::stoi(lines[1]); + SPDLOG_DEBUG("Number of cuboids to load: {}", num_cuboids); + SPDLOG_DEBUG("Dimension of simulation: {}", dimension); + + for (int i = 2; i < num_cuboids + 2; ++i) { + std::istringstream datastream(lines[i]); + parseDataFromLine(datastream, llf); + parseDataFromLine(datastream, numParticles); + datastream >> distance >> mass; + parseDataFromLine(datastream, startV); + datastream >> meanV; + + if (datastream.fail()) { + SPDLOG_ERROR("Error reading file: unexpected data format on line {}", i + 1); + exit(-1); + } + + CuboidParameters cuboidParams(llf, numParticles, distance, mass, startV, meanV, dimension, 1.0, 1.0); + ParticleGenerator::generateCuboid(cuboidParams, particles); + SPDLOG_DEBUG("Completed generating cuboid {}", i); + } + particles.initializePairs(); + SPDLOG_INFO("Finished loading cuboids!"); + } + + + void TXTReader::loadDiscs(const std::vector &lines, ParticleContainer &particles) { + SPDLOG_INFO("Starting to load discs..."); + std::array center{}, startV{}; + int numParticlesAlongRadius; + double distance, mass; + + int num_discs = std::stoi(lines[0]); + int dimension = std::stoi(lines[1]); + SPDLOG_DEBUG("Number of discs to load: {}", num_discs); + SPDLOG_DEBUG("Dimension of simulation: {}", dimension); + + for (int i = 2; i < num_discs + 2; ++i) { + std::istringstream datastream(lines[i]); + parseDataFromLine(datastream, center); + parseDataFromLine(datastream, startV); + datastream >> numParticlesAlongRadius >> distance >> mass; + + if (datastream.fail()) { + SPDLOG_ERROR("Error reading file: unexpected data format on line {}", i + 1); + exit(-1); + } + + DiscParameters discParams(center, startV, numParticlesAlongRadius, distance, mass, dimension, 1.0, 1.0); + ParticleGenerator::generateDisc(discParams, particles); + SPDLOG_DEBUG("Completed generating disc {}", i); + particles.initializePairs(); + } + SPDLOG_INFO("Finished loading discs!"); + } + + // ------------------------------------------- Helper methods -------------------------------------------------- + + const std::set TXTReader::allowedDataCodes = {0, 1, 2}; + const std::set TXTReader::allowedDimensions = {2, 3}; + + template + void TXTReader::parseDataFromLine(std::istringstream &datastream, std::array &data) { + for (auto &value: data) { + datastream >> value; + } + if (datastream.fail()) { + SPDLOG_ERROR("Error reading file: unexpected data format"); + exit(-1); + } + } + + std::vector TXTReader::readFileLines(const std::string &filepath) { + std::vector lines; + std::ifstream input_file(filepath); + std::string tmp_string; + bool data_code_read = false; + bool num_data_read = false; + bool dimension_read = false; + + if (input_file.is_open()) { + while (std::getline(input_file, tmp_string)) { + // Ignore comment lines + if (!tmp_string.empty() && tmp_string[0] == '#') { + continue; + } + + // Read and validate the data code + if (!data_code_read) { + int data_code = std::stoi(tmp_string); + if (allowedDataCodes.find(data_code) == allowedDataCodes.end()) { + SPDLOG_ERROR("Error: Invalid data code {}. Only 0 and 1 are allowed.", data_code); + exit(-1); + } + data_code_read = true; + } + + // Read and validate the number of data sets + else if (!num_data_read) { + int num_data = std::stoi(tmp_string); + if (num_data < 0) { + SPDLOG_ERROR("Error: Number of data sets cannot be negative."); + exit(-1); + } + num_data_read = true; + } + + // Read and validate the dimension + else if (!dimension_read) { + int dimension = std::stoi(tmp_string); + if (allowedDimensions.find(dimension) == allowedDimensions.end()) { + SPDLOG_ERROR("Error: Invalid dimension {}. Only 2 or 3 are allowed.", dimension); + exit(-1); + } + dimension_read = true; + } + + // Add the line to the vector + lines.push_back(tmp_string); + } + } else { + SPDLOG_ERROR("Error: could not open file {}", filepath); + exit(-1); + } + return lines; + } + + void TXTReader::validateHeaderLines(const std::vector &lines) { + bool data_code_read = false; + bool num_datasets_read = false; + + if (lines.size() < 3) { + SPDLOG_ERROR("Error: File does not contain enough header lines. Expected 3 header lines, but found {}.", + lines.size()); + exit(-1); + } + + for (const auto &line: lines) { + // Read and validate the data code + if (!data_code_read) { + int data_code = std::stoi(line); + if (allowedDataCodes.find(data_code) == allowedDataCodes.end()) { + SPDLOG_ERROR("Error: Invalid data code {}. Only 0 and 1 are allowed.", data_code); + exit(-1); + } + data_code_read = true; + } + + // Read and validate the number of data sets + else if (!num_datasets_read) { + int num_data = std::stoi(line); + if (num_data < 0) { + SPDLOG_ERROR("Error: Number of data sets cannot be negative."); + exit(-1); + } + num_datasets_read = true; + } + + // Read and validate the dimension + else { + int dimension = std::stoi(line); + if (allowedDimensions.find(dimension) == allowedDimensions.end()) { + SPDLOG_ERROR("Error: Invalid dimension {}. Only 2 or 3 are allowed.", dimension); + exit(-1); + } + return; + } + } + } +} + diff --git a/src/io/in/TXTReader.h b/src/io/in/TXTReader.h new file mode 100644 index 000000000..d0d536390 --- /dev/null +++ b/src/io/in/TXTReader.h @@ -0,0 +1,78 @@ + +/* + * FileReader.h + * + * Created on: 23.02.2010 + * Author: eckhardw + */ + +#pragma once + +#include + +#include "../../objects/ParticleContainer.h" +#include "ParticleGenerator.h" +#include "FileReader.h" + +namespace fileReaders { + + class TXTReader : public FileReader { + + public: + + TXTReader() = default; + + ~TXTReader() override = default; + + SimulationDataContainer readFile(const std::string &filepath) override; + + static const std::set allowedDataCodes; + static const std::set allowedDimensions; + + /** + * Reads particle data from a file and returns a ParticleContainer. + * + * @param filepath The path to the file to read particle data from. + * @return A ParticleContainer containing the particles read from the file. + */ + void loadParticles(const std::vector &lines, ParticleContainer &particles); + + void loadCuboids(const std::vector &lines, ParticleContainer &particles); + + void loadDiscs(const std::vector &lines, ParticleContainer &particles); + + /** + * This method parses an array of values from a single line (string) + * and update the data object, specified as parameter, accordingly. + * + * @tparam T type of 'data' + * @tparam N array size of 'data' + * @param line current file line + * @param data data object to update according to the given line + */ + template + void parseDataFromLine(std::istringstream &datastream, std::array &data); + + /** + * This method reads the file specified by the parameter 'filepath' + * and returns only relevant lines (that are no comments) in the file as a vector strings. + * + * Moreover, this functions checks if the given "number of cuboid" in the input file is non-negative or not. + * + * @param filepath + * @return vector of strings + */ + std::vector readFileLines(const std::string &filepath); + + /** + * This method validates the header lines of the input file. + * The header lines should contain the data code, number of data sets, and the dimension of the simulation. + * + * This method checks if the header data are allowed and returns error exitcode, if not. + * + * @param lines + */ + void validateHeaderLines(const std::vector &lines); + + }; +}// namespace fileReaders diff --git a/src/io/in/XMLReader.cpp b/src/io/in/XMLReader.cpp new file mode 100644 index 000000000..66f8247e0 --- /dev/null +++ b/src/io/in/XMLReader.cpp @@ -0,0 +1,240 @@ +#include "XMLReader.h" +#include "input_schema.hxx" +#include "spdlog/spdlog.h" +#include "objects/LinkedCellContainer.h" +#include "utils/ArrayUtils.h" +#include +#include +#include + +namespace fileReaders { + + SimulationDataContainer XMLReader::readFile(const std::string &filepath) { + SPDLOG_INFO("Reading XML file: {}", filepath); + + std::unique_ptr simulation = Simulation_(filepath); + + + std::unique_ptr fileWriterParameters = std::make_unique( + loadFileWriterParameters(*simulation)); + std::unique_ptr simulationParameters = std::make_unique( + loadSimulationParameters(*simulation)); + std::unique_ptr thermostatParameters = std::make_unique( + loadThermostatParameters(*simulation)); + std::unique_ptr linkedCellParameters = std::make_unique( + loadLinkedCellsParameters(*simulation)); + std::unique_ptr boundaryParameters = std::make_unique( + loadBoundaryParameters(*simulation)); + + std::unique_ptr particleContainer = std::make_unique(); + std::unique_ptr linkedCellContainer = std::make_unique(); + if (linkedCellParameters->isLinkedCellsUsed()) { + const double cutoffRadius = linkedCellParameters->getCutOffRadius(); + linkedCellContainer->setCellSize(cutoffRadius); + linkedCellContainer->setCutOffRadius(cutoffRadius); + linkedCellContainer->setDomain(boundaryParameters->getDomain()); + loadCuboids(*simulation, *linkedCellContainer); + loadDiscs(*simulation, *linkedCellContainer); + } else { + loadCuboids(*simulation, *particleContainer); + loadDiscs(*simulation, *particleContainer); + } + + SimulationDataContainer simulationDataContainer(std::move(particleContainer), + std::move(linkedCellContainer), + std::move(fileWriterParameters), + std::move(simulationParameters), + std::move(thermostatParameters), + std::move(linkedCellParameters), + std::move(boundaryParameters)); + + return simulationDataContainer; + } + + LinkedCellsParameters XMLReader::loadLinkedCellsParameters(const Simulation &simulation) { + const auto &linkedCellParametersParsed = simulation.LinkedCellsParameters(); + return {linkedCellParametersParsed.LinkedCellsUsed(), linkedCellParametersParsed.CutoffRadius()}; + } + + FileWriterParameters XMLReader::loadFileWriterParameters(const Simulation &simulation) { + const auto &fileWriterParametersParsed = simulation.FileWriterParameters(); + return {fileWriterParametersParsed.BaseName(), fileWriterParametersParsed.WriteFrequency()}; + } + + SimulationParameters XMLReader::loadSimulationParameters(const Simulation &simulation) { + const auto &simulationParametersParsed = simulation.SimulationParameters(); + + double gravity = 0.0; // default value + + if (simulationParametersParsed.Gravity().present()) { + gravity = simulationParametersParsed.Gravity().get(); + } + + int dimension = simulationParametersParsed.Dimension(); + if (dimension != 2 && dimension != 3) { + throw std::invalid_argument("Invalid dimension: " + std::to_string(dimension) + " (must be 2 or 3)"); + } + + return {simulationParametersParsed.EndT(), simulationParametersParsed.DeltaT(), gravity, dimension}; + } + + ThermostatParameters XMLReader::loadThermostatParameters(const Simulation &simulation) { + const auto &thermostatParametersParsed = simulation.ThermostatParameters(); + return {thermostatParametersParsed.StartTemperature(), thermostatParametersParsed.TargetTemperature(), + thermostatParametersParsed.ApplyFrequency(), thermostatParametersParsed.MaxDeltaTemperature(), + thermostatParametersParsed.Dimension()}; + } + + BoundaryParameters XMLReader::loadBoundaryParameters(const Simulation &simulation) { + const auto &boundaryParametersParsed = simulation.BoundaryParameters(); + + std::map boundaryMap; + + boundaryMap[boundaries::BoundaryDirection::TOP] = stringToBoundaryType(boundaryParametersParsed.TOP()); + boundaryMap[boundaries::BoundaryDirection::RIGHT] = stringToBoundaryType(boundaryParametersParsed.RIGHT()); + boundaryMap[boundaries::BoundaryDirection::BOTTOM] = stringToBoundaryType(boundaryParametersParsed.BOTTOM()); + boundaryMap[boundaries::BoundaryDirection::LEFT] = stringToBoundaryType(boundaryParametersParsed.LEFT()); + boundaryMap[boundaries::BoundaryDirection::FRONT] = stringToBoundaryType(boundaryParametersParsed.FRONT()); + boundaryMap[boundaries::BoundaryDirection::BACK] = stringToBoundaryType(boundaryParametersParsed.BACK()); + + std::array domain{}; + std::istringstream domainStream(boundaryParametersParsed.Domain()); + for (auto &value: domain) domainStream >> value; + + return {boundaryMap, domain}; + } + + boundaries::BoundaryType XMLReader::stringToBoundaryType(const std::string &boundaryTypeStr) { + if (boundaryTypeStr == "REFLECTING") { + return boundaries::BoundaryType::REFLECTING; + } else if (boundaryTypeStr == "OUTFLOW") { + return boundaries::BoundaryType::OUTFLOW; + } else if (boundaryTypeStr == "PERIODIC") { + return boundaries::BoundaryType::PERIODIC; + } else if (boundaryTypeStr == "OFF") { + return boundaries::BoundaryType::OFF; + } else { + throw std::invalid_argument("Invalid boundary type string: " + boundaryTypeStr); + } + } + + void XMLReader::loadCuboids(const Simulation &simulation, ParticleContainer &particleContainer) { + SPDLOG_INFO("Starting to load cuboids into a particle container..."); + const auto &cuboids = simulation.Cuboid(); + + for (const auto &cuboid: cuboids) { + std::array llf{}; + std::array numParticles{}; + std::array startV{}; + const double distance = cuboid.Distance(); + const double mass = cuboid.Mass(); + const double meanV = cuboid.MeanVelocity(); + const double sigma = cuboid.Sigma(); + const double epsilon = cuboid.Epsilon(); + + std::istringstream coordStream(cuboid.Coordinates()); + std::istringstream partDimStream(cuboid.ParticlesPerDimension()); + std::istringstream initVelStream(cuboid.InitialVelocities()); + + for (auto &value: llf) coordStream >> value; + for (auto &value: numParticles) partDimStream >> value; + for (auto &value: startV) initVelStream >> value; + + CuboidParameters cuboidParams(llf, numParticles, distance, mass, startV, meanV, 3, sigma, epsilon); + ParticleGenerator::generateCuboid(cuboidParams, particleContainer); + } + particleContainer.initializePairs(); + SPDLOG_INFO("Finished loading {} cuboids into a particle container!", cuboids.size()); + } + + void XMLReader::loadCuboids(const Simulation &simulation, LinkedCellContainer &linkedCellContainer) { + SPDLOG_INFO("Starting to load cuboids into a linked-cell container..."); + const auto &cuboids = simulation.Cuboid(); + + size_t id_arg = 0; + for (const auto &cuboid: cuboids) { + std::array llf{}; + std::array numParticles{}; + std::array startV{}; + const double distance = cuboid.Distance(); + const double mass = cuboid.Mass(); + const double meanV = cuboid.MeanVelocity(); + const double sigma = cuboid.Sigma(); + const double epsilon = cuboid.Epsilon(); + + std::istringstream coordStream(cuboid.Coordinates()); + std::istringstream partDimStream(cuboid.ParticlesPerDimension()); + std::istringstream initVelStream(cuboid.InitialVelocities()); + + for (auto &value: llf) coordStream >> value; + for (auto &value: numParticles) partDimStream >> value; + for (auto &value: startV) initVelStream >> value; + + CuboidParameters cuboidParams(llf, numParticles, distance, mass, startV, meanV, 3, sigma, epsilon); + SPDLOG_INFO("Read cuboid parameters: llf: {}, numParticles: {} , distance: {}, mass: {}, startV: {}, meanV: {}", + ArrayUtils::to_string(cuboidParams.getLowerLeftFrontCorner()), + ArrayUtils::to_string(cuboidParams.getNumParticlesPerDimension()), cuboidParams.getDistance(), + cuboidParams.getMass(), + ArrayUtils::to_string(cuboidParams.getStartV()), cuboidParams.getMeanV()); + ParticleGenerator::generateCuboid(cuboidParams, linkedCellContainer, id_arg); + } + linkedCellContainer.initializeAndPopulateCells(); + SPDLOG_INFO("Finished loading {} cuboids into a linked-cell container!", cuboids.size()); + } + + void XMLReader::loadDiscs(const Simulation &simulation, ParticleContainer &particleContainer) { + SPDLOG_INFO("Starting to load discs into a particle container..."); + const auto &discs = simulation.Disc(); + + for (const auto &disc: discs) { + std::array center{}; + std::array startV{}; + const int numParticlesAlongRadius = disc.NumberOfParticlesAlongRadius(); + const double distance = disc.Distance(); + const double mass = disc.Mass(); + const double sigma = disc.Sigma(); + const double epsilon = disc.Epsilon(); + + std::istringstream centerStream(disc.CenterCoordinates()); + std::istringstream startVStream(disc.InitialVelocities()); + + for (auto &value: center) centerStream >> value; + for (auto &value: startV) startVStream >> value; + + const int dimension = simulation.SimulationParameters().Dimension(); + DiscParameters discParams(center, startV, numParticlesAlongRadius, distance, mass, dimension, sigma, epsilon); + ParticleGenerator::generateDisc(discParams, particleContainer); + } + particleContainer.initializePairs(); + SPDLOG_INFO("Finished loading {} discs into a particle container!", discs.size()); + } + + void XMLReader::loadDiscs(const Simulation &simulation, LinkedCellContainer &linkedCellContainer) { + SPDLOG_INFO("Starting to load discs into a linked-cell container..."); + const auto &discs = simulation.Disc(); + + size_t id_arg = 0; + for (const auto &disc: discs) { + std::array center{}; + std::array startV{}; + const int numParticlesAlongRadius = disc.NumberOfParticlesAlongRadius(); + const double distance = disc.Distance(); + const double mass = disc.Mass(); + const double sigma = disc.Sigma(); + const double epsilon = disc.Epsilon(); + + std::istringstream centerStream(disc.CenterCoordinates()); + std::istringstream startVStream(disc.InitialVelocities()); + + for (auto &value: center) centerStream >> value; + for (auto &value: startV) startVStream >> value; + + const int dimension = simulation.SimulationParameters().Dimension(); + DiscParameters discParams(center, startV, numParticlesAlongRadius, distance, mass, dimension, sigma, epsilon); + ParticleGenerator::generateDisc(discParams, linkedCellContainer, id_arg); + } + linkedCellContainer.initializeAndPopulateCells(); + SPDLOG_INFO("Finished loading {} discs into a linked-cell container!", discs.size()); + } + +} // namespace fileReaders diff --git a/src/io/in/XMLReader.h b/src/io/in/XMLReader.h new file mode 100644 index 000000000..fb97fcb49 --- /dev/null +++ b/src/io/in/XMLReader.h @@ -0,0 +1,37 @@ +#pragma once + +#include "../../objects/ParticleContainer.h" +#include "input_schema.hxx" +#include "FileReader.h" +#include +#include +#include + +namespace fileReaders { + + class XMLReader : public FileReader { + public: + SimulationDataContainer readFile(const std::string& filepath) override; + private: + void loadCuboids(const Simulation& simulation, ParticleContainer& particleContainer); + + void loadCuboids(const Simulation& simulation, LinkedCellContainer& linkedCellContainer); + + void loadDiscs(const Simulation& simulation, ParticleContainer& particleContainer); + + void loadDiscs(const Simulation& simulation, LinkedCellContainer& linkedCellContainer); + + FileWriterParameters loadFileWriterParameters(const Simulation &simulation); + + SimulationParameters loadSimulationParameters(const Simulation &simulation); + + ThermostatParameters loadThermostatParameters(const Simulation &simulation); + + LinkedCellsParameters loadLinkedCellsParameters(const Simulation &simulation); + + BoundaryParameters loadBoundaryParameters(const Simulation &simulation); + + boundaries::BoundaryType stringToBoundaryType(const std::string &boundaryTypeStr); + }; + +} // namespace fileReaders diff --git a/src/io/in/input_schema.cxx b/src/io/in/input_schema.cxx new file mode 100644 index 000000000..613f640f8 --- /dev/null +++ b/src/io/in/input_schema.cxx @@ -0,0 +1,2883 @@ +// Copyright (c) 2005-2023 Code Synthesis. +// +// This program was generated by CodeSynthesis XSD, an XML Schema to +// C++ data binding compiler. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// 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, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// +// In addition, as a special exception, Code Synthesis gives permission +// to link this program with the Xerces-C++ library (or with modified +// versions of Xerces-C++ that use the same license as Xerces-C++), and +// distribute linked combinations including the two. You must obey the GNU +// General Public License version 2 in all respects for all of the code +// used other than Xerces-C++. If you modify this copy of the program, you +// may extend this exception to your version of the program, but you are +// not obligated to do so. If you do not wish to do so, delete this +// exception statement from your version. +// +// Furthermore, Code Synthesis makes a special exception for the Free/Libre +// and Open Source Software (FLOSS) which is described in the accompanying +// FLOSSE file. +// + +// Begin prologue. +// +// +// End prologue. + +#include + +#include "input_schema.hxx" + +// FileWriterParametersType +// + +const FileWriterParametersType::BaseName_type& FileWriterParametersType:: +BaseName () const +{ + return this->BaseName_.get (); +} + +FileWriterParametersType::BaseName_type& FileWriterParametersType:: +BaseName () +{ + return this->BaseName_.get (); +} + +void FileWriterParametersType:: +BaseName (const BaseName_type& x) +{ + this->BaseName_.set (x); +} + +void FileWriterParametersType:: +BaseName (::std::unique_ptr< BaseName_type > x) +{ + this->BaseName_.set (std::move (x)); +} + +const FileWriterParametersType::WriteFrequency_type& FileWriterParametersType:: +WriteFrequency () const +{ + return this->WriteFrequency_.get (); +} + +FileWriterParametersType::WriteFrequency_type& FileWriterParametersType:: +WriteFrequency () +{ + return this->WriteFrequency_.get (); +} + +void FileWriterParametersType:: +WriteFrequency (const WriteFrequency_type& x) +{ + this->WriteFrequency_.set (x); +} + + +// SimulationParametersType +// + +const SimulationParametersType::EndT_type& SimulationParametersType:: +EndT () const +{ + return this->EndT_.get (); +} + +SimulationParametersType::EndT_type& SimulationParametersType:: +EndT () +{ + return this->EndT_.get (); +} + +void SimulationParametersType:: +EndT (const EndT_type& x) +{ + this->EndT_.set (x); +} + +const SimulationParametersType::DeltaT_type& SimulationParametersType:: +DeltaT () const +{ + return this->DeltaT_.get (); +} + +SimulationParametersType::DeltaT_type& SimulationParametersType:: +DeltaT () +{ + return this->DeltaT_.get (); +} + +void SimulationParametersType:: +DeltaT (const DeltaT_type& x) +{ + this->DeltaT_.set (x); +} + +const SimulationParametersType::Gravity_optional& SimulationParametersType:: +Gravity () const +{ + return this->Gravity_; +} + +SimulationParametersType::Gravity_optional& SimulationParametersType:: +Gravity () +{ + return this->Gravity_; +} + +void SimulationParametersType:: +Gravity (const Gravity_type& x) +{ + this->Gravity_.set (x); +} + +void SimulationParametersType:: +Gravity (const Gravity_optional& x) +{ + this->Gravity_ = x; +} + +const SimulationParametersType::Dimension_type& SimulationParametersType:: +Dimension () const +{ + return this->Dimension_.get (); +} + +SimulationParametersType::Dimension_type& SimulationParametersType:: +Dimension () +{ + return this->Dimension_.get (); +} + +void SimulationParametersType:: +Dimension (const Dimension_type& x) +{ + this->Dimension_.set (x); +} + + +// ThermostatParametersType +// + +const ThermostatParametersType::StartTemperature_type& ThermostatParametersType:: +StartTemperature () const +{ + return this->StartTemperature_.get (); +} + +ThermostatParametersType::StartTemperature_type& ThermostatParametersType:: +StartTemperature () +{ + return this->StartTemperature_.get (); +} + +void ThermostatParametersType:: +StartTemperature (const StartTemperature_type& x) +{ + this->StartTemperature_.set (x); +} + +const ThermostatParametersType::TargetTemperature_type& ThermostatParametersType:: +TargetTemperature () const +{ + return this->TargetTemperature_.get (); +} + +ThermostatParametersType::TargetTemperature_type& ThermostatParametersType:: +TargetTemperature () +{ + return this->TargetTemperature_.get (); +} + +void ThermostatParametersType:: +TargetTemperature (const TargetTemperature_type& x) +{ + this->TargetTemperature_.set (x); +} + +const ThermostatParametersType::ApplyFrequency_type& ThermostatParametersType:: +ApplyFrequency () const +{ + return this->ApplyFrequency_.get (); +} + +ThermostatParametersType::ApplyFrequency_type& ThermostatParametersType:: +ApplyFrequency () +{ + return this->ApplyFrequency_.get (); +} + +void ThermostatParametersType:: +ApplyFrequency (const ApplyFrequency_type& x) +{ + this->ApplyFrequency_.set (x); +} + +const ThermostatParametersType::MaxDeltaTemperature_type& ThermostatParametersType:: +MaxDeltaTemperature () const +{ + return this->MaxDeltaTemperature_.get (); +} + +ThermostatParametersType::MaxDeltaTemperature_type& ThermostatParametersType:: +MaxDeltaTemperature () +{ + return this->MaxDeltaTemperature_.get (); +} + +void ThermostatParametersType:: +MaxDeltaTemperature (const MaxDeltaTemperature_type& x) +{ + this->MaxDeltaTemperature_.set (x); +} + +const ThermostatParametersType::Dimension_type& ThermostatParametersType:: +Dimension () const +{ + return this->Dimension_.get (); +} + +ThermostatParametersType::Dimension_type& ThermostatParametersType:: +Dimension () +{ + return this->Dimension_.get (); +} + +void ThermostatParametersType:: +Dimension (const Dimension_type& x) +{ + this->Dimension_.set (x); +} + + +// LinkedCellsParametersType +// + +const LinkedCellsParametersType::LinkedCellsUsed_type& LinkedCellsParametersType:: +LinkedCellsUsed () const +{ + return this->LinkedCellsUsed_.get (); +} + +LinkedCellsParametersType::LinkedCellsUsed_type& LinkedCellsParametersType:: +LinkedCellsUsed () +{ + return this->LinkedCellsUsed_.get (); +} + +void LinkedCellsParametersType:: +LinkedCellsUsed (const LinkedCellsUsed_type& x) +{ + this->LinkedCellsUsed_.set (x); +} + +const LinkedCellsParametersType::CutoffRadius_type& LinkedCellsParametersType:: +CutoffRadius () const +{ + return this->CutoffRadius_.get (); +} + +LinkedCellsParametersType::CutoffRadius_type& LinkedCellsParametersType:: +CutoffRadius () +{ + return this->CutoffRadius_.get (); +} + +void LinkedCellsParametersType:: +CutoffRadius (const CutoffRadius_type& x) +{ + this->CutoffRadius_.set (x); +} + + +// BoundaryParametersType +// + +const BoundaryParametersType::Domain_type& BoundaryParametersType:: +Domain () const +{ + return this->Domain_.get (); +} + +BoundaryParametersType::Domain_type& BoundaryParametersType:: +Domain () +{ + return this->Domain_.get (); +} + +void BoundaryParametersType:: +Domain (const Domain_type& x) +{ + this->Domain_.set (x); +} + +void BoundaryParametersType:: +Domain (::std::unique_ptr< Domain_type > x) +{ + this->Domain_.set (std::move (x)); +} + +const BoundaryParametersType::TOP_type& BoundaryParametersType:: +TOP () const +{ + return this->TOP_.get (); +} + +BoundaryParametersType::TOP_type& BoundaryParametersType:: +TOP () +{ + return this->TOP_.get (); +} + +void BoundaryParametersType:: +TOP (const TOP_type& x) +{ + this->TOP_.set (x); +} + +void BoundaryParametersType:: +TOP (::std::unique_ptr< TOP_type > x) +{ + this->TOP_.set (std::move (x)); +} + +const BoundaryParametersType::RIGHT_type& BoundaryParametersType:: +RIGHT () const +{ + return this->RIGHT_.get (); +} + +BoundaryParametersType::RIGHT_type& BoundaryParametersType:: +RIGHT () +{ + return this->RIGHT_.get (); +} + +void BoundaryParametersType:: +RIGHT (const RIGHT_type& x) +{ + this->RIGHT_.set (x); +} + +void BoundaryParametersType:: +RIGHT (::std::unique_ptr< RIGHT_type > x) +{ + this->RIGHT_.set (std::move (x)); +} + +const BoundaryParametersType::BOTTOM_type& BoundaryParametersType:: +BOTTOM () const +{ + return this->BOTTOM_.get (); +} + +BoundaryParametersType::BOTTOM_type& BoundaryParametersType:: +BOTTOM () +{ + return this->BOTTOM_.get (); +} + +void BoundaryParametersType:: +BOTTOM (const BOTTOM_type& x) +{ + this->BOTTOM_.set (x); +} + +void BoundaryParametersType:: +BOTTOM (::std::unique_ptr< BOTTOM_type > x) +{ + this->BOTTOM_.set (std::move (x)); +} + +const BoundaryParametersType::LEFT_type& BoundaryParametersType:: +LEFT () const +{ + return this->LEFT_.get (); +} + +BoundaryParametersType::LEFT_type& BoundaryParametersType:: +LEFT () +{ + return this->LEFT_.get (); +} + +void BoundaryParametersType:: +LEFT (const LEFT_type& x) +{ + this->LEFT_.set (x); +} + +void BoundaryParametersType:: +LEFT (::std::unique_ptr< LEFT_type > x) +{ + this->LEFT_.set (std::move (x)); +} + +const BoundaryParametersType::FRONT_type& BoundaryParametersType:: +FRONT () const +{ + return this->FRONT_.get (); +} + +BoundaryParametersType::FRONT_type& BoundaryParametersType:: +FRONT () +{ + return this->FRONT_.get (); +} + +void BoundaryParametersType:: +FRONT (const FRONT_type& x) +{ + this->FRONT_.set (x); +} + +void BoundaryParametersType:: +FRONT (::std::unique_ptr< FRONT_type > x) +{ + this->FRONT_.set (std::move (x)); +} + +const BoundaryParametersType::BACK_type& BoundaryParametersType:: +BACK () const +{ + return this->BACK_.get (); +} + +BoundaryParametersType::BACK_type& BoundaryParametersType:: +BACK () +{ + return this->BACK_.get (); +} + +void BoundaryParametersType:: +BACK (const BACK_type& x) +{ + this->BACK_.set (x); +} + +void BoundaryParametersType:: +BACK (::std::unique_ptr< BACK_type > x) +{ + this->BACK_.set (std::move (x)); +} + + +// CuboidType +// + +const CuboidType::Coordinates_type& CuboidType:: +Coordinates () const +{ + return this->Coordinates_.get (); +} + +CuboidType::Coordinates_type& CuboidType:: +Coordinates () +{ + return this->Coordinates_.get (); +} + +void CuboidType:: +Coordinates (const Coordinates_type& x) +{ + this->Coordinates_.set (x); +} + +void CuboidType:: +Coordinates (::std::unique_ptr< Coordinates_type > x) +{ + this->Coordinates_.set (std::move (x)); +} + +const CuboidType::ParticlesPerDimension_type& CuboidType:: +ParticlesPerDimension () const +{ + return this->ParticlesPerDimension_.get (); +} + +CuboidType::ParticlesPerDimension_type& CuboidType:: +ParticlesPerDimension () +{ + return this->ParticlesPerDimension_.get (); +} + +void CuboidType:: +ParticlesPerDimension (const ParticlesPerDimension_type& x) +{ + this->ParticlesPerDimension_.set (x); +} + +void CuboidType:: +ParticlesPerDimension (::std::unique_ptr< ParticlesPerDimension_type > x) +{ + this->ParticlesPerDimension_.set (std::move (x)); +} + +const CuboidType::Distance_type& CuboidType:: +Distance () const +{ + return this->Distance_.get (); +} + +CuboidType::Distance_type& CuboidType:: +Distance () +{ + return this->Distance_.get (); +} + +void CuboidType:: +Distance (const Distance_type& x) +{ + this->Distance_.set (x); +} + +const CuboidType::Mass_type& CuboidType:: +Mass () const +{ + return this->Mass_.get (); +} + +CuboidType::Mass_type& CuboidType:: +Mass () +{ + return this->Mass_.get (); +} + +void CuboidType:: +Mass (const Mass_type& x) +{ + this->Mass_.set (x); +} + +const CuboidType::InitialVelocities_type& CuboidType:: +InitialVelocities () const +{ + return this->InitialVelocities_.get (); +} + +CuboidType::InitialVelocities_type& CuboidType:: +InitialVelocities () +{ + return this->InitialVelocities_.get (); +} + +void CuboidType:: +InitialVelocities (const InitialVelocities_type& x) +{ + this->InitialVelocities_.set (x); +} + +void CuboidType:: +InitialVelocities (::std::unique_ptr< InitialVelocities_type > x) +{ + this->InitialVelocities_.set (std::move (x)); +} + +const CuboidType::MeanVelocity_type& CuboidType:: +MeanVelocity () const +{ + return this->MeanVelocity_.get (); +} + +CuboidType::MeanVelocity_type& CuboidType:: +MeanVelocity () +{ + return this->MeanVelocity_.get (); +} + +void CuboidType:: +MeanVelocity (const MeanVelocity_type& x) +{ + this->MeanVelocity_.set (x); +} + +const CuboidType::Sigma_type& CuboidType:: +Sigma () const +{ + return this->Sigma_.get (); +} + +CuboidType::Sigma_type& CuboidType:: +Sigma () +{ + return this->Sigma_.get (); +} + +void CuboidType:: +Sigma (const Sigma_type& x) +{ + this->Sigma_.set (x); +} + +const CuboidType::Epsilon_type& CuboidType:: +Epsilon () const +{ + return this->Epsilon_.get (); +} + +CuboidType::Epsilon_type& CuboidType:: +Epsilon () +{ + return this->Epsilon_.get (); +} + +void CuboidType:: +Epsilon (const Epsilon_type& x) +{ + this->Epsilon_.set (x); +} + + +// DiscType +// + +const DiscType::CenterCoordinates_type& DiscType:: +CenterCoordinates () const +{ + return this->CenterCoordinates_.get (); +} + +DiscType::CenterCoordinates_type& DiscType:: +CenterCoordinates () +{ + return this->CenterCoordinates_.get (); +} + +void DiscType:: +CenterCoordinates (const CenterCoordinates_type& x) +{ + this->CenterCoordinates_.set (x); +} + +void DiscType:: +CenterCoordinates (::std::unique_ptr< CenterCoordinates_type > x) +{ + this->CenterCoordinates_.set (std::move (x)); +} + +const DiscType::InitialVelocities_type& DiscType:: +InitialVelocities () const +{ + return this->InitialVelocities_.get (); +} + +DiscType::InitialVelocities_type& DiscType:: +InitialVelocities () +{ + return this->InitialVelocities_.get (); +} + +void DiscType:: +InitialVelocities (const InitialVelocities_type& x) +{ + this->InitialVelocities_.set (x); +} + +void DiscType:: +InitialVelocities (::std::unique_ptr< InitialVelocities_type > x) +{ + this->InitialVelocities_.set (std::move (x)); +} + +const DiscType::NumberOfParticlesAlongRadius_type& DiscType:: +NumberOfParticlesAlongRadius () const +{ + return this->NumberOfParticlesAlongRadius_.get (); +} + +DiscType::NumberOfParticlesAlongRadius_type& DiscType:: +NumberOfParticlesAlongRadius () +{ + return this->NumberOfParticlesAlongRadius_.get (); +} + +void DiscType:: +NumberOfParticlesAlongRadius (const NumberOfParticlesAlongRadius_type& x) +{ + this->NumberOfParticlesAlongRadius_.set (x); +} + +const DiscType::Distance_type& DiscType:: +Distance () const +{ + return this->Distance_.get (); +} + +DiscType::Distance_type& DiscType:: +Distance () +{ + return this->Distance_.get (); +} + +void DiscType:: +Distance (const Distance_type& x) +{ + this->Distance_.set (x); +} + +const DiscType::Mass_type& DiscType:: +Mass () const +{ + return this->Mass_.get (); +} + +DiscType::Mass_type& DiscType:: +Mass () +{ + return this->Mass_.get (); +} + +void DiscType:: +Mass (const Mass_type& x) +{ + this->Mass_.set (x); +} + +const DiscType::Sigma_type& DiscType:: +Sigma () const +{ + return this->Sigma_.get (); +} + +DiscType::Sigma_type& DiscType:: +Sigma () +{ + return this->Sigma_.get (); +} + +void DiscType:: +Sigma (const Sigma_type& x) +{ + this->Sigma_.set (x); +} + +const DiscType::Epsilon_type& DiscType:: +Epsilon () const +{ + return this->Epsilon_.get (); +} + +DiscType::Epsilon_type& DiscType:: +Epsilon () +{ + return this->Epsilon_.get (); +} + +void DiscType:: +Epsilon (const Epsilon_type& x) +{ + this->Epsilon_.set (x); +} + + +// BoundaryType +// + +BoundaryType:: +BoundaryType (value v) +: ::xml_schema::string (_xsd_BoundaryType_literals_[v]) +{ +} + +BoundaryType:: +BoundaryType (const char* v) +: ::xml_schema::string (v) +{ +} + +BoundaryType:: +BoundaryType (const ::std::string& v) +: ::xml_schema::string (v) +{ +} + +BoundaryType:: +BoundaryType (const ::xml_schema::string& v) +: ::xml_schema::string (v) +{ +} + +BoundaryType:: +BoundaryType (const BoundaryType& v, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::string (v, f, c) +{ +} + +BoundaryType& BoundaryType:: +operator= (value v) +{ + static_cast< ::xml_schema::string& > (*this) = + ::xml_schema::string (_xsd_BoundaryType_literals_[v]); + + return *this; +} + + +// Simulation +// + +const Simulation::FileWriterParameters_type& Simulation:: +FileWriterParameters () const +{ + return this->FileWriterParameters_.get (); +} + +Simulation::FileWriterParameters_type& Simulation:: +FileWriterParameters () +{ + return this->FileWriterParameters_.get (); +} + +void Simulation:: +FileWriterParameters (const FileWriterParameters_type& x) +{ + this->FileWriterParameters_.set (x); +} + +void Simulation:: +FileWriterParameters (::std::unique_ptr< FileWriterParameters_type > x) +{ + this->FileWriterParameters_.set (std::move (x)); +} + +const Simulation::SimulationParameters_type& Simulation:: +SimulationParameters () const +{ + return this->SimulationParameters_.get (); +} + +Simulation::SimulationParameters_type& Simulation:: +SimulationParameters () +{ + return this->SimulationParameters_.get (); +} + +void Simulation:: +SimulationParameters (const SimulationParameters_type& x) +{ + this->SimulationParameters_.set (x); +} + +void Simulation:: +SimulationParameters (::std::unique_ptr< SimulationParameters_type > x) +{ + this->SimulationParameters_.set (std::move (x)); +} + +const Simulation::ThermostatParameters_type& Simulation:: +ThermostatParameters () const +{ + return this->ThermostatParameters_.get (); +} + +Simulation::ThermostatParameters_type& Simulation:: +ThermostatParameters () +{ + return this->ThermostatParameters_.get (); +} + +void Simulation:: +ThermostatParameters (const ThermostatParameters_type& x) +{ + this->ThermostatParameters_.set (x); +} + +void Simulation:: +ThermostatParameters (::std::unique_ptr< ThermostatParameters_type > x) +{ + this->ThermostatParameters_.set (std::move (x)); +} + +const Simulation::LinkedCellsParameters_type& Simulation:: +LinkedCellsParameters () const +{ + return this->LinkedCellsParameters_.get (); +} + +Simulation::LinkedCellsParameters_type& Simulation:: +LinkedCellsParameters () +{ + return this->LinkedCellsParameters_.get (); +} + +void Simulation:: +LinkedCellsParameters (const LinkedCellsParameters_type& x) +{ + this->LinkedCellsParameters_.set (x); +} + +void Simulation:: +LinkedCellsParameters (::std::unique_ptr< LinkedCellsParameters_type > x) +{ + this->LinkedCellsParameters_.set (std::move (x)); +} + +const Simulation::BoundaryParameters_type& Simulation:: +BoundaryParameters () const +{ + return this->BoundaryParameters_.get (); +} + +Simulation::BoundaryParameters_type& Simulation:: +BoundaryParameters () +{ + return this->BoundaryParameters_.get (); +} + +void Simulation:: +BoundaryParameters (const BoundaryParameters_type& x) +{ + this->BoundaryParameters_.set (x); +} + +void Simulation:: +BoundaryParameters (::std::unique_ptr< BoundaryParameters_type > x) +{ + this->BoundaryParameters_.set (std::move (x)); +} + +const Simulation::Cuboid_sequence& Simulation:: +Cuboid () const +{ + return this->Cuboid_; +} + +Simulation::Cuboid_sequence& Simulation:: +Cuboid () +{ + return this->Cuboid_; +} + +void Simulation:: +Cuboid (const Cuboid_sequence& s) +{ + this->Cuboid_ = s; +} + +const Simulation::Disc_sequence& Simulation:: +Disc () const +{ + return this->Disc_; +} + +Simulation::Disc_sequence& Simulation:: +Disc () +{ + return this->Disc_; +} + +void Simulation:: +Disc (const Disc_sequence& s) +{ + this->Disc_ = s; +} + + +#include + +// FileWriterParametersType +// + +FileWriterParametersType:: +FileWriterParametersType (const BaseName_type& BaseName, + const WriteFrequency_type& WriteFrequency) +: ::xml_schema::type (), + BaseName_ (BaseName, this), + WriteFrequency_ (WriteFrequency, this) +{ +} + +FileWriterParametersType:: +FileWriterParametersType (const FileWriterParametersType& x, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::type (x, f, c), + BaseName_ (x.BaseName_, f, this), + WriteFrequency_ (x.WriteFrequency_, f, this) +{ +} + +FileWriterParametersType:: +FileWriterParametersType (const ::xercesc::DOMElement& e, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::type (e, f | ::xml_schema::flags::base, c), + BaseName_ (this), + WriteFrequency_ (this) +{ + if ((f & ::xml_schema::flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, false); + this->parse (p, f); + } +} + +void FileWriterParametersType:: +parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::flags f) +{ + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // BaseName + // + if (n.name () == "BaseName" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< BaseName_type > r ( + BaseName_traits::create (i, f, this)); + + if (!BaseName_.present ()) + { + this->BaseName_.set (::std::move (r)); + continue; + } + } + + // WriteFrequency + // + if (n.name () == "WriteFrequency" && n.namespace_ ().empty ()) + { + if (!WriteFrequency_.present ()) + { + this->WriteFrequency_.set (WriteFrequency_traits::create (i, f, this)); + continue; + } + } + + break; + } + + if (!BaseName_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "BaseName", + ""); + } + + if (!WriteFrequency_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "WriteFrequency", + ""); + } +} + +FileWriterParametersType* FileWriterParametersType:: +_clone (::xml_schema::flags f, + ::xml_schema::container* c) const +{ + return new class FileWriterParametersType (*this, f, c); +} + +FileWriterParametersType& FileWriterParametersType:: +operator= (const FileWriterParametersType& x) +{ + if (this != &x) + { + static_cast< ::xml_schema::type& > (*this) = x; + this->BaseName_ = x.BaseName_; + this->WriteFrequency_ = x.WriteFrequency_; + } + + return *this; +} + +FileWriterParametersType:: +~FileWriterParametersType () +{ +} + +// SimulationParametersType +// + +SimulationParametersType:: +SimulationParametersType (const EndT_type& EndT, + const DeltaT_type& DeltaT, + const Dimension_type& Dimension) +: ::xml_schema::type (), + EndT_ (EndT, this), + DeltaT_ (DeltaT, this), + Gravity_ (this), + Dimension_ (Dimension, this) +{ +} + +SimulationParametersType:: +SimulationParametersType (const SimulationParametersType& x, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::type (x, f, c), + EndT_ (x.EndT_, f, this), + DeltaT_ (x.DeltaT_, f, this), + Gravity_ (x.Gravity_, f, this), + Dimension_ (x.Dimension_, f, this) +{ +} + +SimulationParametersType:: +SimulationParametersType (const ::xercesc::DOMElement& e, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::type (e, f | ::xml_schema::flags::base, c), + EndT_ (this), + DeltaT_ (this), + Gravity_ (this), + Dimension_ (this) +{ + if ((f & ::xml_schema::flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, false); + this->parse (p, f); + } +} + +void SimulationParametersType:: +parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::flags f) +{ + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // EndT + // + if (n.name () == "EndT" && n.namespace_ ().empty ()) + { + if (!EndT_.present ()) + { + this->EndT_.set (EndT_traits::create (i, f, this)); + continue; + } + } + + // DeltaT + // + if (n.name () == "DeltaT" && n.namespace_ ().empty ()) + { + if (!DeltaT_.present ()) + { + this->DeltaT_.set (DeltaT_traits::create (i, f, this)); + continue; + } + } + + // Gravity + // + if (n.name () == "Gravity" && n.namespace_ ().empty ()) + { + if (!this->Gravity_) + { + this->Gravity_.set (Gravity_traits::create (i, f, this)); + continue; + } + } + + // Dimension + // + if (n.name () == "Dimension" && n.namespace_ ().empty ()) + { + if (!Dimension_.present ()) + { + this->Dimension_.set (Dimension_traits::create (i, f, this)); + continue; + } + } + + break; + } + + if (!EndT_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "EndT", + ""); + } + + if (!DeltaT_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "DeltaT", + ""); + } + + if (!Dimension_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "Dimension", + ""); + } +} + +SimulationParametersType* SimulationParametersType:: +_clone (::xml_schema::flags f, + ::xml_schema::container* c) const +{ + return new class SimulationParametersType (*this, f, c); +} + +SimulationParametersType& SimulationParametersType:: +operator= (const SimulationParametersType& x) +{ + if (this != &x) + { + static_cast< ::xml_schema::type& > (*this) = x; + this->EndT_ = x.EndT_; + this->DeltaT_ = x.DeltaT_; + this->Gravity_ = x.Gravity_; + this->Dimension_ = x.Dimension_; + } + + return *this; +} + +SimulationParametersType:: +~SimulationParametersType () +{ +} + +// ThermostatParametersType +// + +ThermostatParametersType:: +ThermostatParametersType (const StartTemperature_type& StartTemperature, + const TargetTemperature_type& TargetTemperature, + const ApplyFrequency_type& ApplyFrequency, + const MaxDeltaTemperature_type& MaxDeltaTemperature, + const Dimension_type& Dimension) +: ::xml_schema::type (), + StartTemperature_ (StartTemperature, this), + TargetTemperature_ (TargetTemperature, this), + ApplyFrequency_ (ApplyFrequency, this), + MaxDeltaTemperature_ (MaxDeltaTemperature, this), + Dimension_ (Dimension, this) +{ +} + +ThermostatParametersType:: +ThermostatParametersType (const ThermostatParametersType& x, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::type (x, f, c), + StartTemperature_ (x.StartTemperature_, f, this), + TargetTemperature_ (x.TargetTemperature_, f, this), + ApplyFrequency_ (x.ApplyFrequency_, f, this), + MaxDeltaTemperature_ (x.MaxDeltaTemperature_, f, this), + Dimension_ (x.Dimension_, f, this) +{ +} + +ThermostatParametersType:: +ThermostatParametersType (const ::xercesc::DOMElement& e, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::type (e, f | ::xml_schema::flags::base, c), + StartTemperature_ (this), + TargetTemperature_ (this), + ApplyFrequency_ (this), + MaxDeltaTemperature_ (this), + Dimension_ (this) +{ + if ((f & ::xml_schema::flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, false); + this->parse (p, f); + } +} + +void ThermostatParametersType:: +parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::flags f) +{ + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // StartTemperature + // + if (n.name () == "StartTemperature" && n.namespace_ ().empty ()) + { + if (!StartTemperature_.present ()) + { + this->StartTemperature_.set (StartTemperature_traits::create (i, f, this)); + continue; + } + } + + // TargetTemperature + // + if (n.name () == "TargetTemperature" && n.namespace_ ().empty ()) + { + if (!TargetTemperature_.present ()) + { + this->TargetTemperature_.set (TargetTemperature_traits::create (i, f, this)); + continue; + } + } + + // ApplyFrequency + // + if (n.name () == "ApplyFrequency" && n.namespace_ ().empty ()) + { + if (!ApplyFrequency_.present ()) + { + this->ApplyFrequency_.set (ApplyFrequency_traits::create (i, f, this)); + continue; + } + } + + // MaxDeltaTemperature + // + if (n.name () == "MaxDeltaTemperature" && n.namespace_ ().empty ()) + { + if (!MaxDeltaTemperature_.present ()) + { + this->MaxDeltaTemperature_.set (MaxDeltaTemperature_traits::create (i, f, this)); + continue; + } + } + + // Dimension + // + if (n.name () == "Dimension" && n.namespace_ ().empty ()) + { + if (!Dimension_.present ()) + { + this->Dimension_.set (Dimension_traits::create (i, f, this)); + continue; + } + } + + break; + } + + if (!StartTemperature_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "StartTemperature", + ""); + } + + if (!TargetTemperature_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "TargetTemperature", + ""); + } + + if (!ApplyFrequency_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "ApplyFrequency", + ""); + } + + if (!MaxDeltaTemperature_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "MaxDeltaTemperature", + ""); + } + + if (!Dimension_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "Dimension", + ""); + } +} + +ThermostatParametersType* ThermostatParametersType:: +_clone (::xml_schema::flags f, + ::xml_schema::container* c) const +{ + return new class ThermostatParametersType (*this, f, c); +} + +ThermostatParametersType& ThermostatParametersType:: +operator= (const ThermostatParametersType& x) +{ + if (this != &x) + { + static_cast< ::xml_schema::type& > (*this) = x; + this->StartTemperature_ = x.StartTemperature_; + this->TargetTemperature_ = x.TargetTemperature_; + this->ApplyFrequency_ = x.ApplyFrequency_; + this->MaxDeltaTemperature_ = x.MaxDeltaTemperature_; + this->Dimension_ = x.Dimension_; + } + + return *this; +} + +ThermostatParametersType:: +~ThermostatParametersType () +{ +} + +// LinkedCellsParametersType +// + +LinkedCellsParametersType:: +LinkedCellsParametersType (const LinkedCellsUsed_type& LinkedCellsUsed, + const CutoffRadius_type& CutoffRadius) +: ::xml_schema::type (), + LinkedCellsUsed_ (LinkedCellsUsed, this), + CutoffRadius_ (CutoffRadius, this) +{ +} + +LinkedCellsParametersType:: +LinkedCellsParametersType (const LinkedCellsParametersType& x, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::type (x, f, c), + LinkedCellsUsed_ (x.LinkedCellsUsed_, f, this), + CutoffRadius_ (x.CutoffRadius_, f, this) +{ +} + +LinkedCellsParametersType:: +LinkedCellsParametersType (const ::xercesc::DOMElement& e, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::type (e, f | ::xml_schema::flags::base, c), + LinkedCellsUsed_ (this), + CutoffRadius_ (this) +{ + if ((f & ::xml_schema::flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, false); + this->parse (p, f); + } +} + +void LinkedCellsParametersType:: +parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::flags f) +{ + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // LinkedCellsUsed + // + if (n.name () == "LinkedCellsUsed" && n.namespace_ ().empty ()) + { + if (!LinkedCellsUsed_.present ()) + { + this->LinkedCellsUsed_.set (LinkedCellsUsed_traits::create (i, f, this)); + continue; + } + } + + // CutoffRadius + // + if (n.name () == "CutoffRadius" && n.namespace_ ().empty ()) + { + if (!CutoffRadius_.present ()) + { + this->CutoffRadius_.set (CutoffRadius_traits::create (i, f, this)); + continue; + } + } + + break; + } + + if (!LinkedCellsUsed_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "LinkedCellsUsed", + ""); + } + + if (!CutoffRadius_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "CutoffRadius", + ""); + } +} + +LinkedCellsParametersType* LinkedCellsParametersType:: +_clone (::xml_schema::flags f, + ::xml_schema::container* c) const +{ + return new class LinkedCellsParametersType (*this, f, c); +} + +LinkedCellsParametersType& LinkedCellsParametersType:: +operator= (const LinkedCellsParametersType& x) +{ + if (this != &x) + { + static_cast< ::xml_schema::type& > (*this) = x; + this->LinkedCellsUsed_ = x.LinkedCellsUsed_; + this->CutoffRadius_ = x.CutoffRadius_; + } + + return *this; +} + +LinkedCellsParametersType:: +~LinkedCellsParametersType () +{ +} + +// BoundaryParametersType +// + +BoundaryParametersType:: +BoundaryParametersType (const Domain_type& Domain, + const TOP_type& TOP, + const RIGHT_type& RIGHT, + const BOTTOM_type& BOTTOM, + const LEFT_type& LEFT, + const FRONT_type& FRONT, + const BACK_type& BACK) +: ::xml_schema::type (), + Domain_ (Domain, this), + TOP_ (TOP, this), + RIGHT_ (RIGHT, this), + BOTTOM_ (BOTTOM, this), + LEFT_ (LEFT, this), + FRONT_ (FRONT, this), + BACK_ (BACK, this) +{ +} + +BoundaryParametersType:: +BoundaryParametersType (const BoundaryParametersType& x, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::type (x, f, c), + Domain_ (x.Domain_, f, this), + TOP_ (x.TOP_, f, this), + RIGHT_ (x.RIGHT_, f, this), + BOTTOM_ (x.BOTTOM_, f, this), + LEFT_ (x.LEFT_, f, this), + FRONT_ (x.FRONT_, f, this), + BACK_ (x.BACK_, f, this) +{ +} + +BoundaryParametersType:: +BoundaryParametersType (const ::xercesc::DOMElement& e, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::type (e, f | ::xml_schema::flags::base, c), + Domain_ (this), + TOP_ (this), + RIGHT_ (this), + BOTTOM_ (this), + LEFT_ (this), + FRONT_ (this), + BACK_ (this) +{ + if ((f & ::xml_schema::flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, false); + this->parse (p, f); + } +} + +void BoundaryParametersType:: +parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::flags f) +{ + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // Domain + // + if (n.name () == "Domain" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< Domain_type > r ( + Domain_traits::create (i, f, this)); + + if (!Domain_.present ()) + { + this->Domain_.set (::std::move (r)); + continue; + } + } + + // TOP + // + if (n.name () == "TOP" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< TOP_type > r ( + TOP_traits::create (i, f, this)); + + if (!TOP_.present ()) + { + this->TOP_.set (::std::move (r)); + continue; + } + } + + // RIGHT + // + if (n.name () == "RIGHT" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< RIGHT_type > r ( + RIGHT_traits::create (i, f, this)); + + if (!RIGHT_.present ()) + { + this->RIGHT_.set (::std::move (r)); + continue; + } + } + + // BOTTOM + // + if (n.name () == "BOTTOM" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< BOTTOM_type > r ( + BOTTOM_traits::create (i, f, this)); + + if (!BOTTOM_.present ()) + { + this->BOTTOM_.set (::std::move (r)); + continue; + } + } + + // LEFT + // + if (n.name () == "LEFT" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< LEFT_type > r ( + LEFT_traits::create (i, f, this)); + + if (!LEFT_.present ()) + { + this->LEFT_.set (::std::move (r)); + continue; + } + } + + // FRONT + // + if (n.name () == "FRONT" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< FRONT_type > r ( + FRONT_traits::create (i, f, this)); + + if (!FRONT_.present ()) + { + this->FRONT_.set (::std::move (r)); + continue; + } + } + + // BACK + // + if (n.name () == "BACK" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< BACK_type > r ( + BACK_traits::create (i, f, this)); + + if (!BACK_.present ()) + { + this->BACK_.set (::std::move (r)); + continue; + } + } + + break; + } + + if (!Domain_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "Domain", + ""); + } + + if (!TOP_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "TOP", + ""); + } + + if (!RIGHT_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "RIGHT", + ""); + } + + if (!BOTTOM_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "BOTTOM", + ""); + } + + if (!LEFT_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "LEFT", + ""); + } + + if (!FRONT_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "FRONT", + ""); + } + + if (!BACK_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "BACK", + ""); + } +} + +BoundaryParametersType* BoundaryParametersType:: +_clone (::xml_schema::flags f, + ::xml_schema::container* c) const +{ + return new class BoundaryParametersType (*this, f, c); +} + +BoundaryParametersType& BoundaryParametersType:: +operator= (const BoundaryParametersType& x) +{ + if (this != &x) + { + static_cast< ::xml_schema::type& > (*this) = x; + this->Domain_ = x.Domain_; + this->TOP_ = x.TOP_; + this->RIGHT_ = x.RIGHT_; + this->BOTTOM_ = x.BOTTOM_; + this->LEFT_ = x.LEFT_; + this->FRONT_ = x.FRONT_; + this->BACK_ = x.BACK_; + } + + return *this; +} + +BoundaryParametersType:: +~BoundaryParametersType () +{ +} + +// CuboidType +// + +CuboidType:: +CuboidType (const Coordinates_type& Coordinates, + const ParticlesPerDimension_type& ParticlesPerDimension, + const Distance_type& Distance, + const Mass_type& Mass, + const InitialVelocities_type& InitialVelocities, + const MeanVelocity_type& MeanVelocity, + const Sigma_type& Sigma, + const Epsilon_type& Epsilon) +: ::xml_schema::type (), + Coordinates_ (Coordinates, this), + ParticlesPerDimension_ (ParticlesPerDimension, this), + Distance_ (Distance, this), + Mass_ (Mass, this), + InitialVelocities_ (InitialVelocities, this), + MeanVelocity_ (MeanVelocity, this), + Sigma_ (Sigma, this), + Epsilon_ (Epsilon, this) +{ +} + +CuboidType:: +CuboidType (const CuboidType& x, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::type (x, f, c), + Coordinates_ (x.Coordinates_, f, this), + ParticlesPerDimension_ (x.ParticlesPerDimension_, f, this), + Distance_ (x.Distance_, f, this), + Mass_ (x.Mass_, f, this), + InitialVelocities_ (x.InitialVelocities_, f, this), + MeanVelocity_ (x.MeanVelocity_, f, this), + Sigma_ (x.Sigma_, f, this), + Epsilon_ (x.Epsilon_, f, this) +{ +} + +CuboidType:: +CuboidType (const ::xercesc::DOMElement& e, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::type (e, f | ::xml_schema::flags::base, c), + Coordinates_ (this), + ParticlesPerDimension_ (this), + Distance_ (this), + Mass_ (this), + InitialVelocities_ (this), + MeanVelocity_ (this), + Sigma_ (this), + Epsilon_ (this) +{ + if ((f & ::xml_schema::flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, false); + this->parse (p, f); + } +} + +void CuboidType:: +parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::flags f) +{ + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // Coordinates + // + if (n.name () == "Coordinates" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< Coordinates_type > r ( + Coordinates_traits::create (i, f, this)); + + if (!Coordinates_.present ()) + { + this->Coordinates_.set (::std::move (r)); + continue; + } + } + + // ParticlesPerDimension + // + if (n.name () == "ParticlesPerDimension" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< ParticlesPerDimension_type > r ( + ParticlesPerDimension_traits::create (i, f, this)); + + if (!ParticlesPerDimension_.present ()) + { + this->ParticlesPerDimension_.set (::std::move (r)); + continue; + } + } + + // Distance + // + if (n.name () == "Distance" && n.namespace_ ().empty ()) + { + if (!Distance_.present ()) + { + this->Distance_.set (Distance_traits::create (i, f, this)); + continue; + } + } + + // Mass + // + if (n.name () == "Mass" && n.namespace_ ().empty ()) + { + if (!Mass_.present ()) + { + this->Mass_.set (Mass_traits::create (i, f, this)); + continue; + } + } + + // InitialVelocities + // + if (n.name () == "InitialVelocities" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< InitialVelocities_type > r ( + InitialVelocities_traits::create (i, f, this)); + + if (!InitialVelocities_.present ()) + { + this->InitialVelocities_.set (::std::move (r)); + continue; + } + } + + // MeanVelocity + // + if (n.name () == "MeanVelocity" && n.namespace_ ().empty ()) + { + if (!MeanVelocity_.present ()) + { + this->MeanVelocity_.set (MeanVelocity_traits::create (i, f, this)); + continue; + } + } + + // Sigma + // + if (n.name () == "Sigma" && n.namespace_ ().empty ()) + { + if (!Sigma_.present ()) + { + this->Sigma_.set (Sigma_traits::create (i, f, this)); + continue; + } + } + + // Epsilon + // + if (n.name () == "Epsilon" && n.namespace_ ().empty ()) + { + if (!Epsilon_.present ()) + { + this->Epsilon_.set (Epsilon_traits::create (i, f, this)); + continue; + } + } + + break; + } + + if (!Coordinates_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "Coordinates", + ""); + } + + if (!ParticlesPerDimension_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "ParticlesPerDimension", + ""); + } + + if (!Distance_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "Distance", + ""); + } + + if (!Mass_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "Mass", + ""); + } + + if (!InitialVelocities_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "InitialVelocities", + ""); + } + + if (!MeanVelocity_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "MeanVelocity", + ""); + } + + if (!Sigma_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "Sigma", + ""); + } + + if (!Epsilon_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "Epsilon", + ""); + } +} + +CuboidType* CuboidType:: +_clone (::xml_schema::flags f, + ::xml_schema::container* c) const +{ + return new class CuboidType (*this, f, c); +} + +CuboidType& CuboidType:: +operator= (const CuboidType& x) +{ + if (this != &x) + { + static_cast< ::xml_schema::type& > (*this) = x; + this->Coordinates_ = x.Coordinates_; + this->ParticlesPerDimension_ = x.ParticlesPerDimension_; + this->Distance_ = x.Distance_; + this->Mass_ = x.Mass_; + this->InitialVelocities_ = x.InitialVelocities_; + this->MeanVelocity_ = x.MeanVelocity_; + this->Sigma_ = x.Sigma_; + this->Epsilon_ = x.Epsilon_; + } + + return *this; +} + +CuboidType:: +~CuboidType () +{ +} + +// DiscType +// + +DiscType:: +DiscType (const CenterCoordinates_type& CenterCoordinates, + const InitialVelocities_type& InitialVelocities, + const NumberOfParticlesAlongRadius_type& NumberOfParticlesAlongRadius, + const Distance_type& Distance, + const Mass_type& Mass, + const Sigma_type& Sigma, + const Epsilon_type& Epsilon) +: ::xml_schema::type (), + CenterCoordinates_ (CenterCoordinates, this), + InitialVelocities_ (InitialVelocities, this), + NumberOfParticlesAlongRadius_ (NumberOfParticlesAlongRadius, this), + Distance_ (Distance, this), + Mass_ (Mass, this), + Sigma_ (Sigma, this), + Epsilon_ (Epsilon, this) +{ +} + +DiscType:: +DiscType (const DiscType& x, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::type (x, f, c), + CenterCoordinates_ (x.CenterCoordinates_, f, this), + InitialVelocities_ (x.InitialVelocities_, f, this), + NumberOfParticlesAlongRadius_ (x.NumberOfParticlesAlongRadius_, f, this), + Distance_ (x.Distance_, f, this), + Mass_ (x.Mass_, f, this), + Sigma_ (x.Sigma_, f, this), + Epsilon_ (x.Epsilon_, f, this) +{ +} + +DiscType:: +DiscType (const ::xercesc::DOMElement& e, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::type (e, f | ::xml_schema::flags::base, c), + CenterCoordinates_ (this), + InitialVelocities_ (this), + NumberOfParticlesAlongRadius_ (this), + Distance_ (this), + Mass_ (this), + Sigma_ (this), + Epsilon_ (this) +{ + if ((f & ::xml_schema::flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, false); + this->parse (p, f); + } +} + +void DiscType:: +parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::flags f) +{ + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // CenterCoordinates + // + if (n.name () == "CenterCoordinates" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< CenterCoordinates_type > r ( + CenterCoordinates_traits::create (i, f, this)); + + if (!CenterCoordinates_.present ()) + { + this->CenterCoordinates_.set (::std::move (r)); + continue; + } + } + + // InitialVelocities + // + if (n.name () == "InitialVelocities" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< InitialVelocities_type > r ( + InitialVelocities_traits::create (i, f, this)); + + if (!InitialVelocities_.present ()) + { + this->InitialVelocities_.set (::std::move (r)); + continue; + } + } + + // NumberOfParticlesAlongRadius + // + if (n.name () == "NumberOfParticlesAlongRadius" && n.namespace_ ().empty ()) + { + if (!NumberOfParticlesAlongRadius_.present ()) + { + this->NumberOfParticlesAlongRadius_.set (NumberOfParticlesAlongRadius_traits::create (i, f, this)); + continue; + } + } + + // Distance + // + if (n.name () == "Distance" && n.namespace_ ().empty ()) + { + if (!Distance_.present ()) + { + this->Distance_.set (Distance_traits::create (i, f, this)); + continue; + } + } + + // Mass + // + if (n.name () == "Mass" && n.namespace_ ().empty ()) + { + if (!Mass_.present ()) + { + this->Mass_.set (Mass_traits::create (i, f, this)); + continue; + } + } + + // Sigma + // + if (n.name () == "Sigma" && n.namespace_ ().empty ()) + { + if (!Sigma_.present ()) + { + this->Sigma_.set (Sigma_traits::create (i, f, this)); + continue; + } + } + + // Epsilon + // + if (n.name () == "Epsilon" && n.namespace_ ().empty ()) + { + if (!Epsilon_.present ()) + { + this->Epsilon_.set (Epsilon_traits::create (i, f, this)); + continue; + } + } + + break; + } + + if (!CenterCoordinates_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "CenterCoordinates", + ""); + } + + if (!InitialVelocities_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "InitialVelocities", + ""); + } + + if (!NumberOfParticlesAlongRadius_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "NumberOfParticlesAlongRadius", + ""); + } + + if (!Distance_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "Distance", + ""); + } + + if (!Mass_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "Mass", + ""); + } + + if (!Sigma_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "Sigma", + ""); + } + + if (!Epsilon_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "Epsilon", + ""); + } +} + +DiscType* DiscType:: +_clone (::xml_schema::flags f, + ::xml_schema::container* c) const +{ + return new class DiscType (*this, f, c); +} + +DiscType& DiscType:: +operator= (const DiscType& x) +{ + if (this != &x) + { + static_cast< ::xml_schema::type& > (*this) = x; + this->CenterCoordinates_ = x.CenterCoordinates_; + this->InitialVelocities_ = x.InitialVelocities_; + this->NumberOfParticlesAlongRadius_ = x.NumberOfParticlesAlongRadius_; + this->Distance_ = x.Distance_; + this->Mass_ = x.Mass_; + this->Sigma_ = x.Sigma_; + this->Epsilon_ = x.Epsilon_; + } + + return *this; +} + +DiscType:: +~DiscType () +{ +} + +// BoundaryType +// + +BoundaryType:: +BoundaryType (const ::xercesc::DOMElement& e, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::string (e, f, c) +{ + _xsd_BoundaryType_convert (); +} + +BoundaryType:: +BoundaryType (const ::xercesc::DOMAttr& a, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::string (a, f, c) +{ + _xsd_BoundaryType_convert (); +} + +BoundaryType:: +BoundaryType (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::string (s, e, f, c) +{ + _xsd_BoundaryType_convert (); +} + +BoundaryType* BoundaryType:: +_clone (::xml_schema::flags f, + ::xml_schema::container* c) const +{ + return new class BoundaryType (*this, f, c); +} + +BoundaryType::value BoundaryType:: +_xsd_BoundaryType_convert () const +{ + ::xsd::cxx::tree::enum_comparator< char > c (_xsd_BoundaryType_literals_); + const value* i (::std::lower_bound ( + _xsd_BoundaryType_indexes_, + _xsd_BoundaryType_indexes_ + 4, + *this, + c)); + + if (i == _xsd_BoundaryType_indexes_ + 4 || _xsd_BoundaryType_literals_[*i] != *this) + { + throw ::xsd::cxx::tree::unexpected_enumerator < char > (*this); + } + + return *i; +} + +const char* const BoundaryType:: +_xsd_BoundaryType_literals_[4] = +{ + "REFLECTING", + "OUTFLOW", + "PERIODIC", + "OFF" +}; + +const BoundaryType::value BoundaryType:: +_xsd_BoundaryType_indexes_[4] = +{ + ::BoundaryType::OFF, + ::BoundaryType::OUTFLOW, + ::BoundaryType::PERIODIC, + ::BoundaryType::REFLECTING +}; + +// Simulation +// + +Simulation:: +Simulation (const FileWriterParameters_type& FileWriterParameters, + const SimulationParameters_type& SimulationParameters, + const ThermostatParameters_type& ThermostatParameters, + const LinkedCellsParameters_type& LinkedCellsParameters, + const BoundaryParameters_type& BoundaryParameters) +: ::xml_schema::type (), + FileWriterParameters_ (FileWriterParameters, this), + SimulationParameters_ (SimulationParameters, this), + ThermostatParameters_ (ThermostatParameters, this), + LinkedCellsParameters_ (LinkedCellsParameters, this), + BoundaryParameters_ (BoundaryParameters, this), + Cuboid_ (this), + Disc_ (this) +{ +} + +Simulation:: +Simulation (::std::unique_ptr< FileWriterParameters_type > FileWriterParameters, + ::std::unique_ptr< SimulationParameters_type > SimulationParameters, + ::std::unique_ptr< ThermostatParameters_type > ThermostatParameters, + ::std::unique_ptr< LinkedCellsParameters_type > LinkedCellsParameters, + ::std::unique_ptr< BoundaryParameters_type > BoundaryParameters) +: ::xml_schema::type (), + FileWriterParameters_ (std::move (FileWriterParameters), this), + SimulationParameters_ (std::move (SimulationParameters), this), + ThermostatParameters_ (std::move (ThermostatParameters), this), + LinkedCellsParameters_ (std::move (LinkedCellsParameters), this), + BoundaryParameters_ (std::move (BoundaryParameters), this), + Cuboid_ (this), + Disc_ (this) +{ +} + +Simulation:: +Simulation (const Simulation& x, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::type (x, f, c), + FileWriterParameters_ (x.FileWriterParameters_, f, this), + SimulationParameters_ (x.SimulationParameters_, f, this), + ThermostatParameters_ (x.ThermostatParameters_, f, this), + LinkedCellsParameters_ (x.LinkedCellsParameters_, f, this), + BoundaryParameters_ (x.BoundaryParameters_, f, this), + Cuboid_ (x.Cuboid_, f, this), + Disc_ (x.Disc_, f, this) +{ +} + +Simulation:: +Simulation (const ::xercesc::DOMElement& e, + ::xml_schema::flags f, + ::xml_schema::container* c) +: ::xml_schema::type (e, f | ::xml_schema::flags::base, c), + FileWriterParameters_ (this), + SimulationParameters_ (this), + ThermostatParameters_ (this), + LinkedCellsParameters_ (this), + BoundaryParameters_ (this), + Cuboid_ (this), + Disc_ (this) +{ + if ((f & ::xml_schema::flags::base) == 0) + { + ::xsd::cxx::xml::dom::parser< char > p (e, true, false, false); + this->parse (p, f); + } +} + +void Simulation:: +parse (::xsd::cxx::xml::dom::parser< char >& p, + ::xml_schema::flags f) +{ + for (; p.more_content (); p.next_content (false)) + { + const ::xercesc::DOMElement& i (p.cur_element ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (i)); + + // FileWriterParameters + // + if (n.name () == "FileWriterParameters" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< FileWriterParameters_type > r ( + FileWriterParameters_traits::create (i, f, this)); + + if (!FileWriterParameters_.present ()) + { + this->FileWriterParameters_.set (::std::move (r)); + continue; + } + } + + // SimulationParameters + // + if (n.name () == "SimulationParameters" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< SimulationParameters_type > r ( + SimulationParameters_traits::create (i, f, this)); + + if (!SimulationParameters_.present ()) + { + this->SimulationParameters_.set (::std::move (r)); + continue; + } + } + + // ThermostatParameters + // + if (n.name () == "ThermostatParameters" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< ThermostatParameters_type > r ( + ThermostatParameters_traits::create (i, f, this)); + + if (!ThermostatParameters_.present ()) + { + this->ThermostatParameters_.set (::std::move (r)); + continue; + } + } + + // LinkedCellsParameters + // + if (n.name () == "LinkedCellsParameters" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< LinkedCellsParameters_type > r ( + LinkedCellsParameters_traits::create (i, f, this)); + + if (!LinkedCellsParameters_.present ()) + { + this->LinkedCellsParameters_.set (::std::move (r)); + continue; + } + } + + // BoundaryParameters + // + if (n.name () == "BoundaryParameters" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< BoundaryParameters_type > r ( + BoundaryParameters_traits::create (i, f, this)); + + if (!BoundaryParameters_.present ()) + { + this->BoundaryParameters_.set (::std::move (r)); + continue; + } + } + + // Cuboid + // + if (n.name () == "Cuboid" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< Cuboid_type > r ( + Cuboid_traits::create (i, f, this)); + + this->Cuboid_.push_back (::std::move (r)); + continue; + } + + // Disc + // + if (n.name () == "Disc" && n.namespace_ ().empty ()) + { + ::std::unique_ptr< Disc_type > r ( + Disc_traits::create (i, f, this)); + + this->Disc_.push_back (::std::move (r)); + continue; + } + + break; + } + + if (!FileWriterParameters_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "FileWriterParameters", + ""); + } + + if (!SimulationParameters_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "SimulationParameters", + ""); + } + + if (!ThermostatParameters_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "ThermostatParameters", + ""); + } + + if (!LinkedCellsParameters_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "LinkedCellsParameters", + ""); + } + + if (!BoundaryParameters_.present ()) + { + throw ::xsd::cxx::tree::expected_element< char > ( + "BoundaryParameters", + ""); + } +} + +Simulation* Simulation:: +_clone (::xml_schema::flags f, + ::xml_schema::container* c) const +{ + return new class Simulation (*this, f, c); +} + +Simulation& Simulation:: +operator= (const Simulation& x) +{ + if (this != &x) + { + static_cast< ::xml_schema::type& > (*this) = x; + this->FileWriterParameters_ = x.FileWriterParameters_; + this->SimulationParameters_ = x.SimulationParameters_; + this->ThermostatParameters_ = x.ThermostatParameters_; + this->LinkedCellsParameters_ = x.LinkedCellsParameters_; + this->BoundaryParameters_ = x.BoundaryParameters_; + this->Cuboid_ = x.Cuboid_; + this->Disc_ = x.Disc_; + } + + return *this; +} + +Simulation:: +~Simulation () +{ +} + +#include +#include +#include + +::std::unique_ptr< ::Simulation > +Simulation_ (const ::std::string& u, + ::xml_schema::flags f, + const ::xml_schema::properties& p) +{ + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::flags::dont_initialize) == 0, + (f & ::xml_schema::flags::keep_dom) == 0); + + ::xsd::cxx::tree::error_handler< char > h; + + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + u, h, p, f)); + + h.throw_if_failed< ::xsd::cxx::tree::parsing< char > > (); + + return ::std::unique_ptr< ::Simulation > ( + ::Simulation_ ( + std::move (d), f | ::xml_schema::flags::own_dom, p)); +} + +::std::unique_ptr< ::Simulation > +Simulation_ (const ::std::string& u, + ::xml_schema::error_handler& h, + ::xml_schema::flags f, + const ::xml_schema::properties& p) +{ + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::flags::dont_initialize) == 0, + (f & ::xml_schema::flags::keep_dom) == 0); + + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + u, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::Simulation > ( + ::Simulation_ ( + std::move (d), f | ::xml_schema::flags::own_dom, p)); +} + +::std::unique_ptr< ::Simulation > +Simulation_ (const ::std::string& u, + ::xercesc::DOMErrorHandler& h, + ::xml_schema::flags f, + const ::xml_schema::properties& p) +{ + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + u, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::Simulation > ( + ::Simulation_ ( + std::move (d), f | ::xml_schema::flags::own_dom, p)); +} + +::std::unique_ptr< ::Simulation > +Simulation_ (::std::istream& is, + ::xml_schema::flags f, + const ::xml_schema::properties& p) +{ + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::flags::dont_initialize) == 0, + (f & ::xml_schema::flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is); + return ::Simulation_ (isrc, f, p); +} + +::std::unique_ptr< ::Simulation > +Simulation_ (::std::istream& is, + ::xml_schema::error_handler& h, + ::xml_schema::flags f, + const ::xml_schema::properties& p) +{ + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::flags::dont_initialize) == 0, + (f & ::xml_schema::flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is); + return ::Simulation_ (isrc, h, f, p); +} + +::std::unique_ptr< ::Simulation > +Simulation_ (::std::istream& is, + ::xercesc::DOMErrorHandler& h, + ::xml_schema::flags f, + const ::xml_schema::properties& p) +{ + ::xsd::cxx::xml::sax::std_input_source isrc (is); + return ::Simulation_ (isrc, h, f, p); +} + +::std::unique_ptr< ::Simulation > +Simulation_ (::std::istream& is, + const ::std::string& sid, + ::xml_schema::flags f, + const ::xml_schema::properties& p) +{ + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::flags::dont_initialize) == 0, + (f & ::xml_schema::flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); + return ::Simulation_ (isrc, f, p); +} + +::std::unique_ptr< ::Simulation > +Simulation_ (::std::istream& is, + const ::std::string& sid, + ::xml_schema::error_handler& h, + ::xml_schema::flags f, + const ::xml_schema::properties& p) +{ + ::xsd::cxx::xml::auto_initializer i ( + (f & ::xml_schema::flags::dont_initialize) == 0, + (f & ::xml_schema::flags::keep_dom) == 0); + + ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); + return ::Simulation_ (isrc, h, f, p); +} + +::std::unique_ptr< ::Simulation > +Simulation_ (::std::istream& is, + const ::std::string& sid, + ::xercesc::DOMErrorHandler& h, + ::xml_schema::flags f, + const ::xml_schema::properties& p) +{ + ::xsd::cxx::xml::sax::std_input_source isrc (is, sid); + return ::Simulation_ (isrc, h, f, p); +} + +::std::unique_ptr< ::Simulation > +Simulation_ (::xercesc::InputSource& i, + ::xml_schema::flags f, + const ::xml_schema::properties& p) +{ + ::xsd::cxx::tree::error_handler< char > h; + + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + i, h, p, f)); + + h.throw_if_failed< ::xsd::cxx::tree::parsing< char > > (); + + return ::std::unique_ptr< ::Simulation > ( + ::Simulation_ ( + std::move (d), f | ::xml_schema::flags::own_dom, p)); +} + +::std::unique_ptr< ::Simulation > +Simulation_ (::xercesc::InputSource& i, + ::xml_schema::error_handler& h, + ::xml_schema::flags f, + const ::xml_schema::properties& p) +{ + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + i, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::Simulation > ( + ::Simulation_ ( + std::move (d), f | ::xml_schema::flags::own_dom, p)); +} + +::std::unique_ptr< ::Simulation > +Simulation_ (::xercesc::InputSource& i, + ::xercesc::DOMErrorHandler& h, + ::xml_schema::flags f, + const ::xml_schema::properties& p) +{ + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + ::xsd::cxx::xml::dom::parse< char > ( + i, h, p, f)); + + if (!d.get ()) + throw ::xsd::cxx::tree::parsing< char > (); + + return ::std::unique_ptr< ::Simulation > ( + ::Simulation_ ( + std::move (d), f | ::xml_schema::flags::own_dom, p)); +} + +::std::unique_ptr< ::Simulation > +Simulation_ (const ::xercesc::DOMDocument& doc, + ::xml_schema::flags f, + const ::xml_schema::properties& p) +{ + if (f & ::xml_schema::flags::keep_dom) + { + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d ( + static_cast< ::xercesc::DOMDocument* > (doc.cloneNode (true))); + + return ::std::unique_ptr< ::Simulation > ( + ::Simulation_ ( + std::move (d), f | ::xml_schema::flags::own_dom, p)); + } + + const ::xercesc::DOMElement& e (*doc.getDocumentElement ()); + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (e)); + + if (n.name () == "Simulation" && + n.namespace_ () == "") + { + ::std::unique_ptr< ::Simulation > r ( + ::xsd::cxx::tree::traits< ::Simulation, char >::create ( + e, f, 0)); + return r; + } + + throw ::xsd::cxx::tree::unexpected_element < char > ( + n.name (), + n.namespace_ (), + "Simulation", + ""); +} + +::std::unique_ptr< ::Simulation > +Simulation_ (::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d, + ::xml_schema::flags f, + const ::xml_schema::properties&) +{ + ::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > c ( + ((f & ::xml_schema::flags::keep_dom) && + !(f & ::xml_schema::flags::own_dom)) + ? static_cast< ::xercesc::DOMDocument* > (d->cloneNode (true)) + : 0); + + ::xercesc::DOMDocument& doc (c.get () ? *c : *d); + const ::xercesc::DOMElement& e (*doc.getDocumentElement ()); + + const ::xsd::cxx::xml::qualified_name< char > n ( + ::xsd::cxx::xml::dom::name< char > (e)); + + if (f & ::xml_schema::flags::keep_dom) + doc.setUserData (::xml_schema::dom::tree_node_key, + (c.get () ? &c : &d), + 0); + + if (n.name () == "Simulation" && + n.namespace_ () == "") + { + ::std::unique_ptr< ::Simulation > r ( + ::xsd::cxx::tree::traits< ::Simulation, char >::create ( + e, f, 0)); + return r; + } + + throw ::xsd::cxx::tree::unexpected_element < char > ( + n.name (), + n.namespace_ (), + "Simulation", + ""); +} + +#include + +// Begin epilogue. +// +// +// End epilogue. + diff --git a/src/io/in/input_schema.hxx b/src/io/in/input_schema.hxx new file mode 100644 index 000000000..ad449b729 --- /dev/null +++ b/src/io/in/input_schema.hxx @@ -0,0 +1,1433 @@ +// Copyright (c) 2005-2023 Code Synthesis. +// +// This program was generated by CodeSynthesis XSD, an XML Schema to +// C++ data binding compiler. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// 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, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// +// In addition, as a special exception, Code Synthesis gives permission +// to link this program with the Xerces-C++ library (or with modified +// versions of Xerces-C++ that use the same license as Xerces-C++), and +// distribute linked combinations including the two. You must obey the GNU +// General Public License version 2 in all respects for all of the code +// used other than Xerces-C++. If you modify this copy of the program, you +// may extend this exception to your version of the program, but you are +// not obligated to do so. If you do not wish to do so, delete this +// exception statement from your version. +// +// Furthermore, Code Synthesis makes a special exception for the Free/Libre +// and Open Source Software (FLOSS) which is described in the accompanying +// FLOSSE file. +// + +#ifndef INPUT_SCHEMA_HXX +#define INPUT_SCHEMA_HXX + +#ifndef XSD_CXX11 +#define XSD_CXX11 +#endif + +#ifndef XSD_USE_CHAR +#define XSD_USE_CHAR +#endif + +#ifndef XSD_CXX_TREE_USE_CHAR +#define XSD_CXX_TREE_USE_CHAR +#endif + +// Begin prologue. +// +// +// End prologue. + +#include + +#if (XSD_INT_VERSION!=4000000L) +#error XSD runtime version mismatch +#endif + +#include + +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace xml_schema +{ + // anyType and anySimpleType. + // + typedef ::xsd::cxx::tree::type type; + typedef ::xsd::cxx::tree::simple_type< char, type > simple_type; + typedef ::xsd::cxx::tree::type container; + + // 8-bit + // + typedef signed char byte; + typedef unsigned char unsigned_byte; + + // 16-bit + // + typedef short short_; + typedef unsigned short unsigned_short; + + // 32-bit + // + typedef int int_; + typedef unsigned int unsigned_int; + + // 64-bit + // + typedef long long long_; + typedef unsigned long long unsigned_long; + + // Supposed to be arbitrary-length integral types. + // + typedef long long integer; + typedef long long non_positive_integer; + typedef unsigned long long non_negative_integer; + typedef unsigned long long positive_integer; + typedef long long negative_integer; + + // Boolean. + // + typedef bool boolean; + + // Floating-point types. + // + typedef float float_; + typedef double double_; + typedef double decimal; + + // String types. + // + typedef ::xsd::cxx::tree::string< char, simple_type > string; + typedef ::xsd::cxx::tree::normalized_string< char, string > normalized_string; + typedef ::xsd::cxx::tree::token< char, normalized_string > token; + typedef ::xsd::cxx::tree::name< char, token > name; + typedef ::xsd::cxx::tree::nmtoken< char, token > nmtoken; + typedef ::xsd::cxx::tree::nmtokens< char, simple_type, nmtoken > nmtokens; + typedef ::xsd::cxx::tree::ncname< char, name > ncname; + typedef ::xsd::cxx::tree::language< char, token > language; + + // ID/IDREF. + // + typedef ::xsd::cxx::tree::id< char, ncname > id; + typedef ::xsd::cxx::tree::idref< char, ncname, type > idref; + typedef ::xsd::cxx::tree::idrefs< char, simple_type, idref > idrefs; + + // URI. + // + typedef ::xsd::cxx::tree::uri< char, simple_type > uri; + + // Qualified name. + // + typedef ::xsd::cxx::tree::qname< char, simple_type, uri, ncname > qname; + + // Binary. + // + typedef ::xsd::cxx::tree::buffer< char > buffer; + typedef ::xsd::cxx::tree::base64_binary< char, simple_type > base64_binary; + typedef ::xsd::cxx::tree::hex_binary< char, simple_type > hex_binary; + + // Date/time. + // + typedef ::xsd::cxx::tree::time_zone time_zone; + typedef ::xsd::cxx::tree::date< char, simple_type > date; + typedef ::xsd::cxx::tree::date_time< char, simple_type > date_time; + typedef ::xsd::cxx::tree::duration< char, simple_type > duration; + typedef ::xsd::cxx::tree::gday< char, simple_type > gday; + typedef ::xsd::cxx::tree::gmonth< char, simple_type > gmonth; + typedef ::xsd::cxx::tree::gmonth_day< char, simple_type > gmonth_day; + typedef ::xsd::cxx::tree::gyear< char, simple_type > gyear; + typedef ::xsd::cxx::tree::gyear_month< char, simple_type > gyear_month; + typedef ::xsd::cxx::tree::time< char, simple_type > time; + + // Entity. + // + typedef ::xsd::cxx::tree::entity< char, ncname > entity; + typedef ::xsd::cxx::tree::entities< char, simple_type, entity > entities; + + typedef ::xsd::cxx::tree::content_order content_order; + // Flags and properties. + // + typedef ::xsd::cxx::tree::flags flags; + typedef ::xsd::cxx::tree::properties< char > properties; + + // Parsing/serialization diagnostics. + // + typedef ::xsd::cxx::tree::severity severity; + typedef ::xsd::cxx::tree::error< char > error; + typedef ::xsd::cxx::tree::diagnostics< char > diagnostics; + + // Exceptions. + // + typedef ::xsd::cxx::tree::exception< char > exception; + typedef ::xsd::cxx::tree::bounds< char > bounds; + typedef ::xsd::cxx::tree::duplicate_id< char > duplicate_id; + typedef ::xsd::cxx::tree::parsing< char > parsing; + typedef ::xsd::cxx::tree::expected_element< char > expected_element; + typedef ::xsd::cxx::tree::unexpected_element< char > unexpected_element; + typedef ::xsd::cxx::tree::expected_attribute< char > expected_attribute; + typedef ::xsd::cxx::tree::unexpected_enumerator< char > unexpected_enumerator; + typedef ::xsd::cxx::tree::expected_text_content< char > expected_text_content; + typedef ::xsd::cxx::tree::no_prefix_mapping< char > no_prefix_mapping; + + // Error handler callback interface. + // + typedef ::xsd::cxx::xml::error_handler< char > error_handler; + + // DOM interaction. + // + namespace dom + { + // Automatic pointer for DOMDocument. + // + using ::xsd::cxx::xml::dom::unique_ptr; + +#ifndef XSD_CXX_TREE_TREE_NODE_KEY__XML_SCHEMA +#define XSD_CXX_TREE_TREE_NODE_KEY__XML_SCHEMA + // DOM user data key for back pointers to tree nodes. + // + const XMLCh* const tree_node_key = ::xsd::cxx::tree::user_data_keys::node; +#endif + } +} + +// Forward declarations. +// +class FileWriterParametersType; +class SimulationParametersType; +class ThermostatParametersType; +class LinkedCellsParametersType; +class BoundaryParametersType; +class CuboidType; +class DiscType; +class BoundaryType; +class Simulation; + +#include // ::std::unique_ptr +#include // std::numeric_limits +#include // std::binary_search +#include // std::move + +#include + +#include +#include +#include +#include + +#include + +class FileWriterParametersType: public ::xml_schema::type +{ + public: + // BaseName + // + typedef ::xml_schema::string BaseName_type; + typedef ::xsd::cxx::tree::traits< BaseName_type, char > BaseName_traits; + + const BaseName_type& + BaseName () const; + + BaseName_type& + BaseName (); + + void + BaseName (const BaseName_type& x); + + void + BaseName (::std::unique_ptr< BaseName_type > p); + + // WriteFrequency + // + typedef ::xml_schema::int_ WriteFrequency_type; + typedef ::xsd::cxx::tree::traits< WriteFrequency_type, char > WriteFrequency_traits; + + const WriteFrequency_type& + WriteFrequency () const; + + WriteFrequency_type& + WriteFrequency (); + + void + WriteFrequency (const WriteFrequency_type& x); + + // Constructors. + // + FileWriterParametersType (const BaseName_type&, + const WriteFrequency_type&); + + FileWriterParametersType (const ::xercesc::DOMElement& e, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + + FileWriterParametersType (const FileWriterParametersType& x, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + + virtual FileWriterParametersType* + _clone (::xml_schema::flags f = 0, + ::xml_schema::container* c = 0) const; + + FileWriterParametersType& + operator= (const FileWriterParametersType& x); + + virtual + ~FileWriterParametersType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::flags); + + protected: + ::xsd::cxx::tree::one< BaseName_type > BaseName_; + ::xsd::cxx::tree::one< WriteFrequency_type > WriteFrequency_; +}; + +class SimulationParametersType: public ::xml_schema::type +{ + public: + // EndT + // + typedef ::xml_schema::double_ EndT_type; + typedef ::xsd::cxx::tree::traits< EndT_type, char, ::xsd::cxx::tree::schema_type::double_ > EndT_traits; + + const EndT_type& + EndT () const; + + EndT_type& + EndT (); + + void + EndT (const EndT_type& x); + + // DeltaT + // + typedef ::xml_schema::double_ DeltaT_type; + typedef ::xsd::cxx::tree::traits< DeltaT_type, char, ::xsd::cxx::tree::schema_type::double_ > DeltaT_traits; + + const DeltaT_type& + DeltaT () const; + + DeltaT_type& + DeltaT (); + + void + DeltaT (const DeltaT_type& x); + + // Gravity + // + typedef ::xml_schema::double_ Gravity_type; + typedef ::xsd::cxx::tree::optional< Gravity_type > Gravity_optional; + typedef ::xsd::cxx::tree::traits< Gravity_type, char, ::xsd::cxx::tree::schema_type::double_ > Gravity_traits; + + const Gravity_optional& + Gravity () const; + + Gravity_optional& + Gravity (); + + void + Gravity (const Gravity_type& x); + + void + Gravity (const Gravity_optional& x); + + // Dimension + // + typedef ::xml_schema::int_ Dimension_type; + typedef ::xsd::cxx::tree::traits< Dimension_type, char > Dimension_traits; + + const Dimension_type& + Dimension () const; + + Dimension_type& + Dimension (); + + void + Dimension (const Dimension_type& x); + + // Constructors. + // + SimulationParametersType (const EndT_type&, + const DeltaT_type&, + const Dimension_type&); + + SimulationParametersType (const ::xercesc::DOMElement& e, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + + SimulationParametersType (const SimulationParametersType& x, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + + virtual SimulationParametersType* + _clone (::xml_schema::flags f = 0, + ::xml_schema::container* c = 0) const; + + SimulationParametersType& + operator= (const SimulationParametersType& x); + + virtual + ~SimulationParametersType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::flags); + + protected: + ::xsd::cxx::tree::one< EndT_type > EndT_; + ::xsd::cxx::tree::one< DeltaT_type > DeltaT_; + Gravity_optional Gravity_; + ::xsd::cxx::tree::one< Dimension_type > Dimension_; +}; + +class ThermostatParametersType: public ::xml_schema::type +{ + public: + // StartTemperature + // + typedef ::xml_schema::double_ StartTemperature_type; + typedef ::xsd::cxx::tree::traits< StartTemperature_type, char, ::xsd::cxx::tree::schema_type::double_ > StartTemperature_traits; + + const StartTemperature_type& + StartTemperature () const; + + StartTemperature_type& + StartTemperature (); + + void + StartTemperature (const StartTemperature_type& x); + + // TargetTemperature + // + typedef ::xml_schema::double_ TargetTemperature_type; + typedef ::xsd::cxx::tree::traits< TargetTemperature_type, char, ::xsd::cxx::tree::schema_type::double_ > TargetTemperature_traits; + + const TargetTemperature_type& + TargetTemperature () const; + + TargetTemperature_type& + TargetTemperature (); + + void + TargetTemperature (const TargetTemperature_type& x); + + // ApplyFrequency + // + typedef ::xml_schema::int_ ApplyFrequency_type; + typedef ::xsd::cxx::tree::traits< ApplyFrequency_type, char > ApplyFrequency_traits; + + const ApplyFrequency_type& + ApplyFrequency () const; + + ApplyFrequency_type& + ApplyFrequency (); + + void + ApplyFrequency (const ApplyFrequency_type& x); + + // MaxDeltaTemperature + // + typedef ::xml_schema::double_ MaxDeltaTemperature_type; + typedef ::xsd::cxx::tree::traits< MaxDeltaTemperature_type, char, ::xsd::cxx::tree::schema_type::double_ > MaxDeltaTemperature_traits; + + const MaxDeltaTemperature_type& + MaxDeltaTemperature () const; + + MaxDeltaTemperature_type& + MaxDeltaTemperature (); + + void + MaxDeltaTemperature (const MaxDeltaTemperature_type& x); + + // Dimension + // + typedef ::xml_schema::int_ Dimension_type; + typedef ::xsd::cxx::tree::traits< Dimension_type, char > Dimension_traits; + + const Dimension_type& + Dimension () const; + + Dimension_type& + Dimension (); + + void + Dimension (const Dimension_type& x); + + // Constructors. + // + ThermostatParametersType (const StartTemperature_type&, + const TargetTemperature_type&, + const ApplyFrequency_type&, + const MaxDeltaTemperature_type&, + const Dimension_type&); + + ThermostatParametersType (const ::xercesc::DOMElement& e, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + + ThermostatParametersType (const ThermostatParametersType& x, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + + virtual ThermostatParametersType* + _clone (::xml_schema::flags f = 0, + ::xml_schema::container* c = 0) const; + + ThermostatParametersType& + operator= (const ThermostatParametersType& x); + + virtual + ~ThermostatParametersType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::flags); + + protected: + ::xsd::cxx::tree::one< StartTemperature_type > StartTemperature_; + ::xsd::cxx::tree::one< TargetTemperature_type > TargetTemperature_; + ::xsd::cxx::tree::one< ApplyFrequency_type > ApplyFrequency_; + ::xsd::cxx::tree::one< MaxDeltaTemperature_type > MaxDeltaTemperature_; + ::xsd::cxx::tree::one< Dimension_type > Dimension_; +}; + +class LinkedCellsParametersType: public ::xml_schema::type +{ + public: + // LinkedCellsUsed + // + typedef ::xml_schema::boolean LinkedCellsUsed_type; + typedef ::xsd::cxx::tree::traits< LinkedCellsUsed_type, char > LinkedCellsUsed_traits; + + const LinkedCellsUsed_type& + LinkedCellsUsed () const; + + LinkedCellsUsed_type& + LinkedCellsUsed (); + + void + LinkedCellsUsed (const LinkedCellsUsed_type& x); + + // CutoffRadius + // + typedef ::xml_schema::double_ CutoffRadius_type; + typedef ::xsd::cxx::tree::traits< CutoffRadius_type, char, ::xsd::cxx::tree::schema_type::double_ > CutoffRadius_traits; + + const CutoffRadius_type& + CutoffRadius () const; + + CutoffRadius_type& + CutoffRadius (); + + void + CutoffRadius (const CutoffRadius_type& x); + + // Constructors. + // + LinkedCellsParametersType (const LinkedCellsUsed_type&, + const CutoffRadius_type&); + + LinkedCellsParametersType (const ::xercesc::DOMElement& e, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + + LinkedCellsParametersType (const LinkedCellsParametersType& x, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + + virtual LinkedCellsParametersType* + _clone (::xml_schema::flags f = 0, + ::xml_schema::container* c = 0) const; + + LinkedCellsParametersType& + operator= (const LinkedCellsParametersType& x); + + virtual + ~LinkedCellsParametersType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::flags); + + protected: + ::xsd::cxx::tree::one< LinkedCellsUsed_type > LinkedCellsUsed_; + ::xsd::cxx::tree::one< CutoffRadius_type > CutoffRadius_; +}; + +class BoundaryParametersType: public ::xml_schema::type +{ + public: + // Domain + // + typedef ::xml_schema::string Domain_type; + typedef ::xsd::cxx::tree::traits< Domain_type, char > Domain_traits; + + const Domain_type& + Domain () const; + + Domain_type& + Domain (); + + void + Domain (const Domain_type& x); + + void + Domain (::std::unique_ptr< Domain_type > p); + + // TOP + // + typedef ::BoundaryType TOP_type; + typedef ::xsd::cxx::tree::traits< TOP_type, char > TOP_traits; + + const TOP_type& + TOP () const; + + TOP_type& + TOP (); + + void + TOP (const TOP_type& x); + + void + TOP (::std::unique_ptr< TOP_type > p); + + // RIGHT + // + typedef ::BoundaryType RIGHT_type; + typedef ::xsd::cxx::tree::traits< RIGHT_type, char > RIGHT_traits; + + const RIGHT_type& + RIGHT () const; + + RIGHT_type& + RIGHT (); + + void + RIGHT (const RIGHT_type& x); + + void + RIGHT (::std::unique_ptr< RIGHT_type > p); + + // BOTTOM + // + typedef ::BoundaryType BOTTOM_type; + typedef ::xsd::cxx::tree::traits< BOTTOM_type, char > BOTTOM_traits; + + const BOTTOM_type& + BOTTOM () const; + + BOTTOM_type& + BOTTOM (); + + void + BOTTOM (const BOTTOM_type& x); + + void + BOTTOM (::std::unique_ptr< BOTTOM_type > p); + + // LEFT + // + typedef ::BoundaryType LEFT_type; + typedef ::xsd::cxx::tree::traits< LEFT_type, char > LEFT_traits; + + const LEFT_type& + LEFT () const; + + LEFT_type& + LEFT (); + + void + LEFT (const LEFT_type& x); + + void + LEFT (::std::unique_ptr< LEFT_type > p); + + // FRONT + // + typedef ::BoundaryType FRONT_type; + typedef ::xsd::cxx::tree::traits< FRONT_type, char > FRONT_traits; + + const FRONT_type& + FRONT () const; + + FRONT_type& + FRONT (); + + void + FRONT (const FRONT_type& x); + + void + FRONT (::std::unique_ptr< FRONT_type > p); + + // BACK + // + typedef ::BoundaryType BACK_type; + typedef ::xsd::cxx::tree::traits< BACK_type, char > BACK_traits; + + const BACK_type& + BACK () const; + + BACK_type& + BACK (); + + void + BACK (const BACK_type& x); + + void + BACK (::std::unique_ptr< BACK_type > p); + + // Constructors. + // + BoundaryParametersType (const Domain_type&, + const TOP_type&, + const RIGHT_type&, + const BOTTOM_type&, + const LEFT_type&, + const FRONT_type&, + const BACK_type&); + + BoundaryParametersType (const ::xercesc::DOMElement& e, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + + BoundaryParametersType (const BoundaryParametersType& x, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + + virtual BoundaryParametersType* + _clone (::xml_schema::flags f = 0, + ::xml_schema::container* c = 0) const; + + BoundaryParametersType& + operator= (const BoundaryParametersType& x); + + virtual + ~BoundaryParametersType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::flags); + + protected: + ::xsd::cxx::tree::one< Domain_type > Domain_; + ::xsd::cxx::tree::one< TOP_type > TOP_; + ::xsd::cxx::tree::one< RIGHT_type > RIGHT_; + ::xsd::cxx::tree::one< BOTTOM_type > BOTTOM_; + ::xsd::cxx::tree::one< LEFT_type > LEFT_; + ::xsd::cxx::tree::one< FRONT_type > FRONT_; + ::xsd::cxx::tree::one< BACK_type > BACK_; +}; + +class CuboidType: public ::xml_schema::type +{ + public: + // Coordinates + // + typedef ::xml_schema::string Coordinates_type; + typedef ::xsd::cxx::tree::traits< Coordinates_type, char > Coordinates_traits; + + const Coordinates_type& + Coordinates () const; + + Coordinates_type& + Coordinates (); + + void + Coordinates (const Coordinates_type& x); + + void + Coordinates (::std::unique_ptr< Coordinates_type > p); + + // ParticlesPerDimension + // + typedef ::xml_schema::string ParticlesPerDimension_type; + typedef ::xsd::cxx::tree::traits< ParticlesPerDimension_type, char > ParticlesPerDimension_traits; + + const ParticlesPerDimension_type& + ParticlesPerDimension () const; + + ParticlesPerDimension_type& + ParticlesPerDimension (); + + void + ParticlesPerDimension (const ParticlesPerDimension_type& x); + + void + ParticlesPerDimension (::std::unique_ptr< ParticlesPerDimension_type > p); + + // Distance + // + typedef ::xml_schema::double_ Distance_type; + typedef ::xsd::cxx::tree::traits< Distance_type, char, ::xsd::cxx::tree::schema_type::double_ > Distance_traits; + + const Distance_type& + Distance () const; + + Distance_type& + Distance (); + + void + Distance (const Distance_type& x); + + // Mass + // + typedef ::xml_schema::double_ Mass_type; + typedef ::xsd::cxx::tree::traits< Mass_type, char, ::xsd::cxx::tree::schema_type::double_ > Mass_traits; + + const Mass_type& + Mass () const; + + Mass_type& + Mass (); + + void + Mass (const Mass_type& x); + + // InitialVelocities + // + typedef ::xml_schema::string InitialVelocities_type; + typedef ::xsd::cxx::tree::traits< InitialVelocities_type, char > InitialVelocities_traits; + + const InitialVelocities_type& + InitialVelocities () const; + + InitialVelocities_type& + InitialVelocities (); + + void + InitialVelocities (const InitialVelocities_type& x); + + void + InitialVelocities (::std::unique_ptr< InitialVelocities_type > p); + + // MeanVelocity + // + typedef ::xml_schema::double_ MeanVelocity_type; + typedef ::xsd::cxx::tree::traits< MeanVelocity_type, char, ::xsd::cxx::tree::schema_type::double_ > MeanVelocity_traits; + + const MeanVelocity_type& + MeanVelocity () const; + + MeanVelocity_type& + MeanVelocity (); + + void + MeanVelocity (const MeanVelocity_type& x); + + // Sigma + // + typedef ::xml_schema::double_ Sigma_type; + typedef ::xsd::cxx::tree::traits< Sigma_type, char, ::xsd::cxx::tree::schema_type::double_ > Sigma_traits; + + const Sigma_type& + Sigma () const; + + Sigma_type& + Sigma (); + + void + Sigma (const Sigma_type& x); + + // Epsilon + // + typedef ::xml_schema::double_ Epsilon_type; + typedef ::xsd::cxx::tree::traits< Epsilon_type, char, ::xsd::cxx::tree::schema_type::double_ > Epsilon_traits; + + const Epsilon_type& + Epsilon () const; + + Epsilon_type& + Epsilon (); + + void + Epsilon (const Epsilon_type& x); + + // Constructors. + // + CuboidType (const Coordinates_type&, + const ParticlesPerDimension_type&, + const Distance_type&, + const Mass_type&, + const InitialVelocities_type&, + const MeanVelocity_type&, + const Sigma_type&, + const Epsilon_type&); + + CuboidType (const ::xercesc::DOMElement& e, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + + CuboidType (const CuboidType& x, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + + virtual CuboidType* + _clone (::xml_schema::flags f = 0, + ::xml_schema::container* c = 0) const; + + CuboidType& + operator= (const CuboidType& x); + + virtual + ~CuboidType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::flags); + + protected: + ::xsd::cxx::tree::one< Coordinates_type > Coordinates_; + ::xsd::cxx::tree::one< ParticlesPerDimension_type > ParticlesPerDimension_; + ::xsd::cxx::tree::one< Distance_type > Distance_; + ::xsd::cxx::tree::one< Mass_type > Mass_; + ::xsd::cxx::tree::one< InitialVelocities_type > InitialVelocities_; + ::xsd::cxx::tree::one< MeanVelocity_type > MeanVelocity_; + ::xsd::cxx::tree::one< Sigma_type > Sigma_; + ::xsd::cxx::tree::one< Epsilon_type > Epsilon_; +}; + +class DiscType: public ::xml_schema::type +{ + public: + // CenterCoordinates + // + typedef ::xml_schema::string CenterCoordinates_type; + typedef ::xsd::cxx::tree::traits< CenterCoordinates_type, char > CenterCoordinates_traits; + + const CenterCoordinates_type& + CenterCoordinates () const; + + CenterCoordinates_type& + CenterCoordinates (); + + void + CenterCoordinates (const CenterCoordinates_type& x); + + void + CenterCoordinates (::std::unique_ptr< CenterCoordinates_type > p); + + // InitialVelocities + // + typedef ::xml_schema::string InitialVelocities_type; + typedef ::xsd::cxx::tree::traits< InitialVelocities_type, char > InitialVelocities_traits; + + const InitialVelocities_type& + InitialVelocities () const; + + InitialVelocities_type& + InitialVelocities (); + + void + InitialVelocities (const InitialVelocities_type& x); + + void + InitialVelocities (::std::unique_ptr< InitialVelocities_type > p); + + // NumberOfParticlesAlongRadius + // + typedef ::xml_schema::int_ NumberOfParticlesAlongRadius_type; + typedef ::xsd::cxx::tree::traits< NumberOfParticlesAlongRadius_type, char > NumberOfParticlesAlongRadius_traits; + + const NumberOfParticlesAlongRadius_type& + NumberOfParticlesAlongRadius () const; + + NumberOfParticlesAlongRadius_type& + NumberOfParticlesAlongRadius (); + + void + NumberOfParticlesAlongRadius (const NumberOfParticlesAlongRadius_type& x); + + // Distance + // + typedef ::xml_schema::double_ Distance_type; + typedef ::xsd::cxx::tree::traits< Distance_type, char, ::xsd::cxx::tree::schema_type::double_ > Distance_traits; + + const Distance_type& + Distance () const; + + Distance_type& + Distance (); + + void + Distance (const Distance_type& x); + + // Mass + // + typedef ::xml_schema::double_ Mass_type; + typedef ::xsd::cxx::tree::traits< Mass_type, char, ::xsd::cxx::tree::schema_type::double_ > Mass_traits; + + const Mass_type& + Mass () const; + + Mass_type& + Mass (); + + void + Mass (const Mass_type& x); + + // Sigma + // + typedef ::xml_schema::double_ Sigma_type; + typedef ::xsd::cxx::tree::traits< Sigma_type, char, ::xsd::cxx::tree::schema_type::double_ > Sigma_traits; + + const Sigma_type& + Sigma () const; + + Sigma_type& + Sigma (); + + void + Sigma (const Sigma_type& x); + + // Epsilon + // + typedef ::xml_schema::double_ Epsilon_type; + typedef ::xsd::cxx::tree::traits< Epsilon_type, char, ::xsd::cxx::tree::schema_type::double_ > Epsilon_traits; + + const Epsilon_type& + Epsilon () const; + + Epsilon_type& + Epsilon (); + + void + Epsilon (const Epsilon_type& x); + + // Constructors. + // + DiscType (const CenterCoordinates_type&, + const InitialVelocities_type&, + const NumberOfParticlesAlongRadius_type&, + const Distance_type&, + const Mass_type&, + const Sigma_type&, + const Epsilon_type&); + + DiscType (const ::xercesc::DOMElement& e, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + + DiscType (const DiscType& x, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + + virtual DiscType* + _clone (::xml_schema::flags f = 0, + ::xml_schema::container* c = 0) const; + + DiscType& + operator= (const DiscType& x); + + virtual + ~DiscType (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::flags); + + protected: + ::xsd::cxx::tree::one< CenterCoordinates_type > CenterCoordinates_; + ::xsd::cxx::tree::one< InitialVelocities_type > InitialVelocities_; + ::xsd::cxx::tree::one< NumberOfParticlesAlongRadius_type > NumberOfParticlesAlongRadius_; + ::xsd::cxx::tree::one< Distance_type > Distance_; + ::xsd::cxx::tree::one< Mass_type > Mass_; + ::xsd::cxx::tree::one< Sigma_type > Sigma_; + ::xsd::cxx::tree::one< Epsilon_type > Epsilon_; +}; + +class BoundaryType: public ::xml_schema::string +{ + public: + enum value + { + REFLECTING, + OUTFLOW, + PERIODIC, + OFF + }; + + BoundaryType (value v); + + BoundaryType (const char* v); + + BoundaryType (const ::std::string& v); + + BoundaryType (const ::xml_schema::string& v); + + BoundaryType (const ::xercesc::DOMElement& e, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + + BoundaryType (const ::xercesc::DOMAttr& a, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + + BoundaryType (const ::std::string& s, + const ::xercesc::DOMElement* e, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + + BoundaryType (const BoundaryType& x, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + +#ifdef XSD_CXX11 + BoundaryType& + operator= (const BoundaryType&) = default; +#endif + + virtual BoundaryType* + _clone (::xml_schema::flags f = 0, + ::xml_schema::container* c = 0) const; + + BoundaryType& + operator= (value v); + + virtual + operator value () const + { + return _xsd_BoundaryType_convert (); + } + + protected: + value + _xsd_BoundaryType_convert () const; + + public: + static const char* const _xsd_BoundaryType_literals_[4]; + static const value _xsd_BoundaryType_indexes_[4]; +}; + +class Simulation: public ::xml_schema::type +{ + public: + // FileWriterParameters + // + typedef ::FileWriterParametersType FileWriterParameters_type; + typedef ::xsd::cxx::tree::traits< FileWriterParameters_type, char > FileWriterParameters_traits; + + const FileWriterParameters_type& + FileWriterParameters () const; + + FileWriterParameters_type& + FileWriterParameters (); + + void + FileWriterParameters (const FileWriterParameters_type& x); + + void + FileWriterParameters (::std::unique_ptr< FileWriterParameters_type > p); + + // SimulationParameters + // + typedef ::SimulationParametersType SimulationParameters_type; + typedef ::xsd::cxx::tree::traits< SimulationParameters_type, char > SimulationParameters_traits; + + const SimulationParameters_type& + SimulationParameters () const; + + SimulationParameters_type& + SimulationParameters (); + + void + SimulationParameters (const SimulationParameters_type& x); + + void + SimulationParameters (::std::unique_ptr< SimulationParameters_type > p); + + // ThermostatParameters + // + typedef ::ThermostatParametersType ThermostatParameters_type; + typedef ::xsd::cxx::tree::traits< ThermostatParameters_type, char > ThermostatParameters_traits; + + const ThermostatParameters_type& + ThermostatParameters () const; + + ThermostatParameters_type& + ThermostatParameters (); + + void + ThermostatParameters (const ThermostatParameters_type& x); + + void + ThermostatParameters (::std::unique_ptr< ThermostatParameters_type > p); + + // LinkedCellsParameters + // + typedef ::LinkedCellsParametersType LinkedCellsParameters_type; + typedef ::xsd::cxx::tree::traits< LinkedCellsParameters_type, char > LinkedCellsParameters_traits; + + const LinkedCellsParameters_type& + LinkedCellsParameters () const; + + LinkedCellsParameters_type& + LinkedCellsParameters (); + + void + LinkedCellsParameters (const LinkedCellsParameters_type& x); + + void + LinkedCellsParameters (::std::unique_ptr< LinkedCellsParameters_type > p); + + // BoundaryParameters + // + typedef ::BoundaryParametersType BoundaryParameters_type; + typedef ::xsd::cxx::tree::traits< BoundaryParameters_type, char > BoundaryParameters_traits; + + const BoundaryParameters_type& + BoundaryParameters () const; + + BoundaryParameters_type& + BoundaryParameters (); + + void + BoundaryParameters (const BoundaryParameters_type& x); + + void + BoundaryParameters (::std::unique_ptr< BoundaryParameters_type > p); + + // Cuboid + // + typedef ::CuboidType Cuboid_type; + typedef ::xsd::cxx::tree::sequence< Cuboid_type > Cuboid_sequence; + typedef Cuboid_sequence::iterator Cuboid_iterator; + typedef Cuboid_sequence::const_iterator Cuboid_const_iterator; + typedef ::xsd::cxx::tree::traits< Cuboid_type, char > Cuboid_traits; + + const Cuboid_sequence& + Cuboid () const; + + Cuboid_sequence& + Cuboid (); + + void + Cuboid (const Cuboid_sequence& s); + + // Disc + // + typedef ::DiscType Disc_type; + typedef ::xsd::cxx::tree::sequence< Disc_type > Disc_sequence; + typedef Disc_sequence::iterator Disc_iterator; + typedef Disc_sequence::const_iterator Disc_const_iterator; + typedef ::xsd::cxx::tree::traits< Disc_type, char > Disc_traits; + + const Disc_sequence& + Disc () const; + + Disc_sequence& + Disc (); + + void + Disc (const Disc_sequence& s); + + // Constructors. + // + Simulation (const FileWriterParameters_type&, + const SimulationParameters_type&, + const ThermostatParameters_type&, + const LinkedCellsParameters_type&, + const BoundaryParameters_type&); + + Simulation (::std::unique_ptr< FileWriterParameters_type >, + ::std::unique_ptr< SimulationParameters_type >, + ::std::unique_ptr< ThermostatParameters_type >, + ::std::unique_ptr< LinkedCellsParameters_type >, + ::std::unique_ptr< BoundaryParameters_type >); + + Simulation (const ::xercesc::DOMElement& e, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + + Simulation (const Simulation& x, + ::xml_schema::flags f = 0, + ::xml_schema::container* c = 0); + + virtual Simulation* + _clone (::xml_schema::flags f = 0, + ::xml_schema::container* c = 0) const; + + Simulation& + operator= (const Simulation& x); + + virtual + ~Simulation (); + + // Implementation. + // + protected: + void + parse (::xsd::cxx::xml::dom::parser< char >&, + ::xml_schema::flags); + + protected: + ::xsd::cxx::tree::one< FileWriterParameters_type > FileWriterParameters_; + ::xsd::cxx::tree::one< SimulationParameters_type > SimulationParameters_; + ::xsd::cxx::tree::one< ThermostatParameters_type > ThermostatParameters_; + ::xsd::cxx::tree::one< LinkedCellsParameters_type > LinkedCellsParameters_; + ::xsd::cxx::tree::one< BoundaryParameters_type > BoundaryParameters_; + Cuboid_sequence Cuboid_; + Disc_sequence Disc_; +}; + +#include + +#include +#include +#include + +// Parse a URI or a local file. +// + +::std::unique_ptr< ::Simulation > +Simulation_ (const ::std::string& uri, + ::xml_schema::flags f = 0, + const ::xml_schema::properties& p = ::xml_schema::properties ()); + +::std::unique_ptr< ::Simulation > +Simulation_ (const ::std::string& uri, + ::xml_schema::error_handler& eh, + ::xml_schema::flags f = 0, + const ::xml_schema::properties& p = ::xml_schema::properties ()); + +::std::unique_ptr< ::Simulation > +Simulation_ (const ::std::string& uri, + ::xercesc::DOMErrorHandler& eh, + ::xml_schema::flags f = 0, + const ::xml_schema::properties& p = ::xml_schema::properties ()); + +// Parse std::istream. +// + +::std::unique_ptr< ::Simulation > +Simulation_ (::std::istream& is, + ::xml_schema::flags f = 0, + const ::xml_schema::properties& p = ::xml_schema::properties ()); + +::std::unique_ptr< ::Simulation > +Simulation_ (::std::istream& is, + ::xml_schema::error_handler& eh, + ::xml_schema::flags f = 0, + const ::xml_schema::properties& p = ::xml_schema::properties ()); + +::std::unique_ptr< ::Simulation > +Simulation_ (::std::istream& is, + ::xercesc::DOMErrorHandler& eh, + ::xml_schema::flags f = 0, + const ::xml_schema::properties& p = ::xml_schema::properties ()); + +::std::unique_ptr< ::Simulation > +Simulation_ (::std::istream& is, + const ::std::string& id, + ::xml_schema::flags f = 0, + const ::xml_schema::properties& p = ::xml_schema::properties ()); + +::std::unique_ptr< ::Simulation > +Simulation_ (::std::istream& is, + const ::std::string& id, + ::xml_schema::error_handler& eh, + ::xml_schema::flags f = 0, + const ::xml_schema::properties& p = ::xml_schema::properties ()); + +::std::unique_ptr< ::Simulation > +Simulation_ (::std::istream& is, + const ::std::string& id, + ::xercesc::DOMErrorHandler& eh, + ::xml_schema::flags f = 0, + const ::xml_schema::properties& p = ::xml_schema::properties ()); + +// Parse xercesc::InputSource. +// + +::std::unique_ptr< ::Simulation > +Simulation_ (::xercesc::InputSource& is, + ::xml_schema::flags f = 0, + const ::xml_schema::properties& p = ::xml_schema::properties ()); + +::std::unique_ptr< ::Simulation > +Simulation_ (::xercesc::InputSource& is, + ::xml_schema::error_handler& eh, + ::xml_schema::flags f = 0, + const ::xml_schema::properties& p = ::xml_schema::properties ()); + +::std::unique_ptr< ::Simulation > +Simulation_ (::xercesc::InputSource& is, + ::xercesc::DOMErrorHandler& eh, + ::xml_schema::flags f = 0, + const ::xml_schema::properties& p = ::xml_schema::properties ()); + +// Parse xercesc::DOMDocument. +// + +::std::unique_ptr< ::Simulation > +Simulation_ (const ::xercesc::DOMDocument& d, + ::xml_schema::flags f = 0, + const ::xml_schema::properties& p = ::xml_schema::properties ()); + +::std::unique_ptr< ::Simulation > +Simulation_ (::xml_schema::dom::unique_ptr< ::xercesc::DOMDocument > d, + ::xml_schema::flags f = 0, + const ::xml_schema::properties& p = ::xml_schema::properties ()); + +#include + +// Begin epilogue. +// +// +// End epilogue. + +#endif // INPUT_SCHEMA_HXX diff --git a/src/io/in/input_schema.xsd b/src/io/in/input_schema.xsd new file mode 100644 index 000000000..93c6598d8 --- /dev/null +++ b/src/io/in/input_schema.xsd @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/io/in/parameters/BoundaryParameters.h b/src/io/in/parameters/BoundaryParameters.h new file mode 100644 index 000000000..37c53b8ea --- /dev/null +++ b/src/io/in/parameters/BoundaryParameters.h @@ -0,0 +1,27 @@ +// +// Created by kimj2 on 15.06.2024. +// +#pragma once + +#include +#include "boundaries/BoundaryEnums.h" + +struct BoundaryParameters { +private: + std::map boundaryMap; + std::array domain; + +public: + BoundaryParameters() = default; + + BoundaryParameters(const std::map& boundaryMap, const std::array& domain) + : boundaryMap(boundaryMap), domain(domain) {} + + [[nodiscard]] const std::map& getBoundaryMap() const { + return boundaryMap; + } + + [[nodiscard]] const std::array& getDomain() const { + return domain; + } +}; \ No newline at end of file diff --git a/src/io/in/parameters/CuboidParameters.h b/src/io/in/parameters/CuboidParameters.h new file mode 100644 index 000000000..ad52cb536 --- /dev/null +++ b/src/io/in/parameters/CuboidParameters.h @@ -0,0 +1,134 @@ +// +// Created by kimj2 on 07.05.2024. +// +#pragma once + +#include + +/** + * @class CuboidParameters + * @brief Parameters for a cuboid. + * + * This class encapsulates the parameters needed to define a cuboid. + * All attributes are private, const and can only be accessed through getter methods. + */ +class CuboidParameters { +public: + /** + * @brief Constructor with initializer list. + * @param llfCorner Lower left front corner of the cuboid. + * @param numParticles Number of particles per dimension in the cuboid. + * @param pDistance Distance between particles. + * @param pMass Mass of the particles. + * @param startV Initial velocity of the particles. + * @param meanV Mean velocity of the particles. + * @param dimension Dimension of the cuboid. + */ + CuboidParameters(std::array llfCorner, std::array numParticles, double pDistance, + double pMass, std::array startV, double meanV, int dimension, double sigma, double epsilon) + : lowerLeftFrontCorner(llfCorner), numParticlesPerDimension(numParticles), distance(pDistance), + m(pMass), startV(startV), meanV(meanV), dimension(dimension), sigma(sigma), epsilon(epsilon){} + + /** + * @brief Get the lower left front corner of the cuboid. + * @return The lower left front corner of the cuboid. + */ + [[nodiscard]] const std::array& getLowerLeftFrontCorner() const { + return lowerLeftFrontCorner; + } + + /** + * @brief Get the number of particles per dimension in the cuboid. + * @return The number of particles per dimension in the cuboid. + */ + [[nodiscard]] const std::array& getNumParticlesPerDimension() const { + return numParticlesPerDimension; + } + + /** + * @brief Get the distance between particles in the cuboid. + * @return The distance between particles in the cuboid. + */ + [[nodiscard]] double getDistance() const { + return distance; + } + + /** + * @brief Get the mass of the particles in the cuboid. + * @return The mass of the particles in the cuboid. + */ + [[nodiscard]] double getMass() const { + return m; + } + + /** + * @brief Get the initial velocity of the particles in the cuboid. + * @return The initial velocity of the particles in the cuboid. + */ + [[nodiscard]] const std::array& getStartV() const { + return startV; + } + + /** + * @brief Get the mean velocity of the particles in the cuboid. + * @return The mean velocity of the particles in the cuboid. + */ + [[nodiscard]] double getMeanV() const { + return meanV; + } + + /** + * @brief Get the dimension of the cuboid. + * @return The dimension of the cuboid. + */ + [[nodiscard]] int getDimension() const { + return dimension; + } + + double getSigma() const { + return sigma; + } + + double getEpsilon() const { + return epsilon; + } + +private: + /** + * @brief Lower left front corner of the cuboid. + */ + const std::array lowerLeftFrontCorner; + + /** + * @brief Number of particles per dimension in the cuboid. + */ + const std::array numParticlesPerDimension; + + /** + * @brief Distance between particles in the cuboid. + */ + const double distance; + + /** + * @brief Mass of the particles in the cuboid. + */ + const double m; + + /** + * @brief Initial velocity of the particles in the cuboid. + */ + const std::array startV; + + /** + * @brief Mean velocity of the particles in the cuboid. + */ + const double meanV; + + /** + * @brief Dimension of the cuboid. + */ + const int dimension; + + const double sigma; + const double epsilon; +}; \ No newline at end of file diff --git a/src/io/in/parameters/DiscParameters.h b/src/io/in/parameters/DiscParameters.h new file mode 100644 index 000000000..45e731ba6 --- /dev/null +++ b/src/io/in/parameters/DiscParameters.h @@ -0,0 +1,83 @@ +// +// Created by kimj2 on 24.05.2024. +// +#pragma once + +#include + +/** + * @class DiscParameters + * @brief Class to hold the parameters needed to generate a disc of particles. + */ +class DiscParameters { +public: + /** + * @brief Construct a new Disc Parameters object + * + * @param center Center coordinates of the disc + * @param startV Initial velocities of all particles in the disc + * @param numParticlesAlongRadius Number of particles along the radius of the disc + * @param distance Distance between the particles + * @param mass Mass of the particles + * @param dimension Dimension of the simulation + */ + DiscParameters(const std::array ¢er, const std::array &startV, + int numParticlesAlongRadius, double distance, double mass, int dimension, double sigma, double epsilon) + : center(center), startV(startV), numParticlesAlongRadius(numParticlesAlongRadius), distance(distance), + mass(mass), dimension(dimension), sigma(sigma), epsilon(epsilon) {} + + /** + * @brief Get the Center coordinates of the disc + * + * @return const std::array& + */ + [[nodiscard]] const std::array &getCenter() const { return center; } + + /** + * @brief Get the Initial velocity of the disc + * + * @return const std::array& + */ + [[nodiscard]] const std::array &getStartV() const { return startV; } + + /** + * @brief Get the Number of particles along the radius of the disc + * + * @return int + */ + [[nodiscard]] int getNumParticlesAlongRadius() const { return numParticlesAlongRadius; } + + /** + * @brief Get the Distance between the particles + * + * @return double + */ + [[nodiscard]] double getDistance() const { return distance; } + + /** + * @brief Get the Mass of the particles + * + * @return double + */ + [[nodiscard]] double getMass() const { return mass; } + + /** + * @brief Get the Dimension of the simulation + * + * @return int + */ + [[nodiscard]] int getDimension() const { return dimension; } + + double getSigma() const { return sigma; } + double getEpsilon() const { return epsilon; } + +private: + const std::array center; + const std::array startV; + const int numParticlesAlongRadius; + const double distance; + const double mass; + const int dimension; + const double sigma; + const double epsilon; +}; \ No newline at end of file diff --git a/src/io/in/parameters/FileWriterParameters.h b/src/io/in/parameters/FileWriterParameters.h new file mode 100644 index 000000000..523b5457e --- /dev/null +++ b/src/io/in/parameters/FileWriterParameters.h @@ -0,0 +1,28 @@ +// +// Created by kimj2 on 05.06.2024. +// + +#pragma once + +#include +#include + +class FileWriterParameters { +public: + FileWriterParameters() : baseName(""), writeFrequency(-1) {} // default constructor + + FileWriterParameters(std::string baseName, int writeFrequency) + : baseName(std::move(baseName)), writeFrequency(writeFrequency) {} + + + const std::string &getBaseName() const { + return baseName; + } + + int getWriteFrequency() const { + return writeFrequency; + } +private: + const std::string baseName; + const int writeFrequency; // How often to write output (every n-th step) +}; \ No newline at end of file diff --git a/src/io/in/parameters/LinkedCellsParameters.h b/src/io/in/parameters/LinkedCellsParameters.h new file mode 100644 index 000000000..89b962e78 --- /dev/null +++ b/src/io/in/parameters/LinkedCellsParameters.h @@ -0,0 +1,22 @@ +// +// Created by kimj2 on 19.06.2024. +// +#pragma once +class LinkedCellsParameters { +public: + LinkedCellsParameters() : linkedCellsUsed(false), cutOffRadius(1.0) {} // default constructor + + LinkedCellsParameters(bool linkedCellsUsed, double cutOffRadius) : linkedCellsUsed(linkedCellsUsed), cutOffRadius(cutOffRadius) {} + + [[nodiscard]] bool isLinkedCellsUsed() const { + return linkedCellsUsed; + } + + [[nodiscard]] double getCutOffRadius() const { + return cutOffRadius; + } + +private: + const bool linkedCellsUsed; + const double cutOffRadius; +}; \ No newline at end of file diff --git a/src/io/in/ParticleParameters.h b/src/io/in/parameters/ParticleParameters.h similarity index 68% rename from src/io/in/ParticleParameters.h rename to src/io/in/parameters/ParticleParameters.h index 9499a485d..e5a8aef83 100644 --- a/src/io/in/ParticleParameters.h +++ b/src/io/in/parameters/ParticleParameters.h @@ -5,10 +5,13 @@ #include /** - * @struct ParticleParameters + * @class ParticleParameters * @brief Parameters for a particle. + * + * This class encapsulates the parameters needed to define a particle. + * All attributes are private, const and can only be accessed through getter methods. */ -struct ParticleParameters { +class ParticleParameters { public: /** * @brief Constructor with initializer list. @@ -17,9 +20,10 @@ struct ParticleParameters { * @param m Initial mass of the particle. * @param volume Initial volume of the particle. * @param type Initial type of the particle. + * @param dimension Dimension of the simulation. */ - ParticleParameters(std::array x, std::array v, double m, double volume, int type) - : x(x), v(v), m(m), volume(volume), type(type) {} + ParticleParameters(std::array x, std::array v, double m, double volume, int type, int dimension) + : x(x), v(v), m(m), volume(volume), type(type), dimension(dimension) {} /** * @brief Get the position of the particle. @@ -37,7 +41,6 @@ struct ParticleParameters { return v; } - /** * @brief Get the mass of the particle. * @return The mass of the particle. @@ -62,31 +65,44 @@ struct ParticleParameters { return type; } + /** + * @brief Get the dimension of the simulation. + * @return The dimension of the simulation. + */ + int getDimension() const { + return dimension; + } + private: /** * @brief Position of the particle. */ - std::array x; + const std::array x; /** * @brief Velocity of the particle. */ - std::array v; + const std::array v; /** * @brief Mass of this particle. */ - double m; + const double m; /** * @brief Paraview volume of this particle. */ - double volume; + const double volume; /** * @brief Type of the particle. * Use it for whatever you want (e.g. to separate * molecules belonging to different bodies, matters, and so on). */ - int type; + const int type; + + /** + * @brief Dimension of the simulation. + */ + const int dimension; }; \ No newline at end of file diff --git a/src/io/in/parameters/SimulationDataContainer.h b/src/io/in/parameters/SimulationDataContainer.h new file mode 100644 index 000000000..8a70512e2 --- /dev/null +++ b/src/io/in/parameters/SimulationDataContainer.h @@ -0,0 +1,69 @@ +// +// Created by kimj2 on 05.06.2024. +// + +#pragma once + +#include "../../../objects/ParticleContainer.h" +#include "FileWriterParameters.h" +#include "SimulationParameters.h" +#include "ThermostatParameters.h" +#include "BoundaryParameters.h" +#include "LinkedCellsParameters.h" + +#include + +class SimulationDataContainer { +public: + SimulationDataContainer(std::unique_ptr particleContainer, + std::unique_ptr linkedCellContainer, + std::unique_ptr fileWriterParameters, + std::unique_ptr simulationParameters, + std::unique_ptr thermostatParameters, + std::unique_ptr linkedCellsParameters, + std::unique_ptr boundaryParameters) + : particleContainer(std::move(particleContainer)), + linkedCellContainer(std::move(linkedCellContainer)), + fileWriterParameters(std::move(fileWriterParameters)), + simulationParameters(std::move(simulationParameters)), + thermostatParameters(std::move(thermostatParameters)), + linkedCellsParameters(std::move(linkedCellsParameters)), + boundaryParameters(std::move(boundaryParameters)) {} + + [[nodiscard]] ParticleContainer *getParticleContainer() const { + return particleContainer.get(); + } + + [[nodiscard]] LinkedCellContainer *getLinkedCellContainer() const { + return linkedCellContainer.get(); + } + + [[nodiscard]] FileWriterParameters *getFileWriterParameters() const { + return fileWriterParameters.get(); + } + + [[nodiscard]] SimulationParameters *getSimulationParameters() const { + return simulationParameters.get(); + } + + [[nodiscard]] ThermostatParameters *getThermostatParameters() const { + return thermostatParameters.get(); + } + + [[nodiscard]] LinkedCellsParameters *getLinkedCellsParameters() const { + return linkedCellsParameters.get(); + } + + [[nodiscard]] BoundaryParameters *getBoundaryParameters() const { + return boundaryParameters.get(); + } + +private: + std::unique_ptr particleContainer; + std::unique_ptr linkedCellContainer; + std::unique_ptr fileWriterParameters; + std::unique_ptr simulationParameters; + std::unique_ptr thermostatParameters; + std::unique_ptr linkedCellsParameters; + std::unique_ptr boundaryParameters; +}; \ No newline at end of file diff --git a/src/io/in/parameters/SimulationParameters.h b/src/io/in/parameters/SimulationParameters.h new file mode 100644 index 000000000..eefa0deca --- /dev/null +++ b/src/io/in/parameters/SimulationParameters.h @@ -0,0 +1,49 @@ +// +// Created by kimj2 on 05.06.2024. +// + +#pragma once +class SimulationParameters { +public: + SimulationParameters() : end_t(-1), delta_t(-1), gravity(-1), dimension(2) {} // default constructor + + SimulationParameters(double end_t, double delta_t, double gravity, int dimension) : end_t(end_t), delta_t(delta_t), gravity(gravity), dimension(dimension) {} + + [[nodiscard]] double getEnd_t() const { + return end_t; + } + + [[nodiscard]] double getDelta_t() const { + return delta_t; + } + + [[nodiscard]] double getGravity() const { + return gravity; + } + + [[nodiscard]] int getDimension() const { + return dimension; + } + + void setEnd_t(double newEnd_t) { + end_t = newEnd_t; + } + + void setDelta_t(double newDelta_t) { + delta_t = newDelta_t; + } + + void setGravity(double newGravity) { + gravity = newGravity; + } + + void setDimension(int newDimension) { + dimension = newDimension; + } + +private: + double end_t; + double delta_t; + double gravity; + int dimension; +}; \ No newline at end of file diff --git a/src/io/in/parameters/ThermostatParameters.h b/src/io/in/parameters/ThermostatParameters.h new file mode 100644 index 000000000..cef278cc7 --- /dev/null +++ b/src/io/in/parameters/ThermostatParameters.h @@ -0,0 +1,43 @@ +// +// Created by kimj2 on 15.06.2024. +// + +#pragma once + +class ThermostatParameters { +public: + ThermostatParameters() : start_temp(0.0), target_temp(0.0), applyFrequency(10), max_delta_temp(1.0), + dimension(3) {} // default constructor; + + ThermostatParameters(double start_temp, double target_temp, int applyFrequency, double max_delta_temp, + int dimension) : + start_temp(start_temp), target_temp(target_temp), applyFrequency(applyFrequency), + max_delta_temp(max_delta_temp), dimension(dimension) {} + + double getStartTemp() const { + return start_temp; + } + + double getTargetTemp() const { + return target_temp; + } + + int getApplyFrequency() const { + return applyFrequency; + } + + double getMaxDeltaTemp() const { + return max_delta_temp; + } + + int getDimension() const { + return dimension; + } + +private: + const double start_temp; + const double target_temp; + const int applyFrequency; + const double max_delta_temp; + const int dimension; +}; \ No newline at end of file diff --git a/src/io/out/FileWriter.h b/src/io/out/FileWriter.h index 5328fe7ef..59c46f22b 100644 --- a/src/io/out/FileWriter.h +++ b/src/io/out/FileWriter.h @@ -4,18 +4,19 @@ #pragma once -#include "../../objects/ParticleContainer.h" +#include "objects/ParticleContainer.h" +#include "objects/LinkedCellContainer.h" namespace outputWriters { /** * Abstract base class for output writers. */ - class OutputWriter { + class FileWriter { public: - OutputWriter() = default; + FileWriter() = default; - virtual ~OutputWriter() = default; + virtual ~FileWriter() = default; /** * Method to plot the particles. @@ -24,5 +25,13 @@ namespace outputWriters { * @param filename the filename to write the plot to */ virtual void plotParticles(int iteration, ParticleContainer& particleContainer, const std::string& filename) = 0; + + /** + * Method to plot the particles. + * @param iteration the current iteration + * @param particleContainer the container of particles + * @param filename the filename to write the plot to + */ + virtual void plotParticlesLC(int iteration, LinkedCellContainer& linkedCellContainer, const std::string& filename) = 0; }; } \ No newline at end of file diff --git a/src/io/out/VTKWriter.cpp b/src/io/out/VTKWriter.cpp index 0eb7326a3..34a04fdbc 100644 --- a/src/io/out/VTKWriter.cpp +++ b/src/io/out/VTKWriter.cpp @@ -16,98 +16,109 @@ namespace outputWriters { -void VTKWriter::initializeOutput(int numParticles) { - vtkFile = new VTKFile_t("UnstructuredGrid"); - - // per point, we add type, position, velocity, force, and volume - PointData pointData; - DataArray_t mass(type::Float32, "mass", 1); - DataArray_t velocity(type::Float32, "velocity", 3); - DataArray_t forces(type::Float32, "force", 3); - DataArray_t particleVolume(type::Float32, "volume", 1); // Add volume data - DataArray_t type(type::Int32, "type", 1); - pointData.DataArray().push_back(mass); - pointData.DataArray().push_back(velocity); - pointData.DataArray().push_back(forces); - pointData.DataArray().push_back(particleVolume); // Add volume data - pointData.DataArray().push_back(type); - - CellData cellData; // we don't have cell data => leave it empty - - // 3 coordinates - Points points; - DataArray_t pointCoordinates(type::Float32, "points", 3); - points.DataArray().push_back(pointCoordinates); - - Cells cells; // we don't have cells, => leave it empty - // for some reasons, we have to add a dummy entry for paraview - DataArray_t cells_data(type::Float32, "types", 0); - cells.DataArray().push_back(cells_data); - - PieceUnstructuredGrid_t piece(pointData, cellData, points, cells, numParticles, 0); - UnstructuredGrid_t unstructuredGrid(piece); - vtkFile->UnstructuredGrid(unstructuredGrid); -} - - -void VTKWriter::writeFile(const std::string &filename, int iteration) { - std::stringstream strstr; - strstr << filename << "_" << std::setfill('0') << std::setw(4) << iteration << ".vtu"; - - std::ofstream file(strstr.str().c_str()); - VTKFile(file, *vtkFile); - delete vtkFile; -} - -void VTKWriter::plotParticle(Particle &p) { - if (vtkFile->UnstructuredGrid().present()) { - SPDLOG_TRACE("UnstructuredGrid is present"); - } else { - SPDLOG_TRACE("ERROR: No UnstructuredGrid present"); + void VTKWriter::initializeOutput(int numParticles) { + vtkFile = new VTKFile_t("UnstructuredGrid"); + + // per point, we add type, position, velocity, force, and volume + PointData pointData; + DataArray_t mass(type::Float32, "mass", 1); + DataArray_t velocity(type::Float32, "velocity", 3); + DataArray_t forces(type::Float32, "force", 3); + DataArray_t particleVolume(type::Float32, "volume", 1); // Add volume data + DataArray_t type(type::Int32, "type", 1); + pointData.DataArray().push_back(mass); + pointData.DataArray().push_back(velocity); + pointData.DataArray().push_back(forces); + pointData.DataArray().push_back(particleVolume); // Add volume data + pointData.DataArray().push_back(type); + + CellData cellData; // we don't have cell data => leave it empty + + // 3 coordinates + Points points; + DataArray_t pointCoordinates(type::Float32, "points", 3); + points.DataArray().push_back(pointCoordinates); + + Cells cells; // we don't have cells, => leave it empty + // for some reasons, we have to add a dummy entry for paraview + DataArray_t cells_data(type::Float32, "types", 0); + cells.DataArray().push_back(cells_data); + + PieceUnstructuredGrid_t piece(pointData, cellData, points, cells, numParticles, 0); + UnstructuredGrid_t unstructuredGrid(piece); + vtkFile->UnstructuredGrid(unstructuredGrid); } - PointData::DataArray_sequence &pointDataSequence = - vtkFile->UnstructuredGrid()->Piece().PointData().DataArray(); - PointData::DataArray_iterator dataIterator = pointDataSequence.begin(); - - dataIterator->push_back(p.getM()); - // cout << "Appended mass data in: " << dataIterator->Name(); - - dataIterator++; - dataIterator->push_back(p.getV()[0]); - dataIterator->push_back(p.getV()[1]); - dataIterator->push_back(p.getV()[2]); - // cout << "Appended velocity data in: " << dataIterator->Name(); - - dataIterator++; - dataIterator->push_back(p.getOldF()[0]); - dataIterator->push_back(p.getOldF()[1]); - dataIterator->push_back(p.getOldF()[2]); - // cout << "Appended force data in: " << dataIterator->Name(); - - dataIterator++; - dataIterator->push_back(p.getVolume()); // Add volume data - - dataIterator++; - dataIterator->push_back(p.getType()); - - Points::DataArray_sequence &pointsSequence = - vtkFile->UnstructuredGrid()->Piece().Points().DataArray(); - Points::DataArray_iterator pointsIterator = pointsSequence.begin(); - pointsIterator->push_back(p.getX()[0]); - pointsIterator->push_back(p.getX()[1]); - pointsIterator->push_back(p.getX()[2]); -} - -void VTKWriter::plotParticles(int iteration, ParticleContainer &particleContainer, const std::string &filename) { - outputWriters::VTKWriter writer; - writer.initializeOutput(particleContainer.getSize()); - - for (auto p = particleContainer.begin(); p != particleContainer.end(); ++p) { - writer.plotParticle(*p); + + void VTKWriter::writeFile(const std::string &filename, int iteration) { + std::stringstream strstr; + strstr << filename << "_" << std::setfill('0') << std::setw(4) << iteration << ".vtu"; + + std::ofstream file(strstr.str().c_str()); + VTKFile(file, *vtkFile); + delete vtkFile; + } + + void VTKWriter::plotParticle(Particle &p) { + if (vtkFile->UnstructuredGrid().present()) { + SPDLOG_TRACE("UnstructuredGrid is present"); + } else { + SPDLOG_ERROR("ERROR: No UnstructuredGrid present"); + } + + PointData::DataArray_sequence &pointDataSequence = + vtkFile->UnstructuredGrid()->Piece().PointData().DataArray(); + PointData::DataArray_iterator dataIterator = pointDataSequence.begin(); + + dataIterator->push_back(p.getM()); + // cout << "Appended mass data in: " << dataIterator->Name(); + + dataIterator++; + dataIterator->push_back(p.getV()[0]); + dataIterator->push_back(p.getV()[1]); + dataIterator->push_back(p.getV()[2]); + // cout << "Appended velocity data in: " << dataIterator->Name(); + + dataIterator++; + dataIterator->push_back(p.getOldF()[0]); + dataIterator->push_back(p.getOldF()[1]); + dataIterator->push_back(p.getOldF()[2]); + // cout << "Appended force data in: " << dataIterator->Name(); + + dataIterator++; + dataIterator->push_back(p.getVolume()); // Add volume data + + dataIterator++; + dataIterator->push_back(p.getType()); + + Points::DataArray_sequence &pointsSequence = + vtkFile->UnstructuredGrid()->Piece().Points().DataArray(); + Points::DataArray_iterator pointsIterator = pointsSequence.begin(); + pointsIterator->push_back(p.getX()[0]); + pointsIterator->push_back(p.getX()[1]); + pointsIterator->push_back(p.getX()[2]); } - writer.writeFile(filename, iteration); -} + void VTKWriter::plotParticles(int iteration, ParticleContainer &particleContainer, const std::string &filename) { + outputWriters::VTKWriter writer; + writer.initializeOutput(particleContainer.getSize()); + + for (auto p = particleContainer.begin(); p != particleContainer.end(); ++p) { + writer.plotParticle(*p); + } + + writer.writeFile(filename, iteration); + } + + void VTKWriter::plotParticlesLC(int iteration, LinkedCellContainer &linkedCellContainer, const std::string &filename) { + outputWriters::VTKWriter writer; + writer.initializeOutput(linkedCellContainer.getSize()); + + for (auto &p : linkedCellContainer) { + writer.plotParticle(*p); + } + + writer.writeFile(filename, iteration); + } -} // namespace out +} // namespace outputWriters \ No newline at end of file diff --git a/src/io/out/VTKWriter.h b/src/io/out/VTKWriter.h index b15d043cc..5d4a5b607 100644 --- a/src/io/out/VTKWriter.h +++ b/src/io/out/VTKWriter.h @@ -7,7 +7,7 @@ #pragma once -#include "../../objects/Particle.h" +#include "objects/Particle.h" #include "vtk-unstructured.h" #include "FileWriter.h" @@ -19,7 +19,7 @@ namespace outputWriters { * This class implements the functionality to generate vtk output from * particles. */ - class VTKWriter : public OutputWriter { + class VTKWriter : public FileWriter { public: VTKWriter() = default; @@ -41,6 +41,14 @@ namespace outputWriters { */ void plotParticles(int iteration, ParticleContainer &particleContainer, const std::string &filename); + /** + * Method to plot the particles. + * @param iteration the current iteration + * @param linkedCellContainer the container of particles + * @param filename the filename to write the plot to + */ + void plotParticlesLC(int iteration, LinkedCellContainer& linkedCellContainer, const std::string& filename); + private: VTKFile_t *vtkFile; @@ -66,4 +74,4 @@ namespace outputWriters { */ void writeFile(const std::string &filename, int iteration); }; -} // namespace out +} // namespace outputWriters \ No newline at end of file diff --git a/src/io/out/XYZWriter.cpp b/src/io/out/XYZWriter.cpp index a79e6e2fd..62062ecc9 100644 --- a/src/io/out/XYZWriter.cpp +++ b/src/io/out/XYZWriter.cpp @@ -11,30 +11,33 @@ namespace outputWriters { -void XYZWriter::plotParticles(int iteration, ParticleContainer &particleContainer, const std::string &filename) { - std::ofstream file; - std::stringstream strstr; - strstr << filename << "_" << std::setfill('0') << std::setw(4) << iteration << ".xyz"; - - file.open(strstr.str().c_str()); - file << particleContainer.getSize() << std::endl; - file << "Generated by MolSim. See http://openbabel.org/wiki/XYZ_(format) for " - "file format doku." - << std::endl; - - for (auto p = particleContainer.begin(); p != particleContainer.end(); ++p) { - std::array x = p->getX(); - file << "Ar "; - file.setf(std::ios_base::showpoint); - - for (auto &xi : x) { - file << xi << " "; + void XYZWriter::plotParticles(int iteration, ParticleContainer &particleContainer, const std::string &filename) { + std::ofstream file; + std::stringstream strstr; + strstr << filename << "_" << std::setfill('0') << std::setw(4) << iteration << ".xyz"; + + file.open(strstr.str().c_str()); + file << particleContainer.getSize() << std::endl; + file << "Generated by MolSim. See http://openbabel.org/wiki/XYZ_(format) for " + "file format doku." + << std::endl; + + for (auto p = particleContainer.begin(); p != particleContainer.end(); ++p) { + std::array x = p->getX(); + file << "Ar "; + file.setf(std::ios_base::showpoint); + + for (auto &xi : x) { + file << xi << " "; + } + + file << std::endl; + } + + file.close(); } - file << std::endl; - } - file.close(); -} + void XYZWriter::plotParticlesLC(int iteration, LinkedCellContainer &linkedCellContainer, const std::string &filename) {} -} // namespace out +} // namespace outputWriters \ No newline at end of file diff --git a/src/io/out/XYZWriter.h b/src/io/out/XYZWriter.h index 589875c10..a8f4b0b02 100644 --- a/src/io/out/XYZWriter.h +++ b/src/io/out/XYZWriter.h @@ -7,7 +7,7 @@ #pragma once -#include "../../objects/Particle.h" +#include "objects/Particle.h" #include "FileWriter.h" #include @@ -21,7 +21,7 @@ namespace outputWriters { * This class is a concrete implementation of the `OutputWriter` base class. * It provides an implementation for the `plotParticles` method, which writes the positions of particles in the provided particle container to an XYZ file. */ - class XYZWriter : public OutputWriter { + class XYZWriter : public FileWriter { public: XYZWriter() = default; @@ -40,5 +40,18 @@ namespace outputWriters { * @note The XYZ file will be written to the current working directory. */ void plotParticles(int iteration, ParticleContainer &particleContainer, const std::string &filename); + + /** + * @brief Writes the particles' positions to an XYZ file. + * + * This method writes the positions of all particles in the provided particle container to an XYZ file. + * + * @param iteration The current iteration number, which is used to generate a unique filename for the output file. + * @param particleContainer The container of particles whose positions will be written to the file. + * @param filename The base name of the file to be written. The iteration number will be appended to this name to create a unique filename for each output file. + * + * @note The XYZ file will be written to the current working directory. + */ + void plotParticlesLC(int iteration, LinkedCellContainer &linkedCellContainer, const std::string &filename); }; -}// namespace out +}// namespace outputWriters \ No newline at end of file diff --git a/src/objects/Cell.cpp b/src/objects/Cell.cpp new file mode 100644 index 000000000..76b5c5608 --- /dev/null +++ b/src/objects/Cell.cpp @@ -0,0 +1,30 @@ +#include "Cell.h" +#include "Particle.h" + +void Cell::addParticle(const std::shared_ptr& particle) { + particles.insert(particle); +} + +void Cell::removeParticle(const std::shared_ptr& particle) { + particles.erase(particle); +} + +void Cell::addNeighbor(const std::shared_ptr& cell) { + neighboringCells.push_back(cell); +} + +std::unordered_set>& Cell::getParticles() { + return particles; +} + +std::vector>& Cell::getNeighboringCells() { + return neighboringCells; +} + +int Cell::getNeighboringCellsSize() { + return neighboringCells.size(); +} + +std::array Cell::getIndex(){ + return index; +} diff --git a/src/objects/Cell.h b/src/objects/Cell.h new file mode 100644 index 000000000..59ed357d6 --- /dev/null +++ b/src/objects/Cell.h @@ -0,0 +1,29 @@ +#pragma once + +#include "Particle.h" + +#include +#include +#include + +class Cell { +public: + Cell() = default; + + Cell(size_t xIndex, size_t yIndex, size_t zIndex, double cellSizeX, double cellSizeY, double cellSizeZ) + : index{xIndex, yIndex, zIndex}, dimensions{cellSizeX, cellSizeY, cellSizeZ} {} + + void addParticle(const std::shared_ptr& particle); + void removeParticle(const std::shared_ptr& particle); + void addNeighbor(const std::shared_ptr& cell); + std::unordered_set>& getParticles(); + std::vector>& getNeighboringCells(); + int getNeighboringCellsSize(); + std::array getIndex(); + +private: + std::array index; + std::array dimensions; + std::unordered_set> particles; + std::vector> neighboringCells; +}; diff --git a/src/objects/LinkedCellContainer.cpp b/src/objects/LinkedCellContainer.cpp new file mode 100644 index 000000000..74393b46e --- /dev/null +++ b/src/objects/LinkedCellContainer.cpp @@ -0,0 +1,232 @@ +#include "LinkedCellContainer.h" +#include "Particle.h" +#include "Cell.h" +#include "../utils/MaxwellBoltzmannDistribution.h" +#include "spdlog/spdlog.h" +#include "utils/ArrayUtils.h" + +#include + +void LinkedCellContainer::initializeAndPopulateCells() { + initializeCells(); + initializeNeighbors(); + populateCells(); +} + +void LinkedCellContainer::addParticle(const std::shared_ptr &particle) { + particles.push_back(particle); +} + +std::vector>::iterator LinkedCellContainer::begin() { + return particles.begin(); +} + +std::vector>::iterator LinkedCellContainer::end() { + return particles.end(); +} + +std::vector> LinkedCellContainer::getParticles() const { + return particles; +} + +std::vector>>> LinkedCellContainer::getCells() { + return cells; +} + +size_t LinkedCellContainer::getSize() const { + return particles.size(); +} + +void LinkedCellContainer::initializeCells() { + size_t numCellsX = static_cast(std::ceil(domain[0] / cellSize)); + size_t numCellsY = static_cast(std::ceil(domain[1] / cellSize)); + size_t numCellsZ = static_cast(std::ceil(domain[2] / cellSize)); + SPDLOG_DEBUG("Number of cells in x: {}, y: {}, z: {}", numCellsX, numCellsY, numCellsZ); + + const double lastCellSizeX = domain[0] - (cellSize * (numCellsX - 1)); + const double lastCellSizeY = domain[1] - (cellSize * (numCellsY - 1)); + const double lastCellSizeZ = domain[2] - (cellSize * (numCellsZ - 1)); + SPDLOG_DEBUG("Last cell size in x: {}, y: {}, z: {}", lastCellSizeX, lastCellSizeY, lastCellSizeZ); + + cells.resize(numCellsX); + for (size_t x = 0; x < numCellsX; ++x) { + cells[x].resize(numCellsY); + for (size_t y = 0; y < numCellsY; ++y) { + cells[x][y].resize(numCellsZ); + for (size_t z = 0; z < numCellsZ; ++z) { + const double cellSizeX = (x == numCellsX - 1) ? lastCellSizeX : cellSize; + const double cellSizeY = (y == numCellsY - 1) ? lastCellSizeY : cellSize; + const double cellSizeZ = (z == numCellsZ - 1) ? lastCellSizeZ : cellSize; + cells[x][y][z] = std::make_shared(x, y, z, cellSizeX, cellSizeY, cellSizeZ); + SPDLOG_DEBUG("Created Cell at index ({}, {}, {}) with dimensions: {} x {} x {}", + x, y, z, cellSizeX, cellSizeY, cellSizeZ); + } + } + } + + SPDLOG_INFO("Created LinkedCellContainer with dimensions: {} x {} x {} and cell grid: {} x {} x {}", + domain[0], domain[1], domain[2], numCellsX, numCellsY, numCellsZ); +} + +void LinkedCellContainer::initializeNeighbors() { + int cutoffRadiusIndex = static_cast(std::ceil(cutoffRadius / cellSize)) + 1; + + for (auto &row: cells) { + for (auto &col: row) { + for (auto &cell: col) { + for (int x = -cutoffRadiusIndex; x <= cutoffRadiusIndex; ++x) { + for (int y = -cutoffRadiusIndex; y <= cutoffRadiusIndex; ++y) { + for (int z = -cutoffRadiusIndex; z <= cutoffRadiusIndex; ++z) { + const int neighborXIndex = x + cell->getIndex()[0]; + const int neighborYIndex = y + cell->getIndex()[1]; + const int neighborZIndex = z + cell->getIndex()[2]; + + if (neighborXIndex >= 0 && neighborXIndex < cells.size() && + neighborYIndex >= 0 && neighborYIndex < cells[0].size() && + neighborZIndex >= 0 && neighborZIndex < cells[0][0].size()) { + cell->addNeighbor(cells[neighborXIndex][neighborYIndex][neighborZIndex]); + SPDLOG_DEBUG("Cell at index ({}, {}, {}) has neighbor at index ({}, {}, {})", + cell->getIndex()[0], cell->getIndex()[1], cell->getIndex()[2], + neighborXIndex, neighborYIndex, neighborZIndex); + } + } + } + } + } + } + } +} + +void LinkedCellContainer::populateCells() { + for (auto &particle: particles) { + auto position = particle->getX(); + SPDLOG_DEBUG("Particle at position ({}, {}, {})", position[0], position[1], position[2]); + if (position[0] >= domain[0] || position[0] < 0 || position[1] >= domain[1] || position[1] < 0 || + position[2] >= domain[2] || position[2] < 0) { + SPDLOG_ERROR("Particle at position ({}, {}, {}) is outside the domain ({},{})", position[0], position[1], + position[2], domain[0], domain[1]); + exit(-1); + } + const std::array cellIndex = getCellIndex(particle); + cells[cellIndex[0]][cellIndex[1]][cellIndex[2]]->addParticle(particle); + } + SPDLOG_INFO("Populated cells with particles"); +} + +std::vector> &LinkedCellContainer::getNeighboringCellsIncludingSelf(const Particle &particle) { + const std::array cellIndex = getCellIndex(std::make_shared(particle)); + return cells[cellIndex[0]][cellIndex[1]][cellIndex[2]]->getNeighboringCells(); +} + +void LinkedCellContainer::updateCells() { + for (auto &row: cells) { + for (auto &col: row) { + for (auto &cell: col) { + auto it = cell->getParticles().begin(); + while (it != cell->getParticles().end()) { + auto particleIndex = getCellIndex(*it); + if (!(cell->getIndex() == particleIndex)) { + cells[particleIndex[0]][particleIndex[1]][particleIndex[2]]->addParticle(*it); + SPDLOG_DEBUG("Moved particle at {} from cell at index {} to cell at index ({}, {}, {})", + ArrayUtils::to_string((*it)->getX()), + ArrayUtils::to_string(cell->getIndex()), + particleIndex[0], + particleIndex[1], + particleIndex[2]); + SPDLOG_DEBUG("Removed particle at {} from cell at index {} cell at index ({}, {}, {})", + ArrayUtils::to_string((*it)->getX()), + ArrayUtils::to_string(cell->getIndex()), + cell->getIndex()[0], + cell->getIndex()[1], + cell->getIndex()[2]); + cell->removeParticle(*it); + it = cell->getParticles().begin(); // Reset the iterator as the set has been modified + + } else { + ++it; + } + } + } + } + } +} + +std::array LinkedCellContainer::getCellIndex(const std::shared_ptr &particle) { + return getCellIndex(particle->getX()); +} + +std::array LinkedCellContainer::getCellIndex(const std::array &positions) { + size_t cellIndexX = static_cast(positions[0] / cellSize); + size_t cellIndexY = static_cast(positions[1] / cellSize); + size_t cellIndexZ = static_cast(positions[2] / cellSize); + SPDLOG_DEBUG("Particle at position ({}, {}, {}) is in cell ({}, {}, {}) with domain ({}, {}, {})", positions[0], + positions[1], positions[2], + cellIndexX, cellIndexY, cellIndexZ, domain[0], domain[1], domain[2]); + return std::array{{cellIndexX, cellIndexY, cellIndexZ}}; +} + +void LinkedCellContainer::setCutOffRadius(const double &cutoffRadius) { + this->cutoffRadius = cutoffRadius; + SPDLOG_INFO("Set cutoff radius to {}", this->cutoffRadius); +} + +void LinkedCellContainer::setCellSize(const double &cellSize) { + this->cellSize = cellSize; + SPDLOG_INFO("Set cell size to {}", this->cellSize); +} + +bool LinkedCellContainer::hasZeroVelocities() { + auto particles = this->getParticles(); + for (const auto &particle: this->particles) { + if (!particle->hasZeroVelocities()) { + return false; + } + } + return true; +} + +void LinkedCellContainer::setDomain(const std::array &domain) { + this->domain = domain; + SPDLOG_INFO("Set domain to ({}, {}, {})", domain[0], domain[1], domain[2]); +} + +std::vector> +LinkedCellContainer::getBoundaryCells(const size_t &boundaryWidthInNumCells) { + std::vector> boundaryCells; + + const size_t numCellsX = cells.size(); + const size_t numCellsY = cells[0].size(); + const size_t numCellsZ = cells[0][0].size(); + + const bool is3D = numCellsZ > 1; + + for (size_t i = 0; i < numCellsX; ++i) { + for (size_t j = 0; j < numCellsY; ++j) { + for (size_t k = 0; k < numCellsZ; ++k) { + bool isBoundaryX = i < boundaryWidthInNumCells || i >= numCellsX - boundaryWidthInNumCells; + bool isBoundaryY = j < boundaryWidthInNumCells || j >= numCellsY - boundaryWidthInNumCells; + bool isBoundaryZ = is3D && (k < boundaryWidthInNumCells || k >= numCellsZ - boundaryWidthInNumCells); + + if (isBoundaryX || isBoundaryY || isBoundaryZ) { + boundaryCells.push_back(cells[i][j][k]); + } + } + } + } + + return boundaryCells; +} + +void LinkedCellContainer::removeParticle(const std::shared_ptr &particle) { + auto it = particles.begin(); + while (it != particles.end()) { + if (*it == particle) { + const std::array cellIndex = getCellIndex(particle); + cells[cellIndex[0]][cellIndex[1]][cellIndex[2]]->removeParticle(particle); + particles.erase(it); + return; + } else { + ++it; + } + } +} diff --git a/src/objects/LinkedCellContainer.h b/src/objects/LinkedCellContainer.h new file mode 100644 index 000000000..9ef27f938 --- /dev/null +++ b/src/objects/LinkedCellContainer.h @@ -0,0 +1,122 @@ +#pragma once + +#include "Particle.h" +#include "Cell.h" +#include "../io/in/parameters/CuboidParameters.h" + +#include + +class LinkedCellContainer { + +private: + + /** + * A vector to store the particles. + */ + std::vector> particles; + + /** + * A 3D vector to store the cells. + */ + std::vector>>> cells; + + /** + * The dimensions of the simulation + */ + std::array domain; + + /** + * Containers cutoff radius. + */ + double cutoffRadius; + + /** + * Normal size of the cells. + */ + double cellSize; + +public: + + LinkedCellContainer() = default; + + //LinkedCellContainer(std::array &domain, std::vector &cuboidParameters, double &cutoffRadius, double &cellSize); + + ~LinkedCellContainer() = default; + + void initializeAndPopulateCells(); + + void setCutOffRadius(const double &cutoffRadius); + + void setCellSize(const double &cellSize); + + void setDomain(const std::array &domain); + + /** + * Method to add a particle to the container. + * @param particle the particle to add + */ + void addParticle(const std::shared_ptr &particle); + + /** + * Method to remove a particle from the container. + * @param particle the particle to be removed + */ + void removeParticle(const std::shared_ptr &particle); + + /** + * Begin iterator for the particles. + * @return an iterator to the beginning of the particles + */ + std::vector>::iterator begin(); + + /** + * End iterator for the particles. + * @return an iterator to the end of the particles + */ + std::vector>::iterator end(); + + /** + * Get the particles in the container. + * @return a vector of all the particles + */ + std::vector> getParticles() const; + + /** + * Get the particles in the container. + * @return a vector of all the particles + */ + std::vector>>> getCells(); + + /** + * Get the number of particles in the container. + * @return the number of particles + */ + size_t getSize() const; + + void initializeCells(); + + void initializeNeighbors(); + + void populateCells(); + + std::vector>& getNeighboringCellsIncludingSelf(const Particle &particle); + + /** + * Method to add a cell to cells. + */ + void addCell(); + + /** + * Method to update the cells and their particles. + */ + void updateCells(); + + + std::array getCellIndex(const std::shared_ptr &particle); + + bool hasZeroVelocities(); + + std::array getCellIndex(const std::array &positions); + + std::vector> getBoundaryCells(const size_t &boundaryWidthInNumCells); +}; \ No newline at end of file diff --git a/src/objects/Particle.cpp b/src/objects/Particle.cpp index dd0a9e27e..b1c83249f 100644 --- a/src/objects/Particle.cpp +++ b/src/objects/Particle.cpp @@ -10,6 +10,8 @@ #include #include "../utils/ArrayUtils.h" +const double COMPARISON_TOLERANCE = 1e-6; + Particle::Particle(int type_arg) { type = type_arg; f = {0., 0., 0.}; @@ -26,16 +28,41 @@ Particle::Particle(const Particle &other) { m = other.m; volume = other.volume; type = other.type; + epsilon = other.epsilon; + sigma = other.sigma; + id = other.id; SPDLOG_TRACE("Particle generated by copy!"); } Particle::Particle(std::array x_arg, std::array v_arg, double m_arg, double volume_arg, int type_arg) : x(x_arg), v(v_arg), f({0., 0., 0.}), old_f({0., 0., 0.}), - m(m_arg), volume(volume_arg), type(type_arg) { + m(m_arg), volume(volume_arg), type(type_arg), sigma(1.0), epsilon(5.0) { + SPDLOG_TRACE("Particle generated!"); +} + +Particle::Particle(std::array x_arg, std::array v_arg, + double m_arg, double volume_arg, int type_arg, size_t id_arg) + : x(x_arg), v(v_arg), f({0., 0., 0.}), old_f({0., 0., 0.}), + m(m_arg), volume(volume_arg), type(type_arg), id(id_arg), sigma(1.0), epsilon(5.0) { + SPDLOG_TRACE("Particle generated!"); +} + +Particle::Particle(std::array x_arg, std::array v_arg, + double m_arg, double volume_arg, int type_arg, double sig_arg, double eps_arg) + : x(x_arg), v(v_arg), f({0., 0., 0.}), old_f({0., 0., 0.}), + m(m_arg), volume(volume_arg), type(type_arg), sigma(sig_arg), epsilon(eps_arg) { + SPDLOG_TRACE("Particle generated!"); +} + +Particle::Particle(std::array x_arg, std::array v_arg, + double m_arg, double volume_arg, int type_arg, double sig_arg, double eps_arg, size_t id_arg) + : x(x_arg), v(v_arg), f({0., 0., 0.}), old_f({0., 0., 0.}), + m(m_arg), volume(volume_arg), type(type_arg), sigma(sig_arg), epsilon(eps_arg), id(id_arg) { SPDLOG_TRACE("Particle generated!"); } + Particle::~Particle() { SPDLOG_TRACE("Particle destructed!"); } const std::array &Particle::getX() const { return x; } @@ -52,6 +79,8 @@ const double Particle::getVolume() const { return volume; } const int Particle::getType() const { return type; } +const size_t Particle::getID() const { return id; } + void Particle::setX(const std::array &newX) { x = newX; } @@ -76,6 +105,13 @@ void Particle::setVolume(const double newVolume) { volume = newVolume; } +bool Particle::hasZeroVelocities() const { + const auto &velocities = this->getV(); + return std::abs(velocities[0]) < COMPARISON_TOLERANCE && std::abs(velocities[1]) < COMPARISON_TOLERANCE && + std::abs(velocities[2]) < COMPARISON_TOLERANCE; +} + + std::string Particle::toString() const { std::stringstream stream; stream << "Particle: X:" << x << " v: " << v << " f: " << f @@ -87,10 +123,19 @@ std::string Particle::toString() const { bool Particle::operator==(const Particle &other) const { return (x == other.x) and (v == other.v) and (f == other.f) and (type == other.type) and (m == other.m) and - (volume == other.volume) and (old_f == other.old_f); + (volume == other.volume) and (old_f == other.old_f) and + (sigma == other.sigma) and (epsilon == other.epsilon); +} + +double Particle::getSigma() const { + return sigma; +} + +double Particle::getEpsilon() const { + return epsilon; } std::ostream &operator<<(std::ostream &stream, Particle &p) { stream << p.toString(); return stream; -} +} \ No newline at end of file diff --git a/src/objects/Particle.h b/src/objects/Particle.h index d081c5d5e..7acd07055 100644 --- a/src/objects/Particle.h +++ b/src/objects/Particle.h @@ -38,6 +38,16 @@ class Particle { */ double m; + /** + * Sigma of this particle + */ + double sigma; + + /** + * Epsilon of this particle + */ + double epsilon; + /** * Paraview volume of this particle */ @@ -49,6 +59,12 @@ class Particle { */ int type; + /** + * Type of the particle. Use it for whatever you want (e.g. to separate + * molecules belonging to different bodies, matters, and so on) + */ + size_t id; + public: explicit Particle(int type = 0); @@ -57,9 +73,22 @@ class Particle { Particle( // for visualization, we need always 3 coordinates // -> in case of 2d, we use only the first and the second - std::array x_arg, std::array v_arg, + std::array x_arg, std::array v_arg, double m_arg, double volume_arg, int type = 0); + Particle( + // for visualization, we need always 3 coordinates + // -> in case of 2d, we use only the first and the second + std::array x_arg, std::array v_arg, + double m_arg, double volume_arg, int type, size_t id); + + // New constructor with sigma and epsilon as new parameters + Particle(std::array x_arg, std::array v_arg, + double m_arg, double volume_arg, int type_arg, double sig_arg, double eps_arg, size_t id); + + Particle(std::array x_arg, std::array v_arg, + double m_arg, double volume_arg, int type_arg, double sig_arg, double eps_arg); + virtual ~Particle(); const std::array &getX() const; @@ -76,6 +105,8 @@ class Particle { const int getType() const; + const size_t getID() const; + void setX(const std::array &newX); void setV(const std::array &newV); @@ -91,6 +122,12 @@ class Particle { bool operator==(const Particle &other) const; std::string toString() const; + + bool hasZeroVelocities() const; + + double getSigma() const; + + double getEpsilon() const; }; -std::ostream &operator<<(std::ostream &stream, Particle &p); +std::ostream &operator<<(std::ostream &stream, Particle &p); \ No newline at end of file diff --git a/src/objects/ParticleContainer.cpp b/src/objects/ParticleContainer.cpp index 97a38f27a..7c0ba983d 100644 --- a/src/objects/ParticleContainer.cpp +++ b/src/objects/ParticleContainer.cpp @@ -8,10 +8,35 @@ void ParticleContainer::addParticle(const Particle &particle) { particles.push_back(particle); } +void ParticleContainer::deleteParticle(const Particle &particle) { + // Find the particle in the vector + auto it = std::find_if(particles.begin(), particles.end(), [&](const Particle &p) { + return p == particle; + }); + + // If the particle is found, erase it from the vector + if (it != particles.end()) { + particles.erase(it); + } + particlePairs.clear(); + initializePairs(); +} + +bool ParticleContainer::pairExists(const Particle &particle1, const Particle &particle2) const { + for (const auto &pair : particlePairs) { + if ((&pair.first.get() == &particle1 && &pair.second.get() == &particle2) || + (&pair.first.get() == &particle2 && &pair.second.get() == &particle1)) { + return true; + } + } + return false; +} + void ParticleContainer::initializePairs() { for (auto it1 = particles.begin(); it1 != particles.end(); ++it1) for (auto it2 = std::next(it1); it2 != particles.end(); ++it2) - particlePairs.push_back({*it1, *it2}); + if (!pairExists(*it1, *it2)) + particlePairs.push_back({*it1, *it2}); } void ParticleContainer::setVolumes() { @@ -63,4 +88,14 @@ size_t ParticleContainer::getSize() const { std::vector ParticleContainer::getParticles() const { return particles; -}; \ No newline at end of file +}; + +bool ParticleContainer::hasZeroVelocities() const { + auto particles = this->getParticles(); + for (const auto& particle : this->particles) { + if (!particle.hasZeroVelocities()) { + return false; + } + } + return true; +} \ No newline at end of file diff --git a/src/objects/ParticleContainer.h b/src/objects/ParticleContainer.h index 643d5649b..f27e1e247 100644 --- a/src/objects/ParticleContainer.h +++ b/src/objects/ParticleContainer.h @@ -11,6 +11,9 @@ */ class ParticleContainer { private: + /** + * Boundary + */ /** * A vector to store the particles. */ @@ -21,6 +24,7 @@ class ParticleContainer { std::vector, std::reference_wrapper>> particlePairs; public: + ParticleContainer() = default; ~ParticleContainer() = default; @@ -31,6 +35,17 @@ class ParticleContainer { */ void addParticle(const Particle &particle); + /** + * Method to remove a particle from the container. + * @param particle the particle to remove + */ + void deleteParticle(const Particle &particle); + + /** + * Method to check if pair in ParticlePairs already exists + */ + bool pairExists(const Particle &particle1, const Particle &particle2) const; + /** * Method to fill the vector of unique pairs with the references to particles. */ @@ -72,4 +87,6 @@ class ParticleContainer { size_t getSize() const; std::vector getParticles() const; + + bool hasZeroVelocities() const; }; \ No newline at end of file diff --git a/src/utils/ArrayUtils.h b/src/utils/ArrayUtils.h index 401655c65..211b2be06 100644 --- a/src/utils/ArrayUtils.h +++ b/src/utils/ArrayUtils.h @@ -162,6 +162,18 @@ inline Container elementWiseScalarOp(const Scalar &lhs, const Container &rhs, return ret; } +/** + * Calculates the dot product of two containers. + * @tparam Container + * @param lhs + * @param rhs + * @return result of the dot product as double value. + */ + template + double dotProduct(const Container &lhs, const Container &rhs) { + return std::inner_product(lhs.begin(), lhs.end(), rhs.begin(), 0.0); + } + /** * Calculates the L2 norm for a given container. * @tparam Container @@ -174,7 +186,6 @@ template auto L2Norm(const Container &c) { } } // namespace ArrayUtils - /** * Stream operator for containers. * diff --git a/src/utils/MaxwellBoltzmannDistribution.cpp b/src/utils/MaxwellBoltzmannDistribution.cpp new file mode 100644 index 000000000..eada856b9 --- /dev/null +++ b/src/utils/MaxwellBoltzmannDistribution.cpp @@ -0,0 +1,18 @@ +// +// Created by kimj2 on 12.06.2024. +// +#include "MaxwellBoltzmannDistribution.h" +#include +#include +#include + +std::array maxwellBoltzmannDistributedVelocity(double averageVelocity, size_t dimensions) { + static std::default_random_engine randomEngine(42); + std::normal_distribution normalDistribution{0, 1}; + std::array randomVelocity{}; + for (size_t i = 0; i < dimensions; ++i) { + randomVelocity[i] = averageVelocity * normalDistribution(randomEngine); + } + SPDLOG_TRACE("Generated random velocity: [{}, {}, {}]", randomVelocity[0], randomVelocity[1], randomVelocity[2]); + return randomVelocity; +} \ No newline at end of file diff --git a/src/utils/MaxwellBoltzmannDistribution.h b/src/utils/MaxwellBoltzmannDistribution.h index 1f0d78108..1709343c4 100644 --- a/src/utils/MaxwellBoltzmannDistribution.h +++ b/src/utils/MaxwellBoltzmannDistribution.h @@ -7,7 +7,6 @@ #pragma once -#include #include /** @@ -17,17 +16,4 @@ * @param dimensions Number of dimensions for which the velocity vector shall be generated. Set this to 2 or 3. * @return Array containing the generated velocity vector. */ -std::array maxwellBoltzmannDistributedVelocity(double averageVelocity, size_t dimensions) { - // we use a constant seed for repeatability. - // random engine needs static lifetime otherwise it would be recreated for every call. - static std::default_random_engine randomEngine(42); - - // when adding independent normally distributed values to all velocity components - // the velocity change is maxwell boltzmann distributed - std::normal_distribution normalDistribution{0, 1}; - std::array randomVelocity{}; - for (size_t i = 0; i < dimensions; ++i) { - randomVelocity[i] = averageVelocity * normalDistribution(randomEngine); - } - return randomVelocity; -} +std::array maxwellBoltzmannDistributedVelocity(double averageVelocity, std::size_t dimensions); diff --git a/tests/boundaries/BoundaryHandlerTest.cpp b/tests/boundaries/BoundaryHandlerTest.cpp new file mode 100644 index 000000000..19d556315 --- /dev/null +++ b/tests/boundaries/BoundaryHandlerTest.cpp @@ -0,0 +1,316 @@ +// +// Created by U-jin Hong on 04.06.24. +// + +#include +#include +#include + +#include "boundaries/BoundaryHandler.h" +#include "calculators/LJCalculator.h" +#include "io/in/FileReader.h" +#include "io/in/TXTReader.h" +#include "io/in/XMLReader.h" +// Helper function to compare two std::array with a given tolerance +bool arraysNear(const std::array &arr1, const std::array &arr2, double tolerance) { + for (size_t i = 0; i < arr1.size(); ++i) { + if (std::fabs(arr1[i] - arr2[i]) > tolerance) { + return false; + } + } + return true; +} + +// Custom Google Test macro for comparing std::array +#define ASSERT_ARRAYS_NEAR(arr1, arr2, tolerance) \ + ASSERT_PRED3(arraysNear, arr1, arr2, tolerance) + +namespace boundaries { +// Testing Particles moving against every reflecting boundary +// Check if the forces after reflection are correct + TEST(BoundaryHandlerTest, BasicReflection) { + SPDLOG_INFO("Testing Reflections..."); + std::map boundaryMap{}; + std::array domain = {20.0, 20.0, 10.0}; + boundaryMap.emplace(boundaries::BoundaryDirection::LEFT, boundaries::BoundaryType::REFLECTING); + boundaryMap.emplace(boundaries::BoundaryDirection::RIGHT, boundaries::BoundaryType::REFLECTING); + boundaryMap.emplace(boundaries::BoundaryDirection::TOP, boundaries::BoundaryType::REFLECTING); + boundaryMap.emplace(boundaries::BoundaryDirection::BOTTOM, boundaries::BoundaryType::REFLECTING); + std::shared_ptr calculator = std::make_shared(3.0); + boundaries::BoundaryProperties properties{domain, boundaryMap}; + // Initialization of BoundaryHandler + boundaries::BoundaryHandler handler{properties, calculator}; + + ParticleContainer container{}; + container.addParticle(Particle{std::array{10.0, 0.5, 0.0}, std::array{0.0, 3.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{10.0, 19.5, 0.0}, std::array{0.0, 3.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{0.5, 10., 0.0}, std::array{0.0, 3.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{19.5, 10., 0.0}, std::array{0.0, 3.0, 0.0}, 1.0, 0.0}); + + // Check if Force of all Particles is zero + std::array zero{0.0, 0.0, 0.0}; + for (Particle &p: container) { + ASSERT_EQ(p.getF(), zero); + } + std::vector> expectedReflectedForces{{0.0, 120.0, 0.0}, + {0.0, -120.0, 0.0}, + {120.0, 0.0, 0.0}, + {-120.0, 0.0, 0.0}}; + + handler.preProcessBoundaries(container); + std::vector particles = container.getParticles(); + for (int i = 0; i < 4; i++) { + ASSERT_ARRAYS_NEAR(particles[i].getF(), expectedReflectedForces[i], 1e-6); + } + } + +// Testing Particles moving against every reflecting boundary +// Check if the forces after reflection are correct + TEST(BoundaryHandlerTest, CornerReflection) { + std::map boundaryMap{}; + std::array domain = {20.0, 20.0, 10.0}; + std::shared_ptr calculator = std::make_shared(3.0); + boundaries::BoundaryProperties properties{domain, boundaryMap}; + boundaryMap[BoundaryDirection::TOP] = boundaries::BoundaryType::REFLECTING; + boundaryMap[BoundaryDirection::BOTTOM] = boundaries::BoundaryType::REFLECTING; + boundaryMap[BoundaryDirection::LEFT] = boundaries::BoundaryType::REFLECTING; + boundaryMap[BoundaryDirection::RIGHT] = boundaries::BoundaryType::REFLECTING; + // Initialization of BoundaryHandler + boundaries::BoundaryHandler handler{properties, calculator}; + + ParticleContainer container{}; + container.addParticle(Particle{std::array{0.5, 0.5, 0.0}, std::array{-3.0, -3.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{0.5, 19.5, 0.0}, std::array{-3.0, -3.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{19.5, 0.5, 0.0}, std::array{3.0, -3.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{19.5, 19.5, 0.0}, std::array{3.0, -3.0, 0.0}, 1.0, 0.0}); + + // Check if Force of all Particles is zero + std::array zero{0.0, 0.0, 0.0}; + for (Particle &p: container) { + ASSERT_EQ(p.getF(), zero); + } + std::vector> expectedReflectedForces{{120.0, 120.0, 0}, + {120.0, -120.0, 0}, + {-120.0, 120.0, 0}, + {-120.0, -120.0, 0}}; + handler.preProcessBoundaries(container); + std::vector particles = container.getParticles(); + for (int i = 0; i < 4; i++) { + ASSERT_ARRAYS_NEAR(particles[i].getF(), expectedReflectedForces[i], 1e-6); + } + } + + + TEST(BoundaryHandlerTest, BasicOutflow) { + std::map boundaryMap{}; + boundaryMap.emplace(boundaries::BoundaryDirection::LEFT, boundaries::BoundaryType::OUTFLOW); + boundaryMap.emplace(boundaries::BoundaryDirection::RIGHT, boundaries::BoundaryType::OUTFLOW); + boundaryMap.emplace(boundaries::BoundaryDirection::BOTTOM, boundaries::BoundaryType::OUTFLOW); + boundaryMap.emplace(boundaries::BoundaryDirection::TOP, boundaries::BoundaryType::OUTFLOW); + + std::array domain = {20.0, 20.0, 10.0}; + std::shared_ptr calculator = std::make_shared(3.0); + boundaries::BoundaryProperties properties{domain, boundaryMap}; + // Initialization of BoundaryHandler + boundaries::BoundaryHandler handler{properties, calculator}; + + ParticleContainer container{}; + container.addParticle(Particle{std::array{10.0, 0.5, 0.0}, std::array{0.0, -500.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{10.0, 19.5, 0.0}, std::array{0.0, 500.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{0.5, 10.0, 0.0}, std::array{-1000.0, 0.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{19.5, 10.0, 0.0}, std::array{2000.0, 0.0, 0.0}, 1.0, 0.0}); + + // Check if Force of all Particles is zero + std::array zero{0.0, 0.0, 0.0}; + for (Particle &p: container) { + ASSERT_EQ(p.getF(), zero); + } + // First timestep - The faster two particles should be deleted on the left/right + handler.preProcessBoundaries(container); + calculator->calculate(container, 0.0005); + handler.postProcessBoundaries(container); + ASSERT_EQ(container.getSize(), 2); + // Second timestep - The two slower particles get deleted on the bottom and top + handler.preProcessBoundaries(container); + calculator->calculate(container, 0.0005); + handler.postProcessBoundaries(container); + ASSERT_EQ(container.getSize(), 0); + } + + // Check the Behaviour of two reflecting boundaries top and left, two outflow boundaries bottom and right + TEST(BoundaryHandlerTest, MixedBoundaries) { + std::map boundaryMap{}; + boundaryMap.emplace(boundaries::BoundaryDirection::BOTTOM, boundaries::BoundaryType::OUTFLOW); + boundaryMap.emplace(boundaries::BoundaryDirection::RIGHT, boundaries::BoundaryType::OUTFLOW); + boundaryMap[BoundaryDirection::TOP] = boundaries::BoundaryType::REFLECTING; + boundaryMap[BoundaryDirection::LEFT] = boundaries::BoundaryType::REFLECTING; + std::array domain = {20.0, 20.0, 10.0}; + std::shared_ptr calculator = std::make_shared(3.0); + boundaries::BoundaryProperties properties{domain, boundaryMap}; + // Initialization of BoundaryHandler + boundaries::BoundaryHandler handler{properties, calculator}; + + ParticleContainer container{}; + container.addParticle(Particle{std::array{10.0, 0.5, 0.0}, std::array{0.0, -300.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{10.0, 19.5, 0.0}, std::array{0.0, -300.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{0.5, 10.0, 0.0}, std::array{-300.0, 0.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{19.5, 10.0, 0.0}, std::array{1000.0, 0.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{0.5, 0.5, 0.0}, std::array{-300.0, -300.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{0.5, 19.5, 0.0}, std::array{-300.0, 300.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{19.5, 0.5, 0.0}, std::array{1000.0, -300.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{19.5, 19.5, 0.0}, std::array{1000.0, 300.0, 0.0}, 1.0, 0.0}); + + // Check if Force of all Particles is zero + std::array zero{0.0, 0.0, 0.0}; + for (Particle &p: container) { + ASSERT_EQ(p.getF(), zero); + } + handler.preProcessBoundaries(container); + calculator->calculate(container, 0.0005); + handler.postProcessBoundaries(container); + std::vector particles = container.getParticles(); + ASSERT_EQ(container.getSize(), 5); + //First iteration + std::vector> expectedForces{{0.0, 0.0, 0.0}, + {0.0, -120.0, 0.0}, + {120.0, 0.0, 0.0}, + {120.0, 0.0, 0.0}, + {120.0, -120.0, 0.0}}; + std::vector> expectedPositions{{10.0, 0.35, 0.0}, + {10.0, 19.35, 0.0}, + {0.35, 10.0, 0.0}, + {0.35, 0.35, 0.0}, + {0.35, 19.65, 0.0}}; + for (int i = 0; i < 5; i++) { + ASSERT_ARRAYS_NEAR(particles[i].getOldF(), expectedForces[i], 1e-6); + ASSERT_ARRAYS_NEAR(particles[i].getX(), expectedPositions[i], 1e-6); + } + for (int i = 0; i < 3; i++) { + handler.preProcessBoundaries(container); + calculator->calculate(container, 0.0005); + handler.postProcessBoundaries(container); + } + expectedForces.clear(); + expectedPositions.clear(); + particles.clear(); + particles = container.getParticles(); + ASSERT_EQ(container.getSize(), 3); + expectedForces = {{0, 1.2851430767584855, 0}, + {20000.0, 0.0, 0.0}, + {20000.0, -20000.0, 0.0}}; + expectedPositions = {{10, 18.899958292097978, 0}, + {-0.09245500000000006, 10.0, 0.0}, + {-0.09245500000000006, 20.092454999999998, 0.0}}; + for (int i = 0; i < 3; i++) { + ASSERT_ARRAYS_NEAR(particles[i].getOldF(), expectedForces[i], 1e-6); + ASSERT_ARRAYS_NEAR(particles[i].getX(), expectedPositions[i], 1e-6); + } + } + + TEST(BoundaryHandlerTest, PeriodicBoundaries) { + std::array domain = {20.0, 20.0, 10.0}; + std::shared_ptr calculator = std::make_shared(3.0); + std::map boundaryMap{}; + boundaryMap[BoundaryDirection::TOP] = boundaries::BoundaryType::PERIODIC; + boundaryMap[BoundaryDirection::BOTTOM] = boundaries::BoundaryType::PERIODIC; + boundaryMap[BoundaryDirection::LEFT] = boundaries::BoundaryType::PERIODIC; + boundaryMap[BoundaryDirection::RIGHT] = boundaries::BoundaryType::PERIODIC; + boundaries::BoundaryProperties properties{domain, boundaryMap}; + // Initialization of BoundaryHandler + boundaries::BoundaryHandler handler{properties, calculator}; + ParticleContainer container{}; + container.addParticle(Particle{std::array{15.0, 0.5, 0.0}, std::array{0.0, -500.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{5.0, 19.5, 0.0}, std::array{0.0, 500.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{0.5, 5.0, 0.0}, std::array{-1000.0, 0.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{19.5, 15.0, 0.0}, std::array{1000.0, 0.0, 0.0}, 1.0, 0.0}); + + // Check if Force of all Particles is zero + std::array zero{0.0, 0.0, 0.0}; + for (Particle &p: container) { + ASSERT_EQ(p.getF(), zero); + } + // First timestep - The faster two particles should be deleted on the left/right + handler.preProcessBoundaries(container); + calculator->calculate(container, 0.0005); + handler.postProcessBoundaries(container); + ASSERT_EQ(container.getSize(), 4); + std::vector> expectedPositions{{15, 0.25, 0}, + {5, 19.75, 0}, + {0, 5, 0}, + {0, 15.0, 0}}; + std::vector particles = container.getParticles(); + for (int i = 0; i < 4; i++) + ASSERT_ARRAYS_NEAR(particles[i].getX(), expectedPositions[i], 1e-6); + // Second timestep - The two slower particles get deleted on the bottom and top + handler.preProcessBoundaries(container); + calculator->calculate(container, 0.0005); + handler.postProcessBoundaries(container); + ASSERT_EQ(container.getSize(), 4); + particles.clear(); + particles = container.getParticles(); + expectedPositions = {{15, 0, 0}, + {5, 0, 0}, + {19.5, 5, 0}, + {0.5, 15, 0}}; + for (int i = 0; i < 4; i++) + ASSERT_ARRAYS_NEAR(particles[i].getX(), expectedPositions[i], 1e-6); + } + + // Check if the forces after reflection are correct + TEST(BoundaryHandlerTest, CornerPeriodic) { + std::map boundaryMap{}; + boundaryMap[BoundaryDirection::TOP] = boundaries::BoundaryType::PERIODIC; + boundaryMap[BoundaryDirection::BOTTOM] = boundaries::BoundaryType::PERIODIC; + boundaryMap[BoundaryDirection::LEFT] = boundaries::BoundaryType::PERIODIC; + boundaryMap[BoundaryDirection::RIGHT] = boundaries::BoundaryType::PERIODIC; + std::array domain = {20.0, 20.0, 10.0}; + std::shared_ptr calculator = std::make_shared(3.0); + boundaries::BoundaryProperties properties{domain, boundaryMap}; + // Initialization of BoundaryHandler + boundaries::BoundaryHandler handler{properties, calculator}; + std::ofstream outfile("particles_near_reflecting_boundary.txt"); + outfile << "0\n" // Data code for Particles + << "4\n" // Number of data sets + << "2\n" // Dimension of simulation + << "0.5 0.5 0.0 -1000.0 -1000.0 0.0 1.0\n" // Bottom Left + << "0.5 19.5 0.0 -1000.0 1000.0 0.0 1.0\n" // Top Left + << "19.5 0.5 0.0 1000.0 -1000.0 0.0 1.0\n" // Bottom Right + << "19.5 19.5 0.0 1000.0 1000.0 0.0 1.0\n";// Top Right + outfile.close(); + + // Read cuboid data from the file + ParticleContainer container{}; + container.addParticle(Particle{std::array{0.5, 0.5, 0.0}, std::array{-1000.0, -1000.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{0.5, 19.5, 0.0}, std::array{-1000.0, 1000.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{19.5, 0.5, 0.0}, std::array{1000.0, -1000.0, 0.0}, 1.0, 0.0}); + container.addParticle(Particle{std::array{19.5, 19.5, 0.0}, std::array{1000.0, 1000.0, 0.0}, 1.0, 0.0}); + std::remove("particles_near_reflecting_boundary"); + + // Check if Force of all Particles is zero + std::array zero{0.0, 0.0, 0.0}; + for (Particle &p: container) { + ASSERT_EQ(p.getF(), zero); + } + // First timestep - The faster two particles should be deleted on the left/right + handler.preProcessBoundaries(container); + calculator->calculate(container, 0.0005); + handler.postProcessBoundaries(container); + ASSERT_EQ(container.getSize(), 4); + std::vector particles = container.getParticles(); + for (int i = 0; i < 4; i++) + ASSERT_ARRAYS_NEAR(particles[i].getX(), zero, 1e-6); + // Second timestep - The two slower particles get deleted on the bottom and top + handler.preProcessBoundaries(container); + calculator->calculate(container, 0.0005); + handler.postProcessBoundaries(container); + ASSERT_EQ(container.getSize(), 4); + particles.clear(); + particles = container.getParticles(); + std::vector> expectedPositions = {{19.5, 19.5, 0.0}, + {19.5, 0.5, 0.0}, + {0.5, 19.5, 0.0}, + {0.5, 0.5, 0.0}}; + for (int i = 0; i < 4; i++) + ASSERT_ARRAYS_NEAR(particles[i].getX(), expectedPositions[i], 1e-6); + } +} //boundaries \ No newline at end of file diff --git a/tests/calculators/CalculatorTest.cpp b/tests/calculators/CalculatorTest.cpp index 82d18f7c4..aaa670ce7 100644 --- a/tests/calculators/CalculatorTest.cpp +++ b/tests/calculators/CalculatorTest.cpp @@ -11,7 +11,10 @@ namespace calculators { class TestCalculator : public calculators::Calculator { private: - void calculateF(ParticleContainer &particleContainer) override {} +// void calculateF(ParticleContainer &particleContainer) override {}; + void calculateFPairwise(Particle &particle1, Particle &particle2) const override{}; + + void calculateLC(LinkedCellContainer &linkedCellContainer, double delta_t) override {}; }; } @@ -38,18 +41,18 @@ TEST(CalculatorTest, CalculateXTest) { calculator->calculateX(pc, delta_t); } - const std::vector> expectedX = { + const std::vector> expectedPositions = { {0.8950, 0.8950, 0.8950}, {-0.8950, -0.8950, -0.8950} }; auto it = pc.begin(); for (size_t i = 0; i < pc.getSize(); ++i, ++it) { - std::array expectedF = expectedX[i]; + std::array expectedX = expectedPositions[i]; std::array actualX = it->getX(); - EXPECT_NEAR(expectedF[0], actualX[0], 1e-3); - EXPECT_NEAR(expectedF[1], actualX[1], 1e-3); - EXPECT_NEAR(expectedF[2], actualX[2], 1e-3); + EXPECT_NEAR(expectedX[0], actualX[0], 1e-3); + EXPECT_NEAR(expectedX[1], actualX[1], 1e-3); + EXPECT_NEAR(expectedX[2], actualX[2], 1e-3); } } @@ -85,4 +88,35 @@ TEST(CalculatorTest, CalculateVTest) { EXPECT_NEAR(expectedV[1], actualV[1], 1e-3); EXPECT_NEAR(expectedV[2], actualV[2], 1e-3); } +} +//Testing Gravity with different Masses +TEST(CalculatorTest, GravityTest) { + calculator->setGravity(-10.0); + ParticleContainer container{}; +// Particle::Particle(std::array x_arg, std::array v_arg, +// double m_arg, double volume_arg, int type_arg) + Particle p1{{1.0, 1.0, 1.0}, {1.0, 1.0, 1.0}, 0.5, 1.0, 1}; + Particle p2{{1.0, 1.0, 1.0}, {1.0, 1.0, 1.0}, 1.0, 1.0, 1}; + Particle p3{{1.0, 1.0, 1.0}, {1.0, 1.0, 1.0}, 2.0, 1.0, 1}; + Particle p4{{1.0, 1.0, 1.0}, {1.0, 1.0, 1.0}, 5.0, 1.0, 1}; + + container.addParticle(p1); + container.addParticle(p2); + container.addParticle(p3); + container.addParticle(p4); + + calculator->calculateGravity(container); + std::vector particles = container.getParticles(); + + std::vector> expectedForces = {{0.0, -5.0, 0.0}, + {0.0, -10.0, 0.0}, + {0.0, -20.0, 0.0}, + {0.0, -50.0, 0.0}}; + // Iteration through vector + for (int i = 0; i < 4; i++) { + // Iteration through vector elements + for (int j = 0; j < 3; j++){ + ASSERT_NEAR(particles[i].getF()[j], expectedForces[i][j], 1e-6); + } + } } \ No newline at end of file diff --git a/tests/calculators/LC_LJCalculatorTest.cpp b/tests/calculators/LC_LJCalculatorTest.cpp new file mode 100644 index 000000000..3903a42be --- /dev/null +++ b/tests/calculators/LC_LJCalculatorTest.cpp @@ -0,0 +1,106 @@ +#include "../../src/calculators/Calculator.h" +#include "../../src/calculators/LC_LJCalculator.h" +#include "../../src/objects/Particle.h" +#include "../../src/objects/LinkedCellContainer.h" +#include "gtest/gtest.h" + +namespace { + const auto calculator = std::make_unique(); +} + +TEST(LC_LJCalculatorTest, CalculateFTest) { + std::array domain = {12.0, 9.0, 3.0}; + double cutoffRadius = 3.0; + double cellSize = 3.0; + LinkedCellContainer lc; + lc.setCellSize(cellSize); + lc.setCutOffRadius(cutoffRadius); + lc.setDomain(domain); + auto p1 = std::make_shared(std::array{0.25, 0.25, 0.25}, std::array{0, 0, 0}, 1.0, 0.0, 0); + auto p2 = std::make_shared(std::array{1.25, 1.25, 1.25}, std::array{0, 0, 0}, 1.0, 0.0, 0); + lc.addParticle(p1); + lc.addParticle(p2); + lc.initializeAndPopulateCells(); + + calculator->calculateLC_F(lc); + + const std::vector> expectedForces = { + {2.743, 2.743, 2.743}, + {-2.743, -2.743, -2.743} + }; + + int index = 0; + for (auto &particle: lc) { + std::array expectedF = expectedForces[index]; + std::array actualF = particle->getF(); + EXPECT_NEAR(expectedF[0], actualF[0], 1e-3); + EXPECT_NEAR(expectedF[1], actualF[1], 1e-3); + EXPECT_NEAR(expectedF[2], actualF[2], 1e-3); + index++; + } +} + +TEST(LC_LJCalculatorTest, DifferentSigma) { + std::array domain = {12.0, 9.0, 3.0}; + double cutoffRadius = 3.0; + double cellSize = 3.0; + LinkedCellContainer lc; + lc.setCellSize(cellSize); + lc.setCutOffRadius(cutoffRadius); + lc.setDomain(domain); + auto p1 = std::make_shared(std::array{1.0, 0.0, 0.0}, std::array{0, 0, 0}, 1.0, 0.0, 1, 2.5, 5.0); + auto p2 = std::make_shared(std::array{2.0, 0.0, 0.0}, std::array{0, 0, 0}, 1.0, 0.0, 1, 3.5, 5.0); + lc.addParticle(p1); + lc.addParticle(p2); + lc.initializeAndPopulateCells(); + + calculator->calculateLC_F(lc); + + const std::vector> expectedForces = { + {-254916720.0, 0.0, 0.0}, + {254916720.0, 0.0, 0.0} + }; + + int index = 0; + for (auto &particle: lc) { + std::array expectedF = expectedForces[index]; + std::array actualF = particle->getF(); + EXPECT_NEAR(expectedF[0], actualF[0], 1e-3); + EXPECT_NEAR(expectedF[1], actualF[1], 1e-3); + EXPECT_NEAR(expectedF[2], actualF[2], 1e-3); + index++; + } +} + + +TEST(LC_LJCalculatorTest, DifferentEpsilon) { + std::array domain = {12.0, 9.0, 3.0}; + double cutoffRadius = 3.0; + double cellSize = 3.0; + LinkedCellContainer lc; + lc.setCellSize(cellSize); + lc.setCutOffRadius(cutoffRadius); + lc.setDomain(domain); + auto p1 = std::make_shared(std::array{1.0, 0.0, 0.0}, std::array{0, 0, 0}, 1.0, 0.0, 0, 3.0, 2.0); + auto p2 = std::make_shared(std::array{2.0, 0.0, 0.0}, std::array{0, 0, 0}, 1.0, 0.0, 0, 3.0, 12.5); + lc.addParticle(p1); + lc.addParticle(p2); + lc.initializeAndPopulateCells(); + + calculator->calculateLC_F(lc); + + const std::vector> expectedForces = { + {-254916720.0, 0.0, 0.0}, + {254916720.0, 0.0, 0.0} + }; + + int index = 0; + for (auto &particle: lc) { + std::array expectedF = expectedForces[index]; + std::array actualF = particle->getF(); + EXPECT_NEAR(expectedF[0], actualF[0], 1e-3); + EXPECT_NEAR(expectedF[1], actualF[1], 1e-3); + EXPECT_NEAR(expectedF[2], actualF[2], 1e-3); + index++; + } +} diff --git a/tests/calculators/LJCalculatorTest.cpp b/tests/calculators/LJCalculatorTest.cpp index 142ccc9ca..a6b37e07e 100644 --- a/tests/calculators/LJCalculatorTest.cpp +++ b/tests/calculators/LJCalculatorTest.cpp @@ -5,9 +5,7 @@ #include "gtest/gtest.h" namespace { - const double sigma = 1.0; - const double epsilon = 5.0; - const auto calculator = std::make_unique(sigma, epsilon, 5.31608); + const auto calculator = std::make_unique(5.31608); } TEST(LJCalculatorTest, CalculateFTest) { @@ -36,4 +34,57 @@ TEST(LJCalculatorTest, CalculateFTest) { EXPECT_NEAR(expectedF[1], actualF[1], 1e-3); EXPECT_NEAR(expectedF[2], actualF[2], 1e-3); } -} \ No newline at end of file +} + +TEST(LJCalculatorTest, DifferentSigma) { + ParticleContainer pc; + // Particle(std::array x_arg, std::array v_arg, + // double m_arg, double volume_arg, int type_arg, double sig_arg, double eps_arg); + Particle p1{{1.0, 0.0, 0.0}, {0, 0, 0}, 1.0, 0.0, 1, 2.5, 5}; + Particle p2{{2.0, 0.0, 0.0}, {0, 0, 0}, 1.0, 0.0, 1, 3.5, 5}; + + calculator->calculateFPairwise(p1, p2); + + const std::vector> expectedForces = { + {-20000.0, 0.0, 0.0}, + {20000.0, 0.0, 0.0} + }; + pc.addParticle(p1); + pc.addParticle(p2); + + auto it = pc.begin(); + for (size_t i = 0; i < pc.getSize(); ++i, ++it) { + std::array expectedF = expectedForces[i]; + std::array actualF = it->getF(); + EXPECT_NEAR(expectedF[0], actualF[0], 1e-3); + EXPECT_NEAR(expectedF[1], actualF[1], 1e-3); + EXPECT_NEAR(expectedF[2], actualF[2], 1e-3); + } +} + +TEST(LJCalculatorTest, DifferentEpsilon) { + ParticleContainer pc; + // Particle(std::array x_arg, std::array v_arg, + // double m_arg, double volume_arg, int type_arg, double sig_arg, double eps_arg); + Particle p1{{1.0, 0.0, 0.0}, {0, 0, 0}, 1.0, 0.0, 1, 3.0, 2}; + Particle p2{{2.0, 0.0, 0.0}, {0, 0, 0}, 1.0, 0.0, 1, 3.0, 12.5}; + + calculator->calculateFPairwise(p1, p2); + + const std::vector> expectedForces = { + {-20000.0, 0.0, 0.0}, + {20000.0, 0.0, 0.0} + }; + pc.addParticle(p1); + pc.addParticle(p2); + + auto it = pc.begin(); + for (size_t i = 0; i < pc.getSize(); ++i, ++it) { + std::array expectedF = expectedForces[i]; + std::array actualF = it->getF(); + EXPECT_NEAR(expectedF[0], actualF[0], 1e-3); + EXPECT_NEAR(expectedF[1], actualF[1], 1e-3); + EXPECT_NEAR(expectedF[2], actualF[2], 1e-3); + } +} + diff --git a/tests/calculators/ThermostatTest.cpp b/tests/calculators/ThermostatTest.cpp new file mode 100644 index 000000000..116c8ed4f --- /dev/null +++ b/tests/calculators/ThermostatTest.cpp @@ -0,0 +1,83 @@ +// +// Created by kimj2 on 11.06.2024. +// +#include "../../src/calculators/Thermostat.h" +#include "../../src/objects/LinkedCellContainer.h" +#include "../../src/objects/Particle.h" +#include "gtest/gtest.h" + +TEST(ThermostatTest, CalculateCurrentTempTest) { + Thermostat thermostat(0.0, 0.0, 0, 1.0, 3); + LinkedCellContainer linkedCellContainer; + std::array x = {0.0, 0.0, 0.0}; + std::array v = {1.0, 1.0, 1.0}; + auto particle = std::make_shared(x, v, 1.0, 0.0); + linkedCellContainer.addParticle(particle); + + double currentTemp = thermostat.calculateCurrentTemp(linkedCellContainer); + + // The kinetic energy of the particle is 0.5 * m * v^2 = 0.5 * 1 * (1^2 + 1^2 + 1^2) = 1.5 + // So, the current temperature should be 2.0 / (3 * 1) * 1.5 = 1.0 + EXPECT_DOUBLE_EQ(currentTemp, 1.0); +} + +TEST(ThermostatTest, InitializeTempTest) { + const Thermostat thermostat(10.0, 20.0, 1, 1.0, 3); + LinkedCellContainer linkedCellContainer; + const std::array x = {0.0, 0.0, 0.0}; + const std::array v = {0.0, 0.0, 0.0}; // Initial velocities are zero + auto particle1 = std::make_shared(x, v, 1.0, 0.0); + auto particle2 = std::make_shared(x, v, 1.0, 0.0); + linkedCellContainer.addParticle(particle1); + linkedCellContainer.addParticle(particle2); + + thermostat.initializeTemp(linkedCellContainer); + + for (auto &particle: linkedCellContainer) { + const auto &velocities = particle->getV(); + for (int i = 0; i < 3; ++i) { + EXPECT_NE(velocities[i], 0.0); + } + } + + const double currentTemp = thermostat.calculateCurrentTemp(linkedCellContainer); + EXPECT_NEAR(currentTemp, 10.0, 1e-3); +} + +TEST(ThermostatTest, SetTempDirectlyTest) { + const double initialTemp = 10.0; + const double targetTemp = 20.0; + const Thermostat thermostat(initialTemp, targetTemp, 1, 1.0, 3); + LinkedCellContainer linkedCellContainer; + const std::array x = {0.0, 0.0, 0.0}; + const std::array v = {1.0, 1.0, 1.0}; + auto particle = std::make_shared(x, v, 1.0, 0.0); + linkedCellContainer.addParticle(particle); + + thermostat.initializeTemp(linkedCellContainer); + + thermostat.setTempDirectly(linkedCellContainer); + + const double currentTemp = thermostat.calculateCurrentTemp(linkedCellContainer); + EXPECT_NEAR(currentTemp, targetTemp, 1e-3); +} + +TEST(ThermostatTest, SetTempGraduallyTest) { + const double initialTemp = 10.0; + const double targetTemp = 20.0; + const double maxDeltaTemp = 1.0; + const Thermostat thermostat(initialTemp, targetTemp, 1, maxDeltaTemp, 3); + LinkedCellContainer linkedCellContainer; + const std::array x = {0.0, 0.0, 0.0}; + const std::array v = {1.0, 1.0, 1.0}; // Initial velocities set to achieve the initial temperature + auto particle = std::make_shared(x, v, 1.0, 0.0); + linkedCellContainer.addParticle(particle); + + thermostat.initializeTemp(linkedCellContainer); + + thermostat.setTempGradually(linkedCellContainer); + + const double currentTemp = thermostat.calculateCurrentTemp(linkedCellContainer); + const double expectedTemp = initialTemp + maxDeltaTemp; + EXPECT_NEAR(currentTemp, expectedTemp, 1e-3); +} diff --git a/tests/io/in/ParticleGeneratorTest.cpp b/tests/io/in/ParticleGeneratorTest.cpp index 7c0fb03cb..b2943936c 100644 --- a/tests/io/in/ParticleGeneratorTest.cpp +++ b/tests/io/in/ParticleGeneratorTest.cpp @@ -11,14 +11,15 @@ TEST(ParticleContainerTest, GenerateCuboid) { double pDistance = 1.0; double pMass = 1.0; - CuboidParameters parameters{{0.0, 0.0, 0.0}, {2, 2, 1}, pDistance, pMass, {0.0, 0.0, 0.0}, 0.1}; + int dimension = 2; + CuboidParameters parameters{{0.0, 0.0, 0.0}, {2, 2, 1}, pDistance, pMass, {0.0, 0.0, 0.0}, 0.1, dimension, 1.0, 1.0}; ParticleContainer container{}; ParticleGenerator::generateCuboid(parameters, container); EXPECT_EQ(container.getSize(), 4); for (int x = 0; x < 2; x++) { for (int y = 0; y < 2; y++) { Particle particle = container.getParticles()[2 * x + y]; - EXPECT_EQ(particle.getM(), 1.0); + EXPECT_NEAR(particle.getM(), 1.0, 1e-6); std::array expectedPosition = {static_cast(x), static_cast(y), 0.0}; EXPECT_EQ(particle.getX(), expectedPosition); } @@ -32,8 +33,28 @@ TEST(ParticleContainerTest, GenerateParticle) { double m = 1.5; double volume = 2.5; int t = 0; - ParticleParameters parameters{x, v, m, volume, t}; + int dimension = 2; + ParticleParameters parameters{x, v, m, volume, t, dimension}; Particle particle{x, v, m, volume, t}; Particle copy = ParticleGenerator::generateParticle(parameters); EXPECT_EQ(copy, particle); +} + +TEST(ParticleContainerTest, GenerateDisc) { + std::array center = {0.0, 0.0, 0.0}; + std::array startV = {0.0, 0.0, 0.0}; + int numParticlesAlongRadius = 2; + double distanceBetweenParticles = 1.0; + double mass = 1.0; + int dimension = 2; + DiscParameters parameters(center, startV, numParticlesAlongRadius, distanceBetweenParticles, mass, dimension, 1.0, 1.0); + ParticleContainer container{}; + ParticleGenerator::generateDisc(parameters, container); + EXPECT_EQ(container.getSize(), 13); // 13 particles for a disc with radius 2 in 2D + for (auto& particle : container.getParticles()) { + double distanceFromCenter = std::sqrt(std::pow(particle.getX()[0] - center[0], 2) + std::pow(particle.getX()[1] - center[1], 2)); + EXPECT_LE(distanceFromCenter, numParticlesAlongRadius * distanceBetweenParticles); // All particles should be within the disc's radius + EXPECT_EQ(particle.getV(), startV); + EXPECT_NEAR(particle.getM(), mass, 1e-6); + } } \ No newline at end of file diff --git a/tests/io/in/FileReaderTest.cpp b/tests/io/in/TXTReaderTest.cpp similarity index 70% rename from tests/io/in/FileReaderTest.cpp rename to tests/io/in/TXTReaderTest.cpp index ac1c3edfe..3588e6456 100644 --- a/tests/io/in/FileReaderTest.cpp +++ b/tests/io/in/TXTReaderTest.cpp @@ -6,23 +6,32 @@ #include #include -#include "../../../src/io/in/FileReader.h" +#include "../../../src/io/in/TXTReader.h" + +namespace { + const auto fileReader = std::make_unique(); +} //Check if the lines are read correctly and wrong lines are ignored TEST(FileReaderTest, readFileLinesBasicTest) { - FileReader fileReader; std::ofstream testfile("test_file.txt"); - testfile << "3\n" + testfile << "# This should be ignored\n" + << "0\n" // Data code for particles + << "4\n" // Number of data sets << "# This should be ignored\n" + << "2\n" // Dimension of simulation << "Data Set 1\n" << "Data Set 2\n" << "Data Set 3\n"; testfile.close(); - std::vector lines = FileReader::readFileLines("test_file.txt"); - ASSERT_EQ(lines.size(), 4); - EXPECT_EQ(lines[1], "Data Set 1"); - EXPECT_EQ(lines[2], "Data Set 2"); - EXPECT_EQ(lines[3], "Data Set 3"); + std::vector lines = fileReader->readFileLines("test_file.txt"); + ASSERT_EQ(lines.size(), 6); + EXPECT_EQ(lines[0], "0"); + EXPECT_EQ(lines[1], "4"); + EXPECT_EQ(lines[2], "2"); + EXPECT_EQ(lines[3], "Data Set 1"); + EXPECT_EQ(lines[4], "Data Set 2"); + EXPECT_EQ(lines[5], "Data Set 3"); // Delete the temporary file std::remove("test_file.txt"); @@ -30,24 +39,22 @@ TEST(FileReaderTest, readFileLinesBasicTest) { // Test case for reading particles from a file TEST(ReadFileTest, ReadParticlesFromFile) { - // Create a temporary file with particle data std::ofstream outfile("test_particles.txt"); outfile << "0\n" // Data code for particles << "4\n" // Number of data sets + << "2\n" // Dimension of simulation << "0.0 0.0 0.0 0.0 0.0 0.0 1.0\n" << "0.0 1.0 0.0 -1.0 0.0 0.0 3.0e-6\n" << "0.0 5.36 0.0 -0.425 0.0 0.0 9.55e-4\n" << "34.75 0.0 0.0 0.0 0.0296 0.0 1.0e-14\n"; outfile.close(); - // Read particle data from the file - ParticleContainer particleContainer = FileReader::readFile("test_particles.txt"); + SimulationDataContainer simulationDataContainer = fileReader->readFile("test_particles.txt"); + ParticleContainer particleContainer = *simulationDataContainer.getParticleContainer(); - // Check if the particles are loaded correctly ASSERT_EQ(particleContainer.getSize(), 4); std::vector container = particleContainer.getParticles(); - // Define expected positions, velocities, and masses std::array, 4> expectedPositions = { {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, @@ -64,35 +71,31 @@ TEST(ReadFileTest, ReadParticlesFromFile) { std::array expectedMasses = {1.0, 3.0e-6, 9.55e-4, 1.0e-14}; - // Loop through particles and perform assertions for (size_t i = 0; i < container.size(); ++i) { ASSERT_EQ(container[i].getX(), expectedPositions[i]); ASSERT_EQ(container[i].getV(), expectedVelocities[i]); ASSERT_EQ(container[i].getM(), expectedMasses[i]); } - // Delete the temporary file std::remove("test_particles.txt"); } // Test case for reading cuboids from a file TEST(ReadFileTest, ReadCuboidsFromFile) { - // Create a temporary file with cuboid data std::ofstream outfile("test_cuboids.txt"); outfile << "1\n" // Data code for cuboids << "2\n" // Number of data sets + << "2\n" // Dimension of simulation << "0.0 0.0 0.0 2 2 1 1.0 1.0 0.0 0.0 0.0 0.1\n" << "-10.0 -10.0 0.0 3 3 1 1.0 1.0 0.0 -10.0 0.0 0.1\n"; outfile.close(); - // Read cuboid data from the file - ParticleContainer particleContainer = FileReader::readFile("test_cuboids.txt"); + SimulationDataContainer simulationDataContainer = fileReader->readFile("test_cuboids.txt"); + ParticleContainer particleContainer = *simulationDataContainer.getParticleContainer(); - // Check if the cuboids are loaded correctly ASSERT_EQ(particleContainer.getSize(), 13); std::vector particles = particleContainer.getParticles(); - // Position check & Mass check double mass = 1.0; std::array, 13> expectedPositions = { {{0.0, 0.0, 0.0}, @@ -115,62 +118,36 @@ TEST(ReadFileTest, ReadCuboidsFromFile) { ASSERT_EQ(particles[i].getM(), mass); } - // Delete the temporary file std::remove("test_cuboids.txt"); } // Test case for handling empty file TEST(ReadFileTest, EmptyFile) { - // Create an empty temporary file std::ofstream outfile("empty_file.txt"); outfile.close(); - // Test whether the method throws an exception for an empty file - ASSERT_THROW(FileReader().readFile("empty_file.txt"), std::runtime_error); + ASSERT_THROW(fileReader->readFile("empty_file.txt"), std::runtime_error); - // Delete the temporary file std::remove("empty_file.txt"); } -// Test case for handling invalid data code -TEST(ReadFileTest, InvalidDataCode) { - // Create a temporary file with an invalid data code - std::ofstream outfile("invalid_data_code.txt"); - outfile << "2\n"; // Invalid data code - outfile.close(); - - // Test whether the method throws an exception for an invalid data code - ASSERT_THROW(FileReader().readFile("invalid_data_code.txt"), std::runtime_error); - - // Delete the temporary file - std::remove("invalid_data_code.txt"); -} - // Test case for FileReader::loadParticles method TEST(FileReaderTest, LoadParticles) { - // Prepare input data std::vector lines = { "4", // Number of particles + "2", // Dimension of simulation "0.0 0.0 0.0 0.0 0.0 0.0 1.0", "0.0 1.0 0.0 -1.0 0.0 0.0 3.0e-6", "0.0 5.36 0.0 -0.425 0.0 0.0 9.55e-4", "34.75 0.0 0.0 0.0 0.0296 0.0 1.0e-14" }; - // Create a FileReader object - FileReader fileReader; - - // Create a ParticleContainer object ParticleContainer particleContainer; + fileReader->loadParticles(lines, particleContainer); - // Call the loadParticles method - FileReader::loadParticles(lines, particleContainer); - - // Check if the particles are loaded correctly ASSERT_EQ(particleContainer.getSize(), 4); std::vector particles = particleContainer.getParticles(); - // Check particle parameters std::array, 4> expectedPositions = { {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, @@ -187,14 +164,11 @@ TEST(FileReaderTest, LoadParticles) { std::array expectedMasses = {1.0, 3.0e-6, 9.55e-4, 1.0e-14}; - // Loop through particles and perform assertions for (size_t i = 0; i < particles.size(); ++i) { - // Get particle parameters std::array xPos = particles[i].getX(); std::array vPos = particles[i].getV(); double mass = particles[i].getM(); - // Compare with expected values ASSERT_EQ(xPos, expectedPositions[i]); ASSERT_EQ(vPos, expectedVelocities[i]); ASSERT_EQ(mass, expectedMasses[i]); @@ -206,24 +180,17 @@ TEST(FileReaderTest, LoadCuboids) { // Prepare input data std::vector lines = { "2", // Number of cuboids + "2", // Dimension of simulation "0.0 0.0 0.0 2 2 1 1.0 1.0 0.0 0.0 0.0 0.1", "-10.0 -10.0 0.0 3 3 1 1.0 1.0 0.0 -10.0 0.0 0.1" }; - // Create a FileReader object - FileReader fileReader; - - // Create a ParticleContainer object ParticleContainer particleContainer; + fileReader->loadCuboids(lines, particleContainer); - // Call the loadCuboids method - FileReader::loadCuboids(lines, particleContainer); - - // Check if the particles are loaded correctly ASSERT_EQ(particleContainer.getSize(), 13); std::vector particles = particleContainer.getParticles(); - // Define expected positions and mass double expectedMass = 1.0; std::array, 13> expectedPositions = { {{0.0, 0.0, 0.0}, @@ -241,14 +208,36 @@ TEST(FileReaderTest, LoadCuboids) { {-8.0, -8.0, 0.0}} }; - // Loop through particles and perform assertions for (size_t i = 0; i < particles.size(); ++i) { - // Get particle parameters std::array xPos = particles[i].getX(); double mass = particles[i].getM(); - // Compare with expected values ASSERT_EQ(xPos, expectedPositions[i]); ASSERT_EQ(mass, expectedMass); } +} + +// Test case for FileReader::loadDiscs method +TEST(FileReaderTest, LoadDiscs) { + std::vector lines = { + "1", // Number of discs + "2", // Dimension of simulation + "0.0 0.0 0.0 0.0 0.0 0.0 2 1.0 1.0 2" // Disc parameters + }; + + ParticleContainer particleContainer; + fileReader->loadDiscs(lines, particleContainer); + + ASSERT_EQ(particleContainer.getSize(), 13); // 13 particles for a disc with radius 2 in 2D + std::vector particles = particleContainer.getParticles(); + + double expectedMass = 1.0; + std::array expectedVelocity = {0.0, 0.0, 0.0}; + + for (auto& particle : particles) { + double distanceFromCenter = std::sqrt(std::pow(particle.getX()[0], 2) + std::pow(particle.getX()[1], 2)); + ASSERT_LE(distanceFromCenter, 2.0); // All particles should be within the disc's radius + ASSERT_EQ(particle.getV(), expectedVelocity); + ASSERT_EQ(particle.getM(), expectedMass); + } } \ No newline at end of file diff --git a/tests/io/in/XMLReaderTest.cpp b/tests/io/in/XMLReaderTest.cpp new file mode 100644 index 000000000..fb375b2c2 --- /dev/null +++ b/tests/io/in/XMLReaderTest.cpp @@ -0,0 +1,121 @@ +// +// Created by kimj2 on 15.06.2024. +// +#include +#include +#include "../../../src/io/in/XMLReader.h" + +const double COMPARISON_TOLERANCE = 1e-6; +constexpr const char* XML_READER_TEST_PATH = ".././tests/io/in/"; + +TEST(XMLReaderTest, ReadCuboidFileTest) { + const auto fileReader = std::make_unique(); + std::string filePath = std::string(XML_READER_TEST_PATH) + "XMLReaderTestCuboid.xml"; + SimulationDataContainer data = fileReader->readFile(filePath); + + EXPECT_EQ(data.getFileWriterParameters()->getBaseName(), "testCuboid"); + EXPECT_EQ(data.getFileWriterParameters()->getWriteFrequency(), 10); + + EXPECT_NEAR(data.getSimulationParameters()->getEnd_t(), 100.0, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getSimulationParameters()->getDelta_t(), 0.1, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getSimulationParameters()->getGravity(), 0.0, COMPARISON_TOLERANCE); + EXPECT_EQ(data.getSimulationParameters()->getDimension(), 2); + + EXPECT_NEAR(data.getThermostatParameters()->getStartTemp(), 300.0, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getThermostatParameters()->getTargetTemp(), 300.0, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getThermostatParameters()->getMaxDeltaTemp(), 10.0, COMPARISON_TOLERANCE); + EXPECT_EQ(data.getThermostatParameters()->getDimension(), 3); + + EXPECT_EQ(data.getLinkedCellsParameters()->isLinkedCellsUsed(), false); + EXPECT_NEAR(data.getLinkedCellsParameters()->getCutOffRadius(), 3.0, COMPARISON_TOLERANCE); + + auto boundaryMap = data.getBoundaryParameters()->getBoundaryMap(); + EXPECT_NEAR(data.getBoundaryParameters()->getDomain()[0], 180.0, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getBoundaryParameters()->getDomain()[1], 90.0, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getBoundaryParameters()->getDomain()[2], 3.0, COMPARISON_TOLERANCE); + EXPECT_EQ(boundaryMap[boundaries::BoundaryDirection::TOP], boundaries::BoundaryType::REFLECTING); + EXPECT_EQ(boundaryMap[boundaries::BoundaryDirection::RIGHT], boundaries::BoundaryType::OUTFLOW); + EXPECT_EQ(boundaryMap[boundaries::BoundaryDirection::BOTTOM], boundaries::BoundaryType::REFLECTING); + EXPECT_EQ(boundaryMap[boundaries::BoundaryDirection::LEFT], boundaries::BoundaryType::PERIODIC); + EXPECT_EQ(boundaryMap[boundaries::BoundaryDirection::FRONT], boundaries::BoundaryType::OFF); + EXPECT_EQ(boundaryMap[boundaries::BoundaryDirection::BACK], boundaries::BoundaryType::OFF); + + EXPECT_EQ(data.getParticleContainer()->getSize(), 125); + EXPECT_EQ(data.getLinkedCellContainer()->getSize(), 0); +} + +TEST(XMLReaderTest, ReadCuboidFileLCTest) { + const auto fileReader = std::make_unique(); + std::string filePath = std::string(XML_READER_TEST_PATH) + "XMLReaderTestLCCuboid.xml"; + SimulationDataContainer data = fileReader->readFile(filePath); + + EXPECT_EQ(data.getFileWriterParameters()->getBaseName(), "testCuboid"); + EXPECT_EQ(data.getFileWriterParameters()->getWriteFrequency(), 10); + + EXPECT_NEAR(data.getSimulationParameters()->getEnd_t(), 100.0, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getSimulationParameters()->getDelta_t(), 0.1, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getSimulationParameters()->getGravity(), -9.81, COMPARISON_TOLERANCE); + EXPECT_EQ(data.getSimulationParameters()->getDimension(), 2); + + EXPECT_NEAR(data.getThermostatParameters()->getStartTemp(), 300.0, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getThermostatParameters()->getTargetTemp(), 300.0, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getThermostatParameters()->getMaxDeltaTemp(), 10.0, COMPARISON_TOLERANCE); + EXPECT_EQ(data.getThermostatParameters()->getDimension(), 3); + + EXPECT_EQ(data.getLinkedCellsParameters()->isLinkedCellsUsed(), true); + EXPECT_NEAR(data.getLinkedCellsParameters()->getCutOffRadius(), 3.0, COMPARISON_TOLERANCE); + + auto boundaryMap = data.getBoundaryParameters()->getBoundaryMap(); + EXPECT_NEAR(data.getBoundaryParameters()->getDomain()[0], 180.0, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getBoundaryParameters()->getDomain()[1], 90.0, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getBoundaryParameters()->getDomain()[2], 3.0, COMPARISON_TOLERANCE); + EXPECT_EQ(boundaryMap[boundaries::BoundaryDirection::TOP], boundaries::BoundaryType::REFLECTING); + EXPECT_EQ(boundaryMap[boundaries::BoundaryDirection::RIGHT], boundaries::BoundaryType::OUTFLOW); + EXPECT_EQ(boundaryMap[boundaries::BoundaryDirection::BOTTOM], boundaries::BoundaryType::REFLECTING); + EXPECT_EQ(boundaryMap[boundaries::BoundaryDirection::LEFT], boundaries::BoundaryType::PERIODIC); + EXPECT_EQ(boundaryMap[boundaries::BoundaryDirection::FRONT], boundaries::BoundaryType::OFF); + EXPECT_EQ(boundaryMap[boundaries::BoundaryDirection::BACK], boundaries::BoundaryType::OFF); + + EXPECT_EQ(data.getParticleContainer()->getSize(), 0); + EXPECT_EQ(data.getLinkedCellContainer()->getSize(), 25); + EXPECT_NEAR(data.getLinkedCellContainer()->getParticles()[0]->getSigma(), 1.0, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getLinkedCellContainer()->getParticles()[0]->getEpsilon(), 1.0, COMPARISON_TOLERANCE); +} + +TEST(XMLReaderTest, ReadDiscFileLCTest) { + const auto fileReader = std::make_unique(); + std::string filePath = std::string(XML_READER_TEST_PATH) + "XMLReaderTestLCDisc.xml"; + SimulationDataContainer data = fileReader->readFile(filePath); + + EXPECT_EQ(data.getFileWriterParameters()->getBaseName(), "testDisc"); + EXPECT_EQ(data.getFileWriterParameters()->getWriteFrequency(), 10); + + EXPECT_NEAR(data.getSimulationParameters()->getEnd_t(), 100.0, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getSimulationParameters()->getDelta_t(), 0.1, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getSimulationParameters()->getGravity(), -9.81, COMPARISON_TOLERANCE); + EXPECT_EQ(data.getSimulationParameters()->getDimension(), 2); + + EXPECT_NEAR(data.getThermostatParameters()->getStartTemp(), 300.0, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getThermostatParameters()->getTargetTemp(), 300.0, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getThermostatParameters()->getMaxDeltaTemp(), 10.0, COMPARISON_TOLERANCE); + EXPECT_EQ(data.getThermostatParameters()->getDimension(), 3); + + EXPECT_EQ(data.getLinkedCellsParameters()->isLinkedCellsUsed(), true); + EXPECT_NEAR(data.getLinkedCellsParameters()->getCutOffRadius(), 3.0, COMPARISON_TOLERANCE); + + auto boundaryMap = data.getBoundaryParameters()->getBoundaryMap(); + EXPECT_NEAR(data.getBoundaryParameters()->getDomain()[0], 180.0, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getBoundaryParameters()->getDomain()[1], 90.0, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getBoundaryParameters()->getDomain()[2], 3.0, COMPARISON_TOLERANCE); + EXPECT_EQ(boundaryMap[boundaries::BoundaryDirection::TOP], boundaries::BoundaryType::REFLECTING); + EXPECT_EQ(boundaryMap[boundaries::BoundaryDirection::RIGHT], boundaries::BoundaryType::OUTFLOW); + EXPECT_EQ(boundaryMap[boundaries::BoundaryDirection::BOTTOM], boundaries::BoundaryType::REFLECTING); + EXPECT_EQ(boundaryMap[boundaries::BoundaryDirection::LEFT], boundaries::BoundaryType::PERIODIC); + EXPECT_EQ(boundaryMap[boundaries::BoundaryDirection::FRONT], boundaries::BoundaryType::OFF); + EXPECT_EQ(boundaryMap[boundaries::BoundaryDirection::BACK], boundaries::BoundaryType::OFF); + + EXPECT_EQ(data.getParticleContainer()->getSize(), 0); + EXPECT_EQ(data.getLinkedCellContainer()->getSize(), 709); + EXPECT_NEAR(data.getLinkedCellContainer()->getParticles()[0]->getSigma(), 1.0, COMPARISON_TOLERANCE); + EXPECT_NEAR(data.getLinkedCellContainer()->getParticles()[0]->getEpsilon(), 1.0, COMPARISON_TOLERANCE); +} \ No newline at end of file diff --git a/tests/io/in/XMLReaderTestCuboid.xml b/tests/io/in/XMLReaderTestCuboid.xml new file mode 100644 index 000000000..9b75bfa0e --- /dev/null +++ b/tests/io/in/XMLReaderTestCuboid.xml @@ -0,0 +1,42 @@ + + + testCuboid + 10 + + + 100.0 + 0.1 + 2 + + + 300.0 + 300.0 + 100 + 10.0 + 3 + + + false + 3.0 + + + 180.0 90.0 3.0 + REFLECTING + OUTFLOW + REFLECTING + PERIODIC + OFF + OFF + + + 0.0 0.0 0.0 + 5 5 5 + 1.0 + 1.0 + 0.0 0.0 0.0 + 0.0 + 1.0 + 1.0 + + \ No newline at end of file diff --git a/tests/io/in/XMLReaderTestLCCuboid.xml b/tests/io/in/XMLReaderTestLCCuboid.xml new file mode 100644 index 000000000..41b32c8fd --- /dev/null +++ b/tests/io/in/XMLReaderTestLCCuboid.xml @@ -0,0 +1,43 @@ + + + testCuboid + 10 + + + 100.0 + 0.1 + -9.81 + 2 + + + 300.0 + 300.0 + 100 + 10.0 + 3 + + + true + 3.0 + + + 180.0 90.0 3.0 + REFLECTING + OUTFLOW + REFLECTING + PERIODIC + OFF + OFF + + + 0.0 0.0 0.0 + 5 5 1 + 1.0 + 1.0 + 0.0 0.0 0.0 + 0.0 + 1.0 + 1.0 + + \ No newline at end of file diff --git a/tests/io/in/XMLReaderTestLCDisc.xml b/tests/io/in/XMLReaderTestLCDisc.xml new file mode 100644 index 000000000..01298713d --- /dev/null +++ b/tests/io/in/XMLReaderTestLCDisc.xml @@ -0,0 +1,42 @@ + + + testDisc + 10 + + + 100.0 + 0.1 + -9.81 + 2 + + + 300.0 + 300.0 + 100 + 10.0 + 3 + + + true + 3.0 + + + 180.0 90.0 3.0 + REFLECTING + OUTFLOW + REFLECTING + PERIODIC + OFF + OFF + + + 60.0 25.0 0.0 + 0.0 -10.0 0.0 + 15 + 1.1225 + 1.0 + 1.0 + 1.0 + + \ No newline at end of file diff --git a/tests/objects/LinkedCellContainerTest.cpp b/tests/objects/LinkedCellContainerTest.cpp new file mode 100644 index 000000000..9b23908fe --- /dev/null +++ b/tests/objects/LinkedCellContainerTest.cpp @@ -0,0 +1,136 @@ +#include "../../src/objects/LinkedCellContainer.h" +#include "../../src/objects/Particle.h" +#include "gtest/gtest.h" + +TEST(LinkedCellContainerTest, AddParticleGetSize) { + LinkedCellContainer lc; + EXPECT_EQ(lc.getSize(), 0); + + auto p1 = std::make_shared(); + auto p2 = std::make_shared(); + lc.addParticle(p1); + lc.addParticle(p2); + EXPECT_EQ(lc.getSize(), 2); +} + +TEST(LinkedCellContainerTest, IterateThroughParticles) { + LinkedCellContainer lc_0; + for (auto it = lc_0.begin(); it != lc_0.end(); ++it) { + FAIL() << "Loop should not run with 0 particles"; + } + + LinkedCellContainer lc_1; + auto p1 = std::make_shared(1); + lc_1.addParticle(p1); + + int expected_types_1[] = {1}; + int index_1 = 0; + for (auto &particle: lc_1) { + EXPECT_EQ(particle->getType(), expected_types_1[index_1]); + } + + LinkedCellContainer lc_2; + auto p2 = std::make_shared(2); + lc_2.addParticle(p1); + lc_2.addParticle(p2); + + int expected_types_2[] = {1, 2}; + int index_2 = 0; + for (auto &particle: lc_2) { + EXPECT_EQ(particle->getType(), expected_types_2[index_2]); + ++index_2; + } +} + +TEST(LinkedCellContainerTest, RemoveParticleGetSize) { + std::array domain = {12.0, 9.0, 3.0}; + double cutoffRadius = 3.0; + double cellSize = 3.0; + + LinkedCellContainer lc; + lc.setCellSize(cellSize); + lc.setCutOffRadius(cutoffRadius); + lc.setDomain(domain); + + auto p1 = std::make_shared(); + auto p2 = std::make_shared(); + lc.addParticle(p1); + lc.addParticle(p2); + lc.initializeCells(); + lc.initializeNeighbors(); + lc.populateCells(); + EXPECT_EQ(lc.getSize(), 2); + + auto cellIndexP1 = lc.getCellIndex(p1->getX()); + auto cellP1 = lc.getCells()[cellIndexP1[0]][cellIndexP1[1]][cellIndexP1[2]]; + const int numParticlesInCellP1Before = cellP1->getParticles().size(); + lc.removeParticle(p1); + const int numParticlesInCellP1After = cellP1->getParticles().size(); + EXPECT_EQ(lc.getSize(), 1); + EXPECT_EQ(numParticlesInCellP1After, numParticlesInCellP1Before - 1); + + auto cellIndexP2 = lc.getCellIndex(p2->getX()); + auto cellP2 = lc.getCells()[cellIndexP2[0]][cellIndexP2[1]][cellIndexP2[2]]; + const int numParticlesInCellP2Before = cellP2->getParticles().size(); + lc.removeParticle(p2); + const int numParticlesInCellP2After = cellP2->getParticles().size(); + EXPECT_EQ(lc.getSize(), 0); + EXPECT_EQ(numParticlesInCellP2After, numParticlesInCellP2Before - 1); +} + +TEST(LinkedCellContainerTest, CheckParticlePositionInCells) { + std::array domain = {12.0, 9.0, 3.0}; + double cutoffRadius = 3.0; + double cellSize = 3.0; + + LinkedCellContainer lc; + lc.setCellSize(cellSize); + lc.setCutOffRadius(cutoffRadius); + lc.setDomain(domain); + + auto p1 = std::make_shared(1); + p1->setX({1.5, 1.5, 1.5}); + lc.addParticle(p1); + lc.initializeCells(); + lc.initializeNeighbors(); + lc.populateCells(); + + auto cellIndex = lc.getCellIndex(p1->getX()); + auto cell = lc.getCells()[cellIndex[0]][cellIndex[1]][cellIndex[2]]; + auto particlesInCell = cell->getParticles(); + + EXPECT_EQ(particlesInCell.size(), 1); + EXPECT_EQ(particlesInCell.begin()->get()->getType(), 1); +} + +TEST(LinkedCellContainerTest, GetBoundaryCellsTest) { + std::array domain = {4.0, 4.0, 1.0}; + double cutoffRadius = 1.0; + double cellSize = 1.0; + + LinkedCellContainer lc; + lc.setCellSize(cellSize); + lc.setCutOffRadius(cutoffRadius); + lc.setDomain(domain); + lc.initializeCells(); + lc.initializeNeighbors(); + lc.populateCells(); + + size_t boundaryWidthInNumCells = 1; + auto boundaryCells = lc.getBoundaryCells(boundaryWidthInNumCells); + + size_t expectedSize = 12; + EXPECT_EQ(boundaryCells.size(), expectedSize); + + std::set> expectedIndexes = { + {0, 0, 0}, {0, 1, 0}, {0, 2, 0}, {0, 3, 0}, + {1, 0, 0}, {1, 3, 0}, + {2, 0, 0}, {2, 3, 0}, + {3, 0, 0}, {3, 1, 0}, {3, 2, 0}, {3, 3, 0} + }; + + for (const auto& cell : boundaryCells) { + auto cellIndex = cell->getIndex(); + ASSERT_TRUE(expectedIndexes.count(cellIndex) > 0); // cellIndex is present in the expectedIndexes + } +}