MC Capabilities — Code Reference
This document walks through the Java classes that implement spectrum assignment via MC capabilities. For the algorithm overview, phases, and examples see Spectrum Assignment Using MC Capabilities.
All classes live under
pce/src/main/java/org/opendaylight/transportpce/pce/.
Package layout
pce/spectrum/
├── slot/
│ ├── McCapability.java ← per-node capability interface
│ ├── InterfaceMcCapability.java ← ROADM degrees and SRGs
│ ├── XpdrMcCapability.java ← XPDR network ports (7.1)
│ ├── UnconstrainedMcCapability.java ← OTN nodes
│ ├── CapabilityCollection.java ← collection interface
│ └── McCapabilityCollection.java ← collection implementation
├── range/
│ ├── FrequencyRange.java ← frequency range interface
│ ├── McCapabilityRange.java ← bounded by min/max-edge-freq
│ └── EntireGridRange.java ← no frequency restriction
├── centerfrequency/
│ ├── Collection.java ← center-freq-granularity interface
│ └── CenterFrequencyGranularityCollection.java ← LCM computation
├── index/
│ ├── Base.java / BaseFrequency.java ← reference frequency → slot index
│ ├── Index.java / SpectrumIndex.java ← first/last valid center slot
│ └── NoIndexFoundException.java
├── assignment/
│ ├── Assign.java / AssignSpectrumHighToLow.java ← slot selection algorithm
│ ├── Range.java / IndexRange.java ← selected slot range
└── observer/
├── Observer.java ← error reporting interface
└── VoidObserver.java ← no-op implementation
frequency/
├── Select.java ← frequency selection interface
└── FrequencySelectionFactory.java ← client-input + node bitmap merge
graph/
└── PostAlgoPathValidator.java ← getSpectrumAssignment entry point
McCapability — per-node capability interface
McCapability (spectrum/slot/McCapability.java) defines the contract that
each node on the path must satisfy:
┌──────────────────────────────────────────────────────┐
│ «interface» │
│ McCapability │
├──────────────────────────────────────────────────────┤
│ + centerFrequencyGranularity() : BigDecimal │
│ + isCompatibleWithServiceFrequency() : boolean │
│ + supportableFrequencyRange() : BitSet │
└───────────────────────────┬──────────────────────────┘
│
┌─────────────────────────┼─────────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────────────┐ ┌──────────────────────┐ ┌───────────────────────────┐
│ InterfaceMcCapability │ │ XpdrMcCapability │ │ UnconstrainedMcCapability │
│ (ROADM degree / SRG) │ │ (XPDR 7.1) │ │ (OTN) │
├───────────────────────┤ ├──────────────────────┤ ├───────────────────────────┤
│ slotWidthGran. │ │ centerFreqGran. │ │ (no constraints; │
│ centerFreqGran. │ │ freqRange │ │ all checks pass) │
│ minSlots / maxSlots │ ├──────────────────────┤ └───────────────────────────┘
│ freqRange │ │ isCompatible() │
├───────────────────────┤ │ → always true │
│ isCompatible() │ └──────────────────────┘
│ (validates width) │
└───────────────────────┘
BigDecimal centerFrequencyGranularity();
boolean isCompatibleWithServiceFrequency(double requiredFrequencyWidthGHz);
boolean isCompatibleWithServiceFrequency(double requiredFrequencyWidthGHz, Observer observer);
BitSet supportableFrequencyRange(double slotWidthGranularityGHz,
double edgeFrequencyTHz,
int effectiveBits);
centerFrequencyGranularity() feeds Phase 5 (LCM computation).
isCompatibleWithServiceFrequency() is the Phase 4 slot-width check.
supportableFrequencyRange() returns the Phase 3 frequency range bitmap.
The Observer parameter lets the collection report a human-readable error
message when a check fails. VoidObserver discards these messages silently;
the real subscriber passed into getSpectrumAssignment is wired in through
McCapabilityCollection.
InterfaceMcCapability — ROADM nodes
Used for ROADM degree and SRG nodes. Fields:
slotWidthGranularity— fromslot-width-granularityin the mc-capability-profile.centerFrequencyGranularity— fromcenter-freq-granularity.minSlots/maxSlots— slot count bounds.supportedFrequencyRange— aFrequencyRange(see below).
The slot-width check (isCompatibleWithServiceFrequency):
// Phase 4 — InterfaceMcCapability.java:96-117
BigDecimal remainder = requiredFrequencyWidthGHz.remainder(slotWidthGranularity);
if (remainder.compareTo(BigDecimal.ZERO) != 0) {
observer.error(...);
return false; // width is not a multiple of granularity
}
BigDecimal quotient = requiredFrequencyWidthGHz.divideToIntegralValue(slotWidthGranularity);
if (quotient >= minSlots && quotient <= maxSlots) {
return true; // nr of steps is within [minSlots, maxSlots]
}
observer.error(...);
return false;
The frequency range bitmap (supportableFrequencyRange) simply delegates:
// InterfaceMcCapability.java:135-141
return supportedFrequencyRange.gridRange(slotWidthGranularityGHz, edgeFrequencyTHz, effectiveBits);
XpdrMcCapability — XPDR nodes
Used for OpenROADM 7.1 XPDR network ports. Only two fields are relevant:
centerFreqGranularitysupportedFrequencyRange(sameFrequencyRangeabstraction)
isCompatibleWithServiceFrequency always returns true:
// XpdrMcCapability.java:72-76
@Override
public boolean isCompatibleWithServiceFrequency(BigDecimal requiredFrequencyWidthGHz, Observer observer) {
return true;
}
The OpenROADM 7.1 White Paper (Section 4.8.3) states that
slot-width-granularity, min-slots, and max-slots from an XPDR
mc-capability-profile describe client-side electrical constraints, not optical
line-side spectrum constraints. The XPDR implementation therefore skips the
slot-width check entirely.
UnconstrainedMcCapability — OTN nodes
A null-object implementation. Both isCompatibleWithServiceFrequency and
supportableFrequencyRange return unconstrained results (true /
all-ones BitSet). centerFrequencyGranularity() returns null, which
CenterFrequencyGranularityCollection.add silently ignores.
FrequencyRange — frequency range interface
FrequencyRange (spectrum/range/FrequencyRange.java) has one method:
BitSet gridRange(double slotWidthGranularityGHz, double edgeFrequencyTHz, int effectiveBits);
It maps a frequency range onto the slot grid, returning a BitSet where each set bit marks an available slot.
McCapabilityRange — bounded range
Constructed from an explicit [minFrequency, maxFrequency] interval. The
mapping to slot indices:
// McCapabilityRange.java:gridRange()
BigDecimal slotWidthTHz = slotWidthGranularityGHz * 0.001;
BigDecimal gridMin = edgeFrequencyTHz;
BigDecimal gridMax = gridMin + effectiveBits * slotWidthTHz;
BigDecimal minDiff = max(minFrequency, gridMin) - gridMin;
BigDecimal maxDiff = min(maxFrequency, gridMax) - gridMin;
int minIndex = ceil(minDiff / slotWidthTHz); // RoundingMode.UP
int maxIndex = floor(maxDiff / slotWidthTHz); // RoundingMode.DOWN
bitSet.set(minIndex, maxIndex); // [minIndex, maxIndex)
The range is clamped to the actual grid boundaries by the max / min
calls. Rounding up the lower edge and down the upper edge ensures that a slot
is only included when it falls fully within the supported band.
The static factory McCapabilityRange.from() handles absent attributes:
minFrequencyTHz == null && maxFrequencyTHz == null → EntireGridRange
minFrequencyTHz == null → use edgeFrequencyTHz as lower bound
maxFrequencyTHz == null → use (edgeFrequencyTHz + grid width) as upper bound
EntireGridRange — no restriction
Sets all effectiveBits bits. Used when a node advertises no
min/max-edge-freq or belongs to a node type (OTN) that carries no
frequency constraint.
McCapabilityCollection — aggregate Phase 3 and 4
McCapabilityCollection holds one McCapability per path node and
implements CapabilityCollection:
Phase 4 — slot-width compatibility check:
// McCapabilityCollection.java:isCompatibleService()
BigDecimal widthGHz = slotWidthGranularityGHz * slotCount;
for (McCapability cap : slots) {
if (!cap.isCompatibleWithServiceFrequency(widthGHz, observer)) {
return false;
}
}
return true;
A single failing node short-circuits the loop.
Phase 3 — usable frequency range:
// McCapabilityCollection.java:usableFrequencyRange()
BitSet result = availableFrequencyGrid.clone();
for (McCapability cap : slots) {
result.and(cap.supportableFrequencyRange(slotWidthGranularityGHz,
edgeFrequencyTHz, effectiveBits));
}
return result;
The running AND accumulates each node’s range until only slots supported by every node on the path remain.
CenterFrequencyGranularityCollection — Phase 5
Stores all center-freq-granularity values seen on the path (in Hz
internally for integer arithmetic) and computes their LCM.
The key output for Phase 5 is slots(). The two examples below correspond
to the diagrams in Spectrum Assignment Using MC Capabilities.
CFG = 25 GHz — effective step = LCM(6.25, 25) = 25 GHz = 4 slots:
Collection centerFrequencyGranularityCollection = new CenterFrequencyGranularityCollection(50);
centerFrequencyGranularityCollection.add(6.25);
centerFrequencyGranularityCollection.add(6.25); // duplicate values are ignored
centerFrequencyGranularityCollection.add(25);
// Distance between center frequencies, i.e. the nr of 6.25 GHz slots: 4
int centerFrequencyGranularity = centerFrequencyGranularityCollection.slots(
GridConstant.GRANULARITY);
CFG = 75 GHz — effective step = LCM(25, 75) = 75 GHz = 12 slots:
Collection centerFrequencyGranularityCollection = new CenterFrequencyGranularityCollection(50);
centerFrequencyGranularityCollection.add(25);
centerFrequencyGranularityCollection.add(75);
// Distance between center frequencies, i.e. the nr of 6.25 GHz slots: 12 (6.25 × 12 = 75 GHz)
int centerFrequencyGranularity = centerFrequencyGranularityCollection.slots(
GridConstant.GRANULARITY);
193.1 THz reference frequency
The reference frequency is primarily needed to find the highest possible center frequency (S). Finding the location of the reference frequency on the spectrum grid:
// ▼ - The location of the 193.1 THz reference frequency
Base baseFrequency = new BaseFrequency();
int baseFrequencyIndex = baseFrequency.referenceFrequencySpectrumIndex(
GridConstant.CENTRAL_FREQUENCY_THZ,
GridConstant.START_EDGE_FREQUENCY_THZ,
GridConstant.GRANULARITY
);
The iteration starting point (S)
In the example below, the service requires 87.5 GHz of bandwidth, which means the iteration must start below the highest valid center frequency granularity to leave room for the half-width on each side. The location of S depends primarily on the center frequency granularity combined with required service bandwidth.
L : spectrum grid lower edge frequency
U : spectrum grid upper edge frequency
▼ : the 193.1 THz reference frequency
|.| : an occupied 6.25 GHz spectrum slot
`-´ : possible 87.5 GHz wide service slot
S : iteration start point
↓ : 25 GHz center frequency granularity
CFG L S U
25 GHz | ↓ ↓ ↓ ↓ ▼ ↓ ↓ ↓ ↓ |
|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|
`---------------------------´
Finding the iteration starting point is dependent on…
The 193.1 THz reference frequency (i.e. denoted as ▼ above)
Center frequency granularity (i.e. the distance between ▼ and ↓ above)
Service frequency width (i.e. nr of slots encapsulated by
`---------------------------´)The total nr of bits on the frequency grid (e.g. 768)
Finding S can be expressed in code like this:
// ▼ - The location of the 193.1 THz reference frequency
Base baseFrequency = new BaseFrequency();
int baseFrequencyIndex = baseFrequency.referenceFrequencySpectrumIndex(
GridConstant.CENTRAL_FREQUENCY_THZ,
GridConstant.START_EDGE_FREQUENCY_THZ,
GridConstant.GRANULARITY
);
// S - The iteration start point, i.e. the last usable index (highest value)
// of the center frequency granularity on the frequency grid
SpectrumIndex spectrumIndex = new SpectrumIndex();
int lastCenterFrequencyIndex = spectrumIndex.lastCenterFrequencyIndex(
centerFrequencyGranularity, //e.g. 25 GHz
baseFrequencyIndex, //See '193.1 THz reference frequency'
serviceSlotWidth, //e.g. 14 (for a 87.5 GHz wide service slot)
effectiveBits //e.g. 768 (the nr of effective bits on the grid)
);
AssignSpectrumHighToLow — slot selection
Implements the high-to-low center-frequency scan:
// AssignSpectrumHighToLow.java:range()
int lastCenter = slotIndex.lastCenterFrequencyIndex(
centerFrequencyGranularity, baseFrequencyIndex, serviceSlotWidth, effectiveBits);
BitSet reference = new BitSet(serviceSlotWidth);
reference.set(0, serviceSlotWidth); // all-ones reference window
int half = serviceSlotWidth / 2;
for (int center = lastCenter; center >= half; center -= centerFrequencyGranularity) {
int lo = center - half;
int hi = center + half;
if (spectrumOccupation.get(lo, hi).equals(reference)) {
return new IndexRange(lo, hi - 1); // found: [lo, hi) → [lo, hi-1] inclusive
}
}
return new IndexRange(0, 0); // not found
SpectrumIndex.lastCenterFrequencyIndex() finds the highest slot index that:
is aligned to a multiple of
centerFrequencyGranularityrelative tobaseFrequencyIndex(193.1 THz, slot 284), andleaves room for the half-width on each side (i.e.
effectiveBits - center ≥ half).
SpectrumIndex.firstCenterFrequencyIndex() mirrors this for the low end.
FrequencySelectionFactory — client-input overlay
Before spectrum assignment the method applies client-driven restrictions via
FrequencySelectionFactory.availableFrequencies():
// FrequencySelectionFactory.java
BitSet available = availableFrequenciesOnNodes.clone();
if (availableCustomerRange != null) {
available.and(availableCustomerRange); // customer restriction
}
BitSet rangeResult = intersectionLimitation.intersection(available); // client range wish
return subsetLimitation.subset(rangeResult); // client specific assignment
clientInput.clientRangeWishListIntersection() represents an optional
frequency range the API caller wants to restrict assignment to (intersection).
clientInput.clientRangeWishListSubset() represents an optional specific
assignment the caller wants (e.g., a requested center frequency / slot count
pair — a hard requirement that must be a subset of the available range).
spectrumConstraint is an optional per-customer allowed range.
In the absence of such constraints both collections act as no-ops and the result equals the MC-filtered bitmap.
getSpectrumAssignment — annotated call sequence
Putting it all together, here is the method body with each step mapped to its phase:
// PostAlgoPathValidator.java:1082-1181 (simplified)
public SpectrumAssignment getSpectrumAssignment(...) {
// Phase 1 — collect unique PceNodes from every edge in the path
Set<PceNode> pceNodes = new LinkedHashSet<>();
for (PceGraphEdge edge : path.getEdgeList()) {
pceNodes.add(allPceNodes.get(edge.link().getSourceId()));
pceNodes.add(allPceNodes.get(edge.link().getDestId()));
}
Collection cfgCollection = new CenterFrequencyGranularityCollection(50);
CapabilityCollection mcCollection = new McCapabilityCollection(errorObserver);
for (PceNode node : pceNodes) {
// Phase 2 — AND each non-contentionless node's frequency bitmap
if (!node.isContentionLessSrg()) {
result.and(node.getBitSetData());
}
McCapability cap = node.mcCapabilities();
cfgCollection.add(cap.centerFrequencyGranularity()); // feeds Phase 5
mcCollection.add(cap); // feeds Phase 3 + 4
}
if (result.isEmpty()) return createEmptySpectrumAssignment(); // Phase 2 early exit
// Phase 3 — AND each node's supported frequency range (min/max-edge-freq)
result = mcCollection.usableFrequencyRange(result, GRANULARITY,
START_EDGE_FREQUENCY_THZ, EFFECTIVE_BITS);
if (result.isEmpty()) return createEmptySpectrumAssignment();
// Phase 4 — reject if any node's slot-width constraints reject the service
int slotCount = clientInput.slotWidth(spectralWidthSlotNumber);
if (!mcCollection.isCompatibleService(GRANULARITY, slotCount)) {
return createEmptySpectrumAssignment();
}
// Apply client-input and customer-range overlays
BitSet assignable = new FrequencySelectionFactory()
.availableFrequencies(clientInput, spectrumConstraint, result);
if (assignable.isEmpty()) return createEmptySpectrumAssignment();
// Phase 5 — find the highest valid center-frequency-aligned slot window
return computeBestSpectrumAssignment(
assignable,
slotCount,
cfgCollection.slots(GRANULARITY), // LCM step in slots
isFlexGrid,
subscriber);
}
// computeBestSpectrumAssignment wires BaseFrequency + AssignSpectrumHighToLow
public SpectrumAssignment computeBestSpectrumAssignment(
BitSet spectrumOccupation, int slotWidth,
int centerFrequencyGranularitySlots, boolean isFlexGrid, ...) {
int baseIndex = new BaseFrequency().referenceFrequencySpectrumIndex(
CENTRAL_FREQUENCY_THZ, // 193.1 THz
START_EDGE_FREQUENCY_THZ, // 191.325 THz
GRANULARITY); // 6.25 GHz → baseIndex = 284
Range range = new AssignSpectrumHighToLow(new SpectrumIndex()).range(
EFFECTIVE_BITS, // 768
baseIndex, // 284 (= 193.1 THz on the grid)
spectrumOccupation,
centerFrequencyGranularitySlots,
slotWidth);
return new SpectrumAssignmentBuilder()
.setBeginIndex(range.lower())
.setStopIndex(range.upper())
.setFlexGrid(isFlexGrid)
.build();
}
Grid constants (GridConstant)
The constants referenced throughout:
Constant |
Value |
Meaning |
|---|---|---|
|
768 |
Number of 6.25 GHz slots in the C-band grid |
|
6.25 GHz |
Slot width |
|
191.325 THz |
Lowest slot left edge (slot 0) |
|
193.1 THz |
ITU-T G.694.1 reference frequency (baseIndex = 284) |
|
96 |
Bytes in the 768-bit frequency map (768 / 8) |
|
0xFF |
All bits set = all slots available |