National Annexes: Structure & Versioning Strategy For Eurocodes

Alex Johnson
-
National Annexes: Structure & Versioning Strategy For Eurocodes

This article discusses the implementation of National Annexes (NA) to Eurocodes within the Blueprints library. National Annexes provide country-specific modifications, additional formulas, and parameter values that deviate from the base Eurocode standards. This article aims to establish a clear strategy for managing these variations effectively.

Context

The primary challenge lies in incorporating country-specific adaptations to Eurocodes while maintaining a clean, efficient, and scalable codebase. Currently, the base Eurocodes are implemented, but National Annexes lack systematic support and a version management strategy. The goal is to define a robust framework that minimizes code duplication and ensures maintainability across multiple countries and versions.

Current Situation

  • Base Eurocodes (e.g., EN 1992-1-1:2004) are implemented in the main eurocode structure.
  • National Annexes are not yet systematically supported.
  • No clear strategy exists for managing multiple versions of National Annexes.

Objectives

  1. Define a clear folder structure for National Annexes.
  2. Establish a strategy for handling multiple versions of the same National Annex.
  3. Minimize code duplication between base norms and National Annexes.
  4. Keep the implementation maintainable for multiple countries.

Proposed Structure

The proposed structure aims to provide a clear and organized approach for managing National Annexes. Here’s one option:

Option 1: Separate national_annex Directory

This option involves creating a separate directory specifically for National Annexes. This approach ensures a clear separation between the base norms and their country-specific adaptations.

blueprints/
└── eurocode/
    ├── en_1992_1_1_2004/
    │   └── chapter_3_materials/
    │       └── formula_3_1.py
    └── national_annex/
        ├── netherlands/
        │   └── nen_en_1992_1_1_2005/
        │       └── chapter_3_materials/
        │       └── formula_3_1.py
        ├── germany/
        │   └── din_en_1992_1_1_2005/
        │   └── chapter_3_materials/
        │       └── formula_3_1.py
        └── belgium/
            └── nbn_en_1992_1_1_2005/
            └── chapter_3_materials/
                └── formula_3_1.py

Pros:

  • Clear separation between base norms and National Annexes, making it easier to differentiate between the core standards and country-specific modifications.
  • Easy to navigate and understand due to the explicit structure that follows a geographical grouping.
  • Follows geographical grouping, which aligns well with the nature of National Annexes.

Cons:

  • Many nested levels could potentially lead to overly deep directory structures, which might complicate maintenance.
  • Potential for deep directory structures, particularly as more countries and versions are added, which could make the codebase harder to manage over time.

Key Decisions Needed

Several critical decisions need to be made to ensure a consistent and maintainable implementation of National Annexes. These decisions cover content strategy, version management, and Eurocode generations.

1. Content Strategy

Agreed: National Annexes should only contain formulas and tables that differ from the base Eurocode, not duplicate everything.

Rationale:

  • Reduces code duplication, making the codebase leaner and easier to manage. By only including what is different, the system avoids unnecessary redundancy.
  • Easier maintenance because changes to the base Eurocode only need to be reflected in the core implementation, and the National Annexes will automatically inherit those changes unless they explicitly override them.
  • Clearer what is actually different per country, which simplifies auditing and ensures that country-specific deviations are easily identifiable.

2. Version Management Strategy

Challenge: National Annexes have multiple versions over time (corrections, updates, etc.).

Managing different versions of National Annexes over time presents a significant challenge. Corrections and updates can lead to multiple versions of the same annex, requiring a robust strategy to handle these variations.

Proposed approach:

  • Implement ONE National Annex per norm per country (latest/most relevant version).
  • Document version information in:
    • Class docstrings
    • Formula documentation
    • Central documentation file per National Annex

Example implementation for a National Annex formula:

class Form3Dot1NLCharacteristicCompressiveStrength(Formula):
    """Class representing NEN-EN 1992-1-1 National Annex formula for Table 3.1.
    
    This is the Dutch National Annex version which modifies the base Eurocode values.
    
    Source: NEN-EN 1992-1-1+C2:2011 - National Annex Table 3.1
    
    Notes
    -----
    This formula is based on NEN-EN 1992-1-1+C2:2011.
    Previous versions (NEN-EN 1992-1-1:2005) may have different values.
    """
    
    label = "3.1 (NL)"
    source_document = NEN_EN_1992_1_1_C2_2011
    
    def __init__(
        self,
        fck: MPa,
    ) -> None:
        """Initialize the formula with Dutch National Annex parameters.
        
        NEN-EN 1992-1-1+C2:2011 - National Annex - Table 3.1
        
        Parameters
        ----------
        fck : MPa
            [$f_{ck}$] Characteristic compressive cylinder strength [MPa].
        """
        super().__init__()
        self.fck = fck
        
    @staticmethod
    def _evaluate(
        fck: MPa,
    ) -> MPa:
        """Evaluates the formula. See __init__ for details."""
        # Dutch-specific calculation or parameter
        return fck * 0.85  # Example
        
    # ... rest of the implementation

Example for modified limit values (like in PR #842):

class Form5Dot1NLCriteriumDisregardSecondOrderEffects(ComparisonFormula):
    """Dutch National Annex version of formula 5.1 with modified limit values.
    
    Source: NEN-EN 1993-1-1+C2:2011 - National Annex
    
    Notes
    -----
    The Dutch National Annex uses different limit values than the base Eurocode:
    - Elastic analysis: 12 (instead of 10)
    - Plastic analysis: 18 (instead of 15)
    """
    
    label = "5.1 (NL)"
    source_document = NEN_EN_1993_1_1_C2_2011
    
    def __init__(
        self, 
        f_cr: N, 
        f_ed: N, 
        analysis_type: Literal["elastic", "plastic"]
    ) -> None:
        """Check if second order effects can be disregarded (Dutch NA version).
        
        NEN-EN 1993-1-1+C2:2011 - National Annex - Formula (5.1)
        
        Parameters
        ----------
        f_cr: N
            [$F_{cr}$] Elastic critical buckling load [N].
        f_ed: N
            [$F_{Ed}$] Design loading on the structure [N].
        analysis_type: Literal["elastic", "plastic"]
            Type of analysis being performed.
        """
        super().__init__()
        self.f_cr = f_cr
        self.f_ed = f_ed
        self.analysis_type = analysis_type

    @staticmethod
    def _limit(analysis_type: Literal["elastic", "plastic"]) -> float:
        """Returns Dutch NA limit values."""
        analysis_type_map = {
            "elastic": 12,   # NL: 12 instead of 10
            "plastic": 18,   # NL: 18 instead of 15
        }
        
        limit = analysis_type_map.get(analysis_type.lower())
        
        if limit is None:
            raise ValueError(
                f"Invalid analysis type: {analysis_type}. "
                "Must be 'elastic' or 'plastic'."
            )
        return limit
        
    # ... rest of implementation similar to base formula

Open question: How do we handle conflicting versions when users combine formulas from different NA versions?

3. Eurocode Generations

Agreed: Distinguish between Generation 1 (current) and Generation 2 (upcoming) Eurocodes, but not between minor corrections within a generation.

Rationale:

  • Prevents version sprawl by focusing on major standard changes rather than minor corrections, keeping the codebase manageable.
  • Supports major standard changes effectively by differentiating between significant Eurocode generations, allowing for future-proof implementation.

Implementation Questions

Several implementation questions need to be addressed to ensure a smooth and consistent integration of National Annexes.

  1. Class naming conventions: Should we use suffixes like NL, DE, BE in class names or rely on import paths?

    # Option A: Suffix in class name
    From5Dot1NLCriteriumDisregardSecondOrderEffects
    
    # Option B: Same name, different import path
    from blueprints.eurocode.national_annex.netherlands.nen_en_1993_1_1_2005 import From5Dot1CriteriumDisregardSecondOrderEffects
    

    Proposed: Use suffix in class name for clarity (Option A)

  2. Documentation: Where should we document which version of the NA is implemented?

    • In each formula class docstring ✓
    • In source_document attribute ✓
  3. Inheritance strategy: Should NA formulas inherit from base Eurocode formulas when only parameters differ?

    # Option A: Full reimplementation
    class Form5Dot1NLCriteriumDisregardSecondOrderEffects(ComparisonFormula):
        # Complete implementation
    
    # Option B: Inherit and override
    class Form5Dot1NLCriteriumDisregardSecondOrderEffects(
        From5Dot1CriteriumDisregardSecondOrderEffects
    ):
        """Dutch NA version with modified limits."""
        
        @staticmethod
        def _limit(analysis_type: Literal["elastic", "plastic"]) -> float:
            """Override with Dutch NA limit values."""
            # Only override what's different
    

    Question: Which approach is cleaner and more maintainable?

  4. Testing: How do we test that NA formulas correctly override or extend base formulas?

  5. API design: How should users import and use National Annex formulas?

    # Explicit import
    from blueprints.eurocode.national_annex.netherlands.nen_en_1993_1_1_2005.chapter_5_structural_analysis import (
        Form5Dot1NLCriteriumDisregardSecondOrderEffects
    )
    
    # Usage
    check = Form5Dot1NLCriteriumDisregardSecondOrderEffects(
        f_cr=1000,
        f_ed=80,
        analysis_type="elastic"
    )
    

References

  • PR #842: First implementation attempt (EN 1993-1-1 Formula 5.1)
  • Discussion in team chat (01-12-2025 - 03-12-2025)

Questions for the team

  1. What do you think about the proposed structure?
  2. Should we go for Option A (suffix in class name) or Option B (inheritance)?
  3. How do we handle formulas that only have parameter changes vs. formulas that are completely different?

Acceptance Criteria

Next Steps

  • [ ] Gather feedback from core team
  • [ ] Make final decision on folder structure
  • [ ] Decide on class naming and inheritance strategy
  • [ ] Create implementation guidelines document
  • [ ] Start with Netherlands (NEN) as pilot implementation
  • [ ] Document versioning strategy in contributing guidelines

Dependencies

No response

Confirmation

  • [x] I have checked that this feature does not already exist in the issue tracker.
  • [x] I have read and understood the contribution guidelines.

For further reading on Eurocodes and National Annexes, consider visiting the European Committee for Standardization (CEN) website.

You may also like