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
-## 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