From 49f05657b11fc0188679bf9a8bf9b38d250e68ed Mon Sep 17 00:00:00 2001 From: Sam Reeve <6740307+streeve@users.noreply.github.com> Date: Mon, 14 Aug 2023 09:44:13 -0400 Subject: [PATCH] Convert Inputs class to json; Library is now header only --- src/CMakeLists.txt | 8 +-- src/CabanaPD_Input.cpp | 141 ---------------------------------------- src/CabanaPD_Input.hpp | 75 +++++++++++++++------ src/CabanaPD_Solver.hpp | 49 ++++++++------ 4 files changed, 86 insertions(+), 187 deletions(-) delete mode 100644 src/CabanaPD_Input.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8c07f9f8..970423d8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,17 +2,15 @@ configure_file(CabanaPD_config.hpp.cmakein CabanaPD_config.hpp @ONLY) file(GLOB HEADERS GLOB *.hpp) -file(GLOB SOURCES *.cpp) - install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/CabanaPD_config.hpp DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) -add_library(CabanaPD ${SOURCES}) +add_library(CabanaPD INTERFACE) -target_include_directories(CabanaPD PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} +target_include_directories(CabanaPD INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} $ $) -target_link_libraries(CabanaPD Cabana::cabanacore Cabana::Cajita nlohmann_json::nlohmann_json) +target_link_libraries(CabanaPD INTERFACE Cabana::cabanacore Cabana::Cajita nlohmann_json::nlohmann_json) install(TARGETS CabanaPD DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/src/CabanaPD_Input.cpp b/src/CabanaPD_Input.cpp deleted file mode 100644 index 9a01e2c6..00000000 --- a/src/CabanaPD_Input.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/**************************************************************************** - * Copyright (c) 2022 by Oak Ridge National Laboratory * - * All rights reserved. * - * * - * This file is part of CabanaPD. CabanaPD is distributed under a * - * BSD 3-clause license. For the licensing terms see the LICENSE file in * - * the top-level directory. * - * * - * SPDX-License-Identifier: BSD-3-Clause * - ****************************************************************************/ - -/**************************************************************************** - * Copyright (c) 2018-2021 by the Cabana authors * - * All rights reserved. * - * * - * This file is part of the Cabana library. Cabana is distributed under a * - * BSD 3-clause license. For the licensing terms see the LICENSE file in * - * the top-level directory. * - * * - * SPDX-License-Identifier: BSD-3-Clause * - ****************************************************************************/ - -//************************************************************************ -// ExaMiniMD v. 1.0 -// Copyright (2018) National Technology & Engineering Solutions of Sandia, -// LLC (NTESS). -// -// Under the terms of Contract DE-NA-0003525 with NTESS, the U.S. Government -// retains certain rights in this software. -// -// ExaMiniMD is licensed under 3-clause BSD terms of use: Redistribution and -// use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the Corporation nor the names of the contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -// IN NO EVENT SHALL NTESS OR THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -//************************************************************************ - -#include - -#include - -#include -#include - -namespace CabanaPD -{ - -// FIXME: hardcoded. -Inputs::Inputs( const std::array nc, std::array lc, - std::array hc, const double t_f, const double dt, - const int of ) - : num_cells( nc ) - , low_corner( lc ) - , high_corner( hc ) - , final_time( t_f ) - , timestep( dt ) - , output_frequency( of ) -{ - num_steps = final_time / timestep; -} - -Inputs::~Inputs() {} - -void Inputs::read_args( int argc, char* argv[] ) -{ - for ( int i = 1; i < argc; i++ ) - { - // Help command. - if ( ( strcmp( argv[i], "-h" ) == 0 ) || - ( strcmp( argv[i], "--help" ) == 0 ) ) - { - if ( print_rank() ) - { - log( std::cout, "CabanaPD\n", "Options:" ); - log( std::cout, - " -o [FILE] (OR)\n" - " --output-file [FILE]: Provide output file name\n" ); - log( std::cout, - " -e [FILE] (OR)\n" - " --error-file [FILE]: Provide error file name\n" ); - /* Not yet enabled. - log( - std::cout, - " --device-type [TYPE]: Kokkos device type to run ", - "with\n", - " (SERIAL, PTHREAD, OPENMP, " - "CUDA, HIP)" ); - */ - } - } - // Output file names. - else if ( ( strcmp( argv[i], "-o" ) == 0 ) || - ( strcmp( argv[i], "--output-file" ) == 0 ) ) - { - output_file = argv[i + 1]; - ++i; - } - else if ( ( strcmp( argv[i], "-e" ) == 0 ) || - ( strcmp( argv[i], "--error-file" ) == 0 ) ) - { - error_file = argv[i + 1]; - ++i; - } - - // Kokkos device type. - else if ( ( strcmp( argv[i], "--device-type" ) == 0 ) ) - { - device_type = argv[i + 1]; - ++i; - } - - else if ( ( strstr( argv[i], "--kokkos-" ) == NULL ) ) - { - log_err( std::cout, "Unknown command line argument: ", argv[i] ); - } - } -} - -} // namespace CabanaPD diff --git a/src/CabanaPD_Input.hpp b/src/CabanaPD_Input.hpp index aaaa022b..61f9c679 100644 --- a/src/CabanaPD_Input.hpp +++ b/src/CabanaPD_Input.hpp @@ -12,34 +12,69 @@ #ifndef INPUTS_H #define INPUTS_H +#include +#include #include +#include + namespace CabanaPD { class Inputs { public: - std::string output_file = "cabanaPD.out"; - std::string error_file = "cabanaPD.err"; - std::string device_type = "SERIAL"; - - std::array num_cells; - std::array low_corner; - std::array high_corner; - - std::size_t num_steps; - double final_time; - double timestep; - int output_frequency; - - bool half_neigh = false; - - Inputs( const std::array nc, std::array lc, - std::array hc, const double t_f, const double dt, - const int output_freq ); - ~Inputs(); - void read_args( int argc, char* argv[] ); + Inputs( const std::string filename ) + { + // Get user inputs. + inputs = parse( filename ); + + // Add additional derived inputs to json. System size. + std::array size = inputs["system_size"]; + inputs["low_corner"] = { -0.5 * size[0], -0.5 * size[1], + -0.5 * size[2] }; + inputs["high_corner"] = { 0.5 * size[0], 0.5 * size[1], 0.5 * size[2] }; + + // Number of steps. + double tf = inputs["final_time"]; + double dt = inputs["timestep"]; + int num_steps = tf / dt; + inputs["num_steps"] = num_steps; + + // Output files. + if ( !inputs.contains( "output_file" ) ) + inputs["output_file"] = "cabanaPD.out"; + if ( !inputs.contains( "error_file" ) ) + inputs["error_file"] = "cabanaPD.err"; + inputs["input_file"] = filename; + + // Save inputs (including derived) to new file. + std::string input_file = "cabanaPD.in.json"; + if ( !inputs.contains( "exported_input_file" ) ) + inputs["exported_input_file"] = input_file; + std::ofstream in( input_file ); + in << inputs; + + // Not yet a user option. + inputs["half_neigh"] = false; + } + ~Inputs() {} + + // Parse JSON file. + inline nlohmann::json parse( const std::string& filename ) + { + std::ifstream stream( filename ); + return nlohmann::json::parse( stream ); + } + + // Get a single input. + auto operator[]( std::string label ) { return inputs[label]; } + + // Check a key exists. + bool contains( std::string label ) { return inputs.contains( label ); } + + protected: + nlohmann::json inputs; }; } // namespace CabanaPD diff --git a/src/CabanaPD_Solver.hpp b/src/CabanaPD_Solver.hpp index 1d9c7a69..f1b5c94e 100644 --- a/src/CabanaPD_Solver.hpp +++ b/src/CabanaPD_Solver.hpp @@ -110,8 +110,8 @@ class SolverElastic SolverElastic( Inputs _inputs, std::shared_ptr _particles, force_model_type force_model ) - : particles( _particles ) - , inputs( std::make_shared( _inputs ) ) + : inputs( _inputs ) + , particles( _particles ) { force_time = 0; integrate_time = 0; @@ -122,12 +122,13 @@ class SolverElastic total_timer.reset(); init_timer.reset(); - num_steps = inputs->num_steps; - output_frequency = inputs->output_frequency; + num_steps = inputs["num_steps"]; + output_frequency = inputs["output_frequency"]; // Create integrator. // FIXME: hardcoded. - integrator = std::make_shared( inputs->timestep, 1.0 ); + dt = inputs["timestep"]; + integrator = std::make_shared( dt, 1.0 ); // Add ghosts from other MPI ranks. comm = std::make_shared( *particles ); @@ -146,7 +147,8 @@ class SolverElastic int max_neighbors = Cabana::NeighborList::maxNeighbor( *neighbors ); - force = std::make_shared( inputs->half_neigh, force_model ); + force = + std::make_shared( inputs["half_neigh"], force_model ); print = print_rank(); if ( print ) @@ -155,8 +157,10 @@ class SolverElastic ", Maximum local neighbors: ", max_neighbors ); log( std::cout, "#Timestep/Total-steps Simulation-time" ); - std::ofstream out( inputs->output_file, std::ofstream::app ); - std::ofstream err( inputs->error_file, std::ofstream::app ); + output_file = inputs["output_file"]; + std::ofstream out( output_file, std::ofstream::app ); + error_file = inputs["error_file"]; + std::ofstream err( error_file, std::ofstream::app ); auto time = std::chrono::system_clock::to_time_t( std::chrono::system_clock::now() ); @@ -236,8 +240,7 @@ class SolverElastic neigh_iter_tag() ); step_output( step, W ); - particles->output( step / output_frequency, - step * inputs->timestep ); + particles->output( step / output_frequency, step * dt ); } other_time += other_timer.seconds(); } @@ -249,7 +252,7 @@ class SolverElastic void init_output() { // Output after construction and initial forces. - std::ofstream out( inputs->output_file, std::ofstream::app ); + std::ofstream out( output_file, std::ofstream::app ); log( out, "Init-Time(s): ", init_time, "\n" ); log( out, "#Timestep/Total-steps Simulation-time Total-strain-energy " "Run-Time(s) Force-Time(s) Comm-Time(s) Int-Time(s) " @@ -260,18 +263,18 @@ class SolverElastic { if ( print ) { - std::ofstream out( inputs->output_file, std::ofstream::app ); + std::ofstream out( output_file, std::ofstream::app ); log( std::cout, step, "/", num_steps, " ", std::scientific, - std::setprecision( 2 ), step * inputs->timestep ); + std::setprecision( 2 ), step * dt ); total_time = total_timer.seconds(); double rate = 1.0 * particles->n_global * output_frequency / ( total_time - last_time ); log( out, std::fixed, std::setprecision( 6 ), step, "/", num_steps, - " ", std::scientific, std::setprecision( 2 ), - step * inputs->timestep, " ", W, " ", std::fixed, total_time, - " ", force_time, " ", comm_time, " ", integrate_time, " ", - other_time, " ", std::scientific, rate ); + " ", std::scientific, std::setprecision( 2 ), step * dt, " ", + W, " ", std::fixed, total_time, " ", force_time, " ", + comm_time, " ", integrate_time, " ", other_time, " ", + std::scientific, rate ); last_time = total_time; out.close(); } @@ -281,7 +284,7 @@ class SolverElastic { if ( print ) { - std::ofstream out( inputs->output_file, std::ofstream::app ); + std::ofstream out( output_file, std::ofstream::app ); total_time = total_timer.seconds(); double steps_per_sec = 1.0 * num_steps / total_time; double p_steps_per_sec = particles->n_global * steps_per_sec; @@ -304,15 +307,19 @@ class SolverElastic int num_steps; int output_frequency; + double dt; protected: + Inputs inputs; std::shared_ptr particles; - std::shared_ptr inputs; std::shared_ptr comm; std::shared_ptr integrator; std::shared_ptr force; std::shared_ptr neighbors; + std::string output_file; + std::string error_file; + double total_time; double force_time; double integrate_time; @@ -445,8 +452,7 @@ class SolverFracture neigh_iter_tag() ); this->step_output( step, W ); - particles->output( step / output_frequency, - step * inputs->timestep ); + particles->output( step / output_frequency, step * dt ); } other_time += other_timer.seconds(); } @@ -455,6 +461,7 @@ class SolverFracture this->final_output(); } + using base_type::dt; using base_type::num_steps; using base_type::output_frequency;