(*
TestState is the main state variable for this program. Studio 5000
does not support enums, so we will use an integer instead
TYPE TestStates :
(
Waiting := 0, // wait for a test to start
SiteSpecific, // site specific actions, 1
Configure, // configure PLC Shift flow computers, 2
ConfirmConfig, // verify that configuration of flow runs is correct, 3
StartPurge, // start purge, 4
Purge, // wait for purge to complete, 5
StartBatch, // start batches at the flow computers, 6
Test, // wait for test to complete, 7
Stop, // stop was requested by the user, 8
Complete // test ended normally, 9
);
END_TYPE
*)
(* ************************************************************************ *)
(* Section get inputs *)
(* Map external inputs to internal tags *)
(* Manual mode 0, auto = 1 *)
(* In manual mode, the well on test is selected manually
and tests must be started manually. In auto mode,
the program cycles through all configured wells
automatically *)
ManualAutoMode := WellTest_Control_ManualAutoMode;
(* Map external start and stop bools to internal state variables *)
(* but only in manual mode *)
IF(ManualAutoMode = 0) THEN
StopTest := WellTest_Control_StopTest;
StartTest := WellTest_Control_StartTest;
END_IF;
(* well on test *)
WellOnTestIn := WellTest_Control_WellOnTestIn;
(* Get time from RTC *)
(* The number of microseconds elapsed since 0000 hours 1 January 1970. * )
(* split into 2 DINTs *)
(* it's hard to convert this into unix time on all platforms/versions so don't bother. *)
(* We could use AOIs to work with LINTs, but portability is better for a demo. *)
(* GSV(WallClockTime, , CurrentValue, CurrentTime[0]); *)
(* ************************************************************************ *)
(* ************************************************************************ *)
(* Section Main State Machine *)
(* main state machine. Do whatever is required depending on the internal state *)
IF(NOT(Connected) AND TestState <> 0) THEN (* Waiting = 0 *)
(* we are not connected and not in the waiting state,
stop the test, which will then take us to the waiting state
we can't leave the waiting state until we are connected *)
StopTest := 1;
END_IF;
IF(TestState = 0) THEN (* Waiting *)
(* waiting to start *)
IF(Connected) THEN
(* only leave this state if we are connected, otherwise don't do anything *)
IF(ManualAutoMode = 1) THEN
(* handle automatic mode *)
WellOnTestAuto := WellOnTestAuto + 1;
IF(WellOnTestAuto > 5) THEN
(* loop back around after max wells *)
WellOnTestAuto := 1;
END_IF;
(* start a test automatically in the waiting state when in auto mode *)
WellOnTestInternal := WellOnTestAuto;
WellOnTestOut := WellOnTestAuto;
WellOnTestIn := WellOnTestAuto;
(* copy the selected configuration to the internal struct *)
COP(WellConfigurations[WellOnTestIn - 1], WellConfig, 1);
//WellConfig := WellConfigurations[WellOnTestIn - 1];
TestTimeRemaining := 0;
StartTest := 1;
StopTest := 0;
TestState := 1; (* SiteSpecific *)
ELSE
(* handle manual mode *)
IF(WellOnTestIn >= 1 AND WellOnTestIn <= 5) THEN
(* always set the config so that the user sees the test info *)
(* even if the test is not started *)
(* copy the selected configuration to the internal struct *)
COP(WellConfigurations[WellOnTestIn - 1], WellConfig, 1);
//WellConfig := WellConfigurations[WellOnTestIn - 1];
END_IF;
IF(StartTest) THEN
IF(WellOnTestIn >= 1 AND WellOnTestIn <= 5) THEN
(* the well on test value is valid *)
(* cache the well on test internally so that *)
(* we're fine if the value changes during *)
(* the test. Also store the config *)
WellOnTestInternal := WellOnTestIn;
WellOnTestOut := WellOnTestIn;
TestTimeRemaining := 0;
TestState := 1; (* TestStates.SiteSpecific *)
ELSE
(* the well on test number is not valid, set start to false *)
StartTest := 0;
END_IF;
END_IF;
(* always force stop test to false in manual mode while waiting *)
StopTest := 0;
(* set batch control to all flow runs to 'Stop Batch' *)
GF01.Control.batchControl := 0;
LF01.Control.batchControl := 0;
WT01.Control.batchControl := 0;
WellOnTestAuto := 0;
(* end manual mode *)
END_IF;
END_IF;
(* end waiting state *)
ELSIF(TestState = 1) THEN (* TestStates.SiteSpecific *)
(* place holder state to do site specific work, like opening and closing valves, etc *)
IF(StopTest) THEN
(* user asked to stop *)
TestState := 8; (* TestStates.Stop *);
ELSE
(* do work here then move to the next state *)
TestState := 2; (* TestStates.Configure *);
END_IF;
(* end site specific *)
ELSIF(TestState = 2) THEN (* TestStates.Configure *)
(* configure the flow runs *)
IF(StopTest) THEN
(* user asked to stop *)
TestState := 8; (* TestStates.Stop *);
ELSE
(* push the configuration to the flow computers *)
(* gas *)
GF01.Compressibility.fractionMethane_w := WellConfig.GasFlowRunConfig.Compressibility_fractionMethane;
GF01.Compressibility.fractionNitrogen_w := WellConfig.GasFlowRunConfig.Compressibility_fractionNitrogen;
GF01.Compressibility.fractionCarbonDi_w := WellConfig.GasFlowRunConfig.Compressibility_fractionCarbonDi;
GF01.Compressibility.fractionEthane_w := WellConfig.GasFlowRunConfig.Compressibility_fractionEthane;
GF01.Compressibility.fractionPropane_w := WellConfig.GasFlowRunConfig.Compressibility_fractionPropane;
GF01.Compressibility.fractionIbutane_w := WellConfig.GasFlowRunConfig.Compressibility_fractionIbutane;
GF01.Compressibility.fractionNbutane_w := WellConfig.GasFlowRunConfig.Compressibility_fractionNbutane;
GF01.Compressibility.fractionIpentane_w := WellConfig.GasFlowRunConfig.Compressibility_fractionIpentane;
GF01.Compressibility.fractionNpentane_w := WellConfig.GasFlowRunConfig.Compressibility_fractionNpentane;
GF01.Compressibility.fractionNhexane_w := WellConfig.GasFlowRunConfig.Compressibility_fractionNhexane;
GF01.Compressibility.fractionNheptane_w := WellConfig.GasFlowRunConfig.Compressibility_fractionNheptane;
GF01.Compressibility.fractionNoctane_w := WellConfig.GasFlowRunConfig.Compressibility_fractionNoctane;
GF01.Compressibility.fractionNnonane_w := WellConfig.GasFlowRunConfig.Compressibility_fractionNnonane;
GF01.Compressibility.fractionNdecane_w := WellConfig.GasFlowRunConfig.Compressibility_fractionNdecane;
GF01.Compressibility.fractionHydrogen_w := WellConfig.GasFlowRunConfig.Compressibility_fractionHydrogen;
GF01.Compressibility.fractionOxygen_w := WellConfig.GasFlowRunConfig.Compressibility_fractionOxygen;
GF01.Compressibility.fractionCarbonMo_w := WellConfig.GasFlowRunConfig.Compressibility_fractionCarbonMo;
GF01.Compressibility.fractionWater_w := WellConfig.GasFlowRunConfig.Compressibility_fractionWater;
GF01.Compressibility.fractionH2s_w := WellConfig.GasFlowRunConfig.Compressibility_fractionH2s;
GF01.Compressibility.fractionHelium_w := WellConfig.GasFlowRunConfig.Compressibility_fractionHelium;
GF01.Compressibility.fractionArgon_w := WellConfig.GasFlowRunConfig.Compressibility_fractionArgon;
(* liquid *)
LF01.FlowCalculation.liqProdType_w := WellConfig.LiquidFlowRunConfig.LiquidProductType;
LF01.Inputs.densityType_w := WellConfig.LiquidFlowRunConfig.DensityType;
LF01.Inputs.fixedDensity_w := WellConfig.LiquidFlowRunConfig.FixedDensity;
LF01.FlowCalculation.baseDensityOil_w := WellConfig.LiquidFlowRunConfig.BaseDensityOil;
LF01.FlowCalculation.corrFactOil_w := WellConfig.LiquidFlowRunConfig.CorrectionFactorOil;
(* water *)
WT01.FlowCalculation.corrFactWater_w := WellConfig.WaterFlowRunConfig.CorrectionFactorWater;
(* set up asset ID. This allows us to link generated records together by asset ID *)
(* which makes reporting easy. *)
(* asset ID is just the well on test number. *)
(* First write to the preset tag then write to the 'set' tag so that app knows to process the value *)
(* gas *)
GF01.Control.assetIdPreset := WellOnTestInternal;
GF01.Control.setAssetId := 1;
(* liquid *)
LF01.Control.assetIdPreset := WellOnTestInternal;
LF01.Control.setAssetId := 1;
(* water *)
WT01.Control.assetIdPreset := WellOnTestInternal;
WT01.Control.setAssetId := 1;
(* batch user ID. All flow runs should have the same batch ID. *)
(* Use the 'Next Batch ID' parameter to see what the IDs are. If they *)
(* are not the same then choose the highest value and push that *)
(* out to the flow computers. It doesn't matter exactly what the ID is, *)
(* what matters is that they are the same for all runs *)
IF(GF01.FlowStatus.nextBatchUserId <> LF01.FlowStatus.nextBatchUserId OR
GF01.FlowStatus.nextBatchUserId <> WT01.FlowStatus.nextBatchUserId OR
LF01.FlowStatus.nextBatchUserId <> WT01.FlowStatus.nextBatchUserId) THEN
(* the batch user IDs are different, need to set them so that the next batch starts with the same IDs *)
(* Note that the parameter holds the next ID, not the last ID, so we want to preset to the next ID - 1 *)
BatchUserId := GF01.FlowStatus.nextBatchUserId;
IF(LF01.FlowStatus.nextBatchUserId > BatchUserId) THEN
BatchUserId := LF01.FlowStatus.nextBatchUserId;
END_IF;
IF(WT01.FlowStatus.nextBatchUserId > BatchUserId) THEN
BatchUserId := WT01.FlowStatus.nextBatchUserId;
END_IF;
(* BatchUserId should now have the highest value, we need to set this value in the flow computers *)
GF01.Control.batchUserIdPreset := BatchUserId;
GF01.Control.setBatchUserId := 1;
LF01.Control.batchUserIdPreset := BatchUserId;
LF01.Control.setBatchUserId := 1;
WT01.Control.batchUserIdPreset := BatchUserId;
WT01.Control.setBatchUserId := 1;
END_IF;
(* move to the next state *)
TestState := 3; (* TestStates.ConfirmConfig *);
(* reset counter as we enter the next state *)
ConfirmConfigCount := 0;
WellTest_Status_ConfigBad := 0;
END_IF;
(* end configure *)
ELSIF(TestState = 3) THEN (* TestStates.ConfirmConfig *)
IF(StopTest) THEN
(* user asked to stop *)
TestState := 8; (* TestStates.Stop *)
ELSE
(* wait 5 seconds before checking the configuration. We really only need a couple of seconds
but a longer wait allows the batch and asset IDs to get fully processed. When in
automatic mode, if a test fails, and then the next one is started, the asset
ID does not get processed properly. 5000 ms / 200 ms callback time = 25 callbacks
There are two ways to validate that the flow computers are configured correctly:
1. Check the "config invalid" tag for each group of interest
2. Check that the _r tag matches the _w tag. This means that the config change was accepted by the app
We'll just do number 1 for the demo, but number 2 allows you to pinpoint which parameter(s) were not accepted *)
ConfirmConfigCount := ConfirmConfigCount + 1;
IF(ConfirmConfigCount > 25) THEN
WellTest_Status_ConfigBad :=
GF01.ConfigurationGroupStatus.compressGrpInVld OR
LF01.ConfigurationGroupStatus.flwCalcGrpVld OR
LF01.ConfigurationGroupStatus.inputGrpVld OR
WT01.ConfigurationGroupStatus.flwCalcGrpVld;
IF(WellTest_Status_ConfigBad) THEN
(* the configuration is not good.
stop. Add additional error codes or logging here *)
StopTest := 1;
TestState := 8; (* TestStates.Stop *)
ELSE
(* move to the next state *)
TestState := 4; (* TestStates.StartPurge *)
PurgeComplete := 0;
END_IF;
END_IF;
END_IF;
(* end confirm config *)
ELSIF(TestState = 4) THEN (* TestStates.StartPurge *)
IF(StopTest) THEN
(* user asked to stop *)
TestState := 8; (* TestStates.Stop *)
ELSE
(* send the purge start command to all flow runs *)
GF01.Control.batchControl := 1;
LF01.Control.batchControl := 1;
WT01.Control.batchControl := 1;
(* go to the next state *)
TestState := 5; (* TestStates.Purge *)
END_IF;
(* end start purge *)
ELSIF(TestState = 5) THEN (* TestStates.Purge *)
IF(StopTest) THEN
(* user asked to stop *)
TestState := 8; (* TestStates.Stop *)
ELSE
(* wait until purge is complete *)
(* check the actual purge volumes against the configured limits *)
(* When all flow runs have exceeded their limit, move to the next state *)
PurgeComplete := GF01.BatchCurrentStatus.prgVolBase >= WellConfig.PurgeVolumeGas AND
LF01.BatchStatus.prgVol >= WellConfig.PurgeVolumeLiquid AND
WT01.BatchStatus.prgVol >= WellConfig.PurgeVolumeWater;
IF(PurgeComplete) THEN
(* go to the next state *)
TestState := 6; (* TestStates.StartBatch *)
END_IF;
END_IF;
(* end of purge *)
ELSIF(TestState = 6) THEN (* TestStates.StartBatch *)
IF(StopTest) THEN
(* user asked to stop *)
TestState := 8; (* TestStates.Stop *)
ELSE
(* send the start batch command for all runs *)
GF01.Control.batchControl := 2;
LF01.Control.batchControl := 2;
WT01.Control.batchControl := 2;
(* Getting unix time is hard so just use a duration *)
(* Ideally we would set the test start time to unix time *)
TestStartTime := 0;
(* clear values that we use to determine test elapsed time *)
TestTimeCallbacks := 0;
TestTimeS := 0;
(* test duration is stored as seconds *)
TestEndTime := TestStartTime + WellConfig.TestDuration;
TestTimeRemaining := WellConfig.TestDuration;
(* go to the next state *)
TestState := 7; (* TestStates.Test *)
END_IF;
(* end start batch *)
ELSIF(TestState = 7) THEN (* TestStates.Test *)
IF(StopTest) THEN
(* user asked to stop *)
TestState := 8; (* TestStates.Stop *)
ELSE
(* calculate test time remaining *)
(* assume an periodic task at 200 ms *)
(* 5 callbacks = 1 second *)
TestTimeCallbacks := TestTimeCallbacks + 1;
IF(TestTimeCallbacks >= 5) THEN
TestTimeCallbacks := 0;
TestTimeS := TestTimeS + 1;
END_IF;
IF(TestEndTime > TestTimeS) THEN
TestTimeRemaining := TestEndTime - TestTimeS;
ELSE
TestTimeRemaining := 0;
END_IF;
(* see if we have exceeded the configured test time, and if so, stop the test *)
(* IF (GF01_bchElapsedTime.VALUE >= UDINT_TO_REAL(WellConfig.TestDuration)) THEN *)
IF(TestTimeRemaining = 0) THEN
(* Stop batches *)
GF01.Control.batchControl := 0;
LF01.Control.batchControl := 0;
WT01.Control.batchControl := 0;
(* go to the next state *)
TestState := 9; (* TestStates.Complete *)
END_IF;
END_IF;
(* end test state *)
ELSIF(TestState = 9) THEN (* TestStates.Complete *)
(* do things when the test ends normally, clear state markers and go back to waiting state *)
TestTimeRemaining := 0;
TestStartTime := 0;
TestEndTime := 0;
(* TestStartTimeLocalDt := TO_DT(TestStartTimeLocal); *)
(* TestEndTimeLocalDt := TO_DT(TestEndTimeLocal); *)
CompleteDelayCount := CompleteDelayCount + 1;
IF(CompleteDelayCount >= 10) THEN
(* change state after some delay *)
CompleteDelayCount := 0;
TestState := 0; (* TestStates.Waiting *)
END_IF;
(* end complete state *)
ELSIF(TestState = 8) THEN (* TestStates.Stop *)
(* stop was requested by the user *)
(* stop batches, clear state markers and go back to waiting state *)
GF01.Control.batchControl := 0;
LF01.Control.batchControl := 0;
WT01.Control.batchControl := 0;
TestTimeRemaining := 0;
TestStartTime := 0;
TestEndTime := 0;
(* TestStartTimeLocalDt := TO_DT(TestStartTimeLocal); *)
(* TestEndTimeLocalDt := TO_DT(TestEndTimeLocal); *)
StopDelayCount := StopDelayCount + 1;
IF(StopDelayCount >= 10) THEN
(* change state after some delay *)
StopDelayCount := 0;
TestState := 0; (* TestStates.Waiting *)
END_IF;
(* end stop state *)
END_IF;
(* end main state machine *)
(* ************************************************************************ *)
(* ************************************************************************ *)
(* Section Connection State *)
(* check connection state of apps. Wait x callbacks and see if the exec count for each app is increasing *)
(* Copy 64 bit values to an array of DINT so that we can work with the values*)
COP(GF01.ApplicationInfo.execCount, GfExecCount_DINT[0], 2);
COP(LF01.ApplicationInfo.execCount, LfExecCount_DINT[0], 2);
COP(WT01.ApplicationInfo.execCount, WtExecCount_DINT[0], 2);
(* check connection state of apps. Wait 50 callbacks and see if the exec count for each app is changing *)
IF(ConnectedCounter >= 50) then
(* The delay timer has expired. Reset the delay timer
and then see if we're connected by comparing the execution counts
to the execution counts from the last time that we executed
this code section *)
ConnectedCounter := 0;
(* an app is connected if the counts have changed *)
GasFlowConnected := GfExecCount_DINT[0] <> GasLastExecCount;
LiquidFlowConnected := LfExecCount_DINT[0] <> LiquidLastExecCount;
WaterFlowConnected := WtExecCount_DINT[0] <> WaterLastExecCount;
(* store counts for next time *)
GasLastExecCount := GfExecCount_DINT[0];
LiquidLastExecCount := LfExecCount_DINT[0];
WaterLastExecCount := WtExecCount_DINT[0];
END_IF;
(* always increment the delay counter *)
ConnectedCounter := ConnectedCounter + 1;
(* connected is true only if all apps are connected *)
Connected := GasFlowConnected AND LiquidFlowConnected AND WaterFlowConnected;
(* ************************************************************************ *)
(* ************************************************************************ *)
(* Section Alarms Active *)
(* get the overall alarm status. Set the bool active if there *)
(* are any alarms on any run. More granular information is *)
(* available from each app if so desired. Each alarm type *)
(* has an individual status tag. *)
(* Only let this go true if we are actually connected. When *)
(* not connected, this will always be false. *)
FlowComputerAlarmsActive := (GF01.InputAlarmStatus.alarmActive OR
LF01.InputAlarmStatus.alarmActive OR
WT01.InputAlarmStatus.alarmActive) AND
Connected;
(* ************************************************************************ *)
(* ************************************************************************ *)
(* Section write outputs *)
(* Write internal tag values to output tags that are visible in RC *)
WellTest_Status_ConnectedToApps := Connected;
(* there is an alarm active for each flow run. This is an aggregated value *)
WellTest_Status_AlarmsActive := FlowComputerAlarmsActive;
WellTest_Status_WellOnTest := WellOnTestInternal;
WellTest_Status_TestTimeRemain := TestTimeRemaining;
(* test state *)
WellTest_Status_TestState := TestState;
(* purge volumes *)
WellTest_Status_GasPurgeLimit := WellConfig.PurgeVolumeGas;
WellTest_Status_LiquidPurgeLimit := WellConfig.PurgeVolumeLiquid;
WellTest_Status_WaterPurgeLimit := WellConfig.PurgeVolumeWater;
(* ************************************************************************ *)
(* ************************************************************************ *)
(* Section copy configs *)
(* This function moves configuration values from tags into the
internal configuration array. Later on, the user selects the
well to test and the configuration is loaded from the internal
array and then pushed out to the flow computer *)
IF(WellTest_Cfg_UpdateCfg) THEN
(* Clear the request since we are processing it *)
WellTest_Cfg_UpdateCfg := 0;
IF(WellTest_Cfg_CfgToUpdate >= 1 AND WellTest_Cfg_CfgToUpdate <= 32) THEN
(* The value is within range of the array that we we have allocated. *)
WellTestCfgIndex := WellTest_Cfg_CfgToUpdate - 1;
(* Possibly add some additional validation here, but maybe in the UI is a better place *)
(* overall settings *)
WellConfigurations[WellTestCfgIndex].WellNumber := WellTestCfgIndex;
WellConfigurations[WellTestCfgIndex].PurgeVolumeGas := WellTest_Cfg_GfPurgeVolLim;
WellConfigurations[WellTestCfgIndex].PurgeVolumeLiquid := WellTest_Cfg_LfPurgeVolLim;
WellConfigurations[WellTestCfgIndex].PurgeVolumeWater := WellTest_Cfg_WtPurgeVolLim;
WellConfigurations[WellTestCfgIndex].TestDuration := WellTest_Cfg_TestDuration; (* seconds *)
(* gas *)
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionMethane := WellTest_Cfg_GfMethane;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionNitrogen := WellTest_Cfg_GfNitrogen;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionCarbonDi := WellTest_Cfg_GfCarbonDi;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionEthane := WellTest_Cfg_GfEthane;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionPropane := WellTest_Cfg_GfPropane;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionWater := WellTest_Cfg_GfWater;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionH2s := WellTest_Cfg_GfH2s;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionHydrogen := WellTest_Cfg_GfHydrogen;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionCarbonMo := WellTest_Cfg_GfCarbonMo;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionOxygen := WellTest_Cfg_GfOxygen;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionIbutane := WellTest_Cfg_GfiButane;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionNbutane := WellTest_Cfg_GfnButane;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionIpentane := WellTest_Cfg_GfiPentane;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionNpentane := WellTest_Cfg_GfnPentane;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionNhexane := WellTest_Cfg_GfnHexane;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionNheptane := WellTest_Cfg_GfnHeptane;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionNoctane := WellTest_Cfg_GfnOctane;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionNnonane := WellTest_Cfg_GfnNonane;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionNdecane := WellTest_Cfg_GfnDecane;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionHelium := WellTest_Cfg_GfHelium;
WellConfigurations[WellTestCfgIndex].GasFlowRunConfig.Compressibility_fractionArgon := WellTest_Cfg_GfArgon;
(* liquid *)
WellConfigurations[WellTestCfgIndex].LiquidFlowRunConfig.DensityType := WellTest_Cfg_LfDensityType;
WellConfigurations[WellTestCfgIndex].LiquidFlowRunConfig.FixedDensity := WellTest_Cfg_LfFixedDensity;
WellConfigurations[WellTestCfgIndex].LiquidFlowRunConfig.LiquidProductType := WellTest_Cfg_LfProductType;
WellConfigurations[WellTestCfgIndex].LiquidFlowRunConfig.CorrectionFactorOil := WellTest_Cfg_LfCorrFactorOil;
WellConfigurations[WellTestCfgIndex].LiquidFlowRunConfig.BaseDensityOil := WellTest_Cfg_LfBaseDensityOil;
(* water *)
WellConfigurations[WellTestCfgIndex].WaterFlowRunConfig.CorrectionFactorWater := WellTest_Cfg_WtCorrFactorWater;
END_IF;
END_IF;
(* ************************************************************************ *)
(* ************************************************************************ *)
(* Section Well Configurations *)
(* configure wells to test *)
(* do this once when the *)
(* program is started *)
IF LoadConfigurations THEN
(* only load configurations once *)
LoadConfigurations := 0;
(* *********************************************************************************** *)
(* well 1, index 0 *)
WellConfigurations[0].WellNumber := 0;
WellConfigurations[0].PurgeVolumeGas := 1.0; (* m3 *)
WellConfigurations[0].PurgeVolumeLiquid := 0.5; (* m3 *)
WellConfigurations[0].PurgeVolumeWater := 0.5; (* m3 *)
WellConfigurations[0].TestDuration := 600; (* seconds *)
(* gas *)
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionMethane := 0.79675;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionNitrogen := 0.0081;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionCarbonDi := 0.016;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionEthane := 0.00525;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionPropane := 0.01805;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionWater := 0.01862;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionH2s := 0.01772;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionHydrogen := 0.00985;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionCarbonMo := 0.00798;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionOxygen := 0.00306;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionIbutane := 0.00462;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionNbutane := 0.01882;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionIpentane := 0.00796;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionNpentane := 0.01444;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionNhexane := 0.00078;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionNheptane := 0.01479;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionNoctane := 0.00297;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionNnonane := 0.00868;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionNdecane := 0.00885;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionHelium := 0.00991;
WellConfigurations[0].GasFlowRunConfig.Compressibility_fractionArgon := 0.0068;
(* liquid *)
WellConfigurations[0].LiquidFlowRunConfig.DensityType := 0; (* live density *)
WellConfigurations[0].LiquidFlowRunConfig.FixedDensity := 757.43;
WellConfigurations[0].LiquidFlowRunConfig.LiquidProductType := 0; (* crude oil *)
WellConfigurations[0].LiquidFlowRunConfig.CorrectionFactorOil := 1.0;
WellConfigurations[0].LiquidFlowRunConfig.BaseDensityOil := 600.0; (* kg/m3 *)
(* water *)
WellConfigurations[0].WaterFlowRunConfig.CorrectionFactorWater := 1.0;
(* end well 1, index 0 *)
(* *********************************************************************************** *)
(* *********************************************************************************** *)
(* well 2, index 1 *)
WellConfigurations[1].WellNumber := 1;
WellConfigurations[1].PurgeVolumeGas := 1.0; (* m3 *)
WellConfigurations[1].PurgeVolumeLiquid := 0.25; (* m3 *)
WellConfigurations[1].PurgeVolumeWater := 0.25; (* m3 *)
WellConfigurations[1].TestDuration := 300; (* seconds *)
(* gas *)
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionMethane := 0.81754;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionNitrogen := 0.01956;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionCarbonDi := 0.0089;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionEthane := 0.00935;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionPropane := 0.0159;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionWater := 0.00993;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionH2s := 0.01296;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionHydrogen := 0.00015;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionCarbonMo := 0.00269;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionOxygen := 0.01688;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionIbutane := 0.00436;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionNbutane := 0.00203;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionIpentane := 0.01276;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionNpentane := 0.01413;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionNhexane := 0.00825;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionNheptane := 0.0125;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionNoctane := 0.00165;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionNnonane := 0.00345;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionNdecane := 0.0;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionHelium := 0.01903;
WellConfigurations[1].GasFlowRunConfig.Compressibility_fractionArgon := 0.00798;
(* liquid *)
WellConfigurations[1].LiquidFlowRunConfig.DensityType := 1; (* fixed density *)
WellConfigurations[1].LiquidFlowRunConfig.FixedDensity := 612.43;
WellConfigurations[1].LiquidFlowRunConfig.LiquidProductType := 4; (* gasoline is unrealistic for a test, but this is just a demo *)
WellConfigurations[1].LiquidFlowRunConfig.CorrectionFactorOil := 1.1;
WellConfigurations[1].LiquidFlowRunConfig.BaseDensityOil := 650.0;
(* water *)
WellConfigurations[1].WaterFlowRunConfig.CorrectionFactorWater := 0.9;
(* end well 2, index 1 *)
(* *********************************************************************************** *)
(* *********************************************************************************** *)
(* well 3, index 2 *)
(* this gas composition is intentionally bad and cannot be loaded. *)
WellConfigurations[2].WellNumber := 2;
WellConfigurations[2].PurgeVolumeGas := 2.0; (* m3 *)
WellConfigurations[2].PurgeVolumeLiquid := 1.0; (* m3 *)
WellConfigurations[2].PurgeVolumeWater := 0.0; (* m3 *)
WellConfigurations[2].TestDuration := 600; (* seconds *)
(* gas *)
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionMethane := 0.7776;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionNitrogen := 0.00721;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionCarbonDi := 0.01813;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionEthane := 0.01355;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionPropane := 0.01582;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionWater := 0.01552;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionH2s := 0.00772;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionHydrogen := 0.01785;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionCarbonMo := 0.01898;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionOxygen := 0.00926;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionIbutane := 0.01662;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionNbutane := 0.01962;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionIpentane := 0.01296;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionNpentane := 0.01944;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionNhexane := 0.01678;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionNheptane := 0.01779;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionNoctane := 0.00917;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionNnonane := 0.01828;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionNdecane := 0.01475;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionHelium := 0.00991;
WellConfigurations[2].GasFlowRunConfig.Compressibility_fractionArgon := 0.01280;
(* liquid *)
WellConfigurations[2].LiquidFlowRunConfig.DensityType := 1; (* fixed density *)
WellConfigurations[2].LiquidFlowRunConfig.FixedDensity := 980.13;
WellConfigurations[2].LiquidFlowRunConfig.LiquidProductType := 1; (* diesel *)
WellConfigurations[2].LiquidFlowRunConfig.CorrectionFactorOil := 1.3;
WellConfigurations[2].LiquidFlowRunConfig.BaseDensityOil := 640.0;
(* water *)
WellConfigurations[2].WaterFlowRunConfig.CorrectionFactorWater := 1.05;
(* end well 3, index 2 *)
(* *********************************************************************************** *)
(* *********************************************************************************** *)
(* well 4, index 3 *)
WellConfigurations[3].WellNumber := 3;
WellConfigurations[3].PurgeVolumeGas := 1.0; (* m3 *)
WellConfigurations[3].PurgeVolumeLiquid := 1.0; (* m3 *)
WellConfigurations[3].PurgeVolumeWater := 1.0; (* m3 *)
WellConfigurations[3].TestDuration := 450; (* seconds *)
(* gas *)
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionMethane := 0.81061;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionNitrogen := 0.00518;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionCarbonDi := 0.00786;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionEthane := 0.0173;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionPropane := 0.01503;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionWater := 0.00918;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionH2s := 0.00871;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionHydrogen := 0.00875;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionCarbonMo := 0.00554;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionOxygen := 0.01932;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionIbutane := 0.00343;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionNbutane := 0.01543;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionIpentane := 0.003;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionNpentane := 0.01873;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionNhexane := 0.0102;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionNheptane := 0.00698;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionNoctane := 0.00261;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionNnonane := 0.00244;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionNdecane := 0.01714;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionHelium := 0.00825;
WellConfigurations[3].GasFlowRunConfig.Compressibility_fractionArgon := 0.00431;
(* liquid *)
WellConfigurations[1].LiquidFlowRunConfig.DensityType := 0; (* live density *)
WellConfigurations[3].LiquidFlowRunConfig.FixedDensity := 703.2;
WellConfigurations[3].LiquidFlowRunConfig.LiquidProductType := 0; (* crude oil *)
WellConfigurations[3].LiquidFlowRunConfig.CorrectionFactorOil := 1.0;
WellConfigurations[3].LiquidFlowRunConfig.BaseDensityOil := 700.0;
(* water *)
WellConfigurations[3].WaterFlowRunConfig.CorrectionFactorWater := 1.2;
(* end well 4, index 3 *)
(* *********************************************************************************** *)
(* *********************************************************************************** *)
(* well 5, index 4 *)
WellConfigurations[4].WellNumber := 4;
WellConfigurations[4].PurgeVolumeGas := 1.5; (* m3 *)
WellConfigurations[4].PurgeVolumeLiquid := 1.5; (* m3 *)
WellConfigurations[4].PurgeVolumeWater := 1.5; (* m3 *)
WellConfigurations[4].TestDuration := 150; (* seconds *)
(* gas *)
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionMethane := 0.84489;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionNitrogen := 0.0153;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionCarbonDi := 0.00023;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionEthane := 0.00564;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionPropane := 0.00318;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionWater := 0.00757;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionH2s := 0.00477;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionHydrogen := 0.01197;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionCarbonMo := 0.00725;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionOxygen := 0.00178;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionIbutane := 0.00229;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionNbutane := 0.01697;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionIpentane := 0.01493;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionNpentane := 0.01806;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionNhexane := 0.0093;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionNheptane := 0.01125;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionNoctane := 0.01047;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionNnonane := 0.0;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionNdecane := 0.0;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionHelium := 0.01415;
WellConfigurations[4].GasFlowRunConfig.Compressibility_fractionArgon := 0.0;
(* liquid *)
WellConfigurations[4].LiquidFlowRunConfig.DensityType := 1; (* fixed density *)
WellConfigurations[4].LiquidFlowRunConfig.FixedDensity := 804.76;
WellConfigurations[4].LiquidFlowRunConfig.LiquidProductType := 1; (* fuel oil *)
WellConfigurations[4].LiquidFlowRunConfig.CorrectionFactorOil := 1.0;
WellConfigurations[4].LiquidFlowRunConfig.BaseDensityOil := 605.0;
(* water *)
WellConfigurations[4].WaterFlowRunConfig.CorrectionFactorWater := 1.0;
(* end well 4, index 5 *)
(* *********************************************************************************** *)
(* *********************************************************************************** *)
(* Section Well Configuration End *)
END_IF;