[Canonical page](<https://docs.dhtmlx.com/planning-engine/net/api/core/evaluate/leveled-metrics/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# LeveledMetrics

Metrics of a leveled stage, together with how the leveling run went. It's found in [`CandidateResult.Leveled`](<https://docs.dhtmlx.com/planning-engine/net/api/core/evaluate/candidate-result.md>) and [`SuggestProposal.Leveled`](<https://docs.dhtmlx.com/planning-engine/net/api/core/suggest/suggest-result.md#suggestproposal>), and only when the call's options set `Level`. It's `null` when the scheduled stage is cyclic, because then there's no leveled stage.

## Declaration

```csharp
namespace Plen;

public sealed class LeveledMetrics : IDeepCloneable<LeveledMetrics>, IEquatable<LeveledMetrics>
{
    public required Metrics Metrics { get; set; }
    public bool Converged { get; set; }
    public uint Rounds { get; set; }
    public uint Windows { get; set; }

    public LeveledMetrics DeepClone();
    public bool Equals(LeveledMetrics? other);
}
```

## Properties

| Property | Type | Description |
|---|---|---|
| `Metrics` | [`Metrics`](<https://docs.dhtmlx.com/planning-engine/net/api/core/evaluate/metrics.md>) | Finish, overload, conflicts, cycles and cost of the leveled stage, against the baseline. |
| `Converged` | `bool` | `Converged` of the leveled schedule. |
| `Rounds` | `uint` | Leveling rounds run. |
| `Windows` | `uint` | Overallocation windows left after leveling, for every reason. |

### Metrics

```csharp
public required Metrics Metrics { get; set; }
```

The leveled stage measured against the same baseline as the scheduled stage. `Metrics.Cost` is the stage's cost, and a candidate's [`CandidateResult.Cost`](<https://docs.dhtmlx.com/planning-engine/net/api/core/evaluate/candidate-result.md>) equals it whenever `Leveled` is set.

### Converged

```csharp
public bool Converged { get; set; }
```

[`ScheduleResult.Converged`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/schedule-result.md#converged>) of the schedule the leveling run returned.

### Rounds

```csharp
public uint Rounds { get; set; }
```

[`LevelingResult.Rounds`](<https://docs.dhtmlx.com/planning-engine/net/api/core/resources/leveling-result.md#rounds>) of the leveling run.

### Windows

```csharp
public uint Windows { get; set; }
```

The number of overallocation windows still left in the leveled schedule, summed over all resources, whatever the reason each one remained. `0` means leveling resolved every overallocation. The windows themselves aren't in the result; see [`ResourceOverallocation`](<https://docs.dhtmlx.com/planning-engine/net/api/core/resources/resource-overallocation.md>) for what a window is.

## Methods

### DeepClone

```csharp
public LeveledMetrics DeepClone()
```

Returns a copy that shares no nested object with this one.

### Equals

```csharp
public bool Equals(LeveledMetrics? other)
public override bool Equals(object? obj)
```

Value equality: `Metrics` is equal and `Converged`, `Rounds` and `Windows` match. `GetHashCode` is consistent with it.

### ToString

```csharp
public override string ToString()
```

Returns a readable dump of all properties, for logging.

## Example

Score one candidate with leveling and read its leveled stage:

```csharp
using Plen;

var monday = Moment.FromYmdHm(2026, 8, 10, 8, 0)
    ?? throw new InvalidOperationException("invalid date");

var data = new ProjectData
{
    Tasks =
    [
        new TaskData(1) { StartDate = monday, Duration = 2.0 },
        new TaskData(2) { StartDate = monday, Duration = 2.0 },
    ],
    Resources = [new ResourceData { Id = "dev1" }],
    Assignments = [new AssignmentData { Task = 1, Resource = "dev1", Value = 1.0 }],
};

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

var changes = new SchedulingChanges();
changes.Assignments.Add.Add(new AssignmentData { Task = 2, Resource = "dev1", Value = 1.0 });

var result = project.Evaluate(
    [new Candidate { Id = "dev1-on-2", Changes = changes }],
    new EvaluateOptions { Level = new LevelingOptions() });

var leveled = result.Candidates[0].Leveled;
if (leveled is not null)
{
    Console.WriteLine($"cost: {leveled.Metrics.Cost}");
    Console.WriteLine($"rounds: {leveled.Rounds}, windows left: {leveled.Windows}");
}
```

## Related

- [`Metrics`](<https://docs.dhtmlx.com/planning-engine/net/api/core/evaluate/metrics.md>) - the stage metrics it wraps
- [`CandidateResult`](<https://docs.dhtmlx.com/planning-engine/net/api/core/evaluate/candidate-result.md>) - where the leveled stage of a candidate is found
- [`EvaluateOptions`](<https://docs.dhtmlx.com/planning-engine/net/api/core/evaluate/evaluate-options.md>) - `Level` turns the leveled stage on
- [`LevelingResult`](<https://docs.dhtmlx.com/planning-engine/net/api/core/resources/leveling-result.md>) - the result of a committed leveling run
- [Evaluating alternatives](<https://docs.dhtmlx.com/planning-engine/net/resources-and-assignment/evaluating-alternatives.md#metrics-and-cost>) - comparing candidates at the leveled stage
