First steps through pyiron
This section gives a brief introduction about fundamental concepts of pyiron and how they can be used to setup, run and analyze atomic simulations. As a first step we import the libraries numpy for data analysis and matplotlib for visualization.
[1]:
import numpy as np
%matplotlib inline
import matplotlib.pylab as plt
To import pyiron simply use:
[2]:
from pyiron import Project
The Project object introduced below is central in pyiron. It allows to name the project as well as to derive all other objects such as structures, jobs etc. without having to import them. Thus, by code completion Tab the respective commands can be found easily.
We now create a pyiron Project named ‘first_steps’.
[3]:
pr = Project(path='first_steps')
The project name also applies for the directory that is created for the project.
Perform a LAMMPS MD simulation
Having created an instance of the pyiron Project we now perform a LAMMPS molecular dynamics simulation.
For this basic simulation example we construct an fcc Al crystal in a cubic supercell (cubic=True
). For more details on generating structures, please have a look at our structures example
[4]:
basis = pr.create_ase_bulk('Al', cubic=True)
supercell_3x3x3 = basis.repeat([3, 3, 3])
supercell_3x3x3.plot3d()
Here create_ase_bulk
uses the ASE bulk module. The structure can be modified - here we extend the original cell to a 3x3x3 supercell (repeat([3, 3, 3]
). Finally, we plot the structure using NGlview.
The project object allows to create various simulation job types. Here, we create a LAMMPS job.
[5]:
job = pr.create_job(job_type=pr.job_type.Lammps, job_name='Al_T800K')
Further, we specify a Molecular Dynamics simulation at \(T=800\) K using the supercell structure created above.
[6]:
job.structure = supercell_3x3x3
job.calc_md(temperature=800, pressure=0, n_ionic_steps=10000)
To see all available interatomic potentials which are compatible with the structure (for our example they must contain Al) and the job type (here LAMMPS) we call job.list_potentials()
.
[7]:
job.list_potentials()
[7]:
['1995--Angelo-J-E--Ni-Al-H--LAMMPS--ipr1',
'1996--Farkas-D--Nb-Ti-Al--LAMMPS--ipr1',
'1997--Liu-X-Y--Al-Mg--LAMMPS--ipr1',
'1998--Liu-X-Y--Al-Mg--LAMMPS--ipr1',
'1999--Liu-X-Y--Al-Cu--LAMMPS--ipr1',
'1999--Mishin-Y--Al--LAMMPS--ipr1',
'2000--Landa-A--Al-Pb--LAMMPS--ipr1',
'2000--Sturgeon-J-B--Al--LAMMPS--ipr1',
'2002--Mishin-Y--Ni-Al--LAMMPS--ipr1',
'2003--Lee-B-J--Al--LAMMPS--ipr1',
'2003--Zope-R-R--Al--LAMMPS--ipr1',
'2003--Zope-R-R--Ti-Al--LAMMPS--ipr1',
'2004--Liu-X-Y--Al--LAMMPS--ipr1',
'2004--Mishin-Y--Ni-Al--LAMMPS--ipr1',
'2004--Mishin-Y--Ni-Al--LAMMPS--ipr2',
'2004--Zhou-X-W--Al--LAMMPS--ipr2',
'2005--Mendelev-M-I--Al-Fe--LAMMPS--ipr1',
'2007--Silva-A-C--Al-Ni--LAMMPS--ipr1',
'2008--Mendelev-M-I--Al--LAMMPS--ipr1',
'2009--Kim-Y-M--Mg-Al--LAMMPS--ipr1',
'2009--Mendelev-M-I--Al-Mg--LAMMPS--ipr1',
'2009--Purja-Pun-G-P--Ni-Al--LAMMPS--ipr1',
'2009--Zhakhovskii-V-V--Al--LAMMPS--ipr2',
'2010--Lee-E--Fe-Al--LAMMPS--ipr1',
'2010--Mendelev-M-I--fictional-Al-1--LAMMPS--ipr1',
'2010--Mendelev-M-I--fictional-Al-2--LAMMPS--ipr1',
'2010--Mendelev-M-I--fictional-Al-3--LAMMPS--ipr1',
'2010--Winey-J-M--Al--LAMMPS--ipr1',
'2011--Apostol-F--Al-Cu--LAMMPS--ipr1',
'2011--Ko-W-S--Al-H--LAMMPS--ipr1',
'2012--Dong-W-P--Co-Al--LAMMPS--ipr1',
'2012--Jelinek-B--Al-Si-Mg-Cu-Fe--LAMMPS--ipr2',
'2012--Schopf-D--Al-Mn-Pd--LAMMPS--ipr1',
'2013--Shim-J-H--V-Al--LAMMPS--ipr1',
'2013--Shim-J-H--V-Al-H--LAMMPS--ipr1',
'2015--Choudhary-K--Al--LAMMPS--ipr1',
'2015--Choudhary-K--Al-O--LAMMPS--ipr1',
'2015--Kim-Y-K--Ni-Al-Co--LAMMPS--ipr1',
'2015--Kumar-A--Al-Ni--LAMMPS--ipr1',
'2015--Kumar-A--Al-Ni-O--LAMMPS--ipr1',
'2015--Mendelev-M-I--Al-Sm--LAMMPS--ipr1',
'2015--Pascuet-M-I--Al--LAMMPS--ipr1',
'2015--Pascuet-M-I--Al-U--LAMMPS--ipr2',
'2015--Purja-Pun-G-P--Al-Co--LAMMPS--ipr2',
'2015--Purja-Pun-G-P--Ni-Al-Co--LAMMPS--ipr2',
'2016--Kim-Y-K--Al-Ti--LAMMPS--ipr1',
'2016--Zhou-X-W--Al-Cu--LAMMPS--ipr2',
'2017--Botu-V--Al--LAMMPS--ipr1',
'2017--Kim-J-S--Pt-Al--LAMMPS--ipr1',
'2017--Kim-Y-K--Ni-Al-Ti--LAMMPS--ipr1',
'2018--Dickel-D-E--Mg-Al-Zn--LAMMPS--ipr1',
'2018--Jeong-G-U--Pd-Al--LAMMPS--ipr1',
'2018--Zhou-X-W--Al-Cu-H--LAMMPS--ipr1',
'2020--Farkas-D--Fe-Ni-Cr-Co-Al--LAMMPS--ipr1',
'2020--Starikov-S--Si-Au-Al--LAMMPS--ipr1',
'2020--Starikov-S--Si-Au-Al--LAMMPS--ipr2',
'EAM_CubicNaturalSpline_ErcolessiAdams_1994_Al__MO_800509458712_002',
'EAM_Dynamo_AngeloMoodyBaskes_1995_NiAlH__MO_418978237058_005',
'EAM_Dynamo_CaiYe_1996_AlCu__MO_942551040047_005',
'EAM_Dynamo_ErcolessiAdams_1994_Al__MO_123629422045_005',
'EAM_Dynamo_FarkasJones_1996_NbTiAl__MO_042691367780_000',
'EAM_Dynamo_JacobsenNorskovPuska_1987_Al__MO_411692133366_000',
'EAM_Dynamo_LandaWynblattSiegel_2000_AlPb__MO_699137396381_005',
'EAM_Dynamo_LiuAdams_1998_AlMg__MO_019873715786_000',
'EAM_Dynamo_LiuErcolessiAdams_2004_Al__MO_051157671505_000',
'EAM_Dynamo_LiuLiuBorucki_1999_AlCu__MO_020851069572_000',
'EAM_Dynamo_LiuOhotnickyAdams_1997_AlMg__MO_559870613549_000',
'EAM_Dynamo_MendelevAstaRahman_2009_AlMg__MO_658278549784_005',
'EAM_Dynamo_MendelevFangYe_2015_AlSm__MO_338600200739_000',
'EAM_Dynamo_MendelevKramerBecker_2008_Al__MO_106969701023_005',
'EAM_Dynamo_MendelevSrolovitzAckland_2005_AlFe__MO_577453891941_005',
'EAM_Dynamo_MishinFarkasMehl_1999_Al__MO_651801486679_005',
'EAM_Dynamo_MishinMehlPapaconstantopoulos_2002_NiAl__MO_109933561507_005',
'EAM_Dynamo_Mishin_2004_NiAl__MO_101214310689_005',
'EAM_Dynamo_PunMishin_2009_NiAl__MO_751354403791_005',
'EAM_Dynamo_PunYamakovMishin_2013_AlCo__MO_678952612413_000',
'EAM_Dynamo_PunYamakovMishin_2013_NiAlCo__MO_826591359508_000',
'EAM_Dynamo_SchopfBrommerFrigan_2012_AlMnPd__MO_137572817842_000',
'EAM_Dynamo_SturgeonLaird_2000_Al__MO_120808805541_005',
'EAM_Dynamo_VailheFarkas_1997_CoAl__MO_284963179498_005',
'EAM_Dynamo_WineyKubotaGupta_2010_Al__MO_149316865608_005',
'EAM_Dynamo_Zhakhovsky_2009_Al__MO_519613893196_000',
'EAM_Dynamo_ZhouJohnsonWadley_2004NISTretabulation_Al__MO_060567868558_000',
'EAM_Dynamo_ZhouJohnsonWadley_2004_Al__MO_131650261510_005',
'EAM_Dynamo_ZhouWadleyJohnson_2001_Al__MO_049243498555_000',
'EAM_Dynamo_ZopeMishin_2003_Al__MO_664470114311_005',
'EAM_Dynamo_ZopeMishin_2003_TiAl__MO_117656786760_005',
'EAM_ErcolessiAdams_1994_Al__MO_324507536345_003',
'EAM_IMD_BrommerGaehler_2006A_AlNiCo__MO_122703700223_003',
'EAM_IMD_BrommerGaehler_2006B_AlNiCo__MO_128037485276_003',
'EAM_IMD_SchopfBrommerFrigan_2012_AlMnPd__MO_878712978062_003',
'EAM_QuinticClampedSpline_ErcolessiAdams_1994_Al__MO_450093727396_002',
'EAM_QuinticHermiteSpline_ErcolessiAdams_1994_Al__MO_781138671863_002',
'EMT_Asap_Standard_JacobsenStoltzeNorskov_1996_AlAgAuCuNiPdPt__MO_115316750986_001',
'EMT_Asap_Standard_JacobsenStoltzeNorskov_1996_Al__MO_623376124862_001',
'MEAM_LAMMPS_AlmyrasSangiovanniSarakinos_2019_NAlTi__MO_958395190627_000',
'MEAM_LAMMPS_CostaAgrenClavaguera_2007_AlNi__MO_131642768288_000',
'MEAM_LAMMPS_DongKimKo_2012_CoAl__MO_099716416216_000',
'MEAM_LAMMPS_JelinekGrohHorstemeyer_2012_AlSiMgCuFe__MO_262519520678_000',
'MEAM_LAMMPS_JeongParkDo_2018_PdAl__MO_616482358807_000',
'MEAM_LAMMPS_KimJungLee_2015_NiAlCo__MO_876687166519_000',
'MEAM_LAMMPS_KimKimJung_2016_AlTi__MO_618133763375_000',
'MEAM_LAMMPS_KimKimJung_2017_NiAlTi__MO_478967255435_000',
'MEAM_LAMMPS_KimKimLee_2009_AlMg__MO_058537087384_000',
'MEAM_LAMMPS_KimSeolJi_2017_PtAl__MO_793141037706_000',
'MEAM_LAMMPS_KoShimLee_2011_AlH__MO_127847080751_000',
'MEAM_LAMMPS_LeeLee_2010_FeAl__MO_332211522050_000',
'MEAM_LAMMPS_PascuetFernandez_2015_AlU__MO_596300673917_000',
'MEAM_LAMMPS_PascuetFernandez_2015_Al__MO_315820974149_000',
'MEAM_LAMMPS_ShimKoKim_2013_AlVH__MO_344724145339_000',
'Morse_Shifted_GirifalcoWeizer_1959HighCutoff_Al__MO_140175748626_004',
'Morse_Shifted_GirifalcoWeizer_1959LowCutoff_Al__MO_411898953661_004',
'Morse_Shifted_GirifalcoWeizer_1959MedCutoff_Al__MO_279544746097_004',
'Sim_LAMMPS_ADP_ApostolMishin_2011_AlCu__SM_667696763561_000',
'Sim_LAMMPS_ADP_StarikovGordeevLysogorskiy_2020_SiAuAl__SM_113843830602_000',
'Sim_LAMMPS_AGNI_BotuBatraChapman_2017_Al__SM_666183636896_000',
'Sim_LAMMPS_BOP_ZhouWardFoster_2016_AlCu__SM_566399258279_000',
'Sim_LAMMPS_MEAM_AlmyrasSangiovanniSarakinos_2019_NAlTi__SM_871795249052_000',
'Sim_LAMMPS_MEAM_JelinekGrohHorstemeyer_2012_AlSiMgCuFe__SM_656517352485_000',
'Sim_LAMMPS_MEAM_PascuetFernandez_2015_AlU__SM_721930391003_000',
'Sim_LAMMPS_MEAM_PascuetFernandez_2015_Al__SM_811588957187_000',
'Sim_LAMMPS_SMTBQ_SallesPolitanoAmzallag_2016_AlO__SM_853967355976_000',
'Sim_LAMMPS_SMTBQ_SallesPolitanoAmzallag_2016_Al__SM_404097633924_000']
From the above let us select the first potential in the list.
[8]:
pot = job.list_potentials()[0]
print ('Selected potential: ', pot)
job.potential = pot
Selected potential: 1995--Angelo-J-E--Ni-Al-H--LAMMPS--ipr1
To run the LAMMPS simulation (locally) we now simply use:
[9]:
job.run()
The job Al_T800K was saved and received the ID: 400
Analyze the calculation
After the simulation has finished the information about the job can be accessed through the Project object.
[10]:
job = pr['Al_T800K']
job
[10]:
{'groups': ['input', 'output'], 'nodes': ['HDF_VERSION', 'NAME', 'TYPE', 'VERSION', 'server', 'status']}
Printing the job object (note that in Jupyter we don’t have to call a print statement if the variable/object is in the last line). The output lists the variables (nodes) and the directories (groups). To get a list of all variables stored in the generic output we type:
[11]:
job['output/generic']
[11]:
{'groups': [], 'nodes': ['cells', 'energy_pot', 'energy_tot', 'forces', 'indices', 'positions', 'pressures', 'steps', 'temperature', 'unwrapped_positions', 'velocities', 'volume']}
An animated 3d plot of the MD trajectories is created by:
[12]:
job.animate_structure()
To analyze the temperature evolution we plot it as function of the MD step.
[13]:
temperatures = job['output/generic/temperature']
steps = job['output/generic/steps']
plt.plot(steps, temperatures)
plt.xlabel('MD step')
plt.ylabel('Temperature [K]');

In the same way we can plot the trajectories.
[14]:
pos = job['output/generic/positions']
x, y, z = [pos[:, :, i] for i in range(3)]
sel = np.abs(z) < 0.1
fig, axs = plt.subplots(1,1)
axs.scatter(x[sel], y[sel])
axs.set_xlabel('x [$\AA$]')
axs.set_ylabel('y [$\AA$]')
axs.set_aspect('equal', 'box');

Perform a series of jobs
To run the MD simulation for various temperatures we can simply loop over the desired temperature values.
[15]:
for temperature in np.arange(200, 1200, 200):
job = pr.create_job(pr.job_type.Lammps,
'Al_T{}K'.format(int(temperature)))
job.structure = supercell_3x3x3
job.potential = pot
job.calc_md(temperature=temperature,
pressure=0,
n_ionic_steps=10000)
job.run()
The job Al_T200K was saved and received the ID: 401
The job Al_T400K was saved and received the ID: 402
The job Al_T600K was saved and received the ID: 403
2021-10-26 15:19:01,407 - pyiron_log - WARNING - The job Al_T800K is being loaded instead of running. To re-run use the argument 'delete_existing_job=True in create_job'
2021-10-26 15:19:01,407 - pyiron_log - WARNING - The job Al_T800K is being loaded instead of running. To re-run use the argument 'delete_existing_job=True in create_job'
The job Al_T1000K was saved and received the ID: 404
To inspect the list of jobs in our current project we type (note that the existing job from the previous excercise at \(T=800\) K has been recognized and not run again):
[16]:
pr
[16]:
{'groups': [], 'nodes': ['Al_T800K', 'Al_T200K', 'Al_T400K', 'Al_T600K', 'Al_T1000K']}
We can now iterate over the jobs and extract volume and mean temperature.
[17]:
vol_lst, temp_lst = [], []
for job in pr.iter_jobs(convert_to_object=False):
volumes = job['output/generic/volume']
temperatures = job['output/generic/temperature']
temp_lst.append(np.mean(temperatures[:-20]))
vol_lst.append(np.mean(volumes[:-20]))
100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 5/5 [00:00<00:00, 27.02it/s]
Then we can use the extracted information to plot the thermal expansion, calculated within the \(NPT\) ensemble. For plotting the temperature values in ascending order the volume list is mapped to the sorted temperature list.
[18]:
plt.figure()
vol_lst[:] = [vol_lst[np.argsort(temp_lst)[k]]
for k in range(len(vol_lst))]
plt.plot(sorted(temp_lst), vol_lst,
linestyle='-',marker='o',)
plt.title('Thermal expansion')
plt.xlabel('Temperature [K]')
plt.ylabel('Volume [$\AA^3$]');

Create a series of projects
We extend the previous example and compute the thermal expansion for three of the available aluminum potentials. First, let us create a new pyiron project named ‘Al_potentials’. We can use the information of the previously run job ‘Al_T200K’ of the ‘first_steps’ project to find all the compatible potentials.
[19]:
pr = Project('Al_potentials')
pot_lst = pr['../first_steps/Al_T200K'].list_potentials()[:3]
[ ]:
[20]:
pot_lst
[20]:
['1995--Angelo-J-E--Ni-Al-H--LAMMPS--ipr1',
'1996--Farkas-D--Nb-Ti-Al--LAMMPS--ipr1',
'1997--Liu-X-Y--Al-Mg--LAMMPS--ipr1']
Note again that list_potentials()
automatically only returns the potentials that are compatible with the structure (chemical species) and the job type.
We can now loop over the selected potentials and run the MD simulation for the desired temperature values for any of the potentials.
[21]:
for pot in pot_lst:
print ('Interatomic potential used: ',pot)
pr_pot = pr.create_group(pot)
for temperature in np.arange(200, 1200, 200):
job = pr_pot.create_job(pr.job_type.Lammps,
'Al_T{}K'.format(int(temperature)))
job.structure = supercell_3x3x3
job.potential = pot
job.calc_md(temperature=temperature,
pressure=0,
n_ionic_steps=10000)
job.run()
Interatomic potential used: 1995--Angelo-J-E--Ni-Al-H--LAMMPS--ipr1
The job Al_T200K was saved and received the ID: 405
The job Al_T400K was saved and received the ID: 406
The job Al_T600K was saved and received the ID: 407
The job Al_T800K was saved and received the ID: 408
The job Al_T1000K was saved and received the ID: 409
Interatomic potential used: 1996--Farkas-D--Nb-Ti-Al--LAMMPS--ipr1
The job Al_T200K was saved and received the ID: 410
The job Al_T400K was saved and received the ID: 411
The job Al_T600K was saved and received the ID: 412
The job Al_T800K was saved and received the ID: 413
The job Al_T1000K was saved and received the ID: 414
Interatomic potential used: 1997--Liu-X-Y--Al-Mg--LAMMPS--ipr1
The job Al_T200K was saved and received the ID: 415
The job Al_T400K was saved and received the ID: 416
The job Al_T600K was saved and received the ID: 417
The job Al_T800K was saved and received the ID: 418
The job Al_T1000K was saved and received the ID: 419
With the pr.create_group()
command a new subproject (directory) is created named here by the name of the potential.
For any particular potential the thermal expansion data can be obtained again by looping over the jobs performed using that potential. To obtain the thermal expansion curves for all the potentials used we can simply iterate over the subprojects (directories) created above by using the pr.iter_groups()
command.
[22]:
for p in pr.iter_groups():
vol_lst, temp_lst = [], []
for out in p.iter_jobs(path='output/generic'):
volumes = out['volume']
temperatures = out['temperature']
temp_lst.append(np.mean(temperatures[:-20]))
vol_lst.append(np.mean(volumes[:-20]))
# Plot only if there is a job in that group
if len(p.get_job_ids()) > 0:
plt.plot(temp_lst, vol_lst,
linestyle='-',marker='o',
label=p.name)
plt.legend(loc='best')
plt.title('Thermal expansion for different interatomic potentials')
plt.xlabel('Temperature [K]')
plt.ylabel('Volume [$\AA^3$]');
100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 5/5 [00:00<00:00, 44.29it/s]
100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 5/5 [00:00<00:00, 46.63it/s]
100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 5/5 [00:00<00:00, 44.18it/s]

[ ]: