Skip to main content

NetworkManager Fixes - History

Component: NetworkManager Period: October 2025 Status: All Fixes Implemented and Verified Purpose: Document critical fixes and improvements


Table of Contents​

  1. Database Upsert Fixes
  2. Default Value Filtering
  3. Property Processing Fixes
  4. Code Quality Improvements

1. Database Upsert Fixes​

1.1 Node Coordinates Update (CRITICAL) 🔴​

Severity: CRITICAL - Data Corruption Status: ✅ FIXED

Problem: Update() methods for Junction, Tank, and Reservoir were missing updates to XCoord and YCoord properties. These properties are defined in the Node base class, but update methods only updated entity-specific properties. Node coordinates would NEVER update after initial import!

Impact:

  • ❌ Visualization showed wrong locations
  • ❌ Geometry calculations incorrect
  • ❌ Spatial queries failed
  • ❌ Re-import didn't fix coordinates

Solution:

// Added to Junction.Update(), Tank.Update(), Reservoir.Update()
public void Update(Junction other)
{
// Base class properties
this.XCoord = other.XCoord; // ✅ ADDED
this.YCoord = other.YCoord; // ✅ ADDED

// Entity-specific properties
this.Elevation = other.Elevation;
this.BaseDemand = other.BaseDemand;
// ...
}

Files Modified:

  • efcorelibraries/HTModels/Models/EN2Models/Junction.cs
  • efcorelibraries/HTModels/Models/EN2Models/Tank.cs
  • efcorelibraries/HTModels/Models/EN2Models/Reservoir.cs

Result: ✅ Node coordinates now properly sync on every import


1.2 LinkVertex Composite Key Issue (CRITICAL) 🔴​

Severity: CRITICAL - Orphaned Data Status: ✅ FIXED

Problem: Vertices have composite primary key (LinkId, Sequence) but no auto-increment Id. GenericEntityProcessor couldn't properly find existing vertices, and removed vertices from INP file would persist in database.

Impact:

  • ❌ Deleted vertices remained in database
  • ❌ Modified vertices duplicated
  • ❌ Geometry became corrupted over time

Solution: Implemented delete-and-reinsert strategy per link:

// Delete all vertices for this link
var existingVertices = await context.LinkVertices
.Where(v => v.LinkId == linkId)
.ToListAsync();
context.LinkVertices.RemoveRange(existingVertices);

// Insert fresh vertices from INP
foreach (var vertex in newVertices)
{
context.LinkVertices.Add(vertex);
}

Files Modified:

  • epanetconsolecore/NetworkManager/Parsers/LinkSectionParser.cs

Result: ✅ Vertices now properly sync with INP file on every run


1.3 DataCurve Array Update​

Severity: MEDIUM Status: ✅ FIXED

Problem: DataCurve stores X/Y values in PostgreSQL array columns (float8[]). Array replacement might not be properly detected by EF Core's change tracking.

Solution:

private void UpdateEntity(DataCurve existingCurve, DataCurve newCurve)
{
// Explicitly replace arrays
existingCurve.XValues = newCurve.XValues;
existingCurve.YValues = newCurve.YValues;
existingCurve.CurveType = newCurve.CurveType;
existingCurve.ModifiedAt = DateTime.UtcNow;
}

Result: ✅ Curves update correctly when data points change


1.4 DataPattern Array Update​

Severity: MEDIUM Status: ✅ FIXED

Problem: Pattern stores multipliers in PostgreSQL array column. Same array tracking issue as DataCurve.

Solution:

private void UpdateEntity(DataPattern existingPattern, DataPattern newPattern)
{
existingPattern.Multipliers = newPattern.Multipliers;
existingPattern.Description = newPattern.Description;
existingPattern.ModifiedAt = DateTime.UtcNow;
}

Result: ✅ Patterns update correctly when multipliers change


2. Default Value Filtering​

2.1 Database Bloat Problem​

Severity: MEDIUM - Performance Status: ✅ FIXED

Problem: LinkProperty and NodeProperty tables filled with default values (zeros and ones):

  • 90%+ entries were defaults
  • Database bloat and performance overhead
  • Confusion about explicit vs default values

Solution: Created EpanetPropertyDefaults service class:

public static class EpanetPropertyDefaults
{
public static readonly Dictionary<int, double> LinkDefaults = new()
{
{ (int)EN_LinkProperty.EN_KWALL, 0.0 },
{ (int)EN_LinkProperty.EN_LEAK_AREA, 0.0 },
{ (int)EN_LinkProperty.EN_INITSTATUS, 1.0 }, // OPEN
{ (int)EN_LinkProperty.EN_PUMP_HCURVE, 0.0 },
// ... complete lookup
};

public static bool IsDefaultLinkValue(int propertyId, double value)
{
return LinkDefaults.TryGetValue(propertyId, out var defaultVal)
&& Math.Abs(value - defaultVal) < 1e-10;
}
}

Usage Pattern:

// Only insert if NOT default
if (!EpanetPropertyDefaults.IsDefaultLinkValue(propertyId, value))
{
linkProperties.Add(new LinkProperty(linkId, propertyId, value));
}

Files Modified:

  • Services/EpanetPropertyDefaults.cs (NEW)
  • Builders/EN2LinkBuilder.cs
  • Builders/EN2NodeBuilder.cs
  • All section parsers

Result: ✅ 90% reduction in LinkProperty/NodeProperty entries ✅ Database significantly leaner ✅ Clear distinction between explicit and default values


3. Property Processing Fixes​

3.1 Section Parser Default Filtering​

Severity: MEDIUM Status: ✅ FIXED

Problem: Section parsers inserted ALL values, even defaults:

  • QualitySectionParser - inserted INITQUAL=0 for ALL nodes
  • StatusSectionParser - inserted INITSTATUS=1 (OPEN) for ALL links

Solution: Added default filtering to both parsers:

QualitySectionParser (AFTER):

var initialQuality = epanetWrapper.GetNodeInitQual(i);

// Only create if NOT default (0)
if (!EpanetPropertyDefaults.IsDefaultNodeValue((int)EN_NodeProperty.EN_INITQUAL, initialQuality))
{
var qualityProperty = new NodeProperty(nodeId, (int)EN_NodeProperty.EN_INITQUAL, initialQuality);
nodeProperties.Add(qualityProperty);
}

StatusSectionParser (AFTER):

var initStatus = epanetWrapper.GetInitStatus(i);
var statusValue = ConvertStatusToNumeric(initStatus);

// Only create if NOT default (1=OPEN)
if (!EpanetPropertyDefaults.IsDefaultLinkValue((int)EN_LinkProperty.EN_INITSTATUS, statusValue))
{
var statusProperty = new LinkProperty(linkId, (int)EN_LinkProperty.EN_INITSTATUS, statusValue);
linkProperties.Add(statusProperty);
}

Result: ✅ Only non-default status and quality values stored


3.2 EN_STATUS vs EN_INITSTATUS (CRITICAL)​

Severity: CRITICAL - Wrong Data Stored Status: ✅ FIXED

Problem: StatusSectionParser used EN_STATUS (11) instead of EN_INITSTATUS (4).

Critical Distinction:

  • EN_INITSTATUS (4): User configuration - Initial status before simulation ✅ Store this
  • EN_STATUS (11): Simulation result - Current status during/after simulation ❌ Don't store this

Analogy:

  • EN_INITSTATUS = "thermostat setting" (configuration)
  • EN_STATUS = "current temperature" (runtime measurement)

Solution:

// BEFORE (WRONG):
new LinkProperty(linkId, (int)EN_LinkProperty.EN_STATUS, statusValue); // ❌

// AFTER (CORRECT):
new LinkProperty(linkId, (int)EN_LinkProperty.EN_INITSTATUS, statusValue); // ✅

Result: ✅ Correct property stored in database


3.3 Parser Entity Processor Fix​

Severity: MEDIUM Status: ✅ FIXED

Problem: GenericEntityProcessor had issues with:

  • Composite primary keys
  • Array property updates
  • Entity relationship handling

Solution:

  • Enhanced UpdateEntity methods for array properties
  • Implemented delete-reinsert for composite keys
  • Improved change tracking

Result: ✅ All entity types update correctly


3.4 Duplicate Metric Resolution​

Severity: LOW Status: ✅ FIXED

Problem: Metric seeding created duplicate entries due to lack of unique constraints.

Solution:

  • Added unique index on metric name
  • Check for existing before insert
  • Proper error handling

Result: ✅ No duplicate metrics in database


4. Code Quality Improvements​

4.1 Architecture Refactoring​

Before: Monolithic parsing in main method After: Section-based architecture with individual parsers

Benefits:

  • ✅ Easier to maintain
  • ✅ Easier to extend
  • ✅ Better separation of concerns
  • ✅ Reusable components

4.2 Standardization​

Default Value Handling:

  • ✅ Single source of truth (EpanetPropertyDefaults)
  • ✅ Consistent across all parsers
  • ✅ Well-documented defaults

Error Handling:

  • ✅ Consistent logging
  • ✅ Proper exception management
  • ✅ User-friendly error messages

Summary​

Total Fixes: 10+ critical and medium severity issues

Categories:

  • 🔴 Critical Fixes: 3 (Node coordinates, LinkVertex, EN_STATUS)
  • 🟡 Medium Fixes: 5 (Array updates, default filtering)
  • 🟢 Improvements: Multiple (code quality, architecture)

Impact:

  • ✅ Data integrity restored
  • ✅ Coordinates sync correctly
  • ✅ Vertices update properly
  • ✅ Database bloat eliminated
  • ✅ Correct properties stored
  • ✅ Better code maintainability

Result: Production-ready NetworkManager with reliable parsing, proper data handling, and maintainable architecture.


Related Documentation:

  • Architecture: NETWORKMANAGER_ARCHITECTURE.md
  • Reference: NetworkManager-Reference.md
  • Design Specs: NetworkManager-design-specs.md

Status: ✅ All Fixes Implemented Last Updated: October 2025