DNA //evolutions

Nodes

The work to be scheduled

A Node represents a task, a location, or an appointment that needs to be visited or performed by a Resource. Nodes are the primary demand objects in JOpt.TourOptimizer. The optimizer assigns nodes to resources and sequences them into routes, respecting time windows, capacity, and all other constraints.

JOpt provides several node types, each designed for a different modeling scenario. All node types implement the INode interface and share common properties (ID, opening hours, visit duration, importance), but differ in what additional information they carry and how the optimizer treats them.


Overview


Common properties

All node types share the following properties:

Unique ID

Every node needs a unique string identifier. This ID is used throughout the optimization for assignment, reporting, and result analysis. No two nodes may share the same ID.

String nodeId = "Cologne";

Opening hours

A node holds a list of IOpeningHours entries. Each entry defines a time window during which the node can be visited. Multiple opening hours represent multiple days or multiple time slots.

ZonedDateTime start = ZonedDateTime.of(2020, MAY.getValue(), 6, 8, 0, 0, 0,
    ZoneId.of("Europe/Berlin"));
ZonedDateTime end = ZonedDateTime.of(2020, MAY.getValue(), 6, 17, 0, 0, 0,
    ZoneId.of("Europe/Berlin"));

IOpeningHours firstDay = new OpeningHours(start, end);

Alternatively, you can construct an OpeningHours from a TimeWindow object:

TimeWindow tw = new TimeWindow(start, end);
IOpeningHours firstDay = new OpeningHours(tw);

Multiple opening hours are collected into a list:

List<IOpeningHours> openingHours = new ArrayList<>();
openingHours.add(dayOneHours);
openingHours.add(dayTwoHours);

Each opening hour corresponds to a potential visit slot. If a resource has matching WorkingHours on the same day, the optimizer can schedule the visit during that window.

Visit duration

The time required to perform the task at the node. This is the productive service time, not including travel.

Duration visitDuration = Duration.ofMinutes(20);

The optimizer accounts for this duration when scheduling: the resource must arrive, spend the visit duration at the node, and then travel to the next stop. A node with a 20-minute visit duration and a 30-minute driving time from the previous stop consumes at least 50 minutes of the resource's working time.

Visit duration can be made route-dependent using the visit duration efficiency feature, where different resources can perform the same task faster or slower. See setHasRouteDependentVisitDuration(true) and setMinimalVisitDuration(...).

Importance

A relative integer value that influences how the optimizer prioritizes nodes when violations are unavoidable. A node with higher importance is less likely to be violated (late arrival, skipping) than a node with lower importance.

int importance = 1; // default

Importance is relative. If all nodes have the same importance value, the optimizer treats them equally. The value only matters when nodes compete for limited resources or time windows. Common practice: use a small integer scale (e.g. 1 to 10) and assign higher values to contractually important tasks.

TimeWindowGeoNode

The most common node type. Represents a physical location that must be visited within a time window.

Constructor

INode node = new TimeWindowGeoNode(
    "Cologne",           // unique ID
    50.9333,             // latitude
    6.95,                // longitude
    openingHours,        // List<IOpeningHours>
    Duration.ofMinutes(20), // visit duration
    1                    // importance
);
ParameterTypeDescription
idStringUnique identifier for the node
latitudedoubleGeographic latitude of the node's location
longitudedoubleGeographic longitude of the node's location
openingHoursList<IOpeningHours>Time windows when the node can be visited
visitDurationDurationService time required at the node
importanceintRelative priority (higher = more protected from violations)

The geo coordinates define where the node is located on the map. The optimizer uses these coordinates to calculate distances and travel times between nodes, either through external connection data or the built-in backup connector.

When to use

Use TimeWindowGeoNode for any task that requires physical presence at a location: customer visits, deliveries, inspections, maintenance jobs, installations.

EventNode

A node without a geographical location. Represents a task that must happen within a time window but does not require travel.

Constructor

INode event = new EventNode(
    "Customer Call",     // unique ID
    openingHours,        // List<IOpeningHours>
    Duration.ofMinutes(30), // visit duration
    1                    // importance
);
ParameterTypeDescription
idStringUnique identifier
openingHoursList<IOpeningHours>Time windows when the task can be performed
visitDurationDurationTime required for the task
importanceintRelative priority

An EventNode has no latitude/longitude. It is placed into the route timeline like any other node (consuming visit duration within the opening hours), but it does not introduce travel distance. The optimizer schedules it in a gap between physical visits where it fits the time window.

When to use

Use EventNode for phone calls, remote support sessions, paperwork, compliance steps, administrative tasks, or any work that can be done from anywhere within working hours. EventNodes can be mixed freely with geo nodes in the same optimization.

PillarTimeWindowGeoNode

A geo-located node with a hard-constrained time window. The optimizer's architecture guarantees that the opening hours of a Pillar cannot be violated. This is not a high-penalty soft constraint. It is a structural property of the solution space.

Constructor

IOpeningHours pillarWindow = new OpeningHours(
    ZonedDateTime.of(2020, MAY.getValue(), 6, 10, 0, 0, 0, ZoneId.of("Europe/Berlin")),
    ZonedDateTime.of(2020, MAY.getValue(), 6, 10, 50, 0, 0, ZoneId.of("Europe/Berlin")));

IPillarNode pillar = new PillarTimeWindowGeoNode(
    "Plumbing Appointment",  // unique ID
    50.9333,                 // latitude
    6.95,                    // longitude
    pillarWindow             // single OpeningHours (the SLA window)
);

When the visit duration equals the opening hour window, it is not necessary to provide the duration separately. The node must be visited during exactly this window.

A Pillar can optionally be attached to a specific resource:

pillar.attachResource(john);

This guarantees not only when the task is done but also who does it.

When to use

Use PillarTimeWindowGeoNode for contractual SLAs, legal obligations, appointments with fixed time commitments, or any task where "almost on time" is not acceptable. See the Pillar Nodes feature guide for detailed conflict resolution behavior.

PillarEventNode

A non-geographical Pillar. The same hard time-window guarantee as PillarTimeWindowGeoNode, but without a physical location.

Constructor

IPillarNode pillarCall = new PillarEventNode(
    "Important Call",            // unique ID
    pillarOpeningHours,          // single OpeningHours
    Duration.ofMinutes(30)       // visit duration
);

pillarCall.attachResource(jack);

When to use

Use PillarEventNode for time-critical phone calls, compliance deadlines, or remote tasks that must happen in an exact window and cannot be missed.

Optional nodes

Any node type can be marked as optional. An optional node may or may not be visited, depending on what is globally optimal. The optimizer decides whether including the node improves or worsens the total cost.

node.setIsOptional(true);

Optional nodes are useful for:

  • Intermediate stops in pickup and delivery (e.g. waste dumps, reload points)
  • Nice-to-have visits that can be deferred if the schedule is too tight
  • Buffer nodes that absorb excess capacity

When an optional node is not visited, it does not appear in the result routes. The optimizer reports which optional nodes were included and which were skipped.

Stay nodes

Any geo node can be marked as a stay node, making it eligible as an overnight position for multi-day routing:

node.setIsStayNode(true);

A stay node can simultaneously be optional. The optimizer will visit the hotel only if staying out is beneficial. See the Overnight Stay feature guide for policy controls.

Builder pattern

For enterprise integrations and REST-compatible workflows, JOpt provides an immutable builder pattern. Instead of using constructors, you compose nodes fluently:

Node node = Node.builder()
    .id("Cologne")
    .type(GeoNode.of(Position.of(50.9333, 6.95)))
    .visitDuration(Duration.ofMinutes(20))
    .addOpeningHours(
        OpeningHours.builder()
            .begin(begin.toInstant())
            .end(end.toInstant())
            .zoneId(begin.getZone())
            .build())
    .build();

The builder produces an immutable object that can be serialized to JSON and used across REST, SDK, and test environments. The OptimizationConfig builder composes nodes, resources, and properties into a single immutable configuration:

OptimizationConfig<JSONConfig> config = OptimizationConfig.<JSONConfig>builder()
    .addAllNodes(createNodes())
    .addAllResources(createResources())
    .extension(createExtension())
    .options(createOptions())
    .build();

This is the recommended approach when building optimization inputs programmatically, especially in service contexts where reproducibility and serialization matter.

Example on GitHub: BuilderPatternExample.java.

Adding nodes to the optimization

Once constructed, nodes are added to the optimization instance:

opti.addElement(node);

All node types use the same addElement(...) method. Geo nodes, event nodes, pillars, and optional nodes are all added the same way. The optimizer identifies the type internally and applies the appropriate handling.

Node IDs must be unique. If you add a node with an ID that already exists, it will be rejected.


Summary

Node typeHas locationHard time windowTypical use case
TimeWindowGeoNodeYesNo (soft)Customer visits, deliveries, inspections
EventNodeNoNo (soft)Phone calls, remote tasks, paperwork
PillarTimeWindowGeoNodeYesYes (architectural)Contractual SLAs, fixed appointments
PillarEventNodeNoYes (architectural)Time-critical calls, compliance deadlines

Additional flags applicable to any node:

  • setIsOptional(true): optimizer decides whether to visit
  • setIsStayNode(true): eligible as overnight position

For the next step, see the Basic Elements tutorial to learn how nodes and resources work together in an optimization.


Authors

A product by dna-evolutions ©