Connector Ports

Public API

MethodOfLines.Interpolate — Type
Interpolate(order = 1)

Couple a PointPort to the field by Lagrange interpolation of degree order in every spatial direction: order + 1 nodes per direction, grown outward from the two nodes that bracket the port, so it never extrapolates. A port that lies exactly on a node uses that node alone. The default linear interpolation has non-negative weights; order >= 2 is more accurate on smooth fields but has negative weights, so a positive flow also removes a little of the quantity at some nodes (a non-monotone source).

source
MethodOfLines.PointPort — Method
PointPort(connector; name, var, at, across, through = nothing,
          select = Interpolate(), kwargs...)

Declare an MTK connector port on the dependent variable var of a PDESystem, at the spatial point at, to be placed in the systems of that PDESystem.

connector(; name, kwargs...) must return a connector (a System built with @connector). at gives one x => value pair for every spatial argument of var. After discretization the connector's unknown across equals the selected field value Σ w_I u_I. If through = :Q => scale names a Flow unknown of the connector, the port adds scale * Q * w_I / V_I (V_I the control volume of node I) to the time derivative of var at each selected node, as if the PDE were solved for Dt(var), however it is written: ρ * c * Dt(T) ~ k * Dxx(T) and Dt(T) ~ k / (ρ * c) * Dxx(T) take the same scale. The PDE must contain Dt(var) linearly, with a constant or parameter coefficient. Q is positive into the PDE, the MTK convention for a component's own port; scale converts the flow into a rate of var, e.g. 1 / (ρ * c * A) for a temperature rod of cross-section A. Without through the port only reads the field.

select is Interpolate or Nearest. A port carrying a flow selects among interior nodes only, since boundary nodes hold boundary conditions; flow into a boundary belongs in a flux boundary condition instead.

Compose the discretized system rather than calling discretize:

@named heater = PointPort(HeatPort; var = T(t, x), at = [x => 0.3], across = :T,
                          through = :Q_flow => 1 / (ρ * c * A))
@named rod = PDESystem(eqs, bcs, domains, [t, x], [T(t, x)], ps; systems = [heater])
sys, tspan = symbolic_discretize(rod, MOLFiniteDifference([x => 0.01], t))
@named model = System([connect(sys.heater, cap.port)], t; systems = [sys, cap])
prob = ODEProblem(mtkcompile(model), nothing, tspan)

A read-out port also works on sys compiled on its own, where its flow is zero.

source

Developer API

MethodOfLines.add_point_ports — Method

Add the port sources and across equations that belong to pde, whose interior equations are eqs. A port's flow is added to Dt(u) of its variable u. Several PDEs may contain Dt(u), so each gets the source scaled by its own coefficient of Dt(u); the residuals then shift by A * e_u * src, with A the matrix of time-derivative coefficients, and the solved system gains exactly src in Dt(u). Every PDE uses the nodes selected in the interior of the PDE assigned to u. The across equation goes with that PDE.

source
MethodOfLines.select_port_nodes — Method
select_port_nodes(spec, s; restrict_to = nothing, periodic = nothing, upper_open = nothing)

Nodes, weights and control volumes of the port spec on the grid of s, as vectors (nodes::Vector{CartesianIndex}, weights, volumes) in the index space of the port variable. restrict_to gives, per spatial direction, the index range the nodes may come from; by default every grid node is allowed. periodic and upper_open flag, per direction, a periodic axis and an axis joined to another domain at its upper end.

source