예제 #1
0
def total_power_single_channel(T_wall, w_channel, Nu_func, T_inlet, T_chamber,
                               T_ref, p_ref, m_dot, h_channel,
                               w_channel_margin, emmisivity, fp):
    """ Function that calculates the total power consumption of a specific chamber, in order to optimize the chamber

    Args:
        T_wall (K): Wall temperature
        w_channel (m): Channel width
        Nu_func (-): Nusselt function
        T_inlet (K): Chamber inlet temperature
        T_chamber (K): Chamber outlet temperature (same as T_c in IRT)
        T_ref (K): Reference temperature for the Nusselt relation and flow similary parameters
        p_ref (Pa): Reference pressure for the Nusselt relation and flow similary parameters (same as inlet pressure as no pressure drop is assumed)
        m_dot (kg/s): Mass flow
        h_channel (m): Channel height
        w_channel_margin (m): The amount of margin around the chamber for structural reasons. Important because it also radiates heat
        emmisivity (-) Emmisivity of the chamber material (for calculation of radation losses)
        fp (-  ): [description]
    """

    ## NOTE: just a test, assumptions are a bit sloppy, and this is just to test optimization approach at this stage

    A_channel = w_channel * h_channel  # [m^2] Channel area
    print("A_channel: {}".format(A_channel))
    wetted_perimeter = wetted_perimeter_rectangular(
        w_channel=w_channel, h_channel=h_channel
    )  # [m] Distance of channel cross-section in contact with fluid
    print("wetted_perimeter: {}".format(wetted_perimeter))
    # Reference length is hydraulic diameter
    D_hydraulic = hydraulic_diameter_rectangular(
        w_channel=w_channel, h_channel=h_channel)  # [m] Hydraulic diameter

    cp = chamber_performance_from_Nu(Nu_func=Nu_func,
                                     T_inlet=T_inlet,
                                     T_chamber=T_chamber,
                                     T_ref=T_ref,
                                     T_wall=T_wall,
                                     p_ref=p_ref,
                                     m_dot=m_dot,
                                     A_channel=A_channel,
                                     L_ref=D_hydraulic,
                                     fp=fp)
    ## Assume single-sided heater heat chamber material through-out at T-wall, and all along the wetted perimeter heat flows equally to teh propellant
    A_heater = cp['A_heater']  # [m^2]
    assert (A_heater > 0)
    L_channel = A_heater / wetted_perimeter  # [m] Required length of channel to achieve required heat flow
    print("L_channel: {}".format(L_channel))
    A_chip = required_chip_area(
        L_channel=L_channel,
        w_channel=w_channel,
        w_channel_margin=w_channel_margin
    )  # [m^2] Assume radiation occurs from silicon on just a single side of the heater
    print("A_microheater: {}".format(A_chip))
    P_radiation = radiation_loss(T=T_wall, A=A_chip,
                                 emmisivity=emmisivity)  # [W] Radiation loss
    P_total = P_radiation + cp[
        'Q_dot']  # [W] Total power consumption, the variable to minimize
    print("Heat loss {}".format(P_radiation / P_total))

    return P_total
예제 #2
0
    def test_simple_input(self):
        # inputs of 1 should return stefan-boltzmann constant
        emmisivity = 1
        A = 1
        T = 1

        exp = 5.670374419e-8  # [W/(m^2*K^4)]  Source: https://en.wikipedia.org/wiki/Stefan%E2%80%93Boltzmann_constant
        res = chamber.radiation_loss(T=T, A=A, emmisivity=emmisivity)
        self.assertEqual(exp, res)

        emmisivity = 0.5
        exp = 0.5 * exp
        res = chamber.radiation_loss(T=T, A=A, emmisivity=emmisivity)
        self.assertEqual(exp, res)

        A = 4
        exp = 4 * exp
        res = chamber.radiation_loss(T=T, A=A, emmisivity=emmisivity)
        self.assertEqual(exp, res)

        T = 2
        exp = 16 * exp
        res = chamber.radiation_loss(T=T, A=A, emmisivity=emmisivity)
        self.assertEqual(exp, res)
예제 #3
0
def calc_bottom_plane_heat_balance(h_conv, T_fluid, we, wall_args, delta_L):
    """Calculates the total heat transfer from the bottom wall to the fluid, and through the wall at lowest wall section.
    This function is necessary, as the bottom wall temperature is only solved if the radiation loss completes the heat balance

    Args:
        we (dict): Dictionary containing all resulting wall effect parameters
        wall_args(dict): Dictionary containing input parameters for wall effect calculations
        dL (m): Length of wall section

    Returns:
        Q_heat_transfer (W): total heat transfer from the bottom wall to the fluid, and through the wall at lowest wall section
    """
    # print("\nT_wall_bottom: {:3.1f} K".format(wall_args['T_wall_bottom']))
    # print("H_conv:")
    # print(h_conv)
    # print("Grad_theta_L:")
    # print(we['grad_theta_L'])
    # print("Delta_L:")
    # print(delta_L)
    Q_conduction_in = -wall_args['kappa_wall']*we['grad_theta_L']*wall_args['w_channel_spacing']*delta_L # [W] Heat flowing in through wall conduction
    # print(" --- Q_conduction_in: ---")
    # print(Q_conduction_in)
    Q_convection_out = h_conv*(wall_args['T_wall_bottom']-T_fluid)*wall_args['w_channel']*delta_L # [W] Heat flowing from bottom wall to fluid through convection
    dA_bottom = (wall_args['w_channel']+wall_args['w_channel_spacing'])*delta_L
    Q_radiation_out = radiation_loss(T=wall_args['T_wall_bottom'],A=dA_bottom,emmisivity=wall_args['emissivity_chip_bottom'])  # [W] Heat radiated from bottom of chip
    
    # Sum the totals to report the (im)balance
    Q_conduction_total = np.sum(Q_conduction_in) # [W]
    Q_convection_total = np.sum(Q_convection_out) # [W]
    Q_radiation_total = np.sum(Q_radiation_out) # [W]

    
    # print("Q_conduction_total: {:3.1f} W".format(Q_conduction_total))
    # print("Q_convection_total: {:3.1f} W".format(Q_convection_total))
    # print("Q_radiation_total: {:3.1f} W".format(Q_radiation_total))


    return (Q_conduction_total - Q_convection_total - Q_radiation_total) # [W] Heat difference that must be compensated by radiation loss for the solution to be valid
예제 #4
0
        T_outlet=T_chamber,
        p_outlet=p_inlet,
        fp=fp)  # [J/kg] Specific enthalpy change of the channel
    Q_dot = required_power(
        m_dot=m_dot, delta_h=delta_h
    )  # [W] Power that must go into the flow to achieve delta_h
    A_heater[it_T.index, :] = required_heater_area(
        Q_dot=Q_dot, h_conv=h_conv[it_T.index, :], T_wall=T,
        T_ref=T_bulk)  # [m^2] Required area to deliver power Q_dot
    L_channel[it_T.index, :] = A_heater[
        it_T.
        index, :] / w_channel  # [m] With this length , the required heater area is obtained for the given channel width
    # Estimated power loss through radation
    # Under the simple assumption that the heater only loses power through radiation, the power loss is calculated
    P_radiation_loss[it_T.index, :] = radiation_loss(
        T=float(T), A=A_heater[it_T.index, :], emmisivity=emmisivity
    )  # [W] Radiation from single-sided heater surface
    P_total[it_T.index, :] = P_radiation_loss[it_T.index, :] + Q_dot

## PLOTTING RESULTS
fig0, axs0 = plt.subplots(3, 1)  # For all the flow similarity parameters
fig1, axs1 = plt.subplots(3, 1)  # For the resulting dimensions and power loss
# First plot the results that do not vary with T_chamber, and need only be plotted once

# Reset the iterator to plot all results with different lines for different chamber temperatures
it_T.reset()
for T in it_T:
    ## First set of subplots
    # Bulk velocity
    axs0[0].plot(w_channel * 1e6,
                 u_bulk[it_T.index, :],
예제 #5
0
def optim_P_total(channel_amount, w_channel, h_channel, inlet_manifold_length_factor, inlet_manifold_width_factor, l_exit_manifold, w_channel_spacing, w_outer_margin, T_wall, p_ref, m_dot, \
    prepared_values, Nusselt_relations, pressure_drop_relations, convergent_half_angle, divergent_half_angle, F_desired, p_back, AR_exit, w_throat, emissivity_top, fp: FluidProperties, wall_args=None):
    # First calculate area ratio at entrance so it can be provided to contraction pressure drop function
    w_inlet_manifold = chamber.inlet_manifold_width(\
            channel_amount=channel_amount,
            w_channel=w_channel,
            w_channel_spacing=w_channel_spacing,
            inlet_manifold_width_factor=inlet_manifold_width_factor) # [m] Total width of inlet manifold
    area_ratio_contraction = chamber.area_ratio_contraction(\
        w_inlet_manifold=w_inlet_manifold,
        w_channel=w_channel,
        channel_amount=channel_amount) # [-] Area ratio of sudden contraction

    def x(T):
        wall_args[
            'T_wall_bottom'] = T  # [K] Add the bottom wall temperature in the wall argument dictionary
        # Calculate heat transfer to determine channel length
        res = oneD.rectangular_multi_channel_homogenous_calculation(\
            channel_amount=channel_amount,
            prepared_values=prepared_values,
            Nusselt_relations=Nusselt_relations,
            pressure_drop_relations=pressure_drop_relations,
            w_channel=w_channel,
            h_channel=h_channel,
            m_dot=m_dot,
            T_wall=T_wall,
            p_inlet=p_ref,
            fp=fp,
            area_ratio_contraction=area_ratio_contraction,
            wall_args=wall_args)

        #print(res['Q_total_bottom_plane_heat_balance'])
        return res['Q_total_bottom_plane_heat_balance']

    ## ROOT FINDING PROBLEM FOR T_WALL_BOTTOM
    # The proper bounds for the optimization are very sensitive to wall temperature and chamber temperature
    # It is hard to pick bounds that are valid for a wide range of those parameters
    # The problem is that that a too low lower bound results in model results that are wholly invalid and break the optimization
    # Too high a lower bound results in the solution not being within the bounds at all.
    # The quick and dirty solution here is to stepwise move the bounds down until the valid solution is between it.
    # The stepsize must be small enough to reliably avoid the scenario where the calculations are completely incorrect.
    delta_T_bounds = 25  # [K] The size of the bound shift could determine how low the bounds can go to the final chamber temperature without resulting into incorrection calculations

    ## The resultant channel length, pressure drops, etc, depends on bottom wall temperature. It must be iterated towards here.
    T_wall_bottom_min = T_wall - delta_T_bounds  # [K] Minimum temperature is in practice probably not lower than chamber temperature (not impossible, though)
    T_wall_bottom_max = T_wall
    bounds_are_correct = False  # [bool] Is False until a solution has been found
    # The bounds are correct once they get the opposite sign
    while not bounds_are_correct:
        a = x(T_wall_bottom_max)
        b = x(T_wall_bottom_min)
        # If the solutions have the same sign, subtract delta_T_bounds
        if np.sign(a) == np.sign(b):
            T_wall_bottom_min -= delta_T_bounds
            T_wall_bottom_max -= delta_T_bounds
        else:
            bounds_are_correct = True

    root_result = root_scalar(x,
                              bracket=([T_wall_bottom_min, T_wall_bottom_max]))

    if root_result.converged:
        T_wall_bottom = root_result.root  # [m^2]
        wall_args['T_wall_bottom'] = T_wall_bottom
        #print(" T_wall_bottom: {:3.2f} K".format(T_wall_bottom))
    else:
        raise Exception("No solution found for given temperature")

    res = oneD.rectangular_multi_channel_homogenous_calculation(\
            channel_amount=channel_amount,
            prepared_values=prepared_values,
            Nusselt_relations=Nusselt_relations,
            pressure_drop_relations=pressure_drop_relations,
            w_channel=w_channel,
            h_channel=h_channel,
            m_dot=m_dot,
            T_wall=T_wall,
            p_inlet=p_ref,
            fp=fp,
            area_ratio_contraction=area_ratio_contraction,
            wall_args=wall_args)

    # Check if these solutions are eventually valid
    assert (np.all(res['res_l']['delta_L'] >= 0))
    assert (np.all(res['res_tp']['delta_L'] >= 0))
    assert (np.all(res['res_g']['delta_L'] >= 0))

    l_channel = res['L_total']  # [m] Channel length
    p_chamber = res[
        'p_chamber']  # [Pa] Pressure out channel outlet/inlet of nozzle according to IRT
    T_chamber = res['T_chamber']

    # Nozzle performance must be recalculated, if pressure drop occured
    assert (pressure_drop_relations
            is not None)  # Just check is one was calculated

    if p_chamber <= 0:  # If pressure drop was so large p_chamber was negative, the solution is invalid, and NaNs must be returned
        # Return the same dictionary, but all NaN.
        return {
            'P_loss': np.nan,  # [W] Current approximation of heat loss
            'l_channel': np.nan,  # [m] Channel length
            'pressure_drop': np.nan,  # [Pa] Total pressure drop
            'dP_contraction': np.nan,  # [Pa] Pressure drop de to contraction
            'w_total': np.nan,  # [m] Total chip width
            'l_total': np.nan,  # [m] Total chip length
            'is_channel_choked': np.nan,
            'Re_channel_exit': np.nan,  # [-] Reynolds number at channel exit
        }
    # This only runs if pressure drop was not too large.
    # In that case the throat area must be recalculated still
    else:

        ep = engine_performance_from_F_and_T(F_desired=F_desired,
                                             p_chamber=p_chamber,
                                             T_chamber=T_chamber,
                                             AR_exit=AR_exit,
                                             p_back=p_back,
                                             fp=fp)

        # New throat widtl_inlet_manifoldmined from desired performance parameter
        w_throat_new = ep['A_throat'] / h_channel  # [m]
        # Check if new pressure, does not cause choked heating channels
        is_channel_choked = (
            w_channel * h_channel * channel_amount < ep['A_throat']
        )  # [bool] If combined channel area is smaller than throat, they are choked.
        # Check new Reynolds number at channel exit for laminar/turbulent flow assumptions
        hydraulic_diameter = chamber.hydraulic_diameter_rectangular(
            w_channel=w_channel, h_channel=h_channel)
        Re_channel_exit = fp.get_Reynolds_from_mass_flow(
            T=T_chamber,
            p=p_chamber,
            L_ref=hydraulic_diameter,
            m_dot=m_dot,
            A=h_channel * w_channel)

        l_outlet = chamber.outlet_length(\
            w_channel=w_channel,
            w_channel_spacing=w_channel_spacing,
            channel_amount=channel_amount,
            convergent_half_angle=convergent_half_angle,
            w_throat=w_throat_new,
            divergent_half_angle=divergent_half_angle,
            AR_exit=AR_exit,
            l_exit_manifold=l_exit_manifold
            )

        l_inlet_manifold = chamber.inlet_manifold_length(
            w_inlet_manifold=w_inlet_manifold,
            inlet_manifold_length_factor=inlet_manifold_length_factor)
        l_total = chamber.total_chip_length(l_inlet_manifold=l_inlet_manifold,
                                            l_channel=l_channel,
                                            l_outlet=l_outlet)
        w_total = chamber.total_chip_width(\
            w_inlet_manifold=w_inlet_manifold,
            w_outer_margin=w_outer_margin,
            w_throat=w_throat_new,
            AR_exit=AR_exit)

        A_chip = l_total * w_total  # [m^2]

        P_rad_loss_top = chamber.radiation_loss(
            T=T_wall, A=A_chip, emmisivity=emissivity_top
        )  # [W]  Radiation loss through top of chip
        P_rad_loss_bottom = chamber.radiation_loss(
            T=wall_args['T_wall_bottom'],
            A=A_chip,
            emmisivity=wall_args['emissivity_chip_bottom']
        )  # Radiation loss through bottom of chip
        P_loss = P_rad_loss_top + P_rad_loss_bottom  # [W] Total heat loss
        return {
            'P_loss': P_loss,  # [W] Current approximation of heat loss
            'l_channel': l_channel,  # [m] Channel length
            'pressure_drop': res['dP_total'],  # [Pa] Total pressure drop
            'dP_contraction':
            res['dP_contraction'],  # [Pa] Pressure drop due to contraction
            'w_total': w_total,  # [m] Total chip width
            'l_total': l_total,  # [m] Total chip length
            'is_channel_choked':
            is_channel_choked,  # [bool] 0 and 1 in this case, to check if channels are not too small
            'Re_channel_exit':
            Re_channel_exit,  # [-] Check Reynolds number to see if laminar flow assumptions still hold 
        }