|
| 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 ¶ms, 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 |
0 commit comments