22#ifndef PFC_UI_FROM_JSON_HPP
23#define PFC_UI_FROM_JSON_HPP
47template <
class T> T from_json(
const json &settings);
61 if (!
j.contains(
"backend") || !
j[
"backend"].is_string()) {
63 std::cout <<
"No FFT backend specified, defaulting to FFTW\n";
64 return fft::Backend::FFTW;
69 [](
unsigned char c) { return std::tolower(c); });
71 std::cout <<
"Selected FFT backend: " <<
backend_str << std::endl;
74 return fft::Backend::FFTW;
76#if defined(OpenPFC_ENABLE_CUDA)
77 return fft::Backend::CUDA;
79 throw std::runtime_error(
80 "CUDA backend requested but OpenPFC was not compiled with CUDA support. "
81 "Rebuild with -DOpenPFC_ENABLE_CUDA=ON");
84 throw std::runtime_error(
86 ". Supported: fftw, cuda");
103 std::cout <<
"\nParsing HeFFTe plan options ...\n";
105 if (
j.contains(
"use_reorder")) {
106 std::cout <<
"Using strided 1d fft operations" << std::endl;
107 options.use_reorder =
j[
"use_reorder"];
109 if (
j.contains(
"reshape_algorithm")) {
110 if (
j[
"reshape_algorithm"] ==
"alltoall") {
111 std::cout <<
"Using alltoall reshape algorithm" << std::endl;
113 }
else if (
j[
"reshape_algorithm"] ==
"alltoallv") {
114 std::cout <<
"Using alltoallv reshape algorithm" << std::endl;
116 }
else if (
j[
"reshape_algorithm"] ==
"p2p") {
117 std::cout <<
"Using p2p reshape algorithm" << std::endl;
119 }
else if (
j[
"reshape_algorithm"] ==
"p2p_plined") {
120 std::cout <<
"Using p2p_plined reshape algorithm" << std::endl;
123 std::cerr <<
"Unknown reshape algorithm " <<
j[
"reshape_algorithm"]
127 if (
j.contains(
"use_pencils")) {
128 std::cout <<
"Using pencil decomposition" << std::endl;
129 options.use_pencils =
j[
"use_pencils"];
131 if (
j.contains(
"use_gpu_aware")) {
132 std::cout <<
"Using gpu aware fft" << std::endl;
133 options.use_gpu_aware =
j[
"use_gpu_aware"];
135 std::cout <<
"Backend options: " <<
options <<
"\n\n";
158 int Lx = 0,
Ly = 0,
Lz = 0;
159 double dx = 0.0,
dy = 0.0,
dz = 0.0;
160 double x0 = 0.0,
y0 = 0.0,
z0 = 0.0;
167 "Lx",
"number of grid points in X direction",
"positive integer",
176 throw std::invalid_argument(
178 "positive integer",
ly_str, {},
"\"Ly\": 256"));
186 throw std::invalid_argument(
188 "positive integer",
lz_str, {},
"\"Lz\": 256"));
196 throw std::invalid_argument(
198 dx_str, {},
"\"dx\": 1.0"));
206 throw std::invalid_argument(
208 dy_str, {},
"\"dy\": 1.0"));
216 throw std::invalid_argument(
218 dz_str, {},
"\"dz\": 1.0"));
228 std::string
origin_key =
j.contains(
"origin") ?
"origin" :
"origo";
232 origin_key,
"coordinate system origin",
"string ('center' or 'corner')",
233 origin_str, {
"center",
"corner"},
"\"origin\": \"center\""));
237 std::string
origin_key =
j.contains(
"origin") ?
"origin" :
"origo";
240 origin_key,
"coordinate system origin",
"string ('center' or 'corner')",
241 "\"" +
origin +
"\"", {
"center",
"corner"},
"\"origin\": \"center\""));
265 throw std::invalid_argument(
266 "Missing required time stepping parameters (t0, t1, dt, saveat)");
272 double saveat = saveat_val;
273 Time time({t0, t1, dt}, saveat);
277inline void from_json(
const json &j, Constant &ic) {
279 if (!j.contains(
"type") || j[
"type"] !=
"constant") {
280 throw std::invalid_argument(
281 "Invalid JSON input: missing or incorrect 'type' field.");
284 if (!j.contains(
"n0") || !j[
"n0"].is_number()) {
285 throw std::invalid_argument(
286 "Invalid JSON input: missing or invalid 'n0' field.");
288 ic.set_density(j[
"n0"]);
291inline void from_json(
const json &j, SingleSeed &seed) {
292 if (!j.count(
"type") || j[
"type"] !=
"single_seed") {
293 throw std::invalid_argument(
294 "JSON object does not contain a 'single_seed' type.");
297 if (!j.count(
"amp_eq")) {
298 throw std::invalid_argument(
"JSON object does not contain an 'amp_eq' key.");
301 if (!j.count(
"rho_seed")) {
302 throw std::invalid_argument(
"JSON object does not contain a 'rho_seed' key.");
305 seed.set_amplitude(j[
"amp_eq"]);
306 seed.set_density(j[
"rho_seed"]);
309inline void from_json(
const json &j, RandomSeeds &ic) {
311 if (!j.contains(
"type") || j[
"type"] !=
"random_seeds") {
312 throw std::invalid_argument(
313 "Invalid JSON input: missing or incorrect 'type' field.");
317 if (!j.contains(
"amplitude") || !j[
"amplitude"].is_number()) {
318 throw std::invalid_argument(
319 "Invalid JSON input: missing or invalid 'amplitude' field.");
323 if (!j.contains(
"rho") || !j[
"rho"].is_number()) {
324 throw std::invalid_argument(
325 "Invalid JSON input: missing or invalid 'rho' field.");
328 ic.set_amplitude(j[
"amplitude"]);
329 ic.set_density(j[
"rho"]);
332inline void from_json(
const json &j, SeedGrid &ic) {
333 if (!j.contains(
"type") || j[
"type"] !=
"seed_grid") {
334 throw std::invalid_argument(
335 "Invalid JSON input: missing or incorrect 'type' field.");
338 if (!j.contains(
"Ny") || !j[
"Ny"].is_number()) {
339 throw std::invalid_argument(
340 "Invalid JSON input: missing or invalid 'Ny' field.");
343 if (!j.contains(
"Nz") || !j[
"Nz"].is_number()) {
344 throw std::invalid_argument(
345 "Invalid JSON input: missing or invalid 'Nz' field.");
348 if (!j.contains(
"X0") || !j[
"X0"].is_number()) {
349 throw std::invalid_argument(
350 "Invalid JSON input: missing or invalid 'X0' field.");
353 if (!j.contains(
"radius") || !j[
"radius"].is_number()) {
354 throw std::invalid_argument(
355 "Invalid JSON input: missing or invalid 'radius' field.");
358 if (!j.contains(
"amplitude") || !j[
"amplitude"].is_number()) {
359 throw std::invalid_argument(
360 "Invalid JSON input: missing or invalid 'amplitude' field.");
363 if (!j.contains(
"rho") || !j[
"rho"].is_number()) {
364 throw std::invalid_argument(
365 "Invalid JSON input: missing or invalid 'rho' field.");
371 ic.set_radius(j[
"radius"]);
372 ic.set_amplitude(j[
"amplitude"]);
373 ic.set_density(j[
"rho"]);
376inline void from_json(
const json &j, FileReader &ic) {
377 if (!j.contains(
"type") || j[
"type"] !=
"from_file") {
378 throw std::invalid_argument(
379 "Invalid JSON input: missing or incorrect 'type' field.");
382 if (!j.contains(
"filename") || !j[
"filename"].is_string()) {
383 throw std::invalid_argument(
384 "Invalid JSON input: missing or invalid 'filename' field.");
387 ic.set_filename(j[
"filename"]);
390inline void from_json(
const json &j, FixedBC &bc) {
391 if (!j.contains(
"type") || j[
"type"] !=
"fixed") {
392 throw std::invalid_argument(
393 "Invalid JSON input: missing or incorrect 'type' field.");
396 if (!j.contains(
"rho_low") || !j[
"rho_low"].is_number()) {
397 throw std::invalid_argument(
398 "Invalid JSON input: missing or invalid 'rho_low' field.");
401 if (!j.contains(
"rho_high") || !j[
"rho_high"].is_number()) {
402 throw std::invalid_argument(
403 "Invalid JSON input: missing or invalid 'rho_high' field.");
406 bc.set_rho_low(j[
"rho_low"]);
407 bc.set_rho_high(j[
"rho_high"]);
410inline void from_json(
const json &j, MovingBC &bc) {
411 if (!j.contains(
"type") || j[
"type"] !=
"moving") {
412 throw std::invalid_argument(
413 "Invalid JSON input: missing or incorrect 'type' field.");
416 if (!j.contains(
"rho_low") || !j[
"rho_low"].is_number()) {
417 throw std::invalid_argument(
418 "Invalid JSON input: missing or invalid 'rho_low' field.");
421 if (!j.contains(
"rho_high") || !j[
"rho_high"].is_number()) {
422 throw std::invalid_argument(
423 "Invalid JSON input: missing or invalid 'rho_high' field.");
426 if (!j.contains(
"width") || !j[
"width"].is_number()) {
427 throw std::invalid_argument(
428 "Invalid JSON input: missing or invalid 'width' field.");
431 if (!j.contains(
"alpha") || !j[
"alpha"].is_number()) {
432 throw std::invalid_argument(
433 "Invalid JSON input: missing or invalid 'alpha' field.");
436 if (!j.contains(
"disp") || !j[
"disp"].is_number()) {
437 throw std::invalid_argument(
438 "Invalid JSON input: missing or invalid 'disp' field.");
441 if (!j.contains(
"xpos") || !j[
"xpos"].is_number()) {
442 throw std::invalid_argument(
443 "Invalid JSON input: missing or invalid 'xpos' field.");
446 bc.set_rho_low(j[
"rho_low"]);
447 bc.set_rho_high(j[
"rho_high"]);
448 bc.set_xwidth(j[
"width"]);
449 bc.set_alpha(j[
"alpha"]);
450 bc.set_disp(j[
"disp"]);
451 bc.set_xpos(j[
"xpos"]);
454inline void from_json(
const json &, Model &) {
455 std::cout <<
"Warning: This model does not implement reading parameters from "
456 "json file. In order to read parameters from json file, one needs to "
457 "implement 'void from_json(const json &, Model &)'"
Constant value initial condition.
Helpful error message formatting for JSON configuration validation.
std::string format_config_error(const std::string &field_name, const std::string &description, const std::string &expected_type, const std::string &actual_value, const std::vector< std::string > &valid_options={}, const std::string &example="")
Format a helpful configuration error message.
Definition errors.hpp:118
std::string get_json_value_string(const nlohmann::json &j, const std::string &field_name)
Get JSON value as string for error messages.
Definition errors.hpp:190
Fast Fourier Transform interface for spectral methods.
Backend
FFT backend selection.
Definition fft.hpp:128
Base class for initial conditions and boundary conditions.
Read initial conditions from binary file.
Fixed boundary condition with smooth transition.
JSON utility functions for configuration parsing.
json get_json_value(const json &j, const std::string &key, const std::string §ion="")
Helper function to get a JSON value from either flat or nested structure.
Definition json_helpers.hpp:38
Physics model abstraction for phase-field simulations.
Moving boundary condition that tracks solidification front.
auto create(const World< T > &world, const heffte::box3d< int > &box)
Construct a new World object from an existing one and a box.
Definition decomposition.hpp:62
Random distribution of crystalline seeds initial condition.
Regular grid of crystalline seeds initial condition.
Single spherical crystalline seed initial condition.
Grid dimensions (number of grid points per dimension)
Definition strong_types.hpp:176
Physical spacing between grid points.
Definition strong_types.hpp:370
Physical origin of coordinate system.
Definition strong_types.hpp:424
Represents the global simulation domain (the "world").
Definition world.hpp:91
World(const Int3 &lower, const Int3 &upper, const CoordinateSystem< T > &cs)
Constructs a World object.
Time state management for simulation time integration.
World class definition and unified interface.