{ "cells": [ { "cell_type": "markdown", "id": "0", "metadata": {}, "source": [ "# 1 - Struphy simulations\n", "\n", "In this tutorial we will create a basic simulation with Struphy, run it, do post-processing and plot the data.\n", "\n", "The first step is to choose a model (that is the PDE) we want to solve:" ] }, { "cell_type": "code", "execution_count": null, "id": "1", "metadata": {}, "outputs": [], "source": [ "from struphy import models\n", "\n", "model = models.Maxwell()" ] }, { "cell_type": "markdown", "id": "2", "metadata": {}, "source": [ "We can print the info of the model to see the governing equations and the physical meaning of the variables:" ] }, { "cell_type": "code", "execution_count": null, "id": "3", "metadata": {}, "outputs": [], "source": [ "model.info()" ] }, { "cell_type": "markdown", "id": "4", "metadata": {}, "source": [ "We now feed the light-weight model instance into a simulation:" ] }, { "cell_type": "code", "execution_count": null, "id": "5", "metadata": {}, "outputs": [], "source": [ "from struphy import Simulation\n", "\n", "sim = Simulation(model=model)" ] }, { "cell_type": "markdown", "id": "6", "metadata": {}, "source": [ "Depending on the model, there are many parameters that can be set for a simulation. You can inspect the `Simulation` class for how to do this. Setting initial conditions for the model's variables will be discussed below.\n", "\n", "It is straightforward to run a simulation:" ] }, { "cell_type": "code", "execution_count": null, "id": "7", "metadata": {}, "outputs": [], "source": [ "sim.run()" ] }, { "cell_type": "markdown", "id": "8", "metadata": {}, "source": [ "The screen output shows several things:\n", "\n", "1. The default options for the propagator 'Maxwell', which is the only propagator in this model.\n", "2. The initial conditions (background + perturbation) for the two variables of the model, both initialized as zero here.\n", "3. Some information about the stages of the run.\n", "\n", "It is possible to re-run the simulation, but be careful: **existing data will be deleted!** We shall re-run the same simulation with more verbose output: " ] }, { "cell_type": "code", "execution_count": null, "id": "9", "metadata": {}, "outputs": [], "source": [ "sim.run(verbose=True)" ] }, { "cell_type": "markdown", "id": "10", "metadata": {}, "source": [ "In verbose mode, we see some more information on the individual time steps during the simulation. Moreover, some info on the allocation and assembly of simulation objects are printed.\n", "\n", "Our next aim is to set an initial condition for the electric field. To find out the species and variables of a model, all we need to do is print the model object: " ] }, { "cell_type": "code", "execution_count": null, "id": "11", "metadata": {}, "outputs": [], "source": [ "print(model)" ] }, { "cell_type": "markdown", "id": "12", "metadata": {}, "source": [ "We want a cosine function for the first component and a sine function for the second component, both in x-direction, of the electric field.\n", "Pre-defined functions can be loaded from the module `perturbations`:" ] }, { "cell_type": "code", "execution_count": null, "id": "13", "metadata": {}, "outputs": [], "source": [ "from struphy import perturbations\n", "\n", "fun1 = perturbations.ModesCos(ls=(1,), amps=(1e-1,), comp=0)\n", "fun2 = perturbations.ModesSin(ls=(2,), amps=(1e-2,), comp=1)\n", "\n", "model.em_fields.e_field.add_perturbation(perturbation=fun1)\n", "model.em_fields.e_field.add_perturbation(perturbation=fun2)" ] }, { "cell_type": "markdown", "id": "14", "metadata": {}, "source": [ "We can check the perturbations of a given variable (try to add another perturbation and check again):" ] }, { "cell_type": "code", "execution_count": null, "id": "15", "metadata": {}, "outputs": [], "source": [ "model.em_fields.e_field.show_perturbations()" ] }, { "cell_type": "markdown", "id": "16", "metadata": {}, "source": [ "Let us now run the simulation with the changed initial condition:" ] }, { "cell_type": "code", "execution_count": null, "id": "17", "metadata": {}, "outputs": [], "source": [ "sim.run()" ] }, { "cell_type": "markdown", "id": "18", "metadata": {}, "source": [ "\n", "We can immediately post-process the simulation with default settings:" ] }, { "cell_type": "code", "execution_count": null, "id": "19", "metadata": {}, "outputs": [], "source": [ "sim.pproc()" ] }, { "cell_type": "markdown", "id": "20", "metadata": {}, "source": [ "After post-processing, the plotting data can be loaded:" ] }, { "cell_type": "code", "execution_count": null, "id": "21", "metadata": {}, "outputs": [], "source": [ "sim.load_plotting_data()" ] }, { "cell_type": "markdown", "id": "22", "metadata": {}, "source": [ "Let us plot the initial condition of the electric field. For this we have to inspect the `spline_values` of the simulation:" ] }, { "cell_type": "code", "execution_count": null, "id": "23", "metadata": {}, "outputs": [], "source": [ "sim.spline_values" ] }, { "cell_type": "markdown", "id": "24", "metadata": {}, "source": [ "In this example there is just one species `em_fields` holding the two variables `b_field_log` and `e_field_log`. The data can be inspected as follows:" ] }, { "cell_type": "code", "execution_count": null, "id": "25", "metadata": {}, "outputs": [], "source": [ "e_field = sim.spline_values.em_fields.e_field_log\n", "print(e_field)" ] }, { "cell_type": "markdown", "id": "26", "metadata": {}, "source": [ "The data is thus a dictionary where the keys are simulation times in normalized units, for every time step. The actual spline values are the corresponding values in the form of lists holding numpy arrays with the indicated shape. The shape matches the grid size seen in the above output.\n", "\n", "Let us plot the initial condition in x-direction of the electric field:" ] }, { "cell_type": "code", "execution_count": null, "id": "27", "metadata": {}, "outputs": [], "source": [ "e_init = e_field.data[0.0]\n", "print(f\"{e_init[1].shape = }\")\n", "\n", "from matplotlib import pyplot as plt\n", "\n", "fig, axes = plt.subplots(1, 3, figsize=(15, 4))\n", "\n", "# Plot 1: First component in x-direction\n", "axes[0].plot(e_init[0][:, 0, 0])\n", "axes[0].set_title(\"E-field component 1 (x-direction)\")\n", "axes[0].set_xlabel(\"x\")\n", "axes[0].set_ylabel(\"Value\")\n", "\n", "# Plot 2: Add your second plot\n", "axes[1].plot(e_init[1][:, 0, 0])\n", "axes[1].set_title(\"E-field component 2 (x-direction)\")\n", "axes[1].set_xlabel(\"x\")\n", "axes[1].set_ylabel(\"Value\")\n", "\n", "# Plot 3: Add your third plot\n", "axes[2].plot(e_init[2][:, 0, 0])\n", "axes[2].set_title(\"E-field component 3 (x-direction)\")\n", "axes[2].set_xlabel(\"x\")\n", "axes[2].set_ylabel(\"Value\")\n", "\n", "plt.tight_layout()" ] } ], "metadata": { "kernelspec": { "display_name": "env (3.12.3)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.3" } }, "nbformat": 4, "nbformat_minor": 5 }