<commit_before>/*
 *            Copyright 2009-2017 The VOTCA Development Team
 *                       (http://www.votca.org)
 *
 *      Licensed under the Apache License, Version 2.0 (the "License")
 *
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *              http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <votca/xtp/numerical_integrations.h>
#include <votca/ctp/logger.h>
#include <votca/xtp/espfit.h>
#include <votca/xtp/aomatrix.h>

//#include <boost/progress.hpp>

#include <math.h>
#include <votca/tools/constants.h>

namespace votca { namespace xtp {

void Espfit::Fit2Density(std::vector< QMAtom* >& _atomlist,const Eigen::MatrixXd &_dmat,const AOBasis &_basis,string gridsize) {

    // setting up grid
    Grid _grid;
    _grid.setAtomlist(&_atomlist);
    _grid.setupCHELPgrid();
    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() <<  " Done setting up CHELPG grid with " << _grid.getsize() << " points " << flush;

    // Calculating nuclear potential at gridpoints
    AOOverlap overlap;
    overlap.Fill(_basis);
    double N_comp=_dmat.cwiseProduct(overlap.Matrix()).sum();

    NumericalIntegration numway;

    numway.GridSetup(gridsize,_atomlist,&_basis);
    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Setup "<<gridsize<<" Numerical Grid with "<<numway.getGridSize()<<" gridpoints."<< flush;
    double N=numway.IntegrateDensity(_dmat);
    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Calculated Densities at Numerical Grid, Number of electrons is "<< N << flush;

    if(std::abs(N-N_comp)>0.001){
        CTP_LOG(ctp::logDEBUG, *_log) <<"=======================" << flush;
        CTP_LOG(ctp::logDEBUG, *_log) <<"WARNING: Calculated Densities at Numerical Grid, Number of electrons "<< N <<" is far away from the the real value "<< N_comp<<", you should increase the accuracy of the integration grid."<< flush;
        N=N_comp;
        CTP_LOG(ctp::logDEBUG, *_log) <<"WARNING: Electronnumber set to "<< N << flush;
        CTP_LOG(ctp::logDEBUG, *_log) <<"=======================" << flush;
    }

    double netcharge=getNetcharge( _atomlist,N );

    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Calculating ESP at CHELPG grid points"  << flush;
    //boost::progress_display show_progress( _grid.getsize() );
    #pragma omp parallel for
    for ( unsigned i = 0 ; i < _grid.getsize(); i++){
        _grid.getGridValues()(i)=numway.IntegratePotential(_grid.getGridPositions()[i]);
    }

    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Electron contribution calculated"  << flush;
    if (!_do_Transition){
      EvalNuclearPotential(  _atomlist,  _grid );
    }

    FitPartialCharges(_atomlist,_grid, netcharge);
    return;
    }

void Espfit::EvalNuclearPotential(const std::vector< QMAtom* >& _atoms, Grid& _grid) {

    const std::vector< tools::vec >& _gridpoints = _grid.getGridPositions();
    Eigen::VectorXd& _gridvalues=_grid.getGridValues();
    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Calculating ESP of nuclei at CHELPG grid points" << flush;

    for (unsigned i = 0; i < _gridpoints.size(); i++) {
        for (unsigned j = 0; j < _atoms.size(); j++) {
            const vec& posatom=_atoms[j]->getPos();
            double Znuc=_atoms[j]->getNuccharge();
            double dist_j = tools::abs(_gridpoints[i]-posatom);
            _gridvalues(i) += Znuc / dist_j;
        }
    }
    return;
}

double Espfit::getNetcharge(const std::vector< QMAtom* >& _atoms, double N ){
    double netcharge = 0.0;
      if (std::abs(N) < 0.05) {
        CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp()<< " Number of Electrons is " << N << " transitiondensity is used for fit" << flush;
        _do_Transition = true;
      } else {
        double Znuc = 0.0;
        for (unsigned j = 0; j < _atoms.size(); j++) {
          Znuc += _atoms[j]->getNuccharge();
        }

        if (std::abs(Znuc - N) < 4) {
          CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp()<< " Number of Electrons minus Nucleus charge is " << Znuc - N << "." << flush;
        } else {
          CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp()<< " Warning: Your molecule is highly ionized." << flush;
        }
        netcharge = Znuc - N;
        _do_Transition = false;
      }

      netcharge = std::round(netcharge);
      CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp()<< " Netcharge constrained to " << netcharge << flush;

      return netcharge;
}

void Espfit::Fit2Density_analytic(std::vector< QMAtom* >& _atomlist,const Eigen::MatrixXd &_dmat,const AOBasis &_basis) {
    // setting up grid
    Grid _grid;
    _grid.setAtomlist(&_atomlist);
    _grid.setupCHELPgrid();

    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() <<  " Done setting up CHELPG grid with " << _grid.getsize() << " points " << endl;
    // Calculating nuclear potential at gridpoints
    AOOverlap overlap;
    overlap.Fill(_basis);
    double N_comp=_dmat.cwiseProduct(overlap.Matrix()).sum();

    double netcharge=getNetcharge( _atomlist,N_comp );
    if(!_do_Transition){
        EvalNuclearPotential(_atomlist, _grid);
    }

    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Calculating ESP at CHELPG grid points"  << flush;
    #pragma omp parallel for
    for ( unsigned i = 0 ; i < _grid.getsize(); i++){
         AOESP _aoesp;
         _aoesp.Fill(_basis, _grid.getGridPositions()[i]);
         _grid.getGridValues()(i) -=_dmat.cwiseProduct(_aoesp.Matrix()).sum();
          }

   FitPartialCharges(_atomlist,_grid,netcharge);

    return;
    }

void Espfit::FitPartialCharges( std::vector< QMAtom* >& _atomlist,const Grid& _grid,double _netcharge ){

  const int NoOfConstraints=1;
  const int matrixSize=_atomlist.size()+NoOfConstraints;

    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Setting up Matrices for fitting of size "<< matrixSize <<" x " << matrixSize<< flush;

    const std::vector< tools::vec >& _gridpoints=_grid.getGridPositions();
    const Eigen::VectorXd & _potential=_grid.getGridValues();
    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Using "<< _atomlist.size() <<" Fittingcenters and " << _gridpoints.size()<< " Gridpoints."<< flush;

    Eigen::MatrixXd _Amat = Eigen::MatrixXd::Zero(matrixSize,matrixSize);
    Eigen::VectorXd _Bvec = Eigen::VectorXd::Zero(matrixSize);
    // setting up _Amat
    #pragma omp parallel for
    for ( int _i =0 ; _i < _Amat.rows()-NoOfConstraints; _i++){
        for ( int _j=_i; _j<_Amat.cols()-NoOfConstraints; _j++){
            for ( unsigned _k=0; _k < _gridpoints.size(); _k++){
                double dist_i = tools::abs(_atomlist[_i]->getPos()-_gridpoints[_k]);
                double dist_j = tools::abs(_atomlist[_j]->getPos()-_gridpoints[_k]);

                 _Amat(_i,_j) += 1.0/dist_i/dist_j;
            }
            _Amat(_j,_i) = _Amat(_i,_j);
        }
    }

    for ( int _i =0 ; _i < _Amat.rows(); _i++){
      _Amat(_i,_Amat.cols()-NoOfConstraints) = 1.0;
      _Amat(_Amat.rows()-NoOfConstraints,_i) = 1.0;
    }
    _Amat(_Amat.rows()-NoOfConstraints,_Amat.cols()-NoOfConstraints) = 0.0;

    // setting up Bvec
    #pragma omp parallel for
    for ( int _i =0 ; _i < _Bvec.size()-1; _i++){
        for ( unsigned _k=0; _k < _gridpoints.size(); _k++){
                double dist_i = tools::abs(_atomlist[_i]->getPos()-_gridpoints[_k]);
                _Bvec(_i) += _potential(_k)/dist_i;
        }
       }

    _Bvec(_Bvec.size()-NoOfConstraints) = _netcharge; //netcharge!!!!
    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Inverting Matrices "<< flush;
    // invert _Amat

    Eigen::VectorXd _charges;
    if(_do_svd){
      Eigen::JacobiSVD<Eigen::MatrixXd> svd;
      svd.setThreshold(_conditionnumber);
      svd.compute(_Amat);
      _charges=svd.solve(_Bvec);
      CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << "SVD Done. "<<_Bvec.size()-svd.nonzeroSingularValues()<<" could not be fitted and are set to zero."<< flush;
    }
    else{
       _charges=_Amat.colPivHouseholderQr().solve(_Bvec);
    }

    //remove constraint
    _charges=_charges.segment(0,_charges.size()-NoOfConstraints);
    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Inverting Matrices done."<< flush;

    CTP_LOG(ctp::logDEBUG, *_log) << " Sum of fitted charges: " << _charges.sum() << flush;
    for (unsigned i=0;i<_atomlist.size();i++){
      _atomlist[i]->setPartialcharge(_charges(i));
    }

    // get RMSE
    double _rmse = 0.0;
    double _totalPotSq = 0.0;
    for ( unsigned _k=0 ; _k < _gridpoints.size(); _k++ ){
        double temp = 0.0;
        for ( const QMAtom* atom:_atomlist){
            double dist =  tools::abs(_gridpoints[_k]-atom->getPos());
            temp += atom->getPartialcharge()/dist;
        }
        _rmse += (_potential(_k) - temp)*(_potential(_k) - temp);
        _totalPotSq += _potential(_k)*_potential(_k);
    }
    CTP_LOG(ctp::logDEBUG, *_log) << " RMSE of fit:  " << sqrt(_rmse/_gridpoints.size()) << flush;
    CTP_LOG(ctp::logDEBUG, *_log) << " RRMSE of fit: " << sqrt(_rmse/_totalPotSq) << flush;

    return;
   }

}}
<commit_msg>fixed bug<commit_after>/*
 *            Copyright 2009-2017 The VOTCA Development Team
 *                       (http://www.votca.org)
 *
 *      Licensed under the Apache License, Version 2.0 (the "License")
 *
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *              http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <votca/xtp/numerical_integrations.h>
#include <votca/ctp/logger.h>
#include <votca/xtp/espfit.h>
#include <votca/xtp/aomatrix.h>

//#include <boost/progress.hpp>

#include <math.h>
#include <votca/tools/constants.h>

namespace votca { namespace xtp {

void Espfit::Fit2Density(std::vector< QMAtom* >& _atomlist,const Eigen::MatrixXd &_dmat,const AOBasis &_basis,string gridsize) {

    // setting up grid
    Grid _grid;
    _grid.setAtomlist(&_atomlist);
    _grid.setupCHELPgrid();
    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() <<  " Done setting up CHELPG grid with " << _grid.getsize() << " points " << flush;

    // Calculating nuclear potential at gridpoints
    AOOverlap overlap;
    overlap.Fill(_basis);
    double N_comp=_dmat.cwiseProduct(overlap.Matrix()).sum();

    NumericalIntegration numway;

    numway.GridSetup(gridsize,_atomlist,&_basis);
    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Setup "<<gridsize<<" Numerical Grid with "<<numway.getGridSize()<<" gridpoints."<< flush;
    double N=numway.IntegrateDensity(_dmat);
    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Calculated Densities at Numerical Grid, Number of electrons is "<< N << flush;

    if(std::abs(N-N_comp)>0.001){
        CTP_LOG(ctp::logDEBUG, *_log) <<"=======================" << flush;
        CTP_LOG(ctp::logDEBUG, *_log) <<"WARNING: Calculated Densities at Numerical Grid, Number of electrons "<< N <<" is far away from the the real value "<< N_comp<<", you should increase the accuracy of the integration grid."<< flush;
        N=N_comp;
        CTP_LOG(ctp::logDEBUG, *_log) <<"WARNING: Electronnumber set to "<< N << flush;
        CTP_LOG(ctp::logDEBUG, *_log) <<"=======================" << flush;
    }

    double netcharge=getNetcharge( _atomlist,N );

    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Calculating ESP at CHELPG grid points"  << flush;
    //boost::progress_display show_progress( _grid.getsize() );
    #pragma omp parallel for
    for ( unsigned i = 0 ; i < _grid.getsize(); i++){
        _grid.getGridValues()(i)=numway.IntegratePotential(_grid.getGridPositions()[i]);
    }

    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Electron contribution calculated"  << flush;
    if (!_do_Transition){
      EvalNuclearPotential(  _atomlist,  _grid );
    }

    FitPartialCharges(_atomlist,_grid, netcharge);
    return;
    }

void Espfit::EvalNuclearPotential(const std::vector< QMAtom* >& _atoms, Grid& _grid) {

    const std::vector< tools::vec >& _gridpoints = _grid.getGridPositions();
    Eigen::VectorXd& _gridvalues=_grid.getGridValues();
    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Calculating ESP of nuclei at CHELPG grid points" << flush;

    for (unsigned i = 0; i < _gridpoints.size(); i++) {
        for (unsigned j = 0; j < _atoms.size(); j++) {
            const vec& posatom=_atoms[j]->getPos();
            double Znuc=_atoms[j]->getNuccharge();
            double dist_j = tools::abs(_gridpoints[i]-posatom);
            _gridvalues(i) += Znuc / dist_j;
        }
    }
    return;
}

double Espfit::getNetcharge(const std::vector< QMAtom* >& _atoms, double N ){
    double netcharge = 0.0;
      if (std::abs(N) < 0.05) {
        CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp()<< " Number of Electrons is " << N << " transitiondensity is used for fit" << flush;
        _do_Transition = true;
      } else {
        double Znuc = 0.0;
        for (unsigned j = 0; j < _atoms.size(); j++) {
          Znuc += _atoms[j]->getNuccharge();
        }

        if (std::abs(Znuc - N) < 4) {
          CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp()<< " Number of Electrons minus Nucleus charge is " << Znuc - N << "." << flush;
        } else {
          CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp()<< " Warning: Your molecule is highly ionized." << flush;
        }
        netcharge = Znuc - N;
        _do_Transition = false;
      }

      netcharge = std::round(netcharge);
      CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp()<< " Netcharge constrained to " << netcharge << flush;

      return netcharge;
}

void Espfit::Fit2Density_analytic(std::vector< QMAtom* >& _atomlist,const Eigen::MatrixXd &_dmat,const AOBasis &_basis) {
    // setting up grid
    Grid _grid;
    _grid.setAtomlist(&_atomlist);
    _grid.setupCHELPgrid();

    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() <<  " Done setting up CHELPG grid with " << _grid.getsize() << " points " << endl;
    // Calculating nuclear potential at gridpoints
    AOOverlap overlap;
    overlap.Fill(_basis);
    double N_comp=_dmat.cwiseProduct(overlap.Matrix()).sum();

    double netcharge=getNetcharge( _atomlist,N_comp );
    if(!_do_Transition){
        EvalNuclearPotential(_atomlist, _grid);
    }

    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Calculating ESP at CHELPG grid points"  << flush;
    #pragma omp parallel for
    for ( unsigned i = 0 ; i < _grid.getsize(); i++){
         AOESP _aoesp;
         _aoesp.Fill(_basis, _grid.getGridPositions()[i]);
         _grid.getGridValues()(i) -=_dmat.cwiseProduct(_aoesp.Matrix()).sum();
          }

   FitPartialCharges(_atomlist,_grid,netcharge);

    return;
    }

void Espfit::FitPartialCharges( std::vector< QMAtom* >& _atomlist,const Grid& _grid,double _netcharge ){

  const int NoOfConstraints=1;
  const int matrixSize=_atomlist.size()+NoOfConstraints;

    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Setting up Matrices for fitting of size "<< matrixSize <<" x " << matrixSize<< flush;

    const std::vector< tools::vec >& _gridpoints=_grid.getGridPositions();
    const Eigen::VectorXd & _potential=_grid.getGridValues();
    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Using "<< _atomlist.size() <<" Fittingcenters and " << _gridpoints.size()<< " Gridpoints."<< flush;

    Eigen::MatrixXd _Amat = Eigen::MatrixXd::Zero(matrixSize,matrixSize);
    Eigen::VectorXd _Bvec = Eigen::VectorXd::Zero(matrixSize);
    // setting up _Amat
    #pragma omp parallel for
    for ( int _i =0 ; _i < _Amat.rows()-NoOfConstraints; _i++){
        for ( int _j=_i; _j<_Amat.cols()-NoOfConstraints; _j++){
            for ( unsigned _k=0; _k < _gridpoints.size(); _k++){
                double dist_i = tools::abs(_atomlist[_i]->getPos()-_gridpoints[_k]);
                double dist_j = tools::abs(_atomlist[_j]->getPos()-_gridpoints[_k]);

                 _Amat(_i,_j) += 1.0/dist_i/dist_j;
            }
            _Amat(_j,_i) = _Amat(_i,_j);
        }
    }

    for ( int _i =0 ; _i < _Amat.rows(); _i++){
      _Amat(_i,_Amat.cols()-NoOfConstraints) = 1.0;
      _Amat(_Amat.rows()-NoOfConstraints,_i) = 1.0;
    }
    _Amat(_Amat.rows()-NoOfConstraints,_Amat.cols()-NoOfConstraints) = 0.0;

    // setting up Bvec
    #pragma omp parallel for
    for ( int _i =0 ; _i < _Bvec.size()-1; _i++){
        for ( unsigned _k=0; _k < _gridpoints.size(); _k++){
                double dist_i = tools::abs(_atomlist[_i]->getPos()-_gridpoints[_k]);
                _Bvec(_i) += _potential(_k)/dist_i;
        }
       }

    _Bvec(_Bvec.size()-NoOfConstraints) = _netcharge; //netcharge!!!!
    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Inverting Matrices "<< flush;
    // invert _Amat

    Eigen::VectorXd _charges;
    if(_do_svd){
      Eigen::JacobiSVD<Eigen::MatrixXd> svd;
      svd.setThreshold(_conditionnumber);
      svd.compute(_Amat);
      _charges=svd.solve(_Bvec);
      CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << "SVD Done. "<<_Bvec.size()-svd.nonzeroSingularValues()<<" could not be fitted and are set to zero."<< flush;
    }
    else{
       _charges=_Amat.colPivHouseholderQr().solve(_Bvec);
    }
    //remove constraint
    _charges.conservativeResize(_atomlist.size());
    CTP_LOG(ctp::logDEBUG, *_log) << ctp::TimeStamp() << " Inverting Matrices done."<< flush;

    CTP_LOG(ctp::logDEBUG, *_log) << " Sum of fitted charges: " << _charges.sum() << flush;
    for (unsigned i=0;i<_atomlist.size();i++){
      _atomlist[i]->setPartialcharge(_charges(i));
    }

    // get RMSE
    double _rmse = 0.0;
    double _totalPotSq = 0.0;
    for ( unsigned _k=0 ; _k < _gridpoints.size(); _k++ ){
        double temp = 0.0;
        for ( const QMAtom* atom:_atomlist){
            double dist =  tools::abs(_gridpoints[_k]-atom->getPos());
            temp += atom->getPartialcharge()/dist;
        }
        _rmse += (_potential(_k) - temp)*(_potential(_k) - temp);
        _totalPotSq += _potential(_k)*_potential(_k);
    }
    CTP_LOG(ctp::logDEBUG, *_log) << " RMSE of fit:  " << sqrt(_rmse/_gridpoints.size()) << flush;
    CTP_LOG(ctp::logDEBUG, *_log) << " RRMSE of fit: " << sqrt(_rmse/_totalPotSq) << flush;

    return;
   }

}}
<|endoftext|>


<commit_before>#include <iostream>

#include <list>
#include <string>

#include <clotho/testserver.hpp>
#include <clotho/socket.hpp>

#include "locktestmaster.hpp"
#include "imapsession.hpp"
#include "mailstorelocktest.hpp"

/*
 * Reimplement these classes:  imapmaster, internetserver
 */

typedef struct {
  std::string s;
  int retry_count;
} commands;

typedef std::list<commands> StringList;

class TestSocket : public Socket {
public:
  TestSocket(void);
  virtual ~TestSocket();
  virtual ssize_t receive(uint8_t *buffer, size_t size);
  virtual ssize_t send(const uint8_t *data, size_t length);
  void in(const std::string &s, int count);
  const std::string *out(void);
  int retry_out(void);
  void reset(void);

private:
  StringList *m_inputs;
  StringList *m_outputs;
  size_t m_inputOffset;
  StringList::iterator m_pIn;
  StringList::iterator m_pOut;
};

TestSocket::TestSocket() : Socket(0, 0, 16384) {
  m_inputs = NULL;
  m_outputs = NULL;
}

TestSocket::~TestSocket() {
}

ssize_t TestSocket::receive(uint8_t *buffer, size_t size) {
  ssize_t result = -1;
  if ((NULL != m_inputs) && (m_inputs->end() != m_pIn)) {
    strcpy((char *)buffer, (*m_pIn).s.c_str());
    result = (*m_pIn).s.length();
    g_lockState.retryCount((*m_pIn).retry_count);
    m_pIn++;
  }

  return result;
}

ssize_t TestSocket::send(const uint8_t *data, size_t length) {
  if (NULL == m_outputs) {
    m_outputs = new StringList;
  }

  commands command = { std::string((char *)data, length), g_lockState.retryCount() };
  m_outputs->push_back(command);
  // m_outputs->push_back(new std::string((char *)data, length));
  // std::cout << data << std::endl;
  m_pOut = m_outputs->begin();

  return length;
}

void TestSocket::in(const std::string &s, int count) {
  if (NULL == m_inputs) {
    m_inputs = new StringList;
  }
  commands command = { s, count };
  m_inputs->push_back(command);
  m_pIn = m_inputs->begin();
}

const std::string *TestSocket::out(void) {
  std::string *result = NULL;
  if ((NULL != m_outputs) && (m_outputs->end() != m_pOut)) {
    result = new std::string ((*m_pOut).s);
    m_pOut++;
  }
  return result;
}

int TestSocket::retry_out(void) {
  if ((NULL != m_outputs) && (m_outputs->end() != m_pOut)) {
    return (*m_pOut).retry_count;
  }
  return -999;
}

void TestSocket::reset(void) {
  delete m_inputs;
  delete m_outputs;
  m_inputs = NULL;
  m_outputs = NULL;
}

bool test(TestServer &server, TestSocket *s, const std::string commands[],
	  int command_count, const std::string &match, int response,
	  int initial_retry_count, int final_retry_count) {
  bool result = true;
  const std::string *o;

  s->reset();
  for (int i=0; i<command_count; ++i) {
    s->in(commands[i], initial_retry_count);
  }
  server.test(s);
  int retries;
  for (int i=0; i< response; ++i) {
    retries = s->retry_out();
    o = s->out();
  }
  if ((NULL == o) || (*o != match)) {
    std::cout << "Response doesn't match. \"";
    if (NULL != o) {
      std::cout << *o;
    }
    else {
      std::cout << "NULL";
    }
    std::cout << "\" expecting \"" << match << "\"" << std::endl;
    result = false;
  }
  if (final_retry_count != retries) {
    std:: cout << "The retry count is " << retries << " and I was expecting " << final_retry_count << std::endl;
    result = false;
  }
  return result;
}

typedef struct {
  const std::string commands[10];
  int command_count;
  const std::string match;
  int response_number;
  int initial_retry_count;
  int final_retry_count;
  const std::string test_name;
} test_descriptor;

test_descriptor descriptors[] = {
#if 0
#endif // 0
  {{
    "1 login foo bar\r\n",
    "2 create inbox\r\n",
    "3 logout\r\n"
    }, 3, "2 NO create Locking Error:  Too Many Retries\r\n", 3, 1000, 987,
   "Creation failure"},
  {{
    "1 login foo bar\r\n",
    "2 create inbox\r\n",
    "3 logout\r\n"
    }, 3, "2 OK create Completed\r\n", 3, 0, -1,
   "Successful creation"},
  {{
      "1 login foo bar\r\n",
      "2 delete inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO delete Locking Error:  Too Many Retries\r\n", 3, 1000, 987,
   "Deletion failure"},
  {{
      "1 login foo bar\r\n",
      "2 delete inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK delete Completed\r\n", 3, 0, -1,
   "Successful deletion"},
  {{
      "1 login foo bar\r\n",
      "2 rename inbox outbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO rename Locking Error:  Too Many Retries\r\n", 3, 1000, 987,
   "Renaming failure"},
  {{
      "1 login foo bar\r\n",
      "2 rename inbox outbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK rename Completed\r\n", 3, 0, -1,
   "Successful renaming"},
  {{
      "1 login foo bar\r\n",
      "2 subscribe inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO subscribe Locking Error:  Too Many Retries\r\n", 3, 1000, 987,
   "Subscribing failure"},
  {{
      "1 login foo bar\r\n",
      "2 subscribe inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK subscribe Completed\r\n", 3, 0, -1,
   "Successful subscribing"},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO select Locking Error:  Too Many Retries\r\n", 3, 1000, 987,
   "Selecting failure"},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK [READ-WRITE] select Completed\r\n", 4, 0, -1,
   "Successful selecting"},
  {{
      "1 login foo bar\r\n",
      "2 examine inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO examine Locking Error:  Too Many Retries\r\n", 3, 1000, 987,
   "Examining failure"},
  {{
      "1 login foo bar\r\n",
      "2 examine inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK [READ-ONLY] examine Completed\r\n", 4, 0, -1,
   "Successful examining"},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 close\r\n",
      "4 close\r\n",
      "5 logout\r\n"
    }, 5, "3 NO close Locking Error:  Too Many Retries\r\n", 5, 1, 4,
   "Selecting failure"},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 close\r\n",
      "4 logout\r\n"
    }, 4, "3 OK close Completed\r\n", 5, 0, -1,
   "Successful selecting"},
};

int main() {
  LockTestMaster master("localhost", 60, 1800, 900, 5, 12, 5);
  TestServer server(&master);
  TestSocket *s = new TestSocket();
  int pass_count = 0;
  int fail_count = 0;

  for (int i=0; i<(sizeof(descriptors)/sizeof(test_descriptor)); ++i) {
    bool result = test(server, s, descriptors[i].commands, descriptors[i].command_count, descriptors[i].match, descriptors[i].response_number, descriptors[i].initial_retry_count, descriptors[i].final_retry_count);
    std::cout << descriptors[i].test_name;
    if (result) {
      std::cout << " success" << std::endl;
      ++pass_count;
    }
    else {
      std::cout << " failure" << std::endl;
      ++fail_count;
    }
  }

  return 0;
}
<commit_msg>Set it up so I can test the lock contention on close.<commit_after>#include <iostream>

#include <list>
#include <string>

#include <clotho/testserver.hpp>
#include <clotho/socket.hpp>

#include "locktestmaster.hpp"
#include "imapsession.hpp"
#include "mailstorelocktest.hpp"

/*
 * Reimplement these classes:  imapmaster, internetserver
 */

typedef struct {
  std::string s;
  int retry_count;
} commands;

typedef std::list<commands> StringList;

class TestSocket : public Socket {
public:
  TestSocket(void);
  virtual ~TestSocket();
  virtual ssize_t receive(uint8_t *buffer, size_t size);
  virtual ssize_t send(const uint8_t *data, size_t length);
  void in(const std::string &s, int count);
  const std::string *out(void);
  int retry_out(void);
  void reset(void);

private:
  StringList *m_inputs;
  StringList *m_outputs;
  size_t m_inputOffset;
  StringList::iterator m_pIn;
  StringList::iterator m_pOut;
};

TestSocket::TestSocket() : Socket(0, 0, 16384) {
  m_inputs = NULL;
  m_outputs = NULL;
}

TestSocket::~TestSocket() {
}

ssize_t TestSocket::receive(uint8_t *buffer, size_t size) {
  ssize_t result = -1;
  if ((NULL != m_inputs) && (m_inputs->end() != m_pIn)) {
    strcpy((char *)buffer, (*m_pIn).s.c_str());
    result = (*m_pIn).s.length();
    g_lockState.retryCount((*m_pIn).retry_count);
    m_pIn++;
  }

  return result;
}

ssize_t TestSocket::send(const uint8_t *data, size_t length) {
  if (NULL == m_outputs) {
    m_outputs = new StringList;
  }

  commands command = { std::string((char *)data, length), g_lockState.retryCount() };
  m_outputs->push_back(command);
  // m_outputs->push_back(new std::string((char *)data, length));
  // std::cout << "retries: " << g_lockState.retryCount() << "=+=+=+=" << data << std::endl;
  m_pOut = m_outputs->begin();

  return length;
}

void TestSocket::in(const std::string &s, int count) {
  if (NULL == m_inputs) {
    m_inputs = new StringList;
  }
  commands command = { s, count };
  m_inputs->push_back(command);
  m_pIn = m_inputs->begin();
}

const std::string *TestSocket::out(void) {
  std::string *result = NULL;
  if ((NULL != m_outputs) && (m_outputs->end() != m_pOut)) {
    result = new std::string ((*m_pOut).s);
    m_pOut++;
  }
  return result;
}

int TestSocket::retry_out(void) {
  if ((NULL != m_outputs) && (m_outputs->end() != m_pOut)) {
    return (*m_pOut).retry_count;
  }
  return -999;
}

void TestSocket::reset(void) {
  delete m_inputs;
  delete m_outputs;
  m_inputs = NULL;
  m_outputs = NULL;
}

bool test(TestServer &server, TestSocket *s, const std::string commands[],
	  int command_count, const std::string &match, int test_step,
	  int response, int initial_retry_count, int final_retry_count) {
  bool result = true;
  const std::string *o;

  s->reset();
  for (int i=0; i<command_count; ++i) {
    if (i == test_step) {
      s->in(commands[i], initial_retry_count);
    }
    else {
      s->in(commands[i], 0);
    }
  }
  server.test(s);
  int retries;
  for (int i=0; i< response; ++i) {
    retries = s->retry_out();
    o = s->out();
  }
  if ((NULL == o) || (*o != match)) {
    std::cout << "Response doesn't match. \"";
    if (NULL != o) {
      std::cout << *o;
    }
    else {
      std::cout << "NULL";
    }
    std::cout << "\" expecting \"" << match << "\"" << std::endl;
    result = false;
  }
  if (final_retry_count != retries) {
    std:: cout << "The retry count is " << retries << " and I was expecting " << final_retry_count << std::endl;
    result = false;
  }
  return result;
}

typedef struct {
  const std::string commands[10];
  int command_count;
  const std::string match;
  int test_step;
  int response_number;
  int initial_retry_count;
  int final_retry_count;
  const std::string test_name;
} test_descriptor;

test_descriptor descriptors[] = {
#if 0
#endif // 0
  {{
    "1 login foo bar\r\n",
    "2 create inbox\r\n",
    "3 logout\r\n"
    }, 3, "2 NO create Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Creation failure"},
  {{
    "1 login foo bar\r\n",
    "2 create inbox\r\n",
    "3 logout\r\n"
    }, 3, "2 OK create Completed\r\n", 1, 3, 0, -1,
   "Successful creation"},
  {{
      "1 login foo bar\r\n",
      "2 delete inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO delete Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Deletion failure"},
  {{
      "1 login foo bar\r\n",
      "2 delete inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK delete Completed\r\n", 1, 3, 0, -1,
   "Successful deletion"},
  {{
      "1 login foo bar\r\n",
      "2 rename inbox outbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO rename Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Renaming failure"},
  {{
      "1 login foo bar\r\n",
      "2 rename inbox outbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK rename Completed\r\n", 1, 3, 0, -1,
   "Successful renaming"},
  {{
      "1 login foo bar\r\n",
      "2 subscribe inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO subscribe Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Subscribing failure"},
  {{
      "1 login foo bar\r\n",
      "2 subscribe inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK subscribe Completed\r\n", 1, 3, 0, -1,
   "Successful subscribing"},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO select Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Selecting failure"},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK [READ-WRITE] select Completed\r\n", 1, 4, 0, -1,
   "Successful selecting"},
  {{
      "1 login foo bar\r\n",
      "2 examine inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 NO examine Locking Error:  Too Many Retries\r\n", 1, 3, 1000, 987,
   "Examining failure"},
  {{
      "1 login foo bar\r\n",
      "2 examine inbox\r\n",
      "3 logout\r\n"
    }, 3, "2 OK [READ-ONLY] examine Completed\r\n", 1, 4, 0, -1,
   "Successful examining"},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 close\r\n",
      "4 close\r\n",
      "5 logout\r\n"
    }, 5, "3 NO close Locking Error:  Too Many Retries\r\n", 2, 5, 1000, 987,
   "Closing failure"},
  {{
      "1 login foo bar\r\n",
      "2 select inbox\r\n",
      "3 close\r\n",
      "4 logout\r\n"
    }, 4, "3 OK close Completed\r\n", 2, 5, 0, -1,
   "Successful closing"},
};

int main() {
  LockTestMaster master("localhost", 60, 1800, 900, 5, 12, 5);
  TestServer server(&master);
  TestSocket *s = new TestSocket();
  int pass_count = 0;
  int fail_count = 0;

  for (int i=0; i<(sizeof(descriptors)/sizeof(test_descriptor)); ++i) {
    bool result = test(server, s, descriptors[i].commands, descriptors[i].command_count, descriptors[i].match, descriptors[i].test_step, descriptors[i].response_number, descriptors[i].initial_retry_count, descriptors[i].final_retry_count);
    std::cout << descriptors[i].test_name;
    if (result) {
      std::cout << " success" << std::endl;
      ++pass_count;
    }
    else {
      std::cout << " failure" << std::endl;
      ++fail_count;
    }
  }

  return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2010-2022, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include <fstream>
#include "mfem.hpp"

using namespace std;
using namespace mfem;

#include "unit_tests.hpp"

void fillRandomMatrix(SparseMatrix & M)
{
   int nrows = M.Size();
   int ncols = M.Width();
   int max_nnz_row = ncols/50;

   for (int i(0); i < nrows; ++i)
   {
      int nnz_row = rand()%max_nnz_row+1;
      for (int j = 0; j < nnz_row; ++j)
      {
         M.Set(i,rand()%ncols, static_cast<double>( rand() )/static_cast<double>
               (RAND_MAX) -.5 );
      }
   }
   M.Finalize();
}

TEST_CASE("BlockMatrix", "[BlockMatrix]")
{

   int size0 = 1000;
   int size1 = 350;

   Array<int> offsets(3);
   offsets[0] = 0;
   offsets[1] = size0;
   offsets[2] = size0+size1;

   SparseMatrix A00(size0, size0), A10(size1,size0), A01(size0,size1);
   fillRandomMatrix(A00);
   fillRandomMatrix(A10);
   fillRandomMatrix(A01);

   BlockMatrix * A = NULL;
   {
      A = new BlockMatrix( offsets );
      A->SetBlock(0,0, &A00);
      A->SetBlock(0,1,  &A01);
      A->SetBlock(1,0,  &A10);
   }

   SparseMatrix * Amono = NULL;
   {
      Amono = A->CreateMonolithic();
   }

   int size(A->NumRows());
   double tol = 1e-10;
   int ntry(5);

   SECTION("Check method BlockMatrix::RowSize")
   {
      int nfails(0);
      for (int i(0); i < size; ++i)
      {
         if ( A->RowSize(i) != Amono->RowSize(i) )
         {
            UNSCOPED_INFO("BlockMatrix::RowSize failure: " << i << '\t'
                          << A->RowSize( i) << '\t'
                          << Amono->RowSize(i));
            ++nfails;
         }
      }
      REQUIRE(nfails == 0);
   }

   SECTION("Check method BlockMatrix::GetRow")
   {
      double maxerror(-1.), currentError;
      Vector glob(size), globgood(size);
      Vector srow, srowgood;
      Array<int> cols, colsgood;

      for (int i(0); i < size; ++i)
      {
         A->GetRow(i, cols, srow);
         glob = 0.0;
         glob.SetSubVector(cols, srow);
         Amono->GetRow(i, colsgood, srowgood);
         globgood = 0.0;
         globgood.SetSubVector(colsgood, srowgood);
         glob.Add(-1., globgood);
         currentError = glob.Normlinf();

         if (currentError > maxerror)
         {
            maxerror = currentError;
         }
      }
      REQUIRE(maxerror < tol);
   }

   Vector x(size), y(size), ymono(size);

   SECTION("Check BlockMatrix::Mult")
   {
      double maxerror(-1.), currentError;
      for (int i(0); i < ntry; ++i)
      {
         x.Randomize();
         A->Mult(x,y);
         Amono->Mult(x,ymono);
         y.Add(-1., ymono);
         currentError = y.Normlinf();

         if (currentError > maxerror)
         {
            maxerror = currentError;
         }

      }
      REQUIRE(maxerror < tol);
   }

   SECTION("Check BlockMatrix::AddMult #1")
   {
      double maxerror(-1.), currentError;
      for (int i(0); i < ntry; ++i)
      {
         x.Randomize();
         y.Randomize();
         ymono = y;
         A->AddMult(x,y);
         Amono->AddMult(x,ymono);
         y.Add(-1., ymono);
         currentError = y.Normlinf();

         if (currentError > maxerror)
         {
            maxerror = currentError;
         }

      }
      REQUIRE(maxerror < tol);
   }

   SECTION("Check BlockMatrix::AddMult #2")
   {
      double maxerror(-1.), currentError;
      for (int i(0); i < ntry; ++i)
      {
         x.Randomize();
         y.Randomize();
         ymono = y;
         double a = 10 * static_cast<double>( rand() )  / static_cast<double>
                    ( RAND_MAX );
         a -= 5;
         A->AddMult(x,y,a);
         Amono->AddMult(x,ymono,a);
         y.Add(-1., ymono);
         currentError = y.Normlinf();

         if (currentError > maxerror)
         {
            maxerror = currentError;
         }

      }
      REQUIRE(maxerror < tol);
   }

   SECTION("Check BlockMatrix::MultTranspose")
   {
      double maxerror(-1.), currentError;
      for (int i(0); i < ntry; ++i)
      {
         x.Randomize();
         A->MultTranspose(x,y);
         Amono->MultTranspose(x,ymono);
         y.Add(-1., ymono);
         currentError = y.Normlinf();

         if (currentError > maxerror)
         {
            maxerror = currentError;
         }

      }
      REQUIRE(maxerror < tol);
   }

   SECTION("Check BlockMatrix::AddMultTranspose #1")
   {
      double maxerror(-1.), currentError;
      for (int i(0); i < ntry; ++i)
      {
         x.Randomize();
         y.Randomize();
         ymono = y;
         A->AddMultTranspose(x,y);
         Amono->AddMultTranspose(x,ymono);
         y.Add(-1., ymono);
         currentError = y.Normlinf();

         if (currentError > maxerror)
         {
            maxerror = currentError;
         }

      }
      REQUIRE(maxerror < tol);
   }

   SECTION("Check BlockMatrix::AddMultTranspose #2")
   {
      double maxerror(-1.), currentError;
      for (int i(0); i < ntry; ++i)
      {
         x.Randomize();
         y.Randomize();
         ymono = y;
         double a = 10 * static_cast<double>( rand() )  / static_cast<double>
                    ( RAND_MAX );
         a -= 5;
         A->AddMultTranspose(x,y,a);
         Amono->AddMultTranspose(x,ymono,a);
         y.Add(-1., ymono);
         currentError = y.Normlinf();

         if (currentError > maxerror)
         {
            maxerror = currentError;
         }

      }
      REQUIRE(maxerror < tol);
   }

   SECTION("Check Transpose(const BlockMatrix &)")
   {
      BlockMatrix * At = Transpose(*A);
      REQUIRE(At->Height() == A->Width() );
      REQUIRE(At->Width() == A->Height() );

      x.Randomize();
      y.Randomize();
      Vector Ax(A->Height()), Aty(At->Height());
      A->Mult(x,Ax);
      double yAx = y*Ax;

      At->Mult(y, Aty);
      double xAty = x* Aty;

      delete At;

      REQUIRE(fabs(yAx - xAty) < tol );
   }

   SECTION("Check Mult(const BlockMatrix &, const BlockMatrix &)")
   {
      BlockMatrix * B = new BlockMatrix(offsets);
      SparseMatrix B00(size0, size0), B10(size1,size0), B01(size0,size1), B11(size1,
                                                                              size1);
      fillRandomMatrix(B00);
      fillRandomMatrix(B10);
      fillRandomMatrix(B01);
      fillRandomMatrix(B11);
      B->SetBlock(0,0, &B00);
      B->SetBlock(0,1, &B01);
      B->SetBlock(1,0, &B10);
      B->SetBlock(1,1, &B11);

      BlockMatrix * C = Mult(*A,*B);
      x.Randomize();
      Vector Bx(A->Height()), ABx(A->Height()), Cx(C->Height());
      B->Mult(x, Bx);
      A->Mult(Bx,ABx);
      C->Mult(x, Cx);

      subtract(Cx, ABx, Cx);

      double error = Cx.Normlinf();

      delete B;
      delete C;

      REQUIRE(error < tol );
   }

   delete A;
   delete Amono;
}
<commit_msg>adding unit tests<commit_after>// Copyright (c) 2010-2022, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include <fstream>
#include "mfem.hpp"

using namespace std;
using namespace mfem;

#include "unit_tests.hpp"

void fillRandomMatrix(SparseMatrix & M)
{
   int nrows = M.Size();
   int ncols = M.Width();
   int max_nnz_row = ncols/50;

   for (int i(0); i < nrows; ++i)
   {
      int nnz_row = rand()%max_nnz_row+1;
      for (int j = 0; j < nnz_row; ++j)
      {
         M.Set(i,rand()%ncols, static_cast<double>( rand() )/static_cast<double>
               (RAND_MAX) -.5 );
      }
   }
   M.Finalize();
}

TEST_CASE("BlockMatrix", "[BlockMatrix]")
{

   int size0 = 1000;
   int size1 = 350;

   Array<int> offsets(3);
   offsets[0] = 0;
   offsets[1] = size0;
   offsets[2] = size0+size1;

   SparseMatrix A00(size0, size0), A10(size1,size0), A01(size0,size1);
   fillRandomMatrix(A00);
   fillRandomMatrix(A10);
   fillRandomMatrix(A01);

   BlockMatrix * A = NULL;
   {
      A = new BlockMatrix( offsets );
      A->SetBlock(0,0, &A00);
      A->SetBlock(0,1,  &A01);
      A->SetBlock(1,0,  &A10);
   }

   SparseMatrix * Amono = NULL;
   {
      Amono = A->CreateMonolithic();
   }

   int size(A->NumRows());
   double tol = 1e-10;
   int ntry(5);

   SECTION("Check method BlockMatrix::RowSize")
   {
      int nfails(0);
      for (int i(0); i < size; ++i)
      {
         if ( A->RowSize(i) != Amono->RowSize(i) )
         {
            UNSCOPED_INFO("BlockMatrix::RowSize failure: " << i << '\t'
                          << A->RowSize( i) << '\t'
                          << Amono->RowSize(i));
            ++nfails;
         }
      }
      REQUIRE(nfails == 0);
   }

   SECTION("Check method BlockMatrix::GetRow")
   {
      double maxerror(-1.), currentError;
      Vector glob(size), globgood(size);
      Vector srow, srowgood;
      Array<int> cols, colsgood;

      for (int i(0); i < size; ++i)
      {
         A->GetRow(i, cols, srow);
         glob = 0.0;
         glob.SetSubVector(cols, srow);
         Amono->GetRow(i, colsgood, srowgood);
         globgood = 0.0;
         globgood.SetSubVector(colsgood, srowgood);
         glob.Add(-1., globgood);
         currentError = glob.Normlinf();

         if (currentError > maxerror)
         {
            maxerror = currentError;
         }
      }
      REQUIRE(maxerror < tol);
   }

   Vector x(size), y(size), ymono(size);

   SECTION("Check BlockMatrix::Mult")
   {
      double maxerror(-1.), currentError;
      for (int i(0); i < ntry; ++i)
      {
         x.Randomize();
         A->Mult(x,y);
         Amono->Mult(x,ymono);
         y.Add(-1., ymono);
         currentError = y.Normlinf();

         if (currentError > maxerror)
         {
            maxerror = currentError;
         }

      }
      REQUIRE(maxerror < tol);
   }

   SECTION("Check BlockMatrix::AddMult #1")
   {
      double maxerror(-1.), currentError;
      for (int i(0); i < ntry; ++i)
      {
         x.Randomize();
         y.Randomize();
         ymono = y;
         A->AddMult(x,y);
         Amono->AddMult(x,ymono);
         y.Add(-1., ymono);
         currentError = y.Normlinf();

         if (currentError > maxerror)
         {
            maxerror = currentError;
         }

      }
      REQUIRE(maxerror < tol);
   }

   SECTION("Check BlockMatrix::AddMult #2")
   {
      double maxerror(-1.), currentError;
      for (int i(0); i < ntry; ++i)
      {
         x.Randomize();
         y.Randomize();
         ymono = y;
         double a = 10 * static_cast<double>( rand() )  / static_cast<double>
                    ( RAND_MAX );
         a -= 5;
         A->AddMult(x,y,a);
         Amono->AddMult(x,ymono,a);
         y.Add(-1., ymono);
         currentError = y.Normlinf();

         if (currentError > maxerror)
         {
            maxerror = currentError;
         }

      }
      REQUIRE(maxerror < tol);
   }

   SECTION("Check BlockMatrix::MultTranspose")
   {
      double maxerror(-1.), currentError;
      for (int i(0); i < ntry; ++i)
      {
         x.Randomize();
         A->MultTranspose(x,y);
         Amono->MultTranspose(x,ymono);
         y.Add(-1., ymono);
         currentError = y.Normlinf();

         if (currentError > maxerror)
         {
            maxerror = currentError;
         }

      }
      REQUIRE(maxerror < tol);
   }

   SECTION("Check BlockMatrix::AddMultTranspose #1")
   {
      double maxerror(-1.), currentError;
      for (int i(0); i < ntry; ++i)
      {
         x.Randomize();
         y.Randomize();
         ymono = y;
         A->AddMultTranspose(x,y);
         Amono->AddMultTranspose(x,ymono);
         y.Add(-1., ymono);
         currentError = y.Normlinf();

         if (currentError > maxerror)
         {
            maxerror = currentError;
         }

      }
      REQUIRE(maxerror < tol);
   }

   SECTION("Check BlockMatrix::AddMultTranspose #2")
   {
      double maxerror(-1.), currentError;
      for (int i(0); i < ntry; ++i)
      {
         x.Randomize();
         y.Randomize();
         ymono = y;
         double a = 10 * static_cast<double>( rand() )  / static_cast<double>
                    ( RAND_MAX );
         a -= 5;
         A->AddMultTranspose(x,y,a);
         Amono->AddMultTranspose(x,ymono,a);
         y.Add(-1., ymono);
         currentError = y.Normlinf();

         if (currentError > maxerror)
         {
            maxerror = currentError;
         }

      }
      REQUIRE(maxerror < tol);
   }

   SECTION("Check Transpose(const BlockMatrix &)")
   {
      BlockMatrix * At = Transpose(*A);
      REQUIRE(At->Height() == A->Width() );
      REQUIRE(At->Width() == A->Height() );

      x.Randomize();
      y.Randomize();
      Vector Ax(A->Height()), Aty(At->Height());
      A->Mult(x,Ax);
      double yAx = y*Ax;

      At->Mult(y, Aty);
      double xAty = x* Aty;

      delete At;

      REQUIRE(fabs(yAx - xAty) < tol );
   }

   SECTION("Check Mult(const BlockMatrix &, const BlockMatrix &)")
   {
      BlockMatrix * B = new BlockMatrix(offsets);
      SparseMatrix B00(size0, size0), B10(size1,size0), B01(size0,size1), B11(size1,
                                                                              size1);
      fillRandomMatrix(B00);
      fillRandomMatrix(B10);
      fillRandomMatrix(B01);
      fillRandomMatrix(B11);
      B->SetBlock(0,0, &B00);
      B->SetBlock(0,1, &B01);
      B->SetBlock(1,0, &B10);
      B->SetBlock(1,1, &B11);

      BlockMatrix * C = Mult(*A,*B);
      x.Randomize();
      Vector Bx(A->Height()), ABx(A->Height()), Cx(C->Height());
      B->Mult(x, Bx);
      A->Mult(Bx,ABx);
      C->Mult(x, Cx);

      subtract(Cx, ABx, Cx);

      double error = Cx.Normlinf();

      delete B;
      delete C;

      REQUIRE(error < tol );
   }

   Vector y1(A->Height());
   Vector y2(Amono->Height());
   SECTION("Check PartMult")
   {
      Array<int> rows{{10,39,509,289,1112,1321,927}};
      x.Randomize();
      y1.Randomize();
      y2 = y1;
      A->PartMult(rows,x,y1);
      Amono->PartMult(rows,x,y2);
      y1-=y2;
      REQUIRE(y1.Norml2() == MFEM_Approx(0.0));
   }

   SECTION("Check PartAddMult")
   {
      Array<int> rows{{8,92,591,203,1094,1211,927}};
      x.Randomize();
      y1.Randomize();
      y2 = y1;
      A->PartAddMult(rows,x,y1);
      Amono->PartAddMult(rows,x,y2);
      y1-=y2;
      REQUIRE(y1.Norml2() == MFEM_Approx(0.0));
   }

   SECTION("Check EliminateRowCols")
   {
      Array<int> rows{{18,72,1342,951,423,877,1234}};
      BlockMatrix Ae(offsets); Ae.owns_blocks = 1;

      for (int i = 0; i<Ae.NumRowBlocks(); i++)
      {
         int h = offsets[i+1] - offsets[i];
         for (int j = 0; j<Ae.NumColBlocks(); j++)
         {
            int w = offsets[j+1] - offsets[j];
            Ae.SetBlock(i,j,new SparseMatrix(h, w));
         }
      }

      A->EliminateRowCols(rows,&Ae);

      SparseMatrix Amono_e(offsets.Last());
      Array<int> colmarker;
      mfem::FiniteElementSpace::ListToMarker(rows,offsets.Last(),colmarker);
      Amono->EliminateCols(colmarker,Amono_e);
      for (int i = 0; i<rows.Size(); i++) { Amono->EliminateRow(rows[i]); }

      x.Randomize();
      Ae.Mult(x,y1);
      Amono_e.Mult(x,y2);
      y1-=y2;
      REQUIRE(y1.Norml2() == MFEM_Approx(0.0));
   }

   delete A;
   delete Amono;
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "SoundResource.h"
#include "SoundData.h"
#include "Stream.h"

namespace ouzel
{
    namespace audio
    {
        SoundResource::SoundResource()
        {
        }

        SoundResource::~SoundResource()
        {
        }

        bool SoundResource::init(const std::shared_ptr<SoundData>& newSoundData)
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            soundData = newSoundData;

            if (soundData)
            {
                stream = soundData->createStream();
            }

            dirty |= DIRTY_SOUND_DATA | DIRTY_POSITION | DIRTY_PITCH | DIRTY_GAIN | DIRTY_PLAY_STATE;

            return true;
        }

        void SoundResource::setPosition(const Vector3& newPosition)
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            position = newPosition;

            dirty |= DIRTY_POSITION;
        }

        void SoundResource::setPitch(float newPitch)
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            pitch = newPitch;

            dirty |= DIRTY_PITCH;
        }

        void SoundResource::setGain(float newGain)
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            gain = newGain;

            dirty |= DIRTY_GAIN;
        }

        bool SoundResource::play(bool repeatSound)
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            shouldPlay = true;
            repeat = repeatSound;

            dirty |= DIRTY_PLAY_STATE;

            return true;
        }

        bool SoundResource::pause()
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            shouldPlay = false;

            dirty |= DIRTY_PLAY_STATE;

            return true;
        }

        bool SoundResource::stop()
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            shouldPlay = false;
            reset = true;

            dirty |= DIRTY_PLAY_STATE;

            return true;
        }

        std::vector<uint8_t> SoundResource::getData(uint32_t size, uint16_t channels, uint32_t samplesPerSecond)
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            std::vector<uint8_t> result;

            if (!shouldPlay)
            {
                result = std::vector<uint8_t>();
            }
            else if (soundData && stream)
            {
                std::vector<uint8_t> data = soundData->getData(stream.get(), size);

                if (channels == soundData->getChannels() &&
                    samplesPerSecond == soundData->getSamplesPerSecond())
                {
                    result = std::move(data);
                }
                else
                {
                    // channel map
                    // 0 - Front left
                    // 1 - Front right
                    // 2 - Rear left
                    // 3 - Rear right
                    // 4 - Center
                    // 5 - Low-frequency effects (LFE)

                    result.resize(size);

                    if (channels != soundData->getChannels())
                    {
                        uint32_t dstSamples = size / sizeof(uint16_t);
                        uint32_t srcSamples = static_cast<uint32_t>(data.size()) / sizeof(uint16_t);

                        // front left channel
                        if (channels >= 1)
                        {
                            uint16_t* dstBuffer = reinterpret_cast<uint16_t*>(result.data());

                            if (soundData->getChannels() >= 1)
                            {
                                uint16_t* srcBuffer = reinterpret_cast<uint16_t*>(data.data());

                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *dstBuffer = *srcBuffer;
                                    dstBuffer += channels;
                                    srcBuffer += soundData->getChannels();
                                }
                            }
                            else
                            {
                                // fill the front left channel with zeros
                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *dstBuffer = 0;
                                    dstBuffer += channels;
                                }
                            }
                        }

                        // front right channel
                        if (channels >= 2)
                        {
                            uint16_t* dstBuffer = reinterpret_cast<uint16_t*>(result.data());

                            // sound data has front right channel
                            if (soundData->getChannels() >= 2)
                            {
                                uint16_t* srcBuffer = reinterpret_cast<uint16_t*>(data.data());

                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 1) = *(srcBuffer + 1);
                                    dstBuffer += channels;
                                    srcBuffer += soundData->getChannels();
                                }
                            }
                            else
                            {
                                // copy the front left channel in to the front right one
                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 1) = *dstBuffer;
                                    dstBuffer += channels;
                                }
                            }
                        }

                        // rear left channel
                        if (channels >= 3)
                        {
                            uint16_t* dstBuffer = reinterpret_cast<uint16_t*>(result.data());

                            // sound data has rear left channel
                            if (soundData->getChannels() >= 3)
                            {
                                uint16_t* srcBuffer = reinterpret_cast<uint16_t*>(data.data());

                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 2) = *(srcBuffer + 2);
                                    dstBuffer += channels;
                                    srcBuffer += soundData->getChannels();
                                }
                            }
                            else
                            {
                                // copy the front left channel in to the rear left one
                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 2) = *dstBuffer;
                                    dstBuffer += channels;
                                }
                            }
                        }

                        // rear right channel
                        if (channels >= 4)
                        {
                            uint16_t* dstBuffer = reinterpret_cast<uint16_t*>(result.data());

                            // sound data has rear right channel
                            if (soundData->getChannels() >= 4)
                            {
                                uint16_t* srcBuffer = reinterpret_cast<uint16_t*>(data.data());

                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 3) = *(srcBuffer + 3);
                                    dstBuffer += channels;
                                    srcBuffer += soundData->getChannels();
                                }
                            }
                            else
                            {
                                // copy the front right channel in to the rear right one
                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 2) = *(dstBuffer + 1);
                                    dstBuffer += channels;
                                }
                            }
                        }

                        // center channel
                        if (channels >= 5)
                        {
                            uint16_t* dstBuffer = reinterpret_cast<uint16_t*>(result.data());

                            if (soundData->getChannels() >= 5)
                            {
                                uint16_t* srcBuffer = reinterpret_cast<uint16_t*>(data.data());

                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 4) = *(srcBuffer + 4);
                                    dstBuffer += channels;
                                    srcBuffer += soundData->getChannels();
                                }
                            }
                            else if (channels >= 2)
                            {
                                // calculate the average of the left and the right channel
                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 4) = (*dstBuffer + *(dstBuffer + 1)) / 2;
                                    dstBuffer += channels;
                                }
                            }
                            else
                            {
                                // copy the front left channel in to the center one
                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 4) = *dstBuffer;
                                    dstBuffer += channels;
                                }
                            }
                        }

                        // LFE channel
                        if (channels >= 6)
                        {
                            uint16_t* dstBuffer = reinterpret_cast<uint16_t*>(result.data());

                            if (soundData->getChannels() >= 6)
                            {
                                uint16_t* srcBuffer = reinterpret_cast<uint16_t*>(data.data());

                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 5) = *(srcBuffer + 5);
                                    dstBuffer += channels;
                                    srcBuffer += soundData->getChannels();
                                }
                            }
                            else
                            {
                                // fill the LFE channel with zeros
                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 5) = 0;
                                    dstBuffer += channels;
                                }
                            }
                        }
                    }
                    else
                    {
                        result = std::move(data);
                    }

                    if (samplesPerSecond != soundData->getSamplesPerSecond())
                    {
                        // TODO: resample
                    }

                    std::vector<float> channelVolume(channels, gain);

                    uint32_t samples = static_cast<uint32_t>(result.size()) / sizeof(uint16_t);
                    uint16_t* buffer = reinterpret_cast<uint16_t*>(result.data());

                    for (uint32_t i = 0; i < samples / channels; ++i)
                    {
                        for (uint32_t channel = 0; channel < channels; ++channel)
                        {
                            *buffer = static_cast<uint16_t>(*buffer * channelVolume[channel]);

                            ++buffer;
                        }
                    }
                }
            }

            return result;
        }
    } // namespace audio
} // namespace ouzel
<commit_msg>Improve the comment<commit_after>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "SoundResource.h"
#include "SoundData.h"
#include "Stream.h"

namespace ouzel
{
    namespace audio
    {
        SoundResource::SoundResource()
        {
        }

        SoundResource::~SoundResource()
        {
        }

        bool SoundResource::init(const std::shared_ptr<SoundData>& newSoundData)
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            soundData = newSoundData;

            if (soundData)
            {
                stream = soundData->createStream();
            }

            dirty |= DIRTY_SOUND_DATA | DIRTY_POSITION | DIRTY_PITCH | DIRTY_GAIN | DIRTY_PLAY_STATE;

            return true;
        }

        void SoundResource::setPosition(const Vector3& newPosition)
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            position = newPosition;

            dirty |= DIRTY_POSITION;
        }

        void SoundResource::setPitch(float newPitch)
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            pitch = newPitch;

            dirty |= DIRTY_PITCH;
        }

        void SoundResource::setGain(float newGain)
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            gain = newGain;

            dirty |= DIRTY_GAIN;
        }

        bool SoundResource::play(bool repeatSound)
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            shouldPlay = true;
            repeat = repeatSound;

            dirty |= DIRTY_PLAY_STATE;

            return true;
        }

        bool SoundResource::pause()
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            shouldPlay = false;

            dirty |= DIRTY_PLAY_STATE;

            return true;
        }

        bool SoundResource::stop()
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            shouldPlay = false;
            reset = true;

            dirty |= DIRTY_PLAY_STATE;

            return true;
        }

        std::vector<uint8_t> SoundResource::getData(uint32_t size, uint16_t channels, uint32_t samplesPerSecond)
        {
            std::lock_guard<std::mutex> lock(uploadMutex);

            std::vector<uint8_t> result;

            if (!shouldPlay)
            {
                result = std::vector<uint8_t>();
            }
            else if (soundData && stream)
            {
                std::vector<uint8_t> data = soundData->getData(stream.get(), size);

                if (channels == soundData->getChannels() &&
                    samplesPerSecond == soundData->getSamplesPerSecond())
                {
                    result = std::move(data);
                }
                else
                {
                    // channel map
                    // 0 - Front left
                    // 1 - Front right
                    // 2 - Rear left
                    // 3 - Rear right
                    // 4 - Center
                    // 5 - Low-frequency effects (LFE)

                    result.resize(size);

                    if (channels != soundData->getChannels())
                    {
                        uint32_t dstSamples = size / sizeof(uint16_t);
                        uint32_t srcSamples = static_cast<uint32_t>(data.size()) / sizeof(uint16_t);

                        // front left channel
                        if (channels >= 1)
                        {
                            uint16_t* dstBuffer = reinterpret_cast<uint16_t*>(result.data());

                            if (soundData->getChannels() >= 1)
                            {
                                uint16_t* srcBuffer = reinterpret_cast<uint16_t*>(data.data());

                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *dstBuffer = *srcBuffer;
                                    dstBuffer += channels;
                                    srcBuffer += soundData->getChannels();
                                }
                            }
                            else
                            {
                                // fill the front left channel with zeros
                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *dstBuffer = 0;
                                    dstBuffer += channels;
                                }
                            }
                        }

                        // front right channel
                        if (channels >= 2)
                        {
                            uint16_t* dstBuffer = reinterpret_cast<uint16_t*>(result.data());

                            // sound data has front right channel
                            if (soundData->getChannels() >= 2)
                            {
                                uint16_t* srcBuffer = reinterpret_cast<uint16_t*>(data.data());

                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 1) = *(srcBuffer + 1);
                                    dstBuffer += channels;
                                    srcBuffer += soundData->getChannels();
                                }
                            }
                            else
                            {
                                // copy the front left channel in to the front right one
                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 1) = *dstBuffer;
                                    dstBuffer += channels;
                                }
                            }
                        }

                        // rear left channel
                        if (channels >= 3)
                        {
                            uint16_t* dstBuffer = reinterpret_cast<uint16_t*>(result.data());

                            // sound data has rear left channel
                            if (soundData->getChannels() >= 3)
                            {
                                uint16_t* srcBuffer = reinterpret_cast<uint16_t*>(data.data());

                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 2) = *(srcBuffer + 2);
                                    dstBuffer += channels;
                                    srcBuffer += soundData->getChannels();
                                }
                            }
                            else
                            {
                                // copy the front left channel in to the rear left one
                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 2) = *dstBuffer;
                                    dstBuffer += channels;
                                }
                            }
                        }

                        // rear right channel
                        if (channels >= 4)
                        {
                            uint16_t* dstBuffer = reinterpret_cast<uint16_t*>(result.data());

                            // sound data has rear right channel
                            if (soundData->getChannels() >= 4)
                            {
                                uint16_t* srcBuffer = reinterpret_cast<uint16_t*>(data.data());

                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 3) = *(srcBuffer + 3);
                                    dstBuffer += channels;
                                    srcBuffer += soundData->getChannels();
                                }
                            }
                            else
                            {
                                // copy the front right channel in to the rear right one
                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 2) = *(dstBuffer + 1);
                                    dstBuffer += channels;
                                }
                            }
                        }

                        // center channel
                        if (channels >= 5)
                        {
                            uint16_t* dstBuffer = reinterpret_cast<uint16_t*>(result.data());

                            if (soundData->getChannels() >= 5)
                            {
                                uint16_t* srcBuffer = reinterpret_cast<uint16_t*>(data.data());

                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 4) = *(srcBuffer + 4);
                                    dstBuffer += channels;
                                    srcBuffer += soundData->getChannels();
                                }
                            }
                            else if (channels >= 2)
                            {
                                // calculate the average of the front left and the front right channel
                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 4) = (*dstBuffer + *(dstBuffer + 1)) / 2;
                                    dstBuffer += channels;
                                }
                            }
                            else
                            {
                                // copy the front left channel in to the center one
                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 4) = *dstBuffer;
                                    dstBuffer += channels;
                                }
                            }
                        }

                        // LFE channel
                        if (channels >= 6)
                        {
                            uint16_t* dstBuffer = reinterpret_cast<uint16_t*>(result.data());

                            if (soundData->getChannels() >= 6)
                            {
                                uint16_t* srcBuffer = reinterpret_cast<uint16_t*>(data.data());

                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 5) = *(srcBuffer + 5);
                                    dstBuffer += channels;
                                    srcBuffer += soundData->getChannels();
                                }
                            }
                            else
                            {
                                // fill the LFE channel with zeros
                                for (uint32_t i = 0; i < dstSamples / channels && i < srcSamples / soundData->getChannels(); ++i)
                                {
                                    *(dstBuffer + 5) = 0;
                                    dstBuffer += channels;
                                }
                            }
                        }
                    }
                    else
                    {
                        result = std::move(data);
                    }

                    if (samplesPerSecond != soundData->getSamplesPerSecond())
                    {
                        // TODO: resample
                    }

                    std::vector<float> channelVolume(channels, gain);

                    uint32_t samples = static_cast<uint32_t>(result.size()) / sizeof(uint16_t);
                    uint16_t* buffer = reinterpret_cast<uint16_t*>(result.data());

                    for (uint32_t i = 0; i < samples / channels; ++i)
                    {
                        for (uint32_t channel = 0; channel < channels; ++channel)
                        {
                            *buffer = static_cast<uint16_t>(*buffer * channelVolume[channel]);

                            ++buffer;
                        }
                    }
                }
            }

            return result;
        }
    } // namespace audio
} // namespace ouzel
<|endoftext|>


<commit_before>
#include "numerics/elliptic_functions.hpp"

#include <limits>

#include "glog/logging.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "numerics/elliptic_integrals.hpp"
#include "quantities/quantities.hpp"
#include "quantities/si.hpp"
#include "testing_utilities/almost_equals.hpp"
#include "testing_utilities/is_near.hpp"
#include "testing_utilities/numerics.hpp"
#include "testing_utilities/serialization.hpp"

namespace principia {
namespace numerics {

using quantities::Angle;
using quantities::si::Radian;
using testing_utilities::AlmostEquals;
using testing_utilities::IsNear;
using testing_utilities::ReadFromTabulatedData;
using testing_utilities::RelativeError;
using ::testing::Le;
using ::testing::Lt;

class EllipticFunctionsTest : public ::testing::Test {};

// The test values found in Fukushima's xgscd.txt file.
TEST_F(EllipticFunctionsTest, Xgscd) {
  auto const xgscd_expected =
      ReadFromTabulatedData(SOLUTION_DIR / "numerics" / "xgscd.proto.txt");
  double Δmc, mc, m, s, c, d;
  Angle u, du;
  int jend, iend;
  jend = 10;
  iend = 8;
  Δmc = 1.0 / static_cast<double>(jend);
  std::printf("%10s%10s%25s%25s%25s\n", "m", "u", "s", "c", "d");
  int expected_index = 0;
  for (int j = 1; j <= jend; ++j) {
    mc = static_cast<double>(j) * Δmc;
    m = 1.0 - mc;
    du = EllipticK(mc) / static_cast<double>(iend);
    for (int i = 0; i <= iend * 8; ++i) {
      u = du * static_cast<double>(i);
      JacobiSNCNDN(u, mc, s, c, d);
      std::printf(
          "%10.5f%10.5f%25.15e%25.15e%25.15e\n", m, u / Radian, s, c, d);

      auto const& expected_entry = xgscd_expected.entry(expected_index);
      auto const expected_argument_m = expected_entry.argument(0);
      auto const expected_argument_u = expected_entry.argument(1) * Radian;
      auto const expected_value_s = expected_entry.value(0);
      auto const expected_value_c = expected_entry.value(1);
      auto const expected_value_d = expected_entry.value(2);
      EXPECT_THAT(m, AlmostEquals(expected_argument_m, 0, 2));
      EXPECT_THAT(RelativeError(expected_argument_u, u), Lt(3e-5));
      EXPECT_THAT(s, AlmostEquals(expected_value_s, 0, 2));
      EXPECT_THAT(c, AlmostEquals(expected_value_c, 0, 3));
      EXPECT_THAT(d, AlmostEquals(expected_value_d, 0, 1));
      ++expected_index;
    }
    std::printf("\n");
  }
}

TEST_F(EllipticFunctionsTest, Mathematica) {
  auto const elliptic_functions_expected = ReadFromTabulatedData(
      SOLUTION_DIR / "numerics" / "elliptic_functions.proto.txt");

  for (auto const& entry : elliptic_functions_expected.entry()) {
    Angle const argument_u = entry.argument(0) * Radian;
    double const argument_m = entry.argument(1);
    double const expected_value_s = entry.value(0);
    double const expected_value_c = entry.value(1);
    double const expected_value_d = entry.value(2);
    Angle const expected_value_a = entry.value(3) * Radian;

    double actual_value_s;
    double actual_value_c;
    double actual_value_d;
    JacobiSNCNDN(argument_u,
                 1.0 - argument_m,
                 actual_value_s,
                 actual_value_c,
                 actual_value_d);

    Angle const actual_value_a = JacobiAmplitude(argument_u, 1.0 - argument_m);

    // TODO(phl): The errors are uncomfortably large here.  Figure out what's
    // happening.
    EXPECT_THAT(actual_value_s, AlmostEquals(expected_value_s, 0, 12507))
        << argument_u << " " << argument_m;
    EXPECT_THAT(actual_value_c, AlmostEquals(expected_value_c, 0, 7648))
        << argument_u << " " << argument_m;
    EXPECT_THAT(actual_value_d, AlmostEquals(expected_value_d, 0, 85))
        << argument_u << " " << argument_m;

    EXPECT_THAT(actual_value_a, AlmostEquals(expected_value_a, 0, 22074))
        << argument_u << " " << argument_m;
  }
}

TEST_F(EllipticFunctionsTest, Monotonicity) {
  for (double const mc : {0.01, 0.1, 0.5}) {
    Angle const k = EllipticK(mc);
    for (int i = -5; i <= 5; ++i) {
      Angle const u = i * k;
      Angle const am = JacobiAmplitude(u, mc);
      LOG(ERROR) << "Testing around " << u << " and mc = " << mc
                 << " starting with am = " << am << " (i = " << i << ")";
      Angle u₊ = u;
      Angle u₋ = u;
      Angle previous_am₊ = am;
      Angle previous_am₋ = am;
      for (int j = 0; j < 10'000; ++j) {
        u₊ = std::nextafter(u₊ / Radian,
                            std::numeric_limits<double>::infinity()) * Radian;
        u₋ = std::nextafter(u₋ / Radian,
                            -std::numeric_limits<double>::infinity()) * Radian;
        Angle const am₊ = JacobiAmplitude(u₊, mc);
        Angle const am₋ = JacobiAmplitude(u₋, mc);
        ASSERT_THAT(previous_am₊, Le(am₊)) << u₊ << " " << mc << " " << j;
        ASSERT_THAT(am₋, Le(previous_am₋)) << u₋ << " " << mc << " " << j;
        previous_am₋ = am₋;
        previous_am₊ = am₊;
      }
    }
  }
}

}  // namespace numerics
}  // namespace principia
<commit_msg>Ifdef out tests longer than 30 seconds in Debug.<commit_after>
#include "numerics/elliptic_functions.hpp"

#include <limits>

#include "glog/logging.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "numerics/elliptic_integrals.hpp"
#include "quantities/quantities.hpp"
#include "quantities/si.hpp"
#include "testing_utilities/almost_equals.hpp"
#include "testing_utilities/is_near.hpp"
#include "testing_utilities/numerics.hpp"
#include "testing_utilities/serialization.hpp"

namespace principia {
namespace numerics {

using quantities::Angle;
using quantities::si::Radian;
using testing_utilities::AlmostEquals;
using testing_utilities::IsNear;
using testing_utilities::ReadFromTabulatedData;
using testing_utilities::RelativeError;
using ::testing::Le;
using ::testing::Lt;

class EllipticFunctionsTest : public ::testing::Test {};

// The test values found in Fukushima's xgscd.txt file.
TEST_F(EllipticFunctionsTest, Xgscd) {
  auto const xgscd_expected =
      ReadFromTabulatedData(SOLUTION_DIR / "numerics" / "xgscd.proto.txt");
  double Δmc, mc, m, s, c, d;
  Angle u, du;
  int jend, iend;
  jend = 10;
  iend = 8;
  Δmc = 1.0 / static_cast<double>(jend);
  std::printf("%10s%10s%25s%25s%25s\n", "m", "u", "s", "c", "d");
  int expected_index = 0;
  for (int j = 1; j <= jend; ++j) {
    mc = static_cast<double>(j) * Δmc;
    m = 1.0 - mc;
    du = EllipticK(mc) / static_cast<double>(iend);
    for (int i = 0; i <= iend * 8; ++i) {
      u = du * static_cast<double>(i);
      JacobiSNCNDN(u, mc, s, c, d);
      std::printf(
          "%10.5f%10.5f%25.15e%25.15e%25.15e\n", m, u / Radian, s, c, d);

      auto const& expected_entry = xgscd_expected.entry(expected_index);
      auto const expected_argument_m = expected_entry.argument(0);
      auto const expected_argument_u = expected_entry.argument(1) * Radian;
      auto const expected_value_s = expected_entry.value(0);
      auto const expected_value_c = expected_entry.value(1);
      auto const expected_value_d = expected_entry.value(2);
      EXPECT_THAT(m, AlmostEquals(expected_argument_m, 0, 2));
      EXPECT_THAT(RelativeError(expected_argument_u, u), Lt(3e-5));
      EXPECT_THAT(s, AlmostEquals(expected_value_s, 0, 2));
      EXPECT_THAT(c, AlmostEquals(expected_value_c, 0, 3));
      EXPECT_THAT(d, AlmostEquals(expected_value_d, 0, 1));
      ++expected_index;
    }
    std::printf("\n");
  }
}

TEST_F(EllipticFunctionsTest, Mathematica) {
  auto const elliptic_functions_expected = ReadFromTabulatedData(
      SOLUTION_DIR / "numerics" / "elliptic_functions.proto.txt");

  for (auto const& entry : elliptic_functions_expected.entry()) {
    Angle const argument_u = entry.argument(0) * Radian;
    double const argument_m = entry.argument(1);
    double const expected_value_s = entry.value(0);
    double const expected_value_c = entry.value(1);
    double const expected_value_d = entry.value(2);
    Angle const expected_value_a = entry.value(3) * Radian;

    double actual_value_s;
    double actual_value_c;
    double actual_value_d;
    JacobiSNCNDN(argument_u,
                 1.0 - argument_m,
                 actual_value_s,
                 actual_value_c,
                 actual_value_d);

    Angle const actual_value_a = JacobiAmplitude(argument_u, 1.0 - argument_m);

    // TODO(phl): The errors are uncomfortably large here.  Figure out what's
    // happening.
    EXPECT_THAT(actual_value_s, AlmostEquals(expected_value_s, 0, 12507))
        << argument_u << " " << argument_m;
    EXPECT_THAT(actual_value_c, AlmostEquals(expected_value_c, 0, 7648))
        << argument_u << " " << argument_m;
    EXPECT_THAT(actual_value_d, AlmostEquals(expected_value_d, 0, 85))
        << argument_u << " " << argument_m;

    EXPECT_THAT(actual_value_a, AlmostEquals(expected_value_a, 0, 22074))
        << argument_u << " " << argument_m;
  }
}

#if !defined(_DEBUG)
TEST_F(EllipticFunctionsTest, Monotonicity) {
  for (double const mc : {0.01, 0.1, 0.5}) {
    Angle const k = EllipticK(mc);
    for (int i = -5; i <= 5; ++i) {
      Angle const u = i * k;
      Angle const am = JacobiAmplitude(u, mc);
      LOG(ERROR) << "Testing around " << u << " and mc = " << mc
                 << " starting with am = " << am << " (i = " << i << ")";
      Angle u₊ = u;
      Angle u₋ = u;
      Angle previous_am₊ = am;
      Angle previous_am₋ = am;
      for (int j = 0; j < 10'000; ++j) {
        u₊ = std::nextafter(u₊ / Radian,
                            std::numeric_limits<double>::infinity()) * Radian;
        u₋ = std::nextafter(u₋ / Radian,
                            -std::numeric_limits<double>::infinity()) * Radian;
        Angle const am₊ = JacobiAmplitude(u₊, mc);
        Angle const am₋ = JacobiAmplitude(u₋, mc);
        ASSERT_THAT(previous_am₊, Le(am₊)) << u₊ << " " << mc << " " << j;
        ASSERT_THAT(am₋, Le(previous_am₋)) << u₋ << " " << mc << " " << j;
        previous_am₋ = am₋;
        previous_am₊ = am₊;
      }
    }
  }
}
#endif

}  // namespace numerics
}  // namespace principia
<|endoftext|>