using System;
using Rugrid.Sdaid.Notation.Documents;
using Building = Rugrid.Sdaid.Epas.Ntr.Domain.BuildingModel.Building;
using ConsumptionModelEntity = Rugrid.Sdaid.Epas.Ntr.Domain.ConsumptionModel.ConsumptionModel;
using EnergyProfileCollectionTask = Rugrid.Sdaid.Epas.Ntr.Domain.EnergyProfileCollectionTaskModel.EnergyProfileCollectionTask;
using EnergyProfileStatus = Rugrid.Sdaid.Epas.Ntr.Domain.Reference.SysReference.EnergyProfileStatus;
using ModelConsistencyStatus = Rugrid.Sdaid.Epas.Ntr.Domain.Reference.SysReference.ModelConsistencyStatus;
namespace Rugrid.Sdaid.Epas.Ntr.Domain.EnergyProfileModel
{
/// <summary>
/// Доменная сущность. Перенесено дословно из ntr-01/domain/energy-profile-model/energy-profile.md.
/// </summary>
public class DOC_EnergyProfile : IDomainEntityDocument, IHasStructuralLinks, IFolder<NtrDomainFolder>
{
public SdaidLink[] Links => new[]
{
Rel.Uses<Rugrid.Sdaid.Epas.Ntr.Domain.BuildingModel.DOC_Building>(),
Rel.Uses<Rugrid.Sdaid.Epas.Ntr.Domain.ConsumptionModel.DOC_ConsumptionModel>(),
Rel.Uses<Rugrid.Sdaid.Epas.Ntr.Domain.EnergyProfileCollectionTaskModel.DOC_EnergyProfileCollectionTask>(),
Rel.Uses<Rugrid.Sdaid.Epas.Ntr.Domain.Reference.SysReference.DOC_EnergyProfileStatus>(),
Rel.Uses<Rugrid.Sdaid.Epas.Ntr.Domain.Reference.SysReference.DOC_ModelConsistencyStatus>(),
};
public static string _refName = "Энергопрофиль";
public string Name => "Энергопрофиль";
public string Description => "Алиасы: Энергопрофиль, Энергопрофиль здания. parents: [energy-profile-diagram].";
public string Version => "1.0";
public string Status => "accepted";
public string[] Comments => new string[0];
public Type Entity => typeof(EnergyProfile);
public static string Body = """"
**Поведение:**
- Энергопрофиль создаётся только автоматически на основе задания на сбор профилей по зданиям орг. объектам за отчётный период. Создаётся один на одно здания на отчётный период.
- При **сохранении** или по отдельной кнопке "**Проверить энергопрофиль**" должна выполняться проверка выполнения условий сохранения ЭП (см. ниже).
- Сохранение энергопрофиля в статусе "Сформирован" блокирует внесение изменений в модели энергопрофиля: модели нельзя редактировать, удалять, удалять из ЭП.
При сохранении Энергопрофиля необходимо выполнять `Проверить энергопрофиль`:
**Условия, обязательные для сохранения Энергопрофиля:
- **Если статус Энергопрофиля "[[../domain/energy-profile-model/energy-profile|Энергопрофиль]]. Статус" == `Формируется`:** сохранять в любом виде.
- **Если статус Энергопрофиля "[[../domain/energy-profile-model/energy-profile|Энергопрофиль]]. Статус" == `Сформирован`, то должны выполняться условия:**
- **Определены модели для всех видов расчётов.** Для каждого вида расчёта $k$ определена модель потребления $M^{k}$:
- **Все виды расчётов выполнены.** Статус расчёта каждой из моделей $M^{k}$ "[[../consumption-model/consumption-model|Модель потребления]]. Статус расчёта" == `Успешно выполнен`.
- **Несущий слой стен не менялся:** не меняются параметры `InputModel`:
- `Walls.CarrierLayerThermalConductivity`;
- `Walls.CarrierLayerThickness`.
- **Несущий слой ВП не менялся:** не меняются параметры `InputModel`:
- `Roof.FloorMaterialThermalConductivity`;
- `Roof.FloorMaterialThickness`.
- **Оконные проёмы не меняются.** Для каждой модели $M^k$ вычисляется количество проёмов $N_{окон}^k(i,a)$ площади $a$ на стороне здания $i\in{[A,B,C,D,E,F,G,H]}$:
$$N_{окон}^{k}(i, a) = \sum_{j,; a=a_{окон}^k(j)} {N_{окон}^k(i,j)}$$
где:
- $a_{окон}^{k}(j)$ - площадь проёма вида окон $j$ в модели $M^k$: `Windows[j].OpeningArea`;
- $N_{окон}^k(i, j)$ - количество проёмов вида окон $j$ на стороне здания $i\in{[A,B,C,D,E,F,G,H]}$ в модели $M^k$: `Windows[j].OpeningsSideA`, ..., `Windows[j].OpeningsSideH`.
Количества проёмов $N_{окон}^k(i,a)$ для всех видов расчётов $k$ должно быть одинаковым.
- **Воротные проёмы не меняются.** Для каждой модели $M^k$ вычисляется количество проёмов $N_{ворот}^{k}(i,a)$ площади $a$ на стороне здания $i\in{[A,B,C,D,E,F,G,H]}$:
$$N_{ворот}^{k}(i, a) = \sum_{j,; a = a_{ворот}^{k}(j)} N_{ворот}^{k}(i, j)$$
где:
- $a_{ворот}^{k}(j)$ — площадь проёма вида ворот $j$ в модели $M^k$: `Doors[j].OpeningArea`;
- $N_{ворот}^{k}(i, j)$ — количество проёмов вида ворот $j$ на стороне здания $i\in{A,B,C,D,E,F,G,H}$ в модели $M^k$: `Doors[j].OpeningsSideA`, ..., `Doors[j].OpeningsSideH`.
Количества проёмов $N_{в}^{k}(i, a)$ для всех видов расчётов $k$ должно быть одинаковым.
- **Сопротивления теплопередаче всех элементов ограждающей конструкции здания не ухудшаются.** Приведённые сопротивления теплопередаче $R_{e}^{k}$ каждого элемента ограждающей конструкции здания $e\in{[стен, окон, ворот, ВОК]}$ для различных видов расчётов $k$ удовлетворяют условиям:
- $R_{e}^{Т} ≥ R_{e}^{Э} ≥ R_{e}^{Н}$.
На $R^{П}_e$ требование не распространяется.
- **Форма и габариты здания не менялись.** Для всех моделей $M^{k}$ в `InputModel` определены одинаковые параметры секции `Geometry`.
- **Функциональное назначение здания не меняется.** Для всех моделей $M^{k}$ определено одинаковое функциональное назначение здания: не меняются параметры `InputModel`, определяемые функциональным назначением:
- `OperatingConditions.NormativeSpecificHeatConsumption`;
- `OperatingConditions.AirConsumptionPerPerson`.
- **Система отопления здания не меняется.** Для всех моделей $M^{k}$ определён один тип системы отопления: `OperatingConditions.HeatingType`.
- **Высота подвала не меняется.** Для всех моделей $M^{k}$ определена одинаковая высота подвала: `GroundContact.BasementHeight`
Если условия выполняются, сохранить ЭП, перейти в режим просмотра. Если нет, подсветить ошибку: сообщить об ошибке, предупредить, что при сохранении статус ЭП будет сброшен в `Формируется`, предложить: отменить, выполнить.
"""";
}
/// <summary>
/// Доменная сущность «Энергопрофиль».
/// Класс — источник структуры: таблица свойств и диаграмма связей на странице документа
/// строятся генератором по нему. Прозу и разбор ведёт документ DOC_EnergyProfile.
/// </summary>
[DomainEntity]
public class EnergyProfile
{
/// <summary>Идентификатор записи</summary>
[DomainField(Alias = "id", RequiredOnCreate = true, Immutable = true)]
public Guid Id { get; set; }
/// <summary>Задание на сбор энергопрофилей</summary>
[Relation]
[DomainField(Alias = "energy_profile_collection_task_id", RequiredOnCreate = true, Immutable = true)]
public EnergyProfileCollectionTask? EnergyProfileCollectionTask { get; set; }
/// <summary>Здание</summary>
[Relation]
[DomainField(Alias = "building_id", RequiredOnCreate = true, Immutable = true)]
public Building? Building { get; set; }
/// <summary>Наименование</summary>
[DomainField(
Alias = "name",
Calculated = "Да, вычисляется при чтении / на UI; не хранится. Формула: \"{FK → Здание. Наименование} ({FK → Задание на сбор энергопрофилей. Год начала отчётного периода}-{Задание на сбор энергопрофилей. Год окончания отчётного периода})\" Пример: Гараж №1 (2026-2026)"
)]
public string? Name { get; set; }
/// <summary>Модель нормативного расчёта</summary>
[Relation]
[DomainField(Alias = "normative_calculation_model_id", Range = "Если выбрана, то может быть только модель с `Вид расчёта` == `Нормативный`")]
public ConsumptionModelEntity? NormativeCalculationModel { get; set; }
/// <summary>Модель эталонного расчёта</summary>
[Relation]
[DomainField(Alias = "standard_calculation_model_id", Range = "Если выбрана, то может быть только модель с `Вид расчёта` == `Эталонный`")]
public ConsumptionModelEntity? StandardCalculationModel { get; set; }
/// <summary>Модель технологического расчёта</summary>
[Relation]
[DomainField(
Alias = "technological_calculation_model_id",
Range = "Если выбрана, то может быть только модель с `Вид расчёта` == `Технологический`"
)]
public ConsumptionModelEntity? TechnologicalCalculationModel { get; set; }
/// <summary>Модель произвольного расчёта</summary>
[Relation]
[DomainField(Alias = "custom_calculation_model_id", Range = "Если выбрана, то может быть только модель с `Вид расчёта` == `Произвольный`")]
public ConsumptionModelEntity? CustomCalculationModel { get; set; }
/// <summary>Статус энергопрофиля</summary>
[Relation]
[DomainField(
Alias = "status_id",
RequiredOnCreate = true,
Range = "{Формируется; Сформирован}",
Default = "Формируется",
Description = "Устанавливается пользователем"
)]
public EnergyProfileStatus? Status { get; set; }
/// <summary>Статус выполнения условий расчётов</summary>
[Relation]
[DomainField(
Alias = "model_consistency_status_id",
RequiredOnCreate = true,
Calculated = "Да",
Range = "{Выполнены; Не выполнены}.",
Default = "Не выполнены",
Description = "Вычисляется автоматически"
)]
public ModelConsistencyStatus? ModelConsistencyStatus { get; set; }
}
}