├── .github └── workflows │ ├── clang.yml │ ├── gcc.yml │ └── msvc_2022.yml ├── .gitignore ├── CMakeLists.txt ├── Doxyfile ├── LICENSE ├── README.md ├── cmake └── ascentConfig.cmake.in ├── examples ├── CMakeLists.txt ├── airy │ ├── CMakeLists.txt │ └── airy.cpp ├── lorenz │ ├── CMakeLists.txt │ └── lorenz.cpp ├── modular-spring-damper │ ├── Body.h │ ├── CMakeLists.txt │ ├── Damper.h │ ├── Main.cpp │ └── Spring.h ├── pliny-fountain │ ├── CMakeLists.txt │ └── fountain.cpp └── sampling │ ├── CMakeLists.txt │ └── sampling.cpp ├── include ├── CMakeLists.txt └── ascent │ ├── Ascent.h │ ├── ChaiEngine.h │ ├── Param.h │ ├── ParamV.h │ ├── Recorder.h │ ├── System.h │ ├── Utility.h │ ├── Vector.h │ ├── algorithms │ └── Derivative.h │ ├── containers │ ├── flat_id_map.h │ └── stack.h │ ├── direct │ └── State.h │ ├── integrators │ ├── ABM4.h │ ├── DOPRI45.h │ ├── Euler.h │ ├── Midpoint.h │ ├── PC233.h │ ├── RK2.h │ ├── RK4.h │ ├── RKMM.h │ └── RTAM4.h │ ├── integrators_direct │ ├── Euler.h │ └── RK4.h │ ├── integrators_modular │ ├── ABM4.h │ ├── DOPRI45.h │ ├── Euler.h │ ├── Heun.h │ ├── Midpoint.h │ ├── ModularIntegrators.h │ ├── NCRK4.h │ ├── PC233.h │ ├── RK2.h │ ├── RK3.h │ ├── RK4.h │ ├── RTAM2.h │ ├── RTAM3.h │ ├── RTAM4.h │ ├── Ralston4.h │ └── VABM.h │ ├── modular │ ├── Link.h │ └── Module.h │ ├── threading │ └── Pool.h │ └── timing │ ├── Sampler.h │ ├── TimeAdvanced.h │ └── Timing.h └── unit_tests ├── CMakeLists.txt └── src └── main.cpp /.github/workflows/clang.yml: -------------------------------------------------------------------------------- 1 | name: clang 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - feature/* 8 | paths-ignore: 9 | - '**/*.md' 10 | - 'docs/**' 11 | pull_request: 12 | branches: 13 | - main 14 | paths-ignore: 15 | - '**/*.md' 16 | - 'docs/**' 17 | workflow_dispatch: 18 | 19 | env: 20 | BUILD_TYPE: Debug 21 | 22 | jobs: 23 | build: 24 | runs-on: macos-latest 25 | 26 | steps: 27 | - uses: actions/checkout@v4 28 | 29 | - uses: maxim-lobanov/setup-xcode@v1 30 | with: 31 | xcode-version: latest-stable 32 | 33 | - name: Configure CMake 34 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} 35 | 36 | - name: Build 37 | run: cmake --build build --config ${{env.BUILD_TYPE}} -j 3 38 | 39 | - name: Test 40 | working-directory: build 41 | run: ctest -C ${{env.BUILD_TYPE}} -j 3 --output-on-failure -------------------------------------------------------------------------------- /.github/workflows/gcc.yml: -------------------------------------------------------------------------------- 1 | name: gcc 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - feature/* 8 | paths-ignore: 9 | - '**.md' 10 | pull_request: 11 | branches: [main] 12 | paths-ignore: 13 | - '**.md' 14 | 15 | env: 16 | BUILD_TYPE: Release 17 | 18 | jobs: 19 | build: 20 | runs-on: ubuntu-22.04 21 | 22 | env: 23 | CC: gcc-11 24 | CXX: g++-11 25 | 26 | steps: 27 | - uses: actions/checkout@v3 28 | 29 | - name: Configure CMake 30 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} 31 | 32 | - name: Build 33 | run: cmake --build build --config ${{env.BUILD_TYPE}} -j 2 34 | 35 | - name: Test 36 | working-directory: build 37 | run: ctest -C ${{env.BUILD_TYPE}} -j 2 --output-on-failure 38 | -------------------------------------------------------------------------------- /.github/workflows/msvc_2022.yml: -------------------------------------------------------------------------------- 1 | name: msvc_2022 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - feature/* 8 | paths-ignore: 9 | - '**.md' 10 | pull_request: 11 | branches: [main] 12 | paths-ignore: 13 | - '**.md' 14 | 15 | env: 16 | BUILD_TYPE: Release 17 | 18 | jobs: 19 | build: 20 | runs-on: windows-2022 21 | 22 | steps: 23 | - uses: actions/checkout@v3 24 | 25 | - name: Configure CMake 26 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} 27 | 28 | - name: Build 29 | run: cmake --build build --config ${{env.BUILD_TYPE}} -j 2 30 | 31 | - name: Test 32 | working-directory: build 33 | run: ctest -C ${{env.BUILD_TYPE}} -j 2 --output-on-failure 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *build/ 2 | doc/ 3 | .DS_store -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | project("ascent" 3 | VERSION 0.5.0 4 | DESCRIPTION "An extremely fast and flexible C++ simulation engine and differential equation solver." 5 | HOMEPAGE_URL "https://github.com/AnyarInc/Ascent" 6 | LANGUAGES CXX) 7 | 8 | include(GNUInstallDirs) 9 | include(CMakePackageConfigHelpers) 10 | include(CPack) 11 | if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) 12 | include(CTest) 13 | endif() 14 | 15 | add_library(${PROJECT_NAME} INTERFACE) 16 | add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) 17 | 18 | target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_20) 19 | if (MSVC) 20 | target_compile_options(${PROJECT_NAME} INTERFACE "/bigobj") # for ChaiScript 21 | endif() 22 | 23 | target_include_directories( 24 | ${PROJECT_NAME} 25 | INTERFACE $ 26 | $) 27 | 28 | install(TARGETS ${PROJECT_NAME} 29 | EXPORT ${PROJECT_NAME}_Targets 30 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 31 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 32 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) 33 | 34 | write_basic_package_version_file("${PROJECT_NAME}ConfigVersion.cmake" 35 | VERSION ${PROJECT_VERSION} 36 | COMPATIBILITY SameMajorVersion) 37 | configure_package_config_file( 38 | "${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in" 39 | "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" 40 | INSTALL_DESTINATION 41 | ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake) 42 | 43 | install(EXPORT ${PROJECT_NAME}_Targets 44 | FILE ${PROJECT_NAME}Targets.cmake 45 | NAMESPACE ${PROJECT_NAME}:: 46 | DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake) 47 | 48 | install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" 49 | "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" 50 | DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake) 51 | 52 | install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME} 53 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 54 | 55 | set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") 56 | 57 | if((CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME OR MODERN_CMAKE_BUILD_TESTING) AND BUILD_TESTING) 58 | add_subdirectory(unit_tests) 59 | endif() 60 | 61 | option(BUILD_EXAMPLES "Build example projects" TRUE) 62 | if((CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) AND BUILD_EXAMPLES) 63 | add_subdirectory(examples) 64 | endif() -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ascent 2 | 3 | An extremely fast and flexible C++ simulation engine and differential equation solver. 4 | 5 | See the [Ascent Wiki](https://github.com/AnyarInc/Ascent/wiki) for more examples and help 6 | 7 | Study the [modular-spring-damper](https://github.com/AnyarInc/Ascent/wiki/modular-spring-damper) example to learn the basics of solving matrix free systems of ordinary differential equations in an object-oriented manner 8 | 9 | ## Blazingly Fast 10 | 11 | Ascent's integration algorithms are designed for speed, and outperform boost's [odeint](http://headmyshoulder.github.io/odeint-v2/index.html) in both Debug and Release 12 | 13 | 14 | 15 | Integration algorithms are automatically vectorized when using std::vector 16 | 17 | ## Extremely Flexible 18 | 19 | Ascent solvers conform to the odeint system syntax, letting you run odeint system without changes (and with faster results!) 20 | 21 | odeint solvers can also be used to run Ascent simulations, providing all flexibility of the odeint engine with Ascent's simulation framework 22 | 23 | Ascent can solve complex, dynamic systems of differential equations in a modular, object-oriented manner 24 | 25 | Easily multi-thread systems and change integrators on the fly 26 | 27 | ## Highlights 28 | - Header Only 29 | - Automatic Vectorization: Ascent conforms to vectorization standards (such as Intel's) 30 | - Free for open source and commercial applications (Apache License) 31 | - Modular (Optional): solve systems in an object-oriented manner 32 | - Variable Tracking: Optimized recording of variable time history 33 | - Asynchronous Sampling and Event Scheduling 34 | - Multiple Integration Algorithms (In Progress): adaptive steppers, predictor-correctors, etc. 35 | - Use boost's odeint library as the numerical integration engine 36 | 37 | *** 38 | ## Requirements 39 | - C++17 compliant compiler 40 | 41 | ## Applications 42 | - Aerospace, multi-body physics, chemical reactions, economics, circuits, and much more 43 | - As a game engine for synchronization and physics 44 | - Agent-based simulations 45 | - Complex systems of differential equations 46 | - State-space modeling 47 | - Control algorithms (e.g. robotics) 48 | 49 | *** 50 | ### About [odeint](https://github.com/boostorg/odeint) 51 | odeint is a C++ ordinary differential equation solver that is part of the boost library. 52 | Ascent was partly inspired by the design of odeint, but Ascent offers better performance where comparisons can be made, this is especially true for solving object-oriented systems. 53 | odeint offers various state types and solvers that Ascent integration algorithms currently do not support, so the odeint solvers are a viable option as the integration algorithm beneath an Ascent simulation. 54 | -------------------------------------------------------------------------------- /cmake/ascentConfig.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") 4 | check_required_components("@PROJECT_NAME@") -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(airy) 2 | add_subdirectory(lorenz) 3 | add_subdirectory(modular-spring-damper) 4 | add_subdirectory(pliny-fountain) 5 | add_subdirectory(sampling) -------------------------------------------------------------------------------- /examples/airy/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(airy airy.cpp) 2 | target_link_libraries(airy ascent) -------------------------------------------------------------------------------- /examples/airy/airy.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "ascent/Ascent.h" 16 | 17 | using namespace asc; 18 | 19 | struct Airy 20 | { 21 | void operator()(const state_t& x, state_t& xd, const double t) 22 | { 23 | xd[0] = x[1]; 24 | xd[1] = -t*x[0]; 25 | } 26 | }; 27 | 28 | int main() 29 | { 30 | state_t x = { 1.0, 0.0 }; 31 | double t = 0.0; 32 | double dt = 0.1; 33 | double t_end = 10.0; 34 | 35 | RK4 integrator; 36 | Airy system; 37 | 38 | Recorder recorder; 39 | 40 | while (t < t_end) 41 | { 42 | recorder({ t, x[0], x[1] }); 43 | integrator(system, x, t, dt); 44 | } 45 | 46 | recorder.csv("airy", { "t", "x0", "x1" }); // generate a file of comma separated values 47 | 48 | return 0; 49 | } -------------------------------------------------------------------------------- /examples/lorenz/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(lorenz lorenz.cpp) 2 | target_link_libraries(lorenz ascent) -------------------------------------------------------------------------------- /examples/lorenz/lorenz.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "ascent/Ascent.h" 16 | 17 | using namespace asc; 18 | 19 | struct Lorenz 20 | { 21 | void operator()(const state_t& x, state_t& xd, const double) 22 | { 23 | static constexpr double sigma = 10.0; 24 | static constexpr double R = 28.0; 25 | static constexpr double b = 8.0 / 3.0; 26 | 27 | xd[0] = sigma * (x[1] - x[0]); 28 | xd[1] = R * x[0] - x[1] - x[0] * x[2]; 29 | xd[2] = -b * x[2] + x[0] * x[1]; 30 | } 31 | }; 32 | 33 | int main() 34 | { 35 | state_t x = { 10.0, 1.0, 1.0 }; 36 | double t = 0.0; 37 | double dt = 0.01; 38 | double t_end = 10.0; 39 | 40 | RK4 integrator; 41 | Lorenz system; 42 | 43 | Recorder recorder; 44 | 45 | while (t < t_end) 46 | { 47 | recorder({ t, x[0], x[1], x[2] }); 48 | integrator(system, x, t, dt); 49 | } 50 | 51 | recorder.csv("lorenz", { "t", "x0", "x1", "x2" }); 52 | 53 | return 0; 54 | } -------------------------------------------------------------------------------- /examples/modular-spring-damper/Body.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/Ascent.h" 18 | 19 | struct Body 20 | { 21 | Body(asc::state_t& state) : s(state), v(state) {} 22 | 23 | asc::Param s; // position 24 | asc::Param v; // velocity 25 | double m{}; // mass 26 | double f{}; // force 27 | 28 | void operator()(const asc::state_t&, asc::state_t& D, const double) 29 | { 30 | s(D) = v; 31 | 32 | if (m > 0.0) 33 | v(D) = f / m; 34 | else 35 | v(D) = 0.0; 36 | 37 | f = 0.0; 38 | } 39 | }; -------------------------------------------------------------------------------- /examples/modular-spring-damper/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(modular-spring-damper Main.cpp) 2 | target_link_libraries(modular-spring-damper ascent) -------------------------------------------------------------------------------- /examples/modular-spring-damper/Damper.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "Body.h" 18 | 19 | struct Damper 20 | { 21 | Damper(Body& b0, Body& b1) : b0(b0), b1(b1) {} 22 | 23 | Body& b0; 24 | Body& b1; 25 | 26 | double dv{}; // velocity difference 27 | double c{}; // damping coefficient 28 | double f{}; // force 29 | 30 | void operator()(const asc::state_t&, asc::state_t&, const double) 31 | { 32 | dv = b0.v - b1.v; 33 | f = c*dv; 34 | 35 | b0.f -= f; 36 | b1.f += f; 37 | } 38 | }; -------------------------------------------------------------------------------- /examples/modular-spring-damper/Main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "Damper.h" 16 | #include "Spring.h" 17 | 18 | using namespace asc; 19 | 20 | int main() 21 | { 22 | state_t x; 23 | x.reserve(100); // We reserve more space than necessary, but Ascent will only allocate what is needed 24 | double t = 0.0; 25 | double dt = 0.01; 26 | double t_end = 1.5; 27 | 28 | Body b0(x); 29 | Body b1(x); 30 | b1.m = 1.0; 31 | b1.s = 1.0; 32 | b1.v = 40.0; 33 | 34 | Spring spring(b0, b1); 35 | spring.k = 2000.0; 36 | 37 | Damper damper(b0, b1); 38 | damper.c = 5.0; 39 | 40 | RK4 integrator; 41 | Recorder recorder; 42 | 43 | auto system = [&](const asc::state_t& x, asc::state_t& D, const double t) 44 | { 45 | // We must run the spring and damper before the body in order to accumulate forces 46 | spring(x, D, t); 47 | damper(x, D, t); 48 | b1(x, D, t); 49 | }; 50 | 51 | while (t < t_end) 52 | { 53 | recorder({ t, b1.s }); 54 | integrator(system, x, t, dt); 55 | } 56 | 57 | recorder.csv("spring-damper", { "t", "b1 position" }); 58 | 59 | return 0; 60 | } -------------------------------------------------------------------------------- /examples/modular-spring-damper/Spring.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "Body.h" 18 | 19 | struct Spring 20 | { 21 | Spring(Body& b0, Body& b1) : b0(b0), b1(b1) 22 | { 23 | l0 = b1.s - b0.s; 24 | } 25 | 26 | Body& b0; 27 | Body& b1; 28 | 29 | double l0{}; // initial spring length (distance between masses) 30 | double ds{}; // spring compression/extension 31 | double k{}; // spring coefficient 32 | double f{}; // force 33 | 34 | void operator()(const asc::state_t&, asc::state_t&, const double) 35 | { 36 | ds = l0 + b0.s - b1.s; 37 | f = k*ds; 38 | 39 | b0.f -= f; 40 | b1.f += f; 41 | } 42 | }; -------------------------------------------------------------------------------- /examples/pliny-fountain/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(pliny-fountain fountain.cpp) 2 | target_link_libraries(pliny-fountain ascent) -------------------------------------------------------------------------------- /examples/pliny-fountain/fountain.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "ascent/Ascent.h" 16 | 17 | using namespace asc; 18 | 19 | // Pliny's Fountain example from: 20 | // Applied Numerical Methods with MATLAB 21 | // for Engineers and Scientists 22 | // Steven C. Chapra 23 | // p.608-609 24 | 25 | struct Fountain 26 | { 27 | double siphon; 28 | static constexpr double Rt = 0.05; 29 | static constexpr double r = 0.007; 30 | static constexpr double yhi = 0.1; 31 | static constexpr double ylo = 0.025; 32 | static constexpr double C = 0.6; 33 | static constexpr double g = 9.81; 34 | static constexpr double Qin = 0.00005; 35 | 36 | static constexpr double pi = 3.14159265359; 37 | 38 | void operator()(const state_t& x, state_t& xd, const double) 39 | { 40 | if (x[0] <= ylo) 41 | siphon = 0.0; 42 | else if (x[0] >= yhi) 43 | siphon = 1.0; 44 | 45 | const double Qout = siphon * C * sqrt(2 * g * x[0]) * pi * r * r; 46 | xd[0] = (Qin - Qout) / (pi * Rt * Rt); 47 | } 48 | }; 49 | 50 | int main() 51 | { 52 | state_t x = { 0.0 }; 53 | double t = 0.0; 54 | double dt = 1.0; 55 | double t_end = 100.0; 56 | 57 | RK4 integrator; 58 | Fountain system; 59 | 60 | Recorder recorder; 61 | 62 | while (t < t_end) 63 | { 64 | recorder({ t, x[0] }); 65 | integrator(system, x, t, dt); 66 | } 67 | 68 | recorder.csv("results", { "t", "x[0]" }); // generate a file of comma separated values 69 | 70 | return 0; 71 | } -------------------------------------------------------------------------------- /examples/sampling/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(sampling sampling.cpp) 2 | target_link_libraries(sampling ascent) -------------------------------------------------------------------------------- /examples/sampling/sampling.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "ascent/Ascent.h" 16 | 17 | using namespace asc; 18 | 19 | struct ODE 20 | { 21 | void operator()(const state_t& x, state_t& xd, const double t) 22 | { 23 | xd[0] = cos(t); 24 | } 25 | }; 26 | 27 | int main() 28 | { 29 | state_t x = { 0.0 }; 30 | double t = 0.0; 31 | double dt = 0.1; 32 | double t_end = 10.0; 33 | 34 | RK4 integrator; 35 | ODE system; 36 | 37 | Recorder recorder; 38 | 39 | while (t < t_end) 40 | { 41 | Sampler sampler(t, dt); 42 | 43 | // We force the system to be evaluated at all increments of 0.33 and 0.41, as well as trigger a single event evaluation at 0.617 44 | if (sampler(0.33) || sampler(0.41) || sampler.event(0.617)) 45 | recorder({ t, x[0] }); 46 | 47 | integrator(system, x, t, dt); 48 | } 49 | 50 | recorder.csv("sampling", { "t", "x0" }); // generate a file of comma separated values 51 | 52 | return 0; 53 | } -------------------------------------------------------------------------------- /include/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | project(ascent) 3 | 4 | # ascent library 5 | add_library(ascent INTERFACE) 6 | target_include_directories(ascent INTERFACE 7 | $ 8 | $) -------------------------------------------------------------------------------- /include/ascent/Ascent.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/Recorder.h" 18 | #include "ascent/Param.h" 19 | 20 | // Timing 21 | #include "ascent/timing/Sampler.h" 22 | 23 | // Integrators 24 | #include "ascent/integrators/Euler.h" 25 | #include "ascent/integrators/Midpoint.h" 26 | #include "ascent/integrators/RK2.h" 27 | #include "ascent/integrators/RK4.h" 28 | #include "ascent/integrators/DOPRI45.h" 29 | #include "ascent/integrators/RTAM4.h" 30 | #include "ascent/integrators/PC233.h" 31 | #include "ascent/integrators/ABM4.h" 32 | 33 | // Linear Algebra 34 | #include "ascent/ParamV.h" 35 | 36 | #include "ascent/System.h" 37 | 38 | #include 39 | #include 40 | 41 | // Type definitions for cleaner code 42 | 43 | namespace asc 44 | { 45 | // Edits To The Following Types Are Not Reccommended 46 | // ------------------------------------------------ 47 | using system_t = std::function; 48 | 49 | using System = SystemT; 50 | 51 | using Recorder = RecorderT; 52 | using RecorderString = RecorderT; 53 | using Sampler = SamplerT; 54 | using Param = ParamT; 55 | 56 | // Integrators 57 | using Euler = EulerT; 58 | using Midpoint = MidpointT; 59 | using RK2 = RK2T; 60 | using RK4 = RK4T; 61 | using DOPRI45 = DOPRI45T; 62 | using PC233 = PC233T; 63 | using ABM4 = ABM4T; 64 | 65 | // Linear Algebra 66 | using ParamV = ParamVT; 67 | } -------------------------------------------------------------------------------- /include/ascent/ChaiEngine.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2018 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/Ascent.h" 18 | #include "ascent/threading/Pool.h" 19 | // #include "ascent/threading/Queue.h" 20 | #include "chaiscript/chaiscript.hpp" 21 | #include "chaiscript/chaiscript_stdlib.hpp" 22 | 23 | namespace asc 24 | { 25 | struct ChaiEngine : public chaiscript::ChaiScript 26 | { 27 | // Captures the systyem object by reference. 28 | template 29 | void addSystem() 30 | { 31 | add(chaiscript::type_conversion([](T& system) -> system_t { return [&](const state_t& x, state_t& xd, const value_t t) { return system(x, xd, t); }; })); 32 | add(chaiscript::type_conversion, system_t>([](std::shared_ptr system) -> system_t { return [=](const state_t& x, state_t& xd, const value_t t) { return (*system)(x, xd, t); }; })); 33 | } 34 | 35 | // This code must exist here and not within the Recorder class for compatibilty with compilers that inspect templates (i.e. Xcode's LLVM) 36 | template 37 | void scriptRecorder(ChaiScript& c, const std::string& name) 38 | { 39 | using namespace chaiscript; 40 | using R = RecorderT; 41 | c.add(user_type(), name); 42 | c.add(constructor(), name); 43 | 44 | c.add(fun(&R::titles), "titles"); 45 | c.add(fun(&R::precision), "precision"); 46 | c.add(fun(&R::update), "update"); 47 | c.add(fun([](R& rec, const T& x) { rec.add(x); }), "add"); 48 | c.add(fun([](R& rec, const std::vector& data) { rec.add(data); }), "add"); 49 | c.add(fun([](R& rec, const std::string& title) { rec.add_title(title); }), "add_title"); 50 | c.add(fun([](R& rec, const std::vector& titles) { rec.add_titles(titles); }), "add_titles"); 51 | c.add(fun([](R& rec, T& x) { rec.record(x); }), "record"); 52 | c.add(fun([](R& rec, T& x, const std::string& title) { rec.record(x, title); }), "record"); 53 | c.add(fun([](R& rec, std::vector& v) { rec.record(v); }), "record"); 54 | c.add(fun([](R& rec, std::vector& v, const std::vector& title) { rec.record(v, title); }), "record"); 55 | c.add(fun([](R& rec, const std::vector& data) { rec.push_back(data); }), "push_back"); 56 | c.add(fun([](R& rec, const std::string& file_name) { rec.csv(file_name); }), "csv"); 57 | c.add(fun([](R& rec, const std::string& file_name, const std::vector& names) { rec.csv(file_name, names); }), "csv"); 58 | } 59 | 60 | ChaiEngine() 61 | { 62 | using namespace chaiscript; 63 | 64 | add(vector_conversion()); 65 | add(vector_conversion>()); 66 | add(bootstrap::standard_library::vector_type("state_t")); 67 | 68 | scriptRecorder(*this, "Recorder"); 69 | add(fun([](RecorderT& rec, int& x) { rec.record(x); }), "record"); 70 | add(fun([](RecorderT& rec, size_t& x) { rec.record(x); }), "record"); 71 | add(fun([](RecorderT& rec, int& x, const std::string& title) { rec.record(x, title); }), "record"); 72 | add(fun([](RecorderT& rec, size_t& x, const std::string& title) { rec.record(x, title); }), "record"); 73 | 74 | // This allows for more generic mixing of various data types, all they need is to be converted to a string prior to being passed into the recorder 75 | // The RecorderString is primarily for data that is going to be output to a file and not operated on during the simulation 76 | scriptRecorder(*this, "RecorderString"); 77 | 78 | add(user_type(), "Param"); 79 | add(constructor(), "Param"); 80 | add(constructor(), "Param"); 81 | add(fun([](asc::Param& param, const value_t y) { return param = y; }), "="); 82 | add(fun([](asc::Param& param) { std::cout << param << '\n'; }), "print"); 83 | add(fun([](asc::Param& param) { return static_cast(param); }), "value"); 84 | 85 | add(user_type(), "ParamV"); 86 | add(constructor(), "ParamV"); 87 | add(fun([](ParamV& lhs, const std::vector& rhs) { return lhs = rhs; }), "="); 88 | add(fun([](ParamV& v) { v.zero(); }), "zero"); 89 | 90 | add(user_type(), "Sampler"); 91 | add(constructor(), "Sampler"); 92 | add(fun(&Sampler::operator()), "eval"); 93 | add(fun(&Sampler::event), "event"); 94 | add(fun(&Sampler::reset), "reset"); 95 | 96 | // System 97 | add(user_type(), "System"); 98 | add(constructor(), "System"); 99 | add(fun([](System& sys, const asc::state_t& x, asc::state_t& D, const asc::value_t t) { sys(x, D, t); }), "eval"); 100 | add(type_conversion()); 101 | add(fun([](System& sys, const system_t& func) { sys.push_back(func); }), "push_back"); 102 | 103 | // Integrators 104 | integrator("ascEuler"); 105 | integrator("ascRK2"); 106 | integrator("ascRK4"); 107 | 108 | // threading 109 | // Queue::script(*this, "Queue"); 110 | Pool::script(*this, "Pool"); 111 | add(fun([] { return std::thread::hardware_concurrency(); }), "hardware_concurrency"); 112 | add(fun([](asc::Recorder& rec, const int sig_digits) { rec.precision = sig_digits; }), "precision"); 113 | } 114 | ChaiEngine(const ChaiEngine&) = delete; 115 | ChaiEngine(ChaiEngine&&) = delete; 116 | ChaiEngine& operator=(const ChaiEngine&) = delete; 117 | ChaiEngine& operator=(ChaiEngine&&) = delete; 118 | 119 | private: 120 | template 121 | void integrator(const std::string& name) 122 | { 123 | add(chaiscript::user_type(), name); 124 | add(chaiscript::constructor(), name); 125 | add(chaiscript::fun([](T& integrator, system_t& system, state_t& state, value_t& t, const value_t dt) { integrator(system, state, t, dt); }), "step"); 126 | } 127 | 128 | template 129 | void adaptiveIntegrator(const std::string& name) 130 | { 131 | add(chaiscript::user_type(), name); 132 | add(chaiscript::constructor(), name); 133 | add(chaiscript::fun([](T& integrator, system_t& system, state_t& state, value_t& t, value_t& dt) { integrator(system, state, t, dt); }), "step"); 134 | } 135 | }; 136 | } 137 | -------------------------------------------------------------------------------- /include/ascent/Param.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | // A Param is a reference to a memory location within the system's state 18 | 19 | namespace asc 20 | { 21 | namespace core 22 | { 23 | template 24 | inline typename C::value_type& emplace_back_ref(C& c, const typename C::value_type x0) 25 | { 26 | c.emplace_back(x0); 27 | return c.back(); 28 | } 29 | } 30 | 31 | template 32 | struct ParamT 33 | { 34 | template 35 | ParamT(C& c, const T x0 = T()) : index(c.size()), x(core::emplace_back_ref(c, x0)) {} 36 | 37 | ParamT(const ParamT&) = default; 38 | ParamT(ParamT&&) = default; 39 | ParamT& operator=(const ParamT&) = default; 40 | ParamT& operator=(ParamT&&) = default; 41 | 42 | template 43 | T& operator()(C& xd) const noexcept { return xd[index]; } 44 | 45 | // Returns true if this State is within a given state array 46 | template 47 | bool within(const C& vec) const noexcept 48 | { 49 | if (&x == &vec[index]) 50 | return true; 51 | return false; 52 | } 53 | 54 | operator T&() const noexcept { return x; } 55 | 56 | T& operator=(const T y) noexcept { x = y; return x; } 57 | 58 | private: 59 | const size_t index; 60 | T& x; 61 | }; 62 | } -------------------------------------------------------------------------------- /include/ascent/ParamV.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "Param.h" 18 | #include 19 | #include 20 | 21 | // The ParamV behaves like a std::vector of Params 22 | 23 | namespace asc 24 | { 25 | template 26 | struct ParamVT 27 | { 28 | using iterator = typename std::vector::iterator; 29 | 30 | ParamVT(ParamVT&& other) : i0(std::move(other.i0)), n(std::move(other.n)), data_ptr(std::move(other.data_ptr)) {} 31 | ParamVT(const ParamVT& other) : i0(other.i0), n(other.n), data_ptr(other.data_ptr) {} 32 | 33 | ParamVT& operator=(const ParamVT& v) 34 | { 35 | for (size_t i = 0; i < n; ++i) 36 | this->operator[](i) = v[i]; 37 | return *this; 38 | } 39 | 40 | template 41 | ParamVT& operator=(const C& c) 42 | { 43 | for (size_t i = 0; i < n; ++i) 44 | this->operator[](i) = c[i]; 45 | return *this; 46 | } 47 | 48 | template 49 | ParamVT(C& c, const size_t _n) : n(_n) 50 | { 51 | ParamT(c, T()); 52 | data_ptr = c.data() + c.size() - 1; 53 | i0 = (--c.end()) - c.begin(); 54 | 55 | for (size_t i = 1; i < n; ++i) 56 | ParamT(c, T()); 57 | } 58 | 59 | template 60 | ParamVT(C& c, std::initializer_list&& list) : n(list.size()) 61 | { 62 | bool first_element{ true }; 63 | for (T x : list) 64 | { 65 | ParamT(c, x); 66 | 67 | if (first_element) 68 | { 69 | first_element = false; 70 | data_ptr = c.data() + c.size() - 1; 71 | i0 = (--c.end()) - c.begin(); 72 | } 73 | } 74 | } 75 | 76 | // Constructor for selecting a specific section of allocated memory 77 | ParamVT(const size_t _i0, const size_t _n, T* data) : i0(_i0), n(_n), data_ptr(data) {} 78 | 79 | template 80 | ParamVT operator()(C& xd) const 81 | { 82 | return ParamVT(i0, n, xd.data() + i0); 83 | } 84 | 85 | const T* begin() const noexcept { return data_ptr; } 86 | const T* end() const noexcept { return data_ptr + n; } 87 | 88 | T& operator[](const size_t i) const noexcept { return *(data_ptr + i); } 89 | 90 | size_t size() const noexcept { return n; } 91 | 92 | T* data() const noexcept { return data_ptr; } 93 | 94 | void zero() noexcept 95 | { 96 | for (size_t i = 0; i < n; ++i) 97 | this->operator[](i) = T(); 98 | } 99 | 100 | protected: 101 | size_t i0{}; // starting index 102 | const size_t n; 103 | T* data_ptr; 104 | }; 105 | } 106 | -------------------------------------------------------------------------------- /include/ascent/Recorder.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2018 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "ascent/containers/stack.h" 26 | 27 | #if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L)) 28 | #include 29 | #include 30 | #endif 31 | 32 | // Helpers 33 | namespace { 34 | #if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L)) 35 | //Handles writing variant types 36 | template 37 | void stream_insert(std::ostream& stream, const std::variant& value) 38 | { 39 | std::visit([&](auto&& arg) { stream << arg; }, value); 40 | } 41 | #endif 42 | 43 | ///Handles non variant types 44 | template 45 | void stream_insert(std::ostream& stream, const V& value) 46 | { 47 | stream << value; 48 | } 49 | } 50 | 51 | namespace asc 52 | { 53 | template 54 | std::string to_string_precision(const T input, const int n = 6) 55 | { 56 | std::ostringstream out; 57 | out << std::setprecision(n) << input; 58 | return out.str(); 59 | } 60 | 61 | /// Recorder is a fast, type specific class for generically recording data. 62 | /// 63 | /// The Recorder class permits variable width rows of data that can be populated by passing in initializer lists (preferred) or std::vectors 64 | /// \paramt T The type to be recorded. 65 | template 66 | struct RecorderT 67 | { 68 | RecorderT() = default; 69 | RecorderT(const RecorderT&) = default; 70 | RecorderT(RecorderT&&) = default; 71 | RecorderT& operator=(const RecorderT&) = default; 72 | RecorderT& operator=(RecorderT&&) = default; 73 | 74 | std::vector recording_pointers; //!< std::vector of pointers to data to be recorded on updat 75 | std::vector&)>> recording_functions; //!< std::vector of type erasing converters (std::functions) to enable user defined classes to be recorded. 76 | std::vector titles; //!< Titles that will appear at the top row of a CSV export. 77 | asc::stack, block_size> history; //!< All recorded data is stored in history. 78 | std::vector buffer; //!< Temp buffer to to reduce dynamic memory allocations 79 | int precision{}; //!< An integer to specify the recording precision for CSV output. If precision is not set (left at 0) then values will be exported with the c++ filestream default precision. This precision only affects export to CSV. 80 | 81 | /// \brief Add row of history data 82 | /// 83 | /// \param[in] initializer_list An input initializer list. Highly efficient as it performs a move operation on the data list. 84 | inline void operator()(std::initializer_list&& initializer_list) { history.emplace_back(std::move(initializer_list)); } 85 | 86 | /// \brief Add row of history data 87 | /// 88 | /// \param[in] v A std::vector of data to be saved. 89 | inline void push_back(const std::vector& v) { history.emplace_back(v); } 90 | 91 | /// \brief Add an item to the current row of data 92 | /// 93 | /// \param[in] x Item to be added to last row of history. 94 | inline void add(const T& x) { history.back().emplace_back(x); } 95 | 96 | /// \brief Add a std::vector of items to the current row of data 97 | /// 98 | /// \param[in] v A std::vector of items to be added to last row of history. 99 | inline void add(const std::vector& v) 100 | { 101 | for (auto& x : v) 102 | history.back().emplace_back(x); 103 | } 104 | 105 | /// \brief Add a title for the next column of data for output to CSV. 106 | /// 107 | /// \param[in] title The title name for a column of data, used in the first row of the CSV generation. 108 | void add_title(const std::string& title) 109 | { 110 | titles.emplace_back(title); 111 | } 112 | 113 | /// \brief Add a std::vector of titles for the next columns of data for output to CSV. 114 | /// 115 | /// \param[in] new_titles A std::vector of title names, used in the first row of the CSV generation. 116 | void add_titles(const std::vector& new_titles) 117 | { 118 | for (auto& title : new_titles) 119 | titles.emplace_back(title); 120 | } 121 | 122 | /// \brief Wrap a user defined type that has an implicit or explicit conversion to this Recorder's type T. 123 | /// 124 | /// \param[in] x The user defined input type, internally a reference to this instance is saved, so the Recorder should not outlive the object. 125 | template 126 | void record(V& x) { record(x, ""); } 127 | 128 | /// \brief Wrap a user defined type that has an implicit or explicit conversion to this Recorder's type T. 129 | /// 130 | /// \param[in] x The user defined input type, internally a reference to this instance is saved, so the Recorder should not outlive the object. 131 | /// \param[in] title The title associated with this input variable. 132 | template 133 | void record(V& x, const std::string& title) 134 | { 135 | titles.emplace_back(title); 136 | recording_pointers.emplace_back(nullptr); 137 | recording_functions.emplace_back([&](std::vector& res) { res = { static_cast(x) }; }); 138 | } 139 | 140 | /// \brief Specify an item of this recorder's type T, to be saved every time update is called. 141 | /// 142 | /// \param[in] x The user defined input type, internally a reference to this instance is saved, so the Recorder should not outlive the object. 143 | /// \param[in] title The title associated with this input variable. 144 | void record(T& x, const std::string& title) 145 | { 146 | titles.emplace_back(title); 147 | recording_pointers.emplace_back(&x); 148 | } 149 | 150 | /// \brief Specify a std::vector of this recorder's type T, to be saved every time update is called. 151 | /// 152 | /// \param[in] v Reference vector to be recorded upon update. 153 | void record(std::vector& v) 154 | { 155 | const size_t n = v.size(); 156 | record(v, std::vector(n)); 157 | } 158 | 159 | /// \brief Specify a std::vector of this recorder's type T, to be saved every time update is called. 160 | /// 161 | /// \param[in] v Reference vector to be recorded upon update. 162 | /// \param[in] new_titles Specify the title for each component of the vector that will be recorded. 163 | void record(std::vector& v, const std::vector& new_titles) 164 | { 165 | for (auto& title : new_titles) 166 | titles.emplace_back(title); 167 | recording_functions.emplace_back([&](std::vector& res) { res = v; }); 168 | recording_pointers.emplace_back(nullptr); 169 | } 170 | 171 | /// \brief All variables specified via the record functions will be saved when update is called. 172 | void update() 173 | { 174 | history.emplace_back(); 175 | auto& row = history.back(); 176 | row.reserve(history.front().size()); 177 | int func_index = 0; 178 | for (auto& ptr : recording_pointers) 179 | { 180 | if (ptr) 181 | history.back().emplace_back(*ptr); 182 | else 183 | { 184 | buffer.clear(); 185 | recording_functions[func_index++](buffer); 186 | add(buffer); 187 | } 188 | } 189 | } 190 | 191 | /// \brief Write out a Comma Separated Value (CSV) file from the recorded data. 192 | /// 193 | /// \param[in] file_name The path and name of the file to be generated, excepting the .csv which is added by the function. 194 | void csv(const std::string& file_name) { csv(file_name, titles); } 195 | 196 | /// \brief Write out a Comma Separated Value (CSV) file from the recorded data. 197 | /// 198 | /// \param[in] file_name The path and name of the file to be generated, excepting the .csv which is added by the function. 199 | /// \param[in] names The variable names associated with each column of data. 200 | void csv(const std::string& file_name, const std::vector& names) 201 | { 202 | std::ofstream file; 203 | file.open(file_name + ".csv"); 204 | 205 | if (file) 206 | { 207 | if (precision > 0) 208 | { 209 | file.precision(precision); 210 | } 211 | 212 | const size_t num_names = names.size(); 213 | for (size_t i = 0; i < num_names; ++i) 214 | { 215 | file << names[i].c_str(); 216 | if (i < num_names - 1) 217 | { 218 | file << ","; 219 | } 220 | } 221 | if (num_names > 0) 222 | { 223 | file << '\n'; 224 | } 225 | 226 | const size_t num_states = history.front().size(); 227 | 228 | for (auto& step : history) 229 | { 230 | for (size_t i = 0; i < num_states; ++i) 231 | { 232 | stream_insert(file, step[i]); 233 | if (i < num_states - 1) 234 | { 235 | file << ","; 236 | } 237 | } 238 | file << '\n'; 239 | } 240 | } 241 | else 242 | { 243 | throw std::runtime_error("Record: file '" + file_name + ".csv' could not be opened."); 244 | } 245 | } 246 | }; 247 | 248 | #if (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L)) 249 | //Faster cvs writer using to_chars for floating point to double conversion 250 | template<> 251 | inline void RecorderT::csv(const std::string& file_name, const std::vector& names) 252 | { 253 | std::ofstream file; 254 | file.open(file_name + ".csv"); 255 | 256 | if (file) 257 | { 258 | const size_t n_names = names.size(); 259 | for (size_t i = 0; i < n_names; ++i) 260 | { 261 | file << names[i].c_str(); 262 | if (i < n_names - 1) 263 | { 264 | file << ","; 265 | } 266 | } 267 | if (n_names > 0) 268 | { 269 | file << '\n'; 270 | } 271 | 272 | const size_t n_rows = history.size(); 273 | if (n_rows == 0) return; 274 | const size_t n_columns = history.front().size(); 275 | size_t capacity = n_columns * n_rows * 20; 276 | size_t size = 0; 277 | char* chr_buffer = (char*)malloc(capacity * sizeof(char)); 278 | for (auto& row : history) { 279 | bool isFirst = true; 280 | for (auto& item : row) { 281 | if (capacity - size < 258) { 282 | capacity *= 2; 283 | chr_buffer = (char*)realloc(chr_buffer, capacity * sizeof(char)); 284 | } 285 | if (isFirst) 286 | isFirst = false; 287 | else 288 | *(chr_buffer + size++) = ','; 289 | auto[p, err] = std::to_chars(chr_buffer + size, chr_buffer + capacity, item); 290 | if (err != std::errc()) 291 | std::runtime_error("Recorder exceeded chr_buffer length"); 292 | size = p - chr_buffer; 293 | } 294 | //We could just allways add a comma after each item and overwrite the last comma with a newline so we dont need isFirst 295 | *(chr_buffer + size++) = '\n'; 296 | } 297 | *(chr_buffer + size++) = 0; 298 | file << chr_buffer; 299 | free(chr_buffer); 300 | 301 | } 302 | else 303 | throw std::runtime_error("Record: file '" + file_name + ".csv' could not be opened."); 304 | } 305 | #endif 306 | } 307 | -------------------------------------------------------------------------------- /include/ascent/System.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | 20 | namespace asc 21 | { 22 | template 23 | struct SystemT 24 | { 25 | void push_back(const system_t& func) 26 | { 27 | functions.push_back(func); 28 | } 29 | 30 | void operator()(const state_t& x, state_t& xd, const double t) 31 | { 32 | for (auto& f : functions) 33 | f(x, xd, t); 34 | } 35 | 36 | std::vector functions; 37 | }; 38 | } -------------------------------------------------------------------------------- /include/ascent/Utility.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include 18 | 19 | namespace asc 20 | { 21 | // User type definitions for ease of use 22 | using value_t = double; // float, double, etc. 23 | using state_t = std::vector; // std::vector, std::deque, etc. 24 | 25 | constexpr value_t cx(long double v) { return static_cast(v); } 26 | constexpr value_t operator"" _v(long double v) { return static_cast(v); } 27 | 28 | struct AdaptiveIntegrator 29 | { 30 | AdaptiveIntegrator() = default; 31 | AdaptiveIntegrator(const AdaptiveIntegrator&) = default; 32 | AdaptiveIntegrator(AdaptiveIntegrator&&) = default; 33 | AdaptiveIntegrator& operator=(const AdaptiveIntegrator&) = default; 34 | AdaptiveIntegrator& operator=(AdaptiveIntegrator&&) = default; 35 | virtual ~AdaptiveIntegrator() = default; 36 | }; 37 | 38 | template 39 | struct AdaptiveT 40 | { 41 | T abs_tol = static_cast(1.0); // absolute tolerance 42 | T rel_tol = static_cast(1.0); // relative tolerance 43 | T safety_factor = static_cast(0.9); // value < 1.0 reduces time step change aggressiveness 44 | }; 45 | } -------------------------------------------------------------------------------- /include/ascent/Vector.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2018 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/ParamV.h" 18 | 19 | namespace asc 20 | { 21 | template 22 | struct Vector : asc::ParamVT 23 | { 24 | Vector(std::vector& c) : asc::ParamVT(c, N) {} 25 | Vector(Vector&& other) : asc::ParamVT(std::move(other)) {} 26 | Vector(const value_t& other) : asc::ParamVT(other) {} 27 | 28 | using value_type = value_t; 29 | 30 | template 31 | Vector(C& c, std::initializer_list&& list) : asc::ParamVT(c, list) {} 32 | 33 | Vector(const size_t i0, const size_t n, value_t* data) : asc::ParamVT(i0, n, data) {} 34 | 35 | Vector& operator=(const Vector& v) 36 | { 37 | for (size_t i = 0; i < n; ++i) 38 | this->operator[](i) = v[i]; 39 | return *this; 40 | } 41 | 42 | Vector& operator=(const std::vector& v) 43 | { 44 | for (size_t i = 0; i < n; ++i) 45 | this->operator[](i) = v[i]; 46 | return *this; 47 | } 48 | 49 | using asc::ParamVT::operator[]; 50 | 51 | double norm() const 52 | { 53 | const size_t n = size(); 54 | value_t sum{}; 55 | for (size_t i = 0; i < n; ++i) 56 | sum += operator[](i) * operator[](i); 57 | return sqrt(sum); 58 | } 59 | 60 | std::vector normalized() const 61 | { 62 | std::vector ret; 63 | ret.reserve(N); 64 | const value_t magnitude = norm(); 65 | for (size_t i = 0; i < N; ++i) 66 | { 67 | ret.emplace_back(operator[](i) / magnitude); 68 | } 69 | return ret; 70 | } 71 | }; 72 | 73 | inline auto operator-(const Vector<3>& lhs, const Vector<3>& rhs) -> std::vector::value_type> 74 | { 75 | const size_t n = lhs.size(); 76 | std::vector::value_type> ret(n); 77 | for (size_t i = 0; i < n; ++i) 78 | ret[i] = lhs[i] - rhs[i]; 79 | return ret; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /include/ascent/algorithms/Derivative.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include 18 | 19 | #ifdef min 20 | #undef min 21 | #endif 22 | 23 | namespace asc 24 | { 25 | // x is the independant variable, y is dependent. Returns derivative for unequally spaced points. xest is the x value at which to evaluate the derivative. 26 | // x and y vectors don't need to be the same length if they have three elements or more each 27 | template 28 | inline auto derivative(const T0& x, const T1& y, const typename T0::value_type xest) 29 | { 30 | const size_t nx = x.size(); 31 | const size_t ny = y.size(); 32 | if (x.size() < 2 || y.size() < 2) 33 | return typename T0::value_type(); 34 | else if (nx == 2 || ny == 2) 35 | return (y.back() - y.front()) / (x.back() - x.front()); 36 | else 37 | { 38 | const typename T0::value_type x2 = x[nx - 1]; 39 | const typename T0::value_type x1 = x[nx - 2]; 40 | const typename T0::value_type x0 = x[nx - 3]; 41 | 42 | const typename T1::value_type y2 = y[ny - 1]; 43 | const typename T1::value_type y1 = y[ny - 2]; 44 | const typename T1::value_type y0 = y[ny - 3]; 45 | 46 | const typename T0::value_type dydx = y0*(2.0 * xest - x1 - x2) / ((x0 - x1)*(x0 - x2)) + y1*(2.0 * xest - x0 - x2) / ((x1 - x0)*(x1 - x2)) + y2*(2.0 * xest - x0 - x1) / ((x2 - x0)*(x2 - x1)); 47 | 48 | return dydx; 49 | } 50 | } 51 | 52 | // x is the independant variable, y is dependent. Returns derivative for unequally spaced points. 53 | // Uses the last x value for the prediction point. 54 | template 55 | inline auto derivative(const T0& x, const T1& y) 56 | { 57 | return derivative(x, y, x.back()); 58 | } 59 | 60 | // supports n dimensional containers of vectors 61 | template 62 | inline std::vector derivative_vector(const T0& t, const T1& v) 63 | { 64 | const size_t n = std::min(t.size(), v.size()); 65 | const size_t dimensions = v.front().size(); 66 | if (n < 2) 67 | return std::vector(dimensions); 68 | else if (n == 2) 69 | { 70 | //return (v[1] - v[0]) / (t[1] - t[0]); // Changed this so its compatible with std::array 71 | std::vector ret; 72 | ret.resize(dimensions); 73 | for (size_t i = 0; i < dimensions; ++i) 74 | ret[i] = (v[1][i] - v[0][i]) / (t[1] - t[0]); 75 | return ret; 76 | } 77 | 78 | std::vector> dimensional_history(dimensions); // each vector is for a dimension, such as x, y, z, . . . (can have more dimensions than 3), saving three time steps of history 79 | for (size_t i = 0; i < dimensions; ++i) 80 | { 81 | for (size_t j = 3; j > 0; --j) // iterate over last three states, from oldest to newest 82 | dimensional_history[i].push_back(v[n - j][i]); // this will push back the ith states (i.e. if i = 0, x dimension) from the last three vx states 83 | } 84 | 85 | std::vector deriv(dimensions); 86 | for (size_t i = 0; i < dimensions; ++i) 87 | deriv[i] = asc::derivative(t, dimensional_history[i]); // t can contain more than 3 steps 88 | 89 | return deriv; 90 | } 91 | 92 | namespace eigen 93 | { 94 | // E is intended to be an Eigen::Vector, such as Eigen::Vector3d, supports n dimensional Eigen vectors 95 | template 96 | inline E derivative_vector(const T0 &t, const T1 &v) 97 | { 98 | const auto n = std::min(t.size(), v.size()); 99 | if (n < 2) 100 | { 101 | return E::Zero(); 102 | } 103 | 104 | return (v[1] - v[0]) / (t[1] - t[0]); 105 | } 106 | 107 | // takes the derivative over three points of history 108 | template 109 | struct derivative_vector_3 110 | { 111 | std::vector> dimensional_history; // each vector is for a dimension, such as x, y, z, . . . (can have more dimensions than 3), saving three time steps of history 112 | 113 | // E is intended to be an Eigen::Vector, such as Eigen::Vector3d, supports n dimensional Eigen vectors 114 | template 115 | inline E operator()(const T0 &t, const T1 &v) 116 | { 117 | const auto n = std::min(t.size(), v.size()); 118 | if (n < 2) 119 | { 120 | return E::Zero(); 121 | } 122 | else if (n == 2) 123 | { 124 | return (v[1] - v[0]) / (t[1] - t[0]); 125 | } 126 | 127 | const auto dimensions = v[0].rows(); 128 | dimensional_history.resize(dimensions); 129 | for (auto& h : dimensional_history) 130 | { 131 | h.resize(3); 132 | } 133 | for (auto i = 0; i < dimensions; ++i) 134 | { 135 | for (auto j = 0; j < 3; ++j) // iterate over last three states, from oldest to newest 136 | { 137 | dimensional_history[i][j] = v[n - 3 + j][i]; // this will push back the ith states (i.e. if i = 0, x dimension) from the last three Eigen::Vector states 138 | } 139 | } 140 | 141 | E deriv; 142 | for (auto i = 0; i < dimensions; ++i) 143 | { 144 | deriv[i] = derivative(t, dimensional_history[i]); // t can contain more than 3 steps 145 | } 146 | 147 | return deriv; 148 | } 149 | }; 150 | } 151 | } -------------------------------------------------------------------------------- /include/ascent/containers/flat_id_map.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2020 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | 20 | namespace asc 21 | { 22 | // A flat map that is as fast to iterate through as possible and uses a binary search to locate elements. 23 | // Important: Keys must be emplaced back in a sorted manner. 24 | template 25 | struct flat_id_map 26 | { 27 | using iterator = typename std::vector>::iterator; 28 | using const_iterator = typename std::vector>::const_iterator; 29 | 30 | template 31 | void emplace_back(Args&&... args) 32 | { 33 | vec.emplace_back(std::forward(args)...); 34 | } 35 | 36 | void reserve(const size_t n) { vec.reserve(n); } 37 | 38 | void erase(const size_t i) 39 | { 40 | const auto it = std::lower_bound(vec.cbegin(), vec.cend(), std::pair{ i, Value{} }, [=](const auto& p0, const auto& p1) { return p0.first < p1.first; }); 41 | vec.erase(it); 42 | } 43 | 44 | iterator find(const size_t i) 45 | { 46 | return std::lower_bound(vec.cbegin(), vec.cend(), std::pair{ i, Value{} }, [=](const auto& p0, const auto& p1) { return p0.first < p1.first; }); 47 | } 48 | 49 | auto& operator[](const size_t i) 50 | { 51 | const auto it = std::lower_bound(vec.cbegin(), vec.cend(), std::pair{ i, Value{} }, [=](const auto& p0, const auto& p1) { return p0.first < p1.first; }); 52 | return it->second; 53 | } 54 | 55 | const auto& operator[](const size_t i) const 56 | { 57 | const auto it = std::lower_bound(vec.cbegin(), vec.cend(), std::pair{ i, Value{} }, [=](const auto& p0, const auto& p1) { return p0.first < p1.first; }); 58 | return it->second; 59 | } 60 | 61 | iterator begin() noexcept { return vec.begin(); } 62 | iterator end() noexcept { return vec.end(); } 63 | 64 | const_iterator begin() const noexcept { return vec.cbegin(); } 65 | const_iterator cbegin() const noexcept { return vec.cbegin(); } 66 | const_iterator end() const noexcept { return vec.cend(); } 67 | const_iterator cend() const noexcept { return vec.cend(); } 68 | 69 | size_t size() const noexcept { return vec.size(); } 70 | 71 | private: 72 | std::vector> vec; 73 | }; 74 | } 75 | -------------------------------------------------------------------------------- /include/ascent/containers/stack.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2018 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | // An optimized stack container for Recorders 18 | 19 | #include 20 | #include 21 | 22 | namespace asc 23 | { 24 | template 25 | struct stack_iterator 26 | { 27 | stack_iterator(const size_t i, stack_t& _stack) noexcept : index(i % stack_t::block_size), slice(i / stack_t::block_size), stack(_stack), ptr(_stack.data(i)) {} 28 | 29 | stack_iterator(const stack_iterator&) noexcept = default; 30 | stack_iterator(stack_iterator&&) noexcept = default; 31 | stack_iterator& operator=(const stack_iterator&) noexcept = default; 32 | stack_iterator& operator=(stack_iterator&&) noexcept = default; 33 | 34 | using value_type = T; 35 | using pointer = T*; 36 | using reference = T&; 37 | using iterator_category = std::forward_iterator_tag; 38 | 39 | T& operator*() 40 | { 41 | return *ptr; 42 | } 43 | 44 | const T& operator*() const 45 | { 46 | return *ptr; 47 | } 48 | 49 | pointer operator->() noexcept 50 | { 51 | return ptr; 52 | } 53 | 54 | pointer operator->() const noexcept 55 | { 56 | return ptr; 57 | } 58 | 59 | stack_iterator& operator++() noexcept 60 | { 61 | ++index; 62 | ++ptr; 63 | if (index == stack_t::block_size) 64 | { 65 | index = 0; 66 | ++slice; 67 | ptr = stack.data_slice(slice); 68 | } 69 | return *this; 70 | } 71 | 72 | bool operator!=(const stack_iterator& rhs) const noexcept 73 | { 74 | if (index != rhs.index || slice != rhs.slice) 75 | return true; 76 | return false; 77 | } 78 | 79 | bool operator==(const stack_iterator& rhs) const noexcept 80 | { 81 | if (index == rhs.index && slice == rhs.slice) 82 | return true; 83 | return false; 84 | } 85 | 86 | private: 87 | size_t index{}; 88 | size_t slice{}; 89 | stack_t& stack; 90 | T* ptr; 91 | }; 92 | 93 | template 94 | struct const_stack_iterator 95 | { 96 | const_stack_iterator(const size_t i, stack_t& _stack) noexcept : index(i % stack_t::block_size), slice(i / stack_t::block_size), stack(_stack), ptr(_stack.data(i)) {} 97 | 98 | const_stack_iterator(const const_stack_iterator&) noexcept = default; 99 | const_stack_iterator(const_stack_iterator&&) noexcept = default; 100 | const_stack_iterator& operator=(const const_stack_iterator&) noexcept = default; 101 | const_stack_iterator& operator=(const_stack_iterator&&) noexcept = default; 102 | 103 | using value_type = T; 104 | using pointer = T*; 105 | using reference = T&; 106 | using iterator_category = std::forward_iterator_tag; 107 | 108 | const T& operator*() const 109 | { 110 | return *ptr; 111 | } 112 | 113 | pointer operator->() const 114 | { 115 | return ptr; 116 | } 117 | 118 | const_stack_iterator& operator++() noexcept 119 | { 120 | ++index; 121 | ++ptr; 122 | if (index == stack_t::block_size) 123 | { 124 | index = 0; 125 | ++slice; 126 | ptr = stack.data_slice(slice); 127 | } 128 | return *this; 129 | } 130 | 131 | bool operator!=(const const_stack_iterator& rhs) const noexcept 132 | { 133 | if (index != rhs.index || slice != rhs.slice) 134 | return true; 135 | return false; 136 | } 137 | 138 | bool operator==(const const_stack_iterator& rhs) const noexcept 139 | { 140 | if (index == rhs.index && slice == rhs.slice) 141 | return true; 142 | return false; 143 | } 144 | 145 | private: 146 | size_t index{}; 147 | size_t slice{}; 148 | stack_t& stack; 149 | T* ptr; 150 | }; 151 | 152 | template 153 | struct stack final 154 | { 155 | stack() noexcept 156 | { 157 | deq.emplace_back(); 158 | deq.back().reserve(block); 159 | } 160 | 161 | stack(const stack& other) 162 | { 163 | deq = other.deq; 164 | deq.back().reserve(block); // is not by default copied to the same size 165 | slice = other.slice; 166 | } 167 | stack(stack&&) = default; 168 | stack& operator=(const stack& other) 169 | { 170 | deq = other.deq; 171 | deq.back().reserve(block); // capacity is not by default copied to the same size 172 | slice = other.slice; 173 | return *this; 174 | } 175 | stack& operator=(stack&&) = default; 176 | 177 | static constexpr size_t block_size = block; 178 | 179 | using iterator = stack_iterator>; 180 | using const_iterator = const_stack_iterator>; 181 | 182 | iterator begin() 183 | { 184 | return{ 0, *this }; 185 | } 186 | 187 | iterator end() 188 | { 189 | return{ size(), *this }; 190 | } 191 | 192 | const_iterator cbegin() 193 | { 194 | return{ size(), *this }; 195 | } 196 | 197 | const_iterator cend() 198 | { 199 | return{ size(), *this }; 200 | } 201 | 202 | void emplace_back() noexcept 203 | { 204 | emplace_back(T()); 205 | } 206 | 207 | template 208 | void emplace_back(Arg&& x) noexcept 209 | { 210 | auto& s = deq[slice]; 211 | if (s.size() == block) 212 | { 213 | deq.emplace_back(); 214 | auto& v_back = deq.back(); 215 | v_back.reserve(block); 216 | v_back.emplace_back(std::forward(x)); 217 | ++slice; 218 | } 219 | else 220 | { 221 | s.emplace_back(std::forward(x)); 222 | } 223 | } 224 | 225 | T& operator[](const size_t i) noexcept 226 | { 227 | return deq[i / block][i % block]; 228 | } 229 | 230 | const T& operator[](const size_t i) const noexcept 231 | { 232 | return deq[i / block][i % block]; 233 | } 234 | 235 | T& operator()(const size_t slice_index, const size_t index) noexcept 236 | { 237 | return deq[slice_index][index]; 238 | } 239 | 240 | const T& operator()(const size_t slice_index, const size_t index) const noexcept 241 | { 242 | return deq[slice_index][index]; 243 | } 244 | 245 | T& front() 246 | { 247 | return deq.front().front(); 248 | } 249 | 250 | const T& front() const 251 | { 252 | return deq.front().front(); 253 | } 254 | 255 | T& back() 256 | { 257 | return deq.back().back(); 258 | } 259 | 260 | const T& back() const 261 | { 262 | return deq.back().back(); 263 | } 264 | 265 | size_t size() const noexcept 266 | { 267 | return (deq.size() - 1) * block + deq.back().size(); 268 | } 269 | 270 | T* data_slice(const size_t s) 271 | { 272 | if (s >= deq.size()) 273 | return nullptr; 274 | return deq[s].data(); 275 | } 276 | 277 | const T* data_slice(const size_t s) const 278 | { 279 | if (s >= deq.size()) 280 | return nullptr; 281 | return deq[s].data(); 282 | } 283 | 284 | T* data(const size_t i) 285 | { 286 | if (i / block >= deq.size()) 287 | return nullptr; 288 | return deq[i / block].data() + i % block; 289 | } 290 | 291 | const T* data(const size_t i) const 292 | { 293 | if (i / block >= deq.size()) 294 | return nullptr; 295 | return deq[i / block].data() + i % block; 296 | } 297 | 298 | void clear() 299 | { 300 | deq.resize(1); 301 | deq.front().resize(0); // we don't want to remove the capacity on the vector by calling clear 302 | } 303 | 304 | private: 305 | std::deque> deq; 306 | size_t slice{}; 307 | }; 308 | } 309 | -------------------------------------------------------------------------------- /include/ascent/direct/State.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | 20 | namespace asc 21 | { 22 | // pointers, rather than references are used for the possibility of developing states with shared_ptrs for x and xd 23 | struct State 24 | { 25 | State() = default; 26 | State(double& _x, double& _xd) noexcept : x(&_x), xd(&_xd) {} 27 | State(const State&) = default; 28 | State(State&&) = default; 29 | State& operator=(const State&) = default; 30 | State& operator=(State&&) = default; 31 | 32 | double* x{}; 33 | double* xd{}; 34 | 35 | std::vector memory; 36 | 37 | size_t hist_len = 0; 38 | std::deque x0_hist; 39 | std::deque xd0_hist; 40 | }; 41 | 42 | template 43 | inline void make_states(states_t& states, x_t& x, xd_t& xd) 44 | { 45 | const size_t n = x.size(); 46 | for (size_t i = 0; i < n; ++i) 47 | { 48 | states.emplace_back(x[i], xd[i]); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /include/ascent/integrators/ABM4.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/Utility.h" 18 | 19 | #include 20 | 21 | namespace asc 22 | { 23 | /// Fourth order Adams-Bashforth-Moulton Predictor Corrector. Fixed step version (Must reinitialize if dt is changed). 24 | /// 25 | /// \tparam state_t The state type of the system to be integrated. I.e. a std::vector or std::deque. 26 | template > 27 | struct ABM4T 28 | { 29 | using value_t = typename state_t::value_type; 30 | 31 | /// \brief Integration step operation 32 | /// 33 | /// Steps the system a single time step (dt), internally advances time (t) 34 | /// 35 | /// \tparam System The system object or function type. The system to be stepped must have a function syntax that takes \c (state_t, state_t, value_t) \c (x, xd, t). 36 | /// The system can be a function, functor, or lambda expression. Taken as an rvalue reference. 37 | /// \param[in, out] system The \c System instance. 38 | /// \param[in, out] x The system's state vector. 39 | /// \param[in, out] t The current time, which will be advanced by c\ dt. 40 | /// \param[in] dt The time step for the input system to be advanced. 41 | template 42 | void operator()(System &&system, state_t &x, value_t &t, const value_t dt) 43 | { 44 | if (initialized < 3) 45 | { 46 | const auto index = 2 - initialized; 47 | xd_prev[index].resize(x.size()); 48 | system(x, xd_prev[index], t); 49 | initializer(system, x, t, dt); 50 | ++initialized; 51 | return; 52 | } 53 | 54 | const size_t n = x.size(); 55 | if (xd0.size() < n) 56 | { 57 | xd0.resize(n); 58 | xd_temp.resize(n); 59 | } 60 | 61 | x0 = x; 62 | system(x, xd0, t); 63 | size_t i{}; 64 | for (; i < n; ++i) 65 | x[i] = x0[i] + c0 * dt * (55.0 * xd0[i] - 59.0 * xd_prev[0][i] + 37.0 * xd_prev[1][i] - 9.0 * xd_prev[2][i]); 66 | t += dt; 67 | 68 | system(x, xd_temp, t); 69 | for (i = 0; i < n; ++i) 70 | x[i] = x0[i] + c0 * dt * (9.0 * xd_temp[i] + 19.0 * xd0[i] - 5.0 * xd_prev[0][i] + xd_prev[1][i]); 71 | 72 | for (i = 2; i > 0; --i) 73 | xd_prev[i] = xd_prev[i - 1]; 74 | xd_prev[0] = xd0; 75 | } 76 | 77 | private: 78 | int initialized{}; 79 | init_integrator initializer; 80 | state_t x0, xd0, xd_temp; 81 | std::array xd_prev; //previous time step derivative 82 | 83 | static constexpr auto c0 = cx(1.0 / 24.0); 84 | }; 85 | } -------------------------------------------------------------------------------- /include/ascent/integrators/DOPRI45.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/Utility.h" 18 | 19 | // Runge Kutta Dormand Prince 45 20 | 21 | namespace asc 22 | { 23 | template 24 | struct DOPRI45T 25 | { 26 | using value_t = typename state_t::value_type; 27 | 28 | template 29 | void operator()(System&& system, state_t& x, value_t& t, const value_t dt) 30 | { 31 | const auto t0 = t; 32 | const auto dt_5 = 0.2_v * dt; 33 | 34 | const auto n = x.size(); 35 | if (xd0.size() < n) 36 | { 37 | xd0.resize(n); 38 | xd_temp.resize(n); 39 | xd2.resize(n); 40 | xd3.resize(n); 41 | xd4.resize(n); 42 | } 43 | 44 | x0 = x; 45 | 46 | if (!fsal_computed) // if an adaptive stepper hasn't computed the first same as last state, we must compute the step here 47 | { 48 | system(x0, xd0, t); 49 | fsal_computed = false; 50 | } 51 | 52 | size_t i{}; 53 | for (; i < n; ++i) 54 | x[i] = x0[i] + dt_5 * xd0[i]; 55 | t += dt_5; 56 | 57 | system(x, xd_temp, t); 58 | for (i = 0; i < n; ++i) 59 | x[i] = x0[i] + dt * (c10 * xd0[i] + c11 * xd_temp[i]); 60 | t = t0 + cx(3.0 / 10.0) * dt; 61 | 62 | system(x, xd2, t); 63 | for (i = 0; i < n; ++i) 64 | x[i] = x0[i] + dt * (c20 * xd0[i] + c21 * xd_temp[i] + c22 * xd2[i]); 65 | t = t0 + cx(4.0 / 5.0) * dt; 66 | 67 | system(x, xd3, t); 68 | for (i = 0; i < n; ++i) 69 | x[i] = x0[i] + dt * (c30 * xd0[i] + c31 * xd_temp[i] + c32 * xd2[i] + c33 * xd3[i]); 70 | t = t0 + cx(8.0 / 9.0) * dt; 71 | 72 | system(x, xd4, t); 73 | for (i = 0; i < n; ++i) 74 | x[i] = x0[i] + dt * (c40 * xd0[i] + c41 * xd_temp[i] + c42 * xd2[i] + c43 * xd3[i] + c44 * xd4[i]); 75 | t = t0 + dt; 76 | 77 | system(x, xd_temp, t); 78 | for (i = 0; i < n; ++i) 79 | x[i] = x0[i] + dt * (c50 * xd0[i] + c52 * xd2[i] + c53 * xd3[i] + c54 * xd4[i] + c55 * xd_temp[i]); 80 | } 81 | 82 | template 83 | void operator()(System&& system, state_t& x, value_t& t, value_t& dt, const AdaptiveT& settings) 84 | { 85 | const value_t abs_tol = settings.abs_tol; 86 | const value_t rel_tol = settings.rel_tol; 87 | const value_t safety_factor = settings.safety_factor; 88 | 89 | const value_t t0 = t; 90 | const size_t n = x.size(); 91 | 92 | xd6.resize(n); 93 | 94 | start_adaptive: 95 | operator()(system, x, t, dt); 96 | 97 | system(x, xd6, t); // xd6 is xd0, because first same as last (FSAL) 98 | 99 | // overwrite xd2 as the error estimate, this lets us vectorize the calculation of errors and saves memory 100 | for (size_t i = 0; i < n; ++i) 101 | { 102 | xd2[i] = abs(x0[i] + dt * (e0 * xd0[i] + e2 * xd2[i] + e3 * xd3[i] + e4 * xd4[i] + e5 * xd_temp[i] + e6 * xd6[i]) - x[i]); // absolute error estimate (x4th - x5th) 103 | } 104 | 105 | value_t e, e_max{}; 106 | for (size_t i = 0; i < n; ++i) 107 | { 108 | //e = xd2[i] / (abs_tol + rel_tol * (1.0 * abs(x0[i]) + 0.01 * abs(xd0[i]))); 109 | e = xd2[i] / (abs_tol + rel_tol * (abs(x0[i]) + 0.01 * abs(xd0[i]))); 110 | 111 | if (e > e_max) 112 | e_max = e; 113 | } 114 | 115 | if (e_max > 1.0_v) 116 | { 117 | dt *= std::max(0.9_v * pow(e_max, -cx(1.0 / 3.0)), 0.2_v); 118 | 119 | t = t0; 120 | x = x0; 121 | 122 | goto start_adaptive; // recompute the solution recursively 123 | } 124 | 125 | if (e_max < 0.5_v) 126 | { 127 | e_max = std::max(3.2e-4_v, e_max); // 3.2e-4 = pow(5, -5) 128 | dt *= 0.9_v * pow(e_max, -0.2_v); 129 | } 130 | 131 | xd0 = xd6; 132 | fsal_computed = true; 133 | } 134 | 135 | private: 136 | bool fsal_computed = false; 137 | 138 | static constexpr auto c10 = cx(3.0 / 40.0); 139 | static constexpr auto c11 = cx(9.0 / 40.0); 140 | 141 | static constexpr auto c20 = cx(44.0 / 45.0); 142 | static constexpr auto c21 = cx(-56.0 / 15.0); 143 | static constexpr auto c22 = cx(32.0 / 9.0); 144 | 145 | static constexpr auto c30 = cx(19372.0 / 6561.0); 146 | static constexpr auto c31 = cx(-25360.0 / 2187.0); 147 | static constexpr auto c32 = cx(64448.0 / 6561.0); 148 | static constexpr auto c33 = cx(-212.0 / 729.0); 149 | 150 | static constexpr auto c40 = cx(9017.0 / 3168.0); 151 | static constexpr auto c41 = cx(-355.0 / 33.0); 152 | static constexpr auto c42 = cx(46732.0 / 5247.0); 153 | static constexpr auto c43 = cx(49.0 / 176.0); 154 | static constexpr auto c44 = cx(-5103.0 / 18656.0); 155 | 156 | static constexpr auto c50 = cx(35.0 / 384.0); 157 | // c51 is 0 158 | static constexpr auto c52 = cx(500.0 / 1113.0); 159 | static constexpr auto c53 = cx(125.0 / 192.0); 160 | static constexpr auto c54 = cx(-2187.0 / 6784.0); 161 | static constexpr auto c55 = cx(11.0 / 84.0); 162 | 163 | static constexpr auto e0 = cx(5179.0 / 57600.0); 164 | // e1 is 0 165 | static constexpr auto e2 = cx(7571.0 / 16695.0); 166 | static constexpr auto e3 = cx(393.0 / 640.0); 167 | static constexpr auto e4 = cx(-92097.0 / 339200.0); 168 | static constexpr auto e5 = cx(187.0 / 2100.0); 169 | static constexpr auto e6 = cx(1.0 / 40.0); 170 | 171 | state_t x0, xd0, xd_temp, xd2, xd3, xd4, xd6; // xd_temp is used for xd1 and xd5 172 | }; 173 | } -------------------------------------------------------------------------------- /include/ascent/integrators/Euler.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | // Simple Euler integration. 18 | 19 | namespace asc 20 | { 21 | template 22 | struct EulerT 23 | { 24 | using value_t = typename state_t::value_type; 25 | 26 | template 27 | void operator()(System&& system, state_t& x, value_t& t, const value_t dt) 28 | { 29 | const size_t n = x.size(); 30 | if (xd.size() < n) 31 | xd.resize(n); 32 | 33 | system(x, xd, t); 34 | for (size_t i = 0; i < n; ++i) 35 | { 36 | x[i] += dt * xd[i]; 37 | } 38 | t += dt; 39 | } 40 | 41 | private: 42 | state_t xd; 43 | }; 44 | } -------------------------------------------------------------------------------- /include/ascent/integrators/Midpoint.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2018 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | // Modified Euler Midpoint integration 18 | 19 | namespace asc 20 | { 21 | template 22 | struct MidpointT 23 | { 24 | using value_t = typename state_t::value_type; 25 | 26 | template 27 | void operator()(System&& system, state_t& x, value_t& t, const value_t dt) 28 | { 29 | const size_t n = x.size(); 30 | if (xd.size() < n) 31 | { 32 | xd.resize(n); 33 | xd_new.resize(n); 34 | } 35 | 36 | system(x, xd_new, t); 37 | for (size_t i = 0; i < n; ++i) 38 | { 39 | x[i] += 0.5 * dt * (xd_new[i] + xd[i]); 40 | } 41 | xd = xd_new; 42 | t += dt; 43 | } 44 | 45 | private: 46 | state_t xd, xd_new; 47 | }; 48 | } -------------------------------------------------------------------------------- /include/ascent/integrators/PC233.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/Utility.h" 18 | #include "ascent/integrators/RK2.h" 19 | 20 | // P-2/PC-3/C-3 algorithm, which has the same error coefficient and order as the P-3/PC-3/C-3 predictor-corrector, but is more stable 21 | 22 | // Real Time (RT) Adam's Moulton predictor-corrector integration 23 | // Source: R.M. Howe. A new family of real-time predictor-corrector integration algorithms. The University of Michigan. September 1991. 24 | 25 | namespace asc 26 | { 27 | template > 28 | struct PC233T 29 | { 30 | using value_t = typename state_t::value_type; 31 | 32 | template 33 | void operator()(System&& system, state_t& x, value_t& t, const value_t dt) 34 | { 35 | if (!initialized) 36 | { 37 | initializer(system, x, t, dt); 38 | xd_1 = initializer.xd; 39 | initialized = true; 40 | return; 41 | } 42 | 43 | const value_t t0 = t; 44 | const value_t dt_3 = cx(1.0 / 3.0)*dt; 45 | 46 | const size_t n = x.size(); 47 | if (xd0.size() < n) 48 | { 49 | xd0.resize(n); 50 | xd_temp.resize(n); 51 | } 52 | 53 | x0 = x; 54 | system(x0, xd0, t); 55 | size_t i{}; 56 | for (; i < n; ++i) 57 | x[i] = x0[i] + c0 * dt * (7.0*xd0[i] - xd_1[i]); // X(n + 1/3), third step computation 58 | t += dt_3; 59 | 60 | system(x, xd_temp, t); 61 | for (i = 0; i < n; ++i) 62 | x[i] = x0[i] + c1 * dt * (39.0*xd_temp[i] - 4.0*xd0[i] + xd_1[i]); // X(n + 2/3), two thirds step computation 63 | t += dt_3; 64 | 65 | system(x, xd_temp, t); 66 | for (i = 0; i < n; ++i) 67 | x[i] = x0[i] + c2 * dt * (xd0[i] + 3.0*xd_temp[i]); 68 | xd_1 = xd0; 69 | t = t0 + dt; 70 | } 71 | 72 | private: 73 | bool initialized{}; 74 | init_integrator initializer; 75 | state_t x0, xd0, xd_temp; 76 | state_t xd_1; // -1, previous time step derivative 77 | 78 | static constexpr auto c0 = cx(1.0 / 18.0); 79 | static constexpr auto c1 = cx(1.0 / 54.0); 80 | static constexpr auto c2 = cx(1.0 / 4.0); 81 | }; 82 | } -------------------------------------------------------------------------------- /include/ascent/integrators/RK2.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/Utility.h" 18 | 19 | // Second order, two pass Runge Kutta. 20 | 21 | namespace asc 22 | { 23 | template 24 | struct RK2T 25 | { 26 | using value_t = typename state_t::value_type; 27 | 28 | template 29 | void operator()(System&& system, state_t& x, value_t& t, const value_t dt) 30 | { 31 | const value_t t0 = t; 32 | const value_t dt_2 = 0.5_v*dt; 33 | 34 | const size_t n = x.size(); 35 | if (xd.size() < n) 36 | xd.resize(n); 37 | 38 | x0 = x; 39 | system(x0, xd, t); 40 | size_t i{}; 41 | for (; i < n; ++i) 42 | x[i] = dt_2 * xd[i] + x0[i]; 43 | t += dt_2; 44 | 45 | system(x, xd, t); 46 | for (i = 0; i < n; ++i) 47 | x[i] = dt * xd[i] + x0[i]; 48 | t = t0 + dt; 49 | } 50 | 51 | state_t xd; 52 | 53 | private: 54 | state_t x0; 55 | }; 56 | } -------------------------------------------------------------------------------- /include/ascent/integrators/RK4.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/Utility.h" 18 | 19 | namespace asc 20 | { 21 | /// Fourth order, four pass Runge Kutta integrator. 22 | /// 23 | /// Designed for optimum speed and minimal memory load. We use one additional multiplication to reduce memory cost by 25%. 24 | /// \tparam state_t The state type of the system to be integrated. I.e. a std::vector or std::deque. 25 | template 26 | struct RK4T 27 | { 28 | using value_t = typename state_t::value_type; 29 | 30 | /// \brief Integration step operation 31 | /// 32 | /// Steps the system a single time step (dt), internally advances time (t) 33 | /// 34 | /// \tparam System The system object or function type. The system to be stepped must have a function syntax that takes \c (state_t, state_t, value_t) \c (x, xd, t). 35 | /// The system can be a function, functor, or lambda expression. Taken as an rvalue reference. 36 | /// \param[in, out] system The \c System instance. 37 | /// \param[in, out] x The system's state vector. 38 | /// \param[in, out] t The current time, which will be advanced by c\ dt. 39 | /// \param[in] dt The time step for the input system to be advanced. 40 | template 41 | void operator()(System&& system, state_t& x, value_t& t, const value_t dt) 42 | { 43 | const value_t t0 = t; 44 | const value_t dt_2 = 0.5_v*dt; 45 | const value_t dt_6 = cx(1.0 / 6.0)*dt; 46 | 47 | const size_t n = x.size(); 48 | if (xd.size() < n) 49 | { 50 | xd.resize(n); 51 | xd_temp.resize(n); 52 | } 53 | 54 | x0 = x; 55 | system(x0, xd, t); 56 | size_t i{}; 57 | for (; i < n; ++i) 58 | x[i] = dt_2 * xd[i] + x0[i]; 59 | t += dt_2; 60 | 61 | system(x, xd_temp, t); 62 | for (i = 0; i < n; ++i) 63 | { 64 | xd[i] += 2 * xd_temp[i]; 65 | x[i] = dt_2 * xd_temp[i] + x0[i]; 66 | } 67 | 68 | system(x, xd_temp, t); 69 | for (i = 0; i < n; ++i) 70 | { 71 | xd[i] += 2 * xd_temp[i]; 72 | x[i] = dt * xd_temp[i] + x0[i]; 73 | } 74 | t = t0 + dt; 75 | 76 | system(x, xd_temp, t); 77 | for (i = 0; i < n; ++i) 78 | x[i] = dt_6 * (xd[i] + xd_temp[i]) + x0[i]; 79 | } 80 | 81 | state_t xd; 82 | 83 | private: 84 | state_t x0, xd_temp; 85 | }; 86 | } -------------------------------------------------------------------------------- /include/ascent/integrators/RKMM.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/Utility.h" 18 | 19 | // Five pass Runge Kutta Merson's Method. With adaptive time stepping. 20 | 21 | namespace asc 22 | { 23 | template 24 | struct RKMMT 25 | { 26 | using value_t = typename state_t::value_type; 27 | 28 | // epsilon is the error tolerance 29 | RKMMT(const value_t epsilon) : epsilon(epsilon), epsilon_64(epsilon / static_cast(64.0)) {} 30 | 31 | template 32 | void operator()(System&& system, state_t& x, value_t& t, value_t& dt) 33 | { 34 | const value_t t0 = t; 35 | const value_t dt_2 = 0.5_v*dt; 36 | const value_t dt_3 = cx(1.0 / 3.0)*dt; 37 | const value_t dt_6 = cx(1.0 / 6.0)*dt; 38 | const value_t dt_8 = cx(1.0 / 8.0)*dt; 39 | 40 | const size_t n = x.size(); 41 | if (xd0.size() < n) 42 | { 43 | xd0.resize(n); 44 | xd2_temp.resize(n); 45 | xd3_temp.resize(n); 46 | xd_temp.resize(n); 47 | x3_temp.resize(n); 48 | } 49 | 50 | x0 = x; 51 | system(x0, xd0, t); 52 | size_t i{}; 53 | for (; i < n; ++i) 54 | x[i] = dt_3 * xd0[i] + x0[i]; 55 | t += dt_3; 56 | 57 | system(x, xd_temp, t); 58 | for (i = 0; i < n; ++i) 59 | x[i] = dt_6 * (xd0[i] + xd_temp[i]) + x0[i]; 60 | 61 | system(x, xd2_temp, t); 62 | for (i = 0; i < n; ++i) 63 | { 64 | xd2_temp[i] *= 3; // all uses of xd2 are 3*xd2, so we perform this multiplication only once 65 | x[i] = dt_8 * (xd0[i] + xd2_temp[i]) + x0[i]; 66 | } 67 | t = t0 + dt_2; 68 | 69 | system(x, xd3_temp, t); 70 | for (i = 0; i < n; ++i) 71 | { 72 | xd3_temp[i] *= 4; // all uses of xd3 are 4*xd3, so we perform this multiplication only once 73 | x[i] = dt_2 * (xd0[i] - xd2_temp[i] + xd3_temp[i]) + x0[i]; 74 | } 75 | x3_temp = x; // used for error estimation 76 | t = t0 + dt; 77 | 78 | system(x, xd_temp, t); 79 | for (i = 0; i < n; ++i) 80 | x[i] = dt_6 * (xd0[i] + xd3_temp[i] + xd_temp[i]) + x0[i]; 81 | 82 | // Adaptive time stepping would probably be best handled by a constexpr if, because we want the handling to be determined at compile time, perhaps by a templated boolean 83 | // https://www.encyclopediaofmath.org/index.php/Kutta-Merson_method#Eq-2 84 | 85 | value_t abs_diff; 86 | value_t max_abs_diff{}; 87 | for (i = 0; i < n; ++i) 88 | { 89 | abs_diff = abs(x3_temp[i] - x[i]); // absolute error estimate 90 | 91 | if (abs_diff > max_abs_diff) 92 | max_abs_diff = abs_diff; 93 | } 94 | 95 | const value_t R = fifth * max_abs_diff; 96 | 97 | if (R > epsilon) 98 | { 99 | dt *= half; // reduce the time step 100 | t = t0; 101 | x = x0; 102 | operator()(system, x, t, dt); // recompute the solution recursively 103 | } 104 | else if (R <= epsilon_64) 105 | dt *= 2; // increase the time step for future steps 106 | } 107 | 108 | private: 109 | state_t x0, xd0, xd2_temp, xd3_temp, xd_temp; 110 | state_t x3_temp; 111 | const value_t epsilon, epsilon_64; 112 | }; 113 | } -------------------------------------------------------------------------------- /include/ascent/integrators/RTAM4.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | // UNDER CONSTRUCTION 18 | 19 | #include "ascent/integrators/RK4.h" 20 | 21 | namespace asc 22 | { 23 | template 24 | struct RTAM4T 25 | { 26 | using value_t = typename state_t::value_type; 27 | 28 | template 29 | void operator()(System&& system, state_t& x, value_t& t, const value_t dt) 30 | { 31 | if (!initialized) 32 | { 33 | initializer(system, x, t, dt); 34 | } 35 | 36 | const value_t t0 = t; 37 | 38 | const size_t n = x.size(); 39 | if (xd.size() < n) 40 | { 41 | xd.resize(n); 42 | xd0.resize(n); 43 | xd_1.resize(n); 44 | xd_2.resize(n); 45 | xd_3.resize(n); 46 | } 47 | 48 | x0 = x; 49 | system(x0, xd, t); 50 | xd0 = xd; 51 | size_t i; 52 | for (i = 0; i < n; ++i) 53 | x[i] = x0[i] + dt * (c0*xd[i] + c1*xd_1[i] + c2*xd_2[i] + c3*xd_3[i]); 54 | t += 0.5_v * dt; 55 | 56 | system(x, xd, t); 57 | for (i = 0; i < n; ++i) 58 | x[i] = x0[i] + dt * (c4*xd[i] + c5*xd0[i] + c6*xd_1[i] + c7*xd_2[i]); 59 | t = t0 + dt; 60 | 61 | xd_3 = xd_2; 62 | xd_2 = xd_1; 63 | xd_1 = xd0; 64 | } 65 | 66 | private: 67 | bool initialized{}; 68 | 69 | RK4T initializer; 70 | 71 | static constexpr auto c0 = cx(297.0 / 384.0); 72 | static constexpr auto c1 = cx(-187.0 / 384.0); 73 | static constexpr auto c2 = cx(107.0 / 384.0); 74 | static constexpr auto c3 = cx(-25.0 / 384.0); 75 | 76 | static constexpr auto c4 = cx(36.0 / 30.0); 77 | static constexpr auto c5 = cx(-10.0 / 30.0); 78 | static constexpr auto c6 = cx(5.0 / 30.0); 79 | static constexpr auto c7 = cx(-1.0 / 30.0); 80 | 81 | state_t x0, xd, xd0, xd_1, xd_2, xd_3; 82 | }; 83 | } 84 | -------------------------------------------------------------------------------- /include/ascent/integrators_direct/Euler.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | // Simple Euler integration. 18 | 19 | namespace asc 20 | { 21 | namespace direct 22 | { 23 | template 24 | struct Euler 25 | { 26 | template 27 | void operator()(system_t&& system, states_t& states, value_t& t, const value_t dt) 28 | { 29 | const size_t n = states.size(); 30 | 31 | system(); 32 | for (size_t i = 0; i < n; ++i) 33 | { 34 | *states[i] += dt * *states[i].xd; 35 | } 36 | t += dt; 37 | } 38 | }; 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /include/ascent/integrators_direct/RK4.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/Utility.h" 18 | 19 | namespace asc 20 | { 21 | namespace direct 22 | { 23 | /// Fourth order, four pass Runge Kutta integrator. 24 | template 25 | struct RK4 26 | { 27 | template 28 | void operator()(system_t&& system, states_t& states, value_t& t, const value_t dt) 29 | { 30 | const auto t0 = t; 31 | const auto dt_2 = 0.5_v*dt; 32 | const auto dt_6 = cx(1.0 / 6.0)*dt; 33 | 34 | const size_t n = states.size(); 35 | if (x0.size() < n) 36 | { 37 | x0.resize(n); 38 | xd.resize(n); 39 | } 40 | 41 | size_t i{}; 42 | for (; i < n; ++i) 43 | x0[i] = *states[i].x; 44 | 45 | system(); 46 | for (i = 0; i < n; ++i) 47 | { 48 | xd[i] = *states[i].xd; 49 | *states[i].x = dt_2 * xd[i] + x0[i]; 50 | } 51 | t += dt_2; 52 | 53 | system(); 54 | for (i = 0; i < n; ++i) 55 | { 56 | const auto& xdi = *states[i].xd; 57 | xd[i] += 2 * xdi; 58 | *states[i].x = dt_2 * xdi + x0[i]; 59 | } 60 | 61 | system(); 62 | for (i = 0; i < n; ++i) 63 | { 64 | const auto& xdi = *states[i].xd; 65 | xd[i] += 2 * xdi; 66 | *states[i].x = dt * xdi + x0[i]; 67 | } 68 | t = t0 + dt; 69 | 70 | system(); 71 | for (i = 0; i < n; ++i) 72 | { 73 | *states[i].x = dt_6 * (xd[i] + *states[i].xd) + x0[i]; 74 | } 75 | } 76 | 77 | std::vector x0, xd; 78 | }; 79 | } 80 | } -------------------------------------------------------------------------------- /include/ascent/integrators_modular/ABM4.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/Utility.h" 18 | #include "ascent/integrators_modular/ModularIntegrators.h" 19 | #include "ascent/integrators_modular/RK4.h" 20 | 21 | // Fourth order Adams-Bashforth-Moulton Predictor Corrector. Fixed step version (Must reinitialize if dt is changed). 22 | namespace asc 23 | { 24 | namespace modular 25 | { 26 | template 27 | struct ABM4prop : public Propagator 28 | { 29 | void operator()(State &state, const value_t dt) override 30 | { 31 | auto &x = *state.x; 32 | auto &xd = *state.xd; 33 | if (state.memory.size() < 6) { 34 | state.memory.resize(6); 35 | } 36 | auto &x0 = state.memory[0]; 37 | auto &xd0 = state.memory[1]; 38 | auto &xp = state.memory[2]; // Can be used for error estimates 39 | auto &xd_1 = state.memory[3]; 40 | auto &xd_2 = state.memory[4]; 41 | auto &xd_3 = state.memory[5]; 42 | 43 | switch (Propagator::pass) 44 | { 45 | case 0: 46 | x0 = x; 47 | xd0 = xd; 48 | x = x0 + c0 * dt * (55.0 * xd0 - 59.0 * xd_1 + 37.0 * xd_2 - 9.0 * xd_3); 49 | xp = x; 50 | break; 51 | case 1: 52 | //x = x0 + c0 * dt * (9.0 * xd + 19.0 * xd0 - 5.0 * xd_1 + xd_2); 53 | x = x0 + c1 * dt * (251.0 * xd + 646.0 * xd0 - 264.0 * xd_1 + 106.0 * xd_2 - 19.0 * xd_3); 54 | xd_3 = xd_2; 55 | xd_2 = xd_1; 56 | xd_1 = xd0; 57 | break; 58 | } 59 | } 60 | 61 | private: 62 | static constexpr auto c0 = cx(1.0 / 24.0); 63 | static constexpr auto c1 = cx(1.0 / 720.0); 64 | }; 65 | 66 | template 67 | struct ABM4stepper : public TimeStepper 68 | { 69 | void operator()(const size_t pass, value_t &t, const value_t dt) override 70 | { 71 | switch (pass) 72 | { 73 | case 0: 74 | t += dt; 75 | break; 76 | case 1: 77 | break; 78 | } 79 | } 80 | }; 81 | 82 | template > 83 | struct ABM4 84 | { 85 | asc::Module *run_first{}; 86 | 87 | ABM4prop propagator; 88 | ABM4stepper stepper; 89 | 90 | template 91 | void operator()(modules_t &blocks, value_t &t, const value_t dt) 92 | { 93 | if (initialized < 3) 94 | { 95 | if (run_first) 96 | { 97 | initializer.run_first = run_first; 98 | } 99 | 100 | // Record full step state history 101 | if (initialized == 0) { 102 | if constexpr (is_pair_v::value_type>) 103 | { 104 | for (auto &block : blocks) 105 | { 106 | for (auto &state : block.second->states) 107 | { 108 | state.hist_len = 3; 109 | } 110 | } 111 | } 112 | else 113 | { 114 | for (auto &block : blocks) 115 | { 116 | for (auto &state : block->states) 117 | { 118 | state.hist_len = 3; 119 | } 120 | } 121 | } 122 | } 123 | 124 | // Run initializer integrator 125 | initializer(blocks, t, dt); 126 | ++initialized; 127 | 128 | if (initialized == 3) { 129 | // calc_phi for past steps and store in the states memory 130 | if constexpr (is_pair_v::value_type>) 131 | { 132 | for (auto &block : blocks) 133 | { 134 | for (auto &state : block.second->states) 135 | { 136 | if (state.memory.size() < 6) { 137 | state.memory.resize(6); 138 | } 139 | for (size_t k = 0; k < 3; ++k) { 140 | state.memory[5 - k] = state.xd0_hist[k]; 141 | state.hist_len = 0; // We dont need to track the history anymore 142 | } 143 | } 144 | } 145 | } 146 | else 147 | { 148 | for (auto &block : blocks) 149 | { 150 | for (auto &state : block->states) 151 | { 152 | if (state.memory.size() < 6) { 153 | state.memory.resize(6); 154 | } 155 | for (size_t k = 0; k < 3; ++k) { 156 | state.memory[5 - k] = state.xd0_hist[k]; 157 | state.hist_len = 0; // We dont need to track the history anymore 158 | } 159 | } 160 | } 161 | } 162 | } 163 | return; 164 | } 165 | 166 | auto &pass = propagator.pass; 167 | pass = 0; 168 | 169 | update(blocks, run_first); 170 | apply(blocks); 171 | propagate(blocks, propagator, dt); 172 | stepper(pass, t, dt); 173 | postprop(blocks); 174 | ++pass; 175 | 176 | update(blocks, run_first); 177 | apply(blocks); 178 | propagate(blocks, propagator, dt); 179 | stepper(pass, t, dt); 180 | postprop(blocks); 181 | } 182 | 183 | size_t initialized = 0; 184 | init_integrator initializer; 185 | }; 186 | } 187 | } -------------------------------------------------------------------------------- /include/ascent/integrators_modular/DOPRI45.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2020 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/modular/Module.h" 18 | #include "ascent/integrators_modular/ModularIntegrators.h" 19 | #include "ascent/timing/Timing.h" 20 | #include "ascent/Utility.h" 21 | 22 | namespace asc 23 | { 24 | namespace modular 25 | { 26 | template 27 | struct DOPRI45prop : public Propagator 28 | { 29 | void operator()(State& state, const value_t dt) override 30 | { 31 | const auto dt_5 = 0.2_v * dt; 32 | 33 | auto& x = *state.x; 34 | auto& xd = *state.xd; 35 | if (state.memory.size() < 7) 36 | { 37 | state.memory.resize(7); 38 | } 39 | auto& x0 = state.memory[0]; 40 | auto& xd0 = state.memory[1]; 41 | auto& xd_temp = state.memory[2]; // xd_temp is used for xd1 and xd5 42 | auto& xd2 = state.memory[3]; 43 | auto& xd3 = state.memory[4]; 44 | auto& xd4 = state.memory[5]; 45 | auto& xd6 = state.memory[6]; 46 | 47 | switch (Propagator::pass) 48 | { 49 | case 0: 50 | x0 = x; 51 | xd0 = xd; 52 | x = x0 + dt_5 * xd0; 53 | break; 54 | case 1: 55 | xd_temp = xd; 56 | x = x0 + dt * (c10 * xd0 + c11 * xd_temp); 57 | break; 58 | case 2: 59 | xd2 = xd; 60 | x = x0 + dt * (c20 * xd0 + c21 * xd_temp + c22 * xd2); 61 | break; 62 | case 3: 63 | xd3 = xd; 64 | x = x0 + dt * (c30 * xd0 + c31 * xd_temp + c32 * xd2 + c33 * xd3); 65 | case 4: 66 | xd4 = xd; 67 | x = x0 + dt * (c40 * xd0 + c41 * xd_temp + c42 * xd2 + c43 * xd3 + c44 * xd4); 68 | break; 69 | case 5: 70 | xd_temp = xd; 71 | x = x0 + dt * (c50 * xd0 + c52 * xd2 + c53 * xd3 + c54 * xd4 + c55 * xd_temp); 72 | break; 73 | default: 74 | break; 75 | } 76 | } 77 | 78 | private: 79 | static constexpr auto c10 = cx(3.0 / 40.0); 80 | static constexpr auto c11 = cx(9.0 / 40.0); 81 | 82 | static constexpr auto c20 = cx(44.0 / 45.0); 83 | static constexpr auto c21 = cx(-56.0 / 15.0); 84 | static constexpr auto c22 = cx(32.0 / 9.0); 85 | 86 | static constexpr auto c30 = cx(19372.0 / 6561.0); 87 | static constexpr auto c31 = cx(-25360.0 / 2187.0); 88 | static constexpr auto c32 = cx(64448.0 / 6561.0); 89 | static constexpr auto c33 = cx(-212.0 / 729.0); 90 | 91 | static constexpr auto c40 = cx(9017.0 / 3168.0); 92 | static constexpr auto c41 = cx(-355.0 / 33.0); 93 | static constexpr auto c42 = cx(46732.0 / 5247.0); 94 | static constexpr auto c43 = cx(49.0 / 176.0); 95 | static constexpr auto c44 = cx(-5103.0 / 18656.0); 96 | 97 | static constexpr auto c50 = cx(35.0 / 384.0); 98 | // c51 is 0 99 | static constexpr auto c52 = cx(500.0 / 1113.0); 100 | static constexpr auto c53 = cx(125.0 / 192.0); 101 | static constexpr auto c54 = cx(-2187.0 / 6784.0); 102 | static constexpr auto c55 = cx(11.0 / 84.0); 103 | }; 104 | 105 | template 106 | struct DOPRI45stepper : public TimeStepper 107 | { 108 | value_t t0{}; 109 | 110 | void operator()(const size_t pass, value_t& t, const value_t dt) override 111 | { 112 | switch (pass) 113 | { 114 | case 0: 115 | t0 = t; 116 | t += 0.2_v * dt; 117 | break; 118 | case 1: 119 | t = t0 + cx(3.0 / 10.0) * dt; 120 | break; 121 | case 2: 122 | t = t0 + cx(4.0 / 5.0) * dt; 123 | break; 124 | case 3: 125 | t = t0 + cx(8.0 / 9.0) * dt; 126 | break; 127 | case 4: 128 | t = t0 + dt; 129 | break; 130 | default: 131 | break; 132 | } 133 | } 134 | }; 135 | 136 | template 137 | struct DOPRI45 : AdaptiveIntegrator 138 | { 139 | static constexpr size_t n_substeps = 5; 140 | 141 | DOPRI45prop propagator; 142 | DOPRI45stepper stepper; 143 | 144 | bool fsal_computed = false; 145 | 146 | asc::Timing* run_first{}; 147 | 148 | template 149 | void system(modules_t& blocks, value_t& t, const value_t dt) 150 | { 151 | if (!fsal_computed) // if an adaptive stepper hasn't computed the first same as last state, we must compute the step here 152 | { 153 | update(blocks); 154 | apply(blocks); 155 | 156 | auto solve = [&](auto& state) 157 | { 158 | auto& xd = *state.xd; 159 | if (state.memory.size() < 7) 160 | { 161 | state.memory.resize(7); 162 | } 163 | auto& xd0 = state.memory[1]; 164 | xd0 = xd; 165 | }; 166 | 167 | for (auto& block : blocks) 168 | { 169 | if constexpr (is_pair_v::value_type>) 170 | { 171 | for (auto& state : block.second->states) 172 | { 173 | solve(state); 174 | } 175 | } 176 | else 177 | { 178 | for (auto& state : block->states) 179 | { 180 | solve(state); 181 | } 182 | } 183 | } 184 | fsal_computed = false; 185 | } 186 | 187 | auto& pass = propagator.pass; 188 | pass = 0; 189 | 190 | for (auto i = 0; i < 5; ++i) 191 | { 192 | update(blocks); 193 | apply(blocks); 194 | propagate(blocks, propagator, dt); 195 | stepper(pass, t, dt); 196 | postprop(blocks); 197 | ++pass; 198 | } 199 | 200 | update(blocks); 201 | apply(blocks); 202 | propagate(blocks, propagator, dt); 203 | postprop(blocks); 204 | } 205 | 206 | template 207 | void operator()(modules_t& blocks, value_t& t, value_t& dt, const AdaptiveT& settings) 208 | { 209 | const value_t abs_tol = settings.abs_tol; 210 | const value_t rel_tol = settings.rel_tol; 211 | const value_t safety_factor = settings.safety_factor; 212 | 213 | const value_t t0 = t; 214 | 215 | start_adaptive: 216 | system(blocks, t, dt); 217 | 218 | // xd6 is xd0, because first same as last (FSAL) 219 | update(blocks); 220 | apply(blocks); 221 | for (auto& block : blocks) 222 | { 223 | auto solve = [&](auto& state) 224 | { 225 | auto& xd = *state.xd; 226 | if (state.memory.size() < 7) 227 | { 228 | state.memory.resize(7); 229 | } 230 | auto& xd6 = state.memory[6]; 231 | xd6 = xd; 232 | }; 233 | 234 | if constexpr (is_pair_v::value_type>) 235 | { 236 | for (auto& state : block.second->states) 237 | { 238 | solve(state); 239 | } 240 | } 241 | else 242 | { 243 | for (auto& state : block->states) 244 | { 245 | solve(state); 246 | } 247 | } 248 | } 249 | 250 | value_t e_max{}; 251 | for (auto& block : blocks) 252 | { 253 | auto solve = [&](auto& state) 254 | { 255 | auto& x = *state.x; 256 | auto& xd = *state.xd; 257 | if (state.memory.size() < 7) 258 | { 259 | state.memory.resize(7); 260 | } 261 | auto& x0 = state.memory[0]; 262 | auto& xd0 = state.memory[1]; 263 | auto& xd_temp = state.memory[2]; // xd_temp is used for xd1 and xd5 264 | auto& xd2 = state.memory[3]; 265 | auto& xd3 = state.memory[4]; 266 | auto& xd4 = state.memory[5]; 267 | auto& xd6 = state.memory[6]; 268 | 269 | // overwrite xd2 as the error estimate, this saves memory 270 | xd2 = abs(x0 + dt * (e0 * xd0 + e2 * xd2 + e3 * xd3 + e4 * xd4 + e5 * xd_temp + e6 * xd6) - x); // absolute error estimate (x4th - x5th) 271 | 272 | value_t e = xd2 / (abs_tol + rel_tol * (abs(x0) + 0.01 * abs(xd0))); 273 | 274 | if (e > e_max) 275 | { 276 | e_max = e; 277 | } 278 | }; 279 | 280 | if constexpr (is_pair_v::value_type>) 281 | { 282 | for (auto& state : block.second->states) 283 | { 284 | solve(state); 285 | } 286 | } 287 | else 288 | { 289 | for (auto& state : block->states) 290 | { 291 | solve(state); 292 | } 293 | } 294 | } 295 | 296 | if (e_max > 1.0) 297 | { 298 | dt *= std::max(0.9_v * pow(e_max, -cx(1.0 / 3.0)), 0.2_v); 299 | 300 | if (run_first) { 301 | run_first->base_time_step(dt); 302 | } 303 | 304 | t = t0; 305 | 306 | for (auto& block : blocks) 307 | { 308 | auto solve = [&](auto& state) 309 | { 310 | *state.x = state.memory[0]; 311 | }; 312 | 313 | if constexpr (is_pair_v::value_type>) 314 | { 315 | for (auto& state : block.second->states) 316 | { 317 | solve(state); 318 | } 319 | } 320 | else 321 | { 322 | for (auto& state : block->states) 323 | { 324 | solve(state); 325 | } 326 | } 327 | } 328 | 329 | goto start_adaptive; // recompute the solution recursively 330 | } 331 | 332 | if (e_max < 0.5_v) 333 | { 334 | e_max = std::max(3.2e-4_v, e_max); // 3.2e-4 = pow(5, -5) 335 | dt *= 0.9_v * pow(e_max, -0.2_v); 336 | 337 | if (run_first) { 338 | run_first->base_time_step(dt); 339 | } 340 | } 341 | 342 | for (auto& block : blocks) 343 | { 344 | auto solve = [&](auto& state) 345 | { 346 | auto& xd = *state.xd; 347 | if (state.memory.size() < 7) 348 | { 349 | state.memory.resize(7); 350 | } 351 | auto& xd0 = state.memory[1]; 352 | auto& xd6 = state.memory[6]; 353 | xd0 = xd6; 354 | }; 355 | 356 | if constexpr (is_pair_v::value_type>) 357 | { 358 | for (auto& state : block.second->states) 359 | { 360 | solve(state); 361 | } 362 | } 363 | else 364 | { 365 | for (auto& state : block->states) 366 | { 367 | solve(state); 368 | } 369 | } 370 | } 371 | 372 | fsal_computed = true; 373 | } 374 | 375 | private: 376 | static constexpr auto e0 = cx(5179.0 / 57600.0); 377 | // e1 is 0 378 | static constexpr auto e2 = cx(7571.0 / 16695.0); 379 | static constexpr auto e3 = cx(393.0 / 640.0); 380 | static constexpr auto e4 = cx(-92097.0 / 339200.0); 381 | static constexpr auto e5 = cx(187.0 / 2100.0); 382 | static constexpr auto e6 = cx(1.0 / 40.0); 383 | }; 384 | } 385 | } 386 | -------------------------------------------------------------------------------- /include/ascent/integrators_modular/Euler.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | // Simple Euler integration. 18 | 19 | #include "ascent/modular/Module.h" 20 | #include "ascent/direct/State.h" 21 | #include "ascent/integrators_modular/ModularIntegrators.h" 22 | 23 | namespace asc 24 | { 25 | namespace modular 26 | { 27 | template 28 | struct EulerProp : public Propagator 29 | { 30 | void operator()(State& state, const value_t dt) override 31 | { 32 | *state.x += dt * *state.xd; 33 | } 34 | }; 35 | 36 | template 37 | struct Euler 38 | { 39 | static constexpr size_t n_substeps = 1; 40 | 41 | asc::Module* run_first{}; 42 | 43 | EulerProp propagator; 44 | 45 | template 46 | void operator()(modules_t& blocks, value_t& t, const value_t dt) 47 | { 48 | update(blocks, run_first); 49 | apply(blocks); 50 | propagate(blocks, propagator, dt); 51 | t += dt; 52 | postprop(blocks); 53 | } 54 | }; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /include/ascent/integrators_modular/Heun.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/modular/Module.h" 18 | #include "ascent/integrators_modular/ModularIntegrators.h" 19 | 20 | // Heun's Method 21 | 22 | namespace asc 23 | { 24 | namespace modular 25 | { 26 | template 27 | struct Heunprop : public Propagator 28 | { 29 | void operator()(State& state, const value_t dt) override 30 | { 31 | auto& x = *state.x; 32 | auto& xd = *state.xd; 33 | state.memory.resize(2); 34 | auto& x0 = state.memory[0]; 35 | auto& xd0 = state.memory[1]; 36 | 37 | switch (Propagator::pass) 38 | { 39 | case 0: 40 | x0 = x; 41 | xd0 = xd; //k1 42 | x = x0 + dt * xd; 43 | break; 44 | case 1: 45 | x = x0 + dt * 0.5 * ( xd0 + xd ); 46 | break; 47 | } 48 | } 49 | }; 50 | 51 | template 52 | struct Heunstepper : public TimeStepper 53 | { 54 | value_t t0{}; 55 | 56 | void operator()(const size_t pass, value_t& t, const value_t dt) override 57 | { 58 | switch (pass) 59 | { 60 | case 0: 61 | t0 = t; 62 | t += dt; 63 | break; 64 | case 1: 65 | t = t0 + dt; 66 | break; 67 | default: 68 | break; 69 | } 70 | } 71 | }; 72 | 73 | template 74 | struct Heun 75 | { 76 | static constexpr size_t n_substeps = 2; 77 | 78 | asc::Module* run_first{}; 79 | 80 | Heunprop propagator; 81 | Heunstepper stepper; 82 | 83 | template 84 | void operator()(modules_t& blocks, value_t& t, const value_t dt) 85 | { 86 | auto& pass = propagator.pass; 87 | pass = 0; 88 | 89 | update(blocks, run_first); 90 | apply(blocks); 91 | propagate(blocks, propagator, dt); 92 | stepper(pass, t, dt); 93 | postprop(blocks); 94 | ++pass; 95 | 96 | update(blocks, run_first); 97 | apply(blocks); 98 | propagate(blocks, propagator, dt); 99 | stepper(pass, t, dt); 100 | postprop(blocks); 101 | } 102 | }; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /include/ascent/integrators_modular/Midpoint.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/modular/Module.h" 18 | #include "ascent/integrators_modular/ModularIntegrators.h" 19 | 20 | namespace asc 21 | { 22 | namespace modular 23 | { 24 | template 25 | struct MidpointProp : public Propagator 26 | { 27 | void operator()(State& state, const value_t dt) override 28 | { 29 | if (state.memory.empty()) 30 | { 31 | state.memory.resize(1); 32 | state.memory[0] = 0.0; 33 | } 34 | auto& xd0 = state.memory[0]; 35 | 36 | auto& xd = *state.xd; 37 | *state.x += 0.5 * dt * (xd0 + xd); 38 | xd0 = xd; 39 | } 40 | }; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /include/ascent/integrators_modular/ModularIntegrators.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | namespace asc 18 | { 19 | namespace modular 20 | { 21 | template 22 | struct TimeStepper 23 | { 24 | TimeStepper() = default; 25 | TimeStepper(const TimeStepper&) = default; 26 | TimeStepper(TimeStepper&&) = default; 27 | TimeStepper& operator=(const TimeStepper&) = default; 28 | TimeStepper& operator=(TimeStepper&&) = default; 29 | virtual ~TimeStepper() {} 30 | 31 | virtual void operator()(const size_t, value_t&, const value_t) = 0; // inputs: pass, t (time), dt (time step) 32 | }; 33 | } 34 | } -------------------------------------------------------------------------------- /include/ascent/integrators_modular/NCRK4.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/modular/Module.h" 18 | #include "ascent/integrators_modular/ModularIntegrators.h" 19 | 20 | // Non-confluent RK4 method ( "3/8th's Rule" ) 21 | 22 | namespace asc 23 | { 24 | namespace modular 25 | { 26 | template 27 | struct NCRK4prop : public Propagator 28 | { 29 | void operator()(State& state, const value_t dt) override 30 | { 31 | auto& x = *state.x; 32 | auto& xd = *state.xd; 33 | state.memory.resize(5); 34 | auto& x0 = state.memory[0]; 35 | auto& xd0 = state.memory[1]; 36 | auto& xd1 = state.memory[2]; 37 | auto& xd2 = state.memory[3]; 38 | auto& xd3 = state.memory[4]; 39 | 40 | switch (Propagator::pass) 41 | { 42 | case 0: 43 | x0 = x; 44 | xd0 = xd; // k1 45 | x = x0 + (1.0/3.0) * dt * xd0; 46 | break; 47 | case 1: 48 | xd1 = xd; // k2 49 | x = x0 + dt * ( (-1.0/3.0) * xd0 + xd1) ; 50 | break; 51 | case 2: 52 | xd2 = xd; // k3 53 | x = x0 + dt * ( xd0 - xd1 + xd2); 54 | break; 55 | case 3: 56 | xd3 = xd; // k4 57 | x = x0 + dt / 8.0 * (xd0 + 3.0 * xd1 + 3.0 * xd2 + xd3); 58 | break; 59 | } 60 | } 61 | }; 62 | 63 | template 64 | struct NCRK4stepper : public TimeStepper 65 | { 66 | value_t t0{}; 67 | 68 | void operator()(const size_t pass, value_t& t, const value_t dt) override 69 | { 70 | switch (pass) 71 | { 72 | case 0: 73 | t0 = t; 74 | t += 1.0/3.0 * dt; 75 | break; 76 | case 1: 77 | t = t0 + 2.0/3.0 * dt; 78 | break; 79 | case 2: 80 | t = t0 + dt; 81 | break; 82 | default: 83 | break; 84 | } 85 | } 86 | }; 87 | 88 | template 89 | struct NCRK4 90 | { 91 | static constexpr size_t n_substeps = 4; 92 | 93 | asc::Module* run_first{}; 94 | 95 | NCRK4prop propagator; 96 | NCRK4stepper stepper; 97 | 98 | template 99 | void operator()(modules_t& blocks, value_t& t, const value_t dt) 100 | { 101 | auto& pass = propagator.pass; 102 | pass = 0; 103 | 104 | update(blocks, run_first); 105 | apply(blocks); 106 | propagate(blocks, propagator, dt); 107 | stepper(pass, t, dt); 108 | postprop(blocks); 109 | ++pass; 110 | 111 | update(blocks, run_first); 112 | apply(blocks); 113 | propagate(blocks, propagator, dt); 114 | postprop(blocks); 115 | ++pass; 116 | 117 | update(blocks, run_first); 118 | apply(blocks); 119 | propagate(blocks, propagator, dt); 120 | stepper(pass, t, dt); 121 | postprop(blocks); 122 | ++pass; 123 | 124 | update(blocks, run_first); 125 | apply(blocks); 126 | propagate(blocks, propagator, dt); 127 | postprop(blocks); 128 | } 129 | }; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /include/ascent/integrators_modular/PC233.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/Utility.h" 18 | #include "ascent/integrators_modular/ModularIntegrators.h" 19 | #include "ascent/integrators_modular/RK4.h" 20 | 21 | // P-2/PC-3/C-3 algorithm, which has the same error coefficient and order as the P-3/PC-3/C-3 predictor-corrector, but is more stable 22 | 23 | // Real Time (RT) Adam's Moulton predictor-corrector integration 24 | // Source: R.M. Howe. A new family of real-time predictor-corrector integration algorithms. The University of Michigan. September 1991. 25 | 26 | namespace asc 27 | { 28 | namespace modular 29 | { 30 | template 31 | struct PC233prop : public Propagator 32 | { 33 | void operator()(State& state, const value_t dt) override 34 | { 35 | auto& x = *state.x; 36 | auto& xd = *state.xd; 37 | if (state.memory.size() < 5) { 38 | state.memory.resize(5); 39 | } 40 | auto& x0 = state.memory[0]; 41 | auto& xd0 = state.memory[1]; 42 | auto& xd1 = state.memory[2]; 43 | auto& xd2 = state.memory[3]; 44 | auto& xd_1 = state.memory[4]; 45 | 46 | switch (Propagator::pass) 47 | { 48 | case 0: 49 | x0 = x; 50 | xd0 = xd; 51 | x = x0 + c0 * dt * (7 * xd0 - xd_1); // X(n + 1/3), third step computation 52 | break; 53 | case 1: 54 | xd1 = xd; 55 | x = x0 + c1 * dt * (39 * xd1 - 4 * xd0 + xd_1); // X(n + 2/3), two thirds step computation 56 | break; 57 | case 2: 58 | xd2 = xd; 59 | x = x0 + c2 * dt * (xd0 + 3 * xd2); 60 | xd_1 = xd0; 61 | break; 62 | } 63 | } 64 | 65 | private: 66 | static constexpr auto c0 = cx(1.0 / 18.0); 67 | static constexpr auto c1 = cx(1.0 / 54.0); 68 | static constexpr auto c2 = cx(1.0 / 4.0); 69 | }; 70 | 71 | template 72 | struct PC233stepper : public TimeStepper 73 | { 74 | value_t t0{}; 75 | 76 | void operator()(const size_t pass, value_t& t, const value_t dt) override 77 | { 78 | switch (pass) 79 | { 80 | case 0: 81 | t0 = t; 82 | t += (1.0 / 3.0) * dt; 83 | break; 84 | case 1: 85 | t += (1.0 / 3.0) * dt; 86 | break; 87 | case 2: 88 | t = t0 + dt; 89 | break; 90 | } 91 | } 92 | }; 93 | 94 | template > 95 | struct PC233 96 | { 97 | static constexpr size_t n_substeps = 3; 98 | 99 | asc::Module* run_first{}; 100 | 101 | PC233prop propagator; 102 | PC233stepper stepper; 103 | 104 | template 105 | void operator()(modules_t& blocks, value_t& t, const value_t dt) 106 | { 107 | if (!initialized) 108 | { 109 | if (run_first) 110 | { 111 | initializer.run_first = run_first; 112 | } 113 | // Run initializer integrator 114 | initializer(blocks, t, dt); 115 | 116 | if constexpr (is_pair_v::value_type>) 117 | { 118 | // Assign previous time step's derivative 119 | for (auto& block : blocks) 120 | { 121 | for (auto& state : block.second->states) 122 | { 123 | state.memory.resize(5); 124 | auto& xd_1 = state.memory[4]; 125 | xd_1 = *state.xd; 126 | } 127 | } 128 | } 129 | else 130 | { 131 | // Assign previous time step's derivative 132 | for (auto& block : blocks) 133 | { 134 | for (auto& state : block->states) 135 | { 136 | state.memory.resize(5); 137 | auto& xd_1 = state.memory[4]; 138 | xd_1 = *state.xd; 139 | } 140 | } 141 | } 142 | 143 | initialized = true; 144 | return; 145 | } 146 | auto& pass = propagator.pass; 147 | pass = 0; 148 | 149 | update(blocks, run_first); 150 | apply(blocks); 151 | propagate(blocks, propagator, dt); 152 | stepper(pass, t, dt); 153 | postprop(blocks); 154 | ++pass; 155 | 156 | update(blocks, run_first); 157 | apply(blocks); 158 | propagate(blocks, propagator, dt); 159 | stepper(pass, t, dt); 160 | postprop(blocks); 161 | ++pass; 162 | 163 | update(blocks, run_first); 164 | apply(blocks); 165 | propagate(blocks, propagator, dt); 166 | stepper(pass, t, dt); 167 | postprop(blocks); 168 | } 169 | 170 | private: 171 | bool initialized{}; 172 | init_integrator initializer; 173 | }; 174 | } 175 | 176 | } 177 | -------------------------------------------------------------------------------- /include/ascent/integrators_modular/RK2.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | //#include "ascent/Utility.h" 18 | #include "ascent/modular/Module.h" 19 | #include "ascent/integrators_modular/ModularIntegrators.h" 20 | 21 | // Second order, two pass Runge Kutta. 22 | 23 | namespace asc 24 | { 25 | namespace modular 26 | { 27 | template 28 | struct RK2prop : public Propagator 29 | { 30 | void operator()(State& state, const value_t dt) override 31 | { 32 | auto& x = *state.x; 33 | auto& xd = *state.xd; 34 | if (state.memory.size() < 1) 35 | { 36 | state.memory.resize(1); 37 | } 38 | auto& x0 = state.memory[0]; 39 | 40 | switch (Propagator::pass) 41 | { 42 | case 0: 43 | x0 = x; 44 | x = x0 + 0.5 * dt * xd; 45 | break; 46 | case 1: 47 | x = x0 + dt * xd; 48 | break; 49 | default: 50 | break; 51 | } 52 | } 53 | }; 54 | 55 | template 56 | struct RK2stepper : public TimeStepper 57 | { 58 | value_t t0{}; 59 | 60 | void operator()(const size_t pass, value_t& t, const value_t dt) override 61 | { 62 | switch (pass) 63 | { 64 | case 0: 65 | t0 = t; 66 | t += 0.5 * dt; 67 | break; 68 | case 1: 69 | t = t0 + dt; 70 | break; 71 | default: 72 | break; 73 | } 74 | } 75 | }; 76 | 77 | template 78 | struct RK2 79 | { 80 | static constexpr size_t n_substeps = 2; 81 | 82 | asc::Module* run_first{}; 83 | 84 | RK2prop propagator; 85 | RK2stepper stepper; 86 | 87 | template 88 | void operator()(modules_t& blocks, value_t& t, const value_t dt) 89 | { 90 | auto& pass = propagator.pass; 91 | pass = 0; 92 | 93 | update(blocks, run_first); 94 | apply(blocks); 95 | propagate(blocks, propagator, dt); 96 | stepper(pass, t, dt); 97 | postprop(blocks); 98 | ++pass; 99 | 100 | update(blocks, run_first); 101 | apply(blocks); 102 | propagate(blocks, propagator, dt); 103 | stepper(pass, t, dt); 104 | postprop(blocks); 105 | } 106 | }; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /include/ascent/integrators_modular/RK3.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/modular/Module.h" 18 | #include "ascent/integrators_modular/ModularIntegrators.h" 19 | 20 | // Third order, Three stage Runge Kutta (Heun's 3rd Order). 21 | 22 | namespace asc 23 | { 24 | namespace modular 25 | { 26 | template 27 | struct RK3prop : public Propagator 28 | { 29 | void operator()(State& state, const value_t dt) override 30 | { 31 | auto& x = *state.x; 32 | auto& xd = *state.xd; 33 | state.memory.resize(4); 34 | auto& x0 = state.memory[0]; 35 | auto& xd0 = state.memory[1]; 36 | auto& xd1 = state.memory[2]; 37 | auto& xd2 = state.memory[3]; 38 | 39 | switch (Propagator::pass) 40 | { 41 | case 0: 42 | x0 = x; 43 | xd0 = xd; // k1 44 | x = x0 + dt * (1.0/3.0) * xd0; 45 | break; 46 | case 1: 47 | xd1 = xd; // k2 48 | x = x0 + dt * (2.0/3.0) * xd1; 49 | break; 50 | case 2: 51 | xd2 = xd; // k3 52 | x = x0 + dt * ( (1.0/4.0)*xd0 + (3.0/4.0)*xd2 ); 53 | break; 54 | } 55 | } 56 | }; 57 | 58 | template 59 | struct RK3stepper : public TimeStepper 60 | { 61 | value_t t0{}; 62 | 63 | void operator()(const size_t pass, value_t& t, const value_t dt) override 64 | { 65 | switch (pass) 66 | { 67 | case 0: 68 | t0 = t; 69 | t += (1.0/3.0) * dt; 70 | break; 71 | case 1: 72 | t = t0 + (2.0/3.0) * dt; 73 | break; 74 | case 2: 75 | t = t0 + dt; 76 | break; 77 | default: 78 | break; 79 | } 80 | } 81 | }; 82 | 83 | template 84 | struct RK3 85 | { 86 | static constexpr size_t n_substeps = 3; 87 | 88 | asc::Module* run_first{}; 89 | 90 | RK3prop propagator; 91 | RK3stepper stepper; 92 | 93 | template 94 | void operator()(modules_t& blocks, value_t& t, const value_t dt) 95 | { 96 | auto& pass = propagator.pass; 97 | pass = 0; 98 | 99 | update(blocks, run_first); 100 | apply(blocks); 101 | propagate(blocks, propagator, dt); 102 | stepper(pass, t, dt); 103 | postprop(blocks); 104 | ++pass; 105 | 106 | update(blocks, run_first); 107 | apply(blocks); 108 | propagate(blocks, propagator, dt); 109 | stepper(pass, t, dt); 110 | postprop(blocks); 111 | ++pass; 112 | 113 | update(blocks, run_first); 114 | apply(blocks); 115 | propagate(blocks, propagator, dt); 116 | stepper(pass, t, dt); 117 | postprop(blocks); 118 | } 119 | }; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /include/ascent/integrators_modular/RK4.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/modular/Module.h" 18 | #include "ascent/integrators_modular/ModularIntegrators.h" 19 | 20 | namespace asc 21 | { 22 | namespace modular 23 | { 24 | template 25 | struct RK4prop : public Propagator 26 | { 27 | void operator()(State& state, const value_t dt) override 28 | { 29 | auto& x = *state.x; 30 | auto& xd = *state.xd; 31 | if (state.memory.size() < 5) 32 | { 33 | state.memory.resize(5); 34 | } 35 | auto& x0 = state.memory[0]; 36 | auto& xd0 = state.memory[1]; 37 | auto& xd1 = state.memory[2]; 38 | auto& xd2 = state.memory[3]; 39 | auto& xd3 = state.memory[4]; 40 | 41 | switch (Propagator::pass) 42 | { 43 | case 0: 44 | x0 = x; 45 | xd0 = xd; 46 | x = x0 + 0.5 * dt * xd0; 47 | break; 48 | case 1: 49 | xd1 = xd; 50 | x = x0 + 0.5 * dt * xd1; 51 | break; 52 | case 2: 53 | xd2 = xd; 54 | x = x0 + dt * xd2; 55 | break; 56 | case 3: 57 | xd3 = xd; 58 | x = x0 + dt / 6.0 * (xd0 + 2 * xd1 + 2 * xd2 + xd3); 59 | break; 60 | } 61 | } 62 | }; 63 | 64 | template 65 | struct RK4stepper : public TimeStepper 66 | { 67 | value_t t0{}; 68 | 69 | void operator()(const size_t pass, value_t& t, const value_t dt) override 70 | { 71 | switch (pass) 72 | { 73 | case 0: 74 | t0 = t; 75 | t += 0.5 * dt; 76 | break; 77 | case 2: 78 | t = t0 + dt; 79 | break; 80 | default: 81 | break; 82 | } 83 | } 84 | }; 85 | 86 | template 87 | struct RK4 88 | { 89 | static constexpr size_t n_substeps = 4; 90 | 91 | asc::Module* run_first{}; 92 | 93 | RK4prop propagator; 94 | RK4stepper stepper; 95 | 96 | template 97 | void operator()(modules_t& blocks, value_t& t, const value_t dt) 98 | { 99 | auto& pass = propagator.pass; 100 | pass = 0; 101 | 102 | update(blocks, run_first); 103 | apply(blocks); 104 | propagate(blocks, propagator, dt); 105 | stepper(pass, t, dt); 106 | postprop(blocks); 107 | ++pass; 108 | 109 | update(blocks, run_first); 110 | apply(blocks); 111 | propagate(blocks, propagator, dt); 112 | postprop(blocks); 113 | ++pass; 114 | 115 | update(blocks, run_first); 116 | apply(blocks); 117 | propagate(blocks, propagator, dt); 118 | stepper(pass, t, dt); 119 | postprop(blocks); 120 | ++pass; 121 | 122 | update(blocks, run_first); 123 | apply(blocks); 124 | propagate(blocks, propagator, dt); 125 | postprop(blocks); 126 | } 127 | }; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /include/ascent/integrators_modular/RTAM2.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/modular/Module.h" 18 | #include "ascent/integrators_modular/ModularIntegrators.h" 19 | 20 | // Second order, two pass Real Time (RT) Adams Moulton predictor-corrector integrator 21 | // A new family of real-time predictor-corrector integration algorithms 22 | // R.M. Howe. A new family of real-time predictor-corrector integration algorithms. The University of Michigan. September 1991. 23 | 24 | namespace asc 25 | { 26 | namespace modular 27 | { 28 | template 29 | struct RTAM2prop : public Propagator 30 | { 31 | void operator()(State& state, const value_t dt) override 32 | { 33 | auto& x = *state.x; 34 | auto& xd = *state.xd; 35 | if (state.memory.size() < 2) 36 | { 37 | state.memory.resize(2); 38 | } 39 | auto& x0 = state.memory[0]; 40 | auto& xd1 = state.memory[1]; 41 | 42 | switch (Propagator::pass) 43 | { 44 | case 0: 45 | x0 = x; 46 | x = x0 + dt / 8 * (5 * xd - xd1); 47 | xd1 = xd; 48 | break; 49 | case 1: 50 | x = x0 + dt * xd; // where xd is the evaluated derivative at n + 1/2 (half a step) 51 | break; 52 | } 53 | } 54 | }; 55 | 56 | template 57 | struct RTAM2stepper : public TimeStepper 58 | { 59 | value_t t0{}; 60 | 61 | void operator()(const size_t pass, value_t& t, const value_t dt) override 62 | { 63 | switch (pass) 64 | { 65 | case 0: 66 | t0 = t; 67 | t += 0.5 * dt; 68 | break; 69 | case 1: 70 | t = t0 + dt; 71 | break; 72 | default: 73 | break; 74 | } 75 | } 76 | }; 77 | 78 | template 79 | struct RTAM2 80 | { 81 | static constexpr size_t n_substeps = 2; 82 | 83 | asc::Module* run_first{}; 84 | 85 | RTAM2prop propagator; 86 | RTAM2stepper stepper; 87 | 88 | template 89 | void operator()(modules_t& blocks, value_t& t, const value_t dt) 90 | { 91 | auto& pass = propagator.pass; 92 | pass = 0; 93 | 94 | update(blocks, run_first); 95 | apply(blocks); 96 | propagate(blocks, propagator, dt); 97 | stepper(pass, t, dt); 98 | postprop(blocks); 99 | ++pass; 100 | 101 | update(blocks, run_first); 102 | apply(blocks); 103 | propagate(blocks, propagator, dt); 104 | stepper(pass, t, dt); 105 | postprop(blocks); 106 | } 107 | }; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /include/ascent/integrators_modular/RTAM3.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/modular/Module.h" 18 | #include "ascent/integrators_modular/ModularIntegrators.h" 19 | 20 | // Third order, two pass Real Time (RT) Adams Moulton predictor-corrector integrator 21 | // A new family of real-time predictor-corrector integration algorithms 22 | // R.M. Howe. A new family of real-time predictor-corrector integration algorithms. The University of Michigan. September 1991. 23 | 24 | namespace asc 25 | { 26 | namespace modular 27 | { 28 | template 29 | struct RTAM3prop : public Propagator 30 | { 31 | void operator()(State& state, const value_t dt) override 32 | { 33 | auto& x = *state.x; 34 | auto& xd = *state.xd; 35 | if (state.memory.size() < 4) 36 | { 37 | state.memory.resize(4); 38 | } 39 | auto& x0 = state.memory[0]; 40 | auto& xd0 = state.memory[1]; 41 | auto& xd1 = state.memory[2]; 42 | auto& xd2 = state.memory[3]; 43 | 44 | switch (Propagator::pass) 45 | { 46 | case 0: 47 | x0 = x; 48 | xd0 = xd; 49 | x = x0 + dt / 24 * (17 * xd - 7 * xd1 + 2 * xd2); 50 | break; 51 | case 1: 52 | x = x0 + dt / 18 * (20 * xd - 3 * xd0 + xd1); 53 | xd2 = xd1; 54 | xd1 = xd0; 55 | break; 56 | } 57 | } 58 | }; 59 | 60 | template 61 | struct RTAM3stepper : public TimeStepper 62 | { 63 | value_t t0{}; 64 | 65 | void operator()(const size_t pass, value_t& t, const value_t dt) override 66 | { 67 | switch (pass) 68 | { 69 | case 0: 70 | t0 = t; 71 | t += 0.5 * dt; 72 | break; 73 | case 1: 74 | t = t0 + dt; 75 | break; 76 | default: 77 | break; 78 | } 79 | } 80 | }; 81 | 82 | template 83 | struct RTAM3 84 | { 85 | static constexpr size_t n_substeps = 2; 86 | 87 | asc::Module* run_first{}; 88 | 89 | RTAM3prop propagator; 90 | RTAM3stepper stepper; 91 | 92 | template 93 | void operator()(modules_t& blocks, value_t& t, const value_t dt) 94 | { 95 | auto& pass = propagator.pass; 96 | pass = 0; 97 | 98 | update(blocks, run_first); 99 | apply(blocks); 100 | propagate(blocks, propagator, dt); 101 | stepper(pass, t, dt); 102 | postprop(blocks); 103 | ++pass; 104 | 105 | update(blocks, run_first); 106 | apply(blocks); 107 | propagate(blocks, propagator, dt); 108 | stepper(pass, t, dt); 109 | postprop(blocks); 110 | } 111 | }; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /include/ascent/integrators_modular/RTAM4.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/modular/Module.h" 18 | #include "ascent/integrators_modular/ModularIntegrators.h" 19 | 20 | // Fourth order, two pass Real Time (RT) Adams Moulton predictor-corrector integrator 21 | // A new family of real-time predictor-corrector integration algorithms 22 | // R.M. Howe. A new family of real-time predictor-corrector integration algorithms. The University of Michigan. September 1991. 23 | 24 | namespace asc 25 | { 26 | namespace modular 27 | { 28 | template 29 | struct RTAM4prop : public Propagator 30 | { 31 | void operator()(State& state, const value_t dt) override 32 | { 33 | auto& x = *state.x; 34 | auto& xd = *state.xd; 35 | if (state.memory.size() < 5) 36 | { 37 | state.memory.resize(5); 38 | } 39 | auto& x0 = state.memory[0]; 40 | auto& xd0 = state.memory[1]; 41 | auto& xd1 = state.memory[2]; 42 | auto& xd2 = state.memory[3]; 43 | auto& xd3 = state.memory[4]; 44 | 45 | switch (Propagator::pass) 46 | { 47 | case 0: 48 | x0 = x; 49 | xd0 = xd; 50 | x = x0 + dt / 384 * (297 * xd - 187 * xd1 + 107 * xd2 - 25 * xd3); 51 | break; 52 | case 1: 53 | x = x0 + dt / 30 * (36 * xd - 10 * xd0 + 5 * xd1 - xd2); 54 | xd3 = xd2; 55 | xd2 = xd1; 56 | xd1 = xd0; 57 | break; 58 | } 59 | } 60 | }; 61 | 62 | template 63 | struct RTAM4stepper : public TimeStepper 64 | { 65 | value_t t0{}; 66 | 67 | void operator()(const size_t pass, value_t& t, const value_t dt) override 68 | { 69 | switch (pass) 70 | { 71 | case 0: 72 | t0 = t; 73 | t += 0.5 * dt; 74 | break; 75 | case 1: 76 | t = t0 + dt; 77 | break; 78 | default: 79 | break; 80 | } 81 | } 82 | }; 83 | 84 | template 85 | struct RTAM4 86 | { 87 | static constexpr size_t n_substeps = 2; 88 | 89 | asc::Module* run_first{}; 90 | 91 | RTAM4prop propagator; 92 | RTAM4stepper stepper; 93 | 94 | template 95 | void operator()(modules_t& blocks, value_t& t, const value_t dt) 96 | { 97 | auto& pass = propagator.pass; 98 | pass = 0; 99 | 100 | update(blocks, run_first); 101 | apply(blocks); 102 | propagate(blocks, propagator, dt); 103 | stepper(pass, t, dt); 104 | postprop(blocks); 105 | ++pass; 106 | 107 | update(blocks, run_first); 108 | apply(blocks); 109 | propagate(blocks, propagator, dt); 110 | stepper(pass, t, dt); 111 | postprop(blocks); 112 | } 113 | }; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /include/ascent/integrators_modular/Ralston4.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2020 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/modular/Module.h" 18 | #include "ascent/integrators_modular/ModularIntegrators.h" 19 | 20 | // Ralston's fourth-order method. 21 | 22 | namespace asc 23 | { 24 | namespace modular 25 | { 26 | template 27 | struct Ralston4prop : public Propagator 28 | { 29 | void operator()(State& state, const value_t dt) override 30 | { 31 | auto& x = *state.x; 32 | auto& xd = *state.xd; 33 | state.memory.resize(5); 34 | auto& x0 = state.memory[0]; 35 | auto& xd0 = state.memory[1]; 36 | auto& xd1 = state.memory[2]; 37 | auto& xd2 = state.memory[3]; 38 | auto& xd3 = state.memory[4]; 39 | 40 | switch (Propagator::pass) 41 | { 42 | case 0: 43 | x0 = x; 44 | xd0 = xd; // k1 45 | x = x0 + dt * (0.4 * xd0); 46 | break; 47 | case 1: 48 | xd1 = xd; // k2 49 | x = x0 + dt * (0.29697761 * xd0 + 0.15875964 * xd1); 50 | break; 51 | case 2: 52 | xd2 = xd; // k3 53 | x = x0 + dt * (0.21810040 * xd0 - 3.05096516 * xd1 + 3.83286476 * xd2); 54 | break; 55 | case 3: 56 | xd3 = xd; // k4 57 | x = x0 + dt * (0.17476028 * xd0 - 0.55148066 * xd1 + 1.20553560 * xd2 + 0.17118478 * xd3); 58 | break; 59 | } 60 | } 61 | }; 62 | 63 | template 64 | struct Ralston4stepper : public TimeStepper 65 | { 66 | value_t t0{}; 67 | 68 | void operator()(const size_t pass, value_t& t, const value_t dt) override 69 | { 70 | switch (pass) 71 | { 72 | case 0: 73 | t0 = t; 74 | t = t0 + 0.4 * dt; 75 | break; 76 | case 1: 77 | t = t0 + 0.45573725 * dt; 78 | break; 79 | case 2: 80 | t = t0 + dt; 81 | break; 82 | default: 83 | break; 84 | } 85 | } 86 | }; 87 | 88 | template 89 | struct Ralston4 90 | { 91 | static constexpr size_t n_substeps = 4; 92 | 93 | asc::Module* run_first{}; 94 | 95 | Ralston4prop propagator; 96 | Ralston4stepper stepper; 97 | 98 | template 99 | void operator()(modules_t& blocks, value_t& t, const value_t dt) 100 | { 101 | auto& pass = propagator.pass; 102 | pass = 0; 103 | 104 | update(blocks, run_first); 105 | apply(blocks); 106 | propagate(blocks, propagator, dt); 107 | stepper(pass, t, dt); 108 | postprop(blocks); 109 | ++pass; 110 | 111 | update(blocks, run_first); 112 | apply(blocks); 113 | propagate(blocks, propagator, dt); 114 | postprop(blocks); 115 | ++pass; 116 | 117 | update(blocks, run_first); 118 | apply(blocks); 119 | propagate(blocks, propagator, dt); 120 | stepper(pass, t, dt); 121 | postprop(blocks); 122 | ++pass; 123 | 124 | update(blocks, run_first); 125 | apply(blocks); 126 | propagate(blocks, propagator, dt); 127 | postprop(blocks); 128 | } 129 | }; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /include/ascent/modular/Link.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/modular/Module.h" 18 | 19 | #include 20 | 21 | namespace asc 22 | { 23 | template 24 | struct Link 25 | { 26 | std::remove_cv_t>* module_{}; // Non-const qualified module for doing low level, potentially dangerous simulation stuff. 27 | // The pointer will be returned with T qualifiers, so that the module can be const qualified. 28 | 29 | Link& operator=(const T* ptr) noexcept 30 | { 31 | module_ = ptr; 32 | return *this; 33 | } 34 | 35 | T& operator*() 36 | { 37 | check(); 38 | return *module_; 39 | } 40 | 41 | T* operator->() 42 | { 43 | check(); 44 | return module_; 45 | } 46 | 47 | explicit operator bool() const noexcept { return (module_ != 0); } 48 | 49 | std::string to_string() const { return "Link<" + static_cast(typeid(T).name()) + '>'; } 50 | 51 | private: 52 | void check_init() 53 | { 54 | if (!module_->init_run) 55 | { 56 | if (module_->init_called) 57 | { 58 | throw std::runtime_error("Circular dependency for init(): " + to_string()); 59 | } 60 | else 61 | { 62 | module_->init_called = true; 63 | module_->init(); 64 | } 65 | module_->init_run = true; 66 | } 67 | } 68 | 69 | void check() 70 | { 71 | if (module_) 72 | { 73 | assert(module_->phase); 74 | // The Link phase and Postprop phase do not check initialization. 75 | // Linking may occur prior to initialization and is not ordered. 76 | // Postprop is not sequenced, as calculations may only be performed on propagated states 77 | switch (*module_->phase) 78 | { 79 | case Phase::Init: 80 | check_init(); 81 | return; 82 | case Phase::Update: 83 | check_init(); 84 | if (!module_->update_run) 85 | { 86 | if (module_->update_called) 87 | { 88 | throw std::runtime_error("Circular dependency for update operator(): " + to_string()); 89 | } 90 | else 91 | { 92 | module_->update_called = true; 93 | module_->operator()(); 94 | } 95 | module_->update_run = true; 96 | } 97 | return; 98 | case Phase::Postcalc: 99 | check_init(); 100 | return; 101 | case default: 102 | return; 103 | } 104 | } 105 | else 106 | { 107 | throw std::runtime_error(("nullptr access ->: " + to_string()).c_str()); 108 | } 109 | } 110 | }; 111 | 112 | template bool operator==(const Link& link, std::nullptr_t ptr) noexcept { return link.module_ == ptr; } 113 | template bool operator==(std::nullptr_t ptr, const Link& link) noexcept { return link.module_ == ptr; } 114 | 115 | template bool operator!=(const Link& link, std::nullptr_t ptr) noexcept { return link.module_ != ptr; } 116 | template bool operator!=(std::nullptr_t ptr, const Link& link) noexcept { return link.module_ != ptr; } 117 | } -------------------------------------------------------------------------------- /include/ascent/modular/Module.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include "ascent/direct/State.h" 18 | 19 | namespace asc 20 | { 21 | template 22 | struct is_pair : std::false_type { }; 23 | 24 | template 25 | struct is_pair> : std::true_type { }; 26 | 27 | template 28 | constexpr bool is_pair_v = is_pair::value; 29 | 30 | template 31 | struct Propagator 32 | { 33 | Propagator() = default; 34 | Propagator(const Propagator&) = default; 35 | Propagator(Propagator&&) = default; 36 | Propagator& operator=(const Propagator&) = default; 37 | Propagator& operator=(Propagator&&) = default; 38 | virtual ~Propagator() {} 39 | 40 | virtual void operator()(State&, const double) = 0; // inputs: state, dt (time step) 41 | 42 | size_t pass{}; 43 | }; 44 | 45 | enum struct Phase 46 | { 47 | Link, 48 | Init, 49 | Update, 50 | Postprop, 51 | Postcalc 52 | }; 53 | 54 | struct Module 55 | { 56 | Module() = default; 57 | Module(const Module&) = default; 58 | Module(Module&&) = default; 59 | Module& operator=(const Module&) = default; 60 | Module& operator=(Module&&) = default; 61 | virtual ~Module() = default; 62 | 63 | std::vector states; 64 | 65 | template 66 | void make_state(x_t& x, xd_t& xd) 67 | { 68 | states.emplace_back(x, xd); 69 | } 70 | 71 | template 72 | void make_states(x_t& x, xd_t& xd) 73 | { 74 | const size_t n = x.size(); 75 | for (size_t i = 0; i < n; ++i) 76 | { 77 | states.emplace_back(x[i], xd[i]); 78 | } 79 | } 80 | 81 | template 82 | void make_states(data_t* x, data_t* xd, const size_t n) 83 | { 84 | for (size_t i = 0; i < n; ++i) { 85 | states.emplace_back(x[i], xd[i]); 86 | } 87 | } 88 | 89 | template 90 | void add_states(states_t& ext_states) 91 | { 92 | for (auto& state : states) { 93 | ext_states.emplace_back(state); 94 | } 95 | } 96 | 97 | virtual void link() {} // linking modules 98 | virtual void init() {} // initialization 99 | virtual void operator()() {} // derivative accumulation 100 | virtual void apply() {} // apply accumulations 101 | virtual void propagate(Propagator& propagator, const double dt) 102 | { 103 | for (auto& state : states) { 104 | propagator(state, dt); 105 | } 106 | } 107 | virtual void postprop() {} // post propagation calculations (every substep) 108 | virtual void postcalc() {} // post integration calculations (every full step) 109 | 110 | bool init_called = false; 111 | }; 112 | 113 | template 114 | inline void init(modules_t& blocks) 115 | { 116 | for (auto& block : blocks) 117 | { 118 | if (!block->init_called) 119 | { 120 | block->init(); 121 | block->init_called = true; 122 | } 123 | } 124 | } 125 | 126 | template 127 | void call_loop(modules_t& blocks) 128 | { 129 | if constexpr (is_pair_v::value_type>) 130 | { 131 | for (auto& block : blocks) { 132 | (block.second->*func)(); 133 | } 134 | } 135 | else 136 | { 137 | for (auto& block : blocks) { 138 | (block->*func)(); 139 | } 140 | } 141 | } 142 | 143 | template 144 | void update(modules_t& blocks) 145 | { 146 | call_loop<&Module::operator()>(blocks); 147 | } 148 | 149 | template 150 | void update(modules_t& blocks, asc::Module* run_first) 151 | { 152 | if (run_first) { 153 | (*run_first)(); 154 | } 155 | update(blocks); 156 | } 157 | 158 | template 159 | void apply(modules_t& blocks) 160 | { 161 | call_loop<&Module::apply>(blocks); 162 | } 163 | 164 | template 165 | void propagate(modules_t& blocks, propagator_t& propagator, const value_t dt) 166 | { 167 | if constexpr (is_pair_v::value_type>) 168 | { 169 | for (auto& block : blocks) { 170 | for (auto &state : block.second->states) { 171 | if (propagator.pass == 0 && state.hist_len > 0) { 172 | state.x0_hist.push_back(*state.x); 173 | if (state.x0_hist.size() > state.hist_len) state.x0_hist.pop_front(); 174 | 175 | state.xd0_hist.push_back(*state.xd); 176 | if (state.xd0_hist.size() > state.hist_len) state.x0_hist.pop_front(); 177 | } 178 | } 179 | block.second->propagate(propagator, dt); 180 | } 181 | } 182 | else 183 | { 184 | for (auto& block : blocks) { 185 | for (auto &state : block->states) { 186 | if (propagator.pass == 0 && state.hist_len > 0) { 187 | state.x0_hist.push_back(*state.x); 188 | if (state.x0_hist.size() > state.hist_len) state.x0_hist.pop_front(); 189 | 190 | state.xd0_hist.push_back(*state.xd); 191 | if (state.xd0_hist.size() > state.hist_len) state.x0_hist.pop_front(); 192 | } 193 | } 194 | block->propagate(propagator, dt); 195 | } 196 | } 197 | } 198 | 199 | template 200 | void postprop(modules_t& blocks) 201 | { 202 | call_loop<&Module::postprop>(blocks); 203 | } 204 | 205 | template 206 | inline void postcalc(modules_t& blocks) 207 | { 208 | call_loop<&Module::postcalc>(blocks); 209 | } 210 | 211 | template 212 | inline void add_states(states_t& states, std::vector& blocks) 213 | { 214 | for (auto& block : blocks) 215 | { 216 | auto& m_states = block->states; 217 | for (auto& state : m_states) { 218 | states.emplace_back(state); 219 | } 220 | } 221 | } 222 | 223 | template 224 | inline void add_states(states_t& states, ptr_t& block) 225 | { 226 | for (auto& state : block->states) { 227 | states.emplace_back(state); 228 | } 229 | } 230 | } -------------------------------------------------------------------------------- /include/ascent/threading/Pool.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2018 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #pragma once 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #ifdef _WIN32 26 | #ifdef NOMINMAX 27 | #include 28 | #else 29 | #define NOMINMAX 30 | #include 31 | #undef NOMINMAX 32 | #endif 33 | #endif 34 | 35 | namespace asc { 36 | // A simple threadpool 37 | class Pool 38 | { 39 | public: 40 | 41 | Pool() : Pool(concurrency()) {} 42 | 43 | Pool(const unsigned int n) 44 | { 45 | n_threads(n); 46 | } 47 | 48 | void n_threads(const unsigned int n) 49 | { 50 | #ifdef _WIN32 51 | // TODO smarter distrubution of threads among groups. 52 | auto num_groups = GetActiveProcessorGroupCount(); 53 | int group = 0; 54 | for (size_t i = threads.size(); i < n; ++i) { 55 | auto thread = std::thread(&Pool::worker, this); 56 | auto hndl = thread.native_handle(); 57 | GROUP_AFFINITY affinity; 58 | if (GetThreadGroupAffinity(hndl, &affinity) && affinity.Group != group) { 59 | affinity.Group = group; 60 | SetThreadGroupAffinity(hndl, &affinity, nullptr); 61 | } 62 | group++; 63 | if (group >= num_groups) group = 0; 64 | threads.emplace_back(std::move(thread)); 65 | } 66 | #else 67 | for (size_t i = threads.size(); i < n; ++i) { 68 | threads.emplace_back(std::thread(&Pool::worker, this)); 69 | } 70 | #endif 71 | } 72 | 73 | unsigned int concurrency() 74 | { 75 | #ifdef _WIN32 76 | auto num_groups = GetActiveProcessorGroupCount(); 77 | unsigned int sum = 0; 78 | for (WORD i = 0; i < num_groups; ++i) { 79 | sum += GetMaximumProcessorCount(i); 80 | } 81 | return sum; 82 | #else 83 | return std::thread::hardware_concurrency(); 84 | #endif 85 | } 86 | 87 | template 88 | std::future>> emplace_back(F &&func) 89 | { 90 | using result_type = decltype(func()); 91 | 92 | std::lock_guard lock(m); 93 | 94 | auto promise = std::make_shared>(); 95 | 96 | queue.emplace_back([=]() { 97 | try 98 | { 99 | if constexpr (std::is_void::value) { 100 | func(); 101 | } 102 | else { 103 | promise->set_value(func()); 104 | } 105 | } 106 | catch (...) 107 | { 108 | promise->set_exception(std::current_exception()); 109 | } 110 | }); 111 | 112 | work_cv.notify_one(); 113 | 114 | return promise->get_future(); 115 | } 116 | 117 | bool computing() const 118 | { 119 | return (working != 0); 120 | } 121 | 122 | void wait() { 123 | std::unique_lock lock(m); 124 | if (queue.empty() && (working == 0)) 125 | return; 126 | done_cv.wait(lock, [&]() { return queue.empty() && (working == 0); }); 127 | } 128 | 129 | size_t size() const 130 | { 131 | return threads.size(); 132 | } 133 | 134 | ~Pool() 135 | { 136 | //Close the queue and finish all the remaining work 137 | std::unique_lock lock(m); 138 | closed = true; 139 | work_cv.notify_all(); 140 | lock.unlock(); 141 | 142 | for (auto &t : threads) 143 | if (t.joinable()) 144 | t.join(); 145 | } 146 | 147 | template 148 | static void script(ChaiScript &c, const std::string &name) 149 | { 150 | using namespace chaiscript; 151 | using T = Pool; 152 | c.add(constructor(), name); 153 | c.add(fun(&T::computing), "computing"); 154 | c.add(fun(&T::n_threads), "n_threads"); 155 | c.add(fun(&T::wait), "wait"); 156 | // c.add(fun(&T::emplace_back), "emplace_back"); 157 | c.add(fun(&T::size), "size"); 158 | } 159 | 160 | private: 161 | std::vector< std::thread > threads; 162 | std::deque< std::function > queue; 163 | std::atomic working = 0; 164 | bool closed = false; 165 | std::mutex m; 166 | std::condition_variable work_cv; 167 | std::condition_variable done_cv; 168 | 169 | void worker() 170 | { 171 | while (true) 172 | { 173 | //Wait for work 174 | std::unique_lock lock(m); 175 | work_cv.wait(lock, [this]() { return closed || !queue.empty(); }); 176 | if (queue.empty()) { 177 | if (closed) { 178 | return; 179 | } 180 | continue; 181 | } 182 | 183 | //Grab work 184 | ++working; 185 | auto work = queue.front(); 186 | queue.pop_front(); 187 | lock.unlock(); 188 | 189 | work(); 190 | 191 | //Notify that work is finished 192 | lock.lock(); 193 | --working; 194 | done_cv.notify_all(); 195 | } 196 | } 197 | }; 198 | } 199 | -------------------------------------------------------------------------------- /include/ascent/timing/Sampler.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include 18 | 19 | namespace asc 20 | { 21 | struct def_eps { 22 | static constexpr double eps = 1e-8; 23 | }; 24 | // A Sampler resets the base time step when it goes out of scope. In this manner it can be used as a short-lived object within the simulation loop. 25 | // If the Sampler is to exist long term, then the reset() must be called after time is incremented within the simulation loop. 26 | // Note that keeping the Sampler around longer maintains a consistent base time step. 27 | template 28 | struct SamplerT 29 | { 30 | SamplerT(T& _t, T& _dt) noexcept : t(_t), dt(_dt), dt_base(dt) {} 31 | SamplerT(const SamplerT& other) : t(other.t), dt(other.dt), dt_base(other.dt_base) {} 32 | SamplerT(SamplerT&&) = default; 33 | SamplerT& operator=(const SamplerT& other) 34 | { 35 | t = other.t; 36 | dt = other.dt; 37 | dt_base = other.dt_base; 38 | return *this; 39 | } 40 | SamplerT& operator=(SamplerT&&) = default; 41 | ~SamplerT() noexcept { dt = dt_base; } 42 | 43 | bool operator()(const T sample_rate) const noexcept 44 | { 45 | const size_t n = static_cast((t + eps) / sample_rate); // the number of sample time steps that have occured 46 | const T sample_time = (n + 1) * sample_rate; // the next sample time 47 | if (sample_time < t + dt - eps) 48 | dt = sample_time - t; 49 | 50 | if (t - sample_time + sample_rate < eps) 51 | return true; 52 | 53 | return false; 54 | } 55 | 56 | bool event(const T event_time) noexcept 57 | { 58 | if (event_time < t + dt - eps && event_time >= t + eps) 59 | dt = event_time - t; 60 | 61 | if (std::abs(event_time - t) < eps) 62 | return true; 63 | 64 | return false; 65 | } 66 | 67 | void reset() noexcept 68 | { 69 | dt = dt_base; 70 | } 71 | 72 | T base_time_step() const noexcept 73 | { 74 | return dt_base; 75 | } 76 | 77 | void base_time_step(const double dt_new) noexcept 78 | { 79 | dt = dt_base = dt_new; 80 | } 81 | 82 | private: 83 | static constexpr T eps = static_cast(Eps::eps); 84 | T& t; 85 | T& dt; 86 | T dt_base; 87 | }; 88 | } 89 | -------------------------------------------------------------------------------- /include/ascent/timing/TimeAdvanced.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | namespace asc 18 | { 19 | // TimeAdvanced must be called at the end of the update sequence, otherwise there will be no difference between the current time and the previous time 20 | template 21 | struct TimeAdvancedT 22 | { 23 | value_t t_previous{}; 24 | value_t eps = static_cast(1.0e-8); 25 | 26 | bool operator()(const value_t t) const noexcept 27 | { 28 | if (t > t_previous + eps) 29 | return true; 30 | return false; 31 | } 32 | 33 | double delta_t(const value_t t) const noexcept 34 | { 35 | return t - t_previous; 36 | } 37 | 38 | void update(const value_t t) noexcept 39 | { 40 | if (operator()(t)) 41 | t_previous = t; 42 | } 43 | 44 | template 45 | void operator()(state_t&, state_t&, const value_t t) noexcept 46 | { 47 | if (operator()(t)) 48 | t_previous = t; 49 | } 50 | }; 51 | } -------------------------------------------------------------------------------- /include/ascent/timing/Timing.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #pragma once 16 | 17 | #include 18 | #include "ascent/timing/Sampler.h" 19 | #include "ascent/modular/Module.h" 20 | 21 | namespace asc 22 | { 23 | template 24 | struct Timing : Module 25 | { 26 | value_t t{}; 27 | value_t dt{ 0.01 }; 28 | value_t t_end = std::numeric_limits::max(); 29 | value_t t_delta{}; 30 | 31 | value_t t_previous{}; 32 | value_t eps = static_cast(1.0e-8); 33 | bool time_advanced = false; 34 | 35 | SamplerT sampler{ t, dt }; 36 | 37 | bool sample(const value_t sample_rate) const noexcept 38 | { 39 | return sampler(sample_rate); 40 | } 41 | 42 | bool event(const value_t event_time) noexcept 43 | { 44 | return sampler.event(event_time); 45 | } 46 | 47 | void base_time_step(const value_t base_dt) 48 | { 49 | sampler.base_time_step(base_dt); 50 | } 51 | 52 | value_t base_time_step() const noexcept 53 | { 54 | return sampler.base_time_step(); 55 | } 56 | 57 | value_t delta_t() const noexcept 58 | { 59 | return t_delta; 60 | } 61 | 62 | void reset() noexcept 63 | { 64 | sampler.reset(); 65 | } 66 | 67 | void init() override 68 | { 69 | t_previous = t; 70 | } 71 | 72 | void operator()() override 73 | { 74 | if (t > t_previous + eps) 75 | { 76 | time_advanced = true; 77 | } 78 | else 79 | { 80 | time_advanced = false; 81 | } 82 | t_delta = t - t_previous; 83 | t_previous = t; 84 | } 85 | }; 86 | } -------------------------------------------------------------------------------- /unit_tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(FetchContent) 2 | 3 | set(BOOST_UT_ENABLE_RUN_AFTER_BUILD OFF CACHE INTERNAL "") 4 | set(BOOST_UT_DISABLE_MODULE ON CACHE INTERNAL "") 5 | 6 | FetchContent_Declare( 7 | ut 8 | GIT_REPOSITORY https://github.com/boost-ext/ut.git 9 | GIT_TAG tags/v1.1.9 10 | GIT_SHALLOW TRUE 11 | FIND_PACKAGE_ARGS 12 | ) 13 | 14 | FetchContent_MakeAvailable(ut) 15 | 16 | add_executable(${PROJECT_NAME}_test src/main.cpp) 17 | target_link_libraries(${PROJECT_NAME}_test PRIVATE Boost::ut ascent) 18 | add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test) -------------------------------------------------------------------------------- /unit_tests/src/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2020 Anyar, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "ascent/Ascent.h" 16 | 17 | #include "ascent/integrators_modular/RK2.h" 18 | #include "ascent/integrators_modular/RK4.h" 19 | #include "ascent/integrators_modular/PC233.h" 20 | #include "ascent/integrators_modular/ABM4.h" 21 | #include "ascent/integrators_modular/VABM.h" 22 | #include "ascent/timing/Timing.h" 23 | 24 | #include 25 | 26 | using namespace asc; 27 | 28 | struct Airy 29 | { 30 | void operator()(const state_t& x, state_t& xd, const double t) 31 | { 32 | xd[0] = x[1]; 33 | xd[1] = -t*x[0]; 34 | } 35 | }; 36 | 37 | struct AiryMod : asc::Module 38 | { 39 | double a{}; 40 | double a_d{}; 41 | double b{}; 42 | double b_d{}; 43 | std::shared_ptr> sim{}; 44 | 45 | void init() 46 | { 47 | make_state(a, a_d); 48 | make_state(b, b_d); 49 | } 50 | 51 | void operator()() 52 | { 53 | a_d = b; 54 | b_d = -sim->t*a; 55 | } 56 | }; 57 | 58 | struct Exponential 59 | { 60 | void operator()(const state_t& x, state_t& xd, const double) 61 | { 62 | xd[0] = x[0]; 63 | } 64 | }; 65 | struct ExponentialMod : asc::Module 66 | { 67 | double value{}; 68 | double deriv{}; 69 | 70 | void init() 71 | { 72 | make_state(value, deriv); 73 | } 74 | void operator()() 75 | { 76 | deriv = value; 77 | } 78 | }; 79 | 80 | template 81 | state_t airy_test(const double dt) 82 | { 83 | state_t x = { 1.0, 0.0 }; 84 | double t = 0.0; 85 | double t_end = 10.0; 86 | 87 | Integrator integrator; 88 | Airy system; 89 | 90 | while (t < t_end) 91 | { 92 | integrator(system, x, t, dt); 93 | } 94 | 95 | return x; 96 | } 97 | 98 | template 99 | std::vector airy_test_mod(const double dt) 100 | { 101 | Integrator integrator; 102 | auto system = std::make_shared(); 103 | system->sim = std::make_shared>(); 104 | system->a = 1.0; 105 | system->b = 0.0; 106 | system->sim->t = 0.0; 107 | system->sim->t_end = 10.0; 108 | std::vector blocks{}; 109 | blocks.emplace_back(system.get()); 110 | 111 | system->init(); 112 | 113 | while (system->sim->t < system->sim->t_end) 114 | { 115 | integrator(blocks, system->sim->t, dt); 116 | } 117 | 118 | return{ system->a, system->b }; 119 | } 120 | 121 | 122 | template 123 | std::pair exponential_test(const double dt) 124 | { 125 | state_t x = { 1.0 }; 126 | double t = 0.0; 127 | double t_end = 10.0; 128 | 129 | Integrator integrator; 130 | Exponential system; 131 | 132 | while (t < t_end) 133 | { 134 | integrator(system, x, t, dt); 135 | } 136 | 137 | return{ x, t }; 138 | } 139 | 140 | template 141 | std::pair exponential_test_mod(const double dt) 142 | { 143 | Integrator integrator; 144 | auto system = std::make_shared(); 145 | auto sim = std::make_shared>(); 146 | system->value = 1.0; 147 | sim->t = 0.0; 148 | sim->t_end = 10.0; 149 | std::vector blocks{}; 150 | blocks.emplace_back(system.get()); 151 | 152 | system->init(); 153 | 154 | while (sim->t < sim->t_end) 155 | { 156 | integrator(blocks, sim->t, dt); 157 | } 158 | 159 | return{ system->value, sim->t }; 160 | } 161 | 162 | template 163 | std::pair exponential_test_mod_adaptive() 164 | { 165 | Integrator integrator; 166 | auto system = std::make_shared(); 167 | auto sim = std::make_shared>(); 168 | auto settings = AdaptiveT(); 169 | system->value = 1.0; 170 | sim->t = 0.0; 171 | sim->t_end = 10.0; 172 | double dt = 0.001; 173 | settings.abs_tol = 1e-16; 174 | settings.rel_tol = 1e-16; 175 | std::vector blocks{}; 176 | blocks.emplace_back(system.get()); 177 | 178 | system->init(); 179 | 180 | while (sim->t < sim->t_end) 181 | { 182 | integrator(blocks, sim->t, dt, settings); 183 | } 184 | 185 | return{ system->value, sim->t }; 186 | } 187 | 188 | #include 189 | 190 | using namespace boost::ut; 191 | 192 | inline bool approx(const auto& x, const auto near, const double epsilon = 1.0e-8) { 193 | return (x <= (near + epsilon)) && (x >= (near - epsilon)); 194 | } 195 | 196 | suite airy_system = [] 197 | { 198 | "airy_rk4"_test = [] { 199 | auto x = airy_test(0.001); 200 | boost::ut:: 201 | expect(approx(x[0], -0.200693641142)) << x[0]; 202 | expect(approx(x[1], -1.49817601143)) << x[1]; 203 | }; 204 | 205 | "airy_rk2"_test = [] { 206 | auto x = airy_test(0.001); 207 | expect(approx(x[0], -0.200703911717)) << x[0]; 208 | expect(approx(x[1], -1.49816435475)) << x[1]; 209 | }; 210 | 211 | "airy_dopri45"_test = [] { 212 | auto x = airy_test(0.001); 213 | expect(approx(x[0], -0.200693641142)) << x[0]; 214 | expect(approx(x[1], -1.49817601143)) << x[1]; 215 | }; 216 | }; 217 | 218 | suite airy_modular = [] 219 | { 220 | "airy_modular_rk4"_test = [] { 221 | auto x = airy_test_mod>(0.001); 222 | expect(approx(x[0], -0.200693641142)) << x[0]; 223 | expect(approx(x[1], -1.49817601143)) << x[1]; 224 | }; 225 | 226 | "airy_modular_rk2"_test = [] { 227 | auto x = airy_test_mod>(0.001); 228 | expect(approx(x[0], -0.200703911717)) << x[0]; 229 | expect(approx(x[1], -1.49816435475)) << x[1]; 230 | }; 231 | 232 | "airy_modular_pc233"_test = [] { 233 | auto x = airy_test_mod>(0.001); 234 | expect(approx(x[0], -0.200693641142)) << x[0]; 235 | expect(approx(x[1], -1.49817601143)) << x[1]; 236 | }; 237 | }; 238 | 239 | suite exponential = [] 240 | { 241 | "exp_rk4"_test = [] { 242 | auto result = exponential_test(0.001); 243 | expect(approx(result.first[0], std::exp(result.second))); 244 | }; 245 | 246 | "exp_rk2"_test = [] { 247 | auto result = exponential_test(0.001); 248 | expect(approx(result.first[0], std::exp(result.second), 1.0e-1)); 249 | }; 250 | 251 | "exp_dopri45"_test = [] { 252 | auto result = exponential_test(0.001); 253 | expect(approx(result.first[0], std::exp(result.second))); 254 | }; 255 | 256 | "exp_pc233"_test = [] { 257 | auto result = exponential_test(0.001); 258 | expect(approx(result.first[0], std::exp(result.second), 1.0e-2)); 259 | }; 260 | 261 | "exp_abm4"_test = [] { 262 | auto result = exponential_test(0.001); 263 | expect(approx(result.first[0], std::exp(result.second))); 264 | }; 265 | }; 266 | 267 | suite exp_modular = [] 268 | { 269 | "exp_modular_rk4"_test = [] { 270 | auto result = exponential_test_mod>(0.001); 271 | expect(approx(result.first, std::exp(result.second))); 272 | }; 273 | 274 | "exp_modular_rk2"_test = [] { 275 | auto result = exponential_test_mod>(0.001); 276 | expect(approx(result.first, std::exp(result.second), 1.0e-1)); 277 | }; 278 | 279 | "exp_modular_pc233"_test = [] { 280 | auto result = exponential_test_mod>(0.001); 281 | expect(approx(result.first, std::exp(result.second), 1.0e-2)); 282 | }; 283 | 284 | "exp_modular_abm4"_test = [] { 285 | auto result = exponential_test_mod>(0.001); 286 | expect(approx(result.first, std::exp(result.second))); 287 | }; 288 | 289 | "exp_modular_vabm"_test = [] { 290 | auto result = exponential_test_mod>(0.001); 291 | expect(approx(result.first, std::exp(result.second))); 292 | }; 293 | 294 | "exp_modular_adaptive_vabm"_test = [] { 295 | auto result = exponential_test_mod_adaptive>(); 296 | expect(approx(result.first, std::exp(result.second))); 297 | }; 298 | }; 299 | 300 | int main() {} 301 | --------------------------------------------------------------------------------