From 606b33ea03e824ef9061c5d2f7aa87d0df793c8e Mon Sep 17 00:00:00 2001 From: tc387 Date: Fri, 5 Feb 2021 16:05:37 -0600 Subject: [PATCH] Added fix_charge_regulation source code and documentation. --- doc/src/fix_charge_regulation.rst | 184 +++ examples/USER/misc/charge_regulation/README | 7 + .../misc/charge_regulation/data_acid.chreg | 235 +++ .../misc/charge_regulation/data_polymer.chreg | 264 ++++ .../USER/misc/charge_regulation/in_acid.chreg | 40 + .../misc/charge_regulation/in_polymer.chreg | 35 + .../misc/charge_regulation/log_acid.lammps | 163 ++ .../misc/charge_regulation/log_polymer.lammps | 181 +++ src/USER-MISC/README | 1 + src/USER-MISC/fix_charge_regulation.cpp | 1335 +++++++++++++++++ src/USER-MISC/fix_charge_regulation.h | 117 ++ 11 files changed, 2562 insertions(+) create mode 100644 doc/src/fix_charge_regulation.rst create mode 100644 examples/USER/misc/charge_regulation/README create mode 100644 examples/USER/misc/charge_regulation/data_acid.chreg create mode 100644 examples/USER/misc/charge_regulation/data_polymer.chreg create mode 100644 examples/USER/misc/charge_regulation/in_acid.chreg create mode 100644 examples/USER/misc/charge_regulation/in_polymer.chreg create mode 100644 examples/USER/misc/charge_regulation/log_acid.lammps create mode 100644 examples/USER/misc/charge_regulation/log_polymer.lammps create mode 100644 src/USER-MISC/fix_charge_regulation.cpp create mode 100644 src/USER-MISC/fix_charge_regulation.h diff --git a/doc/src/fix_charge_regulation.rst b/doc/src/fix_charge_regulation.rst new file mode 100644 index 0000000000..585761e8a9 --- /dev/null +++ b/doc/src/fix_charge_regulation.rst @@ -0,0 +1,184 @@ + +.. Yuan documentation master file, created by + sphinx-quickstart on Sat Jan 30 14:06:22 2021. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + tc387: Multiple text additions/changes, Feb 2 2021 +.. index:: fix fix_charge_regulation + +fix_charge_regulation command +============================= +Syntax +"""""" + +.. parsed-literal:: + + fix ID group-ID charge_regulation cation_type anion_type keyword value(s) + +* ID, group-ID are documented in fix command +* charge_regulation = style name of this fix command +* cation_type = atom type of free cations +* anion_type = atom type of free anions + +* zero or more keyword/value pairs may be appended + + .. parsed-literal:: + + keyword = *pH*, *pKa*, *pKb*, *pIp*, *pIm*, *pKs*, *acid_type*, *base_type*, *lunit_nm*, *temp*, *tempfixid*, *nevery*, *nmc*, *xrd*, *seed*, *tag*, *group*, *onlysalt*, *pmcmoves* + *pH* value = pH of the solution + *pKa* value = acid dissociation constant + *pKb* value = base dissociation constant + *pIp* value = chemical potential of free cations + *pIm* value = chemical potential of free anions + *pKs* value = solution self-dissociation constant + *acid_type* = atom type of acid groups + *base_type* = atom type of base groups + *lunit_nm* value = unit length used by LAMMPS (# in the units of nanometers) + *temp* value = temperature + *tempfixid* value = fix ID of temperature thermostat + *nevery* value = invoke this fix every nevery steps + *nmc* value = number of charge regulation MC moves to attempt every nevery steps + *xrd* value = cutoff distance for acid/base reaction + *seed* value = random # seed (positive integer) + *tag* value = yes or no (yes: The code assign unique tags to inserted ions; no: The tag of all inserted ions is "0") + *group* value = group-ID, inserted ions are assigned to group group-ID. Can be used multiple times to assign inserted ions to multiple groups. + *onlysalt* values = flag charge_cation charge_anion. + flag = yes or no (yes: the fix performs only ion insertion/deletion, no: perform acid/base dissociation and ion insertion/deletion) + charge_cation, charge_anion = value of cation/anion charge, must be an integer (only specify if flag = yes) + *pmcmoves* values = pmcA pmcB pmcI - MC move fractions for acid ionization (pmcA), base ionization (pmcB) and free ion exchange (pmcI) + +Examples +"""""""" +.. code-block:: LAMMPS + + fix chareg all charge_regulation 1 2 acid_type 3 base_type 4 pKa 5 pKb 7 lb 1.0 nevery 200 nexchange 200 seed 123 tempfixid fT + + fix chareg all charge_regulation 1 2 pIp 3 pIm 3 tempfixid fT tag yes onlysalt yes 2 -1 + +Description +""""""""""" +This fix performs Monte Carlo (MC) sampling of charge regulation and exchange of ions with a reservoir as discussed in :ref:`(Curk1) ` and :ref:`(Curk2) `. +The implemented method is largely analogous to the grand-reaction ensemble method in :ref:`(Landsgesell) `. +The implementation is parallelized, compatible with existing LAMMPS functionalities, and applicable to any system utilizing discreet, ionizable groups or surface sites. + + +Specifically, the fix implements the following three types of MC moves, which discretely change the charge state of individual particles and insert ions into the systems: :math:`\mathrm{A} \rightleftharpoons \mathrm{A}^-+\mathrm{X}^+`, :math:`\mathrm{B} \rightleftharpoons \mathrm{B}^++\mathrm{X}^-`, +and :math:`\emptyset \rightleftharpoons Z^-\mathrm{X}^{Z^+}+Z^+\mathrm{X}^{-Z^-}`. +In the former two types of reactions, Monte Carlo moves alter the charge value of specific atoms (:math:`\mathrm{A}`, :math:`\mathrm{B}`) and simultaneously insert a counterion to preserve the charge neutrality of the system, modeling the dissociation/association process. +The last type of reaction performs grand canonical MC exchange of ion pairs with a (fictitious) reservoir. + +In our implementation "acid" refers to particles that can attain charge :math:`q=\{0,-1\}` and "base" to particles with :math:`q=\{0,1\}`, +whereas the MC exchange of free ions allows any integer charge values of :math:`{Z^+}` and :math:`{Z^-}`. + +Here we provide several practical examples for modeling charge regulation effects in solvated systems. +An acid ionization reaction (:math:`\mathrm{A} \rightleftharpoons \mathrm{A}^-+\mathrm{H}^+`) can be defined via a single line in the input file + +.. code-block:: LAMMPS + + fix acid_reaction all charge_regulation 2 3 acid_type 1 pH 7.0 pKa 5.0 pIp 7.0 pIm 7.0 + +where the fix attempts to charge :math:`\mathrm{A}` (discharge :math:`\mathrm{A}^-`) to :math:`\mathrm{A}^-` (:math:`\mathrm{A}`) and insert (delete) a proton (atom type 2). Besides, the fix implements self-ionization reaction of water :math:`\emptyset \rightleftharpoons \mathrm{H}^++\mathrm{OH}^-`. +However, this approach is highly inefficient at :math:`\mathrm{pH} \approx 7` when the concentration of both protons and hydroxyl ions is low, resulting in a relatively low acceptance rate of MC moves. + +A more efficient way is to allow salt ions to +participate in ionization reactions, which can be easily achieved via + +.. code-block:: LAMMPS + + fix acid_reaction all charge_regulation 4 5 acid_type 1 pH 7.0 pKa 5.0 pIp 2.0 pIm 2.0 + +where particles of atom type 4 and 5 are the salt cations and anions, both at chemical potential pI=2.0, see :ref:`(Curk1) ` and :ref:`(Landsgesell) ` for more details. + + + Similarly, we could have simultanously added a base ionization reaction (:math:`\mathrm{B} \rightleftharpoons \mathrm{B}^++\mathrm{OH}^-`) + +.. code-block:: LAMMPS + + fix base_reaction all charge_regulation 2 3 base_type 6 pH 7.0 pKb 6.0 pIp 7.0 pIm 7.0 + +where the fix will attempt to charge :math:`\mathrm{B}` (discharge :math:`\mathrm{B}^+`) to :math:`\mathrm{B}^+` (:math:`\mathrm{B}`) and insert (delete) a hydroxyl ion :math:`\mathrm{OH}^-` of atom type 3. +If neither the acid or the base type is specified, for example, + +.. code-block:: LAMMPS + + fix salt_reaction all charge_regulation 4 5 pIp 2.0 pIm 2.0 + +the fix simply inserts or deletes an ion pair of a free cation (atom type 4) and a free anion (atom type 5) as done in a conventional grand-canonical MC simulation. + + +The fix is compatible with LAMMPS sub-packages such as *molecule* or *rigid*. That said, the acid and base particles can be part of larger molecules or rigid bodies. Free ions that are inserted to or deleted from the system must be defined as single particles (no bonded interactions allowed) and cannot be part of larger molecules or rigid bodies. If *molecule* package is used, all inserted ions have a molecule ID equal to zero. + +Note that LAMMPS implicitly assumes a constant number of particles (degrees of freedom). Since using this fix alters the total number of particles during the simulation, any thermostat used by LAMMPS, such as NVT or Langevin, must use a dynamic calculation of system temperature. This can be achieved by specifying a dynamic temperature compute (e.g. dtemp) and using it with the desired thermostat, e.g. a Langevin thermostat: + +.. code-block:: LAMMPS + + compute dtemp all temp + compute_modify dtemp dynamic yes + fix fT all langevin 1.0 1.0 1.0 123 + fix_modify fT temp dtemp + +The chemical potential units (e.g. pH) are in the standard log10 representation assuming reference concentration :math:`\rho_0 = \mathrm{mol}/\mathrm{l}`. +Therefore, to perform the internal unit conversion, the length (in nanometers) of the LAMMPS unit length +must be specified via *lunit_nm* (default is set to the Bjerrum length in water at room temprature *lunit_nm* = 0.72nm). For example, in the dilute ideal solution limit, the concentration of free ions +will be :math:`c_\mathrm{I} = 10^{-\mathrm{pIp}}\mathrm{mol}/\mathrm{l}`. + +The temperature used in MC acceptance probability is set by *temp*. This temperature should be the same as the temperature set by the molecular dynamics thermostat. For most purposes, it is probably best to use *tempfixid* keyword which dynamically sets the temperature equal to the chosen MD thermostat temperature, in the example above we assumed the thermostat fix-ID is *fT*. The inserted particles attain a random velocity corresponding to the specified temperature. Using *tempfixid* overrides any fixed temperature set by *temp*. + +The *xrd* keyword can be used to restrict the inserted/deleted counterions to a specific radial distance from an acid or base particle that is currently participating in a reaction. This can be used to simulate more realist reaction dynamics. If *xrd* = 0 or *xrd* > *L* / 2, where *L* is the smallest box dimension, the radial restriction is automatically turned off and free ion can be inserted or deleted anywhere in the simulation box. + +If the *tag yes* is used, every inserted atom gets a unique tag ID, otherwise, the tag of every inserted atom is set to 0. *tag yes* might cause an integer overflow in very long simulations since the tags are unique to every particle and thus increase with every successful particle insertion. + +The *pmcmoves* keyword sets the relative probability of attempting the three types of MC moves (reactions): acid charging, base charging, and ion pair exchange. +The fix only attempts to perform particle charging MC moves if *acid_type* or *base_type* is defined. Otherwise fix only performs free ion insertion/deletion. For example, if *acid_type* is not defined, *pmcA* is automatically set to 0. The vector *pmcmoves* is automatically normalized, for example, if set to *pmcmoves* 0 0.33 0.33, the vector would be normalized to [0,0.5,0.5]. + +The *only_salt* option can be used to perform multivalent grand-canonical ion-exchange moves. If *only_salt yes* is used, no charge exchange is performed, only ion insertion/deletion (*pmcmoves* is set to [0,0,1]), but ions can be multivalent. In the example above, an MC move would consist of three ion insertion/deletion to preserve the charge neutrality of the system. + +The *group* keyword can be used to add inserted particles to a specific group-ID. All inserted particles are automatically added to group *all*. + + +Output +"""""" +This fix computes a global vector of length 8, which can be accessed by various output commands. The vector values are the following global cumulative quantities: + +* 1 = cumulative MC attempts +* 2 = cumulative MC successes +* 3 = current # of neutral acid atoms +* 4 = current # of -1 charged acid atoms +* 5 = current # of neutral base atoms +* 6 = current # of +1 charged acid atoms +* 7 = current # of free cations +* 8 = current # of free anions + + +Restrictions +"""""""""""" +This fix is part of the USER-MISC package. It is only enabled if LAMMPS was built with that package. +See the :doc:`Build package ` doc page for more info. + +The :doc:`atom_style `, used must contain the charge property, for example, the style could be *charge* or *full*. Only usable for 3D simulations. Atoms specified as free ions cannot be part of rigid bodies or molecules and cannot have bonding interactions. The scheme is limited to integer charges, any atoms with non-integer charges will not be considered by the fix. + +Note: Region restrictions are not yet implemented. + +Related commands +"""""""""""""""" + +:doc:`fix gcmc `, +:doc:`fix atom/swap ` + +Default +""""""" +pH = 7.0; pKa = 100.0; pKb = 100.0; pIp = 5.0; pIm = 5.0; pKs=14.0; acid_type = -1; base_type = -1; lunit_nm = 0.72; temp = 1.0; nevery = 100; nmc = 100; xrd = 0; seed = 2345; tag = no; onlysalt = no, pmcmoves = 0.33 0.33 0.33, group-ID = all + +---------- + +.. _Curk1: + +**(Curk1)** T. Curk, J. Yuan, and E. Luijten, "Coarse-grained simulation of charge regulation using LAMMPS", preprint (2021). + +.. _Curk2: + +**(Curk2)** T. Curk and E. Luijten, "Charge-regulation effects in nanoparticle self-assembly", PRL (2021) + +.. _Landsgesell: + +**(Landsgesell)** J. Landsgesell, P. Hebbeker, O. Rud, R. Lunkad, P. Kosovan, and C. Holm, “Grand-reaction method for simulations of ionization equilibria coupled to ion partitioning,” Macromolecules 53, 3007–3020 (2020). diff --git a/examples/USER/misc/charge_regulation/README b/examples/USER/misc/charge_regulation/README new file mode 100644 index 0000000000..e0be86d7e4 --- /dev/null +++ b/examples/USER/misc/charge_regulation/README @@ -0,0 +1,7 @@ +This directory has two input scripts that illustrates how to use fix charge_regulation in LAMMPS to perform coarse-grained molecular dynamics (MD) simulations with incorporation of charge regulation effects. The charge regulation is implemented via Monte Carlo (MC) sampling following the reaction ensemble MC approach, producing a MC/MD hybrid tool for modeling charge regulation in solvated systems. + +The script `in_acid.chreg` sets up a simple weak acid electrolyte (pH=7,pKa=6,pI=3). Four different types of MC moves are implemented: acid protonation & de-protonation, and monovalent ion pair insertion and deletion. Note here we have grouped all free monovalent ions into a single type, a physically natural choice on the level of coarse-grained primitive electrolyte models, which increases the calculation performance but has no effects on thermodynamic observables. The variables such as pH, pKa, pI, and lb at the top of the input script can be adjusted to play with various simulation parameters. The cumulative MC attempted moves and cumulative number of accepted moves, as well as, current number of neutral and charged acid particles, neutral and charged base particles (in this example always 0), and the current number of free cations and anions in the system are printed in the `log_acid.lammps`. + +The script `in_polymer.chreg` sets up a weak polyelectrolyte chain of N=80 beads. Each bead is a weak acid with pKa=5 and solution has pH=7 and salt pI=3. In this example, we choose to treat salt ions, protons, and hydroxyl ions separately, which results in 5 types of MC moves: acid [type 1] protonation & de-protonation (with protons [type 4] insertion & deletion), acid [type 1] protonation & de-protonation (with salt cation [type 2] insertion & deletion), water self-ionization (insertion and deletion of proton [type4] and hydroxyl ion [type 5] pair), insertion and deletion of monovalent salt pair [type 2 and type 3] , insertion and deletion +Of a proton [type4] and salt anion [type 3]. The current number of neutral and charged acid particles, the current number of free salt cations and anions, and the current number of protons and hydroxyl ions are printed in the `log_polymer.lammps`. + diff --git a/examples/USER/misc/charge_regulation/data_acid.chreg b/examples/USER/misc/charge_regulation/data_acid.chreg new file mode 100644 index 0000000000..edc7082ad0 --- /dev/null +++ b/examples/USER/misc/charge_regulation/data_acid.chreg @@ -0,0 +1,235 @@ +LAMMPS data file generated by get_input.py + +219 atoms +3 atom types +-2.5000000000000000e+01 2.5000000000000000e+01 xlo xhi +-2.5000000000000000e+01 2.5000000000000000e+01 ylo yhi +-2.5000000000000000e+01 2.5000000000000000e+01 zlo zhi + +Masses + +1 1 +2 1 +3 1 + +Atoms + +1 1 0 2.5983275747497636 -8.368052973860795 20.001288664343484 +2 1 -1 -18.182868728594865 -8.079792367885453 8.253737231981816 +3 1 -1 -17.437350808966414 8.120411567445771 10.747650340639332 +4 1 -1 6.502476583291578 -23.497326620756837 19.948223080086798 +5 1 -1 -22.528179279677296 -18.783433570718127 -17.964657736688018 +6 1 -1 -9.713496019164342 18.97235576760402 -19.495620818582825 +7 1 -1 -12.831976006720659 0.12265736526942561 -21.679396938423718 +8 1 -1 20.909063679212295 -2.16535062758771 0.46197866620165584 +9 1 -1 23.86211981166997 24.024928465132284 10.534067202515907 +10 1 -1 -0.5289298325031275 23.820222457999776 -2.657199543669442 +11 1 -1 9.57021229491361 11.973871502198485 3.4206509716759186 +12 1 -1 -10.201559985782705 7.557482594092384 12.07004973873643 +13 1 -1 4.898458045226889 2.0169997859717945 -20.765285372762087 +14 1 -1 -24.086606883730077 4.424991619615298 -4.204294764756856 +15 1 -1 3.6837161829600795 -4.763233144818308 -12.75873457519811 +16 1 -1 -12.217842496816345 -17.720229208905618 -13.556354139556914 +17 1 -1 -21.456229140133704 -7.423996317612119 -6.94398044071275 +18 1 -1 13.697298849253912 8.503639732052164 8.085487457359058 +19 1 -1 -5.764222710061347 11.49890485049034 -5.1113880296575935 +20 1 -1 3.9944161041544426 16.928204188257893 -14.875635895409372 +21 1 -1 4.509525276444776 16.63590711792657 -22.21846494992397 +22 1 -1 22.115374932704306 -18.97293932558108 -23.982486000144267 +23 1 -1 14.169061011408473 -16.69837647199978 13.779039228068108 +24 1 -1 17.186846147657228 8.827459489898189 23.055435051390333 +25 1 -1 2.9822901981431045 -16.83687718528342 -21.278623587083484 +26 1 -1 16.657554689423897 -1.6217275605348647 -11.315859420404218 +27 1 -1 19.215533149393543 -15.512634977936068 7.2701088767584565 +28 1 -1 -8.886744157248422 -24.09644410100167 4.013016013803799 +29 1 -1 20.99918340066754 4.4716257356730225 0.3847245765737597 +30 1 -1 1.3442294253060716 5.601341425720583 -14.918594492786674 +31 1 -1 -6.962977050326831 20.470183675946515 -16.37885865567279 +32 1 -1 -9.98531733187143 9.52233798117566 -24.979630708193724 +33 1 -1 -17.327989778292306 5.761352103841766 5.720220488689204 +34 1 -1 5.168359673466362 -23.698812306679418 2.6199762372169744 +35 1 -1 18.978042448492154 6.41188742965139 6.31975357155018 +36 1 -1 -16.38534911663758 -14.8262205163943 4.125239045887575 +37 1 -1 7.974455406459249 -18.88332583451115 11.00721254217055 +38 1 -1 13.779816416416402 1.8581999350851426 9.104219696003227 +39 1 -1 -23.90949397031401 -3.346877828308571 -10.228782973473443 +40 1 -1 21.61647622174447 8.443955423089903 -19.12066464239769 +41 1 -1 -8.823979405515548 14.461154001848172 16.061704411241706 +42 1 -1 -2.4406878944912513 12.5535360118296 20.606764200087852 +43 1 -1 -18.459404356124697 15.260951448001258 21.187332685021346 +44 1 -1 2.2354003384439878 -23.350013178190736 11.369307324043625 +45 1 -1 15.595889705552018 -6.6075680254604805 5.434256329408505 +46 1 -1 -17.528243443870238 4.109747707896265 -1.4167331089310942 +47 1 -1 2.161977144405782 -16.511059804921263 -12.186191310598671 +48 1 -1 -8.685671837367341 -7.0743613044263185 -1.1561844713769105 +49 1 -1 15.62258718398045 -6.559293763708908 20.556775995508488 +50 1 -1 -6.965207014475155 -14.348784897390543 -14.421447863144754 +51 1 -1 -12.099361509567913 -24.62785640990423 -15.839126670614329 +52 1 -1 6.673854222058246 7.83575773885061 -9.714128155619994 +53 1 -1 -17.413453800948826 12.386754276446203 -16.882300786608994 +54 1 -1 21.8966589175091 12.485943283688762 -14.553421680298634 +55 1 -1 -8.37629917390651 -24.783875012947064 7.454467809536389 +56 1 -1 14.081149297694104 -21.719204113108943 -17.447225564400064 +57 1 -1 4.681992702049627 1.9719544892622558 -7.823736613205725 +58 1 -1 4.353171917533494 15.86928389762705 24.669680272563014 +59 1 -1 23.31502072066573 -4.685724298328946 2.459643890128799 +60 1 -1 7.0470920520598455 23.016693234922386 -13.139471333592677 +61 1 -1 11.725555941181668 -15.809323171320772 -1.6292879532275037 +62 1 -1 -20.36388898925061 -12.084932320023162 -22.816700826388757 +63 1 -1 -2.492146614764735 -0.7314052253623018 -15.89959178250266 +64 1 -1 -22.45303825831233 -11.27996814407809 -9.553770912146142 +65 1 -1 24.76771926037101 20.128947543233757 10.528974830883733 +66 1 -1 11.326213670190818 -11.624187194192492 -9.687726413467862 +67 1 -1 -5.712764220166093 15.778887306376163 -0.9263244618113831 +68 1 -1 -15.073201136996362 -12.372916148178115 -5.461704510273556 +69 1 -1 -5.82976670348781 -4.57812040989473 9.0443548565365 +70 1 -1 -5.429195387856279 1.4542054472230177 -7.397291151203568 +71 1 -1 -23.385555726942343 -11.924588975396505 3.8215294321466153 +72 1 -1 -1.0694104826815725 2.999945633116507 3.67092922106918 +73 1 -1 12.134312161994352 1.9747455475585376 -14.895893366599623 +74 1 -1 21.30950120583112 18.97294626436546 -17.520867878211376 +75 1 -1 -24.356703356157063 3.594879254976714 17.172993705171677 +76 1 -1 12.634233603338409 24.373499564220822 4.561976273909789 +77 1 -1 -10.740243207970495 19.345205140729554 -3.3368424800818097 +78 1 -1 -3.027848793907552 10.604939843027267 7.493012332728249 +79 1 -1 5.000539296336658 11.770088203844622 17.227492055930185 +80 1 -1 1.1585200269400353 -24.45822157176123 -12.515688997756257 +81 1 -1 1.9163088584430596 -14.064330279670672 11.302445490552905 +82 1 -1 -20.857041355570576 21.292791787236673 17.397470691573346 +83 1 -1 -24.50473305235651 -12.741459355708756 -1.9325218065560357 +84 1 -1 2.658628688373309 -1.1131226252194608 7.491603553398086 +85 1 -1 -18.515435126408363 24.20642384141299 14.466889392835121 +86 1 -1 19.63928177206153 9.942655640416291 8.691463646789934 +87 1 -1 -7.69626451160762 11.762517043363786 -7.457263991495665 +88 1 -1 1.051431093064835 -11.460307039827766 16.90304637479744 +89 1 -1 0.9157815447227939 23.656751182559688 -6.538587603918376 +90 1 -1 23.330169435555234 -7.293893221439802 -10.739388379883973 +91 1 -1 1.3454906653067376 0.3584300740797559 8.837879234629618 +92 1 -1 -21.93056639286312 -10.890279576013356 -10.412914392053596 +93 1 -1 21.9136101677979 -10.780221720642636 11.543925933359859 +94 1 -1 1.213289938136601 -7.171863230861625 20.734527885288102 +95 1 -1 23.102370131877777 21.949933206350458 0.29281565885028016 +96 1 -1 -18.917780884063298 -0.03244735062602544 23.633906995676227 +97 1 -1 7.583004866601307 10.74178675512821 -4.857297835527785 +98 1 -1 -7.4910066746799835 -14.168364618485734 -6.426540836249767 +99 1 -1 -20.672200987670426 -8.746789722660697 11.011389790610103 +100 1 -1 -18.662115132221917 -21.356740361991612 -8.735991534410413 +101 2 1 11.900973676882046 6.591531431964558 19.018193594877637 +102 2 1 -23.433591822114983 -18.956429005519567 4.8373984358422994 +103 2 1 -11.825475204099472 -3.8206287568445134 3.1167558949026173 +104 2 1 -17.49780467176259 -23.115560141825554 9.614132296727426 +105 2 1 10.88916113281772 4.512200980010334 18.685489050240854 +106 2 1 -22.04662313800728 23.973268925992897 -23.417792740205652 +107 2 1 -13.57041123540546 17.3687874050987 21.186270978357783 +108 2 1 6.586851196789095 16.27860887432974 -3.638909639278946 +109 2 1 8.191448685630277 6.828880619305412 -6.347576950950089 +110 2 1 -15.723292856220288 -20.484673256634117 -15.14713811293425 +111 2 1 18.58081219522701 19.060706710849452 -10.295676869062909 +112 2 1 -21.09194001526127 -7.739334786748358 5.417635948058724 +113 2 1 -14.10404878784055 -15.769737592448523 -18.881834262561505 +114 2 1 -14.644589058195612 8.84169065013063 8.611654925486256 +115 2 1 -11.719050253933538 -4.9700119000832 -0.9846728956163453 +116 2 1 19.498247505274143 -10.418045613133986 -22.12098182226518 +117 2 1 21.857683401772697 20.157098661061575 -13.652393197742995 +118 2 1 -17.623414455798407 21.873813778550875 -6.533965802006303 +119 2 1 7.231785003326529 -13.925962842972222 5.360080190636602 +120 2 1 -7.509430039873415 19.13541714591672 -16.23545960168472 +121 2 1 -4.048249209544995 13.126195473202351 -7.156541250053138 +122 2 1 -20.26837137264583 21.46366988603839 15.603080527043964 +123 2 1 -4.478253524569759 -3.1812369811955783 -18.52918159641348 +124 2 1 21.541019047040052 13.514999235394065 -1.8086547561089752 +125 2 1 -15.223319907923727 -5.958117989814905 -7.194967640819577 +126 2 1 -20.87181173003304 -7.66780336209651 20.518235718821714 +127 2 1 -3.7444846073700297 21.014628245718292 7.197818215477007 +128 2 1 -5.904222844268787 7.656315546673127 -1.3911802017487425 +129 2 1 -21.49072414090769 -23.123923448235523 10.49453669763092 +130 2 1 24.90628307456096 7.081046671281136 -14.422530828641655 +131 2 1 -12.173002002514222 -23.250366655717176 -5.145802772598103 +132 2 1 -19.68809858318764 4.476541650697328 6.249229323733747 +133 2 1 16.85550827580734 -0.8462194407221624 18.011901711631936 +134 2 1 17.289399533444858 -11.99379336569853 11.875868193611936 +135 2 1 19.532020913911126 -23.053375288330326 -4.9162076250112605 +136 2 1 -12.432304028989998 5.029488375070969 7.535325299264009 +137 2 1 14.934807008644 8.086694342170496 19.68691014849572 +138 2 1 -7.088283921093918 -23.094109864922018 16.57088328184242 +139 2 1 14.77413976080318 21.343550134324772 13.996489344579572 +140 2 1 -14.606423208703657 -6.928316926567433 -22.717483260149475 +141 2 1 -17.139771555632173 14.533410346451518 -21.83064865887975 +142 2 1 4.261830086466784 15.518968841247663 -17.791505649414617 +143 2 1 -9.814793042774223 -5.120956154726329 14.054454130549104 +144 2 1 8.313311590434793 3.9666876022475606 -20.677101093823236 +145 2 1 10.603190079756637 -2.62347089527481 1.6661989541795634 +146 2 1 -17.763718339721695 1.2541370478041287 -21.55649971308305 +147 2 1 -8.538066365356812 14.81814356892842 -4.478673557614034 +148 2 1 -5.809558827384787 14.611789154829552 13.287687188309562 +149 2 1 8.986830839040898 -17.43898584267833 -18.08640526127862 +150 2 1 -13.315275244526854 8.890431200255954 -8.708179477452443 +151 2 1 -0.5407152591412618 -23.67970550599055 -24.1586910560046 +152 2 1 -19.79961109336906 -16.10906604558887 -5.879899717095562 +153 2 1 -23.626316306846658 9.337407355717588 -9.640842288307239 +154 2 1 -18.847256196659333 -16.303517291166603 -10.786416046984721 +155 2 1 13.567770091716845 -24.4927974402177 8.896906985984664 +156 2 1 13.652894892068794 -24.87567116574863 21.89026113439551 +157 2 1 -8.575912713332162 9.92386172372207 5.029537530028822 +158 2 1 20.69339436974964 1.129252448454178 0.3584458063532807 +159 2 1 -0.9971941518705947 18.317397852358788 6.795424830570379 +160 2 1 23.155704681402298 15.458725773368961 17.01599672991628 +161 2 1 22.278634187244123 14.642946508468171 20.543957651530896 +162 2 1 9.771629496835963 -21.696904301438853 -5.259678202922196 +163 2 1 5.253009955872763 17.911287158418148 15.769047957152992 +164 2 1 -20.759038961257414 5.59089552770853 -12.383953925685166 +165 2 1 3.2163819108147145 -4.948608591009169 -17.85036103684716 +166 2 1 20.637631925250837 9.109955226257064 6.177181979863878 +167 2 1 5.306344093540837 12.647347581939556 23.229957406774105 +168 2 1 -24.15187998806597 17.263903348029615 -17.141028077545826 +169 2 1 -15.705280442832997 -15.655358704303895 -10.488762557871972 +170 2 1 -6.601131108664461 -22.50322976595015 -5.672942609306119 +171 2 1 22.869179482568555 13.369592422303498 -9.378437532422556 +172 2 1 -23.151055417980903 -3.928919101213168 -11.117061489640207 +173 2 1 1.3592343286386246 -18.552063924235036 -15.346172149331993 +174 2 1 10.23567488314778 -18.14207926130103 -1.6884247085891886 +175 2 1 12.595888032974493 -1.7416169207452157 -21.786811832485718 +176 2 1 -0.14792438162408672 17.11748549051584 1.2788726677139053 +177 2 1 24.349235298880274 -8.664350854740949 12.4309854455257 +178 2 1 -18.827147816604253 -18.80258748867273 -1.6980553939283212 +179 2 1 -9.048793002383698 -1.788614428205263 -11.841289777017172 +180 2 1 -22.49667217853208 -22.112076711777533 10.01393503943838 +181 2 1 -16.183333848138453 1.3098533508906556 0.8096413611556166 +182 2 1 -4.007575369376703 -24.447854073342157 -19.683971619997376 +183 2 1 8.79123015290173 -15.890906503248287 -23.45721570121758 +184 2 1 -8.557898021171628 -21.985380426316674 22.626382729361595 +185 2 1 7.143974673263372 16.57516065778192 0.5907315164854055 +186 2 1 7.05280226857041 6.658154377550723 17.993436860997946 +187 2 1 20.98391844656716 -3.7711929542825544 -22.37222924252256 +188 2 1 -8.856382807041598 -16.421301042649826 -7.682473719905396 +189 2 1 -14.381919492441797 -7.667674808763277 -10.178028203828621 +190 2 1 -22.93472549116592 10.072854607637751 3.756868463885592 +191 2 1 9.458987867260412 17.23200182595278 -0.03503381482496337 +192 2 1 11.013603635791974 19.842184408029837 -5.83598462187852 +193 2 1 23.28897987479008 2.835578651649044 -20.512845011389647 +194 2 1 -18.86161127148128 8.956542530565656 14.193388541103026 +195 2 1 13.688477473034126 -15.973205475346514 10.952445409682397 +196 2 1 2.1058159557459497 2.740725960214597 -23.72037436968614 +197 2 1 20.982351847235442 7.072739454450108 -24.07322254392252 +198 2 1 5.962360707177609 -19.424513569281604 22.469955103109243 +199 2 1 -17.13607356062674 20.038457022813326 12.94227215395123 +200 2 1 11.592617137491743 22.283887092702138 2.339699650677858 +201 2 1 -1.3864952037065237 19.199632510575505 -7.684210221911414 +202 2 1 -22.44476570586083 -19.66385674506424 -8.981660607669522 +203 2 1 0.36547911522815824 -7.628556098996082 16.326944822668068 +204 2 1 -9.766164330974753 24.38435844399602 -14.352553497163 +205 2 1 -0.6310792726759544 -5.625399375968325 13.665993163571486 +206 2 1 2.6795300975636103 -0.37097710463575595 15.575183407667495 +207 2 1 10.68508361399715 24.638181487800373 -17.538711281692827 +208 2 1 18.30809729940504 18.39121662193474 18.285926328751984 +209 2 1 -11.52561870836783 -11.871004571782223 12.890674390475048 +210 3 -1 16.038097437687007 -0.8308290507120688 9.140710202344948 +211 3 -1 -12.071581865552927 23.77532123232212 -6.250109721970887 +212 3 -1 24.179073767023887 19.6390206210449 22.20321951706368 +213 3 -1 22.899159789805424 8.918385700451317 -1.1269016129923664 +214 3 -1 -10.48576153865241 5.691510884812594 21.955276995406933 +215 3 -1 6.272776670877239 10.035821052072265 22.22030412319301 +216 3 -1 14.689947575936934 -7.785907120217196 0.5033983092114553 +217 3 -1 23.173937996535116 -21.041572031861037 -21.057283440516468 +218 3 -1 -6.015120142466472 6.3962924962024985 21.58241945230285 +219 3 -1 -0.77667042466472 0.3962848125024985 1.582473830285 \ No newline at end of file diff --git a/examples/USER/misc/charge_regulation/data_polymer.chreg b/examples/USER/misc/charge_regulation/data_polymer.chreg new file mode 100644 index 0000000000..2c5bd3e1ed --- /dev/null +++ b/examples/USER/misc/charge_regulation/data_polymer.chreg @@ -0,0 +1,264 @@ +##A Weak PE Chain of N=80 + +160 atoms +79 bonds + +5 atom types +1 bond types + +-50 50 xlo xhi +-50 50 ylo yhi +-50 50 zlo zhi + +Masses + +1 1.0 +2 1.0 +3 1.0 +4 1.0 +5 1.0 + +Atoms +# atom_id molecule_id atom_type charge x y z +1 1 1 -1 0 0 -48.37753795169063 +2 1 1 -1 0 0 -47.255075903381254 +3 1 1 -1 0 0 -46.13261385507188 +4 1 1 -1 0 0 -45.01015180676251 +5 1 1 -1 0 0 -43.887689758453135 +6 1 1 -1 0 0 -42.76522771014376 +7 1 1 -1 0 0 -41.64276566183439 +8 1 1 -1 0 0 -40.520303613525016 +9 1 1 -1 0 0 -39.39784156521564 +10 1 1 -1 0 0 -38.27537951690627 +11 1 1 -1 0 0 -37.1529174685969 +12 1 1 -1 0 0 -36.030455420287524 +13 1 1 -1 0 0 -34.90799337197815 +14 1 1 -1 0 0 -33.78553132366878 +15 1 1 -1 0 0 -32.663069275359405 +16 1 1 -1 0 0 -31.54060722705003 +17 1 1 -1 0 0 -30.41814517874066 +18 1 1 -1 0 0 -29.295683130431286 +19 1 1 -1 0 0 -28.173221082121913 +20 1 1 -1 0 0 -27.05075903381254 +21 1 1 -1 0 0 -25.928296985503167 +22 1 1 -1 0 0 -24.805834937193794 +23 1 1 -1 0 0 -23.68337288888442 +24 1 1 -1 0 0 -22.560910840575048 +25 1 1 -1 0 0 -21.438448792265675 +26 1 1 -1 0 0 -20.3159867439563 +27 1 1 -1 0 0 -19.19352469564693 +28 1 1 -1 0 0 -18.071062647337556 +29 1 1 -1 0 0 -16.948600599028183 +30 1 1 -1 0 0 -15.82613855071881 +31 1 1 -1 0 0 -14.703676502409436 +32 1 1 -1 0 0 -13.581214454100063 +33 1 1 -1 0 0 -12.45875240579069 +34 1 1 -1 0 0 -11.336290357481317 +35 1 1 -1 0 0 -10.213828309171944 +36 1 1 -1 0 0 -9.091366260862571 +37 1 1 -1 0 0 -7.968904212553198 +38 1 1 -1 0 0 -6.846442164243825 +39 1 1 -1 0 0 -5.723980115934452 +40 1 1 -1 0 0 -4.601518067625079 +41 1 1 -1 0 0 -3.4790560193157063 +42 1 1 -1 0 0 -2.3565939710063333 +43 1 1 -1 0 0 -1.2341319226969603 +44 1 1 -1 0 0 -0.11166987438758724 +45 1 1 -1 0 0 1.0107921739217858 +46 1 1 -1 0 0 2.133254222231159 +47 1 1 -1 0 0 3.255716270540532 +48 1 1 -1 0 0 4.378178318849905 +49 1 1 -1 0 0 5.500640367159278 +50 1 1 -1 0 0 6.623102415468651 +51 1 1 -1 0 0 7.745564463778024 +52 1 1 -1 0 0 8.868026512087397 +53 1 1 -1 0 0 9.99048856039677 +54 1 1 -1 0 0 11.112950608706143 +55 1 1 -1 0 0 12.235412657015516 +56 1 1 -1 0 0 13.357874705324889 +57 1 1 -1 0 0 14.480336753634262 +58 1 1 -1 0 0 15.602798801943635 +59 1 1 -1 0 0 16.725260850253008 +60 1 1 -1 0 0 17.84772289856238 +61 1 1 -1 0 0 18.970184946871754 +62 1 1 -1 0 0 20.092646995181127 +63 1 1 -1 0 0 21.2151090434905 +64 1 1 -1 0 0 22.337571091799873 +65 1 1 -1 0 0 23.460033140109246 +66 1 1 -1 0 0 24.58249518841862 +67 1 1 -1 0 0 25.704957236727992 +68 1 1 -1 0 0 26.827419285037365 +69 1 1 -1 0 0 27.949881333346738 +70 1 1 -1 0 0 29.07234338165611 +71 1 1 -1 0 0 30.194805429965484 +72 1 1 -1 0 0 31.317267478274857 +73 1 1 -1 0 0 32.43972952658423 +74 1 1 -1 0 0 33.5621915748936 +75 1 1 -1 0 0 34.684653623202976 +76 1 1 -1 0 0 35.80711567151235 +77 1 1 -1 0 0 36.92957771982172 +78 1 1 -1 0 0 38.052039768131095 +79 1 1 -1 0 0 39.17450181644047 +80 1 1 -1 0 0 40.29696386474984 +81 0 2 1 -27.886422274724097 27.72001798427955 38.68169635811057 +82 0 2 1 29.812255760623188 17.871838747003693 -29.094648426460257 +83 0 2 1 -13.23881351410531 13.28123966828678 -24.422176415560116 +84 0 2 1 4.9465650593939685 -37.7521903558826 -15.115417767729575 +85 0 2 1 34.82527943387106 29.457664434004897 -25.565595338061254 +86 0 2 1 46.35660570786446 -7.161776614070412 -20.2471250527001 +87 0 2 1 39.20854546781531 34.96815569014278 13.893531822586723 +88 0 2 1 -7.797240698180197 0.07861219105048889 48.686453603015224 +89 0 2 1 43.92391845355516 -39.42362941705827 22.448930565867585 +90 0 2 1 -40.371744364329984 -17.743039071967246 -15.08153047835009 +91 0 2 1 -21.573165497710058 -0.5844447399891948 -45.73596994149077 +92 0 2 1 -19.882394451769102 -7.392447895357577 30.733607063808876 +93 0 2 1 -17.393031309514107 26.882975097407467 -47.64059480000892 +94 0 2 1 25.652222561671735 1.0229206994719107 -14.959030208952043 +95 0 2 1 26.075045766879313 19.902341017250052 46.70284805469666 +96 0 2 1 39.91980369168496 0.753749460187592 -26.203575929573407 +97 0 2 1 13.777613371273958 7.112171629839359 -33.5270487721399 +98 0 2 1 18.944534687271826 20.090215089875286 -34.381335468790574 +99 0 2 1 -23.801856387842435 -42.275962146864586 -8.322936238250279 +100 0 2 1 -31.386991395893826 29.83894468611787 8.937114269513422 +101 0 2 1 -41.07090001085809 49.59339931450579 6.666864232174753 +102 0 2 1 -46.58911504232167 -32.46068937927039 19.40424197066872 +103 0 2 1 -39.94659416571965 -36.28203465180086 5.841020764632312 +104 0 2 1 -26.027467090120137 -41.05522015175137 -1.1145958296128313 +105 0 2 1 37.09602855959457 23.76087951027276 45.09142423198867 +106 0 2 1 -27.78138413517528 -48.97344929918942 45.91491289356401 +107 0 2 1 4.468912883622387 -5.217782298407556 6.381420595433383 +108 0 2 1 36.758686966564525 48.425582881586166 -25.909273336802997 +109 0 2 1 -27.045102667146036 -19.713951008254117 4.339232870380627 +110 0 2 1 -5.984280016624311 -49.45311479123866 36.35727783065221 +111 0 2 1 27.833389147163018 -47.80144978082761 -47.71458334276804 +112 0 2 1 -23.628507668044364 -30.353876765128685 36.174277933133254 +113 0 2 1 -40.93360714431151 40.1336490864843 -27.035347797435495 +114 0 2 1 6.3523980881104976 -28.636485436097082 -10.671354350535445 +115 0 2 1 42.765716958607086 -32.85779663523676 -1.9682360265562124 +116 0 2 1 -33.68069757415453 16.800769050458484 -6.273374390373085 +117 0 2 1 13.909148568042937 4.921040289518388 12.111069913598996 +118 0 2 1 6.728324076730296 -48.44092815223126 -35.92436883370601 +119 0 2 1 -18.121173967321912 -15.76903395165283 2.2495451015454933 +120 0 2 1 -11.75253233489407 -45.82569982175387 -12.477142440015896 +121 0 2 1 1.9713864197144133 17.961034900064007 32.97992150691711 +122 0 2 1 -3.993384770632943 -47.63120435620297 27.75490859098018 +123 0 2 1 -0.32208279553454844 -47.30616152402566 -22.751109302380367 +124 0 2 1 -0.135777029397957 23.88599790464609 -31.87440560354473 +125 0 2 1 -6.123924906817393 -2.038519565120424 45.4809181974626 +126 0 2 1 -29.622588299895046 42.40404115712096 6.640479709229595 +127 0 2 1 -11.694512971272673 19.983258641775762 -38.152427411711145 +128 0 2 1 -20.93721440637313 39.46397829322392 -45.52708262202337 +129 0 2 1 34.13340147809369 36.14268504987945 -23.978137043267044 +130 0 2 1 -37.422309952611485 29.181841318883087 27.55677757161692 +131 0 2 1 30.11314373799594 18.721794400471353 1.5553303682670574 +132 0 2 1 -7.3563467211571805 46.84253369205935 -39.84708490437832 +133 0 2 1 -3.695927445484358 2.494403998274727 -7.634369981832755 +134 0 2 1 44.09701173592077 17.717328437831043 31.54108326477207 +135 0 2 1 48.070189931616795 10.601166369398662 -28.28574863896286 +136 0 2 1 -7.044858382811761 -42.080663380241766 -1.4369925734636553 +137 0 2 1 -12.485032488076918 23.87106169116919 6.178803347562642 +138 0 2 1 -15.613232443702309 10.103630885941392 -20.447182948810916 +139 0 2 1 28.610332347774147 37.08335835592116 -19.90280831362493 +140 0 2 1 25.853920233242505 -27.768648181803655 24.971357611943475 +141 0 2 1 9.256159541363296 -23.562096053197934 -4.722701100419371 +142 0 2 1 39.96929397877305 -11.88228547846326 -28.70638149104603 +143 0 2 1 -37.98545134633291 -23.50528193202669 -10.939982626098441 +144 0 2 1 25.40017763114089 -47.49220127581256 15.1783064865064 +145 0 2 1 28.073596076651768 3.6631266774864386 31.54355751177208 +146 0 2 1 -19.596457173068703 46.79824882013442 -12.302655772327597 +147 0 2 1 -36.46192411958321 -2.785830672302666 -25.1901381125736 +148 0 2 1 -27.377389198969894 11.295792272951147 39.32842550184691 +149 0 2 1 32.24967019136358 -20.517755791016402 31.20590722085157 +150 0 2 1 47.70698618147787 9.75462874031868 -28.267447889542563 +151 0 2 1 17.157803106328345 -27.48141290657965 7.7670687016760525 +152 0 2 1 15.089833959419678 5.342811012118396 27.35336620165029 +153 0 2 1 9.836963929211372 -11.047378229392443 -20.960811370690678 +154 0 2 1 44.66600586278604 14.949733274456321 -29.328965994323575 +155 0 2 1 -21.006260382140685 8.492712712433658 -46.31580169190271 +156 0 2 1 -29.970979487850748 -36.46250489415931 26.914372830947457 +157 0 2 1 -1.0821372755756329 -8.453379951300242 -19.95665062432509 +158 0 2 1 -24.033653425909772 -39.51330620205049 20.067656167683793 +159 0 2 1 27.747287624384626 -21.904990435351312 -10.819345241055956 +160 0 2 1 -40.86737066410612 -25.609300376714796 -21.128139356809783 + +Bonds + # bond_id bond_type atom1_id atom2_id +1 1 1 2 +2 1 2 3 +3 1 3 4 +4 1 4 5 +5 1 5 6 +6 1 6 7 +7 1 7 8 +8 1 8 9 +9 1 9 10 +10 1 10 11 +11 1 11 12 +12 1 12 13 +13 1 13 14 +14 1 14 15 +15 1 15 16 +16 1 16 17 +17 1 17 18 +18 1 18 19 +19 1 19 20 +20 1 20 21 +21 1 21 22 +22 1 22 23 +23 1 23 24 +24 1 24 25 +25 1 25 26 +26 1 26 27 +27 1 27 28 +28 1 28 29 +29 1 29 30 +30 1 30 31 +31 1 31 32 +32 1 32 33 +33 1 33 34 +34 1 34 35 +35 1 35 36 +36 1 36 37 +37 1 37 38 +38 1 38 39 +39 1 39 40 +40 1 40 41 +41 1 41 42 +42 1 42 43 +43 1 43 44 +44 1 44 45 +45 1 45 46 +46 1 46 47 +47 1 47 48 +48 1 48 49 +49 1 49 50 +50 1 50 51 +51 1 51 52 +52 1 52 53 +53 1 53 54 +54 1 54 55 +55 1 55 56 +56 1 56 57 +57 1 57 58 +58 1 58 59 +59 1 59 60 +60 1 60 61 +61 1 61 62 +62 1 62 63 +63 1 63 64 +64 1 64 65 +65 1 65 66 +66 1 66 67 +67 1 67 68 +68 1 68 69 +69 1 69 70 +70 1 70 71 +71 1 71 72 +72 1 72 73 +73 1 73 74 +74 1 74 75 +75 1 75 76 +76 1 76 77 +77 1 77 78 +78 1 78 79 +79 1 79 80 diff --git a/examples/USER/misc/charge_regulation/in_acid.chreg b/examples/USER/misc/charge_regulation/in_acid.chreg new file mode 100644 index 0000000000..32beeda732 --- /dev/null +++ b/examples/USER/misc/charge_regulation/in_acid.chreg @@ -0,0 +1,40 @@ +# Charge regulation lammps for simple weak electrolyte + +units lj +atom_style charge +dimension 3 +boundary p p p +processors * * * +neighbor 3.0 bin +read_data data_acid.chreg + +variable cut_long equal 12.5 +variable nevery equal 100 +variable nmc equal 100 +variable pH equal 7.0 +variable pKa equal 6.0 +variable pIm equal 3.0 +variable pIp equal 3.0 + +variable cut_lj equal 2^(1.0/6.0) +variable lunit_nm equal 0.72 # in the units of nm +velocity all create 1.0 8008 loop geom + +pair_style lj/cut/coul/long ${cut_lj} ${cut_long} +pair_coeff * * 1.0 1.0 ${cut_lj} # charges +kspace_style ewald 1.0e-3 +dielectric 1.0 +pair_modify shift no + +######### VERLET INTEGRATION WITH LANGEVIN THERMOSTAT ########### +fix fnve all nve +compute dtemp all temp +compute_modify dtemp dynamic yes +fix fT all langevin 1.0 1.0 1.0 123 +fix_modify fT temp dtemp + +fix chareg all charge_regulation 2 3 acid_type 1 pH ${pH} pKa ${pKa} pIp ${pIp} pIm ${pIm} lunit_nm ${lunit_nm} nevery ${nevery} nmc ${nmc} seed 2345 tempfixid fT +thermo 100 +thermo_style custom step pe c_dtemp f_chareg[1] f_chareg[2] f_chareg[3] f_chareg[4] f_chareg[5] f_chareg[6] f_chareg[7] f_chareg[8] +timestep 0.005 +run 10000 diff --git a/examples/USER/misc/charge_regulation/in_polymer.chreg b/examples/USER/misc/charge_regulation/in_polymer.chreg new file mode 100644 index 0000000000..4dc72a8156 --- /dev/null +++ b/examples/USER/misc/charge_regulation/in_polymer.chreg @@ -0,0 +1,35 @@ +# Charge regulation lammps for a polymer chain +units lj +atom_style full +dimension 3 +boundary p p p +processors * * * +neighbor 3.0 bin +read_data data_polymer.chreg + +bond_style harmonic +bond_coeff 1 100 1.122462 # K R0 +velocity all create 1.0 8008 loop geom + +pair_style lj/cut/coul/long 1.122462 20 +pair_coeff * * 1.0 1.0 1.122462 # charges +kspace_style pppm 1.0e-3 +pair_modify shift no +dielectric 1.0 + +######### VERLET INTEGRATION WITH LANGEVIN THERMOSTAT ########### +fix fnve all nve +compute dtemp all temp +compute_modify dtemp dynamic yes +fix fT all langevin 1.0 1.0 1.0 123 +fix_modify fT temp dtemp + +fix chareg1 all charge_regulation 2 3 acid_type 1 pH 7.0 pKa 6.5 pIp 3.0 pIm 3.0 temp 1.0 nmc 40 +fix chareg2 all charge_regulation 4 5 acid_type 1 pH 7.0 pKa 6.5 pIp 7.0 pIm 7.0 temp 1.0 nmc 40 +fix chareg3 all charge_regulation 4 3 pIp 7.0 pIm 3.0 temp 1.0 nmc 20 + +thermo 100 +# print: step, potential energy, temperature, neutral acids, charged acids, salt cations, salt anions, H+ ions, OH- ions +thermo_style custom step pe c_dtemp f_chareg1[3] f_chareg1[4] f_chareg1[7] f_chareg1[8] f_chareg2[7] f_chareg2[8] +timestep 0.005 +run 10000 diff --git a/examples/USER/misc/charge_regulation/log_acid.lammps b/examples/USER/misc/charge_regulation/log_acid.lammps new file mode 100644 index 0000000000..cbc3661eb1 --- /dev/null +++ b/examples/USER/misc/charge_regulation/log_acid.lammps @@ -0,0 +1,163 @@ +LAMMPS (24 Dec 2020) +Reading data file ... + orthogonal box = (-25.000000 -25.000000 -25.000000) to (25.000000 25.000000 25.000000) + 1 by 1 by 1 MPI processor grid + reading atoms ... + 219 atoms + read_data CPU = 0.001 seconds +Ewald initialization ... + using 12-bit tables for long-range coulomb (../kspace.cpp:339) + G vector (1/distance) = 0.14221027 + estimated absolute RMS force accuracy = 0.0010128126 + estimated relative force accuracy = 0.0010128126 + KSpace vectors: actual max1d max3d = 257 5 665 + kxmax kymax kzmax = 5 5 5 +0 atoms in group Fix_CR:exclusion_group:chareg +WARNING: Neighbor exclusions used with KSpace solver may give inconsistent Coulombic energies (../neighbor.cpp:486) +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 15.5 + ghost atom cutoff = 15.5 + binsize = 7.75, bins = 7 7 7 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair lj/cut/coul/long, perpetual + attributes: half, newton on + pair build: half/bin/atomonly/newton + stencil: half/bin/3d/newton + bin: standard +Setting up Verlet run ... + Unit style : lj + Current step : 0 + Time step : 0.005 +Per MPI rank memory allocation (min/avg/max) = 11.91 | 11.91 | 11.91 Mbytes +Step PotEng c_dtemp f_chareg[1] f_chareg[2] f_chareg[3] f_chareg[4] f_chareg[5] f_chareg[6] f_chareg[7] f_chareg[8] + 0 -0.054228269 1 0 0 1 99 0 0 109 10 + 100 -0.058672881 0.99159291 100 71 16 84 0 0 92 8 + 200 -0.05399313 0.92006523 200 154 26 74 0 0 85 11 + 300 -0.047035343 0.92728143 300 240 22 78 0 0 85 7 + 400 -0.049597809 1.0617937 400 319 16 84 0 0 92 8 + 500 -0.052409835 1.0006148 500 404 12 88 0 0 97 9 + 600 -0.056012172 0.98059344 600 481 15 85 0 0 92 7 + 700 -0.053639989 0.99572709 700 561 16 84 0 0 94 10 + 800 -0.060026132 0.95764632 800 639 22 78 0 0 84 6 + 900 -0.050785422 0.98399084 900 719 28 72 0 0 82 10 + 1000 -0.062294743 0.97200068 1000 797 26 74 0 0 82 8 + 1100 -0.051269402 1.0064376 1100 877 25 75 0 0 84 9 + 1200 -0.077744839 1.0159098 1200 955 23 77 0 0 88 11 + 1300 -0.084889696 1.1230485 1300 1037 20 80 0 0 90 10 + 1400 -0.059361445 0.96735845 1400 1120 18 82 0 0 93 11 + 1500 -0.052926174 0.95579188 1500 1199 24 76 0 0 86 10 + 1600 -0.052376649 0.99376378 1600 1284 22 78 0 0 89 11 + 1700 -0.052480188 0.96085964 1700 1361 27 73 0 0 84 11 + 1800 -0.065884306 0.96747971 1800 1441 21 79 0 0 84 5 + 1900 -0.054315859 0.95873145 1900 1521 23 77 0 0 84 7 + 2000 -0.037161802 0.93562039 2000 1604 27 73 0 0 79 6 + 2100 -0.034977265 0.97177103 2100 1684 26 74 0 0 85 11 + 2200 -0.047434868 0.97897613 2200 1762 17 83 0 0 93 10 + 2300 -0.047392634 0.96570672 2300 1837 18 82 0 0 92 10 + 2400 -0.044879306 0.98620033 2400 1910 19 81 0 0 89 8 + 2500 -0.069690496 1.0690505 2500 1988 16 84 0 0 91 7 + 2600 -0.081588407 0.97711054 2600 2067 17 83 0 0 92 9 + 2700 -0.06341681 1.0386711 2700 2146 20 80 0 0 85 5 + 2800 -0.045290012 1.0402055 2800 2230 18 82 0 0 91 9 + 2900 -0.046875012 1.0609775 2900 2317 24 76 0 0 86 10 + 3000 -0.031258722 0.93861202 3000 2400 24 76 0 0 85 9 + 3100 -0.04673342 0.90800583 3100 2485 25 75 0 0 90 15 + 3200 -0.054354227 0.94493881 3200 2567 16 84 0 0 94 10 + 3300 -0.053647746 0.92321446 3300 2641 17 83 0 0 94 11 + 3400 -0.031751732 0.93735127 3400 2725 22 78 0 0 92 14 + 3500 -0.053806113 0.98798136 3500 2795 28 72 0 0 84 12 + 3600 -0.040751349 0.84291639 3600 2873 28 72 0 0 84 12 + 3700 -0.051747138 1.072448 3700 2951 24 76 0 0 92 16 + 3800 -0.043420594 1.0076309 3800 3030 26 74 0 0 79 5 + 3900 -0.050845848 1.0250023 3900 3103 29 71 0 0 76 5 + 4000 -0.039837847 1.064111 4000 3182 29 71 0 0 83 12 + 4100 -0.045638995 1.1249685 4100 3262 28 72 0 0 81 9 + 4200 -0.047956491 0.92255907 4200 3348 26 74 0 0 87 13 + 4300 -0.054052822 1.006239 4300 3423 19 81 0 0 90 9 + 4400 -0.053148034 1.0028887 4400 3506 24 76 0 0 83 7 + 4500 -0.062132076 1.0317847 4500 3587 23 77 0 0 82 5 + 4600 -0.04616043 0.99066453 4600 3673 28 72 0 0 82 10 + 4700 -0.066990889 1.0242064 4700 3755 18 82 0 0 90 8 + 4800 -0.0564736 0.91765628 4800 3832 22 78 0 0 91 13 + 4900 -0.052301294 0.95348659 4900 3912 28 72 0 0 81 9 + 5000 -0.062630677 1.0336579 5000 3989 18 82 0 0 92 10 + 5100 -0.053645908 1.0314613 5100 4062 20 80 0 0 85 5 + 5200 -0.062189568 1.0504732 5200 4133 23 77 0 0 84 7 + 5300 -0.049092746 1.0310832 5300 4217 24 76 0 0 82 6 + 5400 -0.051859257 0.99600428 5400 4299 27 73 0 0 80 7 + 5500 -0.065540815 0.98012128 5500 4381 19 81 0 0 92 11 + 5600 -0.071018582 0.9252814 5600 4455 23 77 0 0 84 7 + 5700 -0.066954185 1.0325214 5700 4535 26 74 0 0 82 8 + 5800 -0.064847249 1.0313536 5800 4617 21 79 0 0 90 11 + 5900 -0.063173056 0.95455853 5900 4703 18 82 0 0 92 10 + 6000 -0.064807837 0.97182222 6000 4790 21 79 0 0 91 12 + 6100 -0.07067683 0.91775921 6100 4875 16 84 0 0 94 10 + 6200 -0.071400842 1.0162225 6200 4952 17 83 0 0 87 4 + 6300 -0.078479449 1.0106706 6300 5033 21 79 0 0 84 5 + 6400 -0.083167651 1.0246584 6400 5111 18 82 0 0 90 8 + 6500 -0.092611537 1.0766467 6500 5195 20 80 0 0 88 8 + 6600 -0.096710071 1.0246648 6600 5274 15 85 0 0 91 6 + 6700 -0.073399857 0.94939392 6700 5351 17 83 0 0 92 9 + 6800 -0.062479375 0.9393967 6800 5434 18 82 0 0 93 11 + 6900 -0.065391043 0.93475954 6900 5514 22 78 0 0 89 11 + 7000 -0.045655499 0.98688239 7000 5601 21 79 0 0 90 11 + 7100 -0.061186309 1.0309063 7100 5684 22 78 0 0 87 9 + 7200 -0.074737514 1.0516593 7200 5769 25 75 0 0 80 5 + 7300 -0.075228979 1.0167704 7300 5847 21 79 0 0 86 7 + 7400 -0.06660147 1.0947107 7400 5930 25 75 0 0 87 12 + 7500 -0.071915247 1.10542 7500 6009 24 76 0 0 84 8 + 7600 -0.029974303 0.99202697 7600 6095 28 72 0 0 80 8 + 7700 -0.029024004 1.0390995 7700 6182 28 72 0 0 83 11 + 7800 -0.056250746 0.96393961 7800 6260 18 82 0 0 91 9 + 7900 -0.072178944 0.9833919 7900 6339 21 79 0 0 86 7 + 8000 -0.070377248 1.021342 8000 6419 23 77 0 0 88 11 + 8100 -0.07753283 0.96194312 8100 6493 26 74 0 0 86 12 + 8200 -0.075617309 0.9715344 8200 6576 25 75 0 0 89 14 + 8300 -0.077480013 0.99106705 8300 6662 20 80 0 0 91 11 + 8400 -0.079901928 0.89855112 8400 6744 23 77 0 0 91 14 + 8500 -0.069192745 1.0606791 8500 6822 19 81 0 0 91 10 + 8600 -0.058657202 1.1270217 8600 6898 15 85 0 0 95 10 + 8700 -0.044985397 1.0367419 8700 6979 27 73 0 0 84 11 + 8800 -0.064266376 0.91557003 8800 7060 21 79 0 0 89 10 + 8900 -0.068680533 0.95963643 8900 7133 19 81 0 0 88 7 + 9000 -0.051736144 1.0398547 9000 7213 13 87 0 0 94 7 + 9100 -0.058381436 0.98047663 9100 7290 17 83 0 0 89 6 + 9200 -0.05531014 0.92541631 9200 7368 22 78 0 0 85 7 + 9300 -0.04386907 0.9339658 9300 7454 22 78 0 0 89 11 + 9400 -0.052293168 0.94314034 9400 7539 22 78 0 0 86 8 + 9500 -0.050362046 1.0489028 9500 7617 18 82 0 0 90 8 + 9600 -0.054272227 1.0879161 9600 7697 11 89 0 0 96 7 + 9700 -0.042514179 1.0051505 9700 7771 22 78 0 0 84 6 + 9800 -0.045365018 0.95363669 9800 7850 25 75 0 0 77 2 + 9900 -0.064287274 0.91994667 9900 7928 27 73 0 0 81 8 + 10000 -0.05689162 0.99963208 10000 8011 22 78 0 0 84 6 +Loop time of 19.4452 on 1 procs for 10000 steps with 190 atoms + +Performance: 222162.510 tau/day, 514.265 timesteps/s +99.9% CPU use with 1 MPI tasks x no OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.68864 | 0.68864 | 0.68864 | 0.0 | 3.54 +Kspace | 6.7893 | 6.7893 | 6.7893 | 0.0 | 34.92 +Neigh | 0.060782 | 0.060782 | 0.060782 | 0.0 | 0.31 +Comm | 0.047035 | 0.047035 | 0.047035 | 0.0 | 0.24 +Output | 0.0027227 | 0.0027227 | 0.0027227 | 0.0 | 0.01 +Modify | 11.838 | 11.838 | 11.838 | 0.0 | 60.88 +Other | | 0.01878 | | | 0.10 + +Nlocal: 190.000 ave 190 max 190 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 592.000 ave 592 max 592 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 2194.00 ave 2194 max 2194 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 2194 +Ave neighs/atom = 11.547368 +Neighbor list builds = 10287 +Dangerous builds = 0 +Total wall time: 0:00:19 \ No newline at end of file diff --git a/examples/USER/misc/charge_regulation/log_polymer.lammps b/examples/USER/misc/charge_regulation/log_polymer.lammps new file mode 100644 index 0000000000..87cab63a6c --- /dev/null +++ b/examples/USER/misc/charge_regulation/log_polymer.lammps @@ -0,0 +1,181 @@ +LAMMPS (24 Dec 2020) +Reading data file ... + orthogonal box = (-50.000000 -50.000000 -50.000000) to (50.000000 50.000000 50.000000) + 1 by 1 by 1 MPI processor grid + reading atoms ... + 160 atoms + scanning bonds ... + 1 = max bonds/atom + reading bonds ... + 79 bonds +Finding 1-2 1-3 1-4 neighbors ... + special bond factors lj: 0 0 0 + special bond factors coul: 0 0 0 + 2 = max # of 1-2 neighbors + 2 = max # of 1-3 neighbors + 4 = max # of 1-4 neighbors + 6 = max # of special neighbors + special bonds CPU = 0.000 seconds + read_data CPU = 0.004 seconds +PPPM initialization ... + using 12-bit tables for long-range coulomb (../kspace.cpp:339) + G vector (1/distance) = 0.077106934 + grid = 8 8 8 + stencil order = 5 + estimated absolute RMS force accuracy = 0.00074388331 + estimated relative force accuracy = 0.00074388331 + using double precision KISS FFT + 3d grid and FFT values/proc = 2197 512 +0 atoms in group Fix_CR:exclusion_group:chareg1 +0 atoms in group Fix_CR:exclusion_group:chareg2 +0 atoms in group Fix_CR:exclusion_group:chareg3 +WARNING: Neighbor exclusions used with KSpace solver may give inconsistent Coulombic energies (../neighbor.cpp:486) +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 23 + ghost atom cutoff = 23 + binsize = 11.5, bins = 9 9 9 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair lj/cut/coul/long, perpetual + attributes: half, newton on + pair build: half/bin/newton + stencil: half/bin/3d/newton + bin: standard +Setting up Verlet run ... + Unit style : lj + Current step : 0 + Time step : 0.005 +Per MPI rank memory allocation (min/avg/max) = 6.962 | 6.962 | 6.962 Mbytes +Step PotEng c_dtemp f_chareg1[3] f_chareg1[4] f_chareg1[7] f_chareg1[8] f_chareg2[7] f_chareg2[8] + 0 0.49903297 1 0 80 80 0 0 0 + 100 0.63380666 0.87307225 8 72 77 6 1 0 + 200 0.5865464 1.0048645 16 64 81 16 0 1 + 300 0.55802913 1.0499142 19 61 91 29 0 1 + 400 0.44734087 1.0838048 24 56 98 41 0 1 + 500 0.47010775 1.005226 23 57 106 48 0 1 + 600 0.3452105 0.97814306 28 52 109 56 0 1 + 700 0.29208955 0.99766419 32 48 115 67 0 0 + 800 0.27821915 1.0091641 31 49 128 80 1 0 + 900 0.28943788 0.93619239 26 54 145 91 0 0 + 1000 0.22963142 1.0162138 27 53 150 97 0 0 + 1100 0.24238916 0.99146577 31 49 149 100 0 0 + 1200 0.17029095 1.0406453 38 42 144 102 0 0 + 1300 0.15830969 0.94661447 34 46 155 109 0 0 + 1400 0.16698712 1.0116563 35 45 159 114 0 0 + 1500 0.15432936 0.95600941 36 44 162 118 0 0 + 1600 0.16973501 0.98326602 31 49 171 122 0 0 + 1700 0.19725116 0.9915273 33 47 175 128 0 0 + 1800 0.15278999 1.0304873 29 51 193 142 0 0 + 1900 0.17418479 0.99490216 30 50 194 144 0 0 + 2000 0.14238391 0.9638301 32 48 189 141 0 0 + 2100 0.13054378 0.97164976 32 48 192 144 0 0 + 2200 0.092083069 1.0112059 40 40 191 151 0 0 + 2300 0.085175091 1.0070667 39 41 200 159 0 0 + 2400 0.083367076 0.9934796 35 45 208 163 0 0 + 2500 0.11494744 0.97650855 31 49 220 172 1 0 + 2600 0.10796032 0.97047046 34 46 221 175 0 0 + 2700 0.11080141 0.93570013 36 44 223 179 0 0 + 2800 0.096699277 0.97702627 35 45 223 178 0 0 + 2900 0.079403783 1.0870961 32 48 229 181 0 0 + 3000 0.08288836 1.0642515 35 45 231 186 0 0 + 3100 0.094000833 1.0241111 38 42 229 187 0 0 + 3200 0.10011052 1.043594 34 46 235 189 0 0 + 3300 0.096782103 0.99549134 34 46 234 188 0 0 + 3400 0.057703946 1.00292 34 46 236 190 0 0 + 3500 0.074345642 0.95064523 36 44 234 190 0 0 + 3600 0.085872341 0.9759514 35 45 238 192 0 1 + 3700 0.086427565 0.99843063 35 45 240 194 0 1 + 3800 0.076091357 0.98516844 32 48 252 203 0 1 + 3900 0.047187813 1.0063336 37 43 247 204 0 0 + 4000 0.068269223 1.0390369 35 45 248 203 0 0 + 4100 0.074209582 0.99912762 36 44 249 205 0 0 + 4200 0.087016078 1.050265 36 44 246 202 0 0 + 4300 0.081325479 1.0417103 35 45 245 200 0 0 + 4400 0.047345973 0.96517298 39 41 243 202 0 0 + 4500 0.041856955 0.94569673 38 42 245 203 0 0 + 4600 0.049588267 0.99046371 42 38 249 211 0 0 + 4700 0.043079897 1.0098538 43 37 245 208 0 0 + 4800 0.049122913 1.0229995 41 39 247 208 0 0 + 4900 0.059151797 1.0236679 36 44 249 205 0 0 + 5000 0.053806841 1.0308397 42 38 243 205 0 0 + 5100 0.053623833 1.0638841 39 41 246 205 0 0 + 5200 0.086215806 1.0027613 37 43 243 200 0 0 + 5300 0.031422797 1.0338154 38 42 245 203 0 0 + 5400 0.051341116 0.92205149 34 46 246 200 0 0 + 5500 0.039292708 0.97530704 32 48 251 203 0 0 + 5600 0.035215415 1.023123 33 47 246 199 0 0 + 5700 0.054553598 0.95833063 30 50 253 203 0 0 + 5800 0.035699456 1.0721613 37 43 248 205 0 0 + 5900 0.062426908 1.0612245 38 42 252 210 0 0 + 6000 0.056362902 1.0002968 36 44 248 204 0 0 + 6100 0.061550208 0.97270904 38 42 245 203 0 0 + 6200 0.051825485 0.98187623 36 44 253 209 0 0 + 6300 0.052137885 0.98906723 36 44 253 210 1 0 + 6400 0.068218075 1.0511584 36 44 256 212 0 0 + 6500 0.080167413 0.97270144 36 44 252 208 0 0 + 6600 0.052169204 1.0160108 41 39 249 210 0 0 + 6700 0.057313326 0.98033894 38 42 251 209 0 0 + 6800 0.073008094 0.96239565 35 45 256 211 0 0 + 6900 0.060159599 1.0063892 37 43 264 221 0 0 + 7000 0.061738744 1.0031443 39 41 259 218 0 0 + 7100 0.043263424 1.0425248 44 36 255 219 0 0 + 7200 0.052179167 0.99512151 39 41 261 220 0 0 + 7300 0.053258707 1.0171204 43 37 256 219 0 0 + 7400 0.026037532 0.93786837 45 35 259 224 0 0 + 7500 0.029731213 1.0172281 46 34 250 216 0 0 + 7600 0.023118288 0.95628439 42 38 262 224 0 0 + 7700 0.037021854 0.99991854 42 38 263 225 0 0 + 7800 0.050404736 1.0130826 40 40 260 220 0 0 + 7900 0.035658921 0.95772506 40 40 259 219 0 0 + 8000 0.034426806 1.0028052 40 40 254 214 0 0 + 8100 0.041427611 1.0347682 40 40 256 216 0 0 + 8200 0.05986843 0.9804614 38 42 262 220 0 0 + 8300 0.041419023 1.0613186 37 43 264 221 0 0 + 8400 0.065701758 1.0511531 40 40 256 216 0 0 + 8500 0.091954526 0.97190676 37 43 257 214 0 0 + 8600 0.056982532 1.017813 35 45 252 207 0 0 + 8700 0.075615111 1.0148527 29 51 263 212 0 0 + 8800 0.066070082 1.0259454 33 47 260 213 0 0 + 8900 0.055054194 1.0183535 37 43 247 204 0 0 + 9000 0.063070816 1.0266115 39 41 244 203 0 0 + 9100 0.10174156 0.99457684 34 46 246 200 0 0 + 9200 0.071667261 1.033159 33 47 249 202 0 0 + 9300 0.05520096 0.99821492 38 42 243 201 0 0 + 9400 0.050355422 0.99148522 37 43 243 200 0 0 + 9500 0.062314961 1.0042937 36 44 252 208 0 0 + 9600 0.061148899 1.0052132 37 43 254 211 0 0 + 9700 0.078695273 1.0175164 37 43 252 209 0 0 + 9800 0.067487202 1.0110138 35 45 258 213 0 0 + 9900 0.070340779 0.99640142 31 49 263 214 0 0 + 10000 0.037252172 0.99863894 32 48 259 211 0 0 +Loop time of 23.0419 on 1 procs for 10000 steps with 550 atoms + +Performance: 187484.206 tau/day, 433.991 timesteps/s +100.0% CPU use with 1 MPI tasks x no OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 2.5444 | 2.5444 | 2.5444 | 0.0 | 11.04 +Bond | 0.025075 | 0.025075 | 0.025075 | 0.0 | 0.11 +Kspace | 4.7385 | 4.7385 | 4.7385 | 0.0 | 20.56 +Neigh | 0.2058 | 0.2058 | 0.2058 | 0.0 | 0.89 +Comm | 0.073087 | 0.073087 | 0.073087 | 0.0 | 0.32 +Output | 0.003464 | 0.003464 | 0.003464 | 0.0 | 0.02 +Modify | 15.417 | 15.417 | 15.417 | 0.0 | 66.91 +Other | | 0.03479 | | | 0.15 + +Nlocal: 550.000 ave 550 max 550 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 1023.00 ave 1023 max 1023 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 9644.00 ave 9644 max 9644 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 9644 +Ave neighs/atom = 17.534545 +Ave special neighs/atom = 0.85090909 +Neighbor list builds = 7576 +Dangerous builds = 0 +Total wall time: 0:00:23 \ No newline at end of file diff --git a/src/USER-MISC/README b/src/USER-MISC/README index 314fe6146e..ef25a0c116 100644 --- a/src/USER-MISC/README +++ b/src/USER-MISC/README @@ -53,6 +53,7 @@ dihedral_style table/cut, Mike Salerno, ksalerno@pha.jhu.edu, 11 May 18 fix accelerate/cos, Zheng Gong (ENS de Lyon), z.gong@outlook.com, 24 Apr 20 fix addtorque, Laurent Joly (U Lyon), ljoly.ulyon at gmail.com, 8 Aug 11 fix ave/correlate/long, Jorge Ramirez (UPM Madrid), jorge.ramirez at upm.es, 21 Oct 2015 +fix charge_regulation, Tine Curk and Jiaxing Yuan, tcurk5@gmail.com, 02 Feb 2021 fix electron/stopping/fit, James Stewart (SNL), jstewa .at. sandia.gov, 23 Sep 2020 fix electron/stopping, Konstantin Avchaciov, k.avchachov at gmail.com, 26 Feb 2019 fix ffl, David Wilkins (EPFL Lausanne), david.wilkins @ epfl.ch, 28 Sep 2018 diff --git a/src/USER-MISC/fix_charge_regulation.cpp b/src/USER-MISC/fix_charge_regulation.cpp new file mode 100644 index 0000000000..3bb9de1b27 --- /dev/null +++ b/src/USER-MISC/fix_charge_regulation.cpp @@ -0,0 +1,1335 @@ +/* ---------------------------------------------------------------------- + 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: Tine Curk (tcurk5@gmail.com) and Jiaxing Yuan (yuanjiaxing123@hotmail.com) +------------------------------------------------------------------------- */ +#include "fix_charge_regulation.h" +#include +#include +#include +#include "atom.h" +#include "atom_vec.h" +#include "molecule.h" +#include "update.h" +#include "modify.h" +#include "fix.h" +#include "comm.h" +#include "compute.h" +#include "group.h" +#include "domain.h" +#include "region.h" +#include "random_park.h" +#include "force.h" +#include "pair.h" +#include "bond.h" +#include "angle.h" +#include "dihedral.h" +#include "improper.h" +#include "kspace.h" +#include "math_extra.h" +#include "math_const.h" +#include "memory.h" +#include "error.h" +#include "neighbor.h" + +using namespace LAMMPS_NS; +using namespace FixConst; +using namespace MathConst; + +// large energy value used to signal overlap +#define MAXENERGYSIGNAL 1.0e100 +#define MAXENERGYTEST 1.0e50 +#define small 0.0000001 +#define PI 3.1415926 + +/* ---------------------------------------------------------------------- */ +Fix_charge_regulation::Fix_charge_regulation(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg), + ngroups(0), groupstrings(NULL), + random_equal(NULL), random_unequal(NULL), + idftemp(NULL), ptype_ID(NULL) { + + // Region restrictions not yet implemented .. + + vector_flag = 1; + size_vector = 8; + global_freq = 1; + extvector = 0; + restart_global = 1; + time_depend = 1; + cr_nmax = 0; + overlap_flag = 0; + energy_stored = 0; + + // necessary to specify the free ion types + cation_type = utils::inumeric(FLERR, arg[3], false, lmp); + anion_type = utils::inumeric(FLERR, arg[4], false, lmp); + + // set defaults and read optional arguments + options(narg - 5, &arg[5]); + + if (nevery <= 0) error->all(FLERR, "Illegal fix charge_regulation command"); + if (nmc < 0) error->all(FLERR, "Illegal fix charge_regulation command"); + if (llength_unit_in_nm < 0.0) error->all(FLERR, "Illegal fix charge_regulation command"); + if (*target_temperature_tcp < 0.0) error->all(FLERR, "Illegal fix charge_regulation command"); + if (seed <= 0) error->all(FLERR, "Illegal fix charge_regulation command"); + if (cation_type <= 0) error->all(FLERR, "Illegal fix charge_regulation command"); + if (anion_type <= 0) error->all(FLERR, "Illegal fix charge_regulation command"); + if (reaction_distance < 0.0) error->all(FLERR, "Illegal fix charge_regulation command"); + if (salt_charge[0] <= 0) error->all(FLERR, "Illegal fix charge_regulation command"); + if (salt_charge[1] >= 0) error->all(FLERR, "Illegal fix charge_regulation command"); + if ((salt_charge[1] % salt_charge[0] != 0) && (salt_charge[0] % salt_charge[1] != 0)) + error->all(FLERR, + "Illegal fix charge_regulation command, multivalent cation/anion charges are allowed, " + "but must be divisible, e.g. (3,-1) is fine, but (3,-2) is not implemented"); + + if (pmcmoves[0] < 0 || pmcmoves[1] < 0 || pmcmoves[2] < 0) + error->all(FLERR, "Illegal fix charge_regulation command"); + if (acid_type < 0) pmcmoves[0] = 0; + if (base_type < 0) pmcmoves[1] = 0; + // normalize + double psum = pmcmoves[0] + pmcmoves[1] + pmcmoves[2]; + if (psum <= 0) error->all(FLERR, "Illegal fix charge_regulation command"); + pmcmoves[0] /= psum; + pmcmoves[1] /= psum; + pmcmoves[2] /= psum; + + force_reneighbor = 1; + next_reneighbor = update->ntimestep + 1; + random_equal = new RanPark(lmp, seed); + random_unequal = new RanPark(lmp, seed); + nacid_attempts = 0; + nacid_successes = 0; + nbase_attempts = 0; + nbase_successes = 0; + nsalt_attempts = 0; + nsalt_successes = 0; +} + +Fix_charge_regulation::~Fix_charge_regulation() { + + memory->destroy(ptype_ID); + + delete random_equal; + delete random_unequal; + + if (group) { + int igroupall = group->find("all"); + neighbor->exclusion_group_group_delete(exclusion_group, igroupall); + } +} + +int Fix_charge_regulation::setmask() { + int mask = 0; + mask |= PRE_EXCHANGE; + return mask; +} + +void Fix_charge_regulation::init() { + + triclinic = domain->triclinic; + + char *id_pe = (char *) "thermo_pe"; + int ipe = modify->find_compute(id_pe); + c_pe = modify->compute[ipe]; + + if (atom->molecule_flag) { + + int flag = 0; + for (int i = 0; i < atom->nlocal; i++) + if (atom->type[i] == cation_type || atom->type[i] == anion_type) + if (atom->molecule[i]) flag = 1; + int flagall = flag; + + MPI_Allreduce(&flag, &flagall, 1, MPI_INT, MPI_SUM, world); + if (flagall && comm->me == 0) + error->all(FLERR, "Fix charge regulation cannot exchange individual atoms (ions) belonging to a molecule"); + } + + if (domain->dimension == 2) + error->all(FLERR, "Cannot use fix charge regulation in a 2d simulation"); + + // create a new group for interaction exclusions + // used for attempted atom deletions + // skip if already exists from previous init() + + if (!exclusion_group_bit) { + char **group_arg = new char *[4]; + + // create unique group name for atoms to be excluded + int len = strlen(id) + 30; + group_arg[0] = new char[len]; + sprintf(group_arg[0], "Fix_CR:exclusion_group:%s", id); + group_arg[1] = (char *) "subtract"; + group_arg[2] = (char *) "all"; + group_arg[3] = (char *) "all"; + group->assign(4, group_arg); + exclusion_group = group->find(group_arg[0]); + if (exclusion_group == -1) + error->all(FLERR, "Could not find fix CR exclusion group ID"); + exclusion_group_bit = group->bitmask[exclusion_group]; + + // neighbor list exclusion setup + // turn off interactions between group all and the exclusion group + + int narg = 4; + char **arg = new char *[narg];; + arg[0] = (char *) "exclude"; + arg[1] = (char *) "group"; + arg[2] = group_arg[0]; + arg[3] = (char *) "all"; + neighbor->modify_params(narg, arg); + delete[] group_arg[0]; + delete[] group_arg; + delete[] arg; + } + + // check that no deletable atoms are in atom->firstgroup + // deleting such an atom would not leave firstgroup atoms first + + if (atom->firstgroup >= 0) { + int *mask = atom->mask; + int firstgroupbit = group->bitmask[atom->firstgroup]; + + int flag = 0; + for (int i = 0; i < atom->nlocal; i++) + if ((mask[i] == groupbit) && (mask[i] && firstgroupbit)) flag = 1; + + int flagall; + MPI_Allreduce(&flag, &flagall, 1, MPI_INT, MPI_SUM, world); + + if (flagall) + error->all(FLERR, "Cannot do Fix charge regulation on atoms in atom_modify first group"); + } + + // construct group bitmask for all new atoms + // aggregated over all group keywords + + groupbitall = 1 | groupbit; + + for (int igroup = 0; igroup < ngroups; igroup++) { + int jgroup = group->find(groupstrings[igroup]); + if (jgroup == -1) + error->all(FLERR, "Could not find specified fix charge regulation group ID"); + groupbitall |= group->bitmask[jgroup]; + } +} + +void Fix_charge_regulation::pre_exchange() { + + if (next_reneighbor != update->ntimestep) return; + xlo = domain->boxlo[0]; + xhi = domain->boxhi[0]; + ylo = domain->boxlo[1]; + yhi = domain->boxhi[1]; + zlo = domain->boxlo[2]; + zhi = domain->boxhi[2]; + + if (triclinic) { + sublo = domain->sublo_lamda; + subhi = domain->subhi_lamda; + } else { + sublo = domain->sublo; + subhi = domain->subhi; + } + volume = domain->xprd * domain->yprd * domain->zprd; + if (triclinic) domain->x2lamda(atom->nlocal); + domain->pbc(); + comm->exchange(); + atom->nghost = 0; + comm->borders(); + + if (triclinic) domain->lamda2x(atom->nlocal + atom->nghost); + energy_stored = energy_full(); + if (energy_stored > MAXENERGYTEST) + error->warning(FLERR, "Energy of old configuration in fix charge_regulation is > MAXENERGYTEST."); + + if ((reaction_distance > fabs(domain->boxhi[0] - domain->boxlo[0]) / 2) || + (reaction_distance > fabs(domain->boxhi[1] - domain->boxlo[1]) / 2) || + (reaction_distance > fabs(domain->boxhi[2] - domain->boxlo[2]) / 2)) { + error->warning(FLERR, + "reaction distance (rxd) is larger than half the box dimension, resetting default: xrd = 0."); + reaction_distance = 0; + } + // volume in units of (N_A * mol / liter) + volume_rx = (xhi - xlo) * (yhi - ylo) * (zhi - zlo) * pow(llength_unit_in_nm, 3) * 0.602214; + if (reaction_distance < small) { + vlocal_xrd = volume_rx; + } else { + vlocal_xrd = 4.0 * PI * pow(reaction_distance, 3) / 3.0 * pow(llength_unit_in_nm, 3) * 0.602214; + } + beta = 1.0 / (force->boltz * *target_temperature_tcp); + + // reinitialize counters + nacid_neutral = particle_number(acid_type, 0); + nacid_charged = particle_number(acid_type, -1); + nbase_neutral = particle_number(base_type, 0); + nbase_charged = particle_number(base_type, 1); + ncation = particle_number(cation_type, salt_charge[0]); + nanion = particle_number(anion_type, salt_charge[1]); + + + // Attempt exchanges + if (!only_salt_flag) { + + // Do charge regulation + for (int i = 0; i < nmc; i++) { + double rand_number = random_equal->uniform(); + if (rand_number < pmcmoves[0] / 2) { + forward_acid(); + nacid_attempts++; + } else if (rand_number < pmcmoves[0]) { + backward_acid(); + nacid_attempts++; + } else if (rand_number < pmcmoves[0] + pmcmoves[1] / 2) { + forward_base(); + nbase_attempts++; + } else if (rand_number < pmcmoves[0] + pmcmoves[1]) { + backward_base(); + nbase_attempts++; + } else if (rand_number < pmcmoves[0] + pmcmoves[1] + pmcmoves[2] / 2) { + forward_ions(); + nsalt_attempts++; + } else { + backward_ions(); + nsalt_attempts++; + } + } + } else { + // do only ion insertion, multivalent cation/anions are implemented + if (salt_charge[0] >= -salt_charge[1]) { + salt_charge_ratio = -salt_charge[0] / salt_charge[1]; + } else { + salt_charge_ratio = -salt_charge[1] / salt_charge[0]; + } + for (int i = 0; i < nmc; i++) { + double rand_number = random_equal->uniform(); + if (rand_number < 0.5) { + forward_ions_multival(); + nsalt_attempts++; + } else { + backward_ions_multival(); + nsalt_attempts++; + } + } + } + + // assign unique tags to newly inserted ions + if (add_tags_flag && atom->tag_enable) assign_tags(); + + if (triclinic) domain->x2lamda(atom->nlocal); + domain->pbc(); + comm->exchange(); + atom->nghost = 0; + comm->borders(); + if (triclinic) domain->lamda2x(atom->nlocal + atom->nghost); + next_reneighbor = update->ntimestep + nevery; +} + +void Fix_charge_regulation::forward_acid() { + + double energy_before = energy_stored; + double factor; + double *dummyp; + double pos[3]; + pos[0] = 0; + pos[1] = 0; + pos[2] = 0; // acid/base particle position + double pos_all[3]; + int m1 = -1, m2 = -1; + + m1 = get_random_particle(acid_type, 0, 0, dummyp); + if (npart_xrd != nacid_neutral) error->all(FLERR, "Fix charge regulation acid count inconsistent"); + + if (nacid_neutral > 0) { + if (m1 >= 0) { + atom->q[m1] = -1; // assign negative charge to acid + pos[0] = atom->x[m1][0]; + pos[1] = atom->x[m1][1]; + pos[2] = atom->x[m1][2]; + } + npart_xrd2 = ncation; + if (reaction_distance >= small) { + pos_all[0] = pos[0]; + pos_all[1] = pos[1]; + pos_all[2] = pos[2]; + MPI_Allreduce(pos, pos_all, 3, MPI_DOUBLE, MPI_SUM, world); + npart_xrd2 = particle_number_xrd(cation_type, 1, reaction_distance, pos_all); + } + m2 = insert_particle(cation_type, 1, reaction_distance, pos_all); + factor = nacid_neutral * vlocal_xrd * pow(10, -pKa) + * (1 + pow(10, pH - pI_plus)) / ((1 + nacid_charged) * (1 + npart_xrd2)); + + double energy_after = energy_full(); + + if (energy_after < MAXENERGYTEST && + random_equal->uniform() < factor * exp(beta * (energy_before - energy_after))) { + energy_stored = energy_after; + nacid_successes += 1; + ncation++; + nacid_charged++; + nacid_neutral--; + } else { + energy_stored = energy_before; + atom->natoms--; + if (m2 >= 0) { + atom->nlocal--; + } + if (m1 >= 0) { + atom->q[m1] = 0; + } + if (force->kspace) force->kspace->qsum_qsq(); + if (force->pair->tail_flag) force->pair->reinit(); + } + } +} + +void Fix_charge_regulation::backward_acid() { + + double energy_before = energy_stored; + double factor; + int mask_tmp; + double *dummyp; + double pos[3]; + pos[0] = 0; + pos[1] = 0; + pos[2] = 0; // acid/base particle position + double pos_all[3]; + int m1 = -1, m1_all = -1, m2 = -1, m2_all = -1; + + m1 = get_random_particle(acid_type, -1, 0, dummyp); + if (npart_xrd != nacid_charged) error->all(FLERR, "Fix charge regulation acid count inconsistent"); + + if (nacid_charged > 0) { + if (m1 >= 0) { + atom->q[m1] = 0; + pos[0] = atom->x[m1][0]; + pos[1] = atom->x[m1][1]; + pos[2] = atom->x[m1][2]; + } + if (reaction_distance >= small) { + pos_all[0] = pos[0]; + pos_all[1] = pos[1]; + pos_all[2] = pos[2]; + MPI_Allreduce(pos, pos_all, 3, MPI_DOUBLE, MPI_SUM, world); + } + m2 = get_random_particle(cation_type, 1, reaction_distance, pos_all); + // note: npart_xrd changes everytime get_random_particle is called. + + if (npart_xrd > 0) { + if (m2 >= 0) { + atom->q[m2] = 0; + mask_tmp = atom->mask[m2]; // remember group bits. + atom->mask[m2] = exclusion_group_bit; + } + factor = (1 + nacid_neutral) * vlocal_xrd * pow(10, -pKa) + * (1 + pow(10, pH - pI_plus)) / (nacid_charged * npart_xrd); + + double energy_after = energy_full(); + + if (energy_after < MAXENERGYTEST && + random_equal->uniform() < (1.0 / factor) * exp(beta * (energy_before - energy_after))) { + nacid_successes += 1; + atom->natoms--; + energy_stored = energy_after; + nacid_charged--; + nacid_neutral++; + ncation--; + if (m2 >= 0) { + atom->avec->copy(atom->nlocal - 1, m2, 1); + atom->nlocal--; + } + } else { + energy_stored = energy_before; + if (m1 >= 0) { + atom->q[m1] = -1; + } + if (m2 >= 0) { + atom->q[m2] = 1; + atom->mask[m2] = mask_tmp; + } + } + } else { + if (m1 >= 0) { + atom->q[m1] = -1; + } + } + } +} + +void Fix_charge_regulation::forward_base() { + + double energy_before = energy_stored; + double factor; + double *dummyp; + double pos[3]; + pos[0] = 0; + pos[1] = 0; + pos[2] = 0; // acid/base particle position + double pos_all[3]; + int m1 = -1, m1_all = -1, m2 = -1, m2_all = -1; + + m1 = get_random_particle(base_type, 0, 0, dummyp); + if (npart_xrd != nbase_neutral) error->all(FLERR, "Fix charge regulation acid count inconsistent"); + + if (nbase_neutral > 0) { + if (m1 >= 0) { + atom->q[m1] = 1; // assign negative charge to acid + pos[0] = atom->x[m1][0]; + pos[1] = atom->x[m1][1]; + pos[2] = atom->x[m1][2]; + } + npart_xrd2 = nanion; + if (reaction_distance >= small) { + pos_all[0] = pos[0]; + pos_all[1] = pos[1]; + pos_all[2] = pos[2]; + MPI_Allreduce(pos, pos_all, 3, MPI_DOUBLE, MPI_SUM, world); + npart_xrd2 = particle_number_xrd(anion_type, -1, reaction_distance, pos_all); + } + factor = nbase_neutral * vlocal_xrd * pow(10, -pKb) + * (1 + pow(10, pKs - pH - pI_minus)) / + ((1 + nbase_charged) * (1 + npart_xrd2)); + m2 = insert_particle(anion_type, -1, reaction_distance, pos_all); + + double energy_after = energy_full(); + if (energy_after < MAXENERGYTEST && + random_equal->uniform() < factor * exp(beta * (energy_before - energy_after))) { + energy_stored = energy_after; + nbase_successes += 1; + nbase_charged++; + nbase_neutral--; + nanion++; + } else { + energy_stored = energy_before; + atom->natoms--; + if (m2 >= 0) { + atom->nlocal--; + } + if (m1 >= 0) { + atom->q[m1] = 0; + } + if (force->kspace) force->kspace->qsum_qsq(); + if (force->pair->tail_flag) force->pair->reinit(); + } + } +} + +void Fix_charge_regulation::backward_base() { + + double energy_before = energy_stored; + double factor; + double *dummyp; + int mask_tmp; + double pos[3]; + pos[0] = 0; + pos[1] = 0; + pos[2] = 0; // acid/base particle position + double pos_all[3]; + int m1 = -1, m1_all = -1, m2 = -1, m2_all = -1; + + m1 = get_random_particle(base_type, 1, 0, dummyp); + if (npart_xrd != nbase_charged) error->all(FLERR, "Fix charge regulation acid count inconsistent"); + + if (nbase_charged > 0) { + if (m1 >= 0) { + atom->q[m1] = 0; + pos[0] = atom->x[m1][0]; + pos[1] = atom->x[m1][1]; + pos[2] = atom->x[m1][2]; + } + if (reaction_distance >= small) { + pos_all[0] = pos[0]; + pos_all[1] = pos[1]; + pos_all[2] = pos[2]; + MPI_Allreduce(pos, pos_all, 3, MPI_DOUBLE, MPI_SUM, world); + } + m2 = get_random_particle(anion_type, -1, reaction_distance, pos_all); + + if (npart_xrd > 0) { + if (m2 >= 0) { + atom->q[m2] = 0; + mask_tmp = atom->mask[m2]; // remember group bits. + atom->mask[m2] = exclusion_group_bit; + } + factor = (1 + nbase_neutral) * vlocal_xrd * pow(10, -pKb) + * (1 + pow(10, pKs - pH - pI_minus)) / (nbase_charged * npart_xrd); + + double energy_after = energy_full(); + + if (energy_after < MAXENERGYTEST && + random_equal->uniform() < (1.0 / factor) * exp(beta * (energy_before - energy_after))) { + nbase_successes += 1; + atom->natoms--; + energy_stored = energy_after; + nbase_charged--; + nbase_neutral++; + nanion--; + if (m2 >= 0) { + atom->avec->copy(atom->nlocal - 1, m2, 1); + atom->nlocal--; + } + } else { + energy_stored = energy_before; + if (m1 >= 0) { + atom->q[m1] = 1; + } + if (m2 >= 0) { + atom->q[m2] = -1; + atom->mask[m2] = mask_tmp; + } + } + } else { + if (m1 >= 0) { + atom->q[m1] = 1; + } + } + } +} + +void Fix_charge_regulation::forward_ions() { + + double energy_before = energy_stored; + double factor; + double *dummyp; + int m1 = -1, m2 = -1; + factor = volume_rx * volume_rx * (pow(10, -pH) + pow(10, -pI_plus)) + * (pow(10, -pKs + pH) + pow(10, -pI_minus)) / + ((1 + ncation) * (1 + nanion)); + + m1 = insert_particle(cation_type, +1, 0, dummyp); + m2 = insert_particle(anion_type, -1, 0, dummyp); + double energy_after = energy_full(); + if (energy_after < MAXENERGYTEST && random_equal->uniform() < factor * exp(beta * (energy_before - energy_after))) { + energy_stored = energy_after; + nsalt_successes += 1; + ncation++; + nanion++; + } else { + energy_stored = energy_before; + atom->natoms--; + if (m1 >= 0) { + atom->nlocal--; + } + atom->natoms--; + if (m2 >= 0) { + atom->nlocal--; + } + if (force->kspace) force->kspace->qsum_qsq(); + if (force->pair->tail_flag) force->pair->reinit(); + } +} + + +void Fix_charge_regulation::backward_ions() { + + double energy_before = energy_stored; + double factor; + int mask1_tmp, mask2_tmp; + double *dummyp; // dummy pointer + int m1 = -1, m2 = -1; + + m1 = get_random_particle(cation_type, +1, 0, dummyp); + if (npart_xrd != ncation) error->all(FLERR, "Fix charge regulation salt count inconsistent"); + if (ncation > 0) { + m2 = get_random_particle(anion_type, -1, 0, dummyp); + if (npart_xrd != nanion) error->all(FLERR, "Fix charge regulation salt count inconsistent"); + if (nanion > 0) { + + // attempt deletion + + if (m1 >= 0) { + atom->q[m1] = 0; + mask1_tmp = atom->mask[m1]; + atom->mask[m1] = exclusion_group_bit; + } + if (m2 >= 0) { + atom->q[m2] = 0; + mask2_tmp = atom->mask[m2]; + atom->mask[m2] = exclusion_group_bit; + } + factor = (volume_rx * volume_rx * (pow(10, -pH) + pow(10, -pI_plus)) * + (pow(10, -pKs + pH) + pow(10, -pI_minus))) / (ncation * nanion); + + double energy_after = energy_full(); + if (energy_after < MAXENERGYTEST && + random_equal->uniform() < (1.0 / factor) * exp(beta * (energy_before - energy_after))) { + energy_stored = energy_after; + nsalt_successes += 1; + ncation--; + nanion--; + + // ions must be deleted in order, otherwise index m could change upon the first deletion + atom->natoms -= 2; + if (m1 > m2) { + if (m1 >= 0) { + atom->avec->copy(atom->nlocal - 1, m1, 1); + atom->nlocal--; + } + if (m2 >= 0) { + atom->avec->copy(atom->nlocal - 1, m2, 1); + atom->nlocal--; + } + } else { + if (m2 >= 0) { + atom->avec->copy(atom->nlocal - 1, m2, 1); + atom->nlocal--; + } + if (m1 >= 0) { + atom->avec->copy(atom->nlocal - 1, m1, 1); + atom->nlocal--; + } + } + if (force->kspace) force->kspace->qsum_qsq(); + if (force->pair->tail_flag) force->pair->reinit(); + + } else { + energy_stored = energy_before; + + // reassign original charge and mask + if (m1 >= 0) { + atom->q[m1] = 1; + atom->mask[m1] = mask1_tmp; + } + if (m2 >= 0) { + atom->q[m2] = -1; + atom->mask[m2] = mask2_tmp; + } + } + } else { + // reassign original charge and mask + if (m1 >= 0) { + atom->q[m1] = 1; + atom->mask[m1] = mask1_tmp; + } + } + } +} + +void Fix_charge_regulation::forward_ions_multival() { + + double energy_before = energy_stored; + double factor = 1; + double *dummyp; + int mm[salt_charge_ratio + 1];// particle ID array for all ions to be inserted + + if (salt_charge[0] <= -salt_charge[1]) { + // insert one anion and (salt_charge_ratio) cations + + mm[0] = insert_particle(anion_type, salt_charge[1], 0, dummyp); + factor *= volume_rx * pow(10, -pI_minus) / (1 + nanion); + for (int i = 0; i < salt_charge_ratio; i++) { + mm[i + 1] = insert_particle(cation_type, salt_charge[0], 0, dummyp); + factor *= volume_rx * pow(10, -pI_plus) / (1 + ncation + i); + } + } else { + // insert one cation and (salt_charge_ratio) anions + + mm[0] = insert_particle(cation_type, salt_charge[0], 0, dummyp); + factor *= volume_rx * pow(10, -pI_plus) / (1 + ncation); + for (int i = 0; i < salt_charge_ratio; i++) { + mm[i + 1] = insert_particle(anion_type, salt_charge[1], 0, dummyp); + factor *= volume_rx * pow(10, -pI_minus) / (1 + nanion + i); + } + } + + double energy_after = energy_full(); + if (energy_after < MAXENERGYTEST && random_equal->uniform() < factor * exp(beta * (energy_before - energy_after))) { + energy_stored = energy_after; + nsalt_successes += 1; + + if (salt_charge[0] <= -salt_charge[1]) { + ncation += salt_charge_ratio; + nanion++; + } else { + nanion += salt_charge_ratio; + ncation++; + } + } else { + energy_stored = energy_before; + + // delete inserted ions + for (int i = 0; i < salt_charge_ratio + 1; i++) { + atom->natoms--; + if (mm[i] >= 0) { + atom->nlocal--; + } + } + if (force->kspace) force->kspace->qsum_qsq(); + if (force->pair->tail_flag) force->pair->reinit(); + } +} + +void Fix_charge_regulation::backward_ions_multival() { + + double energy_before = energy_stored; + double factor = 1; + double *dummyp; // dummy pointer + int mm[salt_charge_ratio + 1]; // particle ID array for all deleted ions + double qq[salt_charge_ratio + 1]; // charge array for all deleted ions + int mask_tmp[salt_charge_ratio + 1]; // temporary mask array + + if (salt_charge[0] <= -salt_charge[1]) { + // delete one anion and (salt_charge_ratio) cations + if (ncation < salt_charge_ratio || nanion < 1) return; + + mm[0] = get_random_particle(anion_type, salt_charge[1], 0, dummyp); + if (npart_xrd != nanion) error->all(FLERR, "Fix charge regulation salt count inconsistent"); + factor *= volume_rx * pow(10, -pI_minus) / (nanion); + if (mm[0] >= 0) { + qq[0] = atom->q[mm[0]]; + atom->q[mm[0]] = 0; + mask_tmp[0] = atom->mask[mm[0]]; + atom->mask[mm[0]] = exclusion_group_bit; + } + for (int i = 0; i < salt_charge_ratio; i++) { + mm[i + 1] = get_random_particle(cation_type, salt_charge[0], 0, dummyp); + if (npart_xrd != ncation - i) error->all(FLERR, "Fix charge regulation salt count inconsistent"); + factor *= volume_rx * pow(10, -pI_plus) / (ncation - i); + if (mm[i + 1] >= 0) { + qq[i + 1] = atom->q[mm[i + 1]]; + atom->q[mm[i + 1]] = 0; + mask_tmp[i + 1] = atom->mask[mm[i + 1]]; + atom->mask[mm[i + 1]] = exclusion_group_bit; + } + } + } else { + // delete one cation and (salt_charge_ratio) anions + + if (nanion < salt_charge_ratio || ncation < 1) return; + mm[0] = get_random_particle(cation_type, salt_charge[0], 0, dummyp); + if (npart_xrd != ncation) error->all(FLERR, "Fix charge regulation salt count inconsistent"); + factor *= volume_rx * pow(10, -pI_plus) / (ncation); + if (mm[0] >= 0) { + qq[0] = atom->q[mm[0]]; + atom->q[mm[0]] = 0; + mask_tmp[0] = atom->mask[mm[0]]; + atom->mask[mm[0]] = exclusion_group_bit; + } + for (int i = 0; i < salt_charge_ratio; i++) { + mm[i + 1] = get_random_particle(anion_type, salt_charge[1], 0, dummyp); + if (npart_xrd != nanion - i) error->all(FLERR, "Fix charge regulation salt count inconsistent"); + if (mm[i + 1] >= 0) { + qq[i + 1] = atom->q[mm[i + 1]]; + atom->q[mm[i + 1]] = 0; + mask_tmp[i + 1] = atom->mask[mm[i + 1]]; + atom->mask[mm[i + 1]] = exclusion_group_bit; + } + factor *= volume_rx * pow(10, -pI_minus) / (nanion - i); + } + } + + // attempt deletion + + double energy_after = energy_full(); + if (energy_after < MAXENERGYTEST && + random_equal->uniform() < (1.0 / factor) * exp(beta * (energy_before - energy_after))) { + energy_stored = energy_after; + + atom->natoms -= 1 + salt_charge_ratio; + // ions must be deleted in order, otherwise index m could change upon the first deletion + for (int i = 0; i < salt_charge_ratio + 1; i++) { + // get max mm value, poor N^2 scaling, but charge ratio is a small number (2 or 3). + int maxmm = -1, jmaxm = -1; + for (int j = 0; j < salt_charge_ratio + 1; j++) { + if (mm[j] > maxmm) { + maxmm = mm[j]; + jmaxm = j; + } + } + if (maxmm < 0) { + break; // already deleted all particles in this thread + } else { + // delete particle maxmm + atom->avec->copy(atom->nlocal - 1, maxmm, 1); + atom->nlocal--; + mm[jmaxm] = -1; + } + } + + // update indices + nsalt_successes += 1; + if (salt_charge[0] <= -salt_charge[1]) { + ncation -= salt_charge_ratio; + nanion--; + } else { + nanion -= salt_charge_ratio; + ncation--; + } + if (force->kspace) force->kspace->qsum_qsq(); + if (force->pair->tail_flag) force->pair->reinit(); + + } else { + energy_stored = energy_before; + + // reassign original charge and mask + for (int i = 0; i < salt_charge_ratio + 1; i++) { + if (mm[i] >= 0) { + atom->q[mm[i]] = qq[i]; + atom->mask[mm[i]] = mask_tmp[i]; + } + } + } +} + +int Fix_charge_regulation::insert_particle(int ptype, double charge, double rd, double *target) { + + // insert a particle of type (ptype) with charge (charge) within distance (rd) of (target) + + double coord[3]; + int m = -1; + if (rd < small) { + coord[0] = xlo + random_equal->uniform() * (xhi - xlo); + coord[1] = ylo + random_equal->uniform() * (yhi - ylo); + coord[2] = zlo + random_equal->uniform() * (zhi - zlo); + } else { + double radius = reaction_distance * random_equal->uniform(); + double theta = random_equal->uniform() * PI; + double phi = random_equal->uniform() * 2 * PI; + coord[0] = target[0] + radius * sin(theta) * cos(phi); + coord[1] = target[1] + radius * sin(theta) * sin(phi); + coord[2] = target[2] + radius * cos(theta); + coord[0] = coord[0] - floor(1.0 * (coord[0] - xlo) / (xhi - xlo)) * (xhi - xlo); + coord[1] = coord[1] - floor(1.0 * (coord[1] - ylo) / (yhi - ylo)) * (yhi - ylo); + coord[2] = coord[2] - floor(1.0 * (coord[2] - zlo) / (zhi - zlo)) * (zhi - zlo); + } + + 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]) { + atom->avec->create_atom(ptype, coord); + m = atom->nlocal - 1; + atom->mask[m] = groupbitall; + + sigma = sqrt(force->boltz * *target_temperature_tcp / atom->mass[ptype] / force->mvv2e); + atom->v[m][0] = random_unequal->gaussian() * sigma; + atom->v[m][1] = random_unequal->gaussian() * sigma; + atom->v[m][2] = random_unequal->gaussian() * sigma; + atom->q[m] = charge; + modify->create_attribute(m); + + } + atom->nghost = 0; + comm->borders(); + atom->natoms++; + return m; +} + +int Fix_charge_regulation::get_random_particle(int ptype, double charge, double rd, double *target) { + + // returns a randomly chosen particle of type (ptype) with charge (charge) + // chosen among particles within distance (rd) of (target) + + int nlocal = atom->nlocal; + + // expand memory, if necessary + if (atom->nmax > cr_nmax) { + memory->sfree(ptype_ID); + cr_nmax = atom->nmax; + ptype_ID = (int *) memory->smalloc(cr_nmax * sizeof(int), + "CR: local_atom_list"); + } + + int count_local, count_global, count_before; + int m = -1; + count_local = 0; + count_global = 0; + count_before = 0; + + if (rd < small) { //reaction_distance < small: No geometry constraint on random particle choice + for (int i = 0; i < nlocal; i++) { + if (atom->type[i] == ptype && fabs(atom->q[i] - charge) < small && + atom->mask[i] != exclusion_group_bit) { + ptype_ID[count_local] = i; + count_local++; + } + } + } else { + double dx, dy, dz, distance_check; + for (int i = 0; i < nlocal; i++) { + dx = fabs(atom->x[i][0] - target[0]); + dx -= static_cast(1.0 * dx / (xhi - xlo) + 0.5) * (xhi - xlo); + dy = fabs(atom->x[i][1] - target[1]); + dy -= static_cast(1.0 * dy / (yhi - ylo) + 0.5) * (yhi - ylo); + dz = fabs(atom->x[i][2] - target[2]); + dz -= static_cast(1.0 * dz / (zhi - zlo) + 0.5) * (zhi - zlo); + distance_check = dx * dx + dy * dy + dz * dz; + if ((distance_check < rd * rd) && atom->type[i] == ptype && + fabs(atom->q[i] - charge) < small && atom->mask[i] != exclusion_group_bit) { + ptype_ID[count_local] = i; + count_local++; + } + } + } + count_global = count_local; + count_before = count_local; + MPI_Allreduce(&count_local, &count_global, 1, MPI_INT, MPI_SUM, world); + MPI_Scan(&count_local, &count_before, 1, MPI_INT, MPI_SUM, world); + count_before -= count_local; + + npart_xrd = count_global; // save the number of particles, for use in MC acceptance ratio + if (count_global > 0) { + const int ID_global = floor(random_equal->uniform() * count_global); + if ((ID_global >= count_before) && (ID_global < (count_before + count_local))) { + const int ID_local = ID_global - count_before; + m = ptype_ID[ID_local]; // local ID of the chosen particle + return m; + } + } + return -1; +} + +double Fix_charge_regulation::energy_full() { + int imolecule; + if (triclinic) domain->x2lamda(atom->nlocal); + domain->pbc(); + comm->exchange(); + atom->nghost = 0; + comm->borders(); + if (triclinic) domain->lamda2x(atom->nlocal + atom->nghost); + if (modify->n_pre_neighbor) modify->pre_neighbor(); + neighbor->build(1); + int eflag = 1; + int vflag = 0; + if (overlap_flag) { + int overlaptestall; + int overlaptest = 0; + double delx, dely, delz, rsq; + double **x = atom->x; + tagint *molecule = atom->molecule; + int nall = atom->nlocal + atom->nghost; + for (int i = 0; i < atom->nlocal; i++) { + for (int j = i + 1; j < nall; j++) { + delx = x[i][0] - x[j][0]; + dely = x[i][1] - x[j][1]; + delz = x[i][2] - x[j][2]; + rsq = delx * delx + dely * dely + delz * delz; + if (rsq < overlap_cutoffsq) { + overlaptest = 1; + break; + } + } + if (overlaptest) break; + } + overlaptestall = overlaptest; + MPI_Allreduce(&overlaptest, &overlaptestall, 1, + MPI_INT, MPI_MAX, world); + if (overlaptestall) return MAXENERGYSIGNAL; + } + size_t nbytes = sizeof(double) * (atom->nlocal + atom->nghost); + if (nbytes) memset(&atom->f[0][0], 0, 3 * nbytes); + + if (modify->n_pre_force) modify->pre_force(vflag); + + if (force->pair) force->pair->compute(eflag, vflag); + + if (atom->molecular) { + if (force->bond) force->bond->compute(eflag, vflag); + if (force->angle) force->angle->compute(eflag, vflag); + if (force->dihedral) force->dihedral->compute(eflag, vflag); + if (force->improper) force->improper->compute(eflag, vflag); + } + + if (force->kspace) force->kspace->compute(eflag, vflag); + + if (modify->n_post_force) modify->post_force(vflag); + if (modify->n_end_of_step) modify->end_of_step(); + update->eflag_global = update->ntimestep; + double total_energy = c_pe->compute_scalar(); + return total_energy; +} + +int Fix_charge_regulation::particle_number_xrd(int ptype, double charge, double rd, double *target) { + + int count = 0; + if (rd < small) { + for (int i = 0; i < atom->nlocal; i++) { + if (atom->type[i] == ptype && fabs(atom->q[i] - charge) < small && atom->mask[i] != exclusion_group_bit) + count++; + } + } else { + double dx, dy, dz, distance_check; + for (int i = 0; i < atom->nlocal; i++) { + dx = fabs(atom->x[i][0] - target[0]); + dx -= static_cast(1.0 * dx / (xhi - xlo) + 0.5) * (xhi - xlo); + dy = fabs(atom->x[i][1] - target[1]); + dy -= static_cast(1.0 * dy / (yhi - ylo) + 0.5) * (yhi - ylo); + dz = fabs(atom->x[i][2] - target[2]); + dz -= static_cast(1.0 * dz / (zhi - zlo) + 0.5) * (zhi - zlo); + distance_check = dx * dx + dy * dy + dz * dz; + if ((distance_check < rd * rd) && atom->type[i] == ptype && + fabs(atom->q[i] - charge) < small && atom->mask[i] != exclusion_group_bit) { + count++; + } + } + } + int count_sum = count; + MPI_Allreduce(&count, &count_sum, 1, MPI_INT, MPI_SUM, world); + return count_sum; +} + +int Fix_charge_regulation::particle_number(int ptype, double charge) { + + int count = 0; + for (int i = 0; i < atom->nlocal; i++) { + if (atom->type[i] == ptype && fabs(atom->q[i] - charge) < small && atom->mask[i] != exclusion_group_bit) + count = count + 1; + } + int count_sum = count; + MPI_Allreduce(&count, &count_sum, 1, MPI_INT, MPI_SUM, world); + return count_sum; +} + +double Fix_charge_regulation::compute_vector(int n) { + double count_temp = 0; + if (n == 0) { + return nacid_attempts + nbase_attempts + nsalt_attempts; + } else if (n == 1) { + return nacid_successes + nbase_successes + nsalt_successes; + } else if (n == 2) { + return particle_number(acid_type, 0); + } else if (n == 3) { + return particle_number(acid_type, -1); + } else if (n == 4) { + return particle_number(base_type, 0); + } else if (n == 5) { + return particle_number(base_type, 1); + } else if (n == 6) { + return particle_number(cation_type, salt_charge[0]); + } else if (n == 7) { + return particle_number(anion_type, salt_charge[1]); + } + return 0.0; +} + +void Fix_charge_regulation::setThermoTemperaturePointer() { + int ifix = -1; + ifix = modify->find_fix(idftemp); + if (ifix == -1) { + error->all(FLERR, + "Fix charge regulation regulation could not find a temperature fix id provided by tempfixid\n"); + } + Fix *temperature_fix = modify->fix[ifix]; + int dim; + target_temperature_tcp = (double *) temperature_fix->extract("t_target", dim); + +} + +void Fix_charge_regulation::assign_tags() { + // Assign tags to ions with zero tags + if (atom->tag_enable) { + tagint *tag = atom->tag; + tagint maxtag_all = 0; + tagint maxtag = 0; + for (int i = 0; i < atom->nlocal; i++) maxtag = MAX(maxtag, tag[i]); + maxtag_all = maxtag; + MPI_Allreduce(&maxtag, &maxtag_all, 1, MPI_LMP_TAGINT, MPI_MAX, world); + if (maxtag_all >= MAXTAGINT) + error->all(FLERR, "New atom IDs exceed maximum allowed ID"); + + tagint notag = 0; + tagint notag_all; + for (int i = 0; i < atom->nlocal; i++) + if (tag[i] == 0 && (atom->type[i] == cation_type || atom->type[i] == anion_type))notag++; + notag_all = notag; + MPI_Allreduce(¬ag, ¬ag_all, 1, MPI_LMP_TAGINT, MPI_SUM, world); + if (notag_all >= MAXTAGINT) + error->all(FLERR, "New atom IDs exceed maximum allowed ID"); + + tagint notag_sum = notag; + MPI_Scan(¬ag, ¬ag_sum, 1, MPI_LMP_TAGINT, 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 < atom->nlocal; i++) { + if (tag[i] == 0 && (atom->type[i] == cation_type || atom->type[i] == anion_type)) { + tag[i] = itag++; + } + } + if (atom->map_style) atom->map_init(); + atom->nghost = 0; + comm->borders(); + } +} + +/* ---------------------------------------------------------------------- + parse input options +------------------------------------------------------------------------- */ + +void Fix_charge_regulation::options(int narg, char **arg) { + if (narg < 0) error->all(FLERR, "Illegal fix charge regulation command"); + + // defaults + + pH = 7.0; + pI_plus = 100; + pI_minus = 100; + acid_type = -1; + base_type = -1; + pKa = 100; + pKb = 100; + pKs = 14.0; + nevery = 100; + nmc = 100; + pmcmoves[0] = pmcmoves[1] = pmcmoves[2] = 0.33; + llength_unit_in_nm= 0.72; + + reservoir_temperature = 1.0; + reaction_distance = 0; + seed = 12345; + target_temperature_tcp = &reservoir_temperature; + add_tags_flag = false; + only_salt_flag = false; + salt_charge[0] = 1; // cation charge + salt_charge[1] = -1; // anion charge + + exclusion_group = 0; + exclusion_group_bit = 0; + ngroups = 0; + int ngroupsmax = 0; + groupstrings = NULL; + + int iarg = 0; + while (iarg < narg) { + + if (strcmp(arg[iarg], "lunit_nm") == 0) { + if (iarg + 2 > narg) error->all(FLERR, "Illegal fix charge regulation command"); + llength_unit_in_nm = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + iarg += 2; + } else if (strcmp(arg[iarg], "acid_type") == 0) { + if (iarg + 2 > narg) error->all(FLERR, "Illegal fix charge regulation command"); + acid_type = utils::inumeric(FLERR, arg[iarg + 1], false, lmp); + iarg += 2; + } else if (strcmp(arg[iarg], "base_type") == 0) { + if (iarg + 2 > narg) error->all(FLERR, "Illegal fix charge regulation command"); + base_type = utils::inumeric(FLERR, arg[iarg + 1], false, lmp); + iarg += 2; + } else if (strcmp(arg[iarg], "pH") == 0) { + if (iarg + 2 > narg) error->all(FLERR, "Illegal fix charge regulation command"); + pH = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + iarg += 2; + } else if (strcmp(arg[iarg], "pIp") == 0) { + if (iarg + 2 > narg) error->all(FLERR, "Illegal fix charge regulation command"); + pI_plus = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + iarg += 2; + } else if (strcmp(arg[iarg], "pIm") == 0) { + if (iarg + 2 > narg) error->all(FLERR, "Illegal fix charge regulation command"); + pI_minus = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + iarg += 2; + } else if (strcmp(arg[iarg], "pKa") == 0) { + if (iarg + 2 > narg) error->all(FLERR, "Illegal fix charge regulation command"); + pKa = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + iarg += 2; + } else if (strcmp(arg[iarg], "pKb") == 0) { + if (iarg + 2 > narg) error->all(FLERR, "Illegal fix charge regulation command"); + pKb = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + iarg += 2; + + } else if (strcmp(arg[iarg], "temp") == 0) { + if (iarg + 2 > narg) error->all(FLERR, "Illegal fix charge regulation command"); + reservoir_temperature = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + iarg += 2; + } else if (strcmp(arg[iarg], "pKs") == 0) { + if (iarg + 2 > narg) error->all(FLERR, "Illegal fix charge regulation command"); + pKs = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + iarg += 2; + } else if (strcmp(arg[iarg], "tempfixid") == 0) { + if (iarg + 2 > narg) error->all(FLERR, "Illegal fix charge regulation command"); + int n = strlen(arg[iarg + 1]) + 1; + delete[] idftemp; + idftemp = new char[n]; + strcpy(idftemp, arg[iarg + 1]); + setThermoTemperaturePointer(); + iarg += 2; + } else if (strcmp(arg[iarg], "rxd") == 0) { + if (iarg + 2 > narg) error->all(FLERR, "Illegal fix charge regulation command"); + reaction_distance = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + if ((reaction_distance > fabs(domain->boxhi[0] - domain->boxlo[0]) / 2) || + (reaction_distance > fabs(domain->boxhi[1] - domain->boxlo[1]) / 2) || + (reaction_distance > fabs(domain->boxhi[2] - domain->boxlo[2]) / 2)) { + error->warning(FLERR, + "reaction distance (rxd) is larger than half the box dimension, resetting default: xrd = 0."); + reaction_distance = 0; + } + iarg += 2; + } else if (strcmp(arg[iarg], "nevery") == 0) { + if (iarg + 2 > narg) error->all(FLERR, "Illegal fix charge regulation command"); + nevery = utils::inumeric(FLERR, arg[iarg + 1], false, lmp); + iarg += 2; + } else if (strcmp(arg[iarg], "nmc") == 0) { + if (iarg + 2 > narg) error->all(FLERR, "Illegal fix charge regulation command"); + nmc = utils::inumeric(FLERR, arg[iarg + 1], false, lmp); + iarg += 2; + } else if (strcmp(arg[iarg], "pmcmoves") == 0) { + if (iarg + 4 > narg) error->all(FLERR, "Illegal fix charge regulation command"); + pmcmoves[0] = utils::numeric(FLERR, arg[iarg + 1], false, lmp); + pmcmoves[1] = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + pmcmoves[2] = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + iarg += 4; + } else if (strcmp(arg[iarg], "seed") == 0) { + if (iarg + 2 > narg) error->all(FLERR, "Illegal fix charge regulation command"); + seed = utils::inumeric(FLERR, arg[iarg + 1], false, lmp); + iarg += 2; + } else if (strcmp(arg[iarg], "tag") == 0) { + if (iarg + 2 > narg) error->all(FLERR, "Illegal fix charge regulation command"); + if (strcmp(arg[iarg + 1], "yes") == 0) { + add_tags_flag = true; + } else if (strcmp(arg[iarg + 1], "no") == 0) { + add_tags_flag = false; + } else { error->all(FLERR, "Illegal fix charge regulation command"); } + iarg += 2; + } else if (strcmp(arg[iarg], "onlysalt") == 0) { + if (iarg + 2 > narg) error->all(FLERR, "Illegal fix charge regulation command"); + if (strcmp(arg[iarg + 1], "yes") == 0) { + only_salt_flag = true; + // need to specify salt charge + if (iarg + 4 > narg) error->all(FLERR, "Illegal fix charge regulation command"); + salt_charge[0] = utils::numeric(FLERR, arg[iarg + 2], false, lmp); + salt_charge[1] = utils::numeric(FLERR, arg[iarg + 3], false, lmp); + if (fabs(salt_charge[0] - utils::inumeric(FLERR, arg[iarg + 2], false, lmp)) > small) + error->all(FLERR, "Illegal fix charge regulation command, cation charge must be an integer"); + if (fabs(salt_charge[1] - utils::inumeric(FLERR, arg[iarg + 3], false, lmp)) > small) + error->all(FLERR, "Illegal fix charge regulation command, anion charge must be an integer"); + iarg += 4; + } else if (strcmp(arg[iarg + 1], "no") == 0) { + only_salt_flag = false; + iarg += 2; + } else { error->all(FLERR, "Illegal fix charge regulation command"); } + + } else if (strcmp(arg[iarg], "group") == 0) { + if (iarg + 2 > narg) error->all(FLERR, "Illegal fix fix charge regulation command"); + if (ngroups >= ngroupsmax) { + ngroupsmax = ngroups + 1; + groupstrings = (char **) + memory->srealloc(groupstrings, + ngroupsmax * sizeof(char *), + "fix_charge_regulation:groupstrings"); + } + int n = strlen(arg[iarg + 1]) + 1; + groupstrings[ngroups] = new char[n]; + strcpy(groupstrings[ngroups], arg[iarg + 1]); + ngroups++; + iarg += 2; + } else { error->all(FLERR, "Illegal fix charge regulation command"); } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based arrays +------------------------------------------------------------------------- */ + +double Fix_charge_regulation::memory_usage() { + double bytes = cr_nmax * sizeof(int); + return bytes; +} diff --git a/src/USER-MISC/fix_charge_regulation.h b/src/USER-MISC/fix_charge_regulation.h new file mode 100644 index 0000000000..280a6c0d49 --- /dev/null +++ b/src/USER-MISC/fix_charge_regulation.h @@ -0,0 +1,117 @@ +/* -*- 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. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Tine Curk (curk@northwestern.edu) and Jiaxing Yuan (yuanjiaxing123@hotmail.com) +------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS + +FixStyle(charge_regulation,Fix_charge_regulation) + +#else + +#ifndef LMP_FIX_charge_regulation_H +#define LMP_FIX_charge_regulation_H + +#include "fix.h" + +namespace LAMMPS_NS { + + class Fix_charge_regulation : public Fix { + public: + Fix_charge_regulation(class LAMMPS *, int, char **); + ~Fix_charge_regulation(); + int setmask(); + void init(); + void pre_exchange(); + void forward_acid(); + void backward_acid(); + void forward_base(); + void backward_base(); + void forward_ions(); + void forward_ions_multival(); + void backward_ions(); + void backward_ions_multival(); + int get_random_particle(int, double, double, double *); + int insert_particle(int, double, double, double *); + double energy_full(); + int particle_number(int, double); + int particle_number_xrd(int, double, double, double *); + double compute_vector(int n); + void assign_tags(); + void options(int, char **); + void setThermoTemperaturePointer(); + double memory_usage(); + + private: + int exclusion_group, exclusion_group_bit; + int ngcmc_type, nevery, seed; + int nmc; // mc moves per cycle + double llength_unit_in_nm ; // LAMMPS unit of length in nm, needed since chemical potentials are in units of mol/l + double pH, pKa, pKb, pKs, pI_plus, pI_minus; // chemical potentials + double pmcmoves[3]; // mc move attempt probability, acid, base, salt; and comulative + double pmcc; // mc move cumulative attempt probability + int npart_xrd; // # of particles (ions) within xrd + int npart_xrd2; // # of particles (ions) within xrd + double vlocal_xrd; // # local volume within xrd + bool only_salt_flag; // true if performing only salt insertion/deletion, no acid/base dissociation. + bool add_tags_flag; // true if each inserted atom gets its unique atom tag + int groupbitall; // group bitmask for inserted atoms + int ngroups; // number of group-ids for inserted atoms + char **groupstrings; // list of group-ids for inserted atoms + // counters + unsigned long int nacid_attempts, nacid_successes, nbase_attempts, nbase_successes, nsalt_attempts, nsalt_successes; + int nacid_neutral, nacid_charged, nbase_neutral, nbase_charged, ncation, nanion; // particle type counts + int cr_nmax; // max number of local particles + double reservoir_temperature; + double beta, sigma, volume, volume_rx; // inverse temperature, speed, total volume, reacting volume + int salt_charge[2]; // charge of salt ions: [0] - cation, [1] - anion + int salt_charge_ratio; + double xlo, xhi, ylo, yhi, zlo, zhi; // box size + double energy_stored; // full energy of old/current configuration + int triclinic; // 0 = orthog box, 1 = triclinic + double *sublo, *subhi; // triclinic size + int *ptype_ID; // particle ID array + double overlap_cutoffsq; // square distance cutoff for overlap + int overlap_flag; + int acid_type, cation_type, base_type, anion_type; // reacting atom types + int reaction_distance_flag; + double reaction_distance; // max radial distance for atom insertion + + + class Pair *pair; + class Compute *c_pe; // energy compute pointer + class RanPark *random_equal; // random number generator + class RanPark *random_unequal; // random number generator + char *idftemp; // pointer to the temperature fix + + double *target_temperature_tcp; // current temperature of the thermostat + + }; +} + +#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. + +Self-explanatory. + +*/