From 57486d7f2b8e9271695ac28481423d4eac5deb38 Mon Sep 17 00:00:00 2001 From: Moritz Sallermann Date: Thu, 14 Oct 2021 15:04:51 +0000 Subject: [PATCH] API: Implemented an easy way to get basic information about a simulation run via the API. Previously one could only get this information by querying from a concurrent thread. The `Simulation_XXX_Start` methods now take a pointer to a `Simulation_Run_Info` object that contains the following information - the total walltime - the maximum torque norm - the total number of iterations - the total iterations per second In the python API the `simulation_run_info` object is returned by the `simulation.start` method. --- core/include/Spirit/Simulation.h | 35 +++++++++++++----------- core/python/spirit/simulation.py | 28 ++++++++++++++----- core/src/Spirit/Simulation.cpp | 42 ++++++++++++++++------------- ui-cpp/ui-imgui/src/main_window.cpp | 14 +++++----- ui-cpp/ui-qt/src/ControlWidget.cpp | 10 +++---- 5 files changed, 76 insertions(+), 53 deletions(-) diff --git a/core/include/Spirit/Simulation.h b/core/include/Spirit/Simulation.h index 031d40af5..a6fcccf14 100644 --- a/core/include/Spirit/Simulation.h +++ b/core/include/Spirit/Simulation.h @@ -9,7 +9,7 @@ struct State; /* Simulation -==================================================================== +//==================================================================== ```C #include "Spirit/Simulation.h" @@ -53,35 +53,38 @@ Note that the VP and LBFGS Solvers are only meant for direct minimization and no // `Solver_VP_OSO`: Verlet-like velocity projection, exponential transform #define Solver_VP_OSO 7 +struct Simulation_Run_Info +{ + int total_iterations = 0; + int total_walltime = 0; + float total_ips = 0; + float max_torque = 0; +}; + /* Start or stop a simulation -------------------------------------------------------------------- */ // Monte Carlo -PREFIX void Simulation_MC_Start( - State * state, int n_iterations = -1, int n_iterations_log = -1, bool singleshot = false, int idx_image = -1, - int idx_chain = -1 ) SUFFIX; +PREFIX void Simulation_MC_Start(State *state, int n_iterations=-1, int n_iterations_log=-1, + bool singleshot=false, Simulation_Run_Info * info = NULL, int idx_image=-1, int idx_chain=-1) SUFFIX; // Landau-Lifshitz-Gilbert dynamics and energy minimisation -PREFIX void Simulation_LLG_Start( - State * state, int solver_type, int n_iterations = -1, int n_iterations_log = -1, bool singleshot = false, - int idx_image = -1, int idx_chain = -1 ) SUFFIX; +PREFIX void Simulation_LLG_Start(State *state, int solver_type, int n_iterations=-1, int n_iterations_log=-1, + bool singleshot=false, Simulation_Run_Info * info = NULL, int idx_image=-1, int idx_chain=-1) SUFFIX; // Geodesic nudged elastic band method -PREFIX void Simulation_GNEB_Start( - State * state, int solver_type, int n_iterations = -1, int n_iterations_log = -1, bool singleshot = false, - int idx_chain = -1 ) SUFFIX; +PREFIX void Simulation_GNEB_Start(State *state, int solver_type, int n_iterations=-1, int n_iterations_log=-1, + bool singleshot=false, Simulation_Run_Info * info = NULL, int idx_chain=-1) SUFFIX; // Minimum mode following method -PREFIX void Simulation_MMF_Start( - State * state, int solver_type, int n_iterations = -1, int n_iterations_log = -1, bool singleshot = false, - int idx_image = -1, int idx_chain = -1 ) SUFFIX; +PREFIX void Simulation_MMF_Start(State *state, int solver_type, int n_iterations=-1, int n_iterations_log=-1, + bool singleshot=false, Simulation_Run_Info * info = NULL, int idx_image=-1, int idx_chain=-1) SUFFIX; // Eigenmode analysis -PREFIX void Simulation_EMA_Start( - State * state, int n_iterations = -1, int n_iterations_log = -1, bool singleshot = false, int idx_image = -1, - int idx_chain = -1 ) SUFFIX; +PREFIX void Simulation_EMA_Start(State *state, int n_iterations=-1, int n_iterations_log=-1, + bool singleshot=false, Simulation_Run_Info * info = NULL, int idx_image=-1, int idx_chain=-1) SUFFIX; /* Single iteration of a Method diff --git a/core/python/spirit/simulation.py b/core/python/spirit/simulation.py index 73f53747c..eca794836 100644 --- a/core/python/spirit/simulation.py +++ b/core/python/spirit/simulation.py @@ -1,6 +1,5 @@ """ Simulation -==================== This module of Spirit is used to run and monitor iterative calculation methods. @@ -88,32 +87,39 @@ of images corresponding to the movement of the system under the mode. """ +class simulation_run_info(ctypes.Structure): + _fields_ = [ + ("total_iterations", ctypes.c_int), + ("total_walltime", ctypes.c_int), + ("total_ips", ctypes.c_float), + ("max_torque", ctypes.c_float) + ] ### ----- Start methods ### MC _MC_Start = _spirit.Simulation_MC_Start _MC_Start.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, - ctypes.c_bool, ctypes.c_int, ctypes.c_int] + ctypes.c_bool, ctypes.POINTER(simulation_run_info), ctypes.c_int, ctypes.c_int] _MC_Start.restype = None ### LLG _LLG_Start = _spirit.Simulation_LLG_Start _LLG_Start.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_int, - ctypes.c_bool, ctypes.c_int, ctypes.c_int] + ctypes.c_bool, ctypes.POINTER(simulation_run_info), ctypes.c_int, ctypes.c_int] _LLG_Start.restype = None ### GNEB _GNEB_Start = _spirit.Simulation_GNEB_Start _GNEB_Start.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, - ctypes.c_int, ctypes.c_bool, ctypes.c_int] + ctypes.c_int, ctypes.c_bool, ctypes.POINTER(simulation_run_info), ctypes.c_int] _GNEB_Start.restype = None ### MMF _MMF_Start = _spirit.Simulation_MMF_Start _MMF_Start.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_int, - ctypes.c_bool, ctypes.c_int, ctypes.c_int] + ctypes.c_bool, ctypes.POINTER(simulation_run_info), ctypes.c_int, ctypes.c_int] _MMF_Start.restype = None ### EMA _EMA_Start = _spirit.Simulation_EMA_Start _EMA_Start.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, - ctypes.c_bool, ctypes.c_int, ctypes.c_int] + ctypes.c_bool, ctypes.POINTER(simulation_run_info), ctypes.c_int, ctypes.c_int] _EMA_Start.restype = None ### ----- Wrapper def start(p_state, method_type, solver_type=None, n_iterations=-1, n_iterations_log=-1, @@ -128,37 +134,45 @@ def start(p_state, method_type, solver_type=None, n_iterations=-1, n_iterations_ - `idx_image`: the image on which to run the calculation (default: active image). Not used for GNEB """ + info = simulation_run_info() + if method_type == METHOD_MC: spiritlib.wrap_function(_MC_Start, [ctypes.c_void_p(p_state), ctypes.c_int(n_iterations), ctypes.c_int(n_iterations_log), ctypes.c_bool(single_shot), + ctypes.pointer(info), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)]) elif method_type == METHOD_LLG: spiritlib.wrap_function(_LLG_Start, [ctypes.c_void_p(p_state), ctypes.c_int(solver_type), ctypes.c_int(n_iterations), ctypes.c_int(n_iterations_log), ctypes.c_bool(single_shot), + ctypes.pointer(info), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)]) elif method_type == METHOD_GNEB: spiritlib.wrap_function(_GNEB_Start, [ctypes.c_void_p(p_state), ctypes.c_int(solver_type), ctypes.c_int(n_iterations), ctypes.c_int(n_iterations_log), ctypes.c_bool(single_shot), - ctypes.c_int(idx_image), ctypes.c_int(idx_chain)]) + ctypes.pointer(info), + ctypes.c_int(idx_chain)]) elif method_type == METHOD_MMF: spiritlib.wrap_function(_MMF_Start, [ctypes.c_void_p(p_state), ctypes.c_int(solver_type), ctypes.c_int(n_iterations), ctypes.c_int(n_iterations_log), ctypes.c_bool(single_shot), + ctypes.pointer(info), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)]) elif method_type == METHOD_EMA: spiritlib.wrap_function(_EMA_Start, [ctypes.c_void_p(p_state), ctypes.c_int(n_iterations), ctypes.c_int(n_iterations_log), ctypes.c_bool(single_shot), + ctypes.pointer(info), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)]) else: print("Invalid method_type passed to simulation.start...") + return info # _Start(ctypes.c_void_p(p_state), ctypes.c_char_p(method_type), # ctypes.c_char_p(solver_type), ctypes.c_int(n_iterations), # ctypes.c_int(n_iterations_log), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) diff --git a/core/src/Spirit/Simulation.cpp b/core/src/Spirit/Simulation.cpp index eca21bb73..756ed63ee 100644 --- a/core/src/Spirit/Simulation.cpp +++ b/core/src/Spirit/Simulation.cpp @@ -12,7 +12,7 @@ #include // Helper function to start a simulation once a Method has been created -void run_method( std::shared_ptr method, bool singleshot ) +void run_method(std::shared_ptr method, bool singleshot, Simulation_Run_Info * info = nullptr) { if( singleshot ) { @@ -32,11 +32,18 @@ void run_method( std::shared_ptr method, bool singleshot ) else { method->Iterate(); + if(info) + { + info->max_torque = method->getTorqueMaxNorm(); + info->total_iterations = method->getNIterations(); + info->total_walltime = method->getWallTime(); + info->total_ips = float(info->total_iterations) / info->total_walltime * 1000.0; + } } } -void Simulation_MC_Start( - State * state, int n_iterations, int n_iterations_log, bool singleshot, int idx_image, int idx_chain ) noexcept +void Simulation_MC_Start(State *state, + int n_iterations, int n_iterations_log, bool singleshot, Simulation_Run_Info * info, int idx_image, int idx_chain) noexcept try { // Fetch correct indices and pointers for image and chain @@ -83,7 +90,7 @@ try image->Unlock(); state->method_image[idx_image] = method; - run_method( method, singleshot ); + run_method(method, singleshot, info); } } catch( ... ) @@ -91,9 +98,8 @@ catch( ... ) spirit_handle_exception_api( idx_image, idx_chain ); } -void Simulation_LLG_Start( - State * state, int solver_type, int n_iterations, int n_iterations_log, bool singleshot, int idx_image, - int idx_chain ) noexcept +void Simulation_LLG_Start(State *state, int solver_type, + int n_iterations, int n_iterations_log, bool singleshot, Simulation_Run_Info * info, int idx_image, int idx_chain) noexcept try { // Fetch correct indices and pointers for image and chain @@ -168,7 +174,7 @@ try image->Unlock(); state->method_image[idx_image] = method; - run_method( method, singleshot ); + run_method(method, singleshot, info); } } catch( ... ) @@ -176,8 +182,8 @@ catch( ... ) spirit_handle_exception_api( idx_image, idx_chain ); } -void Simulation_GNEB_Start( - State * state, int solver_type, int n_iterations, int n_iterations_log, bool singleshot, int idx_chain ) noexcept +void Simulation_GNEB_Start(State *state, int solver_type, + int n_iterations, int n_iterations_log, bool singleshot, Simulation_Run_Info * info, int idx_chain) noexcept try { // Fetch correct indices and pointers for image and chain @@ -264,7 +270,7 @@ try chain->Unlock(); state->method_chain = method; - run_method( method, singleshot ); + run_method(method, singleshot, info); } } } @@ -273,9 +279,8 @@ catch( ... ) spirit_handle_exception_api( -1, idx_chain ); } -void Simulation_MMF_Start( - State * state, int solver_type, int n_iterations, int n_iterations_log, bool singleshot, int idx_image, - int idx_chain ) noexcept +void Simulation_MMF_Start(State *state, int solver_type, + int n_iterations, int n_iterations_log, bool singleshot, Simulation_Run_Info * info, int idx_image, int idx_chain) noexcept try { // Fetch correct indices and pointers for image and chain @@ -339,7 +344,7 @@ try image->Unlock(); state->method_image[idx_image] = method; - run_method( method, singleshot ); + run_method(method, singleshot, info); } } catch( ... ) @@ -347,8 +352,8 @@ catch( ... ) spirit_handle_exception_api( idx_image, idx_chain ); } -void Simulation_EMA_Start( - State * state, int n_iterations, int n_iterations_log, bool singleshot, int idx_image, int idx_chain ) noexcept +void Simulation_EMA_Start(State *state, + int n_iterations, int n_iterations_log, bool singleshot, Simulation_Run_Info * info, int idx_image, int idx_chain) noexcept try { // Fetch correct indices and pointers for image and chain @@ -395,7 +400,8 @@ try image->Unlock(); state->method_image[idx_image] = method; - run_method( method, singleshot ); + + run_method(method, singleshot, info); } } catch( ... ) diff --git a/ui-cpp/ui-imgui/src/main_window.cpp b/ui-cpp/ui-imgui/src/main_window.cpp index 5df5b9f3d..e2c26b024 100644 --- a/ui-cpp/ui-imgui/src/main_window.cpp +++ b/ui-cpp/ui-imgui/src/main_window.cpp @@ -723,7 +723,7 @@ try if( threads_image[idx].joinable() ) threads_image[System_Get_Index( state.get() )].join(); this->threads_image[System_Get_Index( state.get() )] = std::thread( - &Simulation_LLG_Start, this->state.get(), ui_shared_state.selected_solver_min, -1, -1, false, -1, -1 ); + &Simulation_LLG_Start, this->state.get(), ui_shared_state.selected_solver_min, -1, -1, false, nullptr, -1, -1 ); } if( ui_shared_state.selected_mode == GUI_Mode::LLG ) { @@ -731,7 +731,7 @@ try if( threads_image[idx].joinable() ) threads_image[System_Get_Index( state.get() )].join(); this->threads_image[System_Get_Index( state.get() )] = std::thread( - &Simulation_LLG_Start, this->state.get(), ui_shared_state.selected_solver_llg, -1, -1, false, -1, -1 ); + &Simulation_LLG_Start, this->state.get(), ui_shared_state.selected_solver_llg, -1, -1, false, nullptr, -1, -1 ); } else if( ui_shared_state.selected_mode == GUI_Mode::MC ) { @@ -739,22 +739,22 @@ try if( threads_image[idx].joinable() ) threads_image[System_Get_Index( state.get() )].join(); this->threads_image[System_Get_Index( state.get() )] - = std::thread( &Simulation_MC_Start, this->state.get(), -1, -1, false, -1, -1 ); + = std::thread( &Simulation_MC_Start, this->state.get(), -1, -1, false, nullptr, -1, -1 ); } else if( ui_shared_state.selected_mode == GUI_Mode::GNEB ) { if( thread_chain.joinable() ) thread_chain.join(); this->thread_chain = std::thread( - &Simulation_GNEB_Start, this->state.get(), ui_shared_state.selected_solver_min, -1, -1, false, -1 ); + &Simulation_GNEB_Start, this->state.get(), ui_shared_state.selected_solver_min, -1, -1, false, nullptr, -1 ); } else if( ui_shared_state.selected_mode == GUI_Mode::MMF ) - { + { int idx = System_Get_Index( state.get() ); if( threads_image[idx].joinable() ) threads_image[System_Get_Index( state.get() )].join(); this->threads_image[System_Get_Index( state.get() )] = std::thread( - &Simulation_MMF_Start, this->state.get(), ui_shared_state.selected_solver_min, -1, -1, false, -1, -1 ); + &Simulation_MMF_Start, this->state.get(), ui_shared_state.selected_solver_min, -1, -1, false, nullptr, -1, -1 ); } else if( ui_shared_state.selected_mode == GUI_Mode::EMA ) { @@ -762,7 +762,7 @@ try if( threads_image[idx].joinable() ) threads_image[System_Get_Index( state.get() )].join(); this->threads_image[System_Get_Index( state.get() )] - = std::thread( &Simulation_EMA_Start, this->state.get(), -1, -1, false, -1, -1 ); + = std::thread( &Simulation_EMA_Start, this->state.get(), -1, -1, false, nullptr, -1, -1 ); } this->ui_shared_state.notify( "started calculation" ); } diff --git a/ui-cpp/ui-qt/src/ControlWidget.cpp b/ui-cpp/ui-qt/src/ControlWidget.cpp index 3342609b9..bbabe9bd7 100644 --- a/ui-cpp/ui-qt/src/ControlWidget.cpp +++ b/ui-cpp/ui-qt/src/ControlWidget.cpp @@ -195,7 +195,7 @@ void ControlWidget::play_pause() if( threads_image[idx].joinable() ) threads_image[System_Get_Index( state.get() )].join(); this->threads_image[System_Get_Index( state.get() )] - = std::thread( &Simulation_LLG_Start, this->state.get(), solver, -1, -1, false, -1, -1 ); + = std::thread( &Simulation_LLG_Start, this->state.get(), solver, -1, -1, false, nullptr, -1, -1 ); } else if( this->s_method == "MC" ) { @@ -203,13 +203,13 @@ void ControlWidget::play_pause() if( threads_image[idx].joinable() ) threads_image[System_Get_Index( state.get() )].join(); this->threads_image[System_Get_Index( state.get() )] - = std::thread( &Simulation_MC_Start, this->state.get(), -1, -1, false, -1, -1 ); + = std::thread( &Simulation_MC_Start, this->state.get(), -1, -1, false, nullptr, -1, -1 ); } else if( this->s_method == "GNEB" ) { if( thread_chain.joinable() ) thread_chain.join(); - this->thread_chain = std::thread( &Simulation_GNEB_Start, this->state.get(), solver, -1, -1, false, -1 ); + this->thread_chain = std::thread( &Simulation_GNEB_Start, this->state.get(), solver, -1, -1, false, nullptr, -1 ); } else if( this->s_method == "MMF" ) { @@ -217,7 +217,7 @@ void ControlWidget::play_pause() if( threads_image[idx].joinable() ) threads_image[System_Get_Index( state.get() )].join(); this->threads_image[System_Get_Index( state.get() )] - = std::thread( &Simulation_MMF_Start, this->state.get(), solver, -1, -1, false, -1, -1 ); + = std::thread( &Simulation_MMF_Start, this->state.get(), solver, -1, -1, false, nullptr, -1, -1 ); } else if( this->s_method == "EMA" ) { @@ -225,7 +225,7 @@ void ControlWidget::play_pause() if( threads_image[idx].joinable() ) threads_image[System_Get_Index( state.get() )].join(); this->threads_image[System_Get_Index( state.get() )] - = std::thread( &Simulation_EMA_Start, this->state.get(), -1, -1, false, -1, -1 ); + = std::thread( &Simulation_EMA_Start, this->state.get(), -1, -1, false, nullptr, -1, -1 ); } // New button text this->pushButton_PlayPause->setText( "Stop" );