private static ProjectData Finalize(this ProjectData project) { var calendar = project.Information.Calendar; foreach (var taskId in project.Tasks) { var earlyStart = project.Get(TaskFields.EarlyStart, taskId); var earlyFinish = project.Get(TaskFields.EarlyFinish, taskId); var lateStart = project.Get(TaskFields.LateStart, taskId); var lateFinish = project.Get(TaskFields.LateFinish, taskId); // Set start, finish, and duration var start = earlyStart; var finish = earlyFinish; var duration = calendar.GetWork(start, finish); project = project.SetRaw(TaskFields.Start, taskId, start) .SetRaw(TaskFields.Finish, taskId, finish) .SetRaw(TaskFields.Duration, taskId, duration); // Set start slack, finish slack, total slack, and criticality var startSlack = calendar.GetWork(earlyStart, lateStart); var finishSlack = calendar.GetWork(earlyFinish, lateFinish); var totalSlack = startSlack <= finishSlack ? startSlack : finishSlack; var isCritical = totalSlack == TimeSpan.Zero; project = project.SetRaw(TaskFields.StartSlack, taskId, startSlack) .SetRaw(TaskFields.FinishSlack, taskId, finishSlack) .SetRaw(TaskFields.TotalSlack, taskId, totalSlack) .SetRaw(TaskFields.IsCritical, taskId, isCritical); // Set free slack var freeSlack = GetFreeSlack(project, taskId); project = project.SetRaw(TaskFields.FreeSlack, taskId, freeSlack); } // Set assignment start and finish foreach (var assignmentId in project.Assignments) { var taskId = project.Get(AssignmentFields.TaskId, assignmentId); var taskStart = project.Get(TaskFields.Start, taskId); var assignmentWork = project.Get(AssignmentFields.Work, assignmentId); var assignmentUnits = project.Get(AssignmentFields.Units, assignmentId); var assignmentStart = taskStart; var duration = TimeSpan.FromHours(assignmentWork.TotalHours / assignmentUnits); ComputeFinish(project.Information.Calendar, ref assignmentStart, out var assignmentFinish, duration); project = project.SetRaw(AssignmentFields.Start, assignmentId, assignmentStart) .SetRaw(AssignmentFields.Finish, assignmentId, assignmentFinish); } return(project); }
private static ProjectData ResetTaskResourceNamesOrInitials(ProjectData project, TaskId id, bool isInitials) { var resourceField = isInitials ? ResourceFields.Initials : ResourceFields.Name; var taskField = isInitials ? TaskFields.ResourceInitials : TaskFields.ResourceNames; var sb = new StringBuilder(); foreach (var a in project.GetAssignments(id) .OrderBy(a => project.Get(resourceField, project.Get(AssignmentFields.ResourceId, a)))) { var resourceId = project.Get(AssignmentFields.ResourceId, a); var resourceName = project.Get(resourceField, resourceId); var units = project.Get(AssignmentFields.Units, a); if (sb.Length > 0) { sb.Append(", "); } sb.Append(resourceName); if (units != 1.0) { sb.Append(" ["); sb.Append(Math.Round(units * 100, 2, MidpointRounding.AwayFromZero)); sb.Append("%]"); } } var resourceNames = sb.ToString(); return(project.SetRaw(taskField, id, resourceNames)); }
private static ProjectData ResetTaskPredecessorsOrSuccessors(ProjectData project, TaskId id, bool isSuccessors) { TaskId GetPredecessor(TaskLink l) => l.PredecessorId; TaskId GetSuccessor(TaskLink l) => l.SuccessorId; var getTask = isSuccessors ? (Func <TaskLink, TaskId>)GetSuccessor : GetPredecessor; var field = isSuccessors ? TaskFields.Successors : TaskFields.Predecessors; var linkField = isSuccessors ? TaskFields.SuccessorLinks : TaskFields.PredecessorLinks; var sb = new StringBuilder(); var predecessors = project.Get(linkField, id); foreach (var p in predecessors.OrderBy(p => project.Get(TaskFields.Ordinal, getTask(p)))) { if (sb.Length > 0) { sb.Append(","); } var ordinal = project.Get(TaskFields.Ordinal, getTask(p)); sb.Append(ordinal); switch (p.Type) { case TaskLinkType.FinishToStart: if (p.Lag != TimeSpan.Zero) { sb.Append("FS"); } break; case TaskLinkType.StartToStart: sb.Append("SS"); break; case TaskLinkType.FinishToFinish: sb.Append("FF"); break; case TaskLinkType.StartToFinish: sb.Append("SF"); break; } if (p.Lag != TimeSpan.Zero) { if (p.Lag > TimeSpan.Zero) { sb.Append("+"); } var lag = project.Information.TimeConversion.FormatDuration(p.Lag); sb.Append(lag); } } var precedessors = sb.ToString(); return(project.SetRaw(field, id, precedessors)); }
private static ProjectData BackwardPass(this ProjectData project) { var computedTasks = new HashSet <TaskId>(); var toBeScheduled = new Queue <TaskId>(project.Tasks); while (toBeScheduled.Count > 0) { var taskId = toBeScheduled.Dequeue(); var successors = project.Get(TaskFields.SuccessorLinks, taskId); var allSuccessorsComputed = successors.All(l => computedTasks.Contains(l.SuccessorId)); if (!allSuccessorsComputed) { toBeScheduled.Enqueue(taskId); } else { ComputeLateStartAndFinish(project, taskId, successors, out var lateStart, out var lateFinish); project = project.SetRaw(TaskFields.LateStart, taskId, lateStart) .SetRaw(TaskFields.LateFinish, taskId, lateFinish); computedTasks.Add(taskId); } } return(project); }
private static ProjectData ForwardPass(this ProjectData project) { var computedTasks = new HashSet <TaskId>(); var toBeScheduled = new Queue <TaskId>(project.Tasks); while (toBeScheduled.Count > 0) { var taskId = toBeScheduled.Dequeue(); var predecessors = project.Get(TaskFields.PredecessorLinks, taskId); var allPredecessorsComputed = predecessors.All(l => computedTasks.Contains(l.PredecessorId)); if (!allPredecessorsComputed) { toBeScheduled.Enqueue(taskId); } else { ComputeEarlyStartAndFinish(project, taskId, predecessors, out var earlyStart, out var earlyFinish); project = project.SetRaw(TaskFields.EarlyStart, taskId, earlyStart) .SetRaw(TaskFields.EarlyFinish, taskId, earlyFinish); computedTasks.Add(taskId); } } var projectFinish = ComputeProjectFinish(project); var information = project.Information.WithFinish(projectFinish); return(project.WithInformation(information)); }
private static ProjectData SetAssignmentUnits(ProjectData project, AssignmentId id, double value) { var taskId = project.Get(AssignmentFields.TaskId, id); return(project.SetRaw(AssignmentFields.Units, id, value) .Reset(TaskFields.ResourceNames, taskId) .Reset(TaskFields.ResourceInitials, taskId)); }
private static ProjectData SetTaskWork(ProjectData project, TaskId id, TimeSpan value) { project = project.SetRaw(TaskFields.Work, id, value); if (value == TimeSpan.Zero) { foreach (var assignmentId in project.GetAssignments(id)) { project = project.SetRaw(AssignmentFields.Work, assignmentId, TimeSpan.Zero); } } else { var totalExistingWork = TimeSpan.Zero; foreach (var assignmentId in project.GetAssignments(id)) { totalExistingWork += project.Get(AssignmentFields.Work, assignmentId); } var assignmentCount = project.GetAssignments(id).Count(); foreach (var assignmentId in project.GetAssignments(id)) { var assignmentWork = project.Get(AssignmentFields.Work, assignmentId); double newHours; if (totalExistingWork > TimeSpan.Zero) { newHours = assignmentWork.TotalHours / totalExistingWork.TotalHours * value.TotalHours; } else { newHours = value.TotalHours / assignmentCount; } var newWork = TimeSpan.FromHours(newHours); project = project.SetRaw(AssignmentFields.Work, assignmentId, newWork); } } return(project); }
private static ProjectData SetResourceName(ProjectData project, ResourceId id, string value) { project = project.SetRaw(ResourceFields.Name, id, value); // Update Assignment.ResourceName foreach (var assignmentId in project.GetAssignments(id)) { project = project.SetRaw(AssignmentFields.ResourceName, assignmentId, value); } // Update Task.ResourceNames foreach (var taskId in project.GetTasks(id)) { project = project.Reset(TaskFields.ResourceNames, taskId); } return(project); }
private static ProjectData SetAssignmentWork(ProjectData project, AssignmentId id, TimeSpan value) { var taskId = project.Get(AssignmentFields.TaskId, id); var oldTaskWork = project.Get(TaskFields.Work, taskId); var oldAssignmentWork = project.Get(AssignmentFields.Work, id); var newAssignmentWork = value; var newTaskWork = oldTaskWork + newAssignmentWork - oldAssignmentWork; return(project.SetRaw(TaskFields.Work, taskId, newTaskWork) .SetRaw(AssignmentFields.Work, id, newAssignmentWork)); }
private static ProjectData SetResourceInitials(ProjectData project, ResourceId id, string value) { project = project.SetRaw(ResourceFields.Initials, id, value); // Update Task.ResourceInitials foreach (var taskId in project.GetTasks(id)) { project = project.Reset(TaskFields.ResourceInitials, taskId); } return(project); }
private static ProjectData SetTaskName(ProjectData project, TaskId id, string value) { var assignmentIds = project.GetAssignments(id); project = project.SetRaw(TaskFields.Name, id, value); foreach (var assignmentId in assignmentIds) { project = project.Set(AssignmentFields.TaskName, assignmentId, value); } return(project); }
private static ProjectData SetTaskDuration(ProjectData project, TaskId id, TimeSpan value) { project = project.SetRaw(TaskFields.Duration, id, value); var taskFinish = project.Get(TaskFields.Finish, id); foreach (var assignmentId in project.GetAssignments(id)) { var assignmentFinish = project.Get(AssignmentFields.Finish, assignmentId); var assignmentUnits = project.Get(AssignmentFields.Units, assignmentId); if (assignmentFinish == taskFinish) { var assignmentWork = TimeSpan.FromHours(value.TotalHours * assignmentUnits); project = project.Set(AssignmentFields.Work, assignmentId, assignmentWork); } } return(project); }
private static ProjectData SetTaskOrdinal(ProjectData project, TaskId id, int value) { if (value < 0 || value >= project.TaskMap.Count) { throw new ArgumentOutOfRangeException(nameof(value)); } var oldOrdinal = project.Get(TaskFields.Ordinal, id); var newOrdinal = value; var orderedTaskIds = project.Tasks .OrderBy(t => project.Get(TaskFields.Ordinal, t)) .ToList(); orderedTaskIds.RemoveAt(oldOrdinal); orderedTaskIds.Insert(newOrdinal, id); // First we update all ordinals for (var i = 0; i < orderedTaskIds.Count; i++) { var taskId = orderedTaskIds[i]; var ordinal = i; project = project.SetRaw(TaskFields.Ordinal, taskId, ordinal); } // Then we can update all predecessors/successors foreach (var taskId in orderedTaskIds) { project = project.Reset(TaskFields.Predecessors, taskId) .Reset(TaskFields.Successors, taskId); } return(project); }