From aaaa187eb9fcdf98a49f8b95ab3fc73967607796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85smund=20V=C3=A5ge=20Fannemel?= <34712686+asmfstatoil@users.noreply.github.com> Date: Fri, 8 Aug 2025 18:42:01 +0200 Subject: [PATCH 1/2] feat: support loop mode to not add processequipment to processoperations when they are created refact: removed folder level src --- .gitignore | 3 + .pre-commit-config.yaml | 4 +- examples/propertiesDataframes.py | 18 +-- {src/neqsim => neqsim}/__init__.py | 1 - .../lib/java11/neqsim-3.0.36.jar | Bin .../lib/java8/neqsim-3.0.36-Java8.jar | Bin {src/neqsim => neqsim}/neqsimpython.py | 0 {src/neqsim => neqsim}/process/__init__.py | 0 {src/neqsim => neqsim}/process/measurement.py | 0 .../neqsim => neqsim}/process/processTools.py | 125 ++++++++++++------ {src/neqsim => neqsim}/process/unitop.py | 0 {src/neqsim => neqsim}/standards/__init__.py | 0 .../standards/standardTools.py | 0 {src/neqsim => neqsim}/thermo/__init__.py | 0 {src/neqsim => neqsim}/thermo/thermoTools.py | 6 +- pyproject.toml | 2 +- tests/process/test_ProcessTools.py | 33 +++++ 17 files changed, 137 insertions(+), 55 deletions(-) rename {src/neqsim => neqsim}/__init__.py (99%) rename {src/neqsim => neqsim}/lib/java11/neqsim-3.0.36.jar (100%) rename {src/neqsim => neqsim}/lib/java8/neqsim-3.0.36-Java8.jar (100%) rename {src/neqsim => neqsim}/neqsimpython.py (100%) rename {src/neqsim => neqsim}/process/__init__.py (100%) rename {src/neqsim => neqsim}/process/measurement.py (100%) rename {src/neqsim => neqsim}/process/processTools.py (87%) rename {src/neqsim => neqsim}/process/unitop.py (100%) rename {src/neqsim => neqsim}/standards/__init__.py (100%) rename {src/neqsim => neqsim}/standards/standardTools.py (100%) rename {src/neqsim => neqsim}/thermo/__init__.py (100%) rename {src/neqsim => neqsim}/thermo/thermoTools.py (99%) diff --git a/.gitignore b/.gitignore index e61c1a88..7134020a 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,6 @@ ENV/ # SNYK .dccache poetry.lock + +test_gasoilprocess.zip +test_gasoilprocess.neqsim diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fe35b9ee..6260e94b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,13 +2,13 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.2.0 + rev: v5.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - id: check-added-large-files - repo: https://github.com/psf/black - rev: 23.12.1 + rev: 24.10.0 hooks: - id: black diff --git a/examples/propertiesDataframes.py b/examples/propertiesDataframes.py index 1518f5ef..dc64f4f0 100644 --- a/examples/propertiesDataframes.py +++ b/examples/propertiesDataframes.py @@ -146,9 +146,9 @@ def calcProperties(frame): frame["gasmolfraction[mol/mol]"] = gascondensateFluid.getMoleFraction( phaseNumber ) - frame[ - "gasvolumefraction[mol/mol]" - ] = gascondensateFluid.getCorrectedVolumeFraction(phaseNumber) + frame["gasvolumefraction[mol/mol]"] = ( + gascondensateFluid.getCorrectedVolumeFraction(phaseNumber) + ) frame["gasthermalconductivity[W/mK]"] = gascondensateFluid.getPhase( phaseNumber ).getThermalConductivity("W/mK") @@ -164,9 +164,9 @@ def calcProperties(frame): frame["oilmolfraction[mol/mol]"] = gascondensateFluid.getMoleFraction( phaseNumber ) - frame[ - "oilvolumefraction[mol/mol]" - ] = gascondensateFluid.getCorrectedVolumeFraction(phaseNumber) + frame["oilvolumefraction[mol/mol]"] = ( + gascondensateFluid.getCorrectedVolumeFraction(phaseNumber) + ) frame["oilthermalconductivity[W/mK]"] = gascondensateFluid.getPhase( phaseNumber ).getThermalConductivity("W/mK") @@ -179,9 +179,9 @@ def calcProperties(frame): frame["oilmolfraction[mol/mol]"] = gascondensateFluid.getMoleFraction( phaseNumber ) - frame[ - "oilvolumefraction[mol/mol]" - ] = gascondensateFluid.getCorrectedVolumeFraction(phaseNumber) + frame["oilvolumefraction[mol/mol]"] = ( + gascondensateFluid.getCorrectedVolumeFraction(phaseNumber) + ) frame["oilthermalconductivity[W/mK]"] = gascondensateFluid.getPhase( phaseNumber ).getThermalConductivity("W/mK") diff --git a/src/neqsim/__init__.py b/neqsim/__init__.py similarity index 99% rename from src/neqsim/__init__.py rename to neqsim/__init__.py index e68cef9d..a6b0d5e6 100644 --- a/src/neqsim/__init__.py +++ b/neqsim/__init__.py @@ -5,7 +5,6 @@ """ from neqsim.neqsimpython import jneqsim, jpype -import gzip def methods(checkClass): diff --git a/src/neqsim/lib/java11/neqsim-3.0.36.jar b/neqsim/lib/java11/neqsim-3.0.36.jar similarity index 100% rename from src/neqsim/lib/java11/neqsim-3.0.36.jar rename to neqsim/lib/java11/neqsim-3.0.36.jar diff --git a/src/neqsim/lib/java8/neqsim-3.0.36-Java8.jar b/neqsim/lib/java8/neqsim-3.0.36-Java8.jar similarity index 100% rename from src/neqsim/lib/java8/neqsim-3.0.36-Java8.jar rename to neqsim/lib/java8/neqsim-3.0.36-Java8.jar diff --git a/src/neqsim/neqsimpython.py b/neqsim/neqsimpython.py similarity index 100% rename from src/neqsim/neqsimpython.py rename to neqsim/neqsimpython.py diff --git a/src/neqsim/process/__init__.py b/neqsim/process/__init__.py similarity index 100% rename from src/neqsim/process/__init__.py rename to neqsim/process/__init__.py diff --git a/src/neqsim/process/measurement.py b/neqsim/process/measurement.py similarity index 100% rename from src/neqsim/process/measurement.py rename to neqsim/process/measurement.py diff --git a/src/neqsim/process/processTools.py b/neqsim/process/processTools.py similarity index 87% rename from src/neqsim/process/processTools.py rename to neqsim/process/processTools.py index 79bdf351..e834e084 100644 --- a/src/neqsim/process/processTools.py +++ b/neqsim/process/processTools.py @@ -1,11 +1,12 @@ -import jpype import json -import jpype.imports +from jpype.types import JDouble from jpype.types import * + from neqsim.neqsimpython import jneqsim processoperations = jneqsim.process.processmodel.ProcessSystem() +_loop_mode = False def newProcess(name=""): @@ -17,6 +18,17 @@ def newProcess(name=""): return processoperations +def set_loop_mode(loop_mode): + """ + Set the loop mode for process operations. + + Parameters: + loop_mode (bool): If True, sets the loop mode to allow multiple runs without clearing the process. + """ + global _loop_mode + _loop_mode = loop_mode + + def stream(name, thermoSystem, t=0, p=0): """ Create a stream with the given name and thermodynamic system, optionally setting temperature and pressure. @@ -35,7 +47,8 @@ def stream(name, thermoSystem, t=0, p=0): if p != 0: thermoSystem.setPressure(p) stream = jneqsim.process.equipment.stream.Stream(name, thermoSystem) - processoperations.add(stream) + if not _loop_mode: + processoperations.add(stream) return stream @@ -51,7 +64,8 @@ def virtualstream(name, streamIn): VirtualStream: The created virtual stream object. """ stream = jneqsim.process.equipment.stream.VirtualStream(name, streamIn) - processoperations.add(stream) + if not _loop_mode: + processoperations.add(stream) return stream @@ -74,7 +88,8 @@ def neqstream(name, thermoSystem, t=0, p=0): thermoSystem.setPressure(p) stream = jneqsim.process.equipment.stream.NeqStream(name, thermoSystem) stream.setName(name) - processoperations.add(stream) + if not _loop_mode: + processoperations.add(stream) return stream @@ -92,7 +107,8 @@ def recycle(name, stream=None): recycle1 = jneqsim.process.equipment.util.Recycle(name) if not stream is None: recycle1.addStream(stream) - processoperations.add(recycle1) + if not _loop_mode: + processoperations.add(recycle1) return recycle1 @@ -110,7 +126,8 @@ def saturator(name, teststream): streamsaturator = jneqsim.process.equipment.util.StreamSaturatorUtil( name, teststream ) - processoperations.add(streamsaturator) + if not _loop_mode: + processoperations.add(streamsaturator) return streamsaturator @@ -119,7 +136,8 @@ def glycoldehydrationlmodule(name, teststream): jneqsim.process.processmodel.processModules.GlycolDehydrationlModule(name) ) dehydrationlmodule.addInputStream("gasStreamToAbsorber", teststream) - processoperations.add(dehydrationlmodule) + if not _loop_mode: + processoperations.add(dehydrationlmodule) return dehydrationlmodule @@ -141,7 +159,8 @@ def separator(name, teststream): """ separator = jneqsim.process.equipment.separator.Separator(name, teststream) separator.setName(name) - processoperations.add(separator) + if not _loop_mode: + processoperations.add(separator) return separator @@ -158,28 +177,32 @@ def GORfitter(name, teststream): """ GORfitter1 = jneqsim.process.equipment.util.GORfitter(name, teststream) GORfitter1.setName(name) - processoperations.add(GORfitter1) + if not _loop_mode: + processoperations.add(GORfitter1) return GORfitter1 def simpleTEGAbsorber(name): absorber = jneqsim.process.equipment.absorber.SimpleTEGAbsorber(name) absorber.setName(name) - processoperations.add(absorber) + if not _loop_mode: + processoperations.add(absorber) return absorber def waterStripperColumn(name): stripper = jneqsim.process.equipment.absorber.WaterStripperColumn(name) stripper.setName(name) - processoperations.add(stripper) + if not _loop_mode: + processoperations.add(stripper) return stripper def gasscrubber(name, teststream): separator = jneqsim.process.equipment.separator.GasScrubber(name, teststream) separator.setName(name) - processoperations.add(separator) + if not _loop_mode: + processoperations.add(separator) return separator @@ -198,7 +221,8 @@ def separator3phase(name, teststream): name, teststream ) separator.setName(name) - processoperations.add(separator) + if not _loop_mode: + processoperations.add(separator) return separator @@ -217,25 +241,29 @@ def valve(name, teststream, p=1.0): valve = jneqsim.process.equipment.valve.ThrottlingValve(name, teststream) valve.setOutletPressure(p) valve.setName(name) - processoperations.add(valve) + if not _loop_mode: + processoperations.add(valve) return valve def calculator(name): calc2 = jneqsim.process.equipment.util.Calculator(name) - processoperations.add(calc2) + if not _loop_mode: + processoperations.add(calc2) return calc2 def setpoint(name1, unit1, name2, unit2): setp = jneqsim.process.equipment.util.SetPoint(name1, unit1, name2, unit2) - processoperations.add(setp) + if not _loop_mode: + processoperations.add(setp) return setp def filters(name, teststream): filter2 = jneqsim.process.equipment.filter.Filter(name, teststream) - processoperations.add(filter2) + if not _loop_mode: + processoperations.add(filter2) return filter2 @@ -253,7 +281,8 @@ def compressor(name, teststream, pres=10.0): """ compressor = jneqsim.process.equipment.compressor.Compressor(name, teststream) compressor.setOutletPressure(pres) - processoperations.add(compressor) + if not _loop_mode: + processoperations.add(compressor) return compressor @@ -305,7 +334,8 @@ def pump(name, teststream, p=1.0): """ pump = jneqsim.process.equipment.pump.Pump(name, teststream) pump.setOutletPressure(p) - processoperations.add(pump) + if not _loop_mode: + processoperations.add(pump) return pump @@ -324,7 +354,8 @@ def expander(name, teststream, p): expander = jneqsim.process.equipment.expander.Expander(name, teststream) expander.setOutletPressure(p) expander.setName(name) - processoperations.add(expander) + if not _loop_mode: + processoperations.add(expander) return expander @@ -339,13 +370,15 @@ def mixer(name=""): Mixer: An instance of the Mixer class. """ mixer = jneqsim.process.equipment.mixer.Mixer(name) - processoperations.add(mixer) + if not _loop_mode: + processoperations.add(mixer) return mixer def phasemixer(name): mixer = jneqsim.process.equipment.mixer.StaticPhaseMixer(name) - processoperations.add(mixer) + if not _loop_mode: + processoperations.add(mixer) return mixer @@ -356,7 +389,8 @@ def nequnit( teststream, equipment, flowpattern ) neqUn.setNumberOfNodes(numberOfNodes) - processoperations.add(neqUn) + if not _loop_mode: + processoperations.add(neqUn) return neqUn @@ -365,7 +399,8 @@ def compsplitter(name, teststream, splitfactors): name, teststream ) compSplitter.setSplitFactors(splitfactors) - processoperations.add(compSplitter) + if not _loop_mode: + processoperations.add(compSplitter) return compSplitter @@ -388,7 +423,8 @@ def splitter(name, teststream, splitfactors=[]): if len(splitfactors) > 0: splitter.setSplitNumber(len(splitfactors)) splitter.setSplitFactors(JDouble[:](splitfactors)) - processoperations.add(splitter) + if not _loop_mode: + processoperations.add(splitter) return splitter @@ -405,7 +441,8 @@ def heater(name, teststream): """ heater = jneqsim.process.equipment.heatexchanger.Heater(name, teststream) heater.setName(name) - processoperations.add(heater) + if not _loop_mode: + processoperations.add(heater) return heater @@ -418,7 +455,8 @@ def simplereservoir( ): reserv = jneqsim.process.equipment.reservoir.SimpleReservoir(name) reserv.setReservoirFluid(fluid, gasvolume, oilvolume, watervolume) - processoperations.add(reserv) + if not _loop_mode: + processoperations.add(reserv) return reserv @@ -435,7 +473,8 @@ def cooler(name, teststream): """ cooler = jneqsim.process.equipment.heatexchanger.Cooler(name, teststream) cooler.setName(name) - processoperations.add(cooler) + if not _loop_mode: + processoperations.add(cooler) return cooler @@ -458,7 +497,8 @@ def heatExchanger(name, stream1, stream2=None): name, stream1, stream2 ) heater.setName(name) - processoperations.add(heater) + if not _loop_mode: + processoperations.add(heater) return heater @@ -466,13 +506,15 @@ def distillationColumn(name, trays=5, reboil=True, condenser=True): distillationColumn = jneqsim.process.equipment.distillation.DistillationColumn( name, trays, reboil, condenser ) - processoperations.add(distillationColumn) + if not _loop_mode: + processoperations.add(distillationColumn) return distillationColumn def neqheater(name, teststream): neqheater = jneqsim.process.equipment.heatexchanger.NeqHeater(name, teststream) - processoperations.add(neqheater) + if not _loop_mode: + processoperations.add(neqheater) return neqheater @@ -491,7 +533,8 @@ def twophasepipe(name, teststream, position, diameter, height, outTemp, rough): pipe.setOuterTemperatures(outTemp) pipe.setEquilibriumMassTransfer(0) pipe.setEquilibriumHeatTransfer(1) - processoperations.add(pipe) + if not _loop_mode: + processoperations.add(pipe) return pipe @@ -502,7 +545,8 @@ def pipe(name, teststream, length, deltaElevation, diameter, rough): pipe.setPipeWallRoughness(rough) pipe.setInletElevation(0.0) pipe.setOutletElevation(deltaElevation) - processoperations.add(pipe) + if not _loop_mode: + processoperations.add(pipe) return pipe @@ -530,7 +574,8 @@ def pipeline( pipe.setPipeOuterHeatTransferCoefficients(outerHeatTransferCoefficients) pipe.setPipeWallHeatTransferCoefficients(pipeWallHeatTransferCoefficients) pipe.setOuterTemperatures(outTemp) - processoperations.add(pipe) + if not _loop_mode: + processoperations.add(pipe) return pipe @@ -561,7 +606,7 @@ def clearProcess(): This function clears all the process operations by calling the clearAll method from the processoperations module. """ - processoperations.clearAll() + clear() def runProcess(): @@ -571,7 +616,7 @@ def runProcess(): This function triggers the execution of the process operations by calling the `run` method from the `processoperations` module. """ - processoperations.run() + run() def runProcessAsThread(): @@ -599,7 +644,8 @@ def waterDewPointAnalyser(name, teststream): teststream ) waterDewPointAnalyser.setName(name) - processoperations.add(waterDewPointAnalyser) + if not _loop_mode: + processoperations.add(waterDewPointAnalyser) return waterDewPointAnalyser @@ -610,7 +656,8 @@ def hydrateEquilibriumTemperatureAnalyser(name, teststream): ) ) hydrateEquilibriumTemperatureAnalyser.setName(name) - processoperations.add(hydrateEquilibriumTemperatureAnalyser) + if not _loop_mode: + processoperations.add(hydrateEquilibriumTemperatureAnalyser) return hydrateEquilibriumTemperatureAnalyser diff --git a/src/neqsim/process/unitop.py b/neqsim/process/unitop.py similarity index 100% rename from src/neqsim/process/unitop.py rename to neqsim/process/unitop.py diff --git a/src/neqsim/standards/__init__.py b/neqsim/standards/__init__.py similarity index 100% rename from src/neqsim/standards/__init__.py rename to neqsim/standards/__init__.py diff --git a/src/neqsim/standards/standardTools.py b/neqsim/standards/standardTools.py similarity index 100% rename from src/neqsim/standards/standardTools.py rename to neqsim/standards/standardTools.py diff --git a/src/neqsim/thermo/__init__.py b/neqsim/thermo/__init__.py similarity index 100% rename from src/neqsim/thermo/__init__.py rename to neqsim/thermo/__init__.py diff --git a/src/neqsim/thermo/thermoTools.py b/neqsim/thermo/thermoTools.py similarity index 99% rename from src/neqsim/thermo/thermoTools.py rename to neqsim/thermo/thermoTools.py index 2e3997ae..73457423 100644 --- a/src/neqsim/thermo/thermoTools.py +++ b/neqsim/thermo/thermoTools.py @@ -266,7 +266,7 @@ """ import logging -from typing import List, Union +from typing import List, Optional, Union import jpype import pandas from jpype.types import * @@ -575,8 +575,8 @@ def fluidflashproperties( spec2: pandas.Series, mode: Union[int, str] = 1, system=None, - components: List[str] = None, - fractions: list = None, + components: Optional[List[str]] = None, + fractions: Optional[list] = None, ): """Perform flash and return fluid properties for a series of process properties. diff --git a/pyproject.toml b/pyproject.toml index 0b0f6b7e..0352fcdf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "neqsim" -version = "3.0.36" +version = "3.0.38" description = "NeqSim is a tool for thermodynamic and process calculations" authors = ["Even Solbraa "] license = "Apache-2.0" diff --git a/tests/process/test_ProcessTools.py b/tests/process/test_ProcessTools.py index 28173385..81e07e56 100644 --- a/tests/process/test_ProcessTools.py +++ b/tests/process/test_ProcessTools.py @@ -1,10 +1,12 @@ # import the package from neqsim.process.processTools import ( + getProcess, separator, pump, heater, separator3phase, compsplitter, + set_loop_mode, waterDewPointAnalyser, hydrateEquilibriumTemperatureAnalyser, virtualstream, @@ -424,11 +426,15 @@ def test_gasoilprocess(): save_neqsim(getProcess(), "test_gasoilprocess.zip") process1 = open_neqsim("test_gasoilprocess.zip") + if process1 is None: + raise RuntimeError("Failed to open process from zip file.") process1.run() save_neqsim(getProcess(), "test_gasoilprocess.neqsim") process1 = open_neqsim("test_gasoilprocess.zip") + if process1 is None: + raise RuntimeError("Failed to open process from zip file.") process1.run() # assert 3859.9 == approx(recirc1stream.getFlowRate('kg/hr'), abs=1.0) @@ -490,3 +496,30 @@ def test_AFR(): ), abs=0.01, ) + + +def test_loop_mode(): + fluid1 = fluid("srk") # create a fluid using the SRK-EoS + fluid1.setTemperature(28.15, "C") + fluid1.setPressure(100.0, "bara") + fluid1.addComponent("nitrogen", 1.0, "mol/sec") + fluid1.addComponent("methane", 5, "mol/sec") + fluid1.addComponent("ethane", 1, "mol/sec") + fluid1.addComponent("propane", 1, "mol/sec") + fluid1.addComponent("water", 50e-6, "mol/sec") + fluid1.setMixingRule(2) + clearProcess() + stream1 = stream("stream1", fluid1) + hydrateDewPoint = hydrateEquilibriumTemperatureAnalyser("analyser1", stream1) + runProcess() + assert hydrateDewPoint.getMeasuredValue("C") == approx(-25.204324, rel=0.001) + assert getProcess().getAllUnitNames().size() > 0 + + clearProcess() + assert getProcess().getAllUnitNames().size() == 0 + set_loop_mode(True) + stream1 = stream("stream1", fluid1) + hydrateDewPoint = hydrateEquilibriumTemperatureAnalyser("analyser1", stream1) + assert hydrateDewPoint.getMeasuredValue("C") == approx(-25.204324, rel=0.001) + assert getProcess().getAllUnitNames().size() == 0 + set_loop_mode(False) From baa51ee8d56e89fe06d357c1c6757499357ce3f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85smund=20V=C3=A5ge=20Fannemel?= <34712686+asmfstatoil@users.noreply.github.com> Date: Sun, 10 Aug 2025 18:04:49 +0200 Subject: [PATCH 2/2] Update pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 0352fcdf..0b0f6b7e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "neqsim" -version = "3.0.38" +version = "3.0.36" description = "NeqSim is a tool for thermodynamic and process calculations" authors = ["Even Solbraa "] license = "Apache-2.0"