ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
ibm_triel.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2022 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
21
22#include "BoxGeometry.hpp"
23#include "ibm_common.hpp"
24#include "system/System.hpp"
25
26#include <utils/Vector.hpp>
27#include <utils/math/sqr.hpp>
28
29#include <boost/optional.hpp>
30
31#include <tuple>
32
33namespace {
34/** Rotate calculated trielastic forces in the 2d plane back to the 3d plane.
35 * Use knowledge that the x-axis in rotated system is parallel to r(p1->p2) in
36 * original system; To find the corresponding unit vector to y in the rotated
37 * system, construct vector perpendicular to r(p1->p2); note that f3 is not
38 * calculated here but is implicitly calculated by f3 = -(f1+f2) which is
39 * consistent with the literature
40 * @return forces on particles 1, 2, 3
41 */
42std::tuple<Utils::Vector3d, Utils::Vector3d, Utils::Vector3d>
43RotateForces(Utils::Vector2d const &f1_rot, Utils::Vector2d const &f2_rot,
44 Utils::Vector3d const &v12, Utils::Vector3d const &v13) {
45 // fRot is in the rotated system, i.e. in a system where the side lPrime of
46 // the triangle (i.e. v12) is parallel to the x-axis, and the y-axis is
47 // perpendicular to the x-axis (cf. Krueger, Fig. 7.1c).
48 // I.e. fRot[XX] is the component parallel to the x-axis, fRot[YY]] the
49 // component parallel to the y-axis. Now, the idea is to get these unit
50 // vectors for the x- and y-axis in the real coordinate system. They are named
51 // xu and yu below. The x-component of the force in the real coordinate system
52 // is therefore: fRot[XX]*xu
53
54 // xu is simple: The x-axis in the rotated system is parallel to v12 --> xu =
55 // v12 (+ normalization)
56 auto const xu = Utils::Vector3d(v12).normalize();
57
58 // yu needs to be orthogonal to xu, and point in the direction of node 3 in
59 // Krueger, Fig. 7.1b. Therefore: First get the projection of v13 onto v12:
60 // The direction is defined by xu, the length by the scalar product (scalar
61 // product can be interpreted as a projection, after all). --> sca * xu Then:
62 // v13 - sca * xu gives the component of v13 orthogonal to v12, i.e.
63 // perpendicular to the x-axis --> yu Last: Normalize yu.
64 auto const yu = (v13 - (v13 * xu) * xu).normalize();
65
66 // Calculate forces in 3D
67 auto const force1 = f1_rot[0] * xu + f1_rot[1] * yu;
68 auto const force2 = f2_rot[0] * xu + f2_rot[1] * yu;
69 auto const force3 = -(force1 + force2);
70 return std::make_tuple(force1, force2, force3);
71}
72} // namespace
73
74boost::optional<std::tuple<Utils::Vector3d, Utils::Vector3d, Utils::Vector3d>>
76 Utils::Vector3d const &vec2) const {
77
78 // Calculate the current shape of the triangle (l,lp,cos(phi),sin(phi));
79 // l = length between 1 and 3
80 // get_mi_vector is an ESPResSo function which considers PBC
81 auto const l = vec2.norm();
82
83 // lp = length between 1 and 2
84 auto const lp = vec1.norm();
85
86 // Check for sanity
87 if ((lp - lp0 > maxDist) || (l - l0 > maxDist)) {
88 return {};
89 }
90
91 // angles between these vectors; calculated directly via the products
92 auto const cosPhi = (vec1 * vec2) / (lp * l);
93 auto const vecpro = Utils::vector_product(vec1, vec2);
94 auto const sinPhi = vecpro.norm() / (l * lp);
95
96 // Displacement gradient tensor D: eq. (C.9) in @cite kruger12a
97 const double Dxx = lp / lp0;
98 const double Dxy = ((l / l0 * cosPhi) - (lp / lp0 * cosPhi0)) / sinPhi0;
99 const double Dyx = 0.0;
100 const double Dyy = l / l0 * sinPhi / sinPhi0;
101
102 // Tensor G: eq. (C.12)
103 const double Gxx = Utils::sqr(Dxx) + Utils::sqr(Dyx);
104 const double Gxy = Dxx * Dxy + Dyx * Dyy;
105 const double Gyx = Dxx * Dxy + Dyy * Dyx; // = Gxy because of symmetry
106 const double Gyy = Utils::sqr(Dxy) + Utils::sqr(Dyy);
107
108 // Strain invariants: eq. (C.11) and (C.12)
109 const double i1 = (Gxx + Gyy) - 2;
110 const double i2 = ((Gxx * Gyy) - (Gxy * Gyx)) - 1;
111
112 // Derivatives of energy density E used in chain rule below: eq. (C.14)
113 double dEdI1;
114 double dEdI2;
116 // Neo-Hookean
117 dEdI1 = k1 / 6.0;
118 dEdI2 = -k1 / (6.0 * (i2 + 1.0) * (i2 + 1.0));
119 } else {
120 // Skalak
121 dEdI1 = k1 * (i1 + 1) / 6.0;
122 dEdI2 = -k1 / 6.0 + k2 * i2 / 6.0;
123 }
124
125 // Derivatives of Is: eq. (C.15)
126 const double dI1dGxx = 1;
127 const double dI1dGxy = 0;
128 const double dI1dGyx = 0;
129 const double dI1dGyy = 1;
130
131 const double dI2dGxx = Gyy;
132 const double dI2dGxy = -Gyx; // Note: Krueger has a factor 2 here, because he
133 // uses the symmetry of the G-matrix.
134 const double dI2dGyx = -Gxy; // But we don't use it. So, Krueger is missing
135 // the yx term, whereas we have it.
136 const double dI2dGyy = Gxx;
137
138 // Derivatives of G: eq. (C.16)
139 const double dGxxdV1x = 2 * a1 * Dxx;
140 const double dGxxdV1y = 0;
141 const double dGxxdV2x = 2 * a2 * Dxx;
142 const double dGxxdV2y = 0;
143
144 const double dGxydV1x = a1 * Dxy + b1 * Dxx;
145 const double dGxydV1y = a1 * Dyy;
146 const double dGxydV2x = a2 * Dxy + b2 * Dxx;
147 const double dGxydV2y = a2 * Dyy;
148
149 const double dGyxdV1x = a1 * Dxy + b1 * Dxx;
150 const double dGyxdV1y = a1 * Dyy;
151 const double dGyxdV2x = a2 * Dxy + b2 * Dxx;
152 const double dGyxdV2y = a2 * Dyy;
153
154 const double dGyydV1x = 2 * b1 * Dxy;
155 const double dGyydV1y = 2 * b1 * Dyy;
156 const double dGyydV2x = 2 * b2 * Dxy;
157 const double dGyydV2y = 2 * b2 * Dyy;
158
159 // Calculate forces per area in rotated system: chain rule as in appendix C of
160 // Krüger (chain rule applied in eq. (C.13), but for the energy density). Only
161 // two nodes are needed, third one is calculated from momentum conservation
162 // Note: If you calculate the derivatives in a straightforward manner, you get
163 // 8 terms (done here). Krueger exploits the symmetry of the G-matrix, which
164 // results in 6 elements, but with an additional factor 2 for the xy-elements
165 // (see also above at the definition of dI2dGxy).
166 Utils::Vector2d f1_rot{};
167 Utils::Vector2d f2_rot{};
168 f1_rot[0] = -(dEdI1 * dI1dGxx * dGxxdV1x) - (dEdI1 * dI1dGxy * dGxydV1x) -
169 (dEdI1 * dI1dGyx * dGyxdV1x) - (dEdI1 * dI1dGyy * dGyydV1x) -
170 (dEdI2 * dI2dGxx * dGxxdV1x) - (dEdI2 * dI2dGxy * dGxydV1x) -
171 (dEdI2 * dI2dGyx * dGyxdV1x) - (dEdI2 * dI2dGyy * dGyydV1x);
172 f1_rot[1] = -(dEdI1 * dI1dGxx * dGxxdV1y) - (dEdI1 * dI1dGxy * dGxydV1y) -
173 (dEdI1 * dI1dGyx * dGyxdV1y) - (dEdI1 * dI1dGyy * dGyydV1y) -
174 (dEdI2 * dI2dGxx * dGxxdV1y) - (dEdI2 * dI2dGxy * dGxydV1y) -
175 (dEdI2 * dI2dGyx * dGyxdV1y) - (dEdI2 * dI2dGyy * dGyydV1y);
176 f2_rot[0] = -(dEdI1 * dI1dGxx * dGxxdV2x) - (dEdI1 * dI1dGxy * dGxydV2x) -
177 (dEdI1 * dI1dGyx * dGyxdV2x) - (dEdI1 * dI1dGyy * dGyydV2x) -
178 (dEdI2 * dI2dGxx * dGxxdV2x) - (dEdI2 * dI2dGxy * dGxydV2x) -
179 (dEdI2 * dI2dGyx * dGyxdV2x) - (dEdI2 * dI2dGyy * dGyydV2x);
180 f2_rot[1] = -(dEdI1 * dI1dGxx * dGxxdV2y) - (dEdI1 * dI1dGxy * dGxydV2y) -
181 (dEdI1 * dI1dGyx * dGyxdV2y) - (dEdI1 * dI1dGyy * dGyydV2y) -
182 (dEdI2 * dI2dGxx * dGxxdV2y) - (dEdI2 * dI2dGxy * dGxydV2y) -
183 (dEdI2 * dI2dGyx * dGyxdV2y) - (dEdI2 * dI2dGyy * dGyydV2y);
184
185 // Multiply by undeformed area
186 f1_rot *= area0;
187 f2_rot *= area0;
188
189 // Rotate forces back into original position of triangle
190 auto forces = RotateForces(f1_rot, f2_rot, vec1, vec2);
191
192 return {forces};
193}
194
195IBMTriel::IBMTriel(const int ind1, const int ind2, const int ind3,
196 const double maxDist, const tElasticLaw elasticLaw,
197 const double k1, const double k2) {
198
199 auto const &box_geo = *System::get_system().box_geo;
200
201 // collect particles from nodes
202 auto const pos1 = get_ibm_particle_position(ind1);
203 auto const pos2 = get_ibm_particle_position(ind2);
204 auto const pos3 = get_ibm_particle_position(ind3);
205
206 // Calculate equilibrium lengths and angle; Note the sequence of the points!
207 // l0 = length between 1 and 3
208 auto const temp_l0 = box_geo.get_mi_vector(pos3, pos1);
209 l0 = temp_l0.norm();
210 // lp0 = length between 1 and 2
211 auto const temp_lp0 = box_geo.get_mi_vector(pos2, pos1);
212 lp0 = temp_lp0.norm();
213
214 // cospo / sinpo angle functions between these vectors; calculated directly
215 // via the products
216 cosPhi0 = (temp_l0 * temp_lp0) / (l0 * lp0);
217 auto const vecpro = Utils::vector_product(temp_l0, temp_lp0);
218 sinPhi0 = vecpro.norm() / (l0 * lp0);
219
220 // Use the values determined above for further constants of the stretch-force
221 // calculation
222 const double area2 = l0 * lp0 * sinPhi0;
223 a1 = -(l0 * sinPhi0) / area2;
224 a2 = -a1;
225 b1 = (l0 * cosPhi0 - lp0) / area2;
226 b2 = -(l0 * cosPhi0) / area2;
227 area0 = 0.5 * area2;
228 this->maxDist = maxDist;
229 this->elasticLaw = elasticLaw;
230 // Always store two constants, for NeoHookean only k1 is used
231 this->k1 = k1;
232 this->k2 = k2;
233}
Vector implementation and trait types for boost qvm interoperability.
std::shared_ptr< BoxGeometry > box_geo
T norm() const
Definition Vector.hpp:131
Utils::Vector3d get_ibm_particle_position(int pid)
Returns the position of a given particle.
tElasticLaw
Definition ibm_triel.hpp:31
System & get_system()
VectorXd< 3 > Vector3d
Definition Vector.hpp:157
Vector< T, 3 > vector_product(Vector< T, 3 > const &a, Vector< T, 3 > const &b)
Definition Vector.hpp:353
DEVICE_QUALIFIER constexpr T sqr(T x)
Calculates the SQuaRe of x.
Definition sqr.hpp:26
std::tuple< Utils::Vector3d, Utils::Vector3d, Utils::Vector3d > RotateForces(Utils::Vector2d const &f1_rot, Utils::Vector2d const &f2_rot, Utils::Vector3d const &v12, Utils::Vector3d const &v13)
Rotate calculated trielastic forces in the 2d plane back to the 3d plane.
Definition ibm_triel.cpp:43
double cosPhi0
Definition ibm_triel.hpp:39
boost::optional< std::tuple< Utils::Vector3d, Utils::Vector3d, Utils::Vector3d > > calc_forces(Utils::Vector3d const &vec1, Utils::Vector3d const &vec2) const
Calculate the forces.
Definition ibm_triel.cpp:75
double lp0
Definition ibm_triel.hpp:37
double k1
Definition ibm_triel.hpp:53
double b2
Definition ibm_triel.hpp:46
double l0
Definition ibm_triel.hpp:36
tElasticLaw elasticLaw
Definition ibm_triel.hpp:52
double maxDist
Definition ibm_triel.hpp:51
double b1
Definition ibm_triel.hpp:45
double a1
Definition ibm_triel.hpp:43
double a2
Definition ibm_triel.hpp:44
double sinPhi0
Definition ibm_triel.hpp:38
IBMTriel(int ind1, int ind2, int ind3, double maxDist, tElasticLaw elasticLaw, double k1, double k2)
Set the IBM Triel parameters.
double area0
Definition ibm_triel.hpp:40
double k2
Definition ibm_triel.hpp:54