Commit 45391341 authored by Salko Jr, Robert's avatar Salko Jr, Robert
Browse files

Add ability to set axial variation tables

parent 1cf7bf8d
Loading
Loading
Loading
Loading
+124 −0
Original line number Diff line number Diff line
@@ -66,6 +66,20 @@ class Model:
        # which will either be the axial location or the power factor, depending on which dictionary it is.
        me.axialPowerShapeAxial = {}
        me.axialPowerShapePower = {}
        # Axial geometry modification tables.  Of the form {ID: {'axial': [a1, a2, ...], 'mult': [m1, m2, ...]}}
        # Here ID is an ID for the table, the 'axial' list gives the axial level locations, and the 'mult' list
        # gives the multipliers for each level
        me.axialGeoShape = {}
        # Links the axial geometry modification tables to channels in the model.  Of the form:
        # {chID: {'tables': [tab1, tab2, ...], 'aspects': [[aspect1], [aspect1, aspect2]]}}
        # A single channel may have multiple geometry modification tables applied to it, with each table applying
        # to multiple aspects of the geometry (momentum area, scalar area, wetted perimeter).
        me.channelGeoTables = {}
        # Links the axial geometry modification tables to gaps in the model.  A gap can only have one
        # table applied, so the form is:
        # {gapID: tab1}
        # A geometry modification table can only apply to gap width.
        me.gapGeoTables = {}
        # List of FormLoss objects in the model
        me.formLosses = []
        # Same size as formLosses.  Gives the channel ID of the loss
@@ -1079,6 +1093,84 @@ class Model:
        me.axialPowerShapeAxial[time][powID] = axial
        me.axialPowerShapePower[time][powID] = power

    def addAxialGeoShape(me, ID, axialLevels, multipliers):
        """
        Add a axially-dependent geometry modification table to the model

        This will specify a list of multipliers to be applied at axial levels specified in the
        axialLevels list.  The axial levels shall be integer level indices.  The meaning of the node
        (momentum level or scalar level) depends on how the table is applied.  If the table is applied
        to momentum cell area, it will mean momentum level and if it is applied to scalar cell area, wetted
        perimeter, or gap width, it will mean scalar level.

        It is important to consider how CTF will apply these tables.  A linear interpolation is done
        between points in the table to determine the local multiplier.  For example, for the following table:

        1 0.5
        3 0.7
        4 0.8
        8 0.8

        The multiplier that will be applied to level 2 will be 0.6.  However, if adjacent levels are
        specified, as in the case of 3 and 4 in the table, then no interpolation can be done.  In this
        case, the 0.7 multiplier will be applied to Level 3 and 0.8 will be applied to Level 4.  If
        the user desires no interpolation, then each region must be "capped", as in the case of Levels
        4 to 8.  In this case, each level will have a value of 0.8 applied.  Furthermore, the bottom and
        top of the model should be included in the table to ensure all multipliers are defined.

        Args:
           ID (int): Identifier for the table
           axialLevels (list): List of integer node levels
           multipliers (list): List of float multiplier values
        """
        assert isinstance(ID, int)
        assert ID>0
        assert len(axialLevels)==len(multipliers)
        assert all(multipliers)>0.0
        assert ID not in me.axialGeoShape
        me.axialGeoShape[ID] = {'axial': axialLevels, 'mult': multipliers}

    def assignTableToChannel(me, tableID, chID, applies):
        """ Use this procedure to assign a geometry modification table to a channel in the model.

        The tableID must match a table ID that was defined using the :meth:`addAxialGeoTable` procedure.
        The chID must match a channel ID that was defined using the :meth:`addChannel` procedure.
        The `applies` input is a list of geometry aspects to which the table shall apply.
        The `applies` list can include "momentum", "scalar", and "pw", which represent the momentum
        cell areas, scalar cell areas, and wetted perimeter.

        Args:
           tableID (choice): ID of previously defined axial geometry table
           chID (int): ID of previously defined channel
           applies (list or str):  Can provide a single string value or list of strings to define
              which aspects of the geometry this table shall apply
        """
        if chID not in me.channelGeoTables:
            me.channelGeoTables[chID] = {'tables': [], 'aspects': []}
        me.channelGeoTables[chID]['tables'].append(tableID)
        validApplies = ['momentum', 'scalar', 'pw']
        if not isinstance(applies, list):
            ls = [applies]
            assert applies in validApplies
        else:
            ls = applies
            for val in applies:
                assert val in validApplies
        me.channelGeoTables[chID]['aspects'].append(ls)

    def assignTableToGap(me, tableID, gapID):
        """ Assigns a geometry modification table to a gap in the model

        The axial geometry modification table assigned to tableID and defined with :meth:`addAxialGeoTable`
        will be assigned to the specified gapID.  The table multipliers will operate on the gap width.

        Args:
           tableID (choice): ID of previously defined geometry modification table
           gapID (int): ID of gap defined by :meth:`setGap` procedure
        """
        assert gapID not in me.gapGeoTables
        me.gapGeoTables[gapID] = tableID

    def addTransientGroup(me, tEnd, editInterval=None, dtMin=None, dtMax=None):
        """
        Adds a transient group to the simulation
@@ -1573,6 +1665,8 @@ class Model:

        me._validateBoundaryConditions()

        me._validateGeoTables()

        # Add a uniform power profile that covers the entire model so it can be assigned to rods
        # that had now power shape assigned
        if me._anyRodsWithoutPowerID():
@@ -2088,6 +2182,36 @@ class Model:
                    raise RuntimeError("For solidID: " + str(solidID) + " in Section: " + str(
                        u) + " percentages of connected channels add up to " + str(totPercent) + " instead of 1.0")

    def _validateGeoTables(me):
        """ Ensure all geometry tables applied to model objects were defined and that they were all assigned
        to objects that exist in the model.
        """
        # Ensure axial geo table IDs are sequential
        ID = 1
        for key in sorted(me.axialGeoShape.keys()):
            if key!=ID:
                raise RuntimeError("Axial geometry table IDs must be sequential starting at 1.")
            ID=ID+1
        for chID in me.channelGeoTables.keys():
            foundChannel = False
            for section in me.sections.keys():
                if chID in me.sections[section].channels.keys():
                    foundChannel = True
            if not foundChannel:
                raise RuntimeError("Geometry table ID: "+str(me.channelGeoTables[chID]['tables'][0])+
                        " assigned to non-existent channel: "+str(chID))
            for tableID in me.channelGeoTables[chID]['tables']:
                if tableID not in me.axialGeoShape:
                    raise RuntimeError("Geometry table ID: "+str(tableID)+" was not defined, but is trying "+
                            "to be applied to channel: "+str(chID))
        for gapID in me.gapGeoTables.keys():
            if gapID not in me.gaps:
                raise RuntimeError("Geometry table ID: "+str(me.gapGeoTables[gapID])+" attempting to be applied"+
                        " to non-existent gap: "+str(gapID))
            if tableID not in me.axialGeoShape:
                raise RuntimeError("Geometry table ID: "+str(tableID)+" was not defined, but is trying "+
                         "to be applied to gap: "+str(gapID))


class Gap(object):
    """ Defines a gap (a lateral connection between two channels in the same axial section)
+64 −0
Original line number Diff line number Diff line
@@ -295,6 +295,60 @@ def writeDeck(model, filename):
    group4Data.append("**  MSIM\n")
    group4Data.append("{0:8d}\n".format(model._getNCELLS()))

    group5Data = []
    group6Data = []
    if len(model.gapGeoTables)>0 or len(model.channelGeoTables)>0:
        group5Data.append("**NGR\n5\n")
        group5Data.append("*Card 5.1\n")
        maxLen = 0
        for key in model.axialGeoShape.keys():
            maxLen = max(maxLen, len(model.axialGeoShape[key]['axial']))
        group5Data.append("** NAFACT   NAXL\n")
        group5Data.append("{:9d}{:7d} 0 0 0 0 0 0 0 0 0 0 0 0\n".format(len(model.axialGeoShape.keys()), maxLen))
        group5Data.append("**Card 5.2\n")
        for key in sorted(model.axialGeoShape.keys()):
            line = ""
            for i in range(len(model.axialGeoShape[key]['axial'])):
                line = line+"{:5d}{:16.4e}".format(model.axialGeoShape[key]['axial'][i],
                        model.axialGeoShape[key]['mult'][i])
            # Pad the rest with zeros if this table is shorter than max
            for i in range(len(model.axialGeoShape[key]['axial']), maxLen):
                line = line+"{:5d}{:16.4e}".format(0, 0.0)
            group5Data.append(line+"\n")

        group6Data.append("**NGR\n6\n")
        group6Data.append("*Card 6.1\n")
        group6Data.append("**   N1\n")
        group6Data.append("{:7d} 0 0 0 0 0 0 0 0 0 0 0 0 0\n".format(len(model.channelGeoTables.keys())+
            len(model.gapGeoTables.keys())))
        group6Data.append("*Card 6.2\n")
        group6Data.append("** IACT   IAMT   IPWT   ICRG\n")
        def getMom(channelGeoTables):
            """ Takes the channelGeoTables entry for chID and returns the flag for IAMT in the CTF input deck."""
            for i, tableID in enumerate(channelGeoTables['tables']):
                if 'momentum' in channelGeoTables['aspects'][i]:
                    return tableID
            return 0
        def getScal(channelGeoTables):
            """ Takes the channelGeoTables entry for chID and returns the flag for IACT in the CTF input deck."""
            for i, tableID in enumerate(channelGeoTables['tables']):
                if 'scalar' in channelGeoTables['aspects'][i]:
                    return tableID
            return 0
        def getPw(channelGeoTables):
            """ Takes the channelGeoTables entry for chID and returns the flag for IPWT in the CTF input deck."""
            for i, tableID in enumerate(channelGeoTables['tables']):
                if 'pw' in channelGeoTables['aspects'][i]:
                    return tableID
            return 0
        for chID in sorted(model.channelGeoTables.keys()):
            group6Data.append("{:7d}{:7d}{:7d}{:7d} 0 0 0 0 0 0 0 0 0 0 0\n".format(getScal(model.channelGeoTables[chID]),
                getMom(model.channelGeoTables[chID]), getPw(model.channelGeoTables[chID]), chID))
        for gapID in sorted(model.gapGeoTables.keys()):
            group6Data.append("{:7d}{:7d}{:7d}{:7d} 0 0 0 0 0 0 0 0 0 0 0\n".format(-model.gapGeoTables[gapID], 0, 0,
                gapID))


    group7Data = []
    group7Data.append("**NGR\n")
    group7Data.append("    7\n")
@@ -995,6 +1049,16 @@ def writeDeck(model, filename):
        "GROUP 4 - Vertical Channel Connection Data"))
    for l in group4Data:
        newDeckLines.append(l)
    if len(group5Data)>0:
        newDeckLines.append(makeGroupBanner(
            "GROUP 5 - Axial Geometry Variation Tables"))
        for l in group5Data:
            newDeckLines.append(l)
    if len(group6Data)>0:
        newDeckLines.append(makeGroupBanner(
            "GROUP 6 - Channel/Gap Variation Table Application"))
        for l in group6Data:
            newDeckLines.append(l)
    newDeckLines.append(makeGroupBanner(
        "GROUP 7 - Grid Loss Coefficient Data"))
    for l in group7Data:
+255 −0
Original line number Diff line number Diff line
***********************************************************************************************
*MAIN CONTROL DATA
***********************************************************************************************
*ICOBRA
      1
*INITIAL   DUMPF
       1       0
**    EPSO    OITMAX    IITMAX   COURANT
  1e-4             5       200  0.800000
*TITLE
ctf model
***********************************************************************************************
*GROUP 1 - Calculation Variables and Initial Conditions
***********************************************************************************************
**NGR
   1
**NGAS IRFC EDMD IMIX ISOL          GINIT NOTRN MESH MAPS IPRP MFLX IBTM PPV  NM14
     1    2    0    3    0    1.70995e+02     1    1    0   11    0    0   7     0
*Card 1.2
**         GTOT          AFLUX         DHFRAC
      170.99460       69.79200        0.97629
*Card 1.3
**         PREF            HIN           HGIN         VFRAC1         VFRAC2
        3.44738     -908.15000 288.4200000      1.0000000      0.9999000
*Card 1.4
**GTP(1)   VFRAC(3)  GTP(2) VFRAC(4)  GTP(3) VFRAC(5)  GTP(4) VFRAC(6)
     air     0.0001
***********************************************************************************************
*GROUP 2 - Channel Description
***********************************************************************************************
**NGR
    2
*Card 2.1
**  NCH NDM2 NDM3 NDM4 NDM5 NDM6 NDM7 NDM8 NDM9 NM10 NM11 NM12 NM13 NM14
   1    0    0    0    0    0    0    0    0    0    0    0    0    0
*Card 2.2
**   I          AN          PW ABOT ATOP NMGP           X           Y        XSIZ        YSIZ
     1  1.6360e-01  4.1286e+01  0.0  0.0    0  0.0000e+00  0.0000e+00  0.0000e+00  0.0000e+00
***********************************************************************************************
*GROUP 4 - Vertical Channel Connection Data
***********************************************************************************************
**NGR
    4
*Card 4.1
**NSEC NSIM IREB NDM4 NDM5 NDM6 NDM7 NDM8 NDM9 NM10 NM11 NM12 NM13 NM14
     1    1    0    0    0    0    0    0    0    0    0    0    0    0    0
*Card 4.2
**ISEC    NCHN  NONO         DXS     IVAR
     1         1    20  1.0160e-01          0
*Card 4.4
**    I   NCHA  KCHA(:)    NCHB  KCHB(:)
      1      0
             0
*Card4.5
**  IWDE
       1
*Card 4.6
**  MSIM
      20
***********************************************************************************************
*GROUP 7 - Grid Loss Coefficient Data
***********************************************************************************************
**NGR
    7
*Card 7.1
**  NCD NGT  IFGQF IFSDRP  IFESPV  IFTPE  IGTEMP  NFBS  NDM9 NDM10 NDM11 NDM12 NDM13 NDM14
      0   0      0      0       0      0       0     0     0     0     0     0     0     0
*Card 7.2
**   CDL    J   CD1   CD2   CD3   CD4   CD5   CD6   CD7   CD8   CD9  CD10  CD11  CD12
***********************************************************************************************
*GROUP 8 - Rod and Unheated Conductor Data
***********************************************************************************************
**NGR
    8
*Card 8.1
** NRRD   NSRD    NC  NRTB  NRAD  NLTY  NSTA   NXF  NCAN  RADF    W3 IHTC  DNBCHK NDM14
      1      0     1     1     0     0     1     1     0     0    -1     1     1     0
*Card 8.2
**    N   IFTY   IAXP   NRND DAXMIN       RMULT         HGAP  ISECR       HTAMB        TAMB  SYMROD  HTCMAP TKEMAP NSUBAX NSUBAZ
*Card 8.3
**NSCH   PIE  NSCH   PIE  NSCH   PIE  NSCH   PIE  NSCH   PIE  NSCH   PIE  NSCH   PIE NSCH   PIE
      1      1      1      0       0  5.6900e+02  0.0000e+00      1  0.0000e+00  0.0000e+00    1.000      0      0      1      1
     1 1.000     0 0.000     0 0.000     0 0.000     0 0.000     0 0.000     0 0.000     0 0.000
*Card 8.5
**    N   ISTYP      HPERIM     HPERIMI       RMULS  NOSLCH  NSLCHC       HTAMBS        TAMBS
*Card 8.6
**    I   NRT1   NST1   NRX1
      1      1      0      2
*Card 8.7
**IRTB1  IRTB2  IRTB3  IRTB4  IRTB5  IRTB6  IRTB7  IRTB8  IRTB9 IRTB10 IRTB11 IRTB12
      1
*Card 8.8
**ISTB1  ISTB2  ISTB3  ISTB4  ISTB5  ISTB6  ISTB7  ISTB8  ISTB9 ISTB10 ISTB11 ISTB12
*Card 8.9
**    AXIALT      TRINIT
 0.00000e+00 9.08150e+02
 2.03200e+00 9.08150e+02
***********************************************************************************************
*GROUP 9 - Conductor Geometry Description
***********************************************************************************************
**NGR
    9
*Card 9.1
** NFLT IRLF ICNF IMWR ISWL IDNS IRLG CREEP NDM9 NM10 NM11 NM12 NM13 NM14
      1   -1   -1   -1   -1   -1   -1   -1    0    0    0    0    0    0
*Card 9.6
**  I FTYP           DROD            DIN   NFUL IMTF IMTC DUM8 DUM9  DUM10  DUM11  DUM12  DUM13  DUM14  EPSO
    1 hrod   5.053314e-02    0.00000e+00      1    0    0    0   0       0     0     0      0    0    0.0
*Card 9.7
** NODER  MATR          TREG   QREG
       3     1  2.526657e-02  1.0
***********************************************************************************************
*GROUP 10 - Material Properties Tables
***********************************************************************************************
*NGRP
   10
*NMAT NDM2 NDM3 NDM4 NDM5 NDM6 NDM7 NDM8 NDM9 NM10 NM11 NM12 NM13 NM14
     1    0    0    0    0    0    0    0    0    0    0    0    0    0
*   N NTDP     RCOLD              IMATAN
     1   20  1740.000            graphite
*    TPROP      CPF1      THCF
    250.00    0.5948  177.6810
    337.50    0.8370  155.8017
    425.00    1.0473  138.9136
    512.50    1.2283  125.4402
    600.00    1.3823  114.4129
    687.50    1.5118  105.2023
    775.00    1.6192   97.3804
    862.50    1.7069   90.6458
    950.00    1.7775   84.7795
   1037.50    1.8332   79.6184
   1125.00    1.8766   75.0385
   1212.50    1.9101   70.9437
   1300.00    1.9361   67.2582
   1387.50    1.9570   63.9215
   1475.00    1.9753   60.8846
   1562.50    1.9934   58.1076
   1650.00    2.0137   55.5572
   1737.50    2.0387   53.2058
   1825.00    2.0708   51.0303
   1912.50    2.1124   49.0109
*
***********************************************************************************************
*GROUP 11 - Core Power Distribution Information
***********************************************************************************************
*NGR group number
   11
**Card 11.1
* NQA  NAXP  MNXN    NQ NGPFF   NQR  NDM7  NDM8  NDM9 NDM10 NDM11 NDM12 NDM13 NDM14
    1     1     2     0     0     1     0     0     0     0     0     0     0     0
**Card 11.2
*           YQA
    0.00000e+00
**Card 11.3
*     I   NAXN
      1      2
**Card 11.4
*             Y         AXIALZ
    0.00000e+00    1.00000e+00
    2.03200e+00    1.00000e+00
**Radial power profile forcing function
**Card 11.7
*          YQR
    0.00000E+00
**Card 11.8
*    FQR1      FQR2      FQR3      FQR4      FQR5      FQR6      FQR7      FQR8
   1.00000
***********************************************************************************************
*GROUP 12 - Turbulent Mixing and Void Drift Data
***********************************************************************************************
**NGR
   12
*Card 12.2
**    AAAK      BETA     THETM
 0.140E+01 3.700e-02 0.500E+01
***********************************************************************************************
*GROUP 13 -  Boundary Condition Data
***********************************************************************************************
*NGR group number
   13
**Card 13.1
* NBND   NKBD NFUN NGBD VBC  NDM6 NDM7 NDM8 NDM9 NM10 NM11 NM12 NM13 NM14
     2      0    0    0  0    0    0    0    0    0    0    0    0    0
*Card 13.2
** NPTS
*Card 13.3
**Card 13.4
* IBD1   IBD2 ISPC N1FN N2FN N3FN     BCVALUE1     BCVALUE2     BCVALUE3 INITGAS
     1      1    2    0    0    0  1.70995e+02 -9.08150e+02  0.00000e+00       1
     1     22    1    0    0    0  0.00000e+00 -9.08150e+02  3.44738e+00       1
***********************************************************************************************
*GROUP 14 - Output Options
***********************************************************************************************
**NGR
  -14
**               KEY     VALUE
           rod_edits         0
             rod_vtk         0
         native_hdf5         1
           fluid_vtk         0
           dnb_edits         0
          chan_edits         0
                hdf5         0
         convergence         1
           gap_edits         0
end 14
***********************************************************************************************
*GROUP 15 - Time Domain Data
***********************************************************************************************
**NGR
   15
*Card 15.1
**        DTMIN          DTMAX           TEND          EDINT         DMPINT          RTWFP     MAXITS
    1.00000e-06    1.00000e-01     1.0000E-01  0.0000E+00  0.0000E+00     1.000000e+02      10000
***********************************************************************************************
*GROUP 19 - convergence Criteria for Steady State Solve
***********************************************************************************************
**NGR
   19
** Normalized l-infinity of checked solution terms must go below these tolerances for the case
** to be considered steady state.  The code converges if the following is true for each checked
** solution term:
**
**   abs((X-Xn))<=max(rtol*abs(Xn),atol)
**
** In this equation, 'X' is a vector of the checked solution terms from the current checkpoint
** and 'Xn' is the vector of the same solution terms, but from the previous checkpoint.  Checks
** are made every 0.05 seconds in the transient.  The relative tolerances are defined on Card
** 19.1 and the absolute tolerances are defined on Card 19.2.  This check is done for pressure,
** fluid temperature, solid temperature, and the three components of axial velocity.  There is
** also a check on void, but it does not invole the relative check because void is a
** dimensionless value; only the absolute check is done.
**
** The final check involves checking that the mass and energy balance over the system is below
** a tolerance as well.
** Balance of mass ((mass_in-mass_out)/mass_in) and balance of energy ((energy_in-energy_out)/
** energy_in) must go below tolerance values defined on Card 19.3 for case to be considered
** steady state.
*Card 19.1 - relative stopping criteria [unitless]
** LIPRESS   LITCOOL  LITSOLID      LIVL      LIVV      LIVD
 1.000e-03 1.000e-03 1.000e-03 1.000e-03 1.000e-03 1.000e-03
*Card 19.2 - absolute stopping criteria [pressure in psia|bar, velocity in ft/s|m/s,
** and temperature in F|C]
** LIAVOID  LIAPRESS  LIATCOOL LIATSOLID     LIAVL     LIAVV     LIAVD
 1.000e-04 1.000e-04 1.000e-04 1.000e-04 1.000e-04 1.000e-04 1.000e-04
*Card 19.2   [%]
** ENERGYBAL     MASSBAL
   1.000000e-01   1.000000e-01
*Card 19.4   [%]
** L2PRESS   L2TCOOL  L2TSOLID      L2VL      L2VV      L2VD
*Card 19.5 - absolute stopping criteria [pressure in psia|bar, velocity in ft/s|m/s,
 1.000e-04 1.000e-04 1.000e-04 1.000e-04 1.000e-04 1.000e-04
** and temperature in F|C]
** L2AVOID  L2APRESS  L2ATCOOL L2ATSOLID     L2AVL     L2AVV     L2AVD
 1.000e-04 1.000e-04 1.000e-04 1.000e-04 1.000e-04 1.000e-04 1.000e-04
+61 −0

File added.

Preview size limit exceeded, changes collapsed.

+1 −0
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ runScriptTest "scriptRegression/case1" "make_deck.py" "$rebaseline"
runScriptTest "scriptRegression/case2" "make_deck.py" "$rebaseline"
runScriptTest "scriptRegression/case3" "make_deck.py" "$rebaseline"
runScriptTest "scriptRegression/case4" "make_deck.py" "$rebaseline"
runScriptTest "scriptRegression/case5" "make_deck.py" "$rebaseline"

# Put these at the end because they take forever
runScriptTest "mcfr" "coreRegion.py" "$rebaseline"