diff --git a/.github/workflows/build.sh b/.github/workflows/build.sh deleted file mode 100755 index 6cfe9ce..0000000 --- a/.github/workflows/build.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -set -e - -FANS_BUILD_DIR=${1:-build} - -if [ -z "$FANS_DIR" ]; then - echo "FANS_DIR is not set" - exit 1 -fi - -echo "---------------------------------------------------" -ARCH=$(uname -m) -NPROC=$(nproc) -echo "arch=$ARCH" -echo "Processors: ${NPROC}" -echo "---------------------------------------------------" - -CMAKE_BUILD_PARALLEL_LEVEL=${NPROC} -CTEST_PARALLEL_LEVEL=${NPROC} - -cd "$FANS_DIR" || exit - -start=$(date +%s) - -rm -rf ${FANS_BUILD_DIR} -mkdir ${FANS_BUILD_DIR} -cd ${FANS_BUILD_DIR} -cmake -DCMAKE_BUILD_TYPE=Release .. -configure=$(date +%s) - -# run in parallel, but retry single threaded in case of failure such -# that error messages are more readable. -cmake --build . || cmake --build . -j1 -build=$(date +%s) - -echo "---------------------------------------------------" -echo "configure time: $((configure-start))s" -echo "build time: $((build-configure))s" -echo "total time: $((build-start))s" -echo "---------------------------------------------------" diff --git a/.github/workflows/build_and_package.yaml b/.github/workflows/build_and_package.yaml deleted file mode 100644 index d2b41cd..0000000 --- a/.github/workflows/build_and_package.yaml +++ /dev/null @@ -1,59 +0,0 @@ -name: Build FANS and create Debian packages -on: - workflow_dispatch: - -env: - FANS_DIR: /FANS - FANS_IMG: unistuttgartdae/fans-ci - FANS_CONTAINER: fans-ci - FANS_BUILD_DIR: build - -jobs: - fans-ci: - strategy: - matrix: - arch: [amd64, arm64] - ubuntu-version: [noble, jammy, focal] - - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Pull Docker image - run: docker pull --platform linux/${{ matrix.arch }} ${FANS_IMG}:${{ matrix.ubuntu-version }} - - - name: Create and start container - run: | - docker create \ - --name ${FANS_CONTAINER} \ - -i -t \ - -u `id -u`:`id -g` \ - -v /etc/localtime:/etc/localtime:ro \ - -v /etc/timezone:/etc/timezone:ro \ - -v ${{ github.workspace }}:${FANS_DIR} \ - -e FANS_DIR=${FANS_DIR} \ - -w ${FANS_DIR} \ - ${FANS_IMG}:${{ matrix.ubuntu-version }} - docker start ${FANS_CONTAINER} - - - name: Build FANS - run: | - docker exec ${FANS_CONTAINER} \ - bash .github/workflows/build.sh ${FANS_BUILD_DIR} - - - name: Package FANS - run: | - docker exec \ - -w ${FANS_DIR}/${FANS_BUILD_DIR} \ - ${FANS_CONTAINER} \ - cpack -G "DEB" - - - name: Upload packages - uses: actions/upload-artifact@v4 - with: - name: fans-packages-${{ matrix.ubuntu-version }}-${{ matrix.arch }} - path: ${{ github.workspace }}/${{ env.FANS_BUILD_DIR }}/packages/*.deb diff --git a/.github/workflows/build_and_test.yaml b/.github/workflows/build_and_test.yaml new file mode 100644 index 0000000..27c32a0 --- /dev/null +++ b/.github/workflows/build_and_test.yaml @@ -0,0 +1,76 @@ +name: Build and Test +# Builds FANS inside various docker containers and runs the tests. + +on: + push: + branches: + - main + - develop + pull_request: + workflow_dispatch: + +concurrency: + group: ${{ github.event_name }}-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{github.event_name == 'pull_request'}} + +jobs: + build: + name: ${{ format('Ubuntu {0}', matrix.UBUNTU_VERSION) }} + runs-on: ubuntu-latest + container: unistuttgartdae/fans-ci:${{ matrix.UBUNTU_VERSION }} + defaults: + run: + shell: "bash --login -eo pipefail {0}" + env: + FANS_BUILD_DIR: build + FANS_MPI_USER: fans + strategy: + fail-fast: false + matrix: + UBUNTU_VERSION: [noble, jammy, focal] + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Generate build directory + run: mkdir -p ${{ env.FANS_BUILD_DIR }} + + - name: Configure + working-directory: ${{ env.FANS_BUILD_DIR }} + run: | + cmake --version + cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .. + + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: ${{ format('Ubuntu {0}', matrix.UBUNTU_VERSION) }} CMakeCache + path: ${{ env.FANS_BUILD_DIR }}/CMakeCache.txt + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: ${{ format('Ubuntu {0}', matrix.UBUNTU_VERSION) }} CMakeLogs + path: '${{ env.FANS_BUILD_DIR }}/CMakeFiles/*.log' + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: ${{ format('Ubuntu {0}', matrix.UBUNTU_VERSION) }} CompileCommands + path: ${{ env.FANS_BUILD_DIR }}/compile_commands.json + + - name: Compile + working-directory: ${{ env.FANS_BUILD_DIR }} + run: + cmake --build . -j $(nproc) || cmake --build . -j1 + + - name: Adjust user rights + run: chown -R ${{ env.FANS_MPI_USER }} ${{ env.FANS_BUILD_DIR }} + + - name: Tests + working-directory: ${{ env.FANS_BUILD_DIR }} + run: su -c "ctest" ${{ env.FANS_MPI_USER }} + + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: ${{ format('Ubuntu {0}', matrix.UBUNTU_VERSION) }} CTest logs + path: ${{ env.FANS_BUILD_DIR }}/Testing/Temporary/LastTest.log diff --git a/.gitignore b/.gitignore index 4b23465..2bc948f 100644 --- a/.gitignore +++ b/.gitignore @@ -201,7 +201,7 @@ test/input_files/**/*.json !sphere.h5 # Test input files -!test_LinearElasticIsotropic.json -!test_LinearThermalIsotropic.json -!test_PseudoPlasticLinearHardening.json -!test_VonMisesPlasticLinearIsotropicHardening.json +!test_LinearElastic.json +!test_LinearThermal.json +!test_PseudoPlastic.json +!test_J2Plasticity.json diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 963aebf..0240fee 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,3 +14,10 @@ repos: rev: 22.12.0 hooks: - id: black +# clang-format for C/C++ formatting +- repo: https://github.com/pre-commit/mirrors-clang-format + rev: v8.0.1 + hooks: + - id: clang-format + args: ['--style=file'] + exclude: "include/json.hpp" diff --git a/CHANGELOG.md b/CHANGELOG.md index b5a99b7..f94b6f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # FANS Changelog +## v0.2.0 + +- Add integration tests https://github.com/DataAnalyticsEngineering/FANS/pull/20 +- Add GitHub Action workflow to build and test FANS https://github.com/DataAnalyticsEngineering/FANS/pull/19 + ## v0.1.2 - Update TIK GitHub links in the documentation to public GitHub links https://github.com/DataAnalyticsEngineering/FANS/pull/13 diff --git a/CMakeLists.txt b/CMakeLists.txt index a3a2402..1918e68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.0...3.28) # ############################################################################## project(FANS - VERSION 0.1.2 + VERSION 0.2.0 LANGUAGES C CXX ) @@ -135,8 +135,8 @@ set_property(TARGET FANS_FANS PROPERTY PUBLIC_HEADER include/material_models/LinearThermalIsotropic.h include/material_models/LinearElasticIsotropic.h - include/material_models/PseudoPlasticLinearHardening.h - include/material_models/VonMisesPlasticLinearIsotropicHardening.h + include/material_models/PseudoPlastic.h + include/material_models/J2Plasticity.h ) # ############################################################################## @@ -251,6 +251,19 @@ install( COMPONENT FANS_Development ) +# ############################################################################## +# TESTING +# ############################################################################## + +if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(FANS_ENABLE_TESTING_DEFAULT ON) +endif () +option(FANS_ENABLE_TESTING "Enable testing" ${FANS_ENABLE_TESTING_DEFAULT}) +if (FANS_ENABLE_TESTING) + enable_testing() + add_subdirectory(test) +endif () + # ############################################################################## # PACKAGING # ############################################################################## diff --git a/FANS_Dashboard/FANS_Dashboard.ipynb b/FANS_Dashboard/FANS_Dashboard.ipynb index 619303a..bf48dab 100644 --- a/FANS_Dashboard/FANS_Dashboard.ipynb +++ b/FANS_Dashboard/FANS_Dashboard.ipynb @@ -133,8 +133,8 @@ "outputs": [], "source": [ "# Specify which microstructures, load cases, and quantities to load\n", - "microstructures_to_load = ['/sphere/32x32x32/ms']\n", - "load_cases_to_load = ['load0']\n", + "microstructures_to_load = list(hierarchy.keys())\n", + "load_cases_to_load = list(hierarchy[microstructures_to_load[0]].keys())\n", "quantities_to_load = ['strain_average', 'stress_average', 'phase_stress_average_phase0', \"stress\"]\n", "time_steps_to_load = []\n", "\n", @@ -143,7 +143,11 @@ " quantities_to_load, \n", " microstructures_to_load, \n", " load_cases_to_load, \n", - " time_steps_to_load)" + " time_steps_to_load)\n", + "\n", + "strain_average = data[microstructures_to_load[0]][load_cases_to_load[0]]['strain_average'] \n", + "stress_average = data[microstructures_to_load[0]][load_cases_to_load[0]]['stress_average']\n", + "time_steps = data[microstructures_to_load[0]][load_cases_to_load[0]]['time_steps']\n" ] }, { @@ -164,10 +168,6 @@ "metadata": {}, "outputs": [], "source": [ - "strain_average = data['/sphere/32x32x32/ms']['load0']['strain_average']\n", - "stress_average = data['/sphere/32x32x32/ms']['load0']['stress_average']\n", - "time_steps = data['/sphere/32x32x32/ms']['load0']['time_steps']\n", - "\n", "# Specify measures to compute\n", "measures_to_compute = ['von_mises', 'hydrostatic', 'deviatoric', 'principal', \n", " 'max_shear', 'I_invariants', 'J_invariants', 'eigenvalues',\n", @@ -209,8 +209,8 @@ "# Postprocessing and writing to h5 file\n", "quantities_to_postprocess = ['stress_average', 'stress']\n", "measures_to_postprocess = ['deviatoric', 'von_mises']\n", - "microstructures_to_postprocess = ['/sphere/32x32x32/ms']\n", - "load_cases_to_postprocess = ['load0']\n", + "microstructures_to_postprocess = microstructures_to_load[0]\n", + "load_cases_to_postprocess = load_cases_to_load[0]\n", "\n", "processed_data = postprocess_and_write_to_h5(file_path, hierarchy, quantities_to_postprocess, measures_to_postprocess, \n", " microstructures_to_postprocess, load_cases_to_postprocess)" diff --git a/FANS_Dashboard/PlotYoungsModulus.py b/FANS_Dashboard/PlotYoungsModulus.py new file mode 100644 index 0000000..124e682 --- /dev/null +++ b/FANS_Dashboard/PlotYoungsModulus.py @@ -0,0 +1,110 @@ +import numpy as np +import plotly.graph_objs as go + + +def compute_3d_youngs_modulus(C): + """ + Compute Young's modulus for all directions in 3D. + + Parameters: + C : ndarray + Stiffness tensor in Mandel notation. + + Returns: + E: ndarray + Young's modulus in all directions. + X, Y, Z: ndarrays + Coordinates for plotting the modulus surface. + """ + + n_theta = 180 + n_phi = 360 + theta = np.linspace(0, np.pi, n_theta) # Polar angle + phi = np.linspace(0, 2 * np.pi, n_phi) # Azimuthal angle + + S = np.linalg.inv(C) + + E = np.zeros((n_theta, n_phi)) + + for i in range(n_theta): + for j in range(n_phi): + d = np.array( + [ + np.sin(theta[i]) * np.cos(phi[j]), + np.sin(theta[i]) * np.sin(phi[j]), + np.cos(theta[i]), + ] + ) + + N = np.array( + [ + d[0] ** 2, + d[1] ** 2, + d[2] ** 2, + np.sqrt(2.0) * d[0] * d[1], + np.sqrt(2.0) * d[0] * d[2], + np.sqrt(2.0) * d[2] * d[1], + ] + ) + + E[i, j] = 1.0 / (N.T @ S @ N) + + X = E * np.sin(theta)[:, np.newaxis] * np.cos(phi)[np.newaxis, :] + Y = E * np.sin(theta)[:, np.newaxis] * np.sin(phi)[np.newaxis, :] + Z = E * np.cos(theta)[:, np.newaxis] + + return X, Y, Z, E + + +def plot_3d_youngs_modulus_surface(C, title="Young's Modulus Surface"): + """ + Plot a 3D surface of Young's modulus. + + Parameters: + C : ndarray + Stiffness tensor in Mandel notation. + title : str + Title of the plot. + + """ + X, Y, Z, E = compute_3d_youngs_modulus(C) + + surface = go.Surface(x=X, y=Y, z=Z, surfacecolor=E, colorscale="Viridis") + + layout = go.Layout( + title=title, + scene=dict( + xaxis=dict(title="X"), + yaxis=dict(title="Y"), + zaxis=dict(title="Z"), + aspectmode="auto", + ), + ) + + fig = go.Figure(data=[surface], layout=layout) + fig.show() + + +def demoCubic(): + """ + Demonstrates the Young's modulus surface plotting routine for a cubic material (Copper) + + Returns + ------- + None. + + """ + P1 = np.zeros((6, 6)) + P1[:3, :3] = 1.0 / 3.0 + D = np.diag([1, 1, 1, 0, 0, 0]) + P2 = D - P1 + P3 = np.eye(6) - D + + # generate stiffness for a cubic material: copper + l1, l2, l3 = 136.67, 46, 150 + C = 3 * l1 * P1 + l2 * P2 + l3 * P3 + + print(C) + + # show the 3D Young's modulus plot for copper + plot_3d_youngs_modulus_surface(C, title="Young's Modulus Surface for Copper") diff --git a/README.md b/README.md index ecff43d..2c56764 100644 --- a/README.md +++ b/README.md @@ -4,50 +4,63 @@ Fourier Accelerated Nodal Solvers (FANS) is an FFT-based homogenization solver d Example Image -## Table of Contents +## Table of contents -- [Installation](#installation) -- [Input File Format](#input-file-format) +- [Dependencies](#dependencies) +- [Building](#building) +- [Installing](#installing) +- [Input file format](#input-file-format) - [Examples](#examples) -- [Acknowledgements](#acknowledgements) -## Installation +## Dependencies -### Prerequisites +FANS has the following dependencies: -Before proceeding with the installation, ensure that your system has the necessary dependencies. The prerequisites of FANS can be installed using Spack for a streamlined setup on high-performance computing systems, or through traditional package management for personal use. - -### Traditional Installation - -If you're setting up FANS on a personal computer or in a non-HPC environment, follow these instructions: - -Please ensure you have the following dependencies installed on your system: - -- CMake (version 3.0 or higher) +- A C++ compiler (e.g. GCC) +- CMake (version 3.0 or higher) (+ Unix file utility for creating .deb packages) +- Git (for cloning this repo) - MPI (mpicc and mpic++) - HDF5 with parallel support - Eigen3 - FFTW3 with MPI support -Specifically, to run FANS, you at least need the following packages: +### Installing dependencies + +We recommend installing the dependencies using a package manager. For example, using `apt`, the following commands are run: ```bash -openmpi-bin libc6 libfftw3-double3 libfftw3-mpi3 libgcc-s1 libgomp1 libhdf5-103 libopenmpi3 libstdc++6 +apt-get install \ + libhdf5-dev \ + libopenmpi-dev \ + libeigen3-dev \ + libfftw3-dev \ + libfftw3-mpi-dev ``` -To build fans, you additionally need these packages: +Also, we recommend to set up a Python virtual environment for the `FANS_Dashboard`: ```bash -libhdf5-dev libopenmpi-dev libeigen3-dev libfftw3-dev libfftw3-mpi-dev +apt-get install \ + time \ + htop \ + python3 \ + python3-pip \ + python3-venv \ + python-is-python3 \ + python3-dev + +python -m venv ~/venvs/FANS +source ~/venvs/FANS/bin/activate +python -m pip install h5py lxml ``` -If for some reason you are unable to install these packages directly on your host machine, have a look at the [set of Docker images](docker/) to create and work with FANS within an isolated environment. +We also provide a [set of Docker images](docker/) to work with FANS within an isolated environment. -### Spack Installation (Recommended for Clusters/Supercomputers) +### Installing dependencies using Spack -Spack is a package manager designed for high-performance computing environments. It simplifies the installation of complex software stacks, making it ideal for setting up FANS on large clusters or supercomputers. +Spack is a package manager designed for high-performance computing environments. It simplifies the installation of complex software stacks, making it ideal for setting up FANS on remote systems. -1. **Install Spack**: If you don’t have Spack installed, you can set it up with the following commands: +1. **Install Spack**: If Spack is not installed, set it up with the following commands: ```bash git clone https://github.com/spack/spack.git @@ -65,7 +78,7 @@ Spack is a package manager designed for high-performance computing environments. spack install fftw +mpi ``` - You can also use alternative and optimized FFTW implementations depending on your system's architecture like amdfftw (For AMD systems) or cray-fftw (For Cray systems) or fujitsu-fftw (For Fujitsu systems). + Alternatively, optimized FFTW implementations can be used depending on your system's architecture, for example `amdfftw` (For AMD systems) or `cray-fftw` (For Cray systems) or `fujitsu-fftw` (For Fujitsu systems). 3. **Load Dependencies** Once dependencies are installed, you can load them before building: @@ -73,7 +86,7 @@ Spack is a package manager designed for high-performance computing environments. spack load cmake mpi hdf5 eigen fftw ``` -### Building the Project +## Building 1. Clone the repository: @@ -82,7 +95,7 @@ Spack is a package manager designed for high-performance computing environments. cd FANS ``` -2. Configure the project using CMake: +2. Configure the build using CMake: ```bash mkdir build @@ -90,17 +103,17 @@ Spack is a package manager designed for high-performance computing environments. cmake .. ``` -3. Compile the project: +3. Compile: ```bash cmake --build . -j ``` -The compilation will symlink the generated `FANS` binary into the `test/` directory for convenience. +The compilation symlinks the generated `FANS` binary into the `test/` directory for convenience. -### Build Options +### Configuring a build -This project supports the following CMake build options: +The following CMake configuration options exist: - `CMAKE_BUILD_TYPE`: Sets the build type. Common values are Debug, Release, RelWithDebInfo, and MinSizeRel. @@ -108,14 +121,14 @@ This project supports the following CMake build options: - Default: OFF - Usage: `-DFANS_BUILD_STATIC=ON` -- `CMAKE_INTERPROCEDURAL_OPTIMIZATION`: Enable interprocedural optimization (IPO) for all targets. +- `CMAKE_INTERPROCEDURAL_OPTIMIZATION`: Enable inter-procedural optimization (IPO) for all targets. - Default: ON (if supported) - Usage: `-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=OFF` - Note: When you run the configure step for the first time, IPO support is automatically checked and enabled if available. A status message will indicate whether IPO is activated or not supported. -### Installing the Project +## Installing -After compiling, you can install FANS (system-wide) using the following options: +Install FANS (system-wide) using the following options: 1. Using CMake (sudo required if --prefix is omitted): @@ -133,8 +146,7 @@ After compiling, you can install FANS (system-wide) using the following options: ## Input File Format -To run the FANS solver, you need to provide a JSON input file specifying the problem parameters. -Example input files can be found in the [`test/input_files`](test/input_files) directory. You can use these files as a reference to create your own input file. The input file is in JSON format and contains several fields to define the problem settings... +FANS requires a JSON input file specifying the problem parameters. Example input files can be found in the [`test/input_files`](test/input_files) directory. It is recommended to use these files as a reference to create your own input file. ### Microstructure Definition @@ -159,8 +171,8 @@ Example input files can be found in the [`test/input_files`](test/input_files) ``` - `problem_type`: This defines the type of physical problem you are solving. Common options include "thermal" problems and "mechanical" problems. -- `matmodel`: This specifies the material model to be used in the simulation. Examples include `LinearThermalIsotropic` for isotropic linear thermal problems, `LinearElasticIsotropic` for isotropic linear elastic mechanical problems, `PseudoPlasticLinearHardening` for plasticity mimicking model with linear hardening, and `VonMisesPlasticLinearIsotropicHardening` for rate independent J2 plasticity model with linear isotropic hardening. -- `material_properties`: This provides the necessary material parameters for the chosen material model. For thermal problems, you might specify `conductivity`, while mechanical problems might require `bulk_modulus`, `shear_modulus`, `yield_stress`, and `hardening_parameter`. These properties can be defined as arrays to represent multiple phases within the microstructure. +- `matmodel`: This specifies the material model to be used in the simulation. Examples include `LinearThermalIsotropic` for isotropic linear thermal problems, `LinearElasticIsotropic` for isotropic linear elastic mechanical problems, `PseudoPlasticLinearHardening`/`PseudoPlasticNonLinearHardening` for plasticity mimicking model with linear/nonlinear hardening, and `J2ViscoPlastic_LinearIsotropicHardening`/`J2ViscoPlastic_NonLinearIsotropicHardening` for rate dependent J2 plasticity model with linear/nonlinear isotropic hardening. +- `material_properties`: This provides the necessary material parameters for the chosen material model. For thermal problems, you might specify `conductivity`, while mechanical problems might require `bulk_modulus`, `shear_modulus`, and more properties for advanced material models. These properties can be defined as arrays to represent multiple phases within the microstructure. ### Solver Settings @@ -194,9 +206,8 @@ Example input files can be found in the [`test/input_files`](test/input_files) ``` - `macroscale_loading`: This defines the external loading applied to the microstructure. It is an array of arrays, where each sub-array represents a loading condition applied to the system. The format of the loading array depends on the problem type: - - - For `thermal` problems, the array typically has 3 components, representing the temperature gradients in the x, y, and z directions. - - For `mechanical` problems, the array must have 6 components, corresponding to the components of the strain tensor in Mandel notation (e.g., [[ε11, ε22, ε33, ε12, ε13, ε23]]). +- For `thermal` problems, the array typically has 3 components, representing the temperature gradients in the x, y, and z directions. +- For `mechanical` problems, the array must have 6 components, corresponding to the components of the strain tensor in Mandel notation (e.g., [[ε_11, ε_22, ε_33, √2 ε_12, √2 ε_13, √2 ε_23]]). In the case of path/time-dependent loading as shown, for example as in plasticity problems, the `macroscale_loading` array can include multiple steps with corresponding loading conditions. @@ -216,16 +227,23 @@ In the case of path/time-dependent loading as shown, for example as in plasticit - `displacement`: The displacement fluctuation field (for mechanical problems) and temperature fluctuation field (for thermal problems). - `stress` and `strain`: The stress and strain fields at each voxel in the microstructure. -- Additional material model specific results, such as `plastic_flag`, `plastic_strain`, and `hardening_variable`, can be included depending on the problem type and material model. +- Additional material model specific results can be included depending on the problem type and material model. -### Examples +## Examples -If you would like to run some example tests, you can execute the [`run_tests.sh`](test/run_tests.sh) file. For example to run a linear elastic mechanical homogenization problem for a 6 othonormal load cases on a microstructure image of size `32 x 32 x 32` with a single spherical inclusion, +Execute the [`run_tests.sh`](test/run_tests.sh) file to run tests, which are also examples. For example, to run a linear elastic mechanical homogenization problem for a 6 othonormal load cases on a microstructure image of size `32 x 32 x 32` with a single spherical inclusion, ```bash -mpiexec -n 2 ./FANS input_files/test_LinearElasticIsotropic.json test_results.h5 +mpiexec -n 2 ./FANS input_files/test_LinearElastic.json test_results.h5 ``` ## Acknowledgements Funded by Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) under Germany’s Excellence Strategy - EXC 2075 – 390740016. Contributions by Felix Fritzen are funded by Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) within the Heisenberg program - DFG-FR2702/8 - 406068690; DFG-FR2702/10 - 517847245 and through NFDI-MatWerk - NFDI 38/1 - 460247524. We acknowledge the support by the Stuttgart Center for Simulation Science (SimTech). + +## Contributors + +- [Sanath Keshav](https://github.com/sanathkeshav) +- [Florian Rieg](about:blank) +- [Ishaan Desai](https://github.com/IshaanDesai) +- [Moritz Sigg](https://github.com/siggmo) diff --git a/docker/Dockerfile b/docker/Dockerfile index 125e1c8..5398805 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -2,11 +2,13 @@ # to take effect) ARG DEBIAN_FRONTEND=noninteractive ARG UBUNTU_VERSION=noble +ARG USER=fans ################################################################################ FROM ubuntu:${UBUNTU_VERSION} AS fans_base ARG DEBIAN_FRONTEND +ARG USER # Context: https://askubuntu.com/questions/1513927/ubuntu-24-04-docker-images-now-includes-user-ubuntu-with-uid-gid-1000 RUN bash -c 'if id "ubuntu" &>/dev/null; then \ @@ -16,6 +18,9 @@ RUN bash -c 'if id "ubuntu" &>/dev/null; then \ echo "Deleted user ubuntu."; \ fi' +# Create a non-root user +RUN useradd -m -s /bin/bash ${USER} + ################################################################################ FROM fans_base AS fans_ci @@ -44,6 +49,8 @@ RUN apt-get update -qq && apt-get install -y --no-install-recommends \ FROM fans_ci AS fans_dev ARG DEBIAN_FRONTEND +ARG USER +ARG FANS_venv=FANS_venv RUN apt-get update -qq && apt-get install -y --no-install-recommends \ # Packages required for setting up the non-root user @@ -63,25 +70,9 @@ RUN apt-get update -qq && apt-get install -y --no-install-recommends \ && apt-get autoremove --purge -y \ && rm -rf /var/lib/apt/lists/* -# Create a non-root user -ENV USER=develop -ENV UID=1000 -ENV GID=100 -ENV HOME=/home/${USER} -RUN adduser --disabled-password \ - --gecos "Non-root user" \ - --uid ${UID} \ - --gid ${GID} \ - --home ${HOME} \ - ${USER} \ - # - && echo ${USER} ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/${USER} \ - && chmod 0440 /etc/sudoers.d/${USER} - # Create a python venv for test/h52xdmf.py script USER ${USER} -ARG FANS_venv=FANS_venv RUN python -m venv /home/${USER}/venvs/${FANS_venv} && \ echo "\nsource /home/${USER}/venvs/${FANS_venv}/bin/activate\n" >> /home/${USER}/.bashrc && \ . /home/${USER}/venvs/${FANS_venv}/bin/activate && \ @@ -89,6 +80,10 @@ RUN python -m venv /home/${USER}/venvs/${FANS_venv} && \ USER root +# Add fans user to sudoers +RUN echo ${USER} ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/${USER} \ + && chmod 440 /etc/sudoers.d/${USER} + # Entrypoint script changes UID and GID to match given host UID and GID COPY --chmod=755 docker/Dockerfile_user_env_entrypoint.sh /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] diff --git a/include/material_models/J2Plasticity.h b/include/material_models/J2Plasticity.h new file mode 100644 index 0000000..5551b76 --- /dev/null +++ b/include/material_models/J2Plasticity.h @@ -0,0 +1,290 @@ +#ifndef J2PLASTICITY_H +#define J2PLASTICITY_H + +#include "matmodel.h" +#include "solver.h" + +class J2Plasticity : public MechModel { + public: + J2Plasticity(vector l_e, map> materialProperties) + : MechModel(l_e) + { + try { + bulk_modulus = materialProperties["bulk_modulus"]; + shear_modulus = materialProperties["shear_modulus"]; + yield_stress = materialProperties["yield_stress"]; // Initial yield stress + K = materialProperties["isotropic_hardening_parameter"]; // Isotropic hardening parameter + H = materialProperties["kinematic_hardening_parameter"]; // Kinematic hardening parameter + eta = materialProperties["viscosity"]; // Viscosity parameter + dt = materialProperties["time_step"][0]; // Time step + } catch (const std::out_of_range &e) { + throw std::runtime_error("Missing material properties for the requested material model."); + } + n_mat = bulk_modulus.size(); + + Matrix *Ce = new Matrix[n_mat]; + Matrix topLeft = Matrix::Zero(); + topLeft.topLeftCorner(3, 3).setConstant(1); + + kapparef_mat = Matrix::Zero(); + for (int i = 0; i < n_mat; ++i) { + Ce[i] = 3 * bulk_modulus[i] * topLeft + + 2 * shear_modulus[i] * (-1.0 / 3.0 * topLeft + Matrix::Identity()); + kapparef_mat += Ce[i]; + } + kapparef_mat /= n_mat; + + // Allocate the member matrices/vectors for performance optimization + sqrt_two_over_three = sqrt(2.0 / 3.0); + sigma_trial_n1.setZero(); + dev.setZero(); + qbar_trial_n1.setZero(); + n.setZero(); + eps_elastic.setZero(); + dev_minus_qbar.setZero(); + } + + /** + * @brief Initializes internal variables for the J2 plasticity model. + * + * This function sets up the internal variables required for the J2 plasticity model. + * It initializes the plastic strain and other internal variables for the given number + * of elements and Gauss points. + * + * @param num_elements The number of elements in the model. + * @param num_gauss_points The number of Gauss points per element. + * + * @note Variables with the suffix '_t' represent values from the previous time step. + */ + virtual void initializeInternalVariables(ptrdiff_t num_elements, int num_gauss_points) override + { + // Initialize plastic strain and other internal variables + plasticStrain.resize(num_elements, Matrix::Zero(6, num_gauss_points)); + plasticStrain_t.resize(num_elements, Matrix::Zero(6, num_gauss_points)); + psi.resize(num_elements, VectorXd::Zero(num_gauss_points)); + psi_t.resize(num_elements, VectorXd::Zero(num_gauss_points)); + psi_bar.resize(num_elements, Matrix::Zero(6, num_gauss_points)); + psi_bar_t.resize(num_elements, Matrix::Zero(6, num_gauss_points)); + } + + virtual void updateInternalVariables() override + { + plasticStrain_t = plasticStrain; + psi_t = psi; + psi_bar_t = psi_bar; + } + + void get_sigma(int i, int mat_index, ptrdiff_t element_idx) override + { + // Elastic Predictor + eps_elastic = eps.block<6, 1>(i, 0) - plasticStrain_t[element_idx].col(i / n_str); + treps = eps_elastic.head<3>().sum(); + + // Compute trial stress + sigma_trial_n1.head<3>().setConstant(bulk_modulus[mat_index] * treps); + sigma_trial_n1.head<3>() += 2 * shear_modulus[mat_index] * eps_elastic.head<3>(); + sigma_trial_n1.tail<3>() = 2 * shear_modulus[mat_index] * eps_elastic.tail<3>(); + + // Deviatoric stress and norm + dev = sigma_trial_n1; + dev.head<3>().array() -= sigma_trial_n1.head<3>().mean(); + + // Compute trial q and q_bar + q_trial_n1 = compute_q_trial(psi_t[element_idx](i / n_str), mat_index); + qbar_trial_n1.head<3>() = -H[mat_index] * (2.0 / 3.0) * psi_bar_t[element_idx].col(i / n_str).head<3>(); + qbar_trial_n1.tail<3>().setZero(); // Lower part is zero + + // Calculate the trial yield function + dev_minus_qbar = dev - qbar_trial_n1; + norm_dev_minus_qbar = dev_minus_qbar.norm(); + + // Avoid division by zero + n = (norm_dev_minus_qbar < 1e-12) ? n.setZero() : dev_minus_qbar / norm_dev_minus_qbar; + + f_trial = norm_dev_minus_qbar - sqrt_two_over_three * (yield_stress[mat_index] - q_trial_n1); + + // Compute plastic multiplier + gamma_n1 = (f_trial < 0) ? 0 : compute_gamma(f_trial, mat_index, i, element_idx); + + // Update stress and internal variables + sigma_trial_n1 -= gamma_n1 * 2 * shear_modulus[mat_index] * n; + plasticStrain[element_idx].col(i / n_str) = plasticStrain_t[element_idx].col(i / n_str) + gamma_n1 * n; + psi[element_idx](i / n_str) += gamma_n1 * sqrt_two_over_three; + psi_bar[element_idx].col(i / n_str) -= gamma_n1 * n; + + // Assign final stress + sigma.block<6, 1>(i, 0) = sigma_trial_n1; + } + + // Virtual methods for derived classes to implement different behaviors + virtual double compute_q_trial(double psi_val, int mat_index) = 0; + virtual double compute_gamma(double f_trial, int mat_index, int i, ptrdiff_t element_idx) = 0; + + void postprocess(Solver<3> &solver, Reader &reader, const char *resultsFileName, int load_idx, int time_idx) override; + + protected: + // Material properties + vector bulk_modulus; + vector shear_modulus; + vector yield_stress; + vector K; // Isotropic hardening parameter + vector H; // Kinematic hardening parameter + vector eta; // Viscosity parameter + double dt; // Time step + + // Internal variables + vector> plasticStrain; + vector> plasticStrain_t; + vector psi; + vector psi_t; + vector> psi_bar; + vector> psi_bar_t; + + // Preallocated member variables for reuse + Matrix sigma_trial_n1; + Matrix dev; + Matrix qbar_trial_n1; + Matrix n; + Matrix eps_elastic; + double treps; + double q_trial_n1; + double f_trial; + Matrix dev_minus_qbar; + double norm_dev_minus_qbar; + double gamma_n1; + double sqrt_two_over_three; +}; + +// Derived Class Linear Isotropic Hardening +class J2ViscoPlastic_LinearIsotropicHardening : public J2Plasticity { + public: + J2ViscoPlastic_LinearIsotropicHardening(vector l_e, map> materialProperties) + : J2Plasticity(l_e, materialProperties) + { + } + + double compute_q_trial(double psi_val, int mat_index) override + { + return -K[mat_index] * psi_val; + } + + double compute_gamma(double f_trial, int mat_index, int i, ptrdiff_t element_idx) override + { + return f_trial / (2 * shear_modulus[mat_index] + (2.0 / 3.0) * (K[mat_index] + H[mat_index]) + eta[mat_index] / dt); + } +}; + +// Derived Class Non-Linear (Exponential law) Isotropic Hardening +class J2ViscoPlastic_NonLinearIsotropicHardening : public J2Plasticity { + public: + J2ViscoPlastic_NonLinearIsotropicHardening(vector l_e, map> materialProperties) + : J2Plasticity(l_e, materialProperties) + { + try { + sigma_inf = materialProperties["saturation_stress"]; // Saturation stress + delta = materialProperties["saturation_exponent"]; // Saturation exponent + } catch (const std::out_of_range &e) { + throw std::runtime_error("Missing material properties for the requested material model."); + } + + // Precompute constants for optimization + denominator.resize(n_mat); + sigma_diff.resize(n_mat); + for (size_t i = 0; i < n_mat; ++i) { + denominator[i] = 2 * shear_modulus[i] + H[i] * (2.0 / 3.0) + eta[i] / dt; + sigma_diff[i] = sqrt_two_over_three * (sigma_inf[i] - yield_stress[i]); + } + } + + double compute_q_trial(double psi_val, int mat_index) override + { + return -K[mat_index] * psi_val - (sigma_inf[mat_index] - yield_stress[mat_index]) * (1 - exp(-delta[mat_index] * psi_val)); + } + + double compute_gamma(double f_trial, int mat_index, int i, ptrdiff_t element_idx) override + { + gamma_n1 = 0; + gamma_inc = 1; + NR_iter = 0; + while (gamma_inc > NR_tol && NR_iter < NR_max_iter) { + g = f_trial - gamma_n1 * denominator[mat_index] - + sigma_diff[mat_index] * + (-exp(-delta[mat_index] * (psi_t[element_idx](i / n_str) + sqrt_two_over_three * gamma_n1)) + exp(-delta[mat_index] * psi_t[element_idx](i / n_str))); + dg = -denominator[mat_index] - + (2 / 3) * (sigma_inf[mat_index] - yield_stress[mat_index]) * delta[mat_index] * exp(-delta[mat_index] * (psi_t[element_idx](i / n_str) + sqrt_two_over_three * gamma_n1)); + gamma_inc = -g / dg; + gamma_n1 += gamma_inc; + NR_iter++; + } + return gamma_n1; + } + + protected: + // Material properties + vector sigma_inf; // Saturation stress + vector delta; // Saturation exponent + private: + // Newton-Raphson parameters + double NR_tol = 1e-10; + int NR_max_iter = 10; + int NR_iter; + + // Preallocated member variables for reuse + double gamma_inc; + double g; + double dg; + + // Precomputed constants + vector denominator; // 2 * mu + H * (2/3) + eta/dt + vector sigma_diff; // sqrt(2/3) * (sigma_inf - yield_stress) +}; + +void J2Plasticity::postprocess(Solver<3> &solver, Reader &reader, const char *resultsFileName, int load_idx, int time_idx) +{ + int n_str = 6; // The plastic strain and stress vectors have 6 components each + VectorXd mean_plastic_strain = VectorXd::Zero(solver.local_n0 * solver.n_y * solver.n_z * n_str); + VectorXd mean_isotropic_hardening_variable = VectorXd::Zero(solver.local_n0 * solver.n_y * solver.n_z); + VectorXd mean_kinematic_hardening_variable = VectorXd::Zero(solver.local_n0 * solver.n_y * solver.n_z * n_str); + + // Compute the mean values for each element + for (ptrdiff_t elem_idx = 0; elem_idx < solver.local_n0 * solver.n_y * solver.n_z; ++elem_idx) { + mean_plastic_strain.segment(n_str * elem_idx, n_str) = plasticStrain_t[elem_idx].rowwise().mean(); + mean_isotropic_hardening_variable(elem_idx) = psi_t[elem_idx].mean(); + mean_kinematic_hardening_variable.segment(n_str * elem_idx, n_str) = psi_bar_t[elem_idx].rowwise().mean(); + } + + if (find(reader.resultsToWrite.begin(), reader.resultsToWrite.end(), "plastic_strain") != reader.resultsToWrite.end()) { + for (int i = 0; i < solver.world_size; ++i) { + if (i == solver.world_rank) { + char name[5096]; + sprintf(name, "%s/load%i/time_step%i/plastic_strain", reader.ms_datasetname, load_idx, time_idx); + reader.WriteSlab(mean_plastic_strain.data(), n_str, resultsFileName, name); + } + MPI_Barrier(MPI_COMM_WORLD); + } + } + + if (find(reader.resultsToWrite.begin(), reader.resultsToWrite.end(), "isotropic_hardening_variable") != reader.resultsToWrite.end()) { + for (int i = 0; i < solver.world_size; ++i) { + if (i == solver.world_rank) { + char name[5096]; + sprintf(name, "%s/load%i/time_step%i/isotropic_hardening_variable", reader.ms_datasetname, load_idx, time_idx); + reader.WriteSlab(mean_isotropic_hardening_variable.data(), 1, resultsFileName, name); + } + MPI_Barrier(MPI_COMM_WORLD); + } + } + + if (find(reader.resultsToWrite.begin(), reader.resultsToWrite.end(), "kinematic_hardening_variable") != reader.resultsToWrite.end()) { + for (int i = 0; i < solver.world_size; ++i) { + if (i == solver.world_rank) { + char name[5096]; + sprintf(name, "%s/load%i/time_step%i/kinematic_hardening_variable", reader.ms_datasetname, load_idx, time_idx); + reader.WriteSlab(mean_kinematic_hardening_variable.data(), n_str, resultsFileName, name); + } + MPI_Barrier(MPI_COMM_WORLD); + } + } +} + +#endif // J2PLASTICITY_H diff --git a/include/material_models/LinearElasticIsotropic.h b/include/material_models/LinearElasticIsotropic.h index a7858a9..684ba79 100644 --- a/include/material_models/LinearElasticIsotropic.h +++ b/include/material_models/LinearElasticIsotropic.h @@ -8,8 +8,12 @@ class LinearElasticIsotropic : public MechModel, public LinearModel<3> { LinearElasticIsotropic(vector l_e, map> materialProperties) : MechModel(l_e) { - bulk_modulus = materialProperties["bulk_modulus"]; - mu = materialProperties["shear_modulus"]; + try { + bulk_modulus = materialProperties["bulk_modulus"]; + mu = materialProperties["shear_modulus"]; + } catch (const std::exception &e) { + throw std::runtime_error("Missing material properties for the requested material model."); + } n_mat = bulk_modulus.size(); lambda.resize(n_mat); diff --git a/include/material_models/PseudoPlastic.h b/include/material_models/PseudoPlastic.h new file mode 100644 index 0000000..f3f8d21 --- /dev/null +++ b/include/material_models/PseudoPlastic.h @@ -0,0 +1,185 @@ +/** + * @file PseudoPlastic.h + * @brief This file contains the declaration of the PseudoPlastic class and its derived classes. + * + * The PseudoPlastic class is a base class that represents a pseudo-plastic material model. + * The models implemented are described in https://doi.org/10.1016/j.euromechsol.2017.11.007 -> Appendix A.1 and A.2. + * It contains common properties and methods for all pseudo-plastic material models. The derived classes, + * PseudoPlasticLinearHardening and PseudoPlasticNonLinearHardening, implement specific variations + * of the pseudo-plastic material model with linear and nonlinear hardening, respectively. + * + * The PseudoPlastic class and its derived classes are used in the FANS for simulating + * mechanical behavior of materials. + */ + +#ifndef PSEUDOPLASTIC_H +#define PSEUDOPLASTIC_H + +#include "matmodel.h" +#include "solver.h" + +class PseudoPlastic : public MechModel { + public: + PseudoPlastic(vector l_e, map> materialProperties) + : MechModel(l_e) + { + try { + bulk_modulus = materialProperties["bulk_modulus"]; + shear_modulus = materialProperties["shear_modulus"]; + yield_stress = materialProperties["yield_stress"]; + } catch (const std::exception &e) { + throw std::runtime_error("Missing material properties for the requested material model."); + } + n_mat = bulk_modulus.size(); + + // Initialize stiffness matrix (assuming for two materials, otherwise needs extension) + Matrix *Ce = new Matrix[n_mat]; + Matrix topLeft = Matrix::Zero(); + topLeft.topLeftCorner(3, 3).setConstant(1); + + kapparef_mat = Matrix::Zero(); + for (int i = 0; i < n_mat; ++i) { + Ce[i] = 3 * bulk_modulus[i] * topLeft + + 2 * shear_modulus[i] * (-1.0 / 3.0 * topLeft + Matrix::Identity()); + kapparef_mat += Ce[i]; + } + kapparef_mat /= n_mat; + } + + void initializeInternalVariables(ptrdiff_t num_elements, int num_gauss_points) override + { + plastic_flag.resize(num_elements, VectorXi::Zero(num_gauss_points)); + } + + virtual void get_sigma(int i, int mat_index, ptrdiff_t element_idx) override = 0; // Pure virtual method + + void postprocess(Solver<3> &solver, Reader &reader, const char *resultsFileName, int load_idx, int time_idx) override + { + VectorXf element_plastic_flag = VectorXf::Zero(solver.local_n0 * solver.n_y * solver.n_z); + for (ptrdiff_t elem_idx = 0; elem_idx < solver.local_n0 * solver.n_y * solver.n_z; ++elem_idx) { + element_plastic_flag(elem_idx) = plastic_flag[elem_idx].cast().mean(); + } + + if (find(reader.resultsToWrite.begin(), reader.resultsToWrite.end(), "plastic_flag") != reader.resultsToWrite.end()) { + for (int i = 0; i < solver.world_size; ++i) { + if (i == solver.world_rank) { + char name[5096]; + sprintf(name, "%s/load%i/time_step%i/plastic_flag", reader.ms_datasetname, load_idx, time_idx); + reader.WriteSlab(element_plastic_flag.data(), 1, resultsFileName, name); + } + MPI_Barrier(MPI_COMM_WORLD); + } + } + } + + protected: + vector bulk_modulus; + vector shear_modulus; + vector yield_stress; + vector eps_crit; + vector plastic_flag; + Matrix dev_eps; + double treps, norm_dev_eps, buf1, buf2; +}; + +class PseudoPlasticLinearHardening : public PseudoPlastic { + public: + PseudoPlasticLinearHardening(vector l_e, map> materialProperties) + : PseudoPlastic(l_e, materialProperties) + { + try { + hardening_parameter = materialProperties["hardening_parameter"]; + } catch (const std::exception &e) { + throw std::runtime_error("Missing material properties for the requested material model."); + } + + E_s.resize(n_mat); + eps_crit.resize(n_mat); + + for (int i = 0; i < n_mat; ++i) { + eps_crit[i] = sqrt(2. / 3.) * yield_stress[i] / (2. * shear_modulus[i]); + E_s[i] = (3. * shear_modulus[i]) / (3. * shear_modulus[i] + hardening_parameter[i]); + } + } + + void get_sigma(int i, int mat_index, ptrdiff_t element_idx) override + { + treps = eps.block<3, 1>(i, 0).sum(); + dev_eps.head<3>() = eps.block<3, 1>(i, 0) - (1.0 / 3.0) * treps * Matrix::Ones(); + dev_eps.tail<3>() = eps.block<3, 1>(i + 3, 0); + + norm_dev_eps = dev_eps.norm(); + buf1 = bulk_modulus[mat_index] * treps; + + if (norm_dev_eps <= eps_crit[mat_index]) { + buf2 = 2.0 * shear_modulus[mat_index]; + plastic_flag[element_idx](i / n_str) = mat_index; + } else { + buf2 = (b * yield_stress[mat_index] + a * E_s[mat_index] * hardening_parameter[mat_index] * + (norm_dev_eps - eps_crit[mat_index])) / + norm_dev_eps; + plastic_flag[element_idx](i / n_str) = this->n_mat + mat_index; + } + sigma.block<3, 1>(i, 0).setConstant(buf1); + sigma.block<3, 1>(i, 0) += buf2 * dev_eps.head<3>(); + sigma.block<3, 1>(i + 3, 0) = buf2 * dev_eps.tail<3>(); + } + + private: + vector hardening_parameter; + vector E_s; + double a = 2. / 3; + double b = sqrt(a); +}; + +class PseudoPlasticNonLinearHardening : public PseudoPlastic { + public: + PseudoPlasticNonLinearHardening(vector l_e, map> materialProperties) + : PseudoPlastic(l_e, materialProperties) + { + try { + hardening_exponent = materialProperties["hardening_exponent"]; + eps_0 = materialProperties["eps_0"]; // ε0 parameter + } catch (const std::exception &e) { + throw std::runtime_error("Missing material properties for the requested material model."); + } + + eps_crit.resize(n_mat); + for (int i = 0; i < n_mat; ++i) { + eps_crit[i] = eps_0[i] * pow(yield_stress[i] / (3.0 * shear_modulus[i] * eps_0[i]), 1.0 / (1.0 - hardening_exponent[i])); + } + } + + void get_sigma(int i, int mat_index, ptrdiff_t element_idx) override + { + treps = eps.block<3, 1>(i, 0).sum(); + dev_eps.head<3>() = eps.block<3, 1>(i, 0) - (1.0 / 3.0) * treps * Matrix::Ones(); + dev_eps.tail<3>() = eps.block<3, 1>(i + 3, 0); + + norm_dev_eps = sqrt(2.0 / 3.0) * dev_eps.norm(); // ε_eq + + buf1 = bulk_modulus[mat_index] * treps; + sigma.block<6, 1>(i, 0).setConstant(0); + if (norm_dev_eps <= eps_crit[mat_index]) { + buf2 = 2.0 * shear_modulus[mat_index]; + sigma.block<3, 1>(i, 0).setConstant(buf1); + sigma.block<3, 1>(i, 0) += buf2 * dev_eps.head<3>(); + sigma.block<3, 1>(i + 3, 0) = buf2 * dev_eps.tail<3>(); + + plastic_flag[element_idx](i / n_str) = mat_index; + } else { + buf2 = sqrt(2.0 / 3.0) * yield_stress[mat_index] * + pow(norm_dev_eps / eps_0[mat_index], hardening_exponent[mat_index]); + sigma.block<3, 1>(i, 0).setConstant(buf1); + sigma.block<6, 1>(i, 0) += buf2 * dev_eps / dev_eps.norm(); + + plastic_flag[element_idx](i / n_str) = this->n_mat + mat_index; + } + } + + private: + vector hardening_exponent; + vector eps_0; +}; + +#endif // PSEUDOPLASTIC_H diff --git a/include/material_models/PseudoPlasticLinearHardening.h b/include/material_models/PseudoPlasticLinearHardening.h deleted file mode 100644 index 3c107f1..0000000 --- a/include/material_models/PseudoPlasticLinearHardening.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef PSEUDOPLASTICLINEARHARDENING_H -#define PSEUDOPLASTICLINEARHARDENING_H - -#include "matmodel.h" -#include "solver.h" - -class PseudoPlasticLinearHardening : public MechModel { - public: - PseudoPlasticLinearHardening(vector l_e, map> materialProperties) - : MechModel(l_e) - { - bulk_modulus = materialProperties["bulk_modulus"]; - shear_modulus = materialProperties["shear_modulus"]; - yield_stress = materialProperties["yield_stress"]; - hardening_parameter = materialProperties["hardening_parameter"]; - - a = 2. / 3; - b = sqrt(a); - n_mat = bulk_modulus.size(); - - eps_crit.resize(n_mat); - E_s.resize(n_mat); - Matrix *Ce = new Matrix[n_mat]; - Matrix topLeft = Matrix::Zero(); - topLeft.topLeftCorner(3, 3).setConstant(1); - - for (int i = 0; i < n_mat; ++i) { - eps_crit[i] = sqrt(2. / 3.) * yield_stress[i] / (2. * shear_modulus[i]); - E_s[i] = (3. * shear_modulus[i]) / (3. * shear_modulus[i] + hardening_parameter[i]); - - Ce[i] = 3 * bulk_modulus[i] * topLeft + - 2 * shear_modulus[i] * (-1. / 3 * topLeft + Matrix::Identity()); - } - kapparef_mat = 0.5 * (Ce[0] + Ce[1]); // Note: only works for two materials - } - - void initializeInternalVariables(ptrdiff_t num_elements, int num_gauss_points) override - { - plastic_flag.resize(num_elements, VectorXi::Zero(num_gauss_points)); - } - - void get_sigma(int i, int mat_index, ptrdiff_t element_idx) override - { - treps = eps.block<3, 1>(i, 0).sum(); - dev_eps.head<3>() = eps.block<3, 1>(i, 0) - (1.0 / 3.0) * treps * Matrix::Ones(); - dev_eps.tail<3>() = eps.block<3, 1>(i + 3, 0); - - norm_dev_eps = dev_eps.norm(); - buf1 = bulk_modulus[mat_index] * treps; - - if (norm_dev_eps <= eps_crit[mat_index]) { - buf2 = 2.0 * shear_modulus[mat_index]; - plastic_flag[element_idx](i / n_str) = mat_index; - } else { - buf2 = (b * yield_stress[mat_index] + a * E_s[mat_index] * hardening_parameter[mat_index] * - (norm_dev_eps - eps_crit[mat_index])) / - norm_dev_eps; - plastic_flag[element_idx](i / n_str) = this->n_mat + mat_index; - } - sigma.block<3, 1>(i, 0).setConstant(buf1); - sigma.block<3, 1>(i, 0) += buf2 * dev_eps.head<3>(); - sigma.block<3, 1>(i + 3, 0) = buf2 * dev_eps.tail<3>(); - } - - void postprocess(Solver<3> &solver, Reader &reader, const char *resultsFileName, int load_idx, int time_idx) override; - - private: - vector bulk_modulus; - vector shear_modulus; - vector yield_stress; - vector hardening_parameter; - vector eps_crit; - vector E_s; - vector plastic_flag; - - Matrix dev_eps; - double treps, norm_dev_eps, buf1, buf2; - double a; - double b; -}; - -void PseudoPlasticLinearHardening::postprocess(Solver<3> &solver, Reader &reader, const char *resultsFileName, int load_idx, int time_idx) -{ - - VectorXf element_plastic_flag = VectorXf::Zero(solver.local_n0 * solver.n_y * solver.n_z); - for (ptrdiff_t elem_idx = 0; elem_idx < solver.local_n0 * solver.n_y * solver.n_z; ++elem_idx) { - element_plastic_flag(elem_idx) = plastic_flag[elem_idx].cast().mean(); - } - - if (find(reader.resultsToWrite.begin(), reader.resultsToWrite.end(), "plastic_flag") != reader.resultsToWrite.end()) { - for (int i = 0; i < solver.world_size; ++i) { - if (i == solver.world_rank) { - char name[5096]; - sprintf(name, "%s/load%i/time_step%i/plastic_flag", reader.ms_datasetname, load_idx, time_idx); - reader.WriteSlab(element_plastic_flag.data(), 1, resultsFileName, name); - } - MPI_Barrier(MPI_COMM_WORLD); - } - } -} - -#endif // PSEUDOPLASTICLINEARHARDENING_H diff --git a/include/material_models/VonMisesPlasticLinearIsotropicHardening.h b/include/material_models/VonMisesPlasticLinearIsotropicHardening.h deleted file mode 100644 index c1844d7..0000000 --- a/include/material_models/VonMisesPlasticLinearIsotropicHardening.h +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef VONMISESPLASTICLINEARISOTROPICHARDENING_H -#define VONMISESPLASTICLINEARISOTROPICHARDENING_H - -#include "matmodel.h" -#include "solver.h" - -class VonMisesPlasticLinearIsotropicHardening : public MechModel { - public: - VonMisesPlasticLinearIsotropicHardening(vector l_e, map> materialProperties) - : MechModel(l_e) - { - bulk_modulus = materialProperties["bulk_modulus"]; - shear_modulus = materialProperties["shear_modulus"]; - yield_stress = materialProperties["yield_stress"]; - hardening_parameter = materialProperties["hardening_parameter"]; - - n_mat = bulk_modulus.size(); - - two_G_plus_H.resize(n_mat); - sqrt_two_over_three = sqrt(2.0 / 3.0); - - Matrix *Ce = new Matrix[n_mat]; - Matrix topLeft = Matrix::Zero(); - topLeft.topLeftCorner(3, 3).setConstant(1); - - for (int i = 0; i < n_mat; ++i) { - Ce[i] = 3 * bulk_modulus[i] * topLeft + - 2 * shear_modulus[i] * (-1.0 / 3.0 * topLeft + Matrix::Identity()); - two_G_plus_H[i] = 2 * shear_modulus[i] + (2.0 / 3.0) * hardening_parameter[i]; - } - kapparef_mat = 0.5 * (Ce[0] + Ce[1]); // Note: only works for two materials - } - - void initializeInternalVariables(ptrdiff_t num_elements, int num_gauss_points) override - { - plastic_strain.resize(num_elements, Matrix::Zero(6, num_gauss_points)); - hardening_variable.resize(num_elements, VectorXd::Zero(num_gauss_points)); - - plastic_strain_t.resize(num_elements, Matrix::Zero(6, num_gauss_points)); - hardening_variable_t.resize(num_elements, VectorXd::Zero(num_gauss_points)); - } - - void get_sigma(int i, int mat_index, ptrdiff_t element_idx) override - { - - // Elastic Predictor - eps_elastic = eps.template block<6, 1>(i, 0) - plastic_strain_t[element_idx].col(i / n_str); - treps = eps_elastic.head<3>().sum(); - - // Compute trial stress - stress_trial.head<3>().setConstant(bulk_modulus[mat_index] * treps); - stress_trial.head<3>() += 2 * shear_modulus[mat_index] * eps_elastic.head<3>(); - stress_trial.tail<3>() = 2 * shear_modulus[mat_index] * eps_elastic.tail<3>(); - - // Deviatoric stress and von Mises equivalent stress - sigma_hydrostatic = stress_trial.head<3>().mean(); - dev_stress = stress_trial; - dev_stress.head<3>().array() -= sigma_hydrostatic; - norm_dev_stress = dev_stress.head<3>().norm(); - - // Yield function - yield_function = norm_dev_stress - sqrt_two_over_three * (yield_stress[mat_index] + hardening_parameter[mat_index] * hardening_variable_t[element_idx](i / n_str)); - - if (yield_function > 0) { - // Plastic correction - delta_lambda = yield_function / two_G_plus_H[mat_index]; - - // Update plastic strain and hardening variable - plastic_strain_increment = delta_lambda * (dev_stress / norm_dev_stress); - plastic_strain[element_idx].col(i / n_str) = plastic_strain_t[element_idx].col(i / n_str) + plastic_strain_increment; - - // Update hardening variable - hardening_variable[element_idx](i / n_str) = hardening_variable_t[element_idx](i / n_str) + sqrt_two_over_three * delta_lambda; - - // Update stress - stress_trial -= 2 * shear_modulus[mat_index] * plastic_strain_increment; - } - - // Final stress - sigma.template block<6, 1>(i, 0) = stress_trial; - } - - void postprocess(Solver<3> &solver, Reader &reader, const char *resultsFileName, int load_idx, int time_idx) override; - - private: - vector bulk_modulus; - vector shear_modulus; - vector yield_stress; - vector hardening_parameter; - vector two_G_plus_H; - double sqrt_two_over_three; - - // Internal variables - vector> plastic_strain; // Stores plastic strain at each Gauss point of each element - vector hardening_variable; // Stores hardening variable at each Gauss point of each element - - vector> plastic_strain_t; // Stores plastic strain at each Gauss point of each element - vector hardening_variable_t; // Stores hardening variable at each Gauss point of each element - - Matrix eps_elastic; - Matrix stress_trial; - Matrix dev_stress; - Matrix plastic_strain_increment; - double norm_dev_stress; - double yield_function; - double treps; - double sigma_hydrostatic; - double delta_lambda; -}; - -void VonMisesPlasticLinearIsotropicHardening::postprocess(Solver<3> &solver, Reader &reader, const char *resultsFileName, int load_idx, int time_idx) -{ - plastic_strain_t = plastic_strain; - hardening_variable_t = hardening_variable; - - int n_str = 6; // The plastic strain and stress vectors have 6 components each - VectorXd mean_plastic_strain = VectorXd::Zero(solver.local_n0 * solver.n_y * solver.n_z * n_str); - VectorXd mean_hardening_variable = VectorXd::Zero(solver.local_n0 * solver.n_y * solver.n_z); - - // Compute the mean values for each element - for (ptrdiff_t elem_idx = 0; elem_idx < solver.local_n0 * solver.n_y * solver.n_z; ++elem_idx) { - mean_plastic_strain.segment(n_str * elem_idx, n_str) = plastic_strain[elem_idx].rowwise().mean(); - mean_hardening_variable(elem_idx) = hardening_variable[elem_idx].mean(); - } - - if (find(reader.resultsToWrite.begin(), reader.resultsToWrite.end(), "plastic_strain") != reader.resultsToWrite.end()) { - for (int i = 0; i < solver.world_size; ++i) { - if (i == solver.world_rank) { - char name[5096]; - sprintf(name, "%s/load%i/time_step%i/plastic_strain", reader.ms_datasetname, load_idx, time_idx); - reader.WriteSlab(mean_plastic_strain.data(), n_str, resultsFileName, name); - } - MPI_Barrier(MPI_COMM_WORLD); - } - } - - if (find(reader.resultsToWrite.begin(), reader.resultsToWrite.end(), "hardening_variable") != reader.resultsToWrite.end()) { - for (int i = 0; i < solver.world_size; ++i) { - if (i == solver.world_rank) { - char name[5096]; - sprintf(name, "%s/load%i/time_step%i/hardening_variable", reader.ms_datasetname, load_idx, time_idx); - reader.WriteSlab(mean_hardening_variable.data(), 1, resultsFileName, name); - } - MPI_Barrier(MPI_COMM_WORLD); - } - } -} - -#endif // VONMISESPLASTICLINEARISOTROPICHARDENING_H diff --git a/include/matmodel.h b/include/matmodel.h index 8c13cec..f99519d 100644 --- a/include/matmodel.h +++ b/include/matmodel.h @@ -39,6 +39,7 @@ class Matmodel { virtual void postprocess(Solver &solver, Reader &reader, const char *resultsFileName, int load_idx, int time_idx) {} virtual void initializeInternalVariables(ptrdiff_t num_elements, int num_gauss_points) {} + virtual void updateInternalVariables() {} protected: double l_e_x; diff --git a/include/setup.h b/include/setup.h index 2e91669..79d3581 100644 --- a/include/setup.h +++ b/include/setup.h @@ -6,8 +6,8 @@ // Mechanical models #include "material_models/LinearElasticIsotropic.h" -#include "material_models/PseudoPlasticLinearHardening.h" -#include "material_models/VonMisesPlasticLinearIsotropicHardening.h" +#include "material_models/PseudoPlastic.h" +#include "material_models/J2Plasticity.h" template Matmodel *createMatmodel(const Reader &reader); @@ -25,12 +25,22 @@ Matmodel<1> *createMatmodel(const Reader &reader) template <> Matmodel<3> *createMatmodel(const Reader &reader) { + // Linear Elastic models if (reader.matmodel == "LinearElasticIsotropic") { return new LinearElasticIsotropic(reader.l_e, reader.materialProperties); + + // Pseudo Plastic models } else if (reader.matmodel == "PseudoPlasticLinearHardening") { return new PseudoPlasticLinearHardening(reader.l_e, reader.materialProperties); - } else if (reader.matmodel == "VonMisesPlasticLinearIsotropicHardening") { - return new VonMisesPlasticLinearIsotropicHardening(reader.l_e, reader.materialProperties); + } else if (reader.matmodel == "PseudoPlasticNonLinearHardening") { + return new PseudoPlasticNonLinearHardening(reader.l_e, reader.materialProperties); + + // J2 Plastic models + } else if (reader.matmodel == "J2ViscoPlastic_LinearIsotropicHardening") { + return new J2ViscoPlastic_LinearIsotropicHardening(reader.l_e, reader.materialProperties); + } else if (reader.matmodel == "J2ViscoPlastic_NonLinearIsotropicHardening") { + return new J2ViscoPlastic_NonLinearIsotropicHardening(reader.l_e, reader.materialProperties); + } else { throw std::invalid_argument(reader.matmodel + " is not a valid matmodel for mechanical problem"); } diff --git a/include/solver.h b/include/solver.h index eb44609..17531db 100644 --- a/include/solver.h +++ b/include/solver.h @@ -247,6 +247,7 @@ void Solver::solve() printf("# Total Time ................... %2.6f sec\n", double(tot_time) / CLOCKS_PER_SEC); printf("# FFT contribution to total time %2.6f %% \n", 100. * double(fft_time) / double(tot_time)); } + matmodel->updateInternalVariables(); } template diff --git a/src/reader.cpp b/src/reader.cpp index 03e9ba8..5a2e2b1 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -204,6 +204,10 @@ void Reader ::ReadMS(int hm) alloc_local = fftw_mpi_local_size_many_transposed(rank, n, hm, block0, block1, MPI_COMM_WORLD, &local_n0, &local_0_start, &local_n1, &local_1_start); + if (local_n0 < 4) + throw std::runtime_error("[ FANS3D_Grid ] ERROR: Number of voxels in x-direction is less than 4 in process " + to_string(world_rank)); + MPI_Barrier(MPI_COMM_WORLD); + // Each process defines a dataset in memory which reads a hyperslab from the file count[0] = local_n0; count[1] = dims[1]; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..5969958 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,33 @@ +set(FANS_TEST_INPUT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(FANS_TEST_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) +set(FANS_EXECUTABLE $) + +# determine MPI process count. The discretization of the test geometry allows for max. 8 processes. +set(FANS_N_MPI_PROCESSES_MAX 8) +cmake_host_system_information(RESULT FANS_CORES_AVAILABLE QUERY NUMBER_OF_PHYSICAL_CORES) +if (FANS_N_MPI_PROCESSES_MAX LESS FANS_CORES_AVAILABLE) + set(FANS_N_MPI_PROCESSES ${FANS_N_MPI_PROCESSES_MAX}) +else() + set(FANS_N_MPI_PROCESSES ${FANS_CORES_AVAILABLE}) +endif() +message(STATUS "Will use ${FANS_N_MPI_PROCESSES} processes for MPI test cases.") + +set(FANS_TEST_CASES + J2Plasticity + LinearElastic + LinearThermal + PseudoPlastic +) + +list(LENGTH FANS_TEST_CASES N_TESTS) +math(EXPR N_TESTS "${N_TESTS} - 1") + +foreach(N RANGE ${N_TESTS}) + list(GET FANS_TEST_CASES ${N} FANS_TEST_CASE) + + add_test( + NAME ${FANS_TEST_CASE} + COMMAND mpiexec -n ${FANS_N_MPI_PROCESSES} ${FANS_EXECUTABLE} input_files/test_${FANS_TEST_CASE}.json ${FANS_TEST_OUTPUT_DIR}/test_${FANS_TEST_CASE}.h5 + WORKING_DIRECTORY ${FANS_TEST_INPUT_DIR} + ) +endforeach() diff --git a/test/input_files/test_VonMisesPlasticLinearIsotropicHardening.json b/test/input_files/test_J2Plasticity.json similarity index 95% rename from test/input_files/test_VonMisesPlasticLinearIsotropicHardening.json rename to test/input_files/test_J2Plasticity.json index 098c541..ef770ee 100644 --- a/test/input_files/test_VonMisesPlasticLinearIsotropicHardening.json +++ b/test/input_files/test_J2Plasticity.json @@ -4,17 +4,23 @@ "ms_L": [1.0, 1.0, 1.0], "problem_type": "mechanical", - "matmodel": "VonMisesPlasticLinearIsotropicHardening", + "matmodel": "J2ViscoPlastic_NonLinearIsotropicHardening", "material_properties":{ "bulk_modulus": [62.5000, 222.222], "shear_modulus": [28.8462, 166.6667], "yield_stress": [0.1, 10000], - "hardening_parameter": [0.0, 0.0] + "isotropic_hardening_parameter": [0.0, 0.0], + "kinematic_hardening_parameter": [0.0, 0.0], + "viscosity": [1, 1], + "time_step": [0.01], + + "saturation_stress": [0.15, 10000], + "saturation_exponent": [1000, 1000] }, "method": "cg", "TOL": 1e-10, - "n_it": 500, + "n_it": 100, "macroscale_loading": [ [ [0.0000, 0, 0, 0, 0, 0], [0.0001, 0, 0, 0, 0, 0], [0.0002, 0, 0, 0, 0, 0], @@ -171,5 +177,5 @@ "results": ["stress_average", "strain_average", "absolute_error", "phase_stress_average", "phase_strain_average", "microstructure", "displacement", "stress", "strain", - "plastic_strain", "hardening_variable"] + "plastic_strain", "kinematic_hardening_variable", "isotropic_hardening_variable"] } diff --git a/test/input_files/test_LinearElasticIsotropic.json b/test/input_files/test_LinearElastic.json similarity index 100% rename from test/input_files/test_LinearElasticIsotropic.json rename to test/input_files/test_LinearElastic.json diff --git a/test/input_files/test_LinearThermalIsotropic.json b/test/input_files/test_LinearThermal.json similarity index 100% rename from test/input_files/test_LinearThermalIsotropic.json rename to test/input_files/test_LinearThermal.json diff --git a/test/input_files/test_PseudoPlasticLinearHardening.json b/test/input_files/test_PseudoPlastic.json similarity index 55% rename from test/input_files/test_PseudoPlasticLinearHardening.json rename to test/input_files/test_PseudoPlastic.json index f7f8efd..12deb08 100644 --- a/test/input_files/test_PseudoPlasticLinearHardening.json +++ b/test/input_files/test_PseudoPlastic.json @@ -4,70 +4,72 @@ "ms_L": [1.0, 1.0, 1.0], "problem_type": "mechanical", - "matmodel": "PseudoPlasticLinearHardening", + "matmodel": "PseudoPlasticNonLinearHardening", "material_properties":{ "bulk_modulus": [62.5000, 222.222], "shear_modulus": [28.8462, 166.6667], "yield_stress": [0.1, 10000], - "hardening_parameter": [0.0, 0.0] + "hardening_parameter": [0.0, 0.0], + "hardening_exponent": [0.2, 0.2], + "eps_0": [0.01, 0.01] }, "method": "cg", "TOL": 1e-10, - "n_it": 500, + "n_it": 100, "macroscale_loading": [ [ [0.0000, -0.0000, -0.0000, 0, 0, 0], + [0.0001, -5e-05, -5e-05, 0, 0, 0], [0.0002, -0.0001, -0.0001, 0, 0, 0], + [0.0003, -0.00015, -0.00015, 0, 0, 0], [0.0004, -0.0002, -0.0002, 0, 0, 0], + [0.0005, -0.00025, -0.00025, 0, 0, 0], [0.0006, -0.0003, -0.0003, 0, 0, 0], + [0.0007, -0.00035, -0.00035, 0, 0, 0], [0.0008, -0.0004, -0.0004, 0, 0, 0], - [0.001, -0.0005, -0.0005, 0, 0, 0 ], + [0.0009, -0.00045, -0.00045, 0, 0, 0], + [0.001, -0.0005, -0.0005, 0, 0, 0], + [0.0011, -0.00055, -0.00055, 0, 0, 0], [0.0012, -0.0006, -0.0006, 0, 0, 0], + [0.0013, -0.00065, -0.00065, 0, 0, 0], [0.0014, -0.0007, -0.0007, 0, 0, 0], + [0.0015, -0.00075, -0.00075, 0, 0, 0], [0.0016, -0.0008, -0.0008, 0, 0, 0], + [0.0017, -0.00085, -0.00085, 0, 0, 0], [0.0018, -0.0009, -0.0009, 0, 0, 0], - [0.002, -0.001, -0.001, 0, 0, 0 ], + [0.0019, -0.00095, -0.00095, 0, 0, 0], + [0.002, -0.001, -0.001, 0, 0, 0], + [0.0021, -0.00105, -0.00105, 0, 0, 0], [0.0022, -0.0011, -0.0011, 0, 0, 0], + [0.0023, -0.00115, -0.00115, 0, 0, 0], [0.0024, -0.0012, -0.0012, 0, 0, 0], + [0.0025, -0.00125, -0.00125, 0, 0, 0], [0.0026, -0.0013, -0.0013, 0, 0, 0], + [0.0027, -0.00135, -0.00135, 0, 0, 0], [0.0028, -0.0014, -0.0014, 0, 0, 0], - [0.003, -0.0015, -0.0015, 0, 0, 0 ], + [0.0029, -0.00145, -0.00145, 0, 0, 0], + [0.003, -0.0015, -0.0015, 0, 0, 0], + [0.0031, -0.00155, -0.00155, 0, 0, 0], [0.0032, -0.0016, -0.0016, 0, 0, 0], + [0.0033, -0.00165, -0.00165, 0, 0, 0], [0.0034, -0.0017, -0.0017, 0, 0, 0], + [0.0035, -0.00175, -0.00175, 0, 0, 0], [0.0036, -0.0018, -0.0018, 0, 0, 0], + [0.0037, -0.00185, -0.00185, 0, 0, 0], [0.0038, -0.0019, -0.0019, 0, 0, 0], - [0.004, -0.002, -0.002, 0, 0, 0 ], + [0.0039, -0.00195, -0.00195, 0, 0, 0], + [0.004, -0.002, -0.002, 0, 0, 0], + [0.0041, -0.00205, -0.00205, 0, 0, 0], [0.0042, -0.0021, -0.0021, 0, 0, 0], + [0.0043, -0.00215, -0.00215, 0, 0, 0], [0.0044, -0.0022, -0.0022, 0, 0, 0], + [0.0045, -0.00225, -0.00225, 0, 0, 0], [0.0046, -0.0023, -0.0023, 0, 0, 0], + [0.0047, -0.00235, -0.00235, 0, 0, 0], [0.0048, -0.0024, -0.0024, 0, 0, 0], - [0.005, -0.0025, -0.0025, 0, 0, 0 ], - [0.0052, -0.0026, -0.0026, 0, 0, 0], - [0.0054, -0.0027, -0.0027, 0, 0, 0], - [0.0056, -0.0028, -0.0028, 0, 0, 0], - [0.0058, -0.0029, -0.0029, 0, 0, 0], - [0.006, -0.003, -0.003, 0, 0, 0 ], - [0.0062, -0.0031, -0.0031, 0, 0, 0], - [0.0064, -0.0032, -0.0032, 0, 0, 0], - [0.0066, -0.0033, -0.0033, 0, 0, 0], - [0.0068, -0.0034, -0.0034, 0, 0, 0], - [0.007, -0.0035, -0.0035, 0, 0, 0 ], - [0.0072, -0.0036, -0.0036, 0, 0, 0], - [0.0074, -0.0037, -0.0037, 0, 0, 0], - [0.0076, -0.0038, -0.0038, 0, 0, 0], - [0.0078, -0.0039, -0.0039, 0, 0, 0], - [0.008, -0.004, -0.004, 0, 0, 0 ], - [0.0082, -0.0041, -0.0041, 0, 0, 0], - [0.0084, -0.0042, -0.0042, 0, 0, 0], - [0.0086, -0.0043, -0.0043, 0, 0, 0], - [0.0088, -0.0044, -0.0044, 0, 0, 0], - [0.009, -0.0045, -0.0045, 0, 0, 0 ], - [0.0092, -0.0046, -0.0046, 0, 0, 0], - [0.0094, -0.0047, -0.0047, 0, 0, 0], - [0.0096, -0.0048, -0.0048, 0, 0, 0], - [0.0098, -0.0049, -0.0049, 0, 0, 0], - [0.01, -0.005, -0.005, 0, 0, 0 ] + [0.0049, -0.00245, -0.00245, 0, 0, 0], + [0.005, -0.0025, -0.0025, 0, 0, 0] ] ], diff --git a/test/run_tests.sh b/test/run_tests.sh index be997b3..ef95e54 100755 --- a/test/run_tests.sh +++ b/test/run_tests.sh @@ -9,10 +9,10 @@ fi num_processes=$2 # Run the jobs serially -command time -v mpiexec -n $num_processes ./FANS input_files/test_LinearThermalIsotropic.json test_LinearThermalIsotropic.h5 > test_LinearThermalIsotropic.log 2>&1 +command time -v mpiexec -n $num_processes ./FANS input_files/test_LinearThermal.json test_LinearThermal.h5 > test_LinearThermal.log 2>&1 -command time -v mpiexec -n $num_processes ./FANS input_files/test_LinearElasticIsotropic.json test_LinearElasticIsotropic.h5 > test_LinearElasticIsotropic.log 2>&1 +command time -v mpiexec -n $num_processes ./FANS input_files/test_LinearElastic.json test_LinearElastic.h5 > test_LinearElastic.log 2>&1 -command time -v mpiexec -n $num_processes ./FANS input_files/test_PseudoPlasticLinearHardening.json test_PseudoPlasticLinearHardening.h5 > test_PseudoPlasticLinearHardening.log 2>&1 +command time -v mpiexec -n $num_processes ./FANS input_files/test_PseudoPlastic.json test_PseudoPlastic.h5 > test_PseudoPlastic.log 2>&1 -command time -v mpiexec -n $num_processes ./FANS input_files/test_VonMisesPlasticLinearIsotropicHardening.json test_VonMisesPlasticLinearIsotropicHardening.h5 > test_VonMisesPlasticLinearIsotropicHardening.log 2>&1 +command time -v mpiexec -n $num_processes ./FANS input_files/test_J2Plasticity.json test_J2Plasticity.h5 > test_J2Plasticity.log 2>&1