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