Project.Level#

Resolves resource overallocation in a Project. It runs Solve(null, …) with default options first, then writes persistent LevelingDelay and Pauses edits and accepts the leveled state as the baseline.

Signature#

public LevelingResult Level(LevelingOptions options)

Synchronous and CPU-only. Changes the project's state.

Parameters#

Name Type Description
options LevelingOptions Scope, order, basis and how leveling may move tasks

Behavior#

  • Forward scheduling only.
  • On a cyclic project, it returns the initial solve's result with Rounds = 0.
  • The leveled dates replace the baseline. To see leveling without committing it, call Level on a Clone().

Returns#

A LevelingResult. The project keeps its Schedule as the baseline and shares it with clones. Treat Schedule as read-only, or call DeepClone() before modifying it.

Errors#

Error When
InputException An unknown id in options.Scope.Resources or options.Scope.Tasks (Path is scope.resources / scope.tasks); the project has Config.ScheduleFromEnd = true (Path is config.schedule_from_end)
ProjectException NeedsResync Thrown by the initial solve
ArgumentNullException options is null

Example#

Level two tasks that share one resource, first on a copy, then for real.

using Plen;

var monday = Moment.FromYmdHm(2026, 8, 10, 8, 0) ?? throw new InvalidOperationException("invalid date");
TaskData Task(string id) => new(id) { StartDate = monday, Duration = 2.0 };
AssignmentData Assign(string task) => new() { Task = task, Resource = "dev", Value = 1.0 };

var data = new ProjectData
{
    Tasks = [Task("a"), Task("b")],
    Resources = [new ResourceData { Id = "dev" }],
    Assignments = [Assign("a"), Assign("b")],
};

var project = new Project();
project.Solve(data, new SolveOptions());

// A proposal: level a cheap copy, the project keeps its dates.
var draft = project.Clone();
var proposal = draft.Level(new LevelingOptions());
foreach (var update in proposal.Schedule.Updates)
    Console.WriteLine($"task {update.Id} delay {update.LevelingDelay}");

// Commit: level the project itself.
var leveled = project.Level(new LevelingOptions());
Console.WriteLine($"{leveled.Rounds} round(s)");