├── .gitignore ├── utilities ├── Finch │ ├── scan_path_small.txt │ ├── inputs_small.json │ └── inputs_small_refined.json ├── TASMANIAN │ └── TasmanianTest.py └── MTEX │ ├── ColorMap4.m │ ├── ColorMap8.m │ ├── PlotPoleFigure.m │ └── PlotIPFColoredSection.m ├── analysis ├── CMakeLists.txt ├── bin │ ├── CMakeLists.txt │ └── runGA.cpp ├── unit_test │ ├── CMakeLists.txt │ ├── tstKokkosUtils.hpp │ └── tstUtils.hpp ├── examples │ ├── AnalyzeAMB.json │ ├── AnalyzeSmallDirS.json │ └── AnalyzeDirS.json ├── src │ ├── CMakeLists.txt │ ├── GAutils.cpp │ └── GAutils.hpp └── README.md ├── examples ├── Materials │ ├── SS316.json │ ├── SS316L_Austenite.json │ ├── Inconel625_Quadratic.json │ ├── Inconel625.json │ └── SS316L_AusteniteFerrite.json ├── Inp_EquiaxedGrain.json ├── Inp_SmallEquiaxedGrain.json ├── Inp_SmallFinch.json ├── Inp_Finch.json ├── Inp_SmallSpotMelt_Steel1phase.json ├── Inp_SmallSpotMelt_Steel2phase.json ├── Inp_SmallDirSolidification.json ├── Inp_SingleLine.json ├── Inp_FinchTranslate.json ├── Inp_DirSolidification.json ├── Inp_SmallSpotMelt.json ├── Inp_SpotMelt.json ├── Inp_TwoLineTwoLayer.json ├── Inp_TwoGrainDirSolidification.json └── Inp_SingleLineTranslate.json ├── unit_test ├── TestCUDA_Category.hpp ├── TestOPENMP_Category.hpp ├── TestSERIAL_Category.hpp ├── TestPTHREAD_Category.hpp ├── TestTHREADS_Category.hpp ├── TestHIP_Category.hpp ├── unit_test_main.cpp ├── CMakeLists.txt ├── test_harness.cmake ├── tstParse.hpp ├── tstPrint.hpp ├── tstUpdate.hpp ├── tstOrientation.hpp ├── tstInterfacialResponse.hpp └── tstGrid.hpp ├── bin ├── CMakeLists.txt ├── run.cpp └── runCoupled.cpp ├── .github └── workflows │ ├── format.yml │ ├── Nightly.yml │ └── CI.yml ├── CONTRIBUTING.md ├── src ├── CAinfo.hpp ├── CAinfo.cpp ├── CAconfig.hpp.cmakein ├── CAtypes.hpp ├── ExaCA.hpp ├── CMakeLists.txt ├── CAparsefiles.hpp ├── CAinterfacialresponse.hpp ├── CAtimers.hpp ├── CAparsefiles.cpp ├── CAinputdata.hpp └── runCA.hpp ├── .pre-commit-config.yaml ├── cmake ├── ExaCAconfig.cmakein └── FindCLANG_FORMAT.cmake ├── CITATION.bib ├── envs └── nix │ ├── dev.nix │ ├── flake.nix │ ├── NIX.md │ ├── exaca.nix │ └── flake.lock ├── .clang-format ├── LICENSE ├── .cmake-format.json ├── NOTICE ├── PUBLICATIONS.bib └── CMakeLists.txt /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *~ 3 | *.bov 4 | *.dat 5 | -------------------------------------------------------------------------------- /utilities/Finch/scan_path_small.txt: -------------------------------------------------------------------------------- 1 | Mode X Y Z Power Parameter 2 | 1 0.000 0.00 0.0 195 0.0005 3 | 0 0.0002 0.00 0.0 195 0.8 4 | -------------------------------------------------------------------------------- /analysis/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(src) 2 | 3 | if(ExaCA_ENABLE_TESTING) 4 | add_subdirectory(unit_test) 5 | endif() 6 | 7 | add_subdirectory(bin) 8 | -------------------------------------------------------------------------------- /examples/Materials/SS316.json: -------------------------------------------------------------------------------- 1 | { 2 | "function": "power", 3 | "coefficients": { 4 | "A": 0.000007325, 5 | "B": 3.12, 6 | "C": 0 7 | }, 8 | "freezing_range": 26.5 9 | } 10 | -------------------------------------------------------------------------------- /analysis/bin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(ExaCA-GrainAnalysis runGA.cpp) 2 | target_link_libraries(ExaCA-GrainAnalysis ExaCA-Analysis) 3 | install(TARGETS ExaCA-GrainAnalysis DESTINATION ${CMAKE_INSTALL_BINDIR}) 4 | -------------------------------------------------------------------------------- /analysis/unit_test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(${TEST_HARNESS_DIR}/test_harness.cmake) 2 | 3 | exaca_add_tests(PACKAGE ExaCA-Analysis NAMES Utils KokkosUtils) 4 | exaca_add_tests(PACKAGE ExaCA-Analysis NAMES RepresentativeRegion) 5 | -------------------------------------------------------------------------------- /examples/Materials/SS316L_Austenite.json: -------------------------------------------------------------------------------- 1 | { 2 | "function": "power", 3 | "coefficients": { 4 | "A": 3.1718E-18, 5 | "B": 12.024, 6 | "C": 0 7 | }, 8 | "freezing_range": 24.9 9 | } 10 | -------------------------------------------------------------------------------- /examples/Materials/Inconel625_Quadratic.json: -------------------------------------------------------------------------------- 1 | { 2 | "function": "quadratic", 3 | "coefficients": { 4 | "A": 0.000072879, 5 | "B": 0.004939, 6 | "C": -0.047024 7 | }, 8 | "freezing_range": 210 9 | } 10 | -------------------------------------------------------------------------------- /examples/Materials/Inconel625.json: -------------------------------------------------------------------------------- 1 | { 2 | "function": "cubic", 3 | "coefficients": { 4 | "A": -0.00000010302, 5 | "B": 0.00010533, 6 | "C": 0.0022196, 7 | "D": 0 8 | }, 9 | "freezing_range": 210 10 | } 11 | -------------------------------------------------------------------------------- /unit_test/TestCUDA_Category.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EXACA_TEST_CUDA_CATEGORY_HPP 2 | #define EXACA_TEST_CUDA_CATEGORY_HPP 3 | 4 | #define TEST_CATEGORY cuda 5 | #define TEST_EXECSPACE Kokkos::Cuda 6 | #define TEST_MEMSPACE Kokkos::CudaSpace 7 | #define TEST_DEVICE Kokkos::Device 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /unit_test/TestOPENMP_Category.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EXACA_TEST_OPENMP_CATEGORY_HPP 2 | #define EXACA_TEST_OPENMP_CATEGORY_HPP 3 | 4 | #define TEST_CATEGORY openmp 5 | #define TEST_EXECSPACE Kokkos::OpenMP 6 | #define TEST_MEMSPACE Kokkos::HostSpace 7 | #define TEST_DEVICE Kokkos::Device 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /unit_test/TestSERIAL_Category.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EXACA_TEST_SERIAL_CATEGORY_HPP 2 | #define EXACA_TEST_SERIAL_CATEGORY_HPP 3 | 4 | #define TEST_CATEGORY serial 5 | #define TEST_EXECSPACE Kokkos::Serial 6 | #define TEST_MEMSPACE Kokkos::HostSpace 7 | #define TEST_DEVICE Kokkos::Device 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /unit_test/TestPTHREAD_Category.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EXACA_TEST_PTHREAD_CATEGORY_HPP 2 | #define EXACA_TEST_PTHREAD_CATEGORY_HPP 3 | 4 | #define TEST_CATEGORY pthread 5 | #define TEST_EXECSPACE Kokkos::Threads 6 | #define TEST_MEMSPACE Kokkos::HostSpace 7 | #define TEST_DEVICE Kokkos::Device 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /unit_test/TestTHREADS_Category.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EXACA_TEST_THREADS_CATEGORY_HPP 2 | #define EXACA_TEST_THREADS_CATEGORY_HPP 3 | 4 | #define TEST_CATEGORY threads 5 | #define TEST_EXECSPACE Kokkos::Threads 6 | #define TEST_MEMSPACE Kokkos::HostSpace 7 | #define TEST_DEVICE Kokkos::Device 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /unit_test/TestHIP_Category.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EXACA_TEST_HIP_CATEGORY_HPP 2 | #define EXACA_TEST_HIP_CATEGORY_HPP 3 | 4 | #define TEST_CATEGORY hip 5 | #define TEST_EXECSPACE Kokkos::Experimental::HIP 6 | #define TEST_MEMSPACE Kokkos::Experimental::HIPSpace 7 | #define TEST_DEVICE Kokkos::Device 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /bin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(ExaCA run.cpp) 2 | target_link_libraries(ExaCA ExaCA-Core) 3 | install(TARGETS ExaCA DESTINATION ${CMAKE_INSTALL_BINDIR}) 4 | 5 | if(ExaCA_ENABLE_FINCH) 6 | add_executable(Finch-ExaCA runCoupled.cpp) 7 | target_link_libraries(Finch-ExaCA ExaCA-Core) 8 | install(TARGETS Finch-ExaCA DESTINATION ${CMAKE_INSTALL_BINDIR}) 9 | endif() 10 | -------------------------------------------------------------------------------- /.github/workflows/format.yml: -------------------------------------------------------------------------------- 1 | name: Clang-Format Check 2 | on: [pull_request] 3 | jobs: 4 | formatting-check: 5 | name: Formatting Check 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v4 9 | - name: Run clang-format style check 10 | uses: DoozyX/clang-format-lint-action@v0.20 11 | with: 12 | extensions: 'hpp,cpp' 13 | clangFormatVersion: 17 14 | inplace: True 15 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to ExaCA, please first discuss the changes you wish to make via issue (or directly with the ExaCA developers). 4 | Changes should be made through opening a pull request with `master` as the destination branch. 5 | Coding style from .clang-format and review from at least one ExaCA developer are required. 6 | 7 | ExaCA is distributed under the terms of the MIT license. All new contributions must be made under this license. 8 | -------------------------------------------------------------------------------- /src/CAinfo.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #ifndef EXACA_INFO_HPP 7 | #define EXACA_INFO_HPP 8 | 9 | #include "CAconfig.hpp" 10 | 11 | #include 12 | 13 | // Functions for printing for ExaCA/Kokkos version 14 | std::string version(); 15 | std::string gitCommitHash(); 16 | std::string kokkosVersion(); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/CAinfo.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #include "CAinfo.hpp" 7 | 8 | #include 9 | 10 | // Functions for printing for ExaCA/Kokkos version 11 | std::string version() { return ExaCA_VERSION; } 12 | 13 | std::string gitCommitHash() { return ExaCA_GIT_COMMIT_HASH; } 14 | 15 | std::string kokkosVersion() { return ExaCA_Kokkos_VERSION_STRING; } 16 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v3.4.0 4 | hooks: 5 | - id: check-merge-conflict 6 | - id: end-of-file-fixer 7 | 8 | - repo: https://github.com/pre-commit/mirrors-clang-format 9 | rev: v17.0.1 10 | hooks: 11 | - id: clang-format 12 | types_or: [c++] 13 | args: ["-style=file", "-i"] 14 | 15 | - repo: https://github.com/cheshirekow/cmake-format-precommit 16 | rev: v0.6.13 17 | hooks: 18 | - id: cmake-format 19 | -------------------------------------------------------------------------------- /cmake/ExaCAconfig.cmakein: -------------------------------------------------------------------------------- 1 | include(CMakeFindDependencyMacro) 2 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}" ) 3 | list(APPEND CMAKE_PREFIX_PATH @CMAKE_PREFIX_PATH@) 4 | include("${CMAKE_CURRENT_LIST_DIR}/ExaCA_Targets.cmake") 5 | if(ExaCA_ENABLE_FINCH) 6 | find_dependency(Finch REQUIRED COMPONENTS Finch::Core Finch::ScanPaths) 7 | endif() 8 | find_dependency(Kokkos REQUIRED) 9 | find_dependency(MPI REQUIRED) 10 | if(ExaCA_ENABLE_TESTING) 11 | find_dependency(GTest REQUIRED) 12 | endif() 13 | find_dependency(nlohmann_json REQUIRED) 14 | -------------------------------------------------------------------------------- /CITATION.bib: -------------------------------------------------------------------------------- 1 | @article{rolchigo2022, 2 | title = {ExaCA: A performance portable exascale cellular automata application for alloy solidification modeling}, 3 | journal = {Computational Materials Science}, 4 | volume = {214}, 5 | pages = {111692}, 6 | year = {2022}, 7 | issn = {0927-0256}, 8 | doi = {https://doi.org/10.1016/j.commatsci.2022.111692}, 9 | url = {https://www.sciencedirect.com/science/article/pii/S0927025622004189}, 10 | author = {Matt Rolchigo and Samuel Temple Reeve and Benjamin Stump and Gerald L. Knapp and John Coleman and Alex Plotkowski and James Belak}, 11 | } 12 | -------------------------------------------------------------------------------- /unit_test/unit_test_main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | 12 | int main(int argc, char *argv[]) { 13 | MPI_Init(&argc, &argv); 14 | Kokkos::initialize(argc, argv); 15 | ::testing::InitGoogleTest(&argc, argv); 16 | int return_val = RUN_ALL_TESTS(); 17 | Kokkos::finalize(); 18 | MPI_Finalize(); 19 | return return_val; 20 | } 21 | -------------------------------------------------------------------------------- /src/CAconfig.hpp.cmakein: -------------------------------------------------------------------------------- 1 | // Copyright 2021-2023 Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #ifndef EXACA_CONFIG_HPP 7 | #define EXACA_CONFIG_HPP 8 | 9 | #define ExaCA_DATA_SOURCE "@CMAKE_SOURCE_DIR@" 10 | #define ExaCA_DATA_INSTALL "@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_DATADIR@/ExaCA" 11 | 12 | #define ExaCA_VERSION "@PROJECT_VERSION@" 13 | #define ExaCA_GIT_COMMIT_HASH "@ExaCA_GIT_COMMIT_HASH@" 14 | 15 | #define ExaCA_Kokkos_VERSION_STRING "@Kokkos_VERSION@" 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/CAtypes.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #ifndef EXACA_TYPES_HPP 7 | #define EXACA_TYPES_HPP 8 | 9 | #include 10 | 11 | enum TypeNames { 12 | Wall = 0, 13 | Solid = 1, 14 | Active = 2, 15 | TemporaryUpdate = 3, 16 | TemporaryInit = 4, 17 | Liquid = 5, 18 | TempSolid = 6, 19 | FutureActive = 7, 20 | ActiveFailedBufferLoad = 8, 21 | FutureLiquid = 9, 22 | LiquidFailedBufferLoad = 10 23 | }; 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /analysis/examples/AnalyzeAMB.json: -------------------------------------------------------------------------------- 1 | { 2 | "Regions": { 3 | "XY1mm": { 4 | "units": "Meters", 5 | "zBounds": [0.001,0.001], 6 | "printStats": ["GrainTypeFractions"], 7 | "printPerGrainStats": ["Size","IPFZ-RGB"], 8 | "printPoleFigureData": true, 9 | "printInversePoleFigureData": true 10 | }, 11 | "XZ500microns": { 12 | "units": "Meters", 13 | "yBounds": [0.00255,0.00255], 14 | "printStats": ["GrainTypeFractions"], 15 | "printPoleFigureData": false, 16 | "printInversePoleFigureData": true 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /analysis/unit_test/tstKokkosUtils.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #include 7 | 8 | #include "GAutils.hpp" 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | namespace Test { 16 | //---------------------------------------------------------------------------// 17 | // GAutils tests with Kokkos 18 | //---------------------------------------------------------------------------// 19 | TEST(TEST_CATEGORY, grain_util_tests_kokkos) {} 20 | } // end namespace Test 21 | -------------------------------------------------------------------------------- /envs/nix/dev.nix: -------------------------------------------------------------------------------- 1 | { self', pkgs, lib, ... }: 2 | 3 | { 4 | devShells = rec { 5 | default = exacaDev; 6 | 7 | exacaDev = pkgs.mkShell { 8 | name = "exaca-dev"; 9 | 10 | packages = with pkgs; [ 11 | git 12 | clang-tools 13 | ] ++ lib.optionals (pkgs.stdenv.hostPlatform.isLinux) [ 14 | gdb 15 | ]; 16 | 17 | inputsFrom = [ 18 | self'.packages.default 19 | ]; 20 | 21 | # Ensure the locales point at the correct archive location. 22 | LOCALE_ARCHIVE = lib.optional (pkgs.stdenv.hostPlatform.isLinux) ( 23 | "${pkgs.glibcLocales}/lib/locale/locale-archive" 24 | ); 25 | }; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /examples/Materials/SS316L_AusteniteFerrite.json: -------------------------------------------------------------------------------- 1 | { 2 | "phases": ["austenite", "ferrite"], 3 | "austenite": { 4 | "function": "power", 5 | "coefficients": { 6 | "A": 3.1718E-18, 7 | "B": 12.024, 8 | "C": 0 9 | }, 10 | "freezing_range": 24.9, 11 | "velocity_cap": true 12 | }, 13 | "ferrite": { 14 | "function": "exponential", 15 | "coefficients": { 16 | "A": 5.6442E-5, 17 | "B": 0.37259, 18 | "C": 0 19 | }, 20 | "freezing_range": 23.9, 21 | "transformation": "solidification", 22 | "velocity_cap": true 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/ExaCA.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #ifndef EXACA_HPP 7 | #define EXACA_HPP 8 | 9 | #include "CAgrid.hpp" 10 | #include "CAinfo.hpp" 11 | #include "CAinputs.hpp" 12 | #include "CAinterface.hpp" 13 | #include "CAinterfacialresponse.hpp" 14 | #include "CAnucleation.hpp" 15 | #include "CAorientation.hpp" 16 | #include "CAparsefiles.hpp" 17 | #include "CAprint.hpp" 18 | #include "CAtemperature.hpp" 19 | #include "CAtimers.hpp" 20 | #include "CAtypes.hpp" 21 | #include "CAupdate.hpp" 22 | #include "runCA.hpp" 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | --- 3 | Language: Cpp 4 | ColumnLimit: 120 5 | AlwaysBreakTemplateDeclarations: true 6 | BinPackParameters: true 7 | IndentWidth: 4 8 | SpacesInParentheses: false 9 | BreakConstructorInitializersBeforeComma: true 10 | PointerAlignment: Right 11 | # Attach with else on newline 12 | BraceWrapping: 13 | AfterClass: false 14 | AfterControlStatement: false 15 | AfterEnum: false 16 | AfterFunction: false 17 | AfterNamespace: false 18 | AfterObjCDeclaration: false 19 | AfterStruct: false 20 | AfterUnion: false 21 | BeforeCatch: false 22 | BeforeElse: true 23 | IndentBraces: false 24 | BreakBeforeBraces: Custom 25 | AlignTrailingComments: false 26 | -------------------------------------------------------------------------------- /analysis/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB EXAGA_HEADERS GLOB *.hpp) 2 | file(GLOB EXAGA_SOURCES GLOB *.cpp) 3 | 4 | install(FILES ${EXAGA_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 5 | 6 | add_library(ExaCA-Analysis ${EXAGA_SOURCES}) 7 | add_library(ExaCA::Analysis ALIAS ExaCA-Analysis) 8 | 9 | target_link_libraries(ExaCA-Analysis PUBLIC ExaCA-Core) 10 | 11 | target_include_directories( 12 | ExaCA-Analysis 13 | PUBLIC $ 14 | $ 15 | $) 16 | 17 | install( 18 | TARGETS ExaCA-Analysis 19 | EXPORT ExaCA_Targets 20 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 21 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) 22 | -------------------------------------------------------------------------------- /examples/Inp_EquiaxedGrain.json: -------------------------------------------------------------------------------- 1 | { 2 | "SimulationType": "SingleGrain", 3 | "MaterialFileName": "Inconel625.json", 4 | "GrainOrientationFile": "GrainOrientationVectors.csv", 5 | "Domain": { 6 | "CellSize": 1, 7 | "TimeStep": 0.0666667, 8 | "Nx": 49, 9 | "Ny": 49, 10 | "Nz": 49 11 | }, 12 | "TemperatureData": { 13 | "InitUndercooling": 10, 14 | "G": 0, 15 | "R": 0 16 | }, 17 | "Substrate": { 18 | "GrainOrientation": 0 19 | }, 20 | "Printing": { 21 | "PathToOutput": "./", 22 | "OutputFile": "TestProblemEquiaxedGrain", 23 | "PrintBinary": false, 24 | "PrintExaConstitSize": 0, 25 | "Interlayer": { 26 | "Fields": ["GrainID"] 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/Inp_SmallEquiaxedGrain.json: -------------------------------------------------------------------------------- 1 | { 2 | "SimulationType": "SingleGrain", 3 | "MaterialFileName": "Inconel625.json", 4 | "GrainOrientationFile": "GrainOrientationVectors.csv", 5 | "Domain": { 6 | "CellSize": 1, 7 | "TimeStep": 0.0666667, 8 | "Nx": 19, 9 | "Ny": 19, 10 | "Nz": 19 11 | }, 12 | "TemperatureData": { 13 | "InitUndercooling": 10, 14 | "G": 0, 15 | "R": 0 16 | }, 17 | "Substrate": { 18 | "GrainOrientation": 0 19 | }, 20 | "Printing": { 21 | "PathToOutput": "./", 22 | "OutputFile": "TestProblemSmallEquiaxedGrain", 23 | "PrintBinary": false, 24 | "PrintExaConstitSize": 0, 25 | "Interlayer": { 26 | "Fields": ["GrainID"] 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/Inp_SmallFinch.json: -------------------------------------------------------------------------------- 1 | { 2 | "SimulationType": "FromFinch", 3 | "MaterialFileName": "Inconel625.json", 4 | "GrainOrientationFile": "GrainOrientationVectors.csv", 5 | "RandomSeed": 0, 6 | "Domain": { 7 | "CellSize": 10, 8 | "TimeStep": 0.2, 9 | "NumberOfLayers": 1, 10 | "LayerOffset": 8 11 | }, 12 | "Nucleation": { 13 | "Density": 100, 14 | "MeanUndercooling": 5, 15 | "StDev": 0.5 16 | }, 17 | "Substrate": { 18 | "MeanBaseplateGrainSize": 75 19 | }, 20 | "Printing": { 21 | "PathToOutput": "./", 22 | "OutputFile": "TestProblemSmallFinch", 23 | "PrintBinary": true, 24 | "PrintExaConstitSize": 0, 25 | "Interlayer": { 26 | "Fields": ["LayerID", "GrainMisorientation"] 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /envs/nix/flake.nix: -------------------------------------------------------------------------------- 1 | ## See NIX.md for help getting started with Nix 2 | 3 | { 4 | description = "An exascale-capable cellular automaton for nucleation and grain growth"; 5 | 6 | inputs = { 7 | nixpkgs.url = "github:nixos/nixpkgs/25.05"; 8 | parts.url = "github:hercules-ci/flake-parts"; 9 | }; 10 | 11 | outputs = inputs @ { self, parts, ... }: ( 12 | parts.lib.mkFlake { inherit inputs; } { 13 | systems = [ 14 | "x86_64-linux" 15 | "aarch64-linux" 16 | ]; 17 | 18 | perSystem = { pkgs, ... }: { 19 | packages = rec { 20 | default = exaca; 21 | 22 | exaca = pkgs.callPackage ./exaca.nix { 23 | src = ../..; 24 | version = "master"; 25 | }; 26 | 27 | }; 28 | 29 | imports = [ 30 | ./dev.nix 31 | ]; 32 | }; 33 | } 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /examples/Inp_Finch.json: -------------------------------------------------------------------------------- 1 | { 2 | "SimulationType": "FromFinch", 3 | "MaterialFileName": "Inconel625.json", 4 | "GrainOrientationFile": "GrainOrientationVectors.csv", 5 | "RandomSeed": 0, 6 | "Domain": { 7 | "CellSize": 3, 8 | "TimeStep": 0.08, 9 | "NumberOfLayers": 3, 10 | "LayerOffset": 8 11 | }, 12 | "Nucleation": { 13 | "Density": 100, 14 | "MeanUndercooling": 5, 15 | "StDev": 0.5 16 | }, 17 | "TemperatureData": { 18 | "TrimUnmeltedRegion": true 19 | }, 20 | "Substrate": { 21 | "MeanBaseplateGrainSize": 50 22 | }, 23 | "Printing": { 24 | "PathToOutput": "./", 25 | "OutputFile": "TestProblemFinch", 26 | "PrintBinary": true, 27 | "PrintExaConstitSize": 0, 28 | "Interlayer": { 29 | "Fields": ["LayerID", "GrainMisorientation"] 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/Inp_SmallSpotMelt_Steel1phase.json: -------------------------------------------------------------------------------- 1 | { 2 | "SimulationType": "Spot", 3 | "MaterialFileName": "SS316L_Austenite.json", 4 | "GrainOrientationFile": "GrainOrientationVectors.csv", 5 | "RandomSeed": 0, 6 | "Domain": { 7 | "CellSize": 1, 8 | "TimeStep": 0.0666667, 9 | "SpotRadius": 25 10 | }, 11 | "Nucleation": { 12 | "Density": 100, 13 | "MeanUndercooling": 2, 14 | "StDev": 0.5 15 | }, 16 | "TemperatureData": { 17 | "G": 150000, 18 | "R": 75000 19 | }, 20 | "Substrate": { 21 | "MeanBaseplateGrainSize": 25 22 | }, 23 | "Printing": { 24 | "PathToOutput": "./", 25 | "OutputFile": "TestProblemSmallSpot_Steel1Phase", 26 | "PrintBinary": false, 27 | "PrintExaConstitSize": 0, 28 | "Interlayer": { 29 | "Fields": ["GrainID", "PhaseID", "GrainMisorientation"] 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/Inp_SmallSpotMelt_Steel2phase.json: -------------------------------------------------------------------------------- 1 | { 2 | "SimulationType": "Spot", 3 | "MaterialFileName": "SS316L_AusteniteFerrite.json", 4 | "GrainOrientationFile": "GrainOrientationVectors.csv", 5 | "RandomSeed": 0, 6 | "Domain": { 7 | "CellSize": 1, 8 | "TimeStep": 0.0666667, 9 | "SpotRadius": 25 10 | }, 11 | "Nucleation": { 12 | "Density": 100, 13 | "MeanUndercooling": 2, 14 | "StDev": 0.5 15 | }, 16 | "TemperatureData": { 17 | "G": 150000, 18 | "R": 75000 19 | }, 20 | "Substrate": { 21 | "MeanBaseplateGrainSize": 25 22 | }, 23 | "Printing": { 24 | "PathToOutput": "./", 25 | "OutputFile": "TestProblemSmallSpot_Steel2Phase", 26 | "PrintBinary": false, 27 | "PrintExaConstitSize": 0, 28 | "Interlayer": { 29 | "Fields": ["GrainID", "PhaseID", "GrainMisorientation"] 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/Inp_SmallDirSolidification.json: -------------------------------------------------------------------------------- 1 | { 2 | "SimulationType": "Directional", 3 | "MaterialFileName": "Inconel625.json", 4 | "GrainOrientationFile": "GrainOrientationVectors.csv", 5 | "RandomSeed": 0, 6 | "Domain": { 7 | "CellSize": 1, 8 | "TimeStep": 0.0666667, 9 | "Nx": 20, 10 | "Ny": 20, 11 | "Nz": 20 12 | }, 13 | "Nucleation": { 14 | "Density": 250, 15 | "MeanUndercooling": 5, 16 | "StDev": 0.5 17 | }, 18 | "TemperatureData": { 19 | "G": 500000, 20 | "R": 300000 21 | }, 22 | "Substrate": { 23 | "SurfaceSiteDensity": 0.25 24 | }, 25 | "Printing": { 26 | "PathToOutput": "./", 27 | "OutputFile": "TestProblemSmallDirS", 28 | "PrintBinary": false, 29 | "PrintExaConstitSize": 0, 30 | "Interlayer": { 31 | "Fields": ["GrainID", "LayerID", "GrainMisorientation"] 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /utilities/Finch/inputs_small.json: -------------------------------------------------------------------------------- 1 | { 2 | "time": 3 | { 4 | "Co": 0.125, 5 | "start_time": 0.0, 6 | "end_time": 0.0015, 7 | "total_output_steps": 2, 8 | "total_monitor_steps": 10 9 | }, 10 | "space": 11 | { 12 | "initial_temperature": 300.0, 13 | "cell_size": 10e-6, 14 | "global_low_corner": [-2e-4, -2e-4, -2e-4], 15 | "global_high_corner": [3e-4, 2e-4, 0.0], 16 | "ranks_per_dim": [1, 1, 1] 17 | }, 18 | "properties": 19 | { 20 | "density": 7500.0, 21 | "specific_heat": 750.0, 22 | "thermal_conductivity": 25.0, 23 | "latent_heat": 2e5, 24 | "solidus": 1410.0, 25 | "liquidus": 1620.0 26 | }, 27 | "source": 28 | { 29 | "absorption": 0.3, 30 | "two_sigma": [60e-6, 60e-6, 60e-6], 31 | "scan_path_file": "scan_path_small.txt" 32 | }, 33 | "sampling": 34 | { 35 | "type": "solidification_data", 36 | "format": "default", 37 | "directory_name": "single_line_small" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /utilities/Finch/inputs_small_refined.json: -------------------------------------------------------------------------------- 1 | { 2 | "time": 3 | { 4 | "Co": 0.125, 5 | "start_time": 0.0, 6 | "end_time": 0.0015, 7 | "total_output_steps": 2, 8 | "total_monitor_steps": 10 9 | }, 10 | "space": 11 | { 12 | "initial_temperature": 300.0, 13 | "cell_size": 3e-6, 14 | "global_low_corner": [-210e-6, -180e-6, -180e-6], 15 | "global_high_corner": [300e-6, 180e-6, 0.0], 16 | "ranks_per_dim": [2, 2, 1] 17 | }, 18 | "properties": 19 | { 20 | "density": 7500.0, 21 | "specific_heat": 750.0, 22 | "thermal_conductivity": 25.0, 23 | "latent_heat": 2e5, 24 | "solidus": 1410.0, 25 | "liquidus": 1620.0 26 | }, 27 | "source": 28 | { 29 | "absorption": 0.3, 30 | "two_sigma": [60e-6, 60e-6, 60e-6], 31 | "scan_path_file": "scan_path_small.txt" 32 | }, 33 | "sampling": 34 | { 35 | "type": "solidification_data", 36 | "format": "default", 37 | "directory_name": "single_line_small_exaca" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /analysis/examples/AnalyzeSmallDirS.json: -------------------------------------------------------------------------------- 1 | { 2 | "Regions": { 3 | "RepresentativeVolume": { 4 | "units": "Cells", 5 | "xBounds": [0, 19], 6 | "yBounds": [0, 19], 7 | "zBounds": [0, 19], 8 | "printExaConstit": false, 9 | "printPoleFigure": true, 10 | "printAvgStats": ["GrainTypeFractions","Misorientation","Size", "BuildTransAspectRatio","Extent"], 11 | "printPerGrainStats": ["Misorientation","Size","ZExtent"], 12 | "printPerZCoordinateStats": ["MeanGrainArea"] 13 | }, 14 | "XYCross": { 15 | "units": "Cells", 16 | "zBounds": [19,19], 17 | "printPoleFigureData": true, 18 | "printInversePoleFigureData": true 19 | }, 20 | "XZCross": { 21 | "units": "Cells", 22 | "yBounds": [10,10], 23 | "printPoleFigureData": false, 24 | "printInversePoleFigureData": true 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /analysis/examples/AnalyzeDirS.json: -------------------------------------------------------------------------------- 1 | { 2 | "Regions": { 3 | "RepresentativeVolume": { 4 | "units": "cells", 5 | "xBounds": [15, 184], 6 | "yBounds": [15, 184], 7 | "zBounds": [1, 199], 8 | "printExaConstit": false, 9 | "printPoleFigureData": true, 10 | "printAvgStats": ["GrainTypeFractions","Misorientation","Size", "BuildTransAspectRatio","Extent"], 11 | "printPerGrainStats": ["Misorientation","Size","ZExtent"], 12 | "printPerZCoordinateStats": ["MeanGrainArea"] 13 | }, 14 | "XYCross": { 15 | "units": "cells", 16 | "zBounds": [199,199], 17 | "printPoleFigureData": true, 18 | "printInversePoleFigureData": true 19 | }, 20 | "XZCross": { 21 | "units": "cells", 22 | "yBounds": [100,100], 23 | "printPoleFigureData": false, 24 | "printInversePoleFigureData": true 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/Inp_SingleLine.json: -------------------------------------------------------------------------------- 1 | { 2 | "SimulationType": "FromFile", 3 | "MaterialFileName": "Inconel625.json", 4 | "GrainOrientationFile": "GrainOrientationVectors.csv", 5 | "RandomSeed": 0, 6 | "Domain": { 7 | "CellSize": 2.5, 8 | "TimeStep": 0.0825, 9 | "NumberOfLayers": 1, 10 | "LayerOffset": 8 11 | }, 12 | "Nucleation": { 13 | "Density": 100, 14 | "MeanUndercooling": 5, 15 | "StDev": 0.5 16 | }, 17 | "TemperatureData": { 18 | "LayerwiseTempRead": false, 19 | "TemperatureFiles": ["examples/Temperatures/Line.txt"] 20 | }, 21 | "Substrate": { 22 | "MeanBaseplateGrainSize": 25, 23 | "MeanPowderGrainSize": 2.5, 24 | "BaseplateTopZ": -0.000020 25 | }, 26 | "Printing": { 27 | "PathToOutput": "./", 28 | "OutputFile": "TestProblemSingleLine", 29 | "PrintBinary": false, 30 | "PrintExaConstitSize": 0, 31 | "Interlayer": { 32 | "Fields": ["GrainID", "LayerID", "GrainMisorientation"] 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/Inp_FinchTranslate.json: -------------------------------------------------------------------------------- 1 | { 2 | "SimulationType": "FromFinch", 3 | "MaterialFileName": "Inconel625.json", 4 | "GrainOrientationFile": "GrainOrientationVectors.csv", 5 | "RandomSeed": 0, 6 | "Domain": { 7 | "CellSize": 3, 8 | "TimeStep": 0.08, 9 | "NumberOfLayers": 1, 10 | "LayerOffset": 8 11 | }, 12 | "Nucleation": { 13 | "Density": 100, 14 | "MeanUndercooling": 5, 15 | "StDev": 0.5 16 | }, 17 | "Substrate": { 18 | "MeanBaseplateGrainSize": 50 19 | }, 20 | "TemperatureData": { 21 | "TranslationCount": 2, 22 | "OffsetDirection": "Y", 23 | "SpatialOffset": 40, 24 | "TemporalOffset": 1600, 25 | "AlternatingDirection": true 26 | }, 27 | "Printing": { 28 | "PathToOutput": "./", 29 | "OutputFile": "TestProblemFinchTranslate", 30 | "PrintBinary": true, 31 | "PrintExaConstitSize": 0, 32 | "Interlayer": { 33 | "Fields": ["CritTimeStep", "LayerID", "GrainMisorientation"] 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /examples/Inp_DirSolidification.json: -------------------------------------------------------------------------------- 1 | { 2 | "SimulationType": "Directional", 3 | "MaterialFileName": "Inconel625.json", 4 | "GrainOrientationFile": "GrainOrientationVectors.csv", 5 | "RandomSeed": 0, 6 | "Domain": { 7 | "CellSize": 1, 8 | "TimeStep": 0.066666666, 9 | "Nx": 200, 10 | "Ny": 200, 11 | "Nz": 200 12 | }, 13 | "Nucleation": { 14 | "Density": 10, 15 | "MeanUndercooling": 5, 16 | "StDev": 0.5 17 | }, 18 | "TemperatureData": { 19 | "G": 500000, 20 | "R": 300000 21 | }, 22 | "Substrate": { 23 | "SurfaceSiteFraction": 0.08 24 | }, 25 | "Printing": { 26 | "PathToOutput": "./", 27 | "OutputFile": "TestProblemDirS", 28 | "PrintBinary": false, 29 | "PrintExaConstitSize": 0, 30 | "Intralayer": { 31 | "Increment": 5250, 32 | "Fields": ["GrainMisorientation"], 33 | "PrintIdleFrames": false 34 | }, 35 | "Interlayer": { 36 | "Fields": ["GrainID", "LayerID", "GrainMisorientation"] 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/Inp_SmallSpotMelt.json: -------------------------------------------------------------------------------- 1 | { 2 | "SimulationType": "Spot", 3 | "MaterialFileName": "Inconel625.json", 4 | "GrainOrientationFile": "GrainOrientationVectors.csv", 5 | "RandomSeed": 0, 6 | "Domain": { 7 | "CellSize": 1, 8 | "TimeStep": 0.0666667, 9 | "SpotRadius": 25 10 | }, 11 | "Nucleation": { 12 | "Density": 10, 13 | "MeanUndercooling": 5, 14 | "StDev": 0.5 15 | }, 16 | "TemperatureData": { 17 | "G": 500000, 18 | "R": 300000 19 | }, 20 | "Substrate": { 21 | "MeanBaseplateGrainSize": 25, 22 | "MeanPowderGrainSize": 1000000 23 | }, 24 | "Printing": { 25 | "PathToOutput": "./", 26 | "OutputFile": "TestProblemSmallSpot", 27 | "PrintBinary": false, 28 | "PrintExaConstitSize": 0, 29 | "Intralayer": { 30 | "Increment": 2000, 31 | "Fields": ["GrainMisorientation"], 32 | "PrintIdleFrames": true 33 | }, 34 | "Interlayer": { 35 | "Fields": ["GrainID", "LayerID", "GrainMisorientation"] 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/Inp_SpotMelt.json: -------------------------------------------------------------------------------- 1 | { 2 | "SimulationType": "Spot", 3 | "MaterialFileName": "Inconel625.json", 4 | "GrainOrientationFile": "GrainOrientationVectors.csv", 5 | "RandomSeed": 0, 6 | "Domain": { 7 | "CellSize": 1, 8 | "TimeStep": 0.066666666, 9 | "SpotRadius": 75 10 | }, 11 | "Nucleation": { 12 | "Density": 10, 13 | "MeanUndercooling": 5, 14 | "StDev": 0.5 15 | }, 16 | "TemperatureData": { 17 | "G": 500000, 18 | "R": 300000 19 | }, 20 | "Substrate": { 21 | "MeanBaseplateGrainSize": 25, 22 | "MeanPowderGrainSize": 1 23 | }, 24 | "Printing": { 25 | "PathToOutput": "./", 26 | "OutputFile": "TestProblemSpot", 27 | "PrintBinary": false, 28 | "PrintExaConstitSize": 0, 29 | "Intralayer": { 30 | "Increment": 2000, 31 | "Fields": ["GrainMisorientation", "MeltTimeStep", "CritTimeStep"], 32 | "PrintIdleFrames": true 33 | }, 34 | "Interlayer": { 35 | "Fields": ["GrainID", "LayerID", "GrainMisorientation"] 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /envs/nix/NIX.md: -------------------------------------------------------------------------------- 1 | ## Nix 2 | 3 | First install the [Nix package manager][NIX] and then enable [Flakes][Flakes]. 4 | Alternatively, check out the [Determinate Systems Installer][Determinate] for 5 | an out of the box experience. See [nix.dev][nix.dev] for more help with Nix. 6 | 7 | To get a shell with ExaCA temporarily installed, run: 8 | 9 | $ nix shell github:LLNL/ExaCA 10 | # ExaCA now available 11 | $ ExaCA --help 12 | 13 | To install this permanently, run: 14 | 15 | $ nix profile install github:LLNL/ExaCA?dir=envs/nix 16 | 17 | To get a specific release, use: 18 | 19 | $ nix shell github:LLNL/ExaCA/?dir=envs/nix 20 | 21 | To build from a working copy use `nix develop` and run CMake manually: 22 | 23 | $ nix develop 24 | $ cmake -B build 25 | $ cmake --build build 26 | 27 | See the main [README](../../README.md#Build-ExaCA) for more details on 28 | building ExaCA. 29 | 30 | 31 | [NIX]: https://nixos.org/download.html 32 | [Flakes]: https://nixos.wiki/wiki/Flakes 33 | [nix.dev]: https://nix.dev 34 | [Determinate]: https://github.com/DeterminateSystems/nix-installer 35 | -------------------------------------------------------------------------------- /examples/Inp_TwoLineTwoLayer.json: -------------------------------------------------------------------------------- 1 | { 2 | "SimulationType": "FromFile", 3 | "MaterialFileName": "Inconel625.json", 4 | "GrainOrientationFile": "GrainOrientationVectors.csv", 5 | "RandomSeed": 0, 6 | "Domain": { 7 | "CellSize": 2.5, 8 | "TimeStep": 0.0825, 9 | "NumberOfLayers": 2, 10 | "LayerOffset": 8 11 | }, 12 | "Nucleation": { 13 | "Density": 100, 14 | "MeanUndercooling": 5, 15 | "StDev": 0.5 16 | }, 17 | "TemperatureData": { 18 | "LayerwiseTempRead": false, 19 | "TemperatureFiles": ["examples/Temperatures/TwoLine.txt"] 20 | }, 21 | "Substrate": { 22 | "MeanBaseplateGrainSize": 25, 23 | "MeanPowderGrainSize": 2.5 24 | }, 25 | "Printing": { 26 | "PathToOutput": "./", 27 | "OutputFile": "TestProblemTwoLineTwoLayer", 28 | "PrintBinary": false, 29 | "PrintExaConstitSize": 0, 30 | "Interlayer": { 31 | "Fields": ["GrainID", "LayerID", "GrainMisorientation", "UndercoolingCurrent", "SolidificationEventCounter"], 32 | "Layers": [0, 1] 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021, Lawrence Livermore National Security, LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/Inp_TwoGrainDirSolidification.json: -------------------------------------------------------------------------------- 1 | { 2 | "SimulationType": "Directional", 3 | "MaterialFileName": "Inconel625.json", 4 | "GrainOrientationFile": "GrainOrientationVectors.csv", 5 | "RandomSeed": 0, 6 | "Domain": { 7 | "CellSize": 1, 8 | "TimeStep": 0.066666666, 9 | "Nx": 200, 10 | "Ny": 200, 11 | "Nz": 200 12 | }, 13 | "Nucleation": { 14 | "Density": 0, 15 | "MeanUndercooling": 5, 16 | "StDev": 0.5 17 | }, 18 | "TemperatureData": { 19 | "InitUndercooling": 10, 20 | "G": 500000, 21 | "R": 300000 22 | }, 23 | "Substrate": { 24 | "GrainLocationsX": [100, 100], 25 | "GrainLocationsY": [50, 150], 26 | "GrainIDs": [25, 9936], 27 | "FillBottomSurface": false 28 | }, 29 | "Printing": { 30 | "PathToOutput": "./", 31 | "OutputFile": "TestProblemTwoGrainDirS", 32 | "PrintBinary": false, 33 | "PrintExaConstitSize": 0, 34 | "Intralayer": { 35 | "Increment": 5250, 36 | "Fields": ["GrainMisorientation"], 37 | "PrintIdleFrames": false 38 | }, 39 | "Interlayer": { 40 | "Fields": ["GrainID", "LayerID", "GrainMisorientation"] 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | configure_file(CAconfig.hpp.cmakein CAconfig.hpp) 2 | 3 | file(GLOB EXACA_HEADERS GLOB *.hpp) 4 | file(GLOB EXACA_SOURCES GLOB *.cpp) 5 | 6 | install(FILES ${EXACA_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 7 | 8 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/CAconfig.hpp 9 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 10 | 11 | add_library(ExaCA-Core ${EXACA_SOURCES}) 12 | add_library(ExaCA::Core ALIAS ExaCA-Core) 13 | 14 | target_link_libraries(ExaCA-Core PUBLIC MPI::MPI_CXX Kokkos::kokkos 15 | nlohmann_json::nlohmann_json) 16 | if(ExaCA_ENABLE_FINCH) 17 | target_link_libraries(ExaCA-Core PUBLIC Finch::Core Finch::ScanPaths) 18 | endif() 19 | 20 | target_include_directories( 21 | ExaCA-Core 22 | PUBLIC $ 23 | $ 24 | $) 25 | 26 | install( 27 | TARGETS ExaCA-Core 28 | EXPORT ExaCA_Targets 29 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 30 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) 31 | 32 | install( 33 | EXPORT ExaCA_Targets 34 | FILE ExaCA_Targets.cmake 35 | NAMESPACE ExaCA:: 36 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ExaCA) 37 | -------------------------------------------------------------------------------- /examples/Inp_SingleLineTranslate.json: -------------------------------------------------------------------------------- 1 | { 2 | "SimulationType": "FromFile", 3 | "MaterialFileName": "Inconel625.json", 4 | "GrainOrientationFile": "GrainOrientationVectors.csv", 5 | "RandomSeed": 0, 6 | "Domain": { 7 | "CellSize": 2.5, 8 | "TimeStep": 0.0825, 9 | "NumberOfLayers": 1, 10 | "LayerOffset": 8 11 | }, 12 | "Nucleation": { 13 | "Density": 100, 14 | "MeanUndercooling": 5, 15 | "StDev": 0.5 16 | }, 17 | "TemperatureData": { 18 | "LayerwiseTempRead": false, 19 | "TemperatureFiles": ["examples/Temperatures/Line.txt"], 20 | "TranslationCount": 2, 21 | "YRegion": [0, 0.000225], 22 | "OffsetDirection": "Y", 23 | "SpatialOffset": 35, 24 | "TemporalOffset": 10000, 25 | "AlternatingDirection": true 26 | }, 27 | "Substrate": { 28 | "MeanBaseplateGrainSize": 25, 29 | "MeanPowderGrainSize": 2.5, 30 | "BaseplateTopZ": -0.000020 31 | }, 32 | "Printing": { 33 | "PathToOutput": "./", 34 | "OutputFile": "TestProblemSingleLineTranslate", 35 | "PrintBinary": false, 36 | "PrintExaConstitSize": 0, 37 | "Interlayer": { 38 | "Fields": ["GrainID", "LayerID", "CritTimeStep", "GrainMisorientation"] 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /envs/nix/exaca.nix: -------------------------------------------------------------------------------- 1 | { 2 | src, version, 3 | 4 | lib, stdenv, 5 | 6 | cmake, 7 | 8 | kokkos, openmpi, nlohmann_json, gtest 9 | }: 10 | 11 | stdenv.mkDerivation { 12 | pname = "exaca"; 13 | inherit version src; 14 | 15 | nativeBuildInputs = [ 16 | cmake 17 | ]; 18 | 19 | buildInputs = [ 20 | kokkos 21 | nlohmann_json 22 | gtest 23 | ]; 24 | 25 | propagatedBuildInputs = [ 26 | openmpi 27 | ]; 28 | 29 | cmakeFlags = [ 30 | (lib.cmakeBool "BUILD_SHARED_LIBS" true) 31 | (lib.cmakeBool "ExaCA_REQUIRE_EXTERNAL_JSON" true) 32 | (lib.cmakeBool "ExaCA_ENABLE_TESTING" false) 33 | ]; 34 | 35 | doCheck = true; 36 | 37 | checkPhase = '' 38 | mkdir -p test 39 | cd test 40 | cp $src/examples/Inp_SmallDirSolidification.json ./ 41 | substituteInPlace Inp_SmallDirSolidification.json --replace-fail "Inconel625.json" "$src/examples/Materials/Inconel625.json" 42 | substituteInPlace Inp_SmallDirSolidification.json --replace-fail "GrainOrientationVectors.csv" "$src/examples/Substrate/GrainOrientationVectors.csv" 43 | ../bin/ExaCA Inp_SmallDirSolidification.json 44 | test -e TestProblemSmallDirS.json 45 | test -e TestProblemSmallDirS_Misorientations.vtk 46 | test -e TestProblemSmallDirS.vtk 47 | cd .. 48 | \rm -rf test 49 | ''; 50 | 51 | } 52 | -------------------------------------------------------------------------------- /.cmake-format.json: -------------------------------------------------------------------------------- 1 | { 2 | "format": { 3 | "disable": false, 4 | "line_width": 80, 5 | "tab_size": 2, 6 | "use_tabchars": false, 7 | "fractional_tab_policy": "use-space", 8 | "max_subgroups_hwrap": 2, 9 | "max_pargs_hwrap": 6, 10 | "max_rows_cmdline": 2, 11 | "separate_ctrl_name_with_space": false, 12 | "separate_fn_name_with_space": false, 13 | "dangle_parens": false, 14 | "dangle_align": "prefix", 15 | "min_prefix_chars": 4, 16 | "max_prefix_chars": 10, 17 | "max_lines_hwrap": 2, 18 | "line_ending": "unix", 19 | "command_case": "canonical", 20 | "keyword_case": "unchanged", 21 | "always_wrap": [], 22 | "enable_sort": true, 23 | "autosort": false, 24 | "require_valid_layout": false, 25 | "layout_passes": {} 26 | }, 27 | "markup": { 28 | "bullet_char": "*", 29 | "enum_char": ".", 30 | "first_comment_is_literal": false, 31 | "literal_comment_pattern": null, 32 | "fence_pattern": "^\\s*([`~]{3}[`~]*)(.*)$", 33 | "ruler_pattern": "^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$", 34 | "explicit_trailing_pattern": "#<", 35 | "hashruler_min_length": 10, 36 | "canonicalize_hashrulers": false, 37 | "enable_markup": true 38 | }, 39 | "encode": { 40 | "emit_byteorder_mark": false, 41 | "input_encoding": "utf-8", 42 | "output_encoding": "utf-8" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | This work was produced under the auspices of the U.S. Department of 2 | Energy by Lawrence Livermore National Laboratory under Contract 3 | DE-AC52-07NA27344 and supported in part by the Exascale Computing Project 4 | (17-SC-20-SC), a collaborative effort of the U.S. DOE Office of Science 5 | and the NNSA. 6 | 7 | This work was prepared as an account of work sponsored by an agency of 8 | the United States Government. Neither the United States Government nor 9 | Lawrence Livermore National Security, LLC, nor any of their employees 10 | makes any warranty, expressed or implied, or assumes any legal liability 11 | or responsibility for the accuracy, completeness, or usefulness of any 12 | information, apparatus, product, or process disclosed, or represents that 13 | its use would not infringe privately owned rights. 14 | 15 | Reference herein to any specific commercial product, process, or service 16 | by trade name, trademark, manufacturer, or otherwise does not necessarily 17 | constitute or imply its endorsement, recommendation, or favoring by the 18 | United States Government or Lawrence Livermore National Security, LLC. 19 | 20 | The views and opinions of authors expressed herein do not necessarily 21 | state or reflect those of the United States Government or Lawrence 22 | Livermore National Security, LLC, and shall not be used for advertising 23 | or product endorsement purposes. 24 | -------------------------------------------------------------------------------- /.github/workflows/Nightly.yml: -------------------------------------------------------------------------------- 1 | name: Nightly 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | cmake_args: 6 | description: 'Extra CMake args' 7 | schedule: 8 | - cron: '0 1 * * *' 9 | 10 | jobs: 11 | CI: 12 | strategy: 13 | matrix: 14 | backend: ["OPENMP", "SERIAL"] 15 | kokkos_ver: ["develop"] 16 | runs-on: ubuntu-latest 17 | timeout-minutes: 30 18 | container: ghcr.io/ecp-copa/ci-containers/ubuntu:latest 19 | steps: 20 | - name: Checkout kokkos 21 | uses: actions/checkout@v3 22 | with: 23 | repository: kokkos/kokkos 24 | ref: ${{ matrix.kokkos_ver }} 25 | path: kokkos 26 | - name: Build kokkos 27 | working-directory: kokkos 28 | run: | 29 | cmake -B build -DCMAKE_INSTALL_PREFIX=$HOME/kokkos -DKokkos_ENABLE_${{ matrix.backend }}=ON -DCMAKE_BUILD_TYPE=Debug 30 | cmake --build build --parallel 2 31 | cmake --install build 32 | - name: Checkout ExaCA 33 | uses: actions/checkout@v3 34 | - name: Build ExaCA 35 | run: | 36 | cmake -B build -DCMAKE_INSTALL_PREFIX=$HOME/exaca -DCMAKE_PREFIX_PATH="$HOME/kokkos" -DExaCA_ENABLE_TESTING=ON -DExaCA_ENABLE_JSON=ON -DCMAKE_BUILD_TYPE=Debug ${{ github.event.inputs.cmake_args }} 37 | cmake --build build --parallel 2 38 | cmake --install build 39 | CTEST_OUTPUT_ON_FAILURE=1 cmake --build build --target test 40 | -------------------------------------------------------------------------------- /cmake/FindCLANG_FORMAT.cmake: -------------------------------------------------------------------------------- 1 | # Find clang-format 2 | # 3 | # CLANG_FORMAT_EXECUTABLE - Path to clang-format executable CLANG_FORMAT_FOUND 4 | # - True if the clang-format executable was found. CLANG_FORMAT_VERSION - 5 | # The version of clang-format found 6 | # 7 | 8 | find_program( 9 | CLANG_FORMAT_EXECUTABLE 10 | NAMES clang-format clang-format-17 11 | DOC "clang-format executable") 12 | mark_as_advanced(CLANG_FORMAT_EXECUTABLE) 13 | 14 | # Extract version from command "clang-format -version" 15 | if(CLANG_FORMAT_EXECUTABLE) 16 | execute_process( 17 | COMMAND ${CLANG_FORMAT_EXECUTABLE} -version 18 | OUTPUT_VARIABLE clang_format_version 19 | ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) 20 | 21 | if(clang_format_version MATCHES "^.*clang-format version .*") 22 | # clang_format_version sample: "clang-format version 3.9.1-4ubuntu3~16.04.1 23 | # (tags/RELEASE_391/rc2)" 24 | string(REGEX REPLACE "^.*clang-format version ([.0-9]+).*" "\\1" 25 | CLANG_FORMAT_VERSION "${clang_format_version}") 26 | # CLANG_FORMAT_VERSION sample: "3.9.1" 27 | else() 28 | set(CLANG_FORMAT_VERSION 0.0) 29 | endif() 30 | else() 31 | set(CLANG_FORMAT_VERSION 0.0) 32 | endif() 33 | 34 | include(FindPackageHandleStandardArgs) 35 | # handle the QUIETLY and REQUIRED arguments and set CLANG_FORMAT_FOUND to TRUE 36 | # if all listed variables are TRUE 37 | find_package_handle_standard_args( 38 | CLANG_FORMAT 39 | REQUIRED_VARS CLANG_FORMAT_EXECUTABLE 40 | VERSION_VAR CLANG_FORMAT_VERSION) 41 | -------------------------------------------------------------------------------- /envs/nix/flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixpkgs": { 4 | "locked": { 5 | "lastModified": 1748026580, 6 | "narHash": "sha256-rWtXrcIzU5wm/C8F9LWvUfBGu5U5E7cFzPYT1pHIJaQ=", 7 | "owner": "nixos", 8 | "repo": "nixpkgs", 9 | "rev": "11cb3517b3af6af300dd6c055aeda73c9bf52c48", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "nixos", 14 | "ref": "25.05", 15 | "repo": "nixpkgs", 16 | "type": "github" 17 | } 18 | }, 19 | "nixpkgs-lib": { 20 | "locked": { 21 | "lastModified": 1753579242, 22 | "narHash": "sha256-zvaMGVn14/Zz8hnp4VWT9xVnhc8vuL3TStRqwk22biA=", 23 | "owner": "nix-community", 24 | "repo": "nixpkgs.lib", 25 | "rev": "0f36c44e01a6129be94e3ade315a5883f0228a6e", 26 | "type": "github" 27 | }, 28 | "original": { 29 | "owner": "nix-community", 30 | "repo": "nixpkgs.lib", 31 | "type": "github" 32 | } 33 | }, 34 | "parts": { 35 | "inputs": { 36 | "nixpkgs-lib": "nixpkgs-lib" 37 | }, 38 | "locked": { 39 | "lastModified": 1754487366, 40 | "narHash": "sha256-pHYj8gUBapuUzKV/kN/tR3Zvqc7o6gdFB9XKXIp1SQ8=", 41 | "owner": "hercules-ci", 42 | "repo": "flake-parts", 43 | "rev": "af66ad14b28a127c5c0f3bbb298218fc63528a18", 44 | "type": "github" 45 | }, 46 | "original": { 47 | "owner": "hercules-ci", 48 | "repo": "flake-parts", 49 | "type": "github" 50 | } 51 | }, 52 | "root": { 53 | "inputs": { 54 | "nixpkgs": "nixpkgs", 55 | "parts": "parts" 56 | } 57 | } 58 | }, 59 | "root": "root", 60 | "version": 7 61 | } 62 | -------------------------------------------------------------------------------- /unit_test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(${TEST_HARNESS_DIR}/test_harness.cmake) 2 | 3 | # --------------------------------------------------------------------------## 4 | # Install example files used in tests 5 | # --------------------------------------------------------------------------## 6 | configure_file( 7 | ${CMAKE_CURRENT_SOURCE_DIR}/../examples/Inp_SmallDirSolidification.json 8 | ${CMAKE_CURRENT_BINARY_DIR}/Inp_SmallDirSolidification.json COPYONLY) 9 | configure_file( 10 | ${CMAKE_CURRENT_SOURCE_DIR}/../examples/Inp_DirSolidification.json 11 | ${CMAKE_CURRENT_BINARY_DIR}/Inp_DirSolidification.json COPYONLY) 12 | configure_file( 13 | ${CMAKE_CURRENT_SOURCE_DIR}/../examples/Inp_TwoGrainDirSolidification.json 14 | ${CMAKE_CURRENT_BINARY_DIR}/Inp_TwoGrainDirSolidification.json COPYONLY) 15 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../examples/Inp_SpotMelt.json 16 | ${CMAKE_CURRENT_BINARY_DIR}/Inp_SpotMelt.json COPYONLY) 17 | configure_file( 18 | ${CMAKE_CURRENT_SOURCE_DIR}/../examples/Inp_SpotMelt.json 19 | ${CMAKE_CURRENT_BINARY_DIR}/Inp_SmallSpotMelt_Steel2phase.json COPYONLY) 20 | 21 | configure_file( 22 | ${CMAKE_CURRENT_SOURCE_DIR}/../examples/Inp_SmallEquiaxedGrain.json 23 | ${CMAKE_CURRENT_BINARY_DIR}/Inp_SmallEquiaxedGrain.json COPYONLY) 24 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../examples/Materials/Inconel625.json 25 | ${CMAKE_CURRENT_BINARY_DIR}/Inconel625.json COPYONLY) 26 | configure_file( 27 | ${CMAKE_CURRENT_SOURCE_DIR}/../examples/Materials/Inconel625_Quadratic.json 28 | ${CMAKE_CURRENT_BINARY_DIR}/Inconel625_Quadratic.json COPYONLY) 29 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../examples/Materials/SS316.json 30 | ${CMAKE_CURRENT_BINARY_DIR}/SS316.json COPYONLY) 31 | configure_file( 32 | ${CMAKE_CURRENT_SOURCE_DIR}/../examples/Materials/SS316L_AusteniteFerrite.json 33 | ${CMAKE_CURRENT_BINARY_DIR}/SS316L_AusteniteFerrite.json COPYONLY) 34 | 35 | exaca_add_tests( 36 | PACKAGE 37 | ExaCA-Core 38 | NAMES 39 | InterfacialResponse 40 | Inputs 41 | Orientation 42 | Parse 43 | Print) 44 | 45 | exaca_add_tests( 46 | MPI 47 | PACKAGE 48 | ExaCA-Core 49 | NAMES 50 | CellData 51 | Grid 52 | Interface 53 | Nucleation 54 | Temperature 55 | Update) 56 | -------------------------------------------------------------------------------- /bin/run.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #include "ExaCA.hpp" 7 | 8 | #include 9 | 10 | #include "mpi.h" 11 | 12 | #include 13 | #include 14 | 15 | int main(int argc, char *argv[]) { 16 | // Initialize MPI 17 | int id, np; 18 | MPI_Init(&argc, &argv); 19 | // Initialize Kokkos 20 | Kokkos::initialize(argc, argv); 21 | { 22 | using memory_space = Kokkos::DefaultExecutionSpace::memory_space; 23 | 24 | // Get number of processes 25 | MPI_Comm_size(MPI_COMM_WORLD, &np); 26 | // Get individual process ID 27 | MPI_Comm_rank(MPI_COMM_WORLD, &id); 28 | 29 | if (id == 0) { 30 | std::cout << "ExaCA version: " << version() << " \nExaCA commit: " << gitCommitHash() 31 | << "\nKokkos version: " << kokkosVersion() << std::endl; 32 | Kokkos::DefaultExecutionSpace().print_configuration(std::cout); 33 | std::cout << "Number of MPI ranks = " << np << std::endl; 34 | } 35 | if (argc < 2) { 36 | throw std::runtime_error("Error: Must provide path to input file on the command line."); 37 | } 38 | else { 39 | 40 | // Create timers 41 | Timers timers(id); 42 | timers.startInit(); 43 | 44 | // Run CA code using reduced temperature data format 45 | std::string input_file = argv[1]; 46 | // Read input file 47 | Inputs inputs(id, input_file); 48 | 49 | // Setup local and global grids, decomposing domain (needed to construct temperature) 50 | Grid grid(inputs.simulation_type, id, np, inputs.domain.number_of_layers, inputs.domain, inputs.substrate, 51 | inputs.temperature); 52 | // Temperature fields characterized by data in this structure 53 | Temperature temperature(grid, inputs.temperature, inputs.print.store_solidification_start); 54 | 55 | runExaCA(id, np, inputs, timers, grid, temperature); 56 | } 57 | } 58 | // Finalize Kokkos 59 | Kokkos::finalize(); 60 | // Finalize MPI 61 | MPI_Finalize(); 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /unit_test/test_harness.cmake: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------## 2 | # Create main tests (all tests use Kokkos) 3 | # --------------------------------------------------------------------------## 4 | macro(ExaCA_add_tests) 5 | cmake_parse_arguments(EXACA_UNIT_TEST "MPI" "PACKAGE" "NAMES" ${ARGN}) 6 | set(EXACA_UNIT_TEST_MPIEXEC_NUMPROCS 1) 7 | if(EXACA_UNIT_TEST_MPI) 8 | # Most tests written to work with at most 4 ranks. 9 | foreach(_np 2 4) 10 | if(MPIEXEC_MAX_NUMPROCS GREATER_EQUAL ${_np}) 11 | list(APPEND EXACA_UNIT_TEST_MPIEXEC_NUMPROCS ${_np}) 12 | endif() 13 | endforeach() 14 | endif() 15 | set(EXACA_UNIT_TEST_NUMTHREADS 1) 16 | foreach(_nt 2 4) 17 | if(MPIEXEC_MAX_NUMPROCS GREATER_EQUAL ${_nt}) 18 | list(APPEND EXACA_UNIT_TEST_NUMTHREADS ${_nt}) 19 | endif() 20 | endforeach() 21 | set(EXACA_UNIT_TEST_MAIN ${TEST_HARNESS_DIR}/unit_test_main.cpp) 22 | foreach(_device ${EXACA_TEST_DEVICES}) 23 | set(_dir ${CMAKE_CURRENT_BINARY_DIR}/${_device}) 24 | file(MAKE_DIRECTORY ${_dir}) 25 | foreach(_test ${EXACA_UNIT_TEST_NAMES}) 26 | set(_file ${_dir}/tst${_test}_${_device}.cpp) 27 | file(WRITE ${_file} "#include \n" 28 | "#include \n") 29 | set(_target ExaCA_${_test}_test_${_device}) 30 | add_executable(${_target} ${_file} ${EXACA_UNIT_TEST_MAIN}) 31 | target_include_directories(${_target} PRIVATE ${_dir} ${TEST_HARNESS_DIR} 32 | ${CMAKE_CURRENT_SOURCE_DIR}) 33 | target_link_libraries(${_target} ${EXACA_UNIT_TEST_PACKAGE} 34 | ${gtest_target}) 35 | 36 | foreach(_np ${EXACA_UNIT_TEST_MPIEXEC_NUMPROCS}) 37 | if(_device STREQUAL THREADS OR _device STREQUAL OPENMP) 38 | foreach(_thread ${EXACA_UNIT_TEST_NUMTHREADS}) 39 | add_test( 40 | NAME ${_target}_np_${_np}_nt_${_thread} 41 | COMMAND 42 | ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${_np} 43 | ${MPIEXEC_PREFLAGS} $ 44 | ${MPIEXEC_POSTFLAGS} ${gtest_args} --kokkos-threads=${_thread}) 45 | endforeach() 46 | else() 47 | add_test( 48 | NAME ${_target}_np_${_np} 49 | COMMAND 50 | ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${_np} 51 | ${MPIEXEC_PREFLAGS} $ 52 | ${MPIEXEC_POSTFLAGS} ${gtest_args}) 53 | endif() 54 | endforeach() 55 | endforeach() 56 | endforeach() 57 | endmacro() 58 | -------------------------------------------------------------------------------- /PUBLICATIONS.bib: -------------------------------------------------------------------------------- 1 | @article{rolchigo2024, 2 | title={Grain structure and texture selection regimes in metal powder bed fusion}, 3 | author={Rolchigo, Matt and Coleman, John and Knapp, Gerry L and Plotkowski, Alex}, 4 | journal={Additive Manufacturing}, 5 | doi={10.1016/j.addma.2024.104024}, 6 | pages={104024}, 7 | year={2024}, 8 | publisher={Elsevier} 9 | } 10 | 11 | @inproceedings{carson2023, 12 | title={Uncertainty Quantification of Metal Additive Manufacturing Processing Conditions Through the use of Exascale Computing}, 13 | author={Carson, Robert and Rolchigo, Matt and Coleman, John and Titov, Mikhail and Belak, Jim and Bement, Matt}, 14 | booktitle={Proceedings of the SC'23 Workshops of The International Conference on High Performance Computing, Network, Storage, and Analysis}, 15 | doi={10.1145/3624062.3624103}, 16 | pages={380--383}, 17 | year={2023} 18 | } 19 | 20 | @article{knapp2023, 21 | title={Calibrating uncertain parameters in melt pool simulations of additive manufacturing}, 22 | author={Knapp, Gerry L and Coleman, John and Rolchigo, Matt and Stoyanov, Miroslav and Plotkowski, Alex}, 23 | journal={Computational Materials Science}, 24 | doi={10.1016/j.commatsci.2022.111904}, 25 | volume={218}, 26 | pages={111904}, 27 | year={2023}, 28 | publisher={Elsevier} 29 | } 30 | 31 | @inproceedings{wells2023, 32 | title={Uncertainty quantification for computational modelling of laser powder bed fusion}, 33 | author={Wells, Scott and Plotkowski, Alex and Coleman, John and Rolchigo, Matt and Carson, Robert and Krane, MJM}, 34 | booktitle={IOP Conference Series: Materials Science and Engineering}, 35 | doi={10.1088/1757-899X/1281/1/012024}, 36 | volume={1281}, 37 | number={1}, 38 | pages={012024}, 39 | year={2023}, 40 | organization={IOP Publishing} 41 | } 42 | 43 | @article{rolchigo2022, 44 | title={Understanding uncertainty in microstructure evolution and constitutive properties in additive process modeling}, 45 | author={Rolchigo, Matthew and Carson, Robert and Belak, James}, 46 | journal={Metals}, 47 | doi={10.3390/met12020324}, 48 | volume={12}, 49 | number={2}, 50 | pages={324}, 51 | year={2022}, 52 | publisher={MDPI} 53 | } 54 | 55 | @article{turner2022, 56 | title={ExaAM: Metal additive manufacturing simulation at the fidelity of the microstructure}, 57 | author={Turner, John A and Belak, James and Barton, Nathan and Bement, Matthew and Carlson, Neil and Carson, Robert and DeWitt, Stephen and Fattebert, Jean-Luc and Hodge, Neil and Jibben, Zechariah and others}, 58 | journal={The International Journal of High Performance Computing Applications}, 59 | doi={10.1177/10943420211042558}, 60 | volume={36}, 61 | number={1}, 62 | pages={13--39}, 63 | year={2022}, 64 | publisher={SAGE Publications Sage UK: London, England} 65 | } 66 | 67 | # Method development preceding ExaCA 68 | 69 | @article{rolchigo2020, 70 | author = {Matthew Rolchigo and Benjamin Stump and James Belak and Alex Plotkowski}, 71 | title = {Sparse thermal data for cellular automata modeling of grain structure in additive manufacturing}, 72 | journal = {Modelling and Simulation in Materials Science and Engineering}, 73 | doi = {10.1088/1361-651X/ab9734}, 74 | year = {2020}, 75 | month = {jun}, 76 | publisher = {IOP Publishing}, 77 | volume = {28}, 78 | number = {6}, 79 | pages = {065003}, 80 | } 81 | -------------------------------------------------------------------------------- /unit_test/tstParse.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #include 7 | 8 | #include "CAconfig.hpp" 9 | #include "CAparsefiles.hpp" 10 | #include "CAprint.hpp" 11 | 12 | #include 13 | 14 | #include "mpi.h" 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | namespace Test { 21 | //---------------------------------------------------------------------------// 22 | // file_read_tests 23 | //---------------------------------------------------------------------------// 24 | void testReadWrite(bool print_read_binary) { 25 | 26 | // Make lists of some int and float data 27 | int int_data[5] = {-2, 0, 2, 4, 6}; 28 | float float_data[5] = {-1.0, 0.0, 1.0, 2.0, 3.0}; 29 | 30 | // Write data as binary to be used as input 31 | std::ofstream test_int_data; 32 | std::ofstream test_float_data; 33 | if (print_read_binary) { 34 | test_int_data.open("TestIntData.txt", std::ios::out | std::ios::binary); 35 | test_float_data.open("TestFloatData.txt", std::ios::out | std::ios::binary); 36 | } 37 | else { 38 | test_int_data.open("TestIntData.txt"); 39 | test_float_data.open("TestFloatData.txt"); 40 | } 41 | for (int n = 0; n < 5; n++) { 42 | // Write to files 43 | writeData(test_int_data, int_data[n], print_read_binary, true); 44 | writeData(test_float_data, float_data[n], print_read_binary, true); 45 | } 46 | test_int_data.close(); 47 | test_float_data.close(); 48 | 49 | // Read data and convert back to ints and floats, compare to original values 50 | std::ifstream test_int_data_read; 51 | test_int_data_read.open("TestIntData.txt"); 52 | std::ifstream test_float_data_read; 53 | test_float_data_read.open("TestFloatData.txt"); 54 | // For reading ASCII data, obtain the lines from the files first, then parse the string stream at the spaces 55 | if (print_read_binary) { 56 | for (int n = 0; n < 5; n++) { 57 | int int_to_compare = readBinaryData(test_int_data_read, true); 58 | float float_to_compare = readBinaryData(test_float_data_read, true); 59 | // Compare to expected values 60 | EXPECT_EQ(int_to_compare, int_data[n]); 61 | EXPECT_FLOAT_EQ(float_to_compare, float_data[n]); 62 | } 63 | } 64 | else { 65 | std::string intline, floatline; 66 | getline(test_int_data_read, intline); 67 | getline(test_float_data_read, floatline); 68 | std::istringstream intss(intline); 69 | std::istringstream floatss(floatline); 70 | for (int n = 0; n < 5; n++) { 71 | // Get values from string stream 72 | int int_to_compare = parseASCIIData(intss); 73 | float float_to_compare = parseASCIIData(floatss); 74 | // Compare to expected values 75 | EXPECT_EQ(int_to_compare, int_data[n]); 76 | EXPECT_FLOAT_EQ(float_to_compare, float_data[n]); 77 | } 78 | } 79 | } 80 | //---------------------------------------------------------------------------// 81 | // RUN TESTS 82 | //---------------------------------------------------------------------------// 83 | TEST(TEST_CATEGORY, parse) { 84 | // test functions for reading and writing data as binary (true) and ASCII (false) 85 | testReadWrite(true); 86 | testReadWrite(false); 87 | } 88 | } // end namespace Test 89 | -------------------------------------------------------------------------------- /unit_test/tstPrint.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #include 7 | 8 | #include "CAgrid.hpp" 9 | #include "CAinputs.hpp" 10 | #include "CAprint.hpp" 11 | 12 | #include "mpi.h" 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | namespace Test { 21 | //---------------------------------------------------------------------------// 22 | void testPrintExaConstitDefaultRVE() { 23 | 24 | // Create test grid - set up so that the RVE is 5 cells in X, Y, and Z 25 | int number_of_layers_temp = 10; 26 | Grid grid(number_of_layers_temp); 27 | grid.nx = 10; 28 | grid.ny = 10; 29 | grid.ny_local = 10; 30 | grid.y_offset = 0; 31 | grid.nz = 10; 32 | grid.deltax = 0.0001; // in meters 33 | 34 | // default inputs struct - manually set non-default substrateInputs values 35 | Inputs inputs; 36 | inputs.print.print_default_rve = true; 37 | inputs.print.rve_size = Kokkos::round(0.0005 / grid.deltax); 38 | // File name/path for test RVE output 39 | inputs.print.base_filename = "TestRVE"; 40 | // Initialize printing struct from inputs 41 | Print print(grid, 1, inputs.print); 42 | 43 | // Check that inputs in print struct match the initialization from inputs 44 | EXPECT_TRUE(print._inputs.print_default_rve); 45 | EXPECT_EQ(inputs.print.rve_size, print._inputs.rve_size); 46 | EXPECT_EQ(inputs.print.base_filename, print._inputs.base_filename); 47 | 48 | // Create test data 49 | Kokkos::View grain_id_whole_domain( 50 | Kokkos::ViewAllocateWithoutInitializing("GrainID_WholeDomain"), grid.nz, grid.nx, grid.ny); 51 | Kokkos::View layer_id_whole_domain( 52 | Kokkos::ViewAllocateWithoutInitializing("LayerID_WholeDomain"), grid.nz, grid.nx, grid.ny); 53 | for (int k = 0; k < grid.nz; k++) { 54 | for (int j = 0; j < grid.ny; j++) { 55 | for (int i = 0; i < grid.nx; i++) { 56 | layer_id_whole_domain(k, i, j) = k; 57 | grain_id_whole_domain(k, i, j) = i + j; 58 | } 59 | } 60 | } 61 | 62 | // Print RVE 63 | print.printExaConstitDefaultRVE(grid, layer_id_whole_domain, grain_id_whole_domain); 64 | 65 | // Check printed RVE 66 | std::ifstream grainplot_e; 67 | std::string expected_filename = "TestRVE_ExaConstit.csv"; 68 | grainplot_e.open(expected_filename); 69 | std::string line; 70 | std::getline(grainplot_e, line); 71 | EXPECT_TRUE(line == "Coordinates are in CA units, 1 cell = 0.0001 m. Data is cell-centered. Origin at 3,3,4 , " 72 | "domain size is 5 by 5 by 5 cells"); 73 | std::getline(grainplot_e, line); 74 | EXPECT_TRUE(line == "X coord, Y coord, Z coord, Grain ID"); 75 | for (int k = 4; k < 9; k++) { 76 | for (int j = 3; j < 8; j++) { 77 | for (int i = 3; i < 8; i++) { 78 | std::string ExpectedLine = 79 | std::to_string(i) + "," + std::to_string(j) + "," + std::to_string(k) + "," + std::to_string(i + j); 80 | std::getline(grainplot_e, line); 81 | EXPECT_TRUE(line == ExpectedLine); 82 | } 83 | } 84 | } 85 | grainplot_e.close(); 86 | } 87 | 88 | //---------------------------------------------------------------------------// 89 | // RUN TESTS 90 | //---------------------------------------------------------------------------// 91 | TEST(TEST_CATEGORY, print_test) { testPrintExaConstitDefaultRVE(); } 92 | 93 | } // end namespace Test 94 | -------------------------------------------------------------------------------- /utilities/TASMANIAN/TasmanianTest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # Command line inputs are the list of temperature files associated with the ensemble of simulations 4 | # See top level README for more details regarding these inputs 5 | # Generate input files for ExaCA using a level 3 tasmanian sparse grid and 3 ExaCA 6 | # input variables: heterogeneous nucleation density, mean substrate grain size, 7 | # and mean nucleation undercooling 8 | import Tasmanian 9 | import sys 10 | 11 | # Generate Tasmanian grid 12 | grid = Tasmanian.SparseGrid() 13 | grid.makeLocalPolynomialGrid(3, 3, 3, 1, 'localp') 14 | points = grid.getPoints() 15 | 16 | # Min, max nucleation density (N0Min * 10^12 /m^3 and N0Max * 10^12 /m^3) 17 | N0Min = 100 # 10^14 18 | N0Max = 10000 # 10^16 19 | N0Mean = 0.5 * (N0Min + N0Max) 20 | N0Dev = N0Mean - N0Min 21 | 22 | # Min, max mean nucleation undercooling (dTNMin and dTNMax, in K relative to 23 | # the alloy liquidus temperature) 24 | dTNMin = 5 25 | dTNMax = 65 26 | dTNMean = 0.5 * (dTNMin + dTNMax) 27 | dTNDev = dTNMean - dTNMin 28 | 29 | # Min, max substrate grain size (S0Min and S0Max, in microns) 30 | S0Min = 2.5 31 | S0Max = 25 32 | S0Mean = 0.5 * (S0Min + S0Max) 33 | S0Dev = S0Mean - S0Min 34 | 35 | # Check number of command line arguments given: should be at least 2 36 | NumCommandLineArgs = len(sys.argv); 37 | if (NumCommandLineArgs == 1): 38 | print('Error: At least one temperature data file associated with these simulations is required') 39 | sys.exit(1) 40 | 41 | # Get list of temperature files from the command line 42 | TemperatureFiles = "[" 43 | for tfile in range(1, NumCommandLineArgs): 44 | TemperatureFiles += "\"" + str(sys.argv[tfile]) + "\""; 45 | if (tfile == NumCommandLineArgs-1): 46 | TemperatureFiles += "]"; 47 | else: 48 | TemperatureFiles += ","; 49 | 50 | # Write ExaCA input files to the examples subdirectory 51 | for filenumber in range(1, 70): 52 | # Heterogeneous nucleation density for this ensemble member 53 | N0ThisMember = N0Mean + N0Dev * points[filenumber-1,0] 54 | # Mean nucleation undercooling for this ensemble member 55 | dTNThisMember = dTNMean + dTNDev * points[filenumber-1,1] 56 | # Substrate grain spacing for this ensemble member 57 | S0ThisMember = S0Mean + S0Dev * points[filenumber-1,2] 58 | 59 | # Write to example file number "filenumber" 60 | filename = 'examples/Inp_TasmanianTest_' + str(filenumber) + '.json' 61 | with open(filename, "w") as f: 62 | OutputData = ['{ \n', 63 | ' "SimulationType": "RM",\n', 64 | ' "MaterialFileName": "Inconel625.json",\n', 65 | ' "GrainOrientationFile": "GrainOrientationVectors.csv",\n', 66 | ' "RandomSeed": 0.0, \n', 67 | ' "Domain": { \n', 68 | ' "CellSize": 2.5, \n', 69 | ' "TimeStep": 0.125, \n', 70 | ' "NumberOfLayers": 56, \n', 71 | ' "LayerOffset": 8 \n', 72 | ' }, \n', 73 | ' "Nucleation": { \n', 74 | ' "Density": ' + str(N0ThisMember) + ',\n', 75 | ' "MeanUndercooling": ' + str(dTNThisMember) + ',\n', 76 | ' "StDev": 0.5 \n' 77 | ' }, \n', 78 | ' "TemperatureData": { \n', 79 | ' "TemperatureFiles\": ' + TemperatureFiles + '\n' 80 | ' }, \n', 81 | ' "Substrate": { \n', 82 | ' "MeanSize": ' + str(S0ThisMember) + ',\n', 83 | ' "PowderDensity": 0 \n' 84 | ' }, \n', 85 | ' "Printing": { \n', 86 | ' "PathToOutput": ./\n', 87 | ' "OutputFile": "TasmanianTest_' + str(filenumber) + '",\n', 88 | ' "PrintBinary": true,\n', 89 | ' "PrintFieldsInit": [],\n', 90 | ' "PrintFieldsFinal": ["GrainID", "LayerID", "GrainMisorientation"] \n', 91 | ' } \n', 92 | '}'] 93 | f.writelines(OutputData) 94 | -------------------------------------------------------------------------------- /utilities/MTEX/ColorMap4.m: -------------------------------------------------------------------------------- 1 | % Copyright Lawrence Livermore National Security, LLC, and other ExaCA Project Developers. 2 | % See the top-level LICENSE file for details. 3 | % 4 | % SPDX-License-Identifier: MIT 5 | % 6 | % NIST-developed software is provided by NIST as a public service. You may use, copy, and distribute copies of the software in any medium, provided that you keep intact this entire notice. You may improve, modify, and create derivative works of the software or any portion of the software, and you may copy and distribute such modifications or works. Modified works should carry a notice stating that you changed the software and should note the date and nature of any such change. Please explicitly acknowledge the National Institute of Standards and Technology as the source of the software. 7 | 8 | % NIST-developed software is expressly provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED, IN FACT, OR ARISING BY OPERATION OF LAW, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND DATA ACCURACY. NIST NEITHER REPRESENTS NOR WARRANTS THAT THE OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT ANY DEFECTS WILL BE CORRECTED. NIST DOES NOT WARRANT OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF THE SOFTWARE OR THE RESULTS THEREOF, INCLUDING BUT NOT LIMITED TO THE CORRECTNESS, ACCURACY, RELIABILITY, OR USEFULNESS OF THE SOFTWARE. 9 | 10 | % You are solely responsible for determining the appropriateness of using and distributing the software and you assume all risks associated with its use, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and the unavailability or interruption of operation. This software is not intended to be used in any situation where a failure could cause risk of injury or damage to property. The software developed by NIST employees is not subject to copyright protection within the United States. 11 | % 12 | % 13 | % Mtex color maps 14 | % Colormap developed by Adam Creuziger (NIST) 15 | % Creates color map with a consistent range for comparison between data sets 16 | % and publications. Developed to distinguish between values less than 1 17 | % (grayscale) and values greater than 1 (color), as a value=1 is equal 18 | % to random (uniform) texture intensity. 19 | % Color range for colormap8.m extends the colormap4.m and are identical in the 20 | % range of 0 to 4. 21 | 22 | % Needed to produce test ODF 23 | %clc 24 | %clear 25 | %close all 26 | %% set colomap with grayscale 0 to 1, colors to 1 to 4 MUD 27 | mtexColorMap([0 0 0; .1 .1 .1 ;.2 .2 .2;.3 .3 .3; .4 .4 .4 ; .5 .5 .5; .6 .6 .6; .7 .7 .7; .8 .8 .8; .9 .9 .9; 0 0 1 ; 0 .1 .9; 0 .2 .8; 0 .3 .7; 0 .4 .6; 0 .5 .5; 0 .6 .4; 0 .7 .3; 0 .8 .2; 0 .9 .1; 0 1 0 ; .1 1 0; .2 1 0; .3 1 0; .4 1 0; .5 1 0; .6 1 0; .7 1 0; .8 1 0; .9 1 0; 1 1 0 ; 1 .9 0; 1 .8 0 ; 1 .7 0; 1 .6 0; 1 .5 0; 1 .4 0; 1 .3 0; 1 .2 0; 1 .1 0; 1 0 0 ]) 28 | cmap = colormap; 29 | setMTEXpref('defaultColorMap',cmap); 30 | setMTEXpref('FontSize',20); 31 | %% create an ODF to view or check the colormap 32 | %{ 33 | savepath='.'; 34 | 35 | HW=20*degree; 36 | 37 | cs = crystalSymmetry('m-3m'); 38 | ss = specimenSymmetry('orthorhombic'); 39 | Cube = orientation('Miller',[0 0 1],[1 0 0],cs,ss); 40 | odf = unimodalODF(Cube,'halfwidth',HW,cs,ss); 41 | figure; plot(odf,'phi2',[45]*degree,'projection','plain','minmax', 'off',cs,ss);CLim(gcm,[0, 4]);mtexColorbar; 42 | export_fig(strcat(savepath,'/','ColorMapExample-phi2-45ODF.tiff'),'-r300') 43 | %export_fig(strcat('ColorMapExample-phi2-45ODF.tiff'),'-r300') 44 | %} 45 | 46 | %% reset to default Mtex colomaps 47 | %setMTEXpref('defaultColorMap',WhiteJetColorpMap); 48 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | project(ExaCA LANGUAGES CXX) 4 | set(PROJECT_VERSION "2.2.0-dev") 5 | 6 | include(GNUInstallDirs) 7 | 8 | option(ExaCA_REQUIRE_FINCH "Build with Finch heat transport support" OFF) 9 | # Build with Finch if available or if requested. 10 | find_package(Finch QUIET) 11 | if(ExaCA_REQUIRE_FINCH OR Finch_FOUND) 12 | set(ExaCA_ENABLE_FINCH ON) 13 | find_package(Finch REQUIRED COMPONENTS Finch::Core Finch::ScanPaths) 14 | message(STATUS "Finch heat transfer enabled.") 15 | endif() 16 | 17 | find_package(Kokkos 4.0 REQUIRED) 18 | find_package(MPI REQUIRED) 19 | 20 | if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.24") 21 | cmake_policy(SET CMP0135 NEW) 22 | endif() 23 | option(ExaCA_REQUIRE_EXTERNAL_JSON 24 | "Build without automatic JSON dependency download" OFF) 25 | if(ExaCA_REQUIRE_EXTERNAL_JSON) 26 | find_package(nlohmann_json 3.10.0 REQUIRED) 27 | else() 28 | find_package(nlohmann_json 3.10.0 QUIET) 29 | if(NOT NLOHMANN_JSON_FOUND) 30 | include(FetchContent) 31 | # Using most recent release here 32 | FetchContent_Declare( 33 | json 34 | URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz 35 | ) 36 | FetchContent_MakeAvailable(json) 37 | # Needs to be installed only in this case. 38 | install( 39 | TARGETS nlohmann_json 40 | EXPORT ExaCA_Targets 41 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 42 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) 43 | endif() 44 | endif() 45 | 46 | find_package(Git) 47 | if(GIT_FOUND AND IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/.git) 48 | execute_process( 49 | COMMAND ${GIT_EXECUTABLE} log --pretty=format:%H -n 1 50 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 51 | OUTPUT_VARIABLE ExaCA_GIT_COMMIT_HASH) 52 | else() 53 | set(ExaCA_GIT_COMMIT_HASH "Not a git repository") 54 | endif() 55 | message(STATUS "ExaCA commit: ${ExaCA_GIT_COMMIT_HASH}") 56 | 57 | # NOTE: this order is specifically used in the unit tests. 58 | set(EXACA_SUPPORTED_DEVICES SERIAL THREADS OPENMP CUDA HIP) 59 | 60 | add_subdirectory(src) 61 | 62 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/ExaCAconfig.cmakein 63 | ${CMAKE_CURRENT_BINARY_DIR}/ExaCAconfig.cmake @ONLY) 64 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ExaCAconfig.cmake" 65 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ExaCA) 66 | 67 | # Install data files 68 | file(GLOB MATERIALS examples/Materials/*) 69 | file(GLOB SUBSTRATE examples/Substrate/GrainOrientation*.csv) 70 | install(FILES ${MATERIALS} 71 | DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/ExaCA) 72 | install(FILES ${SUBSTRATE} 73 | DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/ExaCA) 74 | 75 | option(ExaCA_ENABLE_TESTING "Build unit tests" OFF) 76 | 77 | if(ExaCA_ENABLE_TESTING) 78 | find_package(GTest 1.10 REQUIRED) 79 | # Workaround for FindGTest module in CMake older than 3.20 80 | if(TARGET GTest::gtest) 81 | set(gtest_target GTest::gtest) 82 | elseif(TARGET GTest::GTest) 83 | set(gtest_target GTest::GTest) 84 | else() 85 | message(FATAL_ERROR "bug in GTest find module workaround") 86 | endif() 87 | enable_testing() 88 | 89 | set(TEST_HARNESS_DIR ${CMAKE_SOURCE_DIR}/unit_test) 90 | set(EXACA_TEST_DEVICES) 91 | foreach(_device ${EXACA_SUPPORTED_DEVICES}) 92 | if(Kokkos_ENABLE_${_device}) 93 | list(APPEND EXACA_TEST_DEVICES ${_device}) 94 | endif() 95 | endforeach() 96 | 97 | add_subdirectory(unit_test) 98 | endif() 99 | 100 | add_subdirectory(bin) 101 | 102 | add_subdirectory(analysis) 103 | 104 | # clang-format 105 | set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 106 | find_package(CLANG_FORMAT 17) 107 | if(CLANG_FORMAT_FOUND) 108 | file(GLOB_RECURSE FORMAT_SOURCES *.[c,h]pp) 109 | add_custom_target( 110 | format 111 | COMMAND ${CLANG_FORMAT_EXECUTABLE} -i -style=file ${FORMAT_SOURCES} 112 | DEPENDS ${FORMAT_SOURCES}) 113 | endif() 114 | -------------------------------------------------------------------------------- /unit_test/tstUpdate.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #include 7 | #include 8 | 9 | #include "CAcelldata.hpp" 10 | #include "CAinputs.hpp" 11 | #include "CAinterface.hpp" 12 | #include "CAparsefiles.hpp" 13 | #include "CAtypes.hpp" 14 | #include "ExaCA.hpp" 15 | 16 | #include 17 | 18 | #include "mpi.h" 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace Test { 25 | 26 | //---------------------------------------------------------------------------// 27 | // full_simulations 28 | //---------------------------------------------------------------------------// 29 | void testSmallDirS() { 30 | 31 | using memory_space = TEST_MEMSPACE; 32 | int id, np; 33 | // Get number of processes 34 | MPI_Comm_size(MPI_COMM_WORLD, &np); 35 | // Get individual process ID 36 | MPI_Comm_rank(MPI_COMM_WORLD, &id); 37 | 38 | std::string input_file = "Inp_SmallDirSolidification.json"; 39 | Inputs inputs(id, input_file); 40 | Timers timers(id); 41 | 42 | // Setup local and global grids, decomposing domain (needed to construct temperature) 43 | Grid grid(inputs.simulation_type, id, np, inputs.domain.number_of_layers, inputs.domain, inputs.substrate, 44 | inputs.temperature); 45 | // Temperature fields characterized by data in this structure 46 | Temperature temperature(grid, inputs.temperature, inputs.print.store_solidification_start); 47 | 48 | // Run SmallDirS problem and check volume fraction of nucleated grains with 1% tolerance of expected value (to 49 | // account for the non-deterministic nature of the cell capture) 50 | runExaCA(id, np, inputs, timers, grid, temperature); 51 | 52 | // MPI barrier to ensure that log file has been written 53 | MPI_Barrier(MPI_COMM_WORLD); 54 | std::string log_file = "TestProblemSmallDirS.json"; 55 | std::ifstream log_data_stream(log_file); 56 | nlohmann::json log_data = nlohmann::json::parse(log_data_stream); 57 | float vol_fraction_nucleated = log_data["Nucleation"]["VolFractionNucleated"]; 58 | EXPECT_NEAR(vol_fraction_nucleated, 0.1882, 0.0100); 59 | } 60 | 61 | void testSmallEquiaxedGrain() { 62 | 63 | using memory_space = TEST_MEMSPACE; 64 | int id, np; 65 | // Get number of processes 66 | MPI_Comm_size(MPI_COMM_WORLD, &np); 67 | // Get individual process ID 68 | MPI_Comm_rank(MPI_COMM_WORLD, &id); 69 | 70 | std::string input_file = "Inp_SmallEquiaxedGrain.json"; 71 | Inputs inputs(id, input_file); 72 | Timers timers(id); 73 | 74 | // Setup local and global grids, decomposing domain (needed to construct temperature) 75 | Grid grid(inputs.simulation_type, id, np, inputs.domain.number_of_layers, inputs.domain, inputs.substrate, 76 | inputs.temperature); 77 | // Temperature fields characterized by data in this structure 78 | Temperature temperature(grid, inputs.temperature, inputs.print.store_solidification_start); 79 | 80 | // Run Small equiaxed grain problem and check time step at which the grain reaches the domain edge 81 | runExaCA(id, np, inputs, timers, grid, temperature); 82 | 83 | // MPI barrier to ensure that log file has been written 84 | MPI_Barrier(MPI_COMM_WORLD); 85 | std::string log_file = "TestProblemSmallEquiaxedGrain.json"; 86 | std::ifstream log_data_stream(log_file); 87 | nlohmann::json log_data = nlohmann::json::parse(log_data_stream); 88 | int time_step_of_output = log_data["TimeStepOfOutput"]; 89 | // FIXME: Output time step is usually 4820, but may be 4821 - need to investigate this possible race condition 90 | EXPECT_NEAR(time_step_of_output, 4820, 1); 91 | } 92 | //---------------------------------------------------------------------------// 93 | // RUN TESTS 94 | //---------------------------------------------------------------------------// 95 | TEST(TEST_CATEGORY, full_simulations) { 96 | testSmallDirS(); 97 | testSmallEquiaxedGrain(); 98 | } 99 | } // end namespace Test 100 | -------------------------------------------------------------------------------- /utilities/MTEX/ColorMap8.m: -------------------------------------------------------------------------------- 1 | % Copyright Lawrence Livermore National Security, LLC, and other ExaCA Project Developers. 2 | % See the top-level LICENSE file for details. 3 | % 4 | % SPDX-License-Identifier: MIT 5 | % 6 | % NIST-developed software is provided by NIST as a public service. You may use, copy, and distribute copies of the software in any medium, provided that you keep intact this entire notice. You may improve, modify, and create derivative works of the software or any portion of the software, and you may copy and distribute such modifications or works. Modified works should carry a notice stating that you changed the software and should note the date and nature of any such change. Please explicitly acknowledge the National Institute of Standards and Technology as the source of the software. 7 | 8 | % NIST-developed software is expressly provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED, IN FACT, OR ARISING BY OPERATION OF LAW, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND DATA ACCURACY. NIST NEITHER REPRESENTS NOR WARRANTS THAT THE OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT ANY DEFECTS WILL BE CORRECTED. NIST DOES NOT WARRANT OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF THE SOFTWARE OR THE RESULTS THEREOF, INCLUDING BUT NOT LIMITED TO THE CORRECTNESS, ACCURACY, RELIABILITY, OR USEFULNESS OF THE SOFTWARE. 9 | 10 | % You are solely responsible for determining the appropriateness of using and distributing the software and you assume all risks associated with its use, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and the unavailability or interruption of operation. This software is not intended to be used in any situation where a failure could cause risk of injury or damage to property. The software developed by NIST employees is not subject to copyright protection within the United States. 11 | % 12 | % 13 | % Mtex color maps 14 | % Colormap developed by Adam Creuziger (NIST) 15 | % Creates color map with a consistent range for comparison between data sets 16 | % and publications. Developed to distinguish between values less than 1 17 | % (grayscale) and values greater than 1 (color), as a value=1 is equal 18 | % to random (uniform) texture intensity. 19 | % Color range for colormap8.m extends the colormap4.m and are identical in the 20 | % range of 0 to 4. 21 | 22 | % Needed to produce test ODF 23 | %clc 24 | %clear 25 | %close all 26 | %% set colomap with grayscale 0 to 1, colors to 1 to 8 MUD 27 | mtexColorMap([0 0 0; .1 .1 .1 ;.2 .2 .2;.3 .3 .3; .4 .4 .4 ; .5 .5 .5; .6 .6 .6; .7 .7 .7; .8 .8 .8; .9 .9 .9; 0 0 1 ;... 28 | 0 .1 .9; 0 .2 .8; 0 .3 .7; 0 .4 .6; 0 .5 .5; 0 .6 .4; 0 .7 .3; 0 .8 .2; 0 .9 .1; 0 1 0 ;... 29 | .1 1 0; .2 1 0; .3 1 0; .4 1 0; .5 1 0; .6 1 0; .7 1 0; .8 1 0; .9 1 0; 1 1 0 ;... 30 | 1 .9 0; 1 .8 0 ; 1 .7 0; 1 .6 0; 1 .5 0; 1 .4 0; 1 .3 0; 1 .2 0; 1 .1 0; 1 0 0;... 31 | 1 0 .025; 1 0 .05; 1 0 .075; 1 0 .1; 1 0 .125; 1 0 .15; 1 0 .175; 1 0 .2; 1 0 .225; 1 0 .25;... 32 | 1 0 .275; 1 0 .30; 1 0 .325; 1 0 .35; 1 0 .375; 1 0 .4; 1 0 .425; 1 0 .45; 1 0 .475; 1 0 .5;... 33 | 1 0 .525; 1 0 .55; 1 0 .575; 1 0 .60; 1 0 .625; 1 0 .65; 1 0 .675; 1 0 .70; 1 0 .725; 1 0 .75;... 34 | 1 0 .775; 1 0 .80; 1 0 .825; 1 0 .85; 1 0 .875; 1 0 .90; 1 0 .925; 1 0 .95; 1 0 .975; 1 0 1 ]) 35 | cmap = colormap; 36 | setMTEXpref('defaultColorMap',cmap); 37 | setMTEXpref('FontSize',20); 38 | %% create an ODF to view or check the colormap 39 | %{ 40 | savepath='.'; 41 | 42 | HW=20*degree; 43 | 44 | cs = crystalSymmetry('m-3m'); 45 | ss = specimenSymmetry('orthorhombic'); 46 | Cube = orientation('Miller',[0 0 1],[1 0 0],cs,ss); 47 | odf = unimodalODF(Cube,'halfwidth',HW,cs,ss); 48 | figure; plot(odf,'phi2',[45]*degree,'projection','plain','minmax', 'off',cs,ss);CLim(gcm,[0, 4]);mtexColorbar; 49 | export_fig(strcat(savepath,'/','ColorMapExample-phi2-45ODF.tiff'),'-r150') 50 | 51 | %} 52 | %% reset to default Mtex colomaps 53 | %setMTEXpref('defaultColorMap',WhiteJetColorpMap); 54 | -------------------------------------------------------------------------------- /bin/runCoupled.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #include "ExaCA.hpp" 7 | #include "Finch_Core.hpp" 8 | 9 | #include 10 | 11 | #include "mpi.h" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | void runCoupled(int id, int np, Finch::Inputs finch_inputs, Inputs exaca_inputs) { 18 | // Set up Finch 19 | using exec_space = Kokkos::DefaultExecutionSpace; 20 | using memory_space = exec_space::memory_space; 21 | 22 | // Create timers 23 | Timers timers(id); 24 | timers.startHeatTransfer(); 25 | 26 | // initialize a moving beam 27 | Finch::MovingBeam beam(finch_inputs.source.scan_path_file); 28 | 29 | // Define boundary condition details. 30 | std::array bc_types = {"adiabatic", "adiabatic", "adiabatic", 31 | "adiabatic", "adiabatic", "adiabatic"}; 32 | 33 | // create the global mesh 34 | Finch::Grid finch_grid(MPI_COMM_WORLD, finch_inputs.space.cell_size, 35 | finch_inputs.space.global_low_corner, finch_inputs.space.global_high_corner, 36 | finch_inputs.space.ranks_per_dim, bc_types, 37 | finch_inputs.space.initial_temperature); 38 | 39 | // Run Finch heat transfer 40 | Finch::Layer app(finch_inputs, finch_grid); 41 | auto fd = Finch::createSolver(finch_inputs, finch_grid); 42 | app.run(exec_space(), finch_inputs, finch_grid, beam, fd); 43 | 44 | // Start of ExaCA init time. 45 | timers.stopHeatTransfer(); 46 | timers.startInit(); 47 | 48 | // Setup local and global grids, decomposing domain (needed to construct temperature) 49 | // ExaCA either uses the same bounds as Finch, or a bounding box that only includes the regions that underwent 50 | // melting and solidification 51 | std::array exaca_low_corner, exaca_high_corner; 52 | if (exaca_inputs.temperature.trim_unmelted_region) { 53 | exaca_low_corner = app.getLowerSolidificationDataBounds(MPI_COMM_WORLD); 54 | exaca_high_corner = app.getUpperSolidificationDataBounds(MPI_COMM_WORLD); 55 | } 56 | else { 57 | exaca_low_corner = finch_inputs.space.global_low_corner; 58 | exaca_high_corner = finch_inputs.space.global_high_corner; 59 | } 60 | Grid exaca_grid(id, np, exaca_inputs.domain, exaca_inputs.substrate, exaca_inputs.temperature, 61 | finch_inputs.space.cell_size, exaca_low_corner, exaca_high_corner); 62 | // Temperature fields characterized by data in this structure 63 | Temperature temperature(id, np, exaca_grid, exaca_inputs.temperature, app.getSolidificationData(), 64 | exaca_inputs.print.store_solidification_start); 65 | 66 | // Now run ExaCA 67 | runExaCA(id, np, exaca_inputs, timers, exaca_grid, temperature); 68 | } 69 | 70 | int main(int argc, char *argv[]) { 71 | // Initialize Kokkos & MPI 72 | int id, np; 73 | MPI_Init(&argc, &argv); 74 | Kokkos::initialize(argc, argv); 75 | { 76 | // Get number of processes 77 | MPI_Comm_size(MPI_COMM_WORLD, &np); 78 | // Get individual process ID 79 | MPI_Comm_rank(MPI_COMM_WORLD, &id); 80 | 81 | if (id == 0) { 82 | std::cout << "ExaCA version: " << version() << " \nExaCA commit: " << gitCommitHash() 83 | << "\nKokkos version: " << kokkosVersion() << std::endl; 84 | Kokkos::DefaultExecutionSpace().print_configuration(std::cout); 85 | std::cout << "Number of MPI ranks = " << np << std::endl; 86 | } 87 | if (argc < 3) { 88 | throw std::runtime_error("Error: Must provide path to Finch and ExaCA input files on the command line."); 89 | } 90 | else { 91 | std::string finch_input_file = argv[1]; 92 | std::string exaca_input_file = argv[2]; 93 | 94 | // Setup Finch simulation 95 | Finch::Inputs finch_inputs(MPI_COMM_WORLD, finch_input_file); 96 | 97 | // Setup ExaCA simulation details 98 | Inputs inputs(id, exaca_input_file); 99 | 100 | runCoupled(id, np, finch_inputs, inputs); 101 | } 102 | } 103 | 104 | // Finalize Kokkos & MPI 105 | Kokkos::finalize(); 106 | MPI_Finalize(); 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /utilities/MTEX/PlotPoleFigure.m: -------------------------------------------------------------------------------- 1 | % Copyright Lawrence Livermore National Security, LLC, and other ExaCA Project Developers. 2 | % See the top-level LICENSE file for details. 3 | % 4 | % SPDX-License-Identifier: MIT 5 | % 6 | % NIST-developed software is provided by NIST as a public service. You may use, copy, and distribute copies of the software in any medium, provided that you keep intact this entire notice. You may improve, modify, and create derivative works of the software or any portion of the software, and you may copy and distribute such modifications or works. Modified works should carry a notice stating that you changed the software and should note the date and nature of any such change. Please explicitly acknowledge the National Institute of Standards and Technology as the source of the software. 7 | 8 | % NIST-developed software is expressly provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED, IN FACT, OR ARISING BY OPERATION OF LAW, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND DATA ACCURACY. NIST NEITHER REPRESENTS NOR WARRANTS THAT THE OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT ANY DEFECTS WILL BE CORRECTED. NIST DOES NOT WARRANT OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF THE SOFTWARE OR THE RESULTS THEREOF, INCLUDING BUT NOT LIMITED TO THE CORRECTNESS, ACCURACY, RELIABILITY, OR USEFULNESS OF THE SOFTWARE. 9 | 10 | % You are solely responsible for determining the appropriateness of using and distributing the software and you assume all risks associated with its use, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and the unavailability or interruption of operation. This software is not intended to be used in any situation where a failure could cause risk of injury or damage to property. The software developed by NIST employees is not subject to copyright protection within the United States. 11 | % 12 | 13 | function [] = PlotPoleFigure(MTEXFile, ijk_vals, xyz_vals, ColormapFile, ColormapUpperLimit) 14 | 15 | % Script created by Matt Rolchigo (ORNL) and Adam Creuziger (NIST) 16 | % Plots pole figure data, and inverse pole figure data for the file specified by `MTEXFile`, for crystal planes specified by ijk_vals (for pole figures) and reference directions specified by xyz_vals (for inverse pole figures) using the colormap specified by `ColormapFile`, with colormap bounds [0, `ColormapUpperLimit`]. See `analysis/README.txt` for more details 17 | % crystal symmetry 18 | Ext = strfind(MTEXFile,'.'); 19 | SizeName = size(Ext); 20 | BaseFileName = extractBefore(MTEXFile,Ext(SizeName(2))); 21 | 22 | CS = crystalSymmetry('m3m', [1 1 1], [90,90,90]*degree, 'X||a', 'Y||b*', 'Z||c*'); 23 | SS = specimenSymmetry('mmm'); 24 | % plotting convention 25 | setMTEXpref('xAxisDirection','east'); 26 | setMTEXpref('yAxisDirection','north'); 27 | 28 | % set colorbar 29 | run(ColormapFile) 30 | 31 | % Create ODF 32 | odf_VPSClike = loadODF_generic(MTEXFile, 'Bunge', 'degree', 'cs', CS, ... 33 | 'header', 5, 'ColumnNames', {'phi1' 'Phi' 'phi2' 'weights'}, 'density'); 34 | 35 | num_pole_figs = size(ijk_vals,2); 36 | % Pole figure for each input set of planes 37 | for i=1:num_pole_figs 38 | % Create an Pole figure variable containing the data and plot 39 | ijk_pf = ijk_vals{i}; 40 | i_pf = ijk_pf(1); 41 | j_pf = ijk_pf(2); 42 | k_pf = ijk_pf(3); 43 | h = Miller(i_pf,j_pf,k_pf,CS); 44 | r = regularS2Grid('resolution',5*degree); 45 | pfs_VPSClike = calcPoleFigure(odf_VPSClike,h,r); 46 | 47 | figure(i); plot(pfs_VPSClike,'contourf'); 48 | hold on; 49 | clim(gca,[0, ColormapUpperLimit]); 50 | mtexColorbar; 51 | hold off; 52 | pf_plane_name = strcat(num2str(i_pf),num2str(j_pf),num2str(k_pf)); 53 | OutputFileName = strcat(BaseFileName,'_',pf_plane_name,'_PoleFigure.png'); 54 | export_fig(OutputFileName,'-r150'); 55 | end 56 | 57 | num_xyz = size(xyz_vals,2); 58 | for i=1:num_xyz 59 | if ((strcmp(xyz_vals(i),'x')) || (strcmp(xyz_vals(i),'X'))) 60 | ref_vector = xvector; 61 | elseif ((strcmp(xyz_vals(i),'y')) || (strcmp(xyz_vals(i),'Y'))) 62 | ref_vector = yvector; 63 | elseif ((strcmp(xyz_vals(i),'z')) || (strcmp(xyz_vals(i),'Z'))) 64 | ref_vector = zvector; 65 | else 66 | error('Error: Inputs for xyz_vals must be x, y, or z'); 67 | end 68 | figure(i+num_pole_figs); 69 | hold on; 70 | plotIPDF(odf_VPSClike,ref_vector,'contourf'); 71 | clim(gca,[0, ColormapUpperLimit]); 72 | mtexColorbar; 73 | hold off; 74 | OutputFileName2 = strcat(BaseFileName,'_IPFDensity_',xyz_vals(i),'.png'); 75 | export_fig(OutputFileName2,'-r150'); 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /unit_test/tstOrientation.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #include 7 | 8 | #include "CAconfig.hpp" 9 | #include "CAorientation.hpp" 10 | #include "CAparsefiles.hpp" 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | namespace Test { 19 | //---------------------------------------------------------------------------// 20 | // orientation init tests 21 | //---------------------------------------------------------------------------// 22 | void testOrientationInit_Vectors() { 23 | 24 | using memory_space = TEST_MEMSPACE; 25 | 26 | std::string grain_orientation_file_s = checkFileInstalled("GrainOrientationVectors.csv", 0); 27 | 28 | // Initialize grain orientations - unit vector form only 29 | int id = 0; 30 | std::vector grain_orientation_file = {grain_orientation_file_s}; 31 | Orientation orientation(id, grain_orientation_file, false); 32 | 33 | // Check results for first 2 orientations (first 18 values in the file) 34 | EXPECT_EQ(orientation.n_grain_orientations, 10000); 35 | 36 | std::vector expected_grain_unit_vector = {0.848294, 0.493303, 0.19248, -0.522525, 0.720911, 0.455253, 37 | 0.0858167, -0.486765, 0.869308, 0.685431, 0.188182, 0.7034, 38 | -0.468504, 0.85348, 0.228203, -0.557394, -0.485963, 0.673166}; 39 | auto grain_unit_vector_host = 40 | Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orientation.grain_unit_vector); 41 | for (int n = 0; n < 18; n++) { 42 | EXPECT_FLOAT_EQ(grain_unit_vector_host(n, 0), expected_grain_unit_vector[n]); 43 | } 44 | } 45 | 46 | void testOrientationInit_Angles() { 47 | 48 | using memory_space = TEST_MEMSPACE; 49 | 50 | std::string grain_orientation_file_s = checkFileInstalled("GrainOrientationVectors.csv", 0); 51 | std::vector grain_orientation_file = {grain_orientation_file_s}; 52 | 53 | // Initialize grain orientations - unit vector form and data from GrainOrientationEulerAnglesBungeZXZ.csv should be 54 | // read 55 | int id = 0; 56 | Orientation orientation(id, grain_orientation_file, true); 57 | 58 | // Check results 59 | EXPECT_EQ(orientation.n_grain_orientations, 10000); 60 | 61 | // Check first two orientations (first 6 values in the file) 62 | std::vector expected_euler_angles = {9.99854, 29.62172, 22.91854, 311.08350, 47.68814, 72.02547}; 63 | for (int n = 0; n < 6; n++) { 64 | EXPECT_FLOAT_EQ(orientation.grain_bunge_euler_host(n, 0), expected_euler_angles[n]); 65 | } 66 | } 67 | 68 | void testConvertGrainIDForBuffer() { 69 | using memory_space = TEST_MEMSPACE; 70 | using view_type = Kokkos::View; 71 | 72 | // Create a list of integer grain ID values 73 | // Test positive and negative values 74 | int n_grain_id_values = 7; 75 | int total_n_grain_id_values = 2 * n_grain_id_values; 76 | std::vector grain_id_v(total_n_grain_id_values); 77 | grain_id_v[0] = 1; 78 | grain_id_v[1] = 2; 79 | grain_id_v[2] = 3; 80 | grain_id_v[3] = 10000; 81 | grain_id_v[4] = 10001; 82 | grain_id_v[5] = 19999; 83 | grain_id_v[6] = 30132129; 84 | for (int n = n_grain_id_values; n < total_n_grain_id_values; n++) { 85 | grain_id_v[n] = -grain_id_v[n - n_grain_id_values]; 86 | } 87 | view_type grain_id(Kokkos::ViewAllocateWithoutInitializing("GrainID"), total_n_grain_id_values); 88 | auto grain_id_host = Kokkos::create_mirror_view(Kokkos::HostSpace(), grain_id); 89 | for (int n = 0; n < total_n_grain_id_values; n++) { 90 | grain_id_host(n) = grain_id_v[n]; 91 | } 92 | grain_id = Kokkos::create_mirror_view_and_copy(memory_space(), grain_id_host); 93 | 94 | int n_grain_orientations = 10000; 95 | 96 | // Check that these were converted to their components and back correctly 97 | view_type grain_id_converted(Kokkos::ViewAllocateWithoutInitializing("grain_id_converted"), 98 | total_n_grain_id_values); 99 | 100 | Kokkos::parallel_for( 101 | "TestInitGrainIDs", total_n_grain_id_values, KOKKOS_LAMBDA(const int &n) { 102 | int my_grain_orientation = getGrainOrientation(grain_id(n), n_grain_orientations, false); 103 | int my_grain_number = getGrainNumber(grain_id(n), n_grain_orientations); 104 | grain_id_converted[n] = getGrainID(my_grain_orientation, my_grain_number, n_grain_orientations); 105 | }); 106 | auto grain_id_converted_host = Kokkos::create_mirror_view(Kokkos::HostSpace(), grain_id_converted); 107 | for (int n = 0; n < total_n_grain_id_values; n++) 108 | EXPECT_EQ(grain_id_v[n], grain_id_converted_host(n)); 109 | } 110 | //---------------------------------------------------------------------------// 111 | // RUN TESTS 112 | //---------------------------------------------------------------------------// 113 | TEST(TEST_CATEGORY, orientation) { 114 | testOrientationInit_Vectors(); 115 | testOrientationInit_Angles(); 116 | testConvertGrainIDForBuffer(); 117 | } 118 | } // end namespace Test 119 | -------------------------------------------------------------------------------- /analysis/src/GAutils.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #include "GAutils.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | // Parse log file using json format 16 | void parseLogFile(std::string log_file, int &nx, int &ny, int &nz, double &deltax, int &number_of_layers, 17 | std::vector &xyz_bounds, std::vector &grain_unit_vector_file, 18 | std::vector &phase_names, int &num_phases, bool orientation_files_in_input) { 19 | 20 | std::ifstream input_data_stream; 21 | input_data_stream.open(log_file); 22 | nlohmann::json logdata = nlohmann::json::parse(input_data_stream); 23 | 24 | // X, Y, Z bounds of domain (in microns) 25 | xyz_bounds[0] = logdata["Domain"]["XBounds"][0]; 26 | xyz_bounds[1] = logdata["Domain"]["YBounds"][0]; 27 | xyz_bounds[2] = logdata["Domain"]["ZBounds"][0]; 28 | xyz_bounds[3] = logdata["Domain"]["XBounds"][1]; 29 | xyz_bounds[4] = logdata["Domain"]["YBounds"][1]; 30 | xyz_bounds[5] = logdata["Domain"]["ZBounds"][1]; 31 | // Cell size (in microns) 32 | deltax = logdata["Domain"]["CellSize"]; 33 | // Number of cells per domain direction 34 | nx = logdata["Domain"]["Nx"]; 35 | ny = logdata["Domain"]["Ny"]; 36 | nz = logdata["Domain"]["Nz"]; 37 | std::string simulation_type = logdata["SimulationType"]; 38 | // Directional, Spot, SingleGrain problem types are single layer 39 | if (simulation_type == "FromFinch" || simulation_type == "FromFile") 40 | number_of_layers = logdata["Domain"]["NumberOfLayers"]; 41 | else 42 | number_of_layers = 1; 43 | 44 | if (orientation_files_in_input) 45 | std::cout << "Note: orientation filename specified in log file will be used, overriding value from analysis " 46 | "input file" 47 | << std::endl; 48 | if (logdata["PhaseName"].size() == 2) { 49 | phase_names.push_back(logdata["PhaseName"][0]); 50 | phase_names.push_back(logdata["PhaseName"][1]); 51 | // List of grain unit vector files should be size 2 and consist of two separate files (for an orientation 52 | // transformation on solidification) or the same file twice. As of now, the second orientation file is not used 53 | // as materials without a transformation on solidification should only have one orientation file, and materials 54 | // with a transformation on solidification will have all final grain orientations map to a value from the first 55 | // file 56 | if (logdata["GrainOrientationFile"].size() == 2) { 57 | grain_unit_vector_file.push_back(logdata["GrainOrientationFile"][0]); 58 | grain_unit_vector_file.push_back(logdata["GrainOrientationFile"][1]); 59 | } 60 | else { 61 | grain_unit_vector_file.push_back(logdata["GrainOrientationFile"]); 62 | grain_unit_vector_file.push_back(logdata["GrainOrientationFile"]); 63 | } 64 | num_phases = 2; 65 | } 66 | else { 67 | if (logdata.contains("PhaseName")) 68 | phase_names.push_back(logdata["PhaseName"]); 69 | else 70 | phase_names.push_back("default"); 71 | num_phases = 1; 72 | grain_unit_vector_file.push_back(logdata["GrainOrientationFile"]); 73 | } 74 | input_data_stream.close(); 75 | } 76 | 77 | // Reads and ignored ASCII field data - each line contains data for a specific z coordinate 78 | void readIgnoreASCIIField(std::ifstream &input_data_stream, int nz) { 79 | std::string line; 80 | for (int i = 0; i < nz; i++) 81 | getline(input_data_stream, line); 82 | } 83 | 84 | // Get the scaling factor to convert a number of cells into a length, area, or volume 85 | double convertToMicrons(double deltax, std::string region_type) { 86 | double cell_to_size_scaling; 87 | if (region_type == "volume") 88 | cell_to_size_scaling = Kokkos::pow(deltax, 3) * Kokkos::pow(10, 18); 89 | else if (region_type == "area") 90 | cell_to_size_scaling = Kokkos::pow(deltax, 2) * Kokkos::pow(10, 12); 91 | else if (region_type == "length") 92 | cell_to_size_scaling = deltax * Kokkos::pow(10, 6); 93 | else 94 | throw std::runtime_error("Error: unknown region type"); 95 | return cell_to_size_scaling; 96 | } 97 | 98 | // Get the scaling factor to convert a length, area, or volume into a number of cells 99 | double convertToCells(double deltax, std::string region_type) { 100 | double size_to_cell_scaling; 101 | if (region_type == "volume") 102 | size_to_cell_scaling = 1.0 / (pow(deltax, 3) * Kokkos::pow(10, 18)); 103 | else if (region_type == "area") 104 | size_to_cell_scaling = 1.0 / (pow(deltax, 2) * Kokkos::pow(10, 12)); 105 | else if (region_type == "length") 106 | size_to_cell_scaling = 1.0 / (deltax * Kokkos::pow(10, 6)); 107 | else 108 | throw std::runtime_error("Error: unknown region type"); 109 | return size_to_cell_scaling; 110 | } 111 | 112 | // Print the string "output" to both output file streams 113 | void dualPrint(std::string output, std::ostream &stream1, std::ostream &stream2) { 114 | stream1 << output; 115 | stream2 << output; 116 | } 117 | -------------------------------------------------------------------------------- /src/CAparsefiles.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #ifndef EXACA_PARSE_HPP 7 | #define EXACA_PARSE_HPP 8 | 9 | #include "CAconfig.hpp" 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | std::string removeWhitespace(std::string line, int pos = -1); 19 | bool getInputBool(std::string val_input); 20 | int getInputInt(std::string val_input); 21 | float getInputFloat(std::string val_input, int factor = 0); 22 | double getInputDouble(std::string val_input, int factor = 0); 23 | void splitString(std::string line, std::vector &parsed_line, std::size_t expected_num_values, 24 | char separator = ','); 25 | std::vector splitString(std::ifstream &input_data_stream, std::size_t expected_num_values = 4, 26 | char separator = ' '); 27 | std::size_t checkForHeaderValues(std::string header_line); 28 | bool checkFileExists(const std::string path, const int id, const bool error = true); 29 | std::string checkFileInstalled(const std::string name, const int id); 30 | void checkFileNotEmpty(std::string testfilename); 31 | bool checkTemperatureFileFormat(std::string tempfile_thislayer); 32 | std::size_t checkForHeaderValues(std::string header_line); 33 | 34 | // Swaps bits for a variable of type SwapType 35 | template 36 | void swapEndian(SwapType &var) { 37 | // Cast var into a char array (bit values) 38 | char *var_array = reinterpret_cast(&var); 39 | // Size of char array 40 | int var_size = sizeof(var); 41 | // Swap the "ith" bit with the bit "i" from the end of the array 42 | for (long i = 0; i < static_cast(var_size / 2); i++) 43 | std::swap(var_array[var_size - 1 - i], var_array[i]); 44 | } 45 | // Reads binary data of the type ReadType, optionally swapping the endian format 46 | template 47 | ReadType readBinaryData(std::ifstream &instream, bool swap_endian_yn = false) { 48 | unsigned char temp[sizeof(ReadType)]; 49 | instream.read(reinterpret_cast(temp), sizeof(ReadType)); 50 | if (swap_endian_yn) 51 | swapEndian(temp); 52 | ReadType read_value = reinterpret_cast(temp); 53 | return read_value; 54 | } 55 | // Parse space-separated ASCII data loaded into the string stream 56 | template 57 | ReadType parseASCIIData(std::istringstream &ss) { 58 | ReadType read_value; 59 | ss >> read_value; 60 | return read_value; 61 | } 62 | 63 | // Reads portion of a paraview file and places data in the appropriate data structure 64 | // ASCII data at each Z value is separated by a newline 65 | template 66 | read_view_type_3d_host readASCIIField(std::ifstream &input_data_stream, int nx, int ny, int nz, std::string label) { 67 | read_view_type_3d_host field_of_interest(Kokkos::ViewAllocateWithoutInitializing(label), nz, nx, ny); 68 | using value_type = typename read_view_type_3d_host::value_type; 69 | for (int k = 0; k < nz; k++) { 70 | // Get line from file 71 | std::string line; 72 | getline(input_data_stream, line); 73 | // Parse string at spaces 74 | std::istringstream ss(line); 75 | for (int j = 0; j < ny; j++) { 76 | for (int i = 0; i < nx; i++) { 77 | field_of_interest(k, i, j) = parseASCIIData(ss); 78 | } 79 | } 80 | } 81 | return field_of_interest; 82 | } 83 | 84 | // Reads binary string of type read_datatype from a paraview file, converts field to the appropriate type to match 85 | // read_view_type_3d_host (i.e, value_type), and place data in the appropriate data structure Each field consists of a 86 | // single binary string (no newlines) Store converted values in view - LayerID data is a short int, GrainID data is an 87 | // int In some older vtk files, LayerID may have been stored as an int and should be converted 88 | template 89 | read_view_type_3d_host readBinaryField(std::ifstream &input_data_stream, int nx, int ny, int nz, std::string label) { 90 | read_view_type_3d_host field_of_interest(Kokkos::ViewAllocateWithoutInitializing(label), nz, nx, ny); 91 | using value_type = typename read_view_type_3d_host::value_type; 92 | for (int k = 0; k < nz; k++) { 93 | for (int j = 0; j < ny; j++) { 94 | for (int i = 0; i < nx; i++) { 95 | read_datatype parsed_value = readBinaryData(input_data_stream, true); 96 | field_of_interest(k, i, j) = static_cast(parsed_value); 97 | } 98 | } 99 | } 100 | return field_of_interest; 101 | } 102 | 103 | void readIgnoreASCIIField(std::ifstream &input_data_stream, int nz); 104 | 105 | // Reads and discards binary string of type read_datatype from a paraview file 106 | template 107 | void readIgnoreBinaryField(std::ifstream &input_data_stream, int nx, int ny, int nz) { 108 | unsigned char temp[sizeof(read_datatype)]; 109 | for (int k = 0; k < nz; k++) { 110 | for (int j = 0; j < ny; j++) { 111 | for (int i = 0; i < nx; i++) { 112 | input_data_stream.read(reinterpret_cast(temp), sizeof(read_datatype)); 113 | } 114 | } 115 | } 116 | } 117 | 118 | // Read and discard "n_lines" lines of data from the file 119 | void skipLines(std::ifstream &input_data_stream, const int n_lines); 120 | 121 | #endif 122 | -------------------------------------------------------------------------------- /src/CAinterfacialresponse.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #ifndef EXACA_IRF_HPP 7 | #define EXACA_IRF_HPP 8 | 9 | #include "CAinputdata.hpp" 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | // Interfacial response function with various functional forms. 19 | struct InterfacialResponseFunction { 20 | 21 | InterfacialResponseInputs _inputs; 22 | 23 | // Constructor 24 | InterfacialResponseFunction(const double deltat, const double deltax, const InterfacialResponseInputs inputs) 25 | : _inputs(inputs) { 26 | for (int phase_num = 0; phase_num < _inputs.num_phases; phase_num++) 27 | normalize(deltat, deltax, phase_num); 28 | } 29 | 30 | void normalize(const double deltat, const double deltax, const int phase_num = 0) { 31 | if (_inputs.function[phase_num] == _inputs.cubic) { 32 | // Normalize all 4 coefficients: V = A*x^3 + B*x^2 + C*x + D 33 | _inputs.A[phase_num] *= static_cast(deltat / deltax); 34 | _inputs.B[phase_num] *= static_cast(deltat / deltax); 35 | _inputs.C[phase_num] *= static_cast(deltat / deltax); 36 | _inputs.D[phase_num] *= static_cast(deltat / deltax); 37 | } 38 | else if (_inputs.function[phase_num] == _inputs.quadratic) { 39 | // Normalize the 3 relevant coefficients: V = A*x^2 + B*x + C 40 | _inputs.A[phase_num] *= static_cast(deltat / deltax); 41 | _inputs.B[phase_num] *= static_cast(deltat / deltax); 42 | _inputs.C[phase_num] *= static_cast(deltat / deltax); 43 | } 44 | else if (_inputs.function[phase_num] == _inputs.power) { 45 | // Normalize only the leading and last coefficient: V = A*x^B + C 46 | _inputs.A[phase_num] *= static_cast(deltat / deltax); 47 | _inputs.C[phase_num] *= static_cast(deltat / deltax); 48 | } 49 | else if (_inputs.function[phase_num] == _inputs.exponential) { 50 | // Normalize only the leading and last coefficient: V = A*e^(Bx) + C 51 | _inputs.A[phase_num] *= static_cast(deltat / deltax); 52 | _inputs.C[phase_num] *= static_cast(deltat / deltax); 53 | } 54 | } 55 | 56 | // Compute velocity from local undercooling. 57 | // functional form is assumed to be cubic if not explicitly given in input file 58 | KOKKOS_INLINE_FUNCTION 59 | float compute(const float loc_u_uncapped, const int phase_num = 0) const { 60 | float V; 61 | float loc_u; 62 | // Should the maximum velocity be capped at the freezing range value? 63 | if (_inputs.velocity_cap[phase_num]) 64 | loc_u = Kokkos::min(loc_u_uncapped, _inputs.freezing_range[phase_num]); 65 | else 66 | loc_u = loc_u_uncapped; 67 | assert(phase_num < _inputs.num_phases); 68 | if (_inputs.function[phase_num] == _inputs.quadratic) 69 | V = _inputs.A[phase_num] * Kokkos::pow(loc_u, 2.0) + _inputs.B[phase_num] * loc_u + _inputs.C[phase_num]; 70 | else if (_inputs.function[phase_num] == _inputs.power) 71 | V = _inputs.A[phase_num] * Kokkos::pow(loc_u, _inputs.B[phase_num]) + _inputs.C[phase_num]; 72 | else if (_inputs.function[phase_num] == _inputs.cubic) 73 | V = _inputs.A[phase_num] * Kokkos::pow(loc_u, 3.0) + _inputs.B[phase_num] * Kokkos::pow(loc_u, 2.0) + 74 | _inputs.C[phase_num] * loc_u + _inputs.D[phase_num]; 75 | else 76 | V = _inputs.A[phase_num] * Kokkos::exp(loc_u * _inputs.B[phase_num]) + _inputs.C[phase_num]; 77 | return Kokkos::fmax(0.0, V); 78 | } 79 | 80 | std::string functionName(const int phase_num = 0) { 81 | // Not storing string due to Cuda warnings when constructing on device. 82 | if (_inputs.function[phase_num] == _inputs.cubic) 83 | return "cubic"; 84 | else if (_inputs.function[phase_num] == _inputs.quadratic) 85 | return "quadratic"; 86 | else if (_inputs.function[phase_num] == _inputs.power) 87 | return "power"; 88 | else if (_inputs.function[phase_num] == _inputs.exponential) 89 | return "exponential"; 90 | // Should never make it here 91 | return "none"; 92 | } 93 | 94 | // Get the solid phase based on the faster growing phase at the input undercooling loc_u. If this is a single phase 95 | // problem, return 0 for the default phase 96 | KOKKOS_INLINE_FUNCTION 97 | int getPreferredPhaseNucleation(const float loc_u) const { 98 | if (_inputs.num_phases == 1) 99 | return 0; 100 | else { 101 | const double V_p0 = compute(loc_u, 0); 102 | const double V_p1 = compute(loc_u, 1); 103 | if (V_p0 > V_p1) 104 | return 0; 105 | else 106 | return 1; 107 | } 108 | } 109 | 110 | // Get the solid phase based on the number of phases in the material and the input transformation rule 111 | KOKKOS_INLINE_FUNCTION 112 | int getPreferredPhaseActivation(const int local_phase_id) const { 113 | if (_inputs.transformation == _inputs.solidification) 114 | return 0; 115 | else 116 | return local_phase_id; 117 | } 118 | 119 | auto A(const int phase_num = 0) { return _inputs.A[phase_num]; } 120 | auto B(const int phase_num = 0) { return _inputs.B[phase_num]; } 121 | auto C(const int phase_num = 0) { return _inputs.C[phase_num]; } 122 | auto D(const int phase_num = 0) { return _inputs.D[phase_num]; } 123 | auto freezingRange(const int phase_num = 0) { return _inputs.freezing_range[phase_num]; } 124 | auto numPhases() { return _inputs.num_phases; } 125 | bool solidificationTransformation() { return _inputs.transformation == _inputs.solidification; } 126 | }; 127 | 128 | #endif 129 | -------------------------------------------------------------------------------- /utilities/MTEX/PlotIPFColoredSection.m: -------------------------------------------------------------------------------- 1 | % Copyright Lawrence Livermore National Security, LLC, and other ExaCA Project Developers. 2 | % See the top-level LICENSE file for details. 3 | % 4 | % SPDX-License-Identifier: MIT 5 | % 6 | % NIST-developed software is provided by NIST as a public service. You may use, copy, and distribute copies of the software in any medium, provided that you keep intact this entire notice. You may improve, modify, and create derivative works of the software or any portion of the software, and you may copy and distribute such modifications or works. Modified works should carry a notice stating that you changed the software and should note the date and nature of any such change. Please explicitly acknowledge the National Institute of Standards and Technology as the source of the software. 7 | 8 | % NIST-developed software is expressly provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED, IN FACT, OR ARISING BY OPERATION OF LAW, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND DATA ACCURACY. NIST NEITHER REPRESENTS NOR WARRANTS THAT THE OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT ANY DEFECTS WILL BE CORRECTED. NIST DOES NOT WARRANT OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF THE SOFTWARE OR THE RESULTS THEREOF, INCLUDING BUT NOT LIMITED TO THE CORRECTNESS, ACCURACY, RELIABILITY, OR USEFULNESS OF THE SOFTWARE. 9 | 10 | % You are solely responsible for determining the appropriateness of using and distributing the software and you assume all risks associated with its use, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and the unavailability or interruption of operation. This software is not intended to be used in any situation where a failure could cause risk of injury or damage to property. The software developed by NIST employees is not subject to copyright protection within the United States. 11 | 12 | function [] = PlotIPFColoredSection(MTEXFile, Phaselist) 13 | 14 | % Script created by Matt Rolchigo (ORNL) and Adam Creuziger (NIST) 15 | % Plots the cross-section specified by `MTEXFile` using the inverse pole figure colormap relative to the X, Y, and Z directions 16 | % crystal summetry 17 | if (nargin == 1) 18 | numphases = 1; 19 | CS = crystalSymmetry('m3m', [1 1 1], [90,90,90]*degree, 'X||a', 'Y||b*', 'Z||c*'); 20 | else 21 | numphases = 2; 22 | pname1 = Phaselist{1}; 23 | pname2 = Phaselist{2}; 24 | CS = {crystalSymmetry('m3m', [1 1 1], [90,90,90]*degree, 'X||a', 'Y||b*', 'Z||c*','mineral',pname1),... 25 | crystalSymmetry('m3m', [1 1 1], [90,90,90]*degree, 'X||a', 'Y||b*', 'Z||c*','mineral',pname2)}; 26 | end 27 | 28 | Ext = strfind(MTEXFile,'.'); 29 | SizeName = size(Ext); 30 | BaseFileName = extractBefore(MTEXFile,Ext(SizeName(2))); 31 | fig_counter = 1; 32 | 33 | % plotting convention 34 | setMTEXpref('xAxisDirection','east'); 35 | setMTEXpref('yAxisDirection','north'); 36 | 37 | % create an EBSD variable containing the data 38 | ebsd = EBSD.load(MTEXFile,CS,'interface','generic',... 39 | 'ColumnNames', { 'phi1' 'Phi' 'phi2' 'Phase' 'x' 'y'}, 'Bunge'); 40 | 41 | % Draw grain boundaries 42 | [grains,ebsd.grainId] = calcGrains(ebsd('indexed'),'threshold',0.001); 43 | 44 | % remove very small grains 45 | ebsd(grains(grains.grainSize<=6.25)) = []; 46 | 47 | % smooth the grains a bit 48 | grains = smooth(grains,5); 49 | ebsd = smooth(ebsd, halfQuadraticFilter, 'extrapolate'); 50 | gB = grains.boundary; 51 | 52 | % and recompute grains 53 | [grains,ebsd.grainId] = calcGrains(ebsd('indexed'),'threshold',0.001); 54 | 55 | % two phase solidification: plot 56 | if (numphases == 2) 57 | figure(fig_counter); 58 | ebsd(pname1).color = [0 0 0]; 59 | ebsd(pname2).color = [1 1 1]; 60 | plot(ebsd); 61 | OutputFileName = strcat(BaseFileName,'_SolidifiedPhases.png'); 62 | export_fig(OutputFileName,'-r150'); 63 | fig_counter = fig_counter + 1; 64 | % for IPF maps, only grain orientation differences make up a phase 65 | % plot as single phase 66 | % Set EBSD data to one phase - only grain orientation differences make up 67 | % a grain boundary 68 | ebsd.phase = ones(ebsd.size(1), 1); 69 | % redraw grain boundaries 70 | [grains,ebsd.grainId] = calcGrains(ebsd('indexed'),'threshold',0.001); 71 | % remove very small grains 72 | ebsd(grains(grains.grainSize<=6.25)) = []; 73 | % smooth the grains a bit 74 | ebsd = smooth(ebsd('indexed'), halfQuadraticFilter, 'extrapolate'); 75 | % and recompute grains 76 | [grains,ebsd.grainId] = calcGrains(ebsd('indexed'),'threshold',0.001); 77 | grains = smooth(grains,5); 78 | gB = grains.boundary; 79 | end 80 | 81 | ipfKey = ipfColorKey(ebsd('1').orientations); 82 | 83 | %plotting 84 | figure(fig_counter); 85 | ipfKey.inversePoleFigureDirection = vector3d.X; 86 | colors = ipfKey.orientation2color(grains('indexed').meanOrientation); 87 | plot(grains('indexed'),colors) 88 | hold on 89 | plot(gB,'lineWidth',1); 90 | hold off 91 | OutputFileName = strcat(BaseFileName,'_IPF-X.png'); 92 | export_fig(OutputFileName,'-r150'); 93 | fig_counter = fig_counter + 1; 94 | 95 | figure(fig_counter); 96 | ipfKey.inversePoleFigureDirection = vector3d.Y; 97 | colors = ipfKey.orientation2color(grains('indexed').meanOrientation); 98 | plot(grains('indexed'),colors) 99 | hold on 100 | plot(gB,'lineWidth',1); 101 | hold off 102 | OutputFileName = strcat(BaseFileName,'_IPF-Y.png'); 103 | export_fig(OutputFileName,'-r150'); 104 | fig_counter = fig_counter + 1; 105 | 106 | figure(fig_counter); 107 | ipfKey.inversePoleFigureDirection = vector3d.Z; 108 | colors = ipfKey.orientation2color(grains('indexed').meanOrientation); 109 | plot(grains('indexed'),colors) 110 | hold on 111 | plot(gB,'lineWidth',1); 112 | hold off 113 | OutputFileName = strcat(BaseFileName,'_IPF-Z.png'); 114 | export_fig(OutputFileName,'-r150'); 115 | 116 | end 117 | -------------------------------------------------------------------------------- /src/CAtimers.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #ifndef EXACA_TIMERS_HPP 7 | #define EXACA_TIMERS_HPP 8 | 9 | #include "mpi.h" 10 | #include 11 | #include 12 | 13 | class Timer { 14 | double _time = 0.0; 15 | double start_time = 0.0; 16 | double max_time, min_time = 0.0; 17 | int num_calls = 0; 18 | 19 | public: 20 | void start() { start_time = MPI_Wtime(); } 21 | void stop() { 22 | _time += MPI_Wtime() - start_time; 23 | num_calls++; 24 | } 25 | void reset() { _time = 0.0; } 26 | auto time() { return _time; } 27 | auto numCalls() { return num_calls; } 28 | auto minTime() { return min_time; } 29 | auto maxTime() { return max_time; } 30 | 31 | void reduceMPI() { 32 | MPI_Allreduce(&_time, &max_time, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); 33 | MPI_Allreduce(&_time, &min_time, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); 34 | } 35 | 36 | auto print(std::string description) { 37 | std::stringstream out; 38 | out << "Time spent " << description << " = " << _time << " s" << std::endl; 39 | return out.str(); 40 | } 41 | 42 | auto printMinMax(std::string description) { 43 | std::stringstream out; 44 | out << "Max/min rank time " << description << " = " << max_time << " / " << min_time << " s" << std::endl; 45 | return out.str(); 46 | } 47 | }; 48 | 49 | // Print timing info 50 | struct Timers { 51 | 52 | int id; 53 | Timer init, run, output; 54 | Timer nucl, create_sv, capture, ghost; 55 | Timer layer; 56 | Timer heat_transfer; 57 | 58 | Timers(const int mpi_id) 59 | : id(mpi_id) 60 | , init() 61 | , run() 62 | , output() 63 | , nucl() 64 | , create_sv() 65 | , capture() 66 | , ghost() 67 | , layer() 68 | , heat_transfer() {} 69 | 70 | void startInit() { init.start(); } 71 | void stopInit() { 72 | init.stop(); 73 | if (id == 0) 74 | std::cout << "Data initialized: Time spent: " << init.time() << " s" << std::endl; 75 | } 76 | 77 | void startRun() { run.start(); } 78 | 79 | void stopRun() { run.stop(); } 80 | 81 | void startOutput() { output.start(); } 82 | 83 | void stopOutput() { output.stop(); } 84 | 85 | void startNucleation() { nucl.start(); } 86 | void stopNucleation() { nucl.stop(); } 87 | 88 | void startSV() { create_sv.start(); } 89 | void stopSV() { create_sv.stop(); } 90 | 91 | void startCapture() { capture.start(); } 92 | void stopCapture() { capture.stop(); } 93 | 94 | void startComm() { ghost.start(); } 95 | void stopComm() { ghost.stop(); } 96 | 97 | void startLayer() { layer.start(); } 98 | void stopLayer(const int layernumber) { 99 | layer.stop(); 100 | if (id == 0) 101 | std::cout << "Time for layer number " << layernumber << " was " << layer.time() << " s, starting layer " 102 | << layernumber + 1 << std::endl; 103 | layer.reset(); 104 | } 105 | void stopLayer() { 106 | layer.stop(); 107 | if (id == 0) 108 | std::cout << "Time for final layer was " << layer.time() << " s" << std::endl; 109 | } 110 | 111 | void startHeatTransfer() { heat_transfer.start(); } 112 | void stopHeatTransfer() { heat_transfer.stop(); } 113 | 114 | double getTotal() { return init.time() + run.time() + output.time(); } 115 | 116 | auto printLog() { 117 | // This assumes reduceMPI() has already been called. 118 | std::stringstream log; 119 | log << " \"Timing\": {" << std::endl; 120 | log << " \"Runtime\": " << getTotal() << "," << std::endl; 121 | log << " \"InitRunOutputBreakdown\": [" << init.time() << "," << run.time() << "," << output.time() 122 | << "]," << std::endl; 123 | log << " \"MaxMinInitTime\": [" << init.maxTime() << "," << init.minTime() << "]," << std::endl; 124 | log << " \"MaxMinNucleationTime\": [" << nucl.maxTime() << "," << nucl.minTime() << "]," << std::endl; 125 | log << " \"MaxMinSteeringVectorCreationTime\": [" << create_sv.maxTime() << "," << create_sv.minTime() 126 | << "]," << std::endl; 127 | log << " \"MaxMinCellCaptureTime\": [" << capture.maxTime() << "," << capture.minTime() << "]," 128 | << std::endl; 129 | log << " \"MaxMinGhostExchangeTime\": [" << ghost.maxTime() << "," << ghost.minTime() << "]," 130 | << std::endl; 131 | log << " \"MaxMinOutputTime\": [" << output.maxTime() << "," << output.minTime() << "]" << std::endl; 132 | log << " }" << std::endl; 133 | return log.str(); 134 | } 135 | 136 | void reduceMPI() { 137 | // Reduce all times across MPI ranks 138 | init.reduceMPI(); 139 | nucl.reduceMPI(); 140 | create_sv.reduceMPI(); 141 | capture.reduceMPI(); 142 | ghost.reduceMPI(); 143 | output.reduceMPI(); 144 | 145 | if (heat_transfer.time() > 0) 146 | heat_transfer.reduceMPI(); 147 | } 148 | 149 | void printFinal(const int np, const int cycle) { 150 | 151 | if (id != 0) 152 | return; 153 | 154 | std::cout << "===================================================================================" << std::endl; 155 | std::cout << "Having run with = " << np << " processors" << std::endl; 156 | std::cout << "Output written at cycle = " << cycle << std::endl; 157 | std::cout << "Total time = " << getTotal() << std::endl; 158 | if (heat_transfer.time() > 0) 159 | std::cout << heat_transfer.print("performing heat transfer simulation"); 160 | std::cout << init.print("initializing data"); 161 | std::cout << run.print("performing CA calculations"); 162 | std::cout << output.print("collecting and printing output data"); 163 | 164 | std::cout << init.printMinMax("initializing data"); 165 | std::cout << nucl.printMinMax("in CA nucleation"); 166 | std::cout << create_sv.printMinMax("in CA steering vector creation"); 167 | std::cout << capture.printMinMax("in CA cell capture"); 168 | std::cout << ghost.printMinMax("in CA cell communication"); 169 | std::cout << output.printMinMax("exporting data"); 170 | 171 | std::cout << "===================================================================================" << std::endl; 172 | } 173 | }; 174 | 175 | #endif 176 | -------------------------------------------------------------------------------- /unit_test/tstInterfacialResponse.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #include 7 | #include 8 | 9 | #include "CAinputs.hpp" 10 | #include "CAinterfacialresponse.hpp" 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | namespace Test { 19 | //---------------------------------------------------------------------------// 20 | // Tests the interfacial response function construction 21 | //---------------------------------------------------------------------------// 22 | void testInterfacialResponse() { 23 | 24 | // Test that the interfacial response can be read for the new file format 25 | std::vector material_file_names = {"Inconel625.json", "Inconel625_Quadratic.json", "SS316.json", 26 | "SS316L_AusteniteFerrite.json"}; 27 | double deltax = 0.5; 28 | double deltat = 1.0; 29 | for (auto file_name : material_file_names) { 30 | std::cout << "Reading " << file_name << std::endl; 31 | 32 | Inputs inputs; 33 | inputs.material_filename = file_name; 34 | inputs.parseIRF(0); 35 | InterfacialResponseFunction irf(deltat, deltax, inputs.irf); 36 | 37 | // Check that fitting parameters were correctly initialized and normalized for the single phase present or for 38 | // both phases (SS316L_FA material input file) Fitting parameters should've been normalized by deltat / deltax, 39 | // i.e. twice as large as the numbers in the file 40 | float a_test[2], b_test[2], c_test[2], d_test[2], freezing_range_test[2], expected_v[2]; 41 | float loc_u = 11.0; 42 | if (file_name == material_file_names[0]) { 43 | a_test[0] = -0.00000010302; 44 | b_test[0] = 0.00010533; 45 | c_test[0] = 0.0022196; 46 | d_test[0] = 0; 47 | freezing_range_test[0] = 210; 48 | expected_v[0] = (deltat / deltax) * 49 | (a_test[0] * pow(loc_u, 3.0) + b_test[0] * pow(loc_u, 2.0) + c_test[0] * loc_u + d_test[0]); 50 | } 51 | else if (file_name == material_file_names[1]) { 52 | a_test[0] = 0.000072879; 53 | b_test[0] = 0.004939; 54 | c_test[0] = -0.047024; 55 | freezing_range_test[0] = 210; 56 | expected_v[0] = (deltat / deltax) * (a_test[0] * pow(loc_u, 2.0) + b_test[0] * loc_u + c_test[0]); 57 | } 58 | else if (file_name == material_file_names[2]) { 59 | a_test[0] = 0.000007325; 60 | b_test[0] = 3.12; 61 | c_test[0] = 0; 62 | freezing_range_test[0] = 26.5; 63 | expected_v[0] = (deltat / deltax) * (a_test[0] * pow(loc_u, b_test[0]) + c_test[0]); 64 | } 65 | else if (file_name == material_file_names[3]) { 66 | // Austenite inputs 67 | a_test[0] = 3.1718E-18; 68 | b_test[0] = 12.024; 69 | c_test[0] = 0; 70 | freezing_range_test[0] = 24.9; 71 | expected_v[0] = (deltat / deltax) * (a_test[0] * pow(loc_u, b_test[0]) + c_test[0]); 72 | // Ferrite inputs 73 | a_test[1] = 5.6442E-5; 74 | b_test[1] = 0.37259; 75 | c_test[1] = 0; 76 | freezing_range_test[1] = 23.9; 77 | expected_v[1] = (deltat / deltax) * (a_test[1] * exp(loc_u * b_test[1]) + c_test[1]); 78 | } 79 | else { 80 | throw std::runtime_error("File not set up for testing."); 81 | } 82 | // For all IRFs, A and C should be normalized by deltat/deltax (i.e., 2) 83 | // For the power law IRF (SS316 and both SS316L phases), B is dimensionless and should not be normalized unlike 84 | // the other IRFs where all coefficients are normalized Check that the number of phases are correct 85 | if (file_name == material_file_names[3]) { 86 | EXPECT_EQ(irf.numPhases(), 2); 87 | // Check for correct phase names 88 | EXPECT_TRUE(irf._inputs.phase_names[0] == "austenite"); 89 | EXPECT_TRUE(irf._inputs.phase_names[1] == "ferrite"); 90 | // Check for correct transformation 91 | EXPECT_EQ(irf._inputs.transformation, 1); 92 | // Check for velocity cap for both phases 93 | EXPECT_TRUE(irf._inputs.velocity_cap[0]); 94 | EXPECT_TRUE(irf._inputs.velocity_cap[1]); 95 | } 96 | else 97 | EXPECT_EQ(irf.numPhases(), 1); 98 | for (int phase = 0; phase < irf.numPhases(); phase++) { 99 | EXPECT_FLOAT_EQ(irf.A(phase), a_test[phase] * 2); 100 | if ((irf._inputs.function[phase] == irf._inputs.power) || 101 | (irf._inputs.function[phase] == irf._inputs.exponential)) 102 | EXPECT_FLOAT_EQ(irf.B(phase), b_test[phase]); 103 | else 104 | EXPECT_FLOAT_EQ(irf.B(phase), b_test[phase] * 2); 105 | EXPECT_FLOAT_EQ(irf.C(phase), c_test[phase] * 2); 106 | if (file_name == material_file_names[0]) { 107 | EXPECT_FLOAT_EQ(irf.D(phase), d_test[phase] * 2); 108 | } 109 | EXPECT_FLOAT_EQ(irf.freezingRange(phase), freezing_range_test[phase]); 110 | float computed_v = irf.compute(loc_u, phase); 111 | EXPECT_FLOAT_EQ(computed_v, expected_v[phase]); 112 | } 113 | } 114 | } 115 | 116 | void testGetPreferredPhase() { 117 | 118 | // Single phase IRF 119 | Inputs inputs; 120 | inputs.irf.function[0] = inputs.irf.power; 121 | // IRF for phase 0: V = 1.0 * (loc_u)**0.5 122 | inputs.irf.A[0] = 1.0; 123 | inputs.irf.B[0] = 0.5; 124 | inputs.irf.C[0] = 0.0; 125 | inputs.domain.deltax = 1.0 * pow(10, -6); 126 | inputs.domain.deltat = 1.0 * pow(10, -6); 127 | InterfacialResponseFunction irf(inputs.domain.deltat, inputs.domain.deltax, inputs.irf); 128 | // Regardless of undercooling, the preferred phase should be 0 for single phase IRFs 129 | EXPECT_EQ(irf.getPreferredPhaseNucleation(1.0), 0); 130 | EXPECT_EQ(irf.getPreferredPhaseActivation(0), 0); 131 | 132 | // Two phase IRF: phase 1 IRF: V = 0.5 * (loc_u)**2.0 133 | irf._inputs.num_phases = 2; 134 | irf._inputs.transformation = 1; 135 | irf._inputs.function[1] = inputs.irf.power; 136 | irf._inputs.A[1] = 0.5; 137 | irf._inputs.B[1] = 2.0; 138 | irf._inputs.C[1] = 0.0; 139 | // Preferred phase is phase with larger V: should be phase 0 for loc_u of 1, phase 1 for loc_u of 2 140 | EXPECT_EQ(irf.getPreferredPhaseNucleation(1.0), 0); 141 | EXPECT_EQ(irf.getPreferredPhaseNucleation(2.0), 1); 142 | // With a solidification transformation, preferred phase for activation is always 0 143 | EXPECT_EQ(irf.getPreferredPhaseActivation(1), 0); 144 | } 145 | //---------------------------------------------------------------------------// 146 | // RUN TESTS 147 | //---------------------------------------------------------------------------// 148 | TEST(TEST_CATEGORY, interfacial_response) { 149 | testInterfacialResponse(); 150 | testGetPreferredPhase(); 151 | } 152 | } // end namespace Test 153 | -------------------------------------------------------------------------------- /analysis/unit_test/tstUtils.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #include "CAprint.hpp" 7 | #include "GAutils.hpp" 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace Test { 17 | //---------------------------------------------------------------------------// 18 | // GAutils tests without Kokkos 19 | //---------------------------------------------------------------------------// 20 | template 21 | void writeTestMicrostructureData(std::ofstream &output_fstream, const int nx, const int ny, const int nz, 22 | const std::string data_label, Print3DViewType view_data, const bool write_binary_vtk) { 23 | output_fstream << "LOOKUP_TABLE default" << std::endl; 24 | for (int coord_z = 0; coord_z < nz; coord_z++) { 25 | for (int coord_y = 0; coord_y < ny; coord_y++) { 26 | for (int coord_x = 0; coord_x < nx; coord_x++) { 27 | if (data_label == "int") { 28 | int writeval = static_cast(view_data(coord_z, coord_x, coord_y)); 29 | writeData(output_fstream, writeval, write_binary_vtk, true); 30 | } 31 | else if (data_label == "short") { 32 | short writeval = static_cast(view_data(coord_z, coord_x, coord_y)); 33 | writeData(output_fstream, writeval, write_binary_vtk, true); 34 | } 35 | else if (data_label == "float") { 36 | float writeval = static_cast(view_data(coord_z, coord_x, coord_y)); 37 | writeData(output_fstream, writeval, write_binary_vtk, true); 38 | } 39 | } 40 | } 41 | // Do not insert newline character if using binary writing, as this will break the binary data read by 42 | // adding a blank line 43 | if (!(write_binary_vtk)) 44 | output_fstream << std::endl; 45 | } 46 | } 47 | 48 | void testInitializeData(const bool write_binary_vtk, const bool read_write_layer_id, 49 | const bool read_write_unused_field) { 50 | 51 | // Fixed domain size 52 | const int nx = 2; 53 | const int ny = 4; 54 | const int nz = 3; 55 | const int num_points = nx * ny * nz; 56 | 57 | // Analysis data currently stored only on host 58 | Kokkos::View dummy_id(Kokkos::ViewAllocateWithoutInitializing("dummy_id"), nz, nx, 59 | ny); 60 | Kokkos::View layer_id_write(Kokkos::ViewAllocateWithoutInitializing("layer_id_w"), nz, 61 | nx, ny); 62 | Kokkos::View grain_id_write(Kokkos::ViewAllocateWithoutInitializing("grain_id_w"), nz, 63 | nx, ny); 64 | for (int coord_z = 0; coord_z < nz; coord_z++) { 65 | for (int coord_y = 0; coord_y < ny; coord_y++) { 66 | for (int coord_x = 0; coord_x < nx; coord_x++) { 67 | dummy_id(coord_z, coord_x, coord_y) = 0.7; 68 | layer_id_write(coord_z, coord_x, coord_y) = static_cast(coord_z); 69 | grain_id_write(coord_z, coord_x, coord_y) = coord_x; 70 | } 71 | } 72 | } 73 | Kokkos::View layer_id_read(Kokkos::ViewAllocateWithoutInitializing("layer_id_r"), nz, 74 | nx, ny); 75 | Kokkos::View grain_id_read(Kokkos::ViewAllocateWithoutInitializing("grain_id_r"), nz, 76 | nx, ny); 77 | Kokkos::View phase_id_read(Kokkos::ViewAllocateWithoutInitializing("phase_id_r"), nz, 78 | nx, ny); 79 | 80 | // Write microstructure header data to test file 81 | std::string microstructure_file = "TestMicrostructure.vtk"; 82 | std::ofstream test_microstructure; 83 | test_microstructure.open(microstructure_file); 84 | test_microstructure << "# vtk DataFile Version 3.0" << std::endl; 85 | test_microstructure << "vtk output" << std::endl; 86 | if (write_binary_vtk) 87 | test_microstructure << "BINARY" << std::endl; 88 | else 89 | test_microstructure << "ASCII" << std::endl; 90 | test_microstructure << "DATASET STRUCTURED_POINTS" << std::endl; 91 | test_microstructure << "DIMENSIONS " << nx << " " << ny << " " << nz << std::endl; 92 | test_microstructure << "ORIGIN 0 0 0" << std::endl; 93 | test_microstructure << "SPACING 1e-06 1e-06 1e-06" << std::endl; 94 | test_microstructure << "POINT_DATA " << num_points << std::endl; 95 | 96 | // Write microstructure field data to test file - always grain_id, optionally other fields 97 | test_microstructure << "SCALARS GrainID int 1" << std::endl; 98 | writeTestMicrostructureData(test_microstructure, nx, ny, nz, "int", grain_id_write, write_binary_vtk); 99 | if (read_write_unused_field) { 100 | test_microstructure << "SCALARS DummyID float 1" << std::endl; 101 | writeTestMicrostructureData(test_microstructure, nx, ny, nz, "float", dummy_id, write_binary_vtk); 102 | } 103 | if (read_write_layer_id) { 104 | test_microstructure << "SCALARS LayerID short 1" << std::endl; 105 | writeTestMicrostructureData(test_microstructure, nx, ny, nz, "short", layer_id_write, write_binary_vtk); 106 | } 107 | test_microstructure.close(); 108 | 109 | // Check that fields can be initialized correctly 110 | bool found_layer_id = false; 111 | initializeData(microstructure_file, nx, ny, nz, grain_id_read, layer_id_read, phase_id_read, found_layer_id); 112 | if (read_write_layer_id) 113 | EXPECT_TRUE(found_layer_id); 114 | else 115 | EXPECT_FALSE(found_layer_id); 116 | for (int coord_z = 0; coord_z < nz; coord_z++) { 117 | for (int coord_y = 0; coord_y < ny; coord_y++) { 118 | for (int coord_x = 0; coord_x < nx; coord_x++) { 119 | EXPECT_EQ(grain_id_read(coord_z, coord_x, coord_y), grain_id_write(coord_z, coord_x, coord_y)); 120 | if (read_write_layer_id) { 121 | EXPECT_EQ(layer_id_read(coord_z, coord_x, coord_y), layer_id_write(coord_z, coord_x, coord_y)); 122 | } 123 | // For single phase w/o phase id data printed, should be initialized to zeros 124 | EXPECT_EQ(phase_id_read(coord_z, coord_x, coord_y), 0.0); 125 | } 126 | } 127 | } 128 | } 129 | 130 | TEST(TEST_CATEGORY, grain_util_tests) { 131 | // Test init for BINARY/ASCII data and 1) a case where layer_id is present, 2) a case where layer_id is not present, 132 | // and 3) a case where layer_id is present as well as a field that should be ignored by the analysis parsing 133 | std::vector layer_id_used = {true, false, true}; 134 | std::vector dummy_id_used = {false, false, true}; 135 | for (int test_num = 0; test_num < 3; test_num++) { 136 | testInitializeData(true, layer_id_used[test_num], dummy_id_used[test_num]); 137 | testInitializeData(false, layer_id_used[test_num], dummy_id_used[test_num]); 138 | } 139 | } 140 | } // end namespace Test 141 | -------------------------------------------------------------------------------- /src/CAparsefiles.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #include "CAparsefiles.hpp" 7 | 8 | #include "mpi.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | // Functions that are used to simplify the parsing of input files, either by ExaCA or related utilities 17 | 18 | //*****************************************************************************/ 19 | // Remove whitespace from "line", optional argument to take only portion of the line after position "pos" 20 | std::string removeWhitespace(std::string line, int pos) { 21 | 22 | std::string val = line.substr(pos + 1, std::string::npos); 23 | std::regex r("\\s+"); 24 | val = std::regex_replace(val, r, ""); 25 | return val; 26 | } 27 | 28 | // Check if a string is Y (true) or N (false) 29 | bool getInputBool(std::string val_input) { 30 | std::string val = removeWhitespace(val_input); 31 | if (val == "N") { 32 | return false; 33 | } 34 | else if (val == "Y") { 35 | return true; 36 | } 37 | else { 38 | std::string error = "Input \"" + val + "\" must be \"Y\" or \"N\"."; 39 | throw std::runtime_error(error); 40 | } 41 | } 42 | 43 | // Convert string "val_input" to base 10 integer 44 | int getInputInt(std::string val_input) { 45 | int IntFromString = stoi(val_input, nullptr, 10); 46 | return IntFromString; 47 | } 48 | 49 | // Convert string "val_input" to float value multiplied by 10^(factor) 50 | float getInputFloat(std::string val_input, int factor) { 51 | float FloatFromString = atof(val_input.c_str()) * pow(10, factor); 52 | return FloatFromString; 53 | } 54 | 55 | // Convert string "val_input" to double value multiplied by 10^(factor) 56 | double getInputDouble(std::string val_input, int factor) { 57 | double DoubleFromString = std::stod(val_input.c_str()) * pow(10, factor); 58 | return DoubleFromString; 59 | } 60 | 61 | // Given a string ("line"), parse at "separator" (commas used by default) 62 | // Modifies "parsed_line" to hold the separated values 63 | // expected_num_values may be larger than parsed_line_size, if only a portion of the line is being parsed 64 | void splitString(const std::string line, std::vector &parsed_line, std::size_t expected_num_values, 65 | char separator) { 66 | // Make sure the right number of values are present on the line - one more than the number of separators 67 | std::size_t actual_num_values = std::count(line.begin(), line.end(), separator) + 1; 68 | if (expected_num_values != actual_num_values) { 69 | std::string error = "Error: Expected " + std::to_string(expected_num_values) + 70 | " values while reading file; but " + std::to_string(actual_num_values) + " were found"; 71 | throw std::runtime_error(error); 72 | } 73 | // Separate the line into its components, now that the number of values has been checked 74 | std::size_t parsed_line_size = parsed_line.size(); 75 | // Make a copy that we can modify 76 | std::string line_copy = line; 77 | for (std::size_t n = 0; n < parsed_line_size - 1; n++) { 78 | std::size_t pos = line_copy.find(separator); 79 | parsed_line[n] = line_copy.substr(0, pos); 80 | line_copy = line_copy.substr(pos + 1, std::string::npos); 81 | } 82 | parsed_line[parsed_line_size - 1] = line_copy; 83 | } 84 | 85 | // Reads a line from an input file stream and outputs the components of the line split at "separator" (spaces used by 86 | // default). By default, expects 4 components of the line to separate (used in parsing vtk header data) 87 | std::vector splitString(std::ifstream &input_data_stream, std::size_t expected_num_values, 88 | char separator) { 89 | 90 | std::string line; 91 | std::vector parsed_line(expected_num_values); 92 | getline(input_data_stream, line); 93 | splitString(line, parsed_line, expected_num_values, separator); 94 | return parsed_line; 95 | } 96 | 97 | bool checkFileExists(const std::string path, const int id, const bool error) { 98 | std::ifstream stream; 99 | stream.open(path); 100 | if (!(stream.is_open())) { 101 | stream.close(); 102 | if (error) 103 | throw std::runtime_error("Could not locate/open \"" + path + "\""); 104 | else 105 | return false; 106 | } 107 | stream.close(); 108 | if (id == 0) 109 | std::cout << "Opened \"" << path << "\"" << std::endl; 110 | return true; 111 | } 112 | 113 | std::string checkFileInstalled(const std::string name, const int id) { 114 | // Path to file. Prefer installed location; if not installed use source location. 115 | std::string path = ExaCA_DATA_INSTALL; 116 | std::string file = path + "/" + name; 117 | bool files_installed = checkFileExists(file, id, false); 118 | if (!files_installed) { 119 | // If full file path, just use it. 120 | if (name.substr(0, 1) == "/") { 121 | file = name; 122 | } 123 | // If a relative path, it has to be with respect to the source path. 124 | else { 125 | path = ExaCA_DATA_SOURCE; 126 | file = path + "/" + name; 127 | } 128 | checkFileExists(file, id); 129 | } 130 | return file; 131 | } 132 | 133 | // Make sure file contains data 134 | void checkFileNotEmpty(std::string testfilename) { 135 | std::ifstream testfilestream; 136 | testfilestream.open(testfilename); 137 | std::string testline; 138 | std::getline(testfilestream, testline); 139 | if (testline.empty()) 140 | throw std::runtime_error("First line of file " + testfilename + " appears empty"); 141 | testfilestream.close(); 142 | } 143 | 144 | // Check if the temperature data is in ASCII or binary format 145 | bool checkTemperatureFileFormat(std::string tempfile_thislayer) { 146 | bool binary_input_data; 147 | std::size_t found = tempfile_thislayer.find(".catemp"); 148 | if (found == std::string::npos) 149 | binary_input_data = false; 150 | else 151 | binary_input_data = true; 152 | return binary_input_data; 153 | } 154 | 155 | // Check to make sure that the 6 expected column names appear in the correct order in the header for this temperature 156 | // file Return the number of columns present - ignore any columns after the 6 of interest 157 | std::size_t checkForHeaderValues(std::string header_line) { 158 | 159 | // Header values from file - number of commas plus one is the size of the header 160 | std::size_t header_size = std::count(header_line.begin(), header_line.end(), ',') + 1; 161 | std::vector header_values(header_size, ""); 162 | splitString(header_line, header_values, header_size); 163 | 164 | std::vector> expected_values = {{"x"}, {"y"}, {"z"}, {"tm"}, {"tl", "ts"}, {"r", "cr"}}; 165 | std::size_t num_expected_values = expected_values.size(); 166 | if (num_expected_values > header_size) 167 | throw std::runtime_error("Error: Fewer values than expected found in temperature file header"); 168 | 169 | // Case insensitive comparison 170 | for (std::size_t n = 0; n < num_expected_values; n++) { 171 | auto val = removeWhitespace(header_values[n]); 172 | std::transform(val.begin(), val.end(), val.begin(), ::tolower); 173 | // Check each header column label against the expected value(s) - throw error if no match 174 | std::size_t options_size = expected_values[n].size(); 175 | for (std::size_t e = 0; e < options_size; e++) { 176 | auto ev = expected_values[n][e]; 177 | if (val == ev) 178 | break; 179 | else if (e == options_size - 1) 180 | throw std::runtime_error(ev + " not found in temperature file header"); 181 | } 182 | } 183 | return header_size; 184 | } 185 | 186 | // Read and discard "n_lines" lines of data from the file 187 | void skipLines(std::ifstream &input_data_stream, const int n_lines) { 188 | std::string dummy_str; 189 | for (int line = 0; line < n_lines; line++) 190 | getline(input_data_stream, dummy_str); 191 | } 192 | -------------------------------------------------------------------------------- /analysis/README.md: -------------------------------------------------------------------------------- 1 | # ExaCA grain analysis post-processing 2 | 3 | ## Running the grain_analysis executable 4 | Running the `ExaCA-GrainAnalysis` executable after generation of an ExaCA data set (i.e., a .vtk file that at minimum contains the field `GrainID`, and the associated .json file of log info) allows additional insights into the microstructure generated. When running the analysis script, the path to and name of an associated analysis inputs file, as well as the path to and base name of the microstructure to be analyzed, should be given on the command line. For example: 5 | 6 | ``` 7 | ./build/install/bin/ExaCA-GrainAnalysis analysis/examples/AnalyzeDirS.txt TestProblemDirS 8 | ``` 9 | 10 | The analysis files, such as `examples/AnalyzeDirS.json`, allow analysis of multiple regions of the microstructure. Under the top level header `Regions`, the user-specified names of the regions for analysis are given (in the case of `examples/AnalyzeDirS.json`, these are `RepresentativeVolume`, `XYCross`, and `YZCross`). At the third level, analysis options for each individual region are given. 11 | 12 | 1D, 2D, and 3D regions can be analyzed depending on the bounds provided. The `units` input for each region should be either Meters or Cells, depending on the values used as the bounds. For example, if `xBounds`, `yBounds`, and `zBounds` are all provided (in the form `[lower, upper]`), and the lower and upper bounds for each direction do not match, the region is analyzed as a volume. If one direction has equivalent lower and upper bounds, the region is analyzed as an area, and if two directions have equivalent lower and upper bounds, the region is analyzed as a line. If no bounds are given for a direction, the analysis will default to including the entire domain extent in said direction. 13 | 14 | Once the bounds of each region are identified, the analysis options can be specified within JSON arrays under `printAvgStats`, `printPerGrainStats`, and `printPerZCoordinateStats`. 15 | * Values specified in `printStats` will print average quantities to the console as well as to a file names `[MicrostructureBaseFilename]_[RegionName]_QoIs.txt` 16 | * Values specified in `printPerGrainStats` will print data for each individual grain ID to a csv file of per-grain data named `[MicrostructureBaseFilename]_[RegionName]_grains.csv` 17 | * Values specified in `printPerZCoordinateStats` will be printed in additional separate files. 18 | 19 | | Output | Compatible options | Details | 20 | | --------------------- | -------------------------------- | ------------------- | 21 | | GrainTypeFractions | printAvgStats | Prints the fraction of the region consisting of nucleated grains, and the fraction that did not undergo melting 22 | | Misorientation | printAvgStats/printPerGrainStats | Prints the misorientation of the grain's <001> directions with the cardinal directions 23 | | Size | printAvgStats/printPerGrainStats | Prints the grain size (length in microns, area in square microns, or volume in cubic microns, depending on the dimensionality of the region) 24 | | BuildTransAspectRatio | printAvgStats/printPerGrainStats | Prints the grain aspect ratio, calculated as the extent of the grain in the build (Z) direction divided by the average of the extents in the X and Y directions 25 | | XExtent | printAvgStats/printPerGrainStats | Prints the extent of the grain (in microns) in the X direction 26 | | YExtent | printAvgStats/printPerGrainStats | Prints the extent of the grain (in microns) in the Y direction 27 | | ZExtent | printAvgStats/printPerGrainStats | Prints the extent of the grain (in microns) in the Z direction 28 | | IPFZ-RGB | printPerGrainStats | Prints the R,G,B values (each between 0 and 1) corresponding to the inverse pole figure mapping of the grain orientation, relative to the build (Z) direction 29 | | MeanGrainArea | printPerZCoordinateStats | Prints the mean grain cross-sectional (XY) area for each Z coordinate in the simulation to a file `[MicrostructureBaseFilename]_GrainAreas.csv` 30 | | MeanWeightedGrainArea | printPerZCoordinateStats | Prints the mean grain cross-sectional (XY) area, weighted by the grain area itself, for each 5th Z coordinate in the simulation to a file `[MicrostructureBaseFilename]_WeightedGrainAreas.csv` (Note: this option will be removed in a future release) 31 | 32 | Additional analysis options for certain region types can be specified by setting them to `true` in the analysis input file (if the option does not appear in the input file, it is turned off by default) 33 | 34 | | Output | Compatible options | Details | 35 | | --------------------------- | --------------------- | ------------------- | 36 | | PrintExaConstitYN | volume | Prints the grain ID data into an RVE usable by ExaConstit for constitutive properties simulation 37 | | PrintPoleFigureYN | area/volume | Prints the grain orientation frequency data to a file which can be further analyzed in Matlab to generate pole figure and inverse pole figure data using the MTEX library 38 | | PrintInversePoleFigureMapYN | area | Prints the grain euler angle data as a function of location in the cross-section to a file which can be further analyzed in Matlab to map the orientations to inverse pole figure-colored values (EBSD-like) using the MTEX library 39 | 40 | ## MATLAB post-processing 41 | The pole figure data and inverse pole figure coloring data generated from Section 2 cross-sections or the volume in Section 3 can be plotted using Matlab and the MTEX toolbox (https://mtex-toolbox.github.io/) using the scripts and colormaps located in the `utilities/MTEX` folder. Those files are as follows: 42 | 43 | * `PlotPoleFigure.m` takes an appropriate input file from the analysis post-processing script and outputs pole figures for user-specified crystal planes and inverse pole figures for user-specified cartesian directions. The inputs are: 44 | * MTEXFile: The name of the output file from ExaCA's analysis routine (should end in 'PoleFigureData.txt') containing data from which pole figures and inverse pole figures will be constructed 45 | * ijk_vals: A cell array of (i,j,k) values for the crystal planes that correspond to the desired pole figures. For example, an input of '{[0 0 1],[1 1 0]}' will create figures for the (001) and (110) pole figures, an input of {[0 0 1]} will create a plot just for the (001) pole figure, and an empty cell array {} will skip pole figure generation. 46 | * xyz_vals: An array of directions for which inverse pole figures will be plotted. For example, an input of ['x','y','z'] will create inverse pole figures for the x, y, and z directions, an input of ['z'] will create a pole figure just for the z direction, and an empty array [] will skip inverse pole figure generation. 47 | * ColormapFile: The file mapping colors to multiples of uniform distribution for the figures 48 | * ColormapUpperLimit: The upper limit of the colormap (lower limit is always 0) 49 | * `PlotIPFColoredSection.m` takes an appropriate input file from the analysis post-processing script, smooths the grain structure data, and plots the microstructure colored using the inverse pole figure X, Y, and Z maps (cubic crystal geometry). For cross-sections containing two solidification phases, a map of the as-solidified phase will also be plotted. The inputs are 50 | * MTEXFile: The name of the output file from ExaCA's analysis routine (should end in 'IPFCrossSectionData.txt') containing data from which the inverse pole figure-mapped grain structure will be constructed. 51 | * Phaselist: Provided only for simulations where two solidification phases were present (i.e., more than one interfacial response function was present in the ExaCA simulation's `Materials` input file), consists of a Matlab cell array giving the names for the primary and secondary solidification phase. For example, if a two-phase solidification problem was simulated using the `Materials` input file `SS316L_AusteniteFerrite.json`, this argument would be ["austenite","ferrite"]. 52 | * `ColorMap4.m` and `ColorMap8.m` are example colormap files to be used as an input for `PlotPoleFigure.m` (note that the appropriate corresponding upper limits of 4 and 8, respectively, should be used as inputs to `PlotPoleFigure.m` as well) 53 | 54 | Three MTEX files resulting from running the ExaCA and analysis executables for the directional solidification example problem can be accessed at https://github.com/LLNL/ExaCA-Data and used as test input in these post-processing scripts. 55 | -------------------------------------------------------------------------------- /analysis/src/GAutils.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #ifndef GA_UTIL_HPP 7 | #define GA_UTIL_HPP 8 | 9 | #include "CAparsefiles.hpp" 10 | 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | // These are used in reading/parsing ExaCA microstructure data 24 | void parseLogFile(std::string logfile, int &nx, int &ny, int &nz, double &deltax, int &number_of_layers, 25 | std::vector &xyz_bounds, std::vector &grain_unit_vector_file, 26 | std::vector &phase_names, int &num_phases, bool orientation_files_in_input); 27 | double convertToMicrons(double deltax, std::string region_type); 28 | double convertToCells(double deltax, std::string region_type); 29 | void dualPrint(std::string temp, std::ostream &stream1, std::ostream &stream2); 30 | template 31 | ReturnType divideCast(FirstType int1, SecondType int2) { 32 | return static_cast(int1) / static_cast(int2); 33 | } 34 | 35 | template 36 | void initializeData(std::string microstructure_file, int nx, int ny, int nz, ViewTypeInt3dHost &grain_id, 37 | ViewTypeShort3dHost &layer_id, ViewTypeShort3dHost &phase_id, bool &found_layer_id) { 38 | 39 | std::ifstream input_data_stream; 40 | input_data_stream.open(microstructure_file); 41 | if (!(input_data_stream)) 42 | throw std::runtime_error("Error: Cannot find ExaCA microstructure file"); 43 | std::string line; 44 | bool binary_vtk = false; 45 | // 8 header lines at beginning of Paraview file from header 46 | // 3rd line tells whether data is in ASCII or binary format 47 | for (int header_lines = 0; header_lines < 8; header_lines++) { 48 | getline(input_data_stream, line); 49 | if (header_lines == 2) 50 | if (line.find("BINARY") != std::string::npos) 51 | binary_vtk = true; 52 | } 53 | bool reading_vtk = true; 54 | bool found_grain_id = false; 55 | bool found_phase_id = false; 56 | while (reading_vtk) { 57 | // This line says which variable appears next in the file, along with its type 58 | // A blank line ends the file read 59 | std::string read_datatype_string, read_fieldname; 60 | getline(input_data_stream, line); 61 | if (line.empty()) 62 | reading_vtk = false; 63 | else { 64 | // Thus far, every ExaCA field printed to VTK files has been one of these three types - ensure that this 65 | // field is one of them 66 | std::vector possible_vtk_datatypes = {"short", "int", "float"}; 67 | int num_possible_vtk_types = possible_vtk_datatypes.size(); 68 | for (auto n = 0; n < num_possible_vtk_types; n++) { 69 | if (line.find(possible_vtk_datatypes[n]) != std::string::npos) 70 | read_datatype_string = possible_vtk_datatypes[n]; 71 | } 72 | if (read_datatype_string.empty()) 73 | throw std::runtime_error("Error: Unknown data type for a field in the vtk file"); 74 | 75 | // grain_id is only fields currently used by the analysis, other fields will be skipped/ignored 76 | std::vector possible_fieldnames = {"GrainID", "LayerID", "PhaseID"}; 77 | int num_possible_fieldnames = possible_fieldnames.size(); 78 | for (auto n = 0; n < num_possible_fieldnames; n++) { 79 | if (line.find(possible_fieldnames[n]) != std::string::npos) 80 | read_fieldname = possible_fieldnames[n]; 81 | } 82 | if (read_fieldname.empty()) { 83 | std::cout << "Reading and ignoring field described by " << line << std::endl; 84 | // 1 more unused line 85 | getline(input_data_stream, line); 86 | if (binary_vtk) { 87 | if (read_datatype_string == "short") 88 | readIgnoreBinaryField(input_data_stream, nx, ny, nz); 89 | else if (read_datatype_string == "int") 90 | readIgnoreBinaryField(input_data_stream, nx, ny, nz); 91 | else if (read_datatype_string == "float") 92 | readIgnoreBinaryField(input_data_stream, nx, ny, nz); 93 | } 94 | else 95 | readIgnoreASCIIField(input_data_stream, nz); 96 | } 97 | else { 98 | // Valid fieldname to be read 99 | // 1 more unused line 100 | getline(input_data_stream, line); 101 | // Place grain_id data and (optionally) layer_id data 102 | if (read_fieldname == possible_fieldnames[0]) { 103 | // grain_id data should be type int 104 | if (read_datatype_string != "int") 105 | throw std::runtime_error("Error: Field GrainID should be data of type int"); 106 | if (binary_vtk) 107 | grain_id = readBinaryField, int>(input_data_stream, nx, 108 | ny, nz, "GrainID"); 109 | else 110 | grain_id = readASCIIField>(input_data_stream, nx, ny, 111 | nz, "GrainID"); 112 | found_grain_id = true; 113 | } 114 | else if (read_fieldname == possible_fieldnames[1]) { 115 | // layer_id may be int or short, but is stored as type short 116 | if ((read_datatype_string != "int") && (read_datatype_string != "short")) 117 | throw std::runtime_error("Error: Field LayerID should be data of type int or short"); 118 | if (!binary_vtk) 119 | layer_id = readASCIIField>(input_data_stream, nx, ny, 120 | nz, "LayerID"); 121 | else { 122 | if (read_datatype_string == "int") 123 | layer_id = readBinaryField, int>( 124 | input_data_stream, nx, ny, nz, "LayerID"); 125 | else 126 | layer_id = readBinaryField, short>( 127 | input_data_stream, nx, ny, nz, "LayerID"); 128 | } 129 | found_layer_id = true; 130 | } 131 | else if (read_fieldname == possible_fieldnames[2]) { 132 | if (!binary_vtk) 133 | phase_id = readASCIIField>(input_data_stream, nx, ny, 134 | nz, "PhaseID"); 135 | else { 136 | phase_id = readBinaryField, short>( 137 | input_data_stream, nx, ny, nz, "PhaseID"); 138 | } 139 | found_phase_id = true; 140 | } 141 | std::cout << "Data field " << read_fieldname << " read" << std::endl; 142 | } 143 | } 144 | } 145 | input_data_stream.close(); 146 | if (!found_grain_id) 147 | throw std::runtime_error("Error: analysis requires the GrainID field to be present in the vtk file"); 148 | if (!found_layer_id) { 149 | std::cout << "Note: LayerID not present in vtk data, analysis will not differentiate between cells that did " 150 | "and did not undergo melting" 151 | << std::endl; 152 | Kokkos::deep_copy(layer_id, 0); 153 | } 154 | // PhaseID defaults to zeros if not present in the file (assumed single as-solidified phase) 155 | if (!found_phase_id) 156 | Kokkos::deep_copy(phase_id, 0); 157 | } 158 | 159 | #endif 160 | -------------------------------------------------------------------------------- /src/CAinputdata.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #ifndef EXACA_INPUTDATA_HPP 7 | #define EXACA_INPUTDATA_HPP 8 | 9 | #include "CAinfo.hpp" 10 | #include "CAtimers.hpp" 11 | 12 | #include "mpi.h" 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | // Error if this is not a valid simulation type. 22 | // "Directional": directional solidification 23 | // "Spot": hemispherical spot with fixed thermal gradient and cooling rate 24 | // "FromFile": time-temperature history comes from external files 25 | // "FromFinch": from Finch heat transport run 26 | inline void validSimulationType(std::string simulation_type) { 27 | if (simulation_type != "Directional" && simulation_type != "Spot" && simulation_type != "SingleGrain" && 28 | simulation_type != "FromFile" && simulation_type != "FromFinch") 29 | throw std::runtime_error("Error: unknown problem type \"" + simulation_type + "\"."); 30 | } 31 | 32 | // Structs to organize data within inputs struct 33 | struct DomainInputs { 34 | double deltax = 0.0, deltat = 0.0; 35 | // number of CA cells in each direction only initialized here for problem types Directional, Spot, and SingleGrain 36 | int nx = 0, ny = 0, nz = 0; 37 | // multilayer problems only 38 | int number_of_layers = 1, layer_height = 0; 39 | // problem type Spot only 40 | int spot_radius = 0; 41 | }; 42 | 43 | struct NucleationInputs { 44 | // unused for single grain problem type, zero by default 45 | double n_max = 0.0; 46 | double dtn = 0.0; 47 | double dtsigma = 0.0; 48 | }; 49 | 50 | struct InterfacialResponseInputs { 51 | int num_phases = 1; 52 | std::vector phase_names; 53 | float freezing_range[2]; 54 | float A[2]; 55 | float B[2]; 56 | float C[2]; 57 | float D[2] = {0.0, 0.0}; 58 | enum IRFtypes { 59 | cubic = 0, 60 | quadratic = 1, 61 | power = 2, 62 | exponential = 3, 63 | }; 64 | enum Transformationtypes { none = 0, solidification = 1 }; 65 | int function[2] = {cubic, cubic}; 66 | int transformation = none; 67 | bool velocity_cap[2] = {false, false}; 68 | }; 69 | 70 | struct TemperatureInputs { 71 | // Used for problem type FromFile (by default, all temperature files read during init) 72 | bool layerwise_temp_read = false; 73 | int temp_files_in_series = 0; 74 | std::vector temp_paths; 75 | // Use for problem types other than FromFinch and FromFile (no temperature files to read) - default to no initial 76 | // undercooling at solidification front 77 | double G = 0, R = 0; 78 | double init_undercooling = 0.0; 79 | // Used for FromFinch and FromFile problem types with translated temperature data 80 | bool trim_unmelted_region = false; 81 | bool use_fixed_x_bounds = false, use_fixed_y_bounds = false; 82 | std::vector temperature_x_bounds = {std::numeric_limits::lowest(), 83 | std::numeric_limits::max()}; 84 | std::vector temperature_y_bounds = {std::numeric_limits::lowest(), 85 | std::numeric_limits::max()}; 86 | int number_of_copies = 1; 87 | double x_offset = 0.0, y_offset = 0.0; 88 | double temporal_offset = 0.0; 89 | bool mirror_x = false, mirror_y = false; 90 | }; 91 | 92 | struct SubstrateInputs { 93 | // problem type Directional only 94 | std::string surface_init_mode = ""; 95 | // Only used for mode (i) 96 | double fract_surface_sites_active = 0.0; 97 | // Only used for mode (ii) 98 | double surface_site_density = 0.0; 99 | // Only used for mode (iii) 100 | std::vector grain_locations_x, grain_locations_y, grain_ids; 101 | bool fill_bottom_surface = false; 102 | // problem type SingleGrain only 103 | int single_grain_orientation = 0; 104 | // problem types Spot and FromFile only 105 | bool use_substrate_file = false; 106 | bool baseplate_through_powder = false; 107 | std::string substrate_filename = ""; 108 | double baseplate_grain_spacing = 0.0; 109 | double powder_grain_spacing = 1.0; 110 | // Top of baseplate assumed at Z = 0 if not otherwise given 111 | double baseplate_top_z = 0.0; 112 | // Bottom of baseplate assumed to be the smallest Z with associated temperature data if not otherwise given 113 | bool use_fixed_z_bounds = false; 114 | double baseplate_bottom_z = std::numeric_limits::max(); 115 | // Initial size of octahedra during initialization of an active cell 116 | float init_oct_size = 0.01; 117 | }; 118 | 119 | struct PrintInputs { 120 | // Base name of CA output 121 | std::string base_filename = ""; 122 | // Path to CA output 123 | std::string path_to_output = ""; 124 | // List of valid print outputs and whether or not they are required 125 | std::vector print_field_label = {"PathToOutput", "OutputFile", "PrintFrontUndercooling", 126 | "PrintBinary", "PrintExaConstitSize", "Intralayer", 127 | "Interlayer"}; 128 | std::vector required_print_field = {true, true, false, false, false, false, false}; 129 | 130 | // Names of output fields that can be printed to files during or at the end of a simulation 131 | std::vector fieldnames_key = {"GrainID", 132 | "LayerID", 133 | "PhaseID", 134 | "GrainMisorientation", 135 | "UndercoolingCurrent", 136 | "UndercoolingSolidificationStart", 137 | "MeltPoolEdge", 138 | "MeltTimeStep", 139 | "CritTimeStep", 140 | "UndercoolingChange", 141 | "CellType", 142 | "DiagonalLength", 143 | "SolidificationEventCounter", 144 | "NumberOfSolidificationEvents"}; 145 | // Fields to be printed during a given layer 146 | bool intralayer = false; 147 | int intralayer_increment = 1; 148 | bool intralayer_idle_frames = false; 149 | bool intralayer_non_misorientation_fields = false; 150 | bool intralayer_grain_id = false; 151 | bool intralayer_layer_id = false; 152 | bool intralayer_phase_id = false; 153 | bool intralayer_grain_misorientation = false; 154 | bool intralayer_undercooling_current = false; 155 | bool intralayer_undercooling_solidification_start = false; 156 | bool intralayer_melt_time_step = false; 157 | bool intralayer_crit_time_step = false; 158 | bool intralayer_undercooling_change = false; 159 | bool intralayer_cell_type = false; 160 | bool intralayer_diagonal_length = false; 161 | bool intralayer_solidification_event_counter = false; 162 | bool intralayer_number_of_solidification_events = false; 163 | bool intralayer_melt_pool_edge = false; 164 | // Fields to be printed at end of a layer 165 | bool interlayer_full = false; 166 | bool interlayer_current = false; 167 | bool interlayer_grain_id = false; 168 | bool interlayer_phase_id = false; 169 | bool interlayer_layer_id = false; 170 | bool interlayer_grain_misorientation = false; 171 | bool interlayer_undercooling_solidification_start = false; 172 | bool interlayer_undercooling_current = false; 173 | bool interlayer_melt_time_step = false; 174 | bool interlayer_crit_time_step = false; 175 | bool interlayer_undercooling_change = false; 176 | bool interlayer_cell_type = false; 177 | bool interlayer_diagonal_length = false; 178 | bool interlayer_solidification_event_counter = false; 179 | bool interlayer_number_of_solidification_events = false; 180 | bool interlayer_melt_pool_edge = false; 181 | // True if intralayer_undercooling_solidification_start or interlayer_undercooling_solidification_start is true 182 | bool store_solidification_start = false; 183 | bool print_front_undercooling = false; 184 | // True if intralayer_melt_pool_edge or interlayer_melt_pool_edge is true 185 | bool store_melt_pool_edge = false; 186 | // List of layers following which the interlayer fields should be printed (will always include final layer of 187 | // simulation) 188 | std::vector print_layer_number; 189 | 190 | // Should binary be used for printing vtk data? 191 | bool print_binary = false; 192 | 193 | // Should the default RVE data for ExaConstit be printed? If so, with what size? 194 | bool print_default_rve = false; 195 | bool skip_all_printing = false; 196 | int rve_size = 0; 197 | }; 198 | 199 | #endif 200 | -------------------------------------------------------------------------------- /unit_test/tstGrid.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #include 7 | 8 | #include "CAgrid.hpp" 9 | #include "CAinputs.hpp" 10 | #include "CAprint.hpp" 11 | 12 | #include 13 | 14 | #include "mpi.h" 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | namespace Test { 21 | //---------------------------------------------------------------------------// 22 | // activedomainsizecalc 23 | //---------------------------------------------------------------------------// 24 | void testCalcZLayerBottom() { 25 | 26 | // Default initialized inputs and grid structs 27 | Inputs inputs; 28 | int number_of_layers_temp = 10; 29 | Grid grid(number_of_layers_temp); 30 | 31 | // Manually set layer info 32 | grid.layer_height = 10; 33 | grid.deltax = 1 * pow(10, -6); 34 | grid.z_min = -0.5 * pow(10, -6); 35 | 36 | // Test for simulation type "Spot" 37 | int z_layer_bottom = grid.calcZLayerBottom("Spot", 0); 38 | 39 | // Call function for each layernumber with simulation type and "FromFile" 40 | EXPECT_EQ(z_layer_bottom, 0); 41 | for (int layernumber = 0; layernumber < grid.number_of_layers; layernumber++) { 42 | // Set z_min_layer for each layer to be offset by layer_height cells from the previous one (lets solution for 43 | // both problem types by the same) 44 | grid.z_min_layer(layernumber) = grid.z_min + layernumber * grid.layer_height * grid.deltax; 45 | int z_layer_bottom = grid.calcZLayerBottom("FromFile", layernumber); 46 | EXPECT_EQ(z_layer_bottom, grid.layer_height * layernumber); 47 | } 48 | } 49 | 50 | void testCalcZLayerTop() { 51 | 52 | // Default initialized inputs and grid structs with manually set values for tests 53 | Inputs inputs; 54 | inputs.domain.layer_height = 10; 55 | int number_of_layers_temp = 10; 56 | Grid grid(number_of_layers_temp); 57 | grid.z_min = 0.5 * pow(10, -6); 58 | grid.deltax = 1.0 * pow(10, -6); 59 | for (int layernumber = 0; layernumber < number_of_layers_temp; layernumber++) { 60 | grid.z_max_layer(layernumber) = grid.z_min + grid.deltax * inputs.domain.layer_height; 61 | } 62 | grid.nz = 111; 63 | for (int layernumber = 0; layernumber < grid.number_of_layers; layernumber++) { 64 | // Set ZMaxLayer for each layer to be offset by layer_height cells from the previous one, with layer 0 having a 65 | // z_max_layer value of z_min + spot_radius (lets solution for both problem types be the same) 66 | // Call function for each layernumber for simulation types "FromFile" 67 | int z_layer_top_R = grid.calcZLayerTop("FromFile", layernumber); 68 | EXPECT_EQ(z_layer_top_R, (grid.z_max_layer(layernumber) - grid.z_min) / grid.deltax); 69 | // For simulation type Directional, should be independent of layernumber 70 | int z_layer_top_C = grid.calcZLayerTop("Directional", layernumber); 71 | EXPECT_EQ(z_layer_top_C, grid.nz - 1); 72 | int z_layer_top_S = grid.calcZLayerTop("Spot", layernumber); 73 | EXPECT_EQ(z_layer_top_S, grid.nz - 1); 74 | } 75 | } 76 | 77 | void testCalcNzLayer() { 78 | 79 | int id = 0; 80 | Inputs inputs; 81 | int number_of_layers_temp = 10; 82 | Grid grid(number_of_layers_temp); 83 | grid.z_layer_bottom = 5; 84 | for (int layernumber = 0; layernumber < grid.number_of_layers; layernumber++) { 85 | grid.z_layer_top = 6 + layernumber; 86 | int nz_layer = grid.calcNzLayer(id, layernumber); 87 | EXPECT_EQ(nz_layer, 2 + layernumber); 88 | } 89 | } 90 | 91 | void testCalcDomainSize() { 92 | 93 | Grid grid; 94 | grid.nx = 5; 95 | grid.ny_local = 4; 96 | grid.nz_layer = 10; 97 | int domain_size = grid.calcDomainSize(); 98 | EXPECT_EQ(domain_size, 10 * 5 * 4); 99 | } 100 | 101 | //---------------------------------------------------------------------------// 102 | // bounds_init_test 103 | //---------------------------------------------------------------------------// 104 | void testFindXYZBounds(bool test_binary_input_read, bool use_fixed_z) { 105 | 106 | int id, np; 107 | // Get number of processes 108 | MPI_Comm_size(MPI_COMM_WORLD, &np); 109 | // Get individual process ID 110 | MPI_Comm_rank(MPI_COMM_WORLD, &id); 111 | 112 | // Write fake OpenFOAM data - temperature data should be of type double 113 | const int nx = 4; 114 | const int ny = 8; 115 | const int nz = 3; 116 | double deltax = 1 * pow(10, -6); 117 | std::string test_filename = "TestData"; 118 | if (test_binary_input_read) 119 | test_filename = test_filename + ".catemp"; 120 | else 121 | test_filename = test_filename + ".txt"; 122 | if (id == 0) { 123 | std::ofstream test_data_stream; 124 | if (test_binary_input_read) 125 | test_data_stream.open(test_filename, std::ios::out | std::ios::binary); 126 | else { 127 | test_data_stream.open(test_filename); 128 | test_data_stream << "x, y, z, tm, tl, cr" << std::endl; 129 | } 130 | // only x,y,z data should be read, tm, tl, cr should not affect result 131 | for (int k = 0; k < nz; k++) { 132 | for (int j = 0; j < ny; j++) { 133 | for (int i = 0; i < nx; i++) { 134 | if (test_binary_input_read) { 135 | writeData(test_data_stream, static_cast(i * deltax), test_binary_input_read); 136 | writeData(test_data_stream, static_cast(j * deltax), test_binary_input_read); 137 | writeData(test_data_stream, static_cast(k * deltax), test_binary_input_read); 138 | writeData(test_data_stream, static_cast(-1.0), test_binary_input_read); 139 | writeData(test_data_stream, static_cast(-1.0), test_binary_input_read); 140 | writeData(test_data_stream, static_cast(-1.0), test_binary_input_read); 141 | } 142 | else 143 | test_data_stream << i * deltax << "," << j * deltax << "," << k * deltax << "," 144 | << static_cast(-1.0) << "," << static_cast(-1.0) << "," 145 | << static_cast(-1.0) << std::endl; 146 | } 147 | } 148 | } 149 | test_data_stream.close(); 150 | } 151 | MPI_Barrier(MPI_COMM_WORLD); 152 | 153 | // Set up grid 154 | Inputs inputs; 155 | inputs.temperature.temp_files_in_series = 1; 156 | inputs.temperature.temp_paths.push_back(test_filename); 157 | inputs.domain.deltax = deltax; 158 | inputs.domain.layer_height = 2; 159 | inputs.domain.number_of_layers = 2; 160 | inputs.substrate.use_fixed_z_bounds = use_fixed_z; 161 | if (use_fixed_z) { 162 | // Should drop the z min value of the domain by one cell spacing, and increase the nz value by 1 163 | inputs.substrate.baseplate_bottom_z = -deltax; 164 | } 165 | 166 | // Fill grid struct 167 | Grid grid("FromFile", id, np, inputs.domain.number_of_layers, inputs.domain, inputs.substrate, inputs.temperature); 168 | 169 | EXPECT_DOUBLE_EQ(grid.x_min, 0.0); 170 | EXPECT_DOUBLE_EQ(grid.y_min, 0.0); 171 | if (use_fixed_z) 172 | EXPECT_DOUBLE_EQ(grid.z_min, -1.0 * pow(10, -6)); 173 | else 174 | EXPECT_DOUBLE_EQ(grid.z_min, 0.0); 175 | EXPECT_DOUBLE_EQ(grid.x_max, (nx - 1) * deltax); 176 | EXPECT_DOUBLE_EQ(grid.y_max, (ny - 1) * deltax); 177 | // z_max is equal to the largest Z coordinate in the file, offset by layer_height cells in the build direction due 178 | // to the second layer 179 | EXPECT_DOUBLE_EQ(grid.z_max, 4 * grid.deltax); 180 | // Bounds for each individual layer - 2nd layer offset by layer_height cells from the first 181 | EXPECT_DOUBLE_EQ(grid.z_min_layer(0), 0.0); 182 | EXPECT_DOUBLE_EQ(grid.z_max_layer(0), (nz - 1) * deltax); 183 | EXPECT_DOUBLE_EQ(grid.z_min_layer(1), (nz - 1) * deltax); 184 | EXPECT_DOUBLE_EQ(grid.z_max_layer(1), (nz - 1 + inputs.domain.layer_height) * deltax); 185 | // Size of overall domain 186 | EXPECT_EQ(grid.nx, nx); 187 | EXPECT_EQ(grid.ny, ny); 188 | if (use_fixed_z) 189 | EXPECT_EQ(grid.nz, nz + inputs.domain.layer_height + 1); 190 | else 191 | EXPECT_EQ(grid.nz, nz + inputs.domain.layer_height); 192 | } 193 | 194 | //---------------------------------------------------------------------------// 195 | // RUN TESTS 196 | //---------------------------------------------------------------------------// 197 | TEST(TEST_CATEGORY, activedomainsizecalc) { 198 | testCalcZLayerBottom(); 199 | testCalcZLayerTop(); 200 | testCalcNzLayer(); 201 | testCalcDomainSize(); 202 | } 203 | TEST(TEST_CATEGORY, bounds_init_test) { 204 | // reading temperature files to obtain xyz bounds, using binary/non-binary format and with/without the bottom Z of 205 | // the domain fixed via the BaseplateBottomZ input 206 | testFindXYZBounds(false, false); 207 | testFindXYZBounds(true, false); 208 | testFindXYZBounds(false, true); 209 | } 210 | } // end namespace Test 211 | -------------------------------------------------------------------------------- /src/runCA.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #ifndef RUNCA_HPP 7 | #define RUNCA_HPP 8 | 9 | #include "ExaCA.hpp" 10 | 11 | #include "mpi.h" 12 | 13 | #include 14 | #include 15 | 16 | template 17 | void runExaCA(int id, int np, Inputs inputs, Timers timers, Grid grid, Temperature temperature) { 18 | 19 | // Run on the default space. 20 | using memory_space = MemorySpace; 21 | 22 | std::string simulation_type = inputs.simulation_type; 23 | 24 | // Material response function 25 | InterfacialResponseFunction irf(inputs.domain.deltat, grid.deltax, inputs.irf); 26 | 27 | // Read temperature data if necessary 28 | if (simulation_type == "FromFile") 29 | temperature.readTemperatureData(id, grid, 0); 30 | // Initialize the temperature fields for the simulation type of interest 31 | if ((simulation_type == "Directional") || (simulation_type == "SingleGrain")) 32 | temperature.initialize(id, simulation_type, grid, inputs.domain.deltat); 33 | else if (simulation_type == "Spot") 34 | temperature.initialize(id, grid, irf.freezingRange(), inputs.domain.deltat, inputs.domain.spot_radius); 35 | else if ((simulation_type == "FromFile") || (simulation_type == "FromFinch")) 36 | temperature.initialize(0, id, grid, irf.freezingRange(), inputs.domain.deltat, simulation_type); 37 | MPI_Barrier(MPI_COMM_WORLD); 38 | 39 | // Initialize grain orientations 40 | Orientation orientation(id, inputs.grain_orientation_file, false, inputs.rng_seed, 41 | inputs.irf.num_phases, irf.solidificationTransformation()); 42 | MPI_Barrier(MPI_COMM_WORLD); 43 | 44 | // Initialize cell types, grain IDs, and layer IDs 45 | CellData celldata(grid, inputs.substrate, inputs.print.store_melt_pool_edge); 46 | if (simulation_type == "Directional") 47 | celldata.initSubstrate(id, grid, inputs.rng_seed); 48 | else if (simulation_type == "SingleGrain") 49 | celldata.initSubstrate(id, grid); 50 | else 51 | celldata.initSubstrate(id, grid, inputs.rng_seed, temperature.number_of_solidification_events); 52 | MPI_Barrier(MPI_COMM_WORLD); 53 | 54 | // Variables characterizing the active cell region within each rank's grid, including buffers for ghost node data 55 | // (fixed size) and the steering vector/steering vector size on host/device 56 | Interface interface(id, grid.domain_size, inputs.substrate.init_oct_size); 57 | MPI_Barrier(MPI_COMM_WORLD); 58 | 59 | // Nucleation data structure, containing views of nuclei locations, time steps, and ids, and nucleation event 60 | // counters - initialized with an estimate on the number of nuclei in the layer Without knowing 61 | // estimated_nuclei_this_rank_this_layer yet, initialize nucleation data structures to estimated sizes, resize 62 | // inside of placeNuclei when the number of nuclei per rank is known 63 | int estimated_nuclei_this_rank_this_layer = inputs.nucleation.n_max * pow(grid.deltax, 3) * grid.domain_size; 64 | Nucleation nucleation(estimated_nuclei_this_rank_this_layer, inputs.nucleation, 65 | celldata.num_prior_nuclei); 66 | // Fill in nucleation data structures, and assign nucleation undercooling values to potential nucleation events 67 | // Potential nucleation grains are only associated with liquid cells in layer 0 - they will be initialized for each 68 | // successive layer when layer 0 is complete 69 | nucleation.placeNuclei(temperature, irf, inputs.rng_seed, 0, grid, id); 70 | 71 | // Initialize printing struct from inputs 72 | Print print(grid, np, inputs.print); 73 | 74 | // End of initialization 75 | timers.stopInit(); 76 | MPI_Barrier(MPI_COMM_WORLD); 77 | 78 | int cycle = 0; 79 | timers.startRun(); 80 | for (int layernumber = 0; layernumber < grid.number_of_layers; layernumber++) { 81 | 82 | int x_switch = 0; 83 | timers.startLayer(); 84 | 85 | // Loop continues until all liquid cells claimed by solid grains, and no solid cells undergo remelting 86 | do { 87 | 88 | // Start of time step - optional print current state of ExaCA simulation (up to and including the current 89 | // layer's data) 90 | print.printIntralayer(id, np, layernumber, inputs.domain.deltat, cycle, grid, celldata, temperature, 91 | interface, orientation); 92 | cycle++; 93 | 94 | // Cells with a successful nucleation event are marked and added to a steering vector, later dealt with in 95 | // cellCapture 96 | timers.startNucleation(); 97 | nucleation.nucleateGrain(cycle, grid, celldata, interface); 98 | timers.stopNucleation(); 99 | 100 | // Cells that have a successful nucleation event, and other cells that are at the solid-liquid interface are 101 | // added to a steering vector. Logic in fillSteeringVector_NoRemelt is a simpified version of 102 | // fillSteeringVector_Remelt 103 | timers.startSV(); 104 | if ((simulation_type == "Directional") || (simulation_type == "SingleGrain")) 105 | fillSteeringVector_NoRemelt(cycle, grid, celldata, temperature, interface); 106 | else 107 | fillSteeringVector_Remelt(cycle, grid, irf, celldata, temperature, interface); 108 | timers.stopSV(); 109 | 110 | // Iterate over the steering vector to perform active cell creation and capture operations, and if needed, 111 | // melting of cells that have gone above the liquidus. Also places halo cell data into send buffers, later 112 | // checking the MPI buffers to ensure that all appropriate interface updates in the halo regions were 113 | // recorded 114 | timers.startCapture(); 115 | cellCapture(cycle, np, grid, irf, celldata, temperature, interface, orientation); 116 | checkBuffers(id, cycle, grid, celldata, interface, orientation.n_grain_orientations); 117 | timers.stopCapture(); 118 | 119 | if (np > 1) { 120 | // Update ghost nodes 121 | timers.startComm(); 122 | haloUpdate(cycle, id, grid, celldata, interface, orientation); 123 | timers.stopComm(); 124 | } 125 | 126 | // Check on progress of solidification simulation of the current layer, setting x_switch = 1 if complete 127 | if ((cycle % 1000 == 0) && (simulation_type != "SingleGrain")) { 128 | intermediateOutputAndCheck(id, np, cycle, grid, nucleation.successful_nucleation_counter, x_switch, 129 | nucleation, celldata, temperature, inputs.simulation_type, layernumber, 130 | orientation, print, inputs.domain.deltat, interface); 131 | } 132 | else if (simulation_type == "SingleGrain") { 133 | intermediateOutputAndCheck(id, cycle, grid, x_switch, celldata.cell_type); 134 | } 135 | 136 | } while (x_switch == 0); 137 | 138 | // Reset intralayer print counter and print time series file for previous layer's intralayer data (if needed) 139 | print.resetIntralayer(id, layernumber); 140 | 141 | if (layernumber != grid.number_of_layers - 1) { 142 | MPI_Barrier(MPI_COMM_WORLD); 143 | 144 | // Optional print current state of ExaCA 145 | print.printInterlayer(id, np, layernumber, inputs.domain.deltat, cycle, grid, celldata, temperature, 146 | interface, orientation); 147 | 148 | // Determine new active cell domain size and offset from bottom of global domain 149 | grid.initNextLayer(id, simulation_type, layernumber + 1); 150 | 151 | // Initialize new temperature field data for layer "layernumber + 1" 152 | // TODO: reorganize these temperature functions calls into a temperature.init_next_layer as done with the 153 | // substrate 154 | // If the next layer's temperature data isn't already stored, it should be read 155 | if ((simulation_type == "FromFile") && (inputs.temperature.layerwise_temp_read)) 156 | temperature.readTemperatureData(id, grid, layernumber + 1); 157 | MPI_Barrier(MPI_COMM_WORLD); 158 | // Initialize next layer's temperature data 159 | temperature.initialize(layernumber + 1, id, grid, irf.freezingRange(0), inputs.domain.deltat, 160 | simulation_type); 161 | 162 | // Reset solidification event counter of all cells to zeros for the next layer, resizing to number of cells 163 | // associated with the next layer, and get the subview for undercooling 164 | temperature.resetLayerEventsUndercooling(grid); 165 | // Resize and zero all view data relating to the active region from the last layer, in preparation for the 166 | // next layer 167 | interface.initNextLayer(grid.domain_size); 168 | MPI_Barrier(MPI_COMM_WORLD); 169 | 170 | // Sets up views, powder layer (if necessary), and cell types for the next layer of a multilayer problem 171 | celldata.initNextLayer(layernumber + 1, id, grid, inputs.rng_seed, 172 | temperature.number_of_solidification_events); 173 | 174 | // Initialize potential nucleation event data for next layer "layernumber + 1" 175 | // Views containing nucleation data will be resized to the possible number of nuclei on a given MPI rank for 176 | // the next layer 177 | nucleation.resetNucleiCounters(); // start counters at 0 178 | nucleation.placeNuclei(temperature, irf, inputs.rng_seed, layernumber + 1, grid, id); 179 | 180 | x_switch = 0; 181 | MPI_Barrier(MPI_COMM_WORLD); 182 | cycle = 0; 183 | timers.stopLayer(layernumber); 184 | } 185 | else { 186 | MPI_Barrier(MPI_COMM_WORLD); 187 | timers.stopLayer(); 188 | } 189 | } 190 | timers.stopRun(); 191 | MPI_Barrier(MPI_COMM_WORLD); 192 | timers.startOutput(); 193 | 194 | // Collect and print specified final fields to output files 195 | print.printInterlayer(id, np, grid.number_of_layers - 1, inputs.domain.deltat, cycle, grid, celldata, temperature, 196 | interface, orientation); 197 | 198 | // Calculate volume fraction of solidified domain consisting of nucleated grains 199 | float vol_fraction_nucleated = celldata.calcVolFractionNucleated(id, grid); 200 | // Get MPI timing statisticss 201 | timers.stopOutput(); 202 | timers.reduceMPI(); 203 | 204 | // Print the log file with JSON format 205 | inputs.printExaCALog(id, np, cycle, grid, timers, vol_fraction_nucleated); 206 | 207 | // Print timing information to the console 208 | timers.printFinal(np, cycle); 209 | } 210 | 211 | #endif 212 | -------------------------------------------------------------------------------- /analysis/bin/runGA.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Lawrence Livermore National Security, LLC and other ExaCA Project Developers. 2 | // See the top-level LICENSE file for details. 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | #include "CAorientation.hpp" 7 | #include "CAparsefiles.hpp" 8 | #include "GArepresentativeregion.hpp" 9 | #include "GAutils.hpp" 10 | 11 | #include "ExaCA.hpp" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | // Given on the command line: Name of analysis input file, name (without file extension) of the ExaCA data 22 | int main(int argc, char *argv[]) { 23 | 24 | // Initialize Kokkos 25 | Kokkos::initialize(); 26 | { 27 | using memory_space = typename Kokkos::DefaultExecutionSpace::memory_space; 28 | // Read command line input to obtain name of analysis file 29 | std::string analysis_file; 30 | if (argc < 3) { 31 | throw std::runtime_error("Error: Full path to analysis file and path to ExaCA log/microstructure file " 32 | "(without file endings) must be given on " 33 | "the command line. Alternatively, paths to log (with .json) and microstructure " 34 | "output (with .vtk) can be given.\n\nUsage:\n " 35 | "./ExaCA-Analysis analysis/examples/analysis.json output\n\nOR\n\n " 36 | "./ExaCA-Analysis analysis/examples/analysis.json output.json output.vtk\n"); 37 | } 38 | analysis_file = argv[1]; 39 | std::string base_filename = argv[2]; 40 | std::string log_file; 41 | std::string microstructure_file; 42 | 43 | // JSON file (and VTK) were passed 44 | if (base_filename.find(".json") != std::string::npos) { 45 | log_file = base_filename; 46 | base_filename = base_filename.substr(0, base_filename.find(".json")); 47 | if (argc < 4) { 48 | throw std::runtime_error( 49 | "Error: Full path to ExaCA log file was given: path to microstructure file required." 50 | "\n\nUsage:\n " 51 | "./ExaCA-Analysis analysis/examples/analysis.json out.json out.vtk\n"); 52 | } 53 | microstructure_file = argv[3]; 54 | } 55 | // Base file was passed 56 | else { 57 | log_file = base_filename + ".json"; 58 | microstructure_file = base_filename + ".vtk"; 59 | } 60 | std::cout << "Performing analysis of " << microstructure_file << " , using the log file " << log_file 61 | << " and the options specified in " << analysis_file << std::endl; 62 | 63 | std::vector grain_unit_vector_file, phase_names; 64 | double deltax; 65 | int nx, ny, nz, number_of_layers, num_phases; 66 | std::vector xyz_bounds(6); 67 | parseLogFile(log_file, nx, ny, nz, deltax, number_of_layers, xyz_bounds, grain_unit_vector_file, phase_names, 68 | num_phases, false); 69 | std::cout << "Parsed log file" << std::endl; 70 | 71 | // Allocate memory blocks for grain_id and layer_id data 72 | Kokkos::View grain_id(Kokkos::ViewAllocateWithoutInitializing("grain_id"), nz, nx, 73 | ny); 74 | Kokkos::View layer_id(Kokkos::ViewAllocateWithoutInitializing("layer_id"), nz, nx, 75 | ny); 76 | Kokkos::View phase_id(Kokkos::ViewAllocateWithoutInitializing("phase_id"), nz, nx, 77 | ny); 78 | 79 | // Whether layer_id was given in the microstructure file 80 | bool found_layer_id = false; 81 | 82 | // Fill arrays with data from paraview file 83 | initializeData(microstructure_file, nx, ny, nz, grain_id, layer_id, phase_id, found_layer_id); 84 | std::cout << "Parsed ExaCA grain structure" << std::endl; 85 | 86 | // Grain unit vectors, grain euler angles, RGB colors for IPF-Z coloring 87 | // (9*NumberOfOrientations, 3*NumberOfOrientations, and 3*NumberOfOrientations in size, respectively) 88 | Orientation orientation(0, grain_unit_vector_file, true, num_phases); 89 | std::cout << "Parsed orientation files" << std::endl; 90 | 91 | // Representative region creation 92 | std::ifstream analysis_data_stream(analysis_file); 93 | nlohmann::json analysis_data = nlohmann::json::parse(analysis_data_stream); 94 | nlohmann::json regions_data = analysis_data["Regions"]; 95 | int number_of_regions = analysis_data["Regions"].size(); 96 | std::cout << "There are " << number_of_regions << " regions to analyze" << std::endl; 97 | for (auto it = regions_data.begin(); it != regions_data.end(); it++) { 98 | // Create region 99 | std::string region_name = it.key(); 100 | RepresentativeRegion representativeregion(analysis_data, region_name, nx, ny, nz, deltax, xyz_bounds, 101 | grain_id, phase_id); 102 | std::string base_filename_this_region = base_filename + "_" + region_name; 103 | 104 | // Output file stream for quantities of interest 105 | std::ofstream qois; 106 | std::string qois_fname = base_filename_this_region + "_QoIs.txt"; 107 | // Print QoIs file if at least one analysis option is turned on 108 | if (representativeregion.print_stats_yn) { 109 | qois.open(qois_fname); 110 | // Header data for qois file 111 | representativeregion.printAnalysisHeader(qois); 112 | } 113 | 114 | // Fraction of region consisting of nucleated grains, unmelted material 115 | if (representativeregion.analysis_options_stats_yn[0]) 116 | representativeregion.printGrainTypeFractions(qois, grain_id, layer_id, phase_id, num_phases, 117 | found_layer_id); 118 | 119 | // Calculate and if specified, print misorientation data 120 | std::vector grain_misorientation_x_vector = 121 | representativeregion.getGrainMisorientation("X", orientation); 122 | std::vector grain_misorientation_y_vector = 123 | representativeregion.getGrainMisorientation("Y", orientation); 124 | std::vector grain_misorientation_z_vector = 125 | representativeregion.getGrainMisorientation("Z", orientation); 126 | if (representativeregion.analysis_options_stats_yn[1]) 127 | representativeregion.printMeanMisorientations( 128 | qois, grain_misorientation_x_vector, grain_misorientation_y_vector, grain_misorientation_z_vector); 129 | 130 | // Print mean size data if specified 131 | if (representativeregion.analysis_options_stats_yn[2]) 132 | representativeregion.printMeanSize(qois, deltax, num_phases); 133 | 134 | // Obtain extents of grains in X, Y, Z if necessary for requested analysis 135 | representativeregion.calcNecessaryGrainExtents(grain_id, deltax); 136 | std::vector build_trans_aspect_ratio(representativeregion.number_of_grains); 137 | if ((representativeregion.analysis_options_stats_yn[3]) || 138 | (representativeregion.analysis_options_per_grain_stats_yn[5])) 139 | representativeregion.calcBuildTransAspectRatio(build_trans_aspect_ratio); 140 | if (representativeregion.analysis_options_stats_yn[3]) 141 | representativeregion.printMeanBuildTransAspectRatio(qois); 142 | 143 | if (representativeregion.analysis_options_stats_yn[4]) 144 | representativeregion.printMeanExtent(qois, "X"); 145 | if (representativeregion.analysis_options_stats_yn[5]) 146 | representativeregion.printMeanExtent(qois, "Y"); 147 | if (representativeregion.analysis_options_stats_yn[6]) 148 | representativeregion.printMeanExtent(qois, "Z"); 149 | 150 | // Determine IPF-Z color of each grain relative to each direction: 0 (red), 1 (green), 2 (blue) 151 | std::vector grain_red = representativeregion.getIPFZColor(0, orientation); 152 | std::vector grain_green = representativeregion.getIPFZColor(1, orientation); 153 | std::vector grain_blue = representativeregion.getIPFZColor(2, orientation); 154 | 155 | // Write grain area data as a function of Z location in the representative volume if the options are 156 | // toggled, writing to files 157 | // "[base_filename_this_region]_WeightedGrainAreas.csv" and "[base_filename_this_region]_GrainAreas.csv", 158 | // respectively 159 | if ((representativeregion.analysis_options_per_z_stats_yn[0]) || 160 | (representativeregion.analysis_options_per_z_stats_yn[1])) 161 | representativeregion.writeAreaSeries(base_filename_this_region, deltax, grain_id); 162 | if (representativeregion.print_stats_yn) 163 | qois.close(); 164 | 165 | // Write per-grain stats for the analysis types specified to the file 166 | // "[base_filename_this_region]_grains.csv" 167 | if (representativeregion.print_per_grain_stats_yn) 168 | representativeregion.writePerGrainStats(base_filename_this_region, grain_misorientation_x_vector, 169 | grain_misorientation_y_vector, grain_misorientation_z_vector, 170 | build_trans_aspect_ratio, grain_red, grain_green, grain_blue); 171 | 172 | // ExaConstit print a file named "[base_filename_this_region]_ExaConstit.csv" 173 | if (representativeregion.print_exaconstit_yn) { 174 | representativeregion.writeExaConstitRVE(base_filename_this_region, deltax, grain_id); 175 | } 176 | 177 | // Pole figure print a file named "[base_filename_this_region]_PoleFigureData.txt" 178 | if (representativeregion.print_pole_figure_yn) { 179 | auto go_histogram = representativeregion.getOrientationHistogram( 180 | orientation.n_grain_orientations, grain_id, layer_id, phase_id, num_phases, found_layer_id); 181 | representativeregion.writePoleFigure(base_filename_this_region, orientation, go_histogram); 182 | } 183 | 184 | // IPF map for area print a file named "[base_filename_this_region]_IPFCrossSectionData.txt" 185 | if (representativeregion.print_inverse_pole_figure_map_yn) { 186 | representativeregion.writeIPFColoredCrossSection(base_filename_this_region, grain_id, phase_id, 187 | orientation, deltax); 188 | } 189 | std::cout << "Finished analysis for region " << region_name << std::endl; 190 | } // end loop over all representative regions in analysis file 191 | } // end scope for kokkos 192 | // Finalize kokkos and end program 193 | Kokkos::finalize(); 194 | return 0; 195 | } 196 | -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | concurrency: 10 | group: ${ {github.event_name }}-${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: ${{github.event_name == 'pull_request'}} 12 | jobs: 13 | CI: 14 | defaults: 15 | run: 16 | shell: bash 17 | env: 18 | # Fix for "Read -1, expected xxx errno = 1" https://github.com/open-mpi/ompi/issues/4948#issuecomment-395468231 19 | OMPI_MCA_btl_vader_single_copy_mechanism: "none" 20 | strategy: 21 | matrix: 22 | distro: ['ubuntu:latest'] 23 | cxx: ['g++', 'clang++'] 24 | backend: ['SERIAL', 'OPENMP'] 25 | cmake_build_type: ['Debug', 'Release'] 26 | kokkos_ver: ['4.0.01'] 27 | json: ['External'] 28 | heat_transfer: ['None'] 29 | include: 30 | - distro: 'ubuntu:intel' 31 | cxx: 'icpx' 32 | backend: 'SERIAL' 33 | cmake_build_type: 'Release' 34 | kokkos_ver: '4.0.01' 35 | json: External 36 | heat_transfer: 'None' 37 | - distro: 'ubuntu:intel' 38 | cxx: 'icpx' 39 | backend: 'OPENMP' 40 | cmake_build_type: 'Release' 41 | kokkos_ver: '4.0.01' 42 | json: External 43 | heat_transfer: 'None' 44 | - distro: 'ubuntu:latest' 45 | cxx: 'g++' 46 | backend: 'SERIAL' 47 | cmake_build_type: 'Debug' 48 | kokkos_ver: '4.0.01' 49 | json: Internal 50 | heat_transfer: 'None' 51 | - distro: 'ubuntu:latest' 52 | cxx: 'g++' 53 | backend: 'THREADS' 54 | cmake_build_type: 'Debug' 55 | kokkos_ver: '4.0.01' 56 | json: External 57 | heat_transfer: 'None' 58 | - distro: 'ubuntu:latest' 59 | cxx: 'g++' 60 | backend: 'SERIAL' 61 | cmake_build_type: 'Release' 62 | kokkos_ver: '4.0.01' 63 | json: External 64 | heat_transfer: 'Finch' 65 | runs-on: ubuntu-latest 66 | timeout-minutes: 30 67 | container: ghcr.io/ecp-copa/ci-containers/${{ matrix.distro }} 68 | continue-on-error: ${{ matrix.distro == 'ubuntu:intel' }} 69 | steps: 70 | - name: Checkout json 71 | if: ${{ matrix.json == 'External' }} 72 | uses: actions/checkout@v3 73 | with: 74 | repository: nlohmann/json 75 | ref: v3.11.2 76 | path: json 77 | - name: Build json 78 | if: ${{ matrix.json == 'External' }} 79 | working-directory: json 80 | run: | 81 | cmake -B build \ 82 | -DCMAKE_INSTALL_PREFIX=$HOME/json \ 83 | -DCMAKE_BUILD_TYPE=${{ matrix.cmake_build_type }} \ 84 | -DJSON_BuildTests=OFF 85 | cmake --build build --parallel 2 86 | cmake --install build 87 | - name: Checkout kokkos 88 | uses: actions/checkout@v3 89 | with: 90 | repository: kokkos/kokkos 91 | ref: ${{ matrix.kokkos_ver }} 92 | path: kokkos 93 | - name: Build kokkos 94 | working-directory: kokkos 95 | run: | 96 | cmake -B build \ 97 | -DCMAKE_INSTALL_PREFIX=$HOME/kokkos \ 98 | -DKokkos_ENABLE_${{ matrix.backend }}=ON \ 99 | -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} \ 100 | -DKokkos_ENABLE_HWLOC=ON \ 101 | -DCMAKE_BUILD_TYPE=${{ matrix.cmake_build_type }} 102 | cmake --build build --parallel 2 103 | cmake --install build 104 | - name: Checkout Cabana 105 | if: ${{ matrix.heat_transfer == 'Finch' }} 106 | uses: actions/checkout@v3 107 | with: 108 | repository: ECP-CoPA/Cabana 109 | ref: 0.6.1 110 | path: cabana 111 | - name: Build Cabana 112 | if: ${{ matrix.heat_transfer == 'Finch' }} 113 | working-directory: cabana 114 | run: | 115 | cmake -B build \ 116 | -DCMAKE_BUILD_TYPE=${{ matrix.cmake_build_type }} \ 117 | -DCMAKE_INSTALL_PREFIX=$HOME/cabana \ 118 | -DCMAKE_PREFIX_PATH="$HOME/kokkos" \ 119 | -DCabana_ENABLE_GRID=ON 120 | cmake --build build --parallel 2 121 | cmake --install build 122 | - name: Checkout Finch 123 | if: ${{ matrix.heat_transfer == 'Finch' }} 124 | uses: actions/checkout@v3 125 | with: 126 | repository: ORNL-MDF/Finch 127 | # This is after the ability to extract data bounds with an input MPI comm was added 128 | ref: 928d56776550e1a546a93197f713fc4d7e1a618d 129 | path: finch 130 | - name: Build Finch 131 | if: ${{ matrix.heat_transfer == 'Finch' }} 132 | working-directory: finch 133 | run: | 134 | cmake -B build \ 135 | -DCMAKE_INSTALL_PREFIX=$HOME/finch \ 136 | -DCMAKE_PREFIX_PATH="$HOME/cabana" \ 137 | -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} \ 138 | -DCMAKE_BUILD_TYPE=${{ matrix.cmake_build_type }} 139 | cmake --build build --parallel 2 140 | cmake --install build 141 | - name: Checkout ExaCA 142 | uses: actions/checkout@v3 143 | - name: Build ExaCA 144 | run: | 145 | cmake -B build \ 146 | -D CMAKE_INSTALL_PREFIX=$HOME/exaca \ 147 | -D CMAKE_PREFIX_PATH="$HOME/kokkos;$HOME/json;$HOME/finch" \ 148 | -D CMAKE_BUILD_TYPE=${{ matrix.cmake_build_type }} \ 149 | -D CMAKE_CXX_COMPILER=${{ matrix.cxx }} \ 150 | -D CMAKE_CXX_FLAGS="-Wall -Wextra -pedantic -Werror" \ 151 | -D MPIEXEC_MAX_NUMPROCS=2 \ 152 | -D MPIEXEC_PREFLAGS="--oversubscribe" \ 153 | -D ExaCA_ENABLE_TESTING=ON \ 154 | ${exaca_cmake_opts[@]} 155 | cmake --build build --parallel 2 156 | cmake --install build 157 | - name: Unit test ExaCA 158 | run: | 159 | CTEST_OUTPUT_ON_FAILURE=1 cmake --build build --target test 160 | - name: Test ExaCA 161 | working-directory: examples 162 | run: | 163 | $HOME/exaca/bin/ExaCA Inp_SmallDirSolidification.json 164 | $HOME/exaca/bin/ExaCA Inp_SmallSpotMelt.json 165 | mpirun -n 2 --oversubscribe $HOME/exaca/bin/ExaCA Inp_SmallDirSolidification.json 166 | mpirun -n 2 --oversubscribe $HOME/exaca/bin/ExaCA Inp_SmallSpotMelt.json 167 | - name: Test GA 168 | working-directory: analysis/examples 169 | run: | 170 | $HOME/exaca/bin/ExaCA ../../examples/Inp_SmallDirSolidification.json 171 | $HOME/exaca/bin/ExaCA-GrainAnalysis AnalyzeSmallDirS.json TestProblemSmallDirS 172 | - name: Test Finch-ExaCA 173 | if: ${{ matrix.heat_transfer == 'Finch' }} 174 | working-directory: utilities/Finch 175 | run: | 176 | $HOME/exaca/bin/Finch-ExaCA inputs_small.json ../../examples/Inp_SmallFinch.json 177 | 178 | HIP: 179 | defaults: 180 | run: 181 | shell: bash 182 | env: 183 | # Needed because FindMPI relies heavily on the compiler wrappers, which aren't used with hipcc 184 | MPI_LOCATION: /usr/lib/x86_64-linux-gnu/openmpi/ 185 | strategy: 186 | matrix: 187 | cxx: ['hipcc'] 188 | cmake_build_type: ['Release'] 189 | # Using >4.0 because of kokkos build error without available device 190 | kokkos_ver: ['4.2.00'] 191 | runs-on: ubuntu-latest 192 | container: ghcr.io/ecp-copa/ci-containers/rocm:latest 193 | steps: 194 | - name: Checkout json 195 | uses: actions/checkout@v3 196 | with: 197 | repository: nlohmann/json 198 | ref: v3.11.2 199 | path: json 200 | - name: Build json 201 | working-directory: json 202 | run: | 203 | cmake -B build \ 204 | -DCMAKE_INSTALL_PREFIX=$HOME/json \ 205 | -DCMAKE_BUILD_TYPE=${{ matrix.cmake_build_type }} \ 206 | -DJSON_BuildTests=OFF 207 | cmake --build build --parallel 2 208 | cmake --install build 209 | - name: Checkout kokkos 210 | uses: actions/checkout@v3 211 | with: 212 | repository: kokkos/kokkos 213 | ref: ${{ matrix.kokkos_ver }} 214 | path: kokkos 215 | - name: Build kokkos 216 | working-directory: kokkos 217 | run: | 218 | cmake -B build \ 219 | -DCMAKE_INSTALL_PREFIX=$HOME/kokkos \ 220 | -DKokkos_ENABLE_HIP=ON \ 221 | -DKokkos_ARCH_VEGA908=ON \ 222 | -DCMAKE_BUILD_TYPE=${{ matrix.cmake_build_type }} \ 223 | -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} 224 | cmake --build build --parallel 2 225 | cmake --install build 226 | - name: Checkout ExaCA 227 | uses: actions/checkout@v3 228 | - name: Build ExaCA 229 | run: | 230 | cmake -B build \ 231 | -D CMAKE_INSTALL_PREFIX=$HOME/exaca \ 232 | -D CMAKE_PREFIX_PATH="$HOME/kokkos;$HOME/json" \ 233 | -D CMAKE_BUILD_TYPE=${{ matrix.cmake_build_type }} \ 234 | -D CMAKE_CXX_COMPILER=${{ matrix.cxx }} \ 235 | -D CMAKE_CXX_FLAGS="-Wall -Wextra -pedantic -Werror -I${MPI_LOCATION}/include" \ 236 | -D CMAKE_EXE_LINKER_FLAGS="-L${MPI_LOCATION}/lib -lmpi" \ 237 | -D CMAKE_SHARED_LINKER_FLAGS="-L${MPI_LOCATION}/lib -lmpi" \ 238 | -D ExaCA_ENABLE_TESTING=ON 239 | cmake --build build --parallel 2 240 | cmake --install build 241 | 242 | CUDA: 243 | defaults: 244 | run: 245 | shell: bash 246 | strategy: 247 | matrix: 248 | cxx: ['nvcc'] 249 | cmake_build_type: ['Release'] 250 | kokkos_ver: ['4.0.01'] 251 | runs-on: ubuntu-latest 252 | container: ghcr.io/ecp-copa/ci-containers/cuda:12.2.0 253 | steps: 254 | - name: Checkout json 255 | uses: actions/checkout@v3 256 | with: 257 | repository: nlohmann/json 258 | ref: v3.11.2 259 | path: json 260 | - name: Build json 261 | working-directory: json 262 | run: | 263 | cmake -B build \ 264 | -DCMAKE_INSTALL_PREFIX=$HOME/json \ 265 | -DCMAKE_BUILD_TYPE=${{ matrix.cmake_build_type }} \ 266 | -DJSON_BuildTests=OFF 267 | cmake --build build --parallel 2 268 | cmake --install build 269 | - name: Checkout kokkos 270 | uses: actions/checkout@v3 271 | with: 272 | repository: kokkos/kokkos 273 | ref: ${{ matrix.kokkos_ver }} 274 | path: kokkos 275 | - name: Build kokkos 276 | working-directory: kokkos 277 | run: | 278 | cmake -B build \ 279 | -DCMAKE_INSTALL_PREFIX=$HOME/kokkos \ 280 | -DCMAKE_BUILD_TYPE=${{ matrix.cmake_build_type }} \ 281 | -DKokkos_ENABLE_CUDA=ON \ 282 | -DKokkos_ARCH_VOLTA72=ON \ 283 | -DKokkos_ENABLE_CUDA_LAMBDA=ON 284 | cmake --build build --parallel 2 285 | cmake --install build 286 | - name: Checkout ExaCA 287 | uses: actions/checkout@v3 288 | - name: Build ExaCA 289 | run: | 290 | cmake -B build \ 291 | -D CMAKE_INSTALL_PREFIX=$HOME/exaca \ 292 | -D CMAKE_PREFIX_PATH="$HOME/kokkos;$HOME/json" \ 293 | -D CMAKE_BUILD_TYPE=${{ matrix.cmake_build_type }} \ 294 | -D CMAKE_CXX_FLAGS="-Wall -Wextra -pedantic -Werror" \ 295 | -D ExaCA_ENABLE_TESTING=ON 296 | cmake --build build --parallel 2 297 | cmake --install build 298 | --------------------------------------------------------------------------------