diff --git a/bindings/c/include/CMakeLists.txt b/bindings/c/include/CMakeLists.txt index 8ff866d91..27a6e139e 100644 --- a/bindings/c/include/CMakeLists.txt +++ b/bindings/c/include/CMakeLists.txt @@ -11,3 +11,4 @@ mgis_header(MGIS/Behaviour BehaviourDataView.h) mgis_header(MGIS/Behaviour MaterialStateManager.h) mgis_header(MGIS/Behaviour MaterialDataManager.h) mgis_header(MGIS/Behaviour Integrate.h) +mgis_header(MGIS/Model Model.h) diff --git a/bindings/c/include/MGIS/Behaviour/State.h b/bindings/c/include/MGIS/Behaviour/State.h index 347756912..9d5f8152c 100644 --- a/bindings/c/include/MGIS/Behaviour/State.h +++ b/bindings/c/include/MGIS/Behaviour/State.h @@ -159,6 +159,14 @@ MGIS_C_EXPORT mgis_status mgis_bv_state_set_internal_state_variable_by_name( mgis_bv_State* const, const char* const, const mgis_real* const); +/*! + * \brief get a pointer to the state variables + * \param[out] v: pointer to internal state variables + * \param[in] s: state + */ +MGIS_C_EXPORT mgis_status mgis_bv_state_get_internal_state_variables( + mgis_real**, + mgis_bv_State* const); /*! * \brief get a internal state variable' value in a state * \param[out] v: pointer to internal state variable' value(s) diff --git a/bindings/c/include/MGIS/Model/Model.h b/bindings/c/include/MGIS/Model/Model.h new file mode 100644 index 000000000..b28a00a1f --- /dev/null +++ b/bindings/c/include/MGIS/Model/Model.h @@ -0,0 +1,60 @@ +/*! + * \file bindings/c/include/MGIS/Model.h + * \brief + * \author Thomas Helfer + * \date 14/10/2021 + * \copyright (C) Copyright Thomas Helfer 2018. + * Use, modification and distribution are subject + * to one of the following licences: + * - GNU Lesser General Public License (LGPL), Version 3.0. (See accompanying + * file LGPL-3.0.txt) + * - CECILL-C, Version 1.0 (See accompanying files + * CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt). + */ + +#ifndef LIB_MGIS_MODEL_MODEL_H +#define LIB_MGIS_MODEL_MODEL_H + +#include "MGIS/Config.h" +#include "MGIS/Status.h" +#include "MGIS/Behaviour/Behaviour.h" + +#ifdef __cplusplus +#include "MGIS/Model/Model.hxx" +#endif /* __cplusplus */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef __cplusplus +//! \brief a simple alias +using mgis_model_Model = mgis::model::Model; +#else +//! \brief a simple alias +typedef mgis_bv_Behaviour mgis_model_Model; +#endif + +/*! + * \brief load a behaviour + * + * \param[out] ptr: behaviour + * \param[in] l: library name + * \param[in] m: model name + * \param[in] h: hypothesis + */ +MGIS_C_EXPORT mgis_status mgis_model_load(mgis_model_Model**, + const char* const, + const char* const, + const char* const); +/*! + * \brief free the memory associated with the given model. + * \param[in,out] m: model + */ +MGIS_C_EXPORT mgis_status mgis_model_free_model(mgis_model_Model**); + +#ifdef __cplusplus +} // end of extern "C" +#endif /* __cplusplus */ + +#endif /* LIB_MGIS_MODEL_MODEL_H */ diff --git a/bindings/c/src/CMakeLists.txt b/bindings/c/src/CMakeLists.txt index 6f899586b..e973c84bd 100644 --- a/bindings/c/src/CMakeLists.txt +++ b/bindings/c/src/CMakeLists.txt @@ -9,7 +9,8 @@ mgis_library(MFrontGenericInterface-c SHARED BehaviourDataView.cxx MaterialStateManager.cxx MaterialDataManager.cxx - Integrate.cxx) + Integrate.cxx + Model.cxx) target_include_directories(MFrontGenericInterface-c PUBLIC $ PUBLIC $ diff --git a/bindings/c/src/Model.cxx b/bindings/c/src/Model.cxx new file mode 100644 index 000000000..0d4b4e9bb --- /dev/null +++ b/bindings/c/src/Model.cxx @@ -0,0 +1,43 @@ +/*! + * \file Model.cxx + * \brief + * \author Thomas Helfer + * \date 14/10/2021 + * \copyright (C) Copyright Thomas Helfer 2018. + * Use, modification and distribution are subject + * to one of the following licences: + * - GNU Lesser General Public License (LGPL), Version 3.0. (See accompanying + * file LGPL-3.0.txt) + * - CECILL-C, Version 1.0 (See accompanying files + * CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt). + */ + +#include "MGIS/Model/Model.h" + +extern "C" { + +mgis_status mgis_model_load(mgis_model_Model** ptr, + const char* const l, + const char* const m, + const char* const h) { + *ptr = nullptr; + try { + const auto model = mgis::model::load(l, m, mgis::behaviour::fromString(h)); + *ptr = new mgis::model::Model(std::move(model)); + if (*ptr == nullptr) { + return mgis_report_failure( + "mgis_model_load: " + "memory allocation failed"); + } + } catch (...) { + return mgis_handle_cxx_exception(); + } + return mgis_report_success(); +} // end of mgis_model_load + +mgis_status mgis_model_free_model(mgis_model_Model** m) { + return mgis_bv_free_behaviour(m); +} // end of mgis_model_free_model + +} // end of extern "C" + diff --git a/bindings/c/src/State.cxx b/bindings/c/src/State.cxx index d8f6d075d..3bc3cd0a8 100644 --- a/bindings/c/src/State.cxx +++ b/bindings/c/src/State.cxx @@ -231,6 +231,22 @@ mgis_status mgis_bv_state_set_internal_state_variable_by_name( return mgis_report_success(); } // end of mgis_bv_state_set_internal_state_variable_by_name +mgis_status mgis_bv_state_get_internal_state_variables( + mgis_real** v, mgis_bv_State* const s) { + if (s == nullptr) { + return mgis_report_failure("invalid argument (null state)"); + } + if (v == nullptr) { + return mgis_report_failure("invalid argument (null values)"); + } + if(s->internal_state_variables.empty()){ + *v = nullptr; + return mgis_report_failure("no internal state variables declared"); + } + *v = s->internal_state_variables.data(); + return mgis_report_success(); +} // end of mgis_bv_state_get_internal_state_variable_by_name + mgis_status mgis_bv_state_get_internal_state_variable_by_name( mgis_real** v, mgis_bv_State* const s, const char* const n) { if (s == nullptr) { diff --git a/bindings/c/tests/CMakeLists.txt b/bindings/c/tests/CMakeLists.txt index 140420630..93acf29a6 100644 --- a/bindings/c/tests/CMakeLists.txt +++ b/bindings/c/tests/CMakeLists.txt @@ -63,6 +63,16 @@ add_executable(IntegrateTest3-c IntegrateTest3-c.c) target_link_libraries(IntegrateTest3-c PRIVATE MFrontGenericInterface-c MFrontGenericInterface) +add_executable(IntegrateTest4-c + EXCLUDE_FROM_ALL + IntegrateTest4-c.c) +target_link_libraries(IntegrateTest4-c + PRIVATE MFrontGenericInterface-c MFrontGenericInterface m) +add_executable(IntegrateTest5-c + EXCLUDE_FROM_ALL + IntegrateTest5-c.c) +target_link_libraries(IntegrateTest5-c + PRIVATE MFrontGenericInterface-c MFrontGenericInterface m) add_test(NAME MFrontGenericBehaviourInterfaceTest-c COMMAND MFrontGenericBehaviourInterfaceTest-c @@ -207,4 +217,28 @@ else((CMAKE_HOST_WIN32) AND (NOT MSYS)) PROPERTY DEPENDS BehaviourTest) endif((CMAKE_HOST_WIN32) AND (NOT MSYS)) +add_test(NAME IntegrateTest4-c + COMMAND IntegrateTest4-c + "$") +add_dependencies(check IntegrateTest4-c) +if((CMAKE_HOST_WIN32) AND (NOT MSYS)) + set_property(TEST IntegrateTest4-c + PROPERTY DEPENDS ModelTest + PROPERTY ENVIRONMENT "PATH=$\;$\;${MGIS_PATH_STRING}") +else((CMAKE_HOST_WIN32) AND (NOT MSYS)) + set_property(TEST IntegrateTest4-c + PROPERTY DEPENDS ModelTest) +endif((CMAKE_HOST_WIN32) AND (NOT MSYS)) +add_test(NAME IntegrateTest5-c + COMMAND IntegrateTest5-c + "$") +add_dependencies(check IntegrateTest5-c) +if((CMAKE_HOST_WIN32) AND (NOT MSYS)) + set_property(TEST IntegrateTest5-c + PROPERTY DEPENDS ModelTest + PROPERTY ENVIRONMENT "PATH=$\;$\;${MGIS_PATH_STRING}") +else((CMAKE_HOST_WIN32) AND (NOT MSYS)) + set_property(TEST IntegrateTest5-c + PROPERTY DEPENDS ModelTest) +endif((CMAKE_HOST_WIN32) AND (NOT MSYS)) diff --git a/bindings/c/tests/IntegrateTest4-c.c b/bindings/c/tests/IntegrateTest4-c.c new file mode 100644 index 000000000..60f5fcb73 --- /dev/null +++ b/bindings/c/tests/IntegrateTest4-c.c @@ -0,0 +1,131 @@ +/*! + * \file IntegrateTest4-c.c + * \brief + * \author Thomas Helfer + * \date 21/09/2018 + * \copyright (C) Copyright Thomas Helfer 2018. + * Use, modification and distribution are subject + * to one of the following licences: + * - GNU Lesser General Public License (LGPL), Version 3.0. (See accompanying + * file LGPL-3.0.txt) + * - CECILL-C, Version 1.0 (See accompanying files + * CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt). + */ + +#include +#include +#include +#include "MGIS/ThreadPool.h" +#include "MGIS/Model/Model.h" +#include "MGIS/Behaviour/MaterialDataManager.h" +#include "MGIS/Behaviour/Integrate.h" + +int test_status = EXIT_SUCCESS; +mgis_model_Model* model = NULL; +mgis_ThreadPool* p = NULL; +mgis_bv_MaterialDataManager* m = NULL; + +static void check_status(const mgis_status s) { + if (s.exit_status != MGIS_SUCCESS) { + fprintf(stderr, "invalid function call: %s\n", s.msg); + mgis_model_free_model(&model); + mgis_bv_free_material_data_manager(&m); + mgis_free_thread_pool(&p); + exit(EXIT_FAILURE); + } +} // end of check_status + +static int check(const int b, const char* const e) { + if (b == 0) { + test_status = EXIT_FAILURE; + fprintf(stderr, "%s\n", e); + } + return b; +} // end of check + +int main(const int argc, const char* const* argv) { + if (check(argc == 2, "expected two arguments") == 0) { + return EXIT_FAILURE; + } + const mgis_real eps = 1e-10; + const mgis_real dt =0.1; + mgis_size_type o; + mgis_real* isvs0; /* internal state variables at the beginning of the time step */ + mgis_real* isvs1; /* internal state variables at the end of the time step */ + mgis_size_type isvs_stride; /* internal state variables stride */ + const mgis_size_type n = 100; + mgis_bv_MaterialStateManager* + s0; /* state at the beginning of the time step */ + mgis_bv_MaterialStateManager* s1; /* state at the end of the time step */ + mgis_real xi[11]; /* values of 'x' for the first integration point */ + mgis_real xe[11]; /* values of 'x' for the last integration point */ + mgis_size_type ni,ne; + mgis_size_type idx; + mgis_size_type i; + mgis_real A; + mgis_real t; + mgis_real x_ref; + int r; + check_status(mgis_create_thread_pool(&p, 2)); + check_status(mgis_model_load(&model, argv[1], "ode_rk54", "Tridimensional")); + check_status(mgis_bv_behaviour_get_parameter_default_value(&A, model, "A")); + check_status(mgis_bv_create_material_data_manager(&m, model, 100)); + check_status( + mgis_bv_behaviour_get_internal_state_variable_offset(&o, model, "x")); + check_status(mgis_bv_material_data_manager_get_state_0(&s0, m)); + check_status(mgis_bv_material_data_manager_get_state_1(&s1, m)); + /* initialize the internal state variable */ + check_status( + mgis_bv_material_state_manager_get_internal_state_variables(&isvs0, s0)); + check_status( + mgis_bv_material_state_manager_get_internal_state_variables(&isvs1, s1)); + check_status( + mgis_bv_material_state_manager_get_internal_state_variables_stride( + &isvs_stride, s1)); + for (idx = 0; idx != n; ++idx) { + isvs1[idx * isvs_stride + o] = 1; + } + /* initialize the external state variable */ + check_status( + mgis_bv_material_state_manager_set_uniform_external_state_variable( + s1, "Temperature", 293.15)); + /* copy s1 in s0 */ + check_status(mgis_bv_update_material_data_manager(m)); + // integration */ + ni = o; + ne = (n - 1) * isvs_stride + o; + xi[0] = isvs0[ni]; + xe[0] = isvs0[ne]; + for (i = 0; i != 10; ++i) { + check_status(mgis_bv_integrate_material_data_manager( + &r, p, m, MGIS_BV_INTEGRATION_NO_TANGENT_OPERATOR, dt)); + check_status(mgis_bv_update_material_data_manager(m)); + xi[i + 1] = isvs1[ni]; + xe[i + 1] = isvs1[ne]; + } + check_status(mgis_model_free_model(&model)); + check_status(mgis_bv_free_material_data_manager(&m)); + check_status(mgis_free_thread_pool(&p)); + t = 0; + for (i = 0; i != 11; ++i) { + x_ref = exp(-A * t); + if (fabs(xi[i] - x_ref) > eps) { + fprintf(stderr, + "IntegrateTest: invalid value for x " + "at the first integration point" + "(expected '%g', computed '%g')\n", + x_ref, xi[i]); + return EXIT_FAILURE; + } + if (fabs(xe[i] - x_ref) > eps) { + fprintf(stderr, + "IntegrateTest: invalid value for x " + "at the first integration point" + "(expected '%g', computed '%g')\n", + x_ref, xe[i]); + return EXIT_FAILURE; + } + t += dt; + } + return EXIT_SUCCESS; +} diff --git a/bindings/c/tests/IntegrateTest5-c.c b/bindings/c/tests/IntegrateTest5-c.c new file mode 100644 index 000000000..f9b665437 --- /dev/null +++ b/bindings/c/tests/IntegrateTest5-c.c @@ -0,0 +1,109 @@ +/*! + * \file IntegrateTest4-c.c + * \brief + * \author Thomas Helfer + * \date 21/09/2018 + * \copyright (C) Copyright Thomas Helfer 2018. + * Use, modification and distribution are subject + * to one of the following licences: + * - GNU Lesser General Public License (LGPL), Version 3.0. (See accompanying + * file LGPL-3.0.txt) + * - CECILL-C, Version 1.0 (See accompanying files + * CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt). + */ + +#include +#include +#include +#include "MGIS/ThreadPool.h" +#include "MGIS/Model/Model.h" +#include "MGIS/Behaviour/BehaviourData.h" +#include "MGIS/Behaviour/Integrate.h" + +int test_status = EXIT_SUCCESS; +mgis_model_Model* model = NULL; +mgis_bv_BehaviourData* d = NULL; + +static void check_status(const mgis_status s) { + if (s.exit_status != MGIS_SUCCESS) { + fprintf(stderr, "invalid function call: %s\n", s.msg); + mgis_model_free_model(&model); + mgis_bv_free_behaviour_data(&d); + exit(EXIT_FAILURE); + } +} // end of check_status + +static int check(const int b, const char* const e) { + if (b == 0) { + test_status = EXIT_FAILURE; + fprintf(stderr, "%s\n", e); + } + return b; +} // end of check + +int main(const int argc, const char* const* argv) { + if (check(argc == 2, "expected two arguments") == 0) { + return EXIT_FAILURE; + } + const mgis_real eps = 1e-10; + const mgis_real dt =0.1; + mgis_bv_BehaviourDataView v; + mgis_size_type o; + mgis_real* isvs0; /* internal state variables at the beginning of the time step */ + mgis_real* isvs1; /* internal state variables at the end of the time step */ + mgis_bv_State* s0; /* state at the beginning of the time step */ + mgis_bv_State* s1; /* state at the end of the time step */ + mgis_real xvalues[11]; /* values of 'x' for the first integration point */ + mgis_real* x; + mgis_size_type idx; + mgis_size_type i; + mgis_real A; + mgis_real t; + mgis_real x_ref; + int r; + check_status(mgis_model_load(&model, argv[1], "ode_rk54", "Tridimensional")); + check_status(mgis_bv_behaviour_get_parameter_default_value(&A, model, "A")); + check_status(mgis_bv_allocate_behaviour_data(&d, model)); + check_status( + mgis_bv_behaviour_get_internal_state_variable_offset(&o, model, "x")); + check_status(mgis_bv_behaviour_data_get_state_0(&s0, d)); + check_status(mgis_bv_behaviour_data_get_state_1(&s1, d)); + /* initialize the internal state variable */ + mgis_bv_state_get_internal_state_variable_by_offset(&x, s1, o); + *x = 1; + /* initialize the external state variable */ + check_status(mgis_bv_state_set_external_state_variable_by_name( + s1, "Temperature", 293.15)); + /* copy s1 in s0 */ + check_status(mgis_bv_update_behaviour_data(d)); + // setting the time increment + check_status(mgis_bv_behaviour_data_set_time_increment(d, dt)); + // initializing the view + check_status(mgis_bv_make_behaviour_data_view(&v, d)); + // integration */ + xvalues[0] = *x; + for (i = 0; i != 10; ++i) { + v.K[0] = 0; + check_status(mgis_bv_integrate(&r, &v, model)); + check_status(mgis_bv_update_behaviour_data(d)); + xvalues[i+1] = *x; + } + // clean-up + check_status(mgis_model_free_model(&model)); + check_status(mgis_bv_free_behaviour_data(&d)); + // checks + t = 0; + for (i = 0; i != 11; ++i) { + x_ref = exp(-A * t); + if (fabs(xvalues[i] - x_ref) > eps) { + fprintf(stderr, + "IntegrateTest: invalid value for x " + "at the first integration point" + "(expected '%g', computed '%g')\n", + x_ref, xvalues[i]); + return EXIT_FAILURE; + } + t += dt; + } + return EXIT_SUCCESS; +} diff --git a/bindings/fortran/src/CMakeLists.txt b/bindings/fortran/src/CMakeLists.txt index 5419c7690..1f9386356 100644 --- a/bindings/fortran/src/CMakeLists.txt +++ b/bindings/fortran/src/CMakeLists.txt @@ -1,7 +1,8 @@ mgis_library(MFrontGenericInterface-fortran SHARED mgis_fortran_utilities.f95 mgis.f95 - mgis_behaviour.f95) + mgis_behaviour.f95 + mgis_model.f95) set_target_properties(MFrontGenericInterface-fortran PROPERTIES Fortran_MODULE_DIRECTORY "${CMAKE_BINARY_DIR}/bindings/fortran/modules") target_include_directories(MFrontGenericInterface-fortran diff --git a/bindings/fortran/src/mgis_behaviour.f95 b/bindings/fortran/src/mgis_behaviour.f95 index 149b3ee6d..fa01a91c4 100644 --- a/bindings/fortran/src/mgis_behaviour.f95 +++ b/bindings/fortran/src/mgis_behaviour.f95 @@ -52,7 +52,6 @@ module mgis_behaviour type(c_ptr) :: ptr = c_null_ptr end type FiniteStrainBehaviourOptions type :: Behaviour - private type(c_ptr) :: ptr = c_null_ptr end type Behaviour type :: BehaviourData @@ -2090,6 +2089,41 @@ end function state_get_internal_state_variable_by_offset_wrapper endif end function state_get_internal_state_variable_by_offset ! + function state_get_internal_state_variables(isvs, s, b) & + result(r) + use, intrinsic :: iso_c_binding, only: c_size_t, c_f_pointer + use mgis, only: mgis_status, MGIS_SUCCESS + use mgis_fortran_utilities + implicit none + interface + function state_get_internal_state_variables_wrapper(isvs_ptr, s) & + bind(c,name = 'mgis_bv_state_get_internal_state_variables') & + result(r) + use, intrinsic :: iso_c_binding, only: c_ptr, c_size_t + use mgis, only: mgis_status + type(c_ptr), intent(out) :: isvs_ptr + type(c_ptr), intent(in),value :: s + type(mgis_status) :: r + end function state_get_internal_state_variables_wrapper + end interface + real(kind=8), dimension(:), pointer, intent(out) :: isvs + type(State), intent(in) :: s + type(Behaviour), intent(in) :: b + type(mgis_status) :: r + type(c_ptr) isvs_ptr + integer n + nullify(isvs) + r = state_get_internal_state_variables_wrapper(isvs_ptr, s %ptr) + if( r%exit_status .ne. MGIS_SUCCESS) then + return + end if + r = behaviour_get_number_of_internal_state_variables(n, b) + if( r%exit_status .ne. MGIS_SUCCESS) then + return + end if + call c_f_pointer(isvs_ptr, isvs, [n]) + end function state_get_internal_state_variables + ! function state_set_external_state_variable_by_name(s, n, v) result(r) use mgis_fortran_utilities use mgis, only: mgis_status diff --git a/bindings/fortran/src/mgis_model.f95 b/bindings/fortran/src/mgis_model.f95 new file mode 100644 index 000000000..9dbf157bb --- /dev/null +++ b/bindings/fortran/src/mgis_model.f95 @@ -0,0 +1,53 @@ +module mgis_model + use mgis_behaviour + type, extends(Behaviour) :: Model + end type Model +contains + ! + function load(m,l,mn,h) result(s) + use mgis_fortran_utilities + use mgis, only: mgis_status + implicit none + interface + function load_wrapper(ptr,l,m,h) & + bind(c,name = 'mgis_model_load') result(r) + use, intrinsic :: iso_c_binding, only: c_char, c_ptr + use mgis, only: mgis_status + implicit none + type(c_ptr), intent(out) :: ptr + character(len=1,kind=c_char), dimension(*), intent(in) :: l + character(len=1,kind=c_char), dimension(*), intent(in) :: m + character(len=1,kind=c_char), dimension(*), intent(in) :: h + type(mgis_status) :: r + end function load_wrapper + end interface + type(Model), intent(out) :: m + character(len=*), intent(in) :: l + character(len=*), intent(in) :: mn + character(len=*), intent(in) :: h + type(mgis_status) :: s + s = load_wrapper(m%ptr, convert_fortran_string(l), & + convert_fortran_string(mn), & + convert_fortran_string(h)) + end function load + ! free behaviour + function free_model(ptr) result(r) + use, intrinsic :: iso_c_binding, only: c_associated + use mgis + implicit none + interface + function free_model_wrapper(ptr) bind(c, name='mgis_model_free_model') result(r) + use, intrinsic :: iso_c_binding, only: c_ptr + use mgis + implicit none + type(c_ptr), intent(inout) :: ptr + type(mgis_status) :: r + end function free_model_wrapper + end interface + type(Model), intent(inout) :: ptr + type(mgis_status) :: r + if (c_associated(ptr%ptr)) then + r = free_model_wrapper(ptr%ptr) + end if + end function free_model +end module mgis_model diff --git a/bindings/fortran/tests/CMakeLists.txt b/bindings/fortran/tests/CMakeLists.txt index ced620163..a5ac8a44e 100644 --- a/bindings/fortran/tests/CMakeLists.txt +++ b/bindings/fortran/tests/CMakeLists.txt @@ -24,7 +24,8 @@ function(test_fortran_bindings test) set_tests_properties(${test}_${conf}_f PROPERTIES ENVIRONMENT "MGIS_TEST_TFEL_VERSION=${TFEL_VERSION}" - "MGIS_TEST_BEHAVIOURS_LIBRARY=$") + "MGIS_TEST_BEHAVIOURS_LIBRARY=$" + "MGIS_TEST_MODELS_LIBRARY=$") endforeach(conf ${CMAKE_CONFIGURATION_TYPES}) else(CMAKE_CONFIGURATION_TYPES) add_test(NAME ${test}_f COMMAND ${test}_f) @@ -34,13 +35,15 @@ function(test_fortran_bindings test) PROPERTY ENVIRONMENT "MGIS_TEST_TFEL_VERSION=${TFEL_VERSION}" "PATH=$\;$\;$\;${MGIS_PATH_STRING}" - "MGIS_TEST_BEHAVIOURS_LIBRARY=$") + "MGIS_TEST_BEHAVIOURS_LIBRARY=$" + "MGIS_TEST_MODELS_LIBRARY=$") else((CMAKE_HOST_WIN32) AND (NOT MSYS)) set_property(TEST ${test}_f PROPERTY DEPENDS BehaviourTest PROPERTY ENVIRONMENT "MGIS_TEST_TFEL_VERSION=${TFEL_VERSION}" - "MGIS_TEST_BEHAVIOURS_LIBRARY=$") + "MGIS_TEST_BEHAVIOURS_LIBRARY=$" + "MGIS_TEST_MODELS_LIBRARY=$") endif((CMAKE_HOST_WIN32) AND (NOT MSYS)) add_dependencies(check ${test}_f) endif(CMAKE_CONFIGURATION_TYPES) @@ -56,6 +59,8 @@ test_fortran_bindings(StateTest2-f) test_fortran_bindings(IntegrateTest-f) test_fortran_bindings(IntegrateTest2-f) test_fortran_bindings(IntegrateTest3-f) +test_fortran_bindings(IntegrateTest4-f) +test_fortran_bindings(IntegrateTest5-f) test_fortran_bindings(ParameterTest-f) test_fortran_bindings(BoundsCheckTest-f) test_fortran_bindings(RotateFunctionsTest-f) diff --git a/bindings/fortran/tests/IntegrateTest4-f.f95 b/bindings/fortran/tests/IntegrateTest4-f.f95 new file mode 100644 index 000000000..3470f6157 --- /dev/null +++ b/bindings/fortran/tests/IntegrateTest4-f.f95 @@ -0,0 +1,93 @@ +subroutine test() + use mgis + use mgis_behaviour + use mgis_model + use mgis_testing_utilities + implicit none + type(ThreadPool) p + type(Behaviour) mo + type(MaterialDataManager) m + type(MaterialStateManager) s0,s1 + real(kind=8) A + real(kind=8) eps + real(kind=8) t ! current time + real(kind=8) dt ! time step + real(kind=8) x_ref + real(kind=8), dimension(11) ::xi ! computed values of x + real(kind=8), dimension(11) ::xe ! computed values of x + real(kind=8), dimension (:,:), pointer :: isvs => null() + integer :: n_g ! gradients stride + integer :: n_isvs ! gradients stride + integer :: n = 100 ! index + integer :: i, j ! index + integer :: o ! offset of the x + integer :: ri ! returned value of a behaviour integration + logical :: r + ! + eps = 1e-10 + ! creation of the thread pool + call check_status(create_thread_pool(p, 2)) + ! start of the check + call check_status(load_behaviour(mo, & + get_mfront_model_test_library_path(), & + 'ode_rk54', 'Tridimensional')) + call check_status(behaviour_get_parameter_default_value(A, mo, 'A')) + ! allocating data + call check_status(create_material_data_manager(m, mo, n)) + ! state at the beginning of the time step + call check_status(material_data_manager_get_state_0(s0, m)) + ! state at the end of the time step + call check_status(material_data_manager_get_state_1(s1, m)) + ! + call check_status(behaviour_get_internal_state_variable_offset( & + o, mo, 'x')) + ! initialize the external state variable + call check_status(material_state_manager_set_uniform_external_state_variable( & + s1, "Temperature", 293.15d0)) + ! Getting a pointer to the internal state variables. + call check_status(material_state_manager_get_internal_state_variables(isvs,s1)) + ! initial value of the x + do i = 1, N + isvs(o, 1) = 1 + end do + ! copy s1 in s0 + call check_status(update_material_data_manager(m)) + ! initial value of the x + xi(1) = isvs(o, 1) + xe(1) = isvs(o, n) + ! time step + dt = 0.1d0 + ! integration + do j = 1, 10 + call check_status(integrate_material_data_manager( & + ri, p, m, INTEGRATION_NO_TANGENT_OPERATOR, dt)) + r = check(ri.eq.1, 'integration failed') + call check_status(update_material_data_manager(m)) + xi(j+1) = isvs(o, 1) + xe(j+1) = isvs(o, n) + end do + ! check results + t = 0d0 + do i = 1, 11 + x_ref = exp(-A * t) + r = check(abs(xi(i)-x_ref) < eps, & + 'invalid value for x') + r = check(abs(xi(i)-x_ref) < eps, & + 'invalid value for x') + t = t + dt + end do + ! free ressources + call check_status(free_material_data_manager(m)) + call check_status(free_behaviour(mo)) + call check_status(free_thread_pool(p)) +end subroutine test + +program main + use mgis_testing_utilities + call test() + call tests_summary() + if(.not. status) then + stop -1 + end if +end program main + diff --git a/bindings/fortran/tests/IntegrateTest5-f.f95 b/bindings/fortran/tests/IntegrateTest5-f.f95 new file mode 100644 index 000000000..7a4835a83 --- /dev/null +++ b/bindings/fortran/tests/IntegrateTest5-f.f95 @@ -0,0 +1,79 @@ +subroutine test() + use mgis + use mgis_behaviour + use mgis_model + use mgis_testing_utilities + implicit none + type(Behaviour) mo + type(BehaviourData) d + type(State) s1 + real(kind=8) A + real(kind=8) eps + real(kind=8) t ! current time + real(kind=8) dt ! time step + real(kind=8) x_ref + real(kind=8), dimension(11) ::xvalues ! computed values of x + real(kind=8), dimension (:), pointer :: isvs => null() + integer :: i, j ! index + integer :: o ! offset of the x + integer :: ri ! returned value of a behaviour integration + logical :: r + ! + eps = 1e-10 + ! start of the check + call check_status(load_behaviour(mo, & + get_mfront_model_test_library_path(), & + 'ode_rk54', 'Tridimensional')) + call check_status(behaviour_get_parameter_default_value(A, mo, 'A')) + ! allocating data + call check_status(allocate_behaviour_data(d, mo)) + ! state at the end of the time step + call check_status(behaviour_data_get_state_1(s1, d)) + ! + call check_status(behaviour_get_internal_state_variable_offset( & + o, mo, 'x')) + ! initialize the external state variable + call check_status(state_set_external_state_variable_by_name( & + s1, "Temperature", 293.15d0)) + ! Getting the value of the internal state variable. + call check_status(state_get_internal_state_variables(isvs, s1, mo)) + ! initial value of the x + isvs(o) = 1 + ! copy s1 in s0 + call check_status(update_behaviour_data(d)) + ! initial value of the x + xvalues(1) = isvs(o) + ! time step + dt = 0.1d0 + ! setting the time increment + call check_status(behaviour_data_set_time_increment(d, dt)) + ! integration + do j = 1, 10 + call check_status(integrate(ri, d, mo)) + r = check(ri.eq.1, 'integration failed') + call check_status(update_behaviour_data(d)) + ! Getting the value of the internal state variable. + xvalues(j+1) = isvs(o) + end do + ! check results + t = 0d0 + do i = 1, 11 + x_ref = exp(-A * t) + r = check(abs(xvalues(i)-x_ref) < eps, & + 'invalid value for x') + t = t + dt + end do + ! free ressources + call check_status(free_behaviour_data(d)) + call check_status(free_behaviour(mo)) +end subroutine test + +program main + use mgis_testing_utilities + call test() + call tests_summary() + if(.not. status) then + stop -1 + end if +end program main + diff --git a/bindings/fortran/tests/mgis_testing_utilities.c b/bindings/fortran/tests/mgis_testing_utilities.c index 76e2c8daf..a4739d665 100644 --- a/bindings/fortran/tests/mgis_testing_utilities.c +++ b/bindings/fortran/tests/mgis_testing_utilities.c @@ -17,6 +17,10 @@ const char* mgis_get_mfront_behaviour_test_library_path(){ return getenv("MGIS_TEST_BEHAVIOURS_LIBRARY"); } // end of mgis_get_mfront_behaviour_test_library_path +const char* mgis_get_mfront_model_test_library_path(){ + return getenv("MGIS_TEST_MODELS_LIBRARY"); +} // end of mgis_get_mfront_model_test_library_path + const char* mgis_get_tfel_version(){ return getenv("MGIS_TEST_TFEL_VERSION"); } // end of mgis_get_mfront_behaviour_test_library diff --git a/bindings/fortran/tests/mgis_testing_utilities.f95 b/bindings/fortran/tests/mgis_testing_utilities.f95 index 56da87e9a..9f8e286cc 100644 --- a/bindings/fortran/tests/mgis_testing_utilities.f95 +++ b/bindings/fortran/tests/mgis_testing_utilities.f95 @@ -21,6 +21,22 @@ end function mgis_get_mfront_behaviour_test_library_path_wrapper l = convert_c_string(mgis_get_mfront_behaviour_test_library_path_wrapper()) end function get_mfront_behaviour_test_library_path ! + function get_mfront_model_test_library_path() result(l) + use, intrinsic :: ISO_C_BINDING, only: c_ptr + use mgis_fortran_utilities + implicit none + interface + function mgis_get_mfront_model_test_library_path_wrapper() & + bind(c,name = 'mgis_get_mfront_model_test_library_path') result(l) + import c_ptr + implicit none + type(c_ptr) :: l + end function mgis_get_mfront_model_test_library_path_wrapper + end interface + character(len=:), allocatable :: l + l = convert_c_string(mgis_get_mfront_model_test_library_path_wrapper()) + end function get_mfront_model_test_library_path + ! function get_tfel_version() result(l) use, intrinsic :: ISO_C_BINDING, only: c_ptr use mgis_fortran_utilities diff --git a/bindings/python/src/CMakeLists.txt b/bindings/python/src/CMakeLists.txt index 9c56fb4e2..3f1829568 100644 --- a/bindings/python/src/CMakeLists.txt +++ b/bindings/python/src/CMakeLists.txt @@ -85,3 +85,8 @@ mgis_python_module(mgis_behaviour behaviour MaterialStateManager.cxx Integrate.cxx FiniteStrainSupport.cxx) + +mgis_python_module(mgis_model model + model-module.cxx + Model.cxx) + diff --git a/bindings/python/src/Model.cxx b/bindings/python/src/Model.cxx new file mode 100644 index 000000000..91ec35d4e --- /dev/null +++ b/bindings/python/src/Model.cxx @@ -0,0 +1,26 @@ +/*! + * \file bindings/python/src/Model.cxx + * \brief + * \author Thomas Helfer + * \date 06/11/2018 + * \copyright (C) Copyright Thomas Helfer 2018. + * Use, modification and distribution are subject + * to one of the following licences: + * - GNU Lesser General Public License (LGPL), Version 3.0. (See accompanying + * file LGPL-3.0.txt) + * - CECILL-C, Version 1.0 (See accompanying files + * CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt). + */ + +#include +#include +#include "MGIS/Raise.hxx" +#include "MGIS/Model/Model.hxx" + +// forward declaration +void declareModel(); + +void declareModel() { + // wrapping free functions + boost::python::def("load", mgis::model::load); +} // end of declareModel diff --git a/bindings/python/src/model-module.cxx b/bindings/python/src/model-module.cxx new file mode 100644 index 000000000..2acb91f41 --- /dev/null +++ b/bindings/python/src/model-module.cxx @@ -0,0 +1,22 @@ +/*! + * \file bindings/python/src/model-module.cxx + * \brief + * \author Thomas Helfer + * \date 14/11/2021 + * \copyright (C) Copyright Thomas Helfer 2018. + * Use, modification and distribution are subject + * to one of the following licences: + * - GNU Lesser General Public License (LGPL), Version 3.0. (See accompanying + * file LGPL-3.0.txt) + * - CECILL-C, Version 1.0 (See accompanying files + * CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt). + */ + +#include + +// forward declaration +void declareModel(); + +BOOST_PYTHON_MODULE(model) { + declareModel(); +} // end of module model diff --git a/bindings/python/tests/CMakeLists.txt b/bindings/python/tests/CMakeLists.txt index e13c1f390..eef3aaa7a 100644 --- a/bindings/python/tests/CMakeLists.txt +++ b/bindings/python/tests/CMakeLists.txt @@ -18,6 +18,7 @@ else(CMAKE_CONFIGURATION_TYPES) COMMAND ${CMAKE_COMMAND} -E create_symlink "${PROJECT_SOURCE_DIR}/bindings/python/mgis/__init__.py" "mgis/__init__.py" COMMAND ${CMAKE_COMMAND} -E create_symlink "$" "mgis/$" COMMAND ${CMAKE_COMMAND} -E create_symlink "$" "mgis/$" + COMMAND ${CMAKE_COMMAND} -E create_symlink "$" "mgis/$" ) endif(CMAKE_CONFIGURATION_TYPES) add_dependencies(mgis_python_bindings_checkfiles py_mgis_behaviour) @@ -34,7 +35,8 @@ function(test_python_bindings test) set_tests_properties(${test}_${conf}_py PROPERTIES ENVIRONMENT PYTHONPATH="${PROJECT_BINARY_DIR}/bindings/python/tests/;$ENV{PYTHONPATH}" - MGIS_TEST_BEHAVIOURS_LIBRARY="$") + MGIS_TEST_BEHAVIOURS_LIBRARY="$" + MGIS_TEST_MODELS_LIBRARY="$") endforeach(conf ${CMAKE_CONFIGURATION_TYPES}) else(CMAKE_CONFIGURATION_TYPES) add_test(NAME ${test}_py @@ -43,6 +45,7 @@ function(test_python_bindings test) PROPERTY ENVIRONMENT PYTHONPATH=${PROJECT_BINARY_DIR}/bindings/python/tests/;$ENV{PYTHONPATH} MGIS_TEST_BEHAVIOURS_LIBRARY=$ + MGIS_TEST_MODELS_LIBRARY=$ MGIS_TEST_TFEL_VERSION=${TFEL_VERSION}) endif(CMAKE_CONFIGURATION_TYPES) endfunction(test_python_bindings) @@ -56,4 +59,6 @@ test_python_bindings(IntegrateTest) test_python_bindings(IntegrateTest2) test_python_bindings(IntegrateTest3) test_python_bindings(IntegrateTest4) +test_python_bindings(IntegrateTest5) +test_python_bindings(IntegrateTest6) diff --git a/bindings/python/tests/IntegrateTest4.py b/bindings/python/tests/IntegrateTest4.py index 430d84dae..7c2fe6cc2 100644 --- a/bindings/python/tests/IntegrateTest4.py +++ b/bindings/python/tests/IntegrateTest4.py @@ -9,7 +9,7 @@ import mgis.behaviour as mgis_bv -class IntegrateTest2(unittest.TestCase): +class IntegrateTest4(unittest.TestCase): def test_pass(self): # path to the test library @@ -42,7 +42,6 @@ def test_pass(self): dt = 180 # setting the temperature T = 293.15 * numpy.ones(nig) - print("type: {}".format(type(T))) # type of storage Ts = mgis_bv.MaterialStateManagerStorageMode.ExternalStorage mgis_bv.setExternalStateVariable(m.s1, 'Temperature', T, Ts) diff --git a/bindings/python/tests/IntegrateTest5.py b/bindings/python/tests/IntegrateTest5.py new file mode 100644 index 000000000..ddaebd919 --- /dev/null +++ b/bindings/python/tests/IntegrateTest5.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- + +import os +import math +import numpy +try: + import unittest2 as unittest +except ImportError: + import unittest +import mgis.behaviour as mgis_bv +import mgis.model + + +class IntegrateTest5(unittest.TestCase): + def test_pass(self): + + # path to the test library + lib = os.environ['MGIS_TEST_MODELS_LIBRARY'] + # modelling hypothesis + h = mgis_bv.Hypothesis.Tridimensional + # loading the behaviour + model = mgis.model.load(lib, 'ode_rk54', h) + # default value of parameter A + A = model.getParameterDefaultValue('A') + # number of integration points + nig = 100 + # material data manager + m = mgis_bv.MaterialDataManager(model, nig) + # index of x in the array of state variable + o = mgis_bv.getVariableOffset(model.isvs, 'x', h) + # time step increment + dt = 0.1 + # setting the temperature + T = 293.15 * numpy.ones(nig) + # type of storage + Ts = mgis_bv.MaterialStateManagerStorageMode.ExternalStorage + mgis_bv.setExternalStateVariable(m.s1, 'Temperature', T, Ts) + # Initial value of x + for n in range(0, nig): + m.s1.internal_state_variables[n][o] = 1 + # copy d.s1 in d.s0 + mgis_bv.update(m) + # index of the first integration point + ni = 0 + # index of the last integration point + ne = nig - 1 + # values of x for the first integration point + xi = [m.s0.internal_state_variables[ni][o]] + # values of x for the last integration point + xe = [m.s0.internal_state_variables[ne][o]] + # integration + for i in range(0, 10): + it = mgis_bv.IntegrationType.IntegrationWithoutTangentOperator + mgis_bv.integrate(m, it, dt, 0, m.n) + mgis_bv.update(m) + xi.append(m.s1.internal_state_variables[ni][o]) + xe.append(m.s1.internal_state_variables[ne][o]) + # checks + # comparison criterion + eps = 1.e-10 + t = 0 + for i in range(0, 11): + x_ref = math.exp(-A * t) + self.assertTrue(abs(xi[i] - x_ref) < eps) + self.assertTrue(abs(xe[i] - x_ref) < eps) + t = t + dt + + pass + + +if __name__ == '__main__': + unittest.main() diff --git a/bindings/python/tests/IntegrateTest6.py b/bindings/python/tests/IntegrateTest6.py new file mode 100644 index 000000000..efe0db840 --- /dev/null +++ b/bindings/python/tests/IntegrateTest6.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- + +import os +import math +import numpy +try: + import unittest2 as unittest +except ImportError: + import unittest +import mgis.behaviour as mgis_bv +import mgis.model + + +class IntegrateTest6(unittest.TestCase): + def test_pass(self): + + # path to the test library + lib = os.environ['MGIS_TEST_MODELS_LIBRARY'] + # modelling hypothesis + h = mgis_bv.Hypothesis.Tridimensional + # loading the behaviour + model = mgis.model.load(lib, 'ode_rk54', h) + # default value of parameter A + A = model.getParameterDefaultValue('A') + # material data manager + d = mgis_bv.BehaviourData(model) + # index of x in the array of state variable + o = mgis_bv.getVariableOffset(model.isvs, 'x', h) + # time step increment + d.dt = 0.1 + # type of storage + mgis_bv.setExternalStateVariable(d.s1, 'Temperature', 293.15) + # Initial value of x + d.s1.internal_state_variables[o] = 1 + # copy d.s1 in d.s0 + mgis_bv.update(d) + # values of x + xvalues = [d.s0.internal_state_variables[o]] + # integration + for i in range(0, 10): + mgis_bv.integrate(d, model) + mgis_bv.update(d) + xvalues.append(d.s1.internal_state_variables[o]) + # checks + # comparison criterion + eps = 1.e-10 + t = 0 + for i in range(0, 11): + x_ref = math.exp(-A * t) + self.assertTrue(abs(xvalues[i] - x_ref) < eps) + t = t + d.dt + + pass + + +if __name__ == '__main__': + unittest.main() diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index a70bb34b3..a6d3f3683 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -30,4 +30,5 @@ mgis_header(MGIS/Behaviour MaterialStateManager.hxx) mgis_header(MGIS/Behaviour MaterialDataManager.hxx) mgis_header(MGIS/Behaviour Integrate.hxx) mgis_header(MGIS/Behaviour Integrate.ixx) -mgis_header(MGIS/Behaviour FiniteStrainSupport.hxx) \ No newline at end of file +mgis_header(MGIS/Behaviour FiniteStrainSupport.hxx) +mgis_header(MGIS/Model Model.hxx) diff --git a/include/MGIS/Model/Model.hxx b/include/MGIS/Model/Model.hxx new file mode 100644 index 000000000..7c7738649 --- /dev/null +++ b/include/MGIS/Model/Model.hxx @@ -0,0 +1,47 @@ +/*! + * \file include/MGIS/Model/Model.hxx + * \brief + * \author Thomas Helfer + * \date 14/10/2021 + * \copyright (C) Copyright Thomas Helfer 2018. + * Use, modification and distribution are subject + * to one of the following licences: + * - GNU Lesser General Public License (LGPL), Version 3.0. (See accompanying + * file LGPL-3.0.txt) + * - CECILL-C, Version 1.0 (See accompanying files + * CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt). + */ + +#ifndef LIB_MGIS_MODEL_MODEL_HXX +#define LIB_MGIS_MODEL_MODEL_HXX + +#include "MGIS/Config.hxx" +#include "MGIS/Behaviour/Behaviour.hxx" + +namespace mgis::model { + + /*! + * \brief a simple alias + * + * In `MGIS`, a model is a behaviour without gradients, thermodynamic forces + * nor tangent operator blocks. + */ + using Model = mgis::behaviour::Behaviour; + + /*! + * \brief load the description of a model from a library + * + * \param[in] l: library name + * \param[in] m: model name + * \param[in] h: modelling hypothesis + * \return the model description + * \note: use of `std::string` rather than `mgis::string_view` is + * meaningfull here + */ + MGIS_EXPORT Model load(const std::string &, + const std::string &, + const mgis::behaviour::Hypothesis); + +} // namespace mgis::model + +#endif /* LIB_MGIS_MODEL_MODEL_HXX */ diff --git a/src/BehaviourData.cxx b/src/BehaviourData.cxx index 0690e2930..cbe0a9a0a 100644 --- a/src/BehaviourData.cxx +++ b/src/BehaviourData.cxx @@ -40,7 +40,7 @@ namespace mgis { : dt(0), rdt(1), speed_of_sound(0), s0(b), s1(s0) { static char error_message_buffer[512]; this->error_message = error_message_buffer; - this->K.resize(getTangentOperatorArraySize(b)); + this->K.resize(std::max(getTangentOperatorArraySize(b), mgis::size_type{1})); } // end of Behaviour::Behaviour void update(BehaviourData& d) { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 472c63bdc..74f783717 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,7 +14,8 @@ mgis_library(MFrontGenericInterface SHARED MaterialStateManager.cxx MaterialDataManager.cxx Integrate.cxx - FiniteStrainSupport.cxx) + FiniteStrainSupport.cxx + Model.cxx) target_include_directories(MFrontGenericInterface PUBLIC $ diff --git a/src/Integrate.cxx b/src/Integrate.cxx index 4312b9f39..55211b40b 100644 --- a/src/Integrate.cxx +++ b/src/Integrate.cxx @@ -174,8 +174,9 @@ namespace mgis { v.error_message[0] = '\0'; v.rdt = &rdt; v.dt = dt; - if (opts.integration_type != - IntegrationType::INTEGRATION_NO_TANGENT_OPERATOR) { + if ((opts.integration_type != + IntegrationType::INTEGRATION_NO_TANGENT_OPERATOR) && + (m.K_stride != 0)) { v.K = m.K.data() + m.K_stride * i; } else { v.K = &bopts[0]; diff --git a/src/Model.cxx b/src/Model.cxx new file mode 100644 index 000000000..266dad54e --- /dev/null +++ b/src/Model.cxx @@ -0,0 +1,40 @@ +/*! + * \file src/Model.cxx + * \brief + * \author Thomas Helfer + * \date 14/10/2021 + * \copyright (C) Copyright Thomas Helfer 2018. + * Use, modification and distribution are subject + * to one of the following licences: + * - GNU Lesser General Public License (LGPL), Version 3.0. (See accompanying + * file LGPL-3.0.txt) + * - CECILL-C, Version 1.0 (See accompanying files + * CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt). + */ + +#include "MGIS/Raise.hxx" +#include "MGIS/Model/Model.hxx" + +namespace mgis::model { + + Model load(const std::string &l, + const std::string &m, + const mgis::behaviour::Hypothesis h) { + const auto model = mgis::behaviour::load(l, m, h); + auto throw_if = [&l, &m](const bool c, const char *const type) { + if (c) { + auto msg = std::string{ + "mgis::model::loadModel: " + "model '" + + m + "' in library '" + l + "' shall not declare any "}; + msg += type; + mgis::raise(type); + } + }; + throw_if(!model.gradients.empty(), "gradient"); + throw_if(!model.thermodynamic_forces.empty(), "thermodynamic force"); + throw_if(!model.to_blocks.empty(), "tangent operator block"); + return model; + } // end of load + +} // namespace mgis::model diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6a4044fe3..7c61d7814 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -12,6 +12,9 @@ mfront_behaviours_check_library(BehaviourTest FiniteStrainSingleCrystal StandardElastoViscoPlasticityPlasticityTest11) +mfront_behaviours_check_library(ModelTest + ode_rk54) + add_executable(MFrontGenericBehaviourInterfaceTest EXCLUDE_FROM_ALL MFrontGenericBehaviourInterfaceTest.cxx) @@ -72,6 +75,14 @@ add_executable(IntegrateTest3b EXCLUDE_FROM_ALL IntegrateTest3b.cxx) target_link_libraries(IntegrateTest3b PRIVATE MFrontGenericInterface) +add_executable(IntegrateTest4 + EXCLUDE_FROM_ALL IntegrateTest4.cxx) +target_link_libraries(IntegrateTest4 + PRIVATE MFrontGenericInterface) +add_executable(IntegrateTest5 + EXCLUDE_FROM_ALL IntegrateTest5.cxx) +target_link_libraries(IntegrateTest5 + PRIVATE MFrontGenericInterface) add_executable(RotateFunctionsTest EXCLUDE_FROM_ALL RotateFunctionsTest.cxx) target_link_libraries(RotateFunctionsTest @@ -213,3 +224,27 @@ else((CMAKE_HOST_WIN32) AND (NOT MSYS)) set_property(TEST RotateFunctionsTest PROPERTY DEPENDS BehaviourTest) endif((CMAKE_HOST_WIN32) AND (NOT MSYS)) + +add_test(NAME IntegrateTest4 + COMMAND IntegrateTest4 "$") +add_dependencies(check IntegrateTest4) +if((CMAKE_HOST_WIN32) AND (NOT MSYS)) + set_property(TEST IntegrateTest4 + PROPERTY DEPENDS ModelTest + PROPERTY ENVIRONMENT "PATH=$\;${MGIS_PATH_STRING}") +else((CMAKE_HOST_WIN32) AND (NOT MSYS)) + set_property(TEST IntegrateTest4 + PROPERTY DEPENDS ModelTest) +endif((CMAKE_HOST_WIN32) AND (NOT MSYS)) + +add_test(NAME IntegrateTest5 + COMMAND IntegrateTest5 "$") +add_dependencies(check IntegrateTest5) +if((CMAKE_HOST_WIN32) AND (NOT MSYS)) + set_property(TEST IntegrateTest5 + PROPERTY DEPENDS ModelTest + PROPERTY ENVIRONMENT "PATH=$\;${MGIS_PATH_STRING}") +else((CMAKE_HOST_WIN32) AND (NOT MSYS)) + set_property(TEST IntegrateTest5 + PROPERTY DEPENDS ModelTest) +endif((CMAKE_HOST_WIN32) AND (NOT MSYS)) diff --git a/tests/IntegrateTest4.cxx b/tests/IntegrateTest4.cxx new file mode 100644 index 000000000..e59ae3dd2 --- /dev/null +++ b/tests/IntegrateTest4.cxx @@ -0,0 +1,94 @@ +/*! + * \file tests/IntegrateTest4.cxx + * \brief + * \author Thomas Helfer + * \date 14/11/2021 + * \copyright (C) Copyright Thomas Helfer 2018. + * Use, modification and distribution are subject + * to one of the following licences: + * - GNU Lesser General Public License (LGPL), Version 3.0. (See accompanying + * file LGPL-3.0.txt) + * - CECILL-C, Version 1.0 (See accompanying files + * CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt). + */ + +#include +#include +#include +#include +#include "MGIS/Behaviour/State.hxx" +#include "MGIS/Behaviour/Behaviour.hxx" +#include "MGIS/Behaviour/MaterialDataManager.hxx" +#include "MGIS/ThreadPool.hxx" +#include "MGIS/Model/Model.hxx" +#include "MGIS/Behaviour/Integrate.hxx" + +int main(const int argc, const char* const* argv) { + using namespace mgis; + using namespace mgis::behaviour; + if (argc != 2) { + std::cerr << "IntegrateTest: invalid number of arguments\n"; + std::exit(-1); + } + try { + const auto model = + mgis::model::load(argv[1], "ode_rk54", Hypothesis::TRIDIMENSIONAL); + const auto A = getParameterDefaultValue(model, "A"); + ThreadPool p{2}; + MaterialDataManager m{model, 100}; + const auto o = getVariableOffset(model.isvs, "x", model.hypothesis); + // initialize the internal state variable + auto pos = o; + auto& isvs = m.s1.internal_state_variables; + for (size_type i = 0; i != 100; ++i) { + isvs[pos] = 1; + pos += m.s1.internal_state_variables_stride; + } + // initialize the external state variable + m.s1.external_state_variables["Temperature"] = 293.15; + // copy d.s1 in d.s0 + update(m); + // values of x for the first integration point + auto xvi = std::array{}; + // values of x for the last integration point + auto xve = std::array{}; + const auto ni = size_type{o}; + const auto ne = + size_type{(m.n - 1) * m.s0.internal_state_variables_stride + o}; + xvi[0] = m.s0.internal_state_variables[ni]; + xve[0] = m.s0.internal_state_variables[ne]; + const auto dt = real(0.1); + for (size_type i = 0; i != 10; ++i) { + integrate(p, m, IntegrationType::INTEGRATION_NO_TANGENT_OPERATOR, dt); + update(m); + xvi[i + 1] = m.s1.internal_state_variables[ni]; + xve[i + 1] = m.s1.internal_state_variables[ne]; + } + std::cerr.precision(14); + auto t = mgis::real{}; + for (size_type i = 0; i != 10; ++i) { + constexpr auto eps = mgis::real{1e-10}; + const auto x_ref = exp(-A * t); + if (std::abs(xvi[i] - x_ref) > eps) { + std::cerr << "IntegrateTest: invalid value for x " + << " at the first integration point" + << "(expected '" << x_ref << "', computed '" << xvi[i] + << "')\n"; + return EXIT_FAILURE; + } + if (std::abs(xve[i] - x_ref) > eps) { + std::cerr << "IntegrateTest: invalid value for x " + << "at the last integration point" + << "(expected '" << x_ref << "', computed '" << xve[i] + << "')\n"; + return EXIT_FAILURE; + } + t += dt; + } + } catch (std::exception& e) { + std::cerr << e.what() << '\n'; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + diff --git a/tests/IntegrateTest5.cxx b/tests/IntegrateTest5.cxx new file mode 100644 index 000000000..a266ff924 --- /dev/null +++ b/tests/IntegrateTest5.cxx @@ -0,0 +1,78 @@ +/*! + * \file tests/IntegrateTest5.cxx + * \brief + * \author Thomas Helfer + * \date 14/11/2021 + * \copyright (C) Copyright Thomas Helfer 2018. + * Use, modification and distribution are subject + * to one of the following licences: + * - GNU Lesser General Public License (LGPL), Version 3.0. (See accompanying + * file LGPL-3.0.txt) + * - CECILL-C, Version 1.0 (See accompanying files + * CeCILL-C_V1-en.txt and CeCILL-C_V1-fr.txt). + */ + +#include +#include +#include +#include +#include "MGIS/Behaviour/State.hxx" +#include "MGIS/Behaviour/Behaviour.hxx" +#include "MGIS/Behaviour/BehaviourData.hxx" +#include "MGIS/Model/Model.hxx" +#include "MGIS/Behaviour/Integrate.hxx" + +int main(const int argc, const char* const* argv) { + using namespace mgis; + using namespace mgis::behaviour; + if (argc != 2) { + std::cerr << "IntegrateTest: invalid number of arguments\n"; + std::exit(-1); + } + try { + const auto model = + mgis::model::load(argv[1], "ode_rk54", Hypothesis::TRIDIMENSIONAL); + const auto A = getParameterDefaultValue(model, "A"); + auto d = BehaviourData{model}; + const auto o = getVariableOffset(model.isvs, "x", model.hypothesis); + // initialize the internal state variable + d.s1.internal_state_variables[o] = 1; + // initialize the external state variable + setExternalStateVariable(d.s1, "Temperature", 293.15); + // copy d.s1 in d.s0 + update(d); + // values of 'x' at each time step + auto xvalues = std::array{}; + xvalues[0] = d.s0.internal_state_variables[o]; + const auto dt = real(0.1); + d.K[0] = 0; + for (size_type i = 0; i != 10; ++i) { + d.dt = dt; + auto v = make_view(d); + if (integrate(v, model) != 1) { + return EXIT_FAILURE; + } + update(d); + xvalues[i + 1] = d.s1.internal_state_variables[o]; + } + std::cerr.precision(14); + auto t = mgis::real{}; + for (size_type i = 0; i != 10; ++i) { + constexpr auto eps = mgis::real{1e-10}; + const auto x_ref = exp(-A * t); + if (std::abs(xvalues[i] - x_ref) > eps) { + std::cerr << "IntegrateTest: invalid value for x " + << "at the first integration point" + << "(expected '" << x_ref << "', computed '" << xvalues[i] + << "')\n"; + return EXIT_FAILURE; + } + t += dt; + } + } catch (std::exception& e) { + std::cerr << e.what() << '\n'; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + diff --git a/tests/ode_rk54.mfront b/tests/ode_rk54.mfront new file mode 100644 index 000000000..a7ba6fd7f --- /dev/null +++ b/tests/ode_rk54.mfront @@ -0,0 +1,14 @@ +@DSL RungeKuttaModelDSL; +@Model ode_rk54; +@Author Thomas Helfer; +@Date 21 / 09 / 2021; + +@UseQt true; +@Epsilon 1.e-11; + +@StateVariable real x; +@Parameter frequency A = 1.2; + +@Derivative { + dx = -A * x; +}