OpenPFC  0.1.4
Phase Field Crystal simulation framework
Loading...
Searching...
No Matches
moving_bc.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2025 VTT Technical Research Centre of Finland Ltd
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
36#ifndef PFC_BOUNDARY_CONDITIONS_MOVING_BC_HPP
37#define PFC_BOUNDARY_CONDITIONS_MOVING_BC_HPP
38
39#include <cmath>
40#include <limits>
41#include <mpi.h>
42
43#include "../field_modifier.hpp"
44#include "../utils.hpp"
46
47namespace pfc {
48
49class MovingBC : public FieldModifier {
50
51private:
52 double m_rho_low, m_rho_high;
53 double m_xwidth = 15.0;
54 double m_alpha = 1.0;
55 double m_xpos = 0.0;
56 double m_threshold = 0.1;
57 int m_idx = 0;
58 double m_disp = 40.0;
59 bool m_first = true;
60 std::vector<double> xline, global_xline;
62 int rank = mpi::get_comm_rank(comm);
63 int size = mpi::get_comm_size(comm);
64 std::string m_name = "MovingBC";
65
66public:
67 MovingBC() = default;
68 MovingBC(double rho_low, double rho_high)
69 : m_rho_low(rho_low), m_rho_high(rho_high) {}
70
71 void set_rho_low(double rho_low) { m_rho_low = rho_low; }
72 void set_rho_high(double rho_high) { m_rho_high = rho_high; }
73
74 void set_xpos(double xpos) { m_xpos = xpos; }
75 double get_xpos() const { return m_xpos; }
76
77 void set_xwidth(double xwidth) { m_xwidth = xwidth; }
78 double get_xwidth() const { return m_xwidth; }
79
80 void set_alpha(double alpha) { m_alpha = alpha; }
81
82 void set_disp(double disp) { m_disp = disp; }
83
84 void set_threshold(double threshold) { m_threshold = threshold; }
85 double get_threshold() const { return m_threshold; }
86
87 const std::string &get_modifier_name() const override { return m_name; }
88
89 void apply(Model &m, double) override {
90 const FFT &fft = m.get_fft();
91 Field &field = m.get_real_field(get_field_name());
92 const World &w = m.get_world();
93 Int3 low = get_inbox(fft).low;
94 Int3 high = get_inbox(fft).high;
95
96 auto Lx = get_size(w, 0);
97 auto dx = get_spacing(w, 0);
98 auto x0 = get_origin(w, 0);
99
100 if (m_first) {
101 xline.resize(Lx);
102 if (rank == 0) global_xline.resize(Lx);
103 }
104
105 fill(xline.begin(), xline.end(), std::numeric_limits<double>::min());
106
107 long int idx = 0;
108 for (int k = low[2]; k <= high[2]; k++)
109 for (int j = low[1]; j <= high[1]; j++)
110 for (int i = low[0]; i <= high[0]; i++)
111 xline[i] = std::max(xline[i], field[idx++]);
112
113 MPI_Reduce(xline.data(), global_xline.data(), xline.size(), MPI_DOUBLE, MPI_MAX,
114 0, comm);
115
116 if (rank == 0) {
117 if (m_first) {
118 for (int i = global_xline.size() - 1; i >= 0; i--) {
119 if (global_xline[i] > m_threshold) {
120 m_idx = i;
121 break;
122 }
123 }
124 } else {
125 while (global_xline[m_idx % Lx] > m_threshold) {
126 m_idx += 1;
127 }
128 }
129 }
130
131 double new_xpos = x0 + m_idx * dx + m_disp;
132 if (new_xpos > m_xpos) {
133 m_xpos = new_xpos;
134 }
135 MPI_Bcast(&m_xpos, 1, MPI_DOUBLE, 0, comm);
136
137 if (m_first) {
138 m_first = false;
139 }
140
141 std::cout << "Boundary position: " << m_xpos << std::endl;
142
143 fill_bc(m);
144 }
145
146 void fill_bc(Model &m) {
147 const World &w = m.get_world();
148 const double Lx = get_size(w, 0);
149 const double dx = get_spacing(w, 0);
150 const double l = Lx * dx;
151 const double xpos = std::fmod(m_xpos, l);
152 const double xwidth = m_xwidth;
153 const double alpha = m_alpha;
154
155 pfc::field::apply_inplace(
156 m, get_field_name(), [=](const pfc::Real3 &X, double current) {
157 const double x = X[0];
158 const double dist = x - xpos;
159 auto blend = [&](double d) {
160 const double S = 1.0 / (1.0 + std::exp(-alpha * d));
161 return m_rho_low * S + m_rho_high * (1.0 - S);
162 };
163
164 if (std::abs(dist) < xwidth) {
165 return blend(dist);
166 }
167 if (xpos < xwidth && std::abs(dist - l) < xwidth) {
168 return blend(dist - l);
169 }
170 if (xpos > l - xwidth && std::abs(dist + l) < xwidth) {
171 return blend(dist + l);
172 }
173 return current; // outside transition bands, keep value
174 });
175 }
176};
177
178} // namespace pfc
179
180#endif // PFC_BOUNDARY_CONDITIONS_MOVING_BC_HPP
Definition field_modifier.hpp:240
The Model class represents the physics model for simulations in OpenPFC.
Definition model.hpp:95
Definition moving_bc.hpp:49
void apply(Model &m, double) override
Apply the field modification to the model (pure virtual)
Definition moving_bc.hpp:89
const std::string & get_modifier_name() const override
Get the name of the field modifier.
Definition moving_bc.hpp:87
Functional, coordinate-space field operations (header-only)
FFT class for distributed-memory parallel Fourier transforms.
Definition fft.hpp:248
Represents the global simulation domain (the "world").
Definition world.hpp:91