So far, you have a system with a lot of stores and phases containing various substances. However, that does not represent a life support system yet, you also have to add the various interactions between the different phases, stores and substances to create a model for a LSS. Part of this will be performed in this chapter with the focus on moving matter from one store to another. The next chapter will then focus on moving matter between different phases within the same store.

In order to move matter from one store to another V-HAB uses the so called branches. For branches it is important to differentiate between the branch and the solver for the branch. The branch is the representation of a physical plumbing in V-HAB but unlike in reality the “plumbing” in V-HAB does not inherently have the correct flow rate for the specific boundary conditions. In order for the V-HAB branch to know this, it requires a numerical solver that tells the branch the correct flow rate for the current boundary conditions. Therefore, a branch always requires a solver to go with it. The branches are defined in the createMatterStructure() function while the solvers are defined in the createSolverStructure() function. Each solver has a specific calculation routine that decides how the flowrate is calculated for passing matter through the branch from one store to another. There are branches that let the user set this flow rate manually and other branches calculate it dynamically, depending on the pressure difference between the two sides and the pressure loss in between. This chapter will first explain how to set up a branch and then provide information about the different types of solvers, like how they calculate their flowrates.

Caution: It is part of the model development process to decide which type of solver to use for each case and you have to be careful with your choice. If you use very accurate (but slow) solvers for every branch, the simulation will take a long time and you might not be able to finish your simulations in a meaningful time-frame. However, if you only set constant flowrates, then your system is not a dynamic simulation.

1.4.3.1 Extract Merge Processors (ExMes)

Before you can move matter from A to B you have to add the connections that allow you to add or remove matter to or from a phase. These connections are called Extract Merge Processors, or ExMes, in V-HAB. There are four different types of ExMes, one for each phase: gas, liquid, solid, and mixture, as can be seen in the following code. The type of ExMe that is used has to match the phase type it is connected to, so a solid phase also needs a solid ExMe. You can specifiy the names of the ExMes if you want, or you can leave the generic names for the ports. Alternatively, you can completely leave out the definition of each ExMe and simply create the branches etc. as described below, by only providing the phases you want to connect as inputs. (Instead of the string with Store.ExMe name you provide the phase object as input to the branch).

matter.procs.exmes.gas(		oPhase, 'Name')
matter.procs.exmes.liquid(	oPhase, 'Name')
matter.procs.exmes.solid(	oPhase, 'Name')
matter.procs.exmes.mixture (oPhase, 'Name')

All four ExMe types require a phase object and a string with the name for the ExMe as input. The phase object can be provided by using the toStores struct of the system to reference the store that contains the phase and then use the toPhases struct of that store to reference the specific phase object. For example, to create an ExMe for the cabin air phase in this example the following code could be used.

matter.procs.exmes.gas(this.toStores.Cabin.toPhases.CabinAir, 'Cabin_to_HX');

In principle you can give the ExMe any name you want, but it is helpful to give the ExMe a name that tells you to which component this ExMe is going to or coming from. In this example, the ExMe would be used to take CabinAir from the Cabin and move it to the HX (condensing heat exchanger). It is not important to ensure that ExMe names do not repeat, however, it is important that all ExMes associated with the same store have different names.

For the example system we are working on, we will only use three ExMes in order to learn how to define them. But since the system is small, the other connections will be made using the simpler definition where the phase object is provided directly to the branch (note that an ExMe will still be created in that case, it will just be done automatically with a generic name by V-HAB and not by you). ExMe definitions have to be made in the createMatterStructure() function. Remember that you can receive the phase object from a store by using the following code (here for the example of the cabin air):

this.toStores.Cabin.toPhase.CabinAir

Store

Phase Name

ExMe Name

Cabin

CabinAir

Cabin_to_HX

Cabin

CabinAir

Cabin_from_HX

CabinCabinAirCabin_to_CO2_Removal

Now you have the necessary ports to move the matter, but you do not have the actual connection (branch) between the ports yet. You now have to tell the system which ExMes are connected to each other and how they are connected. The so-called branches perform this task which will be explained in the following chapters.

1.4.3.2 General Branch

Now you have to provide information as to how the phases are connected by adding branches to the system. For now, the branches will not contain any components like pipes, pumps etc. themselves since these will be added and explained in the next chapter. You have to use the following code in order to add a branch to the current system.

matter.branch(this, 'Store_1.ExMe_1', {'F2F_1', 'F2F_2'}, 'Store_2.ExMe_1', 'Branch_Name');

Instead of Store_1 and Store_2 you have to use the names of the stores you want to connect and instead of ExMe_1 and the names of the ExMes you want to use to connect these stores. The ExMe you use defines the phase inside the stores that you actually connect with the branch. Instead of F2F_1 you could specify flow to flow procs that are inside the branch but as mentioned before the branches at the moment will not be provided any components and you can just set {}. The final input you can set for the branch is the name the branch will be given. This can also be omitted in which case the branch will receive a generic name from the stores and ExMes that are used for its definition. However, it is strongly recommended for you to give the branches easily recognizable names to improve the readability of your code. These names could for example be HX_Coolant_Loop. If no specific ExMe is defined to be used for the branch, you can replace the string 'Store_2.ExMe_1' with a phase object. For example, a mixed definition using both an ExMe and a phase object would look as follows:

matter.branch(this, 'Cabin.Cabin_to_CO2_Removal', {}, this.toStores.CO2_Removal.toPhase.Air, 'Cabin_to_CO2_Removal');

In existing V-HAB code you will also often see intermediate variables which are used for these definitions. As the definition of an object always returns the object as output you can for example store a phase directly at its definition in an intermediate variable by using the follow approach:

oVacuum = this.toStores.Vacuum.createPhase(       'gas',  'boundary',	'Vacuum',       1e6,	struct('N2', 2), 3, 0);

And then you could use the intermediate variable oVacuum directly as input for the branch definition. For this example, the following branches have to be defined. (Definition has to be in the createMatterStructure() function). If you like the definition using ExMes better than the one which uses phase objects, feel free to just define your own ExMes for this example.


Left ExMe/Phase

Right ExMe/Phase

Branch Name

Cabin_to_HX

Cabin_from_HX

Cabin_HX_Loop

this.toStores.HX_Coolant.toPhases.Coolant

this.toStores.HX_Coolant.toPhases.Coolant

HX_Coolant_Loop

Cabin_to_CO2_Removal

this.toStores.CO2_Removal.toPhases.Air

Cabin_to_CO2_Removal

this.toStores.CO2_Removal.toPhases.Air

this.toStores.Cabin.toPhases.CabinAir

CO2_Removal_to_Cabin

this.toStores.O2_Generation.toPhases.Oxygen

this.toStores.Cabin.toPhases.CabinAir

O2_Generation_to_Cabin

this.toStores.O2_Generation.toPhases.Hydrogen

this.toStores.Vacuum.toPhases.Vacuum

Hydrogen_to_Vacuum

this.toStores.Water_Supply.toPhases.Water

this.toStores.O2_Generation.toPhases.Water

Water_to_O2_Generation

1.4.3.3 Manual Solver

The simplest solver regarding the calculation of the flow rate is the manual solver. For this solver the user can simply specify the mass flow rate that should pass through the solver. While this might seem too simplistic for any dynamic calculations at all it is actually possible to represent dynamic effects with manual solvers if an appropriate control logic for the solvers exist. For example, if you have a system that changes between different operating states and these changes are reflected by the control logic for the manual solvers you will have a representation of the dynamic state changes of your system. What you will however not have is a dynamic representation of the startup/shutdown phase between each state change and instead the flow rates will instantly jump to their respective values. The basic assumption that would be the foundation of this approach is a completely incompressible system where the stores and the branches are incompressible (therefore any change in flow rates will instantly spread through the complete system).

Now for the actual coding part of the manual solver. You can add branches with the following code line:

solver.matter.manual.branch(this.toBranches.Branch_Name);

where Branch_Name has to be replaced with the name you gave the branch during the definition in chapter 1.4.3.2 Use this type of branch for Cabin_HX_Loop, HX_Coolant_Loop, Cabin_to_CO2_Removal and Water_to_O2_Generation. Since the branch is manual you will sooner or later also require a way to set the flow rate for these branches. This can be done using the following code:

this.toBranches.Branch_Name.oHandler.setFlowRate(0);

where Branch_Name again has to be replaced with the name you specified for the branch. For the HX_Coolant_Loop you can use that command to set a flow rate of 10 kg/s right at the definition as this does not have to change later on. Similarly for the Cabin_HX_Loop you can set 1 kg/s right after its definition. For the other two branches a logic that tells the branch when it has to move how much matter has to be implemented. For the Cabin_to_CO2_Removal branch the assumption is that it contains a pump that ensures a constant volumetric flow rate through the branch. This can be easily implemented using the manual solver by using the setVolumetricFlowRate() function. Like for the mass flow you simply provide the volumetric flowrate (this time in m³/s) and the solver automatically calculates the correct mass flow based on this volumetric flowrate and the densities.

this.toBranches.Cabin_to_CO2_Removal.oHandler.setVolumetricFlowRate(0.01);

For the water supply to the electrolyzer an actual control logic has to be used in the sense that it has to keep the partial pressure of oxygen within certain limits. This also has to be performed over the whole simulation and therefore has to be located in the exec function. For this example, the assumption will be that the oxygen partial pressure has to be kept between 19500 Pa and 22000 Pa. If the partial pressure goes below 19500 Pa the water flow shall be set to a maximum value of 1e-4 kg/s while the nominal water flow that should be used while the partial pressure is within 19500 Pa and 22000 Pa shall be 3.4e-5. If the partial pressure is above 22000 Pa the flow rate should be 0. In order to write the necessary control logic you can use the code line

this.toStores.Cabin.toPhases.CabinAir.afPP(this.oMT.tiN2I.O2)

to get the partial pressure of oxygen from the cabin air. If partial properties of a phase for one specific substances are of interested these are always saved in a vector that has many entries as there are substances defined in the matter table. In order to identify the correct entry (and ensure that the value is still correct even if a new substance is added to the matter table) the code this.oMT.tiN2I.O2 is used in this example to get the correct entry from the vector. It is suggested that you always use the same call with the substance you are interested in instead of using numbers directly as they might change with future V-HAB updates. Now you should have the necessary information to write a control logic that keeps the partial pressure within the specified boundaries using the given flow rates by using an if/else construct. Once you have done this you just have to put another if query around it to ensure that it is not called for the first tick since the partial pressure property is not yet defined at that point.

if this.oTimer.iTick ~=0
	Insert Your Control Logic Here
end


Aside from setting flowrates, the manual solver also has a functionality that allows the user to set a specific mass transfer over a specific time (x kg over y seconds) by using the setMassTransfer() function. In case you want to transfer mass chunks, this option should be used instead of writing a seperate control logic!

1.4.3.4 Interval Solver

This solver calculates the flow rate of the branch based on the phase pressure and the pressure loss of the components within the branch.

solver.matter.interval.branch(this.toBranches.Branch_Name);

The operating principle of the interval solver is to find a flowrate at which the pressure difference (which is the pressure difference from the two phases adjacent of the branch and the pressure increases from active components like pumps) is equal to the pressure losses in the branch. It is therefore a solver that finds the steady state for the current boundary conditions that neglects the time it takes the fluid to reach that state. (e.g. if you have a pressure difference on a chunk of water it results in a force and accelerates it, but you do not instantly jump to the flowrate where the pressure loss is equal to the difference). However, for most cases the initial dynamic flowspeed increase in the branch should be for a very short time and therefore be neglegible. The solver is dynamic in the regard that the adjacent pressures and pressure losses/increases from the components are calculated dynamically. More information on how the solver works can be found in the core documentation chapter Interval Solver.

1.4.3.5 Residual Solver

The residual solver is a modification of the manual solver that automatically calculates the flow rate required to keep the mass in the phase on the left boundary constant (left actually refers to left in the code at the definition of the branch ;). Therefore, it is not possible to use multiple residual solvers that all have the same phase on their left side since all the residual solvers would try to keep the phase mass constant at the same time which no longer works. You can however have multiple residual solvers attached to the same phase if the phase is on the right side.

In order to define a residual solver you can use the following code.

solver.matter.residual.branch(this.toBranches.Branch_Name);


For this system you can use the residual solver for the O2_Generation_to_Cabin and Hydrogen_to_Vacuum branches.

Please note that the residual solver currently will only work if no other residual solver is used in any of the two phases to which it is connected.

1.4.3.6 Multibranch Solver

For some systems the phases inside the components become very small and contain very little mass, which results in slow calculations and many errors. In order to solve this issue a solver that can calculate multiple branches and use "flow" phases was developed. The small phases are called flow phases within V-HAB and exist for all different matter types (gas, liquid, solid, mixture). A flow phase in V-HAB represents the assumption, that the mass of this phase is infinitesimal small and can be neglected. The pressure of these flow phases is therefore not calculated by the matter table but rather by the multibranch solver assigned to solve them. The solver calculates a linear system of equations where the first set of equations represents the pressure differences and pressure losses. Similar to the interval solver, this solver tries to find a solution where the overall pressure loss is equal to the overall pressure difference (making it a steady state solver for the branches themself again just like the interval solver). The second set of equations enforces that the mass change in flow nodes is 0, which is the necessary condition for phases without a mass. The flow nodes can also use P2P processors (you will learn about these in the next chapter 1.4.4 Processors) to simulate absorptions etc.

For more information on how this solver works you can visit: Iterative Multi Branch Solver

For our system, we will not use it as an actual multibranch solver, but only solve the outflow of the LiOH absorber with it. You can define it for the corresponding branch by using:

solver.matter_multibranch.iterative.branch(this.toBranches.CO2_Removal_to_Cabin, 'complex');

If you wanted it to solve multiple branches, you would hand it an array of the branch objects it is supposed to solve instead of the individual branch. (Please view the available examples for this solver in user/+examples/+multibranch_solver to see how this can be done)

You can run an example system of this solver with the following command if you are interested in it:

vhab.exec('tutorials.laminar_incompressible_solver.setup', containers.Map(), struct(), 3600, 4)

1.4.3.7 Thermal Solver

For basic thermal solvers that handle fluid bound thermal energy transport you can use a helper to assign the correct solver at the end of the createSolverStructure() function. This should be set in every system currently, unless you define the thermal solvers yourself!

this.setThermalSolvers();

More information on the thermal structure within V-HAB is provided later in this tutorial (1.4.8 Thermal Components) and the solvers are described in 3.2.2. Thermal Solvers

1.4.3.8 Plotting

Now something is actually moving in the system for the first time, add the mass flows through the CO2 removal (In and Outlet) in a third plot for the second figure and the flowrate of water into OGA in a fourth plot for the figure. Even though something is moving in the system now, since the composition of all phases is still identical and nothing impacts this yet, the lines are still horizontal. You should then have the following results:



  • Keine Stichwörter