ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
polymer.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2022 The ESPResSo project
3 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010
4 * Max-Planck-Institute for Polymer Research, Theory Group
5 *
6 * This file is part of ESPResSo.
7 *
8 * ESPResSo is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * ESPResSo is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21/** \file
22 * This file contains everything needed to create a start-up configuration
23 * of (possibly charged) polymer chains with counterions and salt molecules,
24 * assigning velocities to the particles and cross-linking the polymers if
25 * necessary.
26 *
27 * The corresponding header file is polymer.hpp.
28 */
29
30#include "polymer.hpp"
31
32#include "BoxGeometry.hpp"
34#include "communication.hpp"
35#include "constraints.hpp"
36#include "constraints/Constraints.hpp"
37#include "constraints/ShapeBasedConstraint.hpp"
38#include "random.hpp"
39#include "system/System.hpp"
40
41#include <utils/Vector.hpp>
42#include <utils/constants.hpp>
44
45#include <boost/mpi/collectives/all_reduce.hpp>
46#include <boost/optional.hpp>
47
48#include <cmath>
49#include <cstddef>
50#include <functional>
51#include <memory>
52#include <stdexcept>
53#include <vector>
54
55template <class RNG>
56static Utils::Vector3d random_position(BoxGeometry const &box_geo, RNG &rng) {
58 for (int i = 0; i < 3; ++i)
59 v[i] = box_geo.length()[i] * rng();
60 return v;
61}
62
63template <class RNG> static Utils::Vector3d random_unit_vector(RNG &rng) {
65 double const phi = acos(1. - 2. * rng());
66 double const theta = 2. * Utils::pi() * rng();
67 v[0] = sin(phi) * cos(theta);
68 v[1] = sin(phi) * sin(theta);
69 v[2] = cos(phi);
70 v /= v.norm();
71 return v;
72}
73
74/** Determines whether a given position @p pos is valid, i.e., it doesn't
75 * collide with existing or buffered particles, nor with existing constraints
76 * (if @c respect_constraints).
77 * @param pos the trial position in question
78 * @param positions buffered positions to respect
79 * @param cell_structure existing particles to respect
80 * @param box_geo Box geometry
81 * @param min_distance threshold for the minimum distance between
82 * trial position and buffered/existing particles
83 * @param respect_constraints whether to respect constraints
84 * @return true if valid position, false if not.
85 */
86static bool
88 std::vector<std::vector<Utils::Vector3d>> const &positions,
89 CellStructure const &cell_structure,
90 BoxGeometry const &box_geo, double const min_distance,
91 int const respect_constraints) {
92
93 struct reduce_min {
94 auto operator()(double const a, double const b) const {
95 return std::min(a, b);
96 }
97 };
98
99 // check if constraint is violated
100 if (respect_constraints) {
101 Utils::Vector3d const folded_pos = box_geo.folded_position(pos);
102
103 for (auto &c : Constraints::constraints) {
104 auto cs =
105 std::dynamic_pointer_cast<const Constraints::ShapeBasedConstraint>(c);
106 if (cs) {
107 double d;
109
110 cs->calc_dist(folded_pos, d, v);
111
112 if (d <= 0) {
113 return false;
114 }
115 }
116 }
117 }
118
119 if (min_distance > 0.) {
120 // check for collision with existing particles
121 auto local_mindist_sq = std::numeric_limits<double>::infinity();
122 for (auto const &p : cell_structure.local_particles()) {
123 auto const d = box_geo.get_mi_vector(pos, p.pos());
124 local_mindist_sq = std::min(local_mindist_sq, d.norm2());
125 }
126 auto const global_mindist_sq =
127 boost::mpi::all_reduce(::comm_cart, local_mindist_sq, reduce_min{});
128 if (std::sqrt(global_mindist_sq) < min_distance) {
129 return false;
130 }
131
132 auto const min_distance_sq = min_distance * min_distance;
133 for (auto const &p : positions) {
134 for (auto const &m : p) {
135 if (box_geo.get_mi_vector(pos, m).norm2() < min_distance_sq) {
136 return false;
137 }
138 }
139 }
140 }
141 return true;
142}
143
144std::vector<std::vector<Utils::Vector3d>>
145draw_polymer_positions(System::System const &system, int const n_polymers,
146 int const beads_per_chain, double const bond_length,
147 std::vector<Utils::Vector3d> const &start_positions,
148 double const min_distance, int const max_tries,
149 int const use_bond_angle, double const bond_angle,
150 int const respect_constraints, int const seed) {
151
152 auto const &box_geo = *system.box_geo;
153 auto rng = [mt = Random::mt19937(static_cast<unsigned>(seed)),
154 dist = std::uniform_real_distribution<double>(
155 0.0, 1.0)]() mutable { return dist(mt); };
156
157 std::vector<std::vector<Utils::Vector3d>> positions(n_polymers);
158 for (auto &p : positions) {
159 p.reserve(beads_per_chain);
160 }
161
162 auto is_valid_pos = [&](Utils::Vector3d const &pos) {
163 return is_valid_position(pos, positions, *system.cell_structure, box_geo,
164 min_distance, respect_constraints);
165 };
166
167 for (std::size_t p = 0; p < start_positions.size(); p++) {
168 if (is_valid_pos(start_positions[p])) {
169 positions[p].push_back(start_positions[p]);
170 } else {
171 throw std::runtime_error("Invalid start positions.");
172 }
173 }
174
175 /* Draw a monomer position, obeying angle and starting position
176 * constraints where appropriate. */
177 auto draw_monomer_position = [&](int p, int m) {
178 if (m == 0) {
179 return (p < start_positions.size()) ? start_positions[p]
180 : random_position(box_geo, rng);
181 }
182
183 if (not use_bond_angle or m < 2) {
184 return positions[p][m - 1] + bond_length * random_unit_vector(rng);
185 }
186
187 auto const last_vec = positions[p][m - 1] - positions[p][m - 2];
188 return positions[p][m - 1] +
190 bond_angle, -last_vec);
191 };
192
193 /* Try up to max_tries times to draw a valid position */
194 auto draw_valid_monomer_position =
195 [&](int p, int m) -> boost::optional<Utils::Vector3d> {
196 for (auto i = 0; i < max_tries; i++) {
197 auto const trial_pos = draw_monomer_position(p, m);
198 if (is_valid_pos(trial_pos)) {
199 return trial_pos;
200 }
201 }
202
203 return {};
204 };
205
206 // create remaining monomers' positions by backtracking.
207 for (int p = 0; p < n_polymers; ++p) {
208 for (int attempts_poly = 0; attempts_poly < max_tries; attempts_poly++) {
209 int rejections = 0;
210 while (positions[p].size() < beads_per_chain) {
211 auto pos = draw_valid_monomer_position(
212 p, static_cast<int>(positions[p].size()));
213
214 if (pos) {
215 /* Move on one position */
216 positions[p].push_back(*pos);
217 } else if (not positions[p].empty()) {
218 /* Go back one position and try again */
219 positions[p].pop_back();
220 rejections++;
221 if (rejections > max_tries) {
222 /* Give up for this try. */
223 break;
224 }
225 } else {
226 /* Give up for this try. */
227 break;
228 }
229 }
230
231 /* If the polymer has not full length, we try again. Otherwise we can
232 * move on to the next polymer. */
233 if (positions[p].size() == beads_per_chain) {
234 break;
235 }
236 }
237
238 /* We did not get a complete polymer, but have exceeded the maximal
239 * number of tries, which means failure. */
240 if (positions[p].size() < beads_per_chain)
241 throw std::runtime_error("Failed to create polymer positions.");
242 }
243 return positions;
244}
Vector implementation and trait types for boost qvm interoperability.
__shared__ int pos[MAXDEPTH *THREADS5/WARPSIZE]
Utils::Vector3d const & length() const
Box length.
auto folded_position(Utils::Vector3d const &p) const
Calculate coordinates folded to primary simulation box.
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.
Main system class.
std::shared_ptr< CellStructure > cell_structure
std::shared_ptr< BoxGeometry > box_geo
T norm() const
Definition Vector.hpp:131
boost::mpi::communicator comm_cart
The communicator.
__device__ void vector_product(float const *a, float const *b, float *out)
Constraints< ParticleRange, Constraint > constraints
std::mt19937 mt19937(T &&seed)
Mersenne Twister with warmup.
Definition random.hpp:195
DEVICE_QUALIFIER constexpr T pi()
Ratio of diameter and circumference of a circle.
Definition constants.hpp:36
Vector3d vec_rotate(const Vector3d &axis, double angle, const Vector3d &vector)
Rotate a vector around an axis.
static Utils::Vector3d random_position(BoxGeometry const &box_geo, RNG &rng)
Definition polymer.cpp:56
static Utils::Vector3d random_unit_vector(RNG &rng)
Definition polymer.cpp:63
std::vector< std::vector< Utils::Vector3d > > draw_polymer_positions(System::System const &system, int const n_polymers, int const beads_per_chain, double const bond_length, std::vector< Utils::Vector3d > const &start_positions, double const min_distance, int const max_tries, int const use_bond_angle, double const bond_angle, int const respect_constraints, int const seed)
Determines valid polymer positions and returns them.
Definition polymer.cpp:145
static bool is_valid_position(Utils::Vector3d const &pos, std::vector< std::vector< Utils::Vector3d > > const &positions, CellStructure const &cell_structure, BoxGeometry const &box_geo, double const min_distance, int const respect_constraints)
Determines whether a given position pos is valid, i.e., it doesn't collide with existing or buffered ...
Definition polymer.cpp:87
This file contains everything needed to create a start-up configuration of polymer chains which may r...
Random number generation using Philox.
Describes a cell structure / cell system.
ParticleRange local_particles() const