LCOV - code coverage report
Current view: top level - src/libtorch/utils - LibtorchUtils.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #33416 (b10b36) with base 9fbd27 Lines: 34 42 81.0 %
Date: 2026-07-23 16:15:30 Functions: 7 8 87.5 %
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             : #ifdef MOOSE_LIBTORCH_ENABLED
      11             : 
      12             : #include "LibtorchUtils.h"
      13             : 
      14             : #include <algorithm>
      15             : #include <functional>
      16             : #include <numeric>
      17             : 
      18             : namespace LibtorchUtils
      19             : {
      20             : 
      21             : namespace
      22             : {
      23             : 
      24             : template <typename DataType>
      25             : torch::TensorOptions
      26          53 : tensorOptions()
      27             : {
      28             :   if constexpr (std::is_same<DataType, double>::value)
      29          53 :     return torch::TensorOptions().dtype(at::kDouble);
      30             :   else if constexpr (std::is_same<DataType, float>::value)
      31             :     return torch::TensorOptions().dtype(at::kFloat);
      32             :   else
      33             :     static_assert(Moose::always_false<DataType>,
      34             :                   "Tensor conversion is not implemented for the given data type!");
      35             : }
      36             : 
      37             : template <typename DataType>
      38             : void
      39          54 : checkTensorShape(const std::vector<DataType> & vector, c10::IntArrayRef sizes)
      40             : {
      41             :   const auto expected_numel =
      42          54 :       std::accumulate(sizes.begin(), sizes.end(), int64_t{1}, std::multiplies<int64_t>());
      43             : 
      44          54 :   if (expected_numel != cast_int<int64_t>(vector.size()))
      45           1 :     mooseError("The requested tensor shape is incompatible with the vector size.");
      46          53 : }
      47             : 
      48             : } // namespace
      49             : 
      50             : template <typename DataType>
      51             : torch::Tensor
      52          51 : vectorToTensorCopy(const std::vector<DataType> & vector, c10::IntArrayRef sizes)
      53             : {
      54          51 :   checkTensorShape(vector, sizes);
      55             : 
      56          51 :   const auto options = tensorOptions<DataType>();
      57          51 :   auto tensor = torch::empty(sizes, options);
      58             : 
      59          51 :   if (!vector.empty())
      60          51 :     std::copy(vector.begin(), vector.end(), tensor.template data_ptr<DataType>());
      61             : 
      62         102 :   return tensor;
      63           0 : }
      64             : 
      65             : // Explicitly instantiate for DataType=Real
      66             : template torch::Tensor vectorToTensorCopy<Real>(const std::vector<Real> & vector,
      67             :                                                 c10::IntArrayRef sizes);
      68             : 
      69             : template <typename DataType>
      70             : void
      71          51 : vectorToTensor(const std::vector<DataType> & vector, torch::Tensor & tensor, const bool detach)
      72             : {
      73          51 :   tensor = vectorToTensorCopy(vector, {long(vector.size()), 1});
      74             : 
      75          51 :   if (detach)
      76           0 :     tensor = tensor.detach();
      77          51 : }
      78             : 
      79             : // Explicitly instantiate for DataType=Real
      80             : template void
      81             : vectorToTensor<Real>(const std::vector<Real> & vector, torch::Tensor & tensor, const bool detach);
      82             : 
      83             : template <typename DataType>
      84             : torch::Tensor
      85           3 : vectorToTensorView(std::vector<DataType> & vector, c10::IntArrayRef sizes)
      86             : {
      87           3 :   checkTensorShape(vector, sizes);
      88             : 
      89           2 :   const auto options = tensorOptions<DataType>();
      90           2 :   if (vector.empty())
      91           1 :     return torch::empty(sizes, options);
      92             : 
      93           1 :   return torch::from_blob(vector.data(), sizes, options);
      94             : }
      95             : 
      96             : // Explicitly instantiate for DataType=Real
      97             : template torch::Tensor vectorToTensorView<Real>(std::vector<Real> & vector, c10::IntArrayRef sizes);
      98             : 
      99             : void
     100           0 : moveToLibtorchDevice(torch::Tensor & tensor, const torch::DeviceType device_type)
     101             : {
     102           0 :   tensor = tensor.to(device_type);
     103           0 : }
     104             : 
     105             : torch::Tensor
     106           2 : toCPUContiguous(const torch::Tensor & tensor)
     107             : {
     108             :   // CPU accessors can handle strides, but data_ptr()-based reads require dense logical order.
     109           2 :   return tensor.detach().to(tensor.options().device(at::kCPU)).contiguous();
     110             : }
     111             : 
     112             : template <typename DataType>
     113             : void
     114           1 : tensorToVector(torch::Tensor & tensor, std::vector<DataType> & vector)
     115             : {
     116             :   try
     117             :   {
     118           1 :     tensor.data_ptr<DataType>();
     119             :   }
     120           0 :   catch (const c10::Error & e)
     121             :   {
     122           0 :     mooseError(
     123           0 :         "Cannot cast tensor values to", MooseUtils::prettyCppType<DataType>(), "!\n", e.msg());
     124             :   }
     125             : 
     126           1 :   const auto & sizes = tensor.sizes();
     127             : 
     128           1 :   long int max_size = 0;
     129           3 :   for (const auto & dim_size : sizes)
     130             :     // We do this comparison because XCode complains if we use std::max
     131           2 :     max_size = dim_size > max_size ? dim_size : max_size;
     132             : 
     133             :   mooseAssert(max_size == tensor.numel(), "The given tensor should be one-dimensional!");
     134           2 :   vector = {tensor.data_ptr<DataType>(), tensor.data_ptr<DataType>() + tensor.numel()};
     135           1 : }
     136             : 
     137             : // Explicitly instantiate for DataType=Real
     138             : template void tensorToVector<Real>(torch::Tensor & tensor, std::vector<Real> & vector);
     139             : 
     140             : } // LibtorchUtils namespace
     141             : 
     142             : #endif

Generated by: LCOV version 1.14