# GlassCat

This submodule is used to download, parse, install and manage AGF glass specifications for use in OpticSim.

The central configuration file for GlassCat is located at src/GlassCat/data/sources.txt, which ships with the following default entries.

NIKON a49714470fa875ad4fd8d11cbc0edbf1adfe877f42926d7612c1649dd9441e75 https://www.nikon.com/products/components/assets/pdf/nikon_zemax_data.zip
SUMITA c1093e42a1d08acbe30698aba730161e3b43f8f0d50533f65de8b6b11100fdc8 https://www.sumita-opt.co.jp/en/wp/wp-content/themes/sumita-opt-en/download-files.php files%5B%5D=new_sumita.agf&category=data

Each line corresponds to one AGF source, which is described by 2 to 4 space-delimited columns. The first column provides the installed module name for the catalog, e.g. GlassCat.NIKON. The second column is the expected SHA256 checksum for the AGF file.

The final two columns are optional, specifying download instructions for acquiring the zipped AGF files automatically from the web. The fourth column allows us to use POST requests to acquire files from interactive sites.

When ] build OpticSim is run, the sources are verified and parsed into corresponding Julia files. These are then included in OpticSim via AGFGlassCat.jl. These steps are run automatically when the package is first installed using ] add OpticSim, creating a sufficient working environment for our examples and tests.

sources.txt can be edited freely to add more glass catalogs. However, this is a somewhat tedious process, so we have a convenience function for adding a locally downloaded AGF file to the source list.

OpticSim.GlassCat.add_agfFunction
add_agf(agffile; agfdir = AGF_DIR, sourcefile = SOURCES_PATH, name = nothing, rebuild = true)

Copies a file at agffile (this can be either a download link or local path) to agfdir and appends a corresponding entry to the source list at sourcefile.

If a name is not provided for the catalog, an implicit name is derived from agffile.

If rebuild is true, Pkg.build is called at the end to install the new catalog.

source

## Using installed glasses

Glass types are accessed like so: OpticSim.GlassCat.CATALOG_NAME.GLASS_NAME, e.g.

OpticSim.GlassCat.SUMITA.LAK7
OpticSim.GlassCat.SCHOTT.PK3

All glasses and catalogs are exported in their respective modules, so it is possible to invoke using calls for convenience, e.g.

using OpticSim
GlassCat.SUMITA.LAK7
using OpticSim.GlassCat
SCHOTT.PK3
using OpticsSim.GlassCat.SCHOTT
N_BK7

Autocompletion can be used to see available catalogs and glasses. All catalog glasses are of type OpticSim.GlassCat.Glass. Note that special characters in glass/catalog names are replaced with _. There is a special type and constant value for air: OpticSim.GlassCat.Air.

Unitful.jl is used to manage units, meaning any valid unit can be used for all arguments, e.g., wavelength can be passed in as μm or nm (or cm, mm, m, etc.). Non-unitful options are also available, in which case units are assumed to be μm, °C and Atm for length, temperature and pressure respectively.

TEMP_REF and PRESSURE_REF are constants:

const TEMP_REF = 20.0 # °C
const PRESSURE_REF = 1.0 # Atm

## Types

OpticSim.GlassCat.GlassType

Stores all attributes relating to a glass type specified in an .AGF glass catalog.

Never used directly, instead created using catalog glasses, e.g. GlassCat.SCHOTT.N_BK7.

In order to prevent type ambiguities in OpticSim.jl we can't have this type paramaterized.

source
OpticSim.GlassCat.GlassIDType

Object identifying a glass, containing a type (e.g. MODEL, MIL, OTHER or AGF) depending on how the glass is defined, and an integer ID. Air is AIR:0, others are on the form AGF:N, for example.

source

## Functions

OpticSim.GlassCat.indexFunction
index(glass::AbstractGlass, wavelength; temperature=20°C, pressure=1Atm)

Compute the refractive index of glass at wavelength, optionally at specified temperature and pressure. Result is relative to the refractive index of air at given temperature and pressure.

If unitless, arguments are interpretted as μm, °C and Atm respectively.

This is defined to always equal 1.0 for Air at any temperature and pressure, use absairindex for the absolute refractive index of air at a given temperature and pressure.

Examples

julia> index(GlassCat.SUMITA.LAK7, 700u"nm")
1.646494204478318

julia> index(GlassCat.SCHOTT.N_BK7, 0.55, temperature = 22.0)
1.51852824383283

julia> index(GlassCat.HOYA.FF1, 532u"nm", temperature = 25u"°C", pressure = 1.3)
1.5144848290944655
source
OpticSim.GlassCat.absairindexFunction
absairindex(wavelength; temperature=20°C, pressure=1Atm)

Compute the absolute refractive index of air at wavelength, optionally at specified temperature and pressure. If unitless, arguments are interpretted as μm, °C and Atm respectively.

Examples

julia> absairindex(700u"nm")
1.000271074905147

julia> absairindex(0.7, temperature=27.0)
1.000264738846504

julia> absairindex(532u"nm", temperature = 25u"°C", pressure = 1.3)
1.0003494991178161
source
OpticSim.GlassCat.absorptionFunction
absorption(glass::AbstractGlass, wavelength; temperature=20°C, pressure=1Atm)

Compute the intensity absorption per mm of glass at wavelength, optionally at specified temperature and pressure. Transmission values are linearly interpolated from the adjacent values in the data table of glass, if wavelength is below the minimum or above the maximum in the table then the nearest value is taken.

Absorption is defined as $\frac{-\log(t)}{\tau}$ where $t$ is the transmission value and $\tau$ is the thickness, both of which are provided in the data table.

If unitless, arguments are interpretted as μm, °C and Atm respectively.

Examples

julia> absorption(GlassCat.SUMITA.LAK7, 700u"nm")
0.0006018072325563021

julia> absorption(GlassCat.SCHOTT.N_BK7, 0.55, temperature = 22.0)
0.00016504471175660636

julia> absorption(GlassCat.SCHOTT.PSK3, 532u"nm", temperature = 25u"°C", pressure = 1.3)
0.00020855284788532435
source

OpticSim.GlassCat.glassfromMILFunction
glassfromMIL(glasscode::Union{Float64,Int}) -> Glass

Generates a glass object for the given glass code based on U.S. military standard MIL-G-174, see the MIL specification for further details.

The glass code is a six-digit number specifying the glass according to its refractive index Nd at d-light (587.5618nm), and its Abbe number Vd also taken at d-light. The resulting glass code is the value of Nd - 1 rounded to three digits, followed by Vd rounded to three digits, with all decimal points ignored. For example, N_BK7 has Nd = 1.5168 and Vd = 64.17, giving a six-digit glass code of 517642.

For Nd > 1.999 the format 1.123642 can be used representing Nd = 2.123 and Vd = 64.2.

Accuracy is poor given the low precision of the input parameters, the mean error to measured data may be significant. Behavior may differ from other optical simulation tools when using MIL glasses. The approximate dispersion calculation used these glasses is generally only valid for visible wavelengths, in this case a limit of 360nm to 750nm is imposed.

Examples

julia> index(glassfromMIL(517642), 0.5875618)
1.5170003960064509

julia> index(glassfromMIL(1.134642), 0.5875618)
2.1340008686098946
source
OpticSim.GlassCat.modelglassFunction
modelglass(Nd::Float64, Vd::Float64, ΔPgF::Float64) -> Glass

Generates a glass object for the given refractive index at d-light (587.5618nm), Nd, the Abbe number also at d-light, Vd, and partial dispersion, ΔPgF. The mean error to measured data for these models is typically small - usually < 0.0001. Behavior may differ from other optical simulation tools when using model glasses.

The approximate dispersion calculation used for these glasses is generally only valid for visible wavelengths, in this case a limit of 360nm to 750nm is imposed.

Examples

julia> index(modelglass(1.5168, 64.17, 0.0), 0.5875618)
1.5168003970108495

julia> index(modelglass(1.2344, 61.57, 0.003), 0.678)
1.2329425902693352
source

OpticSim.GlassCat.glasscatalogsFunction
glasscatalogs()

Returns the complete list of glass catalogs available from GlassCat.

Example

julia> glasscatalogs()
41-element Array{Any,1}:
OpticSim.GlassCat.AMTIR
OpticSim.GlassCat.APEL
OpticSim.GlassCat.ARCHER
OpticSim.GlassCat.ARTON
OpticSim.GlassCat.AUER_LIGHTING
OpticSim.GlassCat.BIREFRINGENT
⋮
source
OpticSim.GlassCat.glassnamesFunction
glassnames(catalog::Module)

Returns the glass names available from a given catalog.

Example

julia> glassnames(GlassCat.CARGILLE)
3-element Array{Any,1}:
"OG0607"
"OG0608"
"OG081160"
source
glassnames()

Returns the glass names available from all catalogs.

Example

julia> glassnames()
6-element Array{Pair{Module,Array{Any,1}},1}:
OpticSim.GlassCat.CARGILLE => ["OG0607", "OG0608", "OG081160"]
OpticSim.GlassCat.HOYA => ["BAC4", "BACD11"  …  "TAFD65"]
OpticSim.GlassCat.NIKON => ["BAF10", "BAF11"  …  "_7054"]
OpticSim.GlassCat.OHARA => ["L_BAL35", "L_BAL35P"  …  "S_TIM8"]
OpticSim.GlassCat.SCHOTT => ["AF32ECO", "BAFN6"  …  "SFL6"]
OpticSim.GlassCat.SUMITA => ["BAF1", "BAF10"  …  "ZNSF8"]
source
OpticSim.GlassCat.infoFunction
info([io::IO], glass::AbstractGlass)

Print out all data associated with glass in an easily readable format.

Examples

julia> info(GlassCat.RPO.IG4)
ID:                                                AGF:52
Dispersion formula:                                Schott (1)
Dispersion formula coefficients:
a₀:                                           6.91189161
a₁:                                           -0.000787956404
a₂:                                           -4.22296071
a₃:                                           142.900646
a₄:                                           -1812.32748
a₅:                                           7766.33028
Valid wavelengths:                                 3.0μm to 12.0μm
Reference temperature:                              20.0°C
Thermal ΔRI coefficients:
D₀:                                           3.24e-5
D₁:                                           0.0
D₂:                                           0.0
E₀:                                           0.0
E₁:                                           0.0
λₜₖ:                                          0.0
TCE (÷1e-6):                                       20.4
Ignore thermal expansion:                          false
Density (p):                                       4.47g/m³
ΔPgF:                                              0.0
RI at sodium D-Line (587nm):                       1.0
Abbe Number:                                       0.0
Cost relative to N_BK7:                              ?
Status:                                            Standard (0)
Melt frequency:                                    0
Exclude substitution:                              false
source
OpticSim.GlassCat.findglassFunction
findglass(condition::Function) -> Vector{Glass}

Returns the list of glasses which satisfy condition where condition::(Glass -> Bool).

Example

julia> findglass(x -> (x.Nd > 2.3 && x.λmin < 0.5 && x.λmax > 0.9))
8-element Array{GlassCat.Glass,1}:
BIREFRINGENT.TEO2_E
BIREFRINGENT.PBMOO4
BIREFRINGENT.LINBO3
INFRARED.CLEARTRAN_OLD
INFRARED.CLEARTRAN
INFRARED.SRTIO3
INFRARED.ZNS_VIS
source

OpticSim.GlassCat.polyfit_indicesFunction
polyfit_indices(wavelengths, n_rel; degree=5)

Fit a polynomial to indices at wavelengths, optionally specifying the degree of the polynomial. Returns tuple of array of fitted indices at wavelengths and the polynomial.

source
OpticSim.GlassCat.plot_indicesFunction
plot_indices(glass::AbstractGlass; polyfit=false, fiterror=false, degree=5, temperature=20°C, pressure=1Atm, nsamples=300, sampling_domain="wavelength")

Plot the refractive index for glass for nsamples within its valid range of wavelengths, optionally at temperature and pressure. polyfit will show a polynomial of optionally specified degree fitted to the data, fiterror will also show the fitting error of the result. sampling_domain specifies whether the samples will be spaced uniformly in "wavelength" or "wavenumber".

source
OpticSim.GlassCat.drawglassmapFunction
drawglassmap(glasscatalog::Module; λ::Length = 550nm, glassfontsize::Integer = 3, showprefixglasses::Bool = false)

Draw a scatter plot of index vs dispersion (the derivative of index with respect to wavelength). Both index and dispersion are computed at wavelength λ.

Choose glasses to graph using the glassfilterprediate argument. This is a function that receives a Glass object and returns true if the glass should be graphed.

If showprefixglasses is true then glasses with names like F_BAK7 will be displayed. Otherwise glasses that have a leading letter prefix followed by an underscore, such as F_, will not be displayed.

The index formulas for some glasses may give incorrect results if λ is outside the valid range for that glass. This can give anomalous results, such as indices less than zero or greater than 6. To filter out these glasses set maximumindex to a reasonable value such as 3.0.

example: plot only glasses that do not contain the strings "E" and "J"

drawglassmap(NIKON,showprefixglasses = true,glassfilterpredicate = (x) -> !occursin("J",string(x)) && !occursin("E",string(x)))

source

OpticSim.GlassCat.verify_sources!Function
verify_sources!(sources::AbstractVector{<:AbstractVector{<:AbstractString}}, agfdir::AbstractString)

Verify a list of sources located in agfdir. If AGF files are missing or invalid, try to download them using the information provided in sources.

Each source ∈ sources is a collection of strings in the format name, sha256sum, url [, POST_data], where the last optional string is used to specify data to be sent in a POST request. This allows us to download a greater range of sources (e.g. SUMITA).

Modifies sources in-place such that only verified sources remain.

source
OpticSim.GlassCat.verify_sourceFunction
verify_source(agffile::AbstractString, expected_sha256sum::AbstractString)

Verify a source file using SHA256, returning true if successful. Otherwise, remove the file and return false.

source
OpticSim.GlassCat.download_sourceFunction
download_source(dest::AbstractString, url::AbstractString, POST_data::Union{Nothing,AbstractString} = nothing)

Download and unzip an AGF glass catalog from a publicly available source. Supports POST requests.

source