LCOV - code coverage report
Current view: top level - tensors - crystallography.cxx (source / functions) Coverage Total Hit
Test: coverage.info Lines: 98.1 % 54 53
Test Date: 2025-10-02 16:03:03 Functions: 100.0 % 6 6

            Line data    Source code
       1              : // Copyright 2024, UChicago Argonne, LLC
       2              : // All Rights Reserved
       3              : // Software Name: NEML2 -- the New Engineering material Model Library, version 2
       4              : // By: Argonne National Laboratory
       5              : // OPEN SOURCE LICENSE (MIT)
       6              : //
       7              : // Permission is hereby granted, free of charge, to any person obtaining a copy
       8              : // of this software and associated documentation files (the "Software"), to deal
       9              : // in the Software without restriction, including without limitation the rights
      10              : // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      11              : // copies of the Software, and to permit persons to whom the Software is
      12              : // furnished to do so, subject to the following conditions:
      13              : //
      14              : // The above copyright notice and this permission notice shall be included in
      15              : // all copies or substantial portions of the Software.
      16              : //
      17              : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      18              : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      19              : // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      20              : // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      21              : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      22              : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      23              : // THE SOFTWARE.
      24              : 
      25              : #include "neml2/tensors/crystallography.h"
      26              : 
      27              : #include "neml2/tensors/Transformable.h"
      28              : #include "neml2/tensors/tensors.h"
      29              : #include "neml2/tensors/functions/cat.h"
      30              : #include "neml2/misc/assertions.h"
      31              : 
      32              : namespace neml2::crystallography
      33              : {
      34              : namespace crystal_symmetry_operators
      35              : {
      36              : Quaternion
      37           24 : tetragonal(const TensorOptions & options)
      38              : {
      39         1008 :   return Quaternion::create({{o, z, z, z},
      40              :                              {z, z, o, z},
      41              :                              {z, o, z, z},
      42              :                              {z, z, z, o},
      43              :                              {a, z, z, -a},
      44              :                              {a, z, z, a},
      45              :                              {z, a, a, z},
      46              :                              {z, -a, a, z}},
      47          264 :                             options);
      48          816 : }
      49              : 
      50              : Quaternion
      51           20 : hexagonal(const TensorOptions & options)
      52              : {
      53         1240 :   return Quaternion::create({{o, z, z, z},
      54              :                              {-h, z, z, b},
      55              :                              {h, z, z, b},
      56              :                              {b, z, z, -h},
      57              :                              {z, z, z, o},
      58              :                              {b, z, z, h},
      59              :                              {z, -h, b, z},
      60              :                              {z, o, z, z},
      61              :                              {z, h, b, z},
      62              :                              {z, b, h, z},
      63              :                              {z, z, o, z},
      64              :                              {z, b, -h, z}},
      65          300 :                             options);
      66         1000 : }
      67              : 
      68              : Quaternion
      69           41 : cubic(const TensorOptions & options)
      70              : {
      71         5002 :   return Quaternion::create({{o, z, z, z},   {h, h, h, h},    {-h, h, h, h},  {h, -h, h, h},
      72              :                              {h, h, -h, h},  {-h, -h, -h, h}, {h, -h, -h, h}, {-h, -h, h, h},
      73              :                              {-h, h, -h, h}, {z, z, o, z},    {z, z, z, o},   {z, o, z, z},
      74              :                              {z, -a, z, a},  {z, a, z, a},    {a, z, a, z},   {a, z, -a, z},
      75              :                              {z, z, -a, a},  {a, a, z, z},    {a, -a, z, z},  {z, z, a, a},
      76              :                              {z, -a, a, z},  {a, z, z, -a},   {z, a, a, z},   {a, z, z, a}},
      77         1107 :                             options);
      78         4018 : }
      79              : } // namespace crystal_symmetry_operators
      80              : 
      81              : R2
      82           77 : symmetry_operations_from_orbifold(const std::string & orbifold, const TensorOptions & options)
      83              : {
      84              :   using namespace crystal_symmetry_operators;
      85              : 
      86           77 :   if (orbifold == "432")
      87           37 :     return transform_from_quaternion(cubic(options));
      88              : 
      89           40 :   if (orbifold == "23")
      90           16 :     return transform_from_quaternion(cubic(options).batch_index({indexing::Slice(0, 12)}));
      91              : 
      92           36 :   if (orbifold == "622")
      93            4 :     return transform_from_quaternion(hexagonal(options));
      94              : 
      95           32 :   if (orbifold == "32")
      96              :     return transform_from_quaternion(
      97           28 :         batch_cat({hexagonal(options).batch_index({indexing::Slice(0, 3)}),
      98           24 :                    hexagonal(options).batch_index({indexing::Slice(9, 12)})}));
      99              : 
     100           28 :   if (orbifold == "6")
     101           16 :     return transform_from_quaternion(hexagonal(options).batch_index({indexing::Slice(0, 6)}));
     102              : 
     103           24 :   if (orbifold == "3")
     104           16 :     return transform_from_quaternion(hexagonal(options).batch_index({indexing::Slice(0, 3)}));
     105              : 
     106           20 :   if (orbifold == "42")
     107            4 :     return transform_from_quaternion(tetragonal(options));
     108              : 
     109           16 :   if (orbifold == "4")
     110              :     return transform_from_quaternion(
     111           28 :         batch_cat({tetragonal(options).batch_index({indexing::Slice(0, 1)}),
     112           24 :                    tetragonal(options).batch_index({indexing::Slice(3, 6)})}));
     113              : 
     114           12 :   if (orbifold == "222")
     115           16 :     return transform_from_quaternion(tetragonal(options).batch_index({indexing::Slice(0, 4)}));
     116              : 
     117            8 :   if (orbifold == "2")
     118           16 :     return transform_from_quaternion(tetragonal(options).batch_index({indexing::Slice(0, 2)}));
     119              : 
     120            4 :   if (orbifold == "1")
     121           16 :     return transform_from_quaternion(tetragonal(options).batch_index({indexing::Slice(0, 1)}));
     122              : 
     123            0 :   throw NEMLException("Unknown crystal class " + orbifold);
     124          120 : }
     125              : 
     126              : Vec
     127           66 : unique_bidirectional(const R2 & ops, const Vec & inp)
     128              : {
     129           66 :   neml_assert_dbg(inp.batch_dim() == 0);
     130              :   // Batched tensor with all possible answers
     131           66 :   auto options = ops * inp;
     132              :   // I think we have to go one by one...
     133              :   // Slightly annoying that while Vec and ATensor are convertible a
     134              :   // list of Vecs aren't convertable into a TensorList
     135          330 :   std::vector<ATensor> unique{ATensor(options.batch_index({0}))};
     136           66 :   Vec unique_vecs = Vec(at::stack(unique));
     137         1584 :   for (Size i = 1; i < options.batch_size(0).concrete(); i++)
     138              :   {
     139         3036 :     auto vi = options.batch_index({i});
     140              :     // Compares list of vectors to vector to figure out if any are the same
     141         2574 :     auto same = [](const ATensor & a, const ATensor & b)
     142         2574 :     { return at::any(at::all(at::isclose(a, b), 1)); };
     143         1518 :     if (!(same(unique_vecs, vi).item<bool>() || same(unique_vecs, -vi).item<bool>()))
     144              :     {
     145          264 :       unique.emplace_back(vi);
     146          264 :       unique_vecs = Vec(at::stack(unique));
     147              :     }
     148         1518 :   }
     149              :   // Get the batch of all possible answers
     150          132 :   return unique_vecs;
     151         1716 : }
     152              : 
     153              : } // namespace neml2
        

Generated by: LCOV version 2.0-1