iapws-1.5.5/0000775000175000017500000000000015161562600013033 5ustar alastairalastairiapws-1.5.5/setup.cfg0000664000175000017500000000004615161562600014654 0ustar alastairalastair[egg_info] tag_build = tag_date = 0 iapws-1.5.5/README.rst0000644000175000017500000001237214673772515014544 0ustar alastairalastair.. image:: https://dl.circleci.com/status-badge/img/gh/jjgomera/iapws/tree/master.svg?style=svg :target: https://dl.circleci.com/status-badge/redirect/gh/jjgomera/iapws/tree/master :alt: Build Status .. image:: https://ci.appveyor.com/api/projects/status/a128sh8e50cjsiya?svg=true :target: https://ci.appveyor.com/project/jjgomera/iapws :alt: Windows Build Status .. image:: https://coveralls.io/repos/github/jjgomera/iapws/badge.svg?branch=master :target: https://coveralls.io/github/jjgomera/iapws?branch=master :alt: coveralls.io analysis .. image:: https://codecov.io/gh/jjgomera/iapws/branch/master/graph/badge.svg :target: https://codecov.io/gh/jjgomera/iapws :alt: codecov.io analysis .. image:: https://app.codacy.com/project/badge/Grade/bb92d537dfa1461d919a0782f3c398b9 :target: https://www.codacy.com/gh/jjgomera/iapws/dashboard?utm_source=github.com&utm_medium=referral&utm_content=jjgomera/iapws&utm_campaign=Badge_Grade :alt: Code Quality .. image:: http://readthedocs.org/projects/iapws/badge/?version=latest :target: http://iapws.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status .. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.4744318.svg :target: https://doi.org/10.5281/zenodo.4744318 :alt: DOI iapws ===== Python implementation of standard from IAPWS (http://www.iapws.org/release.html). The module implements the full set of standards, including:: IAPWS-IF97 IAPWS-95 IAPWS-06 for Ice IAPWS-08 for seawater IAPWS-17 for Heavy water ... dependences -------------------- * Support for both python branch:: * python 2.7 * python 3.4 or later * Numpy-scipy: library with mathematic and scientific tools install -------------------- In debian you can find in official repositories in jessie, testing and sid. In ubuntu it's in official repositories from ubuntu saucy (13.10). In other system you can install using pip:: pip install iapws or directly from the github repository:: pip install git+https://github.com/jjgomera/iapws.git This is the recommended option to have the latest version. documentation -------------------- To see the full documentation of package, see `readthedocs `__ .. inclusion-marker-do-not-remove For a rapid usage demostration, see this examples IAPWS-IF97 (`see full documentation `__) .. code:: python from iapws import IAPWS97 sat_steam = IAPWS97(P=1,x=1) #saturated steam with known P sat_liquid = IAPWS97(T=370, x=0) #saturated liquid with known T steam = IAPWS97(P=2.5, T=500) #steam with known P and T print(sat_steam.h, sat_liquid.h, steam.h) #calculated enthalpies IAPWS-95 (`see full documentation `__) .. code:: python from iapws import IAPWS95 sat_steam = IAPWS95(P=1,x=1) #saturated steam with known P sat_liquid = IAPWS95(T=370, x=0) #saturated liquid with known T steam = IAPWS95(P=2.5, T=500) #steam with known P and T print(sat_steam.h, sat_liquid.h, steam.h) #calculated enthalpies For calculation of multiple states is possible use multiprocessing to speed up calculation, 6x in my laptop. Method valid too for D2O .. code:: python from iapws import IAPWS95 from numpy import arange from time import time x = arange(0, 1.01, 0.01) def fi(x): return IAPWS95(P=20.8, x=x) start = time() for xi in x: fi(xi) print(f'Without multiprocessing: {time() - start}') start = time() states = IAPWS95.from_list("P", 20.8, "x", x) print(f'With multiprocessing: {time() - start}') IAPWS-17 for Heavy water (`see full documentation `__) .. code:: python from iapws import D2O sat_liquid = D2O(T=370, x=0) #saturated liquid with known T print(sat_liquid.h) #calculated enthalpy IAPWS-06 for Ice Ih (`see full documentation `__) .. code:: python from iapws import _Ice ice = _Ice(273.15, 0.101325) #Ice at normal melting point print(ice["rho"]) #Calculated density IAPWS-08 for seawater (`see full documentation `__) .. code:: python from iapws import SeaWater state = SeaWater(T=300, P=0.101325, S=0.001) #Seawater with 0.1% Salinity print(state.cp) # Get cp TODO ==== * TODO: Improve convergence in two phase region for IAPWS95 and D2O class * TODO: Implement SBTL method for fast calculation * TODO: Implement TTSE method for fast calculation Ammonia-water mixture: * TODO: Add equilibrium routine I've tried to test all code and use all values for computer verification the standards give, but anyway the code can have hidden problem. For any suggestions, comments, bugs ... you can usage the `github issue section `__, or contact directly with me at `email `__. iapws-1.5.5/setup.py0000755000175000017500000000305114475161354014555 0ustar alastairalastair#!/usr/bin/python # -*- coding: utf-8 -*- """Install IAPWS module using setuptools.""" from setuptools import setup import io # for backwards compatibility with Python 2 import os with open(os.path.join("iapws", "VERSION")) as version_file: __version__ = version_file.read().strip() with io.open('README.rst', encoding="utf8") as file: long_description = file.read() setup( name='iapws', version=__version__, packages=['iapws'], include_package_data=True, author='jjgomera', author_email='jjgomera@gmail.com', url='https://github.com/jjgomera/iapws', download_url='https://github.com/jjgomera/iapws/tarball/v' + __version__, description='Python implementation of standards from The International' 'Association for the Properties of Water and Steam', long_description=long_description, license="gpl v3", python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*', install_requires=["scipy>=1.2"], classifiers=[ "Development Status :: 5 - Production/Stable", "Intended Audience :: Education", "Intended Audience :: Science/Research", "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Scientific/Engineering", "Topic :: Scientific/Engineering :: Chemistry", "Topic :: Scientific/Engineering :: Physics", "Topic :: Software Development :: Libraries :: Python Modules", ], ) iapws-1.5.5/PKG-INFO0000644000175000017500000001473615161562600014141 0ustar alastairalastairMetadata-Version: 2.4 Name: iapws Version: 1.5.5 Summary: Python implementation of standards from The InternationalAssociation for the Properties of Water and Steam Home-page: https://github.com/jjgomera/iapws Download-URL: https://github.com/jjgomera/iapws/tarball/v1.5.5 Author: jjgomera Author-email: jjgomera@gmail.com License: gpl v3 Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Education Classifier: Intended Audience :: Science/Research Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3) Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Scientific/Engineering Classifier: Topic :: Scientific/Engineering :: Chemistry Classifier: Topic :: Scientific/Engineering :: Physics Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.* License-File: LICENSE Requires-Dist: scipy>=1.2 Dynamic: author Dynamic: author-email Dynamic: classifier Dynamic: description Dynamic: download-url Dynamic: home-page Dynamic: license Dynamic: license-file Dynamic: requires-dist Dynamic: requires-python Dynamic: summary .. image:: https://dl.circleci.com/status-badge/img/gh/jjgomera/iapws/tree/master.svg?style=svg :target: https://dl.circleci.com/status-badge/redirect/gh/jjgomera/iapws/tree/master :alt: Build Status .. image:: https://ci.appveyor.com/api/projects/status/a128sh8e50cjsiya?svg=true :target: https://ci.appveyor.com/project/jjgomera/iapws :alt: Windows Build Status .. image:: https://coveralls.io/repos/github/jjgomera/iapws/badge.svg?branch=master :target: https://coveralls.io/github/jjgomera/iapws?branch=master :alt: coveralls.io analysis .. image:: https://codecov.io/gh/jjgomera/iapws/branch/master/graph/badge.svg :target: https://codecov.io/gh/jjgomera/iapws :alt: codecov.io analysis .. image:: https://app.codacy.com/project/badge/Grade/bb92d537dfa1461d919a0782f3c398b9 :target: https://www.codacy.com/gh/jjgomera/iapws/dashboard?utm_source=github.com&utm_medium=referral&utm_content=jjgomera/iapws&utm_campaign=Badge_Grade :alt: Code Quality .. image:: http://readthedocs.org/projects/iapws/badge/?version=latest :target: http://iapws.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status .. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.4744318.svg :target: https://doi.org/10.5281/zenodo.4744318 :alt: DOI iapws ===== Python implementation of standard from IAPWS (http://www.iapws.org/release.html). The module implements the full set of standards, including:: IAPWS-IF97 IAPWS-95 IAPWS-06 for Ice IAPWS-08 for seawater IAPWS-17 for Heavy water ... dependences -------------------- * Support for both python branch:: * python 2.7 * python 3.4 or later * Numpy-scipy: library with mathematic and scientific tools install -------------------- In debian you can find in official repositories in jessie, testing and sid. In ubuntu it's in official repositories from ubuntu saucy (13.10). In other system you can install using pip:: pip install iapws or directly from the github repository:: pip install git+https://github.com/jjgomera/iapws.git This is the recommended option to have the latest version. documentation -------------------- To see the full documentation of package, see `readthedocs `__ .. inclusion-marker-do-not-remove For a rapid usage demostration, see this examples IAPWS-IF97 (`see full documentation `__) .. code:: python from iapws import IAPWS97 sat_steam = IAPWS97(P=1,x=1) #saturated steam with known P sat_liquid = IAPWS97(T=370, x=0) #saturated liquid with known T steam = IAPWS97(P=2.5, T=500) #steam with known P and T print(sat_steam.h, sat_liquid.h, steam.h) #calculated enthalpies IAPWS-95 (`see full documentation `__) .. code:: python from iapws import IAPWS95 sat_steam = IAPWS95(P=1,x=1) #saturated steam with known P sat_liquid = IAPWS95(T=370, x=0) #saturated liquid with known T steam = IAPWS95(P=2.5, T=500) #steam with known P and T print(sat_steam.h, sat_liquid.h, steam.h) #calculated enthalpies For calculation of multiple states is possible use multiprocessing to speed up calculation, 6x in my laptop. Method valid too for D2O .. code:: python from iapws import IAPWS95 from numpy import arange from time import time x = arange(0, 1.01, 0.01) def fi(x): return IAPWS95(P=20.8, x=x) start = time() for xi in x: fi(xi) print(f'Without multiprocessing: {time() - start}') start = time() states = IAPWS95.from_list("P", 20.8, "x", x) print(f'With multiprocessing: {time() - start}') IAPWS-17 for Heavy water (`see full documentation `__) .. code:: python from iapws import D2O sat_liquid = D2O(T=370, x=0) #saturated liquid with known T print(sat_liquid.h) #calculated enthalpy IAPWS-06 for Ice Ih (`see full documentation `__) .. code:: python from iapws import _Ice ice = _Ice(273.15, 0.101325) #Ice at normal melting point print(ice["rho"]) #Calculated density IAPWS-08 for seawater (`see full documentation `__) .. code:: python from iapws import SeaWater state = SeaWater(T=300, P=0.101325, S=0.001) #Seawater with 0.1% Salinity print(state.cp) # Get cp TODO ==== * TODO: Improve convergence in two phase region for IAPWS95 and D2O class * TODO: Implement SBTL method for fast calculation * TODO: Implement TTSE method for fast calculation Ammonia-water mixture: * TODO: Add equilibrium routine I've tried to test all code and use all values for computer verification the standards give, but anyway the code can have hidden problem. For any suggestions, comments, bugs ... you can usage the `github issue section `__, or contact directly with me at `email `__. iapws-1.5.5/LICENSE0000644000175000017500000010446013117765046014053 0ustar alastairalastairGNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {one line to give the program's name and a brief idea of what it does.} Copyright (C) {year} {name of author} This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: {project} Copyright (C) {year} {fullname} This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read .iapws-1.5.5/MANIFEST.in0000644000175000017500000000007113673207676014604 0ustar alastairalastairinclude README.rst include LICENSE include iapws/VERSION iapws-1.5.5/iapws/0000775000175000017500000000000015161562600014156 5ustar alastairalastairiapws-1.5.5/iapws/VERSION0000644000175000017500000000000615161562057015226 0ustar alastairalastair1.5.5 iapws-1.5.5/iapws/__init__.py0000644000175000017500000002175314027412600016267 0ustar alastairalastair#!/usr/bin/python # -*- coding: utf-8 -*- """International Association for the Properties of Water and Steam (IAPWS).""" import os from ._iapws import (_Ice, _Sublimation_Pressure, _Melting_Pressure, # noqa _Viscosity, _ThCond, _Tension, _Dielectric, _Refractive) from .iapws97 import IAPWS97 # noqa from .iapws95 import IAPWS95, D2O # noqa from .iapws08 import SeaWater # noqa from .humidAir import HumidAir # noqa from .ammonia import H2ONH3 # noqa basepath = os.path.abspath(os.path.dirname(__file__)) with open(os.path.join(basepath, 'VERSION')) as version_file: __version__ = version_file.read().strip() __doi__ = { "R1-76": {"autor": "IAPWS", "title": "Revised Release on the Surface Tension of Ordynary Water " "Substance", "ref": "2014", "doi": ""}, "R2-83": {"autor": "IAPWS", "title": "Release on the Values of Temperature, Pressure and Density " "of Ordynary and Heavy Water Substances at their Respectives" " Critical Points", "ref": "1992", "doi": ""}, "R4-84": {"autor": "IAPWS", "title": "Revised Release on Viscosity and Thermal Conductivity of " "Heavy Water Substance", "ref": "2007", "doi": ""}, "R5-85": {"autor": "IAPWS", "title": "Release on Surface Tension of Heavy Water Substance", "ref": "1994", "doi": ""}, "R6-95": {"autor": "IAPWS", "title": "Revised Release on the IAPWS Formulation 1995 for the " "Thermodynamic Properties of Ordinary Water Substance for " "General and Scientific Use", "ref": "2006", "doi": ""}, "R7-97": {"autor": "IAPWS", "title": "Revised Release on the IAPWS Industrial Formulation 1997 " "for the Thermodynamic Properties of Water and Steam", "ref": "2012", "doi": ""}, "R8-97": {"autor": "IAPWS", "title": "Release on the Static Dielectric Constant of Ordinary Water" "Substance for Temperatures from 238 K to 873 K and " "Pressures up to 1000 MPa", "ref": "1997", "doi": ""}, "R9-97": {"autor": "IAPWS", "title": "Release on the Refractive Index of Ordinary Water Substance" " as a Function of Wavelength, Temperature and Pressure", "ref": "1997", "doi": ""}, "R10-06": {"autor": "IAPWS", "title": "Revised Release on the Equation of State 2006 for H2O Ice " "Ih", "ref": "2009", "doi": ""}, "R11-19": {"autor": "IAPWS", "title": "Release on the Ionization Constant of H2O", "ref": "2019", "doi": ""}, "R12-08": {"autor": "IAPWS", "title": "Release on the IAPWS Formulation 2008 for the Viscosity of " "Ordinary Water Substance", "ref": "2008", "doi": ""}, "R13-08": {"autor": "IAPWS", "title": "Release on the IAPWS Formulation 2008 for the Thermodynamic" " Properties of Seawater", "ref": "2008", "doi": ""}, "R14-08": {"autor": "IAPWS", "title": "Revised Release on the Pressure along the Melting and " "Sublimation Curves of Ordinary Water Substance", "ref": "2011", "doi": ""}, "R15-11": {"autor": "IAPWS", "title": "Release on the IAPWS Formulation 2011 for the Thermal " "Conductivity of Ordinary Water Substance", "ref": "2011", "doi": ""}, "R16-17": {"autor": "IAPWS", "title": "Release on the IAPWS Formulation 2017 for the Thermodynamic" " Properties of Heavy Water", "ref": "2017", "doi": ""}, "SR1-86": {"autor": "IAPWS", "title": "Revised Supplementary Release on Saturation Properties of " "Ordinary Water Substance", "ref": "1992", "doi": ""}, "SR2-01": {"autor": "IAPWS", "title": "Revised Supplementary Release on Backward Equations for " "Pressure as a Function of Enthalpy and Entropy p(h,s) for " "Regions 1 and 2 of the IAPWS Industrial Formulation 1997 " "for the Thermodynamic Properties of Water and Steam", "ref": "2014", "doi": ""}, "SR3-03": {"autor": "IAPWS", "title": "Revised Supplementary Release on Backward Equations for " "the Functions T(p,h), v(p,h), and T(p,s), v(p,s) for " "Region 3 of the IAPWS Industrial Formulation 1997 for the " "Thermodynamic Properties of Water and Steam", "ref": "2014", "doi": ""}, "SR4-04": {"autor": "IAPWS", "title": "Revised Supplementary Release on Backward Equations p(h,s) " "for Region 3, Equations as a Function of h and s for the " "Region Boundaries, and an Equation Tsat(h,s) for Region 4 " "of the IAPWS Industrial Formulation 1997 for the " "Thermodynamic Properties of Water and Steam", "ref": "2014", "doi": ""}, "SR5-05": {"autor": "IAPWS", "title": "Revised Supplementary Release on Backward Equations for " "Specific Volume as a Function of Pressure and Temperature " "v(p,T) for Region 3 of the IAPWS Industrial Formulation " "1997 for the Thermodynamic Properties of Water and Steam", "ref": "2016", "doi": ""}, "SR6-08": {"autor": "IAPWS", "title": "Revised Supplementary Release on Properties of Liquid " "Water at 0.1 MPa", "ref": "2011", "doi": ""}, "SR7-09": {"autor": "IAPWS", "title": "Supplementary Release on a Computationally Efficient " "Thermodynamic Formulation for Liquid Water for " "Oceanographic Use", "ref": "2009", "doi": ""}, "G1-90": {"autor": "IAPWS", "title": "Electrolytic Conductivity (Specific Conductance) of Liquid " "and Dense Supercritical Water from 0°C to 800°C and " "Pressures up to 1000 MPa", "ref": "1990", "doi": ""}, "G2-90": {"autor": "IAPWS", "title": "Solubility of Sodium Sulfate in Aqueous Mixtures of Sodium " "Chloride and Sulfuric Acid from Water to Concentrated " "Solutions, from 250 °C to 350 °C", "ref": "1994", "doi": ""}, "G3-00": {"autor": "IAPWS", "title": "Revised Guideline on the Critical Locus of Aqueous " "Solutions of Sodium Chloride", "ref": "2012", "doi": ""}, "G4-01": {"autor": "IAPWS", "title": "Guideline on the IAPWS Formulation 2001 for the " "Thermodynamic Properties of Ammonia-Water Mixtures", "ref": "2001", "doi": ""}, "G5-01": {"autor": "IAPWS", "title": "Guideline on the Use of Fundamental Physical Constants and " "Basic Constants of Water", "ref": "2016", "doi": ""}, "G7-04": {"autor": "IAPWS", "title": "Guideline on the Henry's Constant and Vapor-Liquid " "Distribution Constant for Gases in H2O and D2O at High " "Temperatures", "ref": "2004", "doi": ""}, "G8-10": {"autor": "IAPWS", "title": "Guideline on an Equation of State for Humid Air in Contact " "with Seawater and Ice, Consistent with the IAPWS " "Formulation 2008 for the Thermodynamic Properties of " "Seawater", "ref": "2010", "doi": ""}, "G9-12": {"autor": "IAPWS", "title": "Guideline on a Low-Temperature Extension of the IAPWS-95 " "Formulation for Water Vapor", "ref": "2012", "doi": ""}, "G10-15": {"autor": "IAPWS", "title": "Guideline on the Thermal Conductivity of Seawater", "ref": "2015", "doi": ""}, "G11-15": {"autor": "IAPWS", "title": "Guideline on a Virial Equation for the Fugacity of H2O in " "Humid Air", "ref": "2015", "doi": ""}, "G12-15": {"autor": "IAPWS", "title": "Guideline on Thermodynamic Properties of Supercooled Water", "ref": "2015", "doi": ""}, "AN3-07": {"autor": "IAPWS", "title": "Thermodynamic Derivatives from IAPWS Formulations", "ref": "2014", "doi": ""}, "AN5-13": {"autor": "IAPWS", "title": "Industrial Calculation of the Thermodynamic Properties of " "Seawater", "ref": "2016", "doi": ""}, } iapws-1.5.5/iapws/iapws08.py0000664000175000017500000005771615161316541016044 0ustar alastairalastair#!/usr/bin/python # -*- coding: utf-8 -*- # pylint: disable=invalid-name # pylint: disable=too-many-instance-attributes, too-many-boolean-expressions # pylint: disable=too-many-locals """ IAPWS standard for Seawater IAPWS08 and related functionality. The module include: :class:`SeaWater`: Global module class with all the functionality integrated Other functionality: * :func:`_Tb`: Boiling temperature of seawater * :func:`_Tf`: Freezing temperature of seawater * :func:`_Triple`: Triple point properties of seawater * :func:`_OsmoticPressure`: Osmotic pressure of seawater * :func:`_ThCond_SeaWater`: Thermal conductivity of seawater * :func:`_Tension_SeaWater`: Surface tension of seawater * :func:`_solNa2SO4`: Solubility of sodium sulfate in aqueous mixtures of sodium chloride and sulfuric acid * :func:`_critNaCl`: Critical locus of aqueous solutions of sodium chloride """ from __future__ import division from numpy import exp, log import warnings from scipy.optimize import fsolve from .iapws95 import IAPWS95 from .iapws97 import IAPWS97, _Region1, _Region2, _TSat_P from ._iapws import _ThCond, Tc, Pc, rhoc, _Ice, _Tension from ._utils import deriv_G # Constants Rm = 8.314472 Sn = 0.03516504 S_ = Sn*40/35 Ms = 31.4038218 T_ = 40 P_ = 100 Po = 0.101325 To = 273.15 class SeaWater(object): """ Class to model seawater with standard IAPWS-08 Parameters ---------- T : float Temperature, [K] P : float Pressure, [MPa] S : float Salinity, [kg/kg] fast : bool, default False Use the Supplementary release SR7-09 to speed up the calculation IF97 : bool, default False Use the Advisory Note No. 5 with industrial formulation Returns ------- rho : float Density, [kg/m³] v : float Specific volume, [m³/kg] h : float Specific enthalpy, [kJ/kg] s : float Specific entropy, [kJ/kg·K] u : float Specific internal energy, [kJ/kg] g : float Specific Gibbs free energy, [kJ/kg] a : float Specific Helmholtz free energy, [kJ/kg] cp : float Specific isobaric heat capacity, [kJ/kg·K] cv : float Specific isochoric heat capacity, [kJ/kg·K] gt : float Derivative Gibbs energy with temperature, [kJ/kg·K] gp : float Derivative Gibbs energy with pressure, [m³/kg] gtt : float Derivative Gibbs energy with temperature square, [kJ/kg·K²] gtp : float Derivative Gibbs energy with pressure and temperature, [m³/kg·K] gpp : float Derivative Gibbs energy with temperature square, [m³/kg·MPa] gs : float Derivative Gibbs energy with salinity, [kJ/kg] gsp : float Derivative Gibbs energy with salinity and pressure, [m³/kg] alfav : float Thermal expansion coefficient, [1/K] betas : float Isentropic temperature-pressure coefficient, [K/MPa] xkappa : float Isothermal compressibility, [1/MPa] ks : float Isentropic compressibility, [1/MPa] w : float Sound Speed, [m/s] k : float Thermal conductivity, [W/m·K] sigma: float Surface tension, [N/m] m : float Molality of seawater, [mol/kg] mu : float Relative chemical potential, [kJ/kg] muw : float Chemical potential of H2O, [kJ/kg] mus : float Chemical potential of sea salt, [kJ/kg] osm : float Osmotic coefficient, [-] haline : float Haline contraction coefficient, [kg/kg] Notes ----- :class:`Warning` if input isn't in limit: * 261 ≤ T ≤ 353 * 0 < P ≤ 100 * 0 ≤ S ≤ 0.12 References ---------- IAPWS, Release on the IAPWS Formulation 2008 for the Thermodynamic Properties of Seawater, http://www.iapws.org/relguide/Seawater.html IAPWS, Supplementary Release on a Computationally Efficient Thermodynamic Formulation for Liquid Water for Oceanographic Use, http://www.iapws.org/relguide/OceanLiquid.html IAPWS, Guideline on the Thermal Conductivity of Seawater, http://www.iapws.org/relguide/Seawater-ThCond.html IAPWS, Guideline on the Surface Tension of Seawater, http://www.iapws.org/relguide/Seawater-Surf.html IAPWS, Revised Advisory Note No. 3: Thermodynamic Derivatives from IAPWS Formulations, http://www.iapws.org/relguide/Advise3.pdf IAPWS, Advisory Note No. 5: Industrial Calculation of the Thermodynamic Properties of Seawater, http://www.iapws.org/relguide/Advise5.html Examples -------- >>> salt = iapws.SeaWater(T=300, P=1, S=0.04) >>> salt.rho 1026.7785717245113 >>> salt.gs 88.56221805501536 >>> salt.haline 0.7311487666026304 """ kwargs = {"T": 0.0, "P": 0.0, "S": None, "fast": False, "IF97": False} status = 0 msg = "Undefined" T = None P = None rho = None v = None s = None cp = None cv = None h = None u = None a = None alfav = None betas = None xkappa = None ks = None w = None k = None sigma = None m = None mu = None muw = None mus = None osm = None haline = None def __init__(self, **kwargs): """Constructor, initinialice kwargs""" self.kwargs = SeaWater.kwargs.copy() self.__call__(**kwargs) def __call__(self, **kwargs): """Make instance callable to can add input parameter one to one""" self.kwargs.update(kwargs) if self.kwargs["T"] and self.kwargs["P"] and \ self.kwargs["S"] is not None: self.status = 1 self.calculo() self.msg = "" def calculo(self): """Calculate procedure""" T = self.kwargs["T"] P = self.kwargs["P"] S = self.kwargs["S"] self.m = S/(1-S)/Ms if self.kwargs["fast"] and T <= 313.15: pw = self._waterSupp(T, P) elif self.kwargs["IF97"]: pw = self._waterIF97(T, P) else: pw = self._water(T, P) ps = self.saline(T, P, S) prop = {} for key in ps: prop[key] = pw[key]+ps[key] self.__setattr__(key, prop[key]) self.T = T self.P = P self.rho = 1./prop["gp"] self.v = prop["gp"] self.s = -prop["gt"] self.cp = -T*prop["gtt"] self.cv = T*(prop["gtp"]**2/prop["gpp"]-prop["gtt"]) self.h = prop["g"]-T*prop["gt"] self.u = prop["g"]-T*prop["gt"]-P*1000*prop["gp"] self.a = prop["g"]-P*1000*prop["gp"] self.alfav = prop["gtp"]/prop["gp"] self.betas = -prop["gtp"]/prop["gtt"] self.xkappa = -prop["gpp"]/prop["gp"] self.ks = (prop["gtp"]**2-prop["gtt"]*prop["gpp"])/prop["gp"] / \ prop["gtt"] self.w = prop["gp"]*(prop["gtt"]*1000/( prop["gtp"]**2 - prop["gtt"]*1000*prop["gpp"]*1e-6))**0.5 # Thermal conductivity calculation if "thcond" in pw: kw = pw["thcond"] else: kw = _ThCond(1/pw["gp"], T) try: self.k = _ThCond_SeaWater(T, P, S)+kw except NotImplementedError: self.k = None # Surface tension calculation try: self.sigma = _Tension_SeaWater(T, S) except NotImplementedError: pass if S: self.mu = prop["gs"] self.muw = prop["g"]-S*prop["gs"] self.mus = prop["g"]+(1-S)*prop["gs"] self.osm = -(ps["g"]-S*prop["gs"])/self.m/Rm/T self.haline = -prop["gsp"]/prop["gp"] def derivative(self, z, x, y): """ Wrapper derivative for custom derived properties where x, y, z can be: P, T, v, u, h, s, g, a """ return deriv_G(self, z, x, y, self) @classmethod def _water(cls, T, P): """Get properties of pure water, Table4 pag 8""" water = IAPWS95(P=P, T=T) prop = {} prop["g"] = water.h-T*water.s prop["gt"] = -water.s prop["gp"] = 1./water.rho prop["gtt"] = -water.cp/T prop["gtp"] = water.betas*water.cp/T prop["gpp"] = -1e6/(water.rho*water.w)**2-water.betas**2*1e3*water.cp/T prop["gs"] = 0 prop["gsp"] = 0 prop["thcond"] = water.k return prop @classmethod def _waterIF97(cls, T, P): water = IAPWS97(P=P, T=T) betas = water.derivative("T", "P", "s", water) prop = {} prop["g"] = water.h-T*water.s prop["gt"] = -water.s prop["gp"] = 1./water.rho prop["gtt"] = -water.cp/T prop["gtp"] = betas*water.cp/T prop["gpp"] = -1e6/(water.rho*water.w)**2-betas**2*1e3*water.cp/T prop["gs"] = 0 prop["gsp"] = 0 return prop @classmethod def _waterSupp(cls, T, P): """ Get properties of pure water using the supplementary release SR7-09, Table4 pag 6 """ tau = (T-273.15)/40 pi = (P-0.101325)/100 J = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7] K = [0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 0, 1] G = [0.101342743139674e3, 0.100015695367145e6, -0.254457654203630e4, 0.284517778446287e3, -0.333146754253611e2, 0.420263108803084e1, -0.546428511471039, 0.590578347909402e1, -0.270983805184062e3, 0.776153611613101e3, -0.196512550881220e3, 0.289796526294175e2, -0.213290083518327e1, -0.123577859330390e5, 0.145503645404680e4, -0.756558385769359e3, 0.273479662323528e3, -0.555604063817218e2, 0.434420671917197e1, 0.736741204151612e3, -0.672507783145070e3, 0.499360390819152e3, -0.239545330654412e3, 0.488012518593872e2, -0.166307106208905e1, -0.148185936433658e3, 0.397968445406972e3, -0.301815380621876e3, 0.152196371733841e3, -0.263748377232802e2, 0.580259125842571e2, -0.194618310617595e3, 0.120520654902025e3, -0.552723052340152e2, 0.648190668077221e1, -0.189843846514172e2, 0.635113936641785e2, -0.222897317140459e2, 0.817060541818112e1, 0.305081646487967e1, -0.963108119393062e1] g, gt, gp, gtt, gtp, gpp = 0, 0, 0, 0, 0, 0 for j, k, gi in zip(J, K, G): g += gi*tau**j*pi**k if j >= 1: gt += gi*j*tau**(j-1)*pi**k if k >= 1: gp += k*gi*tau**j*pi**(k-1) if j >= 2: gtt += j*(j-1)*gi*tau**(j-2)*pi**k if j >= 1 and k >= 1: gtp += j*k*gi*tau**(j-1)*pi**(k-1) if k >= 2: gpp += k*(k-1)*gi*tau**j*pi**(k-2) prop = {} prop["g"] = g*1e-3 prop["gt"] = gt/40*1e-3 prop["gp"] = gp/100*1e-6 prop["gtt"] = gtt/40**2*1e-3 prop["gtp"] = gtp/40/100*1e-6 prop["gpp"] = gpp/100**2*1e-6 prop["gs"] = 0 prop["gsp"] = 0 return prop @classmethod def saline(cls, T, P, S): """Eq 4""" # Check input in range of validity if T <= 261 or T > 353 or P <= 0 or P > 100 or S < 0 or S > 0.12: warnings.warn("Incoming out of bound") X = (S/S_)**0.5 tau = (T-273.15)/40 pi = (P-0.101325)/100 Li = [1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 2, 3, 4, 2, 3, 4, 2, 3, 4, 2, 4, 2, 2, 3, 4, 5, 2, 3, 4, 2, 3, 2, 3, 2, 3, 2, 3, 4, 2, 3, 2, 3, 2, 2, 2, 3, 4, 2, 3, 2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2] Lj = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 0, 0, 0, 1, 1, 2, 2, 3, 4, 0, 0, 0, 1, 1, 2, 2, 3, 4, 0, 0, 1, 2, 3, 0, 1, 2] Lk = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5] G = [0.581281456626732e4, 0.141627648484197e4, -0.243214662381794e4, 0.202580115603697e4, -0.109166841042967e4, 0.374601237877840e3, -0.485891069025409e2, 0.851226734946706e3, 0.168072408311545e3, -0.493407510141682e3, 0.543835333000098e3, -0.196028306689776e3, 0.367571622995805e2, 0.880031352997204e3, -0.430664675978042e2, -0.685572509204491e2, -0.225267649263401e3, -0.100227370861875e2, 0.493667694856254e2, 0.914260447751259e2, 0.875600661808945, -0.171397577419788e2, -0.216603240875311e2, 0.249697009569508e1, 0.213016970847183e1, -0.331049154044839e4, 0.199459603073901e3, -0.547919133532887e2, 0.360284195611086e2, 0.729116529735046e3, -0.175292041186547e3, -0.226683558512829e2, -0.860764303783977e3, 0.383058066002476e3, 0.694244814133268e3, -0.460319931801257e3, -0.297728741987187e3, 0.234565187611355e3, 0.384794152978599e3, -0.522940909281335e2, -0.408193978912261e1, -0.343956902961561e3, 0.831923927801819e2, 0.337409530269367e3, -0.541917262517112e2, -0.204889641964903e3, 0.747261411387560e2, -0.965324320107458e2, 0.680444942726459e2, -0.301755111971161e2, 0.124687671116248e3, -0.294830643494290e2, -0.178314556207638e3, 0.256398487389914e2, 0.113561697840594e3, -0.364872919001588e2, 0.158408172766824e2, -0.341251932441282e1, -0.316569643860730e2, 0.442040358308000e2, -0.111282734326413e2, -0.262480156590992e1, 0.704658803315449e1, -0.792001547211682e1] g, gt, gp, gtt, gtp, gpp, gs, gsp = 0, 0, 0, 0, 0, 0, 0, 0 # Calculate only for some salinity if S != 0: for i, j, k, gi in zip(Li, Lj, Lk, G): if i == 1: g += gi*X**2*log(X)*tau**j*pi**k gs += gi*(2*log(X)+1)*tau**j*pi**k else: g += gi*X**i*tau**j*pi**k gs += i*gi*X**(i-2)*tau**j*pi**k if j >= 1: if i == 1: gt += gi*X**2*log(X)*j*tau**(j-1)*pi**k else: gt += gi*X**i*j*tau**(j-1)*pi**k if k >= 1: gp += k*gi*X**i*tau**j*pi**(k-1) gsp += i*k*gi*X**(i-2)*tau**j*pi**(k-1) if j >= 2: gtt += j*(j-1)*gi*X**i*tau**(j-2)*pi**k if j >= 1 and k >= 1: gtp += j*k*gi*X**i*tau**(j-1)*pi**(k-1) if k >= 2: gpp += k*(k-1)*gi*X**i*tau**j*pi**(k-2) prop = {} prop["g"] = g*1e-3 prop["gt"] = gt/40*1e-3 prop["gp"] = gp/100*1e-6 prop["gtt"] = gtt/40**2*1e-3 prop["gtp"] = gtp/40/100*1e-6 prop["gpp"] = gpp/100**2*1e-6 prop["gs"] = gs/S_/2*1e-3 prop["gsp"] = gsp/S_/2/100*1e-6 return prop def _Tb(P, S): """Procedure to calculate the boiling temperature of seawater Parameters ---------- P : float Pressure, [MPa] S : float Salinity, [kg/kg] Returns ------- Tb : float Boiling temperature, [K] References ---------- IAPWS, Advisory Note No. 5: Industrial Calculation of the Thermodynamic Properties of Seawater, http://www.iapws.org/relguide/Advise5.html, Eq 7 """ def f(T): pw = _Region1(T, P) gw = pw["h"]-T*pw["s"] pv = _Region2(T, P) gv = pv["h"]-T*pv["s"] ps = SeaWater.saline(T, P, S) return -ps["g"]+S*ps["gs"]-gw+gv try: to = _TSat_P(P) except NotImplementedError: to = 300 rinput = fsolve(f, to, full_output=True) Tb = fsolve(f, to)[0] if rinput[2] == 1: return Tb def _Tf(P, S): """Procedure to calculate the freezing temperature of seawater Parameters ---------- P : float Pressure, [MPa] S : float Salinity, [kg/kg] Returns ------- Tf : float Freezing temperature, [K] References ---------- IAPWS, Advisory Note No. 5: Industrial Calculation of the Thermodynamic Properties of Seawater, http://www.iapws.org/relguide/Advise5.html, Eq 12 """ def f(T): T = float(T.item()) pw = _Region1(T, P) gw = pw["h"]-T*pw["s"] gih = _Ice(T, P)["g"] ps = SeaWater.saline(T, P, S) return -ps["g"]+S*ps["gs"]-gw+gih try: to = _TSat_P(P) except NotImplementedError: to = 300 rinput = fsolve(f, to, full_output=True) Tf = fsolve(f, to)[0] if rinput[2] == 1: return Tf def _Triple(S): """Procedure to calculate the triple point pressure and temperature for seawater Parameters ---------- S : float Salinity, [kg/kg] Returns ------- prop : dict Dictionary with the triple point properties: * Tt: Triple point temperature, [K] * Pt: Triple point pressure, [MPa] References ---------- IAPWS, Advisory Note No. 5: Industrial Calculation of the Thermodynamic Properties of Seawater, http://www.iapws.org/relguide/Advise5.html, Eq 7 """ def f(parr): T, P = parr pw = _Region1(T, P) gw = pw["h"]-T*pw["s"] pv = _Region2(T, P) gv = pv["h"]-T*pv["s"] gih = _Ice(T, P)["g"] ps = SeaWater.saline(T, P, S) return -ps["g"]+S*ps["gs"]-gw+gih, -ps["g"]+S*ps["gs"]-gw+gv Tt, Pt = fsolve(f, [273, 6e-4]) prop = {} prop["Tt"] = Tt prop["Pt"] = Pt return prop def _OsmoticPressure(T, P, S): """Procedure to calculate the osmotic pressure of seawater Parameters ---------- T : float Tmperature, [K] P : float Pressure, [MPa] S : float Salinity, [kg/kg] Returns ------- Posm : float Osmotic pressure, [MPa] References ---------- IAPWS, Advisory Note No. 5: Industrial Calculation of the Thermodynamic Properties of Seawater, http://www.iapws.org/relguide/Advise5.html, Eq 15 """ pw = _Region1(T, P) gw = pw["h"]-T*pw["s"] def f(Posm): pw2 = _Region1(T, P+Posm) gw2 = pw2["h"]-T*pw2["s"] ps = SeaWater.saline(T, P+Posm, S) return -ps["g"]+S*ps["gs"]-gw+gw2 Posm = fsolve(f, 0)[0] return Posm def _ThCond_SeaWater(T, P, S): """Equation for the thermal conductivity of seawater Parameters ---------- T : float Temperature, [K] P : float Pressure, [MPa] S : float Salinity, [kg/kg] Returns ------- k : float Thermal conductivity excess relative to that of the pure water, [W/mK] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 273.15 ≤ T ≤ 523.15 * 0 ≤ P ≤ 140 * 0 ≤ S ≤ 0.17 Examples -------- >>> _ThCond_Seawater(293.15, 0.1, 0.035) -0.00418604 References ---------- IAPWS, Guideline on the Thermal Conductivity of Seawater, http://www.iapws.org/relguide/Seawater-ThCond.html """ # Check input parameters if T < 273.15 or T > 523.15 or P < 0 or P > 140 or S < 0 or S > 0.17: raise NotImplementedError("Incoming out of bound") # Eq 4 a1 = -7.180891e-5+1.831971e-7*P a2 = 1.048077e-3-4.494722e-6*P # Eq 5 b1 = 1.463375e-1+9.208586e-4*P b2 = -3.086908e-3+1.798489e-5*P a = a1*exp(a2*(T-273.15)) # Eq 2 b = b1*exp(b2*(T-273.15)) # Eq 3 # Eq 1 DL = a*(1000*S)**(1+b) return DL def _Tension_SeaWater(T, S): """Equation for the surface tension of seawater Parameters ---------- T : float Temperature, [K] S : float Salinity, [kg/kg] Returns ------- σ : float Surface tension, [N/m] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 0 ≤ S ≤ 0.131 for 274.15 ≤ T ≤ 365.15 * 0 ≤ S ≤ 0.038 for 248.15 ≤ T ≤ 274.15 Examples -------- >>> _Tension_Seawater(253.15, 0.035) -0.07922517961 References ---------- IAPWS, Guideline on the Surface Tension of Seawater, http://www.iapws.org/relguide/Seawater-Surf.html """ # Check input parameters if 248.15 < T < 274.15: if S < 0 or S > 0.038: raise NotImplementedError("Incoming out of bound") elif 274.15 < T < 365.15: if S < 0 or S > 0.131: raise NotImplementedError("Incoming out of bound") else: raise NotImplementedError("Incoming out of bound") sw = _Tension(T) sigma = sw*(1+3.766e-1*S+2.347e-3*S*(T-273.15)) return sigma def _solNa2SO4(T, mH2SO4, mNaCl): """Equation for the solubility of sodium sulfate in aqueous mixtures of sodium chloride and sulfuric acid Parameters ---------- T : float Temperature, [K] mH2SO4 : float Molality of sufuric acid, [mol/kg(water)] mNaCl : float Molality of sodium chloride, [mol/kg(water)] Returns ------- S : float Molal solutility of sodium sulfate, [mol/kg(water)] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 523.15 ≤ T ≤ 623.15 * 0 ≤ mH2SO4 ≤ 0.75 * 0 ≤ mNaCl ≤ 2.25 Examples -------- >>> _solNa2SO4(523.15, 0.25, 0.75) 2.68 References ---------- IAPWS, Solubility of Sodium Sulfate in Aqueous Mixtures of Sodium Chloride and Sulfuric Acid from Water to Concentrated Solutions, http://www.iapws.org/relguide/na2so4.pdf """ # Check input parameters if T < 523.15 or T > 623.15 or mH2SO4 < 0 or mH2SO4 > 0.75 or \ mNaCl < 0 or mNaCl > 2.25: raise NotImplementedError("Incoming out of bound") A00 = -0.8085987*T+81.4613752+0.10537803*T*log(T) A10 = 3.4636364*T-281.63322-0.46779874*T*log(T) A20 = -6.0029634*T+480.60108+0.81382854*T*log(T) A30 = 4.4540258*T-359.36872-0.60306734*T*log(T) A01 = 0.4909061*T-46.556271-0.064612393*T*log(T) A02 = -0.002781314*T+1.722695+0.0000013319698*T*log(T) A03 = -0.014074108*T+0.99020227+0.0019397832*T*log(T) A11 = -0.87146573*T+71.808756+0.11749585*T*log(T) S = A00 + A10*mH2SO4 + A20*mH2SO4**2 + A30*mH2SO4**3 + A01*mNaCl + \ A02*mNaCl**2 + A03*mNaCl**3 + A11*mH2SO4*mNaCl return S def _critNaCl(x): """Equation for the critical locus of aqueous solutions of sodium chloride Parameters ---------- x : float Mole fraction of NaCl, [-] Returns ------- prop : dict A dictionary withe the properties: * Tc: critical temperature, [K] * Pc: critical pressure, [MPa] * rhoc: critical density, [kg/m³] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 0 ≤ x ≤ 0.12 Examples -------- >>> _critNaCl(0.1) 975.571016 References ---------- IAPWS, Revised Guideline on the Critical Locus of Aqueous Solutions of Sodium Chloride, http://www.iapws.org/relguide/critnacl.html """ # Check input parameters if x < 0 or x > 0.12: raise NotImplementedError("Incoming out of bound") T1 = Tc*(1 + 2.3e1*x - 3.3e2*x**1.5 - 1.8e3*x**2) T2 = Tc*(1 + 1.757e1*x - 3.026e2*x**1.5 + 2.838e3*x**2 - 1.349e4*x**2.5 + 3.278e4*x**3 - 3.674e4*x**3.5 + 1.437e4*x**4) f1 = (abs(10000*x-10-1)-abs(10000*x-10+1))/4+0.5 f2 = (abs(10000*x-10+1)-abs(10000*x-10-1))/4+0.5 # Eq 1 tc = f1*T1+f2*T2 # Eq 7 rc = rhoc*(1 + 1.7607e2*x - 2.9693e3*x**1.5 + 2.4886e4*x**2 - 1.1377e5*x**2.5 + 2.8847e5*x**3 - 3.8195e5*x**3.5 + 2.0633e5*x**4) # Eq 8 DT = tc-Tc pc = Pc*(1+9.1443e-3*DT+5.1636e-5*DT**2-2.5360e-7*DT**3+3.6494e-10*DT**4) prop = {} prop["Tc"] = tc prop["rhoc"] = rc prop["Pc"] = pc return prop iapws-1.5.5/iapws/iapws97.py0000664000175000017500000032212215161316541016036 0ustar alastairalastair#!/usr/bin/python # -*- coding: utf-8 -*- # pylint: disable=too-many-lines, too-many-statements, too-many-locals # pylint: disable=too-many-instance-attributes, too-many-branches # pylint: disable=invalid-name """IAPWS-IF97 standard implementation .. image:: images/iapws97.png :alt: iapws97 The module implement the fundamental equation for the five regions (rectangular boxes) and the backward equation (marked in grey). :class:`IAPWS97`: Global module class with all the functionality integrated Fundamental equations: * :func:`_Region1` * :func:`_Region2` * :func:`_Region3` * :func:`_Region4` * :func:`_TSat_P` * :func:`_PSat_T` * :func:`_Region5` Backward equations: * :func:`_Backward1_T_Ph` * :func:`_Backward1_T_Ps` * :func:`_Backward1_P_hs` * :func:`_Backward2_T_Ph` * :func:`_Backward2_T_Ps` * :func:`_Backward2_P_hs` * :func:`_Backward3_T_Ph` * :func:`_Backward3_T_Ps` * :func:`_Backward3_P_hs` * :func:`_Backward3_v_Ph` * :func:`_Backward3_v_Ps` * :func:`_Backward3_v_PT` * :func:`_Backward4_T_hs` Boundary equations: * :func:`_h13_s` * :func:`_h3a_s` * :func:`_h1_s` * :func:`_t_hs` * :func:`_PSat_h` * :func:`_h2ab_s` * :func:`_h_3ab` * :func:`_h2c3b_s` * :func:`_hab_s` * :func:`_hbc_P` References: IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html IAPWS, Revised Supplementary Release on Backward Equations for Pressure as a Function of Enthalpy and Entropy p(h,s) for Regions 1 and 2 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-PHS12-2014.pdf IAPWS, Revised Supplementary Release on Backward Equations for the Functions T(p,h), v(p,h) and T(p,s), v(p,s) for Region 3 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-Tv%28ph,ps%293-2014.pdf IAPWS, Revised Supplementary Release on Backward Equations p(h,s) for Region 3, Equations as a Function of h and s for the Region Boundaries, and an Equation Tsat(h,s) for Region 4 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-phs3-2014.pdf IAPWS, Revised Supplementary Release on Backward Equations for Specific Volume as a Function of Pressure and Temperature v(p,T) for Region 3 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-VPT3-2016.pdf IAPWS, Revised Advisory Note No. 3: Thermodynamic Derivatives from IAPWS Formulations, http://www.iapws.org/relguide/Advise3.pdf Wagner, W; Kretzschmar, H-J: International Steam Tables: Properties of Water and Steam Based on the Industrial Formulation IAPWS-IF97; Springer, 2008; doi: 10.1007/978-3-540-74234-0 """ from __future__ import division from numpy import sqrt, log, exp from scipy.optimize import fsolve, newton import numpy as np from . import _iapws97Constants as Const from ._iapws import R, Tc, Pc, rhoc, Tt, Pt, Tb, Dipole, f_acent from ._iapws import _Viscosity, _ThCond, _Tension, _Dielectric, _Refractive from ._utils import getphase, deriv_G, _fase # Critic properties sc = 4.41202148223476 hc = 2087.5468451171537 # Pmin = _PSat_T(273.15) # Minimum pressure Pmin = 0.000611212677444 # Ps_623 = _PSat_T(623.15) # P Saturation at 623.15 K, boundary region 1-3 Ps_623 = 16.5291642526 # Boundary Region1-Region3 def _h13_s(s): """Define the boundary between Region 1 and 3, h=f(s) Parameters ---------- s : float Specific entropy, [kJ/kgK] Returns ------- h : float Specific enthalpy, [kJ/kg] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * s(100MPa,623.15K) ≤ s ≤ s'(623.15K) References ---------- IAPWS, Revised Supplementary Release on Backward Equations p(h,s) for Region 3, Equations as a Function of h and s for the Region Boundaries, and an Equation Tsat(h,s) for Region 4 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-phs3-2014.pdf. Eq 7 Examples -------- >>> _h13_s(3.7) 1632.525047 >>> _h13_s(3.5) 1566.104611 """ # Check input parameters if s < 3.397782955 or s > 3.77828134: raise NotImplementedError("Incoming out of bound") n = Const.h13_s_n Li = Const.h13_s_Li Lj = Const.h13_s_Lj sigma = s / 3.8 suma = np.sum(n * (sigma - 0.884) ** Li * (sigma - 0.864) ** Lj) return 1700 * suma # Boundary Region2-Region3 def _P23_T(T): """Define the boundary between Region 2 and 3, P=f(T) Parameters ---------- T : float Temperature, [K] Returns ------- P : float Pressure, [MPa] References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 5 Examples -------- >>> _P23_T(623.15) 16.52916425 """ n = (0.34805185628969e3, -0.11671859879975e1, 0.10192970039326e-2) return n[0] + n[1] * T + n[2] * T ** 2 def _t_P(P): """Define the boundary between Region 2 and 3, T=f(P) Parameters ---------- P : float Pressure, [MPa] Returns ------- T : float Temperature, [K] References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 5 Examples -------- >>> _t_P(16.52916425) 623.15 """ n = (0.10192970039326e-2, 0.57254459862746e3, 0.1391883977870e2) return n[1] + ((P - n[2]) / n[0]) ** 0.5 def _t_hs(h, s): """Define the boundary between Region 2 and 3, T=f(h,s) Parameters ---------- h : float Specific enthalpy, [kJ/kg] s : float Specific entropy, [kJ/kgK] Returns ------- T : float Temperature, [K] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 5.048096828 ≤ s ≤ 5.260578707 * 2.563592004e3 ≤ h ≤ 2.812942061e3 References ---------- IAPWS, Revised Supplementary Release on Backward Equations p(h,s) for Region 3, Equations as a Function of h and s for the Region Boundaries, and an Equation Tsat(h,s) for Region 4 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-phs3-2014.pdf. Eq 8 Examples -------- >>> _t_hs(2600, 5.1) 713.5259364 >>> _t_hs(2800, 5.2) 817.6202120 """ # Check input parameters if s < 5.048096828 or s > 5.260578707 or \ h < 2.563592004e3 or h > 2.812942061e3: raise NotImplementedError("Incoming out of bound") nu = h / 3000 sigma = s / 5.3 n = Const.t_hs_n Li = Const.t_hs_Li Lj = Const.t_hs_Lj suma = np.sum(n * (nu - 0.727) ** Li * (sigma - 0.864) ** Lj) return 900 * suma # Saturated line def _PSat_T(T): """Define the saturated line, P=f(T) Parameters ---------- T : float Temperature, [K] Returns ------- P : float Pressure, [MPa] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 273.15 ≤ T ≤ 647.096 References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 30 Examples -------- >>> _PSat_T(500) 2.63889776 """ # Check input parameters if T < 273.15 or T > Tc: raise NotImplementedError("Incoming out of bound") n = (0, 0.11670521452767E+04, -0.72421316703206E+06, -0.17073846940092E+02, 0.12020824702470E+05, -0.32325550322333E+07, 0.14915108613530E+02, -0.48232657361591E+04, 0.40511340542057E+06, -0.23855557567849E+00, 0.65017534844798E+03) tita = T + n[9] / (T - n[10]) A = tita ** 2 + n[1] * tita + n[2] B = n[3] * tita ** 2 + n[4] * tita + n[5] C = n[6] * tita ** 2 + n[7] * tita + n[8] return (2 * C / (-B + (B ** 2 - 4 * A * C) ** 0.5)) ** 4 def _TSat_P(P): """Define the saturated line, T=f(P) Parameters ---------- P : float Pressure, [MPa] Returns ------- T : float Temperature, [K] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 0.00061121 ≤ P ≤ 22.064 References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 31 Examples -------- >>> _TSat_P(10) 584.149488 """ # Check input parameters if P < 611.212677 / 1e6 or P > 22.064: raise NotImplementedError("Incoming out of bound") n = (0, 0.11670521452767E+04, -0.72421316703206E+06, -0.17073846940092E+02, 0.12020824702470E+05, -0.32325550322333E+07, 0.14915108613530E+02, -0.48232657361591E+04, 0.40511340542057E+06, -0.23855557567849E+00, 0.65017534844798E+03) beta = P ** 0.25 E = beta ** 2 + n[3] * beta + n[6] F = n[1] * beta ** 2 + n[4] * beta + n[7] G = n[2] * beta ** 2 + n[5] * beta + n[8] D = 2 * G / (-F - (F ** 2 - 4 * E * G) ** 0.5) return (n[10] + D - ((n[10] + D) ** 2 - 4 * (n[9] + n[10] * D)) ** 0.5) / 2 def _PSat_h(h): """Define the saturated line, P=f(h) for region 3 Parameters ---------- h : float Specific enthalpy, [kJ/kg] Returns ------- P : float Pressure, [MPa] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * h'(623.15K) ≤ h ≤ h''(623.15K) References ---------- IAPWS, Revised Supplementary Release on Backward Equations for the Functions T(p,h), v(p,h) and T(p,s), v(p,s) for Region 3 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-Tv%28ph,ps%293-2014.pdf, Eq 10 Examples -------- >>> _PSat_h(1700) 17.24175718 >>> _PSat_h(2400) 20.18090839 """ # Check input parameters hmin_Ps3 = _Region1(623.15, Ps_623)["h"] hmax_Ps3 = _Region2(623.15, Ps_623)["h"] if h < hmin_Ps3 or h > hmax_Ps3: raise NotImplementedError("Incoming out of bound") n = Const.PSat_h_n Li = Const.PSat_h_Li Lj = Const.PSat_h_Lj nu = h / 2600 suma = np.sum(n * (nu - 1.02) ** Li * (nu - 0.608) ** Lj) return 22 * suma def _PSat_s(s): """Define the saturated line, P=f(s) for region 3 Parameters ---------- s : float Specific entropy, [kJ/kgK] Returns ------- P : float Pressure, [MPa] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * s'(623.15K) ≤ s ≤ s''(623.15K) References ---------- IAPWS, Revised Supplementary Release on Backward Equations for the Functions T(p,h), v(p,h) and T(p,s), v(p,s) for Region 3 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-Tv%28ph,ps%293-2014.pdf, Eq 11 Examples -------- >>> _PSat_s(3.8) 16.87755057 >>> _PSat_s(5.2) 16.68968482 """ # Check input parameters smin_Ps3 = _Region1(623.15, Ps_623)["s"] smax_Ps3 = _Region2(623.15, Ps_623)["s"] if s < smin_Ps3 or s > smax_Ps3: raise NotImplementedError("Incoming out of bound") n = Const.PSat_s_n Li = Const.PSat_s_Li Lj = Const.PSat_s_Lj sigma = s / 5.2 suma = np.sum(n * (sigma - 1.03) ** Li * (sigma - 0.699) ** Lj) return 22 * suma def _h1_s(s): """Define the saturated line boundary between Region 1 and 4, h=f(s) Parameters ---------- s : float Specific entropy, [kJ/kgK] Returns ------- h : float Specific enthalpy, [kJ/kg] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * s'(273.15K) ≤ s ≤ s'(623.15K) References ---------- IAPWS, Revised Supplementary Release on Backward Equations p(h,s) for Region 3, Equations as a Function of h and s for the Region Boundaries, and an Equation Tsat(h,s) for Region 4 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-phs3-2014.pdf. Eq 3 Examples -------- >>> _h1_s(1) 308.5509647 >>> _h1_s(3) 1198.359754 """ # Check input parameters if s < -1.545495919e-4 or s > 3.77828134: raise NotImplementedError("Incoming out of bound") n = Const.h1_s_n Li = Const.h1_s_Li Lj = Const.h1_s_Lj sigma = s / 3.8 suma = np.sum(n * (sigma - 1.09) ** Li * (sigma + 0.366e-4) ** Lj) return 1700 * suma def _h3a_s(s): """Define the saturated line boundary between Region 4 and 3a, h=f(s) Parameters ---------- s : float Specific entropy, [kJ/kgK] Returns ------- h : float Specific enthalpy, [kJ/kg] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * s'(623.15K) ≤ s ≤ sc References ---------- IAPWS, Revised Supplementary Release on Backward Equations p(h,s) for Region 3, Equations as a Function of h and s for the Region Boundaries, and an Equation Tsat(h,s) for Region 4 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-phs3-2014.pdf. Eq 4 Examples -------- >>> _h3a_s(3.8) 1685.025565 >>> _h3a_s(4.2) 1949.352563 """ # Check input parameters if s < 3.77828134 or s > 4.41202148223476: raise NotImplementedError("Incoming out of bound") n = Const.h3a_s_n Li = Const.h3a_s_Li Lj = Const.h3a_s_Lj sigma = s / 3.8 suma = np.sum(n * (sigma - 1.09) ** Li * (sigma + 0.366e-4) ** Lj) return 1700 * suma def _h2ab_s(s): """Define the saturated line boundary between Region 4 and 2a-2b, h=f(s) Parameters ---------- s : float Specific entropy, [kJ/kgK] Returns ------- h : float Specific enthalpy, [kJ/kg] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 5.85 ≤ s ≤ s"(273.15K) References ---------- IAPWS, Revised Supplementary Release on Backward Equations p(h,s) for Region 3, Equations as a Function of h and s for the Region Boundaries, and an Equation Tsat(h,s) for Region 4 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-phs3-2014.pdf. Eq 5 Examples -------- >>> _h2ab_s(7) 2723.729985 >>> _h2ab_s(9) 2511.861477 """ # Check input parameters if s < 5.85 or s > 9.155759395: raise NotImplementedError("Incoming out of bound") n = Const.h2ab_s_n Li = Const.h2ab_s_Li Lj = Const.h2ab_s_Lj sigma1 = s / 5.21 sigma2 = s / 9.2 suma = np.sum(n * (1 / sigma1 - 0.513) ** Li * (sigma2 - 0.524) ** Lj) return 2800 * exp(suma) def _h2c3b_s(s): """Define the saturated line boundary between Region 4 and 2c-3b, h=f(s) Parameters ---------- s : float Specific entropy, [kJ/kgK] Returns ------- h : float Specific enthalpy, [kJ/kg] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * sc ≤ s ≤ 5.85 References ---------- IAPWS, Revised Supplementary Release on Backward Equations p(h,s) for Region 3, Equations as a Function of h and s for the Region Boundaries, and an Equation Tsat(h,s) for Region 4 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-phs3-2014.pdf. Eq 6 Examples -------- >>> _h2c3b_s(5.5) 2687.693850 >>> _h2c3b_s(4.5) 2144.360448 """ # Check input parameters if s < 4.41202148223476 or s > 5.85: raise NotImplementedError("Incoming out of bound") n = Const.h2c3b_s_n Li = Const.h2c3b_s_Li Lj = Const.h2c3b_s_Lj sigma = s / 5.9 suma = np.sum(n * (sigma - 1.02) ** Li * (sigma - 0.726) ** Lj) return 2800 * suma ** 4 # Region 1 def _Region1(T, P): """Basic equation for region 1 Parameters ---------- T : float Temperature, [K] P : float Pressure, [MPa] Returns ------- prop : dict Dict with calculated properties. The available properties are: * v: Specific volume, [m³/kg] * h: Specific enthalpy, [kJ/kg] * s: Specific entropy, [kJ/kgK] * cp: Specific isobaric heat capacity, [kJ/kgK] * cv: Specific isocoric heat capacity, [kJ/kgK] * w: Speed of sound, [m/s] * alfav: Cubic expansion coefficient, [1/K] * kt: Isothermal compressibility, [1/MPa] References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 7 Examples -------- >>> _Region1(300,3)["v"] 0.00100215168 >>> _Region1(300,3)["h"] 115.331273 >>> _Region1(300,3)["h"]-3000*_Region1(300,3)["v"] 112.324818 >>> _Region1(300,80)["s"] 0.368563852 >>> _Region1(300,80)["cp"] 4.01008987 >>> _Region1(300,80)["cv"] 3.91736606 >>> _Region1(500,3)["w"] 1240.71337 >>> _Region1(500,3)["alfav"] 0.00164118128 >>> _Region1(500,3)["kt"] 0.00112892188 """ if P < 0: P = Pmin Tr = 1386 / T Pr = P / 16.53 n = Const.Region1_n Li = Const.Region1_Li Lj = Const.Region1_Lj Li_1 = Const.Region1_Li_less_1 Li_2 = Const.Region1_Li_less_2 Lj_1 = Const.Region1_Lj_less_1 Lj_2 = Const.Region1_Lj_less_2 g = np.sum(n * (7.1-Pr)**Li * (Tr-1.222)**Lj) gp = -np.sum(n * Li * (7.1-Pr)**Li_1 * (Tr-1.222)**Lj) gpp = np.sum(n * Li * Li_1 * (7.1-Pr)**Li_2 * (Tr-1.222)**Lj) gt = np.sum(n * Lj * (7.1-Pr)**Li * (Tr-1.222)**Lj_1) gtt = np.sum(n * Lj * Lj_1 * (7.1-Pr)**Li * (Tr-1.222)**Lj_2) gpt = -np.sum(n * Li * Lj * (7.1-Pr)**Li_1 * (Tr-1.222)**Lj_1) propiedades = {} propiedades["T"] = T propiedades["P"] = P propiedades["v"] = Pr * gp * R * T / P / 1000 propiedades["h"] = Tr * gt * R * T propiedades["s"] = R * (Tr * gt - g) propiedades["cp"] = -R * Tr ** 2 * gtt propiedades["cv"] = R * (-Tr ** 2 * gtt + (gp - Tr * gpt) ** 2 / gpp) propiedades["w"] = sqrt(R * T * 1000 * gp ** 2 / \ ((gp - Tr * gpt) ** 2 / (Tr ** 2 * gtt) - gpp)) propiedades["alfav"] = (1 - Tr * gpt / gp) / T propiedades["kt"] = -Pr * gpp / gp / P propiedades["region"] = 1 propiedades["x"] = 0 return propiedades def _Backward1_T_Ph(P, h): """ Backward equation for region 1, T=f(P,h) Parameters ---------- P : float Pressure, [MPa] h : float Specific enthalpy, [kJ/kg] Returns ------- T : float Temperature, [K] References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 11 Examples -------- >>> _Backward1_T_Ph(3,500) 391.798509 >>> _Backward1_T_Ph(80,1500) 611.041229 """ n = Const.Backward1_T_Ph_n Li = Const.Backward1_T_Ph_Li Lj = Const.Backward1_T_Ph_Lj Pr = P / 1 nu = h / 2500 T = np.sum(n * Pr ** Li * (nu + 1) ** Lj) return T def _Backward1_T_Ps(P, s): """Backward equation for region 1, T=f(P,s) Parameters ---------- P : float Pressure, [MPa] s : float Specific entropy, [kJ/kgK] Returns ------- T : float Temperature, [K] References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 13 Examples -------- >>> _Backward1_T_Ps(3,0.5) 307.842258 >>> _Backward1_T_Ps(80,3) 565.899909 """ n = Const.Backward1_T_Ps_n Li = Const.Backward1_T_Ps_Li Lj = Const.Backward1_T_Ps_Lj Pr = P / 1 sigma = s / 1 T = np.sum(n * Pr ** Li * (sigma + 2) ** Lj) return T def _Backward1_P_hs(h, s): """Backward equation for region 1, P=f(h,s) Parameters ---------- h : float Specific enthalpy, [kJ/kg] s : float Specific entropy, [kJ/kgK] Returns ------- P : float Pressure, [MPa] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for Pressure as a Function of Enthalpy and Entropy p(h,s) for Regions 1 and 2 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-PHS12-2014.pdf, Eq 1 Examples -------- >>> _Backward1_P_hs(0.001,0) 0.0009800980612 >>> _Backward1_P_hs(90,0) 91.92954727 >>> _Backward1_P_hs(1500,3.4) 58.68294423 """ n = Const.Backward1_P_hs_n Li = Const.Backward1_P_hs_Li Lj = Const.Backward1_P_hs_Lj nu = h / 3400 sigma = s / 7.6 P = np.sum(n * (nu + 0.05) ** Li * (sigma + 0.05) ** Lj) return 100 * P # Region 2 def _Region2(T, P): """Basic equation for region 2 Parameters ---------- T : float Temperature, [K] P : float Pressure, [MPa] Returns ------- prop : dict Dict with calculated properties. The available properties are: * v: Specific volume, [m³/kg] * h: Specific enthalpy, [kJ/kg] * s: Specific entropy, [kJ/kgK] * cp: Specific isobaric heat capacity, [kJ/kgK] * cv: Specific isocoric heat capacity, [kJ/kgK] * w: Speed of sound, [m/s] * alfav: Cubic expansion coefficient, [1/K] * kt: Isothermal compressibility, [1/MPa] References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 15-17 Examples -------- >>> _Region2(700,30)["v"] 0.00542946619 >>> _Region2(700,30)["h"] 2631.49474 >>> _Region2(700,30)["h"]-30000*_Region2(700,30)["v"] 2468.61076 >>> _Region2(700,0.0035)["s"] 10.1749996 >>> _Region2(700,0.0035)["cp"] 2.08141274 >>> _Region2(700,0.0035)["cv"] 1.61978333 >>> _Region2(300,0.0035)["w"] 427.920172 >>> _Region2(300,0.0035)["alfav"] 0.00337578289 >>> _Region2(300,0.0035)["kt"] 286.239651 """ if P < 0: P = Pmin n = Const.Region2_n Li = Const.Region2_Li Lj = Const.Region2_Lj Li_1 = Const.Region2_Li_less_1 Li_2 = Const.Region2_Li_less_2 Lj_1 = Const.Region2_Lj_less_1 Lj_2 = Const.Region2_Lj_less_2 Tr = 540 / T Pr = P / 1 go, gop, gopp, got, gott, gopt = Region2_cp0(Tr, Pr) gr = np.sum(n * Pr**Li * (Tr-0.5)**Lj) grp = np.sum(n * Li * Pr**Li_1 * (Tr-0.5)**Lj) grpp = np.sum(n * Li * Li_1 * Pr**Li_2 * (Tr-0.5)**Lj) grt = np.sum(n * Lj * Pr**Li * (Tr-0.5)**Lj_1) grtt = np.sum(n * Lj * Lj_1 * Pr**Li * (Tr-0.5)**Lj_2) grpt = np.sum(n * Li * Lj * Pr**Li_1 * (Tr-0.5)**Lj_1) propiedades = {} propiedades["T"] = T propiedades["P"] = P propiedades["v"] = Pr * (gop + grp) * R * T / P / 1000 propiedades["h"] = Tr * (got + grt) * R * T propiedades["s"] = R * (Tr * (got + grt) - (go + gr)) propiedades["cp"] = -R * Tr ** 2 * (gott + grtt) propiedades["cv"] = R * (-Tr**2*(gott+grtt) - (1 + Pr*grp - Tr*Pr*grpt)**2 / (1 - Pr ** 2 * grpp)) propiedades["w"] = (R*T*1000*(1 + 2*Pr*grp + Pr**2*grp**2) / (1 - Pr**2*grpp + (1 + Pr*grp - Tr*Pr*grpt)**2 / Tr**2 / (gott + grtt))) ** 0.5 propiedades["alfav"] = (1 + Pr * grp - Tr * Pr * grpt) / (1 + Pr * grp) / T propiedades["kt"] = (1 - Pr ** 2 * grpp) / (1 + Pr * grp) / P propiedades["region"] = 2 propiedades["x"] = 1 return propiedades def Region2_cp0(Tr, Pr, meta=False): """Ideal properties for Region 2 Parameters ---------- Tr : float Reduced temperature, [-] Pr : float Reduced pressure, [-] meta : boolean Boolean to set the calculation from metastable region Returns ------- prop : array Array with ideal Gibbs energy partial derivatives: * g: Ideal Specific Gibbs energy [kJ/kg] * gp: ∂g/∂P|T * gpp: ∂²g/∂P²|T * gt: ∂g/∂T|P * gtt: ∂²g/∂T²|P * gpt: ∂²g/∂T∂P References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 16 """ if meta: no = Const.Region2_cp0_no_meta else: no = Const.Region2_cp0_no Jo = Const.Region2_cp0_Jo go = log(Pr) gop = Pr ** -1 gopp = -Pr ** -2 gopt = 0 go += np.sum(no * Tr**Jo) got = np.sum(no * Jo * Tr**(Jo-1)) gott = np.sum(no * Jo * (Jo-1) * Tr**(Jo-2)) return go, gop, gopp, got, gott, gopt def _Region2_meta(T, P): """Basic equation for region 2 in the metaestable region Parameters ---------- T : float Temperature, [K] P : float Pressure, [MPa] Returns ------- prop : dict Dict with calculated properties. The available properties are: * v: Specific volume, [m³/kg] * h: Specific enthalpy, [kJ/kg] * s: Specific entropy, [kJ/kgK] * cp: Specific isobaric heat capacity, [kJ/kgK] * cv: Specific isocoric heat capacity, [kJ/kgK] * w: Speed of sound, [m/s] * alfav: Cubic expansion coefficient, [1/K] * kt: Isothermal compressibility, [1/MPa] References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 18-19 Examples -------- >>> _Region2_meta(450, 1)["v"] 0.192516540 >>> _Region2_meta(450, 1)["h"] 2768.81115 >>> _Region2_meta(450, 1)["h"]-1000*_Region2_meta(450, 1)["v"] 2576.29461 >>> _Region2_meta(450, 1)["s"] 6.56660377 >>> _Region2_meta(450, 1)["cp"] 2.76349265 >>> _Region2_meta(450, 1)["w"] 498.408101 """ if P < 0: P = Pmin n = Const.Region2_nr_m Ir = Const.Region2_Ir_m Jr = Const.Region2_Jr_m Ir_1 = Const.Region2_Li_less_1_m Ir_2 = Const.Region2_Li_less_2_m Jr_1 = Const.Region2_Lj_less_1_m Jr_2 = Const.Region2_Lj_less_2_m Tr = 540 / T Pr = P / 1 go, gop, gopp, got, gott, gopt = Region2_cp0(Tr, Pr, True) gr = np.sum(n * Pr**Ir * (Tr-0.5)**Jr) grp = np.sum(n * Ir * Pr**Ir_1 * (Tr-0.5)**Jr) grpp = np.sum(n * Ir * Ir_1 * Pr**Ir_2 * (Tr-0.5)**Jr) grt = np.sum(n * Jr * Pr**Ir * (Tr-0.5)**Jr_1) grtt = np.sum(n * Jr * Jr_1 * Pr**Ir * (Tr-0.5)**Jr_2) grpt = np.sum(n * Ir * Jr * Pr**Ir_1 * (Tr-0.5)**Jr_1) propiedades = {} propiedades["T"] = T propiedades["P"] = P propiedades["v"] = Pr * (gop + grp) * R * T / P / 1000 propiedades["h"] = Tr * (got + grt) * R * T propiedades["s"] = R * (Tr * (got + grt) - (go + gr)) propiedades["cp"] = -R * Tr ** 2 * (gott + grtt) propiedades["cv"] = R * (-Tr**2*(gott+grtt) - (1+Pr*grp-Tr*Pr*grpt)**2 / (1-Pr**2*grpp)) propiedades["w"] = (R*T*1000*(1 + 2*Pr*grp + Pr**2*grp**2) / (1-Pr**2*grpp + (1+Pr*grp-Tr*Pr*grpt)**2 / Tr**2 / (gott + grtt))) ** 0.5 propiedades["alfav"] = (1 + Pr * grp - Tr * Pr * grpt) / (1 + Pr * grp) / T propiedades["kt"] = (1 - Pr ** 2 * grpp) / (1 + Pr * grp) / P propiedades["region"] = 2 propiedades["x"] = 1 return propiedades def _P_2bc(h): """Define the boundary between Region 2b and 2c, P=f(h) Parameters ---------- h : float Specific enthalpy, [kJ/kg] Returns ------- P : float Pressure, [MPa] References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 20 Examples -------- >>> _P_2bc(3516.004323) 100.0 """ return 905.84278514723 - 0.67955786399241 * h + 1.2809002730136e-4 * h ** 2 def _hbc_P(P): """Define the boundary between Region 2b and 2c, h=f(P) Parameters ---------- P : float Pressure, [MPa] Returns ------- h : float Specific enthalpy, [kJ/kg] References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 21 Examples -------- >>> _hbc_P(100) 3516.004323 """ return 0.26526571908428e4 + ((P-4.5257578905948) / 1.2809002730136e-4)**0.5 def _hab_s(s): """Define the boundary between Region 2a and 2b, h=f(s) Parameters ---------- s : float Specific entropy, [kJ/kgK] Returns ------- h : float Specific enthalpy, [kJ/kg] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for Pressure as a Function of Enthalpy and Entropy p(h,s) for Regions 1 and 2 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-PHS12-2014.pdf, Eq 2 Examples -------- >>> _hab_s(7) 3376.437884 """ smin = _Region2(_TSat_P(4), 4)["s"] smax = _Region2(1073.15, 4)["s"] if s < smin: h = 0 elif s > smax: h = 5000 else: h = -0.349898083432139e4 + 0.257560716905876e4 * s - \ 0.421073558227969e3 * s ** 2 + 0.276349063799944e2 * s ** 3 return h def _Backward2a_T_Ph(P, h): """Backward equation for region 2a, T=f(P,h) Parameters ---------- P : float Pressure, [MPa] h : float Specific enthalpy, [kJ/kg] Returns ------- T : float Temperature, [K] References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 22 Examples -------- >>> _Backward2a_T_Ph(0.001,3000) 534.433241 >>> _Backward2a_T_Ph(3,4000) 1010.77577 """ n = Const.Backward2a_T_Ph_n Li = Const.Backward2a_T_Ph_Li Lj = Const.Backward2a_T_Ph_Lj Pr = P / 1 nu = h / 2000 T = np.sum(n * Pr**Li * (nu-2.1)**Lj) return T def _Backward2b_T_Ph(P, h): """Backward equation for region 2b, T=f(P,h) Parameters ---------- P : float Pressure, [MPa] h : float Specific enthalpy, [kJ/kg] Returns ------- T : float Temperature, [K] References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 23 Examples -------- >>> _Backward2b_T_Ph(5,4000) 1015.31583 >>> _Backward2b_T_Ph(25,3500) 875.279054 """ n = Const.Backward2b_T_Ph_n Li = Const.Backward2b_T_Ph_Li Lj = Const.Backward2b_T_Ph_Lj Pr = P / 1 nu = h / 2000 T = np.sum(n * (Pr-2)**Li * (nu-2.6)**Lj) return T def _Backward2c_T_Ph(P, h): """Backward equation for region 2c, T=f(P,h) Parameters ---------- P : float Pressure, [MPa] h : float Specific enthalpy, [kJ/kg] Returns ------- T : float Temperature, [K] References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 24 Examples -------- >>> _Backward2c_T_Ph(40,2700) 743.056411 >>> _Backward2c_T_Ph(60,3200) 882.756860 """ n = Const.Backward2c_T_Ph_n Li = Const.Backward2c_T_Ph_Li Lj = Const.Backward2c_T_Ph_Lj Pr = P / 1 nu = h / 2000 T = np.sum(n * (Pr+25)**Li * (nu-1.8)**Lj) return T def _Backward2_T_Ph(P, h): """Backward equation for region 2, T=f(P,h) Parameters ---------- P : float Pressure, [MPa] h : float Specific enthalpy, [kJ/kg] Returns ------- T : float Temperature, [K] """ if P <= 4: T = _Backward2a_T_Ph(P, h) elif 4 < P <= 6.546699678: T = _Backward2b_T_Ph(P, h) else: hf = _hbc_P(P) if h >= hf: T = _Backward2b_T_Ph(P, h) else: T = _Backward2c_T_Ph(P, h) if P <= 22.064: Tsat = _TSat_P(P) T = max(Tsat, T) return T def _Backward2a_T_Ps(P, s): """Backward equation for region 2a, T=f(P,s) Parameters ---------- P : float Pressure, [MPa] s : float Specific entropy, [kJ/kgK] Returns ------- T : float Temperature, [K] References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 25 Examples -------- >>> _Backward2a_T_Ps(0.1,7.5) 399.517097 >>> _Backward2a_T_Ps(2.5,8) 1039.84917 """ n = Const.Backward2a_T_Ps_n Li = Const.Backward2a_T_Ps_Li Lj = Const.Backward2a_T_Ps_Lj Pr = P / 1 sigma = s / 2 T = np.sum(n * Pr**Li * (sigma-2)**Lj) return T def _Backward2b_T_Ps(P, s): """Backward equation for region 2b, T=f(P,s) Parameters ---------- P : float Pressure, [MPa] s : float Specific entropy, [kJ/kgK] Returns ------- T : float Temperature, [K] References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 26 Examples -------- >>> _Backward2b_T_Ps(8,6) 600.484040 >>> _Backward2b_T_Ps(90,6) 1038.01126 """ n = Const.Backward2b_T_Ps_n Li = Const.Backward2b_T_Ps_Li Lj = Const.Backward2b_T_Ps_Lj Pr = P / 1 sigma = s / 0.7853 T = np.sum(n * Pr**Li * (10-sigma)**Lj) return T def _Backward2c_T_Ps(P, s): """Backward equation for region 2c, T=f(P,s) Parameters ---------- P : float Pressure, [MPa] s : float Specific entropy, [kJ/kgK] Returns ------- T : float Temperature, [K] References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 27 Examples -------- >>> _Backward2c_T_Ps(20,5.75) 697.992849 >>> _Backward2c_T_Ps(80,5.75) 949.017998 """ n = Const.Backward2c_T_Ps_n Li = Const.Backward2c_T_Ps_Li Lj = Const.Backward2c_T_Ps_Lj Pr = P / 1 sigma = s / 2.9251 T = np.sum(n * Pr**Li * (2-sigma)**Lj) return T def _Backward2_T_Ps(P, s): """Backward equation for region 2, T=f(P,s) Parameters ---------- P : float Pressure, [MPa] s : float Specific entropy, [kJ/kgK] Returns ------- T : float Temperature, [K] """ if P <= 4: T = _Backward2a_T_Ps(P, s) elif s >= 5.85: T = _Backward2b_T_Ps(P, s) else: T = _Backward2c_T_Ps(P, s) if P <= 22.064: Tsat = _TSat_P(P) T = max(Tsat, T) return T def _Backward2a_P_hs(h, s): """Backward equation for region 2a, P=f(h,s) Parameters ---------- h : float Specific enthalpy, [kJ/kg] s : float Specific entropy, [kJ/kgK] Returns ------- P : float Pressure, [MPa] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for Pressure as a Function of Enthalpy and Entropy p(h,s) for Regions 1 and 2 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-PHS12-2014.pdf, Eq 3 Examples -------- >>> _Backward2a_P_hs(2800,6.5) 1.371012767 >>> _Backward2a_P_hs(2800,9.5) 0.001879743844 >>> _Backward2a_P_hs(4100,9.5) 0.1024788997 """ n = Const.Backward2a_P_hs_n Li = Const.Backward2a_P_hs_Li Lj = Const.Backward2a_P_hs_Lj nu = h / 4200 sigma = s / 12 suma = np.sum(n * (nu-0.5)**Li * (sigma-1.2)**Lj) return 4 * suma ** 4 def _Backward2b_P_hs(h, s): """Backward equation for region 2b, P=f(h,s) Parameters ---------- h : float Specific enthalpy, [kJ/kg] s : float Specific entropy, [kJ/kgK] Returns ------- P : float Pressure, [MPa] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for Pressure as a Function of Enthalpy and Entropy p(h,s) for Regions 1 and 2 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-PHS12-2014.pdf, Eq 4 Examples -------- >>> _Backward2b_P_hs(2800,6) 4.793911442 >>> _Backward2b_P_hs(3600,6) 83.95519209 >>> _Backward2b_P_hs(3600,7) 7.527161441 """ n = Const.Backward2b_P_hs_n Li = Const.Backward2b_P_hs_Li Lj = Const.Backward2b_P_hs_Lj nu = h / 4100 sigma = s / 7.9 suma = np.sum(n * (nu-0.6)**Li * (sigma-1.01)**Lj) return 100 * suma ** 4 def _Backward2c_P_hs(h, s): """Backward equation for region 2c, P=f(h,s) Parameters ---------- h : float Specific enthalpy, [kJ/kg] s : float Specific entropy, [kJ/kgK] Returns ------- P : float Pressure, [MPa] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for Pressure as a Function of Enthalpy and Entropy p(h,s) for Regions 1 and 2 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-PHS12-2014.pdf, Eq 5 Examples -------- >>> _Backward2c_P_hs(2800,5.1) 94.39202060 >>> _Backward2c_P_hs(2800,5.8) 8.414574124 >>> _Backward2c_P_hs(3400,5.8) 83.76903879 """ n = Const.Backward2c_P_hs_n Li = Const.Backward2c_P_hs_Li Lj = Const.Backward2c_P_hs_Lj nu = h / 3500 sigma = s / 5.9 suma = np.sum(n * (nu-0.7)**Li * (sigma-1.1)**Lj) return 100 * suma ** 4 def _Backward2_P_hs(h, s): """Backward equation for region 2, P=f(h,s) Parameters ---------- h : float Specific enthalpy, [kJ/kg] s : float Specific entropy, [kJ/kgK] Returns ------- P : float Pressure, [MPa] """ sfbc = 5.85 hamin = _hab_s(s) if h <= hamin: P = _Backward2a_P_hs(h, s) elif s >= sfbc: P = _Backward2b_P_hs(h, s) else: P = _Backward2c_P_hs(h, s) return P # Region 3 def _Region3(rho, T): """Basic equation for region 3 Parameters ---------- rho : float Density, [kg/m³] T : float Temperature, [K] Returns ------- prop : dict Dict with calculated properties. The available properties are: * v: Specific volume, [m³/kg] * h: Specific enthalpy, [kJ/kg] * s: Specific entropy, [kJ/kgK] * cp: Specific isobaric heat capacity, [kJ/kgK] * cv: Specific isocoric heat capacity, [kJ/kgK] * w: Speed of sound, [m/s] * alfav: Cubic expansion coefficient, [1/K] * kt: Isothermal compressibility, [1/MPa] References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 28 Examples -------- >>> _Region3(500,650)["P"] 25.5837018 >>> _Region3(500,650)["h"] 1863.43019 >>> p = _Region3(500, 650) >>> p["h"]-p["P"]*1000*p["v"] 1812.26279 >>> _Region3(200,650)["s"] 4.85438792 >>> _Region3(200,650)["cp"] 44.6579342 >>> _Region3(200,650)["cv"] 4.04118076 >>> _Region3(200,650)["w"] 383.444594 >>> _Region3(500,750)["alfav"] 0.00441515098 >>> _Region3(500,750)["kt"] 0.00806710817 """ d = rho / rhoc Tr = Tc / T n = Const.Region3_n Li = Const.Region3_Li Lj = Const.Region3_Lj Li_1 = Const.Region3_Li_less_1 Li_2 = Const.Region3_Li_less_2 Lj_1 = Const.Region3_Lj_less_1 Lj_2 = Const.Region3_Lj_less_2 g = (1.0658070028513 * log(d)) + np.sum(n * d**Li * Tr**Lj) gd = (1.0658070028513 / d) + np.sum(n * Li * d**Li_1 * Tr**Lj) gdd = (-1.0658070028513/d**2) + np.sum(n * Li * Li_1 * d**Li_2 * Tr**Lj) gt = np.sum(n * Lj * d**Li * Tr**Lj_1) gtt = np.sum(n * Lj * Lj_1 * d**Li * Tr**Lj_2) gdt = np.sum(n * Li * Lj * d**Li_1 * Tr**Lj_1) propiedades = {} propiedades["T"] = T propiedades["P"] = d * gd * R * T * rho / 1000 propiedades["v"] = 1 / rho propiedades["h"] = R * T * (Tr * gt + d * gd) propiedades["s"] = R * (Tr * gt - g) propiedades["cp"] = R * (-Tr**2*gtt+(d*gd-d*Tr*gdt)**2/(2*d*gd+d**2*gdd)) propiedades["cv"] = -R * Tr ** 2 * gtt propiedades["w"] = sqrt(R*T*1000 * (2*d*gd + d**2*gdd - (d*gd - d*Tr*gdt)**2 / Tr**2 / gtt)) propiedades["alfav"] = (gd - Tr * gdt) / (2 * gd + d * gdd) / T propiedades["kt"] = 1 / (2 * d * gd + d ** 2 * gdd) / rho / R / T * 1000 propiedades["region"] = 3 propiedades["x"] = 1 if T < Tc and propiedades["P"] < Pc: t_sat = _TSat_P(propiedades["P"]) if T < t_sat: propiedades["x"] = 0 return propiedades def _h_3ab(P): """Define the boundary between Region 3a-3b, h=f(P) Parameters ---------- P : float Pressure, [MPa] Returns ------- h : float Specific enthalpy, [kJ/kg] Examples -------- >>> _h_3ab(25) 2095.936454 """ h = 0.201464004206875e4 + 3.74696550136983*P - 0.0219921901054187*P**2 \ + 0.875131686009950e-4*P**3 return h def _tab_P(P): """Define the boundary between Region 3a-3b, T=f(P) Parameters ---------- P : float Pressure, [MPa] Returns ------- T : float Temperature, [K] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for Specific Volume as a Function of Pressure and Temperature v(p,T) for Region 3 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-VPT3-2016.pdf, Eq. 2 Examples -------- >>> _tab_P(40) 693.0341408 """ Pr = P / 1 T = np.sum(Const.tab_P_n * log(Pr) ** Const.tab_P_Li) return T def _top_P(P): """Define the boundary between Region 3o-3p, T=f(P) Parameters ---------- P : float Pressure, [MPa] Returns ------- T : float Temperature, [K] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for Specific Volume as a Function of Pressure and Temperature v(p,T) for Region 3 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-VPT3-2016.pdf, Eq. 2 Examples -------- >>> _top_P(22.8) 650.0106943 """ Pr = P / 1 T = np.sum(Const.top_P_n * log(Pr) ** Const.top_P_Li) return T def _twx_P(P): """Define the boundary between Region 3w-3x, T=f(P) Parameters ---------- P : float Pressure, [MPa] Returns ------- T : float Temperature, [K] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for Specific Volume as a Function of Pressure and Temperature v(p,T) for Region 3 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-VPT3-2016.pdf, Eq. 2 Examples -------- >>> _twx_P(22.3) 648.2049480 """ Pr = P / 1 T = np.sum(Const.twx_P_n * log(Pr) ** Const.twx_P_Li) return T def _tef_P(P): """Define the boundary between Region 3e-3f, T=f(P) Parameters ---------- P : float Pressure, [MPa] Returns ------- T : float Temperature, [K] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for Specific Volume as a Function of Pressure and Temperature v(p,T) for Region 3 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-VPT3-2016.pdf, Eq. 3 Examples -------- >>> _tef_P(40) 713.9593992 """ return 3.727888004*(P-22.064) + 647.096 def _txx_P(P, xy): """Define the boundary between 3x-3y, T=f(P) Parameters ---------- P : float Pressure, [MPa] xy: string Subregions options: cd, gh, ij, jk, mn, qu, rx, uv Returns ------- T : float Temperature, [K] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for Specific Volume as a Function of Pressure and Temperature v(p,T) for Region 3 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-VPT3-2016.pdf, Eq. 1 Examples -------- >>> _txx_P(25,"cd") 649.3659208 >>> _txx_P(23,"gh") 649.8873759 >>> _txx_P(23,"ij") 651.5778091 >>> _txx_P(23,"jk") 655.8338344 >>> _txx_P(22.8,"mn") 649.6054133 >>> _txx_P(22,"qu") 645.6355027 >>> _txx_P(22,"rx") 648.2622754 >>> _txx_P(22.3,"uv") 647.7996121 """ ng = { "cd": [0.585276966696349e3, 0.278233532206915e1, -0.127283549295878e-1, 0.159090746562729e-3], "gh": [-0.249284240900418e5, 0.428143584791546e4, -0.269029173140130e3, 0.751608051114157e1, -0.787105249910383e-1], "ij": [0.584814781649163e3, -0.616179320924617, 0.260763050899562, -0.587071076864459e-2, 0.515308185433082e-4], "jk": [0.617229772068439e3, -0.770600270141675e1, 0.697072596851896, -0.157391839848015e-1, 0.137897492684194e-3], "mn": [0.535339483742384e3, 0.761978122720128e1, -0.158365725441648, 0.192871054508108e-2], "qu": [0.565603648239126e3, 0.529062258221222e1, -0.102020639611016, 0.122240301070145e-2], "rx": [0.584561202520006e3, -0.102961025163669e1, 0.243293362700452, -0.294905044740799e-2], "uv": [0.528199646263062e3, 0.890579602135307e1, -0.222814134903755, 0.286791682263697e-2]} n = ng[xy] Pr = P / 1 T = 0 for i, ni in enumerate(n): T += ni * Pr ** i return T def _Backward3a_v_Ph(P, h): """Backward equation for region 3a, v=f(P,h) Parameters ---------- P : float Pressure, [MPa] h : float Specific enthalpy, [kJ/kg] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for the Functions T(p,h), v(p,h) and T(p,s), v(p,s) for Region 3 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-Tv%28ph,ps%293-2014.pdf, Eq 4 Returns ------- v : float Specific volume, [m³/kg] Examples -------- >>> _Backward3a_v_Ph(20,1700) 0.001749903962 >>> _Backward3a_v_Ph(100,2100) 0.001676229776 """ n = Const.Backward3a_v_Ph_n Li = Const.Backward3a_v_Ph_Li Lj = Const.Backward3a_v_Ph_Lj Pr = P / 100 nu = h / 2100 suma = np.sum(n * (Pr+0.128)**Li * (nu-0.727)**Lj) return 0.0028 * suma def _Backward3b_v_Ph(P, h): """Backward equation for region 3b, v=f(P,h) Parameters ---------- P : float Pressure, [MPa] h : float Specific enthalpy, [kJ/kg] Returns ------- v : float Specific volume, [m³/kg] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for the Functions T(p,h), v(p,h) and T(p,s), v(p,s) for Region 3 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-Tv%28ph,ps%293-2014.pdf, Eq 5 Examples -------- >>> _Backward3b_v_Ph(20,2500) 0.006670547043 >>> _Backward3b_v_Ph(100,2700) 0.002404234998 """ n = Const.Backward3b_v_Ph_n Li = Const.Backward3b_v_Ph_Li Lj = Const.Backward3b_v_Ph_Lj Pr = P / 100 nu = h / 2800 suma = np.sum(n * (Pr+0.0661)**Li * (nu-0.72)**Lj) return 0.0088 * suma def _Backward3_v_Ph(P, h): """Backward equation for region 3, v=f(P,h) Parameters ---------- P : float Pressure, [MPa] h : float Specific enthalpy, [kJ/kg] Returns ------- v : float Specific volume, [m³/kg] """ hf = _h_3ab(P) if h <= hf: return _Backward3a_v_Ph(P, h) return _Backward3b_v_Ph(P, h) def _Backward3a_T_Ph(P, h): """Backward equation for region 3a, T=f(P,h) Parameters ---------- P : float Pressure, [MPa] h : float Specific enthalpy, [kJ/kg] Returns ------- T : float Temperature, [K] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for the Functions T(p,h), v(p,h) and T(p,s), v(p,s) for Region 3 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-Tv%28ph,ps%293-2014.pdf, Eq 2 Examples -------- >>> _Backward3a_T_Ph(20,1700) 629.3083892 >>> _Backward3a_T_Ph(100,2100) 733.6163014 """ n = Const.Backward3a_T_Ph_n Li = Const.Backward3a_T_Ph_Li Lj = Const.Backward3a_T_Ph_Lj Pr = P / 100. nu = h / 2300. suma = np.sum(n * (Pr+0.240)**Li * (nu-0.615)**Lj) return 760 * suma def _Backward3b_T_Ph(P, h): """Backward equation for region 3b, T=f(P,h) Parameters ---------- P : float Pressure, [MPa] h : float Specific enthalpy, [kJ/kg] Returns ------- T : float Temperature, [K] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for the Functions T(p,h), v(p,h) and T(p,s), v(p,s) for Region 3 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-Tv%28ph,ps%293-2014.pdf, Eq 3 Examples -------- >>> _Backward3b_T_Ph(20,2500) 641.8418053 >>> _Backward3b_T_Ph(100,2700) 842.0460876 """ n = Const.Backward3b_T_Ph_n Li = Const.Backward3b_T_Ph_Li Lj = Const.Backward3b_T_Ph_Lj Pr = P / 100. nu = h / 2800. suma = np.sum(n * (Pr+0.298)**Li * (nu-0.72)**Lj) return 860 * suma def _Backward3_T_Ph(P, h): """Backward equation for region 3, T=f(P,h) Parameters ---------- P : float Pressure, [MPa] h : float Specific enthalpy, [kJ/kg] Returns ------- T : float Temperature, [K] """ hf = _h_3ab(P) if h <= hf: T = _Backward3a_T_Ph(P, h) else: T = _Backward3b_T_Ph(P, h) return T def _Backward3a_v_Ps(P, s): """Backward equation for region 3a, v=f(P,s) Parameters ---------- P : float Pressure, [MPa] s : float Specific entropy, [kJ/kgK] Returns ------- v : float Specific volume, [m³/kg] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for the Functions T(p,h), v(p,h) and T(p,s), v(p,s) for Region 3 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-Tv%28ph,ps%293-2014.pdf, Eq 8 Examples -------- >>> _Backward3a_v_Ps(20,3.8) 0.001733791463 >>> _Backward3a_v_Ps(100,4) 0.001555893131 """ n = Const.Backward3a_v_Ps_n Li = Const.Backward3a_v_Ps_Li Lj = Const.Backward3a_v_Ps_Lj Pr = P / 100 sigma = s / 4.4 suma = np.sum(n * (Pr+0.187)**Li * (sigma-0.755)**Lj) return 0.0028 * suma def _Backward3b_v_Ps(P, s): """Backward equation for region 3b, v=f(P,s) Parameters ---------- P : float Pressure, [MPa] s : float Specific entropy, [kJ/kgK] Returns ------- v : float Specific volume, [m³/kg] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for the Functions T(p,h), v(p,h) and T(p,s), v(p,s) for Region 3 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-Tv%28ph,ps%293-2014.pdf, Eq 9 Examples -------- >>> _Backward3b_v_Ps(20,5) 0.006262101987 >>> _Backward3b_v_Ps(100,5) 0.002449610757 """ n = Const.Backward3b_v_Ps_n Li = Const.Backward3b_v_Ps_Li Lj = Const.Backward3b_v_Ps_Lj Pr = P / 100 sigma = s / 5.3 suma = np.sum(n * (Pr+0.298)**Li * (sigma-0.816)**Lj) return 0.0088 * suma def _Backward3_v_Ps(P, s): """Backward equation for region 3, v=f(P,s) Parameters ---------- P : float Pressure, [MPa] s : float Specific entropy, [kJ/kgK] Returns ------- v : float Specific volume, [m³/kg] """ if s <= sc: return _Backward3a_v_Ps(P, s) return _Backward3b_v_Ps(P, s) def _Backward3a_T_Ps(P, s): """Backward equation for region 3a, T=f(P,s) Parameters ---------- P : float Pressure, [MPa] s : float Specific entropy, [kJ/kgK] Returns ------- T : float Temperature, [K] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for the Functions T(p,h), v(p,h) and T(p,s), v(p,s) for Region 3 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-Tv%28ph,ps%293-2014.pdf, Eq 6 Examples -------- >>> _Backward3a_T_Ps(20,3.8) 628.2959869 >>> _Backward3a_T_Ps(100,4) 705.6880237 """ n = Const.Backward3a_T_Ps_n Li = Const.Backward3a_T_Ps_Li Lj = Const.Backward3a_T_Ps_Lj Pr = P / 100 sigma = s / 4.4 suma = np.sum(n * (Pr+0.240)**Li * (sigma-0.703)**Lj) return 760 * suma def _Backward3b_T_Ps(P, s): """Backward equation for region 3b, T=f(P,s) Parameters ---------- P : float Pressure, [MPa] s : float Specific entropy, [kJ/kgK] Returns ------- T : float Temperature, [K] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for the Functions T(p,h), v(p,h) and T(p,s), v(p,s) for Region 3 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-Tv%28ph,ps%293-2014.pdf, Eq 7 Examples -------- >>> _Backward3b_T_Ps(20,5) 640.1176443 >>> _Backward3b_T_Ps(100,5) 847.4332825 """ n = Const.Backward3b_T_Ps_n Li = Const.Backward3b_T_Ps_Li Lj = Const.Backward3b_T_Ps_Lj Pr = P / 100 sigma = s / 5.3 suma = np.sum(n * (Pr+0.760)**Li * (sigma-0.818)**Lj) return 860 * suma def _Backward3_T_Ps(P, s): """Backward equation for region 3, T=f(P,s) Parameters ---------- P : float Pressure, [MPa] s : float Specific entropy, [kJ/kgK] Returns ------- T : float Temperature, [K] """ if s <= sc: return _Backward3a_T_Ps(P, s) return _Backward3b_T_Ps(P, s) def _Backward3a_P_hs(h, s): """Backward equation for region 3a, P=f(h,s) Parameters ---------- h : float Specific enthalpy, [kJ/kg] s : float Specific entropy, [kJ/kgK] Returns ------- P : float Pressure, [MPa] References ---------- IAPWS, Revised Supplementary Release on Backward Equations p(h,s) for Region 3, Equations as a Function of h and s for the Region Boundaries, and an Equation Tsat(h,s) for Region 4 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-phs3-2014.pdf. Eq 1 Examples -------- >>> _Backward3a_P_hs(1700,3.8) 25.55703246 >>> _Backward3a_P_hs(2000,4.2) 45.40873468 >>> _Backward3a_P_hs(2100,4.3) 60.78123340 """ n = Const.Backward3a_P_hs_n Li = Const.Backward3a_P_hs_Li Lj = Const.Backward3a_P_hs_Lj nu = h / 2300 sigma = s / 4.4 suma = np.sum(n * (nu-1.01)**Li * (sigma-0.75)**Lj) return 99 * suma def _Backward3b_P_hs(h, s): """Backward equation for region 3b, P=f(h,s) Parameters ---------- h : float Specific enthalpy, [kJ/kg] s : float Specific entropy, [kJ/kgK] Returns ------- P : float Pressure, [MPa] References ---------- IAPWS, Revised Supplementary Release on Backward Equations p(h,s) for Region 3, Equations as a Function of h and s for the Region Boundaries, and an Equation Tsat(h,s) for Region 4 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-phs3-2014.pdf. Eq 1 Examples -------- >>> _Backward3b_P_hs(2400,4.7) 63.63924887 >>> _Backward3b_P_hs(2600,5.1) 34.34999263 >>> _Backward3b_P_hs(2700,5.0) 88.39043281 """ n = Const.Backward3b_P_hs_n Li = Const.Backward3b_P_hs_Li Lj = Const.Backward3b_P_hs_Lj nu = h / 2800 sigma = s / 5.3 suma = np.sum(n * (nu-0.681)**Li * (sigma-0.792)**Lj) return 16.6 / suma def _Backward3_P_hs(h, s): """Backward equation for region 3, P=f(h,s) Parameters ---------- h : float Specific enthalpy, [kJ/kg] s : float Specific entropy, [kJ/kgK] Returns ------- P : float Pressure, [MPa] """ if s <= sc: return _Backward3a_P_hs(h, s) return _Backward3b_P_hs(h, s) def _Backward3_sat_v_P(P, T, x): """Backward equation for region 3 for saturated state, vs=f(P,x) Parameters ---------- T : float Temperature, [K] P : float Pressure, [MPa] x : integer Vapor quality, [-] Returns ------- v : float Specific volume, [m³/kg] Notes ----- The vapor quality (x) can be 0 (saturated liquid) or 1 (saturated vapour) """ if x == 0: if P < 19.00881189: region = "c" elif P < 21.0434: region = "s" elif P < 21.9316: region = "u" else: region = "y" else: if P < 20.5: region = "t" elif P < 21.0434: region = "r" elif P < 21.9009: region = "x" else: region = "z" return _Backward3x_v_PT(T, P, region) def _Backward3_v_PT(P, T): """Backward equation for region 3, v=f(P,T) Parameters ---------- T : float Temperature, [K] P : float Pressure, [MPa] Returns ------- v : float Specific volume, [m³/kg] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for Specific Volume as a Function of Pressure and Temperature v(p,T) for Region 3 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-VPT3-2016.pdf, Table 2 and 10 """ if P > 40: if T <= _tab_P(P): region = "a" else: region = "b" elif 25 < P <= 40: tcd = _txx_P(P, "cd") tab = _tab_P(P) tef = _tef_P(P) if T <= tcd: region = "c" elif tcd < T <= tab: region = "d" elif tab < T <= tef: region = "e" else: region = "f" elif 23.5 < P <= 25: tcd = _txx_P(P, "cd") tgh = _txx_P(P, "gh") tef = _tef_P(P) tij = _txx_P(P, "ij") tjk = _txx_P(P, "jk") if T <= tcd: region = "c" elif tcd < T <= tgh: region = "g" elif tgh < T <= tef: region = "h" elif tef < T <= tij: region = "i" elif tij < T <= tjk: region = "j" else: region = "k" elif 23 < P <= 23.5: tcd = _txx_P(P, "cd") tgh = _txx_P(P, "gh") tef = _tef_P(P) tij = _txx_P(P, "ij") tjk = _txx_P(P, "jk") if T <= tcd: region = "c" elif tcd < T <= tgh: region = "l" elif tgh < T <= tef: region = "h" elif tef < T <= tij: region = "i" elif tij < T <= tjk: region = "j" else: region = "k" elif 22.5 < P <= 23: tcd = _txx_P(P, "cd") tgh = _txx_P(P, "gh") tmn = _txx_P(P, "mn") tef = _tef_P(P) top = _top_P(P) tij = _txx_P(P, "ij") tjk = _txx_P(P, "jk") if T <= tcd: region = "c" elif tcd < T <= tgh: region = "l" elif tgh < T <= tmn: region = "m" elif tmn < T <= tef: region = "n" elif tef < T <= top: region = "o" elif top < T <= tij: region = "p" elif tij < T <= tjk: region = "j" else: region = "k" elif _PSat_T(643.15) < P <= 22.5: tcd = _txx_P(P, "cd") tqu = _txx_P(P, "qu") trx = _txx_P(P, "rx") tjk = _txx_P(P, "jk") if T <= tcd: region = "c" elif tcd < T <= tqu: region = "q" elif tqu < T <= trx: # Table 10 tef = _tef_P(P) twx = _twx_P(P) tuv = _txx_P(P, "uv") if 22.11 < P <= 22.5: if T <= tuv: region = "u" elif tuv <= T <= tef: region = "v" elif tef <= T <= twx: region = "w" else: region = "x" elif 22.064 < P <= 22.11: if T <= tuv: region = "u" elif tuv <= T <= tef: region = "y" elif tef <= T <= twx: region = "z" else: region = "x" elif T > _TSat_P(P): if _PSat_T(643.15) < P <= 21.90096265: region = "x" elif 21.90096265 < P <= 22.064: if T <= twx: region = "z" else: region = "x" elif T <= _TSat_P(P): if _PSat_T(643.15) < P <= 21.93161551: region = "u" elif 21.93161551 < P <= 22.064: if T <= tuv: region = "u" else: region = "y" elif trx < T <= tjk: region = "r" else: region = "k" elif 20.5 < P <= _PSat_T(643.15): tcd = _txx_P(P, "cd") Ts = _TSat_P(P) tjk = _txx_P(P, "jk") if T <= tcd: region = "c" elif tcd < T <= Ts: region = "s" elif Ts < T <= tjk: region = "r" else: region = "k" elif 19.00881189173929 < P <= 20.5: tcd = _txx_P(P, "cd") Ts = _TSat_P(P) if T <= tcd: region = "c" elif tcd < T <= Ts: region = "s" else: region = "t" elif Ps_623 < P <= 19.00881189173929: Ts = _TSat_P(P) if T <= Ts: region = "c" else: region = "t" return _Backward3x_v_PT(T, P, region) def _Backward3x_v_PT(T, P, x): """Backward equation for region 3x, v=f(P,T) Parameters ---------- T : float Temperature, [K] P : float Pressure, [MPa] x : char Region 3 subregion code Returns ------- v : float Specific volume, [m³/kg] References ---------- IAPWS, Revised Supplementary Release on Backward Equations for Specific Volume as a Function of Pressure and Temperature v(p,T) for Region 3 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-VPT3-2016.pdf, Eq. 4-5 Examples -------- >>> _Backward3x_v_PT(630,50,"a") 0.001470853100 >>> _Backward3x_v_PT(670,80,"a") 0.001503831359 >>> _Backward3x_v_PT(710,50,"b") 0.002204728587 >>> _Backward3x_v_PT(750,80,"b") 0.001973692940 >>> _Backward3x_v_PT(630,20,"c") 0.001761696406 >>> _Backward3x_v_PT(650,30,"c") 0.001819560617 >>> _Backward3x_v_PT(656,26,"d") 0.002245587720 >>> _Backward3x_v_PT(670,30,"d") 0.002506897702 >>> _Backward3x_v_PT(661,26,"e") 0.002970225962 >>> _Backward3x_v_PT(675,30,"e") 0.003004627086 >>> _Backward3x_v_PT(671,26,"f") 0.005019029401 >>> _Backward3x_v_PT(690,30,"f") 0.004656470142 >>> _Backward3x_v_PT(649,23.6,"g") 0.002163198378 >>> _Backward3x_v_PT(650,24,"g") 0.002166044161 >>> _Backward3x_v_PT(652,23.6,"h") 0.002651081407 >>> _Backward3x_v_PT(654,24,"h") 0.002967802335 >>> _Backward3x_v_PT(653,23.6,"i") 0.003273916816 >>> _Backward3x_v_PT(655,24,"i") 0.003550329864 >>> _Backward3x_v_PT(655,23.5,"j") 0.004545001142 >>> _Backward3x_v_PT(660,24,"j") 0.005100267704 >>> _Backward3x_v_PT(660,23,"k") 0.006109525997 >>> _Backward3x_v_PT(670,24,"k") 0.006427325645 >>> _Backward3x_v_PT(646,22.6,"l") 0.002117860851 >>> _Backward3x_v_PT(646,23,"l") 0.002062374674 >>> _Backward3x_v_PT(648.6,22.6,"m") 0.002533063780 >>> _Backward3x_v_PT(649.3,22.8,"m") 0.002572971781 >>> _Backward3x_v_PT(649,22.6,"n") 0.002923432711 >>> _Backward3x_v_PT(649.7,22.8,"n") 0.002913311494 >>> _Backward3x_v_PT(649.1,22.6,"o") 0.003131208996 >>> _Backward3x_v_PT(649.9,22.8,"o") 0.003221160278 >>> _Backward3x_v_PT(649.4,22.6,"p") 0.003715596186 >>> _Backward3x_v_PT(650.2,22.8,"p") 0.003664754790 >>> _Backward3x_v_PT(640,21.1,"q") 0.001970999272 >>> _Backward3x_v_PT(643,21.8,"q") 0.002043919161 >>> _Backward3x_v_PT(644,21.1,"r") 0.005251009921 >>> _Backward3x_v_PT(648,21.8,"r") 0.005256844741 >>> _Backward3x_v_PT(635,19.1,"s") 0.001932829079 >>> _Backward3x_v_PT(638,20,"s") 0.001985387227 >>> _Backward3x_v_PT(626,17,"t") 0.008483262001 >>> _Backward3x_v_PT(640,20,"t") 0.006227528101 >>> _Backward3x_v_PT(644.6,21.5,"u") 0.002268366647 >>> _Backward3x_v_PT(646.1,22,"u") 0.002296350553 >>> _Backward3x_v_PT(648.6,22.5,"v") 0.002832373260 >>> _Backward3x_v_PT(647.9,22.3,"v") 0.002811424405 >>> _Backward3x_v_PT(647.5,22.15,"w") 0.003694032281 >>> _Backward3x_v_PT(648.1,22.3,"w") 0.003622226305 >>> _Backward3x_v_PT(648,22.11,"x") 0.004528072649 >>> _Backward3x_v_PT(649,22.3,"x") 0.004556905799 >>> _Backward3x_v_PT(646.84,22,"y") 0.002698354719 >>> _Backward3x_v_PT(647.05,22.064,"y") 0.002717655648 >>> _Backward3x_v_PT(646.89,22,"z") 0.003798732962 >>> _Backward3x_v_PT(647.15,22.064,"z") 0.003701940009 """ par = Const.Backward3_v_PT_par Li = Const.Backward3_v_PT_Li Lj = Const.Backward3_v_PT_Lj n = Const.Backward3_v_PT_n v_, P_, T_, a, b, c, d, e = par[x] Pr = P / P_ Tr = T / T_ if x == "n": return v_ * exp(np.sum(n[x] * (Pr-a)**Li[x] * (Tr-b)**Lj[x])) return v_ * np.sum(n[x] * (Pr-a)**(c*Li[x]) * (Tr-b)**(Lj[x]*d))**e # Region 4 def _Region4(P, x): """Basic equation for region 4 Parameters ---------- P : float Pressure, [MPa] x : float Vapor quality, [-] Returns ------- prop : dict Dict with calculated properties. The available properties are: * T: Saturated temperature, [K] * P: Saturated pressure, [MPa] * x: Vapor quality, [-] * v: Specific volume, [m³/kg] * h: Specific enthalpy, [kJ/kg] * s: Specific entropy, [kJ/kgK] """ T = _TSat_P(P) if T > 623.15: rhol = 1. / _Backward3_sat_v_P(P, T, 0) P1 = _Region3(rhol, T) rhov = 1. / _Backward3_sat_v_P(P, T, 1) P2 = _Region3(rhov, T) else: P1 = _Region1(T, P) P2 = _Region2(T, P) propiedades = {} propiedades["T"] = T propiedades["P"] = P propiedades["v"] = P1["v"] + x * (P2["v"] - P1["v"]) propiedades["h"] = P1["h"] + x * (P2["h"] - P1["h"]) propiedades["s"] = P1["s"] + x * (P2["s"] - P1["s"]) propiedades["cp"] = None propiedades["cv"] = None propiedades["w"] = None propiedades["alfav"] = None propiedades["kt"] = None propiedades["region"] = 4 propiedades["x"] = x return propiedades def _Backward4_T_hs(h, s): """Backward equation for region 4, T=f(h,s) Parameters ---------- h : float Specific enthalpy, [kJ/kg] s : float Specific entropy, [kJ/kgK] Returns ------- T : float Temperature, [K] References ---------- IAPWS, Revised Supplementary Release on Backward Equations p(h,s) for Region 3, Equations as a Function of h and s for the Region Boundaries, and an Equation Tsat(h,s) for Region 4 of the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam, http://www.iapws.org/relguide/Supp-phs3-2014.pdf. Eq 9 Examples -------- >>> _Backward4_T_hs(1800,5.3) 346.8475498 >>> _Backward4_T_hs(2400,6.0) 425.1373305 >>> _Backward4_T_hs(2500,5.5) 522.5579013 """ n = Const.Backward4_T_hs_n Li = Const.Backward4_T_hs_Li Lj = Const.Backward4_T_hs_Lj nu = h / 2800 sigma = s / 9.2 suma = np.sum(n * (nu-0.119)**Li * (sigma-1.07)**Lj) return 550 * suma # Region 5 def _Region5(T, P): """Basic equation for region 5 Parameters ---------- T : float Temperature, [K] P : float Pressure, [MPa] Returns ------- prop : dict Dict with calculated properties. The available properties are: * v: Specific volume, [m³/kg] * h: Specific enthalpy, [kJ/kg] * s: Specific entropy, [kJ/kgK] * cp: Specific isobaric heat capacity, [kJ/kgK] * cv: Specific isocoric heat capacity, [kJ/kgK] * w: Speed of sound, [m/s] * alfav: Cubic expansion coefficient, [1/K] * kt: Isothermal compressibility, [1/MPa] References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 32-34 Examples -------- >>> _Region5(1500,0.5)["v"] 1.38455090 >>> _Region5(1500,0.5)["h"] 5219.76855 >>> _Region5(1500,0.5)["h"]-500*_Region5(1500,0.5)["v"] 4527.49310 >>> _Region5(1500,30)["s"] 7.72970133 >>> _Region5(1500,30)["cp"] 2.72724317 >>> _Region5(1500,30)["cv"] 2.19274829 >>> _Region5(2000,30)["w"] 1067.36948 >>> _Region5(2000,30)["alfav"] 0.000508830641 >>> _Region5(2000,30)["kt"] 0.0329193892 """ n = Const.Region5_n Li = Const.Region5_Li Lj = Const.Region5_Lj Li_1 = Const.Region5_Li_less_1 Li_2 = Const.Region5_Li_less_2 Lj_1 = Const.Region5_Lj_less_1 Lj_2 = Const.Region5_Lj_less_2 if P < 0: P = Pmin Tr = 1000 / T Pr = P / 1 go, gop, gopp, got, gott, gopt = Region5_cp0(Tr, Pr) gr = np.sum(n * Pr**Li * Tr**Lj) grp = np.sum(n * Li * Pr**Li_1 * Tr**Lj) grpp = np.sum(n * Li * Li_1 * Pr**Li_2 * Tr**Lj) grt = np.sum(n * Lj * Pr**Li * Tr**Lj_1) grtt = np.sum(n * Lj * Lj_1 * Pr**Li * Tr**Lj_2) grpt = np.sum(n * Li * Lj * Pr**Li_1 * Tr**Lj_1) propiedades = {} propiedades["T"] = T propiedades["P"] = P propiedades["v"] = Pr * (gop + grp) * R * T / P / 1000 propiedades["h"] = Tr * (got + grt) * R * T propiedades["s"] = R * (Tr * (got + grt) - (go + gr)) propiedades["cp"] = -R * Tr ** 2 * (gott + grtt) propiedades["cv"] = R * (-Tr**2*(gott+grtt) + ((gop+grp)-Tr*(gopt+grpt))**2 / (gopp+grpp)) propiedades["w"] = (R*T*1000*(1 + 2*Pr*grp + Pr**2*grp**2) / ( 1 - Pr**2*grpp + (1+Pr*grp-Tr*Pr*grpt)**2 / Tr**2 / (gott+grtt)))**0.5 propiedades["alfav"] = (1 + Pr * grp - Tr * Pr * grpt) / (1 + Pr * grp) / T propiedades["kt"] = (1 - Pr ** 2 * grpp) / (1 + Pr * grp) / P propiedades["region"] = 5 propiedades["x"] = 1 return propiedades def Region5_cp0(Tr, Pr): """Ideal properties for Region 5 Parameters ---------- Tr : float Reduced temperature, [-] Pr : float Reduced pressure, [-] Returns ------- prop : array Array with ideal Gibbs energy partial derivatives: * g: Ideal Specific Gibbs energy, [kJ/kg] * gp: [∂g/∂P]T * gpp: [∂²g/∂P²]T * gt: [∂g/∂T]P * gtt: [∂²g/∂T²]P * gpt: [∂²g/∂T∂P] References ---------- IAPWS, Revised Release on the IAPWS Industrial Formulation 1997 for the Thermodynamic Properties of Water and Steam August 2007, http://www.iapws.org/relguide/IF97-Rev.html, Eq 33 """ no = Const.Region5_cp0_no Jo = Const.Region5_cp0_Jo Jo_1 = Const.Region5_cp0_Jo_less_1 Jo_2 = Const.Region5_cp0_Jo_less_2 gop = Pr ** -1 gopp = -Pr ** -2 gopt = 0 go = log(Pr) + np.sum(no * Tr**Jo) got = np.sum(no * Jo * Tr**Jo_1) gott = np.sum(no * Jo * Jo_1 * Tr**Jo_2) return go, gop, gopp, got, gott, gopt # Region definitions def _Bound_TP(T, P): """Region definition for input T and P Parameters ---------- T : float Temperature, [K] P : float Pressure, [MPa] Returns ------- region : float IAPWS-97 region code References ---------- Wagner, W; Kretzschmar, H-J: International Steam Tables: Properties of Water and Steam Based on the Industrial Formulation IAPWS-IF97; Springer, 2008; doi: 10.1007/978-3-540-74234-0. Fig. 2.3 """ region = None if 1073.15 < T <= 2273.15 and Pmin <= P <= 50: region = 5 elif Pmin <= P <= Ps_623: Tsat = _TSat_P(P) if 273.15 <= T <= Tsat: region = 1 elif Tsat < T <= 1073.15: region = 2 elif Ps_623 < P <= 100: T_b23 = _t_P(P) if 273.15 <= T <= 623.15: region = 1 elif 623.15 < T < T_b23: region = 3 elif T_b23 <= T <= 1073.15: region = 2 return region def _Bound_Ph(P, h): """Region definition for input P y h Parameters ---------- P : float Pressure, [MPa] h : float Specific enthalpy, [kJ/kg] Returns ------- region : float IAPWS-97 region code References ---------- Wagner, W; Kretzschmar, H-J: International Steam Tables: Properties of Water and Steam Based on the Industrial Formulation IAPWS-IF97; Springer, 2008; doi: 10.1007/978-3-540-74234-0. Fig. 2.5 """ region = None if Pmin <= P <= Ps_623: h14 = _Region1(_TSat_P(P), P)["h"] h24 = _Region2(_TSat_P(P), P)["h"] h25 = _Region2(1073.15, P)["h"] hmin = _Region1(273.15, P)["h"] hmax = _Region5(2273.15, P)["h"] if hmin <= h <= h14: region = 1 elif h14 < h < h24: region = 4 elif h24 <= h <= h25: region = 2 elif h25 < h <= hmax: region = 5 elif Ps_623 < P < Pc: hmin = _Region1(273.15, P)["h"] h13 = _Region1(623.15, P)["h"] h32 = _Region2(_t_P(P), P)["h"] h25 = _Region2(1073.15, P)["h"] hmax = _Region5(2273.15, P)["h"] if hmin <= h <= h13: region = 1 elif h13 < h < h32: try: p34 = _PSat_h(h) except NotImplementedError: p34 = Ps_623 if P < p34: region = 4 else: region = 3 elif h32 <= h <= h25: region = 2 elif h25 < h <= hmax: region = 5 elif Pc <= P <= 100: hmin = _Region1(273.15, P)["h"] h13 = _Region1(623.15, P)["h"] h32 = _Region2(_t_P(P), P)["h"] h25 = _Region2(1073.15, P)["h"] hmax = _Region5(2273.15, P)["h"] if hmin <= h <= h13: region = 1 elif h13 < h < h32: region = 3 elif h32 <= h <= h25: region = 2 elif P <= 50 and h25 <= h <= hmax: region = 5 return region def _Bound_Ps(P, s): """Region definition for input P and s Parameters ---------- P : float Pressure, [MPa] s : float Specific entropy, [kJ/kgK] Returns ------- region : float IAPWS-97 region code References ---------- Wagner, W; Kretzschmar, H-J: International Steam Tables: Properties of Water and Steam Based on the Industrial Formulation IAPWS-IF97; Springer, 2008; doi: 10.1007/978-3-540-74234-0. Fig. 2.9 """ region = None if Pmin <= P <= Ps_623: smin = _Region1(273.15, P)["s"] s14 = _Region1(_TSat_P(P), P)["s"] s24 = _Region2(_TSat_P(P), P)["s"] s25 = _Region2(1073.15, P)["s"] smax = _Region5(2273.15, P)["s"] if smin <= s <= s14: region = 1 elif s14 < s < s24: region = 4 elif s24 <= s <= s25: region = 2 elif s25 < s <= smax: region = 5 elif Ps_623 < P < Pc: smin = _Region1(273.15, P)["s"] s13 = _Region1(623.15, P)["s"] s32 = _Region2(_t_P(P), P)["s"] s25 = _Region2(1073.15, P)["s"] smax = _Region5(2273.15, P)["s"] if smin <= s <= s13: region = 1 elif s13 < s < s32: try: p34 = _PSat_s(s) except NotImplementedError: smin_Ps3 = _Region1(623.15, Ps_623)["s"] if s < smin_Ps3: p34 = Ps_623 else: p34 = Pc if P < p34: region = 4 else: region = 3 elif s32 <= s <= s25: region = 2 elif s25 < s <= smax: region = 5 elif Pc <= P <= 100: smin = _Region1(273.15, P)["s"] s13 = _Region1(623.15, P)["s"] s32 = _Region2(_t_P(P), P)["s"] s25 = _Region2(1073.15, P)["s"] smax = _Region5(2273.15, P)["s"] if smin <= s <= s13: region = 1 elif s13 < s < s32: region = 3 elif s32 <= s <= s25: region = 2 elif P <= 50 and s25 <= s <= smax: region = 5 return region def _Bound_hs(h, s): """Region definition for input h and s Parameters ---------- h : float Specific enthalpy, [kJ/kg] s : float Specific entropy, [kJ/kgK] Returns ------- region : float IAPWS-97 region code References ---------- Wagner, W; Kretzschmar, H-J: International Steam Tables: Properties of Water and Steam Based on the Industrial Formulation IAPWS-IF97; Springer, 2008; doi: 10.1007/978-3-540-74234-0. Fig. 2.14 """ region = None s13 = _Region1(623.15, 100)["s"] s13s = _Region1(623.15, Ps_623)["s"] sTPmax = _Region2(1073.15, 100)["s"] s2ab = _Region2(1073.15, 4)["s"] # Left point in h-s plot smin = _Region1(273.15, 100)["s"] hmin = _Region1(273.15, Pmin)["h"] # Right point in h-s plot _Pmax = _Region2(1073.15, Pmin) hmax = _Pmax["h"] smax = _Pmax["s"] # Region 4 left and right point _sL = _Region1(273.15, Pmin) h4l = _sL["h"] s4l = _sL["s"] _sV = _Region2(273.15, Pmin) h4v = _sV["h"] s4v = _sV["s"] if smin <= s <= s13: hmin = h4l + (s - s4l) / (s4v - s4l) * (h4v - h4l) hs = _h1_s(s) T = _Backward1_T_Ps(100, s) - 0.0218 hmax = _Region1(T, 100)["h"] if hmin <= h < hs: region = 4 elif hs <= h <= hmax: region = 1 elif s13 < s <= s13s: hmin = h4l + (s - s4l) / (s4v - s4l) * (h4v - h4l) hs = _h1_s(s) h13 = _h13_s(s) v = _Backward3_v_Ps(100, s) * (1 + 9.6e-5) T = _Backward3_T_Ps(100, s) - 0.0248 hmax = _Region3(1 / v, T)["h"] if hmin <= h < hs: region = 4 elif hs <= h < h13: region = 1 elif h13 <= h <= hmax: region = 3 elif s13s < s <= sc: hmin = h4l + (s - s4l) / (s4v - s4l) * (h4v - h4l) hs = _h3a_s(s) v = _Backward3_v_Ps(100, s) * (1 + 9.6e-5) T = _Backward3_T_Ps(100, s) - 0.0248 hmax = _Region3(1 / v, T)["h"] if hmin <= h < hs: region = 4 elif hs <= h <= hmax: region = 3 elif sc < s < 5.049096828: hmin = h4l + (s - s4l) / (s4v - s4l) * (h4v - h4l) hs = _h2c3b_s(s) v = _Backward3_v_Ps(100, s) * (1 + 9.6e-5) T = _Backward3_T_Ps(100, s) - 0.0248 hmax = _Region3(1 / v, T)["h"] if hmin <= h < hs: region = 4 elif hs <= h <= hmax: region = 3 elif 5.049096828 <= s < 5.260578707: # Specific zone with 2-3 boundary in s shape hmin = h4l + (s - s4l) / (s4v - s4l) * (h4v - h4l) hs = _h2c3b_s(s) h23max = _Region2(863.15, 100)["h"] h23min = _Region2(623.15, Ps_623)["h"] T = _Backward2_T_Ps(100, s) - 0.019 hmax = _Region2(T, 100)["h"] if hmin <= h < hs: region = 4 elif hs <= h < h23min: region = 3 elif h23min <= h < h23max: if _Backward2c_P_hs(h, s) <= _P23_T(_t_hs(h, s)): region = 2 else: region = 3 elif h23max <= h <= hmax: region = 2 elif 5.260578707 <= s < 5.85: hmin = h4l + (s - s4l) / (s4v - s4l) * (h4v - h4l) hs = _h2c3b_s(s) T = _Backward2_T_Ps(100, s) - 0.019 hmax = _Region2(T, 100)["h"] if hmin <= h < hs: region = 4 elif hs <= h <= hmax: region = 2 elif 5.85 <= s < sTPmax: hmin = h4l + (s - s4l) / (s4v - s4l) * (h4v - h4l) hs = _h2ab_s(s) T = _Backward2_T_Ps(100, s) - 0.019 hmax = _Region2(T, 100)["h"] if hmin <= h < hs: region = 4 elif hs <= h <= hmax: region = 2 elif sTPmax <= s < s2ab: hmin = h4l + (s - s4l) / (s4v - s4l) * (h4v - h4l) hs = _h2ab_s(s) P = _Backward2_P_hs(h, s) hmax = _Region2(1073.15, P)["h"] if hmin <= h < hs: region = 4 elif hs <= h <= hmax: region = 2 elif s2ab <= s < s4v: hmin = h4l + (s - s4l) / (s4v - s4l) * (h4v - h4l) hs = _h2ab_s(s) P = _Backward2_P_hs(h, s) hmax = _Region2(1073.15, P)["h"] if hmin <= h < hs: region = 4 elif hs <= h <= hmax: region = 2 elif s4v <= s <= smax: hmin = _Region2(273.15, Pmin)["h"] P = _Backward2a_P_hs(h, s) hmax = _Region2(1073.15, P)["h"] if Pmin <= P <= 100 and hmin <= h <= hmax: region = 2 # Check region 5 if not region and \ _Region5(1073.15, 50)["s"] < s <= _Region5(2273.15, Pmin)["s"] \ and _Region5(1073.15, 50)["h"] < h <= _Region5(2273.15, Pmin)["h"]: def funcion(par): return (_Region5(par[0], par[1])["h"] - h, _Region5(par[0], par[1])["s"] - s) T, P = fsolve(funcion, [1400, 1]) if 1073.15 < T <= 2273.15 and Pmin <= P <= 50: region = 5 return region def prop0(T, P): """Ideal gas properties Parameters ---------- T : float Temperature, [K] P : float Pressure, [MPa] Returns ------- prop : dict Dict with calculated properties. The available properties are: * v: Specific volume, [m³/kg] * h: Specific enthalpy, [kJ/kg] * s: Specific entropy, [kJ/kgK] * cp: Specific isobaric heat capacity, [kJ/kgK] * cv: Specific isocoric heat capacity, [kJ/kgK] * w: Speed of sound, [m/s] * alfav: Cubic expansion coefficient, [1/K] * kt: Isothermal compressibility, [1/MPa] """ if T <= 1073.15: Tr = 540 / T Pr = P / 1. go, gop, gopp, got, gott, gopt = Region2_cp0(Tr, Pr) else: Tr = 1000 / T Pr = P / 1. go, gop, gopp, got, gott, gopt = Region5_cp0(Tr, Pr) p0 = {} p0["v"] = Pr * gop * R * T / P / 1000 p0["h"] = Tr * got * R * T p0["s"] = R * (Tr * got - go) p0["cp"] = -R * Tr ** 2 * gott p0["cv"] = R * (-Tr ** 2 * gott - 1) p0["w"] = (R * T * 1000 / (1 + 1 / Tr ** 2 / gott)) ** 0.5 p0["alfav"] = 1 / T p0["xkappa"] = 1 / P return p0 class IAPWS97(_fase): """Class to model a state of liquid water or steam with the IAPWS-IF97 Parameters ---------- T : float Temperature, [K] P : float Pressure, [MPa] h : float Specific enthalpy, [kJ/kg] s : float Specific entropy, [kJ/kgK] x : float Vapor quality, [-] l : float, optional Wavelength of light, for refractive index, [μm] Notes ----- Definitions options: * T, P: Not valid for two-phases region * P, h * P, s * h, s * T, x: Only for two-phases region * P, x: Only for two-phases region Returns ------- prop : dict The calculated instance has the following properties: * P: Pressure, [MPa] * T: Temperature, [K] * g: Specific Gibbs free energy, [kJ/kg] * a: Specific Helmholtz free energy, [kJ/kg] * v: Specific volume, [m³/kg] * rho: Density, [kg/m³] * h: Specific enthalpy, [kJ/kg] * u: Specific internal energy, [kJ/kg] * s: Specific entropy, [kJ/kg·K] * cp: Specific isobaric heat capacity, [kJ/kg·K] * cv: Specific isochoric heat capacity, [kJ/kg·K] * Z: Compression factor, [-] * fi: Fugacity coefficient, [-] * f: Fugacity, [MPa] * gamma: Isoentropic exponent, [-] * alfav: Isobaric cubic expansion coefficient, [1/K] * xkappa: Isothermal compressibility, [1/MPa] * kappas: Adiabatic compresibility, [1/MPa] * alfap: Relative pressure coefficient, [1/K] * betap: Isothermal stress coefficient, [kg/m³] * joule: Joule-Thomson coefficient, [K/MPa] * deltat: Isothermal throttling coefficient, [kJ/kg·MPa] * region: Region * v0: Ideal specific volume, [m³/kg] * u0: Ideal specific internal energy, [kJ/kg] * h0: Ideal specific enthalpy, [kJ/kg] * s0: Ideal specific entropy, [kJ/kg·K] * a0: Ideal specific Helmholtz free energy, [kJ/kg] * g0: Ideal specific Gibbs free energy, [kJ/kg] * cp0: Ideal specific isobaric heat capacity, [kJ/kg·K] * cv0: Ideal specific isochoric heat capacity [kJ/kg·K] * w0: Ideal speed of sound, [m/s] * gamma0: Ideal isoentropic exponent, [-] * w: Speed of sound, [m/s] * mu: Dynamic viscosity, [Pa·s] * nu: Kinematic viscosity, [m²/s] * k: Thermal conductivity, [W/m·K] * alfa: Thermal diffusivity, [m²/s] * sigma: Surface tension, [N/m] * epsilon: Dielectric constant, [-] * n: Refractive index, [-] * Prandt: Prandtl number, [-] * Pr: Reduced Pressure, [-] * Tr: Reduced Temperature, [-] * Hvap: Vaporization heat, [kJ/kg] * Svap: Vaporization entropy, [kJ/kg·K] Examples -------- >>> water=IAPWS97(T=170+273.15, x=0.5) >>> water.Liquid.cp, water.Vapor.cp, water.Liquid.w, water.Vapor.w 4.3695 2.5985 1418.3 498.78 >>> water=IAPWS97(T=325+273.15, x=0.5) >>> water.P, water.Liquid.v, water.Vapor.v, water.Liquid.h, water.Vapor.h 12.0505 0.00152830 0.0141887 1493.37 2684.48 >>> water=IAPWS97(T=50+273.15, P=0.0006112127) >>> water.cp0, water.cv0, water.h0, water.s0, water.w0 1.8714 1.4098 2594.66 9.471 444.93 """ M = 18.015257 # kg/kmol Pc = Pc Tc = Tc rhoc = rhoc Tt = Tt Tb = Tb f_accent = f_acent dipole = Dipole kwargs = {"T": 0.0, "P": 0.0, "x": None, "h": None, "s": None, "v": 0.0, "l": 0.5893} status = 0 msg = "Unknown variables" _thermo = "" region = None Liquid = None Vapor = None Gas = None T = None P = None v = None rho = None phase = None x = None Tr = None Pr = None sigma = None v0 = None h0 = None u0 = None s0 = None a0 = None g0 = None cp0 = None cv0 = None cp0_cv = None w0 = None gamma0 = None h = None u = None s = None a = None g = None Hvap = None Svap = None def __init__(self, **kwargs): self.kwargs = IAPWS97.kwargs.copy() self.__call__(**kwargs) def __call__(self, **kwargs): """Invoke the solver.""" self.kwargs.update(kwargs) if self.calculable: self.status = 1 self.calculo() self.msg = "Solved" @property def calculable(self): """Check if class is calculable by its kwargs""" self._thermo = "" if self.kwargs["T"] and self.kwargs["P"]: self._thermo = "TP" elif self.kwargs["P"] and self.kwargs["h"] is not None: self._thermo = "Ph" elif self.kwargs["P"] and self.kwargs["s"] is not None: self._thermo = "Ps" elif self.kwargs["h"] is not None and self.kwargs["s"] is not None: self._thermo = "hs" elif self.kwargs["T"] and self.kwargs["x"] is not None: self._thermo = "Tx" elif self.kwargs["P"] and self.kwargs["x"] is not None: self._thermo = "Px" # TODO: Add other pairs definitions options # elif self.kwargs["P"] and self.kwargs["v"]: # self._thermo = "Pv" # elif self.kwargs["T"] and self.kwargs["s"] is not None: # self._thermo = "Ts" return self._thermo def calculo(self): """Calculate procedure""" propiedades = None args = (self.kwargs[self._thermo[0]], self.kwargs[self._thermo[1]]) if self._thermo == "TP": T, P = args region = _Bound_TP(T, P) if region == 1: propiedades = _Region1(T, P) elif region == 2: propiedades = _Region2(T, P) elif region == 3: if T == Tc and P == Pc: rho = rhoc else: vo = _Backward3_v_PT(P, T) def funcion(rho): return _Region3(rho, self.kwargs["T"])["P"] - P rho = newton(funcion, 1 / vo) propiedades = _Region3(rho, T) elif region == 5: propiedades = _Region5(T, P) else: raise NotImplementedError("Incoming out of bound") elif self._thermo == "Ph": P, h = args region = _Bound_Ph(P, h) if region == 1: To = _Backward1_T_Ph(P, h) T = newton(lambda T: _Region1(T, P)["h"] - h, To) propiedades = _Region1(T, P) elif region == 2: To = _Backward2_T_Ph(P, h) T = newton(lambda T: _Region2(T, P)["h"] - h, To) propiedades = _Region2(T, P) elif region == 3: vo = _Backward3_v_Ph(P, h) To = _Backward3_T_Ph(P, h) def funcion(par): return (_Region3(par[0], par[1])["h"] - h, _Region3(par[0], par[1])["P"] - P) rho, T = fsolve(funcion, [1 / vo, To]) propiedades = _Region3(rho, T) elif region == 4: T = _TSat_P(P) if T <= 623.15: h1 = _Region1(T, P)["h"] h2 = _Region2(T, P)["h"] x = (h - h1) / (h2 - h1) propiedades = _Region4(P, x) else: h1 = _Region4(P, 0)["h"] h2 = _Region4(P, 1)["h"] x = (h - h1) / (h2 - h1) propiedades = _Region4(P, x) elif region == 5: T = newton(lambda T: _Region5(T, P)["h"] - h, 1500) propiedades = _Region5(T, P) else: raise NotImplementedError("Incoming out of bound") elif self._thermo == "Ps": P, s = args region = _Bound_Ps(P, s) if region == 1: To = _Backward1_T_Ps(P, s) T = newton(lambda T: _Region1(T, P)["s"] - s, To) propiedades = _Region1(T, P) elif region == 2: To = _Backward2_T_Ps(P, s) T = newton(lambda T: _Region2(T, P)["s"] - s, To) propiedades = _Region2(T, P) elif region == 3: vo = _Backward3_v_Ps(P, s) To = _Backward3_T_Ps(P, s) def funcion(par): return (_Region3(par[0], par[1])["s"] - s, _Region3(par[0], par[1])["P"] - P) rho, T = fsolve(funcion, [1 / vo, To]) propiedades = _Region3(rho, T) elif region == 4: T = _TSat_P(P) if T <= 623.15: s1 = _Region1(T, P)["s"] s2 = _Region2(T, P)["s"] x = (s - s1) / (s2 - s1) propiedades = _Region4(P, x) else: s1 = _Region4(P, 0)["s"] s2 = _Region4(P, 1)["s"] x = (s - s1) / (s2 - s1) propiedades = _Region4(P, x) elif region == 5: T = newton(lambda T: _Region5(T, P)["s"] - s, 1500) propiedades = _Region5(T, P) else: raise NotImplementedError("Incoming out of bound") elif self._thermo == "hs": h, s = args region = _Bound_hs(h, s) if region == 1: Po = _Backward1_P_hs(h, s) To = _Backward1_T_Ph(Po, h) def funcion(par): return (_Region1(par[0], par[1])["h"] - h, _Region1(par[0], par[1])["s"] - s) T, P = fsolve(funcion, [To, Po]) propiedades = _Region1(T, P) elif region == 2: Po = _Backward2_P_hs(h, s) To = _Backward2_T_Ph(Po, h) def funcion(par): return (_Region2(par[0], par[1])["h"] - h, _Region2(par[0], par[1])["s"] - s) T, P = fsolve(funcion, [To, Po]) propiedades = _Region2(T, P) elif region == 3: P = _Backward3_P_hs(h, s) vo = _Backward3_v_Ph(P, h) To = _Backward3_T_Ph(P, h) def funcion(par): return (_Region3(par[0], par[1])["h"] - h, _Region3(par[0], par[1])["s"] - s) rho, T = fsolve(funcion, [1 / vo, To]) propiedades = _Region3(rho, T) elif region == 4: if round(s - sc, 6) == 0 and round(h - hc, 6) == 0: propiedades = _Region3(rhoc, Tc) else: To = _Backward4_T_hs(h, s) if To < 273.15 or To > Tc: To = 300 def funcion(par): if par[1] < 0: par[1] = 0 elif par[1] > 1: par[1] = 1 if par[0] < 273.15: par[0] = 273.15 elif par[0] > Tc: par[0] = Tc Po = _PSat_T(par[0]) liquid = _Region1(par[0], Po) vapor = _Region2(par[0], Po) hl = liquid["h"] sl = liquid["s"] hv = vapor["h"] sv = vapor["s"] return (hv * par[1] + hl * (1 - par[1]) - h, sv * par[1] + sl * (1 - par[1]) - s) T, x = fsolve(funcion, [To, 0.5]) P = _PSat_T(T) if Pt <= P < Pc and 0 < x < 1: propiedades = _Region4(P, x) elif Pt <= P <= Ps_623 and x == 0: propiedades = _Region1(T, P) elif region == 5: def funcion(par): return (_Region5(par[0], par[1])["h"] - h, _Region5(par[0], par[1])["s"] - s) T, P = fsolve(funcion, [1400, 1]) propiedades = _Region5(T, P) else: raise NotImplementedError("Incoming out of bound") elif self._thermo == "Px": P, x = args T = _TSat_P(P) if Pt <= P < Pc and 0 < x < 1: propiedades = _Region4(P, x) elif Pt <= P <= Ps_623 and x == 0: propiedades = _Region1(T, P) elif Pt <= P <= Ps_623 and x == 1: propiedades = _Region2(T, P) elif Ps_623 < P < Pc and x in (0, 1): def funcion(rho): return _Region3(rho, T)["P"] - P rhoo = 1. / _Backward3_sat_v_P(P, T, x) rho = fsolve(funcion, rhoo)[0] propiedades = _Region3(rho, T) elif P == Pc and 0 <= x <= 1: propiedades = _Region3(rhoc, Tc) else: raise NotImplementedError("Incoming out of bound") self.sigma = _Tension(T) propiedades["x"] = x elif self._thermo == "Tx": T, x = args P = _PSat_T(T) if 273.15 <= T < Tc and 0 < x < 1: propiedades = _Region4(P, x) elif 273.15 <= T <= 623.15 and x == 0: propiedades = _Region1(T, P) elif 273.15 <= T <= 623.15 and x == 1: propiedades = _Region2(T, P) elif 623.15 < T < Tc and x in (0, 1): rho = 1. / _Backward3_sat_v_P(P, T, x) propiedades = _Region3(rho, T) elif T == Tc and 0 <= x <= 1: propiedades = _Region3(rhoc, Tc) else: raise NotImplementedError("Incoming out of bound") self.sigma = _Tension(T) propiedades["x"] = x self.x = propiedades["x"] self.region = propiedades["region"] self.T = propiedades["T"] self.P = propiedades["P"] self.v = propiedades["v"] self.rho = 1 / self.v self.phase = getphase(self.Tc, self.Pc, self.T, self.P, self.x, self.region) self.Tr = self.T / self.Tc self.Pr = self.P / self.Pc # Ideal properties cp0 = prop0(self.T, self.P) self.v0 = cp0["v"] self.h0 = cp0["h"] self.u0 = self.h0 - self.P * 1000 * self.v0 self.s0 = cp0["s"] self.a0 = self.u0 - self.T * self.s0 self.g0 = self.h0 - self.T * self.s0 self.cp0 = cp0["cp"] self.cv0 = cp0["cv"] self.cp0_cv = self.cp0 / self.cv0 self.w0 = cp0["w"] self.gamma0 = self.cp0_cv self.Liquid = _fase() self.Vapor = _fase() self.Gas = self.Vapor if self.x == 0: # only liquid phase self.fill(self, propiedades) self.fill(self.Liquid, propiedades) self.sigma = _Tension(self.T) elif self.x == 1: # only vapor phase self.fill(self, propiedades) self.fill(self.Vapor, propiedades) else: # two phases if 623.15 < self.T <= Tc: rhol = 1. / _Backward3_sat_v_P(self.P, self.T, 0) liquido = _Region3(rhol, self.T) rhov = 1. / _Backward3_sat_v_P(self.P, self.T, 1) vapor = _Region3(rhov, self.T) else: liquido = _Region1(self.T, self.P) vapor = _Region2(self.T, self.P) self.fill(self.Liquid, liquido) self.fill(self.Vapor, vapor) self.h = propiedades["h"] self.u = self.h - self.P * 1000 * self.v self.s = propiedades["s"] self.a = self.u - self.T * self.s self.g = self.h - self.T * self.s self.sigma = _Tension(self.T) self.Hvap = vapor["h"] - liquido["h"] self.Svap = vapor["s"] - liquido["s"] def fill(self, fase, estado): """Fill phase properties""" fase.v = estado["v"] fase.rho = 1 / fase.v fase.h = estado["h"] fase.s = estado["s"] fase.u = fase.h - self.P * 1000 * fase.v fase.a = fase.u - self.T * fase.s fase.g = fase.h - self.T * fase.s fase.cv = estado["cv"] fase.cp = estado["cp"] fase.cp_cv = fase.cp / fase.cv fase.w = estado["w"] fase.Z = self.P * fase.v / R * 1000 / self.T fase.alfav = estado["alfav"] fase.xkappa = estado["kt"] fase.kappas = -1 / fase.v * self.derivative("v", "P", "s", fase) fase.joule = self.derivative("T", "P", "h", fase) fase.deltat = self.derivative("h", "P", "T", fase) fase.gamma = -fase.v/self.P \ * self.derivative("P", "v", "T", fase)*fase.cp_cv fase.alfap = fase.alfav / self.P / fase.xkappa fase.betap = -1 / self.P * self.derivative("P", "v", "T", fase) fase.fi = exp((fase.g - self.g0) / R / self.T) fase.f = self.P * fase.fi fase.mu = _Viscosity(fase.rho, self.T) # Use industrial formulation for critical enhancement in thermal # conductivity calculation fase.drhodP_T = self.derivative("rho", "P", "T", fase) fase.k = _ThCond(fase.rho, self.T, fase) fase.nu = fase.mu / fase.rho fase.alfa = fase.k / 1000 / fase.rho / fase.cp try: fase.epsilon = _Dielectric(fase.rho, self.T) except NotImplementedError: fase.epsilon = None fase.Prandt = fase.mu * fase.cp * 1000 / fase.k try: fase.n = _Refractive(fase.rho, self.T, self.kwargs["l"]) except NotImplementedError: fase.n = None def derivative(self, z, x, y, fase): """ Wrapper derivative for custom derived properties where x, y, z can be: P, T, v, u, h, s, g, a """ return deriv_G(self, z, x, y, fase) class IAPWS97_PT(IAPWS97): """Derivated class for direct P and T input""" def __init__(self, P, T): IAPWS97.__init__(self, T=T, P=P) class IAPWS97_Ph(IAPWS97): """Derivated class for direct P and h input""" def __init__(self, P, h): IAPWS97.__init__(self, P=P, h=h) class IAPWS97_Ps(IAPWS97): """Derivated class for direct P and s input""" def __init__(self, P, s): IAPWS97.__init__(self, P=P, s=s) class IAPWS97_Px(IAPWS97): """Derivated class for direct P and x input""" def __init__(self, P, x): IAPWS97.__init__(self, P=P, x=x) class IAPWS97_Tx(IAPWS97): """Derivated class for direct T and x input""" def __init__(self, T, x): IAPWS97.__init__(self, T=T, x=x) iapws-1.5.5/iapws/_iapws.py0000664000175000017500000014522715161316541016026 0ustar alastairalastair#!/usr/bin/python # -*- coding: utf-8 -*- # pylint: disable=invalid-name # pylint: disable=too-many-lines, too-many-locals, too-many-statements # pylint: disable=too-many-branches, too-many-boolean-expressions """ Miscelaneous IAPWS standards. This module include: * :func:`_Ice`: Ice Ih state equation * :func:`_Liquid`: Properties of liquid water at 0.1 MPa * :func:`_Supercooled`: Thermodynamic properties of supercooled water * :func:`_Sublimation_Pressure`: Sublimation pressure correlation * :func:`_Melting_Pressure`: Melting pressure correlation * :func:`_Viscosity`: Viscosity correlation * :func:`_ThCond`: Themal conductivity correlation * :func:`_Tension`: Surface tension correlation * :func:`_Dielectric`: Dielectric constant correlation * :func:`_Refractive`: Refractive index correlation * :func:`_Kw`: Ionization constant correlation for ordinary water * :func:`_Conductivity`: Electrolytic conductivity correlation * :func:`_D2O_Viscosity`: Viscosity correlation for heavy water * :func:`_D2O_ThCond`: Thermal conductivity correlation for heavy water * :func:`_D2O_Tension`: Surface tension correlation for heavy water * :func:`_D2O_Sublimation_Pressure`: Sublimation Pressure correlation for heavy water * :func:`_D2O_Melting_Pressure`: Melting Pressure correlation for heavy water * :func:`_Henry`: Henry constant for liquid-gas equilibrium * :func:`_Kvalue`: Vapor-liquid distribution constant """ from __future__ import division from cmath import log as log_c from numpy import log, exp, tan, sin, pi, log10 try: from numpy import acos, atan except ImportError: from math import acos, atan import warnings from scipy.optimize import newton # Constants M = 18.015268 # g/mol R = 0.461526 # kJ/kg·K # Table 1 from Release on the Values of Temperature, Pressure and Density of # Ordinary and Heavy Water Substances at their Respective Critical Points Tc = 647.096 # K Pc = 22.064 # MPa rhoc = 322. # kg/m³ Tc_D2O = 643.847 # K Pc_D2O = 21.6618 # MPa rhoc_D2O = 355.9999698294 # kg/m³ Tt = 273.16 # K Pt = 611.657e-6 # MPa Tb = 373.1243 # K f_acent = 0.3443 # IAPWS, Guideline on the Use of Fundamental Physical Constants and Basic # Constants of Water, http://www.iapws.org/relguide/fundam.pdf Dipole = 1.85498 # Debye # IAPWS-06 for Ice def _Ice(T, P): """Basic state equation for Ice Ih Parameters ---------- T : float Temperature, [K] P : float Pressure, [MPa] Returns ------- prop : dict Dict with calculated properties of ice. The available properties are: * rho: Density, [kg/m³] * h: Specific enthalpy, [kJ/kg] * u: Specific internal energy, [kJ/kg] * a: Specific Helmholtz energy, [kJ/kg] * g: Specific Gibbs energy, [kJ/kg] * s: Specific entropy, [kJ/kgK] * cp: Specific isobaric heat capacity, [kJ/kgK] * alfav: Cubic expansion coefficient, [1/K] * beta: Pressure coefficient, [MPa/K] * xkappa: Isothermal compressibility, [1/MPa] * ks: Isentropic compressibility, [1/MPa] * gt: [∂g/∂T]P * gtt: [∂²g/∂T²]P * gp: [∂g/∂P]T * gpp: [∂²g/∂P²]T * gtp: [∂²g/∂T∂P] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * T ≤ 273.16 * P ≤ 208.566 * State below the melting and sublimation lines Examples -------- >>> st1 = _Ice(100, 100) >>> st1["rho"], st1["h"], st1["s"] 941.678203297 -483.491635676 -2.61195122589 >>> st2 = _Ice(273.152519,0.101325) >>> st2["a"], st2["u"], st2["cp"] -0.00918701567 -333.465403393 2.09671391024 >>> st3 = _Ice(273.16,611.657e-6) >>> st3["alfav"], st3["beta"], st3["xkappa"], st3["ks"] 0.000159863102566 1.35714764659 1.17793449348e-04 1.14161597779e-04 References ---------- IAPWS, Revised Release on the Equation of State 2006 for H2O Ice Ih September 2009, http://iapws.org/relguide/Ice-2009.html """ # Check input in range of validity if T > 273.16: # No Ice Ih stable warnings.warn("Metastable ice") elif P > 208.566: # Ice Ih limit upper pressure raise NotImplementedError("Incoming out of bound") elif P < Pt: Psub = _Sublimation_Pressure(T) if Psub > P: # Zone Gas warnings.warn("Metastable ice in vapor region") elif T > 251.165: Pmel = _Melting_Pressure(T) if Pmel < P: # Zone Liquid warnings.warn("Metastable ice in liquid region") Tr = T/Tt Pr = P/Pt P0 = 101325e-6/Pt s0 = -0.332733756492168e4*1e-3 # Express in kJ/kgK gok = [-0.632020233335886e6, 0.655022213658955, -0.189369929326131e-7, 0.339746123271053e-14, -0.556464869058991e-21] r2k = [complex(-0.725974574329220e2, -0.781008427112870e2)*1e-3, complex(-0.557107698030123e-4, 0.464578634580806e-4)*1e-3, complex(0.234801409215913e-10, -0.285651142904972e-10)*1e-3] t1 = complex(0.368017112855051e-1, 0.510878114959572e-1) t2 = complex(0.337315741065416, 0.335449415919309) r1 = complex(0.447050716285388e2, 0.656876847463481e2)*1e-3 go = gop = gopp = 0 for k in range(5): go += gok[k]*1e-3*(Pr-P0)**k for k in range(1, 5): gop += gok[k]*1e-3*k/Pt*(Pr-P0)**(k-1) for k in range(2, 5): gopp += gok[k]*1e-3*k*(k-1)/Pt**2*(Pr-P0)**(k-2) r2 = r2p = 0 for k in range(3): r2 += r2k[k]*(Pr-P0)**k for k in range(1, 3): r2p += r2k[k]*k/Pt*(Pr-P0)**(k-1) r2pp = r2k[2]*2/Pt**2 c = r1*((t1-Tr)*log_c(t1-Tr)+(t1+Tr)*log_c(t1+Tr)-2*t1*log_c( t1)-Tr**2/t1)+r2*((t2-Tr)*log_c(t2-Tr)+(t2+Tr)*log_c( t2+Tr)-2*t2*log_c(t2)-Tr**2/t2) ct = r1*(-log_c(t1-Tr)+log_c(t1+Tr)-2*Tr/t1)+r2*( -log_c(t2-Tr)+log_c(t2+Tr)-2*Tr/t2) ctt = r1*(1/(t1-Tr)+1/(t1+Tr)-2/t1) + r2*(1/(t2-Tr)+1/(t2+Tr)-2/t2) cp = r2p*((t2-Tr)*log_c(t2-Tr)+(t2+Tr)*log_c( t2+Tr)-2*t2*log_c(t2)-Tr**2/t2) ctp = r2p*(-log_c(t2-Tr)+log_c(t2+Tr)-2*Tr/t2) cpp = r2pp*((t2-Tr)*log_c(t2-Tr)+(t2+Tr)*log_c( t2+Tr)-2*t2*log_c(t2)-Tr**2/t2) g = go-s0*Tt*Tr+Tt*c.real gt = -s0+ct.real gp = gop+Tt*cp.real gtt = ctt.real/Tt gtp = ctp.real gpp = gopp+Tt*cpp.real propiedades = {} propiedades["gt"] = gt propiedades["gp"] = gp propiedades["gtt"] = gtt propiedades["gpp"] = gpp propiedades["gtp"] = gtp propiedades["T"] = T propiedades["P"] = P propiedades["v"] = gp/1000 propiedades["rho"] = 1000./gp propiedades["h"] = g-T*gt propiedades["s"] = -gt propiedades["cp"] = -T*gtt propiedades["u"] = g-T*gt-P*gp propiedades["g"] = g propiedades["a"] = g-P*gp propiedades["alfav"] = gtp/gp propiedades["beta"] = -gtp/gpp propiedades["xkappa"] = -gpp/gp propiedades["ks"] = (gtp**2-gtt*gpp)/gp/gtt return propiedades # IAPWS-08 for Liquid water at 0.1 MPa def _Liquid(T, P=0.1): """Supplementary release on properties of liquid water at 0.1 MPa Parameters ---------- T : float Temperature, [K] P : float Pressure, [MPa] Although this relation is for P=0.1MPa, can be extrapoled at pressure 0.3 MPa Returns ------- prop : dict Dict with calculated properties of water. The available properties are: * h: Specific enthalpy, [kJ/kg] * u: Specific internal energy, [kJ/kg] * a: Specific Helmholtz energy, [kJ/kg] * g: Specific Gibbs energy, [kJ/kg] * s: Specific entropy, [kJ/kgK] * cp: Specific isobaric heat capacity, [kJ/kgK] * cv: Specific isochoric heat capacity, [kJ/kgK] * w: Speed of sound, [m/s²] * rho: Density, [kg/m³] * v: Specific volume, [m³/kg] * vt: [∂v/∂T]P, [m³/kgK] * vtt: [∂²v/∂T²]P, [m³/kgK²] * vp: [∂v/∂P]T, [m³/kg/MPa] * vtp: [∂²v/∂T∂P], [m³/kg/MPa] * alfav: Cubic expansion coefficient, [1/K] * xkappa : Isothermal compressibility, [1/MPa] * ks: Isentropic compressibility, [1/MPa] * mu: Viscosity, [Pas] * k: Thermal conductivity, [W/mK] * epsilon: Dielectric constant, [-] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 253.15 ≤ T ≤ 383.15 * 0.1 ≤ P ≤ 0.3 Examples -------- >>> st1 = _Liquid(260) >>> st1["rho"], st1["h"], st1["s"] 997.0683602710492 -55.86223174460868 -0.20998554842619535 References ---------- IAPWS, Revised Supplementary Release on Properties of Liquid Water at 0.1 MPa, http://www.iapws.org/relguide/LiquidWater.html """ # Check input in range of validity if T <= 253.15 or T >= 383.15 or P < 0.1 or P > 0.3: raise NotImplementedError("Incoming out of bound") if P != 0.1: # Raise a warning if the P value is extrapolated warnings.warn("Using extrapolated values") Rg = 0.46151805 # kJ/kgK Po = 0.1 Tr = 10 tau = T/Tr alfa = Tr/(593-T) beta = Tr/(T-232) a = [None, -1.661470539e5, 2.708781640e6, -1.557191544e8, None, 1.93763157e-2, 6.74458446e3, -2.22521604e5, 1.00231247e8, -1.63552118e9, 8.32299658e9, -7.5245878e-6, -1.3767418e-2, 1.0627293e1, -2.0457795e2, 1.2037414e3] b = [None, -8.237426256e-1, 1.908956353, -2.017597384, 8.546361348e-1, 5.78545292e-3, -1.53195665E-2, 3.11337859e-2, -4.23546241e-2, 3.38713507e-2, -1.19946761e-2, -3.1091470e-6, 2.8964919e-5, -1.3112763e-4, 3.0410453e-4, -3.9034594e-4, 2.3403117e-4, -4.8510101e-5] c = [None, -2.452093414e2, 3.869269598e1, -8.983025854] n = [None, 4, 5, 7, None, None, 4, 5, 7, 8, 9, 1, 3, 5, 6, 7] m = [None, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 1, 3, 4, 5, 6, 7, 9] suma1 = sum(a[i]*alfa**n[i] for i in range(1, 4)) suma2 = sum(b[i]*beta**m[i] for i in range(1, 5)) go = Rg*Tr*(c[1]+c[2]*tau+c[3]*tau*log(tau)+suma1+suma2) suma1 = sum(a[i]*alfa**n[i] for i in range(6, 11)) suma2 = sum(b[i]*beta**m[i] for i in range(5, 11)) vo = Rg*Tr/Po/1000*(a[5]+suma1+suma2) suma1 = sum(a[i]*alfa**n[i] for i in range(11, 16)) suma2 = sum(b[i]*beta**m[i] for i in range(11, 18)) vpo = Rg*Tr/Po**2/1000*(suma1+suma2) suma1 = sum(n[i]*a[i]*alfa**(n[i]+1) for i in range(1, 4)) suma2 = sum(m[i]*b[i]*beta**(m[i]+1) for i in range(1, 5)) so = -Rg*(c[2]+c[3]*(1+log(tau))+suma1-suma2) suma1 = sum(n[i]*(n[i]+1)*a[i]*alfa**(n[i]+2) for i in range(1, 4)) suma2 = sum(m[i]*(m[i]+1)*b[i]*beta**(m[i]+2) for i in range(1, 5)) cpo = -Rg*(c[3]+tau*suma1+tau*suma2) suma1 = sum(n[i]*a[i]*alfa**(n[i]+1) for i in range(6, 11)) suma2 = sum(m[i]*b[i]*beta**(m[i]+1) for i in range(5, 11)) vto = Rg/Po/1000*(suma1-suma2) # This properties are only neccessary for computing thermodynamic # properties at pressures different from 0.1 MPa suma1 = sum(n[i]*(n[i]+1)*a[i]*alfa**(n[i]+2) for i in range(6, 11)) suma2 = sum(m[i]*(m[i]+1)*b[i]*beta**(m[i]+2) for i in range(5, 11)) vtto = Rg/Tr/Po/1000*(suma1+suma2) suma1 = sum(n[i]*a[i]*alfa**(n[i]+1) for i in range(11, 16)) suma2 = sum(m[i]*b[i]*beta**(m[i]+1) for i in range(11, 18)) vpto = Rg/Po**2/1000*(suma1-suma2) if P != 0.1: go += vo*(P-0.1) so -= vto*(P-0.1) cpo -= T*vtto*(P-0.1) vo -= vpo*(P-0.1) vto += vpto*(P-0.1) vppo = 3.24e-10*Rg*Tr/0.1**3 vpo += vppo*(P-0.1) h = go+T*so u = h-P*vo a = go-P*vo cv = cpo+T*vto**2/vpo xkappa = -vpo/vo alfa = vto/vo ks = -(T*vto**2/cpo+vpo)/vo w = (-vo**2*1e9/(vpo*1e3+T*vto**2*1e6/cpo))**0.5 propiedades = {} propiedades["g"] = go propiedades["T"] = T propiedades["P"] = P propiedades["v"] = vo propiedades["vt"] = vto propiedades["vp"] = vpo propiedades["vpt"] = vpto propiedades["vtt"] = vtto propiedades["rho"] = 1/vo propiedades["h"] = h propiedades["s"] = so propiedades["cp"] = cpo propiedades["cv"] = cv propiedades["u"] = u propiedades["a"] = a propiedades["xkappa"] = xkappa propiedades["alfav"] = vto/vo propiedades["ks"] = ks propiedades["w"] = w # Viscosity correlation, Eq 7 a = [None, 280.68, 511.45, 61.131, 0.45903] b = [None, -1.9, -7.7, -19.6, -40] T_ = T/300 mu = sum(a[i]*T_**b[i] for i in range(1, 5))/1e6 propiedades["mu"] = mu # Thermal conductivity correlation, Eq 8 c = [None, 1.6630, -1.7781, 1.1567, -0.432115] d = [None, -1.15, -3.4, -6.0, -7.6] k = sum(c[i]*T_**d[i] for i in range(1, 5)) propiedades["k"] = k # Dielectric constant correlation, Eq 9 e = [None, -43.7527, 299.504, -399.364, 221.327] f = [None, -0.05, -1.47, -2.11, -2.31] epsilon = sum(e[i]*T_**f[i] for i in range(1, 5)) propiedades["epsilon"] = epsilon return propiedades # IAPWS-15 for supercooled liquid water def _Supercooled(T, P): """Guideline on thermodynamic properties of supercooled water Parameters ---------- T : float Temperature, [K] P : float Pressure, [MPa] Returns ------- prop : dict Dict with calculated properties of water. The available properties are: * L: Ordering field, [-] * x: Mole fraction of low-density structure, [-] * rho: Density, [kg/m³] * s: Specific entropy, [kJ/kgK] * h: Specific enthalpy, [kJ/kg] * u: Specific internal energy, [kJ/kg] * a: Specific Helmholtz energy, [kJ/kg] * g: Specific Gibbs energy, [kJ/kg] * alfap: Thermal expansion coefficient, [1/K] * xkappa : Isothermal compressibility, [1/MPa] * cp: Specific isobaric heat capacity, [kJ/kgK] * cv: Specific isochoric heat capacity, [kJ/kgK] * w: Speed of sound, [m/s²] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * Tm ≤ T ≤ 300 * 0 < P ≤ 1000 The minimum temperature in range of validity is the melting temperature, it depend of pressure Raise :class:`RuntimeError` if solution isn't founded Examples -------- >>> liq = _supercooled(235.15, 0.101325) >>> liq["rho"], liq["cp"], liq["w"] 968.09999 5.997563 1134.5855 References ---------- iapws, guideline on thermodynamic properties of supercooled water, http://iapws.org/relguide/Supercooled.html """ # Check input in range of validity if P < 198.9: Tita = T/235.15 Ph = 0.1+228.27*(1-Tita**6.243)+15.724*(1-Tita**79.81) if P < Ph or T > 300: raise NotImplementedError("Incoming out of bound") else: Th = 172.82+0.03718*P+3.403e-5*P**2-1.573e-8*P**3 if T < Th or T > 300 or P > 1000: raise NotImplementedError("Incoming out of bound") # Parameters, Table 1 Tll = 228.2 rho0 = 1081.6482 Rg = 0.461523087 pi0 = 300e3/rho0/Rg/Tll omega0 = 0.5212269 L0 = 0.76317954 k0 = 0.072158686 k1 = -0.31569232 k2 = 5.2992608 # Reducing parameters, Eq 2 tau = T/Tll-1 p = P*1000/rho0/Rg/Tll tau_ = tau+1 p_ = p+pi0 # Eq 3 ci = [-8.1570681381655, 1.2875032, 7.0901673598012, -3.2779161e-2, 7.3703949e-1, -2.1628622e-1, -5.1782479, 4.2293517e-4, 2.3592109e-2, 4.3773754, -2.9967770e-3, -9.6558018e-1, 3.7595286, 1.2632441, 2.8542697e-1, -8.5994947e-1, -3.2916153e-1, 9.0019616e-2, 8.1149726e-2, -3.2788213] ai = [0, 0, 1, -0.2555, 1.5762, 1.6400, 3.6385, -0.3828, 1.6219, 4.3287, 3.4763, 5.1556, -0.3593, 5.0361, 2.9786, 6.2373, 4.0460, 5.3558, 9.0157, 1.2194] bi = [0, 1, 0, 2.1051, 1.1422, 0.9510, 0, 3.6402, 2.0760, -0.0016, 2.2769, 0.0008, 0.3706, -0.3975, 2.9730, -0.3180, 2.9805, 2.9265, 0.4456, 0.1298] di = [0, 0, 0, -0.0016, 0.6894, 0.0130, 0.0002, 0.0435, 0.0500, 0.0004, 0.0528, 0.0147, 0.8584, 0.9924, 1.0041, 1.0961, 1.0228, 1.0303, 1.6180, 0.5213] phir = phirt = phirp = phirtt = phirtp = phirpp = 0 for c, a, b, d in zip(ci, ai, bi, di): phir += c*tau_**a*p_**b*exp(-d*p_) phirt += c*a*tau_**(a-1)*p_**b*exp(-d*p_) phirp += c*tau_**a*p_**(b-1)*(b-d*p_)*exp(-d*p_) phirtt += c*a*(a-1)*tau_**(a-2)*p_**b*exp(-d*p_) phirtp += c*a*tau_**(a-1)*p_**(b-1)*(b-d*p_)*exp(-d*p_) phirpp += c*tau_**a*p_**(b-2)*((d*p_-b)**2-b)*exp(-d*p_) # Eq 5 K1 = ((1+k0*k2+k1*(p-k2*tau))**2-4*k0*k1*k2*(p-k2*tau))**0.5 K2 = (1+k2**2)**0.5 # Eq 6 omega = 2+omega0*p # Eq 4 L = L0*K2/2/k1/k2*(1+k0*k2+k1*(p+k2*tau)-K1) # Define interval of solution, Table 4 if omega < 10/9*(log(19)-L): xmin = 0.049 xmax = 0.5 elif 10/9*(log(19)-L) <= omega < 50/49*(log(99)-L): xmin = 0.0099 xmax = 0.051 else: xmin = 0.99*exp(-50/49*L-omega) xmax = min(1.1*exp(-L-omega), 0.0101) # Eq 8 def f(x): "Function for iterative calculation" if x < xmin: x = xmin if x > xmax: x = xmax return L+log(x/(1-x))+omega*(1-2*x) x = None for xo in (xmin, xmax, (xmin+xmax)/2): try: x, sol = newton(f, xo, full_output=True) except RuntimeError: pass else: if sol.converged: break # Exit when solution don't found if not x: raise RuntimeError("Solution don't found") # Eq 12 fi = 2*x-1 Xi = 1/(2/(1-fi**2)-omega) # Derivatives, Table 3 Lt = L0*K2/2*(1+(1-k0*k2+k1*(p-k2*tau))/K1) Lp = L0*K2*(K1+k0*k2-k1*p+k1*k2*tau-1)/2/k2/K1 Ltt = -2*L0*K2*k0*k1*k2**2/K1**3 Ltp = 2*L0*K2*k0*k1*k2/K1**3 Lpp = -2*L0*K2*k0*k1/K1**3 prop = {} prop["L"] = L prop["x"] = x # Eq 13 prop["rho"] = rho0/((tau+1)/2*(omega0/2*(1-fi**2)+Lp*(fi+1))+phirp) # Eq 1 prop["g"] = phir+(tau+1)*(x*L+x*log(x)+(1-x)*log(1-x)+omega*x*(1-x)) # Eq 14 prop["s"] = -Rg*((tau+1)/2*Lt*(fi+1) + (x*L+x*log(x)+(1-x)*log(1-x)+omega*x*(1-x))+phirt) # Basic derived state properties prop["h"] = prop["g"]+T*prop["s"] prop["u"] = prop["h"]+P/prop["rho"] prop["a"] = prop["u"]-T*prop["s"] # Eq 15 prop["xkappa"] = prop["rho"]/rho0**2/Rg*1000/Tll*( (tau+1)/2*(Xi*(Lp-omega0*fi)**2-(fi+1)*Lpp)-phirpp) prop["alfap"] = prop["rho"]/rho0/Tll*( Ltp/2*(tau+1)*(fi+1) + (omega0*(1-fi**2)/2+Lp*(fi+1))/2 - (tau+1)*Lt/2*Xi*(Lp-omega0*fi) + phirtp) prop["cp"] = -Rg*(tau+1)*(Lt*(fi+1)+(tau+1)/2*(Ltt*(fi+1)-Lt**2*Xi)+phirtt) # Eq 16 prop["cv"] = prop["cp"]-T*prop["alfap"]**2/prop["rho"]/prop["xkappa"]*1e3 # Eq 17 prop["w"] = (prop["rho"]*prop["xkappa"]*1e-6*prop["cv"]/prop["cp"])**-0.5 return prop def _Sublimation_Pressure(T): """Sublimation Pressure correlation Parameters ---------- T : float Temperature, [K] Returns ------- P : float Pressure at sublimation line, [MPa] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 50 ≤ T ≤ 273.16 Examples -------- >>> _Sublimation_Pressure(230) 8.947352740189152e-06 References ---------- IAPWS, Revised Release on the Pressure along the Melting and Sublimation Curves of Ordinary Water Substance, http://iapws.org/relguide/MeltSub.html. """ if 50 <= T <= 273.16: Tita = T/Tt suma = 0 a = [-0.212144006e2, 0.273203819e2, -0.61059813e1] expo = [0.333333333e-2, 1.20666667, 1.70333333] for ai, expi in zip(a, expo): suma += ai*Tita**expi return exp(suma/Tita)*Pt raise NotImplementedError("Incoming out of bound") def _Melting_Pressure(T, ice="Ih"): """Melting Pressure correlation Parameters ---------- T : float Temperature, [K] ice: string Type of ice: Ih, III, V, VI, VII. Below 273.15 is a mandatory input, the ice Ih is the default value. Above 273.15, the ice type is unnecesary. Returns ------- P : float Pressure at sublimation line, [MPa] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 251.165 ≤ T ≤ 715 Examples -------- >>> _Melting_Pressure(260) 8.947352740189152e-06 >>> _Melting_Pressure(254, "III") 268.6846466336108 References ---------- IAPWS, Revised Release on the Pressure along the Melting and Sublimation Curves of Ordinary Water Substance, http://iapws.org/relguide/MeltSub.html. """ if ice == "Ih" and 251.165 <= T <= 273.16: # Ice Ih Tref = Tt Pref = Pt Tita = T/Tref a = [0.119539337e7, 0.808183159e5, 0.33382686e4] expo = [3., 0.2575e2, 0.10375e3] suma = 1 for ai, expi in zip(a, expo): suma += ai*(1-Tita**expi) P = suma*Pref elif ice == "III" and 251.165 < T <= 256.164: # Ice III Tref = 251.165 Pref = 208.566 Tita = T/Tref P = Pref*(1-0.299948*(1-Tita**60.)) elif (ice == "V" and 256.164 < T <= 273.15) or 273.15 < T <= 273.31: # Ice V Tref = 256.164 Pref = 350.100 Tita = T/Tref P = Pref*(1-1.18721*(1-Tita**8.)) elif 273.31 < T <= 355: # Ice VI Tref = 273.31 Pref = 632.400 Tita = T/Tref P = Pref*(1-1.07476*(1-Tita**4.6)) elif 355. < T <= 715: # Ice VII Tref = 355 Pref = 2216.000 Tita = T/Tref P = Pref*exp(1.73683*(1-1./Tita)-0.544606e-1*(1-Tita**5) + 0.806106e-7*(1-Tita**22)) else: raise NotImplementedError("Incoming out of bound") return P # Transport properties def _Viscosity(rho, T, fase=None, drho=None): """Equation for the Viscosity Parameters ---------- rho : float Density, [kg/m³] T : float Temperature, [K] fase: dict, optional for calculate critical enhancement phase properties drho: float, optional for calculate critical enhancement [∂ρ/∂P]T at reference state, Returns ------- μ : float Viscosity, [Pa·s] Examples -------- >>> _Viscosity(998, 298.15) 0.0008897351001498108 >>> _Viscosity(600, 873.15) 7.743019522728247e-05 References ---------- IAPWS, Release on the IAPWS Formulation 2008 for the Viscosity of Ordinary Water Substance, http://www.iapws.org/relguide/viscosity.html """ Tr = T/Tc Dr = rho/rhoc # Eq 11 H = [1.67752, 2.20462, 0.6366564, -0.241605] mu0 = 100*Tr**0.5/sum(Hi/Tr**i for i, Hi in enumerate(H)) # Eq 12 li = [0, 1, 2, 3, 0, 1, 2, 3, 5, 0, 1, 2, 3, 4, 0, 1, 0, 3, 4, 3, 5] lj = [0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6] Hij = [0.520094, 0.850895e-1, -0.108374e1, -0.289555, 0.222531, 0.999115, 0.188797e1, 0.126613e1, 0.120573, -0.281378, -0.906851, -0.772479, -0.489837, -0.257040, 0.161913, 0.257399, -0.325372e-1, 0.698452e-1, 0.872102e-2, -0.435673e-2, -0.593264e-3] mu1 = exp(Dr*sum((1/Tr-1)**i*h*(Dr-1)**j for i, j, h in zip(li, lj, Hij))) # Critical enhancement if rho and fase and drho: qc = 1/1.9 qd = 1/1.1 # Eq 21 DeltaX = Pc*Dr**2*(fase.drhodP_T/rho-drho/rho*1.5/Tr) if DeltaX < 0: DeltaX = 0 # Eq 20 X = 0.13*(DeltaX/0.06)**(0.63/1.239) if X <= 0.3817016416: # Eq 15 Y = qc/5*X*(qd*X)**5*(1-qc*X+(qc*X)**2-765./504*(qd*X)**2) else: Fid = acos((1+qd**2*X**2)**-0.5) # Eq 17 w = abs((qc*X-1)/(qc*X+1))**0.5*tan(Fid/2) # Eq 19 # Eq 18 if qc*X > 1: Lw = log((1+w)/(1-w)) else: Lw = 2*atan(abs(w)) # Eq 16 Y = sin(3*Fid)/12-sin(2*Fid)/4/qc/X+(1-5/4*(qc*X)**2)/( qc*X)**2*sin(Fid)-((1-3/2*(qc*X)**2)*Fid-abs(( qc*X)**2-1)**1.5*Lw)/(qc*X)**3 # Eq 14 mu2 = exp(0.068*Y) else: mu2 = 1 # Eq 10 mu = mu0*mu1*mu2 return mu*1e-6 def _ThCond(rho, T, fase=None, drho=None): """Equation for the thermal conductivity Parameters ---------- rho : float Density, [kg/m³] T : float Temperature, [K] fase: dict, optional for calculate critical enhancement phase properties drho: float, optional for calculate critical enhancement [∂ρ/∂P]T at reference state, Returns ------- k : float Thermal conductivity, [W/mK] Examples -------- >>> _ThCond(998, 298.15) 0.6077128675880629 >>> _ThCond(0, 873.15) 0.07910346589648833 References ---------- IAPWS, Release on the IAPWS Formulation 2011 for the Thermal Conductivity of Ordinary Water Substance, http://www.iapws.org/relguide/ThCond.html """ d = rho/rhoc Tr = T/Tc # Eq 16 no = [2.443221e-3, 1.323095e-2, 6.770357e-3, -3.454586e-3, 4.096266e-4] k0 = Tr**0.5/sum(n/Tr**i for i, n in enumerate(no)) # Eq 17 li = [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4] lj = [0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5] nij = [1.60397357, -0.646013523, 0.111443906, 0.102997357, -0.0504123634, 0.00609859258, 2.33771842, -2.78843778, 1.53616167, -0.463045512, 0.0832827019, -0.00719201245, 2.19650529, -4.54580785, 3.55777244, -1.40944978, 0.275418278, -0.0205938816, -1.21051378, 1.60812989, -0.621178141, 0.0716373224, -2.7203370, 4.57586331, -3.18369245, 1.1168348, -0.19268305, 0.012913842] k1 = exp(d*sum((1/Tr-1)**i*n*(d-1)**j for i, j, n in zip(li, lj, nij))) # Critical enhancement if rho and fase: Rg = 0.46151805 if not drho: # Industrial formulation # Eq 25 if d <= 0.310559006: ai = [6.53786807199516, -5.61149954923348, 3.39624167361325, -2.27492629730878, 10.2631854662709, 1.97815050331519] elif d <= 0.776397516: ai = [6.52717759281799, -6.30816983387575, 8.08379285492595, -9.82240510197603, 12.1358413791395, -5.54349664571295] elif d <= 1.242236025: ai = [5.35500529896124, -3.96415689925446, 8.91990208918795, -12.0338729505790, 9.19494865194302, -2.16866274479712] elif d <= 1.863354037: ai = [1.55225959906681, 0.464621290821181, 8.93237374861479, -11.0321960061126, 6.16780999933360, -0.965458722086812] else: ai = [1.11999926419994, 0.595748562571649, 9.88952565078920, -10.3255051147040, 4.66861294457414, -0.503243546373828] drho = 1/sum(a*d**i for i, a in enumerate(ai))*rhoc/Pc DeltaX = d*(Pc/rhoc*fase.drhodP_T-Pc/rhoc*drho*1.5/Tr) if DeltaX < 0: DeltaX = 0 X = 0.13*(DeltaX/0.06)**(0.63/1.239) # Eq 22 y = X/0.4 # Eq 20 # Eq 19 if y < 1.2e-7: Z = 0 else: Z = 2/pi/y*(((1-1/fase.cp_cv)*atan(y)+y/fase.cp_cv)-( 1-exp(-1/(1/y+y**2/3/d**2)))) # Eq 18 k2 = 177.8514*d*fase.cp/Rg*Tr/fase.mu*1e-6*Z else: # No critical enhancement k2 = 0 # Eq 10 k = k0*k1+k2 return 1e-3*k def _Tension(T): """Equation for the surface tension Parameters ---------- T : float Temperature, [K] Returns ------- σ : float Surface tension, [N/m] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 248.15 ≤ T ≤ 647 * Estrapolate to -25ºC in supercooled liquid metastable state Examples -------- >>> _Tension(300) 0.0716859625 >>> _Tension(450) 0.0428914992 References ---------- IAPWS, Revised Release on Surface Tension of Ordinary Water Substance June 2014, http://www.iapws.org/relguide/Surf-H2O.html """ if 248.15 <= T <= Tc: tau = 1-T/Tc sigma = 235.8 * tau**1.256 * (1-0.625*tau) # The equation give surface tension in mN/m², converted to N/m² return 1e-3*sigma raise NotImplementedError("Incoming out of bound") def _Dielectric(rho, T): """Equation for the Dielectric constant Parameters ---------- rho : float Density, [kg/m³] T : float Temperature, [K] Returns ------- epsilon : float Dielectric constant, [-] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 238 ≤ T ≤ 1200 Examples -------- >>> _Dielectric(999.242866, 298.15) 78.5907250 >>> _Dielectric(26.0569558, 873.15) 1.12620970 References ---------- IAPWS, Release on the Static Dielectric Constant of Ordinary Water Substance for Temperatures from 238 K to 873 K and Pressures up to 1000 MPa, http://www.iapws.org/relguide/Dielec.html """ # Check input parameters if T < 238 or T > 1200: raise NotImplementedError("Incoming out of bound") k = 1.380658e-23 Na = 6.0221367e23 alfa = 1.636e-40 epsilon0 = 8.854187817e-12 mu = 6.138e-30 d = rho/rhoc Tr = Tc/T li = [1, 1, 1, 2, 3, 3, 4, 5, 6, 7, 10] lj = [0.25, 1, 2.5, 1.5, 1.5, 2.5, 2, 2, 5, 0.5, 10] ni = [0.978224486826, -0.957771379375, 0.237511794148, 0.714692244396, -0.298217036956, -0.108863472196, 0.949327488264e-1, -.980469816509e-2, 0.165167634970e-4, 0.937359795772e-4, -0.12317921872e-9, 0.196096504426e-2] g = 1+ni[11]*d/(Tc/228/Tr-1)**1.2 for n, i, j in zip(ni, li, lj): g += n * d**i * Tr**j A = Na*mu**2*rho*g/M*1000/epsilon0/k/T B = Na*alfa*rho/3/M*1000/epsilon0 e = (1+A+5*B+(9+2*A+18*B+A**2+10*A*B+9*B**2)**0.5)/4/(1-B) return e def _Refractive(rho, T, lr=0.5893): """Equation for the refractive index Parameters ---------- rho : float Density, [kg/m³] T : float Temperature, [K] lr : float, optional Light Wavelength, [μm] Returns ------- n : float Refractive index, [-] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 0 ≤ ρ ≤ 1060 * 261.15 ≤ T ≤ 773.15 * 0.2 ≤ λ ≤ 1.1 Examples -------- >>> _Refractive(997.047435, 298.15, 0.2265) 1.39277824 >>> _Refractive(30.4758534, 773.15, 0.5893) 1.00949307 References ---------- IAPWS, Release on the Refractive Index of Ordinary Water Substance as a Function of Wavelength, Temperature and Pressure, http://www.iapws.org/relguide/rindex.pdf """ # Check input parameters if rho < 0 or rho > 1060 or \ T < 261.15 or T > 773.15 or \ lr < 0.2 or lr > 1.1: raise NotImplementedError("Incoming out of bound") Lir = 5.432937 Luv = 0.229202 d = rho/1000. Tr = T/273.15 L = lr/0.589 a = [0.244257733, 0.974634476e-2, -0.373234996e-2, 0.268678472e-3, 0.158920570e-2, 0.245934259e-2, 0.900704920, -0.166626219e-1] A = d*(a[0]+a[1]*d+a[2]*Tr+a[3]*L**2*Tr+a[4]/L**2+a[5]/(L**2-Luv**2)+a[6]/( L**2-Lir**2)+a[7]*d**2) return ((2*A+1)/(1-A))**0.5 def _Kw(rho, T): """Equation for the ionization constant of ordinary water Parameters ---------- rho : float Density, [kg/m³] T : float Temperature, [K] Returns ------- pKw : float Ionization constant in -log10(kw), [-] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 0 ≤ ρ ≤ 1250 * 273.15 ≤ T ≤ 1073.15 Examples -------- >>> _Kw(1000, 300) 13.906565 References ---------- IAPWS, Release on the Ionization Constant of H2O, http://www.iapws.org/relguide/Ionization.pdf """ # Check input parameters if rho < 0 or rho > 1250 or T < 273.15 or T > 1273.15: raise NotImplementedError("Incoming out of bound") # The internal method of calculation use rho in g/cm³ d = rho/1000. # Water molecular weight different Mw = 18.015268 gamma = [6.1415e-1, 4.825133e4, -6.770793e4, 1.01021e7] pKg = 0 for i, g in enumerate(gamma): pKg += g/T**i Z = d*exp(-0.702132+8681.05/T-24145.1/T**2*d**(2./3)) pKw = -12*(log10(1+Z)-Z/(Z+1)*d*(0.813876-51.4471/T-0.46992*d)) + \ pKg + 2*log10(Mw/1000) return pKw def _Conductivity(rho, T): """Equation for the electrolytic conductivity of liquid and dense supercrítical water Parameters ---------- rho : float Density, [kg/m³] T : float Temperature, [K] Returns ------- K : float Electrolytic conductivity, [S/m] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 600 ≤ ρ ≤ 1200 * 273.15 ≤ T ≤ 1073.15 Examples -------- >>> _Conductivity(1000, 373.15) 1.13 References ---------- IAPWS, Electrolytic Conductivity (Specific Conductance) of Liquid and Dense Supercritical Water from 0°C to 800°C and Pressures up to 1000 MPa, http://www.iapws.org/relguide/conduct.pdf """ # density in g/l rho_ = rho/1000 # This guideline predates the current standard on the ionization constant, # therefore the standard accepted at that time must be used in order to # obtain the values of the tables for testing. # Marshall, W.L., Franck, E.U. # Ion product of water substance, 0-1000ºC, 1-10,000 bars New International # Formulation and its background # J. Phys. Chem. Ref. Data 10(2) (1981) 295-304 # doi: 10.1063/1.555643 # Eq 4 kw = 10**(-4.098 - 3245.2/T + 2.2362e5/T**2 - 3.984e7/T**3 + (13.957 - 1262.3/T + 8.5641e5/T**2)*log10(rho_)) # kw = 10**-_Kw(rho, T) A = [1850., 1410., 2.16417e-6, 1.81609e-7, -1.75297e-9, 7.20708e-12] B = [16., 11.6, 3.26e-4, -2.3e-6, 1.1e-8] t = T-273.15 Loo = A[0]-1/(1/A[1] + A[2]*t + A[3]*t**2 + A[4]*t**3 + A[5]*t**4) # Eq 5 rho_h = B[0]-1/(1/B[1] + B[2]*t + B[3]*t**2 + B[4]*t**3) # Eq 6 # Eq 4 L_o = (rho_h-rho_)*Loo/rho_h # Eq 1 k = 1e-3*L_o*kw**0.5*rho_ return k*1e2 # Heavy water transport properties def _D2O_Viscosity(rho, T, fase=None, drho=None): """Equation for the Viscosity of heavy water Parameters ---------- rho : float Density, [kg/m³] T : float Temperature, [K] fase: dict, optional for calculate critical enhancement phase properties drho: float, optional for calculate critical enhancement [∂ρ/∂P]T at reference state, Returns ------- μ : float Viscosity, [Pa·s] Examples -------- >>> _D2O_Viscosity(998, 298.15) 0.0008897351001498108 >>> _D2O_Viscosity(600, 873.15) 7.743019522728247e-05 References ---------- IAPWS, Release on the IAPWS Formulation 2020 for the Viscosity of Heavy Water, http://iapws.org/relguide/D2Ovisc.pdf """ Tr = T/Tc_D2O rhor = rho/356 # Eq 11, viscosity in the dilute-gas limit no = 0.889754+61.22217*Tr-44.8866*Tr**2+111.5812*Tr**3+3.547412*Tr**4 do = 0.79637+2.38127*Tr-0.33463*Tr**2+2.669*Tr**3+0.000211366*Tr**4 mu0 = Tr**0.5 * no/do # Eq 12 hi = [0, 2, 3, 4, 5, 6, 0, 1, 3, 4, 6, 0, 1, 5, 0, 1, 2, 5, 6, 0, 2, 3, 5, 2, 2] hj = [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 6] Hij = [0.510953, -0.558947, -2.718820, 0.480990, 2.404510, -1.824320, 0.275847, 0.762957, 1.760340, 0.0819086, 1.417750, -0.228148, -0.321497, -2.302500, 0.0661035, 0.0449393, 1.466670, 0.938984, -0.108354, -0.00481265, -1.545710, -0.0570938, -0.0753783, 0.553080, -0.0650201] arr = [(1/Tr-1)**i*(rhor-1)**j*hij for i, j, hij in zip(hi, hj, Hij)] mu1 = exp(rhor*sum(arr)) # Critical enhancement if rho and fase and drho: qc = 1/1.9 qd = 1/0.4 # Eq 21 DeltaX = Pc_D2O*rhor**2*(fase.drhodP_T/rho-drho/rho*1.5/Tr) if DeltaX < 0: DeltaX = 0 # Eq 20 X = 0.13*(DeltaX/0.06)**(0.63/1.239) if X <= 0.03021806692: # Eq 15 Y = qc/5*X*(qd*X)**5*(1-qc*X+(qc*X)**2-765/504*(qd*X)**2) else: Fid = acos((1+qd**2*X**2)**-0.5) # Eq 17 w = abs((qc*X-1)/(qc*X+1))**0.5*tan(Fid/2) # Eq 19 # Eq 18 if qc*X > 1: Lw = log((1+w)/(1-w)) else: Lw = 2*atan(abs(w)) # Eq 16 Y = sin(3*Fid)/12-sin(2*Fid)/4/qc/X+(1-5/4*(qc*X)**2)/( qc*X)**2*sin(Fid)-((1-3/2*(qc*X)**2)*Fid-abs(( qc*X)**2-1)**1.5*Lw)/(qc*X)**3 # Eq 14 mu2 = exp(0.068*Y) else: mu2 = 1 return mu0*mu1*mu2*1e-6 def _D2O_ThCond(rho, T, fase=None, drho=None): """Equation for the thermal conductivity of heavy water Parameters ---------- rho : float Density, [kg/m³] T : float Temperature, [K] fase: dict, optional for calculate critical enhancement phase properties drho: float, optional for calculate critical enhancement [∂ρ/∂P]T at reference state, Returns ------- k : float Thermal conductivity, [W/mK] Examples -------- >>> _D2O_ThCond(998, 298.15) 0.6077128675880629 >>> _D2O_ThCond(0, 873.15) 0.07910346589648833 References ---------- IAPWS, Release on the IAPWS Formulation 2021 for the Thermal Conductivity of Heavy Water, http://iapws.org/relguide/D2OThCond.pdf """ d = rho/356 Tr = T/643.847 # Eq 16 no = [1, 3.3620798, -1.0191198, 2.8518117] do = [0.10779213, -0.034637234, 0.036603464, 0.0091018912] k0 = Tr**0.5 * sum(Li*Tr**i for i, Li in enumerate(no)) / \ sum(Li*Tr**i for i, Li in enumerate(do)) # Eq 17 li = [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4] lj = [0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5] nij = [1.50933576, -0.65831078, 0.111174263, 0.140185152, -0.0656227722, 0.00785155213, 2.8414715, -2.9826577, 1.34357932, -0.599233641, 0.28116337, -0.0533292833, 4.86095723, -6.19784468, 2.20941867, 0.224691518, -0.322191265, 0.0596204654, 2.06156007, -3.48612456, 1.47962309, 0.625101458, -0.56123225, 0.0974446139, -2.06105687, 0.416240028, 2.92524513, -2.81703583, 1.00551476, -0.127884416] k1 = exp(d*sum((1/Tr-1)**i * n*(d-1)**j for i, j, n in zip(li, lj, nij))) # Critical enhancement if rho and fase and drho: Rg = 0.415151994 DeltaX = d*(Pc_D2O/rhoc_D2O*fase.drhodP_T-Pc_D2O/rhoc_D2O*drho*1.5/Tr) if DeltaX < 0: DeltaX = 0 X = 0.13*(DeltaX/0.06)**(0.63/1.239) # Eq 22 y = X/0.36 # Eq 20 # Eq 19 if y < 1.2e-7: Z = 0 else: Z = 2/pi/y*(((1-1/fase.cp_cv)*atan(y)+y/fase.cp_cv)-( 1-exp(-1/(1/y+y**2/3/d**2)))) # Eq 18 k2 = 175.987*d*fase.cp/Rg*Tr/fase.mu*1e-6*Z else: # No critical enhancement k2 = 0 # Eq 15 k = k0*k1+k2 return 1e-3*k def _D2O_Tension(T): """Equation for the surface tension of heavy water Parameters ---------- T : float Temperature, [K] Returns ------- σ : float Surface tension, [N/m] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 269.65 ≤ T ≤ 643.847 Examples -------- >>> _D2O_Tension(298.15) 0.07186 >>> _D2O_Tension(573.15) 0.01399 References ---------- IAPWS, Release on Surface Tension of Heavy Water Substance, http://www.iapws.org/relguide/surfd2o.pdf """ Tr = T/643.847 if 269.65 <= T <= 643.847: return 1e-3*(238*(1-Tr)**1.25*(1-0.639*(1-Tr))) raise NotImplementedError("Incoming out of bound") def _D2O_Sublimation_Pressure(T): """Sublimation Pressure correlation for heavy water Parameters ---------- T : float Temperature, [K] Returns ------- P : float Pressure at sublimation line, [MPa] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 210 ≤ T ≤ 276.969 Examples -------- >>> _Sublimation_Pressure(245) 3.27390934e-5 References ---------- IAPWS, Revised Release on the IAPWS Formulation 2017 for the Thermodynamic Properties of Heavy Water, http://www.iapws.org/relguide/Heavy.html. """ if 210 <= T <= 276.969: Tita = T/276.969 suma = 0 ai = [-0.1314226e2, 0.3212969e2] ti = [-1.73, -1.42] for a, t in zip(ai, ti): suma += a*(1-Tita**t) return exp(suma)*0.00066159 raise NotImplementedError("Incoming out of bound") def _D2O_Melting_Pressure(T, ice="Ih"): """Melting Pressure correlation for heavy water Parameters ---------- T : float Temperature, [K] ice: string Type of ice: Ih, III, V, VI, VII. Below 276.969 is a mandatory input, the ice Ih is the default value. Above 276.969, the ice type is unnecesary. Returns ------- P : float Pressure at melting line, [MPa] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 254.415 ≤ T ≤ 315 Examples -------- >>> _D2O__Melting_Pressure(260) 8.947352740189152e-06 >>> _D2O__Melting_Pressure(254, "III") 268.6846466336108 References ---------- IAPWS, Revised Release on the Pressure along the Melting and Sublimation Curves of Ordinary Water Substance, http://iapws.org/relguide/MeltSub.html. """ if ice == "Ih" and 254.415 <= T <= 276.969: # Ice Ih, Eq 9 Tita = T/276.969 ai = [-0.30153e5, 0.692503e6] ti = [5.5, 8.2] suma = 1 for a, t in zip(ai, ti): suma += a*(1-Tita**t) P = suma*0.00066159 elif ice == "III" and 254.415 < T <= 258.661: # Ice III, Eq 10 Tita = T/254.415 P = 222.41*(1-0.802871*(1-Tita**33)) elif ice == "V" and 258.661 < T <= 275.748: # Ice V, Eq 11 Tita = T/258.661 P = 352.19*(1-1.280388*(1-Tita**7.6)) elif (ice == "VI" and 275.748 < T <= 276.969) or 276.969 < T <= 315: # Ice VI Tita = T/275.748 P = 634.53*(1-1.276026*(1-Tita**4)) else: raise NotImplementedError("Incoming out of bound") return P def _Henry(T, gas, liquid="H2O"): """Equation for the calculation of Henry's constant Parameters ---------- T : float Temperature, [K] gas : string Name of gas to calculate solubility liquid : string Name of liquid solvent, can be H20 (default) or D2O Returns ------- kw : float Henry's constant, [MPa] Notes ----- The gas availables for H2O solvent are He, Ne, Ar, Kr, Xe, H2, N2, O2, CO, CO2, H2S, CH4, C2H6, SF6 For D2O as solvent He, Ne, Ar, Kr, Xe, D2, CH4 Raise :class:`NotImplementedError` if input gas or liquid are unsupported Examples -------- >>> _Henry(500, "He") 1.1973 >>> _Henry(300, "D2", "D2O") 1.6594 References ---------- IAPWS, Guideline on the Henry's Constant and Vapor-Liquid Distribution Constant for Gases in H2O and D2O at High Temperatures, http://www.iapws.org/relguide/HenGuide.html """ if liquid == "D2O": gas += "(D2O)" limit = { "He": (273.21, 553.18), "Ne": (273.20, 543.36), "Ar": (273.19, 568.36), "Kr": (273.19, 525.56), "Xe": (273.22, 574.85), "H2": (273.15, 636.09), "N2": (278.12, 636.46), "O2": (274.15, 616.52), "CO": (278.15, 588.67), "CO2": (274.19, 642.66), "H2S": (273.15, 533.09), "CH4": (275.46, 633.11), "C2H6": (275.44, 473.46), "SF6": (283.14, 505.55), "He(D2O)": (288.15, 553.18), "Ne(D2O)": (288.18, 549.96), "Ar(D2O)": (288.30, 583.76), "Kr(D2O)": (288.19, 523.06), "Xe(D2O)": (295.39, 574.85), "D2(D2O)": (288.17, 581.00), "CH4(D2O)": (288.16, 517.46)} # Check input parameters if liquid not in ("D2O", "H2O"): raise NotImplementedError("Solvent liquid unsupported") if gas not in limit: raise NotImplementedError("Gas unsupported") Tmin, Tmax = limit[gas] if T < Tmin or T > Tmax: warnings.warn("Temperature out of data of correlation") if liquid == "D2O": Tc_ = Tc_D2O Pc_ = 21.671 else: Tc_ = Tc Pc_ = Pc Tr = T/Tc_ tau = 1-Tr # Eq 4 if liquid == "H2O": ai = [-7.85951783, 1.84408259, -11.7866497, 22.6807411, -15.9618719, 1.80122502] bi = [1, 1.5, 3, 3.5, 4, 7.5] else: ai = [-7.896657, 24.73308, -27.81128, 9.355913, -9.220083] bi = [1, 1.89, 2, 3, 3.6] ps = Pc_*exp(1/Tr*sum(a*tau**b for a, b in zip(ai, bi))) # Select values from Table 2 par = { "He": (-3.52839, 7.12983, 4.47770), "Ne": (-3.18301, 5.31448, 5.43774), "Ar": (-8.40954, 4.29587, 10.52779), "Kr": (-8.97358, 3.61508, 11.29963), "Xe": (-14.21635, 4.00041, 15.60999), "H2": (-4.73284, 6.08954, 6.06066), "N2": (-9.67578, 4.72162, 11.70585), "O2": (-9.44833, 4.43822, 11.42005), "CO": (-10.52862, 5.13259, 12.01421), "CO2": (-8.55445, 4.01195, 9.52345), "H2S": (-4.51499, 5.23538, 4.42126), "CH4": (-10.44708, 4.66491, 12.12986), "C2H6": (-19.67563, 4.51222, 20.62567), "SF6": (-16.56118, 2.15289, 20.35440), "He(D2O)": (-0.72643, 7.02134, 2.04433), "Ne(D2O)": (-0.91999, 5.65327, 3.17247), "Ar(D2O)": (-7.17725, 4.48177, 9.31509), "Kr(D2O)": (-8.47059, 3.91580, 10.69433), "Xe(D2O)": (-14.46485, 4.42330, 15.60919), "D2(D2O)": (-5.33843, 6.15723, 6.53046), "CH4(D2O)": (-10.01915, 4.73368, 11.75711)} A, B, C = par[gas] # Eq 3 kh = ps*exp(A/Tr+B*tau**0.355/Tr+C*Tr**-0.41*exp(tau)) return kh def _Kvalue(T, gas, liquid="H2O"): """Equation for the vapor-liquid distribution constant Parameters ---------- T : float Temperature, [K] gas : string Name of gas to calculate solubility liquid : string Name of liquid solvent, can be H20 (default) or D2O Returns ------- kd : float Vapor-liquid distribution constant, [-] Notes ----- The gas availables for H2O solvent are He, Ne, Ar, Kr, Xe, H2, N2, O2, CO, CO2, H2S, CH4, C2H6, SF6 For D2O as solvent He, Ne, Ar, Kr, Xe, D2, CH4 Raise :class:`NotImplementedError` if input gas or liquid are unsupported Examples -------- >>> _Kvalue(600, "He") 3.8019 >>> _Kvalue(300, "D2", "D2O") 14.3520 References ---------- IAPWS, Guideline on the Henry's Constant and Vapor-Liquid Distribution Constant for Gases in H2O and D2O at High Temperatures, http://www.iapws.org/relguide/HenGuide.html """ if liquid == "D2O": gas += "(D2O)" limit = { "He": (273.21, 553.18), "Ne": (273.20, 543.36), "Ar": (273.19, 568.36), "Kr": (273.19, 525.56), "Xe": (273.22, 574.85), "H2": (273.15, 636.09), "N2": (278.12, 636.46), "O2": (274.15, 616.52), "CO": (278.15, 588.67), "CO2": (274.19, 642.66), "H2S": (273.15, 533.09), "CH4": (275.46, 633.11), "C2H6": (275.44, 473.46), "SF6": (283.14, 505.55), "He(D2O)": (288.15, 553.18), "Ne(D2O)": (288.18, 549.96), "Ar(D2O)": (288.30, 583.76), "Kr(D2O)": (288.19, 523.06), "Xe(D2O)": (295.39, 574.85), "D2(D2O)": (288.17, 581.00), "CH4(D2O)": (288.16, 517.46)} # Check input parameters if liquid not in ("D2O", "H2O"): raise NotImplementedError("Solvent liquid unsupported") if gas not in limit: raise NotImplementedError("Gas unsupported") Tmin, Tmax = limit[gas] if T < Tmin or T > Tmax: warnings.warn("Temperature out of data of correlation") if liquid == "D2O": Tc_ = Tc_D2O else: Tc_ = Tc Tr = T/Tc_ tau = 1-Tr # Eq 6 if liquid == "H2O": ci = [1.99274064, 1.09965342, -0.510839303, -1.75493479, -45.5170352, -6.7469445e5] di = [1/3, 2/3, 5/3, 16/3, 43/3, 110/3] q = -0.023767 else: ci = [2.7072, 0.58662, -1.3069, -45.663] di = [0.374, 1.45, 2.6, 12.3] q = -0.024552 f = sum(c*tau**d for c, d in zip(ci, di)) # Select values from Table 2 par = {"He": (2267.4082, -2.9616, -3.2604, 7.8819), "Ne": (2507.3022, -38.6955, 110.3992, -71.9096), "Ar": (2310.5463, -46.7034, 160.4066, -118.3043), "Kr": (2276.9722, -61.1494, 214.0117, -159.0407), "Xe": (2022.8375, 16.7913, -61.2401, 41.9236), "H2": (2286.4159, 11.3397, -70.7279, 63.0631), "N2": (2388.8777, -14.9593, 42.0179, -29.4396), "O2": (2305.0674, -11.3240, 25.3224, -15.6449), "CO": (2346.2291, -57.6317, 204.5324, -152.6377), "CO2": (1672.9376, 28.1751, -112.4619, 85.3807), "H2S": (1319.1205, 14.1571, -46.8361, 33.2266), "CH4": (2215.6977, -0.1089, -6.6240, 4.6789), "C2H6": (2143.8121, 6.8859, -12.6084, 0), "SF6": (2871.7265, -66.7556, 229.7191, -172.7400), "He(D2O)": (2293.2474, -54.7707, 194.2924, -142.1257), "Ne(D2O)": (2439.6677, -93.4934, 330.7783, -243.0100), "Ar(D2O)": (2269.2352, -53.6321, 191.8421, -143.7659), "Kr(D2O)": (2250.3857, -42.0835, 140.7656, -102.7592), "Xe(D2O)": (2038.3656, 68.1228, -271.3390, 207.7984), "D2(D2O)": (2141.3214, -1.9696, 1.6136, 0), "CH4(D2O)": (2216.0181, -40.7666, 152.5778, -117.7430)} E, F, G, H = par[gas] # Eq 5 kd = exp(q*F+E/T*f+(F+G*tau**(2./3)+H*tau)*exp((273.15-T)/100)) return kd iapws-1.5.5/iapws/iapws95.py0000644000175000017500000032030714743702402016035 0ustar alastairalastair#!/usr/bin/python # -*- coding: utf-8 -*- # pylint: disable=invalid-name # pylint: disable=too-many-lines, too-many-locals, too-many-instance-attributes # pylint: disable=too-many-branches, too-many-statements """ Implemented multiparameter equation of state as a Helmholtz free energy: * :class:`MEoS`: Base class of multiparameter equation of state * :class:`IAPWS95`: 2016 revision of 1995 formulation for ordinaty water * :class:`D2O`: 2017 formulation for heavy water. """ from __future__ import division try: from concurrent.futures import ProcessPoolExecutor except ImportError: # python2 pass from itertools import repeat import json import os import platform import warnings from numpy import exp, log, ndarray from numpy.polynomial import chebyshev from scipy.optimize import fsolve from .iapws97 import _TSat_P, IAPWS97 from ._iapws import M, Tc, Pc, rhoc, Tc_D2O, Pc_D2O, rhoc_D2O from ._iapws import _Viscosity, _ThCond, _Dielectric, _Refractive, _Tension from ._iapws import _D2O_Viscosity, _D2O_ThCond, _D2O_Tension from ._utils import _fase, getphase, deriv_H, _instanceBuilder def _phir(tau, delta, coef): """Residual contribution to the adimensional free Helmholtz energy Parameters ---------- tau : float Inverse reduced temperature Tc/T, [-] delta : float Reduced density rho/rhoc, [-] coef : dict Dictionary with equation of state parameters Returns ------- fir : float Adimensional free Helmholtz energy References ---------- IAPWS, Revised Release on the IAPWS Formulation 1995 for the Thermodynamic Properties of Ordinary Water Substance for General and Scientific Use, September 2016, Table 5 http://www.iapws.org/relguide/IAPWS-95.html """ fir = 0 # Polinomial terms nr1 = coef.get("nr1", []) d1 = coef.get("d1", []) t1 = coef.get("t1", []) for n, d, t in zip(nr1, d1, t1): fir += n*delta**d*tau**t # Exponential terms nr2 = coef.get("nr2", []) d2 = coef.get("d2", []) g2 = coef.get("gamma2", []) t2 = coef.get("t2", []) c2 = coef.get("c2", []) for n, d, g, t, c in zip(nr2, d2, g2, t2, c2): fir += n*delta**d*tau**t*exp(-g*delta**c) # Gaussian terms nr3 = coef.get("nr3", []) d3 = coef.get("d3", []) t3 = coef.get("t3", []) a3 = coef.get("alfa3", []) e3 = coef.get("epsilon3", []) b3 = coef.get("beta3", []) g3 = coef.get("gamma3", []) for n, d, t, a, e, b, g in zip(nr3, d3, t3, a3, e3, b3, g3): fir += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2) # Non analitic terms nr4 = coef.get("nr4", []) a4 = coef.get("a4", []) b4 = coef.get("b4", []) Ai = coef.get("A", []) Bi = coef.get("B", []) Ci = coef.get("C", []) Di = coef.get("D", []) bt4 = coef.get("beta4", []) for n, a, b, A, B, C, D, bt in zip(nr4, a4, b4, Ai, Bi, Ci, Di, bt4): Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) F = exp(-C*(delta-1)**2-D*(tau-1)**2) Delta = Tita**2+B*((delta-1)**2)**a fir += n*Delta**b*delta*F return fir def _phird(tau, delta, coef): r"""Residual contribution to the adimensional free Helmholtz energy, delta derivative Parameters ---------- tau : float Inverse reduced temperature Tc/T, [-] delta : float Reduced density rho/rhoc, [-] coef : dict Dictionary with equation of state parameters Returns ------- fird : float .. math:: \left.\frac{\partial \phi^r_{\delta}}{\partial \delta}\right|_{\tau} References ---------- IAPWS, Revised Release on the IAPWS Formulation 1995 for the Thermodynamic Properties of Ordinary Water Substance for General and Scientific Use, September 2016, Table 5 http://www.iapws.org/relguide/IAPWS-95.html """ fird = 0 # Polinomial terms nr1 = coef.get("nr1", []) d1 = coef.get("d1", []) t1 = coef.get("t1", []) for n, d, t in zip(nr1, d1, t1): fird += n*d*delta**(d-1)*tau**t # Exponential terms nr2 = coef.get("nr2", []) d2 = coef.get("d2", []) g2 = coef.get("gamma2", []) t2 = coef.get("t2", []) c2 = coef.get("c2", []) for n, d, g, t, c in zip(nr2, d2, g2, t2, c2): fird += n*exp(-g*delta**c)*delta**(d-1)*tau**t*(d-g*c*delta**c) # Gaussian terms nr3 = coef.get("nr3", []) d3 = coef.get("d3", []) t3 = coef.get("t3", []) a3 = coef.get("alfa3", []) e3 = coef.get("epsilon3", []) b3 = coef.get("beta3", []) g3 = coef.get("gamma3", []) for n, d, t, a, e, b, g in zip(nr3, d3, t3, a3, e3, b3, g3): fird += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( d/delta-2*a*(delta-e)) # Non analitic terms nr4 = coef.get("nr4", []) a4 = coef.get("a4", []) b4 = coef.get("b4", []) Ai = coef.get("A", []) Bi = coef.get("B", []) Ci = coef.get("C", []) Di = coef.get("D", []) bt4 = coef.get("beta4", []) for n, a, b, A, B, C, D, bt in zip(nr4, a4, b4, Ai, Bi, Ci, Di, bt4): Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) F = exp(-C*(delta-1)**2-D*(tau-1)**2) Fd = -2*C*F*(delta-1) Delta = Tita**2+B*((delta-1)**2)**a Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**(0.5/bt-1) + 2*B*a*((delta-1)**2)**(a-1)) if Delta == 0: DeltaBd = 0 else: DeltaBd = b*Delta**(b-1)*Deltad fird += n*(Delta**b*(F+delta*Fd)+DeltaBd*delta*F) return fird def _phirt(tau, delta, coef): r"""Residual contribution to the adimensional free Helmholtz energy, tau derivative Parameters ---------- tau : float Inverse reduced temperature Tc/T, [-] delta : float Reduced density rho/rhoc, [-] coef : dict Dictionary with equation of state parameters Returns ------- firt : float .. math:: \left.\frac{\partial \phi^r_{\tau}}{\partial \tau}\right|_{\delta} References ---------- IAPWS, Revised Release on the IAPWS Formulation 1995 for the Thermodynamic Properties of Ordinary Water Substance for General and Scientific Use, September 2016, Table 5 http://www.iapws.org/relguide/IAPWS-95.html """ firt = 0 # Polinomial terms nr1 = coef.get("nr1", []) d1 = coef.get("d1", []) t1 = coef.get("t1", []) for n, d, t in zip(nr1, d1, t1): firt += n*t*delta**d*tau**(t-1) # Exponential terms nr2 = coef.get("nr2", []) d2 = coef.get("d2", []) g2 = coef.get("gamma2", []) t2 = coef.get("t2", []) c2 = coef.get("c2", []) for n, d, g, t, c in zip(nr2, d2, g2, t2, c2): firt += n*t*delta**d*tau**(t-1)*exp(-g*delta**c) # Gaussian terms nr3 = coef.get("nr3", []) d3 = coef.get("d3", []) t3 = coef.get("t3", []) a3 = coef.get("alfa3", []) e3 = coef.get("epsilon3", []) b3 = coef.get("beta3", []) g3 = coef.get("gamma3", []) for n, d, t, a, e, b, g in zip(nr3, d3, t3, a3, e3, b3, g3): firt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( t/tau-2*b*(tau-g)) # Non analitic terms nr4 = coef.get("nr4", []) a4 = coef.get("a4", []) b4 = coef.get("b4", []) Ai = coef.get("A", []) Bi = coef.get("B", []) Ci = coef.get("C", []) Di = coef.get("D", []) bt4 = coef.get("beta4", []) for n, a, b, A, B, C, D, bt in zip(nr4, a4, b4, Ai, Bi, Ci, Di, bt4): Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) F = exp(-C*(delta-1)**2-D*(tau-1)**2) Ft = -2*D*F*(tau-1) Delta = Tita**2+B*((delta-1)**2)**a if Delta == 0: DeltaBt = 0 else: DeltaBt = -2*Tita*b*Delta**(b-1) firt += n*delta*(DeltaBt*F+Delta**b*Ft) return firt class MEoS(_fase): r""" General implementation of multiparameter equation of state. From this derived all child class specified per individual compounds Parameters ---------- T : float Temperature, [K] P : float Pressure, [MPa] rho : float Density, [kg/m³] v : float Specific volume, [m³/kg] h : float Specific enthalpy, [kJ/kg] s : float Specific entropy, [kJ/kgK] u : float Specific internal energy, [kJ/kg] x : float Vapor quality, [-] l : float, optional Wavelength of light, for refractive index, [μm] rho0 : float, optional Initial value of density, to improve iteration, [kg/m³] T0 : float, optional Initial value of temperature, to improve iteration, [K] x0 : Initial value of vapor quality, necessary in bad input pair definition where there are two valid solution (T-h, T-s) Notes ----- * It needs two incoming properties of T, P, rho, h, s, u. * v as a alternate input parameter to rho * T-x, P-x, preferred input pair to specified a point in two phases region The calculated instance has the following properties: * P: Pressure, [MPa] * T: Temperature, [K] * x: Vapor quality, [-] * g: Specific Gibbs free energy, [kJ/kg] * a: Specific Helmholtz free energy, [kJ/kg] * v: Specific volume, [m³/kg] * r: Density, [kg/m³] * h: Specific enthalpy, [kJ/kg] * u: Specific internal energy, [kJ/kg] * s: Specific entropy, [kJ/kg·K] * cp: Specific isobaric heat capacity, [kJ/kg·K] * cv: Specific isochoric heat capacity, [kJ/kg·K] * cp_cv: Heat capacity ratio, [-] * Z: Compression factor, [-] * fi: Fugacity coefficient, [-] * f: Fugacity, [MPa] * gamma: Isoentropic exponent, [-] * alfav: Isobaric cubic expansion coefficient, [1/K] * kappa: Isothermal compressibility, [1/MPa] * kappas: Adiabatic compresibility, [1/MPa] * alfap: Relative pressure coefficient, [1/K] * betap: Isothermal stress coefficient, [kg/m³] * joule: Joule-Thomson coefficient, [K/MPa] * betas: Isoentropic temperature-pressure coefficient, [-] * Gruneisen: Gruneisen parameter, [-] * virialB: Second virial coefficient, [m³/kg] * virialC: Third virial coefficient, [m⁶/kg²] * dpdT_rho: Derivatives, dp/dT at constant rho, [MPa/K] * dpdrho_T: Derivatives, dp/drho at constant T, [MPa·m³/kg] * drhodT_P: Derivatives, drho/dT at constant P, [kg/m³·K] * drhodP_T: Derivatives, drho/dP at constant T, [kg/m³·MPa] * dhdT_rho: Derivatives, dh/dT at constant rho, [kJ/kg·K] * dhdP_T: Isothermal throttling coefficient, [kJ/kg·MPa] * dhdT_P: Derivatives, dh/dT at constant P, [kJ/kg·K] * dhdrho_T: Derivatives, dh/drho at constant T, [kJ·m³/kg²] * dhdrho_P: Derivatives, dh/drho at constant P, [kJ·m³/kg²] * dhdP_rho: Derivatives, dh/dP at constant rho, [kJ/kg·MPa] * kt: Isothermal Expansion Coefficient, [-] * ks: Adiabatic Compressibility, [1/MPa] * Ks: Adiabatic bulk modulus, [MPa] * Kt: Isothermal bulk modulus, [MPa] * v0: Ideal specific volume, [m³/kg] * rho0: Ideal gas density, [kg/m³] * u0: Ideal specific internal energy, [kJ/kg] * h0: Ideal specific enthalpy, [kJ/kg] * s0: Ideal specific entropy, [kJ/kg·K] * a0: Ideal specific Helmholtz free energy, [kJ/kg] * g0: Ideal specific Gibbs free energy, [kJ/kg] * cp0: Ideal specific isobaric heat capacity, [kJ/kg·K] * cv0: Ideal specific isochoric heat capacity, [kJ/kg·K] * w0: Ideal speed of sound, [m/s] * gamma0: Ideal isoentropic exponent, [-] * w: Speed of sound, [m/s] * mu: Dynamic viscosity, [Pa·s] * nu: Kinematic viscosity, [m²/s] * k: Thermal conductivity, [W/m·K] * alfa: Thermal diffusivity, [m²/s] * sigma: Surface tension, [N/m] * epsilon: Dielectric constant, [-] * n: Refractive index, [-] * Prandt: Prandtl number, [-] * Pr: Reduced Pressure, [-] * Tr: Reduced Temperature, [-] * Hvap: Vaporization heat, [kJ/kg] * Svap: Vaporization entropy, [kJ/kg·K] * Z_rho: :math:`(Z-1)/\rho`, [m³/kg] * IntP: Internal pressure, [MPa] * invT: Negative reciprocal temperature, [1/K] * hInput: Specific heat input, [kJ/kg] """ Fi0 = {} _constants = {} _Pv = {} _rhoL = {} _rhoG = {} _surf = {} kwargs = {"T": 0.0, "P": 0.0, "rho": 0.0, "v": 0.0, "h": None, "s": None, "u": None, "x": None, "l": 0.5893, "rho0": None, "T0": None, "x0": 0.5} name = None M = None Tc = None Pc = None rhoc = None Tt = None status = 0 msg = "Undefined" _mode = None Liquid = None Gas = None Vapor = None T = None Tr = None P = None Pr = None x = None phase = None sigma = None virialB = None virialC = None Hvap = None Svap = None invT = None v0 = None rho0 = None h0 = None u0 = None s0 = None a0 = None g0 = None cp0 = None cv0 = None cp0_cv = None gamma0 = None @classmethod def from_list(cls, p1name, p1val, p2name, p2val): """Speed up method using multiprocessing for multiple point calculation with a fixed input and changing other input parameter Parameters ---------- p1name : str string with name of fixed input parameter p1val : float fixed input parameter value p2name : str string with name of changing input parameter p2val : list iterable with values of changing input parameter Returns ------- states : list list with calculated states """ py_version = platform.python_version_tuple()[0] lst = [] if py_version == "3": with ProcessPoolExecutor() as executor: states = executor.map( _instanceBuilder, *(p2val, repeat(cls), repeat(p1name), repeat(p1val), repeat(p2name))) for state in states: lst.append(state) elif py_version == "2": # Disable multithreading in python2 def fi(x): return cls(**{p1name: p1val, p2name: x}) for xi in p2val: lst.append(fi(xi)) return lst def __init__(self, **kwargs): """Constructor, define common constant and initinialice kwargs""" self.R = self._constants["R"]/self._constants.get("M", self.M) self.Zc = self.Pc/self.rhoc/self.R/self.Tc self.kwargs = MEoS.kwargs.copy() self.__call__(**kwargs) def __call__(self, **kwargs): """Make instance callable to can add input parameter one to one""" # Alternative rho input if "rhom" in kwargs: kwargs["rho"] = kwargs["rhom"]*self.M del kwargs["rhom"] elif kwargs.get("v", 0): kwargs["rho"] = 1./kwargs["v"] del kwargs["v"] elif kwargs.get("vm", 0): kwargs["rho"] = self.M/kwargs["vm"] del kwargs["vm"] self.kwargs.update(kwargs) if self.calculable: try: self.status = 1 self.calculo() self.msg = "" except RuntimeError as err: self.status = 0 self.msg = err.args[0] raise err # Add msg for extrapolation state if self.name == "water" and 130 <= self.T < 273.15: self.msg = "Extrapolated state" self.status = 3 warnings.warn("Using extrapolated values") elif self.name == "water" and 50 <= self.T < 130: self.msg = "Extrapolated state using Low-Temperature extension" self.status = 3 warnings.warn("Using extrapolated values and Low-Temperature" "extension") @property def calculable(self): """Check if inputs are enough to define state""" self._mode = "" if self.kwargs["T"] and self.kwargs["P"]: self._mode = "TP" elif self.kwargs["T"] and self.kwargs["rho"]: self._mode = "Trho" elif self.kwargs["T"] and self.kwargs["h"] is not None: self._mode = "Th" elif self.kwargs["T"] and self.kwargs["s"] is not None: self._mode = "Ts" elif self.kwargs["T"] and self.kwargs["u"] is not None: self._mode = "Tu" elif self.kwargs["P"] and self.kwargs["rho"]: self._mode = "Prho" elif self.kwargs["P"] and self.kwargs["h"] is not None: self._mode = "Ph" elif self.kwargs["P"] and self.kwargs["s"] is not None: self._mode = "Ps" elif self.kwargs["P"] and self.kwargs["u"] is not None: self._mode = "Pu" elif self.kwargs["rho"] and self.kwargs["h"] is not None: self._mode = "rhoh" elif self.kwargs["rho"] and self.kwargs["s"] is not None: self._mode = "rhos" elif self.kwargs["rho"] and self.kwargs["u"] is not None: self._mode = "rhou" elif self.kwargs["h"] is not None and self.kwargs["s"] is not None: self._mode = "hs" elif self.kwargs["h"] is not None and self.kwargs["u"] is not None: self._mode = "hu" elif self.kwargs["s"] is not None and self.kwargs["u"] is not None: self._mode = "su" elif self.kwargs["T"] and self.kwargs["x"] is not None: self._mode = "Tx" elif self.kwargs["P"] and self.kwargs["x"] is not None: self._mode = "Px" return bool(self._mode) def calculo(self): """Calculate procedure""" T = self.kwargs["T"] rho = self.kwargs["rho"] P = self.kwargs["P"] s = self.kwargs["s"] h = self.kwargs["h"] u = self.kwargs["u"] x = self.kwargs["x"] # Initial values T0 = self.kwargs["T0"] rho0 = self.kwargs["rho0"] if T0 or rho0: To = T0 rhoo = rho0 elif self.name == "air": To = 300 rhoo = 1e-3 else: try: st0 = IAPWS97(**self.kwargs) except NotImplementedError: To = 300 rhoo = 900 else: if st0.status: To = st0.T rhoo = st0.rho else: To = 300 rhoo = 900 self.R = self._constants["R"]/self._constants.get("M", self.M) rho_c = self._constants.get("rhoref", self.rhoc) T_c = self._constants.get("Tref", self.Tc) propiedades = None if self._mode not in ("Tx", "Px"): # Method with iteration necessary to get x if self._mode == "TP": try: if self.name != "water": raise NotImplementedError st0 = IAPWS97(**self.kwargs) rhoo = st0.rho except NotImplementedError: if rho0: rhoo = rho0 elif T < self.Tc and \ self._Vapor_Pressure(T) < P < self.Pc: rhoo = self._Liquid_Density(T) elif T < self.Tc and P < self.Pc: rhoo = self._Vapor_Density(T) else: rhoo = self.rhoc*3 def f(rho): delta = rho/rho_c tau = T_c/T fird = _phird(tau, delta, self._constants) Po = (1+delta*fird)*self.R*T*rho return Po-P*1000 rho = fsolve(f, rhoo)[0] # Calculate quality if T > self.Tc: x = 1 else: Ps = self._Vapor_Pressure(T) if Ps*0.95 < P < Ps*1.05: rhol, rhov, Ps = self._saturation(T) Ps *= 1e-3 if Ps > P: x = 1 else: x = 0 elif self._mode == "Th": tau = T_c/T ideal = self._phi0(tau, 1) fiot = ideal["fiot"] def f(rho): delta = rho/rho_c fird = _phird(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return ho-h if T >= self.Tc: rhoo = self.rhoc rho = fsolve(f, rhoo)[0] else: x0 = self.kwargs["x0"] rhov = self._Vapor_Density(T) rhol = self._Liquid_Density(T) deltaL = rhol/rho_c deltaG = rhov/rho_c firdL = _phird(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) firdG = _phird(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) hl = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) hv = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) if x0 not in (0, 1) and hl <= h <= hv: rhol, rhov, Ps = self._saturation(T) vapor = self._Helmholtz(rhov, T) liquido = self._Helmholtz(rhol, T) hv = vapor["h"] hl = liquido["h"] x = (h-hl)/(hv-hl) rho = 1/(x/rhov+(1-x)/rhol) P = Ps/1000 else: if h > hv: rhoo = rhov else: rhoo = rhol rho = fsolve(f, rhoo)[0] elif self._mode == "Ts": tau = T_c/T def f(rho): if rho < 0: rho = 1e-20 delta = rho/rho_c ideal = self._phi0(tau, delta) fio = ideal["fio"] fiot = ideal["fiot"] fir = _phir(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) so = self.R*(tau*(fiot+firt)-fio-fir) return so-s if T >= self.Tc: rhoo = self.rhoc rho = fsolve(f, rhoo)[0] else: rhov = self._Vapor_Density(T) rhol = self._Liquid_Density(T) deltaL = rhol/rho_c deltaG = rhov/rho_c idealL = self._phi0(tau, deltaL) idealG = self._phi0(tau, deltaG) fioL = idealL["fio"] fioG = idealG["fio"] fiot = idealL["fiot"] firL = _phir(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) sl = self.R*(tau*(fiot+firtL)-fioL-firL) firG = _phir(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) sv = self.R*(tau*(fiot+firtG)-fioG-firG) if sl <= s <= sv: rhol, rhov, Ps = self._saturation(T) vapor = self._Helmholtz(rhov, T) liquido = self._Helmholtz(rhol, T) sv = vapor["s"] sl = liquido["s"] x = (s-sl)/(sv-sl) rho = 1/(x/rhov+(1-x)/rhol) P = Ps/1000 else: if s > sv: rhoo = rhov else: rhoo = rhol rho = fsolve(f, rhoo)[0] elif self._mode == "Tu": tau = T_c/T ideal = self._phi0(tau, 1) fiot = ideal["fiot"] def f(rho): delta = rho/rho_c fird = _phird(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) Po = (1+delta*fird)*self.R*T*rho ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return ho-Po/rho-u if T >= self.Tc: rhoo = self.rhoc rho = fsolve(f, rhoo)[0] else: rhov = self._Vapor_Density(T) rhol = self._Liquid_Density(T) deltaL = rhol/rho_c deltaG = rhov/rho_c firdL = _phird(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) firdG = _phird(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) PoL = (1+deltaL*firdL)*self.R*T*rhol PoG = (1+deltaG*firdG)*self.R*T*rhov hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) uv = hoG-PoG/rhov ul = hoL-PoL/rhol if ul <= u <= uv: rhol, rhov, Ps = self._saturation(T) vapor = self._Helmholtz(rhov, T) liquido = self._Helmholtz(rhol, T) uv = vapor["h"]-vapor["P"]/rhov ul = liquido["h"]-liquido["P"]/rhol x = (u-ul)/(uv-ul) rho = 1/(x/rhov-(1-x)/rhol) P = Ps/1000 else: if u > uv: rhoo = rhov else: rhoo = rhol rho = fsolve(f, rhoo)[0] elif self._mode == "Prho": delta = rho/rho_c def f(T): tau = T_c/T fird = _phird(tau, delta, self._constants) Po = (1+delta*fird)*self.R*T*rho return Po-P*1000 T = fsolve(f, To)[0] rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if T == To or rhov <= rho <= rhol: def f(parr): T, rhol, rhog = parr tau = T_c/T deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc firL = _phir(tau, deltaL, self._constants) firdL = _phird(tau, deltaL, self._constants) firG = _phir(tau, deltaG, self._constants) firdG = _phird(tau, deltaG, self._constants) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) return (Jl-Jv, Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, Ps - P*1000) for to in [To, 300, 400, 500, 600]: rhoLo = self._Liquid_Density(to) rhoGo = self._Vapor_Density(to) sol = fsolve(f, [to, rhoLo, rhoGo], full_output=True) T, rhoL, rhoG = sol[0] x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: break if sum(abs(sol[1]["fvec"])) > 1e-5: raise RuntimeError(sol[3]) liquido = self._Helmholtz(rhoL, T) vapor = self._Helmholtz(rhoG, T) P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 elif self._mode == "Ph": def funcion(parr): rho, T = parr delta = rho/rho_c tau = T_c/T ideal = self._phi0(tau, delta) fiot = ideal["fiot"] fird = _phird(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) Po = (1+delta*fird)*self.R*T*rho ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return Po-P*1000, ho-h rho, T = fsolve(funcion, [rhoo, To]) rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if rho == rhoo or rhov <= rho <= rhol: def f(parr): T, rhol, rhog, x = parr tau = T_c/T deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc ideal = self._phi0(tau, deltaL) fiot = ideal["fiot"] firL = _phir(tau, deltaL, self._constants) firdL = _phird(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) firG = _phir(tau, deltaG, self._constants) firdG = _phird(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) return (Jl-Jv, Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, hoL*(1-x)+hoG*x - h, Ps - P*1000) for to in [To, 300, 400, 500, 600]: rLo = self._Liquid_Density(to) rGo = self._Vapor_Density(to) sol = fsolve(f, [to, rLo, rGo, 0.5], full_output=True) T, rhoL, rhoG, x = sol[0] if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: break if sum(abs(sol[1]["fvec"])) > 1e-5: raise RuntimeError(sol[3]) liquido = self._Helmholtz(rhoL, T) vapor = self._Helmholtz(rhoG, T) P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 elif self._mode == "Ps": try: x0 = st0.x except NameError: x0 = None if x0 is None or x0 == 0 or x0 == 1: def f(parr): rho, T = parr delta = rho/rho_c tau = T_c/T ideal = self._phi0(tau, delta) fio = ideal["fio"] fiot = ideal["fiot"] fird = _phird(tau, delta, self._constants) fir = _phir(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) Po = (1+delta*fird)*self.R*T*rho so = self.R*(tau*(fiot+firt)-fio-fir) return Po-P*1000, so-s rho, T = fsolve(f, [rhoo, To]) else: def funcion(parr): rho, T = parr rhol, rhov, Ps = self._saturation(T) vapor = self._Helmholtz(rhov, T) liquido = self._Helmholtz(rhol, T) x = (1./rho-1/rhol)/(1/rhov-1/rhol) return Ps-P*1000, vapor["s"]*x+liquido["s"]*(1-x)-s rho, T = fsolve(funcion, [2., 500.]) rhol, rhov, Ps = self._saturation(T) vapor = self._Helmholtz(rhov, T) liquido = self._Helmholtz(rhol, T) sv = vapor["s"] sl = liquido["s"] x = (s-sl)/(sv-sl) elif self._mode == "Pu": def f(parr): rho, T = parr delta = rho/rho_c tau = T_c/T ideal = self._phi0(tau, delta) fiot = ideal["fiot"] fird = _phird(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) Po = (1+delta*fird)*self.R*T*rho ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return ho-Po/rho-u, Po-P*1000 sol = fsolve(f, [rhoo, To], full_output=True) rho, T = sol[0] rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if rho == rhoo or sol[2] != 1: def f(parr): T, rhol, rhog, x = parr tau = T_c/T deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc ideal = self._phi0(tau, deltaL) fiot = ideal["fiot"] firL = _phir(tau, deltaL, self._constants) firdL = _phird(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) firG = _phir(tau, deltaG, self._constants) firdG = _phird(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) vu = hoG-Ps/rhog lu = hoL-Ps/rhol return (Jl-Jv, Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, lu*(1-x)+vu*x - u, Ps - P*1000) for to in [To, 300, 400, 500, 600]: rLo = self._Liquid_Density(to) rGo = self._Vapor_Density(to) sol = fsolve(f, [to, rLo, rGo, 0.5], full_output=True) T, rhoL, rhoG, x = sol[0] if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: break if sum(abs(sol[1]["fvec"])) > 1e-5: raise RuntimeError(sol[3]) liquido = self._Helmholtz(rhoL, T) vapor = self._Helmholtz(rhoG, T) P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 elif self._mode == "rhoh": delta = rho/rho_c def f(T): tau = T_c/T ideal = self._phi0(tau, delta) fiot = ideal["fiot"] fird = _phird(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return ho-h T = fsolve(f, To)[0] rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if T == To or rhov <= rho <= rhol: def f(parr): T, rhol, rhog = parr tau = T_c/T deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc ideal = self._phi0(tau, deltaL) fiot = ideal["fiot"] firL = _phir(tau, deltaL, self._constants) firdL = _phird(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) firG = _phir(tau, deltaG, self._constants) firdG = _phird(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG x = (1./rho-1/rhol)/(1/rhog-1/rhol) return (Jl-Jv, Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, hoL*(1-x)+hoG*x - h) for to in [To, 300, 400, 500, 600]: rhoLo = self._Liquid_Density(to) rhoGo = self._Vapor_Density(to) sol = fsolve(f, [to, rhoLo, rhoGo], full_output=True) T, rhoL, rhoG = sol[0] x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: break if sum(abs(sol[1]["fvec"])) > 1e-5: raise RuntimeError(sol[3]) liquido = self._Helmholtz(rhoL, T) vapor = self._Helmholtz(rhoG, T) P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 elif self._mode == "rhos": delta = rho/rho_c def f(T): tau = T_c/T ideal = self._phi0(tau, delta) fio = ideal["fio"] fiot = ideal["fiot"] fir = _phir(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) so = self.R*(tau*(fiot+firt)-fio-fir) return so-s T = fsolve(f, To)[0] rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if T == To or rhov <= rho <= rhol: def f(parr): T, rhol, rhog = parr tau = T_c/T deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc idealL = self._phi0(tau, deltaL) fioL = idealL["fio"] fiot = idealL["fiot"] idealG = self._phi0(tau, deltaG) fioG = idealG["fio"] firL = _phir(tau, deltaL, self._constants) firdL = _phird(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) soL = self.R*(tau*(fiot+firtL)-fioL-firL) firG = _phir(tau, deltaG, self._constants) firdG = _phird(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) soG = self.R*(tau*(fiot+firtG)-fioG-firG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG x = (1./rho-1/rhol)/(1/rhog-1/rhol) return (Jl-Jv, Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, soL*(1-x)+soG*x - s) for to in [To, 300, 400, 500, 600]: rhoLo = self._Liquid_Density(to) rhoGo = self._Vapor_Density(to) sol = fsolve(f, [to, rhoLo, rhoGo], full_output=True) T, rhoL, rhoG = sol[0] x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: break if sum(abs(sol[1]["fvec"])) > 1e-5: raise RuntimeError(sol[3]) liquido = self._Helmholtz(rhoL, T) vapor = self._Helmholtz(rhoG, T) P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 elif self._mode == "rhou": delta = rho/rho_c def f(T): tau = T_c/T ideal = self._phi0(tau, delta) fiot = ideal["fiot"] fird = _phird(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) Po = (1+delta*fird)*self.R*T*rho ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return ho-Po/rho-u T = fsolve(f, To)[0] rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if T == To or rhov <= rho <= rhol: def f(parr): T, rhol, rhog = parr tau = T_c/T deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc ideal = self._phi0(tau, deltaL) fiot = ideal["fiot"] firL = _phir(tau, deltaL, self._constants) firdL = _phird(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) firG = _phir(tau, deltaG, self._constants) firdG = _phird(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG x = (1./rho-1/rhol)/(1/rhog-1/rhol) Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) vu = hoG-Ps/rhog lu = hoL-Ps/rhol return (Jl-Jv, Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, lu*(1-x)+vu*x - u) for to in [To, 300, 400, 500, 600]: rhoLo = self._Liquid_Density(to) rhoGo = self._Vapor_Density(to) sol = fsolve(f, [to, rhoLo, rhoGo], full_output=True) T, rhoL, rhoG = sol[0] x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: break if sum(abs(sol[1]["fvec"])) > 1e-5: raise RuntimeError(sol[3]) liquido = self._Helmholtz(rhoL, T) vapor = self._Helmholtz(rhoG, T) P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 elif self._mode == "hs": def f(parr): rho, T = parr delta = rho/rho_c tau = T_c/T ideal = self._phi0(tau, delta) fio = ideal["fio"] fiot = ideal["fiot"] fird = _phird(tau, delta, self._constants) fir = _phir(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) so = self.R*(tau*(fiot+firt)-fio-fir) return ho-h, so-s rho, T = fsolve(f, [rhoo, To]) rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if rhov <= rho <= rhol: def f(parr): T, rhol, rhog, x = parr tau = T_c/T deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc idealL = self._phi0(tau, deltaL) fiot = idealL["fiot"] fioL = idealL["fio"] idealG = self._phi0(tau, deltaG) fioG = idealG["fio"] firL = _phir(tau, deltaL, self._constants) firdL = _phird(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) soL = self.R*(tau*(fiot+firtL)-fioL-firL) firG = _phir(tau, deltaG, self._constants) firdG = _phird(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) soG = self.R*(tau*(fiot+firtG)-fioG-firG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG return (Jl-Jv, Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, hoL*(1-x)+hoG*x - h, soL*(1-x)+soG*x - s) for to in [To, 300, 400, 500, 600]: rLo = self._Liquid_Density(to) rGo = self._Vapor_Density(to) sol = fsolve(f, [to, rLo, rGo, 0.5], full_output=True) T, rhoL, rhoG, x = sol[0] if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: break if sum(abs(sol[1]["fvec"])) > 1e-5: raise RuntimeError(sol[3]) liquido = self._Helmholtz(rhoL, T) vapor = self._Helmholtz(rhoG, T) P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 elif self._mode == "hu": def f(parr): rho, T = parr delta = rho/rho_c tau = T_c/T ideal = self._phi0(tau, delta) fiot = ideal["fiot"] fird = _phird(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) Po = (1+delta*fird)*self.R*T*rho ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return ho-Po/rho-u, ho-h sol = fsolve(f, [rhoo, To], full_output=True) rho, T = sol[0] rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if sol[2] != 1 or rhov <= rho <= rhol: def f(parr): T, rhol, rhog, x = parr tau = T_c/T deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc ideal = self._phi0(tau, deltaL) fiot = ideal["fiot"] firL = _phir(tau, deltaL, self._constants) firdL = _phird(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) firG = _phir(tau, deltaG, self._constants) firdG = _phird(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) vu = hoG-Ps/rhog lu = hoL-Ps/rhol return (Jl-Jv, Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, hoL*(1-x)+hoG*x - h, lu*(1-x)+vu*x - u) for to in [To, 300, 400, 500, 600]: rLo = self._Liquid_Density(to) rGo = self._Vapor_Density(to) sol = fsolve(f, [to, rLo, rGo, 0.5], full_output=True) T, rhoL, rhoG, x = sol[0] if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: break if sum(abs(sol[1]["fvec"])) > 1e-5: raise RuntimeError(sol[3]) liquido = self._Helmholtz(rhoL, T) vapor = self._Helmholtz(rhoG, T) P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 elif self._mode == "su": def f(parr): rho, T = parr delta = rho/rho_c tau = T_c/T ideal = self._phi0(tau, delta) fio = ideal["fio"] fiot = ideal["fiot"] fird = _phird(tau, delta, self._constants) fir = _phir(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) so = self.R*(tau*(fiot+firt)-fio-fir) Po = (1+delta*fird)*self.R*T*rho return ho-Po/rho-u, so-s sol = fsolve(f, [rhoo, To], full_output=True) rho, T = sol[0] rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if sol[2] != 1 or rhov <= rho <= rhol: def f(parr): T, rhol, rhog, x = parr tau = T_c/T deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc idealL = self._phi0(tau, deltaL) fiot = idealL["fiot"] fioL = idealL["fio"] idealG = self._phi0(tau, deltaG) fioG = idealG["fio"] firL = _phir(tau, deltaL, self._constants) firdL = _phird(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) soL = self.R*(tau*(fiot+firtL)-fioL-firL) firG = _phir(tau, deltaG, self._constants) firdG = _phird(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) soG = self.R*(tau*(fiot+firtG)-fioG-firG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) vu = hoG-Ps/rhog lu = hoL-Ps/rhol return (Jl-Jv, Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, soL*(1-x)+soG*x - s, lu*(1-x)+vu*x - u) for to in [To, 300, 400, 500, 600]: rLo = self._Liquid_Density(to) rGo = self._Vapor_Density(to) sol = fsolve(f, [to, rLo, rGo, 0.5], full_output=True) T, rhoL, rhoG, x = sol[0] if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: break if sum(abs(sol[1]["fvec"])) > 1e-5: raise RuntimeError(sol[3]) liquido = self._Helmholtz(rhoL, T) vapor = self._Helmholtz(rhoG, T) P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 elif self._mode == "Trho": if T < self.Tc: rhov = self._Vapor_Density(T) rhol = self._Liquid_Density(T) if rhol > rho > rhov: rhol, rhov, Ps = self._saturation(T) if rhol > rho > rhov: vapor = self._Helmholtz(rhov, T) liquido = self._Helmholtz(rhol, T) x = (1/rho-1/rhol)/(1/rhov-1/rhol) P = Ps/1000 rho = float(rho) T = float(T) propiedades = self._Helmholtz(rho, T) if T > self.Tc: x = 1 elif x is None: x = 0 if not P: P = propiedades["P"]/1000. elif self._mode == "Tx": # Check input T in saturation range if self.Tt > T or self.Tc < T or x > 1 or x < 0: raise NotImplementedError("Incoming out of bound") rhol, rhov, Ps = self._saturation(T) vapor = self._Helmholtz(rhov, T) liquido = self._Helmholtz(rhol, T) if x == 0: propiedades = liquido elif x == 1: propiedades = vapor P = Ps/1000. elif self._mode == "Px": # Check input P in saturation range if self.Pc < P or x > 1 or x < 0: raise NotImplementedError("Incoming out of bound") # Iterate over saturation routine to get T def f(T): rhol = self._Liquid_Density(T) rhog = self._Vapor_Density(T) deltaL = rhol/self.rhoc deltaG = rhog/self.rhoc tau = T_c/T firL = _phir(tau, deltaL, self._constants) firG = _phir(tau, deltaG, self._constants) Ps = self.R*T*rhol*rhog/(rhol-rhog)*( firL-firG+log(deltaL/deltaG)) return Ps/1000-P if T0: To = T0 elif self.name == "water": To = _TSat_P(P) else: To = (self.Tc+self.Tt)/2 T = fsolve(f, To)[0] rhol, rhov, Ps = self._saturation(T) vapor = self._Helmholtz(rhov, T) liquido = self._Helmholtz(rhol, T) if x == 0: propiedades = liquido elif x == 1: propiedades = vapor self.T = T self.Tr = T/self.Tc self.P = P self.Pr = self.P/self.Pc self.x = x if self._mode in ["Tx", "Px"] or 0 < x < 1: region = 4 else: region = 0 self.phase = getphase(self.Tc, self.Pc, self.T, self.P, self.x, region) if 0 < x < 1: rho = vapor["rho"] else: rho = propiedades["rho"] self.Liquid = _fase() self.Gas = _fase() self.Vapor = self.Gas if x == 0: # liquid phase self.fill(self.Liquid, propiedades) self.fill(self, propiedades) elif x == 1: # vapor phase self.fill(self.Gas, propiedades) self.fill(self, propiedades) else: self.fill(self.Liquid, liquido) self.fill(self.Gas, vapor) self.v = x*self.Gas.v+(1-x)*self.Liquid.v self.rho = 1./self.v self.h = x*self.Gas.h+(1-x)*self.Liquid.h self.s = x*self.Gas.s+(1-x)*self.Liquid.s self.u = x*self.Gas.u+(1-x)*self.Liquid.u self.a = x*self.Gas.a+(1-x)*self.Liquid.a self.g = x*self.Gas.g+(1-x)*self.Liquid.g self.Z = x*self.Gas.Z+(1-x)*self.Liquid.Z self.f = x*self.Gas.f+(1-x)*self.Liquid.f self.Z_rho = x*self.Gas.Z_rho+(1-x)*self.Liquid.Z_rho self.IntP = x*self.Gas.IntP+(1-x)*self.Liquid.IntP # Calculate special properties useful only for one phase if self._mode in ("Px", "Tx") or (x < 1 and self.Tt <= T <= self.Tc): self.sigma = self._surface(T) else: self.sigma = None vir = self._virial(T) self.virialB = vir["B"]/self.rhoc self.virialC = vir["C"]/self.rhoc**2 if 0 < x < 1: self.Hvap = vapor["h"]-liquido["h"] self.Svap = vapor["s"]-liquido["s"] else: self.Hvap = None self.Svap = None self.invT = -1/self.T # Ideal properties self.v0 = self.R*self.T/self.P/1000 self.rho0 = 1./self.v0 cp0 = self._prop0(self.rho0, self.T) self.h0 = cp0.h self.u0 = self.h0-self.P*self.v0 self.s0 = cp0.s self.a0 = self.u0-self.T*self.s0 self.g0 = self.h0-self.T*self.s0 self.cp0 = cp0.cp self.cv0 = cp0.cv self.cp0_cv = self.cp0/self.cv0 cp0.v = self.v0 self.gamma0 = -self.v0/self.P/1000*self.derivative("P", "v", "s", cp0) def fill(self, fase, estado): """Fill phase properties""" fase.rho = estado["rho"] fase.v = 1/fase.rho fase.h = estado["h"] fase.s = estado["s"] fase.u = fase.h-self.P*1000*fase.v fase.a = fase.u-self.T*fase.s fase.g = fase.h-self.T*fase.s fase.Z = self.P*fase.v/self.T/self.R*1e3 if 1+estado["delta"]*estado["fird"] > 0: fase.fi = exp(estado["fir"]+estado["delta"]*estado["fird"] - log(1+estado["delta"]*estado["fird"])) else: fase.fi = 0 fase.f = fase.fi*self.P fase.cv = estado["cv"] fase.rhoM = fase.rho/self.M fase.hM = fase.h*self.M fase.sM = fase.s*self.M fase.uM = fase.u*self.M fase.aM = fase.a*self.M fase.gM = fase.g*self.M fase.alfap = estado["alfap"] fase.betap = estado["betap"] fase.cp = self.derivative("h", "T", "P", fase) fase.cp_cv = fase.cp/fase.cv w = self.derivative("P", "rho", "s", fase)*1000 if w >= 0: fase.w = w**0.5 else: w = None fase.cvM = fase.cv*self.M fase.cpM = fase.cp*self.M fase.joule = self.derivative("T", "P", "h", fase)*1e3 fase.Gruneisen = fase.v/fase.cv*self.derivative("P", "T", "v", fase) fase.alfav = self.derivative("v", "T", "P", fase)/fase.v fase.kappa = -self.derivative("v", "P", "T", fase)/fase.v*1e3 fase.betas = self.derivative("T", "P", "s", fase) fase.gamma = -fase.v/self.P \ * self.derivative("P", "v", "T", fase)*fase.cp_cv*1e-3 fase.kt = -fase.v/self.P*self.derivative("P", "v", "T", fase)*1e-3 fase.ks = -self.derivative("v", "P", "s", fase)/fase.v*1e3 fase.Kt = -fase.v*self.derivative("P", "v", "s", fase)*1e-3 fase.Ks = -fase.v*self.derivative("P", "v", "T", fase)*1e-3 fase.dhdT_rho = self.derivative("h", "T", "rho", fase) fase.dhdT_P = self.derivative("h", "T", "P", fase) fase.dhdP_T = self.derivative("h", "P", "T", fase)*1e3 fase.dhdP_rho = self.derivative("h", "P", "rho", fase)*1e3 fase.dhdrho_T = self.derivative("h", "rho", "T", fase) fase.dhdrho_P = self.derivative("h", "rho", "P", fase) fase.dpdT_rho = self.derivative("P", "T", "rho", fase)*1e-3 fase.dpdrho_T = self.derivative("P", "rho", "T", fase)*1e-3 fase.drhodP_T = self.derivative("rho", "P", "T", fase)*1e3 fase.drhodT_P = self.derivative("rho", "T", "P", fase) fase.Z_rho = (fase.Z-1)/fase.rho fase.IntP = self.T*self.derivative("P", "T", "rho", fase)*1e-3-self.P fase.hInput = fase.v*self.derivative("h", "v", "P", fase) fase.mu = self._visco(fase.rho, self.T, fase) fase.k = self._thermo(fase.rho, self.T, fase) fase.nu = fase.mu/fase.rho fase.alfa = fase.k/1000/fase.rho/fase.cp fase.Prandt = fase.mu*fase.cp*1000/fase.k if self.name == "water": try: fase.epsilon = _Dielectric(fase.rho, self.T) except NotImplementedError: fase.epsilon = None try: fase.n = _Refractive(fase.rho, self.T, self.kwargs["l"]) except NotImplementedError: fase.n = None else: fase.epsilon = None fase.n = None def derivative(self, z, x, y, fase): """ Wrapper derivative for custom derived properties where x, y, z can be: P, T, v, rho, u, h, s, g, a """ return deriv_H(self, z, x, y, fase) def _saturation(self, T): """Saturation calculation for two phase search""" # Added support for superancillary equation to try speed up saturation # iteration # Using generated data from https://github.com/usnistgov/fastchebpure Ps, rhoL, rhoG = None, None, None anc_file = os.path.join( os.path.dirname(__file__), "%s_anc.json" %self.__class__.__name__) if os.path.isfile(anc_file): with open(anc_file) as anc_file: dat = json.load(anc_file) for coefs in dat["jexpansions_p"]: coef = coefs["coef"] xmin = coefs["xmin"] xmax = coefs["xmax"] if xmin <= T <= xmax: c = chebyshev.Chebyshev(coef, domain=(xmin, xmax)) Ps = c(T)/1e3 break for coefs in dat["jexpansions_rhoL"]: coef = coefs["coef"] xmin = coefs["xmin"] xmax = coefs["xmax"] if xmin <= T <= xmax: c = chebyshev.Chebyshev(coef, domain=(xmin, xmax)) rhoL = c(T)*self.M/1e3 break for coefs in dat["jexpansions_rhoV"]: coef = coefs["coef"] xmin = coefs["xmin"] xmax = coefs["xmax"] if xmin <= T <= xmax: c = chebyshev.Chebyshev(coef, domain=(xmin, xmax)) rhoG = c(T)*self.M/1e3 break if Ps is None: rho_c = self._constants.get("rhoref", self.rhoc) T_c = self._constants.get("Tref", self.Tc) T = min(T, T_c) tau = T_c/T rhoLo = self._Liquid_Density(T) rhoGo = self._Vapor_Density(T) def f(parr): rhol, rhog = parr deltaL = rhol/rho_c deltaG = rhog/rho_c phirL = _phir(tau, deltaL, self._constants) phirG = _phir(tau, deltaG, self._constants) phirdL = _phird(tau, deltaL, self._constants) phirdG = _phird(tau, deltaG, self._constants) Jl = deltaL*(1+deltaL*phirdL) Jv = deltaG*(1+deltaG*phirdG) Kl = deltaL*phirdL+phirL+log(deltaL) Kv = deltaG*phirdG+phirG+log(deltaG) return Kv-Kl, Jv-Jl rhoL, rhoG = fsolve(f, [rhoLo, rhoGo]) if rhoL == rhoG: Ps = self.Pc*1e3 else: deltaL = rhoL/self.rhoc deltaG = rhoG/self.rhoc firL = _phir(tau, deltaL, self._constants) firG = _phir(tau, deltaG, self._constants) Ps = self.R*T*rhoL*rhoG/(rhoL-rhoG)*(firL-firG+log(deltaL/deltaG)) # print(rhoL, rhoG, Ps) return rhoL, rhoG, Ps def _Helmholtz(self, rho, T): """Calculated properties from helmholtz free energy and derivatives Parameters ---------- rho : float Density, [kg/m³] T : float Temperature, [K] Returns ------- prop : dict Dictionary with calculated properties: * fir: [-] * fird: ∂fir/∂δ|τ * firdd: ∂²fir/∂δ²|τ * delta: Reducen density rho/rhoc, [-] * P: Pressure, [kPa] * h: Enthalpy, [kJ/kg] * s: Entropy, [kJ/kgK] * cv: Isochoric specific heat, [kJ/kgK] * alfav: Thermal expansion coefficient, [1/K] * betap: Isothermal compressibility, [1/kPa] References ---------- IAPWS, Revised Release on the IAPWS Formulation 1995 for the Thermodynamic Properties of Ordinary Water Substance for General and Scientific Use, September 2016, Table 3 http://www.iapws.org/relguide/IAPWS-95.html """ if isinstance(rho, ndarray): rho = rho[0] if isinstance(T, ndarray): T = T[0] if rho < 0: rho = 1e-20 T = max(T, 50) rho_c = self._constants.get("rhoref", self.rhoc) T_c = self._constants.get("Tref", self.Tc) delta = rho/rho_c tau = T_c/T ideal = self._phi0(tau, delta) fio = ideal["fio"] fiot = ideal["fiot"] fiott = ideal["fiott"] res = self._phir(tau, delta) fir = res["fir"] firt = res["firt"] firtt = res["firtt"] fird = res["fird"] firdd = res["firdd"] firdt = res["firdt"] propiedades = {} propiedades["fir"] = fir propiedades["fird"] = fird propiedades["firdd"] = firdd propiedades["delta"] = delta propiedades["rho"] = rho propiedades["P"] = (1+delta*fird)*self.R*T*rho propiedades["h"] = self.R*T*(1+tau*(fiot+firt)+delta*fird) propiedades["s"] = self.R*(tau*(fiot+firt)-fio-fir) propiedades["cv"] = -self.R*tau**2*(fiott+firtt) propiedades["alfap"] = (1-delta*tau*firdt/(1+delta*fird))/T propiedades["betap"] = rho*( 1+(delta*fird+delta**2*firdd)/(1+delta*fird)) return propiedades def _prop0(self, rho, T): """Ideal gas properties""" rho_c = self._constants.get("rhoref", self.rhoc) T_c = self._constants.get("Tref", self.Tc) delta = rho/rho_c tau = T_c/T ideal = self._phi0(tau, delta) fio = ideal["fio"] fiot = ideal["fiot"] fiott = ideal["fiott"] propiedades = _fase() propiedades.h = self.R*T*(1+tau*fiot) propiedades.s = self.R*(tau*fiot-fio) propiedades.cv = -self.R*tau**2*fiott propiedades.cp = self.R*(-tau**2*fiott+1) propiedades.alfap = 1/T propiedades.betap = rho return propiedades def _phi0(self, tau, delta): """Ideal gas Helmholtz free energy and derivatives Parameters ---------- tau : float Inverse reduced temperature Tc/T, [-] delta : float Reduced density rho/rhoc, [-] Returns ------- prop : dictionary with ideal adimensional helmholtz energy and deriv fio, [-] fiot: ∂fio/∂τ|δ fiod: ∂fio/∂δ|τ fiott: ∂²fio/∂τ²|δ fiodt: ∂²fio/∂τ∂δ fiodd: ∂²fio/∂δ²|τ References ---------- IAPWS, Revised Release on the IAPWS Formulation 1995 for the Thermodynamic Properties of Ordinary Water Substance for General and Scientific Use, September 2016, Table 4 http://www.iapws.org/relguide/IAPWS-95.html """ Fi0 = self.Fi0 if tau <= 0: fio = 0 fiot = 0 fiott = 0 else: if delta <= 0: fio = 0 else: fio = Fi0["ao_log"][0]*log(delta)+Fi0["ao_log"][1]*log(tau) fiot = +Fi0["ao_log"][1]/tau fiott = -Fi0["ao_log"][1]/tau**2 fiod = 1/delta fiodd = -1/delta**2 fiodt = 0 for n, t in zip(Fi0["ao_pow"], Fi0["pow"]): fio += n*tau**t if t != 0: fiot += t*n*tau**(t-1) if t not in [0, 1]: fiott += n*t*(t-1)*tau**(t-2) for n, t in zip(Fi0["ao_exp"], Fi0["titao"]): fio += n*log(1-exp(-tau*t)) fiot += n*t*((1-exp(-t*tau))**-1-1) fiott -= n*t**2*exp(-t*tau)*(1-exp(-t*tau))**-2 # Extension to especial terms of air if "ao_exp2" in Fi0: for n, g, C in zip(Fi0["ao_exp2"], Fi0["titao2"], Fi0["sum2"]): fio += n*log(C+exp(g*tau)) fiot += n*g/(C*exp(-g*tau)+1) fiott += C*n*g**2*exp(-g*tau)/(C*exp(-g*tau)+1)**2 prop = {} prop["fio"] = fio prop["fiot"] = fiot prop["fiott"] = fiott prop["fiod"] = fiod prop["fiodd"] = fiodd prop["fiodt"] = fiodt return prop def _phir(self, tau, delta): """Residual contribution to the free Helmholtz energy Parameters ---------- tau : float Inverse reduced temperature Tc/T, [-] delta : float Reduced density rho/rhoc, [-] Returns ------- prop : dict Dictionary with residual adimensional helmholtz energy and deriv: * fir * firt: ∂fir/∂τ|δ,x * fird: ∂fir/∂δ|τ,x * firtt: ∂²fir/∂τ²|δ,x * firdt: ∂²fir/∂τ∂δ|x * firdd: ∂²fir/∂δ²|τ,x References ---------- IAPWS, Revised Release on the IAPWS Formulation 1995 for the Thermodynamic Properties of Ordinary Water Substance for General and Scientific Use, September 2016, Table 5 http://www.iapws.org/relguide/IAPWS-95.html """ fir = fird = firdd = firt = firtt = firdt = 0 # Polinomial terms nr1 = self._constants.get("nr1", []) d1 = self._constants.get("d1", []) t1 = self._constants.get("t1", []) for n, d, t in zip(nr1, d1, t1): fir += n*delta**d*tau**t fird += n*d*delta**(d-1)*tau**t firdd += n*d*(d-1)*delta**(d-2)*tau**t firt += n*t*delta**d*tau**(t-1) firtt += n*t*(t-1)*delta**d*tau**(t-2) firdt += n*t*d*delta**(d-1)*tau**(t-1) # Exponential terms nr2 = self._constants.get("nr2", []) d2 = self._constants.get("d2", []) g2 = self._constants.get("gamma2", []) t2 = self._constants.get("t2", []) c2 = self._constants.get("c2", []) for n, d, g, t, c in zip(nr2, d2, g2, t2, c2): fir += n*delta**d*tau**t*exp(-g*delta**c) fird += n*exp(-g*delta**c)*delta**(d-1)*tau**t*(d-g*c*delta**c) firdd += n*exp(-g*delta**c)*delta**(d-2)*tau**t * \ ((d-g*c*delta**c)*(d-1-g*c*delta**c)-g**2*c**2*delta**c) firt += n*t*delta**d*tau**(t-1)*exp(-g*delta**c) firtt += n*t*(t-1)*delta**d*tau**(t-2)*exp(-g*delta**c) firdt += n*t*delta**(d-1)*tau**(t-1)*(d-g*c*delta**c)*exp( -g*delta**c) # Gaussian terms nr3 = self._constants.get("nr3", []) d3 = self._constants.get("d3", []) t3 = self._constants.get("t3", []) a3 = self._constants.get("alfa3", []) e3 = self._constants.get("epsilon3", []) b3 = self._constants.get("beta3", []) g3 = self._constants.get("gamma3", []) for n, d, t, a, e, b, g in zip(nr3, d3, t3, a3, e3, b3, g3): fir += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2) fird += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( d/delta-2*a*(delta-e)) firdd += n*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( -2*a*delta**d + 4*a**2*delta**d*(delta-e)**2 - 4*d*a*delta**(d-1)*(delta-e) + d*(d-1)*delta**(d-2)) firt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( t/tau-2*b*(tau-g)) firtt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( (t/tau-2*b*(tau-g))**2-t/tau**2-2*b) firdt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( t/tau-2*b*(tau-g))*(d/delta-2*a*(delta-e)) # Non analitic terms nr4 = self._constants.get("nr4", []) a4 = self._constants.get("a4", []) b4 = self._constants.get("b4", []) Ai = self._constants.get("A", []) Bi = self._constants.get("B", []) Ci = self._constants.get("C", []) Di = self._constants.get("D", []) bt4 = self._constants.get("beta4", []) for n, a, b, A, B, C, D, bt in zip(nr4, a4, b4, Ai, Bi, Ci, Di, bt4): Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) F = exp(-C*(delta-1)**2-D*(tau-1)**2) Fd = -2*C*F*(delta-1) Fdd = 2*C*F*(2*C*(delta-1)**2-1) Ft = -2*D*F*(tau-1) Ftt = 2*D*F*(2*D*(tau-1)**2-1) Fdt = 4*C*D*F*(delta-1)*(tau-1) Delta = Tita**2+B*((delta-1)**2)**a Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**(0.5/bt-1) + 2*B*a*((delta-1)**2)**(a-1)) if delta == 1: Deltadd = 0 else: Deltadd = Deltad/(delta-1)+(delta-1)**2*( 4*B*a*(a-1)*((delta-1)**2)**(a-2) + 2*A**2/bt**2*(((delta-1)**2)**(0.5/bt-1))**2 + A*Tita*4/bt*(0.5/bt-1)*((delta-1)**2)**(0.5/bt-2)) # Avoid ZeroDivisionError at critical point if Delta == 0: DeltaBd = 0 DeltaBdd = 0 DeltaBt = 0 DeltaBtt = 0 DeltaBdt = 0 else: DeltaBd = b*Delta**(b-1)*Deltad DeltaBdd = b*(Delta**(b-1)*Deltadd+(b-1)*Delta**(b-2)*Deltad**2) DeltaBt = -2*Tita*b*Delta**(b-1) DeltaBtt = 2*b*Delta**(b-1)+4*Tita**2*b*(b-1)*Delta**(b-2) DeltaBdt = -A*b*2/bt*Delta**(b-1)*(delta-1)*((delta-1)**2)**( 0.5/bt-1)-2*Tita*b*(b-1)*Delta**(b-2)*Deltad fir += n*Delta**b*delta*F fird += n*(Delta**b*(F+delta*Fd)+DeltaBd*delta*F) firdd += n*(Delta**b*(2*Fd+delta*Fdd) + 2*DeltaBd*(F+delta*Fd) + DeltaBdd*delta*F) firt += n*delta*(DeltaBt*F+Delta**b*Ft) firtt += n*delta*(DeltaBtt*F+2*DeltaBt*Ft+Delta**b*Ftt) firdt += n*(Delta**b*(Ft+delta*Fdt)+delta*DeltaBd*Ft + DeltaBt*(F+delta*Fd)+DeltaBdt*delta*F) prop = {} prop["fir"] = fir prop["firt"] = firt prop["firtt"] = firtt prop["fird"] = fird prop["firdd"] = firdd prop["firdt"] = firdt return prop def _virial(self, T): """Virial coefficient Parameters ---------- T : float Temperature [K] Returns ------- prop : dict Dictionary with residual adimensional helmholtz energy: * B: ∂fir/∂δ|δ->0 * C: ∂²fir/∂δ²|δ->0 """ T_c = self._constants.get("Tref", self.Tc) tau = T_c/T B = C = 0 delta = 1e-200 # Polinomial terms nr1 = self._constants.get("nr1", []) d1 = self._constants.get("d1", []) t1 = self._constants.get("t1", []) for n, d, t in zip(nr1, d1, t1): B += n*d*delta**(d-1)*tau**t C += n*d*(d-1)*delta**(d-2)*tau**t # Exponential terms nr2 = self._constants.get("nr2", []) d2 = self._constants.get("d2", []) g2 = self._constants.get("gamma2", []) t2 = self._constants.get("t2", []) c2 = self._constants.get("c2", []) for n, d, g, t, c in zip(nr2, d2, g2, t2, c2): B += n*exp(-g*delta**c)*delta**(d-1)*tau**t*(d-g*c*delta**c) C += n*exp(-g*delta**c)*(delta**(d-2)*tau**t*( (d-g*c*delta**c)*(d-1-g*c*delta**c)-g**2*c**2*delta**c)) # Gaussian terms nr3 = self._constants.get("nr3", []) d3 = self._constants.get("d3", []) t3 = self._constants.get("t3", []) a3 = self._constants.get("alfa3", []) e3 = self._constants.get("epsilon3", []) b3 = self._constants.get("beta3", []) g3 = self._constants.get("gamma3", []) for n, d, t, a, e, b, g in zip(nr3, d3, t3, a3, e3, b3, g3): B += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( d/delta-2*a*(delta-e)) C += n*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( -2*a*delta**d+4*a**2*delta**d*( delta-e)**2-4*d*a*delta**2*( delta-e)+d*2*delta) # Non analitic terms nr4 = self._constants.get("nr4", []) a4 = self._constants.get("a4", []) b4 = self._constants.get("b4", []) Ai = self._constants.get("A", []) Bi = self._constants.get("B", []) Ci = self._constants.get("C", []) Di = self._constants.get("D", []) bt4 = self._constants.get("beta4", []) for n, a, b, A, B_, C_, D, bt in zip(nr4, a4, b4, Ai, Bi, Ci, Di, bt4): Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) Delta = Tita**2+B_*((delta-1)**2)**a Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**( 0.5/bt-1)+2*B_*a*((delta-1)**2)**(a-1)) Deltadd = Deltad/(delta-1) + (delta-1)**2*( 4*B_*a*(a-1)*((delta-1)**2)**(a-2) + 2*A**2/bt**2*(((delta-1)**2)**(0.5/bt-1))**2 + A*Tita*4/bt*(0.5/bt-1)*((delta-1)**2)**(0.5/bt-2)) DeltaBd = b*Delta**(b-1)*Deltad DeltaBdd = b*(Delta**(b-1)*Deltadd+(b-1)*Delta**(b-2)*Deltad**2) F = exp(-C_*(delta-1)**2-D*(tau-1)**2) Fd = -2*C_*F*(delta-1) Fdd = 2*C_*F*(2*C_*(delta-1)**2-1) B += n*(Delta**b*(F+delta*Fd)+DeltaBd*delta*F) C += n*(Delta**b*(2*Fd+delta*Fdd)+2*DeltaBd*(F+delta*Fd) + DeltaBdd*delta*F) prop = {} prop["B"] = B prop["C"] = C return prop def _derivDimensional(self, rho, T): """Calcule the dimensional form or Helmholtz free energy derivatives Parameters ---------- rho : float Density, [kg/m³] T : float Temperature, [K] Returns ------- prop : dict Dictionary with residual helmholtz energy and derivatives: * fir, [kJ/kg] * firt: ∂fir/∂T|ρ, [kJ/kgK] * fird: ∂fir/∂ρ|T, [kJ/m³kg²] * firtt: ∂²fir/∂T²|ρ, [kJ/kgK²] * firdt: ∂²fir/∂T∂ρ, [kJ/m³kg²K] * firdd: ∂²fir/∂ρ²|T, [kJ/m⁶kg] References ---------- IAPWS, Guideline on an Equation of State for Humid Air in Contact with Seawater and Ice, Consistent with the IAPWS Formulation 2008 for the Thermodynamic Properties of Seawater, Table 7, http://www.iapws.org/relguide/SeaAir.html """ if not rho: prop = {} prop["fir"] = 0 prop["firt"] = 0 prop["fird"] = 0 prop["firtt"] = 0 prop["firdt"] = 0 prop["firdd"] = 0 return prop R = self._constants.get("R")/self._constants.get("M", self.M) rho_c = self._constants.get("rhoref", self.rhoc) T_c = self._constants.get("Tref", self.Tc) delta = rho/rho_c tau = T_c/T ideal = self._phi0(tau, delta) fio = ideal["fio"] fiot = ideal["fiot"] fiott = ideal["fiott"] fiod = ideal["fiod"] fiodd = ideal["fiodd"] res = self._phir(tau, delta) fir = res["fir"] firt = res["firt"] firtt = res["firtt"] fird = res["fird"] firdd = res["firdd"] firdt = res["firdt"] prop = {} prop["fir"] = R*T*(fio+fir) prop["firt"] = R*(fio+fir-(fiot+firt)*tau) prop["fird"] = R*T/rho_c*(fiod+fird) prop["firtt"] = R*tau**2/T*(fiott+firtt) prop["firdt"] = R/rho_c*(fiod+fird-firdt*tau) prop["firdd"] = R*T/rho_c**2*(fiodd+firdd) return prop def _surface(self, T): """Generic equation for the surface tension Parameters ---------- T : float Temperature, [K] Returns ------- σ : float Surface tension, [N/m] Notes ----- Need a _surf dict in the derived class with the parameters keys: sigma: coefficient exp: exponent """ tau = 1-T/self.Tc sigma = 0 for n, t in zip(self._surf["sigma"], self._surf["exp"]): sigma += n*tau**t return sigma @classmethod def _Vapor_Pressure(cls, T): """Auxiliary equation for the vapour pressure Parameters ---------- T : float Temperature, [K] Returns ------- Pv : float Vapour pressure, [Pa] References ---------- IAPWS, Revised Supplementary Release on Saturation Properties of Ordinary Water Substance September 1992, http://www.iapws.org/relguide/Supp-sat.html, Eq.1 """ if T < cls.Tt: T = cls.Tt elif T > cls.Tc: T = cls.Tc Tita = 1-T/cls.Tc suma = 0 for n, x in zip(cls._Pv["ao"], cls._Pv["exp"]): suma += n*Tita**x Pr = exp(cls.Tc/T*suma) Pv = Pr*cls.Pc return Pv @classmethod def _Liquid_Density(cls, T): """Auxiliary equation for the density of saturated liquid Parameters ---------- T : float Temperature, [K] Returns ------- rho : float Saturated liquid density, [kg/m³] References ---------- IAPWS, Revised Supplementary Release on Saturation Properties of Ordinary Water Substance September 1992, http://www.iapws.org/relguide/Supp-sat.html, Eq.2 """ if T < cls.Tt: T = cls.Tt elif T > cls.Tc: T = cls.Tc eq = cls._rhoL["eq"] Tita = 1-T/cls.Tc if eq == 2: Tita = Tita**(1./3) suma = 0 for n, x in zip(cls._rhoL["ao"], cls._rhoL["exp"]): suma += n*Tita**x Pr = suma+1 rho = Pr*cls.rhoc return rho @classmethod def _Vapor_Density(cls, T): """Auxiliary equation for the density of saturated vapor Parameters ---------- T : float Temperature, [K] Returns ------- rho : float Saturated vapor density, [kg/m³] References ---------- IAPWS, Revised Supplementary Release on Saturation Properties of Ordinary Water Substance September 1992, http://www.iapws.org/relguide/Supp-sat.html, Eq.3 """ if T < cls.Tt: T = cls.Tt elif T > cls.Tc: T = cls.Tc eq = cls._rhoG["eq"] Tita = 1-T/cls.Tc if eq == 4: Tita = Tita**(1./3) suma = 0 for n, x in zip(cls._rhoG["ao"], cls._rhoG["exp"]): suma += n*Tita**x Pr = exp(suma) rho = Pr*cls.rhoc return rho @classmethod def _dPdT_sat(cls, T): """Auxiliary equation for the dP/dT along saturation line Parameters ---------- T : float Temperature, [K] Returns ------- dPdT : float dPdT, [MPa/K] References ---------- IAPWS, Revised Supplementary Release on Saturation Properties of Ordinary Water Substance September 1992, http://www.iapws.org/relguide/Supp-sat.html, derived from Eq.1 """ Tita = 1-T/cls.Tc suma1 = 0 suma2 = 0 for n, x in zip(cls._Pv["ao"], cls._Pv["exp"]): suma1 -= n*x*Tita**(x-1)/cls.Tc suma2 += n*Tita**x Pr = (cls.Tc*suma1/T-cls.Tc/T**2*suma2)*exp(cls.Tc/T*suma2) dPdT = Pr*cls.Pc return dPdT def mainClassDoc(): """ Function decorator used to automatic adiction of base class MEoS in subclass __doc__ """ def decorator(f): # __doc__ is only writable in python3. # The doc build must be done with python3 so this snnippet do the work py_version = platform.python_version_tuple()[0] if py_version == 3: doc = f.__doc__.split(os.linesep) try: ind = doc.index("") except ValueError: ind = 1 doc1 = os.linesep.join(doc[:ind]) doc3 = os.linesep.join(doc[ind:]) doc2 = os.linesep.join(MEoS.__doc__.split(os.linesep)[3:]) f.__doc__ = doc1 + os.linesep + os.linesep + \ doc2 + os.linesep + os.linesep + doc3 return f return decorator @mainClassDoc() class IAPWS95(MEoS): """Implementation of IAPWS Formulation 1995 for ordinary water substance, (revised release of 2016), for internal procedures, see MEoS base class Examples -------- >>> water=IAPWS95(T=300, rho=996.5560) >>> water.P, water.cv, water.w, water.s 0.0992418350 4.13018112 1501.51914 0.393062643 >>> water=IAPWS95(T=500, rho=0.435) >>> water.P, water.cv, water.w, water.s 0.0999679423 1.50817541 548.31425 7.944882714 >>> water=IAPWS95(T=900., P=700) >>> water.rho, water.cv, water.w, water.s 870.7690 2.66422350 2019.33608 4.17223802 >>> water=IAPWS95(T=300., P=0.1) >>> water.P, water.rho, water.h, water.s, water.cp, water.w, water.virialB 0.10000 996.56 112.65 0.39306 4.1806 1501.5 -0.066682 >>> water=IAPWS95(T=500., P=0.1) >>> water.P, water.rho, water.h, water.s, water.cp, water.w, water.virialB 0.10000 0.43514 2928.6 7.9447 1.9813 548.31 -0.0094137 >>> water=IAPWS95(T=450., x=0.5) >>> water.T, water.P, water.rho, water.h, water.s, water.virialB 450.00 0.93220 9.5723 1761.8 4.3589 -0.013028 >>> water=IAPWS95(P=1.5, rho=1000.) >>> water.T, water.rho, water.h, water.s, water.cp, water.w, water.virialB 286.44 1000.0 57.253 0.19931 4.1855 1462.1 -0.085566 >>> water=IAPWS95(h=3000, s=8.) >>> water.T, water.P, water.h, water.s, water.cp, water.w, water.virialB 536.24 0.11970 3000.0 8.0000 1.9984 567.04 -0.0076606 >>> water=IAPWS95(h=150, s=0.4) >>> water.T, water.P, water.rho, water.h, water.s, water.cp, water.w 301.27 35.50549 1011.48 150.00 0.40000 4.0932 1564.1 >>> water=IAPWS95(T=450., rho=300) >>> water.T, water.P, water.rho, water.h, water.s, water.x, water.virialB 450.00 0.93220 300.00 770.82 2.1568 0.010693 -0.013028 >>> water=IAPWS95(rho=300., P=0.1) >>> water.T, water.P, water.rho, water.h, water.s, water.x, water.virialB 372.76 0.10000 300.00 420.56 1.3110 0.0013528 -0.025144 >>> water=IAPWS95(h=1500., P=0.1) >>> water.T, water.P, water.rho, water.h, water.s, water.x, water.virialB 372.76 0.10000 1.2303 1500.0 4.2068 0.47952 -0.025144 >>> water=IAPWS95(s=5., P=3.5) >>> water.T, water.P, water.rho, water.h, water.s, water.x, water.virialB 515.71 3.5000 25.912 2222.8 5.0000 0.66921 -0.0085877 >>> water=IAPWS95(T=500., u=900) >>> water.P, water.rho, water.u, water.h, water.s, water.cp, water.w 108.21 903.62 900.00 1019.8 2.4271 4.1751 1576.0 >>> water=IAPWS95(P=0.3, u=1550.) >>> water.T, water.P, water.rho, water.u, water.h, water.s, water.x 406.67 0.30000 3.3029 1550.0 1640.8 4.3260 0.49893 >>> water=IAPWS95(rho=300, h=1000.) >>> water.T, water.P, water.rho, water.u, water.h, water.s, water.x 494.92 2.3991 300.00 992.00 1000.0 2.6315 0.026071 >>> water=IAPWS95(rho=30, s=8.) >>> water.T, water.P, water.rho, water.u, water.h, water.s, water.cp 1562.42 21.671 30.000 4628.5 5350.9 8.0000 2.7190 >>> water=IAPWS95(rho=30, s=4.) >>> water.T, water.P, water.rho, water.u, water.h, water.s, water.x 495.00 2.4029 30.000 1597.3 1677.4 4.0000 0.39218 >>> water=IAPWS95(rho=300, u=1000.) >>> water.T, water.P, water.rho, water.u, water.h, water.s, water.x 496.44 2.4691 300.000 1000.0 1008.2 2.6476 0.02680 >>> water=IAPWS95(s=3., h=1000.) >>> water.T, water.P, water.rho, water.u, water.h, water.s, water.x 345.73 0.034850 0.73526 952.60 1000.0 3.0000 0.29920 >>> water=IAPWS95(u=995., h=1000.) >>> water.T, water.P, water.rho, water.u, water.h, water.s, water.x 501.89 2.7329 546.58 995.00 1000.0 2.6298 0.00866 >>> water=IAPWS95(u=1000., s=3.) >>> water.T, water.P, water.rho, water.u, water.h, water.s, water.x 371.24 0.094712 1.99072 1000.00 1047.6 3.0000 0.28144 References ---------- IAPWS, Revised Release on the IAPWS Formulation 1995 for the Thermodynamic Properties of Ordinary Water Substance for General and Scientific Use, September 2016, http://www.iapws.org/relguide/IAPWS-95.html IAPWS, Revised Supplementary Release on Saturation Properties of Ordinary Water Substance September 1992, http://www.iapws.org/relguide/Supp-sat.html IAPWS, Guideline on a Low-Temperature Extension of the IAPWS-95 Formulation for Water Vapor, http://www.iapws.org/relguide/LowT.html IAPWS, Revised Advisory Note No. 3: Thermodynamic Derivatives from IAPWS Formulations, http://www.iapws.org/relguide/Advise3.pdf """ name = "water" CASNumber = "7732-18-5" formula = "H2O" synonym = "R-718" Tc = Tc rhoc = rhoc Pc = Pc M = M Tt = 273.16 Tb = 373.1243 f_acent = 0.3443 momentoDipolar = 1.855 Fi0 = {"ao_log": [1, 3.00632], "pow": [0, 1], "ao_pow": [-8.3204464837497, 6.6832105275932], "ao_exp": [0.012436, 0.97315, 1.2795, 0.96956, 0.24873], "titao": [1.28728967, 3.53734222, 7.74073708, 9.24437796, 27.5075105]} _constants = { "R": 8.314371357587, "nr1": [0.12533547935523e-1, 0.78957634722828e1, -0.87803203303561e1, 0.31802509345418, -0.26145533859358, -0.78199751687981e-2, 0.88089493102134e-2], "d1": [1, 1, 1, 2, 2, 3, 4], "t1": [-0.5, 0.875, 1, 0.5, 0.75, 0.375, 1], "nr2": [-0.66856572307965, 0.20433810950965, -0.66212605039687e-4, -0.19232721156002, -0.25709043003438, 0.16074868486251, -0.40092828925807e-1, .39343422603254e-6, -0.75941377088144e-5, 0.56250979351888e-3, -0.15608652257135e-4, 0.11537996422951e-8, .36582165144204e-6, -.13251180074668e-11, -.62639586912454e-9, -0.10793600908932, 0.17611491008752e-1, 0.22132295167546, -0.40247669763528, 0.58083399985759, 0.49969146990806e-2, -0.31358700712549e-1, -0.74315929710341, 0.47807329915480, 0.20527940895948e-1, -0.13636435110343, 0.14180634400617e-1, 0.83326504880713e-2, -0.29052336009585e-1, 0.38615085574206e-1, -0.20393486513704e-1, -0.16554050063734e-2, .19955571979541e-2, 0.15870308324157e-3, -0.16388568342530e-4, 0.43613615723811e-1, 0.34994005463765e-1, -0.76788197844621e-1, 0.22446277332006e-1, -0.62689710414685e-4, -0.55711118565645e-9, -0.19905718354408, 0.31777497330738, -0.11841182425981], "c2": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 6, 6, 6, 6], "d2": [1, 1, 1, 2, 2, 3, 4, 4, 5, 7, 9, 10, 11, 13, 15, 1, 2, 2, 2, 3, 4, 4, 4, 5, 6, 6, 7, 9, 9, 9, 9, 9, 10, 10, 12, 3, 4, 4, 5, 14, 3, 6, 6, 6], "t2": [4, 6, 12, 1, 5, 4, 2, 13, 9, 3, 4, 11, 4, 13, 1, 7, 1, 9, 10, 10, 3, 7, 10, 10, 6, 10, 10, 1, 2, 3, 4, 8, 6, 9, 8, 16, 22, 23, 23, 10, 50, 44, 46, 50], "gamma2": [1]*44, "nr3": [-0.31306260323435e2, 0.31546140237781e2, -0.25213154341695e4], "d3": [3]*3, "t3": [0, 1, 4], "alfa3": [20]*3, "beta3": [150, 150, 250], "gamma3": [1.21, 1.21, 1.25], "epsilon3": [1.]*3, "nr4": [-0.14874640856724, 0.31806110878444], "a4": [3.5, 3.5], "b4": [0.85, 0.95], "B": [0.2, 0.2], "C": [28, 32], "D": [700, 800], "A": [0.32, .32], "beta4": [0.3, 0.3]} _Pv = { "ao": [-7.85951783, 1.84408259, -11.7866497, 22.6807411, -15.9618719, 1.80122502], "exp": [1, 1.5, 3, 3.5, 4, 7.5]} _rhoL = { "eq": 2, "ao": [1.99274064, 1.09965342, -0.510839303, -1.75493479, -45.5170352, -6.74694450e5], "exp": [1, 2, 5, 16, 43, 110]} _rhoG = { "eq": 4, "ao": [-2.0315024, -2.6830294, -5.38626492, -17.2991605, -44.7586581, -63.9201063], "exp": [1, 2, 4, 9, 18.5, 35.5]} def _phi0(self, tau, delta): """Low temperature extension of the IAPWS-95""" prop = MEoS._phi0(self, tau, delta) T = self.Tc/tau if 50 <= T < 130: fex, fext, fextt = self._phiex(T) prop["fio"] += fex prop["fiot"] += fext prop["fiott"] += fextt return prop def _phiex(self, T): """Low temperature extension""" tau = self.Tc/T E = 0.278296458178592 ep = self.Tc/130 fex = E*(-1/2/tau-3/ep**2*(tau+ep)*log(tau/ep)-9/2/ep+9*tau/2/ep**2 + tau**2/2/ep**3) fext = E*(1/2/tau**2-3/tau/ep-3/ep**2*log(tau/ep)+3/2/ep**2+tau/ep**3) fextt = E*(-1/tau+1/ep)**3 return fex, fext, fextt @classmethod def _alfa_sat(cls, T): """Auxiliary equation for the alfa coefficient for calculate the enthalpy along the saturation line Parameters ---------- T : float Temperature, [K] Returns ------- alfa : float alfa coefficient, [kJ/kg] References ---------- IAPWS, Revised Supplementary Release on Saturation Properties of Ordinary Water Substance September 1992, http://www.iapws.org/relguide/Supp-sat.html, Eq.4 """ di = [-1135.905627715, -5.65134998e-8, 2690.66631, 127.287297, -135.003439, 0.981825814] expi = [0, -19, 1, 4.5, 5, 54.5] Tita = T/cls.Tc alfa = 0 for d, x in zip(di, expi): alfa += d*Tita**x return alfa @classmethod def _phi_sat(cls, T): """Auxiliary equation for the phi coefficient for calculate the entropy along the saturation line Parameters ---------- T : float Temperature, [K] Returns ------- phi : float phi coefficient, [kJ/kgK] References ---------- IAPWS, Revised Supplementary Release on Saturation Properties of Ordinary Water Substance September 1992, http://www.iapws.org/relguide/Supp-sat.html, Eq.5 """ di = [2319.5246, -5.65134998e-8*19/20, 2690.66631, 127.287297*9/7, -135.003439*5/4, 0.981825814*109/107] expi = [0, -20, None, 3.5, 4, 53.5] Tita = T/cls.Tc suma = 0 for d, x in zip(di, expi): if x is None: suma += d*log(Tita) else: suma += d*Tita**x phi = suma/cls.Tc return phi @classmethod def _Liquid_Enthalpy(cls, T): """Auxiliary equation for the specific enthalpy for saturated liquid Parameters ---------- T : float Temperature, [K] Returns ------- h : float Saturated liquid enthalpy, [kJ/kg] References ---------- IAPWS, Revised Supplementary Release on Saturation Properties of Ordinary Water Substance September 1992, http://www.iapws.org/relguide/Supp-sat.html, Eq.6 """ alfa = cls._alfa_sat(T) rho = cls._Liquid_Density(T) dpdT = cls._dPdT_sat(T) h = alfa+T/rho*dpdT*1000 return h @classmethod def _Vapor_Enthalpy(cls, T): """Auxiliary equation for the specific enthalpy for saturated vapor Parameters ---------- T : float Temperature, [K] Returns ------- h : float Saturated vapor enthalpy, [kJ/kg] References ---------- IAPWS, Revised Supplementary Release on Saturation Properties of Ordinary Water Substance September 1992, http://www.iapws.org/relguide/Supp-sat.html, Eq.7 """ alfa = cls._alfa_sat(T) rho = cls._Vapor_Density(T) dpdT = cls._dPdT_sat(T) h = alfa+T/rho*dpdT*1000 return h @classmethod def _Liquid_Entropy(cls, T): """Auxiliary equation for the specific entropy for saturated liquid Parameters ---------- T : float Temperature, [K] Returns ------- s : float Saturated liquid entropy, [kJ/kgK] References ---------- IAPWS, Revised Supplementary Release on Saturation Properties of Ordinary Water Substance September 1992, http://www.iapws.org/relguide/Supp-sat.html, Eq.8 """ phi = cls._phi_sat(T) rho = cls._Liquid_Density(T) dpdT = cls._dPdT_sat(T) s = phi+dpdT/rho*1000 return s @classmethod def _Vapor_Entropy(cls, T): """Auxiliary equation for the specific entropy for saturated vapor Parameters ---------- T : float Temperature, [K] Returns ------- s : float Saturated liquid entropy, [kJ/kgK] References ---------- IAPWS, Revised Supplementary Release on Saturation Properties of Ordinary Water Substance September 1992, http://www.iapws.org/relguide/Supp-sat.html, Eq.9 """ phi = cls._phi_sat(T) rho = cls._Vapor_Density(T) dpdT = cls._dPdT_sat(T) s = phi+dpdT/rho*1000 return s def _visco(self, rho, T, fase): ref = IAPWS95() st = ref._Helmholtz(rho, 1.5*Tc) delta = rho/rhoc drho = 1e3/self.R/1.5/Tc/(1+2*delta*st["fird"]+delta**2*st["firdd"]) return _Viscosity(rho, T, fase, drho) def _thermo(self, rho, T, fase): ref = IAPWS95() st = ref._Helmholtz(rho, 1.5*Tc) delta = rho/rhoc drho = 1e3/self.R/1.5/Tc/(1+2*delta*st["fird"]+delta**2*st["firdd"]) return _ThCond(rho, T, fase, drho) def _surface(self, T): s = _Tension(T) return s class IAPWS95_PT(IAPWS95): """Derivated class for direct P and T input""" def __init__(self, P, T): IAPWS95.__init__(self, T=T, P=P) class IAPWS95_Ph(IAPWS95): """Derivated class for direct P and h input""" def __init__(self, P, h): IAPWS95.__init__(self, P=P, h=h) class IAPWS95_Ps(IAPWS95): """Derivated class for direct P and s input""" def __init__(self, P, s): IAPWS95.__init__(self, P=P, s=s) class IAPWS95_Px(IAPWS95): """Derivated class for direct P and v input""" def __init__(self, P, x): IAPWS95.__init__(self, P=P, x=x) class IAPWS95_Tx(IAPWS95): """Derivated class for direct T and x input""" def __init__(self, T, x): IAPWS95.__init__(self, T=T, x=x) @mainClassDoc() class D2O(MEoS): """Implementation of IAPWS Formulation for heavy water substance, for internal procedures, see MEoS base class Examples -------- >>> hwater=D2O(T=300, rho=996.5560) >>> hwater.P, hwater.Liquid.cv, hwater.Liquid.w 0.0030675947 4.21191157 5332.04871 References ---------- IAPWS, Release on the IAPWS Formulation 2017 for the Thermodynamic Properties of Heavy Water, http://www.iapws.org/relguide/Heavy-2017.pdf IAPWS, Revised Advisory Note No. 3: Thermodynamic Derivatives from IAPWS Formulations, http://www.iapws.org/relguide/Advise3.pdf """ name = "heavy water" CASNumber = "7789-20-0" formula = "D2O" synonym = "deuterium oxide" Tc = Tc_D2O rhoc = rhoc_D2O Pc = Pc_D2O M = 20.027508 # g/mol Tt = 276.97 Tb = 374.563 f_acent = 0.364 momentoDipolar = 1.9 Fi0 = {"ao_log": [1, 3], "pow": [0, 1], "ao_pow": [-8.670994022646, 6.96033578458778], "ao_exp": [0.010633, 0.99787, 2.1483, 0.3549], "titao": [308/Tc, 1695/Tc, 3949/Tc, 10317/Tc], "ao_hyp": [], "hyp": []} _constants = { "R": 8.3144598, "nr1": [0.122082060e-1, 0.296956870e1, -0.379004540e1, 0.941089600, -0.922466250, -0.139604190e-1], "d1": [4, 1, 1, 2, 2, 3], "t1": [1.0000, 0.6555, 0.9369, 0.5610, 0.7017, 1.0672], "nr2": [-0.125203570, -0.555391500e1, -0.493009740e1, -0.359470240e-1, -0.936172870e1, -0.691835150], "c2": [1, 2, 2, 1, 2, 2], "d2": [1, 1, 3, 2, 2, 1], "t2": [3.9515, 4.6000, 5.1590, 0.2000, 5.4644, 2.3660], "gamma2": [1]*6, "nr3": [-0.456110600e-1, -0.224513300e1, 0.860006070e1, -0.248410420e1, 0.164476900e2, 0.270393360e1, 0.375637470e2, -0.177607760e1, 0.220924640e1, 0.519652000e1, 0.421097400, -0.391921100], "t3": [3.4553, 1.4150, 1.5745, 3.4540, 3.8106, 4.8950, 1.4300, 1.5870, 3.7900, 2.6200, 1.9000, 4.3200], "d3": [1, 3, 1, 3, 1, 1, 2, 2, 2, 1, 1, 1], "alfa3": [0.6014, 1.4723, 1.5305, 2.4297, 1.3086, 1.3528, 3.4456, 1.2645, 2.5547, 1.2148, 18.738, 18.677], "beta3": [0.4200, 2.4318, 1.2888, 8.2710, 0.3673, 0.9504, 7.8318, 3.3281, 7.1753, 0.9465, 1177.0, 1167.0], "epsilon3": [1.8663, 0.2895, 0.5803, 0.2236, 0.6815, 0.9495, 1.1158, 0.1607, 0.4144, 0.9683, 0.9488, 0.9487], "gamma3": [1.5414, 1.3794, 1.7385, 1.3045, 2.7242, 3.5321, 2.4552, 0.8319, 1.3500, 2.5617, 1.0491, 1.0486]} _Pv = { "ao": [-0.80236e1, 0.23957e1, -0.42639e2, 0.99569e2, -0.62135e2], "exp": [1.0, 1.5, 2.75, 3.0, 3.2]} _rhoL = { "eq": 1, "ao": [0.26406e1, 0.97090e1, -0.18058e2, 0.87202e1, -0.74487e1], "exp": [0.3678, 1.9, 2.2, 2.63, 7.3]} _rhoG = { "eq": 3, "ao": [-0.37651e1, -0.38673e2, 0.73024e2, -0.13251e3, 0.75235e2, -0.70412e2], "exp": [0.409, 1.766, 2.24, 3.04, 3.42, 6.9]} def _visco(self, rho, T, fase): ref = D2O() s = ref._Helmholtz(rho, 1.5*Tc_D2O) delta = rho/rhoc_D2O drho = 1e3/self.R/1.5/Tc_D2O/(1+2*delta*s["fird"]+delta**2*s["firdd"]) return _D2O_Viscosity(rho, T, fase, drho) def _thermo(self, rho, T, fase): ref = D2O() s = ref._Helmholtz(rho, 1.5*Tc_D2O) delta = rho/rhoc_D2O drho = 1e3/self.R/1.5/Tc_D2O/(1+2*delta*s["fird"]+delta**2*s["firdd"]) return _D2O_ThCond(rho, T, fase, drho) def _surface(self, T): s = _D2O_Tension(T) return s iapws-1.5.5/iapws/_iapws97Constants.py0000644000175000017500000020553214624712261020077 0ustar alastairalastair#!/usr/bin/python # -*- coding: utf-8 -*- # pylint: disable=too-many-lines, too-many-statements, too-many-locals # pylint: disable=too-many-instance-attributes, too-many-branches # pylint: disable=invalid-name """ Constants for iapws97.py """ import numpy as np # Boundary Region1-Region3 h13_s_Li = np.array([0, 1, 1, 3, 5, 6]) h13_s_Lj = np.array([0, -2, 2, -12, -4, -3]) h13_s_n = np.array( [0.913965547600543, -0.430944856041991e-4, 0.603235694765419e2, 0.117518273082168e-17, 0.220000904781292, -0.690815545851641e2]) # t_hs t_hs_Li = np.array( [-12, -10, -8, -4, -3, -2, -2, -2, -2, 0, 1, 1, 1, 3, 3, 5, 6, 6, 8, 8, 8, 12, 12, 14, 14]) t_hs_Lj = np.array( [10, 8, 3, 4, 3, -6, 2, 3, 4, 0, -3, -2, 10, -2, -1, -5, -6, -3, -8, -2, -1, -12, -1, -12, 1]) t_hs_n = np.array( [0.629096260829810e-3, -0.823453502583165e-3, 0.515446951519474e-7, -0.117565945784945e1, 0.348519684726192e1, -0.507837382408313e-11, -0.284637670005479e1, -0.236092263939673e1, 0.601492324973779e1, 0.148039650824546e1, 0.360075182221907e-3, -0.126700045009952e-1, -0.122184332521413e7, 0.149276502463272, 0.698733471798484, -0.252207040114321e-1, 0.147151930985213e-1, -0.108618917681849e1, -0.936875039816322e-3, 0.819877897570217e2, -0.182041861521835e3, 0.261907376402688e-5, -0.291626417025961e5, 0.140660774926165e-4, 0.783237062349385e7]) # Psat_h PSat_h_Li = np.array([0, 1, 1, 1, 1, 5, 7, 8, 14, 20, 22, 24, 28, 36]) PSat_h_Lj = np.array([0, 1, 3, 4, 36, 3, 0, 24, 16, 16, 3, 18, 8, 24]) PSat_h_n = np.array( [0.600073641753024, -0.936203654849857e1, 0.246590798594147e2, -0.107014222858224e3, -0.915821315805768e14, -0.862332011700662e4, -0.235837344740032e2, 0.252304969384128e18, -0.389718771997719e19, -0.333775713645296e23, 0.356499469636328e11, -0.148547544720641e27, 0.330611514838798e19, 0.813641294467829e38]) # Psat_s PSat_s_Li = np.array([0, 1, 1, 4, 12, 12, 16, 24, 28, 32]) PSat_s_Lj = np.array([0, 1, 32, 7, 4, 14, 36, 10, 0, 18]) PSat_s_n = np.array( [0.639767553612785, -0.129727445396014e2, -0.224595125848403e16, 0.177466741801846e7, 0.717079349571538e10, -0.378829107169011e18, -0.955586736431328e35, 0.187269814676188e24, 0.119254746466473e12, 0.110649277244882e37]) # h1_s h1_s_Li = np.array( [0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 7, 8, 12, 12, 14, 14, 16, 20, 20, 22, 24, 28, 32, 32]) h1_s_Lj = np.array( [14, 36, 3, 16, 0, 5, 4, 36, 4, 16, 24, 18, 24, 1, 4, 2, 4, 1, 22, 10, 12, 28, 8, 3, 0, 6, 8]) h1_s_n = np.array( [0.332171191705237, 0.611217706323496e-3, -0.882092478906822e1, -0.455628192543250, -0.263483840850452e-4, -0.223949661148062e2, -0.428398660164013e1, -0.616679338856916, -0.146823031104040e2, 0.284523138727299e3, -0.113398503195444e3, 0.115671380760859e4, 0.395551267359325e3, -0.154891257229285e1, 0.194486637751291e2, -0.357915139457043e1, -0.335369414148819e1, -0.664426796332460, 0.323321885383934e5, 0.331766744667084e4, -0.223501257931087e5, 0.573953875852936e7, 0.173226193407919e3, -0.363968822121321e-1, 0.834596332878346e-6, 0.503611916682674e1, 0.655444787064505e2]) # h3_s h3a_s_Li = np.array( [0, 0, 0, 0, 2, 3, 4, 4, 5, 5, 6, 7, 7, 7, 10, 10, 10, 32, 32]) h3a_s_Lj = np.array( [1, 4, 10, 16, 1, 36, 3, 16, 20, 36, 4, 2, 28, 32, 14, 32, 36, 0, 6]) h3a_s_n = np.array( [0.822673364673336, 0.181977213534479, -0.112000260313624e-1, -0.746778287048033e-3, -0.179046263257381, 0.424220110836657e-1, -0.341355823438768, -0.209881740853565e1, -0.822477343323596e1, -0.499684082076008e1, 0.191413958471069, 0.581062241093136e-1, -0.165505498701029e4, 0.158870443421201e4, -0.850623535172818e2, -0.317714386511207e5, -0.945890406632871e5, -0.139273847088690e-5, 0.631052532240980]) # h2ab_s h2ab_s_Li = np.array( [1, 1, 2, 2, 4, 4, 7, 8, 8, 10, 12, 12, 18, 20, 24, 28, 28, 28, 28, 28, 32, 32, 32, 32, 32, 36, 36, 36, 36, 36]) h2ab_s_Lj = np.array( [8, 24, 4, 32, 1, 2, 7, 5, 12, 1, 0, 7, 10, 12, 32, 8, 12, 20, 22, 24, 2, 7, 12, 14, 24, 10, 12, 20, 22, 28]) h2ab_s_n = np.array( [-0.524581170928788e3, -0.926947218142218e7, -0.237385107491666e3, 0.210770155812776e11, -0.239494562010986e2, 0.221802480294197e3, -0.510472533393438e7, 0.124981396109147e7, 0.200008436996201e10, -0.815158509791035e3, -0.157612685637523e3, -0.114200422332791e11, 0.662364680776872e16, -0.227622818296144e19, -0.171048081348406e32, 0.660788766938091e16, 0.166320055886021e23, -0.218003784381501e30, -0.787276140295618e30, 0.151062329700346e32, 0.795732170300541e7, 0.131957647355347e16, -0.325097068299140e24, -0.418600611419248e26, 0.297478906557467e35, -0.953588761745473e20, 0.166957699620939e25, -0.175407764869978e33, 0.347581490626396e35, -0.710971318427851e39]) # h2c3b_s h2c3b_s_Li = np.array([0, 0, 0, 1, 1, 5, 6, 7, 8, 8, 12, 16, 22, 22, 24, 36]) h2c3b_s_Lj = np.array([0, 3, 4, 0, 12, 36, 12, 16, 2, 20, 32, 36, 2, 32, 7, 20]) h2c3b_s_n = np.array( [0.104351280732769e1, -0.227807912708513e1, 0.180535256723202e1, 0.420440834792042, -0.105721244834660e6, 0.436911607493884e25, -0.328032702839753e12, -0.678686760804270e16, 0.743957464645363e4, -0.356896445355761e20, 0.167590585186801e32, -0.355028625419105e38, 0.396611982166538e12, -0.414716268484468e41, 0.359080103867382e19, -0.116994334851995e41]) # Region 1 Region1_Li = np.array( [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 8, 8, 21, 23, 29, 30, 31, 32]) Region1_Lj = np.array( [-2, -1, 0, 1, 2, 3, 4, 5, -9, -7, -1, 0, 1, 3, -3, 0, 1, 3, 17, -4, 0, 6, -5, -2, 10, -8, -11, -6, -29, -31, -38, -39, -40, -41]) Region1_n = np.array( [0.14632971213167, -0.84548187169114, -3.756360367204, 0.33855169168385e1, -0.95791963387872, 0.15772038513228, -0.16616417199501e-1, 0.81214629983568e-3, 0.28319080123804e-3, -0.60706301565874e-3, -0.18990068218419e-1, -0.32529748770505e-1, -0.21841717175414e-1, -0.52838357969930e-4, -0.47184321073267e-3, -0.30001780793026e-3, 0.47661393906987e-4, -0.44141845330846e-5, -0.72694996297594e-15, -0.31679644845054e-4, -0.28270797985312e-5, -0.85205128120103e-9, -0.22425281908000e-5, -0.65171222895601e-6, -0.14341729937924e-12, -0.40516996860117e-6, -0.12734301741641e-8, -0.17424871230634e-9, -0.68762131295531e-18, 0.14478307828521e-19, 0.26335781662795e-22, -0.11947622640071e-22, 0.18228094581404e-23, -0.93537087292458e-25]) Region1_Li_less_1 = Region1_Li - 1 Region1_Lj_less_1 = Region1_Lj - 1 Region1_Li_less_2 = Region1_Li - 2 Region1_Lj_less_2 = Region1_Lj - 2 # _Backward1_T_Ph Backward1_T_Ph_Li = np.array( [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3, 4, 5, 6]) Backward1_T_Ph_Lj = np.array( [0, 1, 2, 6, 22, 32, 0, 1, 2, 3, 4, 10, 32, 10, 32, 10, 32, 32, 32, 32]) Backward1_T_Ph_n = np.array( [-0.23872489924521e3, 0.40421188637945e3, 0.11349746881718e3, -0.58457616048039e1, -0.15285482413140e-3, -0.10866707695377e-5, -0.13391744872602e2, 0.43211039183559e2, -0.54010067170506e2, 0.30535892203916e2, -0.65964749423638e1, 0.93965400878363e-2, 0.11573647505340e-6, -0.25858641282073e-4, -0.40644363084799e-8, 0.66456186191635e-7, 0.80670734103027e-10, -0.93477771213947e-12, 0.58265442020601e-14, -0.15020185953503e-16]) # _Backward1_T_Ps Backward1_T_Ps_Li = np.array( [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 4]) Backward1_T_Ps_Lj = np.array( [0, 1, 2, 3, 11, 31, 0, 1, 2, 3, 12, 31, 0, 1, 2, 9, 31, 10, 32, 32]) Backward1_T_Ps_n = np.array( [0.17478268058307e3, 0.34806930892873e2, 0.65292584978455e1, 0.33039981775489, -0.19281382923196e-6, -0.24909197244573e-22, -0.26107636489332, 0.22592965981586, -0.64256463395226e-1, 0.78876289270526e-2, 0.35672110607366e-9, 0.17332496994895e-23, 0.56608900654837e-3, -0.32635483139717e-3, 0.44778286690632e-4, -0.51322156908507e-9, -0.42522657042207e-25, 0.26400441360689e-12, 0.78124600459723e-28, -0.30732199903668e-30]) # _Backward1_P_hs Backward1_P_hs_Li = np.array( [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 4, 4, 5]) Backward1_P_hs_Lj = np.array( [0, 1, 2, 4, 5, 6, 8, 14, 0, 1, 4, 6, 0, 1, 10, 4, 1, 4, 0]) Backward1_P_hs_n = np.array( [-0.691997014660582, -0.183612548787560e2, -0.928332409297335e1, 0.659639569909906e2, -0.162060388912024e2, 0.450620017338667e3, 0.854680678224170e3, 0.607523214001162e4, 0.326487682621856e2, -0.269408844582931e2, -0.319947848334300e3, -0.928354307043320e3, 0.303634537455249e2, -0.650540422444146e2, -0.430991316516130e4, -0.747512324096068e3, 0.730000345529245e3, 0.114284032569021e4, -0.436407041874559e3]) # Region 2 Region2_Li = np.array( [1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, 10, 10, 10, 16, 16, 18, 20, 20, 20, 21, 22, 23, 24, 24, 24]) Region2_Lj = np.array( [0, 1, 2, 3, 6, 1, 2, 4, 7, 36, 0, 1, 3, 6, 35, 1, 2, 3, 7, 3, 16, 35, 0, 11, 25, 8, 36, 13, 4, 10, 14, 29, 50, 57, 20, 35, 48, 21, 53, 39, 26, 40, 58]) Region2_n = np.array( [-0.0017731742473212999, -0.017834862292357999, -0.045996013696365003, -0.057581259083432, -0.050325278727930002, -3.3032641670203e-05, -0.00018948987516315, -0.0039392777243355001, -0.043797295650572998, -2.6674547914087001e-05, 2.0481737692308999e-08, 4.3870667284435001e-07, -3.2277677238570002e-05, -0.0015033924542148, -0.040668253562648998, -7.8847309559367001e-10, 1.2790717852285001e-08, 4.8225372718507002e-07, 2.2922076337661001e-06, -1.6714766451061001e-11, -0.0021171472321354998, -23.895741934103999, -5.9059564324270004e-18, -1.2621808899101e-06, -0.038946842435739003, 1.1256211360459e-11, -8.2311340897998004, 1.9809712802088e-08, 1.0406965210174e-19, -1.0234747095929e-13, -1.0018179379511e-09, -8.0882908646984998e-11, 0.10693031879409, -0.33662250574170999, 8.9185845355420999e-25, 3.0629316876231997e-13, -4.2002467698208001e-06, -5.9056029685639003e-26, 3.7826947613457002e-06, -1.2768608934681e-15, 7.3087610595061e-29, 5.5414715350778001e-17, -9.4369707241209998e-07]) Region2_Li_less_1 = Region2_Li - 1 Region2_Lj_less_1 = Region2_Lj - 1 Region2_Li_less_2 = Region2_Li - 2 Region2_Lj_less_2 = Region2_Lj - 2 # Region 2 cp0 Region2_cp0_Jo = np.array([0, 1, -5, -4, -3, -2, -1, 2, 3]) Region2_cp0_no = np.array( [-0.96927686500217E+01, 0.10086655968018E+02, -0.56087911283020E-02, 0.71452738081455E-01, -0.40710498223928E+00, 0.14240819171444E+01, -0.43839511319450E+01, -0.28408632460772E+00, 0.21268463753307E-01]) Region2_cp0_no_meta = np.array( [-0.96937268393049E+01, 0.10087275970006E+02, -0.56087911283020E-02, 0.71452738081455E-01, -0.40710498223928E+00, 0.14240819171444E+01, -0.43839511319450E+01, -0.28408632460772E+00, 0.21268463753307E-01]) # Region2 metastable Region2_Ir_m = np.array([1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5]) Region2_Jr_m = np.array([0, 2, 5, 11, 1, 7, 16, 4, 16, 7, 10, 9, 10]) Region2_nr_m = np.array( [-0.73362260186506e-2, -0.88223831943146e-1, -0.72334555213245e-1, -0.40813178534455e-2, 0.20097803380207e-2, -0.53045921898642e-1, -0.76190409086970e-2, -0.63498037657313e-2, -0.86043093028588e-1, 0.75321581522770e-2, -0.79238375446139e-2, -0.22888160778447e-3, -0.26456501482810e-2]) Region2_Li_less_1_m = Region2_Ir_m - 1 Region2_Lj_less_1_m = Region2_Jr_m - 1 Region2_Li_less_2_m = Region2_Ir_m - 2 Region2_Lj_less_2_m = Region2_Jr_m - 2 # Backward2a_T_Ph Backward2a_T_Ph_Li = np.array( [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7]) Backward2a_T_Ph_Lj = np.array( [0, 1, 2, 3, 7, 20, 0, 1, 2, 3, 7, 9, 11, 18, 44, 0, 2, 7, 36, 38, 40, 42, 44, 24, 44, 12, 32, 44, 32, 36, 42, 34, 44, 28]) Backward2a_T_Ph_n = np.array( [0.10898952318288e4, 0.84951654495535e3, -0.10781748091826e3, 0.33153654801263e2, -0.74232016790248e1, 0.11765048724356e2, 0.18445749355790e1, -0.41792700549624e1, 0.62478196935812e1, -0.17344563108114e2, -0.20058176862096e3, 0.27196065473796e3, -0.45511318285818e3, 0.30919688604755e4, 0.25226640357872e6, -0.61707422868339e-2, -0.31078046629583, 0.11670873077107e2, 0.12812798404046e9, -0.98554909623276e9, 0.28224546973002e10, -0.35948971410703e10, 0.17227349913197e10, -0.13551334240775e5, 0.12848734664650e8, 0.13865724283226e1, 0.23598832556514e6, -0.13105236545054e8, 0.73999835474766e4, -0.55196697030060e6, 0.37154085996233e7, 0.19127729239660e5, -0.41535164835634e6, -0.62459855192507e2]) # Backward2b_T_Ph Backward2b_T_Ph_Li = np.array( [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 6, 7, 7, 9, 9]) Backward2b_T_Ph_Lj = np.array( [0, 1, 2, 12, 18, 24, 28, 40, 0, 2, 6, 12, 18, 24, 28, 40, 2, 8, 18, 40, 1, 2, 12, 24, 2, 12, 18, 24, 28, 40, 18, 24, 40, 28, 2, 28, 1, 40]) Backward2b_T_Ph_n = np.array( [0.14895041079516e4, 0.74307798314034e3, -0.97708318797837e2, 0.24742464705674e1, -0.63281320016026, 0.11385952129658e1, -0.47811863648625, 0.85208123431544e-2, 0.93747147377932, 0.33593118604916e1, 0.33809355601454e1, 0.16844539671904, 0.73875745236695, -0.47128737436186, 0.15020273139707, -0.21764114219750e-2, -0.21810755324761e-1, -0.10829784403677, -0.46333324635812e-1, 0.71280351959551e-4, 0.11032831789999e-3, 0.18955248387902e-3, 0.30891541160537e-2, 0.13555504554949e-2, 0.28640237477456e-6, -0.10779857357512e-4, -0.76462712454814e-4, 0.14052392818316e-4, -0.31083814331434e-4, -0.10302738212103e-5, 0.28217281635040e-6, 0.12704902271945e-5, 0.73803353468292e-7, -0.11030139238909e-7, -0.81456365207833e-13, -0.25180545682962e-10, -0.17565233969407e-17, 0.86934156344163e-14]) # Backward2c_T_Ph Backward2c_T_Ph_Li = np.array( [-7, -7, -6, -6, -5, -5, -2, -2, -1, -1, 0, 0, 1, 1, 2, 6, 6, 6, 6, 6, 6, 6, 6]) Backward2c_T_Ph_Lj = np.array( [0, 4, 0, 2, 0, 2, 0, 1, 0, 2, 0, 1, 4, 8, 4, 0, 1, 4, 10, 12, 16, 20, 22]) Backward2c_T_Ph_n = np.array( [-0.32368398555242e13, 0.73263350902181e13, 0.35825089945447e12, -0.58340131851590e12, -0.10783068217470e11, 0.20825544563171e11, 0.61074783564516e6, 0.85977722535580e6, -0.25745723604170e5, 0.31081088422714e5, 0.12082315865936e4, 0.48219755109255e3, 0.37966001272486e1, -0.10842984880077e2, -0.45364172676660e-1, 0.14559115658698e-12, 0.11261597407230e-11, -0.17804982240686e-10, 0.12324579690832e-6, -0.11606921130984e-5, 0.27846367088554e-4, -0.59270038474176e-3, 0.12918582991878e-2]) # Backward2a_T_Ps Backward2a_T_Ps_Li = np.array( [-1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.25, -1.25, -1.25, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -0.75, -0.75, -0.5, -0.5, -0.5, -0.5, -0.25, -0.25, -0.25, -0.25, 0.25, 0.25, 0.25, 0.25, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.75, 0.75, 0.75, 0.75, 1.0, 1.0, 1.25, 1.25, 1.5, 1.5]) Backward2a_T_Ps_Lj = np.array( [-24, -23, -19, -13, -11, -10, -19, -15, -6, -26, -21, -17, -16, -9, -8, -15, -14, -26, -13, -9, -7, -27, -25, -11, -6, 1, 4, 8, 11, 0, 1, 5, 6, 10, 14, 16, 0, 4, 9, 17, 7, 18, 3, 15, 5, 18]) Backward2a_T_Ps_n = np.array( [-0.39235983861984e6, 0.51526573827270e6, 0.40482443161048e5, -0.32193790923902e3, 0.96961424218694e2, -0.22867846371773e2, -0.44942914124357e6, -0.50118336020166e4, 0.35684463560015, 0.44235335848190e5, -0.13673388811708e5, 0.42163260207864e6, 0.22516925837475e5, 0.47442144865646e3, -0.14931130797647e3, -0.19781126320452e6, -0.23554399470760e5, -0.19070616302076e5, 0.55375669883164e5, 0.38293691437363e4, -0.60391860580567e3, 0.19363102620331e4, 0.42660643698610e4, -0.59780638872718e4, -0.70401463926862e3, 0.33836784107553e3, 0.20862786635187e2, 0.33834172656196e-1, -0.43124428414893e-4, 0.16653791356412e3, -0.13986292055898e3, -0.78849547999872, 0.72132411753872e-1, -0.59754839398283e-2, -0.12141358953904e-4, 0.23227096733871e-6, -0.10538463566194e2, 0.20718925496502e1, -0.72193155260427e-1, 0.20749887081120e-6, -0.18340657911379e-1, 0.29036272348696e-6, 0.21037527893619, 0.25681239729999e-3, -0.12799002933781e-1, -0.82198102652018e-5]) # Backward2b_T_Ps Backward2b_T_Ps_Li = np.array( [-6, -6, -5, -5, -4, -4, -4, -3, -3, -3, -3, -2, -2, -2, -2, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5]) Backward2b_T_Ps_Lj = np.array( [0, 11, 0, 11, 0, 1, 11, 0, 1, 11, 12, 0, 1, 6, 10, 0, 1, 5, 8, 9, 0, 1, 2, 4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 0, 1, 5, 0, 1, 3, 0, 1, 0, 1, 2]) Backward2b_T_Ps_n = np.array( [0.31687665083497e6, 0.20864175881858e2, -0.39859399803599e6, -0.21816058518877e2, 0.22369785194242e6, -0.27841703445817e4, 0.99207436071480e1, -0.75197512299157e5, 0.29708605951158e4, -0.34406878548526e1, 0.38815564249115, 0.17511295085750e5, -0.14237112854449e4, 0.10943803364167e1, 0.89971619308495, -0.33759740098958e4, 0.47162885818355e3, -0.19188241993679e1, 0.41078580492196, -0.33465378172097, 0.13870034777505e4, -0.40663326195838e3, 0.41727347159610e2, 0.21932549434532e1, -0.10320050009077e1, 0.35882943516703, 0.52511453726066e-2, 0.12838916450705e2, -0.28642437219381e1, 0.56912683664855, -0.99962954584931e-1, -0.32632037778459e-2, 0.23320922576723e-3, -0.15334809857450, 0.29072288239902e-1, 0.37534702741167e-3, 0.17296691702411e-2, -0.38556050844504e-3, -0.35017712292608e-4, -0.14566393631492e-4, 0.56420857267269e-5, 0.41286150074605e-7, -0.20684671118824e-7, 0.16409393674725e-8]) # Backward2c_T_Ps Backward2c_T_Ps_Li = np.array( [-2, -2, -1, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 7, 7]) Backward2c_T_Ps_Lj = np.array( [0, 1, 0, 0, 1, 2, 3, 0, 1, 3, 4, 0, 1, 2, 0, 1, 5, 0, 1, 4, 0, 1, 2, 0, 1, 0, 1, 3, 4, 5]) Backward2c_T_Ps_n = np.array( [0.90968501005365e3, 0.24045667088420e4, -0.59162326387130e3, 0.54145404128074e3, -0.27098308411192e3, 0.97976525097926e3, -0.46966772959435e3, 0.14399274604723e2, -0.19104204230429e2, 0.53299167111971e1, -0.21252975375934e2, -0.31147334413760, 0.60334840894623, -0.42764839702509e-1, 0.58185597255259e-2, -0.14597008284753e-1, 0.56631175631027e-2, -0.76155864584577e-4, 0.22440342919332e-3, -0.12561095013413e-4, 0.63323132660934e-6, -0.20541989675375e-5, 0.36405370390082e-7, -0.29759897789215e-8, 0.10136618529763e-7, 0.59925719692351e-11, -0.20677870105164e-10, -0.20874278181886e-10, 0.10162166825089e-9, -0.16429828281347e-9]) # Backward2a_P_hs Backward2a_P_hs_Li = np.array( [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 5, 5, 6, 7]) Backward2a_P_hs_Lj = np.array( [1, 3, 6, 16, 20, 22, 0, 1, 2, 3, 5, 6, 10, 16, 20, 22, 3, 16, 20, 0, 2, 3, 6, 16, 16, 3, 16, 3, 1]) Backward2a_P_hs_n = np.array( [-0.182575361923032e-1, -0.125229548799536, 0.592290437320145, 0.604769706185122e1, 0.238624965444474e3, -0.298639090222922e3, 0.512250813040750e-1, -0.437266515606486, 0.413336902999504, -0.516468254574773e1, -0.557014838445711e1, 0.128555037824478e2, 0.114144108953290e2, -0.119504225652714e3, -0.284777985961560e4, 0.431757846408006e4, 0.112894040802650e1, 0.197409186206319e4, 0.151612444706087e4, 0.141324451421235e-1, 0.585501282219601, -0.297258075863012e1, 0.594567314847319e1, -0.623656565798905e4, 0.965986235133332e4, 0.681500934948134e1, -0.633207286824489e4, -0.558919224465760e1, 0.400645798472063e-1]) # Backward2b_P_hs Backward2b_P_hs_Li = np.array( [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 8, 12, 14]) Backward2b_P_hs_Lj = np.array( [0, 1, 2, 4, 8, 0, 1, 2, 3, 5, 12, 1, 6, 18, 0, 1, 7, 12, 1, 16, 1, 12, 1, 8, 18, 1, 16, 1, 3, 14, 18, 10, 16]) Backward2b_P_hs_n = np.array( [0.801496989929495e-1, -0.543862807146111, 0.337455597421283, 0.890555451157450e1, 0.313840736431485e3, 0.797367065977789, -0.121616973556240e1, 0.872803386937477e1, -0.169769781757602e2, -0.186552827328416e3, 0.951159274344237e5, -0.189168510120494e2, -0.433407037194840e4, 0.543212633012715e9, 0.144793408386013, 0.128024559637516e3, -0.672309534071268e5, 0.336972380095287e8, -0.586634196762720e3, -0.221403224769889e11, 0.171606668708389e4, -0.570817595806302e9, -0.312109693178482e4, -0.207841384633010e7, 0.305605946157786e13, 0.322157004314333e4, 0.326810259797295e12, -0.144104158934487e4, 0.410694867802691e3, 0.109077066873024e12, -0.247964654258893e14, 0.188801906865134e10, -0.123651009018773e15]) # Backward2c_P_hs Backward2c_P_hs_Li = np.array( [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 6, 6, 10, 12, 16]) Backward2c_P_hs_Lj = np.array( [0, 1, 2, 3, 4, 8, 0, 2, 5, 8, 14, 2, 3, 7, 10, 18, 0, 5, 8, 16, 18, 18, 1, 4, 6, 14, 8, 18, 7, 7, 10]) Backward2c_P_hs_n = np.array( [0.112225607199012, -0.339005953606712e1, -0.320503911730094e2, -0.197597305104900e3, -0.407693861553446e3, 0.132943775222331e5, 0.170846839774007e1, 0.373694198142245e2, 0.358144365815434e4, 0.423014446424664e6, -0.751071025760063e9, 0.523446127607898e2, -0.228351290812417e3, -0.960652417056937e6, -0.807059292526074e8, 0.162698017225669e13, 0.772465073604171, 0.463929973837746e5, -0.137317885134128e8, 0.170470392630512e13, -0.251104628187308e14, 0.317748830835520e14, 0.538685623675312e2, -0.553089094625169e5, -0.102861522421405e7, 0.204249418756234e13, 0.273918446626977e9, -0.263963146312685e16, -0.107890854108088e10, -0.296492620980124e11, -0.111754907323424e16]) # Region 3 Region3_Li = np.array( [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 8, 9, 9, 10, 10, 11]) Region3_Lj = np.array( [0, 1, 2, 7, 10, 12, 23, 2, 6, 15, 17, 0, 2, 6, 7, 22, 26, 0, 2, 4, 16, 26, 0, 2, 4, 26, 1, 3, 26, 0, 2, 26, 2, 26, 2, 26, 0, 1, 26]) Region3_n = np.array( [-0.15732845290239e2, 0.20944396974307e2, -0.76867707878716e1, 0.26185947787954e1, -0.28080781148620e1, 0.12053369696517e1, -0.84566812812502e-2, -0.12654315477714e1, -0.11524407806681e1, 0.88521043984318, -0.64207765181607, 0.38493460186671, -0.85214708824206, 0.48972281541877e1, -0.30502617256965e1, 0.39420536879154e-1, 0.12558408424308, -0.27999329698710, 0.13899799569460e1, -0.20189915023570e1, -0.82147637173963e-2, -0.47596035734923, 0.43984074473500e-1, -0.44476435428739, 0.90572070719733, .70522450087967, .10770512626332, -0.32913623258954, -0.50871062041158, -0.22175400873096e-1, 0.94260751665092e-1, 0.16436278447961, -0.13503372241348e-1, -0.14834345352472e-1, 0.57922953628084e-3, 0.32308904703711e-2, 0.80964802996215e-4, -0.16557679795037e-3, -0.44923899061815e-4]) Region3_Li_less_1 = Region3_Li - 1 Region3_Lj_less_1 = Region3_Lj - 1 Region3_Li_less_2 = Region3_Li - 2 Region3_Lj_less_2 = Region3_Lj - 2 # tab_P tab_P_Li = np.array([0, 1, 2, -1, -2]) tab_P_n = np.array( [0.154793642129415e4, -0.187661219490113e3, 0.213144632222113e2, -0.191887498864292e4, 0.918419702359447e3]) # top_P top_P_Li = np.array([0, 1, 2, -1, -2]) top_P_n = np.array( [0.969461372400213e3, -0.332500170441278e3, 0.642859598466067e2, 0.773845935768222e3, -0.152313732937084e4]) # twx_P twx_P_Li = np.array([0, 1, 2, -1, -2]) twx_P_n = np.array( [0.728052609145380e1, 0.973505869861952e2, 0.147370491183191e2, 0.329196213998375e3, 0.873371668682417e3]) # Backward3a_V_Ph Backward3a_v_Ph_Li = np.array( [-12, -12, -12, -12, -10, -10, -10, -8, -8, -6, -6, -6, -4, -4, -3, -2, -2, -1, -1, -1, -1, 0, 0, 1, 1, 1, 2, 2, 3, 4, 5, 8]) Backward3a_v_Ph_Lj = np.array( [6, 8, 12, 18, 4, 7, 10, 5, 12, 3, 4, 22, 2, 3, 7, 3, 16, 0, 1, 2, 3, 0, 1, 0, 1, 2, 0, 2, 0, 2, 2, 2]) Backward3a_v_Ph_n = np.array( [0.529944062966028e-2, -0.170099690234461, 0.111323814312927e2, -0.217898123145125e4, -0.506061827980875e-3, 0.556495239685324, -0.943672726094016e1, -0.297856807561527, 0.939353943717186e2, 0.192944939465981e-1, 0.421740664704763, -0.368914126282330e7, -0.737566847600639e-2, -0.354753242424366, -0.199768169338727e1, 0.115456297059049e1, 0.568366875815960e4, 0.808169540124668e-2, 0.172416341519307, 0.104270175292927e1, -0.297691372792847, 0.560394465163593, 0.275234661176914, -0.148347894866012, -0.651142513478515e-1, -0.292468715386302e1, 0.664876096952665e-1, 0.352335014263844e1, -0.146340792313332e-1, -0.224503486668184e1, 0.110533464706142e1, -0.408757344495612e-1]) # Backward3b_V_Ph Backward3b_v_Ph_Li = np.array( [-12, -12, -8, -8, -8, -8, -8, -8, -6, -6, -6, -6, -6, -6, -4, -4, -4, -3, -3, -2, -2, -1, -1, -1, -1, 0, 1, 1, 2, 2]) Backward3b_v_Ph_Lj = np.array( [0, 1, 0, 1, 3, 6, 7, 8, 0, 1, 2, 5, 6, 10, 3, 6, 10, 0, 2, 1, 2, 0, 1, 4, 5, 0, 0, 1, 2, 6]) Backward3b_v_Ph_n = np.array( [-0.225196934336318e-8, 0.140674363313486e-7, 0.233784085280560e-5, -0.331833715229001e-4, 0.107956778514318e-2, -0.271382067378863, 0.107202262490333e1, -0.853821329075382, -0.215214194340526e-4, 0.769656088222730e-3, -0.431136580433864e-2, 0.453342167309331, -0.507749535873652, -0.100475154528389e3, -0.219201924648793, -0.321087965668917e1, 0.607567815637771e3, 0.557686450685932e-3, 0.187499040029550, 0.905368030448107e-2, 0.285417173048685, 0.329924030996098e-1, 0.239897419685483, 0.482754995951394e1, -0.118035753702231e2, 0.169490044091791, -0.179967222507787e-1, 0.371810116332674e-1, -0.536288335065096e-1, 0.160697101092520e1]) # Backward3a_T_Ph Backward3a_T_Ph_Li = np.array( [-12, -12, -12, -12, -12, -12, -12, -12, -10, -10, -10, -8, -8, -8, -8, -5, -3, -2, -2, -2, -1, -1, 0, 0, 1, 3, 3, 4, 4, 10, 12]) Backward3a_T_Ph_Lj = np.array( [0, 1, 2, 6, 14, 16, 20, 22, 1, 5, 12, 0, 2, 4, 10, 2, 0, 1, 3, 4, 0, 2, 0, 1, 1, 0, 1, 0, 3, 4, 5]) Backward3a_T_Ph_n = np.array( [-0.133645667811215e-6, 0.455912656802978e-5, -0.146294640700979e-4, 0.639341312970080e-2, 0.372783927268847e3, -0.718654377460447e4, 0.573494752103400e6, -0.267569329111439e7, -0.334066283302614e-4, -0.245479214069597e-1, 0.478087847764996e2, 0.764664131818904e-5, 0.128350627676972e-2, 0.171219081377331e-1, -0.851007304583213e1, -0.136513461629781e-1, -0.384460997596657e-5, 0.337423807911655e-2, -0.551624873066791, 0.729202277107470, -0.992522757376041e-2, -.119308831407288, .793929190615421, .454270731799386, .20999859125991, -0.642109823904738e-2, -0.235155868604540e-1, 0.252233108341612e-2, -0.764885133368119e-2, 0.136176427574291e-1, -0.133027883575669e-1]) # Backward3b_T_Ph Backward3b_T_Ph_Li = np.array( [-12, -12, -10, -10, -10, -10, -10, -8, -8, -8, -8, -8, -6, -6, -6, -4, -4, -3, -2, -2, -1, -1, -1, -1, -1, -1, 0, 0, 1, 3, 5, 6, 8]) Backward3b_T_Ph_Lj = np.array( [0, 1, 0, 1, 5, 10, 12, 0, 1, 2, 4, 10, 0, 1, 2, 0, 1, 5, 0, 4, 2, 4, 6, 10, 14, 16, 0, 2, 1, 1, 1, 1, 1]) Backward3b_T_Ph_n = np.array( [0.323254573644920e-4, -0.127575556587181e-3, -0.475851877356068e-3, 0.156183014181602e-2, 0.105724860113781, -0.858514221132534e2, 0.724140095480911e3, 0.296475810273257e-2, -0.592721983365988e-2, -0.126305422818666e-1, -0.115716196364853, 0.849000969739595e2, -0.108602260086615e-1, 0.154304475328851e-1, 0.750455441524466e-1, 0.252520973612982e-1, -0.602507901232996e-1, -0.307622221350501e1, -0.574011959864879e-1, 0.503471360939849e1, -0.925081888584834, 0.391733882917546e1, -0.773146007130190e2, 0.949308762098587e4, -0.141043719679409e7, 0.849166230819026e7, 0.861095729446704, 0.323346442811720, 0.873281936020439, -0.436653048526683, 0.286596714529479, -0.131778331276228, 0.676682064330275e-2]) # Backward3a_v_Ps Backward3a_v_Ps_Li = np.array( [-12, -12, -12, -10, -10, -10, -10, -8, -8, -8, -8, -6, -5, -4, -3, -3, -2, -2, -1, -1, 0, 0, 0, 1, 2, 4, 5, 6]) Backward3a_v_Ps_Lj = np.array( [10, 12, 14, 4, 8, 10, 20, 5, 6, 14, 16, 28, 1, 5, 2, 4, 3, 8, 1, 2, 0, 1, 3, 0, 0, 2, 2, 0]) Backward3a_v_Ps_n = np.array( [0.795544074093975e2, -0.238261242984590e4, 0.176813100617787e5, -0.110524727080379e-2, -0.153213833655326e2, 0.297544599376982e3, -0.350315206871242e8, 0.277513761062119, -0.523964271036888, -0.148011182995403e6, 0.160014899374266e7, 0.170802322663427e13, 0.246866996006494e-3, 0.165326084797980e1, -0.118008384666987, 0.253798642355900e1, 0.965127704669424, -0.282172420532826e2, 0.203224612353823, 0.110648186063513e1, 0.526127948451280, 0.277000018736321, 0.108153340501132e1, -0.744127885357893e-1, 0.164094443541384e-1, -0.680468275301065e-1, 0.257988576101640e-1, -0.145749861944416e-3]) # Backward3b_v_Ps Backward3b_v_Ps_Li = np.array( [-12, -12, -12, -12, -12, -12, -10, -10, -10, -10, -8, -5, -5, -5, -4, -4, -4, -4, -3, -2, -2, -2, -2, -2, -2, 0, 0, 0, 1, 1, 2]) Backward3b_v_Ps_Lj = np.array( [0, 1, 2, 3, 5, 6, 0, 1, 2, 4, 0, 1, 2, 3, 0, 1, 2, 3, 1, 0, 1, 2, 3, 4, 12, 0, 1, 2, 0, 2, 2]) Backward3b_v_Ps_n = np.array( [0.591599780322238e-4, -0.185465997137856e-2, 0.104190510480013e-1, 0.598647302038590e-2, -0.771391189901699, 0.172549765557036e1, -0.467076079846526e-3, 0.134533823384439e-1, -0.808094336805495e-1, 0.508139374365767, 0.128584643361683e-2, -0.163899353915435e1, 0.586938199318063e1, -0.292466667918613e1, -0.614076301499537e-2, 0.576199014049172e1, -0.121613320606788e2, 0.167637540957944e1, -0.744135838773463e1, 0.378168091437659e-1, 0.401432203027688e1, 0.160279837479185e2, 0.317848779347728e1, -0.358362310304853e1, -0.115995260446827e7, 0.199256573577909, -0.122270624794624, -0.191449143716586e2, -0.150448002905284e-1, 0.146407900162154e2, -0.327477787188230e1]) # Backward3a_T_Ps Backward3a_T_Ps_Li = np.array( [-12, -12, -10, -10, -10, -10, -8, -8, -8, -8, -6, -6, -6, -5, -5, -5, -4, -4, -4, -2, -2, -1, -1, 0, 0, 0, 1, 2, 2, 3, 8, 8, 10]) Backward3a_T_Ps_Lj = np.array( [28, 32, 4, 10, 12, 14, 5, 7, 8, 28, 2, 6, 32, 0, 14, 32, 6, 10, 36, 1, 4, 1, 6, 0, 1, 4, 0, 0, 3, 2, 0, 1, 2]) Backward3a_T_Ps_n = np.array( [0.150042008263875e10, -0.159397258480424e12, 0.502181140217975e-3, -0.672057767855466e2, 0.145058545404456e4, -0.823889534888890e4, -0.154852214233853, 0.112305046746695e2, -0.297000213482822e2, 0.438565132635495e11, 0.137837838635464e-2, -0.297478527157462e1, 0.971777947349413e13, -0.571527767052398e-4, 0.288307949778420e5, -0.744428289262703e14, 0.128017324848921e2, -0.368275545889071e3, 0.664768904779177e16, 0.449359251958880e-1, -0.422897836099655e1, -0.240614376434179, -0.474341365254924e1, 0.724093999126110, 0.923874349695897, 0.399043655281015e1, 0.384066651868009e-1, -0.359344365571848e-2, -0.735196448821653, 0.188367048396131, 0.141064266818704e-3, -0.257418501496337e-2, 0.123220024851555e-2]) # Backward3b_T_Ps Backward3b_T_Ps_Li = np.array( [-12, -12, -12, -12, -8, -8, -8, -6, -6, -6, -5, -5, -5, -5, -5, -4, -3, -3, -2, 0, 2, 3, 4, 5, 6, 8, 12, 14]) Backward3b_T_Ps_Lj = np.array( [1, 3, 4, 7, 0, 1, 3, 0, 2, 4, 0, 1, 2, 4, 6, 12, 1, 6, 2, 0, 1, 1, 0, 24, 0, 3, 1, 2]) Backward3b_T_Ps_n = np.array( [0.527111701601660, -0.401317830052742e2, 0.153020073134484e3, -0.224799398218827e4, -0.193993484669048, -0.140467557893768e1, 0.426799878114024e2, 0.752810643416743, 0.226657238616417e2, -0.622873556909932e3, -0.660823667935396, 0.841267087271658, -0.253717501764397e2, 0.485708963532948e3, 0.880531517490555e3, 0.265015592794626e7, -0.359287150025783, -0.656991567673753e3, 0.241768149185367e1, 0.856873461222588, 0.655143675313458, -0.213535213206406, 0.562974957606348e-2, -0.316955725450471e15, -0.699997000152457e-3, 0.119845803210767e-1, 0.193848122022095e-4, -0.215095749182309e-4]) # Backward3a_P_hs Backward3a_P_hs_Li = np.array( [0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 6, 7, 8, 10, 10, 14, 18, 20, 22, 22, 24, 28, 28, 32, 32]) Backward3a_P_hs_Lj = np.array( [0, 1, 5, 0, 3, 4, 8, 14, 6, 16, 0, 2, 3, 0, 1, 4, 5, 28, 28, 24, 1, 32, 36, 22, 28, 36, 16, 28, 36, 16, 36, 10, 28]) Backward3a_P_hs_n = np.array( [0.770889828326934e1, -0.260835009128688e2, 0.267416218930389e3, 0.172221089496844e2, -0.293542332145970e3, 0.614135601882478e3, -0.610562757725674e5, -0.651272251118219e8, 0.735919313521937e5, -0.116646505914191e11, 0.355267086434461e2, -0.596144543825955e3, -0.475842430145708e3, 0.696781965359503e2, 0.335674250377312e3, 0.250526809130882e5, 0.146997380630766e6, 0.538069315091534e20, 0.143619827291346e22, 0.364985866165994e20, -0.254741561156775e4, 0.240120197096563e28, -0.393847464679496e30, 0.147073407024852e25, -0.426391250432059e32, 0.194509340621077e39, 0.666212132114896e24, 0.706777016552858e34, 0.175563621975576e42, 0.108408607429124e29, 0.730872705175151e44, 0.159145847398870e25, 0.377121605943324e41]) # Backward3b_P_hs Backward3b_P_hs_Li = np.array( [-12, -12, -12, -12, -12, -10, -10, -10, -10, -8, -8, -6, -6, -6, -6, -5, -4, -4, -4, -3, -3, -3, -3, -2, -2, -1, 0, 2, 2, 5, 6, 8, 10, 14, 14]) Backward3b_P_hs_Lj = np.array( [2, 10, 12, 14, 20, 2, 10, 14, 18, 2, 8, 2, 6, 7, 8, 10, 4, 5, 8, 1, 3, 5, 6, 0, 1, 0, 3, 0, 1, 0, 1, 1, 1, 3, 7]) Backward3b_P_hs_n = np.array( [0.125244360717979e-12, -0.126599322553713e-1, 0.506878030140626e1, 0.317847171154202e2, -0.391041161399932e6, -0.975733406392044e-10, -0.186312419488279e2, 0.510973543414101e3, 0.373847005822362e6, 0.299804024666572e-7, 0.200544393820342e2, -0.498030487662829e-5, -0.102301806360030e2, 0.552819126990325e2, -0.206211367510878e3, -0.794012232324823e4, 0.782248472028153e1, -0.586544326902468e2, 0.355073647696481e4, -0.115303107290162e-3, -0.175092403171802e1, 0.257981687748160e3, -0.727048374179467e3, 0.121644822609198e-3, 0.393137871762692e-1, 0.704181005909296e-2, -0.829108200698110e2, -0.265178818131250, 0.137531682453991e2, -0.522394090753046e2, 0.240556298941048e4, -0.227361631268929e5, 0.890746343932567e5, -0.239234565822486e8, 0.568795808129714e10]) # Backward3_v_PT Backward3_v_PT_par = { "a": (0.0024, 100, 760, 0.085, 0.817, 1, 1, 1), "b": (0.0041, 100, 860, 0.280, 0.779, 1, 1, 1), "c": (0.0022, 40, 690, 0.259, 0.903, 1, 1, 1), "d": (0.0029, 40, 690, 0.559, 0.939, 1, 1, 4), "e": (0.0032, 40, 710, 0.587, 0.918, 1, 1, 1), "f": (0.0064, 40, 730, 0.587, 0.891, 0.5, 1, 4), "g": (0.0027, 25, 660, 0.872, 0.971, 1, 1, 4), "h": (0.0032, 25, 660, 0.898, 0.983, 1, 1, 4), "i": (0.0041, 25, 660, 0.910, 0.984, 0.5, 1, 4), "j": (0.0054, 25, 670, 0.875, 0.964, 0.5, 1, 4), "k": (0.0077, 25, 680, 0.802, 0.935, 1, 1, 1), "l": (0.0026, 24, 650, 0.908, 0.989, 1, 1, 4), "m": (0.0028, 23, 650, 1.000, 0.997, 1, 0.25, 1), "n": (0.0031, 23, 650, 0.976, 0.997, None, None, None), "o": (0.0034, 23, 650, 0.974, 0.996, 0.5, 1, 1), "p": (0.0041, 23, 650, 0.972, 0.997, 0.5, 1, 1), "q": (0.0022, 23, 650, 0.848, 0.983, 1, 1, 4), "r": (0.0054, 23, 650, 0.874, 0.982, 1, 1, 1), "s": (0.0022, 21, 640, 0.886, 0.990, 1, 1, 4), "t": (0.0088, 20, 650, 0.803, 1.020, 1, 1, 1), "u": (0.0026, 23, 650, 0.902, 0.988, 1, 1, 1), "v": (0.0031, 23, 650, 0.960, 0.995, 1, 1, 1), "w": (0.0039, 23, 650, 0.959, 0.995, 1, 1, 4), "x": (0.0049, 23, 650, 0.910, 0.988, 1, 1, 1), "y": (0.0031, 22, 650, 0.996, 0.994, 1, 1, 4), "z": (0.0038, 22, 650, 0.993, 0.994, 1, 1, 4)} Backward3_v_PT_Li = { "a": np.array( [-12, -12, -12, -10, -10, -10, -8, -8, -8, -6, -5, -5, -5, -4, -3, -3, -3, -3, -2, -2, -2, -1, -1, -1, 0, 0, 1, 1, 2, 2]), "b": np.array( [-12, -12, -10, -10, -8, -6, -6, -6, -5, -5, -5, -4, -4, -4, -3, -3, -3, -3, -3, -2, -2, -2, -1, -1, 0, 0, 1, 1, 2, 3, 4, 4]), "c": np.array( [-12, -12, -12, -10, -10, -10, -8, -8, -8, -6, -5, -5, -5, -4, -4, -3, -3, -2, -2, -2, -1, -1, -1, 0, 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 8]), "d": np.array( [-12, -12, -12, -12, -12, -12, -10, -10, -10, -10, -10, -10, -10, -8, -8, -8, -8, -6, -6, -5, -5, -5, -5, -4, -4, -4, -3, -3, -2, -2, -1, -1, -1, 0, 0, 1, 1, 3]), "e": np.array( [-12, -12, -10, -10, -10, -10, -10, -8, -8, -8, -6, -5, -4, -4, -3, -3, -3, -2, -2, -2, -2, -1, 0, 0, 1, 1, 1, 2, 2]), "f": np.array( [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 5, 5, 6, 7, 7, 10, 12, 12, 12, 14, 14, 14, 14, 14, 16, 16, 18, 18, 20, 20, 20, 22, 24, 24, 28, 32]), "g": np.array( [-12, -12, -12, -12, -12, -12, -10, -10, -10, -8, -8, -8, -8, -6, -6, -5, -5, -4, -3, -2, -2, -2, -2, -1, -1, -1, 0, 0, 0, 1, 1, 1, 3, 5, 6, 8, 10, 10]), "h": np.array( [-12, -12, -10, -10, -10, -10, -10, -10, -8, -8, -8, -8, -8, -6, -6, -6, -5, -5, -5, -4, -4, -3, -3, -2, -1, -1, 0, 1, 1]), "i": np.array( [0, 0, 0, 1, 1, 1, 1, 2, 3, 3, 4, 4, 4, 5, 5, 5, 7, 7, 8, 8, 10, 12, 12, 12, 14, 14, 14, 14, 18, 18, 18, 18, 18, 20, 20, 22, 24, 24, 32, 32, 36, 36]), "j": np.array( [0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 5, 5, 6, 10, 12, 12, 14, 14, 14, 16, 18, 20, 20, 24, 24, 28, 28]), "k": np.array( [-2, -2, -1, -1, 0, -0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 5, 5, 5, 6, 6, 6, 6, 8, 10, 12]), "l": np.array( [-12, -12, -12, -12, -12, -10, -10, -8, -8, -8, -8, -8, -8, -8, -6, -5, -5, -4, -4, -3, -3, -3, -3, -2, -2, -2, -1, -1, -1, 0, 0, 0, 0, 1, 1, 2, 4, 5, 5, 6, 10, 10, 14]), "m": np.array( [0, 3, 8, 20, 1, 3, 4, 5, 1, 6, 2, 4, 14, 2, 5, 3, 0, 1, 1, 1, 28, 2, 16, 0, 5, 0, 3, 4, 12, 16, 1, 8, 14, 0, 2, 3, 4, 8, 14, 24]), "n": np.array( [0, 3, 4, 6, 7, 10, 12, 14, 18, 0, 3, 5, 6, 8, 12, 0, 3, 7, 12, 2, 3, 4, 2, 4, 7, 4, 3, 5, 6, 0, 0, 3, 1, 0, 1, 0, 1, 0, 1]), "o": np.array( [0, 0, 0, 2, 3, 4, 4, 4, 4, 4, 5, 5, 6, 7, 8, 8, 8, 10, 10, 14, 14, 20, 20, 24]), "p": np.array( [0, 0, 0, 0, 1, 2, 3, 3, 4, 6, 7, 7, 8, 10, 12, 12, 12, 14, 14, 14, 16, 18, 20, 22, 24, 24, 36]), "q": np.array( [-12, -12, -10, -10, -10, -10, -8, -6, -5, -5, -4, -4, -3, -2, -2, -2, -2, -1, -1, -1, 0, 1, 1, 1]), "r": np.array( [-8, -8, -3, -3, -3, -3, -3, 0, 0, 0, 0, 3, 3, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 12, 14]), "s": np.array( [-12, -12, -10, -8, -6, -5, -5, -4, -4, -3, -3, -2, -1, -1, -1, 0, 0, 0, 0, 1, 1, 3, 3, 3, 4, 4, 4, 5, 14]), "t": np.array( [0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10, 18, 20, 22, 22, 24, 28, 32, 32, 32, 36]), "u": np.array( [-12, -10, -10, -10, -8, -8, -8, -6, -6, -5, -5, -5, -3, -1, -1, -1, -1, 0, 0, 1, 2, 2, 3, 5, 5, 5, 6, 6, 8, 8, 10, 12, 12, 12, 14, 14, 14, 14]), "v": np.array( [-10, -8, -6, -6, -6, -6, -6, -6, -5, -5, -5, -5, -5, -5, -4, -4, -4, -4, -3, -3, -3, -2, -2, -1, -1, 0, 0, 0, 1, 1, 3, 4, 4, 4, 5, 8, 10, 12, 14]), "w": np.array( [-12, -12, -10, -10, -8, -8, -8, -6, -6, -6, -6, -5, -4, -4, -3, -3, -2, -2, -1, -1, -1, 0, 0, 1, 2, 2, 3, 3, 5, 5, 5, 8, 8, 10, 10]), "x": np.array( [-8, -6, -5, -4, -4, -4, -3, -3, -1, 0, 0, 0, 1, 1, 2, 3, 3, 3, 4, 5, 5, 5, 6, 8, 8, 8, 8, 10, 12, 12, 12, 12, 14, 14, 14, 14]), "y": np.array( [0, 0, 0, 0, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 8, 8, 10, 12]), "z": np.array( [-8, -6, -5, -5, -4, -4, -4, -3, -3, -3, -2, -1, 0, 1, 2, 3, 3, 6, 6, 6, 6, 8, 8])} Backward3_v_PT_Lj = { "a": np.array([5, 10, 12, 5, 10, 12, 5, 8, 10, 1, 1, 5, 10, 8, 0, 1, 3, 6, 0, 2, 3, 0, 1, 2, 0, 1, 0, 2, 0, 2]), "b": np.array([10, 12, 8, 14, 8, 5, 6, 8, 5, 8, 10, 2, 4, 5, 0, 1, 2, 3, 5, 0, 2, 5, 0, 2, 0, 1, 0, 2, 0, 2, 0, 1]), "c": np.array([6, 8, 10, 6, 8, 10, 5, 6, 7, 8, 1, 4, 7, 2, 8, 0, 3, 0, 4, 5, 0, 1, 2, 0, 1, 2, 0, 2, 0, 1, 3, 7, 0, 7, 1]), "d": np.array([4, 6, 7, 10, 12, 16, 0, 2, 4, 6, 8, 10, 14, 3, 7, 8, 10, 6, 8, 1, 2, 5, 7, 0, 1, 7, 2, 4, 0, 1, 0, 1, 5, 0, 2, 0, 6, 0]), "e": np.array([14, 16, 3, 6, 10, 14, 16, 7, 8, 10, 6, 6, 2, 4, 2, 6, 7, 0, 1, 3, 4, 0, 0, 1, 0, 4, 6, 0, 2]), "f": np.array([-3, -2, -1, 0, 1, 2, -1, 1, 2, 3, 0, 1, -5, -2, 0, -3, -8, 1, -6, -4, 1, -6, -10, -8, -4, -12, -10, -8, -6, -4, -10, -8, -12, -10, -12, -10, -6, -12, -12, -4, -12, -12]), "g": np.array([7, 12, 14, 18, 22, 24, 14, 20, 24, 7, 8, 10, 12, 8, 22, 7, 20, 22, 7, 3, 5, 14, 24, 2, 8, 18, 0, 1, 2, 0, 1, 3, 24, 22, 12, 3, 0, 6]), "h": np.array([8, 12, 4, 6, 8, 10, 14, 16, 0, 1, 6, 7, 8, 4, 6, 8, 2, 3, 4, 2, 4, 1, 2, 0, 0, 2, 0, 0, 2]), "i": np.array([0, 1, 10, -4, -2, -1, 0, 0, -5, 0, -3, -2, -1, -6, -1, 12, -4, -3, -6, 10, -8, -12, -6, -4, -10, -8, -4, 5, -12, -10, -8, -6, 2, -12, -10, -12, -12, -8, -10, -5, -10, -8]), "j": np.array([-1, 0, 1, -2, -1, 1, -1, 1, -2, -2, 2, -3, -2, 0, 3, -6, -8, -3, -10, -8, -5, -10, -12, -12, -10, -12, -6, -12, -5]), "k": np.array([10, 12, -5, 6, -12, -6, -2, -1, 0, 1, 2, 3, 14, -3, -2, 0, 1, 2, -8, -6, -3, -2, 0, 4, -12, -6, -3, -12, -10, -8, -5, -12, -12, -10]), "l": np.array([14, 16, 18, 20, 22, 14, 24, 6, 10, 12, 14, 18, 24, 36, 8, 4, 5, 7, 16, 1, 3, 18, 20, 2, 3, 10, 0, 1, 3, 0, 1, 2, 12, 0, 16, 1, 0, 0, 1, 14, 4, 12, 10]), "m": np.array([0, 0, 0, 2, 5, 5, 5, 5, 6, 6, 7, 8, 8, 10, 10, 12, 14, 14, 18, 20, 20, 22, 22, 24, 24, 28, 28, 28, 28, 28, 32, 32, 32, 36, 36, 36, 36, 36, 36, 36]), "n": np.array([-12, -12, -12, -12, -12, -12, -12, -12, -12, -10, -10, -10, -10, -10, -10, -8, -8, -8, -8, -6, -6, -6, -5, -5, -5, -4, -3, -3, -3, -2, -1, -1, 0, 1, 1, 2, 4, 5, 6]), "o": np.array([-12, -4, -1, -1, -10, -12, -8, -5, -4, -1, -4, -3, -8, -12, -10, -8, -4, -12, -8, -12, -8, -12, -10, -12]), "p": np.array([-1, 0, 1, 2, 1, -1, -3, 0, -2, -2, -5, -4, -2, -3, -12, -6, -5, -10, -8, -3, -8, -8, -10, -10, -12, -8, -12]), "q": np.array([10, 12, 6, 7, 8, 10, 8, 6, 2, 5, 3, 4, 3, 0, 1, 2, 4, 0, 1, 2, 0, 0, 1, 3]), "r": np.array([6, 14, -3, 3, 4, 5, 8, -1, 0, 1, 5, -6, -2, -12, -10, -8, -5, -12, -10, -8, -6, -5, -4, -3, -2, -12, -12]), "s": np.array([20, 24, 22, 14, 36, 8, 16, 6, 32, 3, 8, 4, 1, 2, 3, 0, 1, 4, 28, 0, 32, 0, 1, 2, 3, 18, 24, 4, 24]), "t": np.array([0, 1, 4, 12, 0, 10, 0, 6, 14, 3, 8, 0, 10, 3, 4, 7, 20, 36, 10, 12, 14, 16, 22, 18, 32, 22, 36, 24, 28, 22, 32, 36, 36]), "u": np.array([14, 10, 12, 14, 10, 12, 14, 8, 12, 4, 8, 12, 2, -1, 1, 12, 14, -3, 1, -2, 5, 10, -5, -4, 2, 3, -5, 2, -8, 8, -4, -12, -4, 4, -12, -10, -6, 6]), "v": np.array([-8, -12, -12, -3, 5, 6, 8, 10, 1, 2, 6, 8, 10, 14, -12, -10, -6, 10, -3, 10, 12, 2, 4, -2, 0, -2, 6, 10, -12, -10, 3, -6, 3, 10, 2, -12, -2, -3, 1]), "w": np.array([8, 14, -1, 8, 6, 8, 14, -4, -3, 2, 8, -10, -1, 3, -10, 3, 1, 2, -8, -4, 1, -12, 1, -1, -1, 2, -12, -5, -10, -8, -6, -12, -10, -12, -8]), "x": np.array([14, 10, 10, 1, 2, 14, -2, 12, 5, 0, 4, 10, -10, -1, 6, -12, 0, 8, 3, -6, -2, 1, 1, -6, -3, 1, 8, -8, -10, -8, -5, -4, -12, -10, -8, -6]), "y": np.array([-3, 1, 5, 8, 8, -4, -1, 4, 5, -8, 4, 8, -6, 6, -2, 1, -8, -2, -5, -8]), "z": np.array([3, 6, 6, 8, 5, 6, 8, -2, 5, 6, 2, -6, 3, 1, 6, -6, -2, -6, -5, -4, -1, -8, -4])} Backward3_v_PT_n = { "a": np.array( [0.110879558823853e-2, 0.572616740810616e3, -0.767051948380852e5, -0.253321069529674e-1, 0.628008049345689e4, 0.234105654131876e6, 0.216867826045856, -0.156237904341963e3, -0.269893956176613e5, -0.180407100085505e-3, 0.116732227668261e-2, 0.266987040856040e2, 0.282776617243286e5, -0.242431520029523e4, 0.435217323022733e-3, -0.122494831387441e-1, 0.179357604019989e1, 0.442729521058314e2, -0.593223489018342e-2, 0.453186261685774, 0.135825703129140e1, 0.408748415856745e-1, 0.474686397863312, 0.118646814997915e1, 0.546987265727549, 0.195266770452643, -0.502268790869663e-1, -0.369645308193377, 0.633828037528420e-2, 0.797441793901017e-1]), "b": np.array( [-0.827670470003621e-1, 0.416887126010565e2, 0.483651982197059e-1, -0.291032084950276e5, -0.111422582236948e3, -.202300083904014e-1, 0.294002509338515e3, 0.140244997609658e3, -0.344384158811459e3, 0.361182452612149e3, -0.140699677420738e4, -0.202023902676481e-2, 0.171346792457471e3, -0.425597804058632e1, 0.691346085000334e-5, 0.151140509678925e-2, -0.416375290166236e-1, -.413754957011042e2, -0.506673295721637e2, -0.572212965569023e-3, 0.608817368401785e1, 0.239600660256161e2, 0.122261479925384e-1, 0.216356057692938e1, 0.398198903368642, -0.116892827834085, -0.102845919373532, -0.492676637589284, 0.655540456406790e-1, -0.240462535078530, -0.269798180310075e-1, 0.128369435967012]), "c": np.array( [0.311967788763030e1, 0.276713458847564e5, 0.322583103403269e8, -0.342416065095363e3, -0.899732529907377e6, -0.793892049821251e8, 0.953193003217388e2, 0.229784742345072e4, 0.175336675322499e6, 0.791214365222792e7, 0.319933345844209e-4, -0.659508863555767e2, -0.833426563212851e6, 0.645734680583292e-1, -0.382031020570813e7, 0.406398848470079e-4, 0.310327498492008e2, -0.892996718483724e-3, 0.234604891591616e3, 0.377515668966951e4, 0.158646812591361e-1, 0.707906336241843, 0.126016225146570e2, 0.736143655772152, 0.676544268999101, -0.178100588189137e2, -0.156531975531713, 0.117707430048158e2, 0.840143653860447e-1, -0.186442467471949, -0.440170203949645e2, 0.123290423502494e7, -0.240650039730845e-1, -0.107077716660869e7, 0.438319858566475e-1]), "d": np.array( [-0.452484847171645e-9, .315210389538801e-4, -.214991352047545e-2, 0.508058874808345e3, -0.127123036845932e8, 0.115371133120497e13, -.197805728776273e-15, .241554806033972e-10, -.156481703640525e-5, 0.277211346836625e-2, -0.203578994462286e2, 0.144369489909053e7, -0.411254217946539e11, 0.623449786243773e-5, -.221774281146038e2, -0.689315087933158e5, -0.195419525060713e8, 0.316373510564015e4, 0.224040754426988e7, -0.436701347922356e-5, -.404213852833996e-3, -0.348153203414663e3, -0.385294213555289e6, 0.135203700099403e-6, 0.134648383271089e-3, 0.125031835351736e6, 0.968123678455841e-1, 0.225660517512438e3, -0.190102435341872e-3, -.299628410819229e-1, 0.500833915372121e-2, 0.387842482998411, -0.138535367777182e4, 0.870745245971773, 0.171946252068742e1, -.326650121426383e-1, 0.498044171727877e4, 0.551478022765087e-2]), "e": np.array( [0.715815808404721e9, -0.114328360753449e12, .376531002015720e-11, -0.903983668691157e-4, 0.665695908836252e6, 0.535364174960127e10, 0.794977402335603e11, 0.922230563421437e2, -0.142586073991215e6, -0.111796381424162e7, 0.896121629640760e4, -0.669989239070491e4, 0.451242538486834e-2, -0.339731325977713e2, -0.120523111552278e1, 0.475992667717124e5, -0.266627750390341e6, -0.153314954386524e-3, 0.305638404828265, 0.123654999499486e3, -0.104390794213011e4, -0.157496516174308e-1, 0.685331118940253, 0.178373462873903e1, -0.544674124878910, 0.204529931318843e4, -0.228342359328752e5, 0.413197481515899, -0.341931835910405e2]), "f": np.array( [-0.251756547792325e-7, .601307193668763e-5, -.100615977450049e-2, 0.999969140252192, 0.214107759236486e1, -0.165175571959086e2, -0.141987303638727e-2, 0.269251915156554e1, 0.349741815858722e2, -0.300208695771783e2, -0.131546288252539e1, -0.839091277286169e1, 0.181545608337015e-9, -0.591099206478909e-3, 0.152115067087106e1, 0.252956470663225e-4, 0.100726265203786e-14, -0.14977453386065e1, -0.793940970562969e-9, -0.150290891264717e-3, .151205531275133e1, 0.470942606221652e-5, .195049710391712e-12, -.911627886266077e-8, .604374640201265e-3, -.225132933900136e-15, .610916973582981e-11, -.303063908043404e-6, -.137796070798409e-4, -.919296736666106e-3, .639288223132545e-9, .753259479898699e-6, -0.400321478682929e-12, .756140294351614e-8, -.912082054034891e-11, -.237612381140539e-7, 0.269586010591874e-4, -.732828135157839e-10, .241995578306660e-9, -.405735532730322e-3, .189424143498011e-9, -.486632965074563e-9]), "g": np.array( [0.412209020652996e-4, -0.114987238280587e7, 0.948180885032080e10, -0.195788865718971e18, 0.4962507048713e25, -0.105549884548496e29, -0.758642165988278e12, -.922172769596101e23, .725379072059348e30, -0.617718249205859e2, 0.107555033344858e5, -0.379545802336487e8, 0.228646846221831e12, -0.499741093010619e7, -.280214310054101e31, 0.104915406769586e7, 0.613754229168619e28, 0.802056715528378e32, -0.298617819828065e8, -0.910782540134681e2, 0.135033227281565e6, -0.712949383408211e19, -0.104578785289542e37, .304331584444093e2, 0.593250797959445e10, -0.364174062110798e28, 0.921791403532461, -0.337693609657471, -0.724644143758508e2, -0.110480239272601, 0.536516031875059e1, -0.291441872156205e4, 0.616338176535305e40, -0.120889175861180e39, 0.818396024524612e23, 0.940781944835829e9, -0.367279669545448e5, -0.837513931798655e16]), "h": np.array( [0.561379678887577e-1, 0.774135421587083e10, 0.111482975877938e-8, -0.143987128208183e-2, 0.193696558764920e4, -0.605971823585005e9, 0.171951568124337e14, -.185461154985145e17, 0.38785116807801e-16, -.395464327846105e-13, -0.170875935679023e3, -0.21201062070122e4, 0.177683337348191e8, 0.110177443629575e2, -0.234396091693313e6, -0.656174421999594e7, 0.156362212977396e-4, -0.212946257021400e1, 0.135249306374858e2, 0.177189164145813, 0.139499167345464e4, -0.703670932036388e-2, -0.152011044389648, 0.981916922991113e-4, 0.147199658618076e-2, 0.202618487025578e2, 0.899345518944240, -0.211346402240858, 0.249971752957491e2]), "i": np.array( [0.106905684359136e1, -0.148620857922333e1, 0.259862256980408e15, -.446352055678749e-11, -.566620757170032e-6, -.235302885736849e-2, -0.269226321968839, 0.922024992944392e1, 0.357633505503772e-11, -.173942565562222e2, 0.700681785556229e-5, -.267050351075768e-3, -.231779669675624e1, -.753533046979752e-12, .481337131452891e1, -0.223286270422356e22, -.118746004987383e-4, .646412934136496e-2, -0.410588536330937e-9, .422739537057241e20, .313698180473812e-12, 0.16439533434504e-23, -.339823323754373e-5, -.135268639905021e-1, -.723252514211625e-14, .184386437538366e-8, -.463959533752385e-1, -.99226310037675e14, .688169154439335e-16, -.222620998452197e-10, -.540843018624083e-7, .345570606200257e-2, .422275800304086e11, -.126974478770487e-14, .927237985153679e-9, .612670812016489e-13, -.722693924063497e-11, -.383669502636822e-3, .374684572410204e-3, -0.931976897511086e5, -0.247690616026922e-1, .658110546759474e2]), "j": np.array( [-0.111371317395540e-3, 0.100342892423685e1, 0.530615581928979e1, 0.179058760078792e-5, -0.728541958464774e-3, -.187576133371704e2, 0.199060874071849e-2, 0.243574755377290e2, -0.177040785499444e-3, -0.25968038522713e-2, -0.198704578406823e3, 0.738627790224287e-4, -0.236264692844138e-2, -0.161023121314333e1, 0.622322971786473e4, -.960754116701669e-8, -.510572269720488e-10, .767373781404211e-2, .663855469485254e-14, -.717590735526745e-9, 0.146564542926508e-4, .309029474277013e-11, -.464216300971708e-15, -.390499637961161e-13, -.236716126781431e-9, .454652854268717e-11, -.422271787482497e-2, 0.283911742354706e-10, 0.270929002720228e1]), "k": np.array( [-0.401215699576099e9, 0.484501478318406e11, .394721471363678e-14, .372629967374147e5, -.369794374168666e-29, -.380436407012452e-14, 0.475361629970233e-6, -0.879148916140706e-3, 0.844317863844331, 0.122433162656600e2, -0.104529634830279e3, 0.589702771277429e3, -.291026851164444e14, .170343072841850e-5, -0.277617606975748e-3, -0.344709605486686e1, 0.221333862447095e2, -0.194646110037079e3, .808354639772825e-15, -.18084520914547e-10, -.696664158132412e-5, -0.181057560300994e-2, 0.255830298579027e1, 0.328913873658481e4, -.173270241249904e-18, -.661876792558034e-6, -.39568892342125e-2, .604203299819132e-17, -.400879935920517e-13, .160751107464958e-8, .383719409025556e-4, -.649565446702457e-14, -.149095328506e-11, 0.541449377329581e-8]), "l": np.array( [0.260702058647537e10, -.188277213604704e15, 0.554923870289667e19, -.758966946387758e23, .413865186848908e27, -.81503800073806e12, -.381458260489955e33, -.123239564600519e-1, 0.226095631437174e8, -.49501780950672e12, 0.529482996422863e16, -0.444359478746295e23, .521635864527315e35, -0.487095672740742e55, -0.714430209937547e6, 0.127868634615495, -0.100752127917598e2, 0.777451437960990e7, -.108105480796471e25, -.357578581169659e-5, -0.212857169423484e1, 0.270706111085238e30, -0.695953622348829e33, 0.110609027472280, 0.721559163361354e2, -0.306367307532219e15, 0.265839618885530e-4, 0.253392392889754e-1, -0.214443041836579e3, 0.937846601489667, 0.223184043101700e1, 0.338401222509191e2, 0.494237237179718e21, -0.198068404154428, -0.141415349881140e31, -0.993862421613651e2, 0.125070534142731e3, -0.996473529004439e3, 0.473137909872765e5, 0.116662121219322e33, -0.315874976271533e16, -0.445703369196945e33, 0.642794932373694e33]), "m": np.array( [0.811384363481847, -0.568199310990094e4, -0.178657198172556e11, 0.795537657613427e32, -0.814568209346872e5, -0.659774567602874e8, -.152861148659302e11, -0.560165667510446e12, 0.458384828593949e6, -0.385754000383848e14, 0.453735800004273e8, 0.939454935735563e12, .266572856432938e28, -0.547578313899097e10, 0.200725701112386e15, 0.185007245563239e13, 0.185135446828337e9, -0.170451090076385e12, 0.157890366037614e15, -0.202530509748774e16, 0.36819392618357e60, 0.170215539458936e18, 0.639234909918741e42, -.821698160721956e15, -.795260241872306e24, 0.23341586947851e18, -0.600079934586803e23, 0.594584382273384e25, 0.189461279349492e40, -.810093428842645e46, 0.188813911076809e22, 0.111052244098768e36, 0.291133958602503e46, -.329421923951460e22, -.137570282536696e26, 0.181508996303902e28, -.346865122768353e30, -.21196114877426e38, -0.128617899887675e49, 0.479817895699239e65]), "n": np.array( [.280967799943151e-38, .614869006573609e-30, .582238667048942e-27, .390628369238462e-22, .821445758255119e-20, .402137961842776e-14, .651718171878301e-12, -.211773355803058e-7, 0.264953354380072e-2, -.135031446451331e-31, -.607246643970893e-23, -.402352115234494e-18, -.744938506925544e-16, .189917206526237e-12, .364975183508473e-5, .177274872361946e-25, -.334952758812999e-18, -.421537726098389e-8, -.391048167929649e-1, .541276911564176e-13, .705412100773699e-11, .258585887897486e-8, -.493111362030162e-10, -.158649699894543e-5, -0.525037427886100, 0.220019901729615e-2, -0.643064132636925e-2, 0.629154149015048e2, 0.135147318617061e3, 0.240560808321713e-6, -.890763306701305e-3, -0.440209599407714e4, -0.302807107747776e3, 0.159158748314599e4, 0.232534272709876e6, -0.792681207132600e6, -.869871364662769e11, .354542769185671e12, 0.400849240129329e15]), "o": np.array( [.128746023979718e-34, -.735234770382342e-11, .28907869214915e-2, 0.244482731907223, 0.141733492030985e-23, -0.354533853059476e-28, -.594539202901431e-17, -.585188401782779e-8, .201377325411803e-5, 0.138647388209306e1, -0.173959365084772e-4, 0.137680878349369e-2, .814897605805513e-14, .425596631351839e-25, -.387449113787755e-17, .13981474793024e-12, -.171849638951521e-2, 0.641890529513296e-21, .118960578072018e-10, -.155282762571611e-17, .233907907347507e-7, -.174093247766213e-12, .377682649089149e-8, -.516720236575302e-10]), "p": np.array( [-0.982825342010366e-4, 0.105145700850612e1, 0.116033094095084e3, 0.324664750281543e4, -0.123592348610137e4, -0.561403450013495e-1, 0.856677401640869e-7, 0.236313425393924e3, 0.972503292350109e-2, -.103001994531927e1, -0.149653706199162e-8, -.215743778861592e-4, -0.834452198291445e1, 0.586602660564988, 0.343480022104968e-25, .816256095947021e-5, .294985697916798e-2, 0.711730466276584e-16, 0.400954763806941e-9, 0.107766027032853e2, -0.409449599138182e-6, -.729121307758902e-5, 0.677107970938909e-8, 0.602745973022975e-7, -.382323011855257e-10, .179946628317437e-2, -.345042834640005e-3]), "q": np.array( [-0.820433843259950e5, 0.473271518461586e11, -.805950021005413e-1, 0.328600025435980e2, -0.35661702998249e4, -0.172985781433335e10, 0.351769232729192e8, -0.775489259985144e6, 0.710346691966018e-4, 0.993499883820274e5, -0.642094171904570, -0.612842816820083e4, .232808472983776e3, -0.142808220416837e-4, -0.643596060678456e-2, -0.428577227475614e1, 0.225689939161918e4, 0.100355651721510e-2, 0.333491455143516, 0.109697576888873e1, 0.961917379376452, -0.838165632204598e-1, 0.247795908411492e1, -.319114969006533e4]), "r": np.array( [.144165955660863e-2, -.701438599628258e13, -.830946716459219e-16, 0.261975135368109, 0.393097214706245e3, -0.104334030654021e5, 0.490112654154211e9, -0.147104222772069e-3, 0.103602748043408e1, 0.305308890065089e1, -0.399745276971264e7, 0.569233719593750e-11, -.464923504407778e-1, -.535400396512906e-17, .399988795693162e-12, -.536479560201811e-6, .159536722411202e-1, .270303248860217e-14, .244247453858506e-7, -0.983430636716454e-5, 0.663513144224454e-1, -0.993456957845006e1, 0.546491323528491e3, -0.143365406393758e5, 0.150764974125511e6, -.337209709340105e-9, 0.377501980025469e-8]), "s": np.array( [-0.532466612140254e23, .100415480000824e32, -.191540001821367e30, 0.105618377808847e17, 0.202281884477061e59, 0.884585472596134e8, 0.166540181638363e23, -0.313563197669111e6, -.185662327545324e54, -.624942093918942e-1, -0.50416072413259e10, 0.187514491833092e5, 0.121399979993217e-2, 0.188317043049455e1, -0.167073503962060e4, 0.965961650599775, 0.294885696802488e1, -0.653915627346115e5, 0.604012200163444e50, -0.198339358557937, -0.175984090163501e58, 0.356314881403987e1, -0.575991255144384e3, 0.456213415338071e5, -.109174044987829e8, 0.437796099975134e34, -0.616552611135792e46, 0.193568768917797e10, 0.950898170425042e54]), "t": np.array( [0.155287249586268e1, 0.664235115009031e1, -0.289366236727210e4, -0.385923202309848e13, -.291002915783761e1, -.829088246858083e12, 0.176814899675218e1, -0.534686695713469e9, 0.160464608687834e18, 0.196435366560186e6, 0.156637427541729e13, -0.178154560260006e1, -0.229746237623692e16, 0.385659001648006e8, 0.110554446790543e10, -.677073830687349e14, -.327910592086523e31, -.341552040860644e51, -.527251339709047e21, .245375640937055e24, -0.168776617209269e27, .358958955867578e29, -0.656475280339411e36, 0.355286045512301e39, .569021454413270e58, -.700584546433113e48, -0.705772623326374e65, 0.166861176200148e53, -.300475129680486e61, -.668481295196808e51, .428432338620678e69, -.444227367758304e72, -.281396013562745e77]), "u": np.array( [0.122088349258355e18, 0.104216468608488e10, -.882666931564652e16, .259929510849499e20, 0.222612779142211e15, -0.878473585050085e18, -0.314432577551552e22, -.216934916996285e13, .159079648196849e21, -.339567617303423e3, 0.884387651337836e13, -0.843405926846418e21, 0.114178193518022e2, -0.122708229235641e-3, -0.106201671767107e3, .903443213959313e25, -0.693996270370852e28, 0.648916718965575e-8, 0.718957567127851e4, 0.105581745346187e-2, -0.651903203602581e15, -0.160116813274676e25, -0.510254294237837e-8, -0.152355388953402, 0.677143292290144e12, 0.276378438378930e15, 0.116862983141686e-1, -.301426947980171e14, 0.169719813884840e-7, 0.104674840020929e27, -0.10801690456014e5, -0.990623601934295e-12, 0.536116483602738e7, .226145963747881e22, -0.488731565776210e-9, 0.151001548880670e-4, -0.227700464643920e5, -0.781754507698846e28]), "v": np.array( [-.415652812061591e-54, .177441742924043e-60, -.357078668203377e-54, 0.359252213604114e-25, -0.259123736380269e2, 0.594619766193460e5, -0.624184007103158e11, 0.313080299915944e17, .105006446192036e-8, -0.192824336984852e-5, 0.654144373749937e6, 0.513117462865044e13, -.697595750347391e19, -.103977184454767e29, .119563135540666e-47, -.436677034051655e-41, .926990036530639e-29, .587793105620748e21, .280375725094731e-17, -0.192359972440634e23, .742705723302738e27, -0.517429682450605e2, 0.820612048645469e7, -0.188214882341448e-8, .184587261114837e-1, -0.135830407782663e-5, -.723681885626348e17, -.223449194054124e27, -.111526741826431e-34, .276032601145151e-28, 0.134856491567853e15, 0.652440293345860e-9, 0.510655119774360e17, -.468138358908732e32, -.760667491183279e16, -.417247986986821e-18, 0.312545677756104e14, -.100375333864186e15, .247761392329058e27]), "w": np.array( [-.586219133817016e-7, -.894460355005526e11, .531168037519774e-30, 0.109892402329239, -0.575368389425212e-1, 0.228276853990249e5, -.158548609655002e19, .329865748576503e-27, -.634987981190669e-24, 0.615762068640611e-8, -.961109240985747e8, -.406274286652625e-44, -0.471103725498077e-12, 0.725937724828145, .187768525763682e-38, -.103308436323771e4, -0.662552816342168e-1, 0.579514041765710e3, .237416732616644e-26, .271700235739893e-14, -0.9078862134836e2, -0.171242509570207e-36, 0.156792067854621e3, 0.923261357901470, -0.597865988422577e1, 0.321988767636389e7, -.399441390042203e-29, .493429086046981e-7, .812036983370565e-19, -.207610284654137e-11, -.340821291419719e-6, .542000573372233e-17, -.856711586510214e-12, 0.266170454405981e-13, 0.858133791857099e-5]), "x": np.array( [.377373741298151e19, -.507100883722913e13, -0.10336322559886e16, .184790814320773e-5, -.924729378390945e-3, -0.425999562292738e24, -.462307771873973e-12, .107319065855767e22, 0.648662492280682e11, 0.244200600688281e1, -0.851535733484258e10, 0.169894481433592e22, 0.215780222509020e-26, -0.320850551367334, -0.382642448458610e17, -.275386077674421e-28, -.563199253391666e6, -.326068646279314e21, 0.397949001553184e14, 0.100824008584757e-6, 0.162234569738433e5, -0.432355225319745e11, -.59287424559861e12, 0.133061647281106e1, 0.157338197797544e7, 0.258189614270853e14, 0.262413209706358e25, -.920011937431142e-1, 0.220213765905426e-2, -0.110433759109547e2, 0.847004870612087e7, -0.592910695762536e9, -0.183027173269660e-4, 0.181339603516302, -0.119228759669889e4, 0.430867658061468e7]), "y": np.array( [-0.525597995024633e-9, 0.583441305228407e4, -.134778968457925e17, .118973500934212e26, -0.159096490904708e27, -.315839902302021e-6, 0.496212197158239e3, 0.327777227273171e19, -0.527114657850696e22, .210017506281863e-16, 0.705106224399834e21, -.266713136106469e31, -0.145370512554562e-7, 0.149333917053130e28, -.149795620287641e8, -.3818819062711e16, 0.724660165585797e-4, -0.937808169550193e14, 0.514411468376383e10, -0.828198594040141e5]), "z": np.array( [0.24400789229065e-10, -0.463057430331242e7, 0.728803274777712e10, .327776302858856e16, -.110598170118409e10, -0.323899915729957e13, .923814007023245e16, 0.842250080413712e-12, 0.663221436245506e12, -.167170186672139e15, .253749358701391e4, -0.819731559610523e-20, 0.328380587890663e12, -0.625004791171543e8, 0.803197957462023e21, -.204397011338353e-10, -.378391047055938e4, 0.97287654593862e-2, 0.154355721681459e2, -0.373962862928643e4, -0.682859011374572e11, -0.248488015614543e-3, 0.394536049497068e7])} # Backward4_T_hs Backward4_T_hs_Li = np.array( [0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 8, 10, 10, 12, 14, 14, 16, 16, 18, 18, 18, 20, 28]) Backward4_T_hs_Lj = np.array( [0, 3, 12, 0, 1, 2, 5, 0, 5, 8, 0, 2, 3, 4, 0, 1, 1, 2, 4, 16, 6, 8, 22, 1, 20, 36, 24, 1, 28, 12, 32, 14, 22, 36, 24, 36]) Backward4_T_hs_n = np.array( [0.179882673606601, -0.267507455199603, 0.116276722612600e1, 0.147545428713616, -0.512871635973248, 0.421333567697984, 0.563749522189870, 0.429274443819153, -0.335704552142140e1, 0.108890916499278e2, -0.248483390456012, 0.304153221906390, -0.494819763939905, 0.107551674933261e1, 0.733888415457688e-1, 0.140170545411085e-1, -0.106110975998808, 0.168324361811875e-1, 0.125028363714877e1, 0.101316840309509e4, -0.151791558000712e1, 0.524277865990866e2, 0.230495545563912e5, 0.249459806365456e-1, 0.210796467412137e7, 0.366836848613065e9, -0.144814105365163e9, -0.179276373003590e-2, 0.489955602100459e10, 0.471262212070518e3, -0.829294390198652e11, -0.171545662263191e4, 0.355777682973575e7, 0.586062760258436e12, -0.129887635078195e8, 0.317247449371057e11]) # Region 5 Region5_Li = np.array([1, 1, 1, 2, 2, 3]) Region5_Lj = np.array([1, 2, 3, 3, 9, 7]) Region5_n = np.array( [0.15736404855259e-2, 0.90153761673944e-3, -0.50270077677648e-2, 0.22440037409485e-5, -0.41163275453471e-5, 0.37919454822955e-7]) Region5_Li_less_1 = Region5_Li - 1 Region5_Li_less_2 = Region5_Li - 2 Region5_Lj_less_1 = Region5_Lj - 1 Region5_Lj_less_2 = Region5_Lj - 2 # Region 5 cp0 Region5_cp0_Jo = np.array([0, 1, -3, -2, -1, 2]) Region5_cp0_no = np.array( [-0.13179983674201e2, 0.68540841634434e1, -0.24805148933466e-1, 0.36901534980333, -0.31161318213925e1, -0.32961626538917]) Region5_cp0_Jo_less_1 = Region5_cp0_Jo - 1 Region5_cp0_Jo_less_2 = Region5_cp0_Jo - 2 iapws-1.5.5/iapws/humidAir.py0000664000175000017500000010165615161316541016304 0ustar alastairalastair#!/usr/bin/python # -*- coding: utf-8 -*- # pylint: disable=invalid-name # pylint: disable=too-many-lines, too-many-locals, too-many-statements # pylint: disable=too-many-instance-attributes, too-many-boolean-expressions """ Module with Air-water mixture properties and related properties. The module include: * :func:`_virial`: Virial equations for humid air * :func:`_fugacity`: Fugacity equation for humid air * :class:`MEoSBlend`: Special MEoS subclass to implement pseudocomponent blend with ancillary dew and bubble point * :class:`Air`: Multiparameter equation of state for Air as pseudocomponent * :class:`HumidAir`: Humid air mixture with complete functionality """ from __future__ import division from numpy import exp, log, pi try: from numpy import atan except ImportError: from math import atan import warnings from scipy.optimize import fsolve from ._iapws import M as MW from ._iapws import _Ice from ._utils import deriv_G from .iapws95 import MEoS, IAPWS95, mainClassDoc Ma = 28.96546 # g/mol R = 8.314472 # J/molK def _virial(T): """Virial equations for humid air Parameters ---------- T : float Temperature [K] Returns ------- prop : dict Dictionary with critical coefficient: * Baa: Second virial coefficient of dry air, [m³/mol] * Baw: Second air-water cross virial coefficient, [m³/mol] * Bww: Second virial coefficient of water, [m³/mol] * Caaa: Third virial coefficient of dry air, [m⁶/mol] * Caaw: Third air-water cross virial coefficient, [m⁶/mol] * Caww: Third air-water cross virial coefficient, [m⁶/mol] * Cwww: Third virial coefficient of dry air, [m⁶/mol] * Bawt: dBaw/dT, [m³/molK] * Bawtt: d²Baw/dT², [m³/molK²] * Caawt: dCaaw/dT, [m⁶/molK] * Caawtt: d²Caaw/dT², [m⁶/molK²] * Cawwt: dCaww/dT, [m⁶/molK] * Cawwtt: d²Caww/dT², [m⁶/molK²] Notes ----- Raise :class:`Warning` if T isn't in range of validity: * Baa: 60 ≤ T ≤ 2000 * Baw: 130 ≤ T ≤ 2000 * Bww: 130 ≤ T ≤ 1273 * Caaa: 60 ≤ T ≤ 2000 * Caaw: 193 ≤ T ≤ 493 * Caww: 173 ≤ T ≤ 473 * Cwww: 130 ≤ T ≤ 1273 Examples -------- >>> _virial(200)["Baa"] -3.92722567e-5 References ---------- IAPWS, Guideline on a Virial Equation for the Fugacity of H2O in Humid Air, http://www.iapws.org/relguide/VirialFugacity.html IAPWS, Guideline on an Equation of State for Humid Air in Contact with Seawater and Ice, Consistent with the IAPWS Formulation 2008 for the Thermodynamic Properties of Seawater, Table 10, http://www.iapws.org/relguide/SeaAir.html """ # Check input parameters if T < 60 or T > 2000: warnings.warn("Baa out of validity range") if T < 130 or T > 2000: warnings.warn("Baw out of validity range") if T < 130 or T > 1273: warnings.warn("Bww out of validity range") if T < 60 or T > 2000: warnings.warn("Caaa out of validity range") if T < 193 or T > 493: warnings.warn("Caaw out of validity range") if T < 173 or T > 473: warnings.warn("Caww out of validity range") if T < 130 or T > 1273: warnings.warn("Cwww out of validity range") T_ = T/100 # Virial coefficient for water # The paper use the specific formulation of virial, here using the general # formulation from helmholtz mEoS wt = IAPWS95() vir = wt._virial(T) Bww = vir["B"]/wt.rhoc*wt.M Cwww = vir["C"]/wt.rhoc**2*wt.M**2 # Table 3 ai = [0.482737e-3, 0.105678e-2, -0.656394e-2, 0.294442e-1, -0.319317e-1] bi = [-10.728876, 34.7802, -38.3383, 33.406] ci = [66.5687, -238.834, -176.755] di = [-0.237, -1.048, -3.183] Baw = 1e-6*sum(c*T_**d for c, d in zip(ci, di)) # Eq 7 Caaw = 1e-6*sum(a/T_**i for i, a in enumerate(ai)) # Eq 8 Caww = -1e-6*exp(sum(b/T_**i for i, b in enumerate(bi))) # Eq 9 # Eq T56 Bawt = 1e-6*T_/T*sum(c*d*T_**(d-1) for c, d in zip(ci, di)) # Eq T57 Bawtt = 1e-6*T_**2/T**2*sum( c*d*(d-1)*T_**(d-2) for c, d in zip(ci, di)) # Eq T59 Caawt = -1e-6*T_/T*sum(i*a*T_**(-i-1) for i, a in enumerate(ai)) # Eq T60 Caawtt = 1e-6*T_**2/T**2*sum( i*(i+1)*a*T_**(-i-2) for i, a in enumerate(ai)) # Eq T62 Cawwt = 1e-6*T_/T*sum(i*b*T_**(-i-1) for i, b in enumerate(bi)) * \ exp(sum(b/T_**i for i, b in enumerate(bi))) # Eq T63 Cawwtt = -1e-6*T_**2/T**2*(( sum(i*(i+1)*b*T_**(-i-2) for i, b in enumerate(bi)) + sum(i*b*T_**(-i-1) for i, b in enumerate(bi))**2) * exp(sum(b/T_**i for i, b in enumerate(bi)))) # Virial coefficient for air, using too the general virial procedure air = Air() vir = air._virial(T) Baa = vir["B"]/air.rhoc*air.M Caaa = vir["C"]/air.rhoc**2*air.M**2 prop = {} prop["Baa"] = Baa/1000 prop["Baw"] = Baw prop["Bww"] = Bww/1000 prop["Caaa"] = Caaa/1e6 prop["Caaw"] = Caaw prop["Caww"] = Caww prop["Cwww"] = Cwww/1e6 prop["Bawt"] = Bawt prop["Bawtt"] = Bawtt prop["Caawt"] = Caawt prop["Caawtt"] = Caawtt prop["Cawwt"] = Cawwt prop["Cawwtt"] = Cawwtt return prop def _fugacity(T, P, x): """Fugacity equation for humid air Parameters ---------- T : float Temperature, [K] P : float Pressure, [MPa] x : float Mole fraction of water-vapor, [-] Returns ------- fv : float fugacity coefficient, [MPa] Notes ----- Raise :class:`NotImplementedError` if input isn't in range of validity: * 193 ≤ T ≤ 473 * 0 ≤ P ≤ 5 * 0 ≤ x ≤ 1 Really the xmax is the xsaturation but isn't implemented Examples -------- >>> _fugacity(300, 1, 0.1) 0.0884061686 References ---------- IAPWS, Guideline on a Virial Equation for the Fugacity of H2O in Humid Air, http://www.iapws.org/relguide/VirialFugacity.html """ # Check input parameters if T < 193 or T > 473 or P < 0 or P > 5 or x < 0 or x > 1: raise NotImplementedError("Input not in range of validity") Rg = 8.314462 # J/molK # Virial coefficients vir = _virial(T) # Eq 3 beta = x*(2-x)*vir["Bww"]+(1-x)**2*(2*vir["Baw"]-vir["Baa"]) # Eq 4 gamma = x**2*(3-2*x)*vir["Cwww"] + \ (1-x)**2*(6*x*vir["Caww"]+3*(1-2*x)*vir["Caaw"]-2*(1-x)*vir["Caaa"]) +\ (x**2*vir["Bww"]+2*x*(1-x)*vir["Baw"]+(1-x)**2*vir["Baa"]) * \ (x*(3*x-4)*vir["Bww"]+2*(1-x)*(3*x-2)*vir["Baw"]+3*(1-x)**2*vir["Baa"]) # Eq 2 fv = x*P*exp(beta*P*1e6/Rg/T+0.5*gamma*(P*1e6/Rg/T)**2) return fv class MEoSBlend(MEoS): """ Special meos class to implement pseudocomponent blend and defining its ancillary dew and bubble point """ _blend = {} @classmethod def _dewP(cls, T): """Using ancillary equation return the pressure of dew point""" c = cls._blend["dew"] Tj = cls._blend["Tj"] Pj = cls._blend["Pj"] Tita = 1-T/Tj suma = 0 for i, n in zip(c["i"], c["n"]): suma += n*Tita**(i/2.) P = Pj*exp(Tj/T*suma) return P @classmethod def _bubbleP(cls, T): """Using ancillary equation return the pressure of bubble point""" c = cls._blend["bubble"] Tj = cls._blend["Tj"] Pj = cls._blend["Pj"] Tita = 1-T/Tj suma = 0 for i, n in zip(c["i"], c["n"]): suma += n*Tita**(i/2.) P = Pj*exp(Tj/T*suma) return P @mainClassDoc() class Air(MEoSBlend): """Multiparameter equation of state for Air as pseudocomponent for internal procedures, see MEoS base class References ---------- Lemmon, E.W., Jacobsen, R.T, Penoncello, S.G., Friend, D.G.; Thermodynamic Properties of Air and Mixtures of Nitrogen, Argon, and Oxygen From 60 to 2000 K at Pressures to 2000 MPa. J. Phys. Chem. Ref. Data 29, 331 (2000). http://dx.doi.org/10.1063/1.1285884 """ name = "air" CASNumber = "1" formula = "N2+Ar+O2" synonym = "R-729" rhoc = 10.4477*Ma Tc = 132.6306 Pc = 3.7860 # MPa M = Ma Tt = 59.75 Tb = 78.903 f_acent = 0.0335 momentoDipolar = 0.0 Fi0 = {"ao_log": [1, 2.490888032], "pow": [-3, -2, -1, 0, 1, 1.5], "ao_pow": [0.6057194e-7, -0.210274769e-4, -0.158860716e-3, 9.7450251743948, 10.0986147428912, -0.19536342e-3], "ao_exp": [0.791309509, 0.212236768], "titao": [25.36365, 16.90741], "ao_exp2": [-0.197938904], "titao2": [87.31279], "sum2": [2./3], } _constants = { "R": 8.31451, "Tref": 132.6312, "rhoref": 10.4477*Ma, "nr1": [0.118160747229, 0.713116392079, -0.161824192067e1, 0.714140178971e-1, -0.865421396646e-1, 0.134211176704, 0.112626704218e-1, -0.420533228842e-1, 0.349008431982e-1, 0.164957183186e-3], "d1": [1, 1, 1, 2, 3, 3, 4, 4, 4, 6], "t1": [0, 0.33, 1.01, 0, 0, 0.15, 0, 0.2, 0.35, 1.35], "nr2": [-0.101365037912, -0.173813690970, -0.472103183731e-1, -0.122523554253e-1, -0.146629609713, -0.316055879821e-1, 0.233594806142e-3, 0.148287891978e-1, -0.938782884667e-2], "d2": [1, 3, 5, 6, 1, 3, 11, 1, 3], "t2": [1.6, 0.8, 0.95, 1.25, 3.6, 6, 3.25, 3.5, 15], "c2": [1, 1, 1, 1, 2, 2, 2, 3, 3], "gamma2": [1]*9} _blend = { "Tj": 132.6312, "Pj": 3.78502, "dew": {"i": [1, 2, 5, 8], "n": [-0.1567266, -5.539635, 0.7567212, -3.514322]}, "bubble": {"i": [1, 2, 3, 4, 5, 6], "n": [0.2260724, -7.080499, 5.700283, -12.44017, 17.81926, -10.81364]}} _melting = {"eq": 1, "Tref": Tb, "Pref": 5.265, "Tmin": 59.75, "Tmax": 2000.0, "a1": [1, 0.354935e5, -0.354935e5], "exp1": [0, 0.178963e1, 0], "a2": [], "exp2": [], "a3": [], "exp3": []} _surf = {"sigma": [0.03046], "exp": [1.28]} _rhoG = { "eq": 3, "ao": [-0.20466e1, -0.4752e1, -0.13259e2, -0.47652e2], "exp": [0.41, 1, 2.8, 6.5]} _Pv = { "ao": [-0.1567266, -0.5539635e1, 0.7567212, -0.3514322e1], "exp": [0.5, 1, 2.5, 4]} @classmethod def _Liquid_Density(cls, T): """Auxiliary equation for the density or saturated liquid Parameters ---------- T : float Temperature [K] Returns ------- rho : float Saturated liquid density [kg/m³] """ Tc = 132.6312 rhoc = 10.4477*cls.M Ni = [44.3413, -240.073, 285.139, -88.3366] ti = [0.65, 0.85, 0.95, 1.1] Tita = 1-T/Tc suma = 1 for n, t in zip(Ni, ti): suma += n*Tita**t suma -= 0.892181*log(T/Tc) rho = suma*rhoc return rho @staticmethod def _visco(rho, T, fase=None): """Equation for the Viscosity Parameters ---------- rho : float Density, [kg/m³] T : float Temperature, [K] Returns ------- μ : float Viscosity, [Pa·s] References ---------- Lemmon, E.W., Jacobsen, R.T. Viscosity and Thermal Conductivity Equations for Nitrogen, Oxygen, Argon, and Air. Int. J. Thermophys. 25 (1) (2004) 21-69. http://dx.doi.org/10.1023/B:IJOT.0000022327.04529.f3 """ ek = 103.3 sigma = 0.36 M = 28.9586 rhoc = 10.4477*M tau = 132.6312/T delta = rho/rhoc b = [0.431, -0.4623, 0.08406, 0.005341, -0.00331] T_ = log(T/ek) suma = 0 for i, bi in enumerate(b): suma += bi*T_**i omega = exp(suma) # Eq 2 muo = 0.0266958*(M*T)**0.5/(sigma**2*omega) n_poly = [10.72, 1.122, 0.002019, -8.876, -0.02916] t_poly = [.2, .05, 2.4, .6, 3.6] d_poly = [1, 4, 9, 1, 8] l_poly = [0, 0, 0, 1, 1] g_poly = [0, 0, 0, 1, 1] # Eq 3 mur = 0 for n, t, d, l, g in zip(n_poly, t_poly, d_poly, l_poly, g_poly): mur += n*tau**t*delta**d*exp(-g*delta**l) # Eq 1 mu = muo+mur return mu*1e-6 def _thermo(self, rho, T, fase=None): """Equation for the thermal conductivity Parameters ---------- rho : float Density, [kg/m³] T : float Temperature, [K] fase: dict phase properties Returns ------- k : float Thermal conductivity, [W/mK] References ---------- Lemmon, E.W., Jacobsen, R.T. Viscosity and Thermal Conductivity Equations for Nitrogen, Oxygen, Argon, and Air. Int. J. Thermophys. 25 (1) (2004) 21-69. http://dx.doi.org/10.1023/B:IJOT.0000022327.04529.f3 """ ek = 103.3 sigma = 0.36 M = 28.9586 rhoc = 10.4477*M tau = 132.6312/T delta = rho/rhoc b = [0.431, -0.4623, 0.08406, 0.005341, -0.00331] T_ = log(T/ek) suma = 0 for i, bi in enumerate(b): suma += bi*T_**i omega = exp(suma) # Eq 2 muo = 0.0266958*(M*T)**0.5/(sigma**2*omega) # Eq 5 N = [1.308, 1.405, -1.036] t = [-1.1, -0.3] lo = N[0]*muo+N[1]*tau**t[0]+N[2]*tau**t[1] n_poly = [8.743, 14.76, -16.62, 3.793, -6.142, -0.3778] t_poly = [0.1, 0, 0.5, 2.7, 0.3, 1.3] d_poly = [1, 2, 3, 7, 7, 11] g_poly = [0, 0, 1, 1, 1, 1] l_poly = [0, 0, 2, 2, 2, 2] # Eq 6 lr = 0 for n, t, d, l, g in zip(n_poly, t_poly, d_poly, l_poly, g_poly): lr += n*tau**t*delta**d*exp(-g*delta**l) lc = 0 # FIXME: Tiny desviation in the test in paper, 0.06% at critical point if fase: qd = 0.31 Gamma = 0.055 Xio = 0.11 Tref = 265.262 k = 1.380658e-23 # J/K # Eq 11 X = self.Pc*rho/rhoc**2*fase.drhodP_T ref = Air() st = ref._Helmholtz(rho, Tref) drho = 1e3/self.R/Tref/(1+2*delta*st["fird"]+delta**2*st["firdd"]) Xref = self.Pc*rho/rhoc**2*drho # Eq 10 bracket = X-Xref*Tref/T if bracket > 0: Xi = Xio*(bracket/Gamma)**(0.63/1.2415) Xq = Xi/qd # Eq 8 Omega = 2/pi*((fase.cp-fase.cv)/fase.cp*atan(Xq) + fase.cv/fase.cp*(Xq)) # Eq 9 Omega0 = 2/pi*(1-exp(-1/(1/Xq+Xq**2/3*rhoc**2/rho**2))) # Eq 7 lc = rho*fase.cp*k*1.01*T/6/pi/Xi/fase.mu*(Omega-Omega0)*1e15 else: lc = 0 # Eq 4 k = lo+lr+lc return k*1e-3 class HumidAir(object): """ Humid air class with complete functionality Parameters ---------- T : float Temperature, [K] P : float Pressure, [MPa] rho : float Density, [kg/m³] v : float Specific volume, [m³/kg] A : float Mass fraction of dry air in humid air, [kg/kg] xa : float Mole fraction of dry air in humid air, [-] W : float Mass fraction of water in humid air, [kg/kg] xw : float Mole fraction of water in humid air, [-] HR : float Humidity ratio, Mass fraction of water in dry air, [kg/kg] Notes ----- * It needs two incoming properties of T, P, rho. * v as a alternate input parameter to rho * For composition need one of A, xa, W, xw, HR. The calculated instance has the following properties: * P: Pressure, [MPa] * T: Temperature, [K] * g: Specific Gibbs free energy, [kJ/kg] * a: Specific Helmholtz free energy, [kJ/kg] * v: Specific volume, [m³/kg] * rho: Density, [kg/m³] * h: Specific enthalpy, [kJ/kg] * u: Specific internal energy, [kJ/kg] * s: Specific entropy, [kJ/kg·K] * cp: Specific isobaric heat capacity, [kJ/kg·K] * w: Speed of sound, [m/s] * alfav: Isobaric cubic expansion coefficient, [1/K] * betas: Isoentropic temperature-pressure coefficient, [-] * xkappa: Isothermal Expansion Coefficient, [-] * ks: Adiabatic Compressibility, [1/MPa] * A: Mass fraction of dry air in humid air, [kg/kg] * W: Mass fraction of water in humid air, [kg/kg] * xa: Mole fraction of dry air, [-] * xw: Mole fraction of water, [-] * Pv: Partial pressure of water, [MPa] * xa_sat: Mole fraction of dry air at saturation state, [-] * mu: Relative chemical potential, [kJ/kg] * muw: Chemical potential of water, [kJ/kg] * M: Molar mass of humid air, [g/mol] * HR: Humidity ratio, Mass fraction of water in dry air, [kg/kg] * RH: Relative humidity, [-] """ kwargs = {"T": 0.0, "P": 0.0, "rho": 0.0, "v": 0.0, "A": None, "xa": None, "W": None, "xw": None, "HR": None} status = 0 msg = "Undefined" _mode = None _composition = None T = None rho = None v = None P = None s = None cp = None h = None g = None u = None alfav = None betas = None xkappa = None ks= None w = None A = None W = None mu = None muw = None M = None HR = None xa = None xw = None Pv = None xa_sat = None RH = None def __init__(self, **kwargs): """Constructor, define common constant and initinialice kwargs""" self.kwargs = HumidAir.kwargs.copy() self.__call__(**kwargs) def __call__(self, **kwargs): """Make instance callable to can add input parameter one to one""" # Check alernate input parameters if kwargs.get("v", None) is not None: kwargs["rho"] = 1./kwargs["v"] del kwargs["v"] if kwargs.get("W", None) is not None: kwargs["A"] = 1-kwargs["W"] del kwargs["W"] if kwargs.get("xw", None) is not None: kwargs["xa"] = 1-kwargs["xw"] del kwargs["xw"] if kwargs.get("HR", None) is not None: kwargs["A"] = 1/(1+kwargs["HR"]) del kwargs["HR"] self.kwargs.update(kwargs) if self.calculable: self.status = 1 self.calculo() self.msg = "" @property def calculable(self): """Check if inputs are enough to define state""" self._mode = "" if self.kwargs["T"] and self.kwargs["P"]: self._mode = "TP" elif self.kwargs["T"] and self.kwargs["rho"]: self._mode = "Trho" elif self.kwargs["P"] and self.kwargs["rho"]: self._mode = "Prho" # Composition definition self._composition = "" if self.kwargs["A"] is not None: self._composition = "A" elif self.kwargs["xa"] is not None: self._composition = "xa" return bool(self._mode) and bool(self._composition) def calculo(self): """Calculate procedure""" T = self.kwargs["T"] rho = self.kwargs["rho"] P = self.kwargs["P"] # Composition alternate definition if self._composition == "A": A = self.kwargs["A"] elif self._composition == "xa": xa = self.kwargs["xa"] A = xa/(1-(1-xa)*(1-MW/Ma)) # Thermodynamic definition if self._mode == "TP": def f(rho): fav = self._fav(T, rho, A) return rho**2*fav["fird"]/1000-P rho = fsolve(f, 1)[0] elif self._mode == "Prho": def f(T): fav = self._fav(T, rho, A) return rho**2*fav["fird"]/1000-P T = fsolve(f, 300)[0] # General calculation procedure fav = self._fav(T, rho, A) # Common thermodynamic properties prop = self._prop(T, rho, fav) self.T = T self.rho = rho self.v = 1/rho self.P = prop["P"] self.s = prop["s"] self.cp = prop["cp"] self.h = prop["h"] self.g = prop["g"] self.u = self.h-self.P*1000*self.v self.alfav = prop["alfav"] self.betas = prop["betas"] self.xkappa = prop["xkappa"] self.ks = prop["ks"] self.w = prop["w"] # Coligative properties coligative = self._coligative(rho, A, fav) self.A = A self.W = 1-A self.mu = coligative["mu"] self.muw = coligative["muw"] self.M = coligative["M"] self.HR = coligative["HR"] self.xa = coligative["xa"] self.xw = coligative["xw"] self.Pv = (1-self.xa)*self.P # Saturation related properties A_sat = self._eq(self.T, self.P) if A_sat: self.xa_sat = A_sat*MW/Ma/(1-A_sat*(1-MW/Ma)) self.RH = (1-self.xa)/(1-self.xa_sat) self.HR_sat = 1 / A_sat - 1 else: self.xa_sat = None self.RH = None self.msg = "Saturation state don't converge" self.status = 3 self.HR_sat = None def derivative(self, z, x, y): """ Wrapper derivative for custom derived properties where x, y, z can be: P, T, v, rho, u, h, s, g, a """ return deriv_G(self, z, x, y, self) def _eq(self, T, P): """Procedure for calculate the composition in saturation state Parameters ---------- T : float Temperature [K] P : float Pressure [MPa] Returns ------- Asat : float Saturation mass fraction of dry air in humid air [kg/kg] """ # ao initial value of air mass fraction for iteration if T <= 273.16: ice = _Ice(T, P) gw = ice["g"] ao = 0.99999 elif T <= 373.16: water = IAPWS95(T=T, P=P) gw = water.g ao = 0.99 else: raise NotImplementedError("Incoming out of bound") def f(parr): rho, a = parr if a > 1: a = 1 fa = self._fav(T, rho, a) muw = fa["fir"]+rho*fa["fird"]-a*fa["fira"] return gw-muw, rho**2*fa["fird"]/1000-P air = Air(T=T, P=P) rinput = fsolve(f, [air.rho, ao], full_output=True) Asat = rinput[0][1] if rinput[2] == 1 and 0 <= Asat <= 1: return Asat warnings.warn("Convergence failed") print(rinput) @staticmethod def _prop(T, rho, fav): """Thermodynamic properties of humid air Parameters ---------- T : float Temperature, [K] rho : float Density, [kg/m³] fav : dict dictionary with helmholtz energy and derivatives Returns ------- prop : dict Dictionary with thermodynamic properties of humid air: * P: Pressure, [MPa] * s: Specific entropy, [kJ/kgK] * cp: Specific isobaric heat capacity, [kJ/kgK] * h: Specific enthalpy, [kJ/kg] * g: Specific gibbs energy, [kJ/kg] * alfav: Thermal expansion coefficient, [1/K] * betas: Isentropic T-P coefficient, [K/MPa] * xkappa: Isothermal compressibility, [1/MPa] * ks: Isentropic compressibility, [1/MPa] * w: Speed of sound, [m/s] References ---------- IAPWS, Guideline on an Equation of State for Humid Air in Contact with Seawater and Ice, Consistent with the IAPWS Formulation 2008 for the Thermodynamic Properties of Seawater, Table 5, http://www.iapws.org/relguide/SeaAir.html """ prop = {} prop["P"] = rho**2*fav["fird"]/1000 # Eq T1 prop["s"] = -fav["firt"] # Eq T2 prop["cp"] = -T*fav["firtt"]+T*rho*fav["firdt"]**2/( # Eq T3 2*fav["fird"]+rho*fav["firdd"]) prop["h"] = fav["fir"]-T*fav["firt"]+rho*fav["fird"] # Eq T4 prop["g"] = fav["fir"]+rho*fav["fird"] # Eq T5 prop["alfav"] = fav["firdt"]/(2*fav["fird"]+rho*fav["firdd"]) # Eq T6 prop["betas"] = 1000*fav["firdt"]/rho/( # Eq T7 rho*fav["firdt"]**2-fav["firtt"]*(2*fav["fird"]+rho*fav["firdd"])) prop["xkappa"] = 1e3/(rho**2*(2*fav["fird"]+rho*fav["firdd"])) # Eq T8 prop["ks"] = 1000*fav["firtt"]/rho**2/( # Eq T9 fav["firtt"]*(2*fav["fird"]+rho*fav["firdd"])-rho*fav["firdt"]**2) prop["w"] = (rho**2*1000*(fav["firtt"]*fav["firdd"]-fav["firdt"]**2) / fav["firtt"]+2*rho*fav["fird"]*1000)**0.5 # Eq T10 return prop @staticmethod def _coligative(rho, A, fav): """Miscelaneous properties of humid air Parameters ---------- rho : float Density, [kg/m³] A : float Mass fraction of dry air in humid air, [kg/kg] fav : dict dictionary with helmholtz energy and derivatives Returns ------- prop : dict Dictionary with calculated properties: * mu: Relative chemical potential, [kJ/kg] * muw: Chemical potential of water, [kJ/kg] * M: Molar mass of humid air, [g/mol] * HR: Humidity ratio, [-] * xa: Mole fraction of dry air, [-] * xw: Mole fraction of water, [-] References ---------- IAPWS, Guideline on an Equation of State for Humid Air in Contact with Seawater and Ice, Consistent with the IAPWS Formulation 2008 for the Thermodynamic Properties of Seawater, Table 12, http://www.iapws.org/relguide/SeaAir.html """ prop = {} prop["mu"] = fav["fira"] prop["muw"] = fav["fir"]+rho*fav["fird"]-A*fav["fira"] prop["M"] = 1/((1-A)/MW+A/Ma) prop["HR"] = 1/A-1 prop["xa"] = A*MW/Ma/(1-A*(1-MW/Ma)) prop["xw"] = 1-prop["xa"] return prop def _fav(self, T, rho, A): r"""Specific Helmholtz energy of humid air and derivatives Parameters ---------- T : float Temperature, [K] rho : float Density, [kg/m³] A : float Mass fraction of dry air in humid air, [kg/kg] Returns ------- prop : dict Dictionary with helmholtz energy and derivatives: * fir, [kJ/kg] * fira: :math:`\left.\frac{\partial f_{av}}{\partial A}\right|_{T,\rho}`, [kJ/kg] * firt: :math:`\left.\frac{\partial f_{av}}{\partial T}\right|_{A,\rho}`, [kJ/kgK] * fird: :math:`\left.\frac{\partial f_{av}}{\partial \rho}\right|_{A,T}`, [kJ/m³kg²] * firaa: :math:`\left.\frac{\partial^2 f_{av}}{\partial A^2}\right|_{T, \rho}`, [kJ/kg] * firat: :math:`\left.\frac{\partial^2 f_{av}}{\partial A \partial T}\right|_{\rho}`, [kJ/kgK] * firad: :math:`\left.\frac{\partial^2 f_{av}}{\partial A \partial \rho}\right|_T`, [kJ/m³kg²] * firtt: :math:`\left.\frac{\partial^2 f_{av}}{\partial T^2}\right|_{A, \rho}`, [kJ/kgK²] * firdt: :math:`\left.\frac{\partial^2 f_{av}}{\partial \rho \partial T}\right|_A`, [kJ/m³kg²K] * firdd: :math:`\left.\frac{\partial^2 f_{av}}{\partial \rho^2}\right|_{A, T}`, [kJ/m⁶kg³] References ---------- IAPWS, Guideline on an Equation of State for Humid Air in Contact with Seawater and Ice, Consistent with the IAPWS Formulation 2008 for the Thermodynamic Properties of Seawater, Table 6, http://www.iapws.org/relguide/SeaAir.html """ # noqa water = IAPWS95() rhov = (1-A)*rho fv = water._derivDimensional(rhov, T) air = Air() rhoa = A*rho fa = air._derivDimensional(rhoa, T) fmix = self._fmix(T, rho, A) prop = {} # Eq T11 prop["fir"] = (1-A)*fv["fir"] + A*fa["fir"] + fmix["fir"] # Eq T12 prop["fira"] = -fv["fir"]-rhov*fv["fird"]+fa["fir"] + \ rhoa*fa["fird"]+fmix["fira"] # Eq T13 prop["firt"] = (1-A)*fv["firt"]+A*fa["firt"]+fmix["firt"] # Eq T14 prop["fird"] = (1-A)**2*fv["fird"]+A**2*fa["fird"]+fmix["fird"] # Eq T15 prop["firaa"] = rho*(2*fv["fird"]+rhov*fv["firdd"] + 2*fa["fird"]+rhoa*fa["firdd"])+fmix["firaa"] # Eq T16 prop["firat"] = -fv["firt"]-rhov*fv["firdt"]+fa["firt"] + \ rhoa*fa["firdt"]+fmix["firat"] # Eq T17 prop["firad"] = -(1-A)*(2*fv["fird"]+rhov*fv["firdd"]) + \ A*(2*fa["fird"]+rhoa*fa["firdd"])+fmix["firad"] # Eq T18 prop["firtt"] = (1-A)*fv["firtt"]+A*fa["firtt"]+fmix["firtt"] # Eq T19 prop["firdt"] = (1-A)**2*fv["firdt"]+A**2*fa["firdt"]+fmix["firdt"] # Eq T20 prop["firdd"] = (1-A)**3*fv["firdd"]+A**3*fa["firdd"]+fmix["firdd"] return prop @staticmethod def _fmix(T, rho, A): r"""Specific Helmholtz energy of air-water interaction Parameters ---------- T : float Temperature, [K] rho : float Density, [kg/m³] A : float Mass fraction of dry air in humid air, [kg/kg] Returns ------- prop : dict Dictionary with helmholtz energy and derivatives: * fir, [kJ/kg] * fira: :math:`\left.\frac{\partial f_{mix}}{\partial A}\right|_{T,\rho}`, [kJ/kg] * firt: :math:`\left.\frac{\partial f_{mix}}{\partial T}\right|_{A,\rho}`, [kJ/kgK] * fird: :math:`\left.\frac{\partial f_{mix}}{\partial \rho}\right|_{A,T}`, [kJ/m³kg²] * firaa: :math:`\left.\frac{\partial^2 f_{mix}}{\partial A^2}\right|_{T, \rho}`, [kJ/kg] * firat: :math:`\left.\frac{\partial^2 f_{mix}}{\partial A \partial T}\right|_{\rho}`, [kJ/kgK] * firad: :math:`\left.\frac{\partial^2 f_{mix}}{\partial A \partial \rho}\right|_T`, [kJ/m³kg²] * firtt: :math:`\left.\frac{\partial^2 f_{mix}}{\partial T^2}\right|_{A, \rho}`, [kJ/kgK²] * firdt: :math:`\left.\frac{\partial^2 f_{mix}}{\partial \rho \partial T}\right|_A`, [kJ/m³kg²K] * firdd: :math:`\left.\frac{\partial^2 f_{mix}}{\partial \rho^2}\right|_{A, T}`, [kJ/m⁶kg³] References ---------- IAPWS, Guideline on an Equation of State for Humid Air in Contact with Seawater and Ice, Consistent with the IAPWS Formulation 2008 for the Thermodynamic Properties of Seawater, Table 10, http://www.iapws.org/relguide/SeaAir.html """ ma = Air.M/1000 Mw = IAPWS95.M/1000 vir = _virial(T) Baw = vir["Baw"] Bawt = vir["Bawt"] Bawtt = vir["Bawtt"] Caaw = vir["Caaw"] Caawt = vir["Caawt"] Caawtt = vir["Caawtt"] Caww = vir["Caww"] Cawwt = vir["Cawwt"] Cawwtt = vir["Cawwtt"] # Eq T45 f = 2*A*(1-A)*rho*R*T/ma/Mw*(Baw+3*rho/4*(A/ma*Caaw+(1-A)/Mw*Caww)) # Eq T46 fa = 2*rho*R*T/ma/Mw*((1-2*A)*Baw+3*rho/4*( A*(2-3*A)/ma*Caaw+(1-A)*(1-3*A)/Mw*Caww)) # Eq T47 ft = 2*A*(1-A)*rho*R/ma/Mw*( Baw+T*Bawt+3*rho/4*(A/ma*(Caaw+T*Caawt)+(1-A)/Mw*(Caww+T*Cawwt))) # Eq T48 fd = A*(1-A)*R*T/ma/Mw*(2*Baw+3*rho*(A/ma*Caaw+(1-A)/Mw*Caww)) # Eq T49 faa = rho*R*T/ma/Mw*(-4*Baw+3*rho*((1-3*A)/ma*Caaw-(2-3*A)/Mw*Caww)) # Eq T50 fat = 2*rho*R/ma/Mw*(1-2*A)*(Baw+T*Bawt)+3*rho**2*R/2/ma/Mw*( A*(2-3*A)/ma*(Caaw+T*Caawt)+(1-A)*(1-3*A)/Mw*(Caww+T*Cawwt)) # Eq T51 fad = 2*R*T/ma/Mw*((1-2*A)*Baw+3/2*rho*( A*(2-3*A)/ma*Caaw+(1-A)*(1-3*A)/Mw*Caww)) # Eq T52 ftt = 2*A*(1-A)*rho*R/ma/Mw*(2*Bawt+T*Bawtt+3*rho/4*( A/ma*(2*Caawt+T*Caawtt)+(1-A)/Mw*(2*Cawwt+T*Cawwtt))) # Eq T53 ftd = 2*A*(1-A)*R/ma/Mw*(Baw+T*Bawt+3*rho/2*( A/ma*(Caaw+T*Caawt)+(1-A)/Mw*(Caww+T*Cawwt))) # Eq T54 fdd = 3*A*(1-A)*R*T/ma/Mw*(A/ma*Caaw+(1-A)/Mw*Caww) prop = {} prop["fir"] = f/1000 prop["fira"] = fa/1000 prop["firt"] = ft/1000 prop["fird"] = fd/1000 prop["firaa"] = faa/1000 prop["firat"] = fat/1000 prop["firad"] = fad/1000 prop["firtt"] = ftt/1000 prop["firdt"] = ftd/1000 prop["firdd"] = fdd/1000 return prop iapws-1.5.5/iapws/ammonia.py0000664000175000017500000005105315161316541016156 0ustar alastairalastair#!/usr/bin/python # -*- coding: utf-8 -*- # pylint: disable=invalid-name # pylint: disable=too-many-locals, too-many-statements """ Module with Ammonia-water mixture properties and related properties. The module include: * :class:`NH3`: Multiparameter equation of state for ammonia * :class:`H2ONH3`: Thermodynamic properties of ammonia-water mixtures * :class:`Ttr`: Triple point of ammonia-water mixtures """ from __future__ import division from numpy import exp, log, pi import warnings from scipy.constants import Boltzmann from .iapws95 import MEoS, IAPWS95, mainClassDoc @mainClassDoc() class NH3(MEoS): """Multiparameter equation of state for ammonia for internal procedures, see MEoS base class References ---------- Baehr, H.D., Tillner-Roth, R.; Thermodynamic Properties of Environmentally Acceptable Refrigerants: Equations of State and Tables for Ammonia, R22, R134a, R152a, and R123. Springer-Verlag, Berlin, 1994. http://doi.org/10.1007/978-3-642-79400-1 """ name = "ammonia" CASNumber = "7664-41-7" formula = "NH3" synonym = "R-717" rhoc = 225. Tc = 405.40 Pc = 11.333 # MPa M = 17.03026 # g/mol Tt = 195.495 Tb = 239.823 f_acent = 0.25601 momentoDipolar = 1.470 Fi0 = {"ao_log": [1, -1], "pow": [0, 1, 1./3, -1.5, -1.75], "ao_pow": [-15.81502, 4.255726, 11.47434, -1.296211, 0.5706757], "ao_exp": [], "titao": [], "ao_hyp": [], "hyp": []} _constants = { "R": 8.314471, "nr1": [-0.1858814e01, 0.4554431e-1, 0.7238548, 0.1229470e-1, 0.2141882e-10], "d1": [1, 2, 1, 4, 15], "t1": [1.5, -0.5, 0.5, 1., 3.], "nr2": [-0.1430020e-1, 0.3441324, -0.2873571, 0.2352589e-4, -0.3497111e-1, 0.1831117e-2, 0.2397852e-1, -0.4085375e-1, 0.2379275, -0.3548972e-1, -0.1823729, 0.2281556e-1, -0.6663444e-2, -0.8847486e-2, 0.2272635e-2, -0.5588655e-3], "d2": [3, 3, 1, 8, 2, 8, 1, 1, 2, 3, 2, 4, 3, 1, 2, 4], "t2": [0, 3, 4, 4, 5, 5, 3, 6, 8, 8, 10, 10, 5, 7.5, 15, 30], "c2": [1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3], "gamma2": [1]*16} _melting = {"eq": 1, "Tref": Tt, "Pref": 1000, "Tmin": Tt, "Tmax": 700.0, "a1": [], "exp1": [], "a2": [], "exp2": [], "a3": [0.2533125e4], "exp3": [1]} _surf = {"sigma": [0.1028, -0.09453], "exp": [1.211, 5.585]} _Pv = { "eq": 5, "ao": [-0.70993e1, -0.24330e1, 0.87591e1, -0.64091e1, -0.21185e1], "exp": [1., 1.5, 1.7, 1.95, 4.2]} _rhoL = { "eq": 1, "ao": [0.34488e2, -0.12849e3, 0.17382e3, -0.10699e3, 0.30339e2], "exp": [0.58, 0.75, 0.9, 1.1, 1.3]} _rhoG = { "eq": 3, "ao": [-.38435, -4.0846, -6.6634, -0.31881e2, 0.21306e3, -0.24648e3], "exp": [0.218, 0.55, 1.5, 3.7, 5.5, 5.8]} def _visco(self, rho, T, fase=None): """Equation for the Viscosity Parameters ---------- rho : float Density [kg/m³] T : float Temperature [K] Returns ------- mu : float Viscosity [Pa·s] References ---------- Fenghour, A., Wakeham, W.A., Vesovic, V., Watson, J.T.R., Millat, J., and Vogel, E., The viscosity of ammonia, J. Phys. Chem. Ref. Data 24, 1649 (1995). doi:10.1063/1.555961 """ ek = 386 sigma = 0.2957 rho = rho/self.M T_ = T/ek # Eq 4 a = [4.99318220, -0.61122364, 0.0, 0.18535124, -0.11160946] omega = exp(sum(ai*log(T_)**i for i, ai in enumerate(a))) # Eq 2, Zero-Density Limit muo = 2.1357*(T*self.M)**0.5/sigma**2/omega # Eq 8, Viscosity virial coefficient cv = [-0.17999496e1, 0.46692621e2, -0.53460794e3, 0.33604074e4, -0.13019164e5, 0.33414230e5, -0.58711743e5, 0.71426686e5, -0.59834012e5, 0.33652741e5, -0.1202735e5, 0.24348205e4, -0.20807957e3] Bn = 0.6022137*sigma**3*sum(c*T_**(-i/2) for i, c in enumerate(cv)) # Eq 7 mub = Bn*muo*rho # Eq 10 dij = [2.19664285e-1, -0.83651107e-1, 0.17366936e-2, -0.64250359e-2, 1.67668649e-4, -1.49710093e-4, 0.77012274e-4] ji = [2, 4, 0, 1, 2, 3, 4] ii = [2, 2, 3, 3, 4, 4, 4] mur = sum(d/T_**j*rho**i for d, j, i in zip(dij, ji, ii)) # Eq 1 mu = muo + mub + mur return mu*1e-6 def _thermo(self, rho, T, fase): """Equation for the thermal conductivity Parameters ---------- rho : float Density, [kg/m³] T : float Temperature, [K] fase: dict phase properties Returns ------- k : float Thermal conductivity [W/mK] References ---------- Tufeu, R., Ivanov, D.Y., Garrabos, Y., and Le Neindre, B., Thermal conductivity of ammonia in a large temperature and pressure range including the critical region, Ber. Bunsenges. Phys. Chem., 88:422-427, 1984. doi:10.1002/bbpc.19840880421 """ # The paper use a diferent rhoc value to the EoS rhoc = 235 if rho == rhoc and T == self.Tc: warnings.warn("Thermal conductiviy undefined in critical point") return None # Eq 6 no = [0.3589e-1, -0.1750e-3, 0.4551e-6, 0.1685e-9, -0.4828e-12] Lo = sum(n*T**i for i, n in enumerate(no)) # Eq 7 nb = [0.16207e-3, 0.12038e-5, -0.23139e-8, 0.32749e-11] L_ = sum(n*rho**(i+1) for i, n in enumerate(nb)) # Critical enchancement t = abs(T-405.4)/405.4 dPT = 1e5*(2.18-0.12/exp(17.8*t)) nb = 1e-5*(2.6+1.6*t) DL = 1.2*Boltzmann*T**2/6/pi/nb/(1.34e-10/t**0.63*(1+t**0.5)) * \ dPT**2 * 0.423e-8/t**1.24*(1+t**0.5/0.7) # Add correction for entire range of temperature, Eq 10 DL *= exp(-36*t**2) X = 0.61*rhoc+16.5*log(t) if rho > 0.6*rhoc: # Eq 11 DL *= X**2/(X**2+(rho-0.96*rhoc)**2) else: # Eq 14 DL = X**2/(X**2+(0.6*rhoc-0.96*rhoc)**2) DL *= rho**2/(0.6*rhoc)**2 # Eq 5 k = Lo+L_+DL return k class H2ONH3(object): """Ammonia-water mixtures.""" # TODO: Add equilibrium routine def _prop(self, rho, T, x): """Thermodynamic properties of ammonia-water mixtures Parameters ---------- T : float Temperature [K] rho : float Density [kg/m³] x : float Mole fraction of ammonia in mixture [mol/mol] Returns ------- prop : dict Dictionary with thermodynamic properties of ammonia-water mixtures: * M: Mixture molecular mass, [g/mol] * P: Pressure, [MPa] * u: Specific internal energy, [kJ/kg] * s: Specific entropy, [kJ/kgK] * h: Specific enthalpy, [kJ/kg] * a: Specific Helmholtz energy, [kJ/kg] * g: Specific gibbs energy, [kJ/kg] * cv: Specific isochoric heat capacity, [kJ/kgK] * cp: Specific isobaric heat capacity, [kJ/kgK] * w: Speed of sound, [m/s] * fugH2O: Fugacity of water, [-] * fugNH3: Fugacity of ammonia, [-] References ---------- IAPWS, Guideline on the IAPWS Formulation 2001 for the Thermodynamic Properties of Ammonia-Water Mixtures, http://www.iapws.org/relguide/nh3h2o.pdf, Table 4 """ # FIXME: The values are good, bad difer by 1%, a error I can´t find # In Pressure happen and only use fird M = (1-x)*IAPWS95.M + x*NH3.M R = 8.314471/M phio = self._phi0(rho, T, x) fio = phio["fio"] tau0 = phio["tau"] fiot = phio["fiot"] fiott = phio["fiott"] phir = self._phir(rho, T, x) fir = phir["fir"] tau = phir["tau"] delta = phir["delta"] firt = phir["firt"] firtt = phir["firtt"] fird = phir["fird"] firdd = phir["firdd"] firdt = phir["firdt"] F = phir["F"] prop = {} Z = 1 + delta*fird prop["M"] = M prop["P"] = Z*R*T*rho/1000 prop["u"] = R*T*(tau0*fiot + tau*firt) prop["s"] = R*(tau0*fiot + tau*firt - fio - fir) prop["h"] = R*T*(1+delta*fird+tau0*fiot+tau*firt) prop["g"] = prop["h"]-T*prop["s"] prop["a"] = prop["u"]-T*prop["s"] cvR = -tau0**2*fiott - tau**2*firtt prop["cv"] = R*cvR prop["cp"] = R*(cvR+(1+delta*fird-delta*tau*firdt)**2 / (1+2*delta*fird+delta**2*firdd)) prop["w"] = (R*T*1000*(1+2*delta*fird+delta**2*firdd + (1+delta*fird-delta*tau*firdt)**2 / cvR))**0.5 prop["fugH2O"] = Z*exp(fir+delta*fird-x*F) prop["fugNH3"] = Z*exp(fir+delta*fird+(1-x)*F) return prop @staticmethod def _phi0(rho, T, x): """Ideal gas Helmholtz energy of binary mixtures and derivatives Parameters ---------- rho : float Density, [kg/m³] T : float Temperature, [K] x : float Mole fraction of ammonia in mixture, [mol/mol] Returns ------- prop : dict Dictionary with ideal adimensional helmholtz energy and derivatives: * tau: the adimensional temperature variable, [-] * delta: the adimensional density variable, [-] * fio,[-] * fiot: [∂fio/∂τ]δ [-] * fiod: [∂fio/∂δ]τ [-] * fiott: [∂²fio/∂τ²]δ [-] * fiodt: [∂²fio/∂τ∂δ] [-] * fiodd: [∂²fio/∂δ²]τ [-] References ---------- IAPWS, Guideline on the IAPWS Formulation 2001 for the Thermodynamic Properties of Ammonia-Water Mixtures, http://www.iapws.org/relguide/nh3h2o.pdf, Eq 2 """ # Define reducing parameters for mixture model M = (1-x)*IAPWS95.M + x*NH3.M tau = 500/T delta = rho/15/M # Table 2 Fi0 = { "log_water": 3.006320, "ao_water": [-7.720435, 8.649358], "pow_water": [0, 1], "ao_exp": [0.012436, 0.97315, 1.279500, 0.969560, 0.248730], "titao": [1.666, 4.578, 10.018, 11.964, 35.600], "log_nh3": -1.0, "ao_nh3": [-16.444285, 4.036946, 10.69955, -1.775436, 0.82374034], "pow_nh3": [0, 1, 1/3, -3/2, -7/4]} fiod = 1/delta fiodd = -1/delta**2 fiodt = 0 fiow = fiotw = fiottw = 0 fioa = fiota = fiotta = 0 # Water section if x < 1: fiow = Fi0["log_water"]*log(tau) + log(1-x) fiotw = Fi0["log_water"]/tau fiottw = -Fi0["log_water"]/tau**2 for n, t in zip(Fi0["ao_water"], Fi0["pow_water"]): fiow += n*tau**t if t != 0: fiotw += t*n*tau**(t-1) if t not in [0, 1]: fiottw += n*t*(t-1)*tau**(t-2) for n, t in zip(Fi0["ao_exp"], Fi0["titao"]): fiow += n*log(1-exp(-tau*t)) fiotw += n*t*((1-exp(-t*tau))**-1-1) fiottw -= n*t**2*exp(-t*tau)*(1-exp(-t*tau))**-2 # ammonia section if x > 0: fioa = Fi0["log_nh3"]*log(tau) + log(x) fiota = Fi0["log_nh3"]/tau fiotta = -Fi0["log_nh3"]/tau**2 for n, t in zip(Fi0["ao_nh3"], Fi0["pow_nh3"]): fioa += n*tau**t if t != 0: fiota += t*n*tau**(t-1) if t not in [0, 1]: fiotta += n*t*(t-1)*tau**(t-2) prop = {} prop["tau"] = tau prop["delta"] = delta prop["fio"] = log(delta) + (1-x)*fiow + x*fioa prop["fiot"] = (1-x)*fiotw + x*fiota prop["fiott"] = (1-x)*fiottw + x*fiotta prop["fiod"] = fiod prop["fiodd"] = fiodd prop["fiodt"] = fiodt return prop def _phir(self, rho, T, x): """Residual contribution to the free Helmholtz energy Parameters ---------- rho : float Density, [kg/m³] T : float Temperature, [K] x : float Mole fraction of ammonia in mixture, [mol/mol] Returns ------- prop : dict dictionary with residual adimensional helmholtz energy and derivatives: * tau: the adimensional temperature variable, [-] * delta: the adimensional density variable, [-] * fir, [-] * firt: [∂fir/∂τ]δ,x [-] * fird: [∂fir/∂δ]τ,x [-] * firtt: [∂²fir/∂τ²]δ,x [-] * firdt: [∂²fir/∂τ∂δ]x [-] * firdd: [∂²fir/∂δ²]τ,x [-] * firx: [∂fir/∂x]τ,δ [-] * F: Function for fugacity calculation, [-] References ---------- IAPWS, Guideline on the IAPWS Formulation 2001 for the Thermodynamic Properties of Ammonia-Water Mixtures, http://www.iapws.org/relguide/nh3h2o.pdf, Eq 3 """ # Temperature reducing value, Eq 4 Tc12 = 0.9648407/2*(IAPWS95.Tc+NH3.Tc) Tn = (1-x)**2*IAPWS95.Tc + x**2*NH3.Tc + 2*x*(1-x**1.125455)*Tc12 # sympy.diff("(1-x)^2*Tc1 + x^2*Tc2 + 2*x*(1-x^a)*Tc12", "x") # Out[]: Tc1*(2*x - 2) - 2*Tc12*a*x**a + 2*Tc12*(1 - x**a) + 2*Tc2*x dTnx = -2*IAPWS95.Tc*(1-x) + 2*x*NH3.Tc + 2*Tc12*(1-x**1.125455) - \ 2*Tc12*1.12455*x**1.12455 # Density reducing value, Eq 5 b = 0.8978069 rhoc1m = IAPWS95.rhoc/(IAPWS95.M/1000) rhoc2m = NH3.rhoc/(NH3.M/1000) M = (1-x)*IAPWS95.M + x*NH3.M rhoc12 = 1/(1.2395117/2*(1/rhoc1m + 1/rhoc2m)) rhonm = 1/((1-x)**2/rhoc1m + x**2/rhoc2m + 2*x*(1-x**b)/rhoc12) rhon = rhonm*M/1000 # sympy.diff("1/((1-x)^2/rhoc1 + x^2/rhoc2 + 2*x*(1-x^b)/rhoc12)", "x") # Out[]: (2*b*x**b/rhoc12 - 2*x/rhoc2 - 2*(1 - x**b)/rhoc12 - # (2*x - 2)/rhoc1)/(x**2/rhoc2 + 2*x*(1 - x**b)/rhoc12 + # (1 - x)**2/rhoc1)**2 drhonx = M/1000*(2*b*x**b/rhoc12 - 2*(1-x**b)/rhoc12 - 2*x/rhoc2m + 2*(1-x)/rhoc1m)/( 2*x*(1-x**b)/rhoc12 + x**2/rhoc2m + (1-x)**2/rhoc1m)**2 tau = Tn/T delta = rho/rhon water = IAPWS95() phi1 = water._phir(tau, delta) ammonia = NH3() phi2 = ammonia._phir(tau, delta) Dphi = self._Dphir(tau, delta, x) prop = {} prop["tau"] = tau prop["delta"] = delta prop["fir"] = (1-x)*phi1["fir"] + x*phi2["fir"] + Dphi["fir"] prop["firt"] = (1-x)*phi1["firt"] + x*phi2["firt"] + Dphi["firt"] prop["firtt"] = (1-x)*phi1["firtt"] + x*phi2["firtt"] + Dphi["firtt"] prop["fird"] = (1-x)*phi1["fird"] + x*phi2["fird"] + Dphi["fird"] prop["firdd"] = (1-x)*phi1["firdd"] + x*phi2["firdd"] + Dphi["firdd"] prop["firdt"] = (1-x)*phi1["firdt"] + x*phi2["firdt"] + Dphi["firdt"] prop["firx"] = -phi1["fir"] + phi2["fir"] + Dphi["firx"] prop["F"] = prop["firx"] - delta/rhon*drhonx*prop["fird"] + \ tau/Tn*dTnx*prop["firt"] return prop @staticmethod def _Dphir(tau, delta, x): """Departure function to the residual contribution to the free Helmholtz energy Parameters ---------- tau : float Adimensional temperature, [-] delta : float Adimensional density, [-] x : float Mole fraction of ammonia in mixture, [mol/mol] Returns ------- prop : dict Dictionary with departure contribution to the residual adimensional helmholtz energy and derivatives: * fir [-] * firt: [∂Δfir/∂τ]δ,x [-] * fird: [∂Δfir/∂δ]τ,x [-] * firtt: [∂²Δfir/∂τ²]δ,x [-] * firdt: [∂²Δfir/∂τ∂δ]x [-] * firdd: [∂²Δfir/∂δ²]τ,x [-] * firx: [∂Δfir/∂x]τ,δ [-] References ---------- IAPWS, Guideline on the IAPWS Formulation 2001 for the Thermodynamic Properties of Ammonia-Water Mixtures, http://www.iapws.org/relguide/nh3h2o.pdf, Eq 8 """ fx = x*(1-x**0.5248379) dfx = 1-1.5248379*x**0.5248379 # Polinomial terms n = -1.855822e-2 t = 1.5 d = 4 fir = n*delta**d*tau**t fird = n*d*delta**(d-1)*tau**t firdd = n*d*(d-1)*delta**(d-2)*tau**t firt = n*t*delta**d*tau**(t-1) firtt = n*t*(t-1)*delta**d*tau**(t-2) firdt = n*t*d*delta**(d-1)*tau**(t-1) firx = dfx*n*delta**d*tau**t # Exponential terms nr2 = [5.258010e-2, 3.552874e-10, 5.451379e-6, -5.998546e-13, -3.687808e-6] t2 = [0.5, 6.5, 1.75, 15, 6] d2 = [5, 15, 12, 12, 15] c2 = [1, 1, 1, 1, 2] for n, d, t, c in zip(nr2, d2, t2, c2): fir += n*delta**d*tau**t*exp(-delta**c) fird += n*exp(-delta**c)*delta**(d-1)*tau**t*(d-c*delta**c) firdd += n*exp(-delta**c)*delta**(d-2)*tau**t * \ ((d-c*delta**c)*(d-1-c*delta**c)-c**2*delta**c) firt += n*t*delta**d*tau**(t-1)*exp(-delta**c) firtt += n*t*(t-1)*delta**d*tau**(t-2)*exp(-delta**c) firdt += n*t*delta**(d-1)*tau**(t-1)*(d-c*delta**c)*exp( -delta**c) firx += dfx*n*delta**d*tau**t*exp(-delta**c) # Exponential terms with composition nr3 = [0.2586192, -1.368072e-8, 1.226146e-2, -7.181443e-2, 9.970849e-2, 1.0584086e-3, -0.1963687] t3 = [-1, 4, 3.5, 0, -1, 8, 7.5] d3 = [4, 15, 4, 5, 6, 10, 6] c3 = [1, 1, 1, 1, 2, 2, 2] for n, d, t, c in zip(nr3, d3, t3, c3): fir += x*n*delta**d*tau**t*exp(-delta**c) fird += x*n*exp(-delta**c)*delta**(d-1)*tau**t*(d-c*delta**c) firdd += x*n*exp(-delta**c)*delta**(d-2)*tau**t * \ ((d-c*delta**c)*(d-1-c*delta**c)-c**2*delta**c) firt += x*n*t*delta**d*tau**(t-1)*exp(-delta**c) firtt += x*n*t*(t-1)*delta**d*tau**(t-2)*exp(-delta**c) firdt += x*n*t*delta**(d-1)*tau**(t-1)*(d-c*delta**c)*exp( -delta**c) firx += x*dfx*n*delta**d*tau**t*exp(-delta**c) n = -0.7777897 t = 4 d = 2 c = 2 fir += x**2*n*delta**d*tau**t*exp(-delta**c) fird += x**2*n*exp(-delta**c)*delta**(d-1)*tau**t*(d-c*delta**c) firdd += x**2*n*exp(-delta**c)*delta**(d-2)*tau**t * \ ((d-c*delta**c)*(d-1-c*delta**c)-c**2*delta**c) firt += x**2*n*t*delta**d*tau**(t-1)*exp(-delta**c) firtt += x**2*n*t*(t-1)*delta**d*tau**(t-2)*exp(-delta**c) firdt += x**2*n*t*delta**(d-1)*tau**(t-1)*(d-c*delta**c)*exp( -delta**c) firx += x**2*dfx*n*delta**d*tau**t*exp(-delta**c) prop = {} prop["fir"] = fir*fx prop["firt"] = firt*fx prop["firtt"] = firtt*fx prop["fird"] = fird*fx prop["firdd"] = firdd*fx prop["firdt"] = firdt*fx prop["firx"] = firx return prop def Ttr(x): """Equation for the triple point of ammonia-water mixture Parameters ---------- x : float Mole fraction of ammonia in mixture, [mol/mol] Returns ------- Ttr : float Triple point temperature, [K] Notes ----- Raise :class:`NotImplementedError` if input isn't in limit: * 0 ≤ x ≤ 1 References ---------- IAPWS, Guideline on the IAPWS Formulation 2001 for the Thermodynamic Properties of Ammonia-Water Mixtures, http://www.iapws.org/relguide/nh3h2o.pdf, Eq 9 """ if 0 <= x <= 0.33367: Tr = 273.16*(1-0.3439823*x-1.3274271*x**2-274.973*x**3) elif 0.33367 < x <= 0.58396: Tr = 193.549*(1-4.987368*(x-0.5)**2) elif 0.58396 < x <= 0.81473: Tr = 194.38*(1-4.886151*(x-2/3)**2+10.37298*(x-2/3)**3) elif 0.81473 < x <= 1: Tr = 195.495*(1-0.323998*(1-x)-15.87560*(1-x)**4) else: raise NotImplementedError("Incoming out of bound") return Tr iapws-1.5.5/iapws/_utils.py0000644000175000017500000002365514673770354016056 0ustar alastairalastair#!/usr/bin/python # -*- coding: utf-8 -*- # pylint: disable=invalid-name, too-many-branches, too-many-statements # pylint: disable=too-many-arguments """ Miscelaneous internal utilities. This module include: * :func:`getphase`: Get phase string of state * :class:`_fase`: Base class to define a phase state * :func:`deriv_H`: Calculate generic partial derivative with a fundamental Helmholtz free energy equation of state * :func:`deriv_G`: Calculate generic partial derivative with a fundamental Gibbs free energy equation of state """ from __future__ import division def getphase(Tc, Pc, T, P, x, region): """Return fluid phase string name Parameters ---------- Tc : float Critical temperature, [K] Pc : float Critical pressure, [MPa] T : float Temperature, [K] P : float Pressure, [MPa] x : float Quality, [-] region: int Region number, used only for IAPWS97 region definition Returns ------- phase : str Phase name """ # Avoid round problem P = round(P, 8) T = round(T, 8) if P > Pc and T > Tc: phase = "Supercritical fluid" elif T > Tc: phase = "Gas" elif P > Pc: phase = "Compressible liquid" elif P == Pc and T == Tc: phase = "Critical point" elif region == 4 and x == 1: phase = "Saturated vapor" elif region == 4 and x == 0: phase = "Saturated liquid" elif region == 4: phase = "Two phases" elif x == 1: phase = "Vapour" elif x == 0: phase = "Liquid" return phase class _fase(object): """Class to implement a null phase""" v = None rho = None h = None s = None u = None a = None g = None cp = None cv = None cp_cv = None w = None Z = None fi = None f = None mu = None k = None nu = None Prandt = None epsilon = None alfa = None n = None alfap = None betap = None joule = None Gruneisen = None alfav = None kappa = None betas = None gamma = None Kt = None kt = None Ks = None ks = None dpdT_rho = None dpdrho_T = None drhodT_P = None drhodP_T = None dhdT_rho = None dhdT_P = None dhdrho_T = None dhdrho_P = None dhdP_T = None dhdP_rho = None Z_rho = None IntP = None hInput = None def deriv_H(state, z, x, y, fase): r"""Calculate generic partial derivative :math:`\left.\frac{\partial z}{\partial x}\right|_{y}` from a fundamental helmholtz free energy equation of state Parameters ---------- state : any python object Only need to define P and T properties, non phase specific properties z : str Name of variables in numerator term of derivatives x : str Name of variables in denominator term of derivatives y : str Name of constant variable in partial derivaritive fase : any python object Define phase specific properties (v, cv, alfap, s, betap) Notes ----- x, y and z can be the following values: * P: Pressure * T: Temperature * v: Specific volume * rho: Density * u: Internal Energy * h: Enthalpy * s: Entropy * g: Gibbs free energy * a: Helmholtz free energy Returns ------- deriv : float ∂z/∂x|y References ---------- IAPWS, Revised Advisory Note No. 3: Thermodynamic Derivatives from IAPWS Formulations, http://www.iapws.org/relguide/Advise3.pdf """ # We use the relation between rho and v and his partial derivative # ∂v/∂b|c = -1/ρ² ∂ρ/∂b|c # ∂a/∂v|c = -ρ² ∂a/∂ρ|c mul = 1 if z == "rho": mul = -fase.rho**2 z = "v" if x == "rho": mul = -1/fase.rho**2 x = "v" if y == "rho": y = "v" if x == "P": dTdx = state.P*1000*fase.alfap dvdx = -state.P*1000*fase.betap elif x == "T": dTdx = 1 dvdx = 0 elif x == "v": dTdx = 0 dvdx = 1 elif x == "u": dTdx = fase.cv dvdx = state.P*1000*(state.T*fase.alfap-1) elif x == "h": dTdx = fase.cv+state.P*1000*fase.v*fase.alfap dvdx = state.P*1000*(state.T*fase.alfap-fase.v*fase.betap) elif x == "s": dTdx = fase.cv/state.T dvdx = state.P*1000*fase.alfap elif x == "g": dTdx = state.P*1000*fase.v*fase.alfap-fase.s dvdx = -state.P*1000*fase.v*fase.betap elif x == "a": dTdx = -fase.s dvdx = -state.P*1000 if y == "P": dTdy = state.P*1000*fase.alfap dvdy = -state.P*1000*fase.betap elif y == "T": dTdy = 1 dvdy = 0 elif y == "v": dTdy = 0 dvdy = 1 elif y == "u": dTdy = fase.cv dvdy = state.P*1000*(state.T*fase.alfap-1) elif y == "h": dTdy = fase.cv+state.P*1000*fase.v*fase.alfap dvdy = state.P*1000*(state.T*fase.alfap-fase.v*fase.betap) elif y == "s": dTdy = fase.cv/state.T dvdy = state.P*1000*fase.alfap elif y == "g": dTdy = state.P*1000*fase.v*fase.alfap-fase.s dvdy = -state.P*1000*fase.v*fase.betap elif y == "a": dTdy = -fase.s dvdy = -state.P*1000 if z == "P": dTdz = state.P*1000*fase.alfap dvdz = -state.P*1000*fase.betap elif z == "T": dTdz = 1 dvdz = 0 elif z == "v": dTdz = 0 dvdz = 1 elif z == "u": dTdz = fase.cv dvdz = state.P*1000*(state.T*fase.alfap-1) elif z == "h": dTdz = fase.cv+state.P*1000*fase.v*fase.alfap dvdz = state.P*1000*(state.T*fase.alfap-fase.v*fase.betap) elif z == "s": dTdz = fase.cv/state.T dvdz = state.P*1000*fase.alfap elif z == "g": dTdz = state.P*1000*fase.v*fase.alfap-fase.s dvdz = -state.P*1000*fase.v*fase.betap elif z == "a": dTdz = -fase.s dvdz = -state.P*1000 deriv = (dvdz*dTdy-dTdz*dvdy)/(dvdx*dTdy-dTdx*dvdy) return mul*deriv def deriv_G(state, z, x, y, fase): r"""Calculate generic partial derivative :math:`\left.\frac{\partial z}{\partial x}\right|_{y}` from a fundamental Gibbs free energy equation of state Parameters ---------- state : any python object Only need to define P and T properties, non phase specific properties z : str Name of variables in numerator term of derivatives x : str Name of variables in denominator term of derivatives y : str Name of constant variable in partial derivaritive fase : any python object Define phase specific properties (v, cp, alfav, s, xkappa) Notes ----- x, y and z can be the following values: * P: Pressure * T: Temperature * v: Specific volume * rho: Density * u: Internal Energy * h: Enthalpy * s: Entropy * g: Gibbs free energy * a: Helmholtz free energy Returns ------- deriv : float ∂z/∂x|y References ---------- IAPWS, Revised Advisory Note No. 3: Thermodynamic Derivatives from IAPWS Formulations, http://www.iapws.org/relguide/Advise3.pdf """ mul = 1 if z == "rho": mul = -fase.rho**2 z = "v" if x == "rho": mul = -1/fase.rho**2 x = "v" if x == "P": dPdx = 1.0 dTdx = 0.0 elif x == "T": dPdx = 0.0 dTdx = 1.0 elif x == "v": dPdx = -fase.v*fase.xkappa dTdx = fase.v*fase.alfav elif x == "u": dPdx = fase.v*(state.P*1000.0*fase.xkappa-state.T*fase.alfav) dTdx = fase.cp-state.P*1000.0*fase.v*fase.alfav elif x == "h": dPdx = fase.v*(1.0-state.T*fase.alfav) dTdx = fase.cp elif x == "s": dPdx = -fase.v * fase.alfav dTdx = fase.cp/state.T elif x == "g": dPdx = fase.v dTdx = -fase.s elif x == "a": dPdx = state.P*1000.0*fase.v*fase.xkappa dTdx = -state.P * 1000.0 * fase.v * fase.alfav - fase.s else: raise ValueError("x must be one of P, T, v, u, h, s, g, a") if y == "P": dPdy = 1.0 dTdy = 0.0 elif y == "T": dPdy = 0.0 dTdy = 1.0 elif y == "v": dPdy = -fase.v*fase.xkappa dTdy = fase.v*fase.alfav elif y == "u": dPdy = fase.v*(state.P*1000.0*fase.xkappa-state.T*fase.alfav) dTdy = fase.cp-state.P*1000.0*fase.v*fase.alfav elif y == "h": dPdy = fase.v*(1.0-state.T*fase.alfav) dTdy = fase.cp elif y == "s": dPdy = -fase.v * fase.alfav dTdy = fase.cp/state.T elif y == "g": dPdy = fase.v dTdy = -fase.s elif y == "a": dPdy = state.P*1000.0*fase.v*fase.xkappa dTdy = -state.P * 1000.0 * fase.v * fase.alfav - fase.s else: raise ValueError("y must be one of P, T, v, u, h, s, g, a") if z == "P": dPdz = 1.0 dTdz = 0.0 elif z == "T": dPdz = 0.0 dTdz = 1.0 elif z == "v": dPdz = -fase.v*fase.xkappa dTdz = fase.v*fase.alfav elif z == "u": dPdz = fase.v*(state.P*1000.0*fase.xkappa-state.T*fase.alfav) dTdz = fase.cp-state.P*1000.0*fase.v*fase.alfav elif z == "h": dPdz = fase.v*(1.0-state.T*fase.alfav) dTdz = fase.cp elif z == "s": dPdz = -fase.v * fase.alfav dTdz = fase.cp/state.T elif z == "g": dPdz = fase.v dTdz = -fase.s elif z == "a": dPdz = state.P*1000.0*fase.v*fase.xkappa dTdz = -state.P * 1000.0 * fase.v * fase.alfav - fase.s else: raise ValueError("z must be one of P, T, v, u, h, s, g, a") deriv = (dPdz * dTdy - dTdz * dPdy) / (dPdx * dTdy - dTdx * dPdy) return mul*deriv def _instanceBuilder(p2val, *args): """Instance builder function""" cls, p1name, p1val, p2name = args return cls(**{p1name: p1val, p2name: p2val}) iapws-1.5.5/iapws.egg-info/0000775000175000017500000000000015161562600015650 5ustar alastairalastairiapws-1.5.5/iapws.egg-info/dependency_links.txt0000644000175000017500000000000115161562600021714 0ustar alastairalastair iapws-1.5.5/iapws.egg-info/requires.txt0000644000175000017500000000001315161562600020240 0ustar alastairalastairscipy>=1.2 iapws-1.5.5/iapws.egg-info/SOURCES.txt0000644000175000017500000000055015161562600017532 0ustar alastairalastairLICENSE MANIFEST.in README.rst setup.py iapws/VERSION iapws/__init__.py iapws/_iapws.py iapws/_iapws97Constants.py iapws/_utils.py iapws/ammonia.py iapws/humidAir.py iapws/iapws08.py iapws/iapws95.py iapws/iapws97.py iapws.egg-info/PKG-INFO iapws.egg-info/SOURCES.txt iapws.egg-info/dependency_links.txt iapws.egg-info/requires.txt iapws.egg-info/top_level.txtiapws-1.5.5/iapws.egg-info/PKG-INFO0000644000175000017500000001473615161562600016756 0ustar alastairalastairMetadata-Version: 2.4 Name: iapws Version: 1.5.5 Summary: Python implementation of standards from The InternationalAssociation for the Properties of Water and Steam Home-page: https://github.com/jjgomera/iapws Download-URL: https://github.com/jjgomera/iapws/tarball/v1.5.5 Author: jjgomera Author-email: jjgomera@gmail.com License: gpl v3 Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Education Classifier: Intended Audience :: Science/Research Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3) Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Scientific/Engineering Classifier: Topic :: Scientific/Engineering :: Chemistry Classifier: Topic :: Scientific/Engineering :: Physics Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.* License-File: LICENSE Requires-Dist: scipy>=1.2 Dynamic: author Dynamic: author-email Dynamic: classifier Dynamic: description Dynamic: download-url Dynamic: home-page Dynamic: license Dynamic: license-file Dynamic: requires-dist Dynamic: requires-python Dynamic: summary .. image:: https://dl.circleci.com/status-badge/img/gh/jjgomera/iapws/tree/master.svg?style=svg :target: https://dl.circleci.com/status-badge/redirect/gh/jjgomera/iapws/tree/master :alt: Build Status .. image:: https://ci.appveyor.com/api/projects/status/a128sh8e50cjsiya?svg=true :target: https://ci.appveyor.com/project/jjgomera/iapws :alt: Windows Build Status .. image:: https://coveralls.io/repos/github/jjgomera/iapws/badge.svg?branch=master :target: https://coveralls.io/github/jjgomera/iapws?branch=master :alt: coveralls.io analysis .. image:: https://codecov.io/gh/jjgomera/iapws/branch/master/graph/badge.svg :target: https://codecov.io/gh/jjgomera/iapws :alt: codecov.io analysis .. image:: https://app.codacy.com/project/badge/Grade/bb92d537dfa1461d919a0782f3c398b9 :target: https://www.codacy.com/gh/jjgomera/iapws/dashboard?utm_source=github.com&utm_medium=referral&utm_content=jjgomera/iapws&utm_campaign=Badge_Grade :alt: Code Quality .. image:: http://readthedocs.org/projects/iapws/badge/?version=latest :target: http://iapws.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status .. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.4744318.svg :target: https://doi.org/10.5281/zenodo.4744318 :alt: DOI iapws ===== Python implementation of standard from IAPWS (http://www.iapws.org/release.html). The module implements the full set of standards, including:: IAPWS-IF97 IAPWS-95 IAPWS-06 for Ice IAPWS-08 for seawater IAPWS-17 for Heavy water ... dependences -------------------- * Support for both python branch:: * python 2.7 * python 3.4 or later * Numpy-scipy: library with mathematic and scientific tools install -------------------- In debian you can find in official repositories in jessie, testing and sid. In ubuntu it's in official repositories from ubuntu saucy (13.10). In other system you can install using pip:: pip install iapws or directly from the github repository:: pip install git+https://github.com/jjgomera/iapws.git This is the recommended option to have the latest version. documentation -------------------- To see the full documentation of package, see `readthedocs `__ .. inclusion-marker-do-not-remove For a rapid usage demostration, see this examples IAPWS-IF97 (`see full documentation `__) .. code:: python from iapws import IAPWS97 sat_steam = IAPWS97(P=1,x=1) #saturated steam with known P sat_liquid = IAPWS97(T=370, x=0) #saturated liquid with known T steam = IAPWS97(P=2.5, T=500) #steam with known P and T print(sat_steam.h, sat_liquid.h, steam.h) #calculated enthalpies IAPWS-95 (`see full documentation `__) .. code:: python from iapws import IAPWS95 sat_steam = IAPWS95(P=1,x=1) #saturated steam with known P sat_liquid = IAPWS95(T=370, x=0) #saturated liquid with known T steam = IAPWS95(P=2.5, T=500) #steam with known P and T print(sat_steam.h, sat_liquid.h, steam.h) #calculated enthalpies For calculation of multiple states is possible use multiprocessing to speed up calculation, 6x in my laptop. Method valid too for D2O .. code:: python from iapws import IAPWS95 from numpy import arange from time import time x = arange(0, 1.01, 0.01) def fi(x): return IAPWS95(P=20.8, x=x) start = time() for xi in x: fi(xi) print(f'Without multiprocessing: {time() - start}') start = time() states = IAPWS95.from_list("P", 20.8, "x", x) print(f'With multiprocessing: {time() - start}') IAPWS-17 for Heavy water (`see full documentation `__) .. code:: python from iapws import D2O sat_liquid = D2O(T=370, x=0) #saturated liquid with known T print(sat_liquid.h) #calculated enthalpy IAPWS-06 for Ice Ih (`see full documentation `__) .. code:: python from iapws import _Ice ice = _Ice(273.15, 0.101325) #Ice at normal melting point print(ice["rho"]) #Calculated density IAPWS-08 for seawater (`see full documentation `__) .. code:: python from iapws import SeaWater state = SeaWater(T=300, P=0.101325, S=0.001) #Seawater with 0.1% Salinity print(state.cp) # Get cp TODO ==== * TODO: Improve convergence in two phase region for IAPWS95 and D2O class * TODO: Implement SBTL method for fast calculation * TODO: Implement TTSE method for fast calculation Ammonia-water mixture: * TODO: Add equilibrium routine I've tried to test all code and use all values for computer verification the standards give, but anyway the code can have hidden problem. For any suggestions, comments, bugs ... you can usage the `github issue section `__, or contact directly with me at `email `__. iapws-1.5.5/iapws.egg-info/top_level.txt0000644000175000017500000000000615161562600020374 0ustar alastairalastairiapws