diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml
new file mode 100644
index 000000000..a1adf4d19
--- /dev/null
+++ b/.github/workflows/codecov.yml
@@ -0,0 +1,21 @@
+name: Codecov
+on: [push, pull_request]
+jobs:
+ run:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Build and run the unit tests
+ run: |
+ cp config/coverage-gcc.mk config.mk
+ make serial
+ make
+ make unit
+ cd src
+ gcov -abcfu *.c
+ - name: Upload results
+ run: |
+ curl -Os https://uploader.codecov.io/latest/linux/codecov
+ chmod +x codecov
+ ./codecov -t ${CODECOV_TOKEN}
diff --git a/.github/workflows/regression.yml b/.github/workflows/regression.yml
new file mode 100644
index 000000000..598e9b9e2
--- /dev/null
+++ b/.github/workflows/regression.yml
@@ -0,0 +1,91 @@
+# Regression tests (serial)
+
+name: "Regression"
+
+on:
+ pull_request:
+ branches:
+ - master
+ - develop
+
+jobs:
+
+ d2q9:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ - name: Build
+ run: |
+ gcc --version
+ cp config/github-gcc.mk config.mk
+ sed -i "s/D3Q19/D2Q9/" config.mk
+ make serial
+ make -j 2
+
+ - name: Check
+ run: |
+ make unit
+ make -C tests d2q9
+
+ d3q15:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ - name: Build
+ run: |
+ gcc --version
+ cp config/github-gcc.mk config.mk
+ sed -i "s/D3Q19/D3Q15/" config.mk
+ make serial
+ make -j 2
+
+ - name: Check
+ run: |
+ make unit
+ make -C tests d3q15
+
+ make-d3q19-short:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ - name: Build
+ run: |
+ gcc --version
+ cp config/github-gcc.mk config.mk
+ make serial
+ make -j 2
+
+ # Some care may be required with threads
+ - name: Check
+ run: |
+ export OMP_NUM_THREADS=1
+ make test
+
+ d3q27:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ - name: Build
+ run: |
+ gcc --version
+ cp config/github-gcc.mk config.mk
+ sed -i "s/D3Q19/D3Q27/" config.mk
+ make serial
+ make -j 2
+
+ # No specific tests yet
+ - name: Check
+ run: |
+ make unit
diff --git a/.travis.yml b/.travis.yml
index 6958a8268..0c1fdeaf3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,12 +5,7 @@ cache:
before_install:
- bash ./config/build-mpi.sh
script:
- - cp config/travis-gcc.mk ./config.mk
- - make serial
- - make
- export OMP_NUM_THREADS=1
- - make test
- - make clean
- export PATH=$(pwd)/mpi/bin:${PATH}
- cp config/travis-mpicc.mk ./config.mk
- make
diff --git a/CHANGES.md b/CHANGES.md
index 6f04add58..c4db7f547 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,6 +1,20 @@
### Changes
+version 0.20.0
+
+- IMPORTANT: The input file can no longer be specified as a command
+ line argument. It must be called "input" in the current directory.
+- The electrokinetics sector has been updated and information is
+ available at
+ https://ludwig.epcc.ed.ac.uk/tutorials/electrokinetics/electrokinetics.html
+- A D3Q27 model is available
+- Added coverage via https://about.codecov.io/
+- The free energy is now reported at t = 0 for the initial state.
+- An extra "first touch" option has been added. For details, see
+ https://ludwig.epcc.ed.ac.uk/inputs/parallel.html
+- Various minor changes and code quality improvements.
+
version 0.19.1
- Fix bug in io_subfile to prevent failure at iogrid > 1.
diff --git a/README.md b/README.md
index 569fe8cd0..1d1eea409 100644
--- a/README.md
+++ b/README.md
@@ -44,10 +44,11 @@ $ make test
```
-Full details of the build process are available at
+Full details of the build process, and tutorials on how to
+use the code are available at
https://ludwig.epcc.ed.ac.uk/.
-#### Background and Tutorial
+#### Background
Background documentation on the LB model and various free energy choices
is available in the `docs` directory.
@@ -57,14 +58,6 @@ $ make
```
will produce a pdf version of the LaTeX source.
-A short tutorial, which includes some examples in which the
-results are visualised, is also provided:
-```
-$ cd docs/tutorial
-$ make
-```
-to produce a pdf of the tutorial instructions.
-
#### Contributing
If you would like to contribute, please consider a pull request.
diff --git a/config/coverage-gcc.mk b/config/coverage-gcc.mk
new file mode 100644
index 000000000..b8138f154
--- /dev/null
+++ b/config/coverage-gcc.mk
@@ -0,0 +1,26 @@
+##############################################################################
+#
+# coverage-gcc.mk
+#
+# One for coverage
+#
+##############################################################################
+
+BUILD = serial
+MODEL = -D_D3Q27_
+
+GCOV = -ftest-coverage -fprofile-arcs
+
+CC = gcc
+CFLAGS = -fopenmp $(GCOV) -O2 -g -Wall
+
+AR = ar
+ARFLAGS = -cru
+LDFLAGS = -fopenmp $(GCOV)
+
+MPI_INC_PATH = ./mpi_s
+MPI_LIB_PATH = ./mpi_s
+MPI_LIB = -lmpi
+
+LAUNCH_SERIAL_CMD =
+LAUNCH_MPIRUN_CMD =
diff --git a/config/github-gcc.mk b/config/github-gcc.mk
new file mode 100644
index 000000000..1e5f9d444
--- /dev/null
+++ b/config/github-gcc.mk
@@ -0,0 +1,22 @@
+##############################################################################
+#
+# github-gcc.mk
+#
+##############################################################################
+
+BUILD = serial
+MODEL = -D_D3Q19_
+
+CC = gcc -fopenmp
+CFLAGS = -g -Wall -O2
+
+AR = ar
+ARFLAGS = -cru
+LDFLAGS =
+
+MPI_INC_PATH = ./mpi_s
+MPI_LIB_PATH = ./mpi_s
+MPI_LIB = -lmpi
+
+LAUNCH_SERIAL_CMD =
+LAUNCH_MPIRUN_CMD =
diff --git a/docs/electrokinetic.tex b/docs/electrokinetic.tex
index bf5b41e9f..42bb0f1db 100644
--- a/docs/electrokinetic.tex
+++ b/docs/electrokinetic.tex
@@ -273,180 +273,6 @@ \subsubsection{Gouy-Chapman}
Debye length $l_D=3.514$, the surface potential $\Psi_D=2.267\e{-4}$
and the centre potential $\Psi_c=-3.395\e{-5}$.
-\subsubsection{Liquid-junction potential}
-
-The liquid junction potential
-is a charge separation process that
-occurs when electrolytes with slightly different concentrations
-whose species have different diffusivities are brought into contact.
-Charges from the regions of higher concentration diffuse
-into the parts with lower concentration. Due to the difference
-in diffusivity they migrate at different speeds, leaving parts of
-the system charged. This leads to a build-up of a potential
-which balances the diffusive flux.
-
-After the initial build-up phase the potential decreases slowly
-again until the charge concentration has become homogeneous throughout
-the system. Both timescales of emergence and decay of the potential
-can be separated by chosing a sufficiently large system size.
-
-This problem allowed us to verify the correct temporal
-behaviour of the Nernst-Planck equation solver by resolving the transient
-dynamics without having to account for advective terms.
-
-\begin{figure}[h!t]
-\includegraphics[width=0.495\textwidth]{./pics/test_lj_zoom1.pdf}
-\includegraphics[width=0.495\textwidth]{./pics/test_lj_zoom3.pdf}
-\caption{Time evolution of the liquid junction potential for $L_x=128$ (blue), $L_x=256$ (green) and $L_x=512$ (blue). The dashed black curves represent the approximate solution in the limit $l_D/L_x<<1$. Deviations can be seen which are presumably due
-to the approximate nature of the analytical solution and the fact that we
-have a different asymptotic flux close to the boundary - the theoretical
-analysis assumes no flux at a boundary which is infinitely far away from
-the diffusive region.}
-\label{fig3}
-\end{figure}
-
-For simplicity we considered systems of size
-$L_x\times L_y\times Lz=128\times4\times4$ and
-$L_x\times L_y\times Lz=256\times4\times4$ with
-periodic boundary conditions at either end.
-The two halfs were electroneutral and had ionic concentrations
-$\rho_{L,\pm}=\rho_{0,\pm} + \delta\rho$ and
-$\rho_{R,\pm}=\rho_{0,\pm} - \delta\rho$
-with $\rho_{0,\pm}=1\e{-2}$ and $\delta\rho = 0.01$.
-
-The potential difference between both sides during the build-up
-obeys approximately
-
-\begin{equation}
-\Delta\Psi(t)\simeq\Delta\Psi_P \left\{1-\exp\left(-\frac{t}{\tau_e}\right)\right\}\\
-\end{equation}
-
-with
-
-\begin{equation}
-\Delta\Psi_P=\frac{(D_+ D_-)}{\beta e (D_+ + D_-)} \frac{\delta\rho}{\rho_0}\\
-\end{equation}
-
-as saturation value of the potential difference.
-The saturation time scale is given by
-
-\begin{equation}
-\tau_e=\frac{\varepsilon}{\beta \, e^2 (D_+ + D_-) \rho_0}.
-\end{equation}
-
-\begin{figure}[htpb]
-\includegraphics[width=0.9\textwidth]{./pics/test_lj_decay1.pdf}
-\caption{Rescaled plot of the decay: Times have been Time evolution of the liquid junction potential for $L_x=128$ (blue), $L_x=256$ (green) and $L_x=512$ (blue). The dashed black curves represent the approximate solution in the limit $l_D/L_x<<1$. Deviations can be seen which are due
-to the approximate nature of the analytical solution and the diffusive fluxes close to the boundary.}
-\label{fig4}
-\end{figure}
-
-A more exact solution can be derived in the limit $l_D/L_x<<1, N\to\infty$:
-
-\begin{eqnarray}
-\Delta\Psi(t)&=&\Delta\Psi_P \left\{1-\exp\left(-\frac{t}{\tau_e}\right)\right\}\frac{4}{\pi}\left\{\sum_{m=1}^N \frac{\sin^3(m\pi/2)}{m} \exp\left(-\frac{ m^2\, t}{\tau_d}\right)\right\}\\
-\tau_d&=&\frac{L^2}{2\pi^2 (D_+ + D_-)}.\label{taud}
-\end{eqnarray}
-
-It contains as well the dependence on the decay timescale $\tau_d$.
-Only odd indices $m$ contribute to the sum:
-
-\begin{eqnarray}
-\sum_{m=1}^N \frac{\sin^3(m\pi/2)}{m} \exp\left(-\frac{m^2\, t}{\tau_d}\right)&=&\nonumber\\
-&&\hspace*{-4cm} \exp\left(-\frac{t}{\tau_d}\right)-\frac{1}{3} \exp\left(-\frac{9 t}{\tau_d}\right)+\frac{1}{5}\exp\left(-\frac{25t}{\tau_d}\right)-\frac{1}{9}\exp\left(-\frac{81 t}{\tau_d}\right)+\ldots
-\end{eqnarray}
-
-A complete discussion of the solution can be found in \cite{Mafe}.
-There, the upper limit of significant modes has been also estimated as $N_{max} = L/\pi l_D$.
-Note the factor 2 difference between Eq. \ref{taud} and the corresponding expression in \cite{Mafe}.
-
-The following parameters were used:
-dielectric permittivity $\epsilon=3.3\e{3}$, temperature $\beta^{-1}=3.333\e{-5}$, unit charge $e=1$, valency $z_\pm=\pm1$, diffusivities $D_+=0.0125$ and $D_-=0.0075$.
-We obtained
-$\Delta\Psi_P=1.6667\e{-7}$, $\tau_e=550$, $\tau_d=41501.2\, (L_x=128)$, $\tau_d=166004.6\, (L_x=256)$ and $\tau_d=664018.5 (L_x=512)$.
-The results for the potential difference over time are shown in Fig. \ref{fig3}.
-
-Fig. \ref{fig4} shows results with times rescaled to the decay
-time scale $\tau_d$ (cf. Eq. \ref{taud}). Obviously the
-deviations we observe are not due to the limited system size
-and have a more systematic origin.
-
-The curves coincide if
-the theoretic limit for $\tau_d$ is rescaled by a factor $1.067$,
-suggesting the effective system length for this sort of setup is
-actually about 3\% larger than the numerical value.
-
-A reason for this might be the approximate nature of the analytical solution
-and the fact that it was gained
-for an infinitely large system with constant charge concentrations,
-vanishing currents at both ends and finite diffusive zone of size $L_x$.
-In our situation the entire system is within the diffusive zone.
-This may lead to smaller effective diffusivities or larger effective
-system sizes.
-Interestingly, all runs with solid walls at both ends resulted in
-oscillatory behaviour and an effective system size of $2L_x$.
-
-
-\subsubsection{Electroosmotic Flow}
-
-To test the implementation with all couplings to external and
-internal forces we consider a forced charged fluid in a slit
-of size $L_z$. An electrostatic field $E_{||}$ is allied
-parallel to the walls. The entire system is electroneutral with
-each wall having the surface charge density $\sigma$
-and compensationg counterions with total charge $2 \sigma A_{wall}$
-in the fluid.
-
-In equilibrium the charge density at a distance $x$ from the wall obeys
-
-\begin{equation}
-\rho(x)=\frac{\rho_0}{\cos^2(K\,x)}
-\end{equation}
-
-with
-
-\begin{equation}
-\rho_0=K^2/2\pi l_B
-\end{equation}
-
-and
-
-\begin{eqnarray}
-K \,L_x \tan\left(\frac{K\, L_x}{2}\right)&=&\pi\, l_B\, L_x\, 2\sigma\label{kex} \\
-K \,L_x&\simeq&\sqrt{4\pi \,l_B\,L_x\,2\sigma}\label{klin}.
-\end{eqnarray}
-
-
-The liniarised version Eq. \ref{klin} has only a limited range of applicabilty.
-We solved Eq. \ref{kex} numerically and found solutions
-$K=0.01959\; (\sigma=0.003125)$ and $K=0.03311\; (\sigma=0.00125)$,
-which is reasonably far away from the
-theoretical limit $K_{max}=\pi/L_x$ set by the tangent.
-
-Note the factor 2 difference on the lhs of Eq. \ref{kex} with respect
-to \cite{Capuani, Rotenberg}. There is also a factor $L_x$ missing on
-the rhs of Eq. \ref{klin}.
-
-The steady state velocity of the fluid can be derived from the
-force balance of the gradient of the stresses and the electrostatic
-forces:
-
-\begin{eqnarray}
-v_y(x)&=&\hat{v} \ln\left(\frac{\cos(K\,x)}{\cos(K\,L_x/2)}\right)\label{vy}\\
-\hat{v}&=&\frac{e \,E_{||}\rho_o}{\eta\, K^2}=\frac{e \,E_{||}}{2\pi\eta l_B}\label{vhat}
-\end{eqnarray}
-
-The result for two different charge densities is shown in Fig. \ref{fig6}.
-The accuracy is acceptable with deviations for high surface
-charged potentially being caused by the chosen discretisation or
-by the numerical solution of Eq. \ref{kex} approaching the limit
-of $\pi/L_z\simeq0.049$.
-
-\begin{figure}[htpb]
-\includegraphics[width=0.9\textwidth]{./pics/test_eo.pdf}
-\caption{Steady state flow profile across a slit of width $L_x=63$ for an applied field of magnitude $e \beta E L_x=1.89$ for two different charge densities $\sigma=0.003125$ (red) and $\sigma=0.0125$ (blue), Bjerrum length $l_B=0.7234$, viscosity $\eta=0.1$ and unit charge $e=1$. The dashed black lines correspond to theoretical prediction according to Eqs. \ref{vy} and \ref{vhat}.}
-\label{fig6}
-\end{figure}
\subsubsection{Debye-H\"uckel Theory}
diff --git a/docs/input.tex b/docs/input.tex
index 49a913135..17d193d23 100644
--- a/docs/input.tex
+++ b/docs/input.tex
@@ -13,785 +13,8 @@
\section{The Input File}
-\subsection{General}
-
-By default, the run time expects to find user input in a file
-\texttt{input} in the current working directory. If a different
-file name is required, its name
-should be provided as the sole command line argument, e.g.,
-\begin{lstlisting}
-./Ludwig.exe input_file_name
-\end{lstlisting}
-If the input file is not located in the current working directory
-the code will terminate immediately with an error message.
-
-When an input file is located, its content is read by a single MPI
-task, and its contents then broadcast to all MPI relevant tasks.
-The format of the file is plain ASCII text, and its contents are
-parsed on a line by line basis. Lines may contain the following:
-\begin{itemize}
-\item comments introduced by \texttt{\#}.
-\item key value pairs separated by white space.
-\end{itemize}
-Blank lines are treated as comments. The behaviour of the code is
-determined by a set of key value pairs. Any given key may appear
-only once in the input file; unused key value pairs are not reported.
-If the key value pairs are not correctly formed, the code will terminate
-with an error message and indicate the offending input line.
-
-Key value pairs may be present in the input file, but have no effect for
-any given run: they are merely ignored. Relevant control parameters for
-given input are reported in the standard output.
-
-\subsubsection{Key value pairs}
-
-Key value pairs are made up of a key --- an alphanumeric string with no
-white space --- and corresponding value following white space. Values
-may take on the follow forms:
-\begin{lstlisting}
-key_string value_string
-
-key_integer_scalar 1
-key_integer_vector 1_2_3
-
-key_double_scalar 1.0
-key_double_vector 1.0_2.0_3.0
-\end{lstlisting}
-Values which are strings should contain no white space. Scalar parameters
-may be integer values, or floating point values with a decimal point
-(scientific notation is also allowed). Vector parameters are introduced
-by a set of three values (to be interpreted as $x,y,z$ components of the
-vector in Cartesian coordinates) separated by an underscore. The identity
-of the key will specify what type of value is expected. Keys and (string)
-values are case sensitive.
-
-
-Most keys have an associated default value which will be used if
-the key is not present. Some keys must be specified: an error will
-occur if they are missing. The remainder of this part
-of the guide details the various choices for key value pairs,
-along with any default values, and any relevant constraints.
-
-\subsection{The Free Energy}
-\label{input-free-energy}
-
-The choice of free energy is determined as follows:
-\begin{lstlisting}
-free_energy none
-\end{lstlisting}
-The default value is \texttt{none}, i.e., a simple Newtonian fluid is used.
-Possible values of the \texttt{free\_energy} key are:
-\begin{lstlisting}
-# none Newtonian fluid [DEFAULT]
-# symmetric Symmetric binary fluid (finite difference)
-# symmetric_lb Symmetric binary fluid (two distributions)
-# brazovskii Brazovskii smectics
-# surfactant Surfactants
-# polar_active Polar active gels
-# lc_blue_phase Liquid crystal (nematics, cholesterics, BPs)
-# lc_droplet Liquid crystal emulsions
-# fe_electro Single fluid electrokinetics
-# fe_electro_symmetric Binary fluid electrokinetics
-\end{lstlisting}
-
-The choice of free energy will control automatically a number of factors
-related to choice of order parameter, the degree of parallel communication
-required, and so on. Each free energy has a number of associated parameters
-discussed in the following sections.
-
-Details of general (Newtonian) fluid parameters, such as viscosity,
-are discussed in Section~\ref{input-fluid-parameters}.
-
-\subsubsection{Symmetric Binary Fluids}
-
-We recall that the free energy density is, as a function of compositional
-order $\phi$:
-\[
-{\textstyle \frac{1}{2}} A\phi^2 +
-{\textstyle \frac{1}{4}} B\phi^4 +
-{\textstyle \frac{1}{2}} \kappa (\mathbf{\nabla}\phi)^2.
-\]
-
-Parameters are introduced by (with default values):
-\begin{lstlisting}
-free_energy symmetric
-A -0.0625 # Default: -0.003125
-B +0.0625 # Default: +0.003125
-K +0.04 # Default: +0.002
-\end{lstlisting}
-Common usage has $A < 0$ and $B = -A$ so that $\phi^\star = \pm 1$.
-The parameter $\kappa$
-(key \texttt{K}) controls
-the interfacial energy penalty and is usually positive.
-
-\subsubsection{Brazovskii smectics}
-\label{input-brazovskki-smectics}
-The free energy density is:
-\[
-{\textstyle \frac{1}{2}} A\phi^2 +
-{\textstyle \frac{1}{4}} B\phi^4 +
-{\textstyle \frac{1}{2}} \kappa (\mathbf{\nabla}\phi)^2 +
-{\textstyle \frac{1}{2}} C (\nabla^2 \phi)^2
-\]
-
-Parameters are introduced via the keys:
-\begin{lstlisting}
-free_energy brazovskii
-A -0.0005 # Default: 0.0
-B +0.0005 # Default: 0.0
-K -0.0006 # Default: 0.0
-C +0.00076 # Default: 0.0
-\end{lstlisting}
-For $A<0$, phase separation occurs with a result depending on $\kappa$:
-one gets two symmetric phases for $\kappa >0$ (cf.\ the symmetric case)
-or a lamellar phase for $\kappa < 0$. Typically, $B = -A$ and the
-parameter in the highest derivative $C > 0$.
-
-\subsubsection{Surfactants}
-\label{input-surfactants}
-
-The surfactant free energy should not be used at the present time.
-
-\subsubsection{Polar active gels}
-\label{input-polar-active-gels}
-
-The free energy density is a function of vector order parameter $P_\alpha$:
-\[
-{\textstyle \frac{1}{2}} A P_\alpha P_\alpha +
-{\textstyle \frac{1}{4}} B (P_\alpha P_\alpha)^2 +
-{\textstyle \frac{1}{2}} \kappa (\partial_\alpha P_\beta)^2
-\]
-
-There are no default parameters:
-\begin{lstlisting}
-free_energy polar_active
-polar_active_a -0.1 # Default: 0.0
-polar_active_b +0.1 # Default: 0.0
-polar_active_k 0.01 # Default: 0.0
-\end{lstlisting}
-It is usual to choose $B > 0$, in which case $A > 0$ gives
-an isotropic phase, whereas $A < 0$ gives a polar nematic phase.
-The elastic constant $\kappa$ (key \texttt{polar\_active\_k})
-is positive.
-
-\subsubsection{Liquid crystal}
-\label{input-liquid-crystal}
-The free energy density is a function of tensor order parameter
-$Q_{\alpha\beta}$:
-\begin{eqnarray}
-{\textstyle\frac{1}{2}} A_0 (1 - \gamma/3)Q^2_{\alpha\beta} -
-{\textstyle\frac{1}{3}} A_0 \gamma
- Q_{\alpha\beta}Q_{\beta\delta}Q_{\delta\alpha} +
-{\textstyle\frac{1}{4}} A_0 \gamma (Q^2_{\alpha\beta})^2
-\nonumber \\
-+ {\textstyle\frac{1}{2}} \Big(
-\kappa_0 (\epsilon_{\alpha\delta\sigma} \partial_\delta Q_{\sigma\beta} +
-2q_0 Q_{\alpha\beta})^2 + \kappa_1(\partial_\alpha Q_{\alpha\beta})^2 \Big)
-\nonumber
-\end{eqnarray}
-
-The corresponding \texttt{free\_energy} value, despite its name, is
-suitable for nematics and cholesterics, and not just blue phases:
-\begin{lstlisting}
-free_energy lc_blue_phase
-lc_a0 0.01 # Deafult: 0.0
-lc_gamma 3.0 # Default: 0.0
-lc_q0 0.19635 # Default: 0.0
-lc_kappa0 0.00648456 # Default: 0.0
-lc_kappa1 0.00648456 # Default: 0.0
-\end{lstlisting}
-The bulk free energy parameter $A_0$ is positive and controls the
-energy scale (key \texttt{lc\_a0}); $\gamma$ is positive and
-influences the position in the phase diagram relative to the
-isotropic/nematic transition (key \texttt{lc\_gamma}).
-The two elastic constants must be equal, i.e., we enforce the
-single elastic constant approximation (both keys \texttt{lc\_kappa0} and
-\texttt{lc\_kappa1} must be specified).
-
-Other important parameters in the liquid crystal picture are:
-\begin{lstlisting}
-lc_xi 0.7 # Default: 0.0
-lc_Gamma 0.5 # Default: 0.0
-lc_active_zeta 0.0 # Default: 0.0
-\end{lstlisting}
-The first is $\xi$ (key \texttt{lc\_xi}) is the effective molecular
-aspect ratio and should be in the range $0< \xi< 1$. The rotational
-diffusion constant is $\Gamma$ (key \texttt{lc\_Gamma}; not to be
-confused with \texttt{lc\_gamma}). The (optional) apolar activity
-parameter is $\zeta$ (key \texttt{lc\_active\_zeta}).
-
-\subsubsection{Liquid crystal anchoring}
-
-Different types of anchoring are available at solid surfaces, with
-one or two related free energy parameters depending on the type.
-The type of anchoring may be set independently for stationary
-boundaries (walls) and colloids.
-\begin{lstlisting}
-lc_anchoring_strength 0.01 # free energy parameter w1
-lc_anchoring_strength_2 0.0 # free energy parameter w2
-lc_wall_anchoring normal # ``normal'' or ``planar''
-lc_coll_anchoring normal # ``normal'' or ``planar''
-\end{lstlisting}
-See section \ref{section-lc-anchoring} for details of surface anchoring.
-
-\subsubsection{Liquid crystal emulsion}
-\label{input-liquid-crystal-emulsion}
-
-This an interaction free energy which combines the symmetric and liquid
-crystal free energies. The liquid crystal free energy constant $\gamma$
-becomes a
-function of composition via $\gamma(\phi) = \gamma_0 + \delta(1 + \phi)$,
-and a coupling term is added to the free energy density:
-\[
-WQ_{\alpha\beta} \partial_\alpha \phi \partial_\beta \phi.
-\]
-Typically, we might choose $\gamma_0$ and $\delta$ so that
-$\gamma(-\phi^\star) < 2.7$ and the $-\phi^\star$ phase is isotropic,
-while $\gamma(+\phi^\star) > 2.7$ and the
-$+\phi^\star$ phase is ordered (nematic, cholesteric, or blue phase).
-Experience suggests that a suitable choice is $\gamma_0 = 2.5$ and
-$\delta = 0.25$.
-
-For anchoring constant $W > 0$, the liquid crystal anchoring at the
-interface is planar, while for $W < 0$ the anchoring is normal. This
-is set via key \texttt{lc\_droplet\_W}.
-
-Relevant keys (with default values) are:
-\begin{lstlisting}
-free_energy lc_droplet
-
-A -0.0625
-B +0.0625
-K +0.053
-
-lc_a0 0.1
-lc_q0 0.19635
-lc_kappa0 0.007
-lc_kappa1 0.007
-
-lc_droplet_gamma 2.586 # Default: 0.0
-lc_droplet_delta 0.25 # Default: 0.0
-lc_droplet_W -0.05 # Default: 0.0
-\end{lstlisting}
-Note that key \texttt{lc\_gamma} is not set in this case.
-
-\subsection{System Parameters}
-\label{input-system-parameters}
-
-Basic parameters controlling the number of time steps
-and the system size are:
-\begin{lstlisting}
-N_start 0 # Default: 0
-N_cycles 100 # Default: 0
-size 128_128_1 # Default: 64_64_64
-\end{lstlisting}
-A typical simulation will start from time zero (key \texttt{N\_start})
-and run for a certain number of time steps (key \texttt{N\_cycles}).
-The system size (key \texttt{size}) specifies the total number of
-lattice sites in each dimension. If a two-dimensional system is
-required, the extent in the $z$-direction must be set to unity, as
-in the above example.
-
-If a restart from a previous run is required, the choice of parameters
-may be as follows:
-\begin{lstlisting}
-N_start 100
-N_cycles 400
-\end{lstlisting}
-This will restart from data previously saved at time step 100, and
-run a further 400 cycles, i.e., to time step 500.
-% TODO Cross-reference to I/O.
-
-\subsubsection{Parallel decomposition}
-
-In parallel, the domain decomposition is closely related to the
-system size, and is specified as follows:
-\begin{lstlisting}
-size 64_64_64
-grid 4_2_1
-\end{lstlisting}
-The \texttt{grid} key specifies the number of MPI tasks required in
-each coordinate direction. In the above example, the decomposition
-is into 4 in the $x$-direction, into 2 in the $y$-direction, while
-the $z$-direction is not decomposed. In this example, the local domain
-size per MPI
-task would then be $16\times32\times64$. The total number of MPI tasks
-available must match the total implied by \texttt{grid} (8 in the
-example).
-
-The \texttt{grid} specifications must exactly divide the system size;
-if no decomposition is possible, the code will terminate with an error
-message.
-If the requested decomposition is not valid, or \texttt{grid} is
-omitted, the code will try to supply a decomposition based on
-the number of MPI tasks available and \texttt{MPI\_Dims\_create()};
-this may be implementation dependent.
-
-
-\subsection{Fluid Parameters}
-\label{input-fluid-parameters}
-
-Control parameters for a Newtonian fluid include:
-\begin{lstlisting}
-fluid_rho0 1.0
-viscosity 0.166666666666666
-viscosity_bulk 0.166666666666666
-isothermal_fluctuations off
-temperature 0.0
-\end{lstlisting}
-The mean fluid density is $\rho_0$ (key \texttt{fluid\_rho0}) which
-defaults to unity in lattice units; it is not usually necessary to
-change this. The shear viscosity is
-\texttt{viscosity} and as default value 1/6 to correspond to
-unit relaxation time in the lattice Boltzmann picture. Reasonable
-values of the shear viscosity are $0.2 > \eta > 0.0001$ in lattice
-units. Higher values move further into the over-relaxation region, and can
-result in poor behaviour. Lower
-values increase the Reynolds number and tend to cause
-problems with stability. The bulk
-viscosity has a default value which is equal to whatever shear
-viscosity has been selected. Higher values of the bulk viscosity
-may be set independently and can help to suppress large deviations
-from incompressibility and maintain numerical stability
-in certain situations.
-
-If fluctuating hydrodynamics is wanted, set the value of
- \texttt{isothermal\_fluctuations} to \texttt{on}. The associated
-temperature is in lattice units: reasonable values (at $\rho_0 = 1$)
-are $0 < kT < 0.0001$. If the temperature is too high, local
-velocities will rapidly exceed the Mach number constraint and
-the simulation will be unstable.
-
-\subsection{Lees Edwards Planes}
-
-Constant uniform shear may be introduced via a number of Lees Edwards
-planes with given speed. This is appropriate for fluid-only
-systems with periodic boundaries.
-\begin{lstlisting}
-N_LE_plane 2 # Number of planes (default: 0)
-LE_plane_vel 0.05 # Constant plane speed
-\end{lstlisting}
-The placing of the planes in the system is as follows.
-The number of planes $N$ must
-divide evenly the lattice size in the $x$-direction to give an integer
-$\delta x$. Planes are then placed at $\delta x / 2, 3\delta x/2, \ldots$.
-All planes have the same, constant, velocity jump associated with them:
-this is positive in the positive $x$-direction. (This jump is usually
-referred to as the plane speed.) The uniform shear rate
-will be $\dot{\gamma} = N U_{LE} / L_x$ where $U_{LE}$ is the plane
-speed (which is always in the $y$-direction).
-
-The velocity gradient or shear direction is $x$, the flow
-direction is $y$ and the vorticity direction is $z$.
-
-The spacing between planes must not be less than twice the halo size
-in lattice units; 8--16 lattice units may be the practical limit in
-many cases. In additional, the speed of the planes must not cause a
-violation of the
-Mach number constraint in the fluid velocity on the lattice, which
-will match the plane speed in magnitude directly either side of the
-planes. A value of around 0.05 should be regarded as a maximum safe
-limit for practical purposes.
-
-Additional keys associated with the Lees Edwards planes are:
-\begin{lstlisting}
-LE_init_profile 1 # Initialise u(x) (off/on)
-LE_time_offset 10000 # Offset time (default 0)
-\end{lstlisting}
-If \texttt{LE\_init\_profile} is set, the fluid velocity is initialised
-to reflect a steady state shear flow appropriate for the number of
-planes at the given speed (ie., shear rate). If set to zero (the default),
-the fluid is initialised with zero velocity.
-
-The code works out the current displacement of the planes by computing
-$U_{LE} t$, where $t$ is the current time step. A shear run should then
-start from $t = 0$, i.e. zero plane displacement.
-It is often convenient to run an equilibration with no shear, and
-then to start an experiment after some number of steps. This
-key allows you to offset the start of the Lees-Edwards motion.
-It should then take the value of the start time (in time steps)
-corresponding to the restart at the end of the equilibration
-period.
-
-There are a couple of additional constraints to use the Lees-Edwards
-planes in parallel. In particular, the planes cannot fall at a
-processor boundary in the $x$-direction. This means you should
-arrange an integer number of planes per process in the $x$-direction.
-(For example, use one plane per process; this will also ensure the number
-of planes
-still evenly divides the total system size.)
-This will interleave the planes with the processor decomposition.
-The $y$-direction and $z$-direction may be decomposed without
-further constraint.
-
-Note that this means a simulation with one plane will only work
-if there is one process in the $x$ decomposition.
-
-
-
-\subsection{Colloids}
-If no relevant key words are present, no colloids will be
-expected at run time. The simulation will progress in the
-usual fashion with fluid only.
-
-If colloids are required, the \texttt{colloid\_init}
-key word must be present to allow the code to determine where
-colloid information will come from. The options for the
-\texttt{colloid\_init} key word are summarised below:
-\begin{lstlisting}
-colloid_init none
-
-# none no colloids [DEFAULT]
-# input_one one colloid from input file
-# input_two two colloids from input file
-# input_three three colloids from input file
-# input_random Small number at random
-# from_file Read a separate file (including all restarts)
-\end{lstlisting}
-
-For idealised simulations which require 1, 2, or 3 colloids, relevant
-initial state information
-for each particle can be included in the input file. In principle, most
-of the colloid state as defined in the colloid
-state structure in \texttt{colloid.h} may be specified. (Some state is
-reserved for internal use only and cannot be set from the input file.)
-Furthermore, not all the state is relevant in all simulations ---
-quantities such as charge and wetting parameters may not be required,
-in which case they a simply ignored.
-
-A minimal initialisation is shown in the following example:
-\begin{lstlisting}
-colloid_init input_one
-
-colloid_one_a0 1.25
-colloid_one_ah 1.25
-colloid_one_r 12.0_12.0_12.0
-\end{lstlisting}
-This initialises a single colloid with an input radius $a_0=1.25$,
-and a hydrodynamic radius $a_h=1.25$; in general both are required,
-but they do not have to be equal.
-A valid position is required within the extent of the system
-$0.5 < x,y,z < L + 0.5$ as specified by the \texttt{size} key word.
-State which is not explicitly defined is initialised to zero.
-
-\subsubsection{General Initialisation}
-
-A full list of colloid state-related key words is as follows. All
-the quantities are floating point numbers unless explicitly stated
-to be otherwise:
-\begin{lstlisting}
-# colloid_one_nbonds (integer) number of bonds
-# colloid_one_bond1 (integer) index of bond partner 1
-# colloid_one_bond2 (integer) index of bond partner 2
-# colloid_one_isfixedr colloid has fixed position (integer 0 or 1)
-# colloid_one_isfixedv colloid has fixed velocity (integer 0 or 1)
-# colloid_one_isfixedw colloid has fixed angular velocity (0 or 1)
-# colloid_one_isfixeds colloid has fixed spin (0 or 1)
-# colloid_one_type ``default'' COLLOID_TYPE_DEFAULT
-# ``active'' COLLOID_TYPE_ACTIVE
-# ``subgrid'' COLLOID_TYPE_SUBGRID
-# colloid_one_a0 input radius
-# colloid_one_ah hydrodynamic radius
-# colloid_one_r position vector
-# colloid_one_v velocity (vector)
-# colloid_one_w angular velocity (vector)
-# colloid_one_s spin (unit vector)
-# colloid_one_m direction of motion (unit) vector for swimmers
-\end{lstlisting}
-
-Note that for magnetic particles, the appropriate initialisation involves
-the spin key word \texttt{colloid\_one\_s} which relates to the dipole
-moment $\mu \mathbf{s}_i$, while \texttt{colloid\_one\_m} relates to the
-direction of motion vector. Do not confuse the two.
-It is possible in principle to have magnetic active particles,
-in which case the dipole direction or spin ($\mathbf{s}_i$) and the
-direction of swimming motion $\mathbf{m}_i$ are allowed to be distinct.
-
-\begin{lstlisting}
-# colloid_one_b1 Squirmer parameter B_1
-# colloid_one_b2 Squirmer parameter B_2
-# colloid_one_rng (integer) random number generator state
-# colloid_one_q0 charge (charge species 0)
-# colloid_one_q1 charge (charge species 1)
-# colloid_one_epsilon Permeativity
-# colloid_one_c Wetting parameter C
-# colloid_one_h Wetting parameter H
-\end{lstlisting}
-
-{\bf Example}: Single active (squirmer) particle
-
-The following example shows a single active particle with initial
-swimming direction along the $x$-axis.
-\begin{lstlisting}
-colloid_init input_one
-
-colloid_one_type active
-colloid_one_a0 7.25
-colloid_one_ah 7.25
-colloid_one_r 32.0_32.0_32.0
-colloid_one_v 0.0_0.0_0.0
-colloid_one_m 1.0_0.0_0.0
-colloid_one_b1 0.05
-colloid_one_b2 0.05
-\end{lstlisting}
-
-
-
-\subsubsection{Random initialisation}
-
-For suspensions with more than few colloids, but still at
-relatively low volume fraction (10--20\% by volume), it is
-possible to request initialisation at random positions.
-
-The additional key word value pair \texttt{colloid\_random\_no}
-determines the total number of particles to be placed in
-the system. To prevent particles being initialised very
-close together, which can cause problems in the first few
-time steps if strong potential interactions are present,
-a ``grace'' distance or minimum surface-surface separation
-may also be specified (\texttt{colloid\_random\_dh}).
-
-The following example asks for 100 colloids to be initialised
-at random positions, with a minimum separation of 0.5 lattice
-spacing.
-
-\begin{lstlisting}
-colloid_init input_random
-
-colloid_random_no 100 # Total number of colloids
-colloid_random_dh 0.5 # ``Grace'' distance
-
-colloid_random_a0 2.30
-colloid_random_ah 2.40
-\end{lstlisting}
-
-An input radius and hydrodynamic radius must be provided: these
-are the same for all colloids.
-If specific initialisations of the colloid state (excepting the
-position) other than the radii are wanted, values should be provided
-as for the single particle case in the preceding section, but using
-\texttt{colloid\_random\_a0} in place of
-\texttt{colloid\_one\_a0} and so on.
-
-The code will try to initialise the requested number in the current
-system size, but only makes a finite number of attempts to place
-particles at random with no overlaps. (The initialisation will also
-take into account the presence of any solid walls, using the same
-grace distance.) If the the number of particles is too large, the
-code will halt with a message to that effect.
-
-In general, colloid information for a arbitrary configuration with many
-particles should be read from a pre-prepared file. See the section on
-File I/O for further information on reading files.
-
-
-\subsubsection{Interactions}
-
-Note that two-body pair-potential interactions are defined uniformly for
-all colloids in a simulation. The same is true for lubrication corrections.
-There are a number of constraints related to the computation of
-interactions discussed below.
-
-{\bf Boundary-colloid lubrication correction}.
-Lubrication corrections (here the normal force) between a flat wall
-(see section XREF) are
-required to prevent overlap between colloid and the wall.
-The cutoff distance is set via the key word value pair
-\begin{lstlisting}
-boundary_lubrication_rcnormal 0.5
-\end{lstlisting}
-It is recommended that this is used in all cases involving walls.
-A reasonable value is in the range $0.1 < r_c < 0.5$ in lattice
-units, and should be calibrated for particle hydrodynamic radius
-and fluid viscosity if exact results are important.
-
-{\bf Colloid-colloid lubrication corrections}.
-The key words to activate the calculation of lubrication corrections
-are:
-\begin{lstlisting}
-lubrication_on 1
-lubrication_normal_cutoff 0.5
-lubrication_tangential_cutoff 0.05
-\end{lstlisting}
-
-
-
-{\bf Soft sphere potential}.
-A cut-and-shifted soft-sphere potential of the form
-$v \sim \epsilon (\sigma/r)^\nu$ is
-available. Some trial-and-error with the parameters may be required in
-any given situation to ensure simulation stability in the long run. The
-following gives an example of the relevant input key words:
-\begin{lstlisting}
-soft_sphere_on 1 # integer 0/1 for off/on
-soft_sphere_epsilon 0.0004 # energy units
-soft_sphere_sigma 1.0 # a length
-soft_sphere_nu 1.0 # exponent is positive
-soft_sphere_cutoff 2.25 # a surface-surface separation
-\end{lstlisting}
-See Section~\ref{section-colloids-soft-sphere} for a detailed description.
-
-{\bf Lennard-Jones potential}.
-The Lennard-Jones potential (Section~\ref{section-colloids-lennard-jones})
-is controlled by the following key words:
-\begin{lstlisting}
-lennard_jones_on 1 # integer 0/1 off/on
-lj_epsilon 0.1 # energy units
-lj_sigma 2.6 # potential length scale
-lj_cutoff 8.0 # a centre-centre separation
-\end{lstlisting}
-
-
-{\bf Yukawa potential}.
-A cut-and-shifted Yukawa potential of the form
-$v \sim \epsilon \exp(-\kappa r)/r$ is
-available using the following key word value pairs:
-
-\begin{lstlisting}
-yukawa_on 1 # integer 0/1 off/on
-yukawa_epsilon 1.330 # energy units
-yukawa_kappa 0.725 # an inverse length
-yukawa_cutoff 16.0 # a centre-centre cutoff
-\end{lstlisting}
-
-{\bf Dipole-dipole interactions (Ewald sum)}.
-The Ewald sum is completely specified in the input file
-by the uniform dipole strength $\mu$ and the real-space cut off $r_c$.
-\begin{lstlisting}
-ewald_sum 1 # integer 0/1 off/on
-ewald_mu 0.285 # dipole strength mu
-ewald_rc 16.0 # real space cut off
-\end{lstlisting}
-
-
-If short range interactions are required, particle information is stored
-in a cell list, which allows efficient computation of the potentially
-$N^2$ interactions present. This gives rise to a constraint that the
-width of the cells must be large enough that all relevant interactions
-are included. This generally means that the cells must be at least
-$2a_h + h_c$ where $h_c$ is the largest relevant cut off distance.
-
-The requirement for at least two cells per local domain in parallel
-means that there is a associated minimum local domain size. This is
-computed at run time on the basis of the input. If the local domain
-is too small, the code will terminate with an error message. The
-local domain size should be increased.
-
-
-\subsubsection{External forces}
-
-{\bf External body force (gravity)}.
-The following example requests a uniform body force in the negative
-$z$-direction on all particles.
-\begin{lstlisting}
-colloid_gravity 0.0_0.0_-0.001 # vector
-\end{lstlisting}
-The counterbalancing body force on the fluid which enforces the
-constraint of momentum conservation for the system as a whole is
-computed automatically by the code at each time step.
-
-
-\subsection{Order parameter initialisations}
-
-Free energy choices requiring one or more fluid order parameters can make
-use of the following initial coniditions.
-
-\subsubsection{Composition $\phi$}
-
-The following initialisations are available.
-\begin{lstlisting}
-phi_initialisation spinodal # spinodal
-phi0 0.0 # mean
-noise 0.05 # noise amplitude
-random_seed 102839 # +ve integer
-\end{lstlisting}
-Suitable for initialising isothermal spinodal decomposition, the order
-parameter may be set at random at each position via
-$\phi = \phi_0 + A(\hat{\phi} - 1/2)$ with the random variate
-$\hat\phi$ selected uniformly on the interval $[0,1)$. For symmetric
-quenches (mean order parameter $\phi_0 = 0$ and $\phi^\star = \pm 1$),
-a value of $A$ in the range 0.05-0.1 is usually appropriate.
-
-For off-symmetric quenches, larger patches of fluid may be required to
-initiate decomposition:
-\begin{lstlisting}
-phi_initialisation patches # patches of phi = +/- 1
-phi_init_patch_size 2 # patch size
-phi_init_patch_vol 0.1 # volume fraction phi = -1 phase
-random_seed 13 # +ve integer
-\end{lstlisting}
-The initialises cubics patches of fluid of given size with $\phi= \pm 1$
-at random. The requested overall volume fractions may be met approximately.
-
-A spherical drop can be initialised at the centre of the system.
-\begin{lstlisting}
-phi_initialisation drop # spherical droplet
-phi_init_drop_radius 16.0 # radius
-phi_init_drop_amplitude -1.0 # phi value inside
-\end{lstlisting}
-The drop is initialised with a $\tanh(r/\xi)$ profile where the
-interfacial width $\xi$ is computed via the current free energy
-parameters.
-
-% block
-% bath
-
-For restarted simulations, the default position is to read order
-parameter information from file
-\begin{lstlisting}
-phi_initialisation from_file
-\end{lstlisting}
-in which case a file or files for the appropriate time step should
-be present in the working directory.
-
-
-\subsubsection{Tensor order $Q_{\alpha\beta}$}
-
-A number of different initialisations are available for the liquid
-crystal order parameter $Q_{\alpha\beta}$. Some care may be required
-to ensure consistency between the choice and the free energy
-parameters, the system size, and so on (particularly for the blue phases).
-
-A summmary of choices is:
-\begin{lstlisting}
-lc_q_initialisation nematic # uniform nematic...
-lc_init_nematic 1.0_0.0_0.0 # ...with given director
-
-lc_q_initialisation cholesteric_x # cholesteric with helical axis x
-lc_q_initialisation cholesteric_y # cholesteric with helical axis y
-lc_q_initialisation cholesteric_z # cholesteric with helical axis z
-
-lc_q_initialisation o8m # BPI high chirality limit
-lc_q_initialisation o2 # BPII high chirality limit
-lc_q_initialisation o5
-lc_q_initialisation h2d # 2d hexagonal
-lc_q_initialisation h3da # 3d hexagonal BP A
-lc_q_initialisation h3db # 3d hexagonal BP B
-lc_q_initialisation dtc # double twist cylinders
-
-lc_q_initialisation bp3
-
-lc_q_initialisation cf1_x # cholesteric ``finger'' axis x
-lc_q_initialisation cf1_y # cholesteric ``finger'' axis y
-lc_q_initialisation cf1_z # cholesteric ``finger'' axis z
-
-lc_q_initialisation cf1_fluc_x # as cf1_x with random perterbations
-lc_q_initialisation cf1_fluc_y # as cf1_y with random perturbations
-lc_q_initialisation cf1_flux_z # as cf1_z with random perturbations
-
-lc_q_initialistion random # with randomly chosen unit director
-\end{lstlisting}
-Note many of the initialiations require an initial amplitude of order,
-which should be set via
-\begin{lstlisting}
-lc_q_init_amplitude 0.01 # initial amplitude of order A
-\end{lstlisting}
-For example, if an initial uniform nematic is requested with
-unit director $n_\alpha$, the corresponding initial tensor will be
-$$
-Q_{\alpha\beta} =
-{\textstyle \frac{1}{2}} A (3 n_\alpha n_\beta - \delta_{\alpha\beta}).
-$$
+The up-to-date version of this material now appears at
+\texttt{https://ludwig.epcc.ed.ac.uk/inputs/index.html}
\vfill
\pagebreak
diff --git a/docs/intro.tex b/docs/intro.tex
index 17ca71fc2..9847d3580 100755
--- a/docs/intro.tex
+++ b/docs/intro.tex
@@ -7,7 +7,9 @@
% Edinburgh Soft Matter and Statistical Physics Group and
% Edinburgh Parallel Computing Centre
%
-% (c) 2016-2019 The University of Edinburgh
+% (c) 2016-2023 The University of Edinburgh
+%
+% This material is being migrated to https://ludwig.epcc.ed.ac.uk/index.html
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -96,196 +98,6 @@ \subsection{Obtaining the code}
The current stable release is available as the master branch.
-
-\vfill
-\pagebreak
-
-\section{Quick Start for Users}
-
-
-
-\subsection{Running an Example}
-
-\subsubsection{Input file}
-
-The behaviour of \textit{Ludwig} at run time is controlled by
-a plain text input file which consists of a series for key value
-pairs. Each key value pair controls a parameter or parameters
-within the code, for example the system size and number of time steps,
-the fluid properties density and viscosity, the free energy type
-and associated parameters (if required), frequency and type of
-output, parallel decomposition, and so on.
-
-For most keys, the associated property has some default value which
-will be used by the code if the relevant key is not present (or
-commented out) in the input file. While such default values are
-chosen to be at least sensible, users need to be aware that all
-necessary keys need to be considered for a given problem. However,
-many keys are irrelevant for any given problem.
-
-A significant number of example input files are available as
-part of the test suite, and these can form a useful starting
-point for a given type of problem. We will consider one which
-uses some of the common keys.
-
-\subsubsection{Example input}
-
-We will consider a simple example which computes the motion of
-a single spherical colloidal particle in an initially stationary
-fluid of given viscosity. The velocity may be measured as a
-function of time. Assume we have an executable in the \texttt{src}
-directory.
-
-Make a copy of the input file
-\begin{lstlisting}
-$ cp ../tests/regression/d3q19-extra/serial-auto-c01.inp .
-\end{lstlisting}
-
-Inspection of this file will reveal the following: blank lines
-and comments --- lines beginning with \texttt{\#} --- may be included,
-but are ignored at run time; other lines are parsed as key value
-pairs, each pair on a separate line, and with key and value separated
-by one or more spaces. Values may be characters or strings, a
-scalar integer or 3-vector of integers, or a scalar or 3-vector
-of floating point numbers. Values which are 3-vectors are delineated
-by an underscore character (not a space), e.g., \texttt{1\_2\_3},
-and always correspond to a Cartesian triple $(x,y,z)$.
-A given value is parsed appropriately in the context of the associated key.
-
-So, the first few lines of the above file are:
-\lstinputlisting[firstline=1, lastline= 16]
-{../tests/regression/d3q19-extra/serial-auto-c01.inp}
-Here, the first key value pair \texttt{N\_cycles 40} sets the number
-of time steps to 40, while the second, \texttt{size 64\_64\_64}, sets
-the system size to be 64 points in each of the three coordinate
-directions. The \texttt{grid} key relates to the parallel
-domain decomposition as is discussed in the following
-section.
-
-\subsubsection{Run time}
-
-The executable takes a single argument on the command line which
-is the name of the input file, which should be in the same
-directory as the executable. If no input file name is supplied,
-the executable will look for a default \texttt{input}. If no
-input file is located at all, an error to that effect will be
-reported.
-
-\textbf{Serial: }
-If a serial executable is run in the normal way with the copy of the
-input file as the argument the code should take around 10--20 seconds
-to execute 40 steps. The fist few lines of output should look like:
-
-\begin{lstlisting}[belowskip=0pt]
-$ ./Ludwig.exe ./serial-auto-c01.inp
-\end{lstlisting}
-\lstinputlisting[aboveskip=0pt, firstline=1, lastline= 16]
-{../tests/regression/d3q19-extra/serial-auto-c01.log}
-This output shows that the appropriate input file has been read, and
-the system size set correspondingly with a number of default settings
-including periodic boundary conditions. ``No free energy'' tells us we
-are using a single Newtonian fluid.
-
-Normal termination of execution is accompanied by a report
-of the time take by various parts of the code, and finally by
-\begin{lstlisting}
-...
-Ludwig finished normally.
-\end{lstlisting}
-
-\textbf{Parallel: }
-The executable compiled and linked against the MPI library can
-be run with the MPI launcher for the local system, often
-\texttt{mpirun}. For example, a run on 8 MPI tasks produces a
-similar output to that seen in the serial case, but reports
-details of the local domain decomposition:
-\begin{lstlisting}
-$ mpirun -np 8 ./Ludwig.exe ./serial-auto-c01.inp
-Welcome to Ludwig v0.1.26 (MPI version running on 8 processes)
-...
-System details
---------------
-System size: 64 64 64
-Decomposition: 2 2 2
-Local domain: 32 32 32
-...
-\end{lstlisting}
-The decomposition is controlled by the \texttt{grid} key in
-the input. Here, \texttt{grid 2\_2\_2} is consistent with the
-8 MPI tasks specified on the command line, and the resulting
-local decomposition is 32 lattice points in each coordinate direction.
-If no grid is specified in the input, or a request is
-make for a grid which cannot be met (e.g., the product
-of the grid dimensions does not agree with the total number
-of MPI tasks available)
-the code will try to determine its own decomposition as best
-it can. If no valid parallel decomposition is available at all,
-the code will exit with a message to that effect.
-
-Further details of various input key value pairs are given in
-relevant sections of the documentation.
-
-\subsubsection{Output}
-
-The standard output of the running code produces a number of
-aggregate quantities which allow a broad overview of the progress
-of the computation to be seen by the user. These include, where
-relevant, global statistics related to fluid density and momentum,
-the integrated free energy, particle-related quantities, and so on.
-The frequency of this information can be adjusted from the input
-file (see, e.g., \texttt{freq\_statistics}).
-
-Output for lattice-based quantities (for example, the velocity field
-$u(\mathbf{r}; t)$) is via external file. This output is in serial
-or in parallel according to how the model is run, and may be in
-either ASCII or raw binary format as required. Output files are produced
-with time step encoded in the file, and an extension which describes the
-parallel output decomposition. Further, each quantity output in this way
-is accompanied by a metadata description with \texttt{meta} extension.
-For example, the two output files
-\begin{lstlisting}
-bash-3.2$ ls dist*
-dist-00000020.001-001 dist.001-001.meta
-\end{lstlisting}
-contain the LB distributions for time step 20 (the file is 1 of a total
-number of 1 in parallel), and the plain text metadata description,
-respectively.
-
-To ensure output for based-based quantities is in the correct order for
-analysis, post-processing
-may be required (always if the code is run in parallel). This uses a utility
-provided for the purpose which required both the data and the metadata
-description to recombine the parallel output. This utility is described
-ELSEWHERE.
-
-Output for colloidal particle data is again to file with a name encoding
-the time step and parallel decomposition of the output. For example,
-\begin{lstlisting}
-bash-3.2$ ls config*
-config.cds00000020.001-001
-\end{lstlisting}
-contains particle data for time step 20 in a format described in
-Section~\ref{section-examples}.
-These data may be requested in ASCII or raw binary format.
-
-\subsubsection{Errors and run time failures}
-
-The code attempts to provide meaningful diagnostic error messages
-for common problems. Such errors include missing or incorrectly
-formatted input files, inconsistent input values, and unacceptable
-feature combinations. The code should also detect other run time
-problems such as insufficient memory and errors writing output
-files. These errors will result in termination.
-
-Instability in the computation will often be manifested by numerically
-absurd values in the statistical output (ultimately \texttt{NaN} in
-many cases). Instability may or may not result in termination, depending
-on the problem. Such instability is very often related to poor parameter
-choices, of which there can be many combinations. Check the
-relevant section of the documentation for advice on reasonable starting
-parameters for different problems.
-
-
\subsection{Note on Units}
All computation in \textit{Ludwig} is undertaken in ``lattice
diff --git a/docs/pics/test_eo.pdf b/docs/pics/test_eo.pdf
deleted file mode 100644
index e12d0f0af..000000000
Binary files a/docs/pics/test_eo.pdf and /dev/null differ
diff --git a/docs/pics/test_lj_decay1.pdf b/docs/pics/test_lj_decay1.pdf
deleted file mode 100644
index cc2cdd859..000000000
Binary files a/docs/pics/test_lj_decay1.pdf and /dev/null differ
diff --git a/docs/pics/test_lj_zoom1.pdf b/docs/pics/test_lj_zoom1.pdf
deleted file mode 100644
index dbf8c1112..000000000
Binary files a/docs/pics/test_lj_zoom1.pdf and /dev/null differ
diff --git a/docs/pics/test_lj_zoom3.pdf b/docs/pics/test_lj_zoom3.pdf
deleted file mode 100644
index 21f90a49a..000000000
Binary files a/docs/pics/test_lj_zoom3.pdf and /dev/null differ
diff --git a/mpi_s/Makefile b/mpi_s/Makefile
index b1098c63d..c063f4379 100644
--- a/mpi_s/Makefile
+++ b/mpi_s/Makefile
@@ -32,3 +32,4 @@ test: mpi_tests.c $(LIBNAME) Makefile
clean:
rm -rf mpi_serial.o $(LIBNAME) a.out
+ rm -f *gcno *gcda
diff --git a/src/Makefile b/src/Makefile
index c2f9154c1..49a664504 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -99,3 +99,4 @@ util_sum.o: util_sum.c
.PHONY : clean
clean:
rm -f *.o $(EXECUTABLE) $(LIBRARY)
+ rm -f *.gcno *.gcda
diff --git a/src/advection.c b/src/advection.c
index 6b30bf09c..05e9397e5 100644
--- a/src/advection.c
+++ b/src/advection.c
@@ -34,7 +34,6 @@
#include
#include "advection_s.h"
-#include "psi_gradients.h"
#include "hydro.h"
#include "timer.h"
@@ -1462,90 +1461,6 @@ static int advection_le_5th(advflux_t * flux, hydro_t * hydro, int nf,
return 0;
}
-/*****************************************************************************
- *
- * advective_fluxes_d3qx
- *
- * General routine for nf fields at starting address f.
- * No Lees Edwards boundaries.
- *
- * The storage of the field(s) for all the related routines is
- * assumed to be f[index][nf], where index is the spatial index.
- *
- *****************************************************************************/
-
-int advective_fluxes_d3qx(hydro_t * hydro, int nf, double * f,
- double ** flx) {
-
- assert(hydro);
- assert(nf > 0);
- assert(f);
- assert(flx);
-
- advective_fluxes_2nd_d3qx(hydro, nf, f, flx);
-
- return 0;
-}
-
-/*****************************************************************************
- *
- * advective_fluxes_2nd_d3qx
- *
- * 'Centred difference' advective fluxes. No LE planes.
- * TODO: belongs to Nernst Planck.
- *
- * Symmetric two-point stencil.
- *
- *****************************************************************************/
-
-int advective_fluxes_2nd_d3qx(hydro_t * hydro, int nf, double * f,
- double ** flx) {
-
- int nlocal[3];
- int ic, jc, kc, c;
- int n;
- int index0, index1;
- int nsites;
- double u0[3], u1[3], u;
-
- assert(hydro);
- assert(hydro->cs);
- assert(nf > 0);
- assert(f);
- assert(flx);
-
- cs_nlocal(hydro->cs, nlocal);
- cs_nsites(hydro->cs, &nsites);
-
- for (ic = 1; ic <= nlocal[X]; ic++) {
- for (jc = 1; jc <= nlocal[Y]; jc++) {
- for (kc = 1; kc <= nlocal[Z]; kc++) {
-
- index0 = cs_index(hydro->cs, ic, jc, kc);
- hydro_u(hydro, index0, u0);
-
- for (c = 1; c < PSI_NGRAD; c++) {
-
- index1 = cs_index(hydro->cs, ic + psi_gr_cv[c][X], jc + psi_gr_cv[c][Y], kc + psi_gr_cv[c][Z]);
- hydro_u(hydro, index1, u1);
-
- u = 0.5*((u0[X] + u1[X])*psi_gr_cv[c][X] + (u0[Y] + u1[Y])*psi_gr_cv[c][Y] + (u0[Z] + u1[Z])*psi_gr_cv[c][Z]);
-
- for (n = 0; n < nf; n++) {
- flx[addr_rank1(nsites, nf, index0, n)][c - 1]
- = u*0.5*(f[addr_rank1(nsites, nf, index1, n)]
- + f[addr_rank1(nsites, nf, index0, n)]);
- }
- }
-
- /* Next site */
- }
- }
- }
-
- return 0;
-}
-
/*****************************************************************************
*
* advflux_cs_compute
diff --git a/src/advection.h b/src/advection.h
index 9e5dbf777..07cb0714b 100644
--- a/src/advection.h
+++ b/src/advection.h
@@ -5,7 +5,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2010-2021 The University of Edinburgh
+ * (c) 2010-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -36,10 +36,6 @@ __host__ int advflux_cs_compute(advflux_t * flux, hydro_t * h, field_t * f);
__host__ int advflux_cs_zero(advflux_t * flux);
__host__ int advection_x(advflux_t * obj, hydro_t * hydro, field_t * field);
-__host__ int advective_fluxes_d3qx(hydro_t * hydro, int nf, double * f,
- double ** flx);
-__host__ int advective_fluxes_2nd_d3qx(hydro_t * hydro, int nf, double * f,
- double ** flx);
__host__ int advection_order_set(const int order);
__host__ int advection_order(int * order);
diff --git a/src/advection_bcs.c b/src/advection_bcs.c
index 971b69077..ec9d6dddc 100644
--- a/src/advection_bcs.c
+++ b/src/advection_bcs.c
@@ -7,7 +7,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2009-2021 The University of Edinburgh
+ * (c) 2009-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -23,7 +23,6 @@
#include "coords.h"
#include "kernel.h"
#include "advection_s.h"
-#include "psi_gradients.h"
#include "timer.h"
#include "advection_bcs.h"
@@ -246,56 +245,6 @@ __global__ void advflux_cs_no_flux_kernel(kernel_ctxt_t * ktx,
return;
}
-/*****************************************************************************
- *
- * advective_bcs_no_flux_d3qx
- *
- * Set normal fluxes at solid fluid interfaces to zero.
- *
- *****************************************************************************/
-
-int advective_bcs_no_flux_d3qx(int nf, double ** flx, map_t * map) {
-
- int n;
- int nsites;
- int nlocal[3];
- int ic, jc, kc, index0, index1;
- int status;
- int c;
- double mask[PSI_NGRAD];
-
- assert(nf > 0);
- assert(flx);
- assert(map);
-
- cs_nsites(map->cs, &nsites);
- cs_nlocal(map->cs, nlocal);
-
- for (ic = 1; ic <= nlocal[X]; ic++) {
- for (jc = 1; jc <= nlocal[Y]; jc++) {
- for (kc = 1; kc <= nlocal[Z]; kc++) {
-
- index0 = cs_index(map->cs, ic, jc, kc);
- map_status(map, index0, &status);
- mask[0] = (status == MAP_FLUID);
-
- for (c = 1; c < PSI_NGRAD; c++) {
-
- index1 = cs_index(map->cs, ic + psi_gr_cv[c][X], jc + psi_gr_cv[c][Y], kc + psi_gr_cv[c][Z]);
- map_status(map, index1, &status);
- mask[c] = (status == MAP_FLUID);
-
- for (n = 0; n < nf; n++) {
- flx[addr_rank1(nsites, nf, index0, n)][c - 1] *= mask[0]*mask[c];
- }
- }
- }
- }
- }
-
- return 0;
-}
-
/*****************************************************************************
*
* advection_bcs_wall
diff --git a/src/advection_bcs.h b/src/advection_bcs.h
index a05e1e22e..6d1430aed 100644
--- a/src/advection_bcs.h
+++ b/src/advection_bcs.h
@@ -5,7 +5,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2009-2019 The University of Edinburgh
+ * (c) 2009-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -21,8 +21,6 @@
__host__ int advection_bcs_no_normal_flux(int nf, advflux_t * flux, map_t * map);
__host__ int advection_bcs_wall(field_t * phi);
-
-__host__ int advective_bcs_no_flux_d3qx(int nf, double ** flx, map_t * map);
__host__ int advflux_cs_no_normal_flux(advflux_t * flux, map_t * map);
#endif
diff --git a/src/blue_phase_beris_edwards.c b/src/blue_phase_beris_edwards.c
index 0c25b0471..bf33cfddb 100644
--- a/src/blue_phase_beris_edwards.c
+++ b/src/blue_phase_beris_edwards.c
@@ -574,7 +574,7 @@ void beris_edw_kernel_v(kernel_ctxt_t * ktx, beris_edw_t * be,
int status = 0;
double q[3][3][NSIMDVL];
- double w[3][3][NSIMDVL];
+ double w[3][3][NSIMDVL] = {0};
double d[3][3][NSIMDVL];
double s[3][3][NSIMDVL];
diff --git a/src/fe_electro.c b/src/fe_electro.c
index 4c4294fa3..b4e475aaf 100644
--- a/src/fe_electro.c
+++ b/src/fe_electro.c
@@ -27,7 +27,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2013-2018 The University of Edinburgh
+ * (c) 2013-2023 The University of Edinburgh
*
* Contributing authors:
* Oliver Henrich (ohenrich@epcc.ed.ac.uk)
@@ -43,7 +43,6 @@
#include "pe.h"
#include "physics.h"
#include "util.h"
-#include "psi_s.h"
#include "psi_gradients.h"
#include "fe_electro.h"
@@ -310,7 +309,7 @@ int fe_electro_stress(fe_electro_t * fe, int index, double s[3][3]) {
reunit = 1.0/eunit;
psi_epsilon(fe->psi, &epsilon);
- psi_electric_field_d3qx(fe->psi, index, e);
+ psi_electric_field(fe->psi, index, e);
e2 = 0.0;
@@ -363,7 +362,7 @@ int fe_electro_stress_ex(fe_electro_t * fe, int index, double s[3][3]) {
reunit = 1.0/eunit;
psi_epsilon(fe->psi, &epsilon);
- psi_electric_field_d3qx(fe->psi, index, e);
+ psi_electric_field(fe->psi, index, e);
e2 = 0.0;
diff --git a/src/fe_electro_symmetric.c b/src/fe_electro_symmetric.c
index 365425f40..9e2917431 100644
--- a/src/fe_electro_symmetric.c
+++ b/src/fe_electro_symmetric.c
@@ -95,6 +95,8 @@ static __constant__ fe_vt_t fe_es_dvt = {
(fe_htensor_v_ft) NULL
};
+__host__ int fe_es_epsilon_set(fe_es_t * fe, double e1, double e2);
+
/*****************************************************************************
*
* fe_es_create
@@ -134,6 +136,7 @@ __host__ int fe_es_create(pe_t * pe, cs_t * cs, fe_symm_t * symm,
fe->super.id = FE_ELECTRO_SYMMETRIC;
psi_nk(psi, &fe->param->nk);
+ fe_es_epsilon_set(fe, psi->epsilon, psi->epsilon2);
tdpGetDeviceCount(&ndevice);
@@ -268,7 +271,7 @@ __host__ int fe_es_mu_phi(fe_es_t * fe, int index, double * mu) {
e2 = 0.0;
- psi_electric_field_d3qx(fe->psi, index, e);
+ psi_electric_field(fe->psi, index, e);
for (ia = 0; ia < 3; ia++) {
e[ia] *= kt*reunit;
@@ -361,8 +364,6 @@ __host__ int fe_es_deltamu_set(fe_es_t * fe, int nk, double * deltamu) {
* If phi = +1 then epsilon(r) = epsilon2, as set in the call to
* fe_es_epsilon_set().
*
- * The function is of signature f_vare_t (see psi_sor.h).
- *
*****************************************************************************/
__host__ int fe_es_var_epsilon(fe_es_t * fe, int index, double * epsilon) {
@@ -436,7 +437,7 @@ __host__ int fe_es_stress_ex(fe_es_t * fe, int index, double s[3][3]) {
requires phi and total electric field */
field_scalar(fe->fe_symm->phi, index, &phi);
- psi_electric_field_d3qx(fe->psi, index, e);
+ psi_electric_field(fe->psi, index, e);
e2 = 0.0;
diff --git a/src/fe_electro_symmetric.h b/src/fe_electro_symmetric.h
index f5b3df36b..48b4b4de0 100644
--- a/src/fe_electro_symmetric.h
+++ b/src/fe_electro_symmetric.h
@@ -2,12 +2,10 @@
*
* fe_electro_symmetric.h
*
- * $Id$
- *
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2013-2017 The University of Edinburgh
+ * (c) 2013-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -49,9 +47,6 @@ int fe_es_mu_ion_solv(fe_es_t * fe, int index, int n, double * mu);
__host__
int fe_es_deltamu_set(fe_es_t * fe, int nk, double * deltamu);
-__host__
-int fe_es_epsilon_set(fe_es_t * fe, double e1, double e2);
-
__host__
int fe_es_var_epsilon(fe_es_t * fe, int index, double * epsilon);
diff --git a/src/field.c b/src/field.c
index 0fbfdc25f..c17aab2dd 100644
--- a/src/field.c
+++ b/src/field.c
@@ -1666,9 +1666,8 @@ int field_io_write(field_t * field, int timestep, io_event_t * event) {
/* Metadata */
if (meta->iswriten == 0) {
- /* No extra comments at the moment */
- cJSON * comments = NULL;
- int ifail = io_metadata_write(meta, field->name, comments);
+ int ifail = io_metadata_write(meta, field->name, event->extra_name,
+ event->extra_json);
if (ifail == 0) field->iometadata_out.iswriten = 1;
}
diff --git a/src/gradient_2d_ternary_solid.c b/src/gradient_2d_ternary_solid.c
index cc8257cf7..dc6b0ebf9 100644
--- a/src/gradient_2d_ternary_solid.c
+++ b/src/gradient_2d_ternary_solid.c
@@ -11,7 +11,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2019-2021 The University of Edinburgh
+ * (c) 2019-2023 The University of Edinburgh
*
* Contributing authors:
* Shan Chen (chan.chen@epfl.ch)
@@ -26,10 +26,14 @@
#include "kernel.h"
#include "gradient_2d_ternary_solid.h"
+typedef struct wetting_s {
+ double hrka[3]; /* Wetting gradients phi, psi, rho */
+} wetting_t;
+
typedef struct solid_s {
map_t * map; /* Map structure reference */
fe_ternary_param_t fe; /* Free energy parameters (copy) */
- double hrka[3]; /* Wetting gradients phi, psi, rho */
+ wetting_t wetting; /* Wetting parameters */
} solid_t;
static solid_t static_solid = {0};
@@ -49,8 +53,8 @@ static __constant__ double wv[NGRAD_] = {w0, w2, w1, w2, w1, w1, w2, w1, w2};
__global__ void grad_2d_ternary_solid_kernel(kernel_ctxt_t * ktx,
field_grad_t * fg,
- map_t * map, solid_t fe);
-
+ map_t * map,
+ wetting_t wet);
/*****************************************************************************
*
@@ -98,8 +102,9 @@ __host__ int grad_2d_ternary_solid_fe_set(fe_ternary_t * fe) {
k3 = fe->param->kappa3;
a2 = fe->param->alpha*fe->param->alpha;
- static_solid.hrka[0] = (-h1/k1 + h2/k2)/a2; /* phi */
- static_solid.hrka[1] = (-h3/k3 )/a2; /* psi */
+ static_solid.wetting.hrka[0] = (-h1/k1 + h2/k2)/a2; /* phi */
+ static_solid.wetting.hrka[1] = (-h3/k3 )/a2; /* psi */
+ static_solid.wetting.hrka[2] = 0.0; /* not used */
return 0;
}
@@ -133,7 +138,7 @@ __host__ int grad_2d_ternary_solid_d2(field_grad_t * fgrad) {
tdpLaunchKernel(grad_2d_ternary_solid_kernel, nblk, ntpb, 0, 0,
ctxt->target, fgrad->target, static_solid.map->target,
- static_solid);
+ static_solid.wetting);
tdpAssert(tdpPeekAtLastError());
tdpAssert(tdpDeviceSynchronize());
@@ -151,7 +156,8 @@ __host__ int grad_2d_ternary_solid_d2(field_grad_t * fgrad) {
__global__ void grad_2d_ternary_solid_kernel(kernel_ctxt_t * ktx,
field_grad_t * fg,
- map_t * map, solid_t fe) {
+ map_t * map,
+ wetting_t wet) {
int kindex;
int kiterations;
@@ -209,7 +215,7 @@ __global__ void grad_2d_ternary_solid_kernel(kernel_ctxt_t * ktx,
if (isite[p] == -1) {
/* Wetting condition */
- dphi = fe.hrka[n];
+ dphi = wet.hrka[n];
}
else {
/* Fluid */
diff --git a/src/hydro_rt.c b/src/hydro_rt.c
index fed227c09..86228594d 100644
--- a/src/hydro_rt.c
+++ b/src/hydro_rt.c
@@ -5,7 +5,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2018-2022 The University of Edinburgh
+ * (c) 2018-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -104,6 +104,16 @@ static int hydro_do_init(pe_t * pe, rt_t * rt, cs_t * cs, lees_edw_t * le,
opts = hydro_options_haloscheme(haloscheme);
}
+ /* First touch option (all or nothing) */
+
+ if (rt_switch(rt, "hydro_data_use_first_touch")) {
+ opts.rho.usefirsttouch = 1;
+ opts.u.usefirsttouch = 1;
+ opts.force.usefirsttouch = 1;
+ opts.eta.usefirsttouch = 1;
+ pe_info(pe, "Hydro data: first touch\n");
+ }
+
/* User i/o options */
io_info_args_rt(rt, RT_FATAL, "rho", IO_INFO_READ_WRITE, &opts.rho.iodata);
io_info_args_rt(rt, RT_FATAL, "vel", IO_INFO_READ_WRITE, &opts.u.iodata);
diff --git a/src/io_event.h b/src/io_event.h
index afe05988b..b4abe9497 100644
--- a/src/io_event.h
+++ b/src/io_event.h
@@ -31,6 +31,8 @@ typedef enum io_event_record_enum io_event_record_t;
typedef struct io_event_s io_event_t;
struct io_event_s {
+ const char * extra_name; /* Extra metadata name */
+ cJSON * extra_json; /* Extra JSON section */
double time[IO_EVENT_MAX]; /* MPI_Wtime()s */
};
diff --git a/src/io_metadata.c b/src/io_metadata.c
index 8c1ee916a..d171b8642 100644
--- a/src/io_metadata.c
+++ b/src/io_metadata.c
@@ -237,13 +237,14 @@ int io_metadata_from_json(cs_t * cs, const cJSON * json, io_metadata_t * m) {
*
* io_metadata_write
*
- * Driver to write to file with an optional extra comment block.
+ * Driver to write to file with an optional extra json block.
*
*****************************************************************************/
int io_metadata_write(const io_metadata_t * metadata,
const char * stub,
- const cJSON * comments) {
+ const char * extra_name,
+ const cJSON * extra_json) {
int ifail = 0;
cJSON * json = NULL;
@@ -257,9 +258,9 @@ int io_metadata_write(const io_metadata_t * metadata,
/* Generate a json with the header inserted (gets deleted below) */
io_metadata_to_json(metadata, &json);
- if (comments) {
- cJSON * jtmp = cJSON_Duplicate(comments, 1);
- cJSON_AddItemToObject(json, "comments", jtmp);
+ if (extra_name && extra_json) {
+ cJSON * jtmp = cJSON_Duplicate(extra_json, 1);
+ cJSON_AddItemToObject(json, extra_name, jtmp);
}
/* The extension uses indices in natural numbers 001-002 etc. */
diff --git a/src/io_metadata.h b/src/io_metadata.h
index 1023a7761..06709befa 100644
--- a/src/io_metadata.h
+++ b/src/io_metadata.h
@@ -55,7 +55,8 @@ int io_metadata_from_json(cs_t * cs, const cJSON * json,
int io_metadata_write(const io_metadata_t * metadata,
const char * stub,
- const cJSON * comments);
+ const char * extra,
+ const cJSON * json);
int io_metadata_from_file(pe_t * pe, const char * filename,
io_metadata_t ** metadata);
diff --git a/src/leesedwards.c b/src/leesedwards.c
index c986e7274..f7b7d1a28 100644
--- a/src/leesedwards.c
+++ b/src/leesedwards.c
@@ -9,7 +9,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2010-2022 The University of Edinburgh
+ * (c) 2010-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -34,10 +34,6 @@ struct lees_edw_s {
lees_edw_param_t * param; /* Parameters */
int nref; /* Reference count */
- int * icbuff_to_real; /* look up table */
- int * icreal_to_buff; /* look up table */
- int * buffer_duy; /* look up table +/- uy as function of ib */
-
MPI_Comm le_comm; /* 1-d communicator */
MPI_Comm le_plane_comm; /* 2-d communicator */
@@ -72,12 +68,6 @@ static int lees_edw_init_tables(lees_edw_t * le);
static __constant__ lees_edw_param_t static_param;
-__host__ __device__ int lees_edw_buffer_duy(lees_edw_t * le, int ib);
-
-/* Scheduled for removal */
-__host__ __device__ int lees_edw_index_real_to_buffer(lees_edw_t * le, int ic, int idisplace);
-__host__ __device__ int lees_edw_index_buffer_to_real(lees_edw_t * le, int ibuf);
-
/*****************************************************************************
*
* lees_edw_create
@@ -175,9 +165,6 @@ __host__ int lees_edw_free(lees_edw_t * le) {
pe_free(le->pe);
cs_free(le->cs);
- free(le->icbuff_to_real);
- free(le->icreal_to_buff);
- free(le->buffer_duy);
free(le->param);
free(le);
}
@@ -217,68 +204,6 @@ __host__ int lees_edw_target(lees_edw_t * le, lees_edw_t ** target) {
return 0;
}
-/*****************************************************************************
- *
- * lees_edw_nplane_set
- *
- *****************************************************************************/
-
-int lees_edw_nplane_set(lees_edw_t * le, int nplanetotal) {
-
- assert(le);
-
- le->param->nplanetotal = nplanetotal;
-
- return 0;
-}
-
-/*****************************************************************************
- *
- * lees_edw_plane_uy_set
- *
- *****************************************************************************/
-
-int lees_edw_plane_uy_set(lees_edw_t * le, double uy) {
-
- assert(le);
-
- le->param->uy = uy;
-
- return 0;
-}
-
-/*****************************************************************************
- *
- * lees_edw_oscillatory_set
- *
- *****************************************************************************/
-
-int lees_edw_oscillatory_set(lees_edw_t * le, int period) {
-
- assert(le);
-
- le->param->type = LE_SHEAR_TYPE_OSCILLATORY;
- le->param->period = period;
- le->param->omega = 2.0*4.0*atan(1.0)/le->param->period;
-
- return 0;
-}
-
-/*****************************************************************************
- *
- * lees_edw_toffset_set
- *
- *****************************************************************************/
-
-int lees_edw_toffset_set(lees_edw_t * le, int nt0) {
-
- assert(le);
-
- le->param->nt0 = nt0;
-
- return 0;
-}
-
/*****************************************************************************
*
* lees_edw_init
@@ -286,10 +211,6 @@ int lees_edw_toffset_set(lees_edw_t * le, int nt0) {
* We assume there are a given number of equally-spaced planes
* all with the same speed.
*
- * Pending (KS):
- * - dx should be integers, i.e, ntotal[X] % ntotal must be zero
- * - look at displacement issue
- *
*****************************************************************************/
static int lees_edw_init(lees_edw_t * le, const lees_edw_options_t * info) {
@@ -319,6 +240,14 @@ static int lees_edw_init(lees_edw_t * le, const lees_edw_options_t * info) {
le->param->dx_sep = 1.0*ntotal[X] / le->param->nplanetotal;
le->param->dx_min = 0.5*le->param->dx_sep;
le->param->time0 = 1.0*le->param->nt0;
+
+ if (le->param->type == LE_SHEAR_TYPE_OSCILLATORY) {
+ if (info->period <= 0) {
+ pe_info(le->pe, "Oscillatory shear must have period > 0\n");
+ pe_fatal(le->pe, "Please check the input and try again.");
+ }
+ le->param->omega = 2.0*4.0*atan(1.0)/le->param->period;
+ }
}
lees_edw_checks(le);
@@ -437,7 +366,6 @@ __host__ int lees_edw_info(lees_edw_t * le) {
static int lees_edw_init_tables(lees_edw_t * le) {
- int ib, ic, ip, n, nb, nh, np;
int nhalo;
int rdims[3];
int cartsz[3];
@@ -454,127 +382,9 @@ static int lees_edw_init_tables(lees_edw_t * le) {
le->param->nhalo = nhalo;
le->param->nplanelocal = le->param->nplanetotal / cartsz[X];
- /* Look up table for buffer -> real index */
-
- /* For each 'x' location in the buffer region, work out the corresponding
- * x index in the real system:
- * - for each boundary there are 2*nhalo buffer planes
- * - the locations extend nhalo points either side of the boundary.
- */
-
+ /* Number of buffer planes */
le->param->nxbuffer = 2*nhalo*le->param->nplanelocal;
- if (le->param->nxbuffer > 0) {
- le->icbuff_to_real = (int *) calloc(le->param->nxbuffer, sizeof(int));
- if (le->icbuff_to_real == NULL) pe_fatal(le->pe, "calloc(le) failed\n");
- }
-
- ib = 0;
- for (n = 0; n < le->param->nplanelocal; n++) {
- ic = lees_edw_plane_location(le, n) - (nhalo - 1);
- for (nh = 0; nh < 2*nhalo; nh++) {
- assert(ib < 2*nhalo*le->param->nplanelocal);
- le->icbuff_to_real[ib] = ic + nh;
- ib++;
- }
- }
-
- /* Look up table for real -> buffer index */
-
- /* For each x location in the real system, work out the index of
- * the appropriate x-location in the buffer region. This is more
- * complex, as it depends on whether you are looking across an
- * LE boundary, and if so, in which direction.
- * ie., we need a look up table = function(x, +/- dx).
- * Note that this table exists when no planes are present, ie.,
- * there is no transformation, ie., f(x, dx) = x + dx for all dx.
- */
-
- n = (le->param->nlocal[X] + 2*nhalo)*(2*nhalo + 1);
- le->param->index_real_nbuffer = n;
-
- le->icreal_to_buff = (int *) calloc(n, sizeof(int));
- assert(le->icreal_to_buff);
- if (le->icreal_to_buff == NULL) pe_fatal(le->pe, "calloc(le) failed\n");
-
- /* Set table in abscence of planes. */
- /* Note the elements of the table at the extreme edges of the local
- * system point outside the system. Accesses must take care. */
-
- for (ic = 1 - nhalo; ic <= le->param->nlocal[X] + nhalo; ic++) {
- for (nh = -nhalo; nh <= nhalo; nh++) {
- n = (ic + nhalo - 1)*(2*nhalo+1) + (nh + nhalo);
- assert(n >= 0 && n < (le->param->nlocal[X] + 2*nhalo)*(2*nhalo + 1));
- le->icreal_to_buff[n] = ic + nh;
- }
- }
-
- /* For each position in the buffer, add appropriate
- * corrections in the table. */
-
- nb = le->param->nlocal[X] + nhalo + 1;
-
- for (ib = 0; ib < le->param->nxbuffer; ib++) {
- np = ib / (2*nhalo);
- ip = lees_edw_plane_location(le, np);
-
- /* This bit of logic chooses the first nhalo points of the
- * buffer region for each plane as the 'downward' looking part */
-
- if ((ib - np*2*nhalo) < nhalo) {
-
- /* Looking across the plane in the -ve x-direction */
-
- for (ic = ip + 1; ic <= ip + nhalo; ic++) {
- for (nh = -nhalo; nh <= -1; nh++) {
- if (ic + nh == le->icbuff_to_real[ib]) {
- n = (ic + nhalo - 1)*(2*nhalo+1) + (nh + nhalo);
- assert(n >= 0 && n < (le->param->nlocal[X] + 2*nhalo)*(2*nhalo + 1));
- le->icreal_to_buff[n] = nb+ib;
- }
- }
- }
- }
- else {
- /* looking across the plane in the +ve x-direction */
-
- for (ic = ip - (nhalo - 1); ic <= ip; ic++) {
- for (nh = 1; nh <= nhalo; nh++) {
- if (ic + nh == le->icbuff_to_real[ib]) {
- n = (ic + nhalo - 1)*(2*nhalo+1) + (nh + nhalo);
- assert(n >= 0 && n < (le->param->nlocal[X] + 2*nhalo)*(2*nhalo + 1));
- le->icreal_to_buff[n] = nb+ib;
- }
- }
- }
- }
- /* Next buffer point */
- }
-
- /* Buffer velocity jumps. When looking from the real system across
- * a boundary into a given buffer, what is the associated velocity
- * jump? This is +1 for 'looking up' and -1 for 'looking down'.*/
-
- if (le->param->nxbuffer > 0) {
- le->buffer_duy = (int *) calloc(le->param->nxbuffer, sizeof(int));
- assert(le->buffer_duy);
- if (le->buffer_duy == NULL) pe_fatal(le->pe,"calloc(buffer_duy) failed\n");
- }
-
- ib = 0;
- for (n = 0; n < le->param->nplanelocal; n++) {
- for (nh = 0; nh < nhalo; nh++) {
- assert(ib < le->param->nxbuffer);
- le->buffer_duy[ib] = -1;
- ib++;
- }
- for (nh = 0; nh < nhalo; nh++) {
- assert(ib < le->param->nxbuffer);
- le->buffer_duy[ib] = +1;
- ib++;
- }
- }
-
/* Set up a 1-dimensional communicator for transfer of data
* along the y-direction. */
@@ -707,7 +517,7 @@ int lees_edw_steady_uy(lees_edw_t * le, int ic, double * uy) {
/*****************************************************************************
*
- * lees_edw_get_block_uy
+ * lees_edw_block_uy
*
* Return the velocity of the LE 'block' at ic relative to the
* centre of the system.
@@ -769,7 +579,9 @@ int lees_edw_plane_uy_now(lees_edw_t * le, double t, double * uy) {
assert(tle >= 0.0);
*uy = le->param->uy;
- if (le->param->type == LE_SHEAR_TYPE_OSCILLATORY) *uy *= cos(le->param->omega*tle);
+ if (le->param->type == LE_SHEAR_TYPE_OSCILLATORY) {
+ *uy *= cos(le->param->omega*tle);
+ }
return 0;
}
@@ -804,53 +616,6 @@ int lees_edw_plane_location(lees_edw_t * le, int np) {
return ix;
}
-/*****************************************************************************
- *
- * lees_edw_index_real_to_buffer
- *
- * For x index 'ic' and step size 'idisplace', return the x index of the
- * translated buffer.
- *
- *****************************************************************************/
-
-__host__ __device__
-int lees_edw_index_real_to_buffer(lees_edw_t * le, int ic, int idisplace) {
-
- int ib;
-
- assert(le);
- assert(le->icreal_to_buff);
-
- assert(idisplace >= -le->param->nhalo && idisplace <= +le->param->nhalo);
-
- ib = (ic + le->param->nhalo - 1)*(2*le->param->nhalo + 1) + idisplace + le->param->nhalo;
-
- assert(ib >= 0 && ib < le->param->index_real_nbuffer);
-
- assert(le->icreal_to_buff[ib] == lees_edw_ic_to_buff(le, ic, idisplace));
- return le->icreal_to_buff[ib];
-}
-
-/*****************************************************************************
- *
- * lees_edw_index_buffer_to_real
- *
- * For x index in the buffer region, return the corresponding
- * x index in the real system.
- *
- *****************************************************************************/
-
-__host__ __device__
-int lees_edw_index_buffer_to_real(lees_edw_t * le, int ib) {
-
- assert(le);
- assert(le->icbuff_to_real);
- assert(ib >=0 && ib < le->param->nxbuffer);
-
- assert(le->icbuff_to_real[ib] == lees_edw_ibuff_to_real(le, ib));
- return le->icbuff_to_real[ib];
-}
-
/*****************************************************************************
*
* lees_edw_buffer_displacement
@@ -872,14 +637,14 @@ int lees_edw_buffer_displacement(lees_edw_t * le, int ib, double t, double * dy)
assert(le);
assert(ib >= 0 && ib < le->param->nxbuffer);
+ if (t < 0.0) t = 0.0;
tle = t - le->param->time0;
assert(tle >= 0.0);
*dy = 0.0;
if (le->param->type == LE_SHEAR_TYPE_STEADY) {
- *dy = tle*le->param->uy*le->buffer_duy[ib];
- assert(le->buffer_duy[ib] == lees_edw_buffer_duy(le, ib));
+ *dy = tle*le->param->uy*lees_edw_buffer_duy(le, ib);
}
if (le->param->type == LE_SHEAR_TYPE_OSCILLATORY) {
@@ -980,6 +745,7 @@ int lees_edw_shear_rate(lees_edw_t * le, double * gammadot) {
double ltot[3];
assert(le);
+
cs_ltot(le->cs, ltot);
*gammadot = le->param->uy*le->param->nplanetotal/ltot[X];
@@ -1206,8 +972,7 @@ __host__ int lees_edw_buffer_du(lees_edw_t * le, int ib, double ule[3]) {
if (le->param->type == LE_SHEAR_TYPE_STEADY) {
ule[X] = 0.0;
- ule[Y] = le->param->uy*le->buffer_duy[ib];
- assert(le->buffer_duy[ib] == lees_edw_buffer_duy(le, ib));
+ ule[Y] = le->param->uy*lees_edw_buffer_duy(le, ib);
ule[Z] = 0.0;
}
else {
@@ -1282,21 +1047,32 @@ int lees_edw_ic_to_buff(lees_edw_t * le, int ic, int di) {
return ib;
}
-/******************************************************************************
+/*****************************************************************************
*
* lees_edw_buffer_duy
*
- ******************************************************************************/
+ * This is the sign (-1 or +1) of the velocity change associated
+ * with buffer location ib.
+ *
+ * The picture is:
+ *
+ * nplane = 0 nplane = 1 ... x, ib ->
+ * nhalo nhalo nhalo nhalo
+ * -1 +1 -1 +1
+ *
+ *****************************************************************************/
__host__ __device__ int lees_edw_buffer_duy(lees_edw_t * le, int ib) {
- int pm1;
+ int pm1 = +1;
assert(le);
- assert(ib >= 0 && ib < le->param->nxbuffer);
+ assert(0 <= ib && ib < le->param->nxbuffer);
- pm1 = +1;
+ /* The first nhalo values for each plane are -1 ... */
if (ib % (2*le->param->nhalo) < le->param->nhalo) pm1 = -1;
+ assert(pm1 == -1 || pm1 == +1);
+
return pm1;
}
diff --git a/src/leesedwards.h b/src/leesedwards.h
index 03812738f..04853ebae 100644
--- a/src/leesedwards.h
+++ b/src/leesedwards.h
@@ -5,8 +5,9 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
+ * (c) 2010-2023 The University of Edinburgh
+ *
* Kevin Stratford (kevin@epcc.ed.ac.uk)
- * (c) 2010-2022 The University of Edinburgh
*
*****************************************************************************/
@@ -70,4 +71,6 @@ __host__ __device__ int lees_edw_ic_to_buff(lees_edw_t * le, int ic, int di);
__host__ __device__ void lees_edw_index_v(lees_edw_t * le, int ic[NSIMDVL],
int jc[NSIMDVL], int kc[NSIMDVL],
int index[NSIMDVL]);
+
+__host__ __device__ int lees_edw_buffer_duy(lees_edw_t * le, int ib);
#endif
diff --git a/src/ludwig.c b/src/ludwig.c
index 12dd4abe9..0387282c1 100644
--- a/src/ludwig.c
+++ b/src/ludwig.c
@@ -101,12 +101,11 @@
/* Electrokinetics */
#include "psi.h"
#include "psi_rt.h"
-#include "psi_sor.h"
#include "psi_stats.h"
#include "psi_force.h"
+#include "psi_solver.h"
#include "psi_colloid.h"
#include "nernst_planck.h"
-#include "psi_petsc.h"
/* Statistics */
#include "stats_colloid.h"
@@ -146,7 +145,8 @@ struct ludwig_s {
wall_t * wall; /* Side walls / Porous media */
noise_t * noise_rho; /* Lattice fluctuation generator (rho) */
noise_t * noise_phi; /* Binary fluid noise generation (fluxes) */
- f_vare_t epsilon; /* Variable epsilon function for Poisson solver */
+
+ psi_solver_t * poisson; /* Poisson solver */
fe_t * fe; /* Free energy "polymorphic" version */
ch_t * ch; /* Cahn Hilliard (surfactants) */
@@ -182,6 +182,7 @@ struct ludwig_s {
static int ludwig_rt(ludwig_t * ludwig);
static int ludwig_report_momentum(ludwig_t * ludwig);
+static int ludwig_report_statistics(ludwig_t * ludwig, int itimestep);
static int ludwig_colloids_update(ludwig_t * ludwig);
static int ludwig_colloids_update_low_freq(ludwig_t * ludwig);
@@ -205,12 +206,10 @@ static int ludwig_rt(ludwig_t * ludwig) {
int ntstep;
int n, nstat;
char filename[FILENAME_MAX];
- char subdirectory[FILENAME_MAX/2];
pe_t * pe = NULL;
cs_t * cs = NULL;
rt_t * rt = NULL;
- io_info_t * iohandler = NULL;
assert(ludwig);
@@ -237,10 +236,6 @@ static int ludwig_rt(ludwig_t * ludwig) {
physics_init_rt(rt, ludwig->phys);
physics_info(pe, ludwig->phys);
-#ifdef PETSC
- if (ludwig->psi) psi_petsc_init(ludwig->psi, ludwig->fe, ludwig->epsilon);
-#endif
-
lb_run_time(pe, cs, rt, &ludwig->lb);
collision_run_time(pe, rt, ludwig->lb, ludwig->noise_rho);
map_init_rt(pe, cs, rt, &ludwig->map);
@@ -310,18 +305,22 @@ static int ludwig_rt(ludwig_t * ludwig) {
/* NOW INITIAL CONDITIONS */
- pe_subdirectory(pe, subdirectory);
ntstep = physics_control_timestep(ludwig->phys);
if (ntstep == 0) {
double rho0 = 1.0;
- n = 0;
lb_rt_initial_conditions(pe, rt, ludwig->lb, ludwig->phys);
physics_rho0(ludwig->phys, &rho0);
if (ludwig->hydro) hydro_rho0(ludwig->hydro, rho0);
- rt_int_parameter(rt, "LE_init_profile", &n);
- if (n != 0) lb_le_init_shear_profile(ludwig->lb, ludwig->le);
+ /* This should be relocated with LE plane input */
+ if (rt_switch(ludwig->rt, "LE_init_profile")) {
+ if (lees_edw_nplane_total(ludwig->le) == 0) {
+ pe_info(ludwig->pe, "Cannot use LE_init_profile with no planes\n");
+ pe_fatal(ludwig->pe, "Please check the input and try again\n");
+ }
+ lb_le_init_shear_profile(ludwig->lb, ludwig->le);
+ }
}
else {
/* Distributions */
@@ -361,10 +360,11 @@ static int ludwig_rt(ludwig_t * ludwig) {
}
if (ludwig->psi) {
- psi_io_info(ludwig->psi, &iohandler);
- sprintf(filename,"%spsi-%8.8d", subdirectory, ntstep);
- pe_info(pe, "electrokinetics files(s) %s\n", filename);
- io_read_data(iohandler, filename, ludwig->psi);
+ io_event_t event1 = {0};
+ io_event_t event2 = {0};
+ pe_info(pe, "Reading electrokinetics files for step %d\n", ntstep);
+ field_io_read(ludwig->psi->psi, ntstep, &event1);
+ field_io_read(ludwig->psi->rho, ntstep, &event2);
}
}
@@ -443,7 +443,6 @@ static int ludwig_rt(ludwig_t * ludwig) {
void ludwig_run(const char * inputfile) {
char filename[FILENAME_MAX];
- char subdirectory[FILENAME_MAX/2];
int is_porous_media = 0;
int step = 0;
int is_pm = 0;
@@ -453,7 +452,6 @@ void ludwig_run(const char * inputfile) {
int im, multisteps;
int flag;
- io_info_t * iohandler = NULL;
ludwig_t * ludwig = NULL;
MPI_Comm comm;
@@ -503,8 +501,6 @@ void ludwig_run(const char * inputfile) {
/* Report initial statistics */
- pe_subdirectory(ludwig->pe, subdirectory);
-
/* Move initilaised data to target for initial conditions/time stepping */
map_memcpy(ludwig->map, tdpMemcpyHostToDevice);
@@ -520,29 +516,7 @@ void ludwig_run(const char * inputfile) {
pe_info(ludwig->pe, "Initial conditions.\n");
wall_is_pm(ludwig->wall, &is_porous_media);
- stats_distribution_print(ludwig->lb, ludwig->map);
-
- lb_ndist(ludwig->lb, &im);
-
- if (im == 2) {
- phi_lb_to_field(ludwig->phi, ludwig->lb);
- stats_field_info_bbl(ludwig->phi, ludwig->map, ludwig->bbl);
- }
- else {
- if (ludwig->phi) {
- if (ludwig->pch) {
- cahn_hilliard_stats(ludwig->pch, ludwig->phi, ludwig->map);
- }
- else {
- stats_field_info(ludwig->phi, ludwig->map);
- }
- }
- }
- if (ludwig->p) stats_field_info(ludwig->p, ludwig->map);
- if (ludwig->q) stats_field_info(ludwig->q, ludwig->map);
- if (ludwig->psi) {
- psi_stats_info(ludwig->psi);
- }
+ ludwig_report_statistics(ludwig, 0);
ludwig_report_momentum(ludwig);
/* Main time stepping loop */
@@ -638,15 +612,11 @@ void ludwig_run(const char * inputfile) {
/* Poisson solve */
- if (step % psi_skipsteps(ludwig->psi) == 0){
- TIMER_start(TIMER_ELECTRO_POISSON);
-#ifdef PETSC
- psi_petsc_solve(ludwig->psi, ludwig->fe, ludwig->epsilon);
-#else
- psi_sor_solve(ludwig->psi, ludwig->fe, ludwig->epsilon, step);
-#endif
- TIMER_stop(TIMER_ELECTRO_POISSON);
- }
+ TIMER_start(TIMER_ELECTRO_POISSON);
+
+ ludwig->poisson->impl->solve(ludwig->poisson, step);
+
+ TIMER_stop(TIMER_ELECTRO_POISSON);
if (ludwig->hydro) {
TIMER_start(TIMER_HALO_LATTICE);
@@ -682,8 +652,8 @@ void ludwig_run(const char * inputfile) {
/* Force calculation as divergence of stress tensor */
if (flag == PSI_FORCE_DIVERGENCE) {
- psi_force_divstress_d3qx(ludwig->psi, ludwig->fe, ludwig->hydro,
- ludwig->map, ludwig->collinfo);
+ psi_force_divstress(ludwig->psi, ludwig->fe, ludwig->hydro,
+ ludwig->collinfo);
}
TIMER_stop(TIMER_FORCE_CALCULATION);
@@ -703,11 +673,7 @@ void ludwig_run(const char * inputfile) {
TIMER_stop(TIMER_HALO_LATTICE);
nernst_planck_adjust_multistep(ludwig->psi);
-
- if (is_statistics_step()) pe_info(ludwig->pe, "%d multisteps\n",im);
-
psi_zero_mean(ludwig->psi);
-
}
/* order parameter dynamics (not if symmetric_lb) */
@@ -895,9 +861,7 @@ void ludwig_run(const char * inputfile) {
TIMER_stop(TIMER_PROPAGATE);
}
- TIMER_stop(TIMER_STEPS);
-
- TIMER_start(TIMER_FREE1); /* Time diagnostics */
+ TIMER_start(TIMER_DIAGNOSTIC_OUTPUT); /* Time diagnostics and i/o */
/* Configuration dump */
@@ -914,7 +878,7 @@ void ludwig_run(const char * inputfile) {
if (is_config_step() || is_measurement_step() || is_colloid_io_step()) {
if (ncolloid > 0) {
pe_info(ludwig->pe, "Writing colloid output at step %d!\n", step);
- sprintf(filename, "%s%s%8.8d", subdirectory, "config.cds", step);
+ sprintf(filename, "%s%8.8d", "config.cds", step);
colloid_io_write(ludwig->cio, filename);
}
}
@@ -946,10 +910,8 @@ void ludwig_run(const char * inputfile) {
if (ludwig->psi) {
if (is_psi_output_step() || is_config_step()) {
- psi_io_info(ludwig->psi, &iohandler);
pe_info(ludwig->pe, "Writing psi file at step %d!\n", step);
- sprintf(filename,"%spsi-%8.8d", subdirectory, step);
- io_write_data(iohandler, filename, ludwig->psi);
+ psi_io_write(ludwig->psi, step);
}
}
@@ -967,7 +929,7 @@ void ludwig_run(const char * inputfile) {
}
if (is_shear_output_step()) {
- sprintf(filename, "%sstr-%8.8d.dat", subdirectory, step);
+ sprintf(filename, "str-%8.8d.dat", step);
stats_rheology_stress_section(ludwig->stat_rheo, filename);
stats_rheology_stress_profile_zero(ludwig->stat_rheo);
}
@@ -985,69 +947,7 @@ void ludwig_run(const char * inputfile) {
if (is_statistics_step()) {
- lb_memcpy(ludwig->lb, tdpMemcpyDeviceToHost);
- stats_distribution_print(ludwig->lb, ludwig->map);
- lb_ndist(ludwig->lb, &im);
-
- if (ludwig->phi) {
- field_memcpy(ludwig->phi, tdpMemcpyDeviceToHost);
- field_grad_memcpy(ludwig->phi_grad, tdpMemcpyDeviceToHost);
- if (im == 2) {
- /* Recompute phi (kernel) and copy back if required */
- phi_lb_to_field(ludwig->phi, ludwig->lb);
- field_memcpy(ludwig->phi, tdpMemcpyDeviceToHost);
- stats_field_info_bbl(ludwig->phi, ludwig->map, ludwig->bbl);
- }
- else {
- if (ludwig->pch) {
- cahn_hilliard_stats(ludwig->pch, ludwig->phi, ludwig->map);
- }
- else {
- field_memcpy(ludwig->phi, tdpMemcpyDeviceToHost);
- stats_field_info(ludwig->phi, ludwig->map);
- }
- }
- }
-
- if (ludwig->p) {
- /* Get the gradients as well for the free energy below */
- field_memcpy(ludwig->p, tdpMemcpyDeviceToHost);
- field_grad_memcpy(ludwig->p_grad, tdpMemcpyDeviceToHost);
- stats_field_info(ludwig->p, ludwig->map);
- }
-
- if (ludwig->q) {
- field_memcpy(ludwig->q, tdpMemcpyDeviceToHost);
- field_grad_memcpy(ludwig->q_grad, tdpMemcpyDeviceToHost);
- stats_field_info(ludwig->q, ludwig->map);
- stats_colloid_force_split_output(ludwig->collinfo, step);
- }
-
- if (ludwig->psi) {
- double psi_zeta;
- psi_colloid_rho_set(ludwig->psi, ludwig->collinfo);
- psi_stats_info(ludwig->psi);
- /* Zeta potential for one colloid only to follow psi_stats()*/
- psi_colloid_zetapotential(ludwig->psi, ludwig->collinfo, &psi_zeta);
- if (ncolloid == 1) pe_info(ludwig->pe, "[psi_zeta] %14.7e\n", psi_zeta);
- }
-
- if (ludwig->fe) {
- switch (ludwig->fe->id) {
- case FE_LC:
- fe_lc_stats_info(ludwig->pe, ludwig->cs, ludwig->fe_lc,
- ludwig->wall, ludwig->map, ludwig->collinfo, step);
- break;
- case FE_TERNARY:
- fe_ternary_stats_info(ludwig->fe_ternary, ludwig->wall,
- ludwig->map, step);
- break;
- default:
- stats_free_energy_density(ludwig->pe, ludwig->cs, ludwig->wall,
- ludwig->fe, ludwig->map,
- ludwig->collinfo);
- }
- }
+ ludwig_report_statistics(ludwig, step);
ludwig_report_momentum(ludwig);
if (ludwig->hydro) {
@@ -1063,7 +963,8 @@ void ludwig_run(const char * inputfile) {
stats_ahydro_accumulate(ludwig->stat_ah, step);
- TIMER_stop(TIMER_FREE1);
+ TIMER_stop(TIMER_DIAGNOSTIC_OUTPUT);
+ TIMER_stop(TIMER_STEPS); /* inclusive of diagnostic/io */
/* Next time step */
}
@@ -1073,10 +974,9 @@ void ludwig_run(const char * inputfile) {
MPI_Barrier(comm);
/* Shut down cleanly. Give the timer statistics. Finalise PE. */
-#ifdef PETSC
- if (ludwig->psi) psi_petsc_finish();
-#endif
- if (ludwig->psi) psi_free(ludwig->psi);
+
+ if (ludwig->poisson) ludwig->poisson->impl->free(&ludwig->poisson);
+ if (ludwig->psi) psi_free(&ludwig->psi);
if (ludwig->stat_rheo) stats_rheology_free(ludwig->stat_rheo);
if (ludwig->stat_turb) stats_turbulent_free(ludwig->stat_turb);
@@ -1848,6 +1748,7 @@ int free_energy_init_rt(ludwig_t * ludwig) {
}
else if(strcmp(description, "fe_electro") == 0) {
+ int ifail = 0;
fe_electro_t * fe = NULL;
fe_force_method_enum_t method = fe_force_method_default();
int psi_method = PSI_FORCE_NONE;
@@ -1892,9 +1793,14 @@ int free_energy_init_rt(ludwig_t * ludwig) {
pe_info(pe, "\n");
pe_info(pe, "Parameters:\n");
- psi_create(pe, cs, nk, &ludwig->psi);
- psi_rt_init_param(pe, rt, ludwig->psi);
- psi_force_method_set(ludwig->psi, psi_method);
+ {
+ /* Options here currently include solver options ... */
+ psi_options_t opts = psi_options_default(nhalo);
+ psi_options_rt(pe, cs, rt, &opts);
+ psi_create(pe, cs, &opts, &ludwig->psi);
+ psi_force_method_set(ludwig->psi, psi_method);
+ psi_info(pe, ludwig->psi);
+ }
pe_info(pe, "Force calculation: %s\n",
fe_force_method_to_string(method));
@@ -1902,6 +1808,16 @@ int free_energy_init_rt(ludwig_t * ludwig) {
/* Create FE objects and set function pointers */
fe_electro_create(pe, ludwig->psi, &fe);
ludwig->fe = (fe_t *) fe;
+
+ /* Uniform solver ok */
+
+ ifail = psi_solver_create(ludwig->psi, &ludwig->poisson);
+ if (ifail != 0) {
+ pe_info(pe, "Poisson solver initialisation failed\n");
+ pe_info(pe, "This probably means you specified \"petsc\" but it has\n");
+ pe_info(pe, "not been compiled. Please specify sor in the input.\n");
+ pe_fatal(pe, "Please check and try again\n");
+ }
}
else if(strcmp(description, "fe_electro_symmetric") == 0) {
@@ -1962,9 +1878,13 @@ int free_energy_init_rt(ludwig_t * ludwig) {
pe_info(pe, "Parameters:\n");
- psi_create(pe, cs, nk, &ludwig->psi);
- psi_rt_init_param(pe, rt, ludwig->psi);
-
+ {
+ psi_options_t opts = psi_options_default(nhalo);
+ psi_options_rt(pe, cs, rt, &opts);
+ psi_create(pe, cs, &opts, &ludwig->psi);
+ psi_info(pe, ludwig->psi);
+ psi_bjerrum_length2(&opts, &lbjerrum2);
+ }
fe_electro_create(pe, ludwig->psi, &fe_elec);
/* Coupling part */
@@ -1982,12 +1902,6 @@ int free_energy_init_rt(ludwig_t * ludwig) {
psi_epsilon(ludwig->psi, &e1);
psi_epsilon2(ludwig->psi, &e2);
- /* Read the second permittivity */
- n = rt_double_parameter(rt, "electrosymmetric_epsilon2", &e2);
- if (n == 1) psi_epsilon2_set(ludwig->psi, e2);
-
- fe_es_epsilon_set(fes, e1, e2);
-
/* Solvation free energy difference: nk = 2 */
mu[0] = 0.0;
@@ -1998,8 +1912,6 @@ int free_energy_init_rt(ludwig_t * ludwig) {
fe_es_deltamu_set(fes, nk, mu);
- psi_bjerrum_length2(ludwig->psi, &lbjerrum2);
-
pe_info(pe, "Second permittivity: %15.7e\n", e2);
pe_info(pe, "Dielectric average: %15.7e\n", 0.5*(e1 + e2));
pe_info(pe, "Dielectric contrast: %15.7e\n", (e1-e2)/(e1+e2));
@@ -2011,11 +1923,28 @@ int free_energy_init_rt(ludwig_t * ludwig) {
/* If permittivities really not the same number... */
if (util_double_same(e1, e2)) {
+ int ifail = 0;
+ ifail = psi_solver_create(ludwig->psi, &ludwig->poisson);
+ if (ifail != 0) {
+ pe_info(pe, "Poisson solver initialisation failed\n");
+ pe_info(pe, "This may mean you specified \"petsc\" but it has\n");
+ pe_info(pe, "not been compiled. Please specify sor in the input.\n");
+ pe_fatal(pe, "Please check and try again\n");
+ }
pe_info(pe, "Poisson solver: %15s\n", "uniform");
}
else {
+ int ifail = 0;
+ var_epsilon_t user = {.fe = (fe_t *) fes,
+ .epsilon = (var_epsilon_ft) fe_es_var_epsilon};
+ ifail = psi_solver_var_epsilon_create(ludwig->psi, user, &ludwig->poisson);
+ if (ifail != 0) {
+ pe_info(pe, "Poisson solver initialisation failed\n");
+ pe_info(pe, "This may mean you specified \"petsc\" but it has\n");
+ pe_info(pe, "not been compiled. Please specify sor in the input.\n");
+ pe_fatal(pe, "Please check and try again\n");
+ }
pe_info(pe, "Poisson solver: %15s\n", "heterogeneous");
- ludwig->epsilon = (f_vare_t) fe_es_var_epsilon;
}
/* Force */
@@ -2194,10 +2123,8 @@ int ludwig_colloids_update(ludwig_t * ludwig) {
TIMER_stop(TIMER_HALO_LATTICE);
- TIMER_start(TIMER_FREE1);
if (iconserve && ludwig->phi) field_halo(ludwig->phi);
if (iconserve && ludwig->psi) psi_halo_rho(ludwig->psi);
- TIMER_stop(TIMER_FREE1);
TIMER_start(TIMER_REBUILD);
@@ -2209,13 +2136,11 @@ int ludwig_colloids_update(ludwig_t * ludwig) {
TIMER_stop(TIMER_REBUILD);
- TIMER_start(TIMER_FREE1);
if (iconserve) {
colloid_sums_halo(ludwig->collinfo, COLLOID_SUM_CONSERVATION);
build_conservation(ludwig->collinfo, ludwig->phi, ludwig->psi,
&ludwig->lb->model);
}
- TIMER_stop(TIMER_FREE1);
TIMER_start(TIMER_FORCES);
@@ -2374,3 +2299,101 @@ __host__ int ludwig_timekeeper_init(ludwig_t * ludwig) {
return 0;
}
+
+/*****************************************************************************
+ *
+ * ludwig_report_statistics
+ *
+ * If t = 0, we need to compute any relevant order parameter gradients
+ * for the fist time.
+ * If t > 0 we use the computation coming from the time step loop.
+ *
+ *****************************************************************************/
+
+int ludwig_report_statistics(ludwig_t * ludwig, int itimestep) {
+
+ assert(ludwig);
+
+ if (itimestep == 0) {
+ if (ludwig->phi) {
+ field_halo(ludwig->phi);
+ field_grad_compute(ludwig->phi_grad);
+ }
+ if (ludwig->p) {
+ field_halo(ludwig->p);
+ field_grad_compute(ludwig->p_grad);
+ }
+ if (ludwig->q) {
+ field_halo(ludwig->q);
+ field_grad_compute(ludwig->q_grad);
+ }
+ }
+
+ lb_memcpy(ludwig->lb, tdpMemcpyDeviceToHost);
+ stats_distribution_print(ludwig->lb, ludwig->map);
+
+ if (ludwig->phi) {
+ field_memcpy(ludwig->phi, tdpMemcpyDeviceToHost);
+ field_grad_memcpy(ludwig->phi_grad, tdpMemcpyDeviceToHost);
+ if (ludwig->lb->ndist == 2) {
+ /* Recompute phi (kernel) and copy back if required */
+ phi_lb_to_field(ludwig->phi, ludwig->lb);
+ field_memcpy(ludwig->phi, tdpMemcpyDeviceToHost);
+ stats_field_info_bbl(ludwig->phi, ludwig->map, ludwig->bbl);
+ }
+ else {
+ if (ludwig->pch) {
+ cahn_hilliard_stats(ludwig->pch, ludwig->phi, ludwig->map);
+ }
+ else {
+ field_memcpy(ludwig->phi, tdpMemcpyDeviceToHost);
+ stats_field_info(ludwig->phi, ludwig->map);
+ }
+ }
+ }
+
+ if (ludwig->p) {
+ /* Get the gradients as well for the free energy below */
+ field_memcpy(ludwig->p, tdpMemcpyDeviceToHost);
+ field_grad_memcpy(ludwig->p_grad, tdpMemcpyDeviceToHost);
+ stats_field_info(ludwig->p, ludwig->map);
+ }
+
+ if (ludwig->q) {
+ field_memcpy(ludwig->q, tdpMemcpyDeviceToHost);
+ field_grad_memcpy(ludwig->q_grad, tdpMemcpyDeviceToHost);
+ stats_field_info(ludwig->q, ludwig->map);
+ stats_colloid_force_split_output(ludwig->collinfo, itimestep);
+ }
+
+ if (ludwig->psi) {
+ int ncolloid = 0;
+ double psi_zeta = 0.0;
+ psi_colloid_rho_set(ludwig->psi, ludwig->collinfo);
+ psi_stats_info(ludwig->psi);
+ /* Zeta potential for one colloid only to follow psi_stats() */
+ /* There should be an explicit option. */
+ colloids_info_ntotal(ludwig->collinfo, &ncolloid);
+ psi_colloid_zetapotential(ludwig->psi, ludwig->collinfo, &psi_zeta);
+ if (ncolloid == 1) pe_info(ludwig->pe, "[psi_zeta] %14.7e\n", psi_zeta);
+ }
+
+ if (ludwig->fe) {
+ switch (ludwig->fe->id) {
+ case FE_LC:
+ fe_lc_stats_info(ludwig->pe, ludwig->cs, ludwig->fe_lc,
+ ludwig->wall, ludwig->map, ludwig->collinfo, itimestep);
+ break;
+ case FE_TERNARY:
+ fe_ternary_stats_info(ludwig->fe_ternary, ludwig->wall,
+ ludwig->map, itimestep);
+ break;
+ default:
+ stats_free_energy_density(ludwig->pe, ludwig->cs, ludwig->wall,
+ ludwig->fe, ludwig->map,
+ ludwig->collinfo);
+ }
+ }
+
+ return 0;
+}
diff --git a/src/main.c b/src/main.c
index 796fa1819..8bed845a9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -4,12 +4,11 @@
*
* Main driver code. See ludwig.c for details of timestepping etc.
*
-
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
* Kevin Stratford (kevin@epcc.ed.ac.uk)
- * (c) 2011-2022 The University of Edinburgh
+ * (c) 2011-2023 The University of Edinburgh
*
*****************************************************************************/
@@ -17,32 +16,40 @@
#include "pe.h"
#include "ludwig.h"
-#ifdef PETSC
- #include "petscksp.h"
-#endif
+#include "util_petsc.h"
/*****************************************************************************
*
* main
*
+ * The Petsc initialisation/finalisation is a facade if there's no
+ * actual Petsc in the build.
+ *
*****************************************************************************/
int main(int argc, char ** argv) {
- char inputfile[FILENAME_MAX] = "input";
+ const char * inputfile = "input";
int provided = MPI_THREAD_SINGLE;
MPI_Init_thread(&argc, &argv, MPI_THREAD_FUNNELED, &provided);
-#ifdef PETSC
PetscInitialize(&argc, &argv, (char*) 0, NULL);
-#endif
- if (argc > 1) snprintf(inputfile, FILENAME_MAX, "%s", argv[1]);
- ludwig_run(inputfile);
+ if (argc == 1) {
+ ludwig_run(inputfile);
+ }
+ else {
+ /* No command line arguments please */
+ int rank = -1;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ if (rank == 0) {
+ printf("Command line arguments are now disabled.\n");
+ printf("In particular, the input file must be called \"input\"\n");
+ printf("and be in the current working directory.\n");
+ }
+ }
-#ifdef PETSC
PetscFinalize();
-#endif
MPI_Finalize();
return 0;
diff --git a/src/model.c b/src/model.c
index 4ff5e8b0d..475b21325 100644
--- a/src/model.c
+++ b/src/model.c
@@ -10,7 +10,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2010-2022 The University of Edinburgh
+ * (c) 2010-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -113,6 +113,7 @@ int lb_data_create(pe_t * pe, cs_t * cs, const lb_data_options_t * options,
if (obj->fprime == NULL) pe_fatal(pe, "malloc(lb->fprime) failed\n");
if (options->usefirsttouch) {
lb_data_touch(obj);
+ pe_info(pe, "Host data: first touch\n");
}
else {
memset(obj->f, 0, sz);
@@ -509,9 +510,11 @@ __host__ void lb_data_touch_kernel(cs_limits_t lim, lb_t * lb) {
int kc = lim.kmin + (ik % stry)/strz;
int index = cs_index(lb->cs, ic, jc, kc);
for (int p = 0; p < lb->nvel; p++) {
- int lindex = LB_ADDR(lb->nsite, lb->ndist, lb->nvel, index, 1, p);
- lb->f[lindex] = 0.0;
- lb->fprime[lindex] = 0.0;
+ for (int n = 0; n < lb->ndist; n++) {
+ int lindex = LB_ADDR(lb->nsite, lb->ndist, lb->nvel, index, n, p);
+ lb->f[lindex] = 0.0;
+ lb->fprime[lindex] = 0.0;
+ }
}
}
@@ -1572,7 +1575,7 @@ int lb_io_write(lb_t * lb, int timestep, io_event_t * event) {
if (meta->iswriten == 0) {
/* No comments at the moment */
cJSON * comments = NULL;
- int ifail = io_metadata_write(meta, "dist", comments);
+ int ifail = io_metadata_write(meta, "dist", NULL, comments);
if (ifail == 0) lb->output.iswriten = 1;
}
diff --git a/src/nernst_planck.c b/src/nernst_planck.c
index 8a51a4b4d..dbc9e0c2b 100644
--- a/src/nernst_planck.c
+++ b/src/nernst_planck.c
@@ -57,7 +57,7 @@
* Edinbrugh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2012-2022 The University of Edinburgh
+ * (c) 2012-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -71,7 +71,6 @@
#include "pe.h"
#include "coords.h"
-#include "psi_s.h"
#include "advection.h"
#include "advection_bcs.h"
#include "nernst_planck.h"
@@ -94,6 +93,9 @@ static int nernst_planck_update_d3qx(psi_t * psi,
map_t * map, double ** flx);
static double max_acc;
+int np_advective_fluxes(psi_t * psi, hydro_t * hydro, double ** flux);
+int np_no_flux_boundary(psi_t * psi, map_t * map, double ** flux);
+
/*****************************************************************************
*
* nernst_planck_driver
@@ -188,18 +190,18 @@ static int nernst_planck_fluxes(psi_t * psi, fe_t * fel, double * fx,
fel->func->mu_solv(fel, index, n, &mu_s0);
mu0 = reunit*mu_s0
- + psi->valency[n]*psi->psi[addr_rank0(nsites, index)];
- rho0 = psi->rho[addr_rank1(nsites, nk, index, n)];
+ + psi->valency[n]*psi->psi->data[addr_rank0(nsites, index)];
+ rho0 = psi->rho->data[addr_rank1(nsites, nk, index, n)];
/* x-direction (between ic and ic+1) */
fel->func->mu_solv(fel, index + xs, n, &mu_s1);
mu1 = reunit*mu_s1
- + psi->valency[n]*psi->psi[addr_rank0(nsites, index + xs)];
+ + psi->valency[n]*psi->psi->data[addr_rank0(nsites, index + xs)];
b0 = exp(mu1 - mu0);
b1 = exp(mu1 - mu0);
- rho1 = psi->rho[addr_rank1(nsites, nk, (index + xs), n)]*b1;
+ rho1 = psi->rho->data[addr_rank1(nsites, nk, (index + xs), n)]*b1;
fx[addr_rank1(nsites, nk, index, n)]
= -psi->diffusivity[n]*0.5*(1.0 + b0)*(rho1 - rho0);
@@ -208,11 +210,11 @@ static int nernst_planck_fluxes(psi_t * psi, fe_t * fel, double * fx,
fel->func->mu_solv(fel, index + ys, n, &mu_s1);
mu1 = reunit*mu_s1
- + psi->valency[n]*psi->psi[addr_rank0(nsites, index + ys)];
+ + psi->valency[n]*psi->psi->data[addr_rank0(nsites, index + ys)];
b0 = exp(mu1 - mu0);
b1 = exp(mu1 - mu0);
- rho1 = psi->rho[addr_rank1(nsites, nk, (index + ys), n)]*b1;
+ rho1 = psi->rho->data[addr_rank1(nsites, nk, (index + ys), n)]*b1;
fy[nk*index + n] = -psi->diffusivity[n]*0.5*(1.0 + b0)*(rho1 - rho0);
@@ -220,11 +222,11 @@ static int nernst_planck_fluxes(psi_t * psi, fe_t * fel, double * fx,
fel->func->mu_solv(fel, index + zs, n, &mu_s1);
mu1 = reunit*mu_s1
- + psi->valency[n]*psi->psi[addr_rank0(nsites, index + zs)];
+ + psi->valency[n]*psi->psi->data[addr_rank0(nsites, index + zs)];
b0 = exp(mu1 - mu0);
b1 = exp(mu1 - mu0);
- rho1 = psi->rho[addr_rank1(nsites, nk, (index + zs), n)]*b1;
+ rho1 = psi->rho->data[addr_rank1(nsites, nk, (index + zs), n)]*b1;
fz[addr_rank1(nsites, nk, index, n)]
= -psi->diffusivity[n]*0.5*(1.0 + b0)*(rho1 - rho0);
@@ -317,7 +319,7 @@ static int nernst_planck_update(psi_t * psi, double * fx, double * fy,
index = cs_index(psi->cs, ic, jc, kc);
for (n = 0; n < nk; n++) {
- psi->rho[addr_rank1(psi->nsites, nk, index, n)]
+ psi->rho->data[addr_rank1(psi->nsites, nk, index, n)]
-= (+ fx[addr_rank1(psi->nsites, nk, index, n)]
- fx[addr_rank1(psi->nsites, nk, (index-xs), n)]
+ fy[addr_rank1(psi->nsites, nk, index, n)]
@@ -360,19 +362,20 @@ int nernst_planck_driver_d3qx(psi_t * psi, fe_t * fe, hydro_t * hydro,
if (flx == NULL) pe_fatal(psi->pe, "calloc(flx) failed\n");
for (ia = 0; ia < psi->nsites*nk; ia++) {
- flx[ia] = (double *) calloc(PSI_NGRAD-1, sizeof(double));
+ int nflux = psi->stencil->npoints;
+ flx[ia] = (double *) calloc(nflux-1, sizeof(double));
assert(flx[ia]);
if (flx[ia] == NULL) pe_fatal(psi->pe, "calloc(flx[]) failed\n");
}
/* Add advective fluxes */
- if (hydro) advective_fluxes_d3qx(hydro, nk, psi->rho, flx);
+ if (hydro) np_advective_fluxes(psi, hydro, flx);
/* Add diffusive fluxes */
nernst_planck_fluxes_d3qx(psi, fe, hydro, map, cinfo, flx);
/* Apply no-flux BC */
- if (map) advective_bcs_no_flux_d3qx(nk, flx, map);
+ if (map) np_no_flux_boundary(psi, map, flx);
/* Update charges */
nernst_planck_update_d3qx(psi, map, flx);
@@ -420,6 +423,11 @@ static int nernst_planck_fluxes_d3qx(psi_t * psi, fe_t * fe, hydro_t * hydro,
colloid_t * pc = NULL;
+ double * __restrict__ psidata = psi->psi->data;
+ double * __restrict__ rhodata = psi->rho->data;
+
+ LB_RCS_TABLE(rcs);
+
assert(psi);
assert(fe);
assert(fe->func->mu_solv);
@@ -445,10 +453,17 @@ static int nernst_planck_fluxes_d3qx(psi_t * psi, fe_t * fe, hydro_t * hydro,
continue;
}
else {
+ stencil_t * s = psi->stencil;
+ assert(s);
- for (c = 1; c < PSI_NGRAD; c++) {
+ for (c = 1; c < s->npoints; c++) {
- index1 = cs_index(psi->cs, ic + psi_gr_cv[c][X], jc + psi_gr_cv[c][Y], kc + psi_gr_cv[c][Z]);
+ int8_t cx = s->cv[c][X];
+ int8_t cy = s->cv[c][Y];
+ int8_t cz = s->cv[c][Z];
+ int8_t pcv = cx*cx + cy*cy + cz*cz;
+
+ index1 = cs_index(psi->cs, ic + cx, jc + cy, kc + cz);
map_status(map, index1, &status1);
if (status1 == MAP_FLUID) {
@@ -457,18 +472,18 @@ static int nernst_planck_fluxes_d3qx(psi_t * psi, fe_t * fe, hydro_t * hydro,
fe->func->mu_solv(fe, index0, n, &mu_s0);
mu0 = reunit*mu_s0
- + psi->valency[n]*psi->psi[addr_rank0(psi->nsites, index0)];
- rho0 = psi->rho[addr_rank1(psi->nsites, nk, index0, n)];
+ + psi->valency[n]*psidata[addr_rank0(psi->nsites, index0)];
+ rho0 = rhodata[addr_rank1(psi->nsites, nk, index0, n)];
fe->func->mu_solv(fe, index1, n, &mu_s1);
mu1 = reunit*mu_s1
- + psi->valency[n]* psi->psi[addr_rank0(psi->nsites, index1)];
+ + psi->valency[n]* psidata[addr_rank0(psi->nsites, index1)];
b0 = exp(mu0 - mu1);
b1 = exp(mu1 - mu0);
- rho1 = psi->rho[addr_rank1(psi->nsites, nk, index1, n)]*b1;
+ rho1 = rhodata[addr_rank1(psi->nsites, nk, index1, n)]*b1;
flx[addr_rank1(psi->nsites, nk, index0, n)][c - 1]
- -= psi->diffusivity[n]*0.5*(1.0 + b0)*(rho1 - rho0)*psi_gr_rnorm[c];
+ -= psi->diffusivity[n]*0.5*(1.0 + b0)*(rho1 - rho0)*rcs[pcv];
}
}
}
@@ -518,11 +533,15 @@ int nernst_planck_fluxes_force_d3qx(psi_t * psi, fe_t * fe, hydro_t * hydro,
double flocal[4] = {0.0, 0.0, 0.0, 0.0}, fsum[4], f[3];
double flxtmp[2];
double dt;
- double aux;
MPI_Comm comm;
colloid_t * pc = NULL;
+ double * __restrict__ psidata = psi->psi->data;
+ double * __restrict__ rhodata = psi->rho->data;
+
+ LB_RCS_TABLE(rcs);
+
assert(psi);
assert(flx);
@@ -553,7 +572,7 @@ int nernst_planck_fluxes_force_d3qx(psi_t * psi, fe_t * fe, hydro_t * hydro,
/* Total electrostatic force on colloid */
if (pc) {
- psi_electric_field_d3qx(psi, index0, e);
+ psi_electric_field(psi, index0, e);
f[X] = rho_elec * e[X] * dt;
f[Y] = rho_elec * e[Y] * dt;
@@ -566,10 +585,15 @@ int nernst_planck_fluxes_force_d3qx(psi_t * psi, fe_t * fe, hydro_t * hydro,
}
else {
- /* Internal electrostatic force on fluid */
- for (c = 1; c < PSI_NGRAD; c++) {
+ stencil_t * s = psi->stencil;
+ /* Internal electrostatic force on fluid */
+ for (c = 1; c < s->npoints; c++) {
+ int8_t cx = s->cv[c][X];
+ int8_t cy = s->cv[c][Y];
+ int8_t cz = s->cv[c][Z];
+ int8_t pcv = cx*cx + cy*cy + cz*cz;
- index1 = cs_index(psi->cs, ic + psi_gr_cv[c][X], jc + psi_gr_cv[c][Y], kc + psi_gr_cv[c][Z]);
+ index1 = cs_index(psi->cs, ic + cx, jc + cy, kc + cz);
map_status(map, index1, &status1);
if (status1 == MAP_FLUID) {
@@ -577,37 +601,27 @@ int nernst_planck_fluxes_force_d3qx(psi_t * psi, fe_t * fe, hydro_t * hydro,
for (n = 0; n < nk; n++) {
fe->func->mu_solv(fe, index0, n, &mu_s0);
mu0 = mu_s0
- + psi->valency[n]*eunit*psi->psi[addr_rank0(nsites, index0)];
- rho0 = psi->rho[addr_rank1(nsites, nk, index0, n)];
+ + psi->valency[n]*eunit*psidata[addr_rank0(nsites, index0)];
+ rho0 = rhodata[addr_rank1(nsites, nk, index0, n)];
fe->func->mu_solv(fe, index1, n, &mu_s1);
mu1 = mu_s1
- + psi->valency[n]*eunit*psi->psi[addr_rank0(nsites, index1)];
+ + psi->valency[n]*eunit*psidata[addr_rank0(nsites, index1)];
b0 = exp(-beta*(mu1 - mu0));
b1 = exp(+beta*(mu1 - mu0));
- rho1 = psi->rho[addr_rank1(nsites, nk, index1, n)]*b1;
+ rho1 = rhodata[addr_rank1(nsites, nk, index1, n)]*b1;
- /* Auxiliary terms */
- /* Adding flxtmp[1] to flxtmp[0] below subtracts the ideal gas part */
- flxtmp[0] = - 0.5*(1.0 + b0)*(rho1 - rho0) * psi_gr_rnorm[c];
- flxtmp[1] = (psi->rho[addr_rank1(nsites, nk, index1, n)]
- - psi->rho[addr_rank1(nsites, nk, index0, n)])
- * psi_gr_rnorm[c];
+ flxtmp[0] = - 0.5*(1.0 + b0)*(rho1 - rho0)*rcs[pcv];
- /* Link flux */
+ /* Diffusive flux accumulated */
flx[addr_rank1(nsites, nk, index0, n)][c - 1] += psi->diffusivity[n]*flxtmp[0];
- /* Force on fluid including ideal gas part in chemical potential */
- aux = psi_gr_rcs2 * psi_gr_wv[c] * flxtmp[0] * rbeta;
-
- f[X] -= aux * psi_gr_cv[c][X];
- f[Y] -= aux * psi_gr_cv[c][Y];
- f[Z] -= aux * psi_gr_cv[c][Z];
-
+ /* Force, including ideal gas part in chemical potential */
+ f[X] -= s->wgradients[c]*cx*flxtmp[0]*rbeta;
+ f[Y] -= s->wgradients[c]*cy*flxtmp[0]*rbeta;
+ f[Z] -= s->wgradients[c]*cz*flxtmp[0]*rbeta;
}
-
}
-
}
/* Electrostatic force in external field */
@@ -647,19 +661,13 @@ int nernst_planck_fluxes_force_d3qx(psi_t * psi, fe_t * fe, hydro_t * hydro,
index0 = cs_index(psi->cs, ic, jc, kc);
colloids_info_map(cinfo, index0, &pc);
- if (pc) {
- continue;
- }
- else {
-
- f[X] = -fsum[X];
- f[Y] = -fsum[Y];
- f[Z] = -fsum[Z];
-
- if (hydro) hydro_f_local_add(hydro, index0, f);
+ if (pc) continue;
- }
+ f[X] = -fsum[X];
+ f[Y] = -fsum[Y];
+ f[Z] = -fsum[Z];
+ if (hydro) hydro_f_local_add(hydro, index0, f);
}
}
}
@@ -703,16 +711,17 @@ static int nernst_planck_update_d3qx(psi_t * psi, map_t * map, double ** flx) {
map_status(map, index, &status);
if (status == MAP_FLUID) {
+ stencil_t * s = psi->stencil;
for (n = 0; n < nk; n++) {
acc = 0.0;
- for (c = 1; c < PSI_NGRAD; c++) {
- psi->rho[addr_rank1(nsites, nk, index, n)]
+ for (c = 1; c < s->npoints; c++) {
+ psi->rho->data[addr_rank1(nsites, nk, index, n)]
-= flx[addr_rank1(nsites, nk, index, n)][c - 1] * dt;
acc += fabs(flx[addr_rank1(nsites, nk, index, n)][c - 1] * dt);
}
- acc /= fabs(psi->rho[addr_rank1(nsites, nk, index, n)]);
+ acc /= fabs(psi->rho->data[addr_rank1(nsites, nk, index, n)]);
if (maxacc < acc) maxacc = acc;
}
}
@@ -784,7 +793,7 @@ int nernst_planck_adjust_multistep(psi_t * psi) {
if (* maxacc > diffacc && diffacc > 0.0) {
psi_multisteps(psi, &multisteps);
multisteps *= 2;
- psi_multisteps_set(psi, multisteps);
+ psi->multisteps = multisteps;
pe_info(psi->pe, "\nMaxacc > diffacc: changing no. of multisteps to %d\n",
multisteps);
}
@@ -800,11 +809,11 @@ int nernst_planck_adjust_multistep(psi_t * psi) {
psi_diffusivity(psi, n, &diff);
if (diff > diffmax) diffmax = diff;
}
-
+
/* Only reduce if sanity criteria fulfilled */
if (multisteps > 1 && diffmax/multisteps < 0.05) {
multisteps *= 0.5;
- psi_multisteps_set(psi, multisteps);
+ psi->multisteps = multisteps;
pe_info(psi->pe, "\nMaxacc << diffacc: changing no. of multisteps to %d\n", multisteps);
}
@@ -812,3 +821,125 @@ int nernst_planck_adjust_multistep(psi_t * psi) {
return 0;
}
+
+/*****************************************************************************
+ *
+ * np_advective_fluxes
+ *
+ * 'Centred difference' advective fluxes for the char densities rho.
+ *
+ * Symmetric two-point stencil.
+ *
+ *****************************************************************************/
+
+int np_advective_fluxes(psi_t * psi, hydro_t * hydro, double ** flx) {
+
+ int nlocal[3] = {0};
+ cs_t * cs = NULL;
+ stencil_t * s = NULL;
+
+ double * __restrict__ rho = psi->rho->data;
+
+ assert(psi);
+ assert(hydro);
+ assert(flx);
+
+ cs = psi->cs;
+ s = psi->stencil;
+ assert(cs);
+ assert(s);
+
+ cs_nlocal(cs, nlocal);
+
+ for (int ic = 1; ic <= nlocal[X]; ic++) {
+ for (int jc = 1; jc <= nlocal[Y]; jc++) {
+ for (int kc = 1; kc <= nlocal[Z]; kc++) {
+
+ int index0 = cs_index(cs, ic, jc, kc);
+ double u0[3] = {0};
+ hydro_u(hydro, index0, u0);
+
+ for (int p = 1; p < s->npoints; p++) {
+
+ int8_t cx = s->cv[p][X];
+ int8_t cy = s->cv[p][Y];
+ int8_t cz = s->cv[p][Z];
+ int index1 = cs_index(cs, ic + cx, jc + cy, kc + cz);
+ double u1[3] = {0};
+ double u = 0.0;
+ hydro_u(hydro, index1, u1);
+
+ u = 0.5*((u0[X]+u1[X])*cx + (u0[Y]+u1[Y])*cy + (u0[Z]+u1[Z])*cz);
+
+ for (int n = 0; n < psi->nk; n++) {
+ double rho0 = rho[addr_rank1(psi->nsites, psi->nk, index0, n)];
+ double rho1 = rho[addr_rank1(psi->nsites, psi->nk, index1, n)];
+ double flux = u*0.5*(rho0 + rho1);
+ flx[addr_rank1(psi->nsites, psi->nk, index0, n)][p-1] = flux;
+ }
+ }
+ /* Next site */
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * advective_bcs_no_flux_d3qx
+ *
+ * Set normal fluxes at solid fluid interfaces to zero.
+ *
+ *****************************************************************************/
+
+int np_no_flux_boundary(psi_t * psi, map_t * map, double ** flx) {
+
+ int nlocal[3] = {0};
+ cs_t * cs = NULL;
+ stencil_t * s = NULL;
+
+ assert(psi);
+ assert(map);
+ assert(flx);
+
+ cs = psi->cs;
+ s = psi->stencil;
+ assert(cs);
+ assert(s);
+
+ cs_nlocal(cs, nlocal);
+
+ for (int ic = 1; ic <= nlocal[X]; ic++) {
+ for (int jc = 1; jc <= nlocal[Y]; jc++) {
+ for (int kc = 1; kc <= nlocal[Z]; kc++) {
+
+ int index0 = cs_index(cs, ic, jc, kc);
+ int mask0 = 1;
+ int status = MAP_BOUNDARY;
+ map_status(map, index0, &status);
+ mask0 = (status == MAP_FLUID);
+
+ for (int p = 1; p < s->npoints; p++) {
+
+ int8_t cx = s->cv[p][X];
+ int8_t cy = s->cv[p][Y];
+ int8_t cz = s->cv[p][Z];
+ int index1 = cs_index(cs, ic + cx, jc + cy, kc + cz);
+ int mask = 1;
+
+ map_status(map, index1, &status);
+ mask = (status == MAP_FLUID);
+ mask = mask*mask0;
+
+ for (int n = 0; n < psi->nk; n++) {
+ flx[addr_rank1(psi->nsites, psi->nk, index0, n)][p-1] *= mask;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/src/psi.c b/src/psi.c
index d29ae487d..6fcff1fd0 100644
--- a/src/psi.c
+++ b/src/psi.c
@@ -9,7 +9,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2012-2022 The University of Edinburgh
+ * (c) 2012-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -18,472 +18,222 @@
*****************************************************************************/
#include
-#include
-#include
#include
-#include
#include
-#include
-
-#include "pe.h"
-#include "coords.h"
-#include "coords_field.h"
-#include "io_harness.h"
-#include "util.h"
-#include "map.h"
-#include "psi_s.h"
-#include "psi_gradients.h"
-
-static const double e_unit_default = 1.0; /* Default unit charge */
-static const double reltol_default = FLT_EPSILON; /* Solver tolerance */
-static const double abstol_default = 0.01*FLT_EPSILON;
-static const int maxits_default = 10000; /* Default number of iterations in Poisson solver */
-static const int multisteps_default = 1; /* Default number of multisteps in NPE */
-static const int skipsteps_default = 1; /* Default number of skipped timesteps in Poisson solver */
-static const double diffacc_default = 0; /* Default diffusive accuracy in NPE for constant no. of multisteps */
-
-static int psi_read(FILE * fp, int index, void * self);
-static int psi_write(FILE * fp, int index, void * self);
-static int psi_read_ascii(FILE * fp, int index, void * self);
-static int psi_write_ascii(FILE * fp, int index, void * self);
+
+#include "psi.h"
/*****************************************************************************
*
* psi_create
*
- * Initialise the electric potential, nk charge density fields.
- *
*****************************************************************************/
-int psi_create(pe_t * pe, cs_t * cs, int nk, psi_t ** pobj) {
+int psi_create(pe_t * pe, cs_t * cs, const psi_options_t * opts,
+ psi_t ** pobj) {
- int nsites;
- int nhalo;
+ int ifail = 0;
psi_t * psi = NULL;
- assert(pe);
- assert(cs);
assert(pobj);
- assert(nk > 1);
- assert(nk <= PSI_NKMAX);
-
- cs_nsites(cs, &nsites);
- cs_nhalo(cs, &nhalo);
psi = (psi_t *) calloc(1, sizeof(psi_t));
- assert(psi);
- if (psi == NULL) pe_fatal(pe, "Allocation of psi failed\n");
-
- psi->pe = pe;
- psi->cs = cs;
-
- psi->nk = nk;
- psi->nsites = nsites;
- psi->psi = (double *) calloc(nsites, sizeof(double));
- psi->rho = (double *) calloc((size_t) nk*nsites, sizeof(double));
- psi->diffusivity = (double *) calloc(nk, sizeof(double));
- psi->valency = (int *) calloc(nk, sizeof(int));
-
- if (psi->psi == NULL) pe_fatal(pe, "Allocation of psi->psi failed\n");
- if (psi->rho == NULL) pe_fatal(pe, "Allocation of psi->rho failed\n");
- if (psi->diffusivity == NULL) pe_fatal(pe, "psi->diffusivity failed\n");
- if (psi->valency == NULL) pe_fatal(pe, "calloc(psi->valency) failed\n");
-
- psi->e = e_unit_default;
- psi->reltol = reltol_default;
- psi->abstol = abstol_default;
- psi->maxits = maxits_default;
- psi->multisteps = multisteps_default;
- psi->skipsteps = skipsteps_default;
- psi->diffacc = diffacc_default;
-
- psi->nfreq_io = INT_MAX;
- psi->nfreq = INT_MAX;
- psi->beta = 1.0; /* Not zero default */
-
- coords_field_init_mpi_indexed(cs, nhalo, 1, MPI_DOUBLE, psi->psihalo);
- coords_field_init_mpi_indexed(cs, nhalo, psi->nk, MPI_DOUBLE, psi->rhohalo);
+ if (psi == NULL) goto err;
- *pobj = psi;
+ ifail = psi_initialise(pe, cs, opts, psi);
+ if (ifail != 0) goto err;
+
+ *pobj = psi;
return 0;
-}
-
-/*****************************************************************************
- *
- * psi_io_info
- *
- *****************************************************************************/
-
-int psi_io_info(psi_t * obj, io_info_t ** info) {
-
- assert(obj);
- assert(info);
-
- *info = obj->info;
- return 0;
+ err:
+ if (psi) free(psi);
+ return -1;
}
/*****************************************************************************
*
- * psi_halo_psi
+ * psi_free
*
*****************************************************************************/
-int psi_halo_psi(psi_t * psi) {
-
- int nh;
+int psi_free(psi_t ** psi) {
assert(psi);
+ assert(*psi);
- cs_nhalo(psi->cs, &nh); /* Swap full halo */
- coords_field_halo_rank1(psi->cs, psi->nsites, nh, 1, psi->psi, MPI_DOUBLE);
+ psi_finalise(*psi);
+ free(*psi);
+ *psi = NULL;
return 0;
}
/*****************************************************************************
*
- * psi_halo_rho
+ * psi_initialise
*
*****************************************************************************/
-int psi_halo_rho(psi_t * psi) {
+int psi_initialise(pe_t * pe, cs_t * cs, const psi_options_t * opts,
+ psi_t * psi) {
- int nh;
+ int ifail = 0;
+ assert(pe);
+ assert(cs);
+ assert(opts);
assert(psi);
- cs_nhalo(psi->cs, &nh); /* Swap full halo */
- coords_field_halo_rank1(psi->cs, psi->nsites, nh, psi->nk, psi->rho,
- MPI_DOUBLE);
- return 0;
-}
-
-/*****************************************************************************
- *
- * psi_nk
- *
- *****************************************************************************/
-
-int psi_nk(psi_t * obj, int * nk) {
-
- assert(obj);
-
- *nk = obj->nk;
-
- return 0;
-}
+ psi->pe = pe;
+ psi->cs = cs;
-/*****************************************************************************
- *
- * psi_valency_set
- *
- *****************************************************************************/
+ psi->nk = opts->nk;
+ cs_nsites(cs, &psi->nsites);
-int psi_valency_set(psi_t * obj, int n, int iv) {
+ psi->e = opts->e;
+ psi->beta = opts->beta;
+ psi->epsilon = opts->epsilon1;
+ psi->epsilon2 = opts->epsilon2;
- assert(obj);
- assert(n < obj->nk);
+ psi->e0[X] = opts->e0[X];
+ psi->e0[Y] = opts->e0[Y];
+ psi->e0[Z] = opts->e0[Z];
- obj->valency[n] = iv;
+ psi->diffusivity = (double *) calloc(opts->nk, sizeof(double));
+ psi->valency = (int *) calloc(opts->nk, sizeof(int));
- return 0;
-}
+ if (psi->diffusivity == NULL) pe_fatal(pe, "psi->diffusivity failed\n");
+ if (psi->valency == NULL) pe_fatal(pe, "calloc(psi->valency) failed\n");
-/*****************************************************************************
- *
- * psi_valency
- *
- *****************************************************************************/
+ for (int n = 0; n < opts->nk; n++) {
+ psi->diffusivity[n] = opts->diffusivity[n];
+ psi->valency[n] = opts->valency[n];
+ }
-int psi_valency(psi_t * obj, int n, int * iv) {
+ /* Solver options */
+ psi->solver = opts->solver;
+ ifail = stencil_create(opts->solver.nstencil, &psi->stencil);
+
+ /* Nernst-Planck */
+ psi->multisteps = opts->nsmallstep;
+ psi->diffacc = opts->diffacc;
+
+ /* Other */
+ {
+ /* Unfortunately, "rho" is not available for the charge density,
+ * as it would conflict with the fluid density. */
+ lees_edw_t * le = NULL;
+ field_create(pe, cs, le, "psi", &opts->psi, &psi->psi);
+ field_create(pe, cs, le, "qsi", &opts->rho, &psi->rho);
+ }
- assert(obj);
- assert(n < obj->nk);
- assert(iv);
+ psi->nfreq_io = INT_MAX;
- *iv = obj->valency[n];
+ /* Copy of the options structure */
+ psi->options = *opts;
- return 0;
+ return ifail;
}
/*****************************************************************************
*
- * psi_diffusivity_set
+ * psi_finalise
*
*****************************************************************************/
-int psi_diffusivity_set(psi_t * obj, int n, double diff) {
-
- assert(obj);
- assert(n < obj->nk);
-
- obj->diffusivity[n] = diff;
-
- return 0;
-}
+int psi_finalise(psi_t * psi) {
-/*****************************************************************************
- *
- * psi_diffusivity
- *
- *****************************************************************************/
+ assert(psi->psi);
-int psi_diffusivity(psi_t * obj, int n, double * diff) {
+ stencil_free(&psi->stencil);
+ field_free(psi->rho);
+ field_free(psi->psi);
- assert(obj);
- assert(n < obj->nk);
- assert(diff);
+ free(psi->valency);
+ free(psi->diffusivity);
- *diff = obj->diffusivity[n];
+ *psi = (psi_t) {0};
return 0;
}
/*****************************************************************************
*
- * psi_e0_set
- *
- * Set external electric field.
+ * psi_halo_psi
*
*****************************************************************************/
-int psi_e0_set(psi_t * psi, const double e0[3]) {
+int psi_halo_psi(psi_t * psi) {
assert(psi);
- psi->e0[X] = e0[X];
- psi->e0[Y] = e0[Y];
- psi->e0[Z] = e0[Z];
+ field_halo(psi->psi);
return 0;
}
/*****************************************************************************
*
- * psi_init_io_info
- *
- * The I/O grid will be requested with Cartesian extent as given.
- *
- * Register all the I/O functions, and set the input/output format
- * appropriately.
+ * psi_halo_rho
*
*****************************************************************************/
-int psi_init_io_info(psi_t * obj, int grid[3], int form_in, int form_out) {
-
- io_info_args_t args = io_info_args_default();
-
- assert(obj);
- assert(grid);
- assert(obj->info == NULL);
-
- args.grid[X] = grid[X];
- args.grid[Y] = grid[Y];
- args.grid[Z] = grid[Z];
-
- io_info_create(obj->pe, obj->cs, &args, &obj->info);
- if (obj->info == NULL) pe_fatal(obj->pe, "io_info_create(psi) failed\n");
-
- io_info_set_name(obj->info, "Potential and charge densities");
-
- io_info_read_set(obj->info, IO_FORMAT_BINARY, psi_read);
- io_info_read_set(obj->info, IO_FORMAT_ASCII, psi_read_ascii);
- io_info_write_set(obj->info, IO_FORMAT_BINARY, psi_write);
- io_info_write_set(obj->info, IO_FORMAT_ASCII, psi_write_ascii);
+int psi_halo_rho(psi_t * psi) {
- io_info_set_bytesize(obj->info, IO_FORMAT_BINARY, (2+obj->nk)*sizeof(double));
- io_info_set_bytesize(obj->info, IO_FORMAT_ASCII, (2+obj->nk)*23 + 1);
+ assert(psi);
- io_info_format_set(obj->info, form_in, form_out);
- io_info_metadata_filestub_set(obj->info, "psi");
+ field_halo(psi->rho);
return 0;
}
/*****************************************************************************
*
- * psi_free
- *
- *****************************************************************************/
-
-void psi_free(psi_t * obj) {
-
- int n;
-
- assert(obj);
-
- for (n = 0; n < 3; n++) {
- MPI_Type_free(&obj->psihalo[n]);
- MPI_Type_free(&obj->rhohalo[n]);
- }
-
- if (obj->info) io_info_free(obj->info);
-
- free(obj->valency);
- free(obj->diffusivity);
- free(obj->rho);
- free(obj->psi);
- free(obj);
- obj = NULL;
-
- return;
-}
-
-/*****************************************************************************
- *
- * psi_write_ascii
- *
- * Returns 0 on success.
+ * psi_nk
*
*****************************************************************************/
-static int psi_write_ascii(FILE * fp, int index, void * self) {
-
- int n, nwrite;
- int nsites;
- double rho_el;
- psi_t * obj = (psi_t*) self;
+int psi_nk(psi_t * obj, int * nk) {
assert(obj);
- assert(fp);
-
- cs_nsites(obj->cs, &nsites);
-
- nwrite = fprintf(fp, "%22.15e ", obj->psi[addr_rank0(nsites,index)]);
- if (nwrite != 23) {
- pe_fatal(obj->pe, "fprintf(psi) failed at index %d\n", index);
- }
-
- for (n = 0; n < obj->nk; n++) {
- nwrite = fprintf(fp, "%22.15e ", obj->rho[addr_rank1(nsites, obj->nk, index, n)]);
- if (nwrite != 23) pe_fatal(obj->pe, "fprintf(rho) failed at index %d %d\n", index, n);
- }
-
- psi_rho_elec(obj, index, &rho_el);
- nwrite = fprintf(fp, "%22.15e ", rho_el);
- if (nwrite != 23) {
- pe_fatal(obj->pe, "fprintf(rho_el) failed at index %d\n", index);
- }
-
- nwrite = fprintf(fp, "\n");
- if (nwrite != 1) pe_fatal(obj->pe, "fprintf() failed at index %d\n", index);
-
- return 0;
-}
-/*****************************************************************************
- *
- * psi_read_ascii
- *
- * Returns 0 on success.
- *
- *****************************************************************************/
-
-static int psi_read_ascii(FILE * fp, int index, void * self) {
-
- int n, nread;
- int nsites;
- int indexf;
- double rho_el;
- psi_t * obj = (psi_t*) self;
-
- assert(fp);
- assert(self);
-
- cs_nsites(obj->cs, &nsites);
-
- indexf = addr_rank0(nsites, index);
- nread = fscanf(fp, "%le", obj->psi + indexf);
- if (nread != 1) pe_fatal(obj->pe, "fscanf(psi) failed %d\n", index);
-
- for (n = 0; n < obj->nk; n++) {
- indexf = addr_rank1(nsites, obj->nk, index, n);
- nread = fscanf(fp, "%le", obj->rho + indexf);
- if (nread != 1) pe_fatal(obj->pe, "fscanf(rho) failed %d %d\n", index, n);
- }
-
- nread = fscanf(fp, "%le", &rho_el);
- if (nread != 1) pe_fatal(obj->pe, "fscanf(rho_el) failed %d %d\n", index, n);
+ *nk = obj->nk;
return 0;
}
/*****************************************************************************
*
- * psi_write
- *
- * Returns 0 on success.
+ * psi_valency
*
*****************************************************************************/
-static int psi_write(FILE * fp, int index, void * self) {
-
- int n;
- int na;
- int nsites;
- int indexf;
- double rho_el;
- psi_t * obj = (psi_t*) self;
+int psi_valency(psi_t * obj, int n, int * iv) {
- assert(fp);
assert(obj);
+ assert(n < obj->nk);
+ assert(iv);
- cs_nsites(obj->cs, &nsites);
-
- indexf = addr_rank0(nsites, index);
- n = fwrite(obj->psi + indexf, sizeof(double), 1, fp);
- if (n != 1) pe_fatal(obj->pe, "fwrite(psi) failed at index %d\n", index);
-
- for (na = 0; na < obj->nk; na++) {
- indexf = addr_rank1(nsites, obj->nk, index, na);
- n = fwrite(obj->rho + indexf, sizeof(double), 1, fp);
- if (n != 1) pe_fatal(obj->pe, "fwrite(rho) failed at index %d\n", index);
- }
-
- psi_rho_elec(obj, index, &rho_el);
- n = fwrite(&rho_el, sizeof(double), 1, fp);
- if (n != 1) pe_fatal(obj->pe, "fwrite(rho_el) failed at index %d", index);
+ *iv = obj->valency[n];
return 0;
}
/*****************************************************************************
*
- * psi_read
- *
- * Returns 0 on success.
+ * psi_diffusivity
*
*****************************************************************************/
-static int psi_read(FILE * fp, int index, void * self) {
-
- int n;
- int na;
- int nsites;
- int indexf;
- double rho_el;
- psi_t * obj = (psi_t*) self;
+int psi_diffusivity(psi_t * obj, int n, double * diff) {
- assert(fp);
assert(obj);
+ assert(n < obj->nk);
+ assert(diff);
- cs_nsites(obj->cs, &nsites);
-
- indexf = addr_rank0(nsites, index);
- n = fread(obj->psi + indexf, sizeof(double), 1, fp);
- if (n != 1) pe_fatal(obj->pe, "fread(psi) failed at index %d\n", index);
-
- for (na = 0; na < obj->nk; na++) {
- indexf = addr_rank1(nsites, obj->nk, index, na);
- n = fread(obj->rho + indexf, sizeof(double), 1, fp);
- if (n != 1) pe_fatal(obj->pe, "fread(rho) failed at index %d\n", index);
- }
-
- n = fread(&rho_el, sizeof(double), 1, fp);
- if (n != 1) pe_fatal(obj->pe, "fread(rho_el) failed at index %d\n", index);
+ *diff = obj->diffusivity[n];
return 0;
}
@@ -498,14 +248,14 @@ static int psi_read(FILE * fp, int index, void * self) {
int psi_rho_elec(psi_t * obj, int index, double * rho) {
- int n;
double rho_elec = 0.0;
assert(obj);
assert(rho);
- for (n = 0; n < obj->nk; n++) {
- rho_elec += obj->e*obj->valency[n]*obj->rho[addr_rank1(obj->nsites, obj->nk, index, n)];
+ for (int n = 0; n < obj->nk; n++) {
+ int irho = addr_rank1(obj->nsites, obj->nk, index, n);
+ rho_elec += obj->e*obj->valency[n]*obj->rho->data[irho];
}
*rho = rho_elec;
@@ -524,7 +274,7 @@ int psi_rho(psi_t * obj, int index, int n, double * rho) {
assert(rho);
assert(n < obj->nk);
- *rho = obj->rho[addr_rank1(obj->nsites, obj->nk, index, n)];
+ *rho = obj->rho->data[addr_rank1(obj->nsites, obj->nk, index, n)];
return 0;
}
@@ -540,7 +290,7 @@ int psi_rho_set(psi_t * obj, int index, int n, double rho) {
assert(obj);
assert(n < obj->nk);
- obj->rho[addr_rank1(obj->nsites, obj->nk, index, n)] = rho;
+ obj->rho->data[addr_rank1(obj->nsites, obj->nk, index, n)] = rho;
return 0;
}
@@ -556,7 +306,7 @@ int psi_psi(psi_t * obj, int index, double * psi) {
assert(obj);
assert(psi);
- *psi = obj->psi[addr_rank0(obj->nsites, index)];
+ *psi = obj->psi->data[addr_rank0(obj->nsites, index)];
return 0;
}
@@ -571,7 +321,7 @@ int psi_psi_set(psi_t * obj, int index, double psi) {
assert(obj);
- obj->psi[addr_rank0(obj->nsites, index)] = psi;
+ obj->psi->data[addr_rank0(obj->nsites, index)] = psi;
return 0;
}
@@ -592,21 +342,6 @@ int psi_unit_charge(psi_t * obj, double * eunit) {
return 0;
}
-/*****************************************************************************
- *
- * psi_unit_charge_set
- *
- *****************************************************************************/
-
-int psi_unit_charge_set(psi_t * obj, double eunit) {
-
- assert(obj);
-
- obj->e = eunit;
-
- return 0;
-}
-
/*****************************************************************************
*
* psi_beta
@@ -623,21 +358,6 @@ int psi_beta(psi_t * obj, double * beta) {
return 0;
}
-/*****************************************************************************
- *
- * psi_beta_set
- *
- *****************************************************************************/
-
-int psi_beta_set(psi_t * obj, double beta) {
-
- assert(obj);
-
- obj->beta = beta;
-
- return 0;
-}
-
/*****************************************************************************
*
* psi_epsilon
@@ -654,21 +374,6 @@ int psi_epsilon(psi_t * obj, double * epsilon) {
return 0;
}
-/*****************************************************************************
- *
- * psi_epsilon_set
- *
- *****************************************************************************/
-
-int psi_epsilon_set(psi_t * obj, double epsilon) {
-
- assert(obj);
-
- obj->epsilon = epsilon;
-
- return 0;
-}
-
/*****************************************************************************
*
* psi_epsilon2
@@ -685,22 +390,6 @@ int psi_epsilon2(psi_t * obj, double * epsilon2) {
return 0;
}
-
-/*****************************************************************************
- *
- * psi_epsilon2_set
- *
- *****************************************************************************/
-
-int psi_epsilon2_set(psi_t * obj, double epsilon2) {
-
- assert(obj);
-
- obj->epsilon2 = epsilon2;
-
- return 0;
-}
-
/*****************************************************************************
*
* psi_ionic_strength
@@ -712,110 +401,18 @@ int psi_epsilon2_set(psi_t * obj, double epsilon2) {
int psi_ionic_strength(psi_t * psi, int index, double * sion) {
- int n;
assert(psi);
assert(sion);
*sion = 0.0;
- for (n = 0; n < psi->nk; n++) {
+ for (int n = 0; n < psi->nk; n++) {
*sion += 0.5*psi->valency[n]*psi->valency[n]
- *psi->rho[addr_rank1(psi->nsites, psi->nk, index, n)];
+ *psi->rho->data[addr_rank1(psi->nsites, psi->nk, index, n)];
}
return 0;
}
-/*****************************************************************************
- *
- * psi_bjerrum_length
- *
- * Is equal to e^2 / 4 pi epsilon k_B T
- *
- *****************************************************************************/
-
-int psi_bjerrum_length(psi_t * obj, double * lb) {
-
- PI_DOUBLE(pi);
-
- assert(obj);
- assert(lb);
-
- *lb = obj->e*obj->e*obj->beta / (4.0*pi*obj->epsilon);
-
- return 0;
-}
-
-
-/*****************************************************************************
- *
- * psi_bjerrum_length2
- *
- * Is equal to e^2 / 4 pi epsilon2 k_B T if we have
- * a dielectric contrast between the electrolytes.
- *
- *****************************************************************************/
-
-int psi_bjerrum_length2(psi_t * obj, double * lb) {
-
- PI_DOUBLE(pi);
-
- assert(obj);
- assert(lb);
-
- *lb = obj->e*obj->e*obj->beta / (4.0*pi*obj->epsilon2);
-
- return 0;
-}
-
-/*****************************************************************************
- *
- * psi_debye_length
- *
- * Returns the Debye length for a simple, symmetric electrolyte.
- * An ionic strength is required as input (see above); this
- * accounts for the factor of 8 in the denominator.
- *
- *****************************************************************************/
-
-int psi_debye_length(psi_t * obj, double rho_b, double * ld) {
-
- double lb;
- PI_DOUBLE(pi);
-
- assert(obj);
- assert(ld);
-
- psi_bjerrum_length(obj, &lb);
- *ld = 1.0 / sqrt(8.0*pi*lb*rho_b);
-
- return 0;
-}
-
-/*****************************************************************************
- *
- * psi_debye_length2
- *
- * Returns the Debye length for the second phase if we
- * have a dielectric contrast between the electrolytes.
- * An ionic strength is required as input (see above); this
- * accounts for the factor of 8 in the denominator.
- *
- *****************************************************************************/
-
-int psi_debye_length2(psi_t * obj, double rho_b, double * ld) {
-
- double lb;
- PI_DOUBLE(pi);
-
- assert(obj);
- assert(ld);
-
- psi_bjerrum_length2(obj, &lb);
- *ld = 1.0 / sqrt(8.0*pi*lb*rho_b);
-
- return 0;
-}
-
/*****************************************************************************
*
* psi_surface_potential
@@ -859,7 +456,7 @@ int psi_reltol(psi_t * obj, double * reltol) {
assert(obj);
assert(reltol);
- *reltol = obj->reltol;
+ *reltol = obj->solver.reltol;
return 0;
}
@@ -877,53 +474,7 @@ int psi_abstol(psi_t * obj, double * abstol) {
assert(obj);
assert(abstol);
- *abstol = obj->abstol;
-
- return 0;
-}
-
-/*****************************************************************************
- *
- * psi_reltol_set
- *
- *****************************************************************************/
-
-int psi_reltol_set(psi_t * obj, double reltol) {
-
- assert(obj);
-
- obj->reltol = reltol;
-
- return 0;
-}
-
-/*****************************************************************************
- *
- * psi_abstol_set
- *
- *****************************************************************************/
-
-int psi_abstol_set(psi_t * obj, double abstol) {
-
- assert(obj);
-
- obj->abstol = abstol;
-
- return 0;
-}
-
-/*****************************************************************************
- *
- * psi_multisteps_set
- *
- *****************************************************************************/
-
-int psi_multisteps_set(psi_t * obj, int multisteps) {
-
- assert(obj);
- assert(multisteps);
-
- obj->multisteps = multisteps;
+ *abstol = obj->solver.abstol;
return 0;
}
@@ -959,22 +510,6 @@ int psi_multistep_timestep(psi_t * obj, double * dt) {
return 0;
}
-/*****************************************************************************
- *
- * psi_maxits_set
- *
- *****************************************************************************/
-
-int psi_maxits_set(psi_t * obj, int maxits) {
-
- assert(obj);
- assert(maxits);
-
- obj->maxits = maxits;
-
- return 0;
-}
-
/*****************************************************************************
*
* psi_maxits
@@ -986,7 +521,7 @@ int psi_maxits(psi_t * obj, int * maxits) {
assert(obj);
assert(maxits);
- *maxits = obj->maxits;
+ *maxits = obj->solver.maxits;
return 0;
}
@@ -1023,35 +558,6 @@ int psi_diffacc(psi_t * obj, double * diffacc) {
return 0;
}
-/*****************************************************************************
- *
- * psi_skipsteps_set
- *
- *****************************************************************************/
-
-int psi_skipsteps_set(psi_t * obj, double skipsteps) {
-
- assert(obj);
- assert(skipsteps>=1);
-
- obj->skipsteps = skipsteps;
-
- return 0;
-}
-
-/*****************************************************************************
- *
- * psi_skipsteps
- *
- *****************************************************************************/
-
-int psi_skipsteps(psi_t * obj) {
-
- assert(obj);
-
- return obj->skipsteps;
-}
-
/*****************************************************************************
*
* psi_zero_mean
@@ -1139,6 +645,8 @@ int psi_halo_psijump(psi_t * psi) {
double eps;
double beta;
+ double * psidata = psi->psi->data;
+
assert(psi);
cs_nhalo(psi->cs, &nhalo);
@@ -1162,13 +670,13 @@ int psi_halo_psijump(psi_t * psi) {
if (periodic[X]) {
/* Add external potential */
- psi->psi[addr_rank0(psi->nsites, index)] += psi->e0[X]*ntotal[X];
+ psidata[addr_rank0(psi->nsites, index)] += psi->e0[X]*ntotal[X];
}
else{
/* Borrow fluid site ic = 1 */
index1 = cs_index(psi->cs, 1, jc, kc);
- psi->psi[addr_rank0(psi->nsites, index)] =
- psi->psi[addr_rank0(psi->nsites, index1)];
+ psidata[addr_rank0(psi->nsites, index)] =
+ psidata[addr_rank0(psi->nsites, index1)];
}
}
}
@@ -1186,13 +694,13 @@ int psi_halo_psijump(psi_t * psi) {
if (periodic[X]) {
/* Subtract external potential */
- psi->psi[addr_rank0(psi->nsites, index)] -= psi->e0[X]*ntotal[X];
+ psidata[addr_rank0(psi->nsites, index)] -= psi->e0[X]*ntotal[X];
}
else {
/* Borrow fluid site at end ... */
index1 = cs_index(psi->cs, nlocal[X], jc, kc);
- psi->psi[addr_rank0(psi->nsites, index)] =
- psi->psi[addr_rank0(psi->nsites, index1)];
+ psidata[addr_rank0(psi->nsites, index)] =
+ psidata[addr_rank0(psi->nsites, index1)];
}
}
}
@@ -1209,13 +717,13 @@ int psi_halo_psijump(psi_t * psi) {
if (periodic[Y]) {
/* Add external potential */
- psi->psi[addr_rank0(psi->nsites, index)] += psi->e0[Y]*ntotal[Y];
+ psidata[addr_rank0(psi->nsites, index)] += psi->e0[Y]*ntotal[Y];
}
else {
/* Not periodic ... just borrow from fluid site jc = 1 */
index1 = cs_index(psi->cs, ic, 1, kc);
- psi->psi[addr_rank0(psi->nsites, index)] =
- psi->psi[addr_rank0(psi->nsites, index1)];
+ psidata[addr_rank0(psi->nsites, index)] =
+ psidata[addr_rank0(psi->nsites, index1)];
}
}
}
@@ -1233,13 +741,13 @@ int psi_halo_psijump(psi_t * psi) {
if (periodic[Y]) {
/* Subtract external potential */
- psi->psi[addr_rank0(psi->nsites, index)] -= psi->e0[Y]*ntotal[Y];
+ psidata[addr_rank0(psi->nsites, index)] -= psi->e0[Y]*ntotal[Y];
}
else {
/* Borrow fluid site at end */
index1 = cs_index(psi->cs, ic, nlocal[Y], kc);
- psi->psi[addr_rank0(psi->nsites, index)] =
- psi->psi[addr_rank0(psi->nsites, index1)];
+ psidata[addr_rank0(psi->nsites, index)] =
+ psidata[addr_rank0(psi->nsites, index1)];
}
}
}
@@ -1257,13 +765,13 @@ int psi_halo_psijump(psi_t * psi) {
if (periodic[Z]) {
/* Add external potential */
- psi->psi[addr_rank0(psi->nsites, index)] += psi->e0[Z]*ntotal[Z];
+ psidata[addr_rank0(psi->nsites, index)] += psi->e0[Z]*ntotal[Z];
}
else {
/* Borrow fluid site kc = 1 */
index1 = cs_index(psi->cs, ic, jc, 1);
- psi->psi[addr_rank0(psi->nsites, index)] =
- psi->psi[addr_rank0(psi->nsites, index1)];
+ psidata[addr_rank0(psi->nsites, index)] =
+ psidata[addr_rank0(psi->nsites, index1)];
}
}
}
@@ -1281,13 +789,13 @@ int psi_halo_psijump(psi_t * psi) {
if (periodic[Z]) {
/* Subtract external potential */
- psi->psi[addr_rank0(psi->nsites, index)] -= psi->e0[Z]*ntotal[Z];
+ psidata[addr_rank0(psi->nsites, index)] -= psi->e0[Z]*ntotal[Z];
}
else {
/* Borrow fluid site at end ... */
index1 = cs_index(psi->cs, ic, jc, nlocal[Z]);
- psi->psi[addr_rank0(psi->nsites, index)] =
- psi->psi[addr_rank0(psi->nsites, index1)];
+ psidata[addr_rank0(psi->nsites, index)] =
+ psidata[addr_rank0(psi->nsites, index1)];
}
}
}
@@ -1329,21 +837,6 @@ int psi_force_method_set(psi_t * psi, int flag) {
return 0;
}
-/*****************************************************************************
- *
- * psi_nfreq_set
- *
- *****************************************************************************/
-
-int psi_nfreq_set(psi_t * psi, int nfreq) {
-
- assert(psi);
-
- psi->nfreq = nfreq;
-
- return 0;
-}
-
/*****************************************************************************
*
* psi_output_step
@@ -1467,3 +960,34 @@ int psi_electroneutral(psi_t * psi, map_t * map) {
return 0;
}
+/*****************************************************************************
+ *
+ * psi_io_write
+ *
+ * Convenience to write both psi, rho with extra information.
+ *
+ *****************************************************************************/
+
+int psi_io_write(psi_t * psi, int nstep) {
+
+ int ifail = 0;
+ io_event_t io1 = {0};
+ io_event_t io2 = {0};
+ const char * extra = "electrokinetics";
+ cJSON * json = NULL;
+
+ ifail = psi_options_to_json(&psi->options, &json);
+ if (ifail == 0) {
+ io1.extra_name = extra;
+ io2.extra_name = extra;
+ io1.extra_json = json;
+ io2.extra_json = json;
+ }
+
+ ifail += field_io_write(psi->psi, nstep, &io1);
+ ifail += field_io_write(psi->rho, nstep, &io2);
+
+ cJSON_Delete(json);
+
+ return ifail;
+}
diff --git a/src/psi.h b/src/psi.h
index 55ffe13ba..85f502286 100644
--- a/src/psi.h
+++ b/src/psi.h
@@ -5,7 +5,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2012-2022 The University of Edinburgh
+ * (c) 2012-2023 The University of Edinburgh
*
* Kevin Stratford (kevin@epcc.ed.ac.uk)
*
@@ -15,82 +15,97 @@
#define LUDWIG_PSI_H
#include "pe.h"
-#include "coords.h"
-#include "io_harness.h"
+#include "field.h"
#include "map.h"
+#include "psi_options.h"
+#include "stencil.h"
-/* PSI_NKMAX is here to allow us to declare arrays to hold
- * per-species quantities. It avoids allocation of short arrays,
- * which is slightly tedious, particularly on the device. */
+typedef struct psi_s psi_t;
-#define PSI_NKMAX 4
+/*
+ * We store here the unit charge, the electric permittivity, and the
+ * temperature, all in lattice units. This allows us to work out the
+ * Bjerrum length,
+ * l_B = e^2 / (4 \pi epsilon_0 epsilon_r kT)
+ * which is the scale at which the interaction energy between two
+ * unit charges is equal to kT. The aim is that the Bjerrum length
+ * should be < 1 (e.g. 0.7) in lattice units.
+ *
+ * For water at room temperature, the Bjerrum length is about
+ * 7 Angstrom.
+ *
+ */
-/* Force computation method */
+struct psi_s {
+ pe_t * pe; /* Parallel environment */
+ cs_t * cs; /* Coordinate system */
-enum psi_force_method {PSI_FORCE_NONE = 0,
- PSI_FORCE_DIVERGENCE,
- PSI_FORCE_GRADMU,
- PSI_FORCE_NTYPES
-};
+ int nk; /* Number of species */
+ int nsites; /* Number sites storage */
-typedef struct psi_s psi_t;
+ field_t * psi; /* Electric potential */
+ field_t * rho; /* Charge densities */
+
+ double * diffusivity; /* Diffusivity for each species */
+ int * valency; /* Valency for each species */
+ double e; /* unit charge */
+ double epsilon; /* first and reference permittivity */
+ double epsilon2; /* second permittivity */
+ double beta; /* Boltzmann factor (1 / k_B T) */
+
+ int method; /* Force computation method */
+ int multisteps; /* Number of substeps in charge dynamics */
+ int nfreq_io; /* Field output */
-/* f_vare_t describes the signature of the function expected
- * to return the permittivity as a function of position index. */
+ double diffacc; /* Number of substeps in charge dynamics */
+ double e0[3]; /* External electric field */
-typedef int (* f_vare_t)(void * fe, int index, double * epsilon);
+ /* Solver options */
+ psi_solver_options_t solver; /* User options */
+ stencil_t * stencil; /* Finite difference stencil info */
-int psi_create(pe_t * pe, cs_t * cs, int nk, psi_t ** pobj);
-void psi_free(psi_t * obj);
-int psi_init_io_info(psi_t * obj, int grid[3], int form_in, int form_out);
-int psi_io_info(psi_t * obj, io_info_t ** info);
+ /* Options */
+ psi_options_t options; /* Overall options (currently a copy) */
+
+};
+
+
+int psi_create(pe_t * pe, cs_t * cs, const psi_options_t * opts, psi_t ** p);
+int psi_free(psi_t ** psi);
+
+int psi_initialise(pe_t * pe, cs_t * cs, const psi_options_t * opts,
+ psi_t * psi);
+int psi_finalise(psi_t * psi);
int psi_nk(psi_t * obj, int * nk);
int psi_valency(psi_t * obj, int n, int * iv);
-int psi_valency_set(psi_t * obj, int n, int iv);
int psi_diffusivity(psi_t * obj, int n, double * diff);
-int psi_diffusivity_set(psi_t * obj, int n, double diff);
-int psi_e0_set(psi_t * psi, const double e0[3]);
int psi_halo_psi(psi_t * obj);
int psi_halo_psijump(psi_t * obj);
int psi_halo_rho(psi_t * obj);
+int psi_io_write(psi_t * psi, int nstep);
+
int psi_rho(psi_t * obj, int index, int n, double * rho);
int psi_rho_set(psi_t * obj, int index, int n, double rho);
int psi_psi(psi_t * obj, int index, double * psi);
int psi_psi_set(psi_t * obj, int index, double psi);
int psi_rho_elec(psi_t * obj, int index, double * rho_elec);
int psi_unit_charge(psi_t * obj, double * eunit);
-int psi_unit_charge_set(psi_t * obj, double eunit);
int psi_beta(psi_t * obj, double * beta);
-int psi_beta_set(psi_t * obj, double beta);
int psi_epsilon(psi_t * obj, double * epsilon);
-int psi_epsilon_set(psi_t * obj, double epsilon);
int psi_epsilon2(psi_t * obj, double * epsilon2);
-int psi_epsilon2_set(psi_t * obj, double epsilon2);
int psi_ionic_strength(psi_t * psi, int index, double * sion);
-int psi_bjerrum_length(psi_t * obj, double * lb);
-int psi_bjerrum_length2(psi_t * obj, double * lb);
-int psi_debye_length(psi_t * obj, double rho_b, double * ld);
-int psi_debye_length2(psi_t * obj, double rho_b, double * ld);
int psi_surface_potential(psi_t * obj, double sigma, double rho_b,
double * sp);
int psi_reltol(psi_t * obj, double * reltol);
int psi_abstol(psi_t * obj, double * abstol);
int psi_maxits(psi_t * obj, int * maxits);
-int psi_reltol_set(psi_t * obj, double reltol);
-int psi_abstol_set(psi_t * obj, double abstol);
-int psi_maxits_set(psi_t * obj, int maxits);
-int psi_nfreq_set(psi_t * psi, int nfreq);
int psi_output_step(psi_t * psi, int its);
int psi_multisteps(psi_t * obj, int * multisteps);
-int psi_multisteps_set(psi_t * obj, int multisteps);
int psi_multistep_timestep(psi_t * obj, double * dt);
int psi_diffacc(psi_t * obj, double * diffacc);
-int psi_diffacc_set(psi_t * obj, double diffacc);
-int psi_skipsteps(psi_t * obj);
-int psi_skipsteps_set(psi_t * obj, double skipsteps);
int psi_zero_mean(psi_t * obj);
int psi_force_method(psi_t * obj, int * flag);
int psi_force_method_set(psi_t * obj, int flag);
diff --git a/src/psi_colloid.c b/src/psi_colloid.c
index 9e06d607b..15d428c42 100644
--- a/src/psi_colloid.c
+++ b/src/psi_colloid.c
@@ -8,7 +8,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2013-2020 The University of Edinburgh
+ * (c) 2013-2023 The University of Edinburgh
*
* Contributing authors:
* Oliver Henrich (ohenrich@epcc.ed.ac.uk)
@@ -21,7 +21,6 @@
#include
#include "pe.h"
-#include "psi_s.h"
#include "util.h"
#include "coords.h"
#include "psi_colloid.h"
diff --git a/src/psi_force.c b/src/psi_force.c
index 3cd536d13..589dc50e4 100644
--- a/src/psi_force.c
+++ b/src/psi_force.c
@@ -7,7 +7,7 @@
* Edinburgh Soft Matter and Statisitical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2013-2016 The University of Edinburgh
+ * (c) 2013-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -22,7 +22,6 @@
#include "pe.h"
#include "coords.h"
#include "physics.h"
-#include "psi_s.h"
#include "fe_electro.h"
#include "fe_electro_symmetric.h"
#include "psi_force.h"
@@ -121,7 +120,7 @@ int psi_force_gradmu_e(psi_t * psi, fe_t * fe, hydro_t * hydro,
are implicitly calculated */
psi_rho_elec(psi, index, &rho_elec);
- psi_electric_field_d3qx(psi, index, e);
+ psi_electric_field(psi, index, e);
for (ia = 0; ia < 3; ia++) {
e[ia] *= kt*reunit;
@@ -296,7 +295,7 @@ int psi_force_gradmu_es(psi_t * psi, fe_t * fe, field_t * phi, hydro_t * hydro,
are implicitly calculated */
psi_rho_elec(psi, index, &rho_elec);
- psi_electric_field_d3qx(psi, index, e);
+ psi_electric_field(psi, index, e);
for (ia = 0; ia < 3; ia++) {
e[ia] *= kt*reunit;
@@ -362,324 +361,60 @@ int psi_force_gradmu_es(psi_t * psi, fe_t * fe, field_t * phi, hydro_t * hydro,
*
* psi_force_divstress
*
- * A test routine for force via divergence of stress, allowing
+ * A routine for force via divergence of stress, allowing
* the stress to be computed inside the colloids.
*
* The stress is to include the full electric field.
*
- * TODO: The assert(0) indicates there is no test for this;
- * the _d3qx version is preferred.
- *
*****************************************************************************/
int psi_force_divstress(psi_t * psi, fe_t * fe, hydro_t * hydro,
colloids_info_t * cinfo) {
- int ic, jc, kc;
- int index, index1;
- int ia;
- int nlocal[3];
-
- double force[3];
- double pth1[3][3];
-
- colloid_t * pc = NULL;
-
- assert(psi);
- assert(fe);
- assert(cinfo);
-
- cs_nlocal(psi->cs, nlocal);
-
- assert(0); /* NO TEST? */
-
- for (ic = 1; ic <= nlocal[X]; ic++) {
- for (jc = 1; jc <= nlocal[Y]; jc++) {
- for (kc = 1; kc <= nlocal[Z]; kc++) {
-
- index = cs_index(psi->cs, ic, jc, kc);
-
- /* Calculate divergence based on 6-pt stencil */
-
- index1 = cs_index(psi->cs, ic+1, jc, kc);
- fe->func->stress(fe, index1, pth1);
-
- for (ia = 0; ia < 3; ia++) {
- force[ia] = -0.5*(pth1[ia][X]);
- }
-
- index1 = cs_index(psi->cs, ic-1, jc, kc);
- fe->func->stress(fe, index1, pth1);
- for (ia = 0; ia < 3; ia++) {
- force[ia] += 0.5*(pth1[ia][X]);
- }
-
- index1 = cs_index(psi->cs, ic, jc+1, kc);
- fe->func->stress(fe, index1, pth1);
- for (ia = 0; ia < 3; ia++) {
- force[ia] -= 0.5*(pth1[ia][Y]);
- }
-
- index1 = cs_index(psi->cs, ic, jc-1, kc);
- fe->func->stress(fe, index1, pth1);
- for (ia = 0; ia < 3; ia++) {
- force[ia] += 0.5*(pth1[ia][Y]);
- }
-
- index1 = cs_index(psi->cs, ic, jc, kc+1);
- fe->func->stress(fe, index1, pth1);
- for (ia = 0; ia < 3; ia++) {
- force[ia] -= 0.5*(pth1[ia][Z]);
- }
-
- index1 = cs_index(psi->cs, ic, jc, kc-1);
- fe->func->stress(fe, index1, pth1);
- for (ia = 0; ia < 3; ia++) {
- force[ia] += 0.5*(pth1[ia][Z]);
- }
-
- /* Store the force on lattice */
- if (pc) {
- pc->force[X] += force[X];
- pc->force[Y] += force[Y];
- pc->force[Z] += force[Z];
- }
- else {
- hydro_f_local_add(hydro, index, force);
- }
-
-
- }
- }
- }
-
- return 0;
-}
-
-
-/*****************************************************************************
- *
- * psi_force_divstress_d3qx
- *
- * A routine for force via divergence of stress, allowing
- * the stress to be computed inside the colloids. The
- * calculation of the divergence is based on the D3QX stencil
- * with X=6, 18 or 26. The stress is to include the full
- * electric field.
- *
- *****************************************************************************/
-
-int psi_force_divstress_d3qx(psi_t * psi, fe_t * fe, hydro_t * hydro,
- map_t * map, colloids_info_t * cinfo) {
-
- int ic, jc, kc;
- int index, index_nb;
- int status, status_nb;
- int ia, ib;
- int nlocal[3];
-
- double force[3];
- double pth_nb[3][3];
-
- colloid_t * pc = NULL;
-
- int p;
- int coords[3], coords_nb[3];
+ int nlocal[3] = {0};
+ cs_t * cs = NULL;
+ stencil_t * s = NULL;
assert(psi);
assert(cinfo);
- cs_nlocal(psi->cs, nlocal);
-
- for (ic = 1; ic <= nlocal[X]; ic++) {
- for (jc = 1; jc <= nlocal[Y]; jc++) {
- for (kc = 1; kc <= nlocal[Z]; kc++) {
-
- index = cs_index(psi->cs, ic, jc, kc);
- map_status(map, index, &status);
- colloids_info_map(cinfo, index, &pc);
-
- cs_index_to_ijk(psi->cs, index, coords);
-
- for (ia = 0; ia < 3; ia++) {
- force[ia] = 0.0;
- }
-
- /* Calculate divergence based on D3QX stencil */
- for (p = 1; p < PSI_NGRAD; p++) {
-
- coords_nb[X] = coords[X] + psi_gr_cv[p][X];
- coords_nb[Y] = coords[Y] + psi_gr_cv[p][Y];
- coords_nb[Z] = coords[Z] + psi_gr_cv[p][Z];
-
- index_nb = cs_index(psi->cs, coords_nb[X], coords_nb[Y], coords_nb[Z]);
- map_status(map, index_nb, &status_nb);
+ cs = psi->cs;
+ s = psi->stencil;
+ assert(cs);
+ assert(s);
- fe->func->stress(fe, index_nb, pth_nb);
+ cs_nlocal(cs, nlocal);
- for (ia = 0; ia < 3; ia++) {
- for (ib = 0; ib < 3; ib++) {
- force[ia] -= psi_gr_wv[p] * psi_gr_rcs2 * pth_nb[ia][ib] * psi_gr_cv[p][ib];
- }
- }
-
- }
-
- /* Store the force on lattice */
-
- if (pc) {
- pc->force[X] += force[X];
- pc->force[Y] += force[Y];
- pc->force[Z] += force[Z];
- }
- else {
- hydro_f_local_add(hydro, index, force);
- }
-
- }
- }
- }
-
- return 0;
-}
-
-/*****************************************************************************
- *
- * psi_force_divstress_one_sided_d3qx
- *
- * A routine for force via divergence of stress, allowing
- * the stress to be computed inside the colloids.
- * This is the attempt to use one-sided derivatives at the
- * surface of the particles.
- * The calculation of the divergence is based on the D3QX stencil
- * with X=6, 18 or 26. The stress is to include the full
- * electric field.
- *
- * TODO
- * This routine has not been refactored as no test exists. The
- * refactoring has retained hardwired references to fe_electro
- * (only).
- *
- *****************************************************************************/
-
-int psi_force_divstress_one_sided_d3qx(psi_t * psi, hydro_t * hydro, map_t * map, colloids_info_t * cinfo) {
-
- int ic, jc, kc;
- int index, index_nb, index1, index2;
- int status, status_nb;
- int ia, ib;
- int nlocal[3];
- int p;
- int coords[3], coords_nb[3], coords1[3], coords2[3];
-
- double force[3];
- double pth1[3][3], pth2[3][3];
- double pth[3][3], pth_nb[3][3];
-
- fe_electro_t * fe = NULL; /* See note above */
- colloid_t * pc = NULL;
+ for (int ic = 1; ic <= nlocal[X]; ic++) {
+ for (int jc = 1; jc <= nlocal[Y]; jc++) {
+ for (int kc = 1; kc <= nlocal[Z]; kc++) {
- assert(psi);
- assert(cinfo);
-
- cs_nlocal(psi->cs, nlocal);
-
- assert(0); /* NO TEST? */
+ int index = cs_index(cs, ic, jc, kc);
+ double force[3] = {0};
+ colloid_t * pc = NULL;
- for (ic = 1; ic <= nlocal[X]; ic++) {
- for (jc = 1; jc <= nlocal[Y]; jc++) {
- for (kc = 1; kc <= nlocal[Z]; kc++) {
-
- index = cs_index(psi->cs, ic, jc, kc);
- map_status(map, index, &status);
colloids_info_map(cinfo, index, &pc);
- cs_index_to_ijk(psi->cs, index, coords);
+ /* Calculate divergence based on the stencil */
+ for (int p = 1; p < s->npoints; p++) {
- for (ia = 0; ia < 3; ia++) {
- force[ia] = 0.0;
- }
-
- /* Calculate divergence based on D3QX stencil */
- for (p = 1; p < PSI_NGRAD; p++) {
-
- coords_nb[X] = coords[X] + psi_gr_cv[p][X];
- coords_nb[Y] = coords[Y] + psi_gr_cv[p][Y];
- coords_nb[Z] = coords[Z] + psi_gr_cv[p][Z];
-
- index_nb = cs_index(psi->cs, coords_nb[X], coords_nb[Y], coords_nb[Z]);
- map_status(map, index_nb, &status_nb);
-
- if (status != MAP_FLUID) {
+ int8_t cx = s->cv[p][X];
+ int8_t cy = s->cv[p][Y];
+ int8_t cz = s->cv[p][Z];
+ int index1 = cs_index(cs, ic + cx, jc + cy, kc + cz);
+ double pth[3][3] = {0};
- fe_electro_stress_ex(fe, index_nb, pth_nb);
+ fe->func->stress(fe, index1, pth);
- for (ia = 0; ia < 3; ia++) {
- for (ib = 0; ib < 3; ib++) {
- force[ia] -= psi_gr_wv[p] * psi_gr_rcs2 * pth_nb[ia][ib] * psi_gr_cv[p][ib];
- }
+ for (int ia = 0; ia < 3; ia++) {
+ for (int ib = 0; ib < 3; ib++) {
+ force[ia] -= s->wgradients[p]*pth[ia][ib]*s->cv[p][ib];
}
-
}
-
- if (status == MAP_FLUID && status_nb == MAP_FLUID) {
-
- fe_electro_stress(fe, index_nb, pth_nb);
-
- for (ia = 0; ia < 3; ia++) {
- force[ia] -= psi_gr_wv[p] * psi_gr_rcs2 * pth_nb[ia][X] * psi_gr_cv[p][X];
- force[ia] -= psi_gr_wv[p] * psi_gr_rcs2 * pth_nb[ia][Y] * psi_gr_cv[p][Y];
- force[ia] -= psi_gr_wv[p] * psi_gr_rcs2 * pth_nb[ia][Z] * psi_gr_cv[p][Z];
- }
- }
-
- if (status == MAP_FLUID && status_nb != MAP_FLUID) {
-
- /* Current site r */
- fe_electro_stress(fe, index, pth);
-
- /* Site r - cv */
- coords1[X] = coords[X] - psi_gr_cv[p][X];
- coords1[Y] = coords[Y] - psi_gr_cv[p][Y];
- coords1[Z] = coords[Z] - psi_gr_cv[p][Z];
-
- index1 = cs_index(psi->cs, coords1[X], coords1[Y], coords1[Z]);
-
- fe_electro_stress(fe, index1, pth1);
-
- /* Subtract the above 'fluid' half of the incomplete two-point formula. */
- /* Note: subtracting means adding here because of inverse lattice vectors. */
- for (ia = 0; ia < 3; ia++) {
- force[ia] -= psi_gr_wv[p] * psi_gr_rcs2 * pth1[ia][X] * psi_gr_cv[p][X];
- force[ia] -= psi_gr_wv[p] * psi_gr_rcs2 * pth1[ia][Y] * psi_gr_cv[p][Y];
- force[ia] -= psi_gr_wv[p] * psi_gr_rcs2 * pth1[ia][Z] * psi_gr_cv[p][Z];
- }
-
- /* Site r - 2*cv */
- coords2[X] = coords[X] - 2*psi_gr_cv[p][X];
- coords2[Y] = coords[Y] - 2*psi_gr_cv[p][Y];
- coords2[Z] = coords[Z] - 2*psi_gr_cv[p][Z];
-
- index2 = cs_index(psi->cs, coords2[X], coords2[Y], coords2[Z]);
-
- fe_electro_stress(fe, index2, pth2);
-
- /* Use one-sided derivative instead */
- for (ia = 0; ia < 3; ia++) {
- for (ib = 0; ib < 3; ib++) {
- force[ia] -= psi_gr_wv[p] * psi_gr_rcs2 *
- (3.0*pth[ia][ib] - 4.0*pth1[ia][ib] + 1.0*pth2[ia][ib])
- * psi_gr_rnorm[p]* psi_gr_cv[p][ib];
- }
- }
-
- }
-
-
}
+ /* Store the force on the colloid or on the lattice */
- /* Store the force on lattice */
if (pc) {
pc->force[X] += force[X];
pc->force[Y] += force[Y];
diff --git a/src/psi_force.h b/src/psi_force.h
index d3cbfee09..7ea1c8bcb 100644
--- a/src/psi_force.h
+++ b/src/psi_force.h
@@ -2,20 +2,17 @@
*
* psi_force.h
*
- * $Id$
- *
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * Contributing Authors:
- * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ * (c) 2013-2023 The University of Edinburgh
*
- * (c) 2013-2016 The University of Edinburgh
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
*
*****************************************************************************/
-#ifndef PSI_FORCE_H
-#define PSI_FORCE_H
+#ifndef LUDWIG_PSI_FORCE_H
+#define LUDWIG_PSI_FORCE_H
#include "psi.h"
#include "free_energy.h"
@@ -24,12 +21,8 @@
#include "map.h"
int psi_force_gradmu(psi_t * psi, fe_t * fe, field_t * phi, hydro_t * hydro,
- map_t * map, colloids_info_t * cinfo);
+ map_t * map, colloids_info_t * cinfo);
int psi_force_divstress(psi_t * psi, fe_t * fe, hydro_t * hydro,
colloids_info_t * cinfo);
-int psi_force_divstress_d3qx(psi_t * psi, fe_t * fe, hydro_t * hydro,
- map_t * map, colloids_info_t * cinfo);
-int psi_force_divstress_one_sided_d3qx(psi_t * psi, hydro_t * hydro,
- map_t * map, colloids_info_t * cinfo);
#endif
diff --git a/src/psi_gradients.c b/src/psi_gradients.c
index 5d925e0f5..21bec91e0 100644
--- a/src/psi_gradients.c
+++ b/src/psi_gradients.c
@@ -2,467 +2,66 @@
*
* psi_gradients.c
*
- * Finite difference stencils used in the
- * electrokinetic routines.
+ * Currently just routines for the electric field, aka, the gradient
+ * of the potential.
+ *
*
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
* Oliver Henrich (ohenrich@epcc.ed.ac.uk)
- * (c) 2014-2018 The University of Edinburgh
+ *
+ * (c) 2014-2023 The University of Edinburgh
*
****************************************************************************/
#include
+
#include "coords.h"
-#include "psi_s.h"
#include "psi_gradients.h"
-#include "fe_electro_symmetric.h"
-
-#if defined NP_D3Q18
-const int psi_gr_cv[PSI_NGRAD][3] = {{ 0, 0, 0},
- { 1, 1, 0}, { 1, 0, 1}, { 1, 0, 0},
- { 1, 0, -1}, { 1, -1, 0}, { 0, 1, 1},
- { 0, 1, 0}, { 0, 1, -1}, { 0, 0, 1},
- { 0, 0, -1}, { 0, -1, 1}, { 0, -1, 0},
- { 0, -1, -1}, {-1, 1, 0}, {-1, 0, 1},
- {-1, 0, 0}, {-1, 0, -1}, {-1, -1, 0}};
-
-
-#define w0 (12.0/36.0)
-#define w1 (2.0/36.0)
-#define w2 (1.0/36.0)
-
-#define sqrt2 1.4142135623730951
-
-const double psi_gr_wv[PSI_NGRAD] = {w0,
- w2, w2, w1, w2, w2, w2,
- w1, w2, w1, w1, w2, w1,
- w2, w2, w2, w1, w2, w2};
-
-const double psi_gr_rnorm[PSI_NGRAD] = {0.0,
- 1.0/sqrt2, 1.0/sqrt2, 1.0, 1.0/sqrt2, 1.0/sqrt2, 1.0/sqrt2,
- 1.0, 1.0/sqrt2, 1.0, 1.0, 1.0/sqrt2, 1.0,
- 1.0/sqrt2, 1.0/sqrt2, 1.0/sqrt2, 1.0, 1.0/sqrt2, 1.0/sqrt2};
-
-const double psi_gr_rcs2 = 3.0;
-
-#elif defined NP_D3Q26
-
-const int psi_gr_cv[PSI_NGRAD][3] = {{ 0, 0, 0},
- {-1,-1,-1}, {-1,-1, 0}, {-1,-1, 1},
- {-1, 0,-1}, {-1, 0, 0}, {-1, 0, 1},
- {-1, 1,-1}, {-1, 1, 0}, {-1, 1, 1},
- { 0,-1,-1}, { 0,-1, 0}, { 0,-1, 1},
- { 0, 0,-1}, { 0, 0, 1},
- { 0, 1,-1}, { 0, 1, 0}, { 0, 1, 1},
- { 1,-1,-1}, { 1,-1, 0}, { 1,-1, 1},
- { 1, 0,-1}, { 1, 0, 0}, { 1, 0, 1},
- { 1, 1,-1}, { 1, 1, 0}, { 1, 1, 1}};
-
-
-#define w0 (8.0/27.0)
-#define w1 (2.0/27.0)
-#define w2 (1.0/54.0)
-#define w3 (1.0/216.0)
-
-#define sqrt2 1.4142135623730951
-#define sqrt3 1.7320508075688772
-
-const double psi_gr_wv[PSI_NGRAD] = {w0,
- w3, w2, w3,
- w2, w1, w2,
- w3, w2, w3,
- w2, w1, w2,
- w1, w1,
- w2, w1, w2,
- w3, w2, w3,
- w2, w1, w2,
- w3, w2, w3};
-
-const double psi_gr_rnorm[PSI_NGRAD] = {0.0,
- 1.0/sqrt3, 1.0/sqrt2, 1.0/sqrt3,
- 1.0/sqrt2, 1.0, 1.0/sqrt2,
- 1.0/sqrt3, 1.0/sqrt2, 1.0/sqrt3,
- 1.0/sqrt2, 1.0, 1.0/sqrt2,
- 1.0, 1.0,
- 1.0/sqrt2, 1.0, 1.0/sqrt2,
- 1.0/sqrt3, 1.0/sqrt2, 1.0/sqrt3,
- 1.0/sqrt2, 1.0, 1.0/sqrt2,
- 1.0/sqrt3, 1.0/sqrt2, 1.0/sqrt3};
-
-const double psi_gr_rcs2 = 3.0;
-
-
-#else
-
-/* NP_D3Q6 */
-
-const int psi_gr_cv[PSI_NGRAD][3] = {{ 0, 0, 0},
- {-1, 0, 0}, { 0, -1, 0}, { 0, 0, -1},
- { 1, 0, 0}, { 0, 1, 0}, { 0, 0, 1}};
-
-#define w0 (0.0)
-#define w1 (1.0/6.0)
-
-const double psi_gr_wv[PSI_NGRAD] = {w0,
- w1, w1, w1,
- w1, w1, w1};
-
-const double psi_gr_rnorm[PSI_NGRAD] = {0.0,
- 1.0, 1.0, 1.0,
- 1.0, 1.0, 1.0};
-
-const double psi_gr_rcs2 = 3.0;
-#endif
-
/*****************************************************************************
*
* psi_electric_field
*
* Return the electric field associated with the current potential.
- *
- * The gradient of the potential is differenced as
- * E_x = - (1/2) [ psi(i+1,j,k) - psi(i-1,j,k ]
- * etc
- *
- * TODO: The assert(0) indicates that there is no test of this code.
+ * E_a = - \nabla_a \psi
*
*****************************************************************************/
int psi_electric_field(psi_t * psi, int index, double e[3]) {
- int nsites;
- int xs, ys, zs;
+ int ijk[3] = {0};
+ cs_t * cs = NULL;
+ stencil_t * s = NULL;
assert(psi);
- assert(0); /* NO TEST? */
-
- cs_nsites(psi->cs, &nsites);
- cs_strides(psi->cs, &xs, &ys, &zs);
-
- e[X] = -0.5*(psi->psi[addr_rank0(nsites, index + xs)] - psi->psi[addr_rank0(nsites, index - xs)]);
- e[Y] = -0.5*(psi->psi[addr_rank0(nsites, index + ys)] - psi->psi[addr_rank0(nsites, index - ys)]);
- e[Z] = -0.5*(psi->psi[addr_rank0(nsites, index + zs)] - psi->psi[addr_rank0(nsites, index - zs)]);
-
- return 0;
-}
-
-/*****************************************************************************
- *
- * psi_electric_field_d3qx
- *
- * Return the electric field associated with the current potential.
- *
- * The gradient of the potential is differenced with wider stencil
- * that includes nearest and next-to-nearest neighbours.
- *
- *****************************************************************************/
-
-int psi_electric_field_d3qx(psi_t * psi, int index, double e[3]) {
-
- int p;
- int nsites;
- int coords[3], coords_nbr[3], index_nbr;
- double aux;
- assert(psi);
+ cs = psi->cs;
+ s = psi->stencil;
+ assert(cs);
+ assert(s);
- cs_nsites(psi->cs, &nsites);
- cs_index_to_ijk(psi->cs, index, coords);
+ cs_index_to_ijk(cs, index, ijk);
- e[X] = 0;
+ e[X] = 0;
e[Y] = 0;
e[Z] = 0;
- for (p = 1; p < PSI_NGRAD; p++) {
-
- coords_nbr[X] = coords[X] + psi_gr_cv[p][X];
- coords_nbr[Y] = coords[Y] + psi_gr_cv[p][Y];
- coords_nbr[Z] = coords[Z] + psi_gr_cv[p][Z];
+ for (int p = 1; p < s->npoints; p++) {
- index_nbr = cs_index(psi->cs, coords_nbr[X], coords_nbr[Y], coords_nbr[Z]);
- aux = psi_gr_wv[p]* psi_gr_rcs2 * psi->psi[addr_rank0(nsites, index_nbr)];
+ int8_t cx = s->cv[p][X];
+ int8_t cy = s->cv[p][Y];
+ int8_t cz = s->cv[p][Z];
- e[X] -= aux * psi_gr_cv[p][X];
- e[Y] -= aux * psi_gr_cv[p][Y];
- e[Z] -= aux * psi_gr_cv[p][Z];
+ int index1 = cs_index(cs, ijk[X] + cx, ijk[Y] + cy, ijk[Z] + cz);
+ double psi0 = psi->psi->data[addr_rank0(psi->nsites, index1)];
+ /* E_a = -\nabla_a psi */
+ e[X] -= s->wgradients[p]*cx*psi0;
+ e[Y] -= s->wgradients[p]*cy*psi0;
+ e[Z] -= s->wgradients[p]*cz*psi0;
}
return 0;
}
-
-/*****************************************************************************
- *
- * psi_grad_rho
- *
- * Returns the gradient of the charge densities of each species.
- *
- * The gradient of the potential is differenced as
- * grad_rho_x = (1/2) [ psi->rho(i+1,j,k) - psi->rho(i-1,j,k)]
- * etc.
- *
- * If we are next to a boundary site we use one-sided derivatives.
- *
- * Boundary to the left:
- * grad_rho_x = -3/2*psi->rho(i,j,k)+2*psi->rho(i+1,k,j)-1/2*psi->rho(i+2,k,j)
- * etc.
- * Boundary to the right:
- * grad_rho_x = 3/2*psi->rho(i,j,k)-2*psi->rho(i-1,k,j)+1/2*psi->rho(i-2,k,j)
- * etc.
- *
- * TODO: The assert(0) indicates there is no test in place.
- *
- *****************************************************************************/
-
-int psi_grad_rho(psi_t * psi, map_t * map, int index, int n, double grad_rho[3]) {
-
- int nsites;
- int xs, ys, zs;
- int index0, index1;
- int status0, status1;
-
- assert(psi);
- assert(n < psi->nk);
- assert(grad_rho);
- assert(0); /* NO TEST? */
-
- cs_nsites(psi->cs, &nsites);
- cs_strides(psi->cs, &xs, &ys, &zs);
-
- grad_rho[X] = 0.0;
- grad_rho[Y] = 0.0;
- grad_rho[Z] = 0.0;
-
- /* x-direction */
- index0 = index - xs;
- map_status(map, index0, &status0);
- index1 = index + xs;
- map_status(map, index1, &status1);
-
- if (status0 == MAP_FLUID && status1 == MAP_FLUID){
- grad_rho[X] = 0.5*(psi->rho[addr_rank1(nsites, psi->nk, (index + xs), n)]
- - psi->rho[addr_rank1(nsites, psi->nk, (index - xs), n)]);
- }
- if (status0 != MAP_FLUID && status1 == MAP_FLUID){
- grad_rho[X] = - 1.5*psi->rho[addr_rank1(nsites, psi->nk, index, n)]
- + 2.0*psi->rho[addr_rank1(nsites, psi->nk, (index + xs), n)]
- - 0.5*psi->rho[addr_rank1(nsites, psi->nk, (index + 2*xs), n)];
- }
- if (status0 == MAP_FLUID && status1 != MAP_FLUID){
- grad_rho[X] = + 1.5*psi->rho[addr_rank1(nsites, psi->nk, index, n)]
- - 2.0*psi->rho[addr_rank1(nsites, psi->nk, (index - xs), n)]
- + 0.5*psi->rho[addr_rank1(nsites, psi->nk, (index - 2*xs), n)];
- }
-
- /* y-direction */
- index0 = index - ys;
- map_status(map, index0, &status0);
- index1 = index + ys;
- map_status(map, index1, &status1);
-
- if (status0 == MAP_FLUID && status1 == MAP_FLUID) {
- grad_rho[Y]
- = 0.5*(+ psi->rho[addr_rank1(nsites, psi->nk, (index+ys), n)]
- - psi->rho[addr_rank1(nsites, psi->nk, (index-ys), n)]);
- }
- if (status0 != MAP_FLUID && status1 == MAP_FLUID) {
- grad_rho[Y]
- = - 1.5*psi->rho[addr_rank1(nsites, psi->nk, index, n)]
- + 2.0*psi->rho[addr_rank1(nsites, psi->nk, (index + ys), n)]
- - 0.5*psi->rho[addr_rank1(nsites, psi->nk, (index + 2*ys), n)];
- }
- if (status0 == MAP_FLUID && status1 != MAP_FLUID) {
- grad_rho[Y] = + 1.5*psi->rho[addr_rank1(nsites, psi->nk, index, n)]
- - 2.0*psi->rho[addr_rank1(nsites, psi->nk, (index - ys), n)]
- + 0.5*psi->rho[addr_rank1(nsites, psi->nk, (index - 2*ys), n)];
- }
-
- /* z-direction */
- index0 = index - zs;
- map_status(map, index0, &status0);
- index1 = index + zs;
- map_status(map, index1, &status1);
-
- if (status0 == MAP_FLUID && status1 == MAP_FLUID) {
- grad_rho[Z] = 0.5*(psi->rho[addr_rank1(nsites, psi->nk, (index+zs), n)] -
- psi->rho[addr_rank1(nsites, psi->nk, (index-zs), n)]);
- }
- if (status0 != MAP_FLUID && status1 == MAP_FLUID) {
- grad_rho[Z] = - 1.5*psi->rho[addr_rank1(nsites, psi->nk, index, n)]
- + 2.0*psi->rho[addr_rank1(nsites, psi->nk, (index + zs), n)]
- - 0.5*psi->rho[addr_rank1(nsites, psi->nk, (index + 2*zs), n)];
- }
- if (status0 == MAP_FLUID && status1 != MAP_FLUID) {
- grad_rho[Z] = + 1.5*psi->rho[addr_rank1(nsites, psi->nk, index, n)]
- - 2.0*psi->rho[addr_rank1(nsites, psi->nk, (index - zs), n)]
- + 0.5*psi->rho[addr_rank1(nsites, psi->nk, (index - 2*zs), n)];
- }
-
- return 0;
-}
-
-
-/*****************************************************************************
- *
- * psi_grad_rho_d3qx
- *
- * Returns the gradient of the charge densities of each species.
- *
- * The gradient of the potential is differenced as
- * grad_rho_x = (1/2) [ psi->rho(i+1,j,k) - psi->rho(i-1,j,k)]
- * etc.
- *
- * If we are next to a boundary site we use one-sided derivatives based on
- * Lagrange interpolating polynomials.
- *
- * Boundary to the left:
- * grad_rho_x = -3/2*psi->rho(i,j,k)+2*psi->rho(i+1,k,j)-1/2*psi->rho(i+2,k,j)
- * etc.
- * Boundary to the right:
- * grad_rho_x = 3/2*psi->rho(i,j,k)-2*psi->rho(i-1,k,j)+1/2*psi->rho(i-2,k,j)
- * etc.
- *
- * TODO: The assert(0) indicates there is no test for this code.
- *
- *****************************************************************************/
-
-int psi_grad_rho_d3qx(psi_t * psi, map_t * map, int index, int n, double grad_rho[3]) {
-
- int p;
- int nsites;
- int coords[3], coords1[3], coords2[3];
- int index1, index2;
- int status, status1, status2;
- double aux;
-
- assert(psi);
- assert(n < psi->nk);
- assert(grad_rho);
- assert(0); /* NO TEST? */
-
- cs_nsites(psi->cs, &nsites);
- cs_index_to_ijk(psi->cs, index, coords);
- map_status(map, index, &status);
-
- grad_rho[X] = 0;
- grad_rho[Y] = 0;
- grad_rho[Z] = 0;
-
- for (p = 1; p < PSI_NGRAD; p++) {
-
- coords1[X] = coords[X] + psi_gr_cv[p][X];
- coords1[Y] = coords[Y] + psi_gr_cv[p][Y];
- coords1[Z] = coords[Z] + psi_gr_cv[p][Z];
-
- index1 = cs_index(psi->cs, coords1[X], coords1[Y], coords1[Z]);
- map_status(map, index1, &status1);
-
- if(status == MAP_FLUID && status1 == MAP_FLUID) {
-
- aux = psi_gr_wv[p]* psi_gr_rcs2 * psi->rho[psi->nk*index1 + n];
-
- grad_rho[X] += aux * psi_gr_cv[p][X];
- grad_rho[Y] += aux * psi_gr_cv[p][Y];
- grad_rho[Z] += aux * psi_gr_cv[p][Z];
-
- }
-
- else {
-
- coords1[X] = coords[X] - psi_gr_cv[p][X];
- coords1[Y] = coords[Y] - psi_gr_cv[p][Y];
- coords1[Z] = coords[Z] - psi_gr_cv[p][Z];
- index1 = cs_index(psi->cs, coords1[X], coords1[Y], coords1[Z]);
- map_status(map, index1, &status1);
-
- coords2[X] = coords[X] - 2*psi_gr_cv[p][X];
- coords2[Y] = coords[Y] - 2*psi_gr_cv[p][Y];
- coords2[Z] = coords[Z] - 2*psi_gr_cv[p][Z];
- index2 = cs_index(psi->cs, coords2[X], coords2[Y], coords2[Z]);
- map_status(map, index2, &status2);
-
- if(status == MAP_FLUID && status1 == MAP_FLUID && status2 == MAP_FLUID) {
-
- /* Subtract the above 'fluid' half of the incomplete two-point formula. */
- /* Note: subtracting means adding here because of inverse lattice vectors. */
-
- aux = psi_gr_wv[p]* psi_gr_rcs2 * psi->rho[addr_rank1(nsites, psi->nk, index1, n)];
-
- grad_rho[X] += aux * psi_gr_cv[p][X];
- grad_rho[Y] += aux * psi_gr_cv[p][Y];
- grad_rho[Z] += aux * psi_gr_cv[p][Z];
-
- /* Use one-sided derivative instead */
- grad_rho[X] += psi_gr_wv[p] * psi_gr_rcs2 *
- (3.0*psi->rho[addr_rank1(nsites, psi->nk, index, n)]
- - 4.0*psi->rho[addr_rank1(nsites, psi->nk, index1, n)]
- + 1.0*psi->rho[addr_rank1(nsites, psi->nk, index2, n)])
- * psi_gr_rnorm[p]* psi_gr_cv[p][X];
-
- grad_rho[Y] += psi_gr_wv[p] * psi_gr_rcs2 *
- (3.0*psi->rho[addr_rank1(nsites, psi->nk, index, n)]
- - 4.0*psi->rho[addr_rank1(nsites, psi->nk, index1, n)]
- + 1.0*psi->rho[addr_rank1(nsites, psi->nk, index2, n)])
- * psi_gr_rnorm[p] * psi_gr_cv[p][Y];
-
- grad_rho[Z] += psi_gr_wv[p] * psi_gr_rcs2 *
- (3.0*psi->rho[addr_rank1(nsites, psi->nk, index, n)]
- - 4.0*psi->rho[addr_rank1(nsites, psi->nk, index1, n)]
- + 1.0*psi->rho[addr_rank1(nsites, psi->nk, index2, n)])
- * psi_gr_rnorm[p] * psi_gr_cv[p][Z];
- }
- }
- }
-
- return 0;
-}
-
-/*****************************************************************************
- *
- * psi_grad_eps_d3qx
- *
- * TODO: This could be tested in psi_sor_vare_poisson() (see psi_sor.h)
- *
- *****************************************************************************/
-
-int psi_grad_eps_d3qx(psi_t * psi, fe_t * fe, f_vare_t fepsilon, int index,
- double grad_eps[3]) {
-
- int p;
- int coords[3], coords1[3];
- int index1;
- double aux, eps1;
-
- assert(psi);
- assert(fepsilon);
- assert(grad_eps);
-
- cs_index_to_ijk(psi->cs, index, coords);
-
- grad_eps[X] = 0;
- grad_eps[Y] = 0;
- grad_eps[Z] = 0;
-
- for (p = 1; p < PSI_NGRAD; p++) {
-
- coords1[X] = coords[X] + psi_gr_cv[p][X];
- coords1[Y] = coords[Y] + psi_gr_cv[p][Y];
- coords1[Z] = coords[Z] + psi_gr_cv[p][Z];
-
- index1 = cs_index(psi->cs, coords1[X], coords1[Y], coords1[Z]);
- fepsilon(fe, index1, &eps1);
-
- aux = psi_gr_wv[p]* psi_gr_rcs2 * eps1;
-
- grad_eps[X] += aux * psi_gr_cv[p][X];
- grad_eps[Y] += aux * psi_gr_cv[p][Y];
- grad_eps[Z] += aux * psi_gr_cv[p][Z];
-
- }
-
- return 0;
-}
-
diff --git a/src/psi_gradients.h b/src/psi_gradients.h
index 297da5537..88ec61981 100644
--- a/src/psi_gradients.h
+++ b/src/psi_gradients.h
@@ -5,46 +5,19 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2014-2018 The University of Edinburgh
+ * (c) 2014-2023 The University of Edinburgh
*
* Contributing authors:
- * Oliver Henrich (ohenrich@epcc.ed.ac.uk)
+ * Oliver Henrich (ohenrich@epcc.ed.ac.uk) (now U. Strathclyde)
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
*
****************************************************************************/
#ifndef LUDWIG_PSI_GRADIENTS_H
#define LUDWIG_PSI_GRADIENTS_H
-#include "map.h"
#include "psi.h"
-#include "fe_electro_symmetric.h"
-
-#if defined NP_D3Q18
-
-#define PSI_NGRAD 19
-
-#elif defined NP_D3Q26
-
-#define PSI_NGRAD 27
-
-#else
-
-/* Default to 7-point stencil */
-
-#define PSI_NGRAD 7
-
-#endif
-
-extern const int psi_gr_cv[PSI_NGRAD][3];
-extern const double psi_gr_wv[PSI_NGRAD];
-extern const double psi_gr_rnorm[PSI_NGRAD];
-extern const double psi_gr_rcs2;
int psi_electric_field(psi_t * psi, int index, double e[3]);
-int psi_electric_field_d3qx(psi_t * psi, int index, double e[3]);
-int psi_grad_rho_d3qx(psi_t * obj, map_t * map, int index, int n,
- double grad_rho[3]);
-int psi_grad_eps_d3qx(psi_t * psi, fe_t * fe, f_vare_t fepsilon, int index,
- double grad_eps[3]);
#endif
diff --git a/src/psi_init.c b/src/psi_init.c
index 1589a1ffe..e6f2f2bcf 100644
--- a/src/psi_init.c
+++ b/src/psi_init.c
@@ -4,12 +4,10 @@
*
* Various initial states for electrokinetics.
*
- * $Id$
- *
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2012-16 The University of Edinburgh
+ * (c) 2012-2023 The University of Edinburgh
*
* Contributing authors:
* Oliver Henrich (ohenrich@epcc.ed.ac.uk)
@@ -23,7 +21,6 @@
#include "pe.h"
#include "coords.h"
#include "psi_init.h"
-#include "psi_s.h"
/*****************************************************************************
*
@@ -160,13 +157,15 @@ int psi_init_gouy_chapman(psi_t * obj, map_t * map, double rho_el,
*
* psi_init_liquid_junction
*
- * Set rho(1 <= x <= Lx/2) = 1.01 * electrolyte
- * rho(Lx/2+1 <= x <= Lx) = 0.99 * electrolyte
+ * This follows Mafe et al., so we set for two species:
+ *
+ * rho_left = rho_el + delta_el / 2
+ * rho_right = rho_el - delta_el / 2
*
- * This sets up the system for liquid junction potential.
+ * where left and right are separated by the half way point in the
+ * x-direction.
*
- * rho_el is the average electrolyte concentration.
- * delta_el is the relative difference of the concentrations.
+ * We should have delta_el << rho_el.
*
*****************************************************************************/
@@ -192,13 +191,13 @@ int psi_init_liquid_junction(psi_t * obj, double rho_el, double delta_el) {
psi_psi_set(obj, index, 0.0);
- if ((1 <= noff[0] + ic) && (noff[0] + ic < ntotal[X]/2)) {
- psi_rho_set(obj, index, 0, rho_el * (1.0 + delta_el));
- psi_rho_set(obj, index, 1, rho_el * (1.0 + delta_el));
+ if ((1 <= noff[X] + ic) && (noff[X] + ic <= ntotal[X]/2)) {
+ psi_rho_set(obj, index, 0, rho_el + 0.5*delta_el);
+ psi_rho_set(obj, index, 1, rho_el + 0.5*delta_el);
}
- else{
- psi_rho_set(obj, index, 0, rho_el * (1.0 - delta_el));
- psi_rho_set(obj, index, 1, rho_el * (1.0 - delta_el));
+ else {
+ psi_rho_set(obj, index, 0, rho_el - 0.5*delta_el);
+ psi_rho_set(obj, index, 1, rho_el - 0.5*delta_el);
}
}
}
diff --git a/src/psi_options.c b/src/psi_options.c
new file mode 100644
index 000000000..71f86f7a0
--- /dev/null
+++ b/src/psi_options.c
@@ -0,0 +1,254 @@
+/*****************************************************************************
+ *
+ * psi_options.c
+ *
+ * Including default options for the Electrokinetic sector.
+ * And some derived quantities only dependent on the options.
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#include
+#include
+#include
+#include
+
+#include "psi_options.h"
+#include "util.h"
+
+/*****************************************************************************
+ *
+ * psi_options_default
+ *
+ * The nhalo is that required for the potential and the charge density
+ * fields.
+ *
+ *****************************************************************************/
+
+psi_options_t psi_options_default(int nhalo) {
+
+ int nk = 2;
+
+ psi_options_t opts = {.nk = nk,
+ .e = 1.0,
+ .beta = 1.0,
+ .epsilon1 = 10000.0,
+ .epsilon2 = 10000.0,
+ .e0 = {0.0, 0.0, 0.0},
+ .diffusivity = {0.01, 0.01, 0.01, 0.01},
+ .valency = {+1, -1, +1, -1},
+ .solver = psi_solver_options_default(),
+ .nsolver = -1,
+ .nsmallstep = 1,
+ .diffacc = 0.0,
+ .method = PSI_FORCE_NONE,
+ .psi = {0},
+ .rho = {0}};
+
+ opts.psi = field_options_ndata_nhalo(1, nhalo);
+ opts.rho = field_options_ndata_nhalo(nk, nhalo);
+
+ return opts;
+}
+
+/*****************************************************************************
+ *
+ * psi_options_to_json
+ *
+ * Return a new cJSON object for the options provided.
+ *
+ *****************************************************************************/
+
+int psi_options_to_json(const psi_options_t * opts, cJSON ** json) {
+
+ int ifail = 0;
+
+ assert(opts);
+
+ if (json == NULL || *json != NULL) {
+ ifail = -1;
+ }
+ else {
+ int nk = opts->nk;
+ cJSON * myjson = cJSON_CreateObject();
+ cJSON * valencies = cJSON_CreateIntArray(opts->valency, nk);
+ cJSON * diffusivities = cJSON_CreateDoubleArray(opts->diffusivity, nk);
+ cJSON * electric_field = cJSON_CreateDoubleArray(opts->e0, 3);
+
+ cJSON * solver_options = NULL;
+ ifail = psi_solver_options_to_json(&opts->solver, &solver_options);
+
+ cJSON_AddNumberToObject(myjson, "Number of species", nk);
+ cJSON_AddNumberToObject(myjson, "Unit charge", opts->e);
+ cJSON_AddNumberToObject(myjson, "Boltzmann factor", opts->beta);
+ cJSON_AddNumberToObject(myjson, "First permittivity", opts->epsilon1);
+ cJSON_AddNumberToObject(myjson, "Second permittivity", opts->epsilon2);
+
+ cJSON_AddItemToObject(myjson, "Valencies", valencies);
+ cJSON_AddItemToObject(myjson, "Diffusivities", diffusivities);
+ cJSON_AddItemToObject(myjson, "External field", electric_field);
+ cJSON_AddItemToObject(myjson, "Solver options", solver_options);
+
+ *json = myjson;
+ }
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * psi_options_from_json
+ *
+ *****************************************************************************/
+
+int psi_options_from_json(const cJSON * json, psi_options_t * opts) {
+
+ int ifail = 0;
+
+ if (json == NULL || opts == NULL) {
+ ifail = -1;
+ }
+ else {
+ cJSON * nk = cJSON_GetObjectItem(json, "Number of species");
+ cJSON * e = cJSON_GetObjectItem(json, "Unit charge");
+ cJSON * beta = cJSON_GetObjectItem(json, "Boltzmann factor");
+ cJSON * epsilon1 = cJSON_GetObjectItem(json, "First permittivity");
+ cJSON * epsilon2 = cJSON_GetObjectItem(json, "Second permittivity");
+ cJSON * valencies = cJSON_GetObjectItem(json, "Valencies");
+ cJSON * diffs = cJSON_GetObjectItem(json, "Diffusivities");
+ cJSON * electric = cJSON_GetObjectItem(json, "External field");
+ cJSON * solver = cJSON_GetObjectItem(json, "Solver options");
+
+ if (nk) opts->nk = cJSON_GetNumberValue(nk);
+ if (e) opts->e = cJSON_GetNumberValue(e);
+ if (beta) opts->beta = cJSON_GetNumberValue(beta);
+ if (epsilon1) opts->epsilon1 = cJSON_GetNumberValue(epsilon1);
+ if (epsilon2) opts->epsilon2 = cJSON_GetNumberValue(epsilon2);
+
+ if (valencies) util_json_to_int_array(valencies, opts->valency, opts->nk);
+ if (diffs) util_json_to_double_array(diffs, opts->diffusivity, opts->nk);
+ if (electric) util_json_to_double_array(electric, opts->e0, 3);
+
+ if (solver) ifail = psi_solver_options_from_json(solver, &opts->solver);
+ }
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * psi_bjerrum_length1
+ *
+ * Is equal to e^2 / 4 pi epsilon1 k_B T
+ *
+ * Sensible parameters give return value 0.
+ *
+ *****************************************************************************/
+
+int psi_bjerrum_length1(const psi_options_t * opts, double * lbjerrum) {
+
+ int ifail = 0;
+ PI_DOUBLE(pi);
+
+ assert(opts);
+ assert(lbjerrum);
+
+ if (opts->beta <= 0.0) ifail = -1;
+ if (opts->epsilon1 <= 0.0) ifail = -1;
+
+ {
+ double e = opts->e;
+ double kt = 1.0/opts->beta;
+ double epsilon1 = opts->epsilon1;
+
+ *lbjerrum = e*e / (4.0*pi*epsilon1*kt);
+ }
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * psi_bjerrum_length2
+ *
+ * Is equal to e^2 / 4 pi epsilon2 k_B T if we have
+ * a dielectric contrast between the electrolytes.
+ *
+ *****************************************************************************/
+
+int psi_bjerrum_length2(const psi_options_t * opts, double * lbjerrum) {
+
+ int ifail = 0;
+ PI_DOUBLE(pi);
+
+ assert(opts);
+ assert(lbjerrum);
+
+ if (opts->beta <= 0.0) ifail = -1;
+ if (opts->epsilon2 <= 0) ifail = -1;
+
+ {
+ double e = opts->e;
+ double kt = 1.0/opts->beta;
+ double epsilon2 = opts->epsilon2;
+
+ *lbjerrum = e*e / (4.0*pi*epsilon2*kt);
+ }
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * psi_debye_length1
+ *
+ * Returns the Debye length for a simple, symmetric electrolyte.
+ * An ionic strength is required as input (see above); this
+ * accounts for the factor of 8 in the denominator.
+ *
+ *****************************************************************************/
+
+int psi_debye_length1(const psi_options_t * opts, double rho_b, double * ld) {
+
+ double lb;
+ PI_DOUBLE(pi);
+
+ assert(opts);
+ assert(ld);
+
+ psi_bjerrum_length1(opts, &lb);
+ *ld = 1.0 / sqrt(8.0*pi*lb*rho_b);
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * psi_debye_length2
+ *
+ * Returns the Debye length for the second phase if we
+ * have a dielectric contrast between the electrolytes.
+ * An ionic strength is required as input (see above); this
+ * accounts for the factor of 8 in the denominator.
+ *
+ *****************************************************************************/
+
+int psi_debye_length2(const psi_options_t * opts, double rho_b, double * ld) {
+
+ double lb;
+ PI_DOUBLE(pi);
+
+ assert(opts);
+ assert(ld);
+
+ psi_bjerrum_length2(opts, &lb);
+ *ld = 1.0 / sqrt(8.0*pi*lb*rho_b);
+
+ return 0;
+}
diff --git a/src/psi_options.h b/src/psi_options.h
new file mode 100644
index 000000000..4ad097765
--- /dev/null
+++ b/src/psi_options.h
@@ -0,0 +1,75 @@
+/*****************************************************************************
+ *
+ * psi_options.h
+ *
+ * Run time options for electrokinetic sector.
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#ifndef LUDWIG_PSI_OPTIONS_H
+#define LUDWIG_PSI_OPTIONS_H
+
+#include "field_options.h"
+#include "psi_solver_options.h"
+
+#define PSI_NKMAX 4
+
+/* Force computation method */
+
+typedef enum psi_force_method_enum_s {
+ PSI_FORCE_NONE = 0,
+ PSI_FORCE_DIVERGENCE,
+ PSI_FORCE_GRADMU,
+ PSI_FORCE_NTYPES
+} psi_force_method_enum_t;
+
+/* There may be a case for splitting this into different concerns;
+ * however, it's all here ... */
+
+typedef struct psi_options_s psi_options_t;
+
+struct psi_options_s {
+
+ int nk; /* Number of charged species */
+
+ /* Physics */
+ double e; /* Unit charge */
+ double beta; /* Boltzmann factor (1 / k_B T) */
+ double epsilon1; /* First permittivity */
+ double epsilon2; /* Second permittivity (if required) */
+ double e0[3]; /* External electric field */
+ double diffusivity[PSI_NKMAX]; /* Per species diffusivity */
+ int valency[PSI_NKMAX]; /* Per species charge valency */
+
+ /* Solver options */
+ psi_solver_options_t solver;
+
+ /* Time stepping for Nernst Planck */
+ int nsolver; /* Nernst Planck method */
+ int nsmallstep; /* No. small timesteps in time splitting */
+ double diffacc; /* Criterion for time splitting adjustment */
+
+ /* Other */
+ int method; /* Force computation method */
+ field_options_t psi; /* Field options for potential (i/o etc) */
+ field_options_t rho; /* field options for charges (i/o etc) */
+};
+
+psi_options_t psi_options_default(int nhalo);
+
+int psi_options_to_json(const psi_options_t * opts, cJSON ** json);
+int psi_options_from_json(const cJSON * json, psi_options_t * opts);
+
+int psi_bjerrum_length1(const psi_options_t * opts, double * lb);
+int psi_bjerrum_length2(const psi_options_t * opts, double * lb);
+int psi_debye_length1(const psi_options_t * obj, double rho_b, double * ld);
+int psi_debye_length2(const psi_options_t * obj, double rho_b, double * ld);
+
+#endif
diff --git a/src/psi_petsc.c b/src/psi_petsc.c
index a98b65585..885950b85 100644
--- a/src/psi_petsc.c
+++ b/src/psi_petsc.c
@@ -7,632 +7,337 @@
*
* This uses the PETSc library.
*
- * The Poisson equation homogeneous permittivity looks like
+ * The Poisson equation with homogeneous permittivity looks like
*
* nabla^2 \psi = - rho_elec / epsilon
*
* where psi is the potential, rho_elec is the free charge density, and
- * epsilon is a permeability.
+ * epsilon is a permittivity.
+ *
+ * There is also a version for non-uniform dielectric.
+ *
*
*
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2013-2017 The University of Edinburgh
+ * (c) 2013-2023 The University of Edinburgh
*
* Contributing Authors:
- * Oliver Henrich (ohenrich@epcc.ed.ac.uk)
- * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ * Oliver Henrich (now U. Strathclyde)
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
*
*****************************************************************************/
#include
#include
#include
-#include
-
-#ifdef PETSC
#include "pe.h"
#include "coords.h"
-#include "control.h"
-#include "physics.h"
-#include "psi_s.h"
-#include "psi.h"
-#include "psi_sor.h"
-#include "psi_gradients.h"
-#include "map.h"
-#include "util.h"
#include "psi_petsc.h"
-#include "petscksp.h"
-#include "petscdmda.h"
-DM da; /* distributed array */
-Vec x,b; /* approx solution, RHS */
-Mat A; /* linear system matrix */
-MatNullSpace nullsp; /* null space of matrix */
-KSP ksp; /* linear solver context */
-PC pc; /* preconditioner context */
-PetscReal norm; /* norm of solution error */
-int i,j,its;
+static psi_solver_vt_t vt_ = {
+ (psi_solver_free_ft) psi_solver_petsc_free,
+ (psi_solver_solve_ft) psi_solver_petsc_solve
+};
-int view_matrix = 0;
-int view_vector = 0;
+static psi_solver_vt_t vart_ = {
+ (psi_solver_free_ft) psi_solver_petsc_free,
+ (psi_solver_solve_ft) psi_solver_petsc_var_epsilon_solve
+};
-/*****************************************************************************
- *
- * psi_petsc_init
- *
- * Initialises PETSc vectors, matrices and KSP solver context
- *
- *****************************************************************************/
+int psi_solver_petsc_initialise(psi_t * psi, psi_solver_petsc_t * solver);
+int psi_solver_petsc_matrix_set(psi_solver_petsc_t * solver);
+int psi_solver_petsc_rhs_set(psi_solver_petsc_t * solver);
+int psi_solver_petsc_psi_to_da(psi_solver_petsc_t * solver);
+int psi_solver_petsc_da_to_psi(psi_solver_petsc_t * solver);
-int psi_petsc_init(psi_t * obj, fe_t * fe, f_vare_t fepsilon){
-
- MPI_Comm new_comm;
- int new_rank, nhalo;
- int mpi_cartsz[3], mpi_coords[3];
- int ntotal[3];
- char version[256];
- double tol_rel; /* Relative tolerance */
- double tol_abs; /* Absolute tolerance */
- int niteration = 10000; /* Number of iterations */
- KSPType solver_type;
- PCType pc_type;
- PetscReal rtol, abstol, dtol;
- int maxits;
-
- assert(obj);
- assert(fe);
-
- /* In order for the DMDA and the Cartesian MPI communicator
- to share the same part of the domain decomposition it is
- necessary to renumber the process ranks of the default
- PETSc communicator. Default PETSc is column major decomposition.
- */
-
- cs_cartsz(obj->cs, mpi_cartsz);
- cs_cart_coords(obj->cs, mpi_coords);
- cs_ntotal(obj->cs, ntotal);
-
- /* Set new rank according to PETSc ordering */
- new_rank = mpi_coords[Z]*mpi_cartsz[Y]*mpi_cartsz[X] \
- + mpi_coords[Y]*mpi_cartsz[X] + mpi_coords[X];
-
- /* Create communicator with new ranks according to PETSc ordering */
- MPI_Comm_split(PETSC_COMM_WORLD, 1, new_rank, &new_comm);
-
- /* Override default PETSc communicator */
- PETSC_COMM_WORLD = new_comm;
-
- /* Create 3D distributed array */
- cs_nhalo(obj->cs, &nhalo);
-
- DMDACreate3d(PETSC_COMM_WORLD, \
- DM_BOUNDARY_PERIODIC, DM_BOUNDARY_PERIODIC, DM_BOUNDARY_PERIODIC, \
- DMDA_STENCIL_BOX, ntotal[X], ntotal[Y], ntotal[Z], \
- mpi_cartsz[X], mpi_cartsz[Y], mpi_cartsz[Z], 1, nhalo, \
- NULL, NULL, NULL, &da);
-
- /* Create global vectors on DM */
- DMCreateGlobalVector(da,&x);
- VecDuplicate(x,&b);
-
- /* Create matrix on DM pre-allocated according to distributed array structure */
- DMCreateMatrix(da,&A);
- DMSetMatType(da,MATMPIAIJ);
- DMSetMatrixPreallocateOnly(da,PETSC_TRUE);
-
- /* Initialise solver context and preconditioner */
-
- psi_reltol(obj, &tol_rel);
- psi_abstol(obj, &tol_abs);
- psi_maxits(obj, &niteration);
-
- KSPCreate(PETSC_COMM_WORLD,&ksp);
- KSPSetOperators(ksp,A,A);
- KSPSetTolerances(ksp,tol_rel,tol_abs,PETSC_DEFAULT,niteration);
- KSPSetFromOptions(ksp);
- KSPSetUp(ksp);
-
- PetscGetVersion(version, 256);
- pe_info(obj->pe, "\n%s\n", version);
-
- KSPGetType(ksp, &solver_type);
- KSPGetTolerances(ksp, &rtol, &abstol, &dtol, &maxits);
- KSPGetPC(ksp, &pc);
- PCGetType(pc, &pc_type);
-
- pe_info(obj->pe, "\nUsing Krylov subspace solver\n");
- pe_info(obj->pe, "----------------------------\n");
- pe_info(obj->pe, "Solver type %s\n", solver_type);
- pe_info(obj->pe, "Tolerances rtol %g abstol %g maxits %d\n", rtol, abstol, maxits);
- pe_info(obj->pe, "Preconditioner type %s\n", pc_type);
-
- if (fepsilon == NULL) psi_petsc_compute_laplacian(obj);
- if (fepsilon != NULL) psi_petsc_compute_matrix(obj, (fe_es_t *) fe, fepsilon);
+int psi_solver_petsc_var_epsilon_initialise(psi_t * psi, var_epsilon_t epsilon,
+ psi_solver_petsc_t * solver);
+int psi_solver_petsc_var_epsilon_matrix_set(psi_solver_petsc_t * solver);
+int psi_solver_petsc_var_epsilon_rhs_set(psi_solver_petsc_t * solver);
- return 0;
-}
/*****************************************************************************
*
- * psi_petsc_compute_laplacian
- *
- * Computes the Laplacian for KSP solver.
- * Note that this routine uses the PETSc stencil structure, which permits
- * local assembly of the matrix.
+ * psi_solver_petsc_create
*
*****************************************************************************/
-int psi_petsc_compute_laplacian(psi_t * obj) {
+int psi_solver_petsc_create(psi_t * psi, psi_solver_petsc_t ** solver) {
- int i, j, k;
- int xs, ys, zs, xw, yw, zw, xe, ye, ze;
- double epsilon;
+ int ifail = -1; /* Check PETSC is available */
+ int isInitialised = 0;
+ PetscInitialised(&isInitialised);
-#if defined NP_D3Q26
- double v[27];
- MatStencil row, col[27];
- const double r10 = 0.1;
- const double r30 = (1.0/30.0);
- const double r15_7 = (7.0/15.0);
- const double r15_64 = (64.0/15.0);
+ if (isInitialised) {
+ psi_solver_petsc_t * petsc = NULL;
-#elif defined NP_D3Q18
- double v[19];
- MatStencil row, col[19];
- const double r3 = (1.0/3.0);
- const double r6 = (1.0/6.0);
+ petsc = (psi_solver_petsc_t *) calloc(1, sizeof(psi_solver_petsc_t));
+ assert(petsc);
-#else
- /* NP_D3Q6 is the default */
- double v[7];
- MatStencil row, col[7];
-#endif
+ if (petsc != NULL) {
+ /* initialise ... */
+ petsc->super.impl = &vt_;
+ petsc->psi = psi;
+ ifail = psi_solver_petsc_initialise(psi, petsc);
+ if (ifail != 0) free(petsc);
+ if (ifail == 0) *solver = petsc;
+ }
+ }
- assert(obj);
+ return ifail;
+}
- /* Get details of the distributed array data structure.
- The PETSc directives return global indices, but
- every process works only on its local copy. */
+/*****************************************************************************
+ *
+ * psi_solver_petsc_var_epsilon_create
+ *
+ *****************************************************************************/
- DMDAGetCorners(da,&xs,&ys,&zs,&xw,&yw,&zw);
+int psi_solver_petsc_var_epsilon_create(psi_t * psi, var_epsilon_t user,
+ psi_solver_petsc_t ** solver) {
- xe = xs + xw;
- ye = ys + yw;
- ze = zs + zw;
+ int ifail = -1; /* Check PETSC is available */
+ int isInitialised = 0;
- psi_epsilon(obj, &epsilon);
+ PetscInitialised(&isInitialised);
- /* 3D-Laplacian with periodic BCs */
- for(k=zs; ksuper.impl = &vart_;
+ petsc->psi = psi;
+ petsc->fe = user.fe;
+ petsc->epsilon = user.epsilon;
+ ifail = psi_solver_petsc_initialise(psi, petsc);
+ if (ifail != 0) free(petsc);
+ if (ifail == 0) *solver = petsc;
}
}
- /* Matrix assembly & halo swap */
- MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
- MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
-
- /* Retain the non-zero structure of the matrix */
- MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);
+ return ifail;
+}
- /* Set the matrix, preconditioner and nullspace */
- KSPSetOperators(ksp,A,A);
- MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_TRUE, 0, NULL, &nullsp);
+/*****************************************************************************
+ *
+ * psi_solver_petsc_free
+ *
+ *****************************************************************************/
-#if PETSC_VERSION_GE(3, 6, 0)
- MatSetNullSpace(A, nullsp);
-#else
- KSPSetNullSpace(ksp, nullsp);
-#endif
+int psi_solver_petsc_free(psi_solver_petsc_t ** solver) {
- MatNullSpaceDestroy(&nullsp);
- KSPSetFromOptions(ksp);
+ assert(solver && *solver);
- if (view_matrix) {
- pe_info(obj->pe, "\nPETSc output matrix\n");
- PetscViewer viewer;
- PetscViewerASCIIOpen(PETSC_COMM_WORLD, "matrix.log", &viewer);
-#if PETSC_VERSION_GE(3, 7, 0)
- PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_INDEX);
- PetscViewerPopFormat(viewer);
-#else
- PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_INDEX);
-#endif
- MatView(A,viewer);;
- PetscViewerDestroy(&viewer);
- }
+ free(*solver);
+ *solver = NULL;
return 0;
}
+
+#ifndef PETSC
+
/*****************************************************************************
*
- * psi_petsc_compute_matrix
+ * psi_solver_petsc_initialise
*
- * Computes the matrix for KSP solver for a system with dielectric contrast.
- * Note that this routine uses the PETSc stencil structure, which permits
- * local assembly of the matrix.
+ * There are two stub routines here for the case that PETSc is not
+ * avialable.
*
*****************************************************************************/
-int psi_petsc_compute_matrix(psi_t * obj, fe_es_t * fe, f_vare_t fepsilon) {
-
- int ic, jc, kc, p;
- int index;
- int noffset[3];
- int i, j, k, ia;
- int xs, ys, zs, xw, yw, zw, xe, ye, ze;
- double eps, grad_eps[3];
-
-#if defined NP_D3Q26
- double v[27];
- MatStencil row, col[27];
-
- const double r10 = 0.1;
- const double r30 = (1.0/30.0);
- const double r15_7 = (7.0/15.0);
- const double r15_64 = (64.0/15.0);
-
- const double matval[27] = {r15_64,
- -r30, -r10 , -r30,
- -r10, -r15_7, -r10,
- -r30, -r10 , -r30,
- -r10, -r15_7, -r10,
- -r15_7, -r15_7,
- -r10, -r15_7, -r10,
- -r30, -r10 , -r30,
- -r10, -r15_7, -r10,
- -r30, -r10 , -r30};
-
-#elif defined NP_D3Q18
- double v[19];
- MatStencil row, col[19];
-
- const double r3 = (1.0/3.0);
- const double r6 = (1.0/6.0);
- const double matval[19] = {4.0,
- -r6, -r6, -r3,
- -r6, -r6, -r6,
- -r3, -r6, -r3,
- -r3, -r6, -r3,
- -r6, -r6, -r6,
- -r3, -r6, -r6};
-
-#else
- /* NP_D3Q6 is the default */
- double v[7];
- MatStencil row, col[7];
- const double matval[7] = {6.0,
- -1.0, -1.0, -1.0,
- -1.0, -1.0, -1.0};
-#endif
+int psi_solver_petsc_initialise(psi_t * psi, psi_solver_petsc_t * solver) {
- assert(obj);
- assert(fe);
- assert(fepsilon);
-
- /* Get details of the distributed array data structure.
- The PETSc directives return global indices, but
- every process works only on its local copy. */
-
- DMDAGetCorners(da,&xs,&ys,&zs,&xw,&yw,&zw);
-
- xe = xs + xw;
- ye = ys + yw;
- ze = zs + zw;
-
- cs_nlocal_offset(obj->cs, noffset);
+ /* No implementation */
+ return -1;
+}
- /* 3D-operator with periodic BCs */
- for(k=zs; kcs, ic, jc, kc);
-
- fepsilon(fe, index, &eps);
- psi_grad_eps_d3qx(obj, (fe_t *) fe, fepsilon, index, grad_eps);
-
- for (p = 0; p < PSI_NGRAD; p++){
+/*****************************************************************************
+ *
+ * psi_solver_petsc_solve
+ *
+ *****************************************************************************/
- /* Laplacian part of operator */
- v[p] = matval[p] * eps;
+int psi_solver_petsc_solve(psi_solver_petsc_t * solver, int ntimestep) {
- /* Addtional terms in generalised Poisson equation */
- for(ia = 0; ia < 3; ia++){
- v[p] -= grad_eps[ia] * psi_gr_wv[p] * psi_gr_rcs2 * psi_gr_cv[p][ia];
- }
+ /* No implementation */
+ return -1;
+}
- }
-
- MatSetValuesStencil(A,1,&row,27,col,v,INSERT_VALUES);
-
-#elif defined NP_D3Q18
- /* 19-point stencil */
- col[0].i = row.i; col[0].j = row.j; col[0].k = row.k;
- col[1].i = i+1; col[1].j = j+1; col[1].k = k;
- col[2].i = i+1; col[2].j = j; col[2].k = k+1;
- col[3].i = i+1; col[3].j = j; col[3].k = k;
- col[4].i = i+1; col[4].j = j; col[4].k = k-1;
- col[5].i = i+1; col[5].j = j-1; col[5].k = k;
- col[6].i = i; col[6].j = j+1; col[6].k = k+1;
- col[7].i = i; col[7].j = j+1; col[7].k = k;
- col[8].i = i; col[8].j = j+1; col[8].k = k-1;
- col[9].i = i; col[9].j = j; col[9].k = k+1;
- col[10].i = i; col[10].j = j; col[10].k = k-1;
- col[11].i = i; col[11].j = j-1; col[11].k = k+1;
- col[12].i = i; col[12].j = j-1; col[12].k = k;
- col[13].i = i; col[13].j = j-1; col[13].k = k-1;
- col[14].i = i-1; col[14].j = j+1; col[14].k = k;
- col[15].i = i-1; col[15].j = j; col[15].k = k+1;
- col[16].i = i-1; col[16].j = j; col[16].k = k;
- col[17].i = i-1; col[17].j = j; col[17].k = k-1;
- col[18].i = i-1; col[18].j = j-1; col[18].k = k;
-
- /* Laplacian part of operator */
- ic = (col[0].i + 1) - noffset[X];
- jc = (col[0].j + 1) - noffset[Y];
- kc = (col[0].k + 1) - noffset[Z];
- index = cs_index(obj->cs, ic, jc, kc);
-
- fepsilon(fe, index, &eps);
- psi_grad_eps_d3qx(obj, (fe_t *) fe, fepsilon, index, grad_eps);
-
- for (p = 0; p < PSI_NGRAD; p++){
+#else
- /* Laplacian part of operator */
- v[p] = matval[p] * eps;
+#include "petscdmda.h"
+#include "petscksp.h"
- /* Addtional terms in generalised Poisson equation */
- for(ia = 0; ia < 3; ia++){
- v[p] -= grad_eps[ia] * psi_gr_wv[p] * psi_gr_rcs2 * psi_gr_cv[p][ia];
- }
+/* Here's the internal state. */
- }
+struct psi_solver_petsc_block_s {
+ DM da; /* Domain management */
+ Mat a; /* System matrix */
+ Vec x; /* Unknown (potential) */
+ Vec b; /* Right-hand side */
+ KSP ksp; /* Krylov solver context */
+};
- MatSetValuesStencil(A,1,&row,19,col,v,INSERT_VALUES);
+/*****************************************************************************
+ *
+ * psi_solver_petsc_initialise
+ *
+ *****************************************************************************/
-#else
- /* 7-point stencil */
- col[0].i = row.i; col[0].j = row.j; col[0].k = row.k;
- col[1].i = i-1; col[1].j = j; col[1].k = k;
- col[2].i = i; col[2].j = j-1; col[2].k = k;
- col[3].i = i; col[3].j = j; col[3].k = k-1;
- col[4].i = i+1; col[4].j = j; col[4].k = k;
- col[5].i = i; col[5].j = j+1; col[5].k = k;
- col[6].i = i; col[6].j = j; col[6].k = k+1;
+int psi_solver_petsc_initialise(psi_t * psi, psi_solver_petsc_t * solver) {
- ic = (col[0].i + 1) - noffset[X];
- jc = (col[0].j + 1) - noffset[Y];
- kc = (col[0].k + 1) - noffset[Z];
- index = cs_index(obj->cs, ic, jc, kc);
+ assert(psi);
+ assert(solver);
- fepsilon(fe, index, &eps);
- psi_grad_eps_d3qx(obj, (fe_t *) fe, fepsilon, index, grad_eps);
+ {
+ size_t sz = sizeof(psi_solver_petsc_block_t);
+ solver->block = (psi_solver_petsc_block_t *) calloc(1, sz);
+ assert(solver->block);
+ if (solver->block == NULL) return -1;
+ }
- for (p = 0; p < PSI_NGRAD; p++){
+ /* In order for the DMDA and the Cartesian MPI communicator
+ * to share the same part of the domain decomposition it is
+ * necessary to renumber the process ranks of the default
+ * PETSc communicator. Default PETSc is column major decomposition. */
+
+ {
+ cs_t * cs = psi->cs;
+ int coords[3] = {0};
+ int cartsz[3] = {0};
+ int ntotal[3] = {0};
+ int nhalo = -1;
+ int rank = -1;
+
+ MPI_Comm comm = MPI_COMM_NULL;
+ DMBoundaryType periodic = DM_BOUNDARY_PERIODIC;
+
+ cs_cartsz(cs, cartsz);
+ cs_cart_coords(cs, coords);
+ cs_nhalo(cs, &nhalo);
+ cs_ntotal(cs, ntotal);
+
+ /* Set new rank according to PETSc ordering */
+ /* Create communicator with new ranks according to PETSc ordering */
+ /* Override default PETSc communicator */
+
+ rank = coords[Z]*cartsz[Y]*cartsz[X] + coords[Y]*cartsz[X] + coords[X];
+ MPI_Comm_split(PETSC_COMM_WORLD, 1, rank, &comm);
+ PETSC_COMM_WORLD = comm;
+
+ /* Create 3D distributed array (always periodic) */
+
+ DMDACreate3d(PETSC_COMM_WORLD, periodic, periodic, periodic,
+ DMDA_STENCIL_BOX, ntotal[X], ntotal[Y], ntotal[Z],
+ cartsz[X], cartsz[Y], cartsz[Z], 1, nhalo,
+ NULL, NULL, NULL, &solver->block->da);
+
+ PetscCall(DMSetVecType(solver->block->da, VECSTANDARD));
+ PetscCall(DMSetMatType(solver->block->da, MATMPIAIJ));
+ PetscCall(DMSetUp(solver->block->da));
+ }
- /* Laplacian part of operator */
- v[p] = matval[p] * eps;
+ /* Create global vectors and matrix */
- /* Addtional terms in generalised Poisson equation */
- for(ia = 0; ia < 3; ia++){
- v[p] -= grad_eps[ia] * psi_gr_wv[p] * psi_gr_rcs2 * psi_gr_cv[p][ia];
- }
+ DMCreateMatrix(solver->block->da, &solver->block->a);
+ DMCreateGlobalVector(solver->block->da, &solver->block->x);
+ VecDuplicate(solver->block->x, &solver->block->b);
- }
+ /* Initialise solver context */
- MatSetValuesStencil(A,1,&row,7,col,v,INSERT_VALUES);
-#endif
+ {
+ PetscReal abstol = psi->solver.abstol;
+ PetscReal rtol = psi->solver.reltol;
+ PetscInt maxits = psi->solver.maxits;
- }
- }
+ KSPCreate(PETSC_COMM_WORLD, &solver->block->ksp);
+ KSPSetOperators(solver->block->ksp, solver->block->a, solver->block->a);
+ KSPSetTolerances(solver->block->ksp, rtol, abstol, PETSC_DEFAULT, maxits);
}
- /* Matrix assembly & halo swap */
- MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
- MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
- /* Retain the non-zero structure of the matrix */
- MatSetOption(A,MAT_NEW_NONZERO_LOCATIONS,PETSC_FALSE);
-
- /* Set the matrix, preconditioner and nullspace */
- KSPSetOperators(ksp,A,A);
- MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_TRUE, 0, NULL, &nullsp);
+ /* Not required in var-epsilon case, but no harm. */
+ psi_solver_petsc_matrix_set(solver);
-#if PETSC_VERSION_GE(3, 6, 0)
- MatSetNullSpace(A, nullsp);
-#else
- KSPSetNullSpace(ksp, nullsp);
-#endif
-
- MatNullSpaceDestroy(&nullsp);
- KSPSetFromOptions(ksp);
-
- if (view_matrix) {
- pe_info(obj->pe, "\nPETSc output matrix\n");
- PetscViewer viewer;
- PetscViewerASCIIOpen(PETSC_COMM_WORLD, "matrix.log", &viewer);
-#if PETSC_VERSION_GE(3, 7, 0)
- PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_INDEX);
- PetscViewerPopFormat(viewer);
-#else
- PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_INDEX);
-#endif
- MatView(A,viewer);;
- PetscViewerDestroy(&viewer);
- }
+ KSPSetUp(solver->block->ksp);
return 0;
}
/*****************************************************************************
*
- * psi_petsc_copy_psi_to_da
+ * psi_solver_petsc_matrix_set
*
*****************************************************************************/
-int psi_petsc_copy_psi_to_da(psi_t * obj) {
+int psi_solver_petsc_matrix_set(psi_solver_petsc_t * solver) {
+
+ int xs, ys, zs;
+ int xw, yw, zw;
+ int xe, ye, ze;
+ double epsilon;
- int ic,jc,kc,index;
- int noffset[3];
- int i,j,k;
- int xs,ys,zs,xw,yw,zw,xe,ye,ze;
- double *** psi_3d;
+ double v[27] = {0}; /* Accomodate largest current stencil */
+ MatStencil col[27] = {0}; /* Ditto */
- assert(obj);
- cs_nlocal_offset(obj->cs, noffset);
+ stencil_t * s = solver->psi->stencil;
- DMDAGetCorners(da,&xs,&ys,&zs,&xw,&yw,&zw);
- DMDAVecGetArray(da, x, &psi_3d);
+ assert(solver);
+ assert(solver->psi->solver.nstencil <= 27);
+
+ /* Obtain start and width ... */
+ DMDAGetCorners(solver->block->da, &xs, &ys, &zs, &xw, &yw, &zw);
xe = xs + xw;
ye = ys + yw;
ze = zs + zw;
- for (k=zs; kpsi, &epsilon);
- index = cs_index(obj->cs, ic,jc,kc);
- psi_3d[k][j][i] = obj->psi[index];
+ for (int k = zs; k < ze; k++) {
+ for (int j = ys; j < ye; j++) {
+ for (int i = xs; i < xe; i++) {
+ MatStencil row = {.i = i, .j = j, .k = k};
+
+ for (int p = 0; p < s->npoints; p++) {
+ col[p].i = i + s->cv[p][X];
+ col[p].j = j + s->cv[p][Y];
+ col[p].k = k + s->cv[p][Z];
+ v[p] = s->wlaplacian[p]*epsilon;
+ }
+ MatSetValuesStencil(solver->block->a, 1, &row, s->npoints, col, v,
+ INSERT_VALUES);
}
}
}
- DMDAVecRestoreArray(da, x, &psi_3d);
+ /* Matrix assembly & halo swap */
+ /* Retain the non-zero structure of the matrix */
- if (view_vector) {
- pe_info(obj->pe, "\nPETSc output DA vector\n");
- PetscViewer viewer;
- PetscViewerASCIIOpen(PETSC_COMM_WORLD, "da.log", &viewer);
-#if PETSC_VERSION_GE(3, 7, 0)
- PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_INDEX);
- PetscViewerPopFormat(viewer);
-#else
- PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_INDEX);
-#endif
- VecView(x,viewer);
- PetscViewerDestroy(&viewer);
+ MatAssemblyBegin(solver->block->a, MAT_FINAL_ASSEMBLY);
+ MatAssemblyEnd(solver->block->a, MAT_FINAL_ASSEMBLY);
+ MatSetOption(solver->block->a, MAT_NEW_NONZERO_LOCATIONS, PETSC_FALSE);
+
+ /* Set the matrix, and the nullspace */
+ KSPSetOperators(solver->block->ksp, solver->block->a, solver->block->a);
+
+ {
+ MatNullSpace nullsp;
+ MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_TRUE, 0, NULL, &nullsp);
+ MatSetNullSpace(solver->block->a, nullsp);
+ MatNullSpaceDestroy(&nullsp);
}
return 0;
@@ -640,467 +345,564 @@ int psi_petsc_copy_psi_to_da(psi_t * obj) {
/*****************************************************************************
*
- * psi_petsc_copy_da_to_psi
+ * psi_solver_petsc_solve
*
*****************************************************************************/
-int psi_petsc_copy_da_to_psi(psi_t * obj) {
-
- int ic,jc,kc,index;
- int noffset[3];
- int i,j,k;
- int xs,ys,zs,xw,yw,zw,xe,ye,ze;
- double *** psi_3d;
-
- assert(obj);
- cs_nlocal_offset(obj->cs, noffset);
+int psi_solver_petsc_solve(psi_solver_petsc_t * solver, int ntimestep) {
- DMDAGetCorners(da,&xs,&ys,&zs,&xw,&yw,&zw);
- DMDAVecGetArray(da, x, &psi_3d);
-
- xe = xs + xw;
- ye = ys + yw;
- ze = zs + zw;
+ assert(solver);
- for (k=zs; kcs, ic,jc,kc);
- obj->psi[index] = psi_3d[k][j][i];
+ KSPSetInitialGuessNonzero(solver->block->ksp, PETSC_TRUE);
+ KSPSolve(solver->block->ksp, solver->block->b, solver->block->x);
- }
- }
+ if (ntimestep % solver->psi->solver.nfreq == 0) {
+ /* Report on progress of the solver.
+ * Note the default Petsc residual is the preconditioned L2 norm. */
+ pe_t * pe = solver->psi->pe;
+ PetscInt its = 0;
+ PetscReal norm = 0.0;
+ PetscCall(KSPGetIterationNumber(solver->block->ksp, &its));
+ PetscCall(KSPGetResidualNorm(solver->block->ksp, &norm));
+ pe_info(pe, "\n");
+ pe_info(pe, "Krylov solver\n");
+ pe_info(pe, "Norm of residual %g at %d iterations\n", norm, its);
}
- DMDAVecRestoreArray(da, x, &psi_3d);
-
- psi_halo_psi(obj);
+ psi_solver_petsc_da_to_psi(solver);
return 0;
}
/*****************************************************************************
*
- * psi_petsc_set_rhs
- *
- * Sets the right hand side of the Poisson equation and
- * modifies the boundary sites if an external electric
- * field is present.
+ * psi_solver_petsc_rhs_set
*
*****************************************************************************/
-int psi_petsc_set_rhs(psi_t * obj) {
-
- int ic,jc,kc,index;
- int mpi_cartsz[3], mpi_coords[3];
- int ntotal[3], noffset[3];
- int periodic[3];
- int i,j,k;
- int xs,ys,zs,xw,yw,zw,xe,ye,ze;
- double *** rho_3d;
- double rho_elec;
- double eunit, beta;
- double epsilon, e0[3];
-
- physics_t * phys = NULL;
-
- assert(obj);
-
- cs_cartsz(obj->cs, mpi_cartsz);
- cs_cart_coords(obj->cs, mpi_coords);
- cs_nlocal_offset(obj->cs, noffset);
- cs_periodic(obj->cs, periodic);
-
- DMDAGetCorners(da,&xs,&ys,&zs,&xw,&yw,&zw);
- DMDAVecGetArray(da, b, &rho_3d);
-
- psi_unit_charge(obj, &eunit);
- psi_beta(obj, &beta);
-
- xe = xs + xw;
- ye = ys + yw;
- ze = zs + zw;
-
- for (k=zs; kcs, ic,jc,kc);
- psi_rho_elec(obj, index, &rho_elec);
- /* Non-dimensional potential in Poisson eqn requires e/kT */
- rho_3d[k][j][i] = rho_elec * eunit * beta;
-
- }
- }
- }
+int psi_solver_petsc_rhs_set(psi_solver_petsc_t * solver) {
+
+ cs_t * cs = NULL;
+ int xs, ys, zs;
+ int xw, yw, zw;
+ int xe, ye, ze;
+ int offset[3] = {0};
+ double e0[3] = {0};
+ double *** rho_3d = {0};
+
+ assert(solver);
+
+ cs = solver->psi->cs;
+ cs_nlocal_offset(cs, offset);
+
+ DMDAGetCorners(solver->block->da, &xs, &ys, &zs, &xw, &yw, &zw);
+ DMDAVecGetArray(solver->block->da, solver->block->b, &rho_3d);
+
+ xe = xs + xw;
+ ye = ys + yw;
+ ze = zs + zw;
+
+ for (int k = zs; k < ze; k++) {
+ int kc = k - offset[Z] + 1;
+ for (int j = ys; j < ye; j++) {
+ int jc = j - offset[Y] + 1;
+ for (int i = xs; i < xe; i++) {
+
+ int ic = i - offset[X] + 1;
+ int index = cs_index(cs, ic, jc, kc);
+ double rho_elec = 0.0;
+ /* Non-dimensional potential in Poisson eqn requires e/kT */
+ double eunit = solver->psi->e;
+ double beta = solver->psi->beta;
+
+ psi_rho_elec(solver->psi, index, &rho_elec);
+ rho_3d[k][j][i] = rho_elec*eunit*beta;
+ }
+ }
+ }
/* Modify right hand side for external electric field */
- physics_ref(&phys);
- physics_e0(phys, e0);
+ /* The system must be periodic, so no need to check. */
+
+ e0[X] = solver->psi->e0[X];
+ e0[Y] = solver->psi->e0[Y];
+ e0[Z] = solver->psi->e0[Z];
if (e0[X] || e0[Y] || e0[Z]) {
- cs_ntotal(obj->cs, ntotal);
+ int ntotal[3] = {0};
+ int mpi_coords[3] = {0};
+ int mpi_cartsz[3] = {0};
+ double epsilon = 0.0;
- psi_epsilon(obj, &epsilon);
+ cs_ntotal(cs, ntotal);
+ cs_cart_coords(cs, mpi_coords);
+ cs_cartsz(cs, mpi_cartsz);
- if (periodic[X]) {
+ psi_epsilon(solver->psi, &epsilon);
- if (mpi_coords[X] == 0) {
- for (k=zs; kblock->da, solver->block->b, &rho_3d);
- }
-
- DMDAVecRestoreArray(da, b, &rho_3d);
-
- if (view_vector) {
- pe_info(obj->pe, "\nPETSc output RHS\n");
- PetscViewer viewer;
- PetscViewerASCIIOpen(PETSC_COMM_WORLD, "rhs.log", &viewer);
-#if PETSC_VERSION_GE(3, 7, 0)
- PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_INDEX);
- PetscViewerPopFormat(viewer);
-#else
- PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_INDEX);
-#endif
- VecView(b,viewer);;
- PetscViewerDestroy(&viewer);
- }
-
- return 0;
+ return 0;
}
/*****************************************************************************
*
- * psi_petsc_set_rhs_vare
+ * psi_solver_petsc_psi_to_da
*
- * Sets the right hand side of the Poisson equation and modifies
- * the boundary sites if an external electric field is present,
- * acounting for dielectric contrast.
+ * Copy the potential from the psi_t represetation to the solution
+ * vector as an initial guess.
*
*****************************************************************************/
-int psi_petsc_set_rhs_vare(psi_t * obj, fe_es_t * fe, f_vare_t fepsilon) {
-
- int ic,jc,kc,index;
- int mpi_cartsz[3], mpi_coords[3];
- int ntotal[3], noffset[3];
- int periodic[3];
- int i,j,k;
- int xs,ys,zs,xw,yw,zw,xe,ye,ze;
- double *** rho_3d;
- double rho_elec;
- double eunit, beta;
- double eps, e0[3];
-
- physics_t * phys = NULL;
-
- assert(obj);
- assert(fe);
- assert(fepsilon);
-
- cs_cartsz(obj->cs, mpi_cartsz);
- cs_cart_coords(obj->cs, mpi_coords);
- cs_nlocal_offset(obj->cs, noffset);
- cs_periodic(obj->cs, periodic);
-
- DMDAGetCorners(da,&xs,&ys,&zs,&xw,&yw,&zw);
- DMDAVecGetArray(da, b, &rho_3d);
-
- psi_unit_charge(obj, &eunit);
- psi_beta(obj, &beta);
-
- xe = xs + xw;
- ye = ys + yw;
- ze = zs + zw;
-
- for (k=zs; kcs, ic,jc,kc);
- psi_rho_elec(obj, index, &rho_elec);
- /* Non-dimensional potential in Poisson eqn requires e/kT */
- rho_3d[k][j][i] = rho_elec * eunit * beta;
-
- }
- }
- }
+int psi_solver_petsc_psi_to_da(psi_solver_petsc_t * solver) {
- /* Modify right hand side for external electric field */
- physics_ref(&phys);
- physics_e0(phys, e0);
-
- if (e0[X] || e0[Y] || e0[Z]) {
+ cs_t * cs = NULL;
+ int xs, ys, zs;
+ int xw, yw, zw;
+ int xe, ye, ze;
+ int offset[3] = {0};
+ double *** psi_3d = NULL;
- cs_ntotal(obj->cs, ntotal);
+ assert(solver);
- if (periodic[X]) {
+ cs = solver->psi->cs;
+ cs_nlocal_offset(cs, offset);
- if (mpi_coords[X] == 0) {
- i = 0;
- ic = i - noffset[X] + 1;
- for (k=zs; kblock->da, &xs, &ys, &zs, &xw, &yw, &zw);
+ DMDAVecGetArray(solver->block->da, solver->block->x, &psi_3d);
- index = cs_index(obj->cs, ic,jc,kc);
- fepsilon(fe, index, &eps);
- rho_3d[k][j][i] += eps * e0[X] * ntotal[X];
+ xe = xs + xw;
+ ye = ys + yw;
+ ze = zs + zw;
- }
- }
+ for (int k = zs; k < ze; k++) {
+ int kc = k - offset[Z] + 1;
+ for (int j = ys; j < ye; j++) {
+ int jc = j - offset[Y] + 1;
+ for (int i = xs; i < xe; i++) {
+ int ic = i - offset[X] + 1;
+ int index = cs_index(cs, ic, jc, kc);
+ psi_3d[k][j][i] = solver->psi->psi->data[index];
}
+ }
+ }
- if (mpi_coords[X] == mpi_cartsz[X]-1) {
- i = xe - 1;
- ic = i - noffset[X] + 1;
- for (k=zs; kcs, ic,jc,kc);
- fepsilon(fe, index, &eps);
- rho_3d[k][j][i] -= eps * e0[X] * ntotal[X];
+ DMDAVecRestoreArray(solver->block->da, solver->block->x, &psi_3d);
- }
- }
- }
+ return 0;
+}
- }
+/*****************************************************************************
+ *
+ * psi_solver_petsc_da_to_psi
+ *
+ * Copy te Petsc solution back to the psi_t represetation.
+ *
+ *****************************************************************************/
- if (periodic[Y]) {
+int psi_solver_petsc_da_to_psi(psi_solver_petsc_t * solver) {
- if (mpi_coords[Y] == 0) {
- j = 0;
- jc = j - noffset[Y] + 1;
- for (k=zs; kcs, ic,jc,kc);
- fepsilon(fe, index, &eps);
- rho_3d[k][j][i] += eps * e0[Y] * ntotal[Y];
+ assert(solver);
- }
- }
- }
+ cs = solver->psi->cs;
+ cs_nlocal_offset(cs, offset);
- if (mpi_coords[Y] == mpi_cartsz[Y]-1) {
- j = ye - 1;
- jc = j - noffset[Y] + 1;
- for (k=zs; kblock->da, &xs, &ys, &zs, &xw, &yw, &zw);
+ DMDAVecGetArray(solver->block->da, solver->block->x, &psi_3d);
- index = cs_index(obj->cs, ic,jc,kc);
- fepsilon(fe, index, &eps);
- rho_3d[k][j][i] -= eps * e0[Y] * ntotal[Y];
+ xe = xs + xw;
+ ye = ys + yw;
+ ze = zs + zw;
- }
- }
+ for (int k = zs; k < ze; k++) {
+ int kc = k - offset[Z] + 1;
+ for (int j = ys; j < ye; j++) {
+ int jc = j - offset[Y] + 1;
+ for (int i = xs; i < xe; i++) {
+ int ic = i - offset[X] + 1;
+ int index = cs_index(cs, ic, jc, kc);
+ solver->psi->psi->data[index] = psi_3d[k][j][i];
}
-
}
+ }
- if (periodic[Z]) {
-
- if (mpi_coords[Z] == 0) {
- k = 0;
- kc = k - noffset[Z] + 1;
- for (j=ys; jblock->da, solver->block->x, &psi_3d);
- index = cs_index(obj->cs, ic,jc,kc);
- fepsilon(fe, index, &eps);
- rho_3d[k][j][i] += eps * e0[Z] * ntotal[Z];
+ return 0;
+}
- }
- }
- }
+/*****************************************************************************
+ *
+ * psi_solver_petsc_var_epsilon_solve
+ *
+ *****************************************************************************/
- if (mpi_coords[Z] == mpi_cartsz[Z]-1) {
- k = ze - 1;
- kc = k - noffset[Z] + 1;
- for (j=ys; jcs, ic,jc,kc);
- fepsilon(fe, index, &eps);
- rho_3d[k][j][i] -= eps * e0[Z] * ntotal[Z];
+ assert(solver);
- }
- }
- }
+ psi_solver_petsc_var_epsilon_matrix_set(solver);
+ psi_solver_petsc_var_epsilon_rhs_set(solver);
- }
+ psi_solver_petsc_psi_to_da(solver);
+ KSPSetInitialGuessNonzero(solver->block->ksp, PETSC_TRUE);
+ KSPSolve(solver->block->ksp, solver->block->b, solver->block->x);
+ if (nt % solver->psi->solver.nfreq == 0) {
+ /* Report on progress of the solver.
+ * Note the default Petsc residual is the preconditioned L2 norm. */
+ pe_t * pe = solver->psi->pe;
+ PetscInt its = 0;
+ PetscReal norm = 0.0;
+ PetscCall(KSPGetIterationNumber(solver->block->ksp, &its));
+ PetscCall(KSPGetResidualNorm(solver->block->ksp, &norm));
+ pe_info(pe, "\n");
+ pe_info(pe, "Krylov solver (with dielectric contrast)\n");
+ pe_info(pe, "Norm of residual %g at %d iterations\n", norm, its);
}
-
- DMDAVecRestoreArray(da, b, &rho_3d);
-
- if (view_vector) {
- pe_info(obj->pe, "\nPETSc output RHS\n");
- PetscViewer viewer;
- PetscViewerASCIIOpen(PETSC_COMM_WORLD, "rhs.log", &viewer);
-#if PETSC_VERSION_GE(3, 7, 0)
- PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_INDEX);
- PetscViewerPopFormat(viewer);
-#else
- PetscViewerSetFormat(viewer, PETSC_VIEWER_ASCII_INDEX);
-#endif
- VecView(b,viewer);;
- PetscViewerDestroy(&viewer);
- }
-
- return 0;
+ psi_solver_petsc_da_to_psi(solver);
+
+ return 0;
}
/*****************************************************************************
*
- * psi_petsc_solve
- *
- * If the f_vare_t argument is NULL, the uniform epsilon solver is used.
- * If the argument is present, the non-uniform solver is used.
+ * psi_solver_petsc_var_epsilon_matrix_set
*
*****************************************************************************/
-int psi_petsc_solve(psi_t * obj, fe_t * fe, f_vare_t fepsilon) {
+int psi_solver_petsc_var_epsilon_matrix_set(psi_solver_petsc_t * solver) {
+
+ cs_t * cs = NULL;
+ int xs, ys, zs;
+ int xw, yw, zw;
+ int xe, ye, ze;
+ int offset[3] = {0};
+
+ double v[27] = {0};
+ MatStencil col[27] = {0};
+ stencil_t * s = solver->psi->stencil;
+
+ assert(solver);
+
+ cs = solver->psi->cs;
+ cs_nlocal_offset(cs, offset);
- assert(obj);
- assert(fe);
+ /* Get details of the distributed array data structure.
+ The PETSc directives return global indices, but
+ every process works only on its local copy. */
+
+ DMDAGetCorners(solver->block->da, &xs, &ys, &zs, &xw, &yw, &zw);
+
+ xe = xs + xw;
+ ye = ys + yw;
+ ze = zs + zw;
+
+ /* 3D-operator with periodic BCs */
+
+ for (int k = zs; k < ze; k++) {
+ int kc = 1 + k - offset[Z];
+ for (int j = ys; j < ye; j++) {
+ int jc = 1 + j - offset[Y];
+ for (int i = xs; i < xe; i++) {
+
+ int ic = 1 + i - offset[X];
+ int index = cs_index(cs, ic, jc, kc);
+ double epsilon0 = 0.0;
+ double gradeps[3] = {0};
+
+ MatStencil row = {.i = i, .j = j, .k = k};
+
+ solver->epsilon(solver->fe, index, &epsilon0);
+
+ /* Local approx. to grad epsilon ... */
+ for (int p = 1; p < s->npoints; p++) {
+ int ic1 = ic + s->cv[p][X];
+ int jc1 = jc + s->cv[p][Y];
+ int kc1 = kc + s->cv[p][Z];
+ int index1 = cs_index(cs, ic1, jc1, kc1);
+ double epsilon1 = 0.0;
+ solver->epsilon(solver->fe, index1, &epsilon1);
+ gradeps[X] += s->wgradients[p]*s->cv[p][X]*epsilon1;
+ gradeps[Y] += s->wgradients[p]*s->cv[p][Y]*epsilon1;
+ gradeps[Z] += s->wgradients[p]*s->cv[p][Z]*epsilon1;
+ }
+
+ for (int p = 0; p < s->npoints; p++) {
+ col[p].i = i + s->cv[p][X];
+ col[p].j = j + s->cv[p][Y];
+ col[p].k = k + s->cv[p][Z];
+
+ /* Laplacian part of operator */
+ v[p] = s->wlaplacian[p]*epsilon0;
+
+ /* Addtional terms in generalised Poisson equation */
+ v[p] += s->wgradients[p]*s->cv[p][X]*gradeps[X];
+ v[p] += s->wgradients[p]*s->cv[p][Y]*gradeps[Y];
+ v[p] += s->wgradients[p]*s->cv[p][Z]*gradeps[Z];
+ }
- if(fepsilon == NULL) {
- psi_petsc_set_rhs(obj);
+ MatSetValuesStencil(solver->block->a, 1, &row, s->npoints, col, v,
+ INSERT_VALUES);
+ }
+ }
}
- if(fepsilon != NULL) {
- psi_petsc_compute_matrix(obj, (fe_es_t *) fe, fepsilon);
- psi_petsc_set_rhs_vare(obj, (fe_es_t *) fe, fepsilon);
+ /* Matrix assembly & halo swap */
+ /* Retain the non-zero structure of the matrix */
+
+ MatAssemblyBegin(solver->block->a, MAT_FINAL_ASSEMBLY);
+ MatAssemblyEnd(solver->block->a, MAT_FINAL_ASSEMBLY);
+ MatSetOption(solver->block->a, MAT_NEW_NONZERO_LOCATIONS, PETSC_FALSE);
+
+ /* Set the matrix, preconditioner and nullspace */
+ KSPSetOperators(solver->block->ksp, solver->block->a, solver->block->a);
+
+ {
+ MatNullSpace nullsp;
+ MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_TRUE, 0, NULL, &nullsp);
+ MatSetNullSpace(solver->block->a, nullsp);
+ MatNullSpaceDestroy(&nullsp);
}
- psi_petsc_copy_psi_to_da(obj);
- psi_petsc_poisson(obj);
- psi_petsc_copy_da_to_psi(obj);
+ KSPSetFromOptions(solver->block->ksp);
return 0;
}
/*****************************************************************************
*
- * psi_petsc_poisson
+ * psi_solver_petsc_var_epsilon_rhs_set
*
- * Solves the Poisson equation for constant permittivity.
- * The vectors b, x are distributed arrays (DA).
+ * The only difference here (cf. uniform epsilon) is in the external
+ * field terms.
*
*****************************************************************************/
-int psi_petsc_poisson(psi_t * obj) {
+int psi_solver_petsc_var_epsilon_rhs_set(psi_solver_petsc_t * solver) {
+
+ cs_t * cs = NULL;
+ int xs, ys, zs;
+ int xw, yw, zw;
+ int xe, ye, ze;
+ int offset[3] = {0};
+ double e0[3] = {0};
+ double *** rho_3d = {0};
- assert(obj);
+ assert(solver);
- KSPSetInitialGuessNonzero(ksp,PETSC_TRUE);
- KSPSolve(ksp,b,x);
+ cs = solver->psi->cs;
+ cs_nlocal_offset(cs, offset);
- if (is_statistics_step()) {
- KSPGetResidualNorm(ksp,&norm);
- KSPGetIterationNumber(ksp,&its);
- pe_info(obj->pe, "\nKrylov solver\nNorm of residual %g at %d iterations\n",norm,its);
+ DMDAGetCorners(solver->block->da, &xs, &ys, &zs, &xw, &yw, &zw);
+ DMDAVecGetArray(solver->block->da, solver->block->b, &rho_3d);
+
+ xe = xs + xw;
+ ye = ys + yw;
+ ze = zs + zw;
+
+ for (int k = zs; k < ze; k++) {
+ int kc = k - offset[Z] + 1;
+ for (int j = ys; j < ye; j++) {
+ int jc = j - offset[Y] + 1;
+ for (int i = xs; i < xe; i++) {
+
+ int ic = i - offset[X] + 1;
+ int index = cs_index(cs, ic, jc, kc);
+ double rho_elec = 0.0;
+ /* Non-dimensional potential in Poisson eqn requires e/kT */
+ double eunit = solver->psi->e;
+ double beta = solver->psi->beta;
+
+ psi_rho_elec(solver->psi, index, &rho_elec);
+ rho_3d[k][j][i] = rho_elec*eunit*beta;
+ }
+ }
}
+ /* Modify right hand side for external electric field */
+ /* The system must be periodic, so no need to check. */
+
+ e0[X] = solver->psi->e0[X];
+ e0[Y] = solver->psi->e0[Y];
+ e0[Z] = solver->psi->e0[Z];
+
+ if (e0[X] || e0[Y] || e0[Z]) {
+
+ int ntotal[3] = {0};
+ int mpi_coords[3] = {0};
+ int mpi_cartsz[3] = {0};
+
+ cs_ntotal(cs, ntotal);
+ cs_cart_coords(cs, mpi_coords);
+ cs_cartsz(cs, mpi_cartsz);
+
+ if (e0[X] && mpi_coords[X] == 0) {
+ for (int k = zs; k < ze; k++) {
+ int kc = 1 + k - offset[Z];
+ for (int j = ys; j < ye; j++) {
+ int jc = 1 + j - offset[Y];
+ int index = cs_index(cs, 1, jc, kc);
+ double epsilon = 0.0;
+ solver->epsilon(solver->fe, index, &epsilon);
+ rho_3d[k][j][0] += epsilon*e0[X]*ntotal[X];
+ }
+ }
+ }
+
+ if (e0[X] && mpi_coords[X] == mpi_cartsz[X] - 1) {
+ for (int k = zs; k < ze; k++) {
+ int kc = 1 + k - offset[Z];
+ for (int j = ys; j < ye; j++) {
+ int jc = 1 + j - offset[Y];
+ int ic = xe - offset[X];
+ int index = cs_index(cs, ic, jc, kc);
+ double epsilon = 0.0;
+ solver->epsilon(solver->fe, index, &epsilon);
+ rho_3d[k][j][xe-1] -= epsilon*e0[X]*ntotal[X];
+ }
+ }
+ }
+
+ if (e0[Y] && mpi_coords[Y] == 0) {
+ for (int k = zs; k < ze; k++) {
+ int kc = 1 + k - offset[Z];
+ for (int i = xs; i < xe; i++) {
+ int ic = 1 + i - offset[X];
+ int index = cs_index(cs, ic, 1, kc);
+ double epsilon = 0.0;
+ solver->epsilon(solver->fe, index, &epsilon);
+ rho_3d[k][0][i] += epsilon*e0[Y]*ntotal[Y];
+ }
+ }
+ }
+
+ if (e0[Y] && mpi_coords[Y] == mpi_cartsz[Y] - 1) {
+ for (int k = zs; k < ze; k++) {
+ int kc = 1 + k - offset[Z];
+ for (int i = xs; i < xe; i++) {
+ int jc = ye - offset[Y];
+ int ic = 1 + i - offset[X];
+ int index = cs_index(cs, ic, jc, kc);
+ double epsilon = 0.0;
+ solver->epsilon(solver->fe, index, &epsilon);
+ rho_3d[k][ye-1][i] -= epsilon*e0[Y]*ntotal[Y];
+ }
+ }
+ }
+
+ if (e0[Z] && mpi_coords[Z] == 0) {
+ for (int j = ys; j < ye; j++) {
+ int jc = 1 + j - offset[Y];
+ for (int i = xs; i < xe; i++) {
+ int ic = 1 + i - offset[X];
+ int index = cs_index(cs, ic, jc, 1);
+ double epsilon = 0.0;
+ solver->epsilon(solver->fe, index, &epsilon);
+ rho_3d[0][j][i] += epsilon*e0[Z]*ntotal[Z];
+ }
+ }
+ }
+
+ if (e0[Z] && mpi_coords[Z] == mpi_cartsz[Z] - 1) {
+ int kc = ze - offset[Z];
+ for (int j = ys; j < ye; j++) {
+ int jc = 1 + j - offset[Y];
+ for (int i = xs; i < xe; i++) {
+ int ic = 1 + i - offset[X];
+ int index = cs_index(cs, ic, jc, kc);
+ double epsilon = 0.0;
+ solver->epsilon(solver->fe, index, &epsilon);
+ rho_3d[ze-1][j][i] -= epsilon*e0[Z]*ntotal[Z];
+ }
+ }
+ }
+ }
+
+ DMDAVecRestoreArray(solver->block->da, solver->block->b, &rho_3d);
+
return 0;
}
/*****************************************************************************
*
- * psi_petsc_finish
- *
- * Destroys the solver context, distributed array, matrix and vectors.
+ * psi_solver_petsc_finalise
*
*****************************************************************************/
-int psi_petsc_finish() {
+int psi_solver_petsc_finalise(psi_solver_petsc_t * solver) {
+
+ assert(solver);
+
+ PetscCall(KSPDestroy(&solver->block->ksp));
+ PetscCall(VecDestroy(&solver->block->x));
+ PetscCall(VecDestroy(&solver->block->b));
+ PetscCall(MatDestroy(&solver->block->a));
+ PetscCall(DMDestroy(&solver->block->da));
- KSPDestroy(&ksp);
- VecDestroy(&x);
- VecDestroy(&b);
- MatDestroy(&A);
- DMDestroy(&da);
+ free(solver->block);
return 0;
}
diff --git a/src/psi_petsc.h b/src/psi_petsc.h
index 8cffc3139..419a6131f 100644
--- a/src/psi_petsc.h
+++ b/src/psi_petsc.h
@@ -1,14 +1,11 @@
-#ifdef PETSC
/*****************************************************************************
*
* psi_petsc.h
*
- * $Id$
- *
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2012-2013 The University of Edinburgh
+ * (c) 2012-2023 The University of Edinburgh
*
* Contributing Authors:
* Oliver Henrich (ohenrich@epcc.ed.ac.uk)
@@ -16,23 +13,29 @@
*
*****************************************************************************/
-#ifndef PSI_PETSC_H
-#define PSI_PETSC_H
+#ifndef LUDWIG_PSI_SOLVER_PETSC_H
+#define LUDWIG_PSI_SOLVER_PETSC_H
-#include "psi.h"
-#include "fe_electro_symmetric.h"
+#include "psi_solver.h"
-int psi_petsc_init(psi_t * obj, fe_t * fe, f_vare_t fepsilon);
-int psi_petsc_copy_psi_to_da(psi_t * obj);
-int psi_petsc_copy_da_to_psi(psi_t * obj);
-int psi_petsc_compute_laplacian(psi_t * obj);
-int psi_petsc_set_rhs(psi_t * obj);
-int psi_petsc_compute_matrix(psi_t * obj, fe_es_t * fe, f_vare_t fepsilon);
-int psi_petsc_set_rhs_vare(psi_t * obj, fe_es_t * fe, f_vare_t epsilon);
-int psi_petsc_solve(psi_t * obj, fe_t * fe, f_vare_t fepsilon);
-int psi_petsc_poisson(psi_t * obj);
-int psi_petsc_finish();
+typedef struct psi_solver_petsc_s psi_solver_petsc_t;
+typedef struct psi_solver_petsc_block_s psi_solver_petsc_block_t;
+
+struct psi_solver_petsc_s {
+ psi_solver_t super; /* Superclass block */
+ psi_t * psi; /* Retain a reference to psi_t */
+ fe_t * fe; /* Free energy */
+ var_epsilon_ft epsilon; /* Variable dielectric model */
+ psi_solver_petsc_block_t * block; /* Opaque internal information. */
+};
+
+int psi_solver_petsc_create(psi_t * psi, psi_solver_petsc_t ** solver);
+int psi_solver_petsc_free(psi_solver_petsc_t ** solver);
+int psi_solver_petsc_solve(psi_solver_petsc_t * solver, int ntimestep);
+
+int psi_solver_petsc_var_epsilon_create(psi_t * psi, var_epsilon_t epsilon,
+ psi_solver_petsc_t ** solver);
+int psi_solver_petsc_var_epsilon_solve(psi_solver_petsc_t * solver, int nt);
-#endif
#endif
diff --git a/src/psi_rt.c b/src/psi_rt.c
index f7faf4cec..99638cb5c 100644
--- a/src/psi_rt.c
+++ b/src/psi_rt.c
@@ -10,7 +10,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2012-2022 The University of Edinburgh
+ * (c) 2012-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -24,154 +24,11 @@
#include "pe.h"
#include "runtime.h"
+#include "io_info_args_rt.h"
#include "psi_rt.h"
#include "psi_init.h"
-#include "io_harness.h"
#include "util_bits.h"
-/*****************************************************************************
- *
- * psi_rt_param_init
- *
- *****************************************************************************/
-
-int psi_rt_init_param(pe_t * pe, rt_t * rt, psi_t * obj) {
-
- int n;
- int nk;
- int nfreq;
-
- int valency[2] = {+1, -1}; /* Valencies (should be +/-!)*/
- double diffusivity[2] = {0.01, 0.01};
-
- double eunit = 1.0; /* Unit charge */
- double temperature, beta; /* Temperature (set by fluctuations) */
- double epsilon = 0.0; /* Reference permittivity */
- double lbjerrum; /* Bjerrum length; derived, not input */
- double tolerance; /* Numerical tolerance for SOR and Krylov subspace solver */
- int niteration; /* Max. number of iterations */
-
- int io_grid[3] = {1,1,1};
- int io_format_in = IO_FORMAT_DEFAULT;
- int io_format_out = IO_FORMAT_DEFAULT;
- char value[BUFSIZ] = "BINARY";
-
- int multisteps; /* Number of substeps in NPE */
- int skipsteps; /* Poisson equation solved every skipstep timesteps */
- double diffacc; /* Relative accuracy of diffusion in NPE */
-
- assert(pe);
- assert(rt);
-
- psi_nk(obj, &nk);
- assert(nk == 2); /* nk must be two for the time being */
-
- rt_int_parameter(rt, "electrokinetics_z0", valency);
- rt_int_parameter(rt, "electrokinetics_z1", valency + 1);
- rt_double_parameter(rt, "electrokinetics_d0", diffusivity);
- rt_double_parameter(rt, "electrokinetics_d1", diffusivity + 1);
-
- for (n = 0; n < nk; n++) {
- psi_valency_set(obj, n, valency[n]);
- psi_diffusivity_set(obj, n, diffusivity[n]);
- }
-
- rt_double_parameter(rt, "electrokinetics_eunit", &eunit);
- rt_double_parameter(rt, "electrokinetics_epsilon", &epsilon);
-
- psi_unit_charge_set(obj, eunit);
- psi_epsilon_set(obj, epsilon);
- psi_epsilon2_set(obj, epsilon); /* Default is no dielectric contrast */
-
- n = rt_double_parameter(rt, "temperature", &temperature);
-
- if (n == 0 || temperature <= 0.0) {
- pe_fatal(pe, "Please set a temperature to use electrokinetics\n");
- }
-
- beta = 1.0/temperature;
-
- psi_beta_set(obj, beta);
- psi_bjerrum_length(obj, &lbjerrum);
-
- pe_info(pe, "Electrokinetic species: %2d\n", nk);
- pe_info(pe, "Boltzmann factor: %14.7e (T = %14.7e)\n", beta, temperature);
- pe_info(pe, "Unit charge: %14.7e\n", eunit);
- pe_info(pe, "Permittivity: %14.7e\n", epsilon);
- pe_info(pe, "Bjerrum length: %14.7e\n", lbjerrum);
-
- for (n = 0; n < nk; n++) {
- pe_info(pe, "Valency species %d: %2d\n", n, valency[n]);
- pe_info(pe, "Diffusivity species %d: %14.7e\n", n, diffusivity[n]);
- }
-
- /* Multisteps and diffusive accuracy in NPE */
-
- n = rt_int_parameter(rt, "electrokinetics_multisteps", &multisteps);
- if (n == 1) psi_multisteps_set(obj, multisteps);
- n = rt_int_parameter(rt, "electrokinetics_skipsteps", &skipsteps);
- if (n == 1) psi_skipsteps_set(obj, skipsteps);
- n = rt_double_parameter(rt, "electrokinetics_diffacc", &diffacc);
- if (n == 1) psi_diffacc_set(obj, diffacc);
-
- psi_multisteps(obj, &multisteps);
- pe_info(pe, "Number of multisteps: %d\n", multisteps);
- pe_info(pe, "Number of skipsteps: %d\n", psi_skipsteps(obj));
- psi_diffacc(obj, &diffacc);
- pe_info(pe, "Diffusive accuracy in NPE: %14.7e\n", diffacc);
-
- /* Tolerances and Iterations */
-
- n = rt_double_parameter(rt, "electrokinetics_rel_tol", &tolerance);
- if (n == 1) psi_reltol_set(obj, tolerance);
- n = rt_double_parameter(rt, "electrokinetics_abs_tol", &tolerance);
- if (n == 1) psi_abstol_set(obj, tolerance);
- n = rt_int_parameter(rt, "electrokinetics_maxits", &niteration);
- if (n == 1) psi_maxits_set(obj, niteration);
-
- psi_reltol(obj, &tolerance);
- pe_info(pe, "Relative tolerance: %20.7e\n", tolerance);
- psi_abstol(obj, &tolerance);
- pe_info(pe, "Absolute tolerance: %20.7e\n", tolerance);
- psi_maxits(obj, &niteration);
- pe_info(pe, "Max. no. of iterations: %16d\n", niteration);
-
- /* External electric field */
-
- {
- double e0[3] = {0};
- rt_double_parameter_vector(rt, "electric_e0", e0);
- psi_e0_set(obj, e0);
- }
-
- /* Output */
-
- n = 0;
- n += rt_int_parameter(rt, "freq_statistics", &nfreq);
- n += rt_int_parameter(rt, "freq_psi_resid", &nfreq);
- if (n > 0) psi_nfreq_set(obj, nfreq);;
-
-
- /* I/O */
-
- rt_int_parameter_vector(rt, "default_io_grid", io_grid);
- rt_string_parameter(rt, "psi_format", value, BUFSIZ);
-
- if (strcmp(value, "ASCII") == 0) {
- io_format_in = IO_FORMAT_ASCII;
- io_format_out = IO_FORMAT_ASCII;
- }
-
- pe_info(pe, "I/O decomposition: %d %d %d\n",
- io_grid[0], io_grid[1],
- io_grid[2]);
- pe_info(pe, "I/O format: %s\n", value);
-
- psi_init_io_info(obj, io_grid, io_format_in, io_format_out);
-
- return 0;
-}
-
/*****************************************************************************
*
* psi_rt_init_rho
@@ -197,11 +54,12 @@ int psi_rt_init_rho(pe_t * pe, rt_t * rt, psi_t * obj, map_t * map) {
double ld2; /* Second Debye length for dielectric contrast */
double eps1, eps2; /* Dielectric permittivities */
- io_info_t * iohandler;
-
assert(pe);
assert(rt);
+ psi_options_t opts = {.e = obj->e, .beta = obj->beta,
+ .epsilon1 = obj->epsilon, .epsilon2 = obj->epsilon2};
+
/* Initial charge densities */
pe_info(pe, "\n");
@@ -211,19 +69,30 @@ int psi_rt_init_rho(pe_t * pe, rt_t * rt, psi_t * obj, map_t * map) {
rt_string_parameter(rt, "electrokinetics_init", value, BUFSIZ);
if (strcmp(value, "gouy_chapman") == 0) {
+ double ld_actual = 0.0;
pe_info(pe, "Initial conditions: %s\n", "Gouy Chapman");
n = rt_double_parameter(rt, "electrokinetics_init_rho_el", &rho_el);
if (n == 0) pe_fatal(pe, "... please set electrokinetics_init_rho_el\n");
- pe_info(pe, "Initial condition rho_el: %14.7e\n", rho_el);
- psi_debye_length(obj, rho_el, &ld);
- pe_info(pe, "Debye length: %14.7e\n", ld);
n = rt_double_parameter(rt, "electrokinetics_init_sigma", &sigma);
if (n == 0) pe_fatal(pe, "... please set electrokinetics_init_sigma\n");
- pe_info(pe, "Initial condition sigma: %14.7e\n", sigma);
+ psi_debye_length1(&opts, rho_el, &ld);
psi_init_gouy_chapman(obj, map, rho_el, sigma);
+
+ {
+ /* We want a real Debye length from the actual charge/countercharge
+ densities that have been initialisated in the fluid. */
+ int index = cs_index(obj->cs, 2, 1, 1);
+ double rho_actual = 0.0;
+ psi_ionic_strength(obj, index, &rho_actual);
+ psi_debye_length1(&opts, rho_actual, &ld_actual);
+ }
+ pe_info(pe, "Initial condition rho_el: %14.7e\n", rho_el);
+ pe_info(pe, "Debye length: %14.7e\n", ld);
+ pe_info(pe, "Debye length (actual): %14.7e\n", ld_actual);
+ pe_info(pe, "Initial condition sigma: %14.7e\n", sigma);
}
if (strcmp(value, "liquid_junction") == 0) {
@@ -232,13 +101,25 @@ int psi_rt_init_rho(pe_t * pe, rt_t * rt, psi_t * obj, map_t * map) {
n = rt_double_parameter(rt, "electrokinetics_init_rho_el", &rho_el);
if (n == 0) pe_fatal(pe, "... please set electrokinetics_init_rho_el\n");
pe_info(pe, "Initial condition rho_el: %14.7e\n", rho_el);
- psi_debye_length(obj, rho_el, &ld);
+ psi_debye_length1(&opts, rho_el, &ld);
pe_info(pe, "Debye length: %14.7e\n", ld);
n = rt_double_parameter(rt, "electrokinetics_init_delta_el", &delta_el);
if (n == 0) pe_fatal(pe, "... please set electrokinetics_init_delta_el\n");
pe_info(pe, "Initial condition delta_el: %14.7e\n", delta_el);
+ {
+ /* psi_p is the saturation potential */
+ double beta = obj->beta;
+ double e = obj->e;
+ double dplus = obj->diffusivity[0];
+ double dminus = obj->diffusivity[1];
+ double psi_p = dplus*dminus*delta_el/(beta*e*(dplus + dminus)*rho_el);
+ double tau_e = obj->epsilon/(beta*e*e*(dplus + dminus)*rho_el);
+ pe_info(pe, "Saturation potential: %14.7e\n", psi_p);
+ pe_info(pe, "Saturation timescale: %14.7e\n", tau_e);
+ }
+
psi_init_liquid_junction(obj, rho_el, delta_el);
}
@@ -248,7 +129,7 @@ int psi_rt_init_rho(pe_t * pe, rt_t * rt, psi_t * obj, map_t * map) {
n = rt_double_parameter(rt, "electrokinetics_init_rho_el", &rho_el);
if (n == 0) pe_fatal(pe, "... please set electrokinetics_init_rho_el\n");
pe_info(pe, "Initial condition rho_el: %14.7e\n", rho_el);
- psi_debye_length(obj, rho_el, &ld);
+ psi_debye_length1(&opts, rho_el, &ld);
pe_info(pe, "Debye length: %14.7e\n", ld);
/* Call permittivities and check for dielectric contrast */
@@ -258,7 +139,7 @@ int psi_rt_init_rho(pe_t * pe, rt_t * rt, psi_t * obj, map_t * map) {
/* Unless really the same number ... */
if (0 == util_double_same(eps1, eps2)) {
- psi_debye_length2(obj, rho_el, &ld2);
+ psi_debye_length2(&opts, rho_el, &ld2);
pe_info(pe, "Second Debye length: %14.7e\n", ld2);
}
@@ -266,12 +147,11 @@ int psi_rt_init_rho(pe_t * pe, rt_t * rt, psi_t * obj, map_t * map) {
}
if (strcmp(value, "from_file") == 0) {
-
- sprintf(filestub, "%s", "psi-00000000");
- pe_info(pe, "Initialisation requested from file %s.001-001\n", filestub);
- psi_io_info(obj, &iohandler);
- io_read_data(iohandler, filestub, obj);
-
+ io_event_t event1 = {0};
+ io_event_t event2 = {0};
+ pe_info(pe, "Initialisation requested from file(s)\n");
+ field_io_read(obj->psi, 0, &event1);
+ field_io_read(obj->rho, 0, &event2);
}
if (strcmp(value, "point_charges") == 0) {
@@ -281,7 +161,7 @@ int psi_rt_init_rho(pe_t * pe, rt_t * rt, psi_t * obj, map_t * map) {
n = rt_double_parameter(rt, "electrokinetics_init_rho_el", &rho_el);
if (n == 0) pe_fatal(pe, "... please set electrokinetics_init_rho_el\n");
pe_info(pe, "Initial condition rho_el: %14.7e\n", rho_el);
- psi_debye_length(obj, rho_el, &ld);
+ psi_debye_length1(&opts, rho_el, &ld);
pe_info(pe, "Debye length: %14.7e\n", ld);
/* Call permittivities and check for dielectric contrast */
@@ -290,7 +170,7 @@ int psi_rt_init_rho(pe_t * pe, rt_t * rt, psi_t * obj, map_t * map) {
/* Unless really the same number... */
if (0 == util_double_same(eps1, eps2)) {
- psi_debye_length2(obj, rho_el, &ld2);
+ psi_debye_length1(&opts, rho_el, &ld2);
pe_info(pe, "Second Debye length: %14.7e\n", ld2);
}
/* Set background charge densities */
@@ -305,3 +185,175 @@ int psi_rt_init_rho(pe_t * pe, rt_t * rt, psi_t * obj, map_t * map) {
return 0;
}
+
+/*****************************************************************************
+ *
+ * psi_options_rt
+ *
+ *****************************************************************************/
+
+int psi_options_rt(pe_t * pe, cs_t * cs, rt_t * rt, psi_options_t * popts) {
+
+ psi_options_t opts = psi_options_default(cs->param->nhalo);
+
+ assert(pe);
+ assert(cs);
+ assert(rt);
+
+ /* Physics */
+ /* The Boltzmann factor comes from the temperature */
+ /* Can use "epsilon" or specific keys "epsilon1" and "epsilon2" */
+
+ rt_double_parameter(rt, "electrokinetics_eunit", &opts.e);
+
+ {
+ double t = -1.0;
+ rt_double_parameter(rt, "temperature", &t);
+ if (t <= 0.0) pe_fatal(pe, "Please use a +ve temperature for electro\n");
+ opts.beta = 1.0/t;
+ }
+
+ rt_double_parameter(rt, "electrokinetics_epsilon", &opts.epsilon1);
+ rt_double_parameter(rt, "electrokinetics_epsilon", &opts.epsilon2);
+ rt_double_parameter(rt, "electrokinetics_epsilon1", &opts.epsilon1);
+ rt_double_parameter(rt, "electrokinetics_epsilon2", &opts.epsilon2);
+
+ rt_double_parameter_vector(rt, "electric_e0", opts.e0);
+
+ rt_double_parameter(rt, "electrokinetics_d0", &opts.diffusivity[0]);
+ rt_double_parameter(rt, "electrokinetics_d1", &opts.diffusivity[1]);
+
+ rt_int_parameter(rt, "electrokinetics_z0", &opts.valency[0]);
+ rt_int_parameter(rt, "electrokinetics_z1", &opts.valency[1]);
+
+ /* Poisson solver */
+ /* There are two possible sources of nfreq */
+
+ {
+ /* Solver type */
+ char str[BUFSIZ] = {0};
+ strcpy(str, psi_poisson_solver_to_string(psi_poisson_solver_default()));
+ rt_string_parameter(rt, "electrokinetics_solver_type", str, BUFSIZ);
+ opts.solver.psolver = psi_poisson_solver_from_string(str);
+ switch (opts.solver.psolver) {
+ case (PSI_POISSON_SOLVER_INVALID):
+ /* Not recognised */
+ pe_info(pe, "electrokinetics_solver_type: %s\n", str);
+ pe_info(pe, "is not recongnised\n");
+ pe_fatal(pe, "Please check and try again!\n");
+ break;
+ case (PSI_POISSON_SOLVER_PETSC):
+ /* Check Petsc is actually available */
+ {
+ int isAvailable = 0;
+ PetscInitialised(&isAvailable);
+ if (isAvailable == 0) {
+ pe_info(pe, "electrokinetics_solver_type: petsc\n");
+ pe_info(pe, "Petsc has not been compiled in this build\n");
+ pe_info(pe, "Please use the `sor` solver.\n");
+ pe_fatal(pe, "Please check the input and try again!\n");
+ }
+ }
+ break;
+ default:
+ ; /* ok */
+ }
+ }
+
+ /* Stencil must be available. */
+ if (rt_int_parameter(rt, "electrokinetics_solver_stencil",
+ &opts.solver.nstencil)) {
+ stencil_t * s = NULL;
+ int ifail = stencil_create(opts.solver.nstencil, &s);
+ if (ifail != 0) {
+ pe_info(pe, "electroknietics_solver_stencil: %d\n", opts.solver.nstencil);
+ pe_fatal(pe, "Not supported. Please check and try again!\n");
+ }
+ if (s) stencil_free(&s);
+ }
+
+ rt_int_parameter(rt, "electrokinetics_maxits", &opts.solver.maxits);
+ rt_int_parameter(rt, "freq_statistics", &opts.solver.nfreq);
+ rt_int_parameter(rt, "freq_psi_resid", &opts.solver.nfreq);
+
+ /* Accept either form (older "rel_tol" "abs_tol" to be removed) */
+ rt_double_parameter(rt, "electrokinetics_rel_tol", &opts.solver.reltol);
+ rt_double_parameter(rt, "electrokinetics_abs_tol", &opts.solver.abstol);
+ rt_double_parameter(rt, "electrokinetics_solver_reltol", &opts.solver.reltol);
+ rt_double_parameter(rt, "electrokinetics_solver_abstol", &opts.solver.abstol);
+
+ /* NPE time splitting and criteria */
+
+ rt_int_parameter(rt, "electrokinetics_multisteps", &opts.nsmallstep);
+ rt_double_parameter(rt, "electrokinetics_diffacc", &opts.diffacc);
+
+ /* Field quantites */
+ /* At the moment there are two fields (potential and charge densities)
+ * but only one input key "psi" involved */
+
+ {
+ opts.psi = field_options_ndata_nhalo(1, cs->param->nhalo);
+ opts.rho = field_options_ndata_nhalo(opts.nk, cs->param->nhalo);
+
+ io_info_args_rt(rt, RT_FATAL, "psi", IO_INFO_READ_WRITE, &opts.psi.iodata);
+ io_info_args_rt(rt, RT_FATAL, "psi", IO_INFO_READ_WRITE, &opts.rho.iodata);
+
+ if (opts.psi.iodata.input.mode != IO_MODE_MPIIO) {
+ pe_fatal(pe, "Electrokinetics i/o must use psi_io_mode mpiio\n");
+ }
+ }
+
+ *popts = opts;
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * psi_info
+ *
+ * Could be moved elsewhere.
+ *
+ *****************************************************************************/
+
+int psi_info(pe_t * pe, const psi_t * psi) {
+
+ double lbjerrum = 0.0;
+
+ assert(pe);
+ assert(psi);
+
+ /* Refactoring has casued a slight awkwardnesss here... */
+ {
+ psi_options_t opts = {.e = psi->e, .beta = psi->beta,
+ .epsilon1 = psi->epsilon};
+ psi_bjerrum_length1(&opts, &lbjerrum);
+ }
+
+ /* Information */
+
+ pe_info(pe, "Electrokinetic species: %2d\n", psi->nk);
+ pe_info(pe, "Boltzmann factor: %14.7e (T = %14.7e)\n",
+ psi->beta, 1.0/psi->beta);
+ pe_info(pe, "Unit charge: %14.7e\n", psi->e);
+ pe_info(pe, "Permittivity: %14.7e\n", psi->epsilon);
+ pe_info(pe, "Bjerrum length: %14.7e\n", lbjerrum);
+
+ for (int n = 0; n < psi->nk; n++) {
+ pe_info(pe, "Valency species %d: %2d\n", n, psi->valency[n]);
+ pe_info(pe, "Diffusivity species %d: %14.7e\n", n, psi->diffusivity[n]);
+ }
+
+ /* Add full information ... */
+ pe_info(pe, "Solver type: %20s\n",
+ psi_poisson_solver_to_string(psi->solver.psolver));
+ pe_info(pe, "Solver stencil points: %16d\n", psi->solver.nstencil);
+ pe_info(pe, "Relative tolerance: %20.7e\n", psi->solver.reltol);
+ pe_info(pe, "Absolute tolerance: %20.7e\n", psi->solver.abstol);
+ pe_info(pe, "Max. no. of iterations: %16d\n", psi->solver.maxits);
+
+ pe_info(pe, "Number of multisteps: %d\n", psi->multisteps);
+ pe_info(pe, "Diffusive accuracy in NPE: %14.7e\n", psi->diffacc);
+
+ return 0;
+}
diff --git a/src/psi_rt.h b/src/psi_rt.h
index 2fbfc55c3..46f6e0efe 100644
--- a/src/psi_rt.h
+++ b/src/psi_rt.h
@@ -2,25 +2,26 @@
*
* psi_rt.h
*
- * $Id$
- *
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
+ * (c) 2012-2023 The University of Edinburgh
+ *
* Kevin Stratford (kevin@epcc.ed.ac.uk)
- * (c) 2012-2016 The University of Edinburgh
*
*****************************************************************************/
-#ifndef PSI_RT_H
-#define PSI_RT_H
+#ifndef LUDWIG_PSI_RT_H
+#define LUDWIG_PSI_RT_H
#include "pe.h"
#include "runtime.h"
#include "psi.h"
#include "map.h"
-int psi_rt_init_param(pe_t * pe, rt_t * rt, psi_t * psi);
int psi_rt_init_rho(pe_t * pe, rt_t * rt, psi_t * psi, map_t * map);
+int psi_options_rt(pe_t * pe, cs_t * cs, rt_t * rt, psi_options_t * opts);
+int psi_info(pe_t * pe, const psi_t * psi);
+
#endif
diff --git a/src/psi_s.h b/src/psi_s.h
deleted file mode 100644
index e073e9f17..000000000
--- a/src/psi_s.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*****************************************************************************
- *
- * psi_s.h
- *
- * Edinburgh Soft Matter and Statistical Physics Group and
- * Edinburgh Parallel Computing Centre
- *
- * (c) 2012-2016 The University of Edinburgh
- *
- * Contributinf authors:
- * Kevin Stratford (kevin@epcc.ed.ac.uk)
- *
- *****************************************************************************/
-
-#ifndef LUDWIG_PSI_S_H
-#define LUDWIG_PSI_S_H
-
-#include
-#include "io_harness.h"
-#include "psi.h"
-#include "memory.h"
-
-/*
- * We store here the unit charge, the electric permittivity, and the
- * temperature, all in lattice units. This allows us to work out the
- * Bjerrum length,
- * l_B = e^2 / (4 \pi epsilon_0 epsilon_r kT)
- * which is the scale at which the interaction energy between two
- * unit charges is equal to kT. The aim is that the Bjerrum length
- * should be < 1 (e.g. 0.7) in lattice units.
- *
- * For water at room temperature, the Bjerrum length is about
- * 7 Angstrom.
- *
- */
-
-struct psi_s {
- pe_t * pe; /* Parallel environment */
- cs_t * cs; /* Coordinate system */
-
- int nk; /* Number of species */
- int nsites; /* Number sites storage */
- double * psi; /* Electric potential */
- double * rho; /* Charge densities */
- double * diffusivity; /* Diffusivity for each species */
- int * valency; /* Valency for each species */
- double e; /* unit charge */
- double epsilon; /* first and reference permittivity */
- double epsilon2; /* second permittivity */
- double beta; /* Boltzmann factor (1 / k_B T) */
- double reltol; /* Relative tolerance for Poisson solver */
- double abstol; /* Absolute tolerance for Poisson solver */
- int method; /* Force computation method */
- int maxits; /* Maximum number of iterations */
- int multisteps; /* Number of substeps in charge dynamics */
- int skipsteps; /* Poisson equation solved every skipsteps timesteps */
- int nfreq_io; /* Field output */
- int nfreq; /* Residual statisics output */
- double diffacc; /* Number of substeps in charge dynamics */
- double e0[3]; /* External electric field */
- MPI_Datatype psihalo[3]; /* psi field halo */
- MPI_Datatype rhohalo[3]; /* charge densities halo */
- io_info_t * info; /* I/O informtation */
-};
-
-int psi_halo(int nf, double * f, MPI_Datatype halo[3]);
-
-#endif
diff --git a/src/psi_solver.c b/src/psi_solver.c
new file mode 100644
index 000000000..7eb40b014
--- /dev/null
+++ b/src/psi_solver.c
@@ -0,0 +1,104 @@
+/*****************************************************************************
+ *
+ * psi_solver.c
+ *
+ * Factory function for the solver object.
+ *
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#include
+
+/* Available implementations ... */
+#include "psi_petsc.h"
+#include "psi_sor.h"
+
+/*****************************************************************************
+ *
+ * psi_solver_create
+ *
+ * Returns pointer to the abstract solver type.
+ *
+ * We must allow that PETSc is not available, so the return value
+ * must be checked by the caller.
+ *
+ *****************************************************************************/
+
+int psi_solver_create(psi_t * psi, psi_solver_t ** solver) {
+
+ int ifail = 0;
+
+ assert(solver && *solver == NULL);
+
+ switch (psi->solver.psolver) {
+
+ case (PSI_POISSON_SOLVER_PETSC):
+ {
+ psi_solver_petsc_t * petsc = NULL;
+ ifail = psi_solver_petsc_create(psi, &petsc);
+ if (ifail == 0) *solver = (psi_solver_t *) petsc;
+ }
+ break;
+
+ case (PSI_POISSON_SOLVER_SOR):
+ {
+ psi_solver_sor_t * sor = NULL;
+ ifail = psi_solver_sor_create(psi, &sor);
+ if (ifail == 0) *solver = (psi_solver_t *) sor;
+ }
+ break;
+
+ default:
+ ifail = -1;
+ }
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * psi_solver_var_epsilon_create
+ *
+ * The equivalent for the version allowing electric contrast.
+ * The same comments apply.
+ *
+ *****************************************************************************/
+
+int psi_solver_var_epsilon_create(psi_t * psi, var_epsilon_t user,
+ psi_solver_t ** solver) {
+
+ int ifail = 0;
+
+ assert(solver && *solver == NULL);
+
+ switch (psi->solver.psolver) {
+
+ case (PSI_POISSON_SOLVER_PETSC):
+ {
+ psi_solver_petsc_t * petsc = NULL;
+ ifail = psi_solver_petsc_var_epsilon_create(psi, user, &petsc);
+ if (ifail == 0) *solver = (psi_solver_t *) petsc;
+ }
+ break;
+
+ case (PSI_POISSON_SOLVER_SOR):
+ {
+ psi_solver_sor_t * sor = NULL;
+ ifail = psi_solver_sor_var_epsilon_create(psi, user, &sor);
+ *solver = (psi_solver_t *) sor;
+ }
+ break;
+
+ default:
+ ifail = -1;
+ }
+
+ return ifail;
+}
diff --git a/src/psi_solver.h b/src/psi_solver.h
new file mode 100644
index 000000000..0099dd3e4
--- /dev/null
+++ b/src/psi_solver.h
@@ -0,0 +1,57 @@
+/*****************************************************************************
+ *
+ * psi_solver.h
+ *
+ * Abstract Poisson solver interface.
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#ifndef LUDWIG_PSI_SOLVER_H
+#define LUDWIG_PSI_SOLVER_H
+
+#include "free_energy.h"
+#include "psi.h"
+
+typedef struct psi_solver_vt_s psi_solver_vt_t;
+typedef struct psi_solver_s psi_solver_t;
+
+typedef int (* psi_solver_free_ft) (psi_solver_t ** psolver);
+typedef int (* psi_solver_solve_ft) (psi_solver_t * solver, int ntimestep);
+
+struct psi_solver_vt_s {
+ psi_solver_free_ft free; /* Destructor */
+ psi_solver_solve_ft solve; /* Driver of solve */
+};
+
+struct psi_solver_s {
+ const psi_solver_vt_t * impl; /* Implementation vtable */
+};
+
+/* Factory methods */
+
+int psi_solver_create(psi_t * psi, psi_solver_t ** solver);
+
+/* For dielectric contrast, we need some abstract component which
+ * involves the free energy. However, as only electrosymmetric is
+ * relevant at the moment, I haven't added a further method to the
+ * abstract free energy interface. So we have a slightly add hoc
+ * addition here... */
+
+typedef struct var_epsilon_s var_epsilon_t;
+typedef int (* var_epsilon_ft)(void * fe, int index, double * epsilon);
+
+struct var_epsilon_s {
+ fe_t * fe;
+ var_epsilon_ft epsilon;
+};
+
+int psi_solver_var_epsilon_create(psi_t * psi, var_epsilon_t epsilon,
+ psi_solver_t ** solver);
+#endif
diff --git a/src/psi_solver_options.c b/src/psi_solver_options.c
new file mode 100644
index 000000000..669a01d67
--- /dev/null
+++ b/src/psi_solver_options.c
@@ -0,0 +1,204 @@
+/*****************************************************************************
+ *
+ * psi_solver_options.c
+ *
+ * Container for Poission solver options.
+ *
+ * nb. The default solver type is Petsc if Petsc is available,
+ * otherwise fall back to the internal sor implementation.
+ *
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#include
+#include
+#include
+
+#include "psi_solver_options.h"
+#include "util.h"
+
+/*****************************************************************************
+ *
+ * psi_poisson_solver_default
+ *
+ *****************************************************************************/
+
+psi_poisson_solver_enum_t psi_poisson_solver_default(void) {
+
+ int havePetsc = 0;
+ psi_poisson_solver_enum_t psolver = PSI_POISSON_SOLVER_SOR;
+
+ PetscInitialised(&havePetsc);
+ if (havePetsc) psolver = PSI_POISSON_SOLVER_PETSC;
+
+ return psolver;
+}
+
+/*****************************************************************************
+ *
+ * psi_poisson_solver_to_string
+ *
+ *****************************************************************************/
+
+const char * psi_poisson_solver_to_string(psi_poisson_solver_enum_t mytype) {
+
+ const char * str = "invalid";
+
+ switch (mytype) {
+ case PSI_POISSON_SOLVER_SOR:
+ str = "sor";
+ break;
+ case PSI_POISSON_SOLVER_PETSC:
+ str = "petsc";
+ break;
+ case PSI_POISSON_SOLVER_NONE:
+ str = "none";
+ break;
+ default:
+ str = "invalid";
+ }
+
+ return str;
+}
+
+/*****************************************************************************
+ *
+ * psi_poisson_solver_from_string
+ *
+ *****************************************************************************/
+
+psi_poisson_solver_enum_t psi_poisson_solver_from_string(const char * str) {
+
+ psi_poisson_solver_enum_t mytype = PSI_POISSON_SOLVER_INVALID;
+ char value[BUFSIZ] = {0};
+
+ strncpy(value, str, BUFSIZ-1);
+ util_str_tolower(value, strlen(value));
+
+ if (strcmp(value, "sor") == 0) mytype = PSI_POISSON_SOLVER_SOR;
+ if (strcmp(value, "petsc") == 0) mytype = PSI_POISSON_SOLVER_PETSC;
+ if (strcmp(value, "none") == 0) mytype = PSI_POISSON_SOLVER_NONE;
+
+ return mytype;
+}
+
+/*****************************************************************************
+ *
+ * psi_solver_options_default
+ *
+ *****************************************************************************/
+
+psi_solver_options_t psi_solver_options_default(void) {
+
+ psi_poisson_solver_enum_t psolver = psi_poisson_solver_default();
+ psi_solver_options_t pso = psi_solver_options_type(psolver);
+
+ return pso;
+}
+
+/*****************************************************************************
+ *
+ * psi_solver_options_type
+ *
+ *****************************************************************************/
+
+psi_solver_options_t psi_solver_options_type(psi_poisson_solver_enum_t ptype) {
+
+ psi_solver_options_t pso = {
+ .psolver = ptype,
+ .maxits = 10000,
+ .verbose = 0,
+ .nfreq = INT_MAX,
+ .nstencil = 7,
+ .reltol = 1.0e-08,
+ .abstol = 1.0e-15,
+ };
+
+ return pso;
+}
+
+/*****************************************************************************
+ *
+ * psi_solver_options_to_json
+ *
+ * Caller to release new json object when finished.
+ *
+ *****************************************************************************/
+
+int psi_solver_options_to_json(const psi_solver_options_t * pso,
+ cJSON ** json) {
+ int ifail = 0;
+
+ if (pso == NULL || json == NULL || *json != NULL) {
+ ifail = -1;
+ }
+ else {
+ cJSON * obj = cJSON_CreateObject();
+
+ cJSON_AddStringToObject(obj, "Solver type",
+ psi_poisson_solver_to_string(pso->psolver));
+ cJSON_AddNumberToObject(obj, "Maximum iterations", pso->maxits);
+ cJSON_AddNumberToObject(obj, "Level of verbosity", pso->verbose);
+ cJSON_AddNumberToObject(obj, "Frequency of output", pso->nfreq);
+ cJSON_AddNumberToObject(obj, "Stencil points", pso->nstencil);
+
+ cJSON_AddNumberToObject(obj, "Relative tolerance", pso->reltol);
+ cJSON_AddNumberToObject(obj, "Absolute tolerance", pso->abstol);
+
+ *json = obj;
+ }
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * psi_solver_options_from_json
+ *
+ *****************************************************************************/
+
+int psi_solver_options_from_json(const cJSON * json,
+ psi_solver_options_t * pso) {
+
+ int ifail = 0;
+
+ if (json == NULL || pso == NULL) {
+ ifail = -1;
+ }
+ else {
+ cJSON * psolver = cJSON_GetObjectItem(json, "Solver type");
+ cJSON * maxits = cJSON_GetObjectItem(json, "Maximum iterations");
+ cJSON * verbose = cJSON_GetObjectItem(json, "Level of verbosity");
+ cJSON * nfreq = cJSON_GetObjectItem(json, "Frequency of output");
+ cJSON * nsten = cJSON_GetObjectItem(json, "Stencil points");
+ cJSON * reltol = cJSON_GetObjectItem(json, "Relative tolerance");
+ cJSON * abstol = cJSON_GetObjectItem(json, "Absolute tolerance");
+
+ /* There must be at least a solver type ... */
+
+ if (psolver == NULL) {
+ pso->psolver = PSI_POISSON_SOLVER_INVALID;
+ ifail = -1;
+ }
+ else {
+ char * str = cJSON_GetStringValue(psolver);
+ pso->psolver = psi_poisson_solver_from_string(str);
+
+ if (maxits) pso->maxits = cJSON_GetNumberValue(maxits);
+ if (verbose) pso->verbose = cJSON_GetNumberValue(verbose);
+ if (nfreq) pso->nfreq = cJSON_GetNumberValue(nfreq);
+ if (nsten) pso->nstencil = cJSON_GetNumberValue(nsten);
+ if (reltol) pso->reltol = cJSON_GetNumberValue(reltol);
+ if (abstol) pso->abstol = cJSON_GetNumberValue(abstol);
+ }
+ }
+
+ return ifail;
+}
diff --git a/src/psi_solver_options.h b/src/psi_solver_options.h
new file mode 100644
index 000000000..4096d6ac8
--- /dev/null
+++ b/src/psi_solver_options.h
@@ -0,0 +1,58 @@
+/*****************************************************************************
+ *
+ * psi_solver_options.h
+ *
+ * Poisson solver options.
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#ifndef LUDWIG_PSI_SOLVER_OPTIONS_H
+#define LUDWIG_PSI_SOLVER_OPTIONS_H
+
+#include "util_json.h"
+#include "util_petsc.h"
+
+/* Poisson solver method */
+
+typedef enum psi_poisson_solver_enum_s {
+ PSI_POISSON_SOLVER_INVALID = 0,
+ PSI_POISSON_SOLVER_SOR = 1,
+ PSI_POISSON_SOLVER_PETSC = 2,
+ PSI_POISSON_SOLVER_NONE = 3
+} psi_poisson_solver_enum_t;
+
+/* This is intended to be general; some components might not be relevant
+ in all specific cases. */
+
+typedef struct psi_solver_options_s psi_solver_options_t;
+
+struct psi_solver_options_s {
+
+ psi_poisson_solver_enum_t psolver; /* Poisson solver id */
+ int maxits; /* Maximum iterations in solver */
+ int verbose; /* Level of verbosity */
+ int nfreq; /* Frequency of report */
+ int nstencil; /* Stencil option */
+
+ double reltol; /* Relative tolerance */
+ double abstol; /* Absolute tolerance */
+};
+
+const char * psi_poisson_solver_to_string(psi_poisson_solver_enum_t mytype);
+psi_poisson_solver_enum_t psi_poisson_solver_from_string(const char * str);
+psi_poisson_solver_enum_t psi_poisson_solver_default(void);
+
+psi_solver_options_t psi_solver_options_default(void);
+psi_solver_options_t psi_solver_options_type(psi_poisson_solver_enum_t mytype);
+
+int psi_solver_options_to_json(const psi_solver_options_t * opts, cJSON ** js);
+int psi_solver_options_from_json(const cJSON * json, psi_solver_options_t * p);
+
+#endif
diff --git a/src/psi_sor.c b/src/psi_sor.c
index 7ffb45398..74aa2f7c2 100644
--- a/src/psi_sor.c
+++ b/src/psi_sor.c
@@ -16,7 +16,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2013-2022 The University of Edinburgh
+ * (c) 2013-2023 The University of Edinburgh
*
* Contributing Authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -31,35 +31,74 @@
#include "pe.h"
#include "coords.h"
-#include "psi_s.h"
#include "psi_sor.h"
#include "util.h"
+/* Function table */
+
+static psi_solver_vt_t vt_ = {
+ (psi_solver_free_ft) psi_solver_sor_free,
+ (psi_solver_solve_ft) psi_solver_sor_solve
+};
+
+static psi_solver_vt_t vart_ = {
+ (psi_solver_free_ft) psi_solver_sor_free,
+ (psi_solver_solve_ft) psi_solver_sor_var_epsilon_solve
+};
+
/*****************************************************************************
*
- * psi_sor_solve
+ * psi_solver_sor_create
+ *
+ *****************************************************************************/
+
+int psi_solver_sor_create(psi_t * psi, psi_solver_sor_t ** sor) {
+
+ int ifail = 0;
+ psi_solver_sor_t * solver = NULL;
+
+ assert(psi);
+ assert(sor);
+
+ solver = (psi_solver_sor_t *) calloc(1, sizeof(psi_solver_sor_t));
+ if (solver == NULL) {
+ ifail = -1;
+ }
+ else {
+ /* Set the function table ... */
+ solver->super.impl = &vt_;
+ solver->psi = psi;
+ }
+
+ *sor = solver;
+
+ return ifail;
+}
+
+/*****************************************************************************
*
- * If the f_vare_t argument is NULL, the uniform epsilon solver is used.
- * If the argument is present, the non-uniform solver is used.
+ * psi_solver_sor_free
*
*****************************************************************************/
-int psi_sor_solve(psi_t * obj, fe_t * fe, f_vare_t fepsilon, int its) {
+int psi_solver_sor_free(psi_solver_sor_t ** sor) {
- assert(obj);
+ assert(sor);
+ assert(*sor);
- if (fepsilon == NULL) psi_sor_poisson(obj, its);
- if (fepsilon != NULL) psi_sor_vare_poisson(obj, (fe_es_t *) fe, fepsilon, its);
+ free(*sor);
+ *sor = NULL;
return 0;
}
/*****************************************************************************
*
- * psi_sor_poisson
+ * psi_solver_sor_solve
*
- * Uniform permittivity. The differencing is a seven
- * point stencil for \nabla^2 \psi. So
+ * Solve Poisson equation with uniform permittivity.
+ *
+ * The differencing is a seven point stencil for \nabla^2 \psi. So
*
* epsilon [ psi(i+1,j,k) - 2 psi(i,j,k) + psi(i-1,j,k)
* + psi(i,j+1,k) - 2 psi(i,j,k) + psi(i,j-1,k)
@@ -90,16 +129,12 @@ int psi_sor_solve(psi_t * obj, fe_t * fe, f_vare_t fepsilon, int its) {
*
*****************************************************************************/
-int psi_sor_poisson(psi_t * obj, int its) {
+int psi_solver_sor_solve(psi_solver_sor_t * sor, int its) {
int niteration = 1000; /* Maximum number of iterations */
const int ncheck = 5; /* Check global residual every n iterations */
- int ic, jc, kc, index;
int nhalo;
- int n; /* Relaxation iterations */
- int pass; /* Red/black iteration */
- int kst; /* Start kc index for red/black iteration */
int nlocal[3];
int nsites;
int xs, ys, zs; /* Memory strides */
@@ -111,19 +146,20 @@ int psi_sor_poisson(psi_t * obj, int its) {
double dpsi;
double omega; /* Over-relaxation parameter 1 < omega < 2 */
double radius; /* Spectral radius of Jacobi iteration */
- double tol_rel; /* Relative tolerance */
- double tol_abs; /* Absolute tolerance */
double eunit, beta;
double ltot[3];
MPI_Comm comm; /* Cartesian communicator */
- cs_ltot(obj->cs, ltot);
- cs_nhalo(obj->cs, &nhalo);
- cs_nsites(obj->cs, &nsites);
- cs_nlocal(obj->cs, nlocal);
- cs_cart_comm(obj->cs, &comm);
- cs_strides(obj->cs, &xs, &ys, &zs);
+ psi_t * psi = sor->psi;
+ double * __restrict__ psidata = psi->psi->data;
+
+ cs_ltot(psi->cs, ltot);
+ cs_nhalo(psi->cs, &nhalo);
+ cs_nsites(psi->cs, &nsites);
+ cs_nlocal(psi->cs, nlocal);
+ cs_cart_comm(psi->cs, &comm);
+ cs_strides(psi->cs, &xs, &ys, &zs);
assert(nhalo >= 1);
@@ -138,78 +174,71 @@ int psi_sor_poisson(psi_t * obj, int its) {
radius = 1.0 - 0.5*pow(4.0*atan(1.0)/dmax(ltot[X],ltot[Z]), 2);
- psi_epsilon(obj, &epsilon);
- psi_reltol(obj, &tol_rel);
- psi_abstol(obj, &tol_abs);
- psi_maxits(obj, &niteration);
+ psi_epsilon(psi, &epsilon);
+ psi_maxits(psi, &niteration);
- psi_beta(obj, &beta);
- psi_unit_charge(obj, &eunit);
+ psi_beta(psi, &beta);
+ psi_unit_charge(psi, &eunit);
rnorm_local[0] = 0.0;
- for (ic = 1; ic <= nlocal[X]; ic++) {
- for (jc = 1; jc <= nlocal[Y]; jc++) {
- for (kc = 1; kc <= nlocal[Z]; kc++) {
+ for (int ic = 1; ic <= nlocal[X]; ic++) {
+ for (int jc = 1; jc <= nlocal[Y]; jc++) {
+ for (int kc = 1; kc <= nlocal[Z]; kc++) {
- index = cs_index(obj->cs, ic, jc, kc);
+ int index = cs_index(psi->cs, ic, jc, kc);
- psi_rho_elec(obj, index, &rho_elec);
-
- /* 6-point stencil of Laplacian */
-
- dpsi
- = obj->psi[addr_rank0(nsites, index + xs)]
- + obj->psi[addr_rank0(nsites, index - xs)]
- + obj->psi[addr_rank0(nsites, index + ys)]
- + obj->psi[addr_rank0(nsites, index - ys)]
- + obj->psi[addr_rank0(nsites, index + zs)]
- + obj->psi[addr_rank0(nsites, index - zs)]
- - 6.0*obj->psi[addr_rank0(nsites, index)];
+ psi_rho_elec(psi, index, &rho_elec);
/* Non-dimensional potential in Poisson eqn requires e/kT */
- rnorm_local[0] += fabs(epsilon*dpsi + eunit*beta*rho_elec);
+ /* This is just the L2 norm of the right hand side. */
+
+ residual = eunit*beta*rho_elec;
+ rnorm_local[0] += residual*residual;
}
}
}
+ rnorm_local[0] = sqrt(rnorm_local[0]);
+
/* Iterate to solution */
omega = 1.0;
- for (n = 0; n < niteration; n++) {
+ for (int n = 0; n < niteration; n++) {
/* Compute current normal of the residual */
rnorm_local[1] = 0.0;
- for (pass = 0; pass < 2; pass++) {
+ for (int pass = 0; pass < 2; pass++) {
- for (ic = 1; ic <= nlocal[X]; ic++) {
- for (jc = 1; jc <= nlocal[Y]; jc++) {
- kst = 1 + (ic + jc + pass) % 2;
- for (kc = kst; kc <= nlocal[Z]; kc += 2) {
+ for (int ic = 1; ic <= nlocal[X]; ic++) {
+ for (int jc = 1; jc <= nlocal[Y]; jc++) {
+ int kst = 1 + (ic + jc + pass) % 2;
+ for (int kc = kst; kc <= nlocal[Z]; kc += 2) {
- index = cs_index(obj->cs, ic, jc, kc);
+ int index = cs_index(psi->cs, ic, jc, kc);
- psi_rho_elec(obj, index, &rho_elec);
+ psi_rho_elec(psi, index, &rho_elec);
/* 6-point stencil of Laplacian */
dpsi
- = obj->psi[addr_rank0(nsites, index + xs)]
- + obj->psi[addr_rank0(nsites, index - xs)]
- + obj->psi[addr_rank0(nsites, index + ys)]
- + obj->psi[addr_rank0(nsites, index - ys)]
- + obj->psi[addr_rank0(nsites, index + zs)]
- + obj->psi[addr_rank0(nsites, index - zs)]
- - 6.0*obj->psi[addr_rank0(nsites, index)];
+ = psidata[addr_rank0(nsites, index + xs)]
+ + psidata[addr_rank0(nsites, index - xs)]
+ + psidata[addr_rank0(nsites, index + ys)]
+ + psidata[addr_rank0(nsites, index - ys)]
+ + psidata[addr_rank0(nsites, index + zs)]
+ + psidata[addr_rank0(nsites, index - zs)]
+ - 6.0*psidata[addr_rank0(nsites, index)];
/* Non-dimensional potential in Poisson eqn requires e/kT */
+
residual = epsilon*dpsi + eunit*beta*rho_elec;
- obj->psi[addr_rank0(nsites, index)]
+ psidata[addr_rank0(nsites, index)]
-= omega*residual / (-6.0*epsilon);
- rnorm_local[1] += fabs(residual);
+ rnorm_local[1] += residual*residual;
}
}
}
@@ -222,46 +251,48 @@ int psi_sor_poisson(psi_t * obj, int its) {
else {
omega = 1.0 / (1.0 - 0.25*radius*radius*omega);
}
- assert(1.0 < omega);
- assert(omega < 2.0);
+ assert(1.0 < omega && omega < 2.0);
- psi_halo_psi(obj);
- psi_halo_psijump(obj);
+ psi_halo_psi(psi);
+ psi_halo_psijump(psi);
}
if ((n % ncheck) == 0) {
+
/* Compare residual and exit if small enough */
+ pe_t * pe = psi->pe;
+
+ rnorm_local[1] = sqrt(rnorm_local[1]);
MPI_Allreduce(rnorm_local, rnorm, 2, MPI_DOUBLE, MPI_SUM, comm);
- if (rnorm[1] < tol_abs) {
+ if (rnorm[1] < psi->solver.abstol) {
- if (its % obj->nfreq == 0) {
- pe_info(obj->pe, "\n");
- pe_info(obj->pe, "SOR solver converged to absolute tolerance\n");
- pe_info(obj->pe, "SOR residual per site %14.7e at %d iterations\n",
- rnorm[1]/(ltot[X]*ltot[Y]*ltot[Z]), n);
+ if (its % psi->solver.nfreq == 0) {
+ pe_info(pe, "\n");
+ pe_info(pe, "SOR solver converged to absolute tolerance\n");
+ pe_info(pe, "SOR residual %14.7e at %d iterations\n", rnorm[1], n);
}
break;
}
- if (rnorm[1] < tol_abs || rnorm[1] < tol_rel*rnorm[0]) {
+ if (rnorm[1] < psi->solver.reltol*rnorm[0]) {
- if (its % obj->nfreq == 0) {
- pe_info(obj->pe, "\n");
- pe_info(obj->pe, "SOR solver converged to relative tolerance\n");
- pe_info(obj->pe, "SOR residual per site %14.7e at %d iterations\n",
- rnorm[1]/(ltot[X]*ltot[Y]*ltot[Z]), n);
+ if (its % psi->solver.nfreq == 0) {
+ pe_info(pe, "\n");
+ pe_info(pe, "SOR solver converged to relative tolerance\n");
+ pe_info(pe, "SOR residual %14.7e at %d iterations\n", rnorm[1], n);
}
break;
}
}
if (n == niteration-1) {
- pe_info(obj->pe, "\n");
- pe_info(obj->pe, "SOR solver exceeded %d iterations\n", n+1);
- pe_info(obj->pe, "SOR residual %le (initial) %le (final)\n\n", rnorm[0], rnorm[1]);
+ pe_info(psi->pe, "\n");
+ pe_info(psi->pe, "SOR solver exceeded %d iterations\n", n+1);
+ pe_info(psi->pe, "SOR residual %le (initial) %le (final)\n\n",
+ rnorm[0], rnorm[1]);
}
}
@@ -270,7 +301,38 @@ int psi_sor_poisson(psi_t * obj, int its) {
/*****************************************************************************
*
- * psi_sor_vare_poisson
+ * psi_solver_sor_var_epsilon_create
+ *
+ *****************************************************************************/
+
+int psi_solver_sor_var_epsilon_create(psi_t * psi, var_epsilon_t user,
+ psi_solver_sor_t ** sor) {
+ int ifail = 0;
+ psi_solver_sor_t * solver = NULL;
+
+ assert(psi);
+ assert(sor);
+
+ solver = (psi_solver_sor_t *) calloc(1, sizeof(psi_solver_sor_t));
+ if (solver == NULL) {
+ ifail = -1;
+ }
+ else {
+ /* Set the function table etc... */
+ solver->super.impl = &vart_;
+ solver->psi = psi;
+ solver->fe = user.fe;
+ solver->epsilon = user.epsilon;
+ }
+
+ *sor = solver;
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * psi_solver_sor_var_epsilon_solve
*
* This is essentially a copy of the above, but it allows a spatially
* varying permittivity epsilon:
@@ -281,15 +343,11 @@ int psi_sor_poisson(psi_t * obj, int its) {
*
****************************************************************************/
-int psi_sor_vare_poisson(psi_t * obj, fe_es_t * fe, f_vare_t fepsilon, int its) {
+int psi_solver_sor_var_epsilon_solve(psi_solver_sor_t * sor, int its) {
int niteration = 2000; /* Maximum number of iterations */
const int ncheck = 1; /* Check global residual every n iterations */
-
- int ic, jc, kc, index;
- int n; /* Relaxation iterations */
- int pass; /* Red/black iteration */
- int kst; /* Start kc index for red/black iteration */
+
int nlocal[3];
int nsites;
int xs, ys, zs; /* Memory strides */
@@ -305,22 +363,19 @@ int psi_sor_vare_poisson(psi_t * obj, fe_es_t * fe, f_vare_t fepsilon, int its)
double omega; /* Over-relaxation parameter 1 < omega < 2 */
double radius; /* Spectral radius of Jacobi iteration */
- double tol_rel; /* Relative tolerance */
- double tol_abs; /* Absolute tolerance */
-
double ltot[3];
double eunit, beta;
MPI_Comm comm; /* Cartesian communicator */
- assert(obj);
- assert(fepsilon);
+ psi_t * psi = sor->psi;
+ double * __restrict__ psidata = psi->psi->data;
- cs_ltot(obj->cs, ltot);
- cs_nlocal(obj->cs, nlocal);
- cs_nsites(obj->cs, &nsites);
- cs_cart_comm(obj->cs, &comm);
- cs_strides(obj->cs, &xs, &ys, &zs);
+ cs_ltot(psi->cs, ltot);
+ cs_nlocal(psi->cs, nlocal);
+ cs_nsites(psi->cs, &nsites);
+ cs_cart_comm(psi->cs, &comm);
+ cs_strides(psi->cs, &xs, &ys, &zs);
/* The red/black operation needs to be tested for odd numbers
* of points in parallel. */
@@ -333,137 +388,99 @@ int psi_sor_vare_poisson(psi_t * obj, fe_es_t * fe, f_vare_t fepsilon, int its)
radius = 1.0 - 0.5*pow(4.0*atan(1.0)/dmax(ltot[X],ltot[Z]), 2);
- psi_reltol(obj, &tol_rel);
- psi_abstol(obj, &tol_abs);
- psi_maxits(obj, &niteration);
- psi_beta(obj, &beta);
- psi_unit_charge(obj, &eunit);
+ psi_maxits(psi, &niteration);
+ psi_beta(psi, &beta);
+ psi_unit_charge(psi, &eunit);
- rnorm_local[0] = 0.0;
- for (ic = 1; ic <= nlocal[X]; ic++) {
- for (jc = 1; jc <= nlocal[Y]; jc++) {
- for (kc = 1; kc <= nlocal[Z]; kc++) {
+ /* Compute the initial norm of the right hand side. */
- depsi = 0.0;
-
- index = cs_index(obj->cs, ic, jc, kc);
-
- psi_rho_elec(obj, index, &rho_elec);
- fepsilon(fe, index, &eps0);
-
- /* Laplacian part of operator */
-
- depsi += eps0*(-6.0*obj->psi[addr_rank0(nsites, index)]
- + obj->psi[addr_rank0(nsites, index + xs)]
- + obj->psi[addr_rank0(nsites, index - xs)]
- + obj->psi[addr_rank0(nsites, index + ys)]
- + obj->psi[addr_rank0(nsites, index - ys)]
- + obj->psi[addr_rank0(nsites, index + zs)]
- + obj->psi[addr_rank0(nsites, index - zs)]);
-
- /* Additional terms in generalised Poisson equation */
-
- fepsilon(fe, index + xs, &eps1);
- depsi += 0.25*eps1*(obj->psi[addr_rank0(nsites, index + xs)]
- - obj->psi[addr_rank0(nsites, index - xs)]);
-
- fepsilon(fe, index - xs, &eps1);
- depsi -= 0.25*eps1*(obj->psi[addr_rank0(nsites, index + xs)]
- - obj->psi[addr_rank0(nsites, index - xs)]);
-
- fepsilon(fe, index + ys, &eps1);
- depsi += 0.25*eps1*(obj->psi[addr_rank0(nsites, index + ys)]
- - obj->psi[addr_rank0(nsites, index - ys)]);
-
- fepsilon(fe, index - ys, &eps1);
- depsi -= 0.25*eps1*(obj->psi[addr_rank0(nsites, index + ys)]
- - obj->psi[addr_rank0(nsites, index - ys)]);
+ rnorm_local[0] = 0.0;
- fepsilon(fe, index + zs, &eps1);
- depsi += 0.25*eps1*(obj->psi[addr_rank0(nsites, index + zs)]
- - obj->psi[addr_rank0(nsites, index - zs)]);
+ for (int ic = 1; ic <= nlocal[X]; ic++) {
+ for (int jc = 1; jc <= nlocal[Y]; jc++) {
+ for (int kc = 1; kc <= nlocal[Z]; kc++) {
- fepsilon(fe, index - zs, &eps1);
- depsi -= 0.25*eps1*(obj->psi[addr_rank0(nsites, index + zs)]
- - obj->psi[addr_rank0(nsites, index - zs)]);
+ int index = cs_index(psi->cs, ic, jc, kc);
+ psi_rho_elec(psi, index, &rho_elec);
- /* Non-dimensional potential in Poisson eqn requires e/kT */
- rnorm_local[0] += fabs(depsi + eunit*beta*rho_elec);
+ residual = eunit*beta*rho_elec;
+ rnorm_local[0] += residual*residual;
}
}
}
+ rnorm_local[0] = sqrt(rnorm_local[0]);
+
/* Iterate to solution */
omega = 1.0;
- for (n = 0; n < niteration; n++) {
+ for (int n = 0; n < niteration; n++) {
/* Compute current normal of the residual */
rnorm_local[1] = 0.0;
- for (pass = 0; pass < 2; pass++) {
+ for (int pass = 0; pass < 2; pass++) {
- for (ic = 1; ic <= nlocal[X]; ic++) {
- for (jc = 1; jc <= nlocal[Y]; jc++) {
- kst = 1 + (ic + jc + pass) % 2;
- for (kc = kst; kc <= nlocal[Z]; kc += 2) {
+ for (int ic = 1; ic <= nlocal[X]; ic++) {
+ for (int jc = 1; jc <= nlocal[Y]; jc++) {
+ int kst = 1 + (ic + jc + pass) % 2;
+ for (int kc = kst; kc <= nlocal[Z]; kc += 2) {
+ int index = cs_index(psi->cs, ic, jc, kc);
depsi = 0.0;
- index = cs_index(obj->cs, ic, jc, kc);
-
- psi_rho_elec(obj, index, &rho_elec);
- fepsilon(fe, index, &eps0);
+ psi_rho_elec(psi, index, &rho_elec);
+ sor->epsilon(sor->fe, index, &eps0);
/* Laplacian part of operator */
- depsi += eps0*(-6.0*obj->psi[addr_rank0(nsites, index)]
- + obj->psi[addr_rank0(nsites, index + xs)]
- + obj->psi[addr_rank0(nsites, index - xs)]
- + obj->psi[addr_rank0(nsites, index + ys)]
- + obj->psi[addr_rank0(nsites, index - ys)]
- + obj->psi[addr_rank0(nsites, index + zs)]
- + obj->psi[addr_rank0(nsites, index - zs)]);
+ depsi += eps0*(-6.0*psidata[addr_rank0(nsites, index)]
+ + psidata[addr_rank0(nsites, index + xs)]
+ + psidata[addr_rank0(nsites, index - xs)]
+ + psidata[addr_rank0(nsites, index + ys)]
+ + psidata[addr_rank0(nsites, index - ys)]
+ + psidata[addr_rank0(nsites, index + zs)]
+ + psidata[addr_rank0(nsites, index - zs)]);
/* Additional terms in generalised Poisson equation */
- fepsilon(fe, index + xs, &eps1);
- depsi += 0.25*eps1*(obj->psi[addr_rank0(nsites, index + xs)]
- - obj->psi[addr_rank0(nsites, index - xs)]);
+ sor->epsilon(sor->fe, index + xs, &eps1);
+ depsi += 0.25*eps1*(psidata[addr_rank0(nsites, index + xs)]
+ - psidata[addr_rank0(nsites, index - xs)]);
- fepsilon(fe, index - xs, &eps1);
- depsi -= 0.25*eps1*(obj->psi[addr_rank0(nsites, index + xs)]
- - obj->psi[addr_rank0(nsites, index - xs)]);
+ sor->epsilon(sor->fe, index - xs, &eps1);
+ depsi -= 0.25*eps1*(psidata[addr_rank0(nsites, index + xs)]
+ - psidata[addr_rank0(nsites, index - xs)]);
- fepsilon(fe, index + ys, &eps1);
- depsi += 0.25*eps1*(obj->psi[addr_rank0(nsites, index + ys)]
- - obj->psi[addr_rank0(nsites, index - ys)]);
+ sor->epsilon(sor->fe, index + ys, &eps1);
+ depsi += 0.25*eps1*(psidata[addr_rank0(nsites, index + ys)]
+ - psidata[addr_rank0(nsites, index - ys)]);
- fepsilon(fe, index - ys, &eps1);
- depsi -= 0.25*eps1*(obj->psi[addr_rank0(nsites, index + ys)]
- - obj->psi[addr_rank0(nsites, index - ys)]);
+ sor->epsilon(sor->fe, index - ys, &eps1);
+ depsi -= 0.25*eps1*(psidata[addr_rank0(nsites, index + ys)]
+ - psidata[addr_rank0(nsites, index - ys)]);
- fepsilon(fe, index + zs, &eps1);
- depsi += 0.25*eps1*(obj->psi[addr_rank0(nsites, index + zs)]
- - obj->psi[addr_rank0(nsites, index - zs)]);
+ sor->epsilon(sor->fe, index + zs, &eps1);
+ depsi += 0.25*eps1*(psidata[addr_rank0(nsites, index + zs)]
+ - psidata[addr_rank0(nsites, index - zs)]);
- fepsilon(fe, index - zs, &eps1);
- depsi -= 0.25*eps1*(obj->psi[addr_rank0(nsites, index + zs)]
- - obj->psi[addr_rank0(nsites, index - zs)]);
+ sor->epsilon(sor->fe, index - zs, &eps1);
+ depsi -= 0.25*eps1*(psidata[addr_rank0(nsites, index + zs)]
+ - psidata[addr_rank0(nsites, index - zs)]);
/* Non-dimensional potential in Poisson eqn requires e/kT */
residual = depsi + eunit*beta*rho_elec;
- obj->psi[addr_rank0(nsites,index)] -= omega*residual / (-6.0*eps0);
- rnorm_local[1] += fabs(residual);
+ psidata[addr_rank0(nsites,index)] -= omega*residual / (-6.0*eps0);
+ rnorm_local[1] += residual*residual;
}
}
}
- psi_halo_psi(obj);
- psi_halo_psijump(obj);
+ psi_halo_psi(psi);
+ psi_halo_psijump(psi);
}
@@ -475,34 +492,39 @@ int psi_sor_vare_poisson(psi_t * obj, fe_es_t * fe, f_vare_t fepsilon, int its)
/* Compare residual and exit if small enough */
+ rnorm_local[1] = sqrt(rnorm_local[1]);
MPI_Allreduce(rnorm_local, rnorm, 2, MPI_DOUBLE, MPI_SUM, comm);
- if (rnorm[1] < tol_abs) {
+ if (rnorm[1] < psi->solver.abstol) {
- if (its % obj->nfreq == 0) {
- pe_info(obj->pe, "\n");
- pe_info(obj->pe, "SOR (heterogeneous) solver converged to absolute tolerance\n");
- pe_info(obj->pe, "SOR residual per site %14.7e at %d iterations\n",
- rnorm[1]/(ltot[X]*ltot[Y]*ltot[Z]), n);
+ if (its % psi->solver.nfreq == 0) {
+ pe_info(psi->pe, "\n");
+ pe_info(psi->pe, "SOR (heterogeneous) solver converged to "
+ "absolute tolerance\n");
+ pe_info(psi->pe, "SOR residual %14.7e at %d iterations\n",
+ rnorm[1], n);
}
break;
}
- if (rnorm[1] < tol_rel*rnorm[0]) {
+ if (rnorm[1] < psi->solver.reltol*rnorm[0]) {
- if (its % obj->nfreq == 0) {
- pe_info(obj->pe, "\n");
- pe_info(obj->pe, "SOR (heterogeneous) solver converged to relative tolerance\n");
- pe_info(obj->pe, "SOR residual per site %14.7e at %d iterations\n",
- rnorm[1]/(ltot[X]*ltot[Y]*ltot[Z]), n);
+ if (its % psi->solver.nfreq == 0) {
+ pe_info(psi->pe, "\n");
+ pe_info(psi->pe, "SOR (heterogeneous) solver converged to "
+ "relative tolerance\n");
+ pe_info(psi->pe, "SOR residual %14.7e at %d iterations\n",
+ rnorm[1], n);
}
break;
}
if (n == niteration-1) {
- pe_info(obj->pe, "\n");
- pe_info(obj->pe, "SOR solver (heterogeneous) exceeded %d iterations\n", n+1);
- pe_info(obj->pe, "SOR residual %le (initial) %le (final)\n\n", rnorm[0], rnorm[1]);
+ pe_info(psi->pe, "\n");
+ pe_info(psi->pe, "SOR solver (heterogeneous) exceeded %d iterations\n",
+ n+1);
+ pe_info(psi->pe, "SOR residual %le (initial) %le (final)\n\n",
+ rnorm[0], rnorm[1]);
}
}
}
diff --git a/src/psi_sor.h b/src/psi_sor.h
index d8025b08d..a8f13c626 100644
--- a/src/psi_sor.h
+++ b/src/psi_sor.h
@@ -9,18 +9,34 @@
* Kevin Stratford (kevin@epcc.ed.ac.uk)
* Ignacio Pagonabarraga (ipagonabarraga@ub.edu)
*
- * (c) 2012-2022 The University of Edinburgh
+ * (c) 2012-2023 The University of Edinburgh
*
*****************************************************************************/
-#ifndef LUDWIG_PSI_SOR_H
-#define LUDWIG_PSI_SOR_H
+#ifndef LUDWIG_PSI_SOLVER_SOR_H
+#define LUDWIG_PSI_SOLVER_SOR_H
-#include "psi.h"
-#include "fe_electro_symmetric.h"
+#include "psi_solver.h"
+
+typedef struct psi_solver_sor_s psi_solver_sor_t;
+
+struct psi_solver_sor_s {
+ psi_solver_t super; /* superclass block */
+ psi_t * psi; /* Reference to psi structure */
+ fe_t * fe; /* abstract free energy */
+ var_epsilon_ft epsilon; /* provides local epsilon */
+};
+
+int psi_solver_sor_create(psi_t * psi, psi_solver_sor_t ** sor);
+int psi_solver_sor_free(psi_solver_sor_t ** sor);
+int psi_solver_sor_solve(psi_solver_sor_t * sor, int ntimestep);
+
+/* This might actually be a separate solver type. */
+
+int psi_solver_sor_var_epsilon_create(psi_t * psi, var_epsilon_t epsilon,
+ psi_solver_sor_t ** sor);
+
+int psi_solver_sor_var_epsilon_solve(psi_solver_sor_t * sor, int ntimestep);
-int psi_sor_solve(psi_t * obj, fe_t * fe, f_vare_t fepsilon, int its);
-int psi_sor_poisson(psi_t * obj, int its);
-int psi_sor_vare_poisson(psi_t * obj, fe_es_t * fe, f_vare_t fepsilon, int its);
#endif
diff --git a/src/psi_stats.c b/src/psi_stats.c
index f992ec7a3..8c38185d0 100644
--- a/src/psi_stats.c
+++ b/src/psi_stats.c
@@ -7,7 +7,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2012-2017 The University of Edinburgh
+ * (c) 2012-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -21,7 +21,6 @@
#include "pe.h"
#include "coords.h"
#include "util.h"
-#include "psi_s.h"
#include "psi_stats.h"
/*****************************************************************************
diff --git a/src/stats_distribution.c b/src/stats_distribution.c
index 547f0a132..40f5e5ee2 100644
--- a/src/stats_distribution.c
+++ b/src/stats_distribution.c
@@ -11,7 +11,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2010-2022 The University of Edinburgh
+ * (c) 2010-2023 The University of Edinburgh
*
* Kevin Stratford (kevin@epcc.ed.ac.uk)
*
@@ -32,13 +32,15 @@ typedef struct gm_util_s {
int8_t cv[27][3];
} gm_util_t;
+static __constant__ gm_util_t util_;
+
__host__ int stats_distribution_momentum_serial(lb_t * lb, map_t * map,
double g[3]);
__host__ int distribution_stats_momentum(lb_t * lb, map_t * map, int root,
MPI_Comm comm, double gm[3]);
__global__ void distribution_gm_kernel(kernel_ctxt_t * ktxt, lb_t * lb,
- map_t * map, gm_util_t u, kahan_t * gm);
+ map_t * map, kahan_t * gm);
/*****************************************************************************
@@ -221,6 +223,8 @@ __host__ int distribution_stats_momentum(lb_t * lb, map_t * map, int root,
util.cv[p][Y] = lb->model.cv[p][Y];
util.cv[p][Z] = lb->model.cv[p][Z];
}
+ tdpMemcpyToSymbol(tdpSymbol(util_), &util, sizeof(gm_util_t), 0,
+ tdpMemcpyHostToDevice);
/* Local kernel */
@@ -233,7 +237,7 @@ __host__ int distribution_stats_momentum(lb_t * lb, map_t * map, int root,
kernel_ctxt_launch_param(ctxt, &nblk, &ntpb);
tdpLaunchKernel(distribution_gm_kernel, nblk, ntpb, 0, 0,
- ctxt->target, lb->target, map->target, util, sum_d);
+ ctxt->target, lb->target, map->target, sum_d);
tdpAssert(tdpPeekAtLastError());
tdpAssert(tdpDeviceSynchronize());
@@ -275,8 +279,7 @@ __host__ int distribution_stats_momentum(lb_t * lb, map_t * map, int root,
*****************************************************************************/
__global__ void distribution_gm_kernel(kernel_ctxt_t * ktx, lb_t * lb,
- map_t * map, gm_util_t util,
- kahan_t * gm) {
+ map_t * map, kahan_t * gm) {
assert(ktx);
assert(lb);
@@ -317,9 +320,9 @@ __global__ void distribution_gm_kernel(kernel_ctxt_t * ktx, lb_t * lb,
if (status == MAP_FLUID) {
for (int p = 1; p < lb->nvel; p++) {
double f = lb->f[LB_ADDR(lb->nsite,lb->ndist,lb->nvel,index,LB_RHO,p)];
- double gxf = f*util.cv[p][X];
- double gyf = f*util.cv[p][Y];
- double gzf = f*util.cv[p][Z];
+ double gxf = f*util_.cv[p][X];
+ double gyf = f*util_.cv[p][Y];
+ double gzf = f*util_.cv[p][Z];
kahan_add_double(&gx[tid], gxf);
kahan_add_double(&gy[tid], gyf);
kahan_add_double(&gz[tid], gzf);
diff --git a/src/stencil.h b/src/stencil.h
new file mode 100644
index 000000000..8b72ab7c7
--- /dev/null
+++ b/src/stencil.h
@@ -0,0 +1,46 @@
+/*****************************************************************************
+ *
+ * stencil.h
+ *
+ * Lattice Boltzmann velocities/weights re-interpreted as a
+ * finite-difference stencil.
+ *
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#ifndef LUDWIG_STENCIL_H
+#define LUDWIG_STENCIL_H
+
+#include
+#include
+#include "cartesian.h" /* not used explicitly here, but required ... */
+
+typedef struct stencil_s stencil_t;
+
+struct stencil_s {
+ int8_t ndim; /* 2 or 3 */
+ int8_t npoints; /* or velocities */
+ int8_t ** cv; /* cv[npoints][ndim] */
+ double * wlaplacian; /* weights for Laplacian */
+ double * wgradients; /* weights for Gradient */
+};
+
+int stencil_create(int npoints, stencil_t ** s);
+int stencil_free(stencil_t ** s);
+int stencil_finalise(stencil_t * s);
+
+/* Could be part of the lattice Boltzmann definition, but used with stencils */
+/* Table for 1/sqrt(cx^2 + cy^2 + cz^2) indexed by c^2 */
+/* We set rcs[0] = 0, rcs[1] = 1, etc... */
+
+#define LB_RCS_TABLE(rcs) \
+ const double rcs[4] = {0.0, 1.0, 1.0/sqrt(2.0), 1.0/sqrt(3.0)};
+
+#endif
diff --git a/src/stencil_d3q19.c b/src/stencil_d3q19.c
new file mode 100644
index 000000000..49bcb38db
--- /dev/null
+++ b/src/stencil_d3q19.c
@@ -0,0 +1,79 @@
+/*****************************************************************************
+ *
+ * stencil_d3q19.c
+ *
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#include
+#include
+
+#include "stencil_d3q19.h"
+
+/*****************************************************************************
+ *
+ * stencil_d3q19_create
+ *
+ *****************************************************************************/
+
+int stencil_d3q19_create(stencil_t ** stencil) {
+
+ stencil_t * s = NULL;
+
+ s = (stencil_t *) calloc(1, sizeof(stencil_t));
+ assert(s);
+
+ s->ndim = 3;
+ s->npoints = NVEL_D3Q19;
+ s->cv = (int8_t **) calloc(NVEL_D3Q19, sizeof(int8_t *));
+ s->wlaplacian = (double *) calloc(NVEL_D3Q19, sizeof(double));
+ s->wgradients = (double *) calloc(NVEL_D3Q19, sizeof(double));
+
+ if (s->cv == NULL) goto err;
+ if (s->wlaplacian == NULL) goto err;
+ if (s->wgradients == NULL) goto err;
+
+ s->cv[0] = (int8_t *) calloc(s->ndim*s->npoints, sizeof(int8_t));
+ if (s->cv[0] == NULL) goto err;
+
+ for (int p = 1; p < s->npoints; p++) {
+ s->cv[p] = s->cv[p-1] + s->ndim;
+ }
+
+ /* Set velocities/weights/stencil */
+ {
+ double wlap0 = 0.0;
+ LB_CV_D3Q19(cv);
+ LB_WEIGHTS_D3Q19(wv);
+ for (int p = 0; p < s->npoints; p++) {
+ for (int ia = 0; ia < s->ndim; ia++) {
+ s->cv[p][ia] = cv[p][ia];
+ }
+ s->wlaplacian[p] = -36.0*wv[p];
+ s->wgradients[p] = +3.0*wv[p];
+ if (p > 0) wlap0 += s->wlaplacian[p];
+ }
+ s->wlaplacian[0] = -wlap0;
+ s->wgradients[0] = 0.0;
+ }
+
+ *stencil = s;
+ return 0;
+
+ err:
+
+ if (s->wgradients) free(s->wgradients);
+ if (s->wlaplacian) free(s->wlaplacian);
+ if (s->cv) free(s->cv);
+
+ *stencil = NULL;
+
+ return -1;
+}
diff --git a/src/stencil_d3q19.h b/src/stencil_d3q19.h
new file mode 100644
index 000000000..ce0b00869
--- /dev/null
+++ b/src/stencil_d3q19.h
@@ -0,0 +1,24 @@
+/*****************************************************************************
+ *
+ * stencil_d3q19.h
+ *
+ * A 19 point finite deifferrence stencil following lb_d3q19.h.
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#ifndef LUDWIG_STENCIL_D3Q19_H
+#define LUDWIG_STENCIL_D3Q19_H
+
+#include "lb_d3q19.h"
+#include "stencil.h"
+
+int stencil_d3q19_create(stencil_t ** s);
+
+#endif
diff --git a/src/stencil_d3q27.c b/src/stencil_d3q27.c
new file mode 100644
index 000000000..6a0eb7556
--- /dev/null
+++ b/src/stencil_d3q27.c
@@ -0,0 +1,84 @@
+/*****************************************************************************
+ *
+ * stencil_d3q27.c
+ *
+ * Finite difference stencils based on lb_d3q27.h weights.
+ *
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#include
+#include
+
+#include "stencil_d3q27.h"
+
+/*****************************************************************************
+ *
+ * stencil_d3q27_create
+ *
+ *****************************************************************************/
+
+int stencil_d3q27_create(stencil_t ** stencil) {
+
+ stencil_t * s = NULL;
+
+ assert(stencil);
+
+ s = (stencil_t *) calloc(1, sizeof(stencil_t));
+ assert(s);
+
+ s->ndim = 3;
+ s->npoints = NVEL_D3Q27;
+ s->cv = (int8_t **) calloc(NVEL_D3Q27, sizeof(int8_t *));
+ s->wlaplacian = (double *) calloc(NVEL_D3Q27, sizeof(double));
+ s->wgradients = (double *) calloc(NVEL_D3Q27, sizeof(double));
+
+ if (s->cv == NULL) goto err;
+ if (s->wlaplacian == NULL) goto err;
+ if (s->wgradients == NULL) goto err;
+
+ s->cv[0] = (int8_t *) calloc(s->ndim*s->npoints, sizeof(int8_t));
+ if (s->cv[0] == NULL) goto err;
+
+ for (int p = 1; p < s->npoints; p++) {
+ s->cv[p] = s->cv[p-1] + s->ndim;
+ }
+
+ /* Set velocities/weights/stencil */
+ {
+ double wlap0 = 0.0;
+ LB_CV_D3Q27(cv);
+ LB_WEIGHTS_D3Q27(wv);
+ for (int p = 0; p < s->npoints; p++) {
+ for (int ia = 0; ia < s->ndim; ia++) {
+ s->cv[p][ia] = cv[p][ia];
+ }
+ s->wlaplacian[p] = -216.0*wv[p];
+ s->wgradients[p] = 3.0*wv[p];
+ if (p > 0) wlap0 += s->wlaplacian[p];
+ }
+ /* Central point */
+ s->wlaplacian[0] = -wlap0;
+ s->wgradients[0] = 0.0;
+ }
+
+ *stencil = s;
+ return 0;
+
+ err:
+
+ if (s->wgradients) free(s->wgradients);
+ if (s->wlaplacian) free(s->wlaplacian);
+ if (s->cv) free(s->cv);
+
+ *stencil = NULL;
+
+ return -1;
+}
diff --git a/src/stencil_d3q27.h b/src/stencil_d3q27.h
new file mode 100644
index 000000000..ca550d447
--- /dev/null
+++ b/src/stencil_d3q27.h
@@ -0,0 +1,25 @@
+/*****************************************************************************
+ *
+ * stencil_d3q27.h
+ *
+ * A finite difference stencil following lb_d3q27.h.
+ *
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#ifndef LUDWIG_STENCIL_D3Q27_H
+#define LUDWIG_STENCIL_D3Q27_H
+
+#include "lb_d3q27.h"
+#include "stencil.h"
+
+int stencil_d3q27_create(stencil_t ** s);
+
+#endif
diff --git a/src/stencil_d3q7.c b/src/stencil_d3q7.c
new file mode 100644
index 000000000..9497fa1f1
--- /dev/null
+++ b/src/stencil_d3q7.c
@@ -0,0 +1,87 @@
+/*****************************************************************************
+ *
+ * stencil_d3q7.c
+ *
+ * A 7-point stencil in three dimensions.
+ *
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#include
+#include
+
+#include "stencil_d3q7.h"
+
+/*****************************************************************************
+ *
+ * stencil_d3q7_create
+ *
+ * The LB weights are {2.0/8.0, 1.0/8.0, ...}
+ * Laplacian. The weights should be {-6.0, +1.0, ...} so a factor of 8.
+ * Gradient. The weights should be { 0.0, +0.5, ...} so a factor of 4.
+ *
+ *****************************************************************************/
+
+int stencil_d3q7_create(stencil_t ** stencil) {
+
+ stencil_t * s = NULL;
+
+ s = (stencil_t *) calloc(1, sizeof(stencil_t));
+ assert(s);
+
+ s->ndim = 3;
+ s->npoints = NVEL_D3Q7;
+ s->cv = (int8_t **) calloc(NVEL_D3Q7, sizeof(int8_t *));
+ s->wlaplacian = (double *) calloc(NVEL_D3Q7, sizeof(double));
+ s->wgradients = (double *) calloc(NVEL_D3Q7, sizeof(double));
+
+ if (s->cv == NULL) goto err;
+ if (s->wlaplacian == NULL) goto err;
+ if (s->wgradients == NULL) goto err;
+
+ s->cv[0] = (int8_t *) calloc(s->ndim*NVEL_D3Q7, sizeof(int8_t));
+ if (s->cv[0] == NULL) goto err;
+
+ for (int p = 1; p < s->npoints; p++) {
+ s->cv[p] = s->cv[p-1] + s->ndim;
+ }
+
+ /* Set velocities/weights/stencil */
+ {
+ double wlap0 = 0.0;
+ LB_CV_D3Q7(cv);
+ LB_WEIGHTS_D3Q7(wv);
+ for (int p = 0; p < s->npoints; p++) {
+ for (int ia = 0; ia < s->ndim; ia++) {
+ s->cv[p][ia] = cv[p][ia];
+ }
+ s->wlaplacian[p] = -8.0*wv[p]; /* 2/8, 1/8 -> 2, 1 */
+ s->wgradients[p] = +4.0*wv[p]; /* 1/8 -> 1/2 */
+ if (p > 0) wlap0 += s->wlaplacian[p];
+ }
+ /* We must have wlaplacian[0] = -\sum_{p=1} wlaplacian[p]. */
+ /* No contribution to the gradient from the central point. */
+ s->wlaplacian[0] = -wlap0;
+ s->wgradients[0] = 0.0;
+ }
+
+ *stencil = s;
+ return 0;
+
+ err:
+
+ if (s->wgradients) free(s->wgradients);
+ if (s->wlaplacian) free(s->wlaplacian);
+ if (s->cv) free(s->cv);
+
+ *stencil = NULL;
+
+ return -1;
+}
diff --git a/src/stencil_d3q7.h b/src/stencil_d3q7.h
new file mode 100644
index 000000000..9eeefeb79
--- /dev/null
+++ b/src/stencil_d3q7.h
@@ -0,0 +1,34 @@
+/*****************************************************************************
+ *
+ * stencil_d3q7.h
+ *
+ * A 7-point stencil inn three dimensions.
+ *
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#ifndef LUDWIG_STENCIL_D3Q7_H
+#define LUDWIG_STENCIL_D3Q7_H
+
+#include
+#include "stencil.h"
+
+enum {NVEL_D3Q7 = 7};
+
+#define LB_CV_D3Q7(cv) const int8_t cv[NVEL_D3Q7][3] = { \
+{0,0,0}, {1, 0, 0}, {0, 1, 0}, {0, 0, 1}, {0, 0, -1}, {0, -1, 0}, {-1, 0, 0}};
+
+/* The weights are |0| = 2 and |1| = 1 (all over 8). */
+#define LB_WEIGHTS_D3Q7(wv) const double wv[NVEL_D3Q7] = { \
+2.0/8.0, 1.0/8.0, 1.0/8.0, 1.0/8.0, 1.0/8.0, 1.0/8.0, 1.0/8.0 };
+
+int stencil_d3q7_create(stencil_t ** s);
+
+#endif
diff --git a/src/stencils.c b/src/stencils.c
new file mode 100644
index 000000000..598762bc9
--- /dev/null
+++ b/src/stencils.c
@@ -0,0 +1,85 @@
+/*****************************************************************************
+ *
+ * stencils.c
+ *
+ * Factory method for stencils.
+ *
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#include
+#include
+
+#include "stencil_d3q7.h"
+#include "stencil_d3q19.h"
+#include "stencil_d3q27.h"
+
+/*****************************************************************************
+ *
+ * stencil_create
+ *
+ *****************************************************************************/
+
+int stencil_create(int npoints, stencil_t ** s) {
+
+ int ifail = 0;
+
+ switch (npoints) {
+ case NVEL_D3Q7:
+ ifail = stencil_d3q7_create(s);
+ break;
+ case NVEL_D3Q19:
+ ifail = stencil_d3q19_create(s);
+ break;
+ case NVEL_D3Q27:
+ ifail = stencil_d3q27_create(s);
+ break;
+ default:
+ ifail = -1;
+ }
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * stencil_free
+ *
+ *****************************************************************************/
+
+int stencil_free(stencil_t ** s) {
+
+ assert(s);
+ assert(*s);
+
+ stencil_finalise(*s);
+ free(*s);
+ *s = NULL;
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * stencil_finalise
+ *
+ *****************************************************************************/
+
+int stencil_finalise(stencil_t * s) {
+
+ assert(s);
+
+ free(s->wgradients);
+ free(s->wlaplacian);
+ free(s->cv[0]);
+ free(s->cv);
+
+ return 0;
+}
diff --git a/src/timer.c b/src/timer.c
index 3f71da603..5141a120d 100644
--- a/src/timer.c
+++ b/src/timer.c
@@ -10,7 +10,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2010-2022 The University of Edinburgh
+ * (c) 2010-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -90,7 +90,7 @@ static const char * timer_name[] = {"Total",
"Poisson equation",
"Nernst Planck",
"Lap timer (no report)",
- "Free1",
+ "Diagnostics / output",
"Free2",
"Free3", "Free4", "Free5", "Free6"
};
diff --git a/src/timer.h b/src/timer.h
index 28067c188..b712076c2 100644
--- a/src/timer.h
+++ b/src/timer.h
@@ -8,7 +8,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2010-2021 The University of Edinburgh
+ * (c) 2010-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -102,7 +102,7 @@ enum timer_id {TIMER_TOTAL = 0,
TIMER_ELECTRO_POISSON,
TIMER_ELECTRO_NPEQ,
TIMER_LAP,
- TIMER_FREE1,
+ TIMER_DIAGNOSTIC_OUTPUT,
TIMER_FREE2,
TIMER_FREE3,
TIMER_FREE4,
diff --git a/src/util.c b/src/util.c
index 87b8636a5..716be929b 100644
--- a/src/util.c
+++ b/src/util.c
@@ -349,13 +349,13 @@ __host__ int util_jacobi(double a[3][3], double vals[3], double vecs[3][3]) {
g = 100.0*fabs(a[ia][ib]);
- if (iterate > 4 && (fabs(vals[ia]) + g) == fabs(vals[ia]) &&
- (fabs(vals[ib]) + g) == fabs(vals[ib])) {
+ if (iterate > 4 && (((fabs(vals[ia]) + g) - fabs(vals[ia])) == 0.0) &&
+ (((fabs(vals[ib]) + g) - fabs(vals[ib])) == 0.0)) {
a[ia][ib] = 0.0;
}
else if (fabs(a[ia][ib]) > tresh) {
h = vals[ib] - vals[ia];
- if ((fabs(h) + g) == fabs(h)) {
+ if (((fabs(h) + g) - fabs(h)) == 0.0) {
t = (a[ia][ib])/h;
}
else {
@@ -594,41 +594,6 @@ int util_gauss_jordan(const int n, double * a, double * b) {
return 0;
}
-/*****************************************************************************
- *
- * util_vector_create
- *
- *****************************************************************************/
-
-__host__
-int util_vector_create(int n, double ** p) {
-
- int ifail = 0;
- double * v = NULL;
-
- v = (double*) calloc(n, sizeof(double));
- if (v == NULL) ifail = 1;
-
- *p = v;
-
- return ifail;
-}
-
-/*****************************************************************************
- *
- * util_vector_free
- *
- *****************************************************************************/
-
-__host__
-int util_vector_free(double ** p) {
-
- free(*p);
- *p = NULL;
-
- return 0;
-}
-
/*****************************************************************************
*
* util_matrix_create
@@ -815,8 +780,7 @@ __host__ int util_matrix_invert(int n, double ** a) {
*
*****************************************************************************/
-__host__ __device__
-int util_dpythag(double a, double b, double * p) {
+__host__ int util_dpythag(double a, double b, double * p) {
double absa, absb, tmp;
diff --git a/src/util.h b/src/util.h
index bdf64981b..7c32eaa6a 100644
--- a/src/util.h
+++ b/src/util.h
@@ -53,11 +53,9 @@ __host__ int util_jacobi(double a[3][3], double vals[3], double vecs[3][3]);
__host__ int util_jacobi_sort(double a[3][3], double vals[3], double vecs[3][3]);
__host__ int util_discrete_volume_sphere(double r0[3], double a0, double * vn);
__host__ int util_gauss_jordan(const int n, double * a, double * b);
-__host__ __device__ int util_dpythag(double a, double b, double * p);
+__host__ int util_dpythag(double a, double b, double * p);
__host__ int util_matrix_create(int m, int n, double *** p);
-__host__ int util_vector_create(int m, double ** p);
__host__ int util_matrix_free(int m, double *** p);
-__host__ int util_vector_free(double ** p);
__host__ int util_matrix_invert(int n, double ** a);
__host__ int util_random_unit_vector(int * state, double rhat[3]);
diff --git a/src/util_cJSON.c b/src/util_cJSON.c
index 8214bbe47..d8e8b4531 100644
--- a/src/util_cJSON.c
+++ b/src/util_cJSON.c
@@ -564,10 +564,9 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out
{
length = sprintf((char*)number_buffer, "null");
}
- else if(d == (double)item->valueint)
- {
- length = sprintf((char*)number_buffer, "%d", item->valueint);
- }
+ else if((d - (double)item->valueint) == 0.0) {
+ length = sprintf((char*)number_buffer, "%d", item->valueint);
+ }
else
{
/* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
diff --git a/src/util_petsc.c b/src/util_petsc.c
new file mode 100644
index 000000000..b35043968
--- /dev/null
+++ b/src/util_petsc.c
@@ -0,0 +1,81 @@
+/*****************************************************************************
+ *
+ * util_petsc.c
+ *
+ * A facade.
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#include
+
+#include "util_petsc.h"
+
+/*****************************************************************************
+ *
+ * PetscInitialised
+ *
+ * A slightly adapted version.
+ *
+ *****************************************************************************/
+
+int PetscInitialised(int * isInitialised) {
+
+ PetscBool havePetsc = PETSC_FALSE;
+ PetscInitialized(&havePetsc);
+
+ *isInitialised = 0;
+ if (havePetsc == PETSC_TRUE) *isInitialised = 1;
+
+ return 0;
+}
+
+#ifdef PETSC
+/* Nothing more required. */
+#else
+
+/*****************************************************************************
+ *
+ * PetscInitialize
+ *
+ *****************************************************************************/
+
+PetscErrorCode PetscInitialize(int * argc, char *** argv, const char * file,
+ const char * help) {
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * PetscFinalize
+ *
+ *****************************************************************************/
+
+PetscErrorCode PetscFinalize(void) {
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * PetscInitialized
+ *
+ *****************************************************************************/
+
+PetscErrorCode PetscInitialized(PetscBool * isInitialised) {
+
+ assert(isInitialised);
+
+ *isInitialised = (PetscBool) 0; /* Always zero */
+
+ return 0;
+}
+
+#endif
diff --git a/src/util_petsc.h b/src/util_petsc.h
new file mode 100644
index 000000000..370494848
--- /dev/null
+++ b/src/util_petsc.h
@@ -0,0 +1,37 @@
+/*****************************************************************************
+ *
+ * util_petsc.h
+ *
+ * A stub interface to deal with Petsc availability.
+ * The idea is to use PetscInitialised() [sic].
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#ifndef LUDWIG_UTIL_PETSC_H
+#define LUDWIG_UTIL_PETSC_H
+
+#ifdef PETSC
+#include "petscsys.h"
+#else
+
+/* Stub replacements for ... */
+
+typedef enum {PETSC_FALSE, PETSC_TRUE} PetscBool;
+typedef int PetscErrorCode;
+
+PetscErrorCode PetscInitialize(int * argc, char *** argv, const char * file,
+ const char * help);
+PetscErrorCode PetscFinalize(void);
+PetscErrorCode PetscInitialized(PetscBool * isInitialised);
+#endif
+
+int PetscInitialised(int * isInitialised);
+
+#endif
diff --git a/src/wall_rt.c b/src/wall_rt.c
index 22d44a1a4..6aaf16764 100644
--- a/src/wall_rt.c
+++ b/src/wall_rt.c
@@ -25,8 +25,6 @@
int wall_rt_init(pe_t * pe, cs_t * cs, rt_t * rt, lb_t * lb, map_t * map,
wall_t ** wall) {
- double ux_bot = 0.0;
- double ux_top = 0.0;
wall_slip_t ws = {0};
wall_param_t p = {0};
@@ -47,6 +45,8 @@ int wall_rt_init(pe_t * pe, cs_t * cs, rt_t * rt, lb_t * lb, map_t * map,
/* Run through input parameters */
if (p.iswall) {
+ double ux_bot = 0.0;
+ double ux_top = 0.0;
rt_double_parameter(rt, "boundary_speed_bottom", &ux_bot);
rt_double_parameter(rt, "boundary_speed_top", &ux_top);
@@ -55,6 +55,12 @@ int wall_rt_init(pe_t * pe, cs_t * cs, rt_t * rt, lb_t * lb, map_t * map,
p.ubot[X] = ux_bot; p.ubot[Y] = 0.0; p.ubot[Z] = 0.0;
p.utop[X] = ux_top; p.utop[Y] = 0.0; p.utop[Z] = 0.0;
+ /* If there is a boundary ux, the wall cannot be in X */
+ if ((ux_bot != 0.0 || ux_top != 0.0) && p.isboundary[X]) {
+ pe_info(pe, "Cannot have non-zero u_x wall velocity if wall is X\n");
+ pe_fatal(pe, "Please check and try again\n");
+ }
+
rt_double_parameter(rt, "boundary_lubrication_rcnormal", &p.lubr_rc[X]);
p.lubr_rc[Y] = p.lubr_rc[X];
p.lubr_rc[Z] = p.lubr_rc[X];
diff --git a/target/Makefile b/target/Makefile
index f86602663..ba18e152b 100644
--- a/target/Makefile
+++ b/target/Makefile
@@ -13,7 +13,7 @@
# Edinburgh Soft Matter and Statistical Physics Group and
# Edinburgh Parallel Computing Centre
#
-# (c) 2018-2019 The University of Edinburgh
+# (c) 2018-2023 The University of Edinburgh
#
# Contributing authors:
# Alan Gray (alang@epcc.ed.ac.uk)
@@ -62,3 +62,4 @@ testmpi:
clean:
rm -f *.o *.a a.out
+ rm -f *gcno *gcda
diff --git a/tests/Makefile b/tests/Makefile
index 15b5d0526..5ca482f6c 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -6,6 +6,8 @@
#
# default: builds unit tests
# test: runs unit tests and d3q19-short (default test)
+# d2q9 D2Q9 tests
+# d3q15 D3Q15 tests
# d3q19-short a batch of shorter tests
# d3q19-io a batch of tests with file I/O
# d3q19-elec a batch of tests for electrokinetics
@@ -15,7 +17,7 @@
# Edinburgh Soft Matter and Statistical Physics Group and
# Edinburgh Parallel Computing Centre
#
-# (c) 2015-2022 The University of Edinburgh
+# (c) 2015-2023 The University of Edinburgh
# Contributing authors:
# Kevin Stratford (kevinAepcc.ed.ac.uk)
#
@@ -40,6 +42,12 @@ verbose:
# Specific tests
+d2q9:
+ $(MAKE) -C regression/d2q9
+
+d3q15:
+ $(MAKE) -C regression/d3q15
+
d3q19-short:
$(MAKE) -C regression/d3q19-short
diff --git a/tests/nightly-test.sh b/tests/nightly-test.sh
deleted file mode 100755
index 91dab3232..000000000
--- a/tests/nightly-test.sh
+++ /dev/null
@@ -1,71 +0,0 @@
-##############################################################################
-#
-# nightly.sh
-#
-# This is the script to run the nightly test, and is specific for
-# local set up.
-#
-# Edinburgh Soft Matter and Statisitcal Physics Group and
-# Edinburgh Parallel Computing Centre
-#
-# Kevin Stratford (kevin@epcc.ed.ac.uk)
-# (c) 2010-2015 The University of Edinburgh
-#
-##############################################################################
-#!/bin/bash --login
-
-# Despite --login we still need to get appropriate paths, etc:
-. /etc/profile
-eval `/usr/bin/modulecmd bash load PMPI`
-export PATH=$PATH:/usr/local/cuda/bin
-
-
-# This is the local directory for the nightly stuff
-thisdir=/home/w02/kevin/nightly
-cd $thisdir
-
-testdir=ludwig/trunk/tests
-summary=$thisdir/ludwig-tests.log
-
-# Log file
-
-record=$thisdir/`date +%F-%T`.log
-
-# Start a new summary file which will overwrite anything present
-echo "Summary of $record" > $summary
-echo "Test directory is $testdir" >> $summary
-
-# Checkout the SVN (and send the report to the record)
-
-svn co --username stratford http://ccpforge.cse.rl.ac.uk/svn/ludwig &> $record
-
-# start via bsub (indy0.epcc.ed.ac.uk)
-
-cd $testdir
-cp ../config/lunix-gcc-default.mk ../config.mk
-bsub -o $record -e $record -n 64 -W 1200 -q normal -J test-cpu < test-all.sh
-
-# Note the need to wait for the first job to finish means
-# that the copy of the nvcc configuation is deferred until
-# the test-gpu script.
-
-bsub -w "ended(test-cpu)" -o $record -e $record -q gpu -J test-gpu < test-gpu-01.sh
-
-# Wait for the tests to finish, and clean up
-# This includes a copy of the summary to a public location
-# (the interactive job will wait for the main "test-all" job to
-# finish before starting and itself will finish before the copy is attempted)
-
-# Using "-q gpu" as "-q interactive" not active
-
-finish=$(cat <> $summary
-EOF
-)
-
-cd $thisdir
-bsub -w "ended(test-gpu)" -o $record -e $record -I -q gpu "$finish"
-
-
-
diff --git a/tests/regression/d2q9/Makefile b/tests/regression/d2q9/Makefile
index 43df1dfac..34d0ca274 100644
--- a/tests/regression/d2q9/Makefile
+++ b/tests/regression/d2q9/Makefile
@@ -28,4 +28,4 @@ mpix64:
@echo "TEST --> regression test mpi (64 mpi tasks)"
clean:
- rm -f *new test-diff*
+ rm -f *new test-diff* input
diff --git a/tests/regression/d2q9/serial-open-phi.log b/tests/regression/d2q9/serial-open-phi.log
index c272651a6..888cec578 100644
--- a/tests/regression/d2q9/serial-open-phi.log
+++ b/tests/regression/d2q9/serial-open-phi.log
@@ -36,7 +36,7 @@ Interfacial width = 1.13137e+00
Using Cahn-Hilliard finite difference solver.
Mobility M = 1.00000e-01
Order parameter noise = off
-Force calculation: divergence method
+Force calculation: stress_divergence
System properties
----------------
@@ -126,6 +126,9 @@ Scalars - total mean variance min max
[rho] 3200.00 1.00000000000 0.0000000e+00 1.00000000000 1.00000000000
[phi] 2.7928338e+03 8.7276057e-01 2.0274235e-01 -9.9999651e-01 1.0000000e+00
+Free energies - timestep f v f/v f_s1 fs_s2
+[fe] 0 -4.7825362015e+01 3.2000000000e+03 -1.4945425630e-02 0.0000000000e+00 0.0000000000e+00
+
Momentum - x y z
[total ] 3.2000000e+01 0.0000000e+00 0.0000000e+00
[fluid ] 3.2000000e+01 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d2q9/serial-surf-t01.log b/tests/regression/d2q9/serial-surf-t01.log
index bb2c93d51..9fdac62e9 100644
--- a/tests/regression/d2q9/serial-surf-t01.log
+++ b/tests/regression/d2q9/serial-surf-t01.log
@@ -85,8 +85,11 @@ Initial conditions.
Scalars - total mean variance min max
[rho] 512.00 1.00000000000 1.1102230e-16 1.00000000000 1.00000000000
-[phi] -2.1427304e-14 -4.1850204e-17 9.4696695e-01 -1.0000000e+00 1.0000000e+00
-[phi] 5.1200000e-02 1.0000000e-04-2.4815418e-22 1.0000000e-04 1.0000000e-04
+[phi] -2.1427304e-14 -4.1850204e-17 9.4696695e-01 -1.0000000e+00 1.0000000e+00
+[phi] 5.1200000e-02 1.0000000e-04 -2.4815418e-22 1.0000000e-04 1.0000000e-04
+
+Free energy density - timestep total fluid
+[fed] 0 -4.8447490995e-03 -4.8447490995e-03
Momentum - x y z
[total ] 7.1054274e-15 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d2q9/serial-surf-t02.inp b/tests/regression/d2q9/serial-surf-t02.inp
deleted file mode 100644
index fecc1efbe..000000000
--- a/tests/regression/d2q9/serial-surf-t02.inp
+++ /dev/null
@@ -1,107 +0,0 @@
-##############################################################################
-#
-# Surfactant model test (with hydrodynamics)
-#
-# See also serial-surf-t01.inp
-#
-# In two dimensions, intialise a drop (ie, a circle)
-# in the composition with uniform surfactant.
-#
-# Hydrodynamics is on, and the force on the fluid from
-# the thermodynamics is via phi grad mu (the only way
-# available at the time of writing; there's no option).
-#
-# Some 100,000 time steps are required to reach equilibrium
-# in this case (no change at precision of standard output).
-#
-##############################################################################
-
-##############################################################################
-#
-# Run duration
-#
-###############################################################################
-
-N_cycles 20
-
-##############################################################################
-#
-# System
-#
-##############################################################################
-
-size 32_32_1
-grid 1_1_1
-
-##############################################################################
-#
-# Fluid parameters
-#
-##############################################################################
-
-viscosity 0.16666666666667
-
-##############################################################################
-#
-# Free energy parameters
-#
-###############################################################################
-
-free_energy surfactant
-
-surf_A -0.0208333
-surf_B +0.0208333
-surf_kappa 0.12
-
-surf_kT 0.00056587
-surf_epsilon 0.03
-surf_beta 0.0
-surf_W 0.0
-
-surf_mobility_phi 0.15
-surf_mobility_psi 0.01
-
-phi_initialisation drop
-phi_init_drop_radius 8.0
-phi_init_drop_amplitude 1.0
-
-psi_initialisation uniform
-psi_initialisation_psi0 0.0001
-
-hydrodynamics yes
-fd_gradient_calculation 2d_tomita_fluid
-
-###############################################################################
-#
-# Colloid parameters
-#
-###############################################################################
-
-colloid_init no_colloids
-
-###############################################################################
-#
-# Periodic conditions / boundaries
-#
-###############################################################################
-
-periodicity 1_1_1
-
-###############################################################################
-#
-# Output frequency and type
-#
-###############################################################################
-
-freq_statistics 20
-config_at_end no
-
-###############################################################################
-#
-# Miscellaneous
-#
-# random_seed +ve integer is the random number generator seed
-#
-###############################################################################
-
-random_seed 8361235
diff --git a/tests/regression/d2q9/serial-surf-t02.log b/tests/regression/d2q9/serial-surf-t02.log
deleted file mode 100644
index 662ab5280..000000000
--- a/tests/regression/d2q9/serial-surf-t02.log
+++ /dev/null
@@ -1,132 +0,0 @@
-Welcome to Ludwig v0.9.2 (Serial version running on 1 process)
-
-Note assertions via standard C assert() are on.
-
-Read 27 user parameters from serial-surf-t02.inp
-
-System details
---------------
-System size: 32 32 1
-Decomposition: 1 1 1
-Local domain: 32 32 1
-Periodic: 1 1 1
-Halo nhalo: 2
-Reorder: true
-Initialised: 1
-
-Surfactant free energy
-----------------------
-Surfactant free energy parameters:
-Bulk parameter A = -2.08333e-02
-Bulk parameter B = 2.08333e-02
-Surface penalty kappa = 1.20000e-01
-Scale energy kT = 5.65870e-04
-Surface adsorption e = 3.00000e-02
-Surface psi^2 beta = 0.00000e+00
-Enthalpic term W = 0.00000e+00
-
-Derived quantities
-Interfacial tension = 4.71404e-02
-Interfacial width = 3.39412e+00
-Langmuir isotherm = 9.98442e+00
-
-Using Cahn-Hilliard solver:
-Number of fields = 2
-Mobility (phi) = 1.50000e-01
-Mobility (psi) = 1.00000e-02
-
-System properties
-----------------
-Mean fluid density: 1.00000e+00
-Shear viscosity 1.66667e-01
-Bulk viscosity 1.66667e-01
-Temperature 0.00000e+00
-External body force density 0.00000e+00 0.00000e+00 0.00000e+00
-External E-field amplitude 0.00000e+00 0.00000e+00 0.00000e+00
-External E-field frequency 0.00000e+00
-External magnetic field 0.00000e+00 0.00000e+00 0.00000e+00
-
-Lattice Boltzmann distributions
--------------------------------
-Model: d2q9
-SIMD vector len: 1
-Number of sets: 1
-Halo type: lb_halo_target (full halo)
-Input format: binary
-Output format: binary
-I/O grid: 1 1 1
-
-Lattice Boltzmann collision
----------------------------
-Relaxation time scheme: M10
-Hydrodynamic modes: on
-Ghost modes: on
-Isothermal fluctuations: off
-Shear relaxation time: 1.00000e+00
-Bulk relaxation time: 1.00000e+00
-Ghost relaxation time: 1.00000e+00
-[User ] Random number seed: 8361235
-
-Hydrodynamics
--------------
-Hydrodynamics: on
-
-Order parameter I/O
--------------------
-Order parameter I/O format:
-I/O decomposition: 1 1 1
-
-Advection scheme order: 1 (default)
-Initialising droplet radius: 8.0000000e+00
-Initialising droplet amplitude: 1.0000000e+00
-Initialising psi to a uniform value psi0
-Initial value psi0: 1.0000000e-04
-Gradient calculation: 2d_tomita_fluid
-Initial conditions.
-
-Scalars - total mean variance min max
-[rho] 1024.00 1.00000000000 1.1102230e-16 1.00000000000 1.00000000000
-[phi] 5.6597516e+02 5.5271012e-01 3.6411123e-01 -9.7620396e-01 9.9964006e-01
-[phi] 1.0240000e-01 1.0000000e-04-4.5825806e-22 1.0000000e-04 1.0000000e-04
-
-Momentum - x y z
-[total ] 1.4210855e-14 0.0000000e+00 0.0000000e+00
-[fluid ] 1.4210855e-14 0.0000000e+00 0.0000000e+00
-
-Starting time step loop.
-
-Scalars - total mean variance min max
-[rho] 1024.00 1.00000000000 3.3785405e-05 0.99310447271 1.01432330422
-[phi] 5.6597516e+02 5.5271012e-01 3.6204978e-01 -9.8526474e-01 9.9464016e-01
-[phi] 1.0240000e-01 1.0000000e-04 3.2331504e-10 7.4125189e-05 1.5362939e-04
-
-Free energy density - timestep total fluid
-[fed] 20 -2.9403928223e-03 -2.9403928223e-03
-
-Momentum - x y z
-[total ] 1.8093166e-14 6.4531713e-16 0.0000000e+00
-[fluid ] 1.8093166e-14 6.4531713e-16 0.0000000e+00
-
-Velocity - x y z
-[minimum ] -1.5015248e-03 -1.5015248e-03 0.0000000e+00
-[maximum ] 1.5015248e-03 1.5015248e-03 1.1754944e-38
-
-Completed cycle 20
-
-Timer resolution: 1e-06 second
-
-Timer statistics
- Section: tmin tmax total
- Total: 0.106 0.106 0.106 0.105538 (1 call)
- Time step loop: 0.005 0.006 0.103 0.005159 (20 calls)
- Propagation: 0.001 0.001 0.014 0.000701 (20 calls)
- Propagtn (krnl) : 0.001 0.001 0.014 0.000697 (20 calls)
- Collision: 0.001 0.002 0.028 0.001417 (20 calls)
- Collision (krnl) : 0.001 0.002 0.028 0.001413 (20 calls)
- Lattice halos: 0.000 0.001 0.008 0.000424 (20 calls)
- phi gradients: 0.000 0.001 0.010 0.000482 (20 calls)
- phi halos: 0.000 0.000 0.004 0.000219 (20 calls)
- BBL: 0.000 0.000 0.000 0.000001 (20 calls)
- Force calculation: 0.001 0.001 0.012 0.000621 (20 calls)
- phi update: 0.001 0.001 0.027 0.001369 (20 calls)
- Free1: 0.000 0.000 0.000 0.000020 (20 calls)
diff --git a/tests/regression/d3q15/Makefile b/tests/regression/d3q15/Makefile
index 3d3e09c58..3ac3de4db 100644
--- a/tests/regression/d3q15/Makefile
+++ b/tests/regression/d3q15/Makefile
@@ -15,19 +15,5 @@ serial:
@echo "TEST --> regression tests serial"
inputs='serial*inp'; \
for file in $$inputs; do ../../test.sh $$file "" ""; done
-
-mpix01:
- @echo "TEST --> regression tests mpi (1 mpi task)"
- inputs='serial*inp'; \
- for file in $$inputs; do ../../test.sh $$file "$(SER)" "$(PAR) 1"; done
-
-mpix08:
- @echo "TEST --> regression tests mpi (8 mpi tasks)"
- inputs='pmpi08*inp'; \
- for file in $$inputs; do ../../test.sh $$file "$(SER)" "$(PAR) 8"; done
-
-mpix64:
- @echo "TEST --> regression test mpi (64 mpi tasks)"
-
clean:
- rm -f *new test-diff*
+ rm -f *new test-diff* input
diff --git a/tests/regression/d3q15/pmpi08-auto-c01.inp b/tests/regression/d3q15/pmpi08-auto-c01.inp
deleted file mode 100644
index 508988376..000000000
--- a/tests/regression/d3q15/pmpi08-auto-c01.inp
+++ /dev/null
@@ -1,74 +0,0 @@
-##############################################################################
-#
-# Colloid velocity autocorrelation test (no noise).
-#
-##############################################################################
-
-N_cycles 40
-
-##############################################################################
-#
-# System and MPI
-#
-##############################################################################
-
-size 64_64_64
-grid 2_2_2
-
-
-##############################################################################
-#
-# Fluid parameters
-#
-##############################################################################
-
-free_energy none
-
-viscosity 0.1
-viscosity_bulk 0.1
-
-isothermal_fluctuations off
-temperature 0.00002133333
-
-###############################################################################
-#
-# Colloid parameters
-#
-###############################################################################
-
-colloid_init input_one
-
-colloid_one_a0 2.3
-colloid_one_ah 2.3
-colloid_one_r 32.0_32.0_32.0
-colloid_one_v 0.043478261_0.0_0.0
-
-colloid_gravity 0.0_0.0_0.0
-
-###############################################################################
-#
-# Periodic conditions / boundaries
-#
-###############################################################################
-
-boundary_walls_on no
-periodicity 1_1_1
-
-###############################################################################
-#
-# Output frequency and type
-#
-###############################################################################
-
-freq_statistics 40
-config_at_end no
-
-colloid_io_freq 1000
-
-###############################################################################
-#
-# Miscellaneous
-#
-###############################################################################
-
-random_seed 8361235
diff --git a/tests/regression/d3q15/pmpi08-auto-c01.log b/tests/regression/d3q15/pmpi08-auto-c01.log
deleted file mode 100644
index 708efcb03..000000000
--- a/tests/regression/d3q15/pmpi08-auto-c01.log
+++ /dev/null
@@ -1,130 +0,0 @@
-Welcome to Ludwig v0.4.6 (MPI version running on 8 processes)
-
-The SVN revision details are:
-Note assertions via standard C assert() are on.
-
-Read 21 user parameters from pmpi08-auto-c01.inp
-
-No free energy selected
-
-System details
---------------
-System size: 64 64 64
-Decomposition: 2 2 2
-Local domain: 32 32 32
-Periodic: 1 1 1
-Halo nhalo: 1
-Reorder: true
-Initialised: 1
-
-System properties
-----------------
-Mean fluid density: 1.00000e+00
-Shear viscosity 1.00000e-01
-Bulk viscosity 1.00000e-01
-Temperature 2.13333e-05
-External body force density 0.00000e+00 0.00000e+00 0.00000e+00
-External E-field amplitude 0.00000e+00 0.00000e+00 0.00000e+00
-External E-field frequency 0.00000e+00
-External magnetic field 0.00000e+00 0.00000e+00 0.00000e+00
-
-Lattice Boltzmann distributions
--------------------------------
-Model: d3q15 R
-SIMD vector len: 1
-Number of sets: 1
-Halo type: lb_halo_target (full halo)
-Input format: binary
-Output format: binary
-I/O grid: 1 1 1
-
-Lattice Boltzmann collision
----------------------------
-Hydrodynamic modes: on
-Ghost modes: on
-Isothermal fluctuations: off
-Shear relaxation time: 8.00000e-01
-Bulk relaxation time: 8.00000e-01
-Ghost relaxation time: 1.00000e+00
-[User ] Random number seed: 8361235
-
-Hydrodynamics
--------------
-Hydrodynamics: on
-
-Colloid information
--------------------
-
-Colloid I/O settings
---------------------
-Decomposition: 1 1 1
-Number of files: 1
-Input format: ascii
-Output format: ascii
-Single file read flag: 0
-
-Requested one colloid via input:
-colloid_one_a0 2.3000000e+00
-colloid_one_ah 2.3000000e+00
-colloid_one_r 3.2000000e+01 3.2000000e+01 3.2000000e+01
-colloid_one_v 4.3478261e-02 0.0000000e+00 0.0000000e+00
-
-Initialised 1 colloid
-
-Colloid cell list information
------------------------------
-Input radius maximum: 2.3000000e+00
-Final cell list: 11 11 11
-Final cell lengths: 2.9090909e+00 2.9090909e+00 2.9090909e+00
-
-Initial conditions.
-
-Scalars - total mean variance min max
-[rho] 262087.00 1.00000000000 0.0000000e+00 1.00000000000 1.00000000000
-
-Momentum - x y z
-[total ] 2.2158700e+00 0.0000000e+00 0.0000000e+00
-[fluid ] 3.6371878e-12 0.0000000e+00 0.0000000e+00
-[colloids] 2.2158700e+00 0.0000000e+00 0.0000000e+00
-
-Starting time step loop.
-
-Particle statistics:
-
-Colloid velocities - x y z
-[minimum ] 2.3053953e-03 -1.5394796e-17 -1.4571112e-17
-[maximum ] 2.3053953e-03 -1.5394796e-17 -1.4571112e-17
-
-Scalars - total mean variance min max
-[rho] 262091.00 1.00000000000 6.5697665e-09 0.99967393682 1.00032331163
-
-Momentum - x y z
-[total ] 2.2158700e+00 1.0323777e-14 -2.2451801e-14
-[fluid ] 2.0999793e+00 1.0991208e-14 -2.2037927e-14
-[colloids] 1.1589069e-01 -6.6743101e-16 -4.1387362e-16
-
-Velocity - x y z
-[minimum ] -1.8677558e-04 -5.3624238e-04 -5.3624238e-04
-[maximum ] 2.4256769e-03 5.3624238e-04 5.3624238e-04
-
-Completed cycle 40
-
-Timer resolution: 0.001 second
-
-Timer statistics
- Section: tmin tmax total
- Total: 2.544 2.544 2.544 2.543866 (1 call)
- Time step loop: 0.062 0.066 2.492 0.062306 (40 calls)
- Propagation: 0.001 0.002 0.050 0.001261 (40 calls)
- Collision: 0.049 0.053 1.981 0.049522 (40 calls)
- Collision (krnl) : 0.049 0.053 1.963 0.049066 (40 calls)
- Lattice halos: 0.003 0.007 0.284 0.003555 (80 calls)
- phi gradients: 0.000 0.000 0.000 0.000000 (40 calls)
- Forces: 0.000 0.000 0.001 0.000021 (40 calls)
- Rebuild: 0.001 0.001 0.046 0.001142 (40 calls)
- BBL: 0.001 0.001 0.029 0.000732 (40 calls)
- Particle halos: 0.000 0.001 0.007 0.000171 (40 calls)
- Force calculation: 0.000 0.000 0.000 0.000002 (40 calls)
- phi update: 0.000 0.000 0.000 0.000000 (40 calls)
- Free1: 0.000 0.000 0.000 0.000000 (80 calls)
-Ludwig finished normally.
diff --git a/tests/regression/d3q15/serial-le2d-lb1.log b/tests/regression/d3q15/serial-le2d-lb1.log
index e1eecc061..f1363144c 100644
--- a/tests/regression/d3q15/serial-le2d-lb1.log
+++ b/tests/regression/d3q15/serial-le2d-lb1.log
@@ -1,6 +1,5 @@
Welcome to Ludwig v0.7.33 (Serial version running on 1 process)
-The SVN revision details are: 3210M
Note assertions via standard C assert() are on.
Read 25 user parameters from serial-le2d-lb1.inp
@@ -86,6 +85,9 @@ Scalars - total mean variance min max
[rho] 4096.00 1.00000000000 0.0000000e+00 1.00000000000 1.00000000000
[phi] -1.1802440e-02 -2.8814551e-06 8.2680383e-04 -4.9977721e-02 4.9988335e-02
+Free energy density - timestep total fluid
+[fed] 0 -2.0247427840e-05 -2.0247427840e-05
+
Momentum - x y z
[total ] 1.7763568e-15 1.3322676e-15 0.0000000e+00
[fluid ] 1.7763568e-15 1.3322676e-15 0.0000000e+00
diff --git a/tests/regression/d3q19-elec/map-elec-gc2.001-001 b/tests/regression/d3q19-elec/map-elec-gc2.001-001
deleted file mode 100644
index 01b0aa2b0..000000000
Binary files a/tests/regression/d3q19-elec/map-elec-gc2.001-001 and /dev/null differ
diff --git a/tests/regression/d3q19-elec/psi-00000000.001-001 b/tests/regression/d3q19-elec/psi-00000000.001-001
deleted file mode 100644
index 5c07a3708..000000000
Binary files a/tests/regression/d3q19-elec/psi-00000000.001-001 and /dev/null differ
diff --git a/tests/regression/d3q19-elec/serial-elec-do1.inp b/tests/regression/d3q19-elec/serial-elec-do1.inp
index 263911c3a..5e15c8522 100644
--- a/tests/regression/d3q19-elec/serial-elec-do1.inp
+++ b/tests/regression/d3q19-elec/serial-elec-do1.inp
@@ -111,39 +111,12 @@ freq_measure 100000
freq_config 100000
config_at_end no
+psi_io_mode mpiio
+psi_io_report no
+
###############################################################################
#
-# Electrokinetics ALWAYS 2 SPECIES FOR NOW
-#
-# electrokinetics_z0 valency species 0 default +1
-# electrokinetics_z1 valency species 1 default -1
-# electrokinetics_d0 diffusivity 0 default 0.0
-# electrokinetics_d1 diffusivity 1 default 0.0
-# electrokinetics_eunit unit charge default +1.0
-# electrokinetics_epsilon permeativity (ref) default 0.0
-#
-# electrokinetics_init [gouy_chapman|liquid_junction|uniform]
-# electrokinetics_init_rho_el electrolyte concentration
-# electrokinetics_init_sigma surface charge density
-#
-# Also important:
-# temperature sets Boltzmann factor beta
-#
-# electrokinetics_rel_tol relative tolerance in Poisson solver
-# electrokinetics_abs_tol absolute tolerance in Poisson solver
-# electrokinetics_maxits maximal number of iteration steps
-# electrokinetics_diffacc diffusive accuracy in Nernst-Planck equation
-# This parameter controls the adaptation of the
-# number of multisteps: 0 < diffacc.
-# A value = 0 deactivates this feature.
-# electrokinetics_multisteps number of fractional LB timesteps in NPE
-#
-# fe_electrosymmetric has a number of additional coupling parameters
-# for the binary problem:
-#
-# electrosymmetric_epsilon2 additional permeativity to set contrast
-# electrosymmetric_delta_mu0 solvation free energy diff species 0
-# electrosymmetric_delta_mu1 solvation free energy diff species 1
+# Electrokinetics
#
###############################################################################
@@ -152,18 +125,20 @@ electrokinetics_z1 -1
electrokinetics_d0 0.1
electrokinetics_d1 0.1
electrokinetics_eunit 1.0
-electrokinetics_epsilon 300.0
-electrokinetics_init uniform
+electrokinetics_epsilon1 300.0
+electrokinetics_epsilon2 300.0
+electrokinetics_init uniform
electrokinetics_init_rho_el 0.00047
-electrokinetics_rel_tol 1e-06
-electrokinetics_abs_tol 1e-07
+electrokinetics_solver_type sor
+electrokinetics_solver_stencil 7
+electrokinetics_rel_tol 1e-10
+electrokinetics_abs_tol 1e-15
electrokinetics_maxits 10000
electrokinetics_diffacc 0.5
electrokinetics_multisteps 1
-electrosymmetric_epsilon2 300.0
electrosymmetric_delta_mu0 +4.0
electrosymmetric_delta_mu1 -4.0
diff --git a/tests/regression/d3q19-elec/serial-elec-do1.log b/tests/regression/d3q19-elec/serial-elec-do1.log
index 7dc44473c..e73f49a8f 100644
--- a/tests/regression/d3q19-elec/serial-elec-do1.log
+++ b/tests/regression/d3q19-elec/serial-elec-do1.log
@@ -46,14 +46,11 @@ Valency species 0: 1
Diffusivity species 0: 1.0000000e-01
Valency species 1: -1
Diffusivity species 1: 1.0000000e-01
-Number of multisteps: 1
-Number of skipsteps: 1
-Diffusive accuracy in NPE: 5.0000000e-01
Relative tolerance: 1.0000000e-06
Absolute tolerance: 1.0000000e-07
Max. no. of iterations: 10000
-I/O decomposition: 1 1 1
-I/O format: BINARY
+Number of multisteps: 1
+Diffusive accuracy in NPE: 5.0000000e-01
Coupling part
-------------
@@ -133,6 +130,9 @@ Scalars - total mean variance min max
[rho] 1.9251200e+00 4.7000000e-04 4.7000000e-04
[elc] 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energy density - timestep total fluid
+[fed] 0 -1.0518099887e-02 -1.0518099887e-02
+
Momentum - x y z
[total ] 0.0000000e+00 1.1368684e-13 0.0000000e+00
[fluid ] 0.0000000e+00 1.1368684e-13 0.0000000e+00
diff --git a/tests/regression/d3q19-elec/serial-elec-do2.inp b/tests/regression/d3q19-elec/serial-elec-do2.inp
index 5c24d8afb..592fcfeea 100644
--- a/tests/regression/d3q19-elec/serial-elec-do2.inp
+++ b/tests/regression/d3q19-elec/serial-elec-do2.inp
@@ -112,39 +112,12 @@ freq_measure 100000
freq_config 100000
config_at_end no
+psi_io_mode mpiio
+psi_io_report no
+
###############################################################################
#
-# Electrokinetics ALWAYS 2 SPECIES FOR NOW
-#
-# electrokinetics_z0 valency species 0 default +1
-# electrokinetics_z1 valency species 1 default -1
-# electrokinetics_d0 diffusivity 0 default 0.0
-# electrokinetics_d1 diffusivity 1 default 0.0
-# electrokinetics_eunit unit charge default +1.0
-# electrokinetics_epsilon permeativity (ref) default 0.0
-#
-# electrokinetics_init [gouy_chapman|liquid_junction|uniform]
-# electrokinetics_init_rho_el electrolyte concentration
-# electrokinetics_init_sigma surface charge density
-#
-# Also important:
-# temperature sets Boltzmann factor beta
-#
-# electrokinetics_rel_tol relative tolerance in Poisson solver
-# electrokinetics_abs_tol absolute tolerance in Poisson solver
-# electrokinetics_maxits maximal number of iteration steps
-# electrokinetics_diffacc diffusive accuracy in Nernst-Planck equation
-# This parameter controls the adaptation of the
-# number of multisteps: 0 < diffacc.
-# A value = 0 deactivates this feature.
-# electrokinetics_multisteps number of fractional LB timesteps in NPE
-#
-# fe_electrosymmetric has a number of additional coupling parameters
-# for the binary problem:
-#
-# electrosymmetric_epsilon2 additional permeativity to set contrast
-# electrosymmetric_delta_mu0 solvation free energy diff species 0
-# electrosymmetric_delta_mu1 solvation free energy diff species 1
+# Electrokinetics
#
###############################################################################
@@ -153,18 +126,18 @@ electrokinetics_z1 -1
electrokinetics_d0 0.1
electrokinetics_d1 0.1
electrokinetics_eunit 1.0
-electrokinetics_epsilon 300.0
+electrokinetics_epsilon1 300.0
+electrokinetics_epsilon2 300.0
electrokinetics_init uniform
electrokinetics_init_rho_el 0.00047
-electrokinetics_rel_tol 1e-06
-electrokinetics_abs_tol 1e-07
+electrokinetics_rel_tol 1e-10
+electrokinetics_abs_tol 1e-15
electrokinetics_maxits 10000
electrokinetics_diffacc 0.5
electrokinetics_multisteps 1
-electrosymmetric_epsilon2 300.0
electrosymmetric_delta_mu0 +4.0
electrosymmetric_delta_mu1 -4.0
diff --git a/tests/regression/d3q19-elec/serial-elec-do2.log b/tests/regression/d3q19-elec/serial-elec-do2.log
index f786c9299..32d386200 100644
--- a/tests/regression/d3q19-elec/serial-elec-do2.log
+++ b/tests/regression/d3q19-elec/serial-elec-do2.log
@@ -46,14 +46,12 @@ Valency species 0: 1
Diffusivity species 0: 1.0000000e-01
Valency species 1: -1
Diffusivity species 1: 1.0000000e-01
-Number of multisteps: 1
-Number of skipsteps: 1
-Diffusive accuracy in NPE: 5.0000000e-01
Relative tolerance: 1.0000000e-06
Absolute tolerance: 1.0000000e-07
Max. no. of iterations: 10000
-I/O decomposition: 1 1 1
-I/O format: BINARY
+Number of multisteps: 1
+Diffusive accuracy in NPE: 5.0000000e-01
+
Coupling part
-------------
@@ -133,6 +131,9 @@ Scalars - total mean variance min max
[rho] 1.9251200e+00 4.7000000e-04 4.7000000e-04
[elc] 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energy density - timestep total fluid
+[fed] 0 -1.0518099887e-02 -1.0518099887e-02
+
Momentum - x y z
[total ] 0.0000000e+00 1.1368684e-13 0.0000000e+00
[fluid ] 0.0000000e+00 1.1368684e-13 0.0000000e+00
diff --git a/tests/regression/d3q19-elec/serial-elec-do3.inp b/tests/regression/d3q19-elec/serial-elec-do3.inp
index 00e1a55df..759a2d035 100644
--- a/tests/regression/d3q19-elec/serial-elec-do3.inp
+++ b/tests/regression/d3q19-elec/serial-elec-do3.inp
@@ -1,6 +1,6 @@
##############################################################################
#
-# Donnan potential with dielectric contrast cf do1.
+# Donnan potential with solvation contrast cf do1.
#
##############################################################################
@@ -98,9 +98,12 @@ freq_measure 100000
freq_config 100000
config_at_end no
+psi_io_mode mpiio
+psi_io_report no
+
###############################################################################
#
-# Electrokinetics ALWAYS 2 SPECIES FOR NOW
+# Electrokinetics
#
###############################################################################
@@ -109,18 +112,18 @@ electrokinetics_z1 -1
electrokinetics_d0 0.1
electrokinetics_d1 0.1
electrokinetics_eunit 1.0
-electrokinetics_epsilon 300.0
+electrokinetics_epsilon1 300.0
+electrokinetics_epsilon2 300.0
electrokinetics_init uniform
electrokinetics_init_rho_el 0.00047
-electrokinetics_rel_tol 1e-06
-electrokinetics_abs_tol 1e-07
+electrokinetics_rel_tol 1e-09
+electrokinetics_abs_tol 1e-15
electrokinetics_maxits 10000
electrokinetics_diffacc 0.5
electrokinetics_multisteps 1
-electrosymmetric_epsilon2 300.0
electrosymmetric_delta_mu0 +5.0
electrosymmetric_delta_mu1 -3.0
diff --git a/tests/regression/d3q19-elec/serial-elec-do3.log b/tests/regression/d3q19-elec/serial-elec-do3.log
index c67762ca5..843a4c8cd 100644
--- a/tests/regression/d3q19-elec/serial-elec-do3.log
+++ b/tests/regression/d3q19-elec/serial-elec-do3.log
@@ -46,14 +46,11 @@ Valency species 0: 1
Diffusivity species 0: 1.0000000e-01
Valency species 1: -1
Diffusivity species 1: 1.0000000e-01
-Number of multisteps: 1
-Number of skipsteps: 1
-Diffusive accuracy in NPE: 5.0000000e-01
Relative tolerance: 1.0000000e-06
Absolute tolerance: 1.0000000e-07
Max. no. of iterations: 10000
-I/O decomposition: 1 1 1
-I/O format: BINARY
+Number of multisteps: 1
+Diffusive accuracy in NPE: 5.0000000e-01
Coupling part
-------------
@@ -133,6 +130,9 @@ Scalars - total mean variance min max
[rho] 1.9251200e+00 4.7000000e-04 4.7000000e-04
[elc] 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energy density - timestep total fluid
+[fed] 0 -1.0048099887e-02 -1.0048099887e-02
+
Momentum - x y z
[total ] 0.0000000e+00 1.1368684e-13 0.0000000e+00
[fluid ] 0.0000000e+00 1.1368684e-13 0.0000000e+00
diff --git a/tests/regression/d3q19-elec/serial-elec-dr1.inp b/tests/regression/d3q19-elec/serial-elec-dr1.inp
index e9475a3fc..a59545c93 100644
--- a/tests/regression/d3q19-elec/serial-elec-dr1.inp
+++ b/tests/regression/d3q19-elec/serial-elec-dr1.inp
@@ -114,39 +114,12 @@ freq_measure 10000000
freq_config 10000000
config_at_end no
+psi_io_mode mpiio
+psi_io_report no
+
###############################################################################
#
-# Electrokinetics ALWAYS 2 SPECIES FOR NOW
-#
-# electrokinetics_z0 valency species 0 default +1
-# electrokinetics_z1 valency species 1 default -1
-# electrokinetics_d0 diffusivity 0 default 0.0
-# electrokinetics_d1 diffusivity 1 default 0.0
-# electrokinetics_eunit unit charge default +1.0
-# electrokinetics_epsilon permeativity (ref) default 0.0
-#
-# electrokinetics_init [gouy_chapman|liquid_junction|uniform]
-# electrokinetics_init_rho_el electrolyte concentration
-# electrokinetics_init_sigma surface charge density
-#
-# Also important:
-# temperature sets Boltzmann factor beta
-#
-# electrokinetics_rel_tol relative tolerance in Poisson solver
-# electrokinetics_abs_tol absolute tolerance in Poisson solver
-# electrokinetics_maxits maximal number of iteration steps
-# electrokinetics_diffacc diffusive accuracy in Nernst-Planck equation
-# This parameter controls the adaptation of the
-# number of multisteps: 0 < diffacc.
-# A value = 0 deactivates this feature.
-# electrokinetics_multisteps number of fractional LB timesteps in NPE
-#
-# fe_electrosymmetric has a number of additional coupling parameters
-# for the binary problem:
-#
-# electrosymmetric_epsilon2 additional permeativity to set contrast
-# electrosymmetric_delta_mu0 solvation free energy diff species 0
-# electrosymmetric_delta_mu1 solvation free energy diff species 1
+# Electrokinetics
#
###############################################################################
@@ -155,7 +128,8 @@ electrokinetics_z1 -1
electrokinetics_d0 0.01
electrokinetics_d1 0.01
electrokinetics_eunit 0.5
-electrokinetics_epsilon 270.0
+electrokinetics_epsilon1 270.0
+electrokinetics_epsilon2 30.0
electrokinetics_init uniform
electrokinetics_init_rho_el 0.00
@@ -166,7 +140,6 @@ electrokinetics_diffacc 0.5
electrokinetics_multisteps 1
-electrosymmetric_epsilon2 30.0
electrosymmetric_delta_mu0 0.0
electrosymmetric_delta_mu1 0.0
diff --git a/tests/regression/d3q19-elec/serial-elec-dr1.log b/tests/regression/d3q19-elec/serial-elec-dr1.log
index 98f40d07b..67f9c76f2 100644
--- a/tests/regression/d3q19-elec/serial-elec-dr1.log
+++ b/tests/regression/d3q19-elec/serial-elec-dr1.log
@@ -46,14 +46,11 @@ Valency species 0: 1
Diffusivity species 0: 1.0000000e-02
Valency species 1: -1
Diffusivity species 1: 1.0000000e-02
-Number of multisteps: 1
-Number of skipsteps: 1
-Diffusive accuracy in NPE: 5.0000000e-01
Relative tolerance: 1.0000000e-06
Absolute tolerance: 1.0000000e-07
Max. no. of iterations: 2000
-I/O decomposition: 1 1 1
-I/O format: BINARY
+Number of multisteps: 1
+Diffusive accuracy in NPE: 5.0000000e-01
Coupling part
-------------
@@ -135,6 +132,9 @@ Scalars - total mean variance min max
[rho] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[elc] 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energy density - timestep total fluid
+[fed] 0 -2.0073826936e-04 -2.0073826936e-04
+
Momentum - x y z
[total ] 0.0000000e+00 2.2737368e-13 0.0000000e+00
[fluid ] 0.0000000e+00 2.2737368e-13 0.0000000e+00
diff --git a/tests/regression/d3q19-elec/serial-elec-dr2.inp b/tests/regression/d3q19-elec/serial-elec-dr2.inp
index a42050de1..918a772e4 100644
--- a/tests/regression/d3q19-elec/serial-elec-dr2.inp
+++ b/tests/regression/d3q19-elec/serial-elec-dr2.inp
@@ -115,39 +115,12 @@ freq_measure 10000000
freq_config 10000000
config_at_end no
+psi_io_mode mpiio
+psi_io_report no
+
###############################################################################
#
-# Electrokinetics ALWAYS 2 SPECIES FOR NOW
-#
-# electrokinetics_z0 valency species 0 default +1
-# electrokinetics_z1 valency species 1 default -1
-# electrokinetics_d0 diffusivity 0 default 0.0
-# electrokinetics_d1 diffusivity 1 default 0.0
-# electrokinetics_eunit unit charge default +1.0
-# electrokinetics_epsilon permeativity (ref) default 0.0
-#
-# electrokinetics_init [gouy_chapman|liquid_junction|uniform]
-# electrokinetics_init_rho_el electrolyte concentration
-# electrokinetics_init_sigma surface charge density
-#
-# Also important:
-# temperature sets Boltzmann factor beta
-#
-# electrokinetics_rel_tol relative tolerance in Poisson solver
-# electrokinetics_abs_tol absolute tolerance in Poisson solver
-# electrokinetics_maxits maximal number of iteration steps
-# electrokinetics_diffacc diffusive accuracy in Nernst-Planck equation
-# This parameter controls the adaptation of the
-# number of multisteps: 0 < diffacc.
-# A value = 0 deactivates this feature.
-# electrokinetics_multisteps number of fractional LB timesteps in NPE
-#
-# fe_electrosymmetric has a number of additional coupling parameters
-# for the binary problem:
-#
-# electrosymmetric_epsilon2 additional permeativity to set contrast
-# electrosymmetric_delta_mu0 solvation free energy diff species 0
-# electrosymmetric_delta_mu1 solvation free energy diff species 1
+# Electrokinetics
#
###############################################################################
@@ -156,7 +129,8 @@ electrokinetics_z1 -1
electrokinetics_d0 0.01
electrokinetics_d1 0.01
electrokinetics_eunit 0.5
-electrokinetics_epsilon 270.0
+electrokinetics_epsilon1 270.0
+electrokinetics_epsilon2 30.0
electrokinetics_init uniform
electrokinetics_init_rho_el 0.00
@@ -167,7 +141,6 @@ electrokinetics_diffacc 0.5
electrokinetics_multisteps 1
-electrosymmetric_epsilon2 30.0
electrosymmetric_delta_mu0 0.0
electrosymmetric_delta_mu1 0.0
diff --git a/tests/regression/d3q19-elec/serial-elec-dr2.log b/tests/regression/d3q19-elec/serial-elec-dr2.log
index 8abcb0788..7c0bf7e52 100644
--- a/tests/regression/d3q19-elec/serial-elec-dr2.log
+++ b/tests/regression/d3q19-elec/serial-elec-dr2.log
@@ -46,14 +46,11 @@ Valency species 0: 1
Diffusivity species 0: 1.0000000e-02
Valency species 1: -1
Diffusivity species 1: 1.0000000e-02
-Number of multisteps: 1
-Number of skipsteps: 1
-Diffusive accuracy in NPE: 5.0000000e-01
Relative tolerance: 1.0000000e-06
Absolute tolerance: 1.0000000e-07
Max. no. of iterations: 2000
-I/O decomposition: 1 1 1
-I/O format: BINARY
+Number of multisteps: 1
+Diffusive accuracy in NPE: 5.0000000e-01
Coupling part
-------------
@@ -135,6 +132,9 @@ Scalars - total mean variance min max
[rho] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[elc] 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energy density - timestep total fluid
+[fed] 0 -2.0073826936e-04 -2.0073826936e-04
+
Momentum - x y z
[total ] 0.0000000e+00 2.2737368e-13 0.0000000e+00
[fluid ] 0.0000000e+00 2.2737368e-13 0.0000000e+00
diff --git a/tests/regression/d3q19-elec/serial-elec-eo1.inp b/tests/regression/d3q19-elec/serial-elec-eo1.inp
deleted file mode 100644
index 3221cb63e..000000000
--- a/tests/regression/d3q19-elec/serial-elec-eo1.inp
+++ /dev/null
@@ -1,144 +0,0 @@
-##############################################################################
-#
-# Electro-osmotic flow
-#
-##############################################################################
-
-N_start 0
-N_cycles 1000
-
-##############################################################################
-#
-# System and MPI
-#
-##############################################################################
-
-size 64_2_2
-grid 8_1_1
-periodicity 0_1_1
-
-##############################################################################
-#
-# Fluid parameters
-#
-##############################################################################
-
-viscosity 0.1
-viscosity_bulk 0.1
-
-isothermal_fluctuations off
-temperature 3.3333e-5
-
-##############################################################################
-#
-# Uniform external fields
-#
-# magnetic_b0 Bx_By_Bz e.g., for dipoles (default zero)
-# electric_e0 Ex_Ey_Ez e.g., for electrokinetics (default zero)
-#
-##############################################################################
-
-magnetic_b0 0.0_0.0_0.0
-electric_e0 0.0_1.0e-6_0.0
-
-##############################################################################
-#
-# Free energy parameters
-#
-###############################################################################
-
-free_energy fe_electro
-fe_force_method phi_gradmu_correction
-
-fd_advection_scheme_order 3
-
-###############################################################################
-#
-# Colloid parameters
-#
-###############################################################################
-
-colloid_init none
-
-###############################################################################
-#
-# Walls / boundaries
-#
-###############################################################################
-
-boundary_walls 1_0_0
-boundary_speed_bottom 0.0
-boundary_speed_top 0.0
-boundary_lubrication_rcnormal 0.0
-
-###############################################################################
-#
-# Output frequency and type
-#
-###############################################################################
-
-freq_statistics 1000
-freq_measure 10000000
-freq_config 10000000
-freq_phi 10000000
-freq_psi 50000
-freq_vel 50000
-freq_shear_measurement 1000000
-freq_shear_output 1000000
-config_at_end no
-
-default_io_grid 1_1_1
-
-distribution_io_grid 1_1_1
-
-phi_io_grid 1_1_1
-phi_format ASCII
-psi_format ASCII
-vel_format ASCII
-
-stats_vel_print_vol_flux yes
-
-##############################################################################
-#
-# colloid i/o
-#
-##############################################################################
-
-colloid_io_freq 1000
-
-###############################################################################
-#
-# Electrokinetics ALWAYS 2 SPECIES FOR NOW
-#
-# electrokinetics_z0 valency species 0 default +1
-# electrokinetics_z1 valency species 1 default -1
-# electrokinetics_d0 diffusivity 0 default 0.0
-# electrokinetics_d1 diffusivity 1 default 0.0
-# electrokinetics_eunit unit charge default +1.0
-# electrokinetics_epsilon permeativity (ref) default 0.0
-#
-# Also important
-#
-# temperature sets Boltzmann factor beta
-#
-###############################################################################
-
-electrokinetics_z0 +1
-electrokinetics_z1 -1
-electrokinetics_d0 0.01
-electrokinetics_d1 0.01
-electrokinetics_eunit 1.0
-electrokinetics_epsilon 3300.0
-electrokinetics_init gouy_chapman
-electrokinetics_init_rho_el 0.00
-electrokinetics_init_sigma 0.0125
-
-###############################################################################
-#
-# Miscellaneous
-#
-# random_seed +ve integer is the random number generator seed
-#
-###############################################################################
-
-random_seed 8361235
diff --git a/tests/regression/d3q19-elec/serial-elec-eo1.log b/tests/regression/d3q19-elec/serial-elec-eo1.log
deleted file mode 100644
index bd4ed9ee6..000000000
--- a/tests/regression/d3q19-elec/serial-elec-eo1.log
+++ /dev/null
@@ -1,163 +0,0 @@
-Welcome to Ludwig v0.5.48 (Serial version running on 1 process)
-
-The SVN revision details are: 2982
-Note assertions via standard C assert() are on.
-
-Read 53 user parameters from serial-elec-eo1.inp
-
-System details
---------------
-System size: 64 2 2
-Decomposition: 1 1 1
-Local domain: 64 2 2
-Periodic: 0 1 1
-Halo nhalo: 1
-Reorder: true
-Initialised: 1
-
-Free energy details
--------------------
-
-Electrokinetics (single fluid) selected
-
-Parameters:
-Electrokinetic species: 2
-Boltzmann factor: 3.0000300e+04 (T = 3.3333000e-05)
-Unit charge: 1.0000000e+00
-Permittivity: 3.3000000e+03
-Bjerrum length: 7.2343879e-01
-Valency species 0: 1
-Diffusivity species 0: 1.0000000e-02
-Valency species 1: -1
-Diffusivity species 1: 1.0000000e-02
-Number of multisteps: 1
-Number of skipsteps: 1
-Diffusive accuracy in NPE: 0.0000000e+00
-Relative tolerance: 1.1920929e-07
-Absolute tolerance: 1.1920929e-09
-Max. no. of iterations: 10000
-I/O decomposition: 1 1 1
-I/O format: ASCII
-Force calculation: phi_gradmu_correction
-
-System properties
-----------------
-Mean fluid density: 1.00000e+00
-Shear viscosity 1.00000e-01
-Bulk viscosity 1.00000e-01
-Temperature 3.33330e-05
-External body force density 0.00000e+00 0.00000e+00 0.00000e+00
-External E-field amplitude 0.00000e+00 1.00000e-06 0.00000e+00
-External E-field frequency 0.00000e+00
-External magnetic field 0.00000e+00 0.00000e+00 0.00000e+00
-
-Lattice Boltzmann distributions
--------------------------------
-Model: d3q19
-SIMD vector len: 1
-Number of sets: 1
-Halo type: lb_halo_target (full halo)
-Input format: binary
-Output format: binary
-I/O grid: 1 1 1
-
-Lattice Boltzmann collision
----------------------------
-Hydrodynamic modes: on
-Ghost modes: on
-Isothermal fluctuations: off
-Shear relaxation time: 8.00000e-01
-Bulk relaxation time: 8.00000e-01
-Ghost relaxation time: 1.00000e+00
-[User ] Random number seed: 8361235
-
-Hydrodynamics
--------------
-Hydrodynamics: on
-
-Advection scheme order: 3
-
-Initial charge densities
-------------------------
-Initial conditions: Gouy Chapman
-Initial condition rho_el: 0.0000000e+00
-Debye length: inf
-Initial condition sigma: 1.2500000e-02
-
-Boundary walls
---------------
-Boundary walls: X - -
-Boundary speed u_x (bottom): 0.0000000e+00
-Boundary speed u_x (top): 0.0000000e+00
-Boundary normal lubrication rc: 0.0000000e+00
-Wall boundary links allocated: 40
-Memory (total, bytes): 640
-Boundary shear initialise: 0
-
-Porous Media
-------------
-Wall boundary links allocated: 40
-Memory (total, bytes): 640
-Arranging initial charge neutrality.
-
-Initial conditions.
-
-Scalars - total mean variance min max
-[rho] 248.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
-[psi] 0.0000000e+00 0.0000000e+00 0.0000000e+00
-[rho] 1.0000000e-01 0.0000000e+00 1.2500000e-02
-[rho] 1.0000000e-01 0.0000000e+00 4.0322581e-04
-[elc] -1.4224733e-16 -4.0322581e-04 1.2500000e-02
-
-Momentum - x y z
-[total ] 3.4416914e-15 0.0000000e+00 0.0000000e+00
-[fluid ] 3.4416914e-15 0.0000000e+00 0.0000000e+00
-[walls ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
-
-Starting time step loop.
-
-SOR solver converged to relative tolerance
-SOR residual per site 4.5083930e-11 at 235 iterations
-1 multisteps
-
-Scalars - total mean variance min max
-[rho] 248.00 1.00000000000 2.2204460e-16 0.99999997379 1.00000004969
-[psi] 1.9317881e-14 -6.0376531e-01 1.1609255e+00
-[rho] 1.0000000e-01 0.0000000e+00 1.2500000e-02
-[rho] 1.0000000e-01 0.0000000e+00 5.4240246e-04
-[elc] -1.7347235e-17 -5.4240246e-04 1.2500000e-02
-
-Free energies - timestep f v f/v f_s1 fs_s2
-[fe] 1000 -8.8100642125e-01 2.4800000000e+02 -3.5524452470e-03 0.0000000000e+00 0.0000000000e+00
-
-Momentum - x y z
-[total ] 3.0239700e-14 -3.3332436e-09 0.0000000e+00
-[fluid ] 5.5885852e-14 -2.4895684e-09 0.0000000e+00
-[walls ] -2.5646152e-14 -8.4367519e-10 0.0000000e+00
-
-Velocity - x y z
-[minimum ] -5.5809081e-09 -1.3023345e-11 0.0000000e+00
-[maximum ] 5.5809084e-09 1.1754944e-38 1.1754944e-38
-[vol flux] 5.5150329e-14 -2.4891785e-09 0.0000000e+00
-
-Completed cycle 1000
-
-Timer resolution: 1e-06 second
-
-Timer statistics
- Section: tmin tmax total
- Total: 17.781 17.781 17.781 17.781467 (1 call)
- Time step loop: 0.017 0.026 17.778 0.017778 (1000 calls)
- Propagation: 0.000 0.001 0.303 0.000303 (1000 calls)
- Propagtn (krnl) : 0.000 0.001 0.301 0.000301 (1000 calls)
- Collision: 0.001 0.001 0.544 0.000544 (1000 calls)
- Collision (krnl) : 0.001 0.001 0.543 0.000543 (1000 calls)
- Lattice halos: 0.000 0.001 0.445 0.000111 (4000 calls)
- phi gradients: 0.000 0.000 0.000 0.000000 (1000 calls)
- BBL: 0.000 0.000 0.006 0.000006 (1000 calls)
- Force calculation: 0.000 0.000 0.036 0.000018 (2000 calls)
- phi update: 0.000 0.000 0.000 0.000000 (1000 calls)
- Poisson equation: 0.015 0.023 15.906 0.015906 (1000 calls)
- Nernst Planck: 0.000 0.001 0.498 0.000498 (1000 calls)
- Free1: 0.000 0.001 0.001 0.000001 (1000 calls)
-Ludwig finished normally.
diff --git a/tests/regression/d3q19-elec/serial-elec-eo2.inp b/tests/regression/d3q19-elec/serial-elec-eo2.inp
deleted file mode 100644
index f1a8c541a..000000000
--- a/tests/regression/d3q19-elec/serial-elec-eo2.inp
+++ /dev/null
@@ -1,132 +0,0 @@
-##############################################################################
-#
-# Electro-osmotic flow
-#
-##############################################################################
-
-N_start 0
-N_cycles 100
-
-##############################################################################
-#
-# System and MPI
-#
-##############################################################################
-
-size 64_4_4
-grid 1_1_1
-periodicity 0_1_1
-
-##############################################################################
-#
-# Fluid parameters
-#
-##############################################################################
-
-viscosity 0.1
-viscosity_bulk 0.1
-
-isothermal_fluctuations off
-temperature 3.3333e-5
-
-##############################################################################
-#
-# External electric field
-#
-# electric_e0 Ex_Ey_Ez e.g., for electrokinetics (default zero)
-#
-##############################################################################
-
-electric_e0 0.0_3.0e-2_0.0
-
-##############################################################################
-#
-# Free energy parameters
-#
-###############################################################################
-
-free_energy fe_electro
-fe_force_method phi_gradmu_correction
-
-fd_advection_scheme_order 3
-
-
-###############################################################################
-#
-# Colloid parameters
-#
-###############################################################################
-
-colloid_init none
-
-###############################################################################
-#
-# Walls / boundaries
-#
-###############################################################################
-
-boundary_walls 1_0_0
-boundary_speed_bottom 0.0
-boundary_speed_top 0.0
-boundary_lubrication_rcnormal 0.0
-
-###############################################################################
-#
-# Output frequency and type
-#
-###############################################################################
-
-freq_statistics 100
-freq_measure 10000000
-config_at_end no
-
-default_io_grid 1_1_1
-
-distribution_io_grid 1_1_1
-
-stats_vel_print_vol_flux yes
-
-###############################################################################
-#
-# Electrokinetics ALWAYS 2 SPECIES FOR NOW
-#
-# electrokinetics_z0 valency species 0 default +1
-# electrokinetics_z1 valency species 1 default -1
-# electrokinetics_d0 diffusivity 0 default 0.0
-# electrokinetics_d1 diffusivity 1 default 0.0
-# electrokinetics_eunit unit charge default +1.0
-# electrokinetics_epsilon permeativity (ref) default 0.0
-#
-# Also important
-#
-# temperature sets Boltzmann factor beta
-#
-###############################################################################
-
-electrokinetics_z0 +1
-electrokinetics_z1 -1
-electrokinetics_d0 0.01
-electrokinetics_d1 0.01
-electrokinetics_eunit 1.0
-electrokinetics_epsilon 3300.0
-electrokinetics_init gouy_chapman
-electrokinetics_init_rho_el 0.00
-electrokinetics_init_sigma 0.0125
-
-electrokinetics_rel_tol 1e-07
-electrokinetics_abs_tol 1e-09
-electrokinetics_maxits 2000
-electrokinetics_diffacc 0.5
-
-electrokinetics_multisteps 1
-
-###############################################################################
-#
-# Miscellaneous
-#
-# random_seed +ve integer is the random number generator seed
-#
-###############################################################################
-
-#random_seed 7361237
-random_seed 8361235
diff --git a/tests/regression/d3q19-elec/serial-elec-eo2.log b/tests/regression/d3q19-elec/serial-elec-eo2.log
deleted file mode 100644
index cc29cd10f..000000000
--- a/tests/regression/d3q19-elec/serial-elec-eo2.log
+++ /dev/null
@@ -1,165 +0,0 @@
-Welcome to Ludwig v0.7.32 (Serial version running on 1 process)
-
-The SVN revision details are: 3209M
-Note assertions via standard C assert() are on.
-
-Read 46 user parameters from serial-elec-eo2.inp
-
-System details
---------------
-System size: 64 4 4
-Decomposition: 1 1 1
-Local domain: 64 4 4
-Periodic: 0 1 1
-Halo nhalo: 1
-Reorder: true
-Initialised: 1
-
-Free energy details
--------------------
-
-Electrokinetics (single fluid) selected
-
-Parameters:
-Electrokinetic species: 2
-Boltzmann factor: 3.0000300e+04 (T = 3.3333000e-05)
-Unit charge: 1.0000000e+00
-Permittivity: 3.3000000e+03
-Bjerrum length: 7.2343879e-01
-Valency species 0: 1
-Diffusivity species 0: 1.0000000e-02
-Valency species 1: -1
-Diffusivity species 1: 1.0000000e-02
-Number of multisteps: 1
-Number of skipsteps: 1
-Diffusive accuracy in NPE: 5.0000000e-01
-Relative tolerance: 1.0000000e-07
-Absolute tolerance: 1.0000000e-09
-Max. no. of iterations: 2000
-I/O decomposition: 1 1 1
-I/O format: BINARY
-Force calculation: phi_gradmu_correction
-
-System properties
-----------------
-Mean fluid density: 1.00000e+00
-Shear viscosity 1.00000e-01
-Bulk viscosity 1.00000e-01
-Temperature 3.33330e-05
-External body force density 0.00000e+00 0.00000e+00 0.00000e+00
-External E-field amplitude 0.00000e+00 3.00000e-02 0.00000e+00
-External E-field frequency 0.00000e+00
-External magnetic field 0.00000e+00 0.00000e+00 0.00000e+00
-
-Lattice Boltzmann distributions
--------------------------------
-Model: d3q19
-SIMD vector len: 1
-Number of sets: 1
-Halo type: lb_halo_target (full halo)
-Input format: binary
-Output format: binary
-I/O grid: 1 1 1
-
-Lattice Boltzmann collision
----------------------------
-Relaxation time scheme: M10
-Hydrodynamic modes: on
-Ghost modes: on
-Isothermal fluctuations: off
-Shear relaxation time: 8.00000e-01
-Bulk relaxation time: 8.00000e-01
-Ghost relaxation time: 1.00000e+00
-[User ] Random number seed: 8361235
-
-Hydrodynamics
--------------
-Hydrodynamics: on
-
-Advection scheme order: 3
-
-Initial charge densities
-------------------------
-Initial conditions: Gouy Chapman
-Initial condition rho_el: 0.0000000e+00
-Debye length: inf
-Initial condition sigma: 1.2500000e-02
-
-Boundary walls
---------------
-Boundary walls: X - -
-Boundary speed u_x (bottom): 0.0000000e+00
-Boundary speed u_x (top): 0.0000000e+00
-Boundary normal lubrication rc: 0.0000000e+00
-Wall boundary links allocated: 160
-Memory (total, bytes): 2560
-Boundary shear initialise: 0
-
-Porous Media
-------------
-Wall boundary links allocated: 160
-Memory (total, bytes): 2560
-
-Arranging initial charge neutrality.
-
-Initial conditions.
-
-Scalars - total mean variance min max
-[rho] 992.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
-[psi] 0.0000000e+00 0.0000000e+00 0.0000000e+00
-[rho] 4.0000000e-01 0.0000000e+00 1.2500000e-02
-[rho] 4.0000000e-01 0.0000000e+00 4.0322581e-04
-[elc] -1.0165480e-15 -4.0322581e-04 1.2500000e-02
-
-Momentum - x y z
-[total ] 1.3766766e-14 0.0000000e+00 0.0000000e+00
-[fluid ] 1.3766766e-14 0.0000000e+00 0.0000000e+00
-[walls ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
-
-Starting time step loop.
-
-SOR solver converged to relative tolerance
-SOR residual per site 5.9828809e-11 at 235 iterations
-1 multisteps
-
-Scalars - total mean variance min max
-[rho] 992.00 1.00000000000 6.3282712e-15 0.99999999731 1.00000001802
-[psi] 2.7511327e-13 -6.6776790e-01 1.2344090e+00
-[rho] 4.0000000e-01 0.0000000e+00 1.2500000e-02
-[rho] 4.0000000e-01 0.0000000e+00 4.3462600e-04
-[elc] -3.5145498e-15 -4.3462600e-04 1.2500000e-02
-
-Free energies - timestep f v f/v f_s1 fs_s2
-[fe] 100 -3.5194748004e+00 9.9200000000e+02 -3.5478576617e-03 0.0000000000e+00 0.0000000000e+00
-
-Momentum - x y z
-[total ] 2.0927704e-14 -3.9999600e-05 0.0000000e+00
-[fluid ] 3.0253577e-14 -3.6870184e-05 0.0000000e+00
-[walls ] -9.3258734e-15 -3.1294162e-06 0.0000000e+00
-
-Velocity - x y z
-[minimum ] -7.5708912e-09 -4.0048301e-08 0.0000000e+00
-[maximum ] 7.5708914e-09 1.1754944e-38 1.1754944e-38
-[vol flux] 2.9309890e-14 -3.6717137e-05 0.0000000e+00
-
-Completed cycle 100
-
-Timer resolution: 0.01 second
-
-Timer statistics
- Section: tmin tmax total
- Total: 3.038 3.038 3.038 3.038123 (1 call)
- Time step loop: 0.030 0.033 3.034 0.030344 (100 calls)
- Propagation: 0.001 0.001 0.057 0.000565 (100 calls)
- Propagtn (krnl) : 0.001 0.001 0.056 0.000564 (100 calls)
- Collision: 0.001 0.001 0.124 0.001240 (100 calls)
- Collision (krnl) : 0.001 0.001 0.124 0.001239 (100 calls)
- Lattice halos: 0.000 0.001 0.062 0.000156 (400 calls)
- phi gradients: 0.000 0.000 0.000 0.000000 (100 calls)
- BBL: 0.000 0.000 0.002 0.000023 (100 calls)
- Force calculation: 0.000 0.000 0.012 0.000062 (200 calls)
- phi update: 0.000 0.000 0.000 0.000000 (100 calls)
- Poisson equation: 0.026 0.029 2.615 0.026147 (100 calls)
- Nernst Planck: 0.002 0.002 0.153 0.001526 (100 calls)
- Free1: 0.000 0.001 0.001 0.000007 (100 calls)
-Ludwig finished normally.
diff --git a/tests/regression/d3q19-elec/serial-elec-ep1.inp b/tests/regression/d3q19-elec/serial-elec-ep1.inp
index bea800561..de7a9bd18 100644
--- a/tests/regression/d3q19-elec/serial-elec-ep1.inp
+++ b/tests/regression/d3q19-elec/serial-elec-ep1.inp
@@ -111,6 +111,9 @@ freq_statistics 100
freq_measure 10000000
config_at_end no
+psi_io_mode mpiio
+psi_io_report no
+
##############################################################################
#
# colloid i/o
@@ -124,37 +127,7 @@ colloid_io_format_output ASCII
###############################################################################
#
-# Electrokinetics ALWAYS 2 SPECIES FOR NOW
-#
-# electrokinetics_z0 valency species 0 default +1
-# electrokinetics_z1 valency species 1 default -1
-# electrokinetics_d0 diffusivity 0 default 0.0
-# electrokinetics_d1 diffusivity 1 default 0.0
-# electrokinetics_eunit unit charge default +1.0
-# electrokinetics_epsilon permeativity (ref) default 0.0
-#
-# electrokinetics_init [gouy_chapman|liquid_junction|uniform]
-# electrokinetics_init_rho_el electrolyte concentration
-# electrokinetics_init_sigma surface charge density
-#
-# Also important:
-# temperature sets Boltzmann factor beta
-#
-# electrokinetics_rel_tol relative tolerance in Poisson solver
-# electrokinetics_abs_tol absolute tolerance in Poisson solver
-# electrokinetics_maxits maximal number of iteration steps
-# electrokinetics_diffacc diffusive accuracy in Nernst-Planck equation
-# This parameter controls the adaptation of the
-# number of multisteps: 0 < diffacc.
-# A value = 0 deactivates this feature.
-# electrokinetics_multisteps number of fractional LB timesteps in NPE
-#
-# fe_electrosymmetric has a number of additional coupling parameters
-# for the binary problem:
-#
-# electrosymmetric_epsilon2 additional permeativity to set contrast
-# electrosymmetric_delta_mu0 solvation free energy diff species 0
-# electrosymmetric_delta_mu1 solvation free energy diff species 1
+# Electrokinetics
#
###############################################################################
@@ -167,13 +140,12 @@ electrokinetics_epsilon 100.0
electrokinetics_init uniform
electrokinetics_init_rho_el 0.00104
-electrokinetics_rel_tol 1e-07
+electrokinetics_rel_tol 1e-08
electrokinetics_abs_tol 1e-15
electrokinetics_maxits 5000
electrokinetics_diffacc 0.5
electrokinetics_multisteps 1
-electrokinetics_skipsteps 1
###############################################################################
#
diff --git a/tests/regression/d3q19-elec/serial-elec-ep1.log b/tests/regression/d3q19-elec/serial-elec-ep1.log
index f2eb0049a..10fabd17a 100644
--- a/tests/regression/d3q19-elec/serial-elec-ep1.log
+++ b/tests/regression/d3q19-elec/serial-elec-ep1.log
@@ -30,14 +30,11 @@ Valency species 0: 1
Diffusivity species 0: 1.0000000e-02
Valency species 1: -1
Diffusivity species 1: 1.0000000e-02
-Number of multisteps: 1
-Number of skipsteps: 1
-Diffusive accuracy in NPE: 5.0000000e-01
Relative tolerance: 1.0000000e-07
Absolute tolerance: 1.0000000e-15
Max. no. of iterations: 5000
-I/O decomposition: 1 1 1
-I/O format: BINARY
+Number of multisteps: 1
+Diffusive accuracy in NPE: 5.0000000e-01
Force calculation: stress_divergence
System properties
@@ -129,6 +126,9 @@ Scalars - total mean variance min max
[rho] 1.3381768e+02 0.0000000e+00 4.1153145e-03
[elc] -1.1347338e-11 -1.5376572e-03 1.9920319e-01
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 -1.1349791372e+03 3.2517000000e+04 -3.4904177422e-02 0.0000000000e+00
+
Momentum - x y z
[total ] 0.0000000e+00 9.0252805e-13 0.0000000e+00
[fluid ] 0.0000000e+00 9.0252805e-13 0.0000000e+00
diff --git a/tests/regression/d3q19-elec/serial-elec-ep2.inp b/tests/regression/d3q19-elec/serial-elec-ep2.inp
index bfae7fdf2..0a3b392f4 100644
--- a/tests/regression/d3q19-elec/serial-elec-ep2.inp
+++ b/tests/regression/d3q19-elec/serial-elec-ep2.inp
@@ -113,6 +113,9 @@ freq_statistics 100
freq_measure 10000000
config_at_end no
+psi_io_mode mpiio
+psi_io_report no
+
##############################################################################
#
# colloid i/o
@@ -126,37 +129,7 @@ colloid_io_format_output ASCII
###############################################################################
#
-# Electrokinetics ALWAYS 2 SPECIES FOR NOW
-#
-# electrokinetics_z0 valency species 0 default +1
-# electrokinetics_z1 valency species 1 default -1
-# electrokinetics_d0 diffusivity 0 default 0.0
-# electrokinetics_d1 diffusivity 1 default 0.0
-# electrokinetics_eunit unit charge default +1.0
-# electrokinetics_epsilon permeativity (ref) default 0.0
-#
-# electrokinetics_init [gouy_chapman|liquid_junction|uniform]
-# electrokinetics_init_rho_el electrolyte concentration
-# electrokinetics_init_sigma surface charge density
-#
-# Also important:
-# temperature sets Boltzmann factor beta
-#
-# electrokinetics_rel_tol relative tolerance in Poisson solver
-# electrokinetics_abs_tol absolute tolerance in Poisson solver
-# electrokinetics_maxits maximal number of iteration steps
-# electrokinetics_diffacc diffusive accuracy in Nernst-Planck equation
-# This parameter controls the adaptation of the
-# number of multisteps: 0 < diffacc.
-# A value = 0 deactivates this feature.
-# electrokinetics_multisteps number of fractional LB timesteps in NPE
-#
-# fe_electrosymmetric has a number of additional coupling parameters
-# for the binary problem:
-#
-# electrosymmetric_epsilon2 additional permeativity to set contrast
-# electrosymmetric_delta_mu0 solvation free energy diff species 0
-# electrosymmetric_delta_mu1 solvation free energy diff species 1
+# Electrokinetics
#
###############################################################################
@@ -169,13 +142,12 @@ electrokinetics_epsilon 100.0
electrokinetics_init uniform
electrokinetics_init_rho_el 0.00104
-electrokinetics_rel_tol 1e-07
+electrokinetics_rel_tol 1e-08
electrokinetics_abs_tol 1e-15
electrokinetics_maxits 5000
electrokinetics_diffacc 0.5
electrokinetics_multisteps 1
-electrokinetics_skipsteps 1
###############################################################################
#
diff --git a/tests/regression/d3q19-elec/serial-elec-ep2.log b/tests/regression/d3q19-elec/serial-elec-ep2.log
index 708519c9b..cf66c5c26 100644
--- a/tests/regression/d3q19-elec/serial-elec-ep2.log
+++ b/tests/regression/d3q19-elec/serial-elec-ep2.log
@@ -30,14 +30,11 @@ Valency species 0: 1
Diffusivity species 0: 1.0000000e-02
Valency species 1: -1
Diffusivity species 1: 1.0000000e-02
-Number of multisteps: 1
-Number of skipsteps: 1
-Diffusive accuracy in NPE: 5.0000000e-01
Relative tolerance: 1.0000000e-07
Absolute tolerance: 1.0000000e-15
Max. no. of iterations: 5000
-I/O decomposition: 1 1 1
-I/O format: BINARY
+Number of multisteps: 1
+Diffusive accuracy in NPE: 5.0000000e-01
Force calculation: phi_gradmu_correction
System properties
@@ -129,6 +126,9 @@ Scalars - total mean variance min max
[rho] 1.3381768e+02 0.0000000e+00 4.1153145e-03
[elc] -1.1347338e-11 -1.5376572e-03 1.9920319e-01
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 -1.1349791372e+03 3.2517000000e+04 -3.4904177422e-02 0.0000000000e+00
+
Momentum - x y z
[total ] 0.0000000e+00 9.0252805e-13 0.0000000e+00
[fluid ] 0.0000000e+00 9.0252805e-13 0.0000000e+00
diff --git a/tests/regression/d3q19-elec/serial-elec-gc1.log b/tests/regression/d3q19-elec/serial-elec-gc1.log
deleted file mode 100644
index da36116ea..000000000
--- a/tests/regression/d3q19-elec/serial-elec-gc1.log
+++ /dev/null
@@ -1,150 +0,0 @@
-Welcome to Ludwig v0.5.48 (Serial version running on 1 process)
-
-The SVN revision details are: 2982
-Note assertions via standard C assert() are on.
-
-Read 38 user parameters from serial-elec-gc1.inp
-
-System details
---------------
-System size: 64 4 4
-Decomposition: 1 1 1
-Local domain: 64 4 4
-Periodic: 1 1 1
-Halo nhalo: 1
-Reorder: true
-Initialised: 1
-
-Free energy details
--------------------
-
-Electrokinetics (single fluid) selected
-
-Parameters:
-Electrokinetic species: 2
-Boltzmann factor: 3.0000000e+04 (T = 3.3333333e-05)
-Unit charge: 1.0000000e+00
-Permittivity: 3.3000000e+03
-Bjerrum length: 7.2343156e-01
-Valency species 0: 1
-Diffusivity species 0: 1.0000000e-02
-Valency species 1: -1
-Diffusivity species 1: 1.0000000e-02
-Number of multisteps: 1
-Number of skipsteps: 1
-Diffusive accuracy in NPE: 0.0000000e+00
-Relative tolerance: 1.1920929e-07
-Absolute tolerance: 1.1920929e-09
-Max. no. of iterations: 10000
-I/O decomposition: 1 1 1
-I/O format: BINARY
-Force calculation: phi_gradmu_correction
-
-System properties
-----------------
-Mean fluid density: 1.00000e+00
-Shear viscosity 1.00000e-01
-Bulk viscosity 1.00000e-01
-Temperature 3.33333e-05
-External body force density 0.00000e+00 0.00000e+00 0.00000e+00
-External E-field amplitude 0.00000e+00 0.00000e+00 0.00000e+00
-External E-field frequency 0.00000e+00
-External magnetic field 0.00000e+00 0.00000e+00 0.00000e+00
-
-Lattice Boltzmann distributions
--------------------------------
-Model: d3q19
-SIMD vector len: 1
-Number of sets: 1
-Halo type: lb_halo_openmp_reduced (host)
-Input format: binary
-Output format: binary
-I/O grid: 1 1 1
-
-Lattice Boltzmann collision
----------------------------
-Hydrodynamic modes: on
-Ghost modes: on
-Isothermal fluctuations: off
-Shear relaxation time: 8.00000e-01
-Bulk relaxation time: 8.00000e-01
-Ghost relaxation time: 1.00000e+00
-[User ] Random number seed: 8361235
-
-Hydrodynamics
--------------
-Hydrodynamics: on
-
-Advection scheme order: 3
-
-Initial charge densities
-------------------------
-Initial conditions: Gouy Chapman
-Initial condition rho_el: 1.0000000e-03
-Debye length: 7.4161985e+00
-Initial condition sigma: 3.1250000e-02
-
-Porous Media
-------------
-Wall boundary links allocated: 160
-Memory (total, bytes): 2560
-Arranging initial charge neutrality.
-
-Initial conditions.
-
-Scalars - total mean variance min max
-[rho] 992.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
-[psi] 0.0000000e+00 0.0000000e+00 0.0000000e+00
-[rho] 1.9920000e+00 1.0000000e-03 3.1250000e-02
-[rho] 1.9920000e+00 0.0000000e+00 2.0080645e-03
-[elc] -1.2878587e-14 -1.0080645e-03 3.1250000e-02
-
-Momentum - x y z
-[total ] 1.3766766e-14 0.0000000e+00 0.0000000e+00
-[fluid ] 1.3766766e-14 0.0000000e+00 0.0000000e+00
-[walls ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
-
-Starting time step loop.
-1 multisteps
-
-Scalars - total mean variance min max
-[rho] 992.00 1.00000000000 3.8857806e-15 0.99999987748 1.00000032642
-[psi] -6.3948846e-14 -1.2074611e+00 2.4452182e+00
-[rho] 1.9920000e+00 4.5245968e-04 3.1250000e-02
-[rho] 1.9920000e+00 0.0000000e+00 3.8175240e-03
-[elc] -7.7715612e-16 -3.3650643e-03 3.1250000e-02
-
-Free energy density - timestep total fluid
-[fed] 1000 -2.4980173368e-02 -2.2516704343e-02
-
-Momentum - x y z
-[total ] 5.9174887e-14 -6.6613381e-16 0.0000000e+00
-[fluid ] -3.5416114e-13 -6.6613381e-16 0.0000000e+00
-[walls ] 4.1333603e-13 0.0000000e+00 0.0000000e+00
-
-Velocity - x y z
-[minimum ] -3.4523433e-08 -6.9388947e-18 0.0000000e+00
-[maximum ] 3.4523432e-08 6.9388945e-18 1.1754944e-38
-[vol flux] -3.5393913e-13 -8.3266727e-16 0.0000000e+00
-
-Completed cycle 1000
-
-Timer resolution: 1e-06 second
-
-Timer statistics
- Section: tmin tmax total
- Total: 34.975 34.975 34.975 34.974571 (1 call)
- Time step loop: 0.032 0.047 34.970 0.034970 (1000 calls)
- Propagation: 0.001 0.002 0.702 0.000702 (1000 calls)
- Propagtn (krnl) : 0.001 0.002 0.700 0.000700 (1000 calls)
- Collision: 0.001 0.002 1.261 0.001261 (1000 calls)
- Collision (krnl) : 0.001 0.002 1.258 0.001258 (1000 calls)
- Lattice halos: 0.000 0.001 0.761 0.000190 (4000 calls)
- phi gradients: 0.000 0.000 0.001 0.000001 (1000 calls)
- BBL: 0.000 0.000 0.023 0.000023 (1000 calls)
- Force calculation: 0.000 0.000 0.151 0.000075 (2000 calls)
- phi update: 0.000 0.000 0.000 0.000000 (1000 calls)
- Poisson equation: 0.028 0.041 30.327 0.030327 (1000 calls)
- Nernst Planck: 0.001 0.003 1.647 0.001647 (1000 calls)
- Free1: 0.000 0.001 0.002 0.000002 (1000 calls)
-Ludwig finished normally.
diff --git a/tests/regression/d3q19-elec/serial-elec-gc2.inp b/tests/regression/d3q19-elec/serial-elec-gc2.inp
deleted file mode 100644
index 3b86e9416..000000000
--- a/tests/regression/d3q19-elec/serial-elec-gc2.inp
+++ /dev/null
@@ -1,120 +0,0 @@
-##############################################################################
-#
-# Gouy-Chapman electrokinetics
-#
-# As serial-elec-gc1.inp, but initial conditions taken from file:
-# psi-00000000.001-001
-# map-elec-gc2.001-001
-#
-# Also fewer time steps.
-#
-##############################################################################
-
-##############################################################################
-#
-# Run duration
-#
-###############################################################################
-
-N_start 0
-N_cycles 100
-
-##############################################################################
-#
-# System and MPI
-#
-##############################################################################
-
-size 64_4_4
-grid 1_1_2
-periodicity 1_1_1
-lb_halo_scheme lb_halo_openmp_reduced
-
-##############################################################################
-#
-# Fluid parameters
-#
-##############################################################################
-
-viscosity 0.1
-viscosity_bulk 0.1
-
-isothermal_fluctuations off
-temperature 3.33333333333333333e-5
-
-
-##############################################################################
-#
-# Free energy parameters
-#
-###############################################################################
-
-free_energy fe_electro
-fe_force_method phi_gradmu_correction
-
-fd_advection_scheme_order 3
-
-###############################################################################
-#
-# Colloid parameters
-#
-###############################################################################
-
-colloid_init none
-
-###############################################################################
-#
-# Walls / boundaries
-#
-###############################################################################
-
-porous_media_file yes
-porous_media_ndata 0
-porous_media_format binary
-
-###############################################################################
-#
-# Output frequency and type
-#
-###############################################################################
-
-freq_statistics 100
-freq_psi_resid 10000
-config_at_end no
-
-colloid_io_freq 1000
-
-stats_vel_print_vol_flux yes
-
-###############################################################################
-#
-# Electrokinetics ALWAYS 2 SPECIES FOR NOW
-#
-# electrokinetics_z0 valency species 0 default +1
-# electrokinetics_z1 valency species 1 default -1
-# electrokinetics_d0 diffusivity 0 default 0.0
-# electrokinetics_d1 diffusivity 1 default 0.0
-# electrokinetics_eunit unit charge default +1.0
-# electrokinetics_epsilon permeativity (ref) default 0.0
-#
-# Also important
-#
-# temperature sets Boltzmann factor beta
-#
-###############################################################################
-
-electrokinetics_z0 +1
-electrokinetics_z1 -1
-electrokinetics_d0 0.01
-electrokinetics_d1 0.01
-electrokinetics_eunit 1.0
-electrokinetics_epsilon 3.3e3
-electrokinetics_init from_file
-
-###############################################################################
-#
-# Miscellaneous
-#
-###############################################################################
-
-random_seed 8361235
diff --git a/tests/regression/d3q19-elec/serial-rest-ec1.inp b/tests/regression/d3q19-elec/serial-rest-ec1.inp
index 8658d52e6..839080032 100644
--- a/tests/regression/d3q19-elec/serial-rest-ec1.inp
+++ b/tests/regression/d3q19-elec/serial-rest-ec1.inp
@@ -73,9 +73,20 @@ electrokinetics_d0 0.01
electrokinetics_d1 0.01
electrokinetics_eunit 1.0
electrokinetics_epsilon 3.3e3
+
+electrokinetics_rel_tol 1e-09
+electrokinetics_abs_tol 1e-15
+electrokinetics_maxits 2000
+
+
electrokinetics_init uniform
electrokinetics_init_rho_el 0.001
+# Now mandatory to use mpiio for electrokinetics
+
+psi_io_mode mpiio
+psi_io_report no
+
###############################################################################
#
# Miscellaneous
diff --git a/tests/regression/d3q19-elec/serial-rest-ec1.log b/tests/regression/d3q19-elec/serial-rest-ec1.log
index 685b61162..679e88e14 100644
--- a/tests/regression/d3q19-elec/serial-rest-ec1.log
+++ b/tests/regression/d3q19-elec/serial-rest-ec1.log
@@ -30,14 +30,11 @@ Valency species 0: 1
Diffusivity species 0: 1.0000000e-02
Valency species 1: -1
Diffusivity species 1: 1.0000000e-02
-Number of multisteps: 1
-Number of skipsteps: 1
-Diffusive accuracy in NPE: 0.0000000e+00
Relative tolerance: 1.1920929e-07
Absolute tolerance: 1.1920929e-09
Max. no. of iterations: 10000
-I/O decomposition: 1 1 1
-I/O format: BINARY
+Number of multisteps: 1
+Diffusive accuracy in NPE: 0.0000000e+00
Force calculation: phi_gradmu_correction
System properties
@@ -125,6 +122,10 @@ Scalars - total mean variance min max
[rho] 3.2726000e+01 1.9230769e-04 1.0000000e-03
[rho] 3.2726000e+01 0.0000000e+00 1.0003057e-03
[elc] -1.4922959e-15 -3.0566084e-07 1.9230769e-04
+[psi_zeta] 0.0000000e+00
+
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 -5.1748931944e+02 3.2716000000e+04 -1.5817621942e-02 0.0000000000e+00
Momentum - x y z
[total ] 4.5402571e-13 0.0000000e+00 5.0965010e-01
@@ -142,6 +143,13 @@ Colloid velocities - x y z
SOR solver converged to relative tolerance
SOR residual per site 3.8552497e-12 at 100 iterations
1 multisteps
+Writing distribution output at step 20!
+Writing colloid output at step 20!
+
+colloid_io_write:
+writing colloid information to config.cds00000020.001-001 etc
+Writing psi file at step 20!
+Writing rho/velocity output at step 20!
Scalars - total mean variance min max
[rho] 32715.00 1.00000000000 5.7030058e-09 0.99976080725 1.00025312238
@@ -165,11 +173,6 @@ Velocity - x y z
Completed cycle 20
-colloid_io_write:
-writing colloid information to config.cds00000020.001-001 etc
-Writing velocity output at step 20!
-Writing psi file at step 20!
-
Timer resolution: 0.01 second
Timer statistics
diff --git a/tests/regression/d3q19-elec/serial-rest-ec2.inp b/tests/regression/d3q19-elec/serial-rest-ec2.inp
index b2949427b..79f112726 100644
--- a/tests/regression/d3q19-elec/serial-rest-ec2.inp
+++ b/tests/regression/d3q19-elec/serial-rest-ec2.inp
@@ -60,9 +60,17 @@ electrokinetics_d0 0.01
electrokinetics_d1 0.01
electrokinetics_eunit 1.0
electrokinetics_epsilon 3.3e3
+
+electrokinetics_rel_tol 1e-09
+electrokinetics_abs_tol 1e-15
+electrokinetics_maxits 2000
+
electrokinetics_init uniform
electrokinetics_init_rho_el 0.001
+psi_io_mode mpiio
+psi_io_report no
+
###############################################################################
#
# Miscellaneous
diff --git a/tests/regression/d3q19-elec/serial-rest-ec2.log b/tests/regression/d3q19-elec/serial-rest-ec2.log
index 2f77527ef..a758c1178 100644
--- a/tests/regression/d3q19-elec/serial-rest-ec2.log
+++ b/tests/regression/d3q19-elec/serial-rest-ec2.log
@@ -30,14 +30,11 @@ Valency species 0: 1
Diffusivity species 0: 1.0000000e-02
Valency species 1: -1
Diffusivity species 1: 1.0000000e-02
-Number of multisteps: 1
-Number of skipsteps: 1
-Diffusive accuracy in NPE: 0.0000000e+00
Relative tolerance: 1.1920929e-07
Absolute tolerance: 1.1920929e-09
Max. no. of iterations: 10000
-I/O decomposition: 1 1 1
-I/O format: BINARY
+Number of multisteps: 1
+Diffusive accuracy in NPE: 0.0000000e+00
Force calculation: phi_gradmu_correction
System properties
@@ -106,10 +103,10 @@ Input radius maximum: 2.3000000e+00
Final cell list: 11 11 11
Final cell lengths: 2.9090909e+00 2.9090909e+00 2.9090909e+00
-Re-starting simulation at step 20 with data read from config
-file(s) dist-00000020
-hydro files(s) vel-00000020
-electrokinetics files(s) psi-00000020
+Re-starting simulation at step 20 with data read from file
+Reading distribution files for step 20
+Reading rho/vel files for step 20
+Reading electrokinetics files for step 20
Initial conditions.
Scalars - total mean variance min max
@@ -118,6 +115,10 @@ Scalars - total mean variance min max
[rho] 3.2726000e+01 1.8867925e-04 1.0413963e-03
[rho] 3.2726000e+01 0.0000000e+00 1.0436820e-03
[elc] 2.4008573e-15 -2.2857042e-06 1.8867925e-04
+[psi_zeta] 8.2502980e-03
+
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 20 -5.1748728127e+02 3.2715000000e+04 -1.5818043138e-02 0.0000000000e+00
Momentum - x y z
[total ] 4.4153432e-13 1.9531615e-14 5.0965010e-01
diff --git a/tests/regression/d3q19-mpi-extra/Makefile b/tests/regression/d3q19-mpi-extra/Makefile
deleted file mode 100644
index 4652d144c..000000000
--- a/tests/regression/d3q19-mpi-extra/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-###############################################################################
-#
-# Makefile
-#
-# D3Q19 extra MPI regression tests
-#
-###############################################################################
-
-include ../../../Makefile.mk
-
-MPIRUN_NTASKS=8
-
-SER=${LAUNCH_SERIAL_CMD}
-PAR=${LAUNCH_MPIRUN_CMD} ${MPIRUN_NTASK_FLAG} ${MPIRUN_NTASKS} ${MPIRUN_EXTRA}
-
-default:
- @echo "TEST --> regression d3q19-mpi-short"
- inputs='*inp'; \
- for file in $$inputs; do ../../test.sh $$file "$(SER)" "${PAR}"; done
-
-clean:
- rm -f *new test-diff*
diff --git a/tests/regression/d3q19-mpi-extra/parallel-auto-c01.inp b/tests/regression/d3q19-mpi-extra/parallel-auto-c01.inp
deleted file mode 100644
index c9870e2d8..000000000
--- a/tests/regression/d3q19-mpi-extra/parallel-auto-c01.inp
+++ /dev/null
@@ -1,179 +0,0 @@
-##############################################################################
-#
-# Colloid velocity autocorrelation test (no noise).
-#
-##############################################################################
-
-##############################################################################
-#
-# Run duration
-#
-# N_start If N_start > 0, this is a restart from previous output
-#
-# N_cycles number of lattice Boltzmann time steps to run
-# (if it's a restart, this is still the number of steps
-# to run, not the final step)
-#
-###############################################################################
-
-N_start 0
-N_cycles 40
-
-##############################################################################
-#
-# System and MPI
-#
-# size NX_NY_NZ is the size of the system in lattice units
-# grid PX_PY_PZ is the processor decomposition
-# If PX*PY*PZ is not equal to the number of processors,
-# MPI will choose a default (may be implementation-dependent).
-#
-# reduced_halo [yes|no] use reduced or full halos. Using reduced halos
-# is *only* appropriate for fluid only problems.
-# Default is no.
-#
-##############################################################################
-
-size 64_64_64
-reduced_halo no
-
-##############################################################################
-#
-# Fluid parameters
-#
-# viscosity shear viscosity [default is 1/6, ie., relaxation time 1]
-# viscosity_bulk bulk viscosity [default = shear viscosity]
-#
-# isothermal_fluctuations [on|off] Default is off.
-# temperature isothermal fluctuation 'temperature'
-#
-# ghost_modes [on|off] Default is on.
-# force FX_FY_FZ Uniform body force on fluid (default zero)
-#
-##############################################################################
-
-free_energy none
-
-viscosity 0.1
-viscosity_bulk 0.1
-
-isothermal_fluctuations off
-temperature 0.00002133333
-
-###############################################################################
-#
-# Colloid parameters
-#
-###############################################################################
-
-colloid_init input_one
-
-colloid_one_a0 2.3
-colloid_one_ah 2.3
-colloid_one_r 64.0_64.0_32.0
-colloid_one_v 0.043478261_0.0_0.0
-colloid_one_w 0.0_0.0_0.0
-colloid_one_s 1.0_0.0_0.0
-
-
-# Constant body force on all colloids ("gravity") [default is zero]
-# Uniform magnetic field [default is zero]
-
-colloid_gravity 0.0_0.0_0.0
-magnetic_b0 0.0_0.0_0.0
-
-###############################################################################
-#
-# Periodic conditions / boundaries
-#
-# boundary_walls_on [yes|no] Use built-in side walls [default no]
-# periodicity X_Y_Z Sets periodic boundary conditions in coordinate
-# directions [default is 1_1_1]. Best to leave this
-# unchanged
-# boundary_speed_top For use with built-in walls
-# boundary_speed_bottom For use with built-in walls
-#
-# porous_media_file filestub If present, the file filestub.001-001
-# should contain porous media data
-# porous_media_format [ASCII|BINARY] file format [default BINARY]
-# porous_media_type [status_only|status_with_h]
-# determines type of porous media data to be
-# supplied
-#
-###############################################################################
-
-boundary_walls_on no
-periodicity 1_1_1
-boundary_speed_bottom 0.0
-boundary_speed_top 0.0
-
-###############################################################################
-#
-# Output frequency and type
-#
-# freq_statistics N Output diagnostics every N steps
-# freq_output N Output field state every N steps
-# freq_config N Output full configuration (for restart) every
-# N steps (can be large!)
-# freq_phi N phi data output frequency
-# freq_vel N velocity data output frequency
-# freq_shear_measurement stress profile accumulator
-# freq_shear_output stress profile output
-# config_at_end [yes|no] write full configuration at end of run
-# [default is yes]
-#
-# io_grid NX_NY_NZ Cartesian processor I/O grid. Default is 1_1_1
-# The following for particle data are under review...
-# n_io_nodes Number of I/O processors for particles
-# output_format [ASCII|BINARY] default output format
-# input_format [ASCII|BINARY] default input format
-#
-# phi_format Override default format for particular quantities
-# etc... (both input and output)
-#
-###############################################################################
-
-freq_statistics 40
-freq_measure 200000
-freq_config 5000000
-freq_phi 100000
-freq_vel 100000
-freq_shear_measurement 100000
-freq_shear_output 100000
-config_at_end no
-
-distribution_io_grid 1_1_1
-
-phi_format ASCII
-vel_format ASCII
-
-##############################################################################
-#
-# colloid i/o
-#
-# colloid_io_freq currently set to freq_measure internally
-# colloid_io_grid currently set to 1_1_1 internally
-# colloid_io_format_input ASCII ASCII_SERIAL BINARY BINARY_SERIAL
-# colloid_io_format_output ASCII BINARY
-#
-# Note that the output is always parallel. A SERIAL input file must
-# be a single serial file.
-#
-##############################################################################
-
-colloid_io_freq 1000
-colloids_io_grid 1_1_1
-colloid_io_format_input BINARY
-colloid_io_format_output BINARY
-
-qs_dir_format BINARY
-
-###############################################################################
-#
-# Miscellaneous
-#
-# random_seed +ve integer is the random number generator seed
-#
-###############################################################################
-
-random_seed 8361235
diff --git a/tests/regression/d3q19-mpi-extra/parallel-auto-c01.log b/tests/regression/d3q19-mpi-extra/parallel-auto-c01.log
deleted file mode 100644
index b1a354e36..000000000
--- a/tests/regression/d3q19-mpi-extra/parallel-auto-c01.log
+++ /dev/null
@@ -1,134 +0,0 @@
-Welcome to Ludwig v0.7.33 (MPI version running on 8 processes)
-
-The SVN revision details are: 3210M
-Note assertions via standard C assert() are on.
-
-Read 39 user parameters from pmpi08-auto-c01.inp
-
-No free energy selected
-
-System details
---------------
-System size: 64 64 64
-Decomposition: 2 2 2
-Local domain: 32 32 32
-Periodic: 1 1 1
-Halo nhalo: 1
-Reorder: true
-Initialised: 1
-
-System properties
-----------------
-Mean fluid density: 1.00000e+00
-Shear viscosity 1.00000e-01
-Bulk viscosity 1.00000e-01
-Temperature 2.13333e-05
-External body force density 0.00000e+00 0.00000e+00 0.00000e+00
-External E-field amplitude 0.00000e+00 0.00000e+00 0.00000e+00
-External E-field frequency 0.00000e+00
-External magnetic field 0.00000e+00 0.00000e+00 0.00000e+00
-
-Lattice Boltzmann distributions
--------------------------------
-Model: d3q19
-SIMD vector len: 1
-Number of sets: 1
-Halo type: full
-Input format: binary
-Output format: binary
-I/O grid: 1 1 1
-
-Lattice Boltzmann collision
----------------------------
-Relaxation time scheme: M10
-Hydrodynamic modes: on
-Ghost modes: on
-Isothermal fluctuations: off
-Shear relaxation time: 8.00000e-01
-Bulk relaxation time: 8.00000e-01
-Ghost relaxation time: 1.00000e+00
-[User ] Random number seed: 8361235
-
-Hydrodynamics
--------------
-Hydrodynamics: on
-
-Colloid information
--------------------
-
-Colloid I/O settings
---------------------
-Decomposition: 1 1 1
-Number of files: 1
-Input format: binary
-Output format: binary
-Single file read flag: 0
-
-Requested one colloid via input:
-colloid_one_a0 2.3000000e+00
-colloid_one_ah 2.3000000e+00
-colloid_one_r 6.4000000e+01 6.4000000e+01 3.2000000e+01
-colloid_one_v 4.3478261e-02 0.0000000e+00 0.0000000e+00
-colloid_one_w 0.0000000e+00 0.0000000e+00 0.0000000e+00
-colloid_one_s 1.0000000e+00 0.0000000e+00 0.0000000e+00
-
-Initialised 1 colloid
-
-Colloid cell list information
------------------------------
-Input radius maximum: 2.3000000e+00
-Final cell list: 11 11 11
-Final cell lengths: 2.9090909e+00 2.9090909e+00 2.9090909e+00
-
-Initial conditions.
-
-Scalars - total mean variance min max
-[rho] 262087.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
-
-Momentum - x y z
-[total ] 2.2158700e+00 0.0000000e+00 0.0000000e+00
-[fluid ] 3.6371878e-12 0.0000000e+00 0.0000000e+00
-[colloids] 2.2158700e+00 0.0000000e+00 0.0000000e+00
-
-Starting time step loop.
-
-Particle statistics:
-
-Colloid velocities - x y z
-[minimum ] 2.2940581e-03 5.4917032e-18 -2.4809345e-17
-[maximum ] 2.2940581e-03 5.4917032e-18 -2.4809345e-17
-
-Scalars - total mean variance min max
-[rho] 262091.00 1.00000000000 6.5539134e-09 0.99967850437 1.00032051415
-
-Momentum - x y z
-[total ] 2.2158700e+00 -9.5225741e-13 -2.1395060e-14
-[fluid ] 2.1013425e+00 -9.5290442e-13 -2.0705659e-14
-[colloids] 1.1452756e-01 6.4701247e-16 -6.8940056e-16
-
-Velocity - x y z
-[minimum ] -1.7220078e-04 -4.9018114e-04 -4.9018114e-04
-[maximum ] 2.2654790e-03 4.9018114e-04 4.9018114e-04
-
-Completed cycle 40
-
-Timer resolution: 1e-06 second
-
-Timer statistics
- Section: tmin tmax total
- Total: 3.354 3.354 3.354 3.354108 (1 call)
- Time step loop: 0.066 0.101 3.227 0.080675 (40 calls)
- Propagation: 0.004 0.027 0.543 0.013564 (40 calls)
- Propagtn (krnl) : 0.004 0.027 0.538 0.013446 (40 calls)
- Collision: 0.009 0.052 1.410 0.035240 (40 calls)
- Collision (krnl) : 0.009 0.052 1.409 0.035227 (40 calls)
- Lattice halos: 0.002 0.049 0.653 0.008163 (80 calls)
- phi gradients: 0.000 0.000 0.000 0.000000 (40 calls)
- Forces: 0.000 0.032 0.013 0.000334 (40 calls)
- Rebuild: 0.001 0.041 0.130 0.003239 (40 calls)
- BBL: 0.002 0.024 0.206 0.005143 (40 calls)
- Particle halos: 0.000 0.019 0.166 0.004158 (40 calls)
- Force calculation: 0.000 0.000 0.000 0.000000 (40 calls)
- phi update: 0.000 0.000 0.000 0.000000 (40 calls)
- Free1: 0.000 0.044 0.039 0.000325 (120 calls)
-Ludwig finished normally.
diff --git a/tests/regression/d3q19-mpi-extra/parallel-auto-c02.inp b/tests/regression/d3q19-mpi-extra/parallel-auto-c02.inp
deleted file mode 100644
index 7f28dc335..000000000
--- a/tests/regression/d3q19-mpi-extra/parallel-auto-c02.inp
+++ /dev/null
@@ -1,179 +0,0 @@
-##############################################################################
-#
-# Colloid velocity autocorrelation test (with noise).
-#
-##############################################################################
-
-##############################################################################
-#
-# Run duration
-#
-# N_start If N_start > 0, this is a restart from previous output
-#
-# N_cycles number of lattice Boltzmann time steps to run
-# (if it's a restart, this is still the number of steps
-# to run, not the final step)
-#
-###############################################################################
-
-N_start 0
-N_cycles 40
-
-##############################################################################
-#
-# System and MPI
-#
-# size NX_NY_NZ is the size of the system in lattice units
-# grid PX_PY_PZ is the processor decomposition
-# If PX*PY*PZ is not equal to the number of processors,
-# MPI will choose a default (may be implementation-dependent).
-#
-# reduced_halo [yes|no] use reduced or full halos. Using reduced halos
-# is *only* appropriate for fluid only problems.
-# Default is no.
-#
-##############################################################################
-
-size 64_64_64
-reduced_halo no
-
-##############################################################################
-#
-# Fluid parameters
-#
-# viscosity shear viscosity [default is 1/6, ie., relaxation time 1]
-# viscosity_bulk bulk viscosity [default = shear viscosity]
-#
-# isothermal_fluctuations [on|off] Default is off.
-# temperature isothermal fluctuation 'temperature'
-#
-# ghost_modes [on|off] Default is on.
-# force FX_FY_FZ Uniform body force on fluid (default zero)
-#
-##############################################################################
-
-free_energy none
-
-viscosity 0.1
-viscosity_bulk 0.1
-
-isothermal_fluctuations on
-temperature 0.00002133333
-
-###############################################################################
-#
-# Colloid parameters
-#
-###############################################################################
-
-colloid_init input_one
-
-colloid_one_a0 2.3
-colloid_one_ah 2.3
-colloid_one_r 64.0_64.0_32.0
-colloid_one_v 0.043478261_0.0_0.0
-colloid_one_w 0.0_0.0_0.0
-colloid_one_s 1.0_0.0_0.0
-
-
-# Constant body force on all colloids ("gravity") [default is zero]
-# Uniform magnetic field [default is zero]
-
-colloid_gravity 0.0_0.0_0.0
-magnetic_b0 0.0_0.0_0.0
-
-###############################################################################
-#
-# Periodic conditions / boundaries
-#
-# boundary_walls_on [yes|no] Use built-in side walls [default no]
-# periodicity X_Y_Z Sets periodic boundary conditions in coordinate
-# directions [default is 1_1_1]. Best to leave this
-# unchanged
-# boundary_speed_top For use with built-in walls
-# boundary_speed_bottom For use with built-in walls
-#
-# porous_media_file filestub If present, the file filestub.001-001
-# should contain porous media data
-# porous_media_format [ASCII|BINARY] file format [default BINARY]
-# porous_media_type [status_only|status_with_h]
-# determines type of porous media data to be
-# supplied
-#
-###############################################################################
-
-boundary_walls_on no
-periodicity 1_1_1
-boundary_speed_bottom 0.0
-boundary_speed_top 0.0
-
-###############################################################################
-#
-# Output frequency and type
-#
-# freq_statistics N Output diagnostics every N steps
-# freq_output N Output field state every N steps
-# freq_config N Output full configuration (for restart) every
-# N steps (can be large!)
-# freq_phi N phi data output frequency
-# freq_vel N velocity data output frequency
-# freq_shear_measurement stress profile accumulator
-# freq_shear_output stress profile output
-# config_at_end [yes|no] write full configuration at end of run
-# [default is yes]
-#
-# io_grid NX_NY_NZ Cartesian processor I/O grid. Default is 1_1_1
-# The following for particle data are under review...
-# n_io_nodes Number of I/O processors for particles
-# output_format [ASCII|BINARY] default output format
-# input_format [ASCII|BINARY] default input format
-#
-# phi_format Override default format for particular quantities
-# etc... (both input and output)
-#
-###############################################################################
-
-freq_statistics 40
-freq_measure 200000
-freq_config 5000000
-freq_phi 100000
-freq_vel 100000
-freq_shear_measurement 100000
-freq_shear_output 100000
-config_at_end no
-
-distribution_io_grid 1_1_1
-
-phi_format ASCII
-vel_format ASCII
-
-##############################################################################
-#
-# colloid i/o
-#
-# colloid_io_freq currently set to freq_measure internally
-# colloid_io_grid currently set to 1_1_1 internally
-# colloid_io_format_input ASCII ASCII_SERIAL BINARY BINARY_SERIAL
-# colloid_io_format_output ASCII BINARY
-#
-# Note that the output is always parallel. A SERIAL input file must
-# be a single serial file.
-#
-##############################################################################
-
-colloid_io_freq 1000
-colloids_io_grid 1_1_1
-colloid_io_format_input BINARY
-colloid_io_format_output BINARY
-
-qs_dir_format BINARY
-
-###############################################################################
-#
-# Miscellaneous
-#
-# random_seed +ve integer is the random number generator seed
-#
-###############################################################################
-
-random_seed 8361235
diff --git a/tests/regression/d3q19-mpi-extra/parallel-auto-c02.log b/tests/regression/d3q19-mpi-extra/parallel-auto-c02.log
deleted file mode 100644
index b8c656a5f..000000000
--- a/tests/regression/d3q19-mpi-extra/parallel-auto-c02.log
+++ /dev/null
@@ -1,138 +0,0 @@
-Welcome to Ludwig v0.7.33 (MPI version running on 8 processes)
-
-The SVN revision details are: 3210M
-Note assertions via standard C assert() are on.
-
-Read 39 user parameters from pmpi08-auto-c02.inp
-
-No free energy selected
-
-System details
---------------
-System size: 64 64 64
-Decomposition: 2 2 2
-Local domain: 32 32 32
-Periodic: 1 1 1
-Halo nhalo: 1
-Reorder: true
-Initialised: 1
-
-System properties
-----------------
-Mean fluid density: 1.00000e+00
-Shear viscosity 1.00000e-01
-Bulk viscosity 1.00000e-01
-Temperature 2.13333e-05
-External body force density 0.00000e+00 0.00000e+00 0.00000e+00
-External E-field amplitude 0.00000e+00 0.00000e+00 0.00000e+00
-External E-field frequency 0.00000e+00
-External magnetic field 0.00000e+00 0.00000e+00 0.00000e+00
-
-Lattice Boltzmann distributions
--------------------------------
-Model: d3q19
-SIMD vector len: 1
-Number of sets: 1
-Halo type: full
-Input format: binary
-Output format: binary
-I/O grid: 1 1 1
-
-Lattice Boltzmann collision
----------------------------
-Relaxation time scheme: M10
-Hydrodynamic modes: on
-Ghost modes: on
-Isothermal fluctuations: on
-Shear relaxation time: 8.00000e-01
-Bulk relaxation time: 8.00000e-01
-Ghost relaxation time: 1.00000e+00
-[User ] Random number seed: 8361235
-
-Hydrodynamics
--------------
-Hydrodynamics: on
-
-Colloid information
--------------------
-
-Colloid I/O settings
---------------------
-Decomposition: 1 1 1
-Number of files: 1
-Input format: binary
-Output format: binary
-Single file read flag: 0
-
-Requested one colloid via input:
-colloid_one_a0 2.3000000e+00
-colloid_one_ah 2.3000000e+00
-colloid_one_r 6.4000000e+01 6.4000000e+01 3.2000000e+01
-colloid_one_v 4.3478261e-02 0.0000000e+00 0.0000000e+00
-colloid_one_w 0.0000000e+00 0.0000000e+00 0.0000000e+00
-colloid_one_s 1.0000000e+00 0.0000000e+00 0.0000000e+00
-
-Initialised 1 colloid
-
-Colloid cell list information
------------------------------
-Input radius maximum: 2.3000000e+00
-Final cell list: 11 11 11
-Final cell lengths: 2.9090909e+00 2.9090909e+00 2.9090909e+00
-
-Initial conditions.
-
-Scalars - total mean variance min max
-[rho] 262087.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
-
-Momentum - x y z
-[total ] 2.2158700e+00 0.0000000e+00 0.0000000e+00
-[fluid ] 3.6371878e-12 0.0000000e+00 0.0000000e+00
-[colloids] 2.2158700e+00 0.0000000e+00 0.0000000e+00
-
-Starting time step loop.
-
-Particle statistics:
-
-Colloid velocities - x y z
-[minimum ] 1.3675763e-03 -5.6482729e-04 5.1186310e-04
-[maximum ] 1.3675763e-03 -5.6482729e-04 5.1186310e-04
-
-Scalars - total mean variance min max
-[rho] 262091.00 1.00000000000 6.3519338e-05 0.96361208587 1.03533858441
-
-Momentum - x y z
-[total ] 2.2158700e+00 1.7273726e-14 4.0794625e-14
-[fluid ] 2.1321758e+00 1.3760202e-03 -3.8498072e-03
-[colloids] 8.3694239e-02 -1.3760202e-03 3.8498072e-03
-
-Velocity - x y z
-[minimum ] -2.2651159e-02 -2.0201971e-02 -2.2199155e-02
-[maximum ] 2.2262575e-02 2.0391258e-02 2.4334011e-02
-
-Isothermal fluctuations
-[eqipart.] 2.1335610e-05 2.1257847e-05 2.1371772e-05
-[measd/kT] 6.3965230e-05 6.3999990e-05
-
-Completed cycle 40
-
-Timer resolution: 1e-06 second
-
-Timer statistics
- Section: tmin tmax total
- Total: 3.801 3.801 3.801 3.800790 (1 call)
- Time step loop: 0.076 0.103 3.667 0.091664 (40 calls)
- Propagation: 0.004 0.025 0.612 0.015305 (40 calls)
- Propagtn (krnl) : 0.004 0.025 0.612 0.015298 (40 calls)
- Collision: 0.012 0.065 2.134 0.053342 (40 calls)
- Collision (krnl) : 0.012 0.065 2.133 0.053331 (40 calls)
- Lattice halos: 0.002 0.053 0.483 0.006032 (80 calls)
- phi gradients: 0.000 0.000 0.000 0.000000 (40 calls)
- Forces: 0.000 0.041 0.010 0.000244 (40 calls)
- Rebuild: 0.001 0.041 0.077 0.001919 (40 calls)
- BBL: 0.002 0.019 0.158 0.003953 (40 calls)
- Particle halos: 0.000 0.015 0.122 0.003039 (40 calls)
- Force calculation: 0.000 0.000 0.000 0.000000 (40 calls)
- phi update: 0.000 0.000 0.000 0.000000 (40 calls)
- Free1: 0.000 0.078 0.072 0.000598 (120 calls)
-Ludwig finished normally.
diff --git a/tests/regression/d3q19-short/serial-actv-s01.log b/tests/regression/d3q19-short/serial-actv-s01.log
index 16bc5a0a9..6e2dff6e1 100644
--- a/tests/regression/d3q19-short/serial-actv-s01.log
+++ b/tests/regression/d3q19-short/serial-actv-s01.log
@@ -97,6 +97,9 @@ Scalars - total mean variance min max
[Qyy] 1.3032632e+03 3.1817948e-01 7.1188129e-03 -1.5158982e-01 3.3333333e-01
[Qyz] 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energies - timestep f v f/v f_bulk/v f_grad/v redshift
+[fe] 0 -2.7821403250e+01 4.0960000000e+03 -6.7923347779e-03 -6.9444444444e-03 1.5210966656e-04 1.0000000000e+00
+
Momentum - x y z
[total ] 5.6843419e-14 0.0000000e+00 0.0000000e+00
[fluid ] 5.6843419e-14 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-actv-s02.log b/tests/regression/d3q19-short/serial-actv-s02.log
index c06598dfe..23e3ffed2 100644
--- a/tests/regression/d3q19-short/serial-actv-s02.log
+++ b/tests/regression/d3q19-short/serial-actv-s02.log
@@ -97,6 +97,9 @@ Scalars - total mean variance min max
[Qyy] 1.3032632e+03 3.1817948e-01 7.1188129e-03 -1.5158982e-01 3.3333333e-01
[Qyz] 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energies - timestep f v f/v f_bulk/v f_grad/v redshift
+[fe] 0 -2.7821403250e+01 4.0960000000e+03 -6.7923347779e-03 -6.9444444444e-03 1.5210966656e-04 1.0000000000e+00
+
Momentum - x y z
[total ] 5.6843419e-14 0.0000000e+00 0.0000000e+00
[fluid ] 5.6843419e-14 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-anch-cn1.log b/tests/regression/d3q19-short/serial-anch-cn1.log
index 8e657895a..beffeccc7 100644
--- a/tests/regression/d3q19-short/serial-anch-cn1.log
+++ b/tests/regression/d3q19-short/serial-anch-cn1.log
@@ -133,6 +133,9 @@ Scalars - total mean variance min max
[Qyy] -4.3428167e+04 -1.6666667e-01 -7.4395351e-14 -1.6666667e-01 -1.6666667e-01
[Qyz] 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 -1.4626035050e+01 2.6056900000e+05 -5.6131140119e-05 1.3520000000e+00 1.0140000000e+03 1.3333333333e-03
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-anch-cn2.log b/tests/regression/d3q19-short/serial-anch-cn2.log
index 78c91c4ee..871249d41 100644
--- a/tests/regression/d3q19-short/serial-anch-cn2.log
+++ b/tests/regression/d3q19-short/serial-anch-cn2.log
@@ -134,6 +134,9 @@ Scalars - total mean variance min max
[Qyy] -4.3428167e+04 -1.6666667e-01 -7.4395351e-14 -1.6666667e-01 -1.6666667e-01
[Qyz] 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 -1.7124366154e+01 2.6056900000e+05 -6.5719122975e-05 1.4909235568e+00 1.0140000000e+03 1.4703388134e-03
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-anch-wn1.log b/tests/regression/d3q19-short/serial-anch-wn1.log
index 600a6ebf6..a66cde764 100644
--- a/tests/regression/d3q19-short/serial-anch-wn1.log
+++ b/tests/regression/d3q19-short/serial-anch-wn1.log
@@ -116,6 +116,9 @@ Scalars - total mean variance min max
[Qyy] 2.0281416e+01 7.9224283e-02 3.0434697e-02 -1.6603977e-01 3.3332787e-01
[Qyz] 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energies - timestep f v f/v f_s1 fs_s2 redshift
+[fe] 0 -8.6959696682e-03 2.5600000000e+02 -3.3968631516e-05 3.0749616130e-04 5.0104380201e-04 1.0000000000e+00
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-anch-wn2.log b/tests/regression/d3q19-short/serial-anch-wn2.log
index c21f5d079..643c7c97a 100644
--- a/tests/regression/d3q19-short/serial-anch-wn2.log
+++ b/tests/regression/d3q19-short/serial-anch-wn2.log
@@ -117,6 +117,9 @@ Scalars - total mean variance min max
[Qyy] 2.0281416e+01 7.9224283e-02 3.0434697e-02 -1.6603977e-01 3.3332787e-01
[Qyz] 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energies - timestep f v f/v f_s1 fs_s2 redshift
+[fe] 0 -8.6306600774e-03 2.5600000000e+02 -3.3713515927e-05 1.0567663416e-03 9.5798326283e-04 1.0000000000e+00
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-anch-wn3.log b/tests/regression/d3q19-short/serial-anch-wn3.log
index da1699b32..e2d6ce2ce 100644
--- a/tests/regression/d3q19-short/serial-anch-wn3.log
+++ b/tests/regression/d3q19-short/serial-anch-wn3.log
@@ -117,6 +117,9 @@ Scalars - total mean variance min max
[Qyy] 2.0281416e+01 7.9224283e-02 3.0434697e-02 -1.6603977e-01 3.3332787e-01
[Qyz] 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energies - timestep f v f/v f_s1 fs_s2 redshift
+[fe] 0 -8.6543552119e-03 2.5600000000e+02 -3.3806075047e-05 4.9250383870e-04 2.9895619799e-04 1.0000000000e+00
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-bond-c01.log b/tests/regression/d3q19-short/serial-bond-c01.log
index f27a71941..2a98dfdb6 100644
--- a/tests/regression/d3q19-short/serial-bond-c01.log
+++ b/tests/regression/d3q19-short/serial-bond-c01.log
@@ -120,6 +120,9 @@ Scalars - total mean variance min max
[rho] 65484.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
[phi] 0.0000000e+00 0.0000000e+00 9.2965928e-01 -1.0000000e+00 1.0000000e+00
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 -9.3481842103e+02 6.5484000000e+04 -1.4275524113e-02 0.0000000000e+00
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-bond-c02.log b/tests/regression/d3q19-short/serial-bond-c02.log
index 4cc8eae19..16bc3cbed 100644
--- a/tests/regression/d3q19-short/serial-bond-c02.log
+++ b/tests/regression/d3q19-short/serial-bond-c02.log
@@ -117,6 +117,9 @@ Scalars - total mean variance min max
[rho] 65484.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
[phi] 0.0000000e+00 0.0000000e+00 9.2965928e-01 -1.0000000e+00 1.0000000e+00
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 -9.3481842103e-01 6.5484000000e+04 -1.4275524113e-05 0.0000000000e+00
+
Momentum - x y z
[total ] 9.0877306e-13 0.0000000e+00 0.0000000e+00
[fluid ] 9.0877306e-13 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-chol-fld.log b/tests/regression/d3q19-short/serial-chol-fld.log
index bdcf56383..c5333faf6 100644
--- a/tests/regression/d3q19-short/serial-chol-fld.log
+++ b/tests/regression/d3q19-short/serial-chol-fld.log
@@ -110,6 +110,9 @@ Scalars - total mean variance min max
[Qyy] 2.0480000e+02 5.0000000e-02 -2.7495367e-16 5.0000000e-02 5.0000000e-02
[Qyz] 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energies - timestep f v f/v f_bulk/v f_grad/v redshift
+[fe] 0 -1.4685971349e+00 4.0960000000e+03 -3.5854422238e-04 -3.5854422238e-04 0.0000000000e+00 1.0000000000e+00
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-chol-n01.log b/tests/regression/d3q19-short/serial-chol-n01.log
index cf8e7501b..28143ebb2 100644
--- a/tests/regression/d3q19-short/serial-chol-n01.log
+++ b/tests/regression/d3q19-short/serial-chol-n01.log
@@ -139,6 +139,9 @@ Scalars - total mean variance min max
[Qyy] 2.1869522e+04 8.3929867e-02 3.1266048e-02 -1.6666667e-01 3.3333333e-01
[Qyz] 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 -1.7252339949e+01 2.6056900000e+05 -6.6210255055e-05 4.3835625600e-01 1.0140000000e+03 4.3230400000e-04
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-chol-n02.log b/tests/regression/d3q19-short/serial-chol-n02.log
index bdb069326..8252beef8 100644
--- a/tests/regression/d3q19-short/serial-chol-n02.log
+++ b/tests/regression/d3q19-short/serial-chol-n02.log
@@ -147,6 +147,9 @@ Scalars - total mean variance min max
[Qyy] 2.1271805e+04 8.2132426e-02 3.1281495e-02 -1.6666667e-01 3.3333333e-01
[Qyz] 1.8665093e-02 7.2067665e-08 3.1217063e-02 -2.5000000e-01 2.5000000e-01
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 -1.6858825082e+01 2.5899400000e+05 -6.5093496690e-05 8.7671251200e-01 2.0280000000e+03 4.3230400000e-04
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-chol-n03.log b/tests/regression/d3q19-short/serial-chol-n03.log
index cd123b751..1cc0b9514 100644
--- a/tests/regression/d3q19-short/serial-chol-n03.log
+++ b/tests/regression/d3q19-short/serial-chol-n03.log
@@ -147,6 +147,9 @@ Scalars - total mean variance min max
[Qyy] -4.3165667e+04 -1.6666667e-01 -7.7306217e-14 -1.6666667e-01 -1.6666667e-01
[Qyz] 0.0000000e+00 0.0000000e+00 0.0000000e+00 -0.0000000e+00 -0.0000000e+00
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 -1.6858825082e+01 2.5899400000e+05 -6.5093496689e-05 8.7671251200e-01 2.0280000000e+03 4.3230400000e-04
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-chol-n04.log b/tests/regression/d3q19-short/serial-chol-n04.log
index 46cdee31e..73dd14c84 100644
--- a/tests/regression/d3q19-short/serial-chol-n04.log
+++ b/tests/regression/d3q19-short/serial-chol-n04.log
@@ -147,6 +147,9 @@ Scalars - total mean variance min max
[Qyy] 2.1893861e+04 8.4534241e-02 3.1281495e-02 -1.6666667e-01 3.3333333e-01
[Qyz] 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 -1.6858825082e+01 2.5899400000e+05 -6.5093496689e-05 8.7671251200e-01 2.0280000000e+03 4.3230400000e-04
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-chol-p01.log b/tests/regression/d3q19-short/serial-chol-p01.log
index 3d83d3ea3..e008d9b7c 100644
--- a/tests/regression/d3q19-short/serial-chol-p01.log
+++ b/tests/regression/d3q19-short/serial-chol-p01.log
@@ -141,6 +141,9 @@ Scalars - total mean variance min max
[Qyy] 2.1869522e+04 8.3929867e-02 3.1266048e-02 -1.6666667e-01 3.3333333e-01
[Qyz] 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 -1.7464619353e+01 2.6056900000e+05 -6.7024931413e-05 1.5407341537e-01 1.0140000000e+03 1.5194616901e-04
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-chol-st1.log b/tests/regression/d3q19-short/serial-chol-st1.log
index 61f8ac8a5..8d0cb47f4 100644
--- a/tests/regression/d3q19-short/serial-chol-st1.log
+++ b/tests/regression/d3q19-short/serial-chol-st1.log
@@ -153,6 +153,9 @@ Scalars - total mean variance min max
[Qyy] -9.1437873e-03 -2.7994328e-07 1.9647331e-09 -5.0000000e-05 9.9995019e-05
[Qyz] 2.1448907e-03 6.5667290e-08 1.5181251e-09 -7.4997452e-05 7.4998120e-05
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 5.9309580698e-04 3.2663000000e+04 1.8158032238e-08 3.7847344338e-02 2.1600000000e+02 1.7521918675e-04
+
Momentum - x y z
[total ] 4.5329018e-13 0.0000000e+00 0.0000000e+00
[fluid ] 4.5329018e-13 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-chol-st2.log b/tests/regression/d3q19-short/serial-chol-st2.log
index 3da66f935..2f5366258 100644
--- a/tests/regression/d3q19-short/serial-chol-st2.log
+++ b/tests/regression/d3q19-short/serial-chol-st2.log
@@ -153,6 +153,9 @@ Scalars - total mean variance min max
[Qyy] -5.1697246e-03 -3.1653959e-07 1.9621852e-09 -5.0000000e-05 9.9979055e-05
[Qyz] -2.4078974e-04 -1.4743433e-08 1.5200098e-09 -7.4985154e-05 7.4998120e-05
+Free energies - timestep f v f/v f_s1 fs_s2 redshift
+[fe] 0 9.2262326809e-03 1.6332000000e+04 5.6491750434e-07 1.7943162655e-01 1.7943344133e-01 1.0000000000e+00
+
Momentum - x y z
[total ] 2.2665203e-13 0.0000000e+00 0.0000000e+00
[fluid ] 2.2665203e-13 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-chol-st3.log b/tests/regression/d3q19-short/serial-chol-st3.log
index e48f5d193..95fe3d75f 100644
--- a/tests/regression/d3q19-short/serial-chol-st3.log
+++ b/tests/regression/d3q19-short/serial-chol-st3.log
@@ -116,6 +116,9 @@ Scalars - total mean variance min max
[Qyy] 2.4576000e+03 7.5000001e-02 2.5312500e-02 -1.5000000e-01 3.0000000e-01
[Qyz] 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energies - timestep f v f/v f_bulk/v f_grad/v redshift
+[fe] 0 -2.4456131969e+00 3.2768000000e+04 -7.4634191799e-05 -8.6978571499e-05 1.2344379700e-05 1.0000000000e+00
+
Momentum - x y z
[total ] -4.2632564e-14 -2.6093711e-14 0.0000000e+00
[fluid ] -4.2632564e-14 -2.6093711e-14 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-chol-st4.log b/tests/regression/d3q19-short/serial-chol-st4.log
index ccb69bb3f..4d0d02023 100644
--- a/tests/regression/d3q19-short/serial-chol-st4.log
+++ b/tests/regression/d3q19-short/serial-chol-st4.log
@@ -116,6 +116,9 @@ Scalars - total mean variance min max
[Qyy] 2.4576000e+03 7.5000001e-02 2.5312500e-02 -1.5000000e-01 3.0000000e-01
[Qyz] 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energies - timestep f v f/v f_bulk/v f_grad/v redshift
+[fe] 0 -2.4456131969e+00 3.2768000000e+04 -7.4634191799e-05 -8.6978571499e-05 1.2344379700e-05 1.0000000000e+00
+
Momentum - x y z
[total ] -4.2632564e-14 -2.6093711e-14 0.0000000e+00
[fluid ] -4.2632564e-14 -2.6093711e-14 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-chol-st5.log b/tests/regression/d3q19-short/serial-chol-st5.log
index 12a12cd23..00a393bb5 100644
--- a/tests/regression/d3q19-short/serial-chol-st5.log
+++ b/tests/regression/d3q19-short/serial-chol-st5.log
@@ -116,6 +116,9 @@ Scalars - total mean variance min max
[Qyy] 2.4576000e+03 7.5000001e-02 2.5312500e-02 -1.5000000e-01 3.0000000e-01
[Qyz] 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energies - timestep f v f/v f_bulk/v f_grad/v redshift
+[fe] 0 -2.4456131969e+00 3.2768000000e+04 -7.4634191799e-05 -8.6978571499e-05 1.2344379700e-05 1.0000000000e+00
+
Momentum - x y z
[total ] -4.2632564e-14 -2.6093711e-14 0.0000000e+00
[fluid ] -4.2632564e-14 -2.6093711e-14 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-chol-st6.log b/tests/regression/d3q19-short/serial-chol-st6.log
index aefb77263..310dcc2db 100644
--- a/tests/regression/d3q19-short/serial-chol-st6.log
+++ b/tests/regression/d3q19-short/serial-chol-st6.log
@@ -116,6 +116,9 @@ Scalars - total mean variance min max
[Qyy] 2.4576000e+03 7.5000001e-02 2.5312500e-02 -1.5000000e-01 3.0000000e-01
[Qyz] 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energies - timestep f v f/v f_bulk/v f_grad/v redshift
+[fe] 0 -2.4456131969e+00 3.2768000000e+04 -7.4634191799e-05 -8.6978571499e-05 1.2344379700e-05 1.0000000000e+00
+
Momentum - x y z
[total ] -4.2632564e-14 -2.6093711e-14 0.0000000e+00
[fluid ] -4.2632564e-14 -2.6093711e-14 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-chol-st7.log b/tests/regression/d3q19-short/serial-chol-st7.log
index 17d4746a1..016c0e874 100644
--- a/tests/regression/d3q19-short/serial-chol-st7.log
+++ b/tests/regression/d3q19-short/serial-chol-st7.log
@@ -152,6 +152,9 @@ Scalars - total mean variance min max
[Qyy] -9.1437873e-03 -2.7994328e-07 1.9647331e-09 -5.0000000e-05 9.9995019e-05
[Qyz] 2.1448907e-03 6.5667290e-08 1.5181251e-09 -7.4997452e-05 7.4998120e-05
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 5.9309580698e-04 3.2663000000e+04 1.8158032238e-08 3.7847344338e-02 2.1600000000e+02 1.7521918675e-04
+
Momentum - x y z
[total ] 4.5329018e-13 0.0000000e+00 0.0000000e+00
[fluid ] 4.5329018e-13 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-chol-w01.log b/tests/regression/d3q19-short/serial-chol-w01.log
index 9cf9056e1..76fb77706 100644
--- a/tests/regression/d3q19-short/serial-chol-w01.log
+++ b/tests/regression/d3q19-short/serial-chol-w01.log
@@ -123,6 +123,9 @@ Scalars - total mean variance min max
[Qyy] 9.7012768e-12 3.7007434e-17 -3.5259967e-45 3.7007434e-17 3.7007434e-17
[Qyz] 4.3690667e+04 1.6666667e-01 -7.1515710e-14 1.6666667e-01 1.6666667e-01
+Free energies - timestep f v f/v f_s1 fs_s2 redshift
+[fe] 0 -1.4668275124e+01 2.6214400000e+05 -5.5955029006e-05 3.0987550720e+00 3.0987550720e+00 1.0000000000e+00
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-chol-w02.log b/tests/regression/d3q19-short/serial-chol-w02.log
index 1b3286872..29c0c1537 100644
--- a/tests/regression/d3q19-short/serial-chol-w02.log
+++ b/tests/regression/d3q19-short/serial-chol-w02.log
@@ -123,6 +123,9 @@ Scalars - total mean variance min max
[Qyy] 9.7012768e-12 3.7007434e-17 -3.5259967e-45 3.7007434e-17 3.7007434e-17
[Qyz] 4.3690667e+04 1.6666667e-01 -7.1515710e-14 1.6666667e-01 1.6666667e-01
+Free energies - timestep f v f/v f_s1 fs_s2 redshift
+[fe] 0 -1.4668275124e+01 2.6214400000e+05 -5.5955029006e-05 3.0987550720e+00 3.0987550720e+00 1.0000000000e+00
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-chol-w03.log b/tests/regression/d3q19-short/serial-chol-w03.log
index 5dced4a8a..531098c97 100644
--- a/tests/regression/d3q19-short/serial-chol-w03.log
+++ b/tests/regression/d3q19-short/serial-chol-w03.log
@@ -123,6 +123,9 @@ Scalars - total mean variance min max
[Qyy] 9.7012768e-12 3.7007434e-17 -3.5259967e-45 3.7007434e-17 3.7007434e-17
[Qyz] 4.3690667e+04 1.6666667e-01 -7.1515710e-14 1.6666667e-01 1.6666667e-01
+Free energies - timestep f v f/v f_s1 fs_s2 redshift
+[fe] 0 -1.4668275124e+01 2.6214400000e+05 -5.5955029006e-05 3.0987550720e+00 3.0987550720e+00 1.0000000000e+00
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-chol-w04.log b/tests/regression/d3q19-short/serial-chol-w04.log
index 07b7fccbb..fd22ee53c 100644
--- a/tests/regression/d3q19-short/serial-chol-w04.log
+++ b/tests/regression/d3q19-short/serial-chol-w04.log
@@ -118,6 +118,9 @@ Scalars - total mean variance min max
[Qyy] 2.4253192e-12 3.7007434e-17 2.7119367e-45 3.7007434e-17 3.7007434e-17
[Qyz] 1.0922667e+04 1.6666667e-01 5.5004612e-14 1.6666667e-01 1.6666667e-01
+Free energies - timestep f v f/v f_s1 fs_s2 redshift
+[fe] 0 -3.1260163080e+00 6.5536000000e+04 -4.7699223450e-05 4.4267929600e-01 4.4267929600e-01 1.0000000000e+00
+
Momentum - x y z
[total ] 9.0949470e-13 0.0000000e+00 0.0000000e+00
[fluid ] 9.0949470e-13 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-chol-w05.log b/tests/regression/d3q19-short/serial-chol-w05.log
index 080cd5046..23d16406c 100644
--- a/tests/regression/d3q19-short/serial-chol-w05.log
+++ b/tests/regression/d3q19-short/serial-chol-w05.log
@@ -118,6 +118,9 @@ Scalars - total mean variance min max
[Qyy] 2.4253192e-12 3.7007434e-17 2.7119367e-45 3.7007434e-17 3.7007434e-17
[Qyz] 1.0922667e+04 1.6666667e-01 5.5004612e-14 1.6666667e-01 1.6666667e-01
+Free energies - timestep f v f/v f_s1 fs_s2 redshift
+[fe] 0 -3.1260163080e+00 6.5536000000e+04 -4.7699223450e-05 4.4267929600e-01 4.4267929600e-01 1.0000000000e+00
+
Momentum - x y z
[total ] 9.0949470e-13 0.0000000e+00 0.0000000e+00
[fluid ] 9.0949470e-13 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-drop-lc1.log b/tests/regression/d3q19-short/serial-drop-lc1.log
index 6923b15f3..5aa44a453 100644
--- a/tests/regression/d3q19-short/serial-drop-lc1.log
+++ b/tests/regression/d3q19-short/serial-drop-lc1.log
@@ -129,6 +129,9 @@ Scalars - total mean variance min max
[Qyy] 2.7306478e+03 8.3332756e-02 3.1250069e-02 -1.6666667e-01 3.3333333e-01
[Qyz] 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energy density - timestep total fluid
+[fed] 0 -1.4702479172e-02 -1.4702479172e-02
+
Momentum - x y z
[total ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
[fluid ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-drop-lc2.log b/tests/regression/d3q19-short/serial-drop-lc2.log
index e58deb099..c75e1f031 100644
--- a/tests/regression/d3q19-short/serial-drop-lc2.log
+++ b/tests/regression/d3q19-short/serial-drop-lc2.log
@@ -124,6 +124,9 @@ Scalars - total mean variance min max
[Qyy] -3.2768000e+03 -1.0000000e-01 6.8330758e-15 -1.0000000e-01 -1.0000000e-01
[Qyz] 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
+Free energy density - timestep total fluid
+[fed] 0 -1.4296432148e-02 -1.4296432148e-02
+
Momentum - x y z
[total ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
[fluid ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-drop-lc3.log b/tests/regression/d3q19-short/serial-drop-lc3.log
index 95679d9a3..d47eecb8d 100644
--- a/tests/regression/d3q19-short/serial-drop-lc3.log
+++ b/tests/regression/d3q19-short/serial-drop-lc3.log
@@ -127,6 +127,9 @@ Scalars - total mean variance min max
[Qyy] -4.7213797e-14 -1.8010634e-19 6.0000000e-02 -4.4966062e-01 4.4966064e-01
[Qyz] -3.1328486e-08 -1.1950869e-13 5.0000000e-02 -6.0000000e-01 6.0000000e-01
+Free energy density - timestep total fluid
+[fed] 0 1.4297372559e-02 1.4297372559e-02
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-drop-lc4.log b/tests/regression/d3q19-short/serial-drop-lc4.log
index bf5093a95..0f2a4a2a0 100644
--- a/tests/regression/d3q19-short/serial-drop-lc4.log
+++ b/tests/regression/d3q19-short/serial-drop-lc4.log
@@ -121,6 +121,9 @@ Scalars - total mean variance min max
[Qyy] -3.9850068e-14 -1.2161276e-18 6.0000000e-02 -4.4966062e-01 4.4966064e-01
[Qyz] -3.7858013e-09 -1.1553349e-13 5.0000000e-02 -6.0000000e-01 6.0000000e-01
+Free energy density - timestep total fluid
+[fed] 0 2.8628468640e-02 2.8628468640e-02
+
Momentum - x y z
[total ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
[fluid ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-drop-lc5.log b/tests/regression/d3q19-short/serial-drop-lc5.log
index 4c3d6e2db..39322e995 100644
--- a/tests/regression/d3q19-short/serial-drop-lc5.log
+++ b/tests/regression/d3q19-short/serial-drop-lc5.log
@@ -121,6 +121,9 @@ Scalars - total mean variance min max
[Qyy] -8.6591172e-15 -2.6425529e-19 6.0000000e-02 -4.4966055e-01 4.4966059e-01
[Qyz] -3.8895517e+03 -1.1869970e-01 3.8159319e-02 -6.0000000e-01 4.8051711e-01
+Free energy density - timestep total fluid
+[fed] 0 1.6905959169e-02 1.6905959169e-02
+
Momentum - x y z
[total ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
[fluid ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-elec-eo1.inp b/tests/regression/d3q19-short/serial-elec-eo1.inp
new file mode 100644
index 000000000..1c4c9efa7
--- /dev/null
+++ b/tests/regression/d3q19-short/serial-elec-eo1.inp
@@ -0,0 +1,145 @@
+##############################################################################
+#
+# Electro-osmotic flow
+#
+# This is a sample input file for the problem described at
+# https://ludwig.epcc.ed.ac.uk/tutorials/electrokinetics/electrokinetics.html
+#
+# We have a quasi-one dimensional system in the x-direction and we
+# use the special initialisation
+#
+# electrokinetics_init gouy_chapman
+#
+# to provide walls at x = 1 and x = Lx. We arrange for the system to
+# have a surface charge 0.03125 and counter-charge only). The whole
+# system is electroneutral. E.g.,
+#
+# electrokinetics_init_rho_el 0.0
+# electrokinetics_init_sigma 0.003125
+#
+# To drive the flow, we have an external electric field
+#
+# electric_e0 0.0_0.001_0.0
+#
+# For viscoity 0.1 the simulation can be run for 100,000 steps to
+# approach a steady state; if the viscosity is 0.01, about 300,000
+# steps will be required.
+#
+# The fluid velocity can be obtained by switching
+#
+# config_at_end yes
+#
+# For the purposes of this test, we only run 10 time steps (and
+# the output is switched off).
+#
+##############################################################################
+
+##############################################################################
+#
+# Run duration
+#
+###############################################################################
+
+N_cycles 10
+
+##############################################################################
+#
+# System and MPI
+#
+##############################################################################
+
+size 64_4_4
+periodicity 1_1_1
+lb_halo_scheme lb_halo_openmp_reduced
+
+##############################################################################
+#
+# Fluid parameters
+#
+# The temperature is relevant for k_B T in the electrokinetics context.
+#
+##############################################################################
+
+viscosity 0.1
+
+isothermal_fluctuations off
+temperature 3.33333333333333333e-5
+
+
+##############################################################################
+#
+# Free energy parameters
+#
+###############################################################################
+
+free_energy fe_electro
+fe_force_method phi_gradmu_correction
+
+fd_advection_scheme_order 3
+
+###############################################################################
+#
+# Colloid parameters
+#
+###############################################################################
+
+colloid_init none
+
+###############################################################################
+#
+# Walls / boundaries
+#
+###############################################################################
+
+boundary_walls 0_0_0
+
+###############################################################################
+#
+# Output frequency and type
+#
+###############################################################################
+
+freq_statistics 10
+freq_psi_resid 1000
+config_at_end no
+
+default_io_mode mpiio
+default_io_format ascii
+
+psi_io_mode mpiio
+psi_io_format ascii
+psi_io_report no
+
+
+###############################################################################
+#
+# Electrokinetics
+#
+###############################################################################
+
+electrokinetics_z0 +1
+electrokinetics_z1 -1
+electrokinetics_d0 0.01
+electrokinetics_d1 0.01
+electrokinetics_eunit 1.0
+electrokinetics_epsilon 3.3e3
+
+electrokinetics_init gouy_chapman
+electrokinetics_init_rho_el 0.0
+electrokinetics_init_sigma 0.03125
+
+electrokinetics_solver_type sor
+electrokinetics_solver_stencil 7
+
+# External electric field in y-direction
+
+electric_e0 0.0_0.001_0.0
+
+
+###############################################################################
+#
+# Miscellaneous
+#
+###############################################################################
+
+random_seed 8361235
diff --git a/tests/regression/d3q19-short/serial-elec-eo1.log b/tests/regression/d3q19-short/serial-elec-eo1.log
new file mode 100644
index 000000000..a79875dfc
--- /dev/null
+++ b/tests/regression/d3q19-short/serial-elec-eo1.log
@@ -0,0 +1,169 @@
+Welcome to: Ludwig v0.19.1 (Serial version running on 1 process)
+Git commit: 6cc1071fbcdf5429715e3a84575c6677409326e8
+
+Start time: Fri Jun 30 17:48:44 2023
+
+Compiler:
+ name: Gnu 11.3.0
+ version-string: 11.3.0
+ options: -O2 -g -fopenmp -Wall -Werror
+
+Note assertions via standard C assert() are on.
+
+Target thread model: OpenMP.
+OpenMP threads: 1; maximum number of threads: 8.
+
+Read 33 user parameters from input
+
+System details
+--------------
+System size: 64 4 4
+Decomposition: 1 1 1
+Local domain: 64 4 4
+Periodic: 1 1 1
+Halo nhalo: 1
+Reorder: true
+Initialised: 1
+
+Free energy details
+-------------------
+
+Electrokinetics (single fluid) selected
+
+Parameters:
+Electrokinetic species: 2
+Boltzmann factor: 3.0000000e+04 (T = 3.3333333e-05)
+Unit charge: 1.0000000e+00
+Permittivity: 3.3000000e+03
+Bjerrum length: 7.2343156e-01
+Valency species 0: 1
+Diffusivity species 0: 1.0000000e-02
+Valency species 1: -1
+Diffusivity species 1: 1.0000000e-02
+Solver type: sor
+Solver stencil points: 7
+Relative tolerance: 1.0000000e-08
+Absolute tolerance: 1.0000000e-15
+Max. no. of iterations: 10000
+Number of multisteps: 1
+Diffusive accuracy in NPE: 0.0000000e+00
+Force calculation: phi_gradmu_correction
+
+System properties
+----------------
+Mean fluid density: 1.00000e+00
+Shear viscosity 1.00000e-01
+Bulk viscosity 1.00000e-01
+Temperature 3.33333e-05
+External body force density 0.00000e+00 0.00000e+00 0.00000e+00
+External E-field amplitude 0.00000e+00 1.00000e-03 0.00000e+00
+External E-field frequency 0.00000e+00
+External magnetic field 0.00000e+00 0.00000e+00 0.00000e+00
+
+Lattice Boltzmann distributions
+-------------------------------
+Model: d3q19
+SIMD vector len: 1
+Number of sets: 1
+Halo type: lb_halo_openmp_reduced (host)
+Input format: binary
+Output format: binary
+I/O grid: 1 1 1
+
+Lattice Boltzmann collision
+---------------------------
+Relaxation time scheme: M10
+Hydrodynamic modes: on
+Ghost modes: on
+Isothermal fluctuations: off
+Shear relaxation time: 8.00000e-01
+Bulk relaxation time: 8.00000e-01
+Ghost relaxation time: 1.00000e+00
+[User ] Random number seed: 8361235
+
+Hydrodynamics
+-------------
+Hydrodynamics: on
+
+Advection scheme order: 3
+
+Initial charge densities
+------------------------
+Initial conditions: Gouy Chapman
+Initial condition rho_el: 0.0000000e+00
+Debye length: inf
+Debye length (actual): 1.0446052e+01
+Initial condition sigma: 3.1250000e-02
+
+Porous Media
+------------
+Wall boundary links allocated: 160
+Memory (total, bytes): 2560
+
+Arranging initial charge neutrality.
+
+Initial conditions.
+
+Scalars - total mean variance min max
+[rho] 992.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
+[psi] 0.0000000e+00 0.0000000e+00 0.0000000e+00
+[rho] 1.0000000e+00 1.2982447e-17 3.1250000e-02
+[rho] 1.0000000e+00 0.0000000e+00 1.0080645e-03
+[elc] 1.8041124e-14 -1.0080645e-03 3.1250000e-02
+
+Free energy density - timestep total fluid
+[fed] 0 -1.2075643565e-02 -7.9634305517e-03
+
+Momentum - x y z
+[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
+[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
+[walls ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
+
+Starting time step loop.
+
+Scalars - total mean variance min max
+[rho] 992.00 1.00000000000 2.2204460e-16 0.99999998307 1.00000013759
+[psi] -4.4408921e-16 -1.5627146e+00 2.9822130e+00
+[rho] 1.0000000e+00 1.2639475e-17 3.1250000e-02
+[rho] 1.0000000e+00 0.0000000e+00 1.0350169e-03
+[elc] 1.4821477e-14 -1.0350169e-03 3.1250000e-02
+
+Free energy density - timestep total fluid
+[fed] 10 -1.0574510134e-02 -7.9162489905e-03
+
+Momentum - x y z
+[total ] 1.7558871e-14 -3.3333335e-07 0.0000000e+00
+[fluid ] 8.8991314e-15 -3.2485317e-07 0.0000000e+00
+[walls ] 8.6597396e-15 -8.4801826e-09 0.0000000e+00
+
+Velocity - x y z
+[minimum ] -6.8238846e-08 -3.1909581e-10 0.0000000e+00
+[maximum ] 6.8238846e-08 1.1754944e-38 1.1754944e-38
+
+Completed cycle 10
+
+Timer resolution: 1e-06 second
+
+Timer statistics
+ Section: tmin tmax total
+ Total: 0.249 0.249 0.249 0.248758 (1 call)
+ Time step loop: 0.023 0.038 0.246 0.024586 (10 calls)
+ Propagation: 0.001 0.001 0.006 0.000608 (10 calls)
+ Propagtn (krnl) : 0.001 0.001 0.006 0.000605 (10 calls)
+ Collision: 0.001 0.001 0.013 0.001261 (10 calls)
+ Collision (krnl) : 0.001 0.001 0.013 0.001255 (10 calls)
+ Lattice halos: 0.000 0.000 0.005 0.000135 (40 calls)
+ -> irecv: 0.000 0.000 0.000 0.000001 (10 calls)
+ -> pack: 0.000 0.000 0.001 0.000118 (10 calls)
+ -> isend: 0.000 0.000 0.000 0.000000 (10 calls)
+ -> waitall: 0.000 0.000 0.000 0.000000 (10 calls)
+ -> unpack: 0.000 0.000 0.001 0.000110 (10 calls)
+ phi gradients: 0.000 0.000 0.000 0.000000 (10 calls)
+ BBL: 0.000 0.000 0.000 0.000027 (10 calls)
+ Force calculation: 0.000 0.000 0.001 0.000072 (20 calls)
+ phi update: 0.000 0.000 0.000 0.000000 (10 calls)
+ Poisson equation: 0.019 0.033 0.204 0.020357 (10 calls)
+ Nernst Planck: 0.001 0.002 0.015 0.001471 (10 calls)
+Diagnostics / output: 0.000 0.001 0.001 0.000081 (10 calls)
+End time: Fri Jun 30 17:48:44 2023
+Ludwig finished normally.
diff --git a/tests/regression/d3q19-elec/serial-elec-gc1.inp b/tests/regression/d3q19-short/serial-elec-gc1.inp
similarity index 52%
rename from tests/regression/d3q19-elec/serial-elec-gc1.inp
rename to tests/regression/d3q19-short/serial-elec-gc1.inp
index 7cdc37819..9fc01d952 100644
--- a/tests/regression/d3q19-elec/serial-elec-gc1.inp
+++ b/tests/regression/d3q19-short/serial-elec-gc1.inp
@@ -2,9 +2,31 @@
#
# Guoy-Chapman electrokinetics
#
-# Note residual reporting is switched off to allow this test to
-# pass at 1000 steps. (Exact residual varies above tolerance on
-# different platforms.)
+# This is a sample input file for the problem described at
+# https://ludwig.epcc.ed.ac.uk/tutorials/electrokinetics/electrokinetics.html
+#
+# We have a quasi-one dimensional system in the x-direction and we
+# use the special initialisation
+#
+# electrokinetics_init gouy_chapman
+#
+# to provide walls at x = 1 and x = Lx. We arrange for the system to
+# have a surface charge (0.3125, 0.03125, or 0.003125) and zero
+# co-ion concentration (counter-charge only). The whole system is
+# electroneutral. E.g.,
+#
+# electrokinetics_init_rho_el 0.0
+# electrokinetics_init_sigma 0.003125
+#
+# For the purposes of this test, only 100 time steps are used,
+# and the SOR residual reporting is switch off to allow the test
+# to pass (the residual can be sensitive to the platform/compiler
+# at the level of the test tolerance).
+#
+# For the results presented, 100,000 steps were used, and the
+# final configuration file is used to provide the charge density.
+# Statistics and residual reporting can be used at 1000 steps
+# interval.
#
##############################################################################
@@ -14,8 +36,7 @@
#
###############################################################################
-N_start 0
-N_cycles 1000
+N_cycles 100
##############################################################################
#
@@ -23,19 +44,19 @@ N_cycles 1000
#
##############################################################################
-size 64_4_4
-grid 1_1_2
-periodicity 1_1_1
+size 64_4_4
+periodicity 1_1_1
lb_halo_scheme lb_halo_openmp_reduced
##############################################################################
#
# Fluid parameters
#
+# The temperature is relevant for k_B T in the electrokinetics context.
+#
##############################################################################
-viscosity 0.1
-viscosity_bulk 0.1
+viscosity 0.1
isothermal_fluctuations off
temperature 3.33333333333333333e-5
@@ -47,7 +68,7 @@ temperature 3.33333333333333333e-5
#
###############################################################################
-free_energy fe_electro
+free_energy fe_electro
fe_force_method phi_gradmu_correction
fd_advection_scheme_order 3
@@ -59,7 +80,6 @@ fd_advection_scheme_order 3
###############################################################################
colloid_init none
-magnetic_b0 0.0_0.0_0.0
###############################################################################
#
@@ -75,40 +95,33 @@ boundary_walls 0_0_0
#
###############################################################################
-freq_statistics 1000
-freq_psi_resid 10000
-config_at_end no
+freq_statistics 100
+freq_psi_resid 1000
+config_at_end no
-colloid_io_freq 1000
-
-stats_vel_print_vol_flux yes
+psi_io_mode mpiio
+psi_io_format ascii
+psi_io_report no
###############################################################################
#
-# Electrokinetics ALWAYS 2 SPECIES FOR NOW
-#
-# electrokinetics_z0 valency species 0 default +1
-# electrokinetics_z1 valency species 1 default -1
-# electrokinetics_d0 diffusivity 0 default 0.0
-# electrokinetics_d1 diffusivity 1 default 0.0
-# electrokinetics_eunit unit charge default +1.0
-# electrokinetics_epsilon permeativity (ref) default 0.0
-#
-# Also important
-#
-# temperature sets Boltzmann factor beta
+# Electrokinetics
#
###############################################################################
-electrokinetics_z0 +1
-electrokinetics_z1 -1
-electrokinetics_d0 0.01
-electrokinetics_d1 0.01
-electrokinetics_eunit 1.0
-electrokinetics_epsilon 3.3e3
-electrokinetics_init gouy_chapman
-electrokinetics_init_rho_el 0.001
-electrokinetics_init_sigma 0.03125
+electrokinetics_z0 +1
+electrokinetics_z1 -1
+electrokinetics_d0 0.01
+electrokinetics_d1 0.01
+electrokinetics_eunit 1.0
+electrokinetics_epsilon 3.3e3
+
+electrokinetics_init gouy_chapman
+electrokinetics_init_rho_el 0.0
+electrokinetics_init_sigma 0.003125
+
+electrokinetics_solver_type sor
+electrokinetics_solver_stencil 7
###############################################################################
#
diff --git a/tests/regression/d3q19-elec/serial-elec-gc2.log b/tests/regression/d3q19-short/serial-elec-gc1.log
similarity index 54%
rename from tests/regression/d3q19-elec/serial-elec-gc2.log
rename to tests/regression/d3q19-short/serial-elec-gc1.log
index 905248069..44f61776a 100644
--- a/tests/regression/d3q19-elec/serial-elec-gc2.log
+++ b/tests/regression/d3q19-short/serial-elec-gc1.log
@@ -1,16 +1,19 @@
-Welcome to Ludwig v0.15.0 (Serial version running on 1 process)
-Start time: Wed Jan 12 12:46:04 2022
+Welcome to: Ludwig v0.19.1 (Serial version running on 1 process)
+Git commit: 0552745563099758c116ac6742dd788ed39f13e3
+
+Start time: Wed Jun 21 12:27:56 2023
Compiler:
- name: Gnu 11.2.0
- version-string: 11.2.0
+ name: Gnu 11.3.0
+ version-string: 11.3.0
+ options: -O2 -g -fopenmp -Wall -Werror
Note assertions via standard C assert() are on.
Target thread model: OpenMP.
OpenMP threads: 1; maximum number of threads: 8.
-Read 30 user parameters from serial-elec-gc2.inp
+Read 30 user parameters from input
System details
--------------
@@ -37,15 +40,14 @@ Valency species 0: 1
Diffusivity species 0: 1.0000000e-02
Valency species 1: -1
Diffusivity species 1: 1.0000000e-02
+Solver type: sor
+Solver stencil points: 7
+Relative tolerance: 1.0000000e-08
+Absolute tolerance: 1.0000000e-15
+Max. no. of iterations: 10000
Number of multisteps: 1
-Number of skipsteps: 1
Diffusive accuracy in NPE: 0.0000000e+00
-Relative tolerance: 1.1920929e-07
-Absolute tolerance: 1.1920929e-09
-Max. no. of iterations: 10000
-I/O decomposition: 1 1 1
-I/O format: BINARY
-Force calculation: phi_gradmu_correction
+Force calculation: phi_gradmu_correction
System properties
----------------
@@ -77,13 +79,6 @@ Isothermal fluctuations: off
Shear relaxation time: 8.00000e-01
Bulk relaxation time: 8.00000e-01
Ghost relaxation time: 1.00000e+00
-
-Porous media
-------------
-Porous media file stub: capillary
-Porous media file data items: 0
-Porous media format (serial): binary
-Porous media io grid: 1 1 1
[User ] Random number seed: 8361235
Hydrodynamics
@@ -94,7 +89,11 @@ Advection scheme order: 3
Initial charge densities
------------------------
-Initialisation requested from file psi-00000000.001-001
+Initial conditions: Gouy Chapman
+Initial condition rho_el: 0.0000000e+00
+Debye length: inf
+Debye length (actual): 3.3033317e+01
+Initial condition sigma: 3.1250000e-03
Porous Media
------------
@@ -108,9 +107,12 @@ Initial conditions.
Scalars - total mean variance min max
[rho] 992.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
[psi] 0.0000000e+00 0.0000000e+00 0.0000000e+00
-[rho] 1.9920000e+00 1.0000000e-03 3.1250000e-02
-[rho] 1.9920000e+00 0.0000000e+00 2.0080645e-03
-[elc] -2.3203661e-14 -1.0080645e-03 3.1250000e-02
+[rho] 1.0000000e-01 0.0000000e+00 3.1250000e-03
+[rho] 1.0000000e-01 0.0000000e+00 1.0080645e-04
+[elc] -2.5413699e-16 -1.0080645e-04 3.1250000e-03
+
+Free energy density - timestep total fluid
+[fed] 0 -1.6572880074e-03 -1.0284584879e-03
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
@@ -118,27 +120,25 @@ Momentum - x y z
[walls ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
Starting time step loop.
-1 multisteps
Scalars - total mean variance min max
-[rho] 992.00 1.00000000000 1.5210055e-14 0.99999998294 1.00000011145
-[psi] 1.1990409e-14 -1.5210888e+00 2.9128003e+00
-[rho] 1.9920000e+00 8.2093661e-04 3.1250000e-02
-[rho] 1.9920000e+00 0.0000000e+00 2.4098347e-03
-[elc] -1.4988011e-14 -1.5888981e-03 3.1250000e-02
+[rho] 992.00 1.00000000000 1.0214052e-14 0.99999999983 1.00000000113
+[psi] 1.3017365e-13 -1.5610986e-01 2.9805899e-01
+[rho] 1.0000000e-01 0.0000000e+00 3.1250000e-03
+[rho] 1.0000000e-01 0.0000000e+00 1.0273708e-04
+[elc] -8.3006518e-16 -1.0273708e-04 3.1250000e-03
Free energy density - timestep total fluid
-[fed] 100 -2.4613216884e-02 -2.2373587017e-02
+[fed] 100 -1.6422762401e-03 -1.0279856047e-03
Momentum - x y z
-[total ] -6.6613381e-16 3.1225023e-17 0.0000000e+00
-[fluid ] -1.4854784e-13 3.1225023e-17 0.0000000e+00
-[walls ] 1.4788171e-13 0.0000000e+00 0.0000000e+00
+[total ] 3.6637360e-14 1.3877788e-17 0.0000000e+00
+[fluid ] 1.1457502e-13 1.3877788e-17 0.0000000e+00
+[walls ] -7.7937656e-14 0.0000000e+00 0.0000000e+00
Velocity - x y z
-[minimum ] -4.7355583e-08 -6.9388940e-18 0.0000000e+00
-[maximum ] 4.7355582e-08 6.9388940e-18 1.1754944e-38
-[vol flux] -1.4543921e-13 -2.2204458e-16 0.0000000e+00
+[minimum ] -4.7309645e-10 -6.9388939e-18 0.0000000e+00
+[maximum ] 4.7309630e-10 6.9388939e-18 1.1754944e-38
Completed cycle 100
@@ -146,19 +146,24 @@ Timer resolution: 1e-06 second
Timer statistics
Section: tmin tmax total
- Total: 2.751 2.751 2.751 2.750747 (1 call)
- Time step loop: 0.027 0.029 2.746 0.027462 (100 calls)
- Propagation: 0.001 0.001 0.061 0.000605 (100 calls)
- Propagtn (krnl) : 0.001 0.001 0.060 0.000604 (100 calls)
- Collision: 0.001 0.001 0.120 0.001200 (100 calls)
- Collision (krnl) : 0.001 0.001 0.120 0.001198 (100 calls)
- Lattice halos: 0.000 0.001 0.066 0.000165 (400 calls)
+ Total: 1.863 1.863 1.863 1.862596 (1 call)
+ Time step loop: 0.018 0.037 1.860 0.018596 (100 calls)
+ Propagation: 0.001 0.001 0.061 0.000608 (100 calls)
+ Propagtn (krnl) : 0.001 0.001 0.060 0.000603 (100 calls)
+ Collision: 0.001 0.002 0.130 0.001299 (100 calls)
+ Collision (krnl) : 0.001 0.002 0.130 0.001295 (100 calls)
+ Lattice halos: 0.000 0.000 0.056 0.000141 (400 calls)
+ -> irecv: 0.000 0.000 0.000 0.000000 (100 calls)
+ -> pack: 0.000 0.000 0.012 0.000124 (100 calls)
+ -> isend: 0.000 0.000 0.000 0.000000 (100 calls)
+ -> waitall: 0.000 0.000 0.000 0.000000 (100 calls)
+ -> unpack: 0.000 0.000 0.012 0.000121 (100 calls)
phi gradients: 0.000 0.000 0.000 0.000000 (100 calls)
- BBL: 0.000 0.000 0.002 0.000024 (100 calls)
- Force calculation: 0.000 0.000 0.013 0.000067 (200 calls)
+ BBL: 0.000 0.000 0.003 0.000026 (100 calls)
+ Force calculation: 0.000 0.000 0.015 0.000073 (200 calls)
phi update: 0.000 0.000 0.000 0.000000 (100 calls)
- Poisson equation: 0.023 0.025 2.338 0.023377 (100 calls)
- Nernst Planck: 0.001 0.002 0.137 0.001366 (100 calls)
- Free1: 0.000 0.001 0.001 0.000009 (100 calls)
-End time: Wed Jan 12 12:46:06 2022
+ Poisson equation: 0.014 0.032 1.439 0.014394 (100 calls)
+ Nernst Planck: 0.001 0.002 0.145 0.001452 (100 calls)
+Diagnostics / output: 0.000 0.001 0.001 0.000009 (100 calls)
+End time: Wed Jun 21 12:27:58 2023
Ludwig finished normally.
diff --git a/tests/regression/d3q19-short/serial-elec-lj1.inp b/tests/regression/d3q19-short/serial-elec-lj1.inp
new file mode 100644
index 000000000..fedba0e09
--- /dev/null
+++ b/tests/regression/d3q19-short/serial-elec-lj1.inp
@@ -0,0 +1,125 @@
+##############################################################################
+#
+# Liquid junction problem
+#
+# This is the liquid junction time dependence as discussed at
+# https://ludwig.epcc.ed.ac.uk/tutorials/electrokinectics/electrokinetics.html
+#
+# For a quasi-one-dimensional system we use the special intialisation
+#
+# electrokinetics_init liquid_junction
+#
+# to provide two charged species with an initial step at the centre
+# of the system in the long direction (the x-direction).
+#
+# The hydrodynamics is switched off for this problem. It is purely
+# diffusive.
+#
+# For the short time scale, the system is run for 5000 time steps
+# with statistics at 50 time steps, while for the long time regime
+# the run is 100,000 time steps with statistics at 1000 steps.
+#
+# For system size 128_4_4, the parameters are the same; for the
+# system size 256_4_4, the short time regime is the same, but
+# the long time regime is run for 200,000 steps.
+#
+# Note that large differences in the diffusivities (e.g., as much
+# as 0.0125 and 0.075) will lead to noticable deviations from the
+# theory of Mafe et al., which assumes they are "close".
+#
+#
+# For the purposes of this test, the number of steps is reduced to
+# 100, with statistics at 100 steps.
+#
+##############################################################################
+
+##############################################################################
+#
+# Run duration
+#
+###############################################################################
+
+N_cycles 100
+
+##############################################################################
+#
+# System and MPI
+#
+##############################################################################
+
+size 64_4_4
+periodicity 1_1_1
+lb_halo_scheme lb_halo_openmp_reduced
+
+##############################################################################
+#
+# Fluid parameters
+#
+##############################################################################
+
+hydrodynamics off
+temperature 3.33333333333333333e-5
+
+##############################################################################
+#
+# Free energy parameters
+#
+###############################################################################
+
+free_energy fe_electro
+fe_force_method phi_gradmu_correction
+
+###############################################################################
+#
+# Colloid parameters
+#
+###############################################################################
+
+colloid_init none
+
+###############################################################################
+#
+# Walls / boundaries
+#
+###############################################################################
+
+boundary_walls 0_0_0
+
+###############################################################################
+#
+# Output frequency and type
+#
+###############################################################################
+
+freq_statistics 100
+freq_psi_resid 1000
+config_at_end no
+
+###############################################################################
+#
+# Electrokinetics
+#
+###############################################################################
+
+electrokinetics_z0 +1
+electrokinetics_z1 -1
+electrokinetics_d0 0.0105
+electrokinetics_d1 0.0095
+electrokinetics_eunit 1.0
+electrokinetics_epsilon 3.3e3
+
+electrokinetics_init liquid_junction
+electrokinetics_init_rho_el 0.01
+electrokinetics_init_delta_el 0.0002
+
+psi_io_mode mpiio
+psi_io_format ascii
+psi_io_report no
+
+###############################################################################
+#
+# Miscellaneous
+#
+###############################################################################
+
+random_seed 8361235
diff --git a/tests/regression/d3q19-short/serial-elec-lj1.log b/tests/regression/d3q19-short/serial-elec-lj1.log
new file mode 100644
index 000000000..c1b4de07b
--- /dev/null
+++ b/tests/regression/d3q19-short/serial-elec-lj1.log
@@ -0,0 +1,149 @@
+Welcome to: Ludwig v0.19.1 (Serial version running on 1 process)
+Git commit: 0552745563099758c116ac6742dd788ed39f13e3
+
+Start time: Wed Jun 21 14:08:46 2023
+
+Compiler:
+ name: Gnu 11.3.0
+ version-string: 11.3.0
+ options: -O2 -g -fopenmp -Wall -Werror
+
+Note assertions via standard C assert() are on.
+
+Target thread model: OpenMP.
+OpenMP threads: 1; maximum number of threads: 8.
+
+Read 26 user parameters from input
+
+System details
+--------------
+System size: 64 4 4
+Decomposition: 1 1 1
+Local domain: 64 4 4
+Periodic: 1 1 1
+Halo nhalo: 1
+Reorder: true
+Initialised: 1
+
+Free energy details
+-------------------
+
+Electrokinetics (single fluid) selected
+
+Parameters:
+Electrokinetic species: 2
+Boltzmann factor: 3.0000000e+04 (T = 3.3333333e-05)
+Unit charge: 1.0000000e+00
+Permittivity: 3.3000000e+03
+Bjerrum length: 7.2343156e-01
+Valency species 0: 1
+Diffusivity species 0: 1.0500000e-02
+Valency species 1: -1
+Diffusivity species 1: 9.5000000e-03
+Solver type: sor
+Solver stencil points: 7
+Relative tolerance: 1.0000000e-08
+Absolute tolerance: 1.0000000e-15
+Max. no. of iterations: 10000
+Number of multisteps: 1
+Diffusive accuracy in NPE: 0.0000000e+00
+Force calculation: phi_gradmu_correction
+
+System properties
+----------------
+Mean fluid density: 1.00000e+00
+Shear viscosity 1.66667e-01
+Bulk viscosity 1.66667e-01
+Temperature 3.33333e-05
+External body force density 0.00000e+00 0.00000e+00 0.00000e+00
+External E-field amplitude 0.00000e+00 0.00000e+00 0.00000e+00
+External E-field frequency 0.00000e+00
+External magnetic field 0.00000e+00 0.00000e+00 0.00000e+00
+
+Lattice Boltzmann distributions
+-------------------------------
+Model: d3q19
+SIMD vector len: 1
+Number of sets: 1
+Halo type: lb_halo_openmp_reduced (host)
+Input format: binary
+Output format: binary
+I/O grid: 1 1 1
+
+Lattice Boltzmann collision
+---------------------------
+Relaxation time scheme: M10
+Hydrodynamic modes: on
+Ghost modes: on
+Isothermal fluctuations: off
+Shear relaxation time: 1.00000e+00
+Bulk relaxation time: 1.00000e+00
+Ghost relaxation time: 1.00000e+00
+[User ] Random number seed: 8361235
+
+Hydrodynamics
+-------------
+Hydrodynamics: off
+
+Advection scheme order: 1 (default)
+
+Initial charge densities
+------------------------
+Initial conditions: Liquid junction
+Initial condition rho_el: 1.0000000e-02
+Debye length: 2.3452079e+00
+Initial condition delta_el: 2.0000000e-04
+Saturation potential: 3.3250000e-09
+Saturation timescale: 5.5000000e+02
+
+Arranging initial charge neutrality.
+
+Initial conditions.
+
+Scalars - total mean variance min max
+[rho] 1024.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
+[psi] 0.0000000e+00 0.0000000e+00 0.0000000e+00
+[rho] 1.0240000e+01 9.9000000e-03 1.0100000e-02
+[rho] 1.0240000e+01 9.9000000e-03 1.0100000e-02
+[elc] 0.0000000e+00 0.0000000e+00 0.0000000e+00
+
+Free energy density - timestep total fluid
+[fed] 0 -1.1210240370e-01 -1.1210240370e-01
+
+Momentum - x y z
+[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
+[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
+
+Starting time step loop.
+
+Scalars - total mean variance min max
+[rho] 1024.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
+[psi] -9.5816367e-18 -8.2430681e-05 8.2435962e-05
+[rho] 1.0240000e+01 9.9000000e-03 1.0100000e-02
+[rho] 1.0240000e+01 9.9000000e-03 1.0100000e-02
+[elc] -1.1102230e-16 -2.2451392e-06 2.2458928e-06
+
+Free energy density - timestep total fluid
+[fed] 100 -1.1210250016e-01 -1.1210250016e-01
+
+Momentum - x y z
+[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
+[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
+
+Completed cycle 100
+
+Timer resolution: 1e-06 second
+
+Timer statistics
+ Section: tmin tmax total
+ Total: 2.667 2.667 2.667 2.667317 (1 call)
+ Time step loop: 0.002 0.034 2.665 0.026649 (100 calls)
+ Lattice halos: 0.000 0.000 0.023 0.000114 (200 calls)
+ phi gradients: 0.000 0.000 0.000 0.000000 (100 calls)
+ Force calculation: 0.000 0.000 0.011 0.000057 (200 calls)
+ phi update: 0.000 0.000 0.000 0.000000 (100 calls)
+ Poisson equation: 0.000 0.032 2.516 0.025155 (100 calls)
+ Nernst Planck: 0.001 0.001 0.110 0.001100 (100 calls)
+Diagnostics / output: 0.000 0.001 0.001 0.000008 (100 calls)
+End time: Wed Jun 21 14:08:48 2023
+Ludwig finished normally.
diff --git a/tests/regression/d3q19-elec/serial-elec-rr1.inp b/tests/regression/d3q19-short/serial-elec-rr1.inp
similarity index 91%
rename from tests/regression/d3q19-elec/serial-elec-rr1.inp
rename to tests/regression/d3q19-short/serial-elec-rr1.inp
index 91b55d2d1..117838088 100644
--- a/tests/regression/d3q19-elec/serial-elec-rr1.inp
+++ b/tests/regression/d3q19-short/serial-elec-rr1.inp
@@ -59,14 +59,18 @@ colloid_one_q1 0.0000
###############################################################################
freq_statistics 1
-config_at_end no
+freq_psi_resid 10
+config_at_end no
default_io_grid 1_1_1
colloid_io_freq 1000
+psi_io_mode mpiio
+psi_io_report no
+
###############################################################################
#
-# Electrokinetics ALWAYS 2 SPECIES FOR NOW
+# Electrokinetics
#
###############################################################################
@@ -76,6 +80,11 @@ electrokinetics_d0 0.01
electrokinetics_d1 0.01
electrokinetics_eunit 1.0
electrokinetics_epsilon 3.3e3
+
+electrokinetics_rel_tol 1e-08
+electrokinetics_abs_tol 1e-15
+electrokinetics_maxits 2000
+
electrokinetics_init uniform
electrokinetics_init_rho_el 0.001
diff --git a/tests/regression/d3q19-elec/serial-elec-rr1.log b/tests/regression/d3q19-short/serial-elec-rr1.log
similarity index 93%
rename from tests/regression/d3q19-elec/serial-elec-rr1.log
rename to tests/regression/d3q19-short/serial-elec-rr1.log
index 72115f699..b509382e5 100644
--- a/tests/regression/d3q19-elec/serial-elec-rr1.log
+++ b/tests/regression/d3q19-short/serial-elec-rr1.log
@@ -1,6 +1,5 @@
Welcome to Ludwig v0.7.32 (Serial version running on 1 process)
-The SVN revision details are: 3209M
Note assertions via standard C assert() are on.
Read 36 user parameters from serial-elec-rr1.inp
@@ -30,14 +29,13 @@ Valency species 0: 1
Diffusivity species 0: 1.0000000e-02
Valency species 1: -1
Diffusivity species 1: 1.0000000e-02
+Solver type: sor
+Solver stencil points: 7
+Relative tolerance: 1.0000000e-08
+Absolute tolerance: 1.0000000e-15
+Max. no. of iterations: 2000
Number of multisteps: 1
-Number of skipsteps: 1
Diffusive accuracy in NPE: 0.0000000e+00
-Relative tolerance: 1.1920929e-07
-Absolute tolerance: 1.1920929e-09
-Max. no. of iterations: 10000
-I/O decomposition: 1 1 1
-I/O format: BINARY
Force calculation: phi_gradmu_correction
System properties
@@ -125,6 +123,10 @@ Scalars - total mean variance min max
[rho] 3.2726000e+01 1.9230769e-04 1.0000000e-03
[rho] 3.2726000e+01 0.0000000e+00 1.0003057e-03
[elc] -1.4922959e-15 -3.0566084e-07 1.9230769e-04
+[psi_zeta] 0.0000000e+00
+
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 -5.1748931944e+02 3.2716000000e+04 -1.5817621942e-02 0.0000000000e+00
Momentum - x y z
[total ] 4.5402571e-13 0.0000000e+00 5.0965010e-01
@@ -139,9 +141,6 @@ Colloid velocities - x y z
[minimum ] 0.0000000e+00 0.0000000e+00 1.0000000e-02
[maximum ] 0.0000000e+00 0.0000000e+00 1.0000000e-02
-SOR solver converged to relative tolerance
-SOR residual per site 4.6031502e-09 at 105 iterations
-1 multisteps
Scalars - total mean variance min max
[rho] 32716.00 1.00000000000 2.0078220e-08 0.99474397928 1.00525602072
@@ -171,13 +170,10 @@ Colloid velocities - x y z
[minimum ] 1.2272861e-17 -4.1743567e-18 5.2560207e-03
[maximum ] 1.2272861e-17 -4.1743567e-18 5.2560207e-03
-SOR solver converged to relative tolerance
-SOR residual per site 7.8603898e-11 at 110 iterations
-1 multisteps
Scalars - total mean variance min max
[rho] 32715.00 1.00000000000 3.1667262e-08 0.99486242850 1.00470540593
-[psi] -2.4471310e-14 -6.0146459e-04 1.3552052e-02
+[psi] -2.4471310e-14 -6.0146458e-04 1.3552052e-02
[rho] 3.2726000e+01 1.8867925e-04 1.0264264e-03
[rho] 3.2726000e+01 4.3470370e-20 1.0269783e-03
[elc] 2.4730652e-15 -5.5183543e-07 1.8867925e-04
diff --git a/tests/regression/d3q19-elec/serial-elec-rr2.inp b/tests/regression/d3q19-short/serial-elec-rr2.inp
similarity index 91%
rename from tests/regression/d3q19-elec/serial-elec-rr2.inp
rename to tests/regression/d3q19-short/serial-elec-rr2.inp
index 8b2a7d6d5..6b1668b58 100644
--- a/tests/regression/d3q19-elec/serial-elec-rr2.inp
+++ b/tests/regression/d3q19-short/serial-elec-rr2.inp
@@ -59,14 +59,18 @@ colloid_one_q1 0.0000
###############################################################################
freq_statistics 1
-config_at_end no
+freq_psi_resid 10
+config_at_end no
default_io_grid 1_1_1
colloid_io_freq 1000
+psi_io_mode mpiio
+psi_io_report no
+
###############################################################################
#
-# Electrokinetics ALWAYS 2 SPECIES FOR NOW
+# Electrokinetics
#
###############################################################################
@@ -76,6 +80,11 @@ electrokinetics_d0 0.01
electrokinetics_d1 0.01
electrokinetics_eunit 1.0
electrokinetics_epsilon 3.3e3
+
+electrokinetics_rel_tol 1e-08
+electrokinetics_abs_tol 1e-15
+electrokinetics_maxits 2000
+
electrokinetics_init uniform
electrokinetics_init_rho_el 0.001
diff --git a/tests/regression/d3q19-elec/serial-elec-rr2.log b/tests/regression/d3q19-short/serial-elec-rr2.log
similarity index 93%
rename from tests/regression/d3q19-elec/serial-elec-rr2.log
rename to tests/regression/d3q19-short/serial-elec-rr2.log
index 5a59df0e6..2ebc1b919 100644
--- a/tests/regression/d3q19-elec/serial-elec-rr2.log
+++ b/tests/regression/d3q19-short/serial-elec-rr2.log
@@ -1,6 +1,5 @@
Welcome to Ludwig v0.7.32 (Serial version running on 1 process)
-The SVN revision details are: 3209M
Note assertions via standard C assert() are on.
Read 38 user parameters from serial-elec-rr2.inp
@@ -30,14 +29,13 @@ Valency species 0: 1
Diffusivity species 0: 1.0000000e-02
Valency species 1: -1
Diffusivity species 1: 1.0000000e-02
+Solver type: sor
+Solver stencil points: 7
+Relative tolerance: 1.0000000e-08
+Absolute tolerance: 1.0000000e-15
+Max. no. of iterations: 2000
Number of multisteps: 1
-Number of skipsteps: 1
Diffusive accuracy in NPE: 0.0000000e+00
-Relative tolerance: 1.1920929e-07
-Absolute tolerance: 1.1920929e-09
-Max. no. of iterations: 10000
-I/O decomposition: 1 1 1
-I/O format: BINARY
Force calculation: phi_gradmu_correction
System properties
@@ -127,6 +125,10 @@ Scalars - total mean variance min max
[rho] 3.2725000e+01 1.8867925e-04 1.0000000e-03
[rho] 3.2725000e+01 0.0000000e+00 1.0003057e-03
[elc] 6.5021773e-15 -3.0567018e-07 1.8867925e-04
+[psi_zeta] 0.0000000e+00
+
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 -5.1747350393e+02 3.2715000000e+04 -1.5817622006e-02 0.0000000000e+00
Momentum - x y z
[total ] 4.5401183e-13 0.0000000e+00 5.0965010e-01
@@ -141,9 +143,6 @@ Colloid velocities - x y z
[minimum ] 0.0000000e+00 0.0000000e+00 1.0000000e-02
[maximum ] 0.0000000e+00 0.0000000e+00 1.0000000e-02
-SOR solver converged to relative tolerance
-SOR residual per site 4.5872319e-09 at 105 iterations
-1 multisteps
Scalars - total mean variance min max
[rho] 32715.00 1.00000000000 1.9422049e-08 0.99561998273 1.00525602072
@@ -173,9 +172,6 @@ Colloid velocities - x y z
[minimum ] 1.3724696e-17 -1.7125470e-20 5.2560207e-03
[maximum ] 1.3724696e-17 -1.7125470e-20 5.2560207e-03
-SOR solver converged to relative tolerance
-SOR residual per site 7.8574724e-11 at 110 iterations
-1 multisteps
Scalars - total mean variance min max
[rho] 32716.00 1.00000000000 3.1603349e-08 0.99563728266 1.00516207987
diff --git a/tests/regression/d3q19-elec/serial-elec-rr3.inp b/tests/regression/d3q19-short/serial-elec-rr3.inp
similarity index 92%
rename from tests/regression/d3q19-elec/serial-elec-rr3.inp
rename to tests/regression/d3q19-short/serial-elec-rr3.inp
index 0afd0c030..90b2dcf6d 100644
--- a/tests/regression/d3q19-elec/serial-elec-rr3.inp
+++ b/tests/regression/d3q19-short/serial-elec-rr3.inp
@@ -57,14 +57,18 @@ colloid_one_q1 0.0000
###############################################################################
freq_statistics 1
+freq_psi_resid 10
config_at_end no
default_io_grid 1_1_1
colloid_io_freq 1000
+psi_io_mode mpiio
+psi_io_report no
+
###############################################################################
#
-# Electrokinetics ALWAYS 2 SPECIES FOR NOW
+# Electrokinetics
#
###############################################################################
@@ -74,6 +78,11 @@ electrokinetics_d0 0.01
electrokinetics_d1 0.01
electrokinetics_eunit 1.0
electrokinetics_epsilon 3.3e3
+
+electrokinetics_rel_tol 1e-08
+electrokinetics_abs_tol 1e-15
+electrokinetics_maxits 2000
+
electrokinetics_init uniform
electrokinetics_init_rho_el 0.001
diff --git a/tests/regression/d3q19-elec/serial-elec-rr3.log b/tests/regression/d3q19-short/serial-elec-rr3.log
similarity index 92%
rename from tests/regression/d3q19-elec/serial-elec-rr3.log
rename to tests/regression/d3q19-short/serial-elec-rr3.log
index bee9c984e..d6c49f828 100644
--- a/tests/regression/d3q19-elec/serial-elec-rr3.log
+++ b/tests/regression/d3q19-short/serial-elec-rr3.log
@@ -1,6 +1,5 @@
Welcome to Ludwig v0.7.32 (Serial version running on 1 process)
-The SVN revision details are: 3209M
Note assertions via standard C assert() are on.
Read 36 user parameters from serial-elec-rr3.inp
@@ -30,14 +29,13 @@ Valency species 0: 1
Diffusivity species 0: 1.0000000e-02
Valency species 1: -1
Diffusivity species 1: 1.0000000e-02
+Solver type: sor
+Solver stencil points: 7
+Relative tolerance: 1.0000000e-08
+Absolute tolerance: 1.0000000e-15
+Max. no. of iterations: 2000
Number of multisteps: 1
-Number of skipsteps: 1
Diffusive accuracy in NPE: 0.0000000e+00
-Relative tolerance: 1.1920929e-07
-Absolute tolerance: 1.1920929e-09
-Max. no. of iterations: 10000
-I/O decomposition: 1 1 1
-I/O format: BINARY
Force calculation: phi_gradmu_correction
System properties
@@ -125,6 +123,10 @@ Scalars - total mean variance min max
[rho] 3.2726000e+01 1.9230769e-04 1.0000000e-03
[rho] 3.2726000e+01 0.0000000e+00 1.0003057e-03
[elc] -1.4933259e-15 -3.0566084e-07 1.9230769e-04
+[psi_zeta] 0.0000000e+00
+
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 -5.1748931944e+02 3.2716000000e+04 -1.5817621942e-02 0.0000000000e+00
Momentum - x y z
[total ] 4.5402571e-13 0.0000000e+00 5.0965010e-01
@@ -139,9 +141,6 @@ Colloid velocities - x y z
[minimum ] 0.0000000e+00 0.0000000e+00 1.0000000e-02
[maximum ] 0.0000000e+00 0.0000000e+00 1.0000000e-02
-SOR solver converged to relative tolerance
-SOR residual per site 4.6031502e-09 at 105 iterations
-1 multisteps
Scalars - total mean variance min max
[rho] 32716.00 1.00000000000 2.0078220e-08 0.99474397928 1.00525602072
@@ -171,13 +170,10 @@ Colloid velocities - x y z
[minimum ] 1.0872407e-17 -2.4106414e-18 5.2560207e-03
[maximum ] 1.0872407e-17 -2.4106414e-18 5.2560207e-03
-SOR solver converged to relative tolerance
-SOR residual per site 7.8603969e-11 at 110 iterations
-1 multisteps
Scalars - total mean variance min max
[rho] 32715.00 1.00000000000 3.1667262e-08 0.99486242850 1.00470540593
-[psi] -1.4641066e-14 -6.0146459e-04 1.3552052e-02
+[psi] -1.4641066e-14 -6.0146458e-04 1.3552052e-02
[rho] 3.2726000e+01 1.8867925e-04 1.0264264e-03
[rho] 3.2726000e+01 1.2785403e-22 1.0269783e-03
[elc] 2.4223787e-15 -5.5183543e-07 1.8867925e-04
@@ -203,9 +199,6 @@ Colloid velocities - x y z
[minimum ] 4.6899957e-18 5.7442582e-18 4.4861247e-03
[maximum ] 4.6899957e-18 5.7442582e-18 4.4861247e-03
-SOR solver converged to relative tolerance
-SOR residual per site 4.3258364e-12 at 100 iterations
-1 multisteps
Scalars - total mean variance min max
[rho] 32715.00 1.00000000000 3.1199459e-08 0.99620284837 1.00361727101
diff --git a/tests/regression/d3q19-elec/serial-elec-rr4.inp b/tests/regression/d3q19-short/serial-elec-rr4.inp
similarity index 92%
rename from tests/regression/d3q19-elec/serial-elec-rr4.inp
rename to tests/regression/d3q19-short/serial-elec-rr4.inp
index 94776dfbd..95886237f 100644
--- a/tests/regression/d3q19-elec/serial-elec-rr4.inp
+++ b/tests/regression/d3q19-short/serial-elec-rr4.inp
@@ -58,14 +58,18 @@ colloid_one_q1 0.0000
###############################################################################
freq_statistics 1
+freq_psi_resid 10
config_at_end no
default_io_grid 1_1_1
colloid_io_freq 1000
+psi_io_mode mpiio
+psi_io_report no
+
###############################################################################
#
-# Electrokinetics ALWAYS 2 SPECIES FOR NOW
+# Electrokinetics
#
###############################################################################
@@ -75,6 +79,11 @@ electrokinetics_d0 0.01
electrokinetics_d1 0.01
electrokinetics_eunit 1.0
electrokinetics_epsilon 3.3e3
+
+electrokinetics_rel_tol 1e-08
+electrokinetics_abs_tol 1e-15
+electrokinetics_maxits 2000
+
electrokinetics_init uniform
electrokinetics_init_rho_el 0.001
diff --git a/tests/regression/d3q19-elec/serial-elec-rr4.log b/tests/regression/d3q19-short/serial-elec-rr4.log
similarity index 93%
rename from tests/regression/d3q19-elec/serial-elec-rr4.log
rename to tests/regression/d3q19-short/serial-elec-rr4.log
index 81f572dd5..8b896829a 100644
--- a/tests/regression/d3q19-elec/serial-elec-rr4.log
+++ b/tests/regression/d3q19-short/serial-elec-rr4.log
@@ -1,6 +1,5 @@
Welcome to Ludwig v0.7.32 (Serial version running on 1 process)
-The SVN revision details are: 3209M
Note assertions via standard C assert() are on.
Read 38 user parameters from serial-elec-rr4.inp
@@ -30,14 +29,13 @@ Valency species 0: 1
Diffusivity species 0: 1.0000000e-02
Valency species 1: -1
Diffusivity species 1: 1.0000000e-02
+Solver type: sor
+Solver stencil points: 7
+Relative tolerance: 1.0000000e-08
+Absolute tolerance: 1.0000000e-15
+Max. no. of iterations: 2000
Number of multisteps: 1
-Number of skipsteps: 1
Diffusive accuracy in NPE: 0.0000000e+00
-Relative tolerance: 1.1920929e-07
-Absolute tolerance: 1.1920929e-09
-Max. no. of iterations: 10000
-I/O decomposition: 1 1 1
-I/O format: BINARY
Force calculation: phi_gradmu_correction
System properties
@@ -127,6 +125,10 @@ Scalars - total mean variance min max
[rho] 3.2725000e+01 1.8867925e-04 1.0000000e-03
[rho] 3.2725000e+01 0.0000000e+00 1.0003057e-03
[elc] 6.5746562e-15 -3.0567018e-07 1.8867925e-04
+[psi_zeta] 0.0000000e+00
+
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 -5.1747350393e+02 3.2715000000e+04 -1.5817622006e-02 0.0000000000e+00
Momentum - x y z
[total ] 4.5401183e-13 0.0000000e+00 5.0965010e-01
@@ -141,9 +143,6 @@ Colloid velocities - x y z
[minimum ] 0.0000000e+00 0.0000000e+00 1.0000000e-02
[maximum ] 0.0000000e+00 0.0000000e+00 1.0000000e-02
-SOR solver converged to relative tolerance
-SOR residual per site 4.5872319e-09 at 105 iterations
-1 multisteps
Scalars - total mean variance min max
[rho] 32715.00 1.00000000000 1.9422049e-08 0.99561998273 1.00525602072
@@ -173,9 +172,6 @@ Colloid velocities - x y z
[minimum ] 4.7845262e-18 4.6982895e-18 5.2560207e-03
[maximum ] 4.7845262e-18 4.6982895e-18 5.2560207e-03
-SOR solver converged to relative tolerance
-SOR residual per site 7.8574612e-11 at 110 iterations
-1 multisteps
Scalars - total mean variance min max
[rho] 32716.00 1.00000000000 3.1603349e-08 0.99563728266 1.00516207987
@@ -205,9 +201,6 @@ Colloid velocities - x y z
[minimum ] 1.2400469e-17 1.2170529e-17 4.4267044e-03
[maximum ] 1.2400469e-17 1.2170529e-17 4.4267044e-03
-SOR solver converged to relative tolerance
-SOR residual per site 4.3359265e-12 at 100 iterations
-1 multisteps
Scalars - total mean variance min max
[rho] 32716.00 1.00000000000 3.1084085e-08 0.99649224677 1.00374026557
diff --git a/tests/regression/d3q19-short/serial-init-bp1.log b/tests/regression/d3q19-short/serial-init-bp1.log
index c4bf36bc2..41934a490 100644
--- a/tests/regression/d3q19-short/serial-init-bp1.log
+++ b/tests/regression/d3q19-short/serial-init-bp1.log
@@ -95,6 +95,9 @@ Scalars - total mean variance min max
[Qyy] -2.5340841e-14 -7.7334108e-19 6.0000000e-02 -4.4966058e-01 4.4966058e-01
[Qyz] -1.4913071e-12 -4.5511080e-17 5.0000000e-02 -6.0000000e-01 6.0000000e-01
+Free energies - timestep f v f/v f_bulk/v f_grad/v redshift
+[fe] 0 1.3742090041e+02 3.2768000000e+04 4.1937530642e-03 4.1667013235e-03 2.7051740705e-05 8.3000000000e-01
+
Momentum - x y z
[total ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
[fluid ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-init-bp2.log b/tests/regression/d3q19-short/serial-init-bp2.log
index 8e7e46c49..3e4444284 100644
--- a/tests/regression/d3q19-short/serial-init-bp2.log
+++ b/tests/regression/d3q19-short/serial-init-bp2.log
@@ -95,6 +95,9 @@ Scalars - total mean variance min max
[Qyy] 0.0000000e+00 0.0000000e+00 8.9999982e-02 -6.0000000e-01 6.0000000e-01
[Qyz] -4.0156293e-04 -1.2254726e-08 4.5000009e-02 -3.0000000e-01 3.0000000e-01
+Free energies - timestep f v f/v f_bulk/v f_grad/v redshift
+[fe] 0 5.3918275382e+01 3.2768000000e+04 1.6454551813e-03 1.6347824504e-03 1.0672730938e-05 9.1000000000e-01
+
Momentum - x y z
[total ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
[fluid ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-init-br1.log b/tests/regression/d3q19-short/serial-init-br1.log
index d1124e8e3..3f32957d2 100644
--- a/tests/regression/d3q19-short/serial-init-br1.log
+++ b/tests/regression/d3q19-short/serial-init-br1.log
@@ -105,6 +105,9 @@ Scalars - total mean variance min max
[Qyy] 4.1466119e-13 1.2654455e-17 6.0000000e-02 -4.4966058e-01 4.4966058e-01
[Qyz] -1.5174528e-12 -4.6308985e-17 5.0000000e-02 -6.0000000e-01 6.0000000e-01
+Free energies - timestep f v f/v f_bulk/v f_grad/v redshift
+[fe] 0 1.6357908149e+02 3.2768000000e+04 4.9920373991e-03 4.1667013235e-03 8.2533607554e-04 8.3000000000e-01
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-init-br2.log b/tests/regression/d3q19-short/serial-init-br2.log
index 219cb486e..8ff613402 100644
--- a/tests/regression/d3q19-short/serial-init-br2.log
+++ b/tests/regression/d3q19-short/serial-init-br2.log
@@ -105,6 +105,9 @@ Scalars - total mean variance min max
[Qyy] 4.4785463e+02 1.3667439e-02 9.3490906e-02 -5.9885749e-01 6.0000000e-01
[Qyz] 1.2765777e+02 3.8958061e-03 4.4853901e-02 -2.9998998e-01 2.9998998e-01
+Free energies - timestep f v f/v f_bulk/v f_grad/v redshift
+[fe] 0 8.4309097066e+01 3.2768000000e+04 2.5729094563e-03 1.6530748961e-03 9.1983456029e-04 9.1000000000e-01
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-init-lcb.log b/tests/regression/d3q19-short/serial-init-lcb.log
index e2d9aaad9..1922f4251 100644
--- a/tests/regression/d3q19-short/serial-init-lcb.log
+++ b/tests/regression/d3q19-short/serial-init-lcb.log
@@ -97,6 +97,9 @@ Scalars - total mean variance min max
[Qyy] 6.8054311e+01 2.0768528e-03 2.6666083e-05 -4.9989978e-03 9.8864636e-03
[Qyz] 3.7123537e+00 1.1329204e-04 2.9388328e-05 -7.4853149e-03 7.4766459e-03
+Free energies - timestep f v f/v f_bulk/v f_grad/v redshift
+[fe] 0 -2.3437999391e-04 3.2768000000e+04 -7.1527097751e-09 -7.4628096480e-08 6.7475386705e-08 1.0000000000e+00
+
Momentum - x y z
[total ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
[fluid ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-init-lcr.log b/tests/regression/d3q19-short/serial-init-lcr.log
index bcf503cae..a92c51ce1 100644
--- a/tests/regression/d3q19-short/serial-init-lcr.log
+++ b/tests/regression/d3q19-short/serial-init-lcr.log
@@ -95,6 +95,9 @@ Scalars - total mean variance min max
[Qyy] -9.4761747e-01 -2.8918990e-05 1.9648064e-05 -5.0000000e-03 9.9995019e-03
[Qyz] 1.8663767e-01 5.6957296e-06 1.5185990e-05 -7.4997452e-03 7.4998120e-03
+Free energies - timestep f v f/v f_bulk/v f_grad/v redshift
+[fe] 0 4.2023235107e-02 3.2768000000e+04 1.2824473604e-06 -7.4628096480e-08 1.3570754569e-06 1.0000000000e+00
+
Momentum - x y z
[total ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
[fluid ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-le2d-fd1.log b/tests/regression/d3q19-short/serial-le2d-fd1.log
index 236fd67cf..67ecb50bf 100644
--- a/tests/regression/d3q19-short/serial-le2d-fd1.log
+++ b/tests/regression/d3q19-short/serial-le2d-fd1.log
@@ -90,6 +90,9 @@ Scalars - total mean variance min max
[rho] 4096.00 1.00000000000 0.0000000e+00 1.00000000000 1.00000000000
[phi] -1.1802440e-02 -2.8814551e-06 8.2680383e-04 -4.9977721e-02 4.9988335e-02
+Free energy density - timestep total fluid
+[fed] 0 -2.0247427840e-05 -2.0247427840e-05
+
Momentum - x y z
[total ] 1.5099033e-14 -3.3306691e-16 0.0000000e+00
[fluid ] 1.5099033e-14 -3.3306691e-16 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-le2d-fd2.log b/tests/regression/d3q19-short/serial-le2d-fd2.log
index 740972ac4..a17b1f020 100644
--- a/tests/regression/d3q19-short/serial-le2d-fd2.log
+++ b/tests/regression/d3q19-short/serial-le2d-fd2.log
@@ -89,6 +89,9 @@ Scalars - total mean variance min max
[rho] 4096.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
[phi] -1.1802440e-01 -2.8814551e-05 8.2680383e-02 -4.9977721e-01 4.9988335e-01
+Free energy density - timestep total fluid
+[fed] 0 5.8277975965e-04 5.8277975965e-04
+
Momentum - x y z
[total ] 5.6843419e-14 0.0000000e+00 0.0000000e+00
[fluid ] 5.6843419e-14 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-le2d-lb1.log b/tests/regression/d3q19-short/serial-le2d-lb1.log
index 53c82b930..198e1b0c8 100644
--- a/tests/regression/d3q19-short/serial-le2d-lb1.log
+++ b/tests/regression/d3q19-short/serial-le2d-lb1.log
@@ -92,6 +92,9 @@ Scalars - total mean variance min max
[rho] 4096.00 1.00000000000 0.0000000e+00 1.00000000000 1.00000000000
[phi] -1.1802440e-02 -2.8814551e-06 8.2680383e-04 -4.9977721e-02 4.9988335e-02
+Free energy density - timestep total fluid
+[fed] 0 -2.0247427840e-05 -2.0247427840e-05
+
Momentum - x y z
[total ] 3.1225023e-17 0.0000000e+00 0.0000000e+00
[fluid ] 3.1225023e-17 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-le3d-st1.log b/tests/regression/d3q19-short/serial-le3d-st1.log
index 156a97cee..b54b3202b 100644
--- a/tests/regression/d3q19-short/serial-le3d-st1.log
+++ b/tests/regression/d3q19-short/serial-le3d-st1.log
@@ -90,6 +90,9 @@ Scalars - total mean variance min max
[rho] 32768.00 1.00000000000 0.0000000e+00 1.00000000000 1.00000000000
[phi] 1.1826252e+01 3.6090857e-04 8.3228431e-04 -4.9999491e-02 4.9993448e-02
+Free energy density - timestep total fluid
+[fed] 0 -1.0291179264e-06 -1.0291179264e-06
+
Momentum - x y z
[total ] -2.1316282e-14 -1.2861240e-14 0.0000000e+00
[fluid ] -2.1316282e-14 -1.2861240e-14 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-le3d-st2.log b/tests/regression/d3q19-short/serial-le3d-st2.log
index 5392e86df..4a13a7a6b 100644
--- a/tests/regression/d3q19-short/serial-le3d-st2.log
+++ b/tests/regression/d3q19-short/serial-le3d-st2.log
@@ -90,6 +90,9 @@ Scalars - total mean variance min max
[rho] 32768.00 1.00000000000 0.0000000e+00 1.00000000000 1.00000000000
[phi] 1.1826252e+01 3.6090857e-04 8.3228431e-04 -4.9999491e-02 4.9993448e-02
+Free energy density - timestep total fluid
+[fed] 0 -1.0291179264e-06 -1.0291179264e-06
+
Momentum - x y z
[total ] -2.1316282e-14 -1.2861240e-14 0.0000000e+00
[fluid ] -2.1316282e-14 -1.2861240e-14 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-le3d-st3.log b/tests/regression/d3q19-short/serial-le3d-st3.log
index 9f4aacfc9..aca3bfc10 100644
--- a/tests/regression/d3q19-short/serial-le3d-st3.log
+++ b/tests/regression/d3q19-short/serial-le3d-st3.log
@@ -90,6 +90,9 @@ Scalars - total mean variance min max
[rho] 32768.00 1.00000000000 0.0000000e+00 1.00000000000 1.00000000000
[phi] 1.1826252e+01 3.6090857e-04 8.3228431e-04 -4.9999491e-02 4.9993448e-02
+Free energy density - timestep total fluid
+[fed] 0 -1.0291179264e-06 -1.0291179264e-06
+
Momentum - x y z
[total ] -2.1316282e-14 -1.2861240e-14 0.0000000e+00
[fluid ] -2.1316282e-14 -1.2861240e-14 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-le3d-st4.log b/tests/regression/d3q19-short/serial-le3d-st4.log
index b791ad620..22444160c 100644
--- a/tests/regression/d3q19-short/serial-le3d-st4.log
+++ b/tests/regression/d3q19-short/serial-le3d-st4.log
@@ -90,6 +90,9 @@ Scalars - total mean variance min max
[rho] 32768.00 1.00000000000 0.0000000e+00 1.00000000000 1.00000000000
[phi] 1.1826252e+01 3.6090857e-04 8.3228431e-04 -4.9999491e-02 4.9993448e-02
+Free energy density - timestep total fluid
+[fed] 0 -1.0291179264e-06 -1.0291179264e-06
+
Momentum - x y z
[total ] -2.1316282e-14 -1.2861240e-14 0.0000000e+00
[fluid ] -2.1316282e-14 -1.2861240e-14 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-le3d-st5.log b/tests/regression/d3q19-short/serial-le3d-st5.log
index 8ab73a5a2..304d6f409 100644
--- a/tests/regression/d3q19-short/serial-le3d-st5.log
+++ b/tests/regression/d3q19-short/serial-le3d-st5.log
@@ -90,6 +90,9 @@ Scalars - total mean variance min max
[rho] 32768.00 1.00000000000 0.0000000e+00 1.00000000000 1.00000000000
[phi] -1.5507344e+00 -4.7324657e-05 8.3289318e-04 -4.9998133e-02 4.9995155e-02
+Free energy density - timestep total fluid
+[fed] 0 -2.3211354094e-05 -2.3211354094e-05
+
Momentum - x y z
[total ] -2.1316282e-14 -1.2861240e-14 0.0000000e+00
[fluid ] -2.1316282e-14 -1.2861240e-14 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-le3d-st6.log b/tests/regression/d3q19-short/serial-le3d-st6.log
index de509d613..8f7b670f8 100644
--- a/tests/regression/d3q19-short/serial-le3d-st6.log
+++ b/tests/regression/d3q19-short/serial-le3d-st6.log
@@ -90,6 +90,9 @@ Scalars - total mean variance min max
[rho] 32768.00 1.00000000000 0.0000000e+00 1.00000000000 1.00000000000
[phi] -1.5507344e+00 -4.7324657e-05 8.3289318e-04 -4.9998133e-02 4.9995155e-02
+Free energy density - timestep total fluid
+[fed] 0 -2.3211354094e-05 -2.3211354094e-05
+
Momentum - x y z
[total ] -2.1316282e-14 -1.2861240e-14 0.0000000e+00
[fluid ] -2.1316282e-14 -1.2861240e-14 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-le3d-st7.log b/tests/regression/d3q19-short/serial-le3d-st7.log
index 3fec43165..5651bdb64 100644
--- a/tests/regression/d3q19-short/serial-le3d-st7.log
+++ b/tests/regression/d3q19-short/serial-le3d-st7.log
@@ -95,6 +95,9 @@ Scalars - total mean variance min max
[rho] 32768.00 1.00000000000 0.0000000e+00 1.00000000000 1.00000000000
[phi] -1.5507344e+00 -4.7324657e-05 8.3289318e-04 -4.9998133e-02 4.9995155e-02
+Free energy density - timestep total fluid
+[fed] 0 -2.3211354094e-05 -2.3211354094e-05
+
Momentum - x y z
[total ] 2.0816682e-17 2.4286129e-17 0.0000000e+00
[fluid ] 2.0816682e-17 2.4286129e-17 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-le3d-st8.log b/tests/regression/d3q19-short/serial-le3d-st8.log
index 5438ce313..2a27d7f21 100644
--- a/tests/regression/d3q19-short/serial-le3d-st8.log
+++ b/tests/regression/d3q19-short/serial-le3d-st8.log
@@ -90,6 +90,9 @@ Scalars - total mean variance min max
[rho] 32768.00 1.00000000000 0.0000000e+00 1.00000000000 1.00000000000
[phi] -1.5507344e+00 -4.7324657e-05 8.3289318e-04 -4.9998133e-02 4.9995155e-02
+Free energy density - timestep total fluid
+[fed] 0 -2.3211354094e-05 -2.3211354094e-05
+
Momentum - x y z
[total ] -2.1316282e-14 -1.2861240e-14 0.0000000e+00
[fluid ] -2.1316282e-14 -1.2861240e-14 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-muex-st1.log b/tests/regression/d3q19-short/serial-muex-st1.log
index c112cf6e1..b9547fac2 100644
--- a/tests/regression/d3q19-short/serial-muex-st1.log
+++ b/tests/regression/d3q19-short/serial-muex-st1.log
@@ -91,6 +91,9 @@ Scalars - total mean variance min max
[rho] 16384.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
[phi] 1.6263778e+04 9.9266224e-01 5.8870003e-03 -9.4336416e-01 1.0000000e+00
+Free energy density - timestep total fluid
+[fed] 0 -1.5496142043e-03 -1.5496142043e-03
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-pola-r01.log b/tests/regression/d3q19-short/serial-pola-r01.log
index 3847d4d7a..cf7f8d95a 100644
--- a/tests/regression/d3q19-short/serial-pola-r01.log
+++ b/tests/regression/d3q19-short/serial-pola-r01.log
@@ -88,6 +88,9 @@ Scalars - total mean variance min max
[Py ] 3.2504065e+03 1.2399317e-02 3.3318213e-01 -1.0000000e+00 1.0000000e+00
[Pz ] 3.2494065e+03 1.2395502e-02 3.3317841e-01 -1.0000000e+00 1.0000000e+00
+Free energy density - timestep total fluid
+[fed] 0 -2.4688264984e-02 -2.4688264984e-02
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-relx-bp1.log b/tests/regression/d3q19-short/serial-relx-bp1.log
index 41921288e..a5e00e015 100644
--- a/tests/regression/d3q19-short/serial-relx-bp1.log
+++ b/tests/regression/d3q19-short/serial-relx-bp1.log
@@ -95,6 +95,9 @@ Scalars - total mean variance min max
[Qyy] -2.5340841e-14 -7.7334108e-19 6.0000000e-02 -4.4966058e-01 4.4966058e-01
[Qyz] -1.4913071e-12 -4.5511080e-17 5.0000000e-02 -6.0000000e-01 6.0000000e-01
+Free energies - timestep f v f/v f_bulk/v f_grad/v redshift
+[fe] 0 1.3742090041e+02 3.2768000000e+04 4.1937530642e-03 4.1667013235e-03 2.7051740705e-05 8.3000000000e-01
+
Momentum - x y z
[total ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
[fluid ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-spin-c01.log b/tests/regression/d3q19-short/serial-spin-c01.log
index 88d700c45..a33e1aad0 100644
--- a/tests/regression/d3q19-short/serial-spin-c01.log
+++ b/tests/regression/d3q19-short/serial-spin-c01.log
@@ -120,6 +120,9 @@ Scalars - total mean variance min max
[rho] 261110.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
[phi] -1.1543906e+01 -4.4210890e-05 8.3500524e-04 -4.9999763e-02 4.9999902e-02
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 -6.0796618987e+00 2.6111000000e+05 -2.3283910607e-05 0.0000000000e+00
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-spin-c02.log b/tests/regression/d3q19-short/serial-spin-c02.log
index f09b58472..69d211a86 100644
--- a/tests/regression/d3q19-short/serial-spin-c02.log
+++ b/tests/regression/d3q19-short/serial-spin-c02.log
@@ -123,6 +123,9 @@ Scalars - total mean variance min max
[rho] 261110.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
[phi] -1.1543906e+01 -4.4210890e-05 8.3500524e-04 -4.9999763e-02 4.9999902e-02
+Free energies - timestep f v f/v f_s a f_s/a
+[fe] 0 -6.0796618987e+00 2.6111000000e+05 -2.3283910607e-05 0.0000000000e+00
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-spin-fd1.log b/tests/regression/d3q19-short/serial-spin-fd1.log
index 998c2e65c..1c4a4e5fc 100644
--- a/tests/regression/d3q19-short/serial-spin-fd1.log
+++ b/tests/regression/d3q19-short/serial-spin-fd1.log
@@ -87,6 +87,9 @@ Scalars - total mean variance min max
[rho] 262144.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
[phi] 3.1484764e+00 1.2010484e-05 8.3289934e-04 -4.9999916e-02 4.9999705e-02
+Free energy density - timestep total fluid
+[fed] 0 -2.3227909424e-06 -2.3227909424e-06
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-spin-fd2.log b/tests/regression/d3q19-short/serial-spin-fd2.log
index 65c08e475..7b726bca8 100644
--- a/tests/regression/d3q19-short/serial-spin-fd2.log
+++ b/tests/regression/d3q19-short/serial-spin-fd2.log
@@ -97,6 +97,9 @@ Scalars - total mean variance min max
[rho] 262144.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
[phi] 3.1484764e+00 1.2010484e-05 8.3289934e-04 -4.9999916e-02 4.9999705e-02
+Free energies - timestep f v f/v f_s1 fs_s2
+[fe] 0 -6.0642209766e-01 2.6214400000e+05 -2.3133167178e-06 0.0000000000e+00 0.0000000000e+00
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-spin-lb1.log b/tests/regression/d3q19-short/serial-spin-lb1.log
index 1f376c601..ac447cd6e 100644
--- a/tests/regression/d3q19-short/serial-spin-lb1.log
+++ b/tests/regression/d3q19-short/serial-spin-lb1.log
@@ -83,6 +83,9 @@ Scalars - total mean variance min max
[rho] 262144.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
[phi] 3.1484764e+00 1.2010484e-05 8.3289934e-04 -4.9999916e-02 4.9999705e-02
+Free energy density - timestep total fluid
+[fed] 0 -2.3227909424e-06 -2.3227909424e-06
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-spin-lb2.log b/tests/regression/d3q19-short/serial-spin-lb2.log
index 60f21935b..c15753b4d 100644
--- a/tests/regression/d3q19-short/serial-spin-lb2.log
+++ b/tests/regression/d3q19-short/serial-spin-lb2.log
@@ -88,6 +88,9 @@ Scalars - total mean variance min max
[rho] 32768.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
[phi] -5.9892076e+00 -1.8277611e-04 8.3100414e-04 -4.9989121e-02 4.9997941e-02
+Free energies - timestep f v f/v f_s1 fs_s2
+[fe] 0 -7.4302952403e-02 3.2768000000e+04 -2.2675461549e-06 0.0000000000e+00 0.0000000000e+00
+
Momentum - x y z
[total ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
[fluid ] 4.5474735e-13 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-spin-lb3.log b/tests/regression/d3q19-short/serial-spin-lb3.log
index ba9692705..064391245 100644
--- a/tests/regression/d3q19-short/serial-spin-lb3.log
+++ b/tests/regression/d3q19-short/serial-spin-lb3.log
@@ -85,6 +85,9 @@ Scalars - total mean variance min max
[rho] 32768.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
[phi] -5.9892076e+00 -1.8277611e-04 8.3100414e-04 -4.9989121e-02 4.9997941e-02
+Free energy density - timestep total fluid
+[fed] 0 -2.3206300630e-06 -2.3206300630e-06
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-spin-lb4.log b/tests/regression/d3q19-short/serial-spin-lb4.log
index 02616f61d..3aaa208d7 100644
--- a/tests/regression/d3q19-short/serial-spin-lb4.log
+++ b/tests/regression/d3q19-short/serial-spin-lb4.log
@@ -85,6 +85,9 @@ Scalars - total mean variance min max
[rho] 32768.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
[phi] -5.9892076e+00 -1.8277611e-04 8.3100414e-04 -4.9989121e-02 4.9997941e-02
+Free energy density - timestep total fluid
+[fed] 0 -2.3206300630e-06 -2.3206300630e-06
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-spin-n01.log b/tests/regression/d3q19-short/serial-spin-n01.log
index 7a3bb4188..20b896907 100644
--- a/tests/regression/d3q19-short/serial-spin-n01.log
+++ b/tests/regression/d3q19-short/serial-spin-n01.log
@@ -87,6 +87,9 @@ Scalars - total mean variance min max
[rho] 262144.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
[phi] 3.1484764e+00 1.2010484e-05 8.3289934e-04 -4.9999916e-02 4.9999705e-02
+Free energy density - timestep total fluid
+[fed] 0 -2.3227909424e-06 -2.3227909424e-06
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-spin-n02.log b/tests/regression/d3q19-short/serial-spin-n02.log
index 0e78eac82..62cd81183 100644
--- a/tests/regression/d3q19-short/serial-spin-n02.log
+++ b/tests/regression/d3q19-short/serial-spin-n02.log
@@ -87,6 +87,9 @@ Scalars - total mean variance min max
[rho] 262144.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
[phi] 3.1484764e+00 1.2010484e-05 8.3289934e-04 -4.9999916e-02 4.9999705e-02
+Free energy density - timestep total fluid
+[fed] 0 -2.3227909424e-06 -2.3227909424e-06
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-symm-dr1.log b/tests/regression/d3q19-short/serial-symm-dr1.log
index f4297f6eb..9b70d7ccc 100644
--- a/tests/regression/d3q19-short/serial-symm-dr1.log
+++ b/tests/regression/d3q19-short/serial-symm-dr1.log
@@ -88,6 +88,9 @@ Scalars - total mean variance min max
[rho] 262144.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
[phi] 2.2740611e+05 8.6748547e-01 2.1958671e-01 -1.0000000e+00 1.0000000e+00
+Free energy density - timestep total fluid
+[fed] 0 -1.5105107994e-03 -1.5105107994e-03
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-symm-dr2.log b/tests/regression/d3q19-short/serial-symm-dr2.log
index 49add1a36..3e3a70ea8 100644
--- a/tests/regression/d3q19-short/serial-symm-dr2.log
+++ b/tests/regression/d3q19-short/serial-symm-dr2.log
@@ -95,6 +95,9 @@ Scalars - total mean variance min max
[rho] 262144.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
[phi] 2.2740611e+05 8.6748547e-01 2.1958671e-01 -1.0000000e+00 1.0000000e+00
+Free energy density - timestep total fluid
+[fed] 0 -1.5105107994e-03 -1.5105107994e-03
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-symm-pat.log b/tests/regression/d3q19-short/serial-symm-pat.log
index f7f3b5e13..3409e168c 100644
--- a/tests/regression/d3q19-short/serial-symm-pat.log
+++ b/tests/regression/d3q19-short/serial-symm-pat.log
@@ -87,6 +87,9 @@ Scalars - total mean variance min max
[rho] 262144.00 1.00000000000 2.2204460e-16 1.00000000000 1.00000000000
[phi] 2.1006400e+05 8.0133057e-01 3.5786932e-01 -1.0000000e+00 1.0000000e+00
+Free energy density - timestep total fluid
+[fed] 0 -1.2299442998e-03 -1.2299442998e-03
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-tern-st1.log b/tests/regression/d3q19-short/serial-tern-st1.log
index 47340da8e..3fa93f95a 100644
--- a/tests/regression/d3q19-short/serial-tern-st1.log
+++ b/tests/regression/d3q19-short/serial-tern-st1.log
@@ -103,6 +103,9 @@ Scalars - total mean variance min max
[phi] -4.7000000e+01 -2.1759259e-03 2.3281934e-01 -1.0000000e+00 1.0000000e+00
[phi] 1.6571000e+04 7.6717593e-01 1.7861702e-01 0.0000000e+00 1.0000000e+00
+Free energies
+[surf/fl/tot] 0 0.0000000000e+00 5.3155555556e+00 5.3155555556e+00
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-tern-st2.log b/tests/regression/d3q19-short/serial-tern-st2.log
index ae18debee..5b978c828 100644
--- a/tests/regression/d3q19-short/serial-tern-st2.log
+++ b/tests/regression/d3q19-short/serial-tern-st2.log
@@ -103,6 +103,9 @@ Scalars - total mean variance min max
[phi] -4.7000000e+01 -2.1759259e-03 2.3281934e-01 -1.0000000e+00 1.0000000e+00
[phi] 1.6571000e+04 7.6717593e-01 1.7861702e-01 0.0000000e+00 1.0000000e+00
+Free energies
+[surf/fl/tot] 0 0.0000000000e+00 5.3155555556e+00 5.3155555556e+00
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-tern-st3.log b/tests/regression/d3q19-short/serial-tern-st3.log
index 4fde8b2a7..f05246524 100644
--- a/tests/regression/d3q19-short/serial-tern-st3.log
+++ b/tests/regression/d3q19-short/serial-tern-st3.log
@@ -103,6 +103,9 @@ Scalars - total mean variance min max
[phi] -4.7000000e+01 -2.1759259e-03 2.3281934e-01 -1.0000000e+00 1.0000000e+00
[phi] 1.6571000e+04 7.6717593e-01 1.7861702e-01 0.0000000e+00 1.0000000e+00
+Free energies
+[surf/fl/tot] 0 0.0000000000e+00 5.3155555556e+00 5.3155555556e+00
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-tern-st4.log b/tests/regression/d3q19-short/serial-tern-st4.log
index 1cd719979..0fe418480 100644
--- a/tests/regression/d3q19-short/serial-tern-st4.log
+++ b/tests/regression/d3q19-short/serial-tern-st4.log
@@ -118,6 +118,10 @@ Scalars - total mean variance min max
[phi] -2.7000000e+02 -6.7500000e-03 6.7495444e-01 -1.0000000e+00 1.0000000e+00
[phi] 1.3000000e+04 3.2500000e-01 2.1937500e-01 0.0000000e+00 1.0000000e+00
+Free energies
+[rho/phi/psi] 0 -4.0000000000e-01 -3.0000000000e-03 1.6500000000e-01
+[surf/fl/tot] 0 -2.3800000000e-01 3.2824083333e+00 3.0444083333e+00
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/regression/d3q19-short/serial-tern-st5.log b/tests/regression/d3q19-short/serial-tern-st5.log
index 2dbc96508..529d50b56 100644
--- a/tests/regression/d3q19-short/serial-tern-st5.log
+++ b/tests/regression/d3q19-short/serial-tern-st5.log
@@ -117,6 +117,10 @@ Scalars - total mean variance min max
[phi] -2.7000000e+02 -6.7500000e-03 6.7495444e-01 -1.0000000e+00 1.0000000e+00
[phi] 1.3000000e+04 3.2500000e-01 2.1937500e-01 0.0000000e+00 1.0000000e+00
+Free energies
+[rho/phi/psi] 0 -4.0000000000e-01 -3.0000000000e-03 1.6500000000e-01
+[surf/fl/tot] 0 -2.3800000000e-01 3.2824083333e+00 3.0444083333e+00
+
Momentum - x y z
[total ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
[fluid ] 0.0000000e+00 0.0000000e+00 0.0000000e+00
diff --git a/tests/repository-dump.sh b/tests/repository-dump.sh
deleted file mode 100755
index b2c8b1fc3..000000000
--- a/tests/repository-dump.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-##############################################################################
-#
-# repository-dump.sh
-#
-# This script backs up the SVN repository via svnadmin dump.
-# As we are remote, this requires first getting a local copy of the
-# whole repository, done using svnsync.
-#
-# Could be, e.g., invoked by cron.
-#
-# $Id$
-#
-# Edinburgh Soft Matter and Statistical Physics Group and
-# Edinburgh Parallel Computing Centre
-#
-# Kevin Stratford (kevin@epcc.ed.ac.uk)
-# (c) 2011 The University of Edinburgh
-#
-##############################################################################
-#!/bin/bash
-
-copydirectory=/home/kevin/nightly/copy
-dumpfile=/home/kevin/nightly/repository-`date +%F`.dmp
-
-# Make a temporary local repository in $copydirectory
-
-svnadmin create $copydirectory
-
-# Allow svn to make revision changes to $copydirectory
-
-echo '#!/bin/sh' > $copydirectory/hooks/pre-revprop-change
-chmod +x $copydirectory/hooks/pre-revprop-change
-
-# Sync the new copy with existing repository
-
-svnsync init file://$copydirectory http://ccpforge.cse.rl.ac.uk/svn/ludwig
-svnsync sync file://$copydirectory
-
-# Dump the whole thing to a file and remove the copy
-
-svnadmin dump $copydirectory > $dumpfile
-rm -rf $copydirectory
-
diff --git a/tests/test-all.sh b/tests/test-all.sh
deleted file mode 100755
index 676bf53a9..000000000
--- a/tests/test-all.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-##############################################################################
-#
-# test-all.sh
-#
-# Just a convenience to run all tests...
-#
-# Edinburgh Soft Matter and Statistical Physics Group and
-# Edinburgh Parallel Computing Centre
-#
-# Kevin Stratford (kevin@epcc.ed.ac.uk)
-# (c) 2014-2015 The University of Edinburgh
-#
-##############################################################################
-#!/bin/bash
-
-make compile-run-serial-d2q9
-make compile-run-serial-d2q9r
-make compile-run-serial-d3q15
-make compile-run-serial-d3q15r
-make compile-run-serial-d3q19
-make compile-run-serial-d3q19r
-
-make compile-run-mpi-d2q9
-make compile-run-mpi-d2q9r
-make compile-run-mpi-d3q15
-make compile-run-mpi-d3q15r
-make compile-run-mpi-d3q19
-make compile-run-mpi-d3q19r
-
-
-#. ./test-mpix08.sh -u d3q19 long08
-#. ./test-long64.sh -r d3q19 long64
diff --git a/tests/test-gpu-01.sh b/tests/test-gpu-01.sh
deleted file mode 100755
index 4e666f196..000000000
--- a/tests/test-gpu-01.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-##############################################################################
-#
-# test-gpu-01.sh
-#
-# Only d3q19r regrssion tests at the moment
-# Serial only, until a parallel test machine is available.
-#
-##############################################################################
-
-# This is intended for the nightly test, so this copy must be here
-
-echo "TEST --> GPU serial"
-cp ../config/lunix-nvcc-default.mk ../config.mk
-make clean
-make compile-serial-d3q19r
-make run-serial-regr-d3q19r
diff --git a/tests/test-simdvl.sh b/tests/test-simdvl.sh
deleted file mode 100755
index 44ea838cf..000000000
--- a/tests/test-simdvl.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash
-##############################################################################
-#
-# test-simdvl.sh
-#
-# Serial tests only.
-#
-# Edinburgh Soft Matter and Statistical Physics Group and
-# Edinburgh Parallel Computing Centre
-#
-# (c) 2016 The University of Edinburgh
-# Kevin Stratford (kevin@epcc.ed.ac.uk)
-#
-##############################################################################
-
-# This is intended for the nightly test, so this copy must be here
-
-echo "TEST --> SIMD VECTOR LENGTH TWO"
-cp ../config/lunix-gcc-simdvl2.mk ../config.mk
-make clean
-make compile-run-serial-d3q15
-make compile-run-serial-d3q19
-
diff --git a/tests/test.sh b/tests/test.sh
index 9af14518c..0f9e2a2e5 100755
--- a/tests/test.sh
+++ b/tests/test.sh
@@ -18,7 +18,7 @@
# Edinburgh Soft Matter and Statisical Physics Group and
# Edinburgh Parallel Computing Centre
#
-# (c) 2014-2020 The University of Edinburgh
+# (c) 2014-2023 The University of Edinburgh
#
# Contributing authors:
# Kevin Stratford (kevin@epcce.ed.ac.uk)
@@ -49,7 +49,8 @@ function main() {
stub=`echo $input | sed 's/.inp//'`
echo
- ${launch_mpi} ${executable} $input > $stub.new
+ ln -s -f ${input} input
+ ${launch_mpi} ${executable} > $stub.new
# Get difference via the difference script
${launch_serial} ${test_diff} $stub.new $stub.log
@@ -63,6 +64,8 @@ function main() {
echo "PASS ./$input"
fi
+ rm -f input
+
return
}
diff --git a/tests/titan-gpu/config.mk b/tests/titan-gpu/config.mk
deleted file mode 100644
index 652801d79..000000000
--- a/tests/titan-gpu/config.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-
-CC=nvcc
-MPICC=nvcc
-CFLAGS=-O2 -arch=sm_35 -x cu -dc -DKEEPFIELDONTARGET -DKEEPHYDROONTARGET -DOVERLAP
-
-AR = ar
-ARFLAGS = -cru
-LDFLAGS=-arch=sm_35
-
-MPI_INCL=-I/opt/cray/mpt/default/gni/mpich2-CRAY64/8.3/include
-
-#cray mpich
-MPI_LIBS=/opt/cray/mpt/default/gni/mpich2-CRAY64/8.3/lib/libmpich.a
-#dependencies of mpich
-MPI_LIBS+= /opt/cray/pmi/default/lib64/libpmi.a /opt/cray/alps/default/lib64/libalps.a /opt/cray/alps/default/lib64/libalpslli.a /opt/cray/alps/default/lib64/libalpsutil.a /opt/cray/dmapp/default/lib64/libdmapp.a /opt/cray/ugni/default/lib64/libugni.a /opt/cray/xpmem/default/lib64/libxpmem.a /opt/cray/wlm_detect/default/lib64/libwlm_detect.a /opt/cray/udreg/default/lib64/libudreg.a
-
-LAUNCH_SERIAL_CMD=
-LAUNCH_MPI_CMD=mpirun
-LAUNCH_MPI_NP_SWITCH=-np
diff --git a/tests/titan-gpu/input b/tests/titan-gpu/input
deleted file mode 100644
index 19a11c92d..000000000
--- a/tests/titan-gpu/input
+++ /dev/null
@@ -1,406 +0,0 @@
-##############################################################################
-#
-# Ludwig input file
-# Reference.
-#
-# Lines introduced with # and blank lines are ignored.
-#
-# The file is made up of a series of (case-sensitive) keyword value
-# pairs which should be separated by a space:
-#
-# keyword value
-#
-# Components of vector values are separated by an underscore, e.g.,
-# force 0.01_0.00_0.00
-#
-# If a given keyword does not appear, or is commented out, a default
-# value will be used.
-#
-##############################################################################
-
-##############################################################################
-#
-# Run duration
-#
-# N_start If N_start > 0, this is a restart from previous output
-#
-# N_cycles number of lattice Boltzmann time steps to run
-# (if it's a restart, this is still the number of steps
-# to run, not the final step)
-#
-###############################################################################
-
-N_start 0
-N_cycles 1000
-
-##############################################################################
-#
-# System and MPI
-#
-# size NX_NY_NZ is the size of the system in lattice units
-# grid PX_PY_PZ is the processor decomposition
-# If PX*PY*PZ is not equal to the number of processors,
-# MPI will choose a default (may be implementation-dependent).
-#
-# reduced_halo [yes|no] use reduced or full halos. Using reduced halos
-# is *only* appropriate for fluid only problems.
-# Default is no.
-#
-##############################################################################
-
-size 128_128_128
-#grid GRID
-reduced_halo no
-
-##############################################################################
-#
-# Fluid parameters
-#
-# viscosity shear viscosity [default is 1/6, ie., relaxation time 1]
-# viscosity_bulk bulk viscosity [default = shear viscosity]
-#
-# isothermal_fluctuations [on|off] Default is off.
-# temperature isothermal fluctuation 'temperature'
-#
-# ghost_modes [on|off] Default is on.
-# force FX_FY_FZ Uniform body force on fluid (default zero)
-#
-##############################################################################
-
-viscosity 1.0
-#viscosity_bulk 1.0
-
-isothermal_fluctuations off
-temperature 0.00002133333
-
-# ghost_modes off
-# force 0.00_0.0_0.0
-
-##############################################################################
-#
-# Free energy parameters
-#
-# free_energy none single fluid only [the default]
-#
-# Otherwise
-#
-# free_energy symmetric
-# brazovskii
-# surfactant
-# polar_active
-# lc_blue_phase
-#
-# symmetric_lb symmetric with 2 distributions
-#
-# fd_advection_scheme_order 1-7
-# sets order of finite difference
-# advection scheme
-#
-# fd_gradient_calcualtion Scheme to yse for gradient calculations
-# 2d_5pt_fluid
-# 3d_7pt_fluid
-# 3d_27pt_fluid
-# 3d_27pt_solid
-#
-# Note: only parameters for the currently selected free energy at
-# run time are meaningful; you don't have to comment out all the others.
-#
-###############################################################################
-
-free_energy lc_blue_phase
-
-fd_advection_scheme_order 3
-fd_gradient_calculation 3d_7pt_fluid
-
-###############################################################################
-#
-# Symmetric / Brazovskii
-#
-# A symmetric bulk parameter (A < 0 for binary fluid)
-# B symmetric bulk parameter (B = -A for binary fluid)
-# kappa surface 'penalty' parameter (kappa > 0 for binary fluid)
-# C additional brazovskki parameter (C = 0 for binary fluid)
-#
-# mobility Order parameter mobility M
-#
-# phi_initialisation spinodal or block [spinodal]
-# noise magnitude of initial order parameter noise [default 0.05]
-# phi0 mean order parameter
-#
-#
-###############################################################################
-
-A -0.0625
-B 0.0625
-K 0.04
-C 0.0
-
-mobility 0.15
-
-noise 0.05
-phi0 0.0
-phi_initialisation spinodal
-
-###############################################################################
-#
-# Surfactant free energy; set
-#
-# In addition to A, B, K, of the symmrtric binary fluid, there are the
-# extra parameters
-#
-# surf_kT bulk surfactant parameter
-# surf_epsilon surface term
-# surf_beta non-linear term
-# surf_W entropy term
-#
-# surf_mobility_phi fluid order parameter mobility
-# surf_mobility_psi surfactant order parameter mobility
-# surf_psi_b initial uniform (background) concentration
-#
-###############################################################################
-
-surf_A -0.0208333
-surf_B 0.0208333
-surf_kappa 0.12
-
-surf_kT 0.00056587
-surf_epsilon 0.03
-surf_beta 0.0
-surf_W 0.0
-
-surf_mobility_phi 0.15
-surf_mobility_psi 2.0
-surf_psi_b 0.01
-
-###############################################################################
-#
-# Blue Phase free energy
-#
-# lc_a0
-# lc_gamma
-# lc_q0
-# lc_kappa0
-# lc_kappa1
-# lc_xi
-#
-# lc_q_initialisation twist
-# o8m
-# o2
-#
-# lc_q_init_amplitude scalar order parameter amplitude for initialisation
-#
-# Typically BPI o8m amplitude -0.2
-# BPII o2 amplitude +0.3
-# simple cholesteric twist (z-axis) amplitude +1/3
-#
-###############################################################################
-
-lc_a0 0.01
-lc_gamma 3.0
-lc_q0 0.19635
-lc_kappa0 0.000648456
-lc_kappa1 0.000648456
-lc_xi 0.7
-
-lc_Gamma 0.5
-lc_active_zeta 0.0
-
-lc_q_initialisation twist
-lc_q_init_amplitude 0.333333333333333
-lc_init_redshift 1.0
-lc_init_nematic 1.0_0.0_0.0
-
-lc_anchoring_method two
-lc_wall_anchoring normal
-lc_coll_anchoring normal
-lc_anchoring_strength_colloid 0.002593824
-
-
-###############################################################################
-#
-# polar active gel
-#
-###############################################################################
-
-polar_active_a -0.1
-polar_active_b +0.1
-polar_active_k 0.01
-polar_active_klc 0.02
-polar_active_zeta 0.0
-polar_active_lambda 0.0
-
-leslie_ericksen_gamma 0.3
-leslie_ericksen_swim 0.0
-
-###############################################################################
-#
-# Colloid parameters
-#
-# colloid_init: no_colloids [default]
-# from_file
-# random (see below)
-# colloid_type: inactive bbl [default]
-# active Include active terms in BBL
-# subgrid No bbl ("unresolved particles")
-#
-# colloid_cell_min:
-# This MUST be set if colloids are present: it specifies
-# the minimum cell list width, and must be at least 2ah
-# + delta, where delta catches any colloid-colloid
-# interactions.
-#
-###############################################################################
-
-colloid_init no_colloids
-colloid_type inactive
-
-colloid_random_no 1
-colloid_random_a0 7.25
-colloid_random_ah 7.25
-colloid_random_dh 0.4
-colloid_random_r0 32.0_32.0_32.0
-colloid_random_v0 0.0_0.0_0.0
-colloid_random_s0 1.0_0.0_0.0
-colloid_random_m0 1.0_0.0_0.0
-
-# Constant body force on all colloids ("gravity")
-
-colloid_cell_list_interactions no
-colloid_cell_min 4.0
-colloid_gravity 0.0_0.0_0.0
-
-# Colloid-colloid lubrication corrections
-
-lubrication_on 0
-lubrication_normal_cutoff 0.3
-lubrication_tangential_cutoff 0.0
-
-###############################################################################
-#
-# Colloid-colloid soft-sphere potential parameters
-# The soft sphere is always needed
-#
-###############################################################################
-
-soft_sphere_on 0
-soft_sphere_epsilon 0.04
-soft_sphere_sigma 0.1
-soft_sphere_nu 1.0
-soft_sphere_cutoff 0.25
-
-# Lennard Jones
-lennard_jones_on 0
-lj_sigma 2.3
-lj_cutoff 4.6
-lj_epsilon 0.0003
-
-###############################################################################
-#
-# Periodic conditions / boundaries
-#
-# boundary_walls_on [yes|no] Use built-in side walls [default no]
-# periodicity X_Y_Z Sets periodic boundary conditions in coordinate
-# directions [default is 1_1_1]. Best to leave this
-# unchanged
-# boundary_speed_top For use with built-in walls
-# boundary_speed_bottom For use with built-in walls
-#
-# porous_media_file filestub If present, the file filestub.001-001
-# should contain porous media data
-# porous_media_format [ASCII|BINARY] file format [default BINARY]
-# porous_media_type [status_only|status_with_h]
-# determines type of porous media data to be
-# supplied
-#
-###############################################################################
-
-boundary_walls_on no
-periodicity 1_1_1
-boundary_speed_bottom 0.0
-boundary_speed_top 0.0
-
-#porous_media_format BINARY
-#porous_media_file capillary_8_8_32.dat
-#porous_media_type status_only
-
-###############################################################################
-#
-# Output frequency and type
-#
-# freq_statistics N Output diagnostics every N steps
-# freq_output N Output field state every N steps
-# freq_config N Output full configuration (for restart) every
-# N steps (can be large!)
-# freq_phi N phi data output frequency
-# freq_vel N velocity data output frequency
-# freq_shear_measurement stress profile accumulator
-# freq_shear_output stress profile output
-# config_at_end [yes|no] write full configuration at end of run
-# [default is yes]
-#
-# io_grid NX_NY_NZ Cartesian processor I/O grid. Default is 1_1_1
-# The following for particle data are under review...
-# n_io_nodes Number of I/O processors for particles
-# output_format [ASCII|BINARY] default output format
-# input_format [ASCII|BINARY] default input format
-#
-# phi_format Override default format for particular quantities
-# etc... (both input and output)
-#
-###############################################################################
-
-freq_statistics 10000
-freq_measure 500000
-freq_config 200000
-freq_phi 200000
-freq_vel 300000
-freq_shear_measurement 100000
-freq_shear_output 100000
-config_at_end no
-
-distribution_io_grid 1_1_1
-
-phi_format BINARY
-vel_format BINARY
-
-colloid_io_freq 10000000
-colloids_io_grid 1_1_1
-colloid_io_format_input ASCII
-colloid_io_format_output ASCII
-
-qs_dir_format BINARY
-
-###############################################################################
-#
-# Lees-Edwards planes
-#
-# These parameters set up a number of equally spaced planes
-# with constant velocity.
-#
-# N_LE_plane the number of planes
-# LE_plane_vel the y-component of the plane velocity
-# LE_init_profile set the initial velocity profile to be consistent with
-# desired shear rate. (Only valid at t = 0). [0|1]
-#
-# LE_oscillation_period
-# Integer > 1, switches on u = u_0 cos(2\pi t/T) where
-# u_0 is maximum plane velocity set via LE_plane_vel,
-# and T is the oscillation period
-#
-###############################################################################
-
-#N_LE_plane 2
-#LE_plane_vel 0.008
-#LE_init_profile 1
-#LE_oscillation_period 0
-
-###############################################################################
-#
-# Miscellaneous
-#
-# random_seed +ve integer is the random number generator seed
-#
-###############################################################################
-
-#random_seed 7361237
-random_seed 8361235
diff --git a/tests/unit/Makefile b/tests/unit/Makefile
index 5805fcb75..06dd21797 100644
--- a/tests/unit/Makefile
+++ b/tests/unit/Makefile
@@ -12,7 +12,7 @@
# Edinburgh Soft Matter and Statistical Physics Group and
# Edinburgh Parallel Computing Centre
#
-# (c) 2010-2022 The University of Edinburgh
+# (c) 2010-2023 The University of Edinburgh
#
# Contributing authors:
# Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -45,6 +45,11 @@ LIBS = $(BLIBS) $(SRC)/libludwig.a -lm
MPI_RUN = $(LAUNCH_MPIRUN_CMD) $(MPIRUN_NTASK_FLAG) $(MPIRUN_NTASKS)
+ifdef HAVE_PETSC
+INCL += $(PETSC_INCL)
+LIBS += $(PETSC_LIB)
+endif
+
#------------------------------------------------------------------------------
# Rules
#------------------------------------------------------------------------------
@@ -61,6 +66,7 @@ test:
clean:
$(RM) core *.o a.out
+ $(RM) -f *gcno *gcda
#------------------------------------------------------------------------------
# Implicit Rules
diff --git a/tests/unit/test_blue_phase.c b/tests/unit/test_blue_phase.c
index 716b47392..7c9f81aca 100644
--- a/tests/unit/test_blue_phase.c
+++ b/tests/unit/test_blue_phase.c
@@ -44,7 +44,7 @@ int test_fe_lc_dimensionless_field_strength(pe_t * pe);
__host__ int do_test_fe_lc_device1(pe_t * pe, cs_t * cs, fe_lc_t * fe);
-__global__ void do_test_fe_lc_kernel1(fe_lc_t * fe, fe_lc_param_t ref);
+__global__ void do_test_fe_lc_kernel1(fe_lc_t * fe, const fe_lc_param_t * ref);
/*****************************************************************************
@@ -959,8 +959,15 @@ __host__ int do_test_fe_lc_device1(pe_t * pe, cs_t * cs, fe_lc_t * fe) {
kernel_launch_param(1, &nblk, &ntpb);
ntpb.x = 1;
- tdpLaunchKernel(do_test_fe_lc_kernel1, nblk, ntpb, 0, 0, fetarget, param);
- tdpDeviceSynchronize();
+ {
+ fe_lc_param_t * p = NULL;
+ tdpAssert(tdpMalloc((void **) &p, sizeof(fe_lc_param_t)));
+ tdpAssert(tdpMemcpy(p, ¶m, sizeof(fe_lc_param_t),
+ tdpMemcpyHostToDevice));
+ tdpLaunchKernel(do_test_fe_lc_kernel1, nblk, ntpb, 0, 0, fetarget, p);
+ tdpDeviceSynchronize();
+ tdpAssert(tdpFree(p));
+ }
physics_free(phys);
@@ -973,7 +980,8 @@ __host__ int do_test_fe_lc_device1(pe_t * pe, cs_t * cs, fe_lc_t * fe) {
*
*****************************************************************************/
-__global__ void do_test_fe_lc_kernel1(fe_lc_t * fe, fe_lc_param_t ref) {
+__global__ void do_test_fe_lc_kernel1(fe_lc_t * fe,
+ const fe_lc_param_t * pref) {
fe_lc_param_t p;
PI_DOUBLE(pi);
@@ -984,11 +992,11 @@ __global__ void do_test_fe_lc_kernel1(fe_lc_t * fe, fe_lc_param_t ref) {
/* epsilon is sclaed by a factor of 12pi within fe_lc */
- test_assert(fabs(p.a0 - ref.a0) < DBL_EPSILON);
- test_assert(fabs(p.gamma - ref.gamma) < DBL_EPSILON);
- test_assert(fabs(p.kappa0 - ref.kappa0) < DBL_EPSILON);
- test_assert(fabs(12.0*pi*p.epsilon - ref.epsilon) < FLT_EPSILON);
- test_assert(fabs(p.redshift - ref.redshift) < DBL_EPSILON);
+ test_assert(fabs(p.a0 - pref->a0) < DBL_EPSILON);
+ test_assert(fabs(p.gamma - pref->gamma) < DBL_EPSILON);
+ test_assert(fabs(p.kappa0 - pref->kappa0) < DBL_EPSILON);
+ test_assert(fabs(12.0*pi*p.epsilon - pref->epsilon) < FLT_EPSILON);
+ test_assert(fabs(p.redshift - pref->redshift) < DBL_EPSILON);
return;
}
diff --git a/tests/unit/test_fe_electro.c b/tests/unit/test_fe_electro.c
index 2158c5193..0c3094c6c 100644
--- a/tests/unit/test_fe_electro.c
+++ b/tests/unit/test_fe_electro.c
@@ -7,7 +7,7 @@
* Edinburgh Soft Matter and Statistical Phsyics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2014-2017 The University of Edinburgh
+ * (c) 2014-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -79,11 +79,9 @@ int test_fe_electro_suite(void) {
static int do_test1(pe_t * pe, cs_t * cs, physics_t * phys) {
- int nk = 2;
- double valency[2] = {1, 2};
- double kt = 2.0;
- double eunit = 3.0;
psi_t * psi = NULL;
+ double kt = 2.0;
+ int valency[2] = {1, 2};
int index = 1;
double rho0, rho1; /* Test charge densities */
@@ -96,8 +94,18 @@ static int do_test1(pe_t * pe, cs_t * cs, physics_t * phys) {
assert(cs);
assert(phys);
- psi_create(pe, cs, nk, &psi);
- psi_unit_charge_set(psi, eunit);
+ {
+ int nhalo = 0;
+ cs_nhalo(cs, &nhalo);
+ {
+ psi_options_t opts = psi_options_default(nhalo);
+ opts.e = 3.0;
+ opts.beta = 1.0/kt;
+ opts.valency[0] = valency[0];
+ opts.valency[1] = valency[1];
+ psi_create(pe, cs, &opts, &psi);
+ }
+ }
physics_kt_set(phys, kt);
@@ -139,13 +147,11 @@ static int do_test1(pe_t * pe, cs_t * cs, physics_t * phys) {
fed1 += rho1*0.5*valency[1]*psi0;
psi_psi_set(psi, index, psi0);
- psi_valency_set(psi, 0, valency[0]);
- psi_valency_set(psi, 1, valency[1]);
fe_electro_fed(fe, index, &fed);
test_assert(fabs(fed - (fed0 + fed1)) < DBL_EPSILON);
fe_electro_free(fe);
- psi_free(psi);
+ psi_free(&psi);
return 0;
}
@@ -160,12 +166,10 @@ static int do_test1(pe_t * pe, cs_t * cs, physics_t * phys) {
int do_test2(pe_t * pe, cs_t * cs, physics_t * phys) {
- int n;
- int nk = 3;
- double kt = 0.1;
- double eunit = 1.0;
- double valency[3] = {3, 2, 1};
psi_t * psi = NULL;
+ double eunit = 1.0;
+ double kt = 0.1;
+ int valency[3] = {3, 2, 1};
int index = 1;
double rho0; /* Test charge density */
@@ -179,18 +183,30 @@ int do_test2(pe_t * pe, cs_t * cs, physics_t * phys) {
assert(cs);
assert(phys);
- psi_create(pe, cs, nk, &psi);
- psi_unit_charge_set(psi, eunit);
+ {
+ int nhalo = 0;
+ cs_nhalo(cs, &nhalo);
+ {
+ psi_options_t opts = psi_options_default(nhalo);
+ opts.nk = 3;
+ opts.e = eunit;
+ opts.beta = 1.0/kt;
+ opts.valency[0] = valency[0];
+ opts.valency[1] = valency[1];
+ opts.valency[2] = valency[2];
+ psi_create(pe, cs, &opts, &psi);
+ }
+ }
+
physics_kt_set(phys, kt);
fe_electro_create(pe, psi, &fe);
assert(fe);
- for (n = 0; n < 3; n++) {
+ for (int n = 0; n < 3; n++) {
rho0 = 1.0 + 1.0*n;
psi_rho_set(psi, index, n, rho0);
- psi_valency_set(psi, n, valency[n]);
-
+
/* For psi = 0, have mu_a = kT log(rho_a) */
psi0 = 0.0;
psi_psi_set(psi, index, psi0);
@@ -207,7 +223,7 @@ int do_test2(pe_t * pe, cs_t * cs, physics_t * phys) {
}
fe_electro_free(fe);
- psi_free(psi);
+ psi_free(&psi);
return 0;
}
@@ -223,7 +239,6 @@ int do_test2(pe_t * pe, cs_t * cs, physics_t * phys) {
static int do_test3(pe_t * pe, cs_t * cs, physics_t * phys) {
- int nk = 2;
int index;
int ia, ib;
psi_t * psi = NULL;
@@ -245,9 +260,19 @@ static int do_test3(pe_t * pe, cs_t * cs, physics_t * phys) {
assert(cs);
assert(phys);
- psi_create(pe, cs, nk, &psi);
- psi_epsilon_set(psi, epsilon);
- psi_unit_charge_set(psi, eunit);
+ {
+ int nhalo = 0;
+ cs_nhalo(cs, &nhalo);
+ {
+ psi_options_t opts = psi_options_default(nhalo);
+ opts.e = eunit;
+ opts.beta = 1.0/kt;
+ opts.epsilon1 = epsilon;
+ opts.epsilon2 = epsilon;
+ psi_create(pe, cs, &opts, &psi);
+ }
+ }
+
fe_electro_create(pe, psi, &fe);
assert(fe);
@@ -268,6 +293,7 @@ static int do_test3(pe_t * pe, cs_t * cs, physics_t * phys) {
/* With a potential (only): explicitly set the relevant terms
* (we need to know the differencing scheme in fe_electro.c). */
+ /* Note these values don't test the sign of the field terms. */
psi0 = 1.0;
psi1 = 2.0;
@@ -298,7 +324,7 @@ static int do_test3(pe_t * pe, cs_t * cs, physics_t * phys) {
}
fe_electro_free(fe);
- psi_free(psi);
+ psi_free(&psi);
return 0;
}
diff --git a/tests/unit/test_fe_electro_symm.c b/tests/unit/test_fe_electro_symm.c
index 6fb702016..f2d28be5c 100644
--- a/tests/unit/test_fe_electro_symm.c
+++ b/tests/unit/test_fe_electro_symm.c
@@ -7,7 +7,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2013-2017 The University of Edinburgh
+ * (c) 2013-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -63,6 +63,7 @@ int test_fe_electro_symm_suite(void) {
static int do_test1(pe_t * pe) {
int nk = 2;
+ int nhalo = 2;
int index = 1;
double dmu[2] = {1.0, 2.0}; /* Solvation free energy differences */
double dmu_test;
@@ -85,11 +86,15 @@ static int do_test1(pe_t * pe) {
assert(pe);
cs_create(pe, &cs);
- cs_nhalo_set(cs, 2);
+ cs_nhalo_set(cs, nhalo);
cs_init(cs);
- psi_create(pe, cs, nk, &psi);
- assert(psi);
+ {
+ psi_options_t opts = psi_options_default(nhalo);
+ opts.epsilon1 = epsilon1;
+ opts.epsilon2 = epsilon2;
+ psi_create(pe, cs, &opts, &psi);
+ }
fe_electro_create(pe, psi, &fe_elec);
{
@@ -125,8 +130,6 @@ static int do_test1(pe_t * pe) {
/* Check epsilon e = ebar [ 1 - gamma phi ] */
- fe_es_epsilon_set(fe, epsilon1, epsilon2);
-
phi0 = 0.0;
field_scalar_set(phi, index, phi0);
fe_es_var_epsilon(fe, index, &eps_test);
@@ -144,7 +147,7 @@ static int do_test1(pe_t * pe) {
fe_es_free(fe);
field_grad_free(dphi);
field_free(phi);
- psi_free(psi);
+ psi_free(&psi);
cs_free(cs);
return 0;
diff --git a/tests/unit/test_field.c b/tests/unit/test_field.c
index 3c45d9f7b..e9688d2a9 100644
--- a/tests/unit/test_field.c
+++ b/tests/unit/test_field.c
@@ -719,10 +719,13 @@ int test_field_io_write(pe_t * pe, cs_t * cs, const field_options_t * opts) {
assert(opts);
/* Establish data and test values. */
+ /* Because field_io_write() has a memcpyDeviceToHost, we need to make
+ * sure the test data is on the device before the write */
field_create(pe, cs, NULL, "test-field-io", opts, &field);
util_field_data_check_set(field);
+ field_memcpy(field, tdpMemcpyHostToDevice);
/* Write */
diff --git a/tests/unit/test_io_metadata.c b/tests/unit/test_io_metadata.c
index 4d189b06b..7e6208c4e 100644
--- a/tests/unit/test_io_metadata.c
+++ b/tests/unit/test_io_metadata.c
@@ -214,7 +214,7 @@ int test_io_metadata_write(cs_t * cs, int keep) {
assert(cs);
io_metadata_create(cs, &options, &element, &meta);
- ifail = io_metadata_write(meta, "test-io", header);
+ ifail = io_metadata_write(meta, "test-io", "Extra", header);
assert(ifail == 0);
/* Remove at rank 0 (a test that the file exists with the correct name) */
diff --git a/tests/unit/test_le.c b/tests/unit/test_le.c
index 2d10fa7e2..0ecd36941 100644
--- a/tests/unit/test_le.c
+++ b/tests/unit/test_le.c
@@ -7,7 +7,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2010-2022 The University of Edinburgh
+ * (c) 2010-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -30,6 +30,12 @@
static int test_parallel1(pe_t * pe, cs_t * cs);
static int test_le_parallel2(pe_t * pe, cs_t * cs);
+int test_lees_edw_create(pe_t * pe, cs_t * cs);
+int test_lees_edw_buffer_displacement(pe_t * pe, cs_t * cs);
+int test_lees_edw_buffer_du(pe_t * pe, cs_t * cs);
+int test_lees_edw_buffer_duy(pe_t * pe, cs_t * cs);
+int test_lees_edw_plane_uy_now(pe_t * pe, cs_t * cs);
+
int test_lees_edw_type_to_string(void);
int test_lees_edw_type_from_string(void);
int test_lees_edw_opts_to_json(void);
@@ -54,6 +60,12 @@ int test_le_suite(void) {
physics_create(pe, &phys);
+ test_lees_edw_create(pe, cs);
+ test_lees_edw_buffer_displacement(pe, cs);
+ test_lees_edw_buffer_du(pe, cs);
+ test_lees_edw_buffer_duy(pe, cs);
+ test_lees_edw_plane_uy_now(pe, cs);
+
test_parallel1(pe, cs);
test_le_parallel2(pe, cs);
@@ -71,6 +83,228 @@ int test_le_suite(void) {
return 0;
}
+/*****************************************************************************
+ *
+ * test_lees_edw_create
+ *
+ *****************************************************************************/
+
+int test_lees_edw_create(pe_t * pe, cs_t * cs) {
+
+ int ifail = 0;
+
+ /* No planes */
+ {
+ lees_edw_options_t opts = {.nplanes = 0};
+ lees_edw_t * le = NULL;
+
+ ifail = lees_edw_create(pe, cs, &opts, &le);
+ assert(le);
+ assert(lees_edw_nplane_total(le) == 0);
+ assert(lees_edw_nplane_local(le) == 0);
+ lees_edw_free(le);
+ }
+
+ /* Two planes */
+ {
+ lees_edw_options_t opts = {.nplanes = 2, .type = LE_SHEAR_TYPE_STEADY,
+ .nt0 = 0, .uy = 0.01};
+ lees_edw_t * le = NULL;
+ ifail = lees_edw_create(pe, cs, &opts, &le);
+ assert(ifail == 0);
+ assert(lees_edw_nplane_total(le) == 2);
+ lees_edw_free(le);
+ }
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * test_lees_edw_buffer_displacement
+ *
+ *****************************************************************************/
+
+int test_lees_edw_buffer_displacement(pe_t * pe, cs_t * cs) {
+
+ int ifail = 0;
+
+ /* Steady displacement is uy.t, with a sign dependent on buffer ib */
+ {
+ int ib = 0;
+ double t = 2.0;
+ double dy = 0.0;
+
+ lees_edw_options_t opts = {.nplanes = 1, .type = LE_SHEAR_TYPE_STEADY,
+ .nt0 = 0, .uy = 0.01};
+ lees_edw_t * le = NULL;
+
+ ifail = lees_edw_create(pe, cs, &opts, &le);
+ assert(ifail == 0);
+ lees_edw_buffer_displacement(le, ib, t, &dy);
+ if (fabs(dy + t*opts.uy) > DBL_EPSILON) ifail = -1; /* ib = 0 is -ve */
+ assert(ifail == 0);
+ lees_edw_free(le);
+ }
+
+ /* Oscillatory displacement */
+ /* The uy is just set to fix up the displacement at time t = 0.5;
+ * it's not realistic */
+ {
+ lees_edw_options_t opts = {.nplanes = 1, .type = LE_SHEAR_TYPE_OSCILLATORY,
+ .period = 2, .nt0 = 0, .uy = 4.0*atan(1.0)};
+ lees_edw_t * le = NULL;
+ int ib = 0;
+ double t = 0.5;
+ double dy = 0.0;
+
+ ifail = lees_edw_create(pe, cs, &opts, &le);
+ assert(ifail == 0);
+ lees_edw_buffer_displacement(le, ib, t, &dy);
+ if (fabs(dy - 1.0) > FLT_EPSILON) ifail = -1;
+ assert(ifail == 0);
+ lees_edw_free(le);
+ }
+
+ return ifail;
+}
+/*****************************************************************************
+ *
+ * test_lees_edw_buffer_du
+ *
+ *****************************************************************************/
+
+int test_lees_edw_buffer_du(pe_t * pe, cs_t * cs) {
+
+ int ifail = 0;
+
+ lees_edw_options_t opts = {.nplanes = 1, .type = LE_SHEAR_TYPE_STEADY,
+ .nt0 = 0, .uy = 0.01};
+ lees_edw_t * le = NULL;
+
+ ifail = lees_edw_create(pe, cs, &opts, &le);
+ assert(ifail == 0);
+
+ /* This follows duy */
+ {
+ int ib = 0;
+ int nhalo = -1;
+
+ lees_edw_nhalo(le, &nhalo);
+
+ for (int p = 0; p < lees_edw_nplane_local(le); p++) {
+ for (int nh = 0; nh < nhalo; nh++) {
+ int isgn = -1;
+ double u[3] = {-1.0, -1.0, -1.0};
+ lees_edw_buffer_du(le, ib, u);
+ assert(u[X] == 0.0 && u[Z] == 0.0);
+ if (fabs(u[Y] - opts.uy*isgn) > DBL_EPSILON) ifail = -1;
+ assert(ifail == 0);
+ ib++;
+ }
+ for (int nh = 0; nh < nhalo; nh++) {
+ int isgn = +1;
+ double u[3] = {-1.0, -1.0, -1.0};
+ lees_edw_buffer_du(le, ib, u);
+ assert(u[X] == 0.0 && u[Z] == 0.0);
+ if (fabs(u[Y] - opts.uy*isgn) > DBL_EPSILON) ifail = -1;
+ assert(ifail == 0);
+ ib++;
+ }
+ }
+ }
+
+ lees_edw_free(le);
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * test_lees_edw_buffer_duy
+ *
+ *****************************************************************************/
+
+int test_lees_edw_buffer_duy(pe_t * pe, cs_t * cs) {
+
+ int ifail = 0;
+
+ lees_edw_options_t opts = {.nplanes = 2, .type = LE_SHEAR_TYPE_STEADY,
+ .nt0 = 0, .uy = 0.01};
+ lees_edw_t * le = NULL;
+
+ ifail = lees_edw_create(pe, cs, &opts, &le);
+ assert(ifail == 0);
+
+ /* Check pattern using alternative initialisation code */
+
+ {
+ int nhalo = -1;
+ int ib = 0; /* Increments by +1 moving along the buffer */
+
+ lees_edw_nhalo(le, &nhalo);
+
+ for (int p = 0; p < lees_edw_nplane_local(le); p++) {
+ for (int nh = 0; nh < nhalo; nh++) {
+ assert(lees_edw_buffer_duy(le, ib) == -1);
+ ib++;
+ }
+ for (int nh = 0; nh < nhalo; nh++) {
+ assert(lees_edw_buffer_duy(le, ib) == +1);
+ ib++;
+ }
+ }
+ }
+
+ lees_edw_free(le);
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * test_lees_edw_plane_uy_now
+ *
+ *****************************************************************************/
+
+int test_lees_edw_plane_uy_now(pe_t * pe, cs_t * cs) {
+
+ int ifail = 0;
+
+ /* Steady shear */
+ {
+ lees_edw_options_t opts = {.nplanes = 1, .type = LE_SHEAR_TYPE_STEADY,
+ .nt0 = 0, .uy = 0.01};
+ lees_edw_t * le = NULL;
+ double t = 0.5; /* Steady result independent of t */
+ double uy = 0.0;
+
+ ifail = lees_edw_create(pe, cs, &opts, &le);
+ lees_edw_plane_uy_now(le, t, &uy);
+ if (fabs(uy - opts.uy) > DBL_EPSILON) ifail = -1;
+ assert(ifail == 0);
+ lees_edw_free(le);
+ }
+
+ /* Oscillatory shear */
+ /* Parameters are to get uy cos(omega.t) = 1 ... */
+ {
+ lees_edw_options_t opts = {.nplanes = 1, LE_SHEAR_TYPE_OSCILLATORY,
+ .period = 3, .nt0 = 100, .uy = -2.0};
+ lees_edw_t * le = NULL;
+ double t = 1.0 + 1.0*opts.nt0;
+ double uy = 0.0;
+
+ ifail = lees_edw_create(pe, cs, &opts, &le);
+ lees_edw_plane_uy_now(le, t, &uy);
+ if (fabs(uy - 1.0) > FLT_EPSILON) ifail = -1;
+ assert(ifail == 0);
+ lees_edw_free(le);
+ }
+
+ return ifail;
+}
+
/*****************************************************************************
*
* test_parallel1
diff --git a/tests/unit/test_nernst_planck.c b/tests/unit/test_nernst_planck.c
index acbf35282..7579f6bd9 100644
--- a/tests/unit/test_nernst_planck.c
+++ b/tests/unit/test_nernst_planck.c
@@ -7,7 +7,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2012-2022 The University of Edinburgh
+ * (c) 2012-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -23,19 +23,12 @@
#include "pe.h"
#include "coords.h"
#include "physics.h"
-#include "control.h"
#include "map.h"
-#include "psi.h"
-#include "psi_s.h"
#include "psi_sor.h"
-#include "psi_stats.h"
#include "fe_electro.h"
#include "nernst_planck.h"
-#include "util_fopen.h"
-#include "tests.h"
static int test_nernst_planck_driver(pe_t * pe);
-static int test_io(cs_t * cs, psi_t * psi, int tstep);
/*****************************************************************************
*
@@ -90,12 +83,11 @@ int test_nernst_planck_suite(void) {
static int test_nernst_planck_driver(pe_t * pe) {
+ int nhalo = 1;
int ntotal[3] = {64, 4, 4}; /* Quasi-one-dimensional system */
- int nk = 2; /* Number of species */
int nlocal[3];
int noffst[3];
- int test_output_required = 0;
int mpi_cartsz[3];
int mpi_cartcoords[3];
@@ -103,12 +95,6 @@ static int test_nernst_planck_driver(pe_t * pe) {
double rho_i; /* Interior charge density */
double rho_b, rho_b_local; /* background ionic strength */
- int valency[2] = {+1, -1};
- double diffusivity[2] = {1.e-2, 1.e-2};
-
- double eunit = 1.; /* Unit charge, ... */
- double epsilon = 3.3e3; /* ... epsilon, and ... */
- double beta = 3.0e4; /* ... the Boltzmann factor i.e., t ~ 10^5 */
double rho_el = 1.0e-3; /* charge density */
double ltot[3];
@@ -119,12 +105,17 @@ static int test_nernst_planck_driver(pe_t * pe) {
physics_t * phys = NULL;
fe_electro_t * fe = NULL;
+ double epsilon = 3.3e3; /* ... epsilon, and ... */
+ double beta = 3.0e4; /* ... the Boltzmann factor i.e., t ~ 10^5 */
+
+ psi_options_t opts = psi_options_default(nhalo);
+
assert(pe);
physics_create(pe, &phys);
cs_create(pe, &cs);
- cs_nhalo_set(cs, 1);
+ cs_nhalo_set(cs, nhalo);
cs_ntotal_set(cs, ntotal);
{
@@ -144,19 +135,12 @@ static int test_nernst_planck_driver(pe_t * pe) {
map_create(pe, cs, 0, &map);
assert(map);
- psi_create(pe, cs, nk, &psi);
- assert(psi);
-
- psi_valency_set(psi, 0, valency[0]);
- psi_valency_set(psi, 1, valency[1]);
- psi_diffusivity_set(psi, 0, diffusivity[0]);
- psi_diffusivity_set(psi, 1, diffusivity[1]);
- psi_unit_charge_set(psi, eunit);
- psi_epsilon_set(psi, epsilon);
- psi_beta_set(psi, beta);
+ opts.beta = beta;
+ opts.epsilon1 = epsilon;
+ opts.epsilon2 = epsilon;
+ psi_create(pe, cs, &opts, &psi);
- /* Care. the free energy gets the temperatue from global physics_t. */
- physics_kt_set(phys, 1.0/beta);
+ /* Care. the free energy gets the temperature from global physics_t. */
fe_electro_create(pe, psi, &fe);
/* wall charge density */
@@ -217,13 +201,18 @@ static int test_nernst_planck_driver(pe_t * pe) {
map_halo(map);
psi_halo_psi(psi);
- psi_sor_poisson(psi, -1);
+
+ {
+ psi_solver_sor_t * sor = NULL;
+ psi_solver_sor_create(psi, &sor);
+ psi_solver_sor_solve(sor, -1);
+ psi_solver_sor_free(&sor);
+ }
+
psi_halo_rho(psi);
nernst_planck_driver(psi, (fe_t *) fe, map);
- if (test_output_required) test_io(cs, psi, 0);
-
/* We adopt a rather simple way to extract the answer from the
* MPI task holding the centre of the system. The charge
* density must be > 0 to compute the debye length and the
@@ -253,8 +242,8 @@ static int test_nernst_planck_driver(pe_t * pe) {
double ldebye = 0.0; /* Debye length */
double yd = 0.0; /* Dimensionless surface potential */
- psi_bjerrum_length(psi, &lb);
- psi_debye_length(psi, rho_b, &ldebye);
+ psi_bjerrum_length1(&opts, &lb);
+ psi_debye_length1(&opts, rho_b, &ldebye);
psi_surface_potential(psi, rho_w, rho_b, &yd);
/* Only the surface potential has really changed compared with the
@@ -267,99 +256,9 @@ static int test_nernst_planck_driver(pe_t * pe) {
map_free(map);
fe_electro_free(fe);
- psi_free(psi);
+ psi_free(&psi);
cs_free(cs);
physics_free(phys);
return 0;
}
-
-/*****************************************************************************
- *
- * test_io
- *
- *****************************************************************************/
-
-static int test_io(cs_t * cs, psi_t * psi, int tstep) {
-
- int ntotal[3];
- int nlocal[3];
- int ic, jc, kc, index;
-
- double * field; /* 1-d field (local) */
- double * psifield; /* 1-d psi field for output */
- double * rho0field; /* 1-d rho0 field for output */
- double * rho1field; /* 1-d rho0 field for output */
-
- char filename[BUFSIZ];
- FILE * out;
- MPI_Comm comm;
-
- cs_nlocal(cs, nlocal);
- cs_ntotal(cs, ntotal);
- cs_cart_comm(cs, &comm);
-
- jc = 2;
- kc = 2;
-
- /* 1D output. calloc() is used to zero the arays, then
- * MPI_Gather to get complete picture. */
-
- field = (double *) calloc(nlocal[X], sizeof(double));
- psifield = (double *) calloc(ntotal[X], sizeof(double));
- rho0field = (double *) calloc(ntotal[X], sizeof(double));
- rho1field = (double *) calloc(ntotal[X], sizeof(double));
- assert(field);
- assert(psifield);
- assert(rho0field);
- assert(rho1field);
- if (field == NULL) pe_fatal(psi->pe, "calloc(field) failed\n");
- if (psifield == NULL) pe_fatal(psi->pe, "calloc(psifield) failed\n");
- if (rho0field == NULL) pe_fatal(psi->pe, "calloc(rho0field) failed\n");
- if (rho1field == NULL) pe_fatal(psi->pe, "calloc(rho1field) failed\n");
-
- for (ic = 1; ic <= nlocal[X]; ic++) {
-
- index = cs_index(cs, ic, jc, kc);
- psi_psi(psi, index, field + ic - 1);
- }
-
- MPI_Gather(field, nlocal[X], MPI_DOUBLE,
- psifield, nlocal[X], MPI_DOUBLE, 0, comm);
-
- for (ic = 1; ic <= nlocal[X]; ic++) {
- index = cs_index(cs, ic, jc, kc);
- psi_rho(psi, index, 0, field + ic - 1);
- }
-
- MPI_Gather(field, nlocal[X], MPI_DOUBLE,
- rho0field, nlocal[X], MPI_DOUBLE, 0, comm);
-
- for (ic = 1; ic <= nlocal[X]; ic++) {
- index = cs_index(cs, ic, jc, kc);
- psi_rho(psi, index, 1, field + ic - 1);
- }
-
- MPI_Gather(field, nlocal[X], MPI_DOUBLE,
- rho1field, nlocal[X], MPI_DOUBLE, 0, comm);
-
- if (cs_cart_rank(cs) == 0) {
-
- sprintf(filename, "np_test-%d.dat", tstep);
- out = util_fopen(filename, "w");
- if (out == NULL) pe_fatal(psi->pe, "Could not open %s\n", filename);
-
- for (ic = 1; ic <= ntotal[X]; ic++) {
- fprintf(out, "%d %14.7e %14.7e %14.7e\n", ic, psifield[ic-1],
- rho0field[ic-1], rho1field[ic-1]);
- }
- fclose(out);
- }
-
- free(rho1field);
- free(rho0field);
- free(psifield);
- free(field);
-
- return 0;
-}
diff --git a/tests/unit/test_psi.c b/tests/unit/test_psi.c
index caaf86945..ed7e66977 100644
--- a/tests/unit/test_psi.c
+++ b/tests/unit/test_psi.c
@@ -7,7 +7,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2012-2017 The University of Edinburgh
+ * (c) 2012-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -18,23 +18,15 @@
#include
#include
-#include "pe.h"
-#include "coords.h"
-#include "util.h"
#include "psi.h"
-#include "psi_s.h"
-#include "test_coords_field.h"
-#include "tests.h"
-
-static int testf2(cs_t * cs, int ic, int jc, int kc, int n, void * ref);
-static int do_test1(pe_t * pe);
-static int do_test2(pe_t * pe);
-static int do_test_halo1(pe_t * pe);
-static int do_test_halo2(pe_t * pe);
-static int do_test_bjerrum(pe_t * pe);
-static int do_test_ionic_strength(pe_t * pe);
-static int do_test_io1(pe_t * pe);
+int test_psi_initialise(pe_t * pe);
+int test_psi_create(pe_t * pe);
+int test_psi_psi_set(pe_t * pe);
+int test_psi_rho_set(pe_t * pe);
+int test_psi_halo_psi(pe_t * pe);
+int test_psi_halo_rho(pe_t * pe);
+int test_psi_ionic_strength(pe_t * pe);
/*****************************************************************************
*
@@ -48,13 +40,16 @@ int test_psi_suite(void) {
pe_create(MPI_COMM_WORLD, PE_QUIET, &pe);
- do_test1(pe);
- do_test2(pe);
- do_test_halo1(pe);
- do_test_halo2(pe);
- do_test_io1(pe);
- do_test_bjerrum(pe);
- do_test_ionic_strength(pe);
+ /* Changes in psi_t should be accompanied by changes in tests... */
+ assert(sizeof(psi_t) == 576);
+
+ test_psi_initialise(pe);
+ test_psi_create(pe);
+ test_psi_psi_set(pe);
+ test_psi_rho_set(pe);
+ test_psi_halo_psi(pe);
+ test_psi_halo_rho(pe);
+ test_psi_ionic_strength(pe);
pe_info(pe, "PASS ./unit/test_psi\n");
pe_free(pe);
@@ -64,51 +59,76 @@ int test_psi_suite(void) {
/*****************************************************************************
*
- * do_test1
- *
- * Test object creation/deletion, and the various access functions.
+ * test_psi_initialise
*
*****************************************************************************/
-static int do_test1(pe_t * pe) {
+int test_psi_initialise(pe_t * pe) {
- int nk;
- int iv, n;
- int valency[3] = {1, 2, 3};
- double e, diff;
- double diffusivity[3] = {1.0, 2.0, 3.0};
- double eunit = -1.0;
-
- cs_t * cs;
- psi_t * psi;
-
- assert(pe);
+ int nhalo = 1;
+ cs_t * cs = NULL;
cs_create(pe, &cs);
+ cs_nhalo_set(cs, nhalo);
cs_init(cs);
- nk = 3;
- psi_create(pe, cs, nk, &psi);
- assert(psi);
- psi_nk(psi, &n);
- test_assert(n == 3);
-
- for (n = 0; n < nk; n++) {
- psi_valency_set(psi, n, valency[n]);
- psi_valency(psi, n, &iv);
- test_assert(iv == valency[n]);
- psi_diffusivity_set(psi, n, diffusivity[n]);
- psi_diffusivity(psi, n, &diff);
- test_assert(fabs(diff - diffusivity[n]) < DBL_EPSILON);
+ {
+ /* With some non-default values ... */
+ int nsites = 0;
+ psi_options_t opts = psi_options_default(nhalo);
+ psi_t psi = {0};
+
+ opts.e = 2.0;
+ opts.beta = 0.5;
+ opts.epsilon1 = 0.2;
+ opts.epsilon2 = 0.3;
+ opts.e0[X] = 4.0;
+ opts.e0[Y] = 5.0;
+ opts.e0[Z] = 6.0;
+
+ psi_initialise(pe, cs, &opts, &psi);
+
+ cs_nsites(cs, &nsites);
+
+ /* Check existing structure */
+ assert(psi.pe == pe);
+ assert(psi.cs == cs);
+ assert(psi.nk == opts.nk);
+ assert(psi.nsites == nsites);
+ assert(psi.psi != NULL);
+ assert(psi.rho != NULL);
+
+ assert(fabs(psi.diffusivity[0] - opts.diffusivity[0]) < DBL_EPSILON);
+ assert(fabs(psi.diffusivity[1] - opts.diffusivity[1]) < DBL_EPSILON);
+ assert(psi.valency[0] == opts.valency[0]);
+ assert(psi.valency[1] == opts.valency[1]);
+
+ /* Physical quantities */
+ assert(fabs(psi.e - opts.e) < DBL_EPSILON);
+ assert(fabs(psi.epsilon - opts.epsilon1) < DBL_EPSILON);
+ assert(fabs(psi.epsilon2 - opts.epsilon2) < DBL_EPSILON);
+ assert(fabs(psi.beta - opts.beta) < DBL_EPSILON);
+ assert(fabs(psi.e0[X] - opts.e0[X]) < DBL_EPSILON);
+ assert(fabs(psi.e0[Y] - opts.e0[Y]) < DBL_EPSILON);
+ assert(fabs(psi.e0[Z] - opts.e0[Z]) < DBL_EPSILON);
+
+ /* Solver options */
+ /* Assume correctly covered in solver options tests ... */
+ assert(psi.solver.psolver == PSI_POISSON_SOLVER_SOR);
+ assert(psi.stencil);
+ assert(psi.stencil->npoints == psi.solver.nstencil);
+
+ /* Nernst Planck */
+ assert(psi.multisteps == opts.nsmallstep);
+ assert(fabs(psi.diffacc - opts.diffacc) < DBL_EPSILON);
+
+ /* Other */
+ assert(psi.method == opts.method);
+ assert(psi.options.nk == opts.nk);
+
+ psi_finalise(&psi);
}
- psi_unit_charge(psi, &e);
- test_assert(fabs(e - 1.0) < DBL_EPSILON); /* Default unit = 1.0 */
- psi_unit_charge_set(psi, eunit);
- psi_unit_charge(psi, &e);
- test_assert(fabs(eunit - e) < DBL_EPSILON);
-
- psi_free(psi);
cs_free(cs);
return 0;
@@ -116,62 +136,32 @@ static int do_test1(pe_t * pe) {
/*****************************************************************************
*
- * do_test2
- *
- * Check access to the lattice-based quantities.
+ * test_psi_create
*
*****************************************************************************/
-static int do_test2(pe_t * pe) {
-
- int nk = 2;
- int iv, n;
- int index;
- int valency[2] = {1, 2};
- double diff;
- double ref, value;
- double diffusivity[2] = {1.0, 2.0};
+int test_psi_create(pe_t * pe) {
+ int nhalo = 2;
cs_t * cs = NULL;
- psi_t * psi = NULL;
-
- assert(pe);
cs_create(pe, &cs);
+ cs_nhalo_set(cs, nhalo);
cs_init(cs);
- psi_create(pe, cs, nk, &psi);
- assert(psi);
- psi_nk(psi, &n);
- test_assert(n == 2);
-
- for (n = 0; n < nk; n++) {
- psi_valency_set(psi, n, valency[n]);
- psi_valency(psi, n, &iv);
- test_assert(iv == valency[n]);
- psi_diffusivity_set(psi, n, diffusivity[n]);
- psi_diffusivity(psi, n, &diff);
- test_assert(fabs(diff - diffusivity[n]) < DBL_EPSILON);
- }
+ {
+ psi_options_t opts = psi_options_default(nhalo);
+ psi_t * psi = NULL;
- index = 1;
- ref = 1.0;
- psi_psi_set(psi, index, ref);
- psi_psi(psi, index, &value);
- test_assert(fabs(value - ref) < DBL_EPSILON);
+ psi_create(pe, cs, &opts, &psi);
+ assert(psi);
+ assert(psi->psi);
+ assert(psi->rho);
- for (n = 0; n < nk; n++) {
- ref = 1.0 + n;
- psi_rho_set(psi, index, n, ref);
- psi_rho(psi, index, n, &value);
- test_assert(fabs(value - ref) < DBL_EPSILON);
+ psi_free(&psi);
+ assert(psi == NULL);
}
- ref = 1.0 + 4.0;
- psi_rho_elec(psi, index, &value);
- test_assert(fabs(value - ref) < DBL_EPSILON);
-
- psi_free(psi);
cs_free(cs);
return 0;
@@ -179,43 +169,37 @@ static int do_test2(pe_t * pe) {
/*****************************************************************************
*
- * do_test_halo1
- *
- * Take the default system size with nhalo = 2 and nk = 3, and
- * check the halo swap.
+ * test_psi_psi_set
*
*****************************************************************************/
-static int do_test_halo1(pe_t * pe) {
+int test_psi_psi_set(pe_t * pe) {
- int nk;
int nhalo = 2;
- cs_t * cs = NULL;
+ int ntotal[3] = {64, 4, 4};
+ psi_options_t opts = psi_options_default(nhalo);
psi_t * psi = NULL;
-
- assert(pe);
+ cs_t * cs = NULL;
cs_create(pe, &cs);
cs_nhalo_set(cs, nhalo);
+ cs_ntotal_set(cs, ntotal);
cs_init(cs);
- nk = 3;
- psi_create(pe, cs, nk, &psi);
- assert(psi);
-
- test_coords_field_set(cs, 1, psi->psi, MPI_DOUBLE, test_ref_double1);
- psi_halo_psi(psi);
- test_coords_field_check(cs, nhalo, 1, psi->psi, MPI_DOUBLE, test_ref_double1);
-
- test_coords_field_set(cs, nk, psi->rho, MPI_DOUBLE, test_ref_double1);
- psi_halo_rho(psi);
- test_coords_field_check(cs, nhalo, nk, psi->rho, MPI_DOUBLE, test_ref_double1);
-
- test_coords_field_set(cs, nk, psi->rho, MPI_DOUBLE, testf2);
- psi_halo_rho(psi);
- test_coords_field_check(cs, nhalo, nk, psi->rho, MPI_DOUBLE, testf2);
+ psi_create(pe, cs, &opts, &psi);
+ assert(psi->psi->data);
+
+ {
+ /* potential */
+ int index = 1;
+ double psi0 = 2.0;
+ double value = 0.0;
+ psi_psi_set(psi, index, psi0);
+ psi_psi(psi, index, &value);
+ assert(fabs(value - psi0) < DBL_EPSILON);
+ }
- psi_free(psi);
+ psi_free(&psi);
cs_free(cs);
return 0;
@@ -223,47 +207,37 @@ static int do_test_halo1(pe_t * pe) {
/*****************************************************************************
*
- * do_test_halo2
- *
- * Check the halo swap in a one-dimensional decomposition.
+ * psi_rho_set
*
*****************************************************************************/
-static int do_test_halo2(pe_t * pe) {
+int test_psi_rho_set(pe_t * pe) {
- int nk;
- int grid[3];
- int nhalo = 3;
+ int nhalo = 2;
+ int ntotal[3] = {64, 4, 4};
+ psi_options_t opts = psi_options_default(nhalo);
+ psi_t * psi = NULL;
cs_t * cs = NULL;
- psi_t * psi;
-
- assert(pe);
-
- /* Use a 1-d decomposition, which increases the number of
- * MPI tasks in one direction cf. the default. */
-
- grid[0] = 1;
- grid[1] = pe_mpi_size(pe);
- grid[2] = 1;
cs_create(pe, &cs);
- cs_decomposition_set(cs, grid);
cs_nhalo_set(cs, nhalo);
+ cs_ntotal_set(cs, ntotal);
cs_init(cs);
- nk = 2;
- psi_create(pe, cs, nk, &psi);
- assert(psi);
+ psi_create(pe, cs, &opts, &psi);
+ assert(psi->rho->data);
- test_coords_field_set(cs, 1, psi->psi, MPI_DOUBLE, test_ref_double1);
- psi_halo_psi(psi);
- test_coords_field_check(cs, nhalo, 1, psi->psi, MPI_DOUBLE, test_ref_double1);
-
- test_coords_field_set(cs, nk, psi->rho, MPI_DOUBLE, test_ref_double1);
- psi_halo_rho(psi);
- test_coords_field_check(cs, nhalo, nk, psi->rho, MPI_DOUBLE, test_ref_double1);
+ /* Charge densities */
+ for (int n = 0; n < psi->nk; n++) {
+ int index = 1 + n;
+ double rho0 = 6.0 + 1.0*n;
+ double value = 0.0;
+ psi_rho_set(psi, index, n, rho0);
+ psi_rho(psi, index, n, &value);
+ assert(fabs(value - rho0) < DBL_EPSILON);
+ }
- psi_free(psi);
+ psi_free(&psi);
cs_free(cs);
return 0;
@@ -271,208 +245,184 @@ static int do_test_halo2(pe_t * pe) {
/*****************************************************************************
*
- * do_test_io1
+ * test_psi_halo_psi
*
- * Note that the io functions must use the psi_ object at the moment.
- * Take default (i.e., binary) write, and specify explicitly binary
- * read.
- *
*****************************************************************************/
-static int do_test_io1(pe_t * pe) {
-
- int nk;
- int grid[3] = {1, 1, 1};
- const char * filename = "psi-test-io";
+int test_psi_halo_psi(pe_t * pe) {
- cs_t * cs = NULL;
+ int ifail = 0;
+ int nhalo = 2;
+ int ntotal[3] = {16, 16, 16};
+ psi_options_t opts = psi_options_default(nhalo);
psi_t * psi = NULL;
- io_info_t * iohandler = NULL;
- MPI_Comm comm;
-
- assert(pe);
+ cs_t * cs = NULL;
cs_create(pe, &cs);
+ cs_nhalo_set(cs, nhalo);
+ cs_ntotal_set(cs, ntotal);
cs_init(cs);
- cs_cart_comm(cs, &comm);
- if (pe_mpi_size(pe) == 8) {
- grid[X] = 2;
- grid[Y] = 2;
- grid[Z] = 2;
+ psi_create(pe, cs, &opts, &psi);
+
+ /* Provide uniform values ... */
+ {
+ int nlocal[3] = {0};
+ double psi0 = 2.0;
+ cs_nlocal(cs, nlocal);
+
+ for (int ic = 1; ic <= nlocal[X]; ic++) {
+ for (int jc = 1; jc <= nlocal[Y]; jc++) {
+ for (int kc = 1; kc <= nlocal[Z]; kc++) {
+ int index = cs_index(cs, ic, jc, kc);
+ psi_psi_set(psi, index, psi0);
+ }
+ }
+ }
}
- nk = 2;
- psi_create(pe, cs, nk, &psi);
- assert(psi);
- psi_init_io_info(psi, grid, IO_FORMAT_DEFAULT, IO_FORMAT_DEFAULT);
-
- test_coords_field_set(cs, 1, psi->psi, MPI_DOUBLE, test_ref_double1);
- test_coords_field_set(cs, nk, psi->rho, MPI_DOUBLE, test_ref_double1);
-
- psi_io_info(psi, &iohandler);
- assert(iohandler);
- io_write_data(iohandler, filename, psi);
-
- psi_free(psi);
- MPI_Barrier(comm);
-
- /* Recreate, and read. This zeros out all the fields, so they
- * must be read correctly to pass. */
-
- psi_create(pe, cs, nk, &psi);
- psi_init_io_info(psi, grid, IO_FORMAT_BINARY, IO_FORMAT_BINARY);
-
- psi_io_info(psi, &iohandler);
- assert(iohandler);
- io_read_data(iohandler, filename, psi);
-
psi_halo_psi(psi);
- psi_halo_rho(psi);
-
- /* Zero halo region required */
- test_coords_field_check(cs, 0, 1, psi->psi, MPI_DOUBLE, test_ref_double1);
- test_coords_field_check(cs, 0, nk, psi->rho, MPI_DOUBLE, test_ref_double1);
- MPI_Barrier(comm);
- io_remove(filename, iohandler);
- io_remove_metadata(iohandler, "psi");
+ /* Check ... */
+ {
+ int nlocal[3] = {0};
+ double psi0 = 2.0;
+ cs_nlocal(cs, nlocal);
+
+ for (int ic = 1 - nhalo; ic <= nlocal[X] + nhalo; ic++) {
+ for (int jc = 1 - nhalo; jc <= nlocal[Y] + nhalo; jc++) {
+ for (int kc = 1 - nhalo; kc <= nlocal[Z] + nhalo; kc++) {
+ int index = cs_index(cs, ic, jc, kc);
+ double value = 0.0;
+ psi_psi(psi, index, &value);
+ assert(fabs(value - psi0) < DBL_EPSILON);
+ if (fabs(value - psi0) > DBL_EPSILON) ifail += 1;
+ }
+ }
+ }
+ }
- psi_free(psi);
+ psi_free(&psi);
cs_free(cs);
- return 0;
+ return ifail;
}
/*****************************************************************************
*
- * do_test_bjerrum
- *
- * Test the bjerrum length comes out right.
- * l_B = e^2 / 4\pi epsilon KT
- *
- * We set out unit charge to be 1 in lattice units, and a plausable
- * lattice Boltzmann temperature of 10^-05; the units of permeativity
- * are still somewhat open to investigation...
- *
- * At the moment I have the famous 41.4 which is the dielectric
- * *isotropy* used for blue phases scaled by an arbitrary 1000.
- *
- * Also test the Debye length for unit ionic strength while we
- * are at it.
+ * test_psi_halo_rho
*
*****************************************************************************/
-static int do_test_bjerrum(pe_t * pe) {
+int test_psi_halo_rho(pe_t * pe) {
+ int ifail = 0;
+ int nhalo = 1;
+ int ntotal[3] = {16, 16, 16};
+ psi_options_t opts = psi_options_default(nhalo);
psi_t * psi = NULL;
- double eref = 1.0;
- double epsilonref = 41.4*1000.0;
- double ktref = 0.00001;
- double tmp, lbref, ldebyeref;
-
cs_t * cs = NULL;
- PI_DOUBLE(pi_);
-
- assert(pe);
cs_create(pe, &cs);
+ cs_nhalo_set(cs, nhalo);
+ cs_ntotal_set(cs, ntotal);
cs_init(cs);
- psi_create(pe, cs, 2, &psi);
-
- psi_beta_set(psi, 1.0/ktref);
- psi_beta(psi, &tmp);
- test_assert(fabs(1.0/ktref - tmp) < DBL_EPSILON);
- psi_epsilon_set(psi, epsilonref);
- psi_epsilon(psi, &tmp);
- test_assert(fabs(tmp - epsilonref) < DBL_EPSILON);
-
- psi_unit_charge_set(psi, eref);
- psi_unit_charge(psi, &tmp);
- test_assert(fabs(tmp - eref) < DBL_EPSILON);
+ psi_create(pe, cs, &opts, &psi);
+
+ /* Provide uniform values per chareged species ... */
+ {
+ int nlocal[3] = {0};
+ cs_nlocal(cs, nlocal);
+
+ for (int ic = 1; ic <= nlocal[X]; ic++) {
+ for (int jc = 1; jc <= nlocal[Y]; jc++) {
+ for (int kc = 1; kc <= nlocal[Z]; kc++) {
+ int index = cs_index(cs, ic, jc, kc);
+ for (int n = 0; n < psi->nk; n++) {
+ double rho0 = 6.0 + 1.0*n;
+ psi_rho_set(psi, index, n, rho0);
+ }
+ }
+ }
+ }
+ }
- lbref = eref*eref / (4.0*pi_*epsilonref*ktref);
- psi_bjerrum_length(psi, &tmp);
- test_assert(fabs(lbref - tmp) < DBL_EPSILON);
+ psi_halo_rho(psi);
- /* For unit ionic strength */
- ldebyeref = 1.0 / sqrt(8.0*pi_*lbref);
- psi_debye_length(psi, 1.0, &tmp);
- test_assert(fabs(ldebyeref - tmp) < DBL_EPSILON);
+ /* Check ... */
+ {
+ int nlocal[3] = {0};
+ cs_nlocal(cs, nlocal);
+
+ for (int ic = 1 - nhalo; ic <= nlocal[X] + nhalo; ic++) {
+ for (int jc = 1 - nhalo; jc <= nlocal[Y] + nhalo; jc++) {
+ for (int kc = 1 - nhalo; kc <= nlocal[Z] + nhalo; kc++) {
+ int index = cs_index(cs, ic, jc, kc);
+ for (int n = 0; n < psi->nk; n++) {
+ double rho0 = 6.0 + 1.0*n;
+ double value = 0.0;
+ psi_rho(psi, index, n, &value);
+ assert(fabs(value - rho0) < DBL_EPSILON);
+ if (fabs(value - rho0) > DBL_EPSILON) ifail += 1;
+ }
+ }
+ }
+ }
+ }
- psi_free(psi);
+ psi_free(&psi);
cs_free(cs);
- return 0;
+ return ifail;
}
/*****************************************************************************
*
- * do_test_ionic_strength
- *
- * Test the calculation of the ionic strength. We require just
- * valency and charge density for a given number of species.
+ * test_psi_ionic_strength
*
*****************************************************************************/
-static int do_test_ionic_strength(pe_t * pe) {
-
- int n, nk = 2;
+int test_psi_ionic_strength(pe_t * pe) {
+
+ int nhalo = 1;
+ int ntotal[3] = {8, 8, 8};
+ psi_options_t opts = psi_options_default(nhalo);
psi_t * psi = NULL;
+ cs_t * cs = NULL;
- int index = 1; /* Lattice point will be present */
+ /* We require a valency and a charge density ... */
int valency[2] = {+2, -2};
- double rho[2] = {1.0, 2.0};
- double rhoi;
- double expect;
- cs_t * cs = NULL;
+ double rho0[2] = {3.0, 5.0};
- assert(pe);
+ opts.valency[0] = valency[0];
+ opts.valency[1] = valency[1];
cs_create(pe, &cs);
+ cs_nhalo_set(cs, nhalo);
+ cs_ntotal_set(cs, ntotal);
cs_init(cs);
- psi_create(pe, cs, nk, &psi);
- for (n = 0; n < nk; n++) {
- psi_valency_set(psi, n, valency[n]);
- psi_rho_set(psi, index, n, rho[n]);
+ psi_create(pe, cs, &opts, &psi);
+
+ /* Set the charge density, and compute an ionic strength */
+ {
+ int index = 2;
+ int strength = 0.0;
+ for (int n = 0; n < psi->nk; n++) {
+ psi_rho_set(psi, index, n, rho0[n]);
+ strength += 0.5*valency[n]*valency[n]*rho0[n];
+ }
+
+ {
+ double value = 0.0;
+ psi_ionic_strength(psi, index, &value);
+ assert(fabs(value - strength) < DBL_EPSILON);
+ }
}
-
- expect = 0.5*(pow(valency[0], 2)*rho[0] + pow(valency[1], 2)*rho[1]);
-
- psi_ionic_strength(psi, index, &rhoi);
- test_assert(fabs(expect - rhoi) < DBL_EPSILON);
-
- psi_free(psi);
+
+ psi_free(&psi);
cs_free(cs);
return 0;
}
-
-/*****************************************************************************
- *
- * testf2
- *
- * With signature halo_ft from test_coords_field.h
- * A 'wall' function perioidic in z-direction.
- *
- *****************************************************************************/
-
-static int testf2(cs_t * cs, int ic, int jc, int kc, int n, void * buf) {
-
- int ntotal[3];
- double * ref = (double *) buf;
-
- assert(cs);
- assert(ref);
-
- cs_ntotal(cs, ntotal);
-
- *ref = -1.0;
-
- if (kc == 1 || kc == 0) *ref = 1.0;
- if (kc == ntotal[Z] || kc == ntotal[Z] + 1) *ref = 1.0;
-
- return 0;
-}
diff --git a/tests/unit/test_psi_options.c b/tests/unit/test_psi_options.c
new file mode 100644
index 000000000..7ffd18aa3
--- /dev/null
+++ b/tests/unit/test_psi_options.c
@@ -0,0 +1,296 @@
+/*****************************************************************************
+ *
+ * test_psi_options.c
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#include
+#include
+#include
+#include
+
+#include "pe.h"
+#include "psi_options.h"
+
+int test_psi_options_default(void);
+int test_psi_options_to_json(void);
+int test_psi_options_from_json(void);
+int test_psi_bjerrum_length(void);
+int test_psi_debye_length(void);
+
+/*****************************************************************************
+ *
+ * test_psi_options_suite
+ *
+ *****************************************************************************/
+
+int test_psi_options_suite(void) {
+
+ pe_t * pe = NULL;
+
+ pe_create(MPI_COMM_WORLD, PE_QUIET, &pe);
+
+ /* A change in components requires a test update... */
+ assert(sizeof(psi_options_t) == 392);
+ assert(PSI_NKMAX >= 2);
+
+ test_psi_options_default();
+ test_psi_options_to_json();
+ test_psi_options_from_json();
+ test_psi_bjerrum_length();
+ test_psi_debye_length();
+
+ pe_info(pe, "%-9s %s\n", "PASS", __FILE__);
+ pe_free(pe);
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * test_psi_options_default
+ *
+ *****************************************************************************/
+
+int test_psi_options_default(void) {
+
+ int ifail = 0;
+
+ psi_options_t opts = psi_options_default(0);
+
+ assert(opts.nk == 2);
+ if (opts.nk != 2) ifail = -1;
+
+ /* Physics */
+ assert(fabs(opts.e - 1.0) < DBL_EPSILON);
+ assert(fabs(opts.beta - 1.0) < DBL_EPSILON);
+ assert(fabs(opts.epsilon1 - 10000.0) < DBL_EPSILON);
+ assert(fabs(opts.epsilon2 - 10000.0) < DBL_EPSILON);
+ assert(fabs(opts.e0[0] - 0.0) < DBL_EPSILON);
+ assert(fabs(opts.e0[1] - 0.0) < DBL_EPSILON);
+ assert(fabs(opts.e0[2] - 0.0) < DBL_EPSILON);
+ assert(fabs(opts.diffusivity[0] - 0.01) < DBL_EPSILON);
+ assert(fabs(opts.diffusivity[1] - 0.01) < DBL_EPSILON);
+
+ assert(opts.valency[0] == +1);
+ assert(opts.valency[1] == -1);
+
+ /* Solver */
+ assert(opts.solver.psolver == PSI_POISSON_SOLVER_SOR);
+
+ /* Nernst Planck */
+ assert(opts.nsolver == -1);
+ assert(opts.nsmallstep == 1);
+ assert(fabs(opts.diffacc - 0.0) < DBL_EPSILON);
+
+ /* Other */
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * test_psi_options_to_json
+ *
+ *****************************************************************************/
+
+int test_psi_options_to_json(void) {
+
+ int ifail = 0;
+ psi_options_t opts = psi_options_default(0);
+ cJSON * json = NULL;
+
+ ifail = psi_options_to_json(&opts, &json);
+ assert(ifail == 0);
+
+ {
+ psi_options_t check = {0};
+ ifail = psi_options_from_json(json, &check);
+ assert(ifail == 0);
+ if (check.nk != 2) ifail = -1;
+ assert(check.nk == 2);
+ }
+
+ cJSON_Delete(json);
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * test_psi_options_from_json
+ *
+ * Using the minimum requirement for solver options.
+ *
+ *****************************************************************************/
+
+int test_psi_options_from_json(void) {
+
+ int ifail = 0;
+ const char * jstr = "{ \"Number of species\": 2,"
+ " \"Unit charge\": 2.5,"
+ " \"Boltzmann factor\": 3.0,"
+ " \"First permittivity\": 2000.0,"
+ " \"Second permittivity\": 3000.0,"
+ " \"Valencies\": [1, -1],"
+ " \"Diffusivities\": [0.01, 0.02],"
+ " \"External field\": [1.0, 2.0, 3.0],"
+ " \"Solver options\": {"
+ " \"Solver type\": \"sor\" "
+ "}}";
+
+ cJSON * json = cJSON_Parse(jstr);
+ assert(json);
+
+ {
+ /* Check result */
+ psi_options_t opts = {0};
+ ifail = psi_options_from_json(json, &opts);
+ assert(ifail == 0);
+
+ assert(opts.nk == 2);
+ assert(fabs(opts.e - 2.5) < DBL_EPSILON);
+ assert(fabs(opts.beta - 3.0) < DBL_EPSILON);
+ assert(fabs(opts.epsilon1 - 2000.0) < DBL_EPSILON);
+ assert(fabs(opts.epsilon2 - 3000.0) < DBL_EPSILON);
+ assert(opts.valency[0] == +1);
+ assert(opts.valency[1] == -1);
+ assert(fabs(opts.diffusivity[0] - 0.01) < DBL_EPSILON);
+ assert(fabs(opts.diffusivity[1] - 0.02) < DBL_EPSILON);
+ assert(fabs(opts.e0[0] - 1.0) < DBL_EPSILON);
+ assert(fabs(opts.e0[1] - 2.0) < DBL_EPSILON);
+ assert(fabs(opts.e0[2] - 3.0) < DBL_EPSILON);
+
+ assert(opts.solver.psolver == PSI_POISSON_SOLVER_SOR);
+ }
+
+ cJSON_Delete(json);
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * test_psi_bjerrum_length
+ *
+ * Check both Bjerrum lengths.
+ *
+ *****************************************************************************/
+
+int test_psi_bjerrum_length(void) {
+
+ int ifail = 0;
+
+ {
+ psi_options_t opts = psi_options_default(0);
+ double b1 = 0.0;
+ double b2 = 0.0;
+
+ ifail = psi_bjerrum_length1(&opts, &b1);
+ assert(ifail == 0);
+ ifail = psi_bjerrum_length2(&opts, &b2);
+ assert(ifail == 0);
+ {
+ double e = opts.e;
+ double kt = 1.0/opts.beta;
+ double epsilon = opts.epsilon1;
+ double lbjerrum = e*e/(4.0*4.0*atan(1.0)*epsilon*kt);
+
+ ifail = (fabs(b1 - lbjerrum) > DBL_EPSILON);
+ assert(ifail == 0);
+ ifail = (fabs(b2 - lbjerrum) > DBL_EPSILON);
+ assert(ifail == 0);
+ }
+ }
+
+ {
+ double e = 1.0;
+ double ktref = 0.00001;
+ double epsilon1 = 41.4*1000.0;
+ double epsilon2 = 57.1*1000.0;
+ psi_options_t opts = {.e = e, .beta = 1.0/ktref, .epsilon1 = epsilon1,
+ .epsilon2 = epsilon2};
+ double b1 = 0.0;
+ double b2 = 0.0;
+
+ ifail = psi_bjerrum_length1(&opts, &b1);
+ assert(ifail == 0);
+ assert(fabs(b1 - 0.19221611) < FLT_EPSILON);
+
+ ifail = psi_bjerrum_length2(&opts, &b2);
+ assert(ifail == 0);
+ assert(fabs(b2 - 0.13936510) < FLT_EPSILON);
+ }
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * test_psi_debye_length
+ *
+ * Check both Debye lengths.
+ *
+ *****************************************************************************/
+
+int test_psi_debye_length(void) {
+
+ int ifail = 0;
+
+ {
+ psi_options_t opts = psi_options_default(0);
+ double rho_b = 6.0;
+ double ldebye1 = 0.0;
+ double ldebye2 = 0.0;
+ double ldebye0 = 0.0;
+
+ ifail = psi_debye_length1(&opts, rho_b, &ldebye1);
+ assert(ifail == 0);
+ ifail = psi_debye_length2(&opts, rho_b, &ldebye2);
+ assert(ifail == 0);
+
+ {
+ double lbjerrum = 0.0;
+
+ psi_bjerrum_length1(&opts, &lbjerrum);
+ ldebye0 = 1.0/sqrt(8.0*4.0*atan(1.0)*lbjerrum*rho_b);
+ ifail = (fabs(ldebye1 - ldebye0) > DBL_EPSILON);
+ assert(ifail == 0);
+
+ psi_bjerrum_length2(&opts, &lbjerrum);
+ ldebye0 = 1.0/sqrt(8.0*4.0*atan(1.0)*lbjerrum*rho_b);
+ ifail = (fabs(ldebye2 - ldebye0) > DBL_EPSILON);
+ assert(ifail == 0);
+ }
+ }
+
+ {
+ /* Some numbers from an historical example. */
+ double e = 1.0;
+ double beta = 1.0/0.00033333;
+ double epsilon1 = 300.0;
+ double epsilon2 = 400.0;
+ double rho_el = 0.00047;
+ double ldebye1 = 0.0;
+ double ldebye2 = 0.0;
+ psi_options_t opts = {.e = e, .beta = beta, .epsilon1 = epsilon1,
+ .epsilon2 = epsilon2};
+
+ ifail = psi_debye_length1(&opts, rho_el, &ldebye1);
+ assert(ifail == 0);
+ ifail = psi_debye_length2(&opts, rho_el, &ldebye2);
+ assert(ifail == 0);
+
+ assert(fabs(ldebye1 - 1.03141609e+01) < FLT_EPSILON);
+ assert(fabs(ldebye2 - 1.19097671e+01) < FLT_EPSILON);
+ }
+
+ return ifail;
+}
diff --git a/tests/unit/test_psi_solver_options.c b/tests/unit/test_psi_solver_options.c
new file mode 100644
index 000000000..54b36e014
--- /dev/null
+++ b/tests/unit/test_psi_solver_options.c
@@ -0,0 +1,298 @@
+/*****************************************************************************
+ *
+ * test_psi_solver_options.c
+ *
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "pe.h"
+#include "psi_solver_options.h"
+
+int test_psi_poisson_solver_to_string(void);
+int test_psi_poisson_solver_from_string(void);
+int test_psi_poisson_solver_default(int argc, char ** argv);
+int test_psi_solver_options_default(void);
+int test_psi_solver_options_type(void);
+int test_psi_solver_options_to_json(void);
+int test_psi_solver_options_from_json(void);
+
+/*****************************************************************************
+ *
+ * test_psi_solver_options_suite
+ *
+ *****************************************************************************/
+
+int test_psi_solver_options_suite(int argc, char ** argv) {
+
+ pe_t * pe = NULL;
+
+ pe_create(MPI_COMM_WORLD, PE_QUIET, &pe);
+
+ /* Change in size means change in tests required ... */
+ assert(sizeof(psi_solver_options_t) == 40);
+
+ test_psi_poisson_solver_to_string();
+ test_psi_poisson_solver_from_string();
+ test_psi_poisson_solver_default(argc, argv);
+ test_psi_solver_options_default();
+ test_psi_solver_options_type();
+ test_psi_solver_options_to_json();
+ test_psi_solver_options_from_json();
+
+ pe_info(pe, "%-9s %s\n", "PASS", __FILE__);
+ pe_free(pe);
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * test_psi_poisson_solver_to_string
+ *
+ *****************************************************************************/
+
+int test_psi_poisson_solver_to_string(void) {
+
+ int ifail = 0;
+
+ {
+ const char * str = psi_poisson_solver_to_string(PSI_POISSON_SOLVER_SOR);
+ ifail += strcmp(str, "sor");
+ assert(ifail == 0);
+ }
+
+ {
+ const char * str = psi_poisson_solver_to_string(PSI_POISSON_SOLVER_PETSC);
+ ifail += strcmp(str, "petsc");
+ assert(ifail == 0);
+ }
+
+ {
+ const char * str = psi_poisson_solver_to_string(PSI_POISSON_SOLVER_NONE);
+ ifail += strcmp(str, "none");
+ assert(ifail == 0);
+ }
+
+ {
+ const char * str = psi_poisson_solver_to_string(PSI_POISSON_SOLVER_INVALID);
+ ifail += strcmp(str, "invalid");
+ assert(ifail == 0);
+ }
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * test_psi_poisson_solver_from_string
+ *
+ *****************************************************************************/
+
+int test_psi_poisson_solver_from_string(void) {
+
+ int ifail = 0;
+
+ {
+ psi_poisson_solver_enum_t ps = psi_poisson_solver_from_string("SOR");
+ if (ps != PSI_POISSON_SOLVER_SOR) ifail += 1;
+ assert(ifail == 0);
+ }
+
+ {
+ psi_poisson_solver_enum_t ps = psi_poisson_solver_from_string("PETSC");
+ if (ps != PSI_POISSON_SOLVER_PETSC) ifail += 1;
+ assert(ifail == 0);
+ }
+
+ {
+ psi_poisson_solver_enum_t ps = psi_poisson_solver_from_string("NONE");
+ if (ps != PSI_POISSON_SOLVER_NONE) ifail += 1;
+ }
+
+ {
+ /* Sample rubbish */
+ psi_poisson_solver_enum_t ps = psi_poisson_solver_from_string("RUBBISH");
+ if (ps != PSI_POISSON_SOLVER_INVALID) ifail += 1;
+ assert(ifail == 0);
+ }
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * test_psi_poisson_solver_default
+ *
+ *****************************************************************************/
+
+int test_psi_poisson_solver_default(int argc, char ** argv) {
+
+ int ifail = 0;
+
+ {
+ /* No Petsc */
+ psi_poisson_solver_enum_t psolver = psi_poisson_solver_default();
+ if (psolver != PSI_POISSON_SOLVER_SOR) ifail = -1;
+ assert(ifail == 0);
+ }
+
+ {
+ /* Petsc. This requires check with PetscInitialised(). */
+ int havePetsc = 0;
+
+ PetscInitialize(&argc, &argv, (char *) 0, NULL);
+ PetscInitialised(&havePetsc);
+ if (havePetsc) {
+ psi_poisson_solver_enum_t psolver = psi_poisson_solver_default();
+ if (psolver != PSI_POISSON_SOLVER_PETSC) ifail = -1;
+ assert(ifail == 0);
+ }
+ PetscFinalize();
+ }
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * test_psi_solver_options_default
+ *
+ *****************************************************************************/
+
+int test_psi_solver_options_default(void) {
+
+ int ifail = 0;
+ psi_solver_options_t pso = psi_solver_options_default();
+
+ assert(pso.psolver == psi_poisson_solver_default());
+ assert(pso.maxits == 10000);
+ assert(pso.verbose == 0);
+ assert(pso.nfreq == INT_MAX);
+ assert(pso.nstencil == 7);
+
+ assert(pso.reltol == 1.0e-08);
+ assert(pso.abstol == 1.0e-15);
+
+ ifail = pso.verbose;
+ assert(ifail == 0);
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * test_psi_solver_options_type
+ *
+ *****************************************************************************/
+
+int test_psi_solver_options_type(void) {
+
+ int ifail = 0;
+
+ /* Assume default has passed, and then only the type is relevant... */
+ {
+ psi_solver_options_t p = psi_solver_options_type(PSI_POISSON_SOLVER_SOR);
+ if (p.psolver != PSI_POISSON_SOLVER_SOR) ifail += 1;
+ assert(ifail == 0);
+ }
+
+ {
+ psi_solver_options_t p = psi_solver_options_type(PSI_POISSON_SOLVER_PETSC);
+ if (p.psolver != PSI_POISSON_SOLVER_PETSC) ifail += 1;
+ assert(ifail == 0);
+ }
+
+ {
+ psi_solver_options_t p = psi_solver_options_type(PSI_POISSON_SOLVER_NONE);
+ if (p.psolver != PSI_POISSON_SOLVER_NONE) ifail += 1;
+ assert(ifail == 0);
+ }
+
+ return ifail;
+}
+
+
+/*****************************************************************************
+ *
+ * test_psi_solver_options_to_json
+ *
+ *****************************************************************************/
+
+int test_psi_solver_options_to_json(void) {
+
+ int ifail = 0;
+ psi_solver_options_t pso = psi_solver_options_default();
+ cJSON * json = NULL;
+
+ ifail = psi_solver_options_to_json(&pso, &json);
+ assert(ifail == 0);
+
+ {
+ /* We assume psi_solver_options_from_json() is independent ... */
+ psi_solver_options_t check = {PSI_POISSON_SOLVER_INVALID};
+ ifail = psi_solver_options_from_json(json, &check);
+ assert(ifail == 0);
+ if (check.psolver != PSI_POISSON_SOLVER_SOR) ifail += 1;
+ assert(ifail == 0);
+ }
+
+ cJSON_Delete(json);
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * test_psi_solver_options_from_json
+ *
+ *****************************************************************************/
+
+int test_psi_solver_options_from_json(void) {
+
+ int ifail = 0;
+ const char * jstr = "{\"Solver type\": \"petsc\","
+ "\"Maximum iterations\": 200,"
+ "\"Level of verbosity\": 2,"
+ "\"Frequency of output\": 20,"
+ "\"Stencil points\": 19,"
+ "\"Relative tolerance\": 0.01,"
+ "\"Absolute tolerance\": 0.02}";
+
+ cJSON * json = cJSON_Parse(jstr);
+ assert(json);
+
+ {
+ /* Check result ... */
+ psi_solver_options_t pso = {PSI_POISSON_SOLVER_INVALID};
+ ifail = psi_solver_options_from_json(json, &pso);
+ assert(ifail == 0);
+
+ assert(pso.psolver == PSI_POISSON_SOLVER_PETSC);
+ assert(pso.maxits == 200);
+ assert(pso.verbose == 2);
+ assert(pso.nfreq == 20);
+ assert(pso.nstencil == 19);
+
+ assert(fabs(pso.reltol - 0.01) < DBL_EPSILON);
+ assert(fabs(pso.abstol - 0.02) < DBL_EPSILON);
+ }
+
+ return ifail;
+}
+
+
diff --git a/tests/unit/test_psi_solver_petsc.c b/tests/unit/test_psi_solver_petsc.c
new file mode 100644
index 000000000..6d87e3209
--- /dev/null
+++ b/tests/unit/test_psi_solver_petsc.c
@@ -0,0 +1,67 @@
+/*****************************************************************************
+ *
+ * test_psi_solver_petsc.c
+ *
+ * Some ducking and diving is required depending on whether Petsc
+ * is available.
+ *
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#include
+
+#include "psi_petsc.h"
+
+int test_psi_solver_petsc_create(pe_t * pe);
+
+/*****************************************************************************
+ *
+ * test_psi_solver_petsc_suite
+ *
+ *****************************************************************************/
+
+int test_psi_solver_petsc_suite(void) {
+
+ pe_t * pe = NULL;
+
+ pe_create(MPI_COMM_WORLD, PE_QUIET, &pe);
+
+ test_psi_solver_petsc_create(pe);
+
+ pe_info(pe, "%-9s %s\n", "PASS", __FILE__);
+ pe_free(pe);
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * test_psi_solver_petsc_create
+ *
+ *****************************************************************************/
+
+int test_psi_solver_petsc_create(pe_t * pe) {
+
+ int ifail = 0;
+ int isInitialised = 0;
+
+ PetscInitialised(&isInitialised);
+
+ if (isInitialised == 0) {
+ psi_t * psi = NULL;
+ psi_solver_petsc_t * petsc = NULL;
+
+ ifail = psi_solver_petsc_create(psi, &petsc);
+ assert(ifail != 0);
+ if (ifail != 0) ifail = 0;
+ }
+
+ return 0;
+}
diff --git a/tests/unit/test_psi_sor.c b/tests/unit/test_psi_sor.c
index 39bc9a02d..a97f874dc 100644
--- a/tests/unit/test_psi_sor.c
+++ b/tests/unit/test_psi_sor.c
@@ -7,7 +7,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2012-2022 The University of Edinburgh
+ * (c) 2012-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -22,21 +22,19 @@
#include "pe.h"
#include "coords.h"
-#include "control.h"
-#include "psi_s.h"
#include "psi_sor.h"
-
#include "util.h"
-#include "psi_stats.h"
-#include "tests.h"
#define fe_fake_t void
-int test_psi_sor_poisson(pe_t * pe);
-int test_psi_sor_vare_poisson(pe_t * pe);
+int test_psi_solver_sor_create(pe_t * pe);
+int test_psi_solver_sor_solve(pe_t * pe);
+
+int test_psi_solver_sor_var_epsilon_create(pe_t * pe);
+int test_psi_solver_sor_var_epsilon_solve(pe_t * pe);
static int test_charge1_set(psi_t * psi);
-static int test_charge1_exact(psi_t * obj, f_vare_t fepsilon);
+static int test_charge1_exact(psi_t * obj, var_epsilon_ft fepsilon);
#define REF_PERMEATIVITY 1.0
static int fepsilon_constant(fe_fake_t * fe, int index, double * epsilon);
@@ -53,20 +51,13 @@ int test_psi_sor_suite(void) {
pe_create(MPI_COMM_WORLD, PE_QUIET, &pe);
- {
- int mpisz = pe_mpi_size(pe);
+ test_psi_solver_sor_create(pe);
+ test_psi_solver_sor_solve(pe);
- if (mpisz > 4) {
- /* It's really just a 1-d problem, so no large deompcositions */
- pe_info(pe, "SKIP ./unit/test_psi_sor\n");
- }
- else {
- test_psi_sor_poisson(pe);
- test_psi_sor_vare_poisson(pe);
+ test_psi_solver_sor_var_epsilon_create(pe);
+ test_psi_solver_sor_var_epsilon_solve(pe);
- pe_info(pe, "PASS ./unit/test_psi_sor\n");
- }
- }
+ pe_info(pe, "%-9s %s\n", "PASS", __FILE__);
pe_free(pe);
@@ -75,21 +66,53 @@ int test_psi_sor_suite(void) {
/*****************************************************************************
*
- * test_psi_sor_poisson
+ * test_psi_solver_sor_create
*
- * Set rho(z = 1) = + (1/2NxNy)
- * rho(z = Lz) = + (1/2NxNy)
- * rho = - 1/(NxNy*(Nz-2)) everywhere else.
+ *****************************************************************************/
+
+int test_psi_solver_sor_create(pe_t * pe) {
+
+ int ifail = 0;
+ int nhalo = 2;
+
+ cs_t * cs = NULL;
+ psi_t * psi = NULL;
+ psi_options_t opts = psi_options_default(nhalo);
+
+ cs_create(pe, &cs);
+ cs_nhalo_set(cs, nhalo);
+ cs_init(cs);
+ psi_create(pe, cs, &opts, &psi);
+
+ {
+ psi_solver_sor_t * sor = NULL;
+
+ ifail = psi_solver_sor_create(psi, &sor);
+ assert(ifail == 0);
+ assert(sor->psi == psi);
+ assert(sor->super.impl->solve);
+
+ psi_solver_sor_free(&sor);
+ assert(sor == NULL);
+ }
+
+ return ifail;
+}
+
+/*****************************************************************************
*
- * This is a fully periodic system with zero total charge.
+ * test_psi_solver_sor_solve
*
*****************************************************************************/
-int test_psi_sor_poisson(pe_t * pe) {
+int test_psi_solver_sor_solve(pe_t * pe) {
+
+ int nhalo = 1;
+ int ntotal[3] = {4, 4, 64}; /* Always quasi-1d system in z */
cs_t * cs = NULL;
psi_t * psi = NULL;
- int ntotal[3] = {4, 4, 64};
+ psi_solver_sor_t * sor = NULL;
assert(pe);
@@ -100,32 +123,36 @@ int test_psi_sor_poisson(pe_t * pe) {
int dims[3] = {0,0,1};
MPI_Dims_create(pe_mpi_size(pe), ndims, dims);
- cs_nhalo_set(cs, 1);
+ cs_nhalo_set(cs, nhalo);
cs_ntotal_set(cs, ntotal);
cs_decomposition_set(cs, dims);
}
cs_init(cs);
- psi_create(pe, cs, 2, &psi);
- assert(psi);
-
- psi_valency_set(psi, 0, +1);
- psi_valency_set(psi, 1, -1);
- psi_beta_set(psi, 1.0);
- psi_epsilon_set(psi, REF_PERMEATIVITY);
+ {
+ psi_options_t opts = psi_options_default(nhalo);
+ opts.nk = 2;
+ opts.beta = 1.0;
+ opts.epsilon1 = REF_PERMEATIVITY;
+ psi_create(pe, cs, &opts, &psi);
+ }
test_charge1_set(psi);
psi_halo_psi(psi);
psi_halo_rho(psi);
+ psi_solver_sor_create(psi, &sor);
+
/* Time step is -1 for no output. */
- psi_sor_poisson(psi, -1);
+ psi_solver_sor_solve(sor, -1);
test_charge1_exact(psi, fepsilon_constant);
- psi_free(psi);
+ /* Clear up */
+ psi_solver_sor_free(&sor);
+ psi_free(&psi);
cs_free(cs);
return 0;
@@ -133,7 +160,44 @@ int test_psi_sor_poisson(pe_t * pe) {
/*****************************************************************************
*
- * test_psi_sor_vare_poisson
+ * test_psi_solver_sor_var_epsilon_create
+ *
+ *****************************************************************************/
+
+int test_psi_solver_sor_var_epsilon_create(pe_t * pe) {
+
+ int ifail = 0;
+ int nhalo = 2;
+
+ cs_t * cs = NULL;
+ psi_t * psi = NULL;
+ psi_options_t opts = psi_options_default(nhalo);
+
+ cs_create(pe, &cs);
+ cs_nhalo_set(cs, nhalo);
+ cs_init(cs);
+ psi_create(pe, cs, &opts, &psi);
+
+ {
+ psi_solver_sor_t * sor = NULL;
+ var_epsilon_t user = {.fe = NULL, .epsilon = fepsilon_constant};
+
+ ifail = psi_solver_sor_var_epsilon_create(psi, user, &sor);
+ assert(ifail == 0);
+ assert(sor->psi == psi);
+ assert(sor->epsilon);
+ assert(sor->super.impl->solve);
+
+ psi_solver_sor_free(&sor);
+ assert(sor == NULL);
+ }
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * test_psi_solver_sor_var_epsilon_solve
*
* Same problem as above, but use variable epsilon solver (albeit with
* fixed epsilon here).
@@ -143,27 +207,30 @@ int test_psi_sor_poisson(pe_t * pe) {
*
*****************************************************************************/
-int test_psi_sor_vare_poisson(pe_t * pe) {
+int test_psi_solver_sor_var_epsilon_solve(pe_t * pe) {
+
+ int nhalo = 1;
+ int ntotal[3] = {4, 4, 64}; /* Always quasi-1d system in z */
cs_t * cs = NULL;
psi_t * psi = NULL;
- int ntotal[3] = {4, 4, 64};
+ psi_solver_sor_t * sor = NULL;
assert(pe);
cs_create(pe, &cs);
- cs_nhalo_set(cs, 1);
+ cs_nhalo_set(cs, nhalo);
cs_ntotal_set(cs, ntotal);
cs_init(cs);
- psi_create(pe, cs, 2, &psi);
- assert(psi);
-
- psi_valency_set(psi, 0, +1);
- psi_valency_set(psi, 1, -1);
- psi_beta_set(psi, 1.0);
- psi_reltol_set(psi, 0.01*FLT_EPSILON);
- psi_epsilon_set(psi, REF_PERMEATIVITY);
+ {
+ psi_options_t opts = psi_options_default(nhalo);
+ opts.nk = 2;
+ opts.beta = 1.0;
+ opts.epsilon1 = REF_PERMEATIVITY;
+ opts.solver.reltol = 0.01*FLT_EPSILON; /* Not the default */
+ psi_create(pe, cs, &opts, &psi);
+ }
test_charge1_set(psi);
@@ -171,11 +238,17 @@ int test_psi_sor_vare_poisson(pe_t * pe) {
psi_halo_rho(psi);
/* Time step is -1 to avoid output */
- psi_sor_vare_poisson(psi, NULL, fepsilon_constant, -1);
+ {
+ var_epsilon_t user = {.fe = NULL, .epsilon = fepsilon_constant};
+
+ psi_solver_sor_var_epsilon_create(psi, user, &sor);
+ psi_solver_sor_var_epsilon_solve(sor, -1);
+ psi_solver_sor_free(&sor);
+ }
test_charge1_exact(psi, fepsilon_constant);
- psi_free(psi);
+ psi_free(&psi);
cs_free(cs);
return 0;
@@ -204,10 +277,6 @@ static int test_charge1_set(psi_t * psi) {
double ltot[3];
double rho0, rho1;
-
- double rho_min[4]; /* For psi_stats */
- double rho_max[4]; /* For psi_stats */
- double rho_tot[4]; /* For psi_stats */
MPI_Comm comm;
cs_ltot(psi->cs, ltot);
@@ -220,7 +289,7 @@ static int test_charge1_set(psi_t * psi) {
rho1 = 1.0 / (ltot[X]*ltot[Y]*(ltot[Z] - 2.0)); /* Interior values */
psi_nk(psi, &nk);
- test_assert(nk == 2);
+ assert(nk == 2);
/* Throughout set to rho1 */
@@ -265,27 +334,6 @@ static int test_charge1_set(psi_t * psi) {
}
}
- psi_stats_reduce(psi, rho_min, rho_max, rho_tot, 0, comm);
-
- if (pe_mpi_rank(psi->pe) == 0) {
- /* psi all zero */
- test_assert(fabs(rho_min[0] - 0.0) < DBL_EPSILON);
- test_assert(fabs(rho_max[0] - 0.0) < DBL_EPSILON);
- test_assert(fabs(rho_tot[0] - 0.0) < DBL_EPSILON);
- /* First rho0 interior */
- test_assert(fabs(rho_min[1] - 0.0) < DBL_EPSILON);
- test_assert(fabs(rho_max[1] - rho0) < DBL_EPSILON);
- test_assert(fabs(rho_tot[1] - 1.0) < DBL_EPSILON);
- /* Next rho1 edge */
- test_assert(fabs(rho_min[2] - 0.0) < DBL_EPSILON);
- test_assert(fabs(rho_max[2] - rho1) < DBL_EPSILON);
- test_assert(fabs(rho_tot[2] - 1.0) < FLT_EPSILON);
- /* Total rho_elec */
- test_assert(fabs(rho_min[3] + rho1) < DBL_EPSILON); /* + because valency is - */
- test_assert(fabs(rho_max[3] - rho0) < DBL_EPSILON);
- test_assert(fabs(rho_tot[3] - 0.0) < FLT_EPSILON);
- }
-
return 0;
}
@@ -313,7 +361,7 @@ static int test_charge1_set(psi_t * psi) {
* We also recompute the RHS by differencing the SOR solution with
* a three point stencil in one dimension to provide a final check.
*
- * For variable epsilon, described by the f_vare_t fepsilon,
+ * For variable epsilon, described by the var_epsilon_ft fepsilon,
* we set up a difference scheme using a three-point stencil:
*
* e(i+1/2) psi(i+1) - [ e(i+1/2) + e(i-1/2) ] psi(i) + e(i-1/2) psi(i-1)
@@ -323,7 +371,7 @@ static int test_charge1_set(psi_t * psi) {
*
*****************************************************************************/
-static int test_charge1_exact(psi_t * obj, f_vare_t fepsilon) {
+static int test_charge1_exact(psi_t * obj, var_epsilon_ft fepsilon) {
int k, kp1, km1, index;
int nlocal[3];
@@ -401,7 +449,7 @@ static int test_charge1_exact(psi_t * obj, f_vare_t fepsilon) {
/* Check the Gauss Jordan answer b[] against the answer from psi_t */
- psi_abstol(obj, &tolerance);
+ tolerance = FLT_EPSILON;
rhotot = 0.0;
psi0 = 0.0;
@@ -440,7 +488,7 @@ static int test_charge1_exact(psi_t * obj, f_vare_t fepsilon) {
}
/* Total rho should be unchanged at zero. */
- test_assert(fabs(rhotot) < tolerance);
+ assert(fabs(rhotot) < tolerance);
free(b);
free(a);
@@ -465,15 +513,3 @@ static int fepsilon_constant(fe_fake_t * fe, int index, double * epsilon) {
return 0;
}
-
-/*****************************************************************************
- *
- * fepsilon_sinz
- *
- * Permeativity is a function of z only:
- *
- * e = e0 sin(pi z / Lz)
- *
- * The - 0.5 is to make it symmetric about the centre line.
- *
- *****************************************************************************/
diff --git a/tests/unit/test_stencil_d3q19.c b/tests/unit/test_stencil_d3q19.c
new file mode 100644
index 000000000..711478c85
--- /dev/null
+++ b/tests/unit/test_stencil_d3q19.c
@@ -0,0 +1,65 @@
+/*****************************************************************************
+ *
+ * test_stencil_d3q19.c
+ *
+ *****************************************************************************/
+
+#include
+#include
+#include
+
+#include "pe.h"
+#include "stencil_d3q19.h"
+
+int test_stencil_d3q19_create(void);
+
+/*****************************************************************************
+ *
+ * test_stencil_d3q19_suite
+ *
+ *****************************************************************************/
+
+int test_stencil_d3q19_suite(void) {
+
+ pe_t * pe = NULL;
+
+ pe_create(MPI_COMM_WORLD, PE_QUIET, &pe);
+
+ test_stencil_d3q19_create();
+
+ pe_info(pe, "%-9s %s\n", "PASS", __FILE__);
+ pe_free(pe);
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * test_stencil_d3q19_create
+ *
+ *****************************************************************************/
+
+int test_stencil_d3q19_create(void) {
+
+ int ifail = 0;
+ stencil_t * s = NULL;
+
+ ifail = stencil_d3q19_create(&s);
+ assert(ifail == 0);
+ assert(s);
+ assert(s->ndim == 3);
+ assert(s->npoints == 19);
+ assert(s->cv);
+ assert(s->wlaplacian);
+ assert(s->wgradients);
+
+ if (s->wlaplacian[0] != 24.0) ifail = -1;
+ if (s->wgradients[0] != 0.0) ifail = -1;
+ assert(ifail == 0);
+
+ ifail = stencil_free(&s);
+ assert(ifail == 0);
+ assert(s == NULL);
+
+ return ifail;
+}
diff --git a/tests/unit/test_stencil_d3q27.c b/tests/unit/test_stencil_d3q27.c
new file mode 100644
index 000000000..989102694
--- /dev/null
+++ b/tests/unit/test_stencil_d3q27.c
@@ -0,0 +1,73 @@
+/*****************************************************************************
+ *
+ * test_stencil_d3q27.c
+ *
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#include
+#include
+#include
+
+#include "pe.h"
+#include "stencil_d3q27.h"
+
+int test_stencil_d3q27_create(void);
+
+/*****************************************************************************
+ *
+ * test_stencil_d3q27_suite
+ *
+ *****************************************************************************/
+
+int test_stencil_d3q27_suite(void) {
+
+ pe_t * pe = NULL;
+
+ pe_create(MPI_COMM_WORLD, PE_QUIET, &pe);
+
+ test_stencil_d3q27_create();
+
+ pe_info(pe, "%-9s %s\n", "PASS", __FILE__);
+ pe_free(pe);
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * test_stencil_d3q27_create
+ *
+ *****************************************************************************/
+
+int test_stencil_d3q27_create(void) {
+
+ int ifail = 0;
+ stencil_t * s = NULL;
+
+ ifail = stencil_d3q27_create(&s);
+ assert(ifail == 0);
+ assert(s);
+ assert(s->ndim == 3);
+ assert(s->npoints == 27);
+ assert(s->cv);
+ assert(s->wlaplacian);
+ assert(s->wgradients);
+
+ if (s->wlaplacian[0] != 152.0) ifail = -1;
+ if (s->wgradients[0] != 0.0) ifail = -1;
+ assert(ifail == 0);
+
+ ifail = stencil_free(&s);
+ assert(ifail == 0);
+ assert(s == NULL);
+
+ return ifail;
+}
diff --git a/tests/unit/test_stencil_d3q7.c b/tests/unit/test_stencil_d3q7.c
new file mode 100644
index 000000000..aa8a6bc53
--- /dev/null
+++ b/tests/unit/test_stencil_d3q7.c
@@ -0,0 +1,66 @@
+/*****************************************************************************
+ *
+ * test_stencil_d3q7.c
+ *
+ *****************************************************************************/
+
+#include
+#include
+#include
+
+#include "pe.h"
+#include "stencil_d3q7.h"
+
+int test_stencil_d3q7_create(void);
+
+/*****************************************************************************
+ *
+ * test_stencil_d3q7_suite
+ *
+ *****************************************************************************/
+
+int test_stencil_d3q7_suite(void) {
+
+ pe_t * pe = NULL;
+
+ pe_create(MPI_COMM_WORLD, PE_QUIET, &pe);
+
+ test_stencil_d3q7_create();
+
+ pe_info(pe, "%-9s %s\n", "PASS", __FILE__);
+ pe_free(pe);
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * test_stencil_d3q7_create
+ *
+ *****************************************************************************/
+
+int test_stencil_d3q7_create(void) {
+
+ int ifail = 0;
+ stencil_t * s = NULL;
+
+ ifail = stencil_d3q7_create(&s);
+
+ assert(ifail == 0);
+ assert(s);
+ assert(s->ndim == 3);
+ assert(s->npoints == NVEL_D3Q7);
+ assert(s->cv);
+ assert(s->wlaplacian);
+ assert(s->wgradients);
+
+ if (s->wlaplacian[0] != 6.0) ifail = -1;
+ if (s->wgradients[0] != 0.0) ifail = -1;
+ assert(ifail == 0);
+
+ ifail = stencil_free(&s);
+ assert(ifail == 0);
+ assert(s == NULL);
+
+ return ifail;
+}
diff --git a/tests/unit/test_stencils.c b/tests/unit/test_stencils.c
new file mode 100644
index 000000000..a06afd91f
--- /dev/null
+++ b/tests/unit/test_stencils.c
@@ -0,0 +1,130 @@
+/*****************************************************************************
+ *
+ * test_stencils.c
+ *
+ * Generic tests for the various finite difference stencils.
+ *
+ *
+ * Edinburgh Soft Matter and Statistical Physics Group and
+ * Edinburgh Parallel Computing Centre
+ *
+ * (c) 2023 The University of Edinburgh
+ *
+ * Kevin Stratford (kevin@epcc.ed.ac.uk)
+ *
+ *****************************************************************************/
+
+#include
+#include
+#include
+
+#include "pe.h"
+#include "stencil.h"
+
+int test_stencil_create(int npoints);
+
+/*****************************************************************************
+ *
+ * test_stencils_suite
+ *
+ *****************************************************************************/
+
+int test_stencils_suite(void) {
+
+ pe_t * pe = NULL;
+
+ pe_create(MPI_COMM_WORLD, PE_QUIET, &pe);
+
+ test_stencil_create(7);
+ test_stencil_create(19);
+ test_stencil_create(27);
+
+ pe_info(pe, "%-9s %s\n", "PASS", __FILE__);
+ pe_free(pe);
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * test_stencil_create
+ *
+ * These are generic tests related to the Laplacian and Gradient
+ * computations. Specific errors should be captured by the
+ * relevant specific test.
+ *
+ *****************************************************************************/
+
+int test_stencil_create(int npoints) {
+
+ int ifail = 0;
+ stencil_t * s = NULL;
+
+ ifail = stencil_create(npoints, &s);
+ assert(ifail == 0);
+ assert(s);
+ assert(s->npoints == npoints);
+
+ /* Laplacian central weight */
+
+ {
+ double sum = 0.0;
+ for (int p = 1; p < s->npoints; p++) {
+ sum += s->wlaplacian[p];
+ }
+ if (fabs(s->wlaplacian[0] + sum) > DBL_EPSILON) ifail = -1;
+ assert(ifail == 0);
+ }
+
+ /* Gradient */
+
+ /* d_x */
+ {
+ double fgrad[3] = {0};
+ for (int p = 0; p < s->npoints; p++) {
+ double f = 1.0*s->cv[p][X];
+ fgrad[X] += s->wgradients[p]*s->cv[p][X]*f;
+ fgrad[Y] += s->wgradients[p]*s->cv[p][Y]*f;
+ fgrad[Z] += s->wgradients[p]*s->cv[p][Z]*f;
+ }
+ if (fabs(fgrad[X] - 1.0) > DBL_EPSILON) ifail = -1;
+ if (fabs(fgrad[Y] - 0.0) > DBL_EPSILON) ifail = -2;
+ if (fabs(fgrad[Z] - 0.0) > DBL_EPSILON) ifail = -4;
+ assert(ifail == 0);
+ }
+
+ /* d_y */
+ {
+ double fgrad[3] = {0};
+ for (int p = 0; p < s->npoints; p++) {
+ double f = 1.0*s->cv[p][Y];
+ fgrad[X] += s->wgradients[p]*s->cv[p][X]*f;
+ fgrad[Y] += s->wgradients[p]*s->cv[p][Y]*f;
+ fgrad[Z] += s->wgradients[p]*s->cv[p][Z]*f;
+ }
+ if (fabs(fgrad[X] - 0.0) > DBL_EPSILON) ifail = -1;
+ if (fabs(fgrad[Y] - 1.0) > DBL_EPSILON) ifail = -2;
+ if (fabs(fgrad[Z] - 0.0) > DBL_EPSILON) ifail = -4;
+ assert(ifail == 0);
+ }
+
+ /* d_z */
+ {
+ double fgrad[3] = {0};
+ for (int p = 0; p < s->npoints; p++) {
+ double f = 1.0*s->cv[p][Z];
+ fgrad[X] += s->wgradients[p]*s->cv[p][X]*f;
+ fgrad[Y] += s->wgradients[p]*s->cv[p][Y]*f;
+ fgrad[Z] += s->wgradients[p]*s->cv[p][Z]*f;
+ }
+ if (fabs(fgrad[X] - 0.0) > DBL_EPSILON) ifail = -1;
+ if (fabs(fgrad[Y] - 0.0) > DBL_EPSILON) ifail = -2;
+ if (fabs(fgrad[Z] - 1.0) > DBL_EPSILON) ifail = -4;
+ assert(ifail == 0);
+ }
+
+ stencil_free(&s);
+
+ return ifail;
+}
+
diff --git a/tests/unit/test_util.c b/tests/unit/test_util.c
index 1fcfc03d4..8b7ced2e6 100644
--- a/tests/unit/test_util.c
+++ b/tests/unit/test_util.c
@@ -5,7 +5,7 @@
* Edinburgh Soft Matter and Statistical Physics Group and
* Edinburgh Parallel Computing Centre
*
- * (c) 2012-2020 The University of Edinburgh
+ * (c) 2012-2023 The University of Edinburgh
*
* Contributing authors:
* Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -28,6 +28,8 @@
#define STAT_TOLERANCE 0.001
int util_random_unit_vector_check(void);
+int util_jacobi_check(void);
+int util_dpythag_check(void);
int util_str_tolower_check(void);
int util_rectangle_conductance_check(void);
@@ -45,6 +47,8 @@ int test_util_suite(void) {
util_random_unit_vector_check();
+ util_jacobi_check();
+ util_dpythag_check();
util_str_tolower_check();
util_rectangle_conductance_check();
@@ -107,6 +111,69 @@ int util_random_unit_vector_check(void) {
return 0;
}
+/*****************************************************************************
+ *
+ * util_jacobi_check
+ *
+ *****************************************************************************/
+
+int util_jacobi_check(void) {
+
+ int ifail = 0;
+
+ {
+ double a[3][3] = {0};
+ double evals[3] = {0};
+ double evecs[3][3] = {0};
+
+ ifail = util_jacobi(a, evals, evecs);
+ assert(ifail == 0);
+ if (evals[0] != 0.0) ifail = -1;
+ if (evals[1] != 0.0) ifail = -2;
+ if (evals[2] != 0.0) ifail = -3;
+ if (evecs[0][0] != 1.0) ifail = -4;
+ if (evecs[1][1] != 1.0) ifail = -5;
+ if (evecs[2][2] != 1.0) ifail = -6;
+ assert(ifail == 0);
+ }
+
+ return ifail;
+}
+
+/*****************************************************************************
+ *
+ * util_dpythag_check
+ *
+ *****************************************************************************/
+
+int util_dpythag_check(void) {
+
+ int ifail = 0;
+
+ {
+ double a = 0.0;
+ ifail = util_dpythag(3.0, 4.0, &a);
+ if (fabs(a - 5.0) > DBL_EPSILON) ifail = -1;
+ assert(ifail == 0);
+ }
+
+ {
+ double a = -1.0;
+ ifail = util_dpythag(0.0, 0.0, &a);
+ if (a != 0.0) ifail = -1;
+ assert(ifail == 0);
+ }
+
+ {
+ double a = 0.0;
+ ifail = util_dpythag(12.0, 5.0, &a);
+ if (fabs(a - 13.0) > DBL_EPSILON) ifail = -1;
+ assert(ifail == 0);
+ }
+
+ return ifail;
+}
+
/*****************************************************************************
*
* util_str_tolower_check
diff --git a/tests/unit/tests.c b/tests/unit/tests.c
index 5f7befd5c..6610ab31a 100644
--- a/tests/unit/tests.c
+++ b/tests/unit/tests.c
@@ -19,7 +19,7 @@
#include "tests.h"
-__host__ int tests_create(void);
+__host__ int tests_create(int argc, char ** argv);
/*****************************************************************************
*
@@ -31,7 +31,7 @@ __host__ int main(int argc, char ** argv) {
MPI_Init(&argc, &argv);
- tests_create();
+ tests_create(argc, argv);
MPI_Finalize();
@@ -44,12 +44,12 @@ __host__ int main(int argc, char ** argv) {
*
*****************************************************************************/
-__host__ int tests_create() {
+__host__ int tests_create(int argc, char ** argv) {
test_pe_suite();
test_coords_suite();
test_cs_limits_suite();
-
+
test_kernel_suite();
test_gradient_d3q27_suite();
test_angle_cosine_suite();
@@ -112,12 +112,20 @@ __host__ int tests_create() {
test_phi_bc_outflow_free_suite();
test_phi_ch_suite();
test_polar_active_suite();
+
+ test_psi_solver_options_suite(argc, argv);
+ test_psi_options_suite();
test_psi_suite();
+ test_psi_solver_petsc_suite();
test_psi_sor_suite();
test_nernst_planck_suite();
test_lb_prop_suite();
test_random_suite();
test_rt_suite();
+ test_stencil_d3q7_suite();
+ test_stencil_d3q19_suite();
+ test_stencil_d3q27_suite();
+ test_stencils_suite();
test_timer_suite();
test_util_suite();
test_util_bits_suite();
diff --git a/tests/unit/tests.h b/tests/unit/tests.h
index 6cd5e295b..47ebfa7d5 100644
--- a/tests/unit/tests.h
+++ b/tests/unit/tests.h
@@ -96,10 +96,17 @@ int test_phi_bc_inflow_opts_suite(void);
int test_phi_bc_inflow_fixed_suite(void);
int test_phi_bc_outflow_opts_suite(void);
int test_phi_bc_outflow_free_suite(void);
+int test_psi_solver_options_suite(int argc, char ** argv);
+int test_psi_options_suite(void);
int test_psi_suite(void);
+int test_psi_solver_petsc_suite(void);
int test_psi_sor_suite(void);
int test_random_suite(void);
int test_rt_suite(void);
+int test_stencil_d3q7_suite(void);
+int test_stencil_d3q19_suite(void);
+int test_stencil_d3q27_suite(void);
+int test_stencils_suite(void);
int test_timer_suite(void);
int test_util_suite(void);
int test_util_bits_suite(void);
diff --git a/util/Makefile b/util/Makefile
index 21db9b477..2be135c59 100644
--- a/util/Makefile
+++ b/util/Makefile
@@ -11,7 +11,7 @@
# Edinburgh Soft Matter and Statistical Physics Group and
# Edinburgh Parallel Computing Centre
#
-# (c) 2016-2021 The University of Edinburgh
+# (c) 2016-2023 The University of Edinburgh
#
# Contributing authors:
# Kevin Stratford (kevin@epcc.ed.ac.uk)
@@ -71,10 +71,10 @@ polarizer: polarizer.o
clean:
rm -f *.o colloid_init extract_colloids capillary extract \
coll_squ_subgrid_init multi_poly_init polarizer
+ rm -f *gcda *gcno
.SUFFIXES:
.SUFFIXES: .c .o
.c.o:
$(CC) $(CFLAGS) $(INCL) -c $*.c
-
diff --git a/util/extract.c b/util/extract.c
index a5a51d135..2a73c8ee3 100644
--- a/util/extract.c
+++ b/util/extract.c
@@ -238,7 +238,8 @@ int main(int argc, char ** argv) {
printf("%s %s\n", argv[0], argv[argc-1]);
printf("Identified file name as %s\n", stub);
- sprintf(filename, "%s-metadata.%3.3d-%3.3d", stub, nfile, ifile);
+ snprintf(filename, FILENAME_MAX, "%s-metadata.%3.3d-%3.3d",
+ stub, nfile, ifile);
printf("Attempt to read metadata file %s\n", filename);
pe_create(MPI_COMM_WORLD, PE_QUIET, &pe);
ifail = io_metadata_from_file(pe, filename, &meta);
@@ -267,11 +268,11 @@ int main(int argc, char ** argv) {
exit(-1);
}
else {
- char buf[FILENAME_MAX] = {0};
+ char buf[BUFSIZ] = {0};
char * filename = buf;
int ifile = file_get_file_index(argv[optind]);
int nfile = file_get_file_nfile(argv[optind]);
- sprintf(filename, "%s.%3.3d-%3.3d.meta", stub, nfile, ifile);
+ snprintf(filename, BUFSIZ, "%s.%3.3d-%3.3d.meta", stub, nfile, ifile);
read_meta_data_file(filename, &metadata);
}
}
diff --git a/version.h b/version.h
index 3f2d0d7c8..a78d17dea 100644
--- a/version.h
+++ b/version.h
@@ -13,7 +13,7 @@
#define LUDWIG_VERSION_H
#define LUDWIG_MAJOR_VERSION 0
-#define LUDWIG_MINOR_VERSION 19
-#define LUDWIG_PATCH_VERSION 1
+#define LUDWIG_MINOR_VERSION 20
+#define LUDWIG_PATCH_VERSION 0
#endif