Skip to main content

EN2 New Controllers Implementation Plan

Overview

This document outlines the implementation plan for creating controllers for 14 new EN2Models in the dwd-api-aspnet project. These models represent newly implemented EPANET input file sections that provide comprehensive coverage of EPANET functionality.

New Models to Implement

1. Pattern - Time-varying data

  • Model: EN2Models.Pattern
  • EPANET Section: [PATTERNS]
  • Type: Single entity with array data
  • Key Properties: Id, Multipliers[], Description
  • Controller: PatternController
  • CRUD Operations: Full CRUD
  • Special Features: Array manipulation methods for multipliers

2. DataCurve - Pump and tank curves

  • Model: EN2Models.DataCurve
  • EPANET Section: [CURVES]
  • Type: Single entity with coordinate arrays
  • Key Properties: Id, CurveType, XValues[], YValues[], Description
  • Controller: DataCurveController
  • CRUD Operations: Full CRUD
  • Special Features: Point manipulation, min/max calculations

3. TimeParameters - Simulation timing

  • Model: EN2Models.TimeParameters
  • EPANET Section: [TIMES]
  • Type: Network defaults with optional scenario overrides
  • Key Properties: ScenarioId? (nullable), Duration, HydraulicTimestep, QualityTimestep, etc.
  • Controller: TimeParametersController
  • CRUD Operations: Full CRUD + network defaults endpoints
  • Special Features: Network-wide defaults (ScenarioId = null), scenario-specific overrides

4. Options - Analysis configuration

  • Model: EN2Models.Options
  • EPANET Section: [OPTIONS]
  • Type: Network defaults with optional scenario overrides
  • Key Properties: ScenarioId? (nullable), various analysis options
  • Controller: OptionsController
  • CRUD Operations: Full CRUD + network defaults endpoints
  • Special Features: Network-wide defaults (ScenarioId = null), scenario-specific overrides

5. Demand - Multiple demand categories

  • Model: EN2Models.Demand
  • EPANET Section: [DEMANDS]
  • Type: Multiple entities (list per junction)
  • Key Properties: JunctionId, DemandValue, PatternId, Category
  • Controller: DemandController
  • CRUD Operations: Full CRUD + LIST endpoint
  • Special Features: Junction-based, multiple demands per junction

6. Source - Water quality sources

  • Model: EN2Models.Source
  • EPANET Section: [SOURCES]
  • Type: Multiple entities (list per node)
  • Key Properties: NodeId, SourceType, Strength, PatternId
  • Controller: SourceController
  • CRUD Operations: Full CRUD + LIST endpoint
  • Special Features: Node-based, multiple sources per node

7. Reaction - Chemical reactions

  • Model: EN2Models.Reaction
  • EPANET Section: [REACTIONS]
  • Type: Multiple entities (list of reactions)
  • Key Properties: ReactionType, Coefficient, ObjectId, Order
  • Controller: ReactionController
  • CRUD Operations: Full CRUD + LIST endpoint
  • Special Features: Global and object-specific reactions

8. TankMixing - Tank mixing models

  • Model: EN2Models.TankMixing
  • EPANET Section: [MIXING]
  • Type: Single entity per tank
  • Key Properties: TankId, MixingModel, CompartmentVolume
  • Controller: TankMixingController
  • CRUD Operations: Full CRUD
  • Special Features: Tank-based (one per tank)

9. Energy - Energy analysis

  • Model: EN2Models.Energy
  • EPANET Section: [ENERGY]
  • Type: Network defaults with optional scenario overrides
  • Key Properties: ScenarioId? (nullable), GlobalPrice, GlobalPattern, PumpId, etc.
  • Controller: EnergyController
  • CRUD Operations: Full CRUD + network defaults endpoints
  • Special Features: Network-wide defaults (ScenarioId = null), scenario-specific overrides with pump-specific overrides

10. Emitter - Pressure-dependent demands

  • Model: EN2Models.Emitter
  • EPANET Section: [EMITTERS]
  • Type: Multiple entities (list per junction)
  • Key Properties: JunctionId, Coefficient
  • Controller: EmitterController
  • CRUD Operations: Full CRUD + LIST endpoint
  • Special Features: Junction-based, multiple emitters per junction

11. Leakage - Pipe leakage modeling

  • Model: EN2Models.Leakage
  • EPANET Section: [LEAKAGE]
  • Type: Multiple entities (list per pipe)
  • Key Properties: PipeId, LeakageCoefficient, Exponent
  • Controller: LeakageController
  • CRUD Operations: Full CRUD + LIST endpoint
  • Special Features: Pipe-based, multiple leakage models per pipe

12. Quality - Initial water quality

  • Model: EN2Models.Quality
  • EPANET Section: [QUALITY]
  • Type: Network defaults with optional scenario overrides
  • Key Properties: ScenarioId? (nullable), GlobalQuality, NodeId, NodeQuality
  • Controller: QualityController
  • CRUD Operations: Full CRUD + network defaults endpoints
  • Special Features: Network-wide defaults (ScenarioId = null), scenario-specific overrides with node-specific overrides
  • Model: EN2Models.Status
  • EPANET Section: [STATUS]
  • Type: Multiple entities (list per link)
  • Key Properties: LinkId, Status, Setting
  • Controller: StatusController
  • CRUD Operations: Full CRUD + LIST endpoint
  • Special Features: Link-based, multiple status entries per link

14. Report - Output reporting options

  • Model: EN2Models.Report
  • EPANET Section: [REPORT]
  • Type: Network defaults with optional scenario overrides
  • Key Properties: ScenarioId? (nullable), Status, Summary, Energy, etc.
  • Controller: ReportController
  • CRUD Operations: Full CRUD + network defaults endpoints
  • Special Features: Network-wide defaults (ScenarioId = null), scenario-specific overrides

Network Defaults Design

Scenario-Based Models with Network Defaults

The following models use a network defaults with scenario overrides approach:

  • TimeParameters - Simulation timing settings
  • Options - Analysis configuration options
  • Energy - Energy analysis parameters
  • Report - Output reporting options

Design Pattern

// Network-wide defaults (ScenarioId = null)
public class TimeParameters
{
public int? ScenarioId { get; set; } // null = network default
public string Duration { get; set; }
// ... other properties
}

Usage Pattern

  1. Network Defaults: One record per model with ScenarioId = null
  2. Scenario Overrides: Optional records with specific ScenarioId values
  3. Effective Settings: Check for scenario-specific first, fall back to network defaults

API Endpoints

// Get network defaults
GET /api/timeparameters/defaults

// Get effective settings for scenario (with fallback)
GET /api/timeparameters/scenario/{scenarioId}

// Create scenario-specific override
POST /api/timeparameters/scenario/{scenarioId}

// Update scenario-specific override
PUT /api/timeparameters/scenario/{scenarioId}

Benefits

  • Better UX: New scenarios inherit sensible defaults
  • Industry Standard: Matches EPANET desktop behavior
  • Flexibility: Power users can customize per scenario
  • Reduced Complexity: Less required configuration upfront
  • Consistency: All scenarios have valid settings

Implementation Strategy

Phase 1: Database Context Updates

  1. Add DbSet properties for all 14 new models to EN2PostgresContext.cs
  2. Update scenario-based models: Change ScenarioId from [Required] to nullable (ScenarioId?)
  3. Configure entity relationships and constraints in OnModelCreating
  4. Create database migration if needed
  5. Create network default records: Insert default records with ScenarioId = null

Phase 2: DTO Creation

  1. Create response DTOs for each model following existing patterns
  2. Include display values for enums where applicable
  3. Add JSON property names for consistency

Phase 3: Controller Implementation

  1. Implement controllers following existing patterns from TankController, PumpController, etc.
  2. Use consistent naming: {ModelName}Controller
  3. Place all controllers in Controllers/EN2/ directory
  4. Implement full CRUD operations:
    • GET - Retrieve with optional ID filter
    • POST - Create new entity
    • PUT - Update existing entity
    • DELETE - Delete entity
  5. Special endpoints for scenario-based models:
    • GET /defaults - Get network-wide defaults (ScenarioId = null)
    • GET /scenario/{scenarioId} - Get effective settings for scenario (with fallback to defaults)
    • POST /scenario/{scenarioId} - Create scenario-specific override

Phase 4: Special Endpoints

  1. Implement LIST endpoints for models that represent multiple entries:
    • DemandController - /api/demand/list/{junctionId}
    • SourceController - /api/source/list/{nodeId}
    • ReactionController - /api/reaction/list
    • EmitterController - /api/emitter/list/{junctionId}
    • LeakageController - /api/leakage/list/{pipeId}
    • StatusController - /api/status/list/{linkId}

Controller Structure Template

Network-Based Models (Pattern, DataCurve, Demand, Source, etc.)

[ApiController]
[Route("api/[controller]")]
public class {ModelName}Controller : ControllerBase
{
private readonly EN2PostgresContext.EN2PostgresContext _context;
private readonly EnumMappingService _enumMappingService;

public {ModelName}Controller(EN2PostgresContext.EN2PostgresContext context, EnumMappingService enumMappingService)
{
_context = context;
_enumMappingService = enumMappingService;
}

[HttpGet]
public async Task<ActionResult<IEnumerable<{ModelName}ResponseDto>>> Get([FromQuery] string? id)
{
// Implementation - no scenario filtering
}

[HttpPost]
public async Task<ActionResult<{ModelName}ResponseDto>> Post([FromBody] {ModelName}RequestDto request)
{
// Implementation - no ScenarioId needed
}

[HttpPut("{id}")]
public async Task<IActionResult> Put(string id, [FromBody] {ModelName}RequestDto request)
{
// Implementation
}

[HttpDelete("{id}")]
public async Task<IActionResult> Delete(string id)
{
// Implementation
}

// LIST endpoint for models with multiple entries
[HttpGet("list/{parentId}")]
public async Task<ActionResult<IEnumerable<{ModelName}ResponseDto>>> GetList(string parentId)
{
// Implementation
}
}

Scenario-Based Models (TimeParameters, Options, Energy, Report)

[ApiController]
[Route("api/[controller]")]
public class {ModelName}Controller : ControllerBase
{
private readonly EN2PostgresContext.EN2PostgresContext _context;
private readonly EnumMappingService _enumMappingService;

public {ModelName}Controller(EN2PostgresContext.EN2PostgresContext context, EnumMappingService enumMappingService)
{
_context = context;
_enumMappingService = enumMappingService;
}

// Get network defaults
[HttpGet("defaults")]
public async Task<ActionResult<{ModelName}ResponseDto>> GetDefaults()
{
var defaults = await _context.{ModelName}s
.Where(x => x.ScenarioId == null)
.FirstOrDefaultAsync();
// Implementation
}

// Get effective settings for scenario (with fallback to defaults)
[HttpGet("scenario/{scenarioId}")]
public async Task<ActionResult<{ModelName}ResponseDto>> GetForScenario(int scenarioId)
{
// Try scenario-specific first
var scenario = await _context.{ModelName}s
.Where(x => x.ScenarioId == scenarioId)
.FirstOrDefaultAsync();

if (scenario != null) return Ok(scenario);

// Fall back to network defaults
var defaults = await _context.{ModelName}s
.Where(x => x.ScenarioId == null)
.FirstOrDefaultAsync();

return Ok(defaults);
}

// Create scenario-specific override
[HttpPost("scenario/{scenarioId}")]
public async Task<ActionResult<{ModelName}ResponseDto>> CreateScenarioOverride(int scenarioId, [FromBody] {ModelName}RequestDto request)
{
// Implementation - set ScenarioId = scenarioId
}

// Update scenario-specific override
[HttpPut("scenario/{scenarioId}")]
public async Task<IActionResult> UpdateScenarioOverride(int scenarioId, [FromBody] {ModelName}RequestDto request)
{
// Implementation
}

// Delete scenario-specific override
[HttpDelete("scenario/{scenarioId}")]
public async Task<IActionResult> DeleteScenarioOverride(int scenarioId)
{
// Implementation - delete scenario-specific record, fall back to defaults
}
}

DTO Structure Template

public class {ModelName}ResponseDto
{
public string Id { get; set; } = string.Empty;
// Model-specific properties
public string? DisplayValue { get; set; } // For enums
public DateTime CreatedAt { get; set; }
public DateTime? ModifiedAt { get; set; }
}

public class {ModelName}RequestDto
{
public string Id { get; set; } = string.Empty;
// Model-specific properties for creation/update
}

Key Considerations

1. Model Types Classification

  • Network-Based Models: Pattern, DataCurve, Demand, Source, Reaction, TankMixing, Emitter, Leakage, Quality, Status
  • Scenario-Based Models with Network Defaults: TimeParameters, Options, Energy, Report
  • List Models: Demand, Source, Reaction, Emitter, Leakage, Status

2. Relationship Handling

  • Scenario-based models: Use nullable ScenarioId for network defaults with scenario overrides
  • Network-based models: No ScenarioId needed, tied to network elements (JunctionId, NodeId, etc.)
  • Navigation properties should be included in queries where beneficial

3. Array Data Handling

  • Pattern.Multipliers and DataCurve.XValues/YValues are stored as PostgreSQL arrays
  • Consider special endpoints for array manipulation if needed

4. Enum Display Values

  • Use EnumMappingService for consistent enum display values
  • Follow existing patterns from current controllers

5. Error Handling

  • Implement consistent error handling across all controllers
  • Return appropriate HTTP status codes
  • Include meaningful error messages

6. Validation

  • Add model validation attributes where appropriate
  • Implement business logic validation in controllers

Testing Strategy

  1. Unit Tests: Test individual controller methods
  2. Integration Tests: Test full CRUD operations
  3. API Tests: Test endpoints with various scenarios
  4. Data Validation: Test with valid and invalid data

Documentation

  1. Update API documentation for new endpoints
  2. Add Swagger/OpenAPI annotations
  3. Include example requests and responses
  4. Document special features and limitations

Timeline

  • Phase 1: Database Context Updates (1 day)
  • Phase 2: DTO Creation (1 day)
  • Phase 3: Controller Implementation (3-4 days)
  • Phase 4: Special Endpoints (1 day)
  • Testing & Documentation: (1-2 days)

Total Estimated Time: 7-9 days

Success Criteria

  1. All 14 controllers implemented with full CRUD operations
  2. LIST endpoints implemented for appropriate models
  3. Consistent API design following existing patterns
  4. Proper error handling and validation
  5. Complete test coverage
  6. Updated documentation
  7. All endpoints working correctly with the database