diff --git a/CMakeLists.txt b/CMakeLists.txt index c933ef39..386bd3a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,7 +66,7 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ExaCAconfig.cmake" # Install data files file(GLOB MATERIALS examples/Materials/*) -file(GLOB SUBSTRATE examples/Substrate/GrainOrientation*.csv) +file(GLOB SUBSTRATE examples/Substrate/CrystalOrientation*.csv) install(FILES ${MATERIALS} DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/ExaCA) install(FILES ${SUBSTRATE} diff --git a/README.md b/README.md index 8d779475..9e72817d 100644 --- a/README.md +++ b/README.md @@ -235,7 +235,9 @@ As detailed further in [examples/README.md](examples/README.md), ExaCA can print | GrainID | All layers | A unique identifier for each grain in the ExaCA simulation. Positive numbers represent grains from either the initial substrate/baseplate or from a powder layer, while negative numbers represent grains formed via a nucleation event. GrainIDs of 0 are used to identify cells from a powder layer that do not have any associated material (i.e., voids or gas in the powder layer). Each GrainID is linked to a grain orientation through the substrate input file - GrainID = 1 or -1 is associated with the first orientation in the file, GrainID = 2 or -2 with the second orientatation, etc, with orientations reused when the number of grains exceeds the number of orientations in the file (for example, [examples/Substrate/`GrainOrientationVectors.csv](examples/Substrate/GrainOrientationVectors.csv) has 10,000 grain orientations, so a GrainID of 10,001 will share its orientation with the GrainID of 1). | LayerID | All layers | The final (or most recent) layer in which a given cell undergoes/underwent melting and solidification. Layer numbers start at 0, with -1 used for cells that have not undergone melting/solidification. | PhaseID | All layers | The solid phase associated with the most recent solidification in a cell. For single phase solidification problems, this will always be 0, while for two phase solidification problems, this will be 0 for cells that solidified as the primary phase and 1 for cells that solidified as the second phase -| GrainMisorientation | All layers | The orientation (in degrees) of the grain's nearest <100> direction to the Z axis (the thermal gradient direction for directional solidification problems, the build/layer offset direction for other problems). Epitaxial grains (from the initial grain structure or powder layer) are assigned (rounded) integer values between 0 and 55, while nucleated grains (not present in the initial grain structure) are assigned values between 100 and 155 (the offset of 100 is simply used to ensure the two types of grains are differentiated, but a nucleated grain with a value of 135 actually has <100> misoriented with Z by 35 degrees). All cells belonging to the same grain (same GrainID value) will have the same GrainMisorientation, as no intra-granular misorientations are currently simulated. Also of note is that for intermediate output files where liquid cells are present, these cells are assigned a value of -1, and that unmelted material (or non-existent material in a powder layer) is assigned a value of 200. +| CrystalMisorientationZ | All layers | The orientation (in degrees) of the grain's nearest <100> direction to the Z axis (the thermal gradient direction for directional solidification problems, the build/layer offset direction for other problems). Epitaxial grains (from the initial grain structure or powder layer) are assigned (rounded) integer values between 0 and 55, while nucleated grains (not present in the initial grain structure) are assigned values between 100 and 155 (the offset of 100 is simply used to ensure the two types of grains are differentiated, but a nucleated grain with a value of 135 actually has <100> misoriented with Z by 35 degrees). All cells belonging to the same grain (same GrainID value) will have the same GrainMisorientation, as no intra-granular misorientations are currently simulated. Also of note is that for intermediate output files where liquid cells are present, these cells are assigned a value of -1, and that unmelted material (or non-existent material in a powder layer) is assigned a value of 200. +| CrystalMisorientationY | All layers | The orientation (in degrees) of the grain's nearest <100> direction to the Y axis +| CrystalMisorientationX | All layers | The orientation (in degrees) of the grain's nearest <100> direction to the X axis | UndercoolingCurrent | All layers | The current undercooling of a cell (if liquid or active), or the undercooling when a cell was most recently active (if solid). Superheated liquid cells or cells that have not undergone melting and solidification will have a value of 0. | UndercoolingSolidificationStart | All layers | For cells that are currently undergoing solidification or have finished solidification, the undercooling when solidification started. Will have a value of 0 for all other cells | MeltPoolEdge | All layers | Value of 1 for cells that were at the edge of the time-temperature history data and converted to active cells, value of 0 for all other cells including cells that became active via a cell capture or nucleation event diff --git a/analysis/bin/runGA.cpp b/analysis/bin/runGA.cpp index f34c692b..beb8ddc1 100644 --- a/analysis/bin/runGA.cpp +++ b/analysis/bin/runGA.cpp @@ -117,15 +117,16 @@ int main(int argc, char *argv[]) { found_layer_id); // Calculate and if specified, print misorientation data - std::vector grain_misorientation_x_vector = - representativeregion.getGrainMisorientation("X", orientation); - std::vector grain_misorientation_y_vector = - representativeregion.getGrainMisorientation("Y", orientation); - std::vector grain_misorientation_z_vector = - representativeregion.getGrainMisorientation("Z", orientation); + std::vector crystal_misorientation_x_vector = + representativeregion.getCrystalMisorientation("X", orientation); + std::vector crystal_misorientation_y_vector = + representativeregion.getCrystalMisorientation("Y", orientation); + std::vector crystal_misorientation_z_vector = + representativeregion.getCrystalMisorientation("Z", orientation); if (representativeregion.analysis_options_stats_yn[1]) - representativeregion.printMeanMisorientations( - qois, grain_misorientation_x_vector, grain_misorientation_y_vector, grain_misorientation_z_vector); + representativeregion.printMeanMisorientations(qois, crystal_misorientation_x_vector, + crystal_misorientation_y_vector, + crystal_misorientation_z_vector); // Print mean size data if specified if (representativeregion.analysis_options_stats_yn[2]) @@ -165,9 +166,9 @@ int main(int argc, char *argv[]) { // Write per-grain stats for the analysis types specified to the file // "[base_filename_this_region]_grains.csv" if (representativeregion.print_per_grain_stats_yn) - representativeregion.writePerGrainStats(base_filename_this_region, grain_misorientation_x_vector, - grain_misorientation_y_vector, grain_misorientation_z_vector, - build_trans_aspect_ratio, grain_red, grain_green, grain_blue); + representativeregion.writePerGrainStats( + base_filename_this_region, crystal_misorientation_x_vector, crystal_misorientation_y_vector, + crystal_misorientation_z_vector, build_trans_aspect_ratio, grain_red, grain_green, grain_blue); // ExaConstit print a file named "[base_filename_this_region]_ExaConstit.csv" if (representativeregion.print_exaconstit_yn) { @@ -177,7 +178,7 @@ int main(int argc, char *argv[]) { // Pole figure print a file named "[base_filename_this_region]_PoleFigureData.txt" if (representativeregion.print_pole_figure_yn) { auto go_histogram = representativeregion.getOrientationHistogram( - orientation.n_grain_orientations, grain_id, layer_id, phase_id, num_phases, found_layer_id); + orientation.n_crystal_orientations, grain_id, layer_id, phase_id, num_phases, found_layer_id); representativeregion.writePoleFigure(base_filename_this_region, orientation, go_histogram); } diff --git a/analysis/src/GArepresentativeregion.hpp b/analysis/src/GArepresentativeregion.hpp index 31aa2db2..135b2740 100644 --- a/analysis/src/GArepresentativeregion.hpp +++ b/analysis/src/GArepresentativeregion.hpp @@ -455,11 +455,12 @@ struct RepresentativeRegion { } } - // Calculate misorientation relative to the specified cardinal direction for each grain and store in the vector + // Calculate <100> misorientation relative to the specified cardinal direction for each grain and store in the + // vector template - std::vector getGrainMisorientation(std::string direction, Orientation &orientation) { + std::vector getCrystalMisorientation(std::string direction, Orientation &orientation) { - std::vector grain_misorientation_vector(number_of_grains); + std::vector crystal_misorientation_vector(number_of_grains); int direction_int; if (direction == "X") direction_int = 0; @@ -469,22 +470,22 @@ struct RepresentativeRegion { direction_int = 2; else throw std::runtime_error( - "Error: invalid direction specified in calcGrainMisorientation: should be X, Y, or Z"); - auto grain_misorientation = orientation.misorientationCalc(direction_int); + "Error: invalid direction specified in calcCrystalMisorientation: should be X, Y, or Z"); + auto crystal_misorientation = orientation.misorientationCalc(direction_int); for (int n = 0; n < number_of_grains; n++) { - int my_orientation = getGrainOrientation(unique_grain_id_vector[n], orientation.n_grain_orientations); + int my_orientation = getCrystalOrientation(unique_grain_id_vector[n], orientation.n_crystal_orientations); // Grain misorientation always corresponds to phase 0, even if original crystallographic orientation during // initial solidification as phase 1 was different - float my_misorientation = grain_misorientation(my_orientation, 0); - grain_misorientation_vector[n] = my_misorientation; + float my_misorientation = crystal_misorientation(my_orientation, 0); + crystal_misorientation_vector[n] = my_misorientation; } - return grain_misorientation_vector; + return crystal_misorientation_vector; } // Create a histogram of orientations for texture determination, using the grain_id values in the volume bounded by // [XMin,XMax], [YMin,YMax], [ZMin,ZMax] and excluding and cells that did not undergo melting (layer_id = -1) template - auto getOrientationHistogram(int n_grain_orientations, ViewTypeInt3dHost grain_id, ViewTypeShort3dHost layer_id, + auto getOrientationHistogram(int n_crystal_orientations, ViewTypeInt3dHost grain_id, ViewTypeShort3dHost layer_id, ViewTypeShort3dHost phase_id, const int num_phases, bool found_layer_id) { // Init histogram values to zero @@ -494,14 +495,14 @@ struct RepresentativeRegion { "melting and solidification as they cannot be differentiated from the regions that were simulated" << std::endl; using int_type = typename ViewTypeInt3dHost::value_type; - Kokkos::View go_histogram("go_histogram", n_grain_orientations, num_phases); + Kokkos::View go_histogram("go_histogram", n_crystal_orientations, num_phases); for (int phase_num = 0; phase_num < num_phases; phase_num++) { for (int k = z_bounds_cells[0]; k <= z_bounds_cells[1]; k++) { for (int j = y_bounds_cells[0]; j <= y_bounds_cells[1]; j++) { for (int i = x_bounds_cells[0]; i <= x_bounds_cells[1]; i++) { if ((grain_id(k, i, j) != 0) && (layer_id(k, i, j) != -1)) { short my_phase = phase_id(k, i, j); - int go_val = getGrainOrientation(grain_id(k, i, j), n_grain_orientations); + int go_val = getCrystalOrientation(grain_id(k, i, j), n_crystal_orientations); go_histogram(go_val, my_phase)++; } } @@ -632,24 +633,24 @@ struct RepresentativeRegion { } // Print average misorientation for the region relative to each direction - void printMeanMisorientations(std::ofstream &qois, std::vector grain_misorientation_x_vector, - std::vector grain_misorientation_y_vector, - std::vector grain_misorientation_z_vector) { + void printMeanMisorientations(std::ofstream &qois, std::vector crystal_misorientation_x_vector, + std::vector crystal_misorientation_y_vector, + std::vector crystal_misorientation_z_vector) { std::vector misorientation_direction_labels = {"misorientationX", "misorientationY", "misorientationZ"}; std::vector misorientation_direction_labels_short = {"+X", "+Y", "+Z"}; - float grain_misorientation_sum_x = 0.0; - float grain_misorientation_sum_y = 0.0; - float grain_misorientation_sum_z = 0.0; + float crystal_misorientation_sum_x = 0.0; + float crystal_misorientation_sum_y = 0.0; + float crystal_misorientation_sum_z = 0.0; for (int n = 0; n < number_of_grains; n++) { - grain_misorientation_sum_x += grain_misorientation_x_vector[n] * grain_size_vector_microns[n]; - grain_misorientation_sum_y += grain_misorientation_y_vector[n] * grain_size_vector_microns[n]; - grain_misorientation_sum_z += grain_misorientation_z_vector[n] * grain_size_vector_microns[n]; + crystal_misorientation_sum_x += crystal_misorientation_x_vector[n] * grain_size_vector_microns[n]; + crystal_misorientation_sum_y += crystal_misorientation_y_vector[n] * grain_size_vector_microns[n]; + crystal_misorientation_sum_z += crystal_misorientation_z_vector[n] * grain_size_vector_microns[n]; } - float avg_misorientation_x = divideCast(grain_misorientation_sum_x, region_size_microns); - float avg_misorientation_y = divideCast(grain_misorientation_sum_y, region_size_microns); - float avg_misorientation_z = divideCast(grain_misorientation_sum_z, region_size_microns); + float avg_misorientation_x = divideCast(crystal_misorientation_sum_x, region_size_microns); + float avg_misorientation_y = divideCast(crystal_misorientation_sum_y, region_size_microns); + float avg_misorientation_z = divideCast(crystal_misorientation_sum_z, region_size_microns); std::string temp; temp = "-- Average misorientation (weighted by size) for grains relative to the X direction (in degrees): " + std::to_string(avg_misorientation_x) + "\n"; @@ -806,7 +807,7 @@ struct RepresentativeRegion { grainplot_pf << "% specimen symmetry: \"43\"" << std::endl; grainplot_pf << "% phi1 Phi phi2 value" << std::endl; grainplot_pf << std::fixed << std::setprecision(6); - for (int i = 0; i < orientation.n_grain_orientations; i++) { + for (int i = 0; i < orientation.n_crystal_orientations; i++) { grainplot_pf << orientation.grain_bunge_euler_host(3 * i, 0) << " " << orientation.grain_bunge_euler_host(3 * i + 1, 0) << " " << orientation.grain_bunge_euler_host(3 * i + 2, 0) << " " @@ -832,7 +833,7 @@ struct RepresentativeRegion { std::vector getIPFZColor(int color, Orientation &orientation) { std::vector ipfz_color(number_of_grains); for (int n = 0; n < number_of_grains; n++) { - int my_orientation = getGrainOrientation(unique_grain_id_vector[n], orientation.n_grain_orientations); + int my_orientation = getCrystalOrientation(unique_grain_id_vector[n], orientation.n_crystal_orientations); ipfz_color[n] = orientation.grain_rgb_ipfz_host(3 * my_orientation + color, 0); } return ipfz_color; @@ -898,7 +899,7 @@ struct RepresentativeRegion { throw std::runtime_error("Error: Unknown region_orientation input for WriteIPFColoredCrossSection: " "should be XY, YZ, or XZ"); // What orientation does this grain id correspond to? Should be between 0 and NumberOfOrientations-1 - int go_val = (Kokkos::abs(grain_id(z_loc, x_loc, y_loc)) - 1) % orientation.n_grain_orientations; + int go_val = (Kokkos::abs(grain_id(z_loc, x_loc, y_loc)) - 1) % orientation.n_crystal_orientations; // Unlike the vtk data which was zero-indexed (the two solid phase ids were 0 and 1), the grain // structure used by MTEX is phase "1" or "2" - any unindexed points with GOVal = -1 (which are possible // from regions that didn't undergo melting) are assigned phase "0" @@ -949,9 +950,9 @@ struct RepresentativeRegion { } // Write a csv file of stats for each grain - void writePerGrainStats(std::string output_filename, std::vector grain_misorientation_x_vector, - std::vector grain_misorientation_y_vector, - std::vector grain_misorientation_z_vector, + void writePerGrainStats(std::string output_filename, std::vector crystal_misorientation_x_vector, + std::vector crystal_misorientation_y_vector, + std::vector crystal_misorientation_z_vector, std::vector build_trans_aspect_ratio, std::vector grain_red, std::vector grain_green, std::vector grain_blue) { @@ -981,8 +982,8 @@ struct RepresentativeRegion { for (int n = 0; n < number_of_grains; n++) { grain_stats << unique_grain_id_vector[n]; if (analysis_options_per_grain_stats_yn[0]) - grain_stats << "," << grain_misorientation_x_vector[n] << "," << grain_misorientation_y_vector[n] << "," - << grain_misorientation_z_vector[n]; + grain_stats << "," << crystal_misorientation_x_vector[n] << "," << crystal_misorientation_y_vector[n] + << "," << crystal_misorientation_z_vector[n]; if (analysis_options_per_grain_stats_yn[1]) grain_stats << "," << grain_size_vector_microns[n]; if (analysis_options_per_grain_stats_yn[2]) diff --git a/analysis/src/GAutils.cpp b/analysis/src/GAutils.cpp index e24ca640..a60e5641 100644 --- a/analysis/src/GAutils.cpp +++ b/analysis/src/GAutils.cpp @@ -45,6 +45,12 @@ void parseLogFile(std::string log_file, int &nx, int &ny, int &nz, double &delta std::cout << "Note: orientation filename specified in log file will be used, overriding value from analysis " "input file" << std::endl; + + std::string crystal_orientation_input_label; + if (logdata.contains("GrainOrientationFile")) + crystal_orientation_input_label = "GrainOrientationFile"; + else + crystal_orientation_input_label = "CrystalOrientationFile"; if (logdata["PhaseName"].size() == 2) { phase_names.push_back(logdata["PhaseName"][0]); phase_names.push_back(logdata["PhaseName"][1]); @@ -53,13 +59,13 @@ void parseLogFile(std::string log_file, int &nx, int &ny, int &nz, double &delta // as materials without a transformation on solidification should only have one orientation file, and materials // with a transformation on solidification will have all final grain orientations map to a value from the first // file - if (logdata["GrainOrientationFile"].size() == 2) { - grain_unit_vector_file.push_back(logdata["GrainOrientationFile"][0]); - grain_unit_vector_file.push_back(logdata["GrainOrientationFile"][1]); + if (logdata[crystal_orientation_input_label].size() == 2) { + grain_unit_vector_file.push_back(logdata[crystal_orientation_input_label][0]); + grain_unit_vector_file.push_back(logdata[crystal_orientation_input_label][1]); } else { - grain_unit_vector_file.push_back(logdata["GrainOrientationFile"]); - grain_unit_vector_file.push_back(logdata["GrainOrientationFile"]); + grain_unit_vector_file.push_back(logdata[crystal_orientation_input_label]); + grain_unit_vector_file.push_back(logdata[crystal_orientation_input_label]); } num_phases = 2; } @@ -69,7 +75,7 @@ void parseLogFile(std::string log_file, int &nx, int &ny, int &nz, double &delta else phase_names.push_back("default"); num_phases = 1; - grain_unit_vector_file.push_back(logdata["GrainOrientationFile"]); + grain_unit_vector_file.push_back(logdata[crystal_orientation_input_label]); } input_data_stream.close(); } diff --git a/bin/run.cpp b/bin/run.cpp index fb984388..ad169b36 100644 --- a/bin/run.cpp +++ b/bin/run.cpp @@ -79,7 +79,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); // Initialize grain orientations - Orientation orientation(id, inputs.grain_orientation_file, false, inputs.rng_seed, + Orientation orientation(id, inputs.crystal_orientation_file, false, inputs.rng_seed, inputs.irf.num_phases, irf.solidificationTransformation()); MPI_Barrier(MPI_COMM_WORLD); diff --git a/bin/runCoupled.cpp b/bin/runCoupled.cpp index 850f8e7c..89613f98 100644 --- a/bin/runCoupled.cpp +++ b/bin/runCoupled.cpp @@ -194,7 +194,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); // Initialize grain orientations - Orientation orientation(id, inputs.grain_orientation_file, false, inputs.rng_seed, + Orientation orientation(id, inputs.crystal_orientation_file, false, inputs.rng_seed, inputs.irf.num_phases, irf.solidificationTransformation()); MPI_Barrier(MPI_COMM_WORLD); diff --git a/examples/Inp_DirSolidification.json b/examples/Inp_DirSolidification.json index 5155b79c..1a885925 100644 --- a/examples/Inp_DirSolidification.json +++ b/examples/Inp_DirSolidification.json @@ -1,7 +1,7 @@ { "SimulationType": "Directional", "MaterialFileName": "Inconel625.json", - "GrainOrientationFile": "GrainOrientationVectors.csv", + "CrystalOrientationFile": "CrystalOrientationVectors.csv", "RandomSeed": 0, "Domain": { "CellSize": 1, @@ -29,11 +29,11 @@ "PrintExaConstitSize": 0, "Intralayer": { "Increment": 5250, - "Fields": ["GrainMisorientation"], + "Fields": ["CrystalMisorientationZ"], "PrintIdleFrames": false }, "Interlayer": { - "Fields": ["GrainID", "LayerID", "GrainMisorientation"] + "Fields": ["GrainID", "LayerID", "CrystalMisorientationZ"] } } } diff --git a/examples/Inp_EquiaxedGrain.json b/examples/Inp_EquiaxedGrain.json index 562a947c..e5c6c2a5 100644 --- a/examples/Inp_EquiaxedGrain.json +++ b/examples/Inp_EquiaxedGrain.json @@ -1,7 +1,7 @@ { "SimulationType": "SingleGrain", "MaterialFileName": "Inconel625.json", - "GrainOrientationFile": "GrainOrientationVectors.csv", + "CrystalOrientationFile": "CrystalOrientationVectors.csv", "Domain": { "CellSize": 1, "TimeStep": 0.0666667, diff --git a/examples/Inp_Finch.json b/examples/Inp_Finch.json index c5e7ae65..524a4610 100644 --- a/examples/Inp_Finch.json +++ b/examples/Inp_Finch.json @@ -36,7 +36,7 @@ "ExaCA": { "SimulationType": "FromFinch", "MaterialFileName": "Inconel625.json", - "GrainOrientationFile": "GrainOrientationVectors.csv", + "CrystalOrientationFile": "CrystalOrientationVectors.csv", "RandomSeed": 0, "Domain": { "CellSize": 3, @@ -61,7 +61,7 @@ "PrintBinary": true, "PrintExaConstitSize": 0, "Interlayer": { - "Fields": ["GrainID", "LayerID", "GrainMisorientation"] + "Fields": ["GrainID", "LayerID", "CrystalMisorientationZ"] } } } diff --git a/examples/Inp_FinchTranslate.json b/examples/Inp_FinchTranslate.json index 667cceea..2f0cff5a 100644 --- a/examples/Inp_FinchTranslate.json +++ b/examples/Inp_FinchTranslate.json @@ -36,7 +36,7 @@ "ExaCA": { "SimulationType": "FromFinch", "MaterialFileName": "Inconel625.json", - "GrainOrientationFile": "GrainOrientationVectors.csv", + "CrystalOrientationFile": "CrystalOrientationVectors.csv", "RandomSeed": 0, "Domain": { "CellSize": 3, @@ -65,7 +65,7 @@ "PrintBinary": true, "PrintExaConstitSize": 0, "Interlayer": { - "Fields": ["CritTimeStep", "LayerID", "GrainMisorientation"] + "Fields": ["CritTimeStep", "LayerID", "CrystalMisorientationZ"] } } } diff --git a/examples/Inp_FinchVariedLayers.json b/examples/Inp_FinchVariedLayers.json index 36356bb1..375d9fc3 100644 --- a/examples/Inp_FinchVariedLayers.json +++ b/examples/Inp_FinchVariedLayers.json @@ -54,7 +54,7 @@ "ExaCA": { "SimulationType": "FromFinch", "MaterialFileName": "Inconel625.json", - "GrainOrientationFile": "GrainOrientationVectors.csv", + "CrystalOrientationFile": "CrystalOrientationVectors.csv", "RandomSeed": 0, "Domain": { "CellSize": 3, @@ -80,7 +80,7 @@ "PrintBinary": true, "PrintExaConstitSize": 0, "Interlayer": { - "Fields": ["GrainID", "LayerID", "GrainMisorientation"] + "Fields": ["GrainID", "LayerID", "CrystalMisorientationZ"] } } } diff --git a/examples/Inp_SingleLine.json b/examples/Inp_SingleLine.json index e283aae6..cadea039 100644 --- a/examples/Inp_SingleLine.json +++ b/examples/Inp_SingleLine.json @@ -1,7 +1,7 @@ { "SimulationType": "FromFile", "MaterialFileName": "Inconel625.json", - "GrainOrientationFile": "GrainOrientationVectors.csv", + "CrystalOrientationFile": "CrystalOrientationVectors.csv", "RandomSeed": 0, "Domain": { "CellSize": 2.5, @@ -29,7 +29,7 @@ "PrintBinary": false, "PrintExaConstitSize": 0, "Interlayer": { - "Fields": ["GrainID", "LayerID", "GrainMisorientation"] + "Fields": ["GrainID", "LayerID", "CrystalMisorientationZ"] } } } diff --git a/examples/Inp_SingleLineTranslate.json b/examples/Inp_SingleLineTranslate.json index 2e883072..4edd3b11 100644 --- a/examples/Inp_SingleLineTranslate.json +++ b/examples/Inp_SingleLineTranslate.json @@ -1,7 +1,7 @@ { "SimulationType": "FromFile", "MaterialFileName": "Inconel625.json", - "GrainOrientationFile": "GrainOrientationVectors.csv", + "CrystalOrientationFile": "CrystalOrientationVectors.csv", "RandomSeed": 0, "Domain": { "CellSize": 2.5, @@ -35,7 +35,7 @@ "PrintBinary": false, "PrintExaConstitSize": 0, "Interlayer": { - "Fields": ["GrainID", "LayerID", "CritTimeStep", "GrainMisorientation"] + "Fields": ["GrainID", "LayerID", "CritTimeStep", "CrystalMisorientationZ"] } } } diff --git a/examples/Inp_SmallDirSolidification.json b/examples/Inp_SmallDirSolidification.json index db2e1470..428c4656 100644 --- a/examples/Inp_SmallDirSolidification.json +++ b/examples/Inp_SmallDirSolidification.json @@ -1,7 +1,7 @@ { "SimulationType": "Directional", "MaterialFileName": "Inconel625.json", - "GrainOrientationFile": "GrainOrientationVectors.csv", + "CrystalOrientationFile": "CrystalOrientationVectors.csv", "RandomSeed": 0, "Domain": { "CellSize": 1, @@ -28,7 +28,7 @@ "PrintBinary": false, "PrintExaConstitSize": 0, "Interlayer": { - "Fields": ["GrainID", "LayerID", "GrainMisorientation"] + "Fields": ["GrainID", "LayerID", "CrystalMisorientationZ"] } } } diff --git a/examples/Inp_SmallEquiaxedGrain.json b/examples/Inp_SmallEquiaxedGrain.json index 48cd13e4..096bc83c 100644 --- a/examples/Inp_SmallEquiaxedGrain.json +++ b/examples/Inp_SmallEquiaxedGrain.json @@ -1,7 +1,7 @@ { "SimulationType": "SingleGrain", "MaterialFileName": "Inconel625.json", - "GrainOrientationFile": "GrainOrientationVectors.csv", + "CrystalOrientationFile": "CrystalOrientationVectors.csv", "Domain": { "CellSize": 1, "TimeStep": 0.0666667, diff --git a/examples/Inp_SmallFinch.json b/examples/Inp_SmallFinch.json index b7662945..fafd4ebd 100644 --- a/examples/Inp_SmallFinch.json +++ b/examples/Inp_SmallFinch.json @@ -36,7 +36,7 @@ "ExaCA": { "SimulationType": "FromFinch", "MaterialFileName": "Inconel625.json", - "GrainOrientationFile": "GrainOrientationVectors.csv", + "CrystalOrientationFile": "CrystalOrientationVectors.csv", "RandomSeed": 0, "Domain": { "CellSize": 10, @@ -58,7 +58,7 @@ "PrintBinary": true, "PrintExaConstitSize": 0, "Interlayer": { - "Fields": ["LayerID", "GrainMisorientation"] + "Fields": ["LayerID", "CrystalMisorientationZ"] } } } diff --git a/examples/Inp_SmallSpotMelt.json b/examples/Inp_SmallSpotMelt.json index c1b08bfd..04520d87 100644 --- a/examples/Inp_SmallSpotMelt.json +++ b/examples/Inp_SmallSpotMelt.json @@ -1,7 +1,7 @@ { "SimulationType": "Spot", "MaterialFileName": "Inconel625.json", - "GrainOrientationFile": "GrainOrientationVectors.csv", + "CrystalOrientationFile": "CrystalOrientationVectors.csv", "RandomSeed": 0, "Domain": { "CellSize": 1, @@ -28,11 +28,11 @@ "PrintExaConstitSize": 0, "Intralayer": { "Increment": 2000, - "Fields": ["GrainMisorientation"], + "Fields": ["CrystalMisorientationZ"], "PrintIdleFrames": true }, "Interlayer": { - "Fields": ["GrainID", "LayerID", "GrainMisorientation"] + "Fields": ["GrainID", "LayerID", "CrystalMisorientationZ"] } } } diff --git a/examples/Inp_SmallSpotMelt_Steel1phase.json b/examples/Inp_SmallSpotMelt_Steel1phase.json index d94bcdf0..25ed1c16 100644 --- a/examples/Inp_SmallSpotMelt_Steel1phase.json +++ b/examples/Inp_SmallSpotMelt_Steel1phase.json @@ -1,7 +1,7 @@ { "SimulationType": "Spot", "MaterialFileName": "SS316L_Austenite.json", - "GrainOrientationFile": "GrainOrientationVectors.csv", + "GrainOrientationFile": "CrystalOrientationVectors.csv", "RandomSeed": 0, "Domain": { "CellSize": 1, @@ -26,7 +26,7 @@ "PrintBinary": false, "PrintExaConstitSize": 0, "Interlayer": { - "Fields": ["GrainID", "PhaseID", "GrainMisorientation"] + "Fields": ["GrainID", "PhaseID", "CrystalMisorientationZ"] } } } diff --git a/examples/Inp_SmallSpotMelt_Steel2phase.json b/examples/Inp_SmallSpotMelt_Steel2phase.json index bd4c8929..8d451b1b 100644 --- a/examples/Inp_SmallSpotMelt_Steel2phase.json +++ b/examples/Inp_SmallSpotMelt_Steel2phase.json @@ -1,7 +1,7 @@ { "SimulationType": "Spot", "MaterialFileName": "SS316L_AusteniteFerrite.json", - "GrainOrientationFile": "GrainOrientationVectors.csv", + "CrystalOrientationFile": "CrystalOrientationVectors.csv", "RandomSeed": 0, "Domain": { "CellSize": 1, @@ -26,7 +26,7 @@ "PrintBinary": false, "PrintExaConstitSize": 0, "Interlayer": { - "Fields": ["GrainID", "PhaseID", "GrainMisorientation"] + "Fields": ["GrainID", "PhaseID", "CrystalMisorientationZ"] } } } diff --git a/examples/Inp_SpotMelt.json b/examples/Inp_SpotMelt.json index ab17d04e..8d01cff3 100644 --- a/examples/Inp_SpotMelt.json +++ b/examples/Inp_SpotMelt.json @@ -1,7 +1,7 @@ { "SimulationType": "Spot", "MaterialFileName": "Inconel625.json", - "GrainOrientationFile": "GrainOrientationVectors.csv", + "CrystalOrientationFile": "CrystalOrientationVectors.csv", "RandomSeed": 0, "Domain": { "CellSize": 1, @@ -28,11 +28,11 @@ "PrintExaConstitSize": 0, "Intralayer": { "Increment": 2000, - "Fields": ["GrainMisorientation", "MeltTimeStep", "CritTimeStep"], + "Fields": ["CrystalMisorientationZ", "MeltTimeStep", "CritTimeStep"], "PrintIdleFrames": true }, "Interlayer": { - "Fields": ["GrainID", "LayerID", "GrainMisorientation"] + "Fields": ["GrainID", "LayerID", "CrystalMisorientationZ"] } } } diff --git a/examples/Inp_TwoGrainDirSolidification.json b/examples/Inp_TwoGrainDirSolidification.json index 9bc07583..bb9e67cd 100644 --- a/examples/Inp_TwoGrainDirSolidification.json +++ b/examples/Inp_TwoGrainDirSolidification.json @@ -1,7 +1,7 @@ { "SimulationType": "Directional", "MaterialFileName": "Inconel625.json", - "GrainOrientationFile": "GrainOrientationVectors.csv", + "CrystalOrientationFile": "CrystalOrientationVectors.csv", "RandomSeed": 0, "Domain": { "CellSize": 1, @@ -33,11 +33,11 @@ "PrintExaConstitSize": 0, "Intralayer": { "Increment": 5250, - "Fields": ["GrainMisorientation"], + "Fields": ["CrystalMisorientationZ"], "PrintIdleFrames": false }, "Interlayer": { - "Fields": ["GrainID", "LayerID", "GrainMisorientation"] + "Fields": ["GrainID", "LayerID", "CrystalMisorientationZ"] } } } diff --git a/examples/Inp_TwoLineTwoLayer.json b/examples/Inp_TwoLineTwoLayer.json index 485197e9..bc377ebf 100644 --- a/examples/Inp_TwoLineTwoLayer.json +++ b/examples/Inp_TwoLineTwoLayer.json @@ -1,7 +1,7 @@ { "SimulationType": "FromFile", "MaterialFileName": "Inconel625.json", - "GrainOrientationFile": "GrainOrientationVectors.csv", + "CrystalOrientationFile": "CrystalOrientationVectors.csv", "RandomSeed": 0, "Domain": { "CellSize": 2.5, @@ -28,7 +28,7 @@ "PrintBinary": false, "PrintExaConstitSize": 0, "Interlayer": { - "Fields": ["GrainID", "LayerID", "GrainMisorientation", "UndercoolingCurrent", "SolidificationEventCounter"], + "Fields": ["GrainID", "LayerID", "CrystalMisorientationZ", "UndercoolingCurrent", "SolidificationEventCounter"], "Layers": [0, 1] } } diff --git a/examples/Substrate/GrainOrientationEulerAnglesBungeZXZ.csv b/examples/Substrate/CrystalOrientationEulerAnglesBungeZXZ.csv similarity index 100% rename from examples/Substrate/GrainOrientationEulerAnglesBungeZXZ.csv rename to examples/Substrate/CrystalOrientationEulerAnglesBungeZXZ.csv diff --git a/examples/Substrate/GrainOrientationRGB_IPF-Z.csv b/examples/Substrate/CrystalOrientationRGB_IPF-Z.csv similarity index 100% rename from examples/Substrate/GrainOrientationRGB_IPF-Z.csv rename to examples/Substrate/CrystalOrientationRGB_IPF-Z.csv diff --git a/examples/Substrate/GrainOrientationVectors.csv b/examples/Substrate/CrystalOrientationVectors.csv similarity index 100% rename from examples/Substrate/GrainOrientationVectors.csv rename to examples/Substrate/CrystalOrientationVectors.csv diff --git a/src/CAinputdata.hpp b/src/CAinputdata.hpp index af533be2..40b163db 100644 --- a/src/CAinputdata.hpp +++ b/src/CAinputdata.hpp @@ -128,20 +128,24 @@ struct PrintInputs { std::vector required_print_field = {true, true, false, false, false, false, false}; // Names of output fields that can be printed to files during or at the end of a simulation - std::vector fieldnames_key = {"GrainID", - "LayerID", - "PhaseID", - "GrainMisorientation", - "UndercoolingCurrent", - "UndercoolingSolidificationStart", - "MeltPoolEdge", - "MeltTimeStep", - "CritTimeStep", - "UndercoolingChange", - "CellType", - "DiagonalLength", - "SolidificationEventCounter", - "NumberOfSolidificationEvents"}; + std::vector fieldnames_key = { + "GrainID", + "LayerID", + "PhaseID", + "CrystalMisorientationX", + "CrystalMisorientationY", + "CrystalMisorientationZ", + "UndercoolingCurrent", + "UndercoolingSolidificationStart", + "MeltPoolEdge", + "MeltTimeStep", + "CritTimeStep", + "UndercoolingChange", + "CellType", + "DiagonalLength", + "SolidificationEventCounter", + "NumberOfSolidificationEvents", + }; // Fields to be printed during a given layer bool intralayer = false; int intralayer_increment = 1; @@ -150,7 +154,7 @@ struct PrintInputs { bool intralayer_grain_id = false; bool intralayer_layer_id = false; bool intralayer_phase_id = false; - bool intralayer_grain_misorientation = false; + std::vector intralayer_crystal_misorientation; bool intralayer_undercooling_current = false; bool intralayer_undercooling_solidification_start = false; bool intralayer_melt_time_step = false; @@ -167,7 +171,7 @@ struct PrintInputs { bool interlayer_grain_id = false; bool interlayer_phase_id = false; bool interlayer_layer_id = false; - bool interlayer_grain_misorientation = false; + std::vector interlayer_crystal_misorientation; bool interlayer_undercooling_solidification_start = false; bool interlayer_undercooling_current = false; bool interlayer_melt_time_step = false; diff --git a/src/CAinputs.hpp b/src/CAinputs.hpp index 550b40f3..7c2deae6 100644 --- a/src/CAinputs.hpp +++ b/src/CAinputs.hpp @@ -25,7 +25,7 @@ struct Inputs { std::string simulation_type = "", material_filename = ""; - std::vector grain_orientation_file = {}; + std::vector crystal_orientation_file = {}; unsigned long rng_seed = 0.0; DomainInputs domain; NucleationInputs nucleation; @@ -60,7 +60,15 @@ struct Inputs { // Get interfacial response function coefficients and freezing range from the material input file parseIRF(id); // Path to file of grain orientations based on install/source location - std::vector grain_orientation_file_read; + std::vector crystal_orientation_file_read; + std::string crystallographic_input_name = "CrystalOrientationFile"; + if (input_data.contains("GrainOrientationFile")) { + if (id == 0) + std::cout << "Warning: Input `GrainOrientationFile` has been renamed `CrystalOrientationFile`; " + "compatibility with the old name will be removed in a future release" + << std::endl; + crystallographic_input_name = "GrainOrientationFile"; + } // For two phase problems, each grain is associated with a crystallographic orientation and a phase // One orientation file, no transformation: one orientation per grain, no change during solidification (same as // single phase) One orientation file, solidification transformation: randomly selected grain orientation from @@ -72,29 +80,29 @@ struct Inputs { // orientations on solidification If one orientation file is given, this is used for any phases in the material. // If two are given, this must be a two phase problem and the solidification transformation rule must be // selected - if (input_data["GrainOrientationFile"].size() == 1) { - grain_orientation_file_read.push_back(input_data["GrainOrientationFile"]); + if (input_data[crystallographic_input_name].size() == 1) { + crystal_orientation_file_read.push_back(input_data[crystallographic_input_name]); if (irf.num_phases == 2) - grain_orientation_file_read.push_back(input_data["GrainOrientationFile"]); + crystal_orientation_file_read.push_back(input_data[crystallographic_input_name]); } - else if (input_data["GrainOrientationFile"].size() == 2) { + else if (input_data[crystallographic_input_name].size() == 2) { if ((irf.num_phases == 1) && (id == 0)) - throw std::runtime_error("Error: Only one grain orientation file should be specified for a material " + throw std::runtime_error("Error: Only one crystal orientation file should be specified for a material " "with one interfacial response function"); if ((irf.transformation == irf.none) && (id == 0)) - throw std::runtime_error("Error: Only one grain orientation file should be specified for a material " + throw std::runtime_error("Error: Only one crystal orientation file should be specified for a material " "without a phase transformation rule"); - grain_orientation_file_read.push_back(input_data["GrainOrientationFile"][0]); - grain_orientation_file_read.push_back(input_data["GrainOrientationFile"][1]); + crystal_orientation_file_read.push_back(input_data[crystallographic_input_name][0]); + crystal_orientation_file_read.push_back(input_data[crystallographic_input_name][1]); } else { if (id == 0) throw std::runtime_error("Error: No more than two grain orientation files should be given"); } for (int phase_num = 0; phase_num < irf.num_phases; phase_num++) { - std::string grain_orientation_file_tmp = checkFileInstalled(grain_orientation_file_read[phase_num], id); - checkFileNotEmpty(grain_orientation_file_tmp); - grain_orientation_file.push_back(grain_orientation_file_tmp); + std::string crystal_orientation_file_tmp = checkFileInstalled(crystal_orientation_file_read[phase_num], id); + checkFileNotEmpty(crystal_orientation_file_tmp); + crystal_orientation_file.push_back(crystal_orientation_file_tmp); } // Seed for random number generator (defaults to 0 if not given) if (input_data.contains("RandomSeed")) @@ -573,10 +581,21 @@ struct Inputs { valid_field = true; } } - if ((!valid_field) && (id == 0)) { - std::string error = "Error: Field '" + field_read + "' from " + fieldtype + - " Printing section of input file is not recognized by ExaCA"; - throw std::runtime_error(error); + if (!valid_field) { + // Check for deprecated input GrainMisorientation + if (field_read == "GrainMisorientation") { + if (id == 0) + std::cout << "Warning: Output field `GrainMisorientation` has been renamed " + "CrystalMisorientationZ; use of field name `GrainMisorientation` has been " + "deprecated and will be removed in a future release" + << std::endl; + print_fields_given[5] = true; + } + else if (id == 0) { + std::string error = "Error: Field '" + field_read + "' from " + fieldtype + + " Printing section of input file is not recognized by ExaCA"; + throw std::runtime_error(error); + } } } return print_fields_given; @@ -626,27 +645,31 @@ struct Inputs { print.intralayer_layer_id = true; if (print_fields_intralayer[2]) print.intralayer_phase_id = true; - if (print_fields_intralayer[3]) - print.intralayer_grain_misorientation = true; - if (print_fields_intralayer[4]) + for (int dir = 3; dir < 6; dir++) { + if (print_fields_intralayer[dir]) + print.intralayer_crystal_misorientation.push_back(true); + else + print.intralayer_crystal_misorientation.push_back(false); + } + if (print_fields_intralayer[6]) print.intralayer_undercooling_current = true; - if (print_fields_intralayer[5]) + if (print_fields_intralayer[7]) print.intralayer_undercooling_solidification_start = true; - if (print_fields_intralayer[6]) + if (print_fields_intralayer[8]) print.intralayer_melt_pool_edge = true; - if (print_fields_intralayer[7]) + if (print_fields_intralayer[9]) print.intralayer_melt_time_step = true; - if (print_fields_intralayer[8]) + if (print_fields_intralayer[10]) print.intralayer_crit_time_step = true; - if (print_fields_intralayer[9]) + if (print_fields_intralayer[11]) print.intralayer_undercooling_change = true; - if (print_fields_intralayer[10]) + if (print_fields_intralayer[12]) print.intralayer_cell_type = true; - if (print_fields_intralayer[11]) + if (print_fields_intralayer[13]) print.intralayer_diagonal_length = true; - if (print_fields_intralayer[12]) + if (print_fields_intralayer[14]) print.intralayer_solidification_event_counter = true; - if (print_fields_intralayer[13]) + if (print_fields_intralayer[15]) print.intralayer_number_of_solidification_events = true; // True if any fields are printed @@ -657,7 +680,7 @@ struct Inputs { } // Will fields other than grain misorientations be printed? for (int n = 0; n < num_print_intralayer_inputs; n++) { - if ((n != 3) && (print_fields_intralayer[n])) + if (((n < 3) || (n > 5)) && (print_fields_intralayer[n])) print.intralayer_non_misorientation_fields = true; } } @@ -703,34 +726,38 @@ struct Inputs { print.interlayer_layer_id = true; if (print_fields_interlayer[2]) print.interlayer_phase_id = true; - if (print_fields_interlayer[3]) - print.interlayer_grain_misorientation = true; - if (print_fields_interlayer[4]) + for (int dir = 3; dir < 6; dir++) { + if (print_fields_interlayer[dir]) + print.interlayer_crystal_misorientation.push_back(true); + else + print.interlayer_crystal_misorientation.push_back(false); + } + if (print_fields_interlayer[6]) print.interlayer_undercooling_current = true; - if (print_fields_interlayer[5]) + if (print_fields_interlayer[7]) print.interlayer_undercooling_solidification_start = true; - if (print_fields_interlayer[6]) + if (print_fields_interlayer[8]) print.interlayer_melt_pool_edge = true; - if (print_fields_interlayer[7]) + if (print_fields_interlayer[9]) print.interlayer_melt_time_step = true; - if (print_fields_interlayer[8]) + if (print_fields_interlayer[10]) print.interlayer_crit_time_step = true; - if (print_fields_interlayer[9]) + if (print_fields_interlayer[11]) print.interlayer_undercooling_change = true; - if (print_fields_interlayer[10]) + if (print_fields_interlayer[12]) print.interlayer_cell_type = true; - if (print_fields_interlayer[11]) + if (print_fields_interlayer[13]) print.interlayer_diagonal_length = true; - if (print_fields_interlayer[12]) + if (print_fields_interlayer[14]) print.interlayer_solidification_event_counter = true; - if (print_fields_interlayer[13]) + if (print_fields_interlayer[15]) print.interlayer_number_of_solidification_events = true; if ((print.interlayer_grain_id) || (print.interlayer_phase_id) || (print.interlayer_undercooling_current) || (print.interlayer_undercooling_solidification_start)) print.interlayer_full = true; - // First 7 inputs are full domain inputs - check if any of the others were toggled + // First 9 inputs are full domain inputs - check if any of the others were toggled int num_interlayer_current_inputs = print_fields_interlayer.size(); - for (int n = 7; n < num_interlayer_current_inputs; n++) { + for (int n = 9; n < num_interlayer_current_inputs; n++) { if (print_fields_interlayer[n]) print.interlayer_current = true; } @@ -774,16 +801,17 @@ struct Inputs { exaca_log << " \"MaterialFileName\": \"" << material_filename << "\"," << std::endl; if (irf.num_phases == 1) { exaca_log << " \"PhaseName\": \"" << irf.phase_names[0] << "\"," << std::endl; - exaca_log << " \"GrainOrientationFile\": \"" << grain_orientation_file[0] << "\"," << std::endl; + exaca_log << " \"CrystalOrientationFile\": \"" << crystal_orientation_file[0] << "\"," << std::endl; } else if (irf.num_phases == 2) { exaca_log << " \"PhaseName\": [\"" << irf.phase_names[0] << "\", \"" << irf.phase_names[1] << "\"]," << std::endl; if (irf.transformation == irf.solidification) - exaca_log << " \"GrainOrientationFile\": [\"" << grain_orientation_file[0] << "\", \"" - << grain_orientation_file[1] << "\"]," << std::endl; + exaca_log << " \"CrystalOrientationFile\": [\"" << crystal_orientation_file[0] << "\", \"" + << crystal_orientation_file[1] << "\"]," << std::endl; else - exaca_log << " \"GrainOrientationFile\": \"" << grain_orientation_file[0] << "\"," << std::endl; + exaca_log << " \"CrystalOrientationFile\": \"" << crystal_orientation_file[0] << "\"," + << std::endl; } exaca_log << " \"Domain\": {" << std::endl; exaca_log << " \"Nx\": " << grid.nx << "," << std::endl; diff --git a/src/CAinterface.hpp b/src/CAinterface.hpp index fb3c2c37..7f15c37b 100644 --- a/src/CAinterface.hpp +++ b/src/CAinterface.hpp @@ -274,7 +274,7 @@ struct Interface { const float ghost_octahedron_center_y, const float ghost_octahedron_center_z, const float ghost_diagonal_length, const int ghost_phase_id, const int ny_local, const int coord_x, const int coord_y, const int coord_z, const bool at_north_boundary, - const bool at_south_boundary, const int n_grain_orientations) const { + const bool at_south_boundary, const int n_crystal_orientations) const { bool data_fits_in_buffer = true; if ((coord_y == 1) && (!(at_south_boundary))) { int ghost_position_south = Kokkos::atomic_fetch_add(&send_size_south(0), 1); @@ -284,9 +284,9 @@ struct Interface { buffer_south_send(ghost_position_south, 0) = static_cast(coord_x); buffer_south_send(ghost_position_south, 1) = static_cast(coord_z); buffer_south_send(ghost_position_south, 2) = - static_cast(getGrainOrientation(ghost_grain_id, n_grain_orientations, false)); + static_cast(getCrystalOrientation(ghost_grain_id, n_crystal_orientations, false)); buffer_south_send(ghost_position_south, 3) = - static_cast(getGrainNumber(ghost_grain_id, n_grain_orientations)); + static_cast(getGrainNumber(ghost_grain_id, n_crystal_orientations)); buffer_south_send(ghost_position_south, 4) = ghost_octahedron_center_x; buffer_south_send(ghost_position_south, 5) = ghost_octahedron_center_y; buffer_south_send(ghost_position_south, 6) = ghost_octahedron_center_z; @@ -302,9 +302,9 @@ struct Interface { buffer_north_send(ghost_position_north, 0) = static_cast(coord_x); buffer_north_send(ghost_position_north, 1) = static_cast(coord_z); buffer_north_send(ghost_position_north, 2) = - static_cast(getGrainOrientation(ghost_grain_id, n_grain_orientations, false)); + static_cast(getCrystalOrientation(ghost_grain_id, n_crystal_orientations, false)); buffer_north_send(ghost_position_north, 3) = - static_cast(getGrainNumber(ghost_grain_id, n_grain_orientations)); + static_cast(getGrainNumber(ghost_grain_id, n_crystal_orientations)); buffer_north_send(ghost_position_north, 4) = ghost_octahedron_center_x; buffer_north_send(ghost_position_north, 5) = ghost_octahedron_center_y; buffer_north_send(ghost_position_north, 6) = ghost_octahedron_center_z; diff --git a/src/CAorientation.hpp b/src/CAorientation.hpp index 3b94a499..af379682 100644 --- a/src/CAorientation.hpp +++ b/src/CAorientation.hpp @@ -36,7 +36,7 @@ struct Orientation { // orientation), or RGB values (3 vals per orientation). Unit vectors are stored on the device and no host copy is // maintained in the struct, Euler and RGB representations are only used on the host and no device copy is // maintained - int n_grain_orientations; + int n_crystal_orientations; // Second dimension unused if second phase shares grain orientation with first, or the material only contains 1 // phase view_type_float_2d grain_unit_vector; @@ -80,7 +80,7 @@ struct Orientation { const int vals_per_line, const bool check_n_orientations, unsigned long rng_seed) { - // Resize view for storing grain orientations read from file based on a guess for n_grain_orientations (10000 + // Resize view for storing grain orientations read from file based on a guess for n_crystal_orientations (10000 // used here) view_type_float_2d_host orientation_data_host(Kokkos::ViewAllocateWithoutInitializing("orientation_data_host"), vals_per_line * 10000, _num_phases); @@ -91,24 +91,24 @@ struct Orientation { // Line 1 is the number of orientation values to read (if check_n_orientations is false, store this value as // n_orientations in the struct. Otherwise, read this value and check that it matches n_orientations) - std::string n_grain_orientations_read; - getline(orientation_input_stream, n_grain_orientations_read); + std::string n_crystal_orientations_read; + getline(orientation_input_stream, n_crystal_orientations_read); // If reading 2 files, number of grain orientations must match if ((check_n_orientations) || (phase_num == 1)) { - int n_grain_orientations_check = getInputInt(n_grain_orientations_read); - if (n_grain_orientations != n_grain_orientations_check) + int n_crystal_orientations_check = getInputInt(n_crystal_orientations_read); + if (n_crystal_orientations != n_crystal_orientations_check) throw std::runtime_error("Error: The number of orientations given on the first line of all " "orientation files must match"); } else - n_grain_orientations = getInputInt(n_grain_orientations_read); + n_crystal_orientations = getInputInt(n_crystal_orientations_read); // Resize view for storing grain orientations read from file based on the known value for - // n_grain_orientations - Kokkos::resize(orientation_data_host, vals_per_line * n_grain_orientations, _num_phases); + // n_crystal_orientations + Kokkos::resize(orientation_data_host, vals_per_line * n_crystal_orientations, _num_phases); // Populate data structure for grain orientation data and return the view - for (int i = 0; i < n_grain_orientations; i++) { + for (int i = 0; i < n_crystal_orientations; i++) { std::vector parsed_line(vals_per_line); std::string read_line; if (!getline(orientation_input_stream, read_line)) @@ -127,13 +127,13 @@ struct Orientation { // secondary phase orientations if (_num_phases == 2) { if (orientation_file[0] == orientation_file[1]) { - std::vector orientation_permutation_vector(n_grain_orientations); + std::vector orientation_permutation_vector(n_crystal_orientations); std::mt19937_64 orientation_generator(rng_seed); - for (int i = 0; i < n_grain_orientations; i++) + for (int i = 0; i < n_crystal_orientations; i++) orientation_permutation_vector[i] = i; std::shuffle(orientation_permutation_vector.begin(), orientation_permutation_vector.end(), orientation_generator); - for (int i = 0; i < n_grain_orientations; i++) { + for (int i = 0; i < n_crystal_orientations; i++) { for (int comp = 0; comp < vals_per_line; comp++) orientation_data_host(vals_per_line * i + comp, 1) = orientation_data_host(vals_per_line * orientation_permutation_vector[i] + comp, 1); @@ -150,10 +150,10 @@ struct Orientation { for (int phase_num = 0; phase_num < _num_phases; phase_num++) { std::string grain_unit_vector_file_p = grain_unit_vector_file[phase_num]; std::string euler_angles_filename_p, rgb_filename_p; - if (grain_unit_vector_file_p.find("GrainOrientationVectors.csv") != std::string::npos) { + if (grain_unit_vector_file_p.find("CrystalOrientationVectors.csv") != std::string::npos) { // Default files for euler angles and RGB mapping - euler_angles_filename_p = "GrainOrientationEulerAnglesBungeZXZ.csv"; - rgb_filename_p = "GrainOrientationRGB_IPF-Z.csv"; + euler_angles_filename_p = "CrystalOrientationEulerAnglesBungeZXZ.csv"; + rgb_filename_p = "CrystalOrientationRGB_IPF-Z.csv"; } else { // Custom files for euler angles and RGB mapping based on rotation filename @@ -166,8 +166,8 @@ struct Orientation { std::string customname = baseorientationname.substr(customname_startpos + 1, endpos - customname_startpos - 1); euler_angles_filename_p = - pathtoorientations + "GrainOrientationEulerAnglesBungeZXZ_" + customname + ".csv"; - rgb_filename_p = pathtoorientations + "GrainOrientationRGB_IPF-Z_" + customname + ".csv"; + pathtoorientations + "CrystalOrientationEulerAnglesBungeZXZ_" + customname + ".csv"; + rgb_filename_p = pathtoorientations + "CrystalOrientationRGB_IPF-Z_" + customname + ".csv"; } // Full path to install location was already given for the rotations file, need to check install location // for other files and ensure they are not empty @@ -185,19 +185,19 @@ struct Orientation { grain_rgb_ipfz_host = getOrientationsFromFile(rgb_filename, 3, true, rng_seed); } - // Create a view of size "n_grain_orientations" of the misorientation of each possible grain orientation with the X, - // Y, or Z directions (dir = 0, 1, or 2, respectively) + // Create a view of size "n_crystal_orientations" of the misorientation of each possible grain orientation with the + // X, Y, or Z directions (dir = 0, 1, or 2, respectively) view_type_float_2d_host misorientationCalc(const int dir) { - view_type_float_2d_host grain_misorientation(Kokkos::ViewAllocateWithoutInitializing("GrainMisorientation"), - n_grain_orientations, _num_phases); + view_type_float_2d_host crystal_misorientation(Kokkos::ViewAllocateWithoutInitializing("CrystalMisorientation"), + n_crystal_orientations, _num_phases); view_type_float_2d_host grain_unit_vector_host = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), grain_unit_vector); for (int phase_num = 0; phase_num < _num_phases; phase_num++) { // Find the smallest possible misorientation between the specified direction, and this grain orientations' 6 // possible 001 directions (where 54.7356 degrees is the largest possible misorientation between a 001 and a // given cardinal direction for the cubic crystal system) - for (int n = 0; n < n_grain_orientations; n++) { + for (int n = 0; n < n_crystal_orientations; n++) { float misorientation_angle_min = 54.7356; for (int ll = 0; ll < 3; ll++) { float misorientation = @@ -207,34 +207,34 @@ struct Orientation { misorientation_angle_min = misorientation; } } - grain_misorientation(n, phase_num) = misorientation_angle_min; + crystal_misorientation(n, phase_num) = misorientation_angle_min; } } - return grain_misorientation; + return crystal_misorientation; } }; // Inline functions // Get the grain ID from the repeat number of a grain from a given grain ID and the number of possible orientations -KOKKOS_INLINE_FUNCTION int getGrainID(const int my_grain_orientation, const int my_grain_number, - const int n_grain_orientations) { - int my_grain_id = n_grain_orientations * (Kokkos::abs(my_grain_number) - 1) + my_grain_orientation; +KOKKOS_INLINE_FUNCTION int getGrainID(const int my_crystal_orientation, const int my_grain_number, + const int n_crystal_orientations) { + int my_grain_id = n_crystal_orientations * (Kokkos::abs(my_grain_number) - 1) + my_crystal_orientation; if (my_grain_number < 0) my_grain_id = -my_grain_id; return my_grain_id; } -// Get the orientation of a grain from a given grain ID and the number of possible orientations +// Get the orientation of a grain's <100> from a given grain ID and the number of possible orientations // By default, start indexing at 0 (GrainID of 1 has Orientation number 0), optionally starting at 1 // GrainID of 0 is a special case - has orientation 0 no matter what (only used when reconstructing grain ID in // getGrainID) -KOKKOS_INLINE_FUNCTION int getGrainOrientation(const int my_grain_id, const int n_grain_orientations, - bool start_at_zero = true) { +KOKKOS_INLINE_FUNCTION int getCrystalOrientation(const int my_grain_id, const int n_crystal_orientations, + bool start_at_zero = true) { int my_orientation; if (my_grain_id == 0) my_orientation = 0; else { - my_orientation = (Kokkos::abs(my_grain_id) - 1) % n_grain_orientations; + my_orientation = (Kokkos::abs(my_grain_id) - 1) % n_crystal_orientations; if (!(start_at_zero)) my_orientation++; } @@ -243,8 +243,8 @@ KOKKOS_INLINE_FUNCTION int getGrainOrientation(const int my_grain_id, const int // Get the repeat number for the orientation of a grain with a given grain ID // 1, 2, 3... or -1, -2, -3... -KOKKOS_INLINE_FUNCTION int getGrainNumber(int my_grain_id, int n_grain_orientations) { - int my_grain_number = (Kokkos::abs(my_grain_id) - 1) / n_grain_orientations + 1; +KOKKOS_INLINE_FUNCTION int getGrainNumber(int my_grain_id, int n_crystal_orientations) { + int my_grain_number = (Kokkos::abs(my_grain_id) - 1) / n_crystal_orientations + 1; if (my_grain_id < 0) my_grain_number = -my_grain_number; return my_grain_number; diff --git a/src/CAprint.hpp b/src/CAprint.hpp index b200f099..13523a62 100644 --- a/src/CAprint.hpp +++ b/src/CAprint.hpp @@ -299,7 +299,8 @@ struct Print { intralayer_ofstream.close(); // If necessary, collect/print GrainMisorientation field to separate file - if (_inputs.intralayer_grain_misorientation) { + if (_inputs.intralayer_crystal_misorientation[0] || _inputs.intralayer_crystal_misorientation[1] || + _inputs.intralayer_crystal_misorientation[2]) { // Get GrainID data for all layers auto grain_id_all_layers_whole_domain = collectViewData(id, np, grid, false, MPI_INT, celldata.grain_id_all_layers); @@ -309,8 +310,9 @@ struct Print { // Print GrainMisorientation for all layers up to the current layer std::string misorientations_filename = getIntralayerFilename(layernumber, "_Misorientations"); std::cout << "Printing file of grain misorientations " << misorientations_filename << std::endl; - printGrainMisorientations(misorientations_filename, grid, grain_id_all_layers_whole_domain, - cell_type_whole_domain, orientation); + printCrystalMisorientations(misorientations_filename, grid, grain_id_all_layers_whole_domain, + cell_type_whole_domain, orientation, + _inputs.intralayer_crystal_misorientation); } } // Increment intermediate file counter now that all files have been printed @@ -463,7 +465,8 @@ struct Print { } // If necessary, collect/print GrainMisorientation field to separate file - if (_inputs.interlayer_grain_misorientation) { + if (_inputs.interlayer_crystal_misorientation[0] || _inputs.interlayer_crystal_misorientation[1] || + _inputs.interlayer_crystal_misorientation[2]) { // Get CellType data for current layer auto cell_type_whole_domain = collectViewData(id, np, grid, true, MPI_INT, celldata.cell_type); if (id == 0) { @@ -471,8 +474,9 @@ struct Print { std::string misorientations_filename = getInterlayerFilename(layernumber, grid.number_of_layers, false, "_Misorientations"); std::cout << "Printing file of grain misorientations " << misorientations_filename << std::endl; - printGrainMisorientations(misorientations_filename, grid, grain_id_all_layers_whole_domain, - cell_type_whole_domain, orientation); + printCrystalMisorientations(misorientations_filename, grid, grain_id_all_layers_whole_domain, + cell_type_whole_domain, orientation, + _inputs.interlayer_crystal_misorientation); } } @@ -603,80 +607,96 @@ struct Print { und_ofstream.close(); } - // On rank 0, print grain misorientation, 0-62 for epitaxial grains and 100-162 for nucleated grains, to a vtk - // file. If printing an intermediate state, print -1 for cells that are liquid + // On rank 0, print crystal <100> misorientation with cardinal directions, 0-62 for epitaxial grains and 100-162 for + // nucleated grains, to a vtk file. If printing an intermediate state, print -1 for cells that are liquid template - void printGrainMisorientations(const std::string misorientations_filename, const Grid &grid, - ViewTypeInt3DHost grain_id_whole_domain, ViewTypeInt3DHost cell_type_whole_domain, - Orientation &orientation) { + void printCrystalMisorientations(const std::string misorientations_filename, const Grid &grid, + ViewTypeInt3DHost grain_id_whole_domain, ViewTypeInt3DHost cell_type_whole_domain, + Orientation &orientation, + const std::vector &crystal_misorientation_fields) { - // Print grain orientations to file - either all layers (print_region = 2), or if in an intermediate state, the - // layers up to the current one (print_region = 1) z_end will equal grid.nz if this is the final layer + // Print crustal orientations to file - either all layers (print_region = 2), or if in an intermediate state, + // the layers up to the current one (print_region = 1) z_end will equal grid.nz if this is the final layer int z_end = grid.z_layer_bottom + grid.nz_layer; std::ofstream misorientations_ofstream; writeHeader(misorientations_ofstream, misorientations_filename, grid, false); - misorientations_ofstream << "SCALARS Angle_z short 1" << std::endl; - misorientations_ofstream << "LOOKUP_TABLE default" << std::endl; - - // Get grain <100> misorientation relative to the Z direction for each orientation - auto grain_misorientation = orientation.misorientationCalc(2); - // For cells that are currently liquid (possible only for intermediate state print, as the final state will only - // have solid cells), -1 is printed as the misorienatation. Misorientations for grains from the baseplate or - // powder layer are between 0-62 (degrees, rounded to nearest integer), and cells that are associated with - // nucleated grains are assigned values between 100-162 to differentiate them. Additionally, 200 is printed as - // the misorientation for cells in the powder layer that have not been assigned a grain ID. - // For prior layers, cell type check is unnecessary as these regions have all solidified - for (int k = 0; k < grid.z_layer_bottom; k++) { - for (int j = 0; j < grid.ny; j++) { - for (int i = 0; i < grid.nx; i++) { - short int_print_val; - if (grain_id_whole_domain(k, i, j) == 0) - int_print_val = 200; - else { - // As of now, either both phases share a grain orientation file - or the second phase - // transformed into the first phase after initial solidification. While the grain misorientation - // view contains values for both phases, the printed values correspond to the "final" grain - // orientation after any solid-solid phase transformation and should correspond to an - // orientation for the primary phase ("phase 0") - int my_orientation = - getGrainOrientation(grain_id_whole_domain(k, i, j), orientation.n_grain_orientations); - if (grain_id_whole_domain(k, i, j) < 0) - int_print_val = - static_cast(std::round(grain_misorientation(my_orientation, 0)) + 100); - else - int_print_val = static_cast(std::round(grain_misorientation(my_orientation, 0))); + // Get grain <100> misorientation relative to the toggeled cardinal directions for each orientation + for (int dir = 0; dir < 3; dir++) { + if (crystal_misorientation_fields[dir]) { + // Print field name for the misorientation field + std::string field_name; + if (dir == 0) + field_name = "x"; + else if (dir == 1) + field_name = "y"; + else + field_name = "z"; + misorientations_ofstream << "SCALARS Angle_" << field_name << " short 1" << std::endl; + misorientations_ofstream << "LOOKUP_TABLE default" << std::endl; + // Calculate crystal misorientation relative to the desired direction + auto crystal_misorientation = orientation.misorientationCalc(dir); + // For cells that are currently liquid (possible only for intermediate state print, as the final state + // will only have solid cells), -1 is printed as the misorienatation. Misorientations for grains from + // the baseplate or powder layer are between 0-62 (degrees, rounded to nearest integer), and cells that + // are associated with nucleated grains are assigned values between 100-162 to differentiate them. + // Additionally, 200 is printed as the misorientation for cells in the powder layer that have not been + // assigned a grain ID. For prior layers, cell type check is unnecessary as these regions have all + // solidified + for (int k = 0; k < grid.z_layer_bottom; k++) { + for (int j = 0; j < grid.ny; j++) { + for (int i = 0; i < grid.nx; i++) { + short int_print_val; + if (grain_id_whole_domain(k, i, j) == 0) + int_print_val = 200; + else { + // As of now, either both phases share a grain orientation file - or the second phase + // transformed into the first phase after initial solidification. While the grain + // misorientation view contains values for both phases, the printed values correspond to + // the "final" grain orientation after any solid-solid phase transformation and should + // correspond to an orientation for the primary phase ("phase 0") + int my_orientation = getCrystalOrientation(grain_id_whole_domain(k, i, j), + orientation.n_crystal_orientations); + if (grain_id_whole_domain(k, i, j) < 0) + int_print_val = + static_cast(std::round(crystal_misorientation(my_orientation, 0)) + 100); + else + int_print_val = + static_cast(std::round(crystal_misorientation(my_orientation, 0))); + } + writeData(misorientations_ofstream, int_print_val, _inputs.print_binary, true); + } } - writeData(misorientations_ofstream, int_print_val, _inputs.print_binary, true); + if (!(_inputs.print_binary)) + misorientations_ofstream << std::endl; } - } - if (!(_inputs.print_binary)) - misorientations_ofstream << std::endl; - } - // For current layer, check cell types to see if -1 should be printed (if this is a print following a layer, all - // cells will be solid and no -1s should be written) - for (int k = grid.z_layer_bottom; k < z_end; k++) { - for (int j = 0; j < grid.ny; j++) { - for (int i = 0; i < grid.nx; i++) { - short int_print_val; - if (grain_id_whole_domain(k, i, j) == 0) - int_print_val = 200; - else { - int my_orientation = - getGrainOrientation(grain_id_whole_domain(k, i, j), orientation.n_grain_orientations); - if (grain_id_whole_domain(k, i, j) < 0) - int_print_val = - static_cast(std::round(grain_misorientation(my_orientation, 0)) + 100); - else - int_print_val = static_cast(std::round(grain_misorientation(my_orientation, 0))); + // For current layer, check cell types to see if -1 should be printed (if this is a print following a + // layer, all cells will be solid and no -1s should be written) + for (int k = grid.z_layer_bottom; k < z_end; k++) { + for (int j = 0; j < grid.ny; j++) { + for (int i = 0; i < grid.nx; i++) { + short int_print_val; + if (grain_id_whole_domain(k, i, j) == 0) + int_print_val = 200; + else { + int my_orientation = getCrystalOrientation(grain_id_whole_domain(k, i, j), + orientation.n_crystal_orientations); + if (grain_id_whole_domain(k, i, j) < 0) + int_print_val = + static_cast(std::round(crystal_misorientation(my_orientation, 0)) + 100); + else + int_print_val = + static_cast(std::round(crystal_misorientation(my_orientation, 0))); + } + // Offset in Z as cell type values only exist for current layer + if (cell_type_whole_domain(k - grid.z_layer_bottom, i, j) == Liquid) + int_print_val = -1; + writeData(misorientations_ofstream, int_print_val, _inputs.print_binary, true); + } } - // Offset in Z as cell type values only exist for current layer - if (cell_type_whole_domain(k - grid.z_layer_bottom, i, j) == Liquid) - int_print_val = -1; - writeData(misorientations_ofstream, int_print_val, _inputs.print_binary, true); + if (!(_inputs.print_binary)) + misorientations_ofstream << std::endl; } } - if (!(_inputs.print_binary)) - misorientations_ofstream << std::endl; } misorientations_ofstream.close(); } @@ -764,7 +784,8 @@ struct Print { // were printed, or both were printed if (id == 0) { std::vector series_aux_filenames; - if (_inputs.intralayer_grain_misorientation) + if (_inputs.intralayer_crystal_misorientation[0] || _inputs.intralayer_crystal_misorientation[1] || + _inputs.intralayer_crystal_misorientation[3]) series_aux_filenames.push_back("_Misorientations"); if (_inputs.intralayer_non_misorientation_fields) series_aux_filenames.push_back(""); diff --git a/src/CAupdate.hpp b/src/CAupdate.hpp index f9aaeea2..8da4351f 100644 --- a/src/CAupdate.hpp +++ b/src/CAupdate.hpp @@ -37,7 +37,7 @@ void createOctahedra_NoRemelt(const Grid &grid, CellData &celldata, const int my_grain_id = grain_id(index); // The orientation for the new grain will depend on its Grain ID - const int my_orientation = getGrainOrientation(my_grain_id, orientation.n_grain_orientations); + const int my_orientation = getCrystalOrientation(my_grain_id, orientation.n_crystal_orientations); temperature.setStartingUndercooling(0, index); @@ -250,7 +250,7 @@ void cellCapture(const int cycle, const int np, const Grid &grid, const Interfac // Cell capture event const int my_grain_id = grain_id(index); const int my_orientation = - getGrainOrientation(my_grain_id, orientation.n_grain_orientations); + getCrystalOrientation(my_grain_id, orientation.n_crystal_orientations); // This cell was not at the edge of the temperature field - set indicator to false if // this is being tracked @@ -452,7 +452,7 @@ void cellCapture(const int cycle, const int np, const Grid &grid, const Interfac ghost_grain_id, ghost_octahedron_center_x, ghost_octahedron_center_y, ghost_octahedron_center_z, ghost_diagonal_length, ghost_phase_id, grid.ny_local, neighbor_coord_x, neighbor_coord_y, neighbor_coord_z, grid.at_north_boundary, - grid.at_south_boundary, orientation.n_grain_orientations); + grid.at_south_boundary, orientation.n_crystal_orientations); if (!(data_fits_in_buffer)) { // This cell's data did not fit in the buffer with current size buf_size - // mark with temporary type @@ -498,7 +498,7 @@ void cellCapture(const int cycle, const int np, const Grid &grid, const Interfac interface.createNewOctahedron(index, coord_x, coord_y, grid.y_offset, coord_z); // The orientation for the new grain will depend on its Grain ID (nucleated grains have negative // grain_id values) - const int my_orientation = getGrainOrientation(my_grain_id, orientation.n_grain_orientations); + const int my_orientation = getCrystalOrientation(my_grain_id, orientation.n_crystal_orientations); // Octahedron center is at (cx, cy, cz) - note that the Y coordinate is relative to the domain // origin to keep the coordinate system continuous across ranks const float cx = coord_x + 0.5; @@ -522,7 +522,7 @@ void cellCapture(const int cycle, const int np, const Grid &grid, const Interfac bool data_fits_in_buffer = interface.loadGhostNodes( ghost_grain_id, ghost_octahedron_center_x, ghost_octahedron_center_y, ghost_octahedron_center_z, ghost_diagonal_length, ghost_phase_id, grid.ny_local, coord_x, coord_y, coord_z, - grid.at_north_boundary, grid.at_south_boundary, orientation.n_grain_orientations); + grid.at_north_boundary, grid.at_south_boundary, orientation.n_crystal_orientations); if (!(data_fits_in_buffer)) { // This cell's data did not fit in the buffer with current size buf_size - mark with // temporary type @@ -545,7 +545,7 @@ void cellCapture(const int cycle, const int np, const Grid &grid, const Interfac // length bool data_fits_in_buffer = interface.loadGhostNodes( -1, -1.0, -1.0, -1.0, 0.0, 1, grid.ny_local, coord_x, coord_y, coord_z, grid.at_north_boundary, - grid.at_south_boundary, orientation.n_grain_orientations); + grid.at_south_boundary, orientation.n_crystal_orientations); if (!(data_fits_in_buffer)) { // This cell's data did not fit in the buffer with current size buf_size - mark with temporary // type @@ -563,21 +563,21 @@ void cellCapture(const int cycle, const int np, const Grid &grid, const Interfac // Check buffers for overflow and resize/refill as necessary template void checkBuffers(const int id, const int cycle, const Grid &grid, CellData &celldata, - Interface &interface, const int n_grain_orientations) { + Interface &interface, const int n_crystal_orientations) { // Count the number of cells' in halo regions where the data did not fit into the send buffers // Reduce across all ranks, as the same buf_size should be maintained across all ranks // If any rank overflowed its buffer size, resize all buffers to the new size plus a padding (default val of 25 // cells) bool resize_performed = interface.resizeBuffers(id, cycle); if (resize_performed) - refillBuffers(grid, celldata, interface, n_grain_orientations); + refillBuffers(grid, celldata, interface, n_crystal_orientations); } // Refill the buffers as necessary starting from the old count size, using the data from cells marked with type // ActiveFailedBufferLoad template void refillBuffers(const Grid &grid, CellData &celldata, Interface &interface, - const int n_grain_orientations) { + const int n_crystal_orientations) { auto grain_id = celldata.getGrainIDSubview(grid); auto phase_id = celldata.getPhaseIDSubview(grid); @@ -598,7 +598,7 @@ void refillBuffers(const Grid &grid, CellData &celldata, Interface< bool data_fits_in_buffer = interface.loadGhostNodes( ghost_grain_id, ghost_octahedron_center_x, ghost_octahedron_center_y, ghost_octahedron_center_z, ghost_diagonal_length, ghost_phase_id, grid.ny_local, coord_x, 1, coord_z, - grid.at_north_boundary, grid.at_south_boundary, n_grain_orientations); + grid.at_north_boundary, grid.at_south_boundary, n_crystal_orientations); celldata.cell_type(index_south_buffer) = Active; // If data doesn't fit in the buffer after the resize, warn that buffer data may have been lost interface.checkBufferSize(data_fits_in_buffer); @@ -606,9 +606,9 @@ void refillBuffers(const Grid &grid, CellData &celldata, Interface< else if (celldata.cell_type(index_south_buffer) == LiquidFailedBufferLoad) { // Dummy values for first 4 arguments (Grain ID and octahedron center coordinates), 0 for // diagonal length - bool data_fits_in_buffer = - interface.loadGhostNodes(-1, -1.0, -1.0, -1.0, 0.0, 1, grid.ny_local, coord_x, 1, coord_z, - grid.at_north_boundary, grid.at_south_boundary, n_grain_orientations); + bool data_fits_in_buffer = interface.loadGhostNodes(-1, -1.0, -1.0, -1.0, 0.0, 1, grid.ny_local, + coord_x, 1, coord_z, grid.at_north_boundary, + grid.at_south_boundary, n_crystal_orientations); celldata.cell_type(index_south_buffer) = Liquid; // If data doesn't fit in the buffer after the resize, warn that buffer data may have been lost interface.checkBufferSize(data_fits_in_buffer); @@ -625,7 +625,7 @@ void refillBuffers(const Grid &grid, CellData &celldata, Interface< bool data_fits_in_buffer = interface.loadGhostNodes( ghost_grain_id, ghost_octahedron_center_x, ghost_octahedron_center_y, ghost_octahedron_center_z, ghost_diagonal_length, ghost_phase_id, grid.ny_local, coord_x, grid.ny_local - 2, coord_z, - grid.at_north_boundary, grid.at_south_boundary, n_grain_orientations); + grid.at_north_boundary, grid.at_south_boundary, n_crystal_orientations); celldata.cell_type(index_north_buffer) = Active; // If data doesn't fit in the buffer after the resize, warn that buffer data may have been lost interface.checkBufferSize(data_fits_in_buffer); @@ -635,7 +635,7 @@ void refillBuffers(const Grid &grid, CellData &celldata, Interface< // diagonal length bool data_fits_in_buffer = interface.loadGhostNodes( -1, -1.0, -1.0, -1.0, 0.0, 1, grid.ny_local, coord_x, grid.ny_local - 2, coord_z, - grid.at_north_boundary, grid.at_south_boundary, n_grain_orientations); + grid.at_north_boundary, grid.at_south_boundary, n_crystal_orientations); celldata.cell_type(index_north_buffer) = Liquid; // If data doesn't fit in the buffer after the resize, warn that buffer data may have been lost interface.checkBufferSize(data_fits_in_buffer); @@ -703,7 +703,7 @@ void haloUpdate(const int, const int, const Grid &grid, CellData &c int my_grain_orientation = static_cast(interface.buffer_south_recv(buf_position, 2)); int my_grain_number = static_cast(interface.buffer_south_recv(buf_position, 3)); new_grain_id = - getGrainID(my_grain_orientation, my_grain_number, orientation.n_grain_orientations); + getGrainID(my_grain_orientation, my_grain_number, orientation.n_crystal_orientations); new_octahedron_center_x = interface.buffer_south_recv(buf_position, 4); new_octahedron_center_y = interface.buffer_south_recv(buf_position, 5); new_octahedron_center_z = interface.buffer_south_recv(buf_position, 6); @@ -731,7 +731,7 @@ void haloUpdate(const int, const int, const Grid &grid, CellData &c int my_grain_orientation = static_cast(interface.buffer_north_recv(buf_position, 2)); int my_grain_number = static_cast(interface.buffer_north_recv(buf_position, 3)); new_grain_id = - getGrainID(my_grain_orientation, my_grain_number, orientation.n_grain_orientations); + getGrainID(my_grain_orientation, my_grain_number, orientation.n_crystal_orientations); new_octahedron_center_x = interface.buffer_north_recv(buf_position, 4); new_octahedron_center_y = interface.buffer_north_recv(buf_position, 5); new_octahedron_center_z = interface.buffer_north_recv(buf_position, 6); @@ -749,7 +749,7 @@ void haloUpdate(const int, const int, const Grid &grid, CellData &c interface.octahedron_center(3 * index) = new_octahedron_center_x; interface.octahedron_center(3 * index + 1) = new_octahedron_center_y; interface.octahedron_center(3 * index + 2) = new_octahedron_center_z; - int my_orientation = getGrainOrientation(grain_id(index), orientation.n_grain_orientations); + int my_orientation = getCrystalOrientation(grain_id(index), orientation.n_crystal_orientations); interface.diagonal_length(index) = static_cast(new_diagonal_length); phase_id(index) = new_phase_id; // Cell center - note that the Y coordinate is relative to the domain origin to keep the diff --git a/src/runCA.hpp b/src/runCA.hpp index 5bbb1b07..c05b8dec 100644 --- a/src/runCA.hpp +++ b/src/runCA.hpp @@ -56,7 +56,7 @@ void runExaCALayer(int id, int np, int layernumber, int &cycle, Inputs inputs, T // recorded timers.startCapture(); cellCapture(cycle, np, grid, irf, celldata, temperature, interface, orientation); - checkBuffers(id, cycle, grid, celldata, interface, orientation.n_grain_orientations); + checkBuffers(id, cycle, grid, celldata, interface, orientation.n_crystal_orientations); timers.stopCapture(); if (np > 1) { diff --git a/unit_test/tstInputs.hpp b/unit_test/tstInputs.hpp index db534fa4..ce7905bd 100644 --- a/unit_test/tstInputs.hpp +++ b/unit_test/tstInputs.hpp @@ -25,7 +25,7 @@ void writeTestData(std::string input_filename, int print_version) { test_data_file << "{" << std::endl; test_data_file << " \"SimulationType\": \"FromFile\"," << std::endl; test_data_file << " \"MaterialFileName\": \"Inconel625.json\"," << std::endl; - test_data_file << " \"GrainOrientationFile\": \"GrainOrientationVectors.csv\"," << std::endl; + test_data_file << " \"CrystalOrientationFile\": \"CrystalOrientationVectors.csv\"," << std::endl; test_data_file << " \"RandomSeed\": 2," << std::endl; test_data_file << " \"Domain\": {" << std::endl; test_data_file << " \"CellSize\": 1," << std::endl; @@ -53,7 +53,7 @@ void writeTestData(std::string input_filename, int print_version) { test_data_file << " \"PathToOutput\": \"ExaCA\"," << std::endl; test_data_file << " \"OutputFile\": \"Test\"," << std::endl; test_data_file << " \"PrintBinary\": true," << std::endl; - // two different permutations of print outputs + // two different permutations of print outputs - deprecated and non-deprecated GrainMisorientation if (print_version == 0) { test_data_file << " \"PrintExaConstitSize\": 0," << std::endl; test_data_file << " \"Intralayer\": {" << std::endl; @@ -72,7 +72,9 @@ void writeTestData(std::string input_filename, int print_version) { else if (print_version == 1) { test_data_file << " \"PrintExaConstitSize\": 500," << std::endl; test_data_file << " \"Interlayer\": {" << std::endl; - test_data_file << " \"Fields\": [\"GrainMisorientation\",\"GrainID\",\"LayerID\"]" << std::endl; + test_data_file + << " \"Fields\": [\"CrystalMisorientationX\",\"CrystalMisorientationY\",\"GrainID\",\"LayerID\"]" + << std::endl; test_data_file << " }" << std::endl; } test_data_file << " }" << std::endl; @@ -178,7 +180,9 @@ void testInputs(int print_version) { EXPECT_FALSE(inputs.print.intralayer_idle_frames); EXPECT_FALSE(inputs.print.intralayer_grain_id); EXPECT_FALSE(inputs.print.intralayer_layer_id); - EXPECT_TRUE(inputs.print.intralayer_grain_misorientation); + EXPECT_FALSE(inputs.print.intralayer_crystal_misorientation[0]); + EXPECT_FALSE(inputs.print.intralayer_crystal_misorientation[1]); + EXPECT_TRUE(inputs.print.intralayer_crystal_misorientation[2]); EXPECT_FALSE(inputs.print.intralayer_undercooling_current); EXPECT_FALSE(inputs.print.intralayer_melt_time_step); EXPECT_FALSE(inputs.print.intralayer_crit_time_step); @@ -191,7 +195,9 @@ void testInputs(int print_version) { EXPECT_FALSE(inputs.print.interlayer_current); EXPECT_TRUE(inputs.print.interlayer_grain_id); EXPECT_TRUE(inputs.print.interlayer_layer_id); - EXPECT_TRUE(inputs.print.interlayer_grain_misorientation); + EXPECT_FALSE(inputs.print.interlayer_crystal_misorientation[0]); + EXPECT_FALSE(inputs.print.interlayer_crystal_misorientation[1]); + EXPECT_TRUE(inputs.print.interlayer_crystal_misorientation[2]); EXPECT_FALSE(inputs.print.interlayer_undercooling_current); EXPECT_FALSE(inputs.print.interlayer_melt_time_step); EXPECT_FALSE(inputs.print.interlayer_crit_time_step); @@ -218,7 +224,9 @@ void testInputs(int print_version) { EXPECT_TRUE(inputs.print.intralayer_idle_frames); EXPECT_FALSE(inputs.print.intralayer_grain_id); EXPECT_FALSE(inputs.print.intralayer_layer_id); - EXPECT_TRUE(inputs.print.intralayer_grain_misorientation); + EXPECT_FALSE(inputs.print.intralayer_crystal_misorientation[0]); + EXPECT_FALSE(inputs.print.intralayer_crystal_misorientation[1]); + EXPECT_TRUE(inputs.print.intralayer_crystal_misorientation[2]); EXPECT_FALSE(inputs.print.intralayer_undercooling_current); EXPECT_TRUE(inputs.print.intralayer_melt_time_step); EXPECT_TRUE(inputs.print.intralayer_crit_time_step); @@ -231,7 +239,9 @@ void testInputs(int print_version) { EXPECT_FALSE(inputs.print.interlayer_current); EXPECT_TRUE(inputs.print.interlayer_grain_id); EXPECT_TRUE(inputs.print.interlayer_layer_id); - EXPECT_TRUE(inputs.print.interlayer_grain_misorientation); + EXPECT_FALSE(inputs.print.interlayer_crystal_misorientation[0]); + EXPECT_FALSE(inputs.print.interlayer_crystal_misorientation[1]); + EXPECT_TRUE(inputs.print.interlayer_crystal_misorientation[2]); EXPECT_FALSE(inputs.print.interlayer_undercooling_current); EXPECT_FALSE(inputs.print.interlayer_melt_time_step); EXPECT_FALSE(inputs.print.interlayer_crit_time_step); @@ -263,7 +273,8 @@ void testInputs(int print_version) { EXPECT_TRUE(inputs.print.intralayer_idle_frames); EXPECT_TRUE(inputs.print.intralayer_grain_id); EXPECT_TRUE(inputs.print.intralayer_layer_id); - EXPECT_FALSE(inputs.print.intralayer_grain_misorientation); + for (int dir = 0; dir < 2; dir++) + EXPECT_FALSE(inputs.print.intralayer_crystal_misorientation[dir]); EXPECT_FALSE(inputs.print.intralayer_undercooling_current); EXPECT_TRUE(inputs.print.intralayer_melt_time_step); EXPECT_TRUE(inputs.print.intralayer_crit_time_step); @@ -276,7 +287,9 @@ void testInputs(int print_version) { EXPECT_FALSE(inputs.print.interlayer_current); EXPECT_TRUE(inputs.print.interlayer_grain_id); EXPECT_TRUE(inputs.print.interlayer_layer_id); - EXPECT_TRUE(inputs.print.interlayer_grain_misorientation); + EXPECT_FALSE(inputs.print.interlayer_crystal_misorientation[0]); + EXPECT_FALSE(inputs.print.interlayer_crystal_misorientation[1]); + EXPECT_TRUE(inputs.print.interlayer_crystal_misorientation[2]); EXPECT_TRUE(inputs.print.interlayer_undercooling_current); EXPECT_FALSE(inputs.print.interlayer_melt_time_step); EXPECT_FALSE(inputs.print.interlayer_crit_time_step); @@ -294,7 +307,9 @@ void testInputs(int print_version) { EXPECT_FALSE(inputs.print.interlayer_current); EXPECT_TRUE(inputs.print.interlayer_grain_id); EXPECT_TRUE(inputs.print.interlayer_layer_id); - EXPECT_TRUE(inputs.print.interlayer_grain_misorientation); + EXPECT_TRUE(inputs.print.interlayer_crystal_misorientation[0]); + EXPECT_TRUE(inputs.print.interlayer_crystal_misorientation[1]); + EXPECT_FALSE(inputs.print.interlayer_crystal_misorientation[2]); EXPECT_FALSE(inputs.print.interlayer_undercooling_current); EXPECT_FALSE(inputs.print.interlayer_melt_time_step); EXPECT_FALSE(inputs.print.interlayer_crit_time_step); diff --git a/unit_test/tstInterface.hpp b/unit_test/tstInterface.hpp index 4f917096..e026df70 100644 --- a/unit_test/tstInterface.hpp +++ b/unit_test/tstInterface.hpp @@ -84,9 +84,9 @@ void testHaloUpdate() { grid.nx * grid.ny_local * grid.z_layer_bottom + grid.domain_size); // Initialize grain orientations - std::string grain_orientation_file_s = checkFileInstalled("GrainOrientationVectors.csv", id); - std::vector grain_orientation_file = {grain_orientation_file_s}; - Orientation orientation(id, grain_orientation_file, false); + std::string crystal_orientation_file_s = checkFileInstalled("CrystalOrientationVectors.csv", id); + std::vector crystal_orientation_file = {crystal_orientation_file_s}; + Orientation orientation(id, crystal_orientation_file, false); // Initialize host views - set initial GrainID values to 0, all CellType values to liquid CellData celldata(grid, inputs.substrate); @@ -180,7 +180,7 @@ void testHaloUpdate() { float ghost_pid = 0.0; interface.loadGhostNodes(ghost_gid, ghost_docx, ghost_docy, ghost_docz, ghost_dl, ghost_pid, grid.ny_local, coord_x, coord_y, coord_z, grid.at_north_boundary, - grid.at_south_boundary, orientation.n_grain_orientations); + grid.at_south_boundary, orientation.n_crystal_orientations); } }); haloUpdate(0, 0, grid, celldata, interface, orientation); @@ -272,7 +272,7 @@ void testResizeRefillBuffers() { grid.domain_size_all_layers = grid.nx * grid.ny_local * grid.nz; grid.layer_range = std::make_pair(grid.nx * grid.ny_local * grid.z_layer_bottom, grid.nx * grid.ny_local * grid.z_layer_bottom + grid.domain_size); - int n_grain_orientations = 10000; + int n_crystal_misorientations = 10000; // Allocate device views: entire domain on each rank // Default to wall cells (CellType(index) = 0) with GrainID of 0 @@ -282,9 +282,9 @@ void testResizeRefillBuffers() { // Orientation struct // Initialize grain orientations - std::string grain_orientation_file_s = checkFileInstalled("GrainOrientationVectors.csv", id); - std::vector grain_orientation_file = {grain_orientation_file_s}; - Orientation orientation(id, grain_orientation_file, false); + std::string crystal_misorientation_file_s = checkFileInstalled("CrystalOrientationVectors.csv", id); + std::vector crystal_misorientation_file = {crystal_misorientation_file_s}; + Orientation orientation(id, crystal_misorientation_file, false); // Interface struct - set buffer size to 1 int buf_size_initial_estimate = 1; @@ -313,7 +313,7 @@ void testResizeRefillBuffers() { // Load into appropriate buffers interface.loadGhostNodes(ghost_gid, ghost_docx, ghost_docy, ghost_docz, ghost_dl, ghost_pid, grid.ny_local, coord_x, coord_y, coord_z, grid.at_north_boundary, grid.at_south_boundary, - n_grain_orientations); + n_crystal_misorientations); }); Kokkos::parallel_for( "InitDomainActiveCellsSouth", 1, KOKKOS_LAMBDA(const int &) { @@ -336,7 +336,7 @@ void testResizeRefillBuffers() { // Load into appropriate buffers interface.loadGhostNodes(ghost_gid, ghost_docx, ghost_docy, ghost_docz, ghost_dl, ghost_pid, grid.ny_local, coord_x, coord_y, coord_z, grid.at_north_boundary, grid.at_south_boundary, - n_grain_orientations); + n_crystal_misorientations); }); // Each rank will have "id % 4" cells of additional data to send to the south, and 1 cell of additional data to send @@ -364,7 +364,7 @@ void testResizeRefillBuffers() { // Attempt to load into appropriate buffers bool data_fits_in_buffer = interface.loadGhostNodes( ghost_gid, ghost_docx, ghost_docy, ghost_docz, ghost_dl, ghost_pid, grid.ny_local, coord_x, coord_y, - coord_z, grid.at_north_boundary, grid.at_south_boundary, n_grain_orientations); + coord_z, grid.at_north_boundary, grid.at_south_boundary, n_crystal_misorientations); if (!(data_fits_in_buffer)) { // This cell's data did not fit in the buffer with current size buf_size - mark with temporary type celldata.cell_type(index) = ActiveFailedBufferLoad; @@ -391,7 +391,7 @@ void testResizeRefillBuffers() { // Attempt to load into appropriate buffers bool data_fits_in_buffer = interface.loadGhostNodes( ghost_gid, ghost_docx, ghost_docy, ghost_docz, ghost_dl, ghost_pid, grid.ny_local, coord_x, coord_y, - coord_z, grid.at_north_boundary, grid.at_south_boundary, n_grain_orientations); + coord_z, grid.at_north_boundary, grid.at_south_boundary, n_crystal_misorientations); if (!(data_fits_in_buffer)) { // This cell's data did not fit in the buffer with current size buf_size - mark with temporary type celldata.cell_type(index) = ActiveFailedBufferLoad; @@ -399,7 +399,7 @@ void testResizeRefillBuffers() { }); // Attempt to resize buffers and load the remaining data - checkBuffers(id, 0, grid, celldata, interface, orientation.n_grain_orientations); + checkBuffers(id, 0, grid, celldata, interface, orientation.n_crystal_orientations); // If there was 1 rank, buffer size should still be 1, as no data was loaded // Otherwise, 25 cells should have been added to the buffer in @@ -540,11 +540,11 @@ void testRemeltActivateCells() { CellData celldata(grid, inputs.substrate); auto grain_id = celldata.getGrainIDSubview(grid); Temperature temperature(grid, inputs.temperature, inputs.print); - std::string grain_orientation_file_tmp = checkFileInstalled("GrainOrientationVectors.csv", id); - std::vector grain_orientation_file; - grain_orientation_file.push_back(grain_orientation_file_tmp); - Orientation orientation(id, grain_orientation_file, false, inputs.rng_seed, inputs.irf.num_phases, - irf.solidificationTransformation()); + std::string crystal_misorientation_file_tmp = checkFileInstalled("CrystalOrientationVectors.csv", id); + std::vector crystal_misorientation_file; + crystal_misorientation_file.push_back(crystal_misorientation_file_tmp); + Orientation orientation(id, crystal_misorientation_file, false, inputs.rng_seed, + inputs.irf.num_phases, irf.solidificationTransformation()); // Cells at Z = 0 are Solid and do not change type. Cells at Z = 1 and 2 melt at a time step corresponding to their // Y location in the overall domain (depends on y_offset of the rank) and cool below the liquidus 2 time steps after diff --git a/unit_test/tstOrientation.hpp b/unit_test/tstOrientation.hpp index 897ff487..44af89e3 100644 --- a/unit_test/tstOrientation.hpp +++ b/unit_test/tstOrientation.hpp @@ -23,15 +23,15 @@ void testOrientationInit_Vectors() { using memory_space = TEST_MEMSPACE; - std::string grain_orientation_file_s = checkFileInstalled("GrainOrientationVectors.csv", 0); + std::string crystal_orientation_file_s = checkFileInstalled("CrystalOrientationVectors.csv", 0); // Initialize grain orientations - unit vector form only int id = 0; - std::vector grain_orientation_file = {grain_orientation_file_s}; - Orientation orientation(id, grain_orientation_file, false); + std::vector crystal_orientation_file = {crystal_orientation_file_s}; + Orientation orientation(id, crystal_orientation_file, false); // Check results for first 2 orientations (first 18 values in the file) - EXPECT_EQ(orientation.n_grain_orientations, 10000); + EXPECT_EQ(orientation.n_crystal_orientations, 10000); std::vector expected_grain_unit_vector = {0.848294, 0.493303, 0.19248, -0.522525, 0.720911, 0.455253, 0.0858167, -0.486765, 0.869308, 0.685431, 0.188182, 0.7034, @@ -47,16 +47,16 @@ void testOrientationInit_Angles() { using memory_space = TEST_MEMSPACE; - std::string grain_orientation_file_s = checkFileInstalled("GrainOrientationVectors.csv", 0); - std::vector grain_orientation_file = {grain_orientation_file_s}; + std::string crystal_orientation_file_s = checkFileInstalled("CrystalOrientationVectors.csv", 0); + std::vector crystal_orientation_file = {crystal_orientation_file_s}; - // Initialize grain orientations - unit vector form and data from GrainOrientationEulerAnglesBungeZXZ.csv should be - // read + // Initialize grain orientations - unit vector form and data from CrystalOrientationEulerAnglesBungeZXZ.csv should + // be read int id = 0; - Orientation orientation(id, grain_orientation_file, true); + Orientation orientation(id, crystal_orientation_file, true); // Check results - EXPECT_EQ(orientation.n_grain_orientations, 10000); + EXPECT_EQ(orientation.n_crystal_orientations, 10000); // Check first two orientations (first 6 values in the file) std::vector expected_euler_angles = {9.99854, 29.62172, 22.91854, 311.08350, 47.68814, 72.02547}; @@ -91,7 +91,7 @@ void testConvertGrainIDForBuffer() { } grain_id = Kokkos::create_mirror_view_and_copy(memory_space(), grain_id_host); - int n_grain_orientations = 10000; + int n_crystal_orientations = 10000; // Check that these were converted to their components and back correctly view_type grain_id_converted(Kokkos::ViewAllocateWithoutInitializing("grain_id_converted"), @@ -99,9 +99,9 @@ void testConvertGrainIDForBuffer() { Kokkos::parallel_for( "TestInitGrainIDs", total_n_grain_id_values, KOKKOS_LAMBDA(const int &n) { - int my_grain_orientation = getGrainOrientation(grain_id(n), n_grain_orientations, false); - int my_grain_number = getGrainNumber(grain_id(n), n_grain_orientations); - grain_id_converted[n] = getGrainID(my_grain_orientation, my_grain_number, n_grain_orientations); + int my_grain_orientation = getCrystalOrientation(grain_id(n), n_crystal_orientations, false); + int my_grain_number = getGrainNumber(grain_id(n), n_crystal_orientations); + grain_id_converted[n] = getGrainID(my_grain_orientation, my_grain_number, n_crystal_orientations); }); auto grain_id_converted_host = Kokkos::create_mirror_view(Kokkos::HostSpace(), grain_id_converted); for (int n = 0; n < total_n_grain_id_values; n++) diff --git a/unit_test/tstUpdate.hpp b/unit_test/tstUpdate.hpp index 96533d00..bacda581 100644 --- a/unit_test/tstUpdate.hpp +++ b/unit_test/tstUpdate.hpp @@ -53,7 +53,7 @@ void testSmallDirS() { InterfacialResponseFunction irf(inputs.domain.deltat, grid.deltax, inputs.irf); // Initialize grain orientations - Orientation orientation(id, inputs.grain_orientation_file, false); + Orientation orientation(id, inputs.crystal_orientation_file, false); MPI_Barrier(MPI_COMM_WORLD); // Initialize cell types, grain IDs, and layer IDs @@ -131,7 +131,7 @@ void testSmallEquiaxedGrain() { InterfacialResponseFunction irf(inputs.domain.deltat, grid.deltax, inputs.irf); // Initialize grain orientations - Orientation orientation(id, inputs.grain_orientation_file, false); + Orientation orientation(id, inputs.crystal_orientation_file, false); MPI_Barrier(MPI_COMM_WORLD); // Initialize cell types, grain IDs, and layer IDs