Skip to content

Reference

JosephsonCircuits.JosephsonCircuits Module
julia
JosephsonCircuits

A frequency domain simulator for superconducting circuits containing Josephson junctions, capacitors, inductors, mutual inductors, resistors, and multiport scattering parameter blocks.

Circuits are solved by harmonic balance in a modified nodal analysis formulation in the node flux basis. A strong periodic drive (the pump) is solved with hbnlsolve, the circuit is linearized about that operating point and swept over weak signal frequencies with hblinsolve, and hbsolve runs the two in sequence. From the linearized solution the package computes scattering parameters, noise scattering parameters, quantum efficiency, commutation relations, and adjoint-method sensitivities with respect to component values or, through designsensitivities, to the design parameters of a circuit builder.

The same compiled circuit, on the same node flux unknowns, can also be integrated directly in physical time with transientsolve, for pulsed drives and for drives with more tones than a harmonic grid can hold, with the exact tangent and adjoint of the recorded time steps.

A circuit is written as a Circuit of typed component models, or as a legacy netlist of (name, node1, node2, value) tuples. The stages a circuit passes through, and the files that implement them, are listed next to the include statements below.

source
JosephsonCircuits.CALLABLE_FORMS Constant
julia
CALLABLE_FORMS

The ways a callable provider may be called. See CallableMatrixProvider.

source
JosephsonCircuits.FCONJ Constant
julia
FCONJ

Flag bit marking a slot of the frequency domain array which is a conjugate symmetry target, so the value gathered for it is conjugated. See NonlinearTermPlan.

source
JosephsonCircuits.FWIDE Constant
julia
FWIDE

Flag bit marking a slot of the frequency domain array whose source mode is not self conjugate, so the imaginary part of the source occupies the real slot after the one addressed. See NonlinearTermPlan.

source
JosephsonCircuits.Ground Constant
julia
Ground

The distinguished global electrical reference. Ground may appear as an endpoint in any connection group, and as the negative pin of an interface port. The ground net is always named "0".

For uniformity with ordinary components, ground may also be declared in the components list and referenced through its single terminal:

julia
Circuit([:r1 => Resistor(50.0), :gnd => Ground()],
    [[(:r1, 1)], [(:r1, 2), (:gnd, 1)]])

Ground() and Ground are the same object, so both spellings work in both positions. A ground instance is sugar for the reference net rather than a device: every reference to its terminal resolves to the global ground net, however many instances are declared and at whatever level of the hierarchy, and it contributes no flattened component.

source
JosephsonCircuits.IMPEDANCE_C Constant
julia
IMPEDANCE_C

The integer code impedance uses for a capacitor; see impedancecode.

source
JosephsonCircuits.IMPEDANCE_L Constant
julia
IMPEDANCE_L

The integer code impedance uses for an inductor; see impedancecode.

source
JosephsonCircuits.IMPEDANCE_R Constant
julia
IMPEDANCE_R

The integer code impedance uses for a resistor; see impedancecode.

source
JosephsonCircuits.Phi0 Constant
julia
const Phi0

The magnetic flux quantum h/(2e) in Weber (equivalently H_A), equal to 2_pi*phi0.

source
JosephsonCircuits.REVERSESENSITIVITYCHUNKBYTES Constant
julia
REVERSESENSITIVITYCHUNKBYTES

The byte budget of one chunk of the reverse contraction's dense buffers, which sets the column count calcSsensitivityreverse! works in.

source
JosephsonCircuits.boltzmann_constant Constant
julia
const boltzmann_constant

The Boltzmann constant k_B, 1.380649e-23 J/K, used with reduced_planck_constant to convert a physical temperature into the thermal occupation of a noise channel.

source
JosephsonCircuits.phi0 Constant
julia
const phi0

The reduced magnetic flux quantum hbar/(2e) in Weber (equivalently H*A). This is the flux scale that relates a Josephson junction's inductance to its critical current, Ic = phi0/Lj, and the unit in which the branch phases of the harmonic balance solution are measured.

source
JosephsonCircuits.planck_constant Constant
julia
const planck_constant

The Planck constant h, 6.62607015e-34 J*s.

source
JosephsonCircuits.reduced_planck_constant Constant
julia
const reduced_planck_constant

The reduced Planck constant hbar = h/(2*pi) in J*s.

source
JosephsonCircuits.speed_of_light Constant
julia
const speed_of_light

The speed of light in vacuum, 2.99792458e8 m/s, the default phase velocity of a TransmissionLine.

source
JosephsonCircuits.AbstractComponent Type
julia
AbstractComponent

The supertype of the component models of the typed circuit representation. A component is a concrete struct holding its data; behavior is given by methods such as nterminals and hasports in circuit/parse.jl. A Circuit with an Interface is also a component.

source
JosephsonCircuits.AbstractDCModel Type
julia
AbstractDCModel

The supertype of the zero frequency models a ScatteringParameters may declare, written as dcmodel.

ScatteringLimit() (the default) evaluates the block's own scattering data at zero frequency. OpenDC, ShortDC, ThroughDC and ScatteringDC state it instead.

source
JosephsonCircuits.AbstractFactorization Type
julia
AbstractFactorization

A sparse factorization method. A concrete method f implements factorize(f, A), which computes a factorization of A (the symbolic analysis and the first numeric factorization), and refactorize!(f, F, A), which refactorizes A into the existing F reusing its symbolic analysis and returns F, or nothing when the method has no in place refactorization.

The methods are KLUfactorization, LUfactorization, QRfactorization, CUDSSFactorization and BlockFactorization.

source
JosephsonCircuits.AbstractHBNonlinearSolver Type
julia
AbstractHBNonlinearSolver

A method of solving the operating point, the method of hbnlsolve and hbsolve: NewtonKrylov, Newton, QuasiNewton, Staged or ExternalSolver.

source
JosephsonCircuits.AbstractMatrixProvider Type
julia
AbstractMatrixProvider

The supertype of the sources of frequency dependent matrix data: the scattering parameters and noise covariance of a ScatteringParameters and the X and Y matrices of a GaussianChannel. A provider implements evaluateprovider! and providersize. Its data lives in the shared component definition and is never copied per instance.

source
JosephsonCircuits.AbstractModeCoupling Type
julia
AbstractModeCoupling

The mode coupling family of AbstractPreconditionerSpec: the Jacobian with its mode coupling restricted to a selected set and reduced to the mode diagonal elsewhere, factorized; see ModeCouplingPreconditioner. Each member carries the AbstractFactorization it is built with in its factorization field, nothing for the backend's default (KLU on the host, cuDSS on a device).

source
JosephsonCircuits.AbstractPortTermination Type
julia
AbstractPortTermination

The supertype of the external environments a Port may own. A termination is the source and load the port sees looking outward, which is distinct from the reference impedance the port normalizes its waves to, even where the two are numerically equal.

source
JosephsonCircuits.AbstractPreconditioner Type
julia
AbstractPreconditioner

Supertype of the preconditioners of nlsolvekrylov!. A preconditioner pc approximates the Jacobian of the nonlinear system by something which can be inverted cheaply, and must implement two methods:

  • updatepreconditioner!(pc, x): rebuild pc at the point x,

  • applypreconditioner!(z, pc, r): overwrite z with inv(P)*r.

The Jacobian itself is never required, only its approximation, so the nonlinear solve stays matrix-free. See ModeCouplingPreconditioner for the harmonic balance Jacobian with its mode coupling restricted, and FloquetPreconditioner for that wrapped in a deflation subspace.

The rest of the interface is hooks the driver calls with an inert default, which a preconditioner implements when it has something to say:

hookdefaultwho implements it
pointmoved!(pc)nothinga deflation, whose pair goes stale
stalled!(pc)nothingClusters, which remeasures
escalatepreconditioner!(pc)falsemode coupling, a deflation deferring it
harvest!(pc, ws, out)nothinga deflation
usescycleharvest(pc), harvestcycle!(pc, ws, j)false, nothinga deflation reading every cycle
seeddeflation!(pc, X; ...)nothinga deflation taking physical candidates
isexactpreconditioner(pc)falsean exact factorization
deflationsize, candidatecount, deflationrebuilds, deflationproducts0, 0, 0, 0a deflation

A preconditioner which wraps another subtypes AbstractWrappedPreconditioner and defines innerpreconditioner; every hook it does not implement itself is then forwarded to the inner one, so that wrapping never silently turns a hook off.

source
JosephsonCircuits.AbstractPreconditionerSpec Type
julia
AbstractPreconditionerSpec

How the Newton-Krylov solver preconditions its linear solves: one of the mode coupling family, BlockDiagonal, FullJacobian, HarmonicBand, MeasuredBand, Clusters, CoupledModes and CouplingMask, each built with a factorization, Automatic, which picks among them by the problem and the memory, or Floquet, a deflation wrapping one of them. The solver builds the runtime preconditioner from the value.

source
JosephsonCircuits.AbstractStageInfo Type
julia
AbstractStageInfo

The supertype of every per-stage diagnostic record stored in the stages vector of a SolverInfo. Each solver contributes its own concrete record type instead of adding fields to a shared struct: IterationInfo for the Newton family (with the Krylov linear-solve records where the solver is nlsolvekrylov!), StagedStageInfo for the source continuation driver, and future methods add their own. Every record follows three field conventions so generic reporting works across methods – label::String, converged::Bool and iterations::Int – and everything else belongs to the record type itself.

source
JosephsonCircuits.AbstractTransientIntegrator Type
julia
AbstractTransientIntegrator

The time stepping rules transientsolve chooses between, Trapezoidal, GaussLegendre and BackwardEuler.

source
JosephsonCircuits.AbstractWrappedPreconditioner Type
julia
AbstractWrappedPreconditioner

A preconditioner which wraps another and presents it in different coordinates, at a different size or under a correction. Subtypes define innerpreconditioner and their own updatepreconditioner! and applypreconditioner!; every other hook of the interface forwards to the inner preconditioner unless the wrapper defines it, so escalation, deflation and its diagnostics reach the inner one through any number of wrappers. A wrapper which changes coordinates must define the hooks whose arguments carry vectors of its own coordinates (harvest!, harvestcycle!, seeddeflation!) if the inner preconditioner reads them in its own.

source
JosephsonCircuits.Always Type
julia
Always()

Rebuild the preconditioner before every Newton step: the default, and the policy whose solve path depends on nothing measured, so that the same problem solves the same way every time. Probe measures whether a rebuild pays and skips the ones which do not.

source
JosephsonCircuits.AndersonState Type
julia
AndersonState(x::AbstractVector, depth::Integer)

Preallocated state for Anderson acceleration of the Newton fixed point iteration G(x) = x + deltax: the difference history, the previous iterate/update pair it is built from, the assembled correction vector, and the buffers for the extrapolation least squares problem.

The history lives in fixed n×depth matrices with circular column indexing. andersonhistory! overwrites one column per recorded step and updates the indices. All access to the history columns is through age-ordered indices, so results are independent of the physical column layout.

source
JosephsonCircuits.Automatic Type
julia
Automatic()

The preconditioner chosen when it is built, by the number of tones and the memory the factors would take:

  • one tone: FullJacobian with the backend's sparse factorization, whatever the memory;

  • two or more tones: FullJacobian with a single precision BlockFactorization when its factors, sized exactly from the symbolic analysis by blockfactorbytes, take at most half the free memory of the backend (freememory), leaving the rest to the system, the Krylov basis and the products; otherwise MeasuredBand with the backend's sparse factorization.

The choice looks at nothing else, neither the mixing order of the tones nor the circuit's topology, so that it generalizes. On one tone the full Jacobian's sparse factors give one Krylov iteration per Newton step where the block diagonal needs many, and no escalation; they are taken without sizing them first, since they grow with the square of the mode count and one tone keeps it low, and a problem too large for them wants an explicit BlockDiagonal. See resolveautomatic.

source
JosephsonCircuits.Backtracking Type
julia
Backtracking(; interpolate = true, safeguardlow = 0.1,
    safeguardhigh = 0.5, c1 = 1e-4, maxbacktracks = 10, maxfailures = 2)

Armijo backtracking along the step, the line search of every method. A trial which meets the Armijo condition with constant c1 is accepted; otherwise the step is shortened and retried, at most maxbacktracks times, and maxfailures consecutive steps which return the best decreasing trial rather than an Armijo step are a stall.

interpolate chooses how the step is shortened. Interpolating fits the merit function along the step, a quadratic through the full step for the first proposal and a cubic through the two latest trials for each one after, and clamps every proposal to [safeguardlow, safeguardhigh] of the trial before it; it suits an exact step, whose usable length is a particular number. Halving makes no fit: the first backtrack is to half the step and each later one multiplies it by safeguardhigh, so only that safeguard acts; it suits an inexact step, which is perturbed enough that a power of one half lands acceptably. Halving ends a hopeless solve by itself, since its coarse trials soon fail the Armijo condition, where interpolation always finds a step short enough to meet it and leaves the ending to the stall rule (residualstalled).

safeguardlow bounds how far one interpolated trial may cut. A Newton step in NewtonKrylov refreshes the preconditioner and a backtrack does not, so too deep a cut buys fewer trials at the price of more steps.

source
JosephsonCircuits.BackwardEuler Type
julia
BackwardEuler()

Backward Euler on the flux and on its rate: first order and strongly damping, a deliberately dissipative reference for checking that a result does not depend on the stepping rule.

source
JosephsonCircuits.BathLadder Type
julia
BathLadder

One ladder of the pump of a pumped block over a transient's bath frequencies: the family (rows, cols, K) of the signed frequencies on it (see pumpedfamily), and the bath frequencies whose positive and whose negative mode it holds, by their index among the frequencies of the calculation. A pair of bath frequencies has a normal term when both their positive modes are on one ladder and an anomalous one when the positive mode of one and the negative mode of the other are, so a ladder carries exactly the pair terms of the frequencies it holds.

source
JosephsonCircuits.BlockDiagonal Type
julia
BlockDiagonal(; factorization = nothing)

The mode block diagonal: one small independent factorization per mode, and no coupling. Cheap, and sufficient for weak drives; on a strongly pumped device it stalls and is grown to the full Jacobian by escalation. Its factors grow linearly with the mode count where the full Jacobian's grow with its square, so this is the setting for a one tone problem too large for the full Jacobian Automatic picks.

source
JosephsonCircuits.BlockFactorization Type
julia
BlockFactorization(singletons = nothing; precision = nothing, refine = true)

The AbstractFactorization of a ModeCouplingPreconditioner by dense blocks over the circuit graph rather than by a scalar sparse solver, and, handed a sparse matrix with a block size, of the linearized solve.

The harmonic balance Jacobian has two structures: its sparsity follows the circuit graph, and every nonlinear connection carries a dense coupling between harmonic modes. A scalar sparse solver sees only their product and rediscovers the circuit's block structure, entry by entry, in its symbolic analysis. This factorization eliminates the circuit graph instead, treating every circuit node as a supernode whose block holds the real-layout slots of all retained modes at that node: the nodes are ordered by KLU's analysis of the circuit-node graph (block triangular form, then a fill reducing ordering), amalgamated along the elimination tree into supernodes of a few hundred rows, and eliminated with pivoted dense LU on the diagonal blocks, dense products for the Schur updates and dense matrix-vector products for the solves. The blocks are assembled on the backend straight from the Fourier coefficients with realstructureentry, the same per entry value the sparse assembly uses, so no sparse Jacobian is ever formed. The structure comes from the circuit graph alone, whatever the circuit is.

The same specification serves two operators. Handed a BlockJacobian it factorizes the preconditioner's mode clusters over the circuit graph, as above; handed a SparseMatrixCSC with a blocksize (see factorize) it builds a SparseBlockFactorization, the direct solve of the linearized system in dense node blocks, batched over the frequencies of a device sweep, with precision then meaning the precision of the factors of a double matrix (equilibrated and refined when single).

The coupling set of the preconditioner is honored at the level of its clusters: the retained coupling graph of the modes is split into its connected components, every component of two or more modes becomes one block factorization over the circuit graph restricted to those modes' slots, and the modes left single are solved by the mode block diagonal as before. FullJacobian is therefore one factorization of the complete Jacobian, an exact solve; a mask made of complete clusters (as Clusters produces) is one factorization per cluster; and a coupling set which is not a union of complete clusters, a HarmonicBand say, is factorized on its closure, which keeps at least every coupling the set asked for.

Measured on a three tone line of 128 junctions with 527 modes on a GPU, the single precision factorization of the complete Jacobian takes 0.4 s and 2.8 GB against 2.6 s and 10.5 GB for cuDSS on the measured band, converges the linear solves in three Arnoldi steps against 85, and solves the nonlinear problem in 3.2 s against 38.5 s; clusters halve the memory again at 18 steps. Factor storage grows as the square of the number of retained slots per node and the arithmetic as its cube, which is what bounds it.

singletons is the sparse AbstractFactorization of the block diagonal of the modes left single, the backend's default (KLU on the host, cuDSS on a device) when nothing. precision is the floating point type of the blocks, that of the preconditioner when nothing: Float32 is the mixed precision form, which halves the storage and is two to four times faster on a GPU at three outer steps per solve while the iteration stays in double precision.

The block factorization does not pivot across its supernodes. A supernode whose diagonal block is singular, which happens when a node's stiffness at some mode frequency lives entirely in a promoted branch current and its own elements resonate there, stops it with a SingularException; the mode coupling preconditioner then falls back to the backend's sparse factorization of the same coupling set (see refactorize!).

refine concerns the linearized solve: single precision factors of a double system refine their solutions against the double residual to double accuracy by default; refine = false leaves them single precision solutions computed entirely in single precision, equilibrated, with no refinement, for the cases where single precision scattering parameters suffice (about 1e-2 of the largest element of S on strongly resonant multi-tone lines, 1e-3 on a plain chain) at four to five times double's speed on a device whose single precision rate far exceeds its double one. The outputs are returned in double either way.

source
JosephsonCircuits.BlockJacobian Type
julia
BlockJacobian

The operator a BlockFactorization factorizes: a BlockStructure and the Fourier coefficients of cos(phi(t)) at the current point. Handed to tryfactorize! in place of a sparse matrix.

source
JosephsonCircuits.BlockLU Type
julia
BlockLU

The factors of a batched block LU over a symbolic structure: the supernodes' diagonal blocks, panels and explicit inverses, each (rows, columns, nb), the Schur updates between them and the work blocks. Allocated by blocklu from a clustersymbolic structure, factorized in place by blocklu! once its blocks hold values, and applied by substitute!.

Fields

  • N, nb, n: supernodes, batch, order.

  • perm, range, rowidx: the elimination order (position in the factorization to natural slot) and each supernode's positions and panel rows.

  • D, L, U, Dinv: the blocks; after blocklu!, L is scaled by the inverse and Dinv holds it.

  • tasks, scratch: the Schur updates of each supernode and the work blocks by size.

source
JosephsonCircuits.BlockModulation Type
julia
BlockModulation

One modulated output of a pumped block realized in time: the output matrix C over the block's states of the cosine (quadrature = 1) or sine (quadrature = 2) filter of the harmonic k, whose output the reflected wave carries multiplied by 2 cos(k wp t) or -2 sin(k wp t) and by the block's envelope.

source
JosephsonCircuits.BlockStructure Type
julia
BlockStructure

What a ModeCouplingPreconditioner holds in place of a sparse structure when its factorization is a BlockFactorization: the block factorizations of the mode clusters, the mode block diagonal for the modes left single (nothing when there are none), the assembly ingredients on the backend, work vectors in the factorization's precision, and the backend together with the mode count, Rbnm and the branch count the junction pair table is rebuilt from when the system is rebound (refreshvalues!).

source
JosephsonCircuits.BoundCircuit Type
julia
BoundCircuit

A CompiledCircuit with its component values resolved to numbers, grouped by kind.

Each group is a concrete vector in the compiled group order, so capacitors[k] is the value of the component at flat index circuit.capacitors[k]. Element types are chosen per group exactly as the matrix assembly chooses them, so a lossy capacitance does not make the resistances complex.

Fields

  • circuit: the CompiledCircuit.

  • capacitors, resistors, inductors, junctions, mutualinductors: the values of each group, in the compiled group order. The current sources and the nonlinear inductors are read from values by the assembly, so they have no group here.

  • values: the flat component table, resolved to numbers.

source
JosephsonCircuits.BranchStampPlan Type
julia
BranchStampPlan

The branch each component of a group occupies, and where it lands in the branch vector.

nzind is the sorted list of branches the group touches and dest[k] is the position of group member k within it. Two components on one branch share a destination and are folded together in the order they appear, which is the order the coordinate form combined them.

The branch of a component is a dictionary lookup on its node pair, and there is one per component per assembly; doing it once is most of what this plan saves.

source
JosephsonCircuits.CUDSSFactorization Type
julia
CUDSSFactorization(; precision = nothing, kwargs...)

An AbstractFactorization backed by NVIDIA's cuDSS direct sparse solver, for use on a GPU.

precision is the floating point type the factors are held and the triangular solves run in, nothing for the iteration's own. It is a setting of a NewtonKrylov preconditioner: the factors of a preconditioner need only make the Krylov solve converge, so Float32 halves their memory and runs them at a device's single precision rate, the preconditioner assembling its matrix in that precision and converting the residual and the correction around each solve. Such a preconditioner is not exact, and a Krylov solve it fails is escalated to the same factors in the iteration's precision (escalatepreconditioner!). A direct solve factorizes in the precision of its iteration and refuses a factorization asking for another. cuDSS is the only factorization here which honours a precision; KLU and UMFPACK factorize in double whatever they are handed.

Requires CUDSS.jl and CUDA.jl to be loaded; without them the returned factorization raises an informative error when used, so the constructor itself is always available and a script can select it unconditionally. Nothing else in the solver changes: AbstractFactorization already separates factorize (the symbolic analysis and the first numeric factorization) from refactorize! (a numeric refactorization reusing the analysis), which is exactly the split cuDSS wants.

That split is what makes this worth doing. The symbolic analysis depends only on the circuit topology and the retained mode coupling, neither of which changes across Newton steps, while the values change at every step; the analysis is almost all of the cost of a factorization and is paid once.

cuDSS is handed the whole matrix, block diagonal or not: it discovers the independent blocks of a mode block diagonal itself and works on them together, and measured faster that way than when handed the blocks as a uniform batch.

source
JosephsonCircuits.CallableMatrixProvider Type
julia
CallableMatrixProvider(f, n, form = :matrix)

A matrix provider which evaluates the callable f at each requested angular frequency for an n by n matrix. form says how f is called: :matrix (f(w) returns a fresh n by n matrix, the natural way to write a block by hand and the default), :inplace (f(dest, w) writes into one, which matters when the same provider is evaluated many thousands of times), or :entry (f(p, q, w) returns S[p, q], the only form a kernel can call and so the one which lets a callable block be evaluated on a backend); see CALLABLE_FORMS.

source
JosephsonCircuits.CanonicalJacobianPlan Type
julia
CanonicalJacobianPlan

The canonical Jacobian's pattern and the fixed arithmetic which fills it.

Fields

  • J: the pattern, and the buffer the values are written into.

  • source: for each stored entry of the internal Jacobian, where it lands, or zero when it lands in a row a reference replaces.

  • fixedindex, fixedvalue: the direct current block's constant entries, including the single one of each reference row.

See canonicaljacobianplan and canonicaljacobian!.

source
JosephsonCircuits.CanonicalPreconditioner Type
julia
CanonicalPreconditioner(inner, work::CanonicalWork)

An internal coordinate preconditioner presented in canonical coordinates.

The mode blocks the inner preconditioner is built from include the zero frequency mode, so it is applied where it was built, on the internal block of the canonical vector through internalpart, with no copy and no permutation, rather than the preconditioner being rederived. That is exact, and it keeps the two paths taking the same iterations.

source
JosephsonCircuits.CanonicalWork Type
julia
CanonicalWork

The workspaces a canonical evaluation needs, and the direct current block when it is explicit.

Fields

  • layout: the CompositeLayout the canonical state is written in.

  • xint, Fint: an internal state and an internal residual, for the interfaces which need one of their own; the solve reads and writes the internal block of the canonical vector in place.

  • transport: the transport rows, or nothing when there is no explicit block.

  • blockrows: the scattering blocks' own zero frequency rows, or nothing.

  • dwork: the resistor current the coupling drives into the nodes.

  • nnodaldc: where the zero frequency entries split. The first are the zero frequency flux of each node, which the transport coupling drives; any after them belong to auxiliary branch currents, which it does not.

  • pinning: the reference rows, or nothing. See DCPinning.

  • dcindex, dclocal: the canonical positions of the direct current subsystem's unknowns, and the same positions local to the window.

  • window: the canonical positions of the window, on the backend the state is on, for the gather and the scatter.

  • Fwindow, uwindow: the window itself, on that backend.

  • update: the block in its matrix form, where the state lives, or nothing on the host and when there is no explicit block, where the scalar walk of addtransportwindow! is already the cheaper of the two.

source
JosephsonCircuits.Capacitor Type
julia
Capacitor(C; temperature = nothing)

A two terminal linear capacitor with capacitance C in Farads. Terminals are 1 and 2. The value may be a number or a symbolic variable.

temperature is the physical temperature in Kelvin, which sets the noise a lossy instance adds; a lossless one adds none. nothing, the default, takes the temperature the analysis is run at.

Examples

julia
julia> Capacitor(100e-15)
Capacitor{Float64}(1.0e-13, nothing)

julia> Capacitor(100e-15; temperature = 4.0).temperature
4.0
source
JosephsonCircuits.Circuit Type
julia
Circuit(components, connections, interface = nothing;
    pins = nothing, ports = nothing, validate = true)

The public typed circuit representation.

  • components associates unique instance identifiers (symbols, strings, or integers) with component models, typically as a vector of pairs.

  • connections describes which component endpoints are electrically connected, as groups (tuples of endpoints on one net), pairs (port to port bonds), and Net entries.

  • interface optionally exposes pins and ports so that the circuit can be used as a component inside another circuit.

The pins and ports keywords are sugar for the positional interface: Circuit(components, connections; pins = ..., ports = ...) is Circuit(components, connections, Interface(pins = ..., ports = ...)). Give the interface one way or the other, not both.

The constructor validates identifiers, endpoint references, connector namespaces, and the interface, so that errors point at the construction site, but stores the collections exactly as given: no data is copied, and a thousand instances of one subcircuit hold a thousand references to the same object. Use elaborate to flatten the hierarchy.

Endpoint grammar

writtenmeaning
(:inst, k)scalar terminal or pin k in a group; port k in a pair
(:inst, p, t)terminal t (1 signal, 2 reference) of port p
Groundthe global reference net "0"
(:gnd, 1) with :gnd => Ground()the same reference net, component style
PortRef/PinRefexplicit namespace selection

In a group every endpoint is scalar. In a pair a => b, endpoints resolve in the port namespace of components which expose ports, and the pair expands to signal-to-signal and reference-to-reference groups; components without ports fall back to scalar endpoints, making a pair of scalar endpoints sugar for a two element group. A key which exists both as a pin and as a port of a subcircuit is an error in a pair and requires PortRef or PinRef.

Connection groups may be written as tuples or vectors of endpoints. Vectors are recommended for large or generated groups: a vector is one type whatever its length, where every distinct tuple shape is a separate type for the compiler to specialize on.

Examples

julia
circuit = Circuit(
    [:l1 => Inductor(1e-9), :c1 => Capacitor(100e-15), :p1 => Port(1)],
    [[(:p1, 1), (:l1, 1)],
     [(:l1, 2), (:c1, 1)],
     [(:c1, 2), (:p1, 2), Ground]],
)
source
JosephsonCircuits.Circuit Method
julia
Circuit(netlist::AbstractVector, circuitdefs::AbstractDict)

Construct a typed Circuit from a legacy tuple netlist. Each entry is (name, node1, node2, value) and the component type is taken from the prefix of name: Lj (Josephson junction), NL, L, C, K (mutual inductor, whose "nodes" are the two inductor names), I, R, and P (port, whose value is the port number). Only this adapter reads a name prefix; typed component models never infer behavior from an instance name. The one argument Circuit(netlist) reads a legacy netlist the same way when its entries end in values rather than typed components.

Node labels become net names, so compile of the result gives the same tables the tuple netlist always produced. A port's reference impedance is the value of the single resistor placed across it, which the adapter records as the port's LegacyTermination. When circuitdefs is given, values are resolved with valuetonumber during conversion; otherwise they pass through unchanged and circuitdefs is given to the analysis as usual.

Examples

julia
julia> Circuit([("P1","1","0",1),("R1","1","0",50.0),("C1","1","0",1e-12)]) isa Circuit
true
source
JosephsonCircuits.Circuit Method
julia
Circuit(netlist::AbstractVector; pins = nothing, ports = nothing)

Construct a Circuit from a netlist: a vector of entries (name, nodes..., component), one per component instance, each listing the node of every terminal in terminal order, as a SPICE netlist does.

  • name is the instance identifier, a Symbol or a string.

  • The nodes are integers, strings or symbols. Node 0 (or "0") is ground. Every entry naming a node joins its net, and the nets carry the node names.

  • component is a typed component model, and the entry lists one node per terminal in terminal order: two for a lumped element or a port; for a ScatteringParameters block the signal and reference terminal of each port in turn, or the signal terminal alone when the block is grounded; for a subcircuit Circuit one per interface pin, in the order the pins were declared.

  • A MutualInductor has no terminals. Its entry names the two inductors it couples in place of nodes, and the component is written MutualInductor(K).

pins and ports declare an interface as they do for the connection-group form, so a netlist can define a subcircuit.

The netlist is the connection-group form with the groups written out by node, and builds exactly that: the components in netlist order and one named connection group per node. What the connection-group form expresses beyond a node list, such as the bundled port views of pair connections, is written in that form.

A vector of entries carrying numeric values under type-prefixed names, ("C1", "1", "0", 1e-12), is the legacy tuple netlist, which this method reads through the adapter of Circuit(netlist, circuitdefs).

Examples

julia
julia> circuit = Circuit([
           (:p1, 1, 0, Port(1; Z0 = 50.0)),
           (:cc, 1, 2, Capacitor(100e-15)),
           (:jj, 2, 0, JosephsonJunction(1000e-12)),
           (:cj, 2, 0, Capacitor(1000e-15))]);

julia> compile(circuit).nodenames
3-element Vector{String}:
 "0"
 "1"
 "2"
source
JosephsonCircuits.CircuitGraph Type
julia
CircuitGraph(edge2indexdict, Rbn, searray, cearray, glearray, lvarray,
    isolatednodes, gl, Nbranches)

The graph of the branch carrying components of a circuit, as computed by calccircuitgraph.

Fields

  • edge2indexdict: maps a branch (node1, node2) in either orientation to its branch index, the row of Rbn it occupies.

  • Rbn: the sparse oriented incidence matrix, Nbranches by Nnodes - 1; the ground node column is omitted.

  • searray: the edges of the spanning tree, as (node1, node2) tuples.

  • cearray: the closure branches, the edges not in the spanning tree.

  • glearray: all edges, spanning tree first and closure branches after.

  • lvarray: for each closure branch, the vertices of the loop it closes through the spanning tree (empty for a loop of only two vertices). Empty altogether when calccircuitgraph was called with loops = false.

  • isolatednodes: nodes which appear in the graph but have no branch to any other node.

  • gl: the undirected Graphs.SimpleGraph of all branches.

  • Nbranches: the number of branches, size(Rbn, 1).

source
JosephsonCircuits.CircuitMatrices Type
julia
CircuitMatrices(Cnm::SparseMatrixCSC, Gnm::SparseMatrixCSC, Lb::SparseVector
    Lbm::SparseVector, Ljb::SparseVector, Ljbm::SparseVector,
    Mb::SparseMatrixCSC, invLnm::SparseMatrixCSC,
    Rbnm::SparseMatrixCSC{Int, Int}, portindices::Vector{Int},
    portnumbers::Vector{Int}, portimpedances::Vector,
    portenvironmentindices::Vector{Int},
    noiseportimpedanceindices::Vector{Int}, Lmean, vvn)

The matrices of a compiled circuit at a given mode count: the capacitance, conductance and inverse inductance matrices in the node basis, the inductance vectors in the branch basis, the mutual inductance matrix, the incidence matrix, the port data, and the resolved component values. Built by numericmatrices and symbolicmatrices.

Fields

  • Cnm: the capacitance matrix in the node basis with each element duplicated along the diagonal Nmodes times.

  • Gnm: the conductance matrix in the node basis with each element duplicated along the diagonal Nmodes times.

  • Lb: vector of branch linear inductances.

  • Lbm: vector of branch linear inductances with each element duplicated Nmodes times.

  • Ljb: vector of branch Josephson junction inductances.

  • Ljbm: vector of branch Josephson junction inductances with each element duplicated Nmodes times.

  • Mb: the mutual inductance matrix in the branch basis.

  • invLnm: the inverse inductance matrix in the node basis, with each element duplicated along the diagonal Nmodes times. It excludes the mutually coupled inductor branches, which the solvers represent with auxiliary branch current variables (see circuit/mna.jl).

  • Rbnm::SparseMatrixCSC{Int, Int}: incidence matrix to convert between the node and branch bases.

  • portindices::Vector{Int}: vector of indices at which ports occur.

  • portnumbers::Vector{Int}: vector of port numbers.

  • portimpedances::Vector: the reference impedance of each port, ordered by port number. This is what the waves are normalized to, and it is defined for every port whether or not the port owns an environment.

  • portenvironmentindices::Vector{Int}: vector of indices at which the port owned environments occur, ordered by port number, with zero for a port which owns none.

  • noiseportimpedanceindices::Vector{Int}: vector of indices at which resistive elements other than port impedances occur, for noise calculations.

  • Lmean: the mean of the linear and Josephson inductances, zero when the circuit has none; the solvers replace it by the solver scale of calcsolverscale under the same name.

  • vvn: the vector of component values with the definitions substituted.

source
JosephsonCircuits.CircuitMatrixPlan Type
julia
CircuitMatrixPlan

Everything about a circuit's matrices which depends on its topology but not on its values, for one mode count.

Holds the nodal and branch stamp plans, the orientation of each mutual coupling and the mode expanded incidence matrix. Rebinding at new component values reuses all of it; only the values are refilled. See circuitmatrixplan and assemblematrices.

mutualorientations is the sign which carries each coupling from the terminal order the netlist declared to the orientation the graph gave its two branches (see mutualorientations). It depends on the topology and the declared terminal order alone, so a refill reads it rather than the incidence matrix.

source
JosephsonCircuits.CircuitValue Type
julia
CircuitValue

The package's own expression type for a component value written in terms of parameters: a parameter, a constant, a unary or binary operation on them, or a frequency dependent provider. Built by arithmetic on the parameters of @params and resolved to a number by valuetonumber with the definitions in circuitdefs.

source
JosephsonCircuits.ClusterBlocks Type
julia
ClusterBlocks

The block factorization of one cluster of modes over the circuit graph: the BlockLU of the supernodes, the natural slots its blocks are assembled from, and the work arrays of a solve. Built by clusterblocks, assembled by assembleblocks!, factorized by blocklu! and applied by clustersolve!.

source
JosephsonCircuits.ClusterProbe Type
julia
ClusterProbe

The state of a Clusters request: the block diagonal preconditioner the probe solves with, the probe vector and its per mode norms, the probed strength matrix W, the couplings taken so far and the current cluster mask, and the flag stalled! raises to remeasure. See probecouplings! and spectralclusters.

source
JosephsonCircuits.Clusters Type
julia
Clusters(; factorization = nothing)

Clusters of modes measured from the operator: the block Jacobi coupling strengths are probed and modes merged in decreasing strength until the couplings left between clusters are contractive; see spectralclusters. Probed at the first point and again whenever the solver reports a slow linear solve; the clusters only grow within a solve. With a BlockFactorization each cluster is one dense block factorization over the circuit graph, which halves the memory of FullJacobian on three tones.

source
JosephsonCircuits.ColumnEquilibration Type
julia
ColumnEquilibration

The column scaling of the system matrices of one direction of a batch.

cuDSS chooses its pivots within the blocks its ordering fixes, by the size of the candidates, so the units the unknowns are written in decide which candidates it can tell apart. The columns of the linearized system as assembled vary in size with the elements which meet a node and with the frequency of the column's mode, so each system of a batch is scaled here: every column is divided by its largest entry, which makes the pivot candidates of every column comparable, and the solution is divided by the same scale on the way out. cuDSS's matching, which permutes and scales the matrix ahead of the factorization, is not supported for a uniform batch.

Fields

  • order, segptr: the stored entries of the matrix the solver is handed, grouped by its column, so one work item owns a column and no two write the same scale.

  • scale: the scale of each column of each system of the batch.

source
JosephsonCircuits.CompiledCircuit Type
julia
CompiledCircuit

An elaborated circuit lowered to a flat table of two terminal components, with index groups by component kind.

Fields

The flat table, in elaboration order:

  • componentnames: the hierarchical instance path of each entry. A matched port's own termination is the entry named "<port path>/termination".

  • componenttypes: the type symbol of each entry: :C, :R, :L, :Lj (a sinusoidal NonlinearInductor), :I, :K (a mutual inductor) or :P (a port).

  • componentvalues: the value of each entry as written; the reference impedance for a port.

  • nodeindices: a 2 by ncomponents matrix of the node indices of each entry, ground being node 1; both zero for a mutual inductor.

  • junctioncprs: the PolynomialCPR of each :Lj entry whose current-phase relation is not the sinusoidal Josephson one. Empty for every circuit which does not ask for another, and the solvers then evaluate sin and cos as they always did.

  • componenttemperatures: the temperature of each entry which states one, keyed by flat index.

  • mutualinductorbranchnames: the names of the coupled inductors, two per :K entry in order.

  • nodenames, Nnodes: the node names in sorted order (ground first) and their count.

  • componentnamedict: component name to flat index.

The groups, each a vector of flat indices in table order:

  • capacitors, resistors, inductors, junctions (:Lj), currentsources, mutualinductors.

The records which keep their own structure:

  • ports::Vector{CompiledPort}, in elaboration order.

  • scatteringblocks::Vector{CompiledScatteringBlock}, one per block instance.

See compile.

source
JosephsonCircuits.CompiledPort Type
julia
CompiledPort

An analysis port and the environment it owns.

environment is the flat table index of the port's own termination, or 0 when the port owns none. It is recorded here when the port is compiled, so nothing downstream needs to look for a resistor on the port's branch, and a port may share its terminals with any number of ordinary device resistors.

The reference impedance is not stored here: it is the value of the port's own entry in the flat component table, at component, so it is bound like every other value and read from the bound table by portreferenceimpedances.

source
JosephsonCircuits.CompiledScatteringBlock Type
julia
CompiledScatteringBlock

A multiport ScatteringParameters instance after compilation: its definition, its instance path, and the node of the signal and reference terminal of each port, signalnodes[p] and refnodes[p]. A block has no entries in the flat component table.

source
JosephsonCircuits.ComponentNotSupportedError Type
julia
ComponentNotSupportedError(msg)

An exception thrown when a component in the typed circuit representation parses, validates, and elaborates successfully but is not yet supported by the numerical solvers.

source
JosephsonCircuits.ComponentPerturbation Type
julia
ComponentPerturbation

The derivative of the scaled equations of a TransientProblem with respect to a relative perturbation p -> r*p at r = 1 of the value of each of a set of named components, which the tangent and the adjoint of a recorded transient carry as directions and objectives of their own (see transientsensitivity). The equations are affine in C, 1/R, 1/L and 1/Lj, so the derivative is the component's own contribution to each matrix, with a sign, as SensitivityStamp has it for the linearized solve, built from the same classification (componentstamp) so that the two solvers support the same components and reject the same ones. A component which is a port's own termination moves the port's reference impedance and conductance with it, as the linearized solve has it, which enters the port waves directly (see directcoefficients).

Fields

  • names: the component names, in the order of the directions.

  • entries, hostentries: the derivatives as their stored entries, one PerturbationEntries per kind on the backend and on the host, which the adjoint contracts its multipliers against; a component touches a few entries, so the contraction and its work are the size of the entries, not of the state times the components.

  • forcing: for a tangent, the derivatives of the scaled capacitance, conductance, stiffness and junction current of every component stacked, dC, dG, dL, dJ on the backend with rows (c - 1)n + 1 to cn holding component c's, so one product gives every component's forcing at once, and hdG, hdL, hdJ on the host for the endpoint of a Gauss-Legendre step; the tangent's directions are dense right hand sides in any case. nothing for an adjoint, which never forms them.

  • states: whether any component reads the state; the junctions alone read only the phases the record always holds.

  • ports: the compiled port whose termination each component is, the row of its trace, or zero.

source
JosephsonCircuits.CompositeLayout Type
julia
CompositeLayout

The canonical state layout, [internal | vdc], and where the zero frequency entries of the internal state are.

Fields

  • rdim: the length of the internal real state, which is the first block.

  • ndc: the number of zero frequency entries in it: one per node and one per auxiliary unknown, in internal order.

  • nvdc: the length of the explicit voltage block, which follows. Zero until a circuit injects direct current.

  • dcpos: for the kth zero frequency entry, its position in the internal state.

The direct current window is the ndc + nvdc entries the block reads and writes: the zero frequency entries first, then the voltages. Window entry k sits at canonical position windowindex(L, k).

See compositelayout.

source
JosephsonCircuits.ConjugateSymmetry Type
julia
ConjugateSymmetry()

The default negative frequency rule for scattering and covariance providers: data is evaluated at the absolute value of the requested frequency and conjugated for negative frequencies, imposing S(-ω) = conj(S(ω)). This is uniformly safe for tabulated positive-frequency data and for user callables.

source
JosephsonCircuits.ConstantMatrixProvider Type
julia
ConstantMatrixProvider(A)

A frequency independent matrix provider wrapping the matrix A.

source
JosephsonCircuits.CoupledLinesBasis Type
julia
CoupledLinesBasis(ZC, TI, TV, theta, U, lambda, S)

A simple structure to hold the output of ZC_basis_coupled_tlines.

source
JosephsonCircuits.CoupledModes Type
julia
CoupledModes(indices; factorization = nothing)

Exactly these modes coupled in full, the rest on the mode diagonal; see modecouplingmask.

source
JosephsonCircuits.CouplingMask Type
julia
CouplingMask(mask; factorization = nothing)

The couplings selected by an Nmodes by Nmodes Bool matrix, the block coupling column mode m2 into row mode m1 kept where mask[m1, m2].

source
JosephsonCircuits.CurrentSource Type
julia
CurrentSource(I)

A two terminal current source with current I in Amperes flowing from terminal 1 to terminal 2 through the source. The value is typically a symbolic variable whose numerical value is supplied through circuitdefs or through the analysis sources.

source
JosephsonCircuits.DCAugmentation Type
julia
DCAugmentation

The explicit direct current block of an HBNonlinearProblem.

Fields

  • work: the CanonicalWork holding the layout, the transport rows and the blocks' zero frequency rows.

  • jplan: the CanonicalJacobianPlan, or nothing when no Jacobian was assembled.

  • jint: the internal Jacobian the plan reads, or nothing.

  • keep: the diagonal D over the direct current window: one where a row is added to and zero where the block replaces it.

  • constant: the block's drive dependent constant, at the drive the problem was built with.

  • dcmatrix: the transpose of the block's constant matrix M, restricted to the window, which is what the transposed product needs.

  • scale: the drive scale, kept in step with setdrive!.

  • dwork, Fwork, zwork: workspaces for the transposed product.

source
JosephsonCircuits.DCBlockDescriptor Type
julia
DCBlockDescriptor

The zero frequency constitutive pencil of one scattering block.

Fields

  • B0, C0: R^(-1/2)(I - S(0)) and R^(1/2)(I + S(0)), so the block's rows read B0 V - C0 i = 0.

  • signalnodes, refnodes: the terminals of each port.

  • auxbase: the auxiliary index base, as in StampedScatteringBlock.

  • freecurrents: the dimension of the null space of C0, the number of port current directions the block leaves undetermined. Zero for a block whose current is fixed by its voltages.

  • name: the block's first port, for messages.

source
JosephsonCircuits.DCBlockRows Type
julia
DCBlockRows

The zero frequency rows of every scattering block in a circuit, ready to be applied to a canonical state.

Fields

  • descriptors: one DCBlockDescriptor per block.

  • currentindex: for each block, the window position of each port's zero frequency current: its slot among the zero frequency entries of the state, one per node and then one per auxiliary unknown.

  • signalcomponent, refcomponent: for each block, the static flux component of each port terminal, or zero where the average voltage is held at zero by a path to ground through inductance.

  • scale: the solver scale (see calcsolverscale), which carries the average voltage into the units the stamp's rows are written in.

  • transportterms: (component, window position of the current, sign) for each block current which crosses a static flux component boundary.

The units are the stamp's throughout. At a nonzero frequency the block's row is B (im w scale phi) - C i, so the stamp's voltage is scale/phi0 times the physical one; the explicit direct current coordinate is v = V/phi0, so the same voltage is scale * v and the row is B0 (scale dv) - C0 i with the current the solver already carries.

source
JosephsonCircuits.DCConductancePlan Type
julia
DCConductancePlan

The topology of the direct current voltage block.

Built from the circuit and its assembled conductance; holds nothing which depends on the sources. It exists whenever there is a zero frequency mode, with no components when every node is held at zero by an inductive path to ground, so that the block relations and the classification have the nodal rows and the conductance to work from.

Fields

  • modeindex, dcrows: the zero frequency mode and its nodal rows.

  • components: the nodes of each floating static flux component.

  • componentof: the component index of each node, zero for a node whose average voltage is fixed at zero by a path to ground through inductance.

  • lift: P, mapping a component voltage to its nodes.

  • conductance: G0, the direct current conductance in the solver's scaled units.

  • reduced: Y = P'G0P, the conductance seen between components.

source
JosephsonCircuits.DCConductanceSolution Type
julia
DCConductanceSolution

The solved average voltages and the direct current they carry.

nodevoltage is in volts, indexed by node with ground first and identically zero. On a floating island only voltage differences are physical; one component of it is held at zero as a reference.

A solution exists exactly when the analysis has a zero frequency mode. When no direct current is injected it is the zero every average voltage sits at, which is an answer and not the absence of one: a node shorted to ground sits at zero volts. Only an analysis with no zero frequency mode has no average voltage to report.

Fields

  • nodevoltage: volts, indexed by node with ground first and identically zero.

  • scaledcurrent: G0 P v, the direct current each node carries in the solver's scaled units, with ground dropped; what the Kirchhoff current law validation and applydcconductance read.

source
JosephsonCircuits.DCFactorization Type
julia
DCFactorization

The factorization of the direct current subsystem and the indices it acts on, resident on a backend.

Fields

  • factors: the packed unit lower and upper triangle lu produced.

  • perm: its row permutation.

  • index: the canonical position of each subsystem coordinate.

  • work: a device scratch vector of length n, the permuted right hand side and then the solution.

  • n: the subsystem size.

source
JosephsonCircuits.DCOperatingPoint Type
julia
DCOperatingPoint

The explicit direct current block at a converged point.

Fields

  • work: the CanonicalWork carrying the layout, the transport rows and the blocks' zero frequency rows.

  • u: the converged canonical state, [phiac | phidc | vdc].

  • jacobian: the canonical Jacobian there, which is the one the implicit function theorem applies to when the block is active.

  • plan: the CanonicalJacobianPlan that filled it.

source
JosephsonCircuits.DCPinning Type
julia
DCPinning

The references a singular direct current subsystem needs: which redundant equations to give up, and which coordinate each one fixes at zero.

A direction the descriptor does not determine may be pinned only when nothing outside the descriptor can see it. Write the rest of the harmonic residual's dependence on the direct current unknowns as H, the zero frequency nodal currents they drive; a null direction N is a gauge exactly when H N = 0.

The common case is a floating island's average voltage. A conductance island with no path to ground has zero row sums, so raising every voltage in it by the same amount drives no current anywhere, and only differences were ever physical. Choosing a reference there changes nothing.

An ideal through in parallel with an inductor is the opposite. Its free direction is the division of current between the two ideal branches, which cancels in the transport row because both terminals lie in one static flux component, and does not cancel at the nodes: it injects +d at one and -d at the other, moving the inductor current, the static flux across it and, through a junction, the nonlinear operating point. H N is nonzero, and the circuit is refused rather than given one of infinitely many answers.

A reference is written as y_c = 0 for a chosen coordinate rather than as a minimum norm condition on the whole direction. The subsystem mixes volts and amperes, so a minimum norm row is not invariant under a change of units, while fixing one coordinate is; and the row it produces has a single entry.

Fields

  • rows: positions in the subsystem whose equation is replaced.

  • cols: the coordinate each replaced row fixes at zero.

source
JosephsonCircuits.DCUpdate Type
julia
DCUpdate

The direct current block's contribution to the residual as keep .* Fw + M*uw + c, in whatever array type the state uses.

cresidual carries the injected current; the Jacobian vector product uses the same M and keep with no constant, the two differing only by that.

source
JosephsonCircuits.DeviceBlockNoisePlan Type
julia
DeviceBlockNoisePlan

The vacuum noise channels of the dissipative scattering blocks, on a backend.

Where the host path reads the auxiliary port current rows of an adjoint solution it has brought back, this describes the same channels as flat tables, so blocknoisefactorkernel! and blocknoisecontractkernel! can form them where the solution already is. The scattering data itself comes from the DeviceProviders the stamps are evaluated through, so this holds only what those do not: which block each entry is, where its auxiliary rows and its factor live, and which entry each channel belongs to.

source
JosephsonCircuits.DeviceNoisePlan Type
julia
DeviceNoisePlan

The noise ports of a circuit, on a backend, for noiseoutputwavekernel!.

source
JosephsonCircuits.DeviceProviders Type
julia
DeviceProviders

The scattering blocks of a stamp system on a backend, as flat tables.

The values a batch of system matrices needs are otherwise computed on the host, because a callable provider is an arbitrary Julia function. A block whose data is tabulated or constant is not: its evaluation is a search and an interpolation, which is the shape a kernel wants. When every block of a circuit is one of those, the whole evaluation moves to the backend and the host does nothing per frequency at all.

A constant block is stored as a one point table, so it needs no separate path. Which frequency a block is evaluated at still depends on its negative frequency rule, and a range which must not be extrapolated is checked on the host before each batch, because a kernel cannot raise.

source
JosephsonCircuits.DeviceScatteringStamps Type
julia
DeviceScatteringStamps

The scattering block contribution to a batch of system matrices on a backend.

assemblesweep! covers the terms which are a constant quadratic in the signal frequency, which the scattering blocks are not: each is evaluated through its own provider, an arbitrary callable or an interpolation of tabulated data, so its values have to be computed on the host. What is left is a gather-add into the stored entries, which is this.

The values serve both directions of a sweep: a block's contribution does not depend on the direction the system is assembled in, only on where in that system's stored order each scalar lands. So they are computed and sent once, and the adjoint direction gets a second view of them with its own destinations (see transposedestinations).

The values are computed on the host, because a callable provider is an arbitrary Julia function. A block whose data is tabulated or constant needs no host at all; see plandeviceproviders.

source
JosephsonCircuits.DeviceSparsePattern Type
julia
DeviceSparsePattern{Ti,V}

The sparsity structure of a sparse matrix, compressed by columns, resident on a backend. Carries no values: it describes where the stored entries are, which is all the device path needs of the Jacobian's structure.

The Jacobian is held transposed on a device, so this is usually the pattern of the transpose and its columns are the Jacobian's rows.

Fields

  • colptr, rowval: the compressed columns.

  • m, n: the shape of the matrix this describes, so size(p) == (m, n).

source
JosephsonCircuits.DeviceSweep Type
julia
DeviceSweep

The state of a linearized sweep computed on a device a batch of frequencies at a time, built by devicesolutions and driven by four verbs: solvebatch! solves the batch beginning at a frequency index and stages its solutions on the host, forwardsolution! and adjointsolution! fill the solution of any frequency of the staged batch, and adjointdevice hands out the adjoint solution of a frequency where it was computed, for the noise scattering parameters.

Fields

  • backend, nb, F: the backend, the batch size and the number of frequencies.

  • w, wpumpmodes, wshost, wsdev: the signal frequencies, the pump mode offsets, and the frequencies of the current batch on the host and on the device.

  • fwd, adj: the batch of each direction, (plan, rowptr, colind, nzval, X, B, equil) on the sparse device factorization path or (X,) on the block path, and nothing when no adjoint was asked for.

  • fstage, astage: the staging of each direction, (full, rows, rowsd, gathered, host).

  • blocks: the block path's (plan, nzval, B, F, X, Xadj), or nothing.

  • scatstamps, scatstampsadjoint, providers: the scattering block stamps of each direction and the providers they are evaluated through.

  • sweeps: the cuDSS sweep of each direction, made on the first batch.

  • solverkwargs: the factorization's options, forwarded to each sweep as it is made so a caller can override the sweep's own defaults.

  • batchlo: the first signal frequency of the batch currently staged.

source
JosephsonCircuits.DeviceValuedSparseMatrix Type
julia
DeviceValuedSparseMatrix{Tv,P,V} <: AbstractMatrix{Tv}

A sparse matrix whose structure lives on the host and whose values live on a device, in the stored order of a compressed sparse row matrix built from that structure.

The structure is held as the transpose, because the compressed columns of the transpose are the compressed rows of this matrix: patterntranspose is therefore a row pointer and a column index array already, and a device sparse matrix can be built from it with no conversion at all. That is also the form realjacobianstructure produces directly when asked for it with transposed = true, which is why nothing here permutes anything.

patterntranspose carries the sparsity structure only; its stored values are whatever they were last set to and must not be read. Use nonzeros to reach the device values, and rowpointer and columnindices to reach the structure.

A factorization which does not have a method for this type will fail on it rather than silently reading the pattern, which is deliberate: the values in patterntranspose are stale by construction.

Fields

  • patterntranspose: the stored transpose, a SparseMatrixCSC on the host or a DeviceSparsePattern (the type parameter P).

  • nzval: the values on the device, in the stored order of the transpose.

source
JosephsonCircuits.ElaboratedCircuit Type
julia
ElaboratedCircuit(definitions, definitionof, instancepaths,
    terminaloffsets, terminalnets, netnames, couplings)

The flattened result of elaborate: the hierarchy resolved to a list of primitive instances, definitions deduplicated by identity, and nets numbered densely with the ground net first.

Fields

  • definitions::Vector{Any}: the unique component definitions, deduplicated by object identity, so that a thousand instances of one shared definition store its data once.

  • definitionof::Vector{Int}: for each flattened primitive instance, the index of its definition in definitions.

  • instancepaths::Vector{String}: the hierarchical path of each instance, such as "cell37/cap", with "/" as the separator.

  • terminaloffsets::Vector{Int}: offsets into terminalnets in CSR layout; the terminals of instance i are terminalnets[terminaloffsets[i]:terminaloffsets[i+1]-1].

  • terminalnets::Vector{Int}: the net index of every instance terminal. Net 1 is the ground net.

  • netnames::Vector{String}: the net names; netnames[1] == "0" is the ground net. User supplied Net names win over automatic names; nested names are hierarchical, such as "cell37/net2".

  • couplings::Vector{NTuple{3,Int}}: for each mutual inductor, the flattened instance indices (mutualinductor, inductor1, inductor2).

source
JosephsonCircuits.ExternalSolver Type
julia
ExternalSolver(f)

Solve the operating point with a caller supplied root finder.

f(prob, u0) receives an HBNonlinearProblem and the initial value in the real representation, and returns (u, converged). Everything it needs is on prob: hbresidual!, hbjvp!, JacobianOperator and preconditioner.

This is the plug point for a solver the package does not know about. A NonlinearSolve.jl algorithm, a hand written continuation stepper or a homotopy all go here without an extension.

The assembled real Jacobian is available on the problem unless assemblejacobian = false was passed, which is what a matrix-free solver wants: on a multi-tone problem that plan is the largest object in the solve.

julia
ExternalSolver() do prob, u0
    u = copy(u0); F = similar(u)
    hbresidual!(F, prob, u)
    for k in 1:40
        J = JacobianOperator(prob, u)
        P = preconditioner(prob, u)
        d, st = Krylov.gmres(J, -F; N = P, rtol = 1e-10, atol = 0.0)
        st.solved || return (u, false)
        u .+= d; hbresidual!(F, prob, u)
    end
    return (u, norm(F) <= tol)
end

Absolute tolerances stall Newton

Note atol = 0.0. Krylov.jl defaults to atol = sqrt(eps()), about 1.5e-8, and stops as soon as the linear residual falls below it. Once the Newton residual is smaller than that – which is the whole point of the last few Newton steps – every linear solve returns immediately having done zero iterations, reports success, and hands back a zero step. Newton then stagnates while nothing reports a failure.

Measured on a JPA with the default atol: 40 Newton iterations, final residual 3.2e-10, never converged. With atol = 0.0: 7 Newton iterations, residual 7.4e-17. Any external Krylov solver used inside a Newton loop wants its absolute tolerance set to zero and its stopping left to the relative one.

source
JosephsonCircuits.FactorizationCache Type
julia
FactorizationCache(factorization)

A mutable holder for a factorization object, so that tryfactorize! can refactorize into it across calls. Starts empty (nothing) when constructed without an argument.

Examples

julia
julia> JosephsonCircuits.FactorizationCache(JosephsonCircuits.KLU.klu(JosephsonCircuits.sparse([1, 2], [1, 2], [1/2, 1/2], 2, 2)));
source
JosephsonCircuits.Floquet Type
julia
Floquet(inner = BlockDiagonal(); size = 20, harvest = 4, ritz = 0,
    candidates = 3*size, ranktol = nothing, benefittol = 1e-6,
    cycleharvest = true)

The preconditioner inner wrapped in a FloquetPreconditioner: the residual-image deflation with physical candidates. harvest is the number of singular directions per harvest, ritz the harmonic Ritz directions on top of it, candidates the size of the candidate bank, ranktol the rank tolerance of the residual image (nothing for the precision's default) and benefittol the predicted improvement below which a candidate is not built in; cycleharvest harvests every GMRES cycle rather than the last.

source
JosephsonCircuits.FloquetPreconditioner Type
julia
FloquetPreconditioner(spec::Floquet, inner::AbstractPreconditioner, jvp!,
    b::AbstractVector; state = nothing)
FloquetPreconditioner(spec::Floquet, inner::AbstractPreconditioner, jvp!,
    n::Integer; T = Float64, state = nothing)

Augments a base preconditioner with a low-rank correction for the few global channels it represents badly, in the residual-image A-DEF1 form.

The hypothesis this is built on is not that the harmonic balance Jacobian J is low rank, which it is not, but that the defect of a cheap base preconditioner,

julia
D = I - J*inv(P),

has low effective rank: that a mode block diagonal already solves almost every direction of a multi-tone problem, and what it leaves is a handful of global spectral-spatial channels — an amplifier's signal-idler pair, a dominant conversion channel, a weakly damped Floquet mode. Those are the directions this deflates.

The residual-image form

Candidate correction vectors X0 are held in the physical state space, not in a residual or Krylov coordinate system. At each rebuild their exact images Y0 = J*X0 are formed and factorized, Y0 = U*S*V'. Keeping the numerically significant rank r,

julia
C = U[:, 1:r],    X = X0*V[:, 1:r]*inv(S[1:r])

so that

julia
J*X = C    and    C'C = I

hold by construction. With W = X - inv(P)*C the preconditioner is

julia
inv(Pdef) = inv(P) + W*C'

applied as z = inv(P)*r + W*(C'*r): one base solve and two dense mat-vecs with an n by r matrix, and no Jacobian product. Because J*X = C exactly,

julia
J*inv(Pdef)*C = J*(inv(P)*C + W) = J*X = C,

so range(C) is an exact eigenspace of the right preconditioned operator at eigenvalue one and GMRES never has to resolve those directions again.

Why not the Galerkin pairing

A deflation may instead build its coarse correction from G = Z'*J*Z and a truncated pseudo inverse of it. That pairing is the natural one for a symmetric positive definite system. This Jacobian is none of those things: it is nonsymmetric, strongly nonnormal, and near a parametric threshold nearly singular. A perfectly good correction direction can then have J*z large while z'*J*z is nearly zero, which makes G ill conditioned for a reason that has nothing to do with the quality of z. Orthonormalizing the image J*X instead of the pairing X'*J*X removes that failure mode, needs no projected inverse at application time, and measures the subspace in the Euclidean norm GMRES actually minimizes.

Candidates

Candidates arrive through seeddeflation! and are tagged by source. The harvest contributes up to two families from the Arnoldi factorization of each restart cycle of each solve when cycleharvest is set, and otherwise from the cycle left in the workspace (harvest!, harvestcycle!): the smallest singular directions of the rectangular Hessenberg, robust on a nonnormal operator, and, when ritz is positive, the harmonic Ritz directions nearest zero (harmonicritznearzero), which target the near-singular eigendirections of a device close to threshold. Both are mapped through the current preconditioner into physical coordinates before being stored, so that a candidate stays meaningful after the Jacobian moves. A continuation secant or an externally constructed Floquet mode is injected the same way.

No source is trusted. The residual-image factorization decides the rank, which removes candidates that rediscovered the same channel, and each surviving direction is then tested for whether the base preconditioner needs help with it at all,

julia
eta = norm(x - inv(P)*J*x)/norm(x),

with directions below benefittol dropped: physically interesting but numerically easy channels cost nothing to carry and are not carried. For an amplifier this is the asymmetry between the amplified quadrature, which needs a large correction, and its deamplified partner, which often does not.

That test is applied in the eigenbasis of W'W and nowhere else, which is not a detail. The rank-revealing factorization pins down range(C) but not a basis of it, and the basis it happens to return is arbitrary whenever the retained singular values are close together — which is the normal case here, not a degenerate one, because equalizing candidates by their image norms is what makes those singular values close. eta is not invariant under a rotation of the subspace, so measured in an arbitrary basis a correction of true rank two can present as six columns of comparable eta, each holding a mixture of what the base misses and what it handles, and nothing is droppable. The eigenvectors of W'W diagonalize the correction, so they are the one basis in which the split is visible; they also order the directions by how much correction each carries, which is the order the cap at size wants.

Cost

Per application: one base solve and two dense mat-vecs. Per rebuild: k Jacobian products for the candidate images and r base solves for inv(P)*C. A rebuild happens when the base is rebuilt and, lazily, when the point moves under a frozen base (pointmoved!).

Options

The fields of the Floquet value spec, validated at its construction:

  • size = 20: the largest active rank retained. When more directions survive both filters the update is compressed to the size principal directions of W'W, that is, those carrying the most correction.

  • harvest = 4: smallest singular directions taken per harvest.

  • ritz = 0: harmonic Ritz directions nearest zero taken per harvest. A complex Ritz pair contributes its real and imaginary parts as two real candidates spanning the same invariant subspace. Off by default: on a 128-junction two-tone line the singular directions alone take 1590 Arnoldi steps (1732 Jacobian products in all), and adding one or two Ritz directions per harvest takes 1955 and 1943 (2125 and 2119); over a seven-point cached sweep 10541 against 12623. The Ritz directions of a strongly nonnormal operator carry large corrections without being the directions GMRES stalls on, and the trim by correction strength then keeps them over the singular ones.

  • candidates = 3*size: the candidate bank's capacity. The active directions of the last rebuild are always kept; older candidates are dropped first. A rebuild resets the bank to the active set, so the capacity only matters between rebuilds, and anything at or above size + harvest + 2*ritz behaves the same; below that a harvest displaces its own newest candidates (measured: an escalation returns on the 128-junction line at candidates = size).

  • ranktol = eps(T)^(3/8): relative singular value threshold for the residual-image rank. The candidates' images are equalized to unit norm, so a small singular value of their block means two images nearly parallel, a channel two sources rediscovered, not a small image; the threshold is the angle below which they count as one. The rank is read off the Gram matrix of the images, whose roundoff is k*eps on the squared singular values, so the threshold sits above sqrt(k*eps) with margin (eps^(3/8) is 1.4e-6 in double precision).

  • benefittol = 1e-6: the eta below which a direction is judged already handled by the base.

state = nothing, the constructor's own keyword, is a FloquetState to continue from; a fresh FloquetState(b) is built when none is given.

  • cycleharvest = true: harvest at the end of every restart cycle (harvestcycle!) rather than only from the cycle left in the workspace when the solve returns.

  • state: a FloquetState to start from, the candidates of a previous solve of a nearby system; it is mutated by the harvests of this solve.

The intended base is the mode block diagonal, and everything here is either a dense level 3 kernel on a small block or a device gemv, with the k by k factorizations on the host, so the pairing ports to a GPU for the same reason that one does. The three-argument application reads r after writing z, so the two must not alias.

source
JosephsonCircuits.FloquetState Type
julia
FloquetState(b::AbstractVector)

The part of a FloquetPreconditioner that outlives one solve: the candidate physical correction vectors X, an n by k matrix allocated like b, and the provenance of each column. A candidate is a direction of the unknowns; its image under the current Jacobian is recomputed at every rebuild, so it means the same thing after the base has been rebuilt or rebound to a new operating point. HBReuse carries one across a cached sweep and replaces it only after a converged solve.

source
JosephsonCircuits.FourierIndices Type
julia
FourierIndices(conjsymdict::Dict{CartesianIndex{N},CartesianIndex{N}},
    vectomatmap::Vector{Int}, conjsourceindices::Vector{Int},
    conjtargetindices::Vector{Int}, hbmatmodes::Matrix{NTuple{N, Int}},
    hbmatindices::Matrix{Int}, hbconjmatindices::Matrix{Int})

A simple structure to hold time and frequency domain information for the signals, particularly the indices for converting between the node flux vectors and matrices. The hbmatmodes and hbmatindices matrices are built from the differences of the modes and describe the coupling between the modes (the derivative of the residual with respect to the node fluxes), while the hbconjmatindices matrix is built from the sums of the modes, aliased back onto the sampled grid, and describes the coupling between the modes and the complex conjugates of the modes (the derivative of the residual with respect to the complex conjugates of the node fluxes). The mode sums themselves are not kept: nothing reads them, and at thousands of modes a matrix of mode tuples over every pair is the largest thing in the setup. See also fourierindices.

source
JosephsonCircuits.Frequencies Type
julia
Frequencies(Nharmonics::NTuple{N, Int}, Nw::NTuple{N,Int}, Nt::NTuple{N,Int},
    coords::Vector{CartesianIndex{N}}, modes::Vector{NTuple{N,Int})

A simple structure to hold time and frequency domain information for the signals. See also calcfreqsrdft and calcfreqsdft.

Fields

  • Nharmonics::NTuple{N, Int}: The number of harmonics for each frequency.

  • Nw::NTuple{N,Int}: The dimensions of the frequency domain signal for a single node.

  • Nt::NTuple{N,Int}: The dimensions of the time domain signal for a single node.

  • coords::Vector{CartesianIndex{N}}: The coordinates of each mixing products.

  • modes::Vector{NTuple{N,Int}}: The mode indices of each mixing product, eg. (0,0), (1,0), (2,1).

source
JosephsonCircuits.FrequencyDependent Type
julia
FrequencyDependent(f)

A frequency dependent component value. f is called with each signed mode frequency in radians per second and returns the component value at that frequency. The function may be arbitrary Julia: a closure over other parameters, a special function, an interpolation of tabulated data.

julia
R0 = 50.0; wc = 2*pi*10e9
("R1", "1", "0", FrequencyDependent(w -> R0*(1 + im*w/wc)))

f receives signed frequencies, as a symbolic frequency variable does, so a law defined only for positive frequencies should apply its own conjugate rule for negative ones inside the closure.

The value may be combined with numbers and other component values using + - * / ^ and the unary - inv sqrt exp log conj real imag. For anything richer, put the whole expression inside the closure.

source
JosephsonCircuits.FrequencySweepPlan Type
julia
FrequencySweepPlan

Everything needed to assemble the linearized system matrix of hblinsolve at many signal frequencies at once, on a backend.

The per-frequency assembly of assemblesystemmatrix! is

julia
A = AoLjnm + invLnm + im*Gnm*w - Cnm*w^2 + Amna0

with the frequency of each stored entry taken from its column's mode, and with the stored value of every frequency dependent term conjugated where that mode frequency is negative (see modevalue). Each stored entry is therefore an independent quadratic in its own mode frequency, and the whole assembly collapses to four constant coefficient vectors and one kernel:

julia
A[q] = cst[q] + sel(kinvL[q]) + im*wm*sel(kG[q]) - wm^2*sel(kC[q])

where wm = ws + wpumpmodes[mode of q] and sel conjugates when wm < 0. The terms which share a frequency power and a conjugation rule are summed into one coefficient at build time, AoLjnm with Amna0. Conjugation distributes over that sum, so this is exact.

Because the coefficients do not depend on the signal frequency, one kernel fills the stored values of a whole batch of frequencies, which is what a uniform batch wants, whether cuDSS's or the batched block factorization's: the batch shares one sparsity pattern and one symbolic analysis, and only the values differ.

Fields

  • colof: the matrix column of each stored entry, from which its mode follows, so the kernel needs no search. For the forward structure this is also the structure's own column index array; for the transposed one it is not, so it is carried separately.

  • cst, kinvL, kG, kC: the four coefficient vectors, in the stored order of whichever structure the plan was built for (compressed sparse row of the matrix for the forward plan, the matrix's own stored order for the adjoint one).

  • wpump: the pump mode frequency offsets of the signal modes.

  • assemble!, backend: the compiled assembly kernel and the backend it was compiled for.

  • nmodes, nnz: the mode count the kernel takes a column's mode from, and the number of stored entries, which sizes the value matrix.

source
JosephsonCircuits.FullJacobian Type
julia
FullJacobian(; factorization = nothing)

Every mode coupling: the full Jacobian, an exact preconditioner and a direct solve. With a BlockFactorization this is the dense block factorization over the circuit graph, the fastest measured method on three or more tones.

source
JosephsonCircuits.FunctionOperator Type
julia
FunctionOperator(f!, n)

Wraps an in-place product f!(y, v) as a mul!-able operator of dimension n, so the Krylov machinery can be written against mul! alone while still accepting a bare closure.

source
JosephsonCircuits.GMRES Type
julia
GMRES(; restart = 400, maxrestarts = 4)

The restarted GMRES of this package, with Givens rotations, the recycling subspace harvest and the preconditioner escalation the solver was built around. The default, and the only solver supporting deflation recycling, because harvest! reads the Arnoldi basis out of the internal workspace. restart is the cycle length and maxrestarts the restart budget per solve. A long cycle is the default because a restricted preconditioner leaves a few directions a short Krylov space cannot resolve, and a restart discards the progress on them; the basis of restart + 1 vectors is cheap next to the sparse factorization an escalation would build.

source
JosephsonCircuits.GMRESWorkspace Type
julia
GMRESWorkspace{T<:AbstractFloat}

Preallocated storage for gmres! with a restart length of m on a system of dimension n. Holds the n x (m+1) Arnoldi basis V, the (m+1) x m Hessenberg matrix H as the Givens rotations leave it, the raw Arnoldi Hessenberg Harnoldi beside it, the Givens rotations cs and sn which reduce it, the least squares right hand side s, its solution y, three length n work vectors, and the two length m staging buffers hd and cd of the block Gram-Schmidt projection, allocated like V.

The dominant cost is V, which is n*(m+1) numbers, so m trades memory and orthogonalization work against restart frequency. It is not paid up front: the basis is allocated with a few columns and grows, by doubling, to what the iteration uses, up to m + 1. A restart length long enough for the hardest solve is then free on the easy ones, where a warm started Newton step takes a handful of Arnoldi steps, and the cost of a solve is no longer dominated by touching a basis it never fills. See ensurecolumns!.

source
JosephsonCircuits.GMRESWorkspace Method
julia
GMRESWorkspace(b::AbstractVector{T}, m::Integer)

Build a workspace for a restart length of m on a system whose right hand side is b. The system sized arrays are allocated with similar(b), so they live wherever b does and the iteration runs on that device; the projected m x m quantities are host arrays regardless, because the Givens rotations and the back substitution index them entry by entry.

source
JosephsonCircuits.GaussLegendre Type
julia
GaussLegendre()

The two stage Gauss-Legendre collocation on the flux and its rate, the default of transientsolve: fourth order, A-stable, symplectic, and free of numerical damping, so a lossless LC oscillation keeps its energy and a resonator's frequency is warped by (2 pi f dt)^4/720 rather than the trapezoidal rule's (2 pi f dt)^2/12. Each step solves the two stage equations together, by Newton on one complex factorization of the stage matrix at a frozen junction stiffness, refreshed as the trapezoidal rule's is. Not L-stable: an unresolved fast mode is not damped, as the trapezoidal rule does not damp it.

Along a direction of the state without capacitance the equations are algebraic. Where a resistor acts along it the rate is what the constraint determines and converges at second order. Where none does the constraint is on the flux alone: a junction on the direction or a source driving it makes it nonlinear or moving, and each step projects its endpoint onto it, while a linear constraint no source drives is an invariant of the rule and holds by itself. The rate along every such direction is not the rule's, whose update carries the rounding of every stage solve forward along it, but is read from the differentiated constraint wherever the state is reported, as the trapezoidal rule's is; where a scattering block is on a direction, whose states move the constraint at a rate the reading would have to solve for with the block's port currents, the rate along the projected directions is the derivative of the cubic through the state, the two stages and the projected endpoint, third order. The tangent and the adjoint of a Gauss-Legendre solve differentiate the full stage equations, the projection and the readings included, and are exact for the recorded steps.

source
JosephsonCircuits.GaussianChannel Type
julia
GaussianChannel(X, Y; nmodes = nothing, displacement = nothing,
    grounded = true, interpolation = :cubic, extrapolation = :error,
    atol = 1e-8)

An arbitrary Gaussian bosonic channel in the canonical real quadrature representation: with quadratures ordered (x_1,…,x_n,p_1,…,p_n) and vacuum covariance I/2, the channel acts as d_out = X d_in + d_0 and V_out = X V_in X' + Y. X and Y are 2n by 2n real matrices and may each be a constant matrix, a callable of angular frequency (requires nmodes), or a tuple (frequencies, values) of tabulated data.

Complete positivity, Y + (i/2)(Ω - X Ω X') ⪰ 0, and the symmetry of Y are validated pointwise at construction for constant and tabulated data with absolute tolerance atol; the worst margin is recorded in the cp_margin field (NaN when validation is deferred for callable providers).

Each mode is a two terminal port addressed like a port of a ScatteringParameters, with the same grounded behavior. displacement is the mean displacement d_0 and is stored but unused. A GaussianChannel is accepted by the circuit representation, but the harmonic balance solvers do not support it yet and compile throws a ComponentNotSupportedError for it.

The complex Bogoliubov form b = A a + B conj(a) may be converted to the deterministic part with quadraturetransform.

Examples

julia
julia> η = 0.5; abs(GaussianChannel(sqrt(η)*[1 0;0 1], (1-η)/2*[1 0;0 1]; nmodes=1).cp_margin) < 1e-10
true
source
JosephsonCircuits.GroundType Type
julia
GroundType

The singleton type of Ground.

source
JosephsonCircuits.HB Type
julia
HB(nonlinear, linearized)

The result of hbsolve: the NonlinearHB solution for the pump and its harmonics in nonlinear, and the LinearizedHB solution for the signals in linearized.

source
JosephsonCircuits.HBCache Type
julia
HBCache

A reusable harmonic balance solver over a circuit builder: the parsed sorted circuit, the circuit graph, the mode grid and its Fourier index maps, the solver options, and the last converged operating point, which hbsolve! uses to warm start the next solve.

Built by hbcache. converged reports whether the last solve succeeded, and a solve which does not converge also warns with the reason it stopped. Check it: a solve which does not converge returns a state that looks like a solution and is not one, and comparing timings or gradients against it is meaningless.

source
JosephsonCircuits.HBLinearizedSystem Type
julia
HBLinearizedSystem

Everything needed to assemble the linearized harmonic balance system matrix on the signal frequency grid at any signal frequency, built with the same plan machinery (plancomplexjacobian and addjosephsonterm!) used for the Jacobians of the nonlinear system by HBSystem. hblinsolve constructs one of these and its per-frequency solves are expressed through it, so any external use of this object is exercising exactly the production linearized solver path.

Use assemblesystemmatrix! to assemble

julia
A(ws) = AoLjnm + invLnm + im*Gnm*W - Cnm*W^2

(with the negative frequency mode conjugations and symbolic frequency substitutions of the linearized solver) into a matrix sharing the sparsity structure of the Asparse field, at the signal frequency ws, for either the pump modulation AoLjnm or its complex conjugate (the adjoint system of the noise and quantum efficiency calculations). Operator products and adjoint products are then sparse matrix-vector products with the assembled matrix, mul!(y, A, v) and mul!(y, A', v), suitable for iterative solves and sensitivity adjoints.

Unlike HBSystem, no time domain matrix-free product is provided, deliberately: a Fourier transform based product computes a cyclic convolution on the pump grid, whereas the assembled matrix uses the explicit truncation of hbmatind (the zeros of Amatrixindices), dropping the couplings which fall outside the grid instead of wrapping them. The assembled matrix defines the linearized solver, so products must match it exactly; since the pump modulation contribution is precomputed, assembling at a frequency costs about the same as one matrix-vector product would, and every product thereafter is a plain sparse matrix-vector product.

source
JosephsonCircuits.HBLinearizedSystem Method
julia
HBLinearizedSystem(Amatrixindices::Matrix, Ljb::SparseVector,
    Rbnm::SparseMatrixCSC, Nmodes::Integer, Nbranches::Integer,
    phimatrix::Array, invLnmcopy::SparseMatrixCSC,
    Gnmcopy::SparseMatrixCSC, Cnmcopy::SparseMatrixCSC, invLnm, Gnm,
    Cnm, symbolicvalues::Bool, Amna0::SparseMatrixCSC, symfreqvar,
    wpumpmodes, Nnodes::Integer; scattering = nothing)

Construct an HBLinearizedSystem from the signal frequency grid index matrix Amatrixindices (see hbmatind), the Josephson junction data, the Fourier coefficients of cos(phi(t)) of the pump in phimatrix, the numeric copies of the linear term matrices (which define the sparsity structure) and the possibly symbolic originals, with symbolicvalues saying whether any of their entries is symbolic (see symbolicindices), and the frequency independent augmentation Amna0 (the coupled inductor and scattering block port current rows; see calcAmnaind), whose entries are merged into the sparsity structure. scattering is the ScatteringStampSystem of the circuit's scattering blocks, whose pattern is merged as well, or nothing. Builds the sparsity structure and Josephson map with plancomplexjacobian and assembles the pump modulation contribution and its conjugate with addjosephsonterm!.

source
JosephsonCircuits.HBNonlinearProblem Type
julia
HBNonlinearProblem

The harmonic balance system as a nonlinear problem: the residual, its exact derivatives and the pieces a preconditioner reads, with the unknowns a plain real vector so that a solver written elsewhere can drive it.

Build one with hbnonlinearproblem. length(p) is the number of unknowns; hbresidual!, hbjvp!, hbjacobian! and hbvjp! evaluate at any point, and setdrive! scales the drive for continuation.

When the circuit injects direct current the unknowns are the canonical state rather than the harmonic one, and augmentation carries the block which makes the difference. isaugmented says which, and every entry point above routes through the block when it is there, so a caller does not have to know. See DCAugmentation.

Fields

  • sys: the harmonic balance system the residual is evaluated on.

  • modelayout: the layout relating the real unknowns to the complex modes.

  • u0: the point the problem was built at.

  • jacobian: the assembled Jacobian, or nothing when none was asked for.

  • parts: the pieces a preconditioner needs.

  • bnm0: the drive as built, which setdrive! scales.

  • tplan: the transposed gather maps the vector-Jacobian product walks.

  • Pwork, Qwork, betawork, dirtd3: transform workspaces.

  • augmentation: the direct current block, or nothing.

source
JosephsonCircuits.HBOperatingPoint Type
julia
HBOperatingPoint(sys, x, jacobian, modelayout, Nnodal, Lscale, wmodes,
    Amna, coupledbranches, Nmodes, Nnodes[, dc])

The converged pump operating point of hbnlsolve together with everything needed to propagate a component perturbation through it: the HBSystem evaluation object, the converged augmented state, the exact Jacobian of the equivalent real system assembled there, and the scaled matrices and layout of the augmented system.

Requested with returnoperatingpoint = true. The Jacobian is the exact Jacobian of the equivalent real system, assembled with assemblerealjacobian!, rather than the complex holomorphic Jacobian of the QuasiNewton method, which is only an approximation: the harmonic balance residual is not complex differentiable, so the implicit function theorem does not hold with the holomorphic Jacobian, while in the real representation it applies directly.

source
JosephsonCircuits.HBReuse Type
julia
HBReuse()

What one solve builds and a later solve of the same circuit at new component values takes over: the aliased mode coupling index, the padded linear term with its augmentation (PaddedLinearTerm), the HBSystem with its transforms and workspaces, the mode coupling preconditioner with its structure and symbolic factorization, the deflation candidates of the last converged solve under a Floquet preconditioner, and the Krylov vectors. Hand one to hbnlsolve as reuse; it is filled by the first solve and rebound to the new values by every later one, so a sweep pays for its transforms, index maps and factorization symbolics once, and each solve starts from the deflation subspace the previous one harvested rather than from nothing. hbcache carries one for its sweeps.

Only a NewtonKrylov method reads it. Every solve which shares it must be of the same circuit topology at the same mode grid with the same options, which is what a cache guarantees; a system whose sparse structure moved is refused rather than rebound.

source
JosephsonCircuits.HBSystem Type
julia
HBSystem

Everything needed to evaluate the harmonic balance nonlinear system and its derivatives at a point: the linear term matrices, the Josephson junction data, the frequency domain packing maps and Fourier transform plans, the real representation layout, optional precomputed Jacobian assembly plans, and preallocated workspaces.

Set the evaluation point with setpoint!, then evaluate any of:

  • residual!: the residual F(x) = B(sin.(A*x)) + K*x - b,

  • jacobianvectorproduct!: the exact matrix-free Jacobian-vector product J(x)*v = B(cos.(A*x) .* (A*v)) + K*v,

  • hessianvectorproduct!: the exact matrix-free second directional derivative H(x)[v, w] = B(-sin.(A*x) .* (A*v) .* (A*w)),

  • jacobian!: the assembled complex (holomorphic) or exact real Jacobian via the precomputed plans,

where A is the linear map from the unknowns to the time domain branch fluxes on the Josephson junctions, B the linear map from a time domain signal back to the node vector, and K the frequency dependent linear terms. Each entry point has a complex representation method and an equivalent real representation method, dispatched on the element type of the output (and direction) vectors, so the same object serves both the QuasiNewton and Newton methods of hbnlsolve as well as matrix-free solvers.

The time domain branch fluxes and the pointwise sine and cosine at the current point are cached, so repeated products at the same point (eg. the many Jacobian-vector products of a Krylov solve) cost only two Fourier transforms and the linear term each.

The fields are intentionally loosely typed; all performance critical loops are behind function barriers which specialize on the concrete argument types. The workspaces of the residual and the matrix-free products are parameterized on their array types rather than fixed to Array, so they can live on whichever KernelAbstractions backend the system was built for.

source
JosephsonCircuits.HBSystem Type
julia
HBSystem(Rbnm, invLnm, Gnm, Cnm, wmodesm, wmodes2m, bnm, Ljb,
    Ljbm, Lscale, Nbranches, freqindexmap, conjsourceindices, conjtargetindices,
    phimatrix, phimatrixtd, irfftplan, rfftplan, modelayout,
    realjacobianplan, complexjacobianplan, backend = CPU();
    realbackward = true, relations = nothing)

Construct an HBSystem from the ingredients assembled by hbnlsolve, allocating the workspaces. phimatrix and phimatrixtd are adopted as the frequency domain and one of the time domain workspaces. realjacobianplan and complexjacobianplan may be nothing, in which case the corresponding jacobian! method is unavailable. realbackward = false skips building the real representation of the linear term in the nonlinear term plan, which only a solve in the real representation applies; see plannonlinearterm. backend is the KernelAbstractions backend on which the index mapped kernels run and on which the plan and the workspaces of the residual and the matrix-free products are allocated; CPU() is the default and the reference. phimatrix and phimatrixtd are adopted as given, so pass them already on the backend, and the time domain workspaces derived from them with similar follow. relations are the JunctionRelations of the junctions, or nothing when every one of them is the sinusoidal Josephson relation, which is the case the evaluations take as the plain sin and cos they always did. They are moved to the backend and to the working precision here, and the cache of the second derivative is allocated only when there is one to hold.

source
JosephsonCircuits.HarmonicBand Type
julia
HarmonicBand(p; factorization = nothing)

The couplings whose harmonic offset is within p, an Integer number of offset shells or a per tone tuple of bounds; see modebandmask. Grown by one offset per tone on escalation.

source
JosephsonCircuits.HybridWorkspace Type
julia
HybridWorkspace()

Reusable scratch for evaluatehybrid!.

Every call needs the same six small buffers: which frequencies are nonzero, those frequencies, the scattering parameters there, the two square roots of the reference impedances, and the unsigned frequencies the providers are evaluated at. A line whose every cell is its own block evaluates thousands of blocks at every signal frequency, so allocating those per call dominated the evaluation. They are reallocated only when a block needs a larger one, which for a circuit whose blocks are all the same size is once.

A workspace is mutable and is written by every call, so it belongs to one task. scatteringvalues! makes one per call when it is not given a workspace, which is what keeps it safe to call from several threads at once; a caller which passes one gives each thread its own.

source
JosephsonCircuits.Inductor Type
julia
Inductor(L; temperature = nothing)

A two terminal linear inductor with inductance L in Henries. Terminals are 1 and 2 with orientation from terminal 1 to terminal 2. The value may be a number or a symbolic variable.

temperature is the physical temperature in Kelvin, which sets the noise a lossy instance adds; a lossless one adds none. nothing, the default, takes the temperature the analysis is run at.

Examples

julia
julia> Inductor(1e-9)
Inductor{Float64}(1.0e-9, nothing)

julia> Inductor(1e-9; temperature = 4.0).temperature
4.0
source
JosephsonCircuits.Instance Type
julia
Instance(definition)

An explicit instance wrapper around a component definition. :id => model and :id => Instance(model) are equivalent. Keyword overrides (parameters, thermal bindings) are reserved for future use and currently raise an error.

source
JosephsonCircuits.Interface Type
julia
Interface(; pins, ports = nothing)

The interface of a hierarchical circuit, exposing internal endpoints as scalar pins and optionally grouping pins into oriented two terminal wave port views.

pins maps external keys (integers or symbols) to internal scalar endpoints, analogous to the pin list of a SPICE .subckt:

julia
pins = [1 => (:jj1, 1), 2 => (:jj2, 2), 3 => (:cap, 2)]

ports optionally maps external port keys to (positive, negative) pairs of pin keys, where the negative entry may be Ground:

julia
ports = [1 => (1, 3), 2 => (2, 3)]

The parent circuit physically binds pins; connecting port to port with pair syntax is shorthand which expands to the pin connections.

The explicit call is optional: Circuit(components, connections; pins = ..., ports = ...) constructs the same interface through keywords.

source
JosephsonCircuits.InverseInductancePlan Type
julia
InverseInductancePlan

The fixed pattern of the inverse nodal inductance matrix, and which branch inductances feed it.

positions selects the retained branches out of the assembled branch inductance vector: the coupled ones are dropped, because the solvers carry them as auxiliary MNA currents instead.

source
JosephsonCircuits.IterationInfo Type
julia
IterationInfo(tr::NewtonTrace, label, krylov = [])

The record of a solve from its trace, with the Krylov records of nlsolvekrylov! when there are any.

source
JosephsonCircuits.IterationInfo Type
julia
IterationInfo(label, parameter, regularization, converged, iterations,
    normresidual, alpha, backtracks, andersonaccepted)

Diagnostics recorded for a call of nlsolve!.

Fields

  • label: the solver stage this invocation belongs to.

  • parameter: the continuation parameter of the stage (the source scale or the damping coefficient, depending on the stage), or NaN.

  • regularization: the diagonal regularization of the Jacobian, if any.

  • converged: whether the iterations converged.

  • iterations: the number of Newton iterations performed.

  • normresidual: the norm of the residual at the start of each iteration.

  • alpha: the accepted step size for each iteration, or NaN for iterations where an Anderson extrapolation was accepted instead of a Newton step.

  • backtracks: the number of linesearch backtracks for each iteration.

  • andersonaccepted: whether an Anderson extrapolation was accepted for each iteration.

  • krylov: a KrylovSolveInfo record for every linear solve performed by nlsolvekrylov!, with one entry per GMRES call rather than per Newton step, so that retries and rescues are visible. Empty for the direct solvers, which take each step from a factorization.

  • reason: why the iteration ended. :converged; :iterations when the Newton step budget was spent; :work when the Krylov work budget was spent (nlsolvekrylov! only); :linesearch when the line search found no sufficient decrease along the Newton direction, once with no decrease at all (twice in nlsolvekrylov!, which retries the first from a rebuilt preconditioner, and which also reports a direction that is not a descent direction after its exact rescue here) or twice in a row with a decrease short of the Armijo condition, which is a stall; :progress when the residual stopped coming down and its rate is not improving, or in nlsolvekrylov! comes down too slowly to reach the tolerance within the remaining budget (residualstalled; that loop first takes one recovery, a rebuilt preconditioner and exact Newton steps, and reports the stall only if it persists); :external for a failed ExternalSolver. stallmessage spells each out.

source
JosephsonCircuits.JacobianOperator Type
julia
JacobianOperator(prob::HBNonlinearProblem, u)

The Jacobian of prob at u as a linear operator.

Implements size, eltype, LinearAlgebra.mul!, and the same for its adjoint and transpose (which are matrix free through the transposed gather maps; see hbvjp!). Construction sets the system's evaluation point ONCE – one forward transform – and mul! never touches it again, so the products inside a Krylov loop pay exactly two transforms each and nothing more. After moving u, construct a new operator: that is the point update, and it is the same cost the internal solver pays once per Newton step.

julia
J = JacobianOperator(prob, u)
Krylov.gmres(J, -F; N = preconditioner(prob, u), atol = 0.0)

Set the absolute tolerance to zero inside a Newton loop

rtol in a Krylov solver is relative to the norm of the right hand side, and in a Newton loop that right hand side is the residual being driven to zero. Any absolute floor eventually exceeds it, at which point the linear solver correctly reports success for a system it never touched, the Newton step is zero, and the iteration stagnates with nothing reporting a failure.

Krylov.jl defaults to atol = sqrt(eps()), about 1.5e-8, which is sensible standalone and wrong here. This package's own gmres! defaults to atol = 0.0, and nlsolvekrylov! passes atol/10, tying the floor to the nonlinear tolerance rather than to machine epsilon.

source
JosephsonCircuits.JunctionRelations Type
julia
JunctionRelations(value, derivative, negsecond, sinusoidal, anysinusoidal)

The current-phase relations of the Josephson junction branches of a circuit, in the order of the nonzero entries of the branch inductance vector Ljb, which is the order of the junction axis of every time domain array the solvers hold.

A relation is either the sinusoidal Josephson one or a PolynomialCPR. The polynomial coefficients of every junction sit in the rows of value, in evalpoly order along the second axis and padded with zeros to one common degree, so that a single Horner loop evaluates them all; derivative and negsecond hold the coefficients of the first derivative and of the negative of the second, which is the combination the Hessian and the derivative of the linearized system with respect to the operating point are written in, and third those of the third derivative, which the trilinear form of the problem interface takes. sinusoidal is true for the junctions whose relation no polynomial represents, whose columns the evaluation writes over with the trigonometric one; anysinusoidal is whether any is, so that a circuit of polynomials alone skips that pass.

A circuit whose junctions are all sinusoidal, which is every circuit that does not ask for anything else, has no table at all: the solvers hold nothing and take the plain sin and cos they always did.

source
JosephsonCircuits.JunctionStructure Type
julia
JunctionStructure

What every assembly of the Josephson term reads about the junctions, built once per system and precision and shared by the plans which assemble from it: the incidence triple product as a per node pair table, the coefficient Lscale/Lj of each junction, and the mode coupling index matrices, on the backend. The values which move with the component values, lmolj, are refreshed in place by refreshvalues!, so every plan holding the structure sees the new values at once; the table and the index matrices are fixed by the topology and the mode grid.

Fields

  • pairptr, pairrow, pairjunc, paircoef: the incidence triple product per ordered node pair, from junctionpairtable, on the backend; hostpairptr, hostpairrow: the pointer and row of the table on the host, for the node graph of a block factorization.

  • lmolj: Lscale/Lj per junction, on the backend.

  • ami, amc: the mode coupling index matrices, on the backend.

  • nodesandsigns: the (node, sign) pairs of each branch, on the host.

  • nmodes, nfreq, nnodes: the mode count, the frequency grid stride into phimatrix, and the node count.

  • backend: where the arrays live.

source
JosephsonCircuits.KLUfactorization Type
julia
KLUfactorization(; kwargs...)

The AbstractFactorization using KLU.jl, a sparse LU factorization suited to circuit matrices. This is the default on the host. kwargs are passed to KLU.klu. The fill reducing ordering is chosen by kluordered rather than left at KLU's default.

source
JosephsonCircuits.KrylovJL Type
julia
KrylovJL(method::Symbol = :gmres; kwargs...)

Solve the Newton step with Krylov.jl: :gmres, :fgmres, :bicgstab, :dqgmres or any other solver taking an operator and a right hand side. Requires Krylov.jl to be loaded; the method lives in the package extension.

Only the linear solve changes. The forcing term, the line search, the preconditioner escalation and the stagnation handling are untouched, and the mode coupling preconditioner is passed through unchanged because it is applied by mul!, which is what Krylov.jl's N argument consumes. Deflation recycling is unavailable, since it depends on the internal workspace.

source
JosephsonCircuits.KrylovSolveInfo Type
julia
KrylovSolveInfo

Diagnostics for a single linear solve of nlsolvekrylov!.

There is one record per GMRES call, not per Newton step. A Newton step can contain up to three: the first solve, a refresh-and-retry when the preconditioner has drifted, and a rescue solve when the resulting direction is not a descent direction. Recording per solve rather than per step is what makes the retry structure visible; a one-entry-per-step vector cannot express it, and the extra solves are exactly where the expensive failures hide.

Fields

  • iteration: the outer Newton step this solve belongs to. Repeated values mark a retry or a rescue.

  • role: :step for the solve which produces the step, :retry for the refresh-and-retry after a solve that did not reach tolerance, :rescue for the solve after a non-descent direction.

  • normF: the nonlinear residual norm at the point of the solve, the right hand side norm.

  • forcing: the requested relative tolerance, the Eisenstat-Walker forcing term for this step.

  • residualratio: the achieved explicit linear residual ratio. The pair (forcing, residualratio) is the diagnosis of an oversolving or undersolving forcing sequence: a loose forcing satisfied in one iteration at a residualratio near one is a solve that did almost nothing while reporting success.

  • iterations, cycles, reason: as returned by gmres!.

  • refreshed: whether the preconditioner was rebuilt immediately before this solve.

  • escalated: whether escalatepreconditioner! grew the preconditioner after this solve.

  • stagnated: whether the step was discarded and replaced by the preconditioner solve.

  • slope: dot(F, J*deltax)/normF^2, a scale free measure of direction quality from an exact matrix-free product. -1 is the Newton direction; a small magnitude is a weak descent direction, which is what a loose solve against a stale preconditioner produces. NaN when not computed.

  • alpha, backtracks, armijo: the linesearch outcome for the step this solve produced. armijo is false when the step was merely the best decreasing trial rather than an Armijo accepted one.

  • time: seconds since the start of the nonlinear solve, so that the residual history can be plotted against wall time with the refreshes and escalations marked.

  • escalationrequested: whether an escalation was requested after this solve; with escalated false, that is an escalation the preconditioner refused because the grown factors would not fit its memory budget.

  • deflationsize, deflationrebuilds, precondtime: the active rank of the recycled deflation, how many times it has been built, and the wall time spent applying the preconditioner in this solve.

  • products, deflationproducts: the exact operator products this linear solve took, and the running count of those the deflation wrapper took for its builds. The cost of a solve is in these, not in iterations alone: every restart cycle recomputes the residual.

source
JosephsonCircuits.KrylovVectors Type
julia
KrylovVectors(x, F, m)

The system sized vectors of one Newton-Krylov solve: the GMRES workspace for a restart length of m, and the step, the trial point, the product and the best residual, allocated like x and F. Handed back to nlsolvekrylov! through its workspace argument they are reused across solves of one system, which a sweep over component values is.

source
JosephsonCircuits.LUfactorization Type
julia
LUfactorization(; kwargs...)

The AbstractFactorization using the UMFPACK sparse LU factorization LinearAlgebra.lu, with kwargs passed to it.

source
JosephsonCircuits.LegacyTermination Type
julia
LegacyTermination(component)

The port owned environment of a legacy netlist: a resistor the netlist already contains, named by its instance identifier.

Internal. A legacy netlist states a port's impedance by placing a resistor across it and carries no role marker, so the adapter finds that resistor once and records which one it is. Everything downstream then reads the port's environment from the port, exactly as for a native matched port, and nothing searches for a resistor sharing a port's branch.

source
JosephsonCircuits.LinearizedArrays Type
julia
LinearizedArrays(; requestS, requestSnoise, requestSsensitivity,
    requestQE, requestCM, requestnodeflux, requestnodefluxadjoint,
    requestvoltage, requestvoltageadjoint, Nports, Nmodes,
    Nnoisechannels, Ncomponents, Nnodes, Nfrequencies)

The preallocated output arrays of one hblinsolve run, filled per frequency by hblinsolve_inner!. An output which was not requested is a zero size array of the same dimensionality, which signals, through isempty, that it is not to be computed. The output shapes and the request conditions are defined here and nowhere else.

source
JosephsonCircuits.LinearizedHB Type
julia
LinearizedHB(w, modes, S, Snoise, Cnoise, Ssensitivity, QE, QEideal,
    CM, nodeflux, nodefluxadjoint, voltage, voltageadjoint, nodenames,
    nodeindices, componentnames, componenttypes, componentnamedict,
    mutualinductorbranchnames, portnumbers, portindices,
    portimpedances, noiseportimpedanceindices, sensitivitynames,
    sensitivityindices, Nmodes, Nnodes, Nbranches, Nports, signalindex)

The solution of the linearized harmonic balance problem returned by hblinsolve. An output which was not requested is an empty array. The frequency dependent outputs are indexed as [outputmode, outputport, inputmode, inputport, frequency] (keyed arrays with those axis names when keyedarrays = true).

Fields

  • w: the signal angular frequencies in radians per second.

  • modes: the retained signal modes as tuples of harmonic indices; (0,) is the signal itself and (k,) the idler offset by k pump harmonics.

  • S: the scattering matrix relating the inputs and outputs at each combination of port, mode and signal frequency.

  • Snoise: the scattering matrix from the noise channels of the dissipative elements to the ports, in the same signed frequency convention as S: a resistor's channel is a port of its impedance in vacuum, and its row of Snoise is what that port's column of S would be (see adjointnoisesigns!). The channels are the dissipative lumped components (see noiseindices) followed by one per port of each dissipative ScatteringParameters. Being a scattering matrix it describes a transformation and does not depend on temperature.

  • Cnoise: the added noise covariance at the output ports, sum_c occupation[c]*Snoise[c,i]*conj(Snoise[c,j]), when returnCnoise = true. Together with S this is the Gaussian channel the circuit implements, taking an input covariance to S*sigma*S' + Cnoise; the temperature of each channel enters here through the occupation. At zero temperature its diagonal is the noise term in the denominator of the quantum efficiency.

  • Ssensitivity: the derivative of S with respect to a relative (logarithmic) perturbation of each component in sensitivitynames, or of each design parameter when the sensitivity pair interface is used, at a fixed pump operating point or including the shift of the operating point when sensitivityoperatingpoint = true.

  • QE: the quantum efficiency at each combination of port, mode and frequency.

  • QEideal: the quantum efficiency of an ideal amplifier with the same gain.

  • CM: the bosonic commutation relations of each output, sum_j |S[i,j]|^2 sign(w_j) over the input modes, which equal +1 for an output at positive frequency and -1 for one at negative frequency when the scattering matrix is complete.

  • nodeflux: the node fluxes resulting from a unit input at each port and mode.

  • nodefluxadjoint: the node fluxes of the adjoint (time reversed modulation) problem.

  • voltage: the node voltages resulting from a unit input at each port and mode.

  • voltageadjoint: the node voltages of the adjoint problem.

  • nodenames: the node names, ground first.

  • nodeindices: the 2 by Ncomponents matrix of component node indices from the CompiledCircuit.

  • componentnames, componenttypes, componentnamedict, mutualinductorbranchnames: the corresponding fields of the CompiledCircuit.

  • portnumbers: the port numbers, in the order the port axes use.

  • portindices: the flat component index of each port.

  • portimpedances: the reference impedance of each port, which the scattering parameters are normalized to.

  • noiseportimpedanceindices: the flat component indices of the internal dissipative components, in the order of the noise channel axis of Snoise.

  • sensitivitynames: the component names the sensitivities were taken with respect to.

  • sensitivityindices: their flat component indices.

  • Nmodes: the number of retained signal modes.

  • Nnodes: the number of nodes, including ground.

  • Nbranches: the number of branches in the circuit graph.

  • Nports: the number of ports.

  • signalindex: the position of the signal mode (0,) in modes, which is always 1.

source
JosephsonCircuits.LinearizedScattering Type
julia
LinearizedScattering(linearized, wp; ports = nothing, zref = 50.0,
    grounded = true, noise = Lossless(), phase = 0.0,
    interpolation = :cubic, atol = 1e-6, dcmodel = ScatteringLimit(),
    envelope = nothing)
LinearizedScattering(H, wp; harmonics, nports, zref = 50.0,
    grounded = true, noise = Lossless(), phase = 0.0,
    dcmodel = ScatteringLimit(), envelope = nothing)

The linearized scattering of a pumped device, a linear time-periodic multiport: a parametric amplifier, converter or isolator in its periodic steady state, whose small signal response converts between frequencies separated by harmonics of its pump wp (radians per second). It is described by harmonic transfer functions H_k(nu), the wave leaving at the absolute frequency nu + k*wp per unit wave incident at nu, for the harmonics k >= 0 it converts by; a real device has H_{-k}(nu) = conj(H_k(-nu)), which supplies the rest. H_0 is an ordinary scattering matrix, and every H_k is a function of the signed frequency, so the block is evaluated natively at negative frequencies.

The harmonic transfer functions act on power waves, as the hybrid stamp does; the scattering matrix the solvers report is in waves of photons per second, so a conversion entry of the two differs by the square root of the ratio of the frequencies, which the first form applies.

The first form builds one from the linearized output of hbsolve of the device, with its keyed scattering matrix over the modes of one pump and its frequencies: the entry from input mode n to output mode m at the signal frequency w is a sample of H_{m-n} at w + n*wp, and the samples of every harmonic from every mode pair are collected, folded onto k >= 0, and tabulated band by band over the shifted bands with interpolation, zero between and beyond them, since the data says nothing there (see PiecewiseTabulatedProvider). Samples which fall on the same frequency from different mode pairs must agree to atol, relative to the largest entry, which is what makes the data that of one periodic steady state, and the block built from the tables is checked against its declaration over the modes of the solve at every frequency, as every solve checks it, since the tables hold at one frequency samples from solves of neighboring signal frequencies whose mode truncations differ; a device whose mode truncation was too tight fails both, and atol admits the discrepancy of one which was nearly so. ports selects and orders the device's ports which become the block's, by default all of them, and zref gives their reference impedances. phase rotates H_k by exp(im*k*phase), the phase of the block's pump relative to the one the data was computed with, which matters when other elements of the circuit share the pump.

The second form takes the harmonic transfer functions directly: H is a vector of providers, one per entry of harmonics (nonnegative, ascending, beginning with zero), each a matrix, a callable of the signed angular frequency, or a tuple (frequencies, values) tabulated over signed frequencies.

The block is stamped by the harmonic balance solvers as a coupling between the modes of the circuit whose frequencies differ by its harmonics, so the circuit must be solved with the block's pump: its wp must be a harmonic combination of the circuit's pump frequencies and the mode set must reach the harmonics the block converts by, which is how a circuit with no junctions is solved with a pumped block, by giving hbsolve the pump frequency and no source at it. The block is linear, so it acts on the circuit's own pump harmonics the same way.

noise = Lossless() asserts that the device is lossless: its multi-mode scattering matrix S satisfies J - S J S' = 0 with J the signs of the mode frequencies, which is checked on the block as built and again over the modes of every solve which evaluates it, in harmonic balance at every signal frequency and in time at every bath frequency, and the block then emits no noise. A device with loss states the noise it adds with noise = NoiseCovariance(linearized.Cnoise), the covariance its solve reports with returnCnoise = true, over the same modes, ports and frequencies: in the units of Cnoise, where a vacuum channel counts as one, it becomes the harmonic covariances V_k(nu) = <n(nu + k wp) n(nu)'>, sampled like the transfer functions, and is held to the minimum the commutation relations require, V - K and V + K positive semidefinite with K = J - S J S', on the data and again at every frequency of a sweep. The block then carries channels of both kinds over all its modes at once, as an active block does (see NoiseCovariance), so it adds the noise its solve found, correlated across the modes, and its output obeys the commutation relations. Given by its harmonic transfer functions, the stated noise is one covariance provider per harmonic. atol is the tolerance of the block's data, relative to the square of the largest entry of the multi-mode scattering matrix: the consistency of the data of one periodic steady state, the losslessness declared or the commutation relations a stated covariance must satisfy, which the block is checked for on its stored data when it is built, a table at its knots and a block of constants which does not convert at any one frequency, and over the modes of every solve, whatever outputs the solve is asked for, a callable and constants which convert being checkable only there, and an entry of the data below it is zero where the pump solve asks whether the block converts the conjugate of a mode; a covariance's own atol counts for its checks as well. A fit of the block is held to no tolerance: it states the noise its own commutator requires, a covariance completed to the commutation relations (see NoiseCovariance). grounded and dcmodel are as for ScatteringParameters; the direct current behavior is that of H_0 at zero unless stated.

In time the block is realized by RationalScattering(block, npoles), which fits every harmonic transfer function to stable filters: H_0 as an ordinary rational block, and each H_k as the pair of real filters of its cosine and sine parts, strictly proper, whose outputs the transient multiplies by 2 cos(k wp t) and -2 sin(k wp t). envelope is a callable of the time in seconds which multiplies every harmonic but the zeroth there, a prescribed gate of the conversion and not a model of the pump being switched: H_0, the filters and a stated covariance stay those of the pumped device while the conversion is scaled, so the block satisfies the commutation relations only where the envelope is one, or zero for a device whose H_0 is that of the device unpumped. What the gate is for is the start of a record: ramped from zero, it leaves the circuit time invariant before the record a noise calculation needs, as the pumps of the junction circuits are, and the noise is read once the conversion has been on longer than the block's memory. nothing is a conversion always on, which a noise calculation then takes as periodic from the start of its record with the fluctuations before it those of the unconverted response, not of the periodic device.

source
JosephsonCircuits.LinearizedWorkspace Type
julia
LinearizedWorkspace

The scratch of one worker's pass over a range of signal frequencies in hblinsolve_inner!.

The largest buffers are the size of the solution and of the system matrix, so a worker is given one workspace once and reuses it across every range of frequencies it is handed. This is what lets the device path hand out one batch of frequencies at a time while keeping the host work parallel.

source
JosephsonCircuits.LinearizedWorkspace Method
julia
LinearizedWorkspace(arrays::LinearizedArrays, sensitivity, lsys, Nports,
    Nmodes, Nnoisechannels, Nwpumpmodes, factorization;
    assembles::Bool = true)

Make the scratch of one worker. assembles is false when the solutions are supplied from elsewhere and nothing writes into a copy of the system matrix, which on a large problem is the biggest allocation here.

source
JosephsonCircuits.Lossless Type
julia
Lossless()

A noise model for a ScatteringParameters asserting that its scattering matrix is unitary at every frequency, or for a LinearizedScattering that its multi-mode scattering matrix S satisfies J - S J S' = 0 with J the signs of the mode frequencies, so that the block absorbs nothing and adds no noise.

With the default Passive model a block gets noise channels unless its data can be shown to be unitary, which is possible for a constant matrix and a table but not for a callable, whose values away from the evaluated frequencies are unknown. A lossless callable would therefore carry noise channels which are identically zero, at a real cost on a circuit with many blocks; Lossless() removes them.

For a constant or tabulated block the assertion is checked at construction, with a fixed tolerance of 1e-10 rather than the block's atol, and is an error if false. For a callable it is taken on trust, and asserting it of a block which does absorb omits the noise the block should add, making the quantum efficiency and the commutation relations wrong by that much. A pumped block is checked when it is built and again over the modes of every solve which evaluates it, to the block's atol; a fit of a pumped block is not lossless to better than its error, and states the noise it needs instead (see NoiseCovariance).

source
JosephsonCircuits.MatchedTermination Type
julia
MatchedTermination()

A source and load environment matched to the port's reference impedance, acting across the two port terminals. This is the default: a port owns its environment, so no resistor should be added in order to terminate it.

source
JosephsonCircuits.MeasuredBand Type
julia
MeasuredBand(; tol = 1e-2, budget = 0.25, factorization = nothing)

A HarmonicBand whose per tone width is measured from the Fourier coefficients of cos(phi(t)) at every point and widened when the drive demands it, starting from the block diagonal; see cosphibandwidths for tol and budget. For two strong tones this is the setting that matters.

source
JosephsonCircuits.ModeCouplingPreconditioner Type
julia
ModeCouplingPreconditioner

A preconditioner for the matrix-free Newton-Krylov solve of the harmonic balance system: the Jacobian materialized with its mode coupling restricted to a selected set of modes and reduced to the mode diagonal everywhere else (see modecouplingmask), then factorized.

The restriction is applied while the Jacobian is materialized, not afterwards: the assembly plan is built from mode coupling index matrices whose dropped couplings have been zeroed by restrictmodecoupling, so the restricted operator is assembled directly into its own, sparser, structure by the same assemblerealjacobian! which assembles the full Jacobian, from the same Fourier coefficients of cos(phi(t)) and the same linear term matrices. No submatrices are extracted and no sweep is written by hand; the block triangular structure is what makes the sparse LU cheap, and the sparse triangular solve is what applies the Gauss-Seidel sweep.

The default is BlockDiagonal, the mode block diagonal. Its factorization is a batch of small independent per mode factorizations rather than one large sparse factorization, which is what makes it scale. On a strongly pumped device the block diagonal alone stalls, and escalatepreconditioner! is the safety net.

Fields

  • P: the restricted Jacobian's sparsity structure. A SparseMatrixCSC on the host, and on a backend a DeviceSparsePattern of the transpose, which is the row major structure a device sparse matrix wants.

  • sys: the HBSystem the Jacobian is assembled from.

  • cache: the FactorizationCache holding the factorization of P.

  • factorization: the AbstractFactorization of P. A block factorization which meets a singular supernode is replaced by the backend's sparse factorization of the same coupling set (see refactorize!).

  • Amatrixmodes: the harmonic offset modes[m1] .- modes[m2] of every mode pair, or nothing. Needed by HarmonicBand, MeasuredBand and by their escalation.

  • coupling: the coupling set currently factorized, a BlockDiagonal, FullJacobian, HarmonicBand, CoupledModes or CouplingMask; a MeasuredBand or Clusters request is held as the band or mask it has grown to so far.

  • updates: the number of times the factorization has been rebuilt.

  • escalations: the number of times the coupling set has been grown.

  • plan: the PreconditionerPlan, the structural ingredients from which buildcoupling rebuilds the pattern, the assembly plan and the values for a new coupling set, so the set can be grown after construction; it carries the precision of the factors, and is replaced when they are promoted to the iteration's.

  • Nmodes: the number of modes.

  • autoindices, autotol, autobudget: the ingredients of a MeasuredBand's bandwidth measurement, nothing and zero when none was asked for.

  • deviceplan, nzval: the assembly plan and the values it writes, rebuilt on escalation; on a host nzval aliases the stored values of P.

  • clusterprobe: the state of a Clusters request, nothing otherwise.

  • budget: the memory an escalation may take, or nothing for half the backend's free memory at the time (freememory); set by tests, not by a constructor keyword.

source
JosephsonCircuits.ModeCouplingPreconditioner Method
julia
ModeCouplingPreconditioner(sys::HBSystem, Amatrixindices::Matrix,
    Amatrixconjindices::Matrix, Ljb::SparseVector, Lscale,
    Rbnm::SparseMatrixCSC, Nmodes::Integer, Nbranches::Integer,
    Nfreq::Integer, invLnm::SparseMatrixCSC, Gnm::SparseMatrixCSC,
    Cnm::SparseMatrixCSC, layout::ModeLayout;
    spec::AbstractModeCoupling = BlockDiagonal(), precision = nothing,
    Amatrixmodes = nothing)

Build a ModeCouplingPreconditioner from the same ingredients planstructurerealjacobian takes. spec is the member of the mode coupling family to build (BlockDiagonal, FullJacobian, HarmonicBand, MeasuredBand, Clusters, CoupledModes, CouplingMask, or Automatic, which is resolved by resolveautomatic at construction to the member which fits this problem and this backend's free memory), carrying the factorization it is built with, the backend's default (KLU on the host, cuDSS on a device) when it carries none. A BlockFactorization eliminates the circuit graph with dense blocks over the clusters of the coupling set instead of factorizing a sparse matrix. precision is the floating point type of the factorization, nothing for that of the system. Amatrixmodes is the harmonic offset of every mode pair, needed by HarmonicBand and MeasuredBand.

source
JosephsonCircuits.ModeLayout Type
julia
ModeLayout(isreal::AbstractVector{Bool}, dim::Integer, ::Type{Ti}=Int)
ModeLayout(realindices, nmodes::Integer, dim::Integer, ::Type{Ti}=Int)

Layout of one axis of length dim (a complex dimension), built from a length- nmodes mask of which modes are real. dim must be an integer multiple of nmodes. Complex index i owns real slots ptr[i]:ptr[i+1]-1; inv maps a real slot back to its complex index; isfirst marks the slots that start a mode; rdim is the resulting real dimension.

w is a bit per index recording whether that mode is real.

Fields

  • nmodes, dim, rdim: the mode count, the complex dimension and the real dimension.

  • nreal, isreal: the number of real modes and the mask over the modes.

  • ptr, inv, isfirst: the slot ranges, the inverse map and the mode starts, as above.

  • w: the bit per complex index, whether its mode is real.

source
JosephsonCircuits.ModulatedRationalProvider Type
julia
ModulatedRationalProvider(cosine::RationalScatteringProvider,
    sine::RationalScatteringProvider)

The harmonic transfer function of a LinearizedScattering block for a harmonic k > 0 as fitted for the transient: H_k(nu) = G_c(i nu) + i G_s(i nu) with G_c and G_s real rational functions, the cosine and sine parts G_c(nu) = (H_k(nu) + conj(H_k(-nu)))/2 and G_s(nu) = (H_k(nu) - conj(H_k(-nu)))/(2i), each realized as a stable state space with no feedthrough, since a conversion vanishes at infinite frequency. Natively valid at signed frequencies. In time the block multiplies the output of the cosine filter by 2 cos(k wp t) and that of the sine filter by -2 sin(k wp t), which is 2 Re[exp(i k wp t) (h_k * a)], the sum of the harmonics k and -k of a real system.

source
JosephsonCircuits.MutualInductor Type
julia
MutualInductor(K, inductor1, inductor2)

A mutual inductor with the dimensionless mutual coupling coefficient K coupling the two Inductor instances with identifiers inductor1 and inductor2 in the same circuit level. A mutual inductor couples two named inductor branches rather than nets, so it appears in the component list with no entries in the connections:

julia
:k1 => MutualInductor(0.9, :l1, :l2)

The referenced identifiers are resolved within the containing circuit during elaboration, so each instance of a subcircuit couples its own inductors.

The sign of K follows the order each inductor's terminals are declared in: with K > 0 currents entering the first terminal of each inductor add flux to both, as with the dots of a SPICE coupling statement at the first named nodes, and reversing the terminals of one inductor, or the sign of K, opposes them.

In the netlist form of Circuit the entry names the two inductors in place of nodes, and the component is written MutualInductor(K) alone:

julia
(:k1, :l1, :l2, MutualInductor(0.9))
source
JosephsonCircuits.Native Type
julia
Native()

A negative frequency rule declaring that the provider is natively valid on signed frequencies and may be evaluated directly at negative frequencies. Opt-in for analytic providers whose formulas satisfy the physical conjugation identity by construction.

source
JosephsonCircuits.Net Type
julia
Net(name, endpoints)

A named connection group: all endpoints belong to the same electrical net, which is given the name name for diagnostics and outputs. Unnamed nets are named automatically. Names attached to the ground net are ignored; the ground net is always named "0".

Examples

julia
Net(:bias, ((:source, 1), (:device, 2)))
source
JosephsonCircuits.Never Type
julia
Never()

Rebuild the preconditioner only when it is forced: a linear solve which makes progress but misses its tolerance, a direction which is not a descent direction, a line search which finds no decrease, or a successful escalation. A stagnated solve is not retried and does not rebuild; its step is replaced by the preconditioner solve. The slow-solve report to the preconditioner (stalled!) is off as well, so a Clusters preconditioner never remeasures under this policy. A frozen preconditioner, for when a deflation (Floquet) is to carry the solve across the Newton path against a base built once.

source
JosephsonCircuits.Newton Type
julia
Newton(; factorization = nothing, linesearch = Backtracking())

Newton's method on the equivalent real system with the exact assembled real Jacobian, factorized by factorization (the host's KLU when nothing), the length of every step chosen by linesearch, a Backtracking, interpolating by default.

source
JosephsonCircuits.NewtonKrylov Type
julia
NewtonKrylov(; preconditioner = Automatic(), linearsolver = GMRES(),
    refresh = Always(), escalate = true, linesearch = Backtracking(),
    precision = Float64)

Jacobian-free Newton-Krylov with the mode coupling preconditioner: the default. preconditioner is an AbstractPreconditionerSpec; the default Automatic picks the full Jacobian for one tone and, for more, the set whose factors fit in memory. linearsolver is a GMRES or a KrylovJL solver, refresh Always (the default), Probe (which rebuilds the preconditioner only when a measured probe says a rebuild pays, and is faster by a fifth to a third on the hard cases, at the price of a solve path which depends on measured times and so can differ between two runs) or Never. escalate allows a preconditioner which fails to reach its tolerance to be grown (a band by one offset per tone, any other set to the full Jacobian; see escalatepreconditioner!), within the memory the grown factors are predicted to take; a refused escalation is recorded and the solve carries on.

The solve ends promptly when it cannot succeed and says why, in the reason of its IterationInfo: :iterations when the Newton steps are spent; :work when the Arnoldi steps exceed iterations restart lengths, so that a preconditioner which runs every linear solve to its limit cannot turn the step budget into hours; :linesearch when no sufficient decrease can be found (a step with no decrease at all is retried once from a rebuilt preconditioner and ends the solve if it fails again, as does a direction which is still not a descent direction after the exact rescue, or two consecutive steps short of the Armijo condition); :progress when the residual history stopped coming down or comes down too slowly to reach the tolerance within the remaining budget, its rate is not improving and it is not accelerating, after one recovery which rebuilds the preconditioner and takes exact Newton steps from then on (residualstalled). A stall outside the Newton basin is the continuation problem Staged exists for. linesearch is the Backtracking which chooses the length of every step, interpolating by default; halving (Backtracking(interpolate = false)) suits an inexact preconditioner such as BlockDiagonal. precision is the floating point type of the iteration: the system on the backend, the Krylov vectors, and the factors of a sparse preconditioner; a single precision solve needs a relative tolerance rtol it can meet.

The forcing sequence (Eisenstat-Walker choice 2 clamped to [1e-10, 0.9], starting at 0.3) and the stagnation threshold (a solve which does not bring the linear residual below 0.9 of the residual norm) are fixed; see nlsolvekrylov!.

source
JosephsonCircuits.NewtonTrace Type
julia
NewtonTrace{T}

The record and the acceptance rules shared by the two Newton loops, nlsolve! and nlsolvekrylov!: the residual norm history, the step lengths and backtrack counts of every trial, the count of consecutive line searches which returned the best decreasing trial rather than an Armijo step, the tolerance, and why the iteration ended. The loops differ in how they compute a direction and in what they do about a stall; what a step is, when the iteration has converged and when repeated short steps are a stall, they share here, through tracestart!, tracetrial!, tracestep! and tracestalled. The history vectors are the ones the IterationInfo of the solve reports, so a loop may read normresidual directly for its forcing terms and records.

Fields

  • normresidual: the residual norm at the starting point and after every step taken.

  • alpha, backtracks, andersonaccepted: per trial, the step length, the trial evaluations after the first, and whether the step lies on the accelerated path.

  • atol: the tolerance in force, the absolute one or the relative one times the initial norm, whichever is larger.

  • maxbacktrackfailures, backtrackfailures: the stall threshold and the consecutive count against it.

  • converged, reason: the outcome.

source
JosephsonCircuits.NoPortTermination Type
julia
NoPortTermination()

No port owned environment, written as termination = nothing. The port remains an excitation and observation boundary with its reference impedance intact, but contributes no physical loading of its own.

source
JosephsonCircuits.NodalStampPlan Type
julia
NodalStampPlan

The fixed pattern and stamp destinations of a nodal matrix.

dest[k] is the position in nzval which contribution k accumulates into, src[k] names the group value it comes from, and negate[k] marks the off diagonal terms. invert inverts the value after negating, which is the order calcnodematrix uses and therefore the one that reproduces its arithmetic exactly.

The plan is built once per topology; assemblenodal! is a scatter-add which allocates nothing.

source
JosephsonCircuits.NoiseCovariance Type
julia
NoiseCovariance(V; interpolation = :cubic, extrapolation = :error,
    atol = 1e-8, completed = false, padding = 4)

The noise a ScatteringParameters adds, stated outright rather than derived from its loss, which is how an active block, an amplifier given by its scattering parameters, declares its noise. V is the symmetrized covariance of the noise wave the block emits at its ports, in the units of the rest of the noise outputs, where a vacuum channel counts as one and a channel at temperature T as coth(hbar*w/(2*k*T)), that is 2*nbar + 1: the same units as Cnoise. It may be a matrix, a callable of angular frequency, or a tuple (frequencies, values) of tabulated data, following the same provider forms as the scattering data, and is evaluated with the block's negative frequency rule.

The block's output must obey the commutation relations, so with K = I - S S' the added noise has the commutator K, and a covariance is realizable only when V - K and V + K are both positive semidefinite. (V + K)/2 is then the covariance of channels which emit like a mode in its vacuum and (V - K)/2 of channels which emit like the conjugate of one, the idler channels of an amplifier; a passive block in thermal equilibrium is the case V = coth(hbar*w/(2*k*T)) K. A phase insensitive amplifier of power gain G from port 1 to port 2 has K[2,2] = 1 - G, so V[2,2] >= G - 1, the noise of a quantum limited amplifier, and one with an input referred added noise of nadd photons has V[2,2] = 2*G*nadd; V[1,1] is what it emits backward out of its input, (2*nbar + 1)*K[1,1] for an input matched at its physical temperature.

The condition is checked on the eigenvalues to atol at construction where both the scattering data and V are stored, and at every frequency a solver evaluates the block at. V is also validated for Hermitian symmetry. A block with this model carries no temperature: its noise is V, whatever the analysis temperature.

With completed = true the covariance is completed to the commutation relations rather than held to them: V is replaced by V + neg(V - K) + neg(V + K), neg taking the negative part of a Hermitian matrix, the sum of -lambda v v' over its negative eigenvalues, which makes V - K and V + K positive semidefinite and adds nothing where they are. For V = 0 the addition is |K|, the least total noise a Gaussian channel with the block's map can add, the Ymin of the quantum optics functions in the basis of the modes; for a stated V it is a sufficient addition, the least being a semidefinite program with no closed form. The block then adds the noise it states and what more its commutator requires, and its output obeys the commutation relations exactly, whatever V and S are. An ordinary block is completed at each frequency. A pumped block's covariance spans the modes of a solve at once, and the negative part of a matrix is not that of its parts, so it is completed over the ladder of the modes padded by padding multiples of the pump frequency on either side, with every input which feeds it, and restricted to the modes of the solve (see completedcovariance): the block's noise is then one model whatever modes a solve keeps, to the precision of the padding, which converges since a fit's conversion vanishes at high frequency, and the inputs a solve lacks are traced out in their vacuum. padding is that precision and not a bound on it, so a device whose conversion reaches far is checked by raising it and comparing the covariance the solve keeps. Every mode a solve asks for is completed, including one beyond the sidebands the block's data holds, which it scatters nothing at and so carries the vacuum its commutator requires, as its stamp takes it. This is how a fit of a pumped block states its noise (see RationalScattering): a fit is neither lossless nor consistent with a stated covariance to better than its error, and the completion turns that error into noise the block emits, where a tolerance would only excuse it.

source
JosephsonCircuits.NoiseReduction Type
julia
NoiseReduction

The noise scattering matrix reduced to what the quantum efficiency and the commutation relations read of it: two numbers per output port mode.

Both consume Snoise, a row per noise channel mode c and a column per output port mode i, only through a sum over the noise index. The quantum efficiency reads sum_c occupation[c]*abs2(Snoise[c,i]), the noise power at output i with each channel's occupation (2*nbar + 1); the commutation relations read sum_c sign(w_c)*abs2(Snoise[c,i]), the same power weighted by the sign of the channel's mode frequency and without the occupation, which is why the commutation relations do not depend on temperature. A channel of the conjugate kind, one of a block which states its noise (see noisechannelsigns), enters the second sum with its sign reversed. The first is also the diagonal of the noise covariance matrix of calcnoisecovariance!.

On a circuit whose loss is spread along the line that is a reduction of thousands of rows to one number per port mode, so when the noise scattering parameters are not themselves an output there is no reason to bring the matrix to the host at all: devicenoise returns the reduction, and the host loop forms it from its matrix with noisereduction! (allocating: noisereduction). Passed to calcqe! and calccm!.

Fields

  • denom: sum_c occupation[c]*abs2(Snoise[c, i]) per output mode i.

  • signed: sum_c sign(w_c)*abs2(Snoise[c, i]), with no occupation.

source
JosephsonCircuits.NonlinearHB Type
julia
NonlinearHB(w, frequencies, nodeflux, Rbnm, Ljb, Lb, Ljbm, Nmodes,
    Nbranches, nodes, ports, modes, S, solverinfo, operatingpoint,
    dcnodevoltage)

The solution of the nonlinear harmonic balance problem returned by hbnlsolve.

Fields

  • w: the tuple of pump angular frequencies in radians per second, one per non-commensurate pump.

  • frequencies: the Frequencies describing the retained pump harmonics and intermodulation products.

  • nodeflux: the node fluxes at each retained mode. With keyedarrays = true an Nmodes by Nnodes - 1 keyed array with axes :outputmode and :node; otherwise a vector of length Nmodes*(Nnodes - 1) with the mode index varying fastest.

  • Rbnm: the incidence matrix between the branch and node bases, with each entry repeated Nmodes times.

  • Ljb: sparse vector of the Josephson junction inductances by branch.

  • Lb: sparse vector of the linear inductances by branch.

  • Ljbm: Ljb with each entry repeated Nmodes times.

  • Nmodes: the number of retained modes.

  • Nbranches: the number of branches in the circuit graph.

  • nodes: the node names, ground ("0") first.

  • ports: the port numbers.

  • modes: the retained modes as tuples of harmonic indices; (1,) is the pump of a single pump solve, (1,0) the first of two pumps.

  • S: the scattering matrix at the pump frequencies, relating the inputs and outputs at each combination of port and mode. Its zero frequency entries are identically zero: the waves are in units of sqrt(photons/second), whose normalization 1/sqrt(|w|) (see portwavescale) has no limit at zero, so there is no direct current wave to report. The direct current operating point is in dcnodevoltage.

  • solverinfo: diagnostics of the solution process; see SolverInfo.

  • operatingpoint: the converged operating point with the exact real Jacobian there, when the solver was called with returnoperatingpoint = true; otherwise nothing. See HBOperatingPoint.

  • dcnodevoltage: the average voltage of each non-ground node in volts, keyed by node name like nodeflux, when the analysis has a zero frequency mode; otherwise nothing. This is distinct from the zero mode of nodeflux, which is the static flux setting the inductor currents and junction phases. A vector of zeros is an answer (a node shorted to ground sits at zero volts, and so does every node of a circuit into which no direct current is injected) and differs from nothing.

source
JosephsonCircuits.NonlinearInductor Type
julia
NonlinearInductor(L0, cpr, dcpr)
NonlinearInductor(L0, cpr)

A two terminal nonlinear inductive element defined by its current-phase relation: I(φ) = (phi0/L0)*cpr(φ) where φ is the reduced branch phase, L0 is the small signal inductance in Henries, and cpr is a callable with unit slope at zero. dcpr is the derivative of cpr, required by the harmonic balance Jacobian; it must be supplied explicitly for user defined callables, while built-in CPRs (sin, PolynomialCPR) provide analytic derivatives through cprderivative.

This supports specifying the effective nonlinearity of a SNAIL, SQUID, or Quarton directly, as an alternative to composing the underlying junctions. A quadratic term in the relation is what makes such an element a three wave mixer, which the Josephson relation, being odd, is not.

The relations the solvers evaluate are the sinusoidal Josephson one, which is what JosephsonJunction writes, and a PolynomialCPR; another callable is refused when the circuit is compiled. The element is a junction to everything else in the solvers: it makes the same branch, enters the same matrices, and L0 is its inductance there, so only the pointwise relation differs. Harmonic balance evaluates it, in the residual, in the Jacobian, in the Hessian and in the pump modulation of the linearized system, and the transient solver steps it, in its residual, its Jacobian, its tangent and adjoint, and the linearization its noise is taken about.

See also JosephsonJunction.

source
JosephsonCircuits.NonlinearTermPlan Type
julia
NonlinearTermPlan{Ti<:Integer,T<:Real,VI,VT,VC,VF,KF,KB,KFC,KBC,KRC,KCR,B}

Fully precomputed, device-generic plan for the two linear maps which surround the pointwise time domain nonlinearity of the harmonic balance system:

  • the map A from the unknowns to the frequency domain coefficients of the Josephson junction branch fluxes, which folds together the real to complex conversion of the equivalent real representation, the incidence matrix product Rbnm*z, the gather onto the Josephson branches, and the packing into the array the inverse real transform consumes (phivectortomatrix!), and

  • the map B from the frequency domain coefficients back to the node vector, which folds together the unpacking (phimatrixtovector!), the Lscale/Lj branch scaling, the transposed incidence matrix product, the frequency dependent linear term K, and the complex to real conversion.

Both are expressed, in the complex representation and in the equivalent real one, as KernelAbstractions kernels in which one work item owns one output slot and reads only precomputed index maps, so neither contains a scatter, an atomic, or a write conflict, and both run unchanged on a device once the arrays are moved there. The maps are fixed at the sparsity structure and mode frequencies of the system, so they are built once by plannonlinearterm. The topology of the maps does not depend on the representation, so the two share the incidence entries and the Josephson segment lists and differ only in how a source is addressed and in which form of the linear term matrix they gather.

Only the pointwise time domain function between the two maps distinguishes the entry points of the system, so one plan serves all of them:

entry pointbetween the transformslinear term
residual!sin(phitd)+ K*x - b
jacobianvectorproduct!cos(phitd) .* dirtd+ K*v
hessianvectorproduct!-sin(phitd).*dirtd.*dirtd2none

Fields

The forward map stores, per slot of the frequency domain array, the at most two entries of the corresponding row of the incidence matrix. A row of a branch incidence matrix has at most two entries because a branch is an edge and one of its two nodes may be the ground node, so no segment structure and no inner loop is needed:

  • n1, n2: the real slot holding the real part of the source node flux, or zero when the entry is absent.

  • cn1, cn2: the same entries addressed as complex indices, for the complex representation.

  • s1, s2: the corresponding incidence matrix entries.

  • flags: FCONJ when the slot is a conjugate symmetry target and FWIDE when the source mode is not self conjugate, so its imaginary part occupies the next real slot.

The backward map stores, per complex output index, a segment of contributions gathered from the frequency domain array, and the linear term in compressed sparse row form:

  • bptr, bsrc, bcoef: the segment of frequency domain slots of the Josephson branches incident to that node, with the incidence matrix entry times Lscale/Lj as the coefficient.

  • kptr, kidx, kcoef: the real form of the linear term matrix K, stored transposed so applying it is a gather over the entries of one output row. Empty when the plan was built with realbackward = false, which hasrealbackward reports.

  • cptr, cidx, ccoef: the same for the complex form of K.

  • kptrzero, cptrzero: the row pointers of an empty linear term of each form, for applying the Josephson part alone.

  • lptr, lwide: the first real slot of each complex index and whether that mode is not self conjugate.

  • forward!, backward!, forwardcomplex!, backwardcomplex!, realtocomplex!, complextoreal!: the compiled kernels of the two maps in each representation and of the conversions between them.

  • backend, nslots, ncomplex: the backend, the number of real slots and the number of complex indices.

source
JosephsonCircuits.NonlinearTermTransposePlan Type
julia
NonlinearTermTransposePlan

The transposed gather maps of a NonlinearTermPlan, and the two kernels which apply them. Built once by plannonlineartermtranspose. See hbvjp!.

Fields

  • tbptr, tbnode, tbcoef: per frequency domain slot, the segment of complex node indices which gather that slot in the backward map, with the same coefficients. The transpose of the Josephson contribution.

  • tfptr, tfslot, tfcoef, tfimag: per real slot of the unknowns, the segment of frequency domain slots which read it in the forward map. tfcoef carries the incidence entry with the FCONJ sign and the conjugate multiplicity s already folded in; tfimag says whether the entry reads the imaginary rather than the real part of the slot.

  • ktptr, ktrow, ktcoef: the transpose of the real form of the linear term, gathered by output index.

  • gtscale: the conjugate multiplicity of each frequency domain slot, one for a bin whose conjugate partner is also stored (the zero and Nyquist frequencies of the first dimension, the only one the real transform truncates) and two otherwise.

  • backwardtranspose!, forwardtranspose!: the compiled kernels.

  • backend, nslots, rdim: the backend, the number of frequency domain slots and the real dimension of the unknowns.

source
JosephsonCircuits.OpenDC Type
julia
OpenDC()

A ScatteringParameters which is an open circuit at zero frequency: S(0) = I, so no direct current flows through any port. This is the constant of a series capacitance and of anything else which blocks direct current.

source
JosephsonCircuits.PaddedLinearTerm Type
julia
PaddedLinearTerm

The frequency dependent linear term of the augmented system, padded to the auxiliary variables with the modified nodal analysis augmentation folded in, together with the index maps which refill it from a new assembly of the unpadded matrices. A sweep over component values builds this once and then moves values only: the padding, the union with the augmentation and the incidence matrix's empty columns are structure, which the values do not change (see hbcache).

Fields

  • Rbnm: the incidence matrix with its empty auxiliary columns.

  • invLnm, Gnm, Cnm: the padded matrices, invLnm with Amna added.

  • Amna: the augmentation, whose only value dependent entries are the coupled inductor rows of calcAmnaind.

  • pind: the positions of those rows' entries in nonzeros(Amna).

  • pinv, pamna: the positions of the unpadded inverse inductance entries and of Amna's entries in nonzeros(invLnm).

  • bnm: the drive in the padded node basis.

  • wmodesm, wmodes2m: the mode frequency diagonals over the padded system.

  • stampedblocks: the scattering blocks as stamped, which the direct current path reads.

source
JosephsonCircuits.PaddedLinearTerm Method
julia
PaddedLinearTerm(Rbnm, invLnm, Gnm, Cnm, Amna, AmnaL, invLnm0, bnm,
    wmodesm, wmodes2m, stampedblocks)

Record a padded linear term as hbnlsolve assembled it, with the unpadded inverse inductance invLnm0 and the coupled inductor rows AmnaL it was assembled from, so that refill! can reproduce the assembly at new values. Returns nothing when the coupled inductor rows share an entry with the rest of the augmentation, which a refill by overwrite could not reproduce exactly.

source
JosephsonCircuits.PairTerm Type
julia
PairTerm

One ordered pair (a, b) of bath frequencies of a pumped block's group, with the four real blocks of the covariance of its quadratures, E = (xx, xp, px, pp), from the normal correlator N = <A_a A_b'> and the anomalous one M = <A_a transpose(A_b)> of the complex amplitudes A = x - i p of the block's noise wave at the two frequencies, xx = Re(N + M)/2, pp = Re(N - M)/2, xp = (Im N - Im M)/2, px = -(Im N + Im M)/2, and the same four blocks C of the commutator with N and M replaced by 2i times the commutators of the amplitudes. N can be nonzero when the frequencies differ by a multiple of the pump frequency and M when they sum to one, both read from the block's noise over the family of the bath frequencies, its harmonic covariances and the commutator of its multi-mode scattering matrix as pumpednoisematrices assembles and completes them over the modes of a solve at once (see bathfamily), so the two solvers share one definition of the block's noise.

source
JosephsonCircuits.ParsedLevel Type
julia
ParsedLevel

The normalized form of one circuit level, what the elaboration reads: the component table, the connection groups, the interface pins, the ground ties and the mutual inductors, each with names resolved to instance indices and terminals. Built by parsecircuitlevel.

source
JosephsonCircuits.Passive Type
julia
Passive()

The default noise model for a ScatteringParameters: the block is a passive network with no locally specified noise, so what it adds is set by what it absorbs and by the temperature the analysis is run at. A dissipative block adds noise of covariance I - S S' (see ScatteringNoisePlan), scaled by the thermal factor of the temperature or temperatures given to the analysis, which default to zero temperature and so to the vacuum covariance itself.

Saying nothing here is what keeps temperature out of a component definition which several analyses share. ThermalEquilibrium is how a block states its own temperature instead.

source
JosephsonCircuits.PerturbationEntries Type
julia
PerturbationEntries

The stored entries of one kind of derivative of the components, for the contraction of an adjoint: the forcing of component c is -dM_c A for the derivative dM_c and the state A its kind reads, so its contraction against the multipliers M is the sum over the entries (i, j, v) of dM_c of -v A[j] M[i], taken as the gather of the rows j of A and i of M by two selection matrices, their product, and the sum into the components by a matrix carrying the values, every one the size of the entries.

source
JosephsonCircuits.PiecewiseTabulatedProvider Type
julia
PiecewiseTabulatedProvider(tables::Vector{TabulatedMatrixProvider})

Tabulated data in several disjoint bands, each a TabulatedMatrixProvider over its own frequencies, evaluated by the band a frequency falls in and zero between and beyond them, the data of a response known only in the bands it was sampled over. The harmonic transfer functions of a LinearizedScattering block built from a solve are of this kind: the signal band shifted by every harmonic of the pump, with nothing in between, across which one spline would swing wildly.

source
JosephsonCircuits.PinRef Type
julia
PinRef(instance, key)

An explicit reference to the scalar pin or terminal key of the component instance instance, for use when a bare (instance, key) tuple would be ambiguous between a scalar pin and a port.

source
JosephsonCircuits.PolynomialCPR Type
julia
PolynomialCPR(coefficients)

A current-phase relation (CPR) specified by the coefficients of its polynomial expansion f(φ) = coefficients[1]*φ + coefficients[2]*φ^2 + ..., where φ is the reduced branch phase. The linear coefficient must equal one so that the L0 of the containing NonlinearInductor is the small signal inductance. The object is callable and its analytic derivative is available through cprderivative.

This supports specifying the effective nonlinearity of a SNAIL, SQUID, Quarton, or kinetic inductor directly through its expansion coefficients without wiring up the underlying junction arrangement. An array of N identical junctions in series, for example, divides the phase and so has the relation N*sin(φ/N) with small signal inductance N*Lj, whose expansion is [1, 0, -1/(6N^2), 0, 1/(120N^4), ...].

The coefficients are taken as given. A polynomial is not periodic and not bounded, so where it leaves the range it was fitted on, and what the harmonic count must be for the harmonics its degree generates, are the user's to judge: the solver evaluates what it is given.

Examples

julia
julia> p = PolynomialCPR([1.0, 0.0, -1/6]); p(0.1)
0.09983333333333333

julia> JosephsonCircuits.cprderivative(p)(0.0)
1.0
source
JosephsonCircuits.PolynomialCPRDerivative Type
julia
PolynomialCPRDerivative(a)

The analytic derivative of a PolynomialCPR, produced by cprderivative. Callable.

source
JosephsonCircuits.Port Type
julia
Port(number::Integer; Z0 = 50.0,
    termination = JosephsonCircuits.MatchedTermination())

An analysis port with the port number number and reference impedance Z0 in Ohms. A Port identifies an electrical port for excitation and observation; excitation amplitudes belong to the analysis arguments, not to the circuit topology.

By default the port owns a matched external source and load environment of impedance Z0 acting across its two terminals, so a port needs no resistor to define its impedance. The environment acts between the port terminals and is never tied to Ground on its own, so a differential port behaves the same way as a ground referenced one.

termination = nothing keeps Z0 for wave normalization but adds no physical loading, which is the right form when the circuit already contains the resistor that terminates the port. Such a port is an ideal current source and an impedance probe: a source on it drives its whole current into the circuit, and since the incident wave is that of the source current with nothing to absorb it, the reflection reported at the port is S = 2Z/Z0 - 1 with Z the impedance across its terminals, so the impedance at the node is Z = Z0 (1 + S)/2.

Any further Resistor across the same terminals is an ordinary device resistor: it loads the port in parallel with the environment, it remains a dissipative noise source, and it is never mistaken for the port's own environment.

Examples

julia
julia> Port(1)
Port(1; Z0 = 50.0)

julia> Port(2; Z0 = 1000.0, termination = nothing)
Port(2; Z0 = 1000.0, termination = nothing)
source
JosephsonCircuits.PortDiagonal Type
julia
PortDiagonal(values, rows = Colon())

A port argument handed to a conversion kernel as the diagonal matrix of its values at the frequency, restricted to the ports rows: values is a vector with one value per port, the same at every frequency, or a matrix with one row per port and one column per frequency. See convertperfrequency!.

source
JosephsonCircuits.PortRef Type
julia
PortRef(instance, key)

An explicit reference to the bundled two terminal port key of the component instance instance, for use in pair connections when a bare (instance, key) tuple would be ambiguous between a scalar pin and a port.

source
JosephsonCircuits.PreconditionerPlan Type
julia
PreconditionerPlan

The structural ingredients from which a ModeCouplingPreconditioner rebuilds its pattern, its assembly plan and its values for a new coupling set (buildcoupling) and sizes the factors a coupling set would take (couplingbytes): the Jacobian index matrices, the incidence matrix, the counts, the mode layout, the mode offsets and the requested precision. Everything with a value in it is read from the system at the time of the rebuild, so a system rebound to new values is what a rebuild sees. A plain struct rather than closures over the constructor's locals, so that a preconditioner's type depends on its system's type alone and not on the types of a dozen captured variables; the two parameters, the mode offsets (whose tuple length is the tone count) and the precision, are what a rebuild dispatches on.

source
JosephsonCircuits.Probe Type
julia
Probe()

Decide each rebuild by measurement: one application of the stale preconditioner to the residual and one product give the one-step reduction rho = |J P^-1 F - F|/|F|; the same measurement on the fresh preconditioner, with the Arnoldi count k_fresh of its solve, calibrates the prediction k = k_fresh log(rho_fresh)/log(rho) of the stale solve's Arnoldi count, and the rebuild is skipped when k steps at the measured cost of a step are cheaper than the measured rebuild plus a fresh solve. Everything is measured, so the rule adapts to the device and the factorization; it pays when a rebuild is expensive next to a solve, as with a BlockFactorization of three tones, where it saved a fifth to a third of the time. A rebuild forced by a failed, stalled or non-descent solve is never skipped. Because the decision rests on measured times, the path a solve takes, and the answer within the tolerance, can differ between two runs of the same problem; the default Always is reproducible.

source
JosephsonCircuits.QRfactorization Type
julia
QRfactorization(; kwargs...)

The AbstractFactorization using the SPQR sparse QR factorization LinearAlgebra.qr, with kwargs passed to it. QR does not support refactorization in place, so each call factorizes from scratch.

source
JosephsonCircuits.QuasiNewton Type
julia
QuasiNewton(; anderson = 5, factorization = nothing,
    linesearch = Backtracking())

The holomorphic Jacobian approximation with Anderson acceleration of depth anderson (the maximum number of previous iterates used for the extrapolation; less than one disables it), factorized by factorization (the host's KLU when nothing), the length of every step chosen by linesearch, a Backtracking, interpolating by default; the curvilinear search of a rejected Anderson candidate follows it too. The harmonic balance residual is not complex differentiable, so this Jacobian is an approximation.

The zero frequency flux is complex

This method solves for a complex flux at every mode, the zero frequency mode included, so the imaginary part of a node's zero frequency flux is not held at zero and the converged value can carry a spurious imaginary part. The real part is the direct current flux; read only that, and prefer Newton or NewtonKrylov, which solve the real system, for a circuit with a direct current bias.

source
JosephsonCircuits.RationalScatteringProvider Type
julia
RationalScatteringProvider(A, B, C, D)

A scattering matrix given as the real state space realization S(s) = D + C (s I - A)^(-1) B of a passive rational multiport, the form a vector fit of measured or simulated scattering data takes and the one the transient solver realizes in time, dz/dt = A z + B a, b = C z + D a on the incident and reflected power waves. Evaluated at a signed angular frequency by one dense solve, without forming an inverse. Built by RationalScattering, which validates it.

source
JosephsonCircuits.Resistor Type
julia
Resistor(R; temperature = nothing)

A two terminal linear resistor with resistance R in Ohms. Terminals are 1 and 2. The value may be a number or a symbolic variable.

temperature is the physical temperature in Kelvin, which sets the noise a dissipative instance adds. nothing, the default, takes the temperature the analysis is run at.

Examples

julia
julia> Resistor(50.0)
Resistor{Float64}(50.0, nothing)

julia> Resistor(50.0; temperature = 4.0).temperature
4.0
source
JosephsonCircuits.ReverseSensitivity Type
julia
ReverseSensitivity(op::HBOperatingPoint, lsys, dFr,
    slots = collect(1:size(dFr, 2)))

Precompute the reverse mode contraction data: the branch flux map (calcbranchtimedomainmap), the transform of the pump harmonic grid, the row and the column of each nonzero of the linearized system matrix, and the offset of each entry of the augmented state in its real representation. dFr holds the residual derivative columns and slots[k] is the output slot of Ssensitivity column k accumulates into, so that several columns belonging to one design parameter can share a slot.

source
JosephsonCircuits.ReverseSensitivity Type
julia
ReverseSensitivity(op, dFr, T, fftplan, nzrow, nzcol, realindexmap,
    branchnodes, slots)

Everything the reverse mode contraction of calcSsensitivityreverse! needs, precomputed once and shared read only across the signal frequencies.

source
JosephsonCircuits.ReverseSensitivityBuffers Type
julia
ReverseSensitivityBuffers(rev::ReverseSensitivity, NPM::Integer)

The mutable work arrays of one invocation of calcSsensitivityreverse!, allocated once per batch of signal frequencies rather than at every frequency. Each thread of hblinsolve owns its own set; the ReverseSensitivity itself is shared read only.

source
JosephsonCircuits.ScatteringDC Type
julia
ScatteringDC(S0)

A ScatteringParameters whose zero frequency scattering matrix is stated as S0, which must be real, finite, and of the block's dimension.

Every realizable zero frequency behavior is one of these: a resistor, a transformer, an attenuator, and the open, short and through the named models are shorthand for. It is validated for passivity when the containing ScatteringParameters is constructed, with that block's atol, on the same terms as the block's own data, so an active zero frequency model needs the same NoiseCovariance declaration an active block does.

source
JosephsonCircuits.ScatteringLimit Type
julia
ScatteringLimit()

The default zero frequency model of a ScatteringParameters: its own scattering data, evaluated at zero frequency.

The result must be real and finite there. A block whose limit exists but is not evaluable at zero – a series capacitance written 1/(im*w*C), whose limit is the open circuit – has to state that limit with one of the other models rather than be asked for it.

source
JosephsonCircuits.ScatteringNoisePlan Type
julia
ScatteringNoisePlan

The vacuum noise channels of the dissipative ScatteringParameters components of a circuit: which blocks of a ScatteringStampSystem carry noise and where their channels sit in the rows of the noise scattering matrix.

A block which absorbs must add noise, or its output would violate the commutation relations. In the wave domain its constitutive equation is b = S a + n with an added noise wave whose vacuum covariance is I - S S', and in the hybrid stamp

julia
im*w_m*scale*B(w_m) phi - C(w_m) i = 2 n

that noise is a source in the auxiliary port current rows. A block with n ports therefore carries n noise channels, one per column of the triangular factor of I - S S' (psdcholesky!); those of a lossless block are identically zero, so only blocks which are not provablylossless are given channels.

A block which states its noise with a NoiseCovariance V, which is how an active block declares it, carries 2n channels: n from the factor of (V + K)/2 with K = I - S S', which emit like modes in their vacuum, and n from the factor of (V - K)/2, which emit like the conjugates of modes and enter the commutation relations with the opposite sign (see noisechannelsigns). Their sum is V, their difference K, so the block adds the noise it states and its output obeys the commutation relations, and neither kind carries a temperature.

The channels of the blocks follow the noise ports of the dissipative lumped components in the rows of Snoise, with the same channel-major-mode-minor ordering.

source
JosephsonCircuits.ScatteringNoiseWorkspace Type
julia
ScatteringNoiseWorkspace()

The scratch of scatteringnoisewaves!: the scattering parameters at the mode frequencies, the noise covariance and its factor in one flat array, and the buffer of unsigned frequencies. Reused across frequencies by one worker.

source
JosephsonCircuits.ScatteringParameters Type
julia
ScatteringParameters(S; nports = nothing, zref = nothing, grounded = true,
    noise = Passive(), negative_frequency = ConjugateSymmetry(),
    interpolation = :cubic, extrapolation = :error, form = :matrix,
    derivatives = NamedTuple(), dcmodel = ScatteringLimit(),
    atol = 1e-8)

A multiport component defined by its scattering parameters. S may be:

  • a constant matrix;

  • a callable of angular frequency returning a matrix (requires nports);

  • a tuple (frequencies, values) of tabulated data with frequencies in radians per second and values of size (nports, nports, nfrequencies);

  • a path to a Touchstone file, from which the reference impedance is also read.

Tabulated data is interpolated with the cubic spline through each entry's samples (interpolation = :cubic, the default; :linear takes the chords between them, which lag a rotating phase) and is never extrapolated unless asked: extrapolation is :error by default, with :constant and :linear to opt in. The harmonic balance solvers evaluate a block wherever their mixing products fall, which can be far outside the band the data covers, so measured data meant for them is better fitted with RationalScattering, which extrapolates as a passive rational function and is passive at every frequency by construction, where any interpolant of passive samples can stray between and beyond them.

zref is the reference impedance in Ohms, a scalar broadcast to all ports or a vector with one entry per port. For a Touchstone file the reference impedance is read from the file, and a zref which disagrees with it is an error, since the intent is ambiguous between correcting a mislabeled file and requesting renormalization. Scattering data is used at its native reference impedance; no renormalization of the data is ever performed when stamping, and conversion to analysis reference impedances happens only in the wave domain at analysis boundaries.

With the default grounded = true every reference terminal is automatically tied to Ground and (:instance, p) in a connection group addresses the signal terminal of port p; explicitly connecting a reference terminal of a grounded block is an error. With grounded = false each port p has terminals 1 (signal) and 2 (reference), addressed as (:instance, p, t), and ports may be floating or differential.

noise is Passive (default), Lossless, ThermalEquilibrium, or NoiseCovariance. A dissipative block adds noise, which the noise scattering parameters, the quantum efficiency and the commutation relations account for. A NoiseCovariance states the added noise outright, which is what an active block, an amplifier given by its scattering parameters, needs, and is held to the minimum the commutation relations require of it. Lossless is how a unitary callable says so, since unlike stored data it cannot be checked. negative_frequency is ConjugateSymmetry (default) or Native. form says how a callable S is called; see CallableMatrixProvider. Passivity of constant and tabulated scattering data is validated at construction with absolute tolerance atol unless the noise model is a NoiseCovariance, which permits active blocks.

dcmodel states the block's zero frequency behavior when its own data does not give it: OpenDC, ShortDC, ThroughDC or ScatteringDC, defaulting to ScatteringLimit, which evaluates the block at zero. Measured data which starts at gigahertz has no zero frequency entry, and a closed form whose limit exists may not be evaluable there – a series capacitance written 1/(im*w*C) is an open circuit at direct current and infinite at zero – so those state the limit instead. The model is used only by the direct current rows; the alternating current path always uses the block's own data.

derivatives supplies analytic derivatives of the scattering matrix with respect to design parameters, for designsensitivities: a named tuple keyed by parameter name whose values are accepted in the same forms as S (a matrix, a callable of angular frequency, or tabulated data). A parameter the block depends on but has no entry for is differentiated by central finite differences through S instead. A derivative is not a scattering matrix and is never passivity checked. derivatives and form apply when S is given as data or a callable; a Touchstone path ignores them.

Examples

julia
julia> ScatteringParameters([0 1;1 0]).nports
2
source
JosephsonCircuits.ScatteringStampSystem Type
julia
ScatteringStampSystem

The contribution of the ScatteringParameters components of a parsed circuit to the harmonic balance system matrix, as hybrid (wave to modified nodal analysis) stamps: one auxiliary port current variable per port and mode, the constant Kirchhoff current law couplings kcl of those currents into the node equations, and the constitutive equations

julia
im*w_m*scale*B(w_m) phi - C(w_m) i = 0

per port and mode, whose frequency dependent coefficient entries are described by the sparsity pattern plus, per scalar contribution, the block, port pair, sign, mode, destination index, and which coefficient (B, stamped with the im*w_m*scale factor of a voltage in the node flux basis, mirroring the constitutive equations of the promoted port resistors, or C, stamped as -C). The contribution is diagonal in mode space because a linear time invariant multiport cannot convert frequencies; all mode coupling in the system comes from the junction pump modulation term. This representation exists for every scattering matrix (see evaluatehybrid!); no admittance conversion is performed.

The values side is a pure gather-add over precomputable per (block, mode) coefficients, so the values are computed here and a device adds them with a kernel; see DeviceScatteringStamps.

Fields

  • blocks: the StampedScatteringBlocks.

  • kcl: the constant Kirchhoff current law couplings of the auxiliary port currents, folded into the modified nodal analysis augmentation.

  • pattern: the sparsity pattern of the constitutive rows.

  • patternindex, Aindex: where each stored entry of pattern lands in the system matrix, and the stored position it is added at.

  • blockindex, pindex, qindex, modeindex: for each contribution, the block, the port pair and the mode it reads its coefficient from.

  • coeff, sign: the per contribution coefficient buffer and sign.

  • Nmodes, Nauxports: the mode count and the number of auxiliary port current unknowns.

  • scale: the solver scale the rows are written in.

  • iscale: the scale of the auxiliary port current unknowns. The stored unknown is i/iscale, so every auxiliary column is iscale times the unscaled one; with iscale one over the solver inductance scale (see auxcurrentscale) a port current is written in the same units as a node flux. The outputs are unaffected: they are read from the nodal components of a solution, and the block noise is contracted against the auxiliary rows of an adjoint solution, which a scale on the unknowns leaves alone. Anything which reads a forward auxiliary component as a current multiplies it by iscale.

source
JosephsonCircuits.ScatteringWorkspace Type
julia
ScatteringWorkspace()

Reusable scratch for scatteringvalues!: a HybridWorkspace and the coefficient arrays of every block.

Those arrays have to be live at once, because the contributions are ordered by their destination in the system matrix rather than by block, so they cannot be one buffer reused block by block. They can be reused from one frequency to the next, which is what this is for: a sweep over a line whose every cell is its own block otherwise allocates two arrays per block at every signal frequency.

A workspace is written by every call, so it belongs to one task. A caller which sweeps on several threads gives each one its own.

source
JosephsonCircuits.SensitivityStamp Type
julia
SensitivityStamp(kind, rows, cols, vals, portindex, parameter, portscale)
SensitivityStamp(kind, rows, cols, vals, portindex)

The derivative of the linearized harmonic balance system matrix with respect to a relative (logarithmic) perturbation of one component value, p -> r*p evaluated at r = 1. The system matrix is affine in C, 1/R, 1/L and 1/Lj, so the derivative is that component's own contribution to the system matrix, with a sign: positive for the capacitance and negative for the quantities which enter inversely.

kind selects how the stamp is assembled at each signal frequency, mirroring assemblesystemmatrix!:

  • :C: -vals*wmodes2m, the component's capacitance matrix,

  • :G: -im*vals*wmodesm, the component's conductance matrix,

  • :invL: -vals, the component's inverse inductance matrix,

  • :Lj: the constant values, the negative of the pump modulated Josephson contribution of that junction alone,

  • :S: the derivative stamp of a scattering block (blocksensitivitystamp).

The stamp is the triplet (rows, cols, vals) of the component's own contribution, built by tripletstamp, and each value is scaled by the mode frequency of its column at assembly. portindex is the index of the port whose impedance this component is, or zero, which selects the additional wave normalization term of calcSsensitivity!.

parameter is the design parameter this stamp contributes to, or zero for the legacy relative form where every component is its own output slot. portscale is (dZport/dtheta)/Zport for a port impedance stamp, one for the relative form.

source
JosephsonCircuits.ShortDC Type
julia
ShortDC()

A ScatteringParameters each of whose ports is shorted to its own reference terminal at zero frequency: S(0) = -I. The port voltages are held at zero and the currents are whatever the rest of the circuit sends, which is the ideal short the direct current rows are written to express.

source
JosephsonCircuits.SizedPreconditioner Type
julia
SizedPreconditioner(pc, n)

A preconditioner carrying its dimension, so it satisfies the size/ eltype/mul! contract external Krylov solvers check.

source
JosephsonCircuits.SolverInfo Type
julia
SolverInfo(stages, initialresidual, finalresidual, converged,
    sourcefold)

Diagnostics describing the nonlinear solution process of hbnlsolve.

Fields

  • stages: a vector of per-stage records (subtypes of AbstractStageInfo), one for each invocation of the nonlinear solver, in the order they ran. The direct and Krylov solvers push IterationInfo; method = Staged() pushes one StagedStageInfo per attempted continuation stage, each carrying its inner solver records. Every record has label, converged and iterations fields; the rest is method specific.

  • initialresidual: the norm of the residual at the initial value.

  • finalresidual: the norm of the residual at the returned solution.

  • converged: whether the solver reported convergence.

  • sourcefold: NaN, except for a Staged solve which found the solution branch ending below the requested drive, where it is the last drive fraction the continuation converged at.

source
JosephsonCircuits.SourceTuple Type
julia
SourceTuple{N}

The canonical form of a source: a named tuple (mode, port, current) with the mode as N integers, one harmonic index per tone, the port as an integer and the current as a complex number. See sourcetable.

source
JosephsonCircuits.SparseBlockFactorization Type
julia
SparseBlockFactorization

The BlockFactorization of a sparse matrix whose unknowns come in node blocks: the matrix of the linearized solve, Nmodes unknowns per circuit node (and per auxiliary variable of the modified nodal analysis), whose sparse LU has the block structure of the matrix itself. Built by factorize from the pattern: the node graph is read off the pattern (blocknodegraph), ordered by KLU (klunodeorder), amalgamated into supernodes (clustersymbolic), and every stored entry of the matrix is mapped once to its place in a diagonal block or a panel, so a refactorization is one scatter of the stored values and one block LU.

The factorization holds nb systems with the one pattern, the frequencies of a batch of a device sweep (one on the host): every block is an array (rows, columns, nb) and every dense operation of the factorization and the solves is one batched call over the batch (batchedinverse!, batchedmul!), which is what fills a device with the many small blocks of a chain. Solves take a right-hand side shared by the batch or one per system, a GEMM per block, and the transposed system from the same factors; factors in single precision refine against the double residual formed from the matrix's own blocks kept in double (blockresidual!), at close to twice the memory, since the originals cost as much as the single precision factors.

Fields

  • lu: the BlockLU, the factors and the Schur schedule shared with the preconditioner's clusters; blocksize: the node block size.

  • fills: per block, the stored entries which land in it.

  • original: the matrix's own blocks in its precision when refining.

  • scale, diagidx: the equilibration of single precision factors, the symmetric diagonal scaling by the inverse square roots of the diagonal magnitudes, which brings a linearized matrix's entries (inverse inductances against capacitances times squared frequencies) to order one before single precision arithmetic sees them; nothing in double.

  • A: the sparse pattern matrix; refine and refinesteps: whether the solves refine against the double residual and the most steps they take; backend; work: the work arrays of the last right-hand side width.

source
JosephsonCircuits.SpiceRaw Type
julia
SpiceRaw(header::SpiceRawHeader, variables::Dict{String, Vector{String}},
    values::Dict{String,T})

A simple structure to hold the SPICE raw file contents including the header, variables, and values.

source
JosephsonCircuits.SpiceRawHeader Type
julia
SpiceRawHeader(title::String, date::String, plotname::String,
    flags::String, nvariables::Int, npoints::Int, command::String,
    option::String)

A simple structure to hold the SPICE raw file header.

source
JosephsonCircuits.StageCorrection Type
julia
StageCorrection

The exact stage solve of a circuit with a pumped block. The frozen operator of a step carries the block's converted coupling at the mean of the two stages' weights (see refreshstageoperator!); what is left, the difference of each stage's weights from the mean, acts on the block's port rows alone, so the true stage operator is the frozen one plus a correction of rank twice the block's ports, J = J* + U V', with U the scatter onto the block's rows at each stage and V' the difference of the weights times the output terms on the stacked states from the stage unknowns. It is taken exactly by the Woodbury identity: K = J*^(-1) U by one solve per column of U on the step's factorization, M = I + V' K per column of the batch, and a solve c = J*^(-1) r is corrected to c - K M^(-1) V' c; the transposed operator, which the adjoint solves, has U and V exchanged. A converted coupling as large as the unconverted one, an amplifier's, would not converge on the frozen operator alone.

source
JosephsonCircuits.Staged Type
julia
Staged(; grids = nothing, s0 = 0.5, smin = 0.02, interioratol = 1e-7,
    interioriterations = 60, inner = NewtonKrylov(),
    interiorescalation = false, maxattempts = 60, verbose = false)

Source continuation on an adaptively grown harmonic grid, with inner solving every stage; see stagedhbnlsolve for the keywords. grids is the ladder of retained harmonic caps, nothing for the default ladder of the problem's Nharmonics.

source
JosephsonCircuits.StagedStageInfo Type
julia
StagedStageInfo

One attempted stage of stagedhbnlsolve. Every attempt is stored in solverinfo.stages of the returned solution in the order it ran, including stalled steps and growth retreats, so the whole continuation walk can be examined afterwards.

Fields

  • label: "staged".

  • converged: whether this attempt's inner solve converged.

  • iterations: total inner Newton iterations of the attempt.

  • grid: the harmonic truncation the attempt solved on.

  • sfrom: the last accepted drive fraction before the attempt.

  • starget: the drive fraction the attempt targeted.

  • ds: starget - sfrom (negative for a growth retreat).

  • action: :advance (drive step on the current grid), :grow (a solve on a newly grown grid after carrying a converged point up, and the drive retreats which follow it, including the retreat on the finest grid which never changes the grid), or :final (the full-drive solve on the finest grid).

  • accepted: whether the attempt's result was kept as the new operating point (a stalled attempt is recorded but not accepted).

  • seconds: wall time of the attempt, including the stage's system assembly.

  • finalresidual: the residual norm the attempt ended at.

  • inner: the inner solver's own stage records (IterationInfo), with their Krylov linear-solve diagnostics when the inner method is a NewtonKrylov.

source
JosephsonCircuits.StampedScatteringBlock Type
julia
StampedScatteringBlock

One scattering block instance, with the nodes its ports attach to and the position of the auxiliary port current variables which carry its currents.

auxbase locates them: port p at mode m is the state index auxbase + (p-1)*Nmodes + m. That is the same current the zero frequency row treats as an unknown, which is how a block becomes visible at direct current; see DCBlockRows.

source
JosephsonCircuits.StructureComplexJacobianPlan Type
julia
StructureComplexJacobianPlan{TJ,VT}

The complex Jacobian on a backend: the Josephson map of StructureComplexJosephsonPlan and the constant linear term gathered once, which is what assemblecomplexjacobian! adds to it.

source
JosephsonCircuits.StructureComplexJosephsonPlan Type
julia
StructureComplexJosephsonPlan{Ti,VI,VT,MI,K,B}

The Josephson contribution to the complex Jacobian, as a linear map from the Fourier coefficients of cos(phi(t)) to the stored entries of a matrix with a given structure.

This is what replaced the two segmented gathers of the earlier complex plan used to hold, one entry per contribution. It is used both to assemble the Jacobian and on its own, as the map applied to other coefficient arrays by the linearized solve, which is why it is a plan for the Josephson term rather than for the whole Jacobian.

Fields

  • colptr, rowval: the stored structure, the transpose when transposed.

  • junctions: the JunctionStructure, of which the pair table, the junction coefficients and ami are read.

  • perrow, transposed: as in StructureRealJacobianPlan.

  • assemble!, backend: the compiled kernel and its backend.

  • n: the number of stored entries.

source
JosephsonCircuits.StructureRealJacobianPlan Type
julia
StructureRealJacobianPlan

Everything the structure aware assembly reads, on a backend. There is no segmented gather here and nothing proportional to the number of contributions: the largest arrays are the sparsity structure and the precomputed linear term, both of which are one entry per stored entry of the Jacobian rather than one per contribution.

Fields

  • colptr, rowval: the stored structure, which is the Jacobian's transpose when transposed, so that a column of it is a row of the Jacobian.

  • lin: the constant frequency dependent linear contribution.

  • junctions: the JunctionStructure, the incidence triple product, the junction coefficients and the mode coupling index matrices, shared with every other plan of the system.

  • perrow: whether the assembly runs one work item per stored row rather than per stored entry, which is the better trade on a host.

  • transposed: whether the stored structure is the Jacobian's transpose, which it is on a device and is not for a matrix meant to be factorized directly.

  • rlinv, rlptr, clinv, clptr: the mode layout and its inverse, which turn a stored entry back into a (node, mode) pair.

  • assemble!, backend: the compiled kernel, sized at plan time, and the KernelAbstractions backend it runs on.

  • n: the number of stored entries, checked by assemblerealjacobian!.

source
JosephsonCircuits.TabulatedMatrixProvider Type
julia
TabulatedMatrixProvider(frequencies, values; interpolation = :cubic,
    extrapolation = :error)

A matrix provider for tabulated data. frequencies is a strictly increasing vector of angular frequencies in radians per second and values is an array of dimensions (n, n, length(frequencies)).

interpolation may be :cubic (the default) or :linear. Cubic interpolation evaluates the cubic spline through each entry's samples, which follows a rotating phase far more closely than the chords between them; a table too short for a cubic takes the highest order it determines, the parabola through three samples or the line through two. A spline can overshoot between samples, so a quantity bounded in the data – a scattering entry's magnitude, say – can exceed the bound a little between them; a bound guaranteed at every frequency takes a passive fit, see RationalScattering.

extrapolation may be :error (the default), :constant, :linear or :zero. With :error, any requested frequency outside the tabulated range throws an error listing the offending frequencies; extrapolation of tabulated data is deliberately opt-in. :constant holds the end values beyond the ends, :linear continues from them with the interpolant's end slopes, and :zero is zero beyond them, the data of a response known to vanish outside the band it was sampled over.

source
JosephsonCircuits.ThermalEquilibrium Type
julia
ThermalEquilibrium(temperature)

A noise model for a passive ScatteringParameters in thermal equilibrium at the physical temperature temperature in Kelvin. The added noise covariance is the vacuum covariance I - S S' scaled by coth(hbar*w/(2*k*T)), the factor by which a mode at that temperature exceeds its vacuum noise.

This states the block's temperature where the block is defined, so it overrides the temperature argument of the analysis. At zero temperature it coincides with Passive.

source
JosephsonCircuits.ThroughDC Type
julia
ThroughDC()

A two port ScatteringParameters which passes direct current unchanged: S(0) = [0 1; 1 0], so the port voltages are equal and the currents are equal and opposite. This is the constant of a series inductance and of a transmission line.

source
JosephsonCircuits.TransientBatchSolution Type
julia
TransientBatchSolution

Result of transientsolve on a vector of problems: the arrays of a TransientSolution with the conditions as the trailing dimension, voltage[port, time, condition], flux[state, time, condition], finalflux[state, condition], phases[junction, stage, time, condition], stages[state, stage, time, condition]; problems holds the batch. Indexing, solution[j], is the ordinary solution of condition j, a view of the batch's arrays, on which the demodulation, the tangent, the adjoint and the noise run as on any solution.

stats counts the work of one chunk of conditions: a host batch split across threads reports the counters of the chunk which worked hardest, as a batch on one chunk reports those of the condition which converged worst. The count of Newton corrections therefore falls as the chunks get smaller, while the results do not change.

source
JosephsonCircuits.TransientBlock Type
julia
TransientBlock

A scattering parameter block as the transient realizes it: the real constant scattering matrix S at the reference impedances R of its ports, the node of the signal and the reference terminal of each port (zero for ground), the index of the first of its port current unknowns, and the block's path. Its ports carry the hybrid constitutive equation of the linearized solver, (I - S) R^(-1/2) v - (I + S) R^(1/2) i = 0, with v the port voltages and i the port currents entering the block through the signal terminals, as auxiliary unknowns whose Kirchhoff couplings enter the node equations; nothing is inverted, so a short or an open is stamped exactly, and a scattering entry within roundoff of one is snapped to it, so a fitted feedthrough on the unit circle carries the exact zeros of its hybrid coefficients (see snapscattering). A block whose matrix depends on frequency carries its rational part as states, and a pumped block the states of every filter of its harmonics, the unconverted output on C and the converted ones modulated (see BlockModulation).

source
JosephsonCircuits.TransientIQPlan Type
julia
TransientIQPlan

Reusable causal I/Q measurement plan. times are the right edges of complete windows; centertimes subtract the filter's groupdelay. Frequencies and bandwidth3db are in Hz, times in seconds. noisebandwidth is one-sided, sum(abs2, taps)/(2dt), for the unity-DC-gain low-pass filter. ports are the port numbers of the carriers and rows the compiled port index of each, the row of its trace.

The FFT workspace is mutable. Use separate plans for concurrent measurements.

source
JosephsonCircuits.TransientLine Type
julia
TransientLine

An ideal lossless transmission line as the transient realizes it: its characteristic impedance Z, its delay, and the signal and reference node of each of its two ports (zero for ground). In time the line is the method of characteristics: at each port the current into the line is v/Z - 2 q/sqrt(Z), a conductance 1/Z at the line's own impedance plus a current from the wave q that entered the far port a delay earlier, and the wave leaving a port, a = v/sqrt(Z) - q, is kept as the port's history for the far port to read a delay later. Nothing is inverted and nothing resonates in the equations, since the round trips that make the line's admittance singular in frequency are the recursion through the history; a mismatch to the connected circuit is the shared node. The delay must be at least one step, so that every wave a step reads is accepted history, and the read interpolates the endpoint history with a cubic, centered when the delay allows.

source
JosephsonCircuits.TransientNoiseBath Type
julia
TransientNoiseBath

One bath: its name, the rows of the equations its source enters with its weights there, the port it terminates (zero otherwise), its resistance (zero for a block channel) and its temperature. A resistor's source is a Norton current into its first terminal and out of its second, which for a port's termination is the port's own source convention, so the current enters the port wave as a port source's does; a block channel's source is an emitted noise wave, a combination of the block's ports weighted by an eigenvector of I - S S' times the square root of its eigenvalue, or one port of a block whose channels are correlated by a group (see TransientNoiseBaths), entering the port current rows as the source 2 eta of the hybrid equation. transientinjection builds the columns.

source
JosephsonCircuits.TransientNoiseBaths Type
julia
TransientNoiseBaths

The baths of a TransientProblem, from transientnoisebaths.

source
JosephsonCircuits.TransientProblem Type
julia
TransientProblem

A compiled circuit with its matrices at one mode, its modified nodal analysis augmentation, its bound drives and its port data, ready to be integrated in time by transientsolve. Built by transientproblem.

Fields

  • circuit, graph, matrices: the compiled circuit, its graph and its CircuitMatrices at one mode, with real values.

  • Nnodal, Naux: the node flux unknowns and the auxiliary branch currents of the mutually coupled inductors; the state has Nnodal + Naux entries.

  • Lscale: the inductance scale of the equations, the mean inductance of the circuit as harmonic balance uses at zero frequency, fixed for the problem so that a state is independent of the step: an auxiliary current i is stored as Lscale*i/phi0.

  • coupledbranches, floatingcomponents, gaugeindices: the branches the augmentation promotes, the subnetworks no element connects to ground, whose flux offset is free, and the gauge rows fixing it.

  • inertialess: the directions of the state that carry no inertia, one set of state indices per subnetwork of the capacitive graph no capacitor connects to ground, including every unknown no capacitor touches; the algebraic constraints a state must satisfy at the start lie along them.

  • algebraic: the directions among them that carry no dissipation either, one set per subnetwork no capacitor or resistor connects to ground, each a union of inertialess ones; along them the equations constrain the flux alone, and the rate is what the constraint differentiated says.

  • injection: the unscaled injection of a unit current of each drive into the node equations, one sparse column per drive, in the orientation of the drive.

  • drives: the bound drives, in the order of injection's columns.

  • constantcurrent: the unscaled constant node current of the netlist's current sources not replaced by a drive.

  • portpositive, portnegative, portimpedances, portconductances: the node of each port terminal (zero for ground), the reference impedance and the conductance of the termination the port owns, in compiled port order, for the port waves.

  • blocks: the scattering parameter blocks with a realization in time, see TransientBlock, whose port currents are auxiliary unknowns after the coupled inductor currents.

  • lines: the ideal transmission lines, see TransientLine, whose wave histories the solve keeps.

source
JosephsonCircuits.TransientQuantumPlan Type
julia
TransientQuantumPlan

A finite-record, positive-frequency temporal-mode measurement. Rows of its output are (X1,P1,X2,P2,...), with [X,P]=im and vacuum variance 1/2. coefficients[:,j] specifies mode j in the positive-frequency Fourier basis; gram accounts for overlapping modes on the same port. vacuum and commutator are the corresponding real covariance and commutator matrices. ports are the port numbers of the modes and rows the compiled port index of each, the row of its trace. Numeric measurement weights live on backend; metadata remain on the host. Storage is O(samples*modes). Batch selected windows for long sliding records.

source
JosephsonCircuits.TransientReuse Type
julia
TransientReuse()

What a transient solve builds and a later solve, tangent or adjoint of the same problem at the same step, rule and backend takes over rather than building again: the scaled TransientSystem with its Jacobian plan, the factorization of the step matrix as it was left, the Krylov workspace of the iterative step, and the workspaces of the Gauss-Legendre tangent and adjoint, one per chunk of conditions, with their stage factorizations and the stepper a record of checkpoints is replayed on, taken over by a later tangent or adjoint of the same shape and, for a sensitivity, the same components in the same order; and for the noise and the gain on the host, the reuses of the other threads' workers, kept the same way. Pass one as reuse to transientsolve, transienttangent and transientadjoint. The kept system serves every problem of one compiled circuit driving the same targets, the problems of one batch (see transientproblem), so a sweep of drives keeps it; a solve of another circuit, or at another step, rule or backend, replaces it. The counterpart of the harmonic balance solver's reuse between the solves of an hbcache. The kept objects are mutable and belong to one solve at a time: do not share a reuse between concurrent solves.

source
JosephsonCircuits.TransientSolution Type
julia
TransientSolution

Result of transientsolve. times is in seconds; voltage holds the port voltages in Volts and incident and outgoing the real instantaneous power waves in sqrt(W), one row per port in compiled port order and one column per saved time. initialflux, initialrate, finalflux and finalrate always hold the first and the last scaled state, and transientstate(solution) is the state to continue from. With record = :phases or :states, phases holds the junction phases the tangent and the adjoint read, at every saved time under the trapezoidal rule and at the two stages of each step under GaussLegendre, as (junction, stage, time), endphases the phases at every saved time of the junctions on the algebraic directions the rule projects and endrates the rate across them read from the differentiated constraints, or nothing without any, and linewaves the wave leaving each port of each transmission line at every step, as (port, time) in sqrt(W), or nothing without lines, or with checkpoints when the history before each of them, kept as their waves, is smaller than the record, which is kept instead once the longest delay exceeds the checkpoint interval, and history the waves leaving each line port over the delay window before the start, which the lines read after it; on the solve's backend as every record is; with record = :states, flux and rate hold the scaled node fluxes and their rates at every saved time as well, and under GaussLegendre stages the two stage increments of the step ending at each saved time, as (state, stage, time), which the sensitivity to a component value reads; with record = :checkpoints, checkpoints holds the state and the stage predictor every checkpointevery steps, from which the responses replay the steps between, so that a record of any length costs the checkpoints and one window of phases. stats counts the steps, the Newton corrections, the numeric factorizations, the retries of a rejected correction after a fresh factorization at its base point, and the Krylov iterations. The arrays live on the backend of the solve.

source
JosephsonCircuits.TransientSource Type
julia
TransientSource(target, current)

A real instantaneous current in Amperes, a number or a callable current(t) of the time in seconds. An integer target is a port number: positive current is injected into the port's positive terminal by a Norton source, and the port's termination is part of the compiled circuit already. A string or symbol names a CurrentSource component, whose constant value the waveform replaces; positive current then flows out of the component's first terminal and into its second. Several sources on one target add. Unlike a harmonic balance source the callable returns the physical waveform, not a Fourier coefficient, and it must be deterministic, since the tangent and the adjoint evaluate it again on the recorded grid.

source
JosephsonCircuits.TransientState Type
julia
TransientState

The state a transient starts from or ends at, in the solver's units: the scaled node fluxes flux/phi0 with the auxiliary currents of the coupled inductors and the scattering blocks appended in the problem's fixed units Lscale*i/phi0, their rates, the history of the wave leaving each port of each transmission line in sqrt(W), two per line in compiled order, as the columns of waves at the spacing wavesdt ending at the start, or a single column the lines carry unchanged before the start, and the states of the rational blocks. Built by transientstate, from the physical node fluxes and voltages of a problem or from the end of a solution, and given to transientsolve as initialstate, which takes nothing else, since a bare pair of arrays does not say which units it is in. A state does not depend on the step: a history recorded at one step is read at another through the same interpolation the lines read their history with.

source
JosephsonCircuits.TransientSystem Type
julia
TransientSystem

The scaled system of a TransientProblem at one step size and one stepping rule, on one backend: the padded and scaled capacitance, conductance and augmented inverse inductance matrices, the junction incidence and coefficients, the drive injection, the port readout, the real Jacobian plan of harmonic balance at one mode carrying the step's linear term, the Jacobian it fills and the factorization of it, and the projection onto the algebraic constraints with the reading of the rate along them. Built by transientsystem; transientsolve, the tangent and the adjoint all step on it.

source
JosephsonCircuits.TransmissionLineProvider Type
julia
TransmissionLineProvider(Z0, delay)

The scattering parameter provider of an ideal lossless transmission line of characteristic impedance Z0 and one way delay delay seconds, referenced to Z0: S11 = S22 = 0 and S21 = S12 = exp(-im_ω_delay). Natively valid on signed frequencies.

source
JosephsonCircuits.TransportRows Type
julia
TransportRows

The transport rows Y v = j of the explicit direct current block, together with the coupling into the zero frequency nodal rows.

Fields

  • plan: the topology.

  • Y: P'G0P, unreferenced. It is singular on a floating island, which is correct: these rows state the physics and say nothing about where the potential is measured from.

  • j: the injected current.

  • coupling: G0 P, the resistor current each component's voltage drives into the nodes, indexed by node with ground dropped.

See transportrows and DCConductancePlan.

source
JosephsonCircuits.Trapezoidal Type
julia
Trapezoidal()

The trapezoidal rule on the flux and on its rate (Newmark with the averaging parameters): second order, and free of numerical damping, so a lossless LC oscillation keeps its energy. One implicit equation per step, and the rule which takes a linearsolver. Along an algebraic direction of the state, one without capacitance or conductance, each endpoint is projected onto a constraint a junction or a source touches, as under GaussLegendre, since the constraint's rows weigh little in the step's residual and the rule's average of the two ends would carry what the Newton leaves to the next end with its sign reversed; and the rate is read from the differentiated constraint wherever the state is reported, since the rule's rate update carries the rounding of every step forward along it undamped.

source
JosephsonCircuits.ValueMaps Type
julia
ValueMaps

Where each value array of a NonlinearTermPlan and the linear term it was built from read their numbers, under a fixed structure, so that new component values can be written into them without rebuilding anything.

Fields

  • ml, mg, mc: for each stored entry of Knm, the stored entry of invLnm, Gnm and Cnm it takes, or zero.

  • kmap, kre, kim: for each entry of the real form of the linear term, the entry of Knm it comes from and the coefficient of its real and its imaginary part, which are 0 or ±1.

  • cmap: for each entry of the complex form, the entry of Knm.

  • bjunc, bsgn: for each Josephson coefficient, its junction and the incidence entry, so the coefficient is bsgn*Lscale/Lj.

  • knz: the entries of Knm, on the backend where the plan lives, refilled at each refresh.

Found by valuemaps, which probes the conversions with tagged values rather than restating their rules.

source
JosephsonCircuits.VoltageSource Type
julia
VoltageSource(V)

A two terminal voltage source with voltage V in Volts between terminal 1 and terminal 2.

source
JosephsonCircuits.WRspice Type
julia
WRspice(; executable = nothing, dphimax = 0.01, jjaccel = true,
    maxdata = 2e9)

WRSPICE as the stepping rule of transientsolve, for cross checking the package's own rules against an independent simulator. The problem's circuit is written as a WRSPICE netlist with each junction an instance of the jj model (see exportnetlist) and each drive a current source — a constant one for a waveform given as a number, and a piecewise linear one through the waveform's samples on the grid of dt for a callable — and the simulation runs through the wrspice executable in a temporary directory and is read back as a TransientSolution holding the times, the port voltages and the port waves, and with record = :phases the junction phases from the phase nodes of the jj instances, as (junction, time) on the junction axis every solver uses, in the branch orientation of the package. transientdemodulate and transientiq then read the solution as they read one stepped by the package.

A run keeps those traces and no others: the terminals of the ports, and the phase nodes of the junctions when they are recorded. WRSPICE would otherwise write every node of the circuit at every print point, which is a gigabyte of a record nothing reads for every thousand nodes and every hundred thousand points.

WRSPICE integrates with its own adaptive internal steps: dt is the grid the sources are sampled on and the output is printed on, and dphimax, the largest junction phase change WRSPICE allows per internal step, controls the accuracy in place of the Newton tolerances, which do not apply. jjaccel selects WRSPICE's accelerated convergence testing for Josephson circuits, and maxdata its limit on the exported data in kilobytes. executable is the path of the wrspice executable, or nothing for the one wrspice_cmd finds; loading the XicTools_jll package provides one.

Supported are the circuits of transientproblem without scattering blocks, with the sinusoidal junction relation only, from the zero initial state under WRSPICE's own initial conditions, with record = :ports or :phases. An ideal TransmissionLine is written as the SPICE lossless line element; the wave record linewaves stays empty, since WRSPICE keeps the line histories to itself. The junctions of every run share one jj model, whose subgap loss is set as small as the model allows but is not zero, where the package's junctions are lossless. The solution's final state fields are NaN, since WRSPICE does not hand over a state, and the tangent, the adjoint and the noise need a solution of the package's own rules.

Examples

julia
p = transientproblem(circuit, circuitdefs;
    sources = [TransientSource(1, t -> Ip*sin(wp*t))])
native = transientsolve(p, (0.0, 100e-9); dt = 1e-12)
spice = transientsolve(p, (0.0, 100e-9); dt = 1e-12, method = WRspice())
transientdemodulate(native, 2, wp/(2*pi)), transientdemodulate(spice, 2, wp/(2*pi))
source
JosephsonCircuits.WorkerBlockSensitivity Type
julia
WorkerBlockSensitivity

One worker's private state for the scattering block sensitivity stamps: its own copy of the stamp vector (the lumped stamps are shared read only, the :S stamps' values are private because they are rebuilt at every signal frequency), the provider-swapped systems, and the evaluation scratch.

source
JosephsonCircuits.ABCD_PiY! Method
julia
ABCD_PiY!(ABCD,Y1,Y2,Y3)

In-place version of ABCD_PiY.

Examples

julia
julia> JosephsonCircuits.ABCD_PiY!(zeros(Complex{Float64},2,2),1,2,4)
2×2 Matrix{ComplexF64}:
 1.5+0.0im  0.25+0.0im
 3.5+0.0im  1.25+0.0im
source
JosephsonCircuits.ABCD_PiY Method
julia
ABCD_PiY(Y1,Y2,Y3)

Return the ABCD matrix for a Pi network of admittances Y1, Y2, and Y3.

julia
o----Y3-----o
   |     |   
   Y1    Y2  
   |     |   
o-----------o

Examples

julia
julia> JosephsonCircuits.ABCD_PiY(1.0+0.0im,2.0+0.0im,4.0+0.0im)
2×2 Matrix{ComplexF64}:
 1.5+0.0im  0.25-0.0im
 3.5+0.0im  1.25+0.0im
source
JosephsonCircuits.ABCD_TZ! Method
julia
ABCD_TZ!(ABCD,Z1,Z2,Z3)

In-place version of ABCD_TZ.

Examples

julia
julia> JosephsonCircuits.ABCD_TZ!(ones(Complex{Float64},2,2),1,2,4)
2×2 Matrix{ComplexF64}:
 1.25+0.0im  3.5+0.0im
 0.25+0.0im  1.5+0.0im
source
JosephsonCircuits.ABCD_TZ Method
julia
ABCD_TZ(Z1,Z2,Z3)

Return the ABCD matrix for a T network of impedances Z1, Z2, and Z3.

julia
o--Z1-----Z2--o
       |       
      Z3       
       |       
o-------------o

Examples

julia
julia> JosephsonCircuits.ABCD_TZ(1.0+0.0im,2.0+0.0im,4.0+0.0im)
2×2 Matrix{ComplexF64}:
 1.25+0.0im  3.5+0.0im
 0.25-0.0im  1.5+0.0im
source
JosephsonCircuits.ABCD_attenuator_Pi! Method
julia
ABCD_attenuator_Pi!(ABCD, Zsource, Zload, attenuationdB)

Overwrite ABCD with the ABCD matrix for an attenuator with input impedance Zsource, output impedance Zload, and attenuation attenuationdB made with a T network of impedances Rx, Ry, and Rz.

julia
o----Rz-----o
   |     |   
   Rx    Ry  
   |     |   
o-----------o

Examples

julia
julia> ABCD = zeros(Float64,2,2);JosephsonCircuits.ABCD_attenuator_Pi!(ABCD,50.0,50.0,10.0)
2×2 Matrix{Float64}:
 1.73925    71.1512
 0.0284605   1.73925
source
JosephsonCircuits.ABCD_attenuator_Pi! Method
julia
ABCD_attenuator_Pi!(ABCD, Z0, attenuationdB)

Overwrite ABCD with the ABCD matrix for an attenuator with input and output impedance Z0 and attenuation attenuationdB made with a T network of impedances Rx, Ry, and Rz.

julia
o----Rz-----o
   |     |   
   Rx    Ry  
   |     |   
o-----------o

Examples

julia
julia> ABCD = zeros(Float64,2,2);JosephsonCircuits.ABCD_attenuator_Pi!(ABCD,50.0,10.0)
2×2 Matrix{Float64}:
 1.73925    71.1512
 0.0284605   1.73925
source
JosephsonCircuits.ABCD_attenuator_Pi Method
julia
ABCD_attenuator_Pi(Zsource, Zload, attenuationdB)

Return the ABCD matrix for an attenuator with input impedance Zsource, output impedance Zload, and attenuation attenuationdB made with a T network of impedances Rx, Ry, and Rz.

julia
o----Rz-----o
   |     |   
   Rx    Ry  
   |     |   
o-----------o

Examples

julia
julia> JosephsonCircuits.ABCD_attenuator_Pi(50.0,50.0,10.0)
2×2 Matrix{Float64}:
 1.73925    71.1512
 0.0284605   1.73925
source
JosephsonCircuits.ABCD_attenuator_Pi Method
julia
ABCD_attenuator_Pi(Z0,attenuationdB)

Return the ABCD matrix for an attenuator with input and output impedance Z0 and attenuation attenuationdB made with a T network of impedances Rx, Ry, and Rz.

julia
o----Rz-----o
   |     |   
   Rx    Ry  
   |     |   
o-----------o

Examples

julia
julia> JosephsonCircuits.ABCD_attenuator_Pi(50.0,10.0)
2×2 Matrix{Float64}:
 1.73925    71.1512
 0.0284605   1.73925
source
JosephsonCircuits.ABCD_attenuator_T! Method
julia
ABCD_attenuator_T!(ABCD, Zsource, Zload, attenuationdB)

Overwrite ABCD with the ABCD matrix for an attenuator with input impedance Zsource, output impedance Zload, and attenuation attenuationdB made with a T network of impedances Ra, Rb, and Rc.

julia
o--Ra-----Rb--o
       |       
       Rc       
       |       
o-------------o

Examples

julia
julia> ABCD = zeros(Float64,2,2);JosephsonCircuits.ABCD_attenuator_T!(ABCD, 50.0, 50.0, 10.0)
2×2 Matrix{Float64}:
 1.73925    71.1512
 0.0284605   1.73925
source
JosephsonCircuits.ABCD_attenuator_T! Method
julia
ABCD_attenuator_T!(ABCD, Z0, attenuationdB)

Overwrite ABCD with the ABCD matrix for an attenuator with input and output impedance Z0 and attenuation attenuationdB made with a T network of impedances Ra, Rb, and Rc.

julia
o--Ra-----Rb--o
       |       
       Rc       
       |       
o-------------o

Examples

julia
julia> ABCD = zeros(Float64,2,2);JosephsonCircuits.ABCD_attenuator_T!(ABCD, 50.0, 10.0)
2×2 Matrix{Float64}:
 1.73925    71.1512
 0.0284605   1.73925
source
JosephsonCircuits.ABCD_attenuator_T Method
julia
ABCD_attenuator_T(Zsource, Zload, attenuationdB)

Return the ABCD matrix for an attenuator with input impedance Zsource, output impedance Zload, and attenuation attenuationdB made with a T network of impedances Ra, Rb, and Rc.

julia
o--Ra-----Rb--o
       |       
       Rc       
       |       
o-------------o

Examples

julia
julia> JosephsonCircuits.ABCD_attenuator_T(50.0,50.0,10.0)
2×2 Matrix{Float64}:
 1.73925    71.1512
 0.0284605   1.73925
source
JosephsonCircuits.ABCD_attenuator_T Method
julia
ABCD_attenuator_T(Z0,attenuationdB)

Return the ABCD matrix for an attenuator with input and output impedance Z0 and attenuation attenuationdB made with a T network of impedances Ra, Rb, and Rc.

julia
o--Ra-----Rb--o
       |       
       Rc       
       |       
o-------------o

Examples

julia
julia> JosephsonCircuits.ABCD_attenuator_T(50.0,10.0)
2×2 Matrix{Float64}:
 1.73925    71.1512
 0.0284605   1.73925
source
JosephsonCircuits.ABCD_coupled_tline! Method
julia
ABCD_coupled_tline!(A, Z0e, Z0o, thetae, thetao)

In-place version of ABCD_coupled_tline.

Examples

julia
julia> JosephsonCircuits.ABCD_coupled_tline!(zeros(Complex{Float64},4,4),50,50,pi/4,pi/4)
4×4 Matrix{ComplexF64}:
 0.707107+0.0im             0.0+0.0im       0.0+0.0im
      0.0+0.0im        0.707107+0.0im                0.0+35.3553im
      0.0+0.0141421im       0.0+0.0im                0.0+0.0im
      0.0+0.0im             0.0+0.0141421im     0.707107+0.0im
source
JosephsonCircuits.ABCD_coupled_tline Method
julia
ABCD_coupled_tline(Z0e, Z0o, thetae, thetao)

Return the ABCD matrix for two coupled transmission lines described by even and odd mode phase delays thetae and thetao, and even and odd mode impedances Z0e and Z0o.

julia
thetae, Z0e
thetao, Z0o

V1, I1 -->  ======== <-- I3, V3
V2, I2 -->  ======== <-- I4, V4

[(V1+V2)/2, (I1+I2)/2] = ABCDe * [(V3+V4)/2, -(I3+I4)/2]
[(V1-V2)/2, (I1-I2)/2] = ABCDo * [(V3-V4)/2, -(I3-I4)/2]

[V1, V2, I1, I2] = ABCD_coupled_tline * [V3, V4, -I3, -I4]

Examples

julia
julia> JosephsonCircuits.ABCD_coupled_tline(50,50,pi/4,pi/4)
4×4 Matrix{ComplexF64}:
 0.707107+0.0im             0.0+0.0im       0.0+0.0im
      0.0+0.0im        0.707107+0.0im                0.0+35.3553im
      0.0+0.0141421im       0.0+0.0im                0.0+0.0im
      0.0+0.0im             0.0+0.0141421im     0.707107+0.0im
source
JosephsonCircuits.ABCD_seriesZ! Method
julia
ABCD_seriesZ!(ABCD,Z1)

In-place version of ABCD_seriesZ.

Examples

julia
julia> JosephsonCircuits.ABCD_seriesZ!(zeros(Complex{Float64},2,2),50)
2×2 Matrix{ComplexF64}:
 1.0+0.0im  50.0+0.0im
 0.0+0.0im   1.0+0.0im
source
JosephsonCircuits.ABCD_seriesZ Method
julia
ABCD_seriesZ(Z1)

Return the ABCD matrix for a series impedance Z1.

julia
o---Z1---o
          
          
o--------o

Examples

julia
julia> JosephsonCircuits.ABCD_seriesZ(50.0+0.0im)
2×2 Matrix{ComplexF64}:
 1.0+0.0im  50.0+0.0im
 0.0+0.0im   1.0+0.0im
source
JosephsonCircuits.ABCD_shuntY! Method
julia
ABCD_shuntY!(ABCD,Y1)

In-place version of ABCD_shuntY.

Examples

julia
julia> JosephsonCircuits.ABCD_shuntY!(zeros(Complex{Float64},2,2),1/50)
2×2 Matrix{ComplexF64}:
  1.0+0.0im  0.0+0.0im
 0.02+0.0im  1.0+0.0im
source
JosephsonCircuits.ABCD_shuntY Method
julia
ABCD_shuntY(Y1)

Return the ABCD matrix for a shunt admittance Y1.

julia
o---------o
     |
     Y1
     |
o---------o

Examples

julia
julia> JosephsonCircuits.ABCD_shuntY(1/(50.0+0.0im))
2×2 Matrix{ComplexF64}:
  1.0+0.0im  0.0+0.0im
 0.02-0.0im  1.0+0.0im
source
JosephsonCircuits.ABCD_tline! Method
julia
ABCD_tline!(ABCD, Z0, theta)

In-place version of ABCD_tline.

Examples

julia
julia> JosephsonCircuits.ABCD_tline!(ones(Complex{Float64},2,2),50, pi/4)
2×2 Matrix{ComplexF64}:
 0.707107+0.0im             0.0+35.3553im
      0.0+0.0141421im  0.707107+0.0im
source
JosephsonCircuits.ABCD_tline Method
julia
ABCD_tline(Z0, theta)

Return the ABCD matrix for a transmission line described by phase delay theta in radians and characteristic impedance Z0 in Ohms.

julia
   theta, Z0  
o--========--o
              
              
o------------o

Examples

julia
julia> JosephsonCircuits.ABCD_tline(50, pi/4)
2×2 Matrix{ComplexF64}:
 0.707107+0.0im             0.0+35.3553im
      0.0+0.0141421im  0.707107+0.0im
source
JosephsonCircuits.ABCDtoS Function
julia
ABCDtoS(ABCD;portimpedances=50.0)

Convert the 2 port chain (ABCD) matrix ABCD to the scattering parameter matrix S and return the result. Assumes a port impedance of 50 Ohms unless specified with the portimpedances keyword argument.

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006.

source
JosephsonCircuits.A_B_to_symplectic_pair Method
julia
A_B_to_symplectic_pair(A::AbstractMatrix, B::AbstractMatrix; atol = 0,
    rtol = ...)

Given A (2n×2n) and B (2n×4n) such that A*Ω*A' + B*ΩE*B' = Ω, return the symplectic matrix S = [A B; C D] with respect to Ωtot = Ω ⊕ ΩE, in pair operator order.

C (4n×2n) and D (4n×4n) are constructed here; atol and rtol are the tolerances of the rank decisions that construction makes.

source
JosephsonCircuits.A_coupled_tlines Method
julia
A_coupled_tlines(L,Cmaxwell,l,omega)

Returns the 2mx2m chain (ABCD) matrix for a port number symmetric multi-port network of m coupled transmission lines described by a symmetric mxm Maxwell inductance (per unit length) matrix L, a symmetric mxm Maxwell capacitance matrix (per unit length) Cmaxwell, a physical length l, and an angular frequency omega.

julia
V_1, I_1 -->  ======== <-- I_{m+1}, V_{m+1}
V_2, I_2 -->  ======== <-- I_{m+2}, V_{m+2}
          .
          .
          .
V_m, I_m -->  ======== <-- I_n, V_n
              <---l-->

where n=2*m.

[V_1, ...V_m, I_1, ...I_m] = A_coupled_tline * [V_{m+1}, ...V_n, I_{m+1}, ...I_n]

Examples

julia
Zeven = 51.0
Zodd = 49.0
neven = 1.1
nodd = 1.08
l = 3.5e-3
c = JosephsonCircuits.speed_of_light
omega = 2*pi*5e9

L, C = JosephsonCircuits.even_odd_to_maxwell(Zeven, Zodd, neven, nodd)
A1 = JosephsonCircuits.A_coupled_tlines(L,C,l,omega)
A2 = JosephsonCircuits.ABCD_coupled_tline(Zeven,Zodd,neven*omega/c*l,nodd*omega/c*l)
println(isapprox(A1,A2))

# output
true

References

Paul, Clayton R. Analysis of Multiconductor Transmission Lines, Second Edition. Wiley, 2008.

source
JosephsonCircuits.AtoB Function
julia
AtoB(A)

Convert the chain (ABCD) matrix A to the inverse chain matrix B and return the result. Note that despite the name, the inverse of the chain matrix is not equal to the inverse chain matrix, inv(A) ≠ B.

Examples

julia
julia> A = Complex{Float64}[1.0 0.0;1/50 1.0];JosephsonCircuits.AtoB(A)
2×2 Matrix{ComplexF64}:
  1.0+0.0im  0.0+0.0im
 0.02-0.0im  1.0-0.0im

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006.

source
JosephsonCircuits.AtoB! Method
julia
AtoB!(B::AbstractMatrix,A::AbstractMatrix,tmp::AbstractMatrix)

See AtoB for description.

source
JosephsonCircuits.AtoS Function
julia
AtoS(A)

Convert the chain (ABCD) matrix A to the scattering parameter matrix S and return the result.

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006.

source
JosephsonCircuits.AtoS! Method
julia
AtoS!(S::AbstractMatrix, A::AbstractMatrix, tmp::AbstractMatrix,
    sqrtportimpedances1, sqrtportimpedances2)

See AtoS for description.

source
JosephsonCircuits.AtoY Function
julia
AtoY(A)

Convert the chain (ABCD) matrix A to the admittance matrix Y and return the result.

Examples

julia
julia> A = Complex{Float64}[-1 -50.0;0 -1];JosephsonCircuits.AtoY(A)
2×2 Matrix{ComplexF64}:
 0.02+0.0im  0.02+0.0im
 0.02+0.0im  0.02+0.0im

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006.

source
JosephsonCircuits.AtoY! Method
julia
AtoY!(Y::AbstractMatrix,A::AbstractMatrix,tmp::AbstractMatrix)

See AtoY for description.

source
JosephsonCircuits.AtoZ Function
julia
AtoZ(A)

Convert the ABCD matrix A to the impedance matrix Z and return the result.

Examples

julia
julia> A = Complex{Float64}[1.0 0.0;1/50 1.0];JosephsonCircuits.AtoZ(A)
2×2 Matrix{ComplexF64}:
 50.0+0.0im  50.0+0.0im
 50.0+0.0im  50.0+0.0im

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006.

source
JosephsonCircuits.AtoZ! Method
julia
AtoZ!(Z::AbstractMatrix,A::AbstractMatrix,tmp::AbstractMatrix)

See AtoZ for description.

source
JosephsonCircuits.B_from_X_Y_quadrature_block Method
julia
B_from_X_Y_quadrature_block(X::AbstractMatrix{<:Real},
    Y::AbstractMatrix{<:Real})

Return the B part of a symplectic matrix S=[A B;C D] from the completely positive trace preserving (CPTP) map X, Y assuming the environment is in a vacuum state.

source
JosephsonCircuits.BtoA Function
julia
BtoA(B)

Convert the inverse chain matrix B to the chain (ABCD) matrix A and return the result. Note that despite the name, the inverse of the chain matrix is not equal to the inverse chain matrix, inv(A) ≠ B.

Examples

julia
julia> B = Complex{Float64}[1.0 0.0;1/50 1.0];JosephsonCircuits.BtoA(B)
2×2 Matrix{ComplexF64}:
  1.0+0.0im  0.0+0.0im
 0.02-0.0im  1.0-0.0im

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006.

source
JosephsonCircuits.BtoA! Method
julia
BtoA!(A::AbstractMatrix,B::AbstractMatrix,tmp::AbstractMatrix)

See BtoA for description.

source
JosephsonCircuits.BtoS Function
julia
BtoS(B)

Convert the inverse chain (ABCD) matrix B to the scattering parameter matrix S and return the result.

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006 with change of overall sign (suspected typo).

source
JosephsonCircuits.BtoS! Method
julia
BtoS!(S::AbstractMatrix, B::AbstractMatrix, tmp::AbstractMatrix,
    sqrtportimpedances1, sqrtportimpedances2)

See BtoS for description.

source
JosephsonCircuits.BtoY Function
julia
BtoY(A)

Convert the inverse chain matrix B to the admittance matrix Y and return the result.

Examples

julia
julia> B = Complex{Float64}[-1 -50.0;0 -1];JosephsonCircuits.BtoY(B)
2×2 Matrix{ComplexF64}:
 0.02+0.0im  0.02+0.0im
 0.02+0.0im  0.02+0.0im

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006.

source
JosephsonCircuits.BtoY! Method
julia
BtoY!(Y::AbstractMatrix,B::AbstractMatrix,tmp::AbstractMatrix)

See BtoY for description.

source
JosephsonCircuits.BtoZ Function
julia
BtoZ(A)

Convert the inverse chain matrix B to the impedance matrix Z and return the result.

Examples

julia
julia> B = Complex{Float64}[1.0 0.0;1/50 1];JosephsonCircuits.BtoZ(B)
2×2 Matrix{ComplexF64}:
 50.0+0.0im  50.0+0.0im
 50.0+0.0im  50.0+0.0im

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006 with change of sign on B21 and B22 terms (suspected typo).

source
JosephsonCircuits.BtoZ! Method
julia
BtoZ!(Z::AbstractMatrix,B::AbstractMatrix,tmp::AbstractMatrix)

See BtoZ for description.

source
JosephsonCircuits.CMtokeyed Method
julia
CMtokeyed(CM, outputmodes, outputportnumbers, w)

Convert a commutation relation array CM vs frequency w to a keyed array. Return the keyed array.

Examples

julia
julia> JosephsonCircuits.CMtokeyed([1 2;3 4;;;],[(0,)],[1,2],[1.0,1.1])
3-dimensional KeyedArray(NamedDimsArray(...)) with keys:
   outputmode  1-element Vector{Tuple{Int64}}
   outputport  2-element Vector{Int64}
◪   freqindex  2-element UnitRange{Int64}
And data, 1×2×2 Array{Int64, 3}:
[:, :, 1] ~ (:, :, 1):
          (1)  (2)
   (0,)     1    3

[:, :, 2] ~ (:, :, 2):
          (1)  (2)
   (0,)     2    4
source
JosephsonCircuits.IctoLj Method
julia
IctoLj(Ic)

The junction inductance Lj = phi0/Ic in Henries of a Josephson junction with critical current Ic in Amperes.

Examples

julia
julia> IctoLj(3.29105976e-6)
1.0e-10
source
JosephsonCircuits.JosephsonJunction Method
julia
JosephsonJunction(Lj)
JosephsonJunction(; Ic)

A Josephson junction with junction inductance Lj in Henries, or equivalently critical current Ic in Amperes, and the sinusoidal current-phase relation I(φ) = Ic*sin(φ). Equal to NonlinearInductor(Lj, sin, cos).

Examples

julia
julia> JosephsonJunction(100e-12) == NonlinearInductor(100e-12, sin, cos)
true

julia> JosephsonJunction(Ic = 3.29105976e-6).L0
1.0e-10
source
JosephsonCircuits.LjtoIc Method
julia
LjtoIc(Lj)

The critical current Ic = phi0/Lj in Amperes of a Josephson junction with junction inductance Lj in Henries.

Examples

julia
julia> LjtoIc(100e-12)
3.29105976e-6
source
JosephsonCircuits.R_block_to_pair Method
julia
R_block_to_pair(n::Integer)

Examples

julia
julia> JosephsonCircuits.R_block_to_pair(2)
4×4 SparseArrays.SparseMatrixCSC{Int64, Int64} with 4 stored entries:
 1
  1
  1
  1
source
JosephsonCircuits.R_ladder_to_quadrature_block Method
julia
R_ladder_to_quadrature_block(n::Integer)

Examples

julia
julia> JosephsonCircuits.R_ladder_to_quadrature_block(1)
2×2 Matrix{ComplexF64}:
 0.707107+0.0im       0.707107+0.0im
      0.0-0.707107im       0.0+0.707107im
source
JosephsonCircuits.R_ladder_to_quadrature_pair Method
julia
R_ladder_to_quadrature_pair(n::Integer)

Examples

julia
julia> JosephsonCircuits.R_ladder_to_quadrature_pair(1)
2×2 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 4 stored entries:
 0.707107+0.0im       0.707107+0.0im
      0.0-0.707107im       0.0+0.707107im
source
JosephsonCircuits.R_pair_to_block Method
julia
R_pair_to_block(n::Integer)

Examples

julia
julia> JosephsonCircuits.R_pair_to_block(2)
4×4 SparseArrays.SparseMatrixCSC{Int64, Int64} with 4 stored entries:
 1
  1
  1
  1
source
JosephsonCircuits.R_quadrature_to_ladder_block Method
julia
R_quadrature_to_ladder_block(n::Integer)

Examples

julia
julia> JosephsonCircuits.R_quadrature_to_ladder_block(2)
4×4 Matrix{ComplexF64}:
 0.707107+0.0im       0.0+0.0im  0.0+0.707107im  0.0+0.0im
      0.0+0.0im  0.707107+0.0im  0.0+0.0im       0.0+0.707107im
 0.707107+0.0im       0.0+0.0im  0.0-0.707107im  0.0+0.0im
      0.0+0.0im  0.707107+0.0im  0.0+0.0im       0.0-0.707107im
source
JosephsonCircuits.R_quadrature_to_ladder_pair Method
julia
R_quadrature_to_ladder_pair(n::Integer)

Examples

julia
julia> JosephsonCircuits.R_quadrature_to_ladder_pair(2)
4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 8 stored entries:
 0.707107+0.0im  0.0+0.707107im
 0.707107+0.0im  0.0-0.707107im
           0.707107+0.0im  0.0+0.707107im
           0.707107+0.0im  0.0-0.707107im
source
JosephsonCircuits.RationalScattering Method
julia
RationalScattering(A, B, C, D; zref = 50.0, grounded = true,
    noise = Passive(), atol = 1e-8)

A ScatteringParameters block from the real state space realization S(s) = D + C (s I - A)^(-1) B of a passive rational multiport, with A the nz by nz state matrix, B nz by nports, C nports by nz and D nports by nports, all real and finite, A stable. The block is validated as passive by the bounded real lemma's Hamiltonian test, or by sampling where its feedthrough is lossless, and it is rejected otherwise, unless it states its noise with a NoiseCovariance, which is how an active block, an amplifier given by its scattering parameters, declares it; stability is required of every realization. It is evaluated by the harmonic balance solvers at every frequency and realized in time by the transient solver with its states, so the two describe the same block, and its noise is the noise of its loss at every frequency by Bosma's relation, or the noise it states. The realization is what a vector fit of measured or simulated data delivers; a lossless line is TransmissionLine instead, which needs no states.

source
JosephsonCircuits.RationalScattering Method
julia
RationalScattering(block::LinearizedScattering, npoles; frequencies = nothing,
    band = nothing, delays = nothing, tol = 1e-2, noisetol = 1e-2,
    padding = 4, iterations = 30, pruneslack = 0.05)

The LinearizedScattering block with every harmonic transfer function fitted to a stable rational realization, which is how the transient realizes it: H_0 as an ordinary rational function with its constant term, or as its constant alone with no state where the data needs no pole, and each H_k for k > 0 as the pair of real rational functions of its cosine and sine parts (see ModulatedRationalProvider), strictly proper, since a conversion vanishes at infinite frequency. Each is fitted at npoles poles by the vector fit of the ScatteringParameters method, at the frequencies in Hz, by default the magnitudes of the frequencies the harmonic is tabulated at, within band = (flo, fhi) in Hz when given: a block built from a solve carries every sideband its mode truncation reached, far above the band a signal occupies, and a harmonic with no sample in the band is realized as zero; no passivity is enforced, since a pumped block is lossless as a whole and its parts are not. A harmonic is read where its data covers a frequency and is zero beyond its tables, and H_0, a real function, is read at whichever sign of a frequency its data holds and mirrored to the other, H_0(-nu) = conj(H_0(nu)), so a table of one sign fits. A fit within a band is an approximation within it: a solve evaluates the block at every sideband its harmonics reach from a signal, where such a fit only extrapolates, so it serves signals and pulses in the band and states, through its completed noise, that it is no better outside it. A lumped device fits over all of its sidebands at a few poles each; a long line does not, its sidebands being dispersive delay of many turns of phase. delays, one per port in seconds, removes a delay from the data before the fit, as a cable's is removed before its fit: the entry from port q to port p at the harmonic k is fitted with exp(i (nu + k wp) tau_p + i nu tau_q) taken out, so the fitted block is the device with a lossless line of delay tau_p cut off each port, and is put back with a TransmissionLine of that delay in cascade at the port; the delay of a line's signal band is not that of its sidebands, which keep the difference. The pump phase of block is folded into the fitted functions, and the fitted block keeps its pump, ports, noise model and envelope; a stated covariance is rotated by the phase and the delays as the functions are.

The data must meet what the block declares, that it is lossless or the covariance it states, over the modes its harmonics reach from every frequency it holds, each output against every input which feeds it (see pumpedfamily), to the block's atol and a covariance's, which the fit checks first and refuses otherwise. The fit itself meets the declaration no better than its error, so the fitted block does not declare it: its noise is the covariance the block states, zero for a lossless one, completed to the commutation relations of the fitted functions over the ladder of the modes of a solve padded by padding multiples of the pump frequency (see NoiseCovariance), so that it adds, whatever modes a solve keeps, the noise its own commutator requires, the least a channel with the fitted functions can add for a lossless device, and its output obeys the commutation relations exactly. That noise is what the fit costs, and the fit is refused when it exceeds noisetol of the square of the largest entry over the modes the data reaches from its frequencies and from the midpoints between them; the block's atol stays that of the data. The fit is held to the data as well, and refused where it misses a sample by more than tol of the largest response, in the spectral norm, as the ScatteringParameters method measures a fit: a stated covariance large enough covers the commutator of a poor fit at no noise, so the noise a fit adds says nothing of its accuracy, and the two are held apart. A band must leave the unconverted response a sample. A dcmodel the block states is met by the fit of H_0 exactly. The harmonic balance solvers evaluate the fitted block too, so the two describe the same block.

source
JosephsonCircuits.RationalScattering Method
julia
RationalScattering(block::ScatteringParameters, npoles;
    frequencies = nothing, iterations = 30, passivity = true, atol = 1e-8,
    margin = 1e-6, rounds = 20, pruneslack = 0.05)

A RationalScattering block fitted to the scattering data of block at npoles common poles by vector fitting: starting poles spread over the band are relocated by the relaxed iteration of Gustavsen and Semlyen, for at most iterations rounds, until they settle, and the residues of every entry and the constant term follow by least squares. The data is sampled at frequencies in Hz, by default a tabulated block's own. Poles the data does not need drift out of the band or coalesce and are pruned, so npoles is a budget rather than the order returned; too few poles settle on a poor fit that typically cannot be made passive, which is an error. The result is a real state space realization, stable by construction, with as many states per pole as its residue has rank. The fitted block keeps the reference impedances, grounding and noise model of block. A delay is not a rational function: model a cable as a TransmissionLine of its delay in cascade with a fit of the data with that delay removed.

With passivity = true the fit is perturbed wherever its largest singular value crosses one, by the smallest change of its residues and constant that brings each crossing to 1 - margin, over at most rounds rounds, and the result is validated by the same test as any rational block, to atol. passivity = false returns the raw fit, without the enforcement or its repair of an active constant term, but still rejects a fit that fails validation. The test decides on a lower bound of the largest singular value, so a returned fit can have a true norm above one by up to twice the norm search's relative tolerance; passivityassessment reports that uncertainty, and a solve which cannot tolerate a block active within it should ask for a margin above it. A block which states its noise with a NoiseCovariance may be active, so it is fitted as it is, with neither the enforcement nor the validation, and passivity is moot; the fit is still stable by construction, and the stated covariance is held to what the fitted scattering matrix requires wherever a solver evaluates it.

If block states its zero frequency behavior, through the dcmodel it was built with, the fit meets the statement exactly: the value at zero is linear in the residues once the poles settle, so it is imposed as an equality, on the residue fit and through the passivity enforcement. The statement is the caller's to make and is not checked against the data, which begins above zero and cannot check it. A statement far below the band may need poles placed there: on the connector data in the tests, a stated through or open is refused at twenty poles and accepted once a few poles sit below the band. A statement of unit norm – a through, an open, a short – pins the norm of any fit meeting it at one, so such a fit is accepted at one to atol rather than contracted, which would move the statement; where the statement and passivity cannot both hold, the fit is refused.

pruneslack bounds how much the fit error may grow over the whole pruning, as a fraction of the error before any pole was dropped. It bounds the pruned fit, not the returned block: the feedthrough repair and the passivity enforcement come after. margin must be well below the block's own dissipation 1 - sigma, or the enforcement writes over the loss it should preserve.

The dissipation I - S S' is a difference of nearly equal quantities when the block is nearly lossless, so a fit error E appears in it as roughly 2E. A block with dissipation of order 1e-5 needs a fit accurate to well under that before its noise means anything; compare the fitted dissipation against the data's before trusting the noise of a fit.

source
JosephsonCircuits.RationalScattering Method
julia
RationalScattering(block::ScatteringParameters; tol, minpoles = 4,
    maxpoles = nothing, noisefloor = 1e-12, frequencies = nothing,
    iterations = 30, passivity = true, atol = 1e-8, margin = 1e-6,
    rounds = 20, pruneslack = 0.05)

A RationalScattering block fitted to the scattering data of block at the fewest poles that meet tol, the largest allowed error over the samples as a fraction of the largest response, measured on the block that is returned, after any passivity enforcement. The order matters beyond tidiness because the states of the fit are the states a transient solve steps.

The search scans one order at a time from minpoles, because more poles do not always fit better: past the order the data supports, the pole relocation is decided by directions the samples do not determine, and the fit is then not merely inaccurate but often cannot be made passive at all. The orders meeting a tolerance are therefore a window rather than a tail, so there is nothing to bisect on, and an order that fails to fit counts as one that missed the tolerance. minpoles is the way not to pay for orders a block is known not to need.

Without maxpoles the search budgets itself by the degree the samples determine, the numerical rank of their Loewner pencil with noisefloor as the rank threshold, as a fraction of the largest singular value; it scans to twice that degree or to as many poles as samples, whichever is fewer, and stops sooner if four consecutive orders produce no fit at all, which is the model class running out. The degree is an estimate, not a bound: it moves with noisefloor, which measured data with a real noise floor wants larger than the default, which suits data good to nearly full precision; the pencil is built along cycling coordinate directions from at most four hundred samples, so dynamics weak or narrow in the directions it does not probe can be missed; and a constant term contributes to it. maxpoles overrides all of this and is a hard ceiling.

If no order meets tol, the closest fit found, its order, the degree the samples determine, and why any orders failed to fit are reported as an error, since a block quietly less accurate than asked for is worse than none: loosen tol, raise maxpoles, sample the block more finely, or fit a narrower band.

See the npoles method for the meaning of the remaining arguments, and for the warning about fitting a block with little loss: a tolerance which looks tight against S may still be far too loose against the dissipation I - S S', where the error appears roughly doubled.

source
JosephsonCircuits.S_directional_coupler! Method
julia
S_directional_coupler!(S::AbstractMatrix, α::Number, β::Number, 
    θ::Number, ϕ::Number)

Overwrite S with the scattering parameter matrix for an ideal directional coupler with the convention that if a wave is input at port 1, then port 2 is the through, port 3 is the coupled port, and port 4 is the isolated port:

julia
                           _______
port 1 (input)    -->  ====|     |==== --> port 2 (through)
                           |     |
port 4 (isolated) <--  ====|     |==== --> port 3 (coupled)
                           -------

[0            α            exp(im\*θ)β 0;
 α            0            0            exp(im\*ϕ)β;
 exp(im\*θ)β 0            0            α;
 0            exp(im\*ϕ)β α            0]

The directional coupler is specified by the real coefficients α, β such that α²+β² = 1 and the real phases θ, ϕ which satisfy the condition θ + ϕ = π ± 2_n_π.

The scattering parameter matrix is unitary. Arbitrary phases can be applied to any of the ports (eg. by connecting a lossless transmission line).

The voltage coupling coefficient c is a real number where α = √(1-c^2) and β = c. The coupling in dB is defined as C = -20*log10(c).

  • A symmetric directional coupler has θ = ϕ = π/2.

  • An anti-symmetric directional coupler has θ = 0 and ϕ = π.

  • A quadature hybrid has c = 1/√2 and θ = ϕ = π/2.

  • A magic-T hybrid or a rat-race hybrid has c = 1/√2 and θ = 0, ϕ = π.

References

Pozar, D. M. Microwave Engineering (4 ed.). John Wiley & Sons (2011) ISBN 9780470631553.

source
JosephsonCircuits.S_directional_coupler Method
julia
S_directional_coupler::Number, β::Number, θ::Number, ϕ::Number)

Overwrite S with the scattering parameter matrix for an ideal directional coupler with the convention that if a wave is input at port 1, then port 2 is the through, port 3 is the coupled port, and port 4 is the isolated port:

julia
                           _______
port 1 (input)    -->  ====|     |==== --> port 2 (through)
                           |     |
port 4 (isolated) <--  ====|     |==== --> port 3 (coupled)
                           -------

[0            α            exp(im\*θ)β 0;
 α            0            0            exp(im\*ϕ)β;
 exp(im\*θ)β 0            0            α;
 0            exp(im\*ϕ)β α            0]

The directional coupler is specified by the real coefficients α, β such that α²+β² = 1 and the real phases θ, ϕ which satisfy the condition θ + ϕ = π ± 2_n_π.

The scattering parameter matrix is unitary. Arbitrary phases can be applied to any of the ports (eg. by connecting a lossless transmission line).

The voltage coupling coefficient c is a real number where α = √(1-c^2) and β = c. The coupling in dB is defined as C = -20*log10(c).

  • A symmetric directional coupler has θ = ϕ = π/2.

  • An anti-symmetric directional coupler has θ = 0 and ϕ = π.

  • A symmetric hybrid coupler (a 90 degree or quadature hybrid) has c = 1/√2

and θ = ϕ = π/2.

  • An anti-symmetric hybrid coupler (a magic-T hybrid or a rat-race hybrid or

a 180 degree hybrid) has c = 1/√2 and θ = 0, ϕ = π.

References

Pozar, D. M. Microwave Engineering (4 ed.). John Wiley & Sons (2011) ISBN 9780470631553.

source
JosephsonCircuits.S_directional_coupler_antisymmetric! Method
julia
S_directional_coupler_antisymmetric!(S, couplingdB::Number)

Overwrite S with the scattering parameter matrix for an ideal anti-symmetric directional coupler with the convention that if a wave is input at port 1, then port 2 is the through, port 3 is the coupled port, and port 4 is the isolated port:

julia
                           _______
port 1 (input)    -->  ====|     |==== --> port 2 (through)
                           |     |
port 4 (isolated) <--  ====|     |==== --> port 3 (coupled)
                           -------

[0            α            exp(im\*θ)β 0;
 α            0            0            exp(im\*ϕ)β;
 exp(im\*θ)β 0            0            α;
 0            exp(im\*ϕ)β α            0]

where α = √(1-c^2) and β = c and c is the voltage coupling coefficient which is related to the coupling in dB as c = 10^(-couplingdB/20). The anti-symmetric directional coupler has θ = 0 and ϕ = π.

References

Pozar, D. M. Microwave Engineering (4 ed.). John Wiley & Sons (2011) ISBN 9780470631553.

source
JosephsonCircuits.S_directional_coupler_antisymmetric Method
julia
S_directional_coupler_antisymmetric(couplingdB::Number)

Return the scattering parameter matrix for an ideal anti-symmetric directional coupler with the convention that if a wave is input at port 1, then port 2 is the through, port 3 is the coupled port, and port 4 is the isolated port:

julia
                           _______
port 1 (input)    -->  ====|     |==== --> port 2 (through)
                           |     |
port 4 (isolated) <--  ====|     |==== --> port 3 (coupled)
                           -------

[0            α            exp(im\*θ)β 0;
 α            0            0            exp(im\*ϕ)β;
 exp(im\*θ)β 0            0            α;
 0            exp(im\*ϕ)β α            0]

where α = √(1-c^2) and β = c and c is the voltage coupling coefficient which is related to the coupling in dB as c = 10^(-couplingdB/20). The anti-symmetric directional coupler has θ = 0 and ϕ = π.

References

Pozar, D. M. Microwave Engineering (4 ed.). John Wiley & Sons (2011) ISBN 9780470631553.

source
JosephsonCircuits.S_directional_coupler_symmetric! Method
julia
S_directional_coupler_symmetric!(S, couplingdB::Number)

Overwrite S with the scattering parameter matrix for an ideal symmetric directional coupler with the convention that if a wave is input at port 1, then port 2 is the through, port 3 is the coupled port, and port 4 is the isolated port:

julia
                           _______
port 1 (input)    -->  ====|     |==== --> port 2 (through)
                           |     |
port 4 (isolated) <--  ====|     |==== --> port 3 (coupled)
                           -------

[0            α            exp(im\*θ)β 0;
 α            0            0            exp(im\*ϕ)β;
 exp(im\*θ)β 0            0            α;
 0            exp(im\*ϕ)β α            0]

where α = √(1-c^2) and β = c and c is the voltage coupling coefficient which is related to the coupling in dB as c = 10^(-couplingdB/20). The symmetric directional coupler has θ = ϕ = π/2.

References

Pozar, D. M. Microwave Engineering (4 ed.). John Wiley & Sons (2011) ISBN 9780470631553.

source
JosephsonCircuits.S_directional_coupler_symmetric Method
julia
S_directional_coupler_symmetric(couplingdB::Number)

Return the scattering parameter matrix for an ideal symmetric directional coupler with the convention that if a wave is input at port 1, then port 2 is the through, port 3 is the coupled port, and port 4 is the isolated port:

julia
                           _______
port 1 (input)    -->  ====|     |==== --> port 2 (through)
                           |     |
port 4 (isolated) <--  ====|     |==== --> port 3 (coupled)
                           -------

[0            α            exp(im\*θ)β 0;
 α            0            0            exp(im\*ϕ)β;
 exp(im\*θ)β 0            0            α;
 0            exp(im\*ϕ)β α            0]

where α = √(1-c^2) and β = c and c is the voltage coupling coefficient which is related to the coupling in dB as c = 10^(-couplingdB/20). The symmetric directional coupler has θ = ϕ = π/2.

References

Pozar, D. M. Microwave Engineering (4 ed.). John Wiley & Sons (2011) ISBN 9780470631553.

source
JosephsonCircuits.S_hybrid_coupler_antisymmetric! Method
julia
S_hybrid_coupler_antisymmetric!(S)

Overwrite S with the scattering parameter matrix for an ideal anti-symmetric hybrid (3 dB) coupler (a magic-T hybrid or a rat-race hybrid or a 180 degree hybrid) with the convention that if a wave is input at port 1, then port 2 is the through, port 3 is the coupled port, and port 4 is the isolated port:

julia
                           _______
port 1 (input)    -->  ====|     |==== --> port 2 (through)
                           |     |
port 4 (isolated) <--  ====|     |==== --> port 3 (coupled)
                           -------

[0            α            exp(im\*θ)β 0;
 α            0            0            exp(im\*ϕ)β;
 exp(im\*θ)β 0            0            α;
 0            exp(im\*ϕ)β α            0]

where α = β = 1/√2 and θ = 0 and ϕ = π for an anti-symmetric hybrid (3 dB) coupler.

References

Pozar, D. M. Microwave Engineering (4 ed.). John Wiley & Sons (2011) ISBN 9780470631553.

source
JosephsonCircuits.S_hybrid_coupler_antisymmetric Method
julia
S_hybrid_coupler_antisymmetric()

Return the scattering parameter matrix for an ideal anti-symmetric hybrid (3 dB) coupler (a magic-T hybrid or a rat-race hybrid or a 180 degree hybrid) with the convention that if a wave is input at port 1, then port 2 is the through, port 3 is the coupled port, and port 4 is the isolated port:

julia
                           _______
port 1 (input)    -->  ====|     |==== --> port 2 (through)
                           |     |
port 4 (isolated) <--  ====|     |==== --> port 3 (coupled)
                           -------

[0            α            exp(im\*θ)β 0;
 α            0            0            exp(im\*ϕ)β;
 exp(im\*θ)β 0            0            α;
 0            exp(im\*ϕ)β α            0]

where α = β = 1/√2 and θ = 0 and ϕ = π for an anti-symmetric hybrid (3 dB) coupler.

References

Pozar, D. M. Microwave Engineering (4 ed.). John Wiley & Sons (2011) ISBN 9780470631553.

source
JosephsonCircuits.S_hybrid_coupler_symmetric! Method
julia
S_hybrid_coupler_symmetric!(S)

Overwrite S with the scattering parameter matrix for an ideal symmetric hybrid (3 dB) coupler (a 90 degree or quadature hybrid) with the convention that if a wave is input at port 1, then port 2 is the through, port 3 is the coupled port, and port 4 is the isolated port:

julia
                           _______
port 1 (input)    -->  ====|     |==== --> port 2 (through)
                           |     |
port 4 (isolated) <--  ====|     |==== --> port 3 (coupled)
                           -------

[0            α            exp(im\*θ)β 0;
 α            0            0            exp(im\*ϕ)β;
 exp(im\*θ)β 0            0            α;
 0            exp(im\*ϕ)β α            0]

where α = β = 1/√2 and θ = ϕ = π/2 for a symmetric hybrid (3 dB) coupler.

References

Pozar, D. M. Microwave Engineering (4 ed.). John Wiley & Sons (2011) ISBN 9780470631553.

source
JosephsonCircuits.S_hybrid_coupler_symmetric Method
julia
S_hybrid_coupler_symmetric()

Return the scattering parameter matrix for an ideal symmetric hybrid (3 dB) coupler (a 90 degree or quadature hybrid) with the convention that if a wave is input at port 1, then port 2 is the through, port 3 is the coupled port, and port 4 is the isolated port:

julia
                           _______
port 1 (input)    -->  ====|     |==== --> port 2 (through)
                           |     |
port 4 (isolated) <--  ====|     |==== --> port 3 (coupled)
                           -------

[0            α            exp(im\*θ)β 0;
 α            0            0            exp(im\*ϕ)β;
 exp(im\*θ)β 0            0            α;
 0            exp(im\*ϕ)β α            0]

where α = β = 1/√2 and θ = ϕ = π/2 for a symmetric hybrid (3 dB) coupler.

References

Pozar, D. M. Microwave Engineering (4 ed.). John Wiley & Sons (2011) ISBN 9780470631553.

source
JosephsonCircuits.S_match! Method
julia
S_match!(S::AbstractArray)

Return the scattering parameters for a N port ideal match. OverwriteS with the output.

Examples

julia
julia> JosephsonCircuits.S_match!(ones(1,1))
1×1 Matrix{Float64}:
 0.0

julia> JosephsonCircuits.S_match!(ones(1,1,2))
1×1×2 Array{Float64, 3}:
[:, :, 1] =
 0.0

[:, :, 2] =
 0.0
source
JosephsonCircuits.S_open! Method
julia
S_open!(S::AbstractArray)

Return the scattering parameters for a N port ideal open. OverwriteS with the output.

Examples

julia
julia> JosephsonCircuits.S_open!(ones(1,1))
1×1 Matrix{Float64}:
 1.0

julia> JosephsonCircuits.S_open!(ones(2,2))
2×2 Matrix{Float64}:
 1.0  0.0
 0.0  1.0
source
JosephsonCircuits.S_short! Method
julia
S_short!(S::AbstractArray)

Return the scattering parameters for a N port ideal short. OverwriteS with the output.

Examples

julia
julia> JosephsonCircuits.S_short!(ones(1,1))
1×1 Matrix{Float64}:
 -1.0

julia> JosephsonCircuits.S_short!(ones(2,2))
2×2 Matrix{Float64}:
 -1.0   0.0
  0.0  -1.0
source
JosephsonCircuits.S_splitter! Method
julia
S_splitter!(S::AbstractArray)

Return the scattering parameters for a N port ideal lossless symmetrical reciprocal network. Overwrite S with the output.

Examples

julia
julia> JosephsonCircuits.S_splitter!(ones(2,2))
2×2 Matrix{Float64}:
 0.0  1.0
 1.0  0.0

julia> JosephsonCircuits.S_splitter!(ones(3,3))
3×3 Matrix{Float64}:
 -0.333333   0.666667   0.666667
  0.666667  -0.333333   0.666667
  0.666667   0.666667  -0.333333
source
JosephsonCircuits.Snoisetokeyed Method
julia
Snoisetokeyed(Snoise, inputmodes, components, outputmodes,
    outputportnumbers, w)

Convert a noise scattering parameter array Snoise vs frequency w to a keyed array. Return the keyed array.

Examples

julia
julia> JosephsonCircuits.Snoisetokeyed([11 12;21 22;;;],[(0,)],["C1","C2"],[(0,)],[1,2],[1.0])
5-dimensional KeyedArray(NamedDimsArray(...)) with keys:
   inputmode  1-element Vector{Tuple{Int64}}
   component  2-element Vector{String}
◪   outputmode  1-element Vector{Tuple{Int64}}
▨   outputport  2-element Vector{Int64}
▨   freqindex  1-element UnitRange{Int64}
And data, 1×2×1×2×1 Array{Int64, 5}:
[:, :, 1, 1, 1] ~ (:, :, (0,), 1, 1):
          ("C1")  ("C2")
   (0,)   11      21

[:, :, 1, 2, 1] ~ (:, :, (0,), 2, 1):
          ("C1")  ("C2")
   (0,)   12      22
source
JosephsonCircuits.Ssensitivitytokeyed Method
julia
Ssensitivitytokeyed(Ssensitivity, outputmodes, outputportnumbers,
    inputmodes, inputportnumbers, components, w)

Return the scattering parameter sensitivity array as a keyed array with axes (outputmode, outputport, inputmode, inputport, component, freqindex).

source
JosephsonCircuits.StoA Function
julia
StoA(S)

Convert the scattering parameter matrix S to the chain (ABCD) matrix A and return the result.

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006.

source
JosephsonCircuits.StoA! Method
julia
StoA!(A::AbstractMatrix, S::AbstractMatrix, tmp::AbstractMatrix,
    sqrtportimpedances1, sqrtportimpedances2)

See StoA for description.

source
JosephsonCircuits.StoABCD Function
julia
StoABCD(S;portimpedances=50.0))

Convert the scattering parameter matrix S to the 2 port chain (ABCD) matrix and return the result. Assumes a port impedance of 50 Ohms unless specified with the portimpedances keyword argument.

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006.

source
JosephsonCircuits.StoB Function
julia
StoB(S)

Convert the scattering parameter matrix S to the inverse chain (ABCD) matrix B and return the result. Note that despite the name, the inverse of the chain matrix is not equal to the inverse chain matrix, inv(A) ≠ B.

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006.

source
JosephsonCircuits.StoB! Method
julia
StoB!(B::AbstractMatrix, S::AbstractMatrix, tmp::AbstractMatrix,
    sqrtportimpedances1, sqrtportimpedances2)

See StoB for description.

source
JosephsonCircuits.StoT Function
julia
StoT(S)

Convert the scattering parameter matrix S to a transmission matrix T and return the result.

Examples

julia
julia> S = Complex{Float64}[0.0 1.0;1.0 0.0];JosephsonCircuits.StoT(S)
2×2 Matrix{ComplexF64}:
  1.0+0.0im  -0.0+0.0im
 -0.0-0.0im   1.0-0.0im

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006.

source
JosephsonCircuits.StoT! Method
julia
StoT!(T::AbstractMatrix,S::AbstractMatrix,tmp::AbstractMatrix)

See StoT for description.

source
JosephsonCircuits.StoY Function
julia
StoY(S;portimpedances=50.0)

Convert the scattering parameter matrix S to an admittance parameter matrix Y and return the result. Assumes a port impedance of 50 Ohms unless specified with the portimpedances keyword argument.

Examples

julia
julia> S = Complex{Float64}[0.0 0.999;0.999 0.0];JosephsonCircuits.StoY(S)
2×2 Matrix{ComplexF64}:
  19.99+0.0im  -19.99+0.0im
 -19.99+0.0im   19.99+0.0im

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006.

source
JosephsonCircuits.StoY! Method
julia
StoY!(Y::AbstractMatrix,S::AbstractMatrix,tmp::AbstractMatrix,oneoversqrtportimpedances)

In place version of StoY, writing into Y with tmp as scratch and oneoversqrtportimpedances the reciprocal square roots of the port impedances.

source
JosephsonCircuits.StoZ Function
julia
StoZ(S;portimpedances=50.0)

Convert the scattering parameter matrix S to an impedance parameter matrix Z and return the result. Assumes a port impedance of 50 Ohms unless specified with the portimpedances keyword argument.

Examples

julia
julia> S = Complex{Float64}[0.0 0.0;0.0 0.0];JosephsonCircuits.StoZ(S)
2×2 Matrix{ComplexF64}:
 50.0+0.0im   0.0+0.0im
  0.0+0.0im  50.0+0.0im

julia> S = Complex{Float64}[0.0 0.999;0.999 0.0];JosephsonCircuits.StoZ(S)
2×2 Matrix{ComplexF64}:
 49975.0+0.0im  49975.0+0.0im
 49975.0+0.0im  49975.0+0.0im

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006.

source
JosephsonCircuits.StoZ! Method
julia
StoZ!(Z::AbstractMatrix,S::AbstractMatrix,tmp::AbstractMatrix,sqrtportimpedances)

See StoZ for description.

source
JosephsonCircuits.Stokeyed Method
julia
Stokeyed(S, outputmodes, outputportnumbers, inputmodes, inputportnumbers)

Convert a scattering parameter array S to a keyed array. Returned the keyed array.

Examples

julia
julia> JosephsonCircuits.Stokeyed([11 12;21 22],[(0,)],[1,2],[(0,)],[1,2])
4-dimensional KeyedArray(NamedDimsArray(...)) with keys:
   outputmode  1-element Vector{Tuple{Int64}}
   outputport  2-element Vector{Int64}
◪   inputmode  1-element Vector{Tuple{Int64}}
▨   inputport  2-element Vector{Int64}
And data, 1×2×1×2 Array{Int64, 4}:
[:, :, 1, 1] ~ (:, :, (0,), 1):
          (1)  (2)
   (0,)    11   21

[:, :, 1, 2] ~ (:, :, (0,), 2):
          (1)  (2)
   (0,)    12   22
source
JosephsonCircuits.Stokeyed Method
julia
Stokeyed(S, outputmodes, outputportnumbers, inputmodes,
    inputportnumbers, w)

Convert a scattering parameter array S vs frequency w to a keyed array. Returned the keyed array.

Examples

julia
julia> JosephsonCircuits.Stokeyed([11 12;21 22;;;],[(0,)],[1,2],[(0,)],[1,2],[1.0])
5-dimensional KeyedArray(NamedDimsArray(...)) with keys:
   outputmode  1-element Vector{Tuple{Int64}}
   outputport  2-element Vector{Int64}
◪   inputmode  1-element Vector{Tuple{Int64}}
▨   inputport  2-element Vector{Int64}
▨   freqindex  1-element UnitRange{Int64}
And data, 1×2×1×2×1 Array{Int64, 5}:
[:, :, 1, 1, 1] ~ (:, :, (0,), 1, 1):
          (1)  (2)
   (0,)    11   21

[:, :, 1, 2, 1] ~ (:, :, (0,), 2, 1):
          (1)  (2)
   (0,)    12   22
source
JosephsonCircuits.TransmissionLine Method
julia
TransmissionLine(Z0, len; vp = speed_of_light, grounded = true,
    noise = Passive())

An ideal lossless transmission line of characteristic impedance Z0 Ohms, length len meters, and phase velocity vp meters per second, as a two port ScatteringParameters referenced to Z0. Its TransmissionLineProvider is exact at every signed frequency, so the block uses Native negative frequency evaluation. grounded and noise are as for ScatteringParameters.

Examples

julia
julia> TransmissionLine(50.0, 1e-3).nports
2
source
JosephsonCircuits.TtoS Function
julia
TtoS(T)

Convert the transmission matrix T to a scattering parameter matrix S and return the result.

Examples

julia
julia> T = Complex{Float64}[1.0 0.0;0.0 1.0];JosephsonCircuits.TtoS(T)
2×2 Matrix{ComplexF64}:
 -0.0-0.0im   1.0+0.0im
  1.0-0.0im  -0.0-0.0im

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006 with change of sign on T11 and T21 terms (suspected typo).

source
JosephsonCircuits.TtoS! Method
julia
TtoS!(S::AbstractMatrix,T::AbstractMatrix,tmp::AbstractMatrix)

See TtoS for description.

source
JosephsonCircuits.X_Y_to_bogoliubov_block Method
julia
X_Y_to_bogoliubov_block(X::AbstractMatrix{<:Real}, Y::AbstractMatrix{<:Real})

Return the symplectic matrix S from the completely positive trace preserving (CPTP) map X, Y assumming a vacuum environment.

source
JosephsonCircuits.X_Y_to_bogoliubov_pair Method
julia
X_Y_to_bogoliubov_pair(X::AbstractMatrix{<:Real}, Y::AbstractMatrix{<:Real})

Return the symplectic matrix S from the completely positive trace preserving (CPTP) map X, Y assumming a vacuum environment.

source
JosephsonCircuits.X_Y_to_sympletic_block Method
julia
X_Y_to_sympletic_block(X::AbstractMatrix{<:Real}, Y::AbstractMatrix{<:Real})

Return the symplectic matrix S from the completely positive trace preserving (CPTP) map X, Y assumming a vacuum environment.

source
JosephsonCircuits.X_Y_to_sympletic_pair Method
julia
X_Y_to_sympletic_pair(X::AbstractMatrix{<:Real}, Y::AbstractMatrix{<:Real})

Return the symplectic matrix S from the completely positive trace preserving (CPTP) map X, Y assumming a vacuum environment.

source
JosephsonCircuits.Y_C Method
julia
Y_C(Cmaxwell,w)

The admittance matrix Y for a network of capacitors is the Maxwell capacitance matrix Cmaxwell times im*w.

source
JosephsonCircuits.Y_PiY! Method
julia
Y_PiY!(Y,Y1,Y2,Y3)

In-place version of Y_PiY.

Examples

julia
julia> JosephsonCircuits.Y_PiY!(zeros(Complex{Float64},2,2),1.0,2.0,4.0)
2×2 Matrix{ComplexF64}:
  5.0+0.0im  -4.0+0.0im
 -4.0+0.0im   6.0+0.0im
source
JosephsonCircuits.Y_PiY Method
julia
Y_PiY(Y1,Y2,Y3)

Return the admittance matrix for a Pi network of admittances Y1, Y2, and Y3.

julia
o----Y3-----o
   |     |   
   Y1    Y2  
   |     |   
o-----------o

Examples

julia
julia> JosephsonCircuits.Y_PiY(1.0+0.0im,2.0+0.0im,4.0+0.0im)
2×2 Matrix{ComplexF64}:
  5.0+0.0im  -4.0-0.0im
 -4.0-0.0im   6.0+0.0im
source
JosephsonCircuits.Y_invL Method
julia
Y_invL(L,w)

The admittance matrix Y for a network of inductors and mutual inductors is the inverse of the inductance matrix L divided by im*w.

source
JosephsonCircuits.Y_seriesY! Method
julia
Y_seriesY!(Y,Y1)

In-place version of Y_seriesY.

Examples

julia
julia> JosephsonCircuits.Y_seriesY!(zeros(Complex{Float64},2,2),1/50)
2×2 Matrix{ComplexF64}:
  0.02+0.0im  -0.02+0.0im
 -0.02+0.0im   0.02+0.0im
source
JosephsonCircuits.Y_seriesY Method
julia
Y_seriesY(Y1)

Return the Y matrix for a series admittance Y1.

julia
o---Y1---o
          
          
o--------o

Examples

julia
julia> JosephsonCircuits.Y_seriesY(1/(50.0+0.0im))
2×2 Matrix{ComplexF64}:
  0.02-0.0im  -0.02+0.0im
 -0.02+0.0im   0.02-0.0im
source
JosephsonCircuits.YtoA Function
julia
YtoA(Y)

Convert the admittance matrix Y to the chain (ABCD) matrix A and return the result.

Examples

julia
julia> Y = Complex{Float64}[1/50 1/50;1/50 1/50];JosephsonCircuits.YtoA(Y)
2×2 Matrix{ComplexF64}:
 -1.0+0.0im  -50.0+0.0im
  0.0+0.0im   -1.0+0.0im

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006 with change of overall sign on (suspected typo).

source
JosephsonCircuits.YtoA! Method
julia
YtoA!(A::AbstractMatrix,Y::AbstractMatrix,tmp::AbstractMatrix)

See YtoA for description.

source
JosephsonCircuits.YtoB Function
julia
YtoB(Y)

Convert the admittance matrix Y to the inverse chain matrix B and return the result.

Examples

julia
julia> Y = Complex{Float64}[1/50 1/50;1/50 1/50];JosephsonCircuits.YtoB(Y)
2×2 Matrix{ComplexF64}:
 -1.0+0.0im  -50.0+0.0im
  0.0+0.0im   -1.0+0.0im

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006.

source
JosephsonCircuits.YtoB! Method
julia
YtoB!(B::AbstractMatrix,Y::AbstractMatrix,tmp::AbstractMatrix)

See YtoB for description.

source
JosephsonCircuits.YtoS Function
julia
YtoS(Y;portimpedances=50.0)

Convert the admittance parameter matrix Y to a scattering parameter matrix S and return the result. portimpedances is a scalar, vector, or matrix of port impedances.

Examples

julia
julia> Y = Complex{Float64}[1/50.0 0.0;0.0 1/50.0];JosephsonCircuits.YtoS(Y)
2×2 Matrix{ComplexF64}:
  0.0-0.0im  -0.0-0.0im
 -0.0-0.0im   0.0-0.0im

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006.

source
JosephsonCircuits.YtoS! Method
julia
YtoS!(S::AbstractMatrix,Y::AbstractMatrix,tmp::AbstractMatrix,sqrtportimpedances)

See YtoS for description.

source
JosephsonCircuits.ZC_basis_coupled_tlines Method
julia
ZC_basis_coupled_tlines(L, Cmaxwell)

Returns the characteristic impedance matrix `ZC` and eigenbasis for
current `TI` and voltage `TV` from the inductance per unit length matrix
`L` and Maxwell capacitance per unit length matrix `Cmaxwell`.

Arguments

  • L: inductance per unit length matrix.

  • C: Maxwell capacitance per unit length matrix.

Returns

  • ZC: characteristic impedance matrix.

  • TI: matrix which transforms mode currents to currents, I = TI_Im. Computed from TI = U_theta*S.

  • TV: matrix which transforms mode voltages to voltages, V = TV_Vm. Computed from TV = U_inv(theta)*S.

  • theta: Diagonal matrix with the square of the eigenvalues of Cmaxwell along the diagonals.

  • U: eigenvectors of Cmaxwell.

  • lambda: Diagonal matrix with the square of the eigenvalues of theta_Ut_L_U_theta along the diagonals. lambda is related to the propagation constant, gamma, as gamma^2 = -omega^2*lambda^2.

  • S: eigenvectors of theta_Ut_L_U_theta.

Examples

julia
Zeven = 51.0
Zodd = 49.0
neven = 1.1
nodd = 1.08
c = JosephsonCircuits.speed_of_light

L, C = JosephsonCircuits.even_odd_to_maxwell(Zeven, Zodd, neven, nodd)
b = JosephsonCircuits.ZC_basis_coupled_tlines(L,C)
@show b.ZC
@show b.TI
@show b.TV
@show Matrix(b.theta)
@show b.U
@show Matrix(b.lambda)
@show b.S
println(isapprox(Zeven,b.ZC[1,1]+b.ZC[1,2]))
println(isapprox(Zodd,b.ZC[1,1]-b.ZC[1,2]))
println(isapprox(neven,b.lambda[2,2]*c))
println(isapprox(nodd,b.lambda[1,1]*c))

# output
b.ZC = [49.999999999999986 0.9999999999999929; 0.9999999999999929 49.999999999999986]
b.TI = [-6.063012846509498e-6 -5.997716107132906e-6; 6.063012846509498e-6 -5.997716107132906e-6]
b.TV = [-82467.25063230767 -83365.06614665617; 82467.25063230767 -83365.06614665617]
Matrix(b.theta) = [8.48205146197092e-6 0.0; 0.0 8.574394996376037e-6]
b.U = [-0.7071067811865475 -0.7071067811865475; -0.7071067811865475 0.7071067811865475]
Matrix(b.lambda) = [3.6024922281400425e-9 0.0; 0.0 3.669205047179673e-9]
b.S = [0.0 1.0; 1.0 0.0]
true
true
true
true

References

Paul, Clayton R. Analysis of Multiconductor Transmission Lines, Second Edition. Wiley, 2008.

source
JosephsonCircuits.Z_L Method
julia
Z_L(L,w)

The impedance matrix Z for a network of inductors and mutual inductors is the inductance matrix Z_L times im*w.

source
JosephsonCircuits.Z_TZ! Method
julia
Z_TZ!(Z,Z1,Z2,Z3)

In-place version of Z_TZ.

Examples

julia
julia> JosephsonCircuits.Z_TZ!(ones(Complex{Float64},2,2),1,2,4)
2×2 Matrix{ComplexF64}:
 5.0+0.0im  4.0+0.0im
 4.0+0.0im  6.0+0.0im
source
JosephsonCircuits.Z_TZ Method
julia
Z_TZ(Z1,Z2,Z3)

Return the ABCD matrix for a T network of impedances Z1, Z2, and Z3.

julia
o--Z1-----Z2--o
       |       
      Z3       
       |       
o-------------o

Examples

julia
julia> JosephsonCircuits.Z_TZ(1.0+0.0im,2.0+0.0im,4.0+0.0im)
2×2 Matrix{ComplexF64}:
 5.0+0.0im  4.0+0.0im
 4.0+0.0im  6.0+0.0im
source
JosephsonCircuits.Z_canonical_coupled_line_circuits Method
julia
Z_canonical_coupled_line_circuits(i::Int, Z0e, Z0o, thetae, thetao)

Return the impedance matrix for the i'th canonical coupled line circuit, as a function of the even mode phase delay thetae in radians, the odd mode phase delay thetao in radians, the even mode characteristic impedance Z0e in Ohms, and the odd mode characteristic impedance Z0o in Ohms.

  1. low pass
julia
   gnd--==========
1--> o--==========--o <--2
  1. band pass
julia
   gnd--==========--o <--2
1--> o--==========--gnd
  1. band pass
julia
        ==========--o <--2
1--> o--==========
  1. band pass
julia
1--> o--==========--gnd
2--> o--==========
  1. all pass
julia
        ==========
1--> o--==========--o  <--2
  1. all pass
julia
   gnd--==========--gnd
1--> o--==========--o  <--2
  1. all pass
julia
1--> o--==========--|
2--> o--==========--|
  1. all stop
julia
   gnd--==========--o  <--2
1--> o--==========
  1. all stop
julia
1--> o--==========--gnd
2--> o--==========--gnd
  1. all stop
julia
1--> o--==========
2--> o--==========

Examples

julia
julia> JosephsonCircuits.Z_canonical_coupled_line_circuits(3,50.0,30.0,pi/4,pi/3)
2×2 Matrix{ComplexF64}:
 0.0-33.6603im  0.0-18.0348im
 0.0-18.0348im  0.0-33.6603im

References

E. M. T. Jones, "Coupled-Strip-Transmission-Line Filters and Directional Couplers," in IRE Transactions on Microwave Theory and Techniques, vol. 4, no. 2, pp. 75-81, April 1956, doi: 10.1109/TMTT.1956.1125022.

Pozar, D. M. Microwave Engineering (4 ed.). John Wiley & Sons (2011) ISBN 9780470631553.

source
JosephsonCircuits.Z_coupled_tline! Method
julia
Z_coupled_tline!(Z, Z0e, Z0o, thetae, thetao)

In-place version of Z_coupled_tline.

Examples

julia
julia> JosephsonCircuits.Z_coupled_tline!(zeros(Complex{Float64},4,4),50,50,pi/4,pi/4)
4×4 Matrix{ComplexF64}:
 0.0-50.0im     0.0-0.0im      0.0-70.7107im  0.0-0.0im
 0.0-0.0im      0.0-50.0im     0.0-0.0im      0.0-70.7107im
 0.0-70.7107im  0.0-0.0im      0.0-50.0im     0.0-0.0im
 0.0-0.0im      0.0-70.7107im  0.0-0.0im      0.0-50.0im
source
JosephsonCircuits.Z_coupled_tline Method
julia
Z_coupled_tline(Z0e, Z0o, thetae, thetao)

Return the impedance matrix for two coupled transmission lines described even and odd mode impedances Z0e and Z0o and by even and odd mode phase delays thetae and thetao.

julia
thetae, Z0e
thetao, Z0o

V1, I1 -->  ======== <-- I3, V3
V2, I2 -->  ======== <-- I4, V4

[(V1+V2)/2, (I1+I2)/2] = ABCDe * [(V3+V4)/2, -(I3+I4)/2]
[(V1-V2)/2, (I1-I2)/2] = ABCDo * [(V3-V4)/2, -(I3-I4)/2]

[V1, V2, V3, V4] = Z_coupled_tline * [I1, I2, I3, I4]

Examples

julia
julia> JosephsonCircuits.Z_coupled_tline(50,50,pi/4,pi/4)
4×4 Matrix{ComplexF64}:
 0.0-50.0im     0.0-0.0im      0.0-70.7107im  0.0-0.0im
 0.0-0.0im      0.0-50.0im     0.0-0.0im      0.0-70.7107im
 0.0-70.7107im  0.0-0.0im      0.0-50.0im     0.0-0.0im
 0.0-0.0im      0.0-70.7107im  0.0-0.0im      0.0-50.0im
source
JosephsonCircuits.Z_invC Method
julia
Z_invC(invCmaxwell,w)

The impedance matrix Z for a network of capacitors is the inverse of the Maxwell capacitance matrix invCmaxwell divided by im*w.

source
JosephsonCircuits.Z_shuntZ! Method
julia
Z_shuntZ!(Z,Z1)

In-place version of Z_shuntZ.

Examples

julia
julia> JosephsonCircuits.Z_shuntZ!(zeros(Complex{Float64},2,2),50)
2×2 Matrix{ComplexF64}:
 50.0+0.0im  50.0+0.0im
 50.0+0.0im  50.0+0.0im
source
JosephsonCircuits.Z_shuntZ Method
julia
Z_shuntZ(Z1)

Return the Z matrix for a shunt impedance Z1.

julia
o---------o
     |
     Z1
     |
o---------o

Examples

julia
julia> JosephsonCircuits.Z_shuntZ(50.0+0.0im)
2×2 Matrix{ComplexF64}:
 50.0+0.0im  50.0+0.0im
 50.0+0.0im  50.0+0.0im
source
JosephsonCircuits.Z_tline! Method
julia
Z_tline!(Z, Z0, theta)

In-place version of Z_tline.

Examples

julia
julia> JosephsonCircuits.Z_tline!(ones(Complex{Float64},2,2),50, pi/4)
2×2 Matrix{ComplexF64}:
 0.0-50.0im     0.0-70.7107im
 0.0-70.7107im  0.0-50.0im
source
JosephsonCircuits.Z_tline Method
julia
Z_tline(Z0, theta)

Return the impedance matrix for a transmission line described by a characteristic impedance Z0 in Ohms and phase delay theta in radians

julia
   theta, Z0  
o--========--o
              
              
o------------o

Examples

julia
julia> JosephsonCircuits.Z_tline(50, pi/4)
2×2 Matrix{ComplexF64}:
 0.0-50.0im     0.0-70.7107im
 0.0-70.7107im  0.0-50.0im
source
JosephsonCircuits.ZtoA Function
julia
ZtoA(Z)

Convert the impedance matrix Z to the ABCD matrix A and return the result.

Examples

julia
julia> Z = Complex{Float64}[50.0 50.0;50.0 50.0];JosephsonCircuits.ZtoA(Z)
2×2 Matrix{ComplexF64}:
  1.0+0.0im  0.0-0.0im
 0.02+0.0im  1.0+0.0im

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006.

source
JosephsonCircuits.ZtoA! Method
julia
ZtoA!(A::AbstractMatrix,Z::AbstractMatrix,tmp::AbstractMatrix)

See ZtoA for description.

source
JosephsonCircuits.ZtoB Function
julia
ZtoB(Z)

Convert the impedance matrix Z to the inverse chain matrix B and return the result.

Examples

julia
julia> Z = Complex{Float64}[50.0 50;50 50];JosephsonCircuits.ZtoB(Z)
2×2 Matrix{ComplexF64}:
  1.0+0.0im  0.0-0.0im
 0.02+0.0im  1.0+0.0im

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006.

source
JosephsonCircuits.ZtoB! Method
julia
ZtoB!(B::AbstractMatrix,Z::AbstractMatrix,tmp::AbstractMatrix)

See ZtoB for description.

source
JosephsonCircuits.ZtoS Function
julia
ZtoS(Z;portimpedances=50.0)

Convert the impedance parameter matrix Z to a scattering parameter matrix S and return the result. portimpedances is a scalar, vector, or matrix of port impedances. Assumes a port impedance of 50 Ohms unless specified with the portimpedances keyword argument.

Examples

julia
julia> Z = Complex{Float64}[0.0 0.0;0.0 0.0];JosephsonCircuits.ZtoS(Z)
2×2 Matrix{ComplexF64}:
 -1.0+0.0im   0.0-0.0im
  0.0-0.0im  -1.0+0.0im

References

Russer, Peter. Electromagnetics, Microwave Circuit, And Antenna Design for Communications Engineering, Second Edition. Artech House, 2006.

source
JosephsonCircuits.ZtoS! Method
julia
ZtoS!(S::AbstractMatrix,Z::AbstractMatrix,tmp::AbstractMatrix,oneoversqrtportimpedances)

In place version of ZtoS, writing into S with tmp as scratch and oneoversqrtportimpedances the reciprocal square roots of the port impedances.

source
JosephsonCircuits._harvestfloquet! Method
julia
_harvestfloquet!(pc::FloquetPreconditioner, Vj, Hj)

Harvest candidate correction vectors from an Arnoldi factorization with basis Vj (n by j) and rectangular Hessenberg Hj (j + 1 by j, host resident) and return pc.

Two families are taken, following the principle that on a strongly nonnormal operator neither eigenvalue nor singular value information is reliably the better target:

  • the harvest right singular vectors of Hj with the smallest singular values, the directions this Krylov space found the preconditioned operator shrinks most;

  • the ritz harmonic Ritz directions nearest zero (harmonicritznearzero), which approximate its near-singular eigendirections.

Both are Krylov-space directions. Each is lifted through the Arnoldi basis and then mapped through the current complete preconditioner, x = B*u, into the physical state space before being stored, because that is the space in which a direction still means something once the Jacobian has moved: at the next point the exact image J*x is recomputed and the coarse space rebuilt around it, whereas a stored residual direction would have to be reinterpreted against an operator it was never measured on.

Nothing is rebuilt here. The preconditioner must not change under a running GMRES, so a harvest only appends to the candidate bank and marks the active blocks stale; the rebuild happens at the next Newton step.

source
JosephsonCircuits._rebuildfloquet! Method
julia
_rebuildfloquet!(pc::FloquetPreconditioner)

Rebuild the active basis from the candidate bank at the current point: the exact images Y0 = J*X0, the rank-revealing factorization which makes J*X = C with C'C = I, the base solves inv(P)*C, the correction strength filter, and the compression to size.

Costs k Jacobian products and r base solves for k candidates and active rank r.

source
JosephsonCircuits.activemoderows Function
julia
activemoderows(Nmodes::Integer, Amatrixindices::Matrix,
    Bmatrixindices::Union{Matrix,Nothing} = nothing)

For each column mode, return the sorted list of row modes for which the frequency domain index matrix Amatrixindices (or, if provided, Bmatrixindices) has a nonzero entry, ie. the row modes which contribute to the Jacobian sparsity structure in that column mode.

source
JosephsonCircuits.add_modes Method
julia
add_modes(connections::AbstractVector{Vector{Tuple{T,Int}}},
    Nmodes::Integer) where {T}

Assume the scattering parameter matrices are multi-mode and connections specifies the connections between physical ports. Return the connections vector with the existing connections re-numbered and with added connections between every mode associated with each physical port.

Examples

julia
julia> connections = [[("S1",3),("S2",4)],[("S1",2),("S2",1)]];JosephsonCircuits.add_modes(connections,2)
4-element Vector{Vector{Tuple{String, Int64}}}:
 [("S1", 5), ("S2", 7)]
 [("S1", 6), ("S2", 8)]
 [("S1", 3), ("S2", 1)]
 [("S1", 4), ("S2", 2)]
source
JosephsonCircuits.add_modes Method
julia
add_modes(connections::AbstractVector{Tuple{T,T,Int,Int}},
    Nmodes::Integer) where {T}

Assume the scattering parameter matrices are multi-mode and connections specifies the connections between physical ports. Return the connections vector with the existing connections re-numbered and with added connections between every mode associated with each physical port.

Examples

julia
julia> connections = [("S1","S2",3,4),("S1","S2",2,1)];JosephsonCircuits.add_modes(connections,2)
4-element Vector{Tuple{String, String, Int64, Int64}}:
 ("S1", "S2", 5, 7)
 ("S1", "S2", 6, 8)
 ("S1", "S2", 3, 1)
 ("S1", "S2", 4, 2)
source
JosephsonCircuits.add_splitters Method
julia
add_splitters(networks::AbstractVector{PassiveNetwork{T,N}},
    connections::AbstractVector{Vector{Tuple{T,Int}}};
    small_splitters = true) where {T,N}

Return the networks and connections with splitters (ideal lossless symmetrical reciprocal networks) and connections to the splitters added when more than two ports intersect. connections is also converted from a vector of vectors of tuples where the tuple contains the network and the port such as [[(:S1,1),(:S2,1)]] to a vector of tuples where the tuple contains the two networks and ports being connected [(:S1,:S2,1,1)]. With small_splitters = true an N port splitter is built by combining N-2 three port splitters; with false it is a single N port splitter.

References

S. F. Cao, Y. C. Jiao, and Z. Zhang. "Applications of Generalized Cascade Scattering Matrix on the Microwave Circuits and Antenna Arrays". International Journal of Antennas and Propagation Vol. 2015, 759439, doi:10.1155/2015/759439.

source
JosephsonCircuits.add_splitters Method
julia
add_splitters(networks, connections::AbstractVector{Tuple{T,T,Int,Int}};
    small_splitters = true) where T

Connections already in the pairwise (network1, network2, port1, port2) form are returned unchanged along with networks; splitters must already have been added.

source
JosephsonCircuits.addblockdc! Method
julia
addblockdc!(Fc, r::DCBlockRows, u, v)

Replace each block's zero frequency row in Fc, which holds -i, by the block's own relation B0 (scale dv) - C0 i, with the block currents read from u at the positions r.currentindex gives them and the average voltages from v.

The correction is added rather than written, because the row also carries the Kirchhoff coupling of the current into the node equations, which is unchanged and must survive.

source
JosephsonCircuits.addblocktransport! Method
julia
addblocktransport!(Fv, r::DCBlockRows, u)

Add the block currents which cross a component boundary to that component's transport row, reading each current from u at the position r.currentindex gives it.

Every one of them, unconditionally. A reference row is chosen after this, from the assembled descriptor, so there is no row here which is known in advance to be redundant and no current which may be dropped on the grounds that it lands in one.

source
JosephsonCircuits.addconstantsources! Method
julia
addconstantsources!(bbm, componenttypes, componentnames, nodeindices,
    vvn, cg, modes, Lscale, Nmodes)

Add the constant current sources of the netlist to the source vector in the branch basis: a CurrentSource component of value I drives the zero frequency mode with I flowing out of its first terminal and into its second, as the transient reads it, on its own branch and in the orientation the graph gave that branch. The mode must be retained: a nonzero source without it is an error, so that a netlist carrying a constant source is never solved without its bias in silence.

source
JosephsonCircuits.addjosephsonterm! Function
julia
addjosephsonterm!(nzval::AbstractVector,
    plan::StructureComplexJosephsonPlan, phimatrix, conjugate::Bool = false)

Write the Josephson contribution into nzval, overwriting it. With conjugate the map is the one whose source coefficients are conjugated, which is what the adjoint of the linearized system needs.

source
JosephsonCircuits.addsources! Method
julia
addsources!(bbm, modes, sources, portindices, portnumbers,
    nodeindices, edge2indexdict, Lscale, Nnodes, Nbranches, Nmodes)

Fill bbm with the source vector of calcsources. A source at a port number or mode not in the circuit is ignored.

source
JosephsonCircuits.adjointdevice Method
julia
adjointdevice(ds::DeviceSweep, i::Integer)

The adjoint solution of frequency i of the staged batch where it was computed, a view into the device batch, for the noise scattering parameters which are formed there rather than brought back (see devicenoise). A read of the solved batch, so several workers may hold different frequencies of it at once.

source
JosephsonCircuits.adjointnoisesigns! Method
julia
adjointnoisesigns!(Snoise::AbstractMatrix, wmodes, Nmodes::Integer)

The sign the adjoint route owes the noise scattering matrix: multiply Snoise[c, i] by the sign of the channel's mode frequency times the sign of the port's.

Snoise is formed by the adjoint identity, from the transposed system driven at the ports and read at the channels, because that costs one solve per port rather than one per channel. The output wave read at a channel c is kval_c * i*w_c * phi_c, with the signed mode frequency the voltage of a flux carries, and it is divided by the input wave at the port i, kval_i * Z_i * I_i / 2, which carries no frequency. The scattering matrix the channel's own drive would give is the reverse, kval_i * i*w_i * phi_i over kval_c * Z_c * I_c / 2, and by reciprocity of the transposed system the two flux responses per unit current are the same. With kval^2 = 1/(|w| Z) the ratio of the adjoint quantity to the true one is sign(w_c) * sign(w_i): the magnitudes agree, and the sign of every entry between a positive and a negative frequency mode is reversed. This restores it, so that Snoise is the scattering matrix from the channel's incoming wave to the port's outgoing wave in the same signed frequency convention as S; a resistor's channel is then exactly a port of its impedance in vacuum, and the cross terms of the added noise covariance between positive and negative frequency outputs compose with S as a Gaussian channel does. The quantum efficiency and the commutation relations read only magnitudes and do not see this.

source
JosephsonCircuits.adjointsolution! Method
julia
adjointsolution!(phin, ds::DeviceSweep, i::Integer)

The adjoint counterpart of forwardsolution!.

source
JosephsonCircuits.aliasmode Method
julia
aliasmode(mode::NTuple{N,Int}, Nt::NTuple{N,Int})

Alias the mode mode back onto the sampled grid with Nt time domain samples along each dimension, returning the canonical stored mode and whether the stored element is the complex conjugate of the requested mode. The first dimension is the RDFT dimension of a real signal, which stores only the modes from 0 to Nt[1] ÷ 2; a mode which aliases onto the other half of that dimension is stored as the complex conjugate at the negated mode. The other dimensions are full DFT dimensions whose stored modes range from -(Nt[d]-1) ÷ 2 - iseven(Nt[d]) to (Nt[d]-1) ÷ 2.

Examples

julia
julia> JosephsonCircuits.aliasmode((3,), (8,))
((3,), false)

julia> JosephsonCircuits.aliasmode((5,), (8,))
((3,), true)

julia> JosephsonCircuits.aliasmode((8,), (8,))
((0,), false)

julia> JosephsonCircuits.aliasmode((1, 3), (8, 4))
((1, -1), false)
source
JosephsonCircuits.allsinusoidal Method
julia
allsinusoidal(r::JunctionRelations)

Whether every junction of r is the sinusoidal Josephson one, which is the empty table: the solvers hold a table always, so that their type does not depend on what the circuit holds, and an empty one means the plain sin and cos of the Josephson relation.

source
JosephsonCircuits.amalgamate Method
julia
amalgamate(parent, post, nrows, target::Integer)

Merge chains of the elimination tree into supernodes: walking the postorder, a node joins the supernode of its child when it is that child's parent and the child its only child, until the supernode holds target rows. Each supernode is returned as its list of nodes, in elimination order.

source
JosephsonCircuits.andersoncorrection! Method
julia
andersoncorrection!(s::AndersonState, deltax; rtol = eps(T)^(3//4)) -> Bool

Assemble the Type-II Anderson correction cₖ = (Sₖ + Yₖ)γₖ into s.correction from the current history and the Newton update deltax. Return true when a usable correction was produced and false otherwise, such as when the history is empty or the coefficient solve fails or produces non-finite values, in which case s.correction must not be used.

The real extrapolation coefficients γ minimize ||ΔF*γ - deltax|| via ridge-regularized normal equations (with a default ridge = 1e-12 relative to the largest Gram diagonal), solved by LU with partial pivoting in place in the preallocated buffers. All history access is through age-ordered column indices (oldest first). The coefficients are constrained real because for the harmonic balance quasi-Newton map the error operator is antilinear (involves complex conjugation), so complex coefficients cannot cancel the error modes; real coefficients correspond to Anderson acceleration of the equivalent real system.

source
JosephsonCircuits.andersonhistory! Method
julia
andersonhistory!(s::AndersonState, x, deltax)

Record one step into the Anderson history. Once a previous iterate/update pair exists, write the differences x - xprev and deltax - deltaxprev into the oldest history column in place, then refresh the previous pair, so each stored difference spans exactly one step. The first call after construction (or after a full reset) only establishes the pair.

source
JosephsonCircuits.andersonrestart! Method
julia
andersonrestart!(s::AndersonState)

Discard the entire Anderson history (but keep the preallocated storage). This can be used after, for example, linesearch failures which suggest the local Anderson model was not useful. The previous iterate/update pair is kept, so the acceleration resumes from the next accepted step's difference.

source
JosephsonCircuits.applybackwardjosephsontranspose! Method
julia
applybackwardjosephsontranspose!(P, tplan, plan, w)

Apply the transposed Josephson backward map, scaled by the inverse conjugate multiplicity.

source
JosephsonCircuits.applybackwardterm! Method
julia
applybackwardterm!(out::AbstractVector, plan::NonlinearTermPlan,
    phimatrix::AbstractArray, z::AbstractVector;
    addlinearterm::Bool = true)

Apply the backward map of a NonlinearTermPlan, writing the node vector. Dispatches on the element type of out: a real vector receives the equivalent real representation and a complex vector the complex one, and z must be in the same representation. With addlinearterm = true the frequency dependent linear term applied to z is added in the same pass; with addlinearterm = false only the Josephson contribution is written, as the second directional derivative requires, and z is not read.

source
JosephsonCircuits.applydcconductance Method
julia
applydcconductance(bnm, plan, sol, Nmodes)

Subtract the direct current the resistors and blocks carry from the zero frequency rows of the source.

The solve does not use this: it carries the average voltages as unknowns and the currents reach the nodes through the coupling. What needs it is the Kirchhoff validation, which reconstructs its residual from the system alone and so knows nothing of that coupling; correcting the source here, and adding the same current back to the residual, hands it a consistent pair.

source
JosephsonCircuits.applydcsolve! Method
julia
applydcsolve!(z, r, d::DCFactorization)

Solve the direct current subsystem for the coordinates of r it owns and write the answer into the same coordinates of z, in place and on the backend the factorization lives on.

source
JosephsonCircuits.applydcupdate! Method
julia
applydcupdate!(Fw, uw, up::DCUpdate; residual = true)

Apply the direct current block in its matrix form.

source
JosephsonCircuits.applyfft! Method
julia
applyfft!(fd::AbstractArray{Complex{T}}, td::AbstractArray{T}, rfftplan)

The second half of applynl!: the frequency domain coefficients fd of the time domain signal td, the inverse of applyifft! with the same normalization convention. A nothing plan is the identity.

The real to complex transform of an out of place plan reads td and leaves it as it was (FFTW and cuFFT alike; only the complex to real direction of applyifft! may destroy its input), so a caller may hand in a cached time domain array directly.

source
JosephsonCircuits.applyffttranspose! Method
julia
applyffttranspose!(alpha::Array{Complex{T}}, P::Array{Complex{T}},
    padded::Array{Complex{T}}, fftplan)

Apply the transpose of applyfft!: given a covector P on the stored frequency domain coefficients, compute the covector alpha on the time domain samples such that sum(alpha .* td) == sum(P .* applyfft(td)) for every real time domain array td, exactly, including the truncated first dimension of the real transform.

This is a forward transform again, not a new kernel: the discrete Fourier matrix is symmetric, so the transpose of the transform which produces the stored coefficients is the full complex transform of those coefficients zero padded along the first dimension (the only dimension the real transform truncates; applyfft! stores only its non negative harmonics), with the same 1/prod(Nt) normalization. padded is a work array the size of the time domain grid and alpha may not alias it. The last dimension, the Josephson junction index, is not transformed, exactly as in applyfft!.

Used by the reverse order sensitivity contraction to transpose the map from the time domain samples to the Fourier coefficients of cos(phi(t)), through the same transform plans and normalization which define the forward map, for any number of tones.

source
JosephsonCircuits.applyforwardterm! Method
julia
applyforwardterm!(phimatrix::AbstractArray, plan::NonlinearTermPlan,
    z::AbstractVector)

Apply the forward map of a NonlinearTermPlan, writing the frequency domain coefficients of the Josephson junction branch fluxes for the point or direction z. Dispatches on the element type: a real vector is taken in the equivalent real representation and a complex vector in the complex one.

source
JosephsonCircuits.applyforwardtranspose! Method
julia
applyforwardtranspose!(out, tplan, Q, w)

Apply the transposed forward map and add the transposed linear term. Overwrites out.

source
JosephsonCircuits.applyifft! Method
julia
applyifft!(td::AbstractArray{T}, fd::AbstractArray{Complex{T}}, irfftplan)

The first half of applynl!: the physical time domain signal td from the frequency domain coefficients fd, with the normalization convention of applynl!, so that linear operations can be interleaved with the pointwise time domain nonlinearities. applyfft! is the other half, and applynl! is their composition with a pointwise function between them. A nothing plan (a system with no junctions) is the identity.

NOTE: applyifft! may overwrite fd.

source
JosephsonCircuits.applynl! Method
julia
applynl!(fd::AbstractArray{Complex{T}}, td::AbstractArray{T}, f,
    irfftplan, rfftplan)
applynl!(fd, td, f, ::Nothing, ::Nothing)

Apply the nonlinear function f to the frequency domain data by transforming to the time domain, applying the function, then transforming back to the frequency domain, overwriting the contents of fd and td in the process. We use plans for the forward and reverse RFFT prepared by plan_applynl.

Examples

julia
fd=ones(Complex{Float64},3,2)
td, irfftplan, rfftplan = JosephsonCircuits.plan_applynl(fd)
JosephsonCircuits.applynl!(fd, td, cos, irfftplan, rfftplan)
fd

# output
3×2 Matrix{ComplexF64}:
  0.856732+0.0im   0.856732+0.0im
 -0.143268+0.0im  -0.143268+0.0im
 -0.143268+0.0im  -0.143268+0.0im
source
JosephsonCircuits.applynl Method
julia
applynl(fd::Array{Complex{Float64}}, f::Function)

Perform the inverse discrete Fourier transform on an array fd of complex frequency domain data, apply the function f in the time domain, then perform the discrete Fourier transform to return to the frequency domain. Apply the Fourier transform on all but the last dimensions. See also applynl! and plan_applynl.

Examples

julia
julia> JosephsonCircuits.applynl([[0, 0.2+0.0im];;],cos)
2×1 Matrix{ComplexF64}:
   0.9603980498951228 + 0.0im
 -0.01966852794611884 + 0.0im

julia> JosephsonCircuits.applynl([0.0 + 0.0im 0.45 + 0.0im 0.45 + 0.0im; 0.55 + 0.0im 0.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im;;;],sin)
3×3×1 Array{ComplexF64, 3}:
[:, :, 1] =
 -0.0201302+0.0im    0.292163+0.0im    0.292163+0.0im
   0.380152+0.0im  -0.0423263+0.0im  -0.0423263+0.0im
 -0.0168084+0.0im  -0.0530698+0.0im  -0.0530698+0.0im
source
JosephsonCircuits.applypreconditioner! Function
julia
applypreconditioner!(z::AbstractVector, pc::AbstractPreconditioner,
    r::AbstractVector)

Overwrite z with the action of the inverse of the preconditioner pc on r and return z.

source
JosephsonCircuits.applyrealtocomplex! Method
julia
applyrealtocomplex!(xc::AbstractVector, plan::NonlinearTermPlan,
    xr::AbstractVector)
applycomplextoreal!(xr::AbstractVector, plan::NonlinearTermPlan,
    xc::AbstractVector)

Convert a node vector between the complex representation and the equivalent real one through the layout the plan carries, as a conflict free kernel on the plan's backend. These are the device capable counterparts of real_to_complex! and complex_to_real! for the two representations of an HBSystem point, which advance a serial cursor and read a BitVector.

source
JosephsonCircuits.applyrelationnl! Method
julia
applyrelationnl!(fd, td, work, relations, coefficients, trig, irfftplan,
    rfftplan)

applynl! with the per junction relation of relations in place of a single function: coefficients are the polynomial coefficients to evaluate, one junction per row, and trig is what the junctions the table marks sinusoidal take instead. work is a time domain array the size of td, which the Horner loop reads while it writes td.

source
JosephsonCircuits.applyscatteringstamps! Method
julia
applyscatteringstamps!(nzval::AbstractMatrix, st::DeviceScatteringStamps)

Add the staged scattering values into the stored values nzval of a batch of system matrices. stagescatteringstamps! must have run for the batch nzval was assembled at.

source
JosephsonCircuits.asoperator Method
julia
asoperator(A, n)

A itself when it is already mul!-able, and a FunctionOperator when it is a bare in-place product.

The Krylov solvers of this package apply the Jacobian through mul!, which is the interface every external linear algebra package in the ecosystem consumes. Normalizing here means a JacobianOperator can be handed straight through with no wrapper, while the older closure form keeps working.

source
JosephsonCircuits.assembleblocks! Method
julia
assembleblocks!(C::ClusterBlocks, S::BlockStructure, phimatrix)

Assemble the diagonal blocks and panels of one cluster from the Fourier coefficients phimatrix of cos(phi(t)) and the linear terms.

source
JosephsonCircuits.assemblebranch! Method
julia
assemblebranch!(nzval, seen, plan::BranchStampPlan, values, combine)

Fold values into the branch vector nzval against a fixed set of branches.

combine is applied to the running value and the new one in the order the components appear, matching sparsevec's combination of duplicate indices: two inductors on one branch combine as a parallel inductance, and two junctions raise the error that says to separate them.

source
JosephsonCircuits.assemblebranch Method
julia
assemblebranch(::Type{T}, plan::BranchStampPlan, values, combine, Nmodes)

The branch vector of values, repeated along the diagonal for Nmodes.

source
JosephsonCircuits.assemblecomplexjacobian! Method
julia
assemblecomplexjacobian!(nzval::AbstractVector,
    plan::StructureComplexJacobianPlan, phimatrix)

Assemble the stored values of the complex Jacobian: the Josephson map applied to the Fourier coefficients, plus the constant linear term.

source
JosephsonCircuits.assemblegrid Method
julia
assemblegrid(c::CompiledCircuit, cg::CircuitGraph, circuitdefs, Nmodes)

The numeric matrices of a compiled circuit at a different mode count.

The pump and the signal sweep of one analysis use different mode grids, so each assembles its own; the topology and the values behind them are the same.

source
JosephsonCircuits.assembleinvinductance Method
julia
assembleinvinductance(::Type{T}, plan, Lb, Nmodes)

The inverse nodal inductance matrix of the branch inductances Lb.

source
JosephsonCircuits.assemblematrices! Method
julia
assemblematrices!(nm::CircuitMatrices, plan::CircuitMatrixPlan,
    b::BoundCircuit)

The matrices of nm at the values of b, written into the storage nm already has. The patterns are the plan's and do not move, so only the stored values are rewritten: the nodal matrices through their stamp plans into a scratch the size of one mode and then repeated, and the branch vectors directly. The mutual inductance matrix, the value table and the scalars are rebuilt, and the returned CircuitMatrices shares every array with nm.

This is the sweep's assembly: hbsolve! calls it at every point.

source
JosephsonCircuits.assemblematrices Method
julia
assemblematrices(plan::CircuitMatrixPlan, b::BoundCircuit)

The CircuitMatrices of a bound circuit, assembled against the fixed patterns of plan.

Numerically identical to numericmatrices on the same circuit, entry for entry. The parts which are cheap to rebuild and depend on the values in ways a stamp plan does not express – the mutual inductance matrix, the solver scale and the port index lists – are still computed the same way; the plan covers the five which dominate (the capacitance, conductance, inductance, junction and inverse inductance stamps).

source
JosephsonCircuits.assemblenodal! Method
julia
assemblenodal!(nzval, seen, plan::NodalStampPlan, values)

Accumulate the stamps of values into nzval against a fixed pattern.

Contributions are summed in the order the coordinate form would have combined duplicates, so two components on one node pair add in the same order and the result is bit for bit the old assembly's.

source
JosephsonCircuits.assemblenodal Method
julia
assemblenodal(::Type{T}, plan::NodalStampPlan, values, Nmodes)

The nodal matrix of values, repeated along the diagonal for Nmodes.

source
JosephsonCircuits.assemblerealjacobian! Method
julia
assemblerealjacobian!(nzval::AbstractVector,
    plan::StructureRealJacobianPlan, phimatrix::AbstractArray;
    synchronize = true)

Assemble the stored values of the real Jacobian into nzval from the Fourier coefficients of cos(phi(t)), using the circuit's structure rather than a precomputed gather. On a device the assembly kernel is synchronized before returning unless synchronize = false, for a caller which orders the work on the stream itself, as the transient step does.

source
JosephsonCircuits.assemblescattering! Function
julia
assemblescattering!(A::SparseMatrixCSC, ssys::ScatteringStampSystem,
    wmodes::AbstractVector, work::ScatteringWorkspace = ScatteringWorkspace())

Add the frequency dependent constitutive entries of the scattering blocks at the signed mode frequencies wmodes into the values of the system matrix A: sign*im*w_m*scale*B[p,q](w_m) on the node flux columns and -C[p,q](w_m) on the auxiliary current columns, with the coefficients evaluated per block by evaluatehybrid! (which applies the negative frequency rule of each block, so the negative mode entries carry the complex conjugate data exactly as the conjugation of the conductance matrix does for resistors). The destination indices must have been set with setscatteringindexmap!. Thread safe when each thread has its own work and its own A: blocks are read only.

source
JosephsonCircuits.assemblesweep! Method
julia
assemblesweep!(nzval::AbstractMatrix, plan::FrequencySweepPlan,
    ws::AbstractVector)

Assemble the stored values of the linearized system matrix at each signal frequency of ws into the corresponding column of nzval, which must have one row per stored entry and one column per frequency.

Every stored value is written, so nzval need not be zeroed first.

source
JosephsonCircuits.assemblesystemmatrix! Method
julia
assemblesystemmatrix!(A::SparseMatrixCSC, lsys::HBLinearizedSystem,
    wmodes::AbstractVector; conjugatepump::Bool = false,
    scatteringwork = ScatteringWorkspace())
assemblesystemmatrix!(A::SparseMatrixCSC, lsys::HBLinearizedSystem,
    ws::Number; conjugatepump::Bool = false)

Assemble the linearized harmonic balance system matrix into A, which must share the sparsity structure of lsys.Asparse, either from the mode frequency vector wmodes or at the signal frequency ws (from which the mode frequencies are computed as wmodes = ws .+ lsys.wpumpmodes). The frequency scaling, the negative frequency conjugation, and any symbolic frequency substitution are applied per column from the mode index, without materializing system sized diagonals. With conjugatepump = true the complex conjugate of the pump modulation contribution is used, which for a circuit without scattering blocks is a similarity transformation of the transposed system, as below. The negative frequency mode entries of the linear term matrices are conjugated and any symbolic frequency variables substituted, exactly as in the per-frequency loop of hblinsolve, which calls this function. Returns A.

The conjugated pump system is a diagonal similarity transformation of the transposed forward system,

julia
A(conjugate pump) = D*transpose(A(pump))*inv(D),

with D diagonal, equal to one on every node flux row. (Historically D also carried the constitutive-equation conductance of promoted port resistors on their auxiliary rows; resistors are node conductances now, so no such rows exist.) Nothing else contributes, so long as the circuit has no scattering blocks: the auxiliary rows of the promoted coupled inductors are already symmetric (see calcAmnaind); the linear term matrices are symmetric and mode diagonal, so the column indexed frequency scaling and conjugation of sparseaddconjsubst! are symmetric under transposition; and the transpose of the pump modulation contribution exchanges the mode pair, mapping each difference harmonic to its complex conjugate, which is the same as conjugating the pump. The hybrid rows of a ScatteringParameters do break it: their constant Kirchhoff couplings and frequency dependent constitutive entries exchange under transposition, and no diagonal D undoes that, so with blocks the two are different matrices.

The adjoint solutions the noise, quantum efficiency, commutation relation and adjoint node output calculations read are in every case the solutions of the transposed system: by the adjoint identity, the response at an output port to a source anywhere in the circuit is that source contracted against the transposed solution driven at the port. hblinsolve obtains them with trysolvetranspose! on the factorization of the forward system, which costs a pair of triangular solves rather than an assembly and a factorization at every signal frequency. Where the similarity holds, the conjugated pump assembly is the independent construction that equivalence is tested against. scatteringwork is the scratch of the scattering block evaluation, one per worker in a sweep, so that a frequency allocates nothing for it.

source
JosephsonCircuits.atfrequency Method
julia
atfrequency(a, i)

The port argument a at the frequency index i: a number is the same everywhere, a vector holds one value per port for every frequency, a matrix has one column per frequency, and a PortDiagonal is the diagonal matrix of its ports there.

source
JosephsonCircuits.autonne_takagi Method
julia
autonne_takagi(M::AbstractMatrix{<:Real})

Return a vector Λ and a unitary matrix W for input matrix M such that M == W*Diagonal(Λ)*transpose(W) where M is a symmetric real matrix M = transpose(M).

source
JosephsonCircuits.autonne_takagi Method
julia
autonne_takagi(M::AbstractMatrix)

Return a vector Λ and a unitary matrix W for a symmetric complex input matrix M such that M == W*Diagonal(Λ)*transpose(W) where M satisfies M = transpose(M). Note that if M complex this means M is not Hermitian.

References

[1] A. M. Chebotarev and A. E. Teretenkov, “Singular value decomposition for the Takagi factorization of symmetric matrices,” Applied Mathematics and Computation, vol. 234, pp. 380–384, May 2014, doi: 10.1016/j.amc.2014.01.170. [2] M. Houde, W. McCutcheon, and N. Quesada, “Matrix decompositions in Quantum Optics: Takagi/Autonne, Bloch-Messiah/Euler, Iwasawa, and Williamson,” Can. J. Phys., vol. 102, no. 10, pp. 497–507, Oct. 2024, doi: 10.1139/cjp-2024-0070. [3] https://github.com/XanaduAI/thewalrus/pull/403

source
JosephsonCircuits.auxcurrentscale Method
julia
auxcurrentscale(Lscale)

The scale of the auxiliary port current unknowns of the scattering blocks in the linearized system, one over the solver inductance scale (see calcsolverscale).

A node unknown is a flux and an auxiliary unknown is a current, and flux over current is an inductance, so this writes the two in the same units, which puts the auxiliary columns of the system on the scale of the nodal ones. The nonlinear solve carries the same relation on its node fluxes, since those are its Newton unknowns; the linearized solve carries it on the port currents, which nothing outside the solve reads. A circuit with no scale to take leaves the unknowns as they are.

source
JosephsonCircuits.axis_to_modes Method
julia
axis_to_modes(S::AbstractArray, modes_axis::Integer)

Examples

julia
julia> JosephsonCircuits.axis_to_modes([111 121;211 221;;; 112 122;212 222;;; 113 123;213 223],3)
6×6 Matrix{Int64}:
 111    0    0  121    0    0
   0  112    0    0  122    0
   0    0  113    0    0  123
 211    0    0  221    0    0
   0  212    0    0  222    0
   0    0  213    0    0  223

julia> JosephsonCircuits.axis_to_modes([111 121;211 221;;;; 112 122;212 222;;;; 113 123;213 223],4)
6×6×1 Array{Int64, 3}:
[:, :, 1] =
 111    0    0  121    0    0
   0  112    0    0  122    0
   0    0  113    0    0  123
 211    0    0  221    0    0
   0  212    0    0  222    0
   0    0  213    0    0  223

julia> JosephsonCircuits.axis_to_modes([111 121;211 221;;;; 112 122;212 222;;;; 113 123;213 223],3)
2×2×3 Array{Int64, 3}:
[:, :, 1] =
 111  121
 211  221

[:, :, 2] =
 112  122
 212  222

[:, :, 3] =
 113  123
 213  223
source
JosephsonCircuits.backtracking_linesearch! Method
julia
backtracking_linesearch!(f!, F, xcandidate, x0, deltax, ϕ0, dϕ0dα;
    ls = Backtracking(), correction = nothing, beta = 1.0,
    Fbest = copy(F), ϕfullstep = nothing)

Backtracking line search on the curvilinear trial path:

julia
`x(α) = x0 + α*deltax - beta*α²*correction`

with objective ϕ(α) = 0.5*||F(x(α))||², following Nocedal & Wright section 3.5 with the addition of a curvilinear path. The α²term is a correction to the approximate Jacobian which improves convergence particularly for strongly driven 3WM problems. The α² scaling enables it to turn off at α=0 and not change the merit function or its derivatve at the starting point (so the definition of the Armijo condition is not changed). We currently compute correction using Anderson acceleration (Anderson mixing). When correction == nothing or beta == 0 the path is the straight path x + α*deltax.

When calling backtracking_linesearch!, F should either hold the residual at x (the same residual from which ϕ0 was computed) or that residual should be provided with the kwarg Fbest. The initial value of Fbest is saved and restored if the linesearch fails to find a point satisfying the sufficient-decrease condition or the residuals of the best found point if the line search is successful.

quadratic_trial_step performs a quadratic interpolation on the full-step data to estimate the trial step α at which the minimum of the merit function occurs. The full step data consists of the merit function value ϕ0 and derivative dϕ0dα at the starting point α=0 and the merit function value ϕfullstep at the full step α=1. If ϕfullstep is not provided by the user, then it is computed before calling quadratic_trial_step). If quadratic_trial_step returns a full step with the measured Boolean set to true, then we know it has already passed the Armijo sufficient-decrease condition ϕα <= ϕ0 + c1*α*dϕ0dα and can be used as the step. Return this step α and exit the function.

Otherwise loop over proposed trial step evaluations and cubic interpolations with cubic_trial_step. Once a successful trial step is identified return that or return the best identified once maxbacktracks is reached. The Armijo constant c1, the safeguards of the fits, the trial budget maxbacktracks and whether the fits are made at all are the fields of ls, a Backtracking. Without interpolation neither fit is made: the first backtrack is to α = 1/2 and every later one multiplies α by safeguardhigh, with the Armijo test at each trial.

This function always leavesxcandidate == x(α) and F holds the residual there (for α == 0 that is the residual at x0).

Returns (α, ϕα, accepted, backtracks):

  • accepted == true: α satisfies the α-scaled Armijo condition ϕα <= ϕ0 + c1*α*dϕ0dα, and ϕα is its measured objective value.

  • accepted == false: maxbacktracks was reached. α is the best (lowest measured ϕ) trial found, which may still be a useful step; if no trial produced any decrease at all, α == 0 and ϕα == ϕ0.

  • backtracks counts the trial evaluations after the full step, so the total number of f! residual evaluations is exactly backtracks + 1: the failure path restores the best trial's residual from a copy saved when it was measured (Fbest, a caller-suppliable scratch buffer whose contents are clobbered), never by re-evaluating.

source
JosephsonCircuits.backwardjosephsontransposekernel! Method
julia
backwardjosephsontransposekernel!(P, tbptr, tbnode, tbcoef, w, lptr,
    lwide, gtscale)

Transpose of the Josephson contribution of the backward map, one work item per frequency domain slot. Each item gathers the nodes which read its slot and writes its own entry of P, so the writes are disjoint and no atomic is needed.

Divides by the conjugate multiplicity in the same pass, which is the first half of the adjoint of applyfft!.

The imaginary part of a self-conjugate bin is deliberately not zeroed here. The pairing never sees it, so zeroing looks harmless, and in one dimension it is. In more than one it is wrong: the real part has to be taken after the transform along the remaining dimensions, not before, and the two differ as soon as the first-dimension zero-frequency slice has more than one element. The complex-to-real transform already discards exactly the right component, so the correct action here is none.

source
JosephsonCircuits.backwardtermkernel! Method
julia
backwardtermkernel!(out, bptr, bsrc, bcoef, phimatrix, kptr, kidx, kcoef,
    xr, lptr, lwide)

Evaluate the map from the frequency domain coefficients back to the node vector in the equivalent real representation, one work item per complex output index. Each work item gathers the coefficients of the Josephson branches incident to its node, scaled by the incidence matrix entry and Lscale/Lj, then gathers the one or two rows of the real form of the linear term matrix applied to xr, and writes the one or two real slots it owns. Those slots are disjoint across work items. Passing the kptrzero field of the plan as kptr switches the linear term off. See NonlinearTermPlan.

source
JosephsonCircuits.backwardtermkernelcomplex! Method
julia
backwardtermkernelcomplex!(out, bptr, bsrc, bcoef, phimatrix, kptr, kidx,
    kcoef, xc)

The complex representation counterpart of backwardtermkernel!. Each work item owns one complex output entry, gathers the same segment of Josephson contributions and one row of the complex form of the linear term matrix, so the real slot bookkeeping of the real representation is not needed. Passing the cptrzero field of the plan as kptr switches the linear term off. See NonlinearTermPlan.

source
JosephsonCircuits.batchedinverse! Method
julia
batchedinverse!(Dinv, D, F, backend)

For each k, Dinv[:, :, k] becomes the inverse of D[:, :, k], with F scratch of the same size: a loop of pivoted dense LU solves on the host, one batched call on a device (the CUDA extension).

source
JosephsonCircuits.batchedmul! Method
julia
batchedmul!(C, A, B, alpha, beta, tA::Bool, tB::Bool, backend)

C[:, :, k] = alpha*op(A[:, :, k])*op(B[:, :, k]) + beta*C[:, :, k] for every k, op the transpose when the flag is set: a loop of mul! on the host, one strided batched GEMM on a device (the CUDA extension).

source
JosephsonCircuits.bathamplitude Method
julia
bathamplitude(bath, frequency, weight)

The peak amplitude 2 sqrt(h f df/R) of the cosine and sine Norton currents representing one quadrature pair of bath at the frequency f in Hz with the quadrature weight df in Hz. With the independent quadratures at variance thermaloccupation(2pi f, T)/2 = nbar + 1/2 this gives the bilateral symmetrized current spectral density h f/R coth(h f/2kT), 2kT/R classically.

source
JosephsonCircuits.bathfamily Method
julia
bathfamily(block::LinearizedScattering, frequencies)

The bath frequencies in Hz for a pumped block as the ladders of its pump, one BathLadder each: the modes of a transient's noise are the signed frequencies 2pi f and -2pi f, as the linearized solver's modes are its, and a block couples nothing between frequencies which are not a multiple of its pump apart, so the modes are grouped by ladder (see pumpladders) and each ladder gets the outputs its data covers with every input which feeds them.

Its noise is assembled, completed and read one ladder at a time (see pumpednoisematrices), so every pair term of the group is an entry of the matrix of one ladder and nothing of the block's noise is ever a matrix over all the bath frequencies, whose size would grow with the square of their number.

source
JosephsonCircuits.bind Function
julia
bind(c::CompiledCircuit, circuitdefs = Dict{Symbol,Any}())

Resolve the component values of a compiled circuit into concrete per group arrays.

Symbolic values are substituted from circuitdefs; values which depend on frequency are resolved per mode later and are carried through unevaluated.

A bound circuit records the assumptions the compiled structure rests on – which inductances and resistances are finite and nonzero, which values are complex, which mutual couplings are unit – so that rebinding at new values can tell a change which only moves numbers from one which changes the topology. See structuralkey.

source
JosephsonCircuits.bindvalues Method
julia
bindvalues(c::CompiledCircuit, values)

A BoundCircuit from an already resolved flat value table.

This is the entry point for rebinding: the topology, the groups and the assembly plans are unchanged when only the numbers move, so a sweep resolves its values once per point and gathers them into the groups without touching anything structural. Check structuralkey before reusing a plan across a rebind.

source
JosephsonCircuits.bloch_messiah_block Method
julia
bloch_messiah_block(S::AbstractMatrix{<:Real})

Return the Bloch-Messiah (Euler) decomposition O, D, Q of the symplectic matrix S = O*Diagonal(D)*Q where O and Q are orthogonal-symplectic matrices and Diagonal(D) is a symplectic-diagonal and positive definite matrix. This is also called the symplectic singular value decomposition (SVD). The matrices are symplectric with respect to the block symplectic form Ω.

This decomposition is unique up to permutations and or degeneracies of the Takagi-Autonne singular values.

The singular values are the same as the regular SVD, but the ordering of the singular values and order/signs of the factors are different, in order to make them orthogonal-symplectic.

References

[1] G. Cariolaro and G. Pierobon, “Reexamination of Bloch-Messiah reduction,” Phys. Rev. A, vol. 93, no. 6, p. 062115, Jun. 2016, doi: 10.1103/PhysRevA.93.062115. [2] G. Cariolaro and G. Pierobon, “Bloch-Messiah reduction of Gaussian unitaries by Takagi factorization,” Phys. Rev. A, vol. 94, no. 6, p. 062109, Dec. 2016, doi: 10.1103/PhysRevA.94.062109. [3] M. Houde, W. McCutcheon, and N. Quesada, “Matrix decompositions in Quantum Optics: Takagi/Autonne, Bloch-Messiah/Euler, Iwasawa, and Williamson,” Can. J. Phys., vol. 102, no. 10, pp. 497–507, Oct. 2024, doi: 10.1139/cjp-2024-0070.

source
JosephsonCircuits.block_to_pair Method
julia
block_to_pair(S::AbstractMatrix)
source
JosephsonCircuits.block_to_pair Method
julia
block_to_pair(r::AbstractVector)

Examples

julia
r = [:x1, :x2, :x3, :x4, :p1, :p2, :p3, :p4]
JosephsonCircuits.block_to_pair(r)

# output
8-element Vector{Symbol}:
 :x1
 :p1
 :x2
 :p2
 :x3
 :p3
 :x4
 :p4
source
JosephsonCircuits.block_to_pair2 Method
julia
block_to_pair2(S::AbstractMatrix)
source
JosephsonCircuits.block_to_pair2 Method
julia
block_to_pair2(r::AbstractVector)
source
JosephsonCircuits.block_to_pair_perm Method
julia
block_to_pair_perm(n::Int)

Return a vector p which permutes the block operator ordering into the pair operator ordering.

Return a 2n length vector p which permutes the block operator ordering r = [x1,...,xn,p1,...,pn] to the pair operator ordering r[p] = (x_1,p_1,...,x_n,p_n).

Examples

julia
r = [:x1, :x2, :x3, :x4, :p1, :p2, :p3, :p4]
p = JosephsonCircuits.block_to_pair_perm(4)
r[p]

# output
8-element Vector{Symbol}:
 :x1
 :p1
 :x2
 :p2
 :x3
 :p3
 :x4
 :p4
source
JosephsonCircuits.blockfactorbytes Method
julia
blockfactorbytes(::Type{T}, keep::AbstractMatrix{Bool}, adj, order,
    Nmodes::Integer, layout::ModeLayout)

The bytes a BlockFactorization in precision T of the coupling mask keep will hold on the backend: the diagonal blocks, their inverses, the panels, the scratch of the largest blocks and the work vectors, over every cluster of the mask. Exact for the floating point storage the factorization allocates (the Int32 index maps are not counted), from the symbolic analysis alone, so a caller can decide whether the factors fit before building anything.

source
JosephsonCircuits.blocklu! Method
julia
blocklu!(lu::BlockLU, backend)

The right-looking block LU of the blocks lu holds, in place, over the batch: for each supernode in order, the pivoted dense LU of its diagonal block and the explicit inverse from it, the panel below scaled by that inverse, and the product of the scaled panel with the panel to the right subtracted from the later blocks it reaches. After this the panels and inverses are the factors.

source
JosephsonCircuits.blocklu Method
julia
blocklu(::Type{T}, sym, backend; nb = 1)

Allocate the BlockLU of the symbolic structure sym in precision T on backend, nb systems deep, with its Schur schedule: a supernode's panel product lands, through index maps, in the diagonal block or a panel of each later supernode it reaches.

source
JosephsonCircuits.blocknodegraph Method
julia
blocknodegraph(A::SparseMatrixCSC, blocksize::Integer)

The node graph of a matrix whose unknowns come in contiguous blocks of blocksize (a trailing shorter block allowed): the slot lists of the nodes and the symmetric adjacency read off the pattern.

source
JosephsonCircuits.blocknoisecontractkernel! Method
julia
blocknoisecontractkernel!

The noise output waves of the scattering block channels, one work item per (channel, mode, right hand side).

The noise a block adds is a source in its auxiliary port current rows, so by the adjoint identity its contribution at an output port is that source contracted against those same rows of the adjoint solution: sqrt(abs(w)) sum_p L[p,c] i[p]. Nothing else of the solution is read, which is why the adjoint solutions of a circuit with dissipative blocks need not come back from the backend at all.

source
JosephsonCircuits.blocknoisefactorkernel! Method
julia
blocknoisefactorkernel!

The factor L of the vacuum noise covariance I - S S' of each dissipative scattering block at each mode frequency, one work item per (block, mode), from tabulated or constant scattering data.

The factorization is psdcholesky!, which the host path runs too, so the two agree on the channels themselves and not only on the sums over them. Its covariance is built from 2 n^3 interpolations rather than caching the n^2 scattering parameters, because a work item has nowhere to cache them and a block has few ports.

source
JosephsonCircuits.blockresidual! Method
julia
blockresidual!(R, F::SparseBlockFactorization, X, B; transposed = false)

R_k = B - A_k X_k for the batch, or B - transpose(A_k) X_k with transposed, from the matrix's own blocks kept for the refinement, a batched dense product per block, in the matrix's precision.

source
JosephsonCircuits.blocksensitivitystamp Method
julia
blocksensitivitystamp(ssys, parameter)

The SensitivityStamp skeleton of a scattering block parameter: the triplet positions of the frequency dependent block pattern with zero values, which each worker fills at each signal frequency (refreshblockstamps!). Kind :S carries no further frequency scaling, exactly as :Lj does.

source
JosephsonCircuits.blocksolve! Method
julia
blocksolve!(X, F::SparseBlockFactorization, B; transposed = false)

Overwrite X (n x W x nb) with the solutions of A_k X_k = B (or transpose(A_k) X_k = B) for the batch, B (n x W) shared by the batch or (n x W x nb) one per system: every operation a batched dense product over a whole block, the right-hand side's columns and the batch. Forward substitution through the scaled panels, back substitution through the panels and the inverses; for the transposed system the same factors read the other way round, (D ⊕ U)ᵀ first as a lower block triangular solve with the transposed inverses, then (I + L)ᵀ backward.

source
JosephsonCircuits.blockstampvals! Method
julia
blockstampvals!(vals, dsys, zsys, wmodes, workd, workz, dbuf, zbuf,
    patternindex)

Overwrite vals (in the nonzero order of the stamp pattern) with the derivative of the block contribution at the signed mode frequencies wmodes: the values of the dS system minus the values of the zero system, scattered through patternindex.

source
JosephsonCircuits.blockstructure Method
julia
blockstructure(::Type{T}, sys, Amatrixindices::Matrix,
    Amatrixconjindices::Matrix, keep::AbstractMatrix{Bool},
    Rbnm::SparseMatrixCSC, Nmodes::Integer, Nbranches::Integer,
    Nfreq::Integer, layout::ModeLayout, singletons)

The BlockStructure for the coupling mask keep: one ClusterBlocks per connected component of two or more modes of the retained coupling graph, over the circuit-node graph ordered by klunodeorder. singletons is the block diagonal preconditioner for the remaining modes, or nothing.

source
JosephsonCircuits.blocksystembytes Method
julia
blocksystembytes(::Type{T}, sym; refine = false, TA = T)

The bytes one system of a SparseBlockFactorization in precision T holds, from the symbolic structure: blocks, panels, inverses, scratch, and the original blocks in TA when refining. What sizes the batch of a device sweep.

source
JosephsonCircuits.branchendpoints Method
julia
branchendpoints(Rbn::SparseMatrixCSC, Nbranches::Int)

The two nodes of every branch in the order the incidence matrix Rbn oriented it, as (from, to): branch b leaves from[b] and enters to[b]. Rbn carries -1 at a branch's source and 1 at its destination, and has no column for the ground node, which is node 1, so a branch with a terminal there keeps the initial value at that end.

One walk over the stored entries names the endpoints of every branch at once, which is where the mutual couplings read theirs from.

source
JosephsonCircuits.branchnodesandsigns Method
julia
branchnodesandsigns(Rbnm::SparseMatrixCSC, Nmodes::Integer,
    Nbranches::Integer)

Recover, for each branch, the list of (node, sign) pairs from the incidence matrix Rbnm = diagrepeat(Rbn, Nmodes) which converts node fluxes to branch fluxes. Verifies that Rbnm has the expected mode-diagonal structure (each entry connects a branch-mode to a node-mode of the same mode index, with the same value for every mode) and throws an error otherwise.

source
JosephsonCircuits.branchstampplan Method
julia
branchstampplan(c::CompiledCircuit, group, edge2indexdict, Nbranches)

Build the BranchStampPlan of a two terminal group.

source
JosephsonCircuits.buildcoupling Method
julia
buildcoupling(plan::PreconditionerPlan, S::AbstractModeCoupling, sys,
    factorization)

The pattern P, the assembly plan and the values it writes for the coupling set S of the system sys, factorized by factorization: the triple a ModeCouplingPreconditioner holds, rebuilt when its coupling set grows. On a device backend the Jacobian is built transposed, because its stored order is then the row major order a device sparse matrix and a device direct solver want; on a host the assembly writes straight into the stored values of P. A block factorization eliminates the circuit graph with dense blocks over the clusters of the coupling set, and the modes left single by the block diagonal are handed to this same preconditioner with the empty coupling set and the backend's sparse factorization.

source
JosephsonCircuits.calcAmna Method
julia
calcAmna(gaugeindices::Vector{Int}, Ntot::Int)

The constant gauge fixing rows of the augmented harmonic balance system of hbnlsolve: a one on the diagonal for each index in gaugeindices, one per floating component of the static flux-stiffness graph and zero-frequency mode (see calcdcgaugeindices), in an Ntot square sparse matrix. Because the Kirchhoff current law equations of a floating component are consistent but redundant at DC whenever the direct current subsystem has a solution, which dcpinning checks, this rank-one term renders the system nonsingular while the reference node flux is driven to exactly zero and all original equations remain satisfied.

The augmented state is the (Nnodes-1)*Nmodes node fluxes followed by the auxiliary variables of the mutually coupled inductor branches (calcAmnaind) and of the scattering block port currents, with the mode index fastest. These equations are linear, so the matrix is constant during the nonlinear solve and is its own contribution to the Jacobian.

source
JosephsonCircuits.calcAmnaind Method
julia
calcAmnaind(coupledbranches::Vector{Int}, Lb::SparseVector,
    Mb::SparseMatrixCSC, Rbn::SparseMatrixCSC, Nmodes::Int,
    auxoffset::Int, Ntot::Int, Lscale)

Calculate the constant sparse matrix which augments the harmonic balance system with auxiliary branch current variables for the mutually coupled inductors. For each coupled branch b and mode m an auxiliary variable u is added at index auxoffset + (r-1)*Nmodes + m (with r the position of b in coupledbranches) together with the branch flux constitutive equation

sum_p Rbn[b,p]*phi_p - sum_k (L[b,k]/Lscale)*u_k = 0,

where L[b,k] is the branch inductance matrix (the branch self inductances on the diagonal and the mutual inductances Mb off the diagonal), and the auxiliary variable enters the Kirchhoff current law equation of each node p of the branch with coefficient Rbn[b,p]. In the scaled units of the nonlinear solver the auxiliary variable is u = Lscale*i/phi0 with i the physical branch current in the orientation of the incidence matrix; the linearized solver uses Lscale = 1 and unscaled branch currents. All entries are real and frequency independent. Eliminating the auxiliary variables recovers exactly the coupled part of the nodal inverse inductance stamp, Lscale*Rbn'*inv(L)*Rbn (unit tested as a Schur complement identity), so the formulation is algebraically equivalent to the nodal one wherever the branch inductance matrix is invertible. Its entries remain bounded as the coupling coefficient approaches one, and unlike the nodal formulation it remains well posed at perfect coupling (|k| = 1) whenever the surrounding circuit determines the branch currents. Coupling between inductors sharing a single branch is rejected with an informative error (see mnacoupledbranches); a coupling matrix which leaves some branch current combination physically undetermined would produce a singular system caught at factorization.

source
JosephsonCircuits.calcCjIcmean Method
julia
calcCjIcmean(componenttypes::Vector{Symbol}, nodeindexarray::Matrix{Int},
    componentvalues::Vector, componentnamedict::Dict,
    mutualinductorbranchnames::Vector{String}, countdict::Dict,
    indexdict::Dict)

Calculate the junction properties including the max and min critical currents and ratios of critical current to junction capacitance. This is necessary in order to set the junction properties of the JJ model in WRSPICE.

Examples

julia
componenttypes = [:P, :R, :C, :Lj, :C, :C, :Lj, :C]
nodeindexarray = [2 2 2 3 3 3 4 4; 1 1 3 1 1 4 1 1]
componentvalues = Real[1, 50.0, 1.0e-13, 1.0e-9, 1.0e-12, 1.0e-13, 1.1e-9, 1.2e-12]
componentnamedict = Dict("R1" => 2, "Cc2" => 6, "Cj2" => 8, "Cj1" => 5, "P1" => 1, "Cc1" => 3, "Lj2" => 7, "Lj1" => 4)
mutualinductorbranchnames = String[]
countdict = Dict((:Lj, 1, 4) => 1, (:C, 3, 4) => 1, (:C, 1, 4) => 1, (:Lj, 1, 3) => 1, (:R, 1, 2) => 1, (:P, 1, 2) => 1, (:C, 1, 3) => 1, (:C, 2, 3) => 1)
indexdict = Dict((:C, 2, 3, 1) => 3, (:Lj, 1, 3, 1) => 4, (:C, 1, 3, 1) => 5, (:R, 1, 2, 1) => 2, (:C, 3, 4, 1) => 6, (:P, 1, 2, 1) => 1, (:C, 1, 4, 1) => 8, (:Lj, 1, 4, 1) => 7)
Cj, Icmean = JosephsonCircuits.calcCjIcmean(componenttypes, nodeindexarray,
    componentvalues, componentnamedict,mutualinductorbranchnames, countdict, indexdict)

# output
(3.1100514732000003e-13, 3.1414661345454545e-7)
julia
componenttypes = [:P, :R, :C, :Lj, :C, :C, :Lj, :C]
nodeindexarray = [2 2 2 3 3 3 4 4; 1 1 3 1 1 4 1 1]
componentvalues = Real[1, 50.0, 1.0e-13, 2.0e-9, 1.0e-12, 1.0e-13, 1.1e-9, 1.2e-12]
componentnamedict = Dict("R1" => 2, "Cc2" => 6, "Cj2" => 8, "Cj1" => 5, "P1" => 1, "Cc1" => 3, "Lj2" => 7, "Lj1" => 4)
mutualinductorbranchnames = String[]
countdict = Dict((:Lj, 1, 4) => 1, (:C, 3, 4) => 1, (:C, 1, 4) => 1, (:Lj, 1, 3) => 1, (:R, 1, 2) => 1, (:P, 1, 2) => 1, (:C, 1, 3) => 1, (:C, 2, 3) => 1)
indexdict = Dict((:C, 2, 3, 1) => 3, (:Lj, 1, 3, 1) => 4, (:C, 1, 3, 1) => 5, (:R, 1, 2, 1) => 2, (:C, 3, 4, 1) => 6, (:P, 1, 2, 1) => 1, (:C, 1, 4, 1) => 8, (:Lj, 1, 4, 1) => 7)
Cj, Icmean = JosephsonCircuits.calcCjIcmean(componenttypes, nodeindexarray,
    componentvalues, componentnamedict,mutualinductorbranchnames, countdict, indexdict)

# output
(2.2955141825999997e-13, 2.3187011945454544e-7)
source
JosephsonCircuits.calcCn Method
julia
calcCn(componenttypes::Vector{Symbol}, nodeindices::Matrix{Int},
    componentvalues::Vector, Nmodes, Nnodes)

Returns the node capacitance matrix from the capacitance values in componentvalues when componenttypes has the symbol :C with node indices from nodeindices. Other symbols are ignored. Capacitances to ground become diagonal elements. Capacitance between elements is an off-diagonal element with a minus sign and is added to the diagonal with a plus sign. The dimensions of the output are (Nnodes-1)*Nmodes by (Nnodes-1) times Nmodes where Nnodes is the number of nodes including ground and Nmodes is the number of different frequencies. Note that nodeindices is "one indexed" so 1 is the ground node.

Examples

julia
julia> JosephsonCircuits.calcCn([:C,:C],[2 3;1 1],[1.0,2.0],1,3)
2×2 SparseArrays.SparseMatrixCSC{Float64, Int64} with 2 stored entries:
 1.0 
   2.0

julia> JosephsonCircuits.calcCn([:C,:C,:C],[2 2 3;1 3 1],[1.0,0.1,2.0],1,3)
2×2 SparseArrays.SparseMatrixCSC{Float64, Int64} with 4 stored entries:
  1.1  -0.1
 -0.1   2.1

julia> JosephsonCircuits.calcCn([:C,:C,:C],[2 2 3;1 3 1],[1.0,0.1,2.0],2,3)
4×4 SparseArrays.SparseMatrixCSC{Float64, Int64} with 8 stored entries:
  1.1   -0.1 
    1.1   -0.1
 -0.1    2.1 
   -0.1    2.1
source
JosephsonCircuits.calcCnoise! Method
julia
calcCnoise!(Cnoise, S)

Calculate the noise wave covariance matrix for a scattering matrix in the field ladder operator basis. Overwrites Cnoise with output.

source
JosephsonCircuits.calcCnoise! Method
julia
calcCnoise!(Cnoise, S, Snoise)

Calculate the noise wave covariance matrix for a scattering matrix in the field ladder operator basis. Overwrites Cnoise with output.

Examples

julia
julia> C=zeros(Float64,2,2);JosephsonCircuits.calcCnoise!(C,[1 2;3 4],[0.0 0 0;0 0 0]);C
2×2 Matrix{Float64}:
 0.0  0.0
 0.0  0.0
source
JosephsonCircuits.calcCnoise Method
julia
calcCnoise(S::AbstractMatrix{T}) where {T}

Return the noise wave covariance matrix computed using Bosma's theorem for a passive linear network with scattering parameter matrix S. The network can be lossy and non-reciprocal.

This function assumes vacuum fluctuations as input to the ports, but could be extended to allow arbitrary noise temperatures.

Examples

julia
julia> JosephsonCircuits.calcCnoise(JosephsonCircuits.S_splitter!(zeros(Complex{Float64},2,2)))
2×2 Matrix{ComplexF64}:
 0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im

julia> S = rand(Complex{Float64},3,3);isapprox(JosephsonCircuits.calcCnoise(S),[1.0 0 0;0 1 0;0 0 1].-S*S')
true
source
JosephsonCircuits.calcCnoise Method
julia
calcCnoise(S::AbstractArray{T}, Snoise::AbstractArray{T}) where {T}

Calculate the noise wave covariance matrix for a scattering matrix in the field ladder operator basis.

Examples

julia
julia> JosephsonCircuits.calcCnoise([3/5 4/5;4/5 3/5],[0.0 0.0;0.0 0.0])
2×2 Matrix{Float64}:
 0.0  0.0
 0.0  0.0

julia> JosephsonCircuits.calcCnoise(Complex{Float64}[3/5 4/5;4/5 3/5],Complex{Float64}[0.0 0.0;0.0 0.0])
2×2 Matrix{ComplexF64}:
 0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im
source
JosephsonCircuits.calcGn Method
julia
calcGn(componenttypes::Vector{Symbol}, nodeindices::Matrix{Int},
    componentvalues::Vector, Nmodes, Nnodes)

Returns the node conductance matrix from the resistance values in componentvalues when componenttypes has the symbol :R. The node indices are taken from nodeindices. Conductances to ground are diagonal elements. Conductance between elements is an off-diagonal element with a minus sign and is added to the diagonal with a plus sign. The dimensions of the output are (Nnodes-1) times Nmodes by (Nnodes-1) times Nmodes. Note that nodeindices is "one indexed" so 1 is the ground node.

We have to calculate the inverse of the individual components so select a type that allows that.

Examples

julia
julia> JosephsonCircuits.calcGn([:R,:R],[2 3;1 1],[1.0,2.0],1,3)
2×2 SparseArrays.SparseMatrixCSC{Float64, Int64} with 2 stored entries:
 1.0 
   0.5

julia> JosephsonCircuits.calcGn([:R,:R,:R],[2 2 3;1 3 1],[1.0,100.0,2.0],1,3)
2×2 SparseArrays.SparseMatrixCSC{Float64, Int64} with 4 stored entries:
  1.01  -0.01
 -0.01   0.51

julia> JosephsonCircuits.calcGn([:R,:R,:R],[1 3 1;2 2 3],[1.0,100.0,2.0],1,3)
2×2 SparseArrays.SparseMatrixCSC{Float64, Int64} with 4 stored entries:
  1.01  -0.01
 -0.01   0.51

julia> JosephsonCircuits.calcGn([:R,:R,:R],[2 2 3;1 3 1],[1.0,100.0,2.0],2,3)
4×4 SparseArrays.SparseMatrixCSC{Float64, Int64} with 8 stored entries:
  1.01    -0.01 
     1.01    -0.01
 -0.01     0.51 
    -0.01     0.51
source
JosephsonCircuits.calcIb Method
julia
calcIb(componenttypes::Vector{Symbol}, nodeindices::Matrix{Int},
    componentvalues::Vector, edge2indexdict::Dict, Nmodes, Nbranches)

Calculate the sparse branch current source vector whose length is Nbranches*Nmodes. Note that nodeindices is "one indexed" so 1 is the ground node.

Examples

julia
Nmodes = 1
Nbranches = 2
componenttypes = [:I,:C,:L,:C]
nodeindices = [2 0 3 3; 1 0 1 1]
componentvalues = [1e-9, 0.2, 4e-9, 1e-12]
componentnamedict = Dict{Symbol, Int}(:C2 => 4,:L1 => 3,:I1 => 1,:C1 => 2)
edge2indexdict = Dict{Tuple{Int, Int}, Int}((1, 2) => 1,(3, 1) => 2,(1, 3) => 2,(2, 1) => 1)
Ib = JosephsonCircuits.calcIb(componenttypes,nodeindices,componentvalues,edge2indexdict,Nmodes,Nbranches)
JosephsonCircuits.testshow(stdout,Ib)

# output
sparsevec([1], [1.0e-9], 2)
julia
Nmodes = 1
Nbranches = 2
componenttypes = [:I,:C,:L,:C]
nodeindices = [2 0 3 3; 1 0 1 1]
componentvalues = [1.0, 2.0e-12, 3.0e-9, 4.0e-12]
componentnamedict = Dict{Symbol, Int}(:C2 => 4,:L1 => 3,:I1 => 1,:C1 => 2)
edge2indexdict = Dict{Tuple{Int, Int}, Int}((1, 2) => 1,(3, 1) => 2,(1, 3) => 2,(2, 1) => 1)
Ib = JosephsonCircuits.calcIb(componenttypes,nodeindices,componentvalues,edge2indexdict,Nmodes,Nbranches)
JosephsonCircuits.testshow(stdout,Ib)

# output
sparsevec([1], [1.0], 2)
source
JosephsonCircuits.calcLb Method
julia
calcLb(componenttypes::Vector{Symbol}, nodeindices::Matrix{Int},
    componentvalues::Vector, edge2indexdict::Dict, Nmodes, Nbranches)

Calculate the sparse branch inductance vector whose length is Nbranches*Nmodes. Note that nodeindices is "one indexed" so 1 is the ground node.

Examples

julia
Nmodes = 1
Nbranches = 2
componenttypes = [:L,:K,:L,:C]
nodeindices = [2 0 3 3; 1 0 1 1]
componentvalues = [1e-9, 0.2, 4e-9, 1e-12]
componentnamedict = Dict{Symbol, Int}(:C2 => 4,:L2 => 3,:L1 => 1,:K1 => 2)
edge2indexdict = Dict{Tuple{Int, Int}, Int}((1, 2) => 1,(3, 1) => 2,(1, 3) => 2,(2, 1) => 1)
Lb = JosephsonCircuits.calcLb(componenttypes,nodeindices,componentvalues,edge2indexdict,Nmodes,Nbranches)
JosephsonCircuits.testshow(stdout,Lb)

# output
sparsevec([1, 2], [1.0e-9, 4.0e-9], 2)
julia
Nmodes = 1
Nbranches = 2
componenttypes = [:L,:K,:L,:C]
nodeindices = [2 0 3 3; 1 0 1 1]
componentvalues = [1.0e-9, 0.1, 4.0e-9, 2.0e-12]
componentnamedict = Dict{Symbol, Int}(:C1 => 4,:L2 => 3,:L1 => 1,:K1 => 2)
edge2indexdict = Dict{Tuple{Int, Int}, Int}((1, 2) => 1,(3, 1) => 2,(1, 3) => 2,(2, 1) => 1)
Lb = JosephsonCircuits.calcLb(componenttypes,nodeindices,componentvalues,edge2indexdict,Nmodes,Nbranches)
JosephsonCircuits.testshow(stdout,Lb)

# output
sparsevec([1, 2], [1.0e-9, 4.0e-9], 2)
source
JosephsonCircuits.calcLjb Method
julia
calcLjb(componenttypes, nodeindices, componentvalues, edge2indexdict,
    Nmodes, Nbranches)

Calculate the sparse branch Josephson inductance vector whose length is Nbranches*Nmodes. Note that nodeindices is "one indexed" so 1 is the ground node.

Examples

julia
Nmodes = 1
Nbranches = 2
componenttypes = [:Lj,:C,:Lj,:C]
nodeindices = [2 3 3 3; 1 2 1 1]
componentvalues = [1e-9, 1e-12, 4e-9, 1e-12]
componentnamedict = Dict{Symbol, Int}(:C2 => 4,:L2 => 3,:L1 => 1,:Cc => 2)
edge2indexdict = Dict{Tuple{Int, Int}, Int}((1, 2) => 1,(3, 1) => 2,(1, 3) => 2,(2, 1) => 1)
Ljb = JosephsonCircuits.calcLjb(componenttypes,nodeindices,componentvalues,edge2indexdict,Nmodes,Nbranches)
JosephsonCircuits.testshow(stdout,Ljb)

# output
sparsevec([1, 2], [1.0e-9, 4.0e-9], 2)
julia
Nmodes = 1
Nbranches = 2
componenttypes = [:Lj,:K,:Lj,:C]
nodeindices = [2 0 3 3; 1 0 1 1]
componentvalues = [1.0e-9, 0.1, 4.0e-9, 2.0e-12]
componentnamedict = Dict{Symbol, Int}(:C1 => 4,:Lj2 => 3,:Lj1 => 1,:K1 => 2)
edge2indexdict = Dict{Tuple{Int, Int}, Int}((1, 2) => 1,(3, 1) => 2,(1, 3) => 2,(2, 1) => 1)
Ljb = JosephsonCircuits.calcLjb(componenttypes,nodeindices,componentvalues,edge2indexdict,Nmodes,Nbranches)
JosephsonCircuits.testshow(stdout,Ljb)

# output
sparsevec([1, 2], [1.0e-9, 4.0e-9], 2)
source
JosephsonCircuits.calcLmean Method
julia
calcLmean(componenttypes::Vector{Symbol}, componentvalues::Vector)

Return the mean of the linear and Josephson inductors.

Examples

julia
julia> JosephsonCircuits.calcLmean([:R,:L,:C,:Lj],[10,4,5,1])
2.5
source
JosephsonCircuits.calcLmean_inner Method
julia
calcLmean_inner(componenttypes::Vector, componentvalues::Vector,
    valuecomponenttypes::Vector)

Return the mean of the linear and Josephson inductors.

Examples

julia
julia> JosephsonCircuits.calcLmean_inner([:R,:L,:C,:Lj],[10,4,5,1],Float64[])
2.5

julia> JosephsonCircuits.calcLmean_inner([:R,:C,:C,:C],[10,4,5,1],Float64[])
0.0
source
JosephsonCircuits.calcMb Method
julia
calcMb(componenttypes::Vector{Symbol}, nodeindices::Matrix{Int},
    componentvalues::Vector, componentnamedict::Dict,
    mutualinductorbranchnames::Vector, edge2indexdict::Dict,
    Rbn::SparseMatrixCSC, Nmodes, Nbranches)

Returns the branch mutual inductance matrix. Note that nodeindices is "one indexed" so 1 is the ground node.

The sign of a mutual inductance says whether the two coupled currents, taken in the direction each inductor's terminals were declared in, add or oppose. The incidence matrix Rbn orients each branch by the spanning tree rather than by that declaration, so each entry is multiplied by the orientation of its two branches against the netlist (see mutualorientations). The orientations may be given in place of Rbn, as the Vector{Int8} mutualorientations returns and a CircuitMatrixPlan holds, so that a refill does not walk the incidence matrix.

Examples

julia
Nmodes = 1
Nbranches = 2
componenttypes = [:L,:K,:L,:C]
nodeindices = [2 0 3 3; 1 0 1 1]
componentvalues = [1e-9, 0.2, 2e-9, 1e-12]
componentnamedict = Dict{Symbol, Int}(:C2 => 4,:L2 => 3,:L1 => 1,:K1 => 2)
edge2indexdict = Dict{Tuple{Int, Int}, Int}((1, 2) => 1,(3, 1) => 2,(1, 3) => 2,(2, 1) => 1)
Rbn = JosephsonCircuits.SparseArrays.sparse([1, 2], [1, 2], [1, 1], 2, 2)
mutualinductorbranchnames = [ :L1, :L2]
Mb = JosephsonCircuits.calcMb(componenttypes,nodeindices,componentvalues,componentnamedict,mutualinductorbranchnames,edge2indexdict,Rbn,Nmodes,Nbranches)

# output
2×2 SparseArrays.SparseMatrixCSC{Float64, Int64} with 2 stored entries:
           2.82843e-10
 2.82843e-10
source
JosephsonCircuits.calcSsensitivity! Method
julia
calcSsensitivity!(Ssensitivity, stamps, dAop, dA, dAphin, phin,
    phinadjoint, S, gamma, beta, contraction, wmodes, Nmodes, symfreqvar)

Calculate the derivative of the scattering matrix with respect to a relative (logarithmic) perturbation of each component value, p -> r*p evaluated at r = 1, at the pump operating point, with the adjoint method. Overwrites Ssensitivity. stamps are the fixed operating point stamps of each component (see SensitivityStamp); dAop holds, per component, the values of the operating point contribution to dA in the sparsity structure of the linearized system matrix, or is empty when the operating point is held fixed; dA, dAphin and contraction are scratch of the size of the system matrix, the solution, and the output port mode pairs.

Differentiating the linearized system A*phi = b, whose source terms do not depend on any component value, gives dphi = -inv(A)*dA*phi, so with the adjoint solutions lam of the transposed system driven by the output functionals of calcsensitivityscaling!,

julia
dS[(j,n),(i,m)] = -gamma[(j,n)]*beta[(i,m)]
                  *transpose(lam[:,(j,n)])*dA*phi[:,(i,m)].

The adjoint source vectors are the source vectors of the forward problem scaled by im*w_n, which is folded into gamma, so phinadjoint, the solution of the transposed system already computed for the noise and quantum efficiency calculations, is used directly.

When the perturbed component is itself a port impedance the wave normalization of calcinputoutput! moves as well, contributing the additional closed form term -(portscale/2)*(P*(S+I) + (S+I)*P) with P the projector onto that port and portscale one in the relative form (the design parameter form carries (dZport/dp)/Zport), which is exact for constant real port impedances.

source
JosephsonCircuits.calcSsensitivityreverse! Method
julia
calcSsensitivityreverse!(Ssensitivity, rev::ReverseSensitivity, lsys,
    phin, phinadjoint, gamma, beta, cache,
    bufs::ReverseSensitivityBuffers)

Add the contribution of the shift of the pump operating point to the scattering parameter sensitivities, contracting in the reverse order so that the cost per component is a sparse inner product rather than a product against a matrix which is dense on the sparsity structure of the linearized system.

For each pair of output and input port modes (a,b), the transpose of the Josephson scatter of addjosephsonterm! gives

julia
transpose(lam_a)*dAop_k*phi_b
    = sum_s P[s]*dcos_k[s] + Q[s]*conj(dcos_k[s]),

with P and Q accumulated over the scatter lists of the plan. Since dcos_k is the directional derivative of the Fourier coefficients of cos(phi_b(t)) along the operating point shift (cosdirectionalderivative!), that is a linear functional of the shift, and with

julia
alpha = T(P),  gam = conj(T(Q)),  eta = -sin(phi_b(t)).*(alpha + gam)

with T the transposed transform (applyffttranspose! through rev.fftplan), and

its covector is the transpose of the branch flux map applied to eta. Finally the implicit function theorem gives dx_k = -inv(J)*dF_k, so pushing that covector through the transposed Jacobian once per output pair leaves a sparse inner product with dF_k for each component. The cost per signal frequency is (Nports*Nmodes)^2 transposed solves, independent of the number of components, instead of one product against the full sparsity structure per component. The solves are batched into multi right hand side calls whose column count is set by the REVERSESENSITIVITYCHUNKBYTES budget, which amortizes the per-call overhead of the sparse triangular solves while keeping the per batch work matrices memory bounded.

The transform of the pump harmonic grid is applied one dimension at a time, so this supports any number of pump tones.

source
JosephsonCircuits.calcVb Method
julia
calcVb(componenttypes::Vector{Symbol}, nodeindices::Matrix{Int},
    componentvalues::Vector, edge2indexdict::Dict, Nmodes, Nbranches)

Calculate the sparse branch voltage source vector whose length is Nbranches*Nmodes. Note that nodeindices is "one indexed" so 1 is the ground node.

Examples

julia
Nmodes = 1
Nbranches = 2
componenttypes = [:V,:C,:L1,:C]
nodeindices = [2 0 3 3; 1 0 1 1]
componentvalues = [1e-9, 0.2, 4e-9, 1e-12]
componentnamedict = Dict{Symbol, Int}(:C2 => 4,:L1 => 3,:V1 => 1,:C1 => 2)
edge2indexdict = Dict{Tuple{Int, Int}, Int}((1, 2) => 1,(3, 1) => 2,(1, 3) => 2,(2, 1) => 1)
Vb = JosephsonCircuits.calcVb(componenttypes,nodeindices,componentvalues,edge2indexdict,Nmodes,Nbranches)
JosephsonCircuits.testshow(stdout,Vb)

# output
sparsevec([1], [1.0e-9], 2)
julia
Nmodes = 1
Nbranches = 2
componenttypes = [:V,:C,:L,:C]
nodeindices = [2 0 3 3; 1 0 1 1]
componentvalues = [1.0, 2.0e-12, 3.0e-9, 4.0e-12]
componentnamedict = Dict{Symbol, Int}(:C2 => 4,:L1 => 3,:V1 => 1,:C1 => 2)
edge2indexdict = Dict{Tuple{Int, Int}, Int}((1, 2) => 1,(3, 1) => 2,(1, 3) => 2,(2, 1) => 1)
Vb = JosephsonCircuits.calcVb(componenttypes,nodeindices,componentvalues,edge2indexdict,Nmodes,Nbranches)
JosephsonCircuits.testshow(stdout,Vb)

# output
sparsevec([1], [1.0], 2)
source
JosephsonCircuits.calcblockresidualsensitivity Method
julia
calcblockresidualsensitivity(op::HBOperatingPoint, psc, blockpairs)

The derivative of the harmonic balance residual with respect to each scattering block design parameter of blockpairs = [(blockpath, parameterindex, derivativeblock)], at the operating point, in the real representation of the augmented residual (one column per pair, matching the columns calcresidualsensitivity produces for lumped pairs).

A block enters the nonlinear system as a constant matrix folded into the inverse inductance augmentation, so it moves the pump operating point and its residual derivative is +dA_block/dtheta applied to the converged state: the linear term enters the residual with a plus sign, and unlike the lumped :invL case – whose minus encodes d(1/L)/d(ln L) = -1/L, the derivative of the component law, not a residual sign – the block derivative is computed directly. The derivative matrix comes from the same affine subtraction as the linearized stamps, on a stamp system rebuilt for the pump mode grid with the geometry the operating point already determines: the augmented dimension is the state length and the block auxiliary variables occupy its tail.

source
JosephsonCircuits.calcbranchtimedomainmap Method
julia
calcbranchtimedomainmap(sys, Nmodes, NLj)

The matrix of the map from the branch fluxes of one Josephson junction to its physical time domain branch flux, with the real and the imaginary part of each mode as separate columns. The map is the same for every junction, because the packing and the inverse transform act on each junction independently, so it is built once by transforming unit branch fluxes with phivectortomatrix! and applyifft!, which keeps the conjugate mode bookkeeping inside the functions which define it. This is the transpose of the linear map from the unknowns to the time domain branch fluxes, restricted to one junction.

source
JosephsonCircuits.calcbranchvector Method
julia
calcbranchvector(componenttypes::Vector{Symbol},
    nodeindices::Matrix{Int}, componentvalues::Vector,
    valuecomponenttypes::Vector, edge2indexdict::Dict, Nmodes, Nbranches,
    component::Symbol, combine::Function)

Calculate the sparse branch vector whose length is Nbranches*Nmodes for the given component symbol. Note that nodeindices is "one indexed" so 1 is the ground node. The combine function determines how elements of the sparse vector will be combined.

source
JosephsonCircuits.calccircuitgraph Method
julia
calccircuitgraph(compiledcircuit::CompiledCircuit; loops = false)

Compute the CircuitGraph of a compiled circuit: the incidence matrix, a spanning tree, the closure branches, and (when loops = true) the loop each closure branch closes.

The graph is built from the branches of the inductive components, the Josephson junctions, the current and voltage sources and the ports; see extractbranches for the list. Nothing in the solvers reads the loops, and enumerating them costs a tree walk per closure branch, so they are enumerated only for a caller which passes loops = true.

See also calcgraphs.

Examples

julia
circuit = Circuit(
    [:p1 => Port(1; Z0 = :Rleft),
     :i1 => CurrentSource(:Ipump),
     :l1 => Inductor(:L),
     :jj => JosephsonJunction(:Lj),
     :cj => Capacitor(:Cj),
     :gnd => Ground()],
    [[(:p1, 1), (:i1, 1), (:l1, 1)],
     [(:l1, 2), (:jj, 1), (:cj, 1)],
     [(:p1, 2), (:i1, 2), (:jj, 2), (:cj, 2), (:gnd, 1)]])
psc = JosephsonCircuits.compile(circuit)
cg = JosephsonCircuits.calccircuitgraph(psc; loops = true)
JosephsonCircuits.comparestruct(cg,JosephsonCircuits.CircuitGraph(Dict((3, 2) => 3, (1, 2) => 1, (3, 1) => 2, (1, 3) => 2, (2, 1) => 1, (2, 3) => 3), JosephsonCircuits.SparseArrays.sparse([1, 3, 2, 3], [1, 1, 2, 2], [1, -1, 1, 1], 3, 2), [(1, 2), (1, 3)], [(3, 2)], [(1, 2), (1, 3), (2, 3)], [[2, 1, 3]], Int64[], JosephsonCircuits.Graphs.SimpleGraphs.SimpleGraph{Int64}(3, [[2, 3], [1, 3], [1, 2]]), 3))
# output
true
source
JosephsonCircuits.calccm! Function
julia
calccm(S::AbstractMatrix, w, noise = nothing)
calccm!(cm, S, w, noise = nothing; comp = similar(cm))

Calculate the bosonic commutation relations for a scattering matrix S in the field ladder operator basis: the sum of abs2 along each row, each column weighted by the sign of its mode frequency w[(j-1) % length(w) + 1], plus, with the NoiseReduction noise of the noise scattering matrix of the dissipative elements, the signed noise power noise.signed at each output. Represents energy conservation. The sum is compensated, and comp is its scratch, one entry per row. calccm! overwrites cm.

Examples

julia
julia> JosephsonCircuits.calccm(Complex{Float64}[3/5 4/5;4/5 3/5],[1])
2-element Vector{Float64}:
 1.0
 1.0

julia> JosephsonCircuits.calccm([1 1e-100 2e-100 1;1 0 0 1],[1, -1])
2-element Vector{Float64}:
 3.0e-200
 0.0

julia> cm=Float64[0,0];JosephsonCircuits.calccm!(cm,[3/5 4/5;4/5 3/5],[-1,1]);cm
2-element Vector{Float64}:
  0.28000000000000014
 -0.28000000000000014

julia> w = [1, -1]; JosephsonCircuits.calccm([1 2;3 4], w, JosephsonCircuits.noisereduction([1 2; 3 4; 5 6; 7 8], w))
2-element Vector{Float64}:
 -35.0
 -47.0
source
JosephsonCircuits.calcdcgaugeindices Method
julia
calcdcgaugeindices(floatingcomponents::Vector{Vector{Int}},
    wmodes::Vector, Nmodes::Int)

Return the indices of the node flux variables to which a gauge fixing equation will be added. For each floating component of the static flux-stiffness graph from calcstaticfluxcomponents and each mode with zero frequency (DC), one index is returned, corresponding to the lowest-numbered node of the component (the reference node). The DC flux of a floating component only enters the equations through differences of node fluxes within the component, so exactly one constraint per component and zero-frequency mode removes the gauge degree of freedom without overconstraining the system. The DC node flux reported as zero depends on the node ordering (the sorting keyword of the solvers): the reference is the lowest-numbered node of each component after sorting. All physical quantities are gauge independent and unaffected by this choice.

Examples

julia
julia> JosephsonCircuits.calcdcgaugeindices([[2],[3,4]],[0.0,2pi*4e9],2)
2-element Vector{Int64}:
 1
 3

julia> JosephsonCircuits.calcdcgaugeindices([[2],[3,4]],[2pi*4e9,2pi*8e9],2)
Int64[]
source
JosephsonCircuits.calcfreqs Method
julia
calcfreqs(Nharmonics::NTuple{N,Int}, Nw::NTuple{N,Int}, Nt::NTuple{N,Int})

Calculate the dimensions of the DFT or RFDT in the frequency domain and the time domain given a tuple of the number of harmonics. Eg. 0,w,2w,3w would be 3 harmonics. Also calculate the possible modes and their coordinates in the frequency domain RDFT array. See also calcfreqsrdft and calcfreqsdft.

source
JosephsonCircuits.calcfreqsdft Method
julia
calcfreqsdft(Nharmonics::NTuple{N,Int})

Calculate the dimensions of the DFT in the frequency domain and the time domain given a tuple of the number of harmonics. Eg. 0,w,2w,3w would be 3 harmonics. Also calculate the possible modes and their coordinates in the frequency domain DFT array.

Arguments

  • Nharmonics: is a tuple of the number of harmonics to calculate for each frequency.

Returns

  • Frequencies: A simple structure to hold time and frequency domain information for the signal for a single node. See Frequencies.
source
JosephsonCircuits.calcfreqsrdft Method
julia
calcfreqsrdft(Nharmonics::NTuple{N,Int})

Calculate the dimensions of the RDFT in the frequency domain and the time domain given a tuple of the number of harmonics. Eg. 0,w,2w,3w would be 3 harmonics. Also calculate the possible modes and their coordinates in the frequency domain RDFT array.

Arguments

  • Nharmonics: is a tuple of the number of harmonics to calculate for each frequency.

Returns

  • Frequencies: A simple structure to hold time and frequency domain information for the signal for a single node. See Frequencies.
source
JosephsonCircuits.calcgraphs Method
julia
calcgraphs(Ledgearray::Array{Tuple{Int, Int}, 1}, Nnodes::Int;
    loops = false)

Build the CircuitGraph of the branches Ledgearray, given as (node1, node2) tuples over Nnodes nodes with ground being node 1.

Each connected component of the branch graph gets a minimum spanning tree (Kruskal, on unit weights) rooted at its first vertex. The edges not in the tree are the closure branches, and when loops = true the loop of each closure branch is the unique path between its endpoints through the tree. The oriented incidence matrix is assembled from the tree edges followed by the closure branches, with vertices added for any nodes which carry no branch so that the matrix has Nnodes - 1 columns.

source
JosephsonCircuits.calcimpedance Method
julia
calcimpedance(c, type, w, symfreqvar)

Examples

julia
julia> JosephsonCircuits.@params w;JosephsonCircuits.calcimpedance(30*w,:R,2.0,w)
60.0 + 0.0im

julia> JosephsonCircuits.@params w;JosephsonCircuits.calcimpedance(30*w,:C,2.0,w)
0.0 - 0.008333333333333333im

julia> JosephsonCircuits.@params w;JosephsonCircuits.calcimpedance(30*w,:L,2.0,w)
0.0 + 120.0im

julia> JosephsonCircuits.@params w;JosephsonCircuits.calcimpedance(30*w,:R,-2.0,w)
-60.0 + 0.0im

julia> JosephsonCircuits.@params w;JosephsonCircuits.calcimpedance(30*w,:C,-2.0,w)
0.0 - 0.008333333333333333im

julia> JosephsonCircuits.@params w;JosephsonCircuits.calcimpedance(30*w,:L,-2.0,w)
0.0 + 120.0im
source
JosephsonCircuits.calcimpedance Method
julia
calcimpedance(c::Union{Integer,T,Complex{T}}, type, w, symfreqvar,
    ) where {T<:AbstractFloat}

Examples

julia
julia> JosephsonCircuits.calcimpedance(30.0,:C,1.0,nothing)
0.0 - 0.03333333333333333im

julia> JosephsonCircuits.calcimpedance(30.0,:L,1.0,nothing)
0.0 + 30.0im

julia> JosephsonCircuits.calcimpedance(30.0,:R,1.0,nothing)
30.0 + 0.0im

julia> JosephsonCircuits.calcimpedance(30.0,:C,-1.0,nothing)
-0.0 + 0.03333333333333333im

julia> JosephsonCircuits.calcimpedance(30.0,:L,-1.0,nothing)
-0.0 - 30.0im

julia> JosephsonCircuits.calcimpedance(30.0,:R,-1.0,nothing)
30.0 + 0.0im
source
JosephsonCircuits.calcindexdict Method
julia
calcindexdict(N::Int)

Return a dictionary of Cartesian indices where the Cartesian index is the key and the index giving the order is the value.

source
JosephsonCircuits.calcindexdict Method
julia
calcindexdict(N::Tuple)

Return a dictionary of Cartesian indices where the Cartesian index is the key and the index giving the order is the value.

source
JosephsonCircuits.calcinputoutput! Method
julia
calcinputoutput!(inputwave, outputwave, phin, bnm, inputportindices,
    outputportindices, inputportimpedances, outputportimpedances,
    nodeindices, componenttypes, wmodes, symfreqvar)

Return the input and output waves for the system linearized around the strong pump.

Examples

julia
inputwave = JosephsonCircuits.LinearAlgebra.Diagonal(ComplexF64[0])
outputwave = ComplexF64[0;;]
bnm = ComplexF64[1; 0;;]
portimpedanceindices = [3]
portimpedances = ComplexF64[50]
nodeindices = [2 2 2 2 0 3 3; 1 1 1 1 0 1 1]
componenttypes = [:P, :I, :R, :L, :K, :L, :C]
wmodes = [1]
phin = ComplexF64[0;0;;]
symfreqvar = nothing
JosephsonCircuits.calcinputoutput!(inputwave,outputwave,phin,bnm,portimpedanceindices,
    portimpedanceindices,portimpedances,portimpedances,nodeindices,componenttypes,
    wmodes,symfreqvar)
println(outputwave)

# output
ComplexF64[-3.5355339059327378 + 0.0im;;]
julia
inputwave = JosephsonCircuits.LinearAlgebra.Diagonal(ComplexF64[0])
outputwave = ComplexF64[0;;]
bnm = ComplexF64[1; 0;;]
portimpedanceindices = [3]
portimpedances = ComplexF64[50]
nodeindices = [2 2 2 2 0 3 3; 1 1 1 1 0 1 1]
componenttypes = [:P, :I, :R, :L, :K, :L, :C]
wmodes = [1]
phin = ComplexF64[50/(im*wmodes[1]);0;;]
symfreqvar = nothing
JosephsonCircuits.calcinputoutput!(inputwave,outputwave,phin,bnm,portimpedanceindices,
    portimpedanceindices,portimpedances,portimpedances,nodeindices,componenttypes,
    wmodes,symfreqvar)
println(outputwave)

# output
ComplexF64[3.5355339059327378 + 0.0im;;]
julia
inputwave = JosephsonCircuits.LinearAlgebra.Diagonal(ComplexF64[0])
outputwave = ComplexF64[0;;]
bnm = ComplexF64[1; 0;;]
portimpedanceindices = [3]
portimpedances = ComplexF64[50]
nodeindices = [1 1 1 1 0 1 1; 2 2 2 2 0 3 3;]
componenttypes = [:P, :I, :R, :L, :K, :L, :C]
wmodes = [1]
phin = ComplexF64[50/(im*wmodes[1]);0;;]
symfreqvar = nothing
JosephsonCircuits.calcinputoutput!(inputwave,outputwave,phin,bnm,portimpedanceindices,
    portimpedanceindices,portimpedances,portimpedances,nodeindices,componenttypes,
    wmodes,symfreqvar)
println(outputwave)

# output
ComplexF64[-3.5355339059327378 + 0.0im;;]
julia
inputwave = JosephsonCircuits.LinearAlgebra.Diagonal(ComplexF64[0])
outputwave = ComplexF64[0;;]
bnm = ComplexF64[-1; 1;;]
portimpedanceindices = [2]
portimpedances = ComplexF64[50.0 + 0.0im]
nodeindices = [2 2 2 2 3; 3 3 1 1 1]
componenttypes = [:P, :R, :L, :C, :C]
wmodes = [1]
phin = ComplexF64[0;0;;]
symfreqvar = nothing
JosephsonCircuits.calcinputoutput!(inputwave,outputwave,phin,bnm,portimpedanceindices,
    portimpedanceindices,portimpedances,portimpedances,nodeindices,componenttypes,
    wmodes,symfreqvar)
println(outputwave)

# output
ComplexF64[3.5355339059327378 + 0.0im;;]
julia
inputwave = JosephsonCircuits.LinearAlgebra.Diagonal(ComplexF64[0])
outputwave = ComplexF64[0;;]
bnm = ComplexF64[-1; 1;;]
portimpedanceindices = [2]
portimpedances = ComplexF64[50.0 + 0.0im]
nodeindices = [2 2 2 2 3; 3 3 1 1 1]
componenttypes = [:P, :R, :L, :C, :C]
wmodes = [1]
phin = ComplexF64[-50/(im*wmodes[1]);50/(im*wmodes[1]);;]
symfreqvar = nothing
JosephsonCircuits.calcinputoutput!(inputwave,outputwave,phin,bnm,portimpedanceindices,
    portimpedanceindices,portimpedances,portimpedances,nodeindices,componenttypes,
    wmodes,symfreqvar)
println(outputwave)

# output
ComplexF64[-10.606601717798213 + 0.0im;;]
source
JosephsonCircuits.calcinputoutput_inner! Method
julia
calcinputoutput_inner!(inputwave, outputwave, phin, bnm, inputportindices,
    outputportindices, inputportimpedances, outputportimpedances,
    nodeindices, componenttypes, wmodes, symfreqvar, nosource)

Calculate the input and output power waves as defined in (except in units of sqrt(photons/second) instead of sqrt(power) K. Kurokawa, "Power Waves and the Scattering Matrix", IEEE Trans. Micr. Theory and Tech. 13, 194–202 (1965) doi: 10.1109/TMTT.1965.1125964 inputwave[(i-1)_Nmodes+j,k] = 1/2_kval * (portvoltage + portimpedance * portcurrent) we can simplify the above to: inputwave[(i-1)_Nmodes+j,k] = 1/2_kval * portimpedance * sourcecurrent outputwave[(i-1)_Nmodes+j,k] = 1/2_kval * (portvoltage - conj(portimpedance) * portcurrent) .

source
JosephsonCircuits.calcinputoutputnoise! Method
julia
calcinputoutputnoise!(inputwave, outputwave, phin, bnm,
    inputportindices, outputportindices, inputportimpedances,
    outputportimpedances, nodeindices, componenttypes, wmodes, symfreqvar)

The input and output waves at the ports when the linearized system is driven at the noise channels rather than at the ports: calcinputoutput! with nosource = true, so that no source current is attributed to a port when forming its output wave. (With the source included, a port sharing a branch with a lossy capacitor would be credited with that channel's source current.)

Examples

julia
inputwave = JosephsonCircuits.LinearAlgebra.Diagonal(ComplexF64[0])
noiseoutputwave = ComplexF64[0;;]
phin = ComplexF64[-2.5000000000007394e-10 - 0.000795774715459398im; 1.983790476804266e-20 + 3.141592641138603e-16im;;]
bnm = ComplexF64[1.0 + 0.0im; 0.0 + 0.0im;;]
portimpedanceindices = [2]
noiseportimpedanceindices = [6]
portimpedances = [50]
noiseportimpedances = [1]
nodeindices = [2 2 2 3 3 3; 1 1 3 1 1 1]
componenttypes = [:P, :R, :C, :Lj, :C, :R]
wmodes = [2*pi*5e9]
symfreqvar = nothing
JosephsonCircuits.calcinputoutputnoise!(inputwave,noiseoutputwave,
    phin,bnm,portimpedanceindices,noiseportimpedanceindices,
    portimpedances,noiseportimpedances,nodeindices,
    componenttypes,wmodes,symfreqvar)
println(noiseoutputwave)

# output
ComplexF64[-5.568327974762547e-11 + 3.516177070001411e-15im;;]
source
JosephsonCircuits.calcinvLn Method
julia
calcinvLn(Lb::SparseVector, Rbn::SparseMatrixCSC, Nmodes)

Returns the nodal inverse inductance matrix. Accepts the vector of branch inductances Lb and the incidence matrix Rbn.

Examples

julia
Nmodes = 1
Lb = JosephsonCircuits.SparseArrays.sparsevec([1,2],[1e-9,4e-9])
Rbn = JosephsonCircuits.SparseArrays.sparse([1,2], [1,2], [1,1])
JosephsonCircuits.calcinvLn(Lb,Rbn,Nmodes)

# output
2×2 SparseArrays.SparseMatrixCSC{Float64, Int64} with 2 stored entries:
 1.0e9 
     2.5e8
julia
Nmodes = 1
Lb = JosephsonCircuits.SparseArrays.sparsevec([],Nothing[])
Rbn = JosephsonCircuits.SparseArrays.sparse([1,2], [1,2], [1,1])
JosephsonCircuits.calcinvLn(Lb,Rbn,Nmodes).nzval

# output
Nothing[]
source
JosephsonCircuits.calcjunctionrelations Method
julia
calcjunctionrelations(componenttypes::Vector{Symbol},
    nodeindices::Matrix{Int}, junctioncprs::AbstractDict,
    edge2indexdict::Dict, Ljb::SparseVector)

The JunctionRelations of the junctions of a circuit, ordered by the nonzero entries of the branch inductance vector Ljb, which is the order every solver indexes its junction axis by. Returns nothing when every junction is the sinusoidal Josephson one, which is the case the solvers evaluate as plain sin and cos.

junctioncprs is keyed by the flat component index, as it is on a CompiledCircuit; a junction is placed by the branch its two nodes make, the same way calcbranchvector places its value.

source
JosephsonCircuits.calcmodefreqs Method
julia
calcmodefreqs(w::NTuple{N},modes::Vector{NTuple{N,Int}})

Calculate the frequencies of the modes given a tuple of fundamental frequencies and a vector of tuples containing the mixing products and harmonics.

Examples

julia
julia> JosephsonCircuits.calcmodefreqs((1., 1.1),[(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1)])
6-element Vector{Float64}:
 0.0
 1.0
 2.0
 1.1
 2.1
 3.1
source
JosephsonCircuits.calcnodefluxsensitivity Method
julia
calcnodefluxsensitivity(op::HBOperatingPoint, dFr::AbstractMatrix;
    factorization = KLUfactorization())

Solve dx/dr = -inv(J)*(dF/dr) for the residual sensitivities dFr of calcresidualsensitivity, with one factorization of sensitivityjacobian at the operating point: the canonical Jacobian when a direct current block is active, the harmonic one otherwise. Returns a matrix whose columns are dx/dr for each component, in the complex representation of the augmented state.

source
JosephsonCircuits.calcnodematrix Method
julia
calcnodematrix(componenttypes::Vector{Symbol}, nodeindices::Matrix{Int},
    componentvalues::Vector, valuecomponenttypes::Vector, Nmodes, Nnodes,
    component::Symbol, invert::Bool)

Returns either the capacitance or conductance matrix depending on the values of component and invert. :C and false for capacitance and :R and true for conductance. The dimensions of the output are (Nnodes-1) times Nmodes by (Nnodes-1) times Nmodes. Note that nodeindices is "one indexed" so 1 is the ground node.

source
JosephsonCircuits.calcnodes Method
julia
calcnodes(nodeindex::Int, mutualinductorindex::Int,
    componenttypes::Vector{Symbol}, nodeindexarray::Matrix,
    componentnamedict::Dict, mutualinductorbranchnames::Vector{String})

Calculate the two nodes (or mutual inductor indices) given the index in the typvector and the component type. For component types where order matters, such as mutual inductors, the nodes are not sorted. For other component types where order does not matter, the nodes are sorted.

Examples

julia
circuit = Circuit(
    [:p1 => Port(1; Z0 = :Rleft),
     :i1 => CurrentSource(:Ipump),
     :l1 => Inductor(:L1),
     :l2 => Inductor(:L2),
     :k1 => MutualInductor(:K1, :l1, :l2),
     :k2 => MutualInductor(:K2, :l1, :l2),
     :c2 => Capacitor(:C2),
     :c3 => Capacitor(:C3),
     :gnd => Ground()],
    [[(:p1, 1), (:i1, 1), (:l1, 1)],
     [(:l2, 1), (:c2, 1), (:c3, 1)],
     [(:p1, 2), (:i1, 2), (:l1, 2), (:l2, 2), (:c2, 2), (:c3, 2),
      (:gnd, 1)]])
psc = JosephsonCircuits.compile(circuit)
println(JosephsonCircuits.calcnodes(1,1,psc.componenttypes,psc.nodeindices, psc.componentnamedict,psc.mutualinductorbranchnames))
println(JosephsonCircuits.calcnodes(5,1,psc.componenttypes,psc.nodeindices, psc.componentnamedict,psc.mutualinductorbranchnames))

# output
(1, 2)
(1, 3)
source
JosephsonCircuits.calcnodesorting Method
julia
calcnodesorting(uniquenodevector::Vector{String};sorting=:number)

The permutation which sorts the node names in uniquenodevector according to sorting, with the ground node "0" moved to the front in every case. Throws an ArgumentError if there is no ground node.

Keywords

  • sorting = :number: parse the names as integers and sort numerically. Throws an ArgumentError if a name is not an integer.

  • sorting = :name: sort the names as strings, so that "101" sorts before "11".

  • sorting = :none: keep the names in order of first appearance, apart from moving ground to the front.

Examples

julia
julia> JosephsonCircuits.calcnodesorting(["30","11","0","2"];sorting=:name)
4-element Vector{Int64}:
 3
 2
 4
 1

julia> JosephsonCircuits.calcnodesorting(["30","11","0","2"];sorting=:number)
4-element Vector{Int64}:
 3
 4
 2
 1

julia> JosephsonCircuits.calcnodesorting(["30","11","0","2"];sorting=:none)
4-element Vector{Int64}:
 3
 1
 2
 4
source
JosephsonCircuits.calcnoisecovariance! Function
julia
calcnoisecovariance!(Cnoise, Snoise, occupation = nothing)

The added noise covariance at the output ports,

julia
Cnoise[i,i'] = sum_c occupation[c] Snoise[c,i] conj(Snoise[c,i'])

which is the Y of the Gaussian channel whose X is the scattering matrix: the map takes an input covariance to X sigma X' + Y. Snoise describes the transformation and occupation the state of each channel, so this is where the two meet and where a temperature shows up.

In the normalization of the rest of these outputs a vacuum channel counts as one, so at zero temperature the diagonal is sum(abs2, Snoise[:,i]), which is exactly the noise term in the denominator of calcqe!.

source
JosephsonCircuits.calcoperatingpointstamps Method
julia
calcoperatingpointstamps(op::HBOperatingPoint, lsys, dx)

Calculate the contribution of a shift of the pump operating point to the derivative of the linearized system matrix, for each column of dx. The linearized system matrix depends on the operating point only through the Fourier coefficients of cos(phi_b(t)) of the Josephson junction branch fluxes, so the contribution is the directional derivative of those coefficients along the operating point shift (cosdirectionalderivative!) scattered into the system matrix through the same plan which assembles it (addjosephsonterm!), so the mode coupling and its truncation agree exactly. Returns a vector of nonzero value vectors aligned with the sparsity structure of the system matrix, which are frequency independent.

source
JosephsonCircuits.calcphiindices Method
julia
calcphiindices(frequencies::Frequencies{N},
    conjsymdict::Dict{CartesianIndex{N},CartesianIndex{N}})

Return the indices which map the elements of the frequency domain vector to the corresponding elements of the frequency domain array. Also return the indices conjsourceindices whose data should be copied from the vector to conjtargetindices in the array then complex conjugated.

Arguments

  • Nt: tuple with dimensions of signal in time domain

  • dropdict: dictionary of elements of frequency domain signal to drop where the key is the Cartesian index and the value is the value.

Returns

  • indexmap: the indices which map the elements of the frequency domain vector elements to the corresponding elements of the frequency domain array

  • conjsourceindices: data should be copied from here

  • conjtargetindices: data should be copied to here and conjugated

Examples

julia
freq = JosephsonCircuits.Frequencies{2}((4, 3), (5, 7), (8, 7), CartesianIndex{2}[CartesianIndex(2, 1), CartesianIndex(4, 1), CartesianIndex(1, 2), CartesianIndex(3, 2), CartesianIndex(2, 3), CartesianIndex(1, 4), CartesianIndex(2, 6), CartesianIndex(3, 7)], [(1, 0), (3, 0), (0, 1), (2, 1), (1, 2), (0, 3), (1, -2), (2, -1)])
conjsymdict = Dict{CartesianIndex{2}, CartesianIndex{2}}(CartesianIndex(5, 4) => CartesianIndex(5, 5), CartesianIndex(1, 3) => CartesianIndex(1, 6), CartesianIndex(5, 2) => CartesianIndex(5, 7), CartesianIndex(1, 4) => CartesianIndex(1, 5), CartesianIndex(1, 2) => CartesianIndex(1, 7), CartesianIndex(5, 3) => CartesianIndex(5, 6))
JosephsonCircuits.calcphiindices(freq, conjsymdict)

# output
([2, 4, 6, 8, 12, 16, 27, 33], [6, 16], [31, 21])
julia
freq = JosephsonCircuits.calcfreqsrdft((4,3));
truncfreq = JosephsonCircuits.truncfreqs(freq;dc=false,odd=true,even=false,maxintermodorder=3)
noconjtruncfreq = JosephsonCircuits.removeconjfreqs(truncfreq)
conjsymdict = JosephsonCircuits.conjsym(noconjtruncfreq)
JosephsonCircuits.calcphiindices(noconjtruncfreq,conjsymdict)

# output
([2, 4, 6, 8, 12, 16, 27, 33], [6, 16], [31, 21])
source
JosephsonCircuits.calcportvoltage Method
julia
calcportvoltage(key1, key2, phin, wmodes, Nmodes, j, k)

The port voltage of mode j for the drive column k of the node flux solution phin, at the port between the node indices key1 and key2 (with 1 meaning ground): the node flux difference times im*wmodes[j], with the sign of the canonical orientation of the port branch when one node is ground.

source
JosephsonCircuits.calcqe! Function
julia
calcqe(S::AbstractMatrix, noise = nothing)
calcqe!(qe, S, noise = nothing; denom = similar(qe, size(S, 1)),
    comp = similar(denom))

Calculate the quantum efficiency matrix for a scattering matrix S in the field ladder operator basis: abs2(S[i,j]) over the total power at output i, sum(abs2, S[i,:]), plus, with the NoiseReduction noise of the noise scattering matrix of the dissipative elements, the occupied noise power noise.denom at that output. denom and comp are the scratch of the row sums, one entry per row. calcqe! overwrites qe.

Examples

julia
julia> JosephsonCircuits.calcqe([3/5 4/5;4/5 3/5])
2×2 Matrix{Float64}:
 0.36  0.64
 0.64  0.36

julia> JosephsonCircuits.calcqe(Complex{Float64}[3/5 4/5;4/5 3/5])
2×2 Matrix{Float64}:
 0.36  0.64
 0.64  0.36

julia> qe=Float64[1 2;3 4];JosephsonCircuits.calcqe!(qe,[1 2;3 4],JosephsonCircuits.noisereduction([1 4;2 5;3 6],[1]));qe
2×2 Matrix{Float64}:
 0.0526316  0.210526
 0.0882353  0.156863
source
JosephsonCircuits.calcqe_S_Cnoise! Method
julia
calcqe_S_Cnoise!(qe, S, Cnoise)

Calculate the quantum efficiency matrix from the scattering parameter matrix and the noise wave covariance matrix, both in the field ladder operator (sqrt photon number) basis. Overwrites qe with output.

source
JosephsonCircuits.calcqe_S_Cnoise Method
julia
calcqe_S_Cnoise(S::AbstractArray, Cnoise::AbstractArray)

Calculate the noise wave covariance matrix from the scattering parameter matrix and the noise covariance matrix, both in the field ladder operator (sqrt photon number) basis.

Examples

julia
julia> S = JosephsonCircuits.ABCDtoS(JosephsonCircuits.ABCD_attenuator_T(50,10));isapprox(JosephsonCircuits.calcqe_S_Cnoise(S,JosephsonCircuits.calcCnoise(S)),[0 0.1;0.1 0])
true

julia> S = JosephsonCircuits.ABCDtoS(JosephsonCircuits.ABCD_attenuator_T(50,10).+0im);isapprox(JosephsonCircuits.calcqe_S_Cnoise(S,JosephsonCircuits.calcCnoise(S)),[0 0.1;0.1 0])
true
source
JosephsonCircuits.calcqeideal! Method
julia
calcqeideal!(qeideal,S)

See calcqeideal.

source
JosephsonCircuits.calcqeideal Method
julia
calcqeideal(S::AbstractArray)

Calculate the ideal (best possible) quantum efficiency for each element of a scattering matrix. See also calcqeideal!.

Examples

julia
julia> JosephsonCircuits.calcqeideal([3/5 4/5;4/5 3/5])
2×2 Matrix{Float64}:
 1.0  1.0
 1.0  1.0

julia> JosephsonCircuits.calcqeideal(Complex{Float64}[3/5 4/5;4/5 3/5])
2×2 Matrix{Float64}:
 1.0  1.0
 1.0  1.0
source
JosephsonCircuits.calcresidualsensitivity Function
julia
calcresidualsensitivity(op::HBOperatingPoint, psc, cg, nm,
    sensitivityindices, alphas = ones(Complex{Float64}, length(sensitivityindices)))

Calculate the derivative of the harmonic balance residual with respect to a relative (logarithmic) perturbation of each component value, at the operating point. alphas scales the direction of each column: the derivative of column k is with respect to alphas[k]*r applied to component sensitivityindices[k], which is how a design parameter's direction alpha = (dv/dp)/v is folded into the residual derivative of a component (see designsensitivities). Combined with the implicit function theorem applied to F(x, r) = 0 in the equivalent real representation,

julia
dx/dr = -inv(J)*(dF/dr),

with J the exact real Jacobian retained by hbnlsolve, this gives the derivative of the operating point itself (see calcnodefluxsensitivity). Returns a sparse matrix whose columns are dF/dr for each component, in the real representation of the augmented residual: each component touches only its own rows (its nodes and modes, a promoted resistor's constitutive rows, or a junction branch's Kirchhoff rows), so the storage scales with the touched entries rather than with Nstate*Ncomponents.

The residual is affine in C, 1/R and 1/L, so those parameter derivatives are that component's own contribution to the linear term applied to the converged state, with a sign, built from the shared classification of componentstamp with the same nondimensionalization and negative frequency conjugation the solver applies. The Josephson junction term is the residual's own sine contribution restricted to that junction.

Note that the auxiliary branch currents of the modified nodal analysis formulation are scaled by the solver scale (see calcsolverscale), which itself depends on the port impedances, so for a port resistor the auxiliary rows of the returned derivative differ from a finite difference of a re-solve by that change of normalization. The node flux rows, which are the physical quantity and the only rows the linearized system depends on, are unaffected.

source
JosephsonCircuits.calcscatteringmatrix! Method
julia
calcscatteringmatrix!(S, inputwave, outputwave)

The scattering matrix is defined as outputwave = S * inputwave.

Examples

julia
julia> inputwave=[1.0 0.0;0.0 1.0];outputwave=[im/sqrt(2) 1/sqrt(2);1/sqrt(2) im/sqrt(2)];S = zeros(Complex{Float64},2,2);JosephsonCircuits.calcscatteringmatrix!(S,inputwave,outputwave);S
2×2 Matrix{ComplexF64}:
      0.0+0.707107im  0.707107+0.0im
 0.707107+0.0im            0.0+0.707107im

julia> inputwave = rand(Complex{Float64},2,2);outputwave = rand(Complex{Float64},2,2);S=zeros(Complex{Float64},2,2);JosephsonCircuits.calcscatteringmatrix!(S,inputwave,outputwave);isapprox(S*inputwave,outputwave)
true
source
JosephsonCircuits.calcscatteringmatrix! Method
julia
calcscatteringmatrix!(S, inputwave::Diagonal, outputwave)

The scattering matrix is defined as outputwave = S * inputwave.

Examples

julia
julia> inputwave=JosephsonCircuits.LinearAlgebra.Diagonal([1.0,1.0]);outputwave=[im/sqrt(2) 1/sqrt(2);1/sqrt(2) im/sqrt(2)];S = zeros(Complex{Float64},2,2);JosephsonCircuits.calcscatteringmatrix!(S,inputwave,outputwave);S
2×2 Matrix{ComplexF64}:
      0.0+0.707107im  0.707107+0.0im
 0.707107+0.0im            0.0+0.707107im
source
JosephsonCircuits.calcscatteringmatrix! Method
julia
calcscatteringmatrix!(S, inputwave::Vector, outputwave::Vector)

The scattering matrix is defined as outputwave = S * inputwave.

Examples

julia
julia> inputwave=[1.0,0.0];outputwave=[im/sqrt(2), 1/sqrt(2)];S = zeros(Complex{Float64},2,2);JosephsonCircuits.calcscatteringmatrix!(S,inputwave,outputwave);S
2×2 Matrix{ComplexF64}:
      0.0+0.707107im  0.0+0.0im
 0.707107+0.0im       0.0+0.0im
source
JosephsonCircuits.calcsensitivityscaling! Method
julia
calcsensitivityscaling!(gamma, beta, inputwave, bnm,
    portindices, portimpedances, componenttypes, nodeindices,
    wmodes, Nmodes)

Calculate the scalars which convert the derivative of the node fluxes into the derivative of the scattering parameters. Writing the output wave of calcinputoutput! as a linear functional of the node fluxes, the part which depends on them is (1/2)*kval*(1 + conj(Z)/Z)*im*w_n*(phi_n1 - phi_n2), and the scattering parameters divide by the input wave, so

julia
dS[(j,n),(i,m)] = gamma[(j,n)]*beta[(i,m)]
                  *(dphi[node1,(j,n)] - dphi[node2,(j,n)])

with gamma = (1/2)*kval*(1 + conj(Z)/Z)*im*w_n/s_{(j,n)} and beta = 1/inputwave[(i,m),(i,m)]. The node flux difference is contracted with the adjoint solution by calcSsensitivity!, which is why the im*w_n factor of the port voltage is folded into gamma here: it is exactly the factor relating the adjoint source vector to the source vector of the forward problem.

s_{(j,n)} is the source current of the port's own unit drive (calcsourcecurrent on the diagonal), ±1 depending on whether the canonical orientation of the port branch in the incidence matrix agrees with the node order of the port component. The adjoint solution is the solve against the source columns of bnm, which carry the canonical branch orientation, while the output functional differences the node fluxes in the component node order, so their ratio enters the contraction. Without it the sensitivities of any output at a port written with its nodes in the opposite order of the branch orientation would have the wrong sign, even though the scattering parameters themselves, which use s consistently in both the input and the output waves, would be correct.

source
JosephsonCircuits.calcsensitivitystamps Method
julia
calcsensitivitystamps(sensitivityindices, psc, cg, nm, lsys, phimatrix,
    coupledbranches, Nnodalmna, Nmodes, Nnodes)

Build the SensitivityStamp of each component in sensitivityindices. The classification and the raw one-component matrices come from componentstamp, which is shared with the residual derivatives of calcresidualsensitivity, so the two grids cannot disagree on which components are supported or how they are built. The Josephson junction stamp is the pump modulated contribution of that junction alone, obtained by scattering the Fourier coefficients of cos(phi(t)) of that junction through the same plan (addjosephsonterm!) which assembles the system matrix, so the mode coupling and its truncation agree exactly.

source
JosephsonCircuits.calcsolverscale Method
julia
calcsolverscale(w, componenttypes::Vector{Symbol}, vvn::Vector,
    portimpedances::Vector, Lscale)

Calculate the inductance scale used to nondimensionalize the nonlinear harmonic balance system: the Kirchhoff current law rows are multiplied by this scale (divided by the reduced flux quantum), the Josephson terms enter as ratios of this scale to the junction inductances, and the auxiliary variables of the modified nodal analysis formulation are branch currents in units of the corresponding natural current scale. The scale is

Lscale = Z0/w0

with Z0 the geometric mean of the constant real port reference impedances (falling back to the geometric mean of all constant real resistors and then to 50 ohms when none are present) and w0 the geometric mean of the absolute values of the nonzero drive frequencies. With this choice the natural current unit is phi0*w0/Z0, the entries of the scaled system are dimensionless and of order one for circuits driven near their characteristic impedance and frequency, the auxiliary branch currents have magnitudes comparable to the node fluxes (in particular in circuits without inductors, where the previous mean-inductance scale degenerated to one henry and produced auxiliary values of order 1e9), and the residual tolerance atol becomes independent of the unit system of the problem. Because the scale multiplies rows only, and the auxiliary variables are internal, the returned node fluxes and all physical quantities are unchanged in exact arithmetic.

When every drive frequency is zero the mean inductance Lscale is returned instead, since no frequency scale is available.

source
JosephsonCircuits.calcsourcecurrent Method
julia
calcsourcecurrent(key1, key2, bnm, Nmodes, j, k)

The source current of mode j for the drive column k of the source terms bnm, at the port between the node indices key1 and key2 (with 1 meaning ground): the difference of the two nodes' currents, halved, or the one node's current with the sign of the canonical orientation of the port branch when the other is ground.

source
JosephsonCircuits.calcsources Method
julia
calcsources(modes, sources, portindices, portnumbers, nodeindices,
    edge2indexdict, Lscale, Nnodes, Nbranches, Nmodes)

The source vector in the branch basis: for each source, the current at its port and mode scaled by Lscale/phi0, at the index of that port's branch and mode; zero elsewhere. See also addsources!.

Examples

julia
modes = [(0,), (1,)]
sources = [(mode = (0,), port = 1, current = 0.0005), (mode = (1,), port = 1, current = 1.0e-10)]
portindices = [1]
portnumbers = [1]
nodeindices = [2 2 2 2 0 2 3 4 3 3; 1 1 1 1 0 3 4 1 1 1]
edge2indexdict = Dict((1, 2) => 1, (3, 1) => 2, (1, 3) => 2, (4, 1) => 3, (2, 1) => 1, (1, 4) => 3, (3, 4) => 4, (4, 3) => 4)
Lscale = 1.005e-9 + 0.0im
Nnodes = 4
Nbranches = 4
Nmodes = 2
JosephsonCircuits.calcsources(modes, sources, portindices, portnumbers,
    nodeindices, edge2indexdict, Lscale, Nnodes, Nbranches, Nmodes)

# output
8-element Vector{ComplexF64}:
     1526.863796602709 + 0.0im
 0.0003053727593205418 + 0.0im
                   0.0 + 0.0im
                   0.0 + 0.0im
                   0.0 + 0.0im
                   0.0 + 0.0im
                   0.0 + 0.0im
                   0.0 + 0.0im
source
JosephsonCircuits.calcspicesortperms Method
julia
calcspicesortperms(variabledict::Dict{String,Vector{String}})

Calculate the sortperms which will sort the variable and node names. Numbered names sort numerically before the names without a number, which keep their order, so a rawfile may mix nodes named with numbers and with words.

source
JosephsonCircuits.calcstaticfluxcomponents Method
julia
calcstaticfluxcomponents(componenttypes::Vector{Symbol},
    nodeindices::Matrix{Int}, vvn::Vector, Nnodes::Int)

Return the connected components of the static flux-stiffness graph which do not contain the ground node, as a vector of vectors of "one indexed" node indices (so 1 is the ground node and does not appear in the output). The graph has the circuit nodes as vertices and an edge for every linear inductor and every Josephson junction whose value provides static (zero frequency) flux stiffness: finite numeric values contribute an edge, while a non-finite numeric value does not. Symbolic values are assumed to provide finite, nonzero static stiffness; a symbolic element whose zero-frequency stiffness vanishes or diverges will break this function. Resistors and capacitors contribute no edges because they provide no static flux stiffness in the node flux basis. Mutual inductances also contribute no edges because they couple branch fluxes without providing a galvanic connection. With the coupled branches represented by auxiliary branch current variables (see calcAmnaind), a singular coupling matrix (a perfectly coupled pair, |k| = 1) does not add flux null directions: the constitutive equations constrain the branch fluxes rather than freeing them, so this graph classification of the flux gauge freedom remains sound. Any degeneracies which exist at perfect coupling live in the branch current space (a branch current combination which the surrounding circuit leaves physically undetermined) and produce a singular system caught at factorization. Mutual coupling between inductors sharing a single branch is rejected up front (see mnacoupledbranches).

The DC flux of each returned "floating" component is defined only up to a common shift (a gauge degree of freedom). The modified nodal analysis formulation adds one gauge fixing equation per floating component and zero-frequency mode, see calcdcgaugeindices. A net direct current injected into a floating component is carried by the explicit average voltage block when the component has a conductive path to somewhere that can absorb it; only a component with no such path has no solution, which dcpinning refuses (see harmonics/directcurrent.jl).

Examples

julia
julia> JosephsonCircuits.calcstaticfluxcomponents([:P,:R,:C,:Lj,:C],[2 2 2 3 4;1 1 3 4 1],[1,50.0,1e-13,1e-9,1e-12],4)
2-element Vector{Vector{Int64}}:
 [2]
 [3, 4]

julia> JosephsonCircuits.calcstaticfluxcomponents([:P,:R,:L],[2 2 2;1 1 1],[1,50.0,1e-9],2)
Vector{Int64}[]

julia> JosephsonCircuits.calcstaticfluxcomponents([:P,:R,:L],[2 2 2;1 1 1],[1,50.0,Inf],2)
1-element Vector{Vector{Int64}}:
 [2]
source
JosephsonCircuits.calcvaluetype Method
julia
calcvaluetype(componenttypes::Vector{Symbol},componentvalues::Vector,
    components::Vector{Symbol};checkinverse::Bool=true)

Returns a zero length vector with the (computer science) type which will hold a set of circuit components of the (electrical engineering) types given in components. This function is not type stable by design, but exists to make the later function calls type stable.

Arguments

  • componenttypes::Vector{Symbol}: the component (electrical engineering) types.

  • componentvalues::Vector: the component values.

  • components::Vector{Symbol}: find a (computer science) type which will hold the component (electrical engineering) types in this vector.

Keywords

  • checkinverse = true: also check the inverse of each element. This is useful if the type would be integer but we later want to take the inverse and want an array with a type that supports this operation.

Examples

julia
julia> JosephsonCircuits.calcvaluetype([:R,:C,:R],[1,2,3],[:R])
Float64[]

julia> JosephsonCircuits.calcvaluetype([:R,:C,:R],[1,2,3+0.0im],[:R])
Float64[]

julia> JosephsonCircuits.calcvaluetype([:R,:C,:R],[1,2,3+1.0im],[:R])
ComplexF64[]
source
JosephsonCircuits.candeviceevaluate Method
julia
candeviceevaluate(ssys)

Whether every block of a stamp system has data a kernel can evaluate, which is tabulated or constant. A callable provider is an arbitrary Julia function and stays on the host.

source
JosephsonCircuits.candidatecount Method
julia
candidatecount(pc)

The number of candidate directions a FloquetPreconditioner holds in its bank: at least deflationsize, and more when a candidate was left out of the last build or a harvest has added candidates the next build has not yet seen.

source
JosephsonCircuits.canonicaldim Method
julia
canonicaldim(L::CompositeLayout)

The length of the canonical state.

source
JosephsonCircuits.canonicalfj Method
julia
canonicalfj(fjreal!, work::CanonicalWork, Jint, plan)

Wrap an internal coordinate residual and Jacobian closure for a direct solve method: the residual in canonical coordinates, and the canonical Jacobian filled through plan.

The matrix is filled rather than replaced, because the solver factorizes the one it was handed. Its pattern is fixed – the internal pattern under a permutation plus the direct current block, none of which moves between iterations – and the plan is built from it once.

source
JosephsonCircuits.canonicaljacobian! Method
julia
canonicaljacobian!(plan::CanonicalJacobianPlan, Jint::SparseMatrixCSC)

Fill the plan's matrix from an internal Jacobian and return it.

The flux block is Jint as it is, since the internal state is the first block of the canonical one. What is added is the explicit direct current block and its couplings, in the same places the residual adds them: the resistor current the average voltages drive into the zero frequency nodal rows, the transport rows and the block currents they carry across a component boundary, and each block's own zero frequency row in place of the i = 0 the stamp wrote. A reference row is a replacement rather than an addition, which is why the internal entries landing in it are dropped when the plan is built rather than zeroed here.

The matrix-free product is the reference this is checked against: for every unit vector the two must agree exactly, which is a sharper test than any finite difference of the residual would be.

source
JosephsonCircuits.canonicaljacobian Method
julia
canonicaljacobian(Jint::SparseMatrixCSC, work::CanonicalWork)

The Jacobian in canonical coordinates, assembled from the internal one.

This builds a plan and applies it, which is what a caller wanting one matrix at one point should do. A solve builds the plan once instead; see canonicaljacobianplan.

source
JosephsonCircuits.canonicaljacobianplan Method
julia
canonicaljacobianplan(Jint::SparseMatrixCSC, work::CanonicalWork)

Build the CanonicalJacobianPlan for an internal Jacobian pattern.

Only the pattern of Jint is read, not its values, so the plan is valid for every point the solve visits. It stops being valid if that pattern moves, which it must not.

source
JosephsonCircuits.canonicaljvp Method
julia
canonicaljvp(jvpreal!, work::CanonicalWork)

Wrap an internal coordinate Jacobian vector product so it takes and returns canonical vectors.

source
JosephsonCircuits.canonicalresidual Method
julia
canonicalresidual(fjreal!, work::CanonicalWork)

Wrap an internal coordinate residual and Jacobian closure so it takes and returns canonical vectors.

source
JosephsonCircuits.cansweepondevice Method
julia
cansweepondevice(lsys::HBLinearizedSystem)

Whether the linearized system's per-frequency assembly can be reduced to the constant coefficients of a FrequencySweepPlan.

It cannot when a component value depends on the symbolic frequency variable: then the stored values themselves change with the frequency and there is no constant quadratic to precompute.

source
JosephsonCircuits.cascadeS! Method
julia
cascadeS!(S, Sa, Sb)

See cascadeS for description.

source
JosephsonCircuits.cascadeS Method
julia
cascadeS(Sa, Sb)

Cascade the scattering parameter matrix Sa with the scattering matrix Sb and return the combined scattering matrix.

Examples

julia
julia> Sa = [0.0 0.5;0.5 0.0];Sb = [0.0 0.1;0.1 0.0];JosephsonCircuits.cascadeS(Sa,Sb)
2×2 Matrix{Float64}:
 0.0   0.05
 0.05  0.0

julia> Sa=rand(Complex{Float64},2,2);Sb=rand(Complex{Float64},2,2);isapprox(JosephsonCircuits.cascadeS(Sa,Sb),JosephsonCircuits.AtoS(JosephsonCircuits.StoA(Sa)*JosephsonCircuits.StoA(Sb)))
true

julia> Sa=[rand(Complex{Float64},2,2) for i in 1:10];Sb=[rand(Complex{Float64},2,2) for i in 1:10];isapprox(JosephsonCircuits.cascadeS.(Sa,Sb),JosephsonCircuits.AtoS.(JosephsonCircuits.StoA.(Sa).*JosephsonCircuits.StoA.(Sb)))
true

References

D. J. R. Stock and L. J. Kaplan, "A Comment on the Scattering Matrix of Cascaded 2n-Ports (Correspondence)," in IRE Transactions on Microwave Theory and Techniques, vol. 9, no. 5, pp. 454-454, September 1961, doi: 10.1109/TMTT.1961.1125369 .

source
JosephsonCircuits.checkblocknoisemodels Method
julia
checkblocknoisemodels(ssys::Union{Nothing,ScatteringStampSystem}, w,
    wpumpmodes)

Check the stated noise of the blocks of ssys at every frequency the sweep will solve at, every signal frequency at every pump mode, and throw if one is not met there: a block which states its noise with a NoiseCovariance must state at least what the commutation relations require (see quantumnoisemargin), to the atol of the model. A pumped block is checked by checkpumpedblockmodels.

Stored data is checked when a block is constructed, but a callable cannot be, and a fitted block differs from its data. These are exactly the frequencies the channels are formed at, so nothing the sweep will use goes unchecked, and the check is done here rather than in the sweep so that a refusal reaches the caller before any solve, as a plain error rather than the failure of a task.

source
JosephsonCircuits.checkcachekwargs Method
julia
checkcachekwargs(kwargs)

Validate the solver keywords an hbcache stores for every solve. x0 and reuse are the cache's own to manage and are refused, as is keyedarrays = true, since the state is kept as plain vectors (false is accepted); so is method = Staged(), which the compiled circuit solve does not take; and so is any keyword that solve does not accept, which would otherwise fail at the first hbsolve! with a method error.

source
JosephsonCircuits.checkcomponenttypes Method
julia
checkcomponenttypes(allowedcomponents::Vector{String})

Check that parsecomponenttype maps each prefix in allowedcomponents back to its own index, and throw an ArgumentError otherwise. This fails when a two letter prefix is listed after a one letter prefix with the same first letter, which would shadow it.

Examples

julia
julia> JosephsonCircuits.checkcomponenttypes(["Lj","L","C","K","I","R","P"])
true
source
JosephsonCircuits.checkcomponentvaluesdefined Method
julia
checkcomponentvaluesdefined(componentnames::Vector, vvn::Vector,
    symfreqvar)

Check that every circuit component value is numeric, or symbolic only through the symbolic frequency variable symfreqvar. A value which is symbolic in any other variable indicates a variable which was not assigned a numerical value in the circuit definitions dictionary circuitdefs, and an informative ArgumentError is thrown naming the components and the undefined variables. Values which depend only on symfreqvar describe frequency dependent components and are resolved per frequency by freqsubst, so they are accepted; a value which mixes symfreqvar with undefined variables is still rejected. Called by hbnlsolve and hblinsolve before any computation, so a forgotten entry in circuitdefs fails immediately with the actual cause instead of a downstream error about the symbolic frequency variable.

Examples

julia
julia> JosephsonCircuits.@params w;JosephsonCircuits.checkcomponentvaluesdefined(["P1","R1"], Any[1, 1/(w*50.0)], w)

julia> R2, w = JosephsonCircuits.@params R2 w;try JosephsonCircuits.checkcomponentvaluesdefined(["P1","R1"], Any[1, R2], w) catch e; occursin("R1 has the value", sprint(showerror, e)) end
true
source
JosephsonCircuits.checkcoupledbranchinductors Method
julia
checkcoupledbranchinductors(componentnames::Vector,
    componenttypes::Vector{Symbol}, nodeindices::Matrix,
    edge2indexdict::Dict, Mb::SparseMatrixCSC)

Check that no branch which participates in mutual inductive coupling hosts more than one inductor. Inductors which share a branch (the same pair of nodes) are combined into a single branch inductance by reciprocal sum before the mutual coupling is applied - exact for uncoupled parallel inductors, which share the same branch flux, but a misrepresentation as soon as any inductor on the branch is mutually coupled: the correct effective mutual coupling of the merged branch differs from the stamped one (for an uncoupled L2 sharing a branch with a coupled L1, by the current division factor L2/(L1+L2)). An informative ArgumentError naming the inductors is thrown, directing the user to route the inductors through intermediate nodes so each mutually coupled inductor occupies its own branch. Called by numericmatrices so both solvers and direct users of the circuit matrices are protected; see also mnacoupledbranches, which rejects coupling between two inductors on the same branch (a diagonal mutual inductance entry).

source
JosephsonCircuits.checkissymbolic Method
julia
checkissymbolic(a)

Check if a is a symbolic variable. Define a function to do this because the test depends on which representation the value came from: the core answers for CircuitValue and FrequencyDependent, and the Symbolics extension adds the methods for its own wrappers.

Examples

julia
julia> JosephsonCircuits.@params w;JosephsonCircuits.checkissymbolic(w)
true

julia> JosephsonCircuits.checkissymbolic(1.0)
false
source
JosephsonCircuits.checkjunctiondc Function
julia
checkjunctiondc(sintd::AbstractArray, junctionbranches, branchnames;
    atol = 1e-2)

Warn about a Josephson junction carrying nearly its critical current at zero frequency.

The static flux partition treats a junction of finite inductance as a short at zero frequency, which puts its two terminals in one component and is what lets the transport rows be the component sum of the nodal equations. That is true of a junction in the zero voltage state and false of one which is running, and the difference is whether the junction can carry the direct current asked of it: the branch current is Ic*sin(phi), so its zero frequency part is Ic times the time average of sin(phi), and no zero voltage state exists once that average would have to exceed Ic.

A junction whose current-phase relation is a PolynomialCPR is skipped: the bound below is the one of the sinusoidal relation, and what a polynomial does past the range it was fitted on is the user's to judge.

The solver cannot report the failure itself. sin is bounded, so the average it finds is always a fraction of one, and a circuit which has no periodic solution converges to the nearest thing which is one rather than announcing that it does not exist. What can be reported is the approach: a junction whose direct current is within a percent of its critical current is at the edge of the partition's assumption, and a result there should be checked against a run at a lower drive.

This is a heuristic about the operating point and not a proof of dynamic stability, which harmonic balance does not decide.

source
JosephsonCircuits.checklosslessblocks Method
julia
checklosslessblocks(ssys::Union{Nothing,ScatteringStampSystem}, w,
    wpumpmodes; atol = 1e-6, nsamples = 32)

Check the blocks of ssys which declare Lossless against the frequencies the sweep will solve at, and throw if one of them dissipates there.

A block whose data is stored is held to the declaration when it is constructed. A callable cannot be, which is what the declaration is for, so this is the one check available: evaluate it at up to nsamples of the signal frequencies, at every pump mode, and see. Sampling can show that a block dissipates and can never show that it does not, so this catches a declaration which is wrong at a frequency it looked at and makes no promise about the rest. It is bounded rather than exhaustive because an exhaustive pass would cost a share of what the declaration saves.

source
JosephsonCircuits.checknoform Method
julia
checknoform(form::Symbol, what::AbstractString)

Reject a form for a provider which is not a callable. How a function is called means nothing for data which is already stored.

source
JosephsonCircuits.checkpumpconjugates Method
julia
checkpumpconjugates(blocks::Vector{StampedScatteringBlock}, wmodes)

Refuse a pumped block of blocks which converts, with an entry above its tolerance, the conjugate of one retained mode of a pump solve into another, the two frequencies of wmodes summing to a harmonic of its pump: the pump solve's linear term is complex linear in the retained modes and does not carry a term in their conjugates, so with a source the operating point would be wrong. Called for every solve with a source, whether its operator is new or reused.

source
JosephsonCircuits.checkpumpedblock Method
julia
checkpumpedblock(block::LinearizedScattering, wmodes, K, name, at)
checkpumpedblock(block::LinearizedScattering, rows, cols, K, name, at)

Check the noise model of a pumped block over the signed mode frequencies wmodes coupled by the harmonics K, or over the output modes rows fed by the input modes cols (see pumpednoisematrices): a declared Lossless requires J - S J S' to vanish there, to the block's atol, and a stated NoiseCovariance requires V - K and V + K to be positive semidefinite, to the block's atol or the covariance's, whichever is larger, relative to the square of the largest entry of S, and a covariance must have finite, Hermitian entries, to the same tolerance of its own largest entry. Throws otherwise, naming the block name and the frequency at.

The covariance a completed noise model states is held to its entries like any other, since the completion repairs a covariance and does not stand in for one: what it adds is the negative part of a Hermitian matrix, which is not defined for data that is neither. It is held to them over the whole domain the completion reads, the modes of each ladder padded by the noise model's multiples of the pump frequency (see paddedladder), and not over the modes of the solve alone, since that is the matrix the negative part is taken of; the completion then reads data this has passed. Only the positive semidefiniteness a completed model establishes is left unchecked, so such a block reads its stated covariance alone and never assembles the scattering matrix it would be completed against.

source
JosephsonCircuits.checkpumpedblockmodels Method
julia
checkpumpedblockmodels(ssys::Union{Nothing,ScatteringStampSystem}, w,
    wpumpmodes)

Check what every pumped block of ssys declares, its losslessness or its stated covariance, over the modes of the solve at each signal frequency (see checkpumpedblock), and throw where it is not met. The sweep's modes are the one place the multi-mode matrices of a pumped block are known, and the family its noise is completed over. Runs at every solve, whether or not a noise output is asked for, since a lossless pumped block emits nothing only if it is lossless: a block is accepted or refused on its declaration and not on the outputs. A block whose covariance is completed has what it states checked for finite, Hermitian entries and the relations it meets by construction left alone.

source
JosephsonCircuits.checkpumpedblocks Method
julia
checkpumpedblocks(p::TransientProblem, frequencies)

Check the noise model of every pumped block of p over the family of the bath frequencies in Hz, the signed frequencies as its outputs with every input which feeds them (see bathfamily), a declared Lossless or a stated NoiseCovariance (see checkpumpedblock), and throw where one is not met: the pair terms of the noise are read from this family. A fitted block, whose covariance is completed to the commutation relations of its filters, meets them by construction and has what it states checked for finite, Hermitian entries; a block built from filters by hand is checked as its data.

source
JosephsonCircuits.checkstaticstiffnessvalues Method
julia
checkstaticstiffnessvalues(componenttypes::Vector{Symbol}, vvn::Vector)

Check that every linear inductor and Josephson junction has a finite, nonzero numeric value (or a symbolic value), and throw an ArgumentError otherwise. Symbolic values are accepted under the documented assumption that their zero-frequency stiffness is finite and nonzero (the analysis will fail otherwise), see calcstaticfluxcomponents.

Examples

julia
julia> JosephsonCircuits.checkstaticstiffnessvalues([:P,:R,:L],[1,50.0,1e-9])
source
JosephsonCircuits.circuitmatrixplan Method
julia
circuitmatrixplan(c::CompiledCircuit, cg::CircuitGraph, b::BoundCircuit;
    Nmodes = 1)

Build the CircuitMatrixPlan of a compiled circuit, given its bound values b.

The conductance plan covers the resistors and the port owned environments together, because at this stage an environment is realized as an ordinary resistor; when ports become direct boundary stamps it gains its own plan.

source
JosephsonCircuits.circuitnodegraph Method
julia
circuitnodegraph(pairptr, pairrow, invLnm::SparseMatrixCSC,
    Gnm::SparseMatrixCSC, Cnm::SparseMatrixCSC, Nmodes::Integer,
    nnodes::Integer)

The adjacency lists of the circuit-node graph: two nodes are adjacent when a junction pair table entry or a stored entry of the linear term matrices couples them. This is the graph the block factorization eliminates.

source
JosephsonCircuits.circuitorder Method
julia
circuitorder(sys, Rbnm::SparseMatrixCSC, Nmodes::Integer,
    Nbranches::Integer, layout::ModeLayout)

The circuit-node graph of the system and KLU's elimination order of it, the two symbolic ingredients a block factorization and its memory prediction share.

source
JosephsonCircuits.circuitvariables Method
julia
circuitvariables(a)

The free parameters of a component value. Returns an empty collection for a numeric value and the CircuitValues.Parameters of a CircuitValue (not Symbols). The Symbolics extension adds a method for Num.

source
JosephsonCircuits.clusterblocks Method
julia
clusterblocks(::Type{T}, modes, adj, order, Nmodes::Integer,
    layout::ModeLayout, backend; target = BLOCKTARGETROWS)

The symbolic block structure of one cluster: the supernodes of the amalgamated elimination tree of the circuit-node graph adj under the node order, restricted to the real-layout slots of modes; the panels from a symbolic elimination on the node graph; and the index maps of the Schur updates. Storage is allocated on backend in precision T.

source
JosephsonCircuits.clustersolve! Method
julia
clustersolve!(x::AbstractVector, C::ClusterBlocks, r::AbstractVector,
    backend)

Overwrite the cluster's slots of x with the solution of the cluster's factorized operator against the cluster's slots of r; the other slots of x are untouched. The gather by the elimination order, the substitutions of substitute! and the scatter back, a batch of one.

source
JosephsonCircuits.clustersymbolic Method
julia
clustersymbolic(modes, adj, order, Nmodes::Integer, layout::ModeLayout;
    target = BLOCKTARGETROWS)

The symbolic block structure of one cluster, on the host and without allocating any factor storage: the supernodes of the amalgamated elimination tree of the circuit-node graph adj under the node order, restricted to the real-layout slots of modes, the positions of every supernode, its panel rows after fill, and the offsets the Schur updates scatter through. clusterblocks allocates from it and blockfactorbytes sizes it.

source
JosephsonCircuits.columnindices Method
julia
columnindices(A::DeviceValuedSparseMatrix)

The compressed sparse row column indices of A, which are the row indices of the transpose it stores.

source
JosephsonCircuits.compare Method
julia
compare(x,y)

Compare two values for the tests: isequal, except that floating point arrays are compared with a tolerance (comparearray), the solver result structures are compared field by field (comparestruct), and the solver diagnostics are ignored.

source
JosephsonCircuits.comparearray Method
julia
comparearray(x::AbstractArray{T},y::AbstractArray{T}) where T

Whether two arrays have the same size and differ by at most 1e-6 in the 2-norm.

Examples

julia
julia> JosephsonCircuits.comparearray([1,2],[1,2,3])
false

julia> JosephsonCircuits.comparearray([1,2],[1,2,])
true
source
JosephsonCircuits.comparestruct Method
julia
comparestruct(x,y)

Compare two structures of the same type field by field with compare, which compares floating point arrays with a tolerance and ignores the solver diagnostics.

Examples

julia
julia> JosephsonCircuits.comparestruct(JosephsonCircuits.NoiseReduction([1.0], [2.0]),JosephsonCircuits.NoiseReduction([1.0], [2.0]))
true

julia> JosephsonCircuits.comparestruct(JosephsonCircuits.warmup(),JosephsonCircuits.warmup())
true

julia> JosephsonCircuits.comparestruct(nothing,nothing)
true

julia> JosephsonCircuits.compare(nothing,nothing)
true

julia> cg = JosephsonCircuits.CircuitGraph(Dict((1, 2) => 1, (3, 1) => 2, (1, 3) => 2, (2, 1) => 1), JosephsonCircuits.SparseArrays.sparse([1, 2], [1, 2], [1, 1], 2, 2), [(1, 2), (1, 3)], Tuple{Int64, Int64}[], [(1, 2), (1, 3)], Vector{Int64}[], Int64[], JosephsonCircuits.Graphs.SimpleGraphs.SimpleGraph{Int64}(2, [[2, 3], [1], [1]]), 2);JosephsonCircuits.compare(cg,cg)
true
source
JosephsonCircuits.compile Method
julia
compile(elab::ElaboratedCircuit; sorting = :name)
compile(circuit::Circuit; sorting = :name)
compile(netlist::AbstractVector; sorting = :name)
compile(c::CompiledCircuit; sorting = :name)

Lower a circuit to a CompiledCircuit. A Circuit is elaborated first, and a legacy tuple netlist is converted to a Circuit first; a CompiledCircuit is returned unchanged.

Components appear in the table in elaboration order, with a matched port's own termination emitted as a resistor entry directly after the port. Nodes are numbered by calcnodesorting with ground first; the default sorting = :name sorts the net names as strings, since hierarchical net names are not integers (the tuple netlist entry points of the solvers default to :number instead).

Only components the solvers support can be lowered: a GaussianChannel, a VoltageSource, a non-sinusoidal NonlinearInductor, or any component with other than two terminals throws a ComponentNotSupportedError naming the instance. A circuit with no connection to Ground throws an ArgumentError.

source
JosephsonCircuits.completecovariance Method
julia
completecovariance(V, K)

The covariance V completed to the commutation relations of the commutator K: V + neg(V - K) + neg(V + K) with neg the negative part, which makes V - K and V + K positive semidefinite, so that the channels formed from them exist (see NoiseCovariance); each addition is positive semidefinite and vanishes where V already meets the relations. For V = 0 it is |K|, the least total noise a Gaussian channel with the map of K can add for its output to obey the commutation relations, the least in the trace, which is the Ymin of the quantum optics functions in the basis of the modes; for a stated V the addition is sufficient and not in general the least. The negative part of a matrix is not that of its parts, so a pumped block is completed over a padded ladder (see completedcovariance).

source
JosephsonCircuits.completedcovariance Method
julia
completedcovariance(block::LinearizedScattering, rows, cols)

The covariance of a pumped block whose noise model is completed, over the output modes rows fed by the input modes cols of a solve: the covariance the block states, completed to the commutation relations (see completecovariance) over the ladder of the rows padded by the noise model's padding multiples of the pump frequency on either side, with every input which feeds it, and restricted to the rows, so that the block's noise is one model whatever modes a solve keeps, to the precision of the padding; plus the vacuum of the inputs which feed the rows and are not among cols, S_c S_c' for the scattering S_c from them, which a solve without those modes traces out, so that the covariance meets the commutator of the rows over the inputs the solve has.

Every row a solve asks for is completed, including one the block's data does not reach, which scatters nothing and so absorbs everything and carries the vacuum its commutator requires, as the stamp of the block takes it. The block couples nothing between frequencies which are not a multiple of the pump apart, so the rows are completed one ladder at a time (see pumpladders), the negative part of a matrix of independent blocks being the negative part of each; a block which does not convert couples nothing along a ladder either and needs no padding around a row.

source
JosephsonCircuits.completepositivitymargin Method
julia
completepositivitymargin(X::AbstractMatrix, Y::AbstractMatrix)

Return the minimum eigenvalue of Y + (i/2)(Ω - X Ω X'), which is nonnegative for a completely positive Gaussian channel in the real quadrature representation with vacuum covariance I/2.

source
JosephsonCircuits.complex_to_real! Method
julia
complex_to_real!(xr, xc, isreal) -> xr

Complex -> real. The imaginary part of a real mode is never read.

source
JosephsonCircuits.complex_to_real Method
julia
complex_to_real(A, rowlayout, collayout, ::Type{Tj}=Ti) -> SparseMatrixCSC{T,Tj}

Real form of x -> A*x under the row layout of its output and the column layout of its input, so that complex_to_real(A, rl, cl) * complex_to_real(x, cl.isreal) == complex_to_real(A*x, rl.isreal). Tj selects the index type of the result; Int32 halves rowval and is worth using whenever the dimensions fit. Runs one O(nnz) pass to size the output, then one to fill it.

source
JosephsonCircuits.complexdim Method
julia
complexdim(rdim, isreal) -> Int

Inverse of realdim.

source
JosephsonCircuits.complexlinearcontributionkernel! Method
julia
complexlinearcontributionkernel!(lin, colptr, rowval, ...)

The constant frequency dependent contribution to each stored entry of the complex Jacobian: invLnm + im*Gnm*wmodesm - Cnm*wmodes2m.

The real path's counterpart splits each complex value across a real block; here the stored entry is the complex value itself, so the three are simply summed, in the order assemblecomplexjacobian! adds them.

source
JosephsonCircuits.complextorealkernel! Method
julia
complextorealkernel!(xr, xc, lptr, lwide)

Contract the complex representation of a node vector into the equivalent real one, one work item per complex entry. The imaginary part of a self conjugate mode is never read. The one or two real slots each work item writes are disjoint from every other's, so this is conflict free. The inverse of realtocomplexkernel!. See NonlinearTermPlan.

source
JosephsonCircuits.componentdictionaries Method
julia
componentdictionaries(componenttypes::Vector{Symbol},
    nodeindexarray::Matrix{Int}, componentnamedict::Dict,
    mutualinductorbranchnames::Vector)
source
JosephsonCircuits.componentlookups Method
julia
componentlookups(coupledbranches, Ljb)

Constant time lookups for componentstamp, built once per stamp table rather than searched per component: the set of mutually coupled branches and the ordinal of a junction branch within Ljb.nzind. Without these the classification repeats linear searches per component, which becomes quadratic over a large sensitivity set.

source
JosephsonCircuits.componentnports Method
julia
componentnports(c)

The number of ports of a multiport component: the ports of a ScatteringParameters, the modes of a GaussianChannel. Part of the connector protocol with nterminals and hasports.

source
JosephsonCircuits.componentstamp Method
julia
componentstamp(idx::Integer, psc::CompiledCircuit, cg::CircuitGraph,
    nm::CircuitMatrices, lookups, Nmodes::Integer, Nnodes::Integer)

Classify the component at index idx for sensitivity analysis and build its raw one-component matrix, without any solver scaling, negative frequency conjugation, or padding, which the callers apply for their own grids. The component matrices are built with the same functions which build the system matrices, calcCn, calcGn, calcLb and calcinvLn, applied to the single component, so the node and mode conventions agree by construction. Returns one of

  • (:C, M): the component's capacitance matrix,

  • (:G, M): the component's conductance matrix,

  • (:Lj, j): the ordinal j of a Josephson junction within the junction branch vector nm.Ljb,

  • (:invL, M): the component's inverse inductance matrix.

This is the single definition of which components are supported: :C, :L, :R and :Lj with numeric values. Mutually coupled inductors and components with symbolic (frequency dependent) values throw, with the same message from both the fixed operating point stamps (calcsensitivitystamps) and the residual derivatives (calcresidualsensitivity). lookups are the constant time tables of componentlookups.

source
JosephsonCircuits.componentvalues Method
julia
componentvalues(cache::HBCache, p::NamedTuple)

The component values of cache.builder at p, in the parsed sorted order, without re-parsing. The builder output must have the same component names as the parse and fully numeric values.

source
JosephsonCircuits.componentvaluestonumber Method
julia
componentvaluestonumber(componentvalues::Vector,circuitdefs::Dict)

Resolve each component value in componentvalues with valuetonumber and return the results as a Vector{Any}: the table mixes port numbers, real and complex values, symbolic values and frequency dependent providers, and the groups the assembly reads are typed when they are gathered from it (see grouptype), so the table itself has one type for every circuit.

Examples

julia
julia> JosephsonCircuits.componentvaluestonumber([:Lj1,:Lj2],Dict(:Lj1=>1e-12,:Lj2=>2e-12))
2-element Vector{Any}:
 1.0e-12
 2.0e-12

julia> JosephsonCircuits.@params Lj1 Lj2;JosephsonCircuits.componentvaluestonumber([Lj1,Lj1+Lj2],Dict(Lj1=>1e-12,Lj2=>2e-12))
2-element Vector{Any}:
 1.0e-12
 3.0e-12
source
JosephsonCircuits.compositelayout Method
julia
compositelayout(ml::ModeLayout, modes::AbstractVector{<:Tuple}; kwargs...)

Build the canonical layout from the mode index tuples, taking the zero frequency mode to be the one whose indices are all zero.

source
JosephsonCircuits.compositelayout Method
julia
compositelayout(ml::ModeLayout, isdc::AbstractVector{Bool};
    nvdc = 0)

Build the canonical layout for a state whose internal layout is ml, where isdc[t] marks mode t as the zero frequency one.

A zero frequency mode is self conjugate, so it occupies one internal entry rather than two; isdc must therefore imply ml.isreal. The converse does not hold, since a Nyquist mode is self conjugate without being direct current, which is why the split is made on isdc and not on ml.isreal.

source
JosephsonCircuits.conjnegfreq! Method
julia
conjnegfreq!(A, wmodes)

Take the complex conjugate of any element of A which would be negative when multipled from the right by a diagonal matrix consisting of wmodes replicated along the diagonal. Overwrite A with the output.

Each axis of A should be an integer multiple of the length of wmodes.

Examples

julia
julia> A = JosephsonCircuits.SparseArrays.sparse([1,2,1,2], [1,1,2,2], [1+1im,1+1im,1+1im,1+1im],2,2);JosephsonCircuits.conjnegfreq!(A,[-1,1]);A
2×2 SparseArrays.SparseMatrixCSC{Complex{Int64}, Int64} with 4 stored entries:
 1-1im  1+1im
 1-1im  1+1im
source
JosephsonCircuits.conjnegfreq Method
julia
conjnegfreq(A, wmodes)

Take the complex conjugate of any element of A which would be negative when multipled from the right by a diagonal matrix consisting of wmodes replicated along the diagonal.

Each axis of A should be an integer multiple of the length of wmodes.

Examples

julia
julia> A = JosephsonCircuits.SparseArrays.sparse([1,2,1,2], [1,1,2,2], [1+1im,1+1im,1+1im,1+1im],2,2);JosephsonCircuits.conjnegfreq(A,[-1,1])
2×2 SparseArrays.SparseMatrixCSC{Complex{Int64}, Int64} with 4 stored entries:
 1-1im  1+1im
 1-1im  1+1im

julia> A = JosephsonCircuits.SparseArrays.sparse([1,2,1,2], [1,1,2,2], [1im,1im,1im,1im],2,2);all(A*JosephsonCircuits.LinearAlgebra.Diagonal([-1,1]) .== JosephsonCircuits.conjnegfreq(A,[-1,1]))
true
source
JosephsonCircuits.conjsym Method
julia
conjsym(Nw::NTuple{N, Int}, Nt::NTuple{N, Int})

Calculate the conjugate symmetries in the multi-dimensional frequency domain data.

source
JosephsonCircuits.conjugateladder Method
julia
conjugateladder(block::LinearizedScattering)

Check the stated harmonic covariances of a pumped block against the conjugate ladder and throw where they disagree. The noise of a real wave has the covariance between the conjugates of two modes equal to the conjugate of the covariance between the modes, so the harmonic covariances obey

julia
V_k(-nu - k wp) = transpose(V_k(nu)),

which is how the noise at a frequency a covariance holds no data at is read from the data at its image (see NoiseCovariance). Where a table holds both a knot and its image the two state the same noise and must agree, to the block's atol or the covariance's, whichever is larger, of the largest entry of the table; a constant covariance is its own image and so is symmetric, a Hermitian one real. A callable is what it is at each frequency and is not checked.

source
JosephsonCircuits.conjugatemultiplicity Method
julia
conjugatemultiplicity(fd, td)

The number of harmonics of the real time domain signal each stored bin of the frequency domain array represents: one when the bin's conjugate partner is also stored, two otherwise.

The real transform truncates only the first dimension, so the partner of a bin is stored exactly when its first index is the zero or the Nyquist frequency. This is the factor which distinguishes the adjoint of applyifft! from applyfft!, and getting it wrong gives a vjp which is correct on self-conjugate modes and wrong by a factor of two on every other one.

source
JosephsonCircuits.connectS! Method
julia
connectS!(g::Graphs.SimpleGraphs.SimpleDiGraph{Int},
    fconnectionlist::AbstractVector{<:AbstractVector{Tuple{T,T,Int,Int}}},
    fweightlist::AbstractVector{<:AbstractVector{Int}},
    ports::AbstractVector{<:AbstractVector{Tuple{T,Int}}},
    scattering_parameters::AbstractVector{N},
    noise_covariances::AbstractVector{N}; noise::Bool = false,
    nbatches::Int = Base.Threads.nthreads()) where {T,N}

Return the non-empty elements of the updated scattering_parameters, noise_covariances and ports after applying all of the connections in the connection forward adjacency list fconnectionlist to the graph g, the forward adjacency weight list fweightlist, the vector of ports ports, and the vectors of scattering parameter and noise covariance matrices. The noise covariances are propagated only when noise = true.

Examples

julia
networks = [("S1",[0.0 1.0;1.0 0.0]),("S2",[0.5 0.5;0.5 0.5])];
connections = [[("S1",1),("S2",2)]];
init = JosephsonCircuits.connectS_initialize(networks, connections);
JosephsonCircuits.connectS!(init...)

# output
(S = [[0.5 0.5; 0.5 0.5]], ports = [[("S1", 2), ("S2", 1)]])
source
JosephsonCircuits.connectS Method
julia
connectS(networks, connections; small_splitters::Bool = true,
    noise::Bool = false, Nmodes::Integer = 1,
    nbatches::Int = Base.Threads.nthreads())

Return the network and ports resulting from connecting the networks in networks according to the connections in connections. networks is a vector of tuples of the network name and scattering parameter matrix such as [("network1name",rand(Complex{Float64},2,2), ("network2name",rand(Complex{Float64},2,2)]. connections is a vector of vectors of tuples of networks names and ports such as [[("network1name",1), ("network2name",2)]] where network1 and network2 are the two networks being connected and 1 and 2 are integers describing the ports to connect.

This function supports connections between more than two ports by automatically adding splitters. With noise = true the noise covariance matrices are connected as well, the passive covariance I - S S' being used for a network given without one; with Nmodes > 1 the scattering matrices are multi-mode and connections names physical ports, each expanded to its Nmodes modes (see add_modes).

Examples

julia
networks = [("S1",[0.0 1.0;1.0 0.0]),("S2",[0.5 0.5;0.5 0.5])];
connections = [[("S1",1),("S2",2)]];
JosephsonCircuits.connectS(networks,connections)

# output
(S = [[0.5 0.5; 0.5 0.5]], ports = [[("S1", 2), ("S2", 1)]])
julia
networks = [("S1",[0.0 1.0;1.0 0.0]),("S2",[0.5 0.5;0.5 0.5],[("S3",5),("S3",6)])];
connections = [("S1","S3",1,6)];
JosephsonCircuits.connectS(networks,connections)

# output
(S = [[0.5 0.5; 0.5 0.5]], ports = [[("S1", 2), ("S3", 5)]])
source
JosephsonCircuits.connectS_initialize Method
julia
connectS_initialize(networks::AbstractVector, connections::AbstractVector;
    small_splitters::Bool = true, noise::Bool = false, Nmodes::Integer = 1)

Return the directed graph of connections between the networks and the arrays connectS! works on: the forward adjacency lists, the ports, and the scattering parameter and noise covariance matrices of every network, with splitters added where more than two ports meet. With noise = true the noise covariance I - S S' of each passive network is computed from its scattering parameters unless one was supplied; with Nmodes > 1 each physical port of connections is expanded into its Nmodes mode ports (see add_modes).

Examples

julia
networks = [("S1",[0.0 1.0;1.0 0.0]),("S2",[0.5 0.5;0.5 0.5])];
connections = [[("S1",1),("S2",2)]];
JosephsonCircuits.connectS_initialize(networks,connections)

# output
(Graphs.SimpleGraphs.SimpleDiGraph{Int64}(2, [[2], Int64[]], [Int64[], [1]]), [[("S1", "S2", 1, 2)], Tuple{String, String, Int64, Int64}[]], [[1], Int64[]], [[("S1", 1), ("S1", 2)], [("S2", 1), ("S2", 2)]], [[0.0 1.0; 1.0 0.0], [0.5 0.5; 0.5 0.5]], [[0.0 0.0; 0.0 0.0], [0.0 0.0; 0.0 0.0]])
source
JosephsonCircuits.connectS_initialize Method
julia
connectS_initialize(networks::AbstractVector{Tuple{T,N,Vector{Tuple{T, Int}}}},
    connections::AbstractVector{Tuple{T,T,Int,Int}}) where {T,N}

Return a directed graph of connections between the networks.

Examples

julia
networks = [("S1", [0.0 1.0; 1.0 0.0], [("S1", 1), ("S1", 2)]), ("S2", [0.5 0.5; 0.5 0.5], [("S2", 1), ("S2", 2)])];
connections = [("S1","S2",1,2)];
JosephsonCircuits.connectS_initialize(networks,connections)

# output
(Graphs.SimpleGraphs.SimpleDiGraph{Int64}(2, [[2], Int64[]], [Int64[], [1]]), [[("S1", "S2", 1, 2)], Tuple{String, String, Int64, Int64}[]], [[1], Int64[]], [[("S1", 1), ("S1", 2)], [("S2", 1), ("S2", 2)]], [[0.0 1.0; 1.0 0.0], [0.5 0.5; 0.5 0.5]], [[0.0 0.0; 0.0 0.0], [0.0 0.0; 0.0 0.0]])
source
JosephsonCircuits.convertcopy Method
julia
convertcopy(kernel!, x, a)

The two port chain conversions in place on one copy of x: the kernel kernel!(y_i, a_i) converts the matrix at every frequency index of the copy, with the port argument given at that frequency by atfrequency; a matrix x is converted directly.

source
JosephsonCircuits.convertperfrequency! Method
julia
convertperfrequency!(kernel!, y, x, args...)
convertperfrequency(kernel!, x, args...)

Convert the matrix x[:, :, i] into y[:, :, i] at every frequency index i of the trailing dimensions of x by the kernel kernel!(y_i, x_i, tmp, args_i...), with tmp a scratch matrix and each port argument given at that frequency by atfrequency. The allocating form converts into an array like x, and for a matrix x, one frequency, calls the kernel directly. One method per number of port arguments, none, one or two, rather than a variadic one: the argument map a variadic driver needs is compiled once per kernel and argument type, and that outweighed what it saved. The type parameter makes the method specialize on the kernel, which Julia does not do on its own for a function argument.

source
JosephsonCircuits.correctionstrengths Method
julia
correctionstrengths(pc::FloquetPreconditioner)

The correction strength eta = norm(x - inv(P)*J*x)/norm(x) of each active direction at the last rebuild. eta near zero means the base preconditioner already handles that channel, eta of order one that a substantial part of it is missing from the base. Diagnostic only.

source
JosephsonCircuits.cosdirectionalderivative! Method
julia
cosdirectionalderivative!(dcos::Array, sys::HBSystem, v::AbstractVector)

Evaluate the directional derivative, along v, of the Fourier coefficients of cos(phi_b(t)) of the Josephson junction branch fluxes at the point set with setpoint!, in place. Those coefficients parameterize the pump modulation of the linearized harmonic balance system (see HBLinearizedSystem), so this is what propagates a shift of the pump operating point into the linearized system matrix. The derivative has the coefficients of -sin.(A*x).*(A*v), computed on the same time grid and with the same normalization as the residual, so no separate transform convention is introduced. Shares the cached time domain sine with hessianvectorproduct!, of which this is the first half.

dcos is a host array, and so therefore is sys: the only caller is the sensitivity contraction, and an HBOperatingPoint holds a host system whichever backend solved for it.

source
JosephsonCircuits.cosphibandwidths Function
julia
cosphibandwidths(sys::HBSystem, Amatrixindices::Matrix,
    Amatrixmodes::AbstractMatrix, Nfreq::Integer = 0,
    Nbranches::Integer = 0; tol = 1e-2, budget = 0.25)

The per-tone harmonic bandwidth of the Josephson coupling at the current point, as the tuple of the largest offset in each tone which carries a coefficient of cos(phi(t)) above tol relative to the largest.

This is the bandwidth modebandmask should be given, measured rather than guessed, and it costs nothing beyond the Fourier coefficients updatepreconditioner! already computes: the assembly reads phimatrix[abs(ind) + Nfreq*(b-1)] for ind = Amatrixindices[m1,m2], and this reads the same entries and records how far from the diagonal they stay significant.

The measurement is per tone, and that anisotropy is the point. Jacobi-Anger gives the coefficient at a multi-tone offset m as a product over the tones, chat_m ~ prod_k J_{m_k}(delta_k), with delta_k the phase amplitude tone k contributes. Its support is therefore a rectangle whose sides are set by each delta_k separately, not a ball: a strongly pumped tone earns a wide bandwidth and a weak one collapses to zero, because J_n(delta) falls off super geometrically once n exceeds delta. Keeping a ball instead spends fill on offsets in the weak tones which carry nothing, and the difference is large. On a two tone chain with a 5 percent second drive and 74 modes, the measured rectangle (2,0) converges where the ball of any radius does not, at four percent of the full Jacobian's stored entries.

A tone whose grid is short enough that offsets alias will report a large bandwidth. That is not a failure: the aliased coupling is really there, and a bandwidth which saturates that tone's grid costs nothing extra because the grid had no room to be truncated in the first place.

source
JosephsonCircuits.cosphimatrix Method
julia
cosphimatrix(sys::HBSystem)

The Fourier coefficients of cos(phi(t)) at the current point, from which the Jacobians are assembled: transformed once per point into a buffer of the system's own, which no residual or product touches, and returned as is thereafter. Read it, do not write it.

source
JosephsonCircuits.countscatteringports Method
julia
countscatteringports(psc::CompiledCircuit)

The total number of scattering block ports of the circuit, which is the number of auxiliary port current variables per mode.

source
JosephsonCircuits.coupledbranches Method
julia
coupledbranches(componenttypes::Vector{Symbol}, nodeindices::Matrix{Int},
    componentnamedict::Dict, mutualinductorbranchnames::Vector,
    edge2indexdict::Dict, n::Int)

The structural part of the nth mutual coupling: the indices of the two components it names, the branches they lie on, and the nodes each was declared between. Throws if either named component is not an inductor.

mutualorientations and calcMb both go through this, so they resolve the same components and raise the same errors.

source
JosephsonCircuits.coupling_to_even_odd Method
julia
coupling_to_even_odd(couplingdB, Z0)

Return the even and odd mode impedances Zeven and Zodd for a directional coupler made from two coupled transmission lines with coupling in dB couplingdB and system characteristic impedance Z0.

Examples

julia
julia> JosephsonCircuits.coupling_to_even_odd(20.0,50.0)
(Zeven = 55.27707983925667, Zodd = 45.22670168666455)
source
JosephsonCircuits.couplingbytes Method
julia
couplingbytes(plan::PreconditionerPlan, S::AbstractModeCoupling, sys,
    factorization)
couplingbytes(pc::ModeCouplingPreconditioner, S::AbstractModeCoupling,
    factorization = pc.factorization)

The memory the factors of the coupling set S would take, sized from the symbolic structure alone: the block predictor for block factors, KLU's analysis of the host pattern for a sparse factorization. A coupling set carrying its own factorization is sized with that one. This is what lets an escalation be refused before it is built.

source
JosephsonCircuits.couplingmask Method
julia
couplingmask(S::AbstractModeCoupling, Nmodes::Integer, Amatrixmodes)

The Nmodes x Nmodes mask of the mode couplings the set S retains.

source
JosephsonCircuits.cprderivative Method
julia
cprderivative(cpr)

The derivative of a current-phase relation as a callable. sin gives cos and a PolynomialCPR gives its analytic derivative. Any other callable throws an ArgumentError: there is no automatic differentiation or finite difference fallback, so a user defined relation must supply its derivative through the three argument NonlinearInductor constructor.

source
JosephsonCircuits.cscvaluepermutation Method
julia
cscvaluepermutation(A::SparseMatrixCSC)

The permutation p for which nonzeros(A)[p] is the stored-value order of the compressed sparse row form of A.

A device sparse matrix is CSR, and building one from a host SparseMatrixCSC converts the layout, which permutes the stored values. A numeric refactorization which reuses the symbolic analysis must therefore push new values through the same permutation rather than copying nonzeros straight into the device array: the pattern is unchanged, but the order is not.

The permutation depends only on the sparsity pattern, so it is computed once alongside the analysis and reused for every subsequent refactorization.

source
JosephsonCircuits.cubic_trial_step Method
julia
cubic_trial_step(α0, α1, ϕ0, ϕα0, ϕα1, dϕ0dα; c1 = 1e-4,
    safeguard_low = 0.1, safeguard_high = 0.5)

Return a tuple (αfit, ϕfit, measured) with the proposed step αfit, the estimated merit function value ϕfit, and measured a boolean indicating if the function value is based on an evaluation of the merit function (vs an estimate) that minimizes a cubic function fitted to ϕ(α) = f(xₖ + α pₖ) in the range [0, α1]. The fitting process uses the merit function values at α = 0, α = α0, α = α1, and the derivative at the first point dϕ(α)/dα|α = 0. If the full step α = α1 satisfies the α-scaled Armijo sufficient-decrease condition ϕ(α1) <= ϕ(0) + α1 c1 (dϕ(α)/dα|α = 0), then the full step α1 is returned without fitting. By default c1 = 1e-4.

Based on Nocedal and Wright, chapter 3 section 5.

Arguments

-α0: the previous trial step α = α0. -α1: the proposed full trial step α = α1. -ϕ0: the value of the function at α = 0. -ϕα0: ϕ(α0), the value of the merit function at α = α0. -ϕα1: ϕ(α1), the value of the merit function at α = α1. -dϕ0dα: dϕ(α)/dα|α=0, the derivative of the merit function with respect to α at α = 0.

Keywords

  • c1 = 1e-4: the constant in the α-scaled Armijo sufficient-decrease condition which is typically (heuristicaly) set to be 1e-4, ϕ(α) <= ϕ(0) + α c1 (dϕ(α)/dα|α = 0).

  • safeguard_low = 0.1: the smallest value we allow the step to take relative to the full step α1. This protects against large (eg. order of magnitude) reductions in the step size without an additional function evaluation, which would occur outside of this function.

  • safeguard_high = 0.5: the largest value we allow the step to take relative to the full step α1. This forces the linesearch to at least reduce the step size by a factor of two for every backtrack. Note that if the full step α=α1 satisfies the Armijo sufficient-decrease condition, then it is returned without any clamping.

Returns

  • αtrial: the trial step predicted to minimize the merit function based on cubic interpolation.

  • ϕtrial: either the predicted or measured value of the merit function at the trial step above. If measured = false, then the linesearch function needs to evaluate the trial point to verify that Armijo sufficient-decrease condition is satisfied before accepting the step.

  • measured: true if the returned ϕtrial has been measured (only happens when α=ϕα0) and false if it is an estimate value based on a fit.

source
JosephsonCircuits.dcblockdescriptor Method
julia
dcblockdescriptor(sb::StampedScatteringBlock; atol = 1e-10,
    required = true)

Evaluate the zero frequency pencil of a stamped block.

The matrix comes from the block's AbstractDCModel: by default from its own scattering data evaluated at zero, and from the stated model when the block declared one.

Evaluated or stated, S(0) must be real and finite. A complex zero frequency scattering matrix describes a block with no direct current limit, which is refused here rather than resolved by a convention, on the same principle as a complex direct current conductance.

A block which states no model and whose data has no zero frequency value is refused when required, which is the case when direct current is injected and the block would have to carry its share. When none is, the block is open at zero frequency, which is the i = 0 row the stamp already writes, and nothing is returned so the caller leaves that row alone: a block which cannot say what it does at direct current, and is asked to carry none, carries none. Tabulated data which starts above zero is the common case, and a circuit driven at its pump alone is not refused for it.

source
JosephsonCircuits.dcblockrows Method
julia
dcblockrows(blocks, componentof, Nmodes, modeindex, nnodaldc, scale;
    required = true)

Build the DCBlockRows for the stamped blocks of a circuit.

nnodaldc is the point in the zero frequency block where the nodal entries end and the auxiliary ones begin. A block with no zero frequency data is refused when required and left open otherwise; see dcblockdescriptor.

source
JosephsonCircuits.dcconductanceplan Method
julia
dcconductanceplan(floatingcomponents, Gnm, wmodes, Nmodes, Nnodes)

Build the DCConductancePlan, or nothing when there is no zero frequency mode and so no average voltage at all.

Neither an empty conductance nor an empty set of floating components is a reason to build none. A circuit whose only direct current devices are scattering blocks has an empty G0 and still needs the block rows; a circuit whose every node is held at zero by an inductive path to ground has no voltage to solve for and still has block currents to classify, and gating on either left such a block with the artificial i = 0 row the stamp writes and nothing looking at whether that row is right.

Throws an ArgumentError when the zero frequency conductance has a non-finite or non-real entry, which has no direct current meaning.

source
JosephsonCircuits.dccoupling Method
julia
dccoupling(work::CanonicalWork)

H: the zero frequency nodal current each direct current unknown drives, with the unknowns in the order dcsubsystemindices gives.

This is everything outside the direct current subsystem which can see those unknowns. The average voltages reach the rest of the residual only as the resistor current G0 P v added to the zero frequency nodal rows, and a block port current only as the +1 and -1 it contributes at its two terminals. Nothing else in the harmonic residual reads them, so a direction with H N = 0 is invisible to the whole problem and not only to the subsystem, which is the condition a reference has to meet.

The transport rows are the component sums of these same nodal rows, which is why H and the subsystem cannot disagree about a sign: Y = P' (G0 P) and a block current enters its signal component's row with the sign it enters its signal node's row.

source
JosephsonCircuits.dcinjected Method
julia
dcinjected(plan::DCConductancePlan, bnm::AbstractVector, Nmodes)

Whether any direct current is injected into a static flux component.

When none is, every average voltage is zero, and so is every block port current a nonsingular relation determines from them, so the explicit block has nothing to find: the i = 0 rows the scattering stamp writes are then the right answer rather than a simplification, and the block is classified but not carried. Whether the relations are nonsingular in a way the circuit can see is what the classification decides, and it does not depend on this.

The test is an exact zero and not a tolerance. A drive is either declared at the zero frequency mode or it is not: calcsources writes the coefficient of a mode which no source names as exactly zero, so this asks a structural question and gets a structural answer. A small but nonzero direct current is a direct current, and is solved for.

source
JosephsonCircuits.dckeep Method
julia
dckeep(work::CanonicalWork)

The diagonal which is zero on the rows the direct current block replaces rather than adds to, over the whole canonical vector.

Read off the block by probing it, so it cannot disagree with the residual it describes.

source
JosephsonCircuits.dclimit Method
julia
dclimit(sb::StampedScatteringBlock, n, atol)

The zero frequency scattering matrix read from a block's own data, or nothing and the reason the data has none: :range when it is tabulated and does not reach zero, :nonfinite when the value there is unbounded, :complex when it has no real limit.

Read and not decided: what to do about a block with no zero frequency data depends on whether direct current is asked of it, which is the caller's question. See dcblockdescriptor.

source
JosephsonCircuits.dcpinning Method
julia
dcpinning(work::CanonicalWork)

Return the DCPinning a singular direct current subsystem needs, nothing when it is nonsingular, or throw when it has no solution or an undetermined direction the rest of the circuit can see.

The subsystem this reads, dcsubsystem(work), must be the complete unreferenced descriptor: every transport row and every block relation, with no reference chosen, which is why this is called once at CanonicalWork construction, before any reference exists. Choosing one earlier, from the resistors alone, can discard a row a block has made necessary, and no later check can recover it.

source
JosephsonCircuits.dcresidualsensitivity Function
julia
dcresidualsensitivity(dc::DCOperatingPoint, psc, nm, scale,
    sensitivityindices, alphas)

The direct current block's own contribution to the residual sensitivity, in canonical coordinates.

The canonical residual is D G F(S u) + M u + s c, so its derivative with respect to a component value is the harmonic one gathered and masked, plus (dM/dr) u. Only the conductance depends on a lumped component value, and it enters twice: as the transport rows Y = P' G0 P and as the coupling G0 P into the zero frequency nodal rows. A capacitor, an inductor and a junction are open circuits, a short and a short at zero frequency, none of which carries a conductance, so they contribute nothing here – which is correct and is why the harmonic rows alone were right until a resistor carried direct current.

The perturbation is relative by default: G0 is proportional to 1/R, so a relative change in R scales the whole stamp by -1; alphas carries an absolute direction dv/dp instead, of which only the real part reaches the direct current conductance rows.

source
JosephsonCircuits.dcscatteringmatrix Method
julia
dcscatteringmatrix(m::AbstractDCModel, n)

The n by n real zero frequency scattering matrix of a stated model: OpenDC, ShortDC, ThroughDC or ScatteringDC. ScatteringLimit states none and has no method here; it is handled by evaluating the block's own data. Throws for a ThroughDC with n != 2 or a ScatteringDC of the wrong dimension.

source
JosephsonCircuits.dcsolutionfrom Method
julia
dcsolutionfrom(plan::DCConductancePlan, v::AbstractVector)

Package the solved component voltages as a DCConductanceSolution, the one form in which the direct current answer is reported.

source
JosephsonCircuits.dcsourcecurrent Method
julia
dcsourcecurrent(plan::DCConductancePlan, bnm, Nmodes)

The direct current injected into each static flux component, validated.

The zero frequency mode is self conjugate, so its source coefficient is real by construction; an imaginary part there is not a small direct current but a sign that the source assembly or the mode layout is wrong, and taking the real part of it would carry that error silently into the answer. It is refused instead, against a tolerance relative to the largest coefficient of the zero frequency source, so the decision does not depend on the units the circuit is written in.

source
JosephsonCircuits.dcsubsystem Method
julia
dcsubsystem(work::CanonicalWork)

The dense direct current block [v; i] of the canonical Jacobian: the transport rows and the blocks' zero frequency rows, in the order dcsubsystemindices gives.

source
JosephsonCircuits.dcsubsystemindices Method
julia
dcsubsystemindices(work::CanonicalWork)

The canonical positions the direct current subsystem occupies: the explicit voltage block, then every block port's zero frequency current.

source
JosephsonCircuits.dcsubsystemlocal Method
julia
dcsubsystemlocal(work::CanonicalWork)

The same positions, local to the window.

source
JosephsonCircuits.dcsubsystemrhs Method
julia
dcsubsystemrhs(work::CanonicalWork)

The constant side of the direct current subsystem: the injected current on the transport rows, zero on the blocks' own rows.

source
JosephsonCircuits.dcupdate Method
julia
dcupdate(work::CanonicalWork)

Build the DCUpdate by probing addtransportwindow!, so the matrix form and the scalar form agree by construction.

source
JosephsonCircuits.dcvoltagesensitivity Method
julia
dcvoltagesensitivity(op::HBOperatingPoint, dFr::AbstractMatrix;
    factorization = KLUfactorization())

The derivative of the average node voltages with respect to a relative perturbation of each component value, in volts, indexed by node with ground dropped as hbnlsolve reports them.

The same solve as calcnodefluxsensitivity and the other half of its answer: that returns the node fluxes, which are the periodic part, and this returns the average voltages, which are the direct current part and are unknowns of the canonical system rather than of the harmonic one. nothing for a circuit with no direct current block.

source
JosephsonCircuits.defaultgridladder Method
julia
defaultgridladder(Nharmonics::NTuple{N,Int})

The default coarse to fine ladder of retained harmonic caps for stagedhbnlsolve: Nharmonics halved repeatedly in every dimension down to two harmonics, coarsest first and Nharmonics last.

source
JosephsonCircuits.definitiontable Method
julia
definitiontable(circuitdefs)

The component definitions as a Dict{Any,Any}, whatever the key and value types of the dictionary given.

source
JosephsonCircuits.deflationproducts Method
julia
deflationproducts(pc)

The number of Jacobian products a FloquetPreconditioner has taken itself, one per candidate at every build. Together with products in KrylovSolveInfo this is the exact cost of a solve.

source
JosephsonCircuits.deflationrebuilds Method
julia
deflationrebuilds(pc)

How many times the image pair of a FloquetPreconditioner has been built.

source
JosephsonCircuits.deflationsize Method
julia
deflationsize(pc)

The number of directions the active deflation pair of a FloquetPreconditioner spans. Zero for a preconditioner which does not deflate.

source
JosephsonCircuits.derivativeat Method
julia
derivativeat(r::JunctionRelations, phi)

The derivative of the relation of every junction at the branch phases phi, cos.(phi) for the Josephson relation: the differential inductance which every Jacobian and every linearization is built from. The counterpart of relationat, with derivativeinto! as its in place form.

source
JosephsonCircuits.derivativeinto! Method
julia
derivativeinto!(out, r::JunctionRelations, phi)

derivativeat writing into out, which may not alias phi. A circuit whose junctions are all sinusoidal takes the single broadcast of cos it always did.

source
JosephsonCircuits.derivativestampsystems Method
julia
derivativestampsystems(ssys, target::Integer, dblock)

The pair of provider-swapped stamp systems whose value difference is the derivative of the block contribution with respect to a parameter of the block instance at ordinal target (its position among the compiled scattering blocks, which the stamped blocks follow): the first evaluates dblock (the block whose S is dS/dtheta) in place of that instance and zero for every other block, the second zero for all. Everything else – the sparsity, the contribution lists, the auxiliary layout – is shared with ssys by construction. The instance is selected by its ordinal and not by its definition, because two instances may share one definition object and a parameter belongs to one of them.

source
JosephsonCircuits.designblockjacobian Method
julia
designblockjacobian(builder, p::NamedTuple; parameters = keys(p),
    delta = 1e-6)

The scattering block dependence of a circuit builder: for each design parameter and each ScatteringParameters whose definition the builder rebuilds when that parameter is perturbed, a derivative block whose scattering matrix is dS/dp: the block's own analytic derivative when its derivatives named tuple has an entry for the parameter, otherwise central finite differences through the block's provider, evaluated lazily at whatever frequencies the solver requests.

A block is treated as parameter independent when the perturbed builder calls return the identical block object (===): hoist a fixed block – measured Touchstone data, say – out of the builder and it costs nothing, while a block constructed inside the builder is differentiated. Each perturbed parameter is taken as real(p[q]). Returns a vector of (blockpath, parameterindex, derivativeblock).

source
JosephsonCircuits.designjacobian Method
julia
designjacobian(builder, p::NamedTuple; parameters = keys(p),
    delta = 1e-6)

The Jacobian of the component values with respect to the design parameters: builder(; p...) returns a numeric circuit, and the entry (k, j) is d(value of component k)/d(parameter j), by central finite differences with relative step delta.

Returns (names, values, J): the component names in circuit order, their values at p (a scattering block is reported as zero in both the value and its Jacobian row, since its dependence is carried separately by designblockjacobian), and the complex length(names) by length(parameters) Jacobian. Each perturbed parameter is taken as real(p[q]). The builder must keep the circuit topology fixed as the parameters vary; a parameter-dependent component list has no derivative and is reported as an error.

source
JosephsonCircuits.designparse Method
julia
designparse(circuit)

Parse a builder output – a legacy tuple netlist or a typed Circuit – into (names, values) in the solver's sorted component order, so the names returned to the caller are the names the solver uses. A ScatteringParameters block appears once, named by its instance path and carrying its definition as the value; every other value must be numeric.

Analysis ports are not among them. A port occupies a slot in the flat table whose value is the port number, which is a label and not a quantity, so differencing it is meaningless: at best it is an axis which is always zero, and at worst a builder whose port numbering moved with a parameter would report a derivative for it and the sensitivity would try to rescale a stamp which does not exist.

A port's reference impedance is a design quantity, and it appears here under the component which realizes it: the resistor a legacy netlist placed across the port, or the environment the lowering generated for a matched one, named after the port. That component is the one whose value the matrices read, so it is the one a sensitivity has to name.

source
JosephsonCircuits.designsensitivities Method
julia
designsensitivities(builder, p::NamedTuple, ws, wp, sources,
    Nmodulationharmonics, Npumpharmonics; parameters = keys(p),
    delta = 1e-6, circuitdefs = Dict{Any,Any}(), kwargs...)

The derivative of the scattering parameters with respect to the design parameters of a circuit builder, by the chain rule through the component sensitivities:

julia
dS/dp_j = sum_k (dS/dv_k) (dv_k/dp_j).

builder(; p...) must return a fully numeric circuit. The components which depend on the selected parameters are found automatically from the builder Jacobian, so a derived value like L2 = L/2 contributes its factor of one half without being declared. The solve runs once, with the adjoint sensitivities of hbsolve carrying the exact direction dv_k/dp_j of each dependent component into the contraction (sensitivityoperatingpoint = true, so the shift of the pump operating point is included); the builder is evaluated twice per parameter, which is negligible next to the solve.

Carrying the direction, rather than scaling a relative derivative, is what makes the result exact for complex component values: a parameter which rotates a value in the complex plane – a loss tangent, say – has dv/dp not parallel to v, which no single relative derivative can represent. All the components a parameter touches merge into one contraction, so a design variable shared across a long line costs one contraction rather than one per cell.

Returns (out, dSdp): the full hbsolve output, and a keyed array dS/dp with the axes of the scattering sensitivity and a parameter axis in place of the component axis. Additional keyword arguments are forwarded to hbsolve.

Extended help

A gradient based optimizer wants a closure from a parameter vector to a value and a derivative, evaluated at the same point in sequence, so memoize one solve for both. For the gain in dB, G_k = 20*log10(abs(S[out, in, k])), the chain rule is dG/dp = (20/log(10))*real(conj(S)*dSdp)/abs2(S):

julia
mutable struct Objective; lastp; lastr; end
const obj = Objective(nothing, nothing)
function solveat(pvec)
    p = (Lj = pvec[1], Cc = pvec[2])
    if obj.lastp != pvec
        obj.lastr = designsensitivities(make, p, ws, wp, sources, (2,), (8,))
        obj.lastp = copy(pvec)
    end
    return obj.lastr
end
value(pvec) = [20*log10(abs(s))
    for s in solveat(pvec).out.linearized.S((0,),2,(0,),1,:)]
function jacobian(pvec)
    r = solveat(pvec)
    S = r.out.linearized.S((0,),2,(0,),1,:)
    # the parameter axis precedes the frequency axis of dSdp
    d = permutedims(r.dSdp((0,),2,(0,),1,:,:))
    return (20/log(10)).*real.(conj.(S).*d)./abs2.(S)
end
source
JosephsonCircuits.devicecomplexjacobianpattern Method
julia
devicecomplexjacobianpattern(n, Nmodes, adjacency, activem1,
    linearmatrices, backend)

The sparsity structure of the complex Jacobian, from the node adjacency, the mode couplings activem1 which survive the frequency grid, and the structures of the constant linear term linearmatrices, built on backend and returned there as a DeviceSparsePattern.

source
JosephsonCircuits.deviceexpandrealpattern Method
julia
deviceexpandrealpattern(outerptr, outerrowval, outerlayout::ModeLayout,
    innerlayout::ModeLayout, n::Integer, backend)

Expand a complex sparsity structure into the structure of its real representation, where each complex entry becomes a two by two real block, and return it on backend as a DeviceSparsePattern.

The number of real entries a complex index contributes is the same for every one of its real columns, so the column pointer is a gather of per index counts followed by a prefix sum, and the row indices are then one work item per column with nothing to coordinate.

source
JosephsonCircuits.devicenoise Function
julia
devicenoise(plan::DeviceNoisePlan, blockplan, providers,
    adjointsolution, nrhs, wpumpmodes, w, keepmatrix)

A callback which computes the noise scattering parameters of a signal frequency from the adjoint solutions on the backend.

temperatures is one temperature per noise channel, or nothing; the waves of a warm channel are scaled where they are computed, so nothing downstream of this knows about temperature.

blockplan is the DeviceBlockNoisePlan of the dissipative scattering blocks, or nothing when there are none; their channels follow the noise ports of the lumped components in the rows, as they do on the host, and are evaluated through the same DeviceProviders providers the stamps are.

Returned in the form hblinsolve_inner! takes as presolvednoise: called with the frequency index, its input waves and the destination for the noise scattering matrix, it returns the NoiseReduction the quantum efficiency and the commutation relations read.

The adjoint solution never leaves the backend, and neither does the noise scattering matrix unless keepmatrix: on a line with loss spread along it that matrix has a row per noise port mode and is the largest thing in the sweep, while what is read of it is one number per port mode.

Snoise = noiseoutputwave/inputwave is formed as a product with the inverse of the input waves, which is a dense matrix the size of the scattering matrix and so is inverted on the host.

source
JosephsonCircuits.devicesolutions Function
julia
devicesolutions(lsys::HBLinearizedSystem, bnm, w, backend, forward,
    adjoint = nothing; factorization = nothing, refine = true)

The DeviceSweep which computes the solutions of the linearized system on backend a batch of frequencies at a time. factorization is the linearized solve's factorization: a BlockFactorization takes the batched block path below, anything else the cuDSS one. refine asks single precision block factors to refine against the double residual; false is the fully single precision sweep.

The sweep is driven by solvebatch!, which solves the batch of frequencies beginning at an index and stages its solutions on the host; forwardsolution! and adjointsolution! then fill the solution of any frequency of that batch, and adjointdevice hands out the adjoint solution of a frequency where it was computed, for the noise scattering parameters, which are formed there rather than brought back (see devicenoise). The providers field is the DeviceProviders the scattering blocks are evaluated through, or nothing when there are none or they cannot be evaluated on backend; the noise channels of the dissipative blocks are read through the same one.

The split is what keeps the host work parallel. solvebatch! is the only verb which touches the device; once it has returned, its batch's frequencies can be post-processed by as many workers as the host path uses, because reading a solution touches staged host memory and nothing else.

The systems of a batch share one sparsity pattern, so cuDSS analyzes it once and then refactorizes and solves the whole batch together, from the values of one assemblesweep!. With a sparse device factorization the batch size is capped by uniformbatchlimit; with a BlockFactorization the cap does not apply and the batch is sized by blocksystembytes, the factors, the originals when refining, the solutions of both directions and the value matrix of one system, against half the backend's free memory and the length of the sweep.

forward and adjoint each describe what a direction needs, as a named tuple (full, rows). With full the whole solution is copied back, which the node flux, voltage and sensitivity outputs need; otherwise only rows are gathered and returned, which for the scattering parameters is a handful of port rows out of the whole circuit (see portsolutionrows).

With a sparse device factorization the adjoint direction is a second uniform batch over the transposed system: cuDSS 0.8 cannot solve against the transpose of a factorization, so unlike the host, which gets its adjoint solutions from the forward factors with trysolvetranspose!, it pays a second analysis and a second factorization per batch. A BlockFactorization solves both directions from the one factorization, reading the same factors the other way round (blocksolve! with transposed = true), and assembles one batch of values in the stored column order for both.

source
JosephsonCircuits.diagcombine Method
julia
diagcombine(x::Vector{T}) where T<:AbstractArray

Accept a vector of abstract arrays x where each element is a matrix or array of scattering parameters for one mode. Returns a single matrix or array of the multi-mode scattering parameter matrices.

Examples

julia
julia> JosephsonCircuits.diagcombine([[111 121;211 221],[112 122;212 222],[113 123;213 223]])
6×6 Matrix{Int64}:
 111    0    0  121    0    0
   0  112    0    0  122    0
   0    0  113    0    0  123
 211    0    0  221    0    0
   0  212    0    0  222    0
   0    0  213    0    0  223

julia> JosephsonCircuits.diagcombine([[111 121;211 221;;;],[112 122;212 222;;;],[113 123;213 223;;;]])
6×6×1 Array{Int64, 3}:
[:, :, 1] =
 111    0    0  121    0    0
   0  112    0    0  122    0
   0    0  113    0    0  123
 211    0    0  221    0    0
   0  212    0    0  222    0
   0    0  213    0    0  223
source
JosephsonCircuits.diagrepeat! Method
julia
diagrepeat!(out::AbstractVecOrMat, A::AbstractVecOrMat, Nmodes::Integer)

Overwrite out with the elements of A duplicated Nmodes times along the diagonal.

Examples

julia
julia> A = [1 2;3 4];out = zeros(eltype(A),4,4);JosephsonCircuits.diagrepeat!(out,A,2);out
4×4 Matrix{Int64}:
 1  0  2  0
 0  1  0  2
 3  0  4  0
 0  3  0  4
source
JosephsonCircuits.diagrepeat Method
julia
diagrepeat(A::AbstractArray, Nmodes::Integer)

Return a array with each element of the first two axes of A duplicated along the diagonal Nmodes times.

Examples

julia
julia> JosephsonCircuits.diagrepeat([1 2;3 4;;;],2)
4×4×1 Array{Int64, 3}:
[:, :, 1] =
 1  0  2  0
 0  1  0  2
 3  0  4  0
 0  3  0  4
source
JosephsonCircuits.diagrepeat Method
julia
diagrepeat(A::AbstractVecOrMat, Nmodes::Integer)

Return a matrix with each element of A duplicated along the diagonal Nmodes times.

Examples

julia
julia> JosephsonCircuits.diagrepeat([1 2;3 4],2)
4×4 Matrix{Int64}:
 1  0  2  0
 0  1  0  2
 3  0  4  0
 0  3  0  4

julia> JosephsonCircuits.diagrepeat([1,2],2)
4-element Vector{Int64}:
 1
 1
 2
 2
source
JosephsonCircuits.diagrepeat Method
julia
diagrepeat(A::Diagonal, Nmodes::Integer)

Return a diagonal matrix with each element of A duplicated along the diagonal Nmodes times.

Examples

julia
julia> JosephsonCircuits.diagrepeat(JosephsonCircuits.LinearAlgebra.Diagonal([1,2]),2)
4×4 LinearAlgebra.Diagonal{Int64, Vector{Int64}}:
 1
  1
  2
  2
source
JosephsonCircuits.diagrepeat Method
julia
diagrepeat(A::SparseMatrixCSC, Nmodes::Integer)

Return a sparse matrix with each element of A duplicated along the diagonal Nmodes times.

Examples

julia
julia> JosephsonCircuits.diagrepeat(JosephsonCircuits.SparseArrays.sparse([1,1,2,2], [1,2,1,2], [1,2,3,4],2,2),2)
4×4 SparseArrays.SparseMatrixCSC{Int64, Int64} with 8 stored entries:
 1  2
  1  2
 3  4
  3  4
source
JosephsonCircuits.diagrepeat Method
julia
diagrepeat(A::SparseVector, Nmodes::Integer)

Return a sparse vector with each element of A duplicated along the diagonal Nmodes times.

Examples

julia
julia> JosephsonCircuits.diagrepeat(JosephsonCircuits.SparseArrays.sparsevec([1,2],[1,2]),2)
4-element SparseArrays.SparseVector{Int64, Int64} with 4 stored entries:
  [1]  =  1
  [2]  =  1
  [3]  =  2
  [4]  =  2
source
JosephsonCircuits.direct_sum Method
julia
direct_sum(A; n::Integer=1)
source
JosephsonCircuits.directcoefficients Method
julia
directcoefficients(sys, quantity)

The derivative of the port wave coefficients of outputcoefficients with respect to a relative perturbation of a port's own termination, which moves the port's reference impedance and its termination conductance together, z -> r z and g -> g/r, as the linearized solve moves them: -cv/2 and cd/2 for a wave, since z g is unchanged, and nothing for the voltage.

source
JosephsonCircuits.drivenresidual! Method
julia
drivenresidual!(F, prob, u, scale)

The residual at u with the drive scaled by scale: the F(u, p) form a continuation library asks for, with p the drive scale.

source
JosephsonCircuits.dualsearch! Method
julia
dualsearch!(f!, F, xcandidate, x, deltax, ϕ0, dϕ0dα, ϕcand,
    correction, betak, Fbest, Fspare, Fatx; ls = Backtracking(),
    curvedpriority = false)

Search selection for a rejected Anderson candidate: Both the curvilinear search x + α*deltax - betak*α²*correction and the plain damped-Newton search are run, and the better accepted point is taken. F and xcandidate should hold the candidate's residual and trial point (the curved path's α = 1), ϕcand the merit, and Fbest the residual at x.

The motivation is an iteration costs a Jacobian evaluation, factorization, and a linear solve which for a typical device like a TWPA take an order of magnitude more time than a residual evaluation, so extra residual evaluations are worth it if it results in a better path (which they appear to).

If both searches fail, the better best-effort point is returned and accepted is false. Fatx preserves the residual at x across the searches (which clobber Fbest with best-trial copies), keeping every restore contract valid.

Returns (α, ϕα, accepted, backtracks, usedcorrection), where usedcorrection reports whether the returned point lies on the curved path, and backtracks counts ALL trial evaluations after the candidate (the curved search's backtracks plus the plain search's full step and backtracks), so the iteration's residual evaluations are exactly 1 + backtracks.

source
JosephsonCircuits.edge2index Method
julia
edge2index(graph::Graphs.SimpleDiGraph{Int})

A dictionary from the (src, dst) tuple of each edge of graph, in both orientations, to the position of that edge in Graphs.edges(graph). The positions are the branch indices of the incidence matrix.

source
JosephsonCircuits.elaborate Method
julia
elaborate(circuit::Circuit; maxdepth = 64)

Recursively flatten the hierarchy of circuit into an ElaboratedCircuit. Elaboration:

  1. assigns each primitive instance a stable hierarchical path such as "cell37/cap";

  2. substitutes subcircuit interface pins with parent nets and allocates fresh internal nets for every subcircuit instance;

  3. deduplicates component definitions by object identity, so shared definitions and their data appear once;

  4. parses and validates each unique circuit definition once, however many times it is instantiated;

  5. resolves mutual inductor couplings to flattened instance indices;

  6. rejects recursive circuit definitions.

A repeated subcircuit definition is parsed once and the parse reused for every instance, so the work per instance is proportional to the instance's own size. maxdepth bounds the nesting depth.

source
JosephsonCircuits.eliminationtree Method
julia
eliminationtree(adj, order::AbstractVector{<:Integer})

The elimination tree of the node graph adj under order: parent[a] is the node eliminated first among those coupled to a after a, following the fill, or zero for a root. Returned with the postorder of the tree, which is the order the supernodes are eliminated in.

source
JosephsonCircuits.emptyrelations Method
julia
emptyrelations(A::AbstractArray)

The empty JunctionRelations, of the array types of A, which is what a circuit of sinusoidal junctions alone holds.

source
JosephsonCircuits.ensurecolumns! Method
julia
ensurecolumns!(ws::GMRESWorkspace, k)

Return the basis ws.V with at least k columns, replacing it with a wider one when it has fewer. The columns built so far are copied across; the new ones are uninitialized, as the whole basis was before. The width doubles and is capped at size(ws.H, 1), which is m + 1, so a basis never grows past the restart length.

source
JosephsonCircuits.equilibratecolumns! Method
julia
equilibratecolumns!(nzval::AbstractMatrix, eq::ColumnEquilibration,
    backend)

Divide each column of each system of the batch by its largest entry, recording the scales in eq.

source
JosephsonCircuits.escalatepreconditioner! Method
julia
escalatepreconditioner!(pc::AbstractPreconditioner)

Make the preconditioner pc a better approximation of the Jacobian, at greater cost, and return true; return false when it cannot be improved further. Called by nlsolvekrylov! after repeated linear solves which fail to reach the forcing tolerance, the symptom of a preconditioner too crude for the problem (stagnation alone is deliberately not the trigger). The default method returns false, which is correct for any preconditioner that is already exact or has no cheaper/costlier settings. A preconditioner which can grow must also refuse when the grown factors would not fit in memory: the driver records the refusal and carries on with what it has rather than let a rescue exhaust the machine.

source
JosephsonCircuits.escalatepreconditioner! Method
julia
escalatepreconditioner!(pc::ModeCouplingPreconditioner)

Grow the coupling set, a band by one offset per tone and any other set to every mode, and rebuild, returning true if it grew. Returns false when the set is already full, and when the factors of the grown set are predicted (couplingbytes) to exceed pc.budget, half the backend's free memory unless set, in which case nothing is built: the driver records the refusal and carries on with the set it has rather than let a rescue exhaust the machine.

This is the safety net of the block diagonal. A block diagonal preconditioner is cheap, but on a strongly pumped device it leaves the preconditioned operator nearly singular in a few directions, which stalls GMRES: the residual polynomial is pinned at p(0) = 1 and so cannot be made small near the origin.

For every set but a band, escalation goes straight to the full Jacobian rather than growing the set gradually, because there is no reliable way to know in advance which modes carry those directions (a band has a measured width to step, so it grows by one offset per tone first). Criteria based on the linear response of the circuit, on the mode frequencies, and on the mode diagonal blocks were each measured and none generalized across devices: the deficiency is a specific direction inside a mode's subspace rather than a property of the mode, and any per mode score averages it away. The full set is exact, so the method is never less robust than a direct solve, only faster when the block diagonal suffices. In practice this fires once or twice on a strongly pumped line and not at all otherwise.

The full set held in less precision than the iteration, single precision block factors or a CUDSSFactorization with a precision, is not exact either: its factors approximate the Jacobian to their own precision and can be too poor to converge the Krylov solve. Its escalation is the same coupling set in the iteration's precision, the factorization and the plan the matrix is assembled from promoted by withprecision; a reduced precision factorization of a smaller set grows the set first and escalates its precision once the set is full.

See FloquetPreconditioner for the alternative, which absorbs the same deficiency by measuring the directions rather than enlarging the factorization.

source
JosephsonCircuits.evaluatecovariance! Function
julia
evaluatecovariance!(dest::AbstractArray{Complex{Float64},3},
    block::ScatteringParameters, ws::AbstractVector,
    absbuffer = nothing)

Evaluate the stated noise covariance of block, whose noise model is a NoiseCovariance, at the signed angular frequencies ws with the block's negative frequency rule, as evaluatescattering! does the scattering parameters: the covariance of a wave at a negative frequency is the conjugate of that at the positive one.

source
JosephsonCircuits.evaluateharmoniccovariances! Method
julia
evaluateharmoniccovariances!(dest::AbstractArray{Complex{Float64},4},
    block::LinearizedScattering, ws::AbstractVector)

Evaluate the harmonic covariances of the stated noise of block, whose noise model is a NoiseCovariance over its harmonics, at the signed angular frequencies ws: dest[:, :, j, i] is V_k(ws[i]) = <n(ws[i] + k wp) n(ws[i])'> for k = block.harmonics[j], in the units of Cnoise, where a vacuum channel counts as one, rotated by the block's pump phase as the transfer functions are. The negative harmonics follow from V_{-k}(nu) = V_k(nu - k wp)', and the conjugate ladder of a frequency from V_k(-nu - k wp) = transpose(V_k(nu)) (see conjugateladder), which is how the covariance a solve reports, whose rows are the modes of the solve, states the noise at their conjugates.

This is the covariance every solve reads, zero at a frequency neither the data nor its conjugate ladder reaches.

source
JosephsonCircuits.evaluateharmonics! Method
julia
evaluateharmonics!(dest::AbstractArray{Complex{Float64},4},
    block::LinearizedScattering, ws::AbstractVector)

Evaluate the harmonic transfer functions of block at the signed angular frequencies ws: dest[:, :, j, i] is H_k(ws[i]) for the harmonic k = block.harmonics[j], rotated by the block's pump phase. The negative harmonics follow from H_{-k}(nu) = conj(H_k(-nu)), which a caller evaluates at the negated frequencies.

source
JosephsonCircuits.evaluatehybrid! Method
julia
evaluatehybrid!(B, C, block::ScatteringParameters, ws::AbstractVector,
    work::HybridWorkspace)

Evaluate the coefficient matrices of the hybrid (wave to modified nodal analysis) constitutive equations of block at the signed angular frequencies ws:

julia
B(w) v - C(w) i = 0,  B = (I - S(w)) R^(-1/2),  C = (I + S(w)) R^(1/2),

with R the diagonal of the reference impedances, v the port voltages and i the port currents (which the solvers carry as auxiliary variables). The diagonal multiplies on the right: with the power waves a = (R^(-1/2) v + R^(1/2) i)/2 and b = (R^(-1/2) v - R^(1/2) i)/2 and b = S a, the entry (p, q) of I - S scales with the impedance of port q, the port whose voltage it multiplies, so a block whose ports have different reference impedances is not symmetric between the two sides. This representation exists for every scattering matrix: unlike the admittance Y = R^(-1/2)(I-S)(I+S)^(-1)R^(-1/2), nothing is inverted, so blocks whose I+S is singular somewhere (an ideal short S = -1, or a lossless through line at each of its half wavelength resonances, where det(I+S) = 1-exp(-2*im*theta) = 0) are stamped exactly.

The scattering parameters are evaluated with the negative frequency rule of the block through evaluatescattering! at the native reference impedances; no renormalization of the data is performed. At exactly zero frequency the rows are replaced by i = 0 (B = 0, C = I): the node flux basis carries no DC voltage, and direct currents flow only through the inductive branches of the static flux stiffness graph, so a scattering block carries no direct current, consistent with the treatment of resistors.

work is the HybridWorkspace whose scratch is reused across calls.

source
JosephsonCircuits.evaluatehybridpumped! Method
julia
evaluatehybridpumped!(B, C, block::LinearizedScattering, ws, K,
    work::ScatteringWorkspace)

The coefficient matrices of the hybrid constitutive equations of a pumped block over the modes at the signed frequencies ws, as evaluatehybrid! gives them for a block which does not convert, with the modes coupled: B[p, q, m, n] and C[p, q, m, n] are the entries of (I - S) R^(-1/2) and (I + S) R^(1/2) from input port q at mode n to output port p at mode m, where the multi-mode scattering matrix is S[(p, m), (q, n)] = H_k[p, q](ws[n]) for the harmonic k = K[m, n] (see pumpedharmonics), the negative harmonics by H_{-k}(nu) = conj(H_k(-nu)), and zero where the modes are not coupled. The rows and columns of a mode at zero frequency carry only the identity, the i = 0 row of the stamp.

source
JosephsonCircuits.evaluateprovider! Method
julia
evaluateprovider!(dest::AbstractArray{T,3}, p::AbstractMatrixProvider,
    ws::AbstractVector)

Evaluate the provider at the angular frequencies ws, writing the matrix at frequency ws[i] into dest[:,:,i]. This is the batch, in-place evaluation contract used at analysis time: the caller evaluates each definition once per frequency grid and caches the result, so instances sharing a definition share one evaluation.

source
JosephsonCircuits.evaluatescattering! Function
julia
evaluatescattering!(dest::AbstractArray{Complex{Float64},3},
    block::ScatteringParameters, ws::AbstractVector,
    absbuffer = nothing)

Evaluate the scattering parameters of block at the signed angular frequencies ws, applying the block's negative frequency rule, and write the matrix at ws[i] into dest[:,:,i]. With ConjugateSymmetry the provider is evaluated at abs.(ws) and conjugated where ws[i] < 0; absbuffer, a Vector{Float64} the caller may pass, holds the absolute frequencies and avoids one allocation per call.

source
JosephsonCircuits.even_odd_to_coupling Method
julia
even_odd_to_coupling(Zeven, Zodd)

Return the coupling in dB couplingdB and system characteristic impedance Z0 for a directional coupler made from two coupled transmission lines with with even and odd mode impedances Zeven and Zodd.

Examples

julia
julia> JosephsonCircuits.even_odd_to_coupling(55.0,45.0)
(couplingdB = 20.0, Z0 = 49.749371855331)
source
JosephsonCircuits.even_odd_to_maxwell Method
julia
even_odd_to_maxwell(Zeven, Zodd, neven, nodd)

Return the inductance matrix and Maxwell capacitance matrix for two coupled transmission lines with even and odd mode impedances Zeven, Zodd and even and odd mode indices neven, nodd.

Examples

julia
L1 = [1.1 0.1;0.1 1.1]
C1 = [2.0 -0.4;-0.4 2.0]
L2, C2 = JosephsonCircuits.even_odd_to_maxwell(JosephsonCircuits.maxwell_to_even_odd(L1,C1)...)
isapprox(L1,L2) && isapprox(C1,C2)

# output
true
source
JosephsonCircuits.even_odd_to_mutual Method
julia
even_odd_to_mutual(Zeven, Zodd, neven, nodd)

Return the inductance matrix and mutual capacitance matrix for two coupled transmission lines with even and odd mode impedances Zeven, Zodd and even and odd mode indices neven, nodd.

Examples

julia
L1 = [1.1 0.1;0.1 1.1]
C1 = [1.6 0.4;0.4 1.6]
L2, C2 = JosephsonCircuits.even_odd_to_mutual(JosephsonCircuits.mutual_to_even_odd(L1,C1)...)
isapprox(L1,L2) && isapprox(C1,C2)

# output
true
source
JosephsonCircuits.export_netlist! Method
julia
export_netlist!(io::IO, circuit, circuitdefs)

Export the netlist in circuit to the IOBuffer or IOStream io.

Examples

julia
julia> io = IOBuffer();JosephsonCircuits.export_netlist!(io, [("P","1","0",1),("R","1","0",50.0)],Dict());println(String(take!(io)))
P 1 0 1
R 1 0 50.0
source
JosephsonCircuits.export_netlist Method
julia
export_netlist(filename, circuit, circuitdefs)

Export the netlist in circuit to the file with name and path filename.

source
JosephsonCircuits.export_netlist Method
julia
export_netlist(filename, circuit)

Export the netlist in circuit to the file with name and path filename.

source
JosephsonCircuits.exportnetlist Method
julia
exportnetlist(circuit, circuitdefs::Dict; port::Int = 1, jj::Bool = true)
exportnetlist(psc::CompiledCircuit, circuitdefs::Dict; port::Int = 1,
    jj::Bool = true)
exportnetlist(psc::CompiledCircuit, componentvalues::AbstractVector;
    port::Int = 1, jj::Bool = true)
exportnetlist(circuit; port::Int = 1, jj::Bool = true)

Export a circuit as a WRSPICE netlist. Returns a named tuple with the netlist as a string in netlist, the port number in port, the node count in Nnodes, and in junctions one entry per jj model instance written, in the order of the netlist, with the flat component index of the junction the instance realizes in index and the name of its phase node, whose voltage WRSPICE reports as the junction phase in radians, in phasenode; portnodes and portcurrent are placeholders fixed at 1, since the source nodes and amplitude are given directly to wrspice_input_transient or wrspice_input_ac. A fully numeric circuit needs no circuitdefs; a compiled circuit whose values are already numbers can be given those values directly as a vector in compiled component order. A resistor of infinite resistance is an open and writes no line. An ideal TransmissionLine is written as the SPICE lossless line element with its impedance and delay; any other scattering block has no SPICE element and is refused.

Component values are resolved with circuitdefs. With jj = true each Josephson junction is written as an instance of one WRSPICE jj model whose critical current is the mean over the junctions and whose capacitance to critical current ratio is the smallest such ratio over them, clamped to the WRSPICE maximum of 0.99e-6 (see calcCjIcmean); the part of each junction's shunt capacitance above what the model provides is written as a separate capacitor. With jj = false each junction is written as its linear inductance. port is the port number the sources are applied to, recorded in the output.

Examples

julia
circuit = Circuit(
    [:P1 => Port(1; Z0 = :R),
     :C1 => Capacitor(:Cc),
     :Lj1 => JosephsonJunction(:Lj),
     :C2 => Capacitor(:Cj),
     :gnd => Ground()],
    [Net("1", [(:P1, 1), (:C1, 1)]),
     Net("2", [(:C1, 2), (:Lj1, 1), (:C2, 1)]),
     Net("0", [(:P1, 2), (:Lj1, 2), (:C2, 2), (:gnd, 1)])])

circuitdefs = Dict(
    :Lj =>1000.0e-12,
    :Cc => 100.0e-15,
    :Cj => 1000.0e-15,
    :R => 50.0)

println(JosephsonCircuits.exportnetlist(circuit, circuitdefs;port = 1, jj = true).netlist)
println("")
println(JosephsonCircuits.exportnetlist(circuit, circuitdefs;port = 1, jj = false).netlist)

# output
* SPICE Simulation
RP1_termination 1 0 50.0
C1 1 2 100.0f
B1 2 0 3 jjk ics=0.32910597599999997u
C2 2 0 674.18508376f
.model jjk jj(rtype=0,cct=1,icrit=0.32910597599999997u,cap=325.81491624f,force=1,vm=9.9

* SPICE Simulation
RP1_termination 1 0 50.0
C1 1 2 100.0f
Lj1 2 0 1000.0000000000001p
C2 2 0 1000.0f
julia
circuit = Circuit(
    [:P1 => Port(1; Z0 = :R),
     :C1 => Capacitor(:Cc),
     :L1 => Inductor(:L1),
     :L2 => Inductor(:L2),
     :C2 => Capacitor(:Cj1),
     :C3 => Capacitor(:Cj2),
     :I1 => CurrentSource(:I1),
     :gnd => Ground()],
    [Net("1", [(:P1, 1), (:C1, 1)]),
     Net("2", [(:C1, 2), (:L1, 1), (:L2, 1), (:C2, 1), (:C3, 1), (:I1, 1)]),
     Net("0", [(:P1, 2), (:L1, 2), (:L2, 2), (:C2, 2), (:C3, 2), (:I1, 2),
      (:gnd, 1)])])

circuitdefs = Dict(
    :L1 =>2000.0e-12,
    :L2 =>2000.0e-12,
    :Cc => 100.0e-15,
    :Cj1 => 500.0e-15,
    :Cj2 => 500.0e-15,
    :R => 50.0,
    :I1 =>0.1)

println(JosephsonCircuits.exportnetlist(circuit, circuitdefs;port = 1, jj = true).netlist)
println("")
println(JosephsonCircuits.exportnetlist(circuit, circuitdefs;port = 1, jj = false).netlist)

# output
* SPICE Simulation
RP1_termination 1 0 50.0
C1 1 2 100.0f
L1 2 0 1000.0000000000001p
C2 2 0 1000.0f

* SPICE Simulation
RP1_termination 1 0 50.0
C1 1 2 100.0f
L1 2 0 1000.0000000000001p
C2 2 0 1000.0f
julia
circuit = Circuit(
    [:P1 => Port(1; Z0 = :Rleft),
     :L1 => Inductor(:L1),
     :Lj1 => JosephsonJunction(:Lj1),
     :L2 => Inductor(:L2),
     :K1 => MutualInductor(:K1, :L1, :L2),
     :C2 => Capacitor(:C2),
     :C3 => Capacitor(:C3),
     :gnd => Ground()],
    [Net("1", [(:P1, 1), (:L1, 1)]),
     Net("2", [(:Lj1, 1), (:L2, 1), (:C2, 1), (:C3, 1)]),
     Net("0", [(:P1, 2), (:L1, 2), (:Lj1, 2), (:L2, 2), (:C2, 2), (:C3, 2),
      (:gnd, 1)])])
circuitdefs = Dict(
    :Rleft => 50.0,
    :L1 => 1000.0e-12,
    :Lj1 => 1000.0e-12,
    :K1 => 0.1,
    :L2 => 1000.0e-12,
    :C2 => 1000.0e-15,
    :C3 => 1000.0e-15)

println(JosephsonCircuits.exportnetlist(circuit, circuitdefs;port = 1, jj = true).netlist)
println("")
println(JosephsonCircuits.exportnetlist(circuit, circuitdefs;port = 1, jj = false).netlist)

# output
* SPICE Simulation
RP1_termination 1 0 50.0
L1 1 0 1000.0000000000001p
B1 2 0 3 jjk ics=0.32910597599999997u
C2 2 0 1674.18508376f
L2 2 0 1000.0000000000001p
K1 L1 L2 0.1
.model jjk jj(rtype=0,cct=1,icrit=0.32910597599999997u,cap=325.81491624f,force=1,vm=9.9

* SPICE Simulation
RP1_termination 1 0 50.0
L1 1 0 1000.0000000000001p
Lj1 2 0 1000.0000000000001p
L2 2 0 1000.0000000000001p
K1 L1 L2 0.1
C2 2 0 2000.0f
julia
circuit = Circuit(
    [:P1 => Port(1; Z0 = :Rleft),
     :L1 => Inductor(:L1),
     :Lj1 => JosephsonJunction(:Lj1),
     :L2 => Inductor(:L2),
     :K1 => MutualInductor(:K1, :L2, :L1),
     :C2 => Capacitor(:C2),
     :C3 => Capacitor(:C3),
     :gnd => Ground()],
    [Net("1", [(:P1, 1), (:L1, 1)]),
     Net("2", [(:Lj1, 1), (:L2, 1), (:C2, 1), (:C3, 1)]),
     Net("0", [(:P1, 2), (:L1, 2), (:Lj1, 2), (:L2, 2), (:C2, 2), (:C3, 2),
      (:gnd, 1)])])
circuitdefs = Dict(
    :Rleft => 50.0,
    :L1 => 1000.0e-12,
    :Lj1 => 1000.0e-12,
    :K1 => 0.1,
    :L2 => 1000.0e-12,
    :C2 => 1000.0e-15,
    :C3 => 1000.0e-15)

println(JosephsonCircuits.exportnetlist(circuit, circuitdefs;port = 1, jj = true).netlist)
println("")
println(JosephsonCircuits.exportnetlist(circuit, circuitdefs;port = 1, jj = false).netlist)

# output
* SPICE Simulation
RP1_termination 1 0 50.0
L1 1 0 1000.0000000000001p
B1 2 0 3 jjk ics=0.32910597599999997u
C2 2 0 1674.18508376f
L2 2 0 1000.0000000000001p
K1 L2 L1 0.1
.model jjk jj(rtype=0,cct=1,icrit=0.32910597599999997u,cap=325.81491624f,force=1,vm=9.9

* SPICE Simulation
RP1_termination 1 0 50.0
L1 1 0 1000.0000000000001p
Lj1 2 0 1000.0000000000001p
L2 2 0 1000.0000000000001p
K1 L2 L1 0.1
C2 2 0 2000.0f
source
JosephsonCircuits.extractbranches! Method
julia
extractbranches!(branchvector::Vector,componenttypes::Vector{Symbol},
    nodeindexarray::Matrix{Int})

Push the branches described in extractbranches onto the empty vector branchvector.

source
JosephsonCircuits.extractbranches Method
julia
extractbranches(componenttypes::Vector{Symbol},nodeindexarray::Matrix{Int})

The (node1, node2) branches of the components which define the circuit graph: inductors (:L), Josephson junctions (:Lj), current sources (:I), ports (:P) and voltage sources (:V). Capacitors, resistors and mutual inductors do not create branches.

Components sharing a branch produce duplicate tuples; the graph construction in calcgraphs merges them.

Examples

julia
julia> JosephsonCircuits.extractbranches([:P,:I,:R,:C,:Lj,:C],[2 2 2 2 3 3; 1 1 1 3 1 1])
3-element Vector{Tuple{Int64, Int64}}:
 (2, 1)
 (2, 1)
 (3, 1)
source
JosephsonCircuits.factorizationprecision Method
julia
factorizationprecision(f::AbstractFactorization)

The floating point type the matrix handed to f is built and factorized in, nothing when it follows the iteration's. Only CUDSSFactorization has one; KLU and UMFPACK factorize in double precision whatever they are handed. BlockFactorization also takes a precision, but for the dense blocks it builds itself, while the sparse matrix it is handed stays in the iteration's type, so it has none here.

source
JosephsonCircuits.factorize Method
julia
factorize(f::BlockFactorization, A::SparseMatrixCSC; blocksize,
    backend = CPU(), nb = 1, target, refine = 6)

The SparseBlockFactorization of A with node blocks of blocksize unknowns (the linearized solve passes its mode count), on backend, holding nb systems of the pattern, filled from A's values in every slot. Precision from f; Float32 factors of a double matrix refine against the double residual for at most refine steps (six by default, until the residual stops halving); refine = 0 leaves the solutions single precision solutions of the double system, computed entirely in single precision. target is the amalgamation target in rows: on the host BLOCKTARGETROWS, where LAPACK's LU of a supernode and the BLAS-3 panel products want large blocks; on a device the block size, no amalgamation, since the batched LU and inverse of the diagonal blocks (getrf/getri batched) are efficient only for small blocks and the batch supplies the parallelism amalgamation gave a single system.

source
JosephsonCircuits.fdscatteringderivative Method
julia
fdscatteringderivative(b0, bp, bm, twoh)

A ScatteringParameters whose scattering matrix is the central finite difference (S_plus(w) - S_minus(w))/twoh of the two perturbed blocks, carrying the reference impedances and the negative frequency convention of the unperturbed block, so the solver treats the derivative with exactly the conventions of the value. Constructed directly rather than through the public constructor, because a derivative is not a passive scattering matrix and must not be checked as one.

source
JosephsonCircuits.fftplans Method
julia
fftplans(fd::AbstractArray{Complex{T}}, td::AbstractArray{T},
    stepsperperiod::Int, backend::Backend)

Create the inverse real transform plan from the frequency domain array fd to the time domain array td, and the forward plan back, on the given KernelAbstractions backend. The transform runs over all but the last dimension, the last being the Josephson junction index.

The CPU() method uses FFTW. A device backend supplies its own method, which is the only thing the residual and the matrix-free products need that the core package cannot provide without taking on the device dependency: every other step of those is either a plain array operation or a kernel of NonlinearTermPlan. Load the package extension for the device (for CUDA, using CUDA) to get its method.

source
JosephsonCircuits.fillandfactorize! Method
julia
fillandfactorize!(F::SparseBlockFactorization, vals::AbstractMatrix)

Refactorize the batch from the stored values vals, one column per system in the order of nonzeros of the pattern, on the backend: the device sweep assembles the values of a batch of frequencies there.

source
JosephsonCircuits.find_duplicate_connections Method
julia
find_duplicate_connections(
    connections::AbstractVector{Tuple{T,T,Int,Int}}) where {T}

Return a vector of tuples of (connection, counts) where counts is the number of times a given connection appears.

source
JosephsonCircuits.find_duplicate_network_names Method
julia
find_duplicate_network_names(
    networks::AbstractVector{Tuple{T,N,Vector{Tuple{T, Int}}}}) where {T,N}

Return a vector of tuples of (networkname, counts) where counts is the number of times a given network name appears.

source
JosephsonCircuits.findgroundnodeindex Method
julia
findgroundnodeindex(uniquenodevector::Vector{String})

The index of the ground node "0" in uniquenodevector, or 0 if there is none.

Examples

julia
julia> JosephsonCircuits.findgroundnodeindex(["1","0","2"])
2

julia> JosephsonCircuits.findgroundnodeindex(["1","2"])
0

julia> JosephsonCircuits.findgroundnodeindex(String[])
0
source
JosephsonCircuits.forwardsolution! Method
julia
forwardsolution!(phin, ds::DeviceSweep, i::Integer)
adjointsolution!(phin, ds::DeviceSweep, i::Integer)

Fill phin with the forward or adjoint solution of frequency i of the batch staged by the last solvebatch!: the whole solution when the direction was staged in full, otherwise only its gathered rows. The form hblinsolve_inner! takes as presolved and presolvedadjoint.

source
JosephsonCircuits.forwardtermkernel! Method
julia
forwardtermkernel!(phimatrix, n1, s1, n2, s2, flags, xr)

Evaluate the map from the equivalent real representation of the unknowns to the frequency domain coefficients of the Josephson junction branch fluxes, one work item per slot of phimatrix. Each work item gathers the at most two node fluxes of its branch through the incidence matrix entries held in the plan, assembles the complex coefficient from the real slots of the real representation, and conjugates it when the slot is a conjugate symmetry target. Every slot is written exactly once, so the destination needs no zeroing and the stores are contiguous. See NonlinearTermPlan.

source
JosephsonCircuits.forwardtermkernelcomplex! Method
julia
forwardtermkernelcomplex!(phimatrix, cn1, s1, cn2, s2, flags, xc)

The complex representation counterpart of forwardtermkernel!, which gathers the same at most two node fluxes through the same incidence entries but addresses them as complex indices, so no real slot arithmetic is needed and the FWIDE flag is not consulted. See NonlinearTermPlan.

source
JosephsonCircuits.forwardtransposekernel! Method
julia
forwardtransposekernel!(out, tfptr, tfslot, tfcoef, tfimag, Q, ktptr,
    ktrow, ktcoef, w)

Transpose of the forward map plus the transposed linear term, one work item per real slot of the unknowns. Each item gathers the frequency domain slots which read it and the entries of the transposed linear term which land on it, and writes the single slot it owns.

source
JosephsonCircuits.fourierindices Method
julia
fourierindices(freq::Frequencies)

Generate the indices used in the RDFT or DFT and inverse RDFT or DFT and converting between a node flux vector for solving system and the matrices for the Fourier analysis. See also FourierIndices, Frequencies, calcfreqsrdft and calcfreqsdft.

source
JosephsonCircuits.freecurrents Method
julia
freecurrents(r::DCBlockRows)

The total number of port current directions the blocks leave undetermined. Nonzero means some current is fixed by node level Kirchhoff rather than by the block, which is the case a short or an ideal through presents.

source
JosephsonCircuits.freememory Method
julia
freememory(backend)

The free memory of backend in bytes: the host's for CPU(), the device's on a CUDA backend (defined by the CUDA extension). What Automatic, linearizedfactorization and the device sweep's batch size their choices against.

source
JosephsonCircuits.freqsubst Method
julia
freqsubst(A::SparseMatrixCSC, wmodes::Vector, symfreqvar)

Substitute the frequency dependent elements of A using the vector of mode frequencies wmodes and the symbolic frequency variable symfreqvar. Returns a sparse matrix with type Complex{Float64}.

Examples

julia
JosephsonCircuits.@params w
wmodes = [-1,2];
A = JosephsonCircuits.diagrepeat(JosephsonCircuits.SparseArrays.sparse([1,2,1], [1,2,2], [w,2*w,3*w],2,2),2);
JosephsonCircuits.freqsubst(A,wmodes,w)

# output
4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 6 stored entries:
 -1.0+0.0im      -3.0+0.0im    
      2.0+0.0im      6.0+0.0im
      -2.0+0.0im    
      4.0+0.0im
julia
wmodes = [-1,2];
A = JosephsonCircuits.diagrepeat(JosephsonCircuits.SparseArrays.sparse([1,2,1], [1,2,2], [1,2,3],2,2),2);
JosephsonCircuits.freqsubst(A,wmodes,nothing)

# output
4×4 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 6 stored entries:
 1.0+0.0im      3.0+0.0im    
      1.0+0.0im      3.0+0.0im
      2.0+0.0im    
      2.0+0.0im
source
JosephsonCircuits.gathercanonical! Method
julia
gathercanonical!(u, rint, L::CompositeLayout)

Write the internal real state rint into the internal block of the canonical state u, a copy.

The vdc block has no internal counterpart and is left untouched, so a caller which keeps explicit direct current coordinates in u does not lose them here. A solve does not call this: it hands the harmonic system the internal block of u through internalpart and no copy is made. The interfaces which want a state of their own do.

source
JosephsonCircuits.gatherportrows! Method
julia
gatherportrows!(out, X, rows, backend)

Gather the rows named by rows from every right hand side of every system of the batch X into out, with a kernel on backend. See portsolutionrows.

source
JosephsonCircuits.gathervalues! Method
julia
gathervalues!(dest::AbstractArray, src::AbstractVector,
    index::AbstractArray)

dest[k] = src[index[k]] for every k, as a KernelAbstractions kernel on the backend of dest, which src and index must share. The device side of the permuted copies of the canonical layout (_gatherperm!): index is an injection, so no element is written twice and no atomic is needed.

source
JosephsonCircuits.get_ports Method
julia
get_ports(network::Tuple{T, N, Vector{Tuple{T, Int}}}) where {T,N}

Return the ports for a network network. The ports are already present in the network.

Examples

julia
julia> JosephsonCircuits.get_ports((:S1,[0.0 1.0;1.0 0.0],[(:S1,1),(:S2,3)]))
2-element Vector{Tuple{Symbol, Int64}}:
 (:S1, 1)
 (:S2, 3)
source
JosephsonCircuits.get_ports Method
julia
get_ports(network::Tuple{T, N}) where {T,N}

Return the ports for a network network. The ports are generated based on the network name.

Examples

julia
julia> JosephsonCircuits.get_ports((:S1,[0.0 1.0;1.0 0.0]))
2-element Vector{Tuple{Symbol, Int64}}:
 (:S1, 1)
 (:S1, 2)
source
JosephsonCircuits.gmres! Method
julia
gmres!(x, Aop!, b, ws::GMRESWorkspace; Mop! = nothing, rtol = 1e-6,
    atol = 0.0, maxrestarts = 10, initialzero = true, oncycle = nothing)

Solve A*x = b with restarted GMRES, where mul!(w, Aop, v) computes w = A*v and the optional Mop! applies a preconditioner z = M \ v, either as a bare in-place closure Mop!(z, v) or as an AbstractPreconditioner, which is applied through applypreconditioner! and may fuse its application with the operator product (preconditionedproduct!). The matrix A is never formed; only its action is required, which is what makes this usable with the matrix-free jacobianvectorproduct!.

Preconditioning is applied on the right, solving A*inv(M)*u = b and then x = inv(M)*u. Right preconditioning keeps the recurrence's residual estimate equal to the true residual of the original system, so the stopping test is on norm(b - A*x) and does not depend on the quality of M. Because M is held fixed across a solve, the preconditioner is applied once per Arnoldi step and once more per restart, rather than being stored for every basis vector.

The Arnoldi basis is built by modified Gram-Schmidt with a conditional second pass (gmres_orthogonalize!). A subdiagonal which collapses relative to the vector it came from is a (lucky) breakdown: the Krylov space is invariant, the reduced least squares solution is exact, and the cycle ends there rather than continuing with a spurious basis vector. The residual is recomputed explicitly at every restart so restarts cannot drift from the recurrence estimate.

Converges when norm(b - A*x) <= max(rtol*norm(b), atol). Returns the named tuple (iterations, residual, converged, cycles, reason, precondtime, residualvector, products), where iterations counts Arnoldi steps across all cycles, cycles the number of restart cycles begun, reason is one of :converged, :breakdown (an unhappy breakdown: the Krylov space went invariant without the residual coming down), :stagnation (a cycle failed to reduce the explicit residual, or produced a non-finite one), or :iterationlimit, precondtime the seconds spent applying the preconditioner, and residualvector the final residual b - A*x when it was formed explicitly (nothing otherwise; the caller reads it with get, as it does precondtime and products).

iterations is not the total number of Aop! calls: each cycle costs one further application for the explicit residual recomputation, and a warm start costs one at the outset; products in the returned tuple is that total, not counting products a preconditioner takes inside its own application. maxrestarts bounds the number of cycles including the first, so the Arnoldi work is capped at maxrestarts*m steps. oncycle(ws, j), when given, is called at the end of every cycle with the workspace still holding that cycle's j Arnoldi vectors, for a caller which harvests from each cycle (harvestcycle!); it must only read the workspace.

Allocation free after the workspace is built, apart from whatever Aop! and Mop! themselves allocate.

source
JosephsonCircuits.gmres_applyrotations! Method
julia
gmres_applyrotations!(H, cs, sn, s, j)

Reduce column j of the Hessenberg matrix H to upper triangular form: apply the j-1 previous Givens rotations to the new column, compute and store the rotation which annihilates the new subdiagonal H[j+1, j], and apply it to the least squares right hand side s. After this the magnitude of s[j+1] is the residual norm of the least squares problem, which with right preconditioning is the true residual norm of the original system. Allocation free.

source
JosephsonCircuits.gmres_correction! Method
julia
gmres_correction!(x, ws::GMRESWorkspace, j, Mop!)

Solve the reduced j x j triangular least squares problem by back substitution, assemble the correction u = V[:, 1:j]*y in the Krylov basis, undo the right preconditioning once with Mop! (or not at all when Mop! === nothing), and add the result to x in place. A zero diagonal entry, which can only arise from an exact breakdown, contributes a zero coefficient rather than a division by zero. Allocation free.

source
JosephsonCircuits.gmres_givens Method
julia
gmres_givens(a, b)

The Givens rotation (c, s, r) with c*a + s*b = r and -s*a + c*b = 0, computed through hypot so it cannot overflow, with the identity rotation returned for the zero input.

source
JosephsonCircuits.gmres_orthogonalize! Method
julia
gmres_orthogonalize!(w, V, H, hd, c, j)

Orthogonalize w against the first j Arnoldi basis vectors (the columns of V) by block classical Gram-Schmidt with one reorthogonalization (CGS2), accumulating the coefficients into column j of the Hessenberg matrix H. c is scratch of length at least j. Both passes accumulate into the same entries of H, so H remains the exact projection. Writes the subdiagonal H[j+1, j] and returns (hsub, normw0): the norm of the orthogonalized w and its norm on entry, the pair the caller compares to detect a breakdown.

CGS2 is chosen over modified Gram-Schmidt with a DGKS test for its shape rather than its accuracy, which is equivalent: both are orthogonal to machine precision. Each pass here is two level 2 BLAS calls over the whole basis, where the modified form is j dependent pairs of a dot product and an axpy, each dot having to complete before the axpy that follows it. The second pass is unconditional, which costs what the DGKS path costs whenever it does reorthogonalize and removes a branch on a freshly computed scalar. Neither the coefficient vector nor the branch has to reach the host, which is what makes this form usable on a device.

source
JosephsonCircuits.groupdestinations Method
julia
groupdestinations(destinations)

Group scalar contributions by the stored entry they are added to, as (order, dest, segptr): the contributions sorted by destination, the distinct destinations, and the offset of each one's run in order, so that group k is order[segptr[k]:segptr[k+1]-1] and every one of its members has destination dest[k].

This is what lets scatteringstampkernel! accumulate without an atomic: distinct groups write distinct addresses.

source
JosephsonCircuits.halmos_dilation Method
julia
halmos_dilation(S)

Return the Halmos dilation of the passive lossy scattering parameter matrix S. This converts a passive lossy scattering parameter matrix into a lossless (unitary) scattering parameter matrix with twice the number of ports.

Examples

julia
julia> JosephsonCircuits.is_unitary(JosephsonCircuits.halmos_dilation([0.1 0;0 0.1]))
true

References

[1] P. L. Robinson, “Julia operators and Halmos dilations,” Mar. 25, 2018, arXiv:1803.09329. doi: 10.48550/arXiv.1803.09329. [2] B. Sz.-Nagy, C. Foias, H. Bercovici, and L. Kérchy, Harmonic Analysis of Operators on Hilbert Space. New York, NY: Springer, 2010. doi: 10.1007/978-1-4419-6094-8. [3] P. R. Halmos, “Normal dilations and extensions of operators,” Summa Brasiliensis Mathematicae, vol. II, no. VI, pp. 125–134, Dec. 1950. [4] J. J. Schäffer, “On Unitary Dilations of Contractions,” Proceedings of the American Mathematical Society, vol. 6, no. 2, pp. 322–322, 1955, doi: 10.2307/2032368. [5] B. Szőkefalvi-Nagy, “Sur les contractions de l’espace de Hilbert,” ACTA SCIENTIARUM MATHEMATICARUM, vol. 15, pp. 87–92, 1954.

source
JosephsonCircuits.harmonicritznearzero Method
julia
harmonicritznearzero(Hbar::AbstractMatrix, nkeep::Integer)

The harmonic Ritz vectors of an Arnoldi factorization whose Ritz values lie nearest the origin, returned as the columns of a real m by p matrix of coefficients in the Arnoldi basis, p <= 2*nkeep. Returns an m by 0 matrix when nkeep < 1, when the pencil cannot be factorized, or when every Ritz value is infinite.

For A*V = V_{m+1}*Hbar a harmonic Ritz pair (theta, y) makes the eigenpair residual A*V*y - theta*V*y orthogonal to A*K_m, which is the generalized eigenproblem

julia
Hbar'*Hbar*y = theta*H'*y

with H the square leading block. That is the pencil solved here, on the host, rather than the equivalent H + abs2(h)*inv(H')*e*e', which applies the inverse of H exactly where it is worst conditioned, near the directions of interest; a singular H gives infinite Ritz values, which are simply not selected. Harmonic Ritz values approximate the eigenvalues of A nearest zero far better than the ordinary Ritz values do, whose restarted GMRES cycle approximates the outer spectrum, the part deflation has no use for.

Hbar must be the Arnoldi Hessenberg (GMRESWorkspace.Harnoldi), not the least squares matrix the Givens rotations leave in GMRESWorkspace.H: the singular values of the two agree, the pencil does not. A real matrix has complex eigenpairs in conjugate pairs, and both the real and the imaginary part of such an eigenvector lie in the real invariant subspace the pair spans, so each is returned as its own real column; the duplication is harmless because the residual-image factorization removes whatever is redundant.

source
JosephsonCircuits.harvest! Method
julia
harvest!(pc::AbstractPreconditioner, ws::GMRESWorkspace, out::NamedTuple)

Give the preconditioner pc the Arnoldi factorization a solve just built, so it can extract information for the next solve. out is the named tuple returned by gmres!. Called by nlsolvekrylov! after every GMRES call. The default does nothing, which is correct for any preconditioner that does not recycle.

Only the last restart cycle is still present in the workspace, so implementations must derive the usable Arnoldi dimension from out.iterations and out.cycles rather than from out.iterations alone.

source
JosephsonCircuits.harvestcycle! Method
julia
harvestcycle!(pc::AbstractPreconditioner, ws::GMRESWorkspace, j::Integer)

Give the preconditioner the Arnoldi factorization of the restart cycle which has just ended, j vectors of it, before gmres! overwrites the workspace with the next cycle. The default does nothing.

This is the per-cycle counterpart of harvest!, which sees only the cycle left in the workspace when the solve returns. A preconditioner opts into it through usescycleharvest, and one which does is not harvested again afterwards.

source
JosephsonCircuits.harvestdimension Method
julia
harvestdimension(ws::GMRESWorkspace, out::NamedTuple)

The number of Arnoldi vectors of the last restart cycle still present in the workspace, which is the usable dimension for a harvest; the workspace holds only that cycle, so this is derived from out.iterations and out.cycles rather than from the iteration count alone. Zero when the cycle is empty or overran.

source
JosephsonCircuits.hasports Method
julia
hasports(component)

Whether the component exposes bundled two terminal port views addressable in pair connections.

source
JosephsonCircuits.hasrealbackward Method
julia
hasrealbackward(plan::NonlinearTermPlan)

Whether plan carries the real form of the linear term, and so whether the real representation backward map can be applied. False for a plan built with realbackward = false. The complex representation is always available.

source
JosephsonCircuits.hbcache Method
julia
hbcache(w, Nharmonics, sources, builder, p::NamedTuple;
    dc = false, odd = true, even = false, maxintermodorder = Inf,
    Nevaluationharmonics = map(i -> 2i, Nharmonics),
    frequencywindow = (0, Inf), sorting = :number, kwargs...)

A reusable nonlinear solver over the circuit builder builder, parsed once at the parameter point p. builder(; p...) must return a netlist of (name, node1, node2, value) tuples with fully numeric values; a typed Circuit is refused, because the cache rebinds values by walking the builder's output. The harmonic selection keywords match hbnlsolve; the remaining keywords are stored and forwarded to every solve as keywords of hbnlsolve on the compiled circuit, so they are the solver keywords (method, atol, rtol, iterations, backend, ...) and are validated here: a keyword the compiled circuit solve does not accept is an ArgumentError at construction rather than a failure at the first solve, as are x0 and reuse, which the cache manages itself (the warm start through warmstart, the reuse object internally), keyedarrays = true, since the state is kept as plain vectors (false is accepted as what the cache does anyway), and method = Staged(), which the cache does not support since the continuation builds its own systems at its own truncations.

The builder must keep the circuit topology fixed as the parameters vary; hbsolve! checks the component names of each new evaluation against the parse.

Examples

julia
make(; Lj, Cc) = [("P1","1","0",1), ("R1","1","0",50.0),
    ("C1","1","2",Cc), ("Lj1","2","0",Lj), ("C2","2","0",1000e-15)]
cache = hbcache((2*pi*4.75e9,), (8,),
    [(mode=(1,), port=1, current=1e-8)], make,
    (Lj = 1000e-12, Cc = 100e-15))
for Lj in (900:25:1100)*1e-12
    sol = hbsolve!(cache, (Lj = Lj, Cc = 100e-15))
    cache.converged || break
end
source
JosephsonCircuits.hbconjmatind Method
julia
hbconjmatind(truncfrequencies::Frequencies{N})

Returns a matrix describing which indices of the frequency domain matrix (from the RFFT) to pull out and use in the conjugate harmonic balance matrix, which is built from the sums of the modes, aliased back onto the sampled grid, and describes the coupling between the modes and the complex conjugates of the modes (the derivative of the residual with respect to the complex conjugates of the node fluxes). A negative index means we take the complex conjugate of that element. A zero index means that term is not present, so skip it. See also hbmatind.

Examples

julia
julia> freq = JosephsonCircuits.calcfreqsrdft((3,));JosephsonCircuits.hbconjmatind(JosephsonCircuits.removeconjfreqs(JosephsonCircuits.truncfreqs(freq;dc=true,odd=true,even=true,maxintermodorder=2)))[2]
4×4 Matrix{Int64}:
 1   2   3   4
 2   3   4  -4
 3   4  -4  -3
 4  -4  -3  -2
source
JosephsonCircuits.hbconjmatind Method
julia
hbconjmatind(frequencies::Frequencies{N},
    truncfrequencies::Frequencies{N})

Returns a matrix describing which indices of the frequency domain matrix (from the RFFT) to pull out and use in the conjugate harmonic balance matrix, which is built from the sums of the modes truncfrequencies.modes[i] + truncfrequencies.modes[j], aliased back onto the sampled grid described by frequencies. A negative index means we take the complex conjugate of that element. A zero index means that term is not present, so skip it. See also hbmatind.

source
JosephsonCircuits.hbd2F! Method
julia
hbd2F!(out, prob, u, v, w)

The exact second directional derivative H(u)[v,w] = B(-sin(A*u).*(A*v).*(A*w)).

source
JosephsonCircuits.hbd3F! Method
julia
hbd3F!(out, prob, u, v, w, z)

The exact third directional derivative d3F(u)[v,w,z] = B(-cos(A*u).*(A*v).*(A*w).*(A*z)).

Supplying this exactly rather than by finite differences is what makes a continuation library's normal form computation – cusp, Bogdanov-Takens, Bautin – accurate.

source
JosephsonCircuits.hbdFdp! Method
julia
hbdFdp!(out, prob)

The derivative of the residual with respect to the drive scale, which is -b: the residual is B(sin(A*u)) + K*u - scale*b, so the parameter derivative is exact and constant, and a continuation tangent never needs a finite difference in the parameter.

source
JosephsonCircuits.hbjacobian! Method
julia
hbjacobian!(J, prob::HBNonlinearProblem, u)

Assemble the exact real Jacobian at u.

source
JosephsonCircuits.hbjvp! Method
julia
hbjvp!(Jv, prob::HBNonlinearProblem, u, v)

The exact matrix-free Jacobian-vector product J(u)*v. Two transforms plus the linear term, with no Jacobian assembled.

This convenience form re-sets the evaluation point on every call, which costs one extra forward transform. Inside a Krylov loop use a JacobianOperator, which sets the point once at construction and whose mul! pays only the product itself.

source
JosephsonCircuits.hblinearsolve! Method
julia
hblinearsolve!(ls, deltax, jvp!, F, ws, Mop!; rtol, atol, maxrestarts,
    oncycle = nothing)

Solve for the Newton step and return the output named tuple gmres! produces. converged, residual, iterations, cycles and reason are required; residualvector (the explicit final residual, which the line search slope reads, at the cost of one extra Jacobian product when it is missing), precondtime and products are read with get and may be omitted by an external solver. jvp!(y, v) applies the Jacobian, in place, and Mop! is the preconditioner, an AbstractPreconditioner or a closure Mop!(z, r). oncycle is the per-cycle callback of gmres!, which a solver that does not restart may ignore.

This is the one part of the Newton-Krylov loop with nothing harmonic balance specific about it: an operator, a right hand side, a preconditioner and a tolerance. Putting it behind an interface lets an external Krylov library be substituted without touching anything else.

source
JosephsonCircuits.hblinsolve Function
julia
hblinsolve(w, circuit::Circuit, circuitdefs = Dict{Symbol,Number}();
    sorting = :name, kwargs...)

The linearized sweep of a typed Circuit, with every keyword of the general method. circuitdefs is needed only when component values are symbolic, and sorting defaults to :name because hierarchical net names are not integers.

source
JosephsonCircuits.hblinsolve Method
julia
hblinsolve(w, circuit, circuitdefs; Nmodulationharmonics = (0,),
    nonlinear = nothing, symfreqvar = nothing, threewavemixing = false,
    fourwavemixing = true, maxharmonics = Nmodulationharmonics,
    maxintermodorder = Inf, nbatches = Base.Threads.nthreads(),
    sorting = :number, returnS = true, returnSnoise = false,
    returnCnoise = false, returnQE = true, returnCM = true,
    returnnodeflux = false, returnnodefluxadjoint = false,
    returnvoltage = false, returnvoltageadjoint = false,
    keyedarrays = true, temperature = 0.0,
    sensitivitynames::Vector{String} = String[],
    sensitivitynodeflux = nothing, sensitivityresidual = nothing,
    sensitivitymode = :auto, returnSsensitivity = false,
    factorization = nothing, backend = CPU())

Sweep the weak signal frequencies w through the circuit linearized about the operating point nonlinear found by hbnlsolve, or through the linear circuit when nonlinear = nothing. Any number of signal and idler modes, ports and pumps is supported. The scattering parameters, noise scattering parameters, quantum efficiency, commutation relations, node fluxes and voltages, and sensitivities are computed on request.

The linearized system is solved in the same modified nodal analysis formulation as the nonlinear one (see hbnlsolve), without gauge fixing rows because a mode at (numerically) zero total frequency is rejected with an ArgumentError; estimate a direct current limit from a sequence of decreasing nonzero frequencies instead.

Arguments

  • w: the signal angular frequency or frequencies in radians per second, a real number or any iterable of them.

  • circuit: a typed Circuit, a legacy netlist of (name, node1, node2, value) tuples, or a CompiledCircuit.

  • circuitdefs: a dictionary from the symbols or symbolic variables used as component values to their numerical values. Optional when every component value is numeric.

Keywords

  • Nmodulationharmonics = (0,): how many harmonics of each pump to retain around the signal, which sets the signal and idler modes; (0,) is the signal alone.

  • nonlinear = nothing: the NonlinearHB operating point to linearize about, or nothing for a linear circuit.

  • symfreqvar = nothing: the symbolic frequency variable, such as w, when component values are expressions in the frequency.

  • threewavemixing = false: retain the odd pump harmonics around the signal, through which three wave mixing couples the modes.

  • fourwavemixing = true: retain the even pump harmonics around the signal, through which four wave mixing couples the modes.

  • maxharmonics = Nmodulationharmonics: an upper bound on the absolute harmonic index retained for each pump; see truncfreqs.

  • maxintermodorder = Inf: keep only the modes whose harmonic indices have an absolute sum of at most this order.

  • nbatches = Base.Threads.nthreads(): the number of batches the signal frequencies are split into for multithreading; 1 runs single threaded.

  • sorting = :number: how the nodes are ordered, with ground always first. :number parses the node names as integers and sorts numerically (an error if a name is not an integer); :name sorts the names as strings, so that "101" comes before "11"; :none keeps the order of first appearance. The methods taking a typed Circuit default to :name, since hierarchical net names are not integers.

  • returnS = true: return the scattering parameters of the linearized solve.

  • returnSnoise = false: return the noise scattering parameters.

  • returnCnoise = false: return the added noise covariance at the output ports; see LinearizedHB.

  • returnQE = true: return the quantum efficiency.

  • returnCM = true: return the commutation relations.

  • returnnodeflux = false, returnvoltage = false: return the node fluxes and voltages of the linearized solve.

  • returnnodefluxadjoint = false, returnvoltageadjoint = false: return the node fluxes and voltages of the adjoint (time reversed modulation) linearized solve.

  • keyedarrays = true: return the outputs as keyed arrays with named, labeled axes rather than plain arrays.

  • temperature = 0.0: the physical temperature in Kelvin of every dissipative element which does not state its own, and so of the noise it adds. A channel at temperature T carries coth(hbar*w/(2*k*T)) times its vacuum noise, which at zero temperature is the vacuum noise itself. Raising it lowers the quantum efficiency and changes Cnoise but leaves Snoise and the commutation relations alone, since those describe the transformation rather than the state. The ports are vacuum by definition. A component may state its own temperature in the typed format (Resistor(R; temperature = T), or a ScatteringParameters with noise = ThermalEquilibrium(T)); a tuple netlist cannot, and takes this default throughout. A block which states its noise with a NoiseCovariance, as an amplifier given by its scattering parameters does, adds that covariance whatever the temperature.

  • sensitivitynames::Vector{String} = String[]: the names of the components to take sensitivities with respect to. Supported types are C, L, R and Lj with numeric values. A ScatteringParameters block has no scalar value to perturb and cannot be named; see designsensitivities for sensitivities with respect to the parameters of a block.

  • sensitivitypairs, sensitivityblockpairs, nsensitivityparameters, sensitivitylabels: the design parameter interface used by designsensitivities, which names physical parameters rather than components; each pair (componentname, parameterindex, alpha) gives the relative direction alpha = (dv/dp)/v of a component value under a parameter. Not intended to be passed directly.

  • sensitivitynodeflux = nothing: the derivatives of the pump operating point with respect to each component value, the columns of calcnodefluxsensitivity, to include the shift of the operating point in the sensitivities.

  • sensitivityresidual = nothing: the derivatives of the harmonic balance residual with respect to each component value, the columns of calcresidualsensitivity, which serve the same purpose; required by the reverse contraction order and sufficient for either. hbsolve supplies these. When neither is given the pump operating point is held fixed.

  • sensitivitymode = :auto: the order in which the operating point shift is contracted into the sensitivities. :forward costs one product against the linearized system per component and signal frequency; :reverse pushes the output functionals through the transposed pump Jacobian once per output port and mode pair, so its cost does not grow with the number of components. :auto chooses :reverse when there are more components than output port and mode pairs. Both support any number of pumps.

  • returnSsensitivity = false: return dS/dr, the derivative of the scattering matrix with respect to a relative perturbation r of each named component value (p -> r*p at r = 1), computed by the adjoint method.

  • factorization = nothing: the factorization of the linearized system matrix at each frequency: KLUfactorization, LUfactorization, CUDSSFactorization on a device, or BlockFactorization for dense node blocks (Nmodes unknowns per node, SparseBlockFactorization). nothing chooses by the number of tones and the memory (linearizedfactorization): the sparse factorization for one tone, the block factorization in double for two or more when its factors fit in half the free memory of the backend. On a device the choice also picks the solver of the batch: a sparse factorization is solved by cuDSS, a BlockFactorization by the batched block factorization. The precision of the solutions is the factorization's: BlockFactorization(precision = Float32) refines single precision factors against the double residual to double accuracy, and BlockFactorization(precision = Float32, refine = false) solves each frequency entirely in single precision, for the cases where single precision scattering parameters are enough (see BlockFactorization for the measured accuracy); the outputs are returned in double either way.

  • backend = CPU(): the KernelAbstractions backend the sweep is solved on. On a device the system matrices of a batch of signal frequencies, which share one sparsity pattern, are assembled by one kernel and factorized and solved as a uniform batch: with a sparse factorization by cuDSS (CUDSSFactorization), and with a BlockFactorization, the default from two tones, by the batched dense block factorization, whose batch is sized by the free memory of the device. The adjoint (transposed) solve, the noise scattering parameters and the sensitivities of S run on the device too. The sweep falls back to the host when the component values depend on the symbolic frequency variable (see cansweepondevice) or when sensitivities with respect to scattering block parameters are requested, whose stamps are rebuilt per frequency on the host; a scattering block whose parameters cannot be evaluated on the device forms its noise channels on the host from the whole adjoint solution copied back.

  • returnZ, returnZadjoint, returnZsensitivity, returnZsensitivityadjoint: removed; passing any of them warns. Compute impedances from the scattering parameters instead.

Returns

Examples

julia
circuit = Circuit(
    [:p1 => Port(1; Z0 = :Rleft),
     :l1 => Inductor(:Lm),
     :l2 => Inductor(:Lm),
     :k1 => MutualInductor(:K1, :l1, :l2),
     :cc => Capacitor(:Cc),
     :jj3 => JosephsonJunction(:Lj),
     :jj4 => JosephsonJunction(:Lj),
     :cj => Capacitor(:Cj),
     :gnd => Ground()],
    [[(:p1, 1), (:l1, 1), (:cc, 1)],
     [(:cc, 2), (:l2, 1), (:jj4, 1), (:cj, 1)],
     [(:l2, 2), (:jj3, 1)],
     [(:p1, 2), (:l1, 2), (:jj3, 2), (:jj4, 2), (:cj, 2), (:gnd, 1)]])
circuitdefs = Dict{Symbol,Complex{Float64}}(
    :Lj =>2000e-12,
    :Lm =>10e-12,
    :Cc => 200.0e-15,
    :Cj => 900e-15,
    :Rleft => 50.0,
    :Rright => 50.0,
    :K1 => 0.9,
)

Idc = 1e-6*0
Ip=5.0e-6
wp=2*pi*5e9
ws=2*pi*5.2e9
symfreqvar = nothing

# modulation settings
Npumpharmonics = (16,)
Nmodulationharmonics = (2,)
threewavemixing=false
fourwavemixing=true

nonlinear=hbnlsolve(
    (wp,),
    Npumpharmonics,
    [
        (mode=(0,),port=1,current=Idc),
        (mode=(1,),port=1,current=Ip),
    ],
    circuit,circuitdefs;dc=true,odd=fourwavemixing,even=threewavemixing)

linearized = JosephsonCircuits.hblinsolve(ws,
    circuit, circuitdefs; Nmodulationharmonics = Nmodulationharmonics,
    nonlinear = nonlinear, symfreqvar=nothing, threewavemixing=false,
    fourwavemixing=true, returnnodeflux=true, keyedarrays = false)
isapprox(linearized.nodeflux,
    ComplexF64[9.901008591291e-12 - 6.40587007644028e-14im 2.164688307719963e-14 - 2.90852607344097e-16im 6.671563044645655e-14 - 8.585524364135119e-16im; 2.1633104519765224e-14 - 8.251861334047893e-16im 1.0099063486905209e-11 - 1.948847859339803e-13im -8.532003011745068e-15 + 3.234788465760295e-16im; 6.671648606599472e-14 + 7.892709980649199e-16im -8.53757633177974e-15 - 9.748395563374129e-17im 9.856580758892428e-12 + 5.859984004390703e-14im; 1.5888896262186103e-11 - 1.0303480614499543e-13im -2.557126237504446e-12 + 1.759201163407723e-14im -8.475819811683215e-12 + 5.3531443609574795e-14im; -2.5781681021577177e-13 + 4.757590640631487e-15im 2.36818731889176e-12 - 4.569646499606389e-14im 1.116372367616482e-13 - 2.039935997276492e-15im; -1.0210743447568219e-11 - 5.905490368441375e-14im 1.3377918536056493e-12 + 7.190105205618706e-15im 2.5392856657302323e-11 + 1.5143842454586225e-13im; 2.4781693042536835e-11 - 1.6057018472176702e-13im -2.5342360504077476e-12 + 1.7306764301173096e-14im -8.40554044664581e-12 + 5.269404591748149e-14im; -2.348528974341763e-13 + 3.949450668269274e-15im 1.1449271118157543e-11 - 2.2093702114766968e-13im 1.0261871618968225e-13 - 1.7240213938923877e-15im; -1.0140560031409567e-11 - 5.828587508192886e-14im 1.3288225860409326e-12 + 7.0954601524623594e-15im 3.423954321087654e-11 + 2.0403371894291513e-13im],
    atol = 1e-6)

# output
true
source
JosephsonCircuits.hblinsolve Method
julia
hblinsolve(w, psc::CompiledCircuit, cg::CircuitGraph, circuitdefs,
    signalfreq::Frequencies; nonlinear = nothing, kwargs...)

The linearized sweep on an already compiled circuit psc with its graph cg, at the signal mode set signalfreq. circuitdefs may be the usual dictionary, or the vector of resolved component values nm.vvn of a CircuitMatrices already built for the circuit, which is what hbsolve passes so that the values are resolved once; the sweep w is a real number or any iterable of them (sweepfrequencies). This is what the other methods call after building those; it takes every keyword of the general method except the ones which describe the mode set (Nmodulationharmonics, threewavemixing, fourwavemixing, maxharmonics, maxintermodorder, sorting), plus the design parameter sensitivity keywords described under hbsolve (sensitivitypairs, sensitivityblockpairs, nsensitivityparameters, sensitivitylabels, which only this method accepts) and debuglsys = false, which returns the HBLinearizedSystem and its ingredients instead of solving, for building reference implementations in tests.

Examples

julia
circuit = Circuit(
    [:p1 => Port(1; Z0 = :Rleft),
     :l1 => Inductor(:Lm),
     :l2 => Inductor(:Lm),
     :k1 => MutualInductor(:K1, :l1, :l2),
     :cc => Capacitor(:Cc),
     :jj3 => JosephsonJunction(:Lj),
     :jj4 => JosephsonJunction(:Lj),
     :cj => Capacitor(:Cj),
     :gnd => Ground()],
    [[(:p1, 1), (:l1, 1), (:cc, 1)],
     [(:cc, 2), (:l2, 1), (:jj4, 1), (:cj, 1)],
     [(:l2, 2), (:jj3, 1)],
     [(:p1, 2), (:l1, 2), (:jj3, 2), (:jj4, 2), (:cj, 2), (:gnd, 1)]])
circuitdefs = Dict{Symbol,Complex{Float64}}(
    :Lj =>2000e-12,
    :Lm =>10e-12,
    :Cc => 200.0e-15,
    :Cj => 900e-15,
    :Rleft => 50.0,
    :Rright => 50.0,
    :K1 => 0.9,
)

Idc = 1e-6*0
Ip = 5.0e-6
wp = 2*pi*5e9
ws = 2*pi*5.2e9
Npumpharmonics = (2,)
Nmodulationharmonics = (2,)
threewavemixing = false
fourwavemixing = true

frequencies = JosephsonCircuits.removeconjfreqs(
    JosephsonCircuits.truncfreqs(
        JosephsonCircuits.calcfreqsrdft(Npumpharmonics),
        dc = true, odd = true, even = false, maxintermodorder = Inf,
    )
)
fi = JosephsonCircuits.fourierindices(frequencies)
Nmodes = length(frequencies.modes)
psc = JosephsonCircuits.compile(circuit)
cg = JosephsonCircuits.calccircuitgraph(psc)
nm = JosephsonCircuits.numericmatrices(psc, cg, circuitdefs, Nmodes = Nmodes)
nonlinear = hbnlsolve(
    (wp,),
    [
        (mode=(0,),port=1,current=Idc),
        (mode=(1,),port=1,current=Ip),
    ],
    frequencies, fi, psc, cg, nm)
signalfreq =JosephsonCircuits.truncfreqs(
    JosephsonCircuits.calcfreqsdft(Nmodulationharmonics),
    dc = true, odd = threewavemixing, even = fourwavemixing,
    maxintermodorder = Inf,
)
linearized = JosephsonCircuits.hblinsolve(ws, psc, cg, circuitdefs,
    signalfreq;nonlinear = nonlinear, returnnodeflux=true, keyedarrays = false)
isapprox(linearized.nodeflux,
    ComplexF64[9.901008591291e-12 - 6.40587007644028e-14im 2.164688307719963e-14 - 2.90852607344097e-16im 6.671563044645655e-14 - 8.585524364135119e-16im; 2.1633104519765224e-14 - 8.251861334047893e-16im 1.0099063486905209e-11 - 1.948847859339803e-13im -8.532003011745068e-15 + 3.234788465760295e-16im; 6.671648606599472e-14 + 7.892709980649199e-16im -8.53757633177974e-15 - 9.748395563374129e-17im 9.856580758892428e-12 + 5.859984004390703e-14im; 1.5888896262186103e-11 - 1.0303480614499543e-13im -2.557126237504446e-12 + 1.759201163407723e-14im -8.475819811683215e-12 + 5.3531443609574795e-14im; -2.5781681021577177e-13 + 4.757590640631487e-15im 2.36818731889176e-12 - 4.569646499606389e-14im 1.116372367616482e-13 - 2.039935997276492e-15im; -1.0210743447568219e-11 - 5.905490368441375e-14im 1.3377918536056493e-12 + 7.190105205618706e-15im 2.5392856657302323e-11 + 1.5143842454586225e-13im; 2.4781693042536835e-11 - 1.6057018472176702e-13im -2.5342360504077476e-12 + 1.7306764301173096e-14im -8.40554044664581e-12 + 5.269404591748149e-14im; -2.348528974341763e-13 + 3.949450668269274e-15im 1.1449271118157543e-11 - 2.2093702114766968e-13im 1.0261871618968225e-13 - 1.7240213938923877e-15im; -1.0140560031409567e-11 - 5.828587508192886e-14im 1.3288225860409326e-12 + 7.0954601524623594e-15im 3.423954321087654e-11 + 2.0403371894291513e-13im],
    atol = 1e-6)

# output
true
source
JosephsonCircuits.hblinsolve_inner! Method
julia
hblinsolve_inner!(ws::LinearizedWorkspace, arrays::LinearizedArrays,
    sensitivity, lsys, bnm, portindices, noiseportimpedanceindices,
    portimpedances, noiseportimpedances, nodeindices, componenttypes,
    w, wpumpmodes, Nmodes, Nnodes, symfreqvar, wi, factorization;
    noiseplan = nothing, channeltemperatures = nothing,
    channelsigns = nothing, presolved = nothing,
    presolvedadjoint = nothing, presolvednoise = nothing, refine = true)

Solve the linearized problem at the frequencies w[wi], using the workspace ws, assembling each system matrix from the HBLinearizedSystem lsys with assemblesystemmatrix! and writing the results into the LinearizedArrays arrays through per frequency views. An empty output array means that output was not requested; small working matrices stand in for outputs which are computed but not stored (S when only the quantum efficiency needs it).

sensitivity is a named tuple with the fixed operating point stamps, the operating point dAop stamps of the forward contraction order, and the ReverseSensitivity of the reverse order, or nothing. noiseplan, channeltemperatures and channelsigns describe the noise channels of the scattering blocks, the temperature of every channel and the sign of each in the commutation relations (see noisechannelsigns). presolved, presolvedadjoint and presolvednoise are callbacks which replace the assemble, factorize and solve of a frequency, the transposed solve, and the noise scattering calculation with solutions computed elsewhere, which is how the device sweep hands back its batches (see devicesolutions).

Different frequency ranges may be computed in parallel: lsys, sensitivity and arrays (through disjoint views) are shared, and each task has its own ws.

source
JosephsonCircuits.hbmatind Method
julia
hbmatind(truncfrequencies::Frequencies{N}; alias = false)

With alias = true a difference mode which falls outside the sampled grid is aliased back onto it by the periodicity of the discrete transform (aliasmode) rather than dropped; the linearized solver uses alias = false, which makes the assembled matrix an explicit truncation. Returns a matrix describing which indices of the frequency domain matrix (from the RFFT) to pull out and use in the harmonic balance matrix. A negative index means we take the complex conjugate of that element. A zero index means that term is not present, so skip it. The harmonic balance matrix describes the coupling between different frequency modes.

Examples

julia
julia> freq = JosephsonCircuits.calcfreqsrdft((5,));JosephsonCircuits.hbmatind(JosephsonCircuits.removeconjfreqs(JosephsonCircuits.truncfreqs(freq;dc=false,odd=true,even=false,maxintermodorder=2)))[2]
3×3 Matrix{Int64}:
 1  -3  -5
 3   1  -3
 5   3   1

julia> freq = JosephsonCircuits.calcfreqsrdft((3,));JosephsonCircuits.hbmatind(JosephsonCircuits.removeconjfreqs(JosephsonCircuits.truncfreqs(freq;dc=true,odd=true,even=true,maxintermodorder=2)))[2]
4×4 Matrix{Int64}:
 1  -2  -3  -4
 2   1  -2  -3
 3   2   1  -2
 4   3   2   1

julia> freq = JosephsonCircuits.calcfreqsrdft((2,2));JosephsonCircuits.hbmatind(JosephsonCircuits.removeconjfreqs(JosephsonCircuits.truncfreqs(freq;dc=true,odd=true,even=true,maxintermodorder=2)))[1]
7×7 Matrix{Tuple{Int64, Int64}}:
 (0, 0)   (-1, 0)  (-2, 0)   (0, -1)  (-1, -1)  (0, -2)  (-1, 1)
 (1, 0)   (0, 0)   (-1, 0)   (1, -1)  (0, -1)   (1, -2)  (0, 1)
 (2, 0)   (1, 0)   (0, 0)    (2, -1)  (1, -1)   (2, -2)  (1, 1)
 (0, 1)   (-1, 1)  (-2, 1)   (0, 0)   (-1, 0)   (0, -1)  (-1, 2)
 (1, 1)   (0, 1)   (-1, 1)   (1, 0)   (0, 0)    (1, -1)  (0, 2)
 (0, 2)   (-1, 2)  (-2, 2)   (0, 1)   (-1, 1)   (0, 0)   (-1, 3)
 (1, -1)  (0, -1)  (-1, -1)  (1, -2)  (0, -2)   (1, -3)  (0, 0)

julia> freq = JosephsonCircuits.calcfreqsrdft((2,2));JosephsonCircuits.hbmatind(JosephsonCircuits.removeconjfreqs(JosephsonCircuits.truncfreqs(freq;dc=true,odd=true,even=true,maxintermodorder=2)))[2]
7×7 Matrix{Int64}:
  1   -2   -3  13   -5  10  -14
  2    1   -2  14   13  11    4
  3    2    1  15   14  12    5
  4  -14  -15   1   -2  13  -11
  5    4  -14   2    1  14    7
  7  -11  -12   4  -14   1    0
 14   13   -5  11   10   0    1
source
JosephsonCircuits.hbmatind Method
julia
hbmatind(frequencies::Frequencies{N},
    truncfrequencies::Frequencies{N}; alias::Bool = false)

Returns a matrix describing which indices of the frequency domain matrix (from the RFFT or FFT) to pull out and use in the harmonic balance matrix. A negative index means we take the complex conjugate of that element. A zero index means that term is not present, so skip it. The harmonic balance matrix describes the coupling between different frequency modes.

Examples

julia
pumpfreq = JosephsonCircuits.truncfreqs(
    JosephsonCircuits.calcfreqsrdft((4,)))
signalfreq = JosephsonCircuits.truncfreqs(
    JosephsonCircuits.calcfreqsdft((4,));
    dc=false,odd=true,even=false,maxintermodorder=2,
)
JosephsonCircuits.hbmatind(pumpfreq, signalfreq)[2]

# output
4×4 Matrix{Int64}:
  1  -3  5   3
  3   1  0   5
 -5   0  1  -3
 -3  -5  3   1
julia
pumpfreq = JosephsonCircuits.truncfreqs(
    JosephsonCircuits.calcfreqsrdft((4,)))
signalfreq = JosephsonCircuits.truncfreqs(
    JosephsonCircuits.calcfreqsdft((4,));
    dc=false,odd=true,even=false,maxintermodorder=2,
)
JosephsonCircuits.hbmatind(pumpfreq, signalfreq;alias = true)[2]

# output
4×4 Matrix{Int64}:
  1  -3   5   3
  3   1  -4   5
 -5   4   1  -3
 -3  -5   3   1
source
JosephsonCircuits.hbnlsolve Method
julia
hbnlsolve(w::NTuple{N,Float64}, Nharmonics::NTuple{N,Int},
    sources::Vector{SourceTuple{N}}, psc::CompiledCircuit,
    cg::CircuitGraph, circuitdefs::Dict{Any,Any}; kwargs...)

The general method on a compiled circuit psc with its graph cg, with the inputs in their canonical forms (tonefrequencies, sourcetable, definitiontable): it builds the mode set and the matrices at its mode count, then solves. It takes every keyword of the general method except sorting, which the compilation consumed.

source
JosephsonCircuits.hbnlsolve Method
julia
hbnlsolve(w::NTuple{N,Number}, sources, frequencies::Frequencies{N},
    indices::FourierIndices{N}, psc::CompiledCircuit, cg::CircuitGraph,
    nm::CircuitMatrices; kwargs...)

The nonlinear harmonic balance solve on an already compiled circuit psc with its graph cg and matrices nm, at the mode set frequencies with its Fourier indices indices. This is what the other methods call after building those, with the inputs in their canonical forms (tonefrequencies, sourcetable); it takes every keyword of the general method except the ones which describe the mode set (Nharmonics, Nevaluationharmonics, maxintermodorder, frequencywindow, dc, odd, even, sorting), and it does not accept method = Staged(), whose continuation builds each stage's own system. It takes one keyword the general method does not: reuse = nothing, an HBReuse which a NewtonKrylov solve fills and every later solve of the same topology, mode grid, precision and backend rebinds (a mismatch is an ArgumentError); the other methods ignore it.

Examples

julia
circuit = Circuit(
    [:p1 => Port(1; Z0 = :Rleft),
     :l1 => Inductor(:Lm),
     :l2 => Inductor(:Lm),
     :k1 => MutualInductor(:K1, :l1, :l2),
     :cc => Capacitor(:Cc),
     :jj3 => JosephsonJunction(:Lj),
     :jj4 => JosephsonJunction(:Lj),
     :cj => Capacitor(:Cj),
     :gnd => Ground()],
    [[(:p1, 1), (:l1, 1), (:cc, 1)],
     [(:cc, 2), (:l2, 1), (:jj4, 1), (:cj, 1)],
     [(:l2, 2), (:jj3, 1)],
     [(:p1, 2), (:l1, 2), (:jj3, 2), (:jj4, 2), (:cj, 2), (:gnd, 1)]])
circuitdefs = Dict{Symbol,Complex{Float64}}(
    :Lj =>2000e-12,
    :Lm =>10e-12,
    :Cc => 200.0e-15,
    :Cj => 900e-15,
    :Rleft => 50.0,
    :Rright => 50.0,
    :K1 => 0.9,
)

Idc = 50e-5
Ip=0.0001e-6
wp=2*pi*5e9
Nharmonics = (2,)
frequencies = JosephsonCircuits.removeconjfreqs(
    JosephsonCircuits.truncfreqs(
        JosephsonCircuits.calcfreqsrdft(Nharmonics),
        dc=true, odd=true, even=false, maxintermodorder=Inf,
    )
)
fi = JosephsonCircuits.fourierindices(frequencies)
Nmodes = length(frequencies.modes)
psc = JosephsonCircuits.compile(circuit)
cg = JosephsonCircuits.calccircuitgraph(psc)
nm = JosephsonCircuits.numericmatrices(psc, cg, circuitdefs, Nmodes = Nmodes)

out=hbnlsolve(
    (wp,),
    [
        (mode=(0,),port=1,current=Idc),
        (mode=(1,),port=1,current=Ip),
    ],
    frequencies, fi, psc, cg, nm)
isapprox(out.nodeflux[:],
    ComplexF64[15.190314040027383 + 0.0im, 3.029519334903722e-6 - 1.8979297727605957e-8im, 6.835392148518834 + 0.0im, -2.394037089373057e-6 + 1.4998135927423454e-8im, -6.835392148531882 + 0.0im, -5.116466289829032e-6 + 3.2053578928830107e-8im],
    atol = 1e-6)

# output
true

See the general hbnlsolve docstring for the formulation and the keywords.

source
JosephsonCircuits.hbnlsolve Method
julia
hbnlsolve(w::NTuple{N,Number}, Nharmonics::NTuple{N,Int}, sources,
    circuit, circuitdefs; iterations = 1000,
    Nevaluationharmonics = map(i -> 2i, Nharmonics),
    maxintermodorder = Inf, dc = false, odd = true, even = false,
    atol = 1e-8, rtol = 0.0, method = NewtonKrylov(), x0 = nothing,
    symfreqvar = nothing, sorting = :number, keyedarrays = true,
    sensitivitynames = String[], returnoperatingpoint = false,
    frequencywindow = (0, Inf), backend = CPU(), debugJacobian = false,
    returnsystem = false, assemblejacobian = true,
    warnnotconverged = true)

Solve the nonlinear harmonic balance problem of a circuit driven by any number of strong tones (pumps) at any number of ports, including direct current biases and flux pumping through a current source and a mutual inductor. hblinsolve linearizes the circuit about the operating point found here; hbsolve runs the two in sequence.

The system is solved in a modified nodal analysis (MNA) formulation in the node flux basis: resistors with constant real values (including complex storage with zero imaginary part) and mutually coupled inductor branches are assigned auxiliary branch current variables with their constitutive relations kept as explicit equations, which is algebraically equivalent to the nodal formulation wherever the latter is well posed. Promoting the coupled inductors keeps the system matrix entries bounded as the coupling coefficient approaches one, where the nodal inverse inductance entries diverge as 1/(1-k^2). The system is nondimensionalized by the solver inductance scale Z0/w0 (see calcsolverscale), the geometric mean port impedance over the geometric mean nonzero drive frequency, so the residual tolerance atol is independent of the unit system and the auxiliary variables have magnitudes comparable to the node fluxes. One gauge fixing equation per floating inductive or Josephson subnetwork and zero frequency mode makes circuits which are singular at direct current in a purely nodal formulation (nodes or subnetworks with no inductive path to ground) solvable without workaround inductors; if the net direct current injected into such a subnetwork is nonzero no periodic solution exists and an ArgumentError is thrown. The reported residual norms are those of the augmented system, and the returned structure contains only the node fluxes and the original incidence matrix. Commensurate drive frequencies whose retained intermodulation products reach (numerically) zero frequency are rejected with an ArgumentError. See src/circuit/mna.jl.

Arguments

  • w::NTuple{N,Number}: a tuple containing the angular frequencies of the strong tones (or pumps) such as (2pi5.0e9,) for a single tone at 5 GHz and (2pi5.0e9,2pi6.0e9) for a tone at 5 GHz and a tone at 6 GHz. The frequencies should be non-commensurate. For commensurate frequencies, the lowest frequency should be provided here, and the other added to sources with a mode index equal to the ratio.

  • Nharmonics::NTuple{N,Int}: the largest absolute harmonic index of each tone retained as an unknown, so the modes of the returned solution. The length of the tuple must equal the number of non-commensurate tones. The nonlinearity is evaluated on the larger Nevaluationharmonics grid.

  • sources: the sources, as named tuples with the fields mode, port and current: mode is a tuple of one harmonic index per tone, port is the integer port number and current the (complex) current amplitude. Any iterable of them is accepted and converted to the canonical SourceTuple form by sourcetable. For example: [(mode=(1,0),port=1,current=Ip1),(mode=(0,1),port=1,current=Ip2)] specifies two pumps where the frequency of the first pump would be 1wp1 + 0wp2 and the second 0wp1+1wp2 where wp1 is the first pump frequency and wp2 is the second pump frequency. Both of the pumps are applied to port 1 with currents Ip1 and Ip2, respectively.

  • circuit: a typed Circuit, a legacy netlist of (name, node1, node2, value) tuples, or a CompiledCircuit.

  • circuitdefs: a dictionary from the symbols or symbolic variables used as component values to their numerical values. Optional when every component value is numeric.

Keywords

  • iterations = 1000: the maximum number of nonlinear solver iterations before it returns unconverged.

  • Nevaluationharmonics = map(i -> 2i, Nharmonics): the harmonics of each tone on the grid where the nonlinearity is sampled, at least Nharmonics. The nonlinear products of the retained modes reach higher orders, and a grid with M harmonics folds order p back to p - (2M + 1) (aliasing). Products of two retained modes reach twice Nharmonics and fold outside the retained set once the grid is half again as large, the three halves rule, but the leading nonlinearity of a junction is cubic, and products of three retained modes reach three times Nharmonics, which the three halves grid folds onto the tone itself. Twice the retained set is the default: it dealiases the cubic products and leaves the fifth order ones, whose folded contributions land outside the retained set. Only the transforms grow, the unknowns are the same. Measured against a grid four times the retained set on a 64-junction line with three tones retaining (6,4,4): the unpadded grid is off by 1.5e-4 of the strongest mode in the modes of order four and 1.5e-6 in the tones, three halves by 1.8e-7 and 4e-11, twice by 2.7e-11 and 4.5e-15, at the same solve time and GMRES step count, which the padding took from 196 to 16.

  • maxharmonics: deprecated and ignored with a warning; Nharmonics is the retained set and Nevaluationharmonics the sampling grid.

  • frequencywindow = (0, Inf): a lower and upper bound, in the units of w, on the absolute frequency abs(dot(w, mode)) of the retained modes, a truncation by frequency beside the truncations by order; the zero frequency mode follows dc. See truncfreqs for why a floor matters on incommensurate tones.

  • maxintermodorder = Inf: keep only the modes whose harmonic indices have an absolute sum of at most this order, a diamond truncation of the multi-tone Fourier space.

  • dc = false: retain the zero frequency mode. A CurrentSource component of the netlist is a constant current, out of its first terminal and into its second, which drives this mode; a nonzero one without the mode is an error.

  • odd = true: retain the odd harmonics, which four wave mixing couples through.

  • even = false: retain the even harmonics, which three wave mixing couples through.

  • atol = 1e-8: the residual tolerance norm(F) <= atol at which the nonlinear solution is considered converged. F is scaled by Z0/w0; see calcsolverscale. A tolerance below the rounding error of the scaled source, which a circuit whose interior is far from its port impedances can reach, is raised to it: no iteration resolves a residual below the rounding of the terms which make it.

  • method = NewtonKrylov(): the nonlinear solver, an AbstractHBNonlinearSolver carrying its own options: NewtonKrylov (the matrix-free real Jacobian with a preconditioner, the default), Newton (the assembled real Jacobian), QuasiNewton (the complex holomorphic Jacobian, an approximation, with Anderson acceleration), Staged (source continuation on an adaptively grown harmonic grid, see stagedhbnlsolve, the strategy for operating points the direct methods fail outright and the one that distinguishes a hard operating point from a nonexistent one) or ExternalSolver.

  • rtol = 0.0: a relative residual tolerance; the solve is converged when norm(F) <= max(atol, rtol*norm(F0)) with F0 the initial residual.

  • x0 = nothing: an initial value for the node fluxes, either of the node flux length or of the full augmented length including the auxiliary variables of the modified nodal analysis formulation. x0, rtol, debugJacobian, returnsystem and assemblejacobian apply to the direct and Krylov methods; a Staged method builds and warm starts its own stages and ignores them.

  • keyedarrays = true: return nodeflux and S as keyed arrays with named axes rather than plain arrays.

  • sensitivitynames::Vector{String} = String[]: the components whose indices are recorded for the sensitivity calculation.

  • returnoperatingpoint = false: assemble and return the exact real Jacobian at the converged solution in the operatingpoint field, for sensitivities which include the shift of the operating point.

  • backend = CPU(): the KernelAbstractions backend the solve runs on.

  • debugJacobian = false: instead of solving, return a named tuple with the residual and Jacobian functions and the ingredients they are assembled from, for building reference implementations in tests.

  • returnsystem = false: instead of solving, return a named tuple with the HBSystem, the initial real state and residual, the real representation layout and (when assemblejacobian = true) the assembled real Jacobian, for driving an external solver.

  • assemblejacobian = true: assemble the real Jacobian for returnsystem and for an ExternalSolver; false skips the assembly when the external solver is matrix free.

  • switchofflinesearchtol, alphamin: deprecated and ignored with a warning.

A solve which does not converge returns the last iterate with solverinfo.converged = false and warns with the reason it stopped, which is also the reason of its IterationInfo (:iterations, :work, :linesearch, :progress or :external; stallmessage spells each out). Check solverinfo.converged before using the result.

  • symfreqvar = nothing: the symbolic frequency variable, such as w, when component values are expressions in the frequency.

  • sorting = :number: how the nodes are ordered, with ground always first. :number parses the node names as integers and sorts numerically (an error if a name is not an integer); :name sorts the names as strings, so that "101" comes before "11"; :none keeps the order of first appearance. The methods taking a typed Circuit default to :name, since hierarchical net names are not integers.

  • warnnotconverged = true: warn when the solve does not converge. A continuation whose stage solves are expected to fail passes false and reports its own outcome.

Returns

  • NonlinearHB: A simple structure to hold the harmonic balance solutions. See NonlinearHB.

Examples

julia
circuit = Circuit(
    [:p1 => Port(1; Z0 = :Rleft),
     :l1 => Inductor(:Lm),
     :l2 => Inductor(:Lm),
     :k1 => MutualInductor(:K1, :l1, :l2),
     :cc => Capacitor(:Cc),
     :jj3 => JosephsonJunction(:Lj),
     :jj4 => JosephsonJunction(:Lj),
     :cj => Capacitor(:Cj),
     :gnd => Ground()],
    [[(:p1, 1), (:l1, 1), (:cc, 1)],
     [(:cc, 2), (:l2, 1), (:jj4, 1), (:cj, 1)],
     [(:l2, 2), (:jj3, 1)],
     [(:p1, 2), (:l1, 2), (:jj3, 2), (:jj4, 2), (:cj, 2), (:gnd, 1)]])
circuitdefs = Dict{Symbol,Complex{Float64}}(
    :Lj =>2000e-12,
    :Lm =>10e-12,
    :Cc => 200.0e-15,
    :Cj => 900e-15,
    :Rleft => 50.0,
    :Rright => 50.0,
    :K1 => 0.9,
)

Idc = 50e-5
Ip=0.0001e-6
wp=2*pi*5e9
Npumpmodes = 2
out=hbnlsolve(
    (wp,),
    (Npumpmodes,),
    [
        (mode=(0,),port=1,current=Idc),
        (mode=(1,),port=1,current=Ip),
    ],
    circuit,circuitdefs;dc=true,odd=true,even=false)
isapprox(out.nodeflux[:],
    ComplexF64[15.190314040027383 + 0.0im, 3.029519334903722e-6 - 1.8979297727605957e-8im, 6.835392148518834 + 0.0im, -2.394037089373057e-6 + 1.4998135927423454e-8im, -6.835392148531882 + 0.0im, -5.116466289829032e-6 + 3.2053578928830107e-8im],
    atol = 1e-6)

# output
true
source
JosephsonCircuits.hbnlsolve Method
julia
hbnlsolve(w, Nharmonics, sources, circuit::Circuit,
    circuitdefs = Dict{Symbol,Number}(); sorting = :name, kwargs...)

The nonlinear solve of a typed Circuit, with every keyword of the general method. circuitdefs is needed only when component values are symbolic, and sorting defaults to :name because hierarchical net names are not integers.

source
JosephsonCircuits.hbnonlinearproblem Method
julia
hbnonlinearproblem(w, Nharmonics, sources, circuit, circuitdefs;
    assemblejacobian = true, kwargs...)

Build the harmonic balance system as an HBNonlinearProblem without solving it, by calling hbnlsolve with returnsystem = true and the remaining keywords. assemblejacobian = false leaves out the assembled real Jacobian, which a matrix-free solver does not need.

source
JosephsonCircuits.hbresidual! Method
julia
hbresidual!(F, prob::HBNonlinearProblem, u)

The harmonic balance residual at u, in place.

source
JosephsonCircuits.hbsolve! Method
julia
hbsolve!(cache::HBCache, p::NamedTuple; warmstart = true)

Solve the nonlinear harmonic balance problem of cache at the design parameters p, warm starting from the previously converged operating point. Returns the NonlinearHB solution; cache.converged reports whether it converged.

The parse, the graph and the mode grid are reused, and so are the system, the preconditioner and the Krylov vectors of the previous solve, rebound to the new component values (see HBReuse); only the numeric matrices and the solve itself are recomputed. If the previous solve did not converge its state is not used, because starting from a non-solution is usually worse than starting cold; warmstart = false starts cold without discarding the stored point, unlike reset!. A component value which crosses a structural boundary (an inductance open or shorted, a value turned complex, a mutual coupling reaching one) invalidates the cached sparsity patterns and is an ArgumentError; build a new cache for those parameters.

source
JosephsonCircuits.hbsolve Method
julia
hbsolve(ws, wp::NTuple{N,Number}, sources::Vector,
    Nmodulationharmonics::NTuple{M,Int}, Npumpharmonics::NTuple{N,Int},
    circuit, circuitdefs; dc = false, threewavemixing = false,
    fourwavemixing = true, maxpumpintermodorder = Inf,
    maxmodulationintermodorder = Inf,
    Nevaluationharmonics = map(i -> 2i, Npumpharmonics),
    frequencywindow = (0, Inf),
    maxmodulationharmonics = Nmodulationharmonics,
    iterations = 1000, atol = 1e-8, method = NewtonKrylov(),
    x0 = nothing,
    symfreqvar = nothing, nbatches = Base.Threads.nthreads(),
    sorting = :number, returnS = true, returnSnoise = false,
    returnQE = true, returnCM = true, returnnodeflux = false,
    returnvoltage = false, returnnodefluxadjoint = false,
    returnvoltageadjoint = false, keyedarrays = true,
    temperature = 0.0, returnCnoise = false,
    sensitivitynames::Vector{String} = String[],
    sensitivityoperatingpoint = true, sensitivitymode = :auto,
    returnSsensitivity = false, factorization = nothing,
    backend = CPU())

Solve a circuit driven by one or more strong pumps, then linearize about that operating point and sweep the weak signal frequencies ws. This calls hbnlsolve for the pump and hblinsolve for the signals and returns both solutions in an HB. Any number of pumps, ports and modes is supported, for three and four wave mixing.

The system is solved in a modified nodal analysis formulation in the node flux basis. Resistors with constant real values and mutually coupled inductor branches are given auxiliary branch current variables, which keeps the system matrix bounded as a coupling coefficient approaches one, and one gauge fixing equation per floating inductive or Josephson subnetwork and zero frequency mode makes circuits with no inductive path to ground solvable without workaround inductors (see src/circuit/mna.jl). The nonlinear system is nondimensionalized by the scale Z0/w0 (see calcsolverscale), so atol does not depend on the unit system. The returned node fluxes and voltages contain only the node coordinates, not the auxiliary variables. The linearized solve throws an ArgumentError when any signal plus pump mode frequency is numerically zero; estimate a direct current limit from a sequence of decreasing nonzero frequencies instead.

Arguments

  • ws: the signal angular frequency or frequencies in radians per second, such as 2*pi*5.0e9 or 2*pi*(4.5:0.001:5.0)*1e9; a real number or any iterable of them.

  • wp::NTuple{N,Number}: the pump angular frequencies in radians per second, (2*pi*5.0e9,) for a single pump or (2*pi*5.0e9, 2*pi*6.0e9) for two, as real numbers. The pumps should be non-commensurate; for commensurate pumps give the lowest frequency here and add the others to sources with a mode index equal to the frequency ratio.

  • sources: the sources, as named tuples (mode, port, current) in any iterable. mode is a tuple of harmonic indices, one per pump frequency, port the port number, and current the complex current amplitude in Amperes; see sourcetable for the checks. [(mode=(1,0), port=1, current=Ip1), (mode=(0,1), port=1, current=Ip2)] applies a source at 1*wp[1] + 0*wp[2] and one at 0*wp[1] + 1*wp[2], both at port 1. A source with mode = (0,) and dc = true is a direct current bias.

  • Nmodulationharmonics::NTuple{M,Int}: how many harmonics of each pump to retain around the signal in the linearized solve, which sets the signal and idler modes.

  • Npumpharmonics::NTuple{N,Int}: how many harmonics of each pump to retain as unknowns in the nonlinear solve. Its length is the number of non-commensurate pumps. The nonlinearity is evaluated on the larger Nevaluationharmonics grid.

  • circuit: a typed Circuit, a legacy netlist of (name, node1, node2, value) tuples, or a CompiledCircuit.

  • circuitdefs: a dictionary from the symbols or symbolic variables used as component values to their numerical values. Optional when every component value is numeric.

Keywords

  • dc = false: retain the zero frequency mode in the nonlinear solve. A CurrentSource component of the netlist is a constant current, out of its first terminal and into its second, which drives this mode; a nonzero one without the mode is an error.

  • threewavemixing = false: retain the even pump harmonics, which are what three wave mixing processes couple through.

  • fourwavemixing = true: retain the odd pump harmonics.

  • maxpumpintermodorder = Inf: keep only the pump modes whose harmonic indices have an absolute sum of at most this order, a diamond truncation of the multi-pump Fourier space.

  • maxmodulationintermodorder = Inf: the same truncation for the signal modes.

  • Nevaluationharmonics = map(i -> 2i, Npumpharmonics): the harmonics of each pump on the grid where the nonlinearity is sampled, at least Npumpharmonics; twice the retained set by default, which dealiases the products of order three, the leading ones of a junction. See hbnlsolve.

  • maxpumpharmonics: deprecated and ignored with a warning; Npumpharmonics is the retained set and Nevaluationharmonics the sampling grid.

  • maxmodulationharmonics = Nmodulationharmonics: an upper bound on the absolute harmonic index retained for each pump in the signal modes, applied together with the intermodulation truncation; see truncfreqs.

  • frequencywindow = (0, Inf): a lower and upper bound, in the units of wp, on the absolute frequency of the retained pump modes; see hbnlsolve. The signal modes are not windowed. The signal modes are not windowed.

  • iterations = 1000: the maximum number of nonlinear solver iterations before it returns unconverged.

  • atol = 1e-8: the residual tolerance norm(F) <= atol at which the nonlinear solution is considered converged. F is scaled by Z0/w0; see calcsolverscale. A tolerance below the rounding error of the scaled source, which a circuit whose interior is far from its port impedances can reach, is raised to it: no iteration resolves a residual below the rounding of the terms which make it.

  • method = NewtonKrylov(): the nonlinear solver, an AbstractHBNonlinearSolver carrying its own options: NewtonKrylov (the matrix-free real Jacobian with a preconditioner, the default), Newton (the assembled real Jacobian), QuasiNewton (the complex holomorphic Jacobian, an approximation, with Anderson acceleration), Staged (source continuation on an adaptively grown harmonic grid, see stagedhbnlsolve, the strategy for operating points the direct methods fail outright and the one that distinguishes a hard operating point from a nonexistent one) or ExternalSolver.

  • x0 = nothing: an initial value for the node fluxes of the nonlinear solve, used by the direct and Krylov methods; a Staged method builds its own warm starts and ignores it.

  • symfreqvar = nothing: the symbolic frequency variable, such as w, when component values are expressions in the frequency.

  • nbatches = Base.Threads.nthreads(): the number of batches the signal frequencies are split into for multithreading; 1 runs single threaded.

  • sorting = :number: how the nodes are ordered, with ground always first. :number parses the node names as integers and sorts numerically (an error if a name is not an integer); :name sorts the names as strings, so that "101" comes before "11"; :none keeps the order of first appearance. The methods taking a typed Circuit default to :name, since hierarchical net names are not integers.

  • returnS = true: return the scattering parameters of the linearized solve.

  • returnSnoise = false: return the noise scattering parameters.

  • returnCnoise = false: return the added noise covariance at the output ports; see LinearizedHB.

  • returnQE = true: return the quantum efficiency.

  • returnCM = true: return the commutation relations.

  • returnnodeflux = false, returnvoltage = false: return the node fluxes and voltages of the linearized solve.

  • returnnodefluxadjoint = false, returnvoltageadjoint = false: return the node fluxes and voltages of the adjoint (time reversed modulation) linearized solve.

  • keyedarrays = true: return the outputs as keyed arrays with named, labeled axes rather than plain arrays.

  • temperature = 0.0: the physical temperature in Kelvin of every dissipative element which does not state its own, and so of the noise it adds. A channel at temperature T carries coth(hbar*w/(2*k*T)) times its vacuum noise, which at zero temperature is the vacuum noise itself. Raising it lowers the quantum efficiency and changes Cnoise but leaves Snoise and the commutation relations alone, since those describe the transformation rather than the state. The ports are vacuum by definition. A component may state its own temperature in the typed format (Resistor(R; temperature = T), or a ScatteringParameters with noise = ThermalEquilibrium(T)); a tuple netlist cannot, and takes this default throughout. A block which states its noise with a NoiseCovariance, as an amplifier given by its scattering parameters does, adds that covariance whatever the temperature.

  • sensitivitynames::Vector{String} = String[]: the names of the components to take sensitivities with respect to. Supported types are C, L, R and Lj with numeric values. A ScatteringParameters block has no scalar value to perturb and cannot be named; see designsensitivities for sensitivities with respect to the parameters of a block.

  • sensitivitypairs, sensitivityblockpairs, nsensitivityparameters, sensitivitylabels: the design parameter interface used by designsensitivities, which names physical parameters rather than components; each pair (componentname, parameterindex, alpha) gives the relative direction alpha = (dv/dp)/v of a component value under a parameter. Not intended to be passed directly.

  • sensitivitymode = :auto: the order in which the operating point shift is contracted into the sensitivities. :forward costs one product against the linearized system per component and signal frequency; :reverse pushes the output functionals through the transposed pump Jacobian once per output port and mode pair, so its cost does not grow with the number of components. :auto chooses :reverse when there are more components than output port and mode pairs. Both support any number of pumps.

  • sensitivityoperatingpoint = true: include the shift of the pump operating point in the sensitivities, making them total derivatives rather than derivatives at a fixed operating point. Near the gain peak of a strongly pumped amplifier the operating point term is comparable to or larger than the fixed point term. Requires the exact real Jacobian of the nonlinear solution, which is assembled and factorized once. Without Josephson junctions the operating point contribution is identically zero and is skipped.

  • returnSsensitivity = false: return dS/dr, the derivative of the scattering matrix with respect to a relative perturbation r of each named component value (p -> r*p at r = 1), computed by the adjoint method.

  • factorization = nothing: the factorization of the linearized solve at each signal frequency. nothing chooses by the number of tones and the memory, by the same kind of rule Automatic applies to the nonlinear solve (but in double precision, and counting one system per host batch): the backend's sparse factorization (KLUfactorization on the host, CUDSSFactorization on a device) for one tone, and BlockFactorization, the dense node blocks of the multi-tone system with BLAS-3 arithmetic, for two or more tones when its factors fit in half the free memory (linearizedfactorization). Any of them can be given explicitly; on a device the choice also picks the solver of the batch, cuDSS for a sparse factorization and the batched block factorization for a BlockFactorization. The nonlinear solve's factorization is an option of its method. The precision of the linearized solutions is the factorization's: BlockFactorization(precision = Float32, refine = false) solves each signal frequency entirely in single precision (see BlockFactorization). The nonlinear solve's precision is NewtonKrylov(precision = ...).

  • backend = CPU(): the KernelAbstractions backend both solves run on. The nonlinear solve assembles, factorizes and iterates there; the linearized sweep solves batches of signal frequencies there and falls back to the host for what it cannot serve (see hblinsolve).

  • switchofflinesearchtol, alphamin: deprecated and ignored with a warning.

  • returnZ, returnZadjoint, returnZsensitivity, returnZsensitivityadjoint: removed; passing any of them warns. Compute impedances from the scattering parameters instead.

Returns

  • HB: the nonlinear and linearized solutions; see HB.
source
JosephsonCircuits.hbsolve Method
julia
hbsolve(ws, wp, sources, Nmodulationharmonics, Npumpharmonics,
    circuit::Circuit, circuitdefs = Dict{Symbol,Number}();
    sorting = :name, kwargs...)

Solve a typed Circuit. The circuit is elaborated and lowered with compile and every keyword of the general method applies. circuitdefs is needed only when component values are symbolic. The default sorting is :name because hierarchical net names are not integers.

source
JosephsonCircuits.hbsolve Method
julia
hbsolve(ws::Vector{Float64}, wp::NTuple{N,Float64},
    sources::Vector{SourceTuple{N}}, Nmodulationharmonics::NTuple{M,Int},
    Npumpharmonics::NTuple{N,Int}, psc::CompiledCircuit,
    cg::CircuitGraph, circuitdefs::Dict{Any,Any}; kwargs...)

The general method on a compiled circuit psc with its graph cg, with the inputs in their canonical forms (sweepfrequencies, tonefrequencies, sourcetable, definitiontable). It takes every keyword of the general method except sorting, which the compilation consumed.

source
JosephsonCircuits.hbvjp! Method
julia
hbvjp!(out, prob, u, w)

The transposed product transpose(J(u))*w, matrix free.

Needed by BifurcationKit for minimally augmented codim-2 continuation, fold and Hopf continuation and left eigenvectors, and accepted by NonlinearSolve as vjp.

The adjoints of the two transforms compose so that the normalizations cancel, leaving the conjugate multiplicity divided out in one kernel and multiplied back in through the coefficients of the other; see NonlinearTermTransposePlan.

source
JosephsonCircuits.hessianvectorproduct! Method
julia
hessianvectorproduct!(Hvw::AbstractVector, sys::HBSystem,
    v::AbstractVector, w::AbstractVector)

Evaluate the exact matrix-free second directional derivative of the harmonic balance nonlinear system, H(x)[v, w] = B(-sin.(A*x) .* (A*v) .* (A*w)), at the point set with setpoint!, in place. The frequency dependent linear terms are linear in x so they do not contribute. Dispatches on the element types: complex vectors receive the complex representation and real vectors the equivalent real representation. The product is symmetric in v and w. Useful for continuation and bifurcation tracking methods which require directional second derivatives.

source
JosephsonCircuits.hinfnorm Method
julia
hinfnorm(A, B, C, D; rtol = 1e-8, span = 8.0, refinements = 32,
    pad = 10.0)

The largest singular value of the real rational matrix S(s) = D + C (s I - A)^(-1) B over every frequency, by the level set iteration of Boyd, Balakrishnan, Bruinsma and Steinbuch: a lower bound from the feedthrough, samples spanning the poles' frequencies, and a peak search around each pole is raised by a hair to a level, the frequencies where a singular value equals the level are the imaginary eigenvalues of the pencil of passivitycrossings for S over the level, and the largest singular value between consecutive ones raises the bound, until no singular value reaches the level. A peak however narrow is found, since the pencil finds every crossing of the level, which a sample can miss.

Returns three values: a lower bound on the norm, the frequency in rad/s where it was attained, and the level the search established nothing reaches, Inf where termination established no such level. The first value is only the largest value the search evaluated; what termination proves is the third. They differ by 2 rtol, which matters wherever the answer is compared against one: at the default tolerance a norm returned as 1 - 1e-9 is consistent with a true norm of 1 + 1e-8, so calling a block passive on the first value is calling it passive on a lower bound.

rtol is not worth pushing far below its default. The level is a bound only so far as the pencil resolves the crossings of it, and a peak which exceeds a level by less than roundoff brings its two crossings together into a nearly double eigenvalue which leaves the imaginary axis and is lost: a tolerance below the square root of eps asks the pencil for a resolution it does not have, and returns a level which is not a bound.

span is how many pole half widths the peak search brackets either side of each complex pole, refinements how many golden section steps refine each bracket, and pad how far past the outermost pole magnitudes the probe grid extends.

source
JosephsonCircuits.hostrelations Method
julia
hostrelations(r::JunctionRelations)
hostrelations(r::JunctionRelations, rows::AbstractVector{Int})

The table on the host, for the host loops which cannot read a device array, and with rows the table of that subset of the junctions, in that order, which is what a projection onto part of the circuit reads.

source
JosephsonCircuits.hostsparse Method
julia
hostsparse(A::DeviceValuedSparseMatrix)
hostsparse(A::SparseMatrixCSC)

Bring a matrix whose values live on a backend home as an ordinary SparseMatrixCSC, copying both the structure and the values. A host matrix is returned unchanged.

The structure is held as the transpose (see DeviceValuedSparseMatrix), so this is a copy back followed by a sparse transpose rather than a reinterpretation. Both are proportional to the number of stored entries of the one matrix, which is why this is worth doing for something retained once, such as the real Jacobian of a pump operating point, and not for something produced per signal frequency, such as a solution of the linearized system.

source
JosephsonCircuits.impedance Method
julia
impedance(c, code::Integer, w)

The impedance of a component of value c and type code at frequency w, conjugating the stored value at a negative frequency.

The numeric implementation, called by the numeric method of calcimpedance on the host and directly from the kernels which compute power waves on a backend.

source
JosephsonCircuits.impedancecode Method
julia
impedancecode(type)

The impedance code of a component type, or an error for a type which has no impedance.

source
JosephsonCircuits.import_netlist! Method
julia
import_netlist!(io::IO, circuit)

Import the netlist from the IOBuffer or IOStream io to the vector of tuples circuit.

Examples

julia
julia> io = IOBuffer();circuit1=[("P","1","0",1),("R","1","0",50.0)];JosephsonCircuits.export_netlist!(io,circuit1,Dict());circuit2 = Tuple{String,String,String,Any}[];JosephsonCircuits.import_netlist!(io,circuit2);circuit2
2-element Vector{Tuple{String, String, String, Any}}:
 ("P", "1", "0", 1.0)
 ("R", "1", "0", 50.0)
source
JosephsonCircuits.import_netlist Method
julia
import_netlist(filename)

Import the netlist from the file with name and path filename and return it as a vector of (name, node1, node2, value) tuples. The value field is Any: a number for a literal and a CircuitValue for an expression.

source
JosephsonCircuits.indefinite_hermitian_form_block Method
julia
indefinite_hermitian_form_block(n::Int)

Return the 2n x 2n matrix representing the indefinite Hermitian form Σ for n modes in the annihilation and creation operator basis with block order ξ = [a_1,...,a_n,adag_1,...,adag_n] where Σ = [1_n 0_n;0_n -1_n]. 0_n is an n by n matrix of zeros and 1_n is an n by n identity matrix.

Examples

jldoctest


<Badge type="info" class="source-link" text="source"><a href="https://github.com/kpobrien/JosephsonCircuits.jl/blob/b8bbb27d919228ee63b3cc7350f709b9275d83a9/src/networks/quantumoptics.jl#L93-L109" target="_blank" rel="noreferrer">source</a></Badge>

</details>

<details class='jldocstring custom-block' open>
<summary><a id='JosephsonCircuits.indefinite_hermitian_form_pair-Tuple{Integer}' href='#JosephsonCircuits.indefinite_hermitian_form_pair-Tuple{Integer}'><span class="jlbinding">JosephsonCircuits.indefinite_hermitian_form_pair</span></a> <Badge type="info" class="jlObjectType jlMethod" text="Method" /></summary>



```julia
indefinite_hermitian_form_pair(n)

Return the 2n x 2n matrix representing the indefinite Hermitian form Σ for n modes in the annihilation and creation operator basis with pair order ξ = [a_1,adag_1,...,a_n,adag_n] where Σ = direct sum of n of σ3 where σ3 = [1 0; 0 -1].

Examples

jldoctest


<Badge type="info" class="source-link" text="source"><a href="https://github.com/kpobrien/JosephsonCircuits.jl/blob/b8bbb27d919228ee63b3cc7350f709b9275d83a9/src/networks/quantumoptics.jl#L71-L87" target="_blank" rel="noreferrer">source</a></Badge>

</details>

<details class='jldocstring custom-block' open>
<summary><a id='JosephsonCircuits.initialguess-Tuple{Nothing}' href='#JosephsonCircuits.initialguess-Tuple{Nothing}'><span class="jlbinding">JosephsonCircuits.initialguess</span></a> <Badge type="info" class="jlObjectType jlMethod" text="Method" /></summary>



```julia
initialguess(x0)

The initial guess x0 of a nonlinear solve as a Vector{ComplexF64}, empty when there is none (nothing); a node flux matrix of a previous solve, keyed or plain, is flattened in the solver's own layout.

source
JosephsonCircuits.innerpreconditioner Function
julia
innerpreconditioner(pc::AbstractWrappedPreconditioner)

The preconditioner pc wraps.

source
JosephsonCircuits.instancedefinition Method
julia
instancedefinition(elab::ElaboratedCircuit, i::Integer)

The component definition of flattened instance i.

source
JosephsonCircuits.instanceterminals Method
julia
instanceterminals(elab::ElaboratedCircuit, i::Integer)

A view of the net indices of the terminals of flattened instance i.

source
JosephsonCircuits.interconnectS! Method
julia
interconnectS!(Sout, Cout, Sa, Sb, Ca, Cb, k, l;
    nbatches = Base.Threads.nthreads())

In place version of interconnectS with noise covariances, writing into Sout and Cout.

source
JosephsonCircuits.interconnectS! Method
julia
interconnectS!(Sout, Sa, Sb, k, l; nbatches = Base.Threads.nthreads())

In place version of interconnectS, writing into Sout.

source
JosephsonCircuits.interconnectS Method
julia
interconnectS(Sa::AbstractArray, Sb::AbstractArray, Ca::AbstractArray,
    Cb::AbstractArray,k::Int, l::Int;
    nbatches::Int = Base.Threads.nthreads())

Connect port k on an m port network, represented by the scattering parameter matrix Sa, to port l on an n port network, represented by the scattering parameter matrix Sb, resulting in a single (m+n-2) port network, as illustrated below:

Input network:

julia
      m |        | k+1                       | 2
        |        |                           |
        |   ...  |                     ...   |
        |________|                  _________|________
        |        |                  |        |       1
        |   Sa   |                  |   Sb   |
        |  m x m |                  |  n x n |
    ____|________|__________________|________|
    1   |   ...     k           l   |   ...  |
        |                           |        |
        |                           |        |
      2 |                       l+1 |        | n

Output network:

julia
    m-1 |        | k      | m+1    
        |        |        |        
        |   ...  |   ...  |        
        |________|________|________
        |                 |     m  
        |        S        |        
        |  m+n-2 x m+n-2  |        
    ____|_________________|        
    1   |   ...  |   ...  |        
        |        |        |        
        |        |        |        
      2 |        |        |  m+n-2 
                m-1+l

Arguments

  • Sa::Array: Array of scattering parameters representing the first network with ports along first two dimensions, followed by an arbitrary number of other dimensions (eg. frequency).

  • Sb::Array: Array of scattering parameters representing the second network with ports along first two dimensions, followed by an arbitrary number of other dimensions (eg. frequency).

  • Ca::Array: Array of noise correlation parameters of the same dimensions as Sa.

  • Cb::Array: Array of noise correlation parameters of the same dimensions as Sb.

  • k::Int: Port on first network, with one based indexing.

  • l::Int: Port on second network, with one based indexing.

References

S. W. Wedge, "Computer-aided design of low noise microwave circuits," PhD thesis (1991). R. C. Compton and D. B. Rutledge, "Perspectives in Microwave Circuit Analysis," Proceedings of the 32nd Midwest Symposium on Circuits and Systems, vol. 2, pp. 716–718, Aug. 1989. doi: 10.1109/MWSCAS.1989.101955 V. A. Monaco and P. Tiberio, "Computer-Aided Analysis of Microwave Circuits," in IEEE Transactions on Microwave Theory and Techniques, vol. 22, no. 3, pp. 249-263, Mar. 1974, doi: 10.1109/TMTT.1974.1128208.

source
JosephsonCircuits.interconnectS Method
julia
interconnectS(Sa::AbstractArray, Sb::AbstractArray, k::Int, l::Int;
    nbatches::Int = Base.Threads.nthreads())

Connect port k on an m port network, represented by the scattering parameter matrix Sa, to port l on an n port network, represented by the scattering parameter matrix Sb, resulting in a single (m+n-2) port network, as illustrated below:

Input network:

julia
      m |        | k+1                       | 2
        |        |                           |
        |   ...  |                     ...   |
        |________|                  _________|________
        |        |                  |        |       1
        |   Sa   |                  |   Sb   |
        |  m x m |                  |  n x n |
    ____|________|__________________|________|
    1   |   ...     k           l   |   ...  |
        |                           |        |
        |                           |        |
      2 |                       l+1 |        | n

Output network:

julia
    m-1 |        | k      | m+1    
        |        |        |        
        |   ...  |   ...  |        
        |________|________|________
        |                 |     m  
        |        S        |        
        |  m+n-2 x m+n-2  |        
    ____|_________________|        
    1   |   ...  |   ...  |        
        |        |        |        
        |        |        |        
      2 |        |        |  m+n-2 
                m-1+l

Arguments

  • Sa::Array: Array of scattering parameters representing the first network with ports along first two dimensions, followed by an arbitrary number of other dimensions (eg. frequency).

  • Sb::Array: Array of scattering parameters representing the second network with ports along first two dimensions, followed by an arbitrary number of other dimensions (eg. frequency).

  • k::Int: Port on first network, with one based indexing.

  • l::Int: Port on second network, with one based indexing.

References

V. A. Monaco and P. Tiberio, "Computer-Aided Analysis of Microwave Circuits," in IEEE Transactions on Microwave Theory and Techniques, vol. 22, no. 3, pp. 249-263, Mar. 1974, doi: 10.1109/TMTT.1974.1128208.

source
JosephsonCircuits.interconnectS_inner! Method
julia
interconnectS_inner!(Sout, Cout, Sa, Sb, Ca, Cb, k::Int, l::Int,
    batch::AbstractArray)

See interconnectS for description.

source
JosephsonCircuits.interconnectS_inner! Method
julia
interconnectS_inner!(Sout,Sa,Sb,k::Int,l::Int,batch::AbstractArray)

See interconnectS for description.

source
JosephsonCircuits.interconnectSports Method
julia
interconnectSports(portsa::AbstractVector{Tuple{T,Int}},
    portsb::AbstractVector{Tuple{T,Int}}, k::Int, l::Int) where T

Return a vector of tuples of (networkname, portindex) with portsa from the first network and portsb from the second network after ports k and l from the first and second networks have been connected. If the first network has n ports and the second network has m ports, then the combined network has (m+n-2) ports. See connectS for more information.

Examples

julia
julia> JosephsonCircuits.interconnectSports([(:S1,1),(:S1,2),(:S1,3),(:S1,4),(:S1,5)],[(:S2,1),(:S2,2),(:S2,3),(:S2,4),(:S2,5)],3,4)
8-element Vector{Tuple{Symbol, Int64}}:
 (:S1, 1)
 (:S1, 2)
 (:S1, 4)
 (:S1, 5)
 (:S2, 1)
 (:S2, 2)
 (:S2, 3)
 (:S2, 5)
source
JosephsonCircuits.internalpart Method
julia
internalpart(u::AbstractVector, L::CompositeLayout)

The internal block of a canonical vector u, as a view: the first L.rdim entries, which the harmonic system reads and writes in place.

source
JosephsonCircuits.interpolate_scattering Method
julia
interpolate_scattering(w0::AbstractVector, S::AbstractArray, w::AbstractArray;
    extrap = false, extrap_value = 0.0)

Interpolate the scattering parameters S, an array of size (nports, nports, length(w0)) tabulated at the frequencies w0, onto the frequencies w, interpolating the magnitude and the unwrapped phase of each entry separately. w may be a matrix such as the one returned by wmatrix, in which case the result has one matrix per entry of it. With extrap = true frequencies outside w0 take the value extrap_value; otherwise they are an error.

Examples

julia
w = 0.01:0.01:1.0
S = JosephsonCircuits.ABCD_tline(50,w)
isapprox(S,JosephsonCircuits.interpolate_scattering(w,S,w))

# output
true
source
JosephsonCircuits.intraconnectS! Method
julia
intraconnectS!(Sout, Cout, Sa, Ca, k::Int, l::Int; nbatches::Int = Base.Threads.nthreads())

See intraconnectS for description.

source
JosephsonCircuits.intraconnectS! Method
julia
intraconnectS!(Sout, Sa, k::Int, l::Int; nbatches::Int = Base.Threads.nthreads())

See intraconnectS for description.

source
JosephsonCircuits.intraconnectS Method
julia
intraconnectS(Sa::AbstractArray, Ca::AbstractArray, k::Int, l::Int;
    nbatches::Int = Base.Threads.nthreads())

Connect ports k and l on the same m port microwave network represented by the scattering parameter matrix Sa, and noise correlation matrix Ca resulting in an (m-2) port network, as illustrated below:

Input network:

julia
      m |         | l+1    
        |   ...   |         l
        |_________|__________ 
        |         |          |
        |   Sa    |  ...     |
        |  m x m  |          |
    ____|_________|_____ k+1 |
    1   |   ...   |          |
        |         | k        |
      2 |         |__________|

Output network:

julia
    m-2 |         | l-1     
        |         |         
        |   ...   |         
        |_________|         
        |         |         
        |    S    |  ...    
        |m-2 x m-2|         
    ____|_________|_________
    1   |   ...         k   
        |                   
        |                   
      2 |

Arguments

  • Sa::Array: Array of scattering parameters representing the network with ports along first two dimensions, followed by an arbitrary number of other dimensions (eg. frequency).

  • Ca::Array: Array of noise correlation parameters of the same dimensions as Sa.

  • k::Int: First port to connect, with one based indexing.

  • l::Int: Second port to connect, with one based indexing.

References

S. W. Wedge, "Computer-aided design of low noise microwave circuits," PhD thesis (1991). R. C. Compton and D. B. Rutledge, "Perspectives in Microwave Circuit Analysis," Proceedings of the 32nd Midwest Symposium on Circuits and Systems, vol. 2, pp. 716–718, Aug. 1989. doi: 10.1109/MWSCAS.1989.101955 V. A. Monaco and P. Tiberio, "Computer-Aided Analysis of Microwave Circuits," in IEEE Transactions on Microwave Theory and Techniques, vol. 22, no. 3, pp. 249-263, Mar. 1974, doi: 10.1109/TMTT.1974.1128208.

source
JosephsonCircuits.intraconnectS Method
julia
intraconnectS(Sa::AbstractArray, k::Int, l::Int;
    nbatches::Int = Base.Threads.nthreads())

Connect ports k and l on the same m port microwave network represented by the scattering parameter matrix Sa, resulting in an (m-2) port network, as illustrated below:

Input network:

julia
      m |         | l+1    
        |   ...   |         l
        |_________|__________ 
        |         |          |
        |   Sa    |  ...     |
        |  m x m  |          |
    ____|_________|_____ k+1 |
    1   |   ...   |          |
        |         | k        |
      2 |         |__________|

Output network:

julia
    m-2 |         | l-1     
        |         |         
        |   ...   |         
        |_________|         
        |         |         
        |    S    |  ...    
        |m-2 x m-2|         
    ____|_________|_________
    1   |   ...         k   
        |                   
        |                   
      2 |

Arguments

  • Sa::Array: Array of scattering parameters representing the network with ports along first two dimensions, followed by an arbitrary number of other dimensions (eg. frequency).

  • k::Int: First port to connect, with one based indexing.

  • l::Int: Second port to connect, with one based indexing.

References

R. C. Compton and D. B. Rutledge, "Perspectives in Microwave Circuit Analysis," Proceedings of the 32nd Midwest Symposium on Circuits and Systems, vol. 2, pp. 716–718, Aug. 1989. doi: 10.1109/MWSCAS.1989.101955 V. A. Monaco and P. Tiberio, "Computer-Aided Analysis of Microwave Circuits," in IEEE Transactions on Microwave Theory and Techniques, vol. 22, no. 3, pp. 249-263, Mar. 1974, doi: 10.1109/TMTT.1974.1128208.

source
JosephsonCircuits.intraconnectS_inner! Method
julia
intraconnectS_inner!(Sout, Sa, k::Int, l::Int, batch::AbstractArray)

See intraconnectS for description.

source
JosephsonCircuits.intraconnectSports Method
julia
intraconnectSports(portsa::AbstractVector{Tuple{T,Int}},k::Int,l::Int) where T

Return a vector of tuples of (networkname, portindex) from portsa after ports k and l have been connected. See connectS for more information.

Examples

julia
julia> JosephsonCircuits.intraconnectSports([(:S1,1),(:S1,2),(:S1,3),(:S1,4),(:S1,5)],3,4)
3-element Vector{Tuple{Symbol, Int64}}:
 (:S1, 1)
 (:S1, 2)
 (:S1, 5)
source
JosephsonCircuits.inv_bogoliubov_block Method
julia
inv_bogoliubov_block(S)

Return the inverse of the Bogoliubov matrix S computed from transpose(Ω)*transpose(S)*Ω where Ω is the symplectic form for block operator ordering.

Examples

julia
julia> S = JosephsonCircuits.rand_bogoliubov_block(2);isapprox(inv(S),JosephsonCircuits.inv_bogoliubov_block(S))
true
source
JosephsonCircuits.inv_bogoliubov_pair Method
julia
inv_bogoliubov_pair(S)

Return the inverse of the Bogoliubov matrix S computed from transpose(Ω)*transpose(S)*Ω where Ω is the symplectic form for pair operator ordering.

Examples

julia
julia> S = JosephsonCircuits.rand_bogoliubov_pair(2);isapprox(inv(S),JosephsonCircuits.inv_bogoliubov_pair(S))
true
source
JosephsonCircuits.inv_symplectic_block Method
julia
inv_symplectic_block(S)

Return the inverse of the symplectic matrix S computed from transpose(Ω)*transpose(S)*Ω where Ω is the symplectic form for block operator ordering.

Examples

julia
julia> S = JosephsonCircuits.rand_symplectic_block(2);isapprox(inv(S),JosephsonCircuits.inv_symplectic_block(S))
true
source
JosephsonCircuits.inv_symplectic_pair Method
julia
inv_symplectic_pair(S)

Return the inverse of the symplectic matrix S computed from transpose(Ω)*transpose(S)*Ω where Ω is the symplectic form for pair operator ordering.

Examples

julia
julia> S = JosephsonCircuits.rand_symplectic_pair(2);isapprox(inv(S),JosephsonCircuits.inv_symplectic_pair(S))
true
source
JosephsonCircuits.inverseinductanceplan Method
julia
inverseinductanceplan(c, cg, Lb, coupled)

Build the InverseInductancePlan from the incidence matrix, the branches which carry an inductance, and the branches which are mutually coupled.

source
JosephsonCircuits.is_bogoliubov_block Method
julia
is_bogoliubov_block(M) -> Bool

Return true if the matrix M is Bogoliubov, M ∈ Sp(2n, ℂ) ∩ U(n, n), with block operator order and false otherwise.

source
JosephsonCircuits.is_bogoliubov_pair Method
julia
is_bogoliubov_pair(M) -> Bool

Return true if the matrix M is Bogoliubov, M ∈ Sp(2n, ℂ) ∩ U(n, n), with pair operator order and false otherwise.

source
JosephsonCircuits.is_conjugate_symplectic_block Method
julia
is_conjugate_symplectic_block(M) -> Bool

Return true if the matrix M is conjugate symplectic, , with block operator order and false otherwise.

source
JosephsonCircuits.is_conjugate_symplectic_pair Method
julia
is_conjugate_symplectic_pair(M) -> Bool

Return true if the matrix M is conjugate symplectic, , with pair operator order and false otherwise.

source
JosephsonCircuits.is_cptp Method

Eq. 5.37 from Serafini

source
JosephsonCircuits.is_orthogonal Method
julia
is_orthogonal(M) -> Bool

Return true if the matrix M is orthogonal, M ∈ O(n), and false otherwise.

Tests if M satisfies the condition M*transpose(M)==I where I is the identity matrix.

source
JosephsonCircuits.is_orthogonal_bogoliubov_block Method
julia
is_orthogonal_bogoliubov_block(M) -> Bool

Return true if the matrix M is orthogonal Bogoliubov, M ∈ Sp(2n, ℂ) ∩ U(n, n) ∩ U(2n) ≅ U(n), with pair operator order and false otherwise.

source
JosephsonCircuits.is_orthogonal_bogoliubov_pair Method
julia
is_orthogonal_bogoliubov_pair(M) -> Bool

Return true if the matrix M is orthogonal Bogoliubov, M ∈ Sp(2n, ℂ) ∩ U(n, n) ∩ U(2n) ≅ U(n), with pair operator order and false otherwise.

source
JosephsonCircuits.is_orthogonal_symplectic_block Method
julia
is_orthogonal_symplectic_block(M) -> Bool

Return true if the matrix M is orthogonal symplectic, M ∈ Sp(2n, ℝ) ∩ O(2n) ≅ U(n), with block operator order and false otherwise.

source
JosephsonCircuits.is_orthogonal_symplectic_pair Method
julia
is_orthogonal_symplectic_pair(M) -> Bool

Return true if the matrix M is orthogonal symplectic, M ∈ Sp(2n, ℝ) ∩ O(2n) ≅ U(n), with pair operator order and false otherwise.

source
JosephsonCircuits.is_positive_definite Method
julia
is_positive_definite(M) -> Bool

Return true if the matrix M is positive definite and false otherwise.

source
JosephsonCircuits.is_positive_definite_symplectic_block Method
julia
is_positive_definite_symplectic_block(S) -> Bool

Return true if the matrix S is positive definite and symplectic, S ∈ Sp(2n, ℝ) or S ∈ Sp(2n, ℂ), with block operator order and false otherwise.

source
JosephsonCircuits.is_positive_definite_symplectic_pair Method
julia
is_positive_definite_symplectic_pair(S) -> Bool

Return true if the matrix S is positive definite and symplectic, S ∈ Sp(2n, ℝ) or S ∈ Sp(2n, ℂ), with pair operator order and false otherwise.

source
JosephsonCircuits.is_positive_semi_definite Method
julia
is_positive_semi_definite(M) -> Bool

Return true if the matrix M is positive semi-definite and false otherwise.

source
JosephsonCircuits.is_pseudo_unitary Method
julia
is_pseudo_unitary(Σ,M) -> Bool

Return true if the matrix M is pseudo-unitary, M ∈ U(n, n), and false otherwise.

Tests if M satisfies the pseudo-unitary condition M*Σ*M'==Σ where Σ is a user supplied matrix representing the indefinite Hermitian form.

See also indefinite_hermitian_form_pair, indefinite_hermitian_form_block, is_pseudo_unitary_block, and is_pseudo_unitary_pair.

source
JosephsonCircuits.is_pseudo_unitary_block Method
julia
is_pseudo_unitary_block(M) -> Bool

Return true if the matrix M is pseudo-unitary, M ∈ U(n, n), with block operator order and false otherwise.

Tests if M*Σ*M'==Σ where Σ is a matrix representing the indefinite Hermitian form with block operator order.

See also indefinite_hermitian_form_block.

source
JosephsonCircuits.is_pseudo_unitary_pair Method
julia
is_pseudo_unitary_pair(M) -> Bool

Return true if the matrix M is pseudo-unitary, M ∈ U(n, n), with pair operator order and false otherwise.

Tests if M*Σ*M'==Σ where Σ is a matrix representing the indefinite Hermitian form with pair operator order.

See also indefinite_hermitian_form_pair.

source
JosephsonCircuits.is_symplectic Method
julia
is_symplectic(Ω, S) -> Bool

Return true if the matrix S is symplectic, S ∈ Sp(2n, ℝ) or S ∈ Sp(2n, ℂ), and false otherwise.

Tests if S satisfies the symplectic condition S*Ω*transpose(S)==Ω where Ω is a user supplied symplectic form.

See also symplectic_form_block, symplectic_form_pair, is_symplectic_block, and is_symplectic_pair.

source
JosephsonCircuits.is_symplectic_block Method
julia
is_symplectic_block(S) -> Bool

Return true if the matrix S is symplectic, S ∈ Sp(2n, ℝ) or S ∈ Sp(2n, ℂ), with block operator order and false otherwise.

Tests if S satisfies the symplectic condition S*Ω*transpose(S)==Ω where Ω is the matrix representing the symplectic form with block operator order.

See also symplectic_form_block.

source
JosephsonCircuits.is_symplectic_pair Method
julia
is_symplectic_pair(S) -> Bool

Return true if the matrix S is symplectic, S ∈ Sp(2n, ℝ) or S ∈ Sp(2n, ℂ), with pair operator order and false otherwise.

Tests if S satisfies the symplectic condition S*Ω*transpose(S)==Ω where Ω is the matrix representing the symplectic form with pair operator order.

See also symplectic_form_pair.

source
JosephsonCircuits.is_unitary Method
julia
is_unitary(M) -> Bool

Return true if the matrix M is unitary, M ∈ U(n), and false otherwise.

Tests if M satisfies the condition M*M'==I where I is the identity matrix.

source
JosephsonCircuits.isaugmented Method
julia
isaugmented(p::HBNonlinearProblem)

Whether p carries an explicit direct current block, so that its unknowns are the canonical state rather than the harmonic one.

source
JosephsonCircuits.isexactpreconditioner Method
julia
isexactpreconditioner(pc::AbstractPreconditioner)

Whether pc currently applies the exact Jacobian, so that a deflation or composition layered on top of it can contribute nothing. false for any preconditioner that does not say otherwise.

source
JosephsonCircuits.isgrounded Method
julia
isgrounded(c)

Whether a multiport component's second terminals are all tied to ground, so that only its first terminals connect (grounded = true at construction).

source
JosephsonCircuits.isinternal Method
julia
isinternal(L::CompositeLayout)

Whether the canonical state is the internal one, which it is exactly while there are no explicit direct current coordinates.

source
JosephsonCircuits.ismnaresistance Method
julia
ismnaresistance(value)

Return true if value is a constant, real, finite, nonzero resistance, which is what the port impedance scale of calcsolverscale is taken from. Real numbers and complex numbers with zero imaginary part are accepted; symbolic values, values with nonzero imaginary part, zeros, and non-finite values return false.

Examples

julia
julia> JosephsonCircuits.ismnaresistance(50.0)
true

julia> JosephsonCircuits.ismnaresistance(50.0+0.0im)
true

julia> JosephsonCircuits.ismnaresistance(50.0+1.0im)
false

julia> JosephsonCircuits.ismnaresistance(0.0)
false
source
JosephsonCircuits.isnumericallyzero Method
julia
isnumericallyzero(value, terms)

Return true if value, the floating point result of a linear combination of the given terms, is approximately zero up to roundoff error.

Examples

julia
julia> JosephsonCircuits.isnumericallyzero(2*pi*1.0 + (2*pi*(5e9-1) - 2*pi*5e9), (2*pi*1.0, -2*pi*5e9, 2*pi*(5e9-1)))
true

julia> JosephsonCircuits.isnumericallyzero(2*pi*1.0, (2*pi*1.0, 0.0, 0.0))
false
source
JosephsonCircuits.issinusoidal Method
julia
issinusoidal(c::NonlinearInductor)

Whether the current-phase relation of c is the sinusoidal Josephson relation (sin, cos), in which case the component compiles to the :Lj type the solvers support.

source
JosephsonCircuits.iwasawa_block Method
julia
iwasawa_block(S::AbstractMatrix)

Return the Iwasawa (KAN) decomposition K, A, N of the symplectic matrix S. K is a unitary symplectic matrix (maximal compact), A is a diagonal symplectic matrix (Abelian), and N is a upper triangular symplectric matrix (nilpotent). The symplectric matrices are symplectic with respect to the block symplectric form Ω. This decomposition is unique.

References

[1] Arvind, B. Dutta, N. Mukunda, and R. Simon, “The real symplectic groups in quantum mechanics and optics,” Pramana - J Phys, vol. 45, no. 6, pp. 471–497, Dec. 1995, doi: 10.1007/BF02848172. [2] M. Benzi and N. Razouk, “On the Iwasawa decomposition of a symplectic matrix,” Applied Mathematics Letters, vol. 20, no. 3, pp. 260–265, Mar. 2007, doi: 10.1016/j.aml.2006.04.004. [3] M. Houde, W. McCutcheon, and N. Quesada, “Matrix decompositions in Quantum Optics: Takagi/Autonne, Bloch-Messiah/Euler, Iwasawa, and Williamson,” Can. J. Phys., vol. 102, no. 10, pp. 497–507, Oct. 2024, doi: 10.1139/cjp-2024-0070.

source
JosephsonCircuits.jacobian! Method
julia
jacobian!(A::DeviceValuedSparseMatrix, plan::StructureRealJacobianPlan,
    sys::HBSystem)

Assemble the real Jacobian into the device values of A. Nothing crosses to the host: the coefficients are already on the backend and the assembly runs there.

source
JosephsonCircuits.jacobian! Method
julia
jacobian!(Jx::SparseMatrixCSC{<:Complex}, sys::HBSystem)
jacobian!(Jr::SparseMatrixCSC{<:Real}, sys::HBSystem)
jacobian!(A::DeviceValuedSparseMatrix, sys::HBSystem)
jacobian!(A::DeviceValuedSparseMatrix{<:Complex}, plan, sys::HBSystem)

Assemble the Jacobian of the harmonic balance nonlinear system at the point set with setpoint!, in place, using the precomputed plans. Dispatches on the element type of the matrix: a complex matrix receives the complex holomorphic Jacobian (an approximation to the exact Jacobian, used by the QuasiNewton method, via assemblecomplexjacobian!) and a real matrix the exact Jacobian of the equivalent real system (used by the Newton method, via assemblerealjacobian!). A DeviceValuedSparseMatrix receives the same on its backend. The corresponding plan must have been provided when the HBSystem was constructed; the method taking a plan explicitly is documented below.

source
JosephsonCircuits.jacobian! Method
julia
jacobian!(Jr::SparseMatrixCSC, plan::StructureRealJacobianPlan,
    sys::HBSystem)

Assemble the real Jacobian described by plan at the point set with setpoint!, in place. This is the method jacobian!(Jr, sys) delegates to with the plan stored in sys; taking the plan explicitly lets a different plan, built over the same system, be assembled from the same Fourier coefficients of cos(phi(t)) and the same linear term matrices.

source
JosephsonCircuits.jacobianprototype Method
julia
jacobianprototype(prob::HBNonlinearProblem)

A copy of the assembled real Jacobian's sparsity pattern, for solvers which want a jac_prototype, or nothing.

source
JosephsonCircuits.jacobianvectorproduct! Method
julia
jacobianvectorproduct!(Jv::AbstractVector, sys::HBSystem,
    v::AbstractVector)

Evaluate the exact matrix-free Jacobian-vector product of the harmonic balance nonlinear system, J(x)*v = B(cos.(A*x) .* (A*v)) + K*v, at the point set with setpoint!, in place. Dispatches on the element types: complex vectors receive the complex representation and real vectors the equivalent real representation, for which the product equals the assembled real Jacobian (jacobian!) applied to vr up to floating point roundoff, including the self-conjugate (eg. DC) modes. Each product costs two Fourier transforms and the linear term; the time domain cosine is cached across products at the same point. Suitable as the operator for Krylov methods.

source
JosephsonCircuits.jjnodeadjacency Method
julia
jjnodeadjacency(Ljb::SparseVector, nodesandsigns, Nnodes::Integer)

For each node, return the sorted, deduplicated list of nodes which share at least one Josephson junction branch with it (including itself), from the per-branch (node, sign) lists in nodesandsigns (see branchnodesandsigns) restricted to the Josephson branches in Ljb. Used to enumerate the columns of the Jacobian sparsity structure directly in compressed sparse column form.

source
JosephsonCircuits.josephsonadjoint! Method
julia
josephsonadjoint!(P, Q, plan::StructureComplexJosephsonPlan,
    w::AbstractVector)

Apply the transpose of the Josephson map: accumulate w, which is indexed by stored entry, back onto the Fourier coefficients it was gathered from.

The plain and conjugated contributions land in P and Q respectively, because the caller treats the two halves differently downstream. Which of the two a stored entry belongs to is decided by the sign of its mode coupling index, and a stored entry names one mode pair, so an entry contributes to one of them and never both.

This runs on the host: it is a scatter with collisions, it is used only by the sensitivity calculation, and that calculation is a host loop throughout.

source
JosephsonCircuits.junctioncpr Function
julia
junctioncpr(c::NonlinearInductor, path)

The relation the solvers evaluate for c: nothing for the sinusoidal Josephson relation, which they hold as sin and cos, or the PolynomialCPR they evaluate by Horner. Any other callable throws, since a relation the solvers cannot write down is one they cannot transform.

The coefficients are converted to Float64 here, so that the table the solvers build is concrete whatever the user wrote them as.

source
JosephsonCircuits.junctionpairtable Method
julia
junctionpairtable(::Type{Ti}, ::Type{T}, Ljb::SparseVector, nodesandsigns,
    Nnodes::Integer)

The junctions incident on each ordered node pair, as a compressed sparse column structure over the second node: ptr, the row n1, the junction, and the product of the two incidence signs.

This is the whole of the incidence triple product, and it has one entry per (junction, node, node) triple: four per junction for a two terminal one.

The entries of a pair are ordered by junction index, which fixes the order the assembly sums them in. That order is part of the result, because floating point addition is not associative.

source
JosephsonCircuits.junctionrelations Method
julia
junctionrelations(cprs::AbstractVector)

The JunctionRelations of the junctions whose relations are cprs, one entry per junction in the order of the junction axis, each either nothing for the sinusoidal Josephson relation or a PolynomialCPR. Returns nothing when every entry is nothing.

source
JosephsonCircuits.junctionstructure Method
julia
junctionstructure(::Type{T}, Amatrixindices::Matrix,
    Amatrixconjindices::Matrix, Ljb::SparseVector, Lscale,
    Rbnm::SparseMatrixCSC, Nmodes::Integer, Nbranches::Integer,
    Nfreq::Integer, backend)

Build the JunctionStructure of a system in precision T on backend. The pair table is indexed in Int32, which the node and junction counts never exceed; a plan's own structure keeps whatever index type its size needs.

source
JosephsonCircuits.keepfreqs Method
julia
keepfreqs(frequencies::Frequencies{N},
    keepcoords::AbstractVector{CartesianIndex{N}})

Return a new Frequencies struct with all coordinates and modes except the ones in keepmodes removed.

source
JosephsonCircuits.keepfreqs Method
julia
keepfreqs(frequencies::Frequencies{N},
    keepmodes::AbstractVector{NTuple{N,Int}})

Return a new Frequencies struct with all coordinates and modes except the ones in keepmodes removed.

source
JosephsonCircuits.klunodeorder Method
julia
klunodeorder(adj::AbstractVector{<:AbstractVector{<:Integer}})

The elimination order of the circuit nodes from KLU's symbolic analysis of the node graph: its block triangular form permutation followed by the fill reducing ordering within the blocks. On a chain this walks the chain; on a meshed circuit it halves the fill of a bandwidth reducing order and gives an elimination tree many times shallower.

source
JosephsonCircuits.kluordered Method
julia
kluordered(A::SparseMatrixCSC; kwargs...)

KLU.klu(A) with its fill reducing ordering chosen by measurement. KLU's own default, AMD on the pattern of A + A', is the right ordering for most circuit matrices and a pathological one for some of the mode-coupling patterns the preconditioners of this package factorize: the harmonic band of a two-tone line is a mode lattice crossed with the spatial chain, a grid-like graph, and on the bandwidth-one pattern of a 128-junction line AMD produced 23 million fill entries and a 20 s factorization where METIS nested dissection gave 6 million and 0.4 s. Nested dissection is not uniformly better either: on the full Jacobian of the same line it fills 60% more than AMD and factorizes in twice the time.

So both permutations are computed, AMD and METIS nested dissection, each through the CHOLMOD library that ships with Julia, the flops of the factorization each would need are predicted from the elimination tree (symbolicfill), and the cheaper one is handed to KLU as a given ordering. Everything before the numeric factorization is symbolic and costs a few tenths of a second on a matrix of a million nonzeros, once per sparsity pattern; the numeric refactorizations of the same pattern reuse the choice. Should either ordering fail, KLU's default is used.

source
JosephsonCircuits.ladder_to_quadrature_block Method
julia
ladder_to_quadrature_block(S::AbstractMatrix)
source
JosephsonCircuits.ladder_to_quadrature_block Method
julia
ladder_to_quadrature_block(r::AbstractVector)
source
JosephsonCircuits.ladder_to_quadrature_pair Method
julia
ladder_to_quadrature_pair(S::AbstractMatrix)
source
JosephsonCircuits.ladder_to_quadrature_pair Method
julia
ladder_to_quadrature_pair(r::AbstractVector)
source
JosephsonCircuits.ldiv_2x2 Method
julia
ldiv_2x2(fact,b)

Solve the linear system A*x = b for x using left division when given fact which is the LU factorization of A.

source
JosephsonCircuits.linearcontributionkernel! Method
julia
linearcontributionkernel!(lin, colptr, rowval, ...)

The constant frequency dependent contribution to each stored entry of the Jacobian: invLnm + im*Gnm*wmodesm - Cnm*wmodes2m, in the real representation.

Scattering each stored entry of the three matrices into the Jacobian through a precomputed index map costs a map per matrix, a pass over a Jacobian sized array per matrix, and, on a device, an upload of the result. Each stored entry of the Jacobian takes at most one entry from each of the three, so it is gathered instead: decode the entry into the complex position it belongs to and look that position up in each. The three are summed in the order invLnm, Gnm, Cnm, because floating point addition is not associative and the order is part of the result.

source
JosephsonCircuits.linearizedfactorization Method
julia
linearizedfactorization(A::SparseMatrixCSC, Nmodes::Integer,
    ntones::Integer, backend; nbatches = 1,
    budget = freememory(backend) ÷ 2)

The factorization of the linearized solve when none is given, by the number of tones and the memory, the rule Automatic applies to the nonlinear solve. One tone keeps the backend's sparse factorization (KLU on the host, cuDSS on a device): its node blocks are small and the sparse factorizations are as fast as or faster than the block one on them (measured on the README's JTWPA examples: equal on the host, cuDSS 3.5x faster on a device). Two or more tones take BlockFactorization in double when the factors of one system (blocksystembytes), times the host batches, fit in budget: 2 to 3.5x faster than KLU on the host and at parity with cuDSS on an RTX 4090, where the double rate bounds both; otherwise the sparse factorization.

source
JosephsonCircuits.linearizedoutputs Method
julia
linearizedoutputs(; ...)

The last stage of hblinsolve: the LinearizedHB of the sweep, its arrays keyed by mode, port, node and frequency when asked.

source
JosephsonCircuits.linearizedsensitivity Method
julia
linearizedsensitivity(; ...)

The second stage of hblinsolve: the sensitivity stamps of the requested components and scattering blocks, and the operating point contribution in the contraction order chosen (sensitivitymode), either as forward stamps or as a ReverseSensitivity. Empty when no sensitivity was asked for. The keywords are the fields of linearizedsetup this stage reads, the operating point and the sensitivity arrays.

source
JosephsonCircuits.linearizedsetup Method
julia
linearizedsetup(w, psc, cg, circuitdefs, signalfreq, nonlinear,
    symfreqvar, factorization, backend, temperature, sensitivitynames,
    sensitivitypairs, sensitivityblockpairs; nbatches,
    nsensitivityparameters, wantsnoise)

The first stage of hblinsolve: the circuit matrices at the signal mode count, the pump's cosine transform from the nonlinear solution (or unity without one), the mode frequencies and the checks on them, the modified nodal analysis padding, the sensitivity component indices and their grouping, the port sources, the noise channels with their temperatures, the HBLinearizedSystem with its system matrix assembled, and the factorization the sweep uses. Returned as a named tuple whose fields the later stages read by name.

source
JosephsonCircuits.linearizedsweep! Method
julia
linearizedsweep!(; ...)

The third stage of hblinsolve: the sweep over the signal frequencies, on the backend in batches when the system allows it and on host threads otherwise, each frequency solved by hblinsolve_inner! into the LinearizedArrays returned. The keywords are the fields of the two stages before which this one reads, and the requested outputs.

source
JosephsonCircuits.linearterm! Method
julia
linearterm!(Knm, maps::ValueMaps, invLnm, Gnm, Cnm, wmodesm, wmodes2m)

linearterm in place, through the maps: the same three terms in the same order, so the values are the ones the allocating form gives.

source
JosephsonCircuits.linearterm Method
julia
linearterm(invLnm, Gnm, Cnm, wmodesm::Diagonal, wmodes2m::Diagonal,
    T = Float64)

Collapse the frequency dependent linear terms of the harmonic balance system into the single sparse matrix of element type Complex{T}

julia
K = invLnm + im*Gnm*wmodesm - Cnm*wmodes2m

so that applying them is one gather over the entries of an output row rather than three sparse matrix-vector products and two diagonal scalings through two temporaries. The mode frequency diagonals are fixed for the lifetime of an HBSystem, so this is formed once when the system is constructed and handed to plannonlinearterm, which stores it transposed in both representations.

source
JosephsonCircuits.linesearchevaluate! Method
julia
linesearchevaluate!(f!, F, xcandidate, x, α, deltax, beta, correction)

Evaluate the line search merit function at the trial step α: generate the trial point with linesearchtrialpoint!, evaluate the residual there with f!(F, xcandidate), and return merit(F). xcandidate and F contain the trial point and its residual when this function finishes.

source
JosephsonCircuits.linesearchtrialpoint! Method
julia
linesearchtrialpoint!(xcandidate, x, α, deltax, beta, correction)

Overwrite xcandidate with the line search trial points on the curvilinear path: xcandidate = x + α*deltax - beta*α²*correction, or the straight path x + α*deltax when correction == nothing or beta == 0. Overwrites and returns xcandidate.

source
JosephsonCircuits.lu_2x2 Method
julia
lu_2x2(A)

Return the LU factorization of a 2 by 2 matrix as a StaticArrays.LU struct. Perform the LU factorization even if A is singular.

source
JosephsonCircuits.make_connection! Method
julia
make_connection!(g, fconnectionlist, fweightlist, ports,
    scattering_parameters, noise_covariances, src_node,
    connection_index, nbatches, userinput, scattering_parameter_storage,
    noise_covariance_storage, noise)

Apply the connection specified by the source node src_node and the index of the connection in the forward adjacency list connection_index, updating the graph, the adjacency lists, the ports, and the scattering parameter and noise covariance matrices in place. userinput records which matrices are the user's and must not be overwritten; scattering_parameter_storage and noise_covariance_storage hold reusable buffers by size; noise selects whether the noise covariances are propagated.

source
JosephsonCircuits.matrixprovider Method
julia
matrixprovider(x, T; n = nothing, interpolation = :cubic,
    extrapolation = :error, form = :matrix)

Normalize user input into an AbstractMatrixProvider with element type T: a matrix becomes a ConstantMatrixProvider, a tuple (frequencies, values) a TabulatedMatrixProvider, a callable of angular frequency a CallableMatrixProvider (which requires the dimension n and accepts form), and an existing provider is returned as is. n, when given, is checked against the data.

source
JosephsonCircuits.maxwell_combine Method
julia
maxwell_combine(n::Int, d::Dict{NTuple{N, Int}, T}) where {N,T<:AbstractMatrix}

Return the Maxwell capacitance matrix for an n terminal system from the Maxwell capacitance matrices for sets of terminals stored in the dictionary d. The dictionary keys are tuples of the terminal numbers for the capacitance matrices and the values are the capacitance matrices.

Examples

julia
julia> JosephsonCircuits.maxwell_combine(3, Dict((1,2)=>[1.0 2.0;4.0 5.0],(1,3)=>[1.0 3.0;7.0 9.0],(2,3)=>[5.0 6.0;8.0 9.0]))
3×3 Matrix{Float64}:
 1.0  2.0  3.0
 4.0  5.0  6.0
 7.0  8.0  9.0

julia> JosephsonCircuits.maxwell_combine(3, Dict((1,2,3)=>[1.0 2.0 3.0;4.0 5.0 6.0;7.0 8.0 9.0]))
3×3 Matrix{Float64}:
 1.0  2.0  3.0
 4.0  5.0  6.0
 7.0  8.0  9.0
source
JosephsonCircuits.maxwell_to_even_odd Method
julia
maxwell_to_even_odd(L, Cmaxwell)

Return the even and odd mode impedances and the even and odd mode indices from the inductance matrix L and the Maxwell capacitance matrix Cmaxwell.

Examples

julia
C = [1.0e-12 1.0e-13;1.0e-13 1.0e-12]
L = [1.0e-9 1.0e-10;1.0e-10 1.0e-9]
Zeven, Zodd, neven, nodd = JosephsonCircuits.maxwell_to_even_odd(L,C)
@show Zeven
@show Zodd
@show neven
@show nodd
;

# output
Zeven = 31.622776601683796
Zodd = 31.622776601683796
neven = 0.010428296918824038
nodd = 0.008532242933583305
source
JosephsonCircuits.maxwell_to_mutual Method
julia
maxwell_to_mutual(Cmaxwell::AbstractMatrix)

Return the mutual capacitance matrix from the Maxwell capacitance matrix Cmaxwell.

The Maxwell capacitance Cmaxwell is the relationship between charge and voltage on each node, Q = C V or dQi/dVj = C_ij where C is the Maxwell capacitance matrix.

Each element of the mutual capacitance matrix Cmutual is the value of a physical capacitor placed between two nodes in a circuit or between a node and ground.

Examples

julia
julia> C = [1.0 -0.1;-0.1 2.0];JosephsonCircuits.maxwell_to_mutual(C)
2×2 Matrix{Float64}:
 0.9  0.1
 0.1  1.9
source
JosephsonCircuits.mergestamps Method
julia
mergestamps(stamps, grouping)

Concatenate the stamps of each group of grouping into one. A design parameter typically touches many components – a single junction inductance across a two thousand cell line – and the contraction cost is per stamp, so merging turns one contraction per component into one per parameter (and kind). The grouping comes from parametergrouping, so it is the same one applied to the residual derivative columns.

source
JosephsonCircuits.merit Method
julia
merit(F)

The line search merit function ϕ = 0.5*||F||² = real(0.5*dot(F, F)). The dot product conjugates the first argument so this can be used for real or complex vectors.

source
JosephsonCircuits.meritslope! Method
julia
meritslope!(Jv, jvp, p, F, ϕ0, w)

The slope real(F' J p) of the merit function ϕ = F'F/2 along the step p, where p = -Δ for a linear solve J Δ ≈ F which left the explicit residual w = F - J Δ.

Then J p = w - F and the slope is real(F'w) - 2ϕ0: one inner product, with the Jacobian vector product the solve already paid for. Without a valid residual (w === nothing), the product is taken.

source
JosephsonCircuits.mnacoupledbranches Method
julia
mnacoupledbranches(Mb::SparseMatrixCSC)

Return the sorted branch indices which participate in mutual inductive coupling, the union of the row and column supports of the branch mutual inductance matrix Mb. These branches are assigned auxiliary branch current variables by the modified nodal analysis formulation instead of being eliminated through the inverse of the branch inductance matrix, so the system matrix entries remain bounded as the coupling coefficient approaches one, where the inverse inductance entries of the nodal formulation diverge as 1/(1-k^2).

source
JosephsonCircuits.mnadropbranches Method
julia
mnadropbranches(Lb::SparseVector, branches::Vector{Int})

Return a copy of the branch inductance vector Lb with the entries at branches removed, so the nodal inverse inductance matrix can be computed from the remaining, uncoupled inductors only.

source
JosephsonCircuits.mnagaugenormalize! Method
julia
mnagaugenormalize!(x::AbstractVector,
    floatingcomponents::Vector{Vector{Int}}, wmodes::Vector,
    Nmodes::Int)

Transform an initial guess into the gauge selected by the gauge fixing equations by subtracting, for each floating component of the static flux-stiffness graph and each zero-frequency mode, the flux of the component's reference node from the fluxes of all nodes of the component. A common shift of the DC fluxes of a floating component leaves every branch flux, and therefore every physical circuit quantity and every Kirchhoff current law residual, unchanged - it is exactly the gauge degree of freedom - but it does enter the gauge fixing rows. Normalizing the guess makes physically equivalent initial values produce identical augmented residuals and makes the reference-node gauge rows exactly zero at the initial value.

source
JosephsonCircuits.mnainitialauxind! Method
julia
mnainitialauxind!(x::AbstractVector, coupledbranches::Vector{Int},
    Lb::SparseVector, Mb::SparseMatrixCSC, Rbn::SparseMatrixCSC,
    Nmodes::Int, auxoffset::Int, Lscale)

Initialize the auxiliary branch current variables of the mutually coupled inductors consistently with the node fluxes in x, by solving the small dense branch inductance system (L/Lscale)*u = Rbn*phi over the coupled branches, which zeros their constitutive rows exactly. If the branch inductance matrix is singular (a perfectly coupled pair, |k| = 1) the auxiliary variables are left unchanged: the full system can still be well posed and solvable in that case, because the constitutive equations use the un-inverted branch inductance matrix, so only this warm start refinement is skipped.

source
JosephsonCircuits.mnapad Method
julia
mnapad(A::SparseMatrixCSC, Naux::Int)

Pad the sparse matrix A with Naux empty rows and columns, returning a square matrix suitable for the augmented modified nodal analysis system.

source
JosephsonCircuits.mnaresistance Method
julia
mnaresistance(value)

Return the real resistance of a value accepted by ismnaresistance.

source
JosephsonCircuits.mnaungaugedkcl Method
julia
mnaungaugedkcl(F::AbstractVector, x::AbstractVector,
    gaugeindices::Vector{Int}, Nnodal::Int)

Reconstruct the residuals of the original, ungauged Kirchhoff current law equations from the augmented residual F and the state x. The gauge fixing equations add x[g] to the augmented residual of each gauge row g, so the physical residual is F[g] - x[g] at the gauge rows and F[i] elsewhere in the node block. This is the quantity which must be small for the reported solution to satisfy the original circuit equations: a gauge equation can otherwise absorb an incompatibility (for example a net direct current injected into a floating subnetwork which slipped past the direct current subsystem's solvability check) into the arbitrary flux reference while the augmented residual converges to zero.

source
JosephsonCircuits.mnavalidatekcl Method
julia
mnavalidatekcl(F::AbstractVector, x::AbstractVector,
    gaugeindices::Vector{Int}, Nnodal::Int, bnm::AbstractVector, atol)

Validate the original, ungauged Kirchhoff current law equations at a converged solution by reconstructing their residuals with mnaungaugedkcl and comparing their infinity norm against a block-relative infinity-norm tolerance,

10*atol*(1 + norm(bnm[1:Nnodal], Inf)),

so both sides have the same per-row interpretation and the accepted error in any one equation does not grow with the number of driven rows. The tolerance is deliberately independent of the achieved augmented residual (which would be circular) and of the auxiliary current entries of the state, which are not Kirchhoff current law quantities. (With the solver inductance scale of calcsolverscale the auxiliary entries are of order one; under the earlier mean-inductance scale they reached ~1e9 in inductor free circuits, which motivated this exclusion.) A non-finite reconstructed norm, or a non-finite source scale (which would make the tolerance infinite and accept anything), fails the validation. Returns (ok, normkcl, kcltol) so a diagnostic can report the achieved residual against the applied tolerance.

source
JosephsonCircuits.modebandmask Method
julia
modebandmask(Amatrixmodes::AbstractMatrix, p)

Return the Nmodes x Nmodes boolean matrix of mode coupling blocks retained by a bandwidth restriction on the harmonic offset: the block coupling column mode m2 into row mode m1 is kept when the offset between them, Amatrixmodes[m1, m2] = modes[m1] .- modes[m2], is within p.

This is the restriction the structure of the Jacobian asks for. Multiplication by cos(phi(t)) is a convolution in the harmonic index, so the nonlinear part of the Jacobian is block Toeplitz in the offset m1 - m2: every block shares the junction incidence sparsity and they differ only by the Fourier coefficient of cos(phi(t)) at that offset. Those coefficients are Bessel-like in the junction phase amplitude and fall off quickly once the offset exceeds it, so truncating by offset keeps the large blocks and drops the small ones.

Truncating by column, as modecouplingmask does, cuts across the Toeplitz structure instead: a retained column keeps one large block and a whole column of small ones, and drops large blocks elsewhere. Measured at equal fill the difference is not marginal. On an eight mode, eight junction chain driven to max|phi| = 1.9 rad, a bandwidth of one converges the linear solves of a Newton path in 118 GMRES iterations while a two column selection with the same number of stored nonzeros fails to converge in 1051.

p may be

  • an Integer: the number of offset shells retained beyond the diagonal, where a shell is one distinct value of the total intermodulation order sum(abs, offset) that the retained mode set actually realizes, or

  • an NTuple{N,Integer}: an absolute per-tone bound, abs.(offset) .<= p, for a grid whose coupling is anisotropic, eg. a strong pump and a weak second tone.

Counting shells rather than bounding the raw offset matters, because the offsets a mode set realizes are not the integers. With the usual odd-harmonic-only truncation every mode difference is even, so sum(abs, offset) <= 1 retains exactly what <= 0 does and a raw bound of one would silently be the block diagonal. A shell count is also the quantity the coupling decays in: the Fourier coefficients of cos(phi(t)) live on the harmonic lattice of phi, and the shells are the lattice distances that lattice actually has.

p = 0 is the mode block diagonal and a p large enough to cover the grid is the full Jacobian, so the bandwidth is a graded ladder between the two rather than the jump escalatepreconditioner! had to make when the only alternatives were a column set and the whole operator.

Examples

julia
julia> modes = [(-1,), (0,), (1,)];

julia> A = [modes[i] .- modes[j] for i in 1:3, j in 1:3];

julia> JosephsonCircuits.modebandmask(A, 0)
3×3 Matrix{Bool}:
 1  0  0
 0  1  0
 0  0  1

julia> JosephsonCircuits.modebandmask(A, 1)
3×3 Matrix{Bool}:
 1  1  0
 1  1  1
 0  1  1
source
JosephsonCircuits.modeclusters Method
julia
modeclusters(keep::AbstractMatrix{Bool})

The connected components of two or more modes of the coupling graph whose edges are the off-diagonal true entries of keep, read symmetrically; each as its sorted mode list.

source
JosephsonCircuits.modecouplingmask Method
julia
modecouplingmask(Nmodes::Integer, couplingmodes)

Return the Nmodes x Nmodes boolean matrix of mode coupling blocks retained by the preconditioner of ModeCouplingPreconditioner: the block coupling column mode m2 into row mode m1 is kept when m2 is one of the couplingmodes or when m1 == m2.

In the block partition into the retained set S = couplingmodes and the shell E (everything else) this is

julia
[A_SS   0  ]
[A_ES   D_E]

which is block lower triangular: the soft block with all of its internal coupling, the mode diagonal blocks of the stiff shell, and the one way coupling which carries the soft correction into the stiff equations. It is therefore the multiplicative block Gauss-Seidel sweep (solve the soft block, then each stiff mode against a residual updated by what the soft block just did) expressed as a matrix, and a sparse LU of it is that sweep: the block triangular form permutation of KLU discovers the structure and factorizes only the diagonal blocks, so the factorization costs one factorization of A_SS plus one small factorization per stiff mode, and the forward substitution of the solve applies A_ES.

The two extremes are the endpoints of the accuracy/cost trade: couplingmodes containing every mode keeps every coupling and gives the full Jacobian (an exact preconditioner and a direct solve), while an empty couplingmodes keeps only the mode diagonal and gives the block diagonal (one small factorization per mode and no coupling at all).

The upper triangle A_SE is the part which is dropped. That choice, rather than the transposed one, is what makes the stiffness of E useful: the error of the preconditioned operator carries a factor of the stiff shell's inverse, which is small precisely because those modes are stiff. Which modes go in S is the caller's, not chosen here: see the couplingmodes argument of ModeCouplingPreconditioner.

Examples

julia
julia> JosephsonCircuits.modecouplingmask(3, [2])
3×3 Matrix{Bool}:
 1  1  0
 0  1  0
 0  1  1

julia> JosephsonCircuits.modecouplingmask(3, Int[])
3×3 Matrix{Bool}:
 1  0  0
 0  1  0
 0  0  1
source
JosephsonCircuits.modes_ports_to_ports_modes_block Method
julia
modes_ports_to_ports_modes_block(S::AbstractMatrix,Nmodes::Int)

Examples

julia
S = [:S11 :S12 :S13 :S14 :S15 :S16 :S17 :S18; :S21 :S22 :S23 :S24 :S25 :S26 :S27 :S28; :S31 :S32 :S33 :S34 :S35 :S36 :S37 :S38; :S41 :S42 :S43 :S44 :S45 :S46 :S47 :S48; :S51 :S52 :S53 :S54 :S55 :S56 :S57 :S58; :S61 :S62 :S63 :S64 :S65 :S66 :S67 :S68; :S71 :S72 :S73 :S74 :S75 :S76 :S77 :S78; :S81 :S82 :S83 :S84 :S85 :S86 :S87 :S88]
JosephsonCircuits.modes_ports_to_ports_modes_block(S,2)

# output
8×8 Matrix{Symbol}:
 :S11  :S13  :S12  :S14  :S15  :S17  :S16  :S18
 :S31  :S33  :S32  :S34  :S35  :S37  :S36  :S38
 :S21  :S23  :S22  :S24  :S25  :S27  :S26  :S28
 :S41  :S43  :S42  :S44  :S45  :S47  :S46  :S48
 :S51  :S53  :S52  :S54  :S55  :S57  :S56  :S58
 :S71  :S73  :S72  :S74  :S75  :S77  :S76  :S78
 :S61  :S63  :S62  :S64  :S65  :S67  :S66  :S68
 :S81  :S83  :S82  :S84  :S85  :S87  :S86  :S88
source
JosephsonCircuits.modes_ports_to_ports_modes_pair Method
julia
modes_ports_to_ports_modes_pair(S::AbstractMatrix,Nmodes::Int)

Examples

julia
S = [:S11 :S12 :S13 :S14 :S15 :S16 :S17 :S18; :S21 :S22 :S23 :S24 :S25 :S26 :S27 :S28; :S31 :S32 :S33 :S34 :S35 :S36 :S37 :S38; :S41 :S42 :S43 :S44 :S45 :S46 :S47 :S48; :S51 :S52 :S53 :S54 :S55 :S56 :S57 :S58; :S61 :S62 :S63 :S64 :S65 :S66 :S67 :S68; :S71 :S72 :S73 :S74 :S75 :S76 :S77 :S78; :S81 :S82 :S83 :S84 :S85 :S86 :S87 :S88]
JosephsonCircuits.modes_ports_to_ports_modes_pair(S,2)

# output
8×8 Matrix{Symbol}:
 :S11  :S12  :S15  :S16  :S13  :S14  :S17  :S18
 :S21  :S22  :S25  :S26  :S23  :S24  :S27  :S28
 :S51  :S52  :S55  :S56  :S53  :S54  :S57  :S58
 :S61  :S62  :S65  :S66  :S63  :S64  :S67  :S68
 :S31  :S32  :S35  :S36  :S33  :S34  :S37  :S38
 :S41  :S42  :S45  :S46  :S43  :S44  :S47  :S48
 :S71  :S72  :S75  :S76  :S73  :S74  :S77  :S78
 :S81  :S82  :S85  :S86  :S83  :S84  :S87  :S88
source
JosephsonCircuits.modes_ports_to_ports_modes_perm Method
julia
modes_ports_to_ports_modes_perm(Nports,Nmodes)

Return a permutation vector that converts one axis of a scattering matrix with Nports ports and Nmodes modes from (mode,port) ordering to a (port,mode) ordering. For example, for 2 ports with indices 1,2 and 4 modes with indices 1,2,3,4 then (mode,port) order is: [(1,1),(1,2),(1,3),(1,4),(2,1),(2,2),(2,3),(2,4)] and (port,mode) order is: [(1,1),(1,2),(2,1),(2,2),(3,1),(3,2),(4,1),(4,2)] The permutation to change the first into the second is in the example below:

Examples

julia
julia> p = JosephsonCircuits.modes_ports_to_ports_modes_perm(2,4)
8-element Vector{Int64}:
 1
 5
 2
 6
 3
 7
 4
 8
source
JosephsonCircuits.modes_ports_to_ports_modes_scattering Method
julia
modes_ports_to_ports_modes_scattering(S::AbstractMatrix,Nmodes::Int)

Examples

julia
S = [:S11 :S12 :S13 :S14 :S15 :S16 :S17 :S18; :S21 :S22 :S23 :S24 :S25 :S26 :S27 :S28; :S31 :S32 :S33 :S34 :S35 :S36 :S37 :S38; :S41 :S42 :S43 :S44 :S45 :S46 :S47 :S48; :S51 :S52 :S53 :S54 :S55 :S56 :S57 :S58; :S61 :S62 :S63 :S64 :S65 :S66 :S67 :S68; :S71 :S72 :S73 :S74 :S75 :S76 :S77 :S78; :S81 :S82 :S83 :S84 :S85 :S86 :S87 :S88]
JosephsonCircuits.modes_ports_to_ports_modes_scattering(S,2)

# output
8×8 Matrix{Symbol}:
 :S11  :S13  :S15  :S17  :S12  :S14  :S16  :S18
 :S31  :S33  :S35  :S37  :S32  :S34  :S36  :S38
 :S51  :S53  :S55  :S57  :S52  :S54  :S56  :S58
 :S71  :S73  :S75  :S77  :S72  :S74  :S76  :S78
 :S21  :S23  :S25  :S27  :S22  :S24  :S26  :S28
 :S41  :S43  :S45  :S47  :S42  :S44  :S46  :S48
 :S61  :S63  :S65  :S67  :S62  :S64  :S66  :S68
 :S81  :S83  :S85  :S87  :S82  :S84  :S86  :S88
source
JosephsonCircuits.modeslotindex Method
julia
modeslotindex(layout::ModeLayout)

The vector, of length layout.rdim, giving the mode index of each slot of the real representation.

source
JosephsonCircuits.modevalue Method
julia
modevalue(v, w)

The value a linear term matrix entry contributes in a column belonging to a mode with (signed) frequency w: the stored value for the non negative frequency modes and its complex conjugate for the negative frequency modes. This is the single definition of the negative frequency conjugation convention, used by conjnegfreq! (which bakes it into a matrix), by the vector method of sparseaddconjsubst! (which applies it during assembly; the Diagonal method still conjugates through its conjflag), and by sensitivitystampvalue (which applies it to the sensitivity stamps).

source
JosephsonCircuits.move_bedge! Method
julia
move_bedge!(g,dst_node,dst_node_new,edge_index,fadjlist1,fadjlist2)

Move an edge from graph g at destination node dst_node to the new destination node dst_node_new with the edge index edge_index in the backwards adjacency list. Also perform the same operations on the forward adjacency lists fadjlist1 and fadjlist2.

Examples

julia
julia> g=JosephsonCircuits.Graphs.SimpleDiGraphFromIterator(JosephsonCircuits.tuple2edge([(1,1),(2,1),(2,3)]));JosephsonCircuits.move_bedge!(g,1,2,1,deepcopy(g.fadjlist),deepcopy(g.fadjlist));g.badjlist
3-element Vector{Vector{Int64}}:
 [2]
 [1]
 [2]
source
JosephsonCircuits.move_bedges! Method
julia
move_bedges!(g,dst_node,dst_node_new,fadjlist1,fadjlist2)

Move the edges from graph g at destination node dst_node to the new destination node dst_node_new in the backwards adjacency list. Also perform the same operations on the forward adjacency lists fadjlist1 and fadjlist2.

Examples

julia
julia> g=JosephsonCircuits.Graphs.SimpleDiGraphFromIterator(JosephsonCircuits.tuple2edge([(1,1),(2,1),(2,3)]));JosephsonCircuits.move_bedges!(g,1,2,deepcopy(g.fadjlist),deepcopy(g.fadjlist));g.badjlist
3-element Vector{Vector{Int64}}:
 []
 [2, 1]
 [2]
source
JosephsonCircuits.move_edges! Method
julia
move_edges!(g,node,node_new,fadjlist1,fadjlist2)

Move the edges from graph g at node node to the new node node_new. Also perform the same operations on the forward adjacency lists fadjlist1 and fadjlist2.

Examples

julia
julia> g=JosephsonCircuits.Graphs.SimpleDiGraphFromIterator(JosephsonCircuits.tuple2edge([(1,1),(2,1),(2,3)]));JosephsonCircuits.move_edges!(g,1,2,deepcopy(g.fadjlist),deepcopy(g.fadjlist));g.fadjlist
3-element Vector{Vector{Int64}}:
 []
 [3, 2, 2]
 []
source
JosephsonCircuits.move_fedge! Method
julia
move_fedge!(g,src_node,src_node_new,edge_index,fadjlist1,fadjlist2)

Move an edge from graph g at source node src_node to the new source node src_node_new with the edge index edge_index in the forward adjacency list. Also perform the same operations on the forward adjacency lists fadjlist1 and fadjlist2.

Examples

julia
julia> g=JosephsonCircuits.Graphs.SimpleDiGraphFromIterator(JosephsonCircuits.tuple2edge([(1,1),(2,1),(2,3)]));JosephsonCircuits.move_fedge!(g,1,2,1,deepcopy(g.fadjlist),deepcopy(g.fadjlist));g.fadjlist
3-element Vector{Vector{Int64}}:
 []
 [1, 3, 1]
 []
source
JosephsonCircuits.move_fedges! Method
julia
move_fedges!(g,src_node,src_node_new,fadjlist1,fadjlist2)

Move the edges from graph g at source node src_node to the new source node src_node_new in the forward adjacency list. Also perform the same operations on the forward adjacency lists fadjlist1 and fadjlist2.

Examples

julia
julia> g=JosephsonCircuits.Graphs.SimpleDiGraphFromIterator(JosephsonCircuits.tuple2edge([(1,1),(2,1),(2,3)]));JosephsonCircuits.move_fedges!(g,1,2,deepcopy(g.fadjlist),deepcopy(g.fadjlist));g.fadjlist
3-element Vector{Vector{Int64}}:
 []
 [1, 3, 1]
 []
source
JosephsonCircuits.mutual_to_even_odd Method
julia
mutual_to_even_odd(L, Cmutual)

Return the even and odd mode impedances and the even and odd mode indices from the inductance matrix L and the mutual capacitance matrix Cmutual.

Examples

julia
C = [1.0e-12 1.0e-13; 1.0e-13 1.0e-12]
L = [1.0e-9 1.0e-10; 1.0e-10 1.0e-9]
Zeven, Zodd, neven, nodd = JosephsonCircuits.mutual_to_even_odd(L,C)
@show Zeven
@show Zodd
@show neven
@show nodd
;

# output
Zeven = 33.166247903554
Zodd = 27.386127875258307
neven = 0.0099429909816438
nodd = 0.009852185508991206
source
JosephsonCircuits.mutual_to_maxwell Method
julia
mutual_to_maxwell(C::AbstractMatrix)

Return the Maxwell capacitance matrix from the mutual capacitance matrix C.

The Maxwell capacitance Cmaxwell is the relationship between charge and voltage on each node, Q = C V or dQi/dVj = C_ij where C is the Maxwell capacitance matrix.

Each element of the mutual capacitance matrix Cmutual is the value of a physical capacitor placed between two nodes in a circuit or between a node and ground.

Examples

julia
julia> C = [0.9 0.1;0.1 1.9];JosephsonCircuits.mutual_to_maxwell(C)
2×2 Matrix{Float64}:
  1.0  -0.1
 -0.1   2.0
source
JosephsonCircuits.mutualorientations Method
julia
mutualorientations(componenttypes::Vector{Symbol},
    nodeindices::Matrix{Int}, componentnamedict::Dict,
    mutualinductorbranchnames::Vector, edge2indexdict::Dict,
    Rbn::SparseMatrixCSC, Nbranches)

The orientation of each mutual coupling, in the order the couplings appear in componenttypes: 1 where both coupled branches carry the currents the netlist declared, and -1 where the graph turned exactly one of them around.

An orientation depends on the declared terminal order and on the orientation the incidence matrix gave each branch, and on no value, so a CircuitMatrixPlan holds it across refills; only K and the two self inductances are read again.

source
JosephsonCircuits.ncomponents Method
julia
ncomponents(c::CompiledCircuit)

The number of entries in the flat component table.

source
JosephsonCircuits.needsadjointsolve Function
julia
needsadjointsolve(arrays::LinearizedArrays,
    noiseportimpedanceindices, noiseplan = nothing)

Whether the transposed (adjoint) linearized system must be solved at each signal frequency: for the scattering parameter sensitivities always, and otherwise when a consumer of the adjoint solution (the noise scattering parameters, the quantum efficiency, the commutation relations, or the adjoint node outputs) is requested together with a source of it. The dissipative scattering blocks of a ScatteringNoisePlan are such a source, as the lumped noise ports are.

This does not depend on the frequency, and both the host loop and the device sweep test it, the latter to decide whether to allocate and solve the adjoint direction at all (with cuDSS a whole second factorization, with a block factorization a second solve against the same factors).

source
JosephsonCircuits.negsecondat Method
julia
negsecondat(r::JunctionRelations, phi)

The negative of the second derivative of the relation of every junction at the branch phases phi, sin.(phi) for the Josephson relation: the change of the differential inductance with the phase, which the derivative of a linearization with respect to the phases carries. The counterpart of derivativeat.

source
JosephsonCircuits.ninstances Method
julia
ninstances(elab::ElaboratedCircuit)

The number of flattened primitive instances.

source
JosephsonCircuits.nlsolve! Method
julia
nlsolve!(fj!, F, J, x; iterations = 1000, atol = 1e-8, rtol = 0.0,
    factorization = KLUfactorization(), label = "",
    linesearch = Backtracking(), andersondepth = 5, andersonbeta = 1.0,
    andersonacceptfactor = 0.9)

Newton's method with a line search and Anderson acceleration, suited to quasi-Newton problems with an approximate Jacobian. fj!(F, J, x) must write the residual into F when F !== nothing and the Jacobian into J when J !== nothing. x is updated in place and holds the solution on return; F holds the residual there.

Each iteration solves J*pₖ = -F for the Newton step and forms the Type-II Anderson correction cₖ = (Sₖ + Yₖ)γₖ from a depth- andersondepth history of iterate and update differences (the Newton fixed point map G(x) = x + pₖ has fixed point residual pₖ, which is stored). The step is then chosen by measurement:

  1. The Anderson candidate x + pₖ - andersonbeta*cₖ is evaluated, and

accepted if its residual norm improves on the current one by at least andersonacceptfactor. An accepted candidate records alpha = NaN.

  1. Otherwise both line searches are run and compared: the curvilinear path

x + α*pₖ - andersonbeta*α²*cₖ, starting from the value of (1), and the linear path x + α*pₖ; the point with the lower merit function is taken. A curvilinear trial point which satisfies the Armijo condition at the full step is accepted without comparison. After both line searches have failed the solver gives the curved path priority, taking the linear path only when the curved one produces non-finite values. See dualsearch!.

  1. Without a usable correction (an empty history, or a failed coefficient

solve) only the linear line search runs.

Keywords

  • iterations = 1000: the maximum number of Newton iterations.

  • atol = 1e-8: converged when norm(F) <= atol.

  • rtol = 0.0: a relative tolerance; the effective tolerance is max(atol, rtol*norm(F0)) with F0 the initial residual.

  • factorization = KLUfactorization(): the sparse factorization of J.

  • label = "": label for the returned IterationInfo.

  • linesearch = Backtracking(): the Backtracking of every search of the iteration, the curvilinear one included: the Armijo constant, the safeguards, the trial budget, whether a backtrack is fitted or halved, and the count of consecutive failed searches which is a stall.

  • andersondepth = 5: the history depth; 0 disables the acceleration.

  • andersonbeta = 1.0: correction strength.

  • andersonacceptfactor = 0.9: candidate accept threshold, in (0, 1); smaller is stricter.

Returns an IterationInfo with per-iteration diagnostics: normresidual (residual norms, starting at the initial point), alpha (step lengths; NaN marks an accepted candidate), backtracks (trial evaluations after each iteration's first), andersonaccepted (true when the taken step lies on the curved path), and reason, why the iteration ended: :converged, :iterations, :linesearch (no decrease at all, or two consecutive steps short of the Armijo condition), or :progress (the residual stopped coming down and its rate is not improving, residualstalled); see stallmessage.

source
JosephsonCircuits.nlsolvekrylov! Method
julia
nlsolvekrylov!(fj!, jvp!, F, x, pc::AbstractPreconditioner,
    method::NewtonKrylov = NewtonKrylov(); iterations = 1000,
    atol = 1e-8, rtol = 0.0, workspace = nothing, label = "")

Inexact (Newton-Krylov) solver for a real system: the Newton step is taken from gmres! on the exact matrix-free product jvp!(y, v) rather than from a factorization of an assembled Jacobian. fj!(F, J, x) evaluates the residual and Jacobian as in nlsolve!, accepting nothing for either. x is updated in place and F holds the residual at the returned x.

The Jacobian enters only through jvp! and through the right preconditioner pc (see AbstractPreconditioner), so a preconditioner much cheaper than the Jacobian makes each Newton step much cheaper than a direct one. ModeCouplingPreconditioner is the harmonic balance Jacobian with its mode coupling restricted, and is exact when every mode is retained.

The linear solver of the Newton step, the refresh policy and the escalation are the linearsolver, refresh and escalate of method, a NewtonKrylov whose preconditioner and precision are not read here: the preconditioner is pc, built by the caller.

pc is rebuilt according to refresh: before every step for Always, by the measured rule of Probe, and for Never only when forced. A rebuild is forced regardless of the policy when a solve makes progress but misses its tolerance, when a step is not a descent direction, when the line search finds no decrease, and after a successful escalation. The linear tolerance follows the Eisenstat-Walker choice 2 forcing sequence krylovgamma*(|F_k|/|F_{k-1}|)^krylovalpha clamped to [krylovrtolmin, krylovrtolmax], with an absolute floor of atol/10 so late solves are not pushed below the nonlinear tolerance. Because the assembled Jacobian can be stale, the linesearch slope is always taken from an exact matrix-free product, and a non-descent direction falls back to the exact Newton step through a fresh factorization before the iteration is declared stalled.

The globalization is the plain damped-Newton path of nlsolve!: the backtracking_linesearch! of nlsolve! with the method's Backtracking, which on Armijo failure still takes the best decreasing trial, with consecutive failures counted against its maxfailures and a no-decrease step retried once from a fresh preconditioner before stopping. There is deliberately no Anderson acceleration here: the Krylov steps are near-exact Newton steps, and the solver is kept simple.

Keywords

  • iterations = 1000: the maximum number of Newton iterations.

  • atol = 1e-8: converged when norm(F) <= atol.

  • rtol = 0.0: an additional relative test, norm(F) <= rtol*norm(F0) with F0 the initial residual, satisfied when either holds. A residual whose terms are of size s cannot be driven below about eps*s however exact the step, so an absolute tolerance is a statement about the problem's units; a relative one is not.

  • workspace = nothing: a Ref holding the KrylovVectors of a previous solve of the same system, or holding nothing, in which case the vectors are allocated and stored into it for the next solve. With no Ref at all they are allocated and dropped.

  • label = "": the label of the returned IterationInfo.

And, read off method: linearsolver, the linear solver of the Newton step, a GMRES or a KrylovJL; refresh, when the preconditioner is rebuilt, Always before every step, by the measured rule of Probe, or Never except when forced (either way a solve which made progress but missed its tolerance, a non-descent direction, a line search with no decrease and a successful escalation force a rebuild); and escalate, whether a preconditioner which makes progress but fails to reach its tolerance is escalated (see escalatepreconditioner!) rather than tried again, within the memory the grown factors are predicted to take; a refused escalation is recorded (escalationrequested in the Krylov record) and the solve carries on.

The forcing sequence is Eisenstat-Walker choice 2 with gamma = 0.9 and alpha = (1 + sqrt(5))/2, clamped to [1e-10, 0.9] and started at 0.3; a solve which does not bring the linear residual below 0.9 of the residual norm is treated as stagnated and the preconditioner solve taken as the step; and a solve whose residual came down by less than 0.5 per Arnoldi step is reported to the preconditioner as slow (stalled!; off under Never, which also disables the count rule). These are fixed: none has been changed in any measured case, and each was set by the inexact Newton theory or by a measurement recorded beside it. The line search is the method's Backtracking, interpolating by default. Two budgets bound the work: iterations Newton steps, and iterations restart lengths of Arnoldi steps in total, so that a preconditioner which runs every linear solve to its limit cannot turn the step budget into hours. A residual which has stopped coming down, or comes down too slowly to reach the tolerance within the remaining budget, and whose rate is not improving (residualstalled) gets one recovery, a rebuilt preconditioner and exact Newton steps from then on, and ends the solve if it persists.

These are the settings hbnlsolve runs with; a caller changes them through the NewtonKrylov method object (preconditioner, linearsolver, refresh, escalate, linesearch, precision) and through hbnlsolve's own iterations, atol and rtol.

Returns an IterationInfo with the same per-iteration diagnostics as nlsolve! (the andersonaccepted record is always false) and a reason of :converged, :iterations, :work (the Arnoldi budget was spent), :linesearch (no decrease twice, or a direction which is not a descent direction after the exact rescue), or :progress.

source
JosephsonCircuits.nnets Method
julia
nnets(elab::ElaboratedCircuit)

The number of nets including the ground net.

source
JosephsonCircuits.nodalstampplan Method
julia
nodalstampplan(c::CompiledCircuit, group, Nnodes; invert = false)

Build the NodalStampPlan of a two terminal group.

group is a vector of flat component indices, so the same function plans the capacitance from the capacitors and the conductance from the resistors and the port environments alike.

source
JosephsonCircuits.noderenumbering Method
julia
noderenumbering(order)

The renumbering induced by the sorting permutation order returned by calcnodesorting: renumber[j] is the new index of the node whose old index was j. compile uses it to renumber the node indices of scattering blocks, which have no component table entry to be re-read from.

source
JosephsonCircuits.nodevariabletokeyed Method
julia
nodevariabletokeyed(nodevariable, outputmodes, nodenames, inputmodes,
    inputportnumbers, w)

Convert a node variable array nodevariable (such as node flux or node voltage) vs frequency w to a keyed array. Return the keyed array.

Examples

julia
julia> JosephsonCircuits.nodevariabletokeyed([1 2;3 4;;;],[(0,),(1,)],["0","1"],[(0,),(1,)],[1],[1.0])
5-dimensional KeyedArray(NamedDimsArray(...)) with keys:
   outputmode  2-element Vector{Tuple{Int64}}
   node  1-element Vector{String}
◪   inputmode  2-element Vector{Tuple{Int64}}
▨   inputport  1-element Vector{Int64}
▨   freqindex  1-element UnitRange{Int64}
And data, 2×1×2×1×1 Array{Int64, 5}:
[:, :, 1, 1, 1] ~ (:, :, (0,), 1, 1):
          ("1")
   (0,)    1
   (1,)    3

[:, :, 2, 1, 1] ~ (:, :, (1,), 1, 1):
          ("1")
   (0,)    2
   (1,)    4
source
JosephsonCircuits.nodevariabletokeyed Method
julia
nodevariabletokeyed(nodevariable::AbstractVector, nodenames)

Convert a node variable with one value per node, such as the average direct current voltage, to a keyed array.

nodevariable excludes ground, as every node keyed output does, so it is keyed by nodenames[2:end] exactly as the node flux is.

source
JosephsonCircuits.nodevariabletokeyed Method
julia
nodevariabletokeyed(nodevariable, outputmodes, nodenames)

Convert a node variable array nodevariable (such as node flux or node voltage) to a keyed array. Return the keyed array.

Examples

julia
julia> JosephsonCircuits.nodevariabletokeyed([1 2;3 4],[(0,),(1,)],["0","1","2"])
2-dimensional KeyedArray(NamedDimsArray(...)) with keys:
   outputmode  2-element Vector{Tuple{Int64}}
   node  2-element Vector{String}
And data, 2×2 Matrix{Int64}:
          ("1")  ("2")
   (0,)    1      2
   (1,)    3      4
source
JosephsonCircuits.noisechannelnames Method
julia
noisechannelnames(componentnames, noiseportimpedanceindices, noiseplan,
    ssys)

The name of each row of the noise scattering matrix: the dissipative lumped components first, then the channels of the dissipative scattering blocks.

source
JosephsonCircuits.noisechannelsigns Method
julia
noisechannelsigns(noiseportimpedanceindices, noiseplan, ssys)

The sign kind of each channel of the noise scattering matrix in the commutation relations, in the order noisechannelnames gives them, or nothing when every channel is of the first kind: 1 for a channel which emits like a mode in its vacuum, whose rows count with the sign of their mode frequency; -1 for a channel of the conjugate kind, the second half of the channels of a block which states its noise (see ScatteringNoisePlan), whose rows count with the opposite sign, since what it emits is the conjugate of a mode; and 2 and -2 for the channels of a pumped block which states its noise, which span all its modes at once, so that every row of one counts with the fixed sign of its kind (see pumpedblocknoisewaves!).

source
JosephsonCircuits.noisechanneltemperatures Method
julia
noisechanneltemperatures(psc::CompiledCircuit,
    noiseportimpedanceindices, noiseplan, ssys, temperature)

The temperature of each row of the noise scattering matrix, in the order noisechannelnames gives them.

temperature is the analysis default, which every dissipative element takes unless it states one of its own. A lumped component states it as Resistor(R; temperature = T) and a ScatteringParameters as noise = ThermalEquilibrium(T), both of which are recorded by compile as it lowers the circuit. Only the typed circuit format carries them; a netlist of tuples states none and everything in it takes the default.

The channels of a block which states its noise with a NoiseCovariance are at zero temperature: the covariance it states is the whole of its noise, and the occupation of one is what leaves it so.

source
JosephsonCircuits.noisecovariance! Method
julia
noisecovariance!(L, off, n, S, soff)

The vacuum noise covariance I - S S' of an n port block, into the length n*n column major block of L at off, from the scattering matrix in the same layout at soff in S.

Only the lower triangle is written, which is all psdcholesky! reads: the covariance is Hermitian.

source
JosephsonCircuits.noiseindices Method
julia
noiseindices(c::CompiledCircuit, values)

The flat table indices of the internal dissipative components, which are the noise channels of the linearized analysis: every resistor which is not a port's own termination, and every capacitor or inductor whose resolved value in values has a nonzero imaginary part.

A port termination is an external bath rather than an internal channel and is excluded by its role; any other resistor across a port's nodes is an ordinary device resistor and is included.

source
JosephsonCircuits.noiseoccupation! Method
julia
noiseoccupation!(occupation, temperatures::AbstractVector, wmodes, Nmodes)

Fill occupation with 2*nbar + 1 for each row of the noise scattering matrix, whose rows run over the noise channels with the modes innermost.

This is what a channel's vacuum share of the noise is multiplied by to get the noise it actually carries. It is applied where the noise power is asked for, by calcqe! and by the noise covariance, and never to Snoise itself, which is a scattering matrix and does not depend on temperature. The commutation relations, which are a statement about the transformation rather than about the state of anything, therefore do not see it at all.

temperatures is one temperature per noise channel, in the order noisechannelnames gives them. nothing, and every temperature being zero, both give all ones.

source
JosephsonCircuits.noiseoutputwavekernel! Method
julia
noiseoutputwavekernel!

The output power waves at the noise ports, from the adjoint solution, one work item per (noise port, mode, right hand side).

This is calcinputoutputnoise! restricted to its output waves, which is all of it that reads a solution: the input waves come from the source terms alone and are computed on the host.

source
JosephsonCircuits.noisereduction! Function
julia
noisereduction(Snoise::AbstractMatrix, w, occupation = nothing,
    channelsigns = nothing)
noisereduction!(noise::NoiseReduction, Snoise, w, occupation = nothing,
    channelsigns = nothing)

Reduce the noise scattering matrix Snoise, a row per noise channel mode and a column per output port mode, to the two sums the quantum efficiency and the commutation relations read; see NoiseReduction. w holds the mode frequencies, the mode of row c being (c-1) % length(w) + 1, occupation the occupation of each row, one everywhere when nothing, and channelsigns the sign kind of each channel, the channel of row c being (c-1) ÷ length(w) + 1, in the second sum, one everywhere when nothing: 1 and -1 multiply the sign of the row's mode frequency, 2 and -2 are the fixed signs 1 and -1 (see noisechannelsigns). Each sum is compensated (Kahan-Babuska-Neumaier).

Examples

julia
julia> n = JosephsonCircuits.noisereduction([1 2; 3 4; 5 6; 7 8], [1, -1]); (n.denom, n.signed)
([84.0, 120.0], [-32.0, -40.0])

julia> n = JosephsonCircuits.noisereduction([1 2; 3 4; 5 6; 7 8], [1, -1], nothing, [1.0, -1.0]); (n.denom, n.signed)
([84.0, 120.0], [16.0, 16.0])
source
JosephsonCircuits.nonlinearmatrices Method
julia
nonlinearmatrices(nm::CircuitMatrices, w, componenttypes, wmodes,
    symfreqvar)

The linear term of the nonlinear solve from the circuit matrices nm: the solver scale (see calcsolverscale), and the capacitance, conductance and inverse inductance matrices with the mode frequencies wmodes substituted into frequency dependent values, the entries of the negative frequency modes conjugated and the rows scaled, as SparseMatrixCSC{ComplexF64,Int} whatever the element types of nm; the branch vectors and the port lists come along. A stage of its own in front of nonlinearsetup, so that the setup and everything after it is compiled once for every way the circuit's values were typed rather than once per combination of them.

source
JosephsonCircuits.nonlinearoutputs Method
julia
nonlinearoutputs(; info, dcsol, dccanonical, w, frequencies, atol,
    symfreqvar, keyedarrays, returnoperatingpoint, ...)

The NonlinearHB of a solve: the checks on the accepted point (the ungauged Kirchhoff current law, the junctions' direct current), the node fluxes and the scattering parameters at the pump modes, keyed when asked, the operating point with its assembled Jacobian when asked, and the direct current node voltages. The remaining keywords are the fields of nonlinearsetup this stage reads, and info, dcsol and dccanonical what the solve returned.

source
JosephsonCircuits.nonlinearsetup Method
julia
nonlinearsetup(w, sources, frequencies, indices, psc, cg, m, x0,
    symfreqvar, backend, precision, reuse; needjx, needjr, devicex,
    realrepresentation, sensitivitynames)

Everything the nonlinear solve of hbnlsolve needs before a method is applied: the mode frequencies and the checks on them, the scaled and frequency substituted linear term, the modified nodal analysis augmentation with its direct current block, the initial value in the real representation, the assembled Jacobians the method asked for (needjx the complex one, needjr the real one, devicex the complex one on the backend), the HBSystem with its residual closures fj! and fjreal!, and the canonical work of an explicit direct current block. reuse is an HBReuse whose objects are taken over, or nothing.

Returned as a named tuple, whose fields the solve and the outputs stages read by name; it is the seam between them. This stage depends on the tone count, the matrices, the precision, the backend and the reuse, and not on the method, so a solve with a different method compiles it again only when one of those differs.

source
JosephsonCircuits.norm2 Method
julia
norm2(v::AbstractVector)

The Euclidean norm of v, formed through the inner product.

LinearAlgebra.norm scales its argument before squaring so that an entry cannot overflow or underflow on its way to the sum. That guard is not free on a device: cuBLAS routes a Float64 vector to a scaled nrm2 kernel which runs at a small fraction of memory bandwidth, measured at 22.9 us against 2.7 us for a dot product of the same 51,200 element vector on an RTX 4090, and it is the largest single device kernel of a double precision solve. In single precision cuBLAS selects a different kernel and the gap is gone.

The substitution is made only where it pays and only where it is safe, which is the same place: Float64.

  • In double precision cuBLAS routes norm to a scaled nrm2 kernel that runs at well under a tenth of memory bandwidth, measured at 55.6 us against 14.5 us for sqrt(dot(v, v)) on a 51,200 element device vector, and it was the largest single device kernel of a double precision solve.

  • In single precision cuBLAS selects a different kernel and the two are within 20% of each other, so there is nothing to win. Single precision is also where the exponent range is narrowest and the guard is worth the most.

So Float32 keeps norm and everything else goes through the inner product, and the change is confined to the precision where the trade is favorable in both directions. Anything not covered by the AbstractFloat method – complex vectors, other element types – falls back to norm as well.

The vectors this is applied to are carried at the scale of the harmonic balance residual of a nondimensionalized system, which runs from a few units down to the solver tolerance. Squaring that stays far inside the double precision exponent: overflow would need an entry above 1e154 and underflow to zero an entry below 1e-162.

This is deliberately not exported and not used outside the Krylov solver. Anything whose scale is not controlled should keep using norm.

source
JosephsonCircuits.normalizedefinitions Method
julia
normalizedefinitions(circuitdefs)

The definitions a parameterized value substitutes, as a dictionary keyed by parameter name: keys may be Symbols, Strings or the parameter objects themselves. An entry whose value is not a number cannot be substituted into an expression and is left out, so that a definition which serves another purpose (a component whose value is itself a key, for instance) does not stop every parameterized value from resolving; a parameter left undefined comes back unresolved from valuetonumber.

source
JosephsonCircuits.nterminals Method
julia
nterminals(component)

The number of scalar electrical terminals of a component model. Two terminal lumped components have 2; a ScatteringParameters has two per port; a GaussianChannel has two per mode; a hierarchical Circuit has one per interface pin; a MutualInductor has none because it couples branches, not nets; a Ground instance has one, which is the reference net itself.

source
JosephsonCircuits.numericmatrices Method
julia
numericmatrices(circuit, circuitdefs; Nmodes = 1,
    sorting = defaultsorting(circuit))
numericmatrices(psc::CompiledCircuit, cg::CircuitGraph, circuitdefs;
    Nmodes = 1)
numericmatrices(psc::CompiledCircuit, cg::CircuitGraph, vvn; Nmodes = 1)

The CircuitMatrices of a circuit with its component values resolved to numbers with circuitdefs, at the mode count Nmodes, with every matrix entry repeated Nmodes times along the diagonal. The third form takes the already resolved values vvn, so that a second call at a different mode count (the signal grid of hblinsolve after the pump grid of hbnlsolve) does not resolve them again.

See also CircuitMatrices, numericmatrices, calcCn, calcGn, calcLb,calcLjb, calcMb, calcinvLn, calcLmean, portindicesnumbers, portreferenceimpedances, and noiseindices.

Examples

julia
circuit = Circuit(
    [:p1 => Port(1; Z0 = :Rleft),
     :i1 => CurrentSource(:Ipump),
     :cc => Capacitor(:Cc),
     :jj => JosephsonJunction(:Lj),
     :cj => Capacitor(:Cj),
     :gnd => Ground()],
    [[(:p1, 1), (:i1, 1), (:cc, 1)],
     [(:cc, 2), (:jj, 1), (:cj, 1)],
     [(:p1, 2), (:i1, 2), (:jj, 2), (:cj, 2), (:gnd, 1)]])
circuitdefs = Dict(:Lj => 1000.0e-12, :Cc => 100.0e-15, :Cj => 1000.0e-15, :Rleft => 50.0, :Ipump => 1.0e-8)
JosephsonCircuits.testshow(stdout,numericmatrices(circuit,circuitdefs))

# output
JosephsonCircuits.CircuitMatrices(sparse([1, 2, 1, 2], [1, 1, 2, 2], [1.0e-13, -1.0e-13, -1.0e-13, 1.1e-12], 2, 2), sparse([1], [1], [0.02], 2, 2), sparsevec(Int64[], Float64[], 2), sparsevec(Int64[], Float64[], 2), sparsevec([2], [1.0e-9], 2), sparsevec([2], [1.0e-9], 2), sparse(Int64[], Int64[], Float64[], 2, 2), sparse(Int64[], Int64[], Float64[], 2, 2), sparse([1, 2], [1, 2], [1, 1], 2, 2), [1], [1], [2], Int64[], 1.0e-9, Any[1, 50.0, 1.0e-8, 1.0e-13, 1.0e-9, 1.0e-12])
julia
circuit = Circuit(
    [:p1 => Port(1; Z0 = :Rleft),
     :i1 => CurrentSource(:Ipump),
     :cc => Capacitor(:Cc),
     :jj => JosephsonJunction(:Lj),
     :cj => Capacitor(:Cj),
     :gnd => Ground()],
    [[(:p1, 1), (:i1, 1), (:cc, 1)],
     [(:cc, 2), (:jj, 1), (:cj, 1)],
     [(:p1, 2), (:i1, 2), (:jj, 2), (:cj, 2), (:gnd, 1)]])
circuitdefs = Dict(:Lj => 1000.0e-12, :Cc => 100.0e-15, :Cj => 1000.0e-15, :Rleft => 50.0, :Ipump => 1.0e-8)
psc = JosephsonCircuits.compile(circuit)
cg = JosephsonCircuits.calccircuitgraph(psc)
JosephsonCircuits.testshow(stdout,numericmatrices(psc, cg, circuitdefs))

# output
JosephsonCircuits.CircuitMatrices(sparse([1, 2, 1, 2], [1, 1, 2, 2], [1.0e-13, -1.0e-13, -1.0e-13, 1.1e-12], 2, 2), sparse([1], [1], [0.02], 2, 2), sparsevec(Int64[], Float64[], 2), sparsevec(Int64[], Float64[], 2), sparsevec([2], [1.0e-9], 2), sparsevec([2], [1.0e-9], 2), sparse(Int64[], Int64[], Float64[], 2, 2), sparse(Int64[], Int64[], Float64[], 2, 2), sparse([1, 2], [1, 2], [1, 1], 2, 2), [1], [1], [2], Int64[], 1.0e-9, Any[1, 50.0, 1.0e-8, 1.0e-13, 1.0e-9, 1.0e-12])
source
JosephsonCircuits.nvoltages Method
julia
nvoltages(t::TransportRows)

The number of explicit average voltages, one per floating static flux component.

source
JosephsonCircuits.nwindow Method
julia
nwindow(L::CompositeLayout)

The length of the direct current window.

source
JosephsonCircuits.nzpositions Method
julia
nzpositions(A::SparseMatrixCSC, U::SparseMatrixCSC)

For a matrix A whose stored entries are a subset of those of U, the position in nonzeros(U) of each stored entry of A, in the order of nonzeros(A). Throws if an entry of A has no home in U.

source
JosephsonCircuits.optimum_eigenvalue_angle Method
julia
optimum_eigenvalue_angle(values; target_angle = pi)

For unimodular eigenvalues values, the angle of the midpoint of the widest empty arc between them on the unit circle, and the angle of the rotation which moves that midpoint to target_angle (by default pi, so that no eigenvalue lies near the branch cut of the logarithm). After https://github.com/XanaduAI/thewalrus/pull/403.

Examples

julia
using Plots
t = range(0, , length = 100)
values = randn(Complex{Float64},10)
values ./= abs.(values)
optimum_angle, optimum_rotation = optimum_eigenvalue_angle(values)
shift = exp(im*optimum_rotation)
plot(cos.(t), sin.(t))
plot!(real.(values),imag.(values);seriestype=:scatter)
plot!([cos(optimum_angle)],[sin(optimum_angle)];seriestype=:scatter)
plot!(real.(shift*values),imag.(shift*values);seriestype=:scatter)
source
JosephsonCircuits.pair_to_block Method
julia
pair_to_block(S::AbstractMatrix)
source
JosephsonCircuits.pair_to_block Method
julia
pair_to_block(r::AbstractVector)

Examples

julia
r = [:x1, :p1, :x2, :p2, :x3, :p3, :x4, :p4]
JosephsonCircuits.pair_to_block(r)

# output
8-element Vector{Symbol}:
 :x1
 :x2
 :x3
 :x4
 :p1
 :p2
 :p3
 :p4
source
JosephsonCircuits.pair_to_block2 Method
julia
pair_to_block2(S::AbstractMatrix)
source
JosephsonCircuits.pair_to_block2 Method
julia
pair_to_block2(r::AbstractVector)
source
JosephsonCircuits.pair_to_block_perm Method
julia
pair_to_block_perm(n::Int)

Return a 2n length vector p which permutes the pair operator ordering r = [x_1,p_1,...,x_n,p_n] to the block operator ordering r[p] = (x1,...,xn,p1,...,pn).

Examples

julia
r = [:x1, :p1, :x2, :p2, :x3, :p3, :x4, :p4]
p = JosephsonCircuits.pair_to_block_perm(4)
r[p]

# output
8-element Vector{Symbol}:
 :x1
 :x2
 :x3
 :x4
 :p1
 :p2
 :p3
 :p4
source
JosephsonCircuits.parametergrouping Method
julia
parametergrouping(pairs, componentindices, componenttypes, portordinal)

The grouping of the sensitivity pairs (componentname, parameterindex, alpha) into merged stamps: pairs which share a stamp kind, a design parameter and a port ordinal merge into one contraction. componentindices[i] is the parsed circuit index of pair i. Returns (grouping, slots), the pair indices of each group and the design parameter each group accumulates into.

Computed from the parsed circuit alone, before any stamp exists, because the residual derivative columns and the operating point solves must be merged with the same grouping as the stamps, and both are needed earlier than the stamps are built.

source
JosephsonCircuits.parse_connections_sparse Method
julia
parse_connections_sparse(networks::AbstractVector{Tuple{T,N}},
    connections::AbstractVector{Tuple{T,T,Int,Int}}) where {T,N}

Return the indices of the internal ports porti_indices, the external ports porte_indices, the vector of port tuples ports, the vector of scattering parameter data networkdata, the connection matrix gamma, the sparse matrix containing indices in networkdata Sindices, and an empty sparse matrix of scattering parameter data S. The scattering parameter data consists of the input networks assembled as a block diagonal matrix.

References

V. A. Monaco and P. Tiberio, "Computer-Aided Analysis of Microwave Circuits," in IEEE Transactions on Microwave Theory and Techniques, vol. 22, no. 3, pp. 249-263, Mar. 1974, doi: 10.1109/TMTT.1974.1128208.

source
JosephsonCircuits.parsecircuitlevel Method
julia
parsecircuitlevel(components, connections, interface)
parsecircuitlevel(c::Circuit)

Parse and validate one level of a circuit description into a ParsedLevel: the component table, the connection groups, the interface pins, the ground ties and the mutual inductors. The Circuit constructor runs it to validate its arguments, and the elaboration runs it on every level it flattens.

source
JosephsonCircuits.parsecomponenttype Method
julia
parsecomponenttype(name::String,allowedcomponents::Vector{String})

The index in allowedcomponents of the one or two letter prefix which matches the start of the component name name. Prefixes are tried in order and the first match wins, so a two letter prefix listed after a one letter prefix with the same first letter can never match; checkcomponenttypes detects that ordering mistake.

Examples

julia
julia> JosephsonCircuits.parsecomponenttype("L10",["Lj","L","C","K","I","R","P"])
2

julia> [JosephsonCircuits.parsecomponenttype(c,["Lj","L","C","K","I","R","P"]) for c in ["Lj","L","C","K","I","R","P"]]
7-element Vector{Int64}:
 1
 2
 3
 4
 5
 6
 7
source
JosephsonCircuits.parsecomponentvalue Method
julia
parsecomponentvalue(s::AbstractString)

Parse a SPICE netlist component value into a number or a CircuitValue. Replaces Symbolics.parse_expr_to_symbolic; unlike it, this does not evaluate into a module, so a netlist cannot introduce arbitrary code.

source
JosephsonCircuits.parsespicevariable Method
julia
parsespicevariable(variable::String)

Parse a variable name string into the variable name and node number. Will this work with arbitrary node strings?

Examples

julia
julia> JosephsonCircuits.parsespicevariable("V1(5)")
("V1", 5)

julia> JosephsonCircuits.parsespicevariable("V1")
("V", 1)

julia> JosephsonCircuits.parsespicevariable("V-1")
("V", 1)

julia> JosephsonCircuits.parsespicevariable("frequency")
("frequency", "frequency")
source
JosephsonCircuits.passiveconstant Method
julia
passiveconstant(D; tol = 1e-6, margin = tol)

The constant term D with every singular value above 1 + tol brought to 1 - margin, leaving the singular vectors alone. D is the model at infinite frequency, which no perturbation over a band of frequencies can reach, so an active constant term would leave the passivity enforcement searching a band which begins at infinity; bringing it under one before the residues are fitted removes that failure at its source. tol is how far above one a singular value must stand to be treated as active, and belongs with the tolerance the block is validated against; margin is how far under one it is put, and belongs with the margin the enforcement aims for. Follows Gustavsen, IEEE Transactions on Electromagnetic Compatibility 67(3), 2025, section X-A.

source
JosephsonCircuits.passivityassessment Method
julia
passivityassessment(A, B, C, D; atol = 1e-8, rtol = 1e-8)

Whether the real rational block S(s) = D + C (s I - A)^(-1) B is passive to within atol, as (:passive, :active, :indeterminate), together with the lower bound on its largest singular value over all frequencies, the level the search ended at, and the frequency in rad/s where the lower bound was attained.

Three answers rather than two, because hinfnorm returns two numbers which straddle the truth and the question can fall between them. A block is :active when even the lower bound exceeds 1 + atol, which settles it; :passive when the level does not, which also settles it, the level being what the search's termination establishes. In between nothing is settled: the block may be passive or may not, and the caller is told so rather than given whichever bound suits.

The middle case is not rare. A lossless block has a largest singular value of exactly one, so its level stands at 1 + 2 rtol and it is :indeterminate at any atol below that. Callers which must decide regardless decide on the lower bound, and this makes that choice explicit rather than implicit in a two valued answer.

source
JosephsonCircuits.passivitycrossings Method
julia
passivitycrossings(A, B, C, D)

The frequencies in rad/s at which a singular value of the real rational scattering matrix S(s) = D + C (s I - A)^(-1) B equals one, sorted, and the scale of the poles: the finite eigenvalues on the imaginary axis of the pencil of the equations i w x = A x + B u, -i w y = A' y + C' w, w = C x + D u, u = B' y + D' w, which say S(i w)' S(i w) u = u, whose matrices are formed without inverting I - D' D, so a feedthrough on the unit circle is no obstacle. Returns nothing for the crossings when the pencil is singular, which is when a singular value is one at every frequency, as a lossless block's are. The pencil for S over a level finds the crossings of that level, which is how hinfnorm finds the largest singular value.

source
JosephsonCircuits.passivitymargin Method
julia
passivitymargin(S::AbstractMatrix)

Return the minimum eigenvalue of I - S S', which is nonnegative for a passive scattering matrix.

source
JosephsonCircuits.perfrequency! Method
julia
perfrequency!(kernel!, y, args...)

Fill the network parameter matrix y[:, :, i] at every frequency index i of the trailing dimensions of y by the scalar kernel kernel!, with each array argument indexed at i and each scalar argument the same at every frequency. An array argument must have the size of the trailing dimensions of y. The type parameters make the method specialize on the kernel and on the argument types, which Julia does not do on its own for a function argument and for arguments only passed on; without them the kernel is called through a dynamic dispatch at every frequency.

source
JosephsonCircuits.perfrequency Method
julia
perfrequency(kernel!, f, args...)

The allocating form of perfrequency!: the matrices of the network f at every frequency of the array arguments, in an array whose element type is the one f returns for scalars, found by evaluating f once on the first element of each array argument.

source
JosephsonCircuits.phimatrixtovector! Method
julia
phimatrixtovector!(phivector::Vector, phimatrix::Array,
    indexmap::Vector{Int}, conjsourceindices::Vector{Int},
    conjtargetindices::Vector{Int}, Nbranches::Int)

The harmonic balance method requires a vector with all of the conjugate symmetric terms removed and potentially other terms dropped if specified by the user ( for example, intermodulation products which are not of interest) whereas the Fourier transform operates on multidimensional arrays with the proper conjugate symmetries and with dropped terms set to zero. This function converts an array to a vector with the above properties.

Examples

julia
freqindexmap = [2, 4, 6, 8, 12, 16, 27, 33]
conjsourceindices = [16, 6]
conjtargetindices = [21, 31]
Nbranches = 1

phivector = zeros(Complex{Float64}, Nbranches*length(freqindexmap))
phimatrix = [0.0 + 0.0im 0.0 + 3.0im 0.0 + 0.0im 0.0 + 6.0im 0.0 - 6.0im 0.0 + 0.0im 0.0 - 3.0im; 0.0 + 1.0im 0.0 + 0.0im 0.0 + 5.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 7.0im 0.0 + 0.0im; 0.0 + 0.0im 0.0 + 4.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 8.0im; 0.0 + 2.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im; 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im;;;]

JosephsonCircuits.phimatrixtovector!(phivector,
    phimatrix,
    freqindexmap,
    conjsourceindices,
    conjtargetindices,
    Nbranches,
)
phivector

# output
8-element Vector{ComplexF64}:
 0.0 + 1.0im
 0.0 + 2.0im
 0.0 + 3.0im
 0.0 + 4.0im
 0.0 + 5.0im
 0.0 + 6.0im
 0.0 + 7.0im
 0.0 + 8.0im
source
JosephsonCircuits.phivectortomatrix! Method
julia
phivectortomatrix!(phivector::AbstractVector,phimatrix::AbstractArray,
    indexmap::Vector{Int},conjsourceindices::Vector{Int},
    conjtargetindices::Vector{Int},Nbranches::Int)

The harmonic balance method requires a vector with all of the conjugate symmetric terms removed and potentially other terms dropped if specified by the user ( for example, intermodulation products which are not of interest) whereas the Fourier transform operates on multidimensional arrays with the proper conjugate symmetries and with dropped terms set to zero. This function converts a vector to an array with the above properties.

Examples

julia
freqindexmap = [2, 4, 6, 8, 12, 16, 27, 33]
conjsourceindices = [16, 6]
conjtargetindices = [21, 31]
Nbranches = 1

phivector = 1im.*Complex.(1:Nbranches*length(freqindexmap));
phimatrix=zeros(Complex{Float64},5,7,1)

JosephsonCircuits.phivectortomatrix!(phivector,
    phimatrix,
    freqindexmap,
    conjsourceindices,
    conjtargetindices,
    Nbranches,
)
phimatrix

# output
5×7×1 Array{ComplexF64, 3}:
[:, :, 1] =
 0.0+0.0im  0.0+3.0im  0.0+0.0im  0.0+6.0im  0.0-6.0im  0.0+0.0im  0.0-3.0im
 0.0+1.0im  0.0+0.0im  0.0+5.0im  0.0+0.0im  0.0+0.0im  0.0+7.0im  0.0+0.0im
 0.0+0.0im  0.0+4.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+8.0im
 0.0+2.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im
 0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im
source
JosephsonCircuits.pivot_rows Method
julia
pivot_rows(A11,A21)

Return true if pivoting during LU decomposition.

Examples

julia
julia> JosephsonCircuits.pivot_rows(0,:A21)
true

julia> JosephsonCircuits.pivot_rows(1,:A21)
false
source
JosephsonCircuits.pivot_rows Method
julia
pivot_rows(A11::Union{T,Complex{T}},
A21::Union{T,Complex{T}}) where {T<:AbstractFloat}

Return true if pivoting during LU decomposition.

Examples

julia
julia> JosephsonCircuits.pivot_rows(0.1+0.0im,0.9+0.1im)
true

julia> JosephsonCircuits.pivot_rows(0.9+0.1im,0.1+0.0im)
false
source
JosephsonCircuits.plan_applyffttranspose Method
julia
plan_applyffttranspose(fd::Array{Complex{T}}, td::Array{T})

Create the complex transform plan for applyffttranspose!, the transpose of applyfft! on the same grid. A work array the size of the time domain grid is allocated for planning and discarded; the caller passes its own padded at apply time. The plan is created with FFTW.UNALIGNED so it can be executed against per-thread work arrays allocated elsewhere.

source
JosephsonCircuits.plan_applynl Method
julia
plan_applynl(fd::AbstractArray{Complex{T}}, backend::Backend = CPU())

Creates an empty time domain data array and the inverse and forward plans for the RFFT of an array of frequency domain data. See also applynl!. A system with no junctions has nothing to transform: for an empty fd the two plans are nothing, and applying them is the identity.

source
JosephsonCircuits.plancomplexjacobian Method
julia
plancomplexjacobian(Amatrixindices::Matrix, Ljb::SparseVector, Lscale,
    Rbnm::SparseMatrixCSC, Nmodes::Integer, Nbranches::Integer,
    Nfreq::Integer, invLnm::SparseMatrixCSC, Gnm::SparseMatrixCSC,
    Cnm::SparseMatrixCSC)

Build the complex Jacobian sparse matrix Jx (with the same sparsity structure spaddkeepzeros applied to Rbnm'*AoLjbm*Rbnm and the linear term matrices would produce, including stored numerical zeros) and the StructureComplexJosephsonPlan which writes the Josephson term into it: the map from the Fourier coefficients of cos(phi(t)) to the Josephson branch matrix AoLjbm (Amatrixindices, with negative entries denoting complex conjugation and zeros denoting dropped couplings) and the circuit's incidence triple product Rbnm'*AoLjbm*Rbnm as a per node pair table (junctionpairtable), read backwards at assembly time.

The plan reads a JunctionStructure built here on the host in the precision the scale and the inductances give. The linear term is not part of the plan. The nonlinear solve gathers it once for its mode frequencies with planstructurecomplexjacobian, which takes this plan as its josephson; the linearized solve builds its own index maps for the matrices it substitutes per frequency.

Returns the tuple (Jx, josephson).

source
JosephsonCircuits.plandeviceblocknoise Method
julia
plandeviceblocknoise(ssys, noiseplan, Nmodes, backend)

Build a DeviceBlockNoisePlan from a ScatteringNoisePlan, or nothing when there is none.

source
JosephsonCircuits.plandevicenoise Method
julia
plandevicenoise(nodeindices, componenttypes, noiseportimpedanceindices,
    noiseportimpedances, Nmodes, backend)

Build a DeviceNoisePlan for the noise ports of a circuit.

source
JosephsonCircuits.plandeviceproviders Method
julia
plandeviceproviders(ssys, nbatch, backend, wpumpmodes, scale)

Build a DeviceProviders for a stamp system whose blocks can all be evaluated by a kernel, or nothing otherwise.

source
JosephsonCircuits.plandevicescattering Method
julia
plandevicescattering(ssys, Aindexcsr, nzA, nbatch, backend, Nmodes)

Build a DeviceScatteringStamps from a scattering stamp system whose destination indices have already been mapped into the stored order the batch uses, or nothing when ssys is nothing.

source
JosephsonCircuits.planequilibration Method
julia
planequilibration(colind::AbstractVector{<:Integer}, n, nb, backend)

The ColumnEquilibration of a batch of nb systems of order n whose stored entries lie in the columns colind names.

source
JosephsonCircuits.planfrequencysweep Method
julia
planfrequencysweep(lsys::HBLinearizedSystem, backend;
    adjoint::Bool = false)

Build a FrequencySweepPlan for lsys on backend, together with the compressed sparse row structure a device direct solver factorizes, as (plan, rowptr, colind, colindhost). The column index array comes back on the host as well, which is where the grouping of planequilibration is built.

With adjoint the structure and the coefficients describe the transpose of the system matrix, whose solutions are the adjoint ones the noise, quantum efficiency and sensitivity calculations need. That transpose is free to form: compressed sparse row of the transpose is compressed sparse column of the matrix, which is how the host holds it, so the adjoint plan is the same coefficients in their original order against the original structure.

With cuDSS the adjoint costs a second symbolic analysis and a second numeric factorization per batch, because cuDSS 0.8 has no transposed solve (its "solve_mode" is documented in the header as unsupported), so the factors of the forward system cannot be reused the way the host reuses them with trysolvetranspose!. The block path asks for the adjoint plan for a different reason: its coefficients are in the matrix's own stored order, which is the order a SparseBlockFactorization fills its blocks from, and it costs no second factorization, since the block factors solve both directions.

source
JosephsonCircuits.plannonlinearterm Function
julia
plannonlinearterm(Rbnm::SparseMatrixCSC, Ljb::SparseVector, Lscale,
    Nbranches::Integer, freqindexmap::Vector{Int},
    conjsourceindices::Vector{Int}, conjtargetindices::Vector{Int},
    phimatrix::AbstractArray, Knm::SparseMatrixCSC, layout::ModeLayout,
    backend = CPU(); realbackward = true)

Build the NonlinearTermPlan for the harmonic balance system described by the incidence matrix Rbnm, the Josephson inductances Ljb, the frequency domain packing maps, the frequency domain array phimatrix which fixes the slot layout, the collapsed linear term matrix Knm (see linearterm) and the real representation layout.

The per branch node and sign lists of the forward map come from branchnodesandsigns, the same function the assembled Jacobian plans use, which also verifies that Rbnm has the expected mode-diagonal diagrepeat structure. The backward map reads the columns of Rbnm directly, because the entries of column k are exactly the branch rows contributing to output k, which is what makes the transposed product a gather.

Throws an ArgumentError if a branch touches more than two nodes, which the forward map's flat two entry form assumes.

realbackward = false leaves out the real representation of the linear term, the largest allocation of the plan, which only the backward map of the real representation reads; a solve which stays in the complex representation (method = QuasiNewton()) never applies it.

source
JosephsonCircuits.plannonlineartermtranspose Method
julia
plannonlineartermtranspose(plan, modelayout, fd, td; backend = CPU())

Build the NonlinearTermTransposePlan of a NonlinearTermPlan.

source
JosephsonCircuits.planscatteringnoise Method
julia
planscatteringnoise(ssys)

The ScatteringNoisePlan of a ScatteringStampSystem, or nothing when the circuit has no scattering blocks or every block either declares Lossless or is provablylossless.

Passive and ThermalEquilibrium carry the covariance of the block's loss, differing only in the temperature the channels are at, and give a block one channel per port; Lossless declares there are none; and a NoiseCovariance states the covariance outright and gives a block two channels per port.

source
JosephsonCircuits.planstructurecomplexjacobian Method
julia
planstructurecomplexjacobian(Jx::SparseMatrixCSC,
    junctions::JunctionStructure, invLnm, Gnm, Cnm, wmodesm, wmodes2m,
    backend; transposed = false, josephson = nothing)

Build a StructureComplexJacobianPlan for the structure of Jx: the Josephson map over junctions, built here unless one built for the same structure, backend and orientation is handed in as josephson (the plan plancomplexjacobian returns), and the constant linear term at the mode frequencies wmodesm, gathered once on backend.

source
JosephsonCircuits.planstructurecomplexjosephson Method
julia
planstructurecomplexjosephson(Jx::SparseMatrixCSC, junctions::JunctionStructure,
    Amatrixindices, Ljb, Lscale, nodesandsigns, Nmodes, Nfreq, backend;
    transposed = false)

Build a StructureComplexJosephsonPlan for the structure of Jx.

source
JosephsonCircuits.planstructurerealjacobian Method
julia
planstructurerealjacobian(Jt, T::Type{<:Real}, junctions::JunctionStructure,
    Amatrixconjindices, Ljb, Lscale, nodesandsigns, invLnm, Gnm, Cnm,
    wmodesm, wmodes2m, rl::ModeLayout, cl::ModeLayout, Nmodes, Nfreq,
    backend; transposed = true)

Build a StructureRealJacobianPlan with values of type T for the real Jacobian whose structure is Jt, stored transposed (as a device factorization wants it) when transposed = true and in the natural orientation otherwise. Nothing here is proportional to the number of contributions: what is stored is junctionpairtable, whose size is set by the circuit rather than by the mode count, and the constant linear term, which is gathered on backend by linearcontributionkernel!.

source
JosephsonCircuits.pointmoved! Method
julia
pointmoved!(pc::AbstractPreconditioner)

Tell the preconditioner that the operator it approximates has changed without it having been rebuilt, and return pc. The default does nothing. A FloquetPreconditioner marks its image pair stale, so that the next application rebuilds it from the current Jacobian. Called by nlsolvekrylov! at every Newton step; wrappers forward it.

source
JosephsonCircuits.polar Method
julia
polar(A)

Return a positive semi-definite matrix P and unitary matrix U such that A = P U. A is a square real or complex matrix.

If A is symplectic, both P and U are symplectic.

This definition is different from wikipedia https://en.wikipedia.org/wiki/Polar_decomposition

References

[1] M. Houde, W. McCutcheon, and N. Quesada, “Matrix decompositions in Quantum Optics: Takagi/Autonne, Bloch-Messiah/Euler, Iwasawa, and Williamson,” Can. J. Phys., vol. 102, no. 10, pp. 497–507, Oct. 2024, doi: 10.1139/cjp-2024-0070. [2] https://en.wikipedia.org/wiki/Polar_decomposition#Relation_to_the_SVD

source
JosephsonCircuits.portdiagonal Method
julia
portdiagonal(a)
porthalves(a)

A port impedance argument as the kernels take it: a number stays a number and an array becomes a PortDiagonal; porthalves splits the ports in two, the first half the input ports of a chain matrix and the second half its output ports.

source
JosephsonCircuits.portenvironmentindices Method
julia
portenvironmentindices(c::CompiledCircuit)

The flat table index of each port's own termination, ordered by port number, or zero for a port which owns none.

A port owns a termination when it was written with the default MatchedTermination, or when the legacy adapter recorded the resistor a tuple netlist placed across it. A port written with termination = nothing owns none. The index identifies a role rather than a value: it says which entry realizes the port's reference impedance, which the noise classification needs (a port termination is an external bath, not an internal noise channel) and the sensitivities need (perturbing that entry also moves the wave normalization). The impedance itself comes from portreferenceimpedances, which is defined for every port.

source
JosephsonCircuits.portindicesnumbers Method
julia
portindicesnumbers(c::CompiledCircuit)

The flat table indices and the numbers of the ports, both ordered by port number. Throws an ArgumentError for duplicate port numbers or two ports on the same branch.

source
JosephsonCircuits.portreferenceimpedances Method
julia
portreferenceimpedances(c::CompiledCircuit, values)

The reference impedance of each port, ordered by port number, read from a bound flat value table.

This is the impedance the incoming and outgoing waves are normalized to. It is the port's declared Z0, which is the value of the port's own entry in the table, and it is read from there for every port, whatever the port owns: a symbolic or swept impedance then resolves the same way a component value does, and an unterminated port resolves the same way a matched one. The two cannot disagree with an environment either, because a matched environment is generated with the port's own Z0 and a legacy port's Z0 is the value of the resistor it adopted.

A bound value must be a finite positive real number. The constructor lets a symbol or a deferred value through so that it can be bound; this is where what it bound to is checked, before any matrix or wave is built from it.

source
JosephsonCircuits.ports_modes_to_modes_ports_block Method
julia
ports_modes_to_modes_ports_block(S::AbstractMatrix,Nmodes::Int)

Examples

julia
S = [:S11 :S12 :S13 :S14 :S15 :S16 :S17 :S18; :S21 :S22 :S23 :S24 :S25 :S26 :S27 :S28; :S31 :S32 :S33 :S34 :S35 :S36 :S37 :S38; :S41 :S42 :S43 :S44 :S45 :S46 :S47 :S48; :S51 :S52 :S53 :S54 :S55 :S56 :S57 :S58; :S61 :S62 :S63 :S64 :S65 :S66 :S67 :S68; :S71 :S72 :S73 :S74 :S75 :S76 :S77 :S78; :S81 :S82 :S83 :S84 :S85 :S86 :S87 :S88]
JosephsonCircuits.ports_modes_to_modes_ports_block(S,2)

# output
8×8 Matrix{Symbol}:
 :S11  :S13  :S12  :S14  :S15  :S17  :S16  :S18
 :S31  :S33  :S32  :S34  :S35  :S37  :S36  :S38
 :S21  :S23  :S22  :S24  :S25  :S27  :S26  :S28
 :S41  :S43  :S42  :S44  :S45  :S47  :S46  :S48
 :S51  :S53  :S52  :S54  :S55  :S57  :S56  :S58
 :S71  :S73  :S72  :S74  :S75  :S77  :S76  :S78
 :S61  :S63  :S62  :S64  :S65  :S67  :S66  :S68
 :S81  :S83  :S82  :S84  :S85  :S87  :S86  :S88
source
JosephsonCircuits.ports_modes_to_modes_ports_pair Method
julia
ports_modes_to_modes_ports_pair(S::AbstractMatrix,Nmodes::Int)

Examples

julia
S = [:S11 :S12 :S13 :S14 :S15 :S16 :S17 :S18; :S21 :S22 :S23 :S24 :S25 :S26 :S27 :S28; :S31 :S32 :S33 :S34 :S35 :S36 :S37 :S38; :S41 :S42 :S43 :S44 :S45 :S46 :S47 :S48; :S51 :S52 :S53 :S54 :S55 :S56 :S57 :S58; :S61 :S62 :S63 :S64 :S65 :S66 :S67 :S68; :S71 :S72 :S73 :S74 :S75 :S76 :S77 :S78; :S81 :S82 :S83 :S84 :S85 :S86 :S87 :S88]
JosephsonCircuits.ports_modes_to_modes_ports_pair(S,2)

# output
8×8 Matrix{Symbol}:
 :S11  :S12  :S15  :S16  :S13  :S14  :S17  :S18
 :S21  :S22  :S25  :S26  :S23  :S24  :S27  :S28
 :S51  :S52  :S55  :S56  :S53  :S54  :S57  :S58
 :S61  :S62  :S65  :S66  :S63  :S64  :S67  :S68
 :S31  :S32  :S35  :S36  :S33  :S34  :S37  :S38
 :S41  :S42  :S45  :S46  :S43  :S44  :S47  :S48
 :S71  :S72  :S75  :S76  :S73  :S74  :S77  :S78
 :S81  :S82  :S85  :S86  :S83  :S84  :S87  :S88
source
JosephsonCircuits.ports_modes_to_modes_ports_perm Method
julia
ports_modes_to_modes_ports_perm(Nports,Nmodes)

Return a permutation vector that converts one axis of a scattering matrix with Nports ports and Nmodes modes from (port,mode) ordering to a (mode,port) ordering. For example, for 2 ports with indices 1,2 and 4 modes with indices 1,2,3,4 then (port,mode) order is: [(1,1),(1,2),(2,1),(2,2),(3,1),(3,2),(4,1),(4,2)] and (mode,port) order is: [(1,1),(1,2),(1,3),(1,4),(2,1),(2,2),(2,3),(2,4)] The permutation to change the first into the second is in the example below:

Examples

julia
julia> p = JosephsonCircuits.ports_modes_to_modes_ports_perm(2,4)
8-element Vector{Int64}:
 1
 3
 5
 7
 2
 4
 6
 8
source
JosephsonCircuits.ports_modes_to_modes_ports_scattering Method
julia
ports_modes_to_modes_ports_scattering(S::AbstractMatrix,Nmodes::Int)

Examples

julia
S = [:S11 :S12 :S13 :S14 :S15 :S16 :S17 :S18; :S21 :S22 :S23 :S24 :S25 :S26 :S27 :S28; :S31 :S32 :S33 :S34 :S35 :S36 :S37 :S38; :S41 :S42 :S43 :S44 :S45 :S46 :S47 :S48; :S51 :S52 :S53 :S54 :S55 :S56 :S57 :S58; :S61 :S62 :S63 :S64 :S65 :S66 :S67 :S68; :S71 :S72 :S73 :S74 :S75 :S76 :S77 :S78; :S81 :S82 :S83 :S84 :S85 :S86 :S87 :S88]
JosephsonCircuits.ports_modes_to_modes_ports_scattering(S,2)

# output
8×8 Matrix{Symbol}:
 :S11  :S15  :S12  :S16  :S13  :S17  :S14  :S18
 :S51  :S55  :S52  :S56  :S53  :S57  :S54  :S58
 :S21  :S25  :S22  :S26  :S23  :S27  :S24  :S28
 :S61  :S65  :S62  :S66  :S63  :S67  :S64  :S68
 :S31  :S35  :S32  :S36  :S33  :S37  :S34  :S38
 :S71  :S75  :S72  :S76  :S73  :S77  :S74  :S78
 :S41  :S45  :S42  :S46  :S43  :S47  :S44  :S48
 :S81  :S85  :S82  :S86  :S83  :S87  :S84  :S88
source
JosephsonCircuits.portsolutionrows Method
julia
portsolutionrows(nodeindices, portindices, Nmodes::Integer)

The rows of a solution of the linearized system which the scattering parameter calculation reads: for each port, each of its two nodes which is not ground, and each mode.

calcinputoutput! reads a solution only through calcportvoltage, which touches these rows and no others. On a backend the solutions are produced there, so gathering these rows and copying back only them replaces a transfer of the whole solution, which is the same size as the state of the whole circuit, with one the size of the scattering matrix.

source
JosephsonCircuits.portwavescale Method
julia
portwavescale(portimpedance, w)

The scale factor of the Kurokawa power waves at a port with impedance portimpedance and (signed) mode frequency w, in units of sqrt(photons/second) rather than sqrt(power): 1/sqrt(real(Z))/sqrt(abs(w)), and zero at zero frequency, where the wave normalization is singular. This is the single definition used by the scattering parameter calculation (calcinputoutput_inner!) and by the sensitivity scaling (calcsensitivityscaling!), so the two cannot drift apart.

The zero is a convention and not an approximation, and it is what keeps the direct current out of the waves. The voltage those functions reconstruct is im*w*phi, which is zero at zero frequency whatever the average voltage is; a circuit with an explicit direct current block has a physical zero frequency voltage which that reconstruction cannot see. Returning it through this scale would mix a voltage the extractor does not know about into a normalization which does not exist there. The direct current operating point is reported as a voltage instead.

source
JosephsonCircuits.pre_iwasawa_block Method
julia
pre_iwasawa_block(S::AbstractMatrix)

References

[1] M. Houde, W. McCutcheon, and N. Quesada, “Matrix decompositions in Quantum Optics: Takagi/Autonne, Bloch-Messiah/Euler, Iwasawa, and Williamson,” Can. J. Phys., vol. 102, no. 10, pp. 497–507, Oct. 2024, doi: 10.1139/cjp-2024-0070. [2] Arvind, B. Dutta, N. Mukunda, and R. Simon, “The real symplectic groups in quantum mechanics and optics,” Pramana - J Phys, vol. 45, no. 6, pp. 471–497, Dec. 1995, doi: 10.1007/BF02848172.

source
JosephsonCircuits.preconditionedproduct! Method
julia
preconditionedproduct!(w, z, Aop, M, v)

One right preconditioned Arnoldi step: overwrite z with inv(M)*v and w with A*z, and return the seconds spent inside the preconditioner. The timing excludes the Jacobian product so that precondtime in KrylovSolveInfo means the same thing whatever the preconditioner. (A fused form which folded the deflation's correction into this product existed and was retired: it measured more Arnoldi steps than the image pair form of FloquetPreconditioner on every case tried.)

source
JosephsonCircuits.preconditioner Method
julia
preconditioner(prob::HBNonlinearProblem, u; spec = BlockDiagonal(),
    precision = Float64)

The mode coupling preconditioner of prob (see ModeCouplingPreconditioner for spec, a member of the mode coupling family), updated at u, with its factorization in the given precision. With an explicit direct current block it is wrapped in the canonical coordinates with the direct current subsystem solved exactly.

Applied by ldiv! and by mul!, so it can be handed straight to any external Krylov solver: Krylov.gmres(J, -F; N = preconditioner(prob, u), atol = 0.0). See JacobianOperator for why atol = 0.0.

source
JosephsonCircuits.preparecircuit Method
julia
preparecircuit(circuit, circuitdefs; sorting = :name, Nmodes = 1)

Everything the solvers need from a circuit: the compiled circuit, its graph, and its numeric matrices.

Every circuit takes this path. A netlist of tuples becomes a typed circuit first, which parses to the same thing at the same sorting and refuses the same inputs for the same reasons.

source
JosephsonCircuits.preparenoise Method
julia
preparenoise(noise, provider, n)

The noise model of a block as it is stored: a NoiseCovariance with its data as a matrix provider of the block's dimension n, validated for Hermitian symmetry and, where both it and the scattering provider are stored data, for the minimum noise the commutation relations require (see quantumnoisemargin); any other model unchanged.

source
JosephsonCircuits.printsymmetries Method
julia
printsymmetries(freq::Frequencies)

See printsymmetries.

Examples

julia
julia> JosephsonCircuits.printsymmetries(JosephsonCircuits.calcfreqsrdft((2,)))
3-element Vector{Int64}:
 0
 0
 0

julia> JosephsonCircuits.printsymmetries(JosephsonCircuits.calcfreqsdft((2,)))
5-element Vector{Int64}:
  0
  1
  2
 -2
 -1

julia> JosephsonCircuits.printsymmetries(JosephsonCircuits.calcfreqsrdft((2,2)))
3×5 Matrix{Int64}:
 0  1  2  -2  -1
 0  0  0   0   0
 0  0  0   0   0
source
JosephsonCircuits.printsymmetries Method
julia
printsymmetries(Nw::NTuple{N, Int}, Nt::NTuple{N, Int})

Print the conjugate symmetries in the multi-dimensional DFT or RDFT from the dimensions of the signal in the frequency domain and the time domain. Negative numbers indicate that element is the complex conjugate of the corresponding positive number. A zero indicates that element has no corresponding complex conjugate.

Examples

julia
julia> JosephsonCircuits.printsymmetries((3,),(4,))
3-element Vector{Int64}:
 0
 0
 0

julia> JosephsonCircuits.printsymmetries((4,),(4,))
4-element Vector{Int64}:
  0
  1
  0
 -1

julia> JosephsonCircuits.printsymmetries((3,3),(4,3))
3×3 Matrix{Int64}:
 0  1  -1
 0  0   0
 0  2  -2

julia> JosephsonCircuits.printsymmetries((4,3),(4,3))
4×3 Matrix{Int64}:
  0   2  -2
  1   3   5
  0   4  -4
 -1  -5  -3
source
JosephsonCircuits.probecouplings! Method
julia
probecouplings!(pr::ClusterProbe, sys::HBSystem, Nmodes::Integer)

Measure the block norms of the block Jacobi iteration matrix at the current point, one Jacobian product and one block diagonal solve per mode: the column j of pr.W holds, for every mode, the norm of what the block diagonal solve of the product of the Jacobian with a random vector on mode j's slots leaves on that mode, relative to the input. This is the coupling strength the cluster rule sorts by, and it includes the gain of the receiving mode's block, which a coefficient of cos(phi(t)) alone does not: measured on a two tone line, a coefficient proxy ranked inert near-dc modes first and the probe the difference ladder.

source
JosephsonCircuits.processnode Method
julia
processnode(uniquenodedict::Dict{String, Int},
    uniquenodevector::Vector{String},node)

Intern a node given as anything other than a string (an integer or a symbol) by converting it with string first.

Examples

julia
uniquenodedict = Dict("10" =>1)
uniquenodevector = ["10"]
println(JosephsonCircuits.processnode(uniquenodedict,uniquenodevector,15))
println(uniquenodevector)
println(uniquenodedict)

# output
2
["10", "15"]
Dict("10" => 1, "15" => 2)
julia
uniquenodedict = Dict("10" =>1)
uniquenodevector = ["10"]
println(JosephsonCircuits.processnode(uniquenodedict,uniquenodevector,:A))
println(uniquenodevector)
println(uniquenodedict)

# output
2
["10", "A"]
Dict("A" => 2, "10" => 1)
source
JosephsonCircuits.processnode Method
julia
processnode(uniquenodedict::Dict{String, Int},
    uniquenodevector::Vector{String},node::String)

Return the index of the node named node, interning it if it is new: a new name is appended to uniquenodevector and recorded in uniquenodedict with its position as the value.

Examples

julia
uniquenodedict = Dict("10" =>1)
uniquenodevector = ["10"]
println(JosephsonCircuits.processnode(uniquenodedict,uniquenodevector,"15"))
println(uniquenodevector)
println(uniquenodedict)

# output
2
["10", "15"]
Dict("10" => 1, "15" => 2)
julia
uniquenodedict = Dict("10" =>1)
uniquenodevector = ["10"]
println(JosephsonCircuits.processnode(uniquenodedict,uniquenodevector,"10"))
println(uniquenodevector)
println(uniquenodedict)

# output
1
["10"]
Dict("10" => 1)
source
JosephsonCircuits.provablylossless Method
julia
provablylossless(provider::AbstractMatrixProvider; atol = 1e-10)
provablylossless(block::ScatteringParameters; atol = 1e-10)

Whether the scattering data can be shown to be unitary at every frequency from the data alone, which is possible for a constant matrix and for a table and is not for a callable, whose values away from any sampled frequency are unknown.

A block which is not provably lossless carries vacuum noise channels (ScatteringNoisePlan), and those of a block which is in fact lossless are identically zero. A false here therefore costs work and never correctness, which is why the fallback is false.

source
JosephsonCircuits.providersize Method
julia
providersize(p::AbstractMatrixProvider)

Return the matrix dimension n of the n by n matrices produced by the provider.

source
JosephsonCircuits.psdcholesky! Method
julia
psdcholesky!(L, off, n)

Overwrite the length n*n column major block of L at off, whose lower triangle holds a Hermitian positive semidefinite matrix V, with a lower triangular factor satisfying L L' = V.

The noise covariance of a block which is transparent in some direction, such as a series element, is singular, and rounding can make that of a lossless block slightly indefinite, so this is not a plain Cholesky factorization: a pivot which is not positive is taken as zero, which for a positive semidefinite matrix means its whole column is zero and there is nothing to divide by. The strict upper triangle held the covariance and is zeroed, so the result is the factor and nothing else.

Any factor of the covariance describes the same noise: the channels are defined only up to a unitary mixing among them, and the quantum efficiency and the commutation relations read only sums over them. A triangular factor is chosen over an eigendecomposition because it is a few lines of arithmetic with no iteration, so the host and a kernel can share it and agree to the last bit.

source
JosephsonCircuits.pumpedblocknoisewaves! Method
julia
pumpedblocknoisewaves!(noiseoutputwave, block::LinearizedScattering, sb,
    wmodes, phiadj, rowoffset, Nmodes, K)

The noise output waves of the channels of a pumped block which states its noise, into the rows of noiseoutputwave after rowoffset, as blocknoisewaves! does for a block which does not convert.

The block's noise is one wave over all its ports and modes at once, of covariance V and commutator K = J - S J S' (see pumpednoisematrices), so its channels are the columns of the factors of (V + K)/2, which emit like modes in their vacuum, and of (V - K)/2, which emit like their conjugates; each column spans the port current rows of every mode. The block has 2 nports channel slots of Nmodes rows each in the noise scattering matrix, and the columns are laid out over those rows, a column per row, the first nports slots holding the first kind and the rest the second, so that every row is one channel; their sign kinds are fixed (see noisechannelsigns). Each row is the contraction of its column against the adjoint solution over all the block's rows, with the sign and the square root of each mode's frequency, and is multiplied by the sign of its own row's mode frequency, which the adjoint route's sign (see adjointnoisesigns!) then undoes, so that after it the entry is the wave of the channel in the signed frequency convention.

source
JosephsonCircuits.pumpedfamily Method
julia
pumpedfamily(block::LinearizedScattering, nus; reach = true, keep = false)

The output modes a pumped block's data reaches from the frequencies nus, every input mode which feeds them, and the harmonic coupling each pair, as (rows, cols, K) for pumpednoisematrices: the outputs are the signed frequencies a harmonic of the block apart from one of nus, or nus themselves with reach = false, into which the block holds an entry from an input a harmonic apart that its data covers, and at which a stated covariance holds its row, and the inputs are every such input, which reach one harmonic further out than the outputs where the data goes so far. Frequencies within roundoff of one another are one mode, and K[m, n] is typemin(Int) where the block holds no entry from cols[n] to rows[m]. Validating the outputs against every input which reaches them, rather than one set of modes against itself, keeps a truncation of the inputs at the edge of the set from counting as a violation by the data.

With keep every frequency is an output whether the block's data reaches it or not, which is how a completed covariance is formed (see completedcovariance): a frequency the data does not reach is one the block scatters nothing at, an output of the circuit all the same, and its row of the commutator is the one it has there.

source
JosephsonCircuits.pumpedharmonics Method
julia
pumpedharmonics(block::LinearizedScattering, offsets::AbstractVector)

The harmonic of block which couples each pair of modes of a circuit, as a matrix over (output mode, input mode) of the multiple of the block's pump by which the modes' frequency offsets differ, or typemin(Int) where they differ by no such multiple or by one the block does not convert by. Throws if the block converts and no pair of modes is a pump apart, which is a circuit solved without the block's pump.

source
JosephsonCircuits.pumpednoisematrices Method
julia
pumpednoisematrices(block::LinearizedScattering, wmodes, K)
pumpednoisematrices(block::LinearizedScattering, rows, cols, K)

The multi-mode matrices of a pumped block at the signed mode frequencies wmodes, over the index (p - 1)*Nmodes + m of port p at mode m, in the units of the solver's outputs, waves of photons per second: its scattering matrix S, from its harmonic transfer functions on power waves through the harmonic K[m, n] coupling each pair of modes (see pumpedharmonics) and the square root of the frequency ratio; the commutator J - S J S' of the noise its output needs, with J the signs of the mode frequencies; and, for a block which states its noise, the covariance V from its harmonic covariances, V_{-k}(nu) being V_k(nu - k wp)', or nothing. The rows and columns of a mode at zero frequency are left zero, the wave normalization being singular there. With the output modes rows and the input modes cols given apart, K[m, n] coupling rows[m] to cols[n], S is the block from the inputs to the outputs, the commutator J_rows - S J_cols S' is that of the outputs with every input which reaches them, and V is over the outputs: what validates a set of outputs without truncating the inputs they are fed by (see pumpedfamily). The covariance of a block whose noise model is completed is the completed one, from completedcovariance, unless complete = false asks for the covariance as stated.

source
JosephsonCircuits.pushval! Method
julia
pushval!(V::Vector, val, c, invert::Bool)

Append the value val of capacitance or conductance to the vector V. Scale the value by c. If invert = true, append c/val otherwise append c*val.

Examples

julia
julia> V = Array{Float64, 1}(undef, 0);JosephsonCircuits.pushval!(V,2.0,-1.0,false);V
1-element Vector{Float64}:
 -2.0

julia> V = Array{Float64, 1}(undef, 0);JosephsonCircuits.pushval!(V,2.0,-1.0,true);V
1-element Vector{Float64}:
 -0.5
source
JosephsonCircuits.quadratic_trial_step Method
julia
quadratic_trial_step(ϕ0, ϕ1, dϕ0dα; c1 = 1e-4, safeguard_low = 0.1,
    safeguard_high = 0.5)

Return a tuple (αfit, ϕfit, measured) with the proposed step αfit, the estimated merit function value ϕfit, and measured a boolean indicating if the function value is based on an evaluation of the merit function (vs an estimate) that minimizes a quadratic function fitted to ϕ(α) = f(xₖ + α pₖ) in the range [0, 1]. The fitting process uses the merit function values at α = 0, α = 1, and the derivative at the first point dϕ(α)/dα|α = 0. If the full step α = ϕα1 satisfies the Armijo sufficient-decrease condition ϕ(1) <= ϕ(0) + c1 dϕ(α)/dα|α = 0, then the full step is returned without fitting. By default c1 = 1e-4.

Based on Nocedal and Wright, chapter 3 section 5.

Arguments

-ϕ0: ϕ(0), the value of the merit function at α = 0. -ϕ1: ϕ(1), the value of the merit function at α = 1. -dϕ0dα: dϕ(α)/dα|α=0, the derivative of the merit function with respect to α at α = 0.

Keywords

  • c1 = 1e-4: the constant in the Armijo sufficient-decrease check which is typically (heuristicaly) set to be 1e-4, ϕ(1) <= ϕ(0) + c1 dϕ(α)/dα|α = 0.

  • safeguard_low = 0.1, safeguard_high = 0.5: the bounds of the proposed step. The lower one protects against large (eg. order of magnitude) reductions in the step size without an additional function evaluation, which would occur outside of this function; the fitted minimizer of a full step which fails the Armijo condition is below 1/(2(1 - c1)), so the upper one acts only when it is set below that.

Returns

  • αtrial: αtrial is the trial step predicted to minimize the merit function based on quadratic interpolation.

  • ϕtrial: ϕtrial is either the predicted or measured value of the merit function at the trial step above. If measured = false, then the linesearch function needs to evaluate the trial point to verify that Armijo sufficient-decrease condition is satisfied before accepting the step.

  • measured: true if the returned ϕtrial has been measured and false if it is an estimate value based on a fit.

source
JosephsonCircuits.quadrature_to_ladder_block Method
julia
quadrature_to_ladder_block(S::AbstractMatrix)
source
JosephsonCircuits.quadrature_to_ladder_block Method
julia
quadrature_to_ladder_block(r::AbstractVector)
source
JosephsonCircuits.quadrature_to_ladder_pair Method
julia
quadrature_to_ladder_pair(S::AbstractMatrix)
source
JosephsonCircuits.quadrature_to_ladder_pair Method
julia
quadrature_to_ladder_pair(r::AbstractVector)
source
JosephsonCircuits.quadraturetransform Method
julia
quadraturetransform(A::AbstractMatrix, B::AbstractMatrix)

Convert the complex Bogoliubov transformation b = A a + B conj(a) to the real quadrature transformation X in the ordering (x_1,…,x_n,p_1,…,p_n), so that d_out = X d_in. Returns the 2n by 2n real matrix X = [Re(A+B) -Im(A-B); Im(A+B) Re(A-B)].

Examples

julia
julia> quadraturetransform([0 1;1 0], zeros(2,2)) == [0 1 0 0;1 0 0 0;0 0 0 1;0 0 1 0]
true
source
JosephsonCircuits.quantumnoisemargin Method
julia
quantumnoisemargin(V::AbstractMatrix, S::AbstractMatrix)

The smallest eigenvalue of V - K and of V + K, with K = I - S S', which is nonnegative when the noise covariance V is one a block with the scattering matrix S can add without violating the commutation relations: (V + K)/2 and (V - K)/2 are then the covariances of its channels of either kind (see NoiseCovariance).

source
JosephsonCircuits.rand_bogoliubov_block Method
julia
rand_bogoliubov_block(n::Integer)

Return a random 2n x 2n Bogoliubov matrix S, S ∈ Sp(2n, ℂ) ∩ U(n, n) =: Bog(n), with block operator order.

source
JosephsonCircuits.rand_bogoliubov_pair Method
julia
rand_bogoliubov_pair(n::Integer)

Return a random 2n x 2n Bogoliubov matrix S, S ∈ Sp(2n, ℂ) ∩ U(n, n) =: Bog(n), with pair operator order.

source
JosephsonCircuits.rand_conjugate_symplectic_block Methodsource
JosephsonCircuits.rand_orthogonal_bogoliubov_block Method
julia
rand_orthogonal_bogoliubov_block(n::Integer)

Return a random 2n x 2n orthogonal Bogoliubov matrix S, S ∈ Sp(2n, ℂ) ∩ U(n, n) ∩ U(2n) ≅ U(n), with block operator order.

source
JosephsonCircuits.rand_orthogonal_bogoliubov_pair Method
julia
rand_orthogonal_bogoliubov_pair(n::Integer)

Return a random 2n x 2n orthogonal Bogoliubov matrix S, S ∈ Sp(2n, ℂ) ∩ U(n, n) ∩ U(2n) ≅ U(n), with pair operator order.

source
JosephsonCircuits.rand_orthogonal_symplectic_block Method
julia
rand_orthogonal_symplectic_block(n::Integer)

Return a random 2n x 2n orthogonal symplectic matrix S, S ∈ Sp(2n, ℝ) ∩ O(2n) ≅ U(n), with block operator order.

source
JosephsonCircuits.rand_orthogonal_symplectic_pair Method
julia
rand_orthogonal_symplectic_pair(n::Integer)

Return a random 2n x 2n orthogonal symplectic matrix S, S ∈ Sp(2n, ℝ) ∩ O(2n) ≅ U(n) with pair operator order.

source
JosephsonCircuits.rand_positive_definite_symplectic_block Method
julia
rand_positive_definite_symplectic_block(T, n::Integer)

Return a random 2n x 2n positive definite symplectic matrix S, S ∈ Sp(2n, ℝ) or S ∈ Sp(2n, ℂ), depending on the type T with block operator order.

source
JosephsonCircuits.rand_positive_definite_symplectic_block Method
julia
rand_positive_definite_symplectic_block(n::Integer)

Return a random 2n x 2n positive definite symplectic matrix S, S ∈ Sp(2n, ℝ), with block operator order.

source
JosephsonCircuits.rand_positive_definite_symplectic_pair Method
julia
rand_positive_definite_symplectic_pair(T, n::Integer)

Return a random 2n x 2n positive definite symplectic matrix S, S ∈ Sp(2n, ℝ) or S ∈ Sp(2n, ℂ), depending on the type T with pair operator order.

source
JosephsonCircuits.rand_positive_definite_symplectic_pair Method
julia
rand_positive_definite_symplectic_pair(n::Integer)

Return a random 2n x 2n positive definite symplectic matrix S, S ∈ Sp(2n, ℝ), with pair operator order.

source
JosephsonCircuits.rand_positive_semi_definite Method
julia
rand_positive_semi_definite(T, n, m)
rand_positive_semi_definite(n, m)

A random (n + m) by (n + m) positive semidefinite matrix of rank at most n and element type T (Float64 by default), as A*A' for a random (n + m) by n matrix A with entries uniform in [0, 1).

source
JosephsonCircuits.rand_pseudo_unitary_block Method
julia
rand_pseudo_unitary_block(n::Integer)

Return a random 2n x 2n pseudo-unitary matrix S, S ∈ U(n, n), with block operator order.

source
JosephsonCircuits.rand_pseudo_unitary_pair Method
julia
rand_pseudo_unitary_pair(n::Integer)

Return a random 2n x 2n pseudo-unitary matrix S, S ∈ U(n, n), with pair operator order.

source
JosephsonCircuits.rand_symplectic_block Method
julia
rand_symplectic_block(T, n::Integer)

Return a random 2n x 2n symplectic matrix S, S ∈ Sp(2n, ℝ) or S ∈ Sp(2n, ℂ), depending on the type T with block operator order.

source
JosephsonCircuits.rand_symplectic_block Method
julia
rand_symplectic_block(n::Integer)

Return a random 2n x 2n symplectic matrix S, S ∈ Sp(2n, ℝ), with block operator order.

source
JosephsonCircuits.rand_symplectic_pair Method
julia
rand_symplectic_pair(n::Integer)

Return a random 2n x 2n symplectic matrix S, S ∈ Sp(2n, ℝ), with pair operator order.

source
JosephsonCircuits.rationalvalues! Method
julia
rationalvalues!(vals, p, s, Lscale, Jrs, transposed, terms, weights)

Overwrite vals, the entries of the rational blocks on the Jacobian's pattern at the complex stage frequency s, from the blocks' stage transfers terms (see rationalstageterms) weighted: the unconverted response with one, and each modulated output of a pumped block with its entry of weights, in the order of the coupling's terms after the first, or with nothing of the modulated outputs when weights is nothing. A pumped block's stage operator is refreshed this way at every step with the mean of its two stages' weights, since its converted coupling can be as large as its unconverted one, which the frozen operator of the simplified Newton would not converge without.

source
JosephsonCircuits.real_to_complex! Method
julia
real_to_complex!(xc, xr, isreal) -> xc

Real -> complex. The imaginary part of a real mode is written as an explicit zero, so the result does not depend on what was in xc beforehand.

source
JosephsonCircuits.realblockterm Method
julia
realblockterm(v, dr, dc)

The entry at offset (dr, dc) of the real block a complex value v contributes: the two by two block [real(v) -imag(v); imag(v) real(v)] which multiplication by v is in the (real, imag) coordinates of a complex mode, of which a self conjugate (real) mode keeps only the first row, the first column, or both. The one rule behind every real form in the package: the sparse complex_to_real, the real Jacobian assembly and the block factorization values.

source
JosephsonCircuits.realdim Method
julia
realdim(dim, isreal) -> Int

Length of the real form of a dim-long complex axis under mask isreal.

source
JosephsonCircuits.realjacobianstructure Method
julia
realjacobianstructure(Amatrixindices::Matrix, Amatrixconjindices::Matrix,
    Ljb::SparseVector, Rbnm::SparseMatrixCSC, Nmodes::Integer,
    Nbranches::Integer, invLnm, Gnm, Cnm, rl::ModeLayout, cl::ModeLayout,
    ::Type{T} = Float64; transposed = false, backend = CPU())

The sparsity structure of the real Jacobian, and the branch incidence the assembly needs with it: (P, nodesandsigns).

P is a SparseMatrixCSC with zero values on a host and a DeviceSparsePattern on a backend, which is what a device factorization can be built from without a conversion. transposed returns the structure of the transpose, whose stored order is the row major order of the Jacobian.

Nothing sized by the circuit is built on the host on a backend: the complex pattern is built and transposed there and expanded there, and the only host inputs are the node adjacency and the active mode rows.

source
JosephsonCircuits.realstructureentry Method
julia
realstructureentry(::Type{T}, rri, rci, Nmodes, Nfreq, ami, amc, pairptr,
    pairrow, pairjunc, paircoef, lmolj, rlinv, rlptr, clinv, clptr,
    phimatrix)

The Josephson contribution to the stored entry of the real Jacobian at row rri and column rci, which is what every real assembly kernel computes, the two here and the block preconditioner's blockassemblykernel!, and the only thing they share.

The entry is decoded to the (node, mode) pair of its row and of its column, the junctions incident on that node pair are looked up, and their contributions summed. (r0, c0) and (r0+1, c0+1) are the real part entries and (r0+1, c0) and (r0, c0+1) the imaginary part ones, so a stored entry belongs to exactly one of the two and only one kind of contribution can reach it.

source
JosephsonCircuits.realtocomplexkernel! Method
julia
realtocomplexkernel!(xc, xr, lptr, lwide)

Expand the equivalent real representation of a node vector into the complex one, one work item per complex entry, reading the real slot layout the plan already carries. The imaginary part of a self conjugate mode is written as an explicit zero, so the result does not depend on what was in xc beforehand. Each work item owns its own entry, so this is conflict free. The scalar real_to_complex! it replaces on this path advances a serial cursor and reads a BitVector, neither of which a device can do. See NonlinearTermPlan.

source
JosephsonCircuits.rebind! Method
julia
rebind!(sys::HBSystem, invLnm, Gnm, Cnm, bnm, Ljb, Ljbm, Lscale;
    maps = nothing, realjacobianplan = sys.realjacobianplan,
    complexjacobianplan = sys.complexjacobianplan)

The same system at new component values: the linear term matrices, the source, the junction inductances and the scale are replaced by the new ones, in place where the arrays live and by a new struct sharing them where a scalar does. The transforms, the index maps, the kernels and every workspace stay, and nothing the size of the plan is allocated; with maps given the only allocations are the two temporaries of the source vector.

The structure must not have moved: a sparse pattern which differs from the one the system was built on is refused, because the plans are built on the pattern and a value which moves it is a new circuit and not a new point.

The assembly plans of the Jacobians hold the gathered linear term and, in their JunctionStructure, Lscale/Lj; a plan the system holds is refreshed to the new values here, and a plan passed as realjacobianplan or complexjacobianplan, built for the new values by a solve which needs a Jacobian the system did not hold, is installed instead.

source
JosephsonCircuits.rebind! Method
julia
rebind!(pc::ModeCouplingPreconditioner, sys::HBSystem)

The same preconditioner over a system rebound to new component values: the constant linear contribution of its assembly plan and the junction coefficients are refreshed from the system, and the structure, the coupling set and the factorization's symbolic analysis are kept. The next updatepreconditioner! refactorizes the numbers.

source
JosephsonCircuits.refactorize! Method
julia
refactorize!(pc::ModeCouplingPreconditioner)

Assemble the restricted Jacobian at the system's current point and factorize it: what updatepreconditioner! does after setting the point and choosing the coupling set.

A block factorization does not pivot across supernodes, so a supernode whose diagonal block is singular stops it although the whole matrix need not be singular: a node whose stiffness at some mode frequency lives in a promoted branch current (the current of a coupled inductor, the port current of a scattering block) has an exactly zero diagonal there when its own elements resonate. When that happens the preconditioner switches to the backend's sparse factorization of the same coupling set, which pivots over the whole matrix, and keeps it for the rest of the solve.

source
JosephsonCircuits.refill! Method
julia
refill!(lin::PaddedLinearTerm, invLnm, Gnm, Cnm, AmnaL, bbm, Rbnm0)

Move the values of a new assembly of the unpadded matrices, of the coupled inductor rows AmnaL (or nothing when there are none) and of the branch drive bbm into the padded linear term, in place. The result is entry for entry what hbnlsolve assembles from the same inputs.

source
JosephsonCircuits.refinedsolve! Method
julia
refinedsolve!(X, F::SparseBlockFactorization, B; transposed = false)

The batched solve, refined against the residual when the factors are in single precision: X += F \ (B - A X) while each step lowers the residual, at most refinesteps steps. Exact factors solve once.

source
JosephsonCircuits.refreshblockstamps! Method
julia
refreshblockstamps!(wbs::WorkerBlockSensitivity, wmodes)

Rebuild this worker's :S stamp values at the signed mode frequencies wmodes.

source
JosephsonCircuits.refreshstageoperator! Method
julia
refreshstageoperator!(rw::RationalWork, sys::TransientSystem,
    bf::GaussBatchFactor)

Refresh the entries of the rational blocks in the stage operator of the factor bf at the step's weights, the mean of the two stages' (see rationalvalues!), for a circuit with a pumped block; nothing otherwise. The values are the factor's own, so the system is read only to the batches stepping on it at once. The caller factorizes the operator again after it, and rebuilds the stage correction on the new factorization.

source
JosephsonCircuits.refreshvalues! Method
julia
refreshvalues!(plan::StructureComplexJacobianPlan, invLnm, Gnm, Cnm,
    wmodesm, wmodes2m, Ljb, Lscale)

Rewrite the gathered linear term and the junction coefficients of a complex plan for new component values under the same structure.

source
JosephsonCircuits.refreshvalues! Method
julia
refreshvalues!(S::BlockStructure, sys::HBSystem)

The assembly ingredients of a block structure refreshed from a system rebound to new component values: the linear term matrices, the junction coefficients and the pair table. The structure and the ordering are kept.

source
JosephsonCircuits.refreshvalues! Method
julia
refreshvalues!(js::JunctionStructure, Ljb::SparseVector, Lscale)

Rewrite the junction coefficients Lscale/Lj of a structure for new component values; the table and the index matrices are what they were. The junctions must be the same ones.

source
JosephsonCircuits.refreshvalues! Method
julia
refreshvalues!(plan::NonlinearTermPlan, maps::ValueMaps, Knm, Ljb, Lscale)

Rewrite the value arrays of a plan through its ValueMaps: up to three kernels over the arrays where they live (the real form only when the plan has one, the Josephson coefficients only when there are junctions); nothing the size of the plan is allocated, a junction length vector of inductances is.

source
JosephsonCircuits.refreshvalues! Method
julia
refreshvalues!(plan::NonlinearTermPlan, Rbnm, Ljb, Lscale, Knm, layout,
    freqindexmap)

Rewrite the value arrays of a plan for new component values under the same structure: the Josephson coefficients Lscale/Lj, and the linear term in both representations. Everything else in the plan is structure, which the new values must share; the maps are rebuilt and their structure checked against the plan's before the values are copied in, on whichever backend the plan lives on.

This is what makes a system reusable across the points of a sweep: the transforms, the index maps and the kernels stay, and the numbers move.

source
JosephsonCircuits.refreshvalues! Method
julia
refreshvalues!(plan::StructureRealJacobianPlan, invLnm, Gnm, Cnm,
    wmodesm, wmodes2m, Ljb, Lscale)

Rewrite the value arrays of an assembly plan for new component values under the same structure: the constant linear contribution of each stored entry, and Lscale/Lj per junction. The incidence products and the structure are what they were.

source
JosephsonCircuits.relationat Method
julia
relationat(r::JunctionRelations, phi)

The current-phase relation of every junction at the branch phases phi, whose first axis is the junction: sin.(phi) when every relation is the Josephson one, and the polynomials by Horner otherwise. Allocating, for the setup, the diagnostics and the noise, which are not inside a step loop; relationinto! is the in place form the steps take.

phi and the table must live on the same backend, so a host path takes a host table from hostrelations.

source
JosephsonCircuits.relationinto! Method
julia
relationinto!(out, r::JunctionRelations, phi)

relationat writing into out, which may not alias phi. A circuit whose junctions are all sinusoidal takes the single broadcast of sin it always did.

source
JosephsonCircuits.remove_edge! Method
julia
remove_edge!(g,src_node,edge_index)

Remove an edge from graph g specified by the source node src_node and the edge index edge_index in the forward adjacency list.

Examples

julia
julia> g=JosephsonCircuits.Graphs.SimpleDiGraphFromIterator(JosephsonCircuits.tuple2edge([(1,1),(2,1),(2,3)]));JosephsonCircuits.remove_edge!(g,1,1)
1
source
JosephsonCircuits.removeconjfreqs Method
julia
removeconjfreqs(frequencies::Frequencies{N})

Return a new Frequencies struct with the conjugate symmetric terms in the DFT or RDFT removed.

source
JosephsonCircuits.removefreqs Method
julia
removefreqs(frequencies::Frequencies{N},
    removecoords::AbstractVector{CartesianIndex{N}})

Return a new Frequency struct with the coordinates and modes for the modes in removemodes removed.

source
JosephsonCircuits.removefreqs Method
julia
removefreqs(frequencies::Frequencies{N},
    removemodes::AbstractVector{NTuple{N,Int}})

Return a new Frequency struct with the coordinates and modes for the modes in removemodes removed.

source
JosephsonCircuits.reparameterize Method
julia
reparameterize(stamp::SensitivityStamp, alpha, parameter)

The same stamp expressed as the derivative with respect to a real design parameter rather than a relative perturbation of the component value.

A component's contribution to the system matrix is linear in its value c, and the negative frequency conjugation is applied to the stored value at contraction time (sensitivitystampvalue), so

julia
d/dtheta modevalue(c, w) = modevalue(dc/dtheta, w),

and the stamp for theta is the stamp for c rescaled by alpha = (dc/dtheta)/c. Nothing else changes: the sparsity, the kind and the frequency scaling are all properties of the component, not of the parameterization.

This is what makes the real parameter form correct for complex component values, where the relative form is not. A relative perturbation moves c along itself, so dS/dr is a single complex number which cannot resolve the two real directions of a complex c; carrying dc/dtheta as the direction resolves them, because a real theta which rotates c in the complex plane produces a dc/dtheta which is not parallel to c.

source
JosephsonCircuits.reset! Method
julia
reset!(cache::HBCache)

Discard the stored operating point, so the next hbsolve! starts cold. Use this when the parameters move far enough that the previous solution is a worse starting point than zero, or when crossing to a different solution branch.

source
JosephsonCircuits.residual! Method
julia
residual!(F::AbstractVector, sys::HBSystem)

Evaluate the residual of the harmonic balance nonlinear system, F = B(sin.(A*x)) + K*x - b, at the point set with setpoint!, in place. Dispatches on the element type of F: a complex vector receives the complex representation and a real vector the equivalent real representation.

source
JosephsonCircuits.residualstalled Function
julia
residualstalled(normF::AbstractVector, start::Integer,
    history::Integer = STALLHISTORY; atol = nothing, remaining = nothing)

Whether the residual history normF[start:end] has stalled. The whole history from start is judged, once it is at least history points long: it is split in half and a geometric rate taken over each. A later rate better than the earlier one is an iteration accelerating into a Newton basin, never a stall. Otherwise the residual has stalled when it is flat or rising, and, given the tolerance atol and a budget of remaining further steps, when the steps its later rate projects to the tolerance, log(atol/normF)/log(rate), exceed the budget. A plateau after a long descent is judged against the whole descent, so it is a stall only once it is long enough to bring the later rate to one; a caller which wants a fresh judgement moves start forward, as the Krylov loop does after its recovery.

The projection is what ends a solve whose line search keeps finding a decrease: along a descent direction a short enough step always meets the Armijo condition, and with an inexact direction the residual can creep for the whole iteration budget without its rate reaching one. Near a plateau the projection diverges, so only a loop which gives a first stall a recovery over a fresh history takes it, as the Krylov loop does. The direct loop judges the rate alone: a direct solve whose residual keeps coming down, however slowly, runs to its iteration budget.

source
JosephsonCircuits.resolveautomatic Method
julia
resolveautomatic(sys, Rbnm, Nmodes, Nbranches, layout, Amatrixmodes,
    backend; budget = freememory(backend) ÷ 2)

The member of the mode coupling family an Automatic request stands for on this problem: FullJacobian with the backend's sparse factorization for one tone; otherwise FullJacobian with single precision block factors when blockfactorbytes is within budget, and MeasuredBand when it is not.

One tone takes the full Jacobian for one Krylov iteration per Newton step and no escalation, without sizing its factors first: they grow with the square of the mode count, which one tone keeps low, and a problem too large for them wants preconditioner = BlockDiagonal(). The exact step is no more robust from a cold start than an inexact one; a cold start no line search reaches is the continuation problem Staged exists for.

source
JosephsonCircuits.restrictmodecoupling Method
julia
restrictmodecoupling(Amatrixindices::Matrix, keep::AbstractMatrix{Bool})

Return a copy of a mode coupling index matrix (Amatrixindices or Amatrixconjindices, see hbmatind) with the couplings not selected by keep set to zero.

This is the whole of the coarse frequency grid transformation. A zero entry of these matrices already means "this coupling falls outside the retained grid and is dropped", which planstructurerealjacobian honors when it builds the sparsity structure (through activemoderows) and when it assembles the values. Zeroing entries therefore produces a Jacobian assembly plan for the mode restricted operator directly: the restricted Jacobian is materialized with the restricted structure rather than assembled in full and masked afterwards, so the saving is realized in the sparsity, the fill in, and the factorization, not just in the arithmetic.

The frequency dependent linear terms invLnm, Gnm and Cnm (including the modified nodal analysis augmentation and the gauge fixing equations) are mode diagonal by construction, so they are unaffected by the restriction and are kept exactly. All of the mode coupling of the Jacobian lives in these two index matrices.

source
JosephsonCircuits.rootedtree Method
julia
rootedtree(tree)

Root the tree tree at vertex 1 by breadth first search and return the parent and the depth of every vertex (parent 0 and depth 0 for the root; depth -1 for a vertex unreachable from it).

treepath walks between two vertices using both: the depths bring the two ends to the same level and the parents carry them up to where they meet.

source
JosephsonCircuits.rowpointer Method
julia
rowpointer(A::DeviceValuedSparseMatrix)

The compressed sparse row pointer of A, which is the column pointer of the transpose it stores.

source
JosephsonCircuits.scattercanonical! Method
julia
scattercanonical!(rint, u, L::CompositeLayout)

Write the internal block of the canonical state u into rint, a copy. The inverse of gathercanonical! on that block.

source
JosephsonCircuits.scattering_to_block_perm Method
julia
scattering_to_block_perm(p0::Vector{Int})

Return a permutation vector that converts one axis of a scattering matrix with Nports ports and Nmodes modes from (port,mode) ordering to a (mode,port) ordering. For example, for 2 ports with indices 1,2 and 4 modes with indices 1,2,3,4 then (port,mode) order is: [(1,1),(1,2),(2,1),(2,2),(3,1),(3,2),(4,1),(4,2),(1,1),(1,2),(2,1),(2,2),(3,1),(3,2),(4,1),(4,2)] and (mode,port) order is: [(1,1),(1,2),(1,3),(1,4),(2,1),(2,2),(2,3),(2,4),(1,1),(1,2),(1,3),(1,4),(2,1),(2,2),(2,3),(2,4)] The permutation to change the first into the second is in the example below:

Examples

julia
julia> JosephsonCircuits.scattering_to_block_perm(JosephsonCircuits.ports_modes_to_modes_ports_perm(2,4))
16-element Vector{Int64}:
  1
  3
  5
  7
  2
  4
  6
  8
  9
 11
 13
 15
 10
 12
 14
 16
source
JosephsonCircuits.scattering_to_ladder_block Method
julia
scattering_to_ladder_block(S_scattering::AbstractMatrix, w)
source
JosephsonCircuits.scattering_to_ladder_block Method
julia
scattering_to_ladder_block(S_scattering::AbstractVector, w)
source
JosephsonCircuits.scattering_to_ladder_pair Method
julia
scattering_to_ladder_pair(S_scattering::AbstractMatrix, w)
source
JosephsonCircuits.scattering_to_ladder_pair Method
julia
scattering_to_ladder_pair(S_scattering::AbstractVector, w)
source
JosephsonCircuits.scattering_to_pair_perm Method
julia
scattering_to_pair_perm(p0::Vector{Int})

Return a permutation vector that converts one axis of a scattering matrix with Nports ports and Nmodes modes from (port,mode) ordering to a (mode,port) ordering. For example, for 2 ports with indices 1,2 and 4 modes with indices 1,2,3,4 then (port,mode) order is: [(1,1),(1,1),(1,2),(1,2),(2,1),(2,1),(2,2),(2,2),(3,1),(3,1),(3,2),(3,2),(4,1),(4,1),(4,2),(4,2)] and (mode,port) order is: [(1,1),(1,1),(1,2),(1,2),(1,3),(1,3),(1,4),(1,4),(2,1),(2,1),(2,2),(2,2),(2,3),(2,3),(2,4),(2,4)] The permutation to change the first into the second is in the example below:

Examples

julia
julia> JosephsonCircuits.scattering_to_pair_perm(JosephsonCircuits.ports_modes_to_modes_ports_perm(2,4))
16-element Vector{Int64}:
  1
  2
  5
  6
  9
 10
 13
 14
  3
  4
  7
  8
 11
 12
 15
 16
source
JosephsonCircuits.scattering_to_quadrature_block Method
julia
scattering_to_quadrature_block(S_scattering::AbstractVector{Complex{T}}, w) where {T}
source
JosephsonCircuits.scattering_to_quadrature_block Method
julia
scattering_to_quadrature_block(S_scattering::AbstractMatrix{Complex{T}}, w) where {T}
source
JosephsonCircuits.scattering_to_quadrature_pair Method
julia
scattering_to_quadrature_pair(S_scattering::AbstractVector{Complex{T}}, w) where {T}
source
JosephsonCircuits.scattering_to_quadrature_pair Method
julia
scattering_to_quadrature_pair(S_scattering::AbstractMatrix{Complex{T}}, w) where {T}
source
JosephsonCircuits.scatteringblockindex Method
julia
scatteringblockindex(c::CompiledCircuit, name)

The position in c.scatteringblocks of the block whose instance path is name, or zero when there is none. The spelling "<path>/port1" is also accepted for compatibility with names the design sensitivities once produced.

source
JosephsonCircuits.scatteringlinearterm Method
julia
scatteringlinearterm(psc::CompiledCircuit, wmodes::AbstractVector,
    Nmodes::Integer; auxoffset::Integer, Ntotal::Integer,
    scale::Real = 1.0, blocks = nothing)

The constant sparse matrix of the scattering block contribution at the fixed mode frequencies wmodes (the constitutive entries plus the Kirchhoff current law couplings of the auxiliary port currents), or nothing when the circuit has no scattering blocks. Used by the nonlinear (pump) solver, where the mode frequencies do not change: the contribution is folded into the frequency independent linear term alongside the augmentation matrix of the promoted resistors, so the residual, Jacobian, and solver machinery operate on the augmented system unchanged. blocks stamps the given compiled blocks instead of psc.scatteringblocks.

source
JosephsonCircuits.scatteringnoisenames Method
julia
scatteringnoisenames(plan::ScatteringNoisePlan,
    ssys::ScatteringStampSystem)

The name of each noise channel of the plan, for labelling the rows of a keyed noise scattering matrix. A block with more than one port has one channel per port, distinguished by a channel number, because the columns of the factor of I - S S' mix the ports and no single port owns a channel. The channels of the conjugate kind of a block which states its noise follow its channels of the first kind, marked with a prime.

source
JosephsonCircuits.scatteringnoisewaves! Function
julia
scatteringnoisewaves!(noiseoutputwave, plan::ScatteringNoisePlan,
    ssys::ScatteringStampSystem, phiadj, wmodes, rowoffset,
    work = ScatteringNoiseWorkspace())

Write the noise output waves of the scattering block channels of plan into the rows of noiseoutputwave after rowoffset, from the adjoint solution phiadj at the mode frequencies wmodes.

The noise wave n of a block enters its constitutive equation as a source in the auxiliary port current rows, so by the adjoint identity its contribution to the output is that source contracted against those same rows of the adjoint solution, weighted by the factor L of the vacuum covariance L L' = I - S S':

julia
noiseoutputwave[channel c] = sqrt(abs(w)) sum_p L[p,c] i[p]

phiadj must be the solution of the transposed system, which is what hblinsolve solves for its adjoint. The conjugated pump system, which is the same matrix for a circuit without blocks, is not: it agrees with the transposed system in the node flux rows and not in the auxiliary port current rows, and on a non reciprocal block the two differ by the direction the block transmits in, so contracting it would give a block which emits its noise backwards.

A block which states its noise with a NoiseCovariance V has its channels of the first kind weighted by the factor of (V + K)/2 and, in the rows after them, its channels of the conjugate kind by the factor of (V - K)/2, with K = I - S S', which checkblocknoisemodels has admitted at every mode frequency of the sweep, or which a completed covariance meets by construction.

The channel of a mode whose frequency is zero is zero, matching the wave normalization of the lumped noise ports, which is singular there.

source
JosephsonCircuits.scatteringstampsystem Method
julia
scatteringstampsystem(blocks::Vector{CompiledScatteringBlock}, Nmodes;
    auxoffset, Ntotal, scale = 1.0, modeoffsets = nothing, iscale = 1.0)

The stamp system of the compiled scattering blocks of a circuit.

A compiled block is one instance carrying its own terminal map, so this needs no regrouping and none of the checks which the per port form does: a block cannot be missing a port, cannot repeat one, and cannot be confused with another instance of the same definition. modeoffsets are the frequency offsets of the modes, which a pumped block's coupling between them reads, and iscale the scale of the auxiliary port current unknowns; see scatteringstampsystem.

source
JosephsonCircuits.scatteringstampsystem Method
julia
scatteringstampsystem(blocks::Vector{StampedScatteringBlock}, Nmodes,
    Ntotal, scale; modeoffsets = nothing, iscale = 1.0)

The positional inner form of scatteringstampsystem, everything past the point where the blocks and their terminals are known: the Kirchhoff current law couplings, the constitutive pattern and the contribution tables of a ScatteringStampSystem. Unlike the keyword form it never returns nothing.

modeoffsets are the frequency offsets of the modes from the signal, in radians per second. A LinearizedScattering block couples the modes whose offsets differ by a harmonic of its pump, so with one present the offsets are required, and the contributions between such pairs are entered on top of the diagonal ones; a block which does not convert takes no notice of them.

iscale is the scale of the auxiliary port current unknowns; see ScatteringStampSystem.

source
JosephsonCircuits.scatteringvalues! Method
julia
scatteringvalues!(values::AbstractVector, ssys::ScatteringStampSystem,
    wmodes::AbstractVector, work::ScatteringWorkspace)

The value each scalar contribution of the scattering blocks adds to the system matrix at the signed mode frequencies wmodes, in the order of ssys.Aindex.

This is the half of assemblescattering! which has to run on the host, because it evaluates each block through its provider, which may be an arbitrary callable or an interpolation of tabulated data. What is left is a gather-add of these values into the stored entries, which is where the two backends part company: the host adds them here, and a device adds them with a kernel (see DeviceScatteringStamps). Splitting it this way is what lets both backends stamp identical values.

source
JosephsonCircuits.scattervalues! Method
julia
scattervalues!(dest::AbstractVector, src::AbstractVector,
    index::AbstractArray)

dest[index[k]] = src[k] for every k, as a KernelAbstractions kernel on the backend of src. The inverse of gathervalues! when index is a permutation; index must not repeat, or the writes race.

source
JosephsonCircuits.seeddeflation! Method
julia
seeddeflation!(pc, Xnew::AbstractMatrix; source = :external)

Offer the columns of Xnew to pc as candidate physical correction vectors, between two linear solves, and return pc. The default does nothing, which is correct for any preconditioner which does not deflate.

This is the injection point for an external candidate source: a continuation secant, a Newton step, or a physically constructed Floquet mode. Candidates are not selected here: the rank and benefit filters run at the next rebuild, where they are concatenated with the bank and compressed together against their exact residual images, which is what lets several sources rediscover the same channel without any of them having to know about the others; but every column is normalized, a numerically zero column is dropped, and the bank is trimmed to the option's candidates. The seed marks the active blocks stale when the bank grew, so the next application rebuilds them and the seeded directions take part in the very next solve (a seed into a bank already at the option's candidates may be trimmed away and then changes nothing); for that reason it must not be called while a GMRES solve is running, where the preconditioner has to stay fixed. The harvest banks its candidates through the internal _bankcandidates!, which does not mark anything stale.

source
JosephsonCircuits.segmentbydest! Method
julia
segmentbydest!(seg, perm, dest, backend)

Group dest into contiguous segments by value, writing the segment pointer into seg and, into perm, the positions of dest ordered by segment.

The result is a permutation rather than a copy: the caller gathers whatever payload it has through perm, which keeps this independent of how many arrays travel with the destinations.

The grouping must be stable, because it fixes the order in which the contributions to one entry are added and floating point addition is not associative. A histogram with an atomic cursor is not stable, so the order the positions were emitted in is restored afterwards by sorting each segment. That is cheap because the segments are tiny – 28.8 million contributions over 21.7 million entries is an average of 1.33 – and it is why this is not done with a general sort, which measured 0.315 s on 28.8 million keys.

source
JosephsonCircuits.selfconjmodes Method
julia
selfconjmodes(frequencies::Frequencies)

Return a vector of booleans indicating which of the modes of frequencies are their own complex conjugates on the sampled grid, which is the case when twice the mode aliases to zero along every dimension. The Fourier coefficients of a real signal at those modes, such as dc, are purely real.

Examples

julia
julia> freq = JosephsonCircuits.removeconjfreqs(JosephsonCircuits.truncfreqs(JosephsonCircuits.calcfreqsrdft((3,));dc=true,odd=true,even=true));JosephsonCircuits.selfconjmodes(freq)
4-element Vector{Bool}:
 1
 0
 0
 0
source
JosephsonCircuits.sensitivitydim Method
julia
sensitivitydim(op::HBOperatingPoint)

The dimension of the space the residual derivatives and the adjoint covectors live in: canonical with a direct current block, and the real representation of the augmented harmonic state without one.

source
JosephsonCircuits.sensitivityjacobian Method
julia
sensitivityjacobian(op::HBOperatingPoint)

The Jacobian the implicit function theorem applies to at op: the canonical one when an explicit direct current block is active, and the harmonic one otherwise.

The forward and the reverse contraction both solve against this, forward through it and reverse through its transpose, so naming it once is what keeps the two orders solving the same system.

source
JosephsonCircuits.sensitivitypairtable Method
julia
sensitivitypairtable(pairs)
sensitivityblockpairtable(pairs)

The (name, parameter, direction) sensitivity pairs of a component or of a scattering block as vectors of one tuple type, the direction of a component pair as a complex number.

source
JosephsonCircuits.sensitivitystampvalue Method
julia
sensitivitystampvalue(stamp::SensitivityStamp, t::Integer, wmodes,
    Nmodes)

The value of entry t of the derivative of the linearized harmonic balance system matrix with respect to a relative perturbation of the component of stamp, at the mode frequencies wmodes. Applies the same per mode frequency scaling and negative frequency mode conjugation as assemblesystemmatrix!, which are indexed by the column.

source
JosephsonCircuits.setdrive! Method
julia
setdrive!(prob::HBNonlinearProblem, scale)

Scale the drive of prob by scale, in place, and return the problem.

The residual is F(u) = B(sin(A*u)) + K*u - b, and the drive enters only through b. Scaling it is therefore the one parameter which can be varied without rebuilding anything: the sparsity, the plans and the preconditioner structure are all untouched.

This is what makes continuation in pump power possible. scale = 0 is the undriven problem, whose solution is zero and whose Jacobian is the linear circuit; stepping up to scale = 1 and carrying the converged state forward walks onto the driven branch, which is the reliable way to reach an operating point a cold solve cannot find.

The scale is relative to the drive the problem was built with, so setdrive!(prob, 1) restores it.

source
JosephsonCircuits.setfactorization Method
julia
setfactorization(s::AbstractModeCoupling, f)

The mode coupling set s with its factorization replaced by f, whatever it carried: what a preconditioner applies to its coupling set when it changes the factorization it is built with, so that the set always carries the factorization of its factors.

source
JosephsonCircuits.setpoint! Method
julia
setpoint!(sys::HBSystem, x::AbstractVector)

Set the point at which residual!, jacobianvectorproduct!, hessianvectorproduct! and jacobian! evaluate the harmonic balance nonlinear system, and cache the time domain branch fluxes there. Accepts the complex vector of node fluxes or the equivalent real representation, dispatched on the element type. Returns sys.

source
JosephsonCircuits.setscatteringindexmap! Method
julia
setscatteringindexmap!(ssys::ScatteringStampSystem,
    A::SparseMatrixCSC)

Point the destination indices of the frequency dependent contributions at the nonzero values of the system matrix A, whose sparsity structure must contain the pattern of ssys (ensure this by merging ssys.pattern into the structure before calling, as HBLinearizedSystem does; the constant ssys.kcl couplings are folded into the constant augmentation matrix instead).

source
JosephsonCircuits.showstruct Method
julia
showstruct(io::IO,out)

Print the struct out to io as its constructor name (without type parameters) applied to its fields, each printed with testshow.

Examples

julia
julia> JosephsonCircuits.testshow(stdout,JosephsonCircuits.NoiseReduction([1.0, 2.0], [3.0, -4.0]))
JosephsonCircuits.NoiseReduction{Vector{Float64}}([1.0, 2.0], [3.0, -4.0])

julia> JosephsonCircuits.testshow(IOBuffer(),JosephsonCircuits.warmupsyms())
source
JosephsonCircuits.snapscattering Method
julia
snapscattering(S::AbstractMatrix)

The real scattering matrix S with every entry within 1e-12 of a perfect open, short or isolation snapped to the exact 1, -1 or 0, which is how a block realized in time stamps it. The hybrid coefficients I - S and I + S of a port whose feedthrough reaches the unit circle then hold exact zeros where the algebra has them, so the endpoint's rate system sees a zero row rather than the roundoff residue of one, which its balancing would otherwise scale up into an equation whose inverted singular value multiplies the residual by the reciprocal of machine epsilon at every step. The snap moves an entry by less than 1e-12, far below any scattering the data resolves.

source
JosephsonCircuits.solveS! Method
julia
solveS!(Se, Si, Ce, Ci, portse, portsi, gammaii, See, Sei, Sie, Sii,
    See_indices, Sei_indices, Sie_indices, Sii_indices, gammaii_indexmap,
    Sii_indexmap, scattering_parameters, noise_covariances, nbatches,
    factorization, internal_ports, noise)

In place version of solveS, taking the arrays returned by solveS_initialize, which it is meant to be called with as solveS!(init...). It allows a network connection to be updated in place: change the arrays referenced by networks, then recompute the scattering parameters of the connected system.

Examples

julia
networks = [("S1",[0.0 1.0;1.0 0.0]),("S2",[0.5 0.5;0.5 0.5])];
connections = [[("S1",1),("S2",2)]];
init = JosephsonCircuits.solveS_initialize(networks, connections);
JosephsonCircuits.solveS!(init...)

# output
(S = [0.5 0.5; 0.5 0.5], ports = [("S1", 2), ("S2", 1)], Sinternal = Float64[], portsinternal = [("S1", 1), ("S2", 2)])

References

V. A. Monaco and P. Tiberio, "Computer-Aided Analysis of Microwave Circuits," in IEEE Transactions on Microwave Theory and Techniques, vol. 22, no. 3, pp. 249-263, Mar. 1974, doi: 10.1109/TMTT.1974.1128208.

source
JosephsonCircuits.solveS Method
julia
solveS(networks, connections; small_splitters::Bool = true,
    noise::Bool = false, factorization = KLUfactorization(),
    internal_ports::Bool = false, Nmodes::Integer = 1,
    nbatches::Integer = Base.Threads.nthreads())

Perform the connections between the networks in networks specified by the vector of vectors of tuples connections. Return the sparse matrix of scattering parameters for the external ports S and the external ports ports. Also return the internal port scattering parameters Sinternal and the internal ports portsinternal.

Arguments

  • networks: a vector of tuples of the network name, scattering parameter matrix, and optionally the ports such as [("network1name",rand(Complex{Float64},2,2))] or [("S1",[0.0 1.0;1.0 0.0]),("S2",[0.5 0.5;0.5 0.5])].

  • connections::AbstractVector{<:AbstractVector{Tuple{T,Int}}}: a vector of vectors of tuples of networks names and ports such as [[("S1",1),("S2",2)]] or [[("network1name",1),("network2name",2)]] where network1 and network2 are the two networks being connected and 1 and 2 are integers describing the ports to connect.

Keywords

  • small_splitters::Bool = true: if true, then generate any N port splitter by combining (N-2) 3 port splitters. if false, then make the N port splitter and connect the components to it.

  • noise::Bool = false: also connect the noise covariance matrices of the networks. A network given as (name, S) gets the passive covariance I - S S'; one given as (name, S, C) uses C.

  • factorization = KLUfactorization(): the sparse factorization of the connection system; LUfactorization is another good choice.

  • internal_ports::Bool = false: return the scattering parameters for the internal ports.

  • Nmodes::Integer = 1: the number of modes of each physical port when the scattering matrices are multi-mode, in which case connections names physical ports and each is expanded to its modes (see add_modes).

  • nbatches::Integer = Base.Threads.nthreads(): the number of batches to run on threads. Defaults to the number of threads with which Julia was launched.

Returns

  • S: sparse matrix of scattering parameters for the external ports.

  • ports: the vector of tuples of network name and port number for the external ports.

  • Sinternal: sparse matrix of scattering parameters for the internal ports.

  • portsinternal: the vector of tuples of network name and port number for the internal ports.

Examples

julia
networks = [("S1",[0.0 1.0;1.0 0.0]),("S2",[0.5 0.5;0.5 0.5])];
connections = [[("S1",1),("S2",2)]];
JosephsonCircuits.solveS(networks,connections;internal_ports=true)

# output
(S = [0.5 0.5; 0.5 0.5], ports = [("S1", 2), ("S2", 1)], Sinternal = [1.0 0.0; 0.5 0.5], portsinternal = [("S1", 1), ("S2", 2)])
julia
networks = [("S1",[0.0 1.0;1.0 0.0]),("S2",[0.5 0.5;0.5 0.5],[("S3",5),("S3",6)])];
connections = [("S1","S3",1,6)];
JosephsonCircuits.solveS(networks,connections)

# output
(S = [0.5 0.5; 0.5 0.5], ports = [("S1", 2), ("S3", 5)], Sinternal = Float64[], portsinternal = [("S1", 1), ("S3", 6)])

References

V. A. Monaco and P. Tiberio, "Computer-Aided Analysis of Microwave Circuits," in IEEE Transactions on Microwave Theory and Techniques, vol. 22, no. 3, pp. 249-263, Mar. 1974, doi: 10.1109/TMTT.1974.1128208.

source
JosephsonCircuits.solveS_initialize Method
julia
solveS_initialize(networks, connections; small_splitters = true,
    noise = false, factorization = KLUfactorization(),
    internal_ports = false, Nmodes = 1,
    nbatches = Base.Threads.nthreads())

Build the arrays solveS! works on, from the same arguments as solveS: the external and internal port lists and scattering and covariance outputs, the connection matrix gammaii with the index maps into the networks' matrices, and the networks' scattering parameters and noise covariances. Returned as a tuple to be splatted into solveS!.

source
JosephsonCircuits.solveS_update! Method
julia
solveS_update!(See, Sei, Sie, Sii, See_indices, Sei_indices,
    Sie_indices, Sii_indices, networkdata, i)

Update the sparse matrices See, Sei, Sie, and Sii using the indices from See_indices, Sei_indices, Sie_indices, and Sii_indices which are indices into networkdata with frequency index i.

source
JosephsonCircuits.solvebatch! Method
julia
solvebatch!(ds::DeviceSweep, lo::Integer)

Solve the batch of frequencies beginning at index lo on the device and stage its solutions on the host. This is the only verb which touches the device; once it has returned, the batch's frequencies can be read by as many workers as the host path uses through forwardsolution! and adjointsolution!, because reading a solution touches staged host memory and nothing else.

source
JosephsonCircuits.solveonbackend! Method
julia
solveonbackend!(fj!, F, J, x, backend; kwargs...)

Solve the nonlinear system on the backend its Jacobian and factorization live on, returning the iteration information and writing the converged state back into the host vectors F and x.

The state has to go where the Jacobian is, so that the assembly, the linear solve and the line search all stay on one side. On CPU() tobackend adopts the caller's vectors and the copies back are between an array and itself, so this is exactly nlsolve!.

source
JosephsonCircuits.solvequasinewton! Method
julia
solvequasinewton!(method; ...)
solvenewton!(method; ...)
solvenewtonkrylov!(method; ...)
solveexternal!(method; ...)

Solve the system nonlinearsetup built, each with the fields it reads passed by name: the quasi-Newton iteration on the complex holomorphic Jacobian, Newton's method on the equivalent real system, the Newton-Krylov iteration with its mode coupling preconditioner, or the caller's own solver through a problem object. The state x, xr, F and Fr of the setup is updated in place. Returns the IterationInfo of the solve, the direct current solution and the converged canonical state (the last two nothing when there is no explicit direct current block).

source
JosephsonCircuits.solverkwargs Method
julia
solverkwargs(factorization)

The options a factorization hands to the solver it wraps, so a caller which does not know which factorization it has can forward them unconditionally. Every factorization carries its own kwargs to its own factorize; this is for the batched paths, which reach their solver without one.

source
JosephsonCircuits.solverprecision Method
julia
solverprecision(m::AbstractHBNonlinearSolver)

The floating point type the method iterates in: Float64 for every method but NewtonKrylov, whose precision it is, and the inner method's for Staged.

source
JosephsonCircuits.sortnodes Method
julia
sortnodes(uniquenodevector, nodeindexvector, order)

Apply the precomputed sorting permutation order (see calcnodesorting), returning the sorted names, the renumbered component node indices as a 2 by Ncomponents matrix, and the renumbering itself (see noderenumbering).

source
JosephsonCircuits.sortnodes Method
julia
sortnodes(uniquenodevector::Vector{String},
    nodeindexvector::Vector{Int};sorting=:name)

Sort the node names with calcnodesorting and renumber the node indices in nodeindexvector accordingly. Returns the sorted names and the renumbered indices reshaped from a vector of length 2*Ncomponents into a 2 by Ncomponents matrix. A zero index, which marks a mutual inductor, stays zero.

Note that this method defaults to sorting = :name while calcnodesorting defaults to :number.

Keywords

Examples

julia
julia> nodenames,nodeindexarray=JosephsonCircuits.sortnodes(["101","0","111","11"],[1,2,1,2,1,2,1,3,3,2,3,2,4,1],sorting=:none);println(nodenames);println(nodeindexarray);
["0", "101", "111", "11"]
[2 2 2 2 3 3 4; 1 1 1 3 1 1 2]

julia> nodenames,nodeindexarray=JosephsonCircuits.sortnodes(["101","0","111","11"],[1,2,1,2,1,2,1,3,3,2,3,2,4,1],sorting=:name);println(nodenames);println(nodeindexarray);
["0", "101", "11", "111"]
[2 2 2 2 4 4 3; 1 1 1 4 1 1 2]

julia> nodenames,nodeindexarray=JosephsonCircuits.sortnodes(["101","0","111","11"],[1,2,1,2,1,2,1,3,3,2,3,2,4,1],sorting=:number);println(nodenames);println(nodeindexarray);
["0", "11", "101", "111"]
[3 3 3 3 4 4 2; 1 1 1 4 1 1 3]

julia> nodenames,nodeindexarray=JosephsonCircuits.sortnodes(["1", "0", "2"],[1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 3, 2, 3, 2],sorting=:number);println(nodenames);println(nodeindexarray);
["0", "1", "2"]
[2 2 2 2 0 3 3; 1 1 1 1 0 1 1]
source
JosephsonCircuits.sourcetable Method
julia
sourcetable(sources, w)

The sources as a Vector{SourceTuple{N}} for the N tones of w. sources is any iterable of named tuples with the fields mode, port and current; a source whose mode does not have one integer per tone, whose port is not an integer or whose current is not a number is an ArgumentError.

source
JosephsonCircuits.spaddkeepzeros Method
julia
spaddkeepzeros(A::SparseMatrixCSC, B::SparseMatrixCSC)

Add sparse matrices A and B and return the result, keeping any structural zeros, unlike the default Julia sparse matrix addition functions.

Examples

julia
julia> A = JosephsonCircuits.SparseArrays.sprand(10,10,0.2); B = JosephsonCircuits.SparseArrays.sprand(10,10,0.2);JosephsonCircuits.spaddkeepzeros(A,B) == A+B
true
julia
A = JosephsonCircuits.SparseArrays.sparse([1,2,1], [1,2,2], [1,2,0],2,2);
B = JosephsonCircuits.SparseArrays.sparse([1,2], [1,2], [1,1],2,2);
JosephsonCircuits.spaddkeepzeros(A,B)

# output
2×2 SparseArrays.SparseMatrixCSC{Int64, Int64} with 3 stored entries:
 2  0
  3
source
JosephsonCircuits.sparseadd! Method
julia
sparseadd!(A::SparseMatrixCSC, c::Number, Ad::Diagonal,
    As::SparseMatrixCSC, indexmap::Vector)

Add sparse matrices A and c*Ad*As and return the result in A. The sparse matrix As must have nonzero entries only in a subset of the positions in A which have nonzero (structural zeros are ok) entries.

Examples

julia
A = JosephsonCircuits.SparseArrays.sparse([1,2,1], [1,2,2], [1,2,-3],2,2)
Ad = JosephsonCircuits.LinearAlgebra.Diagonal([1,-2])
As = JosephsonCircuits.SparseArrays.sparse([1,1], [1,2], [3,4],2,2)
indexmap = JosephsonCircuits.sparseaddmap(A,As)
JosephsonCircuits.sparseadd!(A,2,Ad,As,indexmap)
A

# output
2×2 SparseArrays.SparseMatrixCSC{Int64, Int64} with 3 stored entries:
 7  5
  2
source
JosephsonCircuits.sparseadd! Method
julia
sparseadd!(A::SparseMatrixCSC, c::Number, As::SparseMatrixCSC,
    Ad::Diagonal, indexmap)

Add sparse matrices A and c*As*Ad and return the result in A. The sparse matrix As must have nonzero entries only in a subset of the positions in A which have nonzero (structural zeros are ok) entries.

Examples

julia
A = JosephsonCircuits.SparseArrays.sparse([1,2,1], [1,2,2], [1,2,-3],2,2)
As = JosephsonCircuits.SparseArrays.sparse([1,1], [1,2], [3,4],2,2)
Ad = JosephsonCircuits.LinearAlgebra.Diagonal([1,-2])
indexmap = JosephsonCircuits.sparseaddmap(A,As)
JosephsonCircuits.sparseadd!(A,2,As,Ad,indexmap)
A

# output
2×2 SparseArrays.SparseMatrixCSC{Int64, Int64} with 3 stored entries:
 7  -19
    2
source
JosephsonCircuits.sparseadd! Method
julia
sparseadd!(A::SparseMatrixCSC, c::Number, As::SparseMatrixCSC, indexmap)

Add sparse matrices A and c*As and return the result in A. The sparse matrix As must have nonzero entries only in a subset of the positions in A which have nonzero (structural zeros are ok) entries.

Examples

julia
A = JosephsonCircuits.SparseArrays.sparse([1,2,1], [1,2,2], [1,2,-3],2,2)
As = JosephsonCircuits.SparseArrays.sparse([1,1], [1,2], [3,4],2,2)
indexmap = JosephsonCircuits.sparseaddmap(A,As)
JosephsonCircuits.sparseadd!(A,2,As,indexmap)
A

# output
2×2 SparseArrays.SparseMatrixCSC{Int64, Int64} with 3 stored entries:
 7  5
  2
source
JosephsonCircuits.sparseadd! Method
julia
sparseadd!(A::SparseMatrixCSC, As::SparseMatrixCSC, indexmap)

Add sparse matrices A and As and return the result in A without performing any allocations. This is only possible if the positions of elements in As are a subset of the positions of elements in A. The indexmap can be generated with sparseaddmap.

Examples

julia
A = JosephsonCircuits.SparseArrays.sparse([1,2,1], [1,2,2], [1,2,-3],2,2)
As = JosephsonCircuits.SparseArrays.sparse([1,1], [1,2], [3,4],2,2)
indexmap = JosephsonCircuits.sparseaddmap(A,As)
JosephsonCircuits.sparseadd!(A,As,indexmap)
A

# output
2×2 SparseArrays.SparseMatrixCSC{Int64, Int64} with 3 stored entries:
 4  1
  2
source
JosephsonCircuits.sparseaddconjsubst! Method
julia
sparseaddconjsubst!(A::SparseMatrixCSC, c::Number, As::SparseMatrixCSC,
    indexmap, wmodes::AbstractVector, power::Integer, symfreqvar)

Perform A += c*As*Ad with Ad the implicit diagonal whose entry in column i is the signed mode frequency of that column raised to power, wmodes[(i-1) % length(wmodes) + 1]^power, with the mode index fastest over the nodes and any auxiliary variables. The stored value of As is complex conjugated in every column whose mode frequency is negative, and symfreqvar is substituted by the mode frequency in any symbolic entries.

This is the operation of the Diagonal based method below with the frequency, conjugation flag, and substitution diagonals computed from the column index instead of materialized, which would be three system sized allocations at every call, at every signal frequency, in the assembly loop of hblinsolve.

source
JosephsonCircuits.sparseaddconjsubst! Method
julia
sparseaddconjsubst!(A::SparseMatrixCSC, c::Number, As::SparseMatrixCSC,
    Ad::Diagonal, indexmap, conjflag::Diagonal, wmodesm::Diagonal,
    symfreqvar)

Perform the operation A+c*As*Ad and return the result in A. Take the complex conjugate of As for any column where conjflag = true, and substitute the mode frequency of the column for symfreqvar in every entry through substitutefreq.

The sparse matrix As must have nonzero elements only in a subset of the positions in A which has nonzero lements.

Examples

julia
A = JosephsonCircuits.SparseArrays.sparse([1,2,1], [1,2,2], [1.0+1.0im,2.0+1.0im,-3.0+0.0im],2,2)
Ad = JosephsonCircuits.LinearAlgebra.Diagonal([1,-2])
As = JosephsonCircuits.SparseArrays.sparse([1,1], [1,2], [3.0+2.0im,4.0+3.0im],2,2)
wmodesm = JosephsonCircuits.LinearAlgebra.Diagonal([-1,1])
indexmap = JosephsonCircuits.sparseaddmap(A,As)
JosephsonCircuits.sparseaddconjsubst!(A,2,As,Ad,indexmap,wmodesm .< 0,wmodesm,nothing)
A

# output
2×2 SparseArrays.SparseMatrixCSC{ComplexF64, Int64} with 3 stored entries:
 7.0-3.0im  -19.0-12.0im
        2.0+1.0im
source
JosephsonCircuits.sparseaddmap Method
julia
sparseaddmap(A::SparseMatrixCSC, B::SparseMatrixCSC)

Return a vector of length nnz(B) which maps the indices of elements of B in B.nzval to the corresponding indices in A.nzval. The sparse matrix B must have elements in a subset of the positions in A which have nonzero entries (structural zeros are elements).

Examples

julia
A = JosephsonCircuits.SparseArrays.sparse([1,2,1], [1,2,2], [1,2,-3],2,2)
As = JosephsonCircuits.SparseArrays.sparse([1], [2], [4],2,2)
JosephsonCircuits.sparseaddmap(A,As)

# output
1-element Vector{Int64}:
 2
julia
A = JosephsonCircuits.SparseArrays.sparse([1,2,1], [1,2,2], [1,2,-3],2,2)
As = JosephsonCircuits.SparseArrays.sparse([1,2], [1,2], [4,2],2,2)
JosephsonCircuits.sparseaddmap(A,As)

# output
2-element Vector{Int64}:
 1
 3
source
JosephsonCircuits.sparsefactorbytes Method
julia
sparsefactorbytes(P::SparseMatrixCSC, ::Type{T})

The bytes a sparse LU of the pattern P in precision T would hold, from KLU's symbolic analysis of the pattern (its block triangular form and fill-reducing order) and nothing numeric: the entries of L and U and of the off-diagonal blocks, each with its index. What escalation to a larger coupling set is budgeted against on any backend; a device factorization orders differently, but the fill of the same pattern is of the same size.

source
JosephsonCircuits.spectralclusters Method
julia
spectralclusters(W::AbstractMatrix)

Cluster the modes by coupling strength: starting from every mode alone, merge the two clusters of the strongest coupling not yet inside a cluster, in decreasing strength W[i,j] + W[j,i], until the couplings left between clusters have block Jacobi spectral radius below one. Returns the cluster index of every mode, the radius before and after, and the couplings taken.

The value one is not a threshold to tune: for a nonnegative comparison matrix of block norms, a spectral radius below one is the condition under which the block Jacobi iteration on the omitted couplings contracts, so the rule keeps exactly enough coupling inside the clusters for what is left outside to be correctable. It finds collective chains that no pairwise threshold does: on a two tone line every single coupling of the difference ladder is weak but the ladder as a whole is not, and the rule closes it.

source
JosephsonCircuits.spice_hb_load Method
julia
spice_hb_load(filename)

Load a Xyce harmonic balance simulation.

source
JosephsonCircuits.spice_raw_load Method
julia
spice_raw_load(filename)

Parse the binary raw output file from WRSPICE or Xyce. Tested for transient analysis and frequency domain analysis. The file format is documented in the WRSPICE manual in Appendix 1, File Formats, A.1 Rawfile Format.

The Xyce rawfile format is very similar and described here.

The function outputs a header, the times/frequencies, the currents, and the voltages. The voltage and current arrays have dimensions nVoltages by nPoints and nCurrents by nPoints.

source
JosephsonCircuits.spice_run Method
julia
spice_run(input::AbstractVector,spicecmd; ntasks = Threads.nthreads())

If the input to wrspice_run() is an array of strings, then call multiple processes in parallel. The number of parallel processes is decided from Threads.nthreads(). It can be changed manually.

source
JosephsonCircuits.spice_run Method
julia
spice_run(input, spicecmd::String)

Argument is a string or command containing the input commands for wrspice. This function saves the string to disk, runs spice, parses the results with wrsplice_load(), then returns those parsed results.

The input should not should have a file name listed after the write command in the .control block so that we can specify the raw output file with a command line argument.

source
JosephsonCircuits.spmatmul! Method
julia
spmatmul!(C::SparseMatrixCSC, A::SparseMatrixCSC, B::SparseMatrixCSC,
    xb::Vector{Bool})

Non-allocating sparse matrix multiplication of A and B when sparsity pattern of product C is known. Based on spmatmul from SparseArrays.jl.

Examples

julia
julia> a = JosephsonCircuits.sprand(100,100,0.1);b = JosephsonCircuits.sprand(100,100,0.1);c = a*b; d = copy(c);xb = fill(false, size(a,1));JosephsonCircuits.spmatmul!(c,a,b,xb);c == d
true
source
JosephsonCircuits.sprandsubset Function
julia
sprandsubset(A::SparseMatrixCSC, p::AbstractFloat, dropzeros = true)

Given a sparse matrix A, return a sparse matrix with random values in some fraction of the non-zero elements with probability p. If dropzeros = false, then the zeros will be retained as structural zeros otherwise they are dropped.

This is used for testing non-allocating sparse matrix addition.

Examples

julia
A = JosephsonCircuits.SparseArrays.sprand(2,2,0.5)
B = JosephsonCircuits.sprandsubset(A, 0.1)
length(A.nzval) >= length(B.nzval)

# output
true
julia
A = JosephsonCircuits.SparseArrays.sprand(100,100,0.5)
B = JosephsonCircuits.sprandsubset(A, 0.1)
length(A.nzval) >= length(B.nzval)

# output
true
source
JosephsonCircuits.stagedeviceproviders! Method
julia
stagedeviceproviders!(values, dp::DeviceProviders, w, lo, k)

Compute the scattering values of the batch of frequencies beginning at lo directly on the backend, into values.

The host part of this is the batch's own signal frequencies and, for a block whose data must not be extrapolated, a check of the range it will be evaluated over. Nothing per block or per contribution crosses to the host.

source
JosephsonCircuits.stagedhbnlsolve Method
julia
stagedhbnlsolve(m::Staged, w::NTuple{N,Float64}, Nharmonics,
    sources::Vector{SourceTuple{N}}, psc::CompiledCircuit,
    cg::CircuitGraph, circuitdefs::Dict{Any,Any}; kwargs...)

Source continuation on an adaptively grown harmonic grid, reached through hbnlsolve(...; method = Staged(...)); the schedule is the Staged value m, validated at its construction. kwargs are the keywords of hbnlsolve (iterations, atol, Nevaluationharmonics, frequencywindow, maxintermodorder, dc, odd, even, symfreqvar, keyedarrays, sensitivitynames, returnoperatingpoint, backend), which are forwarded to every stage.

Near a critical drive the Newton basin is small and the iteration count large, so those iterations are spent where they are cheap. The drive is climbed in warm started steps with only a small set of harmonics retained as unknowns, and each larger retained set is warm started from the last by matching mode tuples. The nonlinearity is always evaluated on the full Nevaluationharmonics transform grid, so that every stage sees the same aliasing of the nonlinear products; the ladder only controls the modes retained as unknowns, so it is the linear solves which shrink.

The schedule adapts in both directions, because each truncation has its own solvability boundary and the boundaries are not monotone in the grid: a stalled drive step is halved; a stall at the minimum step grows the grid at the current converged drive; and a carried point which fails to reconverge after growth retreats the drive on the new grid until it converges. Interior points converge only to interioratol under a small iteration budget, since they exist to keep the iterate inside the basin, and the one expensive solve, the finest grid at full drive, starts inside the basin with the caller's atol and iterations.

A point carried to the finest grid which stalls there without ever having converged on that grid is not diagnosed as a fold: the drive is retreated on the finest grid and climbed back. Only a stall from a point converged on the finest grid itself is reported as bracketing a fold, the end of the solution branch (the self oscillation threshold) between the last converged drive fraction and the stalled one; the report is what the search saw, not a proof that no operating point exists at the requested drive. Before reporting it, and only when the stalled target was below full drive, one further solve at full drive is attempted from the last converged point with the caller's own method and tolerance, since a coexisting branch may reach it; failing that, the solve returns not converged with a warning stating the bracket, and solverinfo.sourcefold holds the last converged drive fraction (it stays NaN for the other ways a schedule ends). No path throws: a schedule which cannot reach the point (its attempts spent, a carried point which does not reconverge, a first step which stalls) warns, returns its last attempt marked not converged, and records the whole walk in solverinfo.stages.

Keywords

  • grids = defaultgridladder(Nharmonics): the coarse to fine ladder of retained harmonic caps, whose last entry must equal Nharmonics.

  • s0 = 0.5: the first drive fraction attempted.

  • smin = 0.02: the minimum drive step; a stall below it grows the grid.

  • interioratol = 1e-7, interioriterations = 60: the tolerance and the Newton budget of the interior points. The budget is small on purpose: a stalled probe is evident within tens of iterations, and interior stalls are the overhead of the walk.

  • inner = NewtonKrylov(): the method of every stage.

  • interiorescalation = false: whether interior stage solves may escalate their preconditioner to the full Jacobian. Off by default, because an interior probe exists only to produce a cheap warm start, and at a high tone count the full factorization may not fit in memory; a probe which fails without escalation is a stall, which the schedule answers with a smaller step. The final solve keeps the caller's escalation behavior.

  • maxattempts = 60: a bound on the total number of stage solves.

  • verbose = false: print one line per stage solve.

  • warnnotconverged = true: warn when the schedule ends without the requested point. The stage solves never warn: a stage which does not converge is how the schedule finds its step.

source
JosephsonCircuits.stagescatteringstamps! Method
julia
stagescatteringstamps!(st::DeviceScatteringStamps, w, lo, k, wpumpmodes)

Compute the scattering values of the batch beginning at lo on the host and send them to the backend.

source
JosephsonCircuits.stageweights! Method
julia
stageweights!(rw::RationalWork, sys::TransientSystem, t1, t2)

Set the weights of the output terms of the rational blocks at the two stage times t1 and t2 of the step about to be formed, which the reflected waves at the stages read; the weight of the unconverted response is one and those of the modulated outputs of the pumped blocks their modulation at the time. A circuit without a pumped block has only the first, and its weights never change.

source
JosephsonCircuits.stalled! Method
julia
stalled!(pc::AbstractPreconditioner)

Tell the preconditioner that the last linear solve reduced its residual slowly, by a factor worse than 0.5 per Arnoldi step (the report is off under Never), and return pc. The default does nothing. A ModeCouplingPreconditioner with Clusters takes it as the sign that the coupling has outgrown its clusters and remeasures them at the next update. Called by nlsolvekrylov! after every linear solve; wrappers forward it.

source
JosephsonCircuits.stallmessage Method
julia
stallmessage(reason::Symbol)

The sentence behind a reason of an IterationInfo, for the warning a solve which did not converge issues; a reason it does not know (:converged, :unspecified) is reported as reason <name>.

source
JosephsonCircuits.statednoise Method
julia
statednoise(block)

Whether a block states its noise with a NoiseCovariance, and so carries the channels of both kinds rather than those of its loss.

source
JosephsonCircuits.statednoisefactors! Method
julia
statednoisefactors!(L, M, V, m, n)

The factors of the channels of a block which states its noise: on entry the lower triangle of L holds K = I - S S' at mode m and V[:,:,m] the stated covariance there; on exit L holds the triangular factor of (V + K)/2 and M that of (V - K)/2, both by psdcholesky!, which are positive semidefinite for a covariance checkblocknoisemodels has admitted or which is completed.

source
JosephsonCircuits.structuralkey Method
julia
structuralkey(b::BoundCircuit)

The structural facts a compiled plan depends on, as a comparable value.

A plan may be reused at new component values only while this is unchanged. The facts are the ones which move a component between behaviors rather than along a range: an infinite inductance is an open circuit and drops an edge from the static flux graph, a zero one is a short, a resistor or a junction at zero or infinity is likewise a short or an open, a complex capacitance or inductance is a noise channel where a real one is not, and a unit mutual coupling makes the inverse inductance matrix singular. A value crossing any of these changes the sparsity pattern, the branch set, or the noise classification, so the plan must be rebuilt rather than refilled.

source
JosephsonCircuits.structureassemblerowkernel! Method
julia
structureassemblerowkernel!(nzval, colptr, rowval, lin, phimatrix, ...)

As structureassemblykernel!, one work item per stored row rather than per stored entry.

The two differ in what they amortize against what they lose. Per entry, the row has to be found by a binary search and the row side of the decode is redone for every entry; per row, the binary search is paid once for the whole row (the row side decode is still redone per entry), but the entries a work item writes are contiguous rather than interleaved with its neighbours', which costs coalescing on a device and nothing on a host.

source
JosephsonCircuits.structureassemblykernel! Method
julia
structureassemblykernel!(nzval, colptr, rowval, lin, phimatrix, ...)

Assemble one stored entry of the real Jacobian per work item, from the circuit's structure.

The work item decodes the entry it owns into the node pair and mode pair it belongs to, looks up the junctions incident on that node pair, and sums their contributions: per incident junction the difference frequency coupling ami and its conjugate partner amc, and the linear term last. Floating point addition is not associative, so that order is part of the result.

source
JosephsonCircuits.structurejacobian Method
julia
structurejacobian(d, Amatrixindices, Amatrixconjindices, Ljb, Lscale, Rbnm,
    Nmodes, Nbranches, Nfreq, invLnm, Gnm, Cnm, rl, cl)

The sparsity structure of the real Jacobian restricted to the mode coupling described by Amatrixindices and Amatrixconjindices, together with the StructureRealJacobianPlan which assembles it, taking the linear term matrices from d.sys so that the assembly is the one the solver performs. d is the named tuple returned by hbnlsolve(...; debugJacobian = true). Used only by the tests.

source
JosephsonCircuits.substitute! Method
julia
substitute!(Y, lu::BlockLU, Z, Pw, backend; transposed = false)

The substitutions through the factors: overwrite Y (n x W x nb, in factorization order) with the solution against Z (the right-hand side in factorization order, overwritten), with Pw a panel work array of at least (maxpanel, W, nb). Forward substitution through the scaled panels, back substitution through the panels and the inverses; for the transposed system the same factors read the other way round, (D ⊕ U)ᵀ first as a lower block triangular solve with the transposed inverses, then (I + L)ᵀ backward. The caller gathers into Z and scatters out of Y by perm.

source
JosephsonCircuits.substitutedefs Method
julia
substitutedefs(value, circuitdefs)

Substitute the circuit definitions into a component value for printing.

Mirrors Symbolics.substitute, which is the identity on a value that carries no free parameters. Mapping this to valuetonumber instead is wrong: that resolves a bare Symbol or String against the definitions dictionary and throws for a component name, which is not a value at all.

source
JosephsonCircuits.substitutefreq Method
julia
substitutefreq(value, symfreqvar, w)

Resolve a component value at the mode frequency w: the identity for a plain number, the provider evaluation for a CircuitValue, value.f(w) for a FrequencyDependent, and the substitution of symfreqvar when one is given. The Symbolics extension adds the Num method.

source
JosephsonCircuits.sumbranchvalues! Method
julia
sumbranchvalues!(type::Symbol, node1::Int, node2::Int,componentvalues::Vector,
    countdict, indexdict)

Given a branch and a type, return the sum of all of the values of the same type and branch. The sum will behave differently depending on the type.

Examples

julia
vvn = Real[1, 50.0, 1.0e-13, 2.0e-9, 2.0e-9, 5.0e-13, 5.0e-13, 0.1]
countdict = Dict((:L, 1, 3) => 2, (:R, 1, 2) => 1, (:P, 1, 2) => 1, (:C, 1, 3) => 2, (:C, 2, 3) => 1, (:I, 1, 3) => 1)
indexdict = Dict((:C, 2, 3, 1) => 3, (:C, 1, 3, 1) => 6, (:R, 1, 2, 1) => 2, (:L, 1, 3, 1) => 4, (:C, 1, 3, 2) => 7, (:L, 1, 3, 2) => 5, (:P, 1, 2, 1) => 1, (:I, 1, 3, 1) => 8)
println(JosephsonCircuits.sumbranchvalues!(:C, 1, 3, vvn, countdict, indexdict))

# output
(true, 1.0e-12, 6)
source
JosephsonCircuits.sumvalues Method
julia
sumvalues(type::Symbol, value1, value2)

Sum together two values in different ways depending on the circuit component type.

Examples

julia
julia> JosephsonCircuits.sumvalues(:L, 1.0, 4.0)
0.8

julia> JosephsonCircuits.sumvalues(:Lj, 1.0, 4.0)
0.8

julia> JosephsonCircuits.sumvalues(:C, 1.0, 4.0)
5.0

julia> JosephsonCircuits.sumvalues(:K, 1.0, 4.0)
5.0
source
JosephsonCircuits.supportsrecycling Method
julia
supportsrecycling(ls)

Whether the solver exposes an Arnoldi basis for harvest!.

source
JosephsonCircuits.sweepdestinations Method
julia
sweepdestinations(A::SparseMatrixCSC, Aindex, adjoint::Bool)

The destination of each scattering contribution in the stored order a FrequencySweepPlan uses, given its destinations in the stored order of A.

A plan built for the transpose stores its values in A's own order, so the indices pass through; one built for the matrix itself stores them permuted into compressed sparse row order, so they must be permuted the same way.

source
JosephsonCircuits.sweepfrequencies Method
julia
sweepfrequencies(ws)

The signal frequencies ws as a Vector{Float64}: a real number, or any iterable of real numbers (a vector, a range), in radians per second.

source
JosephsonCircuits.symbolicfill Method
julia
symbolicfill(S::SparseMatrixCSC, perm::AbstractVector{<:Integer})

The number of nonzeros of the Cholesky factor of the symmetric pattern S under the symmetric permutation perm (perm[k] is the original index of the kth pivot), and the flop count of that factorization, both from the elimination tree without forming anything: (fill, flops).

Only the pattern of S is read, and only its structural symmetry matters; for the pattern of an unsymmetric A use that of A + A'. The fill of an LU factorization with the same permutation on both sides is about twice this and its flops about the same, which is enough to rank two orderings. Cost O(fill): the column counts are accumulated by walking the row subtrees of the elimination tree, one step per nonzero of the factor.

source
JosephsonCircuits.symbolicindices Method
julia
symbolicindices(A)

Return the indices in A.nzval where the elements of the matrix A are symbolic variables.

Examples

julia
julia> A = JosephsonCircuits.SparseArrays.sparse([1,2,1], [1,2,2], [1,1.0,2+3im]);JosephsonCircuits.symbolicindices(A)
Int64[]
source
JosephsonCircuits.symbolicmatrices Method
julia
symbolicmatrices(circuit; Nmodes = 1, sorting = defaultsorting(circuit))
symbolicmatrices(psc::CompiledCircuit, cg::CircuitGraph; Nmodes = 1)

The CircuitMatrices of a circuit with its component values left symbolic, so that the capacitance and inverse inductance matrices can be inspected as expressions. The mutually coupled inductor branches are excluded from the inverse inductance matrix and represented by auxiliary branch currents instead (see circuit/mna.jl), so no symbolic linear solve is needed. sorting defaults to :number for a tuple netlist and :name for a typed circuit.

See also CircuitMatrices, numericmatrices, calcCn, calcGn, calcLb,calcLjb, calcMb, calcinvLn, calcLmean, portindicesnumbers, portreferenceimpedances, and noiseindices.

Examples

julia
@variables Ipump Rleft Cc Lj Cj
circuit = Circuit(
    [:p1 => Port(1; Z0 = Rleft),
     :i1 => CurrentSource(Ipump),
     :cc => Capacitor(Cc),
     :jj => JosephsonJunction(Lj),
     :cj => Capacitor(Cj),
     :gnd => Ground()],
    [[(:p1, 1), (:i1, 1), (:cc, 1)],
     [(:cc, 2), (:jj, 1), (:cj, 1)],
     [(:p1, 2), (:i1, 2), (:jj, 2), (:cj, 2), (:gnd, 1)]])
JosephsonCircuits.testshow(stdout,symbolicmatrices(circuit))

# output
JosephsonCircuits.CircuitMatrices(sparse([1, 2, 1, 2], [1, 1, 2, 2], SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymReal}[Cc, -Cc, -Cc, Cc + Cj], 2, 2), sparse([1], [1], SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymReal}[1 / Rleft], 2, 2), sparsevec(Int64[], Float64[], 2), sparsevec(Int64[], Float64[], 2), sparsevec([2], SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymReal}[Lj], 2), sparsevec([2], SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymReal}[Lj], 2), sparse(Int64[], Int64[], Float64[], 2, 2), sparse(Int64[], Int64[], Float64[], 2, 2), sparse([1, 2], [1, 2], [1, 1], 2, 2), [1], [1], [2], Int64[], Lj, Any[1, Rleft, Ipump, Cc, Lj, Cj])
source
JosephsonCircuits.symbolicmatrices Method
julia
symbolicmatrices(psc::CompiledCircuit, cg::CircuitGraph;
Nmodes::Int = 1)

Return the symbolic matrices describing the circuit properties.

See also CircuitMatrices, numericmatrices, calcCn, calcGn, calcLb,calcLjb, calcMb, calcinvLn, calcLmean, portindicesnumbers, portreferenceimpedances, and noiseindices.

Examples

julia
@variables Ipump Rleft Cc Lj Cj
circuit = Circuit(
    [:p1 => Port(1; Z0 = Rleft),
     :i1 => CurrentSource(Ipump),
     :cc => Capacitor(Cc),
     :jj => JosephsonJunction(Lj),
     :cj => Capacitor(Cj),
     :gnd => Ground()],
    [[(:p1, 1), (:i1, 1), (:cc, 1)],
     [(:cc, 2), (:jj, 1), (:cj, 1)],
     [(:p1, 2), (:i1, 2), (:jj, 2), (:cj, 2), (:gnd, 1)]])
psc = JosephsonCircuits.compile(circuit)
cg = JosephsonCircuits.calccircuitgraph(psc)
JosephsonCircuits.testshow(stdout,symbolicmatrices(psc,cg))

# output
JosephsonCircuits.CircuitMatrices(sparse([1, 2, 1, 2], [1, 1, 2, 2], SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymReal}[Cc, -Cc, -Cc, Cc + Cj], 2, 2), sparse([1], [1], SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymReal}[1 / Rleft], 2, 2), sparsevec(Int64[], Float64[], 2), sparsevec(Int64[], Float64[], 2), sparsevec([2], SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymReal}[Lj], 2), sparsevec([2], SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymReal}[Lj], 2), sparse(Int64[], Int64[], Float64[], 2, 2), sparse(Int64[], Int64[], Float64[], 2, 2), sparse([1, 2], [1, 2], [1, 1], 2, 2), [1], [1], [2], Int64[], Lj, Any[1, Rleft, Ipump, Cc, Lj, Cj])
source
JosephsonCircuits.symplectic_form_block Method
julia
symplectic_form_block(n::Integer)

Return the 2n x 2n matrix representing the symplectic form Ω for n modes in the real quadrature operator basis with block order r = [x_1,...,x_n,p_1,...,p_n] where Ω = [0_n 1_n;-1_n 0_n]. 0_n is an n by n matrix of zeros and 1_n is an n by n identity matrix.

Examples

julia
julia> JosephsonCircuits.symplectic_form_block(2)
4×4 SparseArrays.SparseMatrixCSC{Int64, Int64} with 4 stored entries:
  1
  1
 -1
  -1
source
JosephsonCircuits.symplectic_form_pair Method
julia
symplectic_form_pair(n::Integer)

Return the 2n x 2n matrix representing the symplectic form Ω for n modes in the real quadrature operator basis with pair order r = [x_1,p_1,...,x_n,p_n] where Ω = direct sum of n of Ω1 where Ω1 = [0 1; -1 0].

Examples

julia
julia> JosephsonCircuits.symplectic_form_pair(2)
4×4 SparseArrays.SparseMatrixCSC{Int64, Int64} with 4 stored entries:
  1
 -1
  1
  -1
source
JosephsonCircuits.symplectic_normal_form_pair Method
julia
symplectic_normal_form_pair(A::AbstractMatrix{<:Real})

For a real skew-symmetric matrix A return Q such that A = Q Ω Q^T where Q is an invertible matrix and Ω is the pair symplectic form. If A is singular, the decomposition works, but Q is no longer invertible.

I should test this function thoroughly to see if the eigenvalues always come in pairs, especially for singular matrices.

alternatively, we can implement this using skewchol from

SkewLinearAgebra.jl

that method is faster 5x faster for 40x40 matrices, but

from the paper not sure how stable

https://etna.ricam.oeaw.ac.at/vol.11.2000/pp85-93.dir/pp85-93.pdf

using Test, LinearAlgebra

import SkewLinearAlgebra as sk

A = randn(Float64,40,40);

Aa = (A-A')/2

C = sk.skewchol(Aa)

Omega = jc.symplectic_form_pair(size(A,1)÷2)

# undo the pivot and transpose to account for definition differences

# skewchol is defined such that transpose(C.R) * C.J * C.R ≈ A[C.p,C.p]

# I want C.R_C.J_transpose(C.R) = A

R = transpose(C.R[:, invperm(C.p)])

@test isapprox(Aa,R_Omega_R')

source
JosephsonCircuits.symplecticform Method
julia
symplecticform(n::Integer)

Return the 2n by 2n symplectic form Ω = [0 I; -I 0] in the real quadrature ordering (x_1,…,x_n,p_1,…,p_n).

source
JosephsonCircuits.testshow Method
julia
testshow(io::IO,S)

Print S to io in a form which can be pasted back into a test as Julia source. The default show does not always produce such a form (a sparse vector, for example), and a parameterized struct would print its full type parameters, which are implementation details; this prints sparse vectors as sparsevec(...) calls and the solver result structs as their constructor applied to their fields.

Examples

julia
julia> JosephsonCircuits.testshow(stdout,JosephsonCircuits.SparseArrays.sparsevec([1],[2],3))
sparsevec([1], [2], 3)

julia> JosephsonCircuits.testshow(stdout,JosephsonCircuits.SparseArrays.sparsevec([],Nothing[],3))
sparsevec(Int64[], Nothing[], 3)

julia> JosephsonCircuits.testshow(IOBuffer(),JosephsonCircuits.AxisKeys.KeyedArray(rand(Int8, 2,10), ([:a, :b], 10:10:100)))
source
JosephsonCircuits.thermaloccupation Method
julia
thermaloccupation(w, temperature)

The factor 2*nbar + 1 = coth(hbar*abs(w)/(2*k*T)) by which a mode at angular frequency w in thermal equilibrium at temperature in Kelvin exceeds its vacuum noise, and 1 at zero temperature or zero frequency.

This is the whole of the temperature dependence of the noise. A dissipative element adds noise whose covariance is its vacuum covariance times this, which in the Gaussian channel picture scales the Y of the map without touching its X.

Zero frequency returns one rather than diverging: the wave normalization of a noise channel is already zero there (see portwavescale), so the factor multiplies nothing.

Examples

julia
julia> JosephsonCircuits.thermaloccupation(2*pi*5e9, 0.0)
1.0

julia> round(JosephsonCircuits.thermaloccupation(2*pi*5e9, 0.1), digits=5)
1.19962

julia> round(JosephsonCircuits.thermaloccupation(2*pi*5e9, 1.0), digits=4)
8.3746
source
JosephsonCircuits.tobackend Method
julia
tobackend(backend, v::AbstractArray)

Move a host array to the given KernelAbstractions backend.

On a device backend this allocates there and copies. On CPU() the vector is already the type and in the memory the plan wants, so it is adopted as is rather than duplicated: allocate would return an ordinary Vector and the copy would leave the original as garbage, which for a plan of a large circuit is a transient copy of every index map. Only a dense Array is adopted, so any other AbstractArray (a view, a range) is still materialized.

The caller must therefore hand over arrays it does not retain, which every call site does: they are all freshly built.

source
JosephsonCircuits.tohost Method
julia
tohost(x::AbstractArray)

The array on the host, for the host loops which cannot read a device array. Returns x itself when it is already an Array, so nothing about the CPU path changes; anything else is copied back with Array.

source
JosephsonCircuits.tonefrequencies Method
julia
tonefrequencies(w)

The tone frequencies w as a tuple of Float64. Each must be a real number, in radians per second; the solve checks that they are finite.

source
JosephsonCircuits.torelations Method
julia
torelations(r, A::AbstractArray)

The relations r, nothing or a host JunctionRelations, in the array types of A: the coefficients take the working precision of A and move to the backend it lives on, so that the solvers' broadcasts stay on one device and in one precision.

source
JosephsonCircuits.tracestalled Method
julia
tracestalled(tr::NewtonTrace, start::Integer; remaining = nothing)

residualstalled on the recorded history from start, against the tolerance in force and remaining further steps when a budget is given.

source
JosephsonCircuits.tracestart! Method
julia
tracestart!(tr::NewtonTrace, F, atol, rtol)

Begin (or, on a restart, begin again) the record at a point whose residual F holds: the history is emptied, the tolerance fixed at atol or rtol*norm(F), whichever is larger, and convergence decided on the residual before any Jacobian work. Returns whether it has converged.

source
JosephsonCircuits.tracestep! Method
julia
tracestep!(tr::NewtonTrace, F, accepted::Bool)

Record the step taken to a point whose residual F holds: its norm is appended, convergence is decided on it, and the consecutive line searches which returned the best decreasing trial rather than an Armijo accepted step are counted, an accepted step resetting the count so that an isolated failure in an otherwise recovering solve is ignored. Returns :converged, :linesearch when the count reached maxbacktrackfailures, which is a stall recorded as the reason, or :continue.

source
JosephsonCircuits.tracetrial! Function
julia
tracetrial!(tr::NewtonTrace, alpha, backtracks, anderson::Bool = false)

Record the outcome of one line search: the step length it returned (zero when no trial decreased the merit, NaN for an accelerated candidate accepted outright), the trial evaluations after its first, and whether the step lies on the accelerated path. Recorded before it is known whether the step is taken, since a zero step is not.

source
JosephsonCircuits.transientadjoint Method
julia
transientadjoint(solution, weights; quantity = :outgoing, targets = the ports,
    factorization = nothing, reuse = nothing, sink = nothing, stagesink = nothing)

The exact discrete adjoint of sum(weights .* getproperty(solution, quantity)) on the recorded grid, weights having one row per port and one column per recorded time and quantity being :voltage, :incident or :outgoing; a third dimension of weights is a set of objectives propagated together on each step's factorization. Returns (currents, initialflux, initialrate): the derivatives with respect to a Norton current at every target (a port number or a component name, see transientinjection) and recorded time, in Amperes, including the direct feedthrough of a port's current into its wave, and with respect to the scaled initial flux and rate, with the objectives as the trailing dimension. For a consistent perturbation the contraction equals the weighted output of transienttangent; a complex demodulation is two real objectives, and a time integral carries its quadrature weights in weights. With a sink, a function sink(k, values), the currents are not stored: each column, a targets by objectives matrix on the backend valid until the next call, is handed to the sink once it is final, in decreasing recorded time, and currents is nothing; a contraction over a long record then needs no memory per time. With a stagesink as well, a function stagesink(k, i, values), the multipliers of the two stages of each Gauss-Legendre step from k to k + 1 go to it as they are, at their stage times, and the grid columns hold only what the grid reads; that pair is the transpose of the staged form of the tangent's currents, and it is what the noise contracts.

source
JosephsonCircuits.transientadjoint Method
julia
transientadjoint(batch::TransientBatchSolution, weights; quantity, targets, sink)

The adjoint of every condition of a batch for the same weights, all conditions on one pass: the arrays of the single adjoint with the conditions as the trailing dimension, and a sink's columns holding the objectives of a condition contiguously, condition after condition. On the host the conditions are split across the threads of the session when the currents are stored, as the solve splits them; a call with a sink or a stagesink runs on one thread.

source
JosephsonCircuits.transientdemodulate Method
julia
transientdemodulate(solution, port, frequency; quantity = :outgoing,
    window = t -> 1.0)

The complex peak amplitude of the saved trace of port at frequency in Hz: the integral of 2*window(t)*trace(t)*exp(-2pi*im*frequency*t) over the integral of window, by trapezoidal quadrature on the saved samples. quantity is :voltage, :incident or :outgoing. A smooth window suppresses leakage from a strong pump; the saved rate must resolve the carrier. On a device solution the port trace is downloaded once.

source
JosephsonCircuits.transientgain Method
julia
transientgain(solution, measurement, inputs; reuse = nothing)

The quadrature gain from the temporal modes of inputs to those of measurement, both TransientQuantumPlans on windows of the record, for a probe applied inside the input window only: each input mode's two quadratures are the incident waves of unit X and unit P at the input's port, evaluated at the grid and the stage times inside the window and zero outside it, driven through transienttangent and read in the measurement's modes. Returns the (2 nout, 2 nin) matrix, with the conditions as a trailing dimension for a TransientBatchSolution. This is the causal, pulsed gain, carrying the transients of the probe's own edges; the gain of transientnoise with an input plan is the response to the periodic Fourier mode of the window, extended over the record and started stationary, which is what a stationary amplifier's harmonic balance gain is. The two agree as the window grows past the circuit's memory.

source
JosephsonCircuits.transientinjection Method
julia
transientinjection(problem, targets)

The unscaled injection of a unit current at each of targets into the node equations, one sparse column per target: a port number injects into the port's positive terminal, as a port source does, and a component name injects the component's own current, out of its first terminal and into its second, as a named source does, whatever the component is, which is how a bath of a resistor is placed. The default targets of transienttangent and transientadjoint are the ports in compiled order.

source
JosephsonCircuits.transientiq! Method
julia
transientiq!(out, plan, traces)

The complex I/Q measurements of plan on the real port traces traces, a (port, time) matrix on the plan's backend, written into out, a complex (channel, window) matrix: one row per carrier of the plan and one column per complete window, in the peak amplitude convention of transientiqplan. Each channel is one mixing kernel, one forward and one backward FFT on the plan's workspace and one extraction kernel, so no samples by windows array is formed.

source
JosephsonCircuits.transientiq Method
julia
transientiq(plan, traces)

The complex I/Q measurements of plan on the real port traces traces, allocated on the plan's backend; see transientiq!.

source
JosephsonCircuits.transientiqplan Method
julia
transientiqplan(problem, times, frequencies; duration, window = :hann,
    ports = the first port, stride = 1, phasereference = first(times),
    backend = CPU())

Plan causal sliding I/Q measurements of uniformly sampled real port traces with shape (port, time) of problem, a TransientProblem or a solution of it. ports gives the port number each carrier in Hz reads, which the plan resolves to the row of the trace, rows[c]. For normalized window taps h[k], the output is

z[c,n] = 2 sum(h[k] x[rows[c],n-k] exp(-2pi*im*f[c]*(t[n-k]-phasereference))).

Thus a resolved cosine of peak amplitude A and phase phi gives approximately A*exp(im*phi) when the doubled-carrier image is rejected by the window. The units match the input (volts or sqrt(watts)); these are peak, not RMS or photon amplitudes. I is real(z) and Q is imag(z).

window is :hann or :rectangular; duration is rounded to an integer number of sample intervals (at least three). Only complete windows are kept, every stride samples, without assumed prehistory. Use plan.times for causal availability or plan.centertimes for delay-corrected plotting. The reported 3 dB bandwidth is the positive-frequency half-width of the low-pass filter. Neither window is a brick-wall filter: choose sampling, duration and stride to control image leakage and aliasing. The input must already resolve the RF.

CPU uses FFTW and CUDA uses cuFFT with KernelAbstractions kernels. One FFT workspace is reused across channels; this avoids a samples-by-window array.

source
JosephsonCircuits.transientiqvjp! Method
julia
transientiqvjp!(rfweights, plan, iqweights)

Overwrite the real RF gradient of real(dot(iqweights, transientiq(plan,rf))). This is the exact transpose of the finite-window measurement, including normalization, overlap, decimation and multiple channels reading the same port. These RF weights, placed on the port rows of the outgoing waves, are the weights of transientadjoint, which propagates them to the currents and the initial state. The routine does not itself integrate an adjoint.

source
JosephsonCircuits.transientnoise Method
julia
transientnoise(solution, measurement; frequencies = the bins of the
    record, weights = 1/T, cutoff = nothing,
    baths = transientnoisebaths(solution.problem), method = :adjoint,
    inputs = nothing, commutationrtol = 1e-3, reuse = nothing)

The symmetrized quantum noise of a recorded transient, or of every condition of a TransientBatchSolution on one pass, in the temporal modes of measurement, a TransientQuantumPlan on a window of the recorded times: the physical baths, the port terminations and the internal resistors, propagated through the linearization about the complete recorded trajectory, pump and signals together. For a batch the covariance, the commutator and the gain carry the conditions as the trailing dimension and the diagnostics are a vector; on the host the conditions are tiled across the threads of the session, each tile its own responses, as the solve splits them. frequencies are the positive nodes in Hz of a quadrature over the bath spectrum and weights its weights in Hz. By default the bath is periodic over the record, of duration T = length(solution.times)*solution.dt: its positive Fourier bins f = k/T with weights 1/T, up to cutoff in Hz when one is given and to the Nyquist frequency of the record otherwise, which is the complete bath of the recorded steps. Its cost grows with the frequency count: the adjoint method contracts a sum per bath, frequency and time and factorizes the stationary operator once per frequency and distinct initial state, and the forward method drives two directions per bath and frequency, so a long record wants a cutoff, and loss spread along a line a few bands given as frequencies. Each bath at each frequency is a pair of cosine and sine Norton currents of amplitude 2 sqrt(h f df/R), whose independent quadratures have variance nbar + 1/2, started from the stationary response of the circuit to them at the initial state, so that the fluctuations stored before the record and their correlation with the forcing are kept; the trajectory must therefore start at a classical equilibrium under a constant drive, with no inductive flux or junction phase moving, and the measurement window may begin after the drive has settled. With an input plan the bath is the periodic Fourier bath of the measurement window, its tones extended over the whole record and started stationary, and the gain is the response to those periodic modes; a probe applied only inside the window is a different quantity, to be computed by driving that waveform.

method = :forward propagates the bath quadratures forward, two tangent directions per bath and frequency through transienttangent; method = :adjoint propagates the measured quadratures backward through transientadjoint, whose derivatives with respect to the bath currents at every recorded time are the bath kernels, contracted against the frequencies as a discrete Fourier sum at the grid and the stage times the adjoint hands over, so the frequency count costs sums rather than integrations. Both return the same covariance, commutator, expectedcommutator, diagnostics (from transientquantumdiagnostics), and, with an input plan inputs on the same record, the incremental quadrature gain from its modes. A failed diagnostic is returned as such, not rescaled away; refine the bath cutoff, the frequency spacing, the record and the step independently before reading a quantum efficiency with transientquantumefficiency.

source
JosephsonCircuits.transientnoiseaccumulate! Method
julia
transientnoiseaccumulate!(covariance, commutator, response, variances)

Add the contribution of the responses response[:, 2j-1:2j] of the quadrature pairs to the covariance, weighted by the pairs' variances, and to the commutator, which the occupation does not weight.

source
JosephsonCircuits.transientnoisebaths Method
julia
transientnoisebaths(problem; temperature = 0.0)

The independent equilibrium baths of a circuit in time: every matched, port owned termination is one external bath, every finite internal resistor one internal bath, and every lossy scattering block the independent channels of its emitted noise wave, whose covariance is I - S S' (Bosma's relation, as the linearized solver has it), one channel per positive eigenvalue; from the compiler's termination ownership, the bound values, the component temperatures and the blocks' noise models, ThermalEquilibrium(T) stating a block's temperature, Passive() taking the default, Lossless() asserting the block emits nothing, which is checked, and NoiseCovariance(V) stating the noise outright, as an amplifier given by its scattering parameters does: such a block's ports are channels correlated by its group, whose covariance is V and whose commutator is I - S S', so the block adds the noise it states, held to the minimum the commutation relations require, and its output obeys them; a pumped block which states its noise is a group whose channels are correlated across the bath frequencies its harmonics relate (see PairTerm), and one declared lossless is no bath. temperature is the default in kelvin, which a component's own stated temperature overrides. Every port must own a matched finite termination; an open resistor adds no bath. The same temperatures and models set the noise of hblinsolve, so the two solvers compare.

source
JosephsonCircuits.transientproblem Function
julia
transientproblem(circuit, circuitdefs = Dict(); sources = (),
    sorting = defaultsorting(circuit))

Compile a circuit for integration in time: the same compiler and numericmatrices as harmonic balance, at one mode, with the mutually coupled inductors promoted to auxiliary branch currents and the floating inductive subnetworks gauge fixed as hbnlsolve does. sources is a tuple or vector of TransientSources; the netlist's constant CurrentSource components keep their constant values unless a source names them. The circuit may be a typed Circuit, a compiled circuit or a legacy netlist.

Supported are real, constant resistors, capacitors, inductors, mutual inductors, sinusoidal Josephson junctions, current sources and ports. Frequency dependent or complex values are rejected, since they need a causal realization in time. A ScatteringParameters block with a constant real matrix is realized as it is, see TransientBlock; any other block is rejected for the same reason.

source
JosephsonCircuits.transientproblem Method
julia
transientproblem(problem::TransientProblem; sources)

The compiled circuit of problem under other sources, without compiling again: the same matrices and augmentation, new bound drives. The problems of one batch must drive the same targets in the same order, which this gives when sources differ only in their waveforms.

source
JosephsonCircuits.transientquantum! Method
julia
transientquantum!(out, plan, traces)

The photon normalized quadratures (X1, P1, X2, P2, ...) of the temporal modes of plan measured on the real power wave traces traces in sqrt(W), a (port, time) matrix on the plan's backend covering the plan's record, written into the real vector out: one product of the plan's weights with each mode's port trace, so a mode's quadratures are exact linear functionals of the trace. The traces, the weights and the output must share a backend.

source
JosephsonCircuits.transientquantum Method
julia
transientquantum(plan, traces)

The quadratures of the temporal modes of plan measured on traces, allocated on the plan's backend; see transientquantum!.

source
JosephsonCircuits.transientquantumdiagnostics Method
julia
transientquantumdiagnostics(covariance, commutator, expected; rtol=1e-3)

Check commutator closure and the Gaussian uncertainty inequality covariance + im*expected/2 >= 0. Small output matrices are inspected on the host. Passing is necessary, not sufficient: refine RF sampling, bath cutoff, frequency quadrature and solver tolerances independently.

source
JosephsonCircuits.transientquantumefficiency Method
julia
transientquantumefficiency(gain, covariance; rtol=1e-3)

Phase-preserving single-mode metrics for a real 2x2 quadrature gain and an isotropic canonical output covariance (vacuum = I/2). gain is the incremental response to a coherent displacement, not a ratio of large loaded amplitudes. Returns photon gain, input-referred added noise, QE, QEideal and QE/QEideal. Uses the existing HB ideal-efficiency convention. Phase-sensitive gain or anisotropic noise is rejected: retain the full gain/covariance for those cases. The caller must also verify commutator closure and bath-basis convergence.

source
JosephsonCircuits.transientquantumplan Method
julia
transientquantumplan(problem, times, coefficients::AbstractMatrix;
    ports = the first port, backend = CPU())
transientquantumplan(problem, times, frequencies::AbstractVector;
    ports = the first port, envelopes = nothing, backend = CPU())

Define photon-normalized temporal modes on a uniformly sampled half-open record [times[1], times[1]+length(times)*dt). Do not include the repeated right endpoint. For N samples the coefficient rows are Fourier bins k=1:fld(N-1,2) at f=k/(N*dt); DC and a self-conjugate Nyquist bin are excluded. Each coefficient column must have unit Euclidean norm. Different columns may overlap. problem is the TransientProblem whose traces the plan measures, or a solution of it, and ports the port number each mode reads, which the plan resolves to the row of the trace.

The frequency convenience form creates bin-aligned monochromatic modes when envelopes=nothing. Otherwise each column of envelopes[sample,mode] defines g(t)=envelope(t)*exp(-2pi*im*f*(t-times[1])); project it onto positive Fourier bins and normalize the resulting coefficients. Supply enough RF bandwidth to resolve the carrier and envelope. Frequencies must lie strictly below Nyquist.

A canonical bin has real physical power wave w(t)=sqrt(h*f/(N*dt))*(X*cos(2pi*f*t)+P*sin(2pi*f*t)). The readout includes the frequency-dependent 1/sqrt(h*f) weighting before combining bins. A resolved cosine of peak amplitude A in one full-record bin has X=A_sqrt(N_dt/(h*f)), P=0 and mean photon number X^2/2. The P convention is the negative of imag(transientiq(...)) for that cosine's classical phasor. Existing peak-amplitude I/Q conventions remain unchanged.

Windows are finite-record mode definitions, not independent white-noise samples. Use gram, vacuum and commutator when modes/windows overlap. The plan is read-only after construction and has no mutable shared FFT workspace.

source
JosephsonCircuits.transientquantumvjp! Method
julia
transientquantumvjp!(out, plan, weights)

The exact transpose of transientquantum!: the real trace weights, a (port, time) matrix on the plan's backend, of the functional dot(weights, transientquantum(plan, traces)) for the quadrature weights given, written into out. Placed on the port rows of the outgoing waves over the plan's window, these are the weights of transientadjoint, which propagates a measured quadrature back to the currents and the initial state; the noise builds its objectives this way.

source
JosephsonCircuits.transientsensitivity Method
julia
transientsensitivity(solution, names; factorization = nothing,
    reuse = nothing, outputsink = nothing)

The derivative of the port responses of a recorded transient, or of every condition of a TransientBatchSolution on one pass, with respect to a relative perturbation r of the value of each component names names (p -> r*p at r = 1), as Ssensitivity of hblinsolve is of the scattering parameters. Returns (voltage, incident, outgoing, finalflux, finalrate) as transienttangent does, with the components as the trailing dimension, before the conditions of a batch. The components supported are those of the linearized solve, C, L, R and Lj with numeric values and no mutual coupling. The equations of a step are differentiated as they were taken, so the derivative is exact for the recorded steps; a capacitor, inductor or resistor reads the recorded states, record = :states, or record = :checkpoints under GaussLegendre, which replays them, while a junction reads the phases every record holds. The adjoint counterpart is the components keyword of transientadjoint, whose sensitivity is the derivative of its objective with respect to the same perturbations.

source
JosephsonCircuits.transientsolve Method
julia
transientsolve(problems::AbstractVector{TransientProblem}, tspan; dt,
    method = GaussLegendre(), backend = CPU(), factorization = nothing,
    reuse = nothing, initialstate = transientstate of each, saveevery = 1,
    record = :ports, checkpointevery = 0, rtol = 1e-9, atol = 1e-10,
    iterations = 15, maxsteps = 10^7)

The same circuit under every drive condition of problems, built by transientproblem(problem; sources) so that they share one compiled circuit and drive the same targets, stepped as one system under GaussLegendre: the states are matrices with the conditions as columns, every product takes all conditions in one call, the junction stiffness and the factorization are one per condition, KLU on the CPU and the uniform cuDSS batch on a device, and the Newton engine accepts and refreshes per condition. On a device this is where the throughput lies, since the launches of a step serve every condition. initialstate is one TransientState for all conditions or a vector of them. Returns a TransientBatchSolution, whose solution[j] is the ordinary solution of condition j.

On the host the conditions are also split across the threads of the session and their chunks stepped at once, since the conditions of a batch are independent of one another. The whole step parallelizes that way, not only the assembly, the factorization and the solve, and the chunks fill the arrays of the batch in place, so the split costs no copy and changes no result: any layout of chunks gives the same bits. Start Julia with -t to use it. A device keeps the one chunk its uniform batch already is.

source
JosephsonCircuits.transientsolve Method
julia
transientsolve(problem, tspan; dt, method = GaussLegendre(), backend = CPU(),
    factorization = nothing, linearsolver = nothing,
    initialstate = transientstate(problem), saveevery = 1,
    record = :ports, checkpointevery = 0, rtol = 1e-9, atol = 1e-10,
    iterations = 15, maxsteps = 10^7)

Integrate the circuit in physical time on a uniform grid of step at most dt, shortened slightly to land on tspan[2]. method is the stepping rule, GaussLegendre by default, fourth order, or Trapezoidal, second order at the same step and the rule which takes a linearsolver, or BackwardEuler, or WRspice to run the same problem through the WRSPICE simulator and read its output back as the same solution; backend is where the solve runs, and factorization the sparse factorization, KLU on the CPU and cuDSS on a CUDA device by default. The Jacobian's pattern is fixed and its symbolic analysis done once; a linear circuit factorizes once. atol and rtol control the Newton residual of a step, not the temporal error, the absolute tolerance and one relative to the step's right hand side, and iterations bounds the corrections of a step, the names hbnlsolve uses, where rtol is relative to the initial residual instead; a Newton step that fails throws.

With linearsolver = GMRES() (or another of the package's Krylov solvers) under Trapezoidal or BackwardEuler each Newton correction is solved iteratively and matrix free, with the last factorization of the step matrix as the preconditioner: the factorization is then refreshed only when the iteration count says it has drifted, rather than at every step the junction phases move. The Krylov workspace and the preconditioner persist for the whole solve.

By default only the port outputs and the first and last states are kept, which is what the port responses need; saveevery decimates the saved samples without changing the grid and keeps both endpoints. record = :phases with saveevery = 1 records the junction phases at every step, the least transienttangent, transientadjoint and the noise need, record = :states the whole flux and rate history as well, and record = :checkpoints, under GaussLegendre, only the state every checkpointevery steps (the square root of the step count by default), from which the responses replay the steps between at the cost of one more solve, so the memory of a record of any length is bounded. initialstate is the TransientState of transientstate, from physical values or from the end of another solution; the solver checks that it satisfies the algebraic equations of the circuit at the start.

source
JosephsonCircuits.transientstate Method
julia
transientstate(problem; flux = zeros(...), voltage = zeros(...),
    linecurrents = zeros(...))
transientstate(solution)

The initial state of a transient, a TransientState, from the node fluxes in Weber and the node voltages in Volts, in the compiled node order without ground: the scaled fluxes flux/phi0, augmented with the auxiliary currents the coupled inductors' constitutive equations imply and normalized into the gauge of the floating subnetworks, and the scaled flux rates voltage/phi0 with the auxiliary rates the same equations imply. The default is the zero state. transientsolve checks that a state satisfies the algebraic equations of the circuit at the start; it does not project one that does not. With transmission lines the waves leaving the ports of each line come from the port voltages and linecurrents, the direct current into the first port of each line, zero by default; before the start the lines carry those waves unchanged.

From a solution, the state at its end, to start another solve from: its final fluxes and rates, the recorded waves leaving each line port over the delay window before the end, which is what the lines read after the start, so a continuation is the uninterrupted solve to the solver's tolerance at the same step and to the interpolation of the history at another, and the final states of the rational blocks, which need record = :states. A record without the line waves, checkpoints with the history kept at each of them, cannot be continued from.

source
JosephsonCircuits.transientsystem Method
julia
transientsystem(problem, h, method, backend, factorization)

The TransientSystem of problem at the step h under method on backend, factorizing with factorization.

source
JosephsonCircuits.transienttangent Method
julia
transienttangent(solution, currents; targets = the ports,
    initialstate = nothing, factorization = nothing, reuse = nothing,
    outputsink = nothing)

The tangent of a recorded transient along a perturbation: currents[q, k] is an additional Norton current in Amperes at target q (a port number, or a component name, see transientinjection) at recorded time k, and initialstate an optional pair of perturbations of the scaled flux and rate at the start. A third dimension of currents is a set of directions propagated together, each step's factorization serving them all. Under GaussLegendre a current on the grid is read at the stage times through a cubic Lagrange stencil, through the line between the step's grid values on a record shorter than four points; a current given as currents[q, s, k, direction], with s = 1 its value at recorded time k and s = 2, 3 its values at the two stage times of the step from k to k + 1, is read as it is, so a pulse keeps its support and a tone its exact phase at the stages; the trapezoidal rule reads the grid values of either form. The rate of a current on the grid, which the reading of the rate along an algebraic direction carries, is that of the cubic through four grid values, of the quadratic through three or of the line through two. Returns (voltage, incident, outgoing, finalflux, finalrate) in the units of the solve, on its backend, with the directions as the trailing dimension; with an outputsink, a function outputsink(k, voltage, incident, outgoing) receiving the three port by direction matrices of recorded time k on the backend, valid until the next call, the histories are not stored and those three are nothing, so a measurement of a long record needs no memory per time. The linearization is about the full recorded state, so the loaded junction phases enter every response; both the trajectory and its grid are held fixed.

source
JosephsonCircuits.transienttangent Method
julia
transienttangent(batch::TransientBatchSolution, currents; targets, initialstate)

The tangent of every condition of a batch along the same currents, all conditions on one pass: the arrays of the single tangent with the conditions as the trailing dimension. The initial perturbation is one pair for every condition, or one per condition with the conditions as a trailing dimension of the pair's arrays. On the host the conditions are split across the threads of the session when the outputs are stored, as the solve splits them; an outputsink receives the columns of every condition at each time, so a call with one runs on one thread.

source
JosephsonCircuits.transportcurrent! Method
julia
transportcurrent!(d, t::TransportRows, v)

The direct resistor current G0 P v each node carries, in place, indexed by node with ground dropped. This is the coupling Jpv applied to v, and it is the quantity a hand elimination would subtract from the source.

source
JosephsonCircuits.transportresidual! Method
julia
transportresidual!(Fv, t::TransportRows, v)

The transport row residual Y v - j, in place.

source
JosephsonCircuits.transportrows Method
julia
transportrows(plan::DCConductancePlan, bnm, Nmodes)

Build the TransportRows for a source bnm.

bnm must be the applied source, not one corrected for the resistor current: that current appears here as the coupling term, and taking it from a corrected source would count it twice.

source
JosephsonCircuits.transposedestinations Method
julia
transposedestinations(st::DeviceScatteringStamps, Aindexcsr, backend)

A view of the same scattering stamp values with different destinations, for the transposed (adjoint) system: the contribution of a block does not depend on the direction the system is assembled in, only on where in the stored order of that system each scalar lands. Sharing values is what lets the providers be evaluated once for both directions.

source
JosephsonCircuits.transposepattern Method
julia
transposepattern(p::DeviceSparsePattern, backend)

The transpose of a sparsity structure, on the same backend.

Compressed sparse columns of the transpose are compressed sparse rows of the original, so this is a stable counting sort of the stored entries by their row: segmentbydest! does exactly that, and its stability is what leaves the column indices ascending within each row, because a column major traversal meets them in that order.

source
JosephsonCircuits.transposeplan Method
julia
transposeplan(prob::HBNonlinearProblem)

The NonlinearTermTransposePlan of prob.

source
JosephsonCircuits.treepath Method
julia
treepath(parent, depth, u, v)

The vertices of the unique path from u to v through the tree described by parent and depth (see rootedtree), u first and v last. Returns an empty vector when either vertex is unreachable from the root.

Together with a closure branch from v back to u this path is the fundamental loop of that branch.

Examples

julia
julia> JosephsonCircuits.treepath([0, 1, 2, 1], [0, 1, 2, 1], 3, 4)
4-element Vector{Int64}:
 3
 2
 1
 4
source
JosephsonCircuits.truncfreqs Method
julia
truncfreqs(frequencies::Frequencies; maxharmonics = frequencies.Nharmonics,
    maxintermodorder = Inf, dc = true, odd = true, even = true,
    w = nothing, frequencywindow = (0, Inf))

Return a new Frequencies with the coordinates and modes truncated to those which satisfy the criteria: the zero frequency mode when dc, modes of odd or even total harmonic order when odd or even, modes which are a harmonic of a single tone or whose absolute harmonic indices sum to at most maxintermodorder, and modes whose absolute harmonic index in each tone is at most maxharmonics for that tone.

With the tone frequencies w given and a window other than the default (0, Inf), a mode is also required to lie in the frequencywindow: wmin <= abs(dot(w, mode)) <= wmax, in the units of w. The zero frequency mode is governed by dc alone. This is a truncation by frequency rather than by order: incommensurate tones scatter combination frequencies of high order arbitrarily close to zero, where a floating circuit's linear response is enormous although nothing excites those modes, and near the junction plasma frequency at the other end. Such modes carry no flux at the operating point (measured at 1e-5 of the strongest tone and 1e-9 of the flux energy on a three-tone line) and their nearly singular blocks are what a block diagonal preconditioner, and every preconditioner built from it, inverts badly. The ceiling is the one that changes a solve: on a 64-junction RPM line with three tones on a (6,4,4) grid, the 138 modes above 40 GHz, near the junction plasma frequency and at the edge of the sampled grid where their products alias, hold at most 5e-4 of the strongest tone's flux, and without them the block diagonal preconditioner converges the solve in 32 Arnoldi steps where with them it fails after 9900; the retained modes change by 3e-4 and the tones by 4e-5.

Examples

julia
julia> JosephsonCircuits.truncfreqs(JosephsonCircuits.calcfreqsrdft((3,3));maxintermodorder=2).modes
12-element Vector{Tuple{Int64, Int64}}:
 (0, 0)
 (1, 0)
 (2, 0)
 (3, 0)
 (0, 1)
 (1, 1)
 (0, 2)
 (0, 3)
 (0, -3)
 (0, -2)
 (0, -1)
 (1, -1)

julia> JosephsonCircuits.truncfreqs(JosephsonCircuits.calcfreqsrdft((3,3));dc=false,even=false,maxintermodorder=3).modes
10-element Vector{Tuple{Int64, Int64}}:
 (1, 0)
 (3, 0)
 (0, 1)
 (2, 1)
 (1, 2)
 (0, 3)
 (0, -3)
 (1, -2)
 (0, -1)
 (2, -1)

julia> JosephsonCircuits.truncfreqs(JosephsonCircuits.calcfreqsrdft((3,3));maxintermodorder=2)
JosephsonCircuits.Frequencies{2}((3, 3), (4, 7), (7, 7), CartesianIndex{2}[CartesianIndex(1, 1), CartesianIndex(2, 1), CartesianIndex(3, 1), CartesianIndex(4, 1), CartesianIndex(1, 2), CartesianIndex(2, 2), CartesianIndex(1, 3), CartesianIndex(1, 4), CartesianIndex(1, 5), CartesianIndex(1, 6), CartesianIndex(1, 7), CartesianIndex(2, 7)], [(0, 0), (1, 0), (2, 0), (3, 0), (0, 1), (1, 1), (0, 2), (0, 3), (0, -3), (0, -2), (0, -1), (1, -1)])

julia> JosephsonCircuits.truncfreqs(JosephsonCircuits.calcfreqsrdft((3,3));dc=false,even=false,maxharmonics=(2,2),maxintermodorder=3).modes
7-element Vector{Tuple{Int64, Int64}}:
 (1, 0)
 (0, 1)
 (2, 1)
 (1, 2)
 (1, -2)
 (0, -1)
 (2, -1)
source
JosephsonCircuits.tryfactorize! Method
julia
tryfactorize!(cache::FactorizationCache,
    factorization::AbstractFactorization, A; kwargs...)

Factorize A, a matrix or a BlockJacobian, with the method factorization and store the result in cache. When the cache already holds a factorization and the method supports refactorization, its symbolic analysis is reused; a SingularException during that refactorization falls back to a fresh factorization, since reusing the symbolic analysis occasionally fails numerically where a fresh one succeeds. kwargs are forwarded to factorize (the block size of a BlockFactorization of a sparse matrix).

source
JosephsonCircuits.trysolve! Method
julia
trysolve!(x,factorization,b)

First try to solve a linear system using ldiv! then if it errors, use . The motivation for this function is some factorizations such as qr with sparse matrices don't support ldiv!.

source
JosephsonCircuits.trysolvetranspose! Method
julia
trysolvetranspose!(x,factorization,b)

Solve the transposed linear system transpose(A)*x = b using an existing factorization of A, without refactorizing. The non-conjugating transpose is used, not the adjoint. Sparse LU factorizations support this directly with a pair of triangular solves against the stored factors (klu_tsolve for KLU), so an adjoint solve costs a solve rather than a factorization. As in trysolve!, fall back to \\ for factorizations which do not support ldiv! with a transposed factorization.

Used by hblinsolve to obtain the solutions of the transposed linearized system, which are the adjoint solutions required by the noise, quantum efficiency, and sensitivity calculations.

source
JosephsonCircuits.tuple2edge Method
julia
tuple2edge(tuplevector::Vector{Tuple{Int, Int, Int, Int}})

Convert a vector of (src1, dst1, src2, dst2) tuples to a vector of pairs of Graphs edges.

Examples

julia
julia> JosephsonCircuits.tuple2edge([(1,2,3,4),(5,6,7,8)])
2-element Vector{Tuple{Graphs.SimpleGraphs.SimpleEdge{Int64}, Graphs.SimpleGraphs.SimpleEdge{Int64}}}:
 (Edge 1 => 2, Edge 3 => 4)
 (Edge 5 => 6, Edge 7 => 8)
source
JosephsonCircuits.tuple2edge Method
julia
tuple2edge(tuplevector::Vector{Tuple{Int, Int}})

Convert a vector of (src, dst) tuples to a vector of Graphs edges.

Examples

julia
julia> JosephsonCircuits.tuple2edge([(1,2),(3,4)])
2-element Vector{Graphs.SimpleGraphs.SimpleEdge{Int64}}:
 Edge 1 => 2
 Edge 3 => 4
source
JosephsonCircuits.tuple2edge Method
julia
tuple2edge(tupledict::Dict{Tuple{Int, Int, Int, Int},T})

Convert a dictionary keyed by (src1, dst1, src2, dst2) tuples to one keyed by pairs of Graphs edges, keeping the values.

source
JosephsonCircuits.tuple2edge Method
julia
tuple2edge(tupledict::Dict{Tuple{Int, Int},T})

Convert a dictionary keyed by (src, dst) tuples to one keyed by Graphs edges, keeping the values.

source
JosephsonCircuits.uniformbatchlimit Method
julia
uniformbatchlimit(nrhs::Integer)

The largest uniform batch of systems to hand cuDSS, whatever the number of right hand sides nrhs. Fifteen, for two independent reasons, one of correctness and one of speed.

A wrong answer above fifteen systems with six or more right hand sides

cuDSS 0.7 and 0.8 (through CUDSS.jl 0.8.0) return silently wrong solutions from a uniform batch of sixteen or more systems once each has six or more right hand sides. Every system of the batch comes back wrong, by order one, while cudss_get(solver, "info") reports success and "lu_nnz" is unchanged, so nothing downstream can detect it. A batch of fifteen is correct with twelve right hand sides and a batch of sixteen is wrong by order one.

A step in the cost at sixteen systems, at every right hand side count

cuDSS 0.8 takes about eight times as long per refactorization and solve for a batch of sixteen as for a batch of fifteen, and then the same time for every batch from sixteen to sixty four. On a 600 by 600 sparse system the cost per refactorization and solve was 2.0 ms at fifteen systems and 16.6 ms at sixteen, and the ratio was 8.2, 8.4, 8.4 and 7.8 at one, two, four and eight right hand sides. Because the cost above the step does not grow with the batch, splitting into chunks of fifteen always wins: sixty four systems as five chunks is about 9.5 ms against 16.2 ms as one batch. This is not documented by NVIDIA and does not appear to have been reported.

The cap costs nothing on this path, since the speedup of batching a frequency sweep through cuDSS saturates by about a dozen systems. It applies only to the cuDSS batch: a SparseBlockFactorization sweep sizes its batch by memory instead (blocksystembytes) and profits from batches well past this. The nrhs argument is kept because the first bound depends on it and the second does not, so a cuDSS release which fixes one can be accommodated without changing the callers. Re-check both against newer releases before raising it.

source
JosephsonCircuits.unitaritydeviation Method
julia
unitaritydeviation(S::AbstractMatrix)

The largest absolute entry of I - S S', which is zero for a lossless (unitary) scattering matrix. Unlike passivitymargin this sees gain as well as loss, so it is the quantity a lossless test compares against a tolerance.

source
JosephsonCircuits.unscalesolution! Method
julia
unscalesolution!(X::AbstractArray{<:Any,3}, eq::ColumnEquilibration,
    backend)

Undo on the solutions of a batch the column scaling equilibratecolumns! applied to its matrices.

source
JosephsonCircuits.unwrap! Method
julia
unwrap!(m; kwargs...)

In-place version of unwrap.

source
JosephsonCircuits.unwrap! Method
julia
unwrap!(y, m; dims = nothing, range = 2pi, kwargs...)

Unwrap m storing the result in y, see unwrap. dims must be given for an array of more than one dimension.

source
JosephsonCircuits.unwrap Method
julia
unwrap(m; kwargs...)

Assumes m to be a sequence of values that has been wrapped to be inside the given range (centered around zero), and undoes the wrapping by identifying discontinuities. If a single dimension is passed to dims, then m is assumed to have wrapping discontinuities only along that dimension. If a range of dimensions, as in 1:ndims(m), is passed to dims, then m is assumed to have wrapping discontinuities across all ndims(m) dimensions.

A common usage for unwrapping across a singleton dimension is for a phase measurement over time, such as when comparing successive frames of a short-time Fourier transform, as each frame is wrapped to stay within (-pi, pi].

A common usage for unwrapping across multiple dimensions is for a phase measurement of a scene, such as when retrieving the phase information of an image, as each pixel is wrapped to stay within (-pi, pi].

Arguments

  • m::AbstractArray{T, N}: Array to unwrap.

  • dims=nothing: Dimensions along which to unwrap. If dims is an integer, then unwrap is called on that dimension. If dims=1:ndims(m), then m is unwrapped across all dimensions.

  • range=2pi: Range of wrapped array.

  • circular_dims=(false, ...): When an element of this tuple is true, the unwrapping process will consider the edges along the corresponding axis of the array to be connected.

  • rng=default_rng(): Unwrapping of arrays with dimension > 1 uses a random initialization. A user can pass their own RNG through this argument.

source
JosephsonCircuits.updatepreconditioner! Function
julia
updatepreconditioner!(pc::AbstractPreconditioner, x::AbstractVector)

Rebuild the preconditioner pc at the point x and return pc.

source
JosephsonCircuits.updatepreconditioner! Method
julia
updatepreconditioner!(pc::ModeCouplingPreconditioner, x)

Rebuild the preconditioner at the point x: set the system's point, let a MeasuredBand remeasure its per tone bandwidths there and grow its band when they have widened (never shrinking), let a Clusters request reprobe its couplings at the first point or after stalled! and grow its mask, then assemble and refactorize.

source
JosephsonCircuits.usescycleharvest Method
julia
usescycleharvest(pc::AbstractPreconditioner)

Whether pc wants harvestcycle! at the end of every restart cycle instead of harvest! once the solve is over. false by default, so that a preconditioner which harvests only the final cycle keeps doing exactly that.

source
JosephsonCircuits.valuemaps Method
julia
valuemaps(sys::HBSystem)

The ValueMaps of a system, for rebinding it without rebuilding the plan, or nothing when a conversion has no fixed map.

source
JosephsonCircuits.valuemaps Method
julia
valuemaps(plan::NonlinearTermPlan, Knm, invLnm, Gnm, Cnm, Rbnm, Ljb,
    layout, freqindexmap)

The ValueMaps of a plan, found by probing.

Each conversion is linear and each of its output entries reads one input entry, so tagging the inputs with their own indices and reading the outputs gives the map, and does so for whatever rule the conversion follows. A conversion whose structure under the tags differs from the plan's – one which drops a zero, say – has no fixed map and nothing is returned; the refresh then rebuilds the arrays instead.

source
JosephsonCircuits.valuetonumber Method
julia
valuetonumber(value, circuitdefs)

A number, or any other type not handled by a more specific method, is returned unchanged.

Examples

julia
julia> JosephsonCircuits.valuetonumber(1.0,Dict(:Lj1=>1e-12,:Lj2=>2e-12))
1.0
source
JosephsonCircuits.valuetonumber Method
julia
valuetonumber(value::FrequencyDependent, circuitdefs)

A frequency dependent value has no number to resolve to yet. It is lowered to a Provider leaf, which passes through the definitions unchanged and is evaluated at each mode frequency later by freqsubst.

source
JosephsonCircuits.valuetonumber Method
julia
valuetonumber(value::CircuitValue, circuitdefs)

Substitute the definitions in circuitdefs, which may be keyed by Symbol, by String, or by the parameter objects themselves, into a parameterized component value.

A fully defined value comes back as a plain number, real when its imaginary part is zero. A value which still depends on an undefined parameter comes back as an expression; this is how a value depending on the symbolic frequency variable reaches freqsubst with that variable free.

source
JosephsonCircuits.valuetonumber Method
julia
valuetonumber(value::String,circuitdefs)

A string is a key of circuitdefs; return the value stored under it.

Examples

julia
julia> JosephsonCircuits.valuetonumber("Lj1",Dict("Lj1"=>1e-12,"Lj2"=>2e-12))
1.0e-12
source
JosephsonCircuits.valuetonumber Method
julia
valuetonumber(value::Symbol,circuitdefs)

A symbol is a key of circuitdefs; return the value stored under it.

Examples

julia
julia> JosephsonCircuits.valuetonumber(:Lj1,Dict(:Lj1=>1e-12,:Lj2=>2e-12))
1.0e-12
source
JosephsonCircuits.visualizefreqs Method
julia
visualizefreqs(w::NTuple{N,Any}, freq::Frequencies{N})

Create a vector or array containing the mixing products for visualization purposes.

Examples

julia
w = (1.1,1.2)
freq = JosephsonCircuits.truncfreqs(
    JosephsonCircuits.calcfreqsrdft((3,3)),
        dc=true, odd=true, even=true, maxintermodorder=3,
)
JosephsonCircuits.visualizefreqs(w,freq)

# output
4×7 Matrix{Float64}:
 0.0  1.2  2.4  3.6  -3.6  -2.4  -1.2
 1.1  2.3  3.5  0.0   0.0  -1.3  -0.1
 2.2  3.4  0.0  0.0   0.0   0.0   1.0
 3.3  0.0  0.0  0.0   0.0   0.0   0.0
source
JosephsonCircuits.warnduplicatematchedload Method
julia
warnduplicatematchedload(ports, componentnames, componenttypes,
    componentvalues, nodeindices)

Warn when a matched port has a device resistor of exactly its own reference impedance across the same two nodes.

Such a circuit is legal, and is what a user who wants two loads means, so it is not refused. It is far more often a circuit written in the tuple netlist style, where the resistor across a port was its termination, and now carries two loads instead of one. Only an exact match of the reference impedance is reported, because that is what makes the resistor a likely duplicate rather than a device.

source
JosephsonCircuits.weightedrowpower! Method
julia
weightedrowpower!(out, comp, A::AbstractMatrix, w)

Overwrite out[i] with sum_j weight_j*abs2(A[i,j]), the weight of column j being the sign of the mode frequency w[(j-1) % length(w) + 1] of the column, or one for every column when w is nothing. The rows are accumulated column by column for cache efficiency, with a Kahan-Babuska-Neumaier compensated sum whose corrections live in comp, one per row: the row of a high gain amplifier is a cancellation between large signal and idler terms. Shared by the quantum efficiency and the commutation relations.

source
JosephsonCircuits.williamson_pair Method
julia
williamson_pair(M::AbstractMatrix{<:Real})

For a symmetric positive semi-definite matrix M, return a vector of values d and a real symplectic matrix S such that M = S Diagonal(d) S^T. S is symplectic with respect to the pair ordered symplectic form Ω.

The values d are unique but the matrix S is not.

At some point evaluate whether the method in this reference http://arxiv.org/abs/2108.05364v2 is better than the one we are using. I switch to the Schur decomposition based method from [2] because anything based on eigedecomposition may have problems with degenerate eigenvalues.

References

[1] M. Idel, S. Soto Gaona, and M. M. Wolf, “Perturbation bounds for Williamson’s symplectic normal form,” Linear Algebra and its Applications, vol. 525, pp. 45–58, Jul. 2017, doi: 10.1016/j.laa.2017.03.013. [2] M. Houde, W. McCutcheon, and N. Quesada, “Matrix decompositions in Quantum Optics: Takagi/Autonne, Bloch-Messiah/Euler, Iwasawa, and Williamson,” Can. J. Phys., vol. 102, no. 10, pp. 497–507, Oct. 2024, doi: 10.1139/cjp-2024-0070.

source
JosephsonCircuits.windowindex Method
julia
windowindex(L::CompositeLayout, k)

The canonical position of window entry k: a zero frequency entry of the internal state for k <= L.ndc, an explicit voltage after that.

source
JosephsonCircuits.windowindices Method
julia
windowindices(L::CompositeLayout)

The canonical positions of the whole window, in window order.

source
JosephsonCircuits.with Method
julia
with(k::KrylovSolveInfo; fields...)
with(k::IterationInfo; fields...)

A copy of the record with the named fields replaced: the step outcome filled in after the line search, an escalation marked after the solve, the drive fraction of a stage.

source
JosephsonCircuits.withescalation Method
julia
withescalation(m::AbstractHBNonlinearSolver, flag::Bool)

The method with its escalate set to flag, for the interior stages of Staged; methods without escalation are returned unchanged.

source
JosephsonCircuits.withfactorization Method
julia
withfactorization(s, f)

The preconditioner spec s with its factorization replaced by f where it had none; a deflation applies this to what it wraps. An Automatic is returned unchanged: it carries no factorization, and the member it resolves to takes the backend's default (resolveautomatic).

source
JosephsonCircuits.withfactors Method
julia
withfactors(bp::DeviceBlockNoisePlan)

A copy of the plan with scratch of its own for the covariance factors, sharing everything else, so that several workers can form the noise channels of different signal frequencies at once. The factors are written by blocknoisefactorkernel! and read by blocknoisecontractkernel! at one frequency, so they cannot be shared; the tables which say where each block is can be.

source
JosephsonCircuits.withprecision Method
julia
withprecision(f::AbstractFactorization, T)

The factorization f holding its factors in T: a CUDSSFactorization or a BlockFactorization with its precision replaced, any other unchanged, since it factorizes in the precision of the matrix it is handed. This is how a preconditioner whose factors are held in less precision than its iteration is escalated.

source
JosephsonCircuits.wmatrix Method
julia
wmatrix(ws::AbstractRange{T}, wp::NTuple{N,T},
    modes::AbstractVector{NTuple{N,Int}}) where {T,N}

Return the Nmodes by Nfreqs matrix of frequencies for the signal, idlers, and sidebands given the signal frequencies ws, pump frequency wp, and modes modes.

Examples

julia
julia> JosephsonCircuits.wmatrix(0.1:0.1:1.0,(1.0,),[(1,),(-1,)])
2×10 Matrix{Float64}:
  1.1   1.2   1.3   1.4   1.5   1.6   1.7   1.8   1.9  2.0
 -0.9  -0.8  -0.7  -0.6  -0.5  -0.4  -0.3  -0.2  -0.1  0.0
source
JosephsonCircuits.wrspice_calcS_paramp Method
julia
wrspice_calcS_paramp(out, wswrspice, Nnodes; stepsperperiod = 80,
    Is = 1e-13)

The reflection S11 and transmission S21 of a parametric amplifier at the signal angular frequencies wswrspice, from the WRSPICE outputs out of the simulations generated by wrspice_input_paramp with the same stepsperperiod and Is. The first node is taken as the input port and the last node as the output port; Nnodes is the number of nodes including ground.

Examples

julia
Nnodes = 2
ws = 2*pi*5e9
wp = 2*pi*6e9
stepsperperiod = 80
t = LinRange(0,2*pi/wp,stepsperperiod)
Is = 1e-13
Vpump = zeros(1,length(t))
Vsignalsin = zeros(1,length(t))
Vsignalcos = zeros(1,length(t))
Vpump[1,:] .= sin.(2*pi*wp*t)
Vsignalsin[1,:] .= sin.(2*pi*wp*t)+Is/50*sin.(2*pi*ws*t)
Vsignalcos[1,:] .= sin.(2*pi*wp*t)+Is/50*cos.(2*pi*ws*t)

out = [(values=Dict("S"=>t,"V"=>Vpump),),
        (values=Dict("S"=>t,"V"=>Vsignalsin),),
        (values=Dict("S"=>t,"V"=>Vsignalcos),),
        ];
out[1].values["V"];
out[2].values["V"];
out[3].values["V"];
JosephsonCircuits.wrspice_calcS_paramp(out, 2*pi, Nnodes;
    stepsperperiod = stepsperperiod, Is = Is)

# output
(S11 = ComplexF64[-0.9999710828404902 + 2.7521387922213123e-5im], S21 = ComplexF64[2.8917159509832197e-5 + 2.7521387922213123e-5im])
source
JosephsonCircuits.wrspice_cmd Method
julia
wrspice_cmd()

The command which runs WRSPICE: the executable at WRSPICE's standard installation path if one is installed there, else the one a loaded provider registered, which loading the XicTools_jll package does on the platforms its artifact supports. Throws when neither is available; WRspice and spice_run take an executable directly for one installed elsewhere.

source
JosephsonCircuits.wrspice_input_ac Method
julia
wrspice_input_ac(netlist, nsteps, fstart, fstop, portnodes, portcurrent;
    maxdata = 2e9)
wrspice_input_ac(netlist, freqs, portnodes, portcurrent; maxdata = 2e9)

Generate the WRSPICE input for an AC small signal simulation of the circuit in netlist, driven by an AC current source of amplitude portcurrent across the node pair portnodes, given as one-based node indices with ground as index 1 (the source is written from portnodes[2] to portnodes[1], each decremented to its SPICE node label), over nsteps linearly spaced frequencies from fstart to fstop in Hz. The second form takes the frequencies as a single number, or as a vector or range of which only the first and last entries are used, with length(freqs) - 2 passed as the number of points. maxdata is the WRSPICE limit on the size of the data written, in kilobytes.

Examples

julia
julia> println(JosephsonCircuits.wrspice_input_ac("* SPICE Simulation",100,4e9,5e9,[1,2],1e-6))
* SPICE Simulation
* AC current source with magnitude 1 and phase 0
isrc 1 0 ac 1.0e-6 0.0

* Set up the AC small signal simulation
.ac lin 100 4.0g 5.0g

* The control block
.control

* Maximum size of data to export in kilobytes from 1e3 to 2e9 with
* default 2.56e5. This has to come before the run command
set maxdata=2.0e9

* Run the simulation
run

* Binary files are faster to save and load.
set filetype=binary

* Leave filename empty so we can add that as a command line argument.
* Don't specify any variables so it saves everything.
write

.endc
julia
julia> println(JosephsonCircuits.wrspice_input_ac("* SPICE Simulation",(4:0.01:5)*1e9,[1,2],1e-6))
* SPICE Simulation
* AC current source with magnitude 1 and phase 0
isrc 1 0 ac 1.0e-6 0.0

* Set up the AC small signal simulation
.ac lin 99 4.0g 5.0g

* The control block
.control

* Maximum size of data to export in kilobytes from 1e3 to 2e9 with
* default 2.56e5. This has to come before the run command
set maxdata=2.0e9

* Run the simulation
run

* Binary files are faster to save and load.
set filetype=binary

* Leave filename empty so we can add that as a command line argument.
* Don't specify any variables so it saves everything.
write

.endc
source
JosephsonCircuits.wrspice_input_paramp Method
julia
wrspice_input_paramp(netlist, ws, wp, Ip, sourcenodes, sourcenodep;
    stepsperperiod = 80, Is = 1e-13, tstop = 200e-9, trise = 10e-9,
    dphimax = 0.01, maxdata = 2e9)

Generate the WRSPICE inputs for the time domain simulations of a parametric amplifier: one with the pump alone at angular frequency wp and current Ip, applied between the (src, dst) node pair sourcenodep, and then for each signal angular frequency in ws one with a small sine and one with a small cosine signal of amplitude Is added between the node pair sourcenodes. Returns the vector of input strings, pump first, which spice_run runs and wrspice_calcS_paramp turns into scattering parameters. stepsperperiod time steps per pump period are taken for tstop seconds with a rise time trise (see wrspice_input_transient).

Examples

julia
using JosephsonCircuits
using Plots
circuit = Circuit(
    [:p1 => Port(1; Z0 = :R),
     :cc => Capacitor(:Cc),
     :jj => JosephsonJunction(:Lj),
     :cj => Capacitor(:Cj),
     :gnd => Ground()],
    [Net("1", [(:p1, 1), (:cc, 1)]),
     Net("2", [(:cc, 2), (:jj, 1), (:cj, 1)]),
     Net("0", [(:p1, 2), (:jj, 2), (:cj, 2), (:gnd, 1)])])
circuitdefs = Dict(
    :Lj =>1000.0e-12,
    :Cc => 100.0e-15,
    :Cj => 1000.0e-15,
    :R => 50.0)
ws = 2*pi*(4.5:0.001:5.0)*1e9
wp = (2*pi*4.75001*1e9,)
Ip = 0.00565e-6
sources = [(mode=(1,),port=1,current=Ip)]
Npumpharmonics = (16,)
Nmodulationharmonics = (8,)
@time jpa = hbsolve(ws, wp, sources, Nmodulationharmonics,
    Npumpharmonics, circuit, circuitdefs)
wswrspice=2*pi*(4.5:0.01:5.0)*1e9
n = JosephsonCircuits.exportnetlist(circuit,circuitdefs);
input = JosephsonCircuits.wrspice_input_paramp(n.netlist,wswrspice,wp[1],2*Ip,(1,0),(1,0));
@time output = JosephsonCircuits.spice_run(input,JosephsonCircuits.wrspice_cmd());
S11,S21=JosephsonCircuits.wrspice_calcS_paramp(output,wswrspice,n.Nnodes);
plot(ws/(2*pi*1e9),
    10*log10.(abs2.(jpa.linearized.S((0,),1,(0,),1,:))),
    label="JosephsonCircuits.jl",
    xlabel="Frequency (GHz)",
    ylabel="S11 (dB)")
plot!(wswrspice/(2*pi*1e9),10*log10.(abs2.(S11)),
    label="WRSPICE",
    seriestype=:scatter)
source
JosephsonCircuits.wrspice_input_transient Method
julia
wrspice_input_transient(netlist::String, current, frequency, phase,
    sourcenodes, tstep, tstop, trise; maxdata = 2e9, jjaccel = 1,
    dphimax = 0.01, filetype = "binary")

Generate the WRSPICE input for a transient simulation of the circuit in netlist, driven by one sinusoidal current source per entry of current, frequency, phase and sourcenodes, with the time step and stop time given. The output file name is left out of the write command so it can be given on the command line, and no variables are named so that every node is saved.

Arguments

  • netlist: String containing the circuit netlist, excluding sources.

  • current: Vector of current source amplitudes in Ampere.

  • frequency: Vector of current source frequencies in Hz.

  • phase: Vector of current source phases in radians.

  • sourcenodes: Vector of tuples of nodes (src,dst) at which to place the current source(s).

  • tstep: Time step in seconds.

  • tstop: Time for which to run the simulation in seconds.

  • trise: The simulation ramps up the current source amplitude with a 1-sech(t/trise) envelope which reaches 35 percent of the peak in one trise.

Keywords

  • maxdata = 2e9: Maximum size of data to export in kilobytes from 1e3 to 2e9 with WRspice default 2.56e5. This has to come before the run command.

  • jjaccel = 1: Causes a faster convergence testing and iteration control algorithm to be used, rather than the standard more comprehensive algorithm suitable for all devices.

  • dphimax = 0.01: The maximum allowed phase change per time step. Decreasing dphimax from the default of pi/5 to a smaller value is critical for matching the accuracy of the harmonic balance method simulations. This increases simulation time by pi/5/(dphimax).

  • filetype = "binary" or "ascii": Binary files are faster to save and load.

Examples

julia
julia> println(JosephsonCircuits.wrspice_input_transient("* SPICE Simulation",[1e-6,1e-3],[5e9,6e9],[3.14,6.28],[(1,0),(1,0)],1e-9,100e-9,10e-9))
* SPICE Simulation
* Current source
* 1-hyperbolic secant rise
isrc1 1 0 1.0u*cos(31.41592653589793g*x+3.14)*(1-2/(exp(x/1.0e-8)+exp(-x/1.0e-8)))
isrc2 1 0 1000.0u*cos(37.69911184307752g*x+6.28)*(1-2/(exp(x/1.0e-8)+exp(-x/1.0e-8)))
* Set up the transient simulation
* .tran 5p 10n
.tran 1000.0000000000001p 100.0n uic

* The control block
.control
set maxdata=2.0e9
set jjaccel=1
set dphimax=0.01
run
set filetype=binary
write
.endc
source
JosephsonCircuits.zeroscatteringblock Method
julia
zeroscatteringblock(b::ScatteringParameters)

A block with the same ports, reference impedances and conventions whose scattering matrix is identically zero. Constructed directly rather than through the public constructor: it needs no passivity check.

source
LinearAlgebra.dot Method
julia
dot(y::AbstractVector{<:BlasFloat}, A::DeviceValuedSparseMatrix,
    x::AbstractVector)

y' * A * x, the model slope the line search of nlsolve! needs.

source
LinearAlgebra.ldiv! Method
julia
LinearAlgebra.ldiv!(z, pc::AbstractPreconditioner, r)
LinearAlgebra.ldiv!(pc::AbstractPreconditioner, r)
pc \ r

Apply the inverse of the preconditioner, forwarding to applypreconditioner!.

ldiv! is the de facto interface every external Krylov package consumes: Pl/Pr in LinearSolve.jl and IterativeSolvers.jl, M/N in Krylov.jl, Pl in BifurcationKit's linear solvers. The domain knowledge of this solver lives in the preconditioner, so defining ldiv! is what makes ModeCouplingPreconditioner and FloquetPreconditioner reusable outside the package without an adapter.

source
LinearAlgebra.mul! Method
julia
LinearAlgebra.mul!(z, pc::AbstractPreconditioner, r)

Apply the inverse of the preconditioner, spelled as a multiplication.

The two conventions in the ecosystem disagree. LinearSolve.jl and IterativeSolvers.jl take a preconditioner and divide by it, so they call ldiv!. Krylov.jl takes M and N to be operators which already represent the inverse and multiplies, so it calls mul!. Supporting both is what lets the same preconditioner object be handed to either without an adapter, which is the whole point of shipping it as an object.

source
LinearAlgebra.mul! Method
julia
mul!(w::AbstractVector{<:BlasFloat}, A::DeviceValuedSparseMatrix,
    x::AbstractVector)

w = A*x on the backend A's values live on.

A stores its structure as the transpose, so a compressed column of that structure is a row of A and the product is a row wise contraction with no atomics.

The destination is restricted to the element types a device backend actually stores, which is also what keeps this from being ambiguous with the mul! methods packages define for their own scalar types.

source
JosephsonCircuits.CircuitValues.@params Macro
julia
@params name1 name2 ...

Declare circuit parameters: each name becomes a CircuitValues.Parameter bound to that name, which component values may be written in terms of (Lj/2, 1/(Cc*w)), and which circuitdefs supplies a number for at solve time, keyed by the parameter or by its symbol. Returns the tuple of the parameters. This is the dependency free counterpart of Symbolics' @variables.

source