qub_doseresponse.cpp.html mathcode2html   
 Source file:   qub_doseresponse.cpp
 Converted:   Wed Jan 6 2016 at 15:24:07
 This documentation file will not reflect any later changes in the source file.

$$\phantom{******** If you see this on the webpage then the browser could not locate *********}$$
$$\phantom{******** jsMath/easy/load.js or the variable root is set wrong in this file *********}$$
$$\newcommand{\vector}[1]{\left[\begin{array}{c} #1 \end{array}\right]}$$ $$\newenvironment{matrix}{\left[\begin{array}{cccccccccc}} {\end{array}\right]}$$ $$\newcommand{\A}{{\cal A}}$$ $$\newcommand{\W}{{\cal W}}$$

/* Copyright 2008-2014 Research Foundation State University of New York   */

/* This file is part of QUB Express.                                      */

/* QUB Express is free software; you can redistribute it and/or modify    */
/* it under the terms of the GNU General Public License as published by   */
/* the Free Software Foundation, either version 3 of the License, or      */
/* (at your option) any later version.                                    */

/* QUB Express is distributed in the hope that it will be useful,         */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of         */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
/* GNU General Public License for more details.                           */

/* You should have received a copy of the GNU General Public License,     */
/* named LICENSE.txt, in the QUB Express program directory.  If not, see  */
/* <http://www.gnu.org/licenses/>.                                        */

/*
Up
*/

#ifdef _WIN32
  #include <windows.h>
  #include <time.h>
  #define sleep Sleep
#else
  #include <stdlib.h>
  #define BOOL int
  #define TRUE 1
  #define FALSE 0
#endif

#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
#include <math.h>
#include <string.h>
#include <vector>
#include <map>
using std::vector;
using std::map;
using std::pair;

#include "qubfast.h"
#include "qub_filter.h"
#include "running_mean.h"



// for each stim level we'll average at most the final Ntail responses.
// user must feed chunks of data in the reverse order of the file
// (though within each chunk the samples are in usual forward order)

class qub_dr_equil
{
public:
  int Ntail;
  map<float, RunningMean> stats;
};


extern "C" QUBFAST_API void* qub_doseresponse_equil_init(int Ntail)
{
  qub_dr_equil *dr = new qub_dr_equil;
  dr->Ntail = Ntail;
  return dr;
}

extern "C" QUBFAST_API void qub_doseresponse_equil_free(void *dr)
{
  if ( dr )
    delete (qub_dr_equil *) dr;
}

extern "C" QUBFAST_API void qub_doseresponse_equil_add_data(void *drx, int Ndata, float *stim, float *resp)
{
  qub_dr_equil *dr = (qub_dr_equil*) drx;
  int Ntail = dr->Ntail;
  
  for (int i=Ndata-1; i>=0; --i) {
    RunningMean& stats = dr->stats[stim[i]];
    if ( stats.n < Ntail )
      stats.add(resp[i]);
  }
}

extern "C" QUBFAST_API int qub_doseresponse_equil_result(void *drx, int max_results, float *dose, float *resp, float *resp_std)
{
  qub_dr_equil *dr = (qub_dr_equil*) drx;
  int N = 0;

  vector<float> tail_dose;
  vector<RunningMean*> tailed;
  for (map<float, RunningMean>::iterator ii = dr->stats.begin(); ii != dr->stats.end(); ++ii) {
    if ( ii->second.n == dr->Ntail ) {
      tail_dose.push_back(ii->first);
      tailed.push_back(&(ii->second));
    }
  }
  int skip = ((int) ceil(((float)tailed.size()) * 1.0 / max_results + 0.5)) - 1;
  if ( tailed.size() > 1 ) {
    for (size_t i=0; i<tailed.size(); i += skip + 1) {
      if ( N == max_results )
	break;
      dose[N] = tail_dose[i];
      resp[N] = (float) tailed[i]->mean;
      resp_std[N] = (float) tailed[i]->std();
      ++N;
    }
  } else {
    skip = ((int) ceil(((float)dr->stats.size()) * 1.0 / max_results + 0.5)) - 1;
    if ( skip >= 0 ) {
      for (map<float, RunningMean>::iterator ii = dr->stats.begin(); ii != dr->stats.end(); ++ii) {
	if ( N == max_results )
	  break;
	dose[N] = ii->first;
	resp[N] = (float) ii->second.mean;
	resp_std[N] = (float) ii->second.std();
	++N;
	for (int i=0; (i<skip) && (ii != dr->stats.end()); ++i)
	  ++ii;
      }
    }
  }
  return N;
}



// filter, then for each stim level take the peak
// also find the global minimum
// chunks can be in any order, and should be complete segments

class qub_dr_peak
{
public:
  float sampling_sec;
  float filter_kHz;
  float sign;
  float minval;
  map<float, float> maxvals;
};


extern "C" QUBFAST_API void* qub_doseresponse_peak_init(double sampling_sec, double filter_kHz, double sign)
{
  qub_dr_peak *dr = new qub_dr_peak;
  dr->sampling_sec = (float) sampling_sec;
  dr->filter_kHz = (float) filter_kHz;
  dr->sign = (sign >= 0.0) ? 1.0 : -1.0;
  //cerr << "init: sign = " << sign << " -> " << dr->sign << endl;
  dr->minval = 1e20f;
  return dr;
}

extern "C" QUBFAST_API void qub_doseresponse_peak_free(void *dr)
{
  if ( dr )
    delete (qub_dr_peak *) dr;
}

extern "C" QUBFAST_API void qub_doseresponse_peak_add_data(void *drx, int Ndata, float *stim, float *resp)
{
  qub_dr_peak *dr = (qub_dr_peak*) drx;
  vector<float> filtered;
  float *ff = resp;
  
  if ( dr->filter_kHz ) {
    filtered.resize(Ndata);
    ff = &(filtered[0]);
    qub_filterdataf(resp, ff, Ndata, dr->sampling_sec, (float) (dr->filter_kHz*1e3));
  }
  
  for (int i=0; i<Ndata; ++i) {
    float r = dr->sign * ff[i];
    if ( r < dr->minval )
      dr->minval = r;

    float d = stim[i];
    map<float,float>::iterator maxi = dr->maxvals.find(d);
    if ( maxi == dr->maxvals.end() ) {
      dr->maxvals[d] = r;
    } else if ( maxi->second < r ) {
      maxi->second = r;
    }
  }
}

extern "C" QUBFAST_API int qub_doseresponse_peak_result(void *drx, int max_results, float *dose, float *resp)
{
  qub_dr_peak *dr = (qub_dr_peak*) drx;
  int N = 0;

  int skip = ((int) ceil(((float)dr->maxvals.size()) * 1.0 / max_results + 0.5)) - 1;
  if ( skip >= 0 ) {
    for (map<float, float>::iterator ii = dr->maxvals.begin(); ii != dr->maxvals.end(); ++ii) {
      if ( N == max_results )
	break;
      dose[N] = ii->first;
      resp[N] = dr->sign * (ii->second - dr->minval);
      //cerr << dose[N] << ": " << resp[N] << " = " << dr->sign << " * (" << ii->second << " - " << dr->minval << ")" << endl;
      ++N;
      for (int i=0; (i<skip) && (ii != dr->maxvals.end()); ++i)
	++ii;
    }
  }
  return N;
}