From ec9c2cf6ba984651265e3f987d8f8b87b4fffe47 Mon Sep 17 00:00:00 2001 From: Paul Shen Date: Tue, 30 Jan 2024 23:46:20 -0500 Subject: [PATCH 1/2] a --- docs/.documenter-siteinfo.json | 2 +- docs/guide/index.html | 2 +- docs/index.html | 28 ++++++------- docs/search_index.js | 2 +- .../3d_quarter_wavelength_antenna_nres_16.mp4 | Bin 314526 -> 313943 bytes .../3d_scattering_nres_16.mp4 | Bin 494493 -> 495242 bytes makedocs/make.jl | 2 +- makedocs/src/index.md | 37 ++++++++++-------- src/FDTDEngine.jl | 3 +- src/sources.jl | 7 ++-- 10 files changed, 43 insertions(+), 40 deletions(-) diff --git a/docs/.documenter-siteinfo.json b/docs/.documenter-siteinfo.json index f03c537..d13a00e 100644 --- a/docs/.documenter-siteinfo.json +++ b/docs/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.10.0","generation_timestamp":"2024-01-25T16:10:05","documenter_version":"1.2.1"}} \ No newline at end of file +{"documenter":{"julia_version":"1.10.0","generation_timestamp":"2024-01-30T23:44:56","documenter_version":"1.2.1"}} \ No newline at end of file diff --git a/docs/guide/index.html b/docs/guide/index.html index 2e3a931..ef9d113 100644 --- a/docs/guide/index.html +++ b/docs/guide/index.html @@ -1,2 +1,2 @@ -- · FDTDEngine

Engineers run simulations to improve designs. Each time the design changes, the simulation is re-run. This can be done systematically in "parameter sweeps" where different combinations of parameter values are simulated to determine the best design. However, this scales exponentially wrt the number of parameters or DOFs.

General workflow

We use gradient descent, the same as in machine learning. In lieu of optimizing neural network parameters, we're optimizing geometry (or source) parameters. In each training iteration, we generate geometry, run the simulation, calculate the objective metric, and do a backward pass to derive the gradient wrt the geometry parameters. We then do a gradient based parameter update in preparation for the next iteration.

The geometry is thus the first step. It typically has a static component which we can't change such as interfacing waveguides. Then there's a design component which we can change or optimize. The user is responsible for generating the design geometry wrt design parameters. If any pattern is allowed in the design region, our sister package Jello.jl can be used as a length scale controlled geometry generator. In any case, the result needs to be a 2d/3d array of each relevant materials property eg permitivity.

With geometry ready, we can run the simulation. Duration is roughly the time it takes to reach steady state, such as how long it take for the signal to reach output port. The objective is usually a steady state metric which can be computed using values from the final period. We optimize geometry for some objective.

+- · FDTDEngine.jl

Engineers run simulations to improve designs. Each time the design changes, the simulation is re-run. This can be done systematically in "parameter sweeps" where different combinations of parameter values are simulated to determine the best design. However, this scales exponentially wrt the number of parameters or DOFs.

General workflow

We use gradient descent, the same as in machine learning. In lieu of optimizing neural network parameters, we're optimizing geometry (or source) parameters. In each training iteration, we generate geometry, run the simulation, calculate the objective metric, and do a backward pass to derive the gradient wrt the geometry parameters. We then do a gradient based parameter update in preparation for the next iteration.

The geometry is thus the first step. It typically has a static component which we can't change such as interfacing waveguides. Then there's a design component which we can change or optimize. The user is responsible for generating the design geometry wrt design parameters. If any pattern is allowed in the design region, our sister package Jello.jl can be used as a length scale controlled geometry generator. In any case, the result needs to be a 2d/3d array of each relevant materials property eg permitivity.

With geometry ready, we can run the simulation. Duration is roughly the time it takes to reach steady state, such as how long it take for the signal to reach output port. The objective is usually a steady state metric which can be computed using values from the final period. We optimize geometry for some objective.

diff --git a/docs/index.html b/docs/index.html index 3864c15..80de03d 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,19 +1,13 @@ -FDTDEngine.jl · FDTDEngine

FDTDEngine.jl

Only 3d works in latest patch. 2d/1d will be fixed in future. Prerelease. Expect breaking changes

Overview

Differentiable FDTD package for inverse design & topology optimization in photonics, acoustics and RF. Uses automatic differentiation by Zygote.jl for adjoint optimization. Integrates with Jello.jl to generate length scale controlled paramaterized geometry . Staggered Yee grid update with fully featured boundary conditions & sources. Customizable physics to potentially incorporate dynamics like heat transfer, charge transport.

Periodic scattering

Quarter wavelength antenna

Inverse design of compact silicon photonic splitter (coming soon)

<!– –> <!– –>

Quickstart

We do a quick 3d simulation of plane wave scattering on periodic array of dielectric spheres (first gallery movie)

"""
-simulation of plane wave scattering on periodic array of dielectric spheres
-"""
-
-using UnPack, LinearAlgebra, GLMakie
-using FDTDEngine
-include("$(pwd())/scripts/plot_recipes.jl")
-
+FDTDEngine.jl · FDTDEngine.jl

FDTDEngine.jl

Only 3d works in latest patch. 2d/1d will be fixed in future. Prerelease. Expect breaking changes

Overview

Differentiable FDTD package for inverse design & topology optimization in photonics, acoustics and RF. Uses automatic differentiation by Zygote.jl for adjoint optimization. Integrates with Jello.jl to generate length scale controlled paramaterized geometry . Staggered Yee grid update with fully featured boundary conditions & sources. Customizable physics to potentially incorporate dynamics like heat transfer, charge transport.

Periodic scattering

Quarter wavelength antenna

Inverse design of compact silicon photonic splitter (coming soon)

In progress, split ratio isn't correct

Quickstart

We do a quick 3d simulation of plane wave scattering on periodic array of dielectric spheres (first gallery movie)

using UnPack, LinearAlgebra, GLMakie
+using FDTDEngine,FDTDToolkit
 
 F = Float32
 name = "3d_scattering"
-T = 4.0f0 # simulation duration in [periods]
+T = 8.0f0 # simulation duration in [periods]
 nres = 16
 dx = 1.0f0 / nres # pixel resolution in [wavelengths]
-Courant = 0.25f0 # Courant number
+Courant = 0.8 / √3 # Courant number
 
 "geometry"
 l = 2 # domain physical size length
@@ -32,14 +26,16 @@
     # PlaneWave(t -> t < 1 ? cos(F(2π) * t) : 0.0f0, -1; Jz=1)
 ]
 configs = setup(boundaries, sources, monitors, dx, sz; F, Courant, T)
-@unpack μ, σ, σm, dt, geometry_padding, geometry_splits, field_padding, source_effects, monitor_instances, fields, step, power = configs
+@unpack μ, σ, σm, dt, geometry_padding, geometry_splits, field_padding, source_effects, monitor_instances, fields, power = configs
 
 ϵ, μ, σ, σm = apply(geometry_padding; ϵ, μ, σ, σm)
 p = apply(geometry_splits; ϵ, μ, σ, σm)
 u0 = collect(values(fields))
 
 # run simulation
-@showtime sol = accumulate((u, t) -> step(u, p, t, configs), 0:dt:T, init=u0)
+t = 0:dt:T
+sol = similar([u0], length(t))
+@showtime sol = accumulate!((u, t) -> step!(u, p, t, configs), sol, t, init=u0)
 
 # make movie
 Ez = map(sol) do u
@@ -47,6 +43,8 @@
 end
 ϵz = p[1][3]
 dir = @__DIR__
-recordsim(Ez, ϵz, configs, "$dir/$(name)_nres_$nres.mp4", title="$name"; playback=1, bipolar=true)
-

<!– –>

Installation

Install via Pkg.add(url="https://github.com/paulxshen/FDTDEngine.jl"). You can additionally access plotting and movie making scripts via include("_your_path/scripts/plot_recipes.jl")

Implementation

Supports 1d (Ez, Hy), 2d TMz (Ez, Hx, Hy), 2d TEz (Hz, Ex, Ey) and 3d. Length and time are in units of wavelength and period. This normalization allows usage of relative permitivity and permeability in equations . Fields including electric, magnetic and current density are simply bundled as a vector of arrays . Boundary conditions pad the field arrays . PML paddings are multilayered, stateful and permanent, increasing size of field and geometry arrays. All other boundaries only add transient single layers which are subsequently consumed by finite differencing every update step. Paddings are coordinated to implictly implement staggered Yee's grid for finite differencing.

Sources

If a source has fewer nonzero dimensions than the simulation domain, its signal will get normalized along its singleton dimensions. For example, all planar sources in 3d or line sources in 2d will get scaled up by a factor of 1/dx. This way, discretisation would not affect radiated power.

PlaneWaveType
function PlaneWave(f, dims; fields...)

Constructs plane wave source

Args

  • f: time function
  • dims: eg -1 for wave coming from -x edge
  • fields: which fields to excite & their scaling constants (typically a current source, eg Jz=1)
source
GaussianBeamType
function GaussianBeam(f, σ, center, dims; fields...)

Constructs gaussian beam source

Args

  • f: time function
  • σ: std dev length
  • dims: eg 1 for x direction
  • fields: which fields to excite & their scaling constants (typically a current source, eg Jz=1)
source
SourceType
function Source(f, center, bounds; fields...)
-function Source(f, center, L::AbstractVector{<:Real}; fields...)

Constructs custom centered source. Can be used to specify modal sources

Args

  • f: time function
  • L: source dimensions in [wavelengths]
  • fields: which fields to excite & their scaling constants (typically a current source, eg Jz=1)
source

Boundaries

Unspecified boundaries default to PML

PMLType
function PML(dims, d=0.25f0, σ=20.0f0)

Constructs perfectly matched layers (PML aka ABC, RBC) boundary of depth d wavelengths

source
PECType
PEC(dims)

perfect electrical conductor

source
PMCType
PMC(dims)

perfect magnetic conductor

source

Monitors

MonitorType
function Monitor(span, normal=nothing)

Constructs monitor which can span a point, line, surface, or volume

Args

  • span
  • normal: flux monitor direction
source

Physics

step1Function
function step1(u, p, t, configs)

Updates fields for 1D (Ez, Hy)

source
stepTMzFunction
function stepTMz(u, p, t, configs)

Updates fields for 2d TMz

source
stepTEzFunction
function stepTEz(u, p, t, configs)

Updates fields for 2d TEz (Hz, Ex, Ey)

source
step3Function
function step3(u, p, t, configs)

Updates fields for 3d

source

Tutorials

see examples/

Generative inverse design

Please contact us for latest scripts.

Community

Discussion & updates at Julia Discourse

Contributors

Paul Shen <pxshen@alumni.stanford.edu>

+° = π / 180 +recordsim(Ez, ϵz, configs, "$dir/$(name)_nres_$nres.mp4", title="$name"; elevation=30°, playback=1, bipolar=true) +

Installation

Install via

Pkg.add(url="https://github.com/paulxshen/FDTDEngine.jl")
+Pkg.add(url="https://github.com/paulxshen/FDTDToolkit.jl")

FDTDToolkit.jl contains visualization utilities

Implementation

Supports 1d (Ez, Hy), 2d TMz (Ez, Hx, Hy), 2d TEz (Hz, Ex, Ey) and 3d. Length and time are in units of wavelength and period. This normalization allows usage of relative permitivity and permeability in equations . Fields including electric, magnetic and current density are simply bundled as a vector of arrays . Boundary conditions pad the field arrays . PML paddings are multilayered, stateful and permanent, increasing size of field and geometry arrays. All other boundaries only add transient single layers which are subsequently consumed by finite differencing every update step. Paddings are coordinated to implictly implement staggered Yee's grid for finite differencing.

Sources

If a source has fewer nonzero dimensions than the simulation domain, its signal will get normalized along its singleton dimensions. For example, all planar sources in 3d or line sources in 2d will get scaled up by a factor of 1/dx. This way, discretisation would not affect radiated power.

PlaneWaveType
function PlaneWave(f, dims; fields...)

Constructs plane wave source

Args

  • f: time function
  • dims: eg -1 for wave coming from -x edge
  • fields: which fields to excite & their scaling constants (typically a current source, eg Jz=1)
source
SourceType
function Source(f, center, bounds; fields...)
+function Source(f, center, L::AbstractVector{<:Real}; fields...)

Constructs custom source. Can be used to specify uniform or modal sources

Args

  • f: time function
  • L: source dimensions in [wavelengths]
  • fields: which fields to excite & their scaling constants (typically a current source, eg Jz=1)
source

<!– GaussianBeam –>

Boundaries

Unspecified boundaries default to PML

PMLType
function PML(dims, d=0.25f0, σ=20.0f0)

Constructs perfectly matched layers (PML aka ABC, RBC) boundary of depth d wavelengths Doesn't need to be explictly declared as all unspecified boundaries default to PML

source
PECType
PEC(dims)

perfect electrical conductor dims: eg -1 for -x side

source
PMCType
PMC(dims)

perfect magnetic conductor

source

Monitors

MonitorType
function Monitor(span, normal=nothing)

Constructs monitor which can span a point, line, surface, or volume

Args

  • span
  • normal: flux monitor direction
source

Physics

step3!Function
function step3(u, p, t, configs)

Updates fields for 3d

source

<!– step1 –> <!– stepTMz –> <!– stepTEz –>

Tutorials

see examples/

Generative inverse design

Please contact us for latest scripts.

Community

Discussion & updates at Julia Discourse

Contributors

Paul Shen <pxshen@alumni.stanford.edu>

diff --git a/docs/search_index.js b/docs/search_index.js index d25a288..3916e29 100644 --- a/docs/search_index.js +++ b/docs/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"guide/#","page":"-","title":"","text":"","category":"section"},{"location":"guide/","page":"-","title":"-","text":"Engineers run simulations to improve designs. Each time the design changes, the simulation is re-run. This can be done systematically in \"parameter sweeps\" where different combinations of parameter values are simulated to determine the best design. However, this scales exponentially wrt the number of parameters or DOFs. ","category":"page"},{"location":"guide/#General-workflow","page":"-","title":"General workflow","text":"","category":"section"},{"location":"guide/","page":"-","title":"-","text":"We use gradient descent, the same as in machine learning. In lieu of optimizing neural network parameters, we're optimizing geometry (or source) parameters. In each training iteration, we generate geometry, run the simulation, calculate the objective metric, and do a backward pass to derive the gradient wrt the geometry parameters. We then do a gradient based parameter update in preparation for the next iteration.","category":"page"},{"location":"guide/","page":"-","title":"-","text":"The geometry is thus the first step. It typically has a static component which we can't change such as interfacing waveguides. Then there's a design component which we can change or optimize. The user is responsible for generating the design geometry wrt design parameters. If any pattern is allowed in the design region, our sister package Jello.jl can be used as a length scale controlled geometry generator. In any case, the result needs to be a 2d/3d array of each relevant materials property eg permitivity. ","category":"page"},{"location":"guide/","page":"-","title":"-","text":"With geometry ready, we can run the simulation. Duration is roughly the time it takes to reach steady state, such as how long it take for the signal to reach output port. The objective is usually a steady state metric which can be computed using values from the final period. We optimize geometry for some objective. ","category":"page"},{"location":"#FDTDEngine.jl","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Only 3d works in latest patch. 2d/1d will be fixed in future. Prerelease. Expect breaking changes","category":"page"},{"location":"#Overview","page":"FDTDEngine.jl","title":"Overview","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Differentiable FDTD package for inverse design & topology optimization in photonics, acoustics and RF. Uses automatic differentiation by Zygote.jl for adjoint optimization. Integrates with Jello.jl to generate length scale controlled paramaterized geometry . Staggered Yee grid update with fully featured boundary conditions & sources. Customizable physics to potentially incorporate dynamics like heat transfer, charge transport.","category":"page"},{"location":"#Gallery","page":"FDTDEngine.jl","title":"Gallery","text":"","category":"section"},{"location":"#Periodic-scattering","page":"FDTDEngine.jl","title":"Periodic scattering","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"(Image: )","category":"page"},{"location":"#Quarter-wavelength-antenna","page":"FDTDEngine.jl","title":"Quarter wavelength antenna","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"(Image: )","category":"page"},{"location":"#Inverse-design-of-compact-silicon-photonic-splitter-(coming-soon)","page":"FDTDEngine.jl","title":"Inverse design of compact silicon photonic splitter (coming soon)","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":" ","category":"page"},{"location":"#Quickstart","page":"FDTDEngine.jl","title":"Quickstart","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"We do a quick 3d simulation of plane wave scattering on periodic array of dielectric spheres (first gallery movie)","category":"page"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"\"\"\"\nsimulation of plane wave scattering on periodic array of dielectric spheres\n\"\"\"\n\nusing UnPack, LinearAlgebra, GLMakie\nusing FDTDEngine\ninclude(\"$(pwd())/scripts/plot_recipes.jl\")\n\n\nF = Float32\nname = \"3d_scattering\"\nT = 4.0f0 # simulation duration in [periods]\nnres = 16\ndx = 1.0f0 / nres # pixel resolution in [wavelengths]\nCourant = 0.25f0 # Courant number\n\n\"geometry\"\nl = 2 # domain physical size length\nsz = nres .* (l, l, l) # domain voxel dimensions\nϵ1 = 1 #\nϵ2 = 2.25f0 # \nb = F.([norm(v .- sz ./ 2) < 0.5 / dx for v = Base.product(Base.oneto.(sz)...)]) # sphere\nϵ = ϵ2 * b + ϵ1 * (1 .- b)\n\n\"setup\"\nboundaries = [Periodic(2), Periodic(3)]# unspecified boundaries default to PML\n# n = [1, 0, 0]\nmonitors = []\nsources = [\n PlaneWave(t -> cos(F(2π) * t), -1; Jz=1) # Jz excited plane wave from -x plane (eg -1)\n # PlaneWave(t -> t < 1 ? cos(F(2π) * t) : 0.0f0, -1; Jz=1)\n]\nconfigs = setup(boundaries, sources, monitors, dx, sz; F, Courant, T)\n@unpack μ, σ, σm, dt, geometry_padding, geometry_splits, field_padding, source_effects, monitor_instances, fields, step, power = configs\n\nϵ, μ, σ, σm = apply(geometry_padding; ϵ, μ, σ, σm)\np = apply(geometry_splits; ϵ, μ, σ, σm)\nu0 = collect(values(fields))\n\n# run simulation\n@showtime sol = accumulate((u, t) -> step(u, p, t, configs), 0:dt:T, init=u0)\n\n# make movie\nEz = map(sol) do u\n u[3]\nend\nϵz = p[1][3]\ndir = @__DIR__\nrecordsim(Ez, ϵz, configs, \"$dir/$(name)_nres_$nres.mp4\", title=\"$name\"; playback=1, bipolar=true)\n","category":"page"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"","category":"page"},{"location":"#Installation","page":"FDTDEngine.jl","title":"Installation","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Install via Pkg.add(url=\"https://github.com/paulxshen/FDTDEngine.jl\"). You can additionally access plotting and movie making scripts via include(\"_your_path/scripts/plot_recipes.jl\") ","category":"page"},{"location":"#Implementation","page":"FDTDEngine.jl","title":"Implementation","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Supports 1d (Ez, Hy), 2d TMz (Ez, Hx, Hy), 2d TEz (Hz, Ex, Ey) and 3d. Length and time are in units of wavelength and period. This normalization allows usage of relative permitivity and permeability in equations . Fields including electric, magnetic and current density are simply bundled as a vector of arrays . Boundary conditions pad the field arrays . PML paddings are multilayered, stateful and permanent, increasing size of field and geometry arrays. All other boundaries only add transient single layers which are subsequently consumed by finite differencing every update step. Paddings are coordinated to implictly implement staggered Yee's grid for finite differencing.","category":"page"},{"location":"#Sources","page":"FDTDEngine.jl","title":"Sources","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"If a source has fewer nonzero dimensions than the simulation domain, its signal will get normalized along its singleton dimensions. For example, all planar sources in 3d or line sources in 2d will get scaled up by a factor of 1/dx. This way, discretisation would not affect radiated power.","category":"page"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"PlaneWave\nGaussianBeam\nSource","category":"page"},{"location":"#PlaneWave","page":"FDTDEngine.jl","title":"PlaneWave","text":"function PlaneWave(f, dims; fields...)\n\nConstructs plane wave source\n\nArgs\n\nf: time function\ndims: eg -1 for wave coming from -x edge\nfields: which fields to excite & their scaling constants (typically a current source, eg Jz=1)\n\n\n\n\n\n","category":"type"},{"location":"#GaussianBeam","page":"FDTDEngine.jl","title":"GaussianBeam","text":"function GaussianBeam(f, σ, center, dims; fields...)\n\nConstructs gaussian beam source\n\nArgs\n\nf: time function\nσ: std dev length\ndims: eg 1 for x direction\nfields: which fields to excite & their scaling constants (typically a current source, eg Jz=1)\n\n\n\n\n\n","category":"type"},{"location":"#Source","page":"FDTDEngine.jl","title":"Source","text":"function Source(f, center, bounds; fields...)\nfunction Source(f, center, L::AbstractVector{<:Real}; fields...)\n\nConstructs custom centered source. Can be used to specify modal sources\n\nArgs\n\nf: time function\nL: source dimensions in [wavelengths]\nfields: which fields to excite & their scaling constants (typically a current source, eg Jz=1)\n\n\n\n\n\n","category":"type"},{"location":"#Boundaries","page":"FDTDEngine.jl","title":"Boundaries","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Unspecified boundaries default to PML ","category":"page"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Periodic\nPML\nPEC\nPMC","category":"page"},{"location":"#Periodic","page":"FDTDEngine.jl","title":"Periodic","text":"Periodic(dims)\n\nperiodic boundary\n\n\n\n\n\n","category":"type"},{"location":"#PML","page":"FDTDEngine.jl","title":"PML","text":"function PML(dims, d=0.25f0, σ=20.0f0)\n\nConstructs perfectly matched layers (PML aka ABC, RBC) boundary of depth d wavelengths \n\n\n\n\n\n","category":"type"},{"location":"#PEC","page":"FDTDEngine.jl","title":"PEC","text":"PEC(dims)\n\nperfect electrical conductor\n\n\n\n\n\n","category":"type"},{"location":"#PMC","page":"FDTDEngine.jl","title":"PMC","text":"PMC(dims)\n\nperfect magnetic conductor\n\n\n\n\n\n","category":"type"},{"location":"#Monitors","page":"FDTDEngine.jl","title":"Monitors","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Monitor","category":"page"},{"location":"#Monitor","page":"FDTDEngine.jl","title":"Monitor","text":"function Monitor(span, normal=nothing)\n\nConstructs monitor which can span a point, line, surface, or volume\n\nArgs\n\nspan\nnormal: flux monitor direction\n\n\n\n\n\n","category":"type"},{"location":"#Physics","page":"FDTDEngine.jl","title":"Physics","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"step1\nstepTMz\nstepTEz\nstep3","category":"page"},{"location":"#step1","page":"FDTDEngine.jl","title":"step1","text":"function step1(u, p, t, configs)\n\nUpdates fields for 1D (Ez, Hy)\n\n\n\n\n\n","category":"function"},{"location":"#stepTMz","page":"FDTDEngine.jl","title":"stepTMz","text":"function stepTMz(u, p, t, configs)\n\nUpdates fields for 2d TMz\n\n\n\n\n\n","category":"function"},{"location":"#stepTEz","page":"FDTDEngine.jl","title":"stepTEz","text":"function stepTEz(u, p, t, configs)\n\nUpdates fields for 2d TEz (Hz, Ex, Ey)\n\n\n\n\n\n","category":"function"},{"location":"#step3","page":"FDTDEngine.jl","title":"step3","text":"function step3(u, p, t, configs)\n\nUpdates fields for 3d\n\n\n\n\n\n","category":"function"},{"location":"#Tutorials","page":"FDTDEngine.jl","title":"Tutorials","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"see examples/","category":"page"},{"location":"#Generative-inverse-design","page":"FDTDEngine.jl","title":"Generative inverse design","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Please contact us for latest scripts.","category":"page"},{"location":"#Community","page":"FDTDEngine.jl","title":"Community","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Discussion & updates at Julia Discourse","category":"page"},{"location":"#Contributors","page":"FDTDEngine.jl","title":"Contributors","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Paul Shen ","category":"page"}] +[{"location":"guide/#","page":"-","title":"","text":"","category":"section"},{"location":"guide/","page":"-","title":"-","text":"Engineers run simulations to improve designs. Each time the design changes, the simulation is re-run. This can be done systematically in \"parameter sweeps\" where different combinations of parameter values are simulated to determine the best design. However, this scales exponentially wrt the number of parameters or DOFs. ","category":"page"},{"location":"guide/#General-workflow","page":"-","title":"General workflow","text":"","category":"section"},{"location":"guide/","page":"-","title":"-","text":"We use gradient descent, the same as in machine learning. In lieu of optimizing neural network parameters, we're optimizing geometry (or source) parameters. In each training iteration, we generate geometry, run the simulation, calculate the objective metric, and do a backward pass to derive the gradient wrt the geometry parameters. We then do a gradient based parameter update in preparation for the next iteration.","category":"page"},{"location":"guide/","page":"-","title":"-","text":"The geometry is thus the first step. It typically has a static component which we can't change such as interfacing waveguides. Then there's a design component which we can change or optimize. The user is responsible for generating the design geometry wrt design parameters. If any pattern is allowed in the design region, our sister package Jello.jl can be used as a length scale controlled geometry generator. In any case, the result needs to be a 2d/3d array of each relevant materials property eg permitivity. ","category":"page"},{"location":"guide/","page":"-","title":"-","text":"With geometry ready, we can run the simulation. Duration is roughly the time it takes to reach steady state, such as how long it take for the signal to reach output port. The objective is usually a steady state metric which can be computed using values from the final period. We optimize geometry for some objective. ","category":"page"},{"location":"#FDTDEngine.jl","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Only 3d works in latest patch. 2d/1d will be fixed in future. Prerelease. Expect breaking changes","category":"page"},{"location":"#Overview","page":"FDTDEngine.jl","title":"Overview","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Differentiable FDTD package for inverse design & topology optimization in photonics, acoustics and RF. Uses automatic differentiation by Zygote.jl for adjoint optimization. Integrates with Jello.jl to generate length scale controlled paramaterized geometry . Staggered Yee grid update with fully featured boundary conditions & sources. Customizable physics to potentially incorporate dynamics like heat transfer, charge transport.","category":"page"},{"location":"#Gallery","page":"FDTDEngine.jl","title":"Gallery","text":"","category":"section"},{"location":"#Periodic-scattering","page":"FDTDEngine.jl","title":"Periodic scattering","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"(Image: )","category":"page"},{"location":"#Quarter-wavelength-antenna","page":"FDTDEngine.jl","title":"Quarter wavelength antenna","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"(Image: )","category":"page"},{"location":"#Inverse-design-of-compact-silicon-photonic-splitter-(coming-soon)","page":"FDTDEngine.jl","title":"Inverse design of compact silicon photonic splitter (coming soon)","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"In progress, split ratio isn't correct (Image: ) (Image: )","category":"page"},{"location":"#Quickstart","page":"FDTDEngine.jl","title":"Quickstart","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"We do a quick 3d simulation of plane wave scattering on periodic array of dielectric spheres (first gallery movie)","category":"page"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"using UnPack, LinearAlgebra, GLMakie\nusing FDTDEngine,FDTDToolkit\n\nF = Float32\nname = \"3d_scattering\"\nT = 8.0f0 # simulation duration in [periods]\nnres = 16\ndx = 1.0f0 / nres # pixel resolution in [wavelengths]\nCourant = 0.8 / √3 # Courant number\n\n\"geometry\"\nl = 2 # domain physical size length\nsz = nres .* (l, l, l) # domain voxel dimensions\nϵ1 = 1 #\nϵ2 = 2.25f0 # \nb = F.([norm(v .- sz ./ 2) < 0.5 / dx for v = Base.product(Base.oneto.(sz)...)]) # sphere\nϵ = ϵ2 * b + ϵ1 * (1 .- b)\n\n\"setup\"\nboundaries = [Periodic(2), Periodic(3)]# unspecified boundaries default to PML\n# n = [1, 0, 0]\nmonitors = []\nsources = [\n PlaneWave(t -> cos(F(2π) * t), -1; Jz=1) # Jz excited plane wave from -x plane (eg -1)\n # PlaneWave(t -> t < 1 ? cos(F(2π) * t) : 0.0f0, -1; Jz=1)\n]\nconfigs = setup(boundaries, sources, monitors, dx, sz; F, Courant, T)\n@unpack μ, σ, σm, dt, geometry_padding, geometry_splits, field_padding, source_effects, monitor_instances, fields, power = configs\n\nϵ, μ, σ, σm = apply(geometry_padding; ϵ, μ, σ, σm)\np = apply(geometry_splits; ϵ, μ, σ, σm)\nu0 = collect(values(fields))\n\n# run simulation\nt = 0:dt:T\nsol = similar([u0], length(t))\n@showtime sol = accumulate!((u, t) -> step!(u, p, t, configs), sol, t, init=u0)\n\n# make movie\nEz = map(sol) do u\n u[3]\nend\nϵz = p[1][3]\ndir = @__DIR__\n° = π / 180\nrecordsim(Ez, ϵz, configs, \"$dir/$(name)_nres_$nres.mp4\", title=\"$name\"; elevation=30°, playback=1, bipolar=true)\n","category":"page"},{"location":"#Installation","page":"FDTDEngine.jl","title":"Installation","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Install via ","category":"page"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Pkg.add(url=\"https://github.com/paulxshen/FDTDEngine.jl\")\nPkg.add(url=\"https://github.com/paulxshen/FDTDToolkit.jl\")","category":"page"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"FDTDToolkit.jl contains visualization utilities","category":"page"},{"location":"#Implementation","page":"FDTDEngine.jl","title":"Implementation","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Supports 1d (Ez, Hy), 2d TMz (Ez, Hx, Hy), 2d TEz (Hz, Ex, Ey) and 3d. Length and time are in units of wavelength and period. This normalization allows usage of relative permitivity and permeability in equations . Fields including electric, magnetic and current density are simply bundled as a vector of arrays . Boundary conditions pad the field arrays . PML paddings are multilayered, stateful and permanent, increasing size of field and geometry arrays. All other boundaries only add transient single layers which are subsequently consumed by finite differencing every update step. Paddings are coordinated to implictly implement staggered Yee's grid for finite differencing.","category":"page"},{"location":"#Sources","page":"FDTDEngine.jl","title":"Sources","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"If a source has fewer nonzero dimensions than the simulation domain, its signal will get normalized along its singleton dimensions. For example, all planar sources in 3d or line sources in 2d will get scaled up by a factor of 1/dx. This way, discretisation would not affect radiated power.","category":"page"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"PlaneWave\nSource","category":"page"},{"location":"#PlaneWave","page":"FDTDEngine.jl","title":"PlaneWave","text":"function PlaneWave(f, dims; fields...)\n\nConstructs plane wave source\n\nArgs\n\nf: time function\ndims: eg -1 for wave coming from -x edge\nfields: which fields to excite & their scaling constants (typically a current source, eg Jz=1)\n\n\n\n\n\n","category":"type"},{"location":"#Source","page":"FDTDEngine.jl","title":"Source","text":"function Source(f, center, bounds; fields...)\nfunction Source(f, center, L::AbstractVector{<:Real}; fields...)\n\nConstructs custom source. Can be used to specify uniform or modal sources\n\nArgs\n\nf: time function\nL: source dimensions in [wavelengths]\nfields: which fields to excite & their scaling constants (typically a current source, eg Jz=1)\n\n\n\n\n\n","category":"type"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"","category":"page"},{"location":"#Boundaries","page":"FDTDEngine.jl","title":"Boundaries","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Unspecified boundaries default to PML ","category":"page"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Periodic\nPML\nPEC\nPMC","category":"page"},{"location":"#Periodic","page":"FDTDEngine.jl","title":"Periodic","text":"Periodic(dims)\n\nperiodic boundary\n\n\n\n\n\n","category":"type"},{"location":"#PML","page":"FDTDEngine.jl","title":"PML","text":"function PML(dims, d=0.25f0, σ=20.0f0)\n\nConstructs perfectly matched layers (PML aka ABC, RBC) boundary of depth d wavelengths Doesn't need to be explictly declared as all unspecified boundaries default to PML\n\n\n\n\n\n","category":"type"},{"location":"#PEC","page":"FDTDEngine.jl","title":"PEC","text":"PEC(dims)\n\nperfect electrical conductor dims: eg -1 for -x side\n\n\n\n\n\n","category":"type"},{"location":"#PMC","page":"FDTDEngine.jl","title":"PMC","text":"PMC(dims)\n\nperfect magnetic conductor\n\n\n\n\n\n","category":"type"},{"location":"#Monitors","page":"FDTDEngine.jl","title":"Monitors","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Monitor","category":"page"},{"location":"#Monitor","page":"FDTDEngine.jl","title":"Monitor","text":"function Monitor(span, normal=nothing)\n\nConstructs monitor which can span a point, line, surface, or volume\n\nArgs\n\nspan\nnormal: flux monitor direction\n\n\n\n\n\n","category":"type"},{"location":"#Physics","page":"FDTDEngine.jl","title":"Physics","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"step3!","category":"page"},{"location":"#step3!","page":"FDTDEngine.jl","title":"step3!","text":"function step3(u, p, t, configs)\n\nUpdates fields for 3d\n\n\n\n\n\n","category":"function"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":" ","category":"page"},{"location":"#Tutorials","page":"FDTDEngine.jl","title":"Tutorials","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"see examples/","category":"page"},{"location":"#Generative-inverse-design","page":"FDTDEngine.jl","title":"Generative inverse design","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Please contact us for latest scripts.","category":"page"},{"location":"#Community","page":"FDTDEngine.jl","title":"Community","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Discussion & updates at Julia Discourse","category":"page"},{"location":"#Contributors","page":"FDTDEngine.jl","title":"Contributors","text":"","category":"section"},{"location":"","page":"FDTDEngine.jl","title":"FDTDEngine.jl","text":"Paul Shen ","category":"page"}] } diff --git a/examples/3d_dipole_antenna/3d_quarter_wavelength_antenna_nres_16.mp4 b/examples/3d_dipole_antenna/3d_quarter_wavelength_antenna_nres_16.mp4 index 6fcf978c2d4554ec27db49398b5bd20abf93b4a1..7bc3da96c534ebf9f1ac50d8f9d74485473449bb 100644 GIT binary patch delta 179254 zcmV)hK%>8&nG@HP6Obwbx(Bf=ssaKp1GCryX&8Ucdi8dv<6SQqa*Y!L7P~}Y!kfH8 z16sae+CUAhb2RYW%=c9V?r#Y7rLRZXSla9esNMAIbsq5Ubf_0gt`_?yOhw{Vc>U=f zyki(Rs$4N>PXj3Yo27QGi zY(#(VWW$d1o5L8wf|dk#tn!Nx`j~4`tZ&782f zA3|FE5HG&Z5@XV8cI9^9z^LGt-S(G$ebs-I_I{#WtjcqRzn}r#TbzhpI_K&EGfDQl zKX>MvvPkhmqj!cE6`mT9q4$Y$13LcySJkWC3a5UU!g_IV4Rh<&E>f1qY3xSe8TiC* z!C9SuD_=>8R<3)n9A^BZn(YFtRSA`}nP)zv&Npr2Rvu(xw>^lX2_ zy8{c>Gn{efaQ=N~jshLsMRuTk%PYIXJv={G8K27g&sa3_InQ!bYJV@8cL(ClkAz%f z-UX5=&8-a8#c1qeuc=rLCA1uX#|{n@G)|p!(Y%$wDMwNXq-=5Ue9sorGu8ptjEv_; z%KhI=<;AcDOd;=mbxOx)(L;}G8`^)-XT6+aHC|f%&XfwsSB62+RF9hX%%DA>zyj)9 zo!MWQz6maUAq*ru8zmC+AW6rw zr%#%D=ScXVgZOTOvAO^X1Fb@-I@⩔Fz@J1R!W#CjXmeB=pF~PnR9p$|`=qg37~J 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