Getting Started

Installation

Pkg.add("CoupledDipole")

Example

A typical simulation requires two inputs: a Cluster, describing the configuration of particles, and a Material, describing the wavelength-dependent dielectric functions of all media.

using CoupledDipole
using DataFrames
using VegaLite

## cluster geometry
cl1 = cluster_helix(8, 20, 20, 50, 200, 300, π/2, 0)
cl0 = cluster_single(20, 20, 50) # reference: single-particle

## materials
wavelengths = collect(400:2:800.0)
media = Dict([("Au", epsilon_Au), ("medium", x -> 1.33)])
mat = Material(wavelengths, media)
Material{Float64}([400.0, 402.0, 404.0, 406.0, 408.0, 410.0, 412.0, 414.0, 416.0, 418.0  …  782.0, 784.0, 786.0, 788.0, 790.0, 792.0, 794.0, 796.0, 798.0, 800.0], Dict{String, Function}("medium" => Main.var"#1#2"(), "Au" => CoupledDipole.epsilon_Au))

From these two objects we can simply call a high-level function to simulate optical properties. The following lines simulate the orientation-averaged optical response,

oa0 = spectrum_oa(cl0, mat) # reference: just one particle
oa1 = spectrum_oa(cl1, mat)
(average = CoupledDipole.CrossSections{Float64}([4378.946066676883, 4362.722044978327, 4346.201706724189, 4329.4154050028765, 4312.396314983564, 4295.180315312668, 4277.8059117947605, 4260.314198900285, 4242.748853297844, 4225.15615266564  …  2014.1114022194508, 1944.7314331532084, 1878.8396593265745, 1816.2127474754036, 1756.6442760833827, 1699.9432957012266, 1645.9330212521859, 1594.44964390688, 1545.341251216252, 1498.4668452240799], [3703.254370735785, 3696.568483018135, 3689.541834802028, 3682.2013972757563, 3674.576227514868, 3666.697369775457, 3658.59778913132, 3650.3123344434375, 3641.8777264446303, 3633.33256582756  …  732.5893772135712, 707.7501628870889, 684.2028085592609, 661.8610132199017, 640.6453213367857, 620.4825073266509, 601.3050206523932, 583.0504852062568, 565.6612473179102, 549.0839673349261], [725.150296228154, 713.8608146464528, 702.6643385556657, 691.5634900279158, 680.5617748048969, 669.6635291845162, 658.8738815059969, 648.1987264158246, 637.6447099233139, 627.2192231907741  …  1280.3642303519432, 1235.8424638758559, 1193.5177568099, 1153.2529237827773, 1114.920865020181, 1078.4037398426806, 1043.5922118205162, 1010.3847594689836, 978.6870468003401, 948.4113484769059]), dichroism = CoupledDipole.CrossSections{Float64}([-3.0857886738434637, -3.2226628459447495, -3.337532422027111, -3.4299199264008946, -3.499776494382177, -3.547449231841739, -3.5736391412829396, -3.5793518427936997, -3.5658434205022393, -3.534563706099158  …  27.49038921938616, 28.010815743094273, 28.475306341207325, 28.88711880531347, 29.249412826410158, 29.565234106589138, 29.83750377824662, 30.069011972100284, 30.262414605423018, 30.420232647474545], [-3.608956196760342, -3.59266298548443, -3.5664086810877675, -3.5313725359447186, -3.4888511940265627, -3.440223063784872, -3.386910495925367, -3.3303413679448233, -3.2719116176718166, -3.2129501341934263  …  -1.1211662873125532, -1.0112605881213024, -0.9035132843786104, -0.7984004441671504, -0.6962807520160702, -0.597416695457432, -0.5019921245701777, -0.41012680781674327, -0.3218884981821268, -0.2373029339460021], [-1.8037688384544988, -1.9420352135651555, -2.0593518183658355, -2.154924492668138, -2.2282247736946283, -2.2789927316403396, -2.30723325664365, -2.3132063023154052, -2.297411751030806, -2.2605696821943213  …  27.957252909173786, 28.369690581647422, 28.729329066294365, 29.0397848817081, 29.304471494049217, 29.526603237778385, 29.709201081510262, 29.85509968234416, 29.96695529578945, 30.04725420681045]))

From there we combine the cross-sections in long-format dataframes for plotting,

d0 = oa_df(oa0, mat.wavelengths)
d1 = oa_df(oa1, mat.wavelengths)

d2 = [insertcols!(d1, :cluster => "helix");
      insertcols!(d0, :cluster => "single")]

d2 |> @vlplot(
 width= 200,
 height =  150,
     mark = {:line, clip = true},
     row = "type", column="variable",
     resolve={scale={y="independent"}},
     encoding = {x = "wavelength:q", y = "value:q",
      strokeDash = "cluster:n", color = "cluster:n"}
 )