\section{How to read this reference}

This part is the normative TeX reference for \pkg{luacoolprop}.  Every public
command has a blue entry; every public key has a green entry and at least one
concrete assignment.  The examples in ``source/result'' boxes are compiled as
part of this manual: the code shown on the left is exactly the code which
produced the result on the right.  Longer examples put the result below the
source.  This is the same literate, executable-documentation principle used by
the PGF/TikZ and PGFPlots manuals.

Signatures use \meta{argument} for a required semantic value, \marg{argument}
for a braced argument, and \oarg{options} for an optional key list.  Boolean
keys take \texttt{true} or \texttt{false}.  A fraction along a curve is in the
closed interval $[0,1]$.  Temperatures, pressures, enthalpies, entropies, and
specific volumes use the units stated by the corresponding unit or scale key.

All numeric input is locale independent.  Use a full stop as the decimal
separator, irrespective of the document language or the output settings of
\pkg{siunitx}.  Integers, decimal floating-point numbers, and decimal scientific
notation are accepted: \texttt{12}, \texttt{-0.25}, \texttt{.5}, and
\texttt{1.2E5} are valid.  A recognized unit may immediately follow a process
quantity, as in \texttt{1.2E5Pa}.  Decimal commas, hexadecimal Lua literals,
non-finite values, trailing characters, and unknown units are errors.  Numeric
lists use commas, spaces, or semicolons only to separate complete numbers.
Likewise, malformed booleans, modes, presets, list members, and reversed
explicit bounds are rejected instead of being replaced by defaults.

\begin{LCPNote}[Namespaces and extensibility]
The canonical root is \texttt{/luacoolprop/diagram}, with uppercase
\texttt{PH}, \texttt{PV}, \texttt{TS}, \texttt{HS}, and \texttt{PT} branches.  Keys are
passed without
that prefix in command option lists.  The generic commands take an uppercase
identifier and allow registered custom coordinate systems.  The
lowercase \texttt{ph diagram}, \texttt{pv diagram}, \texttt{ts diagram},
\texttt{hs diagram}, and \texttt{pt diagram} branches directly below
\texttt{/luacoolprop} are only
alternate public paths.  No diagram type supplies defaults or capabilities to
another type.
\end{LCPNote}

\section{Loading in the three supported formats}

The generic layer is \texttt{luacoolprop.tex}.  The format files only arrange
loading: \texttt{luacoolprop.sty} for LaTeX, \texttt{t-luacoolprop.tex} for
ConTeXt, and \texttt{p-luacoolprop.tex} for plain TeX.

\begin{LCPExample}{LaTeX}
\documentclass{article}
\usepackage{luacoolprop}
\begin{document}
  \LCPPHDiagram
\end{document}
\end{LCPExample}

\begin{LCPExample}{Plain LuaTeX}
\input p-luacoolprop.tex
\pgfplotsset{compat=1.18}
\LCPPHDiagram
\bye
\end{LCPExample}

\begin{LCPExample}{ConTeXt}
\usemodule[t][luacoolprop]
\pgfplotsset{compat=1.18}
\starttext
  \LCPPHDiagram
\stoptext
\end{LCPExample}

All three formats require full shell escape because the TeX Live engine exposes
the FFI module used to load the external CoolProp shared library only in that
mode.  Use \texttt{lualatex --shell-escape},
\texttt{luatex --shell-escape}, or
\texttt{context --luatex --shell-escape}, as appropriate.  This option allows
every trusted or untrusted input in the document to execute external programs;
read the security warning in the installation chapter before enabling it.

\section{Global configuration and fluid constants}

\begin{LCPCommandRef}{LCPSetup}{\marg{options}}
Changes persistent package defaults.  The settings apply to subsequently
created diagrams and process paths.
\begin{LCPExample}{Select a fluid and plotting scales globally}
\LCPSetup{fluid=Propane,
  enthalpy scale=0.001,
  pressure scale=0.00001}
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPSetFluid}{\marg{fluid}}
Sets the global CoolProp fluid identifier.  It does not query CoolProp until a
diagram is drawn or constants are updated.
\begin{LCPExample}{Use propane in subsequent operations}
\LCPSetFluid{Propane}
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPSetLibrary}{\marg{path}}
Sets the CoolProp shared-library path for subsequent calls.  Usually the
environment variable \texttt{LUACOOLPROP\_LIB} is preferable because the TeX
source then remains portable. Leading and trailing whitespace around a braced
path is ignored; spaces inside a directory or file name are preserved.
\begin{LCPExample}{Explicit shared-library path}
\LCPSetLibrary{/opt/coolprop/libCoolProp.dylib}
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPSetReferenceState}{\marg{convention}}
Selects the CoolProp enthalpy/entropy reference convention for the current
global fluid.  The accepted conventions are \texttt{DEF}, \texttt{IIR},
\texttt{ASHRAE}, and \texttt{NBP}.  Call this command during initialization,
before updating constants, creating a diagram, or evaluating a process for the
fluid.  The first diagram calculation locks the choice; a later attempt to
change it is an error because it would mix incompatible $h$ and $s$ coordinates
in one run.  Repeating the same convention is harmless.
\begin{LCPExample}{Select the IIR reference during initialization}
\LCPSetFluid{R134a}
\LCPSetReferenceState{IIR}
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPUpdateFluidConstants}{}
Queries CoolProp for the current fluid and refreshes all constant macros listed
below.  Call it after changing the fluid with \macro{\LCPSetFluid}.
\begin{LCPExample}{Refresh the constants of the current fluid}
\LCPSetFluid{R134a}
\LCPUpdateFluidConstants
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPDeclareFluid}{\marg{fluid}}
Combines \macro{\LCPSetFluid} and \macro{\LCPUpdateFluidConstants}.
\begin{LCPShowcase}{Query and typeset fluid constants}
\LCPDeclareFluid{R134a}
Fluid: \LCPFluidName\par
$T_{\mathrm c}=\LCPFluidTcritC\,^{\circ}\mathrm C$\par
$p_{\mathrm c}=\LCPFluidPcritBar\,\mathrm{bar}$
\end{LCPShowcase}
\end{LCPCommandRef}

The update command defines the following expandable result macros.  Empty
values mean that no update has run yet.

\noindent\begin{tabularx}{\linewidth}{@{}>{\ttfamily\textbackslash}l X@{}}
\toprule
\normalfont Command & Meaning and unit \\
\midrule
LCPFluidName & CoolProp fluid identifier.\\
LCPFluidReferenceState & Active enthalpy/entropy reference convention.\\
LCPFluidPcritSI & Critical pressure in pascals.\\
LCPFluidPcritBar & Critical pressure in bar.\\
LCPFluidPcritPlot & Critical pressure after the global pressure scale.\\
LCPFluidPtripleSI & Triple-point pressure in pascals.\\
LCPFluidPtripleBar & Triple-point pressure in bar.\\
LCPFluidTcritK & Critical temperature in kelvin.\\
LCPFluidTcritC & Critical temperature in degrees Celsius.\\
LCPFluidTtripleK & Triple-point temperature in kelvin.\\
LCPFluidTtripleC & Triple-point temperature in degrees Celsius.\\
LCPFluidRhocritSI & Critical mass density in kilograms per cubic metre.\\
\bottomrule
\end{tabularx}

\foreach \LCPResultMacro in {LCPFluidName,LCPFluidReferenceState,LCPFluidPcritSI,LCPFluidPcritBar,
  LCPFluidPcritPlot,LCPFluidPtripleSI,LCPFluidPtripleBar,LCPFluidTcritK,
  LCPFluidTcritC,LCPFluidTtripleK,LCPFluidTtripleC,LCPFluidRhocritSI}{%
  \index[commands]{\LCPResultMacro@\protect\texttt{\protect\textbackslash\LCPResultMacro}}}

\subsection{Global keys: \texttt{/luacoolprop}}

\LCPKeyDoc{luacoolprop}{fluid}{CoolProp identifier}{R134a}
  {Sets the default fluid and has the same effect as \macro{\LCPSetFluid}.}
  {Propane}
\LCPKeyDoc{luacoolprop}{library}{file path}{empty}
  {Overrides discovery of the external shared library.  Prefer
   \texttt{LUACOOLPROP\_LIB} in reproducible workflows.}
  {/opt/coolprop/libCoolProp.dylib}
\LCPKeyDoc{luacoolprop}{reference state}{DEF, IIR, ASHRAE, or NBP}{DEF}
  {Selects the persistent reference convention used for both enthalpy and
   entropy.  Set it before the first calculation for each fluid.}
  {IIR}
\LCPKeyDoc{luacoolprop}{enthalpy axis unit}{jkg or kjkg}{kjkg}
  {Selects both the enthalpy coordinate conversion and its generated axis
   label.  Prefer this semantic key to a raw scale.}
  {jkg}
\LCPKeyDoc{luacoolprop}{pressure axis unit}{pa, kpa, mpa, or bar}{bar}
  {Selects both the pressure coordinate conversion and its generated axis
   label.}
  {mpa}
\LCPKeyDoc{luacoolprop}{specific volume axis unit}{m3kg or lkg}{m3kg}
  {Selects both the specific-volume coordinate conversion and its generated
   axis label.}
  {lkg}
\LCPKeyDoc{luacoolprop}{entropy axis unit}{jkgk or kjkgk}{kjkgk}
  {Selects both the entropy coordinate conversion and its generated axis
   label.}
  {jkgk}
\LCPKeyDoc{luacoolprop}{temperature axis unit}{kelvin or celsius}{kelvin}
  {Selects the TS ordinate and label together.  Celsius applies the additive
   offset $T_{\rm plot}=T_{\rm SI}-273.15$, not merely a multiplier.}
  {celsius}
\LCPKeyDoc{luacoolprop}{enthalpy scale}{number}{0.001}
  {Multiplies CoolProp enthalpies in SI units before plotting.  The default
   converts \texttt{J/kg} to \texttt{kJ/kg}.  This advanced raw interface
   deliberately replaces the named-unit label by an explicit scaled-SI
   formula; use \texttt{enthalpy axis unit} for an ordinary unit label.}
  {0.001}
\LCPKeyDoc{luacoolprop}{pressure scale}{number}{0.00001}
  {Multiplies CoolProp pressures in pascals before plotting.  The default
   converts pascals to bar.  A raw value produces a scaled-SI axis label.}
  {0.00001}
\LCPKeyDoc{luacoolprop}{specific volume scale}{number}{1}
  {Multiplies CoolProp mass-specific volumes in SI units before plotting a PV
   diagram.  The default retains \texttt{m3/kg}; a raw value produces a
   scaled-SI axis label.}
  {1}
\LCPKeyDoc{luacoolprop}{entropy scale}{number}{0.001}
  {Multiplies CoolProp mass-specific entropy in \texttt{J/(kg K)} before
   plotting a TS or HS diagram.  The default gives \texttt{kJ/(kg K)}; a raw
   value produces a scaled-SI axis label.}
  {0.001}
\LCPKeyDoc{luacoolprop}{temperature scale}{number}{1}
  {Multiplies CoolProp absolute temperatures before plotting a TS diagram.
   A raw scale has zero offset and produces a scaled-SI label.}
  {1}
\LCPKeyAlias{luacoolprop}{h scale}{enthalpy scale}
\LCPKeyAlias{luacoolprop}{p scale}{pressure scale}
\LCPKeyAlias{luacoolprop}{v scale}{specific volume scale}
\LCPKeyAlias{luacoolprop}{s scale}{entropy scale}
\LCPKeyAlias{luacoolprop}{t scale}{temperature scale}

\section{The generic diagram API}

Use this API in libraries or in documents which may later switch diagram
coordinates.  The diagram identifier is case-sensitive and uppercase.

\begin{LCPCommandRef}{LCPDiagram}{\marg{type}\oarg{options}}
Creates a complete TikZ picture and PGFPlots axis for \meta{type}.
\begin{LCPShowcase}[lefthand ratio=.48]{The generic PH renderer}
\LCPDiagram{PH}[
  fluid=R134a,
  quality values={0,0.5,1},
  axis options={width=5.2cm,height=4.1cm,
    font=\scriptsize}
]
\end{LCPShowcase}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddDiagramPlots}{\marg{type}\oarg{options}}
Adds all enabled curve families to an existing axis.  It does not create the
axis, so the caller controls its coordinates and styling.
\begin{LCPExample}{Add PH plots to an existing axis}
\begin{tikzpicture}
\begin{axis}[ymode=log]
  \LCPAddDiagramPlots{PH}[fluid=R134a]
\end{axis}
\end{tikzpicture}
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddDiagramFamily}{\marg{type}\marg{family}\oarg{options}}
Adds exactly one family to an existing axis.  PH registers
\texttt{quality}, \texttt{isotherm}, \texttt{isentrope}, and
\texttt{isochore}; PV registers \texttt{quality}, \texttt{isotherm}, and
\texttt{isentrope}; TS registers \texttt{quality} and \texttt{isenthalp}; HS
registers \texttt{quality}, \texttt{isochore}, \texttt{isotherm}, and
\texttt{isobar}; PT registers \texttt{phase\_envelope},
\texttt{isentrope}, \texttt{isenthalp}, and \texttt{isochore}.
\begin{LCPExample}{Add only PH isotherms}
\LCPAddDiagramFamily{PH}{isotherm}[
  temperature values={-20,0,20,40}]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddDiagramProcess}{\marg{type}\oarg{options}}
Adds one thermodynamic process path to an existing axis.
\begin{LCPExample}{Add an isobaric PH process}
\LCPAddDiagramProcess{PH}[
  type=isobar,pressure=8bar,
  from={quality=0},to={quality=1}]
\end{LCPExample}
\end{LCPCommandRef}

\subsection{A symmetric capability contract}

Each registered type declares its coordinate properties and background
families.  The dispatcher validates those declarations before it performs any
CoolProp calculation; PH is one implementation in this registry, not the base
class of PV, TS, HS, or PT.

\begin{center}
\begin{tabular}{@{}lllll@{}}
\toprule
Type & $x$ & $y$ & quality & other background families \\
\midrule
PH & $h$ & $p$ & yes & isotherm, isentrope, isochore \\
PV & $v$ & $p$ & yes & isotherm, isentrope \\
TS & $s$ & $T$ & yes & isenthalp \\
HS & $s$ & $h$ & yes & isochore, isotherm, isobar \\
PT & $T$ & $p$ & no & phase envelope, isentrope, isenthalp, isochore \\
\bottomrule
\end{tabular}
\end{center}

An explicit switch for a family absent from this table is a hard error, not a
silently ignored option.  For example, \texttt{isochore=true} is invalid for a
PV background, \texttt{isotherm=true} is invalid for TS,
\texttt{isentrope=true} is invalid for HS, and \texttt{quality=true} is
invalid for PT because quality is degenerate in PT coordinates.  A
conserved-property process is a
different object: all six process kinds may be projected on every diagram even
when the corresponding background family is unavailable.

\subsection{Pure-fluid and reference-state contracts}

The diagram API accepts only identifiers for which CoolProp reports
\texttt{pure=true}.  Explicit mixtures, predefined \texttt{.mix} files, and
blend names such as \texttt{R407C} are rejected before sampling.  Diagram
construction assumes one triple point, one critical point, and one saturation
dome; mixtures need phase-envelope and flash logic which this release does not
claim to implement.  Lua's low-level CoolProp wrappers remain available for
deliberate mixture calculations.  See CoolProp's mixture restrictions at
\url{https://coolprop.org/fluid_properties/Mixtures.html}.

Specific enthalpy and entropy are relative properties.  Their numerical
origins depend on \texttt{reference state}; pressure, temperature, density,
specific volume, and enthalpy differences are unaffected by choosing another
origin.  Set one convention during initialization and use it throughout every
diagram, exported state, table, and calculation which is compared.  Energy
balances should normally use differences such as $h_2-h_1$, never infer a
physical heat or work transfer from an isolated absolute value of $h$.
The conventions and initialization rule follow
\url{https://coolprop.org/coolprop/HighLevelAPI.html#reference-states}.

\LCPKeyDoc{luacoolprop/diagram/common}{reference state}{DEF, IIR, ASHRAE, or NBP}{DEF}
  {Selects and then locks the CoolProp enthalpy/entropy origin for the diagram
   fluid.  A per-diagram value must agree with every earlier calculation for
   that fluid.}
  {IIR}

\subsection{Disconnected thermodynamic domains}

Adaptive sampling never joins two valid regions across a state rejected by
CoolProp.  Every connected component is serialized separately and PGFPlots
receives \texttt{unbounded coords=jump}; labels use one connected component
instead of interpolating through the gap.  This matters near equation-of-state
limits and for conserved-property curves which leave and later re-enter a
valid domain.

\LCPKeyDoc{luacoolprop/diagram/common}{domain policy}{ignore, warning, or error}{ignore}
  {Controls the diagnostic when samples are omitted.  \texttt{ignore} keeps
   valid components silently, \texttt{warning} reports the number omitted and
   retained, and \texttt{error} stops the build.  \texttt{silent} and
   \texttt{warn} are accepted Lua compatibility spellings.}
  {warning}
\LCPKeyAlias{luacoolprop/diagram/common}{discontinuity policy}{domain policy}

The same \texttt{reference state} and \texttt{domain policy} keys belong to
every process namespace.  Its canonical path is
\path{/luacoolprop/process/TYPE}.  Process metadata records
the active reference convention; endpoint exports always retain raw SI
properties independently of the plotted coordinate units.
Each process namespace also accepts the semantic axis-unit keys belonging to
its projection, so a manual axis can apply one choice consistently to both
backgrounds and paths.  For example:
\begin{LCPExample}{A Celsius TS background and process}
\LCPSetup{temperature axis unit=celsius}
\LCPAddTSQuality[quality values={0,1}]
\LCPAddTSProcess[type=isobar,pressure=2bar,
  from={quality=0},to={quality=1}]
\end{LCPExample}

\section{PH convenience commands}

The following commands are stable conveniences for the current PH diagram.
Their options use \texttt{/luacoolprop/diagram/PH}; process options use
\texttt{/luacoolprop/process/PH}.

\begin{LCPCommandRef}{LCPPHDiagram}{\oarg{options}}
Equivalent to \texttt{\string\LCPDiagram\{PH\}}.  It creates the picture, axis,
automatic PH ranges, and all enabled families.
\begin{LCPShowcase}[lefthand ratio=.48]{A compact labelled PH diagram}
\LCPPHDiagram[
  fluid=R134a,
  quality values={0,0.5,1},
  labels=true,
  axis options={width=5.2cm,height=4.1cm,
    font=\scriptsize}
]
\end{LCPShowcase}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddPHPlots}{\oarg{options}}
Adds all enabled PH families inside an existing axis.
\begin{LCPExample}{Quality dome plus isotherms}
\LCPAddPHPlots[quality=true,isotherm=true,
  temperature values={-20,0,20,40}]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddPHQuality}{\oarg{options}}
Adds only the quality family, including the saturated-liquid and
saturated-vapour boundaries.
\begin{LCPExample}{Five quality curves}
\LCPAddPHQuality[quality values={0,0.25,0.5,0.75,1}]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddPHIsotherms}{\oarg{options}}
Adds only constant-temperature curves.
\begin{LCPExample}{Explicit Celsius temperatures}
\LCPAddPHIsotherms[temperature values={-20,0,20,40}]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddPHIsentropes}{\oarg{options}}
Adds only constant-specific-entropy curves.
\begin{LCPExample}{Explicit entropy values}
\LCPAddPHIsentropes[entropy values={1.6,1.8,2.0}]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddPHIsochores}{\oarg{options}}
Adds only constant-specific-volume curves.
\begin{LCPExample}{Logarithmic specific-volume grid}
\LCPAddPHIsochores[specific volume min=0.01,
  specific volume max=0.2,specific volume count=5]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddPHProcess}{\oarg{options}}
Adds a PH process path.  See the complete process-key reference below.
\begin{LCPExample}{Named evaporation process}
\LCPAddPHProcess[type=isobar,pressure=8bar,
  from={quality=0},to={quality=1},
  name=evaporation,label={evaporator}]
\end{LCPExample}
\end{LCPCommandRef}

\subsection{Alternate command names}

The uppercase \texttt{PH} spellings above are canonical.
\LCPCommandAlias{LCPPhDiagram}{LCPPHDiagram}
\LCPCommandAlias{LCPAddPHIsoQuality}{LCPAddPHQuality}
\LCPCommandAlias{LCPAddPhIsoQuality}{LCPAddPHQuality}
\LCPCommandAlias{LCPAddPhIsotherms}{LCPAddPHIsotherms}
\LCPCommandAlias{LCPAddPhIsentropes}{LCPAddPHIsentropes}
\LCPCommandAlias{LCPAddPhIsochores}{LCPAddPHIsochores}
\LCPCommandAlias{LCPAddPhPlots}{LCPAddPHPlots}
\LCPCommandAlias{LCPAddPhProcess}{LCPAddPHProcess}
\LCPCommandAlias{LCPPhIsoQualityDiagram}{LCPPHDiagram}

\section{PH diagram keys}
\label{sec:ph-diagram-keys}

Unless stated otherwise, all keys in this section belong to
\texttt{/luacoolprop/diagram/PH}.  In a command option list, write only the
leaf name, for example \texttt{fluid=Propane}.

\subsection{Fluid, families, ranges, and axis}

\LCPKeyDoc{luacoolprop/diagram/PH}{fluid}{CoolProp identifier}{global fluid}
  {Selects the fluid for this diagram only.}{Propane}
\LCPKeyDoc{luacoolprop/diagram/PH}{library}{file path}{global library}
  {Overrides the shared-library path for this diagram.}{/opt/coolprop/libCoolProp.dylib}
\LCPKeyDoc{luacoolprop/diagram/PH}{quality}{boolean}{true}
  {Enables or disables the quality family.}{false}
\LCPKeyDoc{luacoolprop/diagram/PH}{isotherm}{boolean}{false}
  {Enables or disables the isotherm family.}{true}
\LCPKeyDoc{luacoolprop/diagram/PH}{isentrope}{boolean}{false}
  {Enables or disables the isentrope family.}{true}
\LCPKeyDoc{luacoolprop/diagram/PH}{isochore}{boolean}{false}
  {Enables or disables the isochore family.}{true}
\LCPKeyDoc{luacoolprop/diagram/PH}{pressure min}{number or auto}{auto}
  {Sets the lower sampling pressure in pascals.}{50000}
\LCPKeyDoc{luacoolprop/diagram/PH}{pressure max}{number or auto}{auto}
  {Sets the upper sampling pressure in pascals.}{5E6}
\LCPKeyDoc{luacoolprop/diagram/PH}{pressure max factor}{positive number}{1.10}
  {When the maximum is automatic, multiplies the critical pressure to leave
   headroom above the critical point.}{1.05}
\LCPKeyDoc{luacoolprop/diagram/PH}{enthalpy scale}{number}{global scale}
  {Advanced raw multiplier for SI enthalpy.  It selects the explicit
   scaled-SI label rather than claiming a named unit.}{0.002}
\LCPKeyDoc{luacoolprop/diagram/PH}{pressure scale}{number}{global scale}
  {Advanced raw multiplier for SI pressure.  It selects the explicit
   scaled-SI label rather than claiming a named unit.}{0.00002}
\LCPKeyDoc{luacoolprop/diagram/PH}{enthalpy axis unit}{jkg or kjkg}{kjkg}
  {Atomically selects the enthalpy multiplier and horizontal-axis unit.}
  {jkg}
\LCPKeyDoc{luacoolprop/diagram/PH}{pressure axis unit}{pa, kpa, mpa, or bar}{bar}
  {Atomically selects the pressure multiplier and vertical-axis unit.}
  {mpa}
\LCPKeyDoc{luacoolprop/diagram/PH}{enthalpy symbol}{TeX math material}{h}
  {Sets the enthalpy symbol in the horizontal axis created by
   \macro{\LCPPHDiagram}.  Omit surrounding math delimiters.}{{\mathcal H}}
\LCPKeyDoc{luacoolprop/diagram/PH}{pressure symbol}{TeX math material}{p}
  {Sets the pressure symbol in the vertical axis created by
   \macro{\LCPPHDiagram}.  Omit surrounding math delimiters.}{{\pi}}
\LCPKeyDoc{luacoolprop/diagram/PH}{axis options}{PGFPlots options}{empty}
  {Appends options to the axis created by \macro{\LCPPHDiagram}.  Width,
   height, labels, limits, legend placement, and fonts may all be overridden.}
  {{width=10cm,height=7cm,title={R134a}}}

\LCPKeyAlias{luacoolprop/diagram/PH}{iso quality}{quality}
\LCPKeyAlias{luacoolprop/diagram/PH}{isoquality}{quality}
\LCPKeyAlias{luacoolprop/diagram/PH}{quality curves}{quality}
\LCPKeyAlias{luacoolprop/diagram/PH}{isotherms}{isotherm}
\LCPKeyAlias{luacoolprop/diagram/PH}{isentropes}{isentrope}
\LCPKeyAlias{luacoolprop/diagram/PH}{isochores}{isochore}
\LCPKeyAlias{luacoolprop/diagram/PH}{p min}{pressure min}
\LCPKeyAlias{luacoolprop/diagram/PH}{p max}{pressure max}
\LCPKeyAlias{luacoolprop/diagram/PH}{p max factor}{pressure max factor}
\LCPKeyAlias{luacoolprop/diagram/PH}{h scale}{enthalpy scale}
\LCPKeyAlias{luacoolprop/diagram/PH}{p scale}{pressure scale}

\begin{LCPShowcase}[lefthand ratio=.48]{Choosing families and appearance}
\LCPPHDiagram[
  quality=true,isotherm=true,
  isentrope=false,isochore=false,
  temperature values={-20,20,60},
  isotherm color=purple,
  axis options={width=5.2cm,height=4.1cm,
    font=\scriptsize}
]
\end{LCPShowcase}

\subsection{Quality grid}

Quality is the vapour mass fraction: $q=0$ is saturated liquid and $q=1$ is
saturated vapour.  Use either an explicit list, a preset, a count, or a
minimum/maximum/step description.  An explicit list has highest practical
clarity in archival documents.

\LCPKeyDoc{luacoolprop/diagram/PH}{quality min}{number}{0}
  {Lower quality in a generated grid.}{0.1}
\LCPKeyDoc{luacoolprop/diagram/PH}{quality max}{number}{1}
  {Upper quality in a generated grid.}{0.9}
\LCPKeyDoc{luacoolprop/diagram/PH}{quality step}{positive number}{0.1}
  {Increment used by a linear grid.}{0.2}
\LCPKeyDoc{luacoolprop/diagram/PH}{quality count}{integer or auto}{auto}
  {Requests an evenly distributed number of values.}{6}
\LCPKeyDoc{luacoolprop/diagram/PH}{quality values}{comma list}{empty}
  {Supplies the exact qualities and overrides generated-grid controls.}
  {{0,0.25,0.5,0.75,1}}
\begin{LCPKeyRef}{luacoolprop/diagram/PH}{quality mode}{choice}{linear}
Selects how grid values are obtained.
\begin{description}
\LCPChoice{luacoolprop/diagram/PH}{quality mode}{linear}{Uniform spacing between the bounds.}
\LCPChoice{luacoolprop/diagram/PH}{quality mode}{log}{Logarithmic spacing; meaningful only for positive bounds.}
\LCPChoice{luacoolprop/diagram/PH}{quality mode}{list}{Use \texttt{quality values}.}
\LCPChoice{luacoolprop/diagram/PH}{quality mode}{explicit}{Synonym for \texttt{list}.}
\LCPChoice{luacoolprop/diagram/PH}{quality mode}{preset}{Use the selected preset.}
\LCPChoice{luacoolprop/diagram/PH}{quality mode}{predefined}{Synonym for \texttt{preset}.}
\LCPChoice{luacoolprop/diagram/PH}{quality mode}{auto}{Use a known preset, otherwise fall back to generated spacing.}
\end{description}
\LCPKeyUse{luacoolprop/diagram/PH}{quality mode}{linear}
\end{LCPKeyRef}
\begin{LCPKeyRef}{luacoolprop/diagram/PH}{quality preset}{name}{default}
Selects a named grid when \texttt{quality mode} is \texttt{preset},
\texttt{predefined}, or \texttt{auto}.
\begin{description}
\LCPChoice{luacoolprop/diagram/PH}{quality preset}{default}{Qualities from 0 to 1 in steps of 0.1.}
\LCPChoice{luacoolprop/diagram/PH}{quality preset}{dense}{The same eleven-curve grid as \texttt{default}.}
\LCPChoice{luacoolprop/diagram/PH}{quality preset}{sparse}{The five values 0, 0.25, 0.5, 0.75, and 1.}
\LCPChoice{luacoolprop/diagram/PH}{quality preset}{boundary}{Only saturated liquid and saturated vapour.}
\LCPChoice{luacoolprop/diagram/PH}{quality preset}{boundaries}{Synonym for \texttt{boundary}.}
\end{description}
\LCPCodeUse{quality mode=preset,quality preset=sparse}
\end{LCPKeyRef}
\LCPKeyAlias{luacoolprop/diagram/PH}{q min}{quality min}
\LCPKeyAlias{luacoolprop/diagram/PH}{q max}{quality max}
\LCPKeyAlias{luacoolprop/diagram/PH}{q step}{quality step}
\LCPKeyAlias{luacoolprop/diagram/PH}{q mode}{quality mode}
\LCPKeyAlias{luacoolprop/diagram/PH}{q count}{quality count}
\LCPKeyAlias{luacoolprop/diagram/PH}{q values}{quality values}
\LCPKeyAlias{luacoolprop/diagram/PH}{q preset}{quality preset}

\begin{LCPShowcase}[lefthand ratio=.48]{An explicit quality grid}
\LCPPHDiagram[
  quality values={0,0.25,0.5,0.75,1},
  labels=true,quality label every=2,
  axis options={width=5.2cm,height=4.1cm,
    font=\scriptsize}
]
\end{LCPShowcase}

\subsection{Temperature, entropy, and specific-volume grids}

All three grid families share the same pattern: \texttt{min}, \texttt{max},
\texttt{step}, \texttt{mode}, \texttt{count}, \texttt{preset}, and
\texttt{values}.  Explicit \texttt{values} take precedence.

\subsubsection{Temperature and isotherms}

\begin{LCPKeyRef}{luacoolprop/diagram/PH}{temperature unit}{unit}{celsius}
Interprets all temperature-grid values.  Use \texttt{celsius} (aliases
\texttt{c} and \texttt{degc}) or \texttt{kelvin} (alias \texttt{k}).
\LCPIndexValue{temperature unit}{celsius}
\LCPIndexValue{temperature unit}{kelvin}
\LCPIndexValue{temperature unit}{c}
\LCPIndexValue{temperature unit}{degc}
\LCPIndexValue{temperature unit}{k}
\LCPKeyUse{luacoolprop/diagram/PH}{temperature unit}{kelvin}
\end{LCPKeyRef}
\LCPKeyDoc{luacoolprop/diagram/PH}{temperature min}{number or auto}{auto}
  {Lower temperature for the generated grid.}{-40}
\LCPKeyDoc{luacoolprop/diagram/PH}{temperature max}{number or auto}{auto}
  {Upper temperature for the generated grid.}{80}
\LCPKeyDoc{luacoolprop/diagram/PH}{temperature step}{positive number}{10}
  {Linear-grid increment in the selected unit.}{20}
\LCPKeyDoc{luacoolprop/diagram/PH}{temperature count}{integer or auto}{auto}
  {Requests a fixed number of temperatures.}{7}
\LCPKeyDoc{luacoolprop/diagram/PH}{temperature values}{comma list}{empty}
  {Uses exactly the listed temperatures.}{{-40,-20,0,20,40,60}}
\begin{LCPKeyRef}{luacoolprop/diagram/PH}{temperature mode}{choice}{linear}
Selects \texttt{linear}, \texttt{log} (or \texttt{logarithmic}),
\texttt{list} (or \texttt{explicit}), \texttt{preset} (or
\texttt{predefined}), or \texttt{auto}.  Explicit values always force list
mode.  Presets are used only by \texttt{preset}, \texttt{predefined}, or
\texttt{auto}.
\LCPKeyUse{luacoolprop/diagram/PH}{temperature mode}{preset}
\foreach \LCPMode in {linear,log,logarithmic,list,explicit,preset,predefined,auto}{\LCPIndexValue{temperature mode}{\LCPMode}}
\end{LCPKeyRef}
\begin{LCPKeyRef}{luacoolprop/diagram/PH}{temperature preset}{name}{default}
Available names are \texttt{default}, \texttt{refrigeration},
\texttt{sparse}, and \texttt{dense}.  Refrigeration supplies Celsius values
from $-40$ to $120$ in $20$-degree steps; sparse uses $-40,0,40,80,120$;
dense uses $10$-degree steps.
\LCPCodeUse{temperature mode=preset,temperature preset=refrigeration}
\foreach \LCPPreset in {default,refrigeration,sparse,dense}{\LCPIndexValue{temperature preset}{\LCPPreset}}
\end{LCPKeyRef}
\LCPKeyAlias{luacoolprop/diagram/PH}{t min}{temperature min}
\LCPKeyAlias{luacoolprop/diagram/PH}{t max}{temperature max}
\LCPKeyAlias{luacoolprop/diagram/PH}{t step}{temperature step}
\LCPKeyAlias{luacoolprop/diagram/PH}{t mode}{temperature mode}
\LCPKeyAlias{luacoolprop/diagram/PH}{t count}{temperature count}
\LCPKeyAlias{luacoolprop/diagram/PH}{t preset}{temperature preset}
\LCPKeyAlias{luacoolprop/diagram/PH}{t values}{temperature values}

\subsubsection{Specific entropy and isentropes}

\begin{LCPKeyRef}{luacoolprop/diagram/PH}{entropy unit}{unit}{kjkgk}
Interprets entropy values.  Use \texttt{kjkgk} for
$\mathrm{kJ\,kg^{-1}\,K^{-1}}$, or \texttt{si}, \texttt{jkgk}, or
\texttt{j/kg/k} for $\mathrm{J\,kg^{-1}\,K^{-1}}$.
\LCPKeyUse{luacoolprop/diagram/PH}{entropy unit}{si}
\foreach \LCPUnit in {kjkgk,si,jkgk,j/kg/k}{\LCPIndexValue{entropy unit}{\LCPUnit}}
\end{LCPKeyRef}
\LCPKeyDoc{luacoolprop/diagram/PH}{entropy min}{number or auto}{auto}
  {Lower entropy for the generated grid.}{1.4}
\LCPKeyDoc{luacoolprop/diagram/PH}{entropy max}{number or auto}{auto}
  {Upper entropy for the generated grid.}{2.2}
\LCPKeyDoc{luacoolprop/diagram/PH}{entropy step}{positive number}{0.1}
  {Linear-grid entropy increment.}{0.2}
\LCPKeyDoc{luacoolprop/diagram/PH}{entropy count}{integer or auto}{auto}
  {Requests a fixed number of entropy values.}{6}
\LCPKeyDoc{luacoolprop/diagram/PH}{entropy values}{comma list}{empty}
  {Uses exactly the listed entropy values.}{{1.4,1.6,1.8,2.0,2.2}}
\begin{LCPKeyRef}{luacoolprop/diagram/PH}{entropy mode}{choice}{linear}
Supports \texttt{linear}, \texttt{log}/\texttt{logarithmic},
\texttt{list}/\texttt{explicit}, \texttt{preset}/\texttt{predefined}, and
\texttt{auto}, with the same precedence rules as the temperature grid.
\LCPKeyUse{luacoolprop/diagram/PH}{entropy mode}{linear}
\foreach \LCPMode in {linear,log,logarithmic,list,explicit,preset,predefined,auto}{\LCPIndexValue{entropy mode}{\LCPMode}}
\end{LCPKeyRef}
\begin{LCPKeyRef}{luacoolprop/diagram/PH}{entropy preset}{name}{default}
Available names are \texttt{default}, \texttt{refrigeration},
\texttt{sparse}, and \texttt{dense}; values are converted according to
\texttt{entropy unit}.
\LCPCodeUse{entropy mode=preset,entropy preset=dense}
\foreach \LCPPreset in {default,refrigeration,sparse,dense}{\LCPIndexValue{entropy preset}{\LCPPreset}}
\end{LCPKeyRef}
\LCPKeyAlias{luacoolprop/diagram/PH}{s min}{entropy min}
\LCPKeyAlias{luacoolprop/diagram/PH}{s max}{entropy max}
\LCPKeyAlias{luacoolprop/diagram/PH}{s step}{entropy step}
\LCPKeyAlias{luacoolprop/diagram/PH}{s mode}{entropy mode}
\LCPKeyAlias{luacoolprop/diagram/PH}{s count}{entropy count}
\LCPKeyAlias{luacoolprop/diagram/PH}{s preset}{entropy preset}
\LCPKeyAlias{luacoolprop/diagram/PH}{s values}{entropy values}

\subsubsection{Specific volume and isochores}

\begin{LCPKeyRef}{luacoolprop/diagram/PH}{specific volume unit}{unit}{m3kg}
Interprets volume values.  Use \texttt{m3kg} for $\mathrm{m^3\,kg^{-1}}$;
\texttt{lkg}, \texttt{l/kg}, \texttt{dm3kg}, and \texttt{dm3/kg} select litres
per kilogram.
\LCPKeyUse{luacoolprop/diagram/PH}{specific volume unit}{lkg}
\foreach \LCPUnit in {m3kg,lkg,l/kg,dm3kg,dm3/kg}{\LCPIndexValue{specific volume unit}{\LCPUnit}}
\end{LCPKeyRef}
\LCPKeyDoc{luacoolprop/diagram/PH}{specific volume min}{number or auto}{auto}
  {Lower specific volume for the generated grid.}{0.01}
\LCPKeyDoc{luacoolprop/diagram/PH}{specific volume max}{number or auto}{auto}
  {Upper specific volume for the generated grid.}{0.2}
\LCPKeyDoc{luacoolprop/diagram/PH}{specific volume step}{number or auto}{auto}
  {Increment for a linear grid.}{0.02}
\LCPKeyDoc{luacoolprop/diagram/PH}{specific volume count}{integer}{8}
  {Requests a fixed number of volume values.}{6}
\LCPKeyDoc{luacoolprop/diagram/PH}{specific volume values}{comma list}{empty}
  {Uses exactly the listed volumes.}{{0.01,0.02,0.05,0.1,0.2}}
\begin{LCPKeyRef}{luacoolprop/diagram/PH}{specific volume mode}{choice}{log}
Supports \texttt{linear}, \texttt{log}/\texttt{logarithmic},
\texttt{list}/\texttt{explicit}, \texttt{preset}/\texttt{predefined}, and
\texttt{auto}.  Logarithmic spacing is natural over wide volume ranges.
\LCPKeyUse{luacoolprop/diagram/PH}{specific volume mode}{log}
\foreach \LCPMode in {linear,log,logarithmic,list,explicit,preset,predefined,auto}{\LCPIndexValue{specific volume mode}{\LCPMode}}
\end{LCPKeyRef}
\begin{LCPKeyRef}{luacoolprop/diagram/PH}{specific volume preset}{name}{default}
Available names are \texttt{default}, \texttt{refrigeration},
\texttt{sparse}, and \texttt{dense}; values follow
\texttt{specific volume unit}.  Default and refrigeration use the same grid.
\LCPCodeUse{specific volume mode=preset,specific volume preset=sparse}
\foreach \LCPPreset in {default,refrigeration,sparse,dense}{\LCPIndexValue{specific volume preset}{\LCPPreset}}
\end{LCPKeyRef}
\LCPKeyAlias{luacoolprop/diagram/PH}{volume unit}{specific volume unit}
\LCPKeyAlias{luacoolprop/diagram/PH}{v unit}{specific volume unit}
\LCPKeyAlias{luacoolprop/diagram/PH}{v min}{specific volume min}
\LCPKeyAlias{luacoolprop/diagram/PH}{v max}{specific volume max}
\LCPKeyAlias{luacoolprop/diagram/PH}{v step}{specific volume step}
\LCPKeyAlias{luacoolprop/diagram/PH}{v mode}{specific volume mode}
\LCPKeyAlias{luacoolprop/diagram/PH}{v count}{specific volume count}
\LCPKeyAlias{luacoolprop/diagram/PH}{v preset}{specific volume preset}
\LCPKeyAlias{luacoolprop/diagram/PH}{v values}{specific volume values}

\begin{LCPShowcaseWide}{Combining all thermodynamic families}
\LCPPHDiagram[
  quality values={0,0.5,1},
  isotherm=true,temperature values={-20,20,60},
  isentrope=true,entropy values={1.6,1.9,2.2},
  isochore=true,specific volume values={0.01,0.03,0.1},
  axis options={width=10cm,height=6.4cm,font=\small}
]
\end{LCPShowcaseWide}

\subsection{Adaptive sampling and numerical output}

LuaCoolProp adaptively subdivides isolines.  The general controls apply to the
quality family; family-specific controls let expensive curves be tuned
independently.  Raise a tolerance or lower a maximum depth for faster drafts;
lower a tolerance only when the visual improvement justifies the extra
CoolProp calls.

Quality curves receive additional, automatic refinement close to the critical
pressure.  Saturated liquid ($Q=0$), saturated vapour ($Q=1$), and all
intermediate qualities are evaluated at a geometric sequence of subcritical
pressures.  Because the CoolProp $P,Q$ input pair is singular at the critical
state, LuaCoolProp then appends one canonical limiting point evaluated from the
fluid's $T_c$ and $\rho_c$.  Its metadata states
\texttt{critical\_limit=true} and \texttt{quality\_defined=false}; no quality
is assigned at the critical state.  Consequently every subcritical quality
curve approaches exactly the same plotted coordinate when the requested
pressure range reaches $p_c$.  This is a graphical limiting construction, not
a claim that every quality exists at the critical state.  These safeguards
require no sampling key.  The two saturation branches do
\emph{not} meet at the triple point: saturated liquid and saturated vapour are
distinct there and meet only at the critical point.

\LCPKeyDoc{luacoolprop/diagram/PH}{initial intervals}{positive integer}{18}
  {Initial subdivision count for quality curves.}{24}
\LCPKeyDoc{luacoolprop/diagram/PH}{max depth}{nonnegative integer}{8}
  {Maximum recursive subdivision depth for quality curves.}{10}
\LCPKeyDoc{luacoolprop/diagram/PH}{tolerance}{positive number}{0.25}
  {Geometric refinement tolerance for quality curves.}{0.15}
\LCPKeyDoc{luacoolprop/diagram/PH}{log weight}{nonnegative number}{30}
  {Weights pressure changes in logarithmic space during refinement.}{40}
\LCPKeyDoc{luacoolprop/diagram/PH}{coord digits}{positive integer}{6}
  {Decimal significant precision emitted to PGFPlots coordinates.}{8}
\LCPKeyDoc{luacoolprop/diagram/PH}{isotherm initial intervals}{positive integer}{14}
  {Initial subdivisions for each isotherm.}{18}
\LCPKeyDoc{luacoolprop/diagram/PH}{isotherm max depth}{nonnegative integer}{7}
  {Maximum adaptive depth for isotherms.}{9}
\LCPKeyDoc{luacoolprop/diagram/PH}{isotherm tolerance}{positive number}{0.35}
  {Adaptive tolerance for isotherms.}{0.2}
\LCPKeyDoc{luacoolprop/diagram/PH}{isentrope initial intervals}{positive integer}{14}
  {Initial subdivisions for each isentrope.}{18}
\LCPKeyDoc{luacoolprop/diagram/PH}{isentrope max depth}{nonnegative integer}{7}
  {Maximum adaptive depth for isentropes.}{9}
\LCPKeyDoc{luacoolprop/diagram/PH}{isentrope tolerance}{positive number}{0.30}
  {Adaptive tolerance for isentropes.}{0.2}
\LCPKeyDoc{luacoolprop/diagram/PH}{isochore initial intervals}{positive integer}{16}
  {Initial subdivisions for each isochore.}{20}
\LCPKeyDoc{luacoolprop/diagram/PH}{isochore max depth}{nonnegative integer}{8}
  {Maximum adaptive depth for isochores.}{10}
\LCPKeyDoc{luacoolprop/diagram/PH}{isochore tolerance}{positive number}{0.28}
  {Adaptive tolerance for isochores.}{0.18}
\LCPKeyDoc{luacoolprop/diagram/PH}{saturation pressure epsilon}{positive number}{0.00001}
  {Offsets evaluations from the exact saturation boundary to avoid ambiguous
   two-phase states.  Change this only when diagnosing a backend edge case.}
  {0.00002}

\subsection{Curve styles, colours, and legend participation}

Styles are ordinary TikZ/PGFPlots option lists.  A family colour is combined
with its family style; \texttt{curve style} is an additional common style.

\LCPKeyDoc{luacoolprop/diagram/PH}{curve style}{TikZ style}{empty}
  {Adds common drawing options to all emitted thermodynamic curves.}
  {{opacity=.8}}
\LCPKeyDoc{luacoolprop/diagram/PH}{quality color}{colour}{blue!60!black}
  {Sets interior quality-curve colour.}{cyan!60!black}
\LCPKeyDoc{luacoolprop/diagram/PH}{quality boundary color}{colour}{blue!80!black}
  {Sets the saturated-liquid and saturated-vapour boundary colour.}{navy}
\LCPKeyDoc{luacoolprop/diagram/PH}{isotherm color}{colour}{red!65!black}
  {Sets isotherm colour.}{magenta!70!black}
\LCPKeyDoc{luacoolprop/diagram/PH}{isentrope color}{colour}{green!50!black}
  {Sets isentrope colour.}{green!50!black}
\LCPKeyDoc{luacoolprop/diagram/PH}{isochore color}{colour}{orange!80!black}
  {Sets isochore colour.}{brown}
\LCPKeyDoc{luacoolprop/diagram/PH}{interior style}{TikZ style}{line width=0.25pt}
  {Styles interior quality curves.}{{line width=.4pt,densely dashed}}
\LCPKeyDoc{luacoolprop/diagram/PH}{boundary style}{TikZ style}{line width=0.9pt}
  {Styles the quality-envelope boundaries.}{{line width=1.2pt}}
\LCPKeyDoc{luacoolprop/diagram/PH}{isotherm style}{TikZ style}{line width=0.25pt}
  {Styles all isotherms.}{{line width=.35pt,dashed}}
\LCPKeyDoc{luacoolprop/diagram/PH}{isentrope style}{TikZ style}{dotted thin line}
  {Styles all isentropes.}{{line width=.35pt,densely dotted}}
\LCPKeyDoc{luacoolprop/diagram/PH}{isochore style}{TikZ style}{short dashed thin line}
  {Styles all isochores.}{{line width=.35pt,dash dot}}
\LCPKeyDoc{luacoolprop/diagram/PH}{legend}{boolean}{false}
  {Adds emitted curves to the PGFPlots legend when true.}{true}
\LCPKeyDoc{luacoolprop/diagram/PH}{forget plot}{boolean}{true}
  {Applies PGFPlots \texttt{forget plot}; set false when constructing a custom
   legend.}{false}
\LCPKeyAlias{luacoolprop/diagram/PH}{boundary color}{quality boundary color}

\begin{LCPShowcase}[lefthand ratio=.48]{A publication-oriented style}
\LCPPHDiagram[
  quality values={0,0.25,0.5,0.75,1},
  quality color=cyan!55!black,
  quality boundary color=blue!85!black,
  interior style={line width=.35pt,dashed},
  boundary style={line width=1pt},
  axis options={width=5.2cm,height=4.1cm,
    font=\scriptsize}
]
\end{LCPShowcase}

\subsection{Labels and family defaults}

Setting \texttt{labels=true} requests labels from LuaCoolProp.  Placement is
then delegated to the bundled \pkg{pgfplots-autonode} library. High-level
diagram commands enable its hooks locally. A manually created axis using
low-level family or process commands must include \texttt{auto node placement};
LuaCoolProp never appends that style to unrelated PGFPlots axes. The PH keys in
this subsection prepare label text, visibility, preferred positions, and node
styles; the autonomous library performs geometry and collision avoidance.

Symbols are arbitrary TeX math material and are independent of the physical
quantity passed to CoolProp.  Do not include dollar signs: LuaCoolProp supplies
the surrounding math mode.  Symbol settings affect the whole family, while
\texttt{label text for} remains the more specific override for one named curve.
They do not change stable curve identifiers: an isotherm still uses an
\texttt{lcp-ph-T-...} name after displaying \texttt{temperature
symbol=\string\theta}.

\LCPKeyDoc{luacoolprop/diagram/PH}{quality symbol}{TeX math material}{Q}
  {Sets the symbol preceding every generated quality value.}{x}
\LCPKeyDoc{luacoolprop/diagram/PH}{temperature symbol}{TeX math material}{T}
  {Sets the symbol preceding every generated isotherm value.}{{\theta}}
\LCPKeyDoc{luacoolprop/diagram/PH}{entropy symbol}{TeX math material}{s}
  {Sets the symbol preceding every generated isentrope value.}{{\sigma}}
\LCPKeyDoc{luacoolprop/diagram/PH}{specific volume symbol}{TeX math material}{v}
  {Sets the symbol preceding every generated isochore value.}{{\nu}}

\LCPKeyDoc{luacoolprop/diagram/PH}{labels}{boolean}{false}
  {Enables labels for eligible curve families.}{true}
\LCPKeyDoc{luacoolprop/diagram/PH}{label placement}{autonode}{autonode}
  {Selects autonomous placement.  \texttt{autonode} is the supported placement
   engine.}{autonode}
\LCPKeyDoc{luacoolprop/diagram/PH}{quality labels}{boolean or auto}{auto}
  {Overrides global label visibility for quality curves.}{true}
\LCPKeyDoc{luacoolprop/diagram/PH}{isotherm labels}{boolean or auto}{auto}
  {Overrides global label visibility for isotherms.}{true}
\LCPKeyDoc{luacoolprop/diagram/PH}{isentrope labels}{boolean or auto}{auto}
  {Overrides global label visibility for isentropes.}{false}
\LCPKeyDoc{luacoolprop/diagram/PH}{isochore labels}{boolean or auto}{auto}
  {Overrides global label visibility for isochores.}{true}
\LCPKeyDoc{luacoolprop/diagram/PH}{label pos}{fraction}{0.35}
  {Sets the common preferred curve position.}{0.5}
\LCPKeyDoc{luacoolprop/diagram/PH}{quality label pos}{fraction}{0.35}
  {Sets the quality-family preferred position.}{0.3}
\LCPKeyDoc{luacoolprop/diagram/PH}{isotherm label pos}{fraction}{0.20}
  {Sets the isotherm-family preferred position.}{0.25}
\LCPKeyDoc{luacoolprop/diagram/PH}{isentrope label pos}{fraction}{0.45}
  {Sets the isentrope-family preferred position.}{0.5}
\LCPKeyDoc{luacoolprop/diagram/PH}{isochore label pos}{fraction}{0.58}
  {Sets the isochore-family preferred position.}{0.6}
\LCPKeyDoc{luacoolprop/diagram/PH}{label every}{positive integer}{2}
  {Labels one curve out of every $n$ by default.}{3}
\LCPKeyDoc{luacoolprop/diagram/PH}{quality label every}{positive integer}{2}
  {Sets the quality-family label stride.}{1}
\LCPKeyDoc{luacoolprop/diagram/PH}{isotherm label every}{positive integer}{2}
  {Sets the isotherm-family label stride.}{3}
\LCPKeyDoc{luacoolprop/diagram/PH}{isentrope label every}{positive integer}{2}
  {Sets the isentrope-family label stride.}{2}
\LCPKeyDoc{luacoolprop/diagram/PH}{isochore label every}{positive integer}{2}
  {Sets the isochore-family label stride.}{2}
\LCPKeyDoc{luacoolprop/diagram/PH}{label sloped}{boolean}{false}
  {Sets the common label-rotation policy.}{true}
\LCPKeyDoc{luacoolprop/diagram/PH}{quality label sloped}{boolean or auto}{auto}
  {Overrides rotation for quality labels.}{false}
\LCPKeyDoc{luacoolprop/diagram/PH}{isotherm label sloped}{boolean or auto}{auto}
  {Overrides rotation for isotherm labels.}{true}
\LCPKeyDoc{luacoolprop/diagram/PH}{isentrope label sloped}{boolean or auto}{auto}
  {Overrides rotation for isentrope labels.}{true}
\LCPKeyDoc{luacoolprop/diagram/PH}{isochore label sloped}{boolean or auto}{auto}
  {Overrides rotation for isochore labels.}{true}
\LCPKeyDoc{luacoolprop/diagram/PH}{label allow upside down}{boolean}{false}
  {Sets the common PGFPlots orientation policy.}{true}
\LCPKeyDoc{luacoolprop/diagram/PH}{quality label allow upside down}{boolean or auto}{auto}
  {Overrides upside-down orientation for quality labels.}{false}
\LCPKeyDoc{luacoolprop/diagram/PH}{isotherm label allow upside down}{boolean or auto}{auto}
  {Overrides upside-down orientation for isotherm labels.}{false}
\LCPKeyDoc{luacoolprop/diagram/PH}{isentrope label allow upside down}{boolean or auto}{auto}
  {Overrides upside-down orientation for isentrope labels.}{true}
\LCPKeyDoc{luacoolprop/diagram/PH}{isochore label allow upside down}{boolean or auto}{auto}
  {Overrides upside-down orientation for isochore labels.}{false}
\LCPKeyDoc{luacoolprop/diagram/PH}{label style}{TikZ style name}{luacoolprop label node}
  {Sets the common label-node style name.}{luacoolprop label node}
\LCPKeyDoc{luacoolprop/diagram/PH}{quality label style}{TikZ style name}{luacoolprop quality label node}
  {Sets the quality-label style name.}{luacoolprop quality label node}
\LCPKeyDoc{luacoolprop/diagram/PH}{isotherm label style}{TikZ style name}{luacoolprop isotherm label node}
  {Sets the isotherm-label style name.}{luacoolprop isotherm label node}
\LCPKeyDoc{luacoolprop/diagram/PH}{isentrope label style}{TikZ style name}{luacoolprop isentrope label node}
  {Sets the isentrope-label style name.}{luacoolprop isentrope label node}
\LCPKeyDoc{luacoolprop/diagram/PH}{isochore label style}{TikZ style name}{luacoolprop isochore label node}
  {Sets the isochore-label style name.}{luacoolprop isochore label node}

The five \texttt{... label node style} keys redefine the corresponding TikZ
style directly.  They accept a complete node-option list.

\LCPKeyDoc{luacoolprop/diagram/PH}{label node style}{TikZ node options}{package style}
  {Redefines \texttt{luacoolprop label node}.}{{fill=yellow!15,inner sep=2pt}}
\LCPKeyDoc{luacoolprop/diagram/PH}{quality label node style}{TikZ node options}{inherits common style}
  {Redefines the quality label node.}{{fill=blue!8,text=blue!70!black}}
\LCPKeyDoc{luacoolprop/diagram/PH}{isotherm label node style}{TikZ node options}{inherits common style}
  {Redefines the isotherm label node.}{{fill=red!8,text=red!70!black}}
\LCPKeyDoc{luacoolprop/diagram/PH}{isentrope label node style}{TikZ node options}{inherits common style}
  {Redefines the isentrope label node.}{{fill=green!8,text=green!40!black}}
\LCPKeyDoc{luacoolprop/diagram/PH}{isochore label node style}{TikZ node options}{inherits common style}
  {Redefines the isochore label node.}{{fill=orange!8,text=orange!70!black}}

\LCPKeyAlias{luacoolprop/diagram/PH}{sloped labels}{label sloped}
\LCPKeyAlias{luacoolprop/diagram/PH}{smart labels}{label placement=autonode}
\LCPKeyAlias{luacoolprop/diagram/PH}{automatic labels}{label placement=autonode}
\LCPKeyAlias{luacoolprop/diagram/PH}{autonode labels}{label placement=autonode}
\LCPKeyAlias{luacoolprop/diagram/PH}{pgfplots autonode labels}{label placement=autonode}

\begin{LCPShowcase}[lefthand ratio=.48]{Family label controls}
\LCPPHDiagram[
  quality values={0,0.25,0.5,0.75,1},
  labels=true,quality label every=1,
  quality label pos=.45,
  quality label node style={fill=blue!8,
    inner sep=1.5pt,font=\scriptsize},
  axis options={width=5.2cm,height=4.1cm,
    font=\scriptsize}
]
\end{LCPShowcase}

\begin{LCPShowcase}[lefthand ratio=.48]{Alternative thermodynamic notation}
\LCPPHDiagram[
  quality values={0,0.5,1},quality symbol=x,
  isotherm=true,temperature values={-20,20,60},
  temperature symbol={\theta},labels=true,
  label every=1,
  axis options={width=5.2cm,height=4.1cm,
    font=\scriptsize}
]
\end{LCPShowcase}

\subsection{Per-curve overrides}

Each override takes two braced arguments inside the key list: a curve selector
and its value.  Selectors are the stable curve names emitted by LuaCoolProp,
for example \texttt{lcp-ph-q-0p5}, \texttt{lcp-ph-T-20C}, or a process
\texttt{name}.  Repeating a key is allowed and builds a list of overrides.

\LCPKeyDoc{luacoolprop/diagram/PH}{label pos for}{selector and fraction}{none}
  {Overrides one label's preferred position.}{{lcp-ph-q-0p5}{0.62}}
\LCPKeyDoc{luacoolprop/diagram/PH}{label style for}{selector and style}{none}
  {Overrides one label's TikZ style name or options.}{{lcp-ph-q-0p5}{fill=yellow}}
\LCPKeyDoc{luacoolprop/diagram/PH}{label text for}{selector and TeX text}{none}
  {Replaces one automatically generated label.}{{lcp-ph-q-0p5}{$q=50\%$}}
\LCPKeyDoc{luacoolprop/diagram/PH}{label show for}{selector and boolean}{none}
  {Forces one label to be shown or hidden.}{{lcp-ph-q-0p5}{false}}
\LCPKeyDoc{luacoolprop/diagram/PH}{label fixed for}{selector and boolean}{none}
  {Marks one label position as fixed rather than preferred.}{{lcp-ph-q-0p5}{true}}
\LCPKeyDoc{luacoolprop/diagram/PH}{label sloped for}{selector and boolean}{none}
  {Overrides rotation for one label.}{{lcp-ph-q-0p5}{true}}
\LCPKeyDoc{luacoolprop/diagram/PH}{label allow upside down for}{selector and boolean}{none}
  {Overrides the orientation policy for one label.}{{lcp-ph-q-0p5}{false}}
\LCPKeyDoc{luacoolprop/diagram/PH}{curve style for}{selector and TikZ style}{none}
  {Overrides the drawing style for one curve.}{{lcp-ph-q-0p5}{purple,line width=1pt}}

\begin{LCPShowcase}[lefthand ratio=.48]{Highlight one named curve}
\LCPPHDiagram[
  quality values={0,0.25,0.5,0.75,1},labels=true,
  label text for={lcp-ph-q-0p5}{$q=50\%$},
  label pos for={lcp-ph-q-0p5}{0.55},
  curve style for={lcp-ph-q-0p5}{purple,
    line width=1pt},
  axis options={width=5.2cm,height=4.1cm,
    font=\scriptsize}
]
\end{LCPShowcase}

\subsection{Autonode options forwarded by PH diagrams}

These keys configure the candidate set attached to labels emitted by
LuaCoolProp.  The next chapter documents the autonomous library itself and its
axis-wide solver controls.

\LCPKeyDoc{luacoolprop/diagram/PH}{autonode candidates}{positive integer}{51}
  {Sets the number of sampled positions for each PH label.}{31}
\LCPKeyDoc{luacoolprop/diagram/PH}{autonode candidate strategy}{strategy}{around-preferred}
  {Uses \texttt{uniform}, \texttt{around-preferred}, or \texttt{adaptive}
   candidate ordering.}{adaptive}
\LCPIndexValue{autonode candidate strategy}{uniform}
\LCPIndexValue{autonode candidate strategy}{around-preferred}
\LCPKeyDoc{luacoolprop/diagram/PH}{autonode clearance}{TeX dimension}{1pt}
  {Adds collision clearance around PH labels.}{2pt}
\LCPKeyDoc{luacoolprop/diagram/PH}{autonode inner sep}{TeX dimension}{1.5pt}
  {Sets the label node's inner separation for both rendering and measurement;
   a later inner sep in the node style takes precedence.}{2pt}
\LCPKeyDoc{luacoolprop/diagram/PH}{autonode normal shift}{TeX dimension}{0pt}
  {Offsets PH labels along the local curve normal.}{4pt}
\LCPKeyDoc{luacoolprop/diagram/PH}{autonode preferred weight}{number}{8}
  {Weights distance from the preferred position.}{12}
\LCPKeyDoc{luacoolprop/diagram/PH}{autonode overlap weight}{number}{1000}
  {Weights label overlap relative to preferred-position distance.}{2000}
\LCPKeyDoc{luacoolprop/diagram/PH}{label min pos}{fraction}{0}
  {Sets the earliest candidate position along each PH curve.}{0.12}
\LCPKeyDoc{luacoolprop/diagram/PH}{label max pos}{fraction}{1}
  {Sets the latest candidate position along each PH curve.}{0.88}

\subsection{Alternate label-control keys}

The following accepted names do \emph{not} configure the autonomous solver.
The effective controls live under \texttt{/pgfplots} or
\texttt{/pgfplots/autonode} and are documented in the next chapter.

\LCPKeyDoc{luacoolprop/diagram/PH}{label collision policy}{value}{keep}
  {Accepted without solver effect; use \texttt{auto node failure mode}.}{keep}
\LCPKeyAlias{luacoolprop/diagram/PH}{label collision}{label collision policy}
\LCPKeyDoc{luacoolprop/diagram/PH}{label hide overlap threshold}{number}{0.06}
  {Accepted without solver effect; use the autonode failure policy.}{0.08}
\LCPKeyDoc{luacoolprop/diagram/PH}{label hide edge threshold}{number}{0.025}
  {Accepted without solver effect; use \texttt{auto node border margin}.}{0.03}
\LCPKeyDoc{luacoolprop/diagram/PH}{label candidate count}{integer}{21}
  {Accepted without solver effect; use \texttt{autonode candidates}.}{31}
\LCPKeyDoc{luacoolprop/diagram/PH}{label separation}{number}{0.018}
  {Accepted without solver effect; use \texttt{autonode clearance}.}{0.02}
\LCPKeyDoc{luacoolprop/diagram/PH}{label overlap penalty}{number}{1000}
  {Accepted without solver effect; use \texttt{autonode overlap weight}.}{1500}
\LCPKeyDoc{luacoolprop/diagram/PH}{label distance penalty}{number}{1}
  {Accepted without solver effect; use \texttt{autonode preferred weight}.}{2}
\LCPKeyDoc{luacoolprop/diagram/PH}{label edge penalty}{number}{5}
  {Accepted without solver effect; use \texttt{auto node border margin}.}{8}
\LCPKeyDoc{luacoolprop/diagram/PH}{label box base width}{number}{0.045}
  {Accepted without solver effect; autonode measures the real TeX node.}{0.05}
\LCPKeyDoc{luacoolprop/diagram/PH}{label box char width}{number}{0.0060}
  {Accepted without solver effect; autonode measures the real TeX node.}{0.007}
\LCPKeyDoc{luacoolprop/diagram/PH}{label box height}{number}{0.060}
  {Accepted without solver effect; autonode measures the real TeX node.}{0.07}
\LCPKeyDoc{luacoolprop/diagram/PH}{label box sloped multiplier}{number}{1.35}
  {Accepted without solver effect; use \texttt{auto node bbox mode=oriented}.}{1.4}

\section{Shared process paths and the PH projection}

A process is drawn inside an existing PH axis.  Its key namespace is
\texttt{/luacoolprop/process/PH}.  State specifications in \texttt{from} and
\texttt{to} are braced key lists interpreted by the thermodynamic layer.

\begin{LCPShowcaseWide}{A labelled isobaric process over the quality dome}
\begin{tikzpicture}
\begin{axis}[width=10cm,height=6cm,ymode=log,auto node placement,
  xlabel={$h/\mathrm{kJ\,kg^{-1}}$},ylabel={$p/\mathrm{bar}$},
  grid=both]
  \LCPAddPHQuality[quality values={0,0.5,1}]
  \LCPAddPHProcess[type=isobar,pressure=8bar,
    from={quality=0},to={quality=1},
    color=purple,label={evaporation},mark endpoints=true]
\end{axis}
\end{tikzpicture}
\end{LCPShowcaseWide}

\subsection{Thermodynamic definition}

\LCPKeyDoc{luacoolprop/process/PH}{fluid}{CoolProp identifier}{global fluid}
  {Selects the process fluid.}{R134a}
\LCPKeyDoc{luacoolprop/process/PH}{library}{file path}{global library}
  {Overrides the external library path for this process.}{/opt/coolprop/libCoolProp.dylib}
\begin{LCPKeyRef}{luacoolprop/process/PH}{type}{process kind}{isobar}
Selects the property held constant along the path.
\begin{description}
\LCPChoice{luacoolprop/process/PH}{type}{isobar}{Constant pressure.}
\LCPChoice{luacoolprop/process/PH}{type}{isotherm}{Constant temperature.}
\LCPChoice{luacoolprop/process/PH}{type}{isenthalp}{Constant specific enthalpy.}
\LCPChoice{luacoolprop/process/PH}{type}{isentrope}{Constant specific entropy.}
\LCPChoice{luacoolprop/process/PH}{type}{isochore}{Constant specific volume.}
\LCPChoice{luacoolprop/process/PH}{type}{quality}{Constant vapour quality.}
\end{description}
\LCPKeyUse{luacoolprop/process/PH}{type}{isentrope}
The descriptive aliases \texttt{isobaric}, \texttt{pressure},
\texttt{isothermal}, \texttt{temperature}, \texttt{isentropic},
\texttt{entropy}, \texttt{isenthalpic}, \texttt{enthalpy},
\texttt{throttle}, \texttt{isoquality}, \texttt{isochoric}, and
\texttt{volume}, as well as the one-letter forms \texttt{p}, \texttt{t},
\texttt{s}, \texttt{h}, \texttt{q}, and \texttt{v}, are accepted as aliases.
The canonical vocabulary is shown in the list above.
\foreach \LCPKind in {isobaric,pressure,isothermal,temperature,isentropic,
  entropy,isenthalpic,enthalpy,throttle,isoquality,isochoric,volume,p,t,s,h,q,v}{%
  \LCPIndexValue{type}{\LCPKind}}
\end{LCPKeyRef}
\LCPKeyDoc{luacoolprop/process/PH}{from}{state key list}{empty}
  {Defines the initial state on the process constraint.}{{quality=0}}
\LCPKeyDoc{luacoolprop/process/PH}{to}{state key list}{empty}
  {Defines the final state on the process constraint.}{{quality=1}}
\LCPKeyDoc{luacoolprop/process/PH}{value}{quantity}{empty}
  {Supplies the conserved property when its named key is not used.  Unit
   parsing follows the selected process type.}{8bar}
\LCPKeyDoc{luacoolprop/process/PH}{pressure}{pressure}{empty}
  {Sets an isobar.  A bare number is in pascals; accepted suffixes are
   \texttt{Pa}, \texttt{kPa}, \texttt{MPa}, \texttt{bar}, and \texttt{mbar}.}
  {8bar}
\LCPKeyDoc{luacoolprop/process/PH}{temperature}{temperature}{empty}
  {Sets an isotherm.  A bare number is in kelvin; suffix \texttt{C},
   \texttt{degC}, or \texttt{celsius} selects degrees Celsius.}{20C}
\LCPKeyDoc{luacoolprop/process/PH}{enthalpy}{specific enthalpy}{empty}
  {Sets an isenthalpic path.  A bare number is in \texttt{J/kg};
   \texttt{kJkg} selects \texttt{kJ/kg}.}{250kJkg}
\LCPKeyDoc{luacoolprop/process/PH}{entropy}{specific entropy}{empty}
  {Sets an isentrope.  A bare number is in \texttt{J/(kg K)};
   \texttt{kJkgK} selects \texttt{kJ/(kg K)}.}{1.8kJkgK}
\LCPKeyDoc{luacoolprop/process/PH}{quality}{number}{empty}
  {Sets constant vapour quality for a quality path.}{0.5}
\LCPKeyDoc{luacoolprop/process/PH}{specific volume}{specific volume}{empty}
  {Sets an isochore in cubic metres per kilogram.}{0.05}

The nested \texttt{from} and \texttt{to} lists accept the state properties
below.  A state normally needs two independent properties; the conserved
process property may supply one of them.  A colon may replace the equals sign,
and a semicolon may replace a comma.

\noindent\begin{tabularx}{\linewidth}{@{}>{\ttfamily}l >{\ttfamily}l X@{}}
\toprule
State key & Example & Meaning \\
\midrule
p, pressure & p=8bar & Pressure; the suffix rules are the same as above.\\
T, temperature & T=20C & Temperature in kelvin unless a Celsius suffix is present.\\
h, enthalpy & h=250kJkg & Specific enthalpy.\\
s, entropy & s=1.8kJkgK & Specific entropy.\\
q, Q, quality, x & quality=0.5 & Vapour quality from 0 to 1.\\
v, volume, specific volume & v=0.05m3/kg & Specific volume; bare values use $\mathrm{m^3\,kg^{-1}}$, and \texttt{L/kg} or \texttt{dm3/kg} is also accepted.\\
rho, density, rhomass & rho=25kg/m3 & Mass density; bare values use $\mathrm{kg\,m^{-3}}$ and are converted to specific volume.\\
\bottomrule
\end{tabularx}

For example, \texttt{from=\{p=8bar,quality=0\}} is fully specified by itself,
whereas \texttt{from=\{quality=0\}} becomes complete when the surrounding
isobar also supplies \texttt{pressure=8bar}.  LuaCoolProp reports incomplete,
non-physical, and out-of-range states with suggestions rather than silently
drawing a misleading process.

When more than two properties are supplied, LuaCoolProp freezes the first
independent pair in the order documented by the Lua API, asks CoolProp for the
complete canonical state, and verifies every additional explicit property.
It also verifies the conserved property against both completed process
endpoints.  A contradiction is a hard error whose diagnostic gives the
supplied value, the CoolProp value, their absolute difference, and the applied
tolerance.  Comparisons use the larger of an absolute floor and a relative
tolerance of $5\mathord\times10^{-7}$.  The absolute floors in SI units are
$0.1$ for pressure, $10^{-5}$ for temperature, $10^{-3}$ for enthalpy,
$10^{-5}$ for entropy, $10^{-9}$ for quality, $10^{-12}$ for specific volume,
and $10^{-8}$ for density.  These tolerances absorb flash-solver roundoff but
do not conceal scientifically distinct states.

\LCPKeyAlias{luacoolprop/process/PH}{kind}{type}
\LCPKeyAlias{luacoolprop/process/PH}{process}{type}
\LCPKeyAlias{luacoolprop/process/PH}{start}{from}
\LCPKeyAlias{luacoolprop/process/PH}{stop}{to}
\LCPKeyAlias{luacoolprop/process/PH}{p}{pressure}
\LCPKeyAlias{luacoolprop/process/PH}{T}{temperature}
\LCPKeyAlias{luacoolprop/process/PH}{t}{temperature}
\LCPKeyAlias{luacoolprop/process/PH}{h}{enthalpy}
\LCPKeyAlias{luacoolprop/process/PH}{s}{entropy}
\LCPKeyAlias{luacoolprop/process/PH}{q}{quality}
\LCPKeyAlias{luacoolprop/process/PH}{Q}{quality}
\LCPKeyAlias{luacoolprop/process/PH}{v}{specific volume}

\subsection{Identity, appearance, and labels}

\LCPKeyDoc{luacoolprop/process/PH}{name}{identifier}{empty}
  {Assigns the stable TikZ \texttt{name path} selector used by labels,
   intersections, and higher-level documents.}{evaporation}
\LCPKeyDoc{luacoolprop/process/PH}{color}{colour}{black}
  {Sets the process-curve colour.}{purple}
\LCPKeyDoc{luacoolprop/process/PH}{style}{TikZ style}{line width=1pt}
  {Sets process drawing options.}{{line width=1.4pt,-{Stealth}}}
Arrow-tip styles such as \texttt{-\{Stealth\}} require the document to load
TikZ's \texttt{arrows.meta} library explicitly. LuaCoolProp loads only the
\texttt{intersections} library required by its stable named-path contract.
\LCPKeyDoc{luacoolprop/process/PH}{label}{TeX text}{empty}
  {Adds a label managed by autonode.}{{$1\to2$}}
\LCPKeyDoc{luacoolprop/process/PH}{label pos}{fraction}{0.5}
  {Sets the preferred label position along the process.}{0.6}
\LCPKeyDoc{luacoolprop/process/PH}{label style}{TikZ style name}{luacoolprop process label node}
  {Selects the process-label node style.}{luacoolprop process label node}
\LCPKeyDoc{luacoolprop/process/PH}{label node style}{TikZ node options}{package style}
  {Redefines \texttt{luacoolprop process label node}.}{{fill=purple!8,text=purple}}
\LCPKeyDoc{luacoolprop/process/PH}{label sloped}{boolean}{true}
  {Rotates the process label with the local tangent.}{false}
\LCPKeyDoc{luacoolprop/process/PH}{label allow upside down}{boolean}{false}
  {Allows the label to retain an upside-down tangent orientation.}{true}
\LCPKeyDoc{luacoolprop/process/PH}{mark endpoints}{boolean}{false}
  {Draws markers at the start and end states.}{true}
\LCPKeyDoc{luacoolprop/process/PH}{marker style}{TikZ plot style}{only marks, mark=*}
  {Styles endpoint markers.}{{only marks,mark=square*,mark size=1.5pt}}
\LCPKeyAlias{luacoolprop/process/PH}{id}{name}
\LCPKeyAlias{luacoolprop/process/PH}{process color}{color}
\LCPKeyAlias{luacoolprop/process/PH}{process style}{style}
\LCPKeyAlias{luacoolprop/process/PH}{label text}{label}
\LCPKeyAlias{luacoolprop/process/PH}{sloped label}{label sloped}
\LCPKeyAlias{luacoolprop/process/PH}{markers}{mark endpoints}

\subsection{Named intersections and numeric endpoint access}

\LCPKeyDoc{luacoolprop/process/PH}{export coordinates}{control-sequence prefix}{empty}
  {Globally defines four displayed-coordinate macros and all thermodynamic
   endpoint macros that CoolProp can resolve.  The coordinate macros are
   \texttt{\textbackslash\meta{prefix}FromX},
   \texttt{\textbackslash\meta{prefix}FromY},
   \texttt{\textbackslash\meta{prefix}ToX}, and
   \texttt{\textbackslash\meta{prefix}ToY}.  Give the prefix without a
   leading backslash.  Values use the displayed coordinate scales and the
   precision selected by \texttt{coord digits}.}{CycleAB}
\LCPKeyDoc{luacoolprop/process/PH}{log coordinates}{boolean}{false}
  {Writes the process name and its two displayed coordinate pairs to both the
   terminal and the TeX log.}{true}

The exported definitions are global because a process can be evaluated inside
a PGFPlots group while its numerical results are needed later in the document.
A previously exported numeric macro may be used directly inside a later
\key{from} or \key{to} specification.  LuaCoolProp expands state data before
passing it to Lua, so constructs such as
\texttt{to=\{pressure=\string\PreviousToPressureSI\space Pa\}} form a genuine
calculation chain.  TeX-rich process labels and styles follow their separate,
protected serialization path and are not expanded as numerical state data.
A prefix must begin with a letter, \texttt{@}, colon, or underscore; subsequent
characters may also be digits.  For example,
\texttt{export coordinates=CycleAB} defines \macro{\CycleABFromX},
\macro{\CycleABFromY}, \macro{\CycleABToX}, and \macro{\CycleABToY}.  The
values are plain decimal text, without units, and reproduce exactly the rounded
coordinates sent to PGFPlots.  Thus the meaning of X and Y follows the diagram
type; for a PH diagram with the default scales they are respectively
$\mathrm{kJ\,kg^{-1}}$ and bar.

For each endpoint, the bridge also defines every available macro in the table
below.  Replace \meta{side} with \texttt{From} or \texttt{To}.  A property that
CoolProp cannot resolve for that state is intentionally left undefined.

\noindent\begin{tabularx}{\linewidth}{@{}>{\ttfamily}l l X@{}}
\toprule
Suffix after prefix and side & Unit & Meaning \\
\midrule
PressureSI & Pa & Absolute pressure.\\
TemperatureK & K & Absolute temperature.\\
EnthalpySI & $\mathrm{J\,kg^{-1}}$ & Mass-specific enthalpy.\\
EntropySI & $\mathrm{J\,kg^{-1}\,K^{-1}}$ & Mass-specific entropy.\\
SpecificVolumeSI & $\mathrm{m^3\,kg^{-1}}$ & Mass-specific volume.\\
Quality & 1 & Vapour quality, defined only in the two-phase region or on its boundary.\\
\bottomrule
\end{tabularx}

For example, \texttt{\textbackslash CycleABTo\allowbreak TemperatureK} is the
final absolute temperature, while
\texttt{\textbackslash CycleABTo\allowbreak EnthalpySI} retains the SI value
independently of the horizontal plot scale.  These property exports use the
same decimal precision setting as the coordinate exports.

\begin{LCPExample}{Intersecting named processes and reusing their numbers}
\usetikzlibrary{intersections}
\begin{tikzpicture}
\begin{axis}[ymode=log,auto node placement]
  \LCPAddPHProcess[
    fluid=R717,
    type=isentrope,
    from={pressure=3bar,quality=1},to={pressure=10bar},
    name=cycle-ab,export coordinates=CycleAB,
    log coordinates=true]
  \LCPAddPHProcess[
    fluid=R717,type=isobar,pressure=10bar,
    from={entropy=6.2276889kJkgK},to={quality=1},
    name=cycle-bc]
  \path[name intersections={of=cycle-ab and cycle-bc,by=CycleB}];
  \fill (CycleB) circle[radius=1.5pt];
  \node[above] at (CycleB)
    {$h_B=\pgfmathprintnumber{\CycleABToX}$};
\end{axis}
\end{tikzpicture}
\end{LCPExample}

The geometry above comes from TikZ's \texttt{intersections} library; no state
coordinate is repeated manually.  Independently, a document can write the
same numeric endpoint to its own log with
\texttt{\string\typeout\{B=(\string\CycleABToX,\string\CycleABToY)\}} or use
the macros in calculations, tables, and annotations.

\subsection{Process scaling and sampling}

\LCPKeyDoc{luacoolprop/process/PH}{enthalpy scale}{number}{global scale}
  {Multiplies process enthalpies before plotting.}{0.001}
\LCPKeyDoc{luacoolprop/process/PH}{pressure scale}{number}{global scale}
  {Multiplies process pressures before plotting.}{0.00001}
\LCPKeyDoc{luacoolprop/process/PH}{initial intervals}{positive integer}{12}
  {Sets initial process-path subdivisions.}{18}
\LCPKeyDoc{luacoolprop/process/PH}{max depth}{nonnegative integer}{7}
  {Sets maximum adaptive process depth.}{9}
\LCPKeyDoc{luacoolprop/process/PH}{tolerance}{positive number}{0.25}
  {Sets geometric process refinement tolerance.}{0.15}
\LCPKeyDoc{luacoolprop/process/PH}{log weight}{nonnegative number}{30}
  {Weights logarithmic pressure differences during refinement.}{40}
\LCPKeyDoc{luacoolprop/process/PH}{coord digits}{positive integer}{6}
  {Sets decimal precision emitted for process coordinates.}{8}
\LCPKeyAlias{luacoolprop/process/PH}{h scale}{enthalpy scale}
\LCPKeyAlias{luacoolprop/process/PH}{p scale}{pressure scale}

\section{PV pressure--specific-volume diagrams}

A PV diagram plots absolute pressure $p$ as a function of mass-specific volume
$v=1/\rho$.  With the default scales its coordinates are $v$ in
$\mathrm{m^3\,kg^{-1}}$ and $p$ in bar.  Both axes are logarithmic by default:
the liquid region, two-phase dome, vapour region, and several pressure decades
therefore remain legible in one plot.  Every emitted point also retains its raw
SI pressure, specific volume, and density in the Lua record.

PV is a first-class registered diagram type, not a graphical transformation of
PH.  CoolProp evaluates density directly for each thermodynamic pair.  Adaptive
sampling measures curvature in $(\log v,\log p)$ display coordinates; this is
especially important close to the saturated-liquid boundary and the critical
point.

\begin{LCPNote}[Supported PV background families]
The public PV background families are \texttt{quality}, \texttt{isotherm}, and
\texttt{isentrope}.  An isochore would be only a vertical line in these
coordinates, so it is not a PV background family.  Isochores remain available
as PH families and as PV process paths.  PV processes additionally support
isobars, isenthalps, and the other process types documented below.
\end{LCPNote}

\subsection{PV convenience commands}

\begin{LCPCommandRef}{LCPPVDiagram}{\oarg{options}}
Creates a complete PV picture and a log--log PGFPlots axis.  Quality curves are
enabled by default; isotherms and isentropes are opt-in.
\begin{LCPShowcase}[lefthand ratio=.47]{A complete labelled PV diagram}
\LCPPVDiagram[
  fluid=R134a,
  isotherm=true,
  isentrope=true,
  quality values={0,0.5,1},
  temperature values={0,20,40},
  entropy values={1.7,1.9},
  labels=true,
  axis options={width=5.6cm,
    height=4.4cm,font=\scriptsize}
]
\end{LCPShowcase}
It is exactly equivalent to
\texttt{\string\LCPDiagram\{PV\}\oarg{options}}.
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddPVPlots}{\oarg{options}}
Adds every enabled PV family to an existing axis.  The caller must select
positive logarithmic coordinates when reproducing the standard appearance.
\begin{LCPShowcase}[lefthand ratio=.48]{All selected families in a manual axis}
\begin{tikzpicture}
\begin{loglogaxis}[width=5.5cm,auto node placement,
  height=4.2cm,font=\scriptsize]
  \LCPAddPVPlots[
    quality values={0,0.5,1},
    isotherm=true,
    temperature values={0,30,60}]
\end{loglogaxis}
\end{tikzpicture}
\end{LCPShowcase}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddPVQuality}{\oarg{options}}
Adds only the saturation boundaries and selected interior qualities.  Every
subcritical quality curve approaches the same quality-independent critical
limit; quality is undefined at the critical state itself.
\begin{LCPShowcase}[lefthand ratio=.48]{PV quality curves}
\begin{tikzpicture}
\begin{loglogaxis}[width=5.5cm,auto node placement,
  height=4.2cm,font=\scriptsize]
  \LCPAddPVQuality[
    quality step=0.2,
    quality symbol=x,
    labels=true]
\end{loglogaxis}
\end{tikzpicture}
\end{LCPShowcase}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddPVIsotherms}{\oarg{options}}
Adds only isotherms.  A subcritical isotherm contains its superheated-vapour
branch, the exact horizontal segment between saturated vapour and saturated
liquid, and its compressed-liquid branch.
\begin{LCPShowcase}[lefthand ratio=.48]{PV isotherms and their plateaux}
\begin{tikzpicture}
\begin{loglogaxis}[width=5.5cm,auto node placement,
  height=4.2cm,font=\scriptsize]
  \LCPAddPVIsotherms[
    temperature values={-20,0,20,40,80},
    temperature symbol={\theta},
    labels=true]
\end{loglogaxis}
\end{tikzpicture}
\end{LCPShowcase}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddPVIsentropes}{\oarg{options}}
Adds only constant-specific-entropy curves.  Entropy inputs follow
\texttt{entropy unit}; the default is $\mathrm{kJ\,kg^{-1}\,K^{-1}}$.
\begin{LCPShowcase}[lefthand ratio=.48]{PV isentropes}
\begin{tikzpicture}
\begin{loglogaxis}[width=5.5cm,auto node placement,
  height=4.2cm,font=\scriptsize]
  \LCPAddPVIsentropes[
    entropy values={1.5,1.7,1.9,2.1},
    entropy symbol={s_v},
    labels=true]
\end{loglogaxis}
\end{tikzpicture}
\end{LCPShowcase}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddPVProcess}{\oarg{options}}
Adds one process in PV coordinates.  State specifications, conserved-property
inference, named paths, endpoint exports, styles, and diagnostics are identical
to \macro{\LCPAddPHProcess}; X exports are specific volumes instead of
enthalpies.
\begin{LCPShowcase}[lefthand ratio=.49]{A named PV evaporation process}
\begin{tikzpicture}
\begin{loglogaxis}[width=5.4cm,auto node placement,
  height=4cm,font=\scriptsize]
  \LCPAddPVQuality[
    quality values={0,1}]
  \LCPAddPVProcess[
    type=isobar,pressure=3bar,
    from={quality=0},to={quality=1},
    name=pv-evaporation,
    color=purple,label={evaporation},
    mark endpoints=true]
\end{loglogaxis}
\end{tikzpicture}
\end{LCPShowcase}
\end{LCPCommandRef}

The generic spellings are also fully equivalent:

\begin{LCPExample}{PV through the generic registry}
\LCPDiagram{PV}[isotherm=true]
\LCPAddDiagramPlots{PV}[isentrope=true]
\LCPAddDiagramFamily{PV}{quality}[quality step=0.1]
\LCPAddDiagramProcess{PV}[
  type=isobar,pressure=3bar,
  from={quality=0},to={quality=1}]
\end{LCPExample}

\subsection{PV keys and defaults}

Options are read from \path{/luacoolprop/diagram/PV}.  PV intentionally
combines the format-independent controls with its own declared capabilities.
The following table states precisely which shared groups apply; the PH section
is merely where some leaf-key entries appear earlier in this manual.

\begin{longtable}{@{}>{\raggedright\arraybackslash}p{.27\linewidth}>{\raggedright\arraybackslash}p{.67\linewidth}@{}}
\toprule
Group & Keys accepted without change in PV \\
\midrule
\endhead
Source and selection & \texttt{fluid}, \texttt{library}, \texttt{quality},
\texttt{isotherm}, \texttt{isentrope}, and their documented aliases.\\
Pressure & \texttt{pressure min}, \texttt{pressure max},
\texttt{pressure max factor}, \texttt{pressure scale}, and aliases.\\
Quality grid & Every \texttt{quality ...} grid key and every \texttt{q ...}
alias: mode, values, minimum, maximum, step, count, and preset.\\
Temperature grid & Every \texttt{temperature ...} and \texttt{t ...} grid key,
including unit, mode, values, limits, step, count, and preset.\\
Entropy grid & Every \texttt{entropy ...} and \texttt{s ...} grid key,
including unit, mode, values, limits, step, count, and preset.\\
Symbols & \texttt{pressure symbol}, \texttt{specific volume symbol},
\texttt{quality symbol}, \texttt{temperature symbol}, and
\texttt{entropy symbol}.\\
Appearance & General curve style, quality boundary/interior styles,
family colours and styles, legend, forget plot, and \texttt{axis options}.\\
Labels & General and family-specific quality, isotherm, and isentrope label
keys; all autonode forwarding and per-curve override keys.\\
Sampling & \texttt{initial intervals}, \texttt{max depth},
\texttt{tolerance}, \texttt{log weight}, family-specific refinements,
\texttt{saturation pressure epsilon}, and \texttt{coord digits}.\\
\bottomrule
\end{longtable}

PV has no isochore background family: an explicit \texttt{isochore} switch is
an error.  To draw an isochoric transformation, use
\macro{\LCPAddPVProcess} with \texttt{type=isochore}.

\LCPKeyDoc{luacoolprop/diagram/PV}{specific volume scale}{positive number}{global scale, initially 1}
  {Advanced raw multiplier for SI specific volume.  It produces the explicit
   scaled-SI axis label.}
  {500}
\LCPKeyAlias{luacoolprop/diagram/PV}{v scale}{specific volume scale}
\LCPKeyDoc{luacoolprop/diagram/PV}{specific volume axis unit}{m3kg or lkg}{m3kg}
  {Atomically selects the specific-volume conversion and horizontal label.}
  {lkg}
\LCPKeyDoc{luacoolprop/diagram/PV}{pressure axis unit}{pa, kpa, mpa, or bar}{bar}
  {Atomically selects the pressure conversion and vertical label.}
  {kpa}

\LCPKeyDoc{luacoolprop/diagram/PV}{log x weight}{nonnegative number}{30}
  {Weights deviations in $\log_{10}v$ during adaptive refinement.  Increasing
   it produces more points where a curve bends sharply on the logarithmic
   volume axis.}
  {45}

\begin{LCPShowcase}[lefthand ratio=.48]{Scaling the PV abscissa to litres per kilogram}
\LCPPVDiagram[
  specific volume axis unit=lkg,
  quality values={0,0.5,1},
  axis options={width=5.4cm,
    height=4.2cm,font=\scriptsize}
]
\end{LCPShowcase}

\subsection{PV curve names, intersections, and overrides}

Stable PV path names are separate from PH names:

\begin{center}
\begin{tabular}{@{}lll@{}}
\toprule
Family & Pattern & Example \\
\midrule
quality & \texttt{lcp-pv-q-\meta{value}} & \texttt{lcp-pv-q-0p5}\\
isotherm & \texttt{lcp-pv-T-\meta{value}-C} & \texttt{lcp-pv-T-20-C}\\
isentrope & \texttt{lcp-pv-s-\meta{value}-kJkgK} & \texttt{lcp-pv-s-1p8-kJkgK}\\
process & \texttt{lcp-pv-process-\meta{type}-...} & customisable with \texttt{name}\\
\bottomrule
\end{tabular}
\end{center}

Consequently the common per-curve keys target PV curves by their PV name:

\begin{LCPExample}{A PV-specific curve override}
\LCPPVDiagram[
  quality values={0,0.5,1},labels=true,
  curve style for={lcp-pv-q-0p5}{very thick,orange},
  label text for={lcp-pv-q-0p5}{$x=50\%$},
  label fixed for={lcp-pv-q-0p5}{true},
  label pos for={lcp-pv-q-0p5}{0.55}]
\end{LCPExample}

Names can be consumed by TikZ's \texttt{intersections} library exactly as PH
names can.  Automatic label placement remains entirely delegated to the
bundled \pkg{pgfplots-autonode} library.

\subsection{PV process keys and numerical exports}

PV process options use the \texttt{PV} branch of the
\texttt{/luacoolprop/process} namespace.  It uses the shared state definition,
process selection, style, marker, label, naming, sampling, and coordinate-
export keys.  All six process types are supported:

\begin{description}
\item[\texttt{isobar}] exact horizontal segment at constant pressure;
\item[\texttt{isochore}] exact vertical segment at constant specific volume;
\item[\texttt{isotherm}] adaptively sampled constant-temperature path,
including its two-phase plateau where applicable;
\item[\texttt{isentropic}] adaptively sampled constant-entropy path;
\item[\texttt{isenthalpic}] adaptively sampled throttling path; and
\item[\texttt{quality}] adaptively sampled constant-quality path, with
\texttt{isoquality} accepted as an alias.
\end{description}

\LCPKeyDoc{luacoolprop/process/PV}{specific volume scale}{positive number}{global scale, initially 1}
  {Multiplies endpoint and sampled specific volumes before plotting.  It also
   determines the unit scale of exported \texttt{FromX} and \texttt{ToX}.}
  {1000}
\LCPKeyAlias{luacoolprop/process/PV}{v scale}{specific volume scale}

\LCPKeyDoc{luacoolprop/process/PV}{log x weight}{nonnegative number}{30}
  {Weights logarithmic-volume curvature while refining a non-straight PV
   process path.}
  {45}

With \texttt{export coordinates=StateAB}, the generic property exports retain
the SI values documented in the shared process reference.  In addition, the
display-coordinate meanings are now
\texttt{\textbackslash StateAB\allowbreak FromX} $=v_{\rm from}$ times
\texttt{specific volume scale} and
\texttt{\textbackslash StateAB\allowbreak FromY} $=p_{\rm from}$ times
\texttt{pressure scale}, with analogous \texttt{ToX} and \texttt{ToY}
definitions.  This distinction makes numerical tables independent of plot
units: use \texttt{FromSpecific\allowbreak VolumeSI} for SI calculations and
\texttt{FromX} for an annotation aligned with the axis.

\begin{LCPExample}{Exporting PV endpoint coordinates and SI properties}
\LCPAddPVProcess[
  type=isentropic,
  from={p=2bar,quality=1},to={p=12bar},
  export coordinates=Compression,
  log coordinates=true]
% Plot coordinates: \CompressionFromX, \CompressionToX.
% Raw SI properties: \CompressionFromSpecificVolumeSI,
%                    \CompressionToPressureSI.
\end{LCPExample}

\subsection{Plain TeX and ConTeXt}

The implementation is in the generic layer; neither wrapper has a reduced PV
feature set.

\begin{LCPExample}{Plain LuaTeX}
\input p-luacoolprop.tex
\pgfplotsset{compat=1.18}
\LCPPVDiagram[isotherm=true,isentrope=true]
\bye
\end{LCPExample}

\begin{LCPExample}{ConTeXt MkIV}
\usemodule[t][luacoolprop]
\pgfplotsset{compat=1.18}
\starttext
  \LCPPVDiagram[isotherm=true,isentrope=true]
\stoptext
\end{LCPExample}

\section{TS temperature--entropy diagrams}

A TS diagram places mass-specific entropy on the horizontal axis and absolute
temperature on the vertical axis.  LuaCoolProp keeps CoolProp values in SI
units internally and applies \texttt{entropy scale=0.001} and
\texttt{temperature scale=1} at the plotting boundary.  The resulting default
axes therefore read \si{\kilo\joule\per\kilogram\per\kelvin} and
\si{\kelvin}.  Both axes are linear.  Unlike a PH or PV diagram, pressure is a
sampling variable rather than a plotted coordinate.

The saturation family contains the two boundaries $Q=0$ and $Q=1$, optional
interior qualities, and one shared quality-independent critical limit obtained
from the unique critical state.  Isenthalps are sampled adaptively from constant mass-specific
enthalpy and pressure.  This construction is fluid-independent: no R134a
coordinates or refrigerant-specific critical correction are stored in the
package.

\begin{LCPShowcase}[lefthand ratio=.48]{A complete TS diagram}
\LCPTSDiagram[
  fluid=R134a,
  isenthalp=true,
  quality values={0,0.25,0.5,0.75,1},
  enthalpy values={200,250,300,350,400,450},
  labels=true,
  axis options={width=6.1cm,height=5.0cm,
    font=\scriptsize}
]
\end{LCPShowcase}

\subsection{TS commands}

\begin{LCPCommandRef}{LCPTSDiagram}{\oarg{options}}
Creates a complete linear TS axis, computes data-dependent bounds, and draws
all enabled families.  It is equivalent to
\texttt{\string\LCPDiagram\{TS\}}.
\begin{LCPExample}{A saturation dome and selected isenthalps}
\LCPTSDiagram[fluid=R134a,isenthalp=true,
  enthalpy values={200,300,400}]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddTSPlots}{\oarg{options}}
Adds every enabled TS family to the current PGFPlots axis.  Use this command
when the surrounding axis, layers, annotations, and cycle are controlled by
the document.
\begin{LCPExample}{Low-level TS background}
\begin{axis}[xlabel={$s$},ylabel={$T$}]
  \LCPAddTSPlots[fluid=R134a,isenthalp=true]
\end{axis}
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddTSQuality}{\oarg{options}}
Adds only the constant-quality family to the current axis.  The stable path
names have the form \texttt{lcp-ts-q-0p5}; they may be used with TikZ's
\texttt{intersections} library.  Near the critical state, sampling is adaptive
in \(\log_{10}((p_c-p)/p_c)\) as well as in the main log-pressure coordinate;
the shared \texttt{tolerance} and \texttt{max depth} keys control both passes.
\begin{LCPExample}{Only the saturation boundaries}
\LCPAddTSQuality[fluid=R134a,
  quality preset=boundaries]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddTSIsenthalps}{\oarg{options}}
Adds only constant mass-specific-enthalpy curves.  Input values follow
\texttt{enthalpy unit}; the default is \texttt{kjkg}.
\begin{LCPExample}{Three explicit isenthalps}
\LCPAddTSIsenthalps[fluid=R134a,
  enthalpy values={250,300,350}]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddTSProcess}{\oarg{options}}
Adds one process to a current TS axis.  It accepts the same state language and
all six shared process types.  Isotherms are horizontal, isentropes
vertical, and the remaining process types are thermodynamically sampled.
\begin{LCPExample}{An isentropic compression}
\LCPAddTSProcess[fluid=R134a,type=isentrope,
  from={p=2bar,Q=1},to={p=12bar}]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddTSIsoQuality}{\oarg{options}}
Alternate spelling for \macro{\LCPAddTSQuality}; the latter is canonical.
\begin{LCPExample}{Alternate spelling}
\LCPAddTSIsoQuality[quality values={0,0.5,1}]
\end{LCPExample}
\end{LCPCommandRef}

The generic forms are fully equivalent:
\begin{LCPExample}{Generic TS family and process dispatch}
\LCPAddDiagramFamily{TS}{quality}[<options>]
\LCPAddDiagramFamily{TS}{isenthalp}[<options>]
\LCPAddDiagramProcess{TS}[<options>]
\end{LCPExample}
A generic client can thus select PH, PV, TS, or HS without changing its
dispatch structure.

\subsection{Shared diagram vocabulary}

The TS namespace is \texttt{/luacoolprop/diagram/TS}.  It deliberately reuses
the shared keys for the fluid and library, pressure limits, quality grid,
symbols, common sampling controls, curve overrides, autonode controls, styles,
and labels.  These controls have one definition used symmetrically by every
applicable diagram type.
For example:

\begin{LCPExample}{Shared keys used by TS}
\LCPTSDiagram[
  fluid=Propane,
  pressure min=100000,
  pressure max factor=1.05,
  quality symbol=x,
  quality step=0.2,
  labels=true,
  label placement=autonode,
  quality color=teal,
  curve style={opacity=.85},
  axis options={title={Propane TS diagram}}
]
\end{LCPExample}

TS does not register isotherm, isentrope, isochore, or isobar backgrounds, and
their family switches therefore fail explicitly.  Use the TS-specific
\texttt{temperature axis min/max} and \texttt{entropy axis min/max} keys to
constrain the plotted coordinate ranges.

\subsection{TS family, scale, and grid keys}

\LCPKeyDoc{luacoolprop/diagram/TS}{isenthalp}{boolean}{false}
  {Enables the constant-mass-specific-enthalpy background family.}
  {true}
\LCPKeyAlias{luacoolprop/diagram/TS}{isenthalps}{isenthalp}
\LCPKeyAlias{luacoolprop/diagram/TS}{enthalpy curves}{isenthalp}

\LCPKeyDoc{luacoolprop/diagram/TS}{entropy scale}{number}{0.001}
  {Advanced raw multiplier for SI entropy; it produces an explicit scaled-SI
   axis label.}
  {0.002}
\LCPKeyAlias{luacoolprop/diagram/TS}{s scale}{entropy scale}
\LCPKeyDoc{luacoolprop/diagram/TS}{temperature scale}{number}{1}
  {Multiplies vertical absolute temperatures.  This is a multiplicative
   advanced interface with zero offset and a scaled-SI label.}
  {0.5}
\LCPKeyAlias{luacoolprop/diagram/TS}{t scale}{temperature scale}
\LCPKeyDoc{luacoolprop/diagram/TS}{entropy axis unit}{jkgk or kjkgk}{kjkgk}
  {Atomically selects the entropy conversion and horizontal label.}
  {jkgk}
\LCPKeyDoc{luacoolprop/diagram/TS}{temperature axis unit}{kelvin or celsius}{kelvin}
  {Atomically selects the vertical label and conversion.  Celsius subtracts
   \num{273.15} before plotting and is supported because TS uses a linear
   ordinate.}
  {celsius}

\begin{LCPKeyRef}{luacoolprop/diagram/TS}{enthalpy unit}{unit}{kjkg}
Controls explicit enthalpy-grid input and generated labels.  Use
\texttt{kjkg} for \si{\kilo\joule\per\kilogram} or \texttt{si} for
\si{\joule\per\kilogram}; CoolProp always receives SI values.
\LCPKeyUse{luacoolprop/diagram/TS}{enthalpy unit}{si}
\end{LCPKeyRef}
\LCPKeyAlias{luacoolprop/diagram/TS}{h unit}{enthalpy unit}
\LCPKeyDoc{luacoolprop/diagram/TS}{enthalpy min}{number or auto}{auto}
  {Lower value used by an automatically generated isenthalp grid.}
  {200}
\LCPKeyDoc{luacoolprop/diagram/TS}{enthalpy max}{number or auto}{auto}
  {Upper value used by an automatically generated isenthalp grid.}
  {450}
\LCPKeyDoc{luacoolprop/diagram/TS}{enthalpy step}{positive number or auto}{auto}
  {Linear spacing.  With \texttt{auto}, \texttt{enthalpy count} controls the
   number of curves.}
  {50}
\begin{LCPKeyRef}{luacoolprop/diagram/TS}{enthalpy mode}{choice}{linear}
Selects \texttt{linear} automatic generation or \texttt{list} interpretation
of \texttt{enthalpy values}.  Supplying a nonempty explicit list selects list
mode automatically.
\LCPKeyUse{luacoolprop/diagram/TS}{enthalpy mode}{list}
\end{LCPKeyRef}
\LCPKeyDoc{luacoolprop/diagram/TS}{enthalpy count}{positive integer}{8}
  {Number of linearly spaced automatic values when no step is supplied.}
  {6}
\LCPKeyDoc{luacoolprop/diagram/TS}{enthalpy values}{comma list}{empty}
  {Explicit enthalpies in the selected display unit.}
  {{200,250,300,350,400}}
\LCPKeyAlias{luacoolprop/diagram/TS}{h min}{enthalpy min}
\LCPKeyAlias{luacoolprop/diagram/TS}{h max}{enthalpy max}
\LCPKeyAlias{luacoolprop/diagram/TS}{h step}{enthalpy step}
\LCPKeyAlias{luacoolprop/diagram/TS}{h mode}{enthalpy mode}
\LCPKeyAlias{luacoolprop/diagram/TS}{h count}{enthalpy count}
\LCPKeyAlias{luacoolprop/diagram/TS}{h values}{enthalpy values}

\subsection{TS isenthalp appearance and labels}

\LCPKeyDoc{luacoolprop/diagram/TS}{isenthalp labels}{boolean or auto}{auto}
  {Overrides the common \texttt{labels} switch for isenthalps.}
  {true}
\LCPKeyDoc{luacoolprop/diagram/TS}{isenthalp label pos}{fraction}{0.65}
  {Preferred arc-length position forwarded to pgfplots-autonode.}
  {0.55}
\LCPKeyDoc{luacoolprop/diagram/TS}{isenthalp label every}{positive integer}{2}
  {Labels every $n$th isenthalp and always considers the last curve.}
  {1}
\LCPKeyDoc{luacoolprop/diagram/TS}{isenthalp label sloped}{boolean or auto}{auto}
  {Requests a label aligned with its local isenthalp tangent.}
  {true}
\LCPKeyDoc{luacoolprop/diagram/TS}{isenthalp label allow upside down}{boolean or auto}{auto}
  {Allows the automatic node to retain an upside-down tangent direction.}
  {false}
\LCPKeyDoc{luacoolprop/diagram/TS}{isenthalp label style}{TikZ style name}{luacoolprop isenthalp label node}
  {Selects the TikZ node style used for generated enthalpy labels.}
  {luacoolprop label node}
\LCPKeyDoc{luacoolprop/diagram/TS}{isenthalp label node style}{TikZ options}{package default}
  {Redefines the dedicated \texttt{luacoolprop isenthalp label node} style.}
  {{fill=yellow!15,inner sep=1pt}}
\LCPKeyDoc{luacoolprop/diagram/TS}{isenthalp color}{colour}{red!65!black}
  {Sets the base colour of constant-enthalpy curves.}
  {orange!80!black}
\LCPKeyDoc{luacoolprop/diagram/TS}{isenthalp style}{TikZ plot options}{thin dashed line}
  {Appends family-specific drawing options after the colour.}
  {{line width=.35pt,densely dotted}}

The generated stable name includes the displayed enthalpy and unit; with the
defaults, \texttt{enthalpy values=\{300\}} creates
\texttt{lcp-ts-h-300-kJkg}.  All per-curve override keys operate on that name.

\subsection{TS sampling and axis bounds}

\LCPKeyDoc{luacoolprop/diagram/TS}{isenthalp initial intervals}{positive integer}{16}
  {Initial logarithmic-pressure intervals before adaptive refinement.}
  {24}
\LCPKeyDoc{luacoolprop/diagram/TS}{isenthalp max depth}{nonnegative integer}{8}
  {Maximum recursive bisection depth for an isenthalp.}
  {10}
\LCPKeyDoc{luacoolprop/diagram/TS}{isenthalp tolerance}{positive number}{0.10}
  {Maximum scaled midpoint error accepted by isenthalp sampling.}
  {0.06}
\LCPKeyDoc{luacoolprop/diagram/TS}{temperature weight}{positive number}{0.01}
  {Converts vertical deviations in kelvin to the scaled midpoint error used
   on the linear TS axis.  Larger values refine temperature curvature more
   aggressively.}
  {0.02}
\LCPKeyDoc{luacoolprop/diagram/TS}{entropy axis min}{number or auto}{auto}
  {Overrides the automatically padded horizontal lower bound in plotted
   entropy units.}
  {0.8}
\LCPKeyDoc{luacoolprop/diagram/TS}{entropy axis max}{number or auto}{auto}
  {Overrides the automatically padded horizontal upper bound.}
  {2.2}
\LCPKeyDoc{luacoolprop/diagram/TS}{temperature axis min}{number or auto}{auto}
  {Overrides the vertical lower bound after \texttt{temperature scale}.}
  {220}
\LCPKeyDoc{luacoolprop/diagram/TS}{temperature axis max}{number or auto}{auto}
  {Overrides the vertical upper bound after \texttt{temperature scale}.}
  {420}

The general \texttt{initial intervals}, \texttt{max depth}, and
\texttt{tolerance} keys remain fallbacks for both TS families.  Quality curves
use the same coordinate-independent critical-neighbourhood refinement contract
as every other diagram.  Tight tolerances increase both CoolProp calls and generated TeX
coordinates; they should be changed only after inspecting the plotted result.

\subsection{TS process keys and exported values}

The process namespace is \texttt{/luacoolprop/process/TS}.  Every shared
process key applies: state pairs and units, \texttt{type}, constant-property keys,
path identity, styling, endpoint markers, adaptive sampling,
\texttt{export coordinates}, and \texttt{log coordinates}.  Exported endpoint
macros retain the complete SI state.  Their plotted \texttt{X} value is scaled
entropy and their plotted \texttt{Y} value is the selected temperature
coordinate; the exported \texttt{TemperatureSI} value remains absolute kelvin.

\LCPKeyDoc{luacoolprop/process/TS}{entropy scale}{number}{0.001}
  {Multiplies process endpoint and path entropy coordinates.}
  {0.001}
\LCPKeyAlias{luacoolprop/process/TS}{s scale}{entropy scale}
\LCPKeyDoc{luacoolprop/process/TS}{temperature scale}{number}{1}
  {Multiplies process endpoint and path temperature coordinates.}
  {1}
\LCPKeyAlias{luacoolprop/process/TS}{t scale}{temperature scale}
\LCPKeyDoc{luacoolprop/process/TS}{temperature weight}{positive number}{0.01}
  {Controls the temperature contribution to adaptive TS process sampling.}
  {0.02}

\begin{LCPExample}{Chain TS processes through exported SI entropy}
\LCPAddTSProcess[type=isobar,pressure=2bar,
  from={Q=0},to={Q=1},export coordinates=EvapTS]
\LCPAddTSProcess[type=isentrope,
  from={p=2bar,Q=1},
  to={p=12bar,s=\EvapTSToEntropySI}]
\end{LCPExample}

For TS, an isobar is parameterised by entropy.  Consequently, an evaporation
or condensation process crosses the two-phase region as the physically exact
horizontal saturation plateau instead of jumping between separately evaluated
single-phase states.  Isochores are parameterised by temperature; isenthalps
and qualities retain logarithmic-pressure sampling.  These choices affect only
the path sampler, not the public state syntax.

\subsection{Plain TeX and ConTeXt}

The TS commands belong to the generic layer, so their spelling and semantics
are identical in every supported format:

\begin{LCPExample}{Plain LuaTeX TS diagram}
\input p-luacoolprop.tex
\pgfplotsset{compat=1.18}
\LCPTSDiagram[fluid=R134a,isenthalp=true]
\bye
\end{LCPExample}

\begin{LCPExample}{ConTeXt TS diagram}
\usemodule[t][luacoolprop]
\pgfplotsset{compat=1.18}
\starttext
\LCPTSDiagram[fluid=R134a,isenthalp=true]
\stoptext
\end{LCPExample}

Only LaTeX uses siunitx to format generated numerical labels and axis units.
Plain TeX and ConTeXt use the generic math fallbacks and do not acquire a
LaTeX dependency.

\section{HS enthalpy--entropy diagrams}

An HS, or Mollier, diagram places mass-specific entropy on the horizontal
axis and mass-specific enthalpy on the vertical axis.  The default scales
convert CoolProp's SI results to
\si{\kilo\joule\per\kilogram\per\kelvin} and
\si{\kilo\joule\per\kilogram}; both axes are linear.  The implementation
retains the complete SI thermodynamic state on every sampled point, so the
same curve records can support drawing, intersections, and exported process
coordinates without a second property model.

Four independently selectable backgrounds are available: constant quality,
constant mass-specific volume, constant temperature, and constant pressure.
All are calculated from the selected CoolProp fluid.  Constant-quality curves
share one exact quality-independent critical limit.  A subcritical isotherm includes both
saturated endpoints and its straight two-phase mixture segment.  Isobars are
parameterised by entropy rather than by temperature; this makes evaporation
and condensation continuous through the two-phase region.  No water-specific
coordinates or fitted curve data are stored in the package.

\begin{LCPShowcase}[lefthand ratio=.48]{A Water HS diagram with four families}
\LCPHSDiagram[
  fluid=Water,
  pressure min=10000,
  pressure max=30000000,
  quality values={0,0.25,0.5,0.75,1},
  isochore=true,
  specific volume values={0.002,0.01,0.1,1},
  isotherm=true,
  temperature values={100,200,300,400},
  isobar=true,
  isobar values={0.1,1,10,100,250},
  isobar temperature min=10,
  isobar temperature max=500,
  labels=false,
  axis options={width=6.2cm,height=5.1cm,
    font=\scriptsize}
]
\end{LCPShowcase}

\subsection{HS commands}

\begin{LCPCommandRef}{LCPHSDiagram}{\oarg{options}}
Creates the TikZ picture and a complete linear HS axis, derives padded bounds
from the generated data, and draws every enabled family.  It is the convenient
form of \texttt{\string\LCPDiagram\{HS\}}.
\begin{LCPExample}{A compact Water saturation dome}
\LCPHSDiagram[fluid=Water,
  quality preset=boundaries]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddHSPlots}{\oarg{options}}
Adds all enabled HS families to an existing PGFPlots axis.  The document owns
the axis limits and presentation in this low-level form.
\begin{LCPExample}{Add an HS background to a custom axis}
\begin{axis}[xlabel={$s$},ylabel={$h$}]
  \LCPAddHSPlots[fluid=Water,isobar=true]
\end{axis}
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddHSQuality}{\oarg{options}}
Adds only constant-quality curves.  Their stable paths are named
\texttt{lcp-hs-q-<value>}; for example, $Q=0.5$ gives
\texttt{lcp-hs-q-0p5}.  The approach to the critical state is adaptively
resolved in logarithmic reduced pressure, using the shared \texttt{tolerance}
and \texttt{max depth} settings with the HS coordinate-error metric.
\begin{LCPExample}{Only the Water saturation boundaries}
\LCPAddHSQuality[fluid=Water,
  quality values={0,1}]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddHSIsochores}{\oarg{options}}
Adds only constant-mass-specific-volume curves.  Values and labels obey
\texttt{specific volume unit}; the default is
\si{\cubic\metre\per\kilogram}.
\begin{LCPExample}{Three Water isochores}
\LCPAddHSIsochores[fluid=Water,
  specific volume values={0.01,0.1,1}]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddHSIsotherms}{\oarg{options}}
Adds only constant-temperature curves.  Input and labels obey
\texttt{temperature unit}, which defaults to degrees Celsius.
\begin{LCPExample}{Selected Water isotherms}
\LCPAddHSIsotherms[fluid=Water,
  temperature values={100,200,300}]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddHSIsobars}{\oarg{options}}
Adds only constant-pressure curves.  Their stable names include their displayed
value and unit: with the defaults, \texttt{isobar values=\{10\}} creates
\texttt{lcp-hs-p-10-bar}.
\begin{LCPExample}{Selected Water isobars}
\LCPAddHSIsobars[fluid=Water,
  isobar values={0.1,1,10,100}]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddHSProcess}{\oarg{options}}
Adds one thermodynamic path to the current HS axis.  It accepts the common
state language and the process types \texttt{isobar}, \texttt{isotherm},
\texttt{isentropic}/\texttt{isentrope}, \texttt{isenthalpic}/
\texttt{isenthalp}, \texttt{isochore}, and \texttt{quality}.  Isentropes are
exactly vertical and isenthalps exactly horizontal in HS coordinates.
\begin{LCPExample}{An isentropic Water compression}
\LCPAddHSProcess[fluid=Water,type=isentrope,
  from={p=1bar,Q=1},to={p=10bar}]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddHSIsoQuality}{\oarg{options}}
Alternate spelling for \macro{\LCPAddHSQuality}; the latter is canonical.
\begin{LCPExample}{Alternate spelling}
\LCPAddHSIsoQuality[quality values={0,0.5,1}]
\end{LCPExample}
\end{LCPCommandRef}

The generic forms are equivalent and make coordinate selection data-driven:
\begin{LCPExample}{Generic HS dispatch}
\LCPDiagram{HS}[<options>]
\LCPAddDiagramPlots{HS}[<options>]
\LCPAddDiagramFamily{HS}{quality}[<options>]
\LCPAddDiagramFamily{HS}{isochore}[<options>]
\LCPAddDiagramFamily{HS}{isotherm}[<options>]
\LCPAddDiagramFamily{HS}{isobar}[<options>]
\LCPAddDiagramProcess{HS}[<options>]
\end{LCPExample}

\subsection{Shared vocabulary and physical ranges}

The canonical namespace is \texttt{/luacoolprop/diagram/HS}.  It inherits the
shared vocabulary for the fluid and library, pressure range, quality grid,
temperature grid, specific-volume grid, thermodynamic symbols, adaptive
sampling, labels, pgfplots-autonode placement, curve styles, per-curve
overrides, legends, and \texttt{axis options}.  HS owns both coordinate-unit
choices: entropy horizontally and enthalpy vertically.

\begin{LCPExample}{Shared controls in an HS diagram}
\LCPHSDiagram[
  fluid=Water,
  pressure min=10000,
  pressure max factor=1.02,
  quality symbol=x,
  quality step=0.2,
  isotherm=true,
  temperature unit=celsius,
  temperature values={100,200,300},
  isochore=true,
  specific volume values={0.01,0.1,1},
  labels=true,
  label placement=autonode,
  curve style={opacity=.85},
  axis options={title={Water Mollier diagram}}
]
\end{LCPExample}

The \texttt{pressure min/max} interval bounds quality, isochore, and isotherm
sampling, and supplies the default isobar grid.  It should remain inside the
fluid equation-of-state validity range.  An explicitly requested curve may
still have fewer visible points when CoolProp reports that part of the state
domain as invalid; invalid individual samples are omitted, while a wholly
   invalid interval yields no curve.  Valid components on opposite sides of an
   invalid interval are never joined; select \texttt{domain policy=warning}
   to audit omissions.

\subsection{HS switches, scale, and error metric}

\LCPKeyDoc{luacoolprop/diagram/HS}{isobar}{boolean}{false}
  {Enables the constant-pressure background family.}
  {true}
\LCPKeyAlias{luacoolprop/diagram/HS}{isobars}{isobar}
\LCPKeyDoc{luacoolprop/diagram/HS}{entropy scale}{number}{0.001}
  {Advanced raw multiplier for horizontal SI entropy; it produces a scaled-SI
   label.}
  {0.002}
\LCPKeyAlias{luacoolprop/diagram/HS}{s scale}{entropy scale}
\LCPKeyDoc{luacoolprop/diagram/HS}{entropy axis unit}{jkgk or kjkgk}{kjkgk}
  {Atomically selects the horizontal entropy conversion and label.}
  {jkgk}
\LCPKeyDoc{luacoolprop/diagram/HS}{enthalpy axis unit}{jkg or kjkg}{kjkg}
  {Atomically selects the vertical enthalpy conversion and label.}
  {jkg}
\LCPKeyDoc{luacoolprop/diagram/HS}{enthalpy weight}{positive number}{0.01}
  {Weights vertical enthalpy error in the adaptive midpoint test.  Increasing
   it inserts more samples where the HS curve bends sharply.}
  {0.02}

The other declared HS switches select their corresponding families:
\begin{LCPExample}{Every HS family switch}
\LCPHSDiagram[quality=true,isochore=true,
  isotherm=true,isobar=true]
\end{LCPExample}
Their grids, styles, labels, units, and symbols use the shared
\texttt{quality ...}, \texttt{specific volume ...}, and
\texttt{temperature ...} keys documented in the PH reference.

\subsection{Isobar grid and units}

\begin{LCPKeyRef}{luacoolprop/diagram/HS}{isobar unit}{unit}{bar}
Controls the input grid, stable path names, and generated pressure labels.
Accepted values are \texttt{bar}, \texttt{kpa}, \texttt{mpa}, and
\texttt{pa} or \texttt{si}; all values are converted to pascals before calling
CoolProp.
\LCPKeyUse{luacoolprop/diagram/HS}{isobar unit}{mpa}
\end{LCPKeyRef}
\LCPKeyDoc{luacoolprop/diagram/HS}{isobar min}{positive number or auto}{auto}
  {Lower automatically generated pressure in \texttt{isobar unit}.  Automatic
   means the diagram's lower pressure bound.}
  {0.1}
\LCPKeyDoc{luacoolprop/diagram/HS}{isobar max}{positive number or auto}{auto}
  {Upper automatically generated pressure in \texttt{isobar unit}.}
  {250}
\LCPKeyDoc{luacoolprop/diagram/HS}{isobar step}{positive number or auto}{auto}
  {Spacing used by a linear grid.  With \texttt{auto},
   \texttt{isobar count} determines the grid.}
  {10}
\begin{LCPKeyRef}{luacoolprop/diagram/HS}{isobar mode}{choice}{log}
Selects \texttt{log}, \texttt{linear}, or \texttt{list} grid generation.
Supplying \texttt{isobar values} selects list mode automatically.  Logarithmic
spacing is usually the most readable choice over a wide pressure range.
\LCPKeyUse{luacoolprop/diagram/HS}{isobar mode}{linear}
\end{LCPKeyRef}
\LCPKeyDoc{luacoolprop/diagram/HS}{isobar count}{positive integer}{7}
  {Number of automatically spaced isobars when no explicit step is given.}
  {9}
\LCPKeyDoc{luacoolprop/diagram/HS}{isobar values}{comma list}{empty}
  {Explicit constant pressures in \texttt{isobar unit}.}
  {{0.1,1,10,100,250}}
\LCPKeyDoc{luacoolprop/diagram/HS}{isobar temperature min}{number or auto}{auto}
  {Lower endpoint of each isobar.  Numeric values use
   \texttt{temperature unit}; automatic selection stays inside CoolProp's
   fluid validity range.}
  {10}
\LCPKeyDoc{luacoolprop/diagram/HS}{isobar temperature max}{number or auto}{auto}
  {Upper endpoint of each isobar in \texttt{temperature unit}.}
  {500}

For example, this deliberately uses kelvin for both endpoint controls:
\begin{LCPExample}{Kelvin-bounded isobars}
\LCPAddHSIsobars[fluid=Water,
  temperature unit=kelvin,
  isobar values={1,10},
  isobar temperature min=300,
  isobar temperature max=700]
\end{LCPExample}

\subsection{Isobar appearance and automatic labels}

\LCPKeyDoc{luacoolprop/diagram/HS}{isobar labels}{boolean or auto}{auto}
  {Overrides the common \texttt{labels} switch for the isobar family.}
  {true}
\LCPKeyDoc{luacoolprop/diagram/HS}{isobar label pos}{fraction}{0.68}
  {Preferred normalised arc-length position supplied to
   pgfplots-autonode.}
  {0.55}
\LCPKeyDoc{luacoolprop/diagram/HS}{isobar label every}{positive integer}{2}
  {Offers every $n$th isobar, and always the final isobar, for labelling.}
  {1}
\LCPKeyDoc{luacoolprop/diagram/HS}{isobar label sloped}{boolean or auto}{auto}
  {Aligns each generated pressure label with the local curve tangent.}
  {true}
\LCPKeyDoc{luacoolprop/diagram/HS}{isobar label allow upside down}{boolean or auto}{auto}
  {Permits the local tangent to leave an isobar label upside down.}
  {false}
\LCPKeyDoc{luacoolprop/diagram/HS}{isobar label style}{TikZ style name}{luacoolprop isobar label node}
  {Selects the node style attached to generated pressure labels.}
  {luacoolprop label node}
\LCPKeyDoc{luacoolprop/diagram/HS}{isobar label node style}{TikZ options}{package default}
  {Redefines the dedicated \texttt{luacoolprop isobar label node} style in the
   current TeX scope.}
  {{fill=violet!10,inner sep=1.5pt}}
\LCPKeyDoc{luacoolprop/diagram/HS}{isobar color}{colour}{purple!70!black}
  {Sets the base colour of every constant-pressure curve.}
  {violet!80!black}
\LCPKeyDoc{luacoolprop/diagram/HS}{isobar style}{TikZ plot options}{thin dashed line}
  {Appends family-specific drawing options after the colour.}
  {{line width=.35pt,densely dashdotted}}

The common \texttt{pressure symbol} key also controls isobar label text:
\begin{LCPExample}{Use a custom pressure symbol}
\LCPAddHSIsobars[pressure symbol=P,
  isobar values={1,10},labels=true]
\end{LCPExample}
Per-curve overrides use the stable isobar name; for example:
\begin{LCPExample}{Emphasise the ten-bar path}
\LCPAddHSIsobars[isobar values={1,10,100},
  curve style for={lcp-hs-p-10-bar}{line width=1pt},
  label text for={lcp-hs-p-10-bar}{$p_{\rm boiler}$}]
\end{LCPExample}

\subsection{Isobar sampling and HS axis bounds}

\LCPKeyDoc{luacoolprop/diagram/HS}{isobar initial intervals}{positive integer}{16}
  {Initial entropy intervals before adaptive isobar refinement.}
  {24}
\LCPKeyDoc{luacoolprop/diagram/HS}{isobar max depth}{nonnegative integer}{8}
  {Maximum recursive midpoint-bisection depth for an isobar.}
  {10}
\LCPKeyDoc{luacoolprop/diagram/HS}{isobar tolerance}{positive number}{0.10}
  {Maximum scaled midpoint error accepted while sampling an isobar.}
  {0.06}
\LCPKeyDoc{luacoolprop/diagram/HS}{entropy axis min}{number or auto}{auto}
  {Overrides the automatically padded horizontal minimum after
   \texttt{entropy scale}.}
  {0}
\LCPKeyDoc{luacoolprop/diagram/HS}{entropy axis max}{number or auto}{auto}
  {Overrides the horizontal maximum in plotted entropy units.}
  {10}
\LCPKeyDoc{luacoolprop/diagram/HS}{enthalpy axis min}{number or auto}{auto}
  {Overrides the automatically padded vertical minimum after
   \texttt{enthalpy scale}.}
  {0}
\LCPKeyDoc{luacoolprop/diagram/HS}{enthalpy axis max}{number or auto}{auto}
  {Overrides the vertical maximum in plotted enthalpy units.}
  {4500}

The common \texttt{initial intervals}, \texttt{max depth}, and
\texttt{tolerance} remain fallbacks.  Family-specific controls take precedence:
isobars use the three keys above, while isotherms and isochores use their
inherited \texttt{isotherm ...} and \texttt{isochore ...} controls.  Smaller
tolerances generate more CoolProp calls and more TeX coordinates; refine only
when the plotted result requires it.

\subsection{HS process keys and exported coordinates}

The process namespace is \texttt{/luacoolprop/process/HS}.  Every shared
process key applies unchanged: fluid and library; endpoint state pairs and units;
process type and conserved value; names, styles, labels, and endpoint markers;
adaptive sampling; and \texttt{export coordinates}/\texttt{log coordinates}.
The exported \texttt{X} value is scaled entropy and \texttt{Y} is scaled
enthalpy, while all \texttt{...SI} endpoint macros retain SI units.

\LCPKeyDoc{luacoolprop/process/HS}{entropy scale}{number}{0.001}
  {Multiplies entropy coordinates along an HS process path.}
  {0.001}
\LCPKeyAlias{luacoolprop/process/HS}{s scale}{entropy scale}
\LCPKeyDoc{luacoolprop/process/HS}{enthalpy weight}{positive number}{0.01}
  {Controls the vertical enthalpy contribution to adaptive HS process
   refinement.}
  {0.02}

\begin{LCPExample}{Chain HS processes through exported entropy}
\LCPAddHSProcess[fluid=Water,type=isobar,
  from={p=1bar,Q=0},to={p=1bar,Q=1},
  export coordinates=EvapHS,log coordinates=true]
\LCPAddHSProcess[fluid=Water,type=isentrope,
  from={p=1bar,Q=1},
  to={p=10bar,s=\EvapHSToEntropySI}]
% Plot coordinates: \EvapHSFromX, \EvapHSFromY,
%                   \EvapHSToX,   \EvapHSToY.
% Raw SI results:   \EvapHSToEntropySI, \EvapHSToEnthalpySI.
\end{LCPExample}

For an isobar, entropy is the sampling parameter and the saturation mixture is
therefore represented continuously.  Isotherms include their exact mixture
segment; isochores are parameterised by temperature; constant-quality paths
use logarithmic pressure.  The choice of sampler is an implementation detail:
the public endpoint language stays identical across PH, PV, TS, HS, and PT.

\subsection{Plain TeX and ConTeXt}

HS is implemented entirely in the generic layer.  The same API is therefore
available through both non-LaTeX wrappers:

\begin{LCPExample}{Plain LuaTeX HS diagram}
\input p-luacoolprop.tex
\pgfplotsset{compat=1.18}
\LCPHSDiagram[fluid=Water,isobar=true,
  isobar values={1,10,100}]
\bye
\end{LCPExample}

\begin{LCPExample}{ConTeXt HS diagram}
\usemodule[t][luacoolprop]
\pgfplotsset{compat=1.18}
\starttext
\LCPHSDiagram[fluid=Water,isotherm=true,
  temperature values={100,200,300}]
\stoptext
\end{LCPExample}

Only the LaTeX wrapper uses siunitx for numeric labels and units.  It neither
resets nor changes an existing siunitx configuration.  Plain TeX and ConTeXt
use the generic math fallback supplied by \texttt{luacoolprop.tex}.

\section{PT pressure--temperature diagrams}
\label{sec:pt-diagrams}

A PT diagram places absolute thermodynamic temperature on the horizontal axis
and pressure on the vertical axis.  The high-level renderer uses a linear
temperature scale and a logarithmic pressure scale.  With the default bounds,
the vertical axis extends from the fluid's triple-point pressure to
$1.10p_c$, while the liquid--vapour coexistence curve itself ends exactly at
the critical point.

For a pure substance, saturated liquid and saturated vapour at equilibrium
have the same $T$ and $p$.  Consequently, PT contains one coexistence locus,
not separate bubble and dew curves and not a quality grid.  The starting
record uses CoolProp's exact $(T_t,p_t)$ constants; the final record uses the
exact $(T_c,p_c)$ constants.  Vapour quality is undefined at the critical
point and cannot be read anywhere from PT coordinates alone.

\begin{LCPWarning}[Information lost by the PT projection]
Every two-phase state at a given saturation pressure maps to the same PT
point, independently of its quality.  A PT curve therefore establishes phase
equilibrium and operating pressure/temperature, but it cannot replace a PH,
PV, TS, or HS diagram when quality, latent enthalpy, entropy, or specific
volume must be read graphically.  Isentropes, isenthalps, and isochores may
coincide with part of the coexistence locus while they traverse a two-phase
domain; this is the correct projection, not a sampling defect.
\end{LCPWarning}

\begin{LCPShowcase}[lefthand ratio=.50]{A complete R134a PT background}
\LCPPTDiagram[
  fluid=R134a,
  temperature axis unit=celsius,
  pressure axis unit=bar,
  isentrope=true,
  entropy values={1.4,1.7,2.0},
  isenthalp=true,
  enthalpy values={200,300,400},
  isochore=true,
  specific volume values={0.001,0.01,0.1},
  axis options={width=5.5cm,height=5.0cm,
    font=\scriptsize}
]
\end{LCPShowcase}

\subsection{PT commands}

\begin{LCPCommandRef}{LCPPTDiagram}{\oarg{options}}
Creates a TikZ picture and a PT axis, applies the coupled unit labels, obtains
the automatic fluid bounds, and draws all enabled families.
\begin{LCPExample}{Minimal PT diagram}
\LCPPTDiagram[fluid=Water]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddPTPlots}{\oarg{options}}
Adds all enabled PT families inside an existing axis.  The caller must supply
the linear-temperature/log-pressure axis and labels.
\begin{LCPExample}{All enabled families in an existing axis}
\begin{tikzpicture}
\begin{axis}[ymode=log]
  \LCPAddPTPlots[phase envelope=true,
    isentrope=true,entropy values={1.5,1.8},
    isenthalp=true,enthalpy values={250,350},
    isochore=true,specific volume values={0.01,0.1}]
\end{axis}
\end{tikzpicture}
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddPTPhaseEnvelope}{\oarg{options}}
Adds only the triple-to-critical liquid--vapour equilibrium curve.
\begin{LCPExample}{Coexistence curve only}
\LCPAddPTPhaseEnvelope[fluid=Propane,
  phase envelope color=blue,phase envelope style={very thick}]
\end{LCPExample}
\end{LCPCommandRef}
\LCPCommandAlias{LCPAddPTSaturation}{LCPAddPTPhaseEnvelope}

\begin{LCPCommandRef}{LCPAddPTIsentropes}{\oarg{options}}
Adds only constant-mass-specific-entropy curves.
\begin{LCPExample}{Selected PT isentropes}
\LCPAddPTIsentropes[entropy values={1.4,1.7,2.0}]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddPTIsenthalps}{\oarg{options}}
Adds only constant-mass-specific-enthalpy curves.
\begin{LCPExample}{Selected PT isenthalps}
\LCPAddPTIsenthalps[enthalpy values={200,300,400}]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddPTIsochores}{\oarg{options}}
Adds only constant-mass-specific-volume curves.
\begin{LCPExample}{Selected PT isochores}
\LCPAddPTIsochores[specific volume values={0.001,0.01,0.1}]
\end{LCPExample}
\end{LCPCommandRef}

\begin{LCPCommandRef}{LCPAddPTProcess}{\oarg{options}}
Projects any of the six shared conserved-property process kinds onto PT.
\begin{LCPExample}{An isentropic compression in PT coordinates}
\LCPAddPTProcess[type=isentrope,
  from={p=2bar,quality=1},to={p=10bar},
  name=pt-compression,export coordinates=PTCompression]
\end{LCPExample}
\end{LCPCommandRef}

The generic equivalents are listed below.  The family dispatcher also accepts
\texttt{saturation} and \texttt{equilibrium} on the Lua side; the canonical
public family name is \texttt{phase\_envelope}.
\begin{itemize}
  \item \texttt{\string\LCPDiagram\{PT\}};
  \item \texttt{\string\LCPAddDiagramPlots\{PT\}};
  \item \texttt{\string\LCPAddDiagramFamily\{PT\}\{phase\_envelope\}}; and
  \item \texttt{\string\LCPAddDiagramProcess\{PT\}}.
\end{itemize}

\subsection{Families, ranges, and coordinate units}

PT options use \texttt{/luacoolprop/diagram/PT}; the lowercase
\texttt{/luacoolprop/pt diagram} path is an alternate public spelling.

\LCPKeyDoc{luacoolprop/diagram/PT}{fluid}{CoolProp pure-fluid identifier}{global fluid}
  {Selects the pure fluid used by every PT family.}{Water}
\LCPKeyDoc{luacoolprop/diagram/PT}{library}{file path}{global library}
  {Selects an external CoolProp shared library for this diagram.}{/opt/coolprop/libCoolProp.dylib}
\LCPKeyDoc{luacoolprop/diagram/PT}{reference state}{DEF, IIR, ASHRAE, or NBP}{DEF}
  {Selects the locked enthalpy/entropy origin used by isenthalps and
   isentropes.}{DEF}
\LCPKeyDoc{luacoolprop/diagram/PT}{phase envelope}{boolean}{true}
  {Enables the single liquid--vapour equilibrium curve.}{false}
\LCPKeyAlias{luacoolprop/diagram/PT}{saturation}{phase envelope}
\LCPKeyAlias{luacoolprop/diagram/PT}{equilibrium curve}{phase envelope}
\LCPKeyDoc{luacoolprop/diagram/PT}{isentrope}{boolean}{false}
  {Enables constant-mass-specific-entropy curves.}{true}
\LCPKeyAlias{luacoolprop/diagram/PT}{isentropes}{isentrope}
\LCPKeyDoc{luacoolprop/diagram/PT}{isenthalp}{boolean}{false}
  {Enables constant-mass-specific-enthalpy curves.}{true}
\LCPKeyAlias{luacoolprop/diagram/PT}{isenthalps}{isenthalp}
\LCPKeyAlias{luacoolprop/diagram/PT}{enthalpy curves}{isenthalp}
\LCPKeyDoc{luacoolprop/diagram/PT}{isochore}{boolean}{false}
  {Enables constant-mass-specific-volume curves.}{true}
\LCPKeyAlias{luacoolprop/diagram/PT}{isochores}{isochore}

\LCPKeyDoc{luacoolprop/diagram/PT}{pressure min}{positive number or auto}{auto}
  {Sets the axis minimum in Pa; automatic PT bounds use $p_t$.  An explicit
   value also clips every sampled family.}{10000}
\LCPKeyDoc{luacoolprop/diagram/PT}{pressure max}{positive number or auto}{auto}
  {Sets the axis maximum in Pa; automatic PT bounds use $1.10p_c$.}{5E6}
\LCPKeyDoc{luacoolprop/diagram/PT}{pressure max factor}{positive number}{1.10}
  {Sets the automatic pressure maximum as a multiple of $p_c$.}{1.25}
\LCPKeyDoc{luacoolprop/diagram/PT}{temperature axis min}{number or auto}{auto}
  {Overrides the sampled horizontal minimum in the selected temperature axis
   unit.}{-100}
\LCPKeyDoc{luacoolprop/diagram/PT}{temperature axis max}{number or auto}{auto}
  {Overrides the sampled horizontal maximum in the selected temperature axis
   unit.}{150}
\LCPKeyDoc{luacoolprop/diagram/PT}{temperature axis unit}{kelvin or celsius}{kelvin}
  {Changes both horizontal coordinates and the axis label.  Celsius applies
   $T_{\rm plot}=T_{\rm SI}-273.15$, not a multiplicative approximation.}
  {celsius}
\LCPKeyDoc{luacoolprop/diagram/PT}{pressure axis unit}{pa, kpa, mpa, or bar}{bar}
  {Changes both vertical coordinates and the generated pressure-axis label.}
  {mpa}
\LCPKeyDoc{luacoolprop/diagram/PT}{temperature scale}{number}{global scale}
  {Provides an advanced raw multiplier with zero offset and an explicit
   scaled-SI axis label.}{1}
\LCPKeyAlias{luacoolprop/diagram/PT}{t scale}{temperature scale}
\LCPKeyDoc{luacoolprop/diagram/PT}{pressure scale}{number}{global scale}
  {Provides an advanced raw multiplier from Pa to plotted pressure.}{1E-5}
\LCPKeyAlias{luacoolprop/diagram/PT}{p scale}{pressure scale}
\LCPKeyDoc{luacoolprop/diagram/PT}{temperature symbol}{TeX math material}{T}
  {Changes the horizontal-axis symbol without changing the CoolProp
   property.}{{\theta}}
\LCPKeyDoc{luacoolprop/diagram/PT}{pressure symbol}{TeX math material}{p}
  {Changes the vertical-axis symbol.}{{P}}
\LCPKeyDoc{luacoolprop/diagram/PT}{enthalpy symbol}{TeX math material}{h}
  {Changes generated isenthalp labels.}{{i}}
\LCPKeyDoc{luacoolprop/diagram/PT}{entropy symbol}{TeX math material}{s}
  {Changes generated isentrope labels.}{{\sigma}}
\LCPKeyDoc{luacoolprop/diagram/PT}{specific volume symbol}{TeX math material}{v}
  {Changes generated isochore labels.}{{\nu}}

The entropy and specific-volume family grids use the complete shared keys
documented in Section~\ref{sec:ph-diagram-keys}:
\texttt{entropy unit/min/max/step/mode/count/preset/values} and
\texttt{specific volume unit/min/max/step/mode/count/preset/values}, including
their \texttt{s ...} and \texttt{v ...} aliases.  Values are converted to SI
before calling CoolProp.

\subsection{Enthalpy grid and isenthalp presentation}

\LCPKeyDoc{luacoolprop/diagram/PT}{enthalpy unit}{kjkg, jkg, or si}{kjkg}
  {Sets the unit used by the grid and generated labels.}{jkg}
\LCPKeyAlias{luacoolprop/diagram/PT}{h unit}{enthalpy unit}
\LCPKeyDoc{luacoolprop/diagram/PT}{enthalpy min}{number or auto}{auto}
  {Sets the lower automatic-grid bound.}{200}
\LCPKeyDoc{luacoolprop/diagram/PT}{enthalpy max}{number or auto}{auto}
  {Sets the upper automatic-grid bound.}{450}
\LCPKeyDoc{luacoolprop/diagram/PT}{enthalpy step}{positive number or auto}{auto}
  {Sets the linear grid spacing.}{50}
\LCPKeyDoc{luacoolprop/diagram/PT}{enthalpy mode}{linear or list}{linear}
  {Selects generated values; an explicit value list implies list mode.}{linear}
\LCPKeyDoc{luacoolprop/diagram/PT}{enthalpy count}{positive integer}{8}
  {Sets the requested automatic count when no step is supplied.}{6}
\LCPKeyDoc{luacoolprop/diagram/PT}{enthalpy values}{numeric list}{empty}
  {Supplies an explicit grid in \texttt{enthalpy unit}.}{{200,300,400}}
\LCPKeyAlias{luacoolprop/diagram/PT}{h min}{enthalpy min}
\LCPKeyAlias{luacoolprop/diagram/PT}{h max}{enthalpy max}
\LCPKeyAlias{luacoolprop/diagram/PT}{h step}{enthalpy step}
\LCPKeyAlias{luacoolprop/diagram/PT}{h mode}{enthalpy mode}
\LCPKeyAlias{luacoolprop/diagram/PT}{h count}{enthalpy count}
\LCPKeyAlias{luacoolprop/diagram/PT}{h values}{enthalpy values}
\LCPKeyDoc{luacoolprop/diagram/PT}{isenthalp labels}{boolean or auto}{auto}
  {Overrides the shared \texttt{labels} switch for isenthalps.}{true}
\LCPKeyDoc{luacoolprop/diagram/PT}{isenthalp label pos}{fraction}{0.62}
  {Sets the preferred autonode arc-length position.}{0.7}
\LCPKeyDoc{luacoolprop/diagram/PT}{isenthalp label every}{positive integer}{2}
  {Labels one isenthalp out of every $n$.}{1}
\LCPKeyDoc{luacoolprop/diagram/PT}{isenthalp label sloped}{boolean or auto}{auto}
  {Overrides the common rotation policy.}{true}
\LCPKeyDoc{luacoolprop/diagram/PT}{isenthalp label allow upside down}{boolean or auto}{auto}
  {Overrides the common tangent-orientation policy.}{false}
\LCPKeyDoc{luacoolprop/diagram/PT}{isenthalp label style}{TikZ style}{luacoolprop isenthalp label node}
  {Selects the generated label-node style.}{luacoolprop isenthalp label node}
\LCPKeyDoc{luacoolprop/diagram/PT}{isenthalp label node style}{TikZ node options}{package style}
  {Redefines the PT isenthalp label style.}{{fill=red!8,text=red!70!black}}
\LCPKeyDoc{luacoolprop/diagram/PT}{isenthalp color}{colour}{red!65!black}
  {Sets the isenthalp colour.}{purple}
\LCPKeyDoc{luacoolprop/diagram/PT}{isenthalp style}{TikZ plot options}{thin, densely dashed}
  {Sets the isenthalp drawing style.}{{line width=.4pt,dashed}}

\subsection{Phase-envelope presentation and sampling}

\LCPKeyDoc{luacoolprop/diagram/PT}{phase envelope labels}{boolean or auto}{auto}
  {Overrides \texttt{labels} for the coexistence curve.}{true}
\LCPKeyDoc{luacoolprop/diagram/PT}{phase envelope label text}{TeX text}{liquid--vapour equilibrium}
  {Sets the coexistence-curve label.}{{saturation}}
\LCPKeyDoc{luacoolprop/diagram/PT}{phase envelope label pos}{fraction}{0.45}
  {Sets the preferred autonode position.}{0.6}
\LCPKeyDoc{luacoolprop/diagram/PT}{phase envelope label sloped}{boolean or auto}{auto}
  {Overrides label rotation.}{true}
\LCPKeyDoc{luacoolprop/diagram/PT}{phase envelope label allow upside down}{boolean or auto}{auto}
  {Overrides tangent orientation.}{false}
\LCPKeyDoc{luacoolprop/diagram/PT}{phase envelope label style}{TikZ style}{luacoolprop phase envelope label node}
  {Selects the label style.}{luacoolprop phase envelope label node}
\LCPKeyDoc{luacoolprop/diagram/PT}{phase envelope label node style}{TikZ node options}{package style}
  {Redefines the label-node style.}{{fill=blue!8,text=blue!70!black}}
\LCPKeyDoc{luacoolprop/diagram/PT}{phase envelope color}{colour}{blue!80!black}
  {Sets the coexistence-curve colour.}{black}
\LCPKeyDoc{luacoolprop/diagram/PT}{phase envelope style}{TikZ plot options}{line width=0.9pt}
  {Sets its drawing style.}{{very thick}}
\LCPKeyDoc{luacoolprop/diagram/PT}{phase envelope initial intervals}{positive integer}{20}
  {Sets the initial logarithmic-pressure subdivision.}{28}
\LCPKeyDoc{luacoolprop/diagram/PT}{phase envelope max depth}{nonnegative integer}{9}
  {Limits recursive adaptive refinement.}{10}
\LCPKeyDoc{luacoolprop/diagram/PT}{phase envelope tolerance}{positive number}{0.08}
  {Sets the midpoint error tolerance in PT display coordinates.}{0.04}

The coexistence sampler requires both limiting \texttt{P,Q=0} and
\texttt{P,Q=1} evaluations to be valid.  Near $p_c$ it performs an additional
adaptive pass in $\log_{10}((p_c-p)/p_c)$ before appending the exact critical
constant.  At the lower endpoint, a dimensionless pressure-offset bisection
guards against minute inconsistencies between a backend's exact $T_t$ constant
and its first saturation evaluations.  No fluid-specific cutoff is embedded
in the package.

\subsection{Shared styling, adaptive sampling, and stable names}

The shared controls \texttt{labels}, \texttt{label placement}, family-specific
isentrope/isochore label controls, autonode controls, \texttt{curve style},
\texttt{legend}, \texttt{forget plot}, per-curve overrides,
\texttt{coord digits}, and \texttt{axis options} behave exactly as documented
for the other projections.  PT additionally accepts:

\LCPKeyDoc{luacoolprop/diagram/PT}{initial intervals}{positive integer}{18}
  {Sets the common initial logarithmic-pressure subdivision.}{24}
\LCPKeyDoc{luacoolprop/diagram/PT}{max depth}{nonnegative integer}{8}
  {Limits common adaptive recursion.}{9}
\LCPKeyDoc{luacoolprop/diagram/PT}{tolerance}{positive number}{0.10}
  {Sets the common PT midpoint tolerance.}{0.05}
\LCPKeyDoc{luacoolprop/diagram/PT}{log weight}{nonnegative number}{30}
  {Weights logarithmic pressure in the midpoint metric.}{40}
\LCPKeyDoc{luacoolprop/diagram/PT}{domain policy}{ignore, warning, or error}{ignore}
  {Controls diagnostics for invalid CoolProp samples without reconnecting
   separate valid domains.}{warning}
\LCPKeyDoc{luacoolprop/diagram/PT}{isenthalp initial intervals}{positive integer}{18}
  {Overrides initial intervals for isenthalps.}{24}
\LCPKeyDoc{luacoolprop/diagram/PT}{isenthalp max depth}{nonnegative integer}{8}
  {Overrides recursion depth for isenthalps.}{9}
\LCPKeyDoc{luacoolprop/diagram/PT}{isenthalp tolerance}{positive number}{0.10}
  {Overrides the isenthalp midpoint tolerance.}{0.05}

Isentrope sampling can be overridden with \texttt{isentrope initial intervals},
\texttt{isentrope max depth}, and \texttt{isentrope tolerance}.  The analogous
\texttt{isochore ...} keys control isochores.  Curve identifiers are stable and
unit-aware: \texttt{lcp-pt-phase-envelope},
\texttt{lcp-pt-s-...}, \texttt{lcp-pt-h-...}, and
\texttt{lcp-pt-v-...}.  They work with \texttt{label ... for},
\texttt{curve style for}, and TikZ intersections.

\subsection{PT process projection and exports}

PT process options use \texttt{/luacoolprop/process/PT}.  All shared process
keys, strict quantity syntax, endpoint validation, styles, labels, markers,
sampling controls, named paths, and SI exports from the PH process reference
apply without reduction.

\LCPKeyDoc{luacoolprop/process/PT}{temperature axis unit}{kelvin or celsius}{global unit}
  {Couples process X coordinates to the PT axis; Celsius subtracts exactly
   273.15 from absolute temperature.}{celsius}
\LCPKeyDoc{luacoolprop/process/PT}{pressure axis unit}{pa, kpa, mpa, or bar}{global unit}
  {Couples process Y coordinates to the PT pressure axis.}{bar}
\LCPKeyDoc{luacoolprop/process/PT}{temperature scale}{number}{global scale}
  {Sets an advanced raw X-coordinate multiplier with zero offset.}{1}
\LCPKeyAlias{luacoolprop/process/PT}{t scale}{temperature scale}

With \texttt{export coordinates=StateAB},
\texttt{\string\StateAB FromX} is the scaled/offset temperature and
\texttt{\string\StateAB FromY} is scaled pressure.  The property exports
\texttt{FromTemperatureSI}, \texttt{FromPressureSI},
\texttt{FromEnthalpySI}, \texttt{FromEntropySI}, and
\texttt{FromSpecificVolumeSI} remain SI values.  Isobars and isotherms are
exact horizontal and vertical segments.  Isentropes, isenthalps, isochores,
and quality processes are adaptively sampled in logarithmic pressure.  A
quality process is valid, but every one of its points lies on the single
coexistence locus because PT cannot distinguish its quality value.

\subsection{Plain TeX and ConTeXt}

The PT implementation resides entirely in the generic layer.

\begin{LCPExample}{Plain LuaTeX PT diagram}
\input p-luacoolprop.tex
\pgfplotsset{compat=1.18}
\LCPPTDiagram[temperature axis unit=celsius,
  isentrope=true,entropy values={1.4,1.7,2.0}]
\bye
\end{LCPExample}

\begin{LCPExample}{ConTeXt MkIV PT diagram}
\usemodule[t][luacoolprop]
\pgfplotsset{compat=1.18}
\starttext
  \LCPPTDiagram[temperature axis unit=celsius,
    isenthalp=true,enthalpy values={200,300,400}]
\stoptext
\end{LCPExample}

Compile the first example with \texttt{luatex --shell-escape} and the second
with \texttt{context --luatex --shell-escape}.  ConTeXt's default LMTX engine
does not provide the LuaTeX FFI module.

\section{PGFPlots fluid style}

\begin{LCPKeyRef}{pgfplots}{luacoolprop fluid}{CoolProp identifier}{none}
Sets the global fluid while processing an axis option list.  This is useful when
the axis, rather than a LuaCoolProp command, owns document configuration.
\LCPKeyUse{pgfplots}{luacoolprop fluid}{Propane}
\end{LCPKeyRef}
\LCPKeyAlias{pgfplots}{lcp fluid}{luacoolprop fluid}

\begin{LCPExample}{Fluid selected by the PGFPlots axis}
\begin{axis}[luacoolprop fluid=Propane,ymode=log]
  \LCPAddPHQuality
\end{axis}
\end{LCPExample}
