Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
getChildNodesWithTrf.cxx 4.38 KiB
/*
  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
*/
#include <utility>

#include "GeoModelHelpers/getChildNodesWithTrf.h"

#include "GeoModelHelpers/GeoPhysVolSorter.h"
#include "GeoModelHelpers/TransformSorter.h"
#include "GeoModelKernel/GeoVolumeCursor.h"
#include "GeoModelKernel/GeoFullPhysVol.h"

namespace {
    constexpr std::string_view dummyNodeName{"ANON"};
    ///typeis function uses simple arguments to typeid (not an expression) to avoid warnings
    template<class A, class B>
    bool
    typeis(B && b){
      return typeid(A) == typeid(b);
    }
}


 GeoChildNodeWithTrf::GeoChildNodeWithTrf(GeoVolumeCursor& curs):
    transform{curs.getTransform()}, 
    volume{curs.getVolume()},
    nodeName{curs.getName()},
    isAlignable{curs.hasAlignableTransform()},
    isSensitive{typeis<GeoFullPhysVol>(*volume)},
    volumeId{static_cast<const std::optional<int>&>(curs.getId())} {
    //// Do not specify a node name if it's a dummy one
    if (nodeName == dummyNodeName) {
        nodeName = volume->getLogVol()->getName();
    }
}

std::vector <GeoChildNodeWithTrf> getChildrenWithRef(PVConstLink physVol,
                                                     bool summarizeEqualVol) {
    std::vector<GeoChildNodeWithTrf> children{};
 
    static const GeoPhysVolSorter physVolSort{};
    static const GeoTrf::TransformSorter transSort{};

    
    GeoVolumeCursor cursor{std::move(physVol)};
    GeoTrf::Transform3D lastNodeTrf{GeoTrf::Transform3D::Identity()};

    while (!cursor.atEnd()) {
        if (children.empty() || !summarizeEqualVol) {
            children.emplace_back(cursor);
            cursor.next();
            continue;
         }
         GeoChildNodeWithTrf& prevChild{children.back()};
         GeoChildNodeWithTrf currentChild{cursor};
         if (prevChild.isAlignable != currentChild.isAlignable ||
             prevChild.isSensitive != currentChild.isSensitive ||
             physVolSort.compare(prevChild.volume, currentChild.volume)) {
            children.emplace_back(std::move(currentChild));
         } else if (prevChild.nCopies == 1) {
            ++prevChild.nCopies;
            prevChild.volumeId = std::nullopt;
            prevChild.inductionRule = prevChild.transform.inverse() * 
                                      currentChild.transform;            
         } else if (!transSort.compare(prevChild.inductionRule, 
                                      lastNodeTrf.inverse() * currentChild.transform)) {
            ++prevChild.nCopies;
        } else {
            children.emplace_back(std::move(currentChild));
        }
        lastNodeTrf = cursor.getTransform();   
        cursor.next();
    }
    return children;
}
std::vector<GeoChildNodeWithTrf> getAllSubVolumes(PVConstLink physVol,
                                                  const std::function<bool(const GeoChildNodeWithTrf&)>& selector,
                                                  bool summarizeEqualVol) {
    std::vector<GeoChildNodeWithTrf> children{getChildrenWithRef(std::move(physVol), summarizeEqualVol)}, subVolumes{};
    subVolumes.reserve(children.size());
    for (const GeoChildNodeWithTrf& child : children) {
        std::vector<GeoChildNodeWithTrf> grandChildren = getAllSubVolumes(child.volume, selector, summarizeEqualVol);
        if (selector(child)) subVolumes.push_back(child);
  
        subVolumes.reserve(grandChildren.size() + subVolumes.capacity());
        std::transform(std::make_move_iterator(grandChildren.begin()),
                       std::make_move_iterator(grandChildren.end()),
                       std::back_inserter(subVolumes), [&child](GeoChildNodeWithTrf&& grandChild){
                            grandChild.transform = child.transform * grandChild.transform;
                            return grandChild;
                       });
    }
    return subVolumes;
 }


std::vector<GeoChildNodeWithTrf> getAllSubVolumes(PVConstLink physVol) {
    return getAllSubVolumes(std::move(physVol), 
                            [](const GeoChildNodeWithTrf& child){
                                        return true;}, false);
}

bool hasFullPhysVolInTree(const PVConstLink& physVol) {
    if (typeis<GeoFullPhysVol>(*physVol) ||
        typeis<GeoVFullPhysVol>(*physVol)){
        return true;
    }
    for (unsigned int ch = 0; ch < physVol->getNChildVols(); ++ch) {
        if (hasFullPhysVolInTree(physVol->getChildVol(ch))) return true;
    }

    return false;
}