From 76cb30a3ef5be1ee34be2b1331a5f26e51072b89 Mon Sep 17 00:00:00 2001 From: Nicholson Koukpaizan Date: Fri, 6 Jun 2025 08:31:53 -0400 Subject: [PATCH 01/20] Separated out Enzyme macros from FindEnzyme and added a EnzymeAddLibrary macro. --- CMakeLists.txt | 3 + cmake/EnzymeAddLibrary.cmake | 126 +++++++++++++++++++++++++++++++++++ cmake/FindEnzyme.cmake | 79 ---------------------- 3 files changed, 129 insertions(+), 79 deletions(-) create mode 100644 cmake/EnzymeAddLibrary.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 29b8cf90..3dd39cf9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,9 @@ endif() if(${GRIDKIT_ENABLE_ENZYME}) include(FindEnzyme) + include(EnzymeAddLibrary) + # todo Add a centralized configuration file + add_definitions(-DGRIDKIT_ENABLE_ENZYME) endif() # Macro that adds libraries diff --git a/cmake/EnzymeAddLibrary.cmake b/cmake/EnzymeAddLibrary.cmake new file mode 100644 index 00000000..a67149f3 --- /dev/null +++ b/cmake/EnzymeAddLibrary.cmake @@ -0,0 +1,126 @@ +# +#[[ + +Finds Enzyme Clang plugin + +User may set: +- ENZYME_DIR + +Author(s): +- Asher Mancinelli +- Nicholson Koukpaizan + +]] + +macro(enzyme_build_object) + set(options) + set(oneValueArgs NAME) + set(multiValueArgs SOURCES LINK_LIBRARIES INCLUDE_DIRECTORIES) + cmake_parse_arguments(enzyme_build_object "${options}" "${oneValueArgs}" + "${multiValueArgs}" ${ARGN}) + + set(PHASE2 "${CMAKE_CURRENT_BINARY_DIR}/${enzyme_build_object_NAME}.bc") + set(PHASE3 "${CMAKE_CURRENT_BINARY_DIR}/${enzyme_build_object_NAME}_enzyme.ll") + set(PHASE4 "${CMAKE_CURRENT_BINARY_DIR}/${enzyme_build_object_NAME}_opt.ll") + set(PHASE5 "${CMAKE_CURRENT_BINARY_DIR}/${enzyme_build_object_NAME}") + + set(OBJS "") + set(includes "${enzyme_build_object_INCLUDE_DIRECTORIES}") + + foreach(lib ${enzyme_build_object_LINK_LIBRARIES}) + get_target_property(include ${lib} INCLUDE_DIRECTORIES) + set(includes "${includes}" ${include}) + + get_target_property(libsource ${lib} SOURCES) + string(FIND "${libsource}" "TARGET" found) + if(NOT(${found} EQUAL -1)) + list(APPEND LINKER_FLAGS "-Wl,${libsource}") + endif() + endforeach() + + foreach(dir ${includes}) + if(EXISTS ${dir}) + list(APPEND INCLUDE_COMPILER_LIST "-I${dir}") + endif() + endforeach() + + foreach(SRC ${enzyme_build_object_SOURCES}) + set(PHASE0 "${CMAKE_CURRENT_SOURCE_DIR}/${SRC}") + set(PHASE1 "${CMAKE_CURRENT_BINARY_DIR}/${enzyme_build_object_NAME}_${SRC}_compile.o") + add_custom_command( + DEPENDS ${PHASE0} + OUTPUT ${PHASE1} + COMMAND ${CMAKE_CXX_COMPILER} -flto -c ${PHASE0} ${INCLUDE_COMPILER_LIST} -O2 -fno-vectorize -ffast-math -fno-unroll-loops -fpass-plugin=${ENZYME_CLANG_PLUGIN_LIBRARY} -Xclang -load -Xclang ${ENZYME_CLANG_PLUGIN_LIBRARY} -mllvm -enable-load-pre=0 -mllvm -enzyme-auto-sparsity=1 -o ${PHASE1} + COMMENT "Compiling ${SRC} to object file for target ${enzyme_build_object_NAME}" + ) + set(OBJS "${OBJS} ${PHASE1}") + endforeach() + + cmake_language(EVAL CODE " + add_custom_command( + DEPENDS ${OBJS} + OUTPUT ${PHASE2} + COMMAND ${GRIDKIT_LLVM_LINK} ${OBJS} -o ${PHASE2} + COMMENT \"Linking object files to LLVM bytecode for target ${enzyme_build_object_NAME}\" + ) + ") + + add_custom_command( + DEPENDS ${PHASE2} + OUTPUT ${PHASE3} + COMMAND ${GRIDKIT_OPT} ${PHASE2} -load-pass-plugin=${ENZYME_LLVM_PLUGIN_LIBRARY} -passes=enzyme -o ${PHASE3} -S + COMMENT "Running Enzyme opt pass on target ${enzyme_build_object_NAME}" + ) + + add_custom_command( + DEPENDS ${PHASE3} + OUTPUT ${PHASE4} + COMMAND ${GRIDKIT_OPT} ${PHASE3} -O2 -o ${PHASE4} -S + COMMENT "Running remaining opt passes on target ${enzyme_build_object_NAME}" + ) + + add_custom_command( + DEPENDS ${PHASE4} + OUTPUT ${PHASE5} + COMMAND ${CMAKE_CXX_COMPILER} -c ${PHASE4} -o ${PHASE5} + COMMENT "Generating optimized object file for target ${enzyme_build_object_NAME}" + ) +endmacro() + +macro(enzyme_add_executable) + set(options) + set(oneValueArgs NAME) + set(multiValueArgs SOURCES LINK_LIBRARIES INCLUDE_DIRECTORIES) + cmake_parse_arguments(enzyme_add_executable "${options}" "${oneValueArgs}" + "${multiValueArgs}" ${ARGN}) + + enzyme_build_object( + NAME "${enzyme_add_executable_NAME}.o" + SOURCES ${enzyme_add_executable_SOURCES} + LINK_LIBRARIES ${enzyme_add_executable_LINK_LIBRARIES} + INCLUDE_DIRECTORIES ${enzyme_add_executable_INCLUDE_DIRECTORIES} + ) + + add_executable("${enzyme_add_executable_NAME}" "${enzyme_add_executable_NAME}.o") + set_target_properties("${enzyme_add_executable_NAME}" PROPERTIES LINKER_LANGUAGE CXX) + target_link_libraries("${enzyme_add_executable_NAME}" ${enzyme_add_executable_LINK_LIBRARIES}) +endmacro() + +macro(enzyme_add_library) + set(options) + set(oneValueArgs NAME) + set(multiValueArgs SOURCES LINK_LIBRARIES INCLUDE_DIRECTORIES) + cmake_parse_arguments(enzyme_add_library "${options}" "${oneValueArgs}" + "${multiValueArgs}" ${ARGN}) + + enzyme_build_object( + NAME "${enzyme_add_library_NAME}.o" + SOURCES ${enzyme_add_library_SOURCES} + LINK_LIBRARIES ${enzyme_add_library_LINK_LIBRARIES} + INCLUDE_DIRECTORIES ${enzyme_add_library_INCLUDE_DIRECTORIES} + ) + + add_library("${enzyme_add_library_NAME}" "${enzyme_add_library_NAME}.o") + set_target_properties("${enzyme_add_library_NAME}" PROPERTIES LINKER_LANGUAGE CXX) + target_link_libraries("${enzyme_add_library_NAME}" ${enzyme_add_library_LINK_LIBRARIES}) +endmacro() diff --git a/cmake/FindEnzyme.cmake b/cmake/FindEnzyme.cmake index 00a76d37..fbfaa440 100644 --- a/cmake/FindEnzyme.cmake +++ b/cmake/FindEnzyme.cmake @@ -59,82 +59,3 @@ find_program(GRIDKIT_OPT opt bin REQUIRED) message(STATUS "opt: ${GRIDKIT_OPT}") - -macro(enzyme_add_executable) - set(options) - set(oneValueArgs NAME) - set(multiValueArgs SOURCES LINK_LIBRARIES INCLUDE_DIRECTORIES) - cmake_parse_arguments(enzyme_add_executable "${options}" "${oneValueArgs}" - "${multiValueArgs}" ${ARGN}) - - set(PHASE2 "${CMAKE_CURRENT_BINARY_DIR}/${enzyme_add_executable_NAME}.bc") - set(PHASE3 "${CMAKE_CURRENT_BINARY_DIR}/${enzyme_add_executable_NAME}_enzyme.ll") - set(PHASE4 "${CMAKE_CURRENT_BINARY_DIR}/${enzyme_add_executable_NAME}_opt.ll") - set(PHASE5 "${CMAKE_CURRENT_BINARY_DIR}/${enzyme_add_executable_NAME}") - - set(OBJS "") - set(includes "${enzyme_add_executable_INCLUDE_DIRECTORIES}") - - foreach(lib ${enzyme_add_executable_LINK_LIBRARIES}) - get_target_property(include ${lib} INCLUDE_DIRECTORIES) - set(includes "${includes}" ${include}) - - get_target_property(libsource ${lib} SOURCES) - string(FIND "${libsource}" "TARGET" found) - if(NOT(${found} EQUAL -1)) - list(APPEND LINKER_FLAGS "-Wl,${libsource}") - endif() - endforeach() - - foreach(dir ${includes}) - if(EXISTS ${dir}) - list(APPEND INCLUDE_COMPILER_LIST "-I${dir}") - endif() - endforeach() - - foreach(SRC ${enzyme_add_executable_SOURCES}) - set(PHASE0 "${CMAKE_CURRENT_SOURCE_DIR}/${SRC}") - set(PHASE1 "${CMAKE_CURRENT_BINARY_DIR}/${enzyme_add_executable_NAME}_${SRC}_compile.o") - add_custom_command( - DEPENDS ${PHASE0} - OUTPUT ${PHASE1} - COMMAND ${CMAKE_CXX_COMPILER} -flto -c ${PHASE0} ${INCLUDE_COMPILER_LIST} -O2 -fno-vectorize -ffast-math -fno-unroll-loops -fpass-plugin=${ENZYME_CLANG_PLUGIN_LIBRARY} -Xclang -load -Xclang ${ENZYME_CLANG_PLUGIN_LIBRARY} -mllvm -enable-load-pre=0 -mllvm -enzyme-auto-sparsity=1 -o ${PHASE1} - COMMENT "Compiling ${SRC} to object file for target ${enzyme_add_executable_NAME}" - ) - set(OBJS "${OBJS} ${PHASE1}") - endforeach() - - cmake_language(EVAL CODE " - add_custom_command( - DEPENDS ${OBJS} - OUTPUT ${PHASE2} - COMMAND ${GRIDKIT_LLVM_LINK} ${OBJS} -o ${PHASE2} - COMMENT \"Linking object files to LLVM bytecode for target ${enzyme_add_executable_NAME}\" - ) - ") - - add_custom_command( - DEPENDS ${PHASE2} - OUTPUT ${PHASE3} - COMMAND ${GRIDKIT_OPT} ${PHASE2} -load-pass-plugin=${ENZYME_LLVM_PLUGIN_LIBRARY} -passes=enzyme -o ${PHASE3} -S - COMMENT "Running Enzyme opt pass on target ${enzyme_add_executable_NAME}" - ) - - add_custom_command( - DEPENDS ${PHASE3} - OUTPUT ${PHASE4} - COMMAND ${GRIDKIT_OPT} ${PHASE3} -O2 -o ${PHASE4} -S - COMMENT "Running remaining opt passes on target ${enzyme_add_executable_NAME}" - ) - - add_custom_command( - DEPENDS ${PHASE4} ${enzyme_add_executable_LINK_LIBRARIES} - OUTPUT ${PHASE5} - COMMAND ${CMAKE_CXX_COMPILER} ${LINKER_FLAGS} ${PHASE4} -o ${PHASE5} - ) - - add_custom_target( - "${enzyme_add_executable_NAME}_target" ALL - DEPENDS ${PHASE5} - ) -endmacro() From 853f3c0fd0222f74bb9311aed66fc339ef4a7525 Mon Sep 17 00:00:00 2001 From: Nicholson Koukpaizan Date: Fri, 6 Jun 2025 09:05:34 -0400 Subject: [PATCH 02/20] Enzyme wrapper within GridKit. --- .../Enzyme/SparseWrapper.hpp | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 src/AutomaticDifferentiation/Enzyme/SparseWrapper.hpp diff --git a/src/AutomaticDifferentiation/Enzyme/SparseWrapper.hpp b/src/AutomaticDifferentiation/Enzyme/SparseWrapper.hpp new file mode 100644 index 00000000..2450d318 --- /dev/null +++ b/src/AutomaticDifferentiation/Enzyme/SparseWrapper.hpp @@ -0,0 +1,176 @@ +#pragma once + +#include + +/** + * @brief Enzyme constants for activity analysis + * + */ +extern int enzyme_dup; +extern int enzyme_const; +extern int enzyme_dupnoneed; + +/** + * @brief Residual wrapper around residual methods inside model classes + * + * @tparam ModelT - model type + * @tparam ScalarT - scalar data type + */ +template +void residual_wrapper(ModelT* obj, ScalarT* y, ScalarT* f) +{ + obj->evaluateResidualLocally(y, f); +} + +namespace GridKit +{ + namespace Enzyme + { + /** + * @brief Enzyme fwddiff template + * + * @tparam T - return type + * @tparam ModelT - model type + */ + template + extern T __enzyme_fwddiff(void*, ModelT...) noexcept; + + /** + * @brief Enzyme todense template + * + * @tparam T - return type + * @tparam ModelT - model type + */ + template + extern T __enzyme_todense(ModelT...) noexcept; + + /** + * @brief Enzyme sparse storage in triplet format + * + * @tparam ScalarT - scalar data type + */ + template + struct Triple + { + size_t row; + size_t col; + ScalarT val; + Triple(Triple&&) = default; + + Triple(size_t row, size_t col, ScalarT val) + : row(row), + col(col), + val(val) + { + } + }; + + /** + * @brief Enzyme sparse accumulation for float + * + */ + __attribute__((enzyme_sparse_accumulate)) static void inner_storeflt(int64_t row, int64_t col, float val, std::vector>& triplets) + { + triplets.emplace_back(row, col, val); + } + + /** + * @brief Enzyme sparse accumulation for double + * + */ + __attribute__((enzyme_sparse_accumulate)) static void inner_storedbl(int64_t row, int64_t col, double val, std::vector>& triplets) + { + triplets.emplace_back(row, col, val); + } + + /** + * @brief Enzyme sparse store + * + * @tparam ScalarT - scalar data type + */ + template + __attribute__((always_inline)) static void sparse_store(ScalarT val, int64_t idx, size_t i, std::vector>& triplets) + { + if (val == 0.0) + return; + idx /= sizeof(ScalarT); + if constexpr (sizeof(ScalarT) == 4) + inner_storeflt(idx, i, val, triplets); + else + inner_storedbl(idx, i, val, triplets); + } + + /** + * @brief Enzyme sparse load + * + * @tparam ScalarT - scalar data type + */ + template + __attribute__((always_inline)) static ScalarT sparse_load(int64_t idx, size_t i, std::vector>& triplets) + { + return 0.0; + } + + /** + * @brief Enzyme identity store + * + * @tparam ScalarT - scalar data type + */ + template + __attribute__((always_inline)) static void ident_store(ScalarT, int64_t idx, size_t i) + { + assert(0 && "should never load"); + } + + /** + * @brief Enzyme identity load + * + * @tparam ScalarT - scalar data type + */ + template + __attribute__((always_inline)) static ScalarT ident_load(int64_t idx, size_t i) + { + idx /= sizeof(ScalarT); + return (ScalarT) (idx == i); + } + + /** + * @brief Function that computes the Jacobian via automatic differentiation + * + * @tparam ModelT - model type + * @tparam ScalarT - scalar data type + * @tparam IdxT - index data type + */ + template + __attribute__((noinline)) void EnzymeSparseModelJacobian(ModelT* model, IdxT n, ScalarT* input, GridKit::LinearAlgebra::COO_Matrix& jac) + { + std::vector> triplets; + for (IdxT i = 0; i < n; i++) + { + ScalarT* output = __enzyme_todense((void*) ident_load, (void*) ident_store, i); + ScalarT* d_output = __enzyme_todense((void*) sparse_load, (void*) sparse_store, i, &triplets); + + __enzyme_fwddiff((void*) residual_wrapper, + enzyme_const, + model, + enzyme_dup, + input, + output, + enzyme_dupnoneed, + (ScalarT*) 0x1, + d_output); + } + + std::vector ctemp{}; + std::vector rtemp{}; + std::vector valtemp{}; + for (auto& tup : triplets) + { + rtemp.push_back(tup.row); + ctemp.push_back(tup.col); + valtemp.push_back(tup.val); + } + jac.setValues(rtemp, ctemp, valtemp); + } + } // namespace Enzyme +} // namespace GridKit From d2c3f8a44a4b29951c1199badc573ed3824ce3a1 Mon Sep 17 00:00:00 2001 From: Nicholson Koukpaizan Date: Tue, 10 Jun 2025 12:35:15 -0400 Subject: [PATCH 03/20] Fixes to rebase. --- src/Model/PhasorDynamics/Load/CMakeLists.txt | 25 +- src/Model/PhasorDynamics/Load/Load.cpp | 216 +++--------------- src/Model/PhasorDynamics/Load/Load.hpp | 4 + .../Load/LoadDependencyTracking.cpp | 29 +++ src/Model/PhasorDynamics/Load/LoadEnzyme.cpp | 39 ++++ src/Model/PhasorDynamics/Load/LoadImpl.hpp | 174 ++++++++++++++ tests/UnitTests/PhasorDynamics/CMakeLists.txt | 1 + tests/UnitTests/PhasorDynamics/LoadTests.hpp | 48 ++++ .../UnitTests/PhasorDynamics/runLoadTests.cpp | 3 + 9 files changed, 348 insertions(+), 191 deletions(-) create mode 100644 src/Model/PhasorDynamics/Load/LoadDependencyTracking.cpp create mode 100644 src/Model/PhasorDynamics/Load/LoadEnzyme.cpp create mode 100644 src/Model/PhasorDynamics/Load/LoadImpl.hpp diff --git a/src/Model/PhasorDynamics/Load/CMakeLists.txt b/src/Model/PhasorDynamics/Load/CMakeLists.txt index 0f1659a7..909d04dc 100644 --- a/src/Model/PhasorDynamics/Load/CMakeLists.txt +++ b/src/Model/PhasorDynamics/Load/CMakeLists.txt @@ -1,12 +1,29 @@ - + # [[ # Author(s): # - Cameron Rutherford # ]] -gridkit_add_library(phasor_dynamics_load + +if(GRIDKIT_ENABLE_ENZYME) + gridkit_add_library(phasor_dynamics_load + SOURCES + LoadEnzyme.cpp + LINK_LIBRARIES + ClangEnzymeFlags + OUTPUT_NAME + gridkit_phasor_dynamics_load) +else() + gridkit_add_library(phasor_dynamics_load + SOURCES + Load.cpp + OUTPUT_NAME + gridkit_phasor_dynamics_load) +endif() + +gridkit_add_library(phasor_dynamics_load_dependency_tracking SOURCES - Load.cpp + LoadDependencyTracking.cpp OUTPUT_NAME - gridkit_phasor_dynamics_load) + gridkit_phasor_dynamics_load_dependency_tracking) diff --git a/src/Model/PhasorDynamics/Load/Load.cpp b/src/Model/PhasorDynamics/Load/Load.cpp index d3f9e016..bbc18790 100644 --- a/src/Model/PhasorDynamics/Load/Load.cpp +++ b/src/Model/PhasorDynamics/Load/Load.cpp @@ -1,187 +1,29 @@ - -#include "Load.hpp" - -#include -#include - -#include -#include - -namespace GridKit -{ - namespace PhasorDynamics - { - /*! - * @brief Constructor for a pi-model load - * - * Arguments passed to ModelEvaluatorImpl: - * - Number of equations = 0 - * - Number of independent variables = 0 - * - Number of quadratures = 0 - * - Number of optimization parameters = 0 - */ - - template - Load::Load(bus_type* bus) - : bus_(bus) - { - size_ = 0; - } - - template - Load::Load(bus_type* bus, - real_type R, - real_type X) - : bus_(bus), - R_(R), - X_(X) - { - } - - template - Load::Load(bus_type* bus, - model_data_type& data) - : bus_(bus), - R_(data.R), - X_(data.X) - { - } - - template - Load::Load(bus_type* bus, IdxT component_id) - : bus_(bus) - { - size_ = 0; - component_id_ = component_id; - } - - template - Load::~Load() - { - // std::cout << "Destroy Load..." << std::endl; - } - - /*! - * @brief allocate method computes sparsity pattern of the Jacobian. - */ - template - int Load::allocate() - { - // std::cout << "Allocate Load..." << std::endl; - return 0; - } - - /** - * Initialization of the load model - * - */ - template - int Load::initialize() - { - return 0; - } - - /** - * \brief Identify differential variables. - */ - template - int Load::tagDifferentiable() - { - return 0; - } - - /** - * \brief Residual contribution of the load is pushed to the bus. - * - */ - template - int Load::evaluateResidual() - { - real_type b = -X_ / (R_ * R_ + X_ * X_); - real_type g = R_ / (R_ * R_ + X_ * X_); - - Ir() += -g * Vr() + b * Vi(); - Ii() += -b * Vr() - g * Vi(); - - return 0; - } - - /** - * @brief Jacobian evaluation not implemented yet - * - * @tparam ScalarT - scalar data type - * @tparam IdxT - matrix index data type - * @return int - error code, 0 = success - */ - template - int Load::evaluateJacobian() - { - std::cout << "Evaluate Jacobian for Load..." << std::endl; - std::cout << "Jacobian evaluation not implemented!" << std::endl; - return 0; - } - - /** - * @brief Integrand (objective) evaluation not implemented yet - * - * @tparam ScalarT - scalar data type - * @tparam IdxT - matrix index data type - * @return int - error code, 0 = success - */ - template - int Load::evaluateIntegrand() - { - // std::cout << "Evaluate Integrand for Load..." << std::endl; - return 0; - } - - /** - * @brief Adjoint initialization not implemented yet - * - * @tparam ScalarT - scalar data type - * @tparam IdxT - matrix index data type - * @return int - error code, 0 = success - */ - template - int Load::initializeAdjoint() - { - // std::cout << "Initialize adjoint for Load..." << std::endl; - return 0; - } - - /** - * @brief Adjoint residual evaluation not implemented yet - * - * @tparam ScalarT - scalar data type - * @tparam IdxT - matrix index data type - * @return int - error code, 0 = success - */ - template - int Load::evaluateAdjointResidual() - { - // std::cout << "Evaluate adjoint residual for Load..." << std::endl; - return 0; - } - - /** - * @brief Adjoint integrand (objective) evaluation not implemented yet - * - * @tparam ScalarT - scalar data type - * @tparam IdxT - matrix index data type - * @return int - error code, 0 = success - */ - template - int Load::evaluateAdjointIntegrand() - { - // std::cout << "Evaluate adjoint Integrand for Load..." << std::endl; - return 0; - } - - // Available template instantiations - template class Load; - template class Load; - template class Load; - template class Load; - - } // namespace PhasorDynamics -} // namespace GridKit + +#include "LoadImpl.hpp" + +namespace GridKit +{ + namespace PhasorDynamics + { + /** + * @brief Jacobian evaluation not implemented + * + * @tparam ScalarT - scalar data type + * @tparam IdxT - matrix index data type + * @return int - error code, 0 = success + */ + template + int Load::evaluateJacobian() + { + std::cout << "Evaluate Jacobian for Load..." << std::endl; + std::cout << "Jacobian evaluation is not implemented!" << std::endl; + + return 0; + } + + // Available template instantiations + template class Load; + template class Load; + + } // namespace PhasorDynamics +} // namespace GridKit diff --git a/src/Model/PhasorDynamics/Load/Load.hpp b/src/Model/PhasorDynamics/Load/Load.hpp index 6fc996c8..ee20f428 100644 --- a/src/Model/PhasorDynamics/Load/Load.hpp +++ b/src/Model/PhasorDynamics/Load/Load.hpp @@ -36,6 +36,7 @@ namespace GridKit using Component::yp_; using Component::tag_; using Component::f_; + using Component::J_; using Component::component_id_; using real_type = typename Component::real_type; @@ -98,6 +99,9 @@ namespace GridKit return bus_->Ii(); } + public: + int evaluateResidualLocally(ScalarT*, ScalarT*); + private: bus_type* bus_{nullptr}; real_type R_{0.1}; diff --git a/src/Model/PhasorDynamics/Load/LoadDependencyTracking.cpp b/src/Model/PhasorDynamics/Load/LoadDependencyTracking.cpp new file mode 100644 index 00000000..8219abca --- /dev/null +++ b/src/Model/PhasorDynamics/Load/LoadDependencyTracking.cpp @@ -0,0 +1,29 @@ + +#include "LoadImpl.hpp" + +namespace GridKit +{ + namespace PhasorDynamics + { + /** + * @brief Jacobian evaluation not implemented + * + * @tparam ScalarT - scalar data type + * @tparam IdxT - matrix index data type + * @return int - error code, 0 = success + */ + template + int Load::evaluateJacobian() + { + std::cout << "Evaluate Jacobian for Load..." << std::endl; + std::cout << "Jacobian evaluation is not implemented!" << std::endl; + + return 0; + } + + // Available template instantiations + template class Load; + template class Load; + + } // namespace PhasorDynamics +} // namespace GridKit diff --git a/src/Model/PhasorDynamics/Load/LoadEnzyme.cpp b/src/Model/PhasorDynamics/Load/LoadEnzyme.cpp new file mode 100644 index 00000000..1410290f --- /dev/null +++ b/src/Model/PhasorDynamics/Load/LoadEnzyme.cpp @@ -0,0 +1,39 @@ + +#include "LoadImpl.hpp" +#include + +namespace GridKit +{ + namespace PhasorDynamics + { + /** + * @brief Jacobian evaluation experimental + * + * @tparam ScalarT - scalar data type + * @tparam IdxT - matrix index data type + * @return int - error code, 0 = success + */ + template + int Load::evaluateJacobian() + { + std::cout << "Evaluate Jacobian for Load..." << std::endl; + std::cout << "Jacobian evaluation is experimental!" << std::endl; + + std::vector y(2); + std::vector f(2); + y[0] = Vr(); + y[1] = Vi(); + /// Setting J_ via Enzyme works, though J_ had not been initialized within the model. + /// This is because the COO_Matrix class is very permissive. + /// Having the currents as model variables and allocating J_ accordingly will be helpful. + GridKit::Enzyme::EnzymeSparseModelJacobian, ScalarT, IdxT>(this, f.size(), y.data(), J_); + + return 0; + } + + // Available template instantiations + template class Load; + template class Load; + + } // namespace PhasorDynamics +} // namespace GridKit diff --git a/src/Model/PhasorDynamics/Load/LoadImpl.hpp b/src/Model/PhasorDynamics/Load/LoadImpl.hpp new file mode 100644 index 00000000..a327ecab --- /dev/null +++ b/src/Model/PhasorDynamics/Load/LoadImpl.hpp @@ -0,0 +1,174 @@ + +#include +#include + +#include "Load.hpp" +#include +#include + +namespace GridKit +{ + namespace PhasorDynamics + { + /*! + * @brief Constructor for a pi-model load + * + * Arguments passed to ModelEvaluatorImpl: + * - Number of equations = 0 + * - Number of independent variables = 0 + * - Number of quadratures = 0 + * - Number of optimization parameters = 0 + */ + + template + Load::Load(bus_type* bus) + : bus_(bus) + { + size_ = 0; + } + + template + Load::Load(bus_type* bus, + real_type R, + real_type X) + : bus_(bus), + R_(R), + X_(X) + { + } + + template + Load::Load(bus_type* bus, IdxT component_id) + : bus_(bus) + { + size_ = 0; + component_id_ = component_id; + } + + template + Load::~Load() + { + // std::cout << "Destroy Load..." << std::endl; + } + + /*! + * @brief allocate method computes sparsity pattern of the Jacobian. + */ + template + int Load::allocate() + { + // std::cout << "Allocate Load..." << std::endl; + return 0; + } + + /** + * Initialization of the load model + * + */ + template + int Load::initialize() + { + return 0; + } + + /** + * \brief Identify differential variables. + */ + template + int Load::tagDifferentiable() + { + return 0; + } + + /** + * @brief Residual contribution computed locally + * + */ + template + int Load::evaluateResidualLocally(ScalarT* y, ScalarT* f) + { + real_type b = -X_ / (R_ * R_ + X_ * X_); + real_type g = R_ / (R_ * R_ + X_ * X_); + + f[0] = -g * y[0] + b * y[1]; + f[1] = -b * y[0] - g * y[1]; + + return 0; + } + + /** + * \brief Residual contribution of the load is pushed to the bus. + * + */ + template + int Load::evaluateResidual() + { + std::vector y(2); + std::vector f(2); + y[0] = Vr(); + y[1] = Vi(); + evaluateResidualLocally(y.data(), f.data()); + Ir() += f[0]; + Ii() += f[1]; + + return 0; + } + + /** + * @brief Integrand (objective) evaluation not implemented yet + * + * @tparam ScalarT - scalar data type + * @tparam IdxT - matrix index data type + * @return int - error code, 0 = success + */ + template + int Load::evaluateIntegrand() + { + // std::cout << "Evaluate Integrand for Load..." << std::endl; + return 0; + } + + /** + * @brief Adjoint initialization not implemented yet + * + * @tparam ScalarT - scalar data type + * @tparam IdxT - matrix index data type + * @return int - error code, 0 = success + */ + template + int Load::initializeAdjoint() + { + // std::cout << "Initialize adjoint for Load..." << std::endl; + return 0; + } + + /** + * @brief Adjoint residual evaluation not implemented yet + * + * @tparam ScalarT - scalar data type + * @tparam IdxT - matrix index data type + * @return int - error code, 0 = success + */ + template + int Load::evaluateAdjointResidual() + { + // std::cout << "Evaluate adjoint residual for Load..." << std::endl; + return 0; + } + + /** + * @brief Adjoint integrand (objective) evaluation not implemented yet + * + * @tparam ScalarT - scalar data type + * @tparam IdxT - matrix index data type + * @return int - error code, 0 = success + */ + template + int Load::evaluateAdjointIntegrand() + { + // std::cout << "Evaluate adjoint Integrand for Load..." << std::endl; + return 0; + } + + } // namespace PhasorDynamics +} // namespace GridKit diff --git a/tests/UnitTests/PhasorDynamics/CMakeLists.txt b/tests/UnitTests/PhasorDynamics/CMakeLists.txt index dfe3c93d..c8b0a536 100644 --- a/tests/UnitTests/PhasorDynamics/CMakeLists.txt +++ b/tests/UnitTests/PhasorDynamics/CMakeLists.txt @@ -13,6 +13,7 @@ target_link_libraries(test_phasor_branch GRIDKIT::phasor_dynamics_branch add_executable(test_phasor_load runLoadTests.cpp) target_link_libraries(test_phasor_load GRIDKIT::phasor_dynamics_load + GRIDKIT::phasor_dynamics_load_dependency_tracking GRIDKIT::phasor_dynamics_bus) add_executable(test_phasor_genrou runGenrouTests.cpp) diff --git a/tests/UnitTests/PhasorDynamics/LoadTests.hpp b/tests/UnitTests/PhasorDynamics/LoadTests.hpp index f9104336..081db141 100644 --- a/tests/UnitTests/PhasorDynamics/LoadTests.hpp +++ b/tests/UnitTests/PhasorDynamics/LoadTests.hpp @@ -100,6 +100,36 @@ namespace GridKit return success.report(__func__); } +#ifdef GRIDKIT_ENABLE_ENZYME + TestOutcome enzyme_jacobian() + { + TestStatus success = true; + + real_type R{2.0}; ///< Load resistance + real_type X{4.0}; ///< Load reactance + + ScalarT Vr{10.0}; ///< Bus real voltage + ScalarT Vi{20.0}; ///< Bus imaginary voltage + + PhasorDynamics::BusInfinite bus(Vr, Vi); + + PhasorDynamics::Load load(&bus, R, X); + load.evaluateJacobian(); + GridKit::LinearAlgebra::COO_Matrix model_jacobian = load.getJacobian(); + model_jacobian.printMatrix("Model Jacobian"); + + /// Compare model Jacobian wih dependencies computed analytically + std::vector ref = analyticalJacobian(R, X); + std::vector model_dependencies = mapFromCOO(model_jacobian); + for (size_t i = 0; i < ref.size(); ++i) + { + success *= (GridKit::Testing::isEqual(model_dependencies[i], ref[i])); + } + + return success.report(__func__); + } +#endif + private: std::vector analyticalJacobian(const real_type R, const real_type X) @@ -119,6 +149,24 @@ namespace GridKit return dependencies; } + + std::vector mapFromCOO(GridKit::LinearAlgebra::COO_Matrix matrix) + { + std::tuple&, std::vector&, std::vector&> matrix_entries = matrix.getEntries(); + const auto [rows, columns, values] = matrix_entries; + + std::tuple matrix_dimensions = matrix.getDimensions(); + const auto [n_rows, n_columns] = matrix_dimensions; + + std::vector dependencies(n_rows); + + for (IdxT i = 0; i < rows.size(); ++i) + { + dependencies[rows[i]].insert(std::make_pair(columns[i], values[i])); + } + + return dependencies; + } }; } // namespace Testing diff --git a/tests/UnitTests/PhasorDynamics/runLoadTests.cpp b/tests/UnitTests/PhasorDynamics/runLoadTests.cpp index 41426a82..1dac30e2 100644 --- a/tests/UnitTests/PhasorDynamics/runLoadTests.cpp +++ b/tests/UnitTests/PhasorDynamics/runLoadTests.cpp @@ -11,6 +11,9 @@ int main() result += test.constructor(); result += test.residual(); result += test.jacobian(); +#ifdef GRIDKIT_ENABLE_ENZYME + result += test.enzyme_jacobian(); +#endif return result.summary(); } From b3810bdc451d886f6bcf817e84b129c66c337913 Mon Sep 17 00:00:00 2001 From: Nicholson Koukpaizan Date: Fri, 6 Jun 2025 09:54:53 -0400 Subject: [PATCH 04/20] More interesting vector residual for Enzyme examples. --- .../Enzyme/Library/Vector/EnzymeVector.cpp | 4 ++-- examples/Enzyme/Library/Vector/VectorModel.cpp | 6 +++++- examples/Enzyme/Standalone/EnzymeSparse.cpp | 18 +++++++++++------- examples/Enzyme/Standalone/EnzymeVector.cpp | 10 +++++++--- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/examples/Enzyme/Library/Vector/EnzymeVector.cpp b/examples/Enzyme/Library/Vector/EnzymeVector.cpp index 8a3e6925..5e53aee5 100644 --- a/examples/Enzyme/Library/Vector/EnzymeVector.cpp +++ b/examples/Enzyme/Library/Vector/EnzymeVector.cpp @@ -24,8 +24,8 @@ DenseMatrix dsquare_ref(std::vector x, std::vector y) { for (int idx = 0; idx < x.size(); ++idx) { - if (idx == idy) - jac.setValue(idx, idy, dsquare_ref_scalar(x[idx])); + if (idy <= idx) + jac.setValue(idx, idy, dsquare_ref_scalar(x[idy])); } } return jac; diff --git a/examples/Enzyme/Library/Vector/VectorModel.cpp b/examples/Enzyme/Library/Vector/VectorModel.cpp index cb4d89f5..b56afbff 100644 --- a/examples/Enzyme/Library/Vector/VectorModel.cpp +++ b/examples/Enzyme/Library/Vector/VectorModel.cpp @@ -20,7 +20,11 @@ void VectorModel::square(std::vector& x, std::vector& y) { for (int idx = 0; idx < x.size(); ++idx) { - y[idx] = this->square_scalar(x[idx]); + y[idx] = 0.0; + for (int idy = 0; idy <= idx; idy++) + { + y[idx] += this->square_scalar(x[idy]); + } } } diff --git a/examples/Enzyme/Standalone/EnzymeSparse.cpp b/examples/Enzyme/Standalone/EnzymeSparse.cpp index f8e0bf0a..ef440e93 100644 --- a/examples/Enzyme/Standalone/EnzymeSparse.cpp +++ b/examples/Enzyme/Standalone/EnzymeSparse.cpp @@ -59,9 +59,9 @@ __attribute__((always_inline)) static void sparse_store(T val, int64_t idx, size return; idx /= sizeof(T); if constexpr (sizeof(T) == 4) - inner_storeflt(i, idx, val, triplets); - else - inner_storedbl(i, idx, val, triplets); + inner_storeflt(idx, i, val, triplets); + else + inner_storedbl(idx, i, val, triplets); } template @@ -87,9 +87,13 @@ __attribute__((always_inline)) static T ident_load(int64_t idx, size_t i) template __attribute__((always_inline)) static void f(size_t N, T* input, T* output) { - for (size_t i = 0; i < N; i++) + for (size_t idx = 0; idx < N; ++idx) { - output[i] = input[i] * input[i]; + output[idx] = 0.0; + for (size_t idy = 0; idy <= idx; idy++) + { + output[idx] += input[idy] * input[idy]; + } } } @@ -104,11 +108,11 @@ void jac_f_ref(std::vector x, std::vector y, SparseMatrix& jac) { for (int idx = 0; idx < x.size(); ++idx) { - if (idx == idy) + if (idy <= idx) { rtemp.push_back(idx); ctemp.push_back(idy); - valtemp.push_back(2.0 * x[idx]); + valtemp.push_back(2.0 * x[idy]); } } } diff --git a/examples/Enzyme/Standalone/EnzymeVector.cpp b/examples/Enzyme/Standalone/EnzymeVector.cpp index 94a10f9a..05ba7525 100644 --- a/examples/Enzyme/Standalone/EnzymeVector.cpp +++ b/examples/Enzyme/Standalone/EnzymeVector.cpp @@ -32,7 +32,11 @@ void square(std::vector x, std::vector& y) { for (int idx = 0; idx < x.size(); ++idx) { - y[idx] = square_scalar(x[idx]); + y[idx] = 0.0; + for (int idy = 0; idy <= idx; idy++) + { + y[idx] += square_scalar(x[idy]); + } } } @@ -43,8 +47,8 @@ void dsquare_ref(std::vector x, std::vector y, DenseMatrix& dy) { for (int idx = 0; idx < x.size(); ++idx) { - if (idx == idy) - dy.setValue(idx, idy, dsquare_ref_scalar(x[idx])); + if (idy <= idx) + dy.setValue(idx, idy, dsquare_ref_scalar(x[idy])); } } } From af9cef7eb482ae3c66ea798eb147402674a11c60 Mon Sep 17 00:00:00 2001 From: Nicholson Koukpaizan Date: Fri, 6 Jun 2025 13:09:55 -0400 Subject: [PATCH 05/20] Fix some warnings. --- .../Enzyme/SparseWrapper.hpp | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/AutomaticDifferentiation/Enzyme/SparseWrapper.hpp b/src/AutomaticDifferentiation/Enzyme/SparseWrapper.hpp index 2450d318..c6374b01 100644 --- a/src/AutomaticDifferentiation/Enzyme/SparseWrapper.hpp +++ b/src/AutomaticDifferentiation/Enzyme/SparseWrapper.hpp @@ -69,7 +69,7 @@ namespace GridKit * @brief Enzyme sparse accumulation for float * */ - __attribute__((enzyme_sparse_accumulate)) static void inner_storeflt(int64_t row, int64_t col, float val, std::vector>& triplets) + __attribute__((enzyme_sparse_accumulate)) static void inner_storeflt(size_t row, size_t col, float val, std::vector>& triplets) { triplets.emplace_back(row, col, val); } @@ -78,7 +78,7 @@ namespace GridKit * @brief Enzyme sparse accumulation for double * */ - __attribute__((enzyme_sparse_accumulate)) static void inner_storedbl(int64_t row, int64_t col, double val, std::vector>& triplets) + __attribute__((enzyme_sparse_accumulate)) static void inner_storedbl(size_t row, size_t col, double val, std::vector>& triplets) { triplets.emplace_back(row, col, val); } @@ -89,7 +89,7 @@ namespace GridKit * @tparam ScalarT - scalar data type */ template - __attribute__((always_inline)) static void sparse_store(ScalarT val, int64_t idx, size_t i, std::vector>& triplets) + __attribute__((always_inline)) static void sparse_store(ScalarT val, size_t idx, size_t i, std::vector>& triplets) { if (val == 0.0) return; @@ -106,7 +106,7 @@ namespace GridKit * @tparam ScalarT - scalar data type */ template - __attribute__((always_inline)) static ScalarT sparse_load(int64_t idx, size_t i, std::vector>& triplets) + __attribute__((always_inline)) static ScalarT sparse_load(size_t, size_t, std::vector>&) { return 0.0; } @@ -117,7 +117,7 @@ namespace GridKit * @tparam ScalarT - scalar data type */ template - __attribute__((always_inline)) static void ident_store(ScalarT, int64_t idx, size_t i) + __attribute__((always_inline)) static void ident_store(ScalarT, size_t, size_t) { assert(0 && "should never load"); } @@ -128,7 +128,7 @@ namespace GridKit * @tparam ScalarT - scalar data type */ template - __attribute__((always_inline)) static ScalarT ident_load(int64_t idx, size_t i) + __attribute__((always_inline)) static ScalarT ident_load(size_t idx, size_t i) { idx /= sizeof(ScalarT); return (ScalarT) (idx == i); @@ -139,13 +139,13 @@ namespace GridKit * * @tparam ModelT - model type * @tparam ScalarT - scalar data type - * @tparam IdxT - index data type + * @tparam IdxT - matrix index data type */ template - __attribute__((noinline)) void EnzymeSparseModelJacobian(ModelT* model, IdxT n, ScalarT* input, GridKit::LinearAlgebra::COO_Matrix& jac) + __attribute__((noinline)) void EnzymeSparseModelJacobian(ModelT* model, size_t n, ScalarT* input, GridKit::LinearAlgebra::COO_Matrix& jac) { std::vector> triplets; - for (IdxT i = 0; i < n; i++) + for (size_t i = 0; i < n; i++) { ScalarT* output = __enzyme_todense((void*) ident_load, (void*) ident_store, i); ScalarT* d_output = __enzyme_todense((void*) sparse_load, (void*) sparse_store, i, &triplets); @@ -166,8 +166,8 @@ namespace GridKit std::vector valtemp{}; for (auto& tup : triplets) { - rtemp.push_back(tup.row); - ctemp.push_back(tup.col); + rtemp.push_back(static_cast(tup.row)); + ctemp.push_back(static_cast(tup.col)); valtemp.push_back(tup.val); } jac.setValues(rtemp, ctemp, valtemp); From 7878bc6ed994dec36278627d4c3df851c3934326 Mon Sep 17 00:00:00 2001 From: Nicholson Koukpaizan Date: Fri, 6 Jun 2025 13:17:49 -0400 Subject: [PATCH 06/20] Address one more warning. --- src/AutomaticDifferentiation/Enzyme/SparseWrapper.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AutomaticDifferentiation/Enzyme/SparseWrapper.hpp b/src/AutomaticDifferentiation/Enzyme/SparseWrapper.hpp index c6374b01..2c31876e 100644 --- a/src/AutomaticDifferentiation/Enzyme/SparseWrapper.hpp +++ b/src/AutomaticDifferentiation/Enzyme/SparseWrapper.hpp @@ -69,7 +69,7 @@ namespace GridKit * @brief Enzyme sparse accumulation for float * */ - __attribute__((enzyme_sparse_accumulate)) static void inner_storeflt(size_t row, size_t col, float val, std::vector>& triplets) + [[maybe_unused]] __attribute__((enzyme_sparse_accumulate)) static void inner_storeflt(size_t row, size_t col, float val, std::vector>& triplets) { triplets.emplace_back(row, col, val); } @@ -78,7 +78,7 @@ namespace GridKit * @brief Enzyme sparse accumulation for double * */ - __attribute__((enzyme_sparse_accumulate)) static void inner_storedbl(size_t row, size_t col, double val, std::vector>& triplets) + [[maybe_unused]] __attribute__((enzyme_sparse_accumulate)) static void inner_storedbl(size_t row, size_t col, double val, std::vector>& triplets) { triplets.emplace_back(row, col, val); } From 58d7ffa696036d258ca98d2f18cca4cff2eae647 Mon Sep 17 00:00:00 2001 From: nkoukpaizan Date: Fri, 6 Jun 2025 17:30:36 +0000 Subject: [PATCH 07/20] Apply pre-commmit fixes --- examples/Enzyme/Standalone/EnzymeSparse.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Enzyme/Standalone/EnzymeSparse.cpp b/examples/Enzyme/Standalone/EnzymeSparse.cpp index ef440e93..8b50652d 100644 --- a/examples/Enzyme/Standalone/EnzymeSparse.cpp +++ b/examples/Enzyme/Standalone/EnzymeSparse.cpp @@ -60,7 +60,7 @@ __attribute__((always_inline)) static void sparse_store(T val, int64_t idx, size idx /= sizeof(T); if constexpr (sizeof(T) == 4) inner_storeflt(idx, i, val, triplets); - else + else inner_storedbl(idx, i, val, triplets); } From f342e8c9d4df3635442df371f8b8360192ece1a4 Mon Sep 17 00:00:00 2001 From: Nicholson Koukpaizan Date: Fri, 6 Jun 2025 13:31:57 -0400 Subject: [PATCH 08/20] Empty commit to trigger CI after pre-commit fixes. From 75aa4d5a2bb2a21ad6285309bdf4261c20adfaf2 Mon Sep 17 00:00:00 2001 From: Nicholson Koukpaizan Date: Sat, 7 Jun 2025 11:36:26 -0400 Subject: [PATCH 09/20] Successful use of target_compiile_options to pass enzyme-auto-sparsity flags in examples. --- examples/Enzyme/Library/Scalar/CMakeLists.txt | 6 ++---- examples/Enzyme/Library/Vector/CMakeLists.txt | 7 ++----- .../Enzyme/PowerElectronics/CMakeLists.txt | 7 ++----- examples/Enzyme/PowerElectronics/main.cpp | 21 ++++++++++++------- examples/Enzyme/Standalone/CMakeLists.txt | 21 +++++++------------ 5 files changed, 26 insertions(+), 36 deletions(-) diff --git a/examples/Enzyme/Library/Scalar/CMakeLists.txt b/examples/Enzyme/Library/Scalar/CMakeLists.txt index 6dff430a..4e5c5754 100644 --- a/examples/Enzyme/Library/Scalar/CMakeLists.txt +++ b/examples/Enzyme/Library/Scalar/CMakeLists.txt @@ -1,6 +1,4 @@ -enzyme_add_executable( - NAME EnzymeLibScalarCheck - SOURCES EnzymeScalar.cpp ScalarModel.cpp -) +add_executable(EnzymeLibScalarCheck EnzymeScalar.cpp ScalarModel.cpp) +target_link_libraries(EnzymeLibScalarCheck ClangEnzymeFlags) add_test(NAME "EnzymeLibScalarCheck" COMMAND ${CMAKE_CURRENT_BINARY_DIR}/EnzymeLibScalarCheck) diff --git a/examples/Enzyme/Library/Vector/CMakeLists.txt b/examples/Enzyme/Library/Vector/CMakeLists.txt index eda952de..bca9777f 100644 --- a/examples/Enzyme/Library/Vector/CMakeLists.txt +++ b/examples/Enzyme/Library/Vector/CMakeLists.txt @@ -1,7 +1,4 @@ -enzyme_add_executable( - NAME EnzymeLibVectorCheck - SOURCES EnzymeVector.cpp VectorModel.cpp - LINK_LIBRARIES GRIDKIT::DenseMatrix -) +add_executable(EnzymeLibVectorCheck EnzymeVector.cpp VectorModel.cpp) +target_link_libraries(EnzymeLibVectorCheck ClangEnzymeFlags GRIDKIT::DenseMatrix) add_test(NAME "EnzymeLibVectorCheck" COMMAND ${CMAKE_CURRENT_BINARY_DIR}/EnzymeLibVectorCheck) diff --git a/examples/Enzyme/PowerElectronics/CMakeLists.txt b/examples/Enzyme/PowerElectronics/CMakeLists.txt index a8e74e88..5c0473cd 100644 --- a/examples/Enzyme/PowerElectronics/CMakeLists.txt +++ b/examples/Enzyme/PowerElectronics/CMakeLists.txt @@ -1,7 +1,4 @@ -enzyme_add_executable( - NAME EnzymePowerElectronicsCheck - SOURCES main.cpp - LINK_LIBRARIES GRIDKIT::DenseMatrix GRIDKIT::power_elec_disgen -) +add_executable(EnzymePowerElectronicsCheck main.cpp) +target_link_libraries(EnzymePowerElectronicsCheck ClangEnzymeFlags GRIDKIT::DenseMatrix GRIDKIT::power_elec_disgen) add_test(NAME "EnzymePowerElectronicsCheck" COMMAND ${CMAKE_CURRENT_BINARY_DIR}/EnzymePowerElectronicsCheck) diff --git a/examples/Enzyme/PowerElectronics/main.cpp b/examples/Enzyme/PowerElectronics/main.cpp index 5698901d..0689fd17 100644 --- a/examples/Enzyme/PowerElectronics/main.cpp +++ b/examples/Enzyme/PowerElectronics/main.cpp @@ -97,15 +97,15 @@ void evaluateResidual(std::vector y_, std::vector f_) template void EnzymeModelJacobian(T* model, DenseMatrix& jac) { - int N = model->size(); + size_t N = model->size(); std::vector y(N); std::vector v(N); std::vector res(N); std::vector d_res(N); - for (int idy = 0; idy < N; ++idy) + for (size_t idy = 0; idy < N; ++idy) { // Elementary vector for Jacobian-vector product - for (int idx = 0; idx < N; ++idx) + for (size_t idx = 0; idx < N; ++idx) { y[idx] = (model->y())[idx]; res[idx] = (model->getResidual())[idx]; @@ -123,7 +123,7 @@ void EnzymeModelJacobian(T* model, DenseMatrix& jac) &d_res); // Store result - for (int idx = 0; idx < N; ++idx) + for (size_t idx = 0; idx < N; ++idx) { jac.setValue(idx, idy, d_res[idx]); } @@ -171,16 +171,21 @@ int main() // Check int fail = 0; bool verbose = true; - for (int idy = 0; idy < dg->size(); ++idy) + for (size_t idy = 0; idy < dg->size(); ++idy) { - for (int idx = 0; idx < dg->size(); ++idx) + for (size_t idx = 0; idx < dg->size(); ++idx) { - if (std::abs(jac_autodiff.getValue(idx, idy) - jac_ref_dense.getValue(idx, idy)) > std::numeric_limits::epsilon()) + double jac_value = jac_autodiff.getValue(idx, idy); + double jac_ref_value = jac_ref_dense.getValue(idx, idy); + if (std::abs(jac_value - jac_ref_value) > 10*std::numeric_limits::epsilon()) { fail++; if (verbose) { - std::cout << "Result incorrect at line = " << idy << ", column = " << idx << "\n"; + std::cout << "Result incorrect at line = " << idy << ", column = " << idx << + ", obtained = " << jac_value << ", reference = " << jac_ref_value << + ", difference = " << std::abs(jac_value - jac_ref_value) << + "\n"; } } } diff --git a/examples/Enzyme/Standalone/CMakeLists.txt b/examples/Enzyme/Standalone/CMakeLists.txt index d80ba4f5..7f91dbb8 100644 --- a/examples/Enzyme/Standalone/CMakeLists.txt +++ b/examples/Enzyme/Standalone/CMakeLists.txt @@ -1,19 +1,12 @@ -enzyme_add_executable( - NAME EnzymeStandaloneScalarCheck - SOURCES EnzymeScalar.cpp -) +add_executable(EnzymeStandaloneScalarCheck EnzymeScalar.cpp) +target_link_libraries(EnzymeStandaloneScalarCheck ClangEnzymeFlags) -enzyme_add_executable( - NAME EnzymeStandaloneVectorCheck - SOURCES EnzymeVector.cpp - LINK_LIBRARIES GRIDKIT::DenseMatrix -) +add_executable(EnzymeStandaloneVectorCheck EnzymeVector.cpp) +target_link_libraries(EnzymeStandaloneVectorCheck ClangEnzymeFlags GRIDKIT::DenseMatrix) -enzyme_add_executable( - NAME EnzymeStandaloneSparseCheck - SOURCES EnzymeSparse.cpp - LINK_LIBRARIES GRIDKIT::SparseMatrix -) +add_executable(EnzymeStandaloneSparseCheck EnzymeSparse.cpp) +target_compile_options(EnzymeStandaloneSparseCheck PUBLIC -mllvm -enzyme-auto-sparsity=1) +target_link_libraries(EnzymeStandaloneSparseCheck ClangEnzymeFlags GRIDKIT::SparseMatrix) add_test(NAME "EnzymeStandaloneScalarCheck" COMMAND ${CMAKE_CURRENT_BINARY_DIR}/EnzymeStandaloneScalarCheck) add_test(NAME "EnzymeStandaloneVectorCheck" COMMAND ${CMAKE_CURRENT_BINARY_DIR}/EnzymeStandaloneVectorCheck) From b21ecccefd97215000d148fbf011a81b46903855 Mon Sep 17 00:00:00 2001 From: Nicholson Koukpaizan Date: Sat, 7 Jun 2025 12:12:19 -0400 Subject: [PATCH 10/20] More flags needed to get the correct answer to machine precision in EnzymePowerElectronicsCheck. --- examples/Enzyme/PowerElectronics/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/Enzyme/PowerElectronics/CMakeLists.txt b/examples/Enzyme/PowerElectronics/CMakeLists.txt index 5c0473cd..bd12e11d 100644 --- a/examples/Enzyme/PowerElectronics/CMakeLists.txt +++ b/examples/Enzyme/PowerElectronics/CMakeLists.txt @@ -1,4 +1,5 @@ add_executable(EnzymePowerElectronicsCheck main.cpp) +target_compile_options(EnzymePowerElectronicsCheck PUBLIC -O2 -fno-vectorize -ffast-math -fno-unroll-loops) target_link_libraries(EnzymePowerElectronicsCheck ClangEnzymeFlags GRIDKIT::DenseMatrix GRIDKIT::power_elec_disgen) add_test(NAME "EnzymePowerElectronicsCheck" COMMAND ${CMAKE_CURRENT_BINARY_DIR}/EnzymePowerElectronicsCheck) From 4ea98c31d6808152b0887205e91e1d0f103eb379 Mon Sep 17 00:00:00 2001 From: Nicholson Koukpaizan Date: Sat, 7 Jun 2025 12:16:05 -0400 Subject: [PATCH 11/20] EnzymeAddLibrary not currently needed. --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3dd39cf9..7428b046 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,7 +103,6 @@ endif() if(${GRIDKIT_ENABLE_ENZYME}) include(FindEnzyme) - include(EnzymeAddLibrary) # todo Add a centralized configuration file add_definitions(-DGRIDKIT_ENABLE_ENZYME) endif() From 16794975e8b8b81eb80584235662fdf1a7efff88 Mon Sep 17 00:00:00 2001 From: nkoukpaizan Date: Sat, 7 Jun 2025 16:18:21 +0000 Subject: [PATCH 12/20] Apply pre-commmit fixes --- examples/Enzyme/PowerElectronics/main.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/examples/Enzyme/PowerElectronics/main.cpp b/examples/Enzyme/PowerElectronics/main.cpp index 0689fd17..bbae5d56 100644 --- a/examples/Enzyme/PowerElectronics/main.cpp +++ b/examples/Enzyme/PowerElectronics/main.cpp @@ -175,17 +175,14 @@ int main() { for (size_t idx = 0; idx < dg->size(); ++idx) { - double jac_value = jac_autodiff.getValue(idx, idy); + double jac_value = jac_autodiff.getValue(idx, idy); double jac_ref_value = jac_ref_dense.getValue(idx, idy); - if (std::abs(jac_value - jac_ref_value) > 10*std::numeric_limits::epsilon()) + if (std::abs(jac_value - jac_ref_value) > 10 * std::numeric_limits::epsilon()) { fail++; if (verbose) { - std::cout << "Result incorrect at line = " << idy << ", column = " << idx << - ", obtained = " << jac_value << ", reference = " << jac_ref_value << - ", difference = " << std::abs(jac_value - jac_ref_value) << - "\n"; + std::cout << "Result incorrect at line = " << idy << ", column = " << idx << ", obtained = " << jac_value << ", reference = " << jac_ref_value << ", difference = " << std::abs(jac_value - jac_ref_value) << "\n"; } } } From 97afa8479b7d32f882e1a519374e15a9d1cde7cb Mon Sep 17 00:00:00 2001 From: Nicholson Koukpaizan Date: Sat, 7 Jun 2025 12:18:47 -0400 Subject: [PATCH 13/20] Empty commit to trigger CI after pre-commit fixes. From 6c724b3f97f2b518396573424bc0cf080679b55c Mon Sep 17 00:00:00 2001 From: Nicholson Koukpaizan Date: Sat, 7 Jun 2025 12:20:31 -0400 Subject: [PATCH 14/20] Updated documentation in EnzymeAddLibrary. --- cmake/EnzymeAddLibrary.cmake | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cmake/EnzymeAddLibrary.cmake b/cmake/EnzymeAddLibrary.cmake index a67149f3..9d7832ee 100644 --- a/cmake/EnzymeAddLibrary.cmake +++ b/cmake/EnzymeAddLibrary.cmake @@ -1,10 +1,7 @@ # #[[ -Finds Enzyme Clang plugin - -User may set: -- ENZYME_DIR +Macro to manually compile with Enzyme Author(s): - Asher Mancinelli From c32524faf1314f99d1ab91afadccb47082ce8211 Mon Sep 17 00:00:00 2001 From: Nicholson Koukpaizan Date: Sat, 7 Jun 2025 13:38:28 -0400 Subject: [PATCH 15/20] Fix warnings previously hidden by manual builds through enzyme_add_executable CMake macro. --- .../Enzyme/Library/Vector/EnzymeVector.cpp | 14 ++-- .../Enzyme/Library/Vector/VectorModel.cpp | 16 ++-- .../Enzyme/Library/Vector/VectorModel.hpp | 2 +- .../Enzyme/PowerElectronics/CMakeLists.txt | 2 +- examples/Enzyme/Standalone/EnzymeSparse.cpp | 80 +++++++++---------- examples/Enzyme/Standalone/EnzymeVector.cpp | 24 +++--- 6 files changed, 69 insertions(+), 69 deletions(-) diff --git a/examples/Enzyme/Library/Vector/EnzymeVector.cpp b/examples/Enzyme/Library/Vector/EnzymeVector.cpp index 5e53aee5..ca3f8504 100644 --- a/examples/Enzyme/Library/Vector/EnzymeVector.cpp +++ b/examples/Enzyme/Library/Vector/EnzymeVector.cpp @@ -20,9 +20,9 @@ inline double dsquare_ref_scalar(double x) DenseMatrix dsquare_ref(std::vector x, std::vector y) { DenseMatrix jac(x.size(), y.size()); - for (int idy = 0; idy < y.size(); ++idy) + for (size_t idy = 0; idy < y.size(); ++idy) { - for (int idx = 0; idx < x.size(); ++idx) + for (size_t idx = 0; idx < x.size(); ++idx) { if (idy <= idx) jac.setValue(idx, idy, dsquare_ref_scalar(x[idy])); @@ -34,12 +34,12 @@ DenseMatrix dsquare_ref(std::vector x, std::vector y) int main() { // Size and variable declarations - constexpr int n = 10; + constexpr size_t n = 10; std::vector var(n); // Random input values - srand(time(NULL)); - for (int idx = 0; idx < var.size(); ++idx) + srand(static_cast(time(NULL))); + for (size_t idx = 0; idx < var.size(); ++idx) { var[idx] = rand(); } @@ -59,9 +59,9 @@ int main() // Check int fail = 0; bool verbose = true; - for (int idy = 0; idy < res.size(); ++idy) + for (size_t idy = 0; idy < res.size(); ++idy) { - for (int idx = 0; idx < var.size(); ++idx) + for (size_t idx = 0; idx < var.size(); ++idx) { if (std::abs(jac.getValue(idx, idy) - jac_ref.getValue(idx, idy)) > std::numeric_limits::epsilon()) { diff --git a/examples/Enzyme/Library/Vector/VectorModel.cpp b/examples/Enzyme/Library/Vector/VectorModel.cpp index b56afbff..bdd99842 100644 --- a/examples/Enzyme/Library/Vector/VectorModel.cpp +++ b/examples/Enzyme/Library/Vector/VectorModel.cpp @@ -4,7 +4,7 @@ #include "EnzymeWrapper.hpp" -VectorModel::VectorModel(int n) +VectorModel::VectorModel(size_t n) : x_(n), f_(n), df_dx_(n, n) @@ -18,10 +18,10 @@ inline double VectorModel::square_scalar(double x) void VectorModel::square(std::vector& x, std::vector& y) { - for (int idx = 0; idx < x.size(); ++idx) + for (size_t idx = 0; idx < x.size(); ++idx) { y[idx] = 0.0; - for (int idy = 0; idy <= idx; idy++) + for (size_t idy = 0; idy <= idx; idy++) { y[idx] += this->square_scalar(x[idy]); } @@ -30,7 +30,7 @@ void VectorModel::square(std::vector& x, std::vector& y) void VectorModel::setVariable(std::vector x) { - for (int idx = 0; idx < x.size(); ++idx) + for (size_t idx = 0; idx < x.size(); ++idx) { x_[idx] = x[idx]; } @@ -43,13 +43,13 @@ void VectorModel::evalResidual() void VectorModel::evalJacobian() { - const int n = x_.size(); + const size_t n = x_.size(); std::vector v(n); VectorModel d_vector_model(n); - for (int idy = 0; idy < n; ++idy) + for (size_t idy = 0; idy < n; ++idy) { // Elementary vector for Jacobian-vector product - for (int idx = 0; idx < n; ++idx) + for (size_t idx = 0; idx < n; ++idx) { v[idx] = 0.0; } @@ -64,7 +64,7 @@ void VectorModel::evalJacobian() &d_vector_model); // Store result - for (int idx = 0; idx < n; ++idx) + for (size_t idx = 0; idx < n; ++idx) { df_dx_.setValue(idx, idy, d_res[idx]); } diff --git a/examples/Enzyme/Library/Vector/VectorModel.hpp b/examples/Enzyme/Library/Vector/VectorModel.hpp index da66f696..fd85f716 100644 --- a/examples/Enzyme/Library/Vector/VectorModel.hpp +++ b/examples/Enzyme/Library/Vector/VectorModel.hpp @@ -17,7 +17,7 @@ class VectorModel void square(std::vector&, std::vector&); public: - VectorModel(int); + VectorModel(size_t); void setVariable(std::vector); void evalResidual(); void evalJacobian(); diff --git a/examples/Enzyme/PowerElectronics/CMakeLists.txt b/examples/Enzyme/PowerElectronics/CMakeLists.txt index bd12e11d..de40cbbd 100644 --- a/examples/Enzyme/PowerElectronics/CMakeLists.txt +++ b/examples/Enzyme/PowerElectronics/CMakeLists.txt @@ -1,5 +1,5 @@ add_executable(EnzymePowerElectronicsCheck main.cpp) -target_compile_options(EnzymePowerElectronicsCheck PUBLIC -O2 -fno-vectorize -ffast-math -fno-unroll-loops) +target_compile_options(EnzymePowerElectronicsCheck PUBLIC -fno-vectorize -ffast-math -fno-unroll-loops) target_link_libraries(EnzymePowerElectronicsCheck ClangEnzymeFlags GRIDKIT::DenseMatrix GRIDKIT::power_elec_disgen) add_test(NAME "EnzymePowerElectronicsCheck" COMMAND ${CMAKE_CURRENT_BINARY_DIR}/EnzymePowerElectronicsCheck) diff --git a/examples/Enzyme/Standalone/EnzymeSparse.cpp b/examples/Enzyme/Standalone/EnzymeSparse.cpp index 8b50652d..e22459ee 100644 --- a/examples/Enzyme/Standalone/EnzymeSparse.cpp +++ b/examples/Enzyme/Standalone/EnzymeSparse.cpp @@ -26,15 +26,15 @@ template extern T __enzyme_todense(Tys...) noexcept; /// Sparse storage for Enzyme -template +template struct Triple { - size_t row; - size_t col; - T val; + size_t row; + size_t col; + ScalarT val; Triple(Triple&&) = default; - Triple(size_t row, size_t col, T val) + Triple(size_t row, size_t col, ScalarT val) : row(row), col(col), val(val) @@ -42,50 +42,50 @@ struct Triple } }; -__attribute__((enzyme_sparse_accumulate)) static void inner_storeflt(int64_t row, int64_t col, float val, std::vector>& triplets) +[[maybe_unused]] __attribute__((enzyme_sparse_accumulate)) static void inner_storeflt(size_t row, size_t col, float val, std::vector>& triplets) { triplets.emplace_back(row, col, val); } -__attribute__((enzyme_sparse_accumulate)) static void inner_storedbl(int64_t row, int64_t col, double val, std::vector>& triplets) +[[maybe_unused]] __attribute__((enzyme_sparse_accumulate)) static void inner_storedbl(size_t row, size_t col, double val, std::vector>& triplets) { triplets.emplace_back(row, col, val); } -template -__attribute__((always_inline)) static void sparse_store(T val, int64_t idx, size_t i, std::vector>& triplets) +template +__attribute__((always_inline)) static void sparse_store(ScalarT val, size_t idx, size_t i, std::vector>& triplets) { if (val == 0.0) return; - idx /= sizeof(T); - if constexpr (sizeof(T) == 4) + idx /= sizeof(ScalarT); + if constexpr (sizeof(ScalarT) == 4) inner_storeflt(idx, i, val, triplets); else inner_storedbl(idx, i, val, triplets); } -template -__attribute__((always_inline)) static T sparse_load(int64_t idx, size_t i, std::vector>& triplets) +template +__attribute__((always_inline)) static ScalarT sparse_load(size_t, size_t, std::vector>&) { return 0.0; } -template -__attribute__((always_inline)) static void ident_store(T, int64_t idx, size_t i) +template +__attribute__((always_inline)) static void ident_store(ScalarT, size_t, size_t) { assert(0 && "should never load"); } -template -__attribute__((always_inline)) static T ident_load(int64_t idx, size_t i) +template +__attribute__((always_inline)) static ScalarT ident_load(size_t idx, size_t i) { - idx /= sizeof(T); - return (T) (idx == i); + idx /= sizeof(ScalarT); + return (ScalarT) (idx == i); } /// Vector-valued function to differentiate -template -__attribute__((always_inline)) static void f(size_t N, T* input, T* output) +template +__attribute__((always_inline)) static void f(size_t N, ScalarT* input, ScalarT* output) { for (size_t idx = 0; idx < N; ++idx) { @@ -98,15 +98,15 @@ __attribute__((always_inline)) static void f(size_t N, T* input, T* output) } /// Reference Jacobian -template -void jac_f_ref(std::vector x, std::vector y, SparseMatrix& jac) +template +void jac_f_ref(std::vector x, std::vector y, SparseMatrix& jac) { - std::vector ctemp{}; - std::vector rtemp{}; - std::vector valtemp{}; - for (int idy = 0; idy < y.size(); ++idy) + std::vector ctemp{}; + std::vector rtemp{}; + std::vector valtemp{}; + for (size_t idy = 0; idy < y.size(); ++idy) { - for (int idx = 0; idx < x.size(); ++idx) + for (size_t idx = 0; idx < x.size(); ++idx) { if (idy <= idx) { @@ -120,29 +120,29 @@ void jac_f_ref(std::vector x, std::vector y, SparseMatrix& jac) } /// Function that computes the Jacobian via automatic differentiation -template -__attribute__((noinline)) void jac_f(size_t N, T* input, SparseMatrix& jac) +template +__attribute__((noinline)) void jac_f(size_t N, ScalarT* input, SparseMatrix& jac) { - std::vector> triplets; + std::vector> triplets; for (size_t i = 0; i < N; i++) { - T* output = __enzyme_todense((void*) ident_load, (void*) ident_store, i); - T* d_output = __enzyme_todense((void*) sparse_load, (void*) sparse_store, i, &triplets); + ScalarT* output = __enzyme_todense((void*) ident_load, (void*) ident_store, i); + ScalarT* d_output = __enzyme_todense((void*) sparse_load, (void*) sparse_store, i, &triplets); - __enzyme_fwddiff((void*) f, + __enzyme_fwddiff((void*) f, enzyme_const, N, enzyme_dup, input, output, enzyme_dupnoneed, - (T*) 0x1, + (ScalarT*) 0x1, d_output); } - std::vector ctemp{}; - std::vector rtemp{}; - std::vector valtemp{}; + std::vector ctemp{}; + std::vector rtemp{}; + std::vector valtemp{}; for (auto& tup : triplets) { rtemp.push_back(tup.row); @@ -159,7 +159,7 @@ void check(SparseMatrix matrix_1, SparseMatrix matrix_2, int& fail) const auto [rcord_1, ccord_1, vals_1] = entries_1; std::tuple&, std::vector&, std::vector&> entries_2 = matrix_2.getEntries(); const auto [rcord_2, ccord_2, vals_2] = entries_2; - for (int ind = 0; ind < vals_1.size(); ++ind) + for (size_t ind = 0; ind < vals_1.size(); ++ind) { if (rcord_1[ind] != rcord_2[ind]) fail++; @@ -181,7 +181,7 @@ int main() /// Input initialization double val = 0.0; - for (int i = 0; i < N; ++i) + for (size_t i = 0; i < N; ++i) { x[i] = val; val += 1.0; diff --git a/examples/Enzyme/Standalone/EnzymeVector.cpp b/examples/Enzyme/Standalone/EnzymeVector.cpp index 05ba7525..f07ebe6e 100644 --- a/examples/Enzyme/Standalone/EnzymeVector.cpp +++ b/examples/Enzyme/Standalone/EnzymeVector.cpp @@ -30,10 +30,10 @@ inline double dsquare_ref_scalar(double x) // Vector-valued function to differentiate void square(std::vector x, std::vector& y) { - for (int idx = 0; idx < x.size(); ++idx) + for (size_t idx = 0; idx < x.size(); ++idx) { y[idx] = 0.0; - for (int idy = 0; idy <= idx; idy++) + for (size_t idy = 0; idy <= idx; idy++) { y[idx] += square_scalar(x[idy]); } @@ -43,9 +43,9 @@ void square(std::vector x, std::vector& y) // Reference Jacobian void dsquare_ref(std::vector x, std::vector y, DenseMatrix& dy) { - for (int idy = 0; idy < y.size(); ++idy) + for (size_t idy = 0; idy < y.size(); ++idy) { - for (int idx = 0; idx < x.size(); ++idx) + for (size_t idx = 0; idx < x.size(); ++idx) { if (idy <= idx) dy.setValue(idx, idy, dsquare_ref_scalar(x[idy])); @@ -58,10 +58,10 @@ void dsquare(std::vector x, std::vector y, DenseMatrix& dy) { std::vector v(x.size()); std::vector d_y(y.size()); - for (int idy = 0; idy < y.size(); ++idy) + for (size_t idy = 0; idy < y.size(); ++idy) { // Elementary vector for Jacobian-vector product - for (int idx = 0; idx < x.size(); ++idx) + for (size_t idx = 0; idx < x.size(); ++idx) { v[idx] = 0.0; } @@ -71,7 +71,7 @@ void dsquare(std::vector x, std::vector y, DenseMatrix& dy) __enzyme_fwddiff((void*) square, enzyme_dup, x, v, enzyme_dupnoneed, y, &d_y); // Store result - for (int idx = 0; idx < x.size(); ++idx) + for (size_t idx = 0; idx < x.size(); ++idx) { dy.setValue(idx, idy, d_y[idx]); } @@ -81,15 +81,15 @@ void dsquare(std::vector x, std::vector y, DenseMatrix& dy) int main() { // Vector and matrix declarations - constexpr int N = 10; + constexpr size_t N = 10; std::vector x(N); std::vector sq(N); DenseMatrix dsq = DenseMatrix(N, N); DenseMatrix dsq_ref = DenseMatrix(N, N); // Random input values - srand(time(NULL)); - for (int idx = 0; idx < x.size(); ++idx) + srand(static_cast(time(NULL))); + for (size_t idx = 0; idx < x.size(); ++idx) { x[idx] = rand(); } @@ -106,9 +106,9 @@ int main() // Check int fail = 0; bool verbose = true; - for (int idy = 0; idy < sq.size(); ++idy) + for (size_t idy = 0; idy < sq.size(); ++idy) { - for (int idx = 0; idx < x.size(); ++idx) + for (size_t idx = 0; idx < x.size(); ++idx) { if (std::abs(dsq.getValue(idx, idy) - dsq_ref.getValue(idx, idy)) > std::numeric_limits::epsilon()) { From 0c479c32bdf0c7c81436a326bd375d9f6a6f0a0f Mon Sep 17 00:00:00 2001 From: Nicholson Koukpaizan Date: Tue, 10 Jun 2025 12:32:11 -0400 Subject: [PATCH 16/20] Use GridKit::Testing::isEqual in Enzyme examples. --- examples/Enzyme/Library/Scalar/CMakeLists.txt | 2 +- examples/Enzyme/Library/Scalar/EnzymeScalar.cpp | 4 ++-- examples/Enzyme/Library/Vector/CMakeLists.txt | 2 +- examples/Enzyme/Library/Vector/EnzymeVector.cpp | 4 ++-- examples/Enzyme/PowerElectronics/CMakeLists.txt | 2 +- examples/Enzyme/PowerElectronics/main.cpp | 4 ++-- examples/Enzyme/Standalone/CMakeLists.txt | 6 +++--- examples/Enzyme/Standalone/EnzymeScalar.cpp | 4 ++-- examples/Enzyme/Standalone/EnzymeSparse.cpp | 4 ++-- examples/Enzyme/Standalone/EnzymeVector.cpp | 4 ++-- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/examples/Enzyme/Library/Scalar/CMakeLists.txt b/examples/Enzyme/Library/Scalar/CMakeLists.txt index 4e5c5754..21e1b9b9 100644 --- a/examples/Enzyme/Library/Scalar/CMakeLists.txt +++ b/examples/Enzyme/Library/Scalar/CMakeLists.txt @@ -1,4 +1,4 @@ add_executable(EnzymeLibScalarCheck EnzymeScalar.cpp ScalarModel.cpp) -target_link_libraries(EnzymeLibScalarCheck ClangEnzymeFlags) +target_link_libraries(EnzymeLibScalarCheck ClangEnzymeFlags GRIDKIT::Utilities) add_test(NAME "EnzymeLibScalarCheck" COMMAND ${CMAKE_CURRENT_BINARY_DIR}/EnzymeLibScalarCheck) diff --git a/examples/Enzyme/Library/Scalar/EnzymeScalar.cpp b/examples/Enzyme/Library/Scalar/EnzymeScalar.cpp index a20f69e1..933e1bd7 100644 --- a/examples/Enzyme/Library/Scalar/EnzymeScalar.cpp +++ b/examples/Enzyme/Library/Scalar/EnzymeScalar.cpp @@ -1,7 +1,7 @@ #include -#include #include "ScalarModel.hpp" +#include /** * @brief Example that computes the derivative of a library function @@ -23,7 +23,7 @@ int main() double dsq = scalar_model.getDerivativeValue(); std::cout << "x = " << var << ", x^2 = " << sq << ", d(x^2)/dx = " << dsq << "\n"; - if (std::abs(dsq - 2.0 * var) > std::numeric_limits::epsilon()) + if (!GridKit::Testing::isEqual(dsq, 2.0 * var)) { fail++; std::cout << "Result incorrect\n"; diff --git a/examples/Enzyme/Library/Vector/CMakeLists.txt b/examples/Enzyme/Library/Vector/CMakeLists.txt index bca9777f..559a249b 100644 --- a/examples/Enzyme/Library/Vector/CMakeLists.txt +++ b/examples/Enzyme/Library/Vector/CMakeLists.txt @@ -1,4 +1,4 @@ add_executable(EnzymeLibVectorCheck EnzymeVector.cpp VectorModel.cpp) -target_link_libraries(EnzymeLibVectorCheck ClangEnzymeFlags GRIDKIT::DenseMatrix) +target_link_libraries(EnzymeLibVectorCheck ClangEnzymeFlags GRIDKIT::DenseMatrix GRIDKIT::Utilities) add_test(NAME "EnzymeLibVectorCheck" COMMAND ${CMAKE_CURRENT_BINARY_DIR}/EnzymeLibVectorCheck) diff --git a/examples/Enzyme/Library/Vector/EnzymeVector.cpp b/examples/Enzyme/Library/Vector/EnzymeVector.cpp index ca3f8504..4d9dd22f 100644 --- a/examples/Enzyme/Library/Vector/EnzymeVector.cpp +++ b/examples/Enzyme/Library/Vector/EnzymeVector.cpp @@ -1,7 +1,7 @@ #include -#include #include "VectorModel.hpp" +#include /** * @brief Example that computes the Jacobian of a vector-valued residual @@ -63,7 +63,7 @@ int main() { for (size_t idx = 0; idx < var.size(); ++idx) { - if (std::abs(jac.getValue(idx, idy) - jac_ref.getValue(idx, idy)) > std::numeric_limits::epsilon()) + if (!GridKit::Testing::isEqual(jac.getValue(idx, idy), jac_ref.getValue(idx, idy))) { fail++; if (verbose) diff --git a/examples/Enzyme/PowerElectronics/CMakeLists.txt b/examples/Enzyme/PowerElectronics/CMakeLists.txt index de40cbbd..a24c2326 100644 --- a/examples/Enzyme/PowerElectronics/CMakeLists.txt +++ b/examples/Enzyme/PowerElectronics/CMakeLists.txt @@ -1,5 +1,5 @@ add_executable(EnzymePowerElectronicsCheck main.cpp) target_compile_options(EnzymePowerElectronicsCheck PUBLIC -fno-vectorize -ffast-math -fno-unroll-loops) -target_link_libraries(EnzymePowerElectronicsCheck ClangEnzymeFlags GRIDKIT::DenseMatrix GRIDKIT::power_elec_disgen) +target_link_libraries(EnzymePowerElectronicsCheck ClangEnzymeFlags GRIDKIT::DenseMatrix GRIDKIT::power_elec_disgen GRIDKIT::Utilities) add_test(NAME "EnzymePowerElectronicsCheck" COMMAND ${CMAKE_CURRENT_BINARY_DIR}/EnzymePowerElectronicsCheck) diff --git a/examples/Enzyme/PowerElectronics/main.cpp b/examples/Enzyme/PowerElectronics/main.cpp index bbae5d56..35de5af9 100644 --- a/examples/Enzyme/PowerElectronics/main.cpp +++ b/examples/Enzyme/PowerElectronics/main.cpp @@ -1,9 +1,9 @@ #include -#include #include #include #include +#include /** * @brief Standalone example that computes the Jacobian associated with the @@ -177,7 +177,7 @@ int main() { double jac_value = jac_autodiff.getValue(idx, idy); double jac_ref_value = jac_ref_dense.getValue(idx, idy); - if (std::abs(jac_value - jac_ref_value) > 10 * std::numeric_limits::epsilon()) + if (!GridKit::Testing::isEqual(jac_value, jac_ref_value)) { fail++; if (verbose) diff --git a/examples/Enzyme/Standalone/CMakeLists.txt b/examples/Enzyme/Standalone/CMakeLists.txt index 7f91dbb8..e62a2ea1 100644 --- a/examples/Enzyme/Standalone/CMakeLists.txt +++ b/examples/Enzyme/Standalone/CMakeLists.txt @@ -1,12 +1,12 @@ add_executable(EnzymeStandaloneScalarCheck EnzymeScalar.cpp) -target_link_libraries(EnzymeStandaloneScalarCheck ClangEnzymeFlags) +target_link_libraries(EnzymeStandaloneScalarCheck ClangEnzymeFlags GRIDKIT::Utilities) add_executable(EnzymeStandaloneVectorCheck EnzymeVector.cpp) -target_link_libraries(EnzymeStandaloneVectorCheck ClangEnzymeFlags GRIDKIT::DenseMatrix) +target_link_libraries(EnzymeStandaloneVectorCheck ClangEnzymeFlags GRIDKIT::DenseMatrix GRIDKIT::Utilities) add_executable(EnzymeStandaloneSparseCheck EnzymeSparse.cpp) target_compile_options(EnzymeStandaloneSparseCheck PUBLIC -mllvm -enzyme-auto-sparsity=1) -target_link_libraries(EnzymeStandaloneSparseCheck ClangEnzymeFlags GRIDKIT::SparseMatrix) +target_link_libraries(EnzymeStandaloneSparseCheck ClangEnzymeFlags GRIDKIT::SparseMatrix GRIDKIT::Utilities) add_test(NAME "EnzymeStandaloneScalarCheck" COMMAND ${CMAKE_CURRENT_BINARY_DIR}/EnzymeStandaloneScalarCheck) add_test(NAME "EnzymeStandaloneVectorCheck" COMMAND ${CMAKE_CURRENT_BINARY_DIR}/EnzymeStandaloneVectorCheck) diff --git a/examples/Enzyme/Standalone/EnzymeScalar.cpp b/examples/Enzyme/Standalone/EnzymeScalar.cpp index d799e9b0..5dda5e1a 100644 --- a/examples/Enzyme/Standalone/EnzymeScalar.cpp +++ b/examples/Enzyme/Standalone/EnzymeScalar.cpp @@ -1,5 +1,5 @@ #include -#include +#include /** * @brief Standalone example that computes the derivative of a scalar function @@ -27,7 +27,7 @@ int main() double sq = square(var); double dsq = dsquare(var); std::cout << "x = " << var << ", x^2 = " << sq << ", d(x^2)/dx = " << dsq << "\n"; - if (std::abs(dsq - 2.0 * var) > std::numeric_limits::epsilon()) + if (!GridKit::Testing::isEqual(dsq, 2.0 * var)) { fail++; std::cout << "Result incorrect\n"; diff --git a/examples/Enzyme/Standalone/EnzymeSparse.cpp b/examples/Enzyme/Standalone/EnzymeSparse.cpp index e22459ee..22311318 100644 --- a/examples/Enzyme/Standalone/EnzymeSparse.cpp +++ b/examples/Enzyme/Standalone/EnzymeSparse.cpp @@ -1,10 +1,10 @@ #include #include -#include #include #include #include +#include /** * @brief Standalone example that computes the sparse Jacobian of a vector-valued function @@ -165,7 +165,7 @@ void check(SparseMatrix matrix_1, SparseMatrix matrix_2, int& fail) fail++; if (ccord_1[ind] != ccord_2[ind]) fail++; - if (std::abs(vals_1[ind] - vals_2[ind]) > std::numeric_limits::epsilon()) + if (!GridKit::Testing::isEqual(vals_1[ind], vals_2[ind])) fail++; } } diff --git a/examples/Enzyme/Standalone/EnzymeVector.cpp b/examples/Enzyme/Standalone/EnzymeVector.cpp index f07ebe6e..4883fc56 100644 --- a/examples/Enzyme/Standalone/EnzymeVector.cpp +++ b/examples/Enzyme/Standalone/EnzymeVector.cpp @@ -1,8 +1,8 @@ #include -#include #include #include +#include /** * @brief Standalone example that computes the Jacobian of a vector-valued function @@ -110,7 +110,7 @@ int main() { for (size_t idx = 0; idx < x.size(); ++idx) { - if (std::abs(dsq.getValue(idx, idy) - dsq_ref.getValue(idx, idy)) > std::numeric_limits::epsilon()) + if (!GridKit::Testing::isEqual(dsq.getValue(idx, idy), dsq_ref.getValue(idx, idy))) { fail++; if (verbose) From 88b4153584477c11797c424c650e7b1e29a51724 Mon Sep 17 00:00:00 2001 From: Nicholson Koukpaizan Date: Tue, 10 Jun 2025 12:39:31 -0400 Subject: [PATCH 17/20] Fixes to rebase. --- src/Model/PhasorDynamics/Load/LoadImpl.hpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Model/PhasorDynamics/Load/LoadImpl.hpp b/src/Model/PhasorDynamics/Load/LoadImpl.hpp index a327ecab..e8cfbd2b 100644 --- a/src/Model/PhasorDynamics/Load/LoadImpl.hpp +++ b/src/Model/PhasorDynamics/Load/LoadImpl.hpp @@ -37,6 +37,15 @@ namespace GridKit { } + template + Load::Load(bus_type* bus, + model_data_type& data) + : bus_(bus), + R_(data.R), + X_(data.X) + { + } + template Load::Load(bus_type* bus, IdxT component_id) : bus_(bus) @@ -97,7 +106,7 @@ namespace GridKit } /** - * \brief Residual contribution of the load is pushed to the bus. + * @brief Residual contribution of the load is pushed to the bus. * */ template From 03b165d4511affbc10bc645f86d3f0ab34738e52 Mon Sep 17 00:00:00 2001 From: nkoukpaizan Date: Tue, 10 Jun 2025 16:43:19 +0000 Subject: [PATCH 18/20] Apply pre-commmit fixes --- examples/Enzyme/Standalone/EnzymeScalar.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/Enzyme/Standalone/EnzymeScalar.cpp b/examples/Enzyme/Standalone/EnzymeScalar.cpp index 5dda5e1a..01f1ce8d 100644 --- a/examples/Enzyme/Standalone/EnzymeScalar.cpp +++ b/examples/Enzyme/Standalone/EnzymeScalar.cpp @@ -1,4 +1,5 @@ #include + #include /** From c5c5203b355a138377cab8e4e69912d2df4f7896 Mon Sep 17 00:00:00 2001 From: Nicholson Koukpaizan Date: Tue, 10 Jun 2025 12:43:58 -0400 Subject: [PATCH 19/20] Empty commit to trigger CI after pre-commit fixes. From 9261d2cba1d55c81647f1e0c77574d48a1e97057 Mon Sep 17 00:00:00 2001 From: Nicholson Koukpaizan Date: Tue, 10 Jun 2025 16:39:54 -0400 Subject: [PATCH 20/20] residual_wrapper can now be placed within GridKit::Enzyme namespace. --- .../Enzyme/SparseWrapper.hpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/AutomaticDifferentiation/Enzyme/SparseWrapper.hpp b/src/AutomaticDifferentiation/Enzyme/SparseWrapper.hpp index 2c31876e..61ec7ee9 100644 --- a/src/AutomaticDifferentiation/Enzyme/SparseWrapper.hpp +++ b/src/AutomaticDifferentiation/Enzyme/SparseWrapper.hpp @@ -10,22 +10,22 @@ extern int enzyme_dup; extern int enzyme_const; extern int enzyme_dupnoneed; -/** - * @brief Residual wrapper around residual methods inside model classes - * - * @tparam ModelT - model type - * @tparam ScalarT - scalar data type - */ -template -void residual_wrapper(ModelT* obj, ScalarT* y, ScalarT* f) -{ - obj->evaluateResidualLocally(y, f); -} - namespace GridKit { namespace Enzyme { + /** + * @brief Residual wrapper around residual methods inside model classes + * + * @tparam ModelT - model type + * @tparam ScalarT - scalar data type + */ + template + void residual_wrapper(ModelT* obj, ScalarT* y, ScalarT* f) + { + obj->evaluateResidualLocally(y, f); + } + /** * @brief Enzyme fwddiff template *