Physics-PVD

 view release on metacpan or  search on metacpan

lib/Physics/PVD/Interface/QuantumATK.pm  view on Meta::CPAN

    return $filename;
}

# Generate script for sputtering simulation (BCA + MD)
sub setup_sputtering {
    my ($self, %opts) = @_;
    my $ion         = $opts{ion}         // 'Ar';
    my $ion_energy  = $opts{ion_energy}  // 500;   # eV
    my $angle       = $opts{angle}       // 0;     # degrees
    my $n_ions      = $opts{n_ions}      // 100;
    my $filename    = $opts{filename}    // "$self->{work_dir}/sputtering.py";

    my $material = $self->{material};

    my $script = <<PYTHON;
# QuantumATK: Sputtering yield simulation (MD + BCA)
# Generated by Physics::PVD::Interface::QuantumATK
from QuantumATK import *
import numpy as np

# Build target surface
bulk = BulkConfiguration(
    bravais_lattice=BodyCenteredCubic(3.3058*Angstrom),
    elements=[$material],
    fractional_coordinates=[[0.0, 0.0, 0.0]]
)

target = SlabConfiguration(bulk, surface_normal=[1,1,0],
                           number_of_layers=12, vacuum=30*Angstrom)

# MD Calculator (Tersoff or EAM potential)
calculator = TersoffCalculator(target)
target.setCalculator(calculator)

# Ion bombardment parameters
ion_energy = $ion_energy * eV
ion_angle = $angle * np.pi / 180.0
n_ions = $n_ions

sputtered_atoms = 0
for i in range(n_ions):
    # Random impact point
    x = np.random.uniform(0, target.bravaisLattice().a())
    y = np.random.uniform(0, target.bravaisLattice().b())
    z_top = max(target.cartesianCoordinates()[:, 2]) + 5.0*Angstrom

    # Ion velocity
    mass_ion = {'Ar': 39.948, 'Ne': 20.18, 'Xe': 131.29}['$ion'] * amu
    speed = np.sqrt(2 * ion_energy / mass_ion)
    vx = speed * np.sin(ion_angle)
    vy = 0.0
    vz = -speed * np.cos(ion_angle)

    # Add ion and run MD
    config = target.copy()
    config.addAtoms(elements=['$ion'], cartesian_coordinates=[[x, y, z_top]])
    config.setVelocities([vx, vy, vz], indices=[-1])

    md = MolecularDynamics(
        configuration=config,
        trajectory_filename='$self->{work_dir}/cascade_{}.hdf5'.format(i),
        steps=2000,
        time_step=0.5*fs,
        log_interval=100
    )
    md.run()

    # Count sputtered atoms (z > z_top)
    final = md.finalConfiguration()
    z_final = final.cartesianCoordinates()[:, 2]
    sputtered_atoms += np.sum(z_final > z_top)

sputter_yield = sputtered_atoms / n_ions
print(f"Sputter yield ({ion} -> {material}, E={ion_energy} eV, θ={angle}°): {sputter_yield:.3f}")
PYTHON

    open my $fh, '>', $filename or croak "Cannot write $filename: $!";
    print $fh $script;
    close $fh;

    return $filename;
}

# Generate script for adatom diffusion MD
sub run_md {
    my ($self, %opts) = @_;
    my $temperature = $opts{temperature} // 600;  # K
    my $steps       = $opts{steps}       // 50000;
    my $filename    = $opts{filename}    // "$self->{work_dir}/adatom_md.py";

    my $material = $self->{material};
    my $calc = $self->{calculator};

    my $script = <<PYTHON;
# QuantumATK: Adatom diffusion MD on $material surface
# Generated by Physics::PVD::Interface::QuantumATK
from QuantumATK import *
import numpy as np

# Build surface + adatom
bulk = BulkConfiguration(
    bravais_lattice=BodyCenteredCubic(3.3058*Angstrom),
    elements=[$material],
    fractional_coordinates=[[0.0, 0.0, 0.0]]
)

slab = SlabConfiguration(bulk, surface_normal=[1,1,0],
                         number_of_layers=$self->{slab_layers}, vacuum=20*Angstrom)

# Place adatom
top_z = max(slab.cartesianCoordinates()[:, 2])
center_xy = np.mean(slab.cartesianCoordinates()[:, :2], axis=0)
slab.addAtoms(elements=['$material'],
              cartesian_coordinates=[[center_xy[0], center_xy[1], top_z + 2.5]])

# Calculator
calculator = ${calc}Calculator(slab)
slab.setCalculator(calculator)

# NVT MD
md = MolecularDynamics(



( run in 1.219 second using v1.01-cache-2.11-cpan-e7c6538aa59 )