Program Listing for File VoxelizeTriplets.cxx

Return to documentation for file (larflow/Voxelizer/VoxelizeTriplets.cxx)

#include "VoxelizeTriplets.h"

#include <iostream>
#include <sstream>

#include "LArUtil/LArProperties.h"

namespace larflow {
namespace voxelizer {

  bool VoxelizeTriplets::_setup_numpy = false;

  VoxelizeTriplets::VoxelizeTriplets()
  {

    _origin.clear();
    _len.clear();

    const float driftv = larutil::LArProperties::GetME()->DriftVelocity();

    _origin.resize(3,0);
    _origin[0] = (2399-3200)*0.5*driftv;
    _origin[1] = -120.0;
    _origin[2] = 0;

    _len.resize(3,0);
    _len[0] = 1010*6*0.5*driftv;
    _len[1] = 2.0*120.0;
    _len[2] = 1037.0;

    _voxel_size = 0.3;

    _define_voxels();
  }

  VoxelizeTriplets::VoxelizeTriplets( std::vector<float> origin,
                                      std::vector<float> dim_len,
                                      float voxel_size )
    : _origin(origin),
    _len(dim_len),
    _voxel_size(voxel_size)
  {
    _define_voxels();
  }


  void VoxelizeTriplets::_define_voxels()
  {
    _ndims = (int)_origin.size();
    _nvoxels.resize(_ndims,0);

    std::stringstream ss;
    ss << "(";
    for (int v=0; v<_ndims; v++) {
      int nv = (_len[v])/_voxel_size;
      if ( fabs(nv*_voxel_size-_len[v])>0.001 )
        nv++;
      _nvoxels[v] = nv;
      ss << nv;
      if ( v+1<_ndims ) ss << ", ";
    }
    ss << ")";

    std::cout << "[VoxelizeTriplets::" << __FUNCTION__ << ".L" << __LINE__ << "] "
              << "Number of voxels defined: " << ss.str() << ", ndims=" << _ndims
              << std::endl;
    std::cout << "[VoxelizeTriplets::" << __FUNCTION__ << ".L" << __LINE__ << "] "
              << "BOUNDS: [" << _origin[0] << "," << _origin[0]+_len[0] << "] "
              << "[" << _origin[1] << "," << _origin[1]+_len[1] << "] "
              << "[" << _origin[2] << "," << _origin[2]+_len[2] << "] "
              << std::endl;
  }

  int VoxelizeTriplets::get_axis_voxel( int axis, float coord ) const {

    if ( axis<0 || axis>=_ndims ) {
      std::stringstream ss;
      ss << "[VoxelizeTriplets::" << __FUNCTION__ << ".L" << __LINE__ << "] invalid dim given: " << axis << " (_ndims=" << _ndims << ")" << std::endl;
      throw std::runtime_error(ss.str());
    }

    int vidx = (coord-_origin[axis])/_voxel_size;
    if (vidx<0 || vidx>=_nvoxels[axis] ) {
      std::stringstream ss;
      ss << "[VoxelizeTriplets::" << __FUNCTION__ << ".L" << __LINE__ << "]";
      ss << " dim[" << axis << "] coordinate[" << coord << "] "
         << "given is out of bounds [" << _origin[axis] << "," << _origin[axis]+_len[axis] << "]"
         << " vidx=" << vidx << " bounds[0," << _nvoxels[axis] << ")"
         << std::endl;
      throw std::runtime_error(ss.str());
    }

    return vidx;
  }

  void VoxelizeTriplets::make_voxeldata( const larflow::prep::PrepMatchTriplets& triplet_data )
  {

    // first we need to define the voxels that are filled
    _voxel_set.clear();

    for ( int itriplet=0; itriplet<(int)triplet_data._triplet_v.size(); itriplet++ ) {
      const std::vector<float>& pos = triplet_data._pos_v[itriplet];
      std::array<int,3> coord;
      for (int i=0; i<3; i++)
        coord[i] = get_axis_voxel(i,pos[i]);
      _voxel_set.insert( coord );
    }

    // now we assign voxel to an index
    _voxel_list.clear();
    int idx=0;
    for ( auto& coord : _voxel_set ) {
      _voxel_list[coord] = idx;
      idx++;
    }
    int nvidx = idx;

    std::cout << "[VoxelizeTriplets::" << __FUNCTION__ << ".L" << __LINE__ << "] "
              << "Filling " << nvidx << " voxels from " << triplet_data._triplet_v.size() << " triplets"
              << " fillfrac=" << float(nvidx)/((float)_nvoxels[0]*(float)_nvoxels[1]*(float)_nvoxels[2])*100.0 << "%"
              << std::endl;

    // assign triplets to voxels and vice versa
    _voxelidx_to_tripidxlist.clear();
    _voxelidx_to_tripidxlist.resize(nvidx);
    _trip2voxelidx.clear();
    _trip2voxelidx.resize( triplet_data._triplet_v.size(), 0 );

    for ( int itriplet=0; itriplet<(int)triplet_data._triplet_v.size(); itriplet++ ) {
      const std::vector<float>& pos = triplet_data._pos_v[itriplet];
      std::array<int,3> coord;
      for (int i=0; i<3; i++)
        coord[i] = get_axis_voxel(i,pos[i]);
      auto it=_voxel_list.find(coord);
      if ( it==_voxel_list.end() ) {
        throw std::runtime_error("could not find a voxel we defined!!");
      }

      int voxelidx = it->second;
      _trip2voxelidx[itriplet] = voxelidx;
      _voxelidx_to_tripidxlist[voxelidx].push_back( itriplet );
    }

  }

  PyObject* VoxelizeTriplets::make_voxeldata_dict( const larflow::prep::PrepMatchTriplets& triplet_data )
  {

    // ok now we can make the arrays
    if ( !_setup_numpy ) {
      std::cout << "[VoxelizeTriplets::" << __FUNCTION__ << ".L" << __LINE__ << "] setup numpy" << std::endl;
      import_array1(0);
      _setup_numpy = true;
    }

    int nvidx = (int)_voxel_set.size();

    // first the voxel coordinate array
    npy_intp* coord_dims = new npy_intp[2];
    coord_dims[0] = (int)nvidx;
    coord_dims[1] = (int)_ndims;
    PyArrayObject* coord_array = (PyArrayObject*)PyArray_SimpleNew( 2, coord_dims, NPY_LONG );
    for ( auto it=_voxel_list.begin(); it!=_voxel_list.end(); it++ ) {
      int vidx = it->second;
      const std::array<int,3>& coord = it->first;
      for (int j=0; j<_ndims; j++)
        *((long*)PyArray_GETPTR2( coord_array, (int)vidx, j)) = (long)coord[j];
    }
    std::cout << "  made coord array" << std::endl;

    // the voxel truth label
    bool has_truth = triplet_data._truth_v.size()==triplet_data._triplet_v.size();
    npy_intp* vlabel_dims = new npy_intp[1];
    vlabel_dims[0] = (int)nvidx;
    PyArrayObject* vlabel_array = (PyArrayObject*)PyArray_SimpleNew( 1, vlabel_dims, NPY_LONG );
    int num_true_voxels = 0;
    for ( auto it=_voxel_list.begin(); it!=_voxel_list.end(); it++ ) {
      int vidx = it->second;
      int truthlabel = 0.;

      if ( has_truth ) {
        // is there a true pixel?
        std::vector<int>& tripidx_v = _voxelidx_to_tripidxlist[vidx];
        for ( auto const& tidx : tripidx_v ) {
          if ( triplet_data._truth_v[tidx]==1 ) {
            truthlabel = 1;
          }
        }
        if ( truthlabel==1 )
          num_true_voxels++;
      }
      *((long*)PyArray_GETPTR1( vlabel_array, vidx )) = truthlabel;
    }
    std::cout << "  made truth array" << std::endl;

    // the triplet to voxel index array
    npy_intp* trip2vidx_dims = new npy_intp[1];
    trip2vidx_dims[0] = (int)_trip2voxelidx.size();
    PyArrayObject* trip2vidx_array = (PyArrayObject*)PyArray_SimpleNew( 1, trip2vidx_dims, NPY_LONG );
    for (int itriplet=0; itriplet<(int)_trip2voxelidx.size(); itriplet++ ) {
      *((long*)PyArray_GETPTR1( trip2vidx_array, itriplet )) = (long)_trip2voxelidx[itriplet];
    }
    std::cout << "  made triplet-to-voxelindex array" << std::endl;

    // finally the list of triplet indices for each voxel
    PyObject* tripidx_pylist = PyList_New( nvidx );
    for ( int vidx=0; vidx<nvidx; vidx++ ) {

      // make the array
      npy_intp* tidx_dims = new npy_intp[1];
      std::vector<int>& tripidx_v = _voxelidx_to_tripidxlist[vidx];
      tidx_dims[0] = (int)tripidx_v.size();
      PyArrayObject* array = (PyArrayObject*)PyArray_SimpleNew( 1, tidx_dims, NPY_LONG );
      for ( int i=0; i<tidx_dims[0]; i++ ) {
        *((long*)PyArray_GETPTR1( array, i )) = tripidx_v[i];
      }

      int err = PyList_SetItem( tripidx_pylist, (Py_ssize_t)vidx, (PyObject*)array );
      if (err!=0 ) {
        throw std::runtime_error("Error putting voxel's triplet list to pylist");
      }
      Py_DECREF( array );
    }
    std::cout << "  made voxel-index to triplet-list list" << std::endl;

    // the dictionary
    PyObject *d = PyDict_New();
    PyObject *key_coord     = Py_BuildValue("s", "voxcoord" );
    PyObject *key_label     = Py_BuildValue("s", "voxlabel" );
    PyObject *key_trip2vidx = Py_BuildValue("s", "trip2vidx" );
    PyObject *key_vox2trips = Py_BuildValue("s", "vox2trips_list" );

    PyDict_SetItem( d, key_coord, (PyObject*)coord_array );
    PyDict_SetItem( d, key_label, (PyObject*)vlabel_array );
    PyDict_SetItem( d, key_trip2vidx, (PyObject*)trip2vidx_array );
    PyDict_SetItem( d, key_vox2trips, (PyObject*)tripidx_pylist );

    std::cout << "  dereference" << std::endl;
    Py_DECREF( key_coord );
    Py_DECREF( key_label );
    Py_DECREF( key_trip2vidx );
    Py_DECREF( key_vox2trips );
    // Py_DECREF( coord_array );
    // Py_DECREF( vlabel_array );
    // Py_DECREF( trip2vidx_array );
    // Py_DECREF( tripidx_pylist );

    return d;
  }

  PyObject* VoxelizeTriplets::make_voxeldata_dict()
  {
    return make_voxeldata_dict( _triplet_maker );
  }

  void VoxelizeTriplets::process_fullchain( larcv::IOManager& iolcv,
                                            std::string adc_producer,
                                            std::string chstatus_producer,
                                            bool has_mc )
  {

    _triplet_maker.clear();

    const float adc_threshold = 10.;
    const bool calc_triplet_pos3d = true;
    _triplet_maker.process( iolcv, adc_producer, chstatus_producer, adc_threshold, calc_triplet_pos3d );

    if ( has_mc ) {
      larcv::EventImage2D* ev_larflow =
        (larcv::EventImage2D*)iolcv.get_data(larcv::kProductImage2D,"larflow");
      _triplet_maker.make_truth_vector( ev_larflow->Image2DArray() );
    }

    make_voxeldata( _triplet_maker );

    // persistancy:

    // save larflow3dhits for visualization
    // save class in ttree data for training

  }

}
}