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