LCOV - code coverage report
Current view: top level - src/meshgenerators - EBSDMeshGenerator.C (source / functions) Hit Total Coverage
Test: idaholab/moose phase_field: #31405 (292dce) with base fef103 Lines: 85 87 97.7 %
Date: 2025-09-04 07:55:36 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "EBSDMeshGenerator.h"
      11             : #include "MooseApp.h"
      12             : #include "MathUtils.h"
      13             : 
      14             : #include "libmesh/int_range.h"
      15             : #include "libmesh/mesh_refinement.h"
      16             : 
      17             : #include <fstream>
      18             : 
      19             : registerMooseObject("PhaseFieldApp", EBSDMeshGenerator);
      20             : 
      21             : InputParameters
      22         344 : EBSDMeshGenerator::validParams()
      23             : {
      24         344 :   InputParameters params = MeshGenerator::validParams();
      25         344 :   params.addClassDescription("Mesh generated from a specified DREAM.3D EBSD data file.");
      26         688 :   params.addRequiredParam<FileName>("filename", "The name of the file containing the EBSD data");
      27             : 
      28         688 :   params.addDeprecatedParam<unsigned int>("uniform_refine",
      29             :                                           "Deprecated. Use `pre_refine` instead.",
      30             :                                           "Deprecated. Use `pre_refine` instead.");
      31         688 :   params.addParam<unsigned int>(
      32             :       "pre_refine",
      33         688 :       0,
      34             :       "Number of coarsening levels available in adaptive mesh refinement. The resulting mesh will "
      35             :       "have one mesh element per EBSD data cell, but will be based on a refined coarser mesh with "
      36             :       "'pre_refine' levels of refinement. This requires all dimension of the EBSD data to be "
      37             :       "divisible by 2^pre_refine.(this parameter was formerly called 'uniform_refine')");
      38             : 
      39         688 :   params.addParam<processor_id_type>(
      40             :       "num_cores_for_partition",
      41             :       "Number of cores for partitioning the graph (dafaults to the number of MPI ranks)");
      42         344 :   return params;
      43           0 : }
      44             : 
      45         176 : EBSDMeshGenerator::EBSDMeshGenerator(const InputParameters & parameters)
      46             :   : MeshGenerator(parameters),
      47         352 :     _distributed(_mesh->isDistributedMesh()),
      48         352 :     _filename(getParam<FileName>("filename")),
      49         704 :     _pre_refine(isParamValid("pre_refine") ? getParam<unsigned int>("pre_refine")
      50         176 :                                            : getParam<unsigned int>("uniform_refine")),
      51         352 :     _base(buildMeshSubgenerator())
      52             : {
      53         168 : }
      54             : 
      55             : std::unique_ptr<MeshBase> &
      56         176 : EBSDMeshGenerator::buildMeshSubgenerator()
      57             : {
      58         176 :   readEBSDHeader();
      59             : 
      60             :   const auto generator_type =
      61         170 :       _distributed ? "DistributedRectilinearMeshGenerator" : "GeneratedMeshGenerator";
      62         170 :   auto params = _app.getFactory().getValidParams(generator_type);
      63             : 
      64         342 :   params.set<MooseEnum>("dim") = (_geometry.dim == 1 ? "1" : (_geometry.dim == 2 ? "2" : "3"));
      65             : 
      66             :   std::array<unsigned int, 3> nr;
      67         170 :   nr[0] = _geometry.n[0];
      68         170 :   nr[1] = _geometry.n[1];
      69         170 :   nr[2] = _geometry.n[2];
      70             : 
      71             :   // set min/max box length
      72         170 :   params.set<Real>("xmin") = _geometry.min[0];
      73         170 :   params.set<Real>("xmax") = nr[0] * _geometry.d[0] + _geometry.min[0];
      74         170 :   params.set<Real>("ymin") = _geometry.min[1];
      75         170 :   params.set<Real>("ymax") = nr[1] * _geometry.d[1] + _geometry.min[1];
      76         170 :   params.set<Real>("zmin") = _geometry.min[2];
      77         170 :   params.set<Real>("zmax") = nr[2] * _geometry.d[2] + _geometry.min[2];
      78             : 
      79             :   // check if the requested uniform refine level is possible and determine initial grid size
      80         506 :   for (auto i : make_range(_geometry.dim))
      81             :   {
      82         338 :     auto factor = MathUtils::pow(2, _pre_refine);
      83         338 :     if (nr[i] % factor != 0)
      84           2 :       paramError("pre_refine",
      85             :                  "EBSDMeshGenerator error. Requested levels of pre refinement not possible.");
      86         336 :     nr[i] /= factor;
      87             :   }
      88             : 
      89         168 :   if (_distributed)
      90             :   {
      91          22 :     params.set<dof_id_type>("nx") = nr[0];
      92          22 :     params.set<dof_id_type>("ny") = nr[1];
      93          22 :     params.set<dof_id_type>("nz") = nr[2];
      94          22 :     params.set<processor_id_type>("num_cores_for_partition") =
      95          44 :         isParamValid("num_cores_for_partition")
      96          44 :             ? getParam<processor_id_type>("num_cores_for_partition")
      97             :             : 0;
      98             :   }
      99             :   else
     100             :   {
     101         146 :     params.set<unsigned int>("nx") = nr[0];
     102         146 :     params.set<unsigned int>("ny") = nr[1];
     103         146 :     params.set<unsigned int>("nz") = nr[2];
     104             :   }
     105             : 
     106         336 :   addMeshSubgenerator(generator_type, name() + "_base_mesh", params);
     107         504 :   return getMeshByName(name() + "_base_mesh");
     108         168 : }
     109             : 
     110             : void
     111         176 : EBSDMeshGenerator::readEBSDHeader()
     112             : {
     113         176 :   std::ifstream stream_in(_filename.c_str());
     114             : 
     115         176 :   if (!stream_in)
     116           0 :     paramError("filename", "Can't open EBSD file: ", _filename);
     117             : 
     118             :   // Labels to look for in the header
     119             :   const std::vector<std::string> labels = {
     120         176 :       "x_step", "x_dim", "y_step", "y_dim", "z_step", "z_dim", "x_min", "y_min", "z_min"};
     121             : 
     122             :   // Dimension variables to store once they are found in the header
     123             :   // X_step, X_Dim, Y_step, Y_Dim, Z_step, Z_Dim
     124             :   // We use Reals even though the Dim values should all be integers...
     125         176 :   std::vector<Real> label_vals(labels.size(), 0.0);
     126             : 
     127             :   std::string line;
     128        6150 :   while (std::getline(stream_in, line))
     129             :   {
     130             :     // We need to process the comment lines that have:
     131             :     // X_step, X_Dim
     132             :     // Y_step, Y_Dim
     133             :     // Z_step, Z_Dim
     134             :     // in them. The labels are case insensitive.
     135        6150 :     if (line.find("#") == 0)
     136             :     {
     137             :       // Process lines that start with a comment character (comments and meta data)
     138             :       std::transform(line.begin(), line.end(), line.begin(), ::tolower);
     139             : 
     140       51820 :       for (unsigned i = 0; i < labels.size(); ++i)
     141       47430 :         if (line.find(labels[i]) != std::string::npos)
     142             :         {
     143             :           std::string dummy;
     144        1584 :           std::istringstream iss(line);
     145        1584 :           iss >> dummy >> dummy >> label_vals[i];
     146             : 
     147             :           // One label per line, break out of for loop over labels
     148             :           break;
     149        1584 :         }
     150             :     }
     151             :     else
     152             :       // first non comment line marks the end of the header
     153             :       break;
     154             :   }
     155             : 
     156             :   // Copy stuff out of the label_vars array into class variables
     157         176 :   _geometry.d[0] = label_vals[0];
     158         176 :   _geometry.n[0] = label_vals[1];
     159         176 :   _geometry.min[0] = label_vals[6];
     160             : 
     161         176 :   _geometry.d[1] = label_vals[2];
     162         176 :   _geometry.n[1] = label_vals[3];
     163         176 :   _geometry.min[1] = label_vals[7];
     164             : 
     165         176 :   _geometry.d[2] = label_vals[4];
     166         176 :   _geometry.n[2] = label_vals[5];
     167         176 :   _geometry.min[2] = label_vals[8];
     168             : 
     169             :   unsigned int dim;
     170             : 
     171             :   // determine mesh dimension
     172         350 :   for (dim = 3; dim > 0 && _geometry.n[dim - 1] == 0; --dim)
     173             :     ;
     174             : 
     175             :   // check if the data has nonzero stepsizes
     176         518 :   for (unsigned i = 0; i < dim; ++i)
     177             :   {
     178         346 :     if (_geometry.n[i] == 0)
     179           2 :       mooseError("Error reading header, EBSD grid size is zero.");
     180         344 :     if (_geometry.d[i] == 0.0)
     181           2 :       mooseError("Error reading header, EBSD data step size is zero.");
     182             :   }
     183             : 
     184         172 :   if (dim == 0)
     185           2 :     mooseError("Error reading header, EBSD data is zero dimensional.");
     186             : 
     187         170 :   _geometry.dim = dim;
     188         170 : }
     189             : 
     190             : std::unique_ptr<MeshBase>
     191         132 : EBSDMeshGenerator::generate()
     192             : {
     193         132 :   if (_pre_refine)
     194             :   {
     195          16 :     libMesh::MeshRefinement mesh_refinement(*_base);
     196          16 :     mesh_refinement.uniformly_refine(_pre_refine);
     197          16 :   }
     198         132 :   return std::move(_base);
     199             : }

Generated by: LCOV version 1.14