Skip to content

HigherOrderInterfaceBoundary missing from offset/boundary dispatch interface #67

@xtalax

Description

@xtalax

Summary

HigherOrderInterfaceBoundary is exported by PDEBase and is part of the boundary type hierarchy, but it sits in a branch (AbstractInterfaceBoundary) that is sibling to AbstractLowerBoundary/AbstractUpperBoundary — not a subtype of either. Downstream packages (e.g. MethodOfLines.jl) that implement boundary-related functions dispatching on AbstractLowerBoundary/AbstractUpperBoundary silently miss HigherOrderInterfaceBoundary, causing MethodError at runtime.

Type hierarchy

AbstractBoundary
└─ AbstractTruncatingBoundary
   ├─ AbstractInterfaceBoundary        ← HigherOrderInterfaceBoundary lives here
   │  ├─ InterfaceBoundary{IsUpper_u, IsUpper_u2}
   │  └─ HigherOrderInterfaceBoundary  ← NOT <: AbstractLowerBoundary or AbstractUpperBoundary
   ├─ AbstractLowerBoundary            ← offset(::AbstractLowerBoundary, i, len) = i
   │  └─ LowerBoundary
   └─ AbstractUpperBoundary            ← offset(::AbstractUpperBoundary, i, len) = len - i + 1
      └─ UpperBoundary

MWE

using PDEBase

# HigherOrderInterfaceBoundary is constructed during BC parsing
# when a PDE system has interface boundaries with derivative BCs.
# 
# In MethodOfLines.jl, `offset` is defined for AbstractLowerBoundary and
# AbstractUpperBoundary but NOT for HigherOrderInterfaceBoundary:
#
#   offset(::AbstractLowerBoundary, i, len) = i
#   offset(::AbstractUpperBoundary, i, len) = len - i + 1
#
# When generate_array_bc_eqs.jl:144 calls offset(boundary, ...) on a
# HigherOrderInterfaceBoundary, it hits MethodError.

# PDEBase already defines:
PDEBase.isupper(::PDEBase.HigherOrderInterfaceBoundary)  # returns true

# But there's no guidance or default implementation for offset()
# Downstream packages don't know they need to handle this type separately

Error (from MethodOfLines.jl MOL_Interface2 test):

MethodError: no method matching offset(::HigherOrderInterfaceBoundary, ::Int64, ::Int64)

Suggested fix

Since isupper(::HigherOrderInterfaceBoundary) = true is already defined in PDEBase (line 122 of parse_boundaries.jl), one of these approaches would help:

Option A: Add offset to PDEBase interface

Define offset in PDEBase with default implementations based on the existing isupper dispatch:

offset(::AbstractLowerBoundary, i, len) = i
offset(::AbstractUpperBoundary, i, len) = len - i + 1
offset(b::AbstractInterfaceBoundary, i, len) = isupper(b) ? len - i + 1 : i

This would cover HigherOrderInterfaceBoundary automatically and prevent future dispatch gaps for any new AbstractInterfaceBoundary subtypes.

Option B: Document the interface contract

If offset is intentionally left to downstream packages, document which functions must be implemented for each boundary subtype. Currently HigherOrderInterfaceBoundary has isupper, idx, and ordering but no offset, and this isn't documented anywhere.

Impact

Blocks 1 test in MethodOfLines.jl (MOL_Interface2 — "Nonlinlap with flux interface boundary condition"). The workaround is adding offset(::HigherOrderInterfaceBoundary, i, len) = len - i + 1 in MOL, but this is fragile — any new boundary type added to PDEBase could have the same gap.

Environment

  • PDEBase v0.3.x
  • MethodOfLines.jl stencils branch (commit a5519fbe)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions