コード例 #1
0
bool getISMRMRMetaValues(const ISMRMRD::MetaContainer& attrib, const std::string& name, std::vector<std::string>& v)
{
    try
    {
        size_t num = attrib.length(name.c_str());
        if ( num == 0 )
        {
            v.clear();
            GWARN_STREAM("getISMRMRMetaValues, can not find field : " << name);
            return true;
        }

        v.resize(num);

        size_t ii;
        for ( ii=0; ii<num; ii++ )
        {
            v[ii] = std::string( attrib.as_str(name.c_str(), ii) );
        }
    }
    catch(...)
    {
        GERROR_STREAM("Error happened in getISMRMRMetaValues(const ISMRMRD::MetaContainer& attrib, const std::string& name, std::vector<std::string>& v) ... ");
        return false;
    }

    return true;
}
コード例 #2
0
bool appendISMRMRMetaValues(ISMRMRD::MetaContainer& attrib, const std::string& name, const std::vector<std::string>& v)
{
    try
    {
        size_t num = v.size();
        if ( num == 0 )
        {
            GWARN_STREAM("appendISMRMRMetaValues, input vector is empty ... " << name);
            return true;
        }

        attrib.append(name.c_str(), v[0].c_str());

        size_t ii;
        for ( ii=1; ii<v.size(); ii++ )
        {
            attrib.append(name.c_str(), v[ii].c_str());
        }
    }
    catch(...)
    {
        GERROR_STREAM("Error happened in appendISMRMRMetaValues(ISMRMRD::MetaContainer& attrib, const std::string& name, const std::vector<std::string>& v) ... ");
        return false;
    }

    return true;
}
コード例 #3
0
    size_t MultiChannelCartesianGrappaReconGadget::compute_image_number(ISMRMRD::ImageHeader& imheader, size_t encoding, size_t CHA, size_t cha, size_t E2)
    {
        if (encoding >= meas_max_idx_.size())
        {
            GWARN_STREAM("encoding >= meas_max_idx_.size()");
            encoding = 0;
        }

        size_t SET = meas_max_idx_[encoding].set + 1;
        size_t REP = meas_max_idx_[encoding].repetition + 1;
        size_t PHS = meas_max_idx_[encoding].phase + 1;
        size_t SLC = meas_max_idx_[encoding].slice + 1;
        size_t CON = meas_max_idx_[encoding].contrast + 1;
        if (E2 == 0) E2 = 1;

        size_t imageNum = imheader.average*REP*SET*PHS*CON*SLC*E2*CHA + imheader.repetition*SET*PHS*CON*SLC*E2*CHA 
            + imheader.set*PHS*CON*SLC*E2*CHA + imheader.phase*CON*SLC*E2*CHA + imheader.contrast*SLC*E2*CHA + imheader.slice*E2*CHA + cha + 1;

        return imageNum;
    }
コード例 #4
0
    int GenericReconEigenChannelGadget::process(Gadgetron::GadgetContainerMessage< IsmrmrdReconData >* m1)
    {
        if (perform_timing.value()) { gt_timer_.start("GenericReconEigenChannelGadget::process"); }

        process_called_times_++;

        IsmrmrdReconData* recon_bit_ = m1->getObjectPtr();
        if (recon_bit_->rbit_.size() > num_encoding_spaces_)
        {
            GWARN_STREAM("Incoming recon_bit has more encoding spaces than the protocol : " << recon_bit_->rbit_.size() << " instead of " << num_encoding_spaces_);
        }

        // for every encoding space, prepare the recon_bit_->rbit_[e].ref_
        size_t e, n, s, slc;
        for (e = 0; e < recon_bit_->rbit_.size(); e++)
        {
            auto & rbit = recon_bit_->rbit_[e];
            std::stringstream os;
            os << "_encoding_" << e;

            hoNDArray< std::complex<float> >& data = recon_bit_->rbit_[e].data_.data_;

            size_t RO = data.get_size(0);
            size_t E1 = data.get_size(1);
            size_t E2 = data.get_size(2);
            size_t CHA = data.get_size(3);
            size_t N = data.get_size(4);
            size_t S = data.get_size(5);
            size_t SLC = data.get_size(6);

            GDEBUG_CONDITION_STREAM(verbose.value(), "GenericReconEigenChannelGadget - incoming data array : [RO E1 E2 CHA N S SLC] - [" << RO << " " << E1 << " " << E2 << " " << CHA << " " << N << " " << S << " " << SLC << "]");

            // whether it is needed to update coefficients
            bool recompute_coeff = false;
            if ( (KLT_[e].size()!=SLC) || update_eigen_channel_coefficients.value() )
            {
                recompute_coeff = true;
            }
            else
            {
                if(KLT_[e].size() == SLC)
                {
                    for (slc = 0; slc < SLC; slc++)
                    {
                        if (KLT_[e][slc].size() != S) 
                        {
                            recompute_coeff = true;
                            break;
                        }
                        else
                        {
                            for (s = 0; s < S; s++)
                            {
                                if (KLT_[e][slc][s].size() != N)
                                {
                                    recompute_coeff = true;
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            if(recompute_coeff)
            {
                bool average_N = average_all_ref_N.value();
                bool average_S = average_all_ref_S.value();

                if(rbit.ref_)
                {
                    // use ref to compute coefficients
                    Gadgetron::compute_eigen_channel_coefficients(rbit.ref_->data_, average_N, average_S,
                        (calib_mode_[e] == Gadgetron::ISMRMRD_interleaved), N, S, upstream_coil_compression_thres.value(), upstream_coil_compression_num_modesKept.value(), KLT_[e]);
                }
                else
                {
                    // use data to compute coefficients
                    Gadgetron::compute_eigen_channel_coefficients(rbit.data_.data_, average_N, average_S,
                        (calib_mode_[e] == Gadgetron::ISMRMRD_interleaved), N, S, upstream_coil_compression_thres.value(), upstream_coil_compression_num_modesKept.value(), KLT_[e]);
                }

                if (verbose.value())
                {
                    hoNDArray< std::complex<float> > E;

                    for (slc = 0; slc < SLC; slc++)
                    {
                        for (s = 0; s < S; s++)
                        {
                            for (n = 0; n < N; n++)
                            {
                                KLT_[e][slc][s][n].eigen_value(E);

                                GDEBUG_STREAM("Number of modes kept: " << KLT_[e][slc][s][n].output_length() << "; Eigen value, slc - " << slc << ", S - " << s << ", N - " << n << " : [");

                                for (size_t c = 0; c < E.get_size(0); c++)
                                {
                                    GDEBUG_STREAM("        " << E(c));
                                }
                                GDEBUG_STREAM("]");
                            }
                        }
                    }
                }
            }

            /*if (!debug_folder_full_path_.empty())
            {
                gt_exporter_.exportArrayComplex(rbit.data_.data_, debug_folder_full_path_ + "data_before_KLT" + os.str());
            }*/

            // apply KL coefficients
            Gadgetron::apply_eigen_channel_coefficients(KLT_[e], rbit.data_.data_);

            /*if (!debug_folder_full_path_.empty())
            {
                gt_exporter_.exportArrayComplex(rbit.data_.data_, debug_folder_full_path_ + "data_after_KLT" + os.str());
            }*/

            if (rbit.ref_)
            {
                /*if (!debug_folder_full_path_.empty())
                {
                    gt_exporter_.exportArrayComplex(rbit.ref_->data_, debug_folder_full_path_ + "ref_before_KLT" + os.str());
                }*/

                Gadgetron::apply_eigen_channel_coefficients(KLT_[e], rbit.ref_->data_);

                /*if (!debug_folder_full_path_.empty())
                {
                    gt_exporter_.exportArrayComplex(rbit.ref_->data_, debug_folder_full_path_ + "ref_after_KLT" + os.str());
                }*/
            }
        }

        if (perform_timing.value()) { gt_timer_.stop(); }

        if (this->next()->putq(m1) < 0)
        {
            GERROR_STREAM("Put IsmrmrdReconData to Q failed ... ");
            return GADGET_FAIL;
        }

        return GADGET_OK;
    }
コード例 #5
0
    int GenericReconCartesianGrappaGadget::process(Gadgetron::GadgetContainerMessage<IsmrmrdReconData> *m1) {
        if (perform_timing.value()) { gt_timer_local_.start("GenericReconCartesianGrappaGadget::process"); }

        process_called_times_++;

        IsmrmrdReconData *recon_bit_ = m1->getObjectPtr();
        if (recon_bit_->rbit_.size() > num_encoding_spaces_) {
            GWARN_STREAM("Incoming recon_bit has more encoding spaces than the protocol : " << recon_bit_->rbit_.size()
                                                                                            << " instead of "
                                                                                            << num_encoding_spaces_);
        }

        GadgetContainerMessage< std::vector<ISMRMRD::Waveform> > * wav = AsContainerMessage< std::vector<ISMRMRD::Waveform>  >(m1->cont());
        if (wav)
        {
            if (verbose.value())
            {
                GDEBUG_STREAM("Incoming recon_bit with " << wav->getObjectPtr()->size() << " wave form samples ");
            }
        }

        // for every encoding space
        for (size_t e = 0; e < recon_bit_->rbit_.size(); e++) {
            std::stringstream os;
            os << "_encoding_" << e << "_" << process_called_times_;

            GDEBUG_CONDITION_STREAM(verbose.value(),
                                    "Calling " << process_called_times_ << " , encoding space : " << e);
            GDEBUG_CONDITION_STREAM(verbose.value(),
                                    "======================================================================");

            // ---------------------------------------------------------------
            // export incoming data

            if (!debug_folder_full_path_.empty()) {
                gt_exporter_.export_array_complex(recon_bit_->rbit_[e].data_.data_,
                                                  debug_folder_full_path_ + "data" + os.str());
            }

            if (!debug_folder_full_path_.empty() && recon_bit_->rbit_[e].data_.trajectory_) {
                if (recon_bit_->rbit_[e].ref_->trajectory_->get_number_of_elements() > 0) {
                    gt_exporter_.export_array(*(recon_bit_->rbit_[e].data_.trajectory_),
                                              debug_folder_full_path_ + "data_traj" + os.str());
                }
            }

            // ---------------------------------------------------------------

            if (recon_bit_->rbit_[e].ref_) {
                if (!debug_folder_full_path_.empty()) {
                    gt_exporter_.export_array_complex(recon_bit_->rbit_[e].ref_->data_,
                                                      debug_folder_full_path_ + "ref" + os.str());
                }

                if (!debug_folder_full_path_.empty() && recon_bit_->rbit_[e].ref_->trajectory_) {
                    if (recon_bit_->rbit_[e].ref_->trajectory_->get_number_of_elements() > 0) {
                        gt_exporter_.export_array(*(recon_bit_->rbit_[e].ref_->trajectory_),
                                                  debug_folder_full_path_ + "ref_traj" + os.str());
                    }
                }

                // ---------------------------------------------------------------

                // after this step, the recon_obj_[e].ref_calib_ and recon_obj_[e].ref_coil_map_ are set

                if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianGrappaGadget::make_ref_coil_map"); }
                this->make_ref_coil_map(*recon_bit_->rbit_[e].ref_, *recon_bit_->rbit_[e].data_.data_.get_dimensions(),
                                        recon_obj_[e].ref_calib_, recon_obj_[e].ref_coil_map_, e);
                if (perform_timing.value()) { gt_timer_.stop(); }

                // ----------------------------------------------------------
                // export prepared ref for calibration and coil map
                if (!debug_folder_full_path_.empty()) {
                    this->gt_exporter_.export_array_complex(recon_obj_[e].ref_calib_,
                                                            debug_folder_full_path_ + "ref_calib" + os.str());
                }

                if (!debug_folder_full_path_.empty()) {
                    this->gt_exporter_.export_array_complex(recon_obj_[e].ref_coil_map_,
                                                            debug_folder_full_path_ + "ref_coil_map" + os.str());
                }

                // ---------------------------------------------------------------
                // after this step, the recon_obj_[e].ref_calib_dst_ and recon_obj_[e].ref_coil_map_ are modified
                if (perform_timing.value()) {
                    gt_timer_.start("GenericReconCartesianGrappaGadget::prepare_down_stream_coil_compression_ref_data");
                }
                this->prepare_down_stream_coil_compression_ref_data(recon_obj_[e].ref_calib_,
                                                                    recon_obj_[e].ref_coil_map_,
                                                                    recon_obj_[e].ref_calib_dst_, e);
                if (perform_timing.value()) { gt_timer_.stop(); }

                if (!debug_folder_full_path_.empty()) {
                    this->gt_exporter_.export_array_complex(recon_obj_[e].ref_calib_dst_,
                        debug_folder_full_path_ + "ref_calib_dst" + os.str());
                }

                if (!debug_folder_full_path_.empty()) {
                    this->gt_exporter_.export_array_complex(recon_obj_[e].ref_coil_map_,
                        debug_folder_full_path_ + "ref_coil_map_dst" + os.str());
                }

                // ---------------------------------------------------------------

                // after this step, coil map is computed and stored in recon_obj_[e].coil_map_
                if (perform_timing.value()) {
                    gt_timer_.start("GenericReconCartesianGrappaGadget::perform_coil_map_estimation");
                }
                this->perform_coil_map_estimation(recon_obj_[e].ref_coil_map_, recon_obj_[e].coil_map_, e);
                if (perform_timing.value()) { gt_timer_.stop(); }

                // ---------------------------------------------------------------

                // after this step, recon_obj_[e].kernel_, recon_obj_[e].kernelIm_, recon_obj_[e].unmixing_coeff_ are filled
                // gfactor is computed too
                if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianGrappaGadget::perform_calib"); }
                this->perform_calib(recon_bit_->rbit_[e], recon_obj_[e], e);
                if (perform_timing.value()) { gt_timer_.stop(); }

                // ---------------------------------------------------------------

                recon_bit_->rbit_[e].ref_->clear();
                recon_bit_->rbit_[e].ref_ = boost::none;
            }

            if (recon_bit_->rbit_[e].data_.data_.get_number_of_elements() > 0) {
                if (!debug_folder_full_path_.empty()) {
                    gt_exporter_.export_array_complex(recon_bit_->rbit_[e].data_.data_,
                                                      debug_folder_full_path_ + "data_before_unwrapping" + os.str());
                }

                if (!debug_folder_full_path_.empty() && recon_bit_->rbit_[e].data_.trajectory_) {
                    if (recon_bit_->rbit_[e].data_.trajectory_->get_number_of_elements() > 0) {
                        gt_exporter_.export_array(*(recon_bit_->rbit_[e].data_.trajectory_),
                                                  debug_folder_full_path_ + "data_before_unwrapping_traj" + os.str());
                    }
                }

                // ---------------------------------------------------------------

                if (perform_timing.value()) {
                    gt_timer_.start("GenericReconCartesianGrappaGadget::perform_unwrapping");
                }
                this->perform_unwrapping(recon_bit_->rbit_[e], recon_obj_[e], e);
                if (perform_timing.value()) { gt_timer_.stop(); }

                // ---------------------------------------------------------------

                if (perform_timing.value()) {
                    gt_timer_.start("GenericReconCartesianGrappaGadget::compute_image_header");
                }
                this->compute_image_header(recon_bit_->rbit_[e], recon_obj_[e].recon_res_, e);
                if (perform_timing.value()) { gt_timer_.stop(); }

                // ---------------------------------------------------------------
                // pass down waveform
                if(wav) recon_obj_[e].recon_res_.waveform_ = *wav->getObjectPtr();
                recon_obj_[e].recon_res_.acq_headers_ = recon_bit_->rbit_[e].data_.headers_;

                // ---------------------------------------------------------------

                if (!debug_folder_full_path_.empty()) {
                    this->gt_exporter_.export_array_complex(recon_obj_[e].recon_res_.data_,
                                                            debug_folder_full_path_ + "recon_res" + os.str());
                }

                if (perform_timing.value()) {
                    gt_timer_.start("GenericReconCartesianGrappaGadget::send_out_image_array");
                }
                this->send_out_image_array(recon_obj_[e].recon_res_, e,
                                           image_series.value() + ((int) e + 1), GADGETRON_IMAGE_REGULAR);
                if (perform_timing.value()) { gt_timer_.stop(); }

                // ---------------------------------------------------------------
                if (send_out_gfactor.value() && recon_obj_[e].gfactor_.get_number_of_elements() > 0 &&
                    (acceFactorE1_[e] * acceFactorE2_[e] > 1)) {
                    IsmrmrdImageArray res;
                    Gadgetron::real_to_complex(recon_obj_[e].gfactor_, res.data_);
                    res.headers_ = recon_obj_[e].recon_res_.headers_;
                    res.meta_ = recon_obj_[e].recon_res_.meta_;

                    if (perform_timing.value()) {
                        gt_timer_.start("GenericReconCartesianGrappaGadget::send_out_image_array, gfactor");
                    }
                    this->send_out_image_array(res, e, image_series.value() + 10 * ((int) e + 2),
                                               GADGETRON_IMAGE_GFACTOR);
                    if (perform_timing.value()) { gt_timer_.stop(); }
                }

                // ---------------------------------------------------------------
                if (send_out_snr_map.value()) {
                    hoNDArray<std::complex<float> > snr_map;

                    if (calib_mode_[e] == Gadgetron::ISMRMRD_noacceleration) {
                        snr_map = recon_obj_[e].recon_res_.data_;
                    } else {
                        if (recon_obj_[e].gfactor_.get_number_of_elements() > 0) {
                            if (perform_timing.value()) { gt_timer_.start("compute SNR map array"); }
                            this->compute_snr_map(recon_obj_[e], snr_map);
                            if (perform_timing.value()) { gt_timer_.stop(); }
                        }
                    }

                    if (snr_map.get_number_of_elements() > 0) {
                        if (!debug_folder_full_path_.empty()) {
                            this->gt_exporter_.export_array_complex(snr_map,
                                                                    debug_folder_full_path_ + "snr_map" + os.str());
                        }

                        if (perform_timing.value()) { gt_timer_.start("send out gfactor array, snr map"); }

                        IsmrmrdImageArray res;
                        res.data_ = snr_map;
                        res.headers_ = recon_obj_[e].recon_res_.headers_;
                        res.meta_ = recon_obj_[e].recon_res_.meta_;
                        res.acq_headers_ = recon_bit_->rbit_[e].data_.headers_;

                        this->send_out_image_array(res, e,
                                                   image_series.value() + 100 * ((int) e + 3), GADGETRON_IMAGE_SNR_MAP);

                        if (perform_timing.value()) { gt_timer_.stop(); }
                    }
                }
            }

            recon_obj_[e].recon_res_.data_.clear();
            recon_obj_[e].gfactor_.clear();
            recon_obj_[e].recon_res_.headers_.clear();
            recon_obj_[e].recon_res_.meta_.clear();
        }

        m1->release();

        if (perform_timing.value()) { gt_timer_local_.stop(); }

        return GADGET_OK;
    }
コード例 #6
0
  void BucketToBufferGadget::stuff(std::vector<IsmrmrdAcquisitionData>::iterator it, IsmrmrdDataBuffered & dataBuffer, ISMRMRD::Encoding encoding, IsmrmrdAcquisitionBucketStats & stats, bool forref)
  {

    // The acquisition header and data
    ISMRMRD::AcquisitionHeader & acqhdr = *it->head_->getObjectPtr();
    hoNDArray< std::complex<float> > & acqdata = *it->data_->getObjectPtr();
    // we make one for the trajectory down below if we need it

    uint16_t NE0  = (uint16_t)dataBuffer.data_.get_size(0);
    uint16_t NE1  = (uint16_t)dataBuffer.data_.get_size(1);
    uint16_t NE2  = (uint16_t)dataBuffer.data_.get_size(2);
    uint16_t NCHA = (uint16_t)dataBuffer.data_.get_size(3);
    uint16_t NN   = (uint16_t)dataBuffer.data_.get_size(4);
    uint16_t NS   = (uint16_t)dataBuffer.data_.get_size(5);
    uint16_t NLOC = (uint16_t)dataBuffer.data_.get_size(6);

    size_t slice_loc;
    if (split_slices_ || NLOC==1)
      {
        slice_loc = 0;
      }
    else
      {
        slice_loc = acqhdr.idx.slice;
      }

    //Stuff the data
    uint16_t npts_to_copy = acqhdr.number_of_samples - acqhdr.discard_pre - acqhdr.discard_post;
    long long offset;
    if (encoding.trajectory == ISMRMRD::TrajectoryType::CARTESIAN || encoding.trajectory == ISMRMRD::TrajectoryType::EPI) {
        if ((acqhdr.number_of_samples == dataBuffer.data_.get_size(0)) && (acqhdr.center_sample == acqhdr.number_of_samples/2)) // acq has been corrected for center , e.g. by asymmetric handling
        {
            offset = acqhdr.discard_pre;
        }
        else
        {
            offset = (long long)dataBuffer.sampling_.sampling_limits_[0].center_ - (long long)acqhdr.center_sample;
        }
    } else {
        //TODO what about EPI with asymmetric readouts?
        //TODO any other sort of trajectory?
        offset = 0;
    }
    long long roffset = (long long) dataBuffer.data_.get_size(0) - npts_to_copy - offset;

    //GDEBUG_STREAM("Num_samp: "<< acqhdr.number_of_samples << ", pre: " << acqhdr.discard_pre << ", post" << acqhdr.discard_post << std::endl);
    //std::cout << "Sampling limits: "
    //    << "  min: " << dataBuffer.sampling_.sampling_limits_[0].min_
    //    << "  max: " << dataBuffer.sampling_.sampling_limits_[0].max_
    //    << "  center: " << dataBuffer.sampling_.sampling_limits_[0].center_
    //    << std::endl;
    //GDEBUG_STREAM("npts_to_copy = " << npts_to_copy  << std::endl);
    //GDEBUG_STREAM("offset = " << offset  << std::endl);
    //GDEBUG_STREAM("loffset = " << roffset << std::endl);

    if ((offset < 0) | (roffset < 0) )
      {
        throw std::runtime_error("Acquired reference data does not fit into the reference data buffer.\n");
      }

    std::complex<float> *dataptr;

    uint16_t NUsed = (uint16_t)getN(acqhdr.idx);
    if (NUsed >= NN) NUsed = NN - 1;

    uint16_t SUsed = (uint16_t)getS(acqhdr.idx);
    if (SUsed >= NS) SUsed = NS - 1;

    int16_t e1 = (int16_t)acqhdr.idx.kspace_encode_step_1;
    int16_t e2 = (int16_t)acqhdr.idx.kspace_encode_step_2;

    bool is_cartesian_sampling = (encoding.trajectory == ISMRMRD::TrajectoryType::CARTESIAN);
    bool is_epi_sampling = (encoding.trajectory == ISMRMRD::TrajectoryType::EPI);
    if(is_cartesian_sampling || is_epi_sampling)
    {
        if (!forref || (forref && (encoding.parallelImaging.get().calibrationMode.get() == "embedded")))
        {
            // compute the center offset for E1 and E2
            int16_t space_matrix_offset_E1 = 0;
            if (encoding.encodingLimits.kspace_encoding_step_1.is_present())
            {
                space_matrix_offset_E1 = (int16_t)encoding.encodedSpace.matrixSize.y / 2 - (int16_t)encoding.encodingLimits.kspace_encoding_step_1->center;
            }

            int16_t space_matrix_offset_E2 = 0;
            if (encoding.encodingLimits.kspace_encoding_step_2.is_present() && encoding.encodedSpace.matrixSize.z > 1)
            {
                space_matrix_offset_E2 = (int16_t)encoding.encodedSpace.matrixSize.z / 2 - (int16_t)encoding.encodingLimits.kspace_encoding_step_2->center;
            }

            // compute the used e1 and e2 indices and make sure they are in the valid range
            e1 = (int16_t)acqhdr.idx.kspace_encode_step_1 + space_matrix_offset_E1;
            e2 = (int16_t)acqhdr.idx.kspace_encode_step_2 + space_matrix_offset_E2;
        }

        // for external or separate mode, it is possible the starting numbers of ref lines are not zero, therefore it is needed to subtract the staring ref line number
        // because the ref array size is set up by the actual number of lines acquired
        // only assumption for external or separate ref line mode is that all ref lines are numbered sequentially
        // the acquisition order of ref line can be arbitrary
        if (forref && ( (encoding.parallelImaging.get().calibrationMode.get() == "separate") || (encoding.parallelImaging.get().calibrationMode.get() == "external") ) )
        {
            if(*stats.kspace_encode_step_1.begin()>0)
            {
                e1 = acqhdr.idx.kspace_encode_step_1 - *stats.kspace_encode_step_1.begin();
            }

            if(*stats.kspace_encode_step_2.begin()>0)
            {
                e2 = acqhdr.idx.kspace_encode_step_2 - *stats.kspace_encode_step_2.begin();
            }
        }

        if (e1 < 0 || e1 >= (int16_t)NE1)
        {
            // if the incoming line is outside the encoding limits, something is wrong
            GADGET_CHECK_THROW(acqhdr.idx.kspace_encode_step_1>=encoding.encodingLimits.kspace_encoding_step_1->minimum && acqhdr.idx.kspace_encode_step_1 <= encoding.encodingLimits.kspace_encoding_step_1->maximum);

            // if the incoming line is inside encoding limits but outside the encoded matrix, do not include the data
            GWARN_STREAM("incoming readout " << acqhdr.scan_counter << " is inside the encoding limits, but outside the encoded matrix for kspace_encode_step_1 : " << e1 << " out of " << NE1);
            return;
        }

        if (e2 < 0 || e2 >= (int16_t)NE2)
        {
            GADGET_CHECK_THROW(acqhdr.idx.kspace_encode_step_2 >= encoding.encodingLimits.kspace_encoding_step_2->minimum && acqhdr.idx.kspace_encode_step_2 <= encoding.encodingLimits.kspace_encoding_step_2->maximum);

            GWARN_STREAM("incoming readout " << acqhdr.scan_counter << " is inside the encoding limits, but outside the encoded matrix for kspace_encode_step_2 : " << e2 << " out of " << NE2);
            return;
        }
    }

    std::complex<float>* pData = &dataBuffer.data_(offset, e1, e2, 0, NUsed, SUsed, slice_loc);

    for (uint16_t cha = 0; cha < NCHA; cha++)
    {
        dataptr = pData + cha*NE0*NE1*NE2;
        memcpy(dataptr, &acqdata(acqhdr.discard_pre, cha), sizeof(std::complex<float>)*npts_to_copy);
    }

    dataBuffer.headers_(e1, e2, NUsed, SUsed, slice_loc) = acqhdr;

    if (acqhdr.trajectory_dimensions > 0)
    {

        hoNDArray< float > & acqtraj = *it->traj_->getObjectPtr();  // TODO do we need to check this?

        float * trajptr;

        trajptr = &(*dataBuffer.trajectory_)(0, offset, e1, e2, NUsed, SUsed, slice_loc);

        memcpy(trajptr, &acqtraj(0, acqhdr.discard_pre), sizeof(float)*npts_to_copy*acqhdr.trajectory_dimensions);

    }
  }
コード例 #7
0
    int MultiChannelCartesianGrappaReconGadget::process(Gadgetron::GadgetContainerMessage< IsmrmrdReconData >* m1)
    {
        process_called_times_++;

        IsmrmrdReconData* recon_bit_ = m1->getObjectPtr();
        if (recon_bit_->rbit_.size() > num_encoding_spaces_)
        {
            GWARN_STREAM("Incoming recon_bit has more encoding spaces than the protocol : " << recon_bit_->rbit_.size() << " instead of " << num_encoding_spaces_);
        }

        // for every encoding space
        for (size_t e = 0; e < recon_bit_->rbit_.size(); e++)
        {
            std::stringstream os;
            os << "_encoding_" << e;

            GDEBUG_CONDITION_STREAM(verbose.value(), "Calling " << process_called_times_ << " , encoding space : " << e);
            GDEBUG_CONDITION_STREAM(verbose.value(), "======================================================================");

            // ---------------------------------------------------------------

            if (recon_bit_->rbit_[e].ref_)
            {
                // ---------------------------------------------------------------
		
		
		
		        // after this step, the recon_obj_[e].ref_calib_ and recon_obj_[e].ref_coil_map_ are set

	        this->make_ref_coil_map(*recon_bit_->rbit_[e].ref_,*recon_bit_->rbit_[e].data_.data_.get_dimensions(), recon_obj_[e], e);

	        // after this step, coil map is computed and stored in recon_obj_[e].coil_map_
	        if(!flatmap.value())
			this->perform_coil_map_estimation(recon_bit_->rbit_[e], recon_obj_[e], e);
	        else
		{
			recon_obj_[e].coil_map_=recon_obj_[e].ref_coil_map_;
        		recon_obj_[e].coil_map_.fill(1);//create(*recon_bit_->rbit_[e].data_.data_.get_dimensions());
		}
                // after this step, recon_obj_[e].kernel_, recon_obj_[e].kernelIm_, recon_obj_[e].unmixing_coeff_ are filled
                // gfactor is computed too

                this->perform_calib(recon_bit_->rbit_[e], recon_obj_[e], e);


                // ---------------------------------------------------------------

                recon_bit_->rbit_[e].ref_ = boost::none;
            }

            if (recon_bit_->rbit_[e].data_.data_.get_number_of_elements() > 0)
            {
                // ---------------------------------------------------------------


                this->perform_unwrapping(recon_bit_->rbit_[e], recon_obj_[e], e);

                // ---------------------------------------------------------------

                this->compute_image_header(recon_bit_->rbit_[e], recon_obj_[e], e);

                // ---------------------------------------------------------------

                this->send_out_image_array(recon_bit_->rbit_[e], recon_obj_[e].recon_res_, e, image_series.value() + ((int)e + 1), GADGETRON_IMAGE_REGULAR);
            }

            recon_obj_[e].recon_res_.data_.clear();
            recon_obj_[e].gfactor_.clear();
            recon_obj_[e].recon_res_.headers_.clear();
            recon_obj_[e].recon_res_.meta_.clear();
        }

        m1->release();
        return GADGET_OK;
    }
コード例 #8
0
    int GenericReconCartesianReferencePrepGadget::process(Gadgetron::GadgetContainerMessage< IsmrmrdReconData >* m1)
    {
        if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianReferencePrepGadget::process"); }

        process_called_times_++;

        IsmrmrdReconData* recon_bit_ = m1->getObjectPtr();
        if (recon_bit_->rbit_.size() > num_encoding_spaces_)
        {
            GWARN_STREAM("Incoming recon_bit has more encoding spaces than the protocol : " << recon_bit_->rbit_.size() << " instead of " << num_encoding_spaces_);
        }

        // for every encoding space, prepare the recon_bit_->rbit_[e].ref_
        size_t e;
        for (e = 0; e < recon_bit_->rbit_.size(); e++)
        {
            auto & rbit = recon_bit_->rbit_[e];
            std::stringstream os;
            os << "_encoding_" << e;

            // -----------------------------------------
            // no acceleration mode
            // check the availability of ref data
            // -----------------------------------------
            if (calib_mode_[e] == Gadgetron::ISMRMRD_noacceleration)
            {
                if (prepare_ref_always_no_acceleration.value() || !ref_prepared_[e])
                {
                    // if no ref data is set, make copy the ref point from the  data
                    if (!rbit.ref_)
                    {
                        rbit.ref_ = rbit.data_;
                        ref_prepared_[e] = true;
                    }
                }
                else
                {
                    if (ref_prepared_[e])
                    {
                        if (rbit.ref_)
                        {
                            // remove the ref
                            rbit.ref_ = boost::none;
                        }
                    }

                    continue;
                }
            }

            if (!rbit.ref_) continue;

            // useful variables
            hoNDArray< std::complex<float> >& ref = (*rbit.ref_).data_;

            SamplingLimit sampling_limits[3];
            for (int i = 0; i < 3; i++)
            	sampling_limits[i] = (*rbit.ref_).sampling_.sampling_limits_[i];

            size_t RO = ref.get_size(0);
            size_t E1 = ref.get_size(1);
            size_t E2 = ref.get_size(2);
            size_t CHA = ref.get_size(3);
            size_t N = ref.get_size(4);
            size_t S = ref.get_size(5);
            size_t SLC = ref.get_size(6);

            // stored the ref data ready for calibration
            hoNDArray< std::complex<float> > ref_calib;
           // -----------------------------------------
            // 1) average the ref according to the input parameters; 
            //    if interleaved mode, sampling times for every E1/E2 location is detected and line by line averaging is performed 
            //    this is required when irregular cartesian sampling is used or number of frames cannot be divided in full by acceleration factor
            // 2) detect the sampled region and crop the ref data if needed
            // 3) update the sampling_limits
            // -----------------------------------------

            hoNDArray< std::complex<float> > ref_recon_buf;

            // step 1
            bool count_sampling_freq = (calib_mode_[e] == ISMRMRD_interleaved);
            GADGET_CHECK_EXCEPTION_RETURN(Gadgetron::compute_averaged_data_N_S(ref, average_all_ref_N.value(), average_all_ref_S.value(), count_sampling_freq, ref_calib), GADGET_FAIL);

            // step 2, detect sampled region in ref, along E1 and E2
            size_t start_E1(0), end_E1(0);
            auto t = Gadgetron::detect_sampled_region_E1(ref);
            start_E1 = std::get<0>(t);
            end_E1 = std::get<1>(t);

            size_t start_E2(0), end_E2(0);
            if (E2 > 1)
            {
                auto t = Gadgetron::detect_sampled_region_E2(ref);
                start_E2 = std::get<0>(t);
                end_E2 = std::get<1>(t);
            }

            // crop the ref_calib, along RO, E1 and E2
            vector_td<size_t, 3> crop_offset;
            crop_offset[0] = sampling_limits[0].min_;
            crop_offset[1] = start_E1;
            crop_offset[2] = start_E2;

            vector_td<size_t, 3> crop_size;
            crop_size[0] = sampling_limits[0].max_ - sampling_limits[0].min_ + 1;
            crop_size[1] = end_E1 - start_E1 + 1;
            crop_size[2] = end_E2 - start_E2 + 1;

            if(crop_size[0]> (ref_calib.get_size(0)-crop_offset[0]))
            {
                crop_size[0] = ref_calib.get_size(0) - crop_offset[0];
            }

            Gadgetron::crop(crop_offset, crop_size, &ref_calib, &ref_recon_buf);
            ref_calib = ref_recon_buf;
            // step 3, update the sampling limits
            sampling_limits[0].center_ = (uint16_t)(RO/2);

            if ( (calib_mode_[e] == Gadgetron::ISMRMRD_interleaved) || (calib_mode_[e] == Gadgetron::ISMRMRD_noacceleration) )
            {
                // need to keep the ref kspace center information
                sampling_limits[1].min_ = (uint16_t)(start_E1);
                sampling_limits[1].max_ = (uint16_t)(end_E1);

                sampling_limits[2].min_ = (uint16_t)(start_E2);
                sampling_limits[2].max_ = (uint16_t)(end_E2);

                sampling_limits[1].center_ = (uint16_t)(E1 / 2);
                sampling_limits[2].center_ = (uint16_t)(E2 / 2);
            }
            else
            {
                // sepearate, embedded mode, the ref center is the kspace center
                sampling_limits[1].min_ = 0;
                sampling_limits[1].max_ = (uint16_t)(end_E1 - start_E1);

                sampling_limits[2].min_ = 0;
                sampling_limits[2].max_ = (uint16_t)(end_E2 - start_E2);

                sampling_limits[1].center_ = (sampling_limits[1].max_ + 1) / 2;
                sampling_limits[2].center_ = (sampling_limits[2].max_ + 1) / 2;
            }

            if(sampling_limits[0].max_>=RO)
            {
                sampling_limits[0].max_ = RO - 1;
            }

            ref = ref_calib;
            ref_prepared_[e] = true;

            for (int i = 0; i < 3; i++)
                (*rbit.ref_).sampling_.sampling_limits_[i] = sampling_limits[i];
        }

        if (this->next()->putq(m1) < 0)
        {
            GERROR_STREAM("Put IsmrmrdReconData to Q failed ... ");
            return GADGET_FAIL;
        }

        if (perform_timing.value()) { gt_timer_.stop(); }

        return GADGET_OK;
    }
コード例 #9
0
    int GenericReconCartesianFFTGadget::process(Gadgetron::GadgetContainerMessage< IsmrmrdReconData >* m1)
    {
        if (perform_timing.value()) { gt_timer_local_.start("GenericReconCartesianFFTGadget::process"); }

        process_called_times_++;

        IsmrmrdReconData* recon_bit_ = m1->getObjectPtr();
        if (recon_bit_->rbit_.size() > num_encoding_spaces_)
        {
            GWARN_STREAM("Incoming recon_bit has more encoding spaces than the protocol : " << recon_bit_->rbit_.size() << " instead of " << num_encoding_spaces_);
        }

        // for every encoding space
        for (size_t e = 0; e < recon_bit_->rbit_.size(); e++)
        {
            std::stringstream os;
            os << "_encoding_" << e;

            GDEBUG_CONDITION_STREAM(verbose.value(), "Calling " << process_called_times_ << " , encoding space : " << e);
            GDEBUG_CONDITION_STREAM(verbose.value(), "======================================================================");

            // ---------------------------------------------------------------
            // export incoming data

            if (!debug_folder_full_path_.empty())
            {
                gt_exporter_.export_array_complex(recon_bit_->rbit_[e].data_.data_, debug_folder_full_path_ + "data" + os.str());
            }

            if (!debug_folder_full_path_.empty() && recon_bit_->rbit_[e].data_.trajectory_)
            {
                if (recon_bit_->rbit_[e].ref_->trajectory_->get_number_of_elements() > 0)
                {
                    gt_exporter_.export_array(*(recon_bit_->rbit_[e].data_.trajectory_), debug_folder_full_path_ + "data_traj" + os.str());
                }
            }

            // ---------------------------------------------------------------

            if (recon_bit_->rbit_[e].ref_)
            {
                if (!debug_folder_full_path_.empty())
                {
                    gt_exporter_.export_array_complex(recon_bit_->rbit_[e].ref_->data_, debug_folder_full_path_ + "ref" + os.str());
                }

                if (!debug_folder_full_path_.empty() && recon_bit_->rbit_[e].ref_->trajectory_)
                {
                    if (recon_bit_->rbit_[e].ref_->trajectory_->get_number_of_elements() > 0)
                    {
                        gt_exporter_.export_array(*(recon_bit_->rbit_[e].ref_->trajectory_), debug_folder_full_path_ + "ref_traj" + os.str());
                    }
                }

                // ---------------------------------------------------------------

                // after this step, the recon_obj_[e].ref_calib_ and recon_obj_[e].ref_coil_map_ are set

                if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianFFTGadget::make_ref_coil_map"); }
                this->make_ref_coil_map(*recon_bit_->rbit_[e].ref_,*recon_bit_->rbit_[e].data_.data_.get_dimensions(), recon_obj_[e].ref_calib_, recon_obj_[e].ref_coil_map_, e);
                if (perform_timing.value()) { gt_timer_.stop(); }

                // ----------------------------------------------------------
                // export prepared ref for calibration and coil map
                if (!debug_folder_full_path_.empty())
                {
                    this->gt_exporter_.export_array_complex(recon_obj_[e].ref_calib_, debug_folder_full_path_ + "ref_calib" + os.str());
                }

                if (!debug_folder_full_path_.empty())
                {
                    this->gt_exporter_.export_array_complex(recon_obj_[e].ref_coil_map_, debug_folder_full_path_ + "ref_coil_map" + os.str());
                }


                // ---------------------------------------------------------------

                recon_bit_->rbit_[e].ref_ = boost::none;
            }

            if (recon_bit_->rbit_[e].data_.data_.get_number_of_elements() > 0)
            {
                if (!debug_folder_full_path_.empty())
                {
                    gt_exporter_.export_array_complex(recon_bit_->rbit_[e].data_.data_, debug_folder_full_path_ + "data_before_unwrapping" + os.str());
                }

                if (!debug_folder_full_path_.empty() && recon_bit_->rbit_[e].data_.trajectory_)
                {
                    if (recon_bit_->rbit_[e].data_.trajectory_->get_number_of_elements() > 0)
                    {
                        gt_exporter_.export_array(*(recon_bit_->rbit_[e].data_.trajectory_), debug_folder_full_path_ + "data_before_unwrapping_traj" + os.str());
                    }
                }

                // ---------------------------------------------------------------

                if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianFFTGadget::perform_fft_combine"); }
                this->perform_fft_combine(recon_bit_->rbit_[e], recon_obj_[e], e);
                if (perform_timing.value()) { gt_timer_.stop(); }

                // ---------------------------------------------------------------

                if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianFFTGadget::compute_image_header"); }
                this->compute_image_header(recon_bit_->rbit_[e], recon_obj_[e].recon_res_, e);
                if (perform_timing.value()) { gt_timer_.stop(); }

                // ---------------------------------------------------------------

                if (!debug_folder_full_path_.empty())
                {
                    this->gt_exporter_.export_array_complex(recon_obj_[e].recon_res_.data_, debug_folder_full_path_ + "recon_res" + os.str());
                }

                if (perform_timing.value()) { gt_timer_.start("GenericReconCartesianFFTGadget::send_out_image_array"); }
                this->send_out_image_array(recon_bit_->rbit_[e], recon_obj_[e].recon_res_, e, image_series.value() + ((int)e + 1), GADGETRON_IMAGE_REGULAR);
                if (perform_timing.value()) { gt_timer_.stop(); }

              

            }

            recon_obj_[e].recon_res_.data_.clear();
            recon_obj_[e].recon_res_.headers_.clear();
            recon_obj_[e].recon_res_.meta_.clear();
        }

        m1->release();

        if (perform_timing.value()) { gt_timer_local_.stop(); }

        return GADGET_OK;
    }
コード例 #10
0
void grappa2d_calib(const hoNDArray<T>& acsSrc, const hoNDArray<T>& acsDst, double thres, size_t kRO, const std::vector<int>& kE1, const std::vector<int>& oE1, size_t startRO, size_t endRO, size_t startE1, size_t endE1, hoNDArray<T>& ker)
{
    try
    {
        GADGET_CHECK_THROW(acsSrc.get_size(0)==acsDst.get_size(0));
        GADGET_CHECK_THROW(acsSrc.get_size(1)==acsDst.get_size(1));
        GADGET_CHECK_THROW(acsSrc.get_size(2)>=acsDst.get_size(2));

        size_t RO = acsSrc.get_size(0);
        size_t E1 = acsSrc.get_size(1);
        size_t srcCHA = acsSrc.get_size(2);
        size_t dstCHA = acsDst.get_size(2);

        const T* pSrc = acsSrc.begin();
        const T* pDst = acsDst.begin();

        long long kROhalf = kRO/2;
        if ( 2*kROhalf == kRO )
        {
            GWARN_STREAM("grappa<T>::calib(...) - 2*kROhalf == kRO " << kRO);
        }
        kRO = 2*kROhalf + 1;

        size_t kNE1 = kE1.size();
        size_t oNE1 = oE1.size();

        /// allocate kernel
        ker.create(kRO, kNE1, srcCHA, dstCHA, oNE1);

        /// loop over the calibration region and assemble the equation
        /// Ax = b

        size_t sRO = startRO + kROhalf;
        size_t eRO = endRO - kROhalf;
        size_t sE1 = std::abs(kE1[0]) + startE1;
        size_t eE1 = endE1 - kE1[kNE1-1];

        size_t lenRO = eRO - sRO + 1;

        size_t rowA = (eE1-sE1+1)*lenRO;
        size_t colA = kRO*kNE1*srcCHA;
        size_t colB = dstCHA*oNE1;

        hoMatrix<T> A;
        hoMatrix<T> B;
        hoMatrix<T> x( colA, colB );

        hoNDArray<T> A_mem(rowA, colA);
        A.createMatrix( rowA, colA, A_mem.begin() );
        T* pA = A.begin();

        hoNDArray<T> B_mem(rowA, colB);
        B.createMatrix( A.rows(), colB, B_mem.begin() );
        T* pB = B.begin();

        long long e1;
        for ( e1=(long long)sE1; e1<=(long long)eE1; e1++ )
        {
            for ( long long ro=sRO; ro<=(long long)eRO; ro++ )
            {
                long long rInd = (e1-sE1)*lenRO+ro-kROhalf;

                size_t src, dst, ke1, oe1;
                long long kro;

                /// fill matrix A
                size_t col = 0;
                size_t offset = 0;
                for ( src=0; src<srcCHA; src++ )
                {
                    for ( ke1=0; ke1<kNE1; ke1++ )
                    {
                        offset = src*RO*E1 + (e1+kE1[ke1])*RO;
                        for ( kro=-kROhalf; kro<=kROhalf; kro++ )
                        {
                            /// A(rInd, col++) = acsSrc(ro+kro, e1+kE1[ke1], src);
                            pA[rInd + col*rowA] = pSrc[ro+kro+offset];
                            col++;
                        }
                    }
                }

                /// fill matrix B
                col = 0;
                for ( oe1=0; oe1<oNE1; oe1++ )
                {
                    for ( dst=0; dst<dstCHA; dst++ )
                    {
                        B(rInd, col++) = acsDst(ro, e1+oE1[oe1], dst);
                    }
                }
            }
        }

        SolveLinearSystem_Tikhonov(A, B, x, thres);
        memcpy(ker.begin(), x.begin(), ker.get_number_of_bytes());
    }
    catch(...)
    {
        GADGET_THROW("Errors in grappa2d_calib(...) ... ");
    }

    return;
}
コード例 #11
0
void grappa2d_convert_to_convolution_kernel(const hoNDArray<T>& ker, size_t kRO, const std::vector<int>& kE1, const std::vector<int>& oE1, hoNDArray<T>& convKer)
{
    try
    {
        long long srcCHA = (long long)(ker.get_size(2));
        long long dstCHA = (long long)(ker.get_size(3));
        long long kNE1 = (long long)(kE1.size());
        long long oNE1 = (long long)(oE1.size());

        long long kROhalf = kRO / 2;
        if (2 * kROhalf == kRO)
        {
            GWARN_STREAM("grappa2d_convert_to_convolution_kernel - 2*kROhalf == kRO " << kRO);
        }
        kRO = 2 * kROhalf + 1;

        //// fill the convolution kernels
        long long convKRO = 2 * kRO + 3;

        long long maxKE1 = std::abs(kE1[0]);
        if (std::abs(kE1[kNE1 - 1]) > maxKE1)
        {
            maxKE1 = std::abs(kE1[kNE1 - 1]);
        }
        long long convKE1 = 2 * maxKE1 + 1;

        //// allocate the convolution kernel
        convKer.create(convKRO, convKE1, srcCHA, dstCHA);
        Gadgetron::clear(&convKer);

        //// index
        long long oe1, kro, ke1, src, dst;

        //// fill the convolution kernel and sum up multiple kernels
        for (oe1 = 0; oe1<oNE1; oe1++)
        {
            for (ke1 = 0; ke1<kNE1; ke1++)
            {
                for (kro = -kROhalf; kro <= kROhalf; kro++)
                {
                    for (dst = 0; dst<dstCHA; dst++)
                    {
                        for (src = 0; src<srcCHA; src++)
                        {
                            convKer(-kro + kRO + 1, oE1[oe1] - kE1[ke1] + maxKE1, src, dst) = ker(kro + kROhalf, ke1, src, dst, oe1);
                        }
                    }

                }
            }
        }

        if (oE1[0] != 0)
        {
            for (dst = 0; dst<dstCHA; dst++)
            {
                convKer(kRO + 1, maxKE1, dst, dst) = 1.0;
            }
        }
    }
    catch (...)
    {
        GADGET_THROW("Errors in grappa2d_convert_to_convolution_kernel(...) ... ");
    }

    return;
}
コード例 #12
0
ファイル: cmr_time_stamp.cpp プロジェクト: DerOrfa/gadgetron
    void detect_heart_beat_with_time_stamp(hoNDArray<float>& cpt_time_stamp, hoNDArray<int>& ind_hb, 
                                        std::vector<size_t>& start_e1_hb, std::vector<size_t>& end_e1_hb, 
                                        std::vector<size_t>& start_n_hb, std::vector<size_t>& end_n_hb )
    {
        try
        {
            size_t E1 = cpt_time_stamp.get_size(0);
            size_t N = cpt_time_stamp.get_size(1);

            size_t e1, n, ind, ii;

            size_t num_acq_read_outs = 0;
            for ( n=0; n<N; n++ )
            {
                for ( e1=0; e1<E1; e1++ )
                {
                    if ( cpt_time_stamp(e1, n) >= 0 )
                    {
                        num_acq_read_outs++;
                    }
                }
            }

            ind_hb.create(E1, N);
            Gadgetron::clear(ind_hb);

            // --------------------------------------------------------
            // cpt time stamps
            // --------------------------------------------------------

            std::vector<float> acquired_cpt(num_acq_read_outs);
            std::vector<size_t> ind_acquired_cpt(num_acq_read_outs);

            ind = 0;
            for ( n=0; n<N; n++ )
            {
                for ( e1=0; e1<E1; e1++ )
                {
                    if ( cpt_time_stamp(e1, n) > -1 )
                    {
                        acquired_cpt[ind] = cpt_time_stamp(e1, n);
                        ind_acquired_cpt[ind] = e1 + n*E1;
                        ind++;
                    }
                }
            }

            // --------------------------------------------------------
            // find the number of heart beats
            // --------------------------------------------------------
            size_t numOfHB = 0;

            // store the line indexes for every heart beat
            std::vector<size_t> ind_HB_start, ind_HB_end;
            ind_HB_start.push_back(0);

            for ( ind=1; ind<num_acq_read_outs; ind++ )
            {
                if ( acquired_cpt[ind] < acquired_cpt[ind-1] )
                {
                    // find a new heart beat
                    numOfHB++;

                    size_t end_ind_prev_HB = ind_acquired_cpt[ind-1];
                    size_t start_ind_curr_HB = ind_acquired_cpt[ind];

                    // if there is a gap between end and start ind, fill the gap
                    if ( end_ind_prev_HB+1 != start_ind_curr_HB )
                    {
                        long long gap = start_ind_curr_HB - end_ind_prev_HB - 1;
                        if ( gap % 2 == 0 )
                        {
                            end_ind_prev_HB += gap;
                        }
                        else
                        {
                            end_ind_prev_HB += gap;
                        }

                        if ( end_ind_prev_HB+1 != start_ind_curr_HB )
                        {
                            GWARN_STREAM("end_ind_prev_HB+1 ~= start_ind_curr_HB : " << end_ind_prev_HB << " " << start_ind_curr_HB);
                        }
                    }

                    ind_HB_end.push_back( end_ind_prev_HB );
                    ind_HB_start.push_back( start_ind_curr_HB );
                }
            }

            ind_HB_end.push_back( E1*N-1 );
            numOfHB = ind_HB_end.size();

            // --------------------------------------------------------
            // fill the start and end indexes
            // --------------------------------------------------------
            start_e1_hb.resize(numOfHB, 0);
            end_e1_hb.resize(numOfHB, 0);

            start_n_hb.resize(numOfHB, 0);
            end_n_hb.resize(numOfHB, 0);

            std::vector<size_t> start, end;
            for ( ii=0; ii<numOfHB; ii++ )
            {
                start_n_hb[ii] = ind_HB_start[ii] / E1;
                start_e1_hb[ii] = ind_HB_start[ii] - start_n_hb[ii] * E1;

                end_n_hb[ii] = ind_HB_end[ii] / E1;
                end_e1_hb[ii] = ind_HB_end[ii] - end_n_hb[ii]*E1;

                for (ind=ind_HB_start[ii]; ind<=ind_HB_end[ii]; ind++)
                {
                    ind_hb(ind) = ii;
                }
            }
        }
        catch(...)
        {
            GADGET_THROW("Exceptions happened in detect_heart_beat_with_time_stamp(...) ... ");
        }
    }