MRMD 0.4.0
Multi Resolution Molecular Dynamics
Loading...
Searching...
No Matches
ThermodynamicForce.hpp
Go to the documentation of this file.
1// Copyright 2024 Sebastian Eibl
2// Copyright 2026 Julian Friedrich Hille
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// https://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#pragma once
17
18#include <concepts>
19
20#include "assert/assert.hpp"
21#include "data/Atoms.hpp"
23#include "data/Subdomain.hpp"
24#include "datatypes.hpp"
27
28namespace mrmd
29{
30namespace action
31{
33{
34private:
36 data::MultiHistogram densityProfile_;
37 idx_t densityProfileSamples_ = 0;
38 real_t binVolume_;
39 const std::vector<real_t> targetDensity_;
40 const std::vector<real_t> thermodynamicForceModulation_;
41 idx_t numTypes_;
42
43 ScalarView forceFactor_;
44 bool enforceSymmetry_ = false;
45 bool usePeriodicity_ = false;
46
47public:
48 inline auto getForce() const { return force_; }
49 inline auto getForce(const idx_t& typeId) const
50 {
51 assert(typeId < numTypes_);
52 assert(typeId >= 0);
53 return Kokkos::subview(force_.data, Kokkos::ALL(), typeId);
54 }
55 inline void setForce(const MultiView& forces) const { Kokkos::deep_copy(force_.data, forces); }
56 inline auto getDensityProfile() const { return densityProfile_; }
57 inline auto getDensityProfile(const idx_t& typeId) const
58 {
59 assert(typeId < numTypes_);
60 assert(typeId >= 0);
61 return Kokkos::subview(densityProfile_.data, Kokkos::ALL(), typeId);
62 }
63 inline const auto& getNumberOfDensityProfileSamples() const { return densityProfileSamples_; }
64
65 void sample(data::Atoms& atoms);
66 void update(const real_t& smoothingSigma, const real_t& smoothingIntensity);
67 void apply(const data::Atoms& atoms) const;
68
69 template <OnePositionPredicate Pred>
70 void apply_if(const data::Atoms& atoms, const Pred& pred) const;
71
72 template <OneCoordinatePredicate Pred>
73 void update_if(const real_t& smoothingSigma,
74 const real_t& smoothingIntensity,
75 const Pred& pred);
76
77 template <OnePositionPredicate Pred>
78 void applyInterpolated_if(const data::Atoms& atoms, const Pred& pred) const;
79
80 std::vector<real_t> getMuLeft() const;
81 std::vector<real_t> getMuRight() const;
82
83 ThermodynamicForce(const std::vector<real_t>& targetDensity,
84 const data::Subdomain& subdomain,
85 const real_t& requestedDensityBinWidth,
86 const std::vector<real_t>& thermodynamicForceModulation,
87 const bool enforceSymmetry = false,
88 const bool usePeriodicity = false);
89
90 ThermodynamicForce(const real_t targetDensity,
91 const data::Subdomain& subdomain,
92 const real_t& requestedDensityBinWidth,
93 const real_t thermodynamicForceModulation,
94 const bool enforceSymmetry = false,
95 const bool usePeriodicity = false);
96};
97
98template <OnePositionPredicate Pred>
99void ThermodynamicForce::apply_if(const data::Atoms& atoms, const Pred& pred) const
100{
101 auto atomsPos = atoms.getPos();
102 auto atomsForce = atoms.getForce();
103 auto atomsType = atoms.getType();
104
105 auto forceHistogram = force_; // avoid capturing this pointer
106
107 auto policy = Kokkos::RangePolicy<>(0, atoms.numLocalAtoms);
108 auto kernel = KOKKOS_LAMBDA(const idx_t idx)
109 {
110 auto xPos = atomsPos(idx, 0);
111 if (!pred(atomsPos(idx, 0), atomsPos(idx, 1), atomsPos(idx, 2))) return;
112 auto bin = forceHistogram.getBin(xPos);
113 if (bin != -1)
114 {
115 MRMD_DEVICE_ASSERT_LESS(atomsType(idx), forceHistogram.numHistograms);
116 MRMD_DEVICE_ASSERT(!std::isnan(forceHistogram.data(bin, atomsType(idx))));
117 atomsForce(idx, 0) += forceHistogram.data(bin, atomsType(idx));
118 }
119 };
120 Kokkos::parallel_for("ThermodynamicForce::apply_if", policy, kernel);
121 Kokkos::fence();
122}
123
124template <OneCoordinatePredicate Pred>
125void ThermodynamicForce::update_if(const real_t& smoothingSigma,
126 const real_t& smoothingIntensity,
127 const Pred& pred)
128{
129 MRMD_HOST_CHECK_GREATER(densityProfileSamples_, 0);
130
131 if (enforceSymmetry_)
132 {
133 densityProfile_.makeSymmetric();
134 }
135
136 auto normalizationFactor = 1_r / (binVolume_ * real_c(densityProfileSamples_));
137 densityProfile_.scale(normalizationFactor);
138
139 auto smoothedDensityProfile =
140 data::smoothen(densityProfile_, smoothingSigma, smoothingIntensity, usePeriodicity_);
141 auto smoothedDensityGradient = data::gradient(smoothedDensityProfile, usePeriodicity_);
142 smoothedDensityGradient.scale(forceFactor_);
143
145 smoothedDensityGradient, KOKKOS_LAMBDA(const real_t x) { return !pred(x); }, 0_r);
146
147 force_ -= smoothedDensityGradient;
148
149 // reset sampling data
150 Kokkos::deep_copy(densityProfile_.data, 0_r);
151 densityProfileSamples_ = 0;
152}
153
154template <OnePositionPredicate Pred>
155void ThermodynamicForce::applyInterpolated_if(const data::Atoms& atoms, const Pred& pred) const
156{
157 auto atomsPos = atoms.getPos();
158 auto atomsForce = atoms.getForce();
159 auto atomsType = atoms.getType();
160
161 auto forceHistogram = force_; // avoid capturing this pointer
162
163 auto policy = Kokkos::RangePolicy<>(0, atoms.numLocalAtoms);
164 auto kernel = KOKKOS_LAMBDA(const idx_t idx)
165 {
166 auto xPos = atomsPos(idx, 0);
167 if (!pred(atomsPos(idx, 0), atomsPos(idx, 1), atomsPos(idx, 2))) return;
168 auto bin = forceHistogram.getBin(xPos);
169
170 if (bin != -1)
171 {
172 auto atomType = atomsType(idx);
173 MRMD_DEVICE_ASSERT_LESS(atomType, forceHistogram.numHistograms);
174
175 // centered interpolation: switch neighboring bins at the bin center
176 auto binStart = forceHistogram.min + real_c(bin) * forceHistogram.binSize;
177 auto fracInBin = (xPos - binStart) * forceHistogram.inverseBinSize;
178
179 idx_t leftBinIdx;
180 idx_t rightBinIdx;
181 real_t factor;
182
183 if (fracInBin < 0.5_r)
184 {
185 leftBinIdx = bin - 1;
186 rightBinIdx = bin;
187 factor = fracInBin + 0.5_r;
188 }
189 else
190 {
191 leftBinIdx = bin;
192 rightBinIdx = bin + 1;
193 factor = fracInBin - 0.5_r;
194 }
195
196 // interpolate if both neighbors are valid, otherwise clamp to the current bin
197 if (leftBinIdx >= 0 && rightBinIdx < forceHistogram.numBins)
198 {
199 auto inputLeft = forceHistogram.data(leftBinIdx, atomType);
200 auto inputRight = forceHistogram.data(rightBinIdx, atomType);
201 MRMD_DEVICE_ASSERT(!std::isnan(inputLeft));
202 MRMD_DEVICE_ASSERT(!std::isnan(inputRight));
203
204 atomsForce(idx, 0) += util::lerp(inputLeft, inputRight, factor);
205 }
206 else
207 {
208 auto input = forceHistogram.data(bin, atomType);
209 MRMD_DEVICE_ASSERT(!std::isnan(input));
210 atomsForce(idx, 0) += input;
211 }
212 }
213 };
214 Kokkos::parallel_for("ThermodynamicForce::applyInterpolated_if", policy, kernel);
215 Kokkos::fence();
216}
217
218} // namespace action
219} // namespace mrmd
Definition ThermodynamicForce.hpp:33
auto getDensityProfile(const idx_t &typeId) const
Definition ThermodynamicForce.hpp:57
void apply(const data::Atoms &atoms) const
Definition ThermodynamicForce.cpp:93
void update_if(const real_t &smoothingSigma, const real_t &smoothingIntensity, const Pred &pred)
Definition ThermodynamicForce.hpp:125
std::vector< real_t > getMuLeft() const
Definition ThermodynamicForce.cpp:98
void applyInterpolated_if(const data::Atoms &atoms, const Pred &pred) const
Definition ThermodynamicForce.hpp:155
auto getForce(const idx_t &typeId) const
Definition ThermodynamicForce.hpp:49
void sample(data::Atoms &atoms)
Definition ThermodynamicForce.cpp:74
auto getForce() const
Definition ThermodynamicForce.hpp:48
void setForce(const MultiView &forces) const
Definition ThermodynamicForce.hpp:55
std::vector< real_t > getMuRight() const
Definition ThermodynamicForce.cpp:115
const auto & getNumberOfDensityProfileSamples() const
Definition ThermodynamicForce.hpp:63
void update(const real_t &smoothingSigma, const real_t &smoothingIntensity)
Definition ThermodynamicForce.cpp:88
auto getDensityProfile() const
Definition ThermodynamicForce.hpp:56
void apply_if(const data::Atoms &atoms, const Pred &pred) const
Definition ThermodynamicForce.hpp:99
Data structure for storing information about atoms on the host and the device.
Definition Atoms.hpp:35
idx_t numLocalAtoms
Definition Atoms.hpp:120
KOKKOS_FORCEINLINE_FUNCTION pos_t getPos() const
Definition Atoms.hpp:64
KOKKOS_FORCEINLINE_FUNCTION force_t getForce() const
Definition Atoms.hpp:66
KOKKOS_FORCEINLINE_FUNCTION type_t getType() const
Definition Atoms.hpp:67
#define MRMD_DEVICE_ASSERT_LESS(...)
Definition device.hpp:472
#define MRMD_DEVICE_ASSERT(...)
Definition device.hpp:465
#define MRMD_HOST_CHECK_GREATER(...)
Definition host.hpp:116
data::MultiHistogram smoothen(data::MultiHistogram &input, const real_t &sigma, const real_t &range, const bool periodic)
Smoothen a histogram using gaussian convolution.
Definition MultiHistogram.cpp:163
data::Histogram gradient(const data::Histogram &input)
Definition Histogram.cpp:37
void replace_if_bin_position(MultiHistogram &hist, const Pred &pred, real_t newValue)
Replaces histogram values with a new value if the bin position satisfies a predicate.
Definition MultiHistogram.hpp:181
KOKKOS_INLINE_FUNCTION real_t lerp(const real_t &left, const real_t &right, const real_t &factor)
Linear interpolation between two values.
Definition interpolation.hpp:35
Definition BerendsenBarostat.cpp:18
Kokkos::View< real_t * > ScalarView
Definition datatypes.hpp:159
Kokkos::View< real_t ** > MultiView
Definition datatypes.hpp:161
int64_t idx_t
Definition datatypes.hpp:91
double real_t
Definition datatypes.hpp:99
KOKKOS_INLINE_FUNCTION constexpr real_t real_c(T t)
Definition datatypes.hpp:114
Definition MultiHistogram.hpp:30
MultiView data
Definition MultiHistogram.hpp:82
void makeSymmetric()
Definition MultiHistogram.cpp:76
void scale(const real_t &scalingFactor)
Definition MultiHistogram.cpp:48
|X|O|OOOOOOOOOO |X|O|OOOOOOOOOO |X|O+-------— <– minInnerCorner |X|OOOOOOOOOOOO |X+---------— <– minC...
Definition Subdomain.hpp:38