Skip to content

Commit 3c0878d

Browse files
authored
Merge pull request #64 from suviraj1/aluminum_free_function_step
Aluminum free function step
2 parents b42f703 + f79bf46 commit 3c0878d

File tree

6 files changed

+300
-2
lines changed

6 files changed

+300
-2
lines changed

apps/aluminumNew/Aluminum.hpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,4 +461,32 @@ void from_json(const json &j, Aluminum &m) {
461461
p.q4_bar = p.q40_bar;
462462
}
463463

464+
/*
465+
Sometimes, one need to get access to the simulator during stepping. This can be
466+
done by overriding the following function. The default implementation just runs
467+
m.step(t) so if there's no need to access the simulator, it's not necessary to
468+
override this function.
469+
*/
470+
471+
void step(Simulator &s, Aluminum &m) {
472+
#ifdef ALUMINUM_DEBUG
473+
if (m.rank0) cout << "Performing Aluminum step" << endl;
474+
#endif
475+
476+
for (auto const &bc : s.get_boundary_conditions()) {
477+
if (bc->get_modifier_name() == "MovingBC") {
478+
m.set_m_xpos(dynamic_cast<MovingBC &>(*bc).get_xpos());
479+
// auto moving = dynamic_cast< MovingBC& >(*bc);
480+
// double newxpos = moving.get_xpos();
481+
// m.set_m_xpos(newxpos);
482+
// if (m.rank0) std::cout << "Updated xpos to " << m.params.m_xpos << std::endl;
483+
}
484+
}
485+
486+
double t = s.get_time().get_current();
487+
m.step(t);
488+
// perform some extra logic after the step, which can access both simulator
489+
// and model
490+
}
491+
464492
#endif // ALUMINUM_HPP

apps/aluminumNew/SlabFCC.hpp

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
/*
2+
3+
OpenPFC, a simulation software for the phase field crystal method.
4+
Copyright (C) 2024 VTT Technical Research Centre of Finland Ltd.
5+
6+
This program is free software: you can redistribute it and/or modify
7+
it under the terms of the GNU Affero General Public License as
8+
published by the Free Software Foundation, either version 3 of the
9+
License, or (at your option) any later version.
10+
11+
This program 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 Affero General Public License for more details.
15+
16+
You should have received a copy of the GNU Affero General Public License
17+
along with this program. If not, see https://www.gnu.org/licenses/.
18+
19+
*/
20+
21+
#ifndef PFC_INITIAL_CONDITIONS_SLABFCC_HPP
22+
#define PFC_INITIAL_CONDITIONS_SLABFCC_HPP
23+
24+
#include "SeedFCC.hpp"
25+
#include <array>
26+
#include <iostream>
27+
#include <openpfc/openpfc.hpp>
28+
#include <openpfc/ui.hpp>
29+
#include <random>
30+
31+
using json = nlohmann::json;
32+
using namespace pfc;
33+
34+
/**
35+
* @brief SlabFCC is a FieldModifier that seeds the model with a slab of FCC seeds.
36+
*
37+
*/
38+
class SlabFCC : public FieldModifier {
39+
private:
40+
int m_Ny = 2;
41+
int m_Nz = 1;
42+
double m_X0;
43+
double m_amplitude;
44+
double m_fluctuation;
45+
double m_rho;
46+
double m_rseed;
47+
bool randomized = true;
48+
std::vector<std::array<double, 3>> m_orientations;
49+
50+
public:
51+
SlabFCC() = default;
52+
53+
SlabFCC(int Ny, int Nz, double X0, double amplitude, double fluctuation, double rho, double rseed,
54+
std::vector<std::array<double, 3>> orientations = {})
55+
: m_Ny(Ny), m_Nz(Nz), m_X0(X0), m_amplitude(amplitude), m_fluctuation(fluctuation), m_rho(rho), m_rseed(rseed),
56+
m_orientations(orientations) {}
57+
58+
// getters
59+
int get_Ny() const { return m_Ny; }
60+
int get_Nz() const { return m_Nz; }
61+
double get_X0() const { return m_X0; }
62+
double get_amplitude() const { return m_amplitude; }
63+
double get_fluctuation() const { return m_fluctuation; }
64+
double get_rho() const { return m_rho; }
65+
double get_rseed() const { return m_rseed; }
66+
std::vector<std::array<double, 3>> get_orientations() const { return m_orientations; }
67+
68+
// setters
69+
void set_Ny(int Ny) { m_Ny = Ny; }
70+
void set_Nz(int Nz) { m_Nz = Nz; }
71+
void set_X0(double X0) { m_X0 = X0; }
72+
void set_amplitude(double amplitude) { m_amplitude = amplitude; }
73+
void set_fluctuation(double fluctuation) { m_fluctuation = fluctuation; }
74+
void set_rho(double rho) { m_rho = rho; }
75+
void set_rseed(double rseed) { m_rseed = rseed; }
76+
void set_orientations(std::vector<std::array<double, 3>> orientations) { m_orientations = orientations; }
77+
78+
/**
79+
* @brief Apply the initial condition to the model.
80+
*
81+
* @param m is the model to apply the initial condition to.
82+
*/
83+
void apply(Model &m, double) override {
84+
const World &w = m.get_world();
85+
const Decomposition &decomp = m.get_decomposition();
86+
Field &field = m.get_real_field("psi");
87+
Vec3<int> low = decomp.inbox.low;
88+
Vec3<int> high = decomp.inbox.high;
89+
90+
// auto Lx = w.Lx;
91+
auto Ly = w.Ly;
92+
auto Lz = w.Lz;
93+
auto dx = w.dx;
94+
auto dy = w.dy;
95+
auto dz = w.dz;
96+
auto x0 = w.x0;
97+
auto y0 = w.y0;
98+
auto z0 = w.z0;
99+
100+
std::vector<SeedFCC> seeds;
101+
102+
int Ny = m_Ny;
103+
int Nz = m_Nz;
104+
double rseed = m_rseed;
105+
106+
double rho = get_rho();
107+
double amplitude = get_amplitude();
108+
double fluctuation = get_fluctuation();
109+
110+
double X0 = m_X0;
111+
double Dy = dy * Ly / Ny;
112+
double Y0 = Dy / 2.0;
113+
double Dz = dz * Lz / Nz;
114+
double Z0 = Dz / 2.0;
115+
int nseeds = Ny * Nz;
116+
117+
double radius = 1.;
118+
119+
std::vector<std::array<double, 3>> orientations = m_orientations;
120+
121+
randomized = (orientations.empty());
122+
123+
std::mt19937_64 re(rseed);
124+
std::uniform_real_distribution<double> rt(-0.2 * radius, 0.2 * radius);
125+
std::uniform_real_distribution<double> rr(0.0, 8.0 * atan(1.0));
126+
std::uniform_real_distribution<double> ra(-fluctuation, fluctuation);
127+
128+
if (randomized) {
129+
130+
std::cout << "Generating " << nseeds << " random seeds up to distance " << X0 << "\n";
131+
132+
for (int j = 0; j < Ny; j++) {
133+
for (int k = 0; k < Nz; k++) {
134+
const std::array<double, 3> location = {X0 + rt(re), Y0 + Dy * j + rt(re), Z0 + Dz * k + rt(re)};
135+
const std::array<double, 3> orientation = {rr(re), rr(re), rr(re)};
136+
const SeedFCC seed(location, orientation, radius, rho, amplitude);
137+
seeds.push_back(seed);
138+
}
139+
}
140+
141+
} else {
142+
std::cout << "Generating " << nseeds << " seeds from orientation list up to distance " << X0 << "\n";
143+
144+
for (int j = 0; j < Ny; j++) {
145+
for (int k = 0; k < Nz; k++) {
146+
const std::array<double, 3> location = {X0 + rt(re), Y0 + Dy * j + rt(re), Z0 + Dz * k + rt(re)};
147+
const std::array<double, 3> orientation = orientations[j * Nz + k];
148+
const SeedFCC seed(location, orientation, radius, rho, amplitude);
149+
seeds.push_back(seed);
150+
}
151+
}
152+
}
153+
154+
long int idx = 0;
155+
for (int k = low[2]; k <= high[2]; k++) {
156+
for (int j = low[1]; j <= high[1]; j++) {
157+
for (int i = low[0]; i <= high[0]; i++) {
158+
const double x = x0 + i * dx;
159+
const double y = y0 + j * dy;
160+
const double z = z0 + k * dz;
161+
const std::array<double, 3> X = {x, y, z};
162+
if (x < (X0 + ra(re))) {
163+
const int ns = floor(y / Dy) * Nz + floor(z / Dz);
164+
field[idx] = seeds[ns].get_value(X);
165+
}
166+
idx += 1;
167+
}
168+
}
169+
}
170+
}
171+
}; // SlabFCC
172+
173+
/**
174+
* @brief Configure SlabFCC object from a json file.
175+
*
176+
* @param params json object containing the parameters.
177+
* @param ic SlabFCC object to configure.
178+
* @return void
179+
*
180+
* Example json configuration:
181+
*
182+
* { "type": "slab_fcc", "X0": 130.0, "Ny": 2, "Nz": 1,
183+
* "amplitude": 0.2, "fluctuation": 10.0, "rho": -0.036, "rseed": 42 }
184+
*
185+
* The "type" field is required and must be "seed_grid_fcc". The "rseed" field is
186+
* optional and defaults to 0. All other fields are required. The "Ny" and "Nz"
187+
* fields are the number of seeds in the y and z directions, respectively. The
188+
* "X0" field is the x-coordinate of the center of the first seed. The "radius"
189+
* field is the radius of the seeds. The "amplitude" field is the amplitude of
190+
* the seed. The "rho" field is the background density. The "rseed" field is the
191+
* random seed.
192+
*
193+
*/
194+
void from_json(const json &params, SlabFCC &ic) {
195+
std::cout << "Parsing SlabFCC from json" << std::endl;
196+
197+
// check for required fields
198+
if (!params.contains("amplitude") || !params["amplitude"].is_number()) {
199+
throw std::invalid_argument("Reading SlabFCC failed: missing or invalid 'amplitude' field.");
200+
}
201+
if (!params.contains("fluctuation") || !params["fluctuation"].is_number()) {
202+
throw std::invalid_argument("Reading SlabFCC failed: missing or invalid 'amplitude' field.");
203+
}
204+
if (!params.contains("rho") || !params["rho"].is_number()) {
205+
throw std::invalid_argument("Reading SlabFCC failed: missing or invalid 'rho' field.");
206+
}
207+
if (!params.contains("Ny") || !params["Ny"].is_number()) {
208+
throw std::invalid_argument("Reading SlabFCC failed: missing or invalid 'Ny' field.");
209+
}
210+
if (!params.contains("Nz") || !params["Nz"].is_number()) {
211+
throw std::invalid_argument("Reading SlabFCC failed: missing or invalid 'Nz' field.");
212+
}
213+
if (!params.contains("X0") || !params["X0"].is_number()) {
214+
throw std::invalid_argument("Reading SlabFCC failed: missing or invalid 'X0' field.");
215+
}
216+
if (!params.contains("rseed") || !params["rseed"].is_number()) {
217+
std::cout << "No valid random seed detected, using default value 0." << std::endl;
218+
}
219+
if (!params.contains("orientations") || !params["orientations"].is_array()) {
220+
std::cout << "No valid orientation vector detected, randomizing." << std::endl;
221+
}
222+
int Nz = params["Nz"];
223+
int Ny = params["Ny"];
224+
225+
std::vector<std::array<double, 3>> m_orientations;
226+
auto orientations = params.value("orientations", m_orientations);
227+
// auto orientations = params["orientations"];
228+
if (!orientations.empty() && orientations.size() != (Nz * Ny)) {
229+
throw std::invalid_argument("Orientation vector and seed grid sizes do not match.");
230+
}
231+
232+
ic.set_Ny(params["Ny"]);
233+
ic.set_Nz(params["Nz"]);
234+
ic.set_X0(params["X0"]);
235+
ic.set_amplitude(params["amplitude"]);
236+
ic.set_fluctuation(params["fluctuation"]);
237+
ic.set_rho(params["rho"]);
238+
if (params.contains("rseed") && params["rseed"].is_number()) ic.set_rseed(params["rseed"]);
239+
// if (params.contains("orientations") && params["orientations"].is_array())
240+
// ic.set_orientations(params["orientations"]);
241+
ic.set_orientations(orientations);
242+
}
243+
244+
#endif // PFC_INITIAL_CONDITIONS_SLABFCC_HPP

apps/aluminumNew/aluminumNew.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@ along with this program. If not, see https://www.gnu.org/licenses/.
2020

2121
#include "Aluminum.hpp"
2222
#include "SeedGridFCC.hpp"
23+
#include "SlabFCC.hpp"
2324

2425
int main(int argc, char *argv[]) {
2526
std::cout << std::fixed;
2627
std::cout.precision(3);
2728
register_field_modifier<SeedGridFCC>("seed_grid_fcc");
29+
register_field_modifier<SlabFCC>("slab_fcc");
2830
App<Aluminum> app(argc, argv);
2931
return app.main();
3032
}

include/openpfc/boundary_conditions/fixed_bc.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class FixedBC : public FieldModifier {
3131
double xwidth = 20.0;
3232
double alpha = 1.0;
3333
double m_rho_low, m_rho_high;
34+
std::string m_name = "FixedBC";
3435

3536
public:
3637
FixedBC() = default;
@@ -40,6 +41,8 @@ class FixedBC : public FieldModifier {
4041
void set_rho_low(double rho_low) { m_rho_low = rho_low; }
4142
void set_rho_high(double rho_high) { m_rho_high = rho_high; }
4243

44+
const std::string &get_modifier_name() const override { return m_name; }
45+
4346
void apply(Model &m, double) override {
4447
const Decomposition &decomp = m.get_decomposition();
4548
Field &field = m.get_real_field(get_field_name());

include/openpfc/boundary_conditions/moving_bc.hpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,15 @@ class MovingBC : public FieldModifier {
3737
double m_xwidth = 15.0;
3838
double m_alpha = 1.0;
3939
double m_xpos = 0.0;
40+
double m_threshold = 0.1;
4041
int m_idx = 0;
4142
double m_disp = 40.0;
4243
bool m_first = true;
4344
std::vector<double> xline, global_xline;
4445
MPI_Comm comm = MPI_COMM_WORLD;
4546
int rank = mpi::get_comm_rank(comm);
4647
int size = mpi::get_comm_size(comm);
48+
std::string m_name = "MovingBC";
4749

4850
public:
4951
MovingBC() = default;
@@ -53,6 +55,7 @@ class MovingBC : public FieldModifier {
5355
void set_rho_high(double rho_high) { m_rho_high = rho_high; }
5456

5557
void set_xpos(double xpos) { m_xpos = xpos; }
58+
double get_xpos() const { return m_xpos; }
5659

5760
void set_xwidth(double xwidth) { m_xwidth = xwidth; }
5861
double get_xwidth() const { return m_xwidth; }
@@ -61,6 +64,11 @@ class MovingBC : public FieldModifier {
6164

6265
void set_disp(double disp) { m_disp = disp; }
6366

67+
void set_threshold(double threshold) { m_threshold = threshold; }
68+
double get_threshold() const { return m_threshold; }
69+
70+
const std::string &get_modifier_name() const override { return m_name; }
71+
6472
void apply(Model &m, double) override {
6573
const Decomposition &decomp = m.get_decomposition();
6674
Field &field = m.get_real_field(get_field_name());
@@ -87,13 +95,13 @@ class MovingBC : public FieldModifier {
8795
if (rank == 0) {
8896
if (m_first) {
8997
for (int i = global_xline.size() - 1; i >= 0; i--) {
90-
if (global_xline[i] > 0.1) {
98+
if (global_xline[i] > m_threshold) {
9199
m_idx = i;
92100
break;
93101
}
94102
}
95103
} else {
96-
while (global_xline[m_idx % w.Lx] > 0.1) {
104+
while (global_xline[m_idx % w.Lx] > m_threshold) {
97105
m_idx += 1;
98106
}
99107
}
@@ -109,6 +117,8 @@ class MovingBC : public FieldModifier {
109117
m_first = false;
110118
}
111119

120+
std::cout << "Boundary position: " << m_xpos << std::endl;
121+
112122
fill_bc(m);
113123
}
114124

include/openpfc/field_modifier.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class FieldModifier {
3737

3838
private:
3939
std::string m_field_name = "default";
40+
std::string m_default_name = "default";
4041

4142
public:
4243
/**
@@ -72,6 +73,16 @@ class FieldModifier {
7273
*/
7374
const std::string &get_field_name() const { return m_field_name; }
7475

76+
/**
77+
* @brief Get the name of the field modifier.
78+
*
79+
* This function is responsible for getting the name of the field modifier.
80+
*
81+
* @return The modifier name.
82+
*/
83+
84+
virtual const std::string &get_modifier_name() const { return m_default_name; }
85+
7586
/**
7687
* @brief Apply the field modification to the model at a specific time.
7788
*

0 commit comments

Comments
 (0)