EvaluateOptions#
Options for Project.Evaluate and Project.EvaluateWith. They set which baseline the call expects, whether each candidate is also leveled, which tasks get per-task metrics, and whether candidates run against a copy with leveling delays cleared. new EvaluateOptions() scores the scheduled stage only, with no focus tasks.
Declaration#
public sealed class EvaluateOptions : IDeepCloneable<EvaluateOptions>
{
public string? BaselineId { get; set; }
public LevelingOptions? Level { get; set; }
public List<Id> Focus { get; set; } = [];
public bool ClearFirst { get; set; }
public EvaluateOptions DeepClone();
}
Set the properties you need with an object initializer: new EvaluateOptions { Focus = ["B"] }. EvaluateOptions doesn't implement IEquatable<T>, so two instances compare by reference.
Properties#
| Property | Type | Default | Description |
|---|---|---|---|
BaselineId |
string? |
null |
The baseline the call expects. null skips the check. |
Level |
LevelingOptions? |
null |
Levels every candidate after scheduling it and fills CandidateResult.Leveled. null scores the scheduled stage only. |
Focus |
List<Id> |
empty | Tasks to report finish and overload for. |
ClearFirst |
bool |
false |
Scores the baseline and every candidate on a copy with in-scope LevelingDelay / Pauses cleared. |
BaselineId#
public string? BaselineId { get; set; }
A baseline token taken from the latest ScheduleResult.BaselineId. When it isn't null and doesn't name the project's current baseline, the call throws a ProjectException with Code == ProjectError.StaleBaseline.
Each candidate's SchedulingChanges.BaselineId is checked the same way, independently of this property.
Level#
public LevelingOptions? Level { get; set; }
When set, each candidate is leveled with these options, unchanged, after it's scheduled. CandidateResult.Leveled then holds the leveled-stage LeveledMetrics, and CandidateResult.Cost is taken from that stage. A cyclic candidate has no leveled stage, so Leveled stays null. When Level is null, Leveled is always null.
Level.Basis (or the basis derived from config.DurationUnit when it's null or Level is null) is the bucket size for every overload figure in the result. Level.Scope.Tasks also sets the scope of ClearFirst.
Options that are invalid against the baseline make the call throw an InputException. To commit the chosen candidate, pass the same LevelingOptions to Project.Level; otherwise the committed plan isn't the one that was scored.
Focus#
public List<Id> Focus { get; set; } = [];
The tasks the result reports per-task metrics for. Each focus task gets one entry in Finish.Tasks and one in Overload.Focus, in the baseline and in every stage of every candidate. With an empty list, both lists are empty.
Every id must name a task in the baseline. An unknown id makes the call throw an InputException with Path focus[i]. A focus task that a candidate removes reports null for its finish and its focus overload in that candidate.
ClearFirst#
public bool ClearFirst { get; set; }
When true, the reference state is a solved copy of the accepted state with LevelingDelay and Pauses cleared on the tasks in scope. The scope is Level.Scope.Tasks when Level gives it, otherwise every task, also when Level is null. The baseline metrics, Conflicts and Cycles included, are measured on that copy, and every candidate runs on it.
Use it after a Project.Level run: the stored delays already sit in the baseline finish and hide the overload the current assignments cause. ClearFirst doesn't depend on Level.ClearFirst, so it also works when Level is null.
ClearFirst adds no error. BaselineId, candidate tokens, Level and Focus are checked against the accepted state before anything is cleared, and EvaluateResult.BaselineId stays the accepted state's. When nothing in scope has a delay or a pause, the result is the same as with ClearFirst = false.
Methods#
DeepClone#
public EvaluateOptions DeepClone()
Returns a copy that shares no nested object (Level, Focus) with this one.
ToString#
public override string ToString()
Returns a debug dump of the fields, e.g. EvaluateOptions { BaselineId: …, Level: …, Focus: …, ClearFirst: … }.
Example#
using Plen;
var monday = Moment.FromYmdHm(2026, 8, 10, 8, 0) ?? throw new InvalidOperationException("invalid date");
var data = new ProjectData
{
Tasks =
[
new TaskData("A") { StartDate = monday, Duration = 2.0 },
new TaskData("B") { StartDate = monday, Duration = 2.0 },
],
Resources = [new ResourceData { Id = "dev1" }, new ResourceData { Id = "dev2" }],
Assignments =
[
new AssignmentData { Id = "aA", Task = "A", Resource = "dev1", Value = 1.0 },
new AssignmentData { Id = "aB", Task = "B", Resource = "dev1", Value = 1.0 },
],
};
var project = new Project();
var solved = project.Solve(data, new SolveOptions());
var toDev2 = new SchedulingChanges();
toDev2.Assignments.Update.Add(new AssignmentUpdate("aB") { Resource = Patch<Id>.Of("dev2") });
var options = new EvaluateOptions
{
BaselineId = solved.BaselineId,
Level = new LevelingOptions(),
Focus = ["B"],
};
var result = project.Evaluate([new Candidate { Id = "dev2", Changes = toDev2 }], options);
var leveled = result.Candidates[0].Leveled;
Console.WriteLine(leveled?.Metrics.Finish.Tasks[0].Finish?.Delta);
Related#
Project.Evaluate- the call these options configureLevelingOptions- the options of the leveling stage set byLevelEvaluateResult- the returned resultCandidate- the alternatives to score- Evaluating alternatives - choosing between alternatives step by step