-
Notifications
You must be signed in to change notification settings - Fork 5
Workflow example with linear elasticity
- This example demonstrates how to create component-wise ROM from multiple snapshots of a small FOM.
- Predictions are then made on a larger FOM configuration.
- We plot the correlation between relative error, speedup and the number of bases for the ROM.
- The full code is provided at the end of the page.
Above figure: Full Order Model. Prescribed displacements in red. Left boundary is clamped.
We seek to train a component-wise ROM that can accurately predict the deformation field of a linear elastic FOM. The FOM is a lattice structure with a clamped left boundary and a prescribed vertical downwards vertical displacement on the right boundary, see above figure. The FOM lattice is made up of three components: one vertical rod with 512 degrees of freedom (DOFs), one horizontal rod, which is just a rotation of the vertical rod, and one square joint component with 128 DOFs. In total, the FOM lattice consists of 72 vertical rods, 72 horizontal rods and 81 joints, leading to a total FOM dimension of 84,096.
Above figure: FOM components. Dimensions in black text, boundary attributes in blue text.
We use the following script to generate the large FOM configuration file, assuming that the current work directory is the main scaleupROM
folder. Here, n
is the number of grid sections in each dimension (so the total number of joints is (n+1)^2
and the number of rods of each type is n * (n-1)
)
n=8
python3 utils/python/linelast_comp.py lattice_cantilever $n $n
This will create the FOM configuration file in the scaleupROM
folder. Below are some convenience terminal commands to move the configuration file to the examples/linelast/config
and build/examples/linelast/config
folders:
# Copy FOM config to source directory
rm examples/linelast/config/linelast.lattice.h5
cp linelast.lattice.h5 examples/linelast/config
# Copy FOM config to build directory
rm build/examples/linelast/config/linelast.lattice.h5
cp linelast.lattice.h5 build/examples/linelast/config
# Remove FOM config file in main directory
rm linelast.lattice.h5
The goal of our approach is to "Train small, predict large", so we want to generate the training data on a system that is much smaller than the FOM, but still captures the physical behavior of the larger scale structure. We show two ways to do this: gathering snapshots from a smaller FOM, or gathering snapshots from the individual components themselves.
The parameterized problem is shown in the figure below. For a rectangular training model, Dirichlet boundary conditions (corresponding to prescribed displacements) and inhomogenous Neumann boundary conditions (corresponding to external forces) are applied to the boundaries.
Above figure: Parameterized Problem. Prescribed displacements in red. Applied external forces in blue.
The Dirichlet BCs are parameterized as
In the training data generation, all parameters are sampled with a uniform probability distribution over their interval.
We enrich the training data by changing the sides of the training model where the Dirichlet and Neumann BCs are applied. Four different snapshot generation runs for four different BC setups are done in total, see the below figure.
Above figure: Parameterized Problem Permutations. Prescribed displacements in red. Applied external forces in blue. BC setup ID in black.
In the case of the small FOM sampling, our training model is a small portion of the FOM. The Neumann and Dirichlet boundary conditions are applied to the outer boundaries and the inner boundaries have homogenous boundary conditions.
Above figure: Small FOM for BC setup 0. Note that the inner boundaries doesn't have prescribed boundary conditions or applied forces
We start the sampling by creating a configuration file in a similar way to the FOM. The small FOM sampling can be done on a grid of 1x1 grid section (option: cwtrain_1x1
) or on a grid of 2x2 sections (option: cwtrain_2x2
). The following code generates four different configuration files, each one corresponding to a different BC setup (see previous section).
# Create configs for componentwise training
python3 utils/python/linelast_cwtrain.py cwtrain_1x1
# Copy to examples and build folders
for i in {0..3}
do
rm examples/linelast/config/linelast.comp_train$i.h5
cp linelast.comp_train$i.h5 examples/linelast/config
rm build/examples/linelast/config/linelast.comp_train$i.h5
cp linelast.comp_train$i.h5 build/examples/linelast/config
rm linelast.comp_train$i.h5
done
The next step is the actual sample generation, which is done once for every configuration file. The variable n_samp
sets the number of samples per BC setup.
cd ~/build/examples/linelast
# Sample generation
n_samp=100
for i in {0..3}
do
echo "Training $i"
../../bin/main -i linelast.comp_train.yml -f main/mode=sample_generation:mesh/component-wise/global_config="config/linelast.comp_train$i.h5":sample_generation/file_path/prefix="linelast_cwtrain$i":sample_generation/random_sample_generator/number_of_samples=$n_samp
done
Since the sampling is done for different configuration files, which is not standard training procedure, the snapshot file names will not match the name format for training the ROM. Therefore we need to rename the snapshot files:
for i in {0..3}
do
echo "Rename $i"
mv linelast_cwtrain$i\_sample_joint2D_snapshot.000000 linelast_cwtrain_sample_joint2D_snapshot$i\.000000
mv linelast_cwtrain$i\_sample_rod2D_H_snapshot.000000 linelast_cwtrain_sample_rod2D_H_snapshot$i\.000000
mv linelast_cwtrain$i\_sample_rod2D_V_snapshot.000000 linelast_cwtrain_sample_rod2D_V_snapshot$i\.000000
done
For the individual component sampling, no configuration file is used. Instead, we need to generate four different mesh files with shifted boundary attributes, to designate where the Dirichlet and Neumann BCs are applied.
cd ~/build/examples/linelast
# Generate sampling meshes
python3 utils/python/linelast_cwtrain.py cwtrain_mesh build/examples/linelast/meshes
Then the sample generation is run for each component and BC setup.
cd ~/build/examples/linelast
n_samp=600
for i in {0..3}
do
echo "Training $i"
../../bin/main -i linelast.comp_train.yml -f main/mode=sample_generation:sample_generation/file_path/prefix="linelast_cwtrain_joint2D_$i":mesh/filename="meshes/joint2D_$i.mesh":sample_generation/random_sample_generator/number_of_samples=$n_samp:mesh/type=submesh
../../bin/main -i linelast.comp_train.yml -f main/mode=sample_generation:sample_generation/file_path/prefix="linelast_cwtrain_rod2D_H_$i":mesh/filename="meshes/rod2D_H_$i.mesh":sample_generation/random_sample_generator/number_of_samples=$n_samp:mesh/type=submesh
../../bin/main -i linelast.comp_train.yml -f main/mode=sample_generation:sample_generation/file_path/prefix="linelast_cwtrain_rod2D_V_$i":mesh/filename="meshes/rod2D_V_$i.mesh":sample_generation/random_sample_generator/number_of_samples=$n_samp:mesh/type=submesh
done
Finally, we rename the components to fit the snapshot name format for ROM training.
for i in {0..3}
do
echo "Rename $i"
mv linelast_cwtrain_joint2D_$i\_sample_comp0_snapshot.000000 linelast_cwtrain_sample_joint2D_snapshot$i\.000000
mv linelast_cwtrain_rod2D_H_$i\_sample_comp0_snapshot.000000 linelast_cwtrain_sample_rod2D_H_snapshot$i\.000000
mv linelast_cwtrain_rod2D_V_$i\_sample_comp0_snapshot.000000 linelast_cwtrain_sample_rod2D_V_snapshot$i\.000000
done
We then train the ROM by combining the different snapshot files generated either by individual component sampling or small FOM sampling. The keyword basis/tags/2/snapshot_format/maximum
tells us the maximum number in the snapshot file name for each component (every component corresponds to a tag). In this case we set it to 3
, since for every component, we have four snapshot files labeled from 0-3
cd ~/build/examples/linelast
../../bin/main -i linelast.comp_train.yml -f main/mode=train_rom:basis/tags/0/snapshot_format/maximum=3:basis/tags/1/snapshot_format/maximum=3:basis/tags/2/snapshot_format/maximum=3
The final step is to assess the accuracy and speedup of the ROM. We do this in the below code by varying the number of ROM basis vectors for each component. Here, n
is the number of basis vectors for the joint component and nn = 4*n
is the number of basis vectors for the rod components. The resulting plot shows the decrease in relative error and speedup as the dimension of the ROM basis increases.
cd ~/build/examples/linelast
# Create directory for basis scaling.
mkdir basis_scaling
# Run basis scaling
for n in 2 4 6 8 10 12 16 20 24 28 32 40 48 56 64 72 80 88 96 104 112 120 128
do
nn=$((4*$n))
echo "Prediction $n"
# Building ROM
../../bin/main -i linelast.comp_train.yml -f main/mode=build_rom:main/use_rom=true:basis/tags/0/number_of_basis=$n:basis/tags/1/number_of_basis=$nn:basis/tags/2/number_of_basis=$nn
# Single run with larger FOM configuration
../../bin/main -i linelast.comp_train.yml -f main/use_rom=true:mesh/component-wise/global_config="config/linelast.lattice.h5":parameterized_problem/name="linelast_disp_lattice":single_run/linelast_disp_lattice/rdisp_f=1.0:basis/tags/0/number_of_basis=$n:basis/tags/1/number_of_basis=$nn:basis/tags/2/number_of_basis=$nn -o "basis_scaling/comparison$n.h5"
done
# Plot results
python3 ../../../utils/python/linelast_cwtrain.py bscale basis_scaling scaling.png
n=8
python3 utils/python/linelast_comp.py lattice_cantilever $n $n
# Copy FOM config to source directory
rm examples/linelast/config/linelast.lattice.h5
cp linelast.lattice.h5 examples/linelast/config
# Copy FOM config to build directory
rm build/examples/linelast/config/linelast.lattice.h5
cp linelast.lattice.h5 build/examples/linelast/config
# Remove FOM config file in main directory
rm linelast.lattice.h5
# Create configs for componentwise training
python3 utils/python/linelast_cwtrain.py cwtrain_1x1
# Copy to examples and build folders
for i in {0..3}
do
rm examples/linelast/config/linelast.comp_train$i.h5
cp linelast.comp_train$i.h5 examples/linelast/config
rm build/examples/linelast/config/linelast.comp_train$i.h5
cp linelast.comp_train$i.h5 build/examples/linelast/config
rm linelast.comp_train$i.h5
done
cd ~/build/examples/linelast
# Sample generation
n_samp=100
for i in {0..3}
do
echo "Training $i"
../../bin/main -i linelast.comp_train.yml -f main/mode=sample_generation:mesh/component-wise/global_config="config/linelast.comp_train$i.h5":sample_generation/file_path/prefix="linelast_cwtrain$i":sample_generation/random_sample_generator/number_of_samples=$n_samp
done
for i in {0..3}
do
echo "Rename $i"
mv linelast_cwtrain$i\_sample_joint2D_snapshot.000000 linelast_cwtrain_sample_joint2D_snapshot$i\.000000
mv linelast_cwtrain$i\_sample_rod2D_H_snapshot.000000 linelast_cwtrain_sample_rod2D_H_snapshot$i\.000000
mv linelast_cwtrain$i\_sample_rod2D_V_snapshot.000000 linelast_cwtrain_sample_rod2D_V_snapshot$i\.000000
done
../../bin/main -i linelast.comp_train.yml -f main/mode=train_rom:basis/tags/0/snapshot_format/maximum=3:basis/tags/1/snapshot_format/maximum=3:basis/tags/2/snapshot_format/maximum=3
# Create directory for basis scaling.
mkdir basis_scaling
# Run basis scaling
for n in 2 4 6 8 10 12 16 20 24 28 32 40 48 56 64 72 80 88 96 104 112 120 128
do
nn=$((4*$n))
echo "Prediction $n"
# Building ROM
../../bin/main -i linelast.comp_train.yml -f main/mode=build_rom:main/use_rom=true:basis/tags/0/number_of_basis=$n:basis/tags/1/number_of_basis=$nn:basis/tags/2/number_of_basis=$nn
# Single run with larger FOM configuration
../../bin/main -i linelast.comp_train.yml -f main/use_rom=true:mesh/component-wise/global_config="config/linelast.lattice.h5":parameterized_problem/name="linelast_disp_lattice":single_run/linelast_disp_lattice/rdisp_f=1.0:basis/tags/0/number_of_basis=$n:basis/tags/1/number_of_basis=$nn:basis/tags/2/number_of_basis=$nn -o "basis_scaling/comparison$n.h5"
done
# Plot results
python3 ../../../utils/python/linelast_cwtrain.py bscale basis_scaling scaling.png