Module example2bis
Follow-up Example: Introducing Physics via Forcefields (Example2bis)
This script builds upon Example2 by introducing physics into the simulation through the use of forcefields. It demonstrates the integration of forcefields into the simulation workflow, their customization for different regions, and their incorporation into the overall LAMMPS script.
Objective
The goal of this example is to extend the functionality of Example2 by adding: 1. Forcefield Definitions: Introduce physical properties for simulation particles. 2. Customization: Derive region-specific forcefields with modified physical parameters. 3. Integration: Incorporate forcefields into the LAMMPS script dynamically. 4. Analysis and Debugging: Explore variables and generate detailed reports.
Key Features
- Forcefield Initialization: Create and customize forcefields programmatically or using DSCRIPT syntax.
- Dynamic Region-Specific Adjustments: Modify forcefield parameters for different subregions.
- Script Integration: Combine forcefields with previous simulation steps.
- Debugging: Analyze variable occurrences and validate workflow consistency.
Last revision 2025-01-07 Author: INRAE\olivier.vitrac@agroparistech.fr
Expand source code
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
### Follow-up Example: Introducing Physics via Forcefields (Example2bis)
This script builds upon Example2 by introducing **physics** into the simulation through the use of forcefields. It demonstrates the integration of forcefields into the simulation workflow, their customization for different regions, and their incorporation into the overall LAMMPS script.
---
### **Objective**
The goal of this example is to extend the functionality of Example2 by adding:
1. **Forcefield Definitions:** Introduce physical properties for simulation particles.
2. **Customization:** Derive region-specific forcefields with modified physical parameters.
3. **Integration:** Incorporate forcefields into the LAMMPS script dynamically.
4. **Analysis and Debugging:** Explore variables and generate detailed reports.
---
### **Key Features**
- **Forcefield Initialization:** Create and customize forcefields programmatically or using DSCRIPT syntax.
- **Dynamic Region-Specific Adjustments:** Modify forcefield parameters for different subregions.
- **Script Integration:** Combine forcefields with previous simulation steps.
- **Debugging:** Analyze variable occurrences and validate workflow consistency.
Last revision 2025-01-07
Author: INRAE\olivier.vitrac@agroparistech.fr
"""
# Import necessary modules
from pizza.forcefield import parameterforcefield, tlsph
from pizza.generic import generic
from pizza.dforcefield import dforcefield
from pizza.dscript import dscript
# %% LOAD PREVIOUS SCRIPT
"""
Load the DSCRIPT file from example2.py to reuse its definitions, such as regions and bead types.
"""
dscriptfilename = "tmp/example2.d.txt"
previoussteps = dscript.load(dscriptfilename)
# Extract bead type mappings and region arguments from the previous script
beadtype = previoussteps.search("ID", previoussteps.list_values("ID"), "beadtype")
# Additional control (for debugging purposes)
region_args = previoussteps.list_values('args', details=True).get_raw_data()
# %% DEFINE BASE FORCEFIELD
"""
Create a default forcefield using `parameterforcefield` and `dforcefield`.
This serves as the base forcefield for all regions.
"""
FFbase_parameters = parameterforcefield(
base_class=tlsph, # Forcefield class: Total Lagrangian Smoothed Particle Hydrodynamics
rho=1050, # Density
c0=10.0, # Speed of sound
E="50*${c0}^2*${rho}", # Elastic modulus
nu=0.3, # Poisson's ratio
q1=1.0, q2=0.0, # Artificial viscosity parameters
Hg=10.0, Cp=1.0, # Heat capacity and specific energy
sigma_yield="0.1*${E}", # Yield stress
hardening=0, # Hardening coefficient
contact_scale=1.5, # Contact scale
contact_stiffness="2.5*${c0}^2*${rho}" # Contact stiffness
)
FFbase = dforcefield(userid="FFbase", **FFbase_parameters)
# Save the base forcefield for future reuse
FFbase.save("FFbase.default.txt", foldername="./tmp", overwrite=True, verbose=False)
# Reload the base forcefield to demonstrate file management
FFbase = dforcefield.load("FFbase.default.txt", foldername="./tmp")
# %% DEFINE REGION-SPECIFIC FORCEFIELDS
"""
Create specialized forcefields for each region by copying the base forcefield
and modifying region-specific properties.
"""
FFlower = FFbase.copy(
beadtype=beadtype["LowerCylinder"], # Assign bead type
userid="LowerCylinder", # Unique identifier
E="2*"+FFbase.parameters.E, # Increase elastic modulus
rho=1050 # Same density as base
)
FFcentral = FFbase.copy(
beadtype=beadtype["CentralCylinder"],
userid="CentralCylinder",
E="0.5*"+FFbase.parameters.E,
rho=1000 # Reduced density
)
FFupper = FFbase.copy(
beadtype=beadtype["UpperCylinder"],
userid="UpperCylinder",
E="10*"+FFbase.parameters.E, # Much stiffer material
rho=1300, nu=0.1 # Higher density, lower Poisson's ratio
)
# %% ASSIGN FORCEFIELDS TO GROUPS
"""
Assign the specialized forcefields to atom groups and prepare them for the LAMMPS script.
"""
blower = FFlower.scriptobject(name="lowerAtoms", group="lowerAtoms")
bcentral = FFcentral.scriptobject(name="centralAtoms", group="centralAtoms")
bupper = FFupper.scriptobject(name="upperAtoms", group="upperAtoms")
# Combine all forcefield group scripts into a single collection
bcollection = blower + bcentral + bupper
# %% UPDATE SCRIPT WITH FORCEFIELDS
"""
Integrate the new forcefields into the previous script using `pipescript`.
The forcefields are added before the final steps of the previous script.
"""
updatedScript = previoussteps[:-1] | bcollection | previoussteps[-1:]
# Write the updated LAMMPS script to a file
updatedScriptfile = updatedScript.write("tmp/example2bis.txt", verbosity=1, overwrite=True)
print(f"The updated LAMMPS script (example2bis) is available here:\n{updatedScriptfile}")
# %% ANALYZE VARIABLES IN THE UPDATED SCRIPT
"""
Extract and analyze occurrences of variables like 'args' and 'move' from the updated script.
"""
args_values = updatedScript.list_values("args").get_raw_data()
move_count = updatedScript.list_values("move").get_usage_count("")
# %% CONVERT TO DSCRIPT AND SAVE
"""
Convert the updated script to DSCRIPT format for future reuse and reverse engineering.
"""
DupdatedScript = updatedScript.dscript(verbose=True)
DupdatedScriptFile = DupdatedScript.save("tmp/example2bis.d.txt", overwrite=True)
print(f"The updated DSCRIPT (example2bis) is available here:\n{DupdatedScriptFile}")
# %% VERIFY REVERSIBILITY
"""
Reload the updated DSCRIPT file and regenerate the LAMMPS script to ensure consistency.
"""
Drev2bis = dscript.load(DupdatedScriptFile)
Srev2bis = Drev2bis.pipescript(verbose=False)
# Variable control (for eventual debugging)
allvars = Srev2bis.list_values()
allvars["args"].export("tmp/example2bis.rev.args.html")
repr(allvars["args"])
Srev2bis.generate_report("tmp/example2bis.rev.var.html")
# Save the reversed script for control
revUpdatedScriptfile = Srev2bis.write("tmp/example2bis.rev.txt", verbosity=0, overwrite=True)
print(f"The updated and reversed LAMMPS script is available here:\n{revUpdatedScriptfile}")
Global variables
var FFbase
-
Create specialized forcefields for each region by copying the base forcefield and modifying region-specific properties.
var FFupper
-
Assign the specialized forcefields to atom groups and prepare them for the LAMMPS script.
var bcollection
-
Integrate the new forcefields into the previous script using
pipescript
. The forcefields are added before the final steps of the previous script. var move_count
-
Convert the updated script to DSCRIPT format for future reuse and reverse engineering.
var region_args
-
Create a default forcefield using
parameterforcefield
anddforcefield
. This serves as the base forcefield for all regions.