예제 #1
0
class Controller(NumericalModel):
    initialState = F.Choices(
        OrderedDict((
            (TC.FUELING, 'fueling'),
            (TC.EXTRACTION, 'extraction'),
        )),
        label='start with',
        description='start the simulation with fueling or extraction')
    tWaitBeforeExtraction = F.Quantity(
        'Time',
        default=(0., 's'),
        minValue=(0., 's'),
        maxValue=(1.e6, 's'),
        label='&#964 (extraction)',
        description='waiting time before each extraction')
    tWaitBeforeFueling = F.Quantity(
        'Time',
        default=(0., 's'),
        minValue=(0., 's'),
        maxValue=(1.e6, 's'),
        label='&#964 (fueling)',
        description='waiting time before each fueling')
    pMin = F.Quantity(
        'Pressure',
        default=(0., 'bar'),
        label='minimum pressure</sub>',
        description='minimum pressure in the gas storage for starting fueling')
    pMax = F.Quantity(
        'Pressure',
        default=(0., 'bar'),
        label='maximum pressure',
        description='maximum pressure in the gas storage for stopping fueling')
    mDotExtr = F.Quantity('MassFlowRate',
                          default=(0., 'kg/h'),
                          label='extraction mass flow rate',
                          description='extraction mass flow rate')
    nCompressor = F.Quantity('AngularVelocity',
                             default=(0., 'rev/s'),
                             minValue=(0, 'rev/s'),
                             maxValue=(1e4, 'rev/s'),
                             label='compressor speed',
                             description='compressor speed')

    FG = F.FieldGroup([
        initialState, pMin, pMax, mDotExtr, nCompressor, tWaitBeforeExtraction,
        tWaitBeforeFueling
    ],
                      label='Parameters')

    SG = F.SuperGroup([FG], label="Parameters")

    modelBlocks = []
예제 #2
0
class FluidFlowInput(NumericalModel):
    fluidName = F.Choices(Fluids, default='ParaHydrogen', label='fluid')
    flowRateChoice = F.Choices(OrderedDict((
        ('V', 'volume'),
        ('m', 'mass'),
    )),
                               label='flow rate based on')
    mDot = F.Quantity('MassFlowRate',
                      minValue=(0, 'kg/h'),
                      default=(1., 'kg/h'),
                      label='mass flow',
                      description='mass flow rate',
                      show='self.flowRateChoice == "m"')
    VDot = F.Quantity('VolumetricFlowRate',
                      minValue=(0., 'm**3/h'),
                      default=(1., 'm**3/h'),
                      label='volume flow',
                      description='volume flow rate',
                      show='self.flowRateChoice == "V"')
    T = F.Quantity('Temperature', default=(300., 'K'), label='temperature')
    p = F.Quantity('Pressure', default=(1., 'bar'), label='pressure')
    FG = F.FieldGroup([fluidName, flowRateChoice, mDot, VDot, T, p],
                      label='Parameters')

    modelBlocks = []

    def createFluidState(self):
        return CP.FluidState(self.fluidName)

    def compute(self):
        self.fState = self.createFluidState()
        self.fState.update_Tp(self.T, self.p)
        if (self.flowRateChoice == 'm'):
            self.VDot = self.mDot / self.fState.rho
        else:
            self.mDot = self.VDot * self.fState.rho
예제 #3
0
파일: CycleBases.py 프로젝트: birdol/SmoWeb
class LiquefactionCycle(ThermodynamicalCycle):
    abstract = True
    #================ Inputs ================#
    fluidName = F.Choices(Fluids, default='R134a', label='liquefied fluid')
    mDot = F.Quantity('MassFlowRate',
                      default=(1, 'kg/min'),
                      label='inlet flow rate')
    pIn = F.Quantity('Pressure',
                     default=(1, 'bar'),
                     label='inlet gas pressure')
    TIn = F.Quantity('Temperature',
                     default=(15, 'degC'),
                     label='inlet gas temperature')
    pHigh = F.Quantity('Pressure',
                       default=(40, 'bar'),
                       label='compressor high pressure')
    pLiquid = F.Quantity('Pressure',
                         default=(2, 'bar'),
                         label='liquid pressure')
    TAmbient = F.Quantity(
        'Temperature',
        default=(15, 'degC'),
        label='ambient temperature',
        description='used as reference temperature to calculate exergy')
    workingFluidGroup = F.FieldGroup(
        ['fluidName', 'mDot', pIn, TIn, pHigh, pLiquid, TAmbient],
        label='Cycle parameters')
    #================ Results ================#
    liqEnergy = F.Quantity('SpecificEnergy',
                           default=(1, 'kJ/kg'),
                           label='liquefaction energy')
    minLiqEnergy = F.Quantity(
        'SpecificEnergy',
        default=(1, 'kJ/kg'),
        label='min. liquefaction energy',
        description=
        'minimum energy required for liquefaction in an ideal carnot cycle; \
			equal to the difference in exergies between initial and final state')
    etaSecondLaw = F.Quantity(
        'Efficiency',
        label='figure of merit (FOM)',
        description=
        'minimum energy required for liquefaction to the actual energy required \
			in the cycle; equivalent to second law efficiency')
    efficiencyFieldGroup = F.FieldGroup(
        [liqEnergy, minLiqEnergy, etaSecondLaw], label='Efficiency')
예제 #4
0
class IncompressibleSolutionFlowInput(FluidFlowInput):
    solName = F.Choices(IncompressibleSolutions,
                        default='MEG',
                        label='fluid (name)',
                        description='fluid (incompressible solutions)')
    solMassFraction = F.Quantity(
        'Fraction',
        default=(0, '%'),
        label='fluid (mass fraction)',
        description='mass fraction of the substance other than water')

    incomSolFG = F.FieldGroup(
        [solName, solMassFraction, 'flowRateChoice', 'mDot', 'VDot', 'T', 'p'],
        label='Parameters')

    def createFluidState(self):
        return CP5.FluidStateFactory.createIncompressibleSolution(
            self.solName, self.solMassFraction)
예제 #5
0
class FluidStateSource(NumericalModel):
    sourceTypeTxt = F.Choices(OrderedDict((
        ('TP', 'temperature, pressure'),
        ('PQ', 'pressure, vapour quality'),
        ('TQ', 'temperature, vapour quality'),
    )),
                              label='state variables',
                              description='choose the initial state variables')

    @property
    def sourceType(self):
        if self.sourceTypeTxt == 'TP':
            return DM.FluidStateSource.TP
        if self.sourceTypeTxt == 'PQ':
            return DM.FluidStateSource.PQ
        if self.sourceTypeTxt == 'TQ':
            return DM.FluidStateSource.TQ
        else:
            raise ValueError('Unsupported source type of FluidStateSource.')

    T = F.Quantity(
        'Temperature',
        default=(0., 'degC'),
        label='temperature',
        description='temperature',
        show="self.sourceTypeTxt == 'TP' || self.sourceTypeTxt == 'TQ'")
    p = F.Quantity(
        'Pressure',
        default=(0., 'bar'),
        label='pressure',
        description='pressure',
        show="self.sourceTypeTxt == 'TP' || self.sourceTypeTxt == 'PQ'")
    q = F.Quantity(
        'VaporQuality',
        default=(0., '-'),
        minValue=0,
        maxValue=1,
        label='vapour quality',
        description='vapour quality',
        show="self.sourceTypeTxt == 'TQ' || self.sourceTypeTxt == 'PQ'")

    FG = F.FieldGroup([sourceTypeTxt, T, p, q], label='Parameters')

    modelBlocks = []
예제 #6
0
class Compressor(CycleComponent2FlowPorts):
    modelType = F.Choices(OrderedDict((
        ('S', 'isentropic'),
        ('T', 'isothermal'),
    )),
                          label='compressor model')
    etaS = F.Quantity('Efficiency',
                      label='isentropic efficiency',
                      show="self.modelType == 'S'")
    fQ = F.Quantity('Fraction',
                    default=0.,
                    label='heat loss factor',
                    show="self.modelType == 'S'")
    etaT = F.Quantity('Efficiency',
                      label='isosthermal efficiency',
                      show="self.modelType == 'T'")
    dT = F.Quantity('TemperatureDifference',
                    default=0,
                    label='temperature increase',
                    show="self.modelType == 'T'")
    FG = F.FieldGroup([modelType, etaS, fQ, etaT, dT], label='Compressor')
    modelBlocks = []

    #================== Methods =================#
    def compute(self, pOut):
        CycleComponent2FlowPorts.compute(self)
        if (pOut < self.inlet.state.p):
            raise ValueError(
                'Outlet pressure must be higher than inlet pressure')
        if (self.modelType == 'S'):
            self.outlet.state.update_ps(pOut, self.inlet.state.s)
            wIdeal = self.outlet.state.h - self.inlet.state.h
            self.w = wIdeal / self.etaS
            self.qIn = -self.fQ * self.w
            self.delta_h = self.w + self.qIn
            self.outlet.state.update_ph(pOut,
                                        self.inlet.state.h + self.delta_h)
        else:
            self.outlet.state.update_Tp(self.inlet.state.T + self.dT, pOut)
            self.qIn = (self.outlet.state.s -
                        self.inlet.state.s) * self.inlet.state.T
            wIdeal = self.outlet.state.h - self.inlet.state.h - self.qIn
            self.w = wIdeal / self.etaT
            self.qIn -= (self.w - wIdeal)
예제 #7
0
class Condenser(IsobaricHeatExchanger):
    computeMethod = F.Choices(OrderedDict((
        ('dT', 'sub-cooling'),
        ('Q', 'vapor quality'),
        ('eta', 'thermal efficiency'),
        ('T', 'temperature'),
        ('H', 'enthalpy'),
    )),
                              label='compute outlet by')
    dTOutlet = F.Quantity('TemperatureDifference',
                          default=(-10, 'degC'),
                          minValue=-1e10,
                          maxValue=-1e-3,
                          label='outlet subcooling',
                          show='self.computeMethod == "dT"')
    FG = F.FieldGroup([
        'computeMethod', 'etaThermal', 'TExt', 'dTOutlet', 'TOutlet',
        'qOutlet', 'hOutlet'
    ],
                      label='Condenser')
    modelBlocks = []
예제 #8
0
class Cooler(NumericalModel):
    workingState = F.Choices(OrderedDict((
        (0, 'no'),
        (1, 'yes'),
    )),
                             label='enable cooler',
                             description='enable cooler')

    epsilon = F.Quantity('Efficiency',
                         default=(0., '-'),
                         label='effectiveness',
                         description='effectiveness',
                         show="self.workingState")
    TCooler = F.Quantity('Temperature',
                         default=(0., 'degC'),
                         label='coolant temperature',
                         description='coolant temperature',
                         show="self.workingState")

    FG = F.FieldGroup([workingState, epsilon, TCooler], label='Parameters')

    modelBlocks = []
예제 #9
0
class Expansion(ThermodynamicalProcess):
    label = "Expansion"
    description = F.ModelDescription(
        "Parameteric model for expansion process: isentropic and isenthalpic",
        show=True)
    figure = F.ModelFigure(src="ThermoFluids/img/ModuleImages/Expansion.svg")
    turbine = F.SubModelGroup(TC.Turbine,
                              'FG',
                              label='Turbine',
                              show="self.processType == 'S'")
    throttleValve = F.SubModelGroup(TC.ThrottleValve, 'FG', show="false")
    processType = F.Choices(options=OrderedDict((
        ('S', 'isentropic'),
        ('H', 'isenthalpic'),
    )),
                            default='S',
                            label="process type")
    processTypeFG = F.FieldGroup([processType], label="Process type")
    inputs = F.SuperGroup(
        ['fluidSource', 'fluidSink', processTypeFG, turbine, throttleValve])

    def __init__(self):
        self.fluidSource.p1 = (10, 'bar')
        self.fluidSource.p2 = (10, 'bar')
        self.fluidSink.p = (1, 'bar')

    def compute(self):
        if (self.processType == 'S'):
            component = self.turbine
        elif (self.processType == 'H'):
            component = self.throttleValve
        self.initCompute(self.fluidSource.fluidName)
        # Connect components
        self.connectPorts(self.fluidSource.outlet, component.inlet)
        self.connectPorts(component.outlet, self.fluidSink.inlet)
        self.fluidSource.compute()
        component.compute(self.fluidSink.p)
        self.postProcess(component)
예제 #10
0
파일: CycleBases.py 프로젝트: birdol/SmoWeb
class HeatEngineCycle(ThermodynamicalCycle):
    abstract = True
    #================ Inputs ================#
    fluidName = F.Choices(Fluids, default='R134a', label='refrigerant')
    mDot = F.Quantity('MassFlowRate',
                      default=(1, 'kg/min'),
                      label=' refrigerant flow rate')
    pHighMethod = F.Choices(OrderedDict((
        ('P', 'pressure'),
        ('T', 'temperature'),
    )),
                            label='high side defined by')
    TEvaporation = F.Quantity('Temperature',
                              default=(-10, 'degC'),
                              label='evaporation temperature',
                              show="self.pHighMethod == 'T'")
    pHigh = F.Quantity('Pressure',
                       default=(40, 'bar'),
                       label='high pressure',
                       show="self.pHighMethod == 'P'")

    pLowMethod = F.Choices(OrderedDict((
        ('P', 'pressure'),
        ('T', 'temperature'),
    )),
                           label='low side defined by')
    pLow = F.Quantity('Pressure',
                      default=(1, 'bar'),
                      label='low pressure',
                      show="self.pLowMethod == 'P'")
    TCondensation = F.Quantity('Temperature',
                               default=(40, 'degC'),
                               label='condensation temperature',
                               show="self.pLowMethod == 'T'")
    TAmbient = F.Quantity(
        'Temperature',
        default=(15, 'degC'),
        label='ambient temperature',
        description='used as reference temperature to calculate exergy')
    workingFluidGroup = F.FieldGroup([
        'fluidName', 'mDot', pHighMethod, TEvaporation, pHigh, pLowMethod,
        TCondensation, pLow, TAmbient
    ],
                                     label='Cycle parameters')
    #================ Results ================#
    eta = F.Quantity('Efficiency', label='cycle efficiency')
    etaCarnot = F.Quantity(
        'Efficiency',
        label='Carnot efficiency',
        description=
        'efficiency of Carnot cycle between the high (boiler out) temperature and the low (condenser out) tempreature'
    )
    etaSecondLaw = F.Quantity(
        'Efficiency',
        label='second law efficiency',
        description='ratio or real cycle efficiency over Carnot efficiency')
    efficiencyFieldGroup = F.FieldGroup([eta, etaCarnot, etaSecondLaw],
                                        label='Efficiency')

    def setTCondensation(self, T):
        if (self.fluid.tripple['T'] < T < self.fluid.critical['T']):
            self.TCondensation = T
            sat = self.fluid.saturation_T(T)
            self.pLow = sat['psatL']
        else:
            raise ValueError(
                'Condensation temperature ({} K) must be between {} K and {} K'
                .format(T, self.fluid.tripple['T'], self.fluid.critical['T']))

    def setTEvaporation(self, T):
        if (self.fluid.tripple['T'] < T < self.fluid.critical['T']):
            self.TEvaporation = T
            sat = self.fluid.saturation_T(T)
            self.pHigh = sat['psatL']
        else:
            raise ValueError(
                'Evaporation temperature ({} K) must be between {} K and {} K'.
                format(T, self.fluid.tripple['T'], self.fluid.critical['T']))

    def initCompute(self, fluid):
        ThermodynamicalCycle.initCompute(self, fluid)
        # Set high and low pressures
        if (self.pLowMethod == 'P'):
            self.setPLow(self.pLow)
        else:
            self.setTCondensation(self.TCondensation)

        if (self.pHighMethod == 'P'):
            self.setPHigh(self.pHigh)
        else:
            self.setTEvaporation(self.TEvaporation)
        if (self.pLow >= self.pHigh):
            raise ValueError(
                'The low cycle pressure must be less than the high cycle pressure'
            )
예제 #11
0
class HeatExchangerTwoStreams(CycleComponent):
    #================== Inputs =================#
    computeMethod = F.Choices(OrderedDict((
        ('EG', 'effectiveness (given)'),
        ('EN', 'effectiveness (NTU)'),
    )),
                              label='compute method')
    type = F.Choices(options=OrderedDict((
        ('CF', 'counter flow'),
        ('PF', 'parallel flow'),
        ('EC', 'evaporation/condensation'),
    )),
                     default='CF',
                     label="flow configuration",
                     show='self.computeMethod == "EN"')
    epsGiven = F.Quantity('Efficiency',
                          default=1,
                          label='effectiveness',
                          show='self.computeMethod == "EG"')
    UA = F.Quantity('ThermalConductance',
                    default=(1, 'kW/K'),
                    label='UA',
                    show='self.computeMethod == "EN"')
    QDot = F.Quantity('HeatFlowRate',
                      default=(0, 'kW'),
                      label='heat flow rate in')
    FG = F.FieldGroup([computeMethod, epsGiven, UA, type],
                      label='Heat exchanger')
    #================== Results =================#
    NTU = F.Quantity(label='NTU')
    Cr = F.Quantity(label='capacity ratio')
    epsilon = F.Quantity('ThermalConductance', label='effectiveness')
    modelBlocks = []
    #================== Ports =================#
    inlet1 = F.Port(P.ThermodynamicPort)
    outlet1 = F.Port(P.ThermodynamicPort)
    inlet2 = F.Port(P.ThermodynamicPort)
    outlet2 = F.Port(P.ThermodynamicPort)

    #================== Methods =================#
    def compute(self):
        self.outlet1.state.update_Tp(self.inlet2.state.T, self.inlet1.state.p)
        self.outlet2.state.update_Tp(self.inlet1.state.T, self.inlet2.state.p)
        dH1DotMax = self.inlet1.flow.mDot * (self.inlet1.state.h -
                                             self.outlet1.state.h)
        dH2DotMax = self.inlet2.flow.mDot * (self.inlet2.state.h -
                                             self.outlet2.state.h)
        if (abs(dH1DotMax) > abs(dH2DotMax)):
            if (self.computeMethod == 'EG'):
                self.epsilon = self.epsGiven
            else:
                self.computeNTU(dH2DotMax, dH1DotMax)
            self.QDot = dH2DotMax * self.epsilon
        else:
            if (self.computeMethod == 'EG'):
                self.epsilon = self.epsGiven
            else:
                self.computeNTU(dH1DotMax, dH2DotMax)
            self.QDot = -dH1DotMax * self.epsilon

    def computeStream1(self):
        m1Dot = self.outlet1.flow.mDot = self.inlet1.flow.mDot
        self.outlet1.state.update_ph(self.inlet1.state.p,
                                     self.inlet1.state.h + self.QDot / m1Dot)

    def computeStream2(self):
        m2Dot = self.outlet2.flow.mDot = self.inlet2.flow.mDot
        self.outlet2.state.update_ph(self.inlet2.state.p,
                                     self.inlet2.state.h - self.QDot / m2Dot)

    def computeNTU(self, dHDotMin, dHDotMax):
        deltaTInlet = self.inlet1.state.T - self.outlet1.state.T
        CMin = dHDotMin / deltaTInlet
        CMax = dHDotMax / deltaTInlet
        self.NTU = self.UA / abs(CMin)
        self.Cr = abs(CMin / CMax)
        if self.type == 'CF':
            self.NTU_counterFlow()
        elif self.type == 'PF':
            self.NTU_parallelFlow()
        elif self.type == 'EC':
            self.NTU_evaporation_condensation()

    def NTU_counterFlow(self):
        self.epsilon = (1 - m.exp(-self.NTU * (1 - self.Cr))) / (
            1 - self.Cr * m.exp(-self.NTU * (1 - self.Cr)))

    def NTU_parallelFlow(self):
        self.epsilon = (1 - m.exp(-self.NTU * (1 + self.Cr))) / (1 + self.Cr)

    def NTU_evaporation_condensation(self):
        self.epsilon = 1 - m.exp(-self.NTU)

    def __str__(self):
        return """
Inlet 1: T = {self.inlet1.state.T}, p = {self.inlet1.state.p}, q = {self.inlet1.state.q}, h = {self.inlet1.state.h} 
Outlet 1: T = {self.outlet1.state.T}, p = {self.outlet1.state.p}, q = {self.outlet1.state.q}, h = {self.outlet1.state.h} 
Inlet 2: T = {self.inlet2.state.T}, p = {self.inlet2.state.p}, q = {self.inlet2.state.q}, h = {self.inlet2.state.h}
Outlet2: T = {self.outlet2.state.T}, p = {self.outlet2.state.p}, q = {self.outlet2.state.q}, h = {self.outlet2.state.h}
		""".format(self=self)

    @staticmethod
    def test():
        fp = [FluidState('Water') for _ in range(4)]
        he = HeatExchangerTwoStreams()
        he.inlet1.state = fp[0]
        he.outlet1.state = fp[1]
        he.inlet2.state = fp[2]
        he.outlet2.state = fp[3]

        he.inlet1.state.update_Tp(80 + 273.15, 1e5)
        he.inlet2.state.update_Tp(20 + 273.15, 1e5)
        m1Dot = 1.
        m2Dot = 1.

        he.compute(m1Dot, m2Dot)
        print he
예제 #12
0
class CycleDiagram(NumericalModel):
    #================ Inputs ================#
    enable = F.Boolean(label='create process diagram', default=True)
    isotherms = F.Boolean(label='isotherms')
    temperatureUnit = F.Choices(OrderedDict((('K', 'K'), ('degC', 'degC'))),
                                default='K',
                                label="temperature unit",
                                show="self.isotherms == true")
    isochores = F.Boolean(label='isochores')
    isentrops = F.Boolean(label='isentrops')
    qIsolines = F.Boolean(label='vapor quality isolines')
    diagramInputs = F.FieldGroup(
        [enable, isotherms, temperatureUnit, isochores, isentrops, qIsolines],
        label='Diagram')

    defaultMaxP = F.Boolean(label='default max pressure')
    defaultMaxT = F.Boolean(label='default max temperature')
    maxPressure = F.Quantity('Pressure',
                             default=(1, 'bar'),
                             label='max pressure',
                             show="self.defaultMaxP == false")
    maxTemperature = F.Quantity('Temperature',
                                default=(300, 'K'),
                                label='max temperature',
                                show="self.defaultMaxT == false")
    boundaryInputs = F.FieldGroup(
        [defaultMaxP, defaultMaxT, maxPressure, maxTemperature],
        label='Value Limits')

    inputs = F.SuperGroup([diagramInputs, boundaryInputs],
                          label='Diagram settings')
    modelBlocks = []

    def draw(self, fluid, fluidPoints, cycleLines):
        # Create diagram object
        diagram = PHDiagram(fluid.name, temperatureUnit=self.temperatureUnit)
        # Set limits
        pMax, TMax = None, None
        if not self.defaultMaxP:
            pMax = self.maxPressure
        if not self.defaultMaxT:
            TMax = self.maxTemperature
        diagram.setLimits(pMax=pMax, TMax=TMax)
        fig = diagram.draw(isotherms=self.isotherms,
                           isochores=self.isochores,
                           isentrops=self.isentrops,
                           qIsolines=self.qIsolines)
        ax = fig.get_axes()[0]
        # Draw points
        i = 1
        for fp in fluidPoints:
            ax.semilogy(fp.h / 1e3, fp.p / 1e5, 'ko')
            ax.annotate('{}'.format(i),
                        xy=(fp.h / 1e3, fp.p / 1e5),
                        xytext=(3, 2),
                        textcoords='offset points',
                        size='x-large')
            i += 1
        # Draw lines
        for (fp1, fp2) in cycleLines:
            ax.semilogy([fp1.h / 1e3, fp2.h / 1e3], [fp1.p / 1e5, fp2.p / 1e5],
                        'k',
                        linewidth=2)
        # Export diagram to file
        fHandle, resourcePath = diagram.export(fig)
        os.close(fHandle)
        return resourcePath
예제 #13
0
class FluidSource(CycleComponent):
    fluidName = F.Choices(options=Fluids, default='Water', label='fluid')
    stateVariable1 = F.Choices(options=StateVariableOptions,
                               default='P',
                               label='first state variable')
    p1 = F.Quantity('Pressure',
                    default=(1, 'bar'),
                    label='pressure',
                    show="self.stateVariable1 == 'P'")
    T1 = F.Quantity('Temperature',
                    default=(300, 'K'),
                    label='temperature',
                    show="self.stateVariable1 == 'T'")
    rho1 = F.Quantity('Density',
                      default=(1, 'kg/m**3'),
                      label='density',
                      show="self.stateVariable1 == 'D'")
    h1 = F.Quantity('SpecificEnthalpy',
                    default=(1000, 'kJ/kg'),
                    label='specific enthalpy',
                    show="self.stateVariable1 == 'H'")
    s1 = F.Quantity('SpecificEntropy',
                    default=(100, 'kJ/kg-K'),
                    label='specific entropy',
                    show="self.stateVariable1 == 'S'")
    q1 = F.Quantity('VaporQuality',
                    default=(1, '-'),
                    minValue=0,
                    maxValue=1,
                    label='vapour quality',
                    show="self.stateVariable1 == 'Q'")
    stateVariable2 = F.Choices(options=StateVariableOptions,
                               default='T',
                               label='second state variable')
    p2 = F.Quantity('Pressure',
                    default=(1, 'bar'),
                    label='pressure',
                    show="self.stateVariable2 == 'P'")
    T2 = F.Quantity('Temperature',
                    default=(300, 'K'),
                    label='temperature',
                    show="self.stateVariable2 == 'T'")
    rho2 = F.Quantity('Density',
                      default=(1, 'kg/m**3'),
                      label='density',
                      show="self.stateVariable2 == 'D'")
    h2 = F.Quantity('SpecificEnthalpy',
                    default=(1000, 'kJ/kg'),
                    label='specific enthalpy',
                    show="self.stateVariable2 == 'H'")
    s2 = F.Quantity('SpecificEntropy',
                    default=(100, 'kJ/kg-K'),
                    label='specific entropy',
                    show="self.stateVariable2 == 'S'")
    q2 = F.Quantity('VaporQuality',
                    default=(1, '-'),
                    minValue=0,
                    maxValue=1,
                    label='vapour quality',
                    show="self.stateVariable2 == 'Q'")
    mDot = F.Quantity('MassFlowRate', default=(1, 'kg/h'), label='mass flow')

    FG = F.FieldGroup([
        fluidName, stateVariable1, p1, T1, rho1, h1, s1, q1, stateVariable2,
        p2, T2, rho2, h2, s2, q2, mDot
    ],
                      label='Compressor')
    modelBlocks = []
    #================== Ports ===================#
    outlet = F.Port(P.ThermodynamicPort)

    #================== Methods =================#
    def getStateValue(self, sVar, prefix="", suffix=""):
        sVarDict = {
            'P': 'p',
            'T': 'T',
            'D': 'rho',
            'H': 'h',
            'S': 's',
            'Q': 'q'
        }
        return self.__dict__[prefix + sVarDict[sVar] + suffix]

    def compute(self):
        self.outlet.flow.mDot = self.mDot
        self.outlet.state.update(
            self.stateVariable1,
            self.getStateValue(self.stateVariable1, suffix="1"),
            self.stateVariable2,
            self.getStateValue(self.stateVariable2, suffix="2"))