LCOV - code coverage report
Current view: top level - models - farfieldboundaryoperator.cpp (source / functions) Coverage Total Hit
Test: Palace Coverage Report Lines: 27.7 % 47 13
Test Date: 2025-10-23 22:45:05 Functions: 50.0 % 4 2
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
       2              : // SPDX-License-Identifier: Apache-2.0
       3              : 
       4              : #include "farfieldboundaryoperator.hpp"
       5              : 
       6              : #include <set>
       7              : #include "linalg/densematrix.hpp"
       8              : #include "models/materialoperator.hpp"
       9              : #include "utils/communication.hpp"
      10              : #include "utils/geodata.hpp"
      11              : #include "utils/iodata.hpp"
      12              : #include "utils/prettyprint.hpp"
      13              : 
      14              : namespace palace
      15              : {
      16              : 
      17           17 : FarfieldBoundaryOperator::FarfieldBoundaryOperator(const IoData &iodata,
      18              :                                                    const MaterialOperator &mat_op,
      19           17 :                                                    const mfem::ParMesh &mesh)
      20           17 :   : mat_op(mat_op), farfield_attr(SetUpBoundaryProperties(iodata, mesh))
      21              : {
      22              :   // Print out BC info for all farfield attributes.
      23           17 :   if (farfield_attr.Size())
      24              :   {
      25            0 :     Mpi::Print("\nConfiguring Robin absorbing BC (order {:d}) at attributes:\n", order);
      26              :     std::sort(farfield_attr.begin(), farfield_attr.end());
      27            0 :     utils::PrettyPrint(farfield_attr);
      28              :   }
      29           17 : }
      30              : 
      31              : mfem::Array<int>
      32           17 : FarfieldBoundaryOperator::SetUpBoundaryProperties(const IoData &iodata,
      33              :                                                   const mfem::ParMesh &mesh)
      34              : {
      35              :   // Check that impedance boundary attributes have been specified correctly.
      36           17 :   int bdr_attr_max = mesh.bdr_attributes.Size() ? mesh.bdr_attributes.Max() : 0;
      37              :   mfem::Array<int> bdr_attr_marker;
      38           17 :   if (!iodata.boundaries.farfield.empty())
      39              :   {
      40              :     bdr_attr_marker.SetSize(bdr_attr_max);
      41              :     bdr_attr_marker = 0;
      42            0 :     for (auto attr : mesh.bdr_attributes)
      43              :     {
      44            0 :       bdr_attr_marker[attr - 1] = 1;
      45              :     }
      46              :     std::set<int> bdr_warn_list;
      47            0 :     for (auto attr : iodata.boundaries.farfield.attributes)
      48              :     {
      49              :       // MFEM_VERIFY(attr > 0 && attr <= bdr_attr_max,
      50              :       //             "Absorbing boundary attribute tags must be non-negative and correspond
      51              :       //             " "to attributes in the mesh!");
      52              :       // MFEM_VERIFY(bdr_attr_marker[attr - 1],
      53              :       //             "Unknown absorbing boundary attribute " << attr << "!");
      54            0 :       if (attr <= 0 || attr > bdr_attr_max || !bdr_attr_marker[attr - 1])
      55              :       {
      56              :         bdr_warn_list.insert(attr);
      57              :       }
      58            0 :       if (!bdr_warn_list.empty())
      59              :       {
      60            0 :         Mpi::Print("\n");
      61            0 :         Mpi::Warning(
      62              :             "Unknown absorbing boundary attributes!\nSolver will just ignore them!");
      63            0 :         utils::PrettyPrint(bdr_warn_list, "Boundary attribute list:");
      64            0 :         Mpi::Print("\n");
      65              :       }
      66              :     }
      67              :   }
      68              : 
      69              :   // Set the order of the farfield boundary condition.
      70           17 :   order = iodata.boundaries.farfield.order;
      71              : 
      72              :   // Mark selected boundary attributes from the mesh as farfield.
      73              :   mfem::Array<int> farfield_bcs;
      74           17 :   farfield_bcs.Reserve(static_cast<int>(iodata.boundaries.farfield.attributes.size()));
      75           17 :   for (auto attr : iodata.boundaries.farfield.attributes)
      76              :   {
      77            0 :     if (attr <= 0 || attr > bdr_attr_max || !bdr_attr_marker[attr - 1])
      78              :     {
      79            0 :       continue;  // Can just ignore if wrong
      80              :     }
      81            0 :     farfield_bcs.Append(attr);
      82              :   }
      83           17 :   MFEM_VERIFY(farfield_bcs.Size() == 0 || order < 2 ||
      84              :                   iodata.problem.type == ProblemType::DRIVEN ||
      85              :                   iodata.problem.type == ProblemType::EIGENMODE,
      86              :               "Second-order farfield boundaries are only available for frequency "
      87              :               "domain simulations!");
      88           17 :   return farfield_bcs;
      89              : }
      90              : 
      91            0 : void FarfieldBoundaryOperator::AddDampingBdrCoefficients(double coeff,
      92              :                                                          MaterialPropertyCoefficient &fb)
      93              : {
      94              :   // First-order absorbing boundary condition.
      95            0 :   if (farfield_attr.Size())
      96              :   {
      97            0 :     MaterialPropertyCoefficient invz0_func(mat_op.GetBdrAttributeToMaterial(),
      98            0 :                                            mat_op.GetInvImpedance());
      99            0 :     invz0_func.RestrictCoefficient(mat_op.GetCeedBdrAttributes(farfield_attr));
     100            0 :     fb.AddCoefficient(invz0_func.GetAttributeToMaterial(),
     101              :                       invz0_func.GetMaterialProperties(), coeff);
     102            0 :   }
     103            0 : }
     104              : 
     105            0 : void FarfieldBoundaryOperator::AddExtraSystemBdrCoefficients(
     106              :     double omega, MaterialPropertyCoefficient &dfbr, MaterialPropertyCoefficient &dfbi)
     107              : {
     108              :   // Contribution for second-order absorbing BC. See Jin Section 9.3 for reference. The β
     109              :   // coefficient for the second-order ABC is 1/(2ik+2/r). Taking the radius of curvature
     110              :   // as infinity (plane wave scattering), the r-dependence vanishes and the contribution
     111              :   // is purely imaginary. Multiplying through by μ⁻¹ we get the material coefficient to ω
     112              :   // as 1 / (μ √(με)). Also, this implementation ignores the divergence term ∇⋅Eₜ, as
     113              :   // COMSOL does as well.
     114            0 :   if (farfield_attr.Size() && order > 1)
     115              :   {
     116              :     mfem::DenseTensor muinvc0 =
     117            0 :         linalg::Mult(mat_op.GetInvPermeability(), mat_op.GetLightSpeed());
     118            0 :     MaterialPropertyCoefficient muinvc0_func(mat_op.GetBdrAttributeToMaterial(), muinvc0);
     119            0 :     muinvc0_func.RestrictCoefficient(mat_op.GetCeedBdrAttributes(farfield_attr));
     120              : 
     121              :     // Instead getting the correct normal of farfield boundary elements, just pick the
     122              :     // the first element normal. This is fine as long as the farfield material properties
     123              :     // are not anisotropic.
     124            0 :     mfem::Vector normal(mat_op.SpaceDimension());
     125            0 :     normal = 0.0;
     126            0 :     normal(0) = 1.0;
     127            0 :     muinvc0_func.NormalProjectedCoefficient(normal);
     128              : 
     129            0 :     dfbi.AddCoefficient(muinvc0_func.GetAttributeToMaterial(),
     130              :                         muinvc0_func.GetMaterialProperties(), 0.5 / omega);
     131            0 :   }
     132            0 : }
     133              : 
     134              : }  // namespace palace
        

Generated by: LCOV version 2.0-1