The installation package of Dyssol contains all necessary components for the development of such modules. It is provided with a pre-configured solution for IDE Microsoft Visual Studio 2015 (or its Community edition).
+
+Unit development
+You must do the following in order to develop your new solver (plese refer to Configuration of Visual Studio project template):
+
+
+Install Microsoft Visual Studio 2015 (Community).
+Configure template project ModelsCreatorSDK
.
+
+
+There are 4 different pre-defined templates of units available:
+
+
+SteadyState
: performs steady-state calculation; current state of such unit does not depend on the previous state, but only on the input parameters.
+SteadyStateWithNLSolver
: steady-state unit with connected internal solver of non-linear equations.
+Dynamic
: performs dynamic calculation; current state of this unit depends not only on the input parameters as well as on the previous state of the unit.
+DynamicWithDAESolver
: dynamic unit with connected internal solver of differential-algebraic equations.
+
+
+Please also refer to Basic unit for detailed informaiton on functions applied in unit development.
+
+
+Add new unit to the template project
+
+Copy the desired template of the unit from <PathToSolution>\ModelsCreatorSDK\UnitsTemplates
to the folder Units
in solution (<PathToSolution>\ModelsCreatorSDK\Units
).
+Rename template’s folder according to the name of your new unit (further <MyUnitFolder>
). The name can be chosen freely.
+Rename project files in template’s folder (*.vcxproj
, *.vcxproj.filters
) according to the name of your new unit.
+Run the solution file (<PathToSolution>\ModelsCreatorSDK\Dyssol.sln
) to open it in Visual Studio.
+Add project with your new unit to the solution. To do this, select in Visual Studio File → Add → Existing Project and specify path to the project file (<PathToSolution>\ModelsCreatorSDK\Units\<MyUnitFolder>\<*.vcxproj>
).
+Rename added project in Visual Studio according to the name of your unit.
+
+Now you can implement functionality of your new unit. To build your solution press F7, to run it in debug mode press F5. Files with new units will be placed to <PathToSolution>\ModelsCreatorSDK\Debug
.
+As debug versions of compiled and built units contain a lot of additional information, which is used by Visual Studio to perform debugging, their calculation efficiency can be dramatically low. Thus, for the simulation purposes, units should be built in Release mode.
+
+
+
+
+Development of steady-state units
+
+Constructor of the unit: called only once when unit is added to the flowsheet. In this function a set of parameters should be specified:
+
+Basic info:
+
+m_sUnitName
: Name of the unit that will be displayed in Dyssol.
+m_sAuthorName
: Unit’s author
+m_sUniqueID
: Unique identificator of the unit. Simulation environment distinguishes different units with the help of this identificator.
+
+You must ensure that ID of your unit is unique. This ID can be created manually or using GUID-generator of Visual Studio (Tools → GUID Genarator).
+
+Specify ports for stream in- and outlet(s): add new, rename or delete existing.
+Additional internal material streams can be defined here.
+Sepcify unit parameters.
+All other operations, which should take place only once during the unit’s creation.
+
+
+
+Destructor of the unit: called only once when unit is removed from the flowsheet. Here all memory which has been previously allocated in the constructor should be freed.
+
+void CUnit::Initialize(double _dTime)
+
+
+Unit‘s initialization. This function is called only once at the start of the simulation at time point dTime
. Starting from this point, information about defined compounds, phases, distributions, etc. are available for the unit. Here you can create state variables and initialize some additionaly objects (e.g. additional material streams, state variables or plots).
+
+void CUnit::Simulate(double _dTime)
+
+
+Steady-state calculation for a specified time point dTime
. This function is called iteratively for all time points for which this unit should be calculated. All main calculations should be implemented here.
+
+
+Unit‘s finalization. This function is called only once at the end of the simulation. Here one can perform closing and cleaning operations to prepare for the next possible simulation run. Implementation of this function is not obligatory and can be skipped.
+
+
+Application example
+Now you want to develop a new steady-state model of splitter with one input stream and three output streams, as the figure shown below. The splitting factors for the first and second outlets are and respectively.
+
+You need the following steps:
+
+Copy the directory with the template unit <PathToSolution>\ModelsCreatorSDK\UnitsTemplates\SteadyStateUnit
to the directory for new units <PathToSolution>\ModelsCreatorSDK\Units\
.
+Rename the copied template’s directory SteadyStateUnit
to MySplitter
. Open the directory MySplitter
and rename file SteadyState.vcxproj
to MySplitter.vcxproj
.
+Open the template solution <PathToSolution>\ModelsCreatorSDK\Dyssol.sln
in Visual Studio.
+Add project with your new unit to the solution: select in Visual Studio File → Add → Existing Project and specify path to the project file <PathToSolution>\ModelsCreatorSDK\Units\MySplitter\MySplitter.vcxproj
.
+Rename added project in Visual Studio from UnitT_SteadyState
to Unit_MySplitter
.
+Open Unit_MySplitter
→ Unit.cpp
in the Visual Studio’s Solution Explorer and extend the unit with the following functionality (please refer to Basic unit, Stream and label-PSD when necessary):
+
+
+Modify constructor CUnit()
:
+
+
+Specify unit’s name by changing value of variable m_sUnitName
to My Splitter
. This name will appear in the drop-down list for unit types in Dyssol simulation.
+Specify author’s name by changing value of variable m_sAuthorName
.
+Set new unique key of the unit by changing value of variable m_sUniqueID
to some random string. To generate such a string GUID generator of Visual Studio can be used Tools → Create GUID.
+Add two additional output ports and rename all of them.
+
+
CUnit::CUnit() {
+
+// Basic unit's info
+m_sUnitName = "MySplitter";
+m_sAuthorName = "MyName";
+m_sUniqueID = "B59F8349A7014AC294D6580C0D8E21FE";
+
+// Add ports
+AddPort("In", INPUT_PORT);
+AddPort("Out1", OUTPUT_PORT);
+AddPort("Out2", OUTPUT_PORT);
+AddPort("Out3", OUTPUT_PORT);
+
+// Add unit parameters - splitting factors
+AddConstParameter("k1", 0, 1, 0, "k1");
+AddConstParameter("k2", 0, 1, 0, "k2");
+
+}
+
+
+
+
+Modify function Initialize()
: remove all codes in it.
+Modify function Simulate()
:
+
+Here you should perform all steps which are needed in the simulaition, including get port streams, set mass flow of inlet streams and the calculation of output streams. Also don’t forget to give user warning if some streams becomes minus.
+
void CUnit::Simulate(double _dTime) {
+
+// Get streams of all ports and assign them to corresponding material streams
+CMaterialStream* pInStream = GetPortStream("In");
+CMaterialStream* pOutStream1 = GetPortStream("Out1");
+CMaterialStream* pOutStream2 = GetPortStream("Out2");
+CMaterialStream* pOutStream3 = GetPortStream("Out3");
+
+// Copy inlet stream to all outlet streams
+pOutStream1->CopyFromStream(pInStream, _dTime);
+pOutStream2->CopyFromStream(pInStream, _dTime);
+pOutStream3->CopyFromStream(pInStream, _dTime);
+
+// Set mass flow rate of inlet stream
+double dMassFlowIn = pInStream->GetMassFlow(_dTime);
+
+// Add splitting factors
+double dSplitFactor1 = GetConstParameterValue("k1");
+double dSplitFactor2 = GetConstParameterValue("k2");
+
+// Give warning if sum of splitting factors is greater than 1
+if (dSplitFactor1 + dSplitFactor2 > 1)
+ RaiseError("Warning about minus outlet 3...");
+
+// Set calculated mass flow rate to corresponding outlet streams
+pOutStream1->SetMassFlow(_dTime, dMassFlowIn * dSplitFactor1);
+pOutStream2->SetMassFlow(_dTime, dMassFlowIn * dSplitFactor2);
+pOutStream3->SetMassFlow(_dTime, dMassFlowIn * (1 - dSplitFactor1 - dSplitFactor2));
+
+}
+
+
+
+
+Perform test simulation:
+
+Now you have your complete code for the splitter. Build the solution and then run Dyssol in debug mode. Add material streams and the unit, choose the unit type “MySplitter”, set inlet mass flow and splitting factors according to the table below, and finally check if the results are correct. Finally, save the simulation file for the example of developing a dynamic unit.
+
+
+
+
+
+
+General |
+
+Materials |
+Sand |
+
+Phases |
+Solid |
+
+Inlet |
+
+Time points |
+0 s |
+
+Mass stream |
+1 kg/s |
+
+Phase mass fractions |
+Solid: 1 |
+
+Compounds mass fractions |
+Sand: 1 |
+
+Options |
+
+Simulation time |
+60 s |
+
+
+
+
+
+
+
+
+
+
+Development of steady-state units with internal non-linear solver
+You can solve nonlinear equation systems automatically in Dyssol system. In this case, the unit should contain one or several additional objects of CNLModel
class. This class is used to describe non-linear systems and can be automatically solved with CNLSolver
class.
+
+
+Constructor of the unit: called only once when unit is added to the flowsheet. In this function a set of parameters should be specified:
+
+Basic info:
+
+m_sUnitName
: Name of the unit that will be displayed in Dyssol.
+m_sAuthorName
: Unit’s author
+m_sUniqueID
: Unique identificator of the unit. Simulation environment distinguishes different units with the help of this identificator.
+
+You must ensure that ID of your unit is unique. This ID can be created manually or using GUID-generator of Visual Studio (Tools → GUID Genarator).
+
+Specify ports for stream in- and outlet(s): add new, rename or delete existing.
+Additional internal material streams can be defined here.
+Sepcify unit parameters.
+All other operations, which should take place only once during the unit’s creation.
+
+
+
+Destructor of the unit: called only once when unit is removed from the flowsheet. Here all memory which has been previously allocated in the constructor should be freed.
+
+Unit::Initialize(double _dTime)
+
+
+Unit‘s initialization. This function is called only once at the start of the simulation at time point dTime
. Starting from this point, information about defined compounds, phases, distributions, etc. are available for the unit. Here you can create state variables and initialize some additionaly objects (for example holdups, material streams, state variables or plots).
+In this function, variables of all NLModels
should be specified by using function NLModel::AddNLVariable()
; connection between NLModel
and NLSolver
classes should be created by calling function NLSolver::SetModel()
.
+
+Unit::Simulate(double _dTime)
+
+
+Steady-state calculation for a specified time point dTime
. This function is called iteratively for all time points for which this unit should be calculated. All main calculations should be implemented here. Calculation of the defined NL-system can be run here by calling function NLSolver::Calculate()
.
+
+
+For flowsheets containing recycled streams, SaveState()
function is called when the convergence on the current time interval is reached, this also ensures the return to the previous state of the unit if convergence fails during the calculation. Here all internal time-dependent variables which weren’t added to the unit by using AddStateVariable and AddMaterialStream functions should be manually saved. Implementation of this function is not obligatory and can be skipped.
+
+
+Load last state of the unit which has been saved with SaveState()
function. Implementation of this function is not obligatory and can be skipped.
+
+
+Unit‘s finalization. This function is called only once at the end of the simulation. Here one can perform closing and cleaning operations to prepare for the next possible simulation run. Implementation of this function is not obligatory and can be skipped.
+
+NLModel::CalculateFunctions(double* _pVars, double* _pFunc, void* _pUserData)
+
+
+Here the non-linear system should be specified. This function will be called by solver automatically.
+
+NLModel::ResultsHandler(double _dTime, double* _pVars, void* pUserData)
+
+
+Handling of results, which are returned from NLSolver
on each time point. Called by solver every time when the solution in a new time point is ready.
+
+
+Application example
+In this example, you need to develop a steady-state unit for a simple air classifying process, which separates particles according to their sinking velocity in a fluid stream. Additionally, the time and particle size dependence of separation efficiency should be plotted.
+The separation depends on the relative velocity between the fluid and the particles . Floating particles with no velocity, i.e. , will be divided evenly to coarse and fines stream.
+The separation efficiency and cut-off velocity are defined as in the formulas below.
+
+
+
+
+
To complete the simulation, you need to solve the following implicit equation system:
+
+
+
+
+
+
+
+
Note
+
Notations:
+
– Relative velocity of particle of size class [m/s]
+
– Velocity of particle of size class [m/s]
+
– Velocity of gas [m/s]
+
– Separation efficiency of size class [-]
+
– Cut-off velocity [m/s]
+
– Gas mass flow [kg/s]
+
– Reynolds number of size class [-]
+
– Particle diameter of size class [m]
+
– Drag coefficient of size class [-]
+
– Gas density []
+
– Particle / solid density []
+
– Gas dynamic viscosity [Pa·s]
+
– Sharpness factor [-]
+
– Cross-sectional area []
+
– Gravitational acceleration []
+
+Now you need the following steps:
+
+Copy the directory with the template unit <PathToSolution>\ModelsCreatorSDK\UnitsTemplates\SteadyStateWithNLSolver\
to the directory for new units <PathToSolution>\ModelsCreatorSDK\Units\
. Rename the folder to AirClassifierTemplate
and the file SteadyStateWithNLSolver.vcxproj
to AirClassifier.vcxproj
.
+Along with this application example, you obtain a pre-configured template folder of the air classifier unit ...\Task8\AirClassifierTemplate\
, in which you find the source file Unit.cpp
and header file Unit.h
. Copy the contents of them to the corresponding Unit.cpp
and Unit.h
files in your template folder <PathToSolution>\ModelsCreatorSDK\Units\AirClassifierTemplate\
.
+Open the template solution <PathToSolution>\ModelsCreatorSDK\Dyssol.sln
in Visual Studio.
+Add project with your new unit to the solution: select File → Add → Existing Project and specify path to the project file <PathToSolution>\ModelsCreatorSDK\Units\AirClassifierTemplate\
. Rename the unit to Unit_AirClassifier
.
+Open Unit_AirClassifier
→ Unit.cpp
in the Visual Studio’s and extend the unit with the following functionality:
+
+
+Edit the unit CUnit
:
+
+
+
+
+
+
+Test the unit in Dyssol:
+
+
+Build the solution and run Dyssol: Build → Build Solution, and then Debug → Start Debugging.
+Use exemplary flowsheet ...\Tasks8\AirClassifier.dflw
to test your unit. Compare your results with the expected ones below.
+
+
+
+
+
+
+
+
+
+
+Development of dynamic units
+
+Constructor of the unit: called only once when unit is added to the flowsheet. In this function a set of parameters should be specified:
+
+Basic info:
+
+m_sUnitName
: Name of the unit that will be displayed in Dyssol.
+m_sAuthorName
: Unit’s author
+m_sUniqueID
: Unique identificator of the unit. Simulation environment distinguishes different units with the help of this identificator. You must ensure that ID of your unit is unique. This ID can be created manually or using GUID-generator of Visual Studio (Tools → GUID Genarator).
+
+
+Specify ports for stream in- and outlet(s): add new, rename or delete existing.
+Specify unit parameters.
+Define internal holdups and additional material streams.
+Define all other operations, which should take place only once during the unit’s creation.
+
+
+
+Destructor of the unit: called only once when unit is removed from the flowsheet. Here all memory which has been previously allocated in the constructor should be freed.
+
+Unit::Initialize(double _dTime)
+
+
+Unit‘s initialization. This function is called only once at the start of the simulation at dTime
. Starting from this point, information about defined compounds, phases, distributions, etc. are available for the unit. Here you can create state variables and initialize some additionaly objects (e.g. holdups, material streams or state variables).
+
+Unit::Simulate(double _dStartTime, double _dEndTime)
+
+
+Dynamic calculation of the unit on a specified time interval from dStartTime
to dEndTime
. All logic of the unit’s model must be implemented here.
+
+
+For flowsheets containing recycled streams, SaveState()
function is called when the convergence on the current time interval is reached, this also ensures the return to the previous state of the unit if convergence fails during the calculation. Here all internal time-dependent variables which weren’t added to the unit by using AddStateVariable, AddMaterialStream or AddHoldup functions should be manually saved. Implementation of this function is not obligatory and can be skipped.
+
+
+Load last state of the unit which has been saved with the SaveState() function. Implementation of this function is not obligatory and can be skipped.
+
+
+Unit‘s finalization. This function is called only once at the end of the simulation. Here one can perform closing and cleaning operations to prepare for the next possible simulation run. Implementation of this function is not obligatory and can be skipped.
+
+
+Application example
+You will learn to implement a simple dynamic unit (however without any physical meaning), where the basic functionality of classes CBaseUnit
, CMaterialStream
and CHoldup
can be tested.
+Do the following steps:
+
+Copy a directory with the template unit <PathToSolution>\ModelsCreatorSDK\UnitsTemplates\DynamicUnit
to the directory for new units <PathToSolution>\ModelsCreatorSDK\Units\
.
+Rename the copied template’s directory DynamicUnit
to Basics
. Open the directory Basics
and rename the file Dynamic.vcxproj` to Basics.vcxproj
.
+Open the template solution (<PathToSolution>\Dyssol.sln
) in Visual Studio.
+Add project with your new unit to the solution: select in Visual Studio File → Add → Existing Project and specify path to the project file <PathToSolution>\ModelsCreatorSDK\Units\Basics\Basics.vcxproj
.
+Rename added project in Visual Studio from UnitT_Dynamic
to Unit_Basics
.
+Open Unit_Basics
→ Unit.cpp
in the Visual Studio’s Solution Explorer and develop your unit as shown follows. You can use Basic unit, Stream and label-PSD for references.
+
+
+Modify constructor CUnit()
:
+
+
+Specify unit’s name by changing value of variable m_sUnitName
to Basics
. This name will appear in the drop-down list for unit types in Dyssol simulation.
+Specify author’s name by changing value of variable m_sAuthorName
.
+Set new unique key of the unit by changing value of variable m_sUniqueID
to some random string. To generate such a string, you can use GUID generator of Visual Studio (Tools → Create GUID).
+
+
Now your code for constructor should look like this:
+
CUnit::CUnit() {
+
+ // Basic unit's info
+ m_sUnitName = "Basics";
+ m_sAuthorName = "Your name";
+ m_sUniqueID = "30D8887B8E5F4BF5B91B98342684E707";
+
+ // Add ports
+ AddPort("InPort", INPUT_PORT);
+ AddPort("OutPort", OUTPUT_PORT);
+
+ // Add unit parameters
+ AddTDParameter("ParamTD", 0, 1e+6, 0, "Unit parameter description");
+ AddConstParameter("ParamConst", 0, 1e+6, 0, "Unit parameter description");
+ AddStringParameter("ParamString", "Initial value", "Unit parameter description");
+
+ // Add holdups
+ AddHoldup("HoldupName");
+
+}
+
+
+
+
+Modify function Initialize(double _dTime)
:
+
+
+Add warnings if liquid or vapor phases are not defined. Use functions IsPhaseDefined
and RaiseWarning
.
+Add an internal material stream named “BufStream” using the function AddMaterialStream
.
+Add new plot with the name “Plot1” to show dependency of holdup’s mass (Y axis is “Mass”) over time (X axis is “Time”). Add a curve on this plot with the name “Curve1”. Use the functions AddPlot
and AddCurveOnPlot
.
+
+
An example for this section is shown below.
+
void CUnit::Initialize(double _dTime) {
+
+ /// Add state variables ///
+ AddStateVariable("VarName", 0, true);
+ if (!IsPhaseDefined(SOA_LIQUID)) {
+ RaiseWarning("Liquid phase has not been defined");
+ }
+ if (!IsPhaseDefined(SOA_VAPOR)) {
+ RaiseWarning("Vapor phase has not been defined");
+ }
+
+ // Add buffer stream
+ AddMaterialStream("BufStream");
+
+ // Add plot
+ AddPlot("Plot1", "Mass", "Time");
+ AddCurveOnPlot("Plot1", "Curve1");
+
+}
+
+
+
+
+Modify funciton Simulate(double _dStartTime, double _dEndTime)
:
+
+
+Obtain pointer to the BufStream
into the new variable CMaterialStream *bufStream
(with the function GetMaterialStream
).
+Add new time point _dStartTime
to BufStream
with bufStream->AddTimePoint
.
+Copy inlet into BufStream at _dEndTime
with the function bufStream->CopyFromStream
.
+Set mass flow to 12.5 kg/s of the liquid phase in BufStream at t = 10s (bufStream->SetPhaseMassFlow
).
+Add inlet to the holdup on entire time interval from _dStartTime to _dEndTime (pHoldup->AddStream
).
+Copy the holdup into the outlet for _dStartTime
time point with mass flow 1 kg/s (pOutStream->CopyFromHoldup
).
+Set new temperature T = 320 K to the outlet at t = 15 s (pOutStream->SetTemperature
).
+Plot mass of the holdup for all defined time points. Use the functions GetAllDefinedTimePoints
, AddPointOnCurve
and pHoldup->GetMass
.
+
+
The example code looks like follows:
+
void CUnit::Simulate(double _dStartTime, double _dEndTime) {
+
+ // Get pointers to streams
+ CMaterialStream* pInStream = GetPortStream("InPort");
+ CMaterialStream* pOutStream = GetPortStream("OutPort");
+ CMaterialStream* bufStream = GetMaterialStream("bufStream");
+
+ // Get pointers to holdups
+ CHoldup* pHoldup = GetHoldup("Holdup");
+
+ // Add start time point to bufStream
+ bufStream->AddTimePoint(_dStartTime);
+
+ // Copy inlet stream into bufStream
+ bufStream->CopyFromStream(pInStream, _dEndTime);
+
+ // Set mass flow 12.5 kg/s of liquid phase in bufStream at time point 10 s
+ bufStream->SetPhaseMassFlow(10, SOA_LIQUID, 12.5, BASIS_MASS);
+
+ // Add inlet to the holdup on entire time interval
+ pHoldup->AddStream(pInStream, _dStartTime, _dEndTime);
+
+ // Copy the holdup into outlet stream at end time point with mass flow 1 kg/s
+ pOutStream->CopyFromHoldup(pHoldup, _dStartTime, 1);
+
+ // Set new temperature 320 K to outlet at time point 15 s
+ pOutStream->SetTemperature(15, 320);
+
+ // Plot holdup mass for all defined time points
+ std::vector<double> times = GetAllDefinedTimePoints(_dStartTime, _dEndTime);
+ for (int i = 0; i < times.size(); i++) {
+ double x = times[i];
+ double y = pHoldup->GetMass(times[i], BASIS_MASS);
+ AddPointOnCurve("Time dependence of holdup mass", "Curve1", x, y);
+ }
+
+ // Data acquisition:
+ // Get unit parameters
+ double TDParameter = GetTDParameterValue("ParamTD", 5);
+ double ConstParameter = GetConstParameterValue("ParamConst");
+ std::string StringParameter = GetStringParameterValue("ParamString");
+ // Get common compound information
+ std::vector<std::string> compounds = GetCompoundsList(); //only one compound in task6, so only one element in compounds array
+ double molarMass = GetCompoundConstant(compounds[0], MOLAR_MASS);
+ double critTemp = GetCompoundConstant(compounds[0], CRITICAL_TEMPERATURE);
+ double density = GetCompoundTPDProp(compounds[0], DENSITY, 273, 1e5);
+ // Get tolerance
+ double absTol = GetAbsTolerance();
+ double relTol = GetRelTolerance();
+ // Get overall properties of streams and holdups
+ double massFlow = pInStream->GetMassFlow(2, BASIS_MASS);
+ double massHoldup = pHoldup->GetMass(5, BASIS_MASS);
+ double outTemp = pOutStream->GetTemperature(15);
+ double molarMassHoldup = pHoldup->GetOverallProperty(1, MOLAR_MASS);
+ // Get solid distribution information
+ std::vector<double> PSD_b3 = pHoldup->GetPSD(50, PSD_Q3);
+ std::vector<double> PSD_s3 = pHoldup->GetPSD(50, PSD_q3);
+
+}
+
+
+
+
+
+
+Test your unit in Dyssol:
+
+
+
+Extend the Simulate
function with the code to obtain values of unit’s and streams’ parameters, which are specified in the table at the end of this section.
+Use breakpoints in debug mode of Visual Studio to obtain values of variables at runtime. To do this, place a breakpoint at the end of the function Simulate
(select desired line of code, then choose Debug → Toggle Breakpoint or press F9) and start debugging (Debug → Start Debugging or F5). After pressing the Simulate button in Dyssol, the program stops at the breakpoint. Values of all previously calculated variables will be available on mouse hover in Visual Studio. Compare your results with expected values below.
+
+
+Unit parameters:
+
+
+
+
+
+
+
+
+Parameter |
+Function |
+Expected value |
+
+
+
+Value of Time-dependent unit parameter ParamTD at time point 5s |
+GetTDParameterValue()
|
+1.2 |
+
+Value of constant unit parameter ParamConst |
+GetConstParameterValue()
|
+1E-8 |
+
+Value of string unit parameter ParamString |
+GetStringParameterValue()
|
+Initial value |
+
+
+
+
+
+Common compounds information:
+
+
+
+
+
+
+
+
+Parameter |
+Function |
+Expected value |
+
+
+
+List of defined compounds |
+GetCompoundsList()
|
+4031BC62EC7F17EFA33F |
+
+Molar mass of the first defined compound |
+GetCompoundConstant(… MOLAR_MASS)
|
+0.06 |
+
+Critical temperature of the first defined compound |
+GetCompoundConstant(… CRITICAL_TEMPERATURE)
|
+3500 |
+
+Density of the first compound by T = 273 K, P = 1e+5 Pa |
+GetCompoundTPDProp(… DENSITY, …)
|
+1600 |
+
+
+
+
+
+Tolerances:
+
+
+
+
+
+
+
+
+Parameter |
+Function |
+Expected value |
+
+
+
+Global absolute tolerance |
+GetAbsTolerance()
|
+1E-6 |
+
+Global relative tolerance |
+GetRelTolerance()
|
+0.001 |
+
+
+
+
+
+Overall properties of streams and holdups:
+
+
+
+
+
+
+
+
+Parameter |
+Function |
+Expected value |
+
+
+
+Mass flow of the inlet at t = 2 s |
+pInStream->GetMassFlow()
|
+1 |
+
+Mass of the holdup at t = 5 s |
+pHoldup->GetMass()
|
+5 |
+
+Temperature of the outlet at t = 15 s |
+pOutStream->GetTemperature()
|
+300 |
+
+Molar mass of the holdup at t = 1 s |
+pHoldup->GetOverallProperty()
|
+0.06 |
+
+
+
+
+
Note
+
You will see the outlet temperature at 15 s is not changed to 320 K. In this process, only _dStartTime
and _dEndTime
are defined in the simulation (due to the simulation file of a steady-state process), the time point t = 15 s is not defined and thus no change will take place. If you add a time point for the outlet stream,
+
+pOutStream->AddTimePoint(15);
+
+
+
+
the temperature will change to 320 K at t = 15 s.
+
Therefore, please pay attention to your time points during the dynamic simulation. A time point must be defined in advance, at which your simulation is performed. However, in most cases, the time points during a simulation are calculated by the solvers and you don’t need to define them extra.
+
+
+
Note
+
You can also observe the temperature change at _dEndTime
to 320 K, like the code below:
+
+pOutStream->CopyFromHoldup(pHoldup, _dStartTime, 1);
+pOutStream->SetTemperature(_dEndTime, 320);
+// ... intermediate code ... //
+double outTemp = pOutStream->GetTemperature(_dEndTime);
+
+
+
+
In this case, the outlet temperature is still 300 K. The reason is that the default value of variable DeleteDataAfter
in CopyFromHoldup
is true
, which means the information at copied time (here _dStartTime
) is kept and those afterwards are deleted. Since there is no information at _dEndTime
, the program returns the temperature at _dStartTime
.
+
If you set the value of variable DeleteDataAfter
to false
, the outlet temperature doesn’t change either, because only the holdup information at _dStartTime
is copied, which has nothing to do with that at _dEndTime
. You must also copy the holdup info at the end in order to change the temperature at the end.
+
+pOutStream->CopyFromHoldup(pHoldup, _dStartTime, 1, false);
+pOutStream->CopyFromHoldup(pHoldup, _dEndTime, 1);
+pOutStream->SetTemperature(_dEndTime, 320);
+// ... intermediate code ... //
+double outTemp = pOutStream->GetTemperature(_dEndTime);
+
+
+
+
For developing dynamic units in Dyssol, don’t forget to treat your parameter at different time points separately.
+
+
+
+Solid distributed properties and PSD of streams and holdups:
+
+
+
+
+
+
+
+
+Parameter |
+Function |
+Expected value |
+
+
+
+ distribution of the holdup at t = 50 s |
+pHoldup->GetPSD(… PSD_Q3)
|
+(not applicable) |
+
+ distribution of the holdup at t = 50 s |
+pHoldup->GetPSD(… PSD_q3)
|
+(not applicable) |
+
+
+
+
+
+
+
+
+
+
+
+
+
+Development of dynamic units with internal DAE solver
+You can solve systems of DAE automatically in Dyssol system. In this case, the unit should contain one or several additional objects of CDAEModel
class. This class is used to describe DAE systems and can be automatically solved by class CDAESolver
.
+
+
+Constructor of the unit: called only once when unit is added to the flowsheet. In this function a set of parameters should be specified:
+
+Basic info:
+
+m_sUnitName
: Name of the unit that will be displayed in Dyssol.
+m_sAuthorName
: Unit’s author.
+m_sUniqueID
: Unique identificator of the unit. Simulation environment distinguishes different units with the help of this identificator. You must ensure that ID of your unit is unique. This ID can be created manually or using GUID-generator of Visual Studio (Tools → GUID Genarator).
+
+
+Specify ports: add new, rename or delete existing.
+If unit has some additionally parameters, than specify them here.
+Internal holdups and additional material streams can be defined here.
+All other operations, which should take place only once during the unit’s creation.
+
+
+
+Destructor of the unit: called only once when unit is removed from the flowsheet. Here all memory which has been previously allocated in the constructor should be freed.
+
+Unit::Initialize(double _dTime)
+
+
+Unit‘s initialization. This function is called only once at the start of the simulation. Starting from this point, information about defined compounds, phases, distributions, etc. are available for the unit. Here you can create state variables and initialize some additionaly objects (e.g. holdups, material streams or state variables).
+In this function, variables of all DAEModels should be specified by using function AddDAEVariable; connection between CDAEModel
and CDAESolver
classes should be created by calling function SetModel.
+
+Unit::Simulate(double _dStartTime, double _dEndTime)
+
+
+Dynamic calculation for a specified time interval. Is called for each time window on simulation interval. Calculation of the defined DAE-system can be run here by calling function DAESolver::Calculate()
.
+
+
+For flowsheets containing recycled streams, SaveState()
function is called when the convergence on the current time interval is reached, this also ensures the return to the previous state of the unit if convergence fails during the calculation. Here all internal time-dependent variables which weren’t added to the unit by using AddStateVariable, AddMaterialStream or AddHoldup functions should be manually saved. Implementation of this function is not obligatory and can be skipped.
+
+
+Load last state of the unit which has been saved with SaveState()
function. Implementation of this function is not obligatory and can be skipped.
+
+
+Unit‘s finalization. This function is called only once at the end of the simulation. Here one can perform closing and cleaning operations to prepare for the next possible simulation run. Implementation of this function is not obligatory and can be skipped.
+
+DAEModel::CalculateResiduals(double _dTime, double* _pVars, double* _pDers, double* _pRes, void* _pUserData)
+
+
+Here the DAE system should be specified in implicit form. This function will be called by solver automatically.
+
+DAEModel::ResultsHandler(double _dTime, double* _pVars, double* _pDers, void* _pUserData)
+
+
+Handling of results, which are returned from DAESolver
on each time point. Called by solver every time when the solution in a new time point is ready.
+
+
+Application example
+In this example, you will learn how to develop a dynamic screen model with a holdup, wherein the screening efficiency reduces with time and also depends on the holdup‘s mass. Additionally, the time dependency of screening efficiency should be plotted.
+The screening efficiency is calculated according to the equation below:
+
+
+
To complete the simulation, you need to solve the following dynamic equation system:
+
+
+
+
+
+
+
+
Note
+
Notations:
+
– separation sharpness (specified by user)
+
– cut size (specified by user)
+
– output mass flow (specified by user)
+
– time-dependent sharpness reduction factor [] (specified by user)
+
– mass-dependent sharpness reduction factor [] (specified by user)
+
– screening efficiency for particle of size class
+
– mass flow of coarse particles
+
– mass flow of fines particles
+
– input mass flow
+
– holdup mass
+
– particle diameter
+
+Now you need the following steps:
+
+Copy the directory with the template unit <PathToSolution>\ModelsCreatorSDK\UnitsTemplates\DynamicWithDAESolver\
to the directory for new units <PathToSolution>\ModelsCreatorSDK\Units\
. Rename the folder to ScreenTemplate
and the file DynamicWithDAESolver.vcxproj
to Screen.vcxproj
.
+Along with this application example, you obtain a pre-configured template folder of the air classifier unit ...\Task7\ScreenTemplate\
, in which you find the source file Unit.cpp
and header file Unit.h
. Copy the contents of them to the corresponding Unit.cpp
and Unit.h
files in your template folder <PathToSolution>\ModelsCreatorSDK\Units\ScreenTemplate\
.
+Open the template solution <PathToSolution>\ModelsCreatorSDK\Dyssol.sln
in Visual Studio.
+Add project with your new unit to the solution: select File → Add → Existing Project and specify path to the project file <PathToSolution>\ModelsCreatorSDK\Units\ScreenTemplate\
. Rename the unit to Unit_Screen
.
+Open Unit_AirClassifier
→ Unit.cpp
and extend the unit with the following functionality:
+
+
+
+Test your unit in Dyssol:
+
+
+Build the solution and run Dyssol: Build → Build Solution, and then Debug → Start Debugging.
+Use exemplary flowsheet ...\Task7\DynamicScreen.dflw
to test your unit. Compare your results with the expected ones in the figures below.
+
+
+
+
+
+
+
+
+
+
+
+
+Solver development
+You must do the following in order to develop your new solver (plese refer to Configuration of Visual Studio project template):
+
+
+Install Microsoft Visual Studio 2015 (Community).
+Configure template project ModelsCreatorSDK
.
+
+
+After builiding your own new solvers, the functionality of them can be applied in all units by adding them as unit parameters.
+Basically, all solvers have a set of constant functions and parameters, which are available in each new solver (label-externalSolver). and a set of specific ones, which depend on the solver’s type. New types of solvers can be added upon request and will include a set of parameters and functions that are needed to solve a specific problem.
+You can implement several solvers of one type (e.g. with different models) and then choose a specific one to use it in unit by user interface, please refer to section label-unitParameters in Models API.
+Please notice that in the current version of Dyssol, only Agglomeration solvers is available for solver development. The following solvers are implemented by means of open-source libraries connected to Dyssol and thus cannot be developed by yourself.
+
+
+
+
+Add new solver to the template project
+
+Copy the desired template of the unit from <PathToSolution>\ModelsCreatorSDK\SolversTemplates
to the folder Solvers
in solution (<PathToSolution>\ModelsCreatorSDK\Solvers
).
+Rename template’s folder according to the name of your new solver (further <MySolverFolder>
). The name can be chosen freely.
+Rename project files in template’s folder (*.vcxproj
, *.vcxproj.filters
) according to the name of the new solver.
+Run the solution file (<PathToSolution>\Dyssol.sln
) to open it in Visual Studio.
+Add project with your new solver to the solution. To do this, select in Visual Studio File → Add → Existing Project and specify path to the project file: <PathToSolution>\ModelsCreatorSDK\Solvers\<MySolverFolder>\<*.vcxproj>
.
+Rename added project in Visual Studio according to the name of your solver.
+
+Now you can implement functionality of your new solver. The list of available functions depends on type of selected solver.
+To build your solution press F7, to run it in debug mode press F5. Files with new solvers will be placed to <PathToSolution>\ModelsCreatorSDK\Debug
.
+As debug versions of compiled and built solvers contain a lot of additional information, which is used by Visual Studio to perform debugging, their calculation efficiency can be dramatically low. Thus, for the simulation purposes, solvers should be built in Release mode.
+
+
+
+
+Development of agglomeration solver
+Please refer to the background information label-agg and Agglomeration solvers when necessary.
+
+
+Constructor of the solver: called only once when solver is added to the unit. In this function, a set of parameters should be specified:
+
+Basic info:
+
+m_solverName
: Name of the solver that will be displayed in Dyssol.
+m_authorName
: Solver’s author.
+m_solverUniqueKey
: Unique identificator of the solver. Simulation environment distinguishes different solvers with the help of this identificator. You must ensure that ID of your solver is unique. This ID can be created manually or using GUID-generator of Visual Studio (Tools → GUID Genarator).
+
+
+All operations, which should take place only once during the solver’s creation.
+
+
+
+Destructor of the solver: called only once when solver is removed from the unit. Here all memory which has been previously allocated in the constructor should be freed.
+
+Solver::Initialize(vector<double> grid, double betta0, EKernels kernel, size_t rank, vector<double> params)
+
+
+Solver‘s initialization. This function is called only once for each simulation during the initialization of unit. All operations, which should take place only once after the solver’s creation should be implemented here. Implementation of this function is not obligatory and can be skipped.
+
+Solver::Calculate(vector<double> N, vector<double> BRate, vector<double> DRate)
+
+
+Calculation of birth and death rates depending on particle size distribution. All logic of the solver must be implemented here.
+
+
+Solver‘s finalization. This function is called only once for each simulation during the finalization of unti. Here one can perform closing and cleaning operations to prepare for the next possible simulation run. Implementation of this function is not obligatory and can be skipped.
+
+
+
+
+