Surface Evolution Model:
SEEE, Surface Charging, and Ion Reflection

Background and Purpose

Substrate erosion and plasma etching is a popular contemporary issue and understanding erosion is crucial for optimizing materials and coatings in electronics, optics, etc. Our goal was to develop a model of the erosion of a surface over time due to the ions & electrons ejected from plasma and how they interact with a substrate surface based on variable factors.


This project built off of plasma etching, because it is popular in many contemporary fields. It is difficult to conceptualize and visualize, so the main goal of this project was to develop a user-friendly 2D code that models erosion overtime under different surface roughness and insertion angles.


Diagram illustrating substrate erosion Diagram of Particle Paths

Imaged above, one can see how this looks like in practice for a verification model.
Notice the surface charging craters that are created, as well as the paths that are traced by the particles.



What it Does

The particles are ions and electrons that are created with random variations in trajectory. These particles move until they collide with the surface, exceed a maximum path length, or exit the canvas. When the particle interacts with the surface, reflection occurs based on the slope of the surface and type of particle, and the surface is deformed to simulate the effect of the impact. After the impact, the electrons are randomized to simulate diffusion, while the ions are reflected based on the calculated normal angle.



Project Process

The code approach was to load a plasma sheath and edit a boundary that has an initial roughness to it. This was from a wave function similar to what we had for two-stream instability. The process was simulated for multiple surface roughness functions.

Then, this was run and there was a threshold that the boundary either had these electrons be discarded or collide back into the sheath in order to eat away at the surface little by little. Again, a material was modeled by the boundary of the plasma sheath and it continuously changed by the impacts of electrons in order to produce different timestamps before it got completely reduced.


https://aste404project.neocities.org/EEL_report

Simulation Overview

The simulation visualizes ions and electrons as particles interacting with a sinusoidal surface. When particles collide with the surface, they reflect or diffuse based on their type and modify the surface, representing erosion effects.

Interactive Simulation






Advanced Visualization

Since this is a plasma project, C++ was used to solve for the electric field, electric potential, and charge density. This was done in VSCode and was visualized in ParaView.


Surface Evolution: Before, After, Ions, Electrons

Imaged above from left to right is the surface evolution before and after, as well as the ion and electron collection over time.




Ions and Electron Collection on Surface

Imaged above is the before and after of ion collection (left column) and the electron collection (right column) to notice trends.




Electric Field, Plasma Potential, & Charge Density Over Time

Imaged above are the drivers necessitated for a proper plasma profile: Electric Field (left), Plasma Potential (center), and Charge Density (Right).




C++ Files Included, Virtual Toolkit Files, & Command Line

Imaged above are the VSCode file bin, Command Line feedback, and result files generated, and virtual toolkit file writing.



Future Work

An in-depth materials drop-down will be implemented, with at least three of the most-common aerospace materials included (Aluminum 2024, Silicon Carbide, and Fused Silica). The first new material properties of interest to include is reflectance, which would be chosen on a 0 to 100 percentage scale, secondly absorption, which would be a factor between 0 and 1 with 1 being the most absorbent material, thirdly a hardness value, which would be a factor between 1 and 3000, using the Vickers scale of hardness [1], and lastly sputtering, which would be included as an on/off toggle.


Sputtering is a unique property where atoms are emitted from the surface when enough energy from the kinetic particle collision is transferred to individual atoms to be ejected from the surface [2]. In the future, equations governing the sputtering effect will be implemented in the code.


Additionally, it would be optimal to include a path tracing capability in the simulation to illustrate the routes of a specific atom impacting the surface. An example of what this might look like is shown below.


Path Tracing

sources

[1] Vickers hardness test to ISO 6507 / ASTM E384. ZwickRoell LP. Kennesaw, GA. https://www.zwickroell.com/industries/metals/metals-standards/vickers-test-iso-6507/

[2] Hegemann, D., Amberg, M., Ritter, A., & Heuberger, M. (2009). Recent developments in AG metallised textiles using plasma sputtering. Materials Technology, 24(1), 41–45. https://doi.org/10.1179/175355509x417981



JavaScript Code


        let amplitude, offset, period, insertionAngle;
        let particles = [];
        const maxParticles = 200;
        const maxPathLength = 200;
        let simulationRunning = false;

        const tabs = {
            seee: document.getElementById('seeeCanvas'),
            charging: document.getElementById('chargingCanvas'),
            reflection: document.getElementById('reflectionCanvas')
        };
        const ctx = {
            seee: tabs.seee.getContext('2d'),
            charging: tabs.charging.getContext('2d'),
            reflection: tabs.reflection.getContext('2d')
        };

        let surfaceData = [];

        function showTab(tabId) {
            for (let tab in tabs) {
                tabs[tab].parentElement.style.display = 'none';
            }
            tabs[tabId].parentElement.style.display = 'block';
        }

        function initializeSurface() {
            surfaceData = [];
            for (let x = 0; x < tabs.seee.width; x++) {
                surfaceData.push(offset + amplitude * Math.sin((2 * Math.PI * x) / period));
            }
        }

        function drawSurface(ctx) {
            ctx.beginPath();
            for (let x = 0; x < tabs.seee.width; x++) {
                if (x === 0) {
                    ctx.moveTo(x, surfaceData[x]);
                } else {
                    ctx.lineTo(x, surfaceData[x]);
                }
            }
            ctx.strokeStyle = "black";
            ctx.stroke();
        }

        function createParticle(type) {
            const angleRadians = insertionAngle * (Math.PI / 180);
            const angleVariation = Math.random() * Math.PI / 8 - Math.PI / 16;
            return {
                x: Math.random() * tabs.seee.width,
                y: 0,
                angle: angleRadians + angleVariation,
                color: type === "ion" ? "blue" : "red",
                type: type,
                pathLength: 0
            };
        }

        function updateParticles() {
            particles.forEach((particle, index) => {
              let { x, y, angle, type, color, pathLength } = particle;
              x += 2 * Math.cos(angle);
              y += 2 * Math.sin(angle);
              pathLength++; // Increment path length

              // Wrap around the x domain
              if (x < 0) {
                x += tabs.seee.width;
              } else if (x >= tabs.seee.width) {
                x -= tabs.seee.width;
              }

              // Check for collisions with the surface
              if (y >= surfaceData[Math.floor(x)] && x >= 0 && x < tabs.seee.width) {
                  const slope = (surfaceData[Math.floor(x) + 1] - surfaceData[Math.floor(x) - 1]) / 2;
                  const normalAngle = Math.atan(slope);
                  angle = 2 * normalAngle - angle;

                  surfaceData[Math.floor(x)] += 1;

                  if (type === "electron") {
                    angle = Math.random() * Math.PI * 2;
                }
            }

            // Check if particle should be reset
            if (pathLength > maxPathLength || y > tabs.seee.height) {
                particles[index] = createParticle(type);
            } else {
                particles[index] = { x, y, angle, color, type, pathLength };}
            });
        }

        function drawParticles(ctx) {
            particles.forEach(particle => {
                ctx.beginPath();
                ctx.arc(particle.x, particle.y, 2, 0, Math.PI * 2);
                ctx.fillStyle = particle.color;
                ctx.fill();
            });
        }

        function animate() {
            if (!simulationRunning) return;

            for (let tab in ctx) {
                ctx[tab].clearRect(0, 0, tabs[tab].width, tabs[tab].height);
                drawSurface(ctx[tab]);
                updateParticles();
                drawParticles(ctx[tab]);
            }
            requestAnimationFrame(animate);
        }

        function startSimulation() {
            amplitude = parseFloat(document.getElementById('amplitude').value);
            offset = parseFloat(document.getElementById('offset').value);
            period = parseFloat(document.getElementById('period').value);
            insertionAngle = parseFloat(document.getElementById('insertionAngle').value);

            initializeSurface();
            particles = Array.from({ length: maxParticles / 2 }, () => createParticle("ion"))
                            .concat(Array.from({ length: maxParticles / 2 }, () => createParticle("electron")));
            simulationRunning = true;
            animate();
        }

        function stopSimulation() {
            simulationRunning = false;
        }

        function resetSimulation() {
            stopSimulation();  // Stop the current simulation
            for (let tab in ctx) {
                ctx[tab].clearRect(0, 0, tabs[tab].width, tabs[tab].height);  // Clear the canvas
            }
            particles = [];  // Clear all particles
            surfaceData = [];  // Clear surface data
        }

        showTab('seee');
        


C++ Code


        #include 
        #include 
        #include 
        #include 
        #include 
        #include "World.h"
        #include "PotentialSolver.h"
        #include "Species.h"
        #include "Output.h"
        #include "Source.h"

        using namespace std;		//to avoid having to write std::cout
        using namespace Const;		//to avoid having to write Const::ME

        /*program execution starts here*/
        int main(int argc, char *args[])
        {
	        /*initialize domain*/
          World world(41,81);
          world.setExtents({-0.1,0},{0.1,0.4});
          world.setTime(1e-7,400);

	        /*set objects*/
	        double phi_wave = -100;		//set default
	        if (argc>1)
		        phi_wave = atof(args[1]);	//convert argument to float
	        cout<<"Wave potential: "<< phi_wave <<" V"<< endl;
          world.addWave(10,0.1,2,phi_wave);
          world.addInlet();

	        /*set up particle species*/
	        vector< Species > species;
	        species.push_back(Species("O+", 16*AMU, QE, 1e2, world));
	        species.push_back(Species("O-", 16*AMU, -1*QE, 1e2, world));

	        /*setup injection sources*/
	        vector< ColdBeamSource > sources;
	        sources.push_back(ColdBeamSource(species[0],world,7000,1e10));	//ion source
	        sources.push_back(ColdBeamSource(species[1],world,7000,1.5e10)); // electron source

	        /*initialize potential solver and solve initial potential*/
          PotentialSolver solver(world,10000,1e-4);
          solver.setReferenceValues(0,1.5,1e10);
          solver.solve();

          /*obtain initial electric field*/
          solver.computeEF();

          /* main loop*/
	        while(world.advanceTime())
            {
	  	        /*inject particles*/
    	        for (ColdBeamSource &source:sources) 
    		        source.sample();

              /*move particles*/
		          for (Species &sp:species)
		          {
			          sp.advance();
			          sp.computeNumberDensity();
		          }

		          /*compute charge density*/
		          world.computeChargeDensity(species);

              /*update potential*/
              solver.solve();

              /*obtain electric field*/
              solver.computeEF();

		          /*screen and file output*/
              Output::screenOutput(world,species);
              Output::diagOutput(world,species);

		          /*periodically write out results*/
              if (world.getTs()%20==0 || world.isLastTimeStep())
			        Output::fields(world, species);
            }
	
	        /* grab starting time*/
	        cout<<"Simulation took "<< world.getWallTime() <<" seconds"<< endl;
	        return 0;		//indicate normal exit
        }
        




Contact Information

Here is the team that made this project possible, we are Astronautical Engineering students from USC ~ Dr. Lubos Brieda is our advisor for this project.

Emerson Emma Luis Dr. Lubos
Emerson Lo: eflo@usc.edu
Emma Rizen: erizen@usc.edu
Luis Diaz: ladiaz@usc.edu
Dr. Lubos Brieda: brieda@usc.edu