diff --git a/doc/Eqs/HADRESS_AT_pair_coul_dsf.jpg b/doc/Eqs/HADRESS_AT_pair_coul_dsf.jpg new file mode 100644 index 000000000..2edcc1fc5 Binary files /dev/null and b/doc/Eqs/HADRESS_AT_pair_coul_dsf.jpg differ diff --git a/doc/Eqs/HADRESS_AT_pair_coul_dsf.tex b/doc/Eqs/HADRESS_AT_pair_coul_dsf.tex new file mode 100644 index 000000000..e97481cff --- /dev/null +++ b/doc/Eqs/HADRESS_AT_pair_coul_dsf.tex @@ -0,0 +1,10 @@ +\documentclass[12pt]{article} + +\begin{document} +$$ + V^{AT} = + q_iq_j \left[ \frac{\mbox{erfc} (\alpha r)}{r} - \frac{\mbox{erfc} (\alpha r_c)}{r_c} + + \left( \frac{\mbox{erfc} (\alpha r_c)}{r_c^2} + \frac{2\alpha}{\sqrt{\pi}}\frac{\exp (-\alpha^2 r^2_c)}{r_c} \right)(r-r_c) \right] \qquad r < r_c +$$ + +\end{document} diff --git a/doc/Eqs/HADRESS_AT_pair_lj.png b/doc/Eqs/HADRESS_AT_pair_lj.png new file mode 100644 index 000000000..2f2e73591 Binary files /dev/null and b/doc/Eqs/HADRESS_AT_pair_lj.png differ diff --git a/doc/Eqs/HADRESS_AT_pair_lj.tex b/doc/Eqs/HADRESS_AT_pair_lj.tex new file mode 100644 index 000000000..6e28b198b --- /dev/null +++ b/doc/Eqs/HADRESS_AT_pair_lj.tex @@ -0,0 +1,11 @@ +\documentstyle[12pt]{article} + +\begin{document} + +$$ + V^{AT} = 4 \epsilon \left[ \left(\frac{\sigma}{r}\right)^{12} - + \left(\frac{\sigma}{r}\right)^6 \right] + \qquad r < r_c +$$ + +\end{document} diff --git a/doc/Eqs/HADRESS_CG_pair_lj.png b/doc/Eqs/HADRESS_CG_pair_lj.png new file mode 100644 index 000000000..518845994 Binary files /dev/null and b/doc/Eqs/HADRESS_CG_pair_lj.png differ diff --git a/doc/Eqs/HADRESS_CG_pair_lj.tex b/doc/Eqs/HADRESS_CG_pair_lj.tex new file mode 100644 index 000000000..86194536f --- /dev/null +++ b/doc/Eqs/HADRESS_CG_pair_lj.tex @@ -0,0 +1,11 @@ +\documentstyle[12pt]{article} + +\begin{document} + +$$ + V^{CG} = 4 \epsilon \left[ \left(\frac{\sigma}{r}\right)^{12} - + \left(\frac{\sigma}{r}\right)^6 \right] + \qquad r < r_c +$$ + +\end{document} diff --git a/doc/Eqs/HADRESS_Switching_Function_Cylinder.tex b/doc/Eqs/HADRESS_Switching_Function_Cylinder.tex new file mode 100644 index 000000000..bd6b156c0 --- /dev/null +++ b/doc/Eqs/HADRESS_Switching_Function_Cylinder.tex @@ -0,0 +1,15 @@ +\documentclass[12pt]{article} + +\begin{document} + +\begin{eqnarray*} +\lambda(r)=\left\{ +\begin{array}{ll} +1 & r \leq r_{at}\\ +\cos^2\left(\frac{\pi(r-r_{at})}{2r_{hy}}\right) & r_{at}< r \leq r_{at}+r_{hy}\\ +0 & r > r_{at}+r_{hy} +\end{array} +\right. +\end{eqnarray*} + +\end{document} \ No newline at end of file diff --git a/doc/Eqs/HADRESS_Switching_Function_Slab.png b/doc/Eqs/HADRESS_Switching_Function_Slab.png new file mode 100644 index 000000000..c50bcb458 Binary files /dev/null and b/doc/Eqs/HADRESS_Switching_Function_Slab.png differ diff --git a/doc/Eqs/HADRESS_Switching_Function_Slab.tex b/doc/Eqs/HADRESS_Switching_Function_Slab.tex new file mode 100644 index 000000000..878bb4da8 --- /dev/null +++ b/doc/Eqs/HADRESS_Switching_Function_Slab.tex @@ -0,0 +1,13 @@ +\documentclass[12pt]{article} + +\begin{document} +$$ +\lambda(x)=\left\{ +\begin{array}{ll} +1 & |x| \leq L_{AT}/2\\ +\cos^2\left(\frac{\pi(x-L_{AT}/2)}{2L_{HY}}\right) & \frac{L_{AT}}{2}< |x| \leq \frac{L_{AT}}{2}+L_{HY}\\ +0 & |x| > L_{AT}+L_{HY} +\end{array} +\right. +$$ +\end{document} \ No newline at end of file diff --git a/doc/Eqs/HADRESS_Switching_Function_Sphere.png b/doc/Eqs/HADRESS_Switching_Function_Sphere.png new file mode 100644 index 000000000..6a16b9838 Binary files /dev/null and b/doc/Eqs/HADRESS_Switching_Function_Sphere.png differ diff --git a/doc/Eqs/HADRESS_Switching_Function_Sphere.tex b/doc/Eqs/HADRESS_Switching_Function_Sphere.tex new file mode 100644 index 000000000..bd6b156c0 --- /dev/null +++ b/doc/Eqs/HADRESS_Switching_Function_Sphere.tex @@ -0,0 +1,15 @@ +\documentclass[12pt]{article} + +\begin{document} + +\begin{eqnarray*} +\lambda(r)=\left\{ +\begin{array}{ll} +1 & r \leq r_{at}\\ +\cos^2\left(\frac{\pi(r-r_{at})}{2r_{hy}}\right) & r_{at}< r \leq r_{at}+r_{hy}\\ +0 & r > r_{at}+r_{hy} +\end{array} +\right. +\end{eqnarray*} + +\end{document} \ No newline at end of file diff --git a/doc/Eqs/HADRESS_System_Hamiltonian.png b/doc/Eqs/HADRESS_System_Hamiltonian.png new file mode 100644 index 000000000..2e76b4819 Binary files /dev/null and b/doc/Eqs/HADRESS_System_Hamiltonian.png differ diff --git a/doc/Eqs/HADRESS_System_Hamiltonian.tex b/doc/Eqs/HADRESS_System_Hamiltonian.tex new file mode 100644 index 000000000..34239bc52 --- /dev/null +++ b/doc/Eqs/HADRESS_System_Hamiltonian.tex @@ -0,0 +1,9 @@ +\documentclass[12pt]{article} + +\begin{document} + +\begin{eqnarray}\label{hadress_H} +&&H = K + V^{int} + \sum_{\alpha} \left\{{\lambda_\alpha} {V^{AT}_\alpha} + {(1 - \lambda_\alpha)} {V^{CG}_\alpha} \right\}\\ \nonumber +\end{eqnarray} + +\end{document} \ No newline at end of file diff --git a/doc/Eqs/HADRESS_System_Potentials.png b/doc/Eqs/HADRESS_System_Potentials.png new file mode 100644 index 000000000..8cfcfe612 Binary files /dev/null and b/doc/Eqs/HADRESS_System_Potentials.png differ diff --git a/doc/Eqs/HADRESS_System_Potentials.tex b/doc/Eqs/HADRESS_System_Potentials.tex new file mode 100644 index 000000000..821df897a --- /dev/null +++ b/doc/Eqs/HADRESS_System_Potentials.tex @@ -0,0 +1,10 @@ +\documentclass[12pt]{article} + +\begin{document} + +\begin{eqnarray}\label{hadress_V} +&& V^{AT}_\alpha \equiv \displaystyle\frac{1}{2}\sum_{\beta,\beta\neq \alpha}^{N} \sum_{ij} V^{AT}(|\textbf{r}_{\alpha i} - \textbf{r}_{\beta j}|)\\ \nonumber +&& V^{CG}_\alpha \equiv \displaystyle\frac{1}{2}\sum_{\beta,\beta\neq \alpha}^{N} V^{CG}(|\textbf{R}_\alpha - \textbf{R}_\beta|) +\end{eqnarray} + +\end{document} \ No newline at end of file diff --git a/doc/JPG/HADRESS_MODEL_LAMMPS.png b/doc/JPG/HADRESS_MODEL_LAMMPS.png new file mode 100644 index 000000000..5626fef66 Binary files /dev/null and b/doc/JPG/HADRESS_MODEL_LAMMPS.png differ diff --git a/doc/fix_lambdah_calc.html b/doc/fix_lambdah_calc.html new file mode 100644 index 000000000..269af18ff --- /dev/null +++ b/doc/fix_lambdah_calc.html @@ -0,0 +1,244 @@ +<HTML> +<CENTER><A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> - <A HREF = "Manual.html">LAMMPS Documentation</A> - <A HREF = "Section_commands.html#comm">LAMMPS Commands</A> +</CENTER> + + + + + + +<HR> + +<H3>fix lambdah command +</H3> +<P><B>Syntax:</B> +</P> +<PRE>fix ID group-ID lambdah/calc N<sub>H-mol</sub> L<sub>HY</sub> L<sub>AT</sub> P<sub>flag</sub> δλ dT<sub>p</sub> T<sub>p</sub><sup>Start</sup> T<sub>p</sub><sup>End</sup> HY<sub>Shape</sub> D<sub>flag</sub> Δx dT<sub>d</sub> T<sub>d</sub><sup>Start</sup> T<sub>d</sub><sup>End</sup> σ R ρ<sub>0</sub> c file<sub>flag</sub> +</PRE> +<UL><LI>ID is documented in <A HREF = "fix.html">fix</A> command + +<LI>group-ID has to be all + +<LI>lambdaH/calc = style name of this fix command + +<LI>N<sub>H-mol</sub> = Number of molecular types within the low resolution + +<LI>L<sub>HY</sub> = Length of Hybrid region + +<LI>L<sub>AT</sub> = Length of Atomistic (high resolution) region + +<LI>P<sub>flag</sub> = <I>0</I> or <I>1</I> + +<PRE> <I>0</I> Constant-pressure route is off + <I>1</I> Constant-pressure route is on +</PRE> +<LI>δλ = Bin size in constant-pressure route + +<LI>dT<sub>p</sub> = Time step interval of constant-pressure route + +<LI>T<sub>p</sub><sup>Start</sup> = Starting time step of constant-pressure route + +<LI>T<sub>p</sub><sup>End</sup> = Ending time step of constant-pressure route + +<LI>HY<sub>Shape</sub> = Shape of Hybrid region : <I>slab</I>, <I>sphere</I>, <I>cylinder</I> + +<PRE> <I>slab</I> is for rectangular hybrid region + <I>sphere</I> is for spherical hybrid region + <I>cylinder</I> is for cylinderical hybrid region +</PRE> +<LI>D<sub>flag</sub> = <I>0</I> or <I>1</I> + +<PRE> <I>0</I> Constant-density route is off + <I>1</I> Constant-density route is on +</PRE> +<LI>Δx = Bin size in constant-density route (length unit) + +<LI>dT<sub>d</sub> = Time step interval of constant-density route + +<LI>T<sub>d</sub><sup>Start</sup> = Starting time step of constant-density route + +<LI>T<sub>d</sub><sup>End</sup> = Ending time step of constant-density route + +<LI>σ = Width of gaussian function in constant-density route (length unit) + +<LI>R = Range of gaussian function in constant-density route (length unit) + +<LI>ρ<sub>0</sub> = Reference number density in constant-density route + +<LI>c = Prefactor in constant-density route (energy unit) + +<LI>file<sub>flag</sub> = <I>0</I> or <I>1</I> + +<PRE> <I>0</I> Do not employ density-balancing file + <I>1</I> Employ density-balancing file +</PRE> + +</UL> +<P><B>Examples:</B> +</P> +<PRE>fix 1 all lambdah/calc 1 25 60 1 0.02 1000 150000 300000 slab 1 1.5 500 400000 700000 6 2 0.1 2 0 +fix 1 all lambdah/calc 1 25 60 1 0.02 1000 100000 200000 sphere 1 1.5 500 300000 700000 6 2 0.1 2 0 +</PRE> +<P><B>Description:</B> +</P> +<P>The Hamiltonian adaptive resolution simulation scheme (H-AdResS) is a dual-resolution simulation method that +joins models with different levels of complexity for the same system within a global Hamiltonian framework <A HREF = "#Potestio2013_1">(Potestio2013_1)</A>, <A HREF = "#Potestio2013_2">(Potestio2013_2)</A>, <A HREF = "#Heidari2016">(Heidari2016)</A>. +</P> +<P>Depending on the shape of the Hybrid region which might be either slab, sphere or cynlinder, this fix calculates +the resolution of every atom based on the center of mass of its molecule. +The following switching function is defined for a simulation box whose atomistic region is limited to [-0.5L<sub>AT</sub> 0.5L<sub>AT</sub>]: +</P> +<CENTER><IMG SRC = "Eqs/HADRESS_Switching_Function_Slab.png"> +</CENTER> +<P>The following switching function is defined for a spherical/cylinderical atomistic region located at the middle of the simulation box: +</P> +<CENTER><IMG SRC = "Eqs/HADRESS_Switching_Function_Sphere.png"> +</CENTER> +<P>A setup of a Hamiltonian Adaptive Resolution Simulation is shown below. The box is partitioned into three + different region types, namely: Coarse-grained (CG), Hybrid (HY), and Atomistic (AT). In each region, + the resolution of each molecule (here water) is determined by the instantaneous value of the + smooth function λ represented above the simulation snapshot. +</P> +<CENTER><IMG SRC = "JPG/HADRESS_MODEL_LAMMPS.png"> +</CENTER> +<P><I>N<sub>H-mol</sub></I> determines the number of molecular types within the low resolution. For instance, for a system containing +coarse-grained water molecules in the coarse-grained region, this number equals one. However, for a sytem containing +water molecules and ions such as Na and Cl and they interact differently in the coarse-grained region, +this number is 3. +</P> +<P>The <I>L<sub>HY</sub></I> specifies the length of the Hybrid region. For the cases of cylinderical or spherical hybrid regions, this quantity denotes <I>r<sub>HY</sub></I>. +</P> +<P>The <I>L<sub>AT</sub></I> determines the length of Atomistic region. For the cases of cylinderical or spherical hybrid regions, this quantity denotes <I>r<sub>AT</sub></I>. +</P> +<P>The <I>P<sub>flag</sub></I> switches off and on the constant-pressure route. +</P> +<P>The <I>δλ</I> denotes the bin size over the hybrid region. In the on-the-fly method of averaging the drift forces, +particles are sorted into uniformly spaced λ bins of <I>δλ</I> side. +</P> +<P>The <I>dT<sub>p</sub></I> denotes the time intervals in constant-pressure route at which the averaged drift forces are applied on the molecules of the hybrid region. +</P> +<P>The <I>T<sub>p</sub><sup>Start</sup></I> denotes the time step at which the simulation of the constant-pressure route is started. +</P> +<P>The <I>T<sub>p</sub><sup>End</sup></I> specifies the ending time step of the constant-pressure route. +</P> +<P>The <I>HY<sub>Shape</sub></I> specifies the geometry of the Hybrid region. This could be <I>slab</I>, <I>sphere</I>, <I>cylinder</I>. +</P> +<P><I>D<sub>flag</sub></I> switches off and on the constant-pressure route. +</P> +<P><I>Δx</I> is the bin size by which the simulation box is descritized in the constant-density route. +</P> +<P><I>dT<sub>d</sub></I> is the time interval in constant-density route at which the averaged thermodynamic forces are applied. +</P> +<P><I>T<sub>d</sub><sup>Start</sup></I> is the starting time step of constant-density route. +</P> +<P><I>T<sub>d</sub><sup>End</sup></I> is the ending time step of constant-density route. +</P> +<P><I>σ</I> is the width of Gaussian function in the constant-density route. +</P> +<P><I>R</I> is the range of Gaussian function in the constant-density route. +</P> +<P><I>ρ<sub>0</sub></I> is the reference density in the constant-density route. +</P> +<P><I>c</I> is the prefactor in the constant-density route. +</P> +<P><I>file<sub>flag</sub></I> denotes a flag whether the file containing the density-balancing force is employed or not. +</P> +<HR> + +<P><B>Restart, fix_modify, output, run start/stop, minimize info:</B> +</P> +<P>No information about this fix is written to <A HREF = "restart.html">binary restart +files</A>. +</P> +<P>This fix creates a file named "Mean_Comp_Density.txt" in which the compensation forces are printed. +This file is created at <I>T<sub>d</sub><sup>Start</sup></I> and is updated every <I>dT<sub>d</sub></I>. +The updating process of the file is finished at time step <I>T<sub>d</sub><sup>End</sup></I>. +For those equillibrated simulations starting at time step larger than <I>T<sub>d</sub><sup>End</sup></I>, +the file "Mean_Comp_Density.txt" is loaded in this fix. +</P> +<HR> + +<P><B>Restrictions:</B> +</P> +<P>This fix calculates the center of mass of the particles. Thus at the beginning of the calculation, +it is required that all atoms belonging to a molecule are on the same side of the box. +</P> +<P>To employ the H-AdResS scheme, the full/hars atom style has to be used: +</P> +<PRE> atom_style full/hars +</PRE> +<P>To perform HAdResS, Data File should contain the following extra information with respect to the Data File defined in full atom style: +</P> +<P>[1] <B>mol_H</B> determines the number of molecular types in the low resolution (coarse-grained) region. +</P> +<P>[2] <B>representative_flag</B> determines which atom carries the molecule's information +(center of mass, molecule's resolution, ...) in the low resolution (coarse-grained) region. +</P> +<P>[3] <B>mol_type</B> denotes the type of the molecule in the low resolution (coarse-grained) region. +</P> +<P>The following example is extracted from a Data File in which the simulation box contains water molecules and the ions of sodium and cholorine: +</P> +<PRE>30720 atoms +20480 bonds +10240 angles +</PRE> +<PRE>4 atom types +<B>1 mol_H types</B> +1 bond types +1 angle types +</PRE> +<PRE>-99.968000 99.968000 xlo xhi +-20.793600 20.793600 ylo yhi +-20.793600 20.793600 zlo zhi +</PRE> +<PRE>Masses +</PRE> +<PRE>1 15.999400 +2 1.007940 +3 22.9898 +4 35.453 +</PRE> +<PRE>Atoms +#atomID molecule-tag atom-type q <B>representative_flag mol_type</B> x y z +1 1 1 -0.847200 1 1 -99.654503 -19.897600 -20.192101 +2 1 2 0.423600 0 1 -100.568001 -19.999300 -20.586599 +3 1 2 0.423600 0 1 -99.777702 -20.103100 -19.221300 +4 2 1 -0.847200 1 1 -97.826401 -17.709900 -20.127100 +5 2 2 0.423600 0 1 -96.938400 -18.071301 -19.842800 +6 2 2 0.423600 0 1 -97.735100 -16.718800 -20.030100 +7 3 3 1.0 1 1 -97.429398 -20.402201 -17.494900 +8 3 4 -1.0 1 1 -96.834000 -19.671400 -17.160999 +. +. +. +</PRE> +<P>As it is shown, the representative_flag of the oxygen atoms is equal 1, and +since the soldium and cholorine are single atom ions, their representative_flags are also equals 1. +The interactions of water molecules and ions are the same in the coarse-grained region, +thus they all carry the same molecular type (mol_type). +</P> +<HR> + +<P><B>Related commands:</B> +</P> +<P><A HREF = "pair_lj_hars.html">pair_lj_hars.html</A> +</P> +<P><B>Default:</B> none +</P> +<HR> + +<A NAME = "Potestio2013_1"></A> + +<P><B>(Potestio2013_1)</B> R. Potestio, S. Fritsch, P. Espanol, R. Delgado-Buscalioni, K. Kremer, R. Everaers, and D. Donadio, <I>Hamiltonian Adaptive Resolution Simulation for Molecular Liquids</I>, <A HREF = "http://dx.doi.org/10.1103/PhysRevLett.110.108301">Phys. Rev. Lett. [110], +108301 (2013)</A> +</P> +<A NAME = "Potestio2013_2"></A> + +<P><B>(Potestio2013_2)</B> R. Potestio, S. Fritsch, P. Espanol, R. Delgado-Buscalioni, K. Kremer, R. Everaers, and D. Donadio, <I>Monte Carlo Adaptive Resolution Simulation of Multicomponent Molecular Liquids</I>, <A HREF = "http://dx.doi.org/10.1103/PhysRevLett.111.060601">Phys. Rev. Lett. [111], +060601 (2013)</A> +</P> +<A NAME = "Heidari2016"></A> + +<P><B>(Heidari2016)</B> M. Heidari, R. Cortes-Huerto, D. Donadio and R. Potestio, <I>Accurate and general treatment of electrostatic interaction in Hamiltonian adaptive resolution simulations</I>, "EPJST (2016)" +</P> +</HTML> diff --git a/doc/fix_lambdah_calc.txt b/doc/fix_lambdah_calc.txt new file mode 100644 index 000000000..178f727d1 --- /dev/null +++ b/doc/fix_lambdah_calc.txt @@ -0,0 +1,212 @@ +"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c + +:link(lws,http://lammps.sandia.gov) +:link(ld,Manual.html) +:link(lc,Section_commands.html#comm) + +:line + +fix lambdah command :h3 + +[Syntax:] + +fix ID group-ID lambdah/calc N<sub>H-mol</sub> L<sub>HY</sub> L<sub>AT</sub> P<sub>flag</sub> δλ dT<sub>p</sub> T<sub>p</sub><sup>Start</sup> T<sub>p</sub><sup>End</sup> HY<sub>Shape</sub> D<sub>flag</sub> Δx dT<sub>d</sub> T<sub>d</sub><sup>Start</sup> T<sub>d</sub><sup>End</sup> σ R ρ<sub>0</sub> c file<sub>flag</sub> :pre + +ID is documented in "fix"_fix.html command :ulb,l +group-ID has to be all :l +lambdaH/calc = style name of this fix command :l +N<sub>H-mol</sub> = Number of molecular types within the low resolution :l +L<sub>HY</sub> = Length of Hybrid region :l +L<sub>AT</sub> = Length of Atomistic (high resolution) region :l +P<sub>flag</sub> = {0} or {1} :l + {0} Constant-pressure route is off + {1} Constant-pressure route is on :pre +δλ = Bin size in constant-pressure route :l +dT<sub>p</sub> = Time step interval of constant-pressure route :l +T<sub>p</sub><sup>Start</sup> = Starting time step of constant-pressure route :l +T<sub>p</sub><sup>End</sup> = Ending time step of constant-pressure route :l +HY<sub>Shape</sub> = Shape of Hybrid region : {slab}, {sphere}, {cylinder} :l + {slab} is for rectangular hybrid region + {sphere} is for spherical hybrid region + {cylinder} is for cylinderical hybrid region :pre +D<sub>flag</sub> = {0} or {1} :l + {0} Constant-density route is off + {1} Constant-density route is on :pre +Δx = Bin size in constant-density route (length unit) :l +dT<sub>d</sub> = Time step interval of constant-density route :l +T<sub>d</sub><sup>Start</sup> = Starting time step of constant-density route :l +T<sub>d</sub><sup>End</sup> = Ending time step of constant-density route :l +σ = Width of gaussian function in constant-density route (length unit) :l +R = Range of gaussian function in constant-density route (length unit) :l +ρ<sub>0</sub> = Reference number density in constant-density route :l +c = Prefactor in constant-density route (energy unit) :l +file<sub>flag</sub> = {0} or {1} :l + {0} Do not employ density-balancing file + {1} Employ density-balancing file :pre + +:ule + +[Examples:] + +fix 1 all lambdah/calc 1 25 60 1 0.02 1000 150000 300000 slab 1 1.5 500 400000 700000 6 2 0.1 2 0 +fix 1 all lambdah/calc 1 25 60 1 0.02 1000 100000 200000 sphere 1 1.5 500 300000 700000 6 2 0.1 2 0 :pre + +[Description:] + +The Hamiltonian adaptive resolution simulation scheme (H-AdResS) is a dual-resolution simulation method that +joins models with different levels of complexity for the same system within a global Hamiltonian framework "(Potestio2013_1)"_#Potestio2013_1, "(Potestio2013_2)"_#Potestio2013_2, "(Heidari2016)"_#Heidari2016. + +Depending on the shape of the Hybrid region which might be either slab, sphere or cynlinder, this fix calculates +the resolution of every atom based on the center of mass of its molecule. +The following switching function is defined for a simulation box whose atomistic region is limited to \[-0.5L<sub>AT</sub> 0.5L<sub>AT</sub>\]: + +:c,image(Eqs/HADRESS_Switching_Function_Slab.png) + +The following switching function is defined for a spherical/cylinderical atomistic region located at the middle of the simulation box: + +:c,image(Eqs/HADRESS_Switching_Function_Sphere.png) + +A setup of a Hamiltonian Adaptive Resolution Simulation is shown below. The box is partitioned into three + different region types, namely: Coarse-grained (CG), Hybrid (HY), and Atomistic (AT). In each region, + the resolution of each molecule (here water) is determined by the instantaneous value of the + smooth function λ represented above the simulation snapshot. + +:c,image(JPG/HADRESS_MODEL_LAMMPS.png) + +{N<sub>H-mol</sub>} determines the number of molecular types within the low resolution. For instance, for a system containing +coarse-grained water molecules in the coarse-grained region, this number equals one. However, for a sytem containing +water molecules and ions such as Na and Cl and they interact differently in the coarse-grained region, +this number is 3. + +The {L<sub>HY</sub>} specifies the length of the Hybrid region. For the cases of cylinderical or spherical hybrid regions, this quantity denotes {r<sub>HY</sub>}. + +The {L<sub>AT</sub>} determines the length of Atomistic region. For the cases of cylinderical or spherical hybrid regions, this quantity denotes {r<sub>AT</sub>}. + +The {P<sub>flag</sub>} switches off and on the constant-pressure route. + +The {δλ} denotes the bin size over the hybrid region. In the on-the-fly method of averaging the drift forces, +particles are sorted into uniformly spaced λ bins of {δλ} side. + +The {dT<sub>p</sub>} denotes the time intervals in constant-pressure route at which the averaged drift forces are applied on the molecules of the hybrid region. + +The {T<sub>p</sub><sup>Start</sup>} denotes the time step at which the simulation of the constant-pressure route is started. + +The {T<sub>p</sub><sup>End</sup>} specifies the ending time step of the constant-pressure route. + +The {HY<sub>Shape</sub>} specifies the geometry of the Hybrid region. This could be {slab}, {sphere}, {cylinder}. + +{D<sub>flag</sub>} switches off and on the constant-pressure route. + +{Δx} is the bin size by which the simulation box is descritized in the constant-density route. + +{dT<sub>d</sub>} is the time interval in constant-density route at which the averaged thermodynamic forces are applied. + +{T<sub>d</sub><sup>Start</sup>} is the starting time step of constant-density route. + +{T<sub>d</sub><sup>End</sup>} is the ending time step of constant-density route. + +{σ} is the width of Gaussian function in the constant-density route. + +{R} is the range of Gaussian function in the constant-density route. + +{ρ<sub>0</sub>} is the reference density in the constant-density route. + +{c} is the prefactor in the constant-density route. + +{file<sub>flag</sub>} denotes a flag whether the file containing the density-balancing force is employed or not. + +:line + +[Restart, fix_modify, output, run start/stop, minimize info:] + +No information about this fix is written to "binary restart +files"_restart.html. + +This fix creates a file named "Mean_Comp_Density.txt" in which the compensation forces are printed. +This file is created at {T<sub>d</sub><sup>Start</sup>} and is updated every {dT<sub>d</sub>}. +The updating process of the file is finished at time step {T<sub>d</sub><sup>End</sup>}. +For those equillibrated simulations starting at time step larger than {T<sub>d</sub><sup>End</sup>}, +the file "Mean_Comp_Density.txt" is loaded in this fix. + +:line + +[Restrictions:] + +This fix calculates the center of mass of the particles. Thus at the beginning of the calculation, +it is required that all atoms belonging to a molecule are on the same side of the box. + +To employ the H-AdResS scheme, the full/hars atom style has to be used: + + atom_style full/hars :pre + +To perform HAdResS, Data File should contain the following extra information with respect to the Data File defined in full atom style: + +\[1\] [mol_H] determines the number of molecular types in the low resolution (coarse-grained) region. + +\[2\] [representative_flag] determines which atom carries the molecule's information +(center of mass, molecule's resolution, ...) in the low resolution (coarse-grained) region. + +\[3\] [mol_type] denotes the type of the molecule in the low resolution (coarse-grained) region. + +The following example is extracted from a Data File in which the simulation box contains water molecules and the ions of sodium and cholorine: + +30720 atoms +20480 bonds +10240 angles :pre + +4 atom types +[1 mol_H types] +1 bond types +1 angle types :pre + +-99.968000 99.968000 xlo xhi +-20.793600 20.793600 ylo yhi +-20.793600 20.793600 zlo zhi :pre + +Masses :pre + +1 15.999400 +2 1.007940 +3 22.9898 +4 35.453 :pre + +Atoms +#atomID molecule-tag atom-type q [representative_flag mol_type] x y z +1 1 1 -0.847200 1 1 -99.654503 -19.897600 -20.192101 +2 1 2 0.423600 0 1 -100.568001 -19.999300 -20.586599 +3 1 2 0.423600 0 1 -99.777702 -20.103100 -19.221300 +4 2 1 -0.847200 1 1 -97.826401 -17.709900 -20.127100 +5 2 2 0.423600 0 1 -96.938400 -18.071301 -19.842800 +6 2 2 0.423600 0 1 -97.735100 -16.718800 -20.030100 +7 3 3 1.0 1 1 -97.429398 -20.402201 -17.494900 +8 3 4 -1.0 1 1 -96.834000 -19.671400 -17.160999 +. +. +. :pre + +As it is shown, the representative_flag of the oxygen atoms is equal 1, and +since the soldium and cholorine are single atom ions, their representative_flags are also equals 1. +The interactions of water molecules and ions are the same in the coarse-grained region, +thus they all carry the same molecular type (mol_type). + +:line + +[Related commands:] + +"pair_lj_hars.html"_pair_lj_hars.html + +[Default:] none + +:line + + +:link(Potestio2013_1) +[(Potestio2013_1)] R. Potestio, S. Fritsch, P. Espanol, R. Delgado-Buscalioni, K. Kremer, R. Everaers, and D. Donadio, {Hamiltonian Adaptive Resolution Simulation for Molecular Liquids}, "Phys. Rev. Lett. \[110\], +108301 (2013)"_http://dx.doi.org/10.1103/PhysRevLett.110.108301 + +:link(Potestio2013_2) +[(Potestio2013_2)] R. Potestio, S. Fritsch, P. Espanol, R. Delgado-Buscalioni, K. Kremer, R. Everaers, and D. Donadio, {Monte Carlo Adaptive Resolution Simulation of Multicomponent Molecular Liquids}, "Phys. Rev. Lett. \[111\], +060601 (2013)"_http://dx.doi.org/10.1103/PhysRevLett.111.060601 + +:link(Heidari2016) +[(Heidari2016)] M. Heidari, R. Cortes-Huerto, D. Donadio and R. Potestio, {Accurate and general treatment of electrostatic interaction in Hamiltonian adaptive resolution simulations}, "EPJST (2016)" diff --git a/doc/pair_lj_hars.html b/doc/pair_lj_hars.html new file mode 100644 index 000000000..50596c9d3 --- /dev/null +++ b/doc/pair_lj_hars.html @@ -0,0 +1,198 @@ +<HTML> +<CENTER><A HREF = "http://lammps.sandia.gov">LAMMPS WWW Site</A> - <A HREF = "Manual.html">LAMMPS Documentation</A> - <A HREF = "Section_commands.html#comm">LAMMPS Commands</A> +</CENTER> + + + + + + +<HR> + +<H3>pair_style lj/cut/hars/at command +</H3> +<H3>pair_style lj/cut/coul/dsf/hars/at command +</H3> +<H3>pair_style lj/cut/hars/cg command +</H3> +<P><B>Syntax:</B> +</P> +<PRE>pair_style style args +</PRE> +<LI>style = + +<PRE> <I>lj/cut/hars/at</I> or + <I>lj/cut/coul/dsf/hars/at</I> or + <I>lj/cut/hars/cg</I> +</PRE> +<LI>args = list of arguments for a particular style + +<PRE> <I>lj/cut/hars/at</I> args = cutoff All_AT Flag_Load_File + cutoff = global cutoff for Lennard Jones interactions (distance units) + All_AT = Fully atomic simulation flag, = <I>0</I> or <I>1</I> + <I>0</I> Fully atomic simulation is off and HAdResS is on + <I>1</I> Fully atomic simulation is on and HAdResS is off + Flag_Load_File = Flag of employing compensation energy file, = <I>0</I> or <I>1</I> + <I>0</I> Do not employ compensation energy until T<sub>p</sub><sup>Start</sup> + <I>1</I> Employ compensation energy file immediately +</PRE> +<PRE> <I>lj/cut/coul/dsf/hars/at</I> args = Alpha LJcutoff Coulcutoff All_AT Flag_Load_File + Alpha = Damping coefficient in DSF potential (1.0/distance units) + LJcutoff = global cutoff for Lennard Jones interactions (distance units) + Coulcutoff = global cutoff for DSF coulombic interactions (distance units) + All_AT = Fully atomic simulation flag, = <I>0</I> or <I>1</I> + <I>0</I> Fully atomic simulation is off and HAdResS is on + <I>1</I> Fully atomic simulation is on and HAdResS is off + Flag_Load_File = Flag of employing compensation energy file, = <I>0</I> or <I>1</I> + <I>0</I> Do not employ compensation energy until T<sub>p</sub><sup>Start</sup> + <I>1</I> Employ compensation energy file immediately +</PRE> +<PRE> <I>lj/cut/hars/cg</I> args = cutoff All_CG Flag_Load_File + cutoff = global cutoff for Lennard Jones interactions (distance units) + All_CG = Fully coarse-grained simulation flag, = <I>0</I> or <I>1</I> + <I>0</I> Fully coarse-grained simulation is off and HAdResS is on + <I>1</I> Fully coarse-grained simulation is on and HAdResS is off + Flag_Load_File = Flag of employing compensation energy file, = <I>0</I> or <I>1</I> + <I>0</I> Do not employ compensation energy until T<sub>p</sub><sup>Start</sup> + <I>1</I> Employ compensation energy file immediately +</PRE> +<P><B>Examples:</B> +</P> +<PRE>pair_style hybrid/overlay lj/cut/hars/cg 2.469416506 0 0 lj/cut/hars/at 0.2 10.0 12.0 0 0 +pair_style hybrid/overlay lj/cut/hars/cg 1.1224 1 0 lj/cut/hars/at 1.5 1 0 +</PRE> +<P><B>Description:</B> +</P> +<P>In the H-AdResS scheme, the description of the interactions within a system of particles is given in terms +of a global Hamiltonian function H, which has the following form <A HREF = "#Potestio2013_1">(Potestio2013_1)</A>, <A HREF = "#Potestio2013_2">(Potestio2013_2)</A>, <A HREF = "#Heidari2016">(Heidari2016)</A>: +</P> +<CENTER><IMG SRC = "Eqs/HADRESS_System_Hamiltonian.png"> +</CENTER> +<P>The term K is the atomistic kinetic energy, and V<sup>int</sup> consists of all the intramolecular bonded interactions (e.g. bond stretching). +The value of the switching function is determined by the sizes L<sub>AT</sub> +L<sub>HY</sub> of the atomistic and hybrid regions, respectively, and of the specific geometry of the atomistic region. +</P> +<P>In the Hamiltonian, the non-bonded potential energy contribution of each molecule is given by a weighted sum of two terms +V<sub>α</sub><sup>CG</sup> and V<sub>α</sub><sup>AT</sup>, defined as: +</P> +<CENTER><IMG SRC = "Eqs/HADRESS_System_Potentials.png"> +</CENTER> +<P>The <I>lj/cut/hars/at</I> styles compute the standard 12/6 Lennard-Jones potential for the atoms located in atomistic (high resolution) and hybrid region. +The general formula is given by +</P> +<CENTER><IMG SRC = "Eqs/HADRESS_AT_pair_lj.png"> +</CENTER> +<P>rc is the cutoff. +</P> +<P>Style <I>lj/cut/coul/dsf/hars/at</I> computes the standard 12/6 Lennard-Jones and Coulomb interactions for atoms of atomistic (high resolution) and hybrid region. +The Coulombic term is computed via the damped shifted force model introduced by <A HREF = "#Fennell">Fennell et al.</A>, given by: +</P> +<CENTER><IMG SRC = "Eqs/HADRESS_AT_pair_coul_dsf.jpg"> +</CENTER> +<P>where <I>alpha</I> is the damping parameter and erfc() is the complementary +error-function. This potential is essentially a short-range, +spherically-truncated, charge-neutralized, shifted, pairwise <I>1/r</I> +summation. +</P> +<P>The <I>lj/cut/hars/cg</I> styles compute the standard 12/6 Lennard-Jones potential for the atoms located in the low resolution (coarse-grained) and hybrid region. +The general formula is given by +</P> +<CENTER><IMG SRC = "Eqs/HADRESS_CG_pair_lj.png"> +</CENTER> +<P>rc is the cutoff. +As mentioned above, the interactions in the coarse-grained region are computed based on the center of mass of the particles. +</P> +<P>Important Note: For dual resolution simulations, it is required to use hybrid/overlay to include +both resolution pair-styles. +</P> +<P>For all of dual resolution pair styles, the following coefficients must +be defined for each pair of atoms types via the +<A HREF = "pair_coeff.html">pair_coeff</A> command as in the examples below +</P> +<LI>epsilon (energy units) + +<LI>sigma (distance units) + +<LI>cutoff (distance units) + +<P>For examples: +</P> +<PRE> pair_coeff * * lj/cut/hars/cg 1.0 2.2 + pair_coeff 1 1 lj/cut/coul/dsf/hars/at 0.15535 3.166 + pair_coeff * 2 lj/cut/coul/dsf/hars/at 0.0000 0.0000 +</PRE> +<P>Note that sigma is defined in the LJ formula as the zero-crossing +distance for the potential, not as the energy minimum at 2^(1/6) +sigma. +</P> +<P>All potentials have to be shifted at the cutoff through the command +</P> +<PRE> pair_modify shift yes +</PRE> +<HR> + +<P><B>Mixing, shift, table, tail correction, restart, rRESPA info</B>: +</P> +<P>All of the <I>lj/cut</I> pair styles support the +<A HREF = "pair_modify.html">pair_modify</A> shift option for the energy of the +Lennard-Jones portion of the pair interaction. +</P> +<P>All of the <I>lj/cut</I> pair styles write their information to <A HREF = "restart.html">binary +restart files</A>, so pair_style and pair_coeff commands do +not need to be specified in an input script that reads a restart file. +</P> +<P>The pair styles do not support the use of the rRESPA hierarchy. +</P> +<P>Each pair styles creates a file named as "Mean_Comp_Energy_XX.txt", where the file name's suffix "XX", is replaced by "AT" and "CG" for atomistic and coarse-grained pairwise interactions respectively. +In these files the averaged compensation energy as function of the resolution (λ) is printed. Each file is created at <I>T<sub>p</sub><sup>Start</sup></I> and is updated every <I>dT<sub>p</sub></I>. +The updating process of the files is finished at time step <I>T<sub>p</sub><sup>End</sup></I>. +For those equilibrated simulations starting at time step larger than <I>T<sub>p</sub><sup>End</sup></I>, the file "Mean_Comp_Energy_XX.txt" is loaded in each pair styles. For more information, +see <A HREF = "fix_lambdah_calc.html">fix_lambdah_calc</A>. +</P> +<HR> + +<P><B>Restrictions:</B> +</P> +<P>In HAdResS, it is required to include both high resolution (atomistic) +and low resolution (coarse-grained) force fields together through +</P> +<PRE> pair_style hybrid/overlay +</PRE> +<P>An example of such setup is given above. +</P> +<P>To employ the H-AdResS scheme, the full/hars atom style as well as <A HREF = "fix_lambdah_calc.html">(fix_lambdah_calc)</A> have to be used: +</P> +<PRE> atom_style full/hars +</PRE> +<PRE> fix ID group-ID lambdah/calc ... +</PRE> +<HR> + +<P><B>Related commands:</B> +</P> +<P><A HREF = "fix_lambdah_calc.html">fix_lambdah_calc</A>, <A HREF = "pair_coeff.html">pair_coeff</A> +</P> +<P><B>Default:</B> none +</P> +<HR> + +<A NAME = "Potestio2013_1"></A> + +<P><B>(Potestio2013_1)</B> R. Potestio, S. Fritsch, P. Espanol, R. Delgado-Buscalioni, K. Kremer, R. Everaers, and D. Donadio, <I>Hamiltonian Adaptive Resolution Simulation for Molecular Liquids</I>, <A HREF = "http://dx.doi.org/10.1103/PhysRevLett.110.108301">Phys. Rev. Lett. [110], +108301 (2013)</A> +</P> +<A NAME = "Potestio2013_2"></A> + +<P><B>(Potestio2013_2)</B> R. Potestio, S. Fritsch, P. Espanol, R. Delgado-Buscalioni, K. Kremer, R. Everaers, and D. Donadio, <I>Monte Carlo Adaptive Resolution Simulation of Multicomponent Molecular Liquids</I>, <A HREF = "http://dx.doi.org/10.1103/PhysRevLett.111.060601">Phys. Rev. Lett. [111], +060601 (2013)</A> +</P> +<A NAME = "Heidari2016"></A> + +<P><B>(Heidari2016)</B> M. Heidari, R. Cortes-Huerto, D. Donadio and R. Potestio, <I>Accurate and general treatment of electrostatic interaction in Hamiltonian adaptive resolution simulations</I>, "EPJST (2016)" +</P> +<A NAME = "Fennell"></A> + +<P><B>(Fennell)</B> C. J. Fennell, J. D. Gezelter, J Chem Phys, 124, +234104 (2006). +</P> +</HTML> diff --git a/doc/pair_lj_hars.txt b/doc/pair_lj_hars.txt new file mode 100644 index 000000000..7813f40aa --- /dev/null +++ b/doc/pair_lj_hars.txt @@ -0,0 +1,181 @@ +"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c + +:link(lws,http://lammps.sandia.gov) +:link(ld,Manual.html) +:link(lc,Section_commands.html#comm) + +:line + +pair_style lj/cut/hars/at command :h3 +pair_style lj/cut/coul/dsf/hars/at command :h3 +pair_style lj/cut/hars/cg command :h3 + +[Syntax:] + +pair_style style args :pre + +style = :l + {lj/cut/hars/at} or + {lj/cut/coul/dsf/hars/at} or + {lj/cut/hars/cg} :pre +args = list of arguments for a particular style :l + {lj/cut/hars/at} args = cutoff All_AT Flag_Load_File + cutoff = global cutoff for Lennard Jones interactions (distance units) + All_AT = Fully atomic simulation flag, = {0} or {1} + {0} Fully atomic simulation is off and HAdResS is on + {1} Fully atomic simulation is on and HAdResS is off + Flag_Load_File = Flag of employing compensation energy file, = {0} or {1} + {0} Do not employ compensation energy until T<sub>p</sub><sup>Start</sup> + {1} Employ compensation energy file immediately :pre + {lj/cut/coul/dsf/hars/at} args = Alpha LJcutoff Coulcutoff All_AT Flag_Load_File + Alpha = Damping coefficient in DSF potential (1.0/distance units) + LJcutoff = global cutoff for Lennard Jones interactions (distance units) + Coulcutoff = global cutoff for DSF coulombic interactions (distance units) + All_AT = Fully atomic simulation flag, = {0} or {1} + {0} Fully atomic simulation is off and HAdResS is on + {1} Fully atomic simulation is on and HAdResS is off + Flag_Load_File = Flag of employing compensation energy file, = {0} or {1} + {0} Do not employ compensation energy until T<sub>p</sub><sup>Start</sup> + {1} Employ compensation energy file immediately :pre + {lj/cut/hars/cg} args = cutoff All_CG Flag_Load_File + cutoff = global cutoff for Lennard Jones interactions (distance units) + All_CG = Fully coarse-grained simulation flag, = {0} or {1} + {0} Fully coarse-grained simulation is off and HAdResS is on + {1} Fully coarse-grained simulation is on and HAdResS is off + Flag_Load_File = Flag of employing compensation energy file, = {0} or {1} + {0} Do not employ compensation energy until T<sub>p</sub><sup>Start</sup> + {1} Employ compensation energy file immediately :pre + +[Examples:] + +pair_style hybrid/overlay lj/cut/hars/cg 2.469416506 0 0 lj/cut/hars/at 0.2 10.0 12.0 0 0 +pair_style hybrid/overlay lj/cut/hars/cg 1.1224 1 0 lj/cut/hars/at 1.5 1 0 :pre + +[Description:] + +In the H-AdResS scheme, the description of the interactions within a system of particles is given in terms +of a global Hamiltonian function H, which has the following form "(Potestio2013_1)"_#Potestio2013_1, "(Potestio2013_2)"_#Potestio2013_2, "(Heidari2016)"_#Heidari2016: + +:c,image(Eqs/HADRESS_System_Hamiltonian.png) + +The term K is the atomistic kinetic energy, and V<sup>int</sup> consists of all the intramolecular bonded interactions (e.g. bond stretching). +The value of the switching function is determined by the sizes L<sub>AT</sub> +L<sub>HY</sub> of the atomistic and hybrid regions, respectively, and of the specific geometry of the atomistic region. + +In the Hamiltonian, the non-bonded potential energy contribution of each molecule is given by a weighted sum of two terms +V<sub>α</sub><sup>CG</sup> and V<sub>α</sub><sup>AT</sup>, defined as: + +:c,image(Eqs/HADRESS_System_Potentials.png) + +The {lj/cut/hars/at} styles compute the standard 12/6 Lennard-Jones potential for the atoms located in atomistic (high resolution) and hybrid region. +The general formula is given by + +:c,image(Eqs/HADRESS_AT_pair_lj.png) + +rc is the cutoff. + +Style {lj/cut/coul/dsf/hars/at} computes the standard 12/6 Lennard-Jones and Coulomb interactions for atoms of atomistic (high resolution) and hybrid region. +The Coulombic term is computed via the damped shifted force model introduced by "Fennell et al."_#Fennell, given by: + +:c,image(Eqs/HADRESS_AT_pair_coul_dsf.jpg) + +where {alpha} is the damping parameter and erfc() is the complementary +error-function. This potential is essentially a short-range, +spherically-truncated, charge-neutralized, shifted, pairwise {1/r} +summation. + +The {lj/cut/hars/cg} styles compute the standard 12/6 Lennard-Jones potential for the atoms located in the low resolution (coarse-grained) and hybrid region. +The general formula is given by + +:c,image(Eqs/HADRESS_CG_pair_lj.png) + +rc is the cutoff. +As mentioned above, the interactions in the coarse-grained region are computed based on the center of mass of the particles. + +Important Note: For dual resolution simulations, it is required to use hybrid/overlay to include +both resolution pair-styles. + +For all of dual resolution pair styles, the following coefficients must +be defined for each pair of atoms types via the +"pair_coeff"_pair_coeff.html command as in the examples below + +epsilon (energy units) :l +sigma (distance units) :l +cutoff (distance units) :l + +For examples: + + pair_coeff * * lj/cut/hars/cg 1.0 2.2 + pair_coeff 1 1 lj/cut/coul/dsf/hars/at 0.15535 3.166 + pair_coeff * 2 lj/cut/coul/dsf/hars/at 0.0000 0.0000 :pre + +Note that sigma is defined in the LJ formula as the zero-crossing +distance for the potential, not as the energy minimum at 2^(1/6) +sigma. + +All potentials have to be shifted at the cutoff through the command + + pair_modify shift yes :pre + + +:line + + +[Mixing, shift, table, tail correction, restart, rRESPA info]: + +All of the {lj/cut} pair styles support the +"pair_modify"_pair_modify.html shift option for the energy of the +Lennard-Jones portion of the pair interaction. + +All of the {lj/cut} pair styles write their information to "binary +restart files"_restart.html, so pair_style and pair_coeff commands do +not need to be specified in an input script that reads a restart file. + +The pair styles do not support the use of the rRESPA hierarchy. + +Each pair styles creates a file named as "Mean_Comp_Energy_XX.txt", where the file name's suffix "XX", is replaced by "AT" and "CG" for atomistic and coarse-grained pairwise interactions respectively. +In these files the averaged compensation energy as function of the resolution (λ) is printed. Each file is created at {T<sub>p</sub><sup>Start</sup>} and is updated every {dT<sub>p</sub>}. +The updating process of the files is finished at time step {T<sub>p</sub><sup>End</sup>}. +For those equilibrated simulations starting at time step larger than {T<sub>p</sub><sup>End</sup>}, the file "Mean_Comp_Energy_XX.txt" is loaded in each pair styles. For more information, +see "fix_lambdah_calc"_fix_lambdah_calc.html. + +:line + +[Restrictions:] + +In HAdResS, it is required to include both high resolution (atomistic) +and low resolution (coarse-grained) force fields together through + + pair_style hybrid/overlay :pre +An example of such setup is given above. + +To employ the H-AdResS scheme, the full/hars atom style as well as "(fix_lambdah_calc)"_fix_lambdah_calc.html have to be used: + + atom_style full/hars :pre + + fix ID group-ID lambdah/calc ... :pre + +:line + +[Related commands:] + +"fix_lambdah_calc"_fix_lambdah_calc.html, "pair_coeff"_pair_coeff.html + +[Default:] none + +:line + +:link(Potestio2013_1) +[(Potestio2013_1)] R. Potestio, S. Fritsch, P. Espanol, R. Delgado-Buscalioni, K. Kremer, R. Everaers, and D. Donadio, {Hamiltonian Adaptive Resolution Simulation for Molecular Liquids}, "Phys. Rev. Lett. \[110\], +108301 (2013)"_http://dx.doi.org/10.1103/PhysRevLett.110.108301 + +:link(Potestio2013_2) +[(Potestio2013_2)] R. Potestio, S. Fritsch, P. Espanol, R. Delgado-Buscalioni, K. Kremer, R. Everaers, and D. Donadio, {Monte Carlo Adaptive Resolution Simulation of Multicomponent Molecular Liquids}, "Phys. Rev. Lett. \[111\], +060601 (2013)"_http://dx.doi.org/10.1103/PhysRevLett.111.060601 + +:link(Heidari2016) +[(Heidari2016)] M. Heidari, R. Cortes-Huerto, D. Donadio and R. Potestio, {Accurate and general treatment of electrostatic interaction in Hamiltonian adaptive resolution simulations}, "EPJST (2016)" + +:link(Fennell) +[(Fennell)] C. J. Fennell, J. D. Gezelter, J Chem Phys, 124, +234104 (2006). diff --git a/src/USER-HADRESS/Install.sh b/src/USER-HADRESS/Install.sh new file mode 100644 index 000000000..1b919c4c5 --- /dev/null +++ b/src/USER-HADRESS/Install.sh @@ -0,0 +1,60 @@ +# Install/unInstall package files in LAMMPS +# mode = 0/1/2 for uninstall/install/update + +mode=$1 + +# arg1 = file, arg2 = file it depends on + +action () { + if (test $mode = 0) then + rm -f ../$1 + elif (! cmp -s $1 ../$1) then + if (test -z "$2" || test -e ../$2) then + cp $1 .. + if (test $mode = 2) then + echo " updating src/$1" + fi + fi + elif (test -n "$2") then + if (test ! -e ../$2) then + rm -f ../$1 + fi + fi +} + +# all package files with no dependencies + +for file in *.cpp *.h; do + action $file +done + +# edit 2 Makefile.package files to include/exclude package info + +if (test $1 = 1) then + + if (test -e ../Makefile.package) then + sed -i -e 's/[^ \t]*user-hadress[^ \t]* //' ../Makefile.package + sed -i -e 's|^PKG_SYSINC =[ \t]*|&$(user-hadress_SYSINC) |' ../Makefile.package + sed -i -e 's|^PKG_SYSLIB =[ \t]*|&$(user-hadress_SYSLIB) |' ../Makefile.package + sed -i -e 's|^PKG_SYSPATH =[ \t]*|&$(user-hadress_SYSPATH) |' ../Makefile.package + fi + + if (test -e ../Makefile.package.settings) then + sed -i -e '/^include.*user-hadress.*$/d' ../Makefile.package.settings + # multiline form needed for BSD sed on Macs + sed -i -e '4 i \ +include ..\/..\/lib\/user-hadress\/Makefile.lammps +' ../Makefile.package.settings + fi + +elif (test $1 = 0) then + + if (test -e ../Makefile.package) then + sed -i -e 's/[^ \t]*user-hadress[^ \t]* //' ../Makefile.package + fi + + if (test -e ../Makefile.package.settings) then + sed -i -e '/^include.*user-hadress.*$/d' ../Makefile.package.settings + fi + +fi diff --git a/src/USER-HADRESS/atom.cpp b/src/USER-HADRESS/atom.cpp new file mode 100644 index 000000000..6ef632683 --- /dev/null +++ b/src/USER-HADRESS/atom.cpp @@ -0,0 +1,2206 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#include <mpi.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include "atom.h" +#include "style_atom.h" +#include "atom_vec.h" +#include "atom_vec_ellipsoid.h" +#include "comm.h" +#include "neighbor.h" +#include "force.h" +#include "modify.h" +#include "fix.h" +#include "output.h" +#include "thermo.h" +#include "update.h" +#include "domain.h" +#include "group.h" +#include "molecule.h" +#include "accelerator_cuda.h" +#include "atom_masks.h" +#include "math_const.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; +using namespace MathConst; + +#define DELTA 1 +#define DELTA_MEMSTR 1024 +#define EPSILON 1.0e-6 +#define CUDA_CHUNK 3000 + +enum{LAYOUT_UNIFORM,LAYOUT_NONUNIFORM,LAYOUT_TILED}; // several files + +/* ---------------------------------------------------------------------- */ + +Atom::Atom(LAMMPS *lmp) : Pointers(lmp) +{ + natoms = 0; + nlocal = nghost = nmax = 0; + ntypes = 0; + nbondtypes = nangletypes = ndihedraltypes = nimpropertypes = 0; + nbonds = nangles = ndihedrals = nimpropers = 0; + + firstgroupname = NULL; + sortfreq = 1000; + nextsort = 0; + userbinsize = 0.0; + maxbin = maxnext = 0; + binhead = NULL; + next = permute = NULL; + + // initialize atom arrays + // customize by adding new array + + tag = NULL; + type = mask = NULL; + image = NULL; + x = v = f = NULL; + + molecule = NULL; + molindex = molatom = NULL; + q = NULL; + mu = NULL; + omega = angmom = torque = NULL; + radius = rmass = NULL; + ellipsoid = line = tri = body = NULL; + + lambdaH = NULL; + gradlambdaH = NULL; + replambdaH = NULL; + moltypeH = NULL; + comH = NULL; + nmoltypesH = 0; + + vfrac = s0 = NULL; + x0 = NULL; + + spin = NULL; + eradius = ervel = erforce = NULL; + cs = csforce = vforce = ervelforce = NULL; + etag = NULL; + + rho = drho = e = de = cv = NULL; + vest = NULL; + + // USER-DPD + + uCond = uMech = uChem = uCG = uCGnew = NULL; + duCond = duMech = duChem = NULL; + dpdTheta = NULL; + + // USER-SMD + + contact_radius = NULL; + smd_data_9 = NULL; + smd_stress = NULL; + eff_plastic_strain = NULL; + eff_plastic_strain_rate = NULL; + damage = NULL; + + // molecular info + + bond_per_atom = extra_bond_per_atom = 0; + num_bond = NULL; + bond_type = NULL; + bond_atom = NULL; + + angle_per_atom = extra_angle_per_atom = 0; + num_angle = NULL; + angle_type = NULL; + angle_atom1 = angle_atom2 = angle_atom3 = NULL; + + dihedral_per_atom = extra_dihedral_per_atom = 0; + num_dihedral = NULL; + dihedral_type = NULL; + dihedral_atom1 = dihedral_atom2 = dihedral_atom3 = dihedral_atom4 = NULL; + + improper_per_atom = extra_improper_per_atom = 0; + num_improper = NULL; + improper_type = NULL; + improper_atom1 = improper_atom2 = improper_atom3 = improper_atom4 = NULL; + + maxspecial = 1; + nspecial = NULL; + special = NULL; + + // user-defined molecules + + nmolecule = 0; + molecules = NULL; + + // custom atom arrays + + nivector = ndvector = 0; + ivector = NULL; + dvector = NULL; + iname = dname = NULL; + + // initialize atom style and array existence flags + // customize by adding new flag + + sphere_flag = peri_flag = electron_flag = 0; + wavepacket_flag = sph_flag = 0; + + molecule_flag = 0; + q_flag = mu_flag = 0; + omega_flag = torque_flag = angmom_flag = 0; + radius_flag = rmass_flag = 0; + ellipsoid_flag = line_flag = tri_flag = body_flag = 0; + + vfrac_flag = 0; + spin_flag = eradius_flag = ervel_flag = erforce_flag = ervelforce_flag = 0; + cs_flag = csforce_flag = vforce_flag = etag_flag = 0; + + rho_flag = e_flag = cv_flag = vest_flag = 0; + dpd_flag = 0; + + // USER-SMD + + smd_flag = 0; + contact_radius_flag = 0; + smd_data_9_flag = 0; + smd_stress_flag = 0; + x0_flag = 0; + eff_plastic_strain_flag = 0; + eff_plastic_strain_rate_flag = 0; + damage_flag = 0; + + // Peridynamic scale factor + + pdscale = 1.0; + + // ntype-length arrays + + mass = NULL; + mass_setflag = NULL; + + // callback lists & extra restart info + + nextra_grow = nextra_restart = nextra_border = 0; + extra_grow = extra_restart = extra_border = NULL; + nextra_grow_max = nextra_restart_max = nextra_border_max = 0; + nextra_store = 0; + extra = NULL; + + // default atom ID and mapping values + + tag_enable = 1; + map_style = map_user = 0; + map_tag_max = -1; + map_maxarray = map_nhash = -1; + + max_same = 0; + sametag = NULL; + map_array = NULL; + map_bucket = NULL; + map_hash = NULL; + + atom_style = NULL; + avec = NULL; + + datamask = ALL_MASK; + datamask_ext = ALL_MASK; +} + +/* ---------------------------------------------------------------------- */ + +Atom::~Atom() +{ + delete [] atom_style; + delete avec; + + delete [] firstgroupname; + memory->destroy(binhead); + memory->destroy(next); + memory->destroy(permute); + + // delete atom arrays + // customize by adding new array + + memory->destroy(tag); + memory->destroy(type); + memory->destroy(mask); + memory->destroy(image); + memory->destroy(x); + memory->destroy(v); + memory->destroy(f); + + memory->destroy(molecule); + memory->destroy(molindex); + memory->destroy(molatom); + + memory->destroy(lambdaH); + memory->destroy(replambdaH); + memory->destroy(moltypeH); + memory->destroy(gradlambdaH); + memory->destroy(comH); + + memory->destroy(q); + memory->destroy(mu); + memory->destroy(omega); + memory->destroy(angmom); + memory->destroy(torque); + memory->destroy(radius); + memory->destroy(rmass); + memory->destroy(ellipsoid); + memory->destroy(line); + memory->destroy(tri); + memory->destroy(body); + + memory->destroy(vfrac); + memory->destroy(s0); + memory->destroy(x0); + + memory->destroy(spin); + memory->destroy(eradius); + memory->destroy(ervel); + memory->destroy(erforce); + memory->destroy(ervelforce); + memory->destroy(cs); + memory->destroy(csforce); + memory->destroy(vforce); + memory->destroy(etag); + + memory->destroy(rho); + memory->destroy(drho); + memory->destroy(e); + memory->destroy(de); + memory->destroy(cv); + memory->destroy(vest); + + memory->destroy(contact_radius); + memory->destroy(smd_data_9); + memory->destroy(smd_stress); + memory->destroy(eff_plastic_strain); + memory->destroy(eff_plastic_strain_rate); + memory->destroy(damage); + + memory->destroy(dpdTheta); + memory->destroy(uCond); + memory->destroy(uMech); + memory->destroy(uChem); + memory->destroy(uCG); + memory->destroy(uCGnew); + memory->destroy(duCond); + memory->destroy(duMech); + memory->destroy(duChem); + + memory->destroy(nspecial); + memory->destroy(special); + + memory->destroy(num_bond); + memory->destroy(bond_type); + memory->destroy(bond_atom); + + memory->destroy(num_angle); + memory->destroy(angle_type); + memory->destroy(angle_atom1); + memory->destroy(angle_atom2); + memory->destroy(angle_atom3); + + memory->destroy(num_dihedral); + memory->destroy(dihedral_type); + memory->destroy(dihedral_atom1); + memory->destroy(dihedral_atom2); + memory->destroy(dihedral_atom3); + memory->destroy(dihedral_atom4); + + memory->destroy(num_improper); + memory->destroy(improper_type); + memory->destroy(improper_atom1); + memory->destroy(improper_atom2); + memory->destroy(improper_atom3); + memory->destroy(improper_atom4); + + // delete custom atom arrays + + for (int i = 0; i < nivector; i++) { + delete [] iname[i]; + memory->destroy(ivector[i]); + } + for (int i = 0; i < ndvector; i++) { + delete [] dname[i]; + memory->destroy(dvector[i]); + } + + memory->sfree(iname); + memory->sfree(dname); + memory->sfree(ivector); + memory->sfree(dvector); + + // delete user-defined molecules + + for (int i = 0; i < nmolecule; i++) delete molecules[i]; + memory->sfree(molecules); + + // delete per-type arrays + + delete [] mass; + delete [] mass_setflag; + + // delete extra arrays + + memory->destroy(extra_grow); + memory->destroy(extra_restart); + memory->destroy(extra_border); + memory->destroy(extra); + + // delete mapping data structures + + map_delete(); +} + +/* ---------------------------------------------------------------------- + copy modify settings from old Atom class to current Atom class +------------------------------------------------------------------------- */ + +void Atom::settings(Atom *old) +{ + tag_enable = old->tag_enable; + map_user = old->map_user; + map_style = old->map_style; + sortfreq = old->sortfreq; + userbinsize = old->userbinsize; + if (old->firstgroupname) { + int n = strlen(old->firstgroupname) + 1; + firstgroupname = new char[n]; + strcpy(firstgroupname,old->firstgroupname); + } +} + +/* ---------------------------------------------------------------------- + create an AtomVec style + called from lammps.cpp, input script, restart file, replicate +------------------------------------------------------------------------- */ + +void Atom::create_avec(const char *style, int narg, char **arg, int trysuffix) +{ + delete [] atom_style; + if (avec) delete avec; + + // unset atom style and array existence flags + // may have been set by old avec + // customize by adding new flag + + sphere_flag = peri_flag = electron_flag = 0; + wavepacket_flag = sph_flag = 0; + + molecule_flag = 0; + q_flag = mu_flag = 0; + replambdaH_flag = 0; + moltypeH_flag = 0; + + omega_flag = torque_flag = angmom_flag = 0; + radius_flag = rmass_flag = 0; + ellipsoid_flag = line_flag = tri_flag = body_flag = 0; + + vfrac_flag = 0; + spin_flag = eradius_flag = ervel_flag = erforce_flag = ervelforce_flag = 0; + cs_flag = csforce_flag = vforce_flag = etag_flag = 0; + + rho_flag = e_flag = cv_flag = vest_flag = 0; + + // create instance of AtomVec + // use grow() to initialize atom-based arrays to length 1 + // so that x[0][0] can always be referenced even if proc has no atoms + + int sflag; + avec = new_avec(style,trysuffix,sflag); + avec->store_args(narg,arg); + avec->process_args(narg,arg); + avec->grow(1); + + if (sflag) { + char estyle[256]; + if (sflag == 1) sprintf(estyle,"%s/%s",style,lmp->suffix); + else sprintf(estyle,"%s/%s",style,lmp->suffix2); + int n = strlen(estyle) + 1; + atom_style = new char[n]; + strcpy(atom_style,estyle); + } else { + int n = strlen(style) + 1; + atom_style = new char[n]; + strcpy(atom_style,style); + } + + // if molecular system: + // atom IDs must be defined + // force atom map to be created + // map style may be reset by map_init() and its call to map_style_set() + + molecular = avec->molecular; + if (molecular && tag_enable == 0) + error->all(FLERR,"Atom IDs must be used for molecular systems"); + if (molecular) map_style = 1; +} + +/* ---------------------------------------------------------------------- + generate an AtomVec class, first with suffix appended +------------------------------------------------------------------------- */ + +AtomVec *Atom::new_avec(const char *style, int trysuffix, int &sflag) +{ + if (trysuffix && lmp->suffix_enable) { + if (lmp->suffix) { + sflag = 1; + char estyle[256]; + sprintf(estyle,"%s/%s",style,lmp->suffix); + + if (0) return NULL; + +#define ATOM_CLASS +#define AtomStyle(key,Class) \ + else if (strcmp(estyle,#key) == 0) return new Class(lmp); +#include "style_atom.h" +#undef AtomStyle +#undef ATOM_CLASS + } + + if (lmp->suffix2) { + sflag = 2; + char estyle[256]; + sprintf(estyle,"%s/%s",style,lmp->suffix2); + + if (0) return NULL; + +#define ATOM_CLASS +#define AtomStyle(key,Class) \ + else if (strcmp(estyle,#key) == 0) return new Class(lmp); +#include "style_atom.h" +#undef AtomStyle +#undef ATOM_CLASS + } + } + + sflag = 0; + if (0) return NULL; + +#define ATOM_CLASS +#define AtomStyle(key,Class) \ + else if (strcmp(style,#key) == 0) return new Class(lmp); +#include "style_atom.h" +#undef ATOM_CLASS + + else error->all(FLERR,"Unknown atom style"); + return NULL; +} + +/* ---------------------------------------------------------------------- */ + +void Atom::init() +{ + // delete extra array since it doesn't persist past first run + + if (nextra_store) { + memory->destroy(extra); + extra = NULL; + nextra_store = 0; + } + + // check arrays that are atom type in length + + check_mass(); + + // setup of firstgroup + + if (firstgroupname) { + firstgroup = group->find(firstgroupname); + if (firstgroup < 0) + error->all(FLERR,"Could not find atom_modify first group ID"); + } else firstgroup = -1; + + // init AtomVec + + avec->init(); +} + +/* ---------------------------------------------------------------------- */ + +void Atom::setup() +{ + // setup bins for sorting + // cannot do this in init() because uses neighbor cutoff + + if (sortfreq > 0) setup_sort_bins(); +} + +/* ---------------------------------------------------------------------- + return ptr to AtomVec class if matches style or to matching hybrid sub-class + return NULL if no match +------------------------------------------------------------------------- */ + +AtomVec *Atom::style_match(const char *style) +{ + if (strcmp(atom_style,style) == 0) return avec; + else if (strcmp(atom_style,"hybrid") == 0) { + AtomVecHybrid *avec_hybrid = (AtomVecHybrid *) avec; + for (int i = 0; i < avec_hybrid->nstyles; i++) + if (strcmp(avec_hybrid->keywords[i],style) == 0) + return avec_hybrid->styles[i]; + } + return NULL; +} + +/* ---------------------------------------------------------------------- + modify parameters of the atom style + some options can only be invoked before simulation box is defined + first and sort options cannot be used together +------------------------------------------------------------------------- */ + +void Atom::modify_params(int narg, char **arg) +{ + if (narg == 0) error->all(FLERR,"Illegal atom_modify command"); + + int iarg = 0; + while (iarg < narg) { + if (strcmp(arg[iarg],"id") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal atom_modify command"); + if (domain->box_exist) + error->all(FLERR, + "Atom_modify id command after simulation box is defined"); + if (strcmp(arg[iarg+1],"yes") == 0) tag_enable = 1; + else if (strcmp(arg[iarg+1],"no") == 0) tag_enable = 0; + else error->all(FLERR,"Illegal atom_modify command"); + iarg += 2; + } else if (strcmp(arg[iarg],"map") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal atom_modify command"); + if (domain->box_exist) + error->all(FLERR, + "Atom_modify map command after simulation box is defined"); + if (strcmp(arg[iarg+1],"array") == 0) map_user = 1; + else if (strcmp(arg[iarg+1],"hash") == 0) map_user = 2; + else error->all(FLERR,"Illegal atom_modify command"); + map_style = map_user; + iarg += 2; + } else if (strcmp(arg[iarg],"first") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal atom_modify command"); + if (strcmp(arg[iarg+1],"all") == 0) { + delete [] firstgroupname; + firstgroupname = NULL; + } else { + int n = strlen(arg[iarg+1]) + 1; + firstgroupname = new char[n]; + strcpy(firstgroupname,arg[iarg+1]); + sortfreq = 0; + } + iarg += 2; + } else if (strcmp(arg[iarg],"sort") == 0) { + if (iarg+3 > narg) error->all(FLERR,"Illegal atom_modify command"); + sortfreq = force->inumeric(FLERR,arg[iarg+1]); + userbinsize = force->numeric(FLERR,arg[iarg+2]); + if (sortfreq < 0 || userbinsize < 0.0) + error->all(FLERR,"Illegal atom_modify command"); + if (sortfreq >= 0 && firstgroupname) + error->all(FLERR,"Atom_modify sort and first options " + "cannot be used together"); + iarg += 3; + } else error->all(FLERR,"Illegal atom_modify command"); + } +} + +/* ---------------------------------------------------------------------- + check that atom IDs are valid + error if any atom ID < 0 or atom ID = MAXTAGINT + if any atom ID > 0, error if any atom ID == 0 + if any atom ID > 0, error if tag_enable = 0 + if all atom IDs = 0, tag_enable must be 0 + if max atom IDs < natoms, must be duplicates + OK if max atom IDs > natoms + NOTE: not fully checking that atom IDs are unique +------------------------------------------------------------------------- */ + +void Atom::tag_check() +{ + tagint min = MAXTAGINT; + tagint max = 0; + + for (int i = 0; i < nlocal; i++) { + min = MIN(min,tag[i]); + max = MAX(max,tag[i]); + } + + tagint minall,maxall; + MPI_Allreduce(&min,&minall,1,MPI_LMP_TAGINT,MPI_MIN,world); + MPI_Allreduce(&max,&maxall,1,MPI_LMP_TAGINT,MPI_MAX,world); + + if (minall < 0) error->all(FLERR,"One or more Atom IDs is negative"); + if (maxall >= MAXTAGINT) error->all(FLERR,"One or more atom IDs is too big"); + if (maxall > 0 && minall == 0) + error->all(FLERR,"One or more atom IDs is zero"); + if (maxall > 0 && tag_enable == 0) + error->all(FLERR,"Non-zero atom IDs with atom_modify id = no"); + if (maxall == 0 && natoms && tag_enable) + error->all(FLERR,"All atom IDs = 0 but atom_modify id = yes"); + if (tag_enable && maxall < natoms) + error->all(FLERR,"Duplicate atom IDs exist"); +} + +/* ---------------------------------------------------------------------- + add unique tags to any atoms with tag = 0 + new tags are grouped by proc and start after max current tag + called after creating new atoms + error if new tags will exceed MAXTAGINT +------------------------------------------------------------------------- */ + +void Atom::tag_extend() +{ + // maxtag_all = max tag for all atoms + + tagint maxtag = 0; + for (int i = 0; i < nlocal; i++) maxtag = MAX(maxtag,tag[i]); + tagint maxtag_all; + MPI_Allreduce(&maxtag,&maxtag_all,1,MPI_LMP_TAGINT,MPI_MAX,world); + + // DEBUG: useful for generating 64-bit IDs even for small systems + // use only when LAMMPS is compiled with BIGBIG + + //maxtag_all += 1000000000000; + + // notag = # of atoms I own with no tag (tag = 0) + // notag_sum = # of total atoms on procs <= me with no tag + + bigint notag = 0; + for (int i = 0; i < nlocal; i++) if (tag[i] == 0) notag++; + + bigint notag_total; + MPI_Allreduce(¬ag,¬ag_total,1,MPI_LMP_BIGINT,MPI_SUM,world); + if (notag_total >= MAXTAGINT) + error->all(FLERR,"New atom IDs exceed maximum allowed ID"); + + bigint notag_sum; + MPI_Scan(¬ag,¬ag_sum,1,MPI_LMP_BIGINT,MPI_SUM,world); + + // itag = 1st new tag that my untagged atoms should use + + tagint itag = maxtag_all + notag_sum - notag + 1; + for (int i = 0; i < nlocal; i++) if (tag[i] == 0) tag[i] = itag++; +} + +/* ---------------------------------------------------------------------- + check that atom IDs span range from 1 to Natoms inclusive + return 0 if mintag != 1 or maxtag != Natoms + return 1 if OK + doesn't actually check if all tag values are used +------------------------------------------------------------------------- */ + +int Atom::tag_consecutive() +{ + tagint idmin = MAXTAGINT; + tagint idmax = 0; + + for (int i = 0; i < nlocal; i++) { + idmin = MIN(idmin,tag[i]); + idmax = MAX(idmax,tag[i]); + } + tagint idminall,idmaxall; + MPI_Allreduce(&idmin,&idminall,1,MPI_LMP_TAGINT,MPI_MIN,world); + MPI_Allreduce(&idmax,&idmaxall,1,MPI_LMP_TAGINT,MPI_MAX,world); + + if (idminall != 1 || idmaxall != natoms) return 0; + return 1; +} + +/* ---------------------------------------------------------------------- + count and return words in a single line + make copy of line before using strtok so as not to change line + trim anything from '#' onward +------------------------------------------------------------------------- */ + +int Atom::count_words(const char *line) +{ + int n = strlen(line) + 1; + char *copy; + memory->create(copy,n,"atom:copy"); + strcpy(copy,line); + + char *ptr; + if ((ptr = strchr(copy,'#'))) *ptr = '\0'; + + if (strtok(copy," \t\n\r\f") == NULL) { + memory->destroy(copy); + return 0; + } + n = 1; + while (strtok(NULL," \t\n\r\f")) n++; + + memory->destroy(copy); + return n; +} + +/* ---------------------------------------------------------------------- + count and return words in a single line using provided copy buf + make copy of line before using strtok so as not to change line + trim anything from '#' onward +------------------------------------------------------------------------- */ + +int Atom::count_words(const char *line, char *copy) +{ + strcpy(copy,line); + + char *ptr; + if ((ptr = strchr(copy,'#'))) *ptr = '\0'; + + if (strtok(copy," \t\n\r\f") == NULL) { + memory->destroy(copy); + return 0; + } + int n = 1; + while (strtok(NULL," \t\n\r\f")) n++; + + return n; +} + +/* ---------------------------------------------------------------------- + deallocate molecular topology arrays + done before realloc with (possibly) new 2nd dimension set to + correctly initialized per-atom values, e.g. bond_per_atom + needs to be called whenever 2nd dimensions are changed + and these arrays are already pre-allocated, + e.g. due to grow(1) in create_avec() +------------------------------------------------------------------------- */ + +void Atom::deallocate_topology() +{ + memory->destroy(atom->bond_type); + memory->destroy(atom->bond_atom); + atom->bond_type = NULL; + atom->bond_atom = NULL; + + memory->destroy(atom->angle_type); + memory->destroy(atom->angle_atom1); + memory->destroy(atom->angle_atom2); + memory->destroy(atom->angle_atom3); + atom->angle_type = NULL; + atom->angle_atom1 = atom->angle_atom2 = atom->angle_atom3 = NULL; + + memory->destroy(atom->dihedral_type); + memory->destroy(atom->dihedral_atom1); + memory->destroy(atom->dihedral_atom2); + memory->destroy(atom->dihedral_atom3); + memory->destroy(atom->dihedral_atom4); + atom->dihedral_type = NULL; + atom->dihedral_atom1 = atom->dihedral_atom2 = + atom->dihedral_atom3 = atom->dihedral_atom4 = NULL; + + memory->destroy(atom->improper_type); + memory->destroy(atom->improper_atom1); + memory->destroy(atom->improper_atom2); + memory->destroy(atom->improper_atom3); + memory->destroy(atom->improper_atom4); + atom->improper_type = NULL; + atom->improper_atom1 = atom->improper_atom2 = + atom->improper_atom3 = atom->improper_atom4 = NULL; +} + +/* ---------------------------------------------------------------------- + unpack N lines from Atom section of data file + call style-specific routine to parse line +------------------------------------------------------------------------- */ + +void Atom::data_atoms(int n, char *buf, tagint id_offset, int type_offset, + int shiftflag, double *shift) +{ + int m,xptr,iptr; + imageint imagedata; + double xdata[3],lamda[3]; + double *coord; + char *next; + + next = strchr(buf,'\n'); + *next = '\0'; + int nwords = count_words(buf); + *next = '\n'; + + if (nwords != avec->size_data_atom && nwords != avec->size_data_atom + 3) + error->all(FLERR,"Incorrect atom format in data file"); + + char **values = new char*[nwords]; + + // set bounds for my proc + // if periodic and I am lo/hi proc, adjust bounds by EPSILON + // insures all data atoms will be owned even with round-off + + int triclinic = domain->triclinic; + + double epsilon[3]; + if (triclinic) epsilon[0] = epsilon[1] = epsilon[2] = EPSILON; + else { + epsilon[0] = domain->prd[0] * EPSILON; + epsilon[1] = domain->prd[1] * EPSILON; + epsilon[2] = domain->prd[2] * EPSILON; + } + + double sublo[3],subhi[3]; + if (triclinic == 0) { + sublo[0] = domain->sublo[0]; subhi[0] = domain->subhi[0]; + sublo[1] = domain->sublo[1]; subhi[1] = domain->subhi[1]; + sublo[2] = domain->sublo[2]; subhi[2] = domain->subhi[2]; + } else { + sublo[0] = domain->sublo_lamda[0]; subhi[0] = domain->subhi_lamda[0]; + sublo[1] = domain->sublo_lamda[1]; subhi[1] = domain->subhi_lamda[1]; + sublo[2] = domain->sublo_lamda[2]; subhi[2] = domain->subhi_lamda[2]; + } + + if (comm->layout != LAYOUT_TILED) { + if (domain->xperiodic) { + if (comm->myloc[0] == 0) sublo[0] -= epsilon[0]; + if (comm->myloc[0] == comm->procgrid[0]-1) subhi[0] += epsilon[0]; + } + if (domain->yperiodic) { + if (comm->myloc[1] == 0) sublo[1] -= epsilon[1]; + if (comm->myloc[1] == comm->procgrid[1]-1) subhi[1] += epsilon[1]; + } + if (domain->zperiodic) { + if (comm->myloc[2] == 0) sublo[2] -= epsilon[2]; + if (comm->myloc[2] == comm->procgrid[2]-1) subhi[2] += epsilon[2]; + } + + } else { + if (domain->xperiodic) { + if (comm->mysplit[0][0] == 0.0) sublo[0] -= epsilon[0]; + if (comm->mysplit[0][1] == 1.0) subhi[0] += epsilon[0]; + } + if (domain->yperiodic) { + if (comm->mysplit[1][0] == 0.0) sublo[1] -= epsilon[1]; + if (comm->mysplit[1][1] == 1.0) subhi[1] += epsilon[1]; + } + if (domain->zperiodic) { + if (comm->mysplit[2][0] == 0.0) sublo[2] -= epsilon[2]; + if (comm->mysplit[2][1] == 1.0) subhi[2] += epsilon[2]; + } + } + + // xptr = which word in line starts xyz coords + // iptr = which word in line starts ix,iy,iz image flags + + xptr = avec->xcol_data - 1; + int imageflag = 0; + if (nwords > avec->size_data_atom) imageflag = 1; + if (imageflag) iptr = nwords - 3; + + // loop over lines of atom data + // tokenize the line into values + // extract xyz coords and image flags + // remap atom into simulation box + // if atom is in my sub-domain, unpack its values + + for (int i = 0; i < n; i++) { + next = strchr(buf,'\n'); + + values[0] = strtok(buf," \t\n\r\f"); + if (values[0] == NULL) + error->all(FLERR,"Incorrect atom format in data file"); + for (m = 1; m < nwords; m++) { + values[m] = strtok(NULL," \t\n\r\f"); + if (values[m] == NULL) + error->all(FLERR,"Incorrect atom format in data file"); + } + + if (imageflag) + imagedata = ((imageint) (atoi(values[iptr]) + IMGMAX) & IMGMASK) | + (((imageint) (atoi(values[iptr+1]) + IMGMAX) & IMGMASK) << IMGBITS) | + (((imageint) (atoi(values[iptr+2]) + IMGMAX) & IMGMASK) << IMG2BITS); + else imagedata = ((imageint) IMGMAX << IMG2BITS) | + ((imageint) IMGMAX << IMGBITS) | IMGMAX; + + xdata[0] = atof(values[xptr]); + xdata[1] = atof(values[xptr+1]); + xdata[2] = atof(values[xptr+2]); + if (shiftflag) { + xdata[0] += shift[0]; + xdata[1] += shift[1]; + xdata[2] += shift[2]; + } + + domain->remap(xdata,imagedata); + if (triclinic) { + domain->x2lamda(xdata,lamda); + coord = lamda; + } else coord = xdata; + + if (coord[0] >= sublo[0] && coord[0] < subhi[0] && + coord[1] >= sublo[1] && coord[1] < subhi[1] && + coord[2] >= sublo[2] && coord[2] < subhi[2]) { + avec->data_atom(xdata,imagedata,values); + if (id_offset) tag[nlocal-1] += id_offset; + if (type_offset) { + type[nlocal-1] += type_offset; + if (type[nlocal-1] > ntypes) + error->one(FLERR,"Invalid atom type in Atoms section of data file"); + } + } + + buf = next + 1; + } + + delete [] values; +} + +/* ---------------------------------------------------------------------- + unpack N lines from Velocity section of data file + check that atom IDs are > 0 and <= map_tag_max + call style-specific routine to parse line +------------------------------------------------------------------------- */ + +void Atom::data_vels(int n, char *buf, tagint id_offset) +{ + int j,m; + tagint tagdata; + char *next; + + next = strchr(buf,'\n'); + *next = '\0'; + int nwords = count_words(buf); + *next = '\n'; + + if (nwords != avec->size_data_vel) + error->all(FLERR,"Incorrect velocity format in data file"); + + char **values = new char*[nwords]; + + // loop over lines of atom velocities + // tokenize the line into values + // if I own atom tag, unpack its values + + for (int i = 0; i < n; i++) { + next = strchr(buf,'\n'); + + values[0] = strtok(buf," \t\n\r\f"); + for (j = 1; j < nwords; j++) + values[j] = strtok(NULL," \t\n\r\f"); + + tagdata = ATOTAGINT(values[0]) + id_offset; + if (tagdata <= 0 || tagdata > map_tag_max) + error->one(FLERR,"Invalid atom ID in Velocities section of data file"); + if ((m = map(tagdata)) >= 0) avec->data_vel(m,&values[1]); + + buf = next + 1; + } + + delete [] values; +} + +/* ---------------------------------------------------------------------- + process N bonds read into buf from data files + if count is non-NULL, just count bonds per atom + else store them with atoms + check that atom IDs are > 0 and <= map_tag_max +------------------------------------------------------------------------- */ + +void Atom::data_bonds(int n, char *buf, int *count, tagint id_offset, + int type_offset) +{ + int m,tmp,itype; + tagint atom1,atom2; + char *next; + int newton_bond = force->newton_bond; + + for (int i = 0; i < n; i++) { + next = strchr(buf,'\n'); + *next = '\0'; + sscanf(buf,"%d %d " TAGINT_FORMAT " " TAGINT_FORMAT, + &tmp,&itype,&atom1,&atom2); + if (id_offset) { + atom1 += id_offset; + atom2 += id_offset; + } + itype += type_offset; + + if (atom1 <= 0 || atom1 > map_tag_max || + atom2 <= 0 || atom2 > map_tag_max) + error->one(FLERR,"Invalid atom ID in Bonds section of data file"); + if (itype <= 0 || itype > nbondtypes) + error->one(FLERR,"Invalid bond type in Bonds section of data file"); + if ((m = map(atom1)) >= 0) { + if (count) count[m]++; + else { + bond_type[m][num_bond[m]] = itype; + bond_atom[m][num_bond[m]] = atom2; + num_bond[m]++; + } + } + if (newton_bond == 0) { + if ((m = map(atom2)) >= 0) { + if (count) count[m]++; + else { + bond_type[m][num_bond[m]] = itype; + bond_atom[m][num_bond[m]] = atom1; + num_bond[m]++; + } + } + } + buf = next + 1; + } +} + +/* ---------------------------------------------------------------------- + process N angles read into buf from data files + if count is non-NULL, just count angles per atom + else store them with atoms + check that atom IDs are > 0 and <= map_tag_max +------------------------------------------------------------------------- */ + +void Atom::data_angles(int n, char *buf, int *count, tagint id_offset, + int type_offset) +{ + int m,tmp,itype; + tagint atom1,atom2,atom3; + char *next; + int newton_bond = force->newton_bond; + + for (int i = 0; i < n; i++) { + next = strchr(buf,'\n'); + *next = '\0'; + sscanf(buf,"%d %d " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, + &tmp,&itype,&atom1,&atom2,&atom3); + if (id_offset) { + atom1 += id_offset; + atom2 += id_offset; + atom3 += id_offset; + } + itype += type_offset; + + if (atom1 <= 0 || atom1 > map_tag_max || + atom2 <= 0 || atom2 > map_tag_max || + atom3 <= 0 || atom3 > map_tag_max) + error->one(FLERR,"Invalid atom ID in Angles section of data file"); + if (itype <= 0 || itype > nangletypes) + error->one(FLERR,"Invalid angle type in Angles section of data file"); + if ((m = map(atom2)) >= 0) { + if (count) count[m]++; + else { + angle_type[m][num_angle[m]] = itype; + angle_atom1[m][num_angle[m]] = atom1; + angle_atom2[m][num_angle[m]] = atom2; + angle_atom3[m][num_angle[m]] = atom3; + num_angle[m]++; + } + } + if (newton_bond == 0) { + if ((m = map(atom1)) >= 0) { + if (count) count[m]++; + else { + angle_type[m][num_angle[m]] = itype; + angle_atom1[m][num_angle[m]] = atom1; + angle_atom2[m][num_angle[m]] = atom2; + angle_atom3[m][num_angle[m]] = atom3; + num_angle[m]++; + } + } + if ((m = map(atom3)) >= 0) { + if (count) count[m]++; + else { + angle_type[m][num_angle[m]] = itype; + angle_atom1[m][num_angle[m]] = atom1; + angle_atom2[m][num_angle[m]] = atom2; + angle_atom3[m][num_angle[m]] = atom3; + num_angle[m]++; + } + } + } + buf = next + 1; + } +} + +/* ---------------------------------------------------------------------- + process N dihedrals read into buf from data files + if count is non-NULL, just count diihedrals per atom + else store them with atoms + check that atom IDs are > 0 and <= map_tag_max +------------------------------------------------------------------------- */ + +void Atom::data_dihedrals(int n, char *buf, int *count, tagint id_offset, + int type_offset) +{ + int m,tmp,itype; + tagint atom1,atom2,atom3,atom4; + char *next; + int newton_bond = force->newton_bond; + + for (int i = 0; i < n; i++) { + next = strchr(buf,'\n'); + *next = '\0'; + sscanf(buf,"%d %d " + TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, + &tmp,&itype,&atom1,&atom2,&atom3,&atom4); + if (id_offset) { + atom1 += id_offset; + atom2 += id_offset; + atom3 += id_offset; + atom4 += id_offset; + } + itype += type_offset; + + if (atom1 <= 0 || atom1 > map_tag_max || + atom2 <= 0 || atom2 > map_tag_max || + atom3 <= 0 || atom3 > map_tag_max || + atom4 <= 0 || atom4 > map_tag_max) + error->one(FLERR,"Invalid atom ID in Dihedrals section of data file"); + if (itype <= 0 || itype > ndihedraltypes) + error->one(FLERR, + "Invalid dihedral type in Dihedrals section of data file"); + if ((m = map(atom2)) >= 0) { + if (count) count[m]++; + else { + dihedral_type[m][num_dihedral[m]] = itype; + dihedral_atom1[m][num_dihedral[m]] = atom1; + dihedral_atom2[m][num_dihedral[m]] = atom2; + dihedral_atom3[m][num_dihedral[m]] = atom3; + dihedral_atom4[m][num_dihedral[m]] = atom4; + num_dihedral[m]++; + } + } + if (newton_bond == 0) { + if ((m = map(atom1)) >= 0) { + if (count) count[m]++; + else { + dihedral_type[m][num_dihedral[m]] = itype; + dihedral_atom1[m][num_dihedral[m]] = atom1; + dihedral_atom2[m][num_dihedral[m]] = atom2; + dihedral_atom3[m][num_dihedral[m]] = atom3; + dihedral_atom4[m][num_dihedral[m]] = atom4; + num_dihedral[m]++; + } + } + if ((m = map(atom3)) >= 0) { + if (count) count[m]++; + else { + dihedral_type[m][num_dihedral[m]] = itype; + dihedral_atom1[m][num_dihedral[m]] = atom1; + dihedral_atom2[m][num_dihedral[m]] = atom2; + dihedral_atom3[m][num_dihedral[m]] = atom3; + dihedral_atom4[m][num_dihedral[m]] = atom4; + num_dihedral[m]++; + } + } + if ((m = map(atom4)) >= 0) { + if (count) count[m]++; + else { + dihedral_type[m][num_dihedral[m]] = itype; + dihedral_atom1[m][num_dihedral[m]] = atom1; + dihedral_atom2[m][num_dihedral[m]] = atom2; + dihedral_atom3[m][num_dihedral[m]] = atom3; + dihedral_atom4[m][num_dihedral[m]] = atom4; + num_dihedral[m]++; + } + } + } + buf = next + 1; + } +} + +/* ---------------------------------------------------------------------- + process N impropers read into buf from data files + if count is non-NULL, just count impropers per atom + else store them with atoms + check that atom IDs are > 0 and <= map_tag_max +------------------------------------------------------------------------- */ + +void Atom::data_impropers(int n, char *buf, int *count, tagint id_offset, + int type_offset) +{ + int m,tmp,itype; + tagint atom1,atom2,atom3,atom4; + char *next; + int newton_bond = force->newton_bond; + + for (int i = 0; i < n; i++) { + next = strchr(buf,'\n'); + *next = '\0'; + sscanf(buf,"%d %d " + TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, + &tmp,&itype,&atom1,&atom2,&atom3,&atom4); + if (id_offset) { + atom1 += id_offset; + atom2 += id_offset; + atom3 += id_offset; + atom4 += id_offset; + } + itype += type_offset; + + if (atom1 <= 0 || atom1 > map_tag_max || + atom2 <= 0 || atom2 > map_tag_max || + atom3 <= 0 || atom3 > map_tag_max || + atom4 <= 0 || atom4 > map_tag_max) + error->one(FLERR,"Invalid atom ID in Impropers section of data file"); + if (itype <= 0 || itype > nimpropertypes) + error->one(FLERR, + "Invalid improper type in Impropers section of data file"); + if ((m = map(atom2)) >= 0) { + if (count) count[m]++; + else { + improper_type[m][num_improper[m]] = itype; + improper_atom1[m][num_improper[m]] = atom1; + improper_atom2[m][num_improper[m]] = atom2; + improper_atom3[m][num_improper[m]] = atom3; + improper_atom4[m][num_improper[m]] = atom4; + num_improper[m]++; + } + } + if (newton_bond == 0) { + if ((m = map(atom1)) >= 0) { + if (count) count[m]++; + else { + improper_type[m][num_improper[m]] = itype; + improper_atom1[m][num_improper[m]] = atom1; + improper_atom2[m][num_improper[m]] = atom2; + improper_atom3[m][num_improper[m]] = atom3; + improper_atom4[m][num_improper[m]] = atom4; + num_improper[m]++; + } + } + if ((m = map(atom3)) >= 0) { + if (count) count[m]++; + else { + improper_type[m][num_improper[m]] = itype; + improper_atom1[m][num_improper[m]] = atom1; + improper_atom2[m][num_improper[m]] = atom2; + improper_atom3[m][num_improper[m]] = atom3; + improper_atom4[m][num_improper[m]] = atom4; + num_improper[m]++; + } + } + if ((m = map(atom4)) >= 0) { + if (count) count[m]++; + else { + improper_type[m][num_improper[m]] = itype; + improper_atom1[m][num_improper[m]] = atom1; + improper_atom2[m][num_improper[m]] = atom2; + improper_atom3[m][num_improper[m]] = atom3; + improper_atom4[m][num_improper[m]] = atom4; + num_improper[m]++; + } + } + } + buf = next + 1; + } +} + +/* ---------------------------------------------------------------------- + unpack N lines from atom-style specific bonus section of data file + check that atom IDs are > 0 and <= map_tag_max + call style-specific routine to parse line +------------------------------------------------------------------------- */ + +void Atom::data_bonus(int n, char *buf, AtomVec *avec_bonus, tagint id_offset) +{ + int j,m,tagdata; + char *next; + + next = strchr(buf,'\n'); + *next = '\0'; + int nwords = count_words(buf); + *next = '\n'; + + if (nwords != avec_bonus->size_data_bonus) + error->all(FLERR,"Incorrect bonus data format in data file"); + + char **values = new char*[nwords]; + + // loop over lines of bonus atom data + // tokenize the line into values + // if I own atom tag, unpack its values + + for (int i = 0; i < n; i++) { + next = strchr(buf,'\n'); + + values[0] = strtok(buf," \t\n\r\f"); + for (j = 1; j < nwords; j++) + values[j] = strtok(NULL," \t\n\r\f"); + + tagdata = ATOTAGINT(values[0]) + id_offset; + if (tagdata <= 0 || tagdata > map_tag_max) + error->one(FLERR,"Invalid atom ID in Bonus section of data file"); + + // ok to call child's data_atom_bonus() method thru parent avec_bonus, + // since data_bonus() was called with child ptr, and method is virtual + + if ((m = map(tagdata)) >= 0) avec_bonus->data_atom_bonus(m,&values[1]); + + buf = next + 1; + } + + delete [] values; +} + +/* ---------------------------------------------------------------------- + unpack N bodies from Bodies section of data file + each body spans multiple lines + check that atom IDs are > 0 and <= map_tag_max + call style-specific routine to parse line +------------------------------------------------------------------------- */ + +void Atom::data_bodies(int n, char *buf, AtomVecBody *avec_body, + tagint id_offset) +{ + int j,m,nvalues,tagdata,ninteger,ndouble; + + int maxint = 0; + int maxdouble = 0; + int *ivalues = NULL; + double *dvalues = NULL; + + // loop over lines of body data + // if I own atom tag, tokenize lines into ivalues/dvalues, call data_body() + // else skip values + + for (int i = 0; i < n; i++) { + if (i == 0) tagdata = ATOTAGINT(strtok(buf," \t\n\r\f")) + id_offset; + else tagdata = ATOTAGINT(strtok(NULL," \t\n\r\f")) + id_offset; + + if (tagdata <= 0 || tagdata > map_tag_max) + error->one(FLERR,"Invalid atom ID in Bodies section of data file"); + + ninteger = force->inumeric(FLERR,strtok(NULL," \t\n\r\f")); + ndouble = force->inumeric(FLERR,strtok(NULL," \t\n\r\f")); + + if ((m = map(tagdata)) >= 0) { + if (ninteger > maxint) { + delete [] ivalues; + maxint = ninteger; + ivalues = new int[maxint]; + } + if (ndouble > maxdouble) { + delete [] dvalues; + maxdouble = ndouble; + dvalues = new double[maxdouble]; + } + + for (j = 0; j < ninteger; j++) + ivalues[j] = force->inumeric(FLERR,strtok(NULL," \t\n\r\f")); + for (j = 0; j < ndouble; j++) + dvalues[j] = force->numeric(FLERR,strtok(NULL," \t\n\r\f")); + + avec_body->data_body(m,ninteger,ndouble,ivalues,dvalues); + + } else { + nvalues = ninteger + ndouble; // number of values to skip + for (j = 0; j < nvalues; j++) + strtok(NULL," \t\n\r\f"); + } + } + + delete [] ivalues; + delete [] dvalues; +} + +/* ---------------------------------------------------------------------- + allocate arrays of length ntypes + only done after ntypes is set +------------------------------------------------------------------------- */ + +void Atom::allocate_type_arrays() +{ + if (avec->mass_type) { + mass = new double[ntypes+1]; + mass_setflag = new int[ntypes+1]; + for (int itype = 1; itype <= ntypes; itype++) mass_setflag[itype] = 0; + } +} + +/* ---------------------------------------------------------------------- + set a mass and flag it as set + called from reading of data file + type_offset may be used when reading multiple data files +------------------------------------------------------------------------- */ + +void Atom::set_mass(const char *str, int type_offset) +{ + if (mass == NULL) error->all(FLERR,"Cannot set mass for this atom style"); + + int itype; + double mass_one; + int n = sscanf(str,"%d %lg",&itype,&mass_one); + if (n != 2) error->all(FLERR,"Invalid mass line in data file"); + itype += type_offset; + + if (itype < 1 || itype > ntypes) + error->all(FLERR,"Invalid type for mass set"); + + mass[itype] = mass_one; + mass_setflag[itype] = 1; + + if (mass[itype] <= 0.0) error->all(FLERR,"Invalid mass value"); +} + +/* ---------------------------------------------------------------------- + set a mass and flag it as set + called from EAM pair routine +------------------------------------------------------------------------- */ + +void Atom::set_mass(int itype, double value) +{ + if (mass == NULL) error->all(FLERR,"Cannot set mass for this atom style"); + if (itype < 1 || itype > ntypes) + error->all(FLERR,"Invalid type for mass set"); + + mass[itype] = value; + mass_setflag[itype] = 1; + + if (mass[itype] <= 0.0) error->all(FLERR,"Invalid mass value"); +} + +/* ---------------------------------------------------------------------- + set one or more masses and flag them as set + called from reading of input script +------------------------------------------------------------------------- */ + +void Atom::set_mass(int narg, char **arg) +{ + if (mass == NULL) error->all(FLERR,"Cannot set mass for this atom style"); + + int lo,hi; + force->bounds(arg[0],ntypes,lo,hi); + if (lo < 1 || hi > ntypes) error->all(FLERR,"Invalid type for mass set"); + + for (int itype = lo; itype <= hi; itype++) { + mass[itype] = atof(arg[1]); + mass_setflag[itype] = 1; + + if (mass[itype] <= 0.0) error->all(FLERR,"Invalid mass value"); + } +} + +/* ---------------------------------------------------------------------- + set all masses as read in from restart file +------------------------------------------------------------------------- */ + +void Atom::set_mass(double *values) +{ + for (int itype = 1; itype <= ntypes; itype++) { + mass[itype] = values[itype]; + mass_setflag[itype] = 1; + } +} + +/* ---------------------------------------------------------------------- + check that all masses have been set +------------------------------------------------------------------------- */ + +void Atom::check_mass() +{ + if (mass == NULL) return; + for (int itype = 1; itype <= ntypes; itype++) + if (mass_setflag[itype] == 0) error->all(FLERR,"All masses are not set"); +} + +/* ---------------------------------------------------------------------- + check that radii of all particles of itype are the same + return 1 if true, else return 0 + also return the radius value for that type +------------------------------------------------------------------------- */ + +int Atom::radius_consistency(int itype, double &rad) +{ + double value = -1.0; + int flag = 0; + for (int i = 0; i < nlocal; i++) { + if (type[i] != itype) continue; + if (value < 0.0) value = radius[i]; + else if (value != radius[i]) flag = 1; + } + + int flagall; + MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); + if (flagall) return 0; + + MPI_Allreduce(&value,&rad,1,MPI_DOUBLE,MPI_MAX,world); + return 1; +} + +/* ---------------------------------------------------------------------- + check that shape of all particles of itype are the same + return 1 if true, else return 0 + also return the 3 shape params for itype +------------------------------------------------------------------------- */ + +int Atom::shape_consistency(int itype, + double &shapex, double &shapey, double &shapez) +{ + double zero[3] = {0.0, 0.0, 0.0}; + double one[3] = {-1.0, -1.0, -1.0}; + double *shape; + + AtomVecEllipsoid *avec_ellipsoid = + (AtomVecEllipsoid *) style_match("ellipsoid"); + AtomVecEllipsoid::Bonus *bonus = avec_ellipsoid->bonus; + + int flag = 0; + for (int i = 0; i < nlocal; i++) { + if (type[i] != itype) continue; + if (ellipsoid[i] < 0) shape = zero; + else shape = bonus[ellipsoid[i]].shape; + + if (one[0] < 0.0) { + one[0] = shape[0]; + one[1] = shape[1]; + one[2] = shape[2]; + } else if (one[0] != shape[0] || one[1] != shape[1] || one[2] != shape[2]) + flag = 1; + } + + int flagall; + MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); + if (flagall) return 0; + + double oneall[3]; + MPI_Allreduce(one,oneall,3,MPI_DOUBLE,MPI_MAX,world); + shapex = oneall[0]; + shapey = oneall[1]; + shapez = oneall[2]; + return 1; +} + +/* ---------------------------------------------------------------------- + add a new molecule template = set of molecules +------------------------------------------------------------------------- */ + +void Atom::add_molecule(int narg, char **arg) +{ + if (narg < 1) error->all(FLERR,"Illegal molecule command"); + + if (find_molecule(arg[0]) >= 0) + error->all(FLERR,"Reuse of molecule template ID"); + + // 1st molecule in set stores nset = # of mols, others store nset = 0 + // ifile = count of molecules in set + // index = argument index where next molecule starts, updated by constructor + + int ifile = 1; + int index = 1; + while (1) { + molecules = (Molecule **) + memory->srealloc(molecules,(nmolecule+1)*sizeof(Molecule *), + "atom::molecules"); + molecules[nmolecule] = new Molecule(lmp,narg,arg,index); + molecules[nmolecule]->nset = 0; + molecules[nmolecule-ifile+1]->nset++; + nmolecule++; + if (molecules[nmolecule-1]->last) break; + ifile++; + } +} + +/* ---------------------------------------------------------------------- + find first molecule in set with template ID + return -1 if does not exist +------------------------------------------------------------------------- */ + +int Atom::find_molecule(char *id) +{ + int imol; + for (imol = 0; imol < nmolecule; imol++) + if (strcmp(id,molecules[imol]->id) == 0) return imol; + return -1; +} + +/* ---------------------------------------------------------------------- + add info to current atom ilocal from molecule template onemol and its iatom + offset = atom ID preceeding IDs of atoms in this molecule + called by fixes and commands that add molecules +------------------------------------------------------------------------- */ + +void Atom::add_molecule_atom(Molecule *onemol, int iatom, + int ilocal, tagint offset) +{ + if (onemol->qflag && q_flag) q[ilocal] = onemol->q[iatom]; + if (onemol->radiusflag && radius_flag) radius[ilocal] = onemol->radius[iatom]; + if (onemol->rmassflag && rmass_flag) rmass[ilocal] = onemol->rmass[iatom]; + if (onemol->replambdaHflag && replambdaH_flag) replambdaH[ilocal] = onemol->replambdaH[iatom]; + if (onemol->moltypeHflag && moltypeH_flag) moltypeH[ilocal] = onemol->moltypeH[iatom]; + else if (rmass_flag) + rmass[ilocal] = 4.0*MY_PI/3.0 * + radius[ilocal]*radius[ilocal]*radius[ilocal]; + if (onemol->bodyflag) { + body[ilocal] = 0; // as if a body read from data file + onemol->avec_body->data_body(ilocal,onemol->nibody,onemol->ndbody, + onemol->ibodyparams,onemol->dbodyparams); + onemol->avec_body->set_quat(ilocal,onemol->quat_external); + } + + if (molecular != 1) return; + + // add bond topology info + // for molecular atom styles, but not atom style template + + if (avec->bonds_allow) { + num_bond[ilocal] = onemol->num_bond[iatom]; + for (int i = 0; i < num_bond[ilocal]; i++) { + bond_type[ilocal][i] = onemol->bond_type[iatom][i]; + bond_atom[ilocal][i] = onemol->bond_atom[iatom][i] + offset; + } + } + + if (avec->angles_allow) { + num_angle[ilocal] = onemol->num_angle[iatom]; + for (int i = 0; i < num_angle[ilocal]; i++) { + angle_type[ilocal][i] = onemol->angle_type[iatom][i]; + angle_atom1[ilocal][i] = onemol->angle_atom1[iatom][i] + offset; + angle_atom2[ilocal][i] = onemol->angle_atom2[iatom][i] + offset; + angle_atom3[ilocal][i] = onemol->angle_atom3[iatom][i] + offset; + } + } + + if (avec->dihedrals_allow) { + num_dihedral[ilocal] = onemol->num_dihedral[iatom]; + for (int i = 0; i < num_dihedral[ilocal]; i++) { + dihedral_type[ilocal][i] = onemol->dihedral_type[iatom][i]; + dihedral_atom1[ilocal][i] = onemol->dihedral_atom1[iatom][i] + offset; + dihedral_atom2[ilocal][i] = onemol->dihedral_atom2[iatom][i] + offset; + dihedral_atom3[ilocal][i] = onemol->dihedral_atom3[iatom][i] + offset; + dihedral_atom4[ilocal][i] = onemol->dihedral_atom4[iatom][i] + offset; + } + } + + if (avec->impropers_allow) { + num_improper[ilocal] = onemol->num_improper[iatom]; + for (int i = 0; i < num_improper[ilocal]; i++) { + improper_type[ilocal][i] = onemol->improper_type[iatom][i]; + improper_atom1[ilocal][i] = onemol->improper_atom1[iatom][i] + offset; + improper_atom2[ilocal][i] = onemol->improper_atom2[iatom][i] + offset; + improper_atom3[ilocal][i] = onemol->improper_atom3[iatom][i] + offset; + improper_atom4[ilocal][i] = onemol->improper_atom4[iatom][i] + offset; + } + } + + if (onemol->specialflag) { + nspecial[ilocal][0] = onemol->nspecial[iatom][0]; + nspecial[ilocal][1] = onemol->nspecial[iatom][1]; + int n = nspecial[ilocal][2] = onemol->nspecial[iatom][2]; + for (int i = 0; i < n; i++) + special[ilocal][i] = onemol->special[iatom][i] + offset; + } +} + +/* ---------------------------------------------------------------------- + reorder owned atoms so those in firstgroup appear first + called by comm->exchange() if atom_modify first group is set + only owned atoms exist at this point, no ghost atoms +------------------------------------------------------------------------- */ + +void Atom::first_reorder() +{ + // insure there is one extra atom location at end of arrays for swaps + + if (nlocal == nmax) avec->grow(0); + + // loop over owned atoms + // nfirst = index of first atom not in firstgroup + // when find firstgroup atom out of place, swap it with atom nfirst + + int bitmask = group->bitmask[firstgroup]; + nfirst = 0; + while (nfirst < nlocal && mask[nfirst] & bitmask) nfirst++; + + for (int i = 0; i < nlocal; i++) { + if (mask[i] & bitmask && i > nfirst) { + avec->copy(i,nlocal,0); + avec->copy(nfirst,i,0); + avec->copy(nlocal,nfirst,0); + while (nfirst < nlocal && mask[nfirst] & bitmask) nfirst++; + } + } +} + +/* ---------------------------------------------------------------------- + perform spatial sort of atoms within my sub-domain + always called between comm->exchange() and comm->borders() + don't have to worry about clearing/setting atom->map since done in comm +------------------------------------------------------------------------- */ + +void Atom::sort() +{ + int i,m,n,ix,iy,iz,ibin,empty; + + // set next timestep for sorting to take place + + nextsort = (update->ntimestep/sortfreq)*sortfreq + sortfreq; + + // download data from GPU if necessary + + if (lmp->cuda && !lmp->cuda->oncpu) lmp->cuda->downloadAll(); + + // re-setup sort bins if needed + + if (domain->box_change) setup_sort_bins(); + if (nbins == 1) return; + + // reallocate per-atom vectors if needed + + if (nlocal > maxnext) { + memory->destroy(next); + memory->destroy(permute); + maxnext = atom->nmax; + memory->create(next,maxnext,"atom:next"); + memory->create(permute,maxnext,"atom:permute"); + } + + // insure there is one extra atom location at end of arrays for swaps + + if (nlocal == nmax) avec->grow(0); + + // bin atoms in reverse order so linked list will be in forward order + + for (i = 0; i < nbins; i++) binhead[i] = -1; + + for (i = nlocal-1; i >= 0; i--) { + ix = static_cast<int> ((x[i][0]-bboxlo[0])*bininvx); + iy = static_cast<int> ((x[i][1]-bboxlo[1])*bininvy); + iz = static_cast<int> ((x[i][2]-bboxlo[2])*bininvz); + ix = MAX(ix,0); + iy = MAX(iy,0); + iz = MAX(iz,0); + ix = MIN(ix,nbinx-1); + iy = MIN(iy,nbiny-1); + iz = MIN(iz,nbinz-1); + ibin = iz*nbiny*nbinx + iy*nbinx + ix; + next[i] = binhead[ibin]; + binhead[ibin] = i; + } + + // permute = desired permutation of atoms + // permute[I] = J means Ith new atom will be Jth old atom + + n = 0; + for (m = 0; m < nbins; m++) { + i = binhead[m]; + while (i >= 0) { + permute[n++] = i; + i = next[i]; + } + } + + // current = current permutation, just reuse next vector + // current[I] = J means Ith current atom is Jth old atom + + int *current = next; + for (i = 0; i < nlocal; i++) current[i] = i; + + // reorder local atom list, when done, current = permute + // perform "in place" using copy() to extra atom location at end of list + // inner while loop processes one cycle of the permutation + // copy before inner-loop moves an atom to end of atom list + // copy after inner-loop moves atom at end of list back into list + // empty = location in atom list that is currently empty + + for (i = 0; i < nlocal; i++) { + if (current[i] == permute[i]) continue; + avec->copy(i,nlocal,0); + empty = i; + while (permute[empty] != i) { + avec->copy(permute[empty],empty,0); + empty = current[empty] = permute[empty]; + } + avec->copy(nlocal,empty,0); + current[empty] = permute[empty]; + } + + // upload data back to GPU if necessary + + if (lmp->cuda && !lmp->cuda->oncpu) lmp->cuda->uploadAll(); + + // sanity check that current = permute + + //int flag = 0; + //for (i = 0; i < nlocal; i++) + // if (current[i] != permute[i]) flag = 1; + //int flagall; + //MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); + //if (flagall) error->all(FLERR,"Atom sort did not operate correctly"); +} + +/* ---------------------------------------------------------------------- + setup bins for spatial sorting of atoms +------------------------------------------------------------------------- */ + +void Atom::setup_sort_bins() +{ + // binsize: + // user setting if explicitly set + // 1/2 of neighbor cutoff for non-CUDA + // CUDA_CHUNK atoms/proc for CUDA + // check if neighbor cutoff = 0.0 + + double binsize; + if (userbinsize > 0.0) binsize = userbinsize; + else if (!lmp->cuda) binsize = 0.5 * neighbor->cutneighmax; + else { + if (domain->dimension == 3) { + double vol = (domain->boxhi[0]-domain->boxlo[0]) * + (domain->boxhi[1]-domain->boxlo[1]) * + (domain->boxhi[2]-domain->boxlo[2]); + binsize = pow(1.0*CUDA_CHUNK/natoms*vol,1.0/3.0); + } else { + double area = (domain->boxhi[0]-domain->boxlo[0]) * + (domain->boxhi[1]-domain->boxlo[1]); + binsize = pow(1.0*CUDA_CHUNK/natoms*area,1.0/2.0); + } + } + if (binsize == 0.0) error->all(FLERR,"Atom sorting has bin size = 0.0"); + + double bininv = 1.0/binsize; + + // nbin xyz = local bins + // bbox lo/hi = bounding box of my sub-domain + + if (domain->triclinic) + domain->bbox(domain->sublo_lamda,domain->subhi_lamda,bboxlo,bboxhi); + else { + bboxlo[0] = domain->sublo[0]; + bboxlo[1] = domain->sublo[1]; + bboxlo[2] = domain->sublo[2]; + bboxhi[0] = domain->subhi[0]; + bboxhi[1] = domain->subhi[1]; + bboxhi[2] = domain->subhi[2]; + } + + nbinx = static_cast<int> ((bboxhi[0]-bboxlo[0]) * bininv); + nbiny = static_cast<int> ((bboxhi[1]-bboxlo[1]) * bininv); + nbinz = static_cast<int> ((bboxhi[2]-bboxlo[2]) * bininv); + if (domain->dimension == 2) nbinz = 1; + + if (nbinx == 0) nbinx = 1; + if (nbiny == 0) nbiny = 1; + if (nbinz == 0) nbinz = 1; + + bininvx = nbinx / (bboxhi[0]-bboxlo[0]); + bininvy = nbiny / (bboxhi[1]-bboxlo[1]); + bininvz = nbinz / (bboxhi[2]-bboxlo[2]); + + if (1.0*nbinx*nbiny*nbinz > INT_MAX) + error->one(FLERR,"Too many atom sorting bins"); + + nbins = nbinx*nbiny*nbinz; + + // reallocate per-bin memory if needed + + if (nbins > maxbin) { + memory->destroy(binhead); + maxbin = nbins; + memory->create(binhead,maxbin,"atom:binhead"); + } +} + +/* ---------------------------------------------------------------------- + register a callback to a fix so it can manage atom-based arrays + happens when fix is created + flag = 0 for grow, 1 for restart, 2 for border comm +------------------------------------------------------------------------- */ + +void Atom::add_callback(int flag) +{ + int ifix; + + // find the fix + // if find NULL ptr: + // it's this one, since it is being replaced and has just been deleted + // at this point in re-creation + // if don't find NULL ptr: + // i is set to nfix = new one currently being added at end of list + + for (ifix = 0; ifix < modify->nfix; ifix++) + if (modify->fix[ifix] == NULL) break; + + // add callback to lists, reallocating if necessary + + if (flag == 0) { + if (nextra_grow == nextra_grow_max) { + nextra_grow_max += DELTA; + memory->grow(extra_grow,nextra_grow_max,"atom:extra_grow"); + } + extra_grow[nextra_grow] = ifix; + nextra_grow++; + } else if (flag == 1) { + if (nextra_restart == nextra_restart_max) { + nextra_restart_max += DELTA; + memory->grow(extra_restart,nextra_restart_max,"atom:extra_restart"); + } + extra_restart[nextra_restart] = ifix; + nextra_restart++; + } else if (flag == 2) { + if (nextra_border == nextra_border_max) { + nextra_border_max += DELTA; + memory->grow(extra_border,nextra_border_max,"atom:extra_border"); + } + extra_border[nextra_border] = ifix; + nextra_border++; + } +} + +/* ---------------------------------------------------------------------- + unregister a callback to a fix + happens when fix is deleted, called by its destructor + flag = 0 for grow, 1 for restart +------------------------------------------------------------------------- */ + +void Atom::delete_callback(const char *id, int flag) +{ + int ifix; + for (ifix = 0; ifix < modify->nfix; ifix++) + if (strcmp(id,modify->fix[ifix]->id) == 0) break; + + // compact the list of callbacks + + if (flag == 0) { + int match; + for (match = 0; match < nextra_grow; match++) + if (extra_grow[match] == ifix) break; + for (int i = match; i < nextra_grow-1; i++) + extra_grow[i] = extra_grow[i+1]; + nextra_grow--; + + } else if (flag == 1) { + int match; + for (match = 0; match < nextra_restart; match++) + if (extra_restart[match] == ifix) break; + for (int i = match; i < nextra_restart-1; i++) + extra_restart[i] = extra_restart[i+1]; + nextra_restart--; + + } else if (flag == 2) { + int match; + for (match = 0; match < nextra_border; match++) + if (extra_border[match] == ifix) break; + for (int i = match; i < nextra_border-1; i++) + extra_border[i] = extra_border[i+1]; + nextra_border--; + } +} + +/* ---------------------------------------------------------------------- + decrement ptrs in callback lists to fixes beyond the deleted ifix + happens after fix is deleted +------------------------------------------------------------------------- */ + +void Atom::update_callback(int ifix) +{ + for (int i = 0; i < nextra_grow; i++) + if (extra_grow[i] > ifix) extra_grow[i]--; + for (int i = 0; i < nextra_restart; i++) + if (extra_restart[i] > ifix) extra_restart[i]--; + for (int i = 0; i < nextra_border; i++) + if (extra_border[i] > ifix) extra_border[i]--; +} + +/* ---------------------------------------------------------------------- + find custom per-atom vector with name + return index if found, and flag = 0/1 for int/double + return -1 if not found +------------------------------------------------------------------------- */ + +int Atom::find_custom(char *name, int &flag) +{ + for (int i = 0; i < nivector; i++) + if (iname[i] && strcmp(iname[i],name) == 0) { + flag = 0; + return i; + } + + for (int i = 0; i < ndvector; i++) + if (dname[i] && strcmp(dname[i],name) == 0) { + flag = 1; + return i; + } + + return -1; +} + +/* ---------------------------------------------------------------------- + add a custom variable with name of type flag = 0/1 for int/double + assumes name does not already exist + return index in ivector or dvector of its location +------------------------------------------------------------------------- */ + +int Atom::add_custom(char *name, int flag) +{ + int index; + + if (flag == 0) { + index = nivector; + nivector++; + iname = (char **) memory->srealloc(iname,nivector*sizeof(char *), + "atom:iname"); + int n = strlen(name) + 1; + iname[index] = new char[n]; + strcpy(iname[index],name); + ivector = (int **) memory->srealloc(ivector,nivector*sizeof(int *), + "atom:ivector"); + memory->create(ivector[index],nmax,"atom:ivector"); + } else { + index = ndvector; + ndvector++; + dname = (char **) memory->srealloc(dname,ndvector*sizeof(char *), + "atom:dname"); + int n = strlen(name) + 1; + dname[index] = new char[n]; + strcpy(dname[index],name); + dvector = (double **) memory->srealloc(dvector,ndvector*sizeof(double *), + "atom:dvector"); + memory->create(dvector[index],nmax,"atom:dvector"); + } + + return index; +} + +/* ---------------------------------------------------------------------- + remove a custom variable of type flag = 0/1 for int/double at index + free memory for vector and name and set ptrs to NULL + ivector/dvector and iname/dname lists never shrink +------------------------------------------------------------------------- */ + +void Atom::remove_custom(int flag, int index) +{ + if (flag == 0) { + memory->destroy(ivector[index]); + ivector[index] = NULL; + delete [] iname[index]; + iname[index] = NULL; + } else { + memory->destroy(dvector[index]); + dvector[index] = NULL; + delete [] dname[index]; + dname[index] = NULL; + } +} + +/* ---------------------------------------------------------------------- + return a pointer to a named internal variable + if don't recognize name, return NULL + customize by adding names +------------------------------------------------------------------------- */ + +void *Atom::extract(char *name) +{ + if (strcmp(name,"mass") == 0) return (void *) mass; + + if (strcmp(name,"id") == 0) return (void *) tag; + if (strcmp(name,"type") == 0) return (void *) type; + if (strcmp(name,"mask") == 0) return (void *) mask; + if (strcmp(name,"image") == 0) return (void *) image; + if (strcmp(name,"x") == 0) return (void *) x; + if (strcmp(name,"v") == 0) return (void *) v; + if (strcmp(name,"f") == 0) return (void *) f; + if (strcmp(name,"molecule") == 0) return (void *) molecule; + if (strcmp(name,"q") == 0) return (void *) q; + if (strcmp(name,"lambdaH") == 0) return (void *) lambdaH; + if (strcmp(name,"gradlambdaH") == 0) return (void *) gradlambdaH; + if (strcmp(name,"replambdaH") == 0) return (void *) replambdaH; + if (strcmp(name,"mu") == 0) return (void *) mu; + if (strcmp(name,"omega") == 0) return (void *) omega; + if (strcmp(name,"angmom") == 0) return (void *) angmom; + if (strcmp(name,"torque") == 0) return (void *) torque; + if (strcmp(name,"radius") == 0) return (void *) radius; + if (strcmp(name,"rmass") == 0) return (void *) rmass; + if (strcmp(name,"ellipsoid") == 0) return (void *) ellipsoid; + if (strcmp(name,"line") == 0) return (void *) line; + if (strcmp(name,"tri") == 0) return (void *) tri; + + if (strcmp(name,"vfrac") == 0) return (void *) vfrac; + if (strcmp(name,"s0") == 0) return (void *) s0; + if (strcmp(name,"x0") == 0) return (void *) x0; + + if (strcmp(name,"spin") == 0) return (void *) spin; + if (strcmp(name,"eradius") == 0) return (void *) eradius; + if (strcmp(name,"ervel") == 0) return (void *) ervel; + if (strcmp(name,"erforce") == 0) return (void *) erforce; + if (strcmp(name,"ervelforce") == 0) return (void *) ervelforce; + if (strcmp(name,"cs") == 0) return (void *) cs; + if (strcmp(name,"csforce") == 0) return (void *) csforce; + if (strcmp(name,"vforce") == 0) return (void *) vforce; + if (strcmp(name,"etag") == 0) return (void *) etag; + + if (strcmp(name,"rho") == 0) return (void *) rho; + if (strcmp(name,"drho") == 0) return (void *) drho; + if (strcmp(name,"e") == 0) return (void *) e; + if (strcmp(name,"de") == 0) return (void *) de; + if (strcmp(name,"cv") == 0) return (void *) cv; + if (strcmp(name,"vest") == 0) return (void *) vest; + + if (strcmp(name, "contact_radius") == 0) return (void *) contact_radius; + if (strcmp(name, "smd_data_9") == 0) return (void *) smd_data_9; + if (strcmp(name, "smd_stress") == 0) return (void *) smd_stress; + if (strcmp(name, "eff_plastic_strain") == 0) + return (void *) eff_plastic_strain; + if (strcmp(name, "eff_plastic_strain_rate") == 0) + return (void *) eff_plastic_strain_rate; + if (strcmp(name, "damage") == 0) return (void *) damage; + + if (strcmp(name,"dpdTheta") == 0) return (void *) dpdTheta; + + return NULL; +} + +/* ---------------------------------------------------------------------- + return # of bytes of allocated memory + call to avec tallies per-atom vectors + add in global to local mapping storage +------------------------------------------------------------------------- */ + +bigint Atom::memory_usage() +{ + memlength = DELTA_MEMSTR; + memory->create(memstr,memlength,"atom:memstr"); + memstr[0] = '\0'; + bigint bytes = avec->memory_usage(); + memory->destroy(memstr); + + bytes += max_same*sizeof(int); + if (map_style == 1 && map_tag_max >= 0) + bytes += memory->usage(map_array,map_maxarray); + else if (map_style == 2 && map_nhash >=0) { + bytes += map_nbucket*sizeof(int); + bytes += map_nhash*sizeof(HashElem); + } + if (maxnext) { + bytes += memory->usage(next,maxnext); + bytes += memory->usage(permute,maxnext); + } + + return bytes; +} + +/* ---------------------------------------------------------------------- + accumulate per-atom vec names in memstr, padded by spaces + return 1 if padded str is not already in memlist, else 0 +------------------------------------------------------------------------- */ + +int Atom::memcheck(const char *str) +{ + int n = strlen(str) + 3; + char *padded = new char[n]; + strcpy(padded," "); + strcat(padded,str); + strcat(padded," "); + + if (strstr(memstr,padded)) { + delete [] padded; + return 0; + } + + if (strlen(memstr) + n >= memlength) { + memlength += DELTA_MEMSTR; + memory->grow(memstr,memlength,"atom:memstr"); + } + + strcat(memstr,padded); + delete [] padded; + return 1; +} diff --git a/src/USER-HADRESS/atom.h b/src/USER-HADRESS/atom.h new file mode 100644 index 000000000..1675e7fe2 --- /dev/null +++ b/src/USER-HADRESS/atom.h @@ -0,0 +1,519 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifndef LMP_ATOM_H +#define LMP_ATOM_H + +#include "pointers.h" + +namespace LAMMPS_NS { + +class Atom : protected Pointers { + public: + char *atom_style; + class AtomVec *avec; + + // atom counts + + bigint natoms; // total # of atoms in system, could be 0 + // natoms may not be current if atoms lost + int nlocal,nghost; // # of owned and ghost atoms on this proc + int nmax; // max # of owned+ghost in arrays on this proc + int tag_enable; // 0/1 if atom ID tags are defined + int molecular; // 0 = atomic, 1 = standard molecular system, + // 2 = molecule template system + + bigint nbonds,nangles,ndihedrals,nimpropers; + int ntypes,nbondtypes,nangletypes,ndihedraltypes,nimpropertypes; + int bond_per_atom,angle_per_atom,dihedral_per_atom,improper_per_atom; + int extra_bond_per_atom,extra_angle_per_atom; + int extra_dihedral_per_atom,extra_improper_per_atom; + + int firstgroup; // store atoms in this group first, -1 if unset + int nfirst; // # of atoms in first group on this proc + char *firstgroupname; // group-ID to store first, NULL if unset + + // per-atom arrays + // customize by adding new array + + tagint *tag; + int *type,*mask; + imageint *image; + double **x,**v,**f; + + tagint *molecule; + int *molindex,*molatom; + + double *q,**mu; + double *lambdaH,**gradlambdaH; + int *replambdaH; + int *moltypeH; + int nmoltypesH; + double **comH; + + double **omega,**angmom,**torque; + double *radius,*rmass; + int *ellipsoid,*line,*tri,*body; + + // PERI package + + double *vfrac,*s0; + double **x0; + + // USER-EFF and USER-AWPMD packages + + int *spin; + double *eradius,*ervel,*erforce,*ervelforce; + double *cs,*csforce,*vforce; + int *etag; + + // USER-SPH package + + double *rho,*drho,*e,*de,*cv; + double **vest; + + // USER-SMD package + + double *contact_radius; + double **smd_data_9; + double **smd_stress; + double *eff_plastic_strain; + double *eff_plastic_strain_rate; + double *damage; + + // USER-DPD package + + double *uCond, *uMech, *uChem, *uCGnew, *uCG; + double *duCond, *duMech, *duChem; + double *dpdTheta; + + // molecular info + + int **nspecial; // 0,1,2 = cummulative # of 1-2,1-3,1-4 neighs + tagint **special; // IDs of 1-2,1-3,1-4 neighs of each atom + int maxspecial; // special[nlocal][maxspecial] + + int *num_bond; + int **bond_type; + tagint **bond_atom; + + int *num_angle; + int **angle_type; + tagint **angle_atom1,**angle_atom2,**angle_atom3; + + int *num_dihedral; + int **dihedral_type; + tagint **dihedral_atom1,**dihedral_atom2,**dihedral_atom3,**dihedral_atom4; + + int *num_improper; + int **improper_type; + tagint **improper_atom1,**improper_atom2,**improper_atom3,**improper_atom4; + + // custom arrays used by fix property/atom + + int **ivector; + double **dvector; + char **iname,**dname; + int nivector,ndvector; + + // used by USER-CUDA to flag used per-atom arrays + + unsigned int datamask; + unsigned int datamask_ext; + + // atom style and per-atom array existence flags + // customize by adding new flag + + int sphere_flag,ellipsoid_flag,line_flag,tri_flag,body_flag; + int peri_flag,electron_flag; + int ecp_flag; + int wavepacket_flag,sph_flag; + + int molecule_flag,molindex_flag,molatom_flag; + int q_flag,mu_flag; + int replambdaH_flag, moltypeH_flag; + int rmass_flag,radius_flag,omega_flag,torque_flag,angmom_flag; + int vfrac_flag,spin_flag,eradius_flag,ervel_flag,erforce_flag; + int cs_flag,csforce_flag,vforce_flag,ervelforce_flag,etag_flag; + int rho_flag,e_flag,cv_flag,vest_flag; + int dpd_flag; + + // USER-SMD package + + int smd_flag; + int contact_radius_flag; + int smd_data_9_flag; + int smd_stress_flag; + int x0_flag; + int eff_plastic_strain_flag; + int eff_plastic_strain_rate_flag; + int damage_flag; + + // Peridynamics scale factor, used by dump cfg + + double pdscale; + + // molecule templates + // each template can be a set of consecutive molecules + // each with same ID (stored in molecules) + // 1st molecule in template stores nset = # in set + + int nmolecule; + class Molecule **molecules; + + // extra peratom info in restart file destined for fix & diag + + double **extra; + + // per-type arrays + + double *mass; + int *mass_setflag; + + // callback ptrs for atom arrays managed by fix classes + + int nextra_grow,nextra_restart,nextra_border; // # of callbacks of each type + int *extra_grow,*extra_restart,*extra_border; // index of fix to callback to + int nextra_grow_max,nextra_restart_max; // size of callback lists + int nextra_border_max; + int nextra_store; + + int map_style; // style of atom map: 0=none, 1=array, 2=hash + int map_user; // user selected style = same 0,1,2 + tagint map_tag_max; // max atom ID that map() is setup for + + // spatial sorting of atoms + + int sortfreq; // sort atoms every this many steps, 0 = off + bigint nextsort; // next timestep to sort on + double userbinsize; // requested sort bin size + + // indices of atoms with same ID + + int *sametag; // sametag[I] = next atom with same ID, -1 if no more + + // functions + + Atom(class LAMMPS *); + ~Atom(); + + void settings(class Atom *); + void create_avec(const char *, int, char **, int); + virtual class AtomVec *new_avec(const char *, int, int &); + void init(); + void setup(); + + class AtomVec *style_match(const char *); + void modify_params(int, char **); + void tag_check(); + void tag_extend(); + int tag_consecutive(); + + int parse_data(const char *); + int count_words(const char *); + int count_words(const char *, char *); + + void deallocate_topology(); + + void data_atoms(int, char *, tagint, int, int, double *); + void data_vels(int, char *, tagint); + + void data_bonds(int, char *, int *, tagint, int); + void data_angles(int, char *, int *, tagint, int); + void data_dihedrals(int, char *, int *, tagint, int); + void data_impropers(int, char *, int *, tagint, int); + + void data_bonus(int, char *, class AtomVec *, tagint); + void data_bodies(int, char *, class AtomVecBody *, tagint); + + virtual void allocate_type_arrays(); + void set_mass(const char *, int); + void set_mass(int, double); + void set_mass(int, char **); + void set_mass(double *); + void check_mass(); + + int radius_consistency(int, double &); + int shape_consistency(int, double &, double &, double &); + + void add_molecule(int, char **); + int find_molecule(char *); + void add_molecule_atom(class Molecule *, int, int, tagint); + + void first_reorder(); + virtual void sort(); + + void add_callback(int); + void delete_callback(const char *, int); + void update_callback(int); + + int find_custom(char *, int &); + int add_custom(char *, int); + void remove_custom(int, int); + + virtual void sync_modify(ExecutionSpace, unsigned int, unsigned int) {} + + void *extract(char *); + + inline int* get_map_array() {return map_array;}; + inline int get_map_size() {return map_tag_max+1;}; + + bigint memory_usage(); + int memcheck(const char *); + + // functions for global to local ID mapping + // map lookup function inlined for efficiency + // return -1 if no map defined + + inline int map(tagint global) { + if (map_style == 1) return map_array[global]; + else if (map_style == 2) return map_find_hash(global); + else return -1; + }; + + void map_init(int check = 1); + void map_clear(); + void map_set(); + void map_one(tagint, int); + int map_style_set(); + void map_delete(); + int map_find_hash(tagint); + + protected: + + // global to local ID mapping + + int *map_array; // direct map via array that holds map_tag_max + int map_maxarray; // allocated size of map_array (1 larger than this) + + struct HashElem { // hashed map + tagint global; // key to search on = global ID + int local; // value associated with key = local index + int next; // next entry in this bucket, -1 if last + }; + int map_nhash; // # of entries hash table can hold + int map_nused; // # of actual entries in hash table + int map_free; // ptr to 1st unused entry in hash table + int map_nbucket; // # of hash buckets + int *map_bucket; // ptr to 1st entry in each bucket + HashElem *map_hash; // hash table + + int max_same; // allocated size of sametag + + // spatial sorting of atoms + + int nbins; // # of sorting bins + int nbinx,nbiny,nbinz; // bins in each dimension + int maxbin; // max # of bins + int maxnext; // max size of next,permute + int *binhead; // 1st atom in each bin + int *next; // next atom in bin + int *permute; // permutation vector + double bininvx,bininvy,bininvz; // inverse actual bin sizes + double bboxlo[3],bboxhi[3]; // bounding box of my sub-domain + + int memlength; // allocated size of memstr + char *memstr; // string of array names already counted + + void setup_sort_bins(); + int next_prime(int); +}; + +} + +#endif + +/* ERROR/WARNING messages: + +E: Atom IDs must be used for molecular systems + +Atom IDs are used to identify and find partner atoms in bonds. + +E: Unknown atom style + +The choice of atom style is unknown. + +E: Could not find atom_modify first group ID + +Self-explanatory. + +E: Illegal ... command + +Self-explanatory. Check the input script syntax and compare to the +documentation for the command. You can use -echo screen as a +command-line option when running LAMMPS to see the offending line. + +E: Atom_modify id command after simulation box is defined + +The atom_modify id command cannot be used after a read_data, +read_restart, or create_box command. + +E: Atom_modify map command after simulation box is defined + +The atom_modify map command cannot be used after a read_data, +read_restart, or create_box command. + +E: Atom_modify sort and first options cannot be used together + +Self-explanatory. + +E: One or more Atom IDs is negative + +Atom IDs must be positive integers. + +E: One or more atom IDs is too big + +The limit on atom IDs is set by the SMALLBIG, BIGBIG, SMALLSMALL +setting in your Makefile. See Section_start 2.2 of the manual for +more details. + +E: One or more atom IDs is zero + +Either all atoms IDs must be zero or none of them. + +E: Non-zero atom IDs with atom_modify id = no + +Self-explanatory. + +E: All atom IDs = 0 but atom_modify id = yes + +Self-explanatory. + +E: Duplicate atom IDs exist + +Self-explanatory. + +E: New atom IDs exceed maximum allowed ID + +See the setting for tagint in the src/lmptype.h file. + +E: Incorrect atom format in data file + +Number of values per atom line in the data file is not consistent with +the atom style. + +E: Invalid atom type in Atoms section of data file + +Atom types must range from 1 to specified # of types. + +E: Incorrect velocity format in data file + +Each atom style defines a format for the Velocity section +of the data file. The read-in lines do not match. + +E: Invalid atom ID in Velocities section of data file + +Atom IDs must be positive integers and within range of defined +atoms. + +E: Invalid atom ID in Bonds section of data file + +Atom IDs must be positive integers and within range of defined +atoms. + +E: Invalid bond type in Bonds section of data file + +Bond type must be positive integer and within range of specified bond +types. + +E: Invalid atom ID in Angles section of data file + +Atom IDs must be positive integers and within range of defined +atoms. + +E: Invalid angle type in Angles section of data file + +Angle type must be positive integer and within range of specified angle +types. + +E: Invalid atom ID in Dihedrals section of data file + +Atom IDs must be positive integers and within range of defined +atoms. + +E: Invalid dihedral type in Dihedrals section of data file + +Dihedral type must be positive integer and within range of specified +dihedral types. + +E: Invalid atom ID in Impropers section of data file + +Atom IDs must be positive integers and within range of defined +atoms. + +E: Invalid improper type in Impropers section of data file + +Improper type must be positive integer and within range of specified +improper types. + +E: Incorrect bonus data format in data file + +See the read_data doc page for a description of how various kinds of +bonus data must be formatted for certain atom styles. + +E: Invalid atom ID in Bonus section of data file + +Atom IDs must be positive integers and within range of defined +atoms. + +E: Invalid atom ID in Bodies section of data file + +Atom IDs must be positive integers and within range of defined +atoms. + +E: Cannot set mass for this atom style + +This atom style does not support mass settings for each atom type. +Instead they are defined on a per-atom basis in the data file. + +E: Invalid mass line in data file + +Self-explanatory. + +E: Invalid type for mass set + +Mass command must set a type from 1-N where N is the number of atom +types. + +E: Invalid mass value + +Self-explanatory. + +E: All masses are not set + +For atom styles that define masses for each atom type, all masses must +be set in the data file or by the mass command before running a +simulation. They must also be set before using the velocity +command. + +E: Reuse of molecule template ID + +The template IDs must be unique. + +E: Atom sort did not operate correctly + +This is an internal LAMMPS error. Please report it to the +developers. + +E: Atom sorting has bin size = 0.0 + +The neighbor cutoff is being used as the bin size, but it is zero. +Thus you must explicitly list a bin size in the atom_modify sort +command or turn off sorting. + +E: Too many atom sorting bins + +This is likely due to an immense simulation box that has blown up +to a large size. + +*/ diff --git a/src/USER-HADRESS/atom_vec_full_hars.cpp b/src/USER-HADRESS/atom_vec_full_hars.cpp new file mode 100644 index 000000000..fe01c0fa9 --- /dev/null +++ b/src/USER-HADRESS/atom_vec_full_hars.cpp @@ -0,0 +1,1352 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#include "stdlib.h" +#include "atom_vec_full_hars.h" +#include "atom.h" +#include "comm.h" +#include "domain.h" +#include "modify.h" +#include "fix.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +AtomVecFullHars::AtomVecFullHars(LAMMPS *lmp) : AtomVec(lmp) +{ + molecular = 1; + bonds_allow = angles_allow = dihedrals_allow = impropers_allow = 1; + mass_type = 1; + + comm_x_only = comm_f_only = 0; + size_forward = 10; + size_reverse = 3; + size_border = 17; + size_velocity = 3; + size_data_atom = 9; + size_data_vel = 4; + xcol_data = 7; + + atom->molecule_flag = atom->q_flag = 1; + atom->replambdaH_flag = 1; + atom->moltypeH_flag = 1; + +} + +/* ---------------------------------------------------------------------- + grow atom arrays + n = 0 grows arrays by a chunk + n > 0 allocates arrays to size n +------------------------------------------------------------------------- */ + +void AtomVecFullHars::grow(int n) +{ + if (n == 0) grow_nmax(); + else nmax = n; + atom->nmax = nmax; + if (nmax < 0 || nmax > MAXSMALLINT) + error->one(FLERR,"Per-processor system is too big"); + + tag = memory->grow(atom->tag,nmax,"atom:tag"); + type = memory->grow(atom->type,nmax,"atom:type"); + mask = memory->grow(atom->mask,nmax,"atom:mask"); + image = memory->grow(atom->image,nmax,"atom:image"); + x = memory->grow(atom->x,nmax,3,"atom:x"); + v = memory->grow(atom->v,nmax,3,"atom:v"); + f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); + + q = memory->grow(atom->q,nmax,"atom:q"); + lambdaH = memory->grow(atom->lambdaH,nmax,"atom:lambdaH"); + gradlambdaH = memory->grow(atom->gradlambdaH,nmax,3,"atom:gradlambdaH"); + replambdaH = memory->grow(atom->replambdaH,nmax,"atom:replambdaH"); + moltypeH = memory->grow(atom->moltypeH,nmax,"atom:moltypeH"); + comH = memory->grow(atom->comH,nmax,3,"atom:comH"); + + molecule = memory->grow(atom->molecule,nmax,"atom:molecule"); + + nspecial = memory->grow(atom->nspecial,nmax,3,"atom:nspecial"); + special = memory->grow(atom->special,nmax,atom->maxspecial,"atom:special"); + + num_bond = memory->grow(atom->num_bond,nmax,"atom:num_bond"); + bond_type = memory->grow(atom->bond_type,nmax,atom->bond_per_atom, + "atom:bond_type"); + bond_atom = memory->grow(atom->bond_atom,nmax,atom->bond_per_atom, + "atom:bond_atom"); + + num_angle = memory->grow(atom->num_angle,nmax,"atom:num_angle"); + angle_type = memory->grow(atom->angle_type,nmax,atom->angle_per_atom, + "atom:angle_type"); + angle_atom1 = memory->grow(atom->angle_atom1,nmax,atom->angle_per_atom, + "atom:angle_atom1"); + angle_atom2 = memory->grow(atom->angle_atom2,nmax,atom->angle_per_atom, + "atom:angle_atom2"); + angle_atom3 = memory->grow(atom->angle_atom3,nmax,atom->angle_per_atom, + "atom:angle_atom3"); + + num_dihedral = memory->grow(atom->num_dihedral,nmax,"atom:num_dihedral"); + dihedral_type = memory->grow(atom->dihedral_type,nmax, + atom->dihedral_per_atom,"atom:dihedral_type"); + dihedral_atom1 = + memory->grow(atom->dihedral_atom1,nmax,atom->dihedral_per_atom, + "atom:dihedral_atom1"); + dihedral_atom2 = + memory->grow(atom->dihedral_atom2,nmax,atom->dihedral_per_atom, + "atom:dihedral_atom2"); + dihedral_atom3 = + memory->grow(atom->dihedral_atom3,nmax,atom->dihedral_per_atom, + "atom:dihedral_atom3"); + dihedral_atom4 = + memory->grow(atom->dihedral_atom4,nmax,atom->dihedral_per_atom, + "atom:dihedral_atom4"); + + num_improper = memory->grow(atom->num_improper,nmax,"atom:num_improper"); + improper_type = + memory->grow(atom->improper_type,nmax,atom->improper_per_atom, + "atom:improper_type"); + improper_atom1 = + memory->grow(atom->improper_atom1,nmax,atom->improper_per_atom, + "atom:improper_atom1"); + improper_atom2 = + memory->grow(atom->improper_atom2,nmax,atom->improper_per_atom, + "atom:improper_atom2"); + improper_atom3 = + memory->grow(atom->improper_atom3,nmax,atom->improper_per_atom, + "atom:improper_atom3"); + improper_atom4 = + memory->grow(atom->improper_atom4,nmax,atom->improper_per_atom, + "atom:improper_atom4"); + + if (atom->nextra_grow) + for (int iextra = 0; iextra < atom->nextra_grow; iextra++) + modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); +} + +/* ---------------------------------------------------------------------- + reset local array ptrs +------------------------------------------------------------------------- */ + +void AtomVecFullHars::grow_reset() +{ + tag = atom->tag; type = atom->type; + mask = atom->mask; image = atom->image; + x = atom->x; v = atom->v; f = atom->f; comH = atom->comH; + q = atom->q; lambdaH = atom->lambdaH;gradlambdaH = atom->gradlambdaH; + replambdaH = atom->replambdaH;moltypeH = atom->moltypeH;molecule = atom->molecule; + nspecial = atom->nspecial; special = atom->special; + num_bond = atom->num_bond; bond_type = atom->bond_type; + bond_atom = atom->bond_atom; + num_angle = atom->num_angle; angle_type = atom->angle_type; + angle_atom1 = atom->angle_atom1; angle_atom2 = atom->angle_atom2; + angle_atom3 = atom->angle_atom3; + num_dihedral = atom->num_dihedral; dihedral_type = atom->dihedral_type; + dihedral_atom1 = atom->dihedral_atom1; dihedral_atom2 = atom->dihedral_atom2; + dihedral_atom3 = atom->dihedral_atom3; dihedral_atom4 = atom->dihedral_atom4; + num_improper = atom->num_improper; improper_type = atom->improper_type; + improper_atom1 = atom->improper_atom1; improper_atom2 = atom->improper_atom2; + improper_atom3 = atom->improper_atom3; improper_atom4 = atom->improper_atom4; +} + +/* ---------------------------------------------------------------------- + copy atom I info to atom J +------------------------------------------------------------------------- */ + +void AtomVecFullHars::copy(int i, int j, int delflag) +{ + int k; + + tag[j] = tag[i]; + type[j] = type[i]; + mask[j] = mask[i]; + image[j] = image[i]; + x[j][0] = x[i][0]; + x[j][1] = x[i][1]; + x[j][2] = x[i][2]; + v[j][0] = v[i][0]; + v[j][1] = v[i][1]; + v[j][2] = v[i][2]; + + comH[j][0] = comH[i][0]; + comH[j][1] = comH[i][1]; + comH[j][2] = comH[i][2]; + + q[j] = q[i]; + lambdaH[j] = lambdaH[i]; + gradlambdaH[j][0] = gradlambdaH[i][0]; + gradlambdaH[j][1] = gradlambdaH[i][1]; + gradlambdaH[j][2] = gradlambdaH[i][2]; + replambdaH[j] = replambdaH[i]; + moltypeH[j] = moltypeH[i]; + molecule[j] = molecule[i]; + + + num_bond[j] = num_bond[i]; + for (k = 0; k < num_bond[j]; k++) { + bond_type[j][k] = bond_type[i][k]; + bond_atom[j][k] = bond_atom[i][k]; + } + + num_angle[j] = num_angle[i]; + for (k = 0; k < num_angle[j]; k++) { + angle_type[j][k] = angle_type[i][k]; + angle_atom1[j][k] = angle_atom1[i][k]; + angle_atom2[j][k] = angle_atom2[i][k]; + angle_atom3[j][k] = angle_atom3[i][k]; + } + + num_dihedral[j] = num_dihedral[i]; + for (k = 0; k < num_dihedral[j]; k++) { + dihedral_type[j][k] = dihedral_type[i][k]; + dihedral_atom1[j][k] = dihedral_atom1[i][k]; + dihedral_atom2[j][k] = dihedral_atom2[i][k]; + dihedral_atom3[j][k] = dihedral_atom3[i][k]; + dihedral_atom4[j][k] = dihedral_atom4[i][k]; + } + + num_improper[j] = num_improper[i]; + for (k = 0; k < num_improper[j]; k++) { + improper_type[j][k] = improper_type[i][k]; + improper_atom1[j][k] = improper_atom1[i][k]; + improper_atom2[j][k] = improper_atom2[i][k]; + improper_atom3[j][k] = improper_atom3[i][k]; + improper_atom4[j][k] = improper_atom4[i][k]; + } + + nspecial[j][0] = nspecial[i][0]; + nspecial[j][1] = nspecial[i][1]; + nspecial[j][2] = nspecial[i][2]; + for (k = 0; k < nspecial[j][2]; k++) special[j][k] = special[i][k]; + + if (atom->nextra_grow) + for (int iextra = 0; iextra < atom->nextra_grow; iextra++) + modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecFullHars::pack_comm(int n, int *list, double *buf, + int pbc_flag, int *pbc) +{ + int i,j,m; + double dx,dy,dz; + + m = 0; + if (pbc_flag == 0) { + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0]; + buf[m++] = x[j][1]; + buf[m++] = x[j][2]; + buf[m++] = lambdaH[j]; + buf[m++] = gradlambdaH[j][0]; + buf[m++] = gradlambdaH[j][1]; + buf[m++] = gradlambdaH[j][2]; + buf[m++] = comH[j][0]; + buf[m++] = comH[j][1]; + buf[m++] = comH[j][2]; + + } + } else { + if (domain->triclinic == 0) { + dx = pbc[0]*domain->xprd; + dy = pbc[1]*domain->yprd; + dz = pbc[2]*domain->zprd; + } else { + dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; + dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; + dz = pbc[2]*domain->zprd; + } + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0] + dx; + buf[m++] = x[j][1] + dy; + buf[m++] = x[j][2] + dz; + buf[m++] = lambdaH[j]; + buf[m++] = gradlambdaH[j][0]; + buf[m++] = gradlambdaH[j][1]; + buf[m++] = gradlambdaH[j][2]; + buf[m++] = comH[j][0]; + buf[m++] = comH[j][1]; + buf[m++] = comH[j][2]; + + + } + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecFullHars::pack_comm_vel(int n, int *list, double *buf, + int pbc_flag, int *pbc) +{ + int i,j,m; + double dx,dy,dz,dvx,dvy,dvz; + + m = 0; + if (pbc_flag == 0) { + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0]; + buf[m++] = x[j][1]; + buf[m++] = x[j][2]; + buf[m++] = lambdaH[j]; + buf[m++] = gradlambdaH[j][0]; + buf[m++] = gradlambdaH[j][1]; + buf[m++] = gradlambdaH[j][2]; + buf[m++] = comH[j][0]; + buf[m++] = comH[j][1]; + buf[m++] = comH[j][2]; + + buf[m++] = v[j][0]; + buf[m++] = v[j][1]; + buf[m++] = v[j][2]; + + } + } else { + if (domain->triclinic == 0) { + dx = pbc[0]*domain->xprd; + dy = pbc[1]*domain->yprd; + dz = pbc[2]*domain->zprd; + } else { + dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; + dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; + dz = pbc[2]*domain->zprd; + } + if (!deform_vremap) { + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0] + dx; + buf[m++] = x[j][1] + dy; + buf[m++] = x[j][2] + dz; + buf[m++] = lambdaH[j]; + buf[m++] = gradlambdaH[j][0]; + buf[m++] = gradlambdaH[j][1]; + buf[m++] = gradlambdaH[j][2]; + buf[m++] = comH[j][0]; + buf[m++] = comH[j][1]; + buf[m++] = comH[j][2]; + + buf[m++] = v[j][0]; + buf[m++] = v[j][1]; + buf[m++] = v[j][2]; + } + } else { + dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; + dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; + dvz = pbc[2]*h_rate[2]; + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0] + dx; + buf[m++] = x[j][1] + dy; + buf[m++] = x[j][2] + dz; + buf[m++] = lambdaH[j]; + buf[m++] = gradlambdaH[j][0]; + buf[m++] = gradlambdaH[j][1]; + buf[m++] = gradlambdaH[j][2]; + buf[m++] = comH[j][0]; + buf[m++] = comH[j][1]; + buf[m++] = comH[j][2]; + + + + if (mask[i] & deform_groupbit) { + buf[m++] = v[j][0] + dvx; + buf[m++] = v[j][1] + dvy; + buf[m++] = v[j][2] + dvz; + } else { + buf[m++] = v[j][0]; + buf[m++] = v[j][1]; + buf[m++] = v[j][2]; + } + } + } + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void AtomVecFullHars::unpack_comm(int n, int first, double *buf) +{ + int i,m,last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + x[i][0] = buf[m++]; + x[i][1] = buf[m++]; + x[i][2] = buf[m++]; + lambdaH[i] = buf[m++]; + gradlambdaH[i][0] = buf[m++]; + gradlambdaH[i][1] = buf[m++]; + gradlambdaH[i][2] = buf[m++]; + comH[i][0] = buf[m++]; + comH[i][1] = buf[m++]; + comH[i][2] = buf[m++]; + + + + } +} + +/* ---------------------------------------------------------------------- */ + +void AtomVecFullHars::unpack_comm_vel(int n, int first, double *buf) +{ + int i,m,last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + x[i][0] = buf[m++]; + x[i][1] = buf[m++]; + x[i][2] = buf[m++]; + lambdaH[i] = buf[m++]; + gradlambdaH[i][0] = buf[m++]; + gradlambdaH[i][1] = buf[m++]; + gradlambdaH[i][2] = buf[m++]; + comH[i][0] = buf[m++]; + comH[i][1] = buf[m++]; + comH[i][2] = buf[m++]; + + v[i][0] = buf[m++]; + v[i][1] = buf[m++]; + v[i][2] = buf[m++]; + } +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecFullHars::pack_reverse(int n, int first, double *buf) +{ + int i,m,last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + buf[m++] = f[i][0]; + buf[m++] = f[i][1]; + buf[m++] = f[i][2]; + + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void AtomVecFullHars::unpack_reverse(int n, int *list, double *buf) +{ + int i,j,m; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + f[j][0] += buf[m++]; + f[j][1] += buf[m++]; + f[j][2] += buf[m++]; + + + } +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecFullHars::pack_border(int n, int *list, double *buf, + int pbc_flag, int *pbc) +{ + int i,j,m; + double dx,dy,dz; + + m = 0; + if (pbc_flag == 0) { + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0]; + buf[m++] = x[j][1]; + buf[m++] = x[j][2]; + buf[m++] = ubuf(tag[j]).d; + buf[m++] = ubuf(type[j]).d; + buf[m++] = ubuf(mask[j]).d; + buf[m++] = q[j]; + buf[m++] = lambdaH[j]; + buf[m++] = gradlambdaH[j][0]; + buf[m++] = gradlambdaH[j][1]; + buf[m++] = gradlambdaH[j][2]; + buf[m++] = comH[j][0]; + buf[m++] = comH[j][1]; + buf[m++] = comH[j][2]; + + buf[m++] = ubuf(replambdaH[j]).d; + buf[m++] = ubuf(moltypeH[j]).d; + + buf[m++] = ubuf(molecule[j]).d; + } + } else { + if (domain->triclinic == 0) { + dx = pbc[0]*domain->xprd; + dy = pbc[1]*domain->yprd; + dz = pbc[2]*domain->zprd; + } else { + dx = pbc[0]; + dy = pbc[1]; + dz = pbc[2]; + } + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0] + dx; + buf[m++] = x[j][1] + dy; + buf[m++] = x[j][2] + dz; + buf[m++] = ubuf(tag[j]).d; + buf[m++] = ubuf(type[j]).d; + buf[m++] = ubuf(mask[j]).d; + buf[m++] = q[j]; + buf[m++] = lambdaH[j]; + buf[m++] = gradlambdaH[j][0]; + buf[m++] = gradlambdaH[j][1]; + buf[m++] = gradlambdaH[j][2]; + buf[m++] = comH[j][0]; + buf[m++] = comH[j][1]; + buf[m++] = comH[j][2]; + + buf[m++] = ubuf(replambdaH[j]).d; + buf[m++] = ubuf(moltypeH[j]).d; + + buf[m++] = ubuf(molecule[j]).d; + } + } + + if (atom->nextra_border) + for (int iextra = 0; iextra < atom->nextra_border; iextra++) + m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); + + return m; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecFullHars::pack_border_vel(int n, int *list, double *buf, + int pbc_flag, int *pbc) +{ + int i,j,m; + double dx,dy,dz,dvx,dvy,dvz; + + m = 0; + if (pbc_flag == 0) { + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0]; + buf[m++] = x[j][1]; + buf[m++] = x[j][2]; + buf[m++] = ubuf(tag[j]).d; + buf[m++] = ubuf(type[j]).d; + buf[m++] = ubuf(mask[j]).d; + buf[m++] = q[j]; + buf[m++] = lambdaH[j]; + buf[m++] = gradlambdaH[j][0]; + buf[m++] = gradlambdaH[j][1]; + buf[m++] = gradlambdaH[j][2]; + buf[m++] = comH[j][0]; + buf[m++] = comH[j][1]; + buf[m++] = comH[j][2]; + + buf[m++] = ubuf(replambdaH[j]).d; + buf[m++] = ubuf(moltypeH[j]).d; + + buf[m++] = ubuf(molecule[j]).d; + buf[m++] = v[j][0]; + buf[m++] = v[j][1]; + buf[m++] = v[j][2]; + } + } else { + if (domain->triclinic == 0) { + dx = pbc[0]*domain->xprd; + dy = pbc[1]*domain->yprd; + dz = pbc[2]*domain->zprd; + } else { + dx = pbc[0]; + dy = pbc[1]; + dz = pbc[2]; + } + if (!deform_vremap) { + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0] + dx; + buf[m++] = x[j][1] + dy; + buf[m++] = x[j][2] + dz; + buf[m++] = ubuf(tag[j]).d; + buf[m++] = ubuf(type[j]).d; + buf[m++] = ubuf(mask[j]).d; + buf[m++] = q[j]; + buf[m++] = lambdaH[j]; + buf[m++] = gradlambdaH[j][0]; + buf[m++] = gradlambdaH[j][1]; + buf[m++] = gradlambdaH[j][2]; + buf[m++] = comH[j][0]; + buf[m++] = comH[j][1]; + buf[m++] = comH[j][2]; + + buf[m++] = ubuf(replambdaH[j]).d; + buf[m++] = ubuf(moltypeH[j]).d; + + buf[m++] = ubuf(molecule[j]).d; + buf[m++] = v[j][0]; + buf[m++] = v[j][1]; + buf[m++] = v[j][2]; + } + } else { + dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; + dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; + dvz = pbc[2]*h_rate[2]; + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0] + dx; + buf[m++] = x[j][1] + dy; + buf[m++] = x[j][2] + dz; + buf[m++] = ubuf(tag[j]).d; + buf[m++] = ubuf(type[j]).d; + buf[m++] = ubuf(mask[j]).d; + buf[m++] = q[j]; + buf[m++] = lambdaH[j]; + buf[m++] = gradlambdaH[j][0]; + buf[m++] = gradlambdaH[j][1]; + buf[m++] = gradlambdaH[j][2]; + buf[m++] = comH[j][0]; + buf[m++] = comH[j][1]; + buf[m++] = comH[j][2]; + + buf[m++] = ubuf(replambdaH[j]).d; + buf[m++] = ubuf(moltypeH[j]).d; + + buf[m++] = ubuf(molecule[j]).d; + if (mask[i] & deform_groupbit) { + buf[m++] = v[j][0] + dvx; + buf[m++] = v[j][1] + dvy; + buf[m++] = v[j][2] + dvz; + } else { + buf[m++] = v[j][0]; + buf[m++] = v[j][1]; + buf[m++] = v[j][2]; + } + } + } + } + + if (atom->nextra_border) + for (int iextra = 0; iextra < atom->nextra_border; iextra++) + m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); + + return m; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecFullHars::pack_border_hybrid(int n, int *list, double *buf) +{ + int i,j,m; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = q[j]; + buf[m++] = ubuf(replambdaH[j]).d; + buf[m++] = ubuf(moltypeH[j]).d; + buf[m++] = ubuf(molecule[j]).d; + } + return m; +} + +/* ---------------------------------------------------------------------- */ + +void AtomVecFullHars::unpack_border(int n, int first, double *buf) +{ + int i,m,last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + if (i == nmax) grow(0); + x[i][0] = buf[m++]; + x[i][1] = buf[m++]; + x[i][2] = buf[m++]; + tag[i] = (tagint) ubuf(buf[m++]).i; + type[i] = (int) ubuf(buf[m++]).i; + mask[i] = (int) ubuf(buf[m++]).i; + q[i] = buf[m++]; + lambdaH[i] = buf[m++]; + gradlambdaH[i][0] = buf[m++]; + gradlambdaH[i][1] = buf[m++]; + gradlambdaH[i][2] = buf[m++]; + comH[i][0] = buf[m++]; + comH[i][1] = buf[m++]; + comH[i][2] = buf[m++]; + + replambdaH[i] = (int) ubuf(buf[m++]).i; + moltypeH[i] = (int) ubuf(buf[m++]).i; + + molecule[i] = (tagint) ubuf(buf[m++]).i; + + } + + if (atom->nextra_border) + for (int iextra = 0; iextra < atom->nextra_border; iextra++) + m += modify->fix[atom->extra_border[iextra]]-> + unpack_border(n,first,&buf[m]); +} + +/* ---------------------------------------------------------------------- */ + +void AtomVecFullHars::unpack_border_vel(int n, int first, double *buf) +{ + int i,m,last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + if (i == nmax) grow(0); + x[i][0] = buf[m++]; + x[i][1] = buf[m++]; + x[i][2] = buf[m++]; + tag[i] = (tagint) ubuf(buf[m++]).i; + type[i] = (int) ubuf(buf[m++]).i; + mask[i] = (int) ubuf(buf[m++]).i; + q[i] = buf[m++]; + lambdaH[i] = buf[m++]; + gradlambdaH[i][0] = buf[m++]; + gradlambdaH[i][1] = buf[m++]; + gradlambdaH[i][2] = buf[m++]; + comH[i][0] = buf[m++]; + comH[i][1] = buf[m++]; + comH[i][2] = buf[m++]; + + replambdaH[i] = (int) ubuf(buf[m++]).i; + moltypeH[i] = (int) ubuf(buf[m++]).i; + + molecule[i] = (tagint) ubuf(buf[m++]).i; + v[i][0] = buf[m++]; + v[i][1] = buf[m++]; + v[i][2] = buf[m++]; + } + + if (atom->nextra_border) + for (int iextra = 0; iextra < atom->nextra_border; iextra++) + m += modify->fix[atom->extra_border[iextra]]-> + unpack_border(n,first,&buf[m]); +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecFullHars::unpack_border_hybrid(int n, int first, double *buf) +{ + int i,m,last; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + q[i] = buf[m++]; + replambdaH[i] = (int) ubuf(buf[m++]).i; + moltypeH[i] = (int) ubuf(buf[m++]).i; + molecule[i] = (tagint) ubuf(buf[m++]).i; + } + return m; +} + +/* ---------------------------------------------------------------------- + pack data for atom I for sending to another proc + xyz must be 1st 3 values, so comm::exchange() can test on them +------------------------------------------------------------------------- */ + +int AtomVecFullHars::pack_exchange(int i, double *buf) +{ + int k; + + int m = 1; + buf[m++] = x[i][0]; + buf[m++] = x[i][1]; + buf[m++] = x[i][2]; + buf[m++] = v[i][0]; + buf[m++] = v[i][1]; + buf[m++] = v[i][2]; + buf[m++] = ubuf(tag[i]).d; + buf[m++] = ubuf(type[i]).d; + buf[m++] = ubuf(mask[i]).d; + buf[m++] = ubuf(image[i]).d; + + buf[m++] = q[i]; + buf[m++] = lambdaH[i]; + buf[m++] = gradlambdaH[i][0]; + buf[m++] = gradlambdaH[i][1]; + buf[m++] = gradlambdaH[i][2]; + buf[m++] = comH[i][0]; + buf[m++] = comH[i][1]; + buf[m++] = comH[i][2]; + + buf[m++] = ubuf(replambdaH[i]).d; + buf[m++] = ubuf(moltypeH[i]).d; + + buf[m++] = ubuf(molecule[i]).d; + + buf[m++] = ubuf(num_bond[i]).d; + for (k = 0; k < num_bond[i]; k++) { + buf[m++] = ubuf(bond_type[i][k]).d; + buf[m++] = ubuf(bond_atom[i][k]).d; + } + + buf[m++] = ubuf(num_angle[i]).d; + for (k = 0; k < num_angle[i]; k++) { + buf[m++] = ubuf(angle_type[i][k]).d; + buf[m++] = ubuf(angle_atom1[i][k]).d; + buf[m++] = ubuf(angle_atom2[i][k]).d; + buf[m++] = ubuf(angle_atom3[i][k]).d; + } + + buf[m++] = ubuf(num_dihedral[i]).d; + for (k = 0; k < num_dihedral[i]; k++) { + buf[m++] = ubuf(dihedral_type[i][k]).d; + buf[m++] = ubuf(dihedral_atom1[i][k]).d; + buf[m++] = ubuf(dihedral_atom2[i][k]).d; + buf[m++] = ubuf(dihedral_atom3[i][k]).d; + buf[m++] = ubuf(dihedral_atom4[i][k]).d; + } + + buf[m++] = ubuf(num_improper[i]).d; + for (k = 0; k < num_improper[i]; k++) { + buf[m++] = ubuf(improper_type[i][k]).d; + buf[m++] = ubuf(improper_atom1[i][k]).d; + buf[m++] = ubuf(improper_atom2[i][k]).d; + buf[m++] = ubuf(improper_atom3[i][k]).d; + buf[m++] = ubuf(improper_atom4[i][k]).d; + } + + buf[m++] = ubuf(nspecial[i][0]).d; + buf[m++] = ubuf(nspecial[i][1]).d; + buf[m++] = ubuf(nspecial[i][2]).d; + for (k = 0; k < nspecial[i][2]; k++) buf[m++] = ubuf(special[i][k]).d; + + if (atom->nextra_grow) + for (int iextra = 0; iextra < atom->nextra_grow; iextra++) + m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); + + buf[0] = m; + return m; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecFullHars::unpack_exchange(double *buf) +{ + int k; + + int nlocal = atom->nlocal; + if (nlocal == nmax) grow(0); + + int m = 1; + x[nlocal][0] = buf[m++]; + x[nlocal][1] = buf[m++]; + x[nlocal][2] = buf[m++]; + v[nlocal][0] = buf[m++]; + v[nlocal][1] = buf[m++]; + v[nlocal][2] = buf[m++]; + tag[nlocal] = (tagint) ubuf(buf[m++]).i; + type[nlocal] = (int) ubuf(buf[m++]).i; + mask[nlocal] = (int) ubuf(buf[m++]).i; + image[nlocal] = (imageint) ubuf(buf[m++]).i; + + q[nlocal] = buf[m++]; + lambdaH[nlocal] = buf[m++]; + gradlambdaH[nlocal][0] = buf[m++]; + gradlambdaH[nlocal][1] = buf[m++]; + gradlambdaH[nlocal][2] = buf[m++]; + comH[nlocal][0] = buf[m++]; + comH[nlocal][1] = buf[m++]; + comH[nlocal][2] = buf[m++]; + + replambdaH[nlocal] = (int) ubuf(buf[m++]).i; + moltypeH[nlocal] = (int) ubuf(buf[m++]).i; + + molecule[nlocal] = (tagint) ubuf(buf[m++]).i; + + num_bond[nlocal] = (int) ubuf(buf[m++]).i; + for (k = 0; k < num_bond[nlocal]; k++) { + bond_type[nlocal][k] = (int) ubuf(buf[m++]).i; + bond_atom[nlocal][k] = (tagint) ubuf(buf[m++]).i; + } + + num_angle[nlocal] = (int) ubuf(buf[m++]).i; + for (k = 0; k < num_angle[nlocal]; k++) { + angle_type[nlocal][k] = (int) ubuf(buf[m++]).i; + angle_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; + angle_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; + angle_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; + } + + num_dihedral[nlocal] = (int) ubuf(buf[m++]).i; + for (k = 0; k < num_dihedral[nlocal]; k++) { + dihedral_type[nlocal][k] = (int) ubuf(buf[m++]).i; + dihedral_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; + dihedral_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; + dihedral_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; + dihedral_atom4[nlocal][k] = (tagint) ubuf(buf[m++]).i; + } + + num_improper[nlocal] = (int) ubuf(buf[m++]).i; + for (k = 0; k < num_improper[nlocal]; k++) { + improper_type[nlocal][k] = (int) ubuf(buf[m++]).i; + improper_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; + improper_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; + improper_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; + improper_atom4[nlocal][k] = (tagint) ubuf(buf[m++]).i; + } + + nspecial[nlocal][0] = (int) ubuf(buf[m++]).i; + nspecial[nlocal][1] = (int) ubuf(buf[m++]).i; + nspecial[nlocal][2] = (int) ubuf(buf[m++]).i; + for (k = 0; k < nspecial[nlocal][2]; k++) + special[nlocal][k] = (tagint) ubuf(buf[m++]).i; + + if (atom->nextra_grow) + for (int iextra = 0; iextra < atom->nextra_grow; iextra++) + m += modify->fix[atom->extra_grow[iextra]]-> + unpack_exchange(nlocal,&buf[m]); + + atom->nlocal++; + return m; +} + +/* ---------------------------------------------------------------------- + size of restart data for all atoms owned by this proc + include extra data stored by fixes +------------------------------------------------------------------------- */ + +int AtomVecFullHars::size_restart() +{ + int i; + + int nlocal = atom->nlocal; + int n = 0; + for (i = 0; i < nlocal; i++) + n += 17 + 2*num_bond[i] + 4*num_angle[i] + + 5*num_dihedral[i] + 5*num_improper[i]+9; + + if (atom->nextra_restart) + for (int iextra = 0; iextra < atom->nextra_restart; iextra++) + for (i = 0; i < nlocal; i++) + n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); + + return n; +} + +/* ---------------------------------------------------------------------- + pack atom I's data for restart file including extra quantities + xyz must be 1st 3 values, so that read_restart can test on them + molecular types may be negative, but write as positive +------------------------------------------------------------------------- */ + +int AtomVecFullHars::pack_restart(int i, double *buf) +{ + int k; + + int m = 1; + buf[m++] = x[i][0]; + buf[m++] = x[i][1]; + buf[m++] = x[i][2]; + buf[m++] = ubuf(tag[i]).d; + buf[m++] = ubuf(type[i]).d; + buf[m++] = ubuf(mask[i]).d; + buf[m++] = ubuf(image[i]).d; + buf[m++] = v[i][0]; + buf[m++] = v[i][1]; + buf[m++] = v[i][2]; + + buf[m++] = q[i]; + buf[m++] = lambdaH[i]; + buf[m++] = gradlambdaH[i][0]; + buf[m++] = gradlambdaH[i][1]; + buf[m++] = gradlambdaH[i][2]; + buf[m++] = comH[i][0]; + buf[m++] = comH[i][1]; + buf[m++] = comH[i][2]; + + buf[m++] = ubuf(replambdaH[i]).d; + buf[m++] = ubuf(moltypeH[i]).d; + buf[m++] = ubuf(molecule[i]).d; + + buf[m++] = ubuf(num_bond[i]).d; + for (k = 0; k < num_bond[i]; k++) { + buf[m++] = ubuf(MAX(bond_type[i][k],-bond_type[i][k])).d; + buf[m++] = ubuf(bond_atom[i][k]).d; + } + + buf[m++] = ubuf(num_angle[i]).d; + for (k = 0; k < num_angle[i]; k++) { + buf[m++] = ubuf(MAX(angle_type[i][k],-angle_type[i][k])).d; + buf[m++] = ubuf(angle_atom1[i][k]).d; + buf[m++] = ubuf(angle_atom2[i][k]).d; + buf[m++] = ubuf(angle_atom3[i][k]).d; + } + + buf[m++] = ubuf(num_dihedral[i]).d; + for (k = 0; k < num_dihedral[i]; k++) { + buf[m++] = ubuf(MAX(dihedral_type[i][k],-dihedral_type[i][k])).d; + buf[m++] = ubuf(dihedral_atom1[i][k]).d; + buf[m++] = ubuf(dihedral_atom2[i][k]).d; + buf[m++] = ubuf(dihedral_atom3[i][k]).d; + buf[m++] = ubuf(dihedral_atom4[i][k]).d; + } + + buf[m++] = ubuf(num_improper[i]).d; + for (k = 0; k < num_improper[i]; k++) { + buf[m++] = ubuf(MAX(improper_type[i][k],-improper_type[i][k])).d; + buf[m++] = ubuf(improper_atom1[i][k]).d; + buf[m++] = ubuf(improper_atom2[i][k]).d; + buf[m++] = ubuf(improper_atom3[i][k]).d; + buf[m++] = ubuf(improper_atom4[i][k]).d; + } + + if (atom->nextra_restart) + for (int iextra = 0; iextra < atom->nextra_restart; iextra++) + m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); + + buf[0] = m; + return m; +} + +/* ---------------------------------------------------------------------- + unpack data for one atom from restart file including extra quantities +------------------------------------------------------------------------- */ + +int AtomVecFullHars::unpack_restart(double *buf) +{ + int k; + + int nlocal = atom->nlocal; + if (nlocal == nmax) { + grow(0); + if (atom->nextra_store) + memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); + } + + int m = 1; + x[nlocal][0] = buf[m++]; + x[nlocal][1] = buf[m++]; + x[nlocal][2] = buf[m++]; + tag[nlocal] = (tagint) ubuf(buf[m++]).i; + type[nlocal] = (int) ubuf(buf[m++]).i; + mask[nlocal] = (int) ubuf(buf[m++]).i; + image[nlocal] = (imageint) ubuf(buf[m++]).i; + v[nlocal][0] = buf[m++]; + v[nlocal][1] = buf[m++]; + v[nlocal][2] = buf[m++]; + + q[nlocal] = buf[m++]; + lambdaH[nlocal] = buf[m++]; + gradlambdaH[nlocal][0] = buf[m++]; + gradlambdaH[nlocal][1] = buf[m++]; + gradlambdaH[nlocal][2] = buf[m++]; + comH[nlocal][0] = buf[m++]; + comH[nlocal][1] = buf[m++]; + comH[nlocal][2] = buf[m++]; + replambdaH[nlocal] = (int) ubuf(buf[m++]).i; + moltypeH[nlocal] = (int) ubuf(buf[m++]).i; + + molecule[nlocal] = (tagint) ubuf(buf[m++]).i; + + num_bond[nlocal] = (int) ubuf(buf[m++]).i; + for (k = 0; k < num_bond[nlocal]; k++) { + bond_type[nlocal][k] = (int) ubuf(buf[m++]).i; + bond_atom[nlocal][k] = (tagint) ubuf(buf[m++]).i; + } + + num_angle[nlocal] = (int) ubuf(buf[m++]).i; + for (k = 0; k < num_angle[nlocal]; k++) { + angle_type[nlocal][k] = (int) ubuf(buf[m++]).i; + angle_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; + angle_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; + angle_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; + } + + num_dihedral[nlocal] = (int) ubuf(buf[m++]).i; + for (k = 0; k < num_dihedral[nlocal]; k++) { + dihedral_type[nlocal][k] = (int) ubuf(buf[m++]).i; + dihedral_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; + dihedral_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; + dihedral_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; + dihedral_atom4[nlocal][k] = (tagint) ubuf(buf[m++]).i; + } + + num_improper[nlocal] = (int) ubuf(buf[m++]).i; + for (k = 0; k < num_improper[nlocal]; k++) { + improper_type[nlocal][k] = (int) ubuf(buf[m++]).i; + improper_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; + improper_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; + improper_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; + improper_atom4[nlocal][k] = (tagint) ubuf(buf[m++]).i; + } + + nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0; + + double **extra = atom->extra; + if (atom->nextra_store) { + int size = static_cast<int> (buf[0]) - m; + for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; + } + + atom->nlocal++; + return m; +} + +/* ---------------------------------------------------------------------- + create one atom of itype at coord + set other values to defaults +------------------------------------------------------------------------- */ + +void AtomVecFullHars::create_atom(int itype, double *coord) +{ + int nlocal = atom->nlocal; + if (nlocal == nmax) grow(0); + + tag[nlocal] = 0; + type[nlocal] = itype; + x[nlocal][0] = coord[0]; + x[nlocal][1] = coord[1]; + x[nlocal][2] = coord[2]; + mask[nlocal] = 1; + image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | + ((imageint) IMGMAX << IMGBITS) | IMGMAX; + v[nlocal][0] = 0.0; + v[nlocal][1] = 0.0; + v[nlocal][2] = 0.0; + + q[nlocal] = 0.0; + lambdaH[nlocal] = 0.0; + gradlambdaH[nlocal][0] = 0.0; + gradlambdaH[nlocal][1] = 0.0; + gradlambdaH[nlocal][2] = 0.0; + comH[nlocal][0] = 0; + comH[nlocal][1] = 0; + comH[nlocal][2] = 0; + + replambdaH[nlocal] = 0; + moltypeH[nlocal] = 0; + + molecule[nlocal] = 0; + num_bond[nlocal] = 0; + num_angle[nlocal] = 0; + num_dihedral[nlocal] = 0; + num_improper[nlocal] = 0; + nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0; + + atom->nlocal++; +} + +/* ---------------------------------------------------------------------- + unpack one line from Atoms section of data file + initialize other atom quantities +------------------------------------------------------------------------- */ + +void AtomVecFullHars::data_atom(double *coord, imageint imagetmp, char **values) +{ + int nlocal = atom->nlocal; + if (nlocal == nmax) grow(0); + + tag[nlocal] = ATOTAGINT(values[0]); + molecule[nlocal] = ATOTAGINT(values[1]); + type[nlocal] = atoi(values[2]); + if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) + error->one(FLERR,"Invalid atom type in Atoms section of data file"); + + q[nlocal] = atof(values[3]); + replambdaH[nlocal] = atoi(values[4]); + moltypeH[nlocal] = atoi(values[5]); + + + x[nlocal][0] = coord[0]; + x[nlocal][1] = coord[1]; + x[nlocal][2] = coord[2]; + + comH[nlocal][0] = 0; + comH[nlocal][1] = 0; + comH[nlocal][2] = 0; + + image[nlocal] = imagetmp; + + mask[nlocal] = 1; + v[nlocal][0] = 0.0; + v[nlocal][1] = 0.0; + v[nlocal][2] = 0.0; + num_bond[nlocal] = 0; + num_angle[nlocal] = 0; + num_dihedral[nlocal] = 0; + num_improper[nlocal] = 0; + + atom->nlocal++; +} + +/* ---------------------------------------------------------------------- + unpack hybrid quantities from one line in Atoms section of data file + initialize other atom quantities for this sub-style +------------------------------------------------------------------------- */ + +int AtomVecFullHars::data_atom_hybrid(int nlocal, char **values) +{ + molecule[nlocal] = ATOTAGINT(values[0]); + q[nlocal] = atof(values[1]); + replambdaH[nlocal] = atoi(values[2]); + moltypeH[nlocal] = atoi(values[3]); + + num_bond[nlocal] = 0; + num_angle[nlocal] = 0; + num_dihedral[nlocal] = 0; + num_improper[nlocal] = 0; + + return 2; +} + +/* ---------------------------------------------------------------------- + pack atom info for data file including 3 image flags +------------------------------------------------------------------------- */ + +void AtomVecFullHars::pack_data(double **buf) +{ + int nlocal = atom->nlocal; + for (int i = 0; i < nlocal; i++) { + buf[i][0] = ubuf(tag[i]).d; + buf[i][1] = ubuf(molecule[i]).d; + buf[i][2] = ubuf(type[i]).d; + buf[i][3] = q[i]; + buf[i][4] = ubuf(replambdaH[i]).d; + buf[i][5] = ubuf(moltypeH[i]).d; + + buf[i][6] = x[i][0]; + buf[i][7] = x[i][1]; + buf[i][8] = x[i][2]; + buf[i][9] = ubuf((image[i] & IMGMASK) - IMGMAX).d; + buf[i][10] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; + buf[i][11] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; + } +} + +/* ---------------------------------------------------------------------- + pack hybrid atom info for data file +------------------------------------------------------------------------- */ + +int AtomVecFullHars::pack_data_hybrid(int i, double *buf) +{ + buf[0] = ubuf(molecule[i]).d; + buf[1] = q[i]; + buf[2] = ubuf(replambdaH[i]).d; + buf[3] = ubuf(moltypeH[i]).d; + + return 2; +} + +/* ---------------------------------------------------------------------- + write atom info to data file including 3 image flags +------------------------------------------------------------------------- */ + +void AtomVecFullHars::write_data(FILE *fp, int n, double **buf) +{ + for (int i = 0; i < n; i++) + fprintf(fp,TAGINT_FORMAT " " TAGINT_FORMAT + " %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n", + (tagint) ubuf(buf[i][0]).i,(tagint) ubuf(buf[i][1]).i, + (int) ubuf(buf[i][2]).i, + buf[i][3],buf[i][4],buf[i][5],buf[i][6], + (int) ubuf(buf[i][7]).i,(int) ubuf(buf[i][8]).i, + (int) ubuf(buf[i][9]).i); +} + +/* ---------------------------------------------------------------------- + write hybrid atom info to data file +------------------------------------------------------------------------- */ + +int AtomVecFullHars::write_data_hybrid(FILE *fp, double *buf) +{ + fprintf(fp," " TAGINT_FORMAT " %-1.16e",(tagint) ubuf(buf[0]).i,buf[1]); + return 2; +} + +/* ---------------------------------------------------------------------- + return # of bytes of allocated memory +------------------------------------------------------------------------- */ + +bigint AtomVecFullHars::memory_usage() +{ + bigint bytes = 0; + + if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); + if (atom->memcheck("type")) bytes += memory->usage(type,nmax); + if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); + if (atom->memcheck("image")) bytes += memory->usage(image,nmax); + if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); + if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); + if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); + + if (atom->memcheck("q")) bytes += memory->usage(q,nmax); + if (atom->memcheck("lambdaH")) bytes += memory->usage(lambdaH,nmax); + if (atom->memcheck("gradlambdaH")) bytes += memory->usage(gradlambdaH,nmax,3); + if (atom->memcheck("replambdaH")) bytes += memory->usage(replambdaH,nmax); + if (atom->memcheck("moltypeH")) bytes += memory->usage(moltypeH,nmax); + + if (atom->memcheck("comH")) bytes += memory->usage(comH,nmax,3); + + + if (atom->memcheck("molecule")) bytes += memory->usage(molecule,nmax); + if (atom->memcheck("nspecial")) bytes += memory->usage(nspecial,nmax,3); + if (atom->memcheck("special")) + bytes += memory->usage(special,nmax,atom->maxspecial); + + if (atom->memcheck("num_bond")) bytes += memory->usage(num_bond,nmax); + if (atom->memcheck("bond_type")) + bytes += memory->usage(bond_type,nmax,atom->bond_per_atom); + if (atom->memcheck("bond_atom")) + bytes += memory->usage(bond_atom,nmax,atom->bond_per_atom); + + if (atom->memcheck("num_angle")) bytes += memory->usage(num_angle,nmax); + if (atom->memcheck("angle_type")) + bytes += memory->usage(angle_type,nmax,atom->angle_per_atom); + if (atom->memcheck("angle_atom1")) + bytes += memory->usage(angle_atom1,nmax,atom->angle_per_atom); + if (atom->memcheck("angle_atom2")) + bytes += memory->usage(angle_atom2,nmax,atom->angle_per_atom); + if (atom->memcheck("angle_atom3")) + bytes += memory->usage(angle_atom3,nmax,atom->angle_per_atom); + + if (atom->memcheck("num_dihedral")) bytes += memory->usage(num_dihedral,nmax); + if (atom->memcheck("dihedral_type")) + bytes += memory->usage(dihedral_type,nmax,atom->dihedral_per_atom); + if (atom->memcheck("dihedral_atom1")) + bytes += memory->usage(dihedral_atom1,nmax,atom->dihedral_per_atom); + if (atom->memcheck("dihedral_atom2")) + bytes += memory->usage(dihedral_atom2,nmax,atom->dihedral_per_atom); + if (atom->memcheck("dihedral_atom3")) + bytes += memory->usage(dihedral_atom3,nmax,atom->dihedral_per_atom); + if (atom->memcheck("dihedral_atom4")) + bytes += memory->usage(dihedral_atom4,nmax,atom->dihedral_per_atom); + + if (atom->memcheck("num_improper")) bytes += memory->usage(num_improper,nmax); + if (atom->memcheck("improper_type")) + bytes += memory->usage(improper_type,nmax,atom->improper_per_atom); + if (atom->memcheck("improper_atom1")) + bytes += memory->usage(improper_atom1,nmax,atom->improper_per_atom); + if (atom->memcheck("improper_atom2")) + bytes += memory->usage(improper_atom2,nmax,atom->improper_per_atom); + if (atom->memcheck("improper_atom3")) + bytes += memory->usage(improper_atom3,nmax,atom->improper_per_atom); + if (atom->memcheck("improper_atom4")) + bytes += memory->usage(improper_atom4,nmax,atom->improper_per_atom); + + return bytes; +} diff --git a/src/USER-HADRESS/atom_vec_full_hars.h b/src/USER-HADRESS/atom_vec_full_hars.h new file mode 100644 index 000000000..59bac9a3b --- /dev/null +++ b/src/USER-HADRESS/atom_vec_full_hars.h @@ -0,0 +1,104 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef ATOM_CLASS + +AtomStyle(full/hars,AtomVecFullHars) + +#else + +#ifndef LMP_ATOM_VEC_FULL_HARS_H +#define LMP_ATOM_VEC_FULL_HARS_H + +#include "atom_vec.h" + +namespace LAMMPS_NS { + +class AtomVecFullHars : public AtomVec { + public: + AtomVecFullHars(class LAMMPS *); + virtual ~AtomVecFullHars() {} + void grow(int); + void grow_reset(); + void copy(int, int, int); + virtual int pack_comm(int, int *, double *, int, int *); + virtual int pack_comm_vel(int, int *, double *, int, int *); + virtual void unpack_comm(int, int, double *); + virtual void unpack_comm_vel(int, int, double *); + int pack_reverse(int, int, double *); + void unpack_reverse(int, int *, double *); + virtual int pack_border(int, int *, double *, int, int *); + virtual int pack_border_vel(int, int *, double *, int, int *); + int pack_border_hybrid(int, int *, double *); + virtual void unpack_border(int, int, double *); + virtual void unpack_border_vel(int, int, double *); + int unpack_border_hybrid(int, int, double *); + virtual int pack_exchange(int, double *); + virtual int unpack_exchange(double *); + int size_restart(); + int pack_restart(int, double *); + int unpack_restart(double *); + void create_atom(int, double *); + void data_atom(double *, imageint, char **); + int data_atom_hybrid(int, char **); + void pack_data(double **); + int pack_data_hybrid(int, double *); + void write_data(FILE *, int, double **); + int write_data_hybrid(FILE *, double *); + bigint memory_usage(); + + protected: + tagint *tag; + int *type,*mask; + imageint *image; + double **x,**v,**f; + double *q; + double *lambdaH; + double **gradlambdaH; + int *replambdaH; + int *moltypeH; + double **comH; + tagint *molecule; + int **nspecial; + tagint **special; + int *num_bond; + int **bond_type; + tagint **bond_atom; + int *num_angle; + int **angle_type; + tagint **angle_atom1,**angle_atom2,**angle_atom3; + int *num_dihedral; + int **dihedral_type; + tagint **dihedral_atom1,**dihedral_atom2,**dihedral_atom3,**dihedral_atom4; + int *num_improper; + int **improper_type; + tagint **improper_atom1,**improper_atom2,**improper_atom3,**improper_atom4; +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + +E: Per-processor system is too big + +The number of owned atoms plus ghost atoms on a single +processor must fit in 32-bit integer. + +E: Invalid atom type in Atoms section of data file + +Atom types must range from 1 to specified # of types. + +*/ diff --git a/src/USER-HADRESS/fix_lambdah_calc.cpp b/src/USER-HADRESS/fix_lambdah_calc.cpp new file mode 100644 index 000000000..17d84032d --- /dev/null +++ b/src/USER-HADRESS/fix_lambdah_calc.cpp @@ -0,0 +1,958 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Maziar Heidari (Max Planck Institute for Polymer Research) +------------------------------------------------------------------------- */ + +#include "math.h" +#include "string.h" +#include "stdlib.h" +#include "fix_lambdah_calc.h" +#include "atom.h" +#include "input.h" +#include "variable.h" +#include "domain.h" +#include "lattice.h" +#include "update.h" +#include "modify.h" +#include "output.h" +#include "respa.h" +#include "error.h" +#include "force.h" +#include "math_const.h" +#include "memory.h" +#include "comm.h" +#include "citeme.h" + + +using namespace LAMMPS_NS; +using namespace FixConst; +using namespace MathConst; + +#define BIG MAXTAGINT + +static const char cite_HAdResS[] = + "@Article{Heidari et al.2016\n" + " author = {M. Heidari, R. Cortes-Huerto, D. Donadio and R. Potestio},\n" + " title = {Accurate and general treatment of electrostatic interaction in Hamiltonian adaptive resolution simulations},\n" + " journal = {Eur. Phys. J. Special Topics},\n" + " year = 2016,\n" + " volume = Submitted,\n" + " pages = {}\n" + "}\n\n"; + + +/* ---------------------------------------------------------------------- */ + +FixLambdaHCalc::FixLambdaHCalc(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg) +{ + + + if (lmp->citeme) lmp->citeme->add(cite_HAdResS); + + massproc_H = NULL; + masstotal_H = NULL; + com_H = NULL; + comall_H = NULL; + molmap_H = NULL; + lambdaCM = NULL; + gradlambdaCM = NULL; + Comp_Density_Num_H = NULL; + Comp_Density_Num_all_H = NULL; + Mean_Density_H = NULL; + Int_Mean_Density_H = NULL; + Mean_Comp_Density_Conv_H = NULL; + grad_Comp_Density_Conv_H = NULL; + Mean_grad_Comp_Density_Conv_H = NULL; + + + + me = comm->me; + + if (narg < 8) error->all(FLERR,"Illegal fix LambdaH/Calc command"); + + atom->nmoltypesH = force->numeric(FLERR,arg[3]); + Length_Hyb = force->numeric(FLERR,arg[4]); + Length_ATRegion = force->numeric(FLERR,arg[5]); + Pressure_Comp_Flag = force->numeric(FLERR,arg[6]); + Pressure_lambda_Increment = force->numeric(FLERR,arg[7]); + Pressure_Update_Frequency = force->numeric(FLERR,arg[8]); + Pressure_Update_Time_Begin = force->numeric(FLERR,arg[9]); + Pressure_Update_Time_End = force->numeric(FLERR,arg[10]); + + if (strcmp(arg[11],"slab") == 0) Hybrid_Style = 0; + else if (strcmp(arg[11],"sphere") == 0) Hybrid_Style = 1; + else if (strcmp(arg[11],"cylinder") == 0) Hybrid_Style = 2; + else error->all(FLERR,"Illegal fix LambdaH/Calc command"); + + Density_Comp_Flag = force->numeric(FLERR,arg[12]); + Density_Bin_Size = force->numeric(FLERR,arg[13]); + Density_Update_Frequency = force->numeric(FLERR,arg[14]); + Density_Update_Time_Begin = force->numeric(FLERR,arg[15]); + Density_Update_Time_End = force->numeric(FLERR,arg[16]); + Density_Sigma_Gauss = force->numeric(FLERR,arg[17]); + Density_Gauss_Int_Range = force->numeric(FLERR,arg[18]); + Density_Ref = force->numeric(FLERR,arg[19]); + Comp_Density_Scaling_factor_H = force->numeric(FLERR,arg[20]); + Load_File_Flag = force->numeric(FLERR,arg[21]); + + x0lo = domain->boxlo[0]; + x0hi = domain->boxhi[0]; + x1lo = domain->boxlo[1]; + x1hi = domain->boxhi[1]; + x2lo = domain->boxlo[2]; + x2hi = domain->boxhi[2]; + + center_box[0] = (x0hi + x0lo)/2.0; + center_box[1] = (x1hi + x1lo)/2.0; + center_box[2] = (x2hi + x2lo)/2.0; + + + x0BoxSize = x0hi - x0lo; + Length_CGRegion = x0BoxSize - 2*Length_Hyb - Length_ATRegion; + R_Start_Hybrid_1 = x0lo + Length_CGRegion/2.0; + R_Start_Hybrid_2 = x0lo + x0BoxSize - (Length_CGRegion/2.0 + Length_Hyb); + S_Start_Hybrid = Length_ATRegion; + Pressure_Bin_Num = 1.0 / Pressure_lambda_Increment; + xmin_AT = R_Start_Hybrid_1 + Length_Hyb; + xmax_AT= R_Start_Hybrid_1 + Length_Hyb + Length_ATRegion; + if(Hybrid_Style==0)Density_Bin_Num = floor(x0BoxSize / Density_Bin_Size); + else if(Hybrid_Style==1)Density_Bin_Num = floor(sqrt(pow(0.5*(x0hi-x0lo),2.0)+pow(0.5*(x1hi-x1lo),2.0)+pow(0.5*(x2hi-x2lo),2.0)) / Density_Bin_Size); + else if(Hybrid_Style==2)Density_Bin_Num = floor(sqrt(pow(0.5*(x0hi-x0lo),2.0)+pow(0.5*(x1hi-x1lo),2.0)) / Density_Bin_Size); + + + Comp_Counter_H = 0; + Density_Counter_H = 0; + Density_Compensation_Run = 0; + + memory->create(Comp_Density_Num_H,Density_Bin_Num,atom->nmoltypesH+1,"lambdaH/calc:Comp_Density_Num_H"); + memory->create(Comp_Density_Num_all_H,Density_Bin_Num,atom->nmoltypesH+1,"lambdaH/calc:Comp_Density_Num_all_H"); + + if(me==0){ + if (screen){ + fprintf(screen,"nmoltypes= %d\n",atom->nmoltypesH); + fprintf(screen,"Length_Hyb= %f\n",Length_Hyb); + fprintf(screen,"Length_ATRegion= %f\n",Length_ATRegion); + fprintf(screen,"Pressure_Comp_Flag= %d\n",Pressure_Comp_Flag); + fprintf(screen,"Pressure_lambda_Increment= %f\n",Pressure_lambda_Increment); + fprintf(screen,"Pressure_Update_Frequency= %d\n",Pressure_Update_Frequency); + fprintf(screen,"Pressure_Update_Time_Begin= %d\n",Pressure_Update_Time_Begin); + fprintf(screen,"Pressure_Update_Time_End= %d\n",Pressure_Update_Time_End); + fprintf(screen,"Density_Comp_Flag= %d\n",Density_Comp_Flag); + fprintf(screen,"Density_Bin_Size= %f\n",Density_Bin_Size); + fprintf(screen,"Density_Update_Frequency= %d\n",Density_Update_Frequency); + fprintf(screen,"Density_Update_Time_Begin= %d\n",Density_Update_Time_Begin); + fprintf(screen,"Density_Update_Time_End= %d\n",Density_Update_Time_End); + fprintf(screen,"Density_Sigma_Gauss= %f\n",Density_Sigma_Gauss); + fprintf(screen,"Density_Gauss_Int_Range= %d\n",Density_Gauss_Int_Range); + fprintf(screen,"Density_Ref= %f\n",Density_Ref); + fprintf(screen,"Comp_Density_Scaling_factor_H = %f\n",Comp_Density_Scaling_factor_H); + fprintf(screen,"Load_File_Flag = %d\n",Load_File_Flag); + fprintf(screen,"Center_box = %f %f %f\n",center_box[0],center_box[1],center_box[2]); + fprintf(screen,"Density_Bin_Size = %f\n",Density_Bin_Size); + fprintf(screen,"Density_Bin_Num = %d\n",Density_Bin_Num); + fprintf(screen,"x0lo= %f\n",x0lo); + fprintf(screen,"x0hi= %f\n",x0hi); + fprintf(screen,"x0BoxSize= %f\n",x0BoxSize); + fprintf(screen,"d1= %f\n",R_Start_Hybrid_1); + fprintf(screen,"d2= %f\n",R_Start_Hybrid_2); + fprintf(screen,"moltype%d\n",atom->nmoltypesH); + + } + if (logfile){ + fprintf(logfile,"nmoltypes= %d\n",atom->nmoltypesH); + fprintf(logfile,"Length_Hyb= %f\n",Length_Hyb); + fprintf(logfile,"Length_ATRegion= %f\n",Length_ATRegion); + fprintf(logfile,"Pressure_Comp_Flag= %d\n",Pressure_Comp_Flag); + fprintf(logfile,"Pressure_lambda_Increment= %f\n",Pressure_lambda_Increment); + fprintf(logfile,"Pressure_Update_Frequency= %d\n",Pressure_Update_Frequency); + fprintf(logfile,"Pressure_Update_Time_Begin= %d\n",Pressure_Update_Time_Begin); + fprintf(logfile,"Pressure_Update_Time_End= %d\n",Pressure_Update_Time_End); + fprintf(logfile,"Density_Comp_Flag= %d\n",Density_Comp_Flag); + fprintf(logfile,"Density_Bin_Size= %f\n",Density_Bin_Size); + fprintf(logfile,"Density_Update_Frequency= %d\n",Density_Update_Frequency); + fprintf(logfile,"Density_Update_Time_Begin= %d\n",Density_Update_Time_Begin); + fprintf(logfile,"Density_Update_Time_End= %d\n",Density_Update_Time_End); + fprintf(logfile,"Density_Sigma_Gauss= %f\n",Density_Sigma_Gauss); + fprintf(logfile,"Density_Gauss_Int_Range= %d\n",Density_Gauss_Int_Range); + fprintf(logfile,"Density_Ref= %f\n",Density_Ref); + fprintf(logfile,"Comp_Density_Scaling_factor_H = %f\n",Comp_Density_Scaling_factor_H); + fprintf(logfile,"Load_File_Flag = %d\n",Load_File_Flag); + fprintf(logfile,"Center_box = %f %f %f\n",center_box[0],center_box[1],center_box[2]); + fprintf(logfile,"Density_Bin_Size = %f\n",Density_Bin_Size); + fprintf(logfile,"Density_Bin_Num = %d\n",Density_Bin_Num); + fprintf(logfile,"x0lo= %f\n",x0lo); + fprintf(logfile,"x0hi= %f\n",x0hi); + fprintf(logfile,"x0BoxSize= %f\n",x0BoxSize); + fprintf(logfile,"d1= %f\n",R_Start_Hybrid_1); + fprintf(logfile,"d2= %f\n",R_Start_Hybrid_2); + fprintf(logfile,"moltype%d\n",atom->nmoltypesH); + + } + } + + memory->create(Int_Mean_Density_H,Density_Bin_Num,atom->nmoltypesH+1,"lambdaH/calc:Int_Mean_Density_H"); + memory->create(Mean_Density_H,Density_Bin_Num,atom->nmoltypesH+1,"lambdaH/calc:Mean_Density_H"); + memory->create(Mean_Comp_Density_Conv_H,Density_Bin_Num,atom->nmoltypesH+1,"lambdaH/calc:Mean_Comp_Density_Conv_H"); + memory->create(grad_Comp_Density_Conv_H,Density_Bin_Num,atom->nmoltypesH+1,"lambdaH/calc:grad_Comp_Density_Conv_H"); + memory->create(Mean_grad_Comp_Density_Conv_H,Density_Bin_Num,atom->nmoltypesH+1,"lambdaH/calc:Mean_grad_Comp_Density_Conv_H"); + + + int This_Step = update->ntimestep; + + for(int i = 0;i < Density_Bin_Num; i++){ + for(int j = 0; j < atom->nmoltypesH; j++){ + Comp_Density_Num_H[i][j] = 0; + Comp_Density_Num_all_H[i][j] = 0; + Int_Mean_Density_H[i][j] = 0; + Mean_Density_H[i][j] = 0; + Mean_Comp_Density_Conv_H[i][j] = 0; + Mean_grad_Comp_Density_Conv_H[i][j] = 0; + grad_Comp_Density_Conv_H[i][j] = 0; + } + } + + if((This_Step >= Density_Update_Time_End || Load_File_Flag) && Density_Comp_Flag != 0)Load_Compensation_Density(); + + if (atom->molecular == 0) + error->all(FLERR,"Compute com/molecule requires molecular atom style"); + + array_flag = 1; + size_array_cols = 3; + extarray = 0; + // setup molecule-based data + nmolecules = molecules_in_group(idlo,idhi); + size_array_rows = nmolecules; + + //printf("Nmolecules= %d\n",nmolecules); + + memory->create(massproc_H,nmolecules,"lambdaH/calc:massproc_H"); + memory->create(masstotal_H,nmolecules,"lambdaH/calc:masstotal_H"); + memory->create(com_H,nmolecules,3,"lambdaH/calc:com_H"); + memory->create(comall_H,nmolecules,3,"lambdaH/calc:comall_H"); + memory->create(lambdaCM,nmolecules,"lambdaH/calc:lambdaCM"); + memory->create(gradlambdaCM,nmolecules,3,"lambdaH/calc:gradlambdaCM"); + + // compute masstotal for each molecule + + int *mask = atom->mask; + tagint *molecule = atom->molecule; + int *type = atom->type; + double *mass = atom->mass; + double *rmass = atom->rmass; + int nlocal = atom->nlocal; + tagint imol; + double massone; + + for (int i = 0; i < nmolecules; i++) massproc_H[i] = 0.0; + + for (int i = 0; i < nlocal; i++) + { + if (mask[i] & groupbit) { + if (rmass) massone = rmass[i]; + else massone = mass[type[i]]; + imol = molecule[i]; + if (molmap_H) imol = molmap_H[imol-idlo]; + else imol--; + massproc_H[imol] += massone; + } +} + + MPI_Allreduce(massproc_H,masstotal_H,nmolecules,MPI_DOUBLE,MPI_SUM,world); + int *replambdaH = atom->replambdaH; + int pass = 0; + for (int i = 0; i < nlocal; i++) if(replambdaH[i] != 0)pass=1; + if(pass==0) error->all(FLERR,"No representative atom (replambdaH) has been defined!"); + +} + +/* ---------------------------------------------------------------------- */ + +FixLambdaHCalc::~FixLambdaHCalc() +{ + + memory->destroy(massproc_H); + memory->destroy(masstotal_H); + memory->destroy(com_H); + memory->destroy(comall_H); + memory->destroy(molmap_H); + memory->destroy(lambdaCM); + memory->destroy(gradlambdaCM); + memory->destroy(Comp_Density_Num_H); + memory->destroy(Comp_Density_Num_all_H); + memory->destroy(Mean_Density_H); + memory->destroy(Int_Mean_Density_H); + memory->destroy(Mean_Comp_Density_Conv_H); + memory->destroy(grad_Comp_Density_Conv_H); + memory->destroy(Mean_grad_Comp_Density_Conv_H); +} + +/* ---------------------------------------------------------------------- */ + +int FixLambdaHCalc::setmask() +{ + int mask = 0; + //mask |= PRE_FORCE; +// mask |= PRE_NEIGHBOR; + mask |= POST_INTEGRATE; + mask |= THERMO_ENERGY; +// mask |= POST_FORCE_RESPA; + mask |= MIN_PRE_FORCE; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixLambdaHCalc::init() +{ + int ntmp = molecules_in_group(idlo,idhi); + if (ntmp != nmolecules) + error->all(FLERR,"Molecule count changed in compute com/molecule"); + + + +} + +/* ---------------------------------------------------------------------- */ + +void FixLambdaHCalc::setup(int vflag) +{ + +// if (strstr(update->integrate_style,"verlet")) + //pre_force(vflag); + post_integrate(); +// else { +// ((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1); +// post_force_respa(vflag,nlevels_respa-1,0); + // ((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1); + // } +} + +/* ---------------------------------------------------------------------- */ + + +void FixLambdaHCalc::post_integrate() +{ + + tagint imol; + double massone; + double unwrap[3]; + + + //invoked_array = update->ntimestep; + for (int i = 0; i < nmolecules; i++) + com_H[i][0] = com_H[i][1] = com_H[i][2] = 0.0; + + double **x = atom->x; + int *mask = atom->mask; + tagint *molecule = atom->molecule; + int *type = atom->type; + imageint *image = atom->image; + double *mass = atom->mass; + double *rmass = atom->rmass; + int nlocal = atom->nlocal; + + double *lambdaH = atom->lambdaH; + double **gradlambdaH = atom->gradlambdaH; + double **comH = atom->comH; + + int This_Step = update->ntimestep; + if(This_Step >= Density_Update_Time_Begin && This_Step <= Density_Update_Time_End && Density_Comp_Flag == 1){ + Density_Compensation_Run = 1; + if(me==0 && This_Step == Density_Update_Time_Begin){ + if(screen)fprintf(screen,"\nStart of constant-density route\n"); + if(logfile)fprintf(logfile,"\nStart of constant-density route\n"); + Clear_File_Compensation_Density(); + } + } + + + for (int i = 0; i < nlocal; i++) + if (mask[i] & groupbit) { + + if (rmass) massone = rmass[i]; + else massone = mass[type[i]]; + imol = molecule[i]; + if (molmap_H) imol = molmap_H[imol-idlo]; + else imol--; + domain->unmap(x[i],image[i],unwrap); + massone /= masstotal_H[imol]; + + com_H[imol][0] += unwrap[0] * massone; + com_H[imol][1] += unwrap[1] * massone; + com_H[imol][2] += unwrap[2] * massone; + } + + + MPI_Allreduce(&com_H[0][0],&comall_H[0][0],3*nmolecules,MPI_DOUBLE,MPI_SUM,world); + + + double xtmp,ytmp,ztmp; + double delx,dely,delz; + double Grad_Factor; + double rdiff; + + for (int i = 0; i < nmolecules; i++){ + + + domain->remap(comall_H[i]); + + if(Hybrid_Style==0){ + xtmp = comall_H[i][0]; + + if(xtmp < R_Start_Hybrid_1){ + lambdaCM[i] = 0.0; + gradlambdaCM[i][0] = 0.0; + gradlambdaCM[i][1] = 0.0; + gradlambdaCM[i][2] = 0.0; + + } + else if(xtmp >= R_Start_Hybrid_1 && xtmp < R_Start_Hybrid_1+Length_Hyb){ + cosx=cos(MY_PI*(xtmp-R_Start_Hybrid_1+Length_Hyb)/(2.0*Length_Hyb)); + sinx=sin(MY_PI*(xtmp-R_Start_Hybrid_1+Length_Hyb)/(2.0*Length_Hyb)); + lambdaCM[i] = cosx * cosx; + gradlambdaCM[i][0] = -(MY_PI/Length_Hyb) * sinx * cosx; + gradlambdaCM[i][1] = 0.0; + gradlambdaCM[i][2] = 0.0; + + } + else if(xtmp >=R_Start_Hybrid_1+Length_Hyb && xtmp < R_Start_Hybrid_2){ + lambdaCM[i] = 1.0; + gradlambdaCM[i][0] = 0.0; + gradlambdaCM[i][1] = 0.0; + gradlambdaCM[i][2] = 0.0; + + } + else if(xtmp >= R_Start_Hybrid_2 && xtmp < R_Start_Hybrid_2+Length_Hyb){ + cosx = cos(MY_PI*(xtmp-R_Start_Hybrid_2)/(2.0*Length_Hyb)); + sinx = sin(MY_PI*(xtmp-R_Start_Hybrid_2)/(2.0*Length_Hyb)); + lambdaCM[i] = cosx * cosx; + gradlambdaCM[i][0] = -(MY_PI/Length_Hyb) * sinx * cosx; + gradlambdaCM[i][1] = 0.0; + gradlambdaCM[i][2] = 0.0; + + } + else if(xtmp >=R_Start_Hybrid_2+Length_Hyb){ + lambdaCM[i] = 0.0; + gradlambdaCM[i][0] = 0.0; + gradlambdaCM[i][1] = 0.0; + gradlambdaCM[i][2] = 0.0; + + } + } + + else if(Hybrid_Style==1){ + xtmp = comall_H[i][0]; + ytmp = comall_H[i][1]; + ztmp = comall_H[i][2]; + + delx = (xtmp-center_box[0]); + dely = (ytmp-center_box[1]); + delz = (ztmp-center_box[2]); + + r = sqrt(delx*delx+dely*dely+delz*delz); + + if(r < S_Start_Hybrid){ + lambdaCM[i] = 1.0; + gradlambdaCM[i][0] = 0.0; + gradlambdaCM[i][1] = 0.0; + gradlambdaCM[i][2] = 0.0; + } + else if(r >= S_Start_Hybrid && r < S_Start_Hybrid+Length_Hyb) { + rdiff = MY_PI*(r-S_Start_Hybrid)/(2.0*Length_Hyb); + cosr=cos(rdiff); + sinr=sin(rdiff); + lambdaCM[i] = cosr * cosr; + Grad_Factor = -MY_PI * sinr * cosr / (Length_Hyb * r); + gradlambdaCM[i][0] = Grad_Factor * delx; + gradlambdaCM[i][1] = Grad_Factor * dely; + gradlambdaCM[i][2] = Grad_Factor * delz; + } + else if(r >= S_Start_Hybrid+Length_Hyb){ + lambdaCM[i] = 0.0; + gradlambdaCM[i][0] = 0.0; + gradlambdaCM[i][1] = 0.0; + gradlambdaCM[i][2] = 0.0; + } + } + + else if(Hybrid_Style==2){ + + xtmp = comall_H[i][0]; + ytmp = comall_H[i][1]; + + delx = (xtmp-center_box[0]); + dely = (ytmp-center_box[1]); + + r = sqrt(delx*delx+dely*dely); + + if(r < S_Start_Hybrid){ + lambdaCM[i] = 1.0; + gradlambdaCM[i][0] = 0.0; + gradlambdaCM[i][1] = 0.0; + gradlambdaCM[i][2] = 0.0; + } + else if(r >= S_Start_Hybrid && r < S_Start_Hybrid+Length_Hyb) { + rdiff = MY_PI*(r-S_Start_Hybrid)/(2.0*Length_Hyb); + cosr=cos(rdiff); + sinr=sin(rdiff); + lambdaCM[i] = cosr * cosr; + Grad_Factor = -MY_PI * sinr * cosr / (Length_Hyb * r); + + gradlambdaCM[i][0] = Grad_Factor * delx; + gradlambdaCM[i][1] = Grad_Factor * dely; + gradlambdaCM[i][2] = 0.0; + } + else if(r >= S_Start_Hybrid+Length_Hyb){ + lambdaCM[i] = 0.0; + gradlambdaCM[i][0] = 0.0; + gradlambdaCM[i][1] = 0.0; + gradlambdaCM[i][2] = 0.0; + } + } + + +} + + int ibin,imoltypeH; + int *moltypeH = atom->moltypeH; + + for (int i = 0; i < nlocal; i++) + if (mask[i] & groupbit) + { + imol = molecule[i]; + imoltypeH = moltypeH[i]; + if (molmap_H) imol = molmap_H[imol-idlo]; + else imol--; + lambdaH[i] = lambdaCM[imol]; + gradlambdaH[i][0] = gradlambdaCM[imol][0]; + gradlambdaH[i][1] = gradlambdaCM[imol][1]; + gradlambdaH[i][2] = gradlambdaCM[imol][2]; +// if(gradlambdaH[i][2]!=0) printf("gradlambdaH[i][2] = %f\n",gradlambdaH[i][2]); + +// gradlambdaH[i][2] = 0.0; + //gradlambdaH[i] = 0; +// if(replambdaH[i] == 1){ + comH[i][0] = comall_H[imol][0]; + comH[i][1] = comall_H[imol][1]; + comH[i][2] = comall_H[imol][2]; +// } + + if(Density_Comp_Flag != 0 && Density_Compensation_Run != 0){ + + if(Hybrid_Style==0){ +// xtmp = comall_H[imol][0]-x0lo; + xtmp = comH[i][0]-x0lo; +// if(xtmp <= 0.5*x0BoxSize)ibin = floor(xtmp/Density_Bin_Size); +// else ibin = floor((x0BoxSize-xtmp)/Density_Bin_Size); + + ibin = floor(xtmp/Density_Bin_Size); + + } + + else if(Hybrid_Style==1){ + xtmp = comall_H[imol][0]; + ytmp = comall_H[imol][1]; + ztmp = comall_H[imol][2]; + + delx = (xtmp-center_box[0]); + dely = (ytmp-center_box[1]); + delz = (ztmp-center_box[2]); + + r = sqrt(delx*delx+dely*dely+delz*delz); + ibin = floor(r/Density_Bin_Size); + } + + else if(Hybrid_Style==2){ + + xtmp = comall_H[imol][0]; + ytmp = comall_H[imol][1]; + + delx = (xtmp-center_box[0]); + dely = (ytmp-center_box[1]); + + r = sqrt(delx*delx+dely*dely); + ibin = floor(r/Density_Bin_Size); + } + + if(ibin>=Density_Bin_Num)ibin = Density_Bin_Num - 1; + Comp_Density_Num_H[ibin][imoltypeH-1]++; + + } + + } + + +// int Middle_Bin_Num = (Density_Bin_Num-1) / 2; + +// if(Hybrid_Style == 0)for(int i = Middle_Bin_Num+1;i < Density_Bin_Num; i++)Comp_Density_Num_H[i] = Comp_Density_Num_H[Density_Bin_Num-1-i]; + if(Density_Compensation_Run)Density_Counter_H++; + + double Density_Bin_Vol, exponent; + double Normalization; + int jmin, jmax,jj; + if(This_Step % Density_Update_Frequency == 0 && Density_Comp_Flag != 0 && Density_Compensation_Run != 0){ + + // if(atom->nmoltypesH ==1) MPI_Allreduce(&Comp_Density_Num_H[0][0],&Comp_Density_Num_all_H[0][0],Density_Bin_Num,MPI_INT,MPI_SUM,world); + MPI_Allreduce(&Comp_Density_Num_H[0][0],&Comp_Density_Num_all_H[0][0],Density_Bin_Num*(atom->nmoltypesH+1),MPI_INT,MPI_SUM,world); + + if(Hybrid_Style == 0)Density_Bin_Vol = 1.0*Density_Bin_Size * (x1hi-x1lo) * (x2hi-x2lo); + + for(int i = 0; i < Density_Bin_Num; i++){ + if(Hybrid_Style == 1)Density_Bin_Vol = (4.0/3.0) * MY_PI * (pow(((i+1) * Density_Bin_Size),3.0) - pow((i * Density_Bin_Size),3.0)); + if(Hybrid_Style == 2)Density_Bin_Vol = 4.0 * MY_PI * (x2hi-x2lo) * (pow(((i+1) * Density_Bin_Size),2.0) - pow((i * Density_Bin_Size),2.0)); + for(int j = 0; j < atom->nmoltypesH; j++){ + Mean_Density_H[i][j] = Comp_Density_Num_all_H[i][j] / (Density_Counter_H * Density_Bin_Vol); + } + } + + Density_Counter_H = 0; + + for(int k = 0; k < atom->nmoltypesH;k++){ + for(int i = 0;i < Density_Bin_Num; i++){ + Normalization = 0; + jmin = i - Density_Gauss_Int_Range*floor(Density_Sigma_Gauss / Density_Bin_Size); + jmax = i + Density_Gauss_Int_Range*floor(Density_Sigma_Gauss / Density_Bin_Size); + Mean_Comp_Density_Conv_H[i][k] = 0; + if(Hybrid_Style != 0){ + if(jmin<0)jmin=0; + if(jmax>=Density_Bin_Num)jmax=Density_Bin_Num-1; + } + + for(int j = jmin;j <= jmax; j++){ + jj = j; + if(Hybrid_Style == 0){ + if(j < 0)jj = Density_Bin_Num + j; + if(j >= Density_Bin_Num)jj = j - Density_Bin_Num; + } + exponent = (i-j)*Density_Bin_Size/Density_Sigma_Gauss; + exponent = pow(exponent,2.0); + Normalization += exp(-exponent)*Density_Bin_Size; + Mean_Comp_Density_Conv_H[i][k] += Mean_Density_H[jj][k] * exp(-exponent)*Density_Bin_Size; + // Mean_Comp_Density_Conv_H[i] += Mean_Density_H[j] * exp(-exponent); + } + Mean_Comp_Density_Conv_H[i][k] /= Normalization; + + } + } + + Density_Fluctuation = 0; + for(int k = 0; k < atom->nmoltypesH;k++)for(int i = 0;i < Density_Bin_Num; i++)Density_Fluctuation += (Density_Bin_Size/x0BoxSize)*pow((Mean_Density_H[i][k]-Density_Ref)/Density_Ref,2.0); + for(int k = 0; k < atom->nmoltypesH;k++) + for(int i = 1;i < Density_Bin_Num-1; i++) + grad_Comp_Density_Conv_H[i][k] = Comp_Density_Scaling_factor_H * (Mean_Comp_Density_Conv_H[i+1][k] - Mean_Comp_Density_Conv_H[i-1][k])/(2*Density_Bin_Size*Density_Ref); + + + //for(int i = 1;i < Density_Bin_Num-1; i++)Mean_grad_Comp_Density_Conv_H[i] = (Comp_Counter_H * Mean_grad_Comp_Density_Conv_H[i] + grad_Comp_Density_Conv_H[i]) / (Comp_Counter_H + 1); + for(int k = 0; k < atom->nmoltypesH;k++) + for(int i = 1;i < Density_Bin_Num-1; i++) + Mean_grad_Comp_Density_Conv_H[i][k] += grad_Comp_Density_Conv_H[i][k]; + +// for(int i = Middle_Bin_Num+1;i < Density_Bin_Num; i++)Comp_Density_Num_H[i] = Comp_Density_Num_H[Density_Bin_Num-1-i]; + + for(int k = 0; k < atom->nmoltypesH;k++) + for(int i = 0;i < Density_Bin_Num; i++) + Int_Mean_Density_H[i][k]=0; + + for(int k = 0; k < atom->nmoltypesH;k++) + for(int i = 0;i < Density_Bin_Num; i++) + for(int j = 0;j <= i; j++) + Int_Mean_Density_H[i][k] += Mean_grad_Comp_Density_Conv_H[j][k] * Density_Bin_Size; + + Comp_Counter_H += 1; + + for(int k = 0; k < atom->nmoltypesH;k++) + for(int i = 0;i < Density_Bin_Num; i++){ + Comp_Density_Num_H[i][k] = 0; + Comp_Density_Num_all_H[i][k] = 0; + } + + + } + + if(This_Step == Density_Update_Time_End && Density_Compensation_Run != 0){ + Density_Compensation_Run = 0; + if(me==0){ + if(screen)fprintf(screen,"\nEnd of constant-density route\n"); + if(logfile)fprintf(logfile,"\nEnd of constant-density route\n"); + } + } + + if (me == 0 && This_Step % Density_Update_Frequency == 0 && Density_Compensation_Run != 0) Print_Compensation_Density(); + +} + + +double FixLambdaHCalc::memory_usage() +{ + double bytes = (bigint) nmolecules * 2 * sizeof(double); + if (molmap_H) bytes += (idhi-idlo+1) * sizeof(int); + bytes += (bigint) nmolecules * 2*3 * sizeof(double); + bytes += (bigint) nmolecules * 2*3 * sizeof(double); + return bytes; +} + +/* ---------------------------------------------------------------------- */ + + +int FixLambdaHCalc::molecules_in_group(tagint &idlo, tagint &idhi) +{ + int i; + + memory->destroy(molmap_H); + molmap_H = NULL; + + // find lo/hi molecule ID for any atom in group + // warn if atom in group has ID = 0 + + tagint *molecule = atom->molecule; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + tagint lo = BIG; + tagint hi = -BIG; + int flag = 0; + for (i = 0; i < nlocal; i++) + { + if (mask[i] & groupbit) { + if (molecule[i] == 0) flag = 1; + lo = MIN(lo,molecule[i]); + hi = MAX(hi,molecule[i]); + } + } + + int flagall; + MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); + if (flagall && comm->me == 0) + error->warning(FLERR,"Atom with molecule ID = 0 included in " + "compute molecule group"); + + MPI_Allreduce(&lo,&idlo,1,MPI_LMP_TAGINT,MPI_MIN,world); + MPI_Allreduce(&hi,&idhi,1,MPI_LMP_TAGINT,MPI_MAX,world); + if (idlo == BIG) return 0; + + // molmap = vector of length nlen + // set to 1 for IDs that appear in group across all procs, else 0 + + tagint nlen_tag = idhi-idlo+1; + if (nlen_tag > MAXSMALLINT) + error->all(FLERR,"Too many molecules for compute"); + int nlen = (int) nlen_tag; + + memory->create(molmap_H,nlen,"lambdaH/calc:molmap"); + for (i = 0; i < nlen; i++) molmap_H[i] = 0; + + for (i = 0; i < nlocal; i++) + if (mask[i] & groupbit) + molmap_H[molecule[i]-idlo] = 1; + + int *molmapall; + memory->create(molmapall,nlen,"compute:molmapall"); + MPI_Allreduce(molmap_H,molmapall,nlen,MPI_INT,MPI_MAX,world); + + // nmolecules = # of non-zero IDs in molmap + // molmap[i] = index of molecule, skipping molecules not in group with -1 + + int nmolecules = 0; + for (i = 0; i < nlen; i++) + if (molmapall[i]) molmap_H[i] = nmolecules++; + else molmap_H[i] = -1; + memory->destroy(molmapall); + + // warn if any molecule has some atoms in group and some not in group + + flag = 0; + for (i = 0; i < nlocal; i++) { + if (mask[i] & groupbit) continue; + if (molecule[i] < idlo || molecule[i] > idhi) continue; + if (molmap_H[molecule[i]-idlo] >= 0) flag = 1; + } + + MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); + if (flagall && comm->me == 0) + error->warning(FLERR, + "One or more compute molecules has atoms not in group"); + + // if molmap simply stores 1 to Nmolecules, then free it + + if (idlo == 1 && idhi == nmolecules && nlen == nmolecules) { + memory->destroy(molmap_H); + molmap_H = NULL; + } + return nmolecules; +} + + +void FixLambdaHCalc::Print_Compensation_Density(){ + + + FILE *fp1; + fp1 = fopen("Mean_Comp_Density.txt","w"); + + if (fp1 == NULL) { + char str[128]; + sprintf(str,"Cannot open fix Mean_Comp_Density file %s","Mean_Comp_Density.txt"); + error->one(FLERR,str); + } + + + for(int i = 0;i < Density_Bin_Num; i++){ + fprintf(fp1,"%d",i+1); + for(int k = 0; k < atom->nmoltypesH;k++) + fprintf(fp1,"\t%.10f",Mean_grad_Comp_Density_Conv_H[i][k]); + fprintf(fp1,"\n"); + } + fclose(fp1); + + /* + FILE *fp2; + + char filename2[1000]; + sprintf(filename2, "Mean_Comp_Density%4.1f_%d.txt", Comp_Density_Scaling_factor_H,Density_Update_Frequency); + + fp2 = fopen(filename2,"a"); + + if (fp2 == NULL) { + char str[128]; + sprintf(str,"Cannot open fix Mean_Comp_Density file %s","Mean_Comp_Density.txt"); + error->one(FLERR,str); + } + + printf("Density_Fluctuation = %f\n",Density_Fluctuation); + + double x0; + if(Hybrid_Style==0)x0=x0lo; + else x0=0; + + for(int i = 0;i < Density_Bin_Num; i++){ + fprintf(fp2,"%d\t %.10f\t",i+1,i*Density_Bin_Size+x0); + for(int k = 0; k < atom->nmoltypesH;k++) + fprintf(fp2,"\t%.10f\t %.10f\t %.10f\t %.10f",Mean_Comp_Density_Conv_H[i][k],grad_Comp_Density_Conv_H[i][k],Mean_grad_Comp_Density_Conv_H[i][k]); + fprintf(fp2,"\n"); + + } + fclose(fp2); + + + FILE *fp3; + char filename3[1000]; + sprintf(filename3, "Density_Fluctuation%4.1f_%d.txt", Comp_Density_Scaling_factor_H,Density_Update_Frequency); + + fp3 = fopen(filename3,"a"); + + if (fp3 == NULL) { + char str[128]; + sprintf(str,"Cannot open fix Density_Fluctuation file %s","Density_Fluctuation.txt"); + error->one(FLERR,str); + } + + int This_Step = update->ntimestep; + fprintf(fp3,"%d %.10f\n",This_Step,Density_Fluctuation); + + fclose(fp3); + +*/ +} + +void FixLambdaHCalc::Clear_File_Compensation_Density(){ + + FILE *fp1; + fp1 = fopen("Mean_Comp_Density.txt","w"); + + if (fp1 == NULL) { + char str[128]; + sprintf(str,"Cannot open fix Mean_Comp_Density file %s","Mean_Comp_Density.txt"); + error->one(FLERR,str); + } + + + fclose(fp1); + + /* + FILE *fp2; + + char filename2[1000]; + sprintf(filename2, "Mean_Comp_Density%4.1f_%d.txt", Comp_Density_Scaling_factor_H,Density_Update_Frequency); + + fp2 = fopen(filename2,"w"); + + if (fp2 == NULL) { + char str[128]; + sprintf(str,"Cannot open fix Mean_Comp_Density file %s","Mean_Comp_Density.txt"); + error->one(FLERR,str); + } + + + fclose(fp2); + + FILE *fp3; + char filename3[1000]; + sprintf(filename3, "Density_Fluctuation%4.1f_%d.txt", Comp_Density_Scaling_factor_H,Density_Update_Frequency); + + fp3 = fopen(filename3,"w"); + + if (fp3 == NULL) { + char str[128]; + sprintf(str,"Cannot open fix Density_Fluctuation file %s","Density_Fluctuation.txt"); + error->one(FLERR,str); + } + + fclose(fp3); + */ + +} + +void FixLambdaHCalc::Load_Compensation_Density(){ + + if(me == 0){ + FILE *fp1; + char str[128]; + + fp1 = fopen("Mean_Comp_Density.txt","r"); + if (fp1 == NULL) { + sprintf(str,"Cannot open fix Mean_Comp_Density.txt file %s","Mean_Comp_Density.txt"); + error->one(FLERR,str); + } + + int i1; + float i2; + + while (!feof(fp1)){ + fscanf (fp1,"%d",&i1); + for(int k = 0; k < atom->nmoltypesH;k++){ + fscanf (fp1,"\t%f",&i2); + Mean_grad_Comp_Density_Conv_H[i1-1][k] = (double) i2; + } + fscanf (fp1,"\n"); + + if(i1 > Density_Bin_Num){ + sprintf(str,"Density bin number mismatches %d != %d",Density_Bin_Num,i1); + error->one(FLERR,str); + } + + } + + fclose(fp1); + + + if(me==0){ + if(screen)fprintf(screen,"\n\nDensity componsation forces distributed successfully!\n\n"); + if(logfile)fprintf(logfile,"\n\nDensity componsation forces distributed successfully!\n\n"); + } + } + + MPI_Bcast(Mean_grad_Comp_Density_Conv_H,Density_Bin_Num*(atom->nmoltypesH+1),MPI_DOUBLE,0,world); + +} diff --git a/src/USER-HADRESS/fix_lambdah_calc.h b/src/USER-HADRESS/fix_lambdah_calc.h new file mode 100644 index 000000000..d3552e17f --- /dev/null +++ b/src/USER-HADRESS/fix_lambdah_calc.h @@ -0,0 +1,102 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS + +FixStyle(lambdah/calc,FixLambdaHCalc) + +#else + +#ifndef LMP_FIX_LAMBDAH_CALC_H +#define LMP_FIX_LAMBDAH_CALC_H + +#include "fix.h" + +namespace LAMMPS_NS { + +class FixLambdaHCalc : public Fix { + public: + FixLambdaHCalc(class LAMMPS *, int, char **); + ~FixLambdaHCalc(); + int setmask(); + void init(); + void setup(int); + + void post_integrate(); + double memory_usage(); + + + double Length_Hyb,Length_ATRegion,Length_CGRegion; + int Hybrid_Style; + int Pressure_Comp_Flag,Pressure_Bin_Num,Pressure_Update_Frequency,Pressure_Update_Time_End, Pressure_Update_Time_Begin; + double Pressure_lambda_Increment; + int Density_Comp_Flag,Density_Compensation_Run,Density_Bin_Num,Density_Update_Frequency,Density_Update_Time_End,Density_Update_Time_Begin; + double Density_Bin_Size; + int Comp_Counter_H,Density_Counter_H; + double **Mean_grad_Comp_Density_Conv_H; + + double Density_Ref; + double center_box[3]; + int me; + double x0lo,x0hi,x1lo,x1hi,x2lo,x2hi,x0BoxSize; + double Density_Sigma_Gauss; + double Comp_Density_Scaling_factor_H; + int Density_Gauss_Int_Range; + + double xmin_AT,xmax_AT; + private: + int nmolecules; + tagint idlo,idhi; + double *massproc_H,*masstotal_H; + double **com_H,**comall_H; + double Density_Fluctuation; + int **Comp_Density_Num_H, **Comp_Density_Num_all_H; + double **Int_Mean_Density_H, **Mean_Density_H, **grad_Comp_Density_Conv_H, **Mean_Comp_Density_Conv_H; + int Load_File_Flag; + double R_Start_Hybrid_1,R_Start_Hybrid_2,S_Start_Hybrid,r,cosr,sinr,sinx,cosx; + double *lambdaCM, **gradlambdaCM; + int *molmap_H; // convert molecule ID to local index + + int molecules_in_group(tagint &, tagint &); + + void Print_Compensation_Density(); + void Load_Compensation_Density(); + void Clear_File_Compensation_Density(); +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + +E: Illegal ... command + +Self-explanatory. Check the input script syntax and compare to the +documentation for the command. You can use -echo screen as a +command-line option when running LAMMPS to see the offending line. + +E: Variable name for fix indent does not exist + +Self-explanatory. + +E: Variable for fix indent is invalid style + +Only equal-style variables can be used. + +E: Variable for fix indent is not equal style + +Only equal-style variables can be used. + +*/ diff --git a/src/USER-HADRESS/molecule.cpp b/src/USER-HADRESS/molecule.cpp new file mode 100644 index 000000000..89ca26d05 --- /dev/null +++ b/src/USER-HADRESS/molecule.cpp @@ -0,0 +1,1829 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#include <stdlib.h> +#include <string.h> +#include "molecule.h" +#include "atom.h" +#include "atom_vec.h" +#include "atom_vec_body.h" +#include "force.h" +#include "comm.h" +#include "domain.h" +#include "math_extra.h" +#include "math_const.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; +using namespace MathConst; + +#define MAXLINE 256 +#define EPSILON 1.0e-7 +#define BIG 1.0e20 + +#define SINERTIA 0.4 // moment of inertia prefactor for sphere + +/* ---------------------------------------------------------------------- */ + +Molecule::Molecule(LAMMPS *lmp, int narg, char **arg, int &index) : + Pointers(lmp) +{ + me = comm->me; + + if (index >= narg) error->all(FLERR,"Illegal molecule command"); + + int n = strlen(arg[0]) + 1; + id = new char[n]; + strcpy(id,arg[0]); + + for (int i = 0; i < n-1; i++) + if (!isalnum(id[i]) && id[i] != '_') + error->all(FLERR,"Molecule template ID must be " + "alphanumeric or underscore characters"); + + // parse args until reach unknown arg (next file) + + toffset = 0; + boffset = aoffset = doffset = ioffset = 0; + sizescale = 1.0; + + int ifile = index; + int iarg = ifile+1; + + while (iarg < narg) { + if (strcmp(arg[iarg],"offset") == 0) { + if (iarg+6 > narg) error->all(FLERR,"Illegal molecule command"); + toffset = force->inumeric(FLERR,arg[iarg+1]); + boffset = force->inumeric(FLERR,arg[iarg+2]); + aoffset = force->inumeric(FLERR,arg[iarg+3]); + doffset = force->inumeric(FLERR,arg[iarg+4]); + ioffset = force->inumeric(FLERR,arg[iarg+5]); + if (toffset < 0 || boffset < 0 || aoffset < 0 || + doffset < 0 || ioffset < 0) + error->all(FLERR,"Illegal molecule command"); + iarg += 6; + } else if (strcmp(arg[iarg],"toff") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal molecule command"); + toffset = force->inumeric(FLERR,arg[iarg+1]); + if (toffset < 0) error->all(FLERR,"Illegal molecule command"); + iarg += 2; + } else if (strcmp(arg[iarg],"boff") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal molecule command"); + boffset = force->inumeric(FLERR,arg[iarg+1]); + if (boffset < 0) error->all(FLERR,"Illegal molecule command"); + iarg += 2; + } else if (strcmp(arg[iarg],"aoff") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal molecule command"); + aoffset = force->inumeric(FLERR,arg[iarg+1]); + if (aoffset < 0) error->all(FLERR,"Illegal molecule command"); + iarg += 2; + } else if (strcmp(arg[iarg],"doff") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal molecule command"); + doffset = force->inumeric(FLERR,arg[iarg+1]); + if (doffset < 0) error->all(FLERR,"Illegal molecule command"); + iarg += 2; + } else if (strcmp(arg[iarg],"ioff") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal molecule command"); + ioffset = force->inumeric(FLERR,arg[iarg+1]); + if (ioffset < 0) error->all(FLERR,"Illegal molecule command"); + iarg += 2; + } else if (strcmp(arg[iarg],"scale") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal molecule command"); + sizescale = force->numeric(FLERR,arg[iarg+1]); + if (sizescale <= 0.0) error->all(FLERR,"Illegal molecule command"); + iarg += 2; + } else break; + } + + index = iarg; + + // last molecule if have scanned all args + + if (iarg == narg) last = 1; + else last = 0; + + // initialize all fields to empty + + initialize(); + + // scan file for sizes of all fields and allocate them + + if (me == 0) open(arg[ifile]); + read(0); + if (me == 0) fclose(fp); + allocate(); + + // read file again to populate all fields + + if (me == 0) open(arg[ifile]); + read(1); + if (me == 0) fclose(fp); + + // stats + + if (me == 0) { + if (screen) + fprintf(screen,"Read molecule %s:\n" + " %d atoms with %d types\n %d bonds with %d types\n" + " %d angles with %d types\n %d dihedrals with %d types\n" + " %d impropers with %d types\n", + id,natoms,ntypes, + nbonds,nbondtypes,nangles,nangletypes, + ndihedrals,ndihedraltypes,nimpropers,nimpropertypes); + if (logfile) + fprintf(logfile,"Read molecule %s:\n" + " %d atoms with %d types\n %d bonds with %d types\n" + " %d angles with %d types\n %d dihedrals with %d types\n" + " %d impropers with %d types\n", + id,natoms,ntypes, + nbonds,nbondtypes,nangles,nangletypes, + ndihedrals,ndihedraltypes,nimpropers,nimpropertypes); + } +} + +/* ---------------------------------------------------------------------- */ + +Molecule::~Molecule() +{ + delete [] id; + deallocate(); +} + +/* ---------------------------------------------------------------------- + compute center = geometric center of molecule + also compute: + dx = displacement of each atom from center + molradius = radius of molecule from center + including finite-size particles or body particles +------------------------------------------------------------------------- */ + +void Molecule::compute_center() +{ + if (centerflag) return; + centerflag = 1; + + center[0] = center[1] = center[2] = 0.0; + for (int i = 0; i < natoms; i++) { + center[0] += x[i][0]; + center[1] += x[i][1]; + center[2] += x[i][2]; + } + center[0] /= natoms; + center[1] /= natoms; + center[2] /= natoms; + + memory->destroy(dx); + memory->create(dx,natoms,3,"molecule:dx"); + + for (int i = 0; i < natoms; i++) { + dx[i][0] = x[i][0] - center[0]; + dx[i][1] = x[i][1] - center[1]; + dx[i][2] = x[i][2] - center[2]; + } + + molradius = 0.0; + for (int i = 0; i < natoms; i++) { + double rad = MathExtra::len3(dx[i]); + if (radiusflag) rad += radius[i]; + molradius = MAX(molradius,rad); + } +} + +/* ---------------------------------------------------------------------- + compute masstotal = total mass of molecule + could have been set by user, otherwise calculate it +------------------------------------------------------------------------- */ + +void Molecule::compute_mass() +{ + if (massflag) return; + massflag = 1; + + if (!rmassflag) atom->check_mass(); + + masstotal = 0.0; + for (int i = 0; i < natoms; i++) { + if (rmassflag) masstotal += rmass[i]; + else masstotal += atom->mass[type[i]]; + } +} + +/* ---------------------------------------------------------------------- + compute com = center of mass of molecule + could have been set by user, otherwise calculate it + works for finite size particles assuming no overlap + also compute: + dxcom = displacement of each atom from COM + comatom = which atom (1-Natom) is nearest the COM + maxextent = furthest any atom in molecule is from comatom (not COM) +------------------------------------------------------------------------- */ + +void Molecule::compute_com() +{ + if (!comflag) { + comflag = 1; + + if (!rmassflag) atom->check_mass(); + + double onemass; + com[0] = com[1] = com[2] = 0.0; + for (int i = 0; i < natoms; i++) { + if (rmassflag) onemass = rmass[i]; + else onemass = atom->mass[type[i]]; + com[0] += x[i][0]*onemass; + com[1] += x[i][1]*onemass; + com[2] += x[i][2]*onemass; + } + com[0] /= masstotal; + com[1] /= masstotal; + com[2] /= masstotal; + } + + memory->destroy(dxcom); + memory->create(dxcom,natoms,3,"molecule:dxcom"); + + for (int i = 0; i < natoms; i++) { + dxcom[i][0] = x[i][0] - com[0]; + dxcom[i][1] = x[i][1] - com[1]; + dxcom[i][2] = x[i][2] - com[2]; + } + + double rsqmin = BIG; + for (int i = 0; i < natoms; i++) { + double rsq = MathExtra::lensq3(dxcom[i]); + if (rsq < rsqmin) { + comatom = i; + rsqmin = rsq; + } + } + + double rsqmax = 0.0; + for (int i = 0; i < natoms; i++) { + double dx = x[comatom][0] - x[i][0]; + double dy = x[comatom][1] - x[i][1]; + double dz = x[comatom][2] - x[i][2]; + double rsq = dx*dx + dy*dy + dz*dz; + rsqmax = MAX(rsqmax,rsq); + } + + comatom++; + maxextent = sqrt(rsqmax); +} + +/* ---------------------------------------------------------------------- + compute itensor = 6 moments of inertia of molecule around xyz axes + could have been set by user, otherwise calculate it + accounts for finite size spheres, assuming no overlap + also compute: + inertia = 3 principal components of inertia + ex,ey,ez = principal axes in space coords + quat = quaternion for orientation of molecule + dxbody = displacement of each atom from COM in body frame +------------------------------------------------------------------------- */ + +void Molecule::compute_inertia() +{ + if (!inertiaflag) { + inertiaflag = 1; + + if (!rmassflag) atom->check_mass(); + + double onemass,dx,dy,dz; + for (int i = 0; i < 6; i++) itensor[i] = 0.0; + for (int i = 0; i < natoms; i++) { + if (rmassflag) onemass = rmass[i]; + else onemass = atom->type[type[i]]; + dx = dxcom[i][0]; + dy = dxcom[i][1]; + dz = dxcom[i][2]; + itensor[0] += onemass * (dy*dy + dz*dz); + itensor[1] += onemass * (dx*dx + dz*dz); + itensor[2] += onemass * (dx*dx + dy*dy); + itensor[3] -= onemass * dy*dz; + itensor[4] -= onemass * dx*dz; + itensor[5] -= onemass * dx*dy; + } + + if (radiusflag) { + for (int i = 0; i < natoms; i++) { + if (rmassflag) onemass = rmass[i]; + else onemass = atom->type[type[i]]; + itensor[0] += SINERTIA*onemass * radius[i]*radius[i]; + itensor[1] += SINERTIA*onemass * radius[i]*radius[i]; + itensor[2] += SINERTIA*onemass * radius[i]*radius[i]; + } + } + } + + // diagonalize inertia tensor for each body via Jacobi rotations + // inertia = 3 eigenvalues = principal moments of inertia + // evectors and exzy = 3 evectors = principal axes of rigid body + + double cross[3]; + double tensor[3][3],evectors[3][3]; + + tensor[0][0] = itensor[0]; + tensor[1][1] = itensor[1]; + tensor[2][2] = itensor[2]; + tensor[1][2] = tensor[2][1] = itensor[3]; + tensor[0][2] = tensor[2][0] = itensor[4]; + tensor[0][1] = tensor[1][0] = itensor[5]; + + if (MathExtra::jacobi(tensor,inertia,evectors)) + error->all(FLERR,"Insufficient Jacobi rotations for rigid molecule"); + + ex[0] = evectors[0][0]; + ex[1] = evectors[1][0]; + ex[2] = evectors[2][0]; + ey[0] = evectors[0][1]; + ey[1] = evectors[1][1]; + ey[2] = evectors[2][1]; + ez[0] = evectors[0][2]; + ez[1] = evectors[1][2]; + ez[2] = evectors[2][2]; + + // if any principal moment < scaled EPSILON, set to 0.0 + + double max; + max = MAX(inertia[0],inertia[1]); + max = MAX(max,inertia[2]); + + if (inertia[0] < EPSILON*max) inertia[0] = 0.0; + if (inertia[1] < EPSILON*max) inertia[1] = 0.0; + if (inertia[2] < EPSILON*max) inertia[2] = 0.0; + + // enforce 3 evectors as a right-handed coordinate system + // flip 3rd vector if needed + + MathExtra::cross3(ex,ey,cross); + if (MathExtra::dot3(cross,ez) < 0.0) MathExtra::negate3(ez); + + // create quaternion + + MathExtra::exyz_to_q(ex,ey,ez,quat); + + // compute displacements in body frame defined by quat + + memory->destroy(dxbody); + memory->create(dxbody,natoms,3,"molecule:dxbody"); + + for (int i = 0; i < natoms; i++) + MathExtra::transpose_matvec(ex,ey,ez,dxcom[i],dxbody[i]); +} + +/* ---------------------------------------------------------------------- + read molecule info from file + flag = 0, just scan for sizes of fields + flag = 1, read and store fields +------------------------------------------------------------------------- */ + +void Molecule::read(int flag) +{ + char line[MAXLINE],keyword[MAXLINE]; + char *eof,*ptr; + + // skip 1st line of file + + if (me == 0) { + eof = fgets(line,MAXLINE,fp); + if (eof == NULL) error->one(FLERR,"Unexpected end of molecule file"); + } + + // read header lines + // skip blank lines or lines that start with "#" + // stop when read an unrecognized line + + while (1) { + + readline(line); + + // trim anything from '#' onward + // if line is blank, continue + + if ((ptr = strchr(line,'#'))) *ptr = '\0'; + if (strspn(line," \t\n\r") == strlen(line)) continue; + + // search line for header keywords and set corresponding variable + + if (strstr(line,"atoms")) sscanf(line,"%d",&natoms); + else if (strstr(line,"bonds")) sscanf(line,"%d",&nbonds); + else if (strstr(line,"angles")) sscanf(line,"%d",&nangles); + else if (strstr(line,"dihedrals")) sscanf(line,"%d",&ndihedrals); + else if (strstr(line,"impropers")) sscanf(line,"%d",&nimpropers); + + else if (strstr(line,"mass")) { + massflag = 1; + sscanf(line,"%lg",&masstotal); + masstotal *= sizescale*sizescale*sizescale; + } + else if (strstr(line,"com")) { + comflag = 1; + sscanf(line,"%lg %lg %lg",&com[0],&com[1],&com[2]); + com[0] *= sizescale; + com[1] *= sizescale; + com[2] *= sizescale; + if (domain->dimension == 2 && com[2] != 0.0) + error->all(FLERR,"Molecule file z center-of-mass must be 0.0 for 2d"); + } + else if (strstr(line,"inertia")) { + inertiaflag = 1; + sscanf(line,"%lg %lg %lg %lg %lg %lg", + &itensor[0],&itensor[1],&itensor[2], + &itensor[3],&itensor[4],&itensor[5]); + itensor[0] *= sizescale*sizescale*sizescale*sizescale*sizescale; + itensor[1] *= sizescale*sizescale*sizescale*sizescale*sizescale; + itensor[2] *= sizescale*sizescale*sizescale*sizescale*sizescale; + itensor[3] *= sizescale*sizescale*sizescale*sizescale*sizescale; + itensor[4] *= sizescale*sizescale*sizescale*sizescale*sizescale; + itensor[5] *= sizescale*sizescale*sizescale*sizescale*sizescale; + } + else if (strstr(line,"body")) { + bodyflag = 1; + avec_body = (AtomVecBody *) atom->style_match("body"); + if (!avec_body) + error->all(FLERR,"Molecule file requires atom style body"); + sscanf(line,"%d %d",&nibody,&ndbody); + } + + else break; + } + + // error checks + + if (natoms < 1) error->all(FLERR,"No count or invalid atom count in molecule file"); + if (nbonds < 0) error->all(FLERR,"Invalid bond count in molecule file"); + if (nangles < 0) error->all(FLERR,"Invalid angle count in molecule file"); + if (ndihedrals < 0) + error->all(FLERR,"Invalid dihedral count in molecule file"); + if (nimpropers < 0) + error->all(FLERR,"Invalid improper count in molecule file"); + + // count = vector for tallying bonds,angles,etc per atom + + if (flag == 0) memory->create(count,natoms,"molecule:count"); + else count = NULL; + + // grab keyword and skip next line + + parse_keyword(0,line,keyword); + readline(line); + + // loop over sections of molecule file + + while (strlen(keyword)) { + if (strcmp(keyword,"Coords") == 0) { + xflag = 1; + if (flag) coords(line); + else skip_lines(natoms,line); + } else if (strcmp(keyword,"Types") == 0) { + typeflag = 1; + if (flag) types(line); + else skip_lines(natoms,line); + } else if (strcmp(keyword,"Charges") == 0) { + qflag = 1; + if (flag) charges(line); + else skip_lines(natoms,line); + } else if (strcmp(keyword,"Diameters") == 0) { + radiusflag = 1; + if (flag) diameters(line); + else skip_lines(natoms,line); + } else if (strcmp(keyword,"Masses") == 0) { + rmassflag = 1; + if (flag) masses(line); + else skip_lines(natoms,line); + + } else if (strcmp(keyword,"replambdaH") == 0) { + replambdaHflag = 1; + if (flag) representative_atom(line); + else skip_lines(natoms,line); + } else if (strcmp(keyword,"moltypeH") == 0) { + moltypeHflag = 1; + if (flag) moltype_atom(line); + else skip_lines(natoms,line); + + } else if (strcmp(keyword,"Bonds") == 0) { + if (nbonds == 0) + error->all(FLERR,"Molecule file has bonds but no nbonds setting"); + bondflag = tag_require = 1; + bonds(flag,line); + } else if (strcmp(keyword,"Angles") == 0) { + if (nangles == 0) + error->all(FLERR,"Molecule file has angles but no nangles setting"); + angleflag = tag_require = 1; + angles(flag,line); + } else if (strcmp(keyword,"Dihedrals") == 0) { + if (ndihedrals == 0) error->all(FLERR,"Molecule file has dihedrals " + "but no ndihedrals setting"); + dihedralflag = tag_require = 1; + dihedrals(flag,line); + } else if (strcmp(keyword,"Impropers") == 0) { + if (nimpropers == 0) error->all(FLERR,"Molecule file has impropers " + "but no nimpropers setting"); + improperflag = tag_require = 1; + impropers(flag,line); + + } else if (strcmp(keyword,"Special Bond Counts") == 0) { + nspecialflag = 1; + nspecial_read(flag,line); + } else if (strcmp(keyword,"Special Bonds") == 0) { + specialflag = tag_require = 1; + if (flag) special_read(line); + else skip_lines(natoms,line); + + } else if (strcmp(keyword,"Shake Flags") == 0) { + shakeflagflag = 1; + if (flag) shakeflag_read(line); + else skip_lines(natoms,line); + } else if (strcmp(keyword,"Shake Atoms") == 0) { + shakeatomflag = tag_require = 1; + if (shaketypeflag) shakeflag = 1; + if (!shakeflagflag) + error->all(FLERR,"Molecule file shake flags not before shake atoms"); + if (flag) shakeatom_read(line); + else skip_lines(natoms,line); + } else if (strcmp(keyword,"Shake Bond Types") == 0) { + shaketypeflag = 1; + if (shakeatomflag) shakeflag = 1; + if (!shakeflagflag) + error->all(FLERR,"Molecule file shake flags not before shake bonds"); + if (flag) shaketype_read(line); + else skip_lines(natoms,line); + + } else if (strcmp(keyword,"Body Integers") == 0) { + if (bodyflag == 0 || nibody == 0) + error->all(FLERR,"Molecule file has body params " + "but no setting for them"); + ibodyflag = 1; + body(flag,0,line); + } else if (strcmp(keyword,"Body Doubles") == 0) { + if (bodyflag == 0 || ndbody == 0) + error->all(FLERR,"Molecule file has body params " + "but no setting for them"); + dbodyflag = 1; + body(flag,1,line); + + } else error->one(FLERR,"Unknown section in molecule file"); + + parse_keyword(1,line,keyword); + } + + // clean up + + memory->destroy(count); + + // error check + + if (flag == 0) { + if ((nspecialflag && !specialflag) || (!nspecialflag && specialflag)) + error->all(FLERR,"Molecule file needs both Special Bond sections"); + if (specialflag && !bondflag) + error->all(FLERR,"Molecule file has special flags but no bonds"); + if ((shakeflagflag || shakeatomflag || shaketypeflag) && !shakeflag) + error->all(FLERR,"Molecule file shake info is incomplete"); + if (bodyflag && nibody && ibodyflag == 0) + error->all(FLERR,"Molecule file has no Body Integers section"); + if (bodyflag && ndbody && dbodyflag == 0) + error->all(FLERR,"Molecule file has no Body Doubles section"); + } + + // auto-generate special bonds + + if (bondflag && !specialflag) { + specialflag = 1; + nspecialflag = 1; + maxspecial = atom->maxspecial; + if (flag) special_generate(); + } + + // body particle must have natom = 1 + // set radius by having body class compute its own radius + + if (bodyflag) { + radiusflag = 1; + if (natoms != 1) + error->all(FLERR,"Molecule natoms must be 1 for body particle"); + if (sizescale != 1.0) + error->all(FLERR,"Molecule sizescale must be 1.0 for body particle"); + if (flag) { + radius[0] = avec_body->radius_body(nibody,ndbody,ibodyparams,dbodyparams); + maxradius = radius[0]; + } + } +} + +/* ---------------------------------------------------------------------- + read coords from file +------------------------------------------------------------------------- */ + +void Molecule::coords(char *line) +{ + int tmp; + for (int i = 0; i < natoms; i++) { + readline(line); + if (i == 0) { + int nwords = atom->count_words(line); + if (nwords != 4) + error->all(FLERR,"Invalid Coords section in molecule file"); + } + sscanf(line,"%d %lg %lg %lg",&tmp,&x[i][0],&x[i][1],&x[i][2]); + x[i][0] *= sizescale; + x[i][1] *= sizescale; + x[i][2] *= sizescale; + } + + if (domain->dimension == 2) { + for (int i = 0; i < natoms; i++) + if (x[i][2] != 0.0) + error->all(FLERR,"Molecule file z coord must be 0.0 for 2d"); + } +} + +/* ---------------------------------------------------------------------- + read types from file + set ntypes = max of any atom type +------------------------------------------------------------------------- */ + +void Molecule::types(char *line) +{ + int tmp; + for (int i = 0; i < natoms; i++) { + readline(line); + if (i == 0) { + int nwords = atom->count_words(line); + if (nwords != 2) + error->all(FLERR,"Invalid Types section in molecule file"); + } + sscanf(line,"%d %d",&tmp,&type[i]); + type[i] += toffset; + } + + for (int i = 0; i < natoms; i++) + if (type[i] <= 0) + error->all(FLERR,"Invalid atom type in molecule file"); + + for (int i = 0; i < natoms; i++) + ntypes = MAX(ntypes,type[i]); +} + +/* ---------------------------------------------------------------------- + read charges from file +------------------------------------------------------------------------- */ + +void Molecule::charges(char *line) +{ + int tmp; + for (int i = 0; i < natoms; i++) { + readline(line); + if (i == 0) { + int nwords = atom->count_words(line); + if (nwords != 2) + error->all(FLERR,"Invalid Charges section in molecule file"); + } + sscanf(line,"%d %lg",&tmp,&q[i]); + } +} + +void Molecule::representative_atom(char *line) +{ + int tmp; + for (int i = 0; i < natoms; i++) { + readline(line); + sscanf(line,"%d %d",&tmp,&replambdaH[i]); + printf("i=%d rep = %d",i,replambdaH[i]); + } +} + +void Molecule::moltype_atom(char *line) +{ + int tmp; + for (int i = 0; i < natoms; i++) { + readline(line); + sscanf(line,"%d %d",&tmp,&moltypeH[i]); + printf("i=%d rep = %d",i,moltypeH[i]); + } +} + +/* ---------------------------------------------------------------------- + read diameters from file and set radii +------------------------------------------------------------------------- */ + +void Molecule::diameters(char *line) +{ + int tmp; + maxradius = 0.0; + for (int i = 0; i < natoms; i++) { + readline(line); + if (i == 0) { + int nwords = atom->count_words(line); + if (nwords != 2) + error->all(FLERR,"Invalid Diameters section in molecule file"); + } + sscanf(line,"%d %lg",&tmp,&radius[i]); + radius[i] *= sizescale; + radius[i] *= 0.5; + maxradius = MAX(maxradius,radius[i]); + } + + for (int i = 0; i < natoms; i++) + if (radius[i] < 0.0) + error->all(FLERR,"Invalid atom diameter in molecule file"); +} + +/* ---------------------------------------------------------------------- + read masses from file +------------------------------------------------------------------------- */ + +void Molecule::masses(char *line) +{ + int tmp; + for (int i = 0; i < natoms; i++) { + readline(line); + if (i == 0) { + int nwords = atom->count_words(line); + if (nwords != 2) + error->all(FLERR,"Invalid Masses section in molecule file"); + } + sscanf(line,"%d %lg",&tmp,&rmass[i]); + rmass[i] *= sizescale*sizescale*sizescale; + } + + for (int i = 0; i < natoms; i++) + if (rmass[i] <= 0.0) error->all(FLERR,"Invalid atom mass in molecule file"); +} + +/* ---------------------------------------------------------------------- + read bonds from file + set nbondtypes = max type of any bond + store each with both atoms if newton_bond = 0 + if flag = 0, just count bonds/atom + if flag = 1, store them with atoms +------------------------------------------------------------------------- */ + +void Molecule::bonds(int flag, char *line) +{ + int tmp,itype; + tagint m,atom1,atom2; + int newton_bond = force->newton_bond; + + if (flag == 0) + for (int i = 0; i < natoms; i++) count[i] = 0; + else + for (int i = 0; i < natoms; i++) num_bond[i] = 0; + + for (int i = 0; i < nbonds; i++) { + readline(line); + if (i == 0) { + int nwords = atom->count_words(line); + if (nwords != 4) + error->all(FLERR,"Invalid Bonds section in molecule file"); + } + sscanf(line,"%d %d " TAGINT_FORMAT " " TAGINT_FORMAT, + &tmp,&itype,&atom1,&atom2); + itype += boffset; + + if (atom1 <= 0 || atom1 > natoms || + atom2 <= 0 || atom2 > natoms) + error->one(FLERR,"Invalid atom ID in Bonds section of molecule file"); + if (itype <= 0) + error->one(FLERR,"Invalid bond type in Bonds section of molecule file"); + + if (flag) { + m = atom1-1; + nbondtypes = MAX(nbondtypes,itype); + bond_type[m][num_bond[m]] = itype; + bond_atom[m][num_bond[m]] = atom2; + num_bond[m]++; + if (newton_bond == 0) { + m = atom2-1; + bond_type[m][num_bond[m]] = itype; + bond_atom[m][num_bond[m]] = atom1; + num_bond[m]++; + } + } else { + count[atom1-1]++; + if (newton_bond == 0) count[atom2-1]++; + } + } + + // bond_per_atom = max of count vector + + if (flag == 0) { + bond_per_atom = 0; + for (int i = 0; i < natoms; i++) + bond_per_atom = MAX(bond_per_atom,count[i]); + } +} + +/* ---------------------------------------------------------------------- + read angles from file + store each with all 3 atoms if newton_bond = 0 + if flag = 0, just count angles/atom + if flag = 1, store them with atoms +------------------------------------------------------------------------- */ + +void Molecule::angles(int flag, char *line) +{ + int tmp,itype; + tagint m,atom1,atom2,atom3; + int newton_bond = force->newton_bond; + + if (flag == 0) + for (int i = 0; i < natoms; i++) count[i] = 0; + else + for (int i = 0; i < natoms; i++) num_angle[i] = 0; + + for (int i = 0; i < nangles; i++) { + readline(line); + if (i == 0) { + int nwords = atom->count_words(line); + if (nwords != 5) + error->all(FLERR,"Invalid Angles section in molecule file"); + } + sscanf(line,"%d %d " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, + &tmp,&itype,&atom1,&atom2,&atom3); + itype += aoffset; + + if (atom1 <= 0 || atom1 > natoms || + atom2 <= 0 || atom2 > natoms || + atom3 <= 0 || atom3 > natoms) + error->one(FLERR,"Invalid atom ID in Angles section of molecule file"); + if (itype <= 0) + error->one(FLERR,"Invalid angle type in Angles section of molecule file"); + + if (flag) { + m = atom2-1; + nangletypes = MAX(nangletypes,itype); + angle_type[m][num_angle[m]] = itype; + angle_atom1[m][num_angle[m]] = atom1; + angle_atom2[m][num_angle[m]] = atom2; + angle_atom3[m][num_angle[m]] = atom3; + num_angle[m]++; + if (newton_bond == 0) { + m = atom1-1; + angle_type[m][num_angle[m]] = itype; + angle_atom1[m][num_angle[m]] = atom1; + angle_atom2[m][num_angle[m]] = atom2; + angle_atom3[m][num_angle[m]] = atom3; + num_angle[m]++; + m = atom3-1; + angle_type[m][num_angle[m]] = itype; + angle_atom1[m][num_angle[m]] = atom1; + angle_atom2[m][num_angle[m]] = atom2; + angle_atom3[m][num_angle[m]] = atom3; + num_angle[m]++; + } + } else { + count[atom2-1]++; + if (newton_bond == 0) { + count[atom1-1]++; + count[atom3-1]++; + } + } + } + + // angle_per_atom = max of count vector + + if (flag == 0) { + angle_per_atom = 0; + for (int i = 0; i < natoms; i++) + angle_per_atom = MAX(angle_per_atom,count[i]); + } +} + +/* ---------------------------------------------------------------------- + read dihedrals from file + store each with all 4 atoms if newton_bond = 0 + if flag = 0, just count dihedrals/atom + if flag = 1, store them with atoms +------------------------------------------------------------------------- */ + +void Molecule::dihedrals(int flag, char *line) +{ + int tmp,itype; + tagint m,atom1,atom2,atom3,atom4; + int newton_bond = force->newton_bond; + + if (flag == 0) + for (int i = 0; i < natoms; i++) count[i] = 0; + else + for (int i = 0; i < natoms; i++) num_dihedral[i] = 0; + + for (int i = 0; i < ndihedrals; i++) { + readline(line); + if (i == 0) { + int nwords = atom->count_words(line); + if (nwords != 6) + error->all(FLERR,"Invalid Dihedrals section in molecule file"); + } + sscanf(line,"%d %d " TAGINT_FORMAT " " TAGINT_FORMAT " " + TAGINT_FORMAT " " TAGINT_FORMAT " ", + &tmp,&itype,&atom1,&atom2,&atom3,&atom4); + itype += doffset; + + if (atom1 <= 0 || atom1 > natoms || + atom2 <= 0 || atom2 > natoms || + atom3 <= 0 || atom3 > natoms || + atom4 <= 0 || atom4 > natoms) + error->one(FLERR, + "Invalid atom ID in dihedrals section of molecule file"); + if (itype <= 0) + error->one(FLERR, + "Invalid dihedral type in dihedrals section of molecule file"); + + if (flag) { + m = atom2-1; + ndihedraltypes = MAX(ndihedraltypes,itype); + dihedral_type[m][num_dihedral[m]] = itype; + dihedral_atom1[m][num_dihedral[m]] = atom1; + dihedral_atom2[m][num_dihedral[m]] = atom2; + dihedral_atom3[m][num_dihedral[m]] = atom3; + dihedral_atom4[m][num_dihedral[m]] = atom4; + num_dihedral[m]++; + if (newton_bond == 0) { + m = atom1-1; + dihedral_type[m][num_dihedral[m]] = itype; + dihedral_atom1[m][num_dihedral[m]] = atom1; + dihedral_atom2[m][num_dihedral[m]] = atom2; + dihedral_atom3[m][num_dihedral[m]] = atom3; + dihedral_atom4[m][num_dihedral[m]] = atom4; + num_dihedral[m]++; + m = atom3-1; + dihedral_type[m][num_dihedral[m]] = itype; + dihedral_atom1[m][num_dihedral[m]] = atom1; + dihedral_atom2[m][num_dihedral[m]] = atom2; + dihedral_atom3[m][num_dihedral[m]] = atom3; + dihedral_atom4[m][num_dihedral[m]] = atom4; + num_dihedral[m]++; + m = atom4-1; + dihedral_type[m][num_dihedral[m]] = itype; + dihedral_atom1[m][num_dihedral[m]] = atom1; + dihedral_atom2[m][num_dihedral[m]] = atom2; + dihedral_atom3[m][num_dihedral[m]] = atom3; + dihedral_atom4[m][num_dihedral[m]] = atom4; + num_dihedral[m]++; + } + } else { + count[atom2-1]++; + if (newton_bond == 0) { + count[atom1-1]++; + count[atom3-1]++; + count[atom4-1]++; + } + } + } + + // dihedral_per_atom = max of count vector + + if (flag == 0) { + dihedral_per_atom = 0; + for (int i = 0; i < natoms; i++) + dihedral_per_atom = MAX(dihedral_per_atom,count[i]); + } +} + +/* ---------------------------------------------------------------------- + read impropers from file + store each with all 4 atoms if newton_bond = 0 + if flag = 0, just count impropers/atom + if flag = 1, store them with atoms +------------------------------------------------------------------------- */ + +void Molecule::impropers(int flag, char *line) +{ + int tmp,itype; + tagint m,atom1,atom2,atom3,atom4; + int newton_bond = force->newton_bond; + + if (flag == 0) + for (int i = 0; i < natoms; i++) count[i] = 0; + else + for (int i = 0; i < natoms; i++) num_improper[i] = 0; + + for (int i = 0; i < nimpropers; i++) { + readline(line); + if (i == 0) { + int nwords = atom->count_words(line); + if (nwords != 6) + error->all(FLERR,"Invalid Impropers section in molecule file"); + } + sscanf(line,"%d %d " TAGINT_FORMAT " " TAGINT_FORMAT " " + TAGINT_FORMAT " " TAGINT_FORMAT " ", + &tmp,&itype,&atom1,&atom2,&atom3,&atom4); + itype += ioffset; + + if (atom1 <= 0 || atom1 > natoms || + atom2 <= 0 || atom2 > natoms || + atom3 <= 0 || atom3 > natoms || + atom4 <= 0 || atom4 > natoms) + error->one(FLERR, + "Invalid atom ID in impropers section of molecule file"); + if (itype <= 0) + error->one(FLERR, + "Invalid improper type in impropers section of molecule file"); + + if (flag) { + m = atom2-1; + nimpropertypes = MAX(nimpropertypes,itype); + improper_type[m][num_improper[m]] = itype; + improper_atom1[m][num_improper[m]] = atom1; + improper_atom2[m][num_improper[m]] = atom2; + improper_atom3[m][num_improper[m]] = atom3; + improper_atom4[m][num_improper[m]] = atom4; + num_improper[m]++; + if (newton_bond == 0) { + m = atom1-1; + improper_type[m][num_improper[m]] = itype; + improper_atom1[m][num_improper[m]] = atom1; + improper_atom2[m][num_improper[m]] = atom2; + improper_atom3[m][num_improper[m]] = atom3; + improper_atom4[m][num_improper[m]] = atom4; + num_improper[m]++; + m = atom3-1; + improper_type[m][num_improper[m]] = itype; + improper_atom1[m][num_improper[m]] = atom1; + improper_atom2[m][num_improper[m]] = atom2; + improper_atom3[m][num_improper[m]] = atom3; + improper_atom4[m][num_improper[m]] = atom4; + num_improper[m]++; + m = atom4-1; + improper_type[m][num_improper[m]] = itype; + improper_atom1[m][num_improper[m]] = atom1; + improper_atom2[m][num_improper[m]] = atom2; + improper_atom3[m][num_improper[m]] = atom3; + improper_atom4[m][num_improper[m]] = atom4; + num_improper[m]++; + } + } else { + count[atom2-1]++; + if (newton_bond == 0) { + count[atom1-1]++; + count[atom3-1]++; + count[atom4-1]++; + } + } + } + + // improper_per_atom = max of count vector + + if (flag == 0) { + improper_per_atom = 0; + for (int i = 0; i < natoms; i++) + improper_per_atom = MAX(improper_per_atom,count[i]); + } +} + +/* ---------------------------------------------------------------------- + read 3 special bonds counts from file + if flag = 0, just tally maxspecial + if flag = 1, store them with atoms +------------------------------------------------------------------------- */ + +void Molecule::nspecial_read(int flag, char *line) +{ + int tmp,c1,c2,c3; + + if (flag == 0) maxspecial = 0; + + for (int i = 0; i < natoms; i++) { + readline(line); + if (i == 0) { + int nwords = atom->count_words(line); + if (nwords != 4) + error->all(FLERR,"Invalid Special Bond Counts section in " + "molecule file"); + } + sscanf(line,"%d %d %d %d",&tmp,&c1,&c2,&c3); + + if (flag) { + nspecial[i][0] = c1; + nspecial[i][1] = c1+c2; + nspecial[i][2] = c1+c2+c3; + } else maxspecial = MAX(maxspecial,c1+c2+c3); + } +} + +/* ---------------------------------------------------------------------- + read special bond indices from file +------------------------------------------------------------------------- */ + +void Molecule::special_read(char *line) +{ + int m,nwords; + char **words = new char*[maxspecial+1]; + + for (int i = 0; i < natoms; i++) { + readline(line); + nwords = parse(line,words,maxspecial+1); + if (nwords != nspecial[i][2]+1) + error->all(FLERR,"Molecule file special list " + "does not match special count"); + + for (m = 1; m < nwords; m++) { + special[i][m-1] = ATOTAGINT(words[m]); + if (special[i][m-1] <= 0 || special[i][m-1] > natoms || + special[i][m-1] == i+1) + error->all(FLERR,"Invalid special atom index in molecule file"); + } + } + + delete [] words; +} + +/* ---------------------------------------------------------------------- + auto generate special bond info +------------------------------------------------------------------------- */ + +void Molecule::special_generate() +{ + int newton_bond = force->newton_bond; + tagint atom1,atom2; + int count[natoms]; + + for (int i = 0; i < natoms; i++) count[i] = 0; + + // 1-2 neighbors + + if (newton_bond) { + for (int i = 0; i < natoms; i++) { + for (int j = 0; j < num_bond[i]; j++) { + atom1 = i; + atom2 = bond_atom[i][j]-1; + nspecial[i][0]++; + nspecial[atom2][0]++; + if (count[i] >= maxspecial || count[atom2] >= maxspecial) + error->one(FLERR,"Molecule auto special bond generation overflow"); + special[i][count[i]++] = atom2 + 1; + special[atom2][count[atom2]++] = i + 1; + } + } + } else { + for (int i = 0; i < natoms; i++) { + nspecial[i][0] = num_bond[i]; + for (int j = 0; j < num_bond[i]; j++) { + atom1 = i; + atom2 = bond_atom[i][j]; + if (count[atom1] >= maxspecial) + error->one(FLERR,"Molecule auto special bond generation overflow"); + special[i][count[atom1]++] = atom2; + } + } + } + + // 1-3 neighbors with no duplicates + + for (int i = 0; i < natoms; i++) nspecial[i][1] = nspecial[i][0]; + + int dedup; + for (int i = 0; i < natoms; i++) { + for (int m = 0; m < nspecial[i][0]; m++) { + for (int j = 0; j < nspecial[special[i][m]-1][0]; j++) { + dedup = 0; + for (int k =0; k < count[i]; k++) { + if (special[special[i][m]-1][j] == special[i][k] || + special[special[i][m]-1][j] == i+1) { + dedup = 1; + } + } + if (!dedup) { + if (count[i] >= maxspecial) + error->one(FLERR,"Molecule auto special bond generation overflow"); + special[i][count[i]++] = special[special[i][m]-1][j]; + nspecial[i][1]++; + } + } + } + } + + // 1-4 neighbors with no duplicates + + for (int i = 0; i < natoms; i++) nspecial[i][2] = nspecial[i][1]; + + for (int i = 0; i < natoms; i++) { + for (int m = nspecial[i][0]; m < nspecial[i][1]; m++) { + for (int j = 0; j < nspecial[special[i][m]-1][0]; j++) { + dedup = 0; + for (int k =0; k < count[i]; k++) { + if (special[special[i][m]-1][j] == special[i][k] || + special[special[i][m]-1][j] == i+1) { + dedup = 1; + } + } + if (!dedup) { + if (count[i] >= maxspecial) + error->one(FLERR,"Molecule auto special bond generation overflow"); + special[i][count[i]++] = special[special[i][m]-1][j]; + nspecial[i][2]++; + } + } + } + } +} + +/* ---------------------------------------------------------------------- + read SHAKE flags from file +------------------------------------------------------------------------- */ + +void Molecule::shakeflag_read(char *line) +{ + int tmp; + for (int i = 0; i < natoms; i++) { + readline(line); + sscanf(line,"%d %d",&tmp,&shake_flag[i]); + } + + for (int i = 0; i < natoms; i++) + if (shake_flag[i] < 0 || shake_flag[i] > 4) + error->all(FLERR,"Invalid shake flag in molecule file"); +} + +/* ---------------------------------------------------------------------- + read SHAKE atom info from file +------------------------------------------------------------------------- */ + +void Molecule::shakeatom_read(char *line) +{ + int tmp; + for (int i = 0; i < natoms; i++) { + readline(line); + if (shake_flag[i] == 1) + sscanf(line,"%d " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, + &tmp,&shake_atom[i][0],&shake_atom[i][1],&shake_atom[i][2]); + else if (shake_flag[i] == 2) + sscanf(line,"%d " TAGINT_FORMAT " " TAGINT_FORMAT, + &tmp,&shake_atom[i][0],&shake_atom[i][1]); + else if (shake_flag[i] == 3) + sscanf(line,"%d " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT, + &tmp,&shake_atom[i][0],&shake_atom[i][1],&shake_atom[i][2]); + else if (shake_flag[i] == 4) + sscanf(line,"%d " TAGINT_FORMAT " " TAGINT_FORMAT " " + TAGINT_FORMAT " " TAGINT_FORMAT, + &tmp,&shake_atom[i][0],&shake_atom[i][1], + &shake_atom[i][2],&shake_atom[i][3]); + } + + for (int i = 0; i < natoms; i++) { + int m = shake_flag[i]; + if (m == 1) m = 3; + for (int j = 0; j < m; j++) + if (shake_atom[i][j] <= 0 || shake_atom[i][j] > natoms) + error->all(FLERR,"Invalid shake atom in molecule file"); + } +} + +/* ---------------------------------------------------------------------- + read SHAKE bond type info from file +------------------------------------------------------------------------- */ + +void Molecule::shaketype_read(char *line) +{ + int tmp; + for (int i = 0; i < natoms; i++) { + readline(line); + if (shake_flag[i] == 1) + sscanf(line,"%d %d %d %d",&tmp, + &shake_type[i][0],&shake_type[i][1],&shake_type[i][2]); + else if (shake_flag[i] == 2) + sscanf(line,"%d %d",&tmp,&shake_type[i][0]); + else if (shake_flag[i] == 3) + sscanf(line,"%d %d %d",&tmp,&shake_type[i][0],&shake_type[i][1]); + else if (shake_flag[i] == 4) + sscanf(line,"%d %d %d %d",&tmp, + &shake_type[i][0],&shake_type[i][1],&shake_type[i][2]); + } + + for (int i = 0; i < natoms; i++) { + int m = shake_flag[i]; + if (m == 1) m = 3; + for (int j = 0; j < m-1; j++) + if (shake_type[i][j] <= 0) + error->all(FLERR,"Invalid shake bond type in molecule file"); + if (shake_flag[i] == 1) + if (shake_type[i][2] <= 0) + error->all(FLERR,"Invalid shake angle type in molecule file"); + } +} + +/* ---------------------------------------------------------------------- + read body params from file + pflag = 0/1 for integer/double params +------------------------------------------------------------------------- */ + +void Molecule::body(int flag, int pflag, char *line) +{ + int i,ncount; + + int nparam = nibody; + if (pflag) nparam = ndbody; + + int nword = 0; + while (nword < nparam) { + readline(line); + + ncount = atom->count_words(line); + if (ncount == 0) + error->one(FLERR,"Too few values in body section of molecule file"); + if (nword+ncount > nparam) + error->all(FLERR,"Too many values in body section of molecule file"); + + if (flag) { + if (pflag == 0) { + ibodyparams[nword++] = force->inumeric(FLERR,strtok(line," \t\n\r\f")); + for (i = 1; i < ncount; i++) + ibodyparams[nword++] = + force->inumeric(FLERR,strtok(NULL," \t\n\r\f")); + } else { + dbodyparams[nword++] = force->numeric(FLERR,strtok(line," \t\n\r\f")); + for (i = 1; i < ncount; i++) + dbodyparams[nword++] = + force->numeric(FLERR,strtok(NULL," \t\n\r\f")); + } + } else nword += ncount; + } +} + +/* ---------------------------------------------------------------------- + error check molecule attributes and topology against system settings + flag = 0, just check this molecule + flag = 1, check all molecules in set, this is 1st molecule in set +------------------------------------------------------------------------- */ + +void Molecule::check_attributes(int flag) +{ + int n = 1; + if (flag) n = nset; + int imol = atom->find_molecule(id); + + for (int i = imol; i < imol+n; i++) { + Molecule *onemol = atom->molecules[imol]; + + // check per-atom attributes of molecule + // warn if not a match + + int mismatch = 0; + if (onemol->replambdaHflag && !atom->replambdaH_flag) mismatch = 1; + if (onemol->moltypeHflag && !atom->moltypeH_flag) mismatch = 1; + if (onemol->qflag && !atom->q_flag) mismatch = 1; + if (onemol->radiusflag && !atom->radius_flag) mismatch = 1; + if (onemol->rmassflag && !atom->rmass_flag) mismatch = 1; + + if (mismatch && me == 0) + error->warning(FLERR, + "Molecule attributes do not match system attributes"); + + // for all atom styles, check nbondtype,etc + + mismatch = 0; + if (atom->nbondtypes < onemol->nbondtypes) mismatch = 1; + if (atom->nangletypes < onemol->nangletypes) mismatch = 1; + if (atom->ndihedraltypes < onemol->ndihedraltypes) mismatch = 1; + if (atom->nimpropertypes < onemol->nimpropertypes) mismatch = 1; + + if (mismatch) + error->all(FLERR,"Molecule topology type exceeds system topology type"); + + // for molecular atom styles, check bond_per_atom,etc + maxspecial + // do not check for atom style template, since nothing stored per atom + + if (atom->molecular == 1) { + if (atom->avec->bonds_allow && + atom->bond_per_atom < onemol->bond_per_atom) mismatch = 1; + if (atom->avec->angles_allow && + atom->angle_per_atom < onemol->angle_per_atom) mismatch = 1; + if (atom->avec->dihedrals_allow && + atom->dihedral_per_atom < onemol->dihedral_per_atom) mismatch = 1; + if (atom->avec->impropers_allow && + atom->improper_per_atom < onemol->improper_per_atom) mismatch = 1; + if (atom->maxspecial < onemol->maxspecial) mismatch = 1; + + if (mismatch) + error->all(FLERR,"Molecule toplogy/atom exceeds system topology/atom"); + } + + // warn if molecule topology defined but no special settings + + if (onemol->bondflag && !onemol->specialflag) + if (me == 0) error->warning(FLERR,"Molecule has bond topology " + "but no special bond settings"); + } +} + +/* ---------------------------------------------------------------------- + init all data structures to empty +------------------------------------------------------------------------- */ + +void Molecule::initialize() +{ + natoms = 0; + nbonds = nangles = ndihedrals = nimpropers = 0; + ntypes = 0; + nbondtypes = nangletypes = ndihedraltypes = nimpropertypes = 0; + nibody = ndbody = 0; + + bond_per_atom = angle_per_atom = dihedral_per_atom = improper_per_atom = 0; + maxspecial = 0; + + xflag = typeflag = qflag = radiusflag = rmassflag = 0; + bondflag = angleflag = dihedralflag = improperflag = 0; + nspecialflag = specialflag = 0; + shakeflag = shakeflagflag = shakeatomflag = shaketypeflag = 0; + bodyflag = ibodyflag = dbodyflag = 0; + + centerflag = massflag = comflag = inertiaflag = 0; + tag_require = 0; + + x = NULL; + type = NULL; + q = NULL; + radius = NULL; + rmass = NULL; + + num_bond = NULL; + bond_type = NULL; + bond_atom = NULL; + + num_angle = NULL; + angle_type = NULL; + angle_atom1 = angle_atom2 = angle_atom3 = NULL; + + num_dihedral = NULL; + dihedral_type = NULL; + dihedral_atom1 = dihedral_atom2 = dihedral_atom3 = dihedral_atom4 = NULL; + + num_improper = NULL; + improper_type = NULL; + improper_atom1 = improper_atom2 = improper_atom3 = improper_atom4 = NULL; + + nspecial = NULL; + special = NULL; + + shake_flag = NULL; + shake_atom = NULL; + shake_type = NULL; + + ibodyparams = NULL; + dbodyparams = NULL; + + dx = NULL; + dxcom = NULL; + dxbody = NULL; +} + +/* ---------------------------------------------------------------------- + allocate all data structures + also initialize values for data structures that are always allocated +------------------------------------------------------------------------- */ + +void Molecule::allocate() +{ + if (xflag) memory->create(x,natoms,3,"molecule:x"); + if (typeflag) memory->create(type,natoms,"molecule:type"); + if (qflag) memory->create(q,natoms,"molecule:q"); + if (radiusflag) memory->create(radius,natoms,"molecule:radius"); + if (rmassflag) memory->create(rmass,natoms,"molecule:rmass"); + if (replambdaHflag) memory->create(replambdaH,natoms,"molecule:replambdaH"); + if (moltypeHflag) memory->create(moltypeH,natoms,"molecule:moltypeH"); + + // always allocate num_bond,num_angle,etc and special+nspecial + // even if not in molecule file, initialize to 0 + // this is so methods that use these arrays don't have to check they exist + + memory->create(num_bond,natoms,"molecule:num_bond"); + for (int i = 0; i < natoms; i++) num_bond[i] = 0; + memory->create(num_angle,natoms,"molecule:num_angle"); + for (int i = 0; i < natoms; i++) num_angle[i] = 0; + memory->create(num_dihedral,natoms,"molecule:num_dihedral"); + for (int i = 0; i < natoms; i++) num_dihedral[i] = 0; + memory->create(num_improper,natoms,"molecule:num_improper"); + for (int i = 0; i < natoms; i++) num_improper[i] = 0; + + memory->create(special,natoms,maxspecial,"molecule:special"); + + memory->create(nspecial,natoms,3,"molecule:nspecial"); + for (int i = 0; i < natoms; i++) + nspecial[i][0] = nspecial[i][1] = nspecial[i][2] = 0; + + if (bondflag) { + memory->create(bond_type,natoms,bond_per_atom, + "molecule:bond_type"); + memory->create(bond_atom,natoms,bond_per_atom, + "molecule:bond_atom"); + } + + if (angleflag) { + memory->create(angle_type,natoms,angle_per_atom, + "molecule:angle_type"); + memory->create(angle_atom1,natoms,angle_per_atom, + "molecule:angle_atom1"); + memory->create(angle_atom2,natoms,angle_per_atom, + "molecule:angle_atom2"); + memory->create(angle_atom3,natoms,angle_per_atom, + "molecule:angle_atom3"); + } + + if (dihedralflag) { + memory->create(dihedral_type,natoms,dihedral_per_atom, + "molecule:dihedral_type"); + memory->create(dihedral_atom1,natoms,dihedral_per_atom, + "molecule:dihedral_atom1"); + memory->create(dihedral_atom2,natoms,dihedral_per_atom, + "molecule:dihedral_atom2"); + memory->create(dihedral_atom3,natoms,dihedral_per_atom, + "molecule:dihedral_atom3"); + memory->create(dihedral_atom4,natoms,dihedral_per_atom, + "molecule:dihedral_atom4"); + } + + if (improperflag) { + memory->create(improper_type,natoms,improper_per_atom, + "molecule:improper_type"); + memory->create(improper_atom1,natoms,improper_per_atom, + "molecule:improper_atom1"); + memory->create(improper_atom2,natoms,improper_per_atom, + "molecule:improper_atom2"); + memory->create(improper_atom3,natoms,improper_per_atom, + "molecule:improper_atom3"); + memory->create(improper_atom4,natoms,improper_per_atom, + "molecule:improper_atom4"); + } + + if (shakeflag) { + memory->create(shake_flag,natoms,"molecule:shake_flag"); + memory->create(shake_atom,natoms,4,"molecule:shake_flag"); + memory->create(shake_type,natoms,3,"molecule:shake_flag"); + } + + if (bodyflag) { + if (nibody) memory->create(ibodyparams,nibody,"molecule:ibodyparams"); + if (ndbody) memory->create(dbodyparams,ndbody,"molecule:dbodyparams"); + } +} + +/* ---------------------------------------------------------------------- + deallocate all data structures +------------------------------------------------------------------------- */ + +void Molecule::deallocate() +{ + memory->destroy(x); + memory->destroy(type); + memory->destroy(q); + memory->destroy(radius); + memory->destroy(replambdaH); + memory->destroy(moltypeH); + memory->destroy(rmass); + + memory->destroy(num_bond); + memory->destroy(bond_type); + memory->destroy(bond_atom); + + memory->destroy(num_angle); + memory->destroy(angle_type); + memory->destroy(angle_atom1); + memory->destroy(angle_atom2); + memory->destroy(angle_atom3); + + memory->destroy(num_dihedral); + memory->destroy(dihedral_type); + memory->destroy(dihedral_atom1); + memory->destroy(dihedral_atom2); + memory->destroy(dihedral_atom3); + memory->destroy(dihedral_atom4); + + memory->destroy(num_improper); + memory->destroy(improper_type); + memory->destroy(improper_atom1); + memory->destroy(improper_atom2); + memory->destroy(improper_atom3); + memory->destroy(improper_atom4); + + memory->destroy(nspecial); + memory->destroy(special); + + memory->destroy(shake_flag); + memory->destroy(shake_atom); + memory->destroy(shake_type); + + memory->destroy(dx); + memory->destroy(dxcom); + memory->destroy(dxbody); + + memory->destroy(ibodyparams); + memory->destroy(dbodyparams); +} + +/* ---------------------------------------------------------------------- + open molecule file +------------------------------------------------------------------------- */ + +void Molecule::open(char *file) +{ + fp = fopen(file,"r"); + if (fp == NULL) { + char str[128]; + sprintf(str,"Cannot open molecule file %s",file); + error->one(FLERR,str); + } +} + +/* ---------------------------------------------------------------------- + read and bcast a line +------------------------------------------------------------------------- */ + +void Molecule::readline(char *line) +{ + int n; + if (me == 0) { + if (fgets(line,MAXLINE,fp) == NULL) n = 0; + else n = strlen(line) + 1; + } + MPI_Bcast(&n,1,MPI_INT,0,world); + if (n == 0) error->all(FLERR,"Unexpected end of molecule file"); + MPI_Bcast(line,n,MPI_CHAR,0,world); +} + +/* ---------------------------------------------------------------------- + extract keyword from line + flag = 0, read and bcast line + flag = 1, line has already been read +------------------------------------------------------------------------- */ + +void Molecule::parse_keyword(int flag, char *line, char *keyword) +{ + if (flag) { + + // read upto non-blank line plus 1 following line + // eof is set to 1 if any read hits end-of-file + + int eof = 0; + if (me == 0) { + if (fgets(line,MAXLINE,fp) == NULL) eof = 1; + while (eof == 0 && strspn(line," \t\n\r") == strlen(line)) { + if (fgets(line,MAXLINE,fp) == NULL) eof = 1; + } + if (fgets(keyword,MAXLINE,fp) == NULL) eof = 1; + } + + // if eof, set keyword empty and return + + MPI_Bcast(&eof,1,MPI_INT,0,world); + if (eof) { + keyword[0] = '\0'; + return; + } + + // bcast keyword line to all procs + + int n; + if (me == 0) n = strlen(line) + 1; + MPI_Bcast(&n,1,MPI_INT,0,world); + MPI_Bcast(line,n,MPI_CHAR,0,world); + } + + // copy non-whitespace portion of line into keyword + + int start = strspn(line," \t\n\r"); + int stop = strlen(line) - 1; + while (line[stop] == ' ' || line[stop] == '\t' + || line[stop] == '\n' || line[stop] == '\r') stop--; + line[stop+1] = '\0'; + strcpy(keyword,&line[start]); +} + +/* ---------------------------------------------------------------------- + skip N lines of file +------------------------------------------------------------------------- */ + +void Molecule::skip_lines(int n, char *line) +{ + for (int i = 0; i < n; i++) readline(line); +} + +/* ---------------------------------------------------------------------- + parse line into words separated by whitespace + return # of words + max = max pointers storable in words +------------------------------------------------------------------------- */ + +int Molecule::parse(char *line, char **words, int max) +{ + char *ptr; + + int nwords = 0; + words[nwords++] = strtok(line," \t\n\r\f"); + + while ((ptr = strtok(NULL," \t\n\r\f"))) { + if (nwords < max) words[nwords] = ptr; + nwords++; + } + + return nwords; +} + +/* ---------------------------------------------------------------------- + proc 0 prints molecule params +------------------------------------------------------------------------- */ + +/* + +void Molecule::print() +{ + printf("MOLECULE %s\n",id); + printf(" %d natoms\n",natoms); + if (nbonds) printf(" %d nbonds\n",nbonds); + if (nangles) printf(" %d nangles\n",nangles); + if (ndihedrals) printf(" %d ndihedrals\n",ndihedrals); + if (nimpropers) printf(" %d nimpropers\n",nimpropers); + + if (xflag) { + printf( "Coords:\n"); + for (int i = 0; i < natoms; i++) + printf(" %d %g %g %g\n",i+1,x[i][0],x[i][1],x[i][2]); + } + if (typeflag) { + printf( "Types:\n"); + for (int i = 0; i < natoms; i++) + printf(" %d %d\n",i+1,type[i]); + } + if (qflag) { + printf( "Charges:\n"); + for (int i = 0; i < natoms; i++) + printf(" %d %g\n",i+1,q[i]); + } + if (radiusflag) { + printf( "Radii:\n"); + for (int i = 0; i < natoms; i++) + printf(" %d %g\n",i+1,radius[i]); + } + if (rmassflag) { + printf( "Masses:\n"); + for (int i = 0; i < natoms; i++) + printf(" %d %g\n",i+1,rmass[i]); + } + + if (bondflag) { + printf( "Bonds:\n"); + for (int i = 0; i < natoms; i++) { + printf(" %d %d\n",i+1,num_bond[i]); + for (int j = 0; j < num_bond[i]; j++) + printf(" %d %d %d %d\n",j+1,bond_type[i][j],i+1,bond_atom[i][j]); + } + } + if (angleflag) { + printf( "Angles:\n"); + for (int i = 0; i < natoms; i++) { + printf(" %d %d\n",i+1,num_angle[i]); + for (int j = 0; j < num_angle[i]; j++) + printf(" %d %d %d %d %d\n", + j+1,angle_type[i][j], + angle_atom1[i][j],angle_atom2[i][j],angle_atom3[i][j]); + } + } + if (dihedralflag) { + printf( "Dihedrals:\n"); + for (int i = 0; i < natoms; i++) { + printf(" %d %d\n",i+1,num_dihedral[i]); + for (int j = 0; j < num_dihedral[i]; j++) + printf(" %d %d %d %d %d %d\n", + j+1,dihedral_type[i][j], + dihedral_atom1[i][j],dihedral_atom2[i][j], + dihedral_atom3[i][j],dihedral_atom4[i][j]); + } + } + if (improperflag) { + printf( "Impropers:\n"); + for (int i = 0; i < natoms; i++) { + printf(" %d %d\n",i+1,num_improper[i]); + for (int j = 0; j < num_improper[i]; j++) + printf(" %d %d %d %d %d %d\n", + j+1,improper_type[i][j], + improper_atom1[i][j],improper_atom2[i][j], + improper_atom3[i][j],improper_atom4[i][j]); + } + } + + if (specialflag) { + printf( "Special neighs:\n"); + for (int i = 0; i < natoms; i++) { + printf(" %d %d %d %d\n",i+1, + nspecial[i][0],nspecial[i][1]-nspecial[i][0], + nspecial[i][2]-nspecial[i][1]); + printf(" "); + for (int j = 0; j < nspecial[i][2]; j++) + printf(" %d",special[i][j]); + printf("\n"); + } + } +} + +*/ diff --git a/src/USER-HADRESS/molecule.h b/src/USER-HADRESS/molecule.h new file mode 100644 index 000000000..4521fc45b --- /dev/null +++ b/src/USER-HADRESS/molecule.h @@ -0,0 +1,432 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifndef LMP_ONE_MOLECULE_H +#define LMP_ONE_MOLECULE_H + +#include "pointers.h" + +namespace LAMMPS_NS { + +class Molecule : protected Pointers { + public: + char *id; // template id of this molecule, same for all molecules in set + int nset; // if first in set, # of molecules in this set + // else 0 if not first in set + int last; // 1 if last molecule in set, else 0 + + // number of atoms,bonds,etc in molecule + // nibody,ndbody = # of integer/double fields in body + + int natoms; + int nbonds,nangles,ndihedrals,nimpropers; + int ntypes; + int nbondtypes,nangletypes,ndihedraltypes,nimpropertypes; + int nibody,ndbody; + + // max bond,angle,etc per atom + + int bond_per_atom,angle_per_atom,dihedral_per_atom,improper_per_atom; + int maxspecial; + + // 1 if attribute defined in file, 0 if not + + int xflag,typeflag,qflag,radiusflag,rmassflag; + int replambdaHflag,moltypeHflag; + int bondflag,angleflag,dihedralflag,improperflag; + int nspecialflag,specialflag; + int shakeflag,shakeflagflag,shakeatomflag,shaketypeflag; + int bodyflag,ibodyflag,dbodyflag; + + // 1 if attribute defined or computed, 0 if not + + int centerflag,massflag,comflag,inertiaflag; + + // 1 if molecule fields require atom IDs + + int tag_require; + + // attributes + + double **x; // displacement of each atom from origin + int *type; // type of each atom + double *q; // charge on each atom + + int *replambdaH; // replambdaH on each atom + int *moltypeH; // moltypeH on each atom + + double *radius; // radius of each atom + double *rmass; // mass of each atom + + int *num_bond; // bonds, angles, dihedrals, impropers for each atom + int **bond_type; + tagint **bond_atom; + + int *num_angle; + int **angle_type; + tagint **angle_atom1,**angle_atom2,**angle_atom3; + + int *num_dihedral; + int **dihedral_type; + tagint **dihedral_atom1,**dihedral_atom2,**dihedral_atom3,**dihedral_atom4; + + int *num_improper; + int **improper_type; + tagint **improper_atom1,**improper_atom2,**improper_atom3,**improper_atom4; + + int **nspecial; + tagint **special; + + int *shake_flag; + tagint **shake_atom; + int **shake_type; + + class AtomVecBody *avec_body; + int *ibodyparams; // integer and double body params + double *dbodyparams; + + double center[3]; // geometric center of molecule + double masstotal; // total mass of molecule + double com[3]; // center of mass of molecule + double itensor[6]; // moments of inertia of molecule + double inertia[3]; // principal moments of inertia of molecule + double ex[3],ey[3],ez[3]; // principal axes of molecule in space coords + double quat[4]; // quaternion for orientation of molecule + + double maxradius; // max radius of any atom in molecule + double molradius; // radius of molecule from geometric center + // including finite-size particle radii + int comatom; // index (1-Natom) of atom closest to COM + double maxextent; // furthest any atom in molecule is from comatom + + double **dx; // displacement of each atom relative to center + double **dxcom; // displacement of each atom relative to COM + double **dxbody; // displacement of each atom relative to COM + // in body frame (diagonalized interia tensor) + + double *quat_external; // orientation imposed by external class + // e.g. FixPour or CreateAtoms + + Molecule(class LAMMPS *, int, char **, int &); + ~Molecule(); + void compute_center(); + void compute_mass(); + void compute_com(); + void compute_inertia(); + void check_attributes(int); + + private: + int me; + FILE *fp; + int *count; + int toffset,boffset,aoffset,doffset,ioffset; + int autospecial; + double sizescale; + + void read(int); + void coords(char *); + void types(char *); + void charges(char *); + void representative_atom(char *); + void moltype_atom(char *); + void diameters(char *); + void masses(char *); + void bonds(int, char *); + void angles(int, char *); + void dihedrals(int, char *); + void impropers(int, char *); + void nspecial_read(int, char *); + void special_read(char *); + void special_generate(); + void shakeflag_read(char *); + void shakeatom_read(char *); + void shaketype_read(char *); + void body(int, int, char *); + + void initialize(); + void allocate(); + void deallocate(); + + void open(char *); + void readline(char *); + void parse_keyword(int, char *, char *); + void skip_lines(int, char *); + int parse(char *, char **, int); + + // void print(); +}; + +} + +#endif + +/* ERROR/WARNING messages: + +E: Illegal ... command + +Self-explanatory. Check the input script syntax and compare to the +documentation for the command. You can use -echo screen as a +command-line option when running LAMMPS to see the offending line. + +E: Molecule template ID must be alphanumeric or underscore characters + +Self-explanatory. + +E: Insufficient Jacobi rotations for rigid molecule + +Eigensolve for rigid body was not sufficiently accurate. + +E: Unexpected end of molecule file + +Self-explanatory. + +E: Molecule file z center-of-mass must be 0.0 for 2d + +Self-explanatory. + +E: Molecule file requires atom style body + +Self-explanatory. + +E: No count or invalid atom count in molecule file + +The number of atoms must be specified. + +E: Invalid bond count in molecule file + +Self-explanatory. + +E: Invalid angle count in molecule file + +Self-explanatory. + +E: Invalid dihedral count in molecule file + +Self-explanatory. + +E: Invalid improper count in molecule file + +Self-explanatory. + +E: Molecule file has bonds but no nbonds setting + +Self-explanatory. + +E: Molecule file has angles but no nangles setting + +Self-explanatory. + +E: Molecule file has dihedrals but no ndihedrals setting + +Self-explanatory. + +E: Molecule file has impropers but no nimpropers setting + +Self-explanatory. + +E: Molecule file shake flags not before shake atoms + +The order of the two sections is important. + +E: Molecule file shake flags not before shake bonds + +The order of the two sections is important. + +E: Molecule file has body params but no setting for them + +Self-explanatory. + +E: Unknown section in molecule file + +Self-explanatory. + +E: Molecule file needs both Special Bond sections + +Self-explanatory. + +E: Molecule file has special flags but no bonds + +Self-explanatory. + +E: Molecule file shake info is incomplete + +All 3 SHAKE sections are needed. + +E: Molecule file has no Body Integers section + +Self-explanatory. + +E: Molecule file has no Body Doubles section + +Self-explanatory. + +E: Molecule natoms must be 1 for body particle + +Self-explanatory. + +E: Molecule sizescale must be 1.0 for body particle + +Self-explanatory. + +E: Invalid Coords section in molecule file + +Self-explanatory. + +E: Molecule file z coord must be 0.0 for 2d + +Self-explanatory. + +E: Invalid Types section in molecule file + +Self-explanatory. + +E: Invalid atom type in molecule file + +Atom types must range from 1 to specified # of types. + +E: Invalid Charges section in molecule file + +Self-explanatory. + +E: Invalid Diameters section in molecule file + +Self-explanatory. + +E: Invalid atom diameter in molecule file + +Diameters must be >= 0.0. + +E: Invalid Masses section in molecule file + +Self-explanatory. + +E: Invalid atom mass in molecule file + +Masses must be > 0.0. + +E: Invalid Bonds section in molecule file + +Self-explanatory. + +E: Invalid atom ID in Bonds section of molecule file + +Self-explanatory. + +E: Invalid bond type in Bonds section of molecule file + +Self-explanatory. + +E: Invalid Angles section in molecule file + +Self-explanatory. + +E: Invalid atom ID in Angles section of molecule file + +Self-explanatory. + +E: Invalid angle type in Angles section of molecule file + +Self-explanatory. + +E: Invalid Dihedrals section in molecule file + +Self-explanatory. + +E: Invalid atom ID in dihedrals section of molecule file + +Self-explanatory. + +E: Invalid dihedral type in dihedrals section of molecule file + +Self-explanatory. + +E: Invalid Impropers section in molecule file + +Self-explanatory. + +E: Invalid atom ID in impropers section of molecule file + +Self-explanatory. + +E: Invalid improper type in impropers section of molecule file + +Self-explanatory. + +E: Invalid Special Bond Counts section in molecule file + +Self-explanatory. + +E: Molecule file special list does not match special count + +The number of values in an atom's special list does not match count. + +E: Invalid special atom index in molecule file + +Self-explanatory. + +E: Molecule auto special bond generation overflow + +Counts exceed maxspecial setting for other atoms in system. + +E: Invalid shake flag in molecule file + +Self-explanatory. + +E: Invalid shake atom in molecule file + +Self-explanatory. + +E: Invalid shake bond type in molecule file + +Self-explanatory. + +E: Invalid shake angle type in molecule file + +Self-explanatory. + +E: Too few values in body section of molecule file + +Self-explanatory. + +E: Too many values in body section of molecule file + +Self-explanatory. + +W: Molecule attributes do not match system attributes + +An attribute is specified (e.g. diameter, charge) that is +not defined for the specified atom style. + +E: Molecule topology type exceeds system topology type + +The number of bond, angle, etc types in the molecule exceeds the +system setting. See the create_box command for how to specify these +values. + +E: Molecule toplogy/atom exceeds system topology/atom + +The number of bonds, angles, etc per-atom in the molecule exceeds the +system setting. See the create_box command for how to specify these +values. + +W: Molecule has bond topology but no special bond settings + +This means the bonded atoms will not be excluded in pair-wise +interactions. + +E: Cannot open molecule file %s + +The specified file cannot be opened. Check that the path and name are +correct. + +*/ diff --git a/src/USER-HADRESS/pair_lj_cut_coul_dsf_hars_at.cpp b/src/USER-HADRESS/pair_lj_cut_coul_dsf_hars_at.cpp new file mode 100644 index 000000000..5a60d7ef7 --- /dev/null +++ b/src/USER-HADRESS/pair_lj_cut_coul_dsf_hars_at.cpp @@ -0,0 +1,971 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Maziar Heidari, + Robinson Cortes-Huerto, + Davide Donadio and + Raffaello Potestio + (Max Planck Institute for Polymer Research, 2015-2016) +------------------------------------------------------------------------- */ + +#include "math.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "pair_lj_cut_coul_dsf_hars_at.h" +#include "atom.h" +#include "comm.h" +#include "force.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "memory.h" +#include "math_const.h" +#include "error.h" +#include "fix_lambdah_calc.h" +#include "update.h" + + +using namespace LAMMPS_NS; +using namespace MathConst; +#define BIG MAXTAGINT + + +#define EWALD_F 1.12837917 +#define EWALD_P 0.3275911 +#define A1 0.254829592 +#define A2 -0.284496736 +#define A3 1.421413741 +#define A4 -1.453152027 +#define A5 1.061405429 + +/* ---------------------------------------------------------------------- */ + +PairLJCutCoulDSFHARSAT::PairLJCutCoulDSFHARSAT(LAMMPS *lmp) : Pair(lmp) +{ + single_enable = 0; + + AT_molmap_H = NULL; + nmolecules = molecules_in_group(idlo,idhi); + + H_AdResS_allocated = 0; + + AT_Pressure_Compensation_Run = 0; + Comp_Counter_H = 0; + memory->create(AT_massproc_H,nmolecules,"pair:AT_massproc_H"); + memory->create(AT_masstotal_H,nmolecules,"pair:AT_masstotal_H"); + memory->create(AT_mol_f_H,nmolecules,3,"pair:AT_mol_f_H"); + memory->create(AT_mol_f_all_H,nmolecules,3,"pair:AT_mol_f_all_H"); + + + // compute masstotal for each molecule + MPI_Comm_rank(world, &me); + int *mask = atom->mask; + tagint *molecule = atom->molecule; + int *type = atom->type; + double *mass = atom->mass; + double *rmass = atom->rmass; + int nlocal = atom->nlocal; + + tagint imol; + double massone; + + for (int i = 0; i < nmolecules; i++) AT_massproc_H[i] = 0.0; + + + for (int i = 0; i < nlocal; i++) + { +// if (mask[i] & groupbit) { + if (mask[i]) { + if (rmass) massone = rmass[i]; + else massone = mass[type[i]]; + imol = molecule[i]; + if (AT_molmap_H) imol = AT_molmap_H[imol-idlo]; + else imol--; + AT_massproc_H[imol] += massone; + + } + } + + MPI_Allreduce(AT_massproc_H,AT_masstotal_H,nmolecules,MPI_DOUBLE,MPI_SUM,world); + +} + +/* ---------------------------------------------------------------------- */ + +PairLJCutCoulDSFHARSAT::~PairLJCutCoulDSFHARSAT() +{ + if (allocated) { + memory->destroy(setflag); + memory->destroy(cutsq); + + memory->destroy(cut_lj); + memory->destroy(cut_ljsq); + memory->destroy(epsilon); + memory->destroy(sigma); + memory->destroy(lj1); + memory->destroy(lj2); + memory->destroy(lj3); + memory->destroy(lj4); + memory->destroy(offset); + } +} + +/* ---------------------------------------------------------------------- */ + +void PairLJCutCoulDSFHARSAT::compute(int eflag, int vflag) +{ + int i,j,ii,jj,inum,jnum,itype,jtype; + double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,evdwl,ecoul,fpair; + double r,rsq,r2inv,r6inv,forcecoul,forcelj,factor_coul,factor_lj,Vij_Coul,Vij_Lj;; + double prefactor,erfcc,erfcd,t; + int *ilist,*jlist,*numneigh,**firstneigh; + int imoltypeH,jmoltypeH; + + evdwl = ecoul = 0.0; + if (eflag || vflag) ev_setup(eflag,vflag); + else evflag = vflag_fdotr = 0; + + double **x = atom->x; + double **f = atom->f; + double *q = atom->q; + double *lambdaH = atom->lambdaH; + double **gradlambdaH = atom->gradlambdaH; + + int *type = atom->type; + int nlocal = atom->nlocal; + double *special_lj = force->special_lj; + double *special_coul = force->special_coul; + int newton_pair = force->newton_pair; + double qqrd2e = force->qqrd2e; + int imol,jmol; + tagint *molecule = atom->molecule; + double *mass = atom->mass; + int *replambdaH = atom->replambdaH; + int *moltypeH = atom->moltypeH; + + int ibin, jbin; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + double xtmpj, iLambda, jLambda, ijLambda; + + int This_Step = update->ntimestep; + if(This_Step >= AT_Update_Time_Begin && This_Step <= AT_Update_Time_End && AT_Pressure_Comp_Flag != 0) AT_Pressure_Compensation_Run = 1; + + + for (int i = 0; i < nmolecules; i++) { + AT_mol_f_H[i][0] = AT_mol_f_H[i][1] = AT_mol_f_H[i][2] = 0; + AT_mol_f_all_H[i][0] = AT_mol_f_all_H[i][1] = AT_mol_f_all_H[i][2] = 0; + } + + // loop over neighbors of my atoms +// if(update->ntimestep<AT_Restart_Time_Step+1)return; + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + qtmp = q[i]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + itype = type[i]; + imoltypeH = moltypeH[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + iLambda = lambdaH[i]; + + if (eflag) { + double e_self = -(e_shift/2.0 + alpha/MY_PIS) * qtmp*qtmp*qqrd2e; +// e_self = 0; + ev_tally(i,i,nlocal,0,0.0,e_self,0.0,0.0,0.0,0.0); + } + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + factor_lj = special_lj[sbmask(j)]; + factor_coul = special_coul[sbmask(j)]; + j &= NEIGHMASK; + + jLambda = lambdaH[j]; + + if(iLambda==0 && jLambda==0 && AllAtomistic!=1)continue; + + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx*delx + dely*dely + delz*delz; + jtype = type[j]; + jmoltypeH = moltypeH[j]; + + imol = molecule[i]; + jmol = molecule[j]; + if (AT_molmap_H) { + imol = AT_molmap_H[imol-idlo]; + jmol = AT_molmap_H[jmol-idlo]; + } + else { + imol--; + jmol--; + } + +// if(imol == jmol)continue; + if (rsq < cutsq[itype][jtype]) { + r2inv = 1.0/rsq; + + if (rsq < cut_ljsq[itype][jtype]) { + r6inv = r2inv*r2inv*r2inv; + forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); + } else forcelj = 0.0; + + if (rsq < cut_coulsq) { + r = sqrt(rsq); + prefactor = factor_coul * qqrd2e*qtmp*q[j]/r; + erfcd = exp(-alpha*alpha*r*r); + t = 1.0 / (1.0 + EWALD_P*alpha*r); + erfcc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * erfcd; + forcecoul = prefactor * (erfcc/r + 2.0*alpha/MY_PIS * erfcd + + r*f_shift) * r; + } else forcecoul = 0.0; + + if(((iLambda==1 && jLambda==1) || AllAtomistic)){ + + fpair = (forcecoul + factor_lj*forcelj) * r2inv; + f[i][0] += delx*fpair; + f[i][1] += dely*fpair; + f[i][2] += delz*fpair; + + if (newton_pair || j < nlocal) { + f[j][0] -= delx*fpair; + f[j][1] -= dely*fpair; + f[j][2] -= delz*fpair; + } + + if (eflag) { + if (rsq < cut_ljsq[itype][jtype]) { + evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - + offset[itype][jtype]; + evdwl *= factor_lj; + } else evdwl = 0.0; + + if (rsq < cut_coulsq) { + ecoul = prefactor * (erfcc - r*e_shift - rsq*f_shift); + } else ecoul = 0.0; + } + if (evflag) ev_tally(i,j,nlocal,newton_pair, + evdwl,ecoul,fpair,delx,dely,delz); + } + + else if(iLambda !=0 || jLambda != 0){ + + ijLambda = 0.5 * (iLambda + jLambda); + fpair = (forcecoul + factor_lj*forcelj) *ijLambda* r2inv; + + if (rsq < cut_coulsq) + Vij_Coul = 0.5*prefactor * (erfcc - r*e_shift - rsq*f_shift); + else Vij_Coul = 0.0; + + + if (rsq < cut_ljsq[itype][jtype]) + Vij_Lj = 0.5*factor_lj*(r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - + offset[itype][jtype]); + else Vij_Lj = 0; + + f[i][0] += delx*fpair; + f[i][1] += dely*fpair; + f[i][2] += delz*fpair; + + ibin = floor(iLambda/AT_lambda_Increment); + if(ibin==AT_Bin_Num)ibin = AT_Bin_Num - 1; + + if(AT_Pressure_Compensation_Run != 0 && iLambda != 0 && iLambda != 1)Comp_Energy_H[ibin][imoltypeH-1] += Vij_Coul+Vij_Lj; + + AT_mol_f_H[imol][0] += -(Vij_Coul+Vij_Lj)*gradlambdaH[i][0]; + AT_mol_f_H[imol][1] += -(Vij_Coul+Vij_Lj)*gradlambdaH[i][1]; + AT_mol_f_H[imol][2] += -(Vij_Coul+Vij_Lj)*gradlambdaH[i][2]; + + if (newton_pair || j < nlocal) { + f[j][0] -= delx*fpair; + f[j][1] -= dely*fpair; + f[j][2] -= delz*fpair; + + jbin = floor(jLambda/AT_lambda_Increment); + if(jbin==AT_Bin_Num)jbin = AT_Bin_Num - 1; + + if(AT_Pressure_Compensation_Run != 0 && jLambda != 0 && jLambda != 1)Comp_Energy_H[jbin][jmoltypeH-1] += Vij_Coul+Vij_Lj; + + AT_mol_f_H[jmol][0] += -(Vij_Coul+Vij_Lj)*gradlambdaH[j][0]; + AT_mol_f_H[jmol][1] += -(Vij_Coul+Vij_Lj)*gradlambdaH[j][1]; + AT_mol_f_H[jmol][2] += -(Vij_Coul+Vij_Lj)*gradlambdaH[j][2]; + + } + + if (eflag) { + ecoul = ijLambda*Vij_Coul*2.0; + evdwl = ijLambda*Vij_Lj*2.0; + + } + if (evflag) ev_tally(i,j,nlocal,newton_pair, + evdwl,ecoul,fpair,delx,dely,delz); + } + + + + } + } + } + + MPI_Allreduce(&AT_mol_f_H[0][0],&AT_mol_f_all_H[0][0],3*nmolecules,MPI_DOUBLE,MPI_SUM,world); + + if(AT_Pressure_Compensation_Run != 0 && AT_Pressure_Comp_Flag != 0){ + + for (int i = 0; i < nlocal; i++){ + iLambda = lambdaH[i]; + if(replambdaH[i]!=0 && iLambda != 0 && iLambda != 1){ + ibin = floor(iLambda/AT_lambda_Increment); + if(ibin==AT_Bin_Num)ibin = AT_Bin_Num - 1; + imoltypeH = moltypeH[i]-1; + Comp_Energy_Num_H[ibin][imoltypeH]++; + } + } + + if(This_Step % AT_Update_Frequency == 0)AT_Update_Compensation_Energy(); + + } + + + if(This_Step == AT_Update_Time_End && AT_Pressure_Compensation_Run != 0)AT_Print_Compensation_Energy(); + + double mol_mass,mass_frac; + + if(AllAtomistic != 1){ + if(AT_Pressure_Comp_Flag != 0){ + for (int i = 0; i < nlocal; i++){ + iLambda = lambdaH[i]; + if(iLambda != 0 && iLambda != 1){ + imol = molecule[i]; + if (AT_molmap_H)imol = AT_molmap_H[imol-idlo]; + else imol--; + mol_mass = AT_masstotal_H[imol]; + mass_frac = mass[type[i]] / mol_mass; + ibin = floor(iLambda/AT_lambda_Increment); + imoltypeH = moltypeH[i] - 1; + + f[i][0] += mass_frac*(AT_mol_f_all_H[imol][0]+gradlambdaH[i][0]*Mean_Comp_Energy_H[ibin][imoltypeH]); + f[i][1] += mass_frac*(AT_mol_f_all_H[imol][1]+gradlambdaH[i][1]*Mean_Comp_Energy_H[ibin][imoltypeH]); + f[i][2] += mass_frac*(AT_mol_f_all_H[imol][2]+gradlambdaH[i][2]*Mean_Comp_Energy_H[ibin][imoltypeH]); + if (evflag) ev_tally(i,i,nlocal,newton_pair, + -0.5*Int_Mean_Energy_H[ibin][imoltypeH],0.0,0.0,0.0,0.0,0.0); + + } + + } + + } + else{ + + for (int i = 0; i < nlocal; i++){ + + iLambda = lambdaH[i]; + if(iLambda != 0 && iLambda != 1){ + + imol = molecule[i]; + if (AT_molmap_H)imol = AT_molmap_H[imol-idlo]; + else imol--; + mol_mass = AT_masstotal_H[imol]; + mass_frac = mass[type[i]] / mol_mass; + ibin = floor(iLambda/AT_lambda_Increment); + + f[i][0] += mass_frac*(AT_mol_f_all_H[imol][0]); + f[i][1] += mass_frac*(AT_mol_f_all_H[imol][1]); + f[i][2] += mass_frac*(AT_mol_f_all_H[imol][2]); + + } + + } + + } + + } + + + + if(This_Step == AT_Update_Time_End)AT_Pressure_Compensation_Run = 0; + + if (vflag_fdotr) virial_fdotr_compute(); +} + +/* ---------------------------------------------------------------------- + allocate all arrays +------------------------------------------------------------------------- */ + +void PairLJCutCoulDSFHARSAT::allocate() +{ + allocated = 1; + int n = atom->ntypes; + + memory->create(setflag,n+1,n+1,"pair:setflag"); + for (int i = 1; i <= n; i++) + for (int j = i; j <= n; j++) + setflag[i][j] = 0; + + memory->create(cutsq,n+1,n+1,"pair:cutsq"); + + memory->create(cut_lj,n+1,n+1,"pair:cut_lj"); + memory->create(cut_ljsq,n+1,n+1,"pair:cut_ljsq"); + memory->create(epsilon,n+1,n+1,"pair:epsilon"); + memory->create(sigma,n+1,n+1,"pair:sigma"); + memory->create(lj1,n+1,n+1,"pair:lj1"); + memory->create(lj2,n+1,n+1,"pair:lj2"); + memory->create(lj3,n+1,n+1,"pair:lj3"); + memory->create(lj4,n+1,n+1,"pair:lj4"); + memory->create(offset,n+1,n+1,"pair:offset"); +} + +/* ---------------------------------------------------------------------- + global settings +------------------------------------------------------------------------- */ + +void PairLJCutCoulDSFHARSAT::settings(int narg, char **arg) +{ + if (narg != 5) error->all(FLERR,"Illegal pair_style command"); + + alpha = force->numeric(FLERR,arg[0]); + cut_lj_global = force->numeric(FLERR,arg[1]); + cut_coul = force->numeric(FLERR,arg[2]); + + AllAtomistic = force->numeric(FLERR,arg[3]); + Load_File_Flag = force->numeric(FLERR,arg[4]); + // reset cutoffs that have been explicitly set + + if (allocated) { + int i,j; + for (i = 1; i <= atom->ntypes; i++) + for (j = i+1; j <= atom->ntypes; j++) + if (setflag[i][j]) + cut_lj[i][j] = cut_lj_global; + } +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs +------------------------------------------------------------------------- */ + +void PairLJCutCoulDSFHARSAT::coeff(int narg, char **arg) +{ + if (narg < 4 || narg > 5) + error->all(FLERR,"Incorrect args for pair coefficients"); + if (!allocated) allocate(); + + int ilo,ihi,jlo,jhi; + force->bounds(arg[0],atom->ntypes,ilo,ihi); + force->bounds(arg[1],atom->ntypes,jlo,jhi); + + double epsilon_one = force->numeric(FLERR,arg[2]); + double sigma_one = force->numeric(FLERR,arg[3]); + + double cut_lj_one = cut_lj_global; + if (narg == 5) cut_lj_one = force->numeric(FLERR,arg[4]); + + int count = 0; + for (int i = ilo; i <= ihi; i++) { + for (int j = MAX(jlo,i); j <= jhi; j++) { + epsilon[i][j] = epsilon_one; + sigma[i][j] = sigma_one; + cut_lj[i][j] = cut_lj_one; + setflag[i][j] = 1; + + count++; + } + } + + if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); +} + +/* ---------------------------------------------------------------------- + init specific to this pair style +------------------------------------------------------------------------- */ + +void PairLJCutCoulDSFHARSAT::init_style() +{ + if (!atom->q_flag) + error->all(FLERR,"Pair style lj/cut/coul/dsf requires atom attribute q"); + + if(me == 0){ + if (screen)fprintf(screen,"AT_H_AdResS_allocated flag = %d\n",H_AdResS_allocated); + if (logfile)fprintf(logfile,"AT_H_AdResS_allocated flag = %d\n",H_AdResS_allocated); + } + + if(!H_AdResS_allocated)H_AdResS_Allocation(); + + int This_Step = update->ntimestep; + AT_Restart_Time_Step = This_Step; + + if((This_Step >= AT_Update_Time_End || Load_File_Flag) && AT_Pressure_Comp_Flag != 0)Load_Compensation_Pressure(); + + neighbor->request(this,instance_me); + + cut_coulsq = cut_coul * cut_coul; + double erfcc = erfc(alpha*cut_coul); + double erfcd = exp(-alpha*alpha*cut_coul*cut_coul); + f_shift = -(erfcc/cut_coulsq + 2.0/MY_PIS*alpha*erfcd/cut_coul); + e_shift = erfcc/cut_coul - f_shift*cut_coul; + +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i +------------------------------------------------------------------------- */ + +double PairLJCutCoulDSFHARSAT::init_one(int i, int j) +{ + if (setflag[i][j] == 0) { + epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j], + sigma[i][i],sigma[j][j]); + sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]); + cut_lj[i][j] = mix_distance(cut_lj[i][i],cut_lj[j][j]); + } + + double cut = MAX(cut_lj[i][j],cut_coul); + cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; + + lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0); + lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0); + lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); + lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); + + if (offset_flag) { + double ratio = sigma[i][j] / cut_lj[i][j]; + offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); + } else offset[i][j] = 0.0; + + cut_ljsq[j][i] = cut_ljsq[i][j]; + lj1[j][i] = lj1[i][j]; + lj2[j][i] = lj2[i][j]; + lj3[j][i] = lj3[i][j]; + lj4[j][i] = lj4[i][j]; + offset[j][i] = offset[i][j]; + + // compute I,J contribution to long-range tail correction + // count total # of atoms of type I and J via Allreduce + + if (tail_flag) { + int *type = atom->type; + int nlocal = atom->nlocal; + + double count[2],all[2]; + count[0] = count[1] = 0.0; + for (int k = 0; k < nlocal; k++) { + if (type[k] == i) count[0] += 1.0; + if (type[k] == j) count[1] += 1.0; + } + MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world); + + double sig2 = sigma[i][j]*sigma[i][j]; + double sig6 = sig2*sig2*sig2; + double rc3 = cut_lj[i][j]*cut_lj[i][j]*cut_lj[i][j]; + double rc6 = rc3*rc3; + double rc9 = rc3*rc6; + etail_ij = 8.0*MY_PI*all[0]*all[1]*epsilon[i][j] * + sig6 * (sig6 - 3.0*rc6) / (9.0*rc9); + ptail_ij = 16.0*MY_PI*all[0]*all[1]*epsilon[i][j] * + sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9); + } + + return cut; +} + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file +------------------------------------------------------------------------- */ + +void PairLJCutCoulDSFHARSAT::write_restart(FILE *fp) +{ + write_restart_settings(fp); + + int i,j; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) { + fwrite(&setflag[i][j],sizeof(int),1,fp); + if (setflag[i][j]) { + fwrite(&epsilon[i][j],sizeof(double),1,fp); + fwrite(&sigma[i][j],sizeof(double),1,fp); + fwrite(&cut_lj[i][j],sizeof(double),1,fp); + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts +------------------------------------------------------------------------- */ + +void PairLJCutCoulDSFHARSAT::read_restart(FILE *fp) +{ + read_restart_settings(fp); + allocate(); + + int i,j; + int me = comm->me; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) { + if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); + MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); + if (setflag[i][j]) { + if (me == 0) { + fread(&epsilon[i][j],sizeof(double),1,fp); + fread(&sigma[i][j],sizeof(double),1,fp); + fread(&cut_lj[i][j],sizeof(double),1,fp); + } + MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&cut_lj[i][j],1,MPI_DOUBLE,0,world); + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file +------------------------------------------------------------------------- */ + +void PairLJCutCoulDSFHARSAT::write_restart_settings(FILE *fp) +{ + fwrite(&alpha,sizeof(double),1,fp); + fwrite(&cut_lj_global,sizeof(double),1,fp); + fwrite(&cut_coul,sizeof(double),1,fp); + fwrite(&offset_flag,sizeof(int),1,fp); + fwrite(&mix_flag,sizeof(int),1,fp); + fwrite(&tail_flag,sizeof(int),1,fp); +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts +------------------------------------------------------------------------- */ + +void PairLJCutCoulDSFHARSAT::read_restart_settings(FILE *fp) +{ + if (comm->me == 0) { + fread(&alpha,sizeof(double),1,fp); + fread(&cut_lj_global,sizeof(double),1,fp); + fread(&cut_coul,sizeof(double),1,fp); + fread(&offset_flag,sizeof(int),1,fp); + fread(&mix_flag,sizeof(int),1,fp); + fread(&tail_flag,sizeof(int),1,fp); + } + MPI_Bcast(&alpha,1,MPI_DOUBLE,0,world); + MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world); + MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); + MPI_Bcast(&offset_flag,1,MPI_INT,0,world); + MPI_Bcast(&mix_flag,1,MPI_INT,0,world); + MPI_Bcast(&tail_flag,1,MPI_INT,0,world); +} + +/* ---------------------------------------------------------------------- */ + +double PairLJCutCoulDSFHARSAT::single(int i, int j, int itype, int jtype, double rsq, + double factor_coul, double factor_lj, + double &fforce) +{ + double r2inv,r6inv,r,erfcc,erfcd,prefactor; + double forcecoul,forcelj,phicoul,philj; + + r2inv = 1.0/rsq; + if (rsq < cut_ljsq[itype][jtype]) { + r6inv = r2inv*r2inv*r2inv; + forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); + } else forcelj = 0.0; + + if (rsq < cut_coulsq) { + r = sqrt(rsq); + prefactor = factor_coul * force->qqrd2e * atom->q[i]*atom->q[j]/r; + erfcc = erfc(alpha*r); + erfcd = exp(-alpha*alpha*r*r); + forcecoul = prefactor * (erfcc/r + 2.0*alpha/MY_PIS * erfcd + + r*f_shift) * r; + } else forcecoul = 0.0; + + fforce = (forcecoul + factor_lj*forcelj) * r2inv; + + double eng = 0.0; + if (rsq < cut_ljsq[itype][jtype]) { + philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - + offset[itype][jtype]; + eng += factor_lj*philj; + } + + if (rsq < cut_coulsq) { + phicoul = prefactor * (erfcc - r*e_shift - rsq*f_shift); + eng += phicoul; + } + + eng=0; + return eng; +} + +/* ---------------------------------------------------------------------- */ + +void *PairLJCutCoulDSFHARSAT::extract(const char *str, int &dim) +{ + if (strcmp(str,"cut_coul") == 0) { + dim = 0; + return (void *) &cut_coul; + } + return NULL; +} + + +int PairLJCutCoulDSFHARSAT::molecules_in_group(tagint &idlo, tagint &idhi) +{ + int i; + + memory->destroy(AT_molmap_H); + AT_molmap_H = NULL; + + // find lo/hi molecule ID for any atom in group + // warn if atom in group has ID = 0 + + tagint *molecule = atom->molecule; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + tagint lo = BIG; + tagint hi = -BIG; + int flag = 0; + for (i = 0; i < nlocal; i++) + { +// if (mask[i] & groupbit) { + if (mask[i]) { + if (molecule[i] == 0) flag = 1; + lo = MIN(lo,molecule[i]); + hi = MAX(hi,molecule[i]); + } + } + + int flagall; + MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); + if (flagall && comm->me == 0) + error->warning(FLERR,"Atom with molecule ID = 0 included in " + "compute molecule group"); + + MPI_Allreduce(&lo,&idlo,1,MPI_LMP_TAGINT,MPI_MIN,world); + MPI_Allreduce(&hi,&idhi,1,MPI_LMP_TAGINT,MPI_MAX,world); + if (idlo == BIG) return 0; + + // molmap = vector of length nlen + // set to 1 for IDs that appear in group across all procs, else 0 + + tagint nlen_tag = idhi-idlo+1; + if (nlen_tag > MAXSMALLINT) + error->all(FLERR,"Too many molecules for compute"); + int nlen = (int) nlen_tag; + + memory->create(AT_molmap_H,nlen,"pair:molmap_H"); + for (i = 0; i < nlen; i++) AT_molmap_H[i] = 0; + + for (i = 0; i < nlocal; i++) + // if (mask[i] & groupbit) + if (mask[i]) + AT_molmap_H[molecule[i]-idlo] = 1; + + int *AT_molmapall; + memory->create(AT_molmapall,nlen,"pair:AT_molmapall"); + MPI_Allreduce(AT_molmap_H,AT_molmapall,nlen,MPI_INT,MPI_MAX,world); + + // nmolecules = # of non-zero IDs in molmap + // molmap[i] = index of molecule, skipping molecules not in group with -1 + + int nmolecules = 0; + for (i = 0; i < nlen; i++) + if (AT_molmapall[i]) AT_molmap_H[i] = nmolecules++; + else AT_molmap_H[i] = -1; + memory->destroy(AT_molmapall); + + // warn if any molecule has some atoms in group and some not in group + + flag = 0; + for (i = 0; i < nlocal; i++) { +// if (mask[i] & groupbit) continue; + if (mask[i]) continue; + if (molecule[i] < idlo || molecule[i] > idhi) continue; + if (AT_molmap_H[molecule[i]-idlo] >= 0) flag = 1; + } + + MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); + if (flagall && comm->me == 0) + error->warning(FLERR, + "One or more compute molecules has atoms not in group"); + + // if molmap simply stores 1 to Nmolecules, then free it + + if (idlo == 1 && idhi == nmolecules && nlen == nmolecules) { + memory->destroy(AT_molmap_H); + AT_molmap_H = NULL; + } + return nmolecules; +} + + +void PairLJCutCoulDSFHARSAT::AT_Print_Compensation_Energy(){ + + FILE *fp1; + fp1 = fopen("Mean_Comp_Energy_AT.txt","w"); + if (fp1 == NULL) { + char str[128]; + sprintf(str,"Cannot open Mean_Comp_Energy_AT.txt file %s","Mean_Comp_Energy_AT.txt"); + error->one(FLERR,str); + } + + for(int i = 0;i < AT_Bin_Num; i++){ + fprintf(fp1,"%d",i+1); + for(int j = 0; j < atom->nmoltypesH; j++){ + fprintf(fp1,"\t%.10f",Mean_Comp_Energy_H[i][j]); + } + fprintf(fp1,"\n"); + } + fclose(fp1); +} + + + +void PairLJCutCoulDSFHARSAT::AT_Update_Compensation_Energy(){ + MPI_Allreduce(&Comp_Energy_H[0][0],&Comp_Energy_all_H[0][0],AT_Bin_Num*(atom->nmoltypesH+1),MPI_DOUBLE,MPI_SUM,world); + MPI_Allreduce(&Comp_Energy_Num_H[0][0],&Comp_Energy_Num_all_H[0][0],AT_Bin_Num*(atom->nmoltypesH+1),MPI_INT,MPI_SUM,world); + + for(int j = 0;j < atom->nmoltypesH; j++){ + for(int i = 0;i < AT_Bin_Num; i++){ + Mean_Energy_H[i][j] = Comp_Energy_all_H[i][j] / Comp_Energy_Num_all_H[i][j]; + Mean_Comp_Energy_H[i][j] = (Comp_Counter_H * Mean_Comp_Energy_H[i][j] + Mean_Energy_H[i][j]) / (Comp_Counter_H + 1); + Int_Mean_Energy_H[i][j]=0; + } + } + + Comp_Counter_H++; + + for(int j = 0;j < atom->nmoltypesH; j++){ + for(int i = 0;i < AT_Bin_Num; i++){ + Comp_Energy_Num_H[i][j] = 0; + Comp_Energy_Num_all_H[i][j] = 0; + Comp_Energy_H[i][j] = 0; + Comp_Energy_all_H[i][j] =0; + } + + } + if (me == 0)AT_Print_Compensation_Energy(); + + +} + + +void PairLJCutCoulDSFHARSAT::Load_Compensation_Pressure(){ + + if(me == 0){ + FILE *fp1; + char str[128]; + + fp1 = fopen("Mean_Comp_Energy_AT.txt","r"); + if (fp1 == NULL) { + sprintf(str,"Cannot open Mean_Comp_Energy_AT.txt file %s","Mean_Comp_Energy_AT.txt"); + error->one(FLERR,str); + } + + int i1; + + while (!feof(fp1)){ + fscanf (fp1,"%d",&i1); + for(int j=0;j<atom->nmoltypesH;j++)fscanf (fp1,"\t%f",&Mean_Comp_Energy_H[i1-1][j]); + fscanf (fp1,"\n"); + if(i1 > AT_Bin_Num){ + sprintf(str,"At drift force compensation bin number mismatches %d != %d",AT_Bin_Num,i1); + error->one(FLERR,str); + } + + } + + fclose(fp1); + + + if(me==0){ + if(screen)fprintf(screen,"AT_Pressure componsation forces distributed successfully!\n"); + if(logfile)fprintf(logfile,"AT_Pressure componsation forces distributed successfully!\n"); + } + + } + + MPI_Bcast(Mean_Comp_Energy_H,AT_Bin_Num,MPI_DOUBLE,0,world); + + +} + +void PairLJCutCoulDSFHARSAT::H_AdResS_Allocation(){ + for (int i = 0; i < modify->nfix; i++){ + if (strcmp(modify->fix[i]->style,"LambdaH/calc") == 0){ + lambda_H_fix = (FixLambdaHCalc *) modify->fix[i]; + AT_lambda_Increment = lambda_H_fix->Pressure_lambda_Increment; + AT_Bin_Num = lambda_H_fix->Pressure_Bin_Num; + AT_Update_Frequency = lambda_H_fix->Pressure_Update_Frequency; + AT_Update_Time_Begin = lambda_H_fix->Pressure_Update_Time_Begin; + AT_Update_Time_End = lambda_H_fix->Pressure_Update_Time_End; + AT_Pressure_Comp_Flag = lambda_H_fix->Pressure_Comp_Flag; + AT_center_box = lambda_H_fix->center_box; + AT_Hybrid_Style = lambda_H_fix->Hybrid_Style; + } + } + + if(me == 0){ + if (screen){ + fprintf(screen,"AT_lambda_Increment= %f\n",AT_lambda_Increment); + fprintf(screen,"AT_Bin_Num= %d\n",AT_Bin_Num); + fprintf(screen,"AT_Update_Frequency= %d\n",AT_Update_Frequency); + fprintf(screen,"AT_Update_Time_Begin= %d\n",AT_Update_Time_Begin); + fprintf(screen,"AT_Update_Time_End= %d\n",AT_Update_Time_End); + fprintf(screen,"AT_Pressure_Comp_Flag= %d\n",AT_Pressure_Comp_Flag); + } + + if (logfile){ + fprintf(logfile,"AT_lambda_Increment= %f\n",AT_lambda_Increment); + fprintf(logfile,"AT_Bin_Num= %d\n",AT_Bin_Num); + fprintf(logfile,"AT_Update_Frequency= %d\n",AT_Update_Frequency); + fprintf(logfile,"AT_Update_Time_Begin= %d\n",AT_Update_Time_Begin); + fprintf(logfile,"AT_Update_Time_End= %d\n",AT_Update_Time_End); + fprintf(logfile,"AT_Pressure_Comp_Flag= %d\n",AT_Pressure_Comp_Flag); + } + } + + memory->create(Comp_Energy_Num_H,AT_Bin_Num,atom->nmoltypesH+1,"pairLJHAT:Comp_Energy_Num_H"); + memory->create(Comp_Energy_Num_all_H,AT_Bin_Num,atom->nmoltypesH+1,"pairLJHAT:Comp_Energy_Num_all_H"); + + memory->create(Int_Mean_Energy_H,AT_Bin_Num,atom->nmoltypesH+1,"pairLJHAT:Int_Mean_Energy_H"); + memory->create(Comp_Energy_H,AT_Bin_Num,atom->nmoltypesH+1,"pairLJHAT:Comp_Energy_H"); + memory->create(Comp_Energy_all_H,AT_Bin_Num,atom->nmoltypesH+1,"pairLJHAT:Comp_Energy_all_H"); + memory->create(Mean_Comp_Energy_H,AT_Bin_Num,atom->nmoltypesH+1,"pairLJHAT:Mean_Comp_Energy_H"); + memory->create(Mean_Energy_H,AT_Bin_Num,atom->nmoltypesH+1,"pairLJHAT:Mean_Energy_H"); + + + for(int j=0;j<atom->nmoltypesH;j++){ + for(int i = 0;i < AT_Bin_Num; i++){ + Int_Mean_Energy_H[i][j]=0; + Comp_Energy_H[i][j]=0; + Comp_Energy_all_H[i][j]=0; + Mean_Comp_Energy_H[i][j]=0; + Comp_Energy_Num_H[i][j] = 0; + Comp_Energy_Num_all_H[i][j] = 0; + } + + } + + H_AdResS_allocated = 1; +} + diff --git a/src/USER-HADRESS/pair_lj_cut_coul_dsf_hars_at.h b/src/USER-HADRESS/pair_lj_cut_coul_dsf_hars_at.h new file mode 100644 index 000000000..b5d5076c4 --- /dev/null +++ b/src/USER-HADRESS/pair_lj_cut_coul_dsf_hars_at.h @@ -0,0 +1,115 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef PAIR_CLASS + +PairStyle(lj/cut/coul/dsf/hars/at,PairLJCutCoulDSFHARSAT) + +#else + +#ifndef LMP_PAIR_LJ_CUT_COUL_DSF_HARS_AT_H +#define LMP_PAIR_LJ_CUT_COUL_DSF_HARS_AT_H + +#include "pair.h" + +namespace LAMMPS_NS { + +class PairLJCutCoulDSFHARSAT : public Pair { + public: + PairLJCutCoulDSFHARSAT(class LAMMPS *); + ~PairLJCutCoulDSFHARSAT(); + void compute(int, int); + void settings(int, char **); + void coeff(int, char **); + void init_style(); + double init_one(int, int); + void write_restart(FILE *); + void read_restart(FILE *); + void write_restart_settings(FILE *); + void read_restart_settings(FILE *); + double single(int, int, int, int, double, double, double, double &); + void *extract(const char *, int &); + + void AT_Print_Compensation_Energy(); + void AT_Update_Compensation_Energy(); + + protected: + double cut_lj_global; + double **cut_lj,**cut_ljsq; + double **epsilon,**sigma; + double **lj1,**lj2,**lj3,**lj4,**offset; + + double cut_coul,cut_coulsq; + double alpha; + double f_shift,e_shift; + + void allocate(); + class FixLambdaHCalc *lambda_H_fix; + + int AllAtomistic; + + //private: + int me; + + int H_AdResS_allocated; + + int **Comp_Energy_Num_H,**Comp_Energy_Num_all_H, Comp_Counter_H; + + double AT_lambda_Increment; + int AT_Bin_Num, AT_Update_Frequency, AT_Update_Time_End, AT_Update_Time_Begin; + int AT_Pressure_Compensation_Run; + int AT_Pressure_Comp_Flag; + + int AT_Restart_Time_Step; + double *AT_center_box,AT_x0lo; + int AT_Hybrid_Style; + double **Int_Mean_Energy_H, **Comp_Energy_H, **Comp_Energy_all_H, **Mean_Energy_H, **Mean_Comp_Energy_H; + + int nmolecules; + tagint idlo,idhi; + + double *AT_massproc_H,*AT_masstotal_H; + + double **AT_mol_f_H, **AT_mol_f_all_H; + + int *AT_molmap_H; // convert molecule ID to local index + int Load_File_Flag; + + int molecules_in_group(tagint &, tagint &); + void Load_Compensation_Pressure(); + void H_AdResS_Allocation(); + +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + +E: Illegal ... command + +Self-explanatory. Check the input script syntax and compare to the +documentation for the command. You can use -echo screen as a +command-line option when running LAMMPS to see the offending line. + +E: Incorrect args for pair coefficients + +Self-explanatory. Check the input script or data file. + +E: Pair style lj/cut/coul/dsf requires atom attribute q + +The atom style defined does not have these attributes. + +*/ diff --git a/src/USER-HADRESS/pair_lj_cut_hars_at.cpp b/src/USER-HADRESS/pair_lj_cut_hars_at.cpp new file mode 100644 index 000000000..f605c92ac --- /dev/null +++ b/src/USER-HADRESS/pair_lj_cut_hars_at.cpp @@ -0,0 +1,1039 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Paul Crozier (SNL) +------------------------------------------------------------------------- */ + +#include "math.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "pair_lj_cut_hars_at.h" +#include "atom.h" +#include "comm.h" +#include "force.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "update.h" +#include "integrate.h" +#include "respa.h" +#include "math_const.h" +#include "memory.h" +#include "error.h" +#include "domain.h" +#include "fix.h" +#include "fix_lambdah_calc.h" +#include "modify.h" + +using namespace LAMMPS_NS; +using namespace MathConst; +#define BIG MAXTAGINT + +/* ---------------------------------------------------------------------- */ + +PairLJCutHARSAT::PairLJCutHARSAT(LAMMPS *lmp) : Pair(lmp) +{ + respa_enable = 1; + writedata = 1; + + AT_massproc_H = NULL; + AT_masstotal_H = NULL; + AT_molmap_H = NULL; + AT_mol_f_H = NULL; + AT_mol_f_all_H = NULL; + Comp_Energy_Num_H = NULL; + Comp_Energy_Num_all_H = NULL; + + Int_Mean_Energy_H = NULL; + Mean_Energy_H = NULL; + Comp_Energy_H = NULL; + Comp_Energy_all_H = NULL; + Mean_Comp_Energy_H = NULL; + + AT_molmap_H = NULL; + nmolecules = molecules_in_group(idlo,idhi); + + H_AdResS_allocated = 0; + + AT_Pressure_Compensation_Run = 0; + Comp_Counter_H = 0; + memory->create(AT_massproc_H,nmolecules,"pair:AT_massproc_H"); + memory->create(AT_masstotal_H,nmolecules,"pair:AT_masstotal_H"); + memory->create(AT_mol_f_H,nmolecules,3,"pair:AT_mol_f_H"); + memory->create(AT_mol_f_all_H,nmolecules,3,"pair:AT_mol_f_all_H"); + + + // compute masstotal for each molecule + MPI_Comm_rank(world, &me); + int *mask = atom->mask; + tagint *molecule = atom->molecule; + int *type = atom->type; + double *mass = atom->mass; + double *rmass = atom->rmass; + int nlocal = atom->nlocal; + + tagint imol; + double massone; + + for (int i = 0; i < nmolecules; i++) AT_massproc_H[i] = 0.0; + + + for (int i = 0; i < nlocal; i++) + { +// if (mask[i] & groupbit) { + if (mask[i]) { + if (rmass) massone = rmass[i]; + else massone = mass[type[i]]; + imol = molecule[i]; + if (AT_molmap_H) imol = AT_molmap_H[imol-idlo]; + else imol--; + AT_massproc_H[imol] += massone; + + } + } + + MPI_Allreduce(AT_massproc_H,AT_masstotal_H,nmolecules,MPI_DOUBLE,MPI_SUM,world); + +} + +/* ---------------------------------------------------------------------- */ + +PairLJCutHARSAT::~PairLJCutHARSAT() +{ + if (allocated) { + memory->destroy(setflag); + memory->destroy(cutsq); + memory->destroy(cut); + memory->destroy(epsilon); + memory->destroy(sigma); + memory->destroy(lj1); + memory->destroy(lj2); + memory->destroy(lj3); + memory->destroy(lj4); + memory->destroy(offset); + memory->destroy(AT_massproc_H); + memory->destroy(AT_masstotal_H); + memory->destroy(AT_molmap_H); + memory->destroy(AT_mol_f_H); + memory->destroy(AT_mol_f_all_H); + memory->destroy(Comp_Energy_Num_H); + memory->destroy(Comp_Energy_Num_all_H); + memory->destroy(Int_Mean_Energy_H); + memory->destroy(Mean_Energy_H); + memory->destroy(Comp_Energy_H); + memory->destroy(Comp_Energy_all_H); + memory->destroy(Mean_Comp_Energy_H); + + } +} + +/* ---------------------------------------------------------------------- */ + +void PairLJCutHARSAT::compute(int eflag, int vflag) +{ + int i,j,ii,jj,inum,jnum,itype,jtype; + double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; + double rsq,r2inv,r6inv,forcelj, factor_lj,Vij; + int *ilist,*jlist,*numneigh,**firstneigh; + int imoltypeH,jmoltypeH; + + evdwl = 0.0; + if (eflag || vflag) ev_setup(eflag,vflag); + else evflag = vflag_fdotr = 0; + + double **x = atom->x; + double **f = atom->f; + double *lambdaH = atom->lambdaH; + double **gradlambdaH = atom->gradlambdaH; + int *type = atom->type; + int nlocal = atom->nlocal; + double *special_lj = force->special_lj; + int newton_pair = force->newton_pair; + int imol,jmol; + tagint *molecule = atom->molecule; + double *mass = atom->mass; + int *replambdaH = atom->replambdaH; + int *moltypeH = atom->moltypeH; + + int ibin, jbin; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + //if(update->ntimestep<3)return; + + double xtmpj, iLambda, jLambda, ijLambda; + + int This_Step = update->ntimestep; + if(This_Step >= AT_Update_Time_Begin && This_Step <= AT_Update_Time_End && AT_Pressure_Comp_Flag != 0) AT_Pressure_Compensation_Run = 1; + + + for (int i = 0; i < nmolecules; i++) { + AT_mol_f_H[i][0] = AT_mol_f_H[i][1] = AT_mol_f_H[i][2] = 0; + AT_mol_f_all_H[i][0] = AT_mol_f_all_H[i][1] = AT_mol_f_all_H[i][2] = 0; + } + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + itype = type[i]; + imoltypeH = moltypeH[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + iLambda = lambdaH[i]; + + for (jj = 0; jj < jnum; jj++) { + + j = jlist[jj]; + factor_lj = special_lj[sbmask(j)]; + j &= NEIGHMASK; + jLambda = lambdaH[j]; + + + if(iLambda==0 && jLambda==0 && AllAtomistic!=1)continue; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + + xtmpj = x[j][0]; + + rsq = delx*delx + dely*dely + delz*delz; + jtype = type[j]; + jmoltypeH = moltypeH[j]; + + imol = molecule[i]; + jmol = molecule[j]; + if (AT_molmap_H) { + imol = AT_molmap_H[imol-idlo]; + jmol = AT_molmap_H[jmol-idlo]; + } + else { + imol--; + jmol--; + } + + + if (rsq < cutsq[itype][jtype] && lj1[itype][jtype] != 0 && (imol != jmol)) { + + + if(((iLambda==1 && jLambda==1) || AllAtomistic)){ + + r2inv = 1.0/rsq; + r6inv = r2inv*r2inv*r2inv; + forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); + fpair = factor_lj*forcelj*r2inv; + + f[i][0] += delx*fpair; + f[i][1] += dely*fpair; + f[i][2] += delz*fpair; + + if (newton_pair || j < nlocal) { + f[j][0] -= delx*fpair; + f[j][1] -= dely*fpair; + f[j][2] -= delz*fpair; + } + + if (eflag) { + evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - + offset[itype][jtype]; + evdwl *= factor_lj; + } + + if (evflag) ev_tally(i,j,nlocal,newton_pair, + evdwl,0.0,fpair,delx,dely,delz); + + } + else if(iLambda !=0 || jLambda != 0){ + + + ijLambda = 0.5 * (iLambda + jLambda); + r2inv = 1.0/rsq; + r6inv = r2inv*r2inv*r2inv; + forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); + + fpair = factor_lj*(forcelj*ijLambda)*r2inv; + + Vij = 0.5*(r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - + offset[itype][jtype]); + + f[i][0] += delx*fpair; + f[i][1] += dely*fpair; + f[i][2] += delz*fpair; + + ibin = floor(iLambda/AT_lambda_Increment); + if(ibin==AT_Bin_Num)ibin = AT_Bin_Num - 1; + if(AT_Pressure_Compensation_Run != 0 && iLambda != 0 && iLambda != 1)Comp_Energy_H[ibin][imoltypeH-1] += Vij; + + AT_mol_f_H[imol][0] += -Vij*gradlambdaH[i][0]; + AT_mol_f_H[imol][1] += -Vij*gradlambdaH[i][1]; + AT_mol_f_H[imol][2] += -Vij*gradlambdaH[i][2]; + + if (newton_pair || j < nlocal) { + + f[j][0] -= delx*fpair; + f[j][1] -= dely*fpair; + f[j][2] -= delz*fpair; + + jbin = floor(jLambda/AT_lambda_Increment); + if(jbin==AT_Bin_Num)jbin = AT_Bin_Num - 1; + if(AT_Pressure_Compensation_Run != 0 && jLambda != 0 && jLambda != 1)Comp_Energy_H[jbin][jmoltypeH-1] += Vij; + + AT_mol_f_H[jmol][0] += -Vij*gradlambdaH[j][0]; + AT_mol_f_H[jmol][1] += -Vij*gradlambdaH[j][1]; + AT_mol_f_H[jmol][2] += -Vij*gradlambdaH[j][2]; + + } + + if (eflag) { + + evdwl = ijLambda*Vij*2.0; + evdwl *= factor_lj; + } + + if (evflag) ev_tally(i,j,nlocal,newton_pair, + evdwl,0.0,fpair,delx,dely,delz); + + } + } + + } + } + + + + MPI_Allreduce(&AT_mol_f_H[0][0],&AT_mol_f_all_H[0][0],3*nmolecules,MPI_DOUBLE,MPI_SUM,world); + + if(AT_Pressure_Compensation_Run != 0 && AT_Pressure_Comp_Flag != 0){ + + for (int i = 0; i < nlocal; i++){ + iLambda = lambdaH[i]; + if(replambdaH[i]!=0 && iLambda != 0 && iLambda != 1){ + + ibin = floor(iLambda/AT_lambda_Increment); + if(ibin==AT_Bin_Num)ibin = AT_Bin_Num - 1; + + imoltypeH = moltypeH[i]-1; + + Comp_Energy_Num_H[ibin][imoltypeH]++; + } + } + + if(This_Step % AT_Update_Frequency == 0)AT_Update_Compensation_Energy(); + + } + + + if(This_Step == AT_Update_Time_End && AT_Pressure_Compensation_Run != 0)AT_Print_Compensation_Energy(); + + double mol_mass,mass_frac; + + if(AllAtomistic != 1){ + + if(AT_Pressure_Comp_Flag != 0){ + + for (int i = 0; i < nlocal; i++){ + + iLambda = lambdaH[i]; + if(iLambda != 0 && iLambda != 1){ + + imol = molecule[i]; + if (AT_molmap_H)imol = AT_molmap_H[imol-idlo]; + else imol--; + mol_mass = AT_masstotal_H[imol]; + mass_frac = mass[type[i]] / mol_mass; + ibin = floor(iLambda/AT_lambda_Increment); + imoltypeH = moltypeH[i] - 1; + + + f[i][0] += mass_frac*(AT_mol_f_all_H[imol][0]+gradlambdaH[i][0]*Mean_Comp_Energy_H[ibin][imoltypeH]); + f[i][1] += mass_frac*(AT_mol_f_all_H[imol][1]+gradlambdaH[i][1]*Mean_Comp_Energy_H[ibin][imoltypeH]); + f[i][2] += mass_frac*(AT_mol_f_all_H[imol][2]+gradlambdaH[i][2]*Mean_Comp_Energy_H[ibin][imoltypeH]); + if (evflag) ev_tally(i,i,nlocal,newton_pair, + -0.5*Int_Mean_Energy_H[ibin][imoltypeH],0.0,0.0,0.0,0.0,0.0); + + } + + } + + } + else{ + + for (int i = 0; i < nlocal; i++){ + + iLambda = lambdaH[i]; + if(iLambda != 0 && iLambda != 1){ + + imol = molecule[i]; + if (AT_molmap_H)imol = AT_molmap_H[imol-idlo]; + else imol--; + mol_mass = AT_masstotal_H[imol]; + mass_frac = mass[type[i]] / mol_mass; + ibin = floor(iLambda/AT_lambda_Increment); + + + f[i][0] += mass_frac*(AT_mol_f_all_H[imol][0]); + f[i][1] += mass_frac*(AT_mol_f_all_H[imol][1]); + f[i][2] += mass_frac*(AT_mol_f_all_H[imol][2]); + + } + + } + + } + + } + + + if(This_Step == AT_Update_Time_End)AT_Pressure_Compensation_Run = 0; + + if (vflag_fdotr) virial_fdotr_compute(); +} + +/* ---------------------------------------------------------------------- */ + +void PairLJCutHARSAT::compute_inner() +{ + error->all(FLERR,"Rrespa has not been included!"); +} + +/* ---------------------------------------------------------------------- */ + +void PairLJCutHARSAT::compute_middle() +{ + error->all(FLERR,"Rrespa has not been included!"); +} + +/* ---------------------------------------------------------------------- */ + +void PairLJCutHARSAT::compute_outer(int eflag, int vflag) +{ + error->all(FLERR,"Rrespa has not been included!"); + +} + +/* ---------------------------------------------------------------------- + allocate all arrays +------------------------------------------------------------------------- */ + +void PairLJCutHARSAT::allocate() +{ + allocated = 1; + int n = atom->ntypes; + + memory->create(setflag,n+1,n+1,"pairLJHAT:setflag"); + for (int i = 1; i <= n; i++) + for (int j = i; j <= n; j++) + setflag[i][j] = 0; + + memory->create(cutsq,n+1,n+1,"pairLJHAT:cutsq"); + + memory->create(cut,n+1,n+1,"pairLJHAT:cut"); + memory->create(epsilon,n+1,n+1,"pairLJHAT:epsilon"); + memory->create(sigma,n+1,n+1,"pairLJHAT:sigma"); + memory->create(lj1,n+1,n+1,"pairLJHAT:lj1"); + memory->create(lj2,n+1,n+1,"pairLJHAT:lj2"); + memory->create(lj3,n+1,n+1,"pairLJHAT:lj3"); + memory->create(lj4,n+1,n+1,"pairLJHAT:lj4"); + memory->create(offset,n+1,n+1,"pairLJHAT:offset"); + +} + +/* ---------------------------------------------------------------------- + global settings +------------------------------------------------------------------------- */ + +void PairLJCutHARSAT::settings(int narg, char **arg) +{ + if (narg != 3) error->all(FLERR,"Illegal pair_style command"); + + cut_global = force->numeric(FLERR,arg[0]); + + // reset cutoffs that have been explicitly set + AllAtomistic = force->numeric(FLERR,arg[1]); + + Load_File_Flag = force->numeric(FLERR,arg[2]); + + + if (allocated) { + int i,j; + for (i = 1; i <= atom->ntypes; i++) + for (j = i+1; j <= atom->ntypes; j++) + if (setflag[i][j]) cut[i][j] = cut_global; + } + + + +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs +------------------------------------------------------------------------- */ + +void PairLJCutHARSAT::coeff(int narg, char **arg) +{ + + + if (narg < 4 || narg > 5) + error->all(FLERR,"Incorrect args for pair coefficients"); + if (!allocated) allocate(); + + int ilo,ihi,jlo,jhi; + force->bounds(arg[0],atom->ntypes,ilo,ihi); + force->bounds(arg[1],atom->ntypes,jlo,jhi); + + double epsilon_one = force->numeric(FLERR,arg[2]); + double sigma_one = force->numeric(FLERR,arg[3]); + + double cut_one = cut_global; + if (narg == 5) cut_one = force->numeric(FLERR,arg[4]); + + + int count = 0; + for (int i = ilo; i <= ihi; i++) { + for (int j = MAX(jlo,i); j <= jhi; j++) { + epsilon[i][j] = epsilon_one; + sigma[i][j] = sigma_one; + cut[i][j] = cut_one; + setflag[i][j] = 1; + count++; + } + } + + if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); +} + +/* ---------------------------------------------------------------------- + init specific to this pair style +------------------------------------------------------------------------- */ + +void PairLJCutHARSAT::init_style() +{ + // request regular or rRESPA neighbor lists + + + if(me == 0){ + if (screen)fprintf(screen,"AT_H_AdResS_allocated flag = %d\n",H_AdResS_allocated); + if (logfile)fprintf(logfile,"AT_H_AdResS_allocated flag = %d\n",H_AdResS_allocated); + } + + if(!H_AdResS_allocated)H_AdResS_Allocation(); + + int This_Step = update->ntimestep; + if((This_Step >= AT_Update_Time_End || Load_File_Flag) && AT_Pressure_Comp_Flag != 0)Load_Compensation_Pressure(); + + + int irequest; + + if (update->whichflag == 1 && strstr(update->integrate_style,"respa")) { + int respa = 0; + if (((Respa *) update->integrate)->level_inner >= 0) respa = 1; + if (((Respa *) update->integrate)->level_middle >= 0) respa = 2; + + if (respa == 0) irequest = neighbor->request(this,instance_me); + else if (respa == 1) { + irequest = neighbor->request(this,instance_me); + neighbor->requests[irequest]->id = 1; + neighbor->requests[irequest]->half = 0; + neighbor->requests[irequest]->respainner = 1; + irequest = neighbor->request(this,instance_me); + neighbor->requests[irequest]->id = 3; + neighbor->requests[irequest]->half = 0; + neighbor->requests[irequest]->respaouter = 1; + } else { + irequest = neighbor->request(this,instance_me); + neighbor->requests[irequest]->id = 1; + neighbor->requests[irequest]->half = 0; + neighbor->requests[irequest]->respainner = 1; + irequest = neighbor->request(this,instance_me); + neighbor->requests[irequest]->id = 2; + neighbor->requests[irequest]->half = 0; + neighbor->requests[irequest]->respamiddle = 1; + irequest = neighbor->request(this,instance_me); + neighbor->requests[irequest]->id = 3; + neighbor->requests[irequest]->half = 0; + neighbor->requests[irequest]->respaouter = 1; + } + + } else { + irequest = neighbor->request(this,instance_me); + } + // set rRESPA cutoffs + + if (strstr(update->integrate_style,"respa") && + ((Respa *) update->integrate)->level_inner >= 0) + cut_respa = ((Respa *) update->integrate)->cutoff; + else cut_respa = NULL; +} + +/* ---------------------------------------------------------------------- + neighbor callback to inform pair style of neighbor list to use + regular or rRESPA +------------------------------------------------------------------------- */ + +void PairLJCutHARSAT::init_list(int id, NeighList *ptr) +{ + if (id == 0) list = ptr; + else if (id == 1) listinner = ptr; + else if (id == 2) listmiddle = ptr; + else if (id == 3) listouter = ptr; +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i +------------------------------------------------------------------------- */ + +double PairLJCutHARSAT::init_one(int i, int j) +{ + if (setflag[i][j] == 0) { + epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j], + sigma[i][i],sigma[j][j]); + sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]); + cut[i][j] = mix_distance(cut[i][i],cut[j][j]); + } + + + lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0); + lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0); + lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); + lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); + + + if (offset_flag) { + double ratio = sigma[i][j] / cut[i][j]; + offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); + } else offset[i][j] = 0.0; + + lj1[j][i] = lj1[i][j]; + lj2[j][i] = lj2[i][j]; + lj3[j][i] = lj3[i][j]; + lj4[j][i] = lj4[i][j]; + offset[j][i] = offset[i][j]; + + // check interior rRESPA cutoff + + if (cut_respa && cut[i][j] < cut_respa[3]) + error->all(FLERR,"Pair cutoff < Respa interior cutoff"); + + // compute I,J contribution to long-range tail correction + // count total # of atoms of type I and J via Allreduce + + if (tail_flag) { + int *type = atom->type; + int nlocal = atom->nlocal; + + double count[2],all[2]; + count[0] = count[1] = 0.0; + for (int k = 0; k < nlocal; k++) { + if (type[k] == i) count[0] += 1.0; + if (type[k] == j) count[1] += 1.0; + } + MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world); + + double sig2 = sigma[i][j]*sigma[i][j]; + double sig6 = sig2*sig2*sig2; + double rc3 = cut[i][j]*cut[i][j]*cut[i][j]; + double rc6 = rc3*rc3; + double rc9 = rc3*rc6; + etail_ij = 8.0*MY_PI*all[0]*all[1]*epsilon[i][j] * + sig6 * (sig6 - 3.0*rc6) / (9.0*rc9); + ptail_ij = 16.0*MY_PI*all[0]*all[1]*epsilon[i][j] * + sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9); + } + + + return cut[i][j]; +} + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file +------------------------------------------------------------------------- */ + +void PairLJCutHARSAT::write_restart(FILE *fp) +{ + write_restart_settings(fp); + + int i,j; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) { + fwrite(&setflag[i][j],sizeof(int),1,fp); + if (setflag[i][j]) { + fwrite(&epsilon[i][j],sizeof(double),1,fp); + fwrite(&sigma[i][j],sizeof(double),1,fp); + fwrite(&cut[i][j],sizeof(double),1,fp); + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts +------------------------------------------------------------------------- */ + +void PairLJCutHARSAT::read_restart(FILE *fp) +{ + read_restart_settings(fp); + allocate(); + + int i,j; + int me = comm->me; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) { + if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); + MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); + if (setflag[i][j]) { + if (me == 0) { + fread(&epsilon[i][j],sizeof(double),1,fp); + fread(&sigma[i][j],sizeof(double),1,fp); + fread(&cut[i][j],sizeof(double),1,fp); + } + MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file +------------------------------------------------------------------------- */ + +void PairLJCutHARSAT::write_restart_settings(FILE *fp) +{ + fwrite(&cut_global,sizeof(double),1,fp); + fwrite(&offset_flag,sizeof(int),1,fp); + fwrite(&mix_flag,sizeof(int),1,fp); + fwrite(&tail_flag,sizeof(int),1,fp); +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts +------------------------------------------------------------------------- */ + +void PairLJCutHARSAT::read_restart_settings(FILE *fp) +{ + int me = comm->me; + if (me == 0) { + fread(&cut_global,sizeof(double),1,fp); + fread(&offset_flag,sizeof(int),1,fp); + fread(&mix_flag,sizeof(int),1,fp); + fread(&tail_flag,sizeof(int),1,fp); + } + MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); + MPI_Bcast(&offset_flag,1,MPI_INT,0,world); + MPI_Bcast(&mix_flag,1,MPI_INT,0,world); + MPI_Bcast(&tail_flag,1,MPI_INT,0,world); +} + +/* ---------------------------------------------------------------------- + proc 0 writes to data file +------------------------------------------------------------------------- */ + +void PairLJCutHARSAT::write_data(FILE *fp) +{ + for (int i = 1; i <= atom->ntypes; i++) + fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]); +} + +/* ---------------------------------------------------------------------- + proc 0 writes all pairs to data file +------------------------------------------------------------------------- */ + +void PairLJCutHARSAT::write_data_all(FILE *fp) +{ + for (int i = 1; i <= atom->ntypes; i++) + for (int j = i; j <= atom->ntypes; j++) + fprintf(fp,"%d %d %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],cut[i][j]); +} + +/* ---------------------------------------------------------------------- */ + +double PairLJCutHARSAT::single(int i, int j, int itype, int jtype, double rsq, + double factor_coul, double factor_lj, + double &fforce) +{ + double r2inv,r6inv,forcelj,philj; + + r2inv = 1.0/rsq; + r6inv = r2inv*r2inv*r2inv; + forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); + fforce = factor_lj*forcelj*r2inv; + + philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - + offset[itype][jtype]; + return factor_lj*philj; +} + +/* ---------------------------------------------------------------------- */ + +void *PairLJCutHARSAT::extract(const char *str, int &dim) +{ + dim = 2; + if (strcmp(str,"epsilon") == 0) return (void *) epsilon; + if (strcmp(str,"sigma") == 0) return (void *) sigma; + return NULL; +} + + +int PairLJCutHARSAT::molecules_in_group(tagint &idlo, tagint &idhi) +{ + int i; + + memory->destroy(AT_molmap_H); + AT_molmap_H = NULL; + + // find lo/hi molecule ID for any atom in group + // warn if atom in group has ID = 0 + + tagint *molecule = atom->molecule; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + tagint lo = BIG; + tagint hi = -BIG; + int flag = 0; + for (i = 0; i < nlocal; i++) + { +// if (mask[i] & groupbit) { + if (mask[i]) { + if (molecule[i] == 0) flag = 1; + lo = MIN(lo,molecule[i]); + hi = MAX(hi,molecule[i]); + } + } + + int flagall; + MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); + if (flagall && comm->me == 0) + error->warning(FLERR,"Atom with molecule ID = 0 included in " + "compute molecule group"); + + MPI_Allreduce(&lo,&idlo,1,MPI_LMP_TAGINT,MPI_MIN,world); + MPI_Allreduce(&hi,&idhi,1,MPI_LMP_TAGINT,MPI_MAX,world); + if (idlo == BIG) return 0; + + // molmap = vector of length nlen + // set to 1 for IDs that appear in group across all procs, else 0 + + tagint nlen_tag = idhi-idlo+1; + if (nlen_tag > MAXSMALLINT) + error->all(FLERR,"Too many molecules for compute"); + int nlen = (int) nlen_tag; + + memory->create(AT_molmap_H,nlen,"pair:molmap_H"); + for (i = 0; i < nlen; i++) AT_molmap_H[i] = 0; + + for (i = 0; i < nlocal; i++) + // if (mask[i] & groupbit) + if (mask[i]) + AT_molmap_H[molecule[i]-idlo] = 1; + + int *AT_molmapall; + memory->create(AT_molmapall,nlen,"pair:AT_molmapall"); + MPI_Allreduce(AT_molmap_H,AT_molmapall,nlen,MPI_INT,MPI_MAX,world); + + // nmolecules = # of non-zero IDs in molmap + // molmap[i] = index of molecule, skipping molecules not in group with -1 + + int nmolecules = 0; + for (i = 0; i < nlen; i++) + if (AT_molmapall[i]) AT_molmap_H[i] = nmolecules++; + else AT_molmap_H[i] = -1; + memory->destroy(AT_molmapall); + + // warn if any molecule has some atoms in group and some not in group + + flag = 0; + for (i = 0; i < nlocal; i++) { +// if (mask[i] & groupbit) continue; + if (mask[i]) continue; + if (molecule[i] < idlo || molecule[i] > idhi) continue; + if (AT_molmap_H[molecule[i]-idlo] >= 0) flag = 1; + } + + MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); + if (flagall && comm->me == 0) + error->warning(FLERR, + "One or more compute molecules has atoms not in group"); + + // if molmap simply stores 1 to Nmolecules, then free it + + if (idlo == 1 && idhi == nmolecules && nlen == nmolecules) { + memory->destroy(AT_molmap_H); + AT_molmap_H = NULL; + } + return nmolecules; +} + + +void PairLJCutHARSAT::AT_Print_Compensation_Energy(){ + + FILE *fp1; + fp1 = fopen("Mean_Comp_Energy_AT.txt","w"); + if (fp1 == NULL) { + char str[128]; + sprintf(str,"Cannot open Mean_Comp_Energy_AT.txt file %s","Mean_Comp_Energy_AT.txt"); + error->one(FLERR,str); + } + + for(int i = 0;i < AT_Bin_Num; i++){ + fprintf(fp1,"%d",i+1); + for(int j = 0; j < atom->nmoltypesH; j++){ + fprintf(fp1,"\t%.10f",Mean_Comp_Energy_H[i][j]); + } + fprintf(fp1,"\n"); + } + fclose(fp1); +} + + + +void PairLJCutHARSAT::AT_Update_Compensation_Energy(){ + + MPI_Allreduce(&Comp_Energy_H[0][0],&Comp_Energy_all_H[0][0],AT_Bin_Num*atom->nmoltypesH,MPI_DOUBLE,MPI_SUM,world); + MPI_Allreduce(&Comp_Energy_Num_H[0][0],&Comp_Energy_Num_all_H[0][0],AT_Bin_Num*atom->nmoltypesH,MPI_INT,MPI_SUM,world); + + for(int j = 0;j < atom->nmoltypesH; j++){ + for(int i = 0;i < AT_Bin_Num; i++){ + Mean_Energy_H[i][j] = Comp_Energy_all_H[i][j] / Comp_Energy_Num_all_H[i][j]; + Mean_Comp_Energy_H[i][j] = (Comp_Counter_H * Mean_Comp_Energy_H[i][j] + Mean_Energy_H[i][j]) / (Comp_Counter_H + 1); + Int_Mean_Energy_H[i][j]=0; + } + } + + Comp_Counter_H++; + + for(int j = 0;j < atom->nmoltypesH; j++){ + for(int i = 0;i < AT_Bin_Num; i++){ + Comp_Energy_Num_H[i][j] = 0; + Comp_Energy_Num_all_H[i][j] = 0; + Comp_Energy_H[i][j] = 0; + Comp_Energy_all_H[i][j] =0; + } + + } + if (me == 0)AT_Print_Compensation_Energy(); + + + +} + + +void PairLJCutHARSAT::Load_Compensation_Pressure(){ + + if(me == 0){ + FILE *fp1; + char str[128]; + + fp1 = fopen("Mean_Comp_Energy_AT.txt","r"); + if (fp1 == NULL) { + sprintf(str,"Cannot open fix Mean_Comp_Energy_AT.txt file %s","Mean_Comp_Energy_AT.txt"); + error->one(FLERR,str); + } + + int i1; + + while (!feof(fp1)){ + fscanf (fp1,"%d",&i1); + for(int j=0;j<atom->nmoltypesH;j++)fscanf (fp1,"\t%f",&Mean_Comp_Energy_H[i1-1][j]); + fscanf (fp1,"\n"); + if(i1 > AT_Bin_Num){ + sprintf(str,"Pressure bin number mismatches %d != %d",AT_Bin_Num,i1); + error->one(FLERR,str); + } + + } + + fclose(fp1); + + if(me==0){ + if(screen)fprintf(screen,"AT_Pressure componsation forces distributed successfully!\n"); + if(logfile)fprintf(logfile,"AT_Pressure componsation forces distributed successfully!\n"); + } + + } + + MPI_Bcast(Mean_Comp_Energy_H,AT_Bin_Num,MPI_DOUBLE,0,world); + + +} + +void PairLJCutHARSAT::H_AdResS_Allocation(){ + + for (int i = 0; i < modify->nfix; i++){ + if (strcmp(modify->fix[i]->style,"lambdah/calc") == 0){ + lambda_H_fix = (FixLambdaHCalc *) modify->fix[i]; + AT_lambda_Increment = lambda_H_fix->Pressure_lambda_Increment; + AT_Bin_Num = lambda_H_fix->Pressure_Bin_Num; + AT_Update_Frequency = lambda_H_fix->Pressure_Update_Frequency; + AT_Update_Time_Begin = lambda_H_fix->Pressure_Update_Time_Begin; + AT_Update_Time_End = lambda_H_fix->Pressure_Update_Time_End; + + AT_Pressure_Comp_Flag = lambda_H_fix->Pressure_Comp_Flag; + AT_center_box = lambda_H_fix->center_box; + AT_Hybrid_Style = lambda_H_fix->Hybrid_Style; + + + } + } + + if(me == 0){ + if (screen){ + fprintf(screen,"AT_lambda_Increment= %f\n",AT_lambda_Increment); + fprintf(screen,"AT_Bin_Num= %d\n",AT_Bin_Num); + fprintf(screen,"AT_Update_Frequency= %d\n",AT_Update_Frequency); + fprintf(screen,"AT_Update_Time_Begin= %d\n",AT_Update_Time_Begin); + fprintf(screen,"AT_Update_Time_End= %d\n",AT_Update_Time_End); + fprintf(screen,"AT_Pressure_Comp_Flag= %d\n",AT_Pressure_Comp_Flag); + } + + if (logfile){ + fprintf(logfile,"AT_lambda_Increment= %f\n",AT_lambda_Increment); + fprintf(logfile,"AT_Bin_Num= %d\n",AT_Bin_Num); + fprintf(logfile,"AT_Update_Frequency= %d\n",AT_Update_Frequency); + fprintf(logfile,"AT_Update_Time_Begin= %d\n",AT_Update_Time_Begin); + fprintf(logfile,"AT_Update_Time_End= %d\n",AT_Update_Time_End); + fprintf(logfile,"AT_Pressure_Comp_Flag= %d\n",AT_Pressure_Comp_Flag); + } + } + + memory->create(Comp_Energy_Num_H,AT_Bin_Num,atom->nmoltypesH,"pairLJHAT:Comp_Energy_Num_H"); + memory->create(Comp_Energy_Num_all_H,AT_Bin_Num,atom->nmoltypesH,"pairLJHAT:Comp_Energy_Num_all_H"); + + memory->create(Int_Mean_Energy_H,AT_Bin_Num,atom->nmoltypesH,"pairLJHAT:Int_Mean_Energy_H"); + memory->create(Comp_Energy_H,AT_Bin_Num,atom->nmoltypesH,"pairLJHAT:Comp_Energy_H"); + memory->create(Comp_Energy_all_H,AT_Bin_Num,atom->nmoltypesH,"pairLJHAT:Comp_Energy_all_H"); + memory->create(Mean_Comp_Energy_H,AT_Bin_Num,atom->nmoltypesH,"pairLJHAT:Mean_Comp_Energy_H"); + memory->create(Mean_Energy_H,AT_Bin_Num,atom->nmoltypesH,"pairLJHAT:Mean_Energy_H"); + + for(int j=0;j<atom->nmoltypesH;j++){ + for(int i = 0;i < AT_Bin_Num; i++){ + Int_Mean_Energy_H[i][j]=0; + Comp_Energy_H[i][j]=0; + Comp_Energy_all_H[i][j]=0; + Mean_Comp_Energy_H[i][j]=0; + Comp_Energy_Num_H[i][j] = 0; + Comp_Energy_Num_all_H[i][j] = 0; + } + + } + + H_AdResS_allocated = 1; +} + diff --git a/src/USER-HADRESS/pair_lj_cut_hars_at.h b/src/USER-HADRESS/pair_lj_cut_hars_at.h new file mode 100644 index 000000000..04f41cfc9 --- /dev/null +++ b/src/USER-HADRESS/pair_lj_cut_hars_at.h @@ -0,0 +1,119 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef PAIR_CLASS + +PairStyle(lj/cut/hars/at,PairLJCutHARSAT) + +#else + +#ifndef LMP_PAIR_LJ_CUT_HARS_AT_H +#define LMP_PAIR_LJ_CUT_HARS_AT_H + +#include "pair.h" + +namespace LAMMPS_NS { + +class PairLJCutHARSAT : public Pair { + public: + PairLJCutHARSAT(class LAMMPS *); + virtual ~PairLJCutHARSAT(); + virtual void compute(int, int); + void settings(int, char **); + void coeff(int, char **); + void init_style(); + void init_list(int, class NeighList *); + double init_one(int, int); + void write_restart(FILE *); + void read_restart(FILE *); + void write_restart_settings(FILE *); + void read_restart_settings(FILE *); + void write_data(FILE *); + void write_data_all(FILE *); + double single(int, int, int, int, double, double, double, double &); + void *extract(const char *, int &); + + void compute_inner(); + void compute_middle(); + void compute_outer(int, int); + + void AT_Print_Compensation_Energy(); + void AT_Update_Compensation_Energy(); + + protected: + double cut_global; + double **cut; + double **epsilon,**sigma; + double **lj1,**lj2,**lj3,**lj4,**offset; + double *cut_respa; + class FixLambdaHCalc *lambda_H_fix; + + int AllAtomistic; + + virtual void allocate(); + +//private: + int me; + + int H_AdResS_allocated; + + int **Comp_Energy_Num_H,**Comp_Energy_Num_all_H, Comp_Counter_H; + + double AT_lambda_Increment; + int AT_Bin_Num, AT_Update_Frequency, AT_Update_Time_End, AT_Update_Time_Begin; + int AT_Pressure_Compensation_Run; + int AT_Pressure_Comp_Flag; + + double *AT_center_box,AT_x0lo; + int AT_Hybrid_Style; + double **Int_Mean_Energy_H, **Comp_Energy_H, **Comp_Energy_all_H, **Mean_Energy_H, **Mean_Comp_Energy_H; + + int nmolecules; + tagint idlo,idhi; + + double *AT_massproc_H,*AT_masstotal_H; + + double **AT_mol_f_H, **AT_mol_f_all_H; + + int *AT_molmap_H; // convert molecule ID to local index + int Load_File_Flag; + + int molecules_in_group(tagint &, tagint &); + void Load_Compensation_Pressure(); + void H_AdResS_Allocation(); + +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + +E: Illegal ... command + +Self-explanatory. Check the input script syntax and compare to the +documentation for the command. You can use -echo screen as a +command-line option when running LAMMPS to see the offending line. + +E: Incorrect args for pair coefficients + +Self-explanatory. Check the input script or data file. + +E: Pair cutoff < Respa interior cutoff + +One or more pairwise cutoffs are too short to use with the specified +rRESPA cutoffs. + +*/ diff --git a/src/USER-HADRESS/pair_lj_cut_hars_cg.cpp b/src/USER-HADRESS/pair_lj_cut_hars_cg.cpp new file mode 100644 index 000000000..86d61d447 --- /dev/null +++ b/src/USER-HADRESS/pair_lj_cut_hars_cg.cpp @@ -0,0 +1,1120 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Paul Crozier (SNL) +------------------------------------------------------------------------- */ +#include "mpi.h" +#include "math.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "pair_lj_cut_hars_cg.h" +#include "atom.h" +#include "atom_vec.h" +#include "comm.h" +#include "force.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "update.h" +#include "integrate.h" +#include "respa.h" +#include "math_const.h" +#include "memory.h" +#include "error.h" +#include "domain.h" +#include "iostream" +#include "fix.h" +#include "fix_lambdah_calc.h" +#include "modify.h" + +using namespace LAMMPS_NS; +using namespace MathConst; + +#define BIG MAXTAGINT + +/* ---------------------------------------------------------------------- */ + +PairLJCutHARSCG::PairLJCutHARSCG(LAMMPS *lmp) : Pair(lmp) +{ + respa_enable = 1; + writedata = 1; + + massproc_H = NULL; + masstotal_H = NULL; + molmap_H = NULL; + mol_f_H = NULL; + mol_f_all_H = NULL; + Comp_Energy_Num_H = NULL; + Comp_Energy_Num_all_H = NULL; + + Int_Mean_Energy_H = NULL; + Mean_Energy_H = NULL; + Comp_Energy_H = NULL; + Comp_Energy_all_H = NULL; + Mean_Comp_Energy_H = NULL; + CG_Mean_grad_Comp_Density_Conv_H = NULL; + + molmap_H = NULL; + nmolecules = molecules_in_group(idlo,idhi); + + H_AdResS_allocated = 0; + + CG_Pressure_Compensation_Run = 0; + Density_Compensation_Run = 0; + Comp_Counter_H = 0; + CG_Density_Comp_Flag = 0; + CG_Pressure_Comp_Flag = 0; + + + memory->create(massproc_H,nmolecules,"pair:massproc_H"); + memory->create(masstotal_H,nmolecules,"pair:masstotal_H"); + memory->create(mol_f_H,nmolecules,3,"pair:mol_f_H"); + memory->create(mol_f_all_H,nmolecules,3,"pair:mol_f_all_H"); + + + // compute masstotal for each molecule + + MPI_Comm_rank(world, &me); + int *mask = atom->mask; + tagint *molecule = atom->molecule; + int *type = atom->type; + double *mass = atom->mass; + double *rmass = atom->rmass; + int nlocal = atom->nlocal; + tagint imol; + double massone; + + for (int i = 0; i < nmolecules; i++) massproc_H[i] = 0.0; + + for (int i = 0; i < nlocal; i++) + { +// if (mask[i] & groupbit) { + if (mask[i]) { + if (rmass) massone = rmass[i]; + else massone = mass[type[i]]; + imol = molecule[i]; + if (molmap_H) imol = molmap_H[imol-idlo]; + else imol--; + massproc_H[imol] += massone; + + } + } + + MPI_Allreduce(massproc_H,masstotal_H,nmolecules,MPI_DOUBLE,MPI_SUM,world); + +} + +/* ---------------------------------------------------------------------- */ + +PairLJCutHARSCG::~PairLJCutHARSCG() +{ + + + if (allocated) { + + memory->destroy(setflag); + memory->destroy(cutsq); + + memory->destroy(cut); + memory->destroy(epsilon); + memory->destroy(sigma); + memory->destroy(lj1); + memory->destroy(lj2); + memory->destroy(lj3); + memory->destroy(lj4); + memory->destroy(offset); + memory->destroy(massproc_H); + memory->destroy(masstotal_H); + memory->destroy(molmap_H); + memory->destroy(mol_f_H); + memory->destroy(mol_f_all_H); + memory->destroy(Comp_Energy_Num_H); + memory->destroy(Comp_Energy_Num_all_H); + memory->destroy(Int_Mean_Energy_H); + memory->destroy(Mean_Energy_H); + memory->destroy(Comp_Energy_H); + memory->destroy(Comp_Energy_all_H); + memory->destroy(Mean_Comp_Energy_H); + // memory->destroy(CG_Mean_grad_Comp_Density_Conv_H); + +// delete lambda_H_fix; +} +} + +/* ---------------------------------------------------------------------- */ + +void PairLJCutHARSCG::compute(int eflag, int vflag) +{ + int i,j,ii,jj,inum,jnum,itype,jtype; + double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; + double rsq,r2inv,r6inv,forcelj, factor_lj,Vij; + int *ilist,*jlist,*numneigh,**firstneigh; + int imoltype,jmoltype; + + evdwl = 0.0; + if (eflag || vflag) ev_setup(eflag,vflag); + else evflag = vflag_fdotr = 0; + + double **x = atom->x; + double **f = atom->f; + double *lambdaH = atom->lambdaH; + double **gradlambdaH = atom->gradlambdaH; + double **comH = atom->comH; + int *replambdaH = atom->replambdaH; + tagint *molecule = atom->molecule; + double *mass = atom->mass; + int *moltypeH = atom->moltypeH; + int *type = atom->type; + int nlocal = atom->nlocal; + double *special_lj = force->special_lj; + int newton_pair = force->newton_pair; + + int ibin, jbin; + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + double iLambda, jLambda, ijLambda; + int imol,jmol; + + + + int This_Step = update->ntimestep; + if(This_Step >= CG_Update_Time_Begin && This_Step <= CG_Update_Time_End && CG_Pressure_Comp_Flag != 0){ + CG_Pressure_Compensation_Run = 1; + if(me==0 && This_Step == CG_Update_Time_Begin){ + if(screen)fprintf(screen,"\nStart of constant-pressure route\n"); + if(logfile)fprintf(logfile,"\nStart of constant-pressure route\n"); + } + } + + + if(update->ntimestep<CG_Restart_Time_Step+1)return; + + + for (int i = 0; i < nmolecules; i++) { + mol_f_H[i][0] = mol_f_H[i][1] = mol_f_H[i][2] = 0; + mol_f_all_H[i][0] = mol_f_all_H[i][1] = mol_f_all_H[i][2] = 0; + } + + + Density_Compensation_Run = lambda_H_fix->Density_Compensation_Run; + + if(Density_Compensation_Run){ + CG_Mean_grad_Comp_Density_Conv_H = lambda_H_fix->Mean_grad_Comp_Density_Conv_H; + } + + for (ii = 0; ii < inum; ii++) { + + i = ilist[ii]; + if(replambdaH[i] == 0)continue; + + xtmp = comH[i][0]; + ytmp = comH[i][1]; + ztmp = comH[i][2]; + +// itype = moltypeH[i]; + itype = type[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + imoltype = itype - 1; + + iLambda = 1 - lambdaH[i]; + + for (jj = 0; jj < jnum; jj++) { + + j = jlist[jj]; + factor_lj = special_lj[sbmask(j)]; + j &= NEIGHMASK; + jLambda = 1 - lambdaH[j]; + + if(replambdaH[j] == 0)continue; + + if((iLambda==0 && jLambda==0) && AllCoarseGrained != 1)continue; + + delx = xtmp - comH[j][0]; + dely = ytmp - comH[j][1]; + delz = ztmp - comH[j][2]; + + domain->minimum_image(delx,dely,delz); + + rsq = delx*delx + dely*dely + delz*delz; + jtype = type[j]; + //jtype = moltypeH[j]; + jmoltype = jtype - 1; + +// if (rsq < cutsq[itype][jtype] && lj1[itype][jtype] != 0) { + if (rsq < cutsq[itype][jtype]) { + + + imol = molecule[i]; + jmol = molecule[j]; + if (molmap_H) { + imol = molmap_H[imol-idlo]; + jmol = molmap_H[jmol-idlo]; + } + else { + imol--; + jmol--; + } + + + if(((iLambda==1 && jLambda==1) || AllCoarseGrained)){ + + r2inv = 1.0/rsq; + r6inv = r2inv*r2inv*r2inv; + forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); + + fpair = factor_lj*forcelj*r2inv; + mol_f_H[imol][0] += delx*fpair; + mol_f_H[imol][1] += dely*fpair; + mol_f_H[imol][2] += delz*fpair; + + if (newton_pair || j < nlocal) { + mol_f_H[jmol][0] -= delx*fpair; + mol_f_H[jmol][1] -= dely*fpair; + mol_f_H[jmol][2] -= delz*fpair; + } + + if (eflag) { + evdwl = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - + offset[itype][jtype]; + evdwl *= factor_lj; + } + + if (evflag) ev_tally(i,j,nlocal,newton_pair, + evdwl,0.0,fpair,delx,dely,delz); + + } + + else if(iLambda != 0 || jLambda != 0){ + + ijLambda = 0.5 * (iLambda + jLambda); + r2inv = 1.0/rsq; + r6inv = r2inv*r2inv*r2inv; + forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); + fpair = factor_lj*(forcelj*ijLambda)*r2inv; + + Vij = 0.5*(r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - + offset[itype][jtype]); + + + ibin = floor(iLambda/CG_lambda_Increment); + if(ibin==CG_Bin_Num)ibin = CG_Bin_Num - 1; + + if(CG_Pressure_Compensation_Run != 0 && iLambda != 0 && iLambda != 1)Comp_Energy_H[ibin][imoltype] += Vij; + + mol_f_H[imol][0] += delx*fpair + Vij*gradlambdaH[i][0]; + mol_f_H[imol][1] += dely*fpair + Vij*gradlambdaH[i][1]; + mol_f_H[imol][2] += delz*fpair + Vij*gradlambdaH[i][2]; + + if (newton_pair || j < nlocal) { + + jbin = floor(jLambda/CG_lambda_Increment); + if(jbin==CG_Bin_Num)jbin = CG_Bin_Num - 1; + if(CG_Pressure_Compensation_Run != 0 && jLambda != 0 && jLambda != 1)Comp_Energy_H[jbin][jmoltype] += Vij; + + mol_f_H[jmol][0] -= delx*fpair - Vij*gradlambdaH[j][0]; + mol_f_H[jmol][1] -= dely*fpair - Vij*gradlambdaH[j][1]; + mol_f_H[jmol][2] -= delz*fpair - Vij*gradlambdaH[j][2]; + + } + + if (eflag) { + evdwl = ijLambda*Vij*2.0; + evdwl *= factor_lj; + } + + if (evflag) ev_tally(i,j,nlocal,newton_pair, + evdwl,0.0,fpair,delx,dely,delz); + + } + } + + } + } + + + MPI_Allreduce(&mol_f_H[0][0],&mol_f_all_H[0][0],3*nmolecules,MPI_DOUBLE,MPI_SUM,world); + + if(CG_Pressure_Compensation_Run != 0 && CG_Pressure_Comp_Flag != 0){ + for (int i = 0; i < nlocal; i++){ + iLambda = 1 - lambdaH[i]; + if(replambdaH[i] != 0 && lambdaH[i] != 0 && lambdaH[i] != 1){ + ibin = floor(iLambda/CG_lambda_Increment); + if(ibin==CG_Bin_Num)ibin = CG_Bin_Num - 1; + itype = moltypeH[i] - 1; + Comp_Energy_Num_H[ibin][itype]++; + + } + } + + if(This_Step % CG_Update_Frequency == 0)CG_Update_Compensation_Energy(); + } + + + double mol_mass,mass_frac; + double Grad_Density,r; + if(AllCoarseGrained != 1 && (CG_Density_Comp_Flag != 0 || CG_Pressure_Comp_Flag != 0)){ + + for (int i = 0; i < nlocal; i++){ + imol = molecule[i]; + if (molmap_H)imol = molmap_H[imol-idlo]; + else imol--; + mol_mass = masstotal_H[imol]; + mass_frac = mass[type[i]] / mol_mass; + iLambda = 1 - lambdaH[i]; + + if(iLambda != 0 && iLambda != 1){ + + ibin = floor(iLambda/CG_lambda_Increment); + itype = moltypeH[i] - 1; + + f[i][0] += mass_frac*(mol_f_all_H[imol][0]-gradlambdaH[i][0]*Mean_Comp_Energy_H[ibin][itype]); + f[i][1] += mass_frac*(mol_f_all_H[imol][1]-gradlambdaH[i][1]*Mean_Comp_Energy_H[ibin][itype]); + f[i][2] += mass_frac*(mol_f_all_H[imol][2]-gradlambdaH[i][2]*Mean_Comp_Energy_H[ibin][itype]); + + if (evflag) ev_tally(i,i,nlocal,newton_pair, + -0.5*Int_Mean_Energy_H[ibin][itype],0.0,0.0,0.0,0.0,0.0); + + + if(CG_Density_Comp_Flag != 0){ + + if(CG_Hybrid_Style == 0){ + ibin = floor((comH[i][0]-CG_x0lo)/CG_Density_Bin_Size); + f[i][0] += mass_frac*(-1.0*CG_Mean_grad_Comp_Density_Conv_H[ibin][itype]); + } + else if(CG_Hybrid_Style == 1){ + delx = comH[i][0] - CG_center_box[0]; + dely = comH[i][1] - CG_center_box[1]; + delz = comH[i][2] - CG_center_box[2]; + r = sqrt(delx*delx + dely*dely + delz*delz); + ibin = floor(r/CG_Density_Bin_Size); + + Grad_Density = CG_Mean_grad_Comp_Density_Conv_H[ibin][itype] / r; + f[i][0] += -mass_frac * Grad_Density * delx; + f[i][1] += -mass_frac * Grad_Density * dely; + f[i][2] += -mass_frac * Grad_Density * delz; + } + else if(CG_Hybrid_Style == 2){ + delx = comH[i][0] - CG_center_box[0]; + dely = comH[i][1] - CG_center_box[1]; + r = sqrt(delx*delx + dely*dely); + ibin = floor(r/CG_Density_Bin_Size); + + Grad_Density = CG_Mean_grad_Comp_Density_Conv_H[ibin][itype] / r; + f[i][0] += -mass_frac * Grad_Density * delx; + f[i][1] += -mass_frac * Grad_Density * dely; + } + + } + } + else{ + f[i][0] += mass_frac*mol_f_all_H[imol][0]; + f[i][1] += mass_frac*mol_f_all_H[imol][1]; + f[i][2] += mass_frac*mol_f_all_H[imol][2]; + } + + } + + } + else{ + + for (int i = 0; i < nlocal; i++){ + imol = molecule[i]; + if (molmap_H)imol = molmap_H[imol-idlo]; + else imol--; + mol_mass = masstotal_H[imol]; + mass_frac = mass[type[i]] / mol_mass; + + f[i][0] += mass_frac*mol_f_all_H[imol][0]; + f[i][1] += mass_frac*mol_f_all_H[imol][1]; + f[i][2] += mass_frac*mol_f_all_H[imol][2]; + } + + } + + + + if(This_Step == CG_Update_Time_End){ + CG_Pressure_Compensation_Run = 0; + if(me == 0){ + if(screen)fprintf(screen,"\nEnd of constant-pressure route\n"); + if(logfile)fprintf(logfile,"\nEnd of constant-pressure route\n"); + + } + } + + + if (vflag_fdotr) virial_fdotr_compute(); +} + +/* ---------------------------------------------------------------------- */ + +void PairLJCutHARSCG::compute_inner() +{ + + error->all(FLERR,"Rrespa has not been included!"); + +} + +/* ---------------------------------------------------------------------- */ + +void PairLJCutHARSCG::compute_middle() +{ + error->all(FLERR,"Rrespa has not been included!"); + +} + +/* ---------------------------------------------------------------------- */ + +void PairLJCutHARSCG::compute_outer(int eflag, int vflag) +{ + error->all(FLERR,"Rrespa has not been included!"); +} + +/* ---------------------------------------------------------------------- + allocate all arrays +------------------------------------------------------------------------- */ + +void PairLJCutHARSCG::allocate() +{ + + allocated = 1; + int n = atom->ntypes; + + memory->create(setflag,n+1,n+1,"pairLJHCG:setflag"); + for (int i = 1; i <= n; i++) + for (int j = i; j <= n; j++) + setflag[i][j] = 0; + + memory->create(cutsq,n+1,n+1,"pairLJHCG:cutsq"); + memory->create(cut,n+1,n+1,"pairLJHCG:cut"); + memory->create(epsilon,n+1,n+1,"pairLJHCG:epsilon"); + memory->create(sigma,n+1,n+1,"pairLJHCG:sigma"); + memory->create(lj1,n+1,n+1,"pairLJHCG:lj1"); + memory->create(lj2,n+1,n+1,"pairLJHCG:lj2"); + memory->create(lj3,n+1,n+1,"pairLJHCG:lj3"); + memory->create(lj4,n+1,n+1,"pairLJHCG:lj4"); + memory->create(offset,n+1,n+1,"pairLJHCG:offset"); + + + +} + +/* ---------------------------------------------------------------------- + global settings +------------------------------------------------------------------------- */ + +void PairLJCutHARSCG::settings(int narg, char **arg) +{ + if (narg != 3) error->all(FLERR,"Illegal pair_style command"); + + cut_global = force->numeric(FLERR,arg[0]); + + AllCoarseGrained = force->numeric(FLERR,arg[1]); + + Load_File_Flag = force->numeric(FLERR,arg[2]); + // reset cutoffs that have been explicitly set + + if (allocated) { + int i,j; + for (i = 1; i <= atom->ntypes; i++) + for (j = i+1; j <= atom->ntypes; j++) + if (setflag[i][j]) cut[i][j] = cut_global; + } + +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs +------------------------------------------------------------------------- */ + +void PairLJCutHARSCG::coeff(int narg, char **arg) +{ + + if (narg < 4 || narg > 5) + error->all(FLERR,"Incorrect args for pair coefficients"); + if (!allocated) allocate(); + + int ilo,ihi,jlo,jhi; + + force->bounds(arg[0],atom->ntypes,ilo,ihi); + force->bounds(arg[1],atom->ntypes,jlo,jhi); + + + + double epsilon_one = force->numeric(FLERR,arg[2]); + double sigma_one = force->numeric(FLERR,arg[3]); + + double cut_one = cut_global; + if (narg == 5) cut_one = force->numeric(FLERR,arg[4]); + + int count = 0; + for (int i = ilo; i <= ihi; i++) { + for (int j = MAX(jlo,i); j <= jhi; j++) { + epsilon[i][j] = epsilon_one; + sigma[i][j] = sigma_one; + cut[i][j] = cut_one; + setflag[i][j] = 1; + count++; + + } + } + + if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients"); +} + +/* ---------------------------------------------------------------------- + init specific to this pair style +------------------------------------------------------------------------- */ + +void PairLJCutHARSCG::init_style() +{ + // request regular or rRESPA neighbor lists + if(me == 0){ + if (screen)fprintf(screen,"CG_H_AdResS_allocated flag = %d\n",H_AdResS_allocated); + if (logfile)fprintf(logfile,"CG_H_AdResS_allocated flag = %d\n",H_AdResS_allocated); + } + + if(!H_AdResS_allocated)H_AdResS_Allocation(); + + + int This_Step = update->ntimestep; + CG_Restart_Time_Step = This_Step; + + if((This_Step >= CG_Update_Time_End || Load_File_Flag) && CG_Pressure_Comp_Flag != 0)Load_Compensation_Pressure(); + + int irequest; + + if (update->whichflag == 1 && strstr(update->integrate_style,"respa")) { + int respa = 0; + if (((Respa *) update->integrate)->level_inner >= 0) respa = 1; + if (((Respa *) update->integrate)->level_middle >= 0) respa = 2; + + if (respa == 0)irequest = neighbor->request(this,instance_me); + else if (respa == 1) { + irequest = neighbor->request(this,instance_me); + neighbor->requests[irequest]->id = 1; + neighbor->requests[irequest]->half = 0; + neighbor->requests[irequest]->respainner = 1; + irequest = neighbor->request(this,instance_me); + neighbor->requests[irequest]->id = 3; + neighbor->requests[irequest]->half = 0; + neighbor->requests[irequest]->respaouter = 1; + } else { + irequest = neighbor->request(this,instance_me); + neighbor->requests[irequest]->id = 1; + neighbor->requests[irequest]->half = 0; + neighbor->requests[irequest]->respainner = 1; + irequest = neighbor->request(this,instance_me); + neighbor->requests[irequest]->id = 2; + neighbor->requests[irequest]->half = 0; + neighbor->requests[irequest]->respamiddle = 1; + irequest = neighbor->request(this,instance_me); + neighbor->requests[irequest]->id = 3; + neighbor->requests[irequest]->half = 0; + neighbor->requests[irequest]->respaouter = 1; + } + + } else irequest = neighbor->request(this,instance_me); + + // set rRESPA cutoffs + + if (strstr(update->integrate_style,"respa") && + ((Respa *) update->integrate)->level_inner >= 0) + cut_respa = ((Respa *) update->integrate)->cutoff; + else cut_respa = NULL; +} + +/* ---------------------------------------------------------------------- + neighbor callback to inform pair style of neighbor list to use + regular or rRESPA +------------------------------------------------------------------------- */ + +void PairLJCutHARSCG::init_list(int id, NeighList *ptr) +{ + if (id == 0) list = ptr; + else if (id == 1) listinner = ptr; + else if (id == 2) listmiddle = ptr; + else if (id == 3) listouter = ptr; +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i +------------------------------------------------------------------------- */ + +double PairLJCutHARSCG::init_one(int i, int j) +{ + if (setflag[i][j] == 0) { + epsilon[i][j] = mix_energy(epsilon[i][i],epsilon[j][j], + sigma[i][i],sigma[j][j]); + sigma[i][j] = mix_distance(sigma[i][i],sigma[j][j]); + cut[i][j] = mix_distance(cut[i][i],cut[j][j]); + } + + + lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0); + lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0); + lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); + lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); + + + if (offset_flag) { + double ratio = sigma[i][j] / cut[i][j]; + offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); + } else offset[i][j] = 0.0; + + lj1[j][i] = lj1[i][j]; + lj2[j][i] = lj2[i][j]; + lj3[j][i] = lj3[i][j]; + lj4[j][i] = lj4[i][j]; + offset[j][i] = offset[i][j]; + + // check interior rRESPA cutoff + + if (cut_respa && cut[i][j] < cut_respa[3]) + error->all(FLERR,"Pair cutoff < Respa interior cutoff"); + + // compute I,J contribution to long-range tail correction + // count total # of atoms of type I and J via Allreduce + + if (tail_flag) { + int *type = atom->type; + int nlocal = atom->nlocal; + + double count[2],all[2]; + count[0] = count[1] = 0.0; + for (int k = 0; k < nlocal; k++) { + if (type[k] == i) count[0] += 1.0; + if (type[k] == j) count[1] += 1.0; + } + MPI_Allreduce(count,all,2,MPI_DOUBLE,MPI_SUM,world); + + double sig2 = sigma[i][j]*sigma[i][j]; + double sig6 = sig2*sig2*sig2; + double rc3 = cut[i][j]*cut[i][j]*cut[i][j]; + double rc6 = rc3*rc3; + double rc9 = rc3*rc6; + etail_ij = 8.0*MY_PI*all[0]*all[1]*epsilon[i][j] * + sig6 * (sig6 - 3.0*rc6) / (9.0*rc9); + ptail_ij = 16.0*MY_PI*all[0]*all[1]*epsilon[i][j] * + sig6 * (2.0*sig6 - 3.0*rc6) / (9.0*rc9); + } + + return cut[i][j]; +} + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file +------------------------------------------------------------------------- */ + +void PairLJCutHARSCG::write_restart(FILE *fp) +{ + write_restart_settings(fp); + + int i,j; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) { + fwrite(&setflag[i][j],sizeof(int),1,fp); + if (setflag[i][j]) { + fwrite(&epsilon[i][j],sizeof(double),1,fp); + fwrite(&sigma[i][j],sizeof(double),1,fp); + fwrite(&cut[i][j],sizeof(double),1,fp); + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts +------------------------------------------------------------------------- */ + +void PairLJCutHARSCG::read_restart(FILE *fp) +{ + read_restart_settings(fp); + allocate(); + + int i,j; + int me = comm->me; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) { + if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); + MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); + if (setflag[i][j]) { + if (me == 0) { + fread(&epsilon[i][j],sizeof(double),1,fp); + fread(&sigma[i][j],sizeof(double),1,fp); + fread(&cut[i][j],sizeof(double),1,fp); + } + MPI_Bcast(&epsilon[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world); + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file +------------------------------------------------------------------------- */ + +void PairLJCutHARSCG::write_restart_settings(FILE *fp) +{ + fwrite(&cut_global,sizeof(double),1,fp); + fwrite(&offset_flag,sizeof(int),1,fp); + fwrite(&mix_flag,sizeof(int),1,fp); + fwrite(&tail_flag,sizeof(int),1,fp); +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts +------------------------------------------------------------------------- */ + +void PairLJCutHARSCG::read_restart_settings(FILE *fp) +{ + int me = comm->me; + if (me == 0) { + fread(&cut_global,sizeof(double),1,fp); + fread(&offset_flag,sizeof(int),1,fp); + fread(&mix_flag,sizeof(int),1,fp); + fread(&tail_flag,sizeof(int),1,fp); + } + MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); + MPI_Bcast(&offset_flag,1,MPI_INT,0,world); + MPI_Bcast(&mix_flag,1,MPI_INT,0,world); + MPI_Bcast(&tail_flag,1,MPI_INT,0,world); +} + +/* ---------------------------------------------------------------------- + proc 0 writes to data file +------------------------------------------------------------------------- */ + +void PairLJCutHARSCG::write_data(FILE *fp) +{ + for (int i = 1; i <= atom->ntypes; i++) + fprintf(fp,"%d %g %g\n",i,epsilon[i][i],sigma[i][i]); +} + +/* ---------------------------------------------------------------------- + proc 0 writes all pairs to data file +------------------------------------------------------------------------- */ + +void PairLJCutHARSCG::write_data_all(FILE *fp) +{ + for (int i = 1; i <= atom->ntypes; i++) + for (int j = i; j <= atom->ntypes; j++) + fprintf(fp,"%d %d %g %g %g\n",i,j,epsilon[i][j],sigma[i][j],cut[i][j]); +} + +/* ---------------------------------------------------------------------- */ + +double PairLJCutHARSCG::single(int i, int j, int itype, int jtype, double rsq, + double factor_coul, double factor_lj, + double &fforce) +{ + double r2inv,r6inv,forcelj,philj; + + r2inv = 1.0/rsq; + r6inv = r2inv*r2inv*r2inv; + forcelj = r6inv * (lj1[itype][jtype]*r6inv - lj2[itype][jtype]); + fforce = factor_lj*forcelj*r2inv; + + philj = r6inv*(lj3[itype][jtype]*r6inv-lj4[itype][jtype]) - + offset[itype][jtype]; + return factor_lj*philj; +} + +/* ---------------------------------------------------------------------- */ + +void *PairLJCutHARSCG::extract(const char *str, int &dim) +{ + dim = 2; + if (strcmp(str,"epsilon") == 0) return (void *) epsilon; + if (strcmp(str,"sigma") == 0) return (void *) sigma; + return NULL; +} + + + +int PairLJCutHARSCG::molecules_in_group(tagint &idlo, tagint &idhi) +{ + int i; + + memory->destroy(molmap_H); + molmap_H = NULL; + + // find lo/hi molecule ID for any atom in group + // warn if atom in group has ID = 0 + + tagint *molecule = atom->molecule; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + tagint lo = BIG; + tagint hi = -BIG; + int flag = 0; + for (i = 0; i < nlocal; i++) + { +// if (mask[i] & groupbit) { + if (mask[i]) { + if (molecule[i] == 0) flag = 1; + lo = MIN(lo,molecule[i]); + hi = MAX(hi,molecule[i]); + } + } + + int flagall; + MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); + if (flagall && comm->me == 0) + error->warning(FLERR,"Atom with molecule ID = 0 included in " + "compute molecule group"); + + MPI_Allreduce(&lo,&idlo,1,MPI_LMP_TAGINT,MPI_MIN,world); + MPI_Allreduce(&hi,&idhi,1,MPI_LMP_TAGINT,MPI_MAX,world); + if (idlo == BIG) return 0; + + // molmap = vector of length nlen + // set to 1 for IDs that appear in group across all procs, else 0 + + tagint nlen_tag = idhi-idlo+1; + if (nlen_tag > MAXSMALLINT) + error->all(FLERR,"Too many molecules for compute"); + int nlen = (int) nlen_tag; + + memory->create(molmap_H,nlen,"pair:molmap_H"); + for (i = 0; i < nlen; i++) molmap_H[i] = 0; + + for (i = 0; i < nlocal; i++) + // if (mask[i] & groupbit) + if (mask[i]) + molmap_H[molecule[i]-idlo] = 1; + + int *molmapall; + memory->create(molmapall,nlen,"pair:molmapall"); + MPI_Allreduce(molmap_H,molmapall,nlen,MPI_INT,MPI_MAX,world); + + // nmolecules = # of non-zero IDs in molmap + // molmap[i] = index of molecule, skipping molecules not in group with -1 + + int nmolecules = 0; + for (i = 0; i < nlen; i++) + if (molmapall[i]) molmap_H[i] = nmolecules++; + else molmap_H[i] = -1; + memory->destroy(molmapall); + + // warn if any molecule has some atoms in group and some not in group + + flag = 0; + for (i = 0; i < nlocal; i++) { +// if (mask[i] & groupbit) continue; + if (mask[i]) continue; + if (molecule[i] < idlo || molecule[i] > idhi) continue; + if (molmap_H[molecule[i]-idlo] >= 0) flag = 1; + } + + MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); + if (flagall && comm->me == 0) + error->warning(FLERR, + "One or more compute molecules has atoms not in group"); + + // if molmap simply stores 1 to Nmolecules, then free it + + if (idlo == 1 && idhi == nmolecules && nlen == nmolecules) { + memory->destroy(molmap_H); + molmap_H = NULL; + } + return nmolecules; +} + + + +void PairLJCutHARSCG::CG_Print_Compensation_Energy(){ + + FILE *fp1; + + fp1 = fopen("Mean_Comp_Energy_CG.txt","w"); + if (fp1 == NULL) { + char str[128]; + sprintf(str,"Cannot open Mean_Comp_Energy_CG.txt file %s","Mean_Comp_Energy_CG.txt"); + error->one(FLERR,str); + + } + + for(int i = 0;i < CG_Bin_Num; i++){ + fprintf(fp1,"%d",i+1); + for(int k = 0; k < atom->nmoltypesH;k++) + fprintf(fp1,"\t%.10f",Mean_Comp_Energy_H[i][k]); + + fprintf(fp1,"\n"); + } + + fclose(fp1); + +} + + + +void PairLJCutHARSCG::CG_Update_Compensation_Energy(){ + + MPI_Allreduce(&Comp_Energy_H[0][0],&Comp_Energy_all_H[0][0],CG_Bin_Num*(atom->nmoltypesH+1),MPI_DOUBLE,MPI_SUM,world); + MPI_Allreduce(&Comp_Energy_Num_H[0][0],&Comp_Energy_Num_all_H[0][0],CG_Bin_Num*(atom->nmoltypesH+1),MPI_INT,MPI_SUM,world); + + for(int k = 0; k < atom->nmoltypesH;k++)for(int i = 0;i < CG_Bin_Num; i++)Mean_Energy_H[i][k] = Comp_Energy_all_H[i][k] / Comp_Energy_Num_all_H[i][k]; + for(int k = 0; k < atom->nmoltypesH;k++)for(int i = 0;i < CG_Bin_Num; i++)Mean_Comp_Energy_H[i][k] = (Comp_Counter_H * Mean_Comp_Energy_H[i][k] + Mean_Energy_H[i][k]) / (Comp_Counter_H + 1); + for(int k = 0; k < atom->nmoltypesH;k++)for(int i = 0;i < CG_Bin_Num; i++)Int_Mean_Energy_H[i][k]=0; + for(int k = 0; k < atom->nmoltypesH;k++)for(int i = 0;i < CG_Bin_Num; i++)for(int j = 0;j <= i; j++)Int_Mean_Energy_H[i][k] += Mean_Comp_Energy_H[j][k] * CG_lambda_Increment; + + Comp_Counter_H++; + + for(int k = 0; k < atom->nmoltypesH;k++){ + for(int i = 0;i < CG_Bin_Num; i++){ + Comp_Energy_Num_H[i][k] = 0; + Comp_Energy_Num_all_H[i][k] = 0; + Comp_Energy_H[i][k] = 0; + Comp_Energy_all_H[i][k] =0; + } + } + + if (me == 0)CG_Print_Compensation_Energy(); + + +} + + +void PairLJCutHARSCG::Load_Compensation_Pressure(){ + + if(me == 0){ + FILE *fp1; + char str[128]; + + fp1 = fopen("Mean_Comp_Energy_CG.txt","r"); + if (fp1 == NULL) { + sprintf(str,"Cannot open fix Mean_Comp_Energy_CG.txt file %s","Mean_Comp_Energy_CG.txt"); + error->one(FLERR,str); + } + + int i1; + float i2; + + while (!feof(fp1)){ + fscanf (fp1,"%d",&i1); + for(int k = 0; k < atom->nmoltypesH;k++){ + fscanf (fp1,"\t%f",&i2); + Mean_Comp_Energy_H[i1-1][k] = i2; + if(i1 > CG_Bin_Num){ + sprintf(str,"CG drift force compensation bin number mismatches %d != %d",CG_Bin_Num,i1); + error->one(FLERR,str); + } + } + + } + } + + + if(me==0){ + if(screen)fprintf(screen,"CG_Pressure componsation forces distributed successfully!\n"); + if(logfile)fprintf(logfile,"CG_Pressure componsation forces distributed successfully!\n"); + } + + MPI_Bcast(Mean_Comp_Energy_H,CG_Bin_Num*(atom->nmoltypesH+1),MPI_DOUBLE,0,world); +} + + +void PairLJCutHARSCG::H_AdResS_Allocation(){ + + + for (int i = 0; i < modify->nfix; i++){ + + if (strcmp(modify->fix[i]->style,"LambdaH/calc") == 0){ + + lambda_H_fix = (FixLambdaHCalc *) modify->fix[i]; + CG_lambda_Increment = lambda_H_fix->Pressure_lambda_Increment; + CG_Bin_Num = lambda_H_fix->Pressure_Bin_Num; + CG_Update_Frequency = lambda_H_fix->Pressure_Update_Frequency; + CG_Update_Time_Begin = lambda_H_fix->Pressure_Update_Time_Begin; + CG_Update_Time_End = lambda_H_fix->Pressure_Update_Time_End; + + CG_Density_Bin_Num = lambda_H_fix->Density_Bin_Num; + CG_Density_Bin_Size = lambda_H_fix->Density_Bin_Size; + CG_Density_Update_Frequency = lambda_H_fix->Density_Update_Frequency; + CG_Density_Update_Time_Begin = lambda_H_fix->Density_Update_Time_Begin; + CG_Density_Update_Time_End = lambda_H_fix->Density_Update_Time_End; + + CG_Pressure_Comp_Flag = lambda_H_fix->Pressure_Comp_Flag; + CG_Density_Comp_Flag = lambda_H_fix->Density_Comp_Flag; + CG_center_box = lambda_H_fix->center_box; + CG_Hybrid_Style = lambda_H_fix->Hybrid_Style; + CG_x0lo = lambda_H_fix->x0lo; + CG_x0BoxSize = lambda_H_fix->x0BoxSize; + } + } + + if(me == 0){ + if (screen){ + fprintf(screen,"CG_lambda_Increment= %f\n",CG_lambda_Increment); + fprintf(screen,"CG_Bin_Num= %d\n",CG_Bin_Num); + fprintf(screen,"CG_Update_Frequency= %d\n",CG_Update_Frequency); + fprintf(screen,"CG_Update_Time_Begin= %d\n",CG_Update_Time_Begin); + fprintf(screen,"CG_Update_Time_End= %d\n",CG_Update_Time_End); + fprintf(screen,"CG_Pressure_Comp_Flag= %d\n",CG_Pressure_Comp_Flag); + fprintf(screen,"CG_Density_Comp_Flag= %d\n",CG_Density_Comp_Flag); + fprintf(screen,"CG_Hybrid_Style= %d\n",CG_Hybrid_Style); + + } + + if (logfile){ + fprintf(logfile,"CG_lambda_Increment= %f\n",CG_lambda_Increment); + fprintf(logfile,"CG_Bin_Num= %d\n",CG_Bin_Num); + fprintf(logfile,"CG_Update_Frequency= %d\n",CG_Update_Frequency); + fprintf(logfile,"CG_Update_Time_Begin= %d\n",CG_Update_Time_Begin); + fprintf(logfile,"CG_Update_Time_End= %d\n",CG_Update_Time_End); + fprintf(logfile,"CG_Pressure_Comp_Flag= %d\n",CG_Pressure_Comp_Flag); + fprintf(logfile,"CG_Density_Comp_Flag= %d\n",CG_Density_Comp_Flag); + fprintf(logfile,"CG_Hybrid_Style= %d\n",CG_Hybrid_Style); + + } + + + } + + + memory->create(Comp_Energy_Num_H,CG_Bin_Num,atom->nmoltypesH+1,"pairLJHCG:Comp_Energy_Num_H"); + memory->create(Comp_Energy_Num_all_H,CG_Bin_Num,atom->nmoltypesH+1,"pairLJHCG:Comp_Energy_Num_all_H"); + memory->create(Int_Mean_Energy_H,CG_Bin_Num,atom->nmoltypesH+1,"pairLJHCG:Int_Mean_Energy_H"); + memory->create(Comp_Energy_H,CG_Bin_Num,atom->nmoltypesH+1,"pairLJHCG:Comp_Energy_H"); + memory->create(Comp_Energy_all_H,CG_Bin_Num,atom->nmoltypesH+1,"pairLJHCG:Comp_Energy_all_H"); + memory->create(Mean_Comp_Energy_H,CG_Bin_Num,atom->nmoltypesH+1,"pairLJHCG:Mean_Comp_Energy_H"); + memory->create(Mean_Energy_H,CG_Bin_Num,atom->nmoltypesH+1,"pairLJHCG:Mean_Energy_H"); + + memory->create(CG_Mean_grad_Comp_Density_Conv_H,CG_Density_Bin_Num,atom->nmoltypesH+1,"pairLJHCG:CG_Mean_grad_Comp_Density_Conv_H"); + CG_Mean_grad_Comp_Density_Conv_H = lambda_H_fix->Mean_grad_Comp_Density_Conv_H; + + + for(int i = 0;i < CG_Bin_Num; i++){ + for(int j = 0; j < atom->nmoltypesH; j++){ + Int_Mean_Energy_H[i][j] = 0; + Comp_Energy_H[i][j] = 0; + Comp_Energy_all_H[i][j] = 0; + Mean_Comp_Energy_H[i][j] = 0; + Comp_Energy_Num_H[i][j] = 0; + Comp_Energy_Num_all_H[i][j] = 0; + } + } + + + H_AdResS_allocated = 1; + +} diff --git a/src/USER-HADRESS/pair_lj_cut_hars_cg.h b/src/USER-HADRESS/pair_lj_cut_hars_cg.h new file mode 100644 index 000000000..df47c27ec --- /dev/null +++ b/src/USER-HADRESS/pair_lj_cut_hars_cg.h @@ -0,0 +1,123 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef PAIR_CLASS + +PairStyle(lj/cut/hars/cg,PairLJCutHARSCG) + +#else + +#ifndef LMP_PAIR_LJ_CUT_HARS_CG_H +#define LMP_PAIR_LJ_CUT_HARS_CG_H + +#include "pair.h" + +namespace LAMMPS_NS { + +class PairLJCutHARSCG : public Pair { + public: + PairLJCutHARSCG(class LAMMPS *); + virtual ~PairLJCutHARSCG(); + virtual void compute(int, int); + void settings(int, char **); + void coeff(int, char **); + void init_style(); + void init_list(int, class NeighList *); + double init_one(int, int); + void write_restart(FILE *); + void read_restart(FILE *); + void write_restart_settings(FILE *); + void read_restart_settings(FILE *); + void write_data(FILE *); + void write_data_all(FILE *); + double single(int, int, int, int, double, double, double, double &); + void *extract(const char *, int &); + + void compute_inner(); + void compute_middle(); + void compute_outer(int, int); + + void CG_Print_Compensation_Energy(); + void CG_Update_Compensation_Energy(); + + protected: + double cut_global; + double **cut; + double **epsilon,**sigma; + double **lj1,**lj2,**lj3,**lj4,**offset; + double *cut_respa; + class FixLambdaHCalc *lambda_H_fix; + int AllCoarseGrained; + + double *CG_Ave_Mean_Density_H,CG_grad_Ave_Mean_Density_H; + //private: + + int me; + virtual void allocate(); + + int H_AdResS_allocated; + int **Comp_Energy_Num_H,**Comp_Energy_Num_all_H, Comp_Counter_H; + + double CG_lambda_Increment; + int CG_Bin_Num, CG_Update_Frequency, CG_Update_Time_End, CG_Update_Time_Begin; + int CG_Pressure_Compensation_Run, Density_Compensation_Run; + + int CG_Pressure_Comp_Flag, CG_Density_Comp_Flag; + + double CG_Density_Bin_Size,**CG_Mean_grad_Comp_Density_Conv_H,CG_x0BoxSize; + int CG_Density_Bin_Num,CG_Density_Update_Frequency,CG_Density_Update_Time_Begin,CG_Density_Update_Time_End; + double **Int_Mean_Energy_H, **Comp_Energy_H, **Comp_Energy_all_H, **Mean_Energy_H, **Mean_Comp_Energy_H; + + double *CG_center_box, CG_x0lo; + int CG_Hybrid_Style; + int nmolecules; + tagint idlo,idhi; + + double *massproc_H,*masstotal_H; + + double **mol_f_H, **mol_f_all_H; + + int CG_Restart_Time_Step; + //double **drift_f_H, **drift_f_all_H; + //int nbin_H; + int *molmap_H; // convert molecule ID to local index + int Load_File_Flag; + + int molecules_in_group(tagint &, tagint &); + void Load_Compensation_Pressure(); + void H_AdResS_Allocation(); +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + +E: Illegal ... command + +Self-explanatory. Check the input script syntax and compare to the +documentation for the command. You can use -echo screen as a +command-line option when running LAMMPS to see the offending line. + +E: Incorrect args for pair coefficients + +Self-explanatory. Check the input script or data file. + +E: Pair cutoff < Respa interior cutoff + +One or more pairwise cutoffs are too short to use with the specified +rRESPA cutoffs. + +*/ diff --git a/src/USER-HADRESS/read_data.cpp b/src/USER-HADRESS/read_data.cpp new file mode 100644 index 000000000..478412ae0 --- /dev/null +++ b/src/USER-HADRESS/read_data.cpp @@ -0,0 +1,2023 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +// lmptype.h must be first b/c this file uses MAXBIGINT and includes mpi.h +// due to OpenMPI bug which sets INT64_MAX via its mpi.h +// before lmptype.h can set flags to insure it is done correctly + +#include "lmptype.h" +#include <mpi.h> +#include <math.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include "read_data.h" +#include "atom.h" +#include "atom_vec.h" +#include "atom_vec_ellipsoid.h" +#include "atom_vec_line.h" +#include "atom_vec_tri.h" +#include "force.h" +#include "molecule.h" +#include "group.h" +#include "comm.h" +#include "update.h" +#include "modify.h" +#include "fix.h" +#include "force.h" +#include "pair.h" +#include "domain.h" +#include "bond.h" +#include "angle.h" +#include "dihedral.h" +#include "improper.h" +#include "special.h" +#include "irregular.h" +#include "error.h" +#include "memory.h" + +using namespace LAMMPS_NS; + +#define MAXLINE 256 +#define LB_FACTOR 1.1 +#define CHUNK 1024 +#define DELTA 4 // must be 2 or larger +#define MAXBODY 32 // max # of lines in one body + + // customize for new sections +#define NSECTIONS 25 // change when add to header::section_keywords + +enum{NONE,APPEND,VALUE,MERGE}; + +// pair style suffixes to ignore +// when matching Pair Coeffs comment to currently-defined pair style + +const char *suffixes[] = {"/cuda","/gpu","/opt","/omp","/kk", + "/coul/cut","/coul/long","/coul/msm", + "/coul/dsf","/coul/debye","/coul/charmm", + NULL}; + +/* ---------------------------------------------------------------------- */ + +ReadData::ReadData(LAMMPS *lmp) : Pointers(lmp) +{ + MPI_Comm_rank(world,&me); + line = new char[MAXLINE]; + copy = new char[MAXLINE]; + keyword = new char[MAXLINE]; + style = new char[MAXLINE]; + buffer = new char[CHUNK*MAXLINE]; + narg = maxarg = 0; + arg = NULL; + fp = NULL; + + // customize for new sections + // pointers to atom styles that store extra info + + nellipsoids = 0; + avec_ellipsoid = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); + nlines = 0; + avec_line = (AtomVecLine *) atom->style_match("line"); + ntris = 0; + avec_tri = (AtomVecTri *) atom->style_match("tri"); + nbodies = 0; + avec_body = (AtomVecBody *) atom->style_match("body"); +} + +/* ---------------------------------------------------------------------- */ + +ReadData::~ReadData() +{ + delete [] line; + delete [] copy; + delete [] keyword; + delete [] style; + delete [] buffer; + memory->sfree(arg); + + for (int i = 0; i < nfix; i++) { + delete [] fix_header[i]; + delete [] fix_section[i]; + } + memory->destroy(fix_index); + memory->sfree(fix_header); + memory->sfree(fix_section); +} + +/* ---------------------------------------------------------------------- */ + +void ReadData::command(int narg, char **arg) +{ + if (narg < 1) error->all(FLERR,"Illegal read_data command"); + + // optional args + + addflag = NONE; + coeffflag = 1; + id_offset = 0; + offsetflag = shiftflag = 0; + toffset = boffset = aoffset = doffset = ioffset = 0; + shift[0] = shift[1] = shift[2] = 0.0; + extra_atom_types = extra_bond_types = extra_angle_types = + extra_dihedral_types = extra_improper_types = 0; + + groupbit = 0; + + nfix = 0; + fix_index = NULL; + fix_header = NULL; + fix_section = NULL; + + int iarg = 1; + while (iarg < narg) { + if (strcmp(arg[iarg],"add") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal read_data command"); + if (strcmp(arg[iarg+1],"append") == 0) addflag = APPEND; + else if (strcmp(arg[iarg+1],"merge") == 0) addflag = MERGE; + else { + addflag = VALUE; + bigint offset = force->bnumeric(FLERR,arg[iarg+1]); + if (offset > MAXTAGINT) + error->all(FLERR,"Read data add offset is too big"); + id_offset = offset; + } + iarg += 2; + } else if (strcmp(arg[iarg],"offset") == 0) { + if (iarg+6 > narg) error->all(FLERR,"Illegal read_data command"); + offsetflag = 1; + toffset = force->inumeric(FLERR,arg[iarg+1]); + boffset = force->inumeric(FLERR,arg[iarg+2]); + aoffset = force->inumeric(FLERR,arg[iarg+3]); + doffset = force->inumeric(FLERR,arg[iarg+4]); + ioffset = force->inumeric(FLERR,arg[iarg+5]); + if (toffset < 0 || boffset < 0 || aoffset < 0 || + doffset < 0 || ioffset < 0) + error->all(FLERR,"Illegal read_data command"); + iarg += 6; + } else if (strcmp(arg[iarg],"shift") == 0) { + if (iarg+4 > narg) error->all(FLERR,"Illegal read_data command"); + shiftflag = 1; + shift[0] = force->numeric(FLERR,arg[iarg+1]); + shift[1] = force->numeric(FLERR,arg[iarg+2]); + shift[2] = force->numeric(FLERR,arg[iarg+3]); + if (domain->dimension == 2 && shift[2] != 0.0) + error->all(FLERR,"Non-zero read_data shift z value for 2d simulation"); + iarg += 4; + } else if (strcmp(arg[iarg],"nocoeff") == 0) { + coeffflag = 0; + iarg ++; + } else if (strcmp(arg[iarg],"extra/atom/types") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal read_data command"); + extra_atom_types = force->inumeric(FLERR,arg[iarg+1]); + if (extra_atom_types < 0) error->all(FLERR,"Illegal read_data command"); + iarg += 2; + } else if (strcmp(arg[iarg],"extra/bond/types") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal read_data command"); + if (!atom->avec->bonds_allow) + error->all(FLERR,"No bonds allowed with this atom style"); + extra_bond_types = force->inumeric(FLERR,arg[iarg+1]); + if (extra_bond_types < 0) error->all(FLERR,"Illegal read_data command"); + iarg += 2; + } else if (strcmp(arg[iarg],"extra/angle/types") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal read_data command"); + if (!atom->avec->angles_allow) + error->all(FLERR,"No angles allowed with this atom style"); + extra_angle_types = force->inumeric(FLERR,arg[iarg+1]); + if (extra_angle_types < 0) error->all(FLERR,"Illegal read_data command"); + iarg += 2; + } else if (strcmp(arg[iarg],"extra/dihedral/types") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal read_data command"); + if (!atom->avec->dihedrals_allow) + error->all(FLERR,"No dihedrals allowed with this atom style"); + extra_dihedral_types = force->inumeric(FLERR,arg[iarg+1]); + if (extra_dihedral_types < 0) + error->all(FLERR,"Illegal read_data command"); + iarg += 2; + } else if (strcmp(arg[iarg],"extra/improper/types") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal read_data command"); + if (!atom->avec->impropers_allow) + error->all(FLERR,"No impropers allowed with this atom style"); + extra_improper_types = force->inumeric(FLERR,arg[iarg+1]); + if (extra_improper_types < 0) + error->all(FLERR,"Illegal read_data command"); + iarg += 2; + + } else if (strcmp(arg[iarg],"group") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal read_data command"); + int igroup = group->find_or_create(arg[iarg+1]); + groupbit = group->bitmask[igroup]; + iarg += 2; + + } else if (strcmp(arg[iarg],"fix") == 0) { + if (iarg+4 > narg) + error->all(FLERR,"Illegal read_data command"); + memory->grow(fix_index,nfix+1,"read_data:fix_index"); + fix_header = (char **) + memory->srealloc(fix_header,(nfix+1)*sizeof(char *), + "read_data:fix_header"); + fix_section = (char **) + memory->srealloc(fix_section,(nfix+1)*sizeof(char *), + "read_data:fix_section"); + fix_index[nfix] = modify->find_fix(arg[iarg+1]); + if (fix_index[nfix] < 0) + error->all(FLERR,"Fix ID for read_data does not exist"); + if (strcmp(arg[iarg+2],"NULL") == 0) fix_header[nfix] = NULL; + else { + int n = strlen(arg[iarg+2]) + 1; + fix_header[nfix] = new char[n]; + strcpy(fix_header[nfix],arg[iarg+2]); + } + int n = strlen(arg[iarg+3]) + 1; + fix_section[nfix] = new char[n]; + strcpy(fix_section[nfix],arg[iarg+3]); + nfix++; + iarg += 4; + + } else error->all(FLERR,"Illegal read_data command"); + } + + // error checks + + if (domain->dimension == 2 && domain->zperiodic == 0) + error->all(FLERR,"Cannot run 2d simulation with nonperiodic Z dimension"); + if (domain->box_exist && !addflag) + error->all(FLERR,"Cannot read_data without add keyword " + "after simulation box is defined"); + if (!domain->box_exist && addflag) + error->all(FLERR,"Cannot use read_data add before " + "simulation box is defined"); + if (offsetflag && addflag == NONE) + error->all(FLERR,"Cannot use read_data offset without add flag"); + if (shiftflag && addflag == NONE) + error->all(FLERR,"Cannot use read_data shift without add flag"); + if (addflag != NONE && + (extra_atom_types || extra_bond_types || extra_angle_types || + extra_dihedral_types || extra_improper_types)) + error->all(FLERR,"Cannot use read_data extra with add flag"); + + // first time system initialization + + if (addflag == NONE) { + domain->box_exist = 1; + update->ntimestep = 0; + } + + // compute atomID offset for addflag = MERGE + + if (addflag == APPEND) { + tagint *tag = atom->tag; + int nlocal = atom->nlocal; + tagint max = 0; + for (int i = 0; i < nlocal; i++) max = MAX(max,tag[i]); + MPI_Allreduce(&max,&id_offset,1,MPI_LMP_TAGINT,MPI_MAX,world); + } + + // set up pointer to hold original styles while we replace them with "zero" + Pair *saved_pair = NULL; + Bond *saved_bond = NULL; + Angle *saved_angle = NULL; + Dihedral *saved_dihedral = NULL; + Improper *saved_improper = NULL; + KSpace *saved_kspace = NULL; + + if (coeffflag == 0) { + char *coeffs[2]; + coeffs[0] = (char *) "10.0"; + coeffs[1] = (char *) "nocoeff"; + + saved_pair = force->pair; + force->pair = NULL; + force->create_pair("zero",0); + if (force->pair) force->pair->settings(2,coeffs); + + coeffs[0] = coeffs[1]; + saved_bond = force->bond; + force->bond = NULL; + force->create_bond("zero",0); + if (force->bond) force->bond->settings(1,coeffs); + + saved_angle = force->angle; + force->angle = NULL; + force->create_angle("zero",0); + if (force->angle) force->angle->settings(1,coeffs); + + saved_dihedral = force->dihedral; + force->dihedral = NULL; + force->create_dihedral("zero",0); + if (force->dihedral) force->dihedral->settings(1,coeffs); + + saved_improper = force->improper; + force->improper = NULL; + force->create_improper("zero",0); + if (force->improper) force->improper->settings(1,coeffs); + + saved_kspace = force->kspace; + force->kspace = NULL; + } + + // ----------------------------------------------------------------- + + // perform 1-pass read if no molecular topology in file + // perform 2-pass read if molecular topology, + // first pass calculates max topology/atom + + // flags for this data file + + int atomflag,topoflag; + int bondflag,angleflag,dihedralflag,improperflag; + int ellipsoidflag,lineflag,triflag,bodyflag; + + atomflag = topoflag = 0; + bondflag = angleflag = dihedralflag = improperflag = 0; + ellipsoidflag = lineflag = triflag = bodyflag = 0; + + // values in this data file + + natoms = ntypes = 0; + nbonds = nangles = ndihedrals = nimpropers = 0; + nbondtypes = nangletypes = ndihedraltypes = nimpropertypes = 0; + triclinic = 0; + keyword[0] = '\0'; + + nlocal_previous = atom->nlocal; + int firstpass = 1; + + while (1) { + + // open file on proc 0 + + if (me == 0) { + if (firstpass && screen) fprintf(screen,"Reading data file ...\n"); + open(arg[0]); + } else fp = NULL; + + // read header info + + header(firstpass); + + // problem setup using info from header + // only done once, if firstpass and first data file + // apply extra settings before grow(), even if no topology in file + // deallocate() insures new settings are used for topology arrays + // if per-atom topology is in file, another grow() is done below + + if (firstpass && addflag == NONE) { + atom->bond_per_atom = atom->extra_bond_per_atom; + atom->angle_per_atom = atom->extra_angle_per_atom; + atom->dihedral_per_atom = atom->extra_dihedral_per_atom; + atom->improper_per_atom = atom->extra_improper_per_atom; + + int n; + if (comm->nprocs == 1) n = static_cast<int> (atom->natoms); + else n = static_cast<int> (LB_FACTOR * atom->natoms / comm->nprocs); + + atom->allocate_type_arrays(); + atom->deallocate_topology(); + atom->avec->grow(n); + + domain->boxlo[0] = boxlo[0]; domain->boxhi[0] = boxhi[0]; + domain->boxlo[1] = boxlo[1]; domain->boxhi[1] = boxhi[1]; + domain->boxlo[2] = boxlo[2]; domain->boxhi[2] = boxhi[2]; + + if (triclinic) { + domain->triclinic = 1; + domain->xy = xy; domain->xz = xz; domain->yz = yz; + } + + domain->print_box(" "); + domain->set_initial_box(); + domain->set_global_box(); + comm->set_proc_grid(); + domain->set_local_box(); + } + + // change simulation box to be union of existing box and new box + shift + // only done if firstpass and not first data file + + if (firstpass && addflag != NONE) { + domain->boxlo[0] = MIN(domain->boxlo[0],boxlo[0]+shift[0]); + domain->boxhi[0] = MAX(domain->boxhi[0],boxhi[0]+shift[0]); + domain->boxlo[1] = MIN(domain->boxlo[1],boxlo[1]+shift[1]); + domain->boxhi[1] = MAX(domain->boxhi[1],boxhi[1]+shift[1]); + domain->boxlo[2] = MIN(domain->boxlo[2],boxlo[2]+shift[2]); + domain->boxhi[2] = MAX(domain->boxhi[2],boxhi[2]+shift[2]); + + // NOTE: not sure what to do about tilt value in subsequent data files + //if (triclinic) { + // domain->xy = xy; domain->xz = xz; domain->yz = yz; + // } + + domain->print_box(" "); + domain->set_initial_box(); + domain->set_global_box(); + comm->set_proc_grid(); + domain->set_local_box(); + } + + // customize for new sections + // read rest of file in free format + + while (strlen(keyword)) { + + // if special fix matches, it processes section + + if (nfix) { + int i; + for (i = 0; i < nfix; i++) + if (strcmp(keyword,fix_section[i]) == 0) { + if (firstpass) fix(fix_index[i],keyword); + else skip_lines(modify->fix[fix_index[i]]-> + read_data_skip_lines(keyword)); + parse_keyword(0); + break; + } + if (i < nfix) continue; + } + + if (strcmp(keyword,"Atoms") == 0) { + atomflag = 1; + if (firstpass) { + if (me == 0 && !style_match(style,atom->atom_style)) + error->warning(FLERR,"Atom style in data file differs " + "from currently defined atom style"); + atoms(); + } else skip_lines(natoms); + } else if (strcmp(keyword,"Velocities") == 0) { + if (atomflag == 0) + error->all(FLERR,"Must read Atoms before Velocities"); + if (firstpass) velocities(); + else skip_lines(natoms); + + } else if (strcmp(keyword,"Bonds") == 0) { + topoflag = bondflag = 1; + if (nbonds == 0) + error->all(FLERR,"Invalid data file section: Bonds"); + if (atomflag == 0) error->all(FLERR,"Must read Atoms before Bonds"); + bonds(firstpass); + } else if (strcmp(keyword,"Angles") == 0) { + topoflag = angleflag = 1; + if (nangles == 0) + error->all(FLERR,"Invalid data file section: Angles"); + if (atomflag == 0) error->all(FLERR,"Must read Atoms before Angles"); + angles(firstpass); + } else if (strcmp(keyword,"Dihedrals") == 0) { + topoflag = dihedralflag = 1; + if (ndihedrals == 0) + error->all(FLERR,"Invalid data file section: Dihedrals"); + if (atomflag == 0) error->all(FLERR,"Must read Atoms before Dihedrals"); + dihedrals(firstpass); + } else if (strcmp(keyword,"Impropers") == 0) { + topoflag = improperflag = 1; + if (nimpropers == 0) + error->all(FLERR,"Invalid data file section: Impropers"); + if (atomflag == 0) error->all(FLERR,"Must read Atoms before Impropers"); + impropers(firstpass); + + } else if (strcmp(keyword,"Ellipsoids") == 0) { + ellipsoidflag = 1; + if (!avec_ellipsoid) + error->all(FLERR,"Invalid data file section: Ellipsoids"); + if (atomflag == 0) + error->all(FLERR,"Must read Atoms before Ellipsoids"); + if (firstpass) + bonus(nellipsoids,(AtomVec *) avec_ellipsoid,"ellipsoids"); + else skip_lines(nellipsoids); + } else if (strcmp(keyword,"Lines") == 0) { + lineflag = 1; + if (!avec_line) + error->all(FLERR,"Invalid data file section: Lines"); + if (atomflag == 0) error->all(FLERR,"Must read Atoms before Lines"); + if (firstpass) bonus(nlines,(AtomVec *) avec_line,"lines"); + else skip_lines(nlines); + } else if (strcmp(keyword,"Triangles") == 0) { + triflag = 1; + if (!avec_tri) + error->all(FLERR,"Invalid data file section: Triangles"); + if (atomflag == 0) error->all(FLERR,"Must read Atoms before Triangles"); + if (firstpass) bonus(ntris,(AtomVec *) avec_tri,"triangles"); + else skip_lines(ntris); + } else if (strcmp(keyword,"Bodies") == 0) { + bodyflag = 1; + if (!avec_body) + error->all(FLERR,"Invalid data file section: Bodies"); + if (atomflag == 0) error->all(FLERR,"Must read Atoms before Bodies"); + bodies(firstpass); + + } else if (strcmp(keyword,"Masses") == 0) { + if (firstpass) mass(); + else skip_lines(ntypes); + } else if (strcmp(keyword,"Pair Coeffs") == 0) { + if (force->pair == NULL) + error->all(FLERR,"Must define pair_style before Pair Coeffs"); + if (firstpass) { + if (me == 0 && !style_match(style,force->pair_style)) + error->warning(FLERR,"Pair style in data file differs " + "from currently defined pair style"); + paircoeffs(); + } else skip_lines(ntypes); + } else if (strcmp(keyword,"PairIJ Coeffs") == 0) { + if (force->pair == NULL) + error->all(FLERR,"Must define pair_style before PairIJ Coeffs"); + if (firstpass) { + if (me == 0 && !style_match(style,force->pair_style)) + error->warning(FLERR,"Pair style in data file differs " + "from currently defined pair style"); + pairIJcoeffs(); + } else skip_lines(ntypes*(ntypes+1)/2); + } else if (strcmp(keyword,"Bond Coeffs") == 0) { + if (atom->avec->bonds_allow == 0) + error->all(FLERR,"Invalid data file section: Bond Coeffs"); + if (force->bond == NULL) + error->all(FLERR,"Must define bond_style before Bond Coeffs"); + if (firstpass) { + if (me == 0 && !style_match(style,force->bond_style)) + error->warning(FLERR,"Bond style in data file differs " + "from currently defined bond style"); + bondcoeffs(); + } else skip_lines(nbondtypes); + } else if (strcmp(keyword,"Angle Coeffs") == 0) { + if (atom->avec->angles_allow == 0) + error->all(FLERR,"Invalid data file section: Angle Coeffs"); + if (force->angle == NULL) + error->all(FLERR,"Must define angle_style before Angle Coeffs"); + if (firstpass) { + if (me == 0 && !style_match(style,force->angle_style)) + error->warning(FLERR,"Angle style in data file differs " + "from currently defined angle style"); + anglecoeffs(0); + } else skip_lines(nangletypes); + } else if (strcmp(keyword,"Dihedral Coeffs") == 0) { + if (atom->avec->dihedrals_allow == 0) + error->all(FLERR,"Invalid data file section: Dihedral Coeffs"); + if (force->dihedral == NULL) + error->all(FLERR,"Must define dihedral_style before Dihedral Coeffs"); + if (firstpass) { + if (me == 0 && !style_match(style,force->dihedral_style)) + error->warning(FLERR,"Dihedral style in data file differs " + "from currently defined dihedral style"); + dihedralcoeffs(0); + } else skip_lines(ndihedraltypes); + } else if (strcmp(keyword,"Improper Coeffs") == 0) { + if (atom->avec->impropers_allow == 0) + error->all(FLERR,"Invalid data file section: Improper Coeffs"); + if (force->improper == NULL) + error->all(FLERR,"Must define improper_style before Improper Coeffs"); + if (firstpass) { + if (me == 0 && !style_match(style,force->improper_style)) + error->warning(FLERR,"Improper style in data file differs " + "from currently defined improper style"); + impropercoeffs(0); + } else skip_lines(nimpropertypes); + + } else if (strcmp(keyword,"BondBond Coeffs") == 0) { + if (atom->avec->angles_allow == 0) + error->all(FLERR,"Invalid data file section: BondBond Coeffs"); + if (force->angle == NULL) + error->all(FLERR,"Must define angle_style before BondBond Coeffs"); + if (firstpass) anglecoeffs(1); + else skip_lines(nangletypes); + } else if (strcmp(keyword,"BondAngle Coeffs") == 0) { + if (atom->avec->angles_allow == 0) + error->all(FLERR,"Invalid data file section: BondAngle Coeffs"); + if (force->angle == NULL) + error->all(FLERR,"Must define angle_style before BondAngle Coeffs"); + if (firstpass) anglecoeffs(2); + else skip_lines(nangletypes); + + } else if (strcmp(keyword,"MiddleBondTorsion Coeffs") == 0) { + if (atom->avec->dihedrals_allow == 0) + error->all(FLERR, + "Invalid data file section: MiddleBondTorsion Coeffs"); + if (force->dihedral == NULL) + error->all(FLERR, + "Must define dihedral_style before " + "MiddleBondTorsion Coeffs"); + if (firstpass) dihedralcoeffs(1); + else skip_lines(ndihedraltypes); + } else if (strcmp(keyword,"EndBondTorsion Coeffs") == 0) { + if (atom->avec->dihedrals_allow == 0) + error->all(FLERR,"Invalid data file section: EndBondTorsion Coeffs"); + if (force->dihedral == NULL) + error->all(FLERR, + "Must define dihedral_style before EndBondTorsion Coeffs"); + if (firstpass) dihedralcoeffs(2); + else skip_lines(ndihedraltypes); + } else if (strcmp(keyword,"AngleTorsion Coeffs") == 0) { + if (atom->avec->dihedrals_allow == 0) + error->all(FLERR,"Invalid data file section: AngleTorsion Coeffs"); + if (force->dihedral == NULL) + error->all(FLERR, + "Must define dihedral_style before AngleTorsion Coeffs"); + if (firstpass) dihedralcoeffs(3); + else skip_lines(ndihedraltypes); + } else if (strcmp(keyword,"AngleAngleTorsion Coeffs") == 0) { + if (atom->avec->dihedrals_allow == 0) + error->all(FLERR, + "Invalid data file section: AngleAngleTorsion Coeffs"); + if (force->dihedral == NULL) + error->all(FLERR, + "Must define dihedral_style before " + "AngleAngleTorsion Coeffs"); + if (firstpass) dihedralcoeffs(4); + else skip_lines(ndihedraltypes); + } else if (strcmp(keyword,"BondBond13 Coeffs") == 0) { + if (atom->avec->dihedrals_allow == 0) + error->all(FLERR,"Invalid data file section: BondBond13 Coeffs"); + if (force->dihedral == NULL) + error->all(FLERR, + "Must define dihedral_style before BondBond13 Coeffs"); + if (firstpass) dihedralcoeffs(5); + else skip_lines(ndihedraltypes); + + } else if (strcmp(keyword,"AngleAngle Coeffs") == 0) { + if (atom->avec->impropers_allow == 0) + error->all(FLERR,"Invalid data file section: AngleAngle Coeffs"); + if (force->improper == NULL) + error->all(FLERR, + "Must define improper_style before AngleAngle Coeffs"); + if (firstpass) impropercoeffs(1); + else skip_lines(nimpropertypes); + + } else { + char str[128]; + sprintf(str,"Unknown identifier in data file: %s",keyword); + error->all(FLERR,str); + } + + parse_keyword(0); + } + + // error if natoms > 0 yet no atoms were read + + if (natoms > 0 && atomflag == 0) + error->all(FLERR,"No atoms in data file"); + + // close file + + if (me == 0) { + if (compressed) pclose(fp); + else fclose(fp); + fp = NULL; + } + + // done if this was 2nd pass + + if (!firstpass) break; + + // at end of 1st pass, error check for required sections + // customize for new sections + + if ((nbonds && !bondflag) || (nangles && !angleflag) || + (ndihedrals && !dihedralflag) || (nimpropers && !improperflag)) + error->one(FLERR,"Needed molecular topology not in data file"); + + if ((nellipsoids && !ellipsoidflag) || (nlines && !lineflag) || + (ntris && !triflag) || (nbodies && !bodyflag)) + error->one(FLERR,"Needed bonus data not in data file"); + + // break out of loop if no molecular topology in file + // else make 2nd pass + + if (!topoflag) break; + firstpass = 0; + + // reallocate bond,angle,diehdral,improper arrays via grow() + // will use new bond,angle,dihedral,improper per-atom values from 1st pass + // will also observe extra settings even if bond/etc topology not in file + // leaves other atom arrays unchanged, since already nmax in length + + if (addflag == NONE) atom->deallocate_topology(); + atom->avec->grow(atom->nmax); + } + + // assign atoms added by this data file to specified group + + if (groupbit) { + int *mask = atom->mask; + int nlocal = atom->nlocal; + for (int i = nlocal_previous; i < nlocal; i++) + mask[i] |= groupbit; + } + + // create special bond lists for molecular systems + + if (atom->molecular == 1) { + Special special(lmp); + special.build(); + } + + // for atom style template systems, count total bonds,angles,etc + + if (atom->molecular == 2) { + Molecule **onemols = atom->avec->onemols; + int *molindex = atom->molindex; + int *molatom = atom->molatom; + int nlocal = atom->nlocal; + + int imol,iatom; + bigint nbonds,nangles,ndihedrals,nimpropers; + nbonds = nangles = ndihedrals = nimpropers = 0; + + for (int i = 0; i < nlocal; i++) { + imol = molindex[i]; + iatom = molatom[i]; + nbonds += onemols[imol]->num_bond[iatom]; + nangles += onemols[imol]->num_angle[iatom]; + ndihedrals += onemols[imol]->num_dihedral[iatom]; + nimpropers += onemols[imol]->num_improper[iatom]; + } + + MPI_Allreduce(&nbonds,&atom->nbonds,1,MPI_LMP_BIGINT,MPI_SUM,world); + MPI_Allreduce(&nangles,&atom->nangles,1,MPI_LMP_BIGINT,MPI_SUM,world); + MPI_Allreduce(&ndihedrals,&atom->ndihedrals,1,MPI_LMP_BIGINT,MPI_SUM,world); + MPI_Allreduce(&nimpropers,&atom->nimpropers,1,MPI_LMP_BIGINT,MPI_SUM,world); + + if (!force->newton_bond) { + atom->nbonds /= 2; + atom->nangles /= 3; + atom->ndihedrals /= 4; + atom->nimpropers /= 4; + } + + if (me == 0) { + if (atom->nbonds) { + if (screen) + fprintf(screen," " BIGINT_FORMAT " template bonds\n",atom->nbonds); + if (logfile) + fprintf(logfile," " BIGINT_FORMAT " template bonds\n",atom->nbonds); + } + if (atom->nangles) { + if (screen) + fprintf(screen," " BIGINT_FORMAT " template angles\n", + atom->nangles); + if (logfile) + fprintf(logfile," " BIGINT_FORMAT " template angles\n", + atom->nangles); + } + if (atom->ndihedrals) { + if (screen) + fprintf(screen," " BIGINT_FORMAT " template dihedrals\n", + atom->nbonds); + if (logfile) + fprintf(logfile," " BIGINT_FORMAT " template bonds\n", + atom->ndihedrals); + } + if (atom->nimpropers) { + if (screen) + fprintf(screen," " BIGINT_FORMAT " template impropers\n", + atom->nimpropers); + if (logfile) + fprintf(logfile," " BIGINT_FORMAT " template impropers\n", + atom->nimpropers); + } + } + } + + // for atom style template systems + // insure nbondtypes,etc are still consistent with template molecules, + // in case data file re-defined them + + if (atom->molecular == 2) atom->avec->onemols[0]->check_attributes(1); + + // if adding atoms, migrate atoms to new processors + // use irregular() b/c box size could have changed dramaticaly + // resulting in procs now owning very different subboxes + // with their previously owned atoms now far outside the subbox + + if (addflag != NONE) { + if (domain->triclinic) domain->x2lamda(atom->nlocal); + Irregular *irregular = new Irregular(lmp); + irregular->migrate_atoms(1); + delete irregular; + if (domain->triclinic) domain->lamda2x(atom->nlocal); + } + + // shrink-wrap the box if necessary and move atoms to new procs + // if atoms are lost is b/c data file box was far from shrink-wrapped + // do not use irregular() comm, which would not lose atoms, + // b/c then user could specify data file box as far too big and empty + // do comm->init() but not comm->setup() b/c pair/neigh cutoffs not yet set + // need call to map_set() b/c comm->exchange clears atom map + + if (domain->nonperiodic == 2) { + if (domain->triclinic) domain->x2lamda(atom->nlocal); + domain->reset_box(); + comm->init(); + comm->exchange(); + if (atom->map_style) atom->map_set(); + if (domain->triclinic) domain->lamda2x(atom->nlocal); + + bigint natoms; + bigint nblocal = atom->nlocal; + MPI_Allreduce(&nblocal,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world); + if (natoms != atom->natoms) + error->all(FLERR, + "Read_data shrink wrap did not assign all atoms correctly"); + } + + // restore old styles, when reading with nocoeff flag given + if (coeffflag == 0) { + if (force->pair) delete force->pair; + force->pair = saved_pair; + + if (force->bond) delete force->bond; + force->bond = saved_bond; + + if (force->angle) delete force->angle; + force->angle = saved_angle; + + if (force->dihedral) delete force->dihedral; + force->dihedral = saved_dihedral; + + if (force->improper) delete force->improper; + force->improper = saved_improper; + + force->kspace = saved_kspace; + } +} + +/* ---------------------------------------------------------------------- + read free-format header of data file + 1st line and blank lines are skipped + non-blank lines are checked for header keywords and leading value is read + header ends with EOF or non-blank line containing no header keyword + if EOF, line is set to blank line + else line has first keyword line for rest of file + some logic differs if adding atoms +------------------------------------------------------------------------- */ + +void ReadData::header(int firstpass) +{ + int n; + char *ptr; + + // customize for new sections + + const char *section_keywords[NSECTIONS] = + {"Atoms","Velocities","Ellipsoids","Lines","Triangles","Bodies", + "Bonds","Angles","Dihedrals","Impropers", + "Masses","Pair Coeffs","PairIJ Coeffs","Bond Coeffs","Angle Coeffs", + "Dihedral Coeffs","Improper Coeffs", + "BondBond Coeffs","BondAngle Coeffs","MiddleBondTorsion Coeffs", + "EndBondTorsion Coeffs","AngleTorsion Coeffs", + "AngleAngleTorsion Coeffs","BondBond13 Coeffs","AngleAngle Coeffs"}; + + // skip 1st line of file + + if (me == 0) { + char *eof = fgets(line,MAXLINE,fp); + if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); + } + + while (1) { + + // read a line and bcast length + + if (me == 0) { + if (fgets(line,MAXLINE,fp) == NULL) n = 0; + else n = strlen(line) + 1; + } + MPI_Bcast(&n,1,MPI_INT,0,world); + + // if n = 0 then end-of-file so return with blank line + + if (n == 0) { + line[0] = '\0'; + return; + } + + MPI_Bcast(line,n,MPI_CHAR,0,world); + + // trim anything from '#' onward + // if line is blank, continue + + if ((ptr = strchr(line,'#'))) *ptr = '\0'; + if (strspn(line," \t\n\r") == strlen(line)) continue; + + // allow special fixes first chance to match and process the line + // if fix matches, continue to next header line + + if (nfix) { + for (n = 0; n < nfix; n++) { + if (!fix_header[n]) continue; + if (strstr(line,fix_header[n])) { + modify->fix[fix_index[n]]->read_data_header(line); + break; + } + } + if (n < nfix) continue; + } + + // search line for header keyword and set corresponding variable + // customize for new header lines + + if (strstr(line,"atoms")) { + sscanf(line,BIGINT_FORMAT,&natoms); + if (addflag == NONE) atom->natoms = natoms; + else if (firstpass) atom->natoms += natoms; + + // check for these first + // otherwise "triangles" will be matched as "angles" + + } else if (strstr(line,"ellipsoids")) { + if (!avec_ellipsoid) + error->all(FLERR,"No ellipsoids allowed with this atom style"); + sscanf(line,BIGINT_FORMAT,&nellipsoids); + } else if (strstr(line,"lines")) { + if (!avec_line) + error->all(FLERR,"No lines allowed with this atom style"); + sscanf(line,BIGINT_FORMAT,&nlines); + } else if (strstr(line,"triangles")) { + if (!avec_tri) + error->all(FLERR,"No triangles allowed with this atom style"); + sscanf(line,BIGINT_FORMAT,&ntris); + } else if (strstr(line,"bodies")) { + if (!avec_body) + error->all(FLERR,"No bodies allowed with this atom style"); + sscanf(line,BIGINT_FORMAT,&nbodies); + + } else if (strstr(line,"bonds")) { + sscanf(line,BIGINT_FORMAT,&nbonds); + if (addflag == NONE) atom->nbonds = nbonds; + else if (firstpass) atom->nbonds += nbonds; + } else if (strstr(line,"angles")) { + sscanf(line,BIGINT_FORMAT,&nangles); + if (addflag == NONE) atom->nangles = nangles; + else if (firstpass) atom->nangles += nangles; + } else if (strstr(line,"dihedrals")) { + sscanf(line,BIGINT_FORMAT,&ndihedrals); + if (addflag == NONE) atom->ndihedrals = ndihedrals; + else if (firstpass) atom->ndihedrals += ndihedrals; + } else if (strstr(line,"impropers")) { + sscanf(line,BIGINT_FORMAT,&nimpropers); + if (addflag == NONE) atom->nimpropers = nimpropers; + else if (firstpass) atom->nimpropers += nimpropers; + + // Atom class type settings are only set by first data file + + } else if (strstr(line,"atom types")) { + sscanf(line,"%d",&ntypes); + if (addflag == NONE) atom->ntypes = ntypes + extra_atom_types; + } else if (strstr(line,"mol_H types")){ + sscanf(line,"%d",&atom->nmoltypesH); + } + else if (strstr(line,"bond types")) { + sscanf(line,"%d",&nbondtypes); + if (addflag == NONE) atom->nbondtypes = nbondtypes + extra_bond_types; + } else if (strstr(line,"angle types")) { + sscanf(line,"%d",&nangletypes); + if (addflag == NONE) atom->nangletypes = nangletypes + extra_angle_types; + } else if (strstr(line,"dihedral types")) { + sscanf(line,"%d",&ndihedraltypes); + if (addflag == NONE) + atom->ndihedraltypes = ndihedraltypes + extra_dihedral_types; + } else if (strstr(line,"improper types")) { + sscanf(line,"%d",&nimpropertypes); + if (addflag == NONE) + atom->nimpropertypes = nimpropertypes + extra_improper_types; + + // these settings only used by first data file + + } else if (strstr(line,"extra bond per atom")) { + if (addflag == NONE) sscanf(line,"%d",&atom->extra_bond_per_atom); + } else if (strstr(line,"extra angle per atom")) { + if (addflag == NONE) sscanf(line,"%d",&atom->extra_angle_per_atom); + } else if (strstr(line,"extra dihedral per atom")) { + if (addflag == NONE) sscanf(line,"%d",&atom->extra_dihedral_per_atom); + } else if (strstr(line,"extra improper per atom")) { + if (addflag == NONE) sscanf(line,"%d",&atom->extra_improper_per_atom); + } else if (strstr(line,"extra special per atom")) { + if (addflag == NONE) sscanf(line,"%d",&force->special_extra); + + // local copy of box info + // so can treat differently for first vs subsequent data files + + } else if (strstr(line,"xlo xhi")) { + sscanf(line,"%lg %lg",&boxlo[0],&boxhi[0]); + } else if (strstr(line,"ylo yhi")) { + sscanf(line,"%lg %lg",&boxlo[1],&boxhi[1]); + } else if (strstr(line,"zlo zhi")) { + sscanf(line,"%lg %lg",&boxlo[2],&boxhi[2]); + } else if (strstr(line,"xy xz yz")) { + triclinic = 1; + sscanf(line,"%lg %lg %lg",&xy,&xz,&yz); + + } else break; + } + + // error check on total system size + + if (atom->natoms < 0 || atom->natoms >= MAXBIGINT || + atom->nbonds < 0 || atom->nbonds >= MAXBIGINT || + atom->nangles < 0 || atom->nangles >= MAXBIGINT || + atom->ndihedrals < 0 || atom->ndihedrals >= MAXBIGINT || + atom->nimpropers < 0 || atom->nimpropers >= MAXBIGINT) + error->all(FLERR,"System in data file is too big"); + + // check that exiting string is a valid section keyword + + parse_keyword(1); + for (n = 0; n < NSECTIONS; n++) + if (strcmp(keyword,section_keywords[n]) == 0) break; + if (n == NSECTIONS) { + char str[128]; + sprintf(str,"Unknown identifier in data file: %s",keyword); + error->all(FLERR,str); + } + + // error checks on header values + // must be consistent with atom style and other header values + + if ((atom->nbonds || atom->nbondtypes) && + atom->avec->bonds_allow == 0) + error->all(FLERR,"No bonds allowed with this atom style"); + if ((atom->nangles || atom->nangletypes) && + atom->avec->angles_allow == 0) + error->all(FLERR,"No angles allowed with this atom style"); + if ((atom->ndihedrals || atom->ndihedraltypes) && + atom->avec->dihedrals_allow == 0) + error->all(FLERR,"No dihedrals allowed with this atom style"); + if ((atom->nimpropers || atom->nimpropertypes) && + atom->avec->impropers_allow == 0) + error->all(FLERR,"No impropers allowed with this atom style"); + + if (atom->nbonds > 0 && atom->nbondtypes <= 0) + error->all(FLERR,"Bonds defined but no bond types"); + if (atom->nangles > 0 && atom->nangletypes <= 0) + error->all(FLERR,"Angles defined but no angle types"); + if (atom->ndihedrals > 0 && atom->ndihedraltypes <= 0) + error->all(FLERR,"Dihedrals defined but no dihedral types"); + if (atom->nimpropers > 0 && atom->nimpropertypes <= 0) + error->all(FLERR,"Impropers defined but no improper types"); + + if (atom->molecular == 2) { + if (atom->nbonds || atom->nangles || atom->ndihedrals || atom->nimpropers) + error->all(FLERR,"No molecule topology allowed with atom style template"); + } +} + +/* ---------------------------------------------------------------------- + read all atoms +------------------------------------------------------------------------- */ + +void ReadData::atoms() +{ + int nchunk,eof; + + if (me == 0) { + if (screen) fprintf(screen," reading atoms ...\n"); + if (logfile) fprintf(logfile," reading atoms ...\n"); + } + + bigint nread = 0; + + while (nread < natoms) { + nchunk = MIN(natoms-nread,CHUNK); + eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer); + if (eof) error->all(FLERR,"Unexpected end of data file"); + atom->data_atoms(nchunk,buffer,id_offset,toffset,shiftflag,shift); + nread += nchunk; + } + + // check that all atoms were assigned correctly + + bigint n = atom->nlocal; + bigint sum; + MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world); + bigint nassign = sum - (atom->natoms - natoms); + + if (me == 0) { + if (screen) fprintf(screen," " BIGINT_FORMAT " atoms\n",nassign); + if (logfile) fprintf(logfile," " BIGINT_FORMAT " atoms\n",nassign); + } + + if (sum != atom->natoms) + error->all(FLERR,"Did not assign all atoms correctly"); + + // check that atom IDs are valid + + atom->tag_check(); + + // create global mapping of atoms + + if (atom->map_style) { + atom->map_init(); + atom->map_set(); + } +} + +/* ---------------------------------------------------------------------- + read all velocities + to find atoms, must build atom map if not a molecular system +------------------------------------------------------------------------- */ + +void ReadData::velocities() +{ + int nchunk,eof; + + if (me == 0) { + if (screen) fprintf(screen," reading velocities ...\n"); + if (logfile) fprintf(logfile," reading velocities ...\n"); + } + + int mapflag = 0; + if (atom->map_style == 0) { + mapflag = 1; + atom->map_init(); + atom->map_set(); + } + + bigint nread = 0; + + while (nread < natoms) { + nchunk = MIN(natoms-nread,CHUNK); + eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer); + if (eof) error->all(FLERR,"Unexpected end of data file"); + atom->data_vels(nchunk,buffer,id_offset); + nread += nchunk; + } + + if (mapflag) { + atom->map_delete(); + atom->map_style = 0; + } + + if (me == 0) { + if (screen) fprintf(screen," " BIGINT_FORMAT " velocities\n",natoms); + if (logfile) fprintf(logfile," " BIGINT_FORMAT " velocities\n",natoms); + } +} + +/* ---------------------------------------------------------------------- + scan or read all bonds +------------------------------------------------------------------------- */ + +void ReadData::bonds(int firstpass) +{ + int nchunk,eof; + + if (me == 0) { + if (firstpass) { + if (screen) fprintf(screen," scanning bonds ...\n"); + if (logfile) fprintf(logfile," scanning bonds ...\n"); + } else { + if (screen) fprintf(screen," reading bonds ...\n"); + if (logfile) fprintf(logfile," reading bonds ...\n"); + } + } + + // allocate count if firstpass + + int nlocal = atom->nlocal; + int *count = NULL; + if (firstpass) { + memory->create(count,nlocal,"read_data:count"); + for (int i = 0; i < nlocal; i++) count[i] = 0; + } + + // read and process bonds + + bigint nread = 0; + + while (nread < nbonds) { + nchunk = MIN(nbonds-nread,CHUNK); + eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer); + if (eof) error->all(FLERR,"Unexpected end of data file"); + atom->data_bonds(nchunk,buffer,count,id_offset,boffset); + nread += nchunk; + } + + // if firstpass: tally max bond/atom and return + // if addflag = NONE, store max bond/atom with extra + // else just check actual max does not exceed existing max + + if (firstpass) { + int max = 0; + for (int i = nlocal_previous; i < nlocal; i++) max = MAX(max,count[i]); + int maxall; + MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world); + if (addflag == NONE) maxall += atom->extra_bond_per_atom; + + if (me == 0) { + if (screen) fprintf(screen," %d = max bonds/atom\n",maxall); + if (logfile) fprintf(logfile," %d = max bonds/atom\n",maxall); + } + + if (addflag != NONE) { + if (maxall > atom->bond_per_atom) + error->all(FLERR,"Subsequent read data induced " + "too many bonds per atom"); + } else atom->bond_per_atom = maxall; + + memory->destroy(count); + return; + } + + // if 2nd pass: check that bonds were assigned correctly + + bigint n = 0; + for (int i = nlocal_previous; i < nlocal; i++) n += atom->num_bond[i]; + bigint sum; + MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world); + int factor = 1; + if (!force->newton_bond) factor = 2; + + if (me == 0) { + if (screen) fprintf(screen," " BIGINT_FORMAT " bonds\n",sum/factor); + if (logfile) fprintf(logfile," " BIGINT_FORMAT " bonds\n",sum/factor); + } + + if (sum != factor*nbonds) + error->all(FLERR,"Bonds assigned incorrectly"); +} + +/* ---------------------------------------------------------------------- + scan or read all angles +------------------------------------------------------------------------- */ + +void ReadData::angles(int firstpass) +{ + int nchunk,eof; + + if (me == 0) { + if (firstpass) { + if (screen) fprintf(screen," scanning angles ...\n"); + if (logfile) fprintf(logfile," scanning angles ...\n"); + } else { + if (screen) fprintf(screen," reading angles ...\n"); + if (logfile) fprintf(logfile," reading angles ...\n"); + } + } + + // allocate count if firstpass + + int nlocal = atom->nlocal; + int *count = NULL; + if (firstpass) { + memory->create(count,nlocal,"read_data:count"); + for (int i = 0; i < nlocal; i++) count[i] = 0; + } + + // read and process angles + + bigint nread = 0; + + while (nread < nangles) { + nchunk = MIN(nangles-nread,CHUNK); + eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer); + if (eof) error->all(FLERR,"Unexpected end of data file"); + atom->data_angles(nchunk,buffer,count,id_offset,aoffset); + nread += nchunk; + } + + // if firstpass: tally max angle/atom and return + // if addflag = NONE, store max angle/atom with extra + // else just check actual max does not exceed existing max + + if (firstpass) { + int max = 0; + for (int i = nlocal_previous; i < nlocal; i++) max = MAX(max,count[i]); + int maxall; + MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world); + if (addflag == NONE) maxall += atom->extra_angle_per_atom; + + if (me == 0) { + if (screen) fprintf(screen," %d = max angles/atom\n",maxall); + if (logfile) fprintf(logfile," %d = max angles/atom\n",maxall); + } + + if (addflag != NONE) { + if (maxall > atom->angle_per_atom) + error->all(FLERR,"Subsequent read data induced " + "too many angles per atom"); + } else atom->angle_per_atom = maxall; + + memory->destroy(count); + return; + } + + // if 2nd pass: check that angles were assigned correctly + + bigint n = 0; + for (int i = nlocal_previous; i < nlocal; i++) n += atom->num_angle[i]; + bigint sum; + MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world); + int factor = 1; + if (!force->newton_bond) factor = 3; + + if (me == 0) { + if (screen) fprintf(screen," " BIGINT_FORMAT " angles\n",sum/factor); + if (logfile) fprintf(logfile," " BIGINT_FORMAT " angles\n",sum/factor); + } + + if (sum != factor*nangles) + error->all(FLERR,"Angles assigned incorrectly"); +} + +/* ---------------------------------------------------------------------- + scan or read all dihedrals +------------------------------------------------------------------------- */ + +void ReadData::dihedrals(int firstpass) +{ + int nchunk,eof; + + if (me == 0) { + if (firstpass) { + if (screen) fprintf(screen," scanning dihedrals ...\n"); + if (logfile) fprintf(logfile," scanning dihedrals ...\n"); + } else { + if (screen) fprintf(screen," reading dihedrals ...\n"); + if (logfile) fprintf(logfile," reading dihedrals ...\n"); + } + } + + // allocate count if firstpass + + int nlocal = atom->nlocal; + int *count = NULL; + if (firstpass) { + memory->create(count,nlocal,"read_data:count"); + for (int i = 0; i < nlocal; i++) count[i] = 0; + } + + // read and process dihedrals + + bigint nread = 0; + + while (nread < ndihedrals) { + nchunk = MIN(ndihedrals-nread,CHUNK); + eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer); + if (eof) error->all(FLERR,"Unexpected end of data file"); + atom->data_dihedrals(nchunk,buffer,count,id_offset,doffset); + nread += nchunk; + } + + // if firstpass: tally max dihedral/atom and return + // if addflag = NONE, store max dihedral/atom with extra + // else just check actual max does not exceed existing max + + if (firstpass) { + int max = 0; + for (int i = 0; i < nlocal; i++) max = MAX(max,count[i]); + int maxall; + MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world); + if (addflag == NONE) maxall += atom->extra_dihedral_per_atom; + + if (me == 0) { + if (screen) fprintf(screen," %d = max dihedrals/atom\n",maxall); + if (logfile) fprintf(logfile," %d = max dihedrals/atom\n",maxall); + } + + if (addflag != NONE) { + if (maxall > atom->dihedral_per_atom) + error->all(FLERR,"Subsequent read data induced " + "too many dihedrals per atom"); + } else atom->dihedral_per_atom = maxall; + + memory->destroy(count); + return; + } + + // if 2nd pass: check that dihedrals were assigned correctly + + bigint n = 0; + for (int i = nlocal_previous; i < nlocal; i++) n += atom->num_dihedral[i]; + bigint sum; + MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world); + int factor = 1; + if (!force->newton_bond) factor = 4; + + if (me == 0) { + if (screen) fprintf(screen," " BIGINT_FORMAT " dihedrals\n",sum/factor); + if (logfile) fprintf(logfile," " BIGINT_FORMAT " dihedrals\n",sum/factor); + } + + if (sum != factor*ndihedrals) + error->all(FLERR,"Dihedrals assigned incorrectly"); +} + +/* ---------------------------------------------------------------------- + scan or read all impropers +------------------------------------------------------------------------- */ + +void ReadData::impropers(int firstpass) +{ + int nchunk,eof; + + if (me == 0) { + if (firstpass) { + if (screen) fprintf(screen," scanning impropers ...\n"); + if (logfile) fprintf(logfile," scanning impropers ...\n"); + } else { + if (screen) fprintf(screen," reading impropers ...\n"); + if (logfile) fprintf(logfile," reading impropers ...\n"); + } + } + + // allocate count if firstpass + + int nlocal = atom->nlocal; + int *count = NULL; + if (firstpass) { + memory->create(count,nlocal,"read_data:count"); + for (int i = 0; i < nlocal; i++) count[i] = 0; + } + + // read and process impropers + + bigint nread = 0; + + while (nread < nimpropers) { + nchunk = MIN(nimpropers-nread,CHUNK); + eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer); + if (eof) error->all(FLERR,"Unexpected end of data file"); + atom->data_impropers(nchunk,buffer,count,id_offset,ioffset); + nread += nchunk; + } + + // if firstpass: tally max improper/atom and return + // if addflag = NONE, store max improper/atom + // else just check it does not exceed existing max + + if (firstpass) { + int max = 0; + for (int i = nlocal_previous; i < nlocal; i++) max = MAX(max,count[i]); + int maxall; + MPI_Allreduce(&max,&maxall,1,MPI_INT,MPI_MAX,world); + if (addflag == NONE) maxall += atom->extra_improper_per_atom; + + if (me == 0) { + if (screen) fprintf(screen," %d = max impropers/atom\n",maxall); + if (logfile) fprintf(logfile," %d = max impropers/atom\n",maxall); + } + + if (addflag != NONE) { + if (maxall > atom->improper_per_atom) + error->all(FLERR,"Subsequent read data induced " + "too many impropers per atom"); + } else atom->improper_per_atom = maxall; + + memory->destroy(count); + return; + } + + // if 2nd pass: check that impropers were assigned correctly + + bigint n = 0; + for (int i = nlocal_previous; i < nlocal; i++) n += atom->num_improper[i]; + bigint sum; + MPI_Allreduce(&n,&sum,1,MPI_LMP_BIGINT,MPI_SUM,world); + int factor = 1; + if (!force->newton_bond) factor = 4; + + if (me == 0) { + if (screen) fprintf(screen," " BIGINT_FORMAT " impropers\n",sum/factor); + if (logfile) fprintf(logfile," " BIGINT_FORMAT " impropers\n",sum/factor); + } + + if (sum != factor*nimpropers) + error->all(FLERR,"Impropers assigned incorrectly"); +} + +/* ---------------------------------------------------------------------- + read all bonus data + to find atoms, must build atom map if not a molecular system +------------------------------------------------------------------------- */ + +void ReadData::bonus(bigint nbonus, AtomVec *ptr, const char *type) +{ + int nchunk,eof; + + int mapflag = 0; + if (atom->map_style == 0) { + mapflag = 1; + atom->map_init(); + atom->map_set(); + } + + bigint nread = 0; + bigint natoms = nbonus; + + while (nread < natoms) { + nchunk = MIN(natoms-nread,CHUNK); + eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer); + if (eof) error->all(FLERR,"Unexpected end of data file"); + atom->data_bonus(nchunk,buffer,ptr,id_offset); + nread += nchunk; + } + + if (mapflag) { + atom->map_delete(); + atom->map_style = 0; + } + + if (me == 0) { + if (screen) fprintf(screen," " BIGINT_FORMAT " %s\n",natoms,type); + if (logfile) fprintf(logfile," " BIGINT_FORMAT " %s\n",natoms,type); + } +} + +/* ---------------------------------------------------------------------- + read all body data + variable amount of info per body, described by ninteger and ndouble + to find atoms, must build atom map if not a molecular system + if not firstpass, just read past data, but no processing of data +------------------------------------------------------------------------- */ + +void ReadData::bodies(int firstpass) +{ + int m,nchunk,nline,nmax,ninteger,ndouble,nword,ncount,onebody,tmp; + char *eof; + + int mapflag = 0; + if (atom->map_style == 0 && firstpass) { + mapflag = 1; + atom->map_init(); + atom->map_set(); + } + + // nmax = max # of bodies to read in this chunk + // nchunk = actual # read + + bigint nread = 0; + bigint natoms = nbodies; + + while (nread < natoms) { + if (natoms-nread > CHUNK) nmax = CHUNK; + else nmax = natoms-nread; + + if (me == 0) { + nchunk = 0; + nline = 0; + m = 0; + + while (nchunk < nmax && nline <= CHUNK-MAXBODY) { + eof = fgets(&buffer[m],MAXLINE,fp); + if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); + sscanf(&buffer[m],"%d %d %d",&tmp,&ninteger,&ndouble); + m += strlen(&buffer[m]); + + // read lines one at a time into buffer and count words + // count to ninteger and ndouble until have enough lines + + onebody = 0; + + nword = 0; + while (nword < ninteger) { + eof = fgets(&buffer[m],MAXLINE,fp); + if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); + ncount = atom->count_words(&buffer[m],copy); + if (ncount == 0) + error->one(FLERR,"Too few values in body lines in data file"); + nword += ncount; + m += strlen(&buffer[m]); + onebody++; + } + if (nword > ninteger) + error->one(FLERR,"Too many values in body lines in data file"); + + nword = 0; + while (nword < ndouble) { + eof = fgets(&buffer[m],MAXLINE,fp); + if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); + ncount = atom->count_words(&buffer[m],copy); + if (ncount == 0) + error->one(FLERR,"Too few values in body lines in data file"); + nword += ncount; + m += strlen(&buffer[m]); + onebody++; + } + if (nword > ndouble) + error->one(FLERR,"Too many values in body lines in data file"); + + if (onebody+1 > MAXBODY) + error->one(FLERR, + "Too many lines in one body in data file - boost MAXBODY"); + + nchunk++; + nline += onebody+1; + } + + if (buffer[m-1] != '\n') strcpy(&buffer[m++],"\n"); + m++; + } + + MPI_Bcast(&nchunk,1,MPI_INT,0,world); + MPI_Bcast(&m,1,MPI_INT,0,world); + MPI_Bcast(buffer,m,MPI_CHAR,0,world); + + if (firstpass) atom->data_bodies(nchunk,buffer,avec_body,id_offset); + nread += nchunk; + } + + if (mapflag && firstpass) { + atom->map_delete(); + atom->map_style = 0; + } + + if (me == 0 && firstpass) { + if (screen) fprintf(screen," " BIGINT_FORMAT " bodies\n",natoms); + if (logfile) fprintf(logfile," " BIGINT_FORMAT " bodies\n",natoms); + } +} + +/* ---------------------------------------------------------------------- */ + +void ReadData::mass() +{ + char *next; + char *buf = new char[ntypes*MAXLINE]; + + int eof = comm->read_lines_from_file(fp,ntypes,MAXLINE,buf); + if (eof) error->all(FLERR,"Unexpected end of data file"); + + char *original = buf; + for (int i = 0; i < ntypes; i++) { + next = strchr(buf,'\n'); + *next = '\0'; + atom->set_mass(buf,toffset); + buf = next + 1; + } + delete [] original; +} + +/* ---------------------------------------------------------------------- */ + +void ReadData::paircoeffs() +{ + char *next; + char *buf = new char[ntypes*MAXLINE]; + + int eof = comm->read_lines_from_file(fp,ntypes,MAXLINE,buf); + if (eof) error->all(FLERR,"Unexpected end of data file"); + + char *original = buf; + for (int i = 0; i < ntypes; i++) { + next = strchr(buf,'\n'); + *next = '\0'; + parse_coeffs(buf,NULL,1,2,toffset); + if (narg == 0) error->all(FLERR,"Unexpected end of PairCoeffs section"); + force->pair->coeff(narg,arg); + buf = next + 1; + } + delete [] original; +} + +/* ---------------------------------------------------------------------- */ + +void ReadData::pairIJcoeffs() +{ + int i,j; + char *next; + + int nsq = ntypes * (ntypes+1) / 2; + char *buf = new char[nsq * MAXLINE]; + + int eof = comm->read_lines_from_file(fp,nsq,MAXLINE,buf); + if (eof) error->all(FLERR,"Unexpected end of data file"); + + char *original = buf; + for (i = 0; i < ntypes; i++) + for (j = i; j < ntypes; j++) { + next = strchr(buf,'\n'); + *next = '\0'; + parse_coeffs(buf,NULL,0,2,toffset); + if (narg == 0) error->all(FLERR,"Unexpected end of PairCoeffs section"); + force->pair->coeff(narg,arg); + buf = next + 1; + } + delete [] original; +} + +/* ---------------------------------------------------------------------- */ + +void ReadData::bondcoeffs() +{ + char *next; + char *buf = new char[nbondtypes*MAXLINE]; + + int eof = comm->read_lines_from_file(fp,nbondtypes,MAXLINE,buf); + if (eof) error->all(FLERR,"Unexpected end of data file"); + + char *original = buf; + for (int i = 0; i < nbondtypes; i++) { + next = strchr(buf,'\n'); + *next = '\0'; + parse_coeffs(buf,NULL,0,1,boffset); + if (narg == 0) error->all(FLERR,"Unexpected end of BondCoeffs section"); + force->bond->coeff(narg,arg); + buf = next + 1; + } + delete [] original; +} + +/* ---------------------------------------------------------------------- */ + +void ReadData::anglecoeffs(int which) +{ + char *next; + char *buf = new char[nangletypes*MAXLINE]; + + int eof = comm->read_lines_from_file(fp,nangletypes,MAXLINE,buf); + if (eof) error->all(FLERR,"Unexpected end of data file"); + + char *original = buf; + for (int i = 0; i < nangletypes; i++) { + next = strchr(buf,'\n'); + *next = '\0'; + if (which == 0) parse_coeffs(buf,NULL,0,1,aoffset); + else if (which == 1) parse_coeffs(buf,"bb",0,1,aoffset); + else if (which == 2) parse_coeffs(buf,"ba",0,1,aoffset); + if (narg == 0) error->all(FLERR,"Unexpected end of AngleCoeffs section"); + force->angle->coeff(narg,arg); + buf = next + 1; + } + delete [] original; +} + +/* ---------------------------------------------------------------------- */ + +void ReadData::dihedralcoeffs(int which) +{ + char *next; + char *buf = new char[ndihedraltypes*MAXLINE]; + + int eof = comm->read_lines_from_file(fp,ndihedraltypes,MAXLINE,buf); + if (eof) error->all(FLERR,"Unexpected end of data file"); + + char *original = buf; + for (int i = 0; i < ndihedraltypes; i++) { + next = strchr(buf,'\n'); + *next = '\0'; + if (which == 0) parse_coeffs(buf,NULL,0,1,doffset); + else if (which == 1) parse_coeffs(buf,"mbt",0,1,doffset); + else if (which == 2) parse_coeffs(buf,"ebt",0,1,doffset); + else if (which == 3) parse_coeffs(buf,"at",0,1,doffset); + else if (which == 4) parse_coeffs(buf,"aat",0,1,doffset); + else if (which == 5) parse_coeffs(buf,"bb13",0,1,doffset); + if (narg == 0) error->all(FLERR,"Unexpected end of DihedralCoeffs section"); + force->dihedral->coeff(narg,arg); + buf = next + 1; + } + delete [] original; +} + +/* ---------------------------------------------------------------------- */ + +void ReadData::impropercoeffs(int which) +{ + char *next; + char *buf = new char[nimpropertypes*MAXLINE]; + + int eof = comm->read_lines_from_file(fp,nimpropertypes,MAXLINE,buf); + if (eof) error->all(FLERR,"Unexpected end of data file"); + + char *original = buf; + for (int i = 0; i < nimpropertypes; i++) { + next = strchr(buf,'\n'); + *next = '\0'; + if (which == 0) parse_coeffs(buf,NULL,0,1,ioffset); + else if (which == 1) parse_coeffs(buf,"aa",0,1,ioffset); + if (narg == 0) error->all(FLERR,"Unexpected end of ImproperCoeffs section"); + force->improper->coeff(narg,arg); + buf = next + 1; + } + delete [] original; +} + +/* ---------------------------------------------------------------------- + read fix section, pass lines to fix to process + n = index of fix +------------------------------------------------------------------------- */ + +void ReadData::fix(int ifix, char *keyword) +{ + int nchunk,eof; + + bigint nline = modify->fix[ifix]->read_data_skip_lines(keyword); + + bigint nread = 0; + while (nread < nline) { + nchunk = MIN(nline-nread,CHUNK); + eof = comm->read_lines_from_file(fp,nchunk,MAXLINE,buffer); + if (eof) error->all(FLERR,"Unexpected end of data file"); + modify->fix[ifix]->read_data_section(keyword,nchunk,buffer,id_offset); + nread += nchunk; + } +} + +/* ---------------------------------------------------------------------- + reallocate the count vector from cmax to amax+1 and return new length + zero new locations +------------------------------------------------------------------------- */ + +int ReadData::reallocate(int **pcount, int cmax, int amax) +{ + int *count = *pcount; + memory->grow(count,amax+1,"read_data:count"); + for (int i = cmax; i <= amax; i++) count[i] = 0; + *pcount = count; + return amax+1; +} + +/* ---------------------------------------------------------------------- + proc 0 opens data file + test if gzipped +------------------------------------------------------------------------- */ + +void ReadData::open(char *file) +{ + compressed = 0; + char *suffix = file + strlen(file) - 3; + if (suffix > file && strcmp(suffix,".gz") == 0) compressed = 1; + if (!compressed) fp = fopen(file,"r"); + else { +#ifdef LAMMPS_GZIP + char gunzip[128]; + sprintf(gunzip,"gzip -c -d %s",file); + +#ifdef _WIN32 + fp = _popen(gunzip,"rb"); +#else + fp = popen(gunzip,"r"); +#endif + +#else + error->one(FLERR,"Cannot open gzipped file"); +#endif + } + + if (fp == NULL) { + char str[128]; + sprintf(str,"Cannot open file %s",file); + error->one(FLERR,str); + } +} + +/* ---------------------------------------------------------------------- + grab next keyword + read lines until one is non-blank + keyword is all text on line w/out leading & trailing white space + optional style can be appended after comment char '#' + read one additional line (assumed blank) + if any read hits EOF, set keyword to empty + if first = 1, line variable holds non-blank line that ended header +------------------------------------------------------------------------- */ + +void ReadData::parse_keyword(int first) +{ + int eof = 0; + int done = 0; + + // proc 0 reads upto non-blank line plus 1 following line + // eof is set to 1 if any read hits end-of-file + + if (me == 0) { + if (!first) { + if (fgets(line,MAXLINE,fp) == NULL) eof = 1; + } + while (eof == 0 && done == 0) { + int blank = strspn(line," \t\n\r"); + if ((blank == strlen(line)) || (line[blank] == '#')) { + if (fgets(line,MAXLINE,fp) == NULL) eof = 1; + } else done = 1; + } + if (fgets(buffer,MAXLINE,fp) == NULL) { + eof = 1; + buffer[0] = '\0'; + } + } + + // if eof, set keyword empty and return + + MPI_Bcast(&eof,1,MPI_INT,0,world); + if (eof) { + keyword[0] = '\0'; + return; + } + + // bcast keyword line to all procs + + int n; + if (me == 0) n = strlen(line) + 1; + MPI_Bcast(&n,1,MPI_INT,0,world); + MPI_Bcast(line,n,MPI_CHAR,0,world); + + // store optional "style" following comment char '#' after keyword + + char *ptr; + if ((ptr = strchr(line,'#'))) { + *ptr++ = '\0'; + while (*ptr == ' ' || *ptr == '\t') ptr++; + int stop = strlen(ptr) - 1; + while (ptr[stop] == ' ' || ptr[stop] == '\t' + || ptr[stop] == '\n' || ptr[stop] == '\r') stop--; + ptr[stop+1] = '\0'; + strcpy(style,ptr); + } else style[0] = '\0'; + + // copy non-whitespace portion of line into keyword + + int start = strspn(line," \t\n\r"); + int stop = strlen(line) - 1; + while (line[stop] == ' ' || line[stop] == '\t' + || line[stop] == '\n' || line[stop] == '\r') stop--; + line[stop+1] = '\0'; + strcpy(keyword,&line[start]); +} + +/* ---------------------------------------------------------------------- + proc 0 reads N lines from file + could be skipping Natoms lines, so use bigints +------------------------------------------------------------------------- */ + +void ReadData::skip_lines(bigint n) +{ + if (me) return; + if (n <= 0) return; + char *eof = NULL; + for (bigint i = 0; i < n; i++) eof = fgets(line,MAXLINE,fp); + if (eof == NULL) error->one(FLERR,"Unexpected end of data file"); +} + +/* ---------------------------------------------------------------------- + parse a line of coeffs into words, storing them in narg,arg + trim anything from '#' onward + word strings remain in line, are not copied + if addstr != NULL, add addstr as extra arg for class2 angle/dihedral/improper + if 2nd word starts with letter, then is hybrid style, add addstr after it + else add addstr before 2nd word + if dupflag, duplicate 1st word, so pair_coeff "2" becomes "2 2" + if noffset, add offset to first noffset args, which are atom/bond/etc types +------------------------------------------------------------------------- */ + +void ReadData::parse_coeffs(char *line, const char *addstr, + int dupflag, int noffset, int offset) +{ + char *ptr; + if ((ptr = strchr(line,'#'))) *ptr = '\0'; + + narg = 0; + char *word = strtok(line," \t\n\r\f"); + while (word) { + if (narg == maxarg) { + maxarg += DELTA; + arg = (char **) + memory->srealloc(arg,maxarg*sizeof(char *),"read_data:arg"); + } + if (addstr && narg == 1 && !islower(word[0])) arg[narg++] = (char *) addstr; + arg[narg++] = word; + if (addstr && narg == 2 && islower(word[0])) arg[narg++] = (char *) addstr; + if (dupflag && narg == 1) arg[narg++] = word; + word = strtok(NULL," \t\n\r\f"); + } + + if (noffset) { + int value = force->inumeric(FLERR,arg[0]); + sprintf(argoffset1,"%d",value+offset); + arg[0] = argoffset1; + if (noffset == 2) { + value = force->inumeric(FLERR,arg[1]); + sprintf(argoffset2,"%d",value+offset); + arg[1] = argoffset2; + } + } +} + +/* ---------------------------------------------------------------------- + compare two style strings if they both exist + one = comment in data file section, two = currently-defined style + ignore suffixes listed in suffixes array at top of file +------------------------------------------------------------------------- */ + +int ReadData::style_match(const char *one, const char *two) +{ + int i,delta,len,len1,len2; + + if ((one == NULL) || (two == NULL)) return 1; + + len1 = strlen(one); + len2 = strlen(two); + + for (i = 0; suffixes[i] != NULL; i++) { + len = strlen(suffixes[i]); + if ((delta = len1 - len) > 0) + if (strcmp(one+delta,suffixes[i]) == 0) len1 = delta; + if ((delta = len2 - len) > 0) + if (strcmp(two+delta,suffixes[i]) == 0) len2 = delta; + } + + if ((len1 == 0) || (len1 == len2) || (strncmp(one,two,len1) == 0)) return 1; + return 0; +} diff --git a/src/USER-HADRESS/read_data.h b/src/USER-HADRESS/read_data.h new file mode 100644 index 000000000..5463c86f0 --- /dev/null +++ b/src/USER-HADRESS/read_data.h @@ -0,0 +1,560 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef COMMAND_CLASS + +CommandStyle(read_data,ReadData) + +#else + +#ifndef LMP_READ_DATA_H +#define LMP_READ_DATA_H + +#include <stdio.h> +#include "pointers.h" + +namespace LAMMPS_NS { + +class ReadData : protected Pointers { + public: + ReadData(class LAMMPS *); + ~ReadData(); + void command(int, char **); + + private: + int me,compressed; + char *line,*copy,*keyword,*buffer,*style; + FILE *fp; + char **arg; + int narg,maxarg; + char argoffset1[8],argoffset2[8]; + + bigint id_offset; + + int nlocal_previous; + bigint natoms; + bigint nbonds,nangles,ndihedrals,nimpropers; + int ntypes; + int nbondtypes,nangletypes,ndihedraltypes,nimpropertypes; + + bigint nellipsoids; + class AtomVecEllipsoid *avec_ellipsoid; + bigint nlines; + class AtomVecLine *avec_line; + bigint ntris; + class AtomVecTri *avec_tri; + bigint nbodies; + class AtomVecBody *avec_body; + + // box info + + double boxlo[3],boxhi[3]; + double xy,xz,yz; + int triclinic; + + // optional args + + int addflag,offsetflag,shiftflag,coeffflag; + tagint addvalue; + int toffset,boffset,aoffset,doffset,ioffset; + double shift[3]; + int extra_atom_types,extra_bond_types,extra_angle_types; + int extra_dihedral_types,extra_improper_types; + int groupbit; + + int nfix; + int *fix_index; + char **fix_header; + char **fix_section; + + // methods + + void open(char *); + void scan(int &, int &, int &, int &); + int reallocate(int **, int, int); + void header(int); + void parse_keyword(int); + void skip_lines(bigint); + void parse_coeffs(char *, const char *, int, int, int); + int style_match(const char *, const char *); + + void atoms(); + void velocities(); + + void bonds(int); + void bond_scan(int, char *, int *); + void angles(int); + void dihedrals(int); + void impropers(int); + + void bonus(bigint, class AtomVec *, const char *); + void bodies(int); + + void mass(); + void paircoeffs(); + void pairIJcoeffs(); + void bondcoeffs(); + void anglecoeffs(int); + void dihedralcoeffs(int); + void impropercoeffs(int); + + void fix(int, char *); +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + +E: Illegal ... command + +Self-explanatory. Check the input script syntax and compare to the +documentation for the command. You can use -echo screen as a +command-line option when running LAMMPS to see the offending line. + +E: Read data add offset is too big + +It cannot be larger than the size of atom IDs, e.g. the maximum 32-bit +integer. + +E: Non-zero read_data shift z value for 2d simulation + +Self-explanatory. + +E: No bonds allowed with this atom style + +Self-explanatory. + +E: No angles allowed with this atom style + +Self-explanatory. + +E: No dihedrals allowed with this atom style + +Self-explanatory. + +E: No impropers allowed with this atom style + +Self-explanatory. + +E: Fix ID for read_data does not exist + +Self-explanatory. + +E: Cannot run 2d simulation with nonperiodic Z dimension + +Use the boundary command to make the z dimension periodic in order to +run a 2d simulation. + +E: Cannot read_data without add keyword after simulation box is defined + +Self-explanatory. + +E: Cannot use read_data add before simulation box is defined + +Self-explanatory. + +E: Cannot use read_data offset without add flag + +Self-explanatory. + +E: Cannot use read_data shift without add flag + +Self-explanatory. + +E: Cannot use read_data extra with add flag + +Self-explanatory. + +W: Atom style in data file differs from currently defined atom style + +Self-explanatory. + +E: Must read Atoms before Velocities + +The Atoms section of a data file must come before a Velocities +section. + +E: Invalid data file section: Bonds + +Atom style does not allow bonds. + +E: Must read Atoms before Bonds + +The Atoms section of a data file must come before a Bonds section. + +E: Invalid data file section: Angles + +Atom style does not allow angles. + +E: Must read Atoms before Angles + +The Atoms section of a data file must come before an Angles section. + +E: Invalid data file section: Dihedrals + +Atom style does not allow dihedrals. + +E: Must read Atoms before Dihedrals + +The Atoms section of a data file must come before a Dihedrals section. + +E: Invalid data file section: Impropers + +Atom style does not allow impropers. + +E: Must read Atoms before Impropers + +The Atoms section of a data file must come before an Impropers +section. + +E: Invalid data file section: Ellipsoids + +Atom style does not allow ellipsoids. + +E: Must read Atoms before Ellipsoids + +The Atoms section of a data file must come before a Ellipsoids +section. + +E: Invalid data file section: Lines + +Atom style does not allow lines. + +E: Must read Atoms before Lines + +The Atoms section of a data file must come before a Lines section. + +E: Invalid data file section: Triangles + +Atom style does not allow triangles. + +E: Must read Atoms before Triangles + +The Atoms section of a data file must come before a Triangles section. + +E: Invalid data file section: Bodies + +Atom style does not allow bodies. + +E: Must read Atoms before Bodies + +The Atoms section of a data file must come before a Bodies section. + +E: Must define pair_style before Pair Coeffs + +Must use a pair_style command before reading a data file that defines +Pair Coeffs. + +W: Pair style in data file differs from currently defined pair style + +Self-explanatory. + +E: Must define pair_style before PairIJ Coeffs + +Must use a pair_style command before reading a data file that defines +PairIJ Coeffs. + +E: Invalid data file section: Bond Coeffs + +Atom style does not allow bonds. + +E: Must define bond_style before Bond Coeffs + +Must use a bond_style command before reading a data file that +defines Bond Coeffs. + +W: Bond style in data file differs from currently defined bond style + +Self-explanatory. + +E: Invalid data file section: Angle Coeffs + +Atom style does not allow angles. + +E: Must define angle_style before Angle Coeffs + +Must use an angle_style command before reading a data file that +defines Angle Coeffs. + +W: Angle style in data file differs from currently defined angle style + +Self-explanatory. + +E: Invalid data file section: Dihedral Coeffs + +Atom style does not allow dihedrals. + +E: Must define dihedral_style before Dihedral Coeffs + +Must use a dihedral_style command before reading a data file that +defines Dihedral Coeffs. + +W: Dihedral style in data file differs from currently defined dihedral style + +Self-explanatory. + +E: Invalid data file section: Improper Coeffs + +Atom style does not allow impropers. + +E: Must define improper_style before Improper Coeffs + +Must use an improper_style command before reading a data file that +defines Improper Coeffs. + +W: Improper style in data file differs from currently defined improper style + +Self-explanatory. + +E: Invalid data file section: BondBond Coeffs + +Atom style does not allow angles. + +E: Must define angle_style before BondBond Coeffs + +Must use an angle_style command before reading a data file that +defines Angle Coeffs. + +E: Invalid data file section: BondAngle Coeffs + +Atom style does not allow angles. + +E: Must define angle_style before BondAngle Coeffs + +Must use an angle_style command before reading a data file that +defines Angle Coeffs. + +E: Invalid data file section: MiddleBondTorsion Coeffs + +Atom style does not allow dihedrals. + +E: Must define dihedral_style before MiddleBondTorsion Coeffs + +Must use a dihedral_style command before reading a data file that +defines MiddleBondTorsion Coeffs. + +E: Invalid data file section: EndBondTorsion Coeffs + +Atom style does not allow dihedrals. + +E: Must define dihedral_style before EndBondTorsion Coeffs + +Must use a dihedral_style command before reading a data file that +defines EndBondTorsion Coeffs. + +E: Invalid data file section: AngleTorsion Coeffs + +Atom style does not allow dihedrals. + +E: Must define dihedral_style before AngleTorsion Coeffs + +Must use a dihedral_style command before reading a data file that +defines AngleTorsion Coeffs. + +E: Invalid data file section: AngleAngleTorsion Coeffs + +Atom style does not allow dihedrals. + +E: Must define dihedral_style before AngleAngleTorsion Coeffs + +Must use a dihedral_style command before reading a data file that +defines AngleAngleTorsion Coeffs. + +E: Invalid data file section: BondBond13 Coeffs + +Atom style does not allow dihedrals. + +E: Must define dihedral_style before BondBond13 Coeffs + +Must use a dihedral_style command before reading a data file that +defines BondBond13 Coeffs. + +E: Invalid data file section: AngleAngle Coeffs + +Atom style does not allow impropers. + +E: Must define improper_style before AngleAngle Coeffs + +Must use an improper_style command before reading a data file that +defines AngleAngle Coeffs. + +E: Unknown identifier in data file: %s + +A section of the data file cannot be read by LAMMPS. + +E: No atoms in data file + +The header of the data file indicated that atoms would be included, +but they are not present. + +E: Needed molecular topology not in data file + +The header of the data file indicated bonds, angles, etc would be +included, but they are not present. + +E: Needed bonus data not in data file + +Some atom styles require bonus data. See the read_data doc page for +details. + +E: Read_data shrink wrap did not assign all atoms correctly + +This is typically because the box-size specified in the data file is +large compared to the actual extent of atoms in a shrink-wrapped +dimension. When LAMMPS shrink-wraps the box atoms will be lost if the +processor they are re-assigned to is too far away. Choose a box +size closer to the actual extent of the atoms. + +E: Unexpected end of data file + +LAMMPS hit the end of the data file while attempting to read a +section. Something is wrong with the format of the data file. + +E: No ellipsoids allowed with this atom style + +Self-explanatory. Check data file. + +E: No lines allowed with this atom style + +Self-explanatory. Check data file. + +E: No triangles allowed with this atom style + +Self-explanatory. Check data file. + +E: No bodies allowed with this atom style + +Self-explanatory. Check data file. + +E: System in data file is too big + +See the setting for bigint in the src/lmptype.h file. + +E: Bonds defined but no bond types + +The data file header lists bonds but no bond types. + +E: Angles defined but no angle types + +The data file header lists angles but no angle types. + +E: Dihedrals defined but no dihedral types + +The data file header lists dihedrals but no dihedral types. + +E: Impropers defined but no improper types + +The data file header lists improper but no improper types. + +E: No molecule topology allowed with atom style template + +The data file cannot specify the number of bonds, angles, etc, +because this info if inferred from the molecule templates. + +E: Did not assign all atoms correctly + +Atoms read in from a data file were not assigned correctly to +processors. This is likely due to some atom coordinates being +outside a non-periodic simulation box. + +E: Subsequent read data induced too many bonds per atom + +See the create_box extra/bond/per/atom or read_data "extra bond per +atom" header value to set this limit larger. + +E: Bonds assigned incorrectly + +Bonds read in from the data file were not assigned correctly to atoms. +This means there is something invalid about the topology definitions. + +E: Subsequent read data induced too many angles per atom + +See the create_box extra/angle/per/atom or read_data "extra angle per +atom" header value to set this limit larger. + +E: Angles assigned incorrectly + +Angles read in from the data file were not assigned correctly to +atoms. This means there is something invalid about the topology +definitions. + +E: Subsequent read data induced too many dihedrals per atom + +See the create_box extra/dihedral/per/atom or read_data "extra +dihedral per atom" header value to set this limit larger. + +E: Dihedrals assigned incorrectly + +Dihedrals read in from the data file were not assigned correctly to +atoms. This means there is something invalid about the topology +definitions. + +E: Subsequent read data induced too many impropers per atom + +See the create_box extra/improper/per/atom or read_data "extra +improper per atom" header value to set this limit larger. + +E: Impropers assigned incorrectly + +Impropers read in from the data file were not assigned correctly to +atoms. This means there is something invalid about the topology +definitions. + +E: Too few values in body lines in data file + +Self-explanatory. + +E: Too many values in body lines in data file + +Self-explanatory. + +E: Too many lines in one body in data file - boost MAXBODY + +MAXBODY is a setting at the top of the src/read_data.cpp file. +Set it larger and re-compile the code. + +E: Unexpected end of PairCoeffs section + +Read a blank line. + +E: Unexpected end of BondCoeffs section + +Read a blank line. + +E: Unexpected end of AngleCoeffs section + +Read a blank line. + +E: Unexpected end of DihedralCoeffs section + +Read a blank line. + +E: Unexpected end of ImproperCoeffs section + +Read a blank line. + +E: Cannot open gzipped file + +LAMMPS was compiled without support for reading and writing gzipped +files through a pipeline to the gzip program with -DLAMMPS_GZIP. + +E: Cannot open file %s + +The specified file cannot be opened. Check that the path and name are +correct. If the file is a compressed file, also check that the gzip +executable can be found and run. + +*/